Initial import.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f4988b4
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,28 @@
+Copyright 2014, Google 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 Google 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 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.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ac92a97
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,4656 @@
+# GRPC global makefile
+# This currently builds C and C++ code.
+
+
+
+
+# General settings.
+# You may want to change these depending on your system.
+
+prefix ?= /usr/local
+
+PROTOC = protoc
+CC = gcc
+CXX = g++
+LD = gcc
+LDXX = g++
+AR = ar
+STRIP = strip --strip-unneeded
+INSTALL = install -D
+RM = rm -f
+
+ifeq ($(DEBUG),)
+CPPFLAGS += -O2
+DEFINES += NDEBUG
+else
+CPPFLAGS += -O0
+DEFINES += _DEBUG DEBUG
+endif
+
+CFLAGS += -std=c89 -pedantic
+CXXFLAGS += -std=c++11
+CPPFLAGS += -g -fPIC -Wall -Werror -Wno-long-long
+LDFLAGS += -g -pthread -fPIC
+
+INCLUDES = . include gens
+LIBS = rt m z event event_pthreads pthread
+LIBSXX = protobuf
+LIBS_SECURE = ssl crypto dl
+
+ifneq ($(wildcard /usr/src/gtest/src/gtest-all.cc),)
+GTEST_LIB = /usr/src/gtest/src/gtest-all.cc -I/usr/src/gtest
+else
+GTEST_LIB = -lgtest
+endif
+
+ifeq ($(V),1)
+E = @:
+Q =
+else
+E = @echo
+Q = @
+endif
+
+VERSION = 0.8.0.0
+
+CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
+CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
+
+LDFLAGS += $(ARCH_FLAGS)
+LDLIBS += $(addprefix -l, $(LIBS))
+LDLIBSXX += $(addprefix -l, $(LIBSXX))
+LDLIBS_SECURE += $(addprefix -l, $(LIBS_SECURE))
+
+.SECONDARY = %.pb.h %.pb.cc
+
+all: static shared
+
+static: make_dirs dep libs/libgpr.a libs/libgrpc.a libs/libgrpc++.a libs/libgrpc_unsecure.a
+
+shared: make_dirs dep libs/libgpr.so.$(VERSION) libs/libgrpc.so.$(VERSION) libs/libgrpc++.so.$(VERSION) libs/libgrpc_unsecure.so.$(VERSION)
+
+privatelibs: make_dirs dep libs/libgrpc_test_util.a libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_cancel_after_accept.a libs/libend2end_test_cancel_after_accept_and_writes_closed.a libs/libend2end_test_cancel_after_invoke.a libs/libend2end_test_cancel_before_invoke.a libs/libend2end_test_cancel_in_a_vacuum.a libs/libend2end_test_early_server_shutdown_finishes_inflight_calls.a libs/libend2end_test_early_server_shutdown_finishes_tags.a libs/libend2end_test_invoke_large_request.a libs/libend2end_test_max_concurrent_streams.a libs/libend2end_test_no_op.a libs/libend2end_test_ping_pong_streaming.a libs/libend2end_test_request_response_with_metadata_and_payload.a libs/libend2end_test_request_response_with_payload.a libs/libend2end_test_simple_delayed_request.a libs/libend2end_test_simple_request.a libs/libend2end_test_thread_stress_test.a libs/libend2end_test_writes_done_hangs_with_pending_read.a libs/libend2end_certs.a
+
+buildtests: privatelibs bins/grpc_byte_buffer_reader_test bins/gpr_cancellable_test bins/gpr_log_test bins/gpr_cmdline_test bins/gpr_histogram_test bins/gpr_host_port_test bins/gpr_slice_buffer_test bins/gpr_slice_test bins/gpr_string_test bins/gpr_sync_test bins/gpr_thd_test bins/gpr_time_test bins/murmur_hash_test bins/grpc_em_test bins/grpc_em_pipe_test bins/grpc_stream_op_test bins/chttp2_stream_encoder_test bins/hpack_table_test bins/chttp2_stream_map_test bins/hpack_parser_test bins/transport_metadata_test bins/chttp2_status_conversion_test bins/chttp2_transport_end2end_test bins/grpc_tcp_test bins/resolve_address_test bins/tcp_server_test bins/tcp_client_test bins/grpc_channel_stack_test bins/metadata_buffer_test bins/grpc_completion_queue_test bins/census_window_stats_test bins/census_statistics_quick_test bins/census_statistics_performance_test bins/census_statistics_multiple_writers_test bins/census_statistics_multiple_writers_circular_buffer_test bins/census_stub_test bins/census_hash_table_test bins/fling_server bins/fling_client bins/fling_test bins/echo_server bins/echo_client bins/echo_test bins/message_compress_test bins/secure_endpoint_test bins/httpcli_format_request_test bins/httpcli_parser_test bins/httpcli_test bins/grpc_credentials_test bins/fling_stream_test bins/lame_client_test bins/thread_pool_test bins/status_test bins/chttp2_fake_security_cancel_after_accept_test bins/chttp2_fake_security_cancel_after_accept_and_writes_closed_test bins/chttp2_fake_security_cancel_after_invoke_test bins/chttp2_fake_security_cancel_before_invoke_test bins/chttp2_fake_security_cancel_in_a_vacuum_test bins/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test bins/chttp2_fake_security_early_server_shutdown_finishes_tags_test bins/chttp2_fake_security_invoke_large_request_test bins/chttp2_fake_security_max_concurrent_streams_test bins/chttp2_fake_security_no_op_test bins/chttp2_fake_security_ping_pong_streaming_test bins/chttp2_fake_security_request_response_with_metadata_and_payload_test bins/chttp2_fake_security_request_response_with_payload_test bins/chttp2_fake_security_simple_delayed_request_test bins/chttp2_fake_security_simple_request_test bins/chttp2_fake_security_thread_stress_test_test bins/chttp2_fake_security_writes_done_hangs_with_pending_read_test bins/chttp2_fullstack_cancel_after_accept_test bins/chttp2_fullstack_cancel_after_accept_and_writes_closed_test bins/chttp2_fullstack_cancel_after_invoke_test bins/chttp2_fullstack_cancel_before_invoke_test bins/chttp2_fullstack_cancel_in_a_vacuum_test bins/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/chttp2_fullstack_early_server_shutdown_finishes_tags_test bins/chttp2_fullstack_invoke_large_request_test bins/chttp2_fullstack_max_concurrent_streams_test bins/chttp2_fullstack_no_op_test bins/chttp2_fullstack_ping_pong_streaming_test bins/chttp2_fullstack_request_response_with_metadata_and_payload_test bins/chttp2_fullstack_request_response_with_payload_test bins/chttp2_fullstack_simple_delayed_request_test bins/chttp2_fullstack_simple_request_test bins/chttp2_fullstack_thread_stress_test_test bins/chttp2_fullstack_writes_done_hangs_with_pending_read_test bins/chttp2_simple_ssl_fullstack_cancel_after_accept_test bins/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test bins/chttp2_simple_ssl_fullstack_cancel_after_invoke_test bins/chttp2_simple_ssl_fullstack_cancel_before_invoke_test bins/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test bins/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test bins/chttp2_simple_ssl_fullstack_invoke_large_request_test bins/chttp2_simple_ssl_fullstack_max_concurrent_streams_test bins/chttp2_simple_ssl_fullstack_no_op_test bins/chttp2_simple_ssl_fullstack_ping_pong_streaming_test bins/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test bins/chttp2_simple_ssl_fullstack_request_response_with_payload_test bins/chttp2_simple_ssl_fullstack_simple_delayed_request_test bins/chttp2_simple_ssl_fullstack_simple_request_test bins/chttp2_simple_ssl_fullstack_thread_stress_test_test bins/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test bins/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test bins/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test bins/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test bins/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test bins/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test bins/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test bins/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test bins/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test bins/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test bins/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test bins/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test bins/chttp2_socket_pair_cancel_after_accept_test bins/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test bins/chttp2_socket_pair_cancel_after_invoke_test bins/chttp2_socket_pair_cancel_before_invoke_test bins/chttp2_socket_pair_cancel_in_a_vacuum_test bins/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test bins/chttp2_socket_pair_early_server_shutdown_finishes_tags_test bins/chttp2_socket_pair_invoke_large_request_test bins/chttp2_socket_pair_max_concurrent_streams_test bins/chttp2_socket_pair_no_op_test bins/chttp2_socket_pair_ping_pong_streaming_test bins/chttp2_socket_pair_request_response_with_metadata_and_payload_test bins/chttp2_socket_pair_request_response_with_payload_test bins/chttp2_socket_pair_simple_delayed_request_test bins/chttp2_socket_pair_simple_request_test bins/chttp2_socket_pair_thread_stress_test_test bins/chttp2_socket_pair_writes_done_hangs_with_pending_read_test
+
+buildtests_c: privatelibs bins/grpc_byte_buffer_reader_test bins/gpr_cancellable_test bins/gpr_log_test bins/gpr_cmdline_test bins/gpr_histogram_test bins/gpr_host_port_test bins/gpr_slice_buffer_test bins/gpr_slice_test bins/gpr_string_test bins/gpr_sync_test bins/gpr_thd_test bins/gpr_time_test bins/murmur_hash_test bins/grpc_em_test bins/grpc_em_pipe_test bins/grpc_stream_op_test bins/chttp2_stream_encoder_test bins/hpack_table_test bins/chttp2_stream_map_test bins/hpack_parser_test bins/transport_metadata_test bins/chttp2_status_conversion_test bins/chttp2_transport_end2end_test bins/grpc_tcp_test bins/resolve_address_test bins/tcp_server_test bins/tcp_client_test bins/grpc_channel_stack_test bins/metadata_buffer_test bins/grpc_completion_queue_test bins/census_window_stats_test bins/census_statistics_quick_test bins/census_statistics_performance_test bins/census_statistics_multiple_writers_test bins/census_statistics_multiple_writers_circular_buffer_test bins/census_stub_test bins/census_hash_table_test bins/fling_server bins/fling_client bins/fling_test bins/echo_server bins/echo_client bins/echo_test bins/message_compress_test bins/secure_endpoint_test bins/httpcli_format_request_test bins/httpcli_parser_test bins/httpcli_test bins/grpc_credentials_test bins/fling_stream_test bins/lame_client_test bins/chttp2_fake_security_cancel_after_accept_test bins/chttp2_fake_security_cancel_after_accept_and_writes_closed_test bins/chttp2_fake_security_cancel_after_invoke_test bins/chttp2_fake_security_cancel_before_invoke_test bins/chttp2_fake_security_cancel_in_a_vacuum_test bins/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test bins/chttp2_fake_security_early_server_shutdown_finishes_tags_test bins/chttp2_fake_security_invoke_large_request_test bins/chttp2_fake_security_max_concurrent_streams_test bins/chttp2_fake_security_no_op_test bins/chttp2_fake_security_ping_pong_streaming_test bins/chttp2_fake_security_request_response_with_metadata_and_payload_test bins/chttp2_fake_security_request_response_with_payload_test bins/chttp2_fake_security_simple_delayed_request_test bins/chttp2_fake_security_simple_request_test bins/chttp2_fake_security_thread_stress_test_test bins/chttp2_fake_security_writes_done_hangs_with_pending_read_test bins/chttp2_fullstack_cancel_after_accept_test bins/chttp2_fullstack_cancel_after_accept_and_writes_closed_test bins/chttp2_fullstack_cancel_after_invoke_test bins/chttp2_fullstack_cancel_before_invoke_test bins/chttp2_fullstack_cancel_in_a_vacuum_test bins/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/chttp2_fullstack_early_server_shutdown_finishes_tags_test bins/chttp2_fullstack_invoke_large_request_test bins/chttp2_fullstack_max_concurrent_streams_test bins/chttp2_fullstack_no_op_test bins/chttp2_fullstack_ping_pong_streaming_test bins/chttp2_fullstack_request_response_with_metadata_and_payload_test bins/chttp2_fullstack_request_response_with_payload_test bins/chttp2_fullstack_simple_delayed_request_test bins/chttp2_fullstack_simple_request_test bins/chttp2_fullstack_thread_stress_test_test bins/chttp2_fullstack_writes_done_hangs_with_pending_read_test bins/chttp2_simple_ssl_fullstack_cancel_after_accept_test bins/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test bins/chttp2_simple_ssl_fullstack_cancel_after_invoke_test bins/chttp2_simple_ssl_fullstack_cancel_before_invoke_test bins/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test bins/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test bins/chttp2_simple_ssl_fullstack_invoke_large_request_test bins/chttp2_simple_ssl_fullstack_max_concurrent_streams_test bins/chttp2_simple_ssl_fullstack_no_op_test bins/chttp2_simple_ssl_fullstack_ping_pong_streaming_test bins/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test bins/chttp2_simple_ssl_fullstack_request_response_with_payload_test bins/chttp2_simple_ssl_fullstack_simple_delayed_request_test bins/chttp2_simple_ssl_fullstack_simple_request_test bins/chttp2_simple_ssl_fullstack_thread_stress_test_test bins/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test bins/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test bins/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test bins/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test bins/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test bins/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test bins/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test bins/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test bins/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test bins/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test bins/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test bins/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test bins/chttp2_socket_pair_cancel_after_accept_test bins/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test bins/chttp2_socket_pair_cancel_after_invoke_test bins/chttp2_socket_pair_cancel_before_invoke_test bins/chttp2_socket_pair_cancel_in_a_vacuum_test bins/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test bins/chttp2_socket_pair_early_server_shutdown_finishes_tags_test bins/chttp2_socket_pair_invoke_large_request_test bins/chttp2_socket_pair_max_concurrent_streams_test bins/chttp2_socket_pair_no_op_test bins/chttp2_socket_pair_ping_pong_streaming_test bins/chttp2_socket_pair_request_response_with_metadata_and_payload_test bins/chttp2_socket_pair_request_response_with_payload_test bins/chttp2_socket_pair_simple_delayed_request_test bins/chttp2_socket_pair_simple_request_test bins/chttp2_socket_pair_thread_stress_test_test bins/chttp2_socket_pair_writes_done_hangs_with_pending_read_test
+
+tests: buildtests
+	$(E) "[RUN]     Testing grpc_byte_buffer_reader_test"
+	$(Q) ./bins/grpc_byte_buffer_reader_test || ( echo test grpc_byte_buffer_reader_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_cancellable_test"
+	$(Q) ./bins/gpr_cancellable_test || ( echo test gpr_cancellable_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_log_test"
+	$(Q) ./bins/gpr_log_test || ( echo test gpr_log_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_cmdline_test"
+	$(Q) ./bins/gpr_cmdline_test || ( echo test gpr_cmdline_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_histogram_test"
+	$(Q) ./bins/gpr_histogram_test || ( echo test gpr_histogram_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_host_port_test"
+	$(Q) ./bins/gpr_host_port_test || ( echo test gpr_host_port_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_slice_buffer_test"
+	$(Q) ./bins/gpr_slice_buffer_test || ( echo test gpr_slice_buffer_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_slice_test"
+	$(Q) ./bins/gpr_slice_test || ( echo test gpr_slice_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_string_test"
+	$(Q) ./bins/gpr_string_test || ( echo test gpr_string_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_sync_test"
+	$(Q) ./bins/gpr_sync_test || ( echo test gpr_sync_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_thd_test"
+	$(Q) ./bins/gpr_thd_test || ( echo test gpr_thd_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_time_test"
+	$(Q) ./bins/gpr_time_test || ( echo test gpr_time_test failed ; exit 1 )
+	$(E) "[RUN]     Testing murmur_hash_test"
+	$(Q) ./bins/murmur_hash_test || ( echo test murmur_hash_test failed ; exit 1 )
+	$(E) "[RUN]     Testing grpc_em_test"
+	$(Q) ./bins/grpc_em_test || ( echo test grpc_em_test failed ; exit 1 )
+	$(E) "[RUN]     Testing grpc_em_pipe_test"
+	$(Q) ./bins/grpc_em_pipe_test || ( echo test grpc_em_pipe_test failed ; exit 1 )
+	$(E) "[RUN]     Testing grpc_stream_op_test"
+	$(Q) ./bins/grpc_stream_op_test || ( echo test grpc_stream_op_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_stream_encoder_test"
+	$(Q) ./bins/chttp2_stream_encoder_test || ( echo test chttp2_stream_encoder_test failed ; exit 1 )
+	$(E) "[RUN]     Testing hpack_table_test"
+	$(Q) ./bins/hpack_table_test || ( echo test hpack_table_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_stream_map_test"
+	$(Q) ./bins/chttp2_stream_map_test || ( echo test chttp2_stream_map_test failed ; exit 1 )
+	$(E) "[RUN]     Testing hpack_parser_test"
+	$(Q) ./bins/hpack_parser_test || ( echo test hpack_parser_test failed ; exit 1 )
+	$(E) "[RUN]     Testing transport_metadata_test"
+	$(Q) ./bins/transport_metadata_test || ( echo test transport_metadata_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_status_conversion_test"
+	$(Q) ./bins/chttp2_status_conversion_test || ( echo test chttp2_status_conversion_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_transport_end2end_test"
+	$(Q) ./bins/chttp2_transport_end2end_test || ( echo test chttp2_transport_end2end_test failed ; exit 1 )
+	$(E) "[RUN]     Testing grpc_tcp_test"
+	$(Q) ./bins/grpc_tcp_test || ( echo test grpc_tcp_test failed ; exit 1 )
+	$(E) "[RUN]     Testing resolve_address_test"
+	$(Q) ./bins/resolve_address_test || ( echo test resolve_address_test failed ; exit 1 )
+	$(E) "[RUN]     Testing tcp_server_test"
+	$(Q) ./bins/tcp_server_test || ( echo test tcp_server_test failed ; exit 1 )
+	$(E) "[RUN]     Testing tcp_client_test"
+	$(Q) ./bins/tcp_client_test || ( echo test tcp_client_test failed ; exit 1 )
+	$(E) "[RUN]     Testing grpc_channel_stack_test"
+	$(Q) ./bins/grpc_channel_stack_test || ( echo test grpc_channel_stack_test failed ; exit 1 )
+	$(E) "[RUN]     Testing metadata_buffer_test"
+	$(Q) ./bins/metadata_buffer_test || ( echo test metadata_buffer_test failed ; exit 1 )
+	$(E) "[RUN]     Testing grpc_completion_queue_test"
+	$(Q) ./bins/grpc_completion_queue_test || ( echo test grpc_completion_queue_test failed ; exit 1 )
+	$(E) "[RUN]     Testing census_window_stats_test"
+	$(Q) ./bins/census_window_stats_test || ( echo test census_window_stats_test failed ; exit 1 )
+	$(E) "[RUN]     Testing census_statistics_quick_test"
+	$(Q) ./bins/census_statistics_quick_test || ( echo test census_statistics_quick_test failed ; exit 1 )
+	$(E) "[RUN]     Testing census_statistics_performance_test"
+	$(Q) ./bins/census_statistics_performance_test || ( echo test census_statistics_performance_test failed ; exit 1 )
+	$(E) "[RUN]     Testing census_statistics_multiple_writers_test"
+	$(Q) ./bins/census_statistics_multiple_writers_test || ( echo test census_statistics_multiple_writers_test failed ; exit 1 )
+	$(E) "[RUN]     Testing census_statistics_multiple_writers_circular_buffer_test"
+	$(Q) ./bins/census_statistics_multiple_writers_circular_buffer_test || ( echo test census_statistics_multiple_writers_circular_buffer_test failed ; exit 1 )
+	$(E) "[RUN]     Testing census_stub_test"
+	$(Q) ./bins/census_stub_test || ( echo test census_stub_test failed ; exit 1 )
+	$(E) "[RUN]     Testing census_hash_table_test"
+	$(Q) ./bins/census_hash_table_test || ( echo test census_hash_table_test failed ; exit 1 )
+	$(E) "[RUN]     Testing fling_test"
+	$(Q) ./bins/fling_test || ( echo test fling_test failed ; exit 1 )
+	$(E) "[RUN]     Testing echo_test"
+	$(Q) ./bins/echo_test || ( echo test echo_test failed ; exit 1 )
+	$(E) "[RUN]     Testing message_compress_test"
+	$(Q) ./bins/message_compress_test || ( echo test message_compress_test failed ; exit 1 )
+	$(E) "[RUN]     Testing secure_endpoint_test"
+	$(Q) ./bins/secure_endpoint_test || ( echo test secure_endpoint_test failed ; exit 1 )
+	$(E) "[RUN]     Testing httpcli_format_request_test"
+	$(Q) ./bins/httpcli_format_request_test || ( echo test httpcli_format_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing httpcli_parser_test"
+	$(Q) ./bins/httpcli_parser_test || ( echo test httpcli_parser_test failed ; exit 1 )
+	$(E) "[RUN]     Testing httpcli_test"
+	$(Q) ./bins/httpcli_test || ( echo test httpcli_test failed ; exit 1 )
+	$(E) "[RUN]     Testing grpc_credentials_test"
+	$(Q) ./bins/grpc_credentials_test || ( echo test grpc_credentials_test failed ; exit 1 )
+	$(E) "[RUN]     Testing fling_stream_test"
+	$(Q) ./bins/fling_stream_test || ( echo test fling_stream_test failed ; exit 1 )
+	$(E) "[RUN]     Testing lame_client_test"
+	$(Q) ./bins/lame_client_test || ( echo test lame_client_test failed ; exit 1 )
+	$(E) "[RUN]     Testing thread_pool_test"
+	$(Q) ./bins/thread_pool_test || ( echo test thread_pool_test failed ; exit 1 )
+	$(E) "[RUN]     Testing status_test"
+	$(Q) ./bins/status_test || ( echo test status_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_cancel_after_accept_test"
+	$(Q) ./bins/chttp2_fake_security_cancel_after_accept_test || ( echo test chttp2_fake_security_cancel_after_accept_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_cancel_after_accept_and_writes_closed_test"
+	$(Q) ./bins/chttp2_fake_security_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_fake_security_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_cancel_after_invoke_test"
+	$(Q) ./bins/chttp2_fake_security_cancel_after_invoke_test || ( echo test chttp2_fake_security_cancel_after_invoke_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_cancel_before_invoke_test"
+	$(Q) ./bins/chttp2_fake_security_cancel_before_invoke_test || ( echo test chttp2_fake_security_cancel_before_invoke_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_cancel_in_a_vacuum_test"
+	$(Q) ./bins/chttp2_fake_security_cancel_in_a_vacuum_test || ( echo test chttp2_fake_security_cancel_in_a_vacuum_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test"
+	$(Q) ./bins/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test || ( echo test chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_early_server_shutdown_finishes_tags_test"
+	$(Q) ./bins/chttp2_fake_security_early_server_shutdown_finishes_tags_test || ( echo test chttp2_fake_security_early_server_shutdown_finishes_tags_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_invoke_large_request_test"
+	$(Q) ./bins/chttp2_fake_security_invoke_large_request_test || ( echo test chttp2_fake_security_invoke_large_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_max_concurrent_streams_test"
+	$(Q) ./bins/chttp2_fake_security_max_concurrent_streams_test || ( echo test chttp2_fake_security_max_concurrent_streams_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_no_op_test"
+	$(Q) ./bins/chttp2_fake_security_no_op_test || ( echo test chttp2_fake_security_no_op_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_ping_pong_streaming_test"
+	$(Q) ./bins/chttp2_fake_security_ping_pong_streaming_test || ( echo test chttp2_fake_security_ping_pong_streaming_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_request_response_with_metadata_and_payload_test"
+	$(Q) ./bins/chttp2_fake_security_request_response_with_metadata_and_payload_test || ( echo test chttp2_fake_security_request_response_with_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_request_response_with_payload_test"
+	$(Q) ./bins/chttp2_fake_security_request_response_with_payload_test || ( echo test chttp2_fake_security_request_response_with_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_simple_delayed_request_test"
+	$(Q) ./bins/chttp2_fake_security_simple_delayed_request_test || ( echo test chttp2_fake_security_simple_delayed_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_simple_request_test"
+	$(Q) ./bins/chttp2_fake_security_simple_request_test || ( echo test chttp2_fake_security_simple_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_thread_stress_test_test"
+	$(Q) ./bins/chttp2_fake_security_thread_stress_test_test || ( echo test chttp2_fake_security_thread_stress_test_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_writes_done_hangs_with_pending_read_test"
+	$(Q) ./bins/chttp2_fake_security_writes_done_hangs_with_pending_read_test || ( echo test chttp2_fake_security_writes_done_hangs_with_pending_read_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_cancel_after_accept_test"
+	$(Q) ./bins/chttp2_fullstack_cancel_after_accept_test || ( echo test chttp2_fullstack_cancel_after_accept_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_cancel_after_accept_and_writes_closed_test"
+	$(Q) ./bins/chttp2_fullstack_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_fullstack_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_cancel_after_invoke_test"
+	$(Q) ./bins/chttp2_fullstack_cancel_after_invoke_test || ( echo test chttp2_fullstack_cancel_after_invoke_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_cancel_before_invoke_test"
+	$(Q) ./bins/chttp2_fullstack_cancel_before_invoke_test || ( echo test chttp2_fullstack_cancel_before_invoke_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_cancel_in_a_vacuum_test"
+	$(Q) ./bins/chttp2_fullstack_cancel_in_a_vacuum_test || ( echo test chttp2_fullstack_cancel_in_a_vacuum_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test"
+	$(Q) ./bins/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test || ( echo test chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_early_server_shutdown_finishes_tags_test"
+	$(Q) ./bins/chttp2_fullstack_early_server_shutdown_finishes_tags_test || ( echo test chttp2_fullstack_early_server_shutdown_finishes_tags_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_invoke_large_request_test"
+	$(Q) ./bins/chttp2_fullstack_invoke_large_request_test || ( echo test chttp2_fullstack_invoke_large_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_max_concurrent_streams_test"
+	$(Q) ./bins/chttp2_fullstack_max_concurrent_streams_test || ( echo test chttp2_fullstack_max_concurrent_streams_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_no_op_test"
+	$(Q) ./bins/chttp2_fullstack_no_op_test || ( echo test chttp2_fullstack_no_op_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_ping_pong_streaming_test"
+	$(Q) ./bins/chttp2_fullstack_ping_pong_streaming_test || ( echo test chttp2_fullstack_ping_pong_streaming_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_request_response_with_metadata_and_payload_test"
+	$(Q) ./bins/chttp2_fullstack_request_response_with_metadata_and_payload_test || ( echo test chttp2_fullstack_request_response_with_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_request_response_with_payload_test"
+	$(Q) ./bins/chttp2_fullstack_request_response_with_payload_test || ( echo test chttp2_fullstack_request_response_with_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_simple_delayed_request_test"
+	$(Q) ./bins/chttp2_fullstack_simple_delayed_request_test || ( echo test chttp2_fullstack_simple_delayed_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_simple_request_test"
+	$(Q) ./bins/chttp2_fullstack_simple_request_test || ( echo test chttp2_fullstack_simple_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_thread_stress_test_test"
+	$(Q) ./bins/chttp2_fullstack_thread_stress_test_test || ( echo test chttp2_fullstack_thread_stress_test_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_writes_done_hangs_with_pending_read_test"
+	$(Q) ./bins/chttp2_fullstack_writes_done_hangs_with_pending_read_test || ( echo test chttp2_fullstack_writes_done_hangs_with_pending_read_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_cancel_after_accept_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_cancel_after_accept_test || ( echo test chttp2_simple_ssl_fullstack_cancel_after_accept_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_cancel_after_invoke_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_cancel_after_invoke_test || ( echo test chttp2_simple_ssl_fullstack_cancel_after_invoke_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_cancel_before_invoke_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_cancel_before_invoke_test || ( echo test chttp2_simple_ssl_fullstack_cancel_before_invoke_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test || ( echo test chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test || ( echo test chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test || ( echo test chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_invoke_large_request_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_invoke_large_request_test || ( echo test chttp2_simple_ssl_fullstack_invoke_large_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_max_concurrent_streams_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_max_concurrent_streams_test || ( echo test chttp2_simple_ssl_fullstack_max_concurrent_streams_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_no_op_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_no_op_test || ( echo test chttp2_simple_ssl_fullstack_no_op_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_ping_pong_streaming_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_ping_pong_streaming_test || ( echo test chttp2_simple_ssl_fullstack_ping_pong_streaming_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test || ( echo test chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_request_response_with_payload_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_request_response_with_payload_test || ( echo test chttp2_simple_ssl_fullstack_request_response_with_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_simple_delayed_request_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_simple_delayed_request_test || ( echo test chttp2_simple_ssl_fullstack_simple_delayed_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_simple_request_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_simple_request_test || ( echo test chttp2_simple_ssl_fullstack_simple_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_thread_stress_test_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_thread_stress_test_test || ( echo test chttp2_simple_ssl_fullstack_thread_stress_test_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test"
+	$(Q) ./bins/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test || ( echo test chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_no_op_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_no_op_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test"
+	$(Q) ./bins/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_cancel_after_accept_test"
+	$(Q) ./bins/chttp2_socket_pair_cancel_after_accept_test || ( echo test chttp2_socket_pair_cancel_after_accept_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_cancel_after_accept_and_writes_closed_test"
+	$(Q) ./bins/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_socket_pair_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_cancel_after_invoke_test"
+	$(Q) ./bins/chttp2_socket_pair_cancel_after_invoke_test || ( echo test chttp2_socket_pair_cancel_after_invoke_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_cancel_before_invoke_test"
+	$(Q) ./bins/chttp2_socket_pair_cancel_before_invoke_test || ( echo test chttp2_socket_pair_cancel_before_invoke_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_cancel_in_a_vacuum_test"
+	$(Q) ./bins/chttp2_socket_pair_cancel_in_a_vacuum_test || ( echo test chttp2_socket_pair_cancel_in_a_vacuum_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test"
+	$(Q) ./bins/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test || ( echo test chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_early_server_shutdown_finishes_tags_test"
+	$(Q) ./bins/chttp2_socket_pair_early_server_shutdown_finishes_tags_test || ( echo test chttp2_socket_pair_early_server_shutdown_finishes_tags_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_invoke_large_request_test"
+	$(Q) ./bins/chttp2_socket_pair_invoke_large_request_test || ( echo test chttp2_socket_pair_invoke_large_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_max_concurrent_streams_test"
+	$(Q) ./bins/chttp2_socket_pair_max_concurrent_streams_test || ( echo test chttp2_socket_pair_max_concurrent_streams_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_no_op_test"
+	$(Q) ./bins/chttp2_socket_pair_no_op_test || ( echo test chttp2_socket_pair_no_op_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_ping_pong_streaming_test"
+	$(Q) ./bins/chttp2_socket_pair_ping_pong_streaming_test || ( echo test chttp2_socket_pair_ping_pong_streaming_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_request_response_with_metadata_and_payload_test"
+	$(Q) ./bins/chttp2_socket_pair_request_response_with_metadata_and_payload_test || ( echo test chttp2_socket_pair_request_response_with_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_request_response_with_payload_test"
+	$(Q) ./bins/chttp2_socket_pair_request_response_with_payload_test || ( echo test chttp2_socket_pair_request_response_with_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_simple_delayed_request_test"
+	$(Q) ./bins/chttp2_socket_pair_simple_delayed_request_test || ( echo test chttp2_socket_pair_simple_delayed_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_simple_request_test"
+	$(Q) ./bins/chttp2_socket_pair_simple_request_test || ( echo test chttp2_socket_pair_simple_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_thread_stress_test_test"
+	$(Q) ./bins/chttp2_socket_pair_thread_stress_test_test || ( echo test chttp2_socket_pair_thread_stress_test_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_writes_done_hangs_with_pending_read_test"
+	$(Q) ./bins/chttp2_socket_pair_writes_done_hangs_with_pending_read_test || ( echo test chttp2_socket_pair_writes_done_hangs_with_pending_read_test failed ; exit 1 )
+
+
+tools: privatelibs bins/gen_hpack_tables
+
+buildbenchmarks: privatelibs bins/grpc_completion_queue_benchmark bins/low_level_ping_pong_benchmark
+
+benchmarks: buildbenchmarks
+
+make_dirs:
+	$(Q) mkdir -p libs
+	$(Q) mkdir -p bins
+	$(Q) mkdir -p gens
+
+strip: strip-static strip-shared
+
+strip-static: static
+	$(E) "[STRIP]   Stripping libgpr.a"
+	$(Q) $(STRIP) libs/libgpr.a
+	$(E) "[STRIP]   Stripping libgrpc.a"
+	$(Q) $(STRIP) libs/libgrpc.a
+	$(E) "[STRIP]   Stripping libgrpc++.a"
+	$(Q) $(STRIP) libs/libgrpc++.a
+	$(E) "[STRIP]   Stripping libgrpc_unsecure.a"
+	$(Q) $(STRIP) libs/libgrpc_unsecure.a
+
+strip-shared: shared
+	$(E) "[STRIP]   Stripping libgpr.so"
+	$(Q) $(STRIP) libs/libgpr.so.$(VERSION)
+	$(E) "[STRIP]   Stripping libgrpc.so"
+	$(Q) $(STRIP) libs/libgrpc.so.$(VERSION)
+	$(E) "[STRIP]   Stripping libgrpc++.so"
+	$(Q) $(STRIP) libs/libgrpc++.so.$(VERSION)
+	$(E) "[STRIP]   Stripping libgrpc_unsecure.so"
+	$(Q) $(STRIP) libs/libgrpc_unsecure.so.$(VERSION)
+
+gens/%.pb.cc : %.proto
+	$(E) "[PROTOC]  Generating protobuf CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --cpp_out=gens $<
+
+deps/%.dep : %.c
+	$(E) "[DEP]     Generating dependencies for $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(CC) $(CFLAGS) $(CPPFLAGS_NO_ARCH) -MG -M $< > $@
+
+deps/%.dep : gens/%.pb.cc
+	$(E) "[DEP]     Generating dependencies for $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS_NO_ARCH) -MG -M $< > $@
+
+deps/%.dep : %.cc
+	$(E) "[DEP]     Generating dependencies for $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS_NO_ARCH) -MG -M $< > $@
+
+objs/%.o : %.c
+	$(E) "[C]       Compiling $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+objs/%.o : gens/%.pb.cc
+	$(E) "[CXX]     Compiling $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+objs/%.o : %.cc
+	$(E) "[CXX]     Compiling $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+dep: deps_libgpr deps_libgrpc deps_libgrpc_test_util deps_libgrpc++ deps_libgrpc++_test_util deps_libend2end_fixture_chttp2_fake_security deps_libend2end_fixture_chttp2_fullstack deps_libend2end_fixture_chttp2_simple_ssl_fullstack deps_libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack deps_libend2end_fixture_chttp2_socket_pair deps_libend2end_test_cancel_after_accept deps_libend2end_test_cancel_after_accept_and_writes_closed deps_libend2end_test_cancel_after_invoke deps_libend2end_test_cancel_before_invoke deps_libend2end_test_cancel_in_a_vacuum deps_libend2end_test_early_server_shutdown_finishes_inflight_calls deps_libend2end_test_early_server_shutdown_finishes_tags deps_libend2end_test_invoke_large_request deps_libend2end_test_max_concurrent_streams deps_libend2end_test_no_op deps_libend2end_test_ping_pong_streaming deps_libend2end_test_request_response_with_metadata_and_payload deps_libend2end_test_request_response_with_payload deps_libend2end_test_simple_delayed_request deps_libend2end_test_simple_request deps_libend2end_test_thread_stress_test deps_libend2end_test_writes_done_hangs_with_pending_read deps_libend2end_certs deps_libgrpc_unsecure deps_gen_hpack_tables deps_grpc_byte_buffer_reader_test deps_gpr_cancellable_test deps_gpr_log_test deps_gpr_cmdline_test deps_gpr_histogram_test deps_gpr_host_port_test deps_gpr_slice_buffer_test deps_gpr_slice_test deps_gpr_string_test deps_gpr_sync_test deps_gpr_thd_test deps_gpr_time_test deps_murmur_hash_test deps_grpc_em_test deps_grpc_em_pipe_test deps_grpc_stream_op_test deps_chttp2_stream_encoder_test deps_hpack_table_test deps_chttp2_stream_map_test deps_hpack_parser_test deps_transport_metadata_test deps_chttp2_status_conversion_test deps_chttp2_transport_end2end_test deps_grpc_tcp_test deps_resolve_address_test deps_tcp_server_test deps_tcp_client_test deps_grpc_channel_stack_test deps_metadata_buffer_test deps_grpc_completion_queue_test deps_grpc_completion_queue_benchmark deps_census_window_stats_test deps_census_statistics_quick_test deps_census_statistics_performance_test deps_census_statistics_multiple_writers_test deps_census_statistics_multiple_writers_circular_buffer_test deps_census_stub_test deps_census_hash_table_test deps_fling_server deps_fling_client deps_fling_test deps_echo_server deps_echo_client deps_echo_test deps_low_level_ping_pong_benchmark deps_message_compress_test deps_secure_endpoint_test deps_httpcli_format_request_test deps_httpcli_parser_test deps_httpcli_test deps_grpc_credentials_test deps_fling_stream_test deps_lame_client_test deps_thread_pool_test deps_status_test deps_chttp2_fake_security_cancel_after_accept_test deps_chttp2_fake_security_cancel_after_accept_and_writes_closed_test deps_chttp2_fake_security_cancel_after_invoke_test deps_chttp2_fake_security_cancel_before_invoke_test deps_chttp2_fake_security_cancel_in_a_vacuum_test deps_chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test deps_chttp2_fake_security_early_server_shutdown_finishes_tags_test deps_chttp2_fake_security_invoke_large_request_test deps_chttp2_fake_security_max_concurrent_streams_test deps_chttp2_fake_security_no_op_test deps_chttp2_fake_security_ping_pong_streaming_test deps_chttp2_fake_security_request_response_with_metadata_and_payload_test deps_chttp2_fake_security_request_response_with_payload_test deps_chttp2_fake_security_simple_delayed_request_test deps_chttp2_fake_security_simple_request_test deps_chttp2_fake_security_thread_stress_test_test deps_chttp2_fake_security_writes_done_hangs_with_pending_read_test deps_chttp2_fullstack_cancel_after_accept_test deps_chttp2_fullstack_cancel_after_accept_and_writes_closed_test deps_chttp2_fullstack_cancel_after_invoke_test deps_chttp2_fullstack_cancel_before_invoke_test deps_chttp2_fullstack_cancel_in_a_vacuum_test deps_chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test deps_chttp2_fullstack_early_server_shutdown_finishes_tags_test deps_chttp2_fullstack_invoke_large_request_test deps_chttp2_fullstack_max_concurrent_streams_test deps_chttp2_fullstack_no_op_test deps_chttp2_fullstack_ping_pong_streaming_test deps_chttp2_fullstack_request_response_with_metadata_and_payload_test deps_chttp2_fullstack_request_response_with_payload_test deps_chttp2_fullstack_simple_delayed_request_test deps_chttp2_fullstack_simple_request_test deps_chttp2_fullstack_thread_stress_test_test deps_chttp2_fullstack_writes_done_hangs_with_pending_read_test deps_chttp2_simple_ssl_fullstack_cancel_after_accept_test deps_chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test deps_chttp2_simple_ssl_fullstack_cancel_after_invoke_test deps_chttp2_simple_ssl_fullstack_cancel_before_invoke_test deps_chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test deps_chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test deps_chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test deps_chttp2_simple_ssl_fullstack_invoke_large_request_test deps_chttp2_simple_ssl_fullstack_max_concurrent_streams_test deps_chttp2_simple_ssl_fullstack_no_op_test deps_chttp2_simple_ssl_fullstack_ping_pong_streaming_test deps_chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test deps_chttp2_simple_ssl_fullstack_request_response_with_payload_test deps_chttp2_simple_ssl_fullstack_simple_delayed_request_test deps_chttp2_simple_ssl_fullstack_simple_request_test deps_chttp2_simple_ssl_fullstack_thread_stress_test_test deps_chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test deps_chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test deps_chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test deps_chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test deps_chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test deps_chttp2_simple_ssl_with_oauth2_fullstack_no_op_test deps_chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test deps_chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test deps_chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test deps_chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test deps_chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test deps_chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test deps_chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test deps_chttp2_socket_pair_cancel_after_accept_test deps_chttp2_socket_pair_cancel_after_accept_and_writes_closed_test deps_chttp2_socket_pair_cancel_after_invoke_test deps_chttp2_socket_pair_cancel_before_invoke_test deps_chttp2_socket_pair_cancel_in_a_vacuum_test deps_chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test deps_chttp2_socket_pair_early_server_shutdown_finishes_tags_test deps_chttp2_socket_pair_invoke_large_request_test deps_chttp2_socket_pair_max_concurrent_streams_test deps_chttp2_socket_pair_no_op_test deps_chttp2_socket_pair_ping_pong_streaming_test deps_chttp2_socket_pair_request_response_with_metadata_and_payload_test deps_chttp2_socket_pair_request_response_with_payload_test deps_chttp2_socket_pair_simple_delayed_request_test deps_chttp2_socket_pair_simple_request_test deps_chttp2_socket_pair_thread_stress_test_test deps_chttp2_socket_pair_writes_done_hangs_with_pending_read_test
+
+install: install-headers install-static install-shared
+
+install-headers:
+	$(E) "[INSTALL] Installing public headers"
+	$(Q) $(foreach h, $(PUBLIC_HEADERS), $(INSTALL) $(h) $(prefix)/$(h) && ) exit 0 || exit 1
+
+install-static: static strip-static
+	$(E) "[INSTALL] Installing libgpr.a"
+	$(Q) $(INSTALL) libs/libgpr.a $(prefix)/lib/libgpr.a
+	$(E) "[INSTALL] Installing libgrpc.a"
+	$(Q) $(INSTALL) libs/libgrpc.a $(prefix)/lib/libgrpc.a
+	$(E) "[INSTALL] Installing libgrpc++.a"
+	$(Q) $(INSTALL) libs/libgrpc++.a $(prefix)/lib/libgrpc++.a
+	$(E) "[INSTALL] Installing libgrpc_unsecure.a"
+	$(Q) $(INSTALL) libs/libgrpc_unsecure.a $(prefix)/lib/libgrpc_unsecure.a
+
+install-shared: shared strip-shared
+	$(E) "[INSTALL] Installing libgpr.so"
+	$(Q) $(INSTALL) libs/libgpr.so.$(VERSION) $(prefix)/lib/libgpr.so.$(VERSION)
+	$(E) "[INSTALL] Installing libgrpc.so"
+	$(Q) $(INSTALL) libs/libgrpc.so.$(VERSION) $(prefix)/lib/libgrpc.so.$(VERSION)
+	$(E) "[INSTALL] Installing libgrpc++.so"
+	$(Q) $(INSTALL) libs/libgrpc++.so.$(VERSION) $(prefix)/lib/libgrpc++.so.$(VERSION)
+	$(E) "[INSTALL] Installing libgrpc_unsecure.so"
+	$(Q) $(INSTALL) libs/libgrpc_unsecure.so.$(VERSION) $(prefix)/lib/libgrpc_unsecure.so.$(VERSION)
+
+clean: clean_libgpr clean_libgrpc clean_libgrpc_test_util clean_libgrpc++ clean_libgrpc++_test_util clean_libend2end_fixture_chttp2_fake_security clean_libend2end_fixture_chttp2_fullstack clean_libend2end_fixture_chttp2_simple_ssl_fullstack clean_libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack clean_libend2end_fixture_chttp2_socket_pair clean_libend2end_test_cancel_after_accept clean_libend2end_test_cancel_after_accept_and_writes_closed clean_libend2end_test_cancel_after_invoke clean_libend2end_test_cancel_before_invoke clean_libend2end_test_cancel_in_a_vacuum clean_libend2end_test_early_server_shutdown_finishes_inflight_calls clean_libend2end_test_early_server_shutdown_finishes_tags clean_libend2end_test_invoke_large_request clean_libend2end_test_max_concurrent_streams clean_libend2end_test_no_op clean_libend2end_test_ping_pong_streaming clean_libend2end_test_request_response_with_metadata_and_payload clean_libend2end_test_request_response_with_payload clean_libend2end_test_simple_delayed_request clean_libend2end_test_simple_request clean_libend2end_test_thread_stress_test clean_libend2end_test_writes_done_hangs_with_pending_read clean_libend2end_certs clean_libgrpc_unsecure clean_gen_hpack_tables clean_grpc_byte_buffer_reader_test clean_gpr_cancellable_test clean_gpr_log_test clean_gpr_cmdline_test clean_gpr_histogram_test clean_gpr_host_port_test clean_gpr_slice_buffer_test clean_gpr_slice_test clean_gpr_string_test clean_gpr_sync_test clean_gpr_thd_test clean_gpr_time_test clean_murmur_hash_test clean_grpc_em_test clean_grpc_em_pipe_test clean_grpc_stream_op_test clean_chttp2_stream_encoder_test clean_hpack_table_test clean_chttp2_stream_map_test clean_hpack_parser_test clean_transport_metadata_test clean_chttp2_status_conversion_test clean_chttp2_transport_end2end_test clean_grpc_tcp_test clean_resolve_address_test clean_tcp_server_test clean_tcp_client_test clean_grpc_channel_stack_test clean_metadata_buffer_test clean_grpc_completion_queue_test clean_grpc_completion_queue_benchmark clean_census_window_stats_test clean_census_statistics_quick_test clean_census_statistics_performance_test clean_census_statistics_multiple_writers_test clean_census_statistics_multiple_writers_circular_buffer_test clean_census_stub_test clean_census_hash_table_test clean_fling_server clean_fling_client clean_fling_test clean_echo_server clean_echo_client clean_echo_test clean_low_level_ping_pong_benchmark clean_message_compress_test clean_secure_endpoint_test clean_httpcli_format_request_test clean_httpcli_parser_test clean_httpcli_test clean_grpc_credentials_test clean_fling_stream_test clean_lame_client_test clean_thread_pool_test clean_status_test clean_chttp2_fake_security_cancel_after_accept_test clean_chttp2_fake_security_cancel_after_accept_and_writes_closed_test clean_chttp2_fake_security_cancel_after_invoke_test clean_chttp2_fake_security_cancel_before_invoke_test clean_chttp2_fake_security_cancel_in_a_vacuum_test clean_chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test clean_chttp2_fake_security_early_server_shutdown_finishes_tags_test clean_chttp2_fake_security_invoke_large_request_test clean_chttp2_fake_security_max_concurrent_streams_test clean_chttp2_fake_security_no_op_test clean_chttp2_fake_security_ping_pong_streaming_test clean_chttp2_fake_security_request_response_with_metadata_and_payload_test clean_chttp2_fake_security_request_response_with_payload_test clean_chttp2_fake_security_simple_delayed_request_test clean_chttp2_fake_security_simple_request_test clean_chttp2_fake_security_thread_stress_test_test clean_chttp2_fake_security_writes_done_hangs_with_pending_read_test clean_chttp2_fullstack_cancel_after_accept_test clean_chttp2_fullstack_cancel_after_accept_and_writes_closed_test clean_chttp2_fullstack_cancel_after_invoke_test clean_chttp2_fullstack_cancel_before_invoke_test clean_chttp2_fullstack_cancel_in_a_vacuum_test clean_chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test clean_chttp2_fullstack_early_server_shutdown_finishes_tags_test clean_chttp2_fullstack_invoke_large_request_test clean_chttp2_fullstack_max_concurrent_streams_test clean_chttp2_fullstack_no_op_test clean_chttp2_fullstack_ping_pong_streaming_test clean_chttp2_fullstack_request_response_with_metadata_and_payload_test clean_chttp2_fullstack_request_response_with_payload_test clean_chttp2_fullstack_simple_delayed_request_test clean_chttp2_fullstack_simple_request_test clean_chttp2_fullstack_thread_stress_test_test clean_chttp2_fullstack_writes_done_hangs_with_pending_read_test clean_chttp2_simple_ssl_fullstack_cancel_after_accept_test clean_chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test clean_chttp2_simple_ssl_fullstack_cancel_after_invoke_test clean_chttp2_simple_ssl_fullstack_cancel_before_invoke_test clean_chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test clean_chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test clean_chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test clean_chttp2_simple_ssl_fullstack_invoke_large_request_test clean_chttp2_simple_ssl_fullstack_max_concurrent_streams_test clean_chttp2_simple_ssl_fullstack_no_op_test clean_chttp2_simple_ssl_fullstack_ping_pong_streaming_test clean_chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test clean_chttp2_simple_ssl_fullstack_request_response_with_payload_test clean_chttp2_simple_ssl_fullstack_simple_delayed_request_test clean_chttp2_simple_ssl_fullstack_simple_request_test clean_chttp2_simple_ssl_fullstack_thread_stress_test_test clean_chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test clean_chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test clean_chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test clean_chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test clean_chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test clean_chttp2_simple_ssl_with_oauth2_fullstack_no_op_test clean_chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test clean_chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test clean_chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test clean_chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test clean_chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test clean_chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test clean_chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test clean_chttp2_socket_pair_cancel_after_accept_test clean_chttp2_socket_pair_cancel_after_accept_and_writes_closed_test clean_chttp2_socket_pair_cancel_after_invoke_test clean_chttp2_socket_pair_cancel_before_invoke_test clean_chttp2_socket_pair_cancel_in_a_vacuum_test clean_chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test clean_chttp2_socket_pair_early_server_shutdown_finishes_tags_test clean_chttp2_socket_pair_invoke_large_request_test clean_chttp2_socket_pair_max_concurrent_streams_test clean_chttp2_socket_pair_no_op_test clean_chttp2_socket_pair_ping_pong_streaming_test clean_chttp2_socket_pair_request_response_with_metadata_and_payload_test clean_chttp2_socket_pair_request_response_with_payload_test clean_chttp2_socket_pair_simple_delayed_request_test clean_chttp2_socket_pair_simple_request_test clean_chttp2_socket_pair_thread_stress_test_test clean_chttp2_socket_pair_writes_done_hangs_with_pending_read_test
+	$(Q) $(RM) -r deps objs libs bins gens
+
+
+# The various libraries
+
+
+LIBGPR_SRC = \
+    src/core/support/alloc.c \
+    src/core/support/cancellable.c \
+    src/core/support/cmdline.c \
+    src/core/support/cpu_posix.c \
+    src/core/support/histogram.c \
+    src/core/support/host_port.c \
+    src/core/support/log.c \
+    src/core/support/log_posix.c \
+    src/core/support/log_linux.c \
+    src/core/support/log_android.c \
+    src/core/support/log_win32.c \
+    src/core/support/murmur_hash.c \
+    src/core/support/slice.c \
+    src/core/support/slice_buffer.c \
+    src/core/support/string.c \
+    src/core/support/string_posix.c \
+    src/core/support/sync.c \
+    src/core/support/sync_posix.c \
+    src/core/support/thd_posix.c \
+    src/core/support/thd_win32.c \
+    src/core/support/time.c \
+    src/core/support/time_posix.c \
+    src/core/support/time_win32.c \
+
+PUBLIC_HEADERS += \
+    include/grpc/support/alloc.h \
+    include/grpc/support/atm_gcc_atomic.h \
+    include/grpc/support/atm_gcc_sync.h \
+    include/grpc/support/atm.h \
+    include/grpc/support/atm_win32.h \
+    include/grpc/support/cancellable_platform.h \
+    include/grpc/support/cmdline.h \
+    include/grpc/support/histogram.h \
+    include/grpc/support/host_port.h \
+    include/grpc/support/log.h \
+    include/grpc/support/port_platform.h \
+    include/grpc/support/slice_buffer.h \
+    include/grpc/support/slice.h \
+    include/grpc/support/string.h \
+    include/grpc/support/sync_generic.h \
+    include/grpc/support/sync.h \
+    include/grpc/support/sync_posix.h \
+    include/grpc/support/sync_win32.h \
+    include/grpc/support/thd.h \
+    include/grpc/support/thd_posix.h \
+    include/grpc/support/thd_win32.h \
+    include/grpc/support/time.h \
+    include/grpc/support/time_posix.h \
+    include/grpc/support/time_win32.h \
+    include/grpc/support/useful.h \
+
+LIBGPR_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBGPR_SRC))))
+LIBGPR_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBGPR_SRC))))
+
+libs/libgpr.a: $(LIBGPR_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libgpr.a $(LIBGPR_OBJS)
+
+libs/libgpr.so.$(VERSION): $(LIBGPR_OBJS)
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) -shared -Wl,-soname,libgpr.so.0 -o libs/libgpr.so.$(VERSION) $(LIBGPR_OBJS) $(LDLIBS)
+
+deps_libgpr: $(LIBGPR_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBGPR_DEPS)
+endif
+
+clean_libgpr:
+	$(E) "[CLEAN]   Cleaning libgpr files"
+	$(Q) $(RM) $(LIBGPR_OBJS)
+	$(Q) $(RM) $(LIBGPR_DEPS)
+	$(Q) $(RM) libs/libgpr.a
+	$(Q) $(RM) libs/libgpr.so.$(VERSION)
+
+
+LIBGRPC_SRC = \
+    src/core/channel/call_op_string.c \
+    src/core/channel/census_filter.c \
+    src/core/channel/channel_args.c \
+    src/core/channel/channel_stack.c \
+    src/core/channel/client_channel.c \
+    src/core/channel/client_setup.c \
+    src/core/channel/connected_channel.c \
+    src/core/channel/http_client_filter.c \
+    src/core/channel/http_filter.c \
+    src/core/channel/http_server_filter.c \
+    src/core/channel/metadata_buffer.c \
+    src/core/channel/noop_filter.c \
+    src/core/compression/algorithm.c \
+    src/core/compression/message_compress.c \
+    src/core/endpoint/endpoint.c \
+    src/core/endpoint/resolve_address.c \
+    src/core/endpoint/socket_utils.c \
+    src/core/endpoint/socket_utils_linux.c \
+    src/core/endpoint/socket_utils_posix.c \
+    src/core/endpoint/tcp.c \
+    src/core/endpoint/tcp_client.c \
+    src/core/endpoint/tcp_server.c \
+    src/core/eventmanager/em.c \
+    src/core/eventmanager/em_posix.c \
+    src/core/surface/byte_buffer.c \
+    src/core/surface/byte_buffer_reader.c \
+    src/core/surface/call.c \
+    src/core/surface/channel.c \
+    src/core/surface/channel_create.c \
+    src/core/surface/client.c \
+    src/core/surface/lame_client.c \
+    src/core/surface/completion_queue.c \
+    src/core/surface/event_string.c \
+    src/core/surface/init.c \
+    src/core/surface/server.c \
+    src/core/surface/server_chttp2.c \
+    src/core/surface/server_create.c \
+    src/core/surface/surface_em.c \
+    src/core/transport/chttp2/frame_data.c \
+    src/core/transport/chttp2/frame_ping.c \
+    src/core/transport/chttp2/frame_rst_stream.c \
+    src/core/transport/chttp2/frame_settings.c \
+    src/core/transport/chttp2/frame_window_update.c \
+    src/core/transport/chttp2/hpack_parser.c \
+    src/core/transport/chttp2/hpack_table.c \
+    src/core/transport/chttp2/status_conversion.c \
+    src/core/transport/chttp2/stream_encoder.c \
+    src/core/transport/chttp2/stream_map.c \
+    src/core/transport/chttp2/timeout_encoding.c \
+    src/core/transport/chttp2/varint.c \
+    src/core/transport/chttp2_transport.c \
+    src/core/transport/metadata.c \
+    src/core/transport/stream_op.c \
+    src/core/transport/transport.c \
+    src/core/statistics/census_init.c \
+    src/core/statistics/census_rpc_stats.c \
+    src/core/statistics/census_tracing.c \
+    src/core/statistics/log.c \
+    src/core/statistics/window_stats.c \
+    src/core/statistics/hash_table.c \
+    src/core/httpcli/format_request.c \
+    src/core/httpcli/httpcli.c \
+    src/core/httpcli/httpcli_security_context.c \
+    src/core/httpcli/parser.c \
+    src/core/security/auth.c \
+    src/core/security/credentials.c \
+    src/core/security/google_root_certs.c \
+    src/core/security/secure_transport_setup.c \
+    src/core/security/security_context.c \
+    src/core/security/server_secure_chttp2.c \
+    src/core/surface/secure_channel_create.c \
+    src/core/surface/secure_server_create.c \
+    src/core/endpoint/secure_endpoint.c \
+    src/core/tsi/transport_security.c \
+    src/core/tsi/fake_transport_security.c \
+    src/core/tsi/ssl_transport_security.c \
+    third_party/cJSON/cJSON.c \
+
+PUBLIC_HEADERS += \
+    include/grpc/byte_buffer.h \
+    include/grpc/byte_buffer_reader.h \
+    include/grpc/grpc.h \
+    include/grpc/grpc_security.h \
+    include/grpc/status.h \
+
+LIBGRPC_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBGRPC_SRC))))
+LIBGRPC_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBGRPC_SRC))))
+
+libs/libgrpc.a: $(LIBGRPC_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libgrpc.a $(LIBGRPC_OBJS)
+
+libs/libgrpc.so.$(VERSION): $(LIBGRPC_OBJS)
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) -shared -Wl,-soname,libgrpc.so.0 -o libs/libgrpc.so.$(VERSION) $(LIBGRPC_OBJS) $(LDLIBS) $(LDLIBS_SECURE)
+
+
+deps_libgrpc: $(LIBGRPC_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBGRPC_DEPS)
+endif
+
+clean_libgrpc:
+	$(E) "[CLEAN]   Cleaning libgrpc files"
+	$(Q) $(RM) $(LIBGRPC_OBJS)
+	$(Q) $(RM) $(LIBGRPC_DEPS)
+	$(Q) $(RM) libs/libgrpc.a
+	$(Q) $(RM) libs/libgrpc.so.$(VERSION)
+
+
+LIBGRPC_TEST_UTIL_SRC = \
+    test/core/util/grpc_profiler.c \
+    test/core/util/parse_hexstring.c \
+    test/core/util/port.c \
+    test/core/util/slice_splitter.c \
+    test/core/util/test_config.c \
+    test/core/end2end/end2end_tests.c \
+    test/core/end2end/cq_verifier.c \
+    test/core/endpoint/endpoint_tests.c \
+    test/core/transport/transport_end2end_tests.c \
+    test/core/statistics/log_tests.c \
+
+
+LIBGRPC_TEST_UTIL_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBGRPC_TEST_UTIL_SRC))))
+LIBGRPC_TEST_UTIL_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBGRPC_TEST_UTIL_SRC))))
+
+libs/libgrpc_test_util.a: $(LIBGRPC_TEST_UTIL_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libgrpc_test_util.a $(LIBGRPC_TEST_UTIL_OBJS)
+
+
+
+deps_libgrpc_test_util: $(LIBGRPC_TEST_UTIL_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBGRPC_TEST_UTIL_DEPS)
+endif
+
+clean_libgrpc_test_util:
+	$(E) "[CLEAN]   Cleaning libgrpc_test_util files"
+	$(Q) $(RM) $(LIBGRPC_TEST_UTIL_OBJS)
+	$(Q) $(RM) $(LIBGRPC_TEST_UTIL_DEPS)
+	$(Q) $(RM) libs/libgrpc_test_util.a
+	$(Q) $(RM) libs/libgrpc_test_util.so.$(VERSION)
+
+
+LIBGRPC++_SRC = \
+    src/cpp/server/server.cc \
+    src/cpp/server/server_rpc_handler.cc \
+    src/cpp/server/thread_pool.cc \
+    src/cpp/server/async_server_context.cc \
+    src/cpp/server/async_server.cc \
+    src/cpp/server/completion_queue.cc \
+    src/cpp/server/server_builder.cc \
+    src/cpp/stream/stream_context.cc \
+    src/cpp/client/create_channel.cc \
+    src/cpp/client/channel.cc \
+    src/cpp/client/client_context.cc \
+    src/cpp/client/internal_stub.cc \
+    src/cpp/util/time.cc \
+    src/cpp/util/status.cc \
+    src/cpp/proto/proto_utils.cc \
+    src/cpp/rpc_method.cc \
+
+PUBLIC_HEADERS += \
+    include/grpc++/channel_interface.h \
+    include/grpc++/async_server.h \
+    include/grpc++/create_channel.h \
+    include/grpc++/server_builder.h \
+    include/grpc++/thread_pool_interface.h \
+    include/grpc++/stream_context_interface.h \
+    include/grpc++/status.h \
+    include/grpc++/config.h \
+    include/grpc++/completion_queue.h \
+    include/grpc++/stream.h \
+    include/grpc++/async_server_context.h \
+    include/grpc++/server.h \
+    include/grpc++/client_context.h \
+
+LIBGRPC++_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBGRPC++_SRC))))
+LIBGRPC++_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBGRPC++_SRC))))
+
+libs/libgrpc++.a: $(LIBGRPC++_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libgrpc++.a $(LIBGRPC++_OBJS)
+
+libs/libgrpc++.so.$(VERSION): $(LIBGRPC++_OBJS)
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LDXX) $(LDFLAGS) -shared -Wl,-soname,libgrpc++.so.0 -o libs/libgrpc++.so.$(VERSION) $(LIBGRPC++_OBJS) $(LDLIBS) $(LDLIBS_SECURE)
+
+
+deps_libgrpc++: $(LIBGRPC++_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBGRPC++_DEPS)
+endif
+
+clean_libgrpc++:
+	$(E) "[CLEAN]   Cleaning libgrpc++ files"
+	$(Q) $(RM) $(LIBGRPC++_OBJS)
+	$(Q) $(RM) $(LIBGRPC++_DEPS)
+	$(Q) $(RM) libs/libgrpc++.a
+	$(Q) $(RM) libs/libgrpc++.so.$(VERSION)
+
+
+LIBGRPC++_TEST_UTIL_SRC = \
+    test/cpp/end2end/async_test_server.cc \
+    test/cpp/util/echo.proto \
+
+
+LIBGRPC++_TEST_UTIL_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBGRPC++_TEST_UTIL_SRC))))
+LIBGRPC++_TEST_UTIL_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBGRPC++_TEST_UTIL_SRC))))
+
+libs/libgrpc++_test_util.a: $(LIBGRPC++_TEST_UTIL_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libgrpc++_test_util.a $(LIBGRPC++_TEST_UTIL_OBJS)
+
+
+
+deps_libgrpc++_test_util: $(LIBGRPC++_TEST_UTIL_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBGRPC++_TEST_UTIL_DEPS)
+endif
+
+clean_libgrpc++_test_util:
+	$(E) "[CLEAN]   Cleaning libgrpc++_test_util files"
+	$(Q) $(RM) $(LIBGRPC++_TEST_UTIL_OBJS)
+	$(Q) $(RM) $(LIBGRPC++_TEST_UTIL_DEPS)
+	$(Q) $(RM) libs/libgrpc++_test_util.a
+	$(Q) $(RM) libs/libgrpc++_test_util.so.$(VERSION)
+
+
+LIBEND2END_FIXTURE_CHTTP2_FAKE_SECURITY_SRC = \
+    test/core/end2end/fixtures/chttp2_fake_security.c \
+
+
+LIBEND2END_FIXTURE_CHTTP2_FAKE_SECURITY_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_FIXTURE_CHTTP2_FAKE_SECURITY_SRC))))
+LIBEND2END_FIXTURE_CHTTP2_FAKE_SECURITY_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_FIXTURE_CHTTP2_FAKE_SECURITY_SRC))))
+
+libs/libend2end_fixture_chttp2_fake_security.a: $(LIBEND2END_FIXTURE_CHTTP2_FAKE_SECURITY_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_fixture_chttp2_fake_security.a $(LIBEND2END_FIXTURE_CHTTP2_FAKE_SECURITY_OBJS)
+
+
+
+deps_libend2end_fixture_chttp2_fake_security: $(LIBEND2END_FIXTURE_CHTTP2_FAKE_SECURITY_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_FIXTURE_CHTTP2_FAKE_SECURITY_DEPS)
+endif
+
+clean_libend2end_fixture_chttp2_fake_security:
+	$(E) "[CLEAN]   Cleaning libend2end_fixture_chttp2_fake_security files"
+	$(Q) $(RM) $(LIBEND2END_FIXTURE_CHTTP2_FAKE_SECURITY_OBJS)
+	$(Q) $(RM) $(LIBEND2END_FIXTURE_CHTTP2_FAKE_SECURITY_DEPS)
+	$(Q) $(RM) libs/libend2end_fixture_chttp2_fake_security.a
+	$(Q) $(RM) libs/libend2end_fixture_chttp2_fake_security.so.$(VERSION)
+
+
+LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_SRC = \
+    test/core/end2end/fixtures/chttp2_fullstack.c \
+
+
+LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_SRC))))
+LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_SRC))))
+
+libs/libend2end_fixture_chttp2_fullstack.a: $(LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_fixture_chttp2_fullstack.a $(LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_OBJS)
+
+
+
+deps_libend2end_fixture_chttp2_fullstack: $(LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_DEPS)
+endif
+
+clean_libend2end_fixture_chttp2_fullstack:
+	$(E) "[CLEAN]   Cleaning libend2end_fixture_chttp2_fullstack files"
+	$(Q) $(RM) $(LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_OBJS)
+	$(Q) $(RM) $(LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_DEPS)
+	$(Q) $(RM) libs/libend2end_fixture_chttp2_fullstack.a
+	$(Q) $(RM) libs/libend2end_fixture_chttp2_fullstack.so.$(VERSION)
+
+
+LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_FULLSTACK_SRC = \
+    test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c \
+
+
+LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_FULLSTACK_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_FULLSTACK_SRC))))
+LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_FULLSTACK_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_FULLSTACK_SRC))))
+
+libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a: $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_FULLSTACK_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_FULLSTACK_OBJS)
+
+
+
+deps_libend2end_fixture_chttp2_simple_ssl_fullstack: $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_FULLSTACK_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_FULLSTACK_DEPS)
+endif
+
+clean_libend2end_fixture_chttp2_simple_ssl_fullstack:
+	$(E) "[CLEAN]   Cleaning libend2end_fixture_chttp2_simple_ssl_fullstack files"
+	$(Q) $(RM) $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_FULLSTACK_OBJS)
+	$(Q) $(RM) $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_FULLSTACK_DEPS)
+	$(Q) $(RM) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a
+	$(Q) $(RM) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.so.$(VERSION)
+
+
+LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SRC = \
+    test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c \
+
+
+LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SRC))))
+LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SRC))))
+
+libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a: $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_OBJS)
+
+
+
+deps_libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack: $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_DEPS)
+endif
+
+clean_libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack:
+	$(E) "[CLEAN]   Cleaning libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack files"
+	$(Q) $(RM) $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_OBJS)
+	$(Q) $(RM) $(LIBEND2END_FIXTURE_CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_DEPS)
+	$(Q) $(RM) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a
+	$(Q) $(RM) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.so.$(VERSION)
+
+
+LIBEND2END_FIXTURE_CHTTP2_SOCKET_PAIR_SRC = \
+    test/core/end2end/fixtures/chttp2_socket_pair.c \
+
+
+LIBEND2END_FIXTURE_CHTTP2_SOCKET_PAIR_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_FIXTURE_CHTTP2_SOCKET_PAIR_SRC))))
+LIBEND2END_FIXTURE_CHTTP2_SOCKET_PAIR_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_FIXTURE_CHTTP2_SOCKET_PAIR_SRC))))
+
+libs/libend2end_fixture_chttp2_socket_pair.a: $(LIBEND2END_FIXTURE_CHTTP2_SOCKET_PAIR_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_fixture_chttp2_socket_pair.a $(LIBEND2END_FIXTURE_CHTTP2_SOCKET_PAIR_OBJS)
+
+
+
+deps_libend2end_fixture_chttp2_socket_pair: $(LIBEND2END_FIXTURE_CHTTP2_SOCKET_PAIR_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_FIXTURE_CHTTP2_SOCKET_PAIR_DEPS)
+endif
+
+clean_libend2end_fixture_chttp2_socket_pair:
+	$(E) "[CLEAN]   Cleaning libend2end_fixture_chttp2_socket_pair files"
+	$(Q) $(RM) $(LIBEND2END_FIXTURE_CHTTP2_SOCKET_PAIR_OBJS)
+	$(Q) $(RM) $(LIBEND2END_FIXTURE_CHTTP2_SOCKET_PAIR_DEPS)
+	$(Q) $(RM) libs/libend2end_fixture_chttp2_socket_pair.a
+	$(Q) $(RM) libs/libend2end_fixture_chttp2_socket_pair.so.$(VERSION)
+
+
+LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_SRC = \
+    test/core/end2end/tests/cancel_after_accept.c \
+
+
+LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_SRC))))
+LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_SRC))))
+
+libs/libend2end_test_cancel_after_accept.a: $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_cancel_after_accept.a $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_OBJS)
+
+
+
+deps_libend2end_test_cancel_after_accept: $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_DEPS)
+endif
+
+clean_libend2end_test_cancel_after_accept:
+	$(E) "[CLEAN]   Cleaning libend2end_test_cancel_after_accept files"
+	$(Q) $(RM) $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_DEPS)
+	$(Q) $(RM) libs/libend2end_test_cancel_after_accept.a
+	$(Q) $(RM) libs/libend2end_test_cancel_after_accept.so.$(VERSION)
+
+
+LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_SRC = \
+    test/core/end2end/tests/cancel_after_accept_and_writes_closed.c \
+
+
+LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_SRC))))
+LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_SRC))))
+
+libs/libend2end_test_cancel_after_accept_and_writes_closed.a: $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_cancel_after_accept_and_writes_closed.a $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_OBJS)
+
+
+
+deps_libend2end_test_cancel_after_accept_and_writes_closed: $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_DEPS)
+endif
+
+clean_libend2end_test_cancel_after_accept_and_writes_closed:
+	$(E) "[CLEAN]   Cleaning libend2end_test_cancel_after_accept_and_writes_closed files"
+	$(Q) $(RM) $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_DEPS)
+	$(Q) $(RM) libs/libend2end_test_cancel_after_accept_and_writes_closed.a
+	$(Q) $(RM) libs/libend2end_test_cancel_after_accept_and_writes_closed.so.$(VERSION)
+
+
+LIBEND2END_TEST_CANCEL_AFTER_INVOKE_SRC = \
+    test/core/end2end/tests/cancel_after_invoke.c \
+
+
+LIBEND2END_TEST_CANCEL_AFTER_INVOKE_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_CANCEL_AFTER_INVOKE_SRC))))
+LIBEND2END_TEST_CANCEL_AFTER_INVOKE_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_CANCEL_AFTER_INVOKE_SRC))))
+
+libs/libend2end_test_cancel_after_invoke.a: $(LIBEND2END_TEST_CANCEL_AFTER_INVOKE_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_cancel_after_invoke.a $(LIBEND2END_TEST_CANCEL_AFTER_INVOKE_OBJS)
+
+
+
+deps_libend2end_test_cancel_after_invoke: $(LIBEND2END_TEST_CANCEL_AFTER_INVOKE_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_CANCEL_AFTER_INVOKE_DEPS)
+endif
+
+clean_libend2end_test_cancel_after_invoke:
+	$(E) "[CLEAN]   Cleaning libend2end_test_cancel_after_invoke files"
+	$(Q) $(RM) $(LIBEND2END_TEST_CANCEL_AFTER_INVOKE_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_CANCEL_AFTER_INVOKE_DEPS)
+	$(Q) $(RM) libs/libend2end_test_cancel_after_invoke.a
+	$(Q) $(RM) libs/libend2end_test_cancel_after_invoke.so.$(VERSION)
+
+
+LIBEND2END_TEST_CANCEL_BEFORE_INVOKE_SRC = \
+    test/core/end2end/tests/cancel_before_invoke.c \
+
+
+LIBEND2END_TEST_CANCEL_BEFORE_INVOKE_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_CANCEL_BEFORE_INVOKE_SRC))))
+LIBEND2END_TEST_CANCEL_BEFORE_INVOKE_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_CANCEL_BEFORE_INVOKE_SRC))))
+
+libs/libend2end_test_cancel_before_invoke.a: $(LIBEND2END_TEST_CANCEL_BEFORE_INVOKE_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_cancel_before_invoke.a $(LIBEND2END_TEST_CANCEL_BEFORE_INVOKE_OBJS)
+
+
+
+deps_libend2end_test_cancel_before_invoke: $(LIBEND2END_TEST_CANCEL_BEFORE_INVOKE_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_CANCEL_BEFORE_INVOKE_DEPS)
+endif
+
+clean_libend2end_test_cancel_before_invoke:
+	$(E) "[CLEAN]   Cleaning libend2end_test_cancel_before_invoke files"
+	$(Q) $(RM) $(LIBEND2END_TEST_CANCEL_BEFORE_INVOKE_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_CANCEL_BEFORE_INVOKE_DEPS)
+	$(Q) $(RM) libs/libend2end_test_cancel_before_invoke.a
+	$(Q) $(RM) libs/libend2end_test_cancel_before_invoke.so.$(VERSION)
+
+
+LIBEND2END_TEST_CANCEL_IN_A_VACUUM_SRC = \
+    test/core/end2end/tests/cancel_in_a_vacuum.c \
+
+
+LIBEND2END_TEST_CANCEL_IN_A_VACUUM_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_CANCEL_IN_A_VACUUM_SRC))))
+LIBEND2END_TEST_CANCEL_IN_A_VACUUM_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_CANCEL_IN_A_VACUUM_SRC))))
+
+libs/libend2end_test_cancel_in_a_vacuum.a: $(LIBEND2END_TEST_CANCEL_IN_A_VACUUM_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_cancel_in_a_vacuum.a $(LIBEND2END_TEST_CANCEL_IN_A_VACUUM_OBJS)
+
+
+
+deps_libend2end_test_cancel_in_a_vacuum: $(LIBEND2END_TEST_CANCEL_IN_A_VACUUM_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_CANCEL_IN_A_VACUUM_DEPS)
+endif
+
+clean_libend2end_test_cancel_in_a_vacuum:
+	$(E) "[CLEAN]   Cleaning libend2end_test_cancel_in_a_vacuum files"
+	$(Q) $(RM) $(LIBEND2END_TEST_CANCEL_IN_A_VACUUM_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_CANCEL_IN_A_VACUUM_DEPS)
+	$(Q) $(RM) libs/libend2end_test_cancel_in_a_vacuum.a
+	$(Q) $(RM) libs/libend2end_test_cancel_in_a_vacuum.so.$(VERSION)
+
+
+LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_SRC = \
+    test/core/end2end/tests/early_server_shutdown_finishes_inflight_calls.c \
+
+
+LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_SRC))))
+LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_SRC))))
+
+libs/libend2end_test_early_server_shutdown_finishes_inflight_calls.a: $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_early_server_shutdown_finishes_inflight_calls.a $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_OBJS)
+
+
+
+deps_libend2end_test_early_server_shutdown_finishes_inflight_calls: $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_DEPS)
+endif
+
+clean_libend2end_test_early_server_shutdown_finishes_inflight_calls:
+	$(E) "[CLEAN]   Cleaning libend2end_test_early_server_shutdown_finishes_inflight_calls files"
+	$(Q) $(RM) $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_DEPS)
+	$(Q) $(RM) libs/libend2end_test_early_server_shutdown_finishes_inflight_calls.a
+	$(Q) $(RM) libs/libend2end_test_early_server_shutdown_finishes_inflight_calls.so.$(VERSION)
+
+
+LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_SRC = \
+    test/core/end2end/tests/early_server_shutdown_finishes_tags.c \
+
+
+LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_SRC))))
+LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_SRC))))
+
+libs/libend2end_test_early_server_shutdown_finishes_tags.a: $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_early_server_shutdown_finishes_tags.a $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_OBJS)
+
+
+
+deps_libend2end_test_early_server_shutdown_finishes_tags: $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_DEPS)
+endif
+
+clean_libend2end_test_early_server_shutdown_finishes_tags:
+	$(E) "[CLEAN]   Cleaning libend2end_test_early_server_shutdown_finishes_tags files"
+	$(Q) $(RM) $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_DEPS)
+	$(Q) $(RM) libs/libend2end_test_early_server_shutdown_finishes_tags.a
+	$(Q) $(RM) libs/libend2end_test_early_server_shutdown_finishes_tags.so.$(VERSION)
+
+
+LIBEND2END_TEST_INVOKE_LARGE_REQUEST_SRC = \
+    test/core/end2end/tests/invoke_large_request.c \
+
+
+LIBEND2END_TEST_INVOKE_LARGE_REQUEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_INVOKE_LARGE_REQUEST_SRC))))
+LIBEND2END_TEST_INVOKE_LARGE_REQUEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_INVOKE_LARGE_REQUEST_SRC))))
+
+libs/libend2end_test_invoke_large_request.a: $(LIBEND2END_TEST_INVOKE_LARGE_REQUEST_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_invoke_large_request.a $(LIBEND2END_TEST_INVOKE_LARGE_REQUEST_OBJS)
+
+
+
+deps_libend2end_test_invoke_large_request: $(LIBEND2END_TEST_INVOKE_LARGE_REQUEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_INVOKE_LARGE_REQUEST_DEPS)
+endif
+
+clean_libend2end_test_invoke_large_request:
+	$(E) "[CLEAN]   Cleaning libend2end_test_invoke_large_request files"
+	$(Q) $(RM) $(LIBEND2END_TEST_INVOKE_LARGE_REQUEST_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_INVOKE_LARGE_REQUEST_DEPS)
+	$(Q) $(RM) libs/libend2end_test_invoke_large_request.a
+	$(Q) $(RM) libs/libend2end_test_invoke_large_request.so.$(VERSION)
+
+
+LIBEND2END_TEST_MAX_CONCURRENT_STREAMS_SRC = \
+    test/core/end2end/tests/max_concurrent_streams.c \
+
+
+LIBEND2END_TEST_MAX_CONCURRENT_STREAMS_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_MAX_CONCURRENT_STREAMS_SRC))))
+LIBEND2END_TEST_MAX_CONCURRENT_STREAMS_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_MAX_CONCURRENT_STREAMS_SRC))))
+
+libs/libend2end_test_max_concurrent_streams.a: $(LIBEND2END_TEST_MAX_CONCURRENT_STREAMS_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_max_concurrent_streams.a $(LIBEND2END_TEST_MAX_CONCURRENT_STREAMS_OBJS)
+
+
+
+deps_libend2end_test_max_concurrent_streams: $(LIBEND2END_TEST_MAX_CONCURRENT_STREAMS_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_MAX_CONCURRENT_STREAMS_DEPS)
+endif
+
+clean_libend2end_test_max_concurrent_streams:
+	$(E) "[CLEAN]   Cleaning libend2end_test_max_concurrent_streams files"
+	$(Q) $(RM) $(LIBEND2END_TEST_MAX_CONCURRENT_STREAMS_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_MAX_CONCURRENT_STREAMS_DEPS)
+	$(Q) $(RM) libs/libend2end_test_max_concurrent_streams.a
+	$(Q) $(RM) libs/libend2end_test_max_concurrent_streams.so.$(VERSION)
+
+
+LIBEND2END_TEST_NO_OP_SRC = \
+    test/core/end2end/tests/no_op.c \
+
+
+LIBEND2END_TEST_NO_OP_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_NO_OP_SRC))))
+LIBEND2END_TEST_NO_OP_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_NO_OP_SRC))))
+
+libs/libend2end_test_no_op.a: $(LIBEND2END_TEST_NO_OP_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_no_op.a $(LIBEND2END_TEST_NO_OP_OBJS)
+
+
+
+deps_libend2end_test_no_op: $(LIBEND2END_TEST_NO_OP_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_NO_OP_DEPS)
+endif
+
+clean_libend2end_test_no_op:
+	$(E) "[CLEAN]   Cleaning libend2end_test_no_op files"
+	$(Q) $(RM) $(LIBEND2END_TEST_NO_OP_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_NO_OP_DEPS)
+	$(Q) $(RM) libs/libend2end_test_no_op.a
+	$(Q) $(RM) libs/libend2end_test_no_op.so.$(VERSION)
+
+
+LIBEND2END_TEST_PING_PONG_STREAMING_SRC = \
+    test/core/end2end/tests/ping_pong_streaming.c \
+
+
+LIBEND2END_TEST_PING_PONG_STREAMING_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_PING_PONG_STREAMING_SRC))))
+LIBEND2END_TEST_PING_PONG_STREAMING_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_PING_PONG_STREAMING_SRC))))
+
+libs/libend2end_test_ping_pong_streaming.a: $(LIBEND2END_TEST_PING_PONG_STREAMING_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_ping_pong_streaming.a $(LIBEND2END_TEST_PING_PONG_STREAMING_OBJS)
+
+
+
+deps_libend2end_test_ping_pong_streaming: $(LIBEND2END_TEST_PING_PONG_STREAMING_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_PING_PONG_STREAMING_DEPS)
+endif
+
+clean_libend2end_test_ping_pong_streaming:
+	$(E) "[CLEAN]   Cleaning libend2end_test_ping_pong_streaming files"
+	$(Q) $(RM) $(LIBEND2END_TEST_PING_PONG_STREAMING_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_PING_PONG_STREAMING_DEPS)
+	$(Q) $(RM) libs/libend2end_test_ping_pong_streaming.a
+	$(Q) $(RM) libs/libend2end_test_ping_pong_streaming.so.$(VERSION)
+
+
+LIBEND2END_TEST_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_SRC = \
+    test/core/end2end/tests/request_response_with_metadata_and_payload.c \
+
+
+LIBEND2END_TEST_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_SRC))))
+LIBEND2END_TEST_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_SRC))))
+
+libs/libend2end_test_request_response_with_metadata_and_payload.a: $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_request_response_with_metadata_and_payload.a $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_OBJS)
+
+
+
+deps_libend2end_test_request_response_with_metadata_and_payload: $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_DEPS)
+endif
+
+clean_libend2end_test_request_response_with_metadata_and_payload:
+	$(E) "[CLEAN]   Cleaning libend2end_test_request_response_with_metadata_and_payload files"
+	$(Q) $(RM) $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_DEPS)
+	$(Q) $(RM) libs/libend2end_test_request_response_with_metadata_and_payload.a
+	$(Q) $(RM) libs/libend2end_test_request_response_with_metadata_and_payload.so.$(VERSION)
+
+
+LIBEND2END_TEST_REQUEST_RESPONSE_WITH_PAYLOAD_SRC = \
+    test/core/end2end/tests/request_response_with_payload.c \
+
+
+LIBEND2END_TEST_REQUEST_RESPONSE_WITH_PAYLOAD_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_PAYLOAD_SRC))))
+LIBEND2END_TEST_REQUEST_RESPONSE_WITH_PAYLOAD_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_PAYLOAD_SRC))))
+
+libs/libend2end_test_request_response_with_payload.a: $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_PAYLOAD_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_request_response_with_payload.a $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_PAYLOAD_OBJS)
+
+
+
+deps_libend2end_test_request_response_with_payload: $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_PAYLOAD_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_PAYLOAD_DEPS)
+endif
+
+clean_libend2end_test_request_response_with_payload:
+	$(E) "[CLEAN]   Cleaning libend2end_test_request_response_with_payload files"
+	$(Q) $(RM) $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_PAYLOAD_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_REQUEST_RESPONSE_WITH_PAYLOAD_DEPS)
+	$(Q) $(RM) libs/libend2end_test_request_response_with_payload.a
+	$(Q) $(RM) libs/libend2end_test_request_response_with_payload.so.$(VERSION)
+
+
+LIBEND2END_TEST_SIMPLE_DELAYED_REQUEST_SRC = \
+    test/core/end2end/tests/simple_delayed_request.c \
+
+
+LIBEND2END_TEST_SIMPLE_DELAYED_REQUEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_SIMPLE_DELAYED_REQUEST_SRC))))
+LIBEND2END_TEST_SIMPLE_DELAYED_REQUEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_SIMPLE_DELAYED_REQUEST_SRC))))
+
+libs/libend2end_test_simple_delayed_request.a: $(LIBEND2END_TEST_SIMPLE_DELAYED_REQUEST_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_simple_delayed_request.a $(LIBEND2END_TEST_SIMPLE_DELAYED_REQUEST_OBJS)
+
+
+
+deps_libend2end_test_simple_delayed_request: $(LIBEND2END_TEST_SIMPLE_DELAYED_REQUEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_SIMPLE_DELAYED_REQUEST_DEPS)
+endif
+
+clean_libend2end_test_simple_delayed_request:
+	$(E) "[CLEAN]   Cleaning libend2end_test_simple_delayed_request files"
+	$(Q) $(RM) $(LIBEND2END_TEST_SIMPLE_DELAYED_REQUEST_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_SIMPLE_DELAYED_REQUEST_DEPS)
+	$(Q) $(RM) libs/libend2end_test_simple_delayed_request.a
+	$(Q) $(RM) libs/libend2end_test_simple_delayed_request.so.$(VERSION)
+
+
+LIBEND2END_TEST_SIMPLE_REQUEST_SRC = \
+    test/core/end2end/tests/simple_request.c \
+
+
+LIBEND2END_TEST_SIMPLE_REQUEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_SIMPLE_REQUEST_SRC))))
+LIBEND2END_TEST_SIMPLE_REQUEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_SIMPLE_REQUEST_SRC))))
+
+libs/libend2end_test_simple_request.a: $(LIBEND2END_TEST_SIMPLE_REQUEST_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_simple_request.a $(LIBEND2END_TEST_SIMPLE_REQUEST_OBJS)
+
+
+
+deps_libend2end_test_simple_request: $(LIBEND2END_TEST_SIMPLE_REQUEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_SIMPLE_REQUEST_DEPS)
+endif
+
+clean_libend2end_test_simple_request:
+	$(E) "[CLEAN]   Cleaning libend2end_test_simple_request files"
+	$(Q) $(RM) $(LIBEND2END_TEST_SIMPLE_REQUEST_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_SIMPLE_REQUEST_DEPS)
+	$(Q) $(RM) libs/libend2end_test_simple_request.a
+	$(Q) $(RM) libs/libend2end_test_simple_request.so.$(VERSION)
+
+
+LIBEND2END_TEST_THREAD_STRESS_TEST_SRC = \
+    test/core/end2end/tests/thread_stress_test.c \
+
+
+LIBEND2END_TEST_THREAD_STRESS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_THREAD_STRESS_TEST_SRC))))
+LIBEND2END_TEST_THREAD_STRESS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_THREAD_STRESS_TEST_SRC))))
+
+libs/libend2end_test_thread_stress_test.a: $(LIBEND2END_TEST_THREAD_STRESS_TEST_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_thread_stress_test.a $(LIBEND2END_TEST_THREAD_STRESS_TEST_OBJS)
+
+
+
+deps_libend2end_test_thread_stress_test: $(LIBEND2END_TEST_THREAD_STRESS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_THREAD_STRESS_TEST_DEPS)
+endif
+
+clean_libend2end_test_thread_stress_test:
+	$(E) "[CLEAN]   Cleaning libend2end_test_thread_stress_test files"
+	$(Q) $(RM) $(LIBEND2END_TEST_THREAD_STRESS_TEST_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_THREAD_STRESS_TEST_DEPS)
+	$(Q) $(RM) libs/libend2end_test_thread_stress_test.a
+	$(Q) $(RM) libs/libend2end_test_thread_stress_test.so.$(VERSION)
+
+
+LIBEND2END_TEST_WRITES_DONE_HANGS_WITH_PENDING_READ_SRC = \
+    test/core/end2end/tests/writes_done_hangs_with_pending_read.c \
+
+
+LIBEND2END_TEST_WRITES_DONE_HANGS_WITH_PENDING_READ_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_WRITES_DONE_HANGS_WITH_PENDING_READ_SRC))))
+LIBEND2END_TEST_WRITES_DONE_HANGS_WITH_PENDING_READ_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_TEST_WRITES_DONE_HANGS_WITH_PENDING_READ_SRC))))
+
+libs/libend2end_test_writes_done_hangs_with_pending_read.a: $(LIBEND2END_TEST_WRITES_DONE_HANGS_WITH_PENDING_READ_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_test_writes_done_hangs_with_pending_read.a $(LIBEND2END_TEST_WRITES_DONE_HANGS_WITH_PENDING_READ_OBJS)
+
+
+
+deps_libend2end_test_writes_done_hangs_with_pending_read: $(LIBEND2END_TEST_WRITES_DONE_HANGS_WITH_PENDING_READ_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_TEST_WRITES_DONE_HANGS_WITH_PENDING_READ_DEPS)
+endif
+
+clean_libend2end_test_writes_done_hangs_with_pending_read:
+	$(E) "[CLEAN]   Cleaning libend2end_test_writes_done_hangs_with_pending_read files"
+	$(Q) $(RM) $(LIBEND2END_TEST_WRITES_DONE_HANGS_WITH_PENDING_READ_OBJS)
+	$(Q) $(RM) $(LIBEND2END_TEST_WRITES_DONE_HANGS_WITH_PENDING_READ_DEPS)
+	$(Q) $(RM) libs/libend2end_test_writes_done_hangs_with_pending_read.a
+	$(Q) $(RM) libs/libend2end_test_writes_done_hangs_with_pending_read.so.$(VERSION)
+
+
+LIBEND2END_CERTS_SRC = \
+    test/core/end2end/data/ca_cert.c \
+    test/core/end2end/data/server1_cert.c \
+    test/core/end2end/data/server1_key.c \
+
+
+LIBEND2END_CERTS_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBEND2END_CERTS_SRC))))
+LIBEND2END_CERTS_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBEND2END_CERTS_SRC))))
+
+libs/libend2end_certs.a: $(LIBEND2END_CERTS_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libend2end_certs.a $(LIBEND2END_CERTS_OBJS)
+
+
+
+deps_libend2end_certs: $(LIBEND2END_CERTS_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBEND2END_CERTS_DEPS)
+endif
+
+clean_libend2end_certs:
+	$(E) "[CLEAN]   Cleaning libend2end_certs files"
+	$(Q) $(RM) $(LIBEND2END_CERTS_OBJS)
+	$(Q) $(RM) $(LIBEND2END_CERTS_DEPS)
+	$(Q) $(RM) libs/libend2end_certs.a
+	$(Q) $(RM) libs/libend2end_certs.so.$(VERSION)
+
+
+LIBGRPC_UNSECURE_SRC = \
+    src/core/channel/call_op_string.c \
+    src/core/channel/census_filter.c \
+    src/core/channel/channel_args.c \
+    src/core/channel/channel_stack.c \
+    src/core/channel/client_channel.c \
+    src/core/channel/client_setup.c \
+    src/core/channel/connected_channel.c \
+    src/core/channel/http_client_filter.c \
+    src/core/channel/http_filter.c \
+    src/core/channel/http_server_filter.c \
+    src/core/channel/metadata_buffer.c \
+    src/core/channel/noop_filter.c \
+    src/core/compression/algorithm.c \
+    src/core/compression/message_compress.c \
+    src/core/endpoint/endpoint.c \
+    src/core/endpoint/resolve_address.c \
+    src/core/endpoint/socket_utils.c \
+    src/core/endpoint/socket_utils_linux.c \
+    src/core/endpoint/socket_utils_posix.c \
+    src/core/endpoint/tcp.c \
+    src/core/endpoint/tcp_client.c \
+    src/core/endpoint/tcp_server.c \
+    src/core/eventmanager/em.c \
+    src/core/eventmanager/em_posix.c \
+    src/core/surface/byte_buffer.c \
+    src/core/surface/byte_buffer_reader.c \
+    src/core/surface/call.c \
+    src/core/surface/channel.c \
+    src/core/surface/channel_create.c \
+    src/core/surface/client.c \
+    src/core/surface/lame_client.c \
+    src/core/surface/completion_queue.c \
+    src/core/surface/event_string.c \
+    src/core/surface/init.c \
+    src/core/surface/server.c \
+    src/core/surface/server_chttp2.c \
+    src/core/surface/server_create.c \
+    src/core/surface/surface_em.c \
+    src/core/transport/chttp2/frame_data.c \
+    src/core/transport/chttp2/frame_ping.c \
+    src/core/transport/chttp2/frame_rst_stream.c \
+    src/core/transport/chttp2/frame_settings.c \
+    src/core/transport/chttp2/frame_window_update.c \
+    src/core/transport/chttp2/hpack_parser.c \
+    src/core/transport/chttp2/hpack_table.c \
+    src/core/transport/chttp2/status_conversion.c \
+    src/core/transport/chttp2/stream_encoder.c \
+    src/core/transport/chttp2/stream_map.c \
+    src/core/transport/chttp2/timeout_encoding.c \
+    src/core/transport/chttp2/varint.c \
+    src/core/transport/chttp2_transport.c \
+    src/core/transport/metadata.c \
+    src/core/transport/stream_op.c \
+    src/core/transport/transport.c \
+    src/core/statistics/census_init.c \
+    src/core/statistics/census_rpc_stats.c \
+    src/core/statistics/census_tracing.c \
+    src/core/statistics/log.c \
+    src/core/statistics/window_stats.c \
+    src/core/statistics/hash_table.c \
+    src/core/httpcli/format_request.c \
+    src/core/httpcli/httpcli.c \
+    src/core/httpcli/httpcli_security_context.c \
+    src/core/httpcli/parser.c \
+    src/core/surface/secure_channel_create.c \
+    src/core/surface/secure_server_create.c \
+    src/core/endpoint/secure_endpoint.c \
+    third_party/cJSON/cJSON.c \
+
+PUBLIC_HEADERS += \
+    include/grpc/byte_buffer.h \
+    include/grpc/byte_buffer_reader.h \
+    include/grpc/grpc.h \
+    include/grpc/grpc_security.h \
+    include/grpc/status.h \
+
+LIBGRPC_UNSECURE_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIBGRPC_UNSECURE_SRC))))
+LIBGRPC_UNSECURE_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIBGRPC_UNSECURE_SRC))))
+
+libs/libgrpc_unsecure.a: $(LIBGRPC_UNSECURE_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/libgrpc_unsecure.a $(LIBGRPC_UNSECURE_OBJS)
+
+libs/libgrpc_unsecure.so.$(VERSION): $(LIBGRPC_UNSECURE_OBJS)
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) -shared -Wl,-soname,libgrpc_unsecure.so.0 -o libs/libgrpc_unsecure.so.$(VERSION) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LDLIBS_SECURE)
+
+
+deps_libgrpc_unsecure: $(LIBGRPC_UNSECURE_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIBGRPC_UNSECURE_DEPS)
+endif
+
+clean_libgrpc_unsecure:
+	$(E) "[CLEAN]   Cleaning libgrpc_unsecure files"
+	$(Q) $(RM) $(LIBGRPC_UNSECURE_OBJS)
+	$(Q) $(RM) $(LIBGRPC_UNSECURE_DEPS)
+	$(Q) $(RM) libs/libgrpc_unsecure.a
+	$(Q) $(RM) libs/libgrpc_unsecure.so.$(VERSION)
+
+
+
+# All of the test targets
+
+
+GEN_HPACK_TABLES_SRC = \
+    src/core/transport/chttp2/gen_hpack_tables.c \
+
+GEN_HPACK_TABLES_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GEN_HPACK_TABLES_SRC))))
+GEN_HPACK_TABLES_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GEN_HPACK_TABLES_SRC))))
+
+bins/gen_hpack_tables: $(GEN_HPACK_TABLES_OBJS) libs/libgrpc_test_util.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GEN_HPACK_TABLES_OBJS) -Llibs -lgrpc_test_util -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/gen_hpack_tables
+
+deps_gen_hpack_tables: $(GEN_HPACK_TABLES_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GEN_HPACK_TABLES_DEPS)
+endif
+
+clean_gen_hpack_tables:
+	$(E) "[CLEAN]   Cleaning gen_hpack_tables files"
+	$(Q) $(RM) $(GEN_HPACK_TABLES_OBJS)
+	$(Q) $(RM) $(GEN_HPACK_TABLES_DEPS)
+	$(Q) $(RM) bins/gen_hpack_tables
+
+
+GRPC_BYTE_BUFFER_READER_TEST_SRC = \
+    test/core/surface/byte_buffer_reader_test.c \
+
+GRPC_BYTE_BUFFER_READER_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GRPC_BYTE_BUFFER_READER_TEST_SRC))))
+GRPC_BYTE_BUFFER_READER_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GRPC_BYTE_BUFFER_READER_TEST_SRC))))
+
+bins/grpc_byte_buffer_reader_test: $(GRPC_BYTE_BUFFER_READER_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GRPC_BYTE_BUFFER_READER_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/grpc_byte_buffer_reader_test
+
+deps_grpc_byte_buffer_reader_test: $(GRPC_BYTE_BUFFER_READER_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GRPC_BYTE_BUFFER_READER_TEST_DEPS)
+endif
+
+clean_grpc_byte_buffer_reader_test:
+	$(E) "[CLEAN]   Cleaning grpc_byte_buffer_reader_test files"
+	$(Q) $(RM) $(GRPC_BYTE_BUFFER_READER_TEST_OBJS)
+	$(Q) $(RM) $(GRPC_BYTE_BUFFER_READER_TEST_DEPS)
+	$(Q) $(RM) bins/grpc_byte_buffer_reader_test
+
+
+GPR_CANCELLABLE_TEST_SRC = \
+    test/core/support/cancellable_test.c \
+
+GPR_CANCELLABLE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GPR_CANCELLABLE_TEST_SRC))))
+GPR_CANCELLABLE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GPR_CANCELLABLE_TEST_SRC))))
+
+bins/gpr_cancellable_test: $(GPR_CANCELLABLE_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GPR_CANCELLABLE_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/gpr_cancellable_test
+
+deps_gpr_cancellable_test: $(GPR_CANCELLABLE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GPR_CANCELLABLE_TEST_DEPS)
+endif
+
+clean_gpr_cancellable_test:
+	$(E) "[CLEAN]   Cleaning gpr_cancellable_test files"
+	$(Q) $(RM) $(GPR_CANCELLABLE_TEST_OBJS)
+	$(Q) $(RM) $(GPR_CANCELLABLE_TEST_DEPS)
+	$(Q) $(RM) bins/gpr_cancellable_test
+
+
+GPR_LOG_TEST_SRC = \
+    test/core/support/log_test.c \
+
+GPR_LOG_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GPR_LOG_TEST_SRC))))
+GPR_LOG_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GPR_LOG_TEST_SRC))))
+
+bins/gpr_log_test: $(GPR_LOG_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GPR_LOG_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/gpr_log_test
+
+deps_gpr_log_test: $(GPR_LOG_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GPR_LOG_TEST_DEPS)
+endif
+
+clean_gpr_log_test:
+	$(E) "[CLEAN]   Cleaning gpr_log_test files"
+	$(Q) $(RM) $(GPR_LOG_TEST_OBJS)
+	$(Q) $(RM) $(GPR_LOG_TEST_DEPS)
+	$(Q) $(RM) bins/gpr_log_test
+
+
+GPR_CMDLINE_TEST_SRC = \
+    test/core/support/cmdline_test.c \
+
+GPR_CMDLINE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GPR_CMDLINE_TEST_SRC))))
+GPR_CMDLINE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GPR_CMDLINE_TEST_SRC))))
+
+bins/gpr_cmdline_test: $(GPR_CMDLINE_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GPR_CMDLINE_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/gpr_cmdline_test
+
+deps_gpr_cmdline_test: $(GPR_CMDLINE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GPR_CMDLINE_TEST_DEPS)
+endif
+
+clean_gpr_cmdline_test:
+	$(E) "[CLEAN]   Cleaning gpr_cmdline_test files"
+	$(Q) $(RM) $(GPR_CMDLINE_TEST_OBJS)
+	$(Q) $(RM) $(GPR_CMDLINE_TEST_DEPS)
+	$(Q) $(RM) bins/gpr_cmdline_test
+
+
+GPR_HISTOGRAM_TEST_SRC = \
+    test/core/support/histogram_test.c \
+
+GPR_HISTOGRAM_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GPR_HISTOGRAM_TEST_SRC))))
+GPR_HISTOGRAM_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GPR_HISTOGRAM_TEST_SRC))))
+
+bins/gpr_histogram_test: $(GPR_HISTOGRAM_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GPR_HISTOGRAM_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/gpr_histogram_test
+
+deps_gpr_histogram_test: $(GPR_HISTOGRAM_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GPR_HISTOGRAM_TEST_DEPS)
+endif
+
+clean_gpr_histogram_test:
+	$(E) "[CLEAN]   Cleaning gpr_histogram_test files"
+	$(Q) $(RM) $(GPR_HISTOGRAM_TEST_OBJS)
+	$(Q) $(RM) $(GPR_HISTOGRAM_TEST_DEPS)
+	$(Q) $(RM) bins/gpr_histogram_test
+
+
+GPR_HOST_PORT_TEST_SRC = \
+    test/core/support/host_port_test.c \
+
+GPR_HOST_PORT_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GPR_HOST_PORT_TEST_SRC))))
+GPR_HOST_PORT_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GPR_HOST_PORT_TEST_SRC))))
+
+bins/gpr_host_port_test: $(GPR_HOST_PORT_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GPR_HOST_PORT_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/gpr_host_port_test
+
+deps_gpr_host_port_test: $(GPR_HOST_PORT_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GPR_HOST_PORT_TEST_DEPS)
+endif
+
+clean_gpr_host_port_test:
+	$(E) "[CLEAN]   Cleaning gpr_host_port_test files"
+	$(Q) $(RM) $(GPR_HOST_PORT_TEST_OBJS)
+	$(Q) $(RM) $(GPR_HOST_PORT_TEST_DEPS)
+	$(Q) $(RM) bins/gpr_host_port_test
+
+
+GPR_SLICE_BUFFER_TEST_SRC = \
+    test/core/support/slice_buffer_test.c \
+
+GPR_SLICE_BUFFER_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GPR_SLICE_BUFFER_TEST_SRC))))
+GPR_SLICE_BUFFER_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GPR_SLICE_BUFFER_TEST_SRC))))
+
+bins/gpr_slice_buffer_test: $(GPR_SLICE_BUFFER_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GPR_SLICE_BUFFER_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/gpr_slice_buffer_test
+
+deps_gpr_slice_buffer_test: $(GPR_SLICE_BUFFER_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GPR_SLICE_BUFFER_TEST_DEPS)
+endif
+
+clean_gpr_slice_buffer_test:
+	$(E) "[CLEAN]   Cleaning gpr_slice_buffer_test files"
+	$(Q) $(RM) $(GPR_SLICE_BUFFER_TEST_OBJS)
+	$(Q) $(RM) $(GPR_SLICE_BUFFER_TEST_DEPS)
+	$(Q) $(RM) bins/gpr_slice_buffer_test
+
+
+GPR_SLICE_TEST_SRC = \
+    test/core/support/slice_test.c \
+
+GPR_SLICE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GPR_SLICE_TEST_SRC))))
+GPR_SLICE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GPR_SLICE_TEST_SRC))))
+
+bins/gpr_slice_test: $(GPR_SLICE_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GPR_SLICE_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/gpr_slice_test
+
+deps_gpr_slice_test: $(GPR_SLICE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GPR_SLICE_TEST_DEPS)
+endif
+
+clean_gpr_slice_test:
+	$(E) "[CLEAN]   Cleaning gpr_slice_test files"
+	$(Q) $(RM) $(GPR_SLICE_TEST_OBJS)
+	$(Q) $(RM) $(GPR_SLICE_TEST_DEPS)
+	$(Q) $(RM) bins/gpr_slice_test
+
+
+GPR_STRING_TEST_SRC = \
+    test/core/support/string_test.c \
+
+GPR_STRING_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GPR_STRING_TEST_SRC))))
+GPR_STRING_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GPR_STRING_TEST_SRC))))
+
+bins/gpr_string_test: $(GPR_STRING_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GPR_STRING_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/gpr_string_test
+
+deps_gpr_string_test: $(GPR_STRING_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GPR_STRING_TEST_DEPS)
+endif
+
+clean_gpr_string_test:
+	$(E) "[CLEAN]   Cleaning gpr_string_test files"
+	$(Q) $(RM) $(GPR_STRING_TEST_OBJS)
+	$(Q) $(RM) $(GPR_STRING_TEST_DEPS)
+	$(Q) $(RM) bins/gpr_string_test
+
+
+GPR_SYNC_TEST_SRC = \
+    test/core/support/sync_test.c \
+
+GPR_SYNC_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GPR_SYNC_TEST_SRC))))
+GPR_SYNC_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GPR_SYNC_TEST_SRC))))
+
+bins/gpr_sync_test: $(GPR_SYNC_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GPR_SYNC_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/gpr_sync_test
+
+deps_gpr_sync_test: $(GPR_SYNC_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GPR_SYNC_TEST_DEPS)
+endif
+
+clean_gpr_sync_test:
+	$(E) "[CLEAN]   Cleaning gpr_sync_test files"
+	$(Q) $(RM) $(GPR_SYNC_TEST_OBJS)
+	$(Q) $(RM) $(GPR_SYNC_TEST_DEPS)
+	$(Q) $(RM) bins/gpr_sync_test
+
+
+GPR_THD_TEST_SRC = \
+    test/core/support/thd_test.c \
+
+GPR_THD_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GPR_THD_TEST_SRC))))
+GPR_THD_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GPR_THD_TEST_SRC))))
+
+bins/gpr_thd_test: $(GPR_THD_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GPR_THD_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/gpr_thd_test
+
+deps_gpr_thd_test: $(GPR_THD_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GPR_THD_TEST_DEPS)
+endif
+
+clean_gpr_thd_test:
+	$(E) "[CLEAN]   Cleaning gpr_thd_test files"
+	$(Q) $(RM) $(GPR_THD_TEST_OBJS)
+	$(Q) $(RM) $(GPR_THD_TEST_DEPS)
+	$(Q) $(RM) bins/gpr_thd_test
+
+
+GPR_TIME_TEST_SRC = \
+    test/core/support/time_test.c \
+
+GPR_TIME_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GPR_TIME_TEST_SRC))))
+GPR_TIME_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GPR_TIME_TEST_SRC))))
+
+bins/gpr_time_test: $(GPR_TIME_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GPR_TIME_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/gpr_time_test
+
+deps_gpr_time_test: $(GPR_TIME_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GPR_TIME_TEST_DEPS)
+endif
+
+clean_gpr_time_test:
+	$(E) "[CLEAN]   Cleaning gpr_time_test files"
+	$(Q) $(RM) $(GPR_TIME_TEST_OBJS)
+	$(Q) $(RM) $(GPR_TIME_TEST_DEPS)
+	$(Q) $(RM) bins/gpr_time_test
+
+
+MURMUR_HASH_TEST_SRC = \
+    test/core/support/murmur_hash_test.c \
+
+MURMUR_HASH_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(MURMUR_HASH_TEST_SRC))))
+MURMUR_HASH_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(MURMUR_HASH_TEST_SRC))))
+
+bins/murmur_hash_test: $(MURMUR_HASH_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(MURMUR_HASH_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/murmur_hash_test
+
+deps_murmur_hash_test: $(MURMUR_HASH_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(MURMUR_HASH_TEST_DEPS)
+endif
+
+clean_murmur_hash_test:
+	$(E) "[CLEAN]   Cleaning murmur_hash_test files"
+	$(Q) $(RM) $(MURMUR_HASH_TEST_OBJS)
+	$(Q) $(RM) $(MURMUR_HASH_TEST_DEPS)
+	$(Q) $(RM) bins/murmur_hash_test
+
+
+GRPC_EM_TEST_SRC = \
+    test/core/eventmanager/em_test.c \
+
+GRPC_EM_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GRPC_EM_TEST_SRC))))
+GRPC_EM_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GRPC_EM_TEST_SRC))))
+
+bins/grpc_em_test: $(GRPC_EM_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GRPC_EM_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/grpc_em_test
+
+deps_grpc_em_test: $(GRPC_EM_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GRPC_EM_TEST_DEPS)
+endif
+
+clean_grpc_em_test:
+	$(E) "[CLEAN]   Cleaning grpc_em_test files"
+	$(Q) $(RM) $(GRPC_EM_TEST_OBJS)
+	$(Q) $(RM) $(GRPC_EM_TEST_DEPS)
+	$(Q) $(RM) bins/grpc_em_test
+
+
+GRPC_EM_PIPE_TEST_SRC = \
+    test/core/eventmanager/em_pipe_test.c \
+
+GRPC_EM_PIPE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GRPC_EM_PIPE_TEST_SRC))))
+GRPC_EM_PIPE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GRPC_EM_PIPE_TEST_SRC))))
+
+bins/grpc_em_pipe_test: $(GRPC_EM_PIPE_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GRPC_EM_PIPE_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/grpc_em_pipe_test
+
+deps_grpc_em_pipe_test: $(GRPC_EM_PIPE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GRPC_EM_PIPE_TEST_DEPS)
+endif
+
+clean_grpc_em_pipe_test:
+	$(E) "[CLEAN]   Cleaning grpc_em_pipe_test files"
+	$(Q) $(RM) $(GRPC_EM_PIPE_TEST_OBJS)
+	$(Q) $(RM) $(GRPC_EM_PIPE_TEST_DEPS)
+	$(Q) $(RM) bins/grpc_em_pipe_test
+
+
+GRPC_STREAM_OP_TEST_SRC = \
+    test/core/transport/stream_op_test.c \
+
+GRPC_STREAM_OP_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GRPC_STREAM_OP_TEST_SRC))))
+GRPC_STREAM_OP_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GRPC_STREAM_OP_TEST_SRC))))
+
+bins/grpc_stream_op_test: $(GRPC_STREAM_OP_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GRPC_STREAM_OP_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/grpc_stream_op_test
+
+deps_grpc_stream_op_test: $(GRPC_STREAM_OP_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GRPC_STREAM_OP_TEST_DEPS)
+endif
+
+clean_grpc_stream_op_test:
+	$(E) "[CLEAN]   Cleaning grpc_stream_op_test files"
+	$(Q) $(RM) $(GRPC_STREAM_OP_TEST_OBJS)
+	$(Q) $(RM) $(GRPC_STREAM_OP_TEST_DEPS)
+	$(Q) $(RM) bins/grpc_stream_op_test
+
+
+CHTTP2_STREAM_ENCODER_TEST_SRC = \
+    test/core/transport/chttp2/stream_encoder_test.c \
+
+CHTTP2_STREAM_ENCODER_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_STREAM_ENCODER_TEST_SRC))))
+CHTTP2_STREAM_ENCODER_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_STREAM_ENCODER_TEST_SRC))))
+
+bins/chttp2_stream_encoder_test: $(CHTTP2_STREAM_ENCODER_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_STREAM_ENCODER_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_stream_encoder_test
+
+deps_chttp2_stream_encoder_test: $(CHTTP2_STREAM_ENCODER_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_STREAM_ENCODER_TEST_DEPS)
+endif
+
+clean_chttp2_stream_encoder_test:
+	$(E) "[CLEAN]   Cleaning chttp2_stream_encoder_test files"
+	$(Q) $(RM) $(CHTTP2_STREAM_ENCODER_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_STREAM_ENCODER_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_stream_encoder_test
+
+
+HPACK_TABLE_TEST_SRC = \
+    test/core/transport/chttp2/hpack_table_test.c \
+
+HPACK_TABLE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(HPACK_TABLE_TEST_SRC))))
+HPACK_TABLE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(HPACK_TABLE_TEST_SRC))))
+
+bins/hpack_table_test: $(HPACK_TABLE_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(HPACK_TABLE_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/hpack_table_test
+
+deps_hpack_table_test: $(HPACK_TABLE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(HPACK_TABLE_TEST_DEPS)
+endif
+
+clean_hpack_table_test:
+	$(E) "[CLEAN]   Cleaning hpack_table_test files"
+	$(Q) $(RM) $(HPACK_TABLE_TEST_OBJS)
+	$(Q) $(RM) $(HPACK_TABLE_TEST_DEPS)
+	$(Q) $(RM) bins/hpack_table_test
+
+
+CHTTP2_STREAM_MAP_TEST_SRC = \
+    test/core/transport/chttp2/stream_map_test.c \
+
+CHTTP2_STREAM_MAP_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_STREAM_MAP_TEST_SRC))))
+CHTTP2_STREAM_MAP_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_STREAM_MAP_TEST_SRC))))
+
+bins/chttp2_stream_map_test: $(CHTTP2_STREAM_MAP_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_STREAM_MAP_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_stream_map_test
+
+deps_chttp2_stream_map_test: $(CHTTP2_STREAM_MAP_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_STREAM_MAP_TEST_DEPS)
+endif
+
+clean_chttp2_stream_map_test:
+	$(E) "[CLEAN]   Cleaning chttp2_stream_map_test files"
+	$(Q) $(RM) $(CHTTP2_STREAM_MAP_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_STREAM_MAP_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_stream_map_test
+
+
+HPACK_PARSER_TEST_SRC = \
+    test/core/transport/chttp2/hpack_parser_test.c \
+
+HPACK_PARSER_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(HPACK_PARSER_TEST_SRC))))
+HPACK_PARSER_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(HPACK_PARSER_TEST_SRC))))
+
+bins/hpack_parser_test: $(HPACK_PARSER_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(HPACK_PARSER_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/hpack_parser_test
+
+deps_hpack_parser_test: $(HPACK_PARSER_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(HPACK_PARSER_TEST_DEPS)
+endif
+
+clean_hpack_parser_test:
+	$(E) "[CLEAN]   Cleaning hpack_parser_test files"
+	$(Q) $(RM) $(HPACK_PARSER_TEST_OBJS)
+	$(Q) $(RM) $(HPACK_PARSER_TEST_DEPS)
+	$(Q) $(RM) bins/hpack_parser_test
+
+
+TRANSPORT_METADATA_TEST_SRC = \
+    test/core/transport/metadata_test.c \
+
+TRANSPORT_METADATA_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(TRANSPORT_METADATA_TEST_SRC))))
+TRANSPORT_METADATA_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(TRANSPORT_METADATA_TEST_SRC))))
+
+bins/transport_metadata_test: $(TRANSPORT_METADATA_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(TRANSPORT_METADATA_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/transport_metadata_test
+
+deps_transport_metadata_test: $(TRANSPORT_METADATA_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(TRANSPORT_METADATA_TEST_DEPS)
+endif
+
+clean_transport_metadata_test:
+	$(E) "[CLEAN]   Cleaning transport_metadata_test files"
+	$(Q) $(RM) $(TRANSPORT_METADATA_TEST_OBJS)
+	$(Q) $(RM) $(TRANSPORT_METADATA_TEST_DEPS)
+	$(Q) $(RM) bins/transport_metadata_test
+
+
+CHTTP2_STATUS_CONVERSION_TEST_SRC = \
+    test/core/transport/chttp2/status_conversion_test.c \
+
+CHTTP2_STATUS_CONVERSION_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_STATUS_CONVERSION_TEST_SRC))))
+CHTTP2_STATUS_CONVERSION_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_STATUS_CONVERSION_TEST_SRC))))
+
+bins/chttp2_status_conversion_test: $(CHTTP2_STATUS_CONVERSION_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_STATUS_CONVERSION_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_status_conversion_test
+
+deps_chttp2_status_conversion_test: $(CHTTP2_STATUS_CONVERSION_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_STATUS_CONVERSION_TEST_DEPS)
+endif
+
+clean_chttp2_status_conversion_test:
+	$(E) "[CLEAN]   Cleaning chttp2_status_conversion_test files"
+	$(Q) $(RM) $(CHTTP2_STATUS_CONVERSION_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_STATUS_CONVERSION_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_status_conversion_test
+
+
+CHTTP2_TRANSPORT_END2END_TEST_SRC = \
+    test/core/transport/chttp2_transport_end2end_test.c \
+
+CHTTP2_TRANSPORT_END2END_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_TRANSPORT_END2END_TEST_SRC))))
+CHTTP2_TRANSPORT_END2END_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_TRANSPORT_END2END_TEST_SRC))))
+
+bins/chttp2_transport_end2end_test: $(CHTTP2_TRANSPORT_END2END_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_TRANSPORT_END2END_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_transport_end2end_test
+
+deps_chttp2_transport_end2end_test: $(CHTTP2_TRANSPORT_END2END_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_TRANSPORT_END2END_TEST_DEPS)
+endif
+
+clean_chttp2_transport_end2end_test:
+	$(E) "[CLEAN]   Cleaning chttp2_transport_end2end_test files"
+	$(Q) $(RM) $(CHTTP2_TRANSPORT_END2END_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_TRANSPORT_END2END_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_transport_end2end_test
+
+
+GRPC_TCP_TEST_SRC = \
+    test/core/endpoint/tcp_test.c \
+
+GRPC_TCP_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GRPC_TCP_TEST_SRC))))
+GRPC_TCP_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GRPC_TCP_TEST_SRC))))
+
+bins/grpc_tcp_test: $(GRPC_TCP_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GRPC_TCP_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/grpc_tcp_test
+
+deps_grpc_tcp_test: $(GRPC_TCP_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GRPC_TCP_TEST_DEPS)
+endif
+
+clean_grpc_tcp_test:
+	$(E) "[CLEAN]   Cleaning grpc_tcp_test files"
+	$(Q) $(RM) $(GRPC_TCP_TEST_OBJS)
+	$(Q) $(RM) $(GRPC_TCP_TEST_DEPS)
+	$(Q) $(RM) bins/grpc_tcp_test
+
+
+RESOLVE_ADDRESS_TEST_SRC = \
+    test/core/endpoint/resolve_address_test.c \
+
+RESOLVE_ADDRESS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(RESOLVE_ADDRESS_TEST_SRC))))
+RESOLVE_ADDRESS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(RESOLVE_ADDRESS_TEST_SRC))))
+
+bins/resolve_address_test: $(RESOLVE_ADDRESS_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(RESOLVE_ADDRESS_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/resolve_address_test
+
+deps_resolve_address_test: $(RESOLVE_ADDRESS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(RESOLVE_ADDRESS_TEST_DEPS)
+endif
+
+clean_resolve_address_test:
+	$(E) "[CLEAN]   Cleaning resolve_address_test files"
+	$(Q) $(RM) $(RESOLVE_ADDRESS_TEST_OBJS)
+	$(Q) $(RM) $(RESOLVE_ADDRESS_TEST_DEPS)
+	$(Q) $(RM) bins/resolve_address_test
+
+
+TCP_SERVER_TEST_SRC = \
+    test/core/endpoint/tcp_server_test.c \
+
+TCP_SERVER_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(TCP_SERVER_TEST_SRC))))
+TCP_SERVER_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(TCP_SERVER_TEST_SRC))))
+
+bins/tcp_server_test: $(TCP_SERVER_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(TCP_SERVER_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/tcp_server_test
+
+deps_tcp_server_test: $(TCP_SERVER_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(TCP_SERVER_TEST_DEPS)
+endif
+
+clean_tcp_server_test:
+	$(E) "[CLEAN]   Cleaning tcp_server_test files"
+	$(Q) $(RM) $(TCP_SERVER_TEST_OBJS)
+	$(Q) $(RM) $(TCP_SERVER_TEST_DEPS)
+	$(Q) $(RM) bins/tcp_server_test
+
+
+TCP_CLIENT_TEST_SRC = \
+    test/core/endpoint/tcp_client_test.c \
+
+TCP_CLIENT_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(TCP_CLIENT_TEST_SRC))))
+TCP_CLIENT_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(TCP_CLIENT_TEST_SRC))))
+
+bins/tcp_client_test: $(TCP_CLIENT_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(TCP_CLIENT_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/tcp_client_test
+
+deps_tcp_client_test: $(TCP_CLIENT_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(TCP_CLIENT_TEST_DEPS)
+endif
+
+clean_tcp_client_test:
+	$(E) "[CLEAN]   Cleaning tcp_client_test files"
+	$(Q) $(RM) $(TCP_CLIENT_TEST_OBJS)
+	$(Q) $(RM) $(TCP_CLIENT_TEST_DEPS)
+	$(Q) $(RM) bins/tcp_client_test
+
+
+GRPC_CHANNEL_STACK_TEST_SRC = \
+    test/core/channel/channel_stack_test.c \
+
+GRPC_CHANNEL_STACK_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GRPC_CHANNEL_STACK_TEST_SRC))))
+GRPC_CHANNEL_STACK_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GRPC_CHANNEL_STACK_TEST_SRC))))
+
+bins/grpc_channel_stack_test: $(GRPC_CHANNEL_STACK_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GRPC_CHANNEL_STACK_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/grpc_channel_stack_test
+
+deps_grpc_channel_stack_test: $(GRPC_CHANNEL_STACK_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GRPC_CHANNEL_STACK_TEST_DEPS)
+endif
+
+clean_grpc_channel_stack_test:
+	$(E) "[CLEAN]   Cleaning grpc_channel_stack_test files"
+	$(Q) $(RM) $(GRPC_CHANNEL_STACK_TEST_OBJS)
+	$(Q) $(RM) $(GRPC_CHANNEL_STACK_TEST_DEPS)
+	$(Q) $(RM) bins/grpc_channel_stack_test
+
+
+METADATA_BUFFER_TEST_SRC = \
+    test/core/channel/metadata_buffer_test.c \
+
+METADATA_BUFFER_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(METADATA_BUFFER_TEST_SRC))))
+METADATA_BUFFER_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(METADATA_BUFFER_TEST_SRC))))
+
+bins/metadata_buffer_test: $(METADATA_BUFFER_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(METADATA_BUFFER_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/metadata_buffer_test
+
+deps_metadata_buffer_test: $(METADATA_BUFFER_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(METADATA_BUFFER_TEST_DEPS)
+endif
+
+clean_metadata_buffer_test:
+	$(E) "[CLEAN]   Cleaning metadata_buffer_test files"
+	$(Q) $(RM) $(METADATA_BUFFER_TEST_OBJS)
+	$(Q) $(RM) $(METADATA_BUFFER_TEST_DEPS)
+	$(Q) $(RM) bins/metadata_buffer_test
+
+
+GRPC_COMPLETION_QUEUE_TEST_SRC = \
+    test/core/surface/completion_queue_test.c \
+
+GRPC_COMPLETION_QUEUE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GRPC_COMPLETION_QUEUE_TEST_SRC))))
+GRPC_COMPLETION_QUEUE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GRPC_COMPLETION_QUEUE_TEST_SRC))))
+
+bins/grpc_completion_queue_test: $(GRPC_COMPLETION_QUEUE_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GRPC_COMPLETION_QUEUE_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/grpc_completion_queue_test
+
+deps_grpc_completion_queue_test: $(GRPC_COMPLETION_QUEUE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GRPC_COMPLETION_QUEUE_TEST_DEPS)
+endif
+
+clean_grpc_completion_queue_test:
+	$(E) "[CLEAN]   Cleaning grpc_completion_queue_test files"
+	$(Q) $(RM) $(GRPC_COMPLETION_QUEUE_TEST_OBJS)
+	$(Q) $(RM) $(GRPC_COMPLETION_QUEUE_TEST_DEPS)
+	$(Q) $(RM) bins/grpc_completion_queue_test
+
+
+GRPC_COMPLETION_QUEUE_BENCHMARK_SRC = \
+    test/core/surface/completion_queue_benchmark.c \
+
+GRPC_COMPLETION_QUEUE_BENCHMARK_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GRPC_COMPLETION_QUEUE_BENCHMARK_SRC))))
+GRPC_COMPLETION_QUEUE_BENCHMARK_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GRPC_COMPLETION_QUEUE_BENCHMARK_SRC))))
+
+bins/grpc_completion_queue_benchmark: $(GRPC_COMPLETION_QUEUE_BENCHMARK_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GRPC_COMPLETION_QUEUE_BENCHMARK_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/grpc_completion_queue_benchmark
+
+deps_grpc_completion_queue_benchmark: $(GRPC_COMPLETION_QUEUE_BENCHMARK_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GRPC_COMPLETION_QUEUE_BENCHMARK_DEPS)
+endif
+
+clean_grpc_completion_queue_benchmark:
+	$(E) "[CLEAN]   Cleaning grpc_completion_queue_benchmark files"
+	$(Q) $(RM) $(GRPC_COMPLETION_QUEUE_BENCHMARK_OBJS)
+	$(Q) $(RM) $(GRPC_COMPLETION_QUEUE_BENCHMARK_DEPS)
+	$(Q) $(RM) bins/grpc_completion_queue_benchmark
+
+
+CENSUS_WINDOW_STATS_TEST_SRC = \
+    test/core/statistics/window_stats_test.c \
+
+CENSUS_WINDOW_STATS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CENSUS_WINDOW_STATS_TEST_SRC))))
+CENSUS_WINDOW_STATS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CENSUS_WINDOW_STATS_TEST_SRC))))
+
+bins/census_window_stats_test: $(CENSUS_WINDOW_STATS_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CENSUS_WINDOW_STATS_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/census_window_stats_test
+
+deps_census_window_stats_test: $(CENSUS_WINDOW_STATS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CENSUS_WINDOW_STATS_TEST_DEPS)
+endif
+
+clean_census_window_stats_test:
+	$(E) "[CLEAN]   Cleaning census_window_stats_test files"
+	$(Q) $(RM) $(CENSUS_WINDOW_STATS_TEST_OBJS)
+	$(Q) $(RM) $(CENSUS_WINDOW_STATS_TEST_DEPS)
+	$(Q) $(RM) bins/census_window_stats_test
+
+
+CENSUS_STATISTICS_QUICK_TEST_SRC = \
+    test/core/statistics/quick_test.c \
+
+CENSUS_STATISTICS_QUICK_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CENSUS_STATISTICS_QUICK_TEST_SRC))))
+CENSUS_STATISTICS_QUICK_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CENSUS_STATISTICS_QUICK_TEST_SRC))))
+
+bins/census_statistics_quick_test: $(CENSUS_STATISTICS_QUICK_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CENSUS_STATISTICS_QUICK_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/census_statistics_quick_test
+
+deps_census_statistics_quick_test: $(CENSUS_STATISTICS_QUICK_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CENSUS_STATISTICS_QUICK_TEST_DEPS)
+endif
+
+clean_census_statistics_quick_test:
+	$(E) "[CLEAN]   Cleaning census_statistics_quick_test files"
+	$(Q) $(RM) $(CENSUS_STATISTICS_QUICK_TEST_OBJS)
+	$(Q) $(RM) $(CENSUS_STATISTICS_QUICK_TEST_DEPS)
+	$(Q) $(RM) bins/census_statistics_quick_test
+
+
+CENSUS_STATISTICS_PERFORMANCE_TEST_SRC = \
+    test/core/statistics/performance_test.c \
+
+CENSUS_STATISTICS_PERFORMANCE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CENSUS_STATISTICS_PERFORMANCE_TEST_SRC))))
+CENSUS_STATISTICS_PERFORMANCE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CENSUS_STATISTICS_PERFORMANCE_TEST_SRC))))
+
+bins/census_statistics_performance_test: $(CENSUS_STATISTICS_PERFORMANCE_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CENSUS_STATISTICS_PERFORMANCE_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/census_statistics_performance_test
+
+deps_census_statistics_performance_test: $(CENSUS_STATISTICS_PERFORMANCE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CENSUS_STATISTICS_PERFORMANCE_TEST_DEPS)
+endif
+
+clean_census_statistics_performance_test:
+	$(E) "[CLEAN]   Cleaning census_statistics_performance_test files"
+	$(Q) $(RM) $(CENSUS_STATISTICS_PERFORMANCE_TEST_OBJS)
+	$(Q) $(RM) $(CENSUS_STATISTICS_PERFORMANCE_TEST_DEPS)
+	$(Q) $(RM) bins/census_statistics_performance_test
+
+
+CENSUS_STATISTICS_MULTIPLE_WRITERS_TEST_SRC = \
+    test/core/statistics/multiple_writers_test.c \
+
+CENSUS_STATISTICS_MULTIPLE_WRITERS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CENSUS_STATISTICS_MULTIPLE_WRITERS_TEST_SRC))))
+CENSUS_STATISTICS_MULTIPLE_WRITERS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CENSUS_STATISTICS_MULTIPLE_WRITERS_TEST_SRC))))
+
+bins/census_statistics_multiple_writers_test: $(CENSUS_STATISTICS_MULTIPLE_WRITERS_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CENSUS_STATISTICS_MULTIPLE_WRITERS_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/census_statistics_multiple_writers_test
+
+deps_census_statistics_multiple_writers_test: $(CENSUS_STATISTICS_MULTIPLE_WRITERS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CENSUS_STATISTICS_MULTIPLE_WRITERS_TEST_DEPS)
+endif
+
+clean_census_statistics_multiple_writers_test:
+	$(E) "[CLEAN]   Cleaning census_statistics_multiple_writers_test files"
+	$(Q) $(RM) $(CENSUS_STATISTICS_MULTIPLE_WRITERS_TEST_OBJS)
+	$(Q) $(RM) $(CENSUS_STATISTICS_MULTIPLE_WRITERS_TEST_DEPS)
+	$(Q) $(RM) bins/census_statistics_multiple_writers_test
+
+
+CENSUS_STATISTICS_MULTIPLE_WRITERS_CIRCULAR_BUFFER_TEST_SRC = \
+    test/core/statistics/multiple_writers_circular_buffer_test.c \
+
+CENSUS_STATISTICS_MULTIPLE_WRITERS_CIRCULAR_BUFFER_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CENSUS_STATISTICS_MULTIPLE_WRITERS_CIRCULAR_BUFFER_TEST_SRC))))
+CENSUS_STATISTICS_MULTIPLE_WRITERS_CIRCULAR_BUFFER_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CENSUS_STATISTICS_MULTIPLE_WRITERS_CIRCULAR_BUFFER_TEST_SRC))))
+
+bins/census_statistics_multiple_writers_circular_buffer_test: $(CENSUS_STATISTICS_MULTIPLE_WRITERS_CIRCULAR_BUFFER_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CENSUS_STATISTICS_MULTIPLE_WRITERS_CIRCULAR_BUFFER_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/census_statistics_multiple_writers_circular_buffer_test
+
+deps_census_statistics_multiple_writers_circular_buffer_test: $(CENSUS_STATISTICS_MULTIPLE_WRITERS_CIRCULAR_BUFFER_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CENSUS_STATISTICS_MULTIPLE_WRITERS_CIRCULAR_BUFFER_TEST_DEPS)
+endif
+
+clean_census_statistics_multiple_writers_circular_buffer_test:
+	$(E) "[CLEAN]   Cleaning census_statistics_multiple_writers_circular_buffer_test files"
+	$(Q) $(RM) $(CENSUS_STATISTICS_MULTIPLE_WRITERS_CIRCULAR_BUFFER_TEST_OBJS)
+	$(Q) $(RM) $(CENSUS_STATISTICS_MULTIPLE_WRITERS_CIRCULAR_BUFFER_TEST_DEPS)
+	$(Q) $(RM) bins/census_statistics_multiple_writers_circular_buffer_test
+
+
+CENSUS_STUB_TEST_SRC = \
+    test/core/statistics/census_stub_test.c \
+
+CENSUS_STUB_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CENSUS_STUB_TEST_SRC))))
+CENSUS_STUB_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CENSUS_STUB_TEST_SRC))))
+
+bins/census_stub_test: $(CENSUS_STUB_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CENSUS_STUB_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/census_stub_test
+
+deps_census_stub_test: $(CENSUS_STUB_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CENSUS_STUB_TEST_DEPS)
+endif
+
+clean_census_stub_test:
+	$(E) "[CLEAN]   Cleaning census_stub_test files"
+	$(Q) $(RM) $(CENSUS_STUB_TEST_OBJS)
+	$(Q) $(RM) $(CENSUS_STUB_TEST_DEPS)
+	$(Q) $(RM) bins/census_stub_test
+
+
+CENSUS_HASH_TABLE_TEST_SRC = \
+    test/core/statistics/hash_table_test.c \
+
+CENSUS_HASH_TABLE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CENSUS_HASH_TABLE_TEST_SRC))))
+CENSUS_HASH_TABLE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CENSUS_HASH_TABLE_TEST_SRC))))
+
+bins/census_hash_table_test: $(CENSUS_HASH_TABLE_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CENSUS_HASH_TABLE_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/census_hash_table_test
+
+deps_census_hash_table_test: $(CENSUS_HASH_TABLE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CENSUS_HASH_TABLE_TEST_DEPS)
+endif
+
+clean_census_hash_table_test:
+	$(E) "[CLEAN]   Cleaning census_hash_table_test files"
+	$(Q) $(RM) $(CENSUS_HASH_TABLE_TEST_OBJS)
+	$(Q) $(RM) $(CENSUS_HASH_TABLE_TEST_DEPS)
+	$(Q) $(RM) bins/census_hash_table_test
+
+
+FLING_SERVER_SRC = \
+    test/core/fling/server.c \
+
+FLING_SERVER_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(FLING_SERVER_SRC))))
+FLING_SERVER_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(FLING_SERVER_SRC))))
+
+bins/fling_server: $(FLING_SERVER_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(FLING_SERVER_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/fling_server
+
+deps_fling_server: $(FLING_SERVER_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(FLING_SERVER_DEPS)
+endif
+
+clean_fling_server:
+	$(E) "[CLEAN]   Cleaning fling_server files"
+	$(Q) $(RM) $(FLING_SERVER_OBJS)
+	$(Q) $(RM) $(FLING_SERVER_DEPS)
+	$(Q) $(RM) bins/fling_server
+
+
+FLING_CLIENT_SRC = \
+    test/core/fling/client.c \
+
+FLING_CLIENT_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(FLING_CLIENT_SRC))))
+FLING_CLIENT_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(FLING_CLIENT_SRC))))
+
+bins/fling_client: $(FLING_CLIENT_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(FLING_CLIENT_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/fling_client
+
+deps_fling_client: $(FLING_CLIENT_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(FLING_CLIENT_DEPS)
+endif
+
+clean_fling_client:
+	$(E) "[CLEAN]   Cleaning fling_client files"
+	$(Q) $(RM) $(FLING_CLIENT_OBJS)
+	$(Q) $(RM) $(FLING_CLIENT_DEPS)
+	$(Q) $(RM) bins/fling_client
+
+
+FLING_TEST_SRC = \
+    test/core/fling/fling_test.c \
+
+FLING_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(FLING_TEST_SRC))))
+FLING_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(FLING_TEST_SRC))))
+
+bins/fling_test: $(FLING_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(FLING_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/fling_test
+
+deps_fling_test: $(FLING_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(FLING_TEST_DEPS)
+endif
+
+clean_fling_test:
+	$(E) "[CLEAN]   Cleaning fling_test files"
+	$(Q) $(RM) $(FLING_TEST_OBJS)
+	$(Q) $(RM) $(FLING_TEST_DEPS)
+	$(Q) $(RM) bins/fling_test
+
+
+ECHO_SERVER_SRC = \
+    test/core/echo/server.c \
+
+ECHO_SERVER_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(ECHO_SERVER_SRC))))
+ECHO_SERVER_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(ECHO_SERVER_SRC))))
+
+bins/echo_server: $(ECHO_SERVER_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(ECHO_SERVER_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/echo_server
+
+deps_echo_server: $(ECHO_SERVER_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(ECHO_SERVER_DEPS)
+endif
+
+clean_echo_server:
+	$(E) "[CLEAN]   Cleaning echo_server files"
+	$(Q) $(RM) $(ECHO_SERVER_OBJS)
+	$(Q) $(RM) $(ECHO_SERVER_DEPS)
+	$(Q) $(RM) bins/echo_server
+
+
+ECHO_CLIENT_SRC = \
+    test/core/echo/client.c \
+
+ECHO_CLIENT_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(ECHO_CLIENT_SRC))))
+ECHO_CLIENT_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(ECHO_CLIENT_SRC))))
+
+bins/echo_client: $(ECHO_CLIENT_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(ECHO_CLIENT_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/echo_client
+
+deps_echo_client: $(ECHO_CLIENT_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(ECHO_CLIENT_DEPS)
+endif
+
+clean_echo_client:
+	$(E) "[CLEAN]   Cleaning echo_client files"
+	$(Q) $(RM) $(ECHO_CLIENT_OBJS)
+	$(Q) $(RM) $(ECHO_CLIENT_DEPS)
+	$(Q) $(RM) bins/echo_client
+
+
+ECHO_TEST_SRC = \
+    test/core/echo/echo_test.c \
+
+ECHO_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(ECHO_TEST_SRC))))
+ECHO_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(ECHO_TEST_SRC))))
+
+bins/echo_test: $(ECHO_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(ECHO_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/echo_test
+
+deps_echo_test: $(ECHO_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(ECHO_TEST_DEPS)
+endif
+
+clean_echo_test:
+	$(E) "[CLEAN]   Cleaning echo_test files"
+	$(Q) $(RM) $(ECHO_TEST_OBJS)
+	$(Q) $(RM) $(ECHO_TEST_DEPS)
+	$(Q) $(RM) bins/echo_test
+
+
+LOW_LEVEL_PING_PONG_BENCHMARK_SRC = \
+    test/core/network_benchmarks/low_level_ping_pong.c \
+
+LOW_LEVEL_PING_PONG_BENCHMARK_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LOW_LEVEL_PING_PONG_BENCHMARK_SRC))))
+LOW_LEVEL_PING_PONG_BENCHMARK_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LOW_LEVEL_PING_PONG_BENCHMARK_SRC))))
+
+bins/low_level_ping_pong_benchmark: $(LOW_LEVEL_PING_PONG_BENCHMARK_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(LOW_LEVEL_PING_PONG_BENCHMARK_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/low_level_ping_pong_benchmark
+
+deps_low_level_ping_pong_benchmark: $(LOW_LEVEL_PING_PONG_BENCHMARK_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LOW_LEVEL_PING_PONG_BENCHMARK_DEPS)
+endif
+
+clean_low_level_ping_pong_benchmark:
+	$(E) "[CLEAN]   Cleaning low_level_ping_pong_benchmark files"
+	$(Q) $(RM) $(LOW_LEVEL_PING_PONG_BENCHMARK_OBJS)
+	$(Q) $(RM) $(LOW_LEVEL_PING_PONG_BENCHMARK_DEPS)
+	$(Q) $(RM) bins/low_level_ping_pong_benchmark
+
+
+MESSAGE_COMPRESS_TEST_SRC = \
+    test/core/compression/message_compress_test.c \
+
+MESSAGE_COMPRESS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(MESSAGE_COMPRESS_TEST_SRC))))
+MESSAGE_COMPRESS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(MESSAGE_COMPRESS_TEST_SRC))))
+
+bins/message_compress_test: $(MESSAGE_COMPRESS_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(MESSAGE_COMPRESS_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/message_compress_test
+
+deps_message_compress_test: $(MESSAGE_COMPRESS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(MESSAGE_COMPRESS_TEST_DEPS)
+endif
+
+clean_message_compress_test:
+	$(E) "[CLEAN]   Cleaning message_compress_test files"
+	$(Q) $(RM) $(MESSAGE_COMPRESS_TEST_OBJS)
+	$(Q) $(RM) $(MESSAGE_COMPRESS_TEST_DEPS)
+	$(Q) $(RM) bins/message_compress_test
+
+
+SECURE_ENDPOINT_TEST_SRC = \
+    test/core/endpoint/secure_endpoint_test.c \
+
+SECURE_ENDPOINT_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(SECURE_ENDPOINT_TEST_SRC))))
+SECURE_ENDPOINT_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(SECURE_ENDPOINT_TEST_SRC))))
+
+bins/secure_endpoint_test: $(SECURE_ENDPOINT_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(SECURE_ENDPOINT_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/secure_endpoint_test
+
+deps_secure_endpoint_test: $(SECURE_ENDPOINT_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(SECURE_ENDPOINT_TEST_DEPS)
+endif
+
+clean_secure_endpoint_test:
+	$(E) "[CLEAN]   Cleaning secure_endpoint_test files"
+	$(Q) $(RM) $(SECURE_ENDPOINT_TEST_OBJS)
+	$(Q) $(RM) $(SECURE_ENDPOINT_TEST_DEPS)
+	$(Q) $(RM) bins/secure_endpoint_test
+
+
+HTTPCLI_FORMAT_REQUEST_TEST_SRC = \
+    test/core/httpcli/format_request_test.c \
+
+HTTPCLI_FORMAT_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(HTTPCLI_FORMAT_REQUEST_TEST_SRC))))
+HTTPCLI_FORMAT_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(HTTPCLI_FORMAT_REQUEST_TEST_SRC))))
+
+bins/httpcli_format_request_test: $(HTTPCLI_FORMAT_REQUEST_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(HTTPCLI_FORMAT_REQUEST_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/httpcli_format_request_test
+
+deps_httpcli_format_request_test: $(HTTPCLI_FORMAT_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(HTTPCLI_FORMAT_REQUEST_TEST_DEPS)
+endif
+
+clean_httpcli_format_request_test:
+	$(E) "[CLEAN]   Cleaning httpcli_format_request_test files"
+	$(Q) $(RM) $(HTTPCLI_FORMAT_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(HTTPCLI_FORMAT_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/httpcli_format_request_test
+
+
+HTTPCLI_PARSER_TEST_SRC = \
+    test/core/httpcli/parser_test.c \
+
+HTTPCLI_PARSER_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(HTTPCLI_PARSER_TEST_SRC))))
+HTTPCLI_PARSER_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(HTTPCLI_PARSER_TEST_SRC))))
+
+bins/httpcli_parser_test: $(HTTPCLI_PARSER_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(HTTPCLI_PARSER_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/httpcli_parser_test
+
+deps_httpcli_parser_test: $(HTTPCLI_PARSER_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(HTTPCLI_PARSER_TEST_DEPS)
+endif
+
+clean_httpcli_parser_test:
+	$(E) "[CLEAN]   Cleaning httpcli_parser_test files"
+	$(Q) $(RM) $(HTTPCLI_PARSER_TEST_OBJS)
+	$(Q) $(RM) $(HTTPCLI_PARSER_TEST_DEPS)
+	$(Q) $(RM) bins/httpcli_parser_test
+
+
+HTTPCLI_TEST_SRC = \
+    test/core/httpcli/httpcli_test.c \
+
+HTTPCLI_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(HTTPCLI_TEST_SRC))))
+HTTPCLI_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(HTTPCLI_TEST_SRC))))
+
+bins/httpcli_test: $(HTTPCLI_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(HTTPCLI_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/httpcli_test
+
+deps_httpcli_test: $(HTTPCLI_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(HTTPCLI_TEST_DEPS)
+endif
+
+clean_httpcli_test:
+	$(E) "[CLEAN]   Cleaning httpcli_test files"
+	$(Q) $(RM) $(HTTPCLI_TEST_OBJS)
+	$(Q) $(RM) $(HTTPCLI_TEST_DEPS)
+	$(Q) $(RM) bins/httpcli_test
+
+
+GRPC_CREDENTIALS_TEST_SRC = \
+    test/core/security/credentials_test.c \
+
+GRPC_CREDENTIALS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(GRPC_CREDENTIALS_TEST_SRC))))
+GRPC_CREDENTIALS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(GRPC_CREDENTIALS_TEST_SRC))))
+
+bins/grpc_credentials_test: $(GRPC_CREDENTIALS_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(GRPC_CREDENTIALS_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/grpc_credentials_test
+
+deps_grpc_credentials_test: $(GRPC_CREDENTIALS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(GRPC_CREDENTIALS_TEST_DEPS)
+endif
+
+clean_grpc_credentials_test:
+	$(E) "[CLEAN]   Cleaning grpc_credentials_test files"
+	$(Q) $(RM) $(GRPC_CREDENTIALS_TEST_OBJS)
+	$(Q) $(RM) $(GRPC_CREDENTIALS_TEST_DEPS)
+	$(Q) $(RM) bins/grpc_credentials_test
+
+
+FLING_STREAM_TEST_SRC = \
+    test/core/fling/fling_stream_test.c \
+
+FLING_STREAM_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(FLING_STREAM_TEST_SRC))))
+FLING_STREAM_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(FLING_STREAM_TEST_SRC))))
+
+bins/fling_stream_test: $(FLING_STREAM_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(FLING_STREAM_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/fling_stream_test
+
+deps_fling_stream_test: $(FLING_STREAM_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(FLING_STREAM_TEST_DEPS)
+endif
+
+clean_fling_stream_test:
+	$(E) "[CLEAN]   Cleaning fling_stream_test files"
+	$(Q) $(RM) $(FLING_STREAM_TEST_OBJS)
+	$(Q) $(RM) $(FLING_STREAM_TEST_DEPS)
+	$(Q) $(RM) bins/fling_stream_test
+
+
+LAME_CLIENT_TEST_SRC = \
+    test/core/surface/lame_client_test.c \
+
+LAME_CLIENT_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LAME_CLIENT_TEST_SRC))))
+LAME_CLIENT_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LAME_CLIENT_TEST_SRC))))
+
+bins/lame_client_test: $(LAME_CLIENT_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(LAME_CLIENT_TEST_OBJS) -Llibs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/lame_client_test
+
+deps_lame_client_test: $(LAME_CLIENT_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LAME_CLIENT_TEST_DEPS)
+endif
+
+clean_lame_client_test:
+	$(E) "[CLEAN]   Cleaning lame_client_test files"
+	$(Q) $(RM) $(LAME_CLIENT_TEST_OBJS)
+	$(Q) $(RM) $(LAME_CLIENT_TEST_DEPS)
+	$(Q) $(RM) bins/lame_client_test
+
+
+THREAD_POOL_TEST_SRC = \
+    test/cpp/server/thread_pool_test.cc \
+
+THREAD_POOL_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(THREAD_POOL_TEST_SRC))))
+THREAD_POOL_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(THREAD_POOL_TEST_SRC))))
+
+bins/thread_pool_test: $(THREAD_POOL_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc++.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LDXX) $(LDFLAGS) $(THREAD_POOL_TEST_OBJS) $(GTEST_LIB) -Llibs -lgrpc_test_util -lgrpc++ -lgrpc -lgpr $(LDLIBSXX) $(LDLIBS) $(LDLIBS_SECURE) -o bins/thread_pool_test
+
+deps_thread_pool_test: $(THREAD_POOL_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(THREAD_POOL_TEST_DEPS)
+endif
+
+clean_thread_pool_test:
+	$(E) "[CLEAN]   Cleaning thread_pool_test files"
+	$(Q) $(RM) $(THREAD_POOL_TEST_OBJS)
+	$(Q) $(RM) $(THREAD_POOL_TEST_DEPS)
+	$(Q) $(RM) bins/thread_pool_test
+
+
+STATUS_TEST_SRC = \
+    test/cpp/util/status_test.cc \
+
+STATUS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(STATUS_TEST_SRC))))
+STATUS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(STATUS_TEST_SRC))))
+
+bins/status_test: $(STATUS_TEST_OBJS) libs/libgrpc_test_util.a libs/libgrpc++.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LDXX) $(LDFLAGS) $(STATUS_TEST_OBJS) $(GTEST_LIB) -Llibs -lgrpc_test_util -lgrpc++ -lgrpc -lgpr $(LDLIBSXX) $(LDLIBS) $(LDLIBS_SECURE) -o bins/status_test
+
+deps_status_test: $(STATUS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(STATUS_TEST_DEPS)
+endif
+
+clean_status_test:
+	$(E) "[CLEAN]   Cleaning status_test files"
+	$(Q) $(RM) $(STATUS_TEST_OBJS)
+	$(Q) $(RM) $(STATUS_TEST_DEPS)
+	$(Q) $(RM) bins/status_test
+
+
+CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_TEST_SRC))))
+
+bins/chttp2_fake_security_cancel_after_accept_test: $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_cancel_after_accept.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_cancel_after_accept -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_cancel_after_accept_test
+
+deps_chttp2_fake_security_cancel_after_accept_test: $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_cancel_after_accept_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_cancel_after_accept_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_cancel_after_accept_test
+
+
+CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC))))
+
+bins/chttp2_fake_security_cancel_after_accept_and_writes_closed_test: $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_cancel_after_accept_and_writes_closed.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_cancel_after_accept_and_writes_closed -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_cancel_after_accept_and_writes_closed_test
+
+deps_chttp2_fake_security_cancel_after_accept_and_writes_closed_test: $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_cancel_after_accept_and_writes_closed_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_cancel_after_accept_and_writes_closed_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_cancel_after_accept_and_writes_closed_test
+
+
+CHTTP2_FAKE_SECURITY_CANCEL_AFTER_INVOKE_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_CANCEL_AFTER_INVOKE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_INVOKE_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_CANCEL_AFTER_INVOKE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_INVOKE_TEST_SRC))))
+
+bins/chttp2_fake_security_cancel_after_invoke_test: $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_INVOKE_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_cancel_after_invoke.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_INVOKE_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_cancel_after_invoke -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_cancel_after_invoke_test
+
+deps_chttp2_fake_security_cancel_after_invoke_test: $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_INVOKE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_INVOKE_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_cancel_after_invoke_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_cancel_after_invoke_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_INVOKE_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_INVOKE_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_cancel_after_invoke_test
+
+
+CHTTP2_FAKE_SECURITY_CANCEL_BEFORE_INVOKE_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_CANCEL_BEFORE_INVOKE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_CANCEL_BEFORE_INVOKE_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_CANCEL_BEFORE_INVOKE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_CANCEL_BEFORE_INVOKE_TEST_SRC))))
+
+bins/chttp2_fake_security_cancel_before_invoke_test: $(CHTTP2_FAKE_SECURITY_CANCEL_BEFORE_INVOKE_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_cancel_before_invoke.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_CANCEL_BEFORE_INVOKE_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_cancel_before_invoke -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_cancel_before_invoke_test
+
+deps_chttp2_fake_security_cancel_before_invoke_test: $(CHTTP2_FAKE_SECURITY_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_cancel_before_invoke_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_cancel_before_invoke_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_CANCEL_BEFORE_INVOKE_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_cancel_before_invoke_test
+
+
+CHTTP2_FAKE_SECURITY_CANCEL_IN_A_VACUUM_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_CANCEL_IN_A_VACUUM_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_CANCEL_IN_A_VACUUM_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_CANCEL_IN_A_VACUUM_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_CANCEL_IN_A_VACUUM_TEST_SRC))))
+
+bins/chttp2_fake_security_cancel_in_a_vacuum_test: $(CHTTP2_FAKE_SECURITY_CANCEL_IN_A_VACUUM_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_cancel_in_a_vacuum.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_CANCEL_IN_A_VACUUM_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_cancel_in_a_vacuum -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_cancel_in_a_vacuum_test
+
+deps_chttp2_fake_security_cancel_in_a_vacuum_test: $(CHTTP2_FAKE_SECURITY_CANCEL_IN_A_VACUUM_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_CANCEL_IN_A_VACUUM_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_cancel_in_a_vacuum_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_cancel_in_a_vacuum_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_CANCEL_IN_A_VACUUM_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_CANCEL_IN_A_VACUUM_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_cancel_in_a_vacuum_test
+
+
+CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC))))
+
+bins/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test: $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_early_server_shutdown_finishes_inflight_calls.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_early_server_shutdown_finishes_inflight_calls -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test
+
+deps_chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test: $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test
+
+
+CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC))))
+
+bins/chttp2_fake_security_early_server_shutdown_finishes_tags_test: $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_early_server_shutdown_finishes_tags.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_early_server_shutdown_finishes_tags -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_early_server_shutdown_finishes_tags_test
+
+deps_chttp2_fake_security_early_server_shutdown_finishes_tags_test: $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_early_server_shutdown_finishes_tags_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_early_server_shutdown_finishes_tags_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_early_server_shutdown_finishes_tags_test
+
+
+CHTTP2_FAKE_SECURITY_INVOKE_LARGE_REQUEST_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_INVOKE_LARGE_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_INVOKE_LARGE_REQUEST_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_INVOKE_LARGE_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_INVOKE_LARGE_REQUEST_TEST_SRC))))
+
+bins/chttp2_fake_security_invoke_large_request_test: $(CHTTP2_FAKE_SECURITY_INVOKE_LARGE_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_invoke_large_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_INVOKE_LARGE_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_invoke_large_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_invoke_large_request_test
+
+deps_chttp2_fake_security_invoke_large_request_test: $(CHTTP2_FAKE_SECURITY_INVOKE_LARGE_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_INVOKE_LARGE_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_invoke_large_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_invoke_large_request_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_INVOKE_LARGE_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_INVOKE_LARGE_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_invoke_large_request_test
+
+
+CHTTP2_FAKE_SECURITY_MAX_CONCURRENT_STREAMS_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_MAX_CONCURRENT_STREAMS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_MAX_CONCURRENT_STREAMS_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_MAX_CONCURRENT_STREAMS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_MAX_CONCURRENT_STREAMS_TEST_SRC))))
+
+bins/chttp2_fake_security_max_concurrent_streams_test: $(CHTTP2_FAKE_SECURITY_MAX_CONCURRENT_STREAMS_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_max_concurrent_streams.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_MAX_CONCURRENT_STREAMS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_max_concurrent_streams -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_max_concurrent_streams_test
+
+deps_chttp2_fake_security_max_concurrent_streams_test: $(CHTTP2_FAKE_SECURITY_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_max_concurrent_streams_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_max_concurrent_streams_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_MAX_CONCURRENT_STREAMS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_max_concurrent_streams_test
+
+
+CHTTP2_FAKE_SECURITY_NO_OP_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_NO_OP_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_NO_OP_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_NO_OP_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_NO_OP_TEST_SRC))))
+
+bins/chttp2_fake_security_no_op_test: $(CHTTP2_FAKE_SECURITY_NO_OP_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_no_op.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_NO_OP_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_no_op -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_no_op_test
+
+deps_chttp2_fake_security_no_op_test: $(CHTTP2_FAKE_SECURITY_NO_OP_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_NO_OP_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_no_op_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_no_op_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_NO_OP_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_NO_OP_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_no_op_test
+
+
+CHTTP2_FAKE_SECURITY_PING_PONG_STREAMING_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_PING_PONG_STREAMING_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_PING_PONG_STREAMING_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_PING_PONG_STREAMING_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_PING_PONG_STREAMING_TEST_SRC))))
+
+bins/chttp2_fake_security_ping_pong_streaming_test: $(CHTTP2_FAKE_SECURITY_PING_PONG_STREAMING_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_ping_pong_streaming.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_PING_PONG_STREAMING_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_ping_pong_streaming -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_ping_pong_streaming_test
+
+deps_chttp2_fake_security_ping_pong_streaming_test: $(CHTTP2_FAKE_SECURITY_PING_PONG_STREAMING_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_PING_PONG_STREAMING_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_ping_pong_streaming_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_ping_pong_streaming_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_PING_PONG_STREAMING_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_PING_PONG_STREAMING_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_ping_pong_streaming_test
+
+
+CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC))))
+
+bins/chttp2_fake_security_request_response_with_metadata_and_payload_test: $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_request_response_with_metadata_and_payload.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_request_response_with_metadata_and_payload -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_request_response_with_metadata_and_payload_test
+
+deps_chttp2_fake_security_request_response_with_metadata_and_payload_test: $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_request_response_with_metadata_and_payload_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_request_response_with_metadata_and_payload_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_request_response_with_metadata_and_payload_test
+
+
+CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC))))
+
+bins/chttp2_fake_security_request_response_with_payload_test: $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_request_response_with_payload.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_request_response_with_payload -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_request_response_with_payload_test
+
+deps_chttp2_fake_security_request_response_with_payload_test: $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_request_response_with_payload_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_request_response_with_payload_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_request_response_with_payload_test
+
+
+CHTTP2_FAKE_SECURITY_SIMPLE_DELAYED_REQUEST_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_SIMPLE_DELAYED_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_SIMPLE_DELAYED_REQUEST_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_SIMPLE_DELAYED_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_SIMPLE_DELAYED_REQUEST_TEST_SRC))))
+
+bins/chttp2_fake_security_simple_delayed_request_test: $(CHTTP2_FAKE_SECURITY_SIMPLE_DELAYED_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_simple_delayed_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_SIMPLE_DELAYED_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_simple_delayed_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_simple_delayed_request_test
+
+deps_chttp2_fake_security_simple_delayed_request_test: $(CHTTP2_FAKE_SECURITY_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_simple_delayed_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_simple_delayed_request_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_SIMPLE_DELAYED_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_simple_delayed_request_test
+
+
+CHTTP2_FAKE_SECURITY_SIMPLE_REQUEST_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_SIMPLE_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_SIMPLE_REQUEST_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_SIMPLE_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_SIMPLE_REQUEST_TEST_SRC))))
+
+bins/chttp2_fake_security_simple_request_test: $(CHTTP2_FAKE_SECURITY_SIMPLE_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_simple_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_SIMPLE_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_simple_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_simple_request_test
+
+deps_chttp2_fake_security_simple_request_test: $(CHTTP2_FAKE_SECURITY_SIMPLE_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_SIMPLE_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_simple_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_simple_request_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_SIMPLE_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_SIMPLE_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_simple_request_test
+
+
+CHTTP2_FAKE_SECURITY_THREAD_STRESS_TEST_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_THREAD_STRESS_TEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_THREAD_STRESS_TEST_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_THREAD_STRESS_TEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_THREAD_STRESS_TEST_TEST_SRC))))
+
+bins/chttp2_fake_security_thread_stress_test_test: $(CHTTP2_FAKE_SECURITY_THREAD_STRESS_TEST_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_thread_stress_test.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_THREAD_STRESS_TEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_thread_stress_test -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_thread_stress_test_test
+
+deps_chttp2_fake_security_thread_stress_test_test: $(CHTTP2_FAKE_SECURITY_THREAD_STRESS_TEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_THREAD_STRESS_TEST_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_thread_stress_test_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_thread_stress_test_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_THREAD_STRESS_TEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_THREAD_STRESS_TEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_thread_stress_test_test
+
+
+CHTTP2_FAKE_SECURITY_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC = \
+
+CHTTP2_FAKE_SECURITY_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC))))
+CHTTP2_FAKE_SECURITY_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FAKE_SECURITY_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC))))
+
+bins/chttp2_fake_security_writes_done_hangs_with_pending_read_test: $(CHTTP2_FAKE_SECURITY_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS) libs/libend2end_fixture_chttp2_fake_security.a libs/libend2end_test_writes_done_hangs_with_pending_read.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FAKE_SECURITY_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fake_security -lend2end_test_writes_done_hangs_with_pending_read -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fake_security_writes_done_hangs_with_pending_read_test
+
+deps_chttp2_fake_security_writes_done_hangs_with_pending_read_test: $(CHTTP2_FAKE_SECURITY_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FAKE_SECURITY_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+endif
+
+clean_chttp2_fake_security_writes_done_hangs_with_pending_read_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fake_security_writes_done_hangs_with_pending_read_test files"
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FAKE_SECURITY_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fake_security_writes_done_hangs_with_pending_read_test
+
+
+CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_SRC = \
+
+CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_SRC))))
+CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_SRC))))
+
+bins/chttp2_fullstack_cancel_after_accept_test: $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_cancel_after_accept.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_cancel_after_accept -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_cancel_after_accept_test
+
+deps_chttp2_fullstack_cancel_after_accept_test: $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_cancel_after_accept_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_cancel_after_accept_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_cancel_after_accept_test
+
+
+CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC = \
+
+CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC))))
+CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC))))
+
+bins/chttp2_fullstack_cancel_after_accept_and_writes_closed_test: $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_cancel_after_accept_and_writes_closed.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_cancel_after_accept_and_writes_closed -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_cancel_after_accept_and_writes_closed_test
+
+deps_chttp2_fullstack_cancel_after_accept_and_writes_closed_test: $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_cancel_after_accept_and_writes_closed_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_cancel_after_accept_and_writes_closed_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_cancel_after_accept_and_writes_closed_test
+
+
+CHTTP2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_SRC = \
+
+CHTTP2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_SRC))))
+CHTTP2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_SRC))))
+
+bins/chttp2_fullstack_cancel_after_invoke_test: $(CHTTP2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_cancel_after_invoke.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_cancel_after_invoke -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_cancel_after_invoke_test
+
+deps_chttp2_fullstack_cancel_after_invoke_test: $(CHTTP2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_cancel_after_invoke_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_cancel_after_invoke_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_cancel_after_invoke_test
+
+
+CHTTP2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_SRC = \
+
+CHTTP2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_SRC))))
+CHTTP2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_SRC))))
+
+bins/chttp2_fullstack_cancel_before_invoke_test: $(CHTTP2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_cancel_before_invoke.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_cancel_before_invoke -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_cancel_before_invoke_test
+
+deps_chttp2_fullstack_cancel_before_invoke_test: $(CHTTP2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_cancel_before_invoke_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_cancel_before_invoke_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_cancel_before_invoke_test
+
+
+CHTTP2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_SRC = \
+
+CHTTP2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_SRC))))
+CHTTP2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_SRC))))
+
+bins/chttp2_fullstack_cancel_in_a_vacuum_test: $(CHTTP2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_cancel_in_a_vacuum.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_cancel_in_a_vacuum -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_cancel_in_a_vacuum_test
+
+deps_chttp2_fullstack_cancel_in_a_vacuum_test: $(CHTTP2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_cancel_in_a_vacuum_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_cancel_in_a_vacuum_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_cancel_in_a_vacuum_test
+
+
+CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC = \
+
+CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC))))
+CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC))))
+
+bins/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test: $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_early_server_shutdown_finishes_inflight_calls.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_early_server_shutdown_finishes_inflight_calls -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test
+
+deps_chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test: $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test
+
+
+CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC = \
+
+CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC))))
+CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC))))
+
+bins/chttp2_fullstack_early_server_shutdown_finishes_tags_test: $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_early_server_shutdown_finishes_tags.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_early_server_shutdown_finishes_tags -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_early_server_shutdown_finishes_tags_test
+
+deps_chttp2_fullstack_early_server_shutdown_finishes_tags_test: $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_early_server_shutdown_finishes_tags_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_early_server_shutdown_finishes_tags_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_early_server_shutdown_finishes_tags_test
+
+
+CHTTP2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_SRC = \
+
+CHTTP2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_SRC))))
+CHTTP2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_SRC))))
+
+bins/chttp2_fullstack_invoke_large_request_test: $(CHTTP2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_invoke_large_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_invoke_large_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_invoke_large_request_test
+
+deps_chttp2_fullstack_invoke_large_request_test: $(CHTTP2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_invoke_large_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_invoke_large_request_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_invoke_large_request_test
+
+
+CHTTP2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_SRC = \
+
+CHTTP2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_SRC))))
+CHTTP2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_SRC))))
+
+bins/chttp2_fullstack_max_concurrent_streams_test: $(CHTTP2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_max_concurrent_streams.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_max_concurrent_streams -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_max_concurrent_streams_test
+
+deps_chttp2_fullstack_max_concurrent_streams_test: $(CHTTP2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_max_concurrent_streams_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_max_concurrent_streams_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_max_concurrent_streams_test
+
+
+CHTTP2_FULLSTACK_NO_OP_TEST_SRC = \
+
+CHTTP2_FULLSTACK_NO_OP_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_NO_OP_TEST_SRC))))
+CHTTP2_FULLSTACK_NO_OP_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_NO_OP_TEST_SRC))))
+
+bins/chttp2_fullstack_no_op_test: $(CHTTP2_FULLSTACK_NO_OP_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_no_op.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_NO_OP_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_no_op -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_no_op_test
+
+deps_chttp2_fullstack_no_op_test: $(CHTTP2_FULLSTACK_NO_OP_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_NO_OP_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_no_op_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_no_op_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_NO_OP_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_NO_OP_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_no_op_test
+
+
+CHTTP2_FULLSTACK_PING_PONG_STREAMING_TEST_SRC = \
+
+CHTTP2_FULLSTACK_PING_PONG_STREAMING_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_PING_PONG_STREAMING_TEST_SRC))))
+CHTTP2_FULLSTACK_PING_PONG_STREAMING_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_PING_PONG_STREAMING_TEST_SRC))))
+
+bins/chttp2_fullstack_ping_pong_streaming_test: $(CHTTP2_FULLSTACK_PING_PONG_STREAMING_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_ping_pong_streaming.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_PING_PONG_STREAMING_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_ping_pong_streaming -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_ping_pong_streaming_test
+
+deps_chttp2_fullstack_ping_pong_streaming_test: $(CHTTP2_FULLSTACK_PING_PONG_STREAMING_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_PING_PONG_STREAMING_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_ping_pong_streaming_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_ping_pong_streaming_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_PING_PONG_STREAMING_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_PING_PONG_STREAMING_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_ping_pong_streaming_test
+
+
+CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC = \
+
+CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC))))
+CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC))))
+
+bins/chttp2_fullstack_request_response_with_metadata_and_payload_test: $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_request_response_with_metadata_and_payload.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_request_response_with_metadata_and_payload -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_request_response_with_metadata_and_payload_test
+
+deps_chttp2_fullstack_request_response_with_metadata_and_payload_test: $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_request_response_with_metadata_and_payload_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_request_response_with_metadata_and_payload_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_request_response_with_metadata_and_payload_test
+
+
+CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC = \
+
+CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC))))
+CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC))))
+
+bins/chttp2_fullstack_request_response_with_payload_test: $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_request_response_with_payload.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_request_response_with_payload -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_request_response_with_payload_test
+
+deps_chttp2_fullstack_request_response_with_payload_test: $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_request_response_with_payload_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_request_response_with_payload_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_request_response_with_payload_test
+
+
+CHTTP2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_SRC = \
+
+CHTTP2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_SRC))))
+CHTTP2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_SRC))))
+
+bins/chttp2_fullstack_simple_delayed_request_test: $(CHTTP2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_simple_delayed_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_simple_delayed_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_simple_delayed_request_test
+
+deps_chttp2_fullstack_simple_delayed_request_test: $(CHTTP2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_simple_delayed_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_simple_delayed_request_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_simple_delayed_request_test
+
+
+CHTTP2_FULLSTACK_SIMPLE_REQUEST_TEST_SRC = \
+
+CHTTP2_FULLSTACK_SIMPLE_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_SIMPLE_REQUEST_TEST_SRC))))
+CHTTP2_FULLSTACK_SIMPLE_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_SIMPLE_REQUEST_TEST_SRC))))
+
+bins/chttp2_fullstack_simple_request_test: $(CHTTP2_FULLSTACK_SIMPLE_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_simple_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_SIMPLE_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_simple_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_simple_request_test
+
+deps_chttp2_fullstack_simple_request_test: $(CHTTP2_FULLSTACK_SIMPLE_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_SIMPLE_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_simple_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_simple_request_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_SIMPLE_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_SIMPLE_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_simple_request_test
+
+
+CHTTP2_FULLSTACK_THREAD_STRESS_TEST_TEST_SRC = \
+
+CHTTP2_FULLSTACK_THREAD_STRESS_TEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_THREAD_STRESS_TEST_TEST_SRC))))
+CHTTP2_FULLSTACK_THREAD_STRESS_TEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_THREAD_STRESS_TEST_TEST_SRC))))
+
+bins/chttp2_fullstack_thread_stress_test_test: $(CHTTP2_FULLSTACK_THREAD_STRESS_TEST_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_thread_stress_test.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_THREAD_STRESS_TEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_thread_stress_test -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_thread_stress_test_test
+
+deps_chttp2_fullstack_thread_stress_test_test: $(CHTTP2_FULLSTACK_THREAD_STRESS_TEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_THREAD_STRESS_TEST_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_thread_stress_test_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_thread_stress_test_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_THREAD_STRESS_TEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_THREAD_STRESS_TEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_thread_stress_test_test
+
+
+CHTTP2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC = \
+
+CHTTP2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC))))
+CHTTP2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC))))
+
+bins/chttp2_fullstack_writes_done_hangs_with_pending_read_test: $(CHTTP2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS) libs/libend2end_fixture_chttp2_fullstack.a libs/libend2end_test_writes_done_hangs_with_pending_read.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_fullstack -lend2end_test_writes_done_hangs_with_pending_read -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_fullstack_writes_done_hangs_with_pending_read_test
+
+deps_chttp2_fullstack_writes_done_hangs_with_pending_read_test: $(CHTTP2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+endif
+
+clean_chttp2_fullstack_writes_done_hangs_with_pending_read_test:
+	$(E) "[CLEAN]   Cleaning chttp2_fullstack_writes_done_hangs_with_pending_read_test files"
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_fullstack_writes_done_hangs_with_pending_read_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_cancel_after_accept_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_cancel_after_accept.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_cancel_after_accept -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_cancel_after_accept_test
+
+deps_chttp2_simple_ssl_fullstack_cancel_after_accept_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_cancel_after_accept_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_cancel_after_accept_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_cancel_after_accept_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_cancel_after_accept_and_writes_closed.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_cancel_after_accept_and_writes_closed -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test
+
+deps_chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_cancel_after_invoke_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_cancel_after_invoke.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_cancel_after_invoke -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_cancel_after_invoke_test
+
+deps_chttp2_simple_ssl_fullstack_cancel_after_invoke_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_cancel_after_invoke_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_cancel_after_invoke_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_cancel_after_invoke_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_cancel_before_invoke_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_cancel_before_invoke.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_cancel_before_invoke -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_cancel_before_invoke_test
+
+deps_chttp2_simple_ssl_fullstack_cancel_before_invoke_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_cancel_before_invoke_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_cancel_before_invoke_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_cancel_before_invoke_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_cancel_in_a_vacuum.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_cancel_in_a_vacuum -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test
+
+deps_chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_early_server_shutdown_finishes_inflight_calls.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_early_server_shutdown_finishes_inflight_calls -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test
+
+deps_chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_early_server_shutdown_finishes_tags.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_early_server_shutdown_finishes_tags -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test
+
+deps_chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_invoke_large_request_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_invoke_large_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_invoke_large_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_invoke_large_request_test
+
+deps_chttp2_simple_ssl_fullstack_invoke_large_request_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_invoke_large_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_invoke_large_request_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_invoke_large_request_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_max_concurrent_streams_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_max_concurrent_streams.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_max_concurrent_streams -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_max_concurrent_streams_test
+
+deps_chttp2_simple_ssl_fullstack_max_concurrent_streams_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_max_concurrent_streams_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_max_concurrent_streams_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_max_concurrent_streams_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_NO_OP_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_NO_OP_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_NO_OP_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_NO_OP_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_NO_OP_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_no_op_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_NO_OP_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_no_op.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_NO_OP_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_no_op -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_no_op_test
+
+deps_chttp2_simple_ssl_fullstack_no_op_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_NO_OP_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_NO_OP_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_no_op_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_no_op_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_NO_OP_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_NO_OP_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_no_op_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_PING_PONG_STREAMING_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_PING_PONG_STREAMING_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_PING_PONG_STREAMING_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_PING_PONG_STREAMING_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_PING_PONG_STREAMING_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_ping_pong_streaming_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_PING_PONG_STREAMING_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_ping_pong_streaming.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_PING_PONG_STREAMING_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_ping_pong_streaming -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_ping_pong_streaming_test
+
+deps_chttp2_simple_ssl_fullstack_ping_pong_streaming_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_PING_PONG_STREAMING_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_PING_PONG_STREAMING_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_ping_pong_streaming_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_ping_pong_streaming_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_PING_PONG_STREAMING_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_PING_PONG_STREAMING_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_ping_pong_streaming_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_request_response_with_metadata_and_payload.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_request_response_with_metadata_and_payload -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test
+
+deps_chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_request_response_with_payload_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_request_response_with_payload.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_request_response_with_payload -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_request_response_with_payload_test
+
+deps_chttp2_simple_ssl_fullstack_request_response_with_payload_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_request_response_with_payload_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_request_response_with_payload_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_request_response_with_payload_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_simple_delayed_request_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_simple_delayed_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_simple_delayed_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_simple_delayed_request_test
+
+deps_chttp2_simple_ssl_fullstack_simple_delayed_request_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_simple_delayed_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_simple_delayed_request_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_simple_delayed_request_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_REQUEST_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_REQUEST_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_REQUEST_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_simple_request_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_simple_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_simple_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_simple_request_test
+
+deps_chttp2_simple_ssl_fullstack_simple_request_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_simple_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_simple_request_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_SIMPLE_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_simple_request_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_THREAD_STRESS_TEST_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_THREAD_STRESS_TEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_THREAD_STRESS_TEST_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_THREAD_STRESS_TEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_THREAD_STRESS_TEST_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_thread_stress_test_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_THREAD_STRESS_TEST_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_thread_stress_test.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_THREAD_STRESS_TEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_thread_stress_test -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_thread_stress_test_test
+
+deps_chttp2_simple_ssl_fullstack_thread_stress_test_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_THREAD_STRESS_TEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_THREAD_STRESS_TEST_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_thread_stress_test_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_thread_stress_test_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_THREAD_STRESS_TEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_THREAD_STRESS_TEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_thread_stress_test_test
+
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC))))
+
+bins/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_fullstack.a libs/libend2end_test_writes_done_hangs_with_pending_read.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_fullstack -lend2end_test_writes_done_hangs_with_pending_read -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test
+
+deps_chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test: $(CHTTP2_SIMPLE_SSL_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_cancel_after_accept.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_cancel_after_accept -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_cancel_after_accept_and_writes_closed.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_cancel_after_accept_and_writes_closed -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_cancel_after_invoke.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_cancel_after_invoke -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_AFTER_INVOKE_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_cancel_before_invoke.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_cancel_before_invoke -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_cancel_in_a_vacuum.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_cancel_in_a_vacuum -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_CANCEL_IN_A_VACUUM_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_early_server_shutdown_finishes_inflight_calls.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_early_server_shutdown_finishes_inflight_calls -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_early_server_shutdown_finishes_tags.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_early_server_shutdown_finishes_tags -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_invoke_large_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_invoke_large_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_INVOKE_LARGE_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_max_concurrent_streams.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_max_concurrent_streams -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_NO_OP_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_NO_OP_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_NO_OP_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_NO_OP_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_NO_OP_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_NO_OP_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_no_op.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_NO_OP_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_no_op -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_no_op_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_NO_OP_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_NO_OP_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_no_op_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_no_op_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_NO_OP_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_NO_OP_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_PING_PONG_STREAMING_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_PING_PONG_STREAMING_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_PING_PONG_STREAMING_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_PING_PONG_STREAMING_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_PING_PONG_STREAMING_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_PING_PONG_STREAMING_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_ping_pong_streaming.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_PING_PONG_STREAMING_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_ping_pong_streaming -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_PING_PONG_STREAMING_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_PING_PONG_STREAMING_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_PING_PONG_STREAMING_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_PING_PONG_STREAMING_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_request_response_with_metadata_and_payload.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_request_response_with_metadata_and_payload -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_request_response_with_payload.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_request_response_with_payload -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_simple_delayed_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_simple_delayed_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_REQUEST_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_REQUEST_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_REQUEST_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_simple_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_simple_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_SIMPLE_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_THREAD_STRESS_TEST_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_THREAD_STRESS_TEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_THREAD_STRESS_TEST_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_THREAD_STRESS_TEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_THREAD_STRESS_TEST_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_THREAD_STRESS_TEST_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_thread_stress_test.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_THREAD_STRESS_TEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_thread_stress_test -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_THREAD_STRESS_TEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_THREAD_STRESS_TEST_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_THREAD_STRESS_TEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_THREAD_STRESS_TEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test
+
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC = \
+
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC))))
+CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC))))
+
+bins/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS) libs/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a libs/libend2end_test_writes_done_hangs_with_pending_read.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack -lend2end_test_writes_done_hangs_with_pending_read -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test
+
+deps_chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test: $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+endif
+
+clean_chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test:
+	$(E) "[CLEAN]   Cleaning chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test files"
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SIMPLE_SSL_WITH_OAUTH2_FULLSTACK_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test
+
+
+CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_TEST_SRC))))
+
+bins/chttp2_socket_pair_cancel_after_accept_test: $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_cancel_after_accept.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_cancel_after_accept -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_cancel_after_accept_test
+
+deps_chttp2_socket_pair_cancel_after_accept_test: $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_cancel_after_accept_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_cancel_after_accept_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_cancel_after_accept_test
+
+
+CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_SRC))))
+
+bins/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test: $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_cancel_after_accept_and_writes_closed.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_cancel_after_accept_and_writes_closed -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test
+
+deps_chttp2_socket_pair_cancel_after_accept_and_writes_closed_test: $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_cancel_after_accept_and_writes_closed_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_cancel_after_accept_and_writes_closed_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_ACCEPT_AND_WRITES_CLOSED_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test
+
+
+CHTTP2_SOCKET_PAIR_CANCEL_AFTER_INVOKE_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_CANCEL_AFTER_INVOKE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_INVOKE_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_CANCEL_AFTER_INVOKE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_INVOKE_TEST_SRC))))
+
+bins/chttp2_socket_pair_cancel_after_invoke_test: $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_INVOKE_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_cancel_after_invoke.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_INVOKE_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_cancel_after_invoke -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_cancel_after_invoke_test
+
+deps_chttp2_socket_pair_cancel_after_invoke_test: $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_INVOKE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_INVOKE_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_cancel_after_invoke_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_cancel_after_invoke_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_INVOKE_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_CANCEL_AFTER_INVOKE_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_cancel_after_invoke_test
+
+
+CHTTP2_SOCKET_PAIR_CANCEL_BEFORE_INVOKE_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_CANCEL_BEFORE_INVOKE_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_CANCEL_BEFORE_INVOKE_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_CANCEL_BEFORE_INVOKE_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_CANCEL_BEFORE_INVOKE_TEST_SRC))))
+
+bins/chttp2_socket_pair_cancel_before_invoke_test: $(CHTTP2_SOCKET_PAIR_CANCEL_BEFORE_INVOKE_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_cancel_before_invoke.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_CANCEL_BEFORE_INVOKE_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_cancel_before_invoke -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_cancel_before_invoke_test
+
+deps_chttp2_socket_pair_cancel_before_invoke_test: $(CHTTP2_SOCKET_PAIR_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_cancel_before_invoke_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_cancel_before_invoke_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_CANCEL_BEFORE_INVOKE_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_CANCEL_BEFORE_INVOKE_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_cancel_before_invoke_test
+
+
+CHTTP2_SOCKET_PAIR_CANCEL_IN_A_VACUUM_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_CANCEL_IN_A_VACUUM_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_CANCEL_IN_A_VACUUM_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_CANCEL_IN_A_VACUUM_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_CANCEL_IN_A_VACUUM_TEST_SRC))))
+
+bins/chttp2_socket_pair_cancel_in_a_vacuum_test: $(CHTTP2_SOCKET_PAIR_CANCEL_IN_A_VACUUM_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_cancel_in_a_vacuum.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_CANCEL_IN_A_VACUUM_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_cancel_in_a_vacuum -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_cancel_in_a_vacuum_test
+
+deps_chttp2_socket_pair_cancel_in_a_vacuum_test: $(CHTTP2_SOCKET_PAIR_CANCEL_IN_A_VACUUM_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_CANCEL_IN_A_VACUUM_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_cancel_in_a_vacuum_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_cancel_in_a_vacuum_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_CANCEL_IN_A_VACUUM_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_CANCEL_IN_A_VACUUM_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_cancel_in_a_vacuum_test
+
+
+CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_SRC))))
+
+bins/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test: $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_early_server_shutdown_finishes_inflight_calls.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_early_server_shutdown_finishes_inflight_calls -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test
+
+deps_chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test: $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_INFLIGHT_CALLS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test
+
+
+CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_SRC))))
+
+bins/chttp2_socket_pair_early_server_shutdown_finishes_tags_test: $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_early_server_shutdown_finishes_tags.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_early_server_shutdown_finishes_tags -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_early_server_shutdown_finishes_tags_test
+
+deps_chttp2_socket_pair_early_server_shutdown_finishes_tags_test: $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_early_server_shutdown_finishes_tags_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_early_server_shutdown_finishes_tags_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_EARLY_SERVER_SHUTDOWN_FINISHES_TAGS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_early_server_shutdown_finishes_tags_test
+
+
+CHTTP2_SOCKET_PAIR_INVOKE_LARGE_REQUEST_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_INVOKE_LARGE_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_INVOKE_LARGE_REQUEST_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_INVOKE_LARGE_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_INVOKE_LARGE_REQUEST_TEST_SRC))))
+
+bins/chttp2_socket_pair_invoke_large_request_test: $(CHTTP2_SOCKET_PAIR_INVOKE_LARGE_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_invoke_large_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_INVOKE_LARGE_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_invoke_large_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_invoke_large_request_test
+
+deps_chttp2_socket_pair_invoke_large_request_test: $(CHTTP2_SOCKET_PAIR_INVOKE_LARGE_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_INVOKE_LARGE_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_invoke_large_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_invoke_large_request_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_INVOKE_LARGE_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_INVOKE_LARGE_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_invoke_large_request_test
+
+
+CHTTP2_SOCKET_PAIR_MAX_CONCURRENT_STREAMS_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_MAX_CONCURRENT_STREAMS_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_MAX_CONCURRENT_STREAMS_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_MAX_CONCURRENT_STREAMS_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_MAX_CONCURRENT_STREAMS_TEST_SRC))))
+
+bins/chttp2_socket_pair_max_concurrent_streams_test: $(CHTTP2_SOCKET_PAIR_MAX_CONCURRENT_STREAMS_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_max_concurrent_streams.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_MAX_CONCURRENT_STREAMS_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_max_concurrent_streams -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_max_concurrent_streams_test
+
+deps_chttp2_socket_pair_max_concurrent_streams_test: $(CHTTP2_SOCKET_PAIR_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_max_concurrent_streams_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_max_concurrent_streams_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_MAX_CONCURRENT_STREAMS_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_MAX_CONCURRENT_STREAMS_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_max_concurrent_streams_test
+
+
+CHTTP2_SOCKET_PAIR_NO_OP_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_NO_OP_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_NO_OP_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_NO_OP_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_NO_OP_TEST_SRC))))
+
+bins/chttp2_socket_pair_no_op_test: $(CHTTP2_SOCKET_PAIR_NO_OP_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_no_op.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_NO_OP_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_no_op -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_no_op_test
+
+deps_chttp2_socket_pair_no_op_test: $(CHTTP2_SOCKET_PAIR_NO_OP_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_NO_OP_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_no_op_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_no_op_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_NO_OP_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_NO_OP_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_no_op_test
+
+
+CHTTP2_SOCKET_PAIR_PING_PONG_STREAMING_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_PING_PONG_STREAMING_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_PING_PONG_STREAMING_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_PING_PONG_STREAMING_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_PING_PONG_STREAMING_TEST_SRC))))
+
+bins/chttp2_socket_pair_ping_pong_streaming_test: $(CHTTP2_SOCKET_PAIR_PING_PONG_STREAMING_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_ping_pong_streaming.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_PING_PONG_STREAMING_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_ping_pong_streaming -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_ping_pong_streaming_test
+
+deps_chttp2_socket_pair_ping_pong_streaming_test: $(CHTTP2_SOCKET_PAIR_PING_PONG_STREAMING_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_PING_PONG_STREAMING_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_ping_pong_streaming_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_ping_pong_streaming_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_PING_PONG_STREAMING_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_PING_PONG_STREAMING_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_ping_pong_streaming_test
+
+
+CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_SRC))))
+
+bins/chttp2_socket_pair_request_response_with_metadata_and_payload_test: $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_request_response_with_metadata_and_payload.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_request_response_with_metadata_and_payload -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_request_response_with_metadata_and_payload_test
+
+deps_chttp2_socket_pair_request_response_with_metadata_and_payload_test: $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_request_response_with_metadata_and_payload_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_request_response_with_metadata_and_payload_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_METADATA_AND_PAYLOAD_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_request_response_with_metadata_and_payload_test
+
+
+CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_SRC))))
+
+bins/chttp2_socket_pair_request_response_with_payload_test: $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_request_response_with_payload.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_request_response_with_payload -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_request_response_with_payload_test
+
+deps_chttp2_socket_pair_request_response_with_payload_test: $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_request_response_with_payload_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_request_response_with_payload_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_REQUEST_RESPONSE_WITH_PAYLOAD_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_request_response_with_payload_test
+
+
+CHTTP2_SOCKET_PAIR_SIMPLE_DELAYED_REQUEST_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_SIMPLE_DELAYED_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_SIMPLE_DELAYED_REQUEST_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_SIMPLE_DELAYED_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_SIMPLE_DELAYED_REQUEST_TEST_SRC))))
+
+bins/chttp2_socket_pair_simple_delayed_request_test: $(CHTTP2_SOCKET_PAIR_SIMPLE_DELAYED_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_simple_delayed_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_SIMPLE_DELAYED_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_simple_delayed_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_simple_delayed_request_test
+
+deps_chttp2_socket_pair_simple_delayed_request_test: $(CHTTP2_SOCKET_PAIR_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_simple_delayed_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_simple_delayed_request_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_SIMPLE_DELAYED_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_SIMPLE_DELAYED_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_simple_delayed_request_test
+
+
+CHTTP2_SOCKET_PAIR_SIMPLE_REQUEST_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_SIMPLE_REQUEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_SIMPLE_REQUEST_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_SIMPLE_REQUEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_SIMPLE_REQUEST_TEST_SRC))))
+
+bins/chttp2_socket_pair_simple_request_test: $(CHTTP2_SOCKET_PAIR_SIMPLE_REQUEST_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_simple_request.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_SIMPLE_REQUEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_simple_request -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_simple_request_test
+
+deps_chttp2_socket_pair_simple_request_test: $(CHTTP2_SOCKET_PAIR_SIMPLE_REQUEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_SIMPLE_REQUEST_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_simple_request_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_simple_request_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_SIMPLE_REQUEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_SIMPLE_REQUEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_simple_request_test
+
+
+CHTTP2_SOCKET_PAIR_THREAD_STRESS_TEST_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_THREAD_STRESS_TEST_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_THREAD_STRESS_TEST_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_THREAD_STRESS_TEST_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_THREAD_STRESS_TEST_TEST_SRC))))
+
+bins/chttp2_socket_pair_thread_stress_test_test: $(CHTTP2_SOCKET_PAIR_THREAD_STRESS_TEST_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_thread_stress_test.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_THREAD_STRESS_TEST_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_thread_stress_test -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_thread_stress_test_test
+
+deps_chttp2_socket_pair_thread_stress_test_test: $(CHTTP2_SOCKET_PAIR_THREAD_STRESS_TEST_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_THREAD_STRESS_TEST_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_thread_stress_test_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_thread_stress_test_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_THREAD_STRESS_TEST_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_THREAD_STRESS_TEST_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_thread_stress_test_test
+
+
+CHTTP2_SOCKET_PAIR_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC = \
+
+CHTTP2_SOCKET_PAIR_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(CHTTP2_SOCKET_PAIR_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC))))
+CHTTP2_SOCKET_PAIR_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(CHTTP2_SOCKET_PAIR_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_SRC))))
+
+bins/chttp2_socket_pair_writes_done_hangs_with_pending_read_test: $(CHTTP2_SOCKET_PAIR_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS) libs/libend2end_fixture_chttp2_socket_pair.a libs/libend2end_test_writes_done_hangs_with_pending_read.a libs/libend2end_certs.a libs/libgrpc_test_util.a libs/libgrpc.a libs/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) $(LD) $(LDFLAGS) $(CHTTP2_SOCKET_PAIR_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS) -Llibs -lend2end_fixture_chttp2_socket_pair -lend2end_test_writes_done_hangs_with_pending_read -lend2end_certs -lgrpc_test_util -lgrpc -lgpr $(LDLIBS) $(LDLIBS_SECURE) -o bins/chttp2_socket_pair_writes_done_hangs_with_pending_read_test
+
+deps_chttp2_socket_pair_writes_done_hangs_with_pending_read_test: $(CHTTP2_SOCKET_PAIR_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(CHTTP2_SOCKET_PAIR_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+endif
+
+clean_chttp2_socket_pair_writes_done_hangs_with_pending_read_test:
+	$(E) "[CLEAN]   Cleaning chttp2_socket_pair_writes_done_hangs_with_pending_read_test files"
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_OBJS)
+	$(Q) $(RM) $(CHTTP2_SOCKET_PAIR_WRITES_DONE_HANGS_WITH_PENDING_READ_TEST_DEPS)
+	$(Q) $(RM) bins/chttp2_socket_pair_writes_done_hangs_with_pending_read_test
+
+
+
+
+
+
+.PHONY: all strip tools buildtests tests make_dirs install clean deps_libgpr clean_libgpr deps_libgrpc clean_libgrpc deps_libgrpc_test_util clean_libgrpc_test_util deps_libgrpc++ clean_libgrpc++ deps_libgrpc++_test_util clean_libgrpc++_test_util deps_libend2end_fixture_chttp2_fake_security clean_libend2end_fixture_chttp2_fake_security deps_libend2end_fixture_chttp2_fullstack clean_libend2end_fixture_chttp2_fullstack deps_libend2end_fixture_chttp2_simple_ssl_fullstack clean_libend2end_fixture_chttp2_simple_ssl_fullstack deps_libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack clean_libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack deps_libend2end_fixture_chttp2_socket_pair clean_libend2end_fixture_chttp2_socket_pair deps_libend2end_test_cancel_after_accept clean_libend2end_test_cancel_after_accept deps_libend2end_test_cancel_after_accept_and_writes_closed clean_libend2end_test_cancel_after_accept_and_writes_closed deps_libend2end_test_cancel_after_invoke clean_libend2end_test_cancel_after_invoke deps_libend2end_test_cancel_before_invoke clean_libend2end_test_cancel_before_invoke deps_libend2end_test_cancel_in_a_vacuum clean_libend2end_test_cancel_in_a_vacuum deps_libend2end_test_early_server_shutdown_finishes_inflight_calls clean_libend2end_test_early_server_shutdown_finishes_inflight_calls deps_libend2end_test_early_server_shutdown_finishes_tags clean_libend2end_test_early_server_shutdown_finishes_tags deps_libend2end_test_invoke_large_request clean_libend2end_test_invoke_large_request deps_libend2end_test_max_concurrent_streams clean_libend2end_test_max_concurrent_streams deps_libend2end_test_no_op clean_libend2end_test_no_op deps_libend2end_test_ping_pong_streaming clean_libend2end_test_ping_pong_streaming deps_libend2end_test_request_response_with_metadata_and_payload clean_libend2end_test_request_response_with_metadata_and_payload deps_libend2end_test_request_response_with_payload clean_libend2end_test_request_response_with_payload deps_libend2end_test_simple_delayed_request clean_libend2end_test_simple_delayed_request deps_libend2end_test_simple_request clean_libend2end_test_simple_request deps_libend2end_test_thread_stress_test clean_libend2end_test_thread_stress_test deps_libend2end_test_writes_done_hangs_with_pending_read clean_libend2end_test_writes_done_hangs_with_pending_read deps_libend2end_certs clean_libend2end_certs deps_libgrpc_unsecure clean_libgrpc_unsecure deps_gen_hpack_tables clean_gen_hpack_tables deps_grpc_byte_buffer_reader_test clean_grpc_byte_buffer_reader_test deps_gpr_cancellable_test clean_gpr_cancellable_test deps_gpr_log_test clean_gpr_log_test deps_gpr_cmdline_test clean_gpr_cmdline_test deps_gpr_histogram_test clean_gpr_histogram_test deps_gpr_host_port_test clean_gpr_host_port_test deps_gpr_slice_buffer_test clean_gpr_slice_buffer_test deps_gpr_slice_test clean_gpr_slice_test deps_gpr_string_test clean_gpr_string_test deps_gpr_sync_test clean_gpr_sync_test deps_gpr_thd_test clean_gpr_thd_test deps_gpr_time_test clean_gpr_time_test deps_murmur_hash_test clean_murmur_hash_test deps_grpc_em_test clean_grpc_em_test deps_grpc_em_pipe_test clean_grpc_em_pipe_test deps_grpc_stream_op_test clean_grpc_stream_op_test deps_chttp2_stream_encoder_test clean_chttp2_stream_encoder_test deps_hpack_table_test clean_hpack_table_test deps_chttp2_stream_map_test clean_chttp2_stream_map_test deps_hpack_parser_test clean_hpack_parser_test deps_transport_metadata_test clean_transport_metadata_test deps_chttp2_status_conversion_test clean_chttp2_status_conversion_test deps_chttp2_transport_end2end_test clean_chttp2_transport_end2end_test deps_grpc_tcp_test clean_grpc_tcp_test deps_resolve_address_test clean_resolve_address_test deps_tcp_server_test clean_tcp_server_test deps_tcp_client_test clean_tcp_client_test deps_grpc_channel_stack_test clean_grpc_channel_stack_test deps_metadata_buffer_test clean_metadata_buffer_test deps_grpc_completion_queue_test clean_grpc_completion_queue_test deps_grpc_completion_queue_benchmark clean_grpc_completion_queue_benchmark deps_census_window_stats_test clean_census_window_stats_test deps_census_statistics_quick_test clean_census_statistics_quick_test deps_census_statistics_performance_test clean_census_statistics_performance_test deps_census_statistics_multiple_writers_test clean_census_statistics_multiple_writers_test deps_census_statistics_multiple_writers_circular_buffer_test clean_census_statistics_multiple_writers_circular_buffer_test deps_census_stub_test clean_census_stub_test deps_census_hash_table_test clean_census_hash_table_test deps_fling_server clean_fling_server deps_fling_client clean_fling_client deps_fling_test clean_fling_test deps_echo_server clean_echo_server deps_echo_client clean_echo_client deps_echo_test clean_echo_test deps_low_level_ping_pong_benchmark clean_low_level_ping_pong_benchmark deps_message_compress_test clean_message_compress_test deps_secure_endpoint_test clean_secure_endpoint_test deps_httpcli_format_request_test clean_httpcli_format_request_test deps_httpcli_parser_test clean_httpcli_parser_test deps_httpcli_test clean_httpcli_test deps_grpc_credentials_test clean_grpc_credentials_test deps_fling_stream_test clean_fling_stream_test deps_lame_client_test clean_lame_client_test deps_thread_pool_test clean_thread_pool_test deps_status_test clean_status_test deps_chttp2_fake_security_cancel_after_accept_test clean_chttp2_fake_security_cancel_after_accept_test deps_chttp2_fake_security_cancel_after_accept_and_writes_closed_test clean_chttp2_fake_security_cancel_after_accept_and_writes_closed_test deps_chttp2_fake_security_cancel_after_invoke_test clean_chttp2_fake_security_cancel_after_invoke_test deps_chttp2_fake_security_cancel_before_invoke_test clean_chttp2_fake_security_cancel_before_invoke_test deps_chttp2_fake_security_cancel_in_a_vacuum_test clean_chttp2_fake_security_cancel_in_a_vacuum_test deps_chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test clean_chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test deps_chttp2_fake_security_early_server_shutdown_finishes_tags_test clean_chttp2_fake_security_early_server_shutdown_finishes_tags_test deps_chttp2_fake_security_invoke_large_request_test clean_chttp2_fake_security_invoke_large_request_test deps_chttp2_fake_security_max_concurrent_streams_test clean_chttp2_fake_security_max_concurrent_streams_test deps_chttp2_fake_security_no_op_test clean_chttp2_fake_security_no_op_test deps_chttp2_fake_security_ping_pong_streaming_test clean_chttp2_fake_security_ping_pong_streaming_test deps_chttp2_fake_security_request_response_with_metadata_and_payload_test clean_chttp2_fake_security_request_response_with_metadata_and_payload_test deps_chttp2_fake_security_request_response_with_payload_test clean_chttp2_fake_security_request_response_with_payload_test deps_chttp2_fake_security_simple_delayed_request_test clean_chttp2_fake_security_simple_delayed_request_test deps_chttp2_fake_security_simple_request_test clean_chttp2_fake_security_simple_request_test deps_chttp2_fake_security_thread_stress_test_test clean_chttp2_fake_security_thread_stress_test_test deps_chttp2_fake_security_writes_done_hangs_with_pending_read_test clean_chttp2_fake_security_writes_done_hangs_with_pending_read_test deps_chttp2_fullstack_cancel_after_accept_test clean_chttp2_fullstack_cancel_after_accept_test deps_chttp2_fullstack_cancel_after_accept_and_writes_closed_test clean_chttp2_fullstack_cancel_after_accept_and_writes_closed_test deps_chttp2_fullstack_cancel_after_invoke_test clean_chttp2_fullstack_cancel_after_invoke_test deps_chttp2_fullstack_cancel_before_invoke_test clean_chttp2_fullstack_cancel_before_invoke_test deps_chttp2_fullstack_cancel_in_a_vacuum_test clean_chttp2_fullstack_cancel_in_a_vacuum_test deps_chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test clean_chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test deps_chttp2_fullstack_early_server_shutdown_finishes_tags_test clean_chttp2_fullstack_early_server_shutdown_finishes_tags_test deps_chttp2_fullstack_invoke_large_request_test clean_chttp2_fullstack_invoke_large_request_test deps_chttp2_fullstack_max_concurrent_streams_test clean_chttp2_fullstack_max_concurrent_streams_test deps_chttp2_fullstack_no_op_test clean_chttp2_fullstack_no_op_test deps_chttp2_fullstack_ping_pong_streaming_test clean_chttp2_fullstack_ping_pong_streaming_test deps_chttp2_fullstack_request_response_with_metadata_and_payload_test clean_chttp2_fullstack_request_response_with_metadata_and_payload_test deps_chttp2_fullstack_request_response_with_payload_test clean_chttp2_fullstack_request_response_with_payload_test deps_chttp2_fullstack_simple_delayed_request_test clean_chttp2_fullstack_simple_delayed_request_test deps_chttp2_fullstack_simple_request_test clean_chttp2_fullstack_simple_request_test deps_chttp2_fullstack_thread_stress_test_test clean_chttp2_fullstack_thread_stress_test_test deps_chttp2_fullstack_writes_done_hangs_with_pending_read_test clean_chttp2_fullstack_writes_done_hangs_with_pending_read_test deps_chttp2_simple_ssl_fullstack_cancel_after_accept_test clean_chttp2_simple_ssl_fullstack_cancel_after_accept_test deps_chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test clean_chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test deps_chttp2_simple_ssl_fullstack_cancel_after_invoke_test clean_chttp2_simple_ssl_fullstack_cancel_after_invoke_test deps_chttp2_simple_ssl_fullstack_cancel_before_invoke_test clean_chttp2_simple_ssl_fullstack_cancel_before_invoke_test deps_chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test clean_chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test deps_chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test clean_chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test deps_chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test clean_chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test deps_chttp2_simple_ssl_fullstack_invoke_large_request_test clean_chttp2_simple_ssl_fullstack_invoke_large_request_test deps_chttp2_simple_ssl_fullstack_max_concurrent_streams_test clean_chttp2_simple_ssl_fullstack_max_concurrent_streams_test deps_chttp2_simple_ssl_fullstack_no_op_test clean_chttp2_simple_ssl_fullstack_no_op_test deps_chttp2_simple_ssl_fullstack_ping_pong_streaming_test clean_chttp2_simple_ssl_fullstack_ping_pong_streaming_test deps_chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test clean_chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test deps_chttp2_simple_ssl_fullstack_request_response_with_payload_test clean_chttp2_simple_ssl_fullstack_request_response_with_payload_test deps_chttp2_simple_ssl_fullstack_simple_delayed_request_test clean_chttp2_simple_ssl_fullstack_simple_delayed_request_test deps_chttp2_simple_ssl_fullstack_simple_request_test clean_chttp2_simple_ssl_fullstack_simple_request_test deps_chttp2_simple_ssl_fullstack_thread_stress_test_test clean_chttp2_simple_ssl_fullstack_thread_stress_test_test deps_chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test clean_chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test deps_chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test clean_chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test deps_chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test clean_chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test deps_chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test clean_chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test deps_chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test clean_chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test deps_chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test clean_chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test deps_chttp2_simple_ssl_with_oauth2_fullstack_no_op_test clean_chttp2_simple_ssl_with_oauth2_fullstack_no_op_test deps_chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test clean_chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test deps_chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test clean_chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test deps_chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test clean_chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test deps_chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test clean_chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test deps_chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test clean_chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test deps_chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test clean_chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test_test deps_chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test clean_chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test deps_chttp2_socket_pair_cancel_after_accept_test clean_chttp2_socket_pair_cancel_after_accept_test deps_chttp2_socket_pair_cancel_after_accept_and_writes_closed_test clean_chttp2_socket_pair_cancel_after_accept_and_writes_closed_test deps_chttp2_socket_pair_cancel_after_invoke_test clean_chttp2_socket_pair_cancel_after_invoke_test deps_chttp2_socket_pair_cancel_before_invoke_test clean_chttp2_socket_pair_cancel_before_invoke_test deps_chttp2_socket_pair_cancel_in_a_vacuum_test clean_chttp2_socket_pair_cancel_in_a_vacuum_test deps_chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test clean_chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test deps_chttp2_socket_pair_early_server_shutdown_finishes_tags_test clean_chttp2_socket_pair_early_server_shutdown_finishes_tags_test deps_chttp2_socket_pair_invoke_large_request_test clean_chttp2_socket_pair_invoke_large_request_test deps_chttp2_socket_pair_max_concurrent_streams_test clean_chttp2_socket_pair_max_concurrent_streams_test deps_chttp2_socket_pair_no_op_test clean_chttp2_socket_pair_no_op_test deps_chttp2_socket_pair_ping_pong_streaming_test clean_chttp2_socket_pair_ping_pong_streaming_test deps_chttp2_socket_pair_request_response_with_metadata_and_payload_test clean_chttp2_socket_pair_request_response_with_metadata_and_payload_test deps_chttp2_socket_pair_request_response_with_payload_test clean_chttp2_socket_pair_request_response_with_payload_test deps_chttp2_socket_pair_simple_delayed_request_test clean_chttp2_socket_pair_simple_delayed_request_test deps_chttp2_socket_pair_simple_request_test clean_chttp2_socket_pair_simple_request_test deps_chttp2_socket_pair_thread_stress_test_test clean_chttp2_socket_pair_thread_stress_test_test deps_chttp2_socket_pair_writes_done_hangs_with_pending_read_test clean_chttp2_socket_pair_writes_done_hangs_with_pending_read_test
diff --git a/build.json b/build.json
new file mode 100644
index 0000000..b869eb6
--- /dev/null
+++ b/build.json
@@ -0,0 +1,1012 @@
+{
+  "settings": {
+    "#": "The public version number of the library.",
+    "version": {
+      "major": 0,
+      "minor": 8,
+      "micro": 0,
+      "build": 0
+    }
+  },
+  "libs": [
+    {
+      "name": "gpr",
+      "build": "all",
+      "secure": false,
+      "src": [
+        "src/core/support/alloc.c",
+        "src/core/support/cancellable.c",
+        "src/core/support/cmdline.c",
+        "src/core/support/cpu_posix.c",
+        "src/core/support/histogram.c",
+        "src/core/support/host_port.c",
+        "src/core/support/log.c",
+        "src/core/support/log_posix.c",
+        "src/core/support/log_linux.c",
+        "src/core/support/log_android.c",
+        "src/core/support/log_win32.c",
+        "src/core/support/murmur_hash.c",
+        "src/core/support/slice.c",
+        "src/core/support/slice_buffer.c",
+        "src/core/support/string.c",
+        "src/core/support/string_posix.c",
+        "src/core/support/sync.c",
+        "src/core/support/sync_posix.c",
+        "src/core/support/thd_posix.c",
+        "src/core/support/thd_win32.c",
+        "src/core/support/time.c",
+        "src/core/support/time_posix.c",
+        "src/core/support/time_win32.c"
+      ],
+      "public_headers": [
+        "include/grpc/support/alloc.h",
+        "include/grpc/support/atm_gcc_atomic.h",
+        "include/grpc/support/atm_gcc_sync.h",
+        "include/grpc/support/atm.h",
+        "include/grpc/support/atm_win32.h",
+        "include/grpc/support/cancellable_platform.h",
+        "include/grpc/support/cmdline.h",
+        "include/grpc/support/histogram.h",
+        "include/grpc/support/host_port.h",
+        "include/grpc/support/log.h",
+        "include/grpc/support/port_platform.h",
+        "include/grpc/support/slice_buffer.h",
+        "include/grpc/support/slice.h",
+        "include/grpc/support/string.h",
+        "include/grpc/support/sync_generic.h",
+        "include/grpc/support/sync.h",
+        "include/grpc/support/sync_posix.h",
+        "include/grpc/support/sync_win32.h",
+        "include/grpc/support/thd.h",
+        "include/grpc/support/thd_posix.h",
+        "include/grpc/support/thd_win32.h",
+        "include/grpc/support/time.h",
+        "include/grpc/support/time_posix.h",
+        "include/grpc/support/time_win32.h",
+        "include/grpc/support/useful.h"
+      ],
+      "headers": [
+        "src/core/support/cpu.h",
+        "src/core/support/murmur_hash.h",
+        "src/core/support/thd_internal.h"
+      ]
+    },
+    {
+      "name": "grpc",
+      "build": "all",
+      "secure": true,
+      "alternates": [
+        {
+          "name": "grpc_unsecure",
+          "properties": [
+            {
+              "name": "secure",
+              "value": false
+            }
+          ],
+          "exclude_res": [
+            "^src/core/security/",
+            "^src/core/tsi/"
+          ]
+        }
+      ],
+      "src": [
+        "src/core/channel/call_op_string.c",
+        "src/core/channel/census_filter.c",
+        "src/core/channel/channel_args.c",
+        "src/core/channel/channel_stack.c",
+        "src/core/channel/client_channel.c",
+        "src/core/channel/client_setup.c",
+        "src/core/channel/connected_channel.c",
+        "src/core/channel/http_client_filter.c",
+        "src/core/channel/http_filter.c",
+        "src/core/channel/http_server_filter.c",
+        "src/core/channel/metadata_buffer.c",
+        "src/core/channel/noop_filter.c",
+        "src/core/compression/algorithm.c",
+        "src/core/compression/message_compress.c",
+        "src/core/endpoint/endpoint.c",
+        "src/core/endpoint/resolve_address.c",
+        "src/core/endpoint/socket_utils.c",
+        "src/core/endpoint/socket_utils_linux.c",
+        "src/core/endpoint/socket_utils_posix.c",
+        "src/core/endpoint/tcp.c",
+        "src/core/endpoint/tcp_client.c",
+        "src/core/endpoint/tcp_server.c",
+        "src/core/eventmanager/em.c",
+        "src/core/eventmanager/em_posix.c",
+        "src/core/surface/byte_buffer.c",
+        "src/core/surface/byte_buffer_reader.c",
+        "src/core/surface/call.c",
+        "src/core/surface/channel.c",
+        "src/core/surface/channel_create.c",
+        "src/core/surface/client.c",
+        "src/core/surface/lame_client.c",
+        "src/core/surface/completion_queue.c",
+        "src/core/surface/event_string.c",
+        "src/core/surface/init.c",
+        "src/core/surface/server.c",
+        "src/core/surface/server_chttp2.c",
+        "src/core/surface/server_create.c",
+        "src/core/surface/surface_em.c",
+        "src/core/transport/chttp2/frame_data.c",
+        "src/core/transport/chttp2/frame_ping.c",
+        "src/core/transport/chttp2/frame_rst_stream.c",
+        "src/core/transport/chttp2/frame_settings.c",
+        "src/core/transport/chttp2/frame_window_update.c",
+        "src/core/transport/chttp2/hpack_parser.c",
+        "src/core/transport/chttp2/hpack_table.c",
+        "src/core/transport/chttp2/status_conversion.c",
+        "src/core/transport/chttp2/stream_encoder.c",
+        "src/core/transport/chttp2/stream_map.c",
+        "src/core/transport/chttp2/timeout_encoding.c",
+        "src/core/transport/chttp2/varint.c",
+        "src/core/transport/chttp2_transport.c",
+        "src/core/transport/metadata.c",
+        "src/core/transport/stream_op.c",
+        "src/core/transport/transport.c",
+        "src/core/statistics/census_init.c",
+        "src/core/statistics/census_rpc_stats.c",
+        "src/core/statistics/census_tracing.c",
+        "src/core/statistics/log.c",
+        "src/core/statistics/window_stats.c",
+        "src/core/statistics/hash_table.c",
+        "src/core/httpcli/format_request.c",
+        "src/core/httpcli/httpcli.c",
+        "src/core/httpcli/httpcli_security_context.c",
+        "src/core/httpcli/parser.c",
+        "src/core/security/auth.c",
+        "src/core/security/credentials.c",
+        "src/core/security/google_root_certs.c",
+        "src/core/security/secure_transport_setup.c",
+        "src/core/security/security_context.c",
+        "src/core/security/server_secure_chttp2.c",
+        "src/core/surface/secure_channel_create.c",
+        "src/core/surface/secure_server_create.c",
+        "src/core/endpoint/secure_endpoint.c",
+        "src/core/tsi/transport_security.c",
+        "src/core/tsi/fake_transport_security.c",
+        "src/core/tsi/ssl_transport_security.c",
+        "third_party/cJSON/cJSON.c"
+      ],
+      "public_headers": [
+        "include/grpc/byte_buffer.h",
+        "include/grpc/byte_buffer_reader.h",
+        "include/grpc/grpc.h",
+        "include/grpc/grpc_security.h",
+        "include/grpc/status.h"
+      ],
+      "headers": [
+        "src/core/channel/census_filter.h",
+        "src/core/channel/channel_args.h",
+        "src/core/channel/channel_stack.h",
+        "src/core/channel/client_channel.h",
+        "src/core/channel/client_setup.h",
+        "src/core/channel/connected_channel.h",
+        "src/core/channel/http_client_filter.h",
+        "src/core/channel/http_filter.h",
+        "src/core/channel/http_server_filter.h",
+        "src/core/channel/metadata_buffer.h",
+        "src/core/channel/noop_filter.h",
+        "src/core/compression/algorithm.h",
+        "src/core/compression/message_compress.h",
+        "src/core/endpoint/endpoint.h",
+        "src/core/endpoint/resolve_address.h",
+        "src/core/endpoint/secure_endpoint.h",
+        "src/core/endpoint/socket_utils.h",
+        "src/core/endpoint/tcp_client.h",
+        "src/core/endpoint/tcp.h",
+        "src/core/endpoint/tcp_server.h",
+        "src/core/eventmanager/em.h",
+        "src/core/httpcli/format_request.h",
+        "src/core/httpcli/httpcli.h",
+        "src/core/httpcli/httpcli_security_context.h",
+        "src/core/httpcli/parser.h",
+        "src/core/security/auth.h",
+        "src/core/security/credentials.h",
+        "src/core/security/google_root_certs.h",
+        "src/core/security/secure_transport_setup.h",
+        "src/core/security/security_context.h",
+        "src/core/statistics/census_interface.h",
+        "src/core/statistics/census_rpc_stats.h",
+        "src/core/statistics/hash_table.h",
+        "src/core/statistics/log.h",
+        "src/core/statistics/window_stats.h",
+        "src/core/surface/call.h",
+        "src/core/surface/channel.h",
+        "src/core/surface/client.h",
+        "src/core/surface/lame_client.h",
+        "src/core/surface/completion_queue.h",
+        "src/core/surface/event_string.h",
+        "src/core/surface/server.h",
+        "src/core/surface/surface_em.h",
+        "src/core/surface/surface_trace.h",
+        "src/core/transport/chttp2/frame_data.h",
+        "src/core/transport/chttp2/frame.h",
+        "src/core/transport/chttp2/frame_ping.h",
+        "src/core/transport/chttp2/frame_rst_stream.h",
+        "src/core/transport/chttp2/frame_settings.h",
+        "src/core/transport/chttp2/frame_window_update.h",
+        "src/core/transport/chttp2/hpack_parser.h",
+        "src/core/transport/chttp2/hpack_table.h",
+        "src/core/transport/chttp2/http2_errors.h",
+        "src/core/transport/chttp2/status_conversion.h",
+        "src/core/transport/chttp2/stream_encoder.h",
+        "src/core/transport/chttp2/stream_map.h",
+        "src/core/transport/chttp2/timeout_encoding.h",
+        "src/core/transport/chttp2_transport.h",
+        "src/core/transport/chttp2/varint.h",
+        "src/core/transport/metadata.h",
+        "src/core/transport/stream_op.h",
+        "src/core/transport/transport.h",
+        "src/core/transport/transport_impl.h",
+        "src/core/tsi/fake_transport_security.h",
+        "src/core/tsi/ssl_transport_security.h",
+        "src/core/tsi/transport_security.h",
+        "src/core/tsi/transport_security_interface.h",
+        "src/core/tsi/transport_security_test_lib.h"
+      ]
+    },
+    {
+      "name": "grpc_test_util",
+      "build": "private",
+      "src": [
+        "test/core/util/grpc_profiler.c",
+        "test/core/util/parse_hexstring.c",
+        "test/core/util/port.c",
+        "test/core/util/slice_splitter.c",
+        "test/core/util/test_config.c",
+        "test/core/end2end/end2end_tests.c",
+        "test/core/end2end/cq_verifier.c",
+        "test/core/endpoint/endpoint_tests.c",
+        "test/core/transport/transport_end2end_tests.c",
+        "test/core/statistics/log_tests.c"
+      ]
+    },
+    {
+      "name": "grpc++",
+      "build": "all",
+      "c++": true,
+      "secure": true,
+      "src": [
+        "src/cpp/server/server.cc",
+        "src/cpp/server/server_rpc_handler.cc",
+        "src/cpp/server/thread_pool.cc",
+        "src/cpp/server/async_server_context.cc",
+        "src/cpp/server/async_server.cc",
+        "src/cpp/server/completion_queue.cc",
+        "src/cpp/server/server_builder.cc",
+        "src/cpp/stream/stream_context.cc",
+        "src/cpp/client/create_channel.cc",
+        "src/cpp/client/channel.cc",
+        "src/cpp/client/client_context.cc",
+        "src/cpp/client/internal_stub.cc",
+        "src/cpp/util/time.cc",
+        "src/cpp/util/status.cc",
+        "src/cpp/proto/proto_utils.cc",
+        "src/cpp/rpc_method.cc"
+      ],
+      "public_headers": [
+        "include/grpc++/channel_interface.h",
+        "include/grpc++/async_server.h",
+        "include/grpc++/create_channel.h",
+        "include/grpc++/server_builder.h",
+        "include/grpc++/thread_pool_interface.h",
+        "include/grpc++/stream_context_interface.h",
+        "include/grpc++/status.h",
+        "include/grpc++/config.h",
+        "include/grpc++/completion_queue.h",
+        "include/grpc++/stream.h",
+        "include/grpc++/async_server_context.h",
+        "include/grpc++/server.h",
+        "include/grpc++/client_context.h"
+      ],
+      "headers": [
+        "src/cpp/server/rpc_service_method.h",
+        "src/cpp/server/server_rpc_handler.h",
+        "src/cpp/server/thread_pool.h",
+        "src/cpp/stream/stream_context.h",
+        "src/cpp/client/channel.h",
+        "src/cpp/client/internal_stub.h",
+        "src/cpp/util/time.h",
+        "src/cpp/rpc_method.h",
+        "src/cpp/proto/proto_utils.h"
+      ]
+    },
+    {
+      "name": "grpc++_test_util",
+      "build": "test",
+      "src": [
+        "test/cpp/end2end/async_test_server.cc",
+        "test/cpp/util/echo.proto"
+      ],
+      "c++": true
+    }
+  ],
+  "targets": [
+    {
+      "name": "gen_hpack_tables",
+      "build": "tool",
+      "src": [
+        "src/core/transport/chttp2/gen_hpack_tables.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "gpr"
+      ]
+    },
+
+
+    {
+      "name": "grpc_byte_buffer_reader_test",
+      "build": "test",
+      "src": [
+        "test/core/surface/byte_buffer_reader_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "gpr_cancellable_test",
+      "build": "test",
+      "src": [
+        "test/core/support/cancellable_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "gpr_log_test",
+      "build": "test",
+      "src": [
+        "test/core/support/log_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "gpr_cmdline_test",
+      "build": "test",
+      "src": [
+        "test/core/support/cmdline_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "gpr_histogram_test",
+      "build": "test",
+      "src": [
+        "test/core/support/histogram_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "gpr_host_port_test",
+      "build": "test",
+      "src": [
+        "test/core/support/host_port_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "gpr_slice_buffer_test",
+      "build": "test",
+      "src": [
+        "test/core/support/slice_buffer_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "gpr_slice_test",
+      "build": "test",
+      "src": [
+        "test/core/support/slice_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "gpr_string_test",
+      "build": "test",
+      "src": [
+        "test/core/support/string_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "gpr_sync_test",
+      "build": "test",
+      "src": [
+        "test/core/support/sync_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "gpr_thd_test",
+      "build": "test",
+      "src": [
+        "test/core/support/thd_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "gpr_time_test",
+      "build": "test",
+      "src": [
+        "test/core/support/time_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "murmur_hash_test",
+      "build": "test",
+      "src": [
+        "test/core/support/murmur_hash_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "grpc_em_test",
+      "build": "test",
+      "src": [
+        "test/core/eventmanager/em_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "grpc_em_pipe_test",
+      "build": "test",
+      "src": [
+        "test/core/eventmanager/em_pipe_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "grpc_stream_op_test",
+      "build": "test",
+      "src": [
+        "test/core/transport/stream_op_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "chttp2_stream_encoder_test",
+      "build": "test",
+      "src": [
+        "test/core/transport/chttp2/stream_encoder_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "hpack_table_test",
+      "build": "test",
+      "src": [
+        "test/core/transport/chttp2/hpack_table_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "chttp2_stream_map_test",
+      "build": "test",
+      "src": [
+        "test/core/transport/chttp2/stream_map_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "hpack_parser_test",
+      "build": "test",
+      "src": [
+        "test/core/transport/chttp2/hpack_parser_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "transport_metadata_test",
+      "build": "test",
+      "src": [
+        "test/core/transport/metadata_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "chttp2_status_conversion_test",
+      "build": "test",
+      "src": [
+        "test/core/transport/chttp2/status_conversion_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "chttp2_transport_end2end_test",
+      "build": "test",
+      "src": [
+        "test/core/transport/chttp2_transport_end2end_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "grpc_tcp_test",
+      "build": "test",
+      "src": [
+        "test/core/endpoint/tcp_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "resolve_address_test",
+      "build": "test",
+      "src": [
+        "test/core/endpoint/resolve_address_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "tcp_server_test",
+      "build": "test",
+      "src": [
+        "test/core/endpoint/tcp_server_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "tcp_client_test",
+      "build": "test",
+      "src": [
+        "test/core/endpoint/tcp_client_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "grpc_channel_stack_test",
+      "build": "test",
+      "src": [
+        "test/core/channel/channel_stack_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "metadata_buffer_test",
+      "build": "test",
+      "src": [
+        "test/core/channel/metadata_buffer_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "grpc_completion_queue_test",
+      "build": "test",
+      "src": [
+        "test/core/surface/completion_queue_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "grpc_completion_queue_benchmark",
+      "build": "benchmark",
+      "src": [
+        "test/core/surface/completion_queue_benchmark.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "census_window_stats_test",
+      "build": "test",
+      "src": [
+        "test/core/statistics/window_stats_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "census_statistics_quick_test",
+      "build": "test",
+      "src": [
+        "test/core/statistics/quick_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "census_statistics_performance_test",
+      "build": "test",
+      "src": [
+        "test/core/statistics/performance_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "census_statistics_multiple_writers_test",
+      "build": "test",
+      "src": [
+        "test/core/statistics/multiple_writers_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "census_statistics_multiple_writers_circular_buffer_test",
+      "build": "test",
+      "src": [
+        "test/core/statistics/multiple_writers_circular_buffer_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "census_stub_test",
+      "build": "test",
+      "src": [
+        "test/core/statistics/census_stub_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "census_hash_table_test",
+      "build": "test",
+      "src": [
+        "test/core/statistics/hash_table_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "fling_server",
+      "build": "test",
+      "run": false,
+      "src": [
+        "test/core/fling/server.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "fling_client",
+      "build": "test",
+      "run": false,
+      "src": [
+        "test/core/fling/client.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "fling_test",
+      "build": "test",
+      "src": [
+        "test/core/fling/fling_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "echo_server",
+      "build": "test",
+      "run": false,
+      "src": [
+        "test/core/echo/server.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "echo_client",
+      "build": "test",
+      "run": false,
+      "src": [
+        "test/core/echo/client.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "echo_test",
+      "build": "test",
+      "src": [
+        "test/core/echo/echo_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "low_level_ping_pong_benchmark",
+      "build": "benchmark",
+      "src": [
+        "test/core/network_benchmarks/low_level_ping_pong.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "message_compress_test",
+      "build": "test",
+      "src": [
+        "test/core/compression/message_compress_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+
+    {
+      "name": "secure_endpoint_test",
+      "build": "test",
+      "src": [
+        "test/core/endpoint/secure_endpoint_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "httpcli_format_request_test",
+      "build": "test",
+      "src": [
+        "test/core/httpcli/format_request_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "httpcli_parser_test",
+      "build": "test",
+      "src": [
+        "test/core/httpcli/parser_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "httpcli_test",
+      "build": "test",
+      "src": [
+        "test/core/httpcli/httpcli_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "grpc_credentials_test",
+      "build": "test",
+      "src": [
+        "test/core/security/credentials_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "fling_stream_test",
+      "build": "test",
+      "src": [
+        "test/core/fling/fling_stream_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "lame_client_test",
+      "build": "test",
+      "src": [
+        "test/core/surface/lame_client_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr"
+      ]
+    },
+
+    {
+      "name": "thread_pool_test",
+      "build": "test",
+      "c++": true,
+      "src": [
+        "test/cpp/server/thread_pool_test.cc"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "status_test",
+      "build": "test",
+      "c++": true,
+      "src": [
+        "test/cpp/util/status_test.cc"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr"
+      ]
+    }
+
+  ]
+}
diff --git a/include/grpc++/async_server.h b/include/grpc++/async_server.h
new file mode 100644
index 0000000..fe2c5d9
--- /dev/null
+++ b/include/grpc++/async_server.h
@@ -0,0 +1,70 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_ASYNC_SERVER_H__
+#define __GRPCPP_ASYNC_SERVER_H__
+
+#include <mutex>
+
+#include <grpc++/config.h>
+
+struct grpc_server;
+
+namespace grpc {
+class CompletionQueue;
+
+class AsyncServer {
+ public:
+  explicit AsyncServer(CompletionQueue* cc);
+  ~AsyncServer();
+
+  void AddPort(const grpc::string& addr);
+
+  void Start();
+
+  // The user has to call this to get one new rpc on the completion
+  // queue.
+  void RequestOneRpc();
+
+  void Shutdown();
+
+ private:
+  bool started_;
+  std::mutex shutdown_mu_;
+  bool shutdown_;
+  grpc_server* server_;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_ASYNC_SERVER_H__
diff --git a/include/grpc++/async_server_context.h b/include/grpc++/async_server_context.h
new file mode 100644
index 0000000..dd4097b
--- /dev/null
+++ b/include/grpc++/async_server_context.h
@@ -0,0 +1,93 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_ASYNC_SERVER_CONTEXT_H__
+#define __GRPCPP_ASYNC_SERVER_CONTEXT_H__
+
+#include <chrono>
+
+#include <grpc++/config.h>
+
+struct grpc_byte_buffer;
+struct grpc_call;
+struct grpc_completion_queue;
+
+namespace google {
+namespace protobuf {
+class Message;
+}
+}
+
+using std::chrono::system_clock;
+
+namespace grpc {
+class Status;
+
+// TODO(rocking): wrap grpc c structures.
+class AsyncServerContext {
+ public:
+  AsyncServerContext(grpc_call* call, const grpc::string& method,
+                     const grpc::string& host,
+                     system_clock::time_point absolute_deadline);
+  ~AsyncServerContext();
+
+  // Accept this rpc, bind it to a completion queue.
+  void Accept(grpc_completion_queue* cq);
+
+  // Read and write calls, all async. Return true for success.
+  bool StartRead(google::protobuf::Message* request);
+  bool StartWrite(const google::protobuf::Message& response, int flags);
+  bool StartWriteStatus(const Status& status);
+
+  bool ParseRead(grpc_byte_buffer* read_buffer);
+
+  grpc::string method() const { return method_; }
+  grpc::string host() const { return host_; }
+  system_clock::time_point absolute_deadline() { return absolute_deadline_; }
+
+ private:
+  AsyncServerContext(const AsyncServerContext&);
+  AsyncServerContext& operator=(const AsyncServerContext&);
+
+  // These properties may be moved to a ServerContext class.
+  const grpc::string method_;
+  const grpc::string host_;
+  system_clock::time_point absolute_deadline_;
+
+  google::protobuf::Message* request_;  // not owned
+  grpc_call* call_;           // owned
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_ASYNC_SERVER_CONTEXT_H__
diff --git a/include/grpc++/channel_interface.h b/include/grpc++/channel_interface.h
new file mode 100644
index 0000000..4b9d76e
--- /dev/null
+++ b/include/grpc++/channel_interface.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_CHANNEL_INTERFACE_H__
+#define __GRPCPP_CHANNEL_INTERFACE_H__
+
+#include <grpc++/status.h>
+
+namespace google {
+namespace protobuf {
+class Message;
+}
+}
+
+namespace grpc {
+
+class ClientContext;
+class RpcMethod;
+class StreamContextInterface;
+
+class ChannelInterface {
+ public:
+  virtual ~ChannelInterface() {}
+
+  virtual Status StartBlockingRpc(const RpcMethod& method,
+                                  ClientContext* context,
+                                  const google::protobuf::Message& request,
+                                  google::protobuf::Message* result) = 0;
+
+  virtual StreamContextInterface* CreateStream(const RpcMethod& method,
+                                               ClientContext* context,
+                                               const google::protobuf::Message* request,
+                                               google::protobuf::Message* result) = 0;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_CHANNEL_INTERFACE_H__
diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h
new file mode 100644
index 0000000..8301b3c
--- /dev/null
+++ b/include/grpc++/client_context.h
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_CLIENT_CONTEXT_H__
+#define __GRPCPP_CLIENT_CONTEXT_H__
+
+#include <chrono>
+#include <string>
+#include <vector>
+
+#include <grpc++/config.h>
+
+using std::chrono::system_clock;
+
+struct grpc_call;
+struct grpc_completion_queue;
+
+namespace grpc {
+
+class ClientContext {
+ public:
+  ClientContext();
+  ~ClientContext();
+
+  void AddMetadata(const grpc::string &meta_key,
+                   const grpc::string &meta_value);
+
+  void set_absolute_deadline(const system_clock::time_point &deadline);
+  system_clock::time_point absolute_deadline();
+
+  void StartCancel();
+
+ private:
+  // Disallow copy and assign.
+  ClientContext(const ClientContext &);
+  ClientContext &operator=(const ClientContext &);
+
+  friend class Channel;
+  friend class StreamContext;
+
+  grpc_call *call() { return call_; }
+  void set_call(grpc_call *call) { call_ = call; }
+
+  grpc_completion_queue *cq() { return cq_; }
+  void set_cq(grpc_completion_queue *cq) { cq_ = cq; }
+
+  grpc_call *call_;
+  grpc_completion_queue *cq_;
+  system_clock::time_point absolute_deadline_;
+  std::vector<std::pair<grpc::string, grpc::string> > metadata_;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_CLIENT_CONTEXT_H__
diff --git a/include/grpc++/completion_queue.h b/include/grpc++/completion_queue.h
new file mode 100644
index 0000000..72f6253
--- /dev/null
+++ b/include/grpc++/completion_queue.h
@@ -0,0 +1,87 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_COMPLETION_QUEUE_H__
+#define __GRPCPP_COMPLETION_QUEUE_H__
+
+struct grpc_completion_queue;
+
+namespace grpc {
+
+// grpc_completion_queue wrapper class
+class CompletionQueue {
+ public:
+  CompletionQueue();
+  ~CompletionQueue();
+
+  enum CompletionType {
+    QUEUE_CLOSED = 0,       // Shutting down.
+    RPC_END = 1,            // An RPC finished. Either at client or server.
+    CLIENT_READ_OK = 2,     // A client-side read has finished successfully.
+    CLIENT_READ_ERROR = 3,  // A client-side read has finished with error.
+    CLIENT_WRITE_OK = 4,
+    CLIENT_WRITE_ERROR = 5,
+    SERVER_RPC_NEW = 6,     // A new RPC just arrived at the server.
+    SERVER_READ_OK = 7,     // A server-side read has finished successfully.
+    SERVER_READ_ERROR = 8,  // A server-side read has finished with error.
+    SERVER_WRITE_OK = 9,
+    SERVER_WRITE_ERROR = 10,
+    // Client or server has sent half close successfully.
+    HALFCLOSE_OK = 11,
+    // New CompletionTypes may be added in the future, so user code should
+    // always
+    // handle the default case of a CompletionType that appears after such code
+    // was
+    // written.
+    DO_NOT_USE = 20,
+  };
+
+  // Blocking read from queue.
+  // For QUEUE_CLOSED, *tag is not changed.
+  // For SERVER_RPC_NEW, *tag will be a newly allocated AsyncServerContext.
+  // For others, *tag will be the AsyncServerContext of this rpc.
+  CompletionType Next(void** tag);
+
+  // Shutdown has to be called, and the CompletionQueue can only be
+  // destructed when the QUEUE_CLOSED message has been read with Next().
+  void Shutdown();
+
+  grpc_completion_queue* cq() { return cq_; }
+
+ private:
+  grpc_completion_queue* cq_;  // owned
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_COMPLETION_QUEUE_H__
diff --git a/include/grpc++/config.h b/include/grpc++/config.h
new file mode 100644
index 0000000..153b288
--- /dev/null
+++ b/include/grpc++/config.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_CONFIG_H__
+#define __GRPCPP_CONFIG_H__
+
+#include <string>
+
+namespace grpc {
+
+typedef std::string string;
+
+}
+
+#endif  // __GRPCPP_CONFIG_H__
diff --git a/include/grpc++/create_channel.h b/include/grpc++/create_channel.h
new file mode 100644
index 0000000..3bb16b2
--- /dev/null
+++ b/include/grpc++/create_channel.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_CREATE_CHANNEL_H__
+#define __GRPCPP_CREATE_CHANNEL_H__
+
+#include <memory>
+
+#include <grpc++/config.h>
+#include <grpc++/credentials.h>
+
+namespace grpc {
+class ChannelInterface;
+
+std::shared_ptr<ChannelInterface> CreateChannel(const grpc::string& target);
+
+std::shared_ptr<ChannelInterface> CreateChannel(
+    const grpc::string& target,
+    const std::unique_ptr<grpc::Credentials>& creds);
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_CREATE_CHANNEL_H__
diff --git a/include/grpc++/credentials.h b/include/grpc++/credentials.h
new file mode 100644
index 0000000..f0db6c2
--- /dev/null
+++ b/include/grpc++/credentials.h
@@ -0,0 +1,95 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_CREDENTIALS_H_
+#define __GRPCPP_CREDENTIALS_H_
+
+#include <memory>
+
+#include <grpc++/config.h>
+
+struct grpc_credentials;
+
+namespace grpc {
+
+// grpc_credentials wrapper class. Typical use in C++ applications is limited
+// to creating an instance using CredentialsFactory, and passing it down
+// during channel construction.
+
+class Credentials final {
+ public:
+  ~Credentials();
+  // TODO(abhikumar): Specify a plugin API here to be implemented by
+  // credentials that do not have a corresponding implementation in C.
+
+ protected:
+  explicit Credentials(grpc_credentials*);
+
+ private:
+  grpc_credentials* GetRawCreds();
+
+  friend class CredentialsFactory;
+
+  grpc_credentials* creds_;
+};
+
+// Options used to build SslCredentials
+struct SslCredentialsOptions {
+  grpc::string pem_root_certs;
+  grpc::string pem_private_key;
+  grpc::string pem_cert_chain;
+};
+
+// Factory for building different types of Credentials
+class CredentialsFactory {
+ public:
+  // Builds credentials with reasonable defaults.
+  static std::unique_ptr<Credentials> DefaultCredentials();
+
+  // Builds SSL Credentials given SSL specific options
+  static std::unique_ptr<Credentials> SslCredentials(
+      const SslCredentialsOptions& options);
+
+  // Builds credentials for use when running in GCE
+  static std::unique_ptr<Credentials> ComputeEngineCredentials();
+
+
+  // Combines two credentials objects into a composite credentials
+  static std::unique_ptr<Credentials> ComposeCredentials(
+      const std::unique_ptr<Credentials>& creds1,
+      const std::unique_ptr<Credentials>& creds2);
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_CREDENTIALS_H_
diff --git a/include/grpc++/server.h b/include/grpc++/server.h
new file mode 100644
index 0000000..443b4d4
--- /dev/null
+++ b/include/grpc++/server.h
@@ -0,0 +1,111 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_SERVER_H__
+#define __GRPCPP_SERVER_H__
+
+#include <condition_variable>
+#include <map>
+#include <memory>
+#include <mutex>
+
+#include <grpc++/completion_queue.h>
+#include <grpc++/config.h>
+#include <grpc++/status.h>
+
+struct grpc_server;
+
+namespace google {
+namespace protobuf {
+class Message;
+}
+}
+
+namespace grpc {
+class AsyncServerContext;
+class RpcService;
+class RpcServiceMethod;
+class ThreadPoolInterface;
+
+// Currently it only supports handling rpcs in a single thread.
+class Server {
+ public:
+  ~Server();
+
+  // Shutdown the server, block until all rpc processing finishes.
+  void Shutdown();
+
+ private:
+  friend class ServerBuilder;
+
+  // ServerBuilder use only
+  explicit Server(ThreadPoolInterface* thread_pool);
+  Server();
+  // Register a service. This call does not take ownership of the service.
+  // The service must exist for the lifetime of the Server instance.
+  void RegisterService(RpcService* service);
+  // Add a listening port. Can be called multiple times.
+  void AddPort(const grpc::string& addr);
+  // Start the server.
+  void Start();
+
+  void AllowOneRpc();
+  void HandleQueueClosed();
+  void RunRpc();
+  void ScheduleCallback();
+
+  // Completion queue.
+  CompletionQueue cq_;
+
+  // Sever status
+  std::mutex mu_;
+  bool started_;
+  bool shutdown_;
+  // The number of threads which are running callbacks.
+  int num_running_cb_;
+  std::condition_variable callback_cv_;
+
+  // Pointer to the c grpc server.
+  grpc_server* server_;
+
+  // A map for all method information.
+  std::map<grpc::string, RpcServiceMethod*> method_map_;
+
+  ThreadPoolInterface* thread_pool_;
+  // Whether the thread pool is created and owned by the server.
+  bool thread_pool_owned_;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_SERVER_H__
diff --git a/include/grpc++/server_builder.h b/include/grpc++/server_builder.h
new file mode 100644
index 0000000..89e9a25
--- /dev/null
+++ b/include/grpc++/server_builder.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_SERVER_BUILDER_H__
+#define __GRPCPP_SERVER_BUILDER_H__
+
+#include <memory>
+#include <vector>
+
+#include <grpc++/config.h>
+
+namespace grpc {
+
+class RpcService;
+class Server;
+class ThreadPoolInterface;
+
+class ServerBuilder {
+ public:
+  ServerBuilder();
+
+  // Register a service. This call does not take ownership of the service.
+  // The service must exist for the lifetime of the Server instance returned by
+  // BuildAndStart().
+  void RegisterService(RpcService* service);
+
+  // Add a listening port. Can be called multiple times.
+  void AddPort(const grpc::string& addr);
+
+  // Set the thread pool used for running appliation rpc handlers.
+  // Does not take ownership.
+  void SetThreadPool(ThreadPoolInterface* thread_pool);
+
+  // Return a running server which is ready for processing rpcs.
+  std::unique_ptr<Server> BuildAndStart();
+
+ private:
+  std::vector<RpcService*> services_;
+  std::vector<grpc::string> ports_;
+  ThreadPoolInterface* thread_pool_;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_SERVER_BUILDER_H__
diff --git a/include/grpc++/status.h b/include/grpc++/status.h
new file mode 100644
index 0000000..432158a
--- /dev/null
+++ b/include/grpc++/status.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_STATUS_H__
+#define __GRPCPP_STATUS_H__
+
+#include <grpc++/status_code_enum.h>
+#include <grpc++/config.h>
+
+namespace grpc {
+
+class Status {
+ public:
+  Status() : code_(StatusCode::OK) {}
+  explicit Status(StatusCode code) : code_(code) {}
+  Status(StatusCode code, const grpc::string& details)
+      : code_(code), details_(details) {}
+
+  // Pre-defined special status objects.
+  static const Status& OK;
+  static const Status& Cancelled;
+
+  StatusCode code() const { return code_; }
+  grpc::string details() const { return details_; }
+
+  bool IsOk() const { return code_ == StatusCode::OK; }
+
+ private:
+  StatusCode code_;
+  grpc::string details_;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_STATUS_H__
diff --git a/include/grpc++/status_code_enum.h b/include/grpc++/status_code_enum.h
new file mode 100644
index 0000000..964420d
--- /dev/null
+++ b/include/grpc++/status_code_enum.h
@@ -0,0 +1,199 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_STATUS_CODE_ENUM_H__
+#define __GRPCPP_STATUS_CODE_ENUM_H__
+
+
+namespace grpc {
+
+enum StatusCode {
+  /* Not an error; returned on success
+
+     HTTP Mapping: 200 OK */
+  OK = 0,
+
+  /* The operation was cancelled (typically by the caller).
+
+     HTTP Mapping: 499 Client Closed Request */
+  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.
+
+     HTTP Mapping: 500 Internal Server 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).
+
+     HTTP Mapping: 400 Bad Request */
+  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.
+
+     HTTP Mapping: 504 Gateway Timeout */
+  DEADLINE_EXCEEDED = 4,
+
+  /* Some requested entity (e.g., file or directory) was not found.
+
+     HTTP Mapping: 404 Not Found */
+  NOT_FOUND = 5,
+
+  /* Some entity that we attempted to create (e.g., file or directory)
+     already exists.
+
+     HTTP Mapping: 409 Conflict */
+  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).
+
+     HTTP Mapping: 403 Forbidden */
+  PERMISSION_DENIED = 7,
+
+  /* The request does not have valid authentication credentials for the
+     operation.
+
+     HTTP Mapping: 401 Unauthorized */
+  UNAUTHENTICATED = 16,
+
+  /* Some resource has been exhausted, perhaps a per-user quota, or
+     perhaps the entire file system is out of space.
+
+     HTTP Mapping: 429 Too Many Requests */
+  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.
+
+     HTTP Mapping: 400 Bad Request
+
+     NOTE: HTTP spec says 412 Precondition Failed should only be used if
+     the request contains Etag related headers. So if the server does see
+     Etag related headers in the request, it may choose to return 412
+     instead of 400 for this error code. */
+  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.
+
+     HTTP Mapping: 409 Conflict */
+  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.
+
+     HTTP Mapping: 400 Bad Request */
+  OUT_OF_RANGE = 11,
+
+  /* Operation is not implemented or not supported/enabled in this service.
+
+     HTTP Mapping: 501 Not Implemented */
+  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.
+
+     HTTP Mapping: 500 Internal Server Error */
+  INTERNAL = 13,
+
+  /* The service is currently unavailable.  This is a most likely a
+     transient condition and may be corrected by retrying with
+     a backoff.
+
+     See litmus test above for deciding between FAILED_PRECONDITION,
+     ABORTED, and UNAVAILABLE.
+
+     HTTP Mapping: 503 Service Unavailable */
+  UNAVAILABLE = 14,
+
+  /* Unrecoverable data loss or corruption.
+
+     HTTP Mapping: 500 Internal Server Error */
+  DATA_LOSS = 15,
+
+  /* Force users to include a default branch: */
+  DO_NOT_USE = -1
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_STATUS_CODE_ENUM_H_
diff --git a/include/grpc++/stream.h b/include/grpc++/stream.h
new file mode 100644
index 0000000..50c2156
--- /dev/null
+++ b/include/grpc++/stream.h
@@ -0,0 +1,178 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_STREAM_H__
+#define __GRPCPP_STREAM_H__
+
+#include <grpc++/stream_context_interface.h>
+#include <grpc++/status.h>
+#include <grpc/support/log.h>
+
+namespace grpc {
+
+// Common interface for all client side streaming.
+class ClientStreamingInterface {
+ public:
+  virtual ~ClientStreamingInterface() {}
+
+  // Try to cancel the stream. Wait() still needs to be called to get the final
+  // status. Cancelling after the stream has finished has no effects.
+  virtual void Cancel() = 0;
+
+  // Wait until the stream finishes, and return the final status. When the
+  // client side declares it has no more message to send, either implicitly or
+  // by calling WritesDone, it needs to make sure there is no more message to
+  // be received from the server, either implicitly or by getting a false from
+  // a Read(). Otherwise, this implicitly cancels the stream.
+  virtual const Status& Wait() = 0;
+};
+
+// An interface that yields a sequence of R messages.
+template <class R>
+class ReaderInterface {
+ public:
+  virtual ~ReaderInterface() {}
+
+  // Blocking read a message and parse to msg. Returns true on success.
+  // The method returns false when there will be no more incoming messages,
+  // either because the other side has called WritesDone or the stream has
+  // failed (or been cancelled).
+  virtual bool Read(R* msg) = 0;
+};
+
+// An interface that can be fed a sequence of W messages.
+template <class W>
+class WriterInterface {
+ public:
+  virtual ~WriterInterface() {}
+
+  // Blocking write msg to the stream. Returns true on success.
+  // Returns false when the stream has been closed.
+  virtual bool Write(const W& msg) = 0;
+};
+
+template <class R>
+class ClientReader : public ClientStreamingInterface,
+                     public ReaderInterface<R> {
+ public:
+  // Blocking create a stream and write the first request out.
+  explicit ClientReader(StreamContextInterface* context) : context_(context) {
+    GPR_ASSERT(context_);
+    context_->Start(true);
+    context_->Write(context_->request(), true);
+  }
+
+  ~ClientReader() { delete context_; }
+
+  virtual bool Read(R* msg) { return context_->Read(msg); }
+
+  virtual void Cancel() { context_->FinishStream(Status::Cancelled, true); }
+
+  virtual const Status& Wait() { return context_->Wait(); }
+
+ private:
+  StreamContextInterface* const context_;
+};
+
+template <class W>
+class ClientWriter : public ClientStreamingInterface,
+                     public WriterInterface<W> {
+ public:
+  // Blocking create a stream.
+  explicit ClientWriter(StreamContextInterface* context) : context_(context) {
+    GPR_ASSERT(context_);
+    context_->Start(false);
+  }
+
+  ~ClientWriter() { delete context_; }
+
+  virtual bool Write(const W& msg) {
+    return context_->Write(const_cast<W*>(&msg), false);
+  }
+
+  virtual void WritesDone() { context_->Write(nullptr, true); }
+
+  virtual void Cancel() { context_->FinishStream(Status::Cancelled, true); }
+
+  // Read the final response and wait for the final status.
+  virtual const Status& Wait() {
+    bool success = context_->Read(context_->response());
+    if (!success) {
+      Cancel();
+    } else {
+      success = context_->Read(nullptr);
+      if (success) {
+        Cancel();
+      }
+    }
+    return context_->Wait();
+  }
+
+ private:
+  StreamContextInterface* const context_;
+};
+
+// Client-side interface for bi-directional streaming.
+template <class W, class R>
+class ClientReaderWriter : public ClientStreamingInterface,
+                           public WriterInterface<W>,
+                           public ReaderInterface<R> {
+ public:
+  // Blocking create a stream.
+  explicit ClientReaderWriter(StreamContextInterface* context)
+      : context_(context) {
+    GPR_ASSERT(context_);
+    context_->Start(false);
+  }
+
+  ~ClientReaderWriter() { delete context_; }
+
+  virtual bool Read(R* msg) { return context_->Read(msg); }
+
+  virtual bool Write(const W& msg) {
+    return context_->Write(const_cast<W*>(&msg), false);
+  }
+
+  virtual void WritesDone() { context_->Write(nullptr, true); }
+
+  virtual void Cancel() { context_->FinishStream(Status::Cancelled, true); }
+
+  virtual const Status& Wait() { return context_->Wait(); }
+
+ private:
+  StreamContextInterface* const context_;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_STREAM_H__
diff --git a/include/grpc++/stream_context_interface.h b/include/grpc++/stream_context_interface.h
new file mode 100644
index 0000000..eb5c092
--- /dev/null
+++ b/include/grpc++/stream_context_interface.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_STREAM_CONTEXT_INTERFACE_H__
+#define __GRPCPP_STREAM_CONTEXT_INTERFACE_H__
+
+namespace google {
+namespace protobuf {
+class Message;
+}
+}
+
+namespace grpc {
+class Status;
+
+// An interface to avoid dependency on internal implementation.
+class StreamContextInterface {
+ public:
+  virtual ~StreamContextInterface() {}
+
+  virtual void Start(bool buffered) = 0;
+
+  virtual bool Read(google::protobuf::Message* msg) = 0;
+  virtual bool Write(const google::protobuf::Message* msg, bool is_last) = 0;
+  virtual const Status& Wait() = 0;
+  virtual void FinishStream(const Status& status, bool send) = 0;
+
+  virtual const google::protobuf::Message* request() = 0;
+  virtual google::protobuf::Message* response() = 0;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_STREAM_CONTEXT_INTERFACE_H__
diff --git a/include/grpc++/thread_pool_interface.h b/include/grpc++/thread_pool_interface.h
new file mode 100644
index 0000000..a8eacb0
--- /dev/null
+++ b/include/grpc++/thread_pool_interface.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_THREAD_POOL_INTERFACE_H__
+#define __GRPCPP_THREAD_POOL_INTERFACE_H__
+
+#include <functional>
+
+namespace grpc {
+
+// A thread pool interface for running callbacks.
+class ThreadPoolInterface {
+ public:
+  virtual ~ThreadPoolInterface() {}
+
+  // Schedule the given callback for execution.
+  virtual void ScheduleCallback(const std::function<void()>& callback) = 0;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_THREAD_POOL_INTERFACE_H__
diff --git a/include/grpc/byte_buffer.h b/include/grpc/byte_buffer.h
new file mode 100644
index 0000000..0db59d7
--- /dev/null
+++ b/include/grpc/byte_buffer.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_BYTE_BUFFER_H__
+#define __GRPC_BYTE_BUFFER_H__
+
+#include <grpc/grpc.h>
+#include <grpc/support/slice_buffer.h>
+
+typedef enum { GRPC_BB_SLICE_BUFFER } grpc_byte_buffer_type;
+
+/* byte buffers are what meesages are passed in as from the public api's */
+struct grpc_byte_buffer {
+  grpc_byte_buffer_type type;
+  union {
+    gpr_slice_buffer slice_buffer;
+  } data;
+};
+
+#endif  /* __GRPC_BYTE_BUFFER_H__ */
diff --git a/include/grpc/byte_buffer_reader.h b/include/grpc/byte_buffer_reader.h
new file mode 100644
index 0000000..5f1c160
--- /dev/null
+++ b/include/grpc/byte_buffer_reader.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_BYTE_BUFFER_READER_H__
+#define __GRPC_BYTE_BUFFER_READER_H__
+
+#include <grpc/grpc.h>
+#include <grpc/byte_buffer.h>
+
+struct grpc_byte_buffer_reader {
+  grpc_byte_buffer *buffer;
+  /* Different current objects correspond to different types of byte buffers */
+  union {
+    /* Index into a slice buffer's array of slices */
+    int index;
+  } current;
+};
+
+#endif  /* __GRPC_BYTE_BUFFER_READER_H__ */
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
new file mode 100644
index 0000000..17e155a
--- /dev/null
+++ b/include/grpc/grpc.h
@@ -0,0 +1,421 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_GRPC_H__
+#define __GRPC_GRPC_H__
+
+#include <grpc/status.h>
+
+#include <stddef.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Completion Channels enable notification of the completion of asynchronous
+   actions. */
+typedef struct grpc_completion_queue grpc_completion_queue;
+
+/* The Channel interface allows creation of Call objects. */
+typedef struct grpc_channel grpc_channel;
+
+/* A server listens to some port and responds to request calls */
+typedef struct grpc_server grpc_server;
+
+/* A Call represents an RPC. When created, it is in a configuration state
+   allowing properties to be set until it is invoked. After invoke, the Call
+   can have messages written to it and read from it. */
+typedef struct grpc_call grpc_call;
+
+/* Type specifier for grpc_arg */
+typedef enum {
+  GRPC_ARG_STRING,
+  GRPC_ARG_INTEGER,
+  GRPC_ARG_POINTER
+} grpc_arg_type;
+
+/* A single argument... each argument has a key and a value
+
+   A note on naming keys:
+     Keys are namespaced into groups, usually grouped by library, and are
+     keys for module XYZ are named XYZ.key1, XYZ.key2, etc. Module names must
+     be restricted to the regex [A-Za-z][_A-Za-z0-9]{,15}.
+     Key names must be restricted to the regex [A-Za-z][_A-Za-z0-9]{,47}.
+
+     GRPC core library keys are prefixed by grpc.
+
+     Library authors are strongly encouraged to #define symbolic constants for
+     their keys so that it's possible to change them in the future. */
+typedef struct {
+  grpc_arg_type type;
+  char *key;
+  union {
+    char *string;
+    int integer;
+    struct {
+      void *p;
+      void *(*copy)(void *p);
+      void (*destroy)(void *p);
+    } pointer;
+  } value;
+} grpc_arg;
+
+/* An array of arguments that can be passed around */
+typedef struct {
+  size_t num_args;
+  grpc_arg *args;
+} grpc_channel_args;
+
+/* Channel argument keys: */
+/* Enable census for tracing and stats collection */
+#define GRPC_ARG_ENABLE_CENSUS "grpc.census"
+/* Maximum number of concurrent incoming streams to allow on a http2
+   connection */
+#define GRPC_ARG_MAX_CONCURRENT_STREAMS "grpc.max_concurrent_streams"
+/* Maximum message length that the channel can receive */
+#define GRPC_ARG_MAX_MESSAGE_LENGTH "grpc.max_message_length"
+
+/* Status of a completed call */
+typedef struct grpc_status {
+  grpc_status_code code;
+  char *details;
+} grpc_status;
+
+/* Result of a grpc call. If the caller satisfies the prerequisites of a
+   particular operation, the grpc_call_error returned will be GRPC_CALL_OK.
+   Receiving any other value listed here is an indication of a bug in the
+   caller. */
+typedef enum grpc_call_error {
+  /* everything went ok */
+  GRPC_CALL_OK = 0,
+  /* something failed, we don't know what */
+  GRPC_CALL_ERROR,
+  /* this method is not available on the server */
+  GRPC_CALL_ERROR_NOT_ON_SERVER,
+  /* this method is not available on the client */
+  GRPC_CALL_ERROR_NOT_ON_CLIENT,
+  /* this method must be called before invoke */
+  GRPC_CALL_ERROR_ALREADY_INVOKED,
+  /* this method must be called after invoke */
+  GRPC_CALL_ERROR_NOT_INVOKED,
+  /* this call is already finished
+     (writes_done or write_status has already been called) */
+  GRPC_CALL_ERROR_ALREADY_FINISHED,
+  /* there is already an outstanding read/write operation on the call */
+  GRPC_CALL_ERROR_TOO_MANY_OPERATIONS,
+  /* the flags value was illegal for this call */
+  GRPC_CALL_ERROR_INVALID_FLAGS
+} grpc_call_error;
+
+/* Result of a grpc operation */
+typedef enum grpc_op_error {
+  /* everything went ok */
+  GRPC_OP_OK = 0,
+  /* something failed, we don't know what */
+  GRPC_OP_ERROR
+} grpc_op_error;
+
+/* Write Flags: */
+/* Hint that the write may be buffered and need not go out on the wire
+   immediately. GRPC is free to buffer the message until the next non-buffered
+   write, or until writes_done, but it need not buffer completely or at all. */
+#define GRPC_WRITE_BUFFER_HINT (0x00000001u)
+/* Force compression to be disabled for a particular write
+   (start_write/add_metadata). Illegal on invoke/accept. */
+#define GRPC_WRITE_NO_COMPRESS (0x00000002u)
+
+/* A buffer of bytes */
+struct grpc_byte_buffer;
+typedef struct grpc_byte_buffer grpc_byte_buffer;
+
+/* Sample helpers to obtain byte buffers (these will certainly move place */
+grpc_byte_buffer *grpc_byte_buffer_create(gpr_slice *slices, size_t nslices);
+size_t grpc_byte_buffer_length(grpc_byte_buffer *bb);
+void grpc_byte_buffer_destroy(grpc_byte_buffer *byte_buffer);
+
+/* Reader for byte buffers. Iterates over slices in the byte buffer */
+struct grpc_byte_buffer_reader;
+typedef struct grpc_byte_buffer_reader grpc_byte_buffer_reader;
+
+grpc_byte_buffer_reader *grpc_byte_buffer_reader_create(
+    grpc_byte_buffer *buffer);
+/* At the end of the stream, returns 0. Otherwise, returns 1 and sets slice to
+   be the returned slice. Caller is responsible for calling gpr_slice_unref on
+   the result. */
+int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
+                                 gpr_slice *slice);
+void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader);
+
+/* A single metadata element */
+typedef struct grpc_metadata {
+  char *key;
+  char *value;
+  size_t value_length;
+} grpc_metadata;
+
+typedef enum grpc_completion_type {
+  GRPC_QUEUE_SHUTDOWN,       /* Shutting down */
+  GRPC_READ,                 /* A read has completed */
+  GRPC_INVOKE_ACCEPTED,      /* An invoke call has been accepted by flow
+                                control */
+  GRPC_WRITE_ACCEPTED,       /* A write has been accepted by
+                                flow control */
+  GRPC_FINISH_ACCEPTED,      /* writes_done or write_status has been accepted */
+  GRPC_CLIENT_METADATA_READ, /* The metadata array sent by server received at
+                                client */
+  GRPC_FINISHED,             /* An RPC has finished. The event contains status.
+                                On the server this will be OK or Cancelled. */
+  GRPC_SERVER_RPC_NEW,       /* A new RPC has arrived at the server */
+  GRPC_COMPLETION_DO_NOT_USE /* must be last, forces users to include
+                                a default: case */
+} grpc_completion_type;
+
+typedef struct grpc_event {
+  grpc_completion_type type;
+  void *tag;
+  grpc_call *call;
+  /* Data associated with the completion type. Field names match the type of
+     completion as listed in grpc_completion_type. */
+  union {
+    /* Contains a pointer to the buffer that was read, or NULL at the end of a
+       stream. */
+    grpc_byte_buffer *read;
+    grpc_op_error write_accepted;
+    grpc_op_error finish_accepted;
+    grpc_op_error invoke_accepted;
+    struct {
+      size_t count;
+      grpc_metadata *elements;
+    } client_metadata_read;
+    grpc_status finished;
+    struct {
+      const char *method;
+      const char *host;
+      gpr_timespec deadline;
+      size_t metadata_count;
+      grpc_metadata *metadata_elements;
+    } server_rpc_new;
+  } data;
+} grpc_event;
+
+/* Initialize the grpc library */
+void grpc_init();
+
+/* Shutdown the grpc library */
+void grpc_shutdown();
+
+grpc_completion_queue *grpc_completion_queue_create();
+
+/* Blocks until an event is available, the completion queue is being shutdown,
+   or deadline is reached. Returns NULL on timeout, otherwise the event that
+   occurred. Callers should call grpc_event_finish once they have processed
+   the event.
+
+   Callers must not call grpc_completion_queue_next and
+   grpc_completion_queue_pluck simultaneously on the same completion queue. */
+grpc_event *grpc_completion_queue_next(grpc_completion_queue *cq,
+                                       gpr_timespec deadline);
+
+/* Blocks until an event with tag 'tag' is available, the completion queue is
+   being shutdown or deadline is reached. Returns NULL on timeout, or a pointer
+   to the event that occurred. Callers should call grpc_event_finish once they
+   have processed the event.
+
+   Callers must not call grpc_completion_queue_next and
+   grpc_completion_queue_pluck simultaneously on the same completion queue. */
+grpc_event *grpc_completion_queue_pluck(grpc_completion_queue *cq, void *tag,
+                                        gpr_timespec deadline);
+
+/* Cleanup any data owned by the event */
+void grpc_event_finish(grpc_event *event);
+
+/* Begin destruction of a completion queue. Once all possible events are
+   drained it's safe to call grpc_completion_queue_destroy. */
+void grpc_completion_queue_shutdown(grpc_completion_queue *cq);
+
+/* Destroy a completion queue. The caller must ensure that the queue is
+   drained and no threads are executing grpc_completion_queue_next */
+void grpc_completion_queue_destroy(grpc_completion_queue *cq);
+
+/* Create a call given a grpc_channel, in order to call 'method'. The request
+   is not sent until grpc_call_invoke is called. All completions are sent to
+   'completion_queue'. */
+grpc_call *grpc_channel_create_call(grpc_channel *channel, const char *method,
+                                    const char *host, gpr_timespec deadline);
+
+/* Create a client channel */
+grpc_channel *grpc_channel_create(const char *target,
+                                  const grpc_channel_args *args);
+
+/* Close and destroy a grpc channel */
+void grpc_channel_destroy(grpc_channel *channel);
+
+/* THREAD-SAFETY for grpc_call
+   The following functions are thread-compatible for any given call:
+     grpc_call_add_metadata
+     grpc_call_invoke
+     grpc_call_start_write
+     grpc_call_writes_done
+     grpc_call_start_read
+     grpc_call_destroy
+   The function grpc_call_cancel is thread-safe, and can be called at any
+   point before grpc_call_destroy is called. */
+
+/* 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.
+   If a grpc_call fails, it's guaranteed that no change to the call state
+   has been made. */
+
+/* Add a single metadata element to the call, to be sent upon invocation.
+   flags is a bit-field combination of the write flags defined above.
+   REQUIRES: grpc_call_start_invoke/grpc_call_accept have not been called on
+             this call.
+   Produces no events. */
+grpc_call_error grpc_call_add_metadata(grpc_call *call, grpc_metadata *metadata,
+                                       gpr_uint32 flags);
+
+/* Invoke the RPC. Starts sending metadata and request headers on the wire.
+   flags is a bit-field combination of the write flags defined above.
+   REQUIRES: Can be called at most once per call.
+             Can only be called on the client.
+   Produces a GRPC_INVOKE_ACCEPTED event with invoke_accepted_tag when the
+       call has been invoked (meaning bytes can start flowing to the wire).
+   Produces a GRPC_CLIENT_METADATA_READ event with metadata_read_tag when
+       the servers initial metadata has been read.
+   Produces a GRPC_FINISHED event with finished_tag when the call has been
+       completed (there may be other events for the call pending at this
+       time) */
+grpc_call_error grpc_call_start_invoke(grpc_call *call,
+                                       grpc_completion_queue *cq,
+                                       void *invoke_accepted_tag,
+                                       void *metadata_read_tag,
+                                       void *finished_tag, gpr_uint32 flags);
+
+/* Accept an incoming RPC, binding a completion queue to it.
+   To be called after adding metadata to the call, but before sending
+   messages.
+   flags is a bit-field combination of the write flags defined above.
+   REQUIRES: Can be called at most once per call.
+             Can only be called on the server.
+   Produces a GRPC_FINISHED event with finished_tag when the call has been
+       completed (there may be other events for the call pending at this
+       time) */
+grpc_call_error grpc_call_accept(grpc_call *call, grpc_completion_queue *cq,
+                                 void *finished_tag, gpr_uint32 flags);
+
+/* Called by clients to cancel an RPC on the server.
+   Can be called multiple times, from any thread. */
+grpc_call_error grpc_call_cancel(grpc_call *call);
+
+/* Queue a byte buffer for writing.
+   flags is a bit-field combination of the write flags defined above.
+   A write with byte_buffer null is allowed, and will not send any bytes on the
+   wire. If this is performed without GRPC_WRITE_BUFFER_HINT flag it provides
+   a mechanism to flush any previously buffered writes to outgoing flow control.
+   REQUIRES: No other writes are pending on the call. It is only safe to
+             start the next write after the corresponding write_accepted event
+             is received.
+             GRPC_INVOKE_ACCEPTED must have been received by the application
+             prior to calling this on the client. On the server,
+             grpc_call_accept must have been called successfully.
+   Produces a GRPC_WRITE_ACCEPTED event. */
+grpc_call_error grpc_call_start_write(grpc_call *call,
+                                      grpc_byte_buffer *byte_buffer, void *tag,
+                                      gpr_uint32 flags);
+
+/* Queue a status for writing.
+   REQUIRES: No other writes are pending on the call.
+             grpc_call_accept must have been called on the call prior to calling
+             this.
+             Only callable on the server.
+   Produces a GRPC_FINISH_ACCEPTED event when the status is sent. */
+grpc_call_error grpc_call_start_write_status(grpc_call *call,
+                                             grpc_status status, void *tag);
+
+/* No more messages to send.
+   REQUIRES: No other writes are pending on the call.
+             Only callable on the client.
+   Produces a GRPC_FINISH_ACCEPTED event when all bytes for the call have passed
+       outgoing flow control. */
+grpc_call_error grpc_call_writes_done(grpc_call *call, void *tag);
+
+/* Initiate a read on a call. Output event contains a byte buffer with the
+   result of the read.
+   REQUIRES: No other reads are pending on the call. It is only safe to start
+             the next read after the corresponding read event is received.
+             GRPC_INVOKE_ACCEPTED must have been received by the application
+             prior to calling this.
+   Produces a single GRPC_READ event. */
+grpc_call_error grpc_call_start_read(grpc_call *call, void *tag);
+
+/* Destroy a call. */
+void grpc_call_destroy(grpc_call *call);
+
+/* Request a call on a server.
+   Allows the server to create a single GRPC_SERVER_RPC_NEW event, with tag
+   tag_new.
+   If the call is subsequently cancelled, the cancellation will occur with tag
+   tag_cancel.
+   REQUIRES: Server must not have been shutdown.
+   NOTE: calling this is the only way to obtain GRPC_SERVER_RPC_NEW events. */
+grpc_call_error grpc_server_request_call(grpc_server *server, void *tag_new);
+
+/* Create a server */
+grpc_server *grpc_server_create(grpc_completion_queue *cq,
+                                const grpc_channel_args *args);
+
+/* Add a http2 over tcp listener; returns 1 on success, 0 on failure
+   REQUIRES: server not started */
+int grpc_server_add_http2_port(grpc_server *server, const char *addr);
+
+/* Add a secure port to server; returns 1 on success, 0 on failure
+   REQUIRES: server not started */
+int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr);
+
+/* Start a server - tells all listeners to start listening */
+void grpc_server_start(grpc_server *server);
+
+/* Begin shutting down a server. */
+void grpc_server_shutdown(grpc_server *server);
+
+/* Destroy a server */
+void grpc_server_destroy(grpc_server *server);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __GRPC_GRPC_H__ */
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
new file mode 100644
index 0000000..cc1d74c
--- /dev/null
+++ b/include/grpc/grpc_security.h
@@ -0,0 +1,143 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_SECURITY_H_
+#define GRPC_SECURITY_H_
+
+#include "grpc.h"
+#include "status.h"
+
+/* --- grpc_credentials object. ---
+
+   A credentials object represents a way to authenticate a client.  */
+
+typedef struct grpc_credentials grpc_credentials;
+
+/* Releases a credentials object.
+   The creator of the credentials object is responsible for its release. */
+void grpc_credentials_release(grpc_credentials *creds);
+
+/* Creates default credentials. */
+grpc_credentials *grpc_default_credentials_create(void);
+
+/* Creates an SSL credentials object.
+   - pem_roots_cert is the buffer containing the PEM encoding of the server
+     root certificates. This parameter cannot be NULL.
+   - pem_roots_cert_size is the size of the associated buffer.
+   - pem_private_key is the buffer containing the PEM encoding of the client's
+     private key. This parameter can be NULL if the client does not have a
+     private key.
+   - pem_private_key_size is the size of the associated buffer.
+   - pem_cert_chain is the buffer containing the PEM encoding of the client's
+     certificate chain. This parameter can be NULL if the client does not have
+     a certificate chain.
+   - pem_cert_chain_size is the size of the associated buffer. */
+grpc_credentials *grpc_ssl_credentials_create(
+    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
+    const unsigned char *pem_private_key, size_t pem_private_key_size,
+    const unsigned char *pem_cert_chain, size_t pem_cert_chain_size);
+
+/* Creates a composite credentials object. */
+grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
+                                                    grpc_credentials *creds2);
+
+/* Creates a compute engine credentials object. */
+grpc_credentials *grpc_compute_engine_credentials_create(void);
+
+/* Creates a fake transport security credentials object for testing. */
+grpc_credentials *grpc_fake_transport_security_credentials_create(void);
+
+
+/* --- Secure channel creation. --- */
+
+/* The caller of the secure_channel_create functions may override the target
+   name used for SSL host name checking using this channel argument which is of
+   type GRPC_ARG_STRING. This *should* be used for testing only.
+   If this argument is not specified, the name used for SSL host name checking
+   will be the target parameter (assuming that the 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"
+
+/* Creates a default secure channel using the default credentials object using
+   the environment. */
+grpc_channel *grpc_default_secure_channel_create(const char *target,
+                                                 const grpc_channel_args *args);
+
+/* Creates a secure channel using the passed-in credentials. */
+grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
+                                         const char *target,
+                                         const grpc_channel_args *args);
+
+/* --- grpc_server_credentials object. ---
+
+   A server credentials object represents a way to authenticate a server.  */
+
+typedef struct grpc_server_credentials grpc_server_credentials;
+
+/* Releases a server_credentials object.
+   The creator of the server_credentials object is responsible for its release.
+   */
+void grpc_server_credentials_release(grpc_server_credentials *creds);
+
+/* Creates an SSL server_credentials object.
+   TODO(jboeuf): Change the constructor so that it can support multiple
+   key/cert pairs.
+   - pem_roots_cert is the buffer 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.
+   - pem_roots_cert_size is the size of the associated buffer.
+   - pem_private_key is the buffer containing the PEM encoding of the client's
+     private key. This parameter cannot be NULL.
+   - pem_private_key_size is the size of the associated buffer.
+   - pem_cert_chain is the buffer containing the PEM encoding of the client's
+     certificate chain. This parameter cannot be NULL.
+   - pem_cert_chain_size is the size of the associated buffer. */
+grpc_server_credentials *grpc_ssl_server_credentials_create(
+    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
+    const unsigned char *pem_private_key, size_t pem_private_key_size,
+    const unsigned char *pem_cert_chain, size_t pem_cert_chain_size);
+
+/* Creates a fake server transport security credentials object for testing. */
+grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
+    void);
+
+
+/* --- Secure server creation. --- */
+
+/* Creates a secure server using the passed-in server credentials. */
+grpc_server *grpc_secure_server_create(grpc_server_credentials *creds,
+                                       grpc_completion_queue *cq,
+                                       const grpc_channel_args *args);
+
+#endif /* GRPC_SECURITY_H_ */
diff --git a/include/grpc/status.h b/include/grpc/status.h
new file mode 100644
index 0000000..a4ce312
--- /dev/null
+++ b/include/grpc/status.h
@@ -0,0 +1,203 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_STATUS_H__
+#define __GRPC_STATUS_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+  /* Not an error; returned on success
+
+     HTTP Mapping: 200 OK */
+  GRPC_STATUS_OK = 0,
+
+  /* The operation was cancelled (typically by the caller).
+
+     HTTP Mapping: 499 Client Closed Request */
+  GRPC_STATUS_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.
+
+     HTTP Mapping: 500 Internal Server Error */
+  GRPC_STATUS_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).
+
+     HTTP Mapping: 400 Bad Request */
+  GRPC_STATUS_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.
+
+     HTTP Mapping: 504 Gateway Timeout */
+  GRPC_STATUS_DEADLINE_EXCEEDED = 4,
+
+  /* Some requested entity (e.g., file or directory) was not found.
+
+     HTTP Mapping: 404 Not Found */
+  GRPC_STATUS_NOT_FOUND = 5,
+
+  /* Some entity that we attempted to create (e.g., file or directory)
+     already exists.
+
+     HTTP Mapping: 409 Conflict */
+  GRPC_STATUS_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).
+
+     HTTP Mapping: 403 Forbidden */
+  GRPC_STATUS_PERMISSION_DENIED = 7,
+
+  /* The request does not have valid authentication credentials for the
+     operation.
+
+     HTTP Mapping: 401 Unauthorized */
+  GRPC_STATUS_UNAUTHENTICATED = 16,
+
+  /* Some resource has been exhausted, perhaps a per-user quota, or
+     perhaps the entire file system is out of space.
+
+     HTTP Mapping: 429 Too Many Requests */
+  GRPC_STATUS_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.
+
+     HTTP Mapping: 400 Bad Request
+
+     NOTE: HTTP spec says 412 Precondition Failed should only be used if
+     the request contains Etag related headers. So if the server does see
+     Etag related headers in the request, it may choose to return 412
+     instead of 400 for this error code. */
+  GRPC_STATUS_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.
+
+     HTTP Mapping: 409 Conflict */
+  GRPC_STATUS_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.
+
+     HTTP Mapping: 400 Bad Request */
+  GRPC_STATUS_OUT_OF_RANGE = 11,
+
+  /* Operation is not implemented or not supported/enabled in this service.
+
+     HTTP Mapping: 501 Not Implemented */
+  GRPC_STATUS_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.
+
+     HTTP Mapping: 500 Internal Server Error */
+  GRPC_STATUS_INTERNAL = 13,
+
+  /* The service is currently unavailable.  This is a most likely a
+     transient condition and may be corrected by retrying with
+     a backoff.
+
+     See litmus test above for deciding between FAILED_PRECONDITION,
+     ABORTED, and UNAVAILABLE.
+
+     HTTP Mapping: 503 Service Unavailable */
+  GRPC_STATUS_UNAVAILABLE = 14,
+
+  /* Unrecoverable data loss or corruption.
+
+     HTTP Mapping: 500 Internal Server Error */
+  GRPC_STATUS_DATA_LOSS = 15,
+
+  /* Force users to include a default branch: */
+  GRPC_STATUS__DO_NOT_USE = -1
+} grpc_status_code;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __GRPC_STATUS_H__ */
diff --git a/include/grpc/support/alloc.h b/include/grpc/support/alloc.h
new file mode 100644
index 0000000..d613d85
--- /dev/null
+++ b/include/grpc/support/alloc.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_ALLOC_H__
+#define __GRPC_SUPPORT_ALLOC_H__
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* malloc, never returns NULL */
+void *gpr_malloc(size_t size);
+/* free */
+void gpr_free(void *ptr);
+/* realloc, never returns NULL */
+void *gpr_realloc(void *p, size_t size);
+/* aligned malloc, never returns NULL, alignment must be power of 2 */
+void *gpr_malloc_aligned(size_t size, size_t alignment);
+/* free memory allocated by gpr_malloc_aligned */
+void gpr_free_aligned(void *ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __GRPC_SUPPORT_ALLOC_H__ */
diff --git a/include/grpc/support/atm.h b/include/grpc/support/atm.h
new file mode 100644
index 0000000..d9fd383
--- /dev/null
+++ b/include/grpc/support/atm.h
@@ -0,0 +1,92 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_ATM_H__
+#define __GRPC_SUPPORT_ATM_H__
+
+/* This interface provides atomic operations and barriers.
+   It is internal to gpr support code and should not be used outside it.
+
+   If an operation with acquire semantics precedes another memory access by the
+   same thread, the operation will precede that other access as seen by other
+   threads.
+
+   If an operation with release semantics follows another memory access by the
+   same thread, the operation will follow that other access as seen by other
+   threads.
+
+   Routines with "acq" or "full" in the name have acquire semantics.  Routines
+   with "rel" or "full" in the name have release semantics.  Routines with
+   "no_barrier" in the name have neither acquire not release semantics.
+
+   The routines may be implemented as macros.
+
+   // Atomic operations acton an intergral_type gpr_atm that is guaranteed to
+   // be the same size as a pointer.
+   typedef gpr_intptr gpr_atm;
+
+   // A memory barrier, providing both acquire and release semantics, but not
+   // otherwise acting no memory.
+   void gpr_atm_full_barrier(void);
+
+   // Atomically return *p, with acquire semantics.
+   gpr_atm gpr_atm_acq_load(gpr_atm *p);
+
+   // Atomically set *p = value, with release semantics.
+   void gpr_atm_rel_store(gpr_atm *p, gpr_atm value);
+
+   // Atomically add delta to *p, and return the old value of *p, with
+   // the barriers specified.
+   gpr_atm gpr_atm_no_barrier_fetch_add(gpr_atm *p, gpr_atm delta);
+   gpr_atm gpr_atm_full_fetch_add(gpr_atm *p, gpr_atm delta);
+
+   // Atomically, if *p==o, set *p=n and return non-zero otherwise return 0,
+   // with the barriers specified if the operation succeeds.
+   int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
+   int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
+   int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
+*/
+
+#include <grpc/support/port_platform.h>
+
+#if defined(GPR_GCC_ATOMIC)
+#include <grpc/support/atm_gcc_atomic.h>
+#elif defined(GPR_GCC_SYNC)
+#include <grpc/support/atm_gcc_sync.h>
+#elif defined(GPR_WIN32)
+#include <grpc/support/atm_win32.h>
+#else
+#error could not determine platform for atm
+#endif
+
+#endif  /* __GRPC_SUPPORT_ATM_H__ */
diff --git a/include/grpc/support/atm_gcc_atomic.h b/include/grpc/support/atm_gcc_atomic.h
new file mode 100644
index 0000000..4e0a7ab
--- /dev/null
+++ b/include/grpc/support/atm_gcc_atomic.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_ATM_GCC_ATOMIC_H__
+#define __GRPC_SUPPORT_ATM_GCC_ATOMIC_H__
+
+/* atm_platform.h for gcc and gcc-like compilers with the
+   __atomic_* interface.  */
+#include <grpc/support/port_platform.h>
+
+typedef gpr_intptr gpr_atm;
+
+#define gpr_atm_full_barrier() (__atomic_thread_fence(__ATOMIC_SEQ_CST))
+
+#define gpr_atm_acq_load(p) (__atomic_load_n((p), __ATOMIC_ACQUIRE))
+#define gpr_atm_rel_store(p, value) \
+  (__atomic_store_n((p), (gpr_intptr)(value), __ATOMIC_RELEASE))
+
+#define gpr_atm_no_barrier_fetch_add(p, delta) \
+  (__atomic_fetch_add((p), (gpr_intptr)(delta), __ATOMIC_RELAXED))
+#define gpr_atm_full_fetch_add(p, delta) \
+  (__atomic_fetch_add((p), (gpr_intptr)(delta), __ATOMIC_ACQ_REL))
+
+static __inline int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+  return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_RELAXED,
+                                     __ATOMIC_RELAXED);
+}
+
+static __inline int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+  return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_ACQUIRE,
+                                     __ATOMIC_RELAXED);
+}
+
+static __inline int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+  return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_RELEASE,
+                                     __ATOMIC_RELAXED);
+}
+
+#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
new file mode 100644
index 0000000..30570da
--- /dev/null
+++ b/include/grpc/support/atm_gcc_sync.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_ATM_GCC_SYNC_H__
+#define __GRPC_SUPPORT_ATM_GCC_SYNC_H__
+
+/* atm_platform.h for gcc and gcc-like compilers with the
+   __atomic_* interface.  */
+#include <grpc/support/port_platform.h>
+
+typedef gpr_intptr gpr_atm;
+
+#define gpr_atm_full_barrier() (__atomic_thread_fence(__ATOMIC_SEQ_CST))
+
+#define gpr_atm_acq_load(p) (__atomic_load_n((p), __ATOMIC_ACQUIRE))
+#define gpr_atm_rel_store(p, value) \
+  (__atomic_store_n((p), (gpr_intptr)(value), __ATOMIC_RELEASE))
+
+#define gpr_atm_no_barrier_fetch_add(p, delta) \
+  (__atomic_fetch_add((p), (gpr_intptr)(delta), __ATOMIC_RELAXED))
+#define gpr_atm_full_fetch_add(p, delta) \
+  (__atomic_fetch_add((p), (gpr_intptr)(delta), __ATOMIC_ACQ_REL))
+
+static __inline int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+  return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_RELAXED,
+                                     __ATOMIC_RELAXED);
+}
+
+static __inline int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+  return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_ACQUIRE,
+                                     __ATOMIC_RELAXED);
+}
+
+static __inline int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+  return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_RELEASE,
+                                     __ATOMIC_RELAXED);
+}
+
+#endif  /* __GRPC_SUPPORT_ATM_GCC_SYNC_H__ */
diff --git a/include/grpc/support/atm_win32.h b/include/grpc/support/atm_win32.h
new file mode 100644
index 0000000..9b2f0e8
--- /dev/null
+++ b/include/grpc/support/atm_win32.h
@@ -0,0 +1,94 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_ATM_WIN32_H__
+#define __GRPC_SUPPORT_ATM_WIN32_H__
+
+/* Win32 variant of atm_platform.h */
+#include <grpc/support/port_platform.h>
+
+#include <windows.h>
+
+typedef gpr_intptr gpr_atm;
+
+#define gpr_atm_full_barrier MemoryBarrier
+
+static __inline gpr_atm gpr_atm_acq_load(const gpr_atm *p) {
+  gpr_atm result = *p;
+  gpr_atm_full_barrier();
+  return result;
+}
+
+static __inline void gpr_atm_rel_store(gpr_atm *p, gpr_atm value) {
+  gpr_atm_full_barrier();
+  *p = value;
+}
+
+static __inline int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+  /* InterlockedCompareExchangePointerNoFence() not available on vista or
+     windows7 */
+  return o == (gpr_atm)InterlockedCompareExchangePointerAcquire(p, (void *)n,
+                                                                (void *)o);
+}
+
+static __inline int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+  return o == (gpr_atm)InterlockedCompareExchangePointerAcquire(p, (void *)n,
+                                                                (void *)o);
+}
+
+static __inline int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+  return o == (gpr_atm)InterlockedCompareExchangePointerRelease(p, (void *)n,
+                                                                (void *)o);
+}
+
+static __inline gpr_atm gpr_atm_no_barrier_fetch_add(gpr_atm *p,
+                                                     gpr_atm delta) {
+  /* Use the CAS operation to get pointer-sized fetch and add */
+  gpr_atm old;
+  do {
+    old = *p;
+  } while (!gpr_atm_no_barrier_cas(p, old, old + delta));
+  return old;
+}
+
+static __inline gpr_atm gpr_atm_full_fetch_add(gpr_atm *p, gpr_atm delta) {
+  /* Use a CAS operation to get pointer-sized fetch and add */
+  gpr_atm old;
+  do {
+    old = *p;
+  } while (old != (gpr_atm)InterlockedCompareExchangePointer(
+                      p, (void *)(old + delta), (void *)old));
+  return old;
+}
+
+#endif  /* __GRPC_SUPPORT_ATM_WIN32_H__ */
diff --git a/include/grpc/support/cancellable_platform.h b/include/grpc/support/cancellable_platform.h
new file mode 100644
index 0000000..d67302d
--- /dev/null
+++ b/include/grpc/support/cancellable_platform.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_CANCELLABLE_PLATFORM_H__
+#define __GRPC_SUPPORT_CANCELLABLE_PLATFORM_H__
+
+#include <grpc/support/atm.h>
+#include <grpc/support/sync.h>
+
+struct gpr_cancellable_list_ {
+  /* a doubly-linked list on cancellable's waiters queue */
+  struct gpr_cancellable_list_ *next;
+  struct gpr_cancellable_list_ *prev;
+  /* The following two fields are arguments to gpr_cv_cancellable_wait() */
+  gpr_mu *mu;
+  gpr_cv *cv;
+};
+
+/* Internal definition of gpr_cancellable. */
+typedef struct {
+  gpr_mu mu; /* protects waiters and modifications to cancelled */
+  gpr_atm cancelled;
+  struct gpr_cancellable_list_ waiters;
+} gpr_cancellable;
+
+#endif  /* __GRPC_SUPPORT_CANCELLABLE_PLATFORM_H__ */
diff --git a/include/grpc/support/cmdline.h b/include/grpc/support/cmdline.h
new file mode 100644
index 0000000..60e8035
--- /dev/null
+++ b/include/grpc/support/cmdline.h
@@ -0,0 +1,95 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_CMDLINE_H__
+#define __GRPC_SUPPORT_CMDLINE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Simple command line parser.
+
+   Supports flags that can be specified as -foo, --foo, --no-foo, -no-foo, etc
+   And integers, strings that can be specified as -foo=4, -foo blah, etc
+
+   No support for short command line options (but we may get that in the
+   future.)
+
+   Usage (for a program with a single flag argument 'foo'):
+
+   int main(int argc, char **argv) {
+     gpr_cmdline *cl;
+     int verbose = 0;
+
+     cl = gpr_cmdline_create("My cool tool");
+     gpr_cmdline_add_int(cl, "verbose", "Produce verbose output?", &verbose);
+     gpr_cmdline_parse(cl, argc, argv);
+     gpr_cmdline_destroy(cl);
+
+     if (verbose) {
+       gpr_log(GPR_INFO, "Goodbye cruel world!");
+     }
+
+     return 0;
+   } */
+
+typedef struct gpr_cmdline gpr_cmdline;
+
+/* Construct a command line parser: takes a short description of the tool
+   doing the parsing */
+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) */
+void gpr_cmdline_add_int(gpr_cmdline *cl, const char *name, const char *help,
+                         int *value);
+/* The same, for a boolean flag */
+void gpr_cmdline_add_flag(gpr_cmdline *cl, const char *name, const char *help,
+                          int *value);
+/* And for a string */
+void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name, const char *help,
+                            char **value);
+/* Set a callback for non-named arguments */
+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);
+/* Parse the command line */
+void gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv);
+/* Destroy the parser */
+void gpr_cmdline_destroy(gpr_cmdline *cl);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __GRPC_SUPPORT_CMDLINE_H__ */
diff --git a/include/grpc/support/histogram.h b/include/grpc/support/histogram.h
new file mode 100644
index 0000000..13dce3b
--- /dev/null
+++ b/include/grpc/support/histogram.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_HISTOGRAM_H__
+#define __GRPC_SUPPORT_HISTOGRAM_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct gpr_histogram gpr_histogram;
+
+gpr_histogram *gpr_histogram_create(double resolution, double max_bucket_start);
+void gpr_histogram_destroy(gpr_histogram *h);
+void gpr_histogram_add(gpr_histogram *h, double x);
+
+/* The following merges the second histogram into the first. It only works
+   if they have the same buckets and resolution. Returns 0 on failure, 1
+   on success */
+int gpr_histogram_merge(gpr_histogram *dst, gpr_histogram *src);
+
+double gpr_histogram_percentile(gpr_histogram *histogram, double percentile);
+double gpr_histogram_mean(gpr_histogram *histogram);
+double gpr_histogram_stddev(gpr_histogram *histogram);
+double gpr_histogram_variance(gpr_histogram *histogram);
+double gpr_histogram_maximum(gpr_histogram *histogram);
+double gpr_histogram_minimum(gpr_histogram *histogram);
+double gpr_histogram_count(gpr_histogram *histogram);
+double gpr_histogram_sum(gpr_histogram *histogram);
+double gpr_histogram_sum_of_squares(gpr_histogram *histogram);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __GRPC_SUPPORT_HISTOGRAM_H__ */
diff --git a/include/grpc/support/host_port.h b/include/grpc/support/host_port.h
new file mode 100644
index 0000000..9495bfe
--- /dev/null
+++ b/include/grpc/support/host_port.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_HOST_PORT_H__
+#define __GRPC_SUPPORT_HOST_PORT_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
+   brackets will not be added.
+
+   Usage is similar to gpr_asprintf: returns the number of bytes written
+   (excluding the final '\0'), and *out points to a string which must later be
+   destroyed using gpr_free().
+
+   In the unlikely event of an error, returns -1 and sets *out to NULL. */
+int gpr_join_host_port(char **out, const char *host, int port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRPC_SUPPORT_HOST_PORT_H__ */
diff --git a/include/grpc/support/log.h b/include/grpc/support/log.h
new file mode 100644
index 0000000..b79d661
--- /dev/null
+++ b/include/grpc/support/log.h
@@ -0,0 +1,91 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_LOG_H__
+#define __GRPC_SUPPORT_LOG_H__
+
+#include <stdlib.h> /* for abort() */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* GPR log API.
+
+   Usage (within grpc):
+
+   int argument1 = 3;
+   char* argument2 = "hello";
+   gpr_log(GPR_DEBUG, "format string %d", argument1);
+   gpr_log(GPR_INFO, "hello world");
+   gpr_log(GPR_ERROR, "%d %s!!", argument1, argument2); */
+
+/* The severity of a log message - use the #defines below when calling into
+   gpr_log to additionally supply file and line data */
+typedef enum gpr_log_severity {
+  GPR_LOG_SEVERITY_DEBUG,
+  GPR_LOG_SEVERITY_INFO,
+  GPR_LOG_SEVERITY_ERROR
+} gpr_log_severity;
+
+/* Returns a string representation of the log severity */
+const char *gpr_log_severity_string(gpr_log_severity severity);
+
+/* Macros to build log contexts at various severity levels */
+#define GPR_DEBUG __FILE__, __LINE__, GPR_LOG_SEVERITY_DEBUG
+#define GPR_INFO __FILE__, __LINE__, GPR_LOG_SEVERITY_INFO
+#define GPR_ERROR __FILE__, __LINE__, GPR_LOG_SEVERITY_ERROR
+
+/* Log a message. It's advised to use GPR_xxx above to generate the context
+ * for each message */
+void gpr_log(const char *file, int line, gpr_log_severity severity,
+             const char *format, ...);
+
+/* abort() the process if x is zero, having written a line to the log.
+
+   Intended for internal invariants.  If the error can be recovered from,
+   without the possibility of corruption, or might best be reflected via
+   an exception in a higher-level language, consider returning error code.  */
+#define GPR_ASSERT(x)                                 \
+  do {                                                \
+    if (!(x)) {                                       \
+      gpr_log(GPR_ERROR, "assertion failed: %s", #x); \
+      abort();                                        \
+    }                                                 \
+  } while (0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __GRPC_SUPPORT_LOG_H__ */
diff --git a/include/grpc/support/port_platform.h b/include/grpc/support/port_platform.h
new file mode 100644
index 0000000..592fce6
--- /dev/null
+++ b/include/grpc/support/port_platform.h
@@ -0,0 +1,132 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_PORT_PLATFORM_H__
+#define __GRPC_SUPPORT_PORT_PLATFORM_H__
+
+/* Override this file with one for your platform if you need to redefine
+   things.  */
+
+/* For a common case, assume that the platform has a C99-like stdint.h */
+
+#include <stdint.h>
+
+#if !defined(GPR_NO_AUTODETECT_PLATFORM)
+#if defined(_WIN64) || defined(WIN64)
+#define GPR_WIN32 1
+#define GPR_ARCH_64 1
+#define GPR_POSIX_SOCKETUTILS 1
+#elif defined(_WIN32) || defined(WIN32)
+#define GPR_WIN32 1
+#define GPR_ARCH_32 1
+#define GPR_POSIX_SOCKETUTILS 1
+#elif defined(ANDROID) || defined(__ANDROID__)
+#define GPR_POSIX_TIME 1
+#define GPR_POSIX_SYNC 1
+#define GPR_POSIX_SOCKETUTILS 1
+#define GPR_ANDROID 1
+#define GPR_GCC_SYNC 1
+#define GPR_ARCH_32 1
+#elif defined(__linux__)
+#define GPR_POSIX_TIME 1
+#define GPR_POSIX_SYNC 1
+#define GPR_LINUX 1
+#define GPR_GCC_ATOMIC 1
+#ifdef _LP64
+#define GPR_ARCH_64 1
+#else /* _LP64 */
+#define GPR_ARCH_32 1
+#endif /* _LP64 */
+#elif defined(__APPLE__)
+#define GPR_POSIX_TIME 1
+#define GPR_POSIX_SYNC 1
+#define GPR_POSIX_LOG 1
+#define GPR_POSIX_SOCKETUTILS 1
+#define GPR_GCC_ATOMIC 1
+#ifdef _LP64
+#define GPR_ARCH_64 1
+#else /* _LP64 */
+#define GPR_ARCH_32 1
+#endif /* _LP64 */
+#else
+#error Could not auto-detect platform
+#endif
+#endif /* GPR_NO_AUTODETECT_PLATFORM */
+
+/* Cache line alignment */
+#ifndef GPR_CACHELINE_SIZE
+#if defined(__i386__) || defined(__x86_64__)
+#define GPR_CACHELINE_SIZE 64
+#endif
+#ifndef GPR_CACHELINE_SIZE
+/* A reasonable default guess. Note that overestimates tend to waste more
+   space, while underestimates tend to waste more time. */
+#define GPR_CACHELINE_SIZE 64
+#endif /* GPR_CACHELINE_SIZE */
+#endif /* GPR_CACHELINE_SIZE */
+
+/* scrub GCC_ATOMIC if it's not available on this compiler */
+#if defined(GPR_GCC_ATOMIC) && !defined(__ATOMIC_RELAXED)
+#undef GPR_GCC_ATOMIC
+#define GPR_GCC_SYNC 1
+#endif
+
+/* Validate platform combinations */
+#if defined(GPR_GCC_ATOMIC) + defined(GPR_GCC_SYNC) + defined(GPR_WIN32) != 1
+#error Must define exactly one of GPR_GCC_ATOMIC, GPR_GCC_SYNC, GPR_WIN32
+#endif
+
+#if defined(GPR_ARCH_32) + defined(GPR_ARCH_64) != 1
+#error Must define exactly one of GPR_ARCH_32, GPR_ARCH_64
+#endif
+
+typedef int16_t gpr_int16;
+typedef int32_t gpr_int32;
+typedef int64_t gpr_int64;
+typedef uint8_t gpr_uint8;
+typedef uint16_t gpr_uint16;
+typedef uint32_t gpr_uint32;
+typedef uint64_t gpr_uint64;
+typedef intmax_t gpr_intmax;
+typedef intptr_t gpr_intptr;
+typedef uintmax_t gpr_uintmax;
+typedef uintptr_t gpr_uintptr;
+
+/* INT64_MAX is unavailable on some platforms. */
+#define GPR_INT64_MAX (~(gpr_uint64)0 >> 1)
+
+/* maximum alignment needed for any type on this platform, rounded up to a
+   power of two */
+#define GPR_MAX_ALIGNMENT 16
+
+#endif /* __GRPC_SUPPORT_PORT_PLATFORM_H__ */
diff --git a/include/grpc/support/slice.h b/include/grpc/support/slice.h
new file mode 100644
index 0000000..6678f39
--- /dev/null
+++ b/include/grpc/support/slice.h
@@ -0,0 +1,175 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_SLICE_H__
+#define __GRPC_SUPPORT_SLICE_H__
+
+#include <grpc/support/sync.h>
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Slice API
+
+   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.
+
+   The data-structure for slices is exposed here to allow non-gpr code to
+   build slices from whatever data they have available.
+
+   When defining interfaces that handle slices, care should be taken to define
+   reference ownership semantics (who should call unref?) and mutability
+   constraints (is the callee allowed to modify the slice?) */
+
+/* Reference count container for gpr_slice. Contains function pointers to
+   increment and decrement reference counts. Implementations should cleanup
+   when the reference count drops to zero.
+   Typically client code should not touch this, and use gpr_slice_malloc,
+   gpr_slice_new, or gpr_slice_new_with_len instead. */
+typedef struct gpr_slice_refcount {
+  void (*ref)(void *);
+  void (*unref)(void *);
+} gpr_slice_refcount;
+
+#define GPR_SLICE_INLINED_SIZE (sizeof(size_t) + sizeof(gpr_uint8 *) - 1)
+
+/* A gpr_slice s, if initialized, represents the byte range
+   s.bytes[0..s.length-1].
+
+   It can have an associated ref count which has a destruction routine to be run
+   when the ref count reaches zero (see gpr_slice_new() and grp_slice_unref()).
+   Multiple gpr_slice values may share a ref count.
+
+   If the slice does not have a refcount, it represents an inlined small piece
+   of data that is copied by value. */
+typedef struct gpr_slice {
+  struct gpr_slice_refcount *refcount;
+  union {
+    struct {
+      gpr_uint8 *bytes;
+      size_t length;
+    } refcounted;
+    struct {
+      gpr_uint8 length;
+      gpr_uint8 bytes[GPR_SLICE_INLINED_SIZE];
+    } inlined;
+  } data;
+} gpr_slice;
+
+#define GPR_SLICE_START_PTR(slice)                  \
+  ((slice).refcount ? (slice).data.refcounted.bytes \
+                    : (slice).data.inlined.bytes)
+#define GPR_SLICE_LENGTH(slice)                      \
+  ((slice).refcount ? (slice).data.refcounted.length \
+                    : (slice).data.inlined.length)
+#define GPR_SLICE_SET_LENGTH(slice, newlen)                       \
+  ((slice).refcount ? ((slice).data.refcounted.length = (newlen)) \
+                    : ((slice).data.inlined.length = (newlen)))
+#define GPR_SLICE_END_PTR(slice) \
+  GPR_SLICE_START_PTR(slice) + GPR_SLICE_LENGTH(slice)
+
+/* Increment the refcount of s. Requires slice is initialized.
+   Returns s. */
+gpr_slice gpr_slice_ref(gpr_slice s);
+
+/* Decrement the ref count of s.  If the ref count of s reaches zero, all
+   slices sharing the ref count are destroyed, and considered no longer
+   initialized.  If s is ultimately derived from a call to gpr_slice_new(start,
+   len, dest) where dest!=NULL , then (*dest)(start, len) is called.  Requires
+   s initialized.  */
+void gpr_slice_unref(gpr_slice s);
+
+/* 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 pointer
+   passed in at destruction. */
+gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *));
+
+/* Equivalent to gpr_slice_new, but with a two argument destroy function that
+   also takes the slice length. */
+gpr_slice gpr_slice_new_with_len(void *p, size_t len,
+                                 void (*destroy)(void *, size_t));
+
+/* Equivalent to gpr_slice_new(malloc(len), len, free), but saves one malloc()
+   call.
+   Aborts if malloc() fails. */
+gpr_slice gpr_slice_malloc(size_t length);
+
+/* Create a slice by copying a string.
+   Does not preserve null terminators.
+   Equivalent to:
+     size_t len = strlen(source);
+     gpr_slice slice = gpr_slice_malloc(len);
+     memcpy(slice->data, source, len); */
+gpr_slice gpr_slice_from_copied_string(const char *source);
+
+/* Create a slice by copying a buffer.
+   Equivalent to:
+     gpr_slice slice = gpr_slice_malloc(len);
+     memcpy(slice->data, source, len); */
+gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t len);
+
+/* Return a result slice derived from s, which shares a ref count with s, where
+   result.data==s.data+begin, and result.length==end-begin.
+   The ref count of s is increased by one.
+   Requires s initialized, begin <= end, begin <= s.length, and
+   end <= source->length. */
+gpr_slice gpr_slice_sub(gpr_slice s, size_t begin, size_t end);
+
+/* The same as gpr_slice_sub, but without altering the ref count */
+gpr_slice gpr_slice_sub_no_ref(gpr_slice s, size_t begin, size_t end);
+
+/* Splits s into two: modifies s to be s[0:split], and returns a new slice,
+   sharing a refcount with s, that contains s[split:s.length].
+   Requires s intialized, split <= s.length */
+gpr_slice gpr_slice_split_tail(gpr_slice *s, size_t split);
+
+/* Splits s into two: modifies s to be s[split:s.length], and returns a new
+   slice, sharing a refcount with s, that contains s[0:split].
+   Requires s intialized, split <= s.length */
+gpr_slice gpr_slice_split_head(gpr_slice *s, size_t split);
+
+gpr_slice gpr_empty_slice();
+
+/* Returns <0 if a < b, ==0 if a == b, >0 if a > b */
+int gpr_slice_cmp(gpr_slice a, gpr_slice b);
+int gpr_slice_str_cmp(gpr_slice a, const char *b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __GRPC_SUPPORT_SLICE_H__ */
diff --git a/include/grpc/support/slice_buffer.h b/include/grpc/support/slice_buffer.h
new file mode 100644
index 0000000..e4d204b
--- /dev/null
+++ b/include/grpc/support/slice_buffer.h
@@ -0,0 +1,84 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_SLICE_BUFFER_H__
+#define __GRPC_SUPPORT_SLICE_BUFFER_H__
+
+#include <grpc/support/slice.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Represents an expandable array of slices, to be interpreted as a single item
+   TODO(ctiller): inline some small number of elements into the struct, to
+                  avoid per-call allocations */
+typedef struct {
+  /* slices in the array */
+  gpr_slice *slices;
+  /* the number of slices in the array */
+  size_t count;
+  /* the number of slices allocated in the array */
+  size_t capacity;
+  /* the combined length of all slices in the array */
+  size_t length;
+} gpr_slice_buffer;
+
+/* initialize a slice buffer */
+void gpr_slice_buffer_init(gpr_slice_buffer *sb);
+/* destroy a slice buffer - unrefs any held elements */
+void gpr_slice_buffer_destroy(gpr_slice_buffer *sb);
+/* Add an element to a slice buffer - takes ownership of the slice.
+   This function is allowed to concatenate the passed in slice to the end of
+   some other slice if desired by the slice buffer. */
+void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice slice);
+/* add an element to a slice buffer - takes ownership of the slice and returns
+   the index of the slice.
+   Guarantees that the slice will not be concatenated at the end of another
+   slice (i.e. the data for this slice will begin at the first byte of the
+   slice at the returned index in sb->slices)
+   The implementation MAY decide to concatenate data at the end of a small
+   slice added in this fashion. */
+size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice slice);
+void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *slices, size_t n);
+/* add a very small (less than 8 bytes) amount of data to the end of a slice
+   buffer: returns a pointer into which to add the data */
+gpr_uint8 *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, int len);
+/* clear a slice buffer, unref all elements */
+void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __GRPC_SUPPORT_SLICE_BUFFER_H__ */
diff --git a/include/grpc/support/string.h b/include/grpc/support/string.h
new file mode 100644
index 0000000..08c8809
--- /dev/null
+++ b/include/grpc/support/string.h
@@ -0,0 +1,76 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_STRING_H__
+#define __GRPC_SUPPORT_STRING_H__
+
+#include <stddef.h>
+
+#include <grpc/support/port_platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* String utility functions */
+
+/* Returns a copy of src that can be passed to gpr_free().
+   If allocation fails or if src is NULL, returns NULL. */
+char *gpr_strdup(const char *src);
+
+/* flag to include plaintext after a hexdump */
+#define GPR_HEXDUMP_PLAINTEXT 0x00000001
+
+/* Converts array buf, of length len, into a hexadecimal dump. Result should
+   be freed with gpr_free() */
+char *gpr_hexdump(const char *buf, size_t len, gpr_uint32 flags);
+
+/* Parses an array of bytes into an integer (base 10). Returns 1 on success,
+   0 on failure. */
+int gpr_parse_bytes_to_uint32(const char *data, size_t length,
+                              gpr_uint32 *result);
+
+/* printf to a newly-allocated string.  The set of supported formats may vary
+   between platforms.
+
+   On success, returns the number of bytes printed (excluding the final '\0'),
+   and *strp points to a string which must later be destroyed with gpr_free().
+
+   On error, returns -1 and sets *strp to NULL. */
+int gpr_asprintf(char **strp, const char *format, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __GRPC_SUPPORT_STRING_H__ */
diff --git a/include/grpc/support/sync.h b/include/grpc/support/sync.h
new file mode 100644
index 0000000..3e435a6
--- /dev/null
+++ b/include/grpc/support/sync.h
@@ -0,0 +1,348 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_SYNC_H__
+#define __GRPC_SUPPORT_SYNC_H__
+/* Synchronization primitives for GPR.
+
+   The type  gpr_mu              provides a non-reentrant mutex (lock).
+
+   The type  gpr_cv              provides a condition variable.
+
+   The type  gpr_once            provides for one-time initialization.
+
+   The type gpr_event            provides one-time-setting, reading, and
+                                 waiting of a void*, with memory barriers.
+
+   The type gpr_refcount         provides an object reference counter,
+                                 with memory barriers suitable to control
+                                 object lifetimes.
+
+   The type gpr_stats_counter    provides an atomic statistics counter. It
+                                 provides no memory barriers.
+ */
+
+/* Platform-specific type declarations of gpr_mu and gpr_cv.   */
+#include <grpc/support/port_platform.h>
+#include <grpc/support/sync_generic.h>
+
+#if defined(GPR_POSIX_SYNC)
+#include <grpc/support/sync_posix.h>
+#elif defined(GPR_WIN32)
+#include <grpc/support/sync_win32.h>
+#else
+#error Unable to determine platform for sync
+#endif
+
+#include <grpc/support/time.h> /* for gpr_timespec */
+#include <grpc/support/cancellable_platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* --- Mutex interface ---
+
+   At most one thread may hold an exclusive lock on a mutex at any given time.
+   Actions taken by a thread that holds a mutex exclusively happen after
+   actions taken by all previous holders of the mutex.  Variables of type
+   gpr_mu are uninitialized when first declared.  */
+
+/* Initialize *mu.  Requires:  *mu uninitialized.  */
+void gpr_mu_init(gpr_mu *mu);
+
+/* Cause *mu no longer to be initialized, freeing any memory in use.  Requires:
+   *mu initialized; no other concurrent operation on *mu.  */
+void gpr_mu_destroy(gpr_mu *mu);
+
+/* Wait until no thread has a lock on *mu, cause the calling thread to own an
+   exclusive lock on *mu, then return.  May block indefinitely or crash if the
+   calling thread has a lock on *mu.  Requires:  *mu initialized.  */
+void gpr_mu_lock(gpr_mu *mu);
+
+/* Release an exclusive lock on *mu held by the calling thread.  Requires:  *mu
+   initialized; the calling thread holds an exclusive lock on *mu.  */
+void gpr_mu_unlock(gpr_mu *mu);
+
+/* Without blocking, attempt to acquire an exclusive lock on *mu for the
+   calling thread, then return non-zero iff success.  Fail, if any thread holds
+   the lock; succeeds with high probability if no thread holds the lock.
+   Requires:  *mu initialized.  */
+int gpr_mu_trylock(gpr_mu *mu);
+
+/* --- Condition variable interface ---
+
+   A while-loop should be used with gpr_cv_wait() when waiting for conditions
+   to become true.  See the example below.  Variables of type gpr_cv are
+   uninitialized when first declared.  */
+
+/* Initialize *cv.  Requires:  *cv uninitialized.  */
+void gpr_cv_init(gpr_cv *cv);
+
+/* Cause *cv no longer to be initialized, freeing any memory in use.  Requires:
+   *cv initialized; no other concurrent operation on *cv.*/
+void gpr_cv_destroy(gpr_cv *cv);
+
+/* Atomically release *mu and wait on *cv.  When the calling thread is woken
+   from *cv or the deadline abs_deadline is exceeded, execute gpr_mu_lock(mu)
+   and return whether the deadline was exceeded.  Use
+   abs_deadline==gpr_inf_future for no deadline.  May return even when not
+   woken explicitly.  Requires:  *mu and *cv initialized; the calling thread
+   holds an exclusive lock on *mu.  */
+int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline);
+
+/* Behave like gpr_cv_wait(cv, mu, abs_deadline), except behave as though
+   the deadline has expired if *c is cancelled. */
+int gpr_cv_cancellable_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline,
+                            gpr_cancellable *c);
+
+/* If any threads are waiting on *cv, wake at least one.
+   Clients may treat this as an optimization of gpr_cv_broadcast()
+   for use in the case where waking more than one waiter is not useful.
+   Requires:  *cv initialized.  */
+void gpr_cv_signal(gpr_cv *cv);
+
+/* Wake all threads waiting on *cv.  Requires:  *cv initialized.  */
+void gpr_cv_broadcast(gpr_cv *cv);
+
+/* --- Cancellation ---
+   A gpr_cancellable can be used with gpr_cv_cancellable_wait()
+   or gpr_event_cancellable_wait() cancel pending waits. */
+
+/* Initialize *c. */
+void gpr_cancellable_init(gpr_cancellable *c);
+
+/* Cause *c no longer to be initialized, freeing any memory in use.  Requires:
+   *c initialized; no other concurrent operation on *c.  */
+void gpr_cancellable_destroy(gpr_cancellable *c);
+
+/* Return non-zero iff *c has been cancelled.  Requires *c initialized.
+   This call is faster than acquiring a mutex on most platforms. */
+int gpr_cancellable_is_cancelled(gpr_cancellable *c);
+
+/* Cancel *c.  If *c was not previously cancelled, cause
+   gpr_cancellable_init() to return non-zero, and outstanding and future
+   calls to gpr_cv_cancellable_wait() and gpr_event_cancellable_wait() to
+   return immediately indicating a timeout has occurred; otherwise do nothing.
+   Requires *c initialized.*/
+void gpr_cancellable_cancel(gpr_cancellable *c);
+
+/* --- One-time initialization ---
+
+   gpr_once must be declared with static storage class, and initialized with
+   GPR_ONCE_INIT.  e.g.,
+     static gpr_once once_var = GPR_ONCE_INIT;     */
+
+/* Ensure that (*init_routine)() has been called exactly once (for the
+   specified gpr_once instance) and then return.
+   If multiple threads call gpr_once() on the same gpr_once instance, one of
+   them will call (*init_routine)(), and the others will block until that call
+   finishes.*/
+void gpr_once_init(gpr_once *once, void (*init_routine)(void));
+
+/* --- One-time event notification ---
+
+  These operations act on a gpr_event, which should be initialized with
+  gpr_ev_init(), or with GPR_EVENT_INIT if static, e.g.,
+       static gpr_event event_var = GPR_EVENT_INIT;
+  It requires no destruction.  */
+
+/* Initialize *ev. */
+void gpr_event_init(gpr_event *ev);
+
+/* Set *ev so that gpr_event_get() and gpr_event_wait() will return value.
+   Requires:  *ev initialized; value != NULL; no prior or concurrent calls to
+   gpr_event_set(ev, ...) since initialization.  */
+void gpr_event_set(gpr_event *ev, void *value);
+
+/* Return the value set by gpr_event_set(ev, ...), or NULL if no such call has
+   completed.  If the result is non-NULL, all operations that occurred prior to
+   the gpr_event_set(ev, ...) set will be visible after this call returns.
+   Requires:  *ev initialized.  This operation is faster than acquiring a mutex
+   on most platforms.  */
+void *gpr_event_get(gpr_event *ev);
+
+/* Wait until *ev is set by gpr_event_set(ev, ...), or abs_deadline is
+   exceeded, then return gpr_event_get(ev).  Requires:  *ev initialized.  Use
+   abs_deadline==gpr_inf_future for no deadline.  When the event has been
+   signalled before the call, this operation is faster than acquiring a mutex
+   on most platforms.  */
+void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline);
+
+/* Behave like gpr_event_wait(ev, abs_deadline), except behave as though
+   the deadline has expired if *c is cancelled. */
+void *gpr_event_cancellable_wait(gpr_event *ev, gpr_timespec abs_deadline,
+                                 gpr_cancellable *c);
+
+/* --- Reference counting ---
+
+   These calls act on the type gpr_refcount.  It requires no desctruction.  */
+
+/* Initialize *r to value n.  */
+void gpr_ref_init(gpr_refcount *r, int n);
+
+/* Increment the reference count *r.  Requires *r initialized. */
+void gpr_ref(gpr_refcount *r);
+
+/* Increment the reference count *r by n.  Requires *r initialized, n > 0. */
+void gpr_refn(gpr_refcount *r, int n);
+
+/* Decrement the reference count *r and return non-zero iff it has reached
+   zero. .  Requires *r initialized. */
+int gpr_unref(gpr_refcount *r);
+
+/* --- Stats counters ---
+
+   These calls act on the integral type gpr_stats_counter.  It requires no
+   destruction.  Static instances may be initialized with
+       gpr_stats_counter c = GPR_STATS_INIT;
+   Beware:  These operations do not imply memory barriers.  Do not use them to
+   synchronize other events.  */
+
+/* Initialize *c to the value n. */
+void gpr_stats_init(gpr_stats_counter *c, gpr_intptr n);
+
+/* *c += inc.  Requires: *c initialized. */
+void gpr_stats_inc(gpr_stats_counter *c, gpr_intptr inc);
+
+/* Return *c.  Requires: *c initialized. */
+gpr_intptr gpr_stats_read(const gpr_stats_counter *c);
+
+/* ==================Example use of interface===================
+   A producer-consumer queue of up to N integers,
+   illustrating the use of the calls in this interface. */
+#if 0
+
+#define N 4
+
+   typedef struct queue {
+     gpr_cv non_empty;  /* Signalled when length becomes non-zero. */
+     gpr_cv non_full;   /* Signalled when length becomes non-N. */
+     gpr_mu mu;         /* Protects all fields below.
+                            (That is, except during initialization or
+                            destruction, the fields below should be accessed
+                            only by a thread that holds mu.) */
+     int head;           /* Index of head of queue 0..N-1. */
+     int length;         /* Number of valid elements in queue 0..N. */
+     int elem[N];        /* elem[head .. head+length-1] are queue elements. */
+   } queue;
+
+   /* Initialize *q. */
+   void queue_init(queue *q) {
+     gpr_mu_init(&q->mu);
+     gpr_cv_init(&q->non_empty);
+     gpr_cv_init(&q->non_full);
+     q->head = 0;
+     q->length = 0;
+   }
+
+   /* Free storage associated with *q. */
+   void queue_destroy(queue *q) {
+     gpr_mu_destroy(&q->mu);
+     gpr_cv_destroy(&q->non_empty);
+     gpr_cv_destroy(&q->non_full);
+   }
+
+   /* Wait until there is room in *q, then append x to *q. */
+   void queue_append(queue *q, int x) {
+     gpr_mu_lock(&q->mu);
+     /* To wait for a predicate without a deadline, loop on the negation of the
+        predicate, and use gpr_cv_wait(..., gpr_inf_future) inside the loop
+        to release the lock, wait, and reacquire on each iteration.  Code that
+        makes the condition true should use gpr_cv_broadcast() on the
+        corresponding condition variable.  The predicate must be on state
+        protected by the lock.  */
+     while (q->length == N) {
+       gpr_cv_wait(&q->non_full, &q->mu, gpr_inf_future);
+     }
+     if (q->length == 0) {  /* Wake threads blocked in queue_remove(). */
+       /* It's normal to use gpr_cv_broadcast() or gpr_signal() while
+          holding the lock. */
+       gpr_cv_broadcast(&q->non_empty);
+     }
+     q->elem[(q->head + q->length) % N] = x;
+     q->length++;
+     gpr_mu_unlock(&q->mu);
+   }
+
+   /* If it can be done without blocking, append x to *q and return non-zero.
+      Otherwise return 0. */
+   int queue_try_append(queue *q, int x) {
+     int result = 0;
+     if (gpr_mu_trylock(&q->mu)) {
+       if (q->length != N) {
+         if (q->length == 0) {  /* Wake threads blocked in queue_remove(). */
+           gpr_cv_broadcast(&q->non_empty);
+         }
+         q->elem[(q->head + q->length) % N] = x;
+         q->length++;
+         result = 1;
+       }
+       gpr_mu_unlock(&q->mu);
+     }
+     return result;
+   }
+
+   /* Wait until the *q is non-empty or deadline abs_deadline passes.  If the
+      queue is non-empty, remove its head entry, place it in *head, and return
+      non-zero.  Otherwise return 0.  */
+   int queue_remove(queue *q, int *head, gpr_timespec abs_deadline) {
+     int result = 0;
+     gpr_mu_lock(&q->mu);
+     /* To wait for a predicate with a deadline, loop on the negation of the
+        predicate or until gpr_cv_wait() returns true.  Code that makes
+        the condition true should use gpr_cv_broadcast() on the corresponding
+        condition variable.  The predicate must be on state protected by the
+        lock. */
+     while (q->length == 0 &&
+            !gpr_cv_wait(&q->non_empty, &q->mu, abs_deadline)) {
+     }
+     if (q->length != 0) {    /* Queue is non-empty. */
+       result = 1;
+       if (q->length == N) {  /* Wake threads blocked in queue_append(). */
+         gpr_cv_broadcast(&q->non_full);
+       }
+       *head = q->elem[q->head];
+       q->head = (q->head + 1) % N;
+       q->length--;
+     } /* else deadline exceeded */
+     gpr_mu_unlock(&q->mu);
+     return result;
+   }
+#endif /* 0 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __GRPC_SUPPORT_SYNC_H__ */
diff --git a/include/grpc/support/sync_generic.h b/include/grpc/support/sync_generic.h
new file mode 100644
index 0000000..0c8a992
--- /dev/null
+++ b/include/grpc/support/sync_generic.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_SYNC_GENERIC_H__
+#define __GRPC_SUPPORT_SYNC_GENERIC_H__
+/* Generic type defintions for gpr_sync. */
+
+#include <grpc/support/atm.h>
+
+/* gpr_event */
+typedef struct { gpr_atm state; } gpr_event;
+
+#define GPR_EVENT_INIT \
+  { 0 }
+
+/* gpr_refcount */
+typedef struct { gpr_atm count; } gpr_refcount;
+
+/* gpr_stats_counter */
+typedef struct { gpr_atm value; } gpr_stats_counter;
+
+#define GPR_STATS_INIT \
+  { 0 }
+
+#endif  /* __GRPC_SUPPORT_SYNC_GENERIC_H__ */
diff --git a/include/grpc/support/sync_posix.h b/include/grpc/support/sync_posix.h
new file mode 100644
index 0000000..6787695
--- /dev/null
+++ b/include/grpc/support/sync_posix.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_SYNC_POSIX_H__
+#define __GRPC_SUPPORT_SYNC_POSIX_H__
+
+#include <grpc/support/sync_generic.h>
+
+/* Posix variant of gpr_sync_platform.h */
+#include <pthread.h>
+
+typedef pthread_mutex_t gpr_mu;
+typedef pthread_cond_t gpr_cv;
+typedef pthread_once_t gpr_once;
+
+#define GPR_ONCE_INIT PTHREAD_ONCE_INIT
+
+#endif  /* __GRPC_SUPPORT_SYNC_POSIX_H__ */
diff --git a/include/grpc/support/sync_win32.h b/include/grpc/support/sync_win32.h
new file mode 100644
index 0000000..b3230dc
--- /dev/null
+++ b/include/grpc/support/sync_win32.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_SYNC_WIN32_H__
+#define __GRPC_SUPPORT_SYNC_WIN32_H__
+
+#include <grpc/support/sync_generic.h>
+
+/* Win32 variant of gpr_sync_platform.h */
+#include <windows.h>
+
+typedef struct {
+  CRITICAL_SECTION cs; /* Not an SRWLock until Vista is unsupported */
+  int locked;
+} gpr_mu;
+
+typedef CONDITION_VARIABLE gpr_cv;
+
+typedef INIT_ONCE gpr_once;
+#define GPR_ONCE_INIT INIT_ONCE_STATIC_INIT
+
+#endif  /* __GRPC_SUPPORT_SYNC_WIN32_H__ */
diff --git a/include/grpc/support/thd.h b/include/grpc/support/thd.h
new file mode 100644
index 0000000..18a1e80
--- /dev/null
+++ b/include/grpc/support/thd.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __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>
+
+#if defined(GPR_POSIX_SYNC)
+#include <grpc/support/thd_posix.h>
+#elif defined(GPR_WIN32)
+#include <grpc/support/thd_win32.h>
+#else
+#error could not determine platform for thd
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Thread creation options. */
+typedef struct {
+  int flags; /* Flags below can be set here.  Default value 0.  */
+} gpr_thd_options;
+/* No flags are currently defined. */
+
+/* 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.
+   If options==NULL, default options are used.
+   The thread is immediately runnable, and exits when (*thd_body)() returns.  */
+int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
+                const gpr_thd_options *options);
+
+/* Return a gpr_thd_options struct with all fields set to defaults. */
+gpr_thd_options gpr_thd_options_default(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __GRPC_SUPPORT_THD_H__ */
diff --git a/include/grpc/support/thd_posix.h b/include/grpc/support/thd_posix.h
new file mode 100644
index 0000000..3cfa512
--- /dev/null
+++ b/include/grpc/support/thd_posix.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_THD_POSIX_H__
+#define __GRPC_SUPPORT_THD_POSIX_H__
+/* Posix variant of gpr_thd_platform.h. */
+
+#include <pthread.h>
+
+typedef pthread_t gpr_thd_id;
+
+#endif  /* __GRPC_SUPPORT_THD_POSIX_H__ */
diff --git a/include/grpc/support/thd_win32.h b/include/grpc/support/thd_win32.h
new file mode 100644
index 0000000..6fa576e
--- /dev/null
+++ b/include/grpc/support/thd_win32.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_THD_WIN32_H__
+#define __GRPC_SUPPORT_THD_WIN32_H__
+
+/* Win32 variant of gpr_thd_platform.h */
+
+#include <windows.h>
+#include <grpc/support/atm.h>
+
+typedef int gpr_thd_id;
+
+#endif  /* __GRPC_SUPPORT_THD_WIN32_H__ */
diff --git a/include/grpc/support/time.h b/include/grpc/support/time.h
new file mode 100644
index 0000000..6f07de0
--- /dev/null
+++ b/include/grpc/support/time.h
@@ -0,0 +1,109 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_TIME_H__
+#define __GRPC_SUPPORT_TIME_H__
+/* Time support.
+   We use gpr_timespec, which is typedefed to struct timespec on platforms which
+   have it. On some machines, absolute times may be in local time.  */
+
+/* Platform specific header declares gpr_timespec.
+   gpr_timespec contains:
+      time_t tv_sec;  // seconds since start of 1970
+      int tv_nsec;    // nanoseconds;  always in 0..999999999; never negative.
+ */
+
+#include <grpc/support/port_platform.h>
+
+#if defined(GPR_POSIX_TIME)
+#include <grpc/support/time_posix.h>
+#elif defined(GPR_WIN32)
+#include <grpc/support/time_win32.h>
+#else
+#error could not determine platform for time
+#endif
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Time constants. */
+extern const gpr_timespec gpr_time_0;     /* The zero time interval. */
+extern const gpr_timespec gpr_inf_future; /* The far future */
+extern const gpr_timespec gpr_inf_past;   /* The far past. */
+
+#define GPR_MS_PER_SEC 1000
+#define GPR_US_PER_SEC 1000000
+#define GPR_NS_PER_SEC 1000000000
+#define GPR_NS_PER_MS 1000000
+#define GPR_NS_PER_US 1000
+#define GPR_US_PER_MS 1000
+
+/* Return the current time measured from the system's default epoch. */
+gpr_timespec gpr_now(void);
+
+/* Return -ve, 0, or +ve according to whether a < b, a == b, or a > b
+   respectively.  */
+int gpr_time_cmp(gpr_timespec a, gpr_timespec b);
+
+/* Add and subtract times.  Calculations saturate at infinities. */
+gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b);
+gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b);
+
+/* Return a timespec representing a given number of microseconds.  LONG_MIN is
+   interpreted as gpr_inf_past, and LONG_MAX as gpr_inf_future.  */
+gpr_timespec gpr_time_from_micros(long x);
+gpr_timespec gpr_time_from_nanos(long x);
+gpr_timespec gpr_time_from_millis(long x);
+gpr_timespec gpr_time_from_seconds(long x);
+gpr_timespec gpr_time_from_minutes(long x);
+gpr_timespec gpr_time_from_hours(long x);
+
+/* Return 1 if two times are equal or within threshold of each other,
+   0 otherwise */
+int gpr_time_similar(gpr_timespec a, gpr_timespec b, gpr_timespec threshold);
+
+/* Sleep until at least 'until' - an absolute timeout */
+void gpr_sleep_until(gpr_timespec until);
+
+struct timeval gpr_timeval_from_timespec(gpr_timespec t);
+
+gpr_timespec gpr_timespec_from_timeval(struct timeval t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __GRPC_SUPPORT_TIME_H__ */
diff --git a/include/grpc/support/time_posix.h b/include/grpc/support/time_posix.h
new file mode 100644
index 0000000..72ebf5f
--- /dev/null
+++ b/include/grpc/support/time_posix.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_TIME_POSIX_H__
+#define __GRPC_SUPPORT_TIME_POSIX_H__
+/* Posix variant of gpr_time_platform.h */
+
+#include <sys/time.h>
+#include <time.h>
+
+typedef struct timespec gpr_timespec;
+
+#endif  /* __GRPC_SUPPORT_TIME_POSIX_H__ */
diff --git a/include/grpc/support/time_win32.h b/include/grpc/support/time_win32.h
new file mode 100644
index 0000000..2450550
--- /dev/null
+++ b/include/grpc/support/time_win32.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_TIME_WIN32_H__
+#define __GRPC_SUPPORT_TIME_WIN32_H__
+/* Win32 variant of gpr_time_platform.h */
+
+#include <Winsock.h>
+#include <time.h>
+
+typedef struct gpr_timespec {
+  time_t tv_sec;
+  long tv_nsec;
+} gpr_timespec;
+
+#endif  /* __GRPC_SUPPORT_TIME_WIN32_H__ */
diff --git a/include/grpc/support/useful.h b/include/grpc/support/useful.h
new file mode 100644
index 0000000..2f92b63
--- /dev/null
+++ b/include/grpc/support/useful.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_USEFUL_H__
+#define __GRPC_SUPPORT_USEFUL_H__
+
+/* useful macros that don't belong anywhere else */
+
+#define GPR_MIN(a, b) ((a) < (b) ? (a) : (b))
+#define GPR_MAX(a, b) ((a) > (b) ? (a) : (b))
+#define GPR_CLAMP(a, min, max) ((a) < (min) ? (min) : (a) > (max) ? (max) : (a))
+
+#define GPR_ARRAY_SIZE(array) (sizeof(array) / sizeof(*(array)))
+
+#endif  /* __GRPC_SUPPORT_USEFUL_H__ */
diff --git a/src/core/channel/call_op_string.c b/src/core/channel/call_op_string.c
new file mode 100644
index 0000000..4a98cbf
--- /dev/null
+++ b/src/core/channel/call_op_string.c
@@ -0,0 +1,155 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/channel/channel_stack.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string.h>
+#include <grpc/support/useful.h>
+
+#define MAX_APPEND 1024
+
+typedef struct {
+  size_t cap;
+  size_t len;
+  char *buffer;
+} buf;
+
+static void bprintf(buf *b, const char *fmt, ...) {
+  va_list arg;
+  if (b->len + MAX_APPEND > b->cap) {
+    b->cap = GPR_MAX(b->len + MAX_APPEND, b->cap * 3 / 2);
+    b->buffer = gpr_realloc(b->buffer, b->cap);
+  }
+  va_start(arg, fmt);
+  b->len += vsprintf(b->buffer + b->len, fmt, arg);
+  va_end(arg);
+}
+
+static void bputs(buf *b, const char *s) {
+  size_t slen = strlen(s);
+  if (b->len + slen + 1 > b->cap) {
+    b->cap = GPR_MAX(b->len + slen + 1, b->cap * 3 / 2);
+    b->buffer = gpr_realloc(b->buffer, b->cap);
+  }
+  strcat(b->buffer, s);
+  b->len += slen;
+}
+
+static void put_metadata(buf *b, grpc_mdelem *md) {
+  char *txt;
+
+  txt = gpr_hexdump((char *)GPR_SLICE_START_PTR(md->key->slice),
+                    GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT);
+  bputs(b, " key=");
+  bputs(b, txt);
+  gpr_free(txt);
+
+  txt = gpr_hexdump((char *)GPR_SLICE_START_PTR(md->value->slice),
+                    GPR_SLICE_LENGTH(md->value->slice), GPR_HEXDUMP_PLAINTEXT);
+  bputs(b, " value=");
+  bputs(b, txt);
+  gpr_free(txt);
+}
+
+char *grpc_call_op_string(grpc_call_op *op) {
+  buf b = {0, 0, 0};
+
+  switch (op->dir) {
+    case GRPC_CALL_DOWN:
+      bprintf(&b, ">");
+      break;
+    case GRPC_CALL_UP:
+      bprintf(&b, "<");
+      break;
+  }
+  switch (op->type) {
+    case GRPC_SEND_METADATA:
+      bprintf(&b, "SEND_METADATA");
+      put_metadata(&b, op->data.metadata);
+      break;
+    case GRPC_SEND_DEADLINE:
+      bprintf(&b, "SEND_DEADLINE %d.%09d", op->data.deadline.tv_sec,
+              op->data.deadline.tv_nsec);
+      break;
+    case GRPC_SEND_START:
+      bprintf(&b, "SEND_START");
+      break;
+    case GRPC_SEND_MESSAGE:
+      bprintf(&b, "SEND_MESSAGE");
+      break;
+    case GRPC_SEND_FINISH:
+      bprintf(&b, "SEND_FINISH");
+      break;
+    case GRPC_REQUEST_DATA:
+      bprintf(&b, "REQUEST_DATA");
+      break;
+    case GRPC_RECV_METADATA:
+      bprintf(&b, "RECV_METADATA");
+      put_metadata(&b, op->data.metadata);
+      break;
+    case GRPC_RECV_DEADLINE:
+      bprintf(&b, "RECV_DEADLINE %d.%09d", op->data.deadline.tv_sec,
+              op->data.deadline.tv_nsec);
+      break;
+    case GRPC_RECV_END_OF_INITIAL_METADATA:
+      bprintf(&b, "RECV_END_OF_INITIAL_METADATA");
+      break;
+    case GRPC_RECV_MESSAGE:
+      bprintf(&b, "RECV_MESSAGE");
+      break;
+    case GRPC_RECV_HALF_CLOSE:
+      bprintf(&b, "RECV_HALF_CLOSE");
+      break;
+    case GRPC_RECV_FINISH:
+      bprintf(&b, "RECV_FINISH");
+      break;
+    case GRPC_CANCEL_OP:
+      bprintf(&b, "CANCEL_OP");
+      break;
+  }
+  bprintf(&b, " flags=0x%08x", op->flags);
+
+  return b.buffer;
+}
+
+void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
+                      grpc_call_element *elem, grpc_call_op *op) {
+  char *str = grpc_call_op_string(op);
+  gpr_log(file, line, severity, "OP[%s:%p]: %s", elem->filter->name, elem, str);
+  gpr_free(str);
+}
diff --git a/src/core/channel/census_filter.c b/src/core/channel/census_filter.c
new file mode 100644
index 0000000..4285b28
--- /dev/null
+++ b/src/core/channel/census_filter.c
@@ -0,0 +1,189 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/channel/census_filter.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "src/core/channel/channel_stack.h"
+#include "src/core/channel/noop_filter.h"
+#include "src/core/statistics/census_interface.h"
+#include "src/core/statistics/census_rpc_stats.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/time.h>
+
+typedef struct call_data {
+  census_op_id op_id;
+  census_rpc_stats stats;
+  gpr_timespec start_ts;
+} call_data;
+
+typedef struct channel_data {
+  grpc_mdstr* path_str; /* pointer to meta data str with key == ":path" */
+} channel_data;
+
+static void init_rpc_stats(census_rpc_stats* stats) {
+  memset(stats, 0, sizeof(census_rpc_stats));
+  stats->cnt = 1;
+}
+
+static double gpr_timespec_to_micros(gpr_timespec t) {
+  return t.tv_sec * GPR_US_PER_SEC + t.tv_nsec * 1e-3;
+}
+
+static void extract_and_annotate_method_tag(grpc_call_op* op, call_data* calld,
+                                            channel_data* chand) {
+  if (op->data.metadata->key == chand->path_str) {
+    census_add_method_tag(calld->op_id, (const char*)GPR_SLICE_START_PTR(
+                                            op->data.metadata->value->slice));
+  }
+}
+
+static void client_call_op(grpc_call_element* elem, grpc_call_op* op) {
+  call_data* calld = elem->call_data;
+  channel_data* chand = elem->channel_data;
+  GPR_ASSERT(calld != NULL);
+  GPR_ASSERT(chand != NULL);
+  GPR_ASSERT((calld->op_id.upper != 0) && (calld->op_id.lower != 0));
+  switch (op->type) {
+    case GRPC_SEND_METADATA:
+      extract_and_annotate_method_tag(op, calld, chand);
+      break;
+    case GRPC_RECV_FINISH:
+      /* Should we stop timing the rpc here? */
+      break;
+    default:
+      break;
+  }
+  /* Always pass control up or down the stack depending on op->dir */
+  grpc_call_next_op(elem, op);
+}
+
+static void server_call_op(grpc_call_element* elem, grpc_call_op* op) {
+  call_data* calld = elem->call_data;
+  channel_data* chand = elem->channel_data;
+  GPR_ASSERT(calld != NULL);
+  GPR_ASSERT(chand != NULL);
+  GPR_ASSERT((calld->op_id.upper != 0) && (calld->op_id.lower != 0));
+  switch (op->type) {
+    case GRPC_RECV_METADATA:
+      extract_and_annotate_method_tag(op, calld, chand);
+      break;
+    case GRPC_SEND_FINISH:
+      /* Should we stop timing the rpc here? */
+      break;
+    default:
+      break;
+  }
+  /* Always pass control up or down the stack depending on op->dir */
+  grpc_call_next_op(elem, op);
+}
+
+static void channel_op(grpc_channel_element* elem, grpc_channel_op* op) {
+  switch (op->type) {
+    case GRPC_TRANSPORT_CLOSED:
+      /* TODO(hongyu): Annotate trace information for all calls of the channel
+       */
+      break;
+    default:
+      break;
+  }
+  grpc_channel_next_op(elem, op);
+}
+
+static void client_init_call_elem(grpc_call_element* elem,
+                                  const void* server_transport_data) {
+  call_data* d = elem->call_data;
+  GPR_ASSERT(d != NULL);
+  init_rpc_stats(&d->stats);
+  d->start_ts = gpr_now();
+  d->op_id = census_tracing_start_op();
+}
+
+static void client_destroy_call_elem(grpc_call_element* elem) {
+  call_data* d = elem->call_data;
+  GPR_ASSERT(d != NULL);
+  census_record_rpc_client_stats(d->op_id, &d->stats);
+  census_tracing_end_op(d->op_id);
+}
+
+static void server_init_call_elem(grpc_call_element* elem,
+                                  const void* server_transport_data) {
+  call_data* d = elem->call_data;
+  GPR_ASSERT(d != NULL);
+  init_rpc_stats(&d->stats);
+  d->start_ts = gpr_now();
+  d->op_id = census_tracing_start_op();
+}
+
+static void server_destroy_call_elem(grpc_call_element* elem) {
+  call_data* d = elem->call_data;
+  GPR_ASSERT(d != NULL);
+  d->stats.elapsed_time_ms =
+      gpr_timespec_to_micros(gpr_time_sub(gpr_now(), d->start_ts));
+  census_record_rpc_server_stats(d->op_id, &d->stats);
+  census_tracing_end_op(d->op_id);
+}
+
+static void init_channel_elem(grpc_channel_element* elem,
+                              const grpc_channel_args* args, grpc_mdctx* mdctx,
+                              int is_first, int is_last) {
+  channel_data* chand = elem->channel_data;
+  GPR_ASSERT(chand != NULL);
+  GPR_ASSERT(!is_first);
+  GPR_ASSERT(!is_last);
+  chand->path_str = grpc_mdstr_from_string(mdctx, ":path");
+}
+
+static void destroy_channel_elem(grpc_channel_element* elem) {}
+
+const grpc_channel_filter grpc_client_census_filter = {
+    client_call_op, channel_op,
+
+    sizeof(call_data), client_init_call_elem, client_destroy_call_elem,
+
+    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
+
+    "census-client"};
+
+const grpc_channel_filter grpc_server_census_filter = {
+    server_call_op, channel_op,
+
+    sizeof(call_data), server_init_call_elem, server_destroy_call_elem,
+
+    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
+
+    "census-server"};
diff --git a/src/core/channel/census_filter.h b/src/core/channel/census_filter.h
new file mode 100644
index 0000000..5b2c01c
--- /dev/null
+++ b/src/core/channel/census_filter.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_CHANNEL_CENSUS_FILTER_H__
+#define __GRPC_INTERNAL_CHANNEL_CENSUS_FILTER_H__
+
+#include "src/core/channel/channel_stack.h"
+
+/* Census filters: provides tracing and stats collection functionalities. It
+   needs to reside right below the surface filter in the channel stack. */
+extern const grpc_channel_filter grpc_client_census_filter;
+extern const grpc_channel_filter grpc_server_census_filter;
+
+#endif /* __GRPC_INTERNAL_CHANNEL_CENSUS_FILTER_H__ */
diff --git a/src/core/channel/channel_args.c b/src/core/channel/channel_args.c
new file mode 100644
index 0000000..36312e5
--- /dev/null
+++ b/src/core/channel/channel_args.c
@@ -0,0 +1,112 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+#include "src/core/channel/channel_args.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string.h>
+
+#include <string.h>
+
+static grpc_arg copy_arg(const grpc_arg *src) {
+  grpc_arg dst;
+  dst.type = src->type;
+  dst.key = gpr_strdup(src->key);
+  switch (dst.type) {
+    case GRPC_ARG_STRING:
+      dst.value.string = gpr_strdup(src->value.string);
+      break;
+    case GRPC_ARG_INTEGER:
+      dst.value.integer = src->value.integer;
+      break;
+    case GRPC_ARG_POINTER:
+      dst.value.pointer = src->value.pointer;
+      dst.value.pointer.p = src->value.pointer.copy(src->value.pointer.p);
+      break;
+  }
+  return dst;
+}
+
+grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src,
+                                                  const grpc_arg *to_add) {
+  grpc_channel_args *dst = gpr_malloc(sizeof(grpc_channel_args));
+  size_t i;
+  size_t src_num_args = (src == NULL) ? 0 : src->num_args;
+  if (!src && !to_add) {
+    dst->num_args = 0;
+    dst->args = NULL;
+    return dst;
+  }
+  dst->num_args = src_num_args + ((to_add == NULL) ? 0 : 1);
+  dst->args = gpr_malloc(sizeof(grpc_arg) * dst->num_args);
+  for (i = 0; i < src_num_args; i++) {
+    dst->args[i] = copy_arg(&src->args[i]);
+  }
+  if (to_add != NULL) dst->args[src_num_args] = copy_arg(to_add);
+  return dst;
+}
+
+grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src) {
+  return grpc_channel_args_copy_and_add(src, NULL);
+}
+
+void grpc_channel_args_destroy(grpc_channel_args *a) {
+  size_t i;
+  for (i = 0; i < a->num_args; i++) {
+    switch (a->args[i].type) {
+      case GRPC_ARG_STRING:
+        gpr_free(a->args[i].value.string);
+        break;
+      case GRPC_ARG_INTEGER:
+        break;
+      case GRPC_ARG_POINTER:
+        a->args[i].value.pointer.destroy(a->args[i].value.pointer.p);
+        break;
+    }
+    gpr_free(a->args[i].key);
+  }
+  gpr_free(a->args);
+  gpr_free(a);
+}
+
+int grpc_channel_args_is_census_enabled(const grpc_channel_args *a) {
+  int i;
+  if (a == NULL) return 0;
+  for (i = 0; i < a->num_args; i++) {
+    if (0 == strcmp(a->args[i].key, GRPC_ARG_ENABLE_CENSUS)) {
+      return a->args[i].value.integer != 0;
+    }
+  }
+  return 0;
+}
diff --git a/src/core/channel/channel_args.h b/src/core/channel/channel_args.h
new file mode 100644
index 0000000..cf38d5d
--- /dev/null
+++ b/src/core/channel/channel_args.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_CHANNEL_CHANNEL_ARGS_H__
+#define __GRPC_INTERNAL_CHANNEL_CHANNEL_ARGS_H__
+
+#include <grpc/grpc.h>
+
+/* Copy some arguments */
+grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src);
+
+/* Copy some arguments and add the to_add parameter in the end.
+   If to_add is NULL, it is equivalent to call grpc_channel_args_copy. */
+grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src,
+                                                  const grpc_arg *to_add);
+
+/* Destroy arguments created by grpc_channel_args_copy */
+void grpc_channel_args_destroy(grpc_channel_args *a);
+
+/* Reads census_enabled settings from channel args. Returns 1 if census_enabled
+   is specified in channel args, otherwise returns 0. */
+int grpc_channel_args_is_census_enabled(const grpc_channel_args *a);
+
+#endif  /* __GRPC_INTERNAL_CHANNEL_CHANNEL_ARGS_H__ */
diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c
new file mode 100644
index 0000000..a403db3
--- /dev/null
+++ b/src/core/channel/channel_stack.c
@@ -0,0 +1,223 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/channel/channel_stack.h"
+#include <grpc/support/log.h>
+
+#include <stdlib.h>
+
+/* Memory layouts.
+
+   Channel stack is laid out as: {
+     grpc_channel_stack stk;
+     padding to GPR_MAX_ALIGNMENT
+     grpc_channel_element[stk.count];
+     per-filter memory, aligned to GPR_MAX_ALIGNMENT
+   }
+
+   Call stack is laid out as: {
+     grpc_call_stack stk;
+     padding to GPR_MAX_ALIGNMENT
+     grpc_call_element[stk.count];
+     per-filter memory, aligned to GPR_MAX_ALIGNMENT
+   } */
+
+/* Given a size, round up to the next multiple of sizeof(void*) */
+#define ROUND_UP_TO_ALIGNMENT_SIZE(x) \
+  (((x)+GPR_MAX_ALIGNMENT - 1) & ~(GPR_MAX_ALIGNMENT - 1))
+
+size_t grpc_channel_stack_size(const grpc_channel_filter **filters,
+                               size_t filter_count) {
+  /* always need the header, and size for the channel elements */
+  size_t size =
+      ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)) +
+      ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element));
+  size_t i;
+
+  GPR_ASSERT((GPR_MAX_ALIGNMENT & (GPR_MAX_ALIGNMENT - 1)) == 0 &&
+             "GPR_MAX_ALIGNMENT must be a power of two");
+
+  /* add the size for each filter */
+  for (i = 0; i < filter_count; i++) {
+    size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
+  }
+
+  return size;
+}
+
+#define CHANNEL_ELEMS_FROM_STACK(stk)                                   \
+  ((grpc_channel_element *)((char *)(stk) + ROUND_UP_TO_ALIGNMENT_SIZE( \
+                                                sizeof(grpc_channel_stack))))
+
+#define CALL_ELEMS_FROM_STACK(stk)       \
+  ((grpc_call_element *)((char *)(stk) + \
+                         ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack))))
+
+grpc_channel_element *grpc_channel_stack_element(
+    grpc_channel_stack *channel_stack, size_t index) {
+  return CHANNEL_ELEMS_FROM_STACK(channel_stack) + index;
+}
+
+grpc_channel_element *grpc_channel_stack_last_element(
+    grpc_channel_stack *channel_stack) {
+  return grpc_channel_stack_element(channel_stack, channel_stack->count - 1);
+}
+
+grpc_call_element *grpc_call_stack_element(grpc_call_stack *call_stack,
+                                           size_t index) {
+  return CALL_ELEMS_FROM_STACK(call_stack) + index;
+}
+
+void grpc_channel_stack_init(const grpc_channel_filter **filters,
+                             size_t filter_count, const grpc_channel_args *args,
+                             grpc_mdctx *metadata_context,
+                             grpc_channel_stack *stack) {
+  size_t call_size =
+      ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
+      ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_call_element));
+  grpc_channel_element *elems;
+  char *user_data;
+  size_t i;
+
+  stack->count = filter_count;
+  elems = CHANNEL_ELEMS_FROM_STACK(stack);
+  user_data =
+      ((char *)elems) +
+      ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element));
+
+  /* init per-filter data */
+  for (i = 0; i < filter_count; i++) {
+    elems[i].filter = filters[i];
+    elems[i].channel_data = user_data;
+    elems[i].filter->init_channel_elem(&elems[i], args, metadata_context,
+                                       i == 0, i == (filter_count - 1));
+    user_data += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
+    call_size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_call_data);
+  }
+
+  GPR_ASSERT(user_data - (char *)stack ==
+             grpc_channel_stack_size(filters, filter_count));
+
+  stack->call_stack_size = call_size;
+}
+
+void grpc_channel_stack_destroy(grpc_channel_stack *stack) {
+  grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(stack);
+  size_t count = stack->count;
+  size_t i;
+
+  /* destroy per-filter data */
+  for (i = 0; i < count; i++) {
+    channel_elems[i].filter->destroy_channel_elem(&channel_elems[i]);
+  }
+}
+
+void grpc_call_stack_init(grpc_channel_stack *channel_stack,
+                          const void *transport_server_data,
+                          grpc_call_stack *call_stack) {
+  grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
+  size_t count = channel_stack->count;
+  grpc_call_element *call_elems;
+  char *user_data;
+  size_t i;
+
+  call_stack->count = count;
+  call_elems = CALL_ELEMS_FROM_STACK(call_stack);
+  user_data = ((char *)call_elems) +
+              ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
+
+  /* init per-filter data */
+  for (i = 0; i < count; i++) {
+    call_elems[i].filter = channel_elems[i].filter;
+    call_elems[i].channel_data = channel_elems[i].channel_data;
+    call_elems[i].call_data = user_data;
+    call_elems[i].filter->init_call_elem(&call_elems[i], transport_server_data);
+    user_data +=
+        ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
+  }
+}
+
+void grpc_call_stack_destroy(grpc_call_stack *stack) {
+  grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack);
+  size_t count = stack->count;
+  size_t i;
+
+  /* destroy per-filter data */
+  for (i = 0; i < count; i++) {
+    elems[i].filter->destroy_call_elem(&elems[i]);
+  }
+}
+
+void grpc_call_next_op(grpc_call_element *elem, grpc_call_op *op) {
+  grpc_call_element *next_elem = elem + op->dir;
+  next_elem->filter->call_op(next_elem, op);
+}
+
+void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op) {
+  grpc_channel_element *next_elem = elem + op->dir;
+  next_elem->filter->channel_op(next_elem, op);
+}
+
+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)));
+}
+
+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)));
+}
+
+static void do_nothing(void *user_data, grpc_op_error error) {}
+
+void grpc_call_element_send_metadata(grpc_call_element *cur_elem,
+                                     grpc_mdelem *mdelem) {
+  grpc_call_op metadata_op;
+  metadata_op.type = GRPC_SEND_METADATA;
+  metadata_op.dir = GRPC_CALL_DOWN;
+  metadata_op.done_cb = do_nothing;
+  metadata_op.user_data = NULL;
+  metadata_op.data.metadata = grpc_mdelem_ref(mdelem);
+  grpc_call_next_op(cur_elem, &metadata_op);
+}
+
+void grpc_call_element_send_cancel(grpc_call_element *cur_elem) {
+  grpc_call_op cancel_op;
+  cancel_op.type = GRPC_CANCEL_OP;
+  cancel_op.dir = GRPC_CALL_DOWN;
+  cancel_op.done_cb = do_nothing;
+  cancel_op.user_data = NULL;
+  grpc_call_next_op(cur_elem, &cancel_op);
+}
diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h
new file mode 100644
index 0000000..0ae1005
--- /dev/null
+++ b/src/core/channel/channel_stack.h
@@ -0,0 +1,288 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_CHANNEL_CHANNEL_STACK_H__
+#define __GRPC_INTERNAL_CHANNEL_CHANNEL_STACK_H__
+
+/* A channel filter defines how operations on a channel are implemented.
+   Channel filters are chained together to create full channels, and if those
+   chains are linear, then channel stacks provide a mechanism to minimize
+   allocations for that chain.
+   Call stacks are created by channel stacks and represent the per-call data
+   for that stack. */
+
+#include <stddef.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include "src/core/transport/transport.h"
+
+/* #define GRPC_CHANNEL_STACK_TRACE 1 */
+
+typedef struct grpc_channel_element grpc_channel_element;
+typedef struct grpc_call_element grpc_call_element;
+
+/* Call operations - things that can be sent and received.
+
+   Threading:
+     SEND, RECV, and CANCEL ops can be active on a call at the same time, but
+     only one SEND, one RECV, and one CANCEL can be active at a time.
+
+   If state is shared between send/receive/cancel operations, it is up to
+   filters to provide their own protection around that. */
+typedef enum {
+  /* send metadata to the channels peer */
+  GRPC_SEND_METADATA,
+  /* send a deadline */
+  GRPC_SEND_DEADLINE,
+  /* start a connection (corresponds to start_invoke/accept) */
+  GRPC_SEND_START,
+  /* send a message to the channels peer */
+  GRPC_SEND_MESSAGE,
+  /* send half-close to the channels peer */
+  GRPC_SEND_FINISH,
+  /* request that more data be allowed through flow control */
+  GRPC_REQUEST_DATA,
+  /* metadata was received from the channels peer */
+  GRPC_RECV_METADATA,
+  /* receive a deadline */
+  GRPC_RECV_DEADLINE,
+  /* the end of the first batch of metadata was received */
+  GRPC_RECV_END_OF_INITIAL_METADATA,
+  /* a message was received from the channels peer */
+  GRPC_RECV_MESSAGE,
+  /* half-close was received from the channels peer */
+  GRPC_RECV_HALF_CLOSE,
+  /* full close was received from the channels peer */
+  GRPC_RECV_FINISH,
+  /* the call has been abnormally terminated */
+  GRPC_CANCEL_OP
+} grpc_call_op_type;
+
+/* The direction of the call.
+   The values of the enums (1, -1) matter here - they are used to increment
+   or decrement a pointer to find the next element to call */
+typedef enum { GRPC_CALL_DOWN = 1, GRPC_CALL_UP = -1 } grpc_call_dir;
+
+/* A single filterable operation to be performed on a call */
+typedef struct {
+  /* The type of operation we're performing */
+  grpc_call_op_type type;
+  /* The directionality of this call - does the operation begin at the bottom
+     of the stack and flow up, or does the operation start at the top of the
+     stack and flow down through the filters. */
+  grpc_call_dir dir;
+
+  /* Flags associated with this call: see GRPC_WRITE_* in grpc.h */
+  gpr_uint32 flags;
+
+  /* Argument data, matching up with grpc_call_op_type names */
+  union {
+    grpc_byte_buffer *message;
+    grpc_mdelem *metadata;
+    gpr_timespec deadline;
+  } data;
+
+  /* Must be called when processing of this call-op is complete.
+     Signature chosen to match transport flow control callbacks */
+  void (*done_cb)(void *user_data, grpc_op_error error);
+  /* User data to be passed into done_cb */
+  void *user_data;
+} grpc_call_op;
+
+/* returns a string representation of op, that can be destroyed with gpr_free */
+char *grpc_call_op_string(grpc_call_op *op);
+
+typedef enum {
+  GRPC_CHANNEL_SHUTDOWN,
+  GRPC_ACCEPT_CALL,
+  GRPC_TRANSPORT_CLOSED
+} grpc_channel_op_type;
+
+/* A single filterable operation to be performed on a channel */
+typedef struct {
+  /* The type of operation we're performing */
+  grpc_channel_op_type type;
+  /* The directionality of this call - is it bubbling up the stack, or down? */
+  grpc_call_dir dir;
+
+  /* Argument data, matching up with grpc_channel_op_type names */
+  union {
+    struct {
+      grpc_transport *transport;
+      const void *transport_server_data;
+    } accept_call;
+  } data;
+} grpc_channel_op;
+
+/* Channel filters specify:
+   1. the amount of memory needed in the channel & call (via the sizeof_XXX
+      members)
+   2. functions to initialize and destroy channel & call data
+      (init_XXX, destroy_XXX)
+   3. functions to implement call operations and channel operations (call_op,
+      channel_op)
+   4. a name, which is useful when debugging
+
+   Members are laid out in approximate frequency of use order. */
+typedef struct {
+  /* Called to eg. send/receive data on a call.
+     See grpc_call_next_op on how to call the next element in the stack */
+  void (*call_op)(grpc_call_element *elem, grpc_call_op *op);
+  /* Called to handle channel level operations - e.g. new calls, or transport
+     closure.
+     See grpc_channel_next_op on how to call the next element in the stack */
+  void (*channel_op)(grpc_channel_element *elem, grpc_channel_op *op);
+
+  /* sizeof(per call data) */
+  size_t sizeof_call_data;
+  /* Initialize per call data.
+     elem is initialized at the start of the call, and elem->call_data is what
+     needs initializing.
+     The filter does not need to do any chaining.
+     server_transport_data is an opaque pointer. If it is NULL, this call is
+     on a client; if it is non-NULL, then it points to memory owned by the
+     transport and is on the server. Most filters want to ignore this
+     argument.*/
+  void (*init_call_elem)(grpc_call_element *elem,
+                         const void *server_transport_data);
+  /* Destroy per call data.
+     The filter does not need to do any chaining */
+  void (*destroy_call_elem)(grpc_call_element *elem);
+
+  /* sizeof(per channel data) */
+  size_t sizeof_channel_data;
+  /* Initialize per-channel data.
+     elem is initialized at the start of the call, and elem->channel_data is
+     what needs initializing.
+     is_first, is_last designate this elements position in the stack, and are
+     useful for asserting correct configuration by upper layer code.
+     The filter does not need to do any chaining */
+  void (*init_channel_elem)(grpc_channel_element *elem,
+                            const grpc_channel_args *args,
+                            grpc_mdctx *metadata_context, int is_first,
+                            int is_last);
+  /* Destroy per channel data.
+     The filter does not need to do any chaining */
+  void (*destroy_channel_elem)(grpc_channel_element *elem);
+
+  /* The name of this filter */
+  const char *name;
+} grpc_channel_filter;
+
+/* A channel_element tracks its filter and the filter requested memory within
+   a channel allocation */
+struct grpc_channel_element {
+  const grpc_channel_filter *filter;
+  void *channel_data;
+};
+
+/* A call_element tracks its filter, the filter requested memory within
+   a channel allocation, and the filter requested memory within a call
+   allocation */
+struct grpc_call_element {
+  const grpc_channel_filter *filter;
+  void *channel_data;
+  void *call_data;
+};
+
+/* A channel stack tracks a set of related filters for one channel, and
+   guarantees they live within a single malloc() allocation */
+typedef struct {
+  size_t count;
+  /* Memory required for a call stack (computed at channel stack
+     initialization) */
+  size_t call_stack_size;
+} grpc_channel_stack;
+
+/* A call stack tracks a set of related filters for one call, and guarantees
+   they live within a single malloc() allocation */
+typedef struct { size_t count; } grpc_call_stack;
+
+/* Get a channel element given a channel stack and its index */
+grpc_channel_element *grpc_channel_stack_element(grpc_channel_stack *stack,
+                                                 size_t i);
+/* Get the last channel element in a channel stack */
+grpc_channel_element *grpc_channel_stack_last_element(
+    grpc_channel_stack *stack);
+/* Get a call stack element given a call stack and an index */
+grpc_call_element *grpc_call_stack_element(grpc_call_stack *stack, size_t i);
+
+/* Determine memory required for a channel stack containing a set of filters */
+size_t grpc_channel_stack_size(const grpc_channel_filter **filters,
+                               size_t filter_count);
+/* Initialize a channel stack given some filters */
+void grpc_channel_stack_init(const grpc_channel_filter **filters,
+                             size_t filter_count, const grpc_channel_args *args,
+                             grpc_mdctx *metadata_context,
+                             grpc_channel_stack *stack);
+/* Destroy a channel stack */
+void grpc_channel_stack_destroy(grpc_channel_stack *stack);
+
+/* Initialize a call stack given a channel stack. transport_server_data is
+   expected to be NULL on a client, or an opaque transport owned pointer on the
+   server. */
+void grpc_call_stack_init(grpc_channel_stack *channel_stack,
+                          const void *transport_server_data,
+                          grpc_call_stack *call_stack);
+/* Destroy a call stack */
+void grpc_call_stack_destroy(grpc_call_stack *stack);
+
+/* Call the next operation (depending on call directionality) in a call stack */
+void grpc_call_next_op(grpc_call_element *elem, grpc_call_op *op);
+/* Call the next operation (depending on call directionality) in a channel
+   stack */
+void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op);
+
+/* Given the top element of a channel stack, get the channel stack itself */
+grpc_channel_stack *grpc_channel_stack_from_top_element(
+    grpc_channel_element *elem);
+/* Given the top element of a call stack, get the call stack itself */
+grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem);
+
+void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
+                      grpc_call_element *elem, grpc_call_op *op);
+
+void grpc_call_element_send_metadata(grpc_call_element *cur_elem,
+                                     grpc_mdelem *elem);
+void grpc_call_element_send_cancel(grpc_call_element *cur_elem);
+
+#ifdef GRPC_CHANNEL_STACK_TRACE
+#define GRPC_CALL_LOG_OP(sev, elem, op) grpc_call_log_op(sev, elem, op)
+#else
+#define GRPC_CALL_LOG_OP(sev, elem, op) \
+  do {                                  \
+  } while (0)
+#endif
+
+#endif  /* __GRPC_INTERNAL_CHANNEL_CHANNEL_STACK_H__ */
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
new file mode 100644
index 0000000..9056368
--- /dev/null
+++ b/src/core/channel/client_channel.c
@@ -0,0 +1,641 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/channel/client_channel.h"
+
+#include <stdio.h>
+
+#include "src/core/channel/channel_args.h"
+#include "src/core/channel/connected_channel.h"
+#include "src/core/channel/metadata_buffer.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/useful.h>
+
+/* Link back filter: passes up calls to the client channel, pushes down calls
+   down */
+
+typedef struct { grpc_channel_element *back; } lb_channel_data;
+
+typedef struct { grpc_call_element *back; } lb_call_data;
+
+static void lb_call_op(grpc_call_element *elem, grpc_call_op *op) {
+  lb_call_data *calld = elem->call_data;
+
+  switch (op->dir) {
+    case GRPC_CALL_UP:
+      calld->back->filter->call_op(calld->back, op);
+      break;
+    case GRPC_CALL_DOWN:
+      grpc_call_next_op(elem, op);
+      break;
+  }
+}
+
+/* Currently we assume all channel operations should just be pushed up. */
+static void lb_channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+  lb_channel_data *chand = elem->channel_data;
+
+  switch (op->dir) {
+    case GRPC_CALL_UP:
+      chand->back->filter->channel_op(chand->back, op);
+      break;
+    case GRPC_CALL_DOWN:
+      grpc_channel_next_op(elem, op);
+      break;
+  }
+}
+
+/* Constructor for call_data */
+static void lb_init_call_elem(grpc_call_element *elem,
+                              const void *server_transport_data) {}
+
+/* Destructor for call_data */
+static void lb_destroy_call_elem(grpc_call_element *elem) {}
+
+/* Constructor for channel_data */
+static void lb_init_channel_elem(grpc_channel_element *elem,
+                                 const grpc_channel_args *args,
+                                 grpc_mdctx *metadata_context, int is_first,
+                                 int is_last) {
+  GPR_ASSERT(is_first);
+  GPR_ASSERT(!is_last);
+}
+
+/* Destructor for channel_data */
+static void lb_destroy_channel_elem(grpc_channel_element *elem) {}
+
+static const grpc_channel_filter link_back_filter = {
+    lb_call_op,               lb_channel_op,
+
+    sizeof(lb_call_data),     lb_init_call_elem,    lb_destroy_call_elem,
+
+    sizeof(lb_channel_data),  lb_init_channel_elem, lb_destroy_channel_elem,
+
+    "clientchannel.linkback",
+};
+
+/* Client channel implementation */
+
+typedef struct {
+  size_t inflight_requests;
+  grpc_channel_stack *channel_stack;
+} child_entry;
+
+typedef struct call_data call_data;
+
+typedef struct {
+  /* protects children, child_count, child_capacity, active_child,
+     transport_setup_initiated
+     does not protect channel stacks held by children
+     transport_setup is assumed to be set once during construction */
+  gpr_mu mu;
+
+  /* the sending child (points somewhere in children, or NULL) */
+  child_entry *active_child;
+  /* vector of child channels  */
+  child_entry *children;
+  size_t child_count;
+  size_t child_capacity;
+
+  /* calls waiting for a channel to be ready */
+  call_data **waiting_children;
+  size_t waiting_child_count;
+  size_t waiting_child_capacity;
+
+  /* transport setup for this channel */
+  grpc_transport_setup *transport_setup;
+  int transport_setup_initiated;
+
+  grpc_channel_args *args;
+
+  /* metadata cache */
+  grpc_mdelem *cancel_status;
+} channel_data;
+
+typedef enum {
+  CALL_CREATED,
+  CALL_WAITING,
+  CALL_ACTIVE,
+  CALL_CANCELLED
+} call_state;
+
+struct call_data {
+  /* owning element */
+  grpc_call_element *elem;
+
+  call_state state;
+  grpc_metadata_buffer pending_metadata;
+  gpr_timespec deadline;
+  union {
+    struct {
+      /* our child call stack */
+      grpc_call_stack *child_stack;
+      /* ... and the channel stack associated with it */
+      grpc_channel_stack *using_stack;
+    } active;
+    struct {
+      void (*on_complete)(void *user_data, grpc_op_error error);
+      void *on_complete_user_data;
+      gpr_uint32 start_flags;
+    } waiting;
+  } s;
+};
+
+static int prepare_activate(call_data *calld, child_entry *on_child) {
+  grpc_call_element *child_elem;
+  grpc_channel_stack *use_stack = on_child->channel_stack;
+
+  if (calld->state == CALL_CANCELLED) return 0;
+
+  on_child->inflight_requests++;
+
+  /* no more access to calld->s.waiting allowed */
+  GPR_ASSERT(calld->state == CALL_WAITING);
+  calld->state = CALL_ACTIVE;
+
+  /* create a child stack, and record that we're using a particular channel
+     stack */
+  calld->s.active.child_stack = gpr_malloc(use_stack->call_stack_size);
+  calld->s.active.using_stack = use_stack;
+  grpc_call_stack_init(use_stack, NULL, calld->s.active.child_stack);
+  /* initialize the top level link back element */
+  child_elem = grpc_call_stack_element(calld->s.active.child_stack, 0);
+  GPR_ASSERT(child_elem->filter == &link_back_filter);
+  ((lb_call_data *)child_elem->call_data)->back = calld->elem;
+
+  return 1;
+}
+
+static void do_nothing(void *ignored, grpc_op_error error) {}
+
+static void complete_activate(call_data *calld, child_entry *on_child,
+                              grpc_call_op *op) {
+  grpc_call_element *child_elem =
+      grpc_call_stack_element(calld->s.active.child_stack, 0);
+
+  GPR_ASSERT(calld->state == CALL_ACTIVE);
+
+  /* sending buffered metadata down the stack before the start call */
+  grpc_metadata_buffer_flush(&calld->pending_metadata, child_elem);
+
+  if (gpr_time_cmp(calld->deadline, gpr_inf_future) != 0) {
+    grpc_call_op dop;
+    dop.type = GRPC_SEND_DEADLINE;
+    dop.dir = GRPC_CALL_DOWN;
+    dop.flags = 0;
+    dop.data.deadline = calld->deadline;
+    dop.done_cb = do_nothing;
+    dop.user_data = NULL;
+    child_elem->filter->call_op(child_elem, &dop);
+  }
+
+  /* continue the start call down the stack, this nees to happen after metadata
+     are flushed*/
+  child_elem->filter->call_op(child_elem, op);
+}
+
+static void start_rpc(call_data *calld, channel_data *chand, grpc_call_op *op) {
+  gpr_mu_lock(&chand->mu);
+  if (calld->state == CALL_CANCELLED) {
+    gpr_mu_unlock(&chand->mu);
+    op->done_cb(op->user_data, GRPC_OP_ERROR);
+    return;
+  }
+  GPR_ASSERT(calld->state == CALL_CREATED);
+  calld->state = CALL_WAITING;
+  if (chand->active_child) {
+    /* channel is connected - use the connected stack */
+    if (prepare_activate(calld, chand->active_child)) {
+      gpr_mu_unlock(&chand->mu);
+      /* activate the request (pass it down) outside the lock */
+      complete_activate(calld, chand->active_child, op);
+    } else {
+      gpr_mu_unlock(&chand->mu);
+    }
+  } else {
+    /* check to see if we should initiate a connection (if we're not already),
+       but don't do so until outside the lock to avoid re-entrancy problems if
+       the callback is immediate */
+    int initiate_transport_setup = 0;
+    if (!chand->transport_setup_initiated) {
+      chand->transport_setup_initiated = 1;
+      initiate_transport_setup = 1;
+    }
+    /* add this call to the waiting set to be resumed once we have a child
+       channel stack, growing the waiting set if needed */
+    if (chand->waiting_child_count == chand->waiting_child_capacity) {
+      chand->waiting_child_capacity =
+          GPR_MAX(chand->waiting_child_capacity * 2, 8);
+      chand->waiting_children =
+          gpr_realloc(chand->waiting_children,
+                      chand->waiting_child_capacity * sizeof(call_data *));
+    }
+    calld->s.waiting.on_complete = op->done_cb;
+    calld->s.waiting.on_complete_user_data = op->user_data;
+    calld->s.waiting.start_flags = op->flags;
+    chand->waiting_children[chand->waiting_child_count++] = calld;
+    gpr_mu_unlock(&chand->mu);
+
+    /* finally initiate transport setup if needed */
+    if (initiate_transport_setup) {
+      grpc_transport_setup_initiate(chand->transport_setup);
+    }
+  }
+}
+
+static void remove_waiting_child(channel_data *chand, call_data *calld) {
+  size_t new_count;
+  size_t i;
+  for (i = 0, new_count = 0; i < chand->waiting_child_count; i++) {
+    if (chand->waiting_children[i] == calld) continue;
+    chand->waiting_children[new_count++] = chand->waiting_children[i];
+  }
+  GPR_ASSERT(new_count == chand->waiting_child_count - 1 ||
+             new_count == chand->waiting_child_count);
+  chand->waiting_child_count = new_count;
+}
+
+static void cancel_rpc(grpc_call_element *elem, grpc_call_op *op) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  grpc_call_element *child_elem;
+  grpc_call_op finish_op;
+
+  gpr_mu_lock(&chand->mu);
+  switch (calld->state) {
+    case CALL_ACTIVE:
+      child_elem = grpc_call_stack_element(calld->s.active.child_stack, 0);
+      gpr_mu_unlock(&chand->mu);
+      child_elem->filter->call_op(child_elem, op);
+      return; /* early out */
+    case CALL_WAITING:
+      remove_waiting_child(chand, calld);
+      calld->s.waiting.on_complete(calld->s.waiting.on_complete_user_data,
+                                   GRPC_OP_ERROR);
+    /* fallthrough intended */
+    case CALL_CREATED:
+      calld->state = CALL_CANCELLED;
+      gpr_mu_unlock(&chand->mu);
+      /* send up a synthesized status */
+      finish_op.type = GRPC_RECV_METADATA;
+      finish_op.dir = GRPC_CALL_UP;
+      finish_op.flags = 0;
+      finish_op.data.metadata = grpc_mdelem_ref(chand->cancel_status);
+      finish_op.done_cb = do_nothing;
+      finish_op.user_data = NULL;
+      grpc_call_next_op(elem, &finish_op);
+      /* send up a finish */
+      finish_op.type = GRPC_RECV_FINISH;
+      finish_op.dir = GRPC_CALL_UP;
+      finish_op.flags = 0;
+      finish_op.done_cb = do_nothing;
+      finish_op.user_data = NULL;
+      grpc_call_next_op(elem, &finish_op);
+      return; /* early out */
+    case CALL_CANCELLED:
+      gpr_mu_unlock(&chand->mu);
+      return; /* early out */
+  }
+  gpr_log(GPR_ERROR, "should never reach here");
+  abort();
+}
+
+static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  grpc_call_element *child_elem;
+  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
+  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+
+  switch (op->type) {
+    case GRPC_SEND_METADATA:
+      grpc_metadata_buffer_queue(&calld->pending_metadata, op);
+      break;
+    case GRPC_SEND_DEADLINE:
+      calld->deadline = op->data.deadline;
+      op->done_cb(op->user_data, GRPC_OP_OK);
+      break;
+    case GRPC_SEND_START:
+      /* filter out the start event to find which child to send on */
+      start_rpc(calld, chand, op);
+      break;
+    case GRPC_CANCEL_OP:
+      cancel_rpc(elem, op);
+      break;
+    default:
+      switch (op->dir) {
+        case GRPC_CALL_UP:
+          grpc_call_next_op(elem, op);
+          break;
+        case GRPC_CALL_DOWN:
+          child_elem = grpc_call_stack_element(calld->s.active.child_stack, 0);
+          GPR_ASSERT(calld->state == CALL_ACTIVE);
+          child_elem->filter->call_op(child_elem, op);
+          break;
+      }
+      break;
+  }
+}
+
+static void broadcast_channel_op_down(grpc_channel_element *elem,
+                                      grpc_channel_op *op) {
+  channel_data *chand = elem->channel_data;
+  grpc_channel_element *child_elem;
+  grpc_channel_stack **children;
+  size_t child_count;
+  size_t i;
+
+  /* copy the current set of children, and mark them all as having an inflight
+     request */
+  gpr_mu_lock(&chand->mu);
+  child_count = chand->child_count;
+  children = gpr_malloc(sizeof(grpc_channel_stack *) * child_count);
+  for (i = 0; i < child_count; i++) {
+    children[i] = chand->children[i].channel_stack;
+    chand->children[i].inflight_requests++;
+  }
+  gpr_mu_unlock(&chand->mu);
+
+  /* send the message down */
+  for (i = 0; i < child_count; i++) {
+    child_elem = grpc_channel_stack_element(children[i], 0);
+    child_elem->filter->channel_op(child_elem, op);
+  }
+
+  /* unmark the inflight requests */
+  gpr_mu_lock(&chand->mu);
+  for (i = 0; i < child_count; i++) {
+    chand->children[i].inflight_requests--;
+  }
+  gpr_mu_unlock(&chand->mu);
+
+  gpr_free(children);
+}
+
+static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
+
+  switch (op->type) {
+    default:
+      switch (op->dir) {
+        case GRPC_CALL_UP:
+          grpc_channel_next_op(elem, op);
+          break;
+        case GRPC_CALL_DOWN:
+          broadcast_channel_op_down(elem, op);
+          break;
+      }
+      break;
+  }
+}
+
+static void error_bad_on_complete(void *arg, grpc_op_error error) {
+  gpr_log(GPR_ERROR,
+          "Waiting finished but not started? Bad on_complete callback");
+  abort();
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_call_element *elem,
+                           const void *server_transport_data) {
+  call_data *calld = elem->call_data;
+
+  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
+  GPR_ASSERT(server_transport_data == NULL);
+  calld->elem = elem;
+  calld->state = CALL_CREATED;
+  calld->deadline = gpr_inf_future;
+  calld->s.waiting.on_complete = error_bad_on_complete;
+  calld->s.waiting.on_complete_user_data = NULL;
+  grpc_metadata_buffer_init(&calld->pending_metadata);
+}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_call_element *elem) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  size_t i;
+
+  /* if the metadata buffer is not flushed, destroy it here. */
+  grpc_metadata_buffer_destroy(&calld->pending_metadata, GRPC_OP_OK);
+  /* if the call got activated, we need to destroy the child stack also, and
+     remove it from the in-flight requests tracked by the child_entry we
+     picked */
+  if (calld->state == CALL_ACTIVE) {
+    grpc_call_stack_destroy(calld->s.active.child_stack);
+    gpr_free(calld->s.active.child_stack);
+
+    gpr_mu_lock(&chand->mu);
+    for (i = 0; i < chand->child_count; i++) {
+      if (chand->children[i].channel_stack == calld->s.active.using_stack) {
+        chand->children[i].inflight_requests--;
+        /* TODO(ctiller): garbage collect channels that are not active
+           and have no inflight requests */
+      }
+    }
+    gpr_mu_unlock(&chand->mu);
+  }
+}
+
+/* Constructor for channel_data */
+static void init_channel_elem(grpc_channel_element *elem,
+                              const grpc_channel_args *args,
+                              grpc_mdctx *metadata_context, int is_first,
+                              int is_last) {
+  channel_data *chand = elem->channel_data;
+  char temp[16];
+
+  GPR_ASSERT(!is_first);
+  GPR_ASSERT(is_last);
+  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
+
+  gpr_mu_init(&chand->mu);
+  chand->active_child = NULL;
+  chand->children = NULL;
+  chand->child_count = 0;
+  chand->child_capacity = 0;
+  chand->waiting_children = NULL;
+  chand->waiting_child_count = 0;
+  chand->waiting_child_capacity = 0;
+  chand->transport_setup = NULL;
+  chand->transport_setup_initiated = 0;
+  chand->args = grpc_channel_args_copy(args);
+
+  sprintf(temp, "%d", GRPC_STATUS_CANCELLED);
+  chand->cancel_status =
+      grpc_mdelem_from_strings(metadata_context, "grpc-status", temp);
+}
+
+/* Destructor for channel_data */
+static void destroy_channel_elem(grpc_channel_element *elem) {
+  channel_data *chand = elem->channel_data;
+  size_t i;
+
+  grpc_transport_setup_cancel(chand->transport_setup);
+
+  for (i = 0; i < chand->child_count; i++) {
+    GPR_ASSERT(chand->children[i].inflight_requests == 0);
+    grpc_channel_stack_destroy(chand->children[i].channel_stack);
+    gpr_free(chand->children[i].channel_stack);
+  }
+
+  grpc_channel_args_destroy(chand->args);
+  grpc_mdelem_unref(chand->cancel_status);
+
+  gpr_mu_destroy(&chand->mu);
+  GPR_ASSERT(chand->waiting_child_count == 0);
+  gpr_free(chand->waiting_children);
+  gpr_free(chand->children);
+}
+
+const grpc_channel_filter grpc_client_channel_filter = {
+    call_op,              channel_op,
+
+    sizeof(call_data),    init_call_elem,    destroy_call_elem,
+
+    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
+
+    "clientchannel",
+};
+
+grpc_transport_setup_result grpc_client_channel_transport_setup_complete(
+    grpc_channel_stack *channel_stack, grpc_transport *transport,
+    grpc_channel_filter const **channel_filters, size_t num_channel_filters,
+    grpc_mdctx *mdctx) {
+  /* we just got a new transport: lets create a child channel stack for it */
+  grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
+  channel_data *chand = elem->channel_data;
+  grpc_channel_element *lb_elem;
+  grpc_channel_stack *child_stack;
+  size_t num_child_filters = 2 + num_channel_filters;
+  grpc_channel_filter const **child_filters;
+  grpc_transport_setup_result result;
+  child_entry *child_ent;
+  call_data **waiting_children;
+  size_t waiting_child_count;
+  size_t i;
+  grpc_call_op *call_ops;
+
+  /* build the child filter stack */
+  child_filters = gpr_malloc(sizeof(grpc_channel_filter *) * num_child_filters);
+  /* we always need a link back filter to get back to the connected channel */
+  child_filters[0] = &link_back_filter;
+  for (i = 0; i < num_channel_filters; i++) {
+    child_filters[i + 1] = channel_filters[i];
+  }
+  /* and we always need a connected channel to talk to the transport */
+  child_filters[num_child_filters - 1] = &grpc_connected_channel_filter;
+
+  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
+
+  /* BEGIN LOCKING CHANNEL */
+  gpr_mu_lock(&chand->mu);
+  chand->transport_setup_initiated = 0;
+
+  if (chand->child_count == chand->child_capacity) {
+    /* realloc will invalidate chand->active_child, but it's reset in the next
+       stanza anyway */
+    chand->child_capacity =
+        GPR_MAX(2 * chand->child_capacity, chand->child_capacity + 2);
+    chand->children = gpr_realloc(chand->children,
+                                  sizeof(child_entry) * chand->child_capacity);
+  }
+
+  /* build up the child stack */
+  child_stack =
+      gpr_malloc(grpc_channel_stack_size(child_filters, num_child_filters));
+  grpc_channel_stack_init(child_filters, num_child_filters, chand->args, mdctx,
+                          child_stack);
+  lb_elem = grpc_channel_stack_element(child_stack, 0);
+  GPR_ASSERT(lb_elem->filter == &link_back_filter);
+  ((lb_channel_data *)lb_elem->channel_data)->back = elem;
+  result = grpc_connected_channel_bind_transport(child_stack, transport);
+  child_ent = &chand->children[chand->child_count++];
+  child_ent->channel_stack = child_stack;
+  child_ent->inflight_requests = 0;
+  chand->active_child = child_ent;
+
+  /* capture the waiting children - we'll activate them outside the lock
+     to avoid re-entrancy problems */
+  waiting_children = chand->waiting_children;
+  waiting_child_count = chand->waiting_child_count;
+  /* bumping up inflight_requests here avoids taking a lock per rpc below */
+
+  chand->waiting_children = NULL;
+  chand->waiting_child_count = 0;
+  chand->waiting_child_capacity = 0;
+
+  call_ops = gpr_malloc(sizeof(grpc_call_op) * waiting_child_count);
+
+  for (i = 0; i < waiting_child_count; i++) {
+    call_ops[i].type = GRPC_SEND_START;
+    call_ops[i].dir = GRPC_CALL_DOWN;
+    call_ops[i].flags = waiting_children[i]->s.waiting.start_flags;
+    call_ops[i].done_cb = waiting_children[i]->s.waiting.on_complete;
+    call_ops[i].user_data =
+        waiting_children[i]->s.waiting.on_complete_user_data;
+    if (!prepare_activate(waiting_children[i], child_ent)) {
+      waiting_children[i] = NULL;
+      call_ops[i].done_cb(call_ops[i].user_data, GRPC_OP_ERROR);
+    }
+  }
+
+  /* END LOCKING CHANNEL */
+  gpr_mu_unlock(&chand->mu);
+
+  /* activate any pending operations - this is safe to do as we guarantee one
+     and only one write operation per request at the surface api - if we lose
+     that guarantee we need to do some curly locking here */
+  for (i = 0; i < waiting_child_count; i++) {
+    if (waiting_children[i]) {
+      complete_activate(waiting_children[i], child_ent, &call_ops[i]);
+    }
+  }
+  gpr_free(waiting_children);
+  gpr_free(call_ops);
+  gpr_free(child_filters);
+
+  return result;
+}
+
+void grpc_client_channel_set_transport_setup(grpc_channel_stack *channel_stack,
+                                             grpc_transport_setup *setup) {
+  /* post construction initialization: set the transport setup pointer */
+  grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
+  channel_data *chand = elem->channel_data;
+  GPR_ASSERT(!chand->transport_setup);
+  chand->transport_setup = setup;
+}
diff --git a/src/core/channel/client_channel.h b/src/core/channel/client_channel.h
new file mode 100644
index 0000000..576af64
--- /dev/null
+++ b/src/core/channel/client_channel.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_CHANNEL_CLIENT_CHANNEL_H__
+#define __GRPC_INTERNAL_CHANNEL_CLIENT_CHANNEL_H__
+
+#include "src/core/channel/channel_stack.h"
+
+/* A client channel is a channel that begins disconnected, and can connect
+   to some endpoint on demand. If that endpoint disconnects, it will be
+   connected to again later.
+
+   Calls on a disconnected client channel are queued until a connection is
+   established. */
+
+extern const grpc_channel_filter grpc_client_channel_filter;
+
+/* post-construction initializer to let the client channel know which
+   transport setup it should cancel upon destruction, or initiate when it needs
+   a connection */
+void grpc_client_channel_set_transport_setup(grpc_channel_stack *channel_stack,
+                                             grpc_transport_setup *setup);
+
+/* grpc_transport_setup_callback for binding new transports into a client
+   channel - user_data should be the channel stack containing the client
+   channel */
+grpc_transport_setup_result grpc_client_channel_transport_setup_complete(
+    grpc_channel_stack *channel_stack, grpc_transport *transport,
+    grpc_channel_filter const **channel_filters, size_t num_channel_filters,
+    grpc_mdctx *mdctx);
+
+#endif  /* __GRPC_INTERNAL_CHANNEL_CLIENT_CHANNEL_H__ */
diff --git a/src/core/channel/client_setup.c b/src/core/channel/client_setup.c
new file mode 100644
index 0000000..c667e39
--- /dev/null
+++ b/src/core/channel/client_setup.c
@@ -0,0 +1,239 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/channel/client_setup.h"
+#include "src/core/channel/channel_args.h"
+#include "src/core/channel/channel_stack.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+
+struct grpc_client_setup {
+  grpc_transport_setup base; /* must be first */
+  void (*initiate)(void *user_data, grpc_client_setup_request *request);
+  void (*done)(void *user_data);
+  void *user_data;
+  grpc_channel_args *args;
+  grpc_mdctx *mdctx;
+  grpc_em *em;
+  grpc_em_alarm backoff_alarm;
+  gpr_timespec current_backoff_interval;
+  int in_alarm;
+
+  gpr_mu mu;
+  grpc_client_setup_request *active_request;
+  int refs;
+};
+
+struct grpc_client_setup_request {
+  /* pointer back to the setup object */
+  grpc_client_setup *setup;
+  gpr_timespec deadline;
+};
+
+gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r) {
+  return r->deadline;
+}
+
+static void destroy_setup(grpc_client_setup *s) {
+  gpr_mu_destroy(&s->mu);
+  s->done(s->user_data);
+  grpc_channel_args_destroy(s->args);
+  gpr_free(s);
+}
+
+/* initiate handshaking */
+static void setup_initiate(grpc_transport_setup *sp) {
+  grpc_client_setup *s = (grpc_client_setup *)sp;
+  grpc_client_setup_request *r = gpr_malloc(sizeof(grpc_client_setup_request));
+  int in_alarm = 0;
+
+  r->setup = s;
+  /* TODO(klempner): Actually set a deadline */
+  r->deadline = gpr_inf_future;
+
+  gpr_mu_lock(&s->mu);
+  GPR_ASSERT(s->refs > 0);
+  /* there might be more than one request outstanding if the caller calls
+     initiate in some kind of rapid-fire way: we try to connect each time,
+     and keep track of the latest request (which is the only one that gets
+     to finish) */
+  if (!s->in_alarm) {
+    s->active_request = r;
+    s->refs++;
+  } else {
+    /* TODO(klempner): Maybe do something more clever here */
+    in_alarm = 1;
+  }
+  gpr_mu_unlock(&s->mu);
+
+  if (!in_alarm) {
+    s->initiate(s->user_data, r);
+  } else {
+    gpr_free(r);
+  }
+}
+
+/* cancel handshaking: cancel all requests, and shutdown (the caller promises
+   not to initiate again) */
+static void setup_cancel(grpc_transport_setup *sp) {
+  grpc_client_setup *s = (grpc_client_setup *)sp;
+  void *ignored;
+
+  gpr_mu_lock(&s->mu);
+
+  GPR_ASSERT(s->refs > 0);
+  /* effectively cancels the current request (if any) */
+  s->active_request = NULL;
+  if (s->in_alarm) {
+    grpc_em_alarm_cancel(&s->backoff_alarm, &ignored);
+  }
+  if (--s->refs == 0) {
+    gpr_mu_unlock(&s->mu);
+    destroy_setup(s);
+  } else {
+    gpr_mu_unlock(&s->mu);
+  }
+}
+
+/* vtable for transport setup */
+static const grpc_transport_setup_vtable setup_vtable = {setup_initiate,
+                                                         setup_cancel};
+
+void grpc_client_setup_create_and_attach(
+    grpc_channel_stack *newly_minted_channel, const grpc_channel_args *args,
+    grpc_mdctx *mdctx,
+    void (*initiate)(void *user_data, grpc_client_setup_request *request),
+    void (*done)(void *user_data), void *user_data, grpc_em *em) {
+  grpc_client_setup *s = gpr_malloc(sizeof(grpc_client_setup));
+
+  s->base.vtable = &setup_vtable;
+  gpr_mu_init(&s->mu);
+  s->refs = 1;
+  s->mdctx = mdctx;
+  s->initiate = initiate;
+  s->done = done;
+  s->user_data = user_data;
+  s->em = em;
+  s->active_request = NULL;
+  s->args = grpc_channel_args_copy(args);
+  s->current_backoff_interval = gpr_time_from_micros(1000000);
+  s->in_alarm = 0;
+
+  grpc_client_channel_set_transport_setup(newly_minted_channel, &s->base);
+}
+
+int grpc_client_setup_request_should_continue(grpc_client_setup_request *r) {
+  int result;
+  if (gpr_time_cmp(gpr_now(), r->deadline) > 0) {
+    return 0;
+  }
+  gpr_mu_lock(&r->setup->mu);
+  result = r->setup->active_request == r;
+  gpr_mu_unlock(&r->setup->mu);
+  return result;
+}
+
+static void backoff_alarm_done(void *arg /* grpc_client_setup */,
+                               grpc_em_cb_status status) {
+  grpc_client_setup *s = arg;
+  grpc_client_setup_request *r = gpr_malloc(sizeof(grpc_client_setup_request));
+  r->setup = s;
+  /* TODO(klempner): Set this to something useful */
+  r->deadline = gpr_inf_future;
+  /* Handle status cancelled? */
+  gpr_mu_lock(&s->mu);
+  s->active_request = r;
+  s->in_alarm = 0;
+  if (status != GRPC_CALLBACK_SUCCESS) {
+    if (0 == --s->refs) {
+      gpr_mu_unlock(&s->mu);
+      destroy_setup(s);
+      gpr_free(r);
+      return;
+    } else {
+      gpr_mu_unlock(&s->mu);
+      return;
+    }
+  }
+  gpr_mu_unlock(&s->mu);
+  s->initiate(s->user_data, r);
+}
+
+void grpc_client_setup_request_finish(grpc_client_setup_request *r,
+                                      int was_successful) {
+  int retry = !was_successful;
+  grpc_client_setup *s = r->setup;
+
+  gpr_mu_lock(&s->mu);
+  if (s->active_request == r) {
+    s->active_request = NULL;
+  } else {
+    retry = 0;
+  }
+  if (!retry && 0 == --s->refs) {
+    gpr_mu_unlock(&s->mu);
+    destroy_setup(s);
+    gpr_free(r);
+    return;
+  }
+
+  gpr_free(r);
+
+  if (retry) {
+    /* TODO(klempner): Replace these values with further consideration. 2x is
+       probably too aggressive of a backoff. */
+    gpr_timespec max_backoff = gpr_time_from_micros(120000000);
+    GPR_ASSERT(!s->in_alarm);
+    s->in_alarm = 1;
+    grpc_em_alarm_init(&s->backoff_alarm, s->em, backoff_alarm_done, s);
+    grpc_em_alarm_add(&s->backoff_alarm,
+                      gpr_time_add(s->current_backoff_interval, gpr_now()));
+    s->current_backoff_interval =
+        gpr_time_add(s->current_backoff_interval, s->current_backoff_interval);
+    if (gpr_time_cmp(s->current_backoff_interval, max_backoff) > 0) {
+      s->current_backoff_interval = max_backoff;
+    }
+  }
+
+  gpr_mu_unlock(&s->mu);
+}
+
+const grpc_channel_args *grpc_client_setup_get_channel_args(
+    grpc_client_setup_request *r) {
+  return r->setup->args;
+}
+
+grpc_mdctx *grpc_client_setup_get_mdctx(grpc_client_setup_request *r) {
+  return r->setup->mdctx;
+}
diff --git a/src/core/channel/client_setup.h b/src/core/channel/client_setup.h
new file mode 100644
index 0000000..862c132
--- /dev/null
+++ b/src/core/channel/client_setup.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_CHANNEL_CLIENT_SETUP_H__
+#define __GRPC_INTERNAL_CHANNEL_CLIENT_SETUP_H__
+
+#include "src/core/channel/client_channel.h"
+#include "src/core/eventmanager/em.h"
+#include "src/core/transport/metadata.h"
+#include <grpc/support/time.h>
+
+/* Convenience API's to simplify transport setup */
+
+typedef struct grpc_client_setup grpc_client_setup;
+typedef struct grpc_client_setup_request grpc_client_setup_request;
+
+void grpc_client_setup_create_and_attach(
+    grpc_channel_stack *newly_minted_channel, const grpc_channel_args *args,
+    grpc_mdctx *mdctx,
+    void (*initiate)(void *user_data, grpc_client_setup_request *request),
+    void (*done)(void *user_data), void *user_data, grpc_em *em);
+
+/* Check that r is the active request: needs to be performed at each callback.
+   If this races, we'll have two connection attempts running at once and the
+   old one will get cleaned up in due course, which is fine. */
+int grpc_client_setup_request_should_continue(grpc_client_setup_request *r);
+void grpc_client_setup_request_finish(grpc_client_setup_request *r,
+                                      int was_successful);
+const grpc_channel_args *grpc_client_setup_get_channel_args(
+    grpc_client_setup_request *r);
+
+/* Get the deadline for a request passed in to initiate. Implementations should
+   make a best effort to honor this deadline. */
+gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r);
+
+grpc_mdctx *grpc_client_setup_get_mdctx(grpc_client_setup_request *r);
+
+#endif  /* __GRPC_INTERNAL_CHANNEL_CLIENT_SETUP_H__ */
diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c
new file mode 100644
index 0000000..336472e
--- /dev/null
+++ b/src/core/channel/connected_channel.c
@@ -0,0 +1,501 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/channel/connected_channel.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "src/core/transport/transport.h"
+#include <grpc/byte_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/support/string.h>
+
+#define MAX_BUFFER_LENGTH 8192
+/* the protobuf library will (by default) start warning at 100megs */
+#define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024)
+
+typedef struct {
+  grpc_transport *transport;
+  gpr_uint32 max_message_length;
+} channel_data;
+
+typedef struct {
+  grpc_call_element *elem;
+  grpc_stream_op_buffer outgoing_sopb;
+
+  gpr_uint32 max_message_length;
+  gpr_uint32 incoming_message_length;
+  gpr_uint8 reading_message;
+  gpr_uint8 got_metadata_boundary;
+  gpr_uint8 got_read_close;
+  gpr_slice_buffer incoming_message;
+  gpr_uint32 outgoing_buffer_length_estimate;
+} call_data;
+
+/* We perform a small hack to locate transport data alongside the connected
+   channel data in call allocations, to allow everything to be pulled in minimal
+   cache line requests */
+#define TRANSPORT_STREAM_FROM_CALL_DATA(calld) ((grpc_stream *)((calld)+1))
+#define CALL_DATA_FROM_TRANSPORT_STREAM(transport_stream) \
+  (((call_data *)(transport_stream)) - 1)
+
+/* Copy the contents of a byte buffer into stream ops */
+static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer,
+                                           grpc_stream_op_buffer *sopb) {
+  size_t i;
+
+  switch (byte_buffer->type) {
+    case GRPC_BB_SLICE_BUFFER:
+      for (i = 0; i < byte_buffer->data.slice_buffer.count; i++) {
+        gpr_slice slice = byte_buffer->data.slice_buffer.slices[i];
+        gpr_slice_ref(slice);
+        grpc_sopb_add_slice(sopb, slice);
+      }
+      break;
+  }
+}
+
+/* Flush queued stream operations onto the transport */
+static void end_bufferable_op(grpc_call_op *op, channel_data *chand,
+                              call_data *calld, int is_last) {
+  size_t nops;
+
+  if (op->flags & GRPC_WRITE_BUFFER_HINT) {
+    if (calld->outgoing_buffer_length_estimate < MAX_BUFFER_LENGTH) {
+      op->done_cb(op->user_data, GRPC_OP_OK);
+      return;
+    }
+  }
+
+  calld->outgoing_buffer_length_estimate = 0;
+  grpc_sopb_add_flow_ctl_cb(&calld->outgoing_sopb, op->done_cb, op->user_data);
+
+  nops = calld->outgoing_sopb.nops;
+  calld->outgoing_sopb.nops = 0;
+  grpc_transport_send_batch(chand->transport,
+                            TRANSPORT_STREAM_FROM_CALL_DATA(calld),
+                            calld->outgoing_sopb.ops, nops, is_last);
+}
+
+/* Intercept a call operation and either push it directly up or translate it
+   into transport stream operations */
+static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
+  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+
+  switch (op->type) {
+    case GRPC_SEND_METADATA:
+      grpc_sopb_add_metadata(&calld->outgoing_sopb, op->data.metadata);
+      grpc_sopb_add_flow_ctl_cb(&calld->outgoing_sopb, op->done_cb,
+                                op->user_data);
+      break;
+    case GRPC_SEND_DEADLINE:
+      grpc_sopb_add_deadline(&calld->outgoing_sopb, op->data.deadline);
+      grpc_sopb_add_flow_ctl_cb(&calld->outgoing_sopb, op->done_cb,
+                                op->user_data);
+      break;
+    case GRPC_SEND_START:
+      grpc_sopb_add_metadata_boundary(&calld->outgoing_sopb);
+      end_bufferable_op(op, chand, calld, 0);
+      break;
+    case GRPC_SEND_MESSAGE:
+      grpc_sopb_add_begin_message(&calld->outgoing_sopb,
+                                  grpc_byte_buffer_length(op->data.message),
+                                  op->flags);
+      copy_byte_buffer_to_stream_ops(op->data.message, &calld->outgoing_sopb);
+      calld->outgoing_buffer_length_estimate +=
+          (5 + grpc_byte_buffer_length(op->data.message));
+      end_bufferable_op(op, chand, calld, 0);
+      break;
+    case GRPC_SEND_FINISH:
+      end_bufferable_op(op, chand, calld, 1);
+      break;
+    case GRPC_REQUEST_DATA:
+      /* re-arm window updates if they were disarmed by finish_message */
+      grpc_transport_set_allow_window_updates(
+          chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), 1);
+      break;
+    case GRPC_CANCEL_OP:
+      grpc_transport_abort_stream(chand->transport,
+                                  TRANSPORT_STREAM_FROM_CALL_DATA(calld),
+                                  GRPC_STATUS_CANCELLED);
+      break;
+    default:
+      GPR_ASSERT(op->dir == GRPC_CALL_UP);
+      grpc_call_next_op(elem, op);
+      break;
+  }
+}
+
+/* Currently we assume all channel operations should just be pushed up. */
+static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+  channel_data *chand = elem->channel_data;
+  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
+
+  switch (op->type) {
+    case GRPC_CHANNEL_SHUTDOWN:
+      grpc_transport_close(chand->transport);
+      break;
+    default:
+      GPR_ASSERT(op->dir == GRPC_CALL_UP);
+      grpc_channel_next_op(elem, op);
+      break;
+  }
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_call_element *elem,
+                           const void *server_transport_data) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  int r;
+
+  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
+  calld->elem = elem;
+  grpc_sopb_init(&calld->outgoing_sopb);
+
+  calld->reading_message = 0;
+  calld->got_metadata_boundary = 0;
+  calld->got_read_close = 0;
+  calld->outgoing_buffer_length_estimate = 0;
+  calld->max_message_length = chand->max_message_length;
+  gpr_slice_buffer_init(&calld->incoming_message);
+  r = grpc_transport_init_stream(chand->transport,
+                                 TRANSPORT_STREAM_FROM_CALL_DATA(calld),
+                                 server_transport_data);
+  GPR_ASSERT(r == 0);
+}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_call_element *elem) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
+  grpc_sopb_destroy(&calld->outgoing_sopb);
+  gpr_slice_buffer_destroy(&calld->incoming_message);
+  grpc_transport_destroy_stream(chand->transport,
+                                TRANSPORT_STREAM_FROM_CALL_DATA(calld));
+}
+
+/* Constructor for channel_data */
+static void init_channel_elem(grpc_channel_element *elem,
+                              const grpc_channel_args *args, grpc_mdctx *mdctx,
+                              int is_first, int is_last) {
+  channel_data *cd = (channel_data *)elem->channel_data;
+  size_t i;
+  GPR_ASSERT(!is_first);
+  GPR_ASSERT(is_last);
+  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
+  cd->transport = NULL;
+
+  cd->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH;
+  if (args) {
+    for (i = 0; i < args->num_args; i++) {
+      if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) {
+        if (args->args[i].type != GRPC_ARG_INTEGER) {
+          gpr_log(GPR_ERROR, "%s ignored: it must be an integer",
+                  GRPC_ARG_MAX_MESSAGE_LENGTH);
+        } else if (args->args[i].value.integer < 0) {
+          gpr_log(GPR_ERROR, "%s ignored: it must be >= 0",
+                  GRPC_ARG_MAX_MESSAGE_LENGTH);
+        } else {
+          cd->max_message_length = args->args[i].value.integer;
+        }
+      }
+    }
+  }
+}
+
+/* Destructor for channel_data */
+static void destroy_channel_elem(grpc_channel_element *elem) {
+  channel_data *cd = (channel_data *)elem->channel_data;
+  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
+  grpc_transport_destroy(cd->transport);
+}
+
+const grpc_channel_filter grpc_connected_channel_filter = {
+    call_op,              channel_op,
+
+    sizeof(call_data),    init_call_elem,    destroy_call_elem,
+
+    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
+
+    "connected",
+};
+
+static gpr_slice alloc_recv_buffer(void *user_data, grpc_transport *transport,
+                                   grpc_stream *stream, size_t size_hint) {
+  return gpr_slice_malloc(size_hint);
+}
+
+/* Transport callback to accept a new stream... calls up to handle it */
+static void accept_stream(void *user_data, grpc_transport *transport,
+                          const void *transport_server_data) {
+  grpc_channel_element *elem = user_data;
+  channel_data *chand = elem->channel_data;
+  grpc_channel_op op;
+
+  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
+  GPR_ASSERT(chand->transport == transport);
+
+  op.type = GRPC_ACCEPT_CALL;
+  op.dir = GRPC_CALL_UP;
+  op.data.accept_call.transport = transport;
+  op.data.accept_call.transport_server_data = transport_server_data;
+  channel_op(elem, &op);
+}
+
+static void recv_error(channel_data *chand, call_data *calld, int line,
+                       const char *fmt, ...) {
+  char msg[512];
+  va_list a;
+
+  va_start(a, fmt);
+  vsprintf(msg, fmt, a);
+  va_end(a);
+
+  gpr_log(__FILE__, line, GPR_LOG_SEVERITY_ERROR, "%s", msg);
+
+  if (chand->transport) {
+    grpc_transport_abort_stream(chand->transport,
+                                TRANSPORT_STREAM_FROM_CALL_DATA(calld),
+                                GRPC_STATUS_INVALID_ARGUMENT);
+  }
+}
+
+static void do_nothing(void *calldata, grpc_op_error error) {}
+
+static void done_message(void *user_data, grpc_op_error error) {
+  grpc_byte_buffer_destroy(user_data);
+}
+
+static void finish_message(channel_data *chand, call_data *calld) {
+  grpc_call_element *elem = calld->elem;
+  grpc_call_op call_op;
+  call_op.dir = GRPC_CALL_UP;
+  call_op.flags = 0;
+  /* if we got all the bytes for this message, call up the stack */
+  call_op.type = GRPC_RECV_MESSAGE;
+  call_op.done_cb = done_message;
+  /* TODO(ctiller): this could be a lot faster if coded directly */
+  call_op.user_data = call_op.data.message = grpc_byte_buffer_create(
+      calld->incoming_message.slices, calld->incoming_message.count);
+  gpr_slice_buffer_reset_and_unref(&calld->incoming_message);
+
+  /* disable window updates until we get a request more from above */
+  grpc_transport_set_allow_window_updates(
+      chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), 0);
+
+  GPR_ASSERT(calld->incoming_message.count == 0);
+  calld->reading_message = 0;
+  grpc_call_next_op(elem, &call_op);
+}
+
+/* Handle incoming stream ops from the transport, translating them into
+   call_ops to pass up the call stack */
+static void recv_batch(void *user_data, grpc_transport *transport,
+                       grpc_stream *stream, grpc_stream_op *ops,
+                       size_t ops_count, grpc_stream_state final_state) {
+  call_data *calld = CALL_DATA_FROM_TRANSPORT_STREAM(stream);
+  grpc_call_element *elem = calld->elem;
+  channel_data *chand = elem->channel_data;
+  grpc_stream_op *stream_op;
+  grpc_call_op call_op;
+  size_t i;
+  gpr_uint32 length;
+
+  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
+
+  for (i = 0; i < ops_count; i++) {
+    stream_op = ops + i;
+    switch (stream_op->type) {
+      case GRPC_OP_FLOW_CTL_CB:
+        gpr_log(GPR_ERROR,
+                "should not receive flow control ops from transport");
+        abort();
+        break;
+      case GRPC_NO_OP:
+        break;
+      case GRPC_OP_METADATA:
+        call_op.type = GRPC_RECV_METADATA;
+        call_op.dir = GRPC_CALL_UP;
+        call_op.flags = 0;
+        call_op.data.metadata = stream_op->data.metadata;
+        call_op.done_cb = do_nothing;
+        call_op.user_data = NULL;
+        grpc_call_next_op(elem, &call_op);
+        break;
+      case GRPC_OP_DEADLINE:
+        call_op.type = GRPC_RECV_DEADLINE;
+        call_op.dir = GRPC_CALL_UP;
+        call_op.flags = 0;
+        call_op.data.deadline = stream_op->data.deadline;
+        call_op.done_cb = do_nothing;
+        call_op.user_data = NULL;
+        grpc_call_next_op(elem, &call_op);
+        break;
+      case GRPC_OP_METADATA_BOUNDARY:
+        if (!calld->got_metadata_boundary) {
+          calld->got_metadata_boundary = 1;
+          call_op.type = GRPC_RECV_END_OF_INITIAL_METADATA;
+          call_op.dir = GRPC_CALL_UP;
+          call_op.flags = 0;
+          call_op.done_cb = do_nothing;
+          call_op.user_data = NULL;
+          grpc_call_next_op(elem, &call_op);
+        }
+        break;
+      case GRPC_OP_BEGIN_MESSAGE:
+        /* can't begin a message when we're still reading a message */
+        if (calld->reading_message) {
+          recv_error(chand, calld, __LINE__,
+                     "Message terminated early; read %d bytes, expected %d",
+                     calld->incoming_message.length,
+                     calld->incoming_message_length);
+          return;
+        }
+        /* stash away parameters, and prepare for incoming slices */
+        length = stream_op->data.begin_message.length;
+        if (length > calld->max_message_length) {
+          recv_error(
+              chand, calld, __LINE__,
+              "Maximum message length of %d exceeded by a message of length %d",
+              calld->max_message_length, length);
+        } else if (length > 0) {
+          calld->reading_message = 1;
+          calld->incoming_message_length = length;
+        } else {
+          finish_message(chand, calld);
+        }
+        break;
+      case GRPC_OP_SLICE:
+        if (GPR_SLICE_LENGTH(stream_op->data.slice) == 0) {
+          gpr_slice_unref(stream_op->data.slice);
+          break;
+        }
+        /* we have to be reading a message to know what to do here */
+        if (!calld->reading_message) {
+          recv_error(chand, calld, __LINE__,
+                     "Received payload data while not reading a message");
+          return;
+        }
+        /* append the slice to the incoming buffer */
+        gpr_slice_buffer_add(&calld->incoming_message, stream_op->data.slice);
+        if (calld->incoming_message.length > calld->incoming_message_length) {
+          /* if we got too many bytes, complain */
+          recv_error(chand, calld, __LINE__,
+                     "Receiving message overflow; read %d bytes, expected %d",
+                     calld->incoming_message.length,
+                     calld->incoming_message_length);
+          return;
+        } else if (calld->incoming_message.length ==
+                   calld->incoming_message_length) {
+          finish_message(chand, calld);
+        }
+    }
+  }
+  /* if the stream closed, then call up the stack to let it know */
+  if (!calld->got_read_close && (final_state == GRPC_STREAM_RECV_CLOSED ||
+                                 final_state == GRPC_STREAM_CLOSED)) {
+    calld->got_read_close = 1;
+    if (calld->reading_message) {
+      recv_error(chand, calld, __LINE__,
+                 "Last message truncated; read %d bytes, expected %d",
+                 calld->incoming_message.length,
+                 calld->incoming_message_length);
+      return;
+    }
+    call_op.type = GRPC_RECV_HALF_CLOSE;
+    call_op.dir = GRPC_CALL_UP;
+    call_op.flags = 0;
+    call_op.done_cb = do_nothing;
+    call_op.user_data = NULL;
+    grpc_call_next_op(elem, &call_op);
+  }
+  if (final_state == GRPC_STREAM_CLOSED) {
+    call_op.type = GRPC_RECV_FINISH;
+    call_op.dir = GRPC_CALL_UP;
+    call_op.flags = 0;
+    call_op.done_cb = do_nothing;
+    call_op.user_data = NULL;
+    grpc_call_next_op(elem, &call_op);
+  }
+}
+
+static void transport_closed(void *user_data, grpc_transport *transport) {
+  /* transport was closed ==> call up and handle it */
+  grpc_channel_element *elem = user_data;
+  channel_data *chand = elem->channel_data;
+  grpc_channel_op op;
+
+  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
+  GPR_ASSERT(chand->transport == transport);
+
+  op.type = GRPC_TRANSPORT_CLOSED;
+  op.dir = GRPC_CALL_UP;
+  channel_op(elem, &op);
+}
+
+const grpc_transport_callbacks connected_channel_transport_callbacks = {
+    alloc_recv_buffer, accept_stream, recv_batch, transport_closed,
+};
+
+grpc_transport_setup_result grpc_connected_channel_bind_transport(
+    grpc_channel_stack *channel_stack, grpc_transport *transport) {
+  /* Assumes that the connected channel filter is always the last filter
+     in a channel stack */
+  grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
+  channel_data *cd = (channel_data *)elem->channel_data;
+  grpc_transport_setup_result ret;
+  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
+  GPR_ASSERT(cd->transport == NULL);
+  cd->transport = transport;
+
+  /* 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,
+     and I'm not sure what that is yet.
+     This is only "safe" because call stacks place no additional data after
+     the last call element, and the last call element MUST be the connected
+     channel. */
+  channel_stack->call_stack_size += grpc_transport_stream_size(transport);
+
+  ret.user_data = elem;
+  ret.callbacks = &connected_channel_transport_callbacks;
+  return ret;
+}
diff --git a/src/core/channel/connected_channel.h b/src/core/channel/connected_channel.h
new file mode 100644
index 0000000..660ea7a
--- /dev/null
+++ b/src/core/channel/connected_channel.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_CHANNEL_CONNECTED_CHANNEL_H__
+#define __GRPC_INTERNAL_CHANNEL_CONNECTED_CHANNEL_H__
+
+#include "src/core/channel/channel_stack.h"
+
+/* A channel filter representing a channel that is on a connected transport.
+   This filter performs actual sending and receiving of messages. */
+
+extern const grpc_channel_filter grpc_connected_channel_filter;
+
+/* Post construction fixup: set the transport in the connected channel.
+   Must be called before any call stack using this filter is used. */
+grpc_transport_setup_result grpc_connected_channel_bind_transport(
+    grpc_channel_stack *channel_stack, grpc_transport *transport);
+
+#endif  /* __GRPC_INTERNAL_CHANNEL_CONNECTED_CHANNEL_H__ */
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
new file mode 100644
index 0000000..b82c735
--- /dev/null
+++ b/src/core/channel/http_client_filter.c
@@ -0,0 +1,143 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/channel/http_client_filter.h"
+#include <grpc/support/log.h>
+
+typedef struct call_data {
+  int unused; /* C89 requires at least one struct element */
+} call_data;
+
+typedef struct channel_data { grpc_mdelem *te_trailers; } channel_data;
+
+/* used to silence 'variable not used' warnings */
+static void ignore_unused(void *ignored) {}
+
+/* Called either:
+     - in response to an API call (or similar) from above, to send something
+     - a network event (or similar) from below, to receive something
+   op contains type and call direction information, in addition to the data
+   that is being sent or received. */
+static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+
+  ignore_unused(calld);
+
+  switch (op->type) {
+    case GRPC_SEND_START:
+      /* just prior to starting, add a te: trailers header */
+      grpc_call_element_send_metadata(elem, channeld->te_trailers);
+      grpc_call_next_op(elem, op);
+      break;
+    default:
+      /* pass control up or down the stack depending on op->dir */
+      grpc_call_next_op(elem, op);
+      break;
+  }
+}
+
+/* Called on special channel events, such as disconnection or new incoming
+   calls on the server */
+static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+  /* grab pointers to our data from the channel element */
+  channel_data *channeld = elem->channel_data;
+
+  ignore_unused(channeld);
+
+  switch (op->type) {
+    default:
+      /* pass control up or down the stack depending on op->dir */
+      grpc_channel_next_op(elem, op);
+      break;
+  }
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_call_element *elem,
+                           const void *server_transport_data) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+
+  ignore_unused(channeld);
+
+  /* initialize members */
+  calld->unused = 0;
+}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_call_element *elem) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+
+  ignore_unused(calld);
+  ignore_unused(channeld);
+}
+
+/* Constructor for channel_data */
+static void init_channel_elem(grpc_channel_element *elem,
+                              const grpc_channel_args *args, grpc_mdctx *mdctx,
+                              int is_first, int is_last) {
+  /* grab pointers to our data from the channel element */
+  channel_data *channeld = 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
+     path */
+  GPR_ASSERT(!is_first);
+  GPR_ASSERT(!is_last);
+
+  /* initialize members */
+  channeld->te_trailers = grpc_mdelem_from_strings(mdctx, "te", "trailers");
+}
+
+/* Destructor for channel data */
+static void destroy_channel_elem(grpc_channel_element *elem) {
+  /* grab pointers to our data from the channel element */
+  channel_data *channeld = elem->channel_data;
+
+  grpc_mdelem_unref(channeld->te_trailers);
+}
+
+const grpc_channel_filter grpc_http_client_filter = {
+    call_op, channel_op,
+
+    sizeof(call_data), init_call_elem, destroy_call_elem,
+
+    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
+
+    "http-client"};
diff --git a/src/core/channel/http_client_filter.h b/src/core/channel/http_client_filter.h
new file mode 100644
index 0000000..f939cbd
--- /dev/null
+++ b/src/core/channel/http_client_filter.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_CHANNEL_HTTP_CLIENT_FILTER_H__
+#define __GRPC_INTERNAL_CHANNEL_HTTP_CLIENT_FILTER_H__
+
+#include "src/core/channel/channel_stack.h"
+
+/* Processes metadata on the client side for HTTP2 transports */
+extern const grpc_channel_filter grpc_http_client_filter;
+
+#endif /* __GRPC_INTERNAL_CHANNEL_HTTP_CLIENT_FILTER_H__ */
diff --git a/src/core/channel/http_filter.c b/src/core/channel/http_filter.c
new file mode 100644
index 0000000..b5c1541
--- /dev/null
+++ b/src/core/channel/http_filter.c
@@ -0,0 +1,139 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/channel/http_filter.h"
+#include <grpc/support/log.h>
+
+typedef struct call_data {
+  int unused; /* C89 requires at least one struct element */
+} call_data;
+
+typedef struct channel_data {
+  int unused; /* C89 requires at least one struct element */
+} channel_data;
+
+/* used to silence 'variable not used' warnings */
+static void ignore_unused(void *ignored) {}
+
+/* Called either:
+     - in response to an API call (or similar) from above, to send something
+     - a network event (or similar) from below, to receive something
+   op contains type and call direction information, in addition to the data
+   that is being sent or received. */
+static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+
+  ignore_unused(calld);
+  ignore_unused(channeld);
+
+  switch (op->type) {
+    default:
+      /* pass control up or down the stack depending on op->dir */
+      grpc_call_next_op(elem, op);
+      break;
+  }
+}
+
+/* Called on special channel events, such as disconnection or new incoming
+   calls on the server */
+static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+  /* grab pointers to our data from the channel element */
+  channel_data *channeld = elem->channel_data;
+
+  ignore_unused(channeld);
+
+  switch (op->type) {
+    default:
+      /* pass control up or down the stack depending on op->dir */
+      grpc_channel_next_op(elem, op);
+      break;
+  }
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_call_element *elem,
+                           const void *server_transport_data) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+
+  /* initialize members */
+  calld->unused = channeld->unused;
+}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_call_element *elem) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+
+  ignore_unused(calld);
+  ignore_unused(channeld);
+}
+
+/* Constructor for channel_data */
+static void init_channel_elem(grpc_channel_element *elem,
+                              const grpc_channel_args *args, grpc_mdctx *mdctx,
+                              int is_first, int is_last) {
+  /* grab pointers to our data from the channel element */
+  channel_data *channeld = 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
+     path */
+  GPR_ASSERT(!is_first);
+  GPR_ASSERT(!is_last);
+
+  /* initialize members */
+  channeld->unused = 0;
+}
+
+/* Destructor for channel data */
+static void destroy_channel_elem(grpc_channel_element *elem) {
+  /* grab pointers to our data from the channel element */
+  channel_data *channeld = elem->channel_data;
+
+  ignore_unused(channeld);
+}
+
+const grpc_channel_filter grpc_http_filter = {
+    call_op, channel_op,
+
+    sizeof(call_data), init_call_elem, destroy_call_elem,
+
+    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
+
+    "http"};
diff --git a/src/core/channel/http_filter.h b/src/core/channel/http_filter.h
new file mode 100644
index 0000000..89ad482
--- /dev/null
+++ b/src/core/channel/http_filter.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_CHANNEL_HTTP_FILTER_H__
+#define __GRPC_INTERNAL_CHANNEL_HTTP_FILTER_H__
+
+#include "src/core/channel/channel_stack.h"
+
+/* Processes metadata that is common to both client and server for HTTP2
+   transports. */
+extern const grpc_channel_filter grpc_http_filter;
+
+#endif /* __GRPC_INTERNAL_CHANNEL_HTTP_FILTER_H__ */
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
new file mode 100644
index 0000000..b176064
--- /dev/null
+++ b/src/core/channel/http_server_filter.c
@@ -0,0 +1,150 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/channel/http_server_filter.h"
+#include <grpc/support/log.h>
+
+typedef struct call_data {
+  int unused; /* C89 requires at least one struct element */
+} call_data;
+
+typedef struct channel_data { grpc_mdelem *te_trailers; } channel_data;
+
+/* used to silence 'variable not used' warnings */
+static void ignore_unused(void *ignored) {}
+
+/* Called either:
+     - in response to an API call (or similar) from above, to send something
+     - a network event (or similar) from below, to receive something
+   op contains type and call direction information, in addition to the data
+   that is being sent or received. */
+static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+
+  ignore_unused(calld);
+  ignore_unused(channeld);
+
+  switch (op->type) {
+    case GRPC_RECV_METADATA:
+      /* check if it's a te: trailers header */
+      if (op->data.metadata == channeld->te_trailers) {
+        /* swallow it */
+        grpc_mdelem_unref(op->data.metadata);
+        op->done_cb(op->user_data, GRPC_OP_OK);
+      } else {
+        /* pass the event up */
+        grpc_call_next_op(elem, op);
+      }
+      break;
+    default:
+      /* pass control up or down the stack depending on op->dir */
+      grpc_call_next_op(elem, op);
+      break;
+  }
+}
+
+/* Called on special channel events, such as disconnection or new incoming
+   calls on the server */
+static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+  /* grab pointers to our data from the channel element */
+  channel_data *channeld = elem->channel_data;
+
+  ignore_unused(channeld);
+
+  switch (op->type) {
+    default:
+      /* pass control up or down the stack depending on op->dir */
+      grpc_channel_next_op(elem, op);
+      break;
+  }
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_call_element *elem,
+                           const void *server_transport_data) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+
+  ignore_unused(channeld);
+
+  /* initialize members */
+  calld->unused = 0;
+}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_call_element *elem) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+
+  ignore_unused(calld);
+  ignore_unused(channeld);
+}
+
+/* Constructor for channel_data */
+static void init_channel_elem(grpc_channel_element *elem,
+                              const grpc_channel_args *args, grpc_mdctx *mdctx,
+                              int is_first, int is_last) {
+  /* grab pointers to our data from the channel element */
+  channel_data *channeld = 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
+     path */
+  GPR_ASSERT(!is_first);
+  GPR_ASSERT(!is_last);
+
+  /* initialize members */
+  channeld->te_trailers = grpc_mdelem_from_strings(mdctx, "te", "trailers");
+}
+
+/* Destructor for channel data */
+static void destroy_channel_elem(grpc_channel_element *elem) {
+  /* grab pointers to our data from the channel element */
+  channel_data *channeld = elem->channel_data;
+
+  grpc_mdelem_unref(channeld->te_trailers);
+}
+
+const grpc_channel_filter grpc_http_server_filter = {
+    call_op, channel_op,
+
+    sizeof(call_data), init_call_elem, destroy_call_elem,
+
+    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
+
+    "http-server"};
diff --git a/src/core/channel/http_server_filter.h b/src/core/channel/http_server_filter.h
new file mode 100644
index 0000000..5b47543
--- /dev/null
+++ b/src/core/channel/http_server_filter.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_CHANNEL_HTTP_SERVER_FILTER_H__
+#define __GRPC_INTERNAL_CHANNEL_HTTP_SERVER_FILTER_H__
+
+#include "src/core/channel/channel_stack.h"
+
+/* Processes metadata on the client side for HTTP2 transports */
+extern const grpc_channel_filter grpc_http_server_filter;
+
+#endif /* __GRPC_INTERNAL_CHANNEL_HTTP_SERVER_FILTER_H__ */
diff --git a/src/core/channel/metadata_buffer.c b/src/core/channel/metadata_buffer.c
new file mode 100644
index 0000000..75fd90b
--- /dev/null
+++ b/src/core/channel/metadata_buffer.c
@@ -0,0 +1,198 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/channel/metadata_buffer.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+#include <string.h>
+
+#define INITIAL_ELEM_CAP 8
+
+/* One queued call; we track offsets to string data in a shared buffer to
+   reduce allocations. See grpc_metadata_buffer_impl for the memory use
+   strategy */
+typedef struct {
+  grpc_mdelem *md;
+  void (*cb)(void *user_data, grpc_op_error error);
+  void *user_data;
+  gpr_uint32 flags;
+} qelem;
+
+/* Memory layout:
+
+  grpc_metadata_buffer_impl
+  followed by an array of qelem  */
+struct grpc_metadata_buffer_impl {
+  /* number of elements in q */
+  size_t elems;
+  /* capacity of q */
+  size_t elem_cap;
+};
+
+#define ELEMS(buffer) ((qelem *)((buffer)+1))
+
+void grpc_metadata_buffer_init(grpc_metadata_buffer *buffer) {
+  /* start buffer as NULL, indicating no elements */
+  *buffer = NULL;
+}
+
+void grpc_metadata_buffer_destroy(grpc_metadata_buffer *buffer,
+                                  grpc_op_error error) {
+  size_t i;
+  qelem *qe;
+  if (*buffer) {
+    for (i = 0; i < (*buffer)->elems; i++) {
+      qe = &ELEMS(*buffer)[i];
+      grpc_mdelem_unref(qe->md);
+      qe->cb(qe->user_data, error);
+    }
+    gpr_free(*buffer);
+  }
+}
+
+void grpc_metadata_buffer_queue(grpc_metadata_buffer *buffer,
+                                grpc_call_op *op) {
+  grpc_metadata_buffer_impl *impl = *buffer;
+  qelem *qe;
+  size_t bytes;
+
+  GPR_ASSERT(op->type == GRPC_SEND_METADATA || op->type == GRPC_RECV_METADATA);
+
+  if (!impl) {
+    /* this is the first element: allocate enough space to hold the
+       header object and the initial element capacity of qelems */
+    bytes =
+        sizeof(grpc_metadata_buffer_impl) + INITIAL_ELEM_CAP * sizeof(qelem);
+    impl = gpr_malloc(bytes);
+    /* initialize the header object */
+    impl->elems = 0;
+    impl->elem_cap = INITIAL_ELEM_CAP;
+  } else if (impl->elems == impl->elem_cap) {
+    /* more qelems than what we can deal with: grow by doubling size */
+    impl->elem_cap *= 2;
+    bytes = sizeof(grpc_metadata_buffer_impl) + impl->elem_cap * sizeof(qelem);
+    impl = gpr_realloc(impl, bytes);
+  }
+
+  /* append an element to the queue */
+  qe = &ELEMS(impl)[impl->elems];
+  impl->elems++;
+
+  qe->md = op->data.metadata;
+  qe->cb = op->done_cb;
+  qe->user_data = op->user_data;
+  qe->flags = op->flags;
+
+  /* header object may have changed location: store it back */
+  *buffer = impl;
+}
+
+void grpc_metadata_buffer_flush(grpc_metadata_buffer *buffer,
+                                grpc_call_element *elem) {
+  grpc_metadata_buffer_impl *impl = *buffer;
+  grpc_call_op op;
+  qelem *qe;
+  size_t i;
+
+  if (!impl) {
+    /* nothing to send */
+    return;
+  }
+
+  /* construct call_op's, and push them down the stack */
+  op.type = GRPC_SEND_METADATA;
+  op.dir = GRPC_CALL_DOWN;
+  for (i = 0; i < impl->elems; i++) {
+    qe = &ELEMS(impl)[i];
+    op.done_cb = qe->cb;
+    op.user_data = qe->user_data;
+    op.flags = qe->flags;
+    op.data.metadata = qe->md;
+    grpc_call_next_op(elem, &op);
+  }
+
+  /* free data structures and reset to NULL: we can only flush once */
+  gpr_free(impl);
+  *buffer = NULL;
+}
+
+size_t grpc_metadata_buffer_count(const grpc_metadata_buffer *buffer) {
+  return *buffer ? (*buffer)->elems : 0;
+}
+
+typedef struct { grpc_metadata_buffer_impl *impl; } elems_hdr;
+
+grpc_metadata *grpc_metadata_buffer_extract_elements(
+    grpc_metadata_buffer *buffer) {
+  grpc_metadata_buffer_impl *impl;
+  elems_hdr *hdr;
+  qelem *src;
+  grpc_metadata *out;
+  size_t i;
+
+  impl = *buffer;
+
+  if (!impl) {
+    return NULL;
+  }
+
+  hdr = gpr_malloc(sizeof(elems_hdr) + impl->elems * sizeof(grpc_metadata));
+  src = ELEMS(impl);
+  out = (grpc_metadata *)(hdr + 1);
+
+  hdr->impl = impl;
+  for (i = 0; i < impl->elems; i++) {
+    out[i].key = (char *)grpc_mdstr_as_c_string(src[i].md->key);
+    out[i].value = (char *)grpc_mdstr_as_c_string(src[i].md->value);
+    out[i].value_length = GPR_SLICE_LENGTH(src[i].md->value->slice);
+  }
+
+  /* clear out buffer (it's not possible to extract elements twice */
+  *buffer = NULL;
+
+  return out;
+}
+
+void grpc_metadata_buffer_cleanup_elements(void *elements,
+                                           grpc_op_error error) {
+  elems_hdr *hdr = ((elems_hdr *)elements) - 1;
+
+  if (!elements) {
+    return;
+  }
+
+  grpc_metadata_buffer_destroy(&hdr->impl, error);
+  gpr_free(hdr);
+}
diff --git a/src/core/channel/metadata_buffer.h b/src/core/channel/metadata_buffer.h
new file mode 100644
index 0000000..818b290
--- /dev/null
+++ b/src/core/channel/metadata_buffer.h
@@ -0,0 +1,70 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_CHANNEL_METADATA_BUFFER_H__
+#define __GRPC_INTERNAL_CHANNEL_METADATA_BUFFER_H__
+
+#include "src/core/channel/channel_stack.h"
+
+/* Utility code to buffer GRPC_SEND_METADATA calls and pass them down the stack
+   all at once at some otherwise-determined time. Useful for implementing
+   filters that want to queue metadata until a START event chooses some
+   underlying filter stack to send an rpc on. */
+
+/* Clients should declare a member of grpc_metadata_buffer. This may at some
+   point become a typedef for a struct, but for now a pointer suffices */
+typedef struct grpc_metadata_buffer_impl grpc_metadata_buffer_impl;
+typedef grpc_metadata_buffer_impl *grpc_metadata_buffer;
+
+/* Initializes the metadata buffer. Allocates no memory. */
+void grpc_metadata_buffer_init(grpc_metadata_buffer *buffer);
+/* Destroy the metadata buffer. */
+void grpc_metadata_buffer_destroy(grpc_metadata_buffer *buffer,
+                                  grpc_op_error error);
+/* Append a call to the end of a metadata buffer: may allocate memory */
+void grpc_metadata_buffer_queue(grpc_metadata_buffer *buffer, grpc_call_op *op);
+/* Flush all queued operations from the metadata buffer to the element below
+   self */
+void grpc_metadata_buffer_flush(grpc_metadata_buffer *buffer,
+                                grpc_call_element *self);
+/* Count the number of queued elements in the buffer. */
+size_t grpc_metadata_buffer_count(const grpc_metadata_buffer *buffer);
+/* Extract elements as a grpc_metadata*, for presentation to applications.
+   The returned buffer must be freed with
+   grpc_metadata_buffer_cleanup_elements.
+   Clears the metadata buffer (this is a one-shot operation) */
+grpc_metadata *grpc_metadata_buffer_extract_elements(
+    grpc_metadata_buffer *buffer);
+void grpc_metadata_buffer_cleanup_elements(void *elements, grpc_op_error error);
+
+#endif  /* __GRPC_INTERNAL_CHANNEL_METADATA_BUFFER_H__ */
diff --git a/src/core/channel/noop_filter.c b/src/core/channel/noop_filter.c
new file mode 100644
index 0000000..705df4a
--- /dev/null
+++ b/src/core/channel/noop_filter.c
@@ -0,0 +1,138 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/channel/noop_filter.h"
+#include <grpc/support/log.h>
+
+typedef struct call_data {
+  int unused; /* C89 requires at least one struct element */
+} call_data;
+
+typedef struct channel_data {
+  int unused; /* C89 requires at least one struct element */
+} channel_data;
+
+/* used to silence 'variable not used' warnings */
+static void ignore_unused(void *ignored) {}
+
+/* Called either:
+     - in response to an API call (or similar) from above, to send something
+     - a network event (or similar) from below, to receive something
+   op contains type and call direction information, in addition to the data
+   that is being sent or received. */
+static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+
+  ignore_unused(calld);
+  ignore_unused(channeld);
+
+  switch (op->type) {
+    default:
+      /* pass control up or down the stack depending on op->dir */
+      grpc_call_next_op(elem, op);
+      break;
+  }
+}
+
+/* Called on special channel events, such as disconnection or new incoming
+   calls on the server */
+static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+  /* grab pointers to our data from the channel element */
+  channel_data *channeld = elem->channel_data;
+
+  ignore_unused(channeld);
+
+  switch (op->type) {
+    default:
+      /* pass control up or down the stack depending on op->dir */
+      grpc_channel_next_op(elem, op);
+      break;
+  }
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_call_element *elem,
+                           const void *server_transport_data) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+
+  /* initialize members */
+  calld->unused = channeld->unused;
+}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_call_element *elem) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+
+  ignore_unused(calld);
+  ignore_unused(channeld);
+}
+
+/* Constructor for channel_data */
+static void init_channel_elem(grpc_channel_element *elem,
+                              const grpc_channel_args *args, grpc_mdctx *mdctx,
+                              int is_first, int is_last) {
+  /* grab pointers to our data from the channel element */
+  channel_data *channeld = 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
+     path */
+  GPR_ASSERT(!is_first);
+  GPR_ASSERT(!is_last);
+
+  /* initialize members */
+  channeld->unused = 0;
+}
+
+/* Destructor for channel data */
+static void destroy_channel_elem(grpc_channel_element *elem) {
+  /* grab pointers to our data from the channel element */
+  channel_data *channeld = elem->channel_data;
+
+  ignore_unused(channeld);
+}
+
+const grpc_channel_filter grpc_no_op_filter = {
+    call_op,              channel_op,
+
+    sizeof(call_data),    init_call_elem,    destroy_call_elem,
+
+    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
+
+    "no-op"};
diff --git a/src/core/channel/noop_filter.h b/src/core/channel/noop_filter.h
new file mode 100644
index 0000000..4057ff7
--- /dev/null
+++ b/src/core/channel/noop_filter.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_CHANNEL_NOOP_FILTER_H__
+#define __GRPC_INTERNAL_CHANNEL_NOOP_FILTER_H__
+
+#include "src/core/channel/channel_stack.h"
+
+/* No-op filter: simply takes everything it's given, and passes it on to the
+   next filter. Exists simply as a starting point that others can take and
+   customize for their own filters */
+extern const grpc_channel_filter grpc_no_op_filter;
+
+#endif  /* __GRPC_INTERNAL_CHANNEL_NOOP_FILTER_H__ */
diff --git a/src/core/compression/algorithm.c b/src/core/compression/algorithm.c
new file mode 100644
index 0000000..0b5576f
--- /dev/null
+++ b/src/core/compression/algorithm.c
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/compression/algorithm.h"
+
+const char *grpc_compression_algorithm_name(
+    grpc_compression_algorithm algorithm) {
+  switch (algorithm) {
+    case GRPC_COMPRESS_NONE:
+      return "none";
+    case GRPC_COMPRESS_DEFLATE:
+      return "deflate";
+    case GRPC_COMPRESS_GZIP:
+      return "gzip";
+    case GRPC_COMPRESS_ALGORITHMS_COUNT:
+      return "error";
+  }
+  return "error";
+}
diff --git a/src/core/compression/algorithm.h b/src/core/compression/algorithm.h
new file mode 100644
index 0000000..05895a8
--- /dev/null
+++ b/src/core/compression/algorithm.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_COMPRESSION_ALGORITHM_H__
+#define __GRPC_INTERNAL_COMPRESSION_ALGORITHM_H__
+
+/* The various compression algorithms supported by GRPC */
+typedef enum {
+  GRPC_COMPRESS_NONE = 0,
+  GRPC_COMPRESS_DEFLATE,
+  GRPC_COMPRESS_GZIP,
+  /* TODO(ctiller): snappy */
+  GRPC_COMPRESS_ALGORITHMS_COUNT
+} grpc_compression_algorithm;
+
+const char *grpc_compression_algorithm_name(
+    grpc_compression_algorithm algorithm);
+
+#endif  /* __GRPC_INTERNAL_COMPRESSION_ALGORITHM_H__ */
diff --git a/src/core/compression/message_compress.c b/src/core/compression/message_compress.c
new file mode 100644
index 0000000..1787ccd
--- /dev/null
+++ b/src/core/compression/message_compress.c
@@ -0,0 +1,193 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/compression/message_compress.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include <zlib.h>
+
+#define OUTPUT_BLOCK_SIZE 1024
+
+static int zlib_body(z_stream *zs, gpr_slice_buffer *input,
+                     gpr_slice_buffer *output,
+                     int (*flate)(z_stream *zs, int flush)) {
+  int r;
+  int flush;
+  size_t i;
+  size_t output_bytes = 0;
+  gpr_slice outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
+
+  zs->avail_out = GPR_SLICE_LENGTH(outbuf);
+  zs->next_out = GPR_SLICE_START_PTR(outbuf);
+  flush = Z_NO_FLUSH;
+  for (i = 0; i < input->count; i++) {
+    if (i == input->count - 1) flush = Z_FINISH;
+    zs->avail_in = GPR_SLICE_LENGTH(input->slices[i]);
+    zs->next_in = GPR_SLICE_START_PTR(input->slices[i]);
+    do {
+      if (zs->avail_out == 0) {
+        output_bytes += GPR_SLICE_LENGTH(outbuf);
+        gpr_slice_buffer_add_indexed(output, outbuf);
+        outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
+        zs->avail_out = GPR_SLICE_LENGTH(outbuf);
+        zs->next_out = GPR_SLICE_START_PTR(outbuf);
+      }
+      r = flate(zs, flush);
+      if (r == Z_STREAM_ERROR) {
+        gpr_log(GPR_INFO, "zlib: stream error");
+        goto error;
+      }
+    } while (zs->avail_out == 0);
+    if (zs->avail_in) {
+      gpr_log(GPR_INFO, "zlib: not all input consumed");
+      goto error;
+    }
+  }
+
+  GPR_ASSERT(outbuf.refcount);
+  outbuf.data.refcounted.length -= zs->avail_out;
+  output_bytes += GPR_SLICE_LENGTH(outbuf);
+  gpr_slice_buffer_add_indexed(output, outbuf);
+
+  return 1;
+
+error:
+  gpr_slice_unref(outbuf);
+  return 0;
+}
+
+static int zlib_compress(gpr_slice_buffer *input, gpr_slice_buffer *output,
+                         int gzip) {
+  z_stream zs;
+  int r;
+  size_t i;
+  size_t count_before = output->count;
+  size_t length_before = output->length;
+  memset(&zs, 0, sizeof(zs));
+  r = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | (gzip ? 16 : 0),
+                   8, Z_DEFAULT_STRATEGY);
+  if (r != Z_OK) {
+    gpr_log(GPR_ERROR, "deflateInit2 returns %d", r);
+    return 0;
+  }
+  r = zlib_body(&zs, input, output, deflate) && output->length < input->length;
+  if (!r) {
+    for (i = count_before; i < output->count; i++) {
+      gpr_slice_unref(output->slices[i]);
+    }
+    output->count = count_before;
+    output->length = length_before;
+  }
+  deflateEnd(&zs);
+  return r;
+}
+
+static int zlib_decompress(gpr_slice_buffer *input, gpr_slice_buffer *output,
+                           int gzip) {
+  z_stream zs;
+  int r;
+  size_t i;
+  size_t count_before = output->count;
+  size_t length_before = output->length;
+  memset(&zs, 0, sizeof(zs));
+  r = inflateInit2(&zs, 15 | (gzip ? 16 : 0));
+  if (r != Z_OK) {
+    gpr_log(GPR_ERROR, "inflateInit2 returns %d", r);
+    return 0;
+  }
+  r = zlib_body(&zs, input, output, inflate);
+  if (!r) {
+    for (i = count_before; i < output->count; i++) {
+      gpr_slice_unref(output->slices[i]);
+    }
+    output->count = count_before;
+    output->length = length_before;
+  }
+  inflateEnd(&zs);
+  return r;
+}
+
+static int copy(gpr_slice_buffer *input, gpr_slice_buffer *output) {
+  size_t i;
+  for (i = 0; i < input->count; i++) {
+    gpr_slice_buffer_add(output, gpr_slice_ref(input->slices[i]));
+  }
+  return 1;
+}
+
+int compress_inner(grpc_compression_algorithm algorithm,
+                   gpr_slice_buffer *input, gpr_slice_buffer *output) {
+  switch (algorithm) {
+    case GRPC_COMPRESS_NONE:
+      /* the fallback path always needs to be send uncompressed: we simply
+         rely on that here */
+      return 0;
+    case GRPC_COMPRESS_DEFLATE:
+      return zlib_compress(input, output, 0);
+    case GRPC_COMPRESS_GZIP:
+      return zlib_compress(input, output, 1);
+    case GRPC_COMPRESS_ALGORITHMS_COUNT:
+      break;
+  }
+  gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
+  return 0;
+}
+
+int grpc_msg_compress(grpc_compression_algorithm algorithm,
+                      gpr_slice_buffer *input, gpr_slice_buffer *output) {
+  if (!compress_inner(algorithm, input, output)) {
+    copy(input, output);
+    return 0;
+  }
+  return 1;
+}
+
+int grpc_msg_decompress(grpc_compression_algorithm algorithm,
+                        gpr_slice_buffer *input, gpr_slice_buffer *output) {
+  switch (algorithm) {
+    case GRPC_COMPRESS_NONE:
+      return copy(input, output);
+    case GRPC_COMPRESS_DEFLATE:
+      return zlib_decompress(input, output, 0);
+    case GRPC_COMPRESS_GZIP:
+      return zlib_decompress(input, output, 1);
+    case GRPC_COMPRESS_ALGORITHMS_COUNT:
+      break;
+  }
+  gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
+  return 0;
+}
diff --git a/src/core/compression/message_compress.h b/src/core/compression/message_compress.h
new file mode 100644
index 0000000..af8a0a5
--- /dev/null
+++ b/src/core/compression/message_compress.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_COMPRESSION_MESSAGE_COMPRESS_H__
+#define __GRPC_INTERNAL_COMPRESSION_MESSAGE_COMPRESS_H__
+
+#include "src/core/compression/algorithm.h"
+#include <grpc/support/slice_buffer.h>
+
+/* compress 'input' to 'output' using 'algorithm'.
+   On success, appends compressed slices to output and returns 1.
+   On failure, appends uncompressed slices to output and returns 0. */
+int grpc_msg_compress(grpc_compression_algorithm algorithm,
+                      gpr_slice_buffer *input, gpr_slice_buffer *output);
+
+/* decompress 'input' to 'output' using 'algorithm'.
+   On success, appends slices to output and returns 1.
+   On failure, output is unchanged, and returns 0. */
+int grpc_msg_decompress(grpc_compression_algorithm algorithm,
+                        gpr_slice_buffer *input, gpr_slice_buffer *output);
+
+#endif  /* __GRPC_INTERNAL_COMPRESSION_MESSAGE_COMPRESS_H__ */
diff --git a/src/core/endpoint/endpoint.c b/src/core/endpoint/endpoint.c
new file mode 100644
index 0000000..0735375
--- /dev/null
+++ b/src/core/endpoint/endpoint.c
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/endpoint/endpoint.h"
+
+void grpc_endpoint_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
+                                  void *user_data, gpr_timespec deadline) {
+  ep->vtable->notify_on_read(ep, cb, user_data, deadline);
+}
+
+grpc_endpoint_write_status grpc_endpoint_write(
+    grpc_endpoint *ep, gpr_slice *slices, size_t nslices,
+    grpc_endpoint_write_cb cb, void *user_data, gpr_timespec deadline) {
+  return ep->vtable->write(ep, slices, nslices, cb, user_data, deadline);
+}
+
+void grpc_endpoint_shutdown(grpc_endpoint *ep) { ep->vtable->shutdown(ep); }
+
+void grpc_endpoint_destroy(grpc_endpoint *ep) { ep->vtable->destroy(ep); }
diff --git a/src/core/endpoint/endpoint.h b/src/core/endpoint/endpoint.h
new file mode 100644
index 0000000..14d9a56
--- /dev/null
+++ b/src/core/endpoint/endpoint.h
@@ -0,0 +1,99 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_ENDPOINT_ENDPOINT_H__
+#define __GRPC_INTERNAL_ENDPOINT_ENDPOINT_H__
+
+#include <grpc/support/slice.h>
+#include <grpc/support/time.h>
+
+/* An endpoint caps a streaming channel between two communicating processes.
+   Examples may be: a tcp socket, <stdin+stdout>, or some shared memory. */
+
+typedef struct grpc_endpoint grpc_endpoint;
+typedef struct grpc_endpoint_vtable grpc_endpoint_vtable;
+
+typedef enum grpc_endpoint_cb_status {
+  GRPC_ENDPOINT_CB_OK = 0, /* Call completed successfully */
+  GRPC_ENDPOINT_CB_EOF, /* Call completed successfully, end of file reached */
+  GRPC_ENDPOINT_CB_SHUTDOWN, /* Call interrupted by shutdown */
+  GRPC_ENDPOINT_CB_ERROR,    /* Call interrupted by socket error */
+  GRPC_ENDPOINT_CB_TIMED_OUT /* Call timed out */
+} grpc_endpoint_cb_status;
+
+typedef enum grpc_endpoint_write_status {
+  GRPC_ENDPOINT_WRITE_DONE,    /* completed immediately, cb won't be called */
+  GRPC_ENDPOINT_WRITE_PENDING, /* cb will be called when completed */
+  GRPC_ENDPOINT_WRITE_ERROR    /* write errored out, cb won't be called */
+} grpc_endpoint_write_status;
+
+typedef void (*grpc_endpoint_read_cb)(void *user_data, gpr_slice *slices,
+                                      size_t nslices,
+                                      grpc_endpoint_cb_status error);
+typedef void (*grpc_endpoint_write_cb)(void *user_data,
+                                       grpc_endpoint_cb_status error);
+
+struct grpc_endpoint_vtable {
+  void (*notify_on_read)(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
+                         void *user_data, gpr_timespec deadline);
+  grpc_endpoint_write_status (*write)(grpc_endpoint *ep, gpr_slice *slices,
+                                      size_t nslices, grpc_endpoint_write_cb cb,
+                                      void *user_data, gpr_timespec deadline);
+  void (*shutdown)(grpc_endpoint *ep);
+  void (*destroy)(grpc_endpoint *ep);
+};
+
+/* When data is available on the connection, calls the callback with slices. */
+void grpc_endpoint_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
+                                  void *user_data, gpr_timespec deadline);
+
+/* Write slices out to the socket.
+
+   If the connection is ready for more data after the end of the call, it
+   returns GRPC_ENDPOINT_WRITE_DONE.
+   Otherwise it returns GRPC_ENDPOINT_WRITE_PENDING and calls cb when the
+   connection is ready for more data. */
+grpc_endpoint_write_status grpc_endpoint_write(
+    grpc_endpoint *ep, gpr_slice *slices, size_t nslices,
+    grpc_endpoint_write_cb cb, void *user_data, gpr_timespec deadline);
+
+/* Causes any pending read/write callbacks to run immediately with
+   GRPC_ENDPOINT_CB_SHUTDOWN status */
+void grpc_endpoint_shutdown(grpc_endpoint *ep);
+void grpc_endpoint_destroy(grpc_endpoint *ep);
+
+struct grpc_endpoint {
+  const grpc_endpoint_vtable *vtable;
+};
+
+#endif  /* __GRPC_INTERNAL_ENDPOINT_ENDPOINT_H__ */
diff --git a/src/core/endpoint/resolve_address.c b/src/core/endpoint/resolve_address.c
new file mode 100644
index 0000000..aa21954
--- /dev/null
+++ b/src/core/endpoint/resolve_address.c
@@ -0,0 +1,195 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+#define _POSIX_SOURCE
+
+#include "src/core/endpoint/resolve_address.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+
+typedef struct {
+  char *name;
+  char *default_port;
+  grpc_resolve_cb cb;
+  void *arg;
+} request;
+
+static void split_host_port(const char *name, char **host, char **port) {
+  const char *host_start;
+  size_t host_len;
+  const char *port_start;
+
+  *host = NULL;
+  *port = NULL;
+
+  if (name[0] == '[') {
+    /* Parse a bracketed host, typically an IPv6 literal. */
+    const char *rbracket = strchr(name, ']');
+    if (rbracket == NULL) {
+      /* Unmatched [ */
+      return;
+    }
+    if (rbracket[1] == '\0') {
+      /* ]<end> */
+      port_start = NULL;
+    } else if (rbracket[1] == ':') {
+      /* ]:<port?> */
+      port_start = rbracket + 2;
+    } else {
+      /* ]<invalid> */
+      return;
+    }
+    host_start = name + 1;
+    host_len = rbracket - host_start;
+    if (memchr(host_start, ':', host_len) == NULL) {
+      /* Require all bracketed hosts to contain a colon, because a hostname or
+         IPv4 address should never use brackets. */
+      return;
+    }
+  } else {
+    const char *colon = strchr(name, ':');
+    if (colon != NULL && strchr(colon + 1, ':') == NULL) {
+      /* Exactly 1 colon.  Split into host:port. */
+      host_start = name;
+      host_len = colon - name;
+      port_start = colon + 1;
+    } else {
+      /* 0 or 2+ colons.  Bare hostname or IPv6 litearal. */
+      host_start = name;
+      host_len = strlen(name);
+      port_start = NULL;
+    }
+  }
+
+  /* Allocate return values. */
+  *host = gpr_malloc(host_len + 1);
+  memcpy(*host, host_start, host_len);
+  (*host)[host_len] = '\0';
+
+  if (port_start != NULL) {
+    *port = gpr_strdup(port_start);
+  }
+}
+
+grpc_resolved_addresses *grpc_blocking_resolve_address(
+    const char *name, const char *default_port) {
+  struct addrinfo hints;
+  struct addrinfo *result = NULL, *resp;
+  char *host;
+  char *port;
+  int s;
+  size_t i;
+  grpc_resolved_addresses *addrs = NULL;
+
+  /* parse name, splitting it into host and port parts */
+  split_host_port(name, &host, &port);
+  if (host == NULL) {
+    gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name);
+    goto done;
+  }
+  if (port == NULL) {
+    if (default_port == NULL) {
+      gpr_log(GPR_ERROR, "no port in name '%s'", name);
+      goto done;
+    }
+    port = gpr_strdup(default_port);
+  }
+
+  /* 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 = getaddrinfo(host, port, &hints, &result);
+  if (s != 0) {
+    gpr_log(GPR_ERROR, "getaddrinfo: %s", gai_strerror(s));
+    goto done;
+  }
+
+  /* Success path: set addrs non-NULL, fill it in */
+  addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
+  addrs->naddrs = 0;
+  for (resp = result; resp != NULL; resp = resp->ai_next) {
+    addrs->naddrs++;
+  }
+  addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs);
+  i = 0;
+  for (resp = result; resp != NULL; resp = resp->ai_next) {
+    memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
+    addrs->addrs[i].len = resp->ai_addrlen;
+    i++;
+  }
+
+done:
+  gpr_free(host);
+  gpr_free(port);
+  if (result) {
+    freeaddrinfo(result);
+  }
+  return addrs;
+}
+
+/* Thread function to asynch-ify grpc_blocking_resolve_address */
+static void do_request(void *rp) {
+  request *r = rp;
+  r->cb(r->arg, grpc_blocking_resolve_address(r->name, r->default_port));
+  gpr_free(r->name);
+  gpr_free(r->default_port);
+  gpr_free(r);
+}
+
+void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) {
+  gpr_free(addrs->addrs);
+  gpr_free(addrs);
+}
+
+void grpc_resolve_address(const char *name, const char *default_port,
+                          grpc_resolve_cb cb, void *arg) {
+  request *r = gpr_malloc(sizeof(request));
+  gpr_thd_id id;
+  r->name = gpr_strdup(name);
+  r->default_port = gpr_strdup(default_port);
+  r->cb = cb;
+  r->arg = arg;
+  gpr_thd_new(&id, do_request, r, NULL);
+}
diff --git a/src/core/endpoint/resolve_address.h b/src/core/endpoint/resolve_address.h
new file mode 100644
index 0000000..cc32c47
--- /dev/null
+++ b/src/core/endpoint/resolve_address.h
@@ -0,0 +1,67 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_ENDPOINT_RESOLVE_ADDRESS_H__
+#define __GRPC_INTERNAL_ENDPOINT_RESOLVE_ADDRESS_H__
+
+#include <sys/socket.h>
+
+typedef struct {
+  struct sockaddr_storage addr;
+  int len;
+} grpc_resolved_address;
+
+typedef struct {
+  size_t naddrs;
+  grpc_resolved_address *addrs;
+} grpc_resolved_addresses;
+
+/* Async result callback:
+   On success: addresses is the result, and the callee must call
+   grpc_resolved_addresses_destroy when it's done with them
+   On failure: addresses is NULL */
+typedef void (*grpc_resolve_cb)(void *arg, grpc_resolved_addresses *addresses);
+/* 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 */
+void grpc_resolve_address(const char *addr, const char *default_port,
+                          grpc_resolve_cb cb, void *arg);
+/* Destroy resolved addresses */
+void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addresses);
+
+/* Resolve addr in a blocking fashion. Returns NULL on failure. On success,
+   result must be freed with grpc_resolved_addresses_destroy. */
+grpc_resolved_addresses *grpc_blocking_resolve_address(
+    const char *addr, const char *default_port);
+
+#endif  /* __GRPC_INTERNAL_ENDPOINT_RESOLVE_ADDRESS_H__ */
diff --git a/src/core/endpoint/secure_endpoint.c b/src/core/endpoint/secure_endpoint.c
new file mode 100644
index 0000000..4fab0fa
--- /dev/null
+++ b/src/core/endpoint/secure_endpoint.c
@@ -0,0 +1,335 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/endpoint/secure_endpoint.h"
+#include "src/core/tsi/transport_security_interface.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/support/string.h>
+#include <grpc/support/sync.h>
+
+#define STAGING_BUFFER_SIZE 8192
+
+typedef struct {
+  grpc_endpoint base;
+  grpc_endpoint *wrapped_ep;
+  struct tsi_frame_protector *protector;
+  gpr_mu protector_mu;
+  /* saved upper level callbacks and user_data. */
+  grpc_endpoint_read_cb read_cb;
+  void *read_user_data;
+  /* saved handshaker leftover data to unprotect. */
+  gpr_slice_buffer leftover_bytes;
+  /* buffers for read and write */
+  gpr_slice read_staging_buffer;
+  gpr_slice_buffer input_buffer;
+
+  gpr_slice write_staging_buffer;
+  gpr_slice_buffer output_buffer;
+
+  gpr_refcount ref;
+} secure_endpoint;
+
+static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); }
+
+static void destroy(secure_endpoint *secure_ep) {
+  secure_endpoint *ep = (secure_endpoint *)secure_ep;
+  grpc_endpoint_destroy(ep->wrapped_ep);
+  tsi_frame_protector_destroy(ep->protector);
+  gpr_slice_buffer_destroy(&ep->leftover_bytes);
+  gpr_slice_unref(ep->read_staging_buffer);
+  gpr_slice_buffer_destroy(&ep->input_buffer);
+  gpr_slice_unref(ep->write_staging_buffer);
+  gpr_slice_buffer_destroy(&ep->output_buffer);
+  gpr_mu_destroy(&ep->protector_mu);
+  gpr_free(ep);
+}
+
+static void secure_endpoint_unref(secure_endpoint *ep) {
+  if (gpr_unref(&ep->ref)) {
+    destroy(ep);
+  }
+}
+
+static void flush_read_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur,
+                                      gpr_uint8 **end) {
+  gpr_slice_buffer_add(&ep->input_buffer, ep->read_staging_buffer);
+  ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
+  *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
+  *end = GPR_SLICE_END_PTR(ep->read_staging_buffer);
+}
+
+static void call_read_cb(secure_endpoint *ep, gpr_slice *slices, size_t nslices,
+                         grpc_endpoint_cb_status error) {
+#ifdef GRPC_TRACE_SECURE_TRANSPORT
+  size_t i;
+  for (i = 0; i < nslices; i++) {
+    char *data =
+        gpr_hexdump((char*)GPR_SLICE_START_PTR(slices[i]),
+            GPR_SLICE_LENGTH(slices[i]), GPR_HEXDUMP_PLAINTEXT);
+    gpr_log(GPR_DEBUG, "READ %p: %s", ep, data);
+    gpr_free(data);
+  }
+#endif
+  ep->read_cb(ep->read_user_data, slices, nslices, error);
+  secure_endpoint_unref(ep);
+}
+
+static void on_read(void *user_data, gpr_slice *slices, size_t nslices,
+                    grpc_endpoint_cb_status error) {
+  int i = 0;
+  gpr_uint8 keep_looping = 0;
+  int input_buffer_count = 0;
+  tsi_result result = TSI_OK;
+  secure_endpoint *ep = (secure_endpoint *)user_data;
+  gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
+  gpr_uint8 *end = GPR_SLICE_END_PTR(ep->read_staging_buffer);
+
+  /* TODO(yangg) check error, maybe bail out early */
+  for (i = 0; i < nslices; i++) {
+    gpr_slice encrypted = slices[i];
+    gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(encrypted);
+    size_t message_size = GPR_SLICE_LENGTH(encrypted);
+
+    while (message_size > 0 || keep_looping) {
+      gpr_uint32 unprotected_buffer_size_written = end - cur;
+      gpr_uint32 processed_message_size = message_size;
+      gpr_mu_lock(&ep->protector_mu);
+      result = tsi_frame_protector_unprotect(ep->protector, message_bytes,
+                                             &processed_message_size, cur,
+                                             &unprotected_buffer_size_written);
+      gpr_mu_unlock(&ep->protector_mu);
+      if (result != TSI_OK) {
+        gpr_log(GPR_ERROR, "Decryption error: %s",
+                tsi_result_to_string(result));
+        break;
+      }
+      message_bytes += processed_message_size;
+      message_size -= processed_message_size;
+      cur += unprotected_buffer_size_written;
+
+      if (cur == end) {
+        flush_read_staging_buffer(ep, &cur, &end);
+        /* Force to enter the loop again to extract buffered bytes in protector.
+           The bytes could be buffered because of running out of staging_buffer.
+           If this happens at the end of all slices, doing another unprotect
+           avoids leaving data in the protector. */
+        keep_looping = 1;
+      } else if (unprotected_buffer_size_written > 0) {
+        keep_looping = 1;
+      } else {
+        keep_looping = 0;
+      }
+    }
+    if (result != TSI_OK) break;
+  }
+
+  if (cur != GPR_SLICE_START_PTR(ep->read_staging_buffer)) {
+    gpr_slice_buffer_add(
+        &ep->input_buffer,
+        gpr_slice_split_head(
+            &ep->read_staging_buffer,
+            cur - GPR_SLICE_START_PTR(ep->read_staging_buffer)));
+  }
+
+  /* TODO(yangg) experiment with moving this block after read_cb to see if it
+     helps latency */
+  for (i = 0; i < nslices; i++) {
+    gpr_slice_unref(slices[i]);
+  }
+
+  if (result != TSI_OK) {
+    gpr_slice_buffer_reset_and_unref(&ep->input_buffer);
+    call_read_cb(ep, NULL, 0, GRPC_ENDPOINT_CB_ERROR);
+    return;
+  }
+  /* The upper level will unref the slices. */
+  input_buffer_count = ep->input_buffer.count;
+  ep->input_buffer.count = 0;
+  call_read_cb(ep, ep->input_buffer.slices, input_buffer_count, error);
+}
+
+static void notify_on_read(grpc_endpoint *secure_ep, grpc_endpoint_read_cb cb,
+                           void *user_data, gpr_timespec deadline) {
+  secure_endpoint *ep = (secure_endpoint *)secure_ep;
+  ep->read_cb = cb;
+  ep->read_user_data = user_data;
+
+  secure_endpoint_ref(ep);
+
+  if (ep->leftover_bytes.count) {
+    size_t leftover_nslices = ep->leftover_bytes.count;
+    ep->leftover_bytes.count = 0;
+    on_read(ep, ep->leftover_bytes.slices, leftover_nslices,
+            GRPC_ENDPOINT_CB_OK);
+    return;
+  }
+
+  grpc_endpoint_notify_on_read(ep->wrapped_ep, on_read, ep, deadline);
+}
+
+static void flush_write_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur,
+                                       gpr_uint8 **end) {
+  gpr_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer);
+  ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
+  *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
+  *end = GPR_SLICE_END_PTR(ep->write_staging_buffer);
+}
+
+static grpc_endpoint_write_status write(grpc_endpoint *secure_ep,
+                                        gpr_slice *slices, size_t nslices,
+                                        grpc_endpoint_write_cb cb,
+                                        void *user_data,
+                                        gpr_timespec deadline) {
+  int i = 0;
+  int output_buffer_count = 0;
+  tsi_result result = TSI_OK;
+  secure_endpoint *ep = (secure_endpoint *)secure_ep;
+  gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
+  gpr_uint8 *end = GPR_SLICE_END_PTR(ep->write_staging_buffer);
+  GPR_ASSERT(ep->output_buffer.count == 0);
+
+#ifdef GRPC_TRACE_SECURE_TRANSPORT
+  for (i = 0; i < nslices; i++) {
+    char *data =
+        gpr_hexdump((char*)GPR_SLICE_START_PTR(slices[i]),
+            GPR_SLICE_LENGTH(slices[i]), GPR_HEXDUMP_PLAINTEXT);
+    gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data);
+    gpr_free(data);
+  }
+#endif
+
+  for (i = 0; i < nslices; i++) {
+    gpr_slice plain = slices[i];
+    gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(plain);
+    size_t message_size = GPR_SLICE_LENGTH(plain);
+    while (message_size > 0) {
+      gpr_uint32 protected_buffer_size_to_send = end - cur;
+      gpr_uint32 processed_message_size = message_size;
+      gpr_mu_lock(&ep->protector_mu);
+      result = tsi_frame_protector_protect(ep->protector, message_bytes,
+                                           &processed_message_size, cur,
+                                           &protected_buffer_size_to_send);
+      gpr_mu_unlock(&ep->protector_mu);
+      if (result != TSI_OK) {
+        gpr_log(GPR_ERROR, "Encryption error: %s",
+                tsi_result_to_string(result));
+        break;
+      }
+      message_bytes += processed_message_size;
+      message_size -= processed_message_size;
+      cur += protected_buffer_size_to_send;
+
+      if (cur == end) {
+        flush_write_staging_buffer(ep, &cur, &end);
+      }
+    }
+    if (result != TSI_OK) break;
+  }
+  if (result == TSI_OK) {
+    gpr_uint32 still_pending_size;
+    do {
+      gpr_uint32 protected_buffer_size_to_send = end - cur;
+      gpr_mu_lock(&ep->protector_mu);
+      result = tsi_frame_protector_protect_flush(ep->protector, cur,
+                                                 &protected_buffer_size_to_send,
+                                                 &still_pending_size);
+      gpr_mu_unlock(&ep->protector_mu);
+      if (result != TSI_OK) break;
+      cur += protected_buffer_size_to_send;
+      if (cur == end) {
+        flush_write_staging_buffer(ep, &cur, &end);
+      }
+    } while (still_pending_size > 0);
+    if (cur != GPR_SLICE_START_PTR(ep->write_staging_buffer)) {
+      gpr_slice_buffer_add(
+          &ep->output_buffer,
+          gpr_slice_split_head(
+              &ep->write_staging_buffer,
+              cur - GPR_SLICE_START_PTR(ep->write_staging_buffer)));
+    }
+  }
+
+  for (i = 0; i < nslices; i++) {
+    gpr_slice_unref(slices[i]);
+  }
+
+  if (result != TSI_OK) {
+    /* TODO(yangg) do different things according to the error type? */
+    gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
+    return GRPC_ENDPOINT_WRITE_ERROR;
+  }
+
+  /* clear output_buffer and let the lower level handle its slices. */
+  output_buffer_count = ep->output_buffer.count;
+  ep->output_buffer.count = 0;
+  return grpc_endpoint_write(ep->wrapped_ep, ep->output_buffer.slices,
+                             output_buffer_count, cb, user_data, deadline);
+}
+
+static void shutdown(grpc_endpoint *secure_ep) {
+  secure_endpoint *ep = (secure_endpoint *)secure_ep;
+  grpc_endpoint_shutdown(ep->wrapped_ep);
+}
+
+static void unref(grpc_endpoint *secure_ep) {
+  secure_endpoint *ep = (secure_endpoint *)secure_ep;
+  secure_endpoint_unref(ep);
+}
+
+static const grpc_endpoint_vtable vtable = {notify_on_read, write, shutdown,
+                                            unref};
+
+grpc_endpoint *grpc_secure_endpoint_create(
+    struct tsi_frame_protector *protector, grpc_endpoint *transport,
+    gpr_slice *leftover_slices, size_t leftover_nslices) {
+  size_t i;
+  secure_endpoint *ep = (secure_endpoint *)gpr_malloc(sizeof(secure_endpoint));
+  ep->base.vtable = &vtable;
+  ep->wrapped_ep = transport;
+  ep->protector = protector;
+  gpr_slice_buffer_init(&ep->leftover_bytes);
+  for (i = 0; i < leftover_nslices; i++) {
+    gpr_slice_buffer_add(&ep->leftover_bytes,
+                         gpr_slice_ref(leftover_slices[i]));
+  }
+  ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
+  ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
+  gpr_slice_buffer_init(&ep->input_buffer);
+  gpr_slice_buffer_init(&ep->output_buffer);
+  gpr_mu_init(&ep->protector_mu);
+  gpr_ref_init(&ep->ref, 1);
+  return &ep->base;
+}
diff --git a/src/core/endpoint/secure_endpoint.h b/src/core/endpoint/secure_endpoint.h
new file mode 100644
index 0000000..971170a
--- /dev/null
+++ b/src/core/endpoint/secure_endpoint.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_ENDPOINT_SECURE_ENDPOINT_H__
+#define __GRPC_INTERNAL_ENDPOINT_SECURE_ENDPOINT_H__
+
+#include <grpc/support/slice.h>
+#include "src/core/endpoint/endpoint.h"
+
+struct tsi_frame_protector;
+
+/* Takes ownership of protector and to_wrap, and refs leftover_slices. */
+grpc_endpoint *grpc_secure_endpoint_create(
+    struct tsi_frame_protector *protector, grpc_endpoint *to_wrap,
+    gpr_slice *leftover_slices, size_t leftover_nslices);
+
+#endif  /* __GRPC_INTERNAL_ENDPOINT_SECURE_ENDPOINT_H__ */
diff --git a/src/core/endpoint/socket_utils.c b/src/core/endpoint/socket_utils.c
new file mode 100644
index 0000000..9c2540b
--- /dev/null
+++ b/src/core/endpoint/socket_utils.c
@@ -0,0 +1,105 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/endpoint/socket_utils.h"
+
+#include <limits.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+/* set a socket to non blocking mode */
+int grpc_set_socket_nonblocking(int fd, int non_blocking) {
+  int oldflags = fcntl(fd, F_GETFL, 0);
+  if (oldflags < 0) {
+    return 0;
+  }
+
+  if (non_blocking) {
+    oldflags |= O_NONBLOCK;
+  } else {
+    oldflags &= ~O_NONBLOCK;
+  }
+
+  if (fcntl(fd, F_SETFL, oldflags) != 0) {
+    return 0;
+  }
+
+  return 1;
+}
+
+/* set a socket to close on exec */
+int grpc_set_socket_cloexec(int fd, int close_on_exec) {
+  int oldflags = fcntl(fd, F_GETFD, 0);
+  if (oldflags < 0) {
+    return 0;
+  }
+
+  if (close_on_exec) {
+    oldflags |= FD_CLOEXEC;
+  } else {
+    oldflags &= ~FD_CLOEXEC;
+  }
+
+  if (fcntl(fd, F_SETFD, oldflags) != 0) {
+    return 0;
+  }
+
+  return 1;
+}
+
+/* set a socket to reuse old addresses */
+int grpc_set_socket_reuse_addr(int fd, int reuse) {
+  int val = (reuse != 0);
+  int newval;
+  socklen_t intlen = sizeof(newval);
+  return 0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) &&
+         0 == getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen) &&
+         newval == val;
+}
+
+/* disable nagle */
+int grpc_set_socket_low_latency(int fd, int low_latency) {
+  int val = (low_latency != 0);
+  int newval;
+  socklen_t intlen = sizeof(newval);
+  return 0 == setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) &&
+         0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen) &&
+         newval == val;
+}
diff --git a/src/core/endpoint/socket_utils.h b/src/core/endpoint/socket_utils.h
new file mode 100644
index 0000000..545d678
--- /dev/null
+++ b/src/core/endpoint/socket_utils.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_ENDPOINT_SOCKET_UTILS_H__
+#define __GRPC_INTERNAL_ENDPOINT_SOCKET_UTILS_H__
+
+#include <unistd.h>
+#include <sys/socket.h>
+
+struct sockaddr;
+
+/* a wrapper for accept or accept4 */
+int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
+                 int nonblock, int cloexec);
+
+/* set a socket to non blocking mode */
+int grpc_set_socket_nonblocking(int fd, int non_blocking);
+
+/* set a socket to close on exec */
+int grpc_set_socket_cloexec(int fd, int close_on_exec);
+
+/* set a socket to reuse old addresses */
+int grpc_set_socket_reuse_addr(int fd, int reuse);
+
+/* disable nagle */
+int grpc_set_socket_low_latency(int fd, int low_latency);
+
+#endif  /* __GRPC_INTERNAL_ENDPOINT_SOCKET_UTILS_H__ */
diff --git a/src/core/endpoint/socket_utils_linux.c b/src/core/endpoint/socket_utils_linux.c
new file mode 100644
index 0000000..479675e
--- /dev/null
+++ b/src/core/endpoint/socket_utils_linux.c
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_LINUX
+
+#include "src/core/endpoint/socket_utils.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
+                 int nonblock, int cloexec) {
+  int flags = 0;
+  flags |= nonblock ? SOCK_NONBLOCK : 0;
+  flags |= cloexec ? SOCK_CLOEXEC : 0;
+  return accept4(sockfd, addr, addrlen, flags);
+}
+
+#endif
diff --git a/src/core/endpoint/socket_utils_posix.c b/src/core/endpoint/socket_utils_posix.c
new file mode 100644
index 0000000..262d606
--- /dev/null
+++ b/src/core/endpoint/socket_utils_posix.c
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKETUTILS
+
+#define _BSD_SOURCE
+#include "src/core/endpoint/socket_utils.h"
+
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <grpc/support/log.h>
+
+int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
+                 int nonblock, int cloexec) {
+  int fd, flags;
+
+  fd = accept(sockfd, addr, addrlen);
+  if (fd >= 0) {
+    flags = fcntl(fd, F_GETFL, 0);
+    flags |= nonblock ? O_NONBLOCK : 0;
+    flags |= cloexec ? FD_CLOEXEC : 0;
+    GPR_ASSERT(fcntl(fd, F_SETFL, flags) == 0);
+  }
+  return fd;
+}
+
+#endif /* GPR_POSIX_SOCKETUTILS */
diff --git a/src/core/endpoint/tcp.c b/src/core/endpoint/tcp.c
new file mode 100644
index 0000000..39367e8
--- /dev/null
+++ b/src/core/endpoint/tcp.c
@@ -0,0 +1,570 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/endpoint/tcp.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "src/core/eventmanager/em.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/string.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+
+/* Holds a slice array and associated state. */
+typedef struct grpc_tcp_slice_state {
+  gpr_slice *slices;       /* Array of slices */
+  size_t nslices;          /* Size of slices array. */
+  ssize_t first_slice;     /* First valid slice in array */
+  ssize_t last_slice;      /* Last valid slice in array */
+  gpr_slice working_slice; /* pointer to original final slice */
+  int working_slice_valid; /* True if there is a working slice */
+  int memory_owned;        /* True if slices array is owned */
+} grpc_tcp_slice_state;
+
+static void slice_state_init(grpc_tcp_slice_state *state, gpr_slice *slices,
+                             size_t nslices, size_t valid_slices) {
+  state->slices = slices;
+  state->nslices = nslices;
+  if (valid_slices == 0) {
+    state->first_slice = -1;
+  } else {
+    state->first_slice = 0;
+  }
+  state->last_slice = valid_slices - 1;
+  state->working_slice_valid = 0;
+  state->memory_owned = 0;
+}
+
+/* Returns true if there is still available data */
+static int slice_state_has_available(grpc_tcp_slice_state *state) {
+  return state->first_slice != -1 && state->last_slice >= state->first_slice;
+}
+
+static ssize_t slice_state_slices_allocated(grpc_tcp_slice_state *state) {
+  if (state->first_slice == -1) {
+    return 0;
+  } else {
+    return state->last_slice - state->first_slice + 1;
+  }
+}
+
+static void slice_state_realloc(grpc_tcp_slice_state *state, size_t new_size) {
+  /* TODO(klempner): use realloc instead when first_slice is 0 */
+  /* TODO(klempner): Avoid a realloc in cases where it is unnecessary */
+  gpr_slice *slices = state->slices;
+  size_t original_size = slice_state_slices_allocated(state);
+  size_t i;
+  gpr_slice *new_slices = gpr_malloc(sizeof(gpr_slice) * new_size);
+
+  for (i = 0; i < original_size; ++i) {
+    new_slices[i] = slices[i + state->first_slice];
+  }
+
+  state->slices = new_slices;
+  state->last_slice = original_size - 1;
+  if (original_size > 0) {
+    state->first_slice = 0;
+  } else {
+    state->first_slice = -1;
+  }
+  state->nslices = new_size;
+
+  if (state->memory_owned) {
+    gpr_free(slices);
+  }
+  state->memory_owned = 1;
+}
+
+static void slice_state_remove_prefix(grpc_tcp_slice_state *state,
+                                      size_t prefix_bytes) {
+  gpr_slice *current_slice = &state->slices[state->first_slice];
+  size_t current_slice_size;
+
+  while (slice_state_has_available(state)) {
+    current_slice_size = GPR_SLICE_LENGTH(*current_slice);
+    if (current_slice_size > prefix_bytes) {
+      /* TODO(klempner): Get rid of the extra refcount created here by adding a
+         native "trim the first N bytes" operation to splice */
+      /* TODO(klempner): This really shouldn't be modifying the current slice
+         unless we own the slices array. */
+      *current_slice = gpr_slice_split_tail(current_slice, prefix_bytes);
+      gpr_slice_unref(*current_slice);
+      return;
+    } else {
+      gpr_slice_unref(*current_slice);
+      ++state->first_slice;
+      ++current_slice;
+      prefix_bytes -= current_slice_size;
+    }
+  }
+}
+
+static void slice_state_destroy(grpc_tcp_slice_state *state) {
+  while (slice_state_has_available(state)) {
+    gpr_slice_unref(state->slices[state->first_slice]);
+    ++state->first_slice;
+  }
+
+  if (state->memory_owned) {
+    gpr_free(state->slices);
+    state->memory_owned = 0;
+  }
+}
+
+void slice_state_transfer_ownership(grpc_tcp_slice_state *state,
+                                    gpr_slice **slices, size_t *nslices) {
+  *slices = state->slices + state->first_slice;
+  *nslices = state->last_slice - state->first_slice + 1;
+
+  state->first_slice = -1;
+  state->last_slice = -1;
+}
+
+/* Fills iov with the first min(iov_size, available) slices, returns number
+   filled */
+static size_t slice_state_to_iovec(grpc_tcp_slice_state *state,
+                                   struct iovec *iov, size_t iov_size) {
+  size_t nslices = state->last_slice - state->first_slice + 1;
+  gpr_slice *slices = state->slices + state->first_slice;
+  size_t i;
+  if (nslices < iov_size) {
+    iov_size = nslices;
+  }
+
+  for (i = 0; i < iov_size; ++i) {
+    iov[i].iov_base = GPR_SLICE_START_PTR(slices[i]);
+    iov[i].iov_len = GPR_SLICE_LENGTH(slices[i]);
+  }
+  return iov_size;
+}
+
+/* Makes n blocks available at the end of state, writes them into iov, and
+   returns the number of bytes allocated */
+static size_t slice_state_append_blocks_into_iovec(grpc_tcp_slice_state *state,
+                                                   struct iovec *iov, size_t n,
+                                                   size_t slice_size) {
+  size_t target_size;
+  size_t i;
+  size_t allocated_bytes;
+  ssize_t allocated_slices = slice_state_slices_allocated(state);
+
+  if (n - state->working_slice_valid >= state->nslices - state->last_slice) {
+    /* Need to grow the slice array */
+    target_size = state->nslices;
+    do {
+      target_size = target_size * 2;
+    } while (target_size < allocated_slices + n - state->working_slice_valid);
+    /* TODO(klempner): If this ever needs to support both prefix removal and
+       append, we should be smarter about the growth logic here */
+    slice_state_realloc(state, target_size);
+  }
+
+  i = 0;
+  allocated_bytes = 0;
+
+  if (state->working_slice_valid) {
+    iov[0].iov_base = GPR_SLICE_END_PTR(state->slices[state->last_slice]);
+    iov[0].iov_len = GPR_SLICE_LENGTH(state->working_slice) -
+                     GPR_SLICE_LENGTH(state->slices[state->last_slice]);
+    allocated_bytes += iov[0].iov_len;
+    ++i;
+    state->slices[state->last_slice] = state->working_slice;
+    state->working_slice_valid = 0;
+  }
+
+  for (; i < n; ++i) {
+    ++state->last_slice;
+    state->slices[state->last_slice] = gpr_slice_malloc(slice_size);
+    iov[i].iov_base = GPR_SLICE_START_PTR(state->slices[state->last_slice]);
+    iov[i].iov_len = slice_size;
+    allocated_bytes += slice_size;
+  }
+  if (state->first_slice == -1) {
+    state->first_slice = 0;
+  }
+  return allocated_bytes;
+}
+
+/* Remove the last n bytes from state */
+/* TODO(klempner): Consider having this defer actual deletion until later */
+static void slice_state_remove_last(grpc_tcp_slice_state *state, size_t bytes) {
+  while (bytes > 0 && slice_state_has_available(state)) {
+    if (GPR_SLICE_LENGTH(state->slices[state->last_slice]) > bytes) {
+      state->working_slice = state->slices[state->last_slice];
+      state->working_slice_valid = 1;
+      /* TODO(klempner): Combine these into a single operation that doesn't need
+         to refcount */
+      gpr_slice_unref(gpr_slice_split_tail(
+          &state->slices[state->last_slice],
+          GPR_SLICE_LENGTH(state->slices[state->last_slice]) - bytes));
+      bytes = 0;
+    } else {
+      bytes -= GPR_SLICE_LENGTH(state->slices[state->last_slice]);
+      gpr_slice_unref(state->slices[state->last_slice]);
+      --state->last_slice;
+      if (state->last_slice == -1) {
+        state->first_slice = -1;
+      }
+    }
+  }
+}
+
+typedef struct {
+  grpc_endpoint base;
+  grpc_em *em;
+  grpc_em_fd em_fd;
+  int fd;
+  size_t slice_size;
+  gpr_refcount refcount;
+
+  grpc_endpoint_read_cb read_cb;
+  void *read_user_data;
+  gpr_timespec read_deadline;
+  grpc_endpoint_write_cb write_cb;
+  void *write_user_data;
+  gpr_timespec write_deadline;
+
+  grpc_tcp_slice_state write_state;
+} grpc_tcp;
+
+static void grpc_tcp_handle_read(void *arg /* grpc_tcp */,
+                                 grpc_em_cb_status status);
+static void grpc_tcp_handle_write(void *arg /* grpc_tcp */,
+                                  grpc_em_cb_status status);
+
+#define DEFAULT_SLICE_SIZE 8192
+grpc_endpoint *grpc_tcp_create(int fd, grpc_em *em) {
+  return grpc_tcp_create_dbg(fd, em, DEFAULT_SLICE_SIZE);
+}
+
+static void grpc_tcp_shutdown(grpc_endpoint *ep) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  grpc_em_fd_shutdown(&tcp->em_fd);
+}
+
+static void grpc_tcp_unref(grpc_tcp *tcp) {
+  int refcount_zero = gpr_unref(&tcp->refcount);
+  if (refcount_zero) {
+    grpc_em_fd_destroy(&tcp->em_fd);
+    close(tcp->fd);
+    gpr_free(tcp);
+  }
+}
+
+static void grpc_tcp_destroy(grpc_endpoint *ep) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  grpc_tcp_unref(tcp);
+}
+
+static void call_read_cb(grpc_tcp *tcp, gpr_slice *slices, size_t nslices,
+                         grpc_endpoint_cb_status status) {
+  grpc_endpoint_read_cb cb = tcp->read_cb;
+
+#ifdef GRPC_TRACE_TCP
+  size_t i;
+  gpr_log(GPR_DEBUG, "read: status=%d", status);
+  for (i = 0; i < nslices; i++) {
+    char *dump =
+        gpr_hexdump((char *)GPR_SLICE_START_PTR(slices[i]),
+                    GPR_SLICE_LENGTH(slices[i]), GPR_HEXDUMP_PLAINTEXT);
+    gpr_log(GPR_DEBUG, "READ: %s", dump);
+    gpr_free(dump);
+  }
+#endif
+
+  tcp->read_cb = NULL;
+  cb(tcp->read_user_data, slices, nslices, status);
+}
+
+#define INLINE_SLICE_BUFFER_SIZE 8
+#define MAX_READ_IOVEC 4
+static void grpc_tcp_handle_read(void *arg /* grpc_tcp */,
+                                 grpc_em_cb_status status) {
+  grpc_tcp *tcp = (grpc_tcp *)arg;
+  int iov_size = 1;
+  gpr_slice static_read_slices[INLINE_SLICE_BUFFER_SIZE];
+  struct msghdr msg;
+  struct iovec iov[MAX_READ_IOVEC];
+  ssize_t read_bytes;
+  ssize_t allocated_bytes;
+  struct grpc_tcp_slice_state read_state;
+  gpr_slice *final_slices;
+  size_t final_nslices;
+
+  slice_state_init(&read_state, static_read_slices, INLINE_SLICE_BUFFER_SIZE,
+                   0);
+
+  if (status == GRPC_CALLBACK_CANCELLED) {
+    call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
+    grpc_tcp_unref(tcp);
+    return;
+  }
+
+  if (status == GRPC_CALLBACK_TIMED_OUT) {
+    call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_TIMED_OUT);
+    grpc_tcp_unref(tcp);
+    return;
+  }
+
+  /* TODO(klempner): Limit the amount we read at once. */
+  for (;;) {
+    allocated_bytes = slice_state_append_blocks_into_iovec(
+        &read_state, iov, iov_size, tcp->slice_size);
+
+    msg.msg_name = NULL;
+    msg.msg_namelen = 0;
+    msg.msg_iov = iov;
+    msg.msg_iovlen = iov_size;
+    msg.msg_control = NULL;
+    msg.msg_controllen = 0;
+    msg.msg_flags = 0;
+
+    do {
+      read_bytes = recvmsg(tcp->fd, &msg, 0);
+    } while (read_bytes < 0 && errno == EINTR);
+
+    if (read_bytes < allocated_bytes) {
+      /* TODO(klempner): Consider a second read first, in hopes of getting a
+       * quick EAGAIN and saving a bunch of allocations. */
+      slice_state_remove_last(&read_state, read_bytes < 0
+                                               ? allocated_bytes
+                                               : allocated_bytes - read_bytes);
+    }
+
+    if (read_bytes < 0) {
+      /* NB: After calling the user_cb a parallel call of the read handler may
+       * be running. */
+      if (errno == EAGAIN) {
+        if (slice_state_has_available(&read_state)) {
+          /* TODO(klempner): We should probably do the call into the application
+             without all this junk on the stack */
+          /* FIXME(klempner): Refcount properly */
+          slice_state_transfer_ownership(&read_state, &final_slices,
+                                         &final_nslices);
+          call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_OK);
+          slice_state_destroy(&read_state);
+          grpc_tcp_unref(tcp);
+        } else {
+          /* Spurious read event, consume it here */
+          slice_state_destroy(&read_state);
+          grpc_em_fd_notify_on_read(&tcp->em_fd, grpc_tcp_handle_read, tcp,
+                                    tcp->read_deadline);
+        }
+      } else {
+        /* TODO(klempner): Log interesting errors */
+        call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_ERROR);
+        slice_state_destroy(&read_state);
+        grpc_tcp_unref(tcp);
+      }
+      return;
+    } else if (read_bytes == 0) {
+      /* 0 read size ==> end of stream */
+      if (slice_state_has_available(&read_state)) {
+        /* there were bytes already read: pass them up to the application */
+        slice_state_transfer_ownership(&read_state, &final_slices,
+                                       &final_nslices);
+        call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_EOF);
+      } else {
+        call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_EOF);
+      }
+      slice_state_destroy(&read_state);
+      grpc_tcp_unref(tcp);
+      return;
+    } else if (iov_size < MAX_READ_IOVEC) {
+      ++iov_size;
+    }
+  }
+}
+
+static void grpc_tcp_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
+                                    void *user_data, gpr_timespec deadline) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  GPR_ASSERT(tcp->read_cb == NULL);
+  tcp->read_cb = cb;
+  tcp->read_user_data = user_data;
+  tcp->read_deadline = deadline;
+  gpr_ref(&tcp->refcount);
+  grpc_em_fd_notify_on_read(&tcp->em_fd, grpc_tcp_handle_read, tcp, deadline);
+}
+
+#define MAX_WRITE_IOVEC 16
+static grpc_endpoint_write_status grpc_tcp_flush(grpc_tcp *tcp) {
+  struct msghdr msg;
+  struct iovec iov[MAX_WRITE_IOVEC];
+  int iov_size;
+  ssize_t sent_length;
+  grpc_tcp_slice_state *state = &tcp->write_state;
+
+  for (;;) {
+    iov_size = slice_state_to_iovec(state, iov, MAX_WRITE_IOVEC);
+
+    msg.msg_name = NULL;
+    msg.msg_namelen = 0;
+    msg.msg_iov = iov;
+    msg.msg_iovlen = iov_size;
+    msg.msg_control = NULL;
+    msg.msg_controllen = 0;
+    msg.msg_flags = 0;
+
+    do {
+      /* TODO(klempner): Cork if this is a partial write */
+      sent_length = sendmsg(tcp->fd, &msg, 0);
+    } while (sent_length < 0 && errno == EINTR);
+
+    if (sent_length < 0) {
+      if (errno == EAGAIN) {
+        return GRPC_ENDPOINT_WRITE_PENDING;
+      } else {
+        /* TODO(klempner): Log some of these */
+        slice_state_destroy(state);
+        return GRPC_ENDPOINT_WRITE_ERROR;
+      }
+    }
+
+    /* TODO(klempner): Probably better to batch this after we finish flushing */
+    slice_state_remove_prefix(state, sent_length);
+
+    if (!slice_state_has_available(state)) {
+      return GRPC_ENDPOINT_WRITE_DONE;
+    }
+  };
+}
+
+static void grpc_tcp_handle_write(void *arg /* grpc_tcp */,
+                                  grpc_em_cb_status status) {
+  grpc_tcp *tcp = (grpc_tcp *)arg;
+  grpc_endpoint_write_status write_status;
+  grpc_endpoint_cb_status cb_status;
+  grpc_endpoint_write_cb cb;
+
+  cb_status = GRPC_ENDPOINT_CB_OK;
+
+  if (status == GRPC_CALLBACK_CANCELLED) {
+    cb_status = GRPC_ENDPOINT_CB_SHUTDOWN;
+  } else if (status == GRPC_CALLBACK_TIMED_OUT) {
+    cb_status = GRPC_ENDPOINT_CB_TIMED_OUT;
+  }
+
+  if (cb_status != GRPC_ENDPOINT_CB_OK) {
+    slice_state_destroy(&tcp->write_state);
+    cb = tcp->write_cb;
+    tcp->write_cb = NULL;
+    cb(tcp->write_user_data, cb_status);
+    grpc_tcp_unref(tcp);
+    return;
+  }
+
+  write_status = grpc_tcp_flush(tcp);
+  if (write_status == GRPC_ENDPOINT_WRITE_PENDING) {
+    grpc_em_fd_notify_on_write(&tcp->em_fd, grpc_tcp_handle_write, tcp,
+                               tcp->write_deadline);
+  } else {
+    slice_state_destroy(&tcp->write_state);
+    if (write_status == GRPC_ENDPOINT_WRITE_DONE) {
+      cb_status = GRPC_ENDPOINT_CB_OK;
+    } else {
+      cb_status = GRPC_ENDPOINT_CB_ERROR;
+    }
+    cb = tcp->write_cb;
+    tcp->write_cb = NULL;
+    cb(tcp->write_user_data, cb_status);
+    grpc_tcp_unref(tcp);
+  }
+}
+
+static grpc_endpoint_write_status grpc_tcp_write(
+    grpc_endpoint *ep, gpr_slice *slices, size_t nslices,
+    grpc_endpoint_write_cb cb, void *user_data, gpr_timespec deadline) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  grpc_endpoint_write_status status;
+
+#ifdef GRPC_TRACE_TCP
+  size_t i;
+
+  for (i = 0; i < nslices; i++) {
+    char *data =
+        gpr_hexdump((char *)GPR_SLICE_START_PTR(slices[i]),
+                    GPR_SLICE_LENGTH(slices[i]), GPR_HEXDUMP_PLAINTEXT);
+    gpr_log(GPR_DEBUG, "WRITE %p: %s", tcp, data);
+    gpr_free(data);
+  }
+#endif
+
+  GPR_ASSERT(tcp->write_cb == NULL);
+  slice_state_init(&tcp->write_state, slices, nslices, nslices);
+
+  status = grpc_tcp_flush(tcp);
+  if (status == GRPC_ENDPOINT_WRITE_PENDING) {
+    /* TODO(klempner): Consider inlining rather than malloc for small nslices */
+    slice_state_realloc(&tcp->write_state, nslices);
+    gpr_ref(&tcp->refcount);
+    tcp->write_cb = cb;
+    tcp->write_user_data = user_data;
+    tcp->write_deadline = deadline;
+    grpc_em_fd_notify_on_write(&tcp->em_fd, grpc_tcp_handle_write, tcp,
+                               tcp->write_deadline);
+  }
+
+  return status;
+}
+
+static const grpc_endpoint_vtable vtable = {grpc_tcp_notify_on_read,
+                                            grpc_tcp_write, grpc_tcp_shutdown,
+                                            grpc_tcp_destroy};
+
+grpc_endpoint *grpc_tcp_create_dbg(int fd, grpc_em *em, size_t slice_size) {
+  grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
+  tcp->base.vtable = &vtable;
+  tcp->fd = fd;
+  tcp->em = em;
+  tcp->read_cb = NULL;
+  tcp->write_cb = NULL;
+  tcp->read_user_data = NULL;
+  tcp->write_user_data = NULL;
+  tcp->slice_size = slice_size;
+  tcp->read_deadline = gpr_inf_future;
+  tcp->write_deadline = gpr_inf_future;
+  slice_state_init(&tcp->write_state, NULL, 0, 0);
+  /* paired with unref in grpc_tcp_destroy */
+  gpr_ref_init(&tcp->refcount, 1);
+  grpc_em_fd_init(&tcp->em_fd, tcp->em, fd);
+  return &tcp->base;
+}
diff --git a/src/core/endpoint/tcp.h b/src/core/endpoint/tcp.h
new file mode 100644
index 0000000..6507b2f
--- /dev/null
+++ b/src/core/endpoint/tcp.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_ENDPOINT_TCP_H__
+#define __GRPC_INTERNAL_ENDPOINT_TCP_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/endpoint/endpoint.h"
+#include "src/core/eventmanager/em.h"
+
+/* Create a tcp from an already connected file descriptor. */
+grpc_endpoint *grpc_tcp_create(int fd, grpc_em *em);
+/* Special version for debugging slice changes */
+grpc_endpoint *grpc_tcp_create_dbg(int fd, grpc_em *em, size_t slice_size);
+
+#endif  /* __GRPC_INTERNAL_ENDPOINT_TCP_H__ */
diff --git a/src/core/endpoint/tcp_client.c b/src/core/endpoint/tcp_client.c
new file mode 100644
index 0000000..01a0c3f
--- /dev/null
+++ b/src/core/endpoint/tcp_client.c
@@ -0,0 +1,170 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/endpoint/tcp_client.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "src/core/endpoint/socket_utils.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+
+typedef struct {
+  void (*cb)(void *arg, grpc_endpoint *tcp);
+  void *cb_arg;
+  grpc_em_fd fd;
+  gpr_timespec deadline;
+} async_connect;
+
+static int create_fd(int address_family) {
+  int fd = socket(address_family, SOCK_STREAM, 0);
+  if (fd < 0) {
+    gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
+    goto error;
+  }
+
+  if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) ||
+      !grpc_set_socket_low_latency(fd, 1)) {
+    gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
+            strerror(errno));
+    goto error;
+  }
+
+  return fd;
+
+error:
+  if (fd >= 0) {
+    close(fd);
+  }
+  return -1;
+}
+
+static void on_writable(void *acp, grpc_em_cb_status status) {
+  async_connect *ac = acp;
+  int so_error = 0;
+  socklen_t so_error_size;
+  int err;
+  int fd = grpc_em_fd_get(&ac->fd);
+  grpc_em *em = grpc_em_fd_get_em(&ac->fd);
+
+  if (status == GRPC_CALLBACK_SUCCESS) {
+    do {
+      so_error_size = sizeof(so_error);
+      err = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size);
+    } while (err < 0 && errno == EINTR);
+    if (err < 0) {
+      gpr_log(GPR_ERROR, "getsockopt(ERROR): %s", strerror(errno));
+      goto error;
+    } else if (so_error != 0) {
+      if (so_error == ENOBUFS) {
+        /* We will get one of these errors if we have run out of
+           memory in the kernel for the data structures allocated
+           when you connect a socket.  If this happens it is very
+           likely that if we wait a little bit then try again the
+           connection will work (since other programs or this
+           program will close their network connections and free up
+           memory).  This does _not_ indicate that there is anything
+           wrong with the server we are connecting to, this is a
+           local problem.
+
+           If you are looking at this code, then chances are that
+           your program or another program on the same computer
+           opened too many network connections.  The "easy" fix:
+           don't do that! */
+        gpr_log(GPR_ERROR, "kernel out of buffers");
+        grpc_em_fd_notify_on_write(&ac->fd, on_writable, ac, ac->deadline);
+        return;
+      } else {
+        goto error;
+      }
+    } else {
+      goto great_success;
+    }
+  } else {
+    gpr_log(GPR_ERROR, "on_writable failed during connect: status=%d", status);
+    goto error;
+  }
+
+  abort();
+
+error:
+  ac->cb(ac->cb_arg, NULL);
+  grpc_em_fd_destroy(&ac->fd);
+  gpr_free(ac);
+  close(fd);
+  return;
+
+great_success:
+  grpc_em_fd_destroy(&ac->fd);
+  ac->cb(ac->cb_arg, grpc_tcp_create(fd, em));
+  gpr_free(ac);
+}
+
+void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
+                             void *arg, grpc_em *em, struct sockaddr *addr,
+                             int len, gpr_timespec deadline) {
+  int fd = create_fd(addr->sa_family);
+  int err;
+  async_connect *ac;
+
+  if (fd < 0) {
+    cb(arg, NULL);
+    return;
+  }
+
+  do {
+    err = connect(fd, addr, len);
+  } while (err < 0 && errno == EINTR);
+
+  if (err >= 0) {
+    cb(arg, grpc_tcp_create(fd, em));
+    return;
+  }
+
+  if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
+    gpr_log(GPR_ERROR, "connect error: %s", strerror(errno));
+    close(fd);
+    cb(arg, NULL);
+    return;
+  }
+
+  ac = gpr_malloc(sizeof(async_connect));
+  ac->cb = cb;
+  ac->cb_arg = arg;
+  ac->deadline = deadline;
+  grpc_em_fd_init(&ac->fd, em, fd);
+  grpc_em_fd_notify_on_write(&ac->fd, on_writable, ac, deadline);
+}
diff --git a/src/core/endpoint/tcp_client.h b/src/core/endpoint/tcp_client.h
new file mode 100644
index 0000000..2a8b8ee
--- /dev/null
+++ b/src/core/endpoint/tcp_client.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_ENDPOINT_TCP_CLIENT_H__
+#define __GRPC_INTERNAL_ENDPOINT_TCP_CLIENT_H__
+
+#include "src/core/endpoint/tcp.h"
+#include <grpc/support/time.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+/* 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) */
+void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *tcp),
+                             void *arg, grpc_em *em, struct sockaddr *addr,
+                             int len, gpr_timespec deadline);
+
+#endif  /* __GRPC_INTERNAL_ENDPOINT_TCP_CLIENT_H__ */
diff --git a/src/core/endpoint/tcp_server.c b/src/core/endpoint/tcp_server.c
new file mode 100644
index 0000000..2f386ce
--- /dev/null
+++ b/src/core/endpoint/tcp_server.c
@@ -0,0 +1,282 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+#define _GNU_SOURCE
+#include "src/core/endpoint/tcp_server.h"
+
+#include <limits.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "src/core/endpoint/socket_utils.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+
+#define INIT_PORT_CAP 2
+#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
+
+static gpr_once s_init_max_accept_queue_size;
+static int s_max_accept_queue_size;
+
+/* one listening port */
+typedef struct {
+  int fd;
+  grpc_em_fd *emfd;
+  grpc_tcp_server *server;
+} server_port;
+
+/* the overall server */
+struct grpc_tcp_server {
+  grpc_em *em;
+  grpc_tcp_server_cb cb;
+  void *cb_arg;
+
+  gpr_mu mu;
+  gpr_cv cv;
+
+  /* active port count: how many ports are actually still listening */
+  int active_ports;
+
+  /* all listening ports */
+  server_port *ports;
+  size_t nports;
+  size_t port_capacity;
+};
+
+grpc_tcp_server *grpc_tcp_server_create(grpc_em *em) {
+  grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
+  gpr_mu_init(&s->mu);
+  gpr_cv_init(&s->cv);
+  s->active_ports = 0;
+  s->em = em;
+  s->cb = NULL;
+  s->cb_arg = NULL;
+  s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
+  s->nports = 0;
+  s->port_capacity = INIT_PORT_CAP;
+  return s;
+}
+
+void grpc_tcp_server_destroy(grpc_tcp_server *s) {
+  size_t i;
+  gpr_mu_lock(&s->mu);
+  /* shutdown all fd's */
+  for (i = 0; i < s->nports; i++) {
+    grpc_em_fd_shutdown(s->ports[i].emfd);
+  }
+  /* wait while that happens */
+  while (s->active_ports) {
+    gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future);
+  }
+  gpr_mu_unlock(&s->mu);
+
+  /* delete ALL the things */
+  for (i = 0; i < s->nports; i++) {
+    server_port *sp = &s->ports[i];
+    grpc_em_fd_destroy(sp->emfd);
+    gpr_free(sp->emfd);
+    close(sp->fd);
+  }
+  gpr_free(s->ports);
+  gpr_free(s);
+}
+
+/* get max listen queue size on linux */
+static void init_max_accept_queue_size() {
+  int n = SOMAXCONN;
+  char buf[64];
+  FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r");
+  if (fp == NULL) {
+    /* 2.4 kernel. */
+    s_max_accept_queue_size = SOMAXCONN;
+    return;
+  }
+  if (fgets(buf, sizeof buf, fp)) {
+    char *end;
+    long i = strtol(buf, &end, 10);
+    if (i > 0 && i <= INT_MAX && end && *end == 0) {
+      n = i;
+    }
+  }
+  fclose(fp);
+  s_max_accept_queue_size = n;
+
+  if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) {
+    gpr_log(GPR_INFO,
+            "Suspiciously small accept queue (%d) will probably lead to "
+            "connection drops",
+            s_max_accept_queue_size);
+  }
+}
+
+static int get_max_accept_queue_size() {
+  gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size);
+  return s_max_accept_queue_size;
+}
+
+/* create a socket to listen with */
+static int create_listening_socket(struct sockaddr *port, int len) {
+  int fd = socket(port->sa_family, SOCK_STREAM, 0);
+  if (fd < 0) {
+    gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
+    goto error;
+  }
+
+  if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) ||
+      !grpc_set_socket_low_latency(fd, 1) ||
+      !grpc_set_socket_reuse_addr(fd, 1)) {
+    gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
+            strerror(errno));
+    goto error;
+  }
+
+  if (bind(fd, port, len) < 0) {
+    gpr_log(GPR_ERROR, "bind: %s", strerror(errno));
+    goto error;
+  }
+
+  if (listen(fd, get_max_accept_queue_size()) < 0) {
+    gpr_log(GPR_ERROR, "listen: %s", strerror(errno));
+    goto error;
+  }
+
+  return fd;
+
+error:
+  if (fd >= 0) {
+    close(fd);
+  }
+  return -1;
+}
+
+/* event manager callback when reads are ready */
+static void on_read(void *arg, grpc_em_cb_status status) {
+  server_port *sp = arg;
+
+  if (status != GRPC_CALLBACK_SUCCESS) {
+    goto error;
+  }
+
+  /* loop until accept4 returns EAGAIN, and then re-arm notification */
+  for (;;) {
+    struct sockaddr_storage addr;
+    socklen_t addrlen = sizeof(addr);
+    int fd = grpc_accept4(sp->fd, (struct sockaddr *)&addr, &addrlen, 1, 1);
+    if (fd < 0) {
+      switch (errno) {
+        case EINTR:
+          continue;
+        case EAGAIN:
+          if (GRPC_EM_OK != grpc_em_fd_notify_on_read(sp->emfd, on_read, sp,
+                                                      gpr_inf_future)) {
+            gpr_log(GPR_ERROR, "Failed to register read request with em");
+            goto error;
+          }
+          return;
+        default:
+          gpr_log(GPR_ERROR, "Failed accept4: %s", strerror(errno));
+          goto error;
+      }
+    }
+
+    sp->server->cb(sp->server->cb_arg, grpc_tcp_create(fd, sp->server->em));
+  }
+
+  abort();
+
+error:
+  gpr_mu_lock(&sp->server->mu);
+  if (0 == --sp->server->active_ports) {
+    gpr_cv_broadcast(&sp->server->cv);
+  }
+  gpr_mu_unlock(&sp->server->mu);
+}
+
+int grpc_tcp_server_add_port(grpc_tcp_server *s, struct sockaddr *port,
+                             int len) {
+  server_port *sp;
+  /* create a socket */
+  int fd = create_listening_socket(port, len);
+  if (fd < 0) {
+    return -1;
+  }
+
+  gpr_mu_lock(&s->mu);
+  GPR_ASSERT(!s->cb && "must add ports before starting server");
+  /* append it to the list under a lock */
+  if (s->nports == s->port_capacity) {
+    s->port_capacity *= 2;
+    s->ports = gpr_realloc(s->ports, sizeof(server_port *) * s->port_capacity);
+  }
+  sp = &s->ports[s->nports++];
+  sp->emfd = gpr_malloc(sizeof(grpc_em_fd));
+  sp->fd = fd;
+  sp->server = s;
+  /* initialize the em desc */
+  if (GRPC_EM_OK != grpc_em_fd_init(sp->emfd, s->em, fd)) {
+    grpc_em_fd_destroy(sp->emfd);
+    gpr_free(sp->emfd);
+    s->nports--;
+    gpr_mu_unlock(&s->mu);
+    return -1;
+  }
+  gpr_mu_unlock(&s->mu);
+
+  return fd;
+}
+
+void grpc_tcp_server_start(grpc_tcp_server *s, grpc_tcp_server_cb cb,
+                           void *cb_arg) {
+  size_t i;
+  GPR_ASSERT(cb);
+  gpr_mu_lock(&s->mu);
+  GPR_ASSERT(!s->cb);
+  GPR_ASSERT(s->active_ports == 0);
+  s->cb = cb;
+  s->cb_arg = cb_arg;
+  for (i = 0; i < s->nports; i++) {
+    grpc_em_fd_notify_on_read(s->ports[i].emfd, on_read, &s->ports[i],
+                              gpr_inf_future);
+    s->active_ports++;
+  }
+  gpr_mu_unlock(&s->mu);
+}
diff --git a/src/core/endpoint/tcp_server.h b/src/core/endpoint/tcp_server.h
new file mode 100644
index 0000000..99cb83e
--- /dev/null
+++ b/src/core/endpoint/tcp_server.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_ENDPOINT_TCP_SERVER_H__
+#define __GRPC_INTERNAL_ENDPOINT_TCP_SERVER_H__
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "src/core/endpoint/tcp.h"
+#include "src/core/eventmanager/em.h"
+
+/* Forward decl of grpc_tcp_server */
+typedef struct grpc_tcp_server grpc_tcp_server;
+
+/* New server callback: tcp is the newly connected tcp connection */
+typedef void (*grpc_tcp_server_cb)(void *arg, grpc_endpoint *ep);
+
+/* Create a server, initially not bound to any ports */
+grpc_tcp_server *grpc_tcp_server_create(grpc_em *em);
+
+/* Start listening to bound ports */
+void grpc_tcp_server_start(grpc_tcp_server *server, grpc_tcp_server_cb cb,
+                           void *cb_arg);
+
+/* Add a port to the server, returns a file descriptor on success, or <0 on
+   failure; the file descriptor remains owned by the server and will be cleaned
+   up when grpc_tcp_server_destroy is called */
+int grpc_tcp_server_add_port(grpc_tcp_server *server, struct sockaddr *port,
+                             int len);
+
+void grpc_tcp_server_destroy(grpc_tcp_server *server);
+
+#endif  /* __GRPC_INTERNAL_ENDPOINT_TCP_SERVER_H__ */
diff --git a/src/core/eventmanager/em.c b/src/core/eventmanager/em.c
new file mode 100644
index 0000000..e02d56c
--- /dev/null
+++ b/src/core/eventmanager/em.c
@@ -0,0 +1,664 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/eventmanager/em.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <grpc/support/atm.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+#include <event2/event.h>
+#include <event2/thread.h>
+
+int evthread_use_threads(void);
+
+#define ALARM_TRIGGER_INIT ((gpr_atm)0)
+#define ALARM_TRIGGER_INCREMENT ((gpr_atm)1)
+#define DONE_SHUTDOWN ((void *)1)
+
+#define POLLER_ID_INVALID ((gpr_atm)-1)
+
+/* ================== grpc_em implementation ===================== */
+
+/* If anything is in the work queue, process one item and return 1.
+   Return 0 if there were no work items to complete.
+   Requires em->mu locked, may unlock and relock during the call. */
+static int maybe_do_queue_work(grpc_em *em) {
+  grpc_em_activation_data *work = em->q;
+
+  if (work == NULL) return 0;
+
+  if (work->next == work) {
+    em->q = NULL;
+  } else {
+    em->q = work->next;
+    em->q->prev = work->prev;
+    em->q->next->prev = em->q->prev->next = em->q;
+  }
+  work->next = work->prev = NULL;
+  gpr_mu_unlock(&em->mu);
+
+  work->cb(work->arg, work->status);
+
+  gpr_mu_lock(&em->mu);
+  return 1;
+}
+
+/* Break out of the event loop on timeout */
+static void timer_callback(int fd, short events, void *context) {
+  event_base_loopbreak((struct event_base *)context);
+}
+
+/* Spend some time polling if no other thread is.
+   Returns 1 if polling was performed, 0 otherwise.
+   Requires em->mu locked, may unlock and relock during the call. */
+static int maybe_do_polling_work(grpc_em *em, struct timeval delay) {
+  int status;
+
+  if (em->num_pollers) return 0;
+
+  em->num_pollers = 1;
+  gpr_mu_unlock(&em->mu);
+
+  event_add(em->timeout_ev, &delay);
+  status = event_base_loop(em->event_base, EVLOOP_ONCE);
+  if (status < 0) {
+    gpr_log(GPR_ERROR, "event polling loop stops with error status %d", status);
+  }
+  event_del(em->timeout_ev);
+
+  gpr_mu_lock(&em->mu);
+  em->num_pollers = 0;
+  gpr_cv_broadcast(&em->cv);
+  return 1;
+}
+
+int grpc_em_work(grpc_em *em, gpr_timespec deadline) {
+  gpr_timespec delay_timespec = gpr_time_sub(deadline, gpr_now());
+  /* poll for no longer than one second */
+  gpr_timespec max_delay = {1, 0};
+  struct timeval delay;
+
+  GPR_ASSERT(em);
+
+  if (gpr_time_cmp(delay_timespec, gpr_time_0) <= 0) {
+    return 0;
+  }
+
+  if (gpr_time_cmp(delay_timespec, max_delay) > 0) {
+    delay_timespec = max_delay;
+  }
+
+  delay = gpr_timeval_from_timespec(delay_timespec);
+
+  if (maybe_do_queue_work(em) || maybe_do_polling_work(em, delay)) {
+    em->last_poll_completed = gpr_now();
+    return 1;
+  }
+
+  return 0;
+}
+
+static void backup_poller_thread(void *p) {
+  grpc_em *em = p;
+  int backup_poller_engaged = 0;
+  /* allow no pollers for 100 milliseconds, then engage backup polling */
+  gpr_timespec allow_no_pollers = gpr_time_from_micros(100 * 1000);
+
+  gpr_mu_lock(&em->mu);
+  while (!em->shutdown_backup_poller) {
+    if (em->num_pollers == 0) {
+      gpr_timespec now = gpr_now();
+      gpr_timespec time_until_engage = gpr_time_sub(
+          allow_no_pollers, gpr_time_sub(now, em->last_poll_completed));
+      if (gpr_time_cmp(time_until_engage, gpr_time_0) <= 0) {
+        if (!backup_poller_engaged) {
+          gpr_log(GPR_DEBUG, "No pollers for a while - engaging backup poller");
+          backup_poller_engaged = 1;
+        }
+        if (!maybe_do_queue_work(em)) {
+          struct timeval tv = {1, 0};
+          maybe_do_polling_work(em, tv);
+        }
+      } else {
+        if (backup_poller_engaged) {
+          gpr_log(GPR_DEBUG, "Backup poller disengaged");
+          backup_poller_engaged = 0;
+        }
+        gpr_mu_unlock(&em->mu);
+        gpr_sleep_until(gpr_time_add(now, time_until_engage));
+        gpr_mu_lock(&em->mu);
+      }
+    } else {
+      if (backup_poller_engaged) {
+        gpr_log(GPR_DEBUG, "Backup poller disengaged");
+        backup_poller_engaged = 0;
+      }
+      gpr_cv_wait(&em->cv, &em->mu, gpr_inf_future);
+    }
+  }
+  gpr_mu_unlock(&em->mu);
+
+  gpr_event_set(&em->backup_poller_done, (void *)1);
+}
+
+grpc_em_error grpc_em_init(grpc_em *em) {
+  gpr_thd_id backup_poller_id;
+
+  if (evthread_use_threads() != 0) {
+    gpr_log(GPR_ERROR, "Failed to initialize libevent thread support!");
+    return GRPC_EM_ERROR;
+  }
+
+  gpr_mu_init(&em->mu);
+  gpr_cv_init(&em->cv);
+  em->q = NULL;
+  em->num_pollers = 0;
+  em->num_fds = 0;
+  em->last_poll_completed = gpr_now();
+  em->shutdown_backup_poller = 0;
+
+  gpr_event_init(&em->backup_poller_done);
+
+  em->event_base = NULL;
+  em->timeout_ev = NULL;
+
+  em->event_base = event_base_new();
+  if (!em->event_base) {
+    gpr_log(GPR_ERROR, "Failed to create the event base");
+    return GRPC_EM_ERROR;
+  }
+
+  if (evthread_make_base_notifiable(em->event_base) != 0) {
+    gpr_log(GPR_ERROR, "Couldn't make event base notifiable cross threads!");
+    return GRPC_EM_ERROR;
+  }
+
+  em->timeout_ev = evtimer_new(em->event_base, timer_callback, em->event_base);
+
+  gpr_thd_new(&backup_poller_id, backup_poller_thread, em, NULL);
+
+  return GRPC_EM_OK;
+}
+
+grpc_em_error grpc_em_destroy(grpc_em *em) {
+  gpr_timespec fd_shutdown_deadline =
+      gpr_time_add(gpr_now(), gpr_time_from_micros(10 * 1000 * 1000));
+
+  /* broadcast shutdown */
+  gpr_mu_lock(&em->mu);
+  while (em->num_fds) {
+    gpr_log(GPR_INFO,
+            "waiting for %d fds to be destroyed before closing event manager",
+            em->num_fds);
+    if (gpr_cv_wait(&em->cv, &em->mu, fd_shutdown_deadline)) {
+      gpr_log(GPR_ERROR,
+              "not all fds destroyed before shutdown deadline: memory leaks "
+              "are likely");
+      break;
+    } else if (em->num_fds == 0) {
+      gpr_log(GPR_INFO, "all fds closed");
+    }
+  }
+
+  em->shutdown_backup_poller = 1;
+  gpr_cv_broadcast(&em->cv);
+  gpr_mu_unlock(&em->mu);
+
+  gpr_event_wait(&em->backup_poller_done, gpr_inf_future);
+
+  /* drain pending work */
+  gpr_mu_lock(&em->mu);
+  while (maybe_do_queue_work(em))
+    ;
+  gpr_mu_unlock(&em->mu);
+
+  /* complete shutdown */
+  gpr_mu_destroy(&em->mu);
+  gpr_cv_destroy(&em->cv);
+
+  if (em->timeout_ev != NULL) {
+    event_free(em->timeout_ev);
+  }
+
+  if (em->event_base != NULL) {
+    event_base_free(em->event_base);
+    em->event_base = NULL;
+  }
+
+  return GRPC_EM_OK;
+}
+
+static void add_task(grpc_em *em, grpc_em_activation_data *adata) {
+  gpr_mu_lock(&em->mu);
+  if (em->q) {
+    adata->next = em->q;
+    adata->prev = adata->next->prev;
+    adata->next->prev = adata->prev->next = adata;
+  } else {
+    em->q = adata;
+    adata->next = adata->prev = adata;
+  }
+  gpr_cv_broadcast(&em->cv);
+  gpr_mu_unlock(&em->mu);
+}
+
+/* ===============grpc_em_alarm implementation==================== */
+
+/* The following function frees up the alarm's libevent structure and
+   should always be invoked just before calling the alarm's callback */
+static void alarm_ev_destroy(grpc_em_alarm *alarm) {
+  grpc_em_activation_data *adata = &alarm->task.activation[GRPC_EM_TA_ONLY];
+  if (adata->ev != NULL) {
+    event_free(adata->ev);
+    adata->ev = NULL;
+  }
+}
+/* Proxy callback triggered by alarm->ev to call alarm->cb */
+static void libevent_alarm_cb(int fd, short what, void *arg /*=alarm*/) {
+  grpc_em_alarm *alarm = arg;
+  grpc_em_activation_data *adata = &alarm->task.activation[GRPC_EM_TA_ONLY];
+  int trigger_old;
+
+  /* First check if this alarm has been canceled, atomically */
+  trigger_old =
+      gpr_atm_full_fetch_add(&alarm->triggered, ALARM_TRIGGER_INCREMENT);
+  if (trigger_old == ALARM_TRIGGER_INIT) {
+    /* Before invoking user callback, destroy the libevent structure */
+    alarm_ev_destroy(alarm);
+    adata->status = GRPC_CALLBACK_SUCCESS;
+    add_task(alarm->task.em, adata);
+  }
+}
+
+grpc_em_error grpc_em_alarm_init(grpc_em_alarm *alarm, grpc_em *em,
+                                 grpc_em_cb_func alarm_cb, void *alarm_cb_arg) {
+  grpc_em_activation_data *adata = &alarm->task.activation[GRPC_EM_TA_ONLY];
+  alarm->task.type = GRPC_EM_TASK_ALARM;
+  alarm->task.em = em;
+  gpr_atm_rel_store(&alarm->triggered, ALARM_TRIGGER_INIT);
+  adata->cb = alarm_cb;
+  adata->arg = alarm_cb_arg;
+  adata->prev = NULL;
+  adata->next = NULL;
+  adata->ev = NULL;
+  return GRPC_EM_OK;
+}
+
+grpc_em_error grpc_em_alarm_add(grpc_em_alarm *alarm, gpr_timespec deadline) {
+  grpc_em_activation_data *adata = &alarm->task.activation[GRPC_EM_TA_ONLY];
+  gpr_timespec delay_timespec = gpr_time_sub(deadline, gpr_now());
+  struct timeval delay = gpr_timeval_from_timespec(delay_timespec);
+  if (adata->ev) {
+    event_free(adata->ev);
+    gpr_log(GPR_INFO, "Adding an alarm that already has an event.");
+    adata->ev = NULL;
+  }
+  adata->ev = evtimer_new(alarm->task.em->event_base, libevent_alarm_cb, alarm);
+  /* Set the trigger field to untriggered. Do this as the last store since
+     it is a release of previous stores. */
+  gpr_atm_rel_store(&alarm->triggered, ALARM_TRIGGER_INIT);
+
+  if (adata->ev != NULL && evtimer_add(adata->ev, &delay) == 0) {
+    return GRPC_EM_OK;
+  } else {
+    return GRPC_EM_ERROR;
+  }
+}
+
+grpc_em_error grpc_em_alarm_cancel(grpc_em_alarm *alarm, void **arg) {
+  grpc_em_activation_data *adata = &alarm->task.activation[GRPC_EM_TA_ONLY];
+  int trigger_old;
+
+  *arg = adata->arg;
+
+  /* First check if this alarm has been triggered, atomically */
+  trigger_old =
+      gpr_atm_full_fetch_add(&alarm->triggered, ALARM_TRIGGER_INCREMENT);
+  if (trigger_old == ALARM_TRIGGER_INIT) {
+    /* We need to make sure that we only invoke the callback if it hasn't
+       already been invoked */
+    /* First remove this event from libevent. This returns success even if the
+       event has gone active or invoked its callback. */
+    if (evtimer_del(adata->ev) != 0) {
+      /* The delete was unsuccessful for some reason. */
+      gpr_log(GPR_ERROR, "Attempt to delete alarm event was unsuccessful");
+      return GRPC_EM_ERROR;
+    }
+    /* Free up the event structure before invoking callback */
+    alarm_ev_destroy(alarm);
+    adata->status = GRPC_CALLBACK_CANCELLED;
+    add_task(alarm->task.em, adata);
+  }
+  return GRPC_EM_OK;
+}
+
+/* ==================== grpc_em_fd implementation =================== */
+
+/* Proxy callback to call a gRPC read/write callback */
+static void em_fd_cb(int fd, short what, void *arg /*=em_fd*/) {
+  grpc_em_fd *em_fd = arg;
+  grpc_em_cb_status status = GRPC_CALLBACK_SUCCESS;
+  int run_read_cb = 0;
+  int run_write_cb = 0;
+  grpc_em_activation_data *rdata, *wdata;
+
+  gpr_mu_lock(&em_fd->mu);
+  /* TODO(klempner): We need to delete the event here too so we avoid spurious
+     shutdowns. */
+  if (em_fd->shutdown_started) {
+    status = GRPC_CALLBACK_CANCELLED;
+  } else if (status == GRPC_CALLBACK_SUCCESS && (what & EV_TIMEOUT)) {
+    status = GRPC_CALLBACK_TIMED_OUT;
+    /* TODO(klempner): This is broken if we are monitoring both read and write
+       events on the same fd -- generating a spurious event is okay, but
+       generating a spurious timeout is not. */
+    what |= (EV_READ | EV_WRITE);
+  }
+
+  if (what & EV_READ) {
+    switch (em_fd->read_state) {
+      case GRPC_EM_FD_WAITING:
+        run_read_cb = 1;
+        em_fd->read_state = GRPC_EM_FD_IDLE;
+        break;
+      case GRPC_EM_FD_IDLE:
+      case GRPC_EM_FD_CACHED:
+        em_fd->read_state = GRPC_EM_FD_CACHED;
+    }
+  }
+  if (what & EV_WRITE) {
+    switch (em_fd->write_state) {
+      case GRPC_EM_FD_WAITING:
+        run_write_cb = 1;
+        em_fd->write_state = GRPC_EM_FD_IDLE;
+        break;
+      case GRPC_EM_FD_IDLE:
+      case GRPC_EM_FD_CACHED:
+        em_fd->write_state = GRPC_EM_FD_CACHED;
+    }
+  }
+
+  if (run_read_cb) {
+    rdata = &(em_fd->task.activation[GRPC_EM_TA_READ]);
+    rdata->status = status;
+    add_task(em_fd->task.em, rdata);
+  } else if (run_write_cb) {
+    wdata = &(em_fd->task.activation[GRPC_EM_TA_WRITE]);
+    wdata->status = status;
+    add_task(em_fd->task.em, wdata);
+  }
+  gpr_mu_unlock(&em_fd->mu);
+}
+
+static void em_fd_shutdown_cb(int fd, short what, void *arg /*=em_fd*/) {
+  /* TODO(klempner): This could just run directly in the calling thread, except
+     that libevent's handling of event_active() on an event which is already in
+     flight on a different thread is racy and easily triggers TSAN.
+   */
+  grpc_em_fd *em_fd = arg;
+  gpr_mu_lock(&em_fd->mu);
+  em_fd->shutdown_started = 1;
+  if (em_fd->read_state == GRPC_EM_FD_WAITING) {
+    event_active(em_fd->task.activation[GRPC_EM_TA_READ].ev, EV_READ, 1);
+  }
+  if (em_fd->write_state == GRPC_EM_FD_WAITING) {
+    event_active(em_fd->task.activation[GRPC_EM_TA_WRITE].ev, EV_WRITE, 1);
+  }
+  gpr_mu_unlock(&em_fd->mu);
+}
+
+grpc_em_error grpc_em_fd_init(grpc_em_fd *em_fd, grpc_em *em, int fd) {
+  int flags;
+  grpc_em_activation_data *rdata, *wdata;
+
+  gpr_mu_lock(&em->mu);
+  em->num_fds++;
+  gpr_mu_unlock(&em->mu);
+
+  em_fd->shutdown_ev = NULL;
+  gpr_mu_init(&em_fd->mu);
+
+  flags = fcntl(fd, F_GETFL, 0);
+  if ((flags & O_NONBLOCK) == 0) {
+    gpr_log(GPR_ERROR, "File descriptor %d is blocking", fd);
+    return GRPC_EM_INVALID_ARGUMENTS;
+  }
+
+  em_fd->task.type = GRPC_EM_TASK_FD;
+  em_fd->task.em = em;
+  em_fd->fd = fd;
+
+  rdata = &(em_fd->task.activation[GRPC_EM_TA_READ]);
+  rdata->ev = NULL;
+  rdata->cb = NULL;
+  rdata->arg = NULL;
+  rdata->status = GRPC_CALLBACK_SUCCESS;
+  rdata->prev = NULL;
+  rdata->next = NULL;
+
+  wdata = &(em_fd->task.activation[GRPC_EM_TA_WRITE]);
+  wdata->ev = NULL;
+  wdata->cb = NULL;
+  wdata->arg = NULL;
+  wdata->status = GRPC_CALLBACK_SUCCESS;
+  wdata->prev = NULL;
+  wdata->next = NULL;
+
+  em_fd->read_state = GRPC_EM_FD_IDLE;
+  em_fd->write_state = GRPC_EM_FD_IDLE;
+
+  /* TODO(chenw): detect platforms where only level trigger is supported,
+     and set the event to non-persist. */
+  rdata->ev = event_new(em->event_base, em_fd->fd, EV_ET | EV_PERSIST | EV_READ,
+                        em_fd_cb, em_fd);
+  if (!rdata->ev) {
+    gpr_log(GPR_ERROR, "Failed to create read event");
+    return GRPC_EM_ERROR;
+  }
+
+  wdata->ev = event_new(em->event_base, em_fd->fd,
+                        EV_ET | EV_PERSIST | EV_WRITE, em_fd_cb, em_fd);
+  if (!wdata->ev) {
+    gpr_log(GPR_ERROR, "Failed to create write event");
+    return GRPC_EM_ERROR;
+  }
+
+  em_fd->shutdown_ev =
+      event_new(em->event_base, -1, EV_READ, em_fd_shutdown_cb, em_fd);
+
+  if (!em_fd->shutdown_ev) {
+    gpr_log(GPR_ERROR, "Failed to create shutdown event");
+    return GRPC_EM_ERROR;
+  }
+
+  em_fd->shutdown_started = 0;
+  return GRPC_EM_OK;
+}
+
+void grpc_em_fd_destroy(grpc_em_fd *em_fd) {
+  grpc_em_task_activity_type type;
+  grpc_em_activation_data *adata;
+  grpc_em *em = em_fd->task.em;
+
+  /* ensure anyone holding the lock has left - it's the callers responsibility
+     to ensure that no new users enter */
+  gpr_mu_lock(&em_fd->mu);
+  gpr_mu_unlock(&em_fd->mu);
+
+  for (type = GRPC_EM_TA_READ; type < GRPC_EM_TA_COUNT; type++) {
+    adata = &(em_fd->task.activation[type]);
+    GPR_ASSERT(adata->next == NULL);
+    if (adata->ev != NULL) {
+      event_free(adata->ev);
+      adata->ev = NULL;
+    }
+  }
+
+  if (em_fd->shutdown_ev != NULL) {
+    event_free(em_fd->shutdown_ev);
+    em_fd->shutdown_ev = NULL;
+  }
+  gpr_mu_destroy(&em_fd->mu);
+
+  gpr_mu_lock(&em->mu);
+  em->num_fds--;
+  gpr_cv_broadcast(&em->cv);
+  gpr_mu_unlock(&em->mu);
+}
+
+int grpc_em_fd_get(struct grpc_em_fd *em_fd) { return em_fd->fd; }
+
+/* Returns the event manager associated with *em_fd. */
+grpc_em *grpc_em_fd_get_em(grpc_em_fd *em_fd) { return em_fd->task.em; }
+
+/* TODO(chenw): should we enforce the contract that notify_on_read cannot be
+   called when the previously registered callback has not been called yet. */
+grpc_em_error grpc_em_fd_notify_on_read(grpc_em_fd *em_fd,
+                                        grpc_em_cb_func read_cb,
+                                        void *read_cb_arg,
+                                        gpr_timespec deadline) {
+  int force_event = 0;
+  grpc_em_activation_data *rdata;
+  grpc_em_error result = GRPC_EM_OK;
+  gpr_timespec delay_timespec = gpr_time_sub(deadline, gpr_now());
+  struct timeval delay = gpr_timeval_from_timespec(delay_timespec);
+  struct timeval *delayp =
+      gpr_time_cmp(deadline, gpr_inf_future) ? &delay : NULL;
+
+  rdata = &em_fd->task.activation[GRPC_EM_TA_READ];
+
+  gpr_mu_lock(&em_fd->mu);
+  rdata->cb = read_cb;
+  rdata->arg = read_cb_arg;
+
+  force_event =
+      (em_fd->shutdown_started || em_fd->read_state == GRPC_EM_FD_CACHED);
+  em_fd->read_state = GRPC_EM_FD_WAITING;
+
+  if (force_event) {
+    event_active(rdata->ev, EV_READ, 1);
+  } else if (event_add(rdata->ev, delayp) == -1) {
+    result = GRPC_EM_ERROR;
+  }
+  gpr_mu_unlock(&em_fd->mu);
+  return result;
+}
+
+grpc_em_error grpc_em_fd_notify_on_write(grpc_em_fd *em_fd,
+                                         grpc_em_cb_func write_cb,
+                                         void *write_cb_arg,
+                                         gpr_timespec deadline) {
+  int force_event = 0;
+  grpc_em_activation_data *wdata;
+  grpc_em_error result = GRPC_EM_OK;
+  gpr_timespec delay_timespec = gpr_time_sub(deadline, gpr_now());
+  struct timeval delay = gpr_timeval_from_timespec(delay_timespec);
+  struct timeval *delayp =
+      gpr_time_cmp(deadline, gpr_inf_future) ? &delay : NULL;
+
+  wdata = &em_fd->task.activation[GRPC_EM_TA_WRITE];
+
+  gpr_mu_lock(&em_fd->mu);
+  wdata->cb = write_cb;
+  wdata->arg = write_cb_arg;
+
+  force_event =
+      (em_fd->shutdown_started || em_fd->write_state == GRPC_EM_FD_CACHED);
+  em_fd->write_state = GRPC_EM_FD_WAITING;
+
+  if (force_event) {
+    event_active(wdata->ev, EV_WRITE, 1);
+  } else if (event_add(wdata->ev, delayp) == -1) {
+    result = GRPC_EM_ERROR;
+  }
+  gpr_mu_unlock(&em_fd->mu);
+  return result;
+}
+
+void grpc_em_fd_shutdown(grpc_em_fd *em_fd) {
+  event_active(em_fd->shutdown_ev, EV_READ, 1);
+}
+
+/*====================== Other callback functions ======================*/
+
+/* Sometimes we want a followup callback: something to be added from the
+   current callback for the EM to invoke once this callback is complete.
+   This is implemented by inserting an entry into an EM queue. */
+
+/* The following structure holds the field needed for adding the
+   followup callback. These are the argument for the followup callback,
+   the function to use for the followup callback, and the
+   activation data pointer used for the queues (to free in the CB) */
+struct followup_callback_arg {
+  grpc_em_cb_func func;
+  void *cb_arg;
+  grpc_em_activation_data adata;
+};
+
+static void followup_proxy_callback(void *cb_arg, grpc_em_cb_status status) {
+  struct followup_callback_arg *fcb_arg = cb_arg;
+  /* Invoke the function */
+  fcb_arg->func(fcb_arg->cb_arg, status);
+  gpr_free(fcb_arg);
+}
+
+grpc_em_error grpc_em_add_callback(grpc_em *em, grpc_em_cb_func cb,
+                                   void *cb_arg) {
+  grpc_em_activation_data *adptr;
+  struct followup_callback_arg *fcb_arg;
+
+  fcb_arg = gpr_malloc(sizeof(*fcb_arg));
+  if (fcb_arg == NULL) {
+    return GRPC_EM_ERROR;
+  }
+  /* Set up the activation data and followup callback argument structures */
+  adptr = &fcb_arg->adata;
+  adptr->ev = NULL;
+  adptr->cb = followup_proxy_callback;
+  adptr->arg = fcb_arg;
+  adptr->status = GRPC_CALLBACK_SUCCESS;
+  adptr->prev = NULL;
+  adptr->next = NULL;
+
+  fcb_arg->func = cb;
+  fcb_arg->cb_arg = cb_arg;
+
+  /* Insert an activation data for the specified em */
+  add_task(em, adptr);
+  return GRPC_EM_OK;
+}
diff --git a/src/core/eventmanager/em.h b/src/core/eventmanager/em.h
new file mode 100644
index 0000000..32d37a5
--- /dev/null
+++ b/src/core/eventmanager/em.h
@@ -0,0 +1,350 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_EVENTMANAGER_EM_H__
+#define __GRPC_INTERNAL_EVENTMANAGER_EM_H__
+/* grpc_em is an event manager wrapping event loop with multithread support.
+   It executes a callback function when a specific event occurs on a file
+   descriptor or after a timeout has passed.
+   All methods are threadsafe and can be called from any thread.
+
+   To use the event manager, a grpc_em instance needs to be initialized to
+   maintains the internal states. The grpc_em instance can be used to
+   initialize file descriptor instance of grpc_em_fd, or alarm instance of
+   grpc_em_alarm. The former is used to register a callback with a IO event.
+   The later is used to schedule an alarm.
+
+   Instantiating any of these data structures requires including em_internal.h
+   A typical usage example is shown in the end of that header file.  */
+
+#include <grpc/support/atm.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+
+/* =============== Enums used in GRPC event manager API ==================== */
+
+/* Result of a grpc_em operation */
+typedef enum grpc_em_error {
+  GRPC_EM_OK = 0,           /* everything went ok */
+  GRPC_EM_ERROR,            /* internal errors not caused by the caller */
+  GRPC_EM_INVALID_ARGUMENTS /* invalid arguments from the caller */
+} grpc_em_error;
+
+/* Status passed to callbacks for grpc_em_fd_notify_on_read and
+   grpc_em_fd_notify_on_write.  */
+typedef enum grpc_em_cb_status {
+  GRPC_CALLBACK_SUCCESS = 0,
+  GRPC_CALLBACK_TIMED_OUT,
+  GRPC_CALLBACK_CANCELLED,
+  GRPC_CALLBACK_DO_NOT_USE
+} grpc_em_cb_status;
+
+/* ======= Useful forward struct typedefs for GRPC event manager API ======= */
+
+struct grpc_em;
+struct grpc_em_alarm;
+struct grpc_fd;
+
+typedef struct grpc_em grpc_em;
+typedef struct grpc_em_alarm grpc_em_alarm;
+typedef struct grpc_em_fd grpc_em_fd;
+
+/* gRPC Callback definition */
+typedef void (*grpc_em_cb_func)(void *arg, grpc_em_cb_status status);
+
+/* ============================ grpc_em =============================== */
+/* Initialize *em and start polling, return GRPC_EM_OK on success, return
+   GRPC_EM_ERROR on failure. Upon failure, caller should call grpc_em_destroy()
+   to clean partially initialized *em.
+
+   Requires:  *em uninitialized.  */
+grpc_em_error grpc_em_init(grpc_em *em);
+
+/* Stop polling and cause *em no longer to be initialized.
+   Return GRPC_EM_OK if event polling is cleanly stopped.
+   Otherwise, return GRPC_EM_ERROR if polling is shutdown with errors.
+   Requires: *em initialized; no other concurrent operation on *em.  */
+grpc_em_error grpc_em_destroy(grpc_em *em);
+
+/* do some work; assumes em->mu locked; may unlock and relock em->mu */
+int grpc_em_work(grpc_em *em, gpr_timespec deadline);
+
+/* =========================== grpc_em_am ============================== */
+/* Initialize *alarm. When expired or canceled, alarm_cb will be called with
+   *alarm_cb_arg and status to indicate if it expired (SUCCESS) or was
+   canceled (CANCELLED). alarm_cb is guaranteed to be called exactly once,
+   and application code should check the status to determine how it was
+   invoked. The application callback is also responsible for maintaining
+   information about when to free up any user-level state.  */
+grpc_em_error grpc_em_alarm_init(grpc_em_alarm *alarm, grpc_em *em,
+                                 grpc_em_cb_func alarm_cb, void *alarm_cb_arg);
+
+/* Note that there is no alarm destroy function. This is because the
+   alarm is a one-time occurrence with a guarantee that the callback will
+   be called exactly once, either at expiration or cancellation. Thus, all
+   the internal alarm event management state is destroyed just before
+   that callback is invoked. If the user has additional state associated with
+   the alarm, the user is responsible for determining when it is safe to
+   destroy that state. */
+
+/* Schedule *alarm to expire at deadline. If *alarm is
+   re-added before expiration, the *delay is simply reset to the new value.
+   Return GRPC_EM_OK on success, or GRPC_EM_ERROR on failure.
+   Upon failure, caller should abort further operations on *alarm */
+grpc_em_error grpc_em_alarm_add(grpc_em_alarm *alarm, gpr_timespec deadline);
+
+/* Cancel an *alarm.
+   There are three cases:
+   1. We normally cancel the alarm
+   2. The alarm has already run
+   3. We can't cancel the alarm because it is "in flight".
+
+   In all of these cases, the cancellation is still considered successful.
+   They are essentially distinguished in that the alarm_cb will be run
+   exactly once from either the cancellation (with status CANCELLED)
+   or from the activation (with status SUCCESS)
+
+   Requires:  cancel() must happen after add() on a given alarm */
+grpc_em_error grpc_em_alarm_cancel(grpc_em_alarm *alarm, void **arg);
+
+/* ========================== grpc_em_fd ============================= */
+
+/* Initialize *em_fd, return GRPM_EM_OK on success, GRPC_EM_ERROR on internal
+   errors, or GRPC_EM_INVALID_ARGUMENTS if fd is a blocking file descriptor.
+   Upon failure, caller should call grpc_em_fd_destroy() to clean partially
+   initialized *em_fd.
+   fd is a non-blocking file descriptor.
+
+   Requires:  *em_fd uninitialized. fd is a non-blocking file descriptor.  */
+grpc_em_error grpc_em_fd_init(grpc_em_fd *em_fd, grpc_em *em, int fd);
+
+/* Cause *em_fd no longer to be initialized.
+   Requires: *em_fd initialized; no outstanding notify_on_read or
+   notify_on_write.  */
+void grpc_em_fd_destroy(grpc_em_fd *em_fd);
+
+/* Returns the file descriptor associated with *em_fd. */
+int grpc_em_fd_get(grpc_em_fd *em_fd);
+
+/* Returns the event manager associated with *em_fd. */
+grpc_em *grpc_em_fd_get_em(grpc_em_fd *em_fd);
+
+/* Register read interest, causing read_cb to be called once when em_fd becomes
+   readable, on deadline specified by deadline, or on shutdown triggered by
+   grpc_em_fd_shutdown.
+   Return GRPC_EM_OK on success, or GRPC_EM_ERROR on failure.
+   Upon Failure, caller should abort further operations on *em_fd except
+   grpc_em_fd_shutdown().
+   read_cb will be called with read_cb_arg when *em_fd becomes readable.
+   read_cb is Called with status of GRPC_CALLBACK_SUCCESS if readable,
+   GRPC_CALLBACK_TIMED_OUT if the call timed out,
+   and CANCELLED if the call was cancelled.
+
+   Requires:This method must not be called before the read_cb for any previous
+   call runs. Edge triggered events are used whenever they are supported by the
+   underlying platform. This means that users must drain em_fd in read_cb before
+   calling notify_on_read again. Users are also expected to handle spurious
+   events, i.e read_cb is called while nothing can be readable from em_fd  */
+grpc_em_error grpc_em_fd_notify_on_read(grpc_em_fd *em_fd,
+                                        grpc_em_cb_func read_cb,
+                                        void *read_cb_arg,
+                                        gpr_timespec deadline);
+
+/* Exactly the same semantics as above, except based on writable events.  */
+grpc_em_error grpc_em_fd_notify_on_write(grpc_em_fd *fd,
+                                         grpc_em_cb_func write_cb,
+                                         void *write_cb_arg,
+                                         gpr_timespec deadline);
+
+/* Cause any current and all future read/write callbacks to error out with
+   GRPC_CALLBACK_CANCELLED. */
+void grpc_em_fd_shutdown(grpc_em_fd *em_fd);
+
+/* ================== Other functions =================== */
+
+/* This function is called from within a callback or from anywhere else
+   and causes the invocation of a callback at some point in the future */
+grpc_em_error grpc_em_add_callback(grpc_em *em, grpc_em_cb_func cb,
+                                   void *cb_arg);
+
+/* ========== Declarations related to queue management (non-API) =========== */
+
+/* Forward declarations */
+struct grpc_em_activation_data;
+
+/* ================== Actual structure definitions ========================= */
+/* gRPC event manager handle.
+   The handle is used to initialize both grpc_em_alarm and grpc_em_fd. */
+struct em_thread_arg;
+
+struct grpc_em {
+  struct event_base *event_base;
+
+  gpr_mu mu;
+  gpr_cv cv;
+  struct grpc_em_activation_data *q;
+  int num_pollers;
+  int num_fds;
+  gpr_timespec last_poll_completed;
+
+  int shutdown_backup_poller;
+  gpr_event backup_poller_done;
+
+  struct event *timeout_ev; /* activated to break out of the event loop early */
+};
+
+/* gRPC event manager task "base class". This is pretend-inheritance in C89.
+   This should be the first member of any actual grpc_em task type.
+
+   Memory warning: expanding this will increase memory usage in any derived
+   class, so be careful.
+
+   For generality, this base can be on multiple task queues and can have
+   multiple event callbacks registered. Not all "derived classes" will use
+   this feature. */
+
+typedef enum grpc_em_task_type {
+  GRPC_EM_TASK_ALARM,
+  GRPC_EM_TASK_FD,
+  GRPC_EM_TASK_DO_NOT_USE
+} grpc_em_task_type;
+
+/* Different activity types to shape the callback and queueing arrays */
+typedef enum grpc_em_task_activity_type {
+  GRPC_EM_TA_READ, /* use this also for single-type events */
+  GRPC_EM_TA_WRITE,
+  GRPC_EM_TA_COUNT
+} grpc_em_task_activity_type;
+
+/* Include the following #define for convenience for tasks like alarms that
+   only have a single type */
+#define GRPC_EM_TA_ONLY GRPC_EM_TA_READ
+
+typedef struct grpc_em_activation_data {
+  struct event *ev;   /* event activated on this callback type */
+  grpc_em_cb_func cb; /* function pointer for callback */
+  void *arg;          /* argument passed to cb */
+
+  /* Hold the status associated with the callback when queued */
+  grpc_em_cb_status status;
+  /* Now set up to link activations into scheduler queues */
+  struct grpc_em_activation_data *prev;
+  struct grpc_em_activation_data *next;
+} grpc_em_activation_data;
+
+typedef struct grpc_em_task {
+  grpc_em_task_type type;
+  grpc_em *em;
+
+  /* Now have an array of activation data elements: one for each activity
+     type that could get activated */
+  grpc_em_activation_data activation[GRPC_EM_TA_COUNT];
+} grpc_em_task;
+
+/* gRPC alarm handle.
+   The handle is used to add an alarm which expires after specified timeout. */
+struct grpc_em_alarm {
+  grpc_em_task task; /* Include the base class */
+
+  gpr_atm triggered; /* To be used atomically if alarm triggered */
+};
+
+/* =================== Event caching ===================
+   In order to not miss or double-return edges in the context of edge triggering
+   and multithreading, we need a per-fd caching layer in the eventmanager itself
+   to cache relevant events.
+
+   There are two types of events we care about: calls to notify_on_[read|write]
+   and readable/writable events for the socket from eventfd. There are separate
+   event caches for read and write.
+
+   There are three states:
+   0. "waiting" -- There's been a call to notify_on_[read|write] which has not
+   had a corresponding event. In other words, we're waiting for an event so we
+   can run the callback.
+   1. "idle" -- We are neither waiting nor have a cached event.
+   2. "cached" -- There has been a read/write event without a waiting callback,
+   so we want to run the event next time the application calls
+   notify_on_[read|write].
+
+   The high level state diagram:
+
+   +--------------------------------------------------------------------+
+   | WAITING                  | IDLE                | CACHED            |
+   |                          |                     |                   |
+   |                     1. --*->              2. --+->           3.  --+\
+   |                          |                     |                <--+/
+   |                          |                     |                   |
+  x+-- 6.                5. <-+--              4. <-*--                 |
+   |                          |                     |                   |
+   +--------------------------------------------------------------------+
+
+   Transitions right occur on read|write events. Transitions left occur on
+   notify_on_[read|write] events.
+   State transitions:
+   1. Read|Write event while waiting -> run the callback and transition to idle.
+   2. Read|Write event while idle -> transition to cached.
+   3. Read|Write event with one already cached -> still cached.
+   4. notify_on_[read|write] with event cached: run callback and transition to
+      idle.
+   5. notify_on_[read|write] when idle: Store callback and transition to
+      waiting.
+   6. notify_on_[read|write] when waiting: invalid. */
+
+typedef enum grpc_em_fd_state {
+  GRPC_EM_FD_WAITING = 0,
+  GRPC_EM_FD_IDLE = 1,
+  GRPC_EM_FD_CACHED = 2
+} grpc_em_fd_state;
+
+/* gRPC file descriptor handle.
+   The handle is used to register read/write callbacks to a file descriptor */
+struct grpc_em_fd {
+  grpc_em_task task; /* Base class, callbacks, queues, etc */
+  int fd;            /* File descriptor */
+
+  /* Note that the shutdown event is only needed as a workaround for libevent
+     not properly handling event_active on an in flight event. */
+  struct event *shutdown_ev; /* activated to trigger shutdown */
+
+  /* protect shutdown_started|read_state|write_state and ensure barriers
+     between notify_on_[read|write] and read|write callbacks */
+  gpr_mu mu;
+  int shutdown_started; /* 0 -> shutdown not started, 1 -> started */
+  grpc_em_fd_state read_state;
+  grpc_em_fd_state write_state;
+  /* activated after some timeout to activate shutdown_ev */
+};
+
+#endif  /* __GRPC_INTERNAL_EVENTMANAGER_EM_H__ */
diff --git a/src/core/eventmanager/em_posix.c b/src/core/eventmanager/em_posix.c
new file mode 100644
index 0000000..af44934
--- /dev/null
+++ b/src/core/eventmanager/em_posix.c
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Posix grpc event manager support code. */
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <event2/thread.h>
+
+static int error_code = 0;
+static gpr_once threads_once = GPR_ONCE_INIT;
+static void evthread_threads_initialize(void) {
+  error_code = evthread_use_pthreads();
+  if (error_code) {
+    gpr_log(GPR_ERROR, "Failed to initialize libevent thread support!");
+  }
+}
+
+/* Notify LibEvent that Posix pthread is used. */
+int evthread_use_threads() {
+  gpr_once_init(&threads_once, &evthread_threads_initialize);
+  /* For Pthreads or Windows threads, Libevent provides simple APIs to set
+     mutexes and conditional variables to support cross thread operations.
+     For other platforms, LibEvent provide callback APIs to hook mutexes and
+     conditional variables. */
+  return error_code;
+}
diff --git a/src/core/eventmanager/em_win32.c b/src/core/eventmanager/em_win32.c
new file mode 100644
index 0000000..4d5c3b5
--- /dev/null
+++ b/src/core/eventmanager/em_win32.c
@@ -0,0 +1,38 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Windows event manager support code. */
+#include <event2/thread.h>
+
+/* Notify LibEvent that Windows thread is used. */
+int evthread_use_threads() { return evthread_use_windows_threads(); }
diff --git a/src/core/httpcli/format_request.c b/src/core/httpcli/format_request.c
new file mode 100644
index 0000000..7a44f12
--- /dev/null
+++ b/src/core/httpcli/format_request.c
@@ -0,0 +1,121 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/httpcli/format_request.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/useful.h>
+
+typedef struct {
+  size_t length;
+  size_t capacity;
+  char *data;
+} sbuf;
+
+static void sbuf_append(sbuf *buf, const char *bytes, size_t len) {
+  if (buf->length + len > buf->capacity) {
+    buf->capacity = GPR_MAX(buf->length + len, buf->capacity * 3 / 2);
+    buf->data = gpr_realloc(buf->data, buf->capacity);
+  }
+  memcpy(buf->data + buf->length, bytes, len);
+  buf->length += len;
+}
+
+static void sbprintf(sbuf *buf, const char *fmt, ...) {
+  char temp[GRPC_HTTPCLI_MAX_HEADER_LENGTH];
+  size_t len;
+  va_list args;
+
+  va_start(args, fmt);
+  len = vsprintf(temp, fmt, args);
+  va_end(args);
+
+  sbuf_append(buf, temp, len);
+}
+
+static void fill_common_header(const grpc_httpcli_request *request, sbuf *buf) {
+  size_t i;
+  sbprintf(buf, "%s HTTP/1.0\r\n", request->path);
+  /* just in case some crazy server really expects HTTP/1.1 */
+  sbprintf(buf, "Host: %s\r\n", request->host);
+  sbprintf(buf, "Connection: close\r\n");
+  sbprintf(buf, "User-Agent: %s\r\n", GRPC_HTTPCLI_USER_AGENT);
+  /* user supplied headers */
+  for (i = 0; i < request->hdr_count; i++) {
+    sbprintf(buf, "%s: %s\r\n", request->hdrs[i].key, request->hdrs[i].value);
+  }
+}
+
+gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request) {
+  sbuf out = {0, 0, NULL};
+
+  sbprintf(&out, "GET ");
+  fill_common_header(request, &out);
+  sbprintf(&out, "\r\n");
+
+  return gpr_slice_new(out.data, out.length, gpr_free);
+}
+
+gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
+                                           const char *body_bytes,
+                                           size_t body_size) {
+  sbuf out = {0, 0, NULL};
+  size_t i;
+
+  sbprintf(&out, "POST ");
+  fill_common_header(request, &out);
+  if (body_bytes) {
+    gpr_uint8 has_content_type = 0;
+    for (i = 0; i < request->hdr_count; i++) {
+      if (strcmp(request->hdrs[i].key, "Content-Type") == 0) {
+        has_content_type = 1;
+        break;
+      }
+    }
+    if (!has_content_type) {
+      sbprintf(&out, "Content-Type: text/plain\r\n");
+    }
+    sbprintf(&out, "Content-Length: %lu\r\n", (unsigned long)body_size);
+  }
+  sbprintf(&out, "\r\n");
+  if (body_bytes) {
+    sbuf_append(&out, body_bytes, body_size);
+  }
+
+  return gpr_slice_new(out.data, out.length, gpr_free);
+}
diff --git a/src/core/httpcli/format_request.h b/src/core/httpcli/format_request.h
new file mode 100644
index 0000000..988f872
--- /dev/null
+++ b/src/core/httpcli/format_request.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_HTTPCLI_FORMAT_REQUEST_H__
+#define __GRPC_INTERNAL_HTTPCLI_FORMAT_REQUEST_H__
+
+#include "src/core/httpcli/httpcli.h"
+#include <grpc/support/slice.h>
+
+gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request);
+gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
+                                           const char *body_bytes,
+                                           size_t body_size);
+
+#endif  /* __GRPC_INTERNAL_HTTPCLI_FORMAT_REQUEST_H__ */
diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c
new file mode 100644
index 0000000..6c0a688
--- /dev/null
+++ b/src/core/httpcli/httpcli.c
@@ -0,0 +1,259 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/httpcli/httpcli.h"
+
+#include <string.h>
+
+#include "src/core/endpoint/endpoint.h"
+#include "src/core/endpoint/resolve_address.h"
+#include "src/core/endpoint/tcp_client.h"
+#include "src/core/httpcli/format_request.h"
+#include "src/core/httpcli/httpcli_security_context.h"
+#include "src/core/httpcli/parser.h"
+#include "src/core/security/security_context.h"
+#include "src/core/security/google_root_certs.h"
+#include "src/core/security/secure_transport_setup.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+
+typedef struct {
+  gpr_slice request_text;
+  grpc_httpcli_parser parser;
+  grpc_resolved_addresses *addresses;
+  size_t next_address;
+  grpc_endpoint *ep;
+  grpc_em *em;
+  char *host;
+  gpr_timespec deadline;
+  int have_read_byte;
+  int use_ssl;
+  grpc_httpcli_response_cb on_response;
+  void *user_data;
+} internal_request;
+
+static void next_address(internal_request *req);
+
+static void finish(internal_request *req, int success) {
+  gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
+  req->on_response(req->user_data, success ? &req->parser.r : NULL);
+  grpc_httpcli_parser_destroy(&req->parser);
+  if (req->addresses != NULL) {
+    grpc_resolved_addresses_destroy(req->addresses);
+  }
+  if (req->ep != NULL) {
+    grpc_endpoint_destroy(req->ep);
+  }
+  gpr_slice_unref(req->request_text);
+  gpr_free(req->host);
+  gpr_free(req);
+}
+
+static void on_read(void *user_data, gpr_slice *slices, size_t nslices,
+                    grpc_endpoint_cb_status status) {
+  internal_request *req = user_data;
+  size_t i;
+
+  gpr_log(GPR_DEBUG, "%s nslices=%d status=%d", __FUNCTION__, nslices, status);
+
+  for (i = 0; i < nslices; i++) {
+    if (GPR_SLICE_LENGTH(slices[i])) {
+      req->have_read_byte = 1;
+      if (!grpc_httpcli_parser_parse(&req->parser, slices[i])) {
+        finish(req, 0);
+        goto done;
+      }
+    }
+  }
+
+  switch (status) {
+    case GRPC_ENDPOINT_CB_OK:
+      grpc_endpoint_notify_on_read(req->ep, on_read, req, gpr_inf_future);
+      break;
+    case GRPC_ENDPOINT_CB_EOF:
+    case GRPC_ENDPOINT_CB_ERROR:
+    case GRPC_ENDPOINT_CB_SHUTDOWN:
+    case GRPC_ENDPOINT_CB_TIMED_OUT:
+      if (!req->have_read_byte) {
+        next_address(req);
+      } else {
+        finish(req, grpc_httpcli_parser_eof(&req->parser));
+      }
+      break;
+  }
+
+done:
+  for (i = 0; i < nslices; i++) {
+    gpr_slice_unref(slices[i]);
+  }
+}
+
+static void on_written(internal_request *req) {
+  gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
+  grpc_endpoint_notify_on_read(req->ep, on_read, req, gpr_inf_future);
+}
+
+static void done_write(void *arg, grpc_endpoint_cb_status status) {
+  internal_request *req = arg;
+  gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
+  switch (status) {
+    case GRPC_ENDPOINT_CB_OK:
+      on_written(req);
+      break;
+    case GRPC_ENDPOINT_CB_EOF:
+    case GRPC_ENDPOINT_CB_SHUTDOWN:
+    case GRPC_ENDPOINT_CB_ERROR:
+    case GRPC_ENDPOINT_CB_TIMED_OUT:
+      next_address(req);
+      break;
+  }
+}
+
+static void start_write(internal_request *req) {
+  gpr_slice_ref(req->request_text);
+  gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
+  switch (grpc_endpoint_write(req->ep, &req->request_text, 1, done_write, req,
+                              gpr_inf_future)) {
+    case GRPC_ENDPOINT_WRITE_DONE:
+      on_written(req);
+      break;
+    case GRPC_ENDPOINT_WRITE_PENDING:
+      break;
+    case GRPC_ENDPOINT_WRITE_ERROR:
+      finish(req, 0);
+      break;
+  }
+}
+
+static void on_secure_transport_setup_done(void *rp,
+                                           grpc_security_status status,
+                                           grpc_endpoint *secure_endpoint) {
+  internal_request *req = rp;
+  gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
+  if (status != GRPC_SECURITY_OK) {
+    gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status);
+    finish(req, 0);
+  } else {
+    req->ep = secure_endpoint;
+    start_write(req);
+  }
+}
+
+static void on_connected(void *arg, grpc_endpoint *tcp) {
+  internal_request *req = arg;
+
+  gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
+  if (!tcp) {
+    next_address(req);
+    return;
+  }
+  req->ep = tcp;
+  if (req->use_ssl) {
+    grpc_channel_security_context *ctx = NULL;
+    GPR_ASSERT(grpc_httpcli_ssl_channel_security_context_create(
+                   grpc_google_root_certs, grpc_google_root_certs_size,
+                   req->host, &ctx) == GRPC_SECURITY_OK);
+    grpc_setup_secure_transport(&ctx->base, tcp, on_secure_transport_setup_done,
+                                req);
+    grpc_security_context_unref(&ctx->base);
+  } else {
+    start_write(req);
+  }
+}
+
+static void next_address(internal_request *req) {
+  grpc_resolved_address *addr;
+  gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
+  if (req->next_address == req->addresses->naddrs) {
+    finish(req, 0);
+    return;
+  }
+  addr = &req->addresses->addrs[req->next_address++];
+  grpc_tcp_client_connect(on_connected, req, req->em,
+                          (struct sockaddr *)&addr->addr, addr->len,
+                          req->deadline);
+}
+
+static void on_resolved(void *arg, grpc_resolved_addresses *addresses) {
+  internal_request *req = arg;
+  gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
+  if (!addresses) {
+    finish(req, 0);
+  }
+  req->addresses = addresses;
+  req->next_address = 0;
+  next_address(req);
+}
+
+void grpc_httpcli_get(const grpc_httpcli_request *request,
+                      gpr_timespec deadline, grpc_em *em,
+                      grpc_httpcli_response_cb on_response, void *user_data) {
+  internal_request *req = gpr_malloc(sizeof(internal_request));
+  memset(req, 0, sizeof(*req));
+  req->request_text = grpc_httpcli_format_get_request(request);
+  grpc_httpcli_parser_init(&req->parser);
+  req->on_response = on_response;
+  req->user_data = user_data;
+  req->em = em;
+  req->deadline = deadline;
+  req->use_ssl = request->use_ssl;
+  if (req->use_ssl) {
+    req->host = gpr_strdup(request->host);
+  }
+
+  grpc_resolve_address(request->host, req->use_ssl ? "https" : "http",
+                       on_resolved, req);
+}
+
+void grpc_httpcli_post(const grpc_httpcli_request *request,
+                       const char *body_bytes, size_t body_size,
+                       gpr_timespec deadline, grpc_em *em,
+                       grpc_httpcli_response_cb on_response, void *user_data) {
+  internal_request *req = gpr_malloc(sizeof(internal_request));
+  memset(req, 0, sizeof(*req));
+  req->request_text =
+      grpc_httpcli_format_post_request(request, body_bytes, body_size);
+  grpc_httpcli_parser_init(&req->parser);
+  req->on_response = on_response;
+  req->user_data = user_data;
+  req->em = em;
+  req->deadline = deadline;
+  req->use_ssl = request->use_ssl;
+  if (req->use_ssl) {
+    req->host = gpr_strdup(request->host);
+  }
+
+  grpc_resolve_address(request->host, req->use_ssl ? "https" : "http",
+                       on_resolved, req);
+}
diff --git a/src/core/httpcli/httpcli.h b/src/core/httpcli/httpcli.h
new file mode 100644
index 0000000..aef0edf
--- /dev/null
+++ b/src/core/httpcli/httpcli.h
@@ -0,0 +1,104 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_HTTPCLI_HTTPCLI_H__
+#define __GRPC_INTERNAL_HTTPCLI_HTTPCLI_H__
+
+#include <stddef.h>
+
+#include "src/core/eventmanager/em.h"
+#include <grpc/support/time.h>
+
+/* User agent this library reports */
+#define GRPC_HTTPCLI_USER_AGENT "grpc-httpcli/0.0"
+/* Maximum length of a header string of the form 'Key: Value\r\n' */
+#define GRPC_HTTPCLI_MAX_HEADER_LENGTH 4096
+
+/* A single header to be passed in a request */
+typedef struct grpc_httpcli_header {
+  char *key;
+  char *value;
+} grpc_httpcli_header;
+
+/* A request */
+typedef struct grpc_httpcli_request {
+  /* The host name to connect to */
+  char *host;
+  /* The path of the resource to fetch */
+  char *path;
+  /* Additional headers: count and key/values; the following are supplied
+     automatically and MUST NOT be set here:
+       Host, Connection, User-Agent */
+  size_t hdr_count;
+  grpc_httpcli_header *hdrs;
+  /* whether to use ssl for the request */
+  int use_ssl;
+} grpc_httpcli_request;
+
+/* A response */
+typedef struct grpc_httpcli_response {
+  /* HTTP status code */
+  int status;
+  /* Headers: count and key/values */
+  size_t hdr_count;
+  grpc_httpcli_header *hdrs;
+  /* Body: length and contents; contents are NOT null-terminated */
+  size_t body_length;
+  char *body;
+} grpc_httpcli_response;
+
+/* Callback for grpc_httpcli_get */
+typedef void (*grpc_httpcli_response_cb)(void *user_data,
+                                         const grpc_httpcli_response *response);
+
+/* Asynchronously perform a HTTP GET.
+   'request' contains request parameters - these are caller owned and can be
+     destroyed once the call returns
+   'deadline' contains a deadline for the request (or gpr_inf_future)
+   'em' points to a caller owned event manager that must be alive for the
+     lifetime of the request
+   'on_response' is a callback to report results to (and 'user_data' is a user
+     supplied pointer to pass to said call) */
+void grpc_httpcli_get(const grpc_httpcli_request *request,
+                      gpr_timespec deadline, grpc_em *em,
+                      grpc_httpcli_response_cb on_response, void *user_data);
+
+/* Asynchronously perform a HTTP POST.
+   When there is no body, pass in NULL as body_bytes.
+   Does not support ?var1=val1&var2=val2 in the path. */
+void grpc_httpcli_post(const grpc_httpcli_request *request,
+                       const char *body_bytes, size_t body_size,
+                       gpr_timespec deadline, grpc_em *em,
+                       grpc_httpcli_response_cb on_response, void *user_data);
+
+#endif  /* __GRPC_INTERNAL_HTTPCLI_HTTPCLI_H__ */
diff --git a/src/core/httpcli/httpcli_security_context.c b/src/core/httpcli/httpcli_security_context.c
new file mode 100644
index 0000000..c7b9b33
--- /dev/null
+++ b/src/core/httpcli/httpcli_security_context.c
@@ -0,0 +1,128 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/httpcli/httpcli_security_context.h"
+
+#include <string.h>
+
+#include "src/core/security/secure_transport_setup.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+#include "src/core/tsi/ssl_transport_security.h"
+
+typedef struct {
+  grpc_channel_security_context base;
+  tsi_ssl_handshaker_factory *handshaker_factory;
+  char *secure_peer_name;
+} grpc_httpcli_ssl_channel_security_context;
+
+static void httpcli_ssl_destroy(grpc_security_context *ctx) {
+  grpc_httpcli_ssl_channel_security_context *c =
+      (grpc_httpcli_ssl_channel_security_context *)ctx;
+  if (c->handshaker_factory != NULL) {
+    tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
+  }
+  if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name);
+  gpr_free(ctx);
+}
+
+static grpc_security_status httpcli_ssl_create_handshaker(
+    grpc_security_context *ctx, tsi_handshaker **handshaker) {
+  grpc_httpcli_ssl_channel_security_context *c =
+      (grpc_httpcli_ssl_channel_security_context *)ctx;
+  tsi_result result = TSI_OK;
+  if (c->handshaker_factory == NULL) return GRPC_SECURITY_ERROR;
+  result = tsi_ssl_handshaker_factory_create_handshaker(
+      c->handshaker_factory, c->secure_peer_name, handshaker);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
+            tsi_result_to_string(result));
+    return GRPC_SECURITY_ERROR;
+  }
+  return GRPC_SECURITY_OK;
+}
+
+static grpc_security_status httpcli_ssl_check_peer(
+    grpc_security_context *ctx, const tsi_peer *peer,
+    grpc_security_check_peer_cb cb, void *user_data) {
+  grpc_httpcli_ssl_channel_security_context *c =
+      (grpc_httpcli_ssl_channel_security_context *)ctx;
+
+  /* Check the peer name. */
+  if (c->secure_peer_name != NULL &&
+      !tsi_ssl_peer_matches_name(peer, c->secure_peer_name)) {
+    gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate",
+            c->secure_peer_name);
+    return GRPC_SECURITY_ERROR;
+  }
+  return GRPC_SECURITY_OK;
+}
+
+static grpc_security_context_vtable httpcli_ssl_vtable = {
+    httpcli_ssl_destroy, httpcli_ssl_create_handshaker, httpcli_ssl_check_peer};
+
+grpc_security_status grpc_httpcli_ssl_channel_security_context_create(
+    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
+    const char *secure_peer_name, grpc_channel_security_context **ctx) {
+  tsi_result result = TSI_OK;
+  grpc_httpcli_ssl_channel_security_context *c;
+
+  if (secure_peer_name != NULL && pem_root_certs == NULL) {
+    gpr_log(GPR_ERROR,
+            "Cannot assert a secure peer name without a trust root.");
+    return GRPC_SECURITY_ERROR;
+  }
+
+  c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_context));
+  memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_context));
+
+  gpr_ref_init(&c->base.base.refcount, 1);
+  c->base.base.is_client_side = 1;
+  c->base.base.vtable = &httpcli_ssl_vtable;
+  if (secure_peer_name != NULL) {
+    c->secure_peer_name = gpr_strdup(secure_peer_name);
+  }
+  result = tsi_create_ssl_client_handshaker_factory(
+      NULL, 0, NULL, 0, pem_root_certs, pem_root_certs_size, NULL, NULL, NULL,
+      0, &c->handshaker_factory);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
+            tsi_result_to_string(result));
+    httpcli_ssl_destroy(&c->base.base);
+    *ctx = NULL;
+    return GRPC_SECURITY_ERROR;
+  }
+  *ctx = &c->base;
+  return GRPC_SECURITY_OK;
+}
diff --git a/src/core/httpcli/httpcli_security_context.h b/src/core/httpcli/httpcli_security_context.h
new file mode 100644
index 0000000..c267622
--- /dev/null
+++ b/src/core/httpcli/httpcli_security_context.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H__
+#define __GRPC_INTERNAL_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H__
+
+#include "src/core/security/security_context.h"
+
+grpc_security_status grpc_httpcli_ssl_channel_security_context_create(
+    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
+    const char *secure_peer_name, grpc_channel_security_context **ctx);
+
+#endif  /* __GRPC_INTERNAL_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H__ */
diff --git a/src/core/httpcli/parser.c b/src/core/httpcli/parser.c
new file mode 100644
index 0000000..1f0c516
--- /dev/null
+++ b/src/core/httpcli/parser.c
@@ -0,0 +1,212 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/httpcli/parser.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+static int handle_response_line(grpc_httpcli_parser *parser) {
+  gpr_uint8 *beg = parser->cur_line;
+  gpr_uint8 *cur = beg;
+  gpr_uint8 *end = beg + parser->cur_line_length;
+
+  if (cur == end || *cur++ != 'H') goto error;
+  if (cur == end || *cur++ != 'T') goto error;
+  if (cur == end || *cur++ != 'T') goto error;
+  if (cur == end || *cur++ != 'P') goto error;
+  if (cur == end || *cur++ != '/') goto error;
+  if (cur == end || *cur++ != '1') goto error;
+  if (cur == end || *cur++ != '.') goto error;
+  if (cur == end || *cur < '0' || *cur++ > '1') goto error;
+  if (cur == end || *cur++ != ' ') goto error;
+  if (cur == end || *cur < '1' || *cur++ > '9') goto error;
+  if (cur == end || *cur < '0' || *cur++ > '9') goto error;
+  if (cur == end || *cur < '0' || *cur++ > '9') goto error;
+  parser->r.status =
+      (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0');
+  if (cur == end || *cur++ != ' ') goto error;
+
+  /* we don't really care about the status code message */
+
+  return 1;
+
+error:
+  gpr_log(GPR_ERROR, "Failed parsing response line");
+  return 0;
+}
+
+static char *buf2str(void *buffer, size_t length) {
+  char *out = gpr_malloc(length + 1);
+  memcpy(out, buffer, length);
+  out[length] = 0;
+  return out;
+}
+
+static int add_header(grpc_httpcli_parser *parser) {
+  gpr_uint8 *beg = parser->cur_line;
+  gpr_uint8 *cur = beg;
+  gpr_uint8 *end = beg + parser->cur_line_length;
+  grpc_httpcli_header hdr = {NULL, NULL};
+
+  GPR_ASSERT(cur != end);
+
+  if (*cur == ' ' || *cur == '\t') {
+    gpr_log(GPR_ERROR, "Continued header lines not supported yet");
+    goto error;
+  }
+
+  while (cur != end && *cur != ':') {
+    cur++;
+  }
+  if (cur == end) {
+    gpr_log(GPR_ERROR, "Didn't find ':' in header string");
+    goto error;
+  }
+  hdr.key = buf2str(beg, cur - beg);
+  cur++; /* skip : */
+
+  while (cur != end && (*cur == ' ' || *cur == '\t')) {
+    cur++;
+  }
+  hdr.value = buf2str(cur, end - cur - 2);
+
+  if (parser->r.hdr_count == parser->hdr_capacity) {
+    parser->hdr_capacity =
+        GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2);
+    parser->r.hdrs = gpr_realloc(
+        parser->r.hdrs, parser->hdr_capacity * sizeof(*parser->r.hdrs));
+  }
+  parser->r.hdrs[parser->r.hdr_count++] = hdr;
+  return 1;
+
+error:
+  gpr_free(hdr.key);
+  gpr_free(hdr.value);
+  return 0;
+}
+
+static int finish_line(grpc_httpcli_parser *parser) {
+  switch (parser->state) {
+    case GRPC_HTTPCLI_INITIAL_RESPONSE:
+      if (!handle_response_line(parser)) {
+        return 0;
+      }
+      parser->state = GRPC_HTTPCLI_HEADERS;
+      break;
+    case GRPC_HTTPCLI_HEADERS:
+      if (parser->cur_line_length == 2) {
+        parser->state = GRPC_HTTPCLI_BODY;
+        break;
+      }
+      if (!add_header(parser)) {
+        return 0;
+      }
+      break;
+    case GRPC_HTTPCLI_BODY:
+      gpr_log(GPR_ERROR, "should never reach here");
+      abort();
+  }
+
+  parser->cur_line_length = 0;
+  return 1;
+}
+
+static int addbyte(grpc_httpcli_parser *parser, gpr_uint8 byte) {
+  switch (parser->state) {
+    case GRPC_HTTPCLI_INITIAL_RESPONSE:
+    case GRPC_HTTPCLI_HEADERS:
+      if (parser->cur_line_length >= GRPC_HTTPCLI_MAX_HEADER_LENGTH) {
+        gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded",
+                GRPC_HTTPCLI_MAX_HEADER_LENGTH);
+        return 0;
+      }
+      parser->cur_line[parser->cur_line_length] = byte;
+      parser->cur_line_length++;
+      if (parser->cur_line_length >= 2 &&
+          parser->cur_line[parser->cur_line_length - 2] == '\r' &&
+          parser->cur_line[parser->cur_line_length - 1] == '\n') {
+        return finish_line(parser);
+      } else {
+        return 1;
+      }
+      gpr_log(GPR_ERROR, "should never reach here");
+      abort();
+    case GRPC_HTTPCLI_BODY:
+      if (parser->r.body_length == parser->body_capacity) {
+        parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2);
+        parser->r.body =
+            gpr_realloc((void *)parser->r.body, parser->body_capacity);
+      }
+      ((char *)parser->r.body)[parser->r.body_length] = byte;
+      parser->r.body_length++;
+      return 1;
+  }
+  gpr_log(GPR_ERROR, "should never reach here");
+  abort();
+}
+
+void grpc_httpcli_parser_init(grpc_httpcli_parser *parser) {
+  memset(parser, 0, sizeof(*parser));
+  parser->state = GRPC_HTTPCLI_INITIAL_RESPONSE;
+  parser->r.status = 500;
+}
+
+void grpc_httpcli_parser_destroy(grpc_httpcli_parser *parser) {
+  size_t i;
+  gpr_free(parser->r.body);
+  for (i = 0; i < parser->r.hdr_count; i++) {
+    gpr_free(parser->r.hdrs[i].key);
+    gpr_free(parser->r.hdrs[i].value);
+  }
+  gpr_free(parser->r.hdrs);
+}
+
+int grpc_httpcli_parser_parse(grpc_httpcli_parser *parser, gpr_slice slice) {
+  size_t i;
+
+  for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) {
+    if (!addbyte(parser, GPR_SLICE_START_PTR(slice)[i])) {
+      return 0;
+    }
+  }
+
+  return 1;
+}
+
+int grpc_httpcli_parser_eof(grpc_httpcli_parser *parser) {
+  return parser->state == GRPC_HTTPCLI_BODY;
+}
diff --git a/src/core/httpcli/parser.h b/src/core/httpcli/parser.h
new file mode 100644
index 0000000..e2c24a9
--- /dev/null
+++ b/src/core/httpcli/parser.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_HTTPCLI_PARSER_H__
+#define __GRPC_INTERNAL_HTTPCLI_PARSER_H__
+
+#include "src/core/httpcli/httpcli.h"
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice.h>
+
+typedef enum {
+  GRPC_HTTPCLI_INITIAL_RESPONSE,
+  GRPC_HTTPCLI_HEADERS,
+  GRPC_HTTPCLI_BODY
+} grpc_httpcli_parser_state;
+
+typedef struct {
+  grpc_httpcli_parser_state state;
+
+  grpc_httpcli_response r;
+  size_t body_capacity;
+  size_t hdr_capacity;
+
+  gpr_uint8 cur_line[GRPC_HTTPCLI_MAX_HEADER_LENGTH];
+  size_t cur_line_length;
+} grpc_httpcli_parser;
+
+void grpc_httpcli_parser_init(grpc_httpcli_parser *parser);
+void grpc_httpcli_parser_destroy(grpc_httpcli_parser *parser);
+
+int grpc_httpcli_parser_parse(grpc_httpcli_parser *parser, gpr_slice slice);
+int grpc_httpcli_parser_eof(grpc_httpcli_parser *parser);
+
+#endif  /* __GRPC_INTERNAL_HTTPCLI_PARSER_H__ */
diff --git a/src/core/security/auth.c b/src/core/security/auth.c
new file mode 100644
index 0000000..6480dd2
--- /dev/null
+++ b/src/core/security/auth.c
@@ -0,0 +1,160 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/security/auth.h"
+
+#include <string.h>
+
+#include "src/core/security/security_context.h"
+#include "src/core/security/credentials.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+/* We can have a per-call credentials. */
+typedef struct {
+  grpc_credentials *creds;
+  grpc_call_op op;
+} call_data;
+
+/* We can have a per-channel credentials. */
+typedef struct {
+  grpc_channel_security_context *security_context;
+} channel_data;
+
+static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems,
+                                    size_t num_md,
+                                    grpc_credentials_status status) {
+  grpc_call_element *elem = (grpc_call_element *)user_data;
+  size_t i;
+  for (i = 0; i < num_md; i++) {
+    grpc_call_element_send_metadata(elem, md_elems[i]);
+  }
+  grpc_call_next_op(elem, &((call_data *)elem->call_data)->op);
+}
+
+/* Called either:
+     - in response to an API call (or similar) from above, to send something
+     - a network event (or similar) from below, to receive something
+   op contains type and call direction information, in addition to the data
+   that is being sent or received. */
+static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+
+  switch (op->type) {
+    case GRPC_SEND_START: {
+      grpc_credentials *channel_creds =
+          channeld->security_context->request_metadata_only_creds;
+      /* TODO(jboeuf):
+         Decide on the policy in this case:
+         - populate both channel and call?
+         - the call takes precedence over the channel?
+         - leave this decision up to the channel credentials?  */
+      if (calld->creds != NULL) {
+        gpr_log(GPR_ERROR, "Ignoring per call credentials for now.");
+      }
+      if (channel_creds != NULL &&
+          grpc_credentials_has_request_metadata(channel_creds)) {
+        calld->op = *op; /* Copy op (originates from the caller's stack). */
+        grpc_credentials_get_request_metadata(channel_creds,
+                                              on_credentials_metadata, elem);
+        break;
+      }
+      /* FALLTHROUGH INTENDED. */
+    }
+
+    default:
+      /* pass control up or down the stack depending on op->dir */
+      grpc_call_next_op(elem, op);
+      break;
+  }
+}
+
+/* Called on special channel events, such as disconnection or new incoming
+   calls on the server */
+static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+  grpc_channel_next_op(elem, op);
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_call_element *elem,
+                           const void *server_transport_data) {
+  /* TODO(jboeuf):
+     Find a way to pass-in the credentials from the caller here.  */
+  call_data *calld = elem->call_data;
+  calld->creds = NULL;
+}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_call_element *elem) {
+  call_data *calld = elem->call_data;
+  if (calld->creds != NULL) {
+    grpc_credentials_unref(calld->creds);
+  }
+}
+
+/* Constructor for channel_data */
+static void init_channel_elem(grpc_channel_element *elem,
+                              const grpc_channel_args *args,
+                              grpc_mdctx *metadata_context, int is_first,
+                              int is_last) {
+  grpc_security_context *ctx = grpc_find_security_context_in_args(args);
+  /* grab pointers to our data from the channel element */
+  channel_data *channeld = 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
+     path */
+  GPR_ASSERT(!is_first);
+  GPR_ASSERT(!is_last);
+  GPR_ASSERT(ctx != NULL);
+
+  /* initialize members */
+  GPR_ASSERT(ctx->is_client_side);
+  channeld->security_context =
+      (grpc_channel_security_context *)grpc_security_context_ref(ctx);
+}
+
+/* Destructor for channel data */
+static void destroy_channel_elem(grpc_channel_element *elem) {
+  /* grab pointers to our data from the channel element */
+  channel_data *channeld = elem->channel_data;
+  grpc_channel_security_context *ctx = channeld->security_context;
+  if (ctx != NULL) grpc_security_context_unref(&ctx->base);
+}
+
+const grpc_channel_filter grpc_client_auth_filter = {
+    call_op,           channel_op,           sizeof(call_data),
+    init_call_elem,    destroy_call_elem,    sizeof(channel_data),
+    init_channel_elem, destroy_channel_elem, "auth"};
diff --git a/src/core/security/auth.h b/src/core/security/auth.h
new file mode 100644
index 0000000..0b279f8
--- /dev/null
+++ b/src/core/security/auth.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SECURITY_AUTH_H__
+#define __GRPC_INTERNAL_SECURITY_AUTH_H__
+
+#include "src/core/channel/channel_stack.h"
+
+extern const grpc_channel_filter grpc_client_auth_filter;
+
+#endif  /* __GRPC_INTERNAL_SECURITY_AUTH_H__ */
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
new file mode 100644
index 0000000..969a973
--- /dev/null
+++ b/src/core/security/credentials.c
@@ -0,0 +1,534 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/security/credentials.h"
+
+#include "src/core/httpcli/httpcli.h"
+#include "src/core/surface/surface_em.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+
+#include "third_party/cJSON/cJSON.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/* -- Constants. -- */
+
+#define GRPC_COMPUTE_ENGINE_TOKEN_REFRESH_THRESHOLD_SECS 60
+#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata"
+#define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \
+  "computeMetadata/v1/instance/service-accounts/default/token"
+#define GRPC_AUTHORIZATION_METADATA_KEY "Authorization"
+
+/* -- Common. -- */
+
+typedef struct {
+  grpc_credentials *creds;
+  grpc_credentials_metadata_cb cb;
+  void *user_data;
+} grpc_credentials_metadata_request;
+
+static grpc_credentials_metadata_request *
+grpc_credentials_metadata_request_create(grpc_credentials *creds,
+                                         grpc_credentials_metadata_cb cb,
+                                         void *user_data) {
+  grpc_credentials_metadata_request *r =
+      gpr_malloc(sizeof(grpc_credentials_metadata_request));
+  r->creds = grpc_credentials_ref(creds);
+  r->cb = cb;
+  r->user_data = user_data;
+  return r;
+}
+
+static void grpc_credentials_metadata_request_destroy(
+    grpc_credentials_metadata_request *r) {
+  grpc_credentials_unref(r->creds);
+  gpr_free(r);
+}
+
+grpc_credentials *grpc_credentials_ref(grpc_credentials *creds) {
+  if (creds == NULL) return NULL;
+  gpr_ref(&creds->refcount);
+  return creds;
+}
+
+void grpc_credentials_unref(grpc_credentials *creds) {
+  if (creds == NULL) return;
+  if (gpr_unref(&creds->refcount)) creds->vtable->destroy(creds);
+}
+
+void grpc_credentials_release(grpc_credentials *creds) {
+  grpc_credentials_unref(creds);
+}
+
+int grpc_credentials_has_request_metadata(grpc_credentials *creds) {
+  if (creds == NULL) return 0;
+  return creds->vtable->has_request_metadata(creds);
+}
+
+int grpc_credentials_has_request_metadata_only(grpc_credentials *creds) {
+  if (creds == NULL) return 0;
+  return creds->vtable->has_request_metadata_only(creds);
+}
+
+void grpc_credentials_get_request_metadata(grpc_credentials *creds,
+                                           grpc_credentials_metadata_cb cb,
+                                           void *user_data) {
+  if (creds == NULL || !grpc_credentials_has_request_metadata(creds)) return;
+  creds->vtable->get_request_metadata(creds, cb, user_data);
+}
+
+void grpc_server_credentials_release(grpc_server_credentials *creds) {
+  if (creds == NULL) return;
+  creds->vtable->destroy(creds);
+}
+
+/* -- Ssl credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  grpc_ssl_config config;
+} grpc_ssl_credentials;
+
+typedef struct {
+  grpc_server_credentials base;
+  grpc_ssl_config config;
+} grpc_ssl_server_credentials;
+
+static void ssl_destroy(grpc_credentials *creds) {
+  grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
+  if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
+  if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
+  if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
+  gpr_free(creds);
+}
+
+static void ssl_server_destroy(grpc_server_credentials *creds) {
+  grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
+  if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
+  if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
+  if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
+  gpr_free(creds);
+}
+
+static int ssl_has_request_metadata(const grpc_credentials *creds) { return 0; }
+
+static int ssl_has_request_metadata_only(const grpc_credentials *creds) {
+  return 0;
+}
+
+static grpc_credentials_vtable ssl_vtable = {
+    ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only, NULL};
+
+static grpc_server_credentials_vtable ssl_server_vtable = {ssl_server_destroy};
+
+const grpc_ssl_config *grpc_ssl_credentials_get_config(
+    const grpc_credentials *creds) {
+  if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
+    return NULL;
+  } else {
+    grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
+    return &c->config;
+  }
+}
+
+const grpc_ssl_config *grpc_ssl_server_credentials_get_config(
+    const grpc_server_credentials *creds) {
+  if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
+    return NULL;
+  } else {
+    grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
+    return &c->config;
+  }
+}
+
+static void ssl_build_config(const unsigned char *pem_root_certs,
+                             size_t pem_root_certs_size,
+                             const unsigned char *pem_private_key,
+                             size_t pem_private_key_size,
+                             const unsigned char *pem_cert_chain,
+                             size_t pem_cert_chain_size,
+                             grpc_ssl_config *config) {
+  if (pem_root_certs != NULL) {
+    config->pem_root_certs = gpr_malloc(pem_root_certs_size);
+    memcpy(config->pem_root_certs, pem_root_certs, pem_root_certs_size);
+    config->pem_root_certs_size = pem_root_certs_size;
+  }
+  if (pem_private_key != NULL) {
+    config->pem_private_key = gpr_malloc(pem_private_key_size);
+    memcpy(config->pem_private_key, pem_private_key, pem_private_key_size);
+    config->pem_private_key_size = pem_private_key_size;
+  }
+  if (pem_cert_chain != NULL) {
+    config->pem_cert_chain = gpr_malloc(pem_cert_chain_size);
+    memcpy(config->pem_cert_chain, pem_cert_chain, pem_cert_chain_size);
+    config->pem_cert_chain_size = pem_cert_chain_size;
+  }
+}
+
+grpc_credentials *grpc_ssl_credentials_create(
+    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
+    const unsigned char *pem_private_key, size_t pem_private_key_size,
+    const unsigned char *pem_cert_chain, size_t pem_cert_chain_size) {
+  grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials));
+  memset(c, 0, sizeof(grpc_ssl_credentials));
+  c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
+  c->base.vtable = &ssl_vtable;
+  gpr_ref_init(&c->base.refcount, 1);
+  ssl_build_config(pem_root_certs, pem_root_certs_size, pem_private_key,
+                   pem_private_key_size, pem_cert_chain, pem_cert_chain_size,
+                   &c->config);
+  return &c->base;
+}
+
+grpc_server_credentials *grpc_ssl_server_credentials_create(
+    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
+    const unsigned char *pem_private_key, size_t pem_private_key_size,
+    const unsigned char *pem_cert_chain, size_t pem_cert_chain_size) {
+  grpc_ssl_server_credentials *c =
+      gpr_malloc(sizeof(grpc_ssl_server_credentials));
+  memset(c, 0, sizeof(grpc_ssl_server_credentials));
+  c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
+  c->base.vtable = &ssl_server_vtable;
+  ssl_build_config(pem_root_certs, pem_root_certs_size, pem_private_key,
+                   pem_private_key_size, pem_cert_chain, pem_cert_chain_size,
+                   &c->config);
+  return &c->base;
+}
+
+/* -- ComputeEngine credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  gpr_mu mu;
+  grpc_mdctx *md_ctx;
+  grpc_mdelem *access_token_md;
+  gpr_timespec token_expiration;
+} grpc_compute_engine_credentials;
+
+static void compute_engine_destroy(grpc_credentials *creds) {
+  grpc_compute_engine_credentials *c = (grpc_compute_engine_credentials *)creds;
+  if (c->access_token_md != NULL) {
+    grpc_mdelem_unref(c->access_token_md);
+  }
+  gpr_mu_destroy(&c->mu);
+  grpc_mdctx_orphan(c->md_ctx);
+  gpr_free(c);
+}
+
+static int compute_engine_has_request_metadata(const grpc_credentials *creds) {
+  return 1;
+}
+
+static int compute_engine_has_request_metadata_only(
+    const grpc_credentials *creds) {
+  return 1;
+}
+
+grpc_credentials_status grpc_compute_engine_credentials_parse_server_response(
+    const grpc_httpcli_response *response, grpc_mdctx *ctx,
+    grpc_mdelem **token_elem, gpr_timespec *token_lifetime) {
+  char *null_terminated_body = NULL;
+  char *new_access_token = NULL;
+  grpc_credentials_status status = GRPC_CREDENTIALS_OK;
+  cJSON *json = NULL;
+
+  if (response->status != 200) {
+    gpr_log(GPR_ERROR, "Call to metadata server ended with error %d",
+            response->status);
+    status = GRPC_CREDENTIALS_ERROR;
+    goto end;
+  } else {
+    cJSON *access_token = NULL;
+    cJSON *token_type = NULL;
+    cJSON *expires_in = NULL;
+    size_t new_access_token_size = 0;
+    null_terminated_body = gpr_malloc(response->body_length + 1);
+    null_terminated_body[response->body_length] = '\0';
+    memcpy(null_terminated_body, response->body, response->body_length);
+    json = cJSON_Parse(null_terminated_body);
+    if (json == NULL) {
+      gpr_log(GPR_ERROR, "Could not parse JSON from %s", null_terminated_body);
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    if (json->type != cJSON_Object) {
+      gpr_log(GPR_ERROR, "Response should be a JSON object");
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    access_token = cJSON_GetObjectItem(json, "access_token");
+    if (access_token == NULL || access_token->type != cJSON_String) {
+      gpr_log(GPR_ERROR, "Missing or invalid access_token in JSON.");
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    token_type = cJSON_GetObjectItem(json, "token_type");
+    if (token_type == NULL || token_type->type != cJSON_String) {
+      gpr_log(GPR_ERROR, "Missing or invalid token_type in JSON.");
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    expires_in = cJSON_GetObjectItem(json, "expires_in");
+    if (expires_in == NULL || expires_in->type != cJSON_Number) {
+      gpr_log(GPR_ERROR, "Missing or invalid expires_in in JSON.");
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    new_access_token_size = strlen(token_type->valuestring) + 1 +
+                            strlen(access_token->valuestring) + 1;
+    new_access_token = gpr_malloc(new_access_token_size);
+    /* C89 does not have snprintf :(. */
+    sprintf(new_access_token, "%s %s", token_type->valuestring,
+            access_token->valuestring);
+    token_lifetime->tv_sec = expires_in->valueint;
+    token_lifetime->tv_nsec = 0;
+    if (*token_elem != NULL) grpc_mdelem_unref(*token_elem);
+    *token_elem = grpc_mdelem_from_strings(ctx, GRPC_AUTHORIZATION_METADATA_KEY,
+                                           new_access_token);
+    status = GRPC_CREDENTIALS_OK;
+  }
+
+end:
+  if (status != GRPC_CREDENTIALS_OK && (*token_elem != NULL)) {
+    grpc_mdelem_unref(*token_elem);
+    *token_elem = NULL;
+  }
+  if (null_terminated_body != NULL) gpr_free(null_terminated_body);
+  if (new_access_token != NULL) gpr_free(new_access_token);
+  if (json != NULL) cJSON_Delete(json);
+  return status;
+}
+
+static void on_compute_engine_token_response(
+    void *user_data, const grpc_httpcli_response *response) {
+  grpc_credentials_metadata_request *r =
+      (grpc_credentials_metadata_request *)user_data;
+  grpc_compute_engine_credentials *c =
+      (grpc_compute_engine_credentials *)r->creds;
+  gpr_timespec token_lifetime;
+  grpc_credentials_status status;
+
+  gpr_mu_lock(&c->mu);
+  status = grpc_compute_engine_credentials_parse_server_response(
+      response, c->md_ctx, &c->access_token_md, &token_lifetime);
+  if (status == GRPC_CREDENTIALS_OK) {
+    c->token_expiration = gpr_time_add(gpr_now(), token_lifetime);
+    r->cb(r->user_data, &c->access_token_md, 1, status);
+  } else {
+    c->token_expiration = gpr_inf_past;
+    r->cb(r->user_data, NULL, 0, status);
+  }
+  gpr_mu_unlock(&c->mu);
+  grpc_credentials_metadata_request_destroy(r);
+}
+
+static void compute_engine_get_request_metadata(grpc_credentials *creds,
+                                                grpc_credentials_metadata_cb cb,
+                                                void *user_data) {
+  grpc_compute_engine_credentials *c = (grpc_compute_engine_credentials *)creds;
+  gpr_timespec refresh_threshold = {
+      GRPC_COMPUTE_ENGINE_TOKEN_REFRESH_THRESHOLD_SECS, 0};
+
+  gpr_mu_lock(&c->mu);
+  if (c->access_token_md == NULL ||
+      (gpr_time_cmp(gpr_time_sub(gpr_now(), c->token_expiration),
+                    refresh_threshold) < 0)) {
+    grpc_httpcli_header header = {"Metadata-Flavor", "Google"};
+    grpc_httpcli_request request;
+    request.host = GRPC_COMPUTE_ENGINE_METADATA_HOST;
+    request.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH;
+    request.hdr_count = 1;
+    request.hdrs = &header;
+    grpc_httpcli_get(
+        &request, gpr_time_add(gpr_now(), refresh_threshold), grpc_surface_em(),
+        on_compute_engine_token_response,
+        grpc_credentials_metadata_request_create(creds, cb, user_data));
+  } else {
+    cb(user_data, &c->access_token_md, 1, GRPC_CREDENTIALS_OK);
+  }
+  gpr_mu_unlock(&c->mu);
+}
+
+static grpc_credentials_vtable compute_engine_vtable = {
+    compute_engine_destroy, compute_engine_has_request_metadata,
+    compute_engine_has_request_metadata_only,
+    compute_engine_get_request_metadata};
+
+grpc_credentials *grpc_compute_engine_credentials_create(void) {
+  grpc_compute_engine_credentials *c =
+      gpr_malloc(sizeof(grpc_compute_engine_credentials));
+  memset(c, 0, sizeof(grpc_compute_engine_credentials));
+  c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
+  c->base.vtable = &compute_engine_vtable;
+  gpr_ref_init(&c->base.refcount, 1);
+  gpr_mu_init(&c->mu);
+  c->md_ctx = grpc_mdctx_create();
+  c->token_expiration = gpr_inf_past;
+  return &c->base;
+}
+
+/* -- Fake Oauth2 credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  grpc_mdctx *md_ctx;
+  grpc_mdelem *access_token_md;
+  int is_async;
+} grpc_fake_oauth2_credentials;
+
+static void fake_oauth2_destroy(grpc_credentials *creds) {
+  grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
+  if (c->access_token_md != NULL) {
+    grpc_mdelem_unref(c->access_token_md);
+  }
+  grpc_mdctx_orphan(c->md_ctx);
+  gpr_free(c);
+}
+
+static int fake_oauth2_has_request_metadata(const grpc_credentials *creds) {
+  return 1;
+}
+
+static int fake_oauth2_has_request_metadata_only(
+    const grpc_credentials *creds) {
+  return 1;
+}
+
+void on_simulated_token_fetch_done(void *user_data, grpc_em_cb_status status) {
+  grpc_credentials_metadata_request *r =
+      (grpc_credentials_metadata_request *)user_data;
+  grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)r->creds;
+  GPR_ASSERT(status == GRPC_CALLBACK_SUCCESS);
+  r->cb(r->user_data, &c->access_token_md, 1, GRPC_CREDENTIALS_OK);
+  grpc_credentials_metadata_request_destroy(r);
+}
+
+static void fake_oauth2_get_request_metadata(grpc_credentials *creds,
+                                             grpc_credentials_metadata_cb cb,
+                                             void *user_data) {
+  grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
+
+  if (c->is_async) {
+    GPR_ASSERT(grpc_em_add_callback(grpc_surface_em(),
+                                    on_simulated_token_fetch_done,
+                                    grpc_credentials_metadata_request_create(
+                                        creds, cb, user_data)) == GRPC_EM_OK);
+  } else {
+    cb(user_data, &c->access_token_md, 1, GRPC_CREDENTIALS_OK);
+  }
+}
+
+static grpc_credentials_vtable fake_oauth2_vtable = {
+    fake_oauth2_destroy, fake_oauth2_has_request_metadata,
+    fake_oauth2_has_request_metadata_only, fake_oauth2_get_request_metadata};
+
+grpc_credentials *grpc_fake_oauth2_credentials_create(
+    const char *token_md_value, int is_async) {
+  grpc_fake_oauth2_credentials *c =
+      gpr_malloc(sizeof(grpc_fake_oauth2_credentials));
+  memset(c, 0, sizeof(grpc_fake_oauth2_credentials));
+  c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
+  c->base.vtable = &fake_oauth2_vtable;
+  gpr_ref_init(&c->base.refcount, 1);
+  c->md_ctx = grpc_mdctx_create();
+  c->access_token_md = grpc_mdelem_from_strings(
+      c->md_ctx, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value);
+  c->is_async = is_async;
+  return &c->base;
+}
+
+/* -- Fake transport security credentials. -- */
+
+static void fake_transport_security_credentials_destroy(
+    grpc_credentials *creds) {
+  gpr_free(creds);
+}
+
+static void fake_transport_security_server_credentials_destroy(
+    grpc_server_credentials *creds) {
+  gpr_free(creds);
+}
+
+static int fake_transport_security_has_request_metadata(
+    const grpc_credentials *creds) {
+  return 0;
+}
+
+static int fake_transport_security_has_request_metadata_only(
+    const grpc_credentials *creds) {
+  return 0;
+}
+
+static grpc_credentials_vtable fake_transport_security_credentials_vtable = {
+    fake_transport_security_credentials_destroy,
+    fake_transport_security_has_request_metadata,
+    fake_transport_security_has_request_metadata_only, NULL};
+
+static grpc_server_credentials_vtable
+    fake_transport_security_server_credentials_vtable = {
+        fake_transport_security_server_credentials_destroy};
+
+grpc_credentials *grpc_fake_transport_security_credentials_create(void) {
+  grpc_credentials *c = gpr_malloc(sizeof(grpc_credentials));
+  memset(c, 0, sizeof(grpc_credentials));
+  c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
+  c->vtable = &fake_transport_security_credentials_vtable;
+  gpr_ref_init(&c->refcount, 1);
+  return c;
+}
+
+grpc_server_credentials *
+grpc_fake_transport_security_server_credentials_create() {
+  grpc_server_credentials *c = gpr_malloc(sizeof(grpc_server_credentials));
+  memset(c, 0, sizeof(grpc_server_credentials));
+  c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
+  c->vtable = &fake_transport_security_server_credentials_vtable;
+  return c;
+}
+
+
+/* -- Composite credentials TODO(jboeuf). -- */
+
+grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
+                                                    grpc_credentials *creds2) {
+  return NULL;
+}
+
+/* -- Default credentials TODO(jboeuf). -- */
+
+grpc_credentials *grpc_default_credentials_create(void) { return NULL; }
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
new file mode 100644
index 0000000..1432611
--- /dev/null
+++ b/src/core/security/credentials.h
@@ -0,0 +1,125 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SECURITY_CREDENTIALS_H__
+#define __GRPC_INTERNAL_SECURITY_CREDENTIALS_H__
+
+#include "src/core/transport/stream_op.h"
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+#include <grpc/support/sync.h>
+
+struct grpc_httpcli_response;
+
+/* --- Constants. --- */
+
+typedef enum {
+  GRPC_CREDENTIALS_OK = 0,
+  GRPC_CREDENTIALS_ERROR
+} grpc_credentials_status;
+
+#define GRPC_CREDENTIALS_TYPE_SSL "Ssl"
+#define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2"
+#define GRPC_CREDENTIALS_TYPE_COMPOSITE "Composite"
+#define GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY "FakeTransportSecurity"
+
+/* --- grpc_credentials. --- */
+
+typedef void (*grpc_credentials_metadata_cb)(void *user_data,
+                                             grpc_mdelem **md_elems,
+                                             size_t num_md,
+                                             grpc_credentials_status status);
+
+typedef struct {
+  void (*destroy)(grpc_credentials *c);
+  int (*has_request_metadata)(const grpc_credentials *c);
+  int (*has_request_metadata_only)(const grpc_credentials *c);
+  void (*get_request_metadata)(grpc_credentials *c,
+                               grpc_credentials_metadata_cb cb,
+                               void *user_data);
+} grpc_credentials_vtable;
+
+struct grpc_credentials {
+  const grpc_credentials_vtable *vtable;
+  const char *type;
+  gpr_refcount refcount;
+};
+
+grpc_credentials *grpc_credentials_ref(grpc_credentials *creds);
+void grpc_credentials_unref(grpc_credentials *creds);
+int grpc_credentials_has_request_metadata(grpc_credentials *creds);
+int grpc_credentials_has_request_metadata_only(grpc_credentials *creds);
+void grpc_credentials_get_request_metadata(grpc_credentials *creds,
+                                           grpc_credentials_metadata_cb cb,
+                                           void *user_data);
+typedef struct {
+  unsigned char *pem_private_key;
+  size_t pem_private_key_size;
+  unsigned char *pem_cert_chain;
+  size_t pem_cert_chain_size;
+  unsigned char *pem_root_certs;
+  size_t pem_root_certs_size;
+} grpc_ssl_config;
+
+const grpc_ssl_config *grpc_ssl_credentials_get_config(
+    const grpc_credentials *ssl_creds);
+
+/* Exposed for testing only. */
+grpc_credentials_status grpc_compute_engine_credentials_parse_server_response(
+    const struct grpc_httpcli_response *response, grpc_mdctx *ctx,
+    grpc_mdelem **token_elem, gpr_timespec *token_lifetime);
+
+/* Simulates an oauth2 token fetch with the specified value for testing. */
+grpc_credentials *grpc_fake_oauth2_credentials_create(
+    const char *token_md_value, int is_async);
+
+
+/* --- grpc_server_credentials. --- */
+
+typedef struct {
+  void (*destroy)(grpc_server_credentials *c);
+} grpc_server_credentials_vtable;
+
+struct grpc_server_credentials {
+  const grpc_server_credentials_vtable *vtable;
+  const char *type;
+};
+
+/* TODO(jboeuf): Have an ssl_server_config that can contain multiple key/cert
+   pairs. */
+
+const grpc_ssl_config *grpc_ssl_server_credentials_get_config(
+    const grpc_server_credentials *ssl_creds);
+
+
+#endif  /* __GRPC_INTERNAL_SECURITY_CREDENTIALS_H__ */
diff --git a/src/core/security/google_root_certs.c b/src/core/security/google_root_certs.c
new file mode 100644
index 0000000..669d637
--- /dev/null
+++ b/src/core/security/google_root_certs.c
@@ -0,0 +1,11277 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* this file is created by
+   xxd -i security/cacerts/for_connecting_to_google/roots.pem */
+
+unsigned char grpc_google_root_certs[] = {
+    0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x47, 0x54, 0x45, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72,
+    0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52,
+    0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x47, 0x54, 0x45, 0x20, 0x43, 0x6f,
+    0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4f, 0x55,
+    0x3d, 0x47, 0x54, 0x45, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72,
+    0x75, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e,
+    0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75,
+    0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x54,
+    0x45, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74,
+    0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+    0x20, 0x4f, 0x3d, 0x47, 0x54, 0x45, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f,
+    0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4f, 0x55, 0x3d, 0x47, 0x54,
+    0x45, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74,
+    0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2c, 0x20,
+    0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c,
+    0x3a, 0x20, 0x22, 0x47, 0x54, 0x45, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72,
+    0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+    0x20, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72,
+    0x69, 0x61, 0x6c, 0x3a, 0x20, 0x34, 0x32, 0x31, 0x0a, 0x23, 0x20, 0x4d,
+    0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x63, 0x61, 0x3a, 0x33, 0x64, 0x3a, 0x64, 0x33,
+    0x3a, 0x36, 0x38, 0x3a, 0x66, 0x31, 0x3a, 0x30, 0x33, 0x3a, 0x35, 0x63,
+    0x3a, 0x64, 0x30, 0x3a, 0x33, 0x32, 0x3a, 0x66, 0x61, 0x3a, 0x62, 0x38,
+    0x3a, 0x32, 0x62, 0x3a, 0x35, 0x39, 0x3a, 0x65, 0x38, 0x3a, 0x35, 0x61,
+    0x3a, 0x64, 0x62, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x39, 0x37, 0x3a, 0x38, 0x31, 0x3a, 0x37, 0x39, 0x3a, 0x35, 0x30, 0x3a,
+    0x64, 0x38, 0x3a, 0x31, 0x63, 0x3a, 0x39, 0x36, 0x3a, 0x37, 0x30, 0x3a,
+    0x63, 0x63, 0x3a, 0x33, 0x34, 0x3a, 0x64, 0x38, 0x3a, 0x30, 0x39, 0x3a,
+    0x63, 0x66, 0x3a, 0x37, 0x39, 0x3a, 0x34, 0x34, 0x3a, 0x33, 0x31, 0x3a,
+    0x33, 0x36, 0x3a, 0x37, 0x65, 0x3a, 0x66, 0x34, 0x3a, 0x37, 0x34, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x35,
+    0x3a, 0x33, 0x31, 0x3a, 0x32, 0x35, 0x3a, 0x31, 0x38, 0x3a, 0x38, 0x64,
+    0x3a, 0x32, 0x31, 0x3a, 0x31, 0x30, 0x3a, 0x61, 0x61, 0x3a, 0x39, 0x36,
+    0x3a, 0x34, 0x62, 0x3a, 0x30, 0x32, 0x3a, 0x63, 0x37, 0x3a, 0x62, 0x37,
+    0x3a, 0x63, 0x36, 0x3a, 0x64, 0x61, 0x3a, 0x33, 0x32, 0x3a, 0x30, 0x33,
+    0x3a, 0x31, 0x37, 0x3a, 0x30, 0x38, 0x3a, 0x39, 0x34, 0x3a, 0x65, 0x35,
+    0x3a, 0x66, 0x62, 0x3a, 0x37, 0x31, 0x3a, 0x66, 0x66, 0x3a, 0x66, 0x62,
+    0x3a, 0x36, 0x36, 0x3a, 0x36, 0x37, 0x3a, 0x64, 0x35, 0x3a, 0x65, 0x36,
+    0x3a, 0x38, 0x31, 0x3a, 0x30, 0x61, 0x3a, 0x33, 0x36, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52,
+    0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x57, 0x6a, 0x43, 0x43, 0x41, 0x63,
+    0x4d, 0x43, 0x41, 0x67, 0x47, 0x6c, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53,
+    0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x41,
+    0x55, 0x41, 0x4d, 0x48, 0x55, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67,
+    0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x52,
+    0x67, 0x77, 0x46, 0x67, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, 0x4b, 0x45,
+    0x77, 0x39, 0x48, 0x56, 0x45, 0x55, 0x67, 0x51, 0x32, 0x39, 0x79, 0x63,
+    0x47, 0x39, 0x79, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x78, 0x4a,
+    0x7a, 0x41, 0x6c, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x48,
+    0x6b, 0x64, 0x55, 0x52, 0x53, 0x42, 0x44, 0x65, 0x57, 0x4a, 0x6c, 0x63,
+    0x6c, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x46, 0x4e, 0x76, 0x0a,
+    0x62, 0x48, 0x56, 0x30, 0x61, 0x57, 0x39, 0x75, 0x63, 0x79, 0x77, 0x67,
+    0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x6a, 0x4d, 0x43, 0x45, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x61, 0x52, 0x31, 0x52, 0x46,
+    0x49, 0x45, 0x4e, 0x35, 0x59, 0x6d, 0x56, 0x79, 0x56, 0x48, 0x4a, 0x31,
+    0x63, 0x33, 0x51, 0x67, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73,
+    0x49, 0x46, 0x4a, 0x76, 0x0a, 0x62, 0x33, 0x51, 0x77, 0x48, 0x68, 0x63,
+    0x4e, 0x4f, 0x54, 0x67, 0x77, 0x4f, 0x44, 0x45, 0x7a, 0x4d, 0x44, 0x41,
+    0x79, 0x4f, 0x54, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x67,
+    0x77, 0x4f, 0x44, 0x45, 0x7a, 0x4d, 0x6a, 0x4d, 0x31, 0x4f, 0x54, 0x41,
+    0x77, 0x57, 0x6a, 0x42, 0x31, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59,
+    0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x0a, 0x55, 0x7a,
+    0x45, 0x59, 0x4d, 0x42, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68,
+    0x4d, 0x50, 0x52, 0x31, 0x52, 0x46, 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e,
+    0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x53,
+    0x63, 0x77, 0x4a, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78,
+    0x35, 0x48, 0x56, 0x45, 0x55, 0x67, 0x51, 0x33, 0x6c, 0x69, 0x5a, 0x58,
+    0x4a, 0x55, 0x0a, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x54, 0x62,
+    0x32, 0x78, 0x31, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6e, 0x4d, 0x73, 0x49,
+    0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x49, 0x7a, 0x41, 0x68, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x47, 0x6b, 0x64, 0x55, 0x52,
+    0x53, 0x42, 0x44, 0x65, 0x57, 0x4a, 0x6c, 0x63, 0x6c, 0x52, 0x79, 0x64,
+    0x58, 0x4e, 0x30, 0x49, 0x45, 0x64, 0x73, 0x0a, 0x62, 0x32, 0x4a, 0x68,
+    0x62, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x4d, 0x49, 0x47, 0x66,
+    0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33,
+    0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x47, 0x4e,
+    0x41, 0x44, 0x43, 0x42, 0x69, 0x51, 0x4b, 0x42, 0x67, 0x51, 0x43, 0x56,
+    0x44, 0x36, 0x43, 0x32, 0x38, 0x46, 0x43, 0x63, 0x36, 0x48, 0x72, 0x48,
+    0x0a, 0x69, 0x4d, 0x33, 0x64, 0x46, 0x77, 0x34, 0x75, 0x73, 0x4a, 0x54,
+    0x51, 0x47, 0x7a, 0x30, 0x4f, 0x39, 0x70, 0x54, 0x41, 0x69, 0x70, 0x54,
+    0x48, 0x42, 0x73, 0x69, 0x51, 0x6c, 0x38, 0x69, 0x34, 0x5a, 0x42, 0x70,
+    0x36, 0x66, 0x6d, 0x77, 0x38, 0x55, 0x2b, 0x45, 0x33, 0x4b, 0x48, 0x4e,
+    0x67, 0x66, 0x37, 0x4b, 0x58, 0x55, 0x77, 0x65, 0x66, 0x55, 0x2f, 0x6c,
+    0x74, 0x57, 0x4a, 0x54, 0x53, 0x0a, 0x72, 0x34, 0x31, 0x74, 0x69, 0x47,
+    0x65, 0x41, 0x35, 0x75, 0x32, 0x79, 0x6c, 0x63, 0x39, 0x79, 0x4d, 0x63,
+    0x71, 0x6c, 0x48, 0x48, 0x4b, 0x36, 0x58, 0x41, 0x4c, 0x6e, 0x5a, 0x45,
+    0x4c, 0x6e, 0x2b, 0x61, 0x6b, 0x73, 0x31, 0x6a, 0x6f, 0x4e, 0x72, 0x49,
+    0x31, 0x43, 0x71, 0x69, 0x51, 0x42, 0x4f, 0x65, 0x61, 0x63, 0x50, 0x77,
+    0x47, 0x46, 0x56, 0x77, 0x31, 0x59, 0x68, 0x30, 0x58, 0x34, 0x0a, 0x30,
+    0x34, 0x57, 0x71, 0x6b, 0x32, 0x6b, 0x6d, 0x68, 0x58, 0x42, 0x49, 0x67,
+    0x44, 0x38, 0x53, 0x46, 0x63, 0x64, 0x35, 0x74, 0x42, 0x38, 0x46, 0x4c,
+    0x7a, 0x74, 0x69, 0x6d, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x4d,
+    0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44,
+    0x51, 0x45, 0x42, 0x42, 0x41, 0x55, 0x41, 0x41, 0x34, 0x47, 0x42, 0x41,
+    0x47, 0x33, 0x72, 0x0a, 0x47, 0x77, 0x6e, 0x70, 0x58, 0x74, 0x6c, 0x52,
+    0x32, 0x32, 0x63, 0x69, 0x59, 0x61, 0x51, 0x71, 0x50, 0x45, 0x68, 0x33,
+    0x34, 0x36, 0x42, 0x38, 0x70, 0x74, 0x35, 0x7a, 0x6f, 0x68, 0x51, 0x44,
+    0x68, 0x54, 0x33, 0x37, 0x71, 0x77, 0x34, 0x77, 0x78, 0x59, 0x4d, 0x57,
+    0x4d, 0x34, 0x45, 0x54, 0x43, 0x4a, 0x35, 0x37, 0x4e, 0x45, 0x37, 0x66,
+    0x51, 0x4d, 0x68, 0x30, 0x31, 0x37, 0x6c, 0x39, 0x0a, 0x33, 0x50, 0x52,
+    0x32, 0x56, 0x58, 0x32, 0x62, 0x59, 0x31, 0x51, 0x59, 0x36, 0x66, 0x44,
+    0x71, 0x38, 0x31, 0x79, 0x78, 0x32, 0x59, 0x74, 0x43, 0x48, 0x72, 0x6e,
+    0x41, 0x6c, 0x55, 0x36, 0x36, 0x2b, 0x74, 0x58, 0x69, 0x66, 0x50, 0x56,
+    0x6f, 0x59, 0x62, 0x2b, 0x4f, 0x37, 0x41, 0x57, 0x58, 0x58, 0x31, 0x75,
+    0x77, 0x31, 0x36, 0x4f, 0x46, 0x4e, 0x4d, 0x51, 0x6b, 0x70, 0x77, 0x30,
+    0x50, 0x0a, 0x6c, 0x5a, 0x50, 0x76, 0x79, 0x35, 0x54, 0x59, 0x6e, 0x68,
+    0x2b, 0x64, 0x58, 0x49, 0x56, 0x74, 0x78, 0x36, 0x71, 0x75, 0x54, 0x78,
+    0x38, 0x69, 0x74, 0x63, 0x32, 0x56, 0x72, 0x62, 0x71, 0x6e, 0x7a, 0x50,
+    0x6d, 0x72, 0x43, 0x33, 0x70, 0x2f, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43,
+    0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20,
+    0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x54,
+    0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
+    0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65,
+    0x20, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x20,
+    0x63, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+    0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76,
+    0x69, 0x63, 0x65, 0x73, 0x20, 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f,
+    0x6e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a,
+    0x20, 0x43, 0x4e, 0x3d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x53,
+    0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x54,
+    0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c,
+    0x74, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x43,
+    0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+    0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, 0x69,
+    0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62,
+    0x65, 0x6c, 0x3a, 0x20, 0x22, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20,
+    0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23,
+    0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23,
+    0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x35, 0x3a, 0x37, 0x30, 0x3a,
+    0x63, 0x34, 0x3a, 0x61, 0x32, 0x3a, 0x65, 0x64, 0x3a, 0x35, 0x33, 0x3a,
+    0x37, 0x38, 0x3a, 0x30, 0x63, 0x3a, 0x63, 0x38, 0x3a, 0x31, 0x30, 0x3a,
+    0x35, 0x33, 0x3a, 0x38, 0x31, 0x3a, 0x36, 0x34, 0x3a, 0x63, 0x62, 0x3a,
+    0x64, 0x30, 0x3a, 0x31, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x32, 0x33, 0x3a, 0x65, 0x35, 0x3a, 0x39, 0x34, 0x3a, 0x39,
+    0x34, 0x3a, 0x35, 0x31, 0x3a, 0x39, 0x35, 0x3a, 0x66, 0x32, 0x3a, 0x34,
+    0x31, 0x3a, 0x34, 0x38, 0x3a, 0x30, 0x33, 0x3a, 0x62, 0x34, 0x3a, 0x64,
+    0x35, 0x3a, 0x36, 0x34, 0x3a, 0x64, 0x32, 0x3a, 0x61, 0x33, 0x3a, 0x61,
+    0x33, 0x3a, 0x66, 0x35, 0x3a, 0x64, 0x38, 0x3a, 0x38, 0x62, 0x3a, 0x38,
+    0x63, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x62, 0x34, 0x3a, 0x34, 0x31, 0x3a, 0x30, 0x62, 0x3a, 0x37, 0x33, 0x3a,
+    0x65, 0x32, 0x3a, 0x65, 0x36, 0x3a, 0x65, 0x61, 0x3a, 0x63, 0x61, 0x3a,
+    0x34, 0x37, 0x3a, 0x66, 0x62, 0x3a, 0x63, 0x34, 0x3a, 0x32, 0x66, 0x3a,
+    0x38, 0x66, 0x3a, 0x61, 0x34, 0x3a, 0x30, 0x31, 0x3a, 0x38, 0x61, 0x3a,
+    0x66, 0x34, 0x3a, 0x33, 0x38, 0x3a, 0x31, 0x64, 0x3a, 0x63, 0x35, 0x3a,
+    0x34, 0x63, 0x3a, 0x66, 0x61, 0x3a, 0x61, 0x38, 0x3a, 0x34, 0x34, 0x3a,
+    0x35, 0x30, 0x3a, 0x34, 0x36, 0x3a, 0x31, 0x65, 0x3a, 0x65, 0x64, 0x3a,
+    0x30, 0x39, 0x3a, 0x34, 0x35, 0x3a, 0x34, 0x64, 0x3a, 0x65, 0x39, 0x0a,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x45, 0x7a, 0x43, 0x43,
+    0x41, 0x6e, 0x79, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42,
+    0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47,
+    0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x51, 0x46, 0x41, 0x44, 0x43, 0x42,
+    0x78, 0x44, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x42, 0x68, 0x4d, 0x43, 0x57, 0x6b, 0x45, 0x78, 0x0a, 0x46, 0x54, 0x41,
+    0x54, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x54, 0x44, 0x46, 0x64,
+    0x6c, 0x63, 0x33, 0x52, 0x6c, 0x63, 0x6d, 0x34, 0x67, 0x51, 0x32, 0x46,
+    0x77, 0x5a, 0x54, 0x45, 0x53, 0x4d, 0x42, 0x41, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x42, 0x78, 0x4d, 0x4a, 0x51, 0x32, 0x46, 0x77, 0x5a, 0x53, 0x42,
+    0x55, 0x62, 0x33, 0x64, 0x75, 0x4d, 0x52, 0x30, 0x77, 0x47, 0x77, 0x59,
+    0x44, 0x0a, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x52, 0x55, 0x61, 0x47,
+    0x46, 0x33, 0x64, 0x47, 0x55, 0x67, 0x51, 0x32, 0x39, 0x75, 0x63, 0x33,
+    0x56, 0x73, 0x64, 0x47, 0x6c, 0x75, 0x5a, 0x79, 0x42, 0x6a, 0x59, 0x7a,
+    0x45, 0x6f, 0x4d, 0x43, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78,
+    0x4d, 0x66, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57,
+    0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x0a, 0x62, 0x69, 0x42, 0x54, 0x5a,
+    0x58, 0x4a, 0x32, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x79, 0x42, 0x45, 0x61,
+    0x58, 0x5a, 0x70, 0x63, 0x32, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x5a, 0x4d,
+    0x42, 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x51, 0x56,
+    0x47, 0x68, 0x68, 0x64, 0x33, 0x52, 0x6c, 0x49, 0x46, 0x4e, 0x6c, 0x63,
+    0x6e, 0x5a, 0x6c, 0x63, 0x69, 0x42, 0x44, 0x51, 0x54, 0x45, 0x6d, 0x0a,
+    0x4d, 0x43, 0x51, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33,
+    0x44, 0x51, 0x45, 0x4a, 0x41, 0x52, 0x59, 0x58, 0x63, 0x32, 0x56, 0x79,
+    0x64, 0x6d, 0x56, 0x79, 0x4c, 0x57, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x7a,
+    0x51, 0x48, 0x52, 0x6f, 0x59, 0x58, 0x64, 0x30, 0x5a, 0x53, 0x35, 0x6a,
+    0x62, 0x32, 0x30, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4f, 0x54, 0x59, 0x77,
+    0x4f, 0x44, 0x41, 0x78, 0x0a, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41,
+    0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x41, 0x78, 0x4d, 0x6a, 0x4d,
+    0x78, 0x4d, 0x6a, 0x4d, 0x31, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, 0x43,
+    0x42, 0x78, 0x44, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x42, 0x68, 0x4d, 0x43, 0x57, 0x6b, 0x45, 0x78, 0x46, 0x54, 0x41,
+    0x54, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x54, 0x0a, 0x44, 0x46,
+    0x64, 0x6c, 0x63, 0x33, 0x52, 0x6c, 0x63, 0x6d, 0x34, 0x67, 0x51, 0x32,
+    0x46, 0x77, 0x5a, 0x54, 0x45, 0x53, 0x4d, 0x42, 0x41, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x42, 0x78, 0x4d, 0x4a, 0x51, 0x32, 0x46, 0x77, 0x5a, 0x53,
+    0x42, 0x55, 0x62, 0x33, 0x64, 0x75, 0x4d, 0x52, 0x30, 0x77, 0x47, 0x77,
+    0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x52, 0x55, 0x61, 0x47,
+    0x46, 0x33, 0x0a, 0x64, 0x47, 0x55, 0x67, 0x51, 0x32, 0x39, 0x75, 0x63,
+    0x33, 0x56, 0x73, 0x64, 0x47, 0x6c, 0x75, 0x5a, 0x79, 0x42, 0x6a, 0x59,
+    0x7a, 0x45, 0x6f, 0x4d, 0x43, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43,
+    0x78, 0x4d, 0x66, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61,
+    0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x54, 0x5a,
+    0x58, 0x4a, 0x32, 0x61, 0x57, 0x4e, 0x6c, 0x0a, 0x63, 0x79, 0x42, 0x45,
+    0x61, 0x58, 0x5a, 0x70, 0x63, 0x32, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x5a,
+    0x4d, 0x42, 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x51,
+    0x56, 0x47, 0x68, 0x68, 0x64, 0x33, 0x52, 0x6c, 0x49, 0x46, 0x4e, 0x6c,
+    0x63, 0x6e, 0x5a, 0x6c, 0x63, 0x69, 0x42, 0x44, 0x51, 0x54, 0x45, 0x6d,
+    0x4d, 0x43, 0x51, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33,
+    0x0a, 0x44, 0x51, 0x45, 0x4a, 0x41, 0x52, 0x59, 0x58, 0x63, 0x32, 0x56,
+    0x79, 0x64, 0x6d, 0x56, 0x79, 0x4c, 0x57, 0x4e, 0x6c, 0x63, 0x6e, 0x52,
+    0x7a, 0x51, 0x48, 0x52, 0x6f, 0x59, 0x58, 0x64, 0x30, 0x5a, 0x53, 0x35,
+    0x6a, 0x62, 0x32, 0x30, 0x77, 0x67, 0x5a, 0x38, 0x77, 0x44, 0x51, 0x59,
+    0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45,
+    0x42, 0x42, 0x51, 0x41, 0x44, 0x0a, 0x67, 0x59, 0x30, 0x41, 0x4d, 0x49,
+    0x47, 0x4a, 0x41, 0x6f, 0x47, 0x42, 0x41, 0x4e, 0x4f, 0x6b, 0x55, 0x47,
+    0x37, 0x49, 0x2f, 0x31, 0x5a, 0x72, 0x35, 0x73, 0x39, 0x64, 0x74, 0x75,
+    0x6f, 0x4d, 0x61, 0x48, 0x56, 0x48, 0x6f, 0x71, 0x72, 0x43, 0x32, 0x6f,
+    0x51, 0x6c, 0x2f, 0x4b, 0x6a, 0x30, 0x52, 0x31, 0x48, 0x61, 0x68, 0x62,
+    0x55, 0x67, 0x64, 0x4a, 0x53, 0x47, 0x48, 0x67, 0x39, 0x31, 0x0a, 0x79,
+    0x65, 0x6b, 0x49, 0x59, 0x66, 0x55, 0x47, 0x62, 0x54, 0x42, 0x75, 0x46,
+    0x52, 0x6b, 0x43, 0x36, 0x56, 0x4c, 0x41, 0x59, 0x74, 0x74, 0x4e, 0x6d,
+    0x5a, 0x37, 0x69, 0x61, 0x67, 0x78, 0x45, 0x4f, 0x4d, 0x33, 0x2b, 0x76,
+    0x75, 0x4e, 0x6b, 0x43, 0x58, 0x44, 0x46, 0x2f, 0x72, 0x46, 0x72, 0x4b,
+    0x62, 0x59, 0x76, 0x53, 0x63, 0x67, 0x37, 0x31, 0x43, 0x63, 0x45, 0x4a,
+    0x52, 0x43, 0x58, 0x0a, 0x4c, 0x2b, 0x65, 0x51, 0x62, 0x63, 0x41, 0x6f,
+    0x51, 0x70, 0x6e, 0x58, 0x54, 0x45, 0x50, 0x65, 0x77, 0x2f, 0x55, 0x68,
+    0x62, 0x56, 0x53, 0x66, 0x58, 0x63, 0x4e, 0x59, 0x34, 0x63, 0x44, 0x6b,
+    0x32, 0x56, 0x75, 0x77, 0x75, 0x4e, 0x79, 0x30, 0x65, 0x39, 0x38, 0x32,
+    0x4f, 0x73, 0x4b, 0x31, 0x5a, 0x69, 0x49, 0x53, 0x31, 0x6f, 0x63, 0x4e,
+    0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x0a, 0x45, 0x7a, 0x41,
+    0x52, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45,
+    0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38,
+    0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63,
+    0x4e, 0x41, 0x51, 0x45, 0x45, 0x42, 0x51, 0x41, 0x44, 0x67, 0x59, 0x45,
+    0x41, 0x42, 0x2f, 0x70, 0x4d, 0x61, 0x56, 0x7a, 0x37, 0x6c, 0x63, 0x78,
+    0x47, 0x0a, 0x37, 0x6f, 0x57, 0x44, 0x54, 0x53, 0x45, 0x77, 0x6a, 0x73,
+    0x72, 0x5a, 0x71, 0x47, 0x39, 0x4a, 0x47, 0x75, 0x62, 0x61, 0x55, 0x65,
+    0x4e, 0x67, 0x63, 0x47, 0x79, 0x45, 0x59, 0x52, 0x47, 0x68, 0x47, 0x73,
+    0x68, 0x49, 0x50, 0x6c, 0x6c, 0x44, 0x66, 0x55, 0x2b, 0x56, 0x50, 0x61,
+    0x47, 0x4c, 0x74, 0x77, 0x74, 0x69, 0x6d, 0x48, 0x70, 0x31, 0x69, 0x74,
+    0x32, 0x49, 0x54, 0x6b, 0x36, 0x65, 0x0a, 0x51, 0x4e, 0x75, 0x6f, 0x7a,
+    0x44, 0x4a, 0x30, 0x75, 0x57, 0x38, 0x4e, 0x78, 0x75, 0x4f, 0x7a, 0x52,
+    0x41, 0x76, 0x5a, 0x69, 0x6d, 0x2b, 0x61, 0x4b, 0x5a, 0x75, 0x5a, 0x47,
+    0x43, 0x67, 0x37, 0x30, 0x65, 0x4e, 0x41, 0x4b, 0x4a, 0x70, 0x61, 0x50,
+    0x4e, 0x57, 0x31, 0x35, 0x79, 0x41, 0x62, 0x69, 0x38, 0x71, 0x6b, 0x71,
+    0x34, 0x33, 0x70, 0x55, 0x64, 0x6e, 0x69, 0x54, 0x43, 0x78, 0x5a, 0x0a,
+    0x71, 0x64, 0x71, 0x35, 0x73, 0x6e, 0x55, 0x62, 0x39, 0x6b, 0x4c, 0x79,
+    0x37, 0x38, 0x66, 0x79, 0x47, 0x50, 0x6d, 0x4a, 0x76, 0x4b, 0x50, 0x2f,
+    0x69, 0x69, 0x4d, 0x75, 0x63, 0x45, 0x63, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a,
+    0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x65, 0x6d,
+    0x69, 0x75, 0x6d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43,
+    0x41, 0x20, 0x4f, 0x3d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x43,
+    0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x63,
+    0x20, 0x4f, 0x55, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+    0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
+    0x65, 0x73, 0x20, 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x0a,
+    0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43,
+    0x4e, 0x3d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x65,
+    0x6d, 0x69, 0x75, 0x6d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
+    0x43, 0x41, 0x20, 0x4f, 0x3d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20,
+    0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x63,
+    0x63, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+    0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69,
+    0x63, 0x65, 0x73, 0x20, 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e,
+    0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x54,
+    0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75,
+    0x6d, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x22,
+    0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31,
+    0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x36, 0x3a, 0x39,
+    0x66, 0x3a, 0x36, 0x39, 0x3a, 0x37, 0x39, 0x3a, 0x31, 0x36, 0x3a, 0x36,
+    0x36, 0x3a, 0x39, 0x30, 0x3a, 0x30, 0x32, 0x3a, 0x31, 0x62, 0x3a, 0x38,
+    0x63, 0x3a, 0x38, 0x63, 0x3a, 0x61, 0x32, 0x3a, 0x63, 0x33, 0x3a, 0x30,
+    0x37, 0x3a, 0x36, 0x66, 0x3a, 0x33, 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48,
+    0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x36, 0x32, 0x3a, 0x37, 0x66, 0x3a, 0x38, 0x64,
+    0x3a, 0x37, 0x38, 0x3a, 0x32, 0x37, 0x3a, 0x36, 0x35, 0x3a, 0x36, 0x33,
+    0x3a, 0x39, 0x39, 0x3a, 0x64, 0x32, 0x3a, 0x37, 0x64, 0x3a, 0x37, 0x66,
+    0x3a, 0x39, 0x30, 0x3a, 0x34, 0x34, 0x3a, 0x63, 0x39, 0x3a, 0x66, 0x65,
+    0x3a, 0x62, 0x33, 0x3a, 0x66, 0x33, 0x3a, 0x33, 0x65, 0x3a, 0x66, 0x61,
+    0x3a, 0x39, 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x61, 0x62, 0x3a, 0x37, 0x30, 0x3a, 0x33, 0x36, 0x3a, 0x33,
+    0x36, 0x3a, 0x35, 0x63, 0x3a, 0x37, 0x31, 0x3a, 0x35, 0x34, 0x3a, 0x61,
+    0x61, 0x3a, 0x32, 0x39, 0x3a, 0x63, 0x32, 0x3a, 0x63, 0x32, 0x3a, 0x39,
+    0x66, 0x3a, 0x35, 0x64, 0x3a, 0x34, 0x31, 0x3a, 0x39, 0x31, 0x3a, 0x31,
+    0x36, 0x3a, 0x33, 0x62, 0x3a, 0x31, 0x36, 0x3a, 0x32, 0x61, 0x3a, 0x32,
+    0x32, 0x3a, 0x32, 0x35, 0x3a, 0x30, 0x31, 0x3a, 0x31, 0x33, 0x3a, 0x35,
+    0x37, 0x3a, 0x64, 0x35, 0x3a, 0x36, 0x64, 0x3a, 0x30, 0x37, 0x3a, 0x66,
+    0x66, 0x3a, 0x61, 0x37, 0x3a, 0x62, 0x63, 0x3a, 0x31, 0x66, 0x3a, 0x37,
+    0x32, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x4a, 0x7a,
+    0x43, 0x43, 0x41, 0x70, 0x43, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67,
+    0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b,
+    0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x51, 0x46, 0x41, 0x44,
+    0x43, 0x42, 0x7a, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x57, 0x6b, 0x45, 0x78, 0x0a, 0x46,
+    0x54, 0x41, 0x54, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x54, 0x44,
+    0x46, 0x64, 0x6c, 0x63, 0x33, 0x52, 0x6c, 0x63, 0x6d, 0x34, 0x67, 0x51,
+    0x32, 0x46, 0x77, 0x5a, 0x54, 0x45, 0x53, 0x4d, 0x42, 0x41, 0x47, 0x41,
+    0x31, 0x55, 0x45, 0x42, 0x78, 0x4d, 0x4a, 0x51, 0x32, 0x46, 0x77, 0x5a,
+    0x53, 0x42, 0x55, 0x62, 0x33, 0x64, 0x75, 0x4d, 0x52, 0x30, 0x77, 0x47,
+    0x77, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x52, 0x55,
+    0x61, 0x47, 0x46, 0x33, 0x64, 0x47, 0x55, 0x67, 0x51, 0x32, 0x39, 0x75,
+    0x63, 0x33, 0x56, 0x73, 0x64, 0x47, 0x6c, 0x75, 0x5a, 0x79, 0x42, 0x6a,
+    0x59, 0x7a, 0x45, 0x6f, 0x4d, 0x43, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x43, 0x78, 0x4d, 0x66, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d,
+    0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x0a, 0x62, 0x69, 0x42,
+    0x54, 0x5a, 0x58, 0x4a, 0x32, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x79, 0x42,
+    0x45, 0x61, 0x58, 0x5a, 0x70, 0x63, 0x32, 0x6c, 0x76, 0x62, 0x6a, 0x45,
+    0x68, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d,
+    0x59, 0x56, 0x47, 0x68, 0x68, 0x64, 0x33, 0x52, 0x6c, 0x49, 0x46, 0x42,
+    0x79, 0x5a, 0x57, 0x31, 0x70, 0x64, 0x57, 0x30, 0x67, 0x55, 0x32, 0x56,
+    0x79, 0x0a, 0x64, 0x6d, 0x56, 0x79, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x53,
+    0x67, 0x77, 0x4a, 0x67, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76,
+    0x63, 0x4e, 0x41, 0x51, 0x6b, 0x42, 0x46, 0x68, 0x6c, 0x77, 0x63, 0x6d,
+    0x56, 0x74, 0x61, 0x58, 0x56, 0x74, 0x4c, 0x58, 0x4e, 0x6c, 0x63, 0x6e,
+    0x5a, 0x6c, 0x63, 0x6b, 0x42, 0x30, 0x61, 0x47, 0x46, 0x33, 0x64, 0x47,
+    0x55, 0x75, 0x59, 0x32, 0x39, 0x74, 0x0a, 0x4d, 0x42, 0x34, 0x58, 0x44,
+    0x54, 0x6b, 0x32, 0x4d, 0x44, 0x67, 0x77, 0x4d, 0x54, 0x41, 0x77, 0x4d,
+    0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x77, 0x4d,
+    0x54, 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31, 0x4f,
+    0x56, 0x6f, 0x77, 0x67, 0x63, 0x34, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x70, 0x42, 0x0a,
+    0x4d, 0x52, 0x55, 0x77, 0x45, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49,
+    0x45, 0x77, 0x78, 0x58, 0x5a, 0x58, 0x4e, 0x30, 0x5a, 0x58, 0x4a, 0x75,
+    0x49, 0x45, 0x4e, 0x68, 0x63, 0x47, 0x55, 0x78, 0x45, 0x6a, 0x41, 0x51,
+    0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x43, 0x55, 0x4e, 0x68,
+    0x63, 0x47, 0x55, 0x67, 0x56, 0x47, 0x39, 0x33, 0x62, 0x6a, 0x45, 0x64,
+    0x4d, 0x42, 0x73, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d,
+    0x55, 0x56, 0x47, 0x68, 0x68, 0x64, 0x33, 0x52, 0x6c, 0x49, 0x45, 0x4e,
+    0x76, 0x62, 0x6e, 0x4e, 0x31, 0x62, 0x48, 0x52, 0x70, 0x62, 0x6d, 0x63,
+    0x67, 0x59, 0x32, 0x4d, 0x78, 0x4b, 0x44, 0x41, 0x6d, 0x42, 0x67, 0x4e,
+    0x56, 0x42, 0x41, 0x73, 0x54, 0x48, 0x30, 0x4e, 0x6c, 0x63, 0x6e, 0x52,
+    0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x0a, 0x62, 0x32,
+    0x34, 0x67, 0x55, 0x32, 0x56, 0x79, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58,
+    0x4d, 0x67, 0x52, 0x47, 0x6c, 0x32, 0x61, 0x58, 0x4e, 0x70, 0x62, 0x32,
+    0x34, 0x78, 0x49, 0x54, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41,
+    0x4d, 0x54, 0x47, 0x46, 0x52, 0x6f, 0x59, 0x58, 0x64, 0x30, 0x5a, 0x53,
+    0x42, 0x51, 0x63, 0x6d, 0x56, 0x74, 0x61, 0x58, 0x56, 0x74, 0x49, 0x46,
+    0x4e, 0x6c, 0x0a, 0x63, 0x6e, 0x5a, 0x6c, 0x63, 0x69, 0x42, 0x44, 0x51,
+    0x54, 0x45, 0x6f, 0x4d, 0x43, 0x59, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53,
+    0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x4a, 0x41, 0x52, 0x59, 0x5a, 0x63,
+    0x48, 0x4a, 0x6c, 0x62, 0x57, 0x6c, 0x31, 0x62, 0x53, 0x31, 0x7a, 0x5a,
+    0x58, 0x4a, 0x32, 0x5a, 0x58, 0x4a, 0x41, 0x64, 0x47, 0x68, 0x68, 0x64,
+    0x33, 0x52, 0x6c, 0x4c, 0x6d, 0x4e, 0x76, 0x0a, 0x62, 0x54, 0x43, 0x42,
+    0x6e, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47,
+    0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x42,
+    0x6a, 0x51, 0x41, 0x77, 0x67, 0x59, 0x6b, 0x43, 0x67, 0x59, 0x45, 0x41,
+    0x30, 0x6a, 0x59, 0x32, 0x61, 0x6f, 0x76, 0x58, 0x77, 0x6c, 0x75, 0x65,
+    0x32, 0x6f, 0x46, 0x42, 0x59, 0x6f, 0x38, 0x34, 0x37, 0x6b, 0x6b, 0x45,
+    0x0a, 0x56, 0x64, 0x62, 0x51, 0x37, 0x78, 0x77, 0x62, 0x6c, 0x52, 0x5a,
+    0x48, 0x37, 0x78, 0x68, 0x49, 0x4e, 0x54, 0x70, 0x53, 0x39, 0x43, 0x74,
+    0x71, 0x42, 0x6f, 0x38, 0x37, 0x4c, 0x2b, 0x70, 0x57, 0x34, 0x36, 0x2b,
+    0x47, 0x6a, 0x5a, 0x34, 0x58, 0x39, 0x35, 0x36, 0x30, 0x5a, 0x58, 0x55,
+    0x43, 0x54, 0x65, 0x2f, 0x4c, 0x43, 0x61, 0x49, 0x68, 0x55, 0x64, 0x69,
+    0x62, 0x30, 0x47, 0x66, 0x51, 0x0a, 0x75, 0x67, 0x32, 0x53, 0x42, 0x68,
+    0x52, 0x7a, 0x31, 0x4a, 0x50, 0x4c, 0x6c, 0x79, 0x6f, 0x41, 0x6e, 0x46,
+    0x78, 0x4f, 0x44, 0x4c, 0x7a, 0x36, 0x46, 0x56, 0x4c, 0x38, 0x38, 0x6b,
+    0x52, 0x75, 0x32, 0x68, 0x46, 0x4b, 0x62, 0x67, 0x69, 0x66, 0x4c, 0x79,
+    0x33, 0x6a, 0x2b, 0x61, 0x6f, 0x36, 0x68, 0x6e, 0x4f, 0x32, 0x52, 0x6c,
+    0x4e, 0x59, 0x79, 0x49, 0x6b, 0x46, 0x76, 0x59, 0x4d, 0x52, 0x0a, 0x75,
+    0x48, 0x4d, 0x2f, 0x71, 0x67, 0x65, 0x4e, 0x39, 0x45, 0x4a, 0x4e, 0x35,
+    0x30, 0x43, 0x64, 0x48, 0x44, 0x63, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41,
+    0x61, 0x4d, 0x54, 0x4d, 0x42, 0x45, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56,
+    0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41,
+    0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68,
+    0x6b, 0x69, 0x47, 0x0a, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x51, 0x46,
+    0x41, 0x41, 0x4f, 0x42, 0x67, 0x51, 0x41, 0x6d, 0x53, 0x43, 0x77, 0x57,
+    0x77, 0x6c, 0x6a, 0x36, 0x36, 0x42, 0x5a, 0x30, 0x44, 0x4b, 0x71, 0x71,
+    0x58, 0x31, 0x51, 0x2f, 0x38, 0x74, 0x66, 0x4a, 0x65, 0x47, 0x42, 0x65,
+    0x58, 0x6d, 0x34, 0x33, 0x59, 0x79, 0x4a, 0x33, 0x4e, 0x6e, 0x36, 0x79,
+    0x46, 0x38, 0x51, 0x30, 0x75, 0x66, 0x55, 0x49, 0x0a, 0x68, 0x66, 0x7a,
+    0x4a, 0x41, 0x54, 0x6a, 0x2f, 0x54, 0x62, 0x37, 0x79, 0x46, 0x6b, 0x4a,
+    0x44, 0x35, 0x37, 0x74, 0x61, 0x52, 0x76, 0x76, 0x42, 0x78, 0x68, 0x45,
+    0x66, 0x38, 0x55, 0x71, 0x77, 0x4b, 0x45, 0x62, 0x4a, 0x77, 0x38, 0x52,
+    0x43, 0x66, 0x62, 0x7a, 0x36, 0x71, 0x31, 0x6c, 0x75, 0x31, 0x62, 0x64,
+    0x52, 0x69, 0x42, 0x48, 0x6a, 0x70, 0x49, 0x55, 0x5a, 0x61, 0x34, 0x4a,
+    0x4d, 0x0a, 0x70, 0x41, 0x77, 0x53, 0x72, 0x65, 0x6d, 0x6b, 0x72, 0x6a,
+    0x2f, 0x78, 0x77, 0x30, 0x6c, 0x6c, 0x6d, 0x6f, 0x7a, 0x46, 0x79, 0x44,
+    0x34, 0x6c, 0x74, 0x35, 0x53, 0x5a, 0x75, 0x35, 0x49, 0x79, 0x63, 0x51,
+    0x66, 0x77, 0x68, 0x6c, 0x37, 0x74, 0x55, 0x43, 0x65, 0x6d, 0x44, 0x61,
+    0x59, 0x6a, 0x2b, 0x62, 0x76, 0x4c, 0x70, 0x67, 0x63, 0x55, 0x51, 0x67,
+    0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20,
+    0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75,
+    0x65, 0x72, 0x3a, 0x20, 0x4f, 0x3d, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61,
+    0x78, 0x20, 0x4f, 0x55, 0x3d, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78,
+    0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74,
+    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a,
+    0x65, 0x63, 0x74, 0x3a, 0x20, 0x4f, 0x3d, 0x45, 0x71, 0x75, 0x69, 0x66,
+    0x61, 0x78, 0x20, 0x4f, 0x55, 0x3d, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61,
+    0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72,
+    0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74,
+    0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62,
+    0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78,
+    0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x41, 0x22, 0x0a,
+    0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x39, 0x30,
+    0x33, 0x38, 0x30, 0x34, 0x31, 0x31, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44,
+    0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x36, 0x37, 0x3a, 0x63, 0x62, 0x3a, 0x39, 0x64, 0x3a,
+    0x63, 0x30, 0x3a, 0x31, 0x33, 0x3a, 0x32, 0x34, 0x3a, 0x38, 0x61, 0x3a,
+    0x38, 0x32, 0x3a, 0x39, 0x62, 0x3a, 0x62, 0x32, 0x3a, 0x31, 0x37, 0x3a,
+    0x31, 0x65, 0x3a, 0x64, 0x31, 0x3a, 0x31, 0x62, 0x3a, 0x65, 0x63, 0x3a,
+    0x64, 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69,
+    0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64,
+    0x32, 0x3a, 0x33, 0x32, 0x3a, 0x30, 0x39, 0x3a, 0x61, 0x64, 0x3a, 0x32,
+    0x33, 0x3a, 0x64, 0x33, 0x3a, 0x31, 0x34, 0x3a, 0x32, 0x33, 0x3a, 0x32,
+    0x31, 0x3a, 0x37, 0x34, 0x3a, 0x65, 0x34, 0x3a, 0x30, 0x64, 0x3a, 0x37,
+    0x66, 0x3a, 0x39, 0x64, 0x3a, 0x36, 0x32, 0x3a, 0x31, 0x33, 0x3a, 0x39,
+    0x37, 0x3a, 0x38, 0x36, 0x3a, 0x36, 0x33, 0x3a, 0x33, 0x61, 0x0a, 0x23,
+    0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x38, 0x3a,
+    0x32, 0x39, 0x3a, 0x37, 0x61, 0x3a, 0x34, 0x30, 0x3a, 0x34, 0x37, 0x3a,
+    0x64, 0x62, 0x3a, 0x61, 0x32, 0x3a, 0x33, 0x36, 0x3a, 0x38, 0x30, 0x3a,
+    0x63, 0x37, 0x3a, 0x33, 0x31, 0x3a, 0x64, 0x62, 0x3a, 0x36, 0x65, 0x3a,
+    0x33, 0x31, 0x3a, 0x37, 0x36, 0x3a, 0x35, 0x33, 0x3a, 0x63, 0x61, 0x3a,
+    0x37, 0x38, 0x3a, 0x34, 0x38, 0x3a, 0x65, 0x31, 0x3a, 0x62, 0x65, 0x3a,
+    0x62, 0x64, 0x3a, 0x33, 0x61, 0x3a, 0x30, 0x62, 0x3a, 0x30, 0x31, 0x3a,
+    0x37, 0x39, 0x3a, 0x61, 0x37, 0x3a, 0x30, 0x37, 0x3a, 0x66, 0x39, 0x3a,
+    0x32, 0x63, 0x3a, 0x66, 0x31, 0x3a, 0x37, 0x38, 0x0a, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54,
+    0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x0a, 0x4d, 0x49, 0x49, 0x44, 0x49, 0x44, 0x43, 0x43, 0x41, 0x6f, 0x6d,
+    0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x45, 0x4e, 0x64, 0x37,
+    0x30, 0x7a, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69,
+    0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42,
+    0x4f, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x47, 0x45, 0x77, 0x4a, 0x56, 0x0a, 0x55, 0x7a, 0x45, 0x51, 0x4d, 0x41,
+    0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x48, 0x52, 0x58,
+    0x46, 0x31, 0x61, 0x57, 0x5a, 0x68, 0x65, 0x44, 0x45, 0x74, 0x4d, 0x43,
+    0x73, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x6b, 0x52, 0x58,
+    0x46, 0x31, 0x61, 0x57, 0x5a, 0x68, 0x65, 0x43, 0x42, 0x54, 0x5a, 0x57,
+    0x4e, 0x31, 0x63, 0x6d, 0x55, 0x67, 0x51, 0x32, 0x56, 0x79, 0x0a, 0x64,
+    0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x55, 0x67, 0x51,
+    0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d,
+    0x42, 0x34, 0x58, 0x44, 0x54, 0x6b, 0x34, 0x4d, 0x44, 0x67, 0x79, 0x4d,
+    0x6a, 0x45, 0x32, 0x4e, 0x44, 0x45, 0x31, 0x4d, 0x56, 0x6f, 0x58, 0x44,
+    0x54, 0x45, 0x34, 0x4d, 0x44, 0x67, 0x79, 0x4d, 0x6a, 0x45, 0x32, 0x4e,
+    0x44, 0x45, 0x31, 0x0a, 0x4d, 0x56, 0x6f, 0x77, 0x54, 0x6a, 0x45, 0x4c,
+    0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43,
+    0x56, 0x56, 0x4d, 0x78, 0x45, 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x6f, 0x54, 0x42, 0x30, 0x56, 0x78, 0x64, 0x57, 0x6c, 0x6d,
+    0x59, 0x58, 0x67, 0x78, 0x4c, 0x54, 0x41, 0x72, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x73, 0x54, 0x4a, 0x45, 0x56, 0x78, 0x0a, 0x64, 0x57, 0x6c,
+    0x6d, 0x59, 0x58, 0x67, 0x67, 0x55, 0x32, 0x56, 0x6a, 0x64, 0x58, 0x4a,
+    0x6c, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c,
+    0x6a, 0x59, 0x58, 0x52, 0x6c, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68,
+    0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, 0x43, 0x42, 0x6e, 0x7a, 0x41,
+    0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30,
+    0x42, 0x0a, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x42, 0x6a, 0x51,
+    0x41, 0x77, 0x67, 0x59, 0x6b, 0x43, 0x67, 0x59, 0x45, 0x41, 0x77, 0x56,
+    0x32, 0x78, 0x57, 0x47, 0x63, 0x49, 0x59, 0x75, 0x36, 0x67, 0x6d, 0x69,
+    0x30, 0x66, 0x43, 0x47, 0x32, 0x52, 0x46, 0x47, 0x69, 0x59, 0x43, 0x68,
+    0x37, 0x2b, 0x32, 0x67, 0x52, 0x76, 0x45, 0x34, 0x52, 0x69, 0x49, 0x63,
+    0x50, 0x52, 0x66, 0x4d, 0x36, 0x66, 0x0a, 0x42, 0x65, 0x43, 0x34, 0x41,
+    0x66, 0x42, 0x4f, 0x4e, 0x4f, 0x7a, 0x69, 0x69, 0x70, 0x55, 0x45, 0x5a,
+    0x4b, 0x7a, 0x78, 0x61, 0x31, 0x4e, 0x66, 0x42, 0x62, 0x50, 0x4c, 0x5a,
+    0x34, 0x43, 0x2f, 0x51, 0x67, 0x4b, 0x4f, 0x2f, 0x74, 0x30, 0x42, 0x43,
+    0x65, 0x7a, 0x68, 0x41, 0x42, 0x52, 0x50, 0x2f, 0x50, 0x76, 0x77, 0x44,
+    0x4e, 0x31, 0x44, 0x75, 0x6c, 0x73, 0x72, 0x34, 0x52, 0x2b, 0x41, 0x0a,
+    0x63, 0x4a, 0x6b, 0x56, 0x56, 0x35, 0x4d, 0x57, 0x38, 0x51, 0x2b, 0x58,
+    0x61, 0x72, 0x66, 0x43, 0x61, 0x43, 0x4d, 0x63, 0x7a, 0x45, 0x31, 0x5a,
+    0x4d, 0x4b, 0x78, 0x52, 0x48, 0x6a, 0x75, 0x76, 0x4b, 0x39, 0x62, 0x75,
+    0x59, 0x30, 0x56, 0x37, 0x78, 0x64, 0x6c, 0x66, 0x55, 0x4e, 0x4c, 0x6a,
+    0x55, 0x41, 0x38, 0x36, 0x69, 0x4f, 0x65, 0x2f, 0x46, 0x50, 0x33, 0x67,
+    0x78, 0x37, 0x6b, 0x43, 0x0a, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4f,
+    0x43, 0x41, 0x51, 0x6b, 0x77, 0x67, 0x67, 0x45, 0x46, 0x4d, 0x48, 0x41,
+    0x47, 0x41, 0x31, 0x55, 0x64, 0x48, 0x77, 0x52, 0x70, 0x4d, 0x47, 0x63,
+    0x77, 0x5a, 0x61, 0x42, 0x6a, 0x6f, 0x47, 0x47, 0x6b, 0x58, 0x7a, 0x42,
+    0x64, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x51, 0x0a, 0x4d, 0x41,
+    0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x48, 0x52, 0x58,
+    0x46, 0x31, 0x61, 0x57, 0x5a, 0x68, 0x65, 0x44, 0x45, 0x74, 0x4d, 0x43,
+    0x73, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x6b, 0x52, 0x58,
+    0x46, 0x31, 0x61, 0x57, 0x5a, 0x68, 0x65, 0x43, 0x42, 0x54, 0x5a, 0x57,
+    0x4e, 0x31, 0x63, 0x6d, 0x55, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47,
+    0x6c, 0x6d, 0x0a, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x55, 0x67, 0x51,
+    0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d,
+    0x51, 0x30, 0x77, 0x43, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45,
+    0x77, 0x52, 0x44, 0x55, 0x6b, 0x77, 0x78, 0x4d, 0x42, 0x6f, 0x47, 0x41,
+    0x31, 0x55, 0x64, 0x45, 0x41, 0x51, 0x54, 0x4d, 0x42, 0x47, 0x42, 0x44,
+    0x7a, 0x49, 0x77, 0x4d, 0x54, 0x67, 0x77, 0x0a, 0x4f, 0x44, 0x49, 0x79,
+    0x4d, 0x54, 0x59, 0x30, 0x4d, 0x54, 0x55, 0x78, 0x57, 0x6a, 0x41, 0x4c,
+    0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43,
+    0x41, 0x51, 0x59, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6a,
+    0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x53, 0x4f, 0x5a, 0x6f,
+    0x2b, 0x53, 0x76, 0x53, 0x73, 0x70, 0x58, 0x58, 0x52, 0x39, 0x67, 0x6a,
+    0x0a, 0x49, 0x42, 0x42, 0x50, 0x4d, 0x35, 0x69, 0x51, 0x6e, 0x39, 0x51,
+    0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59,
+    0x45, 0x46, 0x45, 0x6a, 0x6d, 0x61, 0x50, 0x6b, 0x72, 0x30, 0x72, 0x4b,
+    0x56, 0x31, 0x30, 0x66, 0x59, 0x49, 0x79, 0x41, 0x51, 0x54, 0x7a, 0x4f,
+    0x59, 0x6b, 0x4a, 0x2f, 0x55, 0x4d, 0x41, 0x77, 0x47, 0x41, 0x31, 0x55,
+    0x64, 0x45, 0x77, 0x51, 0x46, 0x0a, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66,
+    0x38, 0x77, 0x47, 0x67, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76,
+    0x5a, 0x39, 0x42, 0x30, 0x45, 0x41, 0x42, 0x41, 0x30, 0x77, 0x43, 0x78,
+    0x73, 0x46, 0x56, 0x6a, 0x4d, 0x75, 0x4d, 0x47, 0x4d, 0x44, 0x41, 0x67,
+    0x62, 0x41, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49,
+    0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x0a, 0x41,
+    0x34, 0x47, 0x42, 0x41, 0x46, 0x6a, 0x4f, 0x4b, 0x65, 0x72, 0x38, 0x39,
+    0x39, 0x36, 0x31, 0x7a, 0x67, 0x4b, 0x35, 0x46, 0x37, 0x57, 0x46, 0x30,
+    0x62, 0x6e, 0x6a, 0x34, 0x4a, 0x58, 0x4d, 0x4a, 0x54, 0x45, 0x4e, 0x41,
+    0x4b, 0x61, 0x53, 0x62, 0x6e, 0x2b, 0x32, 0x6b, 0x6d, 0x4f, 0x65, 0x55,
+    0x4a, 0x58, 0x52, 0x6d, 0x6d, 0x2f, 0x6b, 0x45, 0x64, 0x35, 0x6a, 0x68,
+    0x57, 0x36, 0x59, 0x0a, 0x37, 0x71, 0x6a, 0x2f, 0x57, 0x73, 0x6a, 0x54,
+    0x56, 0x62, 0x4a, 0x6d, 0x63, 0x56, 0x66, 0x65, 0x77, 0x43, 0x48, 0x72,
+    0x50, 0x53, 0x71, 0x6e, 0x49, 0x30, 0x6b, 0x42, 0x42, 0x49, 0x5a, 0x43,
+    0x65, 0x2f, 0x7a, 0x75, 0x66, 0x36, 0x49, 0x57, 0x55, 0x72, 0x56, 0x6e,
+    0x5a, 0x39, 0x4e, 0x41, 0x32, 0x7a, 0x73, 0x6d, 0x57, 0x4c, 0x49, 0x6f,
+    0x64, 0x7a, 0x32, 0x75, 0x46, 0x48, 0x64, 0x68, 0x0a, 0x31, 0x76, 0x6f,
+    0x71, 0x5a, 0x69, 0x65, 0x67, 0x44, 0x66, 0x71, 0x6e, 0x63, 0x31, 0x7a,
+    0x71, 0x63, 0x50, 0x47, 0x55, 0x49, 0x57, 0x56, 0x45, 0x58, 0x2f, 0x72,
+    0x38, 0x37, 0x79, 0x6c, 0x6f, 0x71, 0x61, 0x4b, 0x48, 0x65, 0x65, 0x39,
+    0x35, 0x37, 0x30, 0x2b, 0x73, 0x42, 0x33, 0x63, 0x34, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49,
+    0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a,
+    0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x4f,
+    0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49,
+    0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x6c, 0x61, 0x73, 0x73,
+    0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72,
+    0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+    0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a,
+    0x65, 0x63, 0x74, 0x3a, 0x20, 0x4f, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53,
+    0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55,
+    0x3d, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62,
+    0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20,
+    0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+    0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a,
+    0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x56, 0x65,
+    0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73,
+    0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72,
+    0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+    0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72,
+    0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x34, 0x39, 0x38, 0x34, 0x33, 0x39,
+    0x32, 0x39, 0x34, 0x33, 0x35, 0x38, 0x31, 0x38, 0x36, 0x39, 0x32, 0x38,
+    0x34, 0x38, 0x30, 0x34, 0x30, 0x33, 0x36, 0x35, 0x37, 0x31, 0x36, 0x38,
+    0x35, 0x31, 0x37, 0x30, 0x32, 0x34, 0x36, 0x33, 0x0a, 0x23, 0x20, 0x4d,
+    0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x31, 0x30, 0x3a, 0x66, 0x63, 0x3a, 0x36, 0x33,
+    0x3a, 0x35, 0x64, 0x3a, 0x66, 0x36, 0x3a, 0x32, 0x36, 0x3a, 0x33, 0x65,
+    0x3a, 0x30, 0x64, 0x3a, 0x66, 0x33, 0x3a, 0x32, 0x35, 0x3a, 0x62, 0x65,
+    0x3a, 0x35, 0x66, 0x3a, 0x37, 0x39, 0x3a, 0x63, 0x64, 0x3a, 0x36, 0x37,
+    0x3a, 0x36, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x37, 0x34, 0x3a, 0x32, 0x63, 0x3a, 0x33, 0x31, 0x3a, 0x39, 0x32, 0x3a,
+    0x65, 0x36, 0x3a, 0x30, 0x37, 0x3a, 0x65, 0x34, 0x3a, 0x32, 0x34, 0x3a,
+    0x65, 0x62, 0x3a, 0x34, 0x35, 0x3a, 0x34, 0x39, 0x3a, 0x35, 0x34, 0x3a,
+    0x32, 0x62, 0x3a, 0x65, 0x31, 0x3a, 0x62, 0x62, 0x3a, 0x63, 0x35, 0x3a,
+    0x33, 0x65, 0x3a, 0x36, 0x31, 0x3a, 0x37, 0x34, 0x3a, 0x65, 0x32, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x37,
+    0x3a, 0x36, 0x38, 0x3a, 0x35, 0x36, 0x3a, 0x33, 0x34, 0x3a, 0x65, 0x66,
+    0x3a, 0x61, 0x63, 0x3a, 0x66, 0x36, 0x3a, 0x39, 0x61, 0x3a, 0x63, 0x65,
+    0x3a, 0x39, 0x33, 0x3a, 0x39, 0x61, 0x3a, 0x36, 0x62, 0x3a, 0x32, 0x35,
+    0x3a, 0x35, 0x62, 0x3a, 0x37, 0x62, 0x3a, 0x34, 0x66, 0x3a, 0x61, 0x62,
+    0x3a, 0x65, 0x66, 0x3a, 0x34, 0x32, 0x3a, 0x39, 0x33, 0x3a, 0x35, 0x62,
+    0x3a, 0x35, 0x30, 0x3a, 0x61, 0x32, 0x3a, 0x36, 0x35, 0x3a, 0x61, 0x63,
+    0x3a, 0x62, 0x35, 0x3a, 0x63, 0x62, 0x3a, 0x36, 0x30, 0x3a, 0x32, 0x37,
+    0x3a, 0x65, 0x34, 0x3a, 0x34, 0x65, 0x3a, 0x37, 0x30, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52,
+    0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x50, 0x44, 0x43, 0x43, 0x41, 0x61,
+    0x55, 0x43, 0x45, 0x48, 0x43, 0x36, 0x35, 0x42, 0x30, 0x51, 0x32, 0x53,
+    0x6b, 0x30, 0x74, 0x6a, 0x6a, 0x4b, 0x65, 0x77, 0x50, 0x4d, 0x75, 0x72,
+    0x38, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76,
+    0x63, 0x4e, 0x41, 0x51, 0x45, 0x43, 0x42, 0x51, 0x41, 0x77, 0x58, 0x7a,
+    0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42,
+    0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x7a, 0x41, 0x56, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x6c, 0x5a, 0x6c, 0x63,
+    0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x4c, 0x43, 0x42, 0x4a, 0x62,
+    0x6d, 0x4d, 0x75, 0x4d, 0x54, 0x63, 0x77, 0x4e, 0x51, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x4c, 0x45, 0x79, 0x35, 0x44, 0x62, 0x47, 0x46, 0x7a, 0x0a,
+    0x63, 0x79, 0x41, 0x7a, 0x49, 0x46, 0x42, 0x31, 0x59, 0x6d, 0x78, 0x70,
+    0x59, 0x79, 0x42, 0x51, 0x63, 0x6d, 0x6c, 0x74, 0x59, 0x58, 0x4a, 0x35,
+    0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a,
+    0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30,
+    0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x42, 0x34, 0x58,
+    0x44, 0x54, 0x6b, 0x32, 0x0a, 0x4d, 0x44, 0x45, 0x79, 0x4f, 0x54, 0x41,
+    0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x49,
+    0x34, 0x4d, 0x44, 0x67, 0x77, 0x4d, 0x54, 0x49, 0x7a, 0x4e, 0x54, 0x6b,
+    0x31, 0x4f, 0x56, 0x6f, 0x77, 0x58, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d,
+    0x78, 0x46, 0x7a, 0x41, 0x56, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41,
+    0x6f, 0x54, 0x44, 0x6c, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57,
+    0x64, 0x75, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x54,
+    0x63, 0x77, 0x4e, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x79,
+    0x35, 0x44, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, 0x41, 0x7a, 0x49, 0x46,
+    0x42, 0x31, 0x59, 0x6d, 0x78, 0x70, 0x59, 0x79, 0x42, 0x51, 0x63, 0x6d,
+    0x6c, 0x74, 0x0a, 0x59, 0x58, 0x4a, 0x35, 0x49, 0x45, 0x4e, 0x6c, 0x63,
+    0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62,
+    0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61,
+    0x58, 0x52, 0x35, 0x4d, 0x49, 0x47, 0x66, 0x4d, 0x41, 0x30, 0x47, 0x43,
+    0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41,
+    0x51, 0x55, 0x41, 0x41, 0x34, 0x47, 0x4e, 0x0a, 0x41, 0x44, 0x43, 0x42,
+    0x69, 0x51, 0x4b, 0x42, 0x67, 0x51, 0x44, 0x4a, 0x58, 0x46, 0x6d, 0x65,
+    0x38, 0x68, 0x75, 0x4b, 0x41, 0x52, 0x53, 0x30, 0x45, 0x4e, 0x38, 0x45,
+    0x51, 0x4e, 0x76, 0x6a, 0x56, 0x36, 0x39, 0x71, 0x52, 0x55, 0x43, 0x50,
+    0x68, 0x41, 0x77, 0x4c, 0x30, 0x54, 0x50, 0x5a, 0x32, 0x52, 0x48, 0x50,
+    0x37, 0x67, 0x4a, 0x59, 0x48, 0x79, 0x58, 0x33, 0x4b, 0x71, 0x68, 0x45,
+    0x0a, 0x42, 0x61, 0x72, 0x73, 0x41, 0x78, 0x39, 0x34, 0x66, 0x35, 0x36,
+    0x54, 0x75, 0x5a, 0x6f, 0x41, 0x71, 0x69, 0x4e, 0x39, 0x31, 0x71, 0x79,
+    0x46, 0x6f, 0x6d, 0x4e, 0x46, 0x78, 0x33, 0x49, 0x6e, 0x7a, 0x50, 0x52,
+    0x4d, 0x78, 0x6e, 0x56, 0x78, 0x30, 0x6a, 0x6e, 0x76, 0x54, 0x30, 0x4c,
+    0x77, 0x64, 0x64, 0x38, 0x4b, 0x6b, 0x4d, 0x61, 0x4f, 0x49, 0x47, 0x2b,
+    0x59, 0x44, 0x2f, 0x69, 0x73, 0x0a, 0x49, 0x31, 0x39, 0x77, 0x4b, 0x54,
+    0x61, 0x6b, 0x79, 0x59, 0x62, 0x6e, 0x73, 0x5a, 0x6f, 0x67, 0x79, 0x31,
+    0x4f, 0x6c, 0x68, 0x65, 0x63, 0x39, 0x76, 0x6e, 0x32, 0x61, 0x2f, 0x69,
+    0x52, 0x46, 0x4d, 0x39, 0x78, 0x32, 0x46, 0x65, 0x30, 0x50, 0x6f, 0x6e,
+    0x46, 0x6b, 0x54, 0x47, 0x55, 0x75, 0x67, 0x57, 0x68, 0x46, 0x70, 0x77,
+    0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x4d, 0x41, 0x30, 0x47, 0x0a, 0x43,
+    0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41,
+    0x67, 0x55, 0x41, 0x41, 0x34, 0x47, 0x42, 0x41, 0x4c, 0x74, 0x4d, 0x45,
+    0x69, 0x76, 0x50, 0x4c, 0x43, 0x59, 0x41, 0x54, 0x78, 0x51, 0x54, 0x33,
+    0x61, 0x62, 0x37, 0x2f, 0x41, 0x6f, 0x52, 0x68, 0x49, 0x7a, 0x7a, 0x4b,
+    0x42, 0x78, 0x6e, 0x6b, 0x69, 0x39, 0x38, 0x74, 0x73, 0x58, 0x36, 0x33,
+    0x2f, 0x44, 0x6f, 0x0a, 0x6c, 0x62, 0x77, 0x64, 0x6a, 0x32, 0x77, 0x73,
+    0x71, 0x46, 0x48, 0x4d, 0x63, 0x39, 0x69, 0x6b, 0x77, 0x46, 0x50, 0x77,
+    0x54, 0x74, 0x59, 0x6d, 0x77, 0x48, 0x59, 0x42, 0x56, 0x34, 0x47, 0x53,
+    0x58, 0x69, 0x48, 0x78, 0x30, 0x62, 0x48, 0x2f, 0x35, 0x39, 0x41, 0x68,
+    0x57, 0x4d, 0x31, 0x70, 0x46, 0x2b, 0x4e, 0x45, 0x48, 0x4a, 0x77, 0x5a,
+    0x52, 0x44, 0x6d, 0x4a, 0x58, 0x4e, 0x79, 0x63, 0x0a, 0x41, 0x41, 0x39,
+    0x57, 0x6a, 0x51, 0x4b, 0x5a, 0x37, 0x61, 0x4b, 0x51, 0x52, 0x55, 0x7a,
+    0x6b, 0x75, 0x78, 0x43, 0x6b, 0x50, 0x66, 0x41, 0x79, 0x41, 0x77, 0x37,
+    0x78, 0x7a, 0x76, 0x6a, 0x6f, 0x79, 0x56, 0x47, 0x4d, 0x35, 0x6d, 0x4b,
+    0x66, 0x35, 0x70, 0x2f, 0x41, 0x66, 0x62, 0x64, 0x79, 0x6e, 0x4d, 0x6b,
+    0x32, 0x4f, 0x6d, 0x75, 0x66, 0x54, 0x71, 0x6a, 0x2f, 0x5a, 0x41, 0x31,
+    0x6b, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65,
+    0x72, 0x3a, 0x20, 0x4f, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+    0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x43,
+    0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69,
+    0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65,
+    0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+    0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20,
+    0x47, 0x32, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x38, 0x20,
+    0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e,
+    0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74,
+    0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20,
+    0x6f, 0x6e, 0x6c, 0x79, 0x2f, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+    0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77,
+    0x6f, 0x72, 0x6b, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63,
+    0x74, 0x3a, 0x20, 0x4f, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+    0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x43,
+    0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69,
+    0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65,
+    0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+    0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20,
+    0x47, 0x32, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x38, 0x20,
+    0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e,
+    0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74,
+    0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20,
+    0x6f, 0x6e, 0x6c, 0x79, 0x2f, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+    0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77,
+    0x6f, 0x72, 0x6b, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a,
+    0x20, 0x22, 0x56, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x43,
+    0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69,
+    0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65,
+    0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+    0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20,
+    0x47, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c,
+    0x3a, 0x20, 0x31, 0x36, 0x37, 0x32, 0x38, 0x35, 0x33, 0x38, 0x30, 0x32,
+    0x34, 0x32, 0x33, 0x31, 0x39, 0x36, 0x34, 0x38, 0x34, 0x35, 0x31, 0x31,
+    0x35, 0x34, 0x34, 0x37, 0x38, 0x38, 0x30, 0x38, 0x30, 0x33, 0x36, 0x38,
+    0x38, 0x31, 0x36, 0x30, 0x36, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x61, 0x32, 0x3a, 0x33, 0x33, 0x3a, 0x39, 0x62, 0x3a, 0x34, 0x63,
+    0x3a, 0x37, 0x34, 0x3a, 0x37, 0x38, 0x3a, 0x37, 0x33, 0x3a, 0x64, 0x34,
+    0x3a, 0x36, 0x63, 0x3a, 0x65, 0x37, 0x3a, 0x63, 0x31, 0x3a, 0x66, 0x33,
+    0x3a, 0x38, 0x64, 0x3a, 0x63, 0x62, 0x3a, 0x35, 0x63, 0x3a, 0x65, 0x39,
+    0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x35, 0x3a,
+    0x33, 0x37, 0x3a, 0x31, 0x63, 0x3a, 0x61, 0x36, 0x3a, 0x65, 0x35, 0x3a,
+    0x35, 0x30, 0x3a, 0x31, 0x34, 0x3a, 0x33, 0x64, 0x3a, 0x63, 0x65, 0x3a,
+    0x32, 0x38, 0x3a, 0x30, 0x33, 0x3a, 0x34, 0x37, 0x3a, 0x31, 0x62, 0x3a,
+    0x64, 0x65, 0x3a, 0x33, 0x61, 0x3a, 0x30, 0x39, 0x3a, 0x65, 0x38, 0x3a,
+    0x66, 0x38, 0x3a, 0x37, 0x37, 0x3a, 0x30, 0x66, 0x0a, 0x23, 0x20, 0x53,
+    0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x33, 0x3a, 0x63, 0x65,
+    0x3a, 0x33, 0x63, 0x3a, 0x31, 0x32, 0x3a, 0x32, 0x39, 0x3a, 0x36, 0x38,
+    0x3a, 0x38, 0x61, 0x3a, 0x35, 0x39, 0x3a, 0x33, 0x64, 0x3a, 0x34, 0x38,
+    0x3a, 0x35, 0x66, 0x3a, 0x38, 0x31, 0x3a, 0x39, 0x37, 0x3a, 0x33, 0x63,
+    0x3a, 0x30, 0x66, 0x3a, 0x39, 0x31, 0x3a, 0x39, 0x35, 0x3a, 0x34, 0x33,
+    0x3a, 0x31, 0x65, 0x3a, 0x64, 0x61, 0x3a, 0x33, 0x37, 0x3a, 0x63, 0x63,
+    0x3a, 0x35, 0x65, 0x3a, 0x33, 0x36, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x65,
+    0x3a, 0x37, 0x39, 0x3a, 0x63, 0x37, 0x3a, 0x61, 0x38, 0x3a, 0x38, 0x38,
+    0x3a, 0x36, 0x33, 0x3a, 0x38, 0x62, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d,
+    0x49, 0x49, 0x44, 0x41, 0x6a, 0x43, 0x43, 0x41, 0x6d, 0x73, 0x43, 0x45,
+    0x48, 0x33, 0x5a, 0x2f, 0x67, 0x66, 0x50, 0x71, 0x42, 0x36, 0x33, 0x45,
+    0x48, 0x6c, 0x6e, 0x2b, 0x36, 0x65, 0x4a, 0x4e, 0x4d, 0x59, 0x77, 0x44,
+    0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41,
+    0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x67, 0x63, 0x45, 0x78, 0x43,
+    0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54,
+    0x41, 0x6c, 0x56, 0x54, 0x4d, 0x52, 0x63, 0x77, 0x46, 0x51, 0x59, 0x44,
+    0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x35, 0x57, 0x5a, 0x58, 0x4a, 0x70,
+    0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a,
+    0x4c, 0x6a, 0x45, 0x38, 0x4d, 0x44, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x43, 0x78, 0x4d, 0x7a, 0x51, 0x32, 0x78, 0x68, 0x0a, 0x63, 0x33, 0x4d,
+    0x67, 0x4d, 0x79, 0x42, 0x51, 0x64, 0x57, 0x4a, 0x73, 0x61, 0x57, 0x4d,
+    0x67, 0x55, 0x48, 0x4a, 0x70, 0x62, 0x57, 0x46, 0x79, 0x65, 0x53, 0x42,
+    0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46,
+    0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68,
+    0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63,
+    0x79, 0x0a, 0x4d, 0x54, 0x6f, 0x77, 0x4f, 0x41, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x4c, 0x45, 0x7a, 0x45, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x54,
+    0x6b, 0x35, 0x4f, 0x43, 0x42, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32,
+    0x6c, 0x6e, 0x62, 0x69, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x69,
+    0x41, 0x74, 0x49, 0x45, 0x5a, 0x76, 0x63, 0x69, 0x42, 0x68, 0x64, 0x58,
+    0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x0a, 0x65, 0x6d, 0x56, 0x6b, 0x49,
+    0x48, 0x56, 0x7a, 0x5a, 0x53, 0x42, 0x76, 0x62, 0x6d, 0x78, 0x35, 0x4d,
+    0x52, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45,
+    0x78, 0x5a, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62,
+    0x69, 0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4f, 0x5a,
+    0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x4d, 0x42, 0x34, 0x58, 0x0a,
+    0x44, 0x54, 0x6b, 0x34, 0x4d, 0x44, 0x55, 0x78, 0x4f, 0x44, 0x41, 0x77,
+    0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x34,
+    0x4d, 0x44, 0x67, 0x77, 0x4d, 0x54, 0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31,
+    0x4f, 0x56, 0x6f, 0x77, 0x67, 0x63, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a,
+    0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54,
+    0x4d, 0x52, 0x63, 0x77, 0x0a, 0x46, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x4b, 0x45, 0x77, 0x35, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c,
+    0x6e, 0x62, 0x69, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45,
+    0x38, 0x4d, 0x44, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d,
+    0x7a, 0x51, 0x32, 0x78, 0x68, 0x63, 0x33, 0x4d, 0x67, 0x4d, 0x79, 0x42,
+    0x51, 0x64, 0x57, 0x4a, 0x73, 0x61, 0x57, 0x4d, 0x67, 0x0a, 0x55, 0x48,
+    0x4a, 0x70, 0x62, 0x57, 0x46, 0x79, 0x65, 0x53, 0x42, 0x44, 0x5a, 0x58,
+    0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57,
+    0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d,
+    0x6c, 0x30, 0x65, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x79, 0x4d, 0x54,
+    0x6f, 0x77, 0x4f, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x7a,
+    0x45, 0x6f, 0x0a, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x54, 0x6b, 0x35, 0x4f,
+    0x43, 0x42, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62,
+    0x69, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x69, 0x41, 0x74, 0x49,
+    0x45, 0x5a, 0x76, 0x63, 0x69, 0x42, 0x68, 0x64, 0x58, 0x52, 0x6f, 0x62,
+    0x33, 0x4a, 0x70, 0x65, 0x6d, 0x56, 0x6b, 0x49, 0x48, 0x56, 0x7a, 0x5a,
+    0x53, 0x42, 0x76, 0x62, 0x6d, 0x78, 0x35, 0x0a, 0x4d, 0x52, 0x38, 0x77,
+    0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x5a, 0x57,
+    0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x55,
+    0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33,
+    0x62, 0x33, 0x4a, 0x72, 0x4d, 0x49, 0x47, 0x66, 0x4d, 0x41, 0x30, 0x47,
+    0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42,
+    0x0a, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x47, 0x4e, 0x41, 0x44, 0x43,
+    0x42, 0x69, 0x51, 0x4b, 0x42, 0x67, 0x51, 0x44, 0x4d, 0x58, 0x74, 0x45,
+    0x52, 0x58, 0x56, 0x78, 0x70, 0x30, 0x4b, 0x76, 0x54, 0x75, 0x57, 0x70,
+    0x4d, 0x6d, 0x52, 0x39, 0x5a, 0x6d, 0x44, 0x43, 0x4f, 0x46, 0x6f, 0x55,
+    0x67, 0x52, 0x6d, 0x31, 0x48, 0x50, 0x39, 0x53, 0x46, 0x49, 0x49, 0x54,
+    0x68, 0x62, 0x62, 0x50, 0x34, 0x0a, 0x70, 0x4f, 0x30, 0x4d, 0x38, 0x52,
+    0x63, 0x50, 0x4f, 0x2f, 0x6d, 0x6e, 0x2b, 0x53, 0x58, 0x58, 0x77, 0x63,
+    0x2b, 0x45, 0x59, 0x2f, 0x4a, 0x38, 0x59, 0x38, 0x2b, 0x69, 0x52, 0x2f,
+    0x4c, 0x47, 0x57, 0x7a, 0x4f, 0x4f, 0x5a, 0x45, 0x41, 0x45, 0x61, 0x4d,
+    0x47, 0x41, 0x75, 0x57, 0x51, 0x63, 0x52, 0x58, 0x66, 0x48, 0x32, 0x47,
+    0x37, 0x31, 0x6c, 0x53, 0x6b, 0x38, 0x55, 0x4f, 0x67, 0x30, 0x0a, 0x31,
+    0x33, 0x67, 0x66, 0x71, 0x4c, 0x70, 0x74, 0x51, 0x35, 0x47, 0x56, 0x6a,
+    0x30, 0x56, 0x58, 0x58, 0x6e, 0x37, 0x46, 0x2b, 0x38, 0x71, 0x6b, 0x42,
+    0x4f, 0x76, 0x71, 0x6c, 0x7a, 0x64, 0x55, 0x4d, 0x47, 0x2b, 0x37, 0x41,
+    0x55, 0x63, 0x79, 0x4d, 0x38, 0x33, 0x63, 0x56, 0x35, 0x74, 0x6b, 0x61,
+    0x57, 0x48, 0x34, 0x6d, 0x78, 0x30, 0x63, 0x69, 0x55, 0x39, 0x63, 0x5a,
+    0x77, 0x49, 0x44, 0x0a, 0x41, 0x51, 0x41, 0x42, 0x4d, 0x41, 0x30, 0x47,
+    0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42,
+    0x42, 0x51, 0x55, 0x41, 0x41, 0x34, 0x47, 0x42, 0x41, 0x46, 0x46, 0x4e,
+    0x7a, 0x62, 0x35, 0x63, 0x79, 0x35, 0x67, 0x5a, 0x6e, 0x42, 0x57, 0x79,
+    0x41, 0x54, 0x6c, 0x34, 0x4c, 0x6b, 0x30, 0x50, 0x5a, 0x33, 0x42, 0x77,
+    0x6d, 0x63, 0x59, 0x51, 0x57, 0x70, 0x53, 0x6b, 0x0a, 0x55, 0x30, 0x31,
+    0x55, 0x62, 0x53, 0x75, 0x76, 0x44, 0x56, 0x31, 0x41, 0x69, 0x32, 0x54,
+    0x54, 0x31, 0x2b, 0x37, 0x65, 0x56, 0x6d, 0x47, 0x53, 0x58, 0x36, 0x62,
+    0x45, 0x48, 0x52, 0x42, 0x68, 0x4e, 0x74, 0x4d, 0x73, 0x4a, 0x7a, 0x7a,
+    0x6f, 0x4b, 0x51, 0x6d, 0x35, 0x45, 0x57, 0x52, 0x30, 0x7a, 0x4c, 0x56,
+    0x7a, 0x6e, 0x78, 0x78, 0x49, 0x71, 0x62, 0x78, 0x68, 0x41, 0x65, 0x37,
+    0x69, 0x0a, 0x46, 0x36, 0x59, 0x4d, 0x34, 0x30, 0x41, 0x49, 0x4f, 0x77,
+    0x37, 0x6e, 0x36, 0x30, 0x52, 0x7a, 0x4b, 0x70, 0x72, 0x78, 0x61, 0x5a,
+    0x4c, 0x76, 0x63, 0x52, 0x54, 0x44, 0x4f, 0x61, 0x78, 0x78, 0x70, 0x35,
+    0x45, 0x4a, 0x62, 0x2b, 0x52, 0x78, 0x42, 0x72, 0x4f, 0x36, 0x57, 0x56,
+    0x63, 0x6d, 0x65, 0x51, 0x44, 0x32, 0x2b, 0x41, 0x32, 0x69, 0x4d, 0x7a,
+    0x41, 0x6f, 0x31, 0x4b, 0x70, 0x59, 0x0a, 0x6f, 0x4a, 0x32, 0x64, 0x61,
+    0x5a, 0x48, 0x39, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73,
+    0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x6c, 0x6f, 0x62,
+    0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+    0x43, 0x41, 0x20, 0x4f, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53,
+    0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, 0x20, 0x4f, 0x55,
+    0x3d, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x0a, 0x23, 0x20, 0x53,
+    0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47,
+    0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f,
+    0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x47, 0x6c, 0x6f, 0x62,
+    0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61,
+    0x20, 0x4f, 0x55, 0x3d, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x0a,
+    0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x6c,
+    0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f,
+    0x74, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69,
+    0x61, 0x6c, 0x3a, 0x20, 0x34, 0x38, 0x33, 0x35, 0x37, 0x30, 0x33, 0x32,
+    0x37, 0x38, 0x34, 0x35, 0x39, 0x37, 0x30, 0x37, 0x36, 0x36, 0x39, 0x30,
+    0x30, 0x35, 0x32, 0x30, 0x34, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x33, 0x65, 0x3a, 0x34, 0x35, 0x3a, 0x35, 0x32, 0x3a, 0x31, 0x35,
+    0x3a, 0x30, 0x39, 0x3a, 0x35, 0x31, 0x3a, 0x39, 0x32, 0x3a, 0x65, 0x31,
+    0x3a, 0x62, 0x37, 0x3a, 0x35, 0x64, 0x3a, 0x33, 0x37, 0x3a, 0x39, 0x66,
+    0x3a, 0x62, 0x31, 0x3a, 0x38, 0x37, 0x3a, 0x32, 0x39, 0x3a, 0x38, 0x61,
+    0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x31, 0x3a,
+    0x62, 0x63, 0x3a, 0x39, 0x36, 0x3a, 0x38, 0x62, 0x3a, 0x64, 0x34, 0x3a,
+    0x66, 0x34, 0x3a, 0x39, 0x64, 0x3a, 0x36, 0x32, 0x3a, 0x32, 0x61, 0x3a,
+    0x61, 0x38, 0x3a, 0x39, 0x61, 0x3a, 0x38, 0x31, 0x3a, 0x66, 0x32, 0x3a,
+    0x31, 0x35, 0x3a, 0x30, 0x31, 0x3a, 0x35, 0x32, 0x3a, 0x61, 0x34, 0x3a,
+    0x31, 0x64, 0x3a, 0x38, 0x32, 0x3a, 0x39, 0x63, 0x0a, 0x23, 0x20, 0x53,
+    0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x62, 0x3a, 0x64, 0x34,
+    0x3a, 0x31, 0x30, 0x3a, 0x34, 0x30, 0x3a, 0x65, 0x34, 0x3a, 0x62, 0x62,
+    0x3a, 0x33, 0x65, 0x3a, 0x63, 0x37, 0x3a, 0x34, 0x32, 0x3a, 0x63, 0x39,
+    0x3a, 0x65, 0x33, 0x3a, 0x38, 0x31, 0x3a, 0x64, 0x33, 0x3a, 0x31, 0x65,
+    0x3a, 0x66, 0x32, 0x3a, 0x61, 0x34, 0x3a, 0x31, 0x61, 0x3a, 0x34, 0x38,
+    0x3a, 0x62, 0x36, 0x3a, 0x36, 0x38, 0x3a, 0x35, 0x63, 0x3a, 0x39, 0x36,
+    0x3a, 0x65, 0x37, 0x3a, 0x63, 0x65, 0x3a, 0x66, 0x33, 0x3a, 0x63, 0x31,
+    0x3a, 0x64, 0x66, 0x3a, 0x36, 0x63, 0x3a, 0x64, 0x34, 0x3a, 0x33, 0x33,
+    0x3a, 0x31, 0x63, 0x3a, 0x39, 0x39, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d,
+    0x49, 0x49, 0x44, 0x64, 0x54, 0x43, 0x43, 0x41, 0x6c, 0x32, 0x67, 0x41,
+    0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x4c, 0x42, 0x41, 0x41, 0x41, 0x41,
+    0x41, 0x41, 0x42, 0x46, 0x55, 0x74, 0x61, 0x77, 0x35, 0x51, 0x77, 0x44,
+    0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41,
+    0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x56, 0x7a, 0x45, 0x4c, 0x4d,
+    0x41, 0x6b, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43,
+    0x51, 0x6b, 0x55, 0x78, 0x47, 0x54, 0x41, 0x58, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x6f, 0x54, 0x45, 0x45, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68,
+    0x62, 0x46, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x67, 0x62, 0x6e, 0x59, 0x74,
+    0x63, 0x32, 0x45, 0x78, 0x45, 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x73, 0x54, 0x42, 0x31, 0x4a, 0x76, 0x0a, 0x62, 0x33, 0x51,
+    0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, 0x67, 0x4e,
+    0x56, 0x42, 0x41, 0x4d, 0x54, 0x45, 0x6b, 0x64, 0x73, 0x62, 0x32, 0x4a,
+    0x68, 0x62, 0x46, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x67, 0x55, 0x6d, 0x39,
+    0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30,
+    0x35, 0x4f, 0x44, 0x41, 0x35, 0x4d, 0x44, 0x45, 0x78, 0x4d, 0x6a, 0x41,
+    0x77, 0x0a, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, 0x79, 0x4f, 0x44,
+    0x41, 0x78, 0x4d, 0x6a, 0x67, 0x78, 0x4d, 0x6a, 0x41, 0x77, 0x4d, 0x44,
+    0x42, 0x61, 0x4d, 0x46, 0x63, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67,
+    0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x4a, 0x46, 0x4d, 0x52,
+    0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78,
+    0x42, 0x48, 0x62, 0x47, 0x39, 0x69, 0x0a, 0x59, 0x57, 0x78, 0x54, 0x61,
+    0x57, 0x64, 0x75, 0x49, 0x47, 0x35, 0x32, 0x4c, 0x58, 0x4e, 0x68, 0x4d,
+    0x52, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45,
+    0x77, 0x64, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d,
+    0x52, 0x73, 0x77, 0x47, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45,
+    0x78, 0x4a, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x78, 0x54, 0x0a,
+    0x61, 0x57, 0x64, 0x75, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67,
+    0x51, 0x30, 0x45, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4d, 0x41, 0x30, 0x47,
+    0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42,
+    0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77, 0x41, 0x77,
+    0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x44, 0x61,
+    0x44, 0x75, 0x61, 0x5a, 0x0a, 0x6a, 0x63, 0x36, 0x6a, 0x34, 0x30, 0x2b,
+    0x4b, 0x66, 0x76, 0x76, 0x78, 0x69, 0x34, 0x4d, 0x6c, 0x61, 0x2b, 0x70,
+    0x49, 0x48, 0x2f, 0x45, 0x71, 0x73, 0x4c, 0x6d, 0x56, 0x45, 0x51, 0x53,
+    0x39, 0x38, 0x47, 0x50, 0x52, 0x34, 0x6d, 0x64, 0x6d, 0x7a, 0x78, 0x7a,
+    0x64, 0x7a, 0x78, 0x74, 0x49, 0x4b, 0x2b, 0x36, 0x4e, 0x69, 0x59, 0x36,
+    0x61, 0x72, 0x79, 0x6d, 0x41, 0x5a, 0x61, 0x76, 0x70, 0x0a, 0x78, 0x79,
+    0x30, 0x53, 0x79, 0x36, 0x73, 0x63, 0x54, 0x48, 0x41, 0x48, 0x6f, 0x54,
+    0x30, 0x4b, 0x4d, 0x4d, 0x30, 0x56, 0x6a, 0x55, 0x2f, 0x34, 0x33, 0x64,
+    0x53, 0x4d, 0x55, 0x42, 0x55, 0x63, 0x37, 0x31, 0x44, 0x75, 0x78, 0x43,
+    0x37, 0x33, 0x2f, 0x4f, 0x6c, 0x53, 0x38, 0x70, 0x46, 0x39, 0x34, 0x47,
+    0x33, 0x56, 0x4e, 0x54, 0x43, 0x4f, 0x58, 0x6b, 0x4e, 0x7a, 0x38, 0x6b,
+    0x48, 0x70, 0x0a, 0x31, 0x57, 0x72, 0x6a, 0x73, 0x6f, 0x6b, 0x36, 0x56,
+    0x6a, 0x6b, 0x34, 0x62, 0x77, 0x59, 0x38, 0x69, 0x47, 0x6c, 0x62, 0x4b,
+    0x6b, 0x33, 0x46, 0x70, 0x31, 0x53, 0x34, 0x62, 0x49, 0x6e, 0x4d, 0x6d,
+    0x2f, 0x6b, 0x38, 0x79, 0x75, 0x58, 0x39, 0x69, 0x66, 0x55, 0x53, 0x50,
+    0x4a, 0x4a, 0x34, 0x6c, 0x74, 0x62, 0x63, 0x64, 0x47, 0x36, 0x54, 0x52,
+    0x47, 0x48, 0x52, 0x6a, 0x63, 0x64, 0x47, 0x0a, 0x73, 0x6e, 0x55, 0x4f,
+    0x68, 0x75, 0x67, 0x5a, 0x69, 0x74, 0x56, 0x74, 0x62, 0x4e, 0x56, 0x34,
+    0x46, 0x70, 0x57, 0x69, 0x36, 0x63, 0x67, 0x4b, 0x4f, 0x4f, 0x76, 0x79,
+    0x4a, 0x42, 0x4e, 0x50, 0x63, 0x31, 0x53, 0x54, 0x45, 0x34, 0x55, 0x36,
+    0x47, 0x37, 0x77, 0x65, 0x4e, 0x4c, 0x57, 0x4c, 0x42, 0x59, 0x79, 0x35,
+    0x64, 0x34, 0x75, 0x78, 0x32, 0x78, 0x38, 0x67, 0x6b, 0x61, 0x73, 0x4a,
+    0x0a, 0x55, 0x32, 0x36, 0x51, 0x7a, 0x6e, 0x73, 0x33, 0x64, 0x4c, 0x6c,
+    0x77, 0x52, 0x35, 0x45, 0x69, 0x55, 0x57, 0x4d, 0x57, 0x65, 0x61, 0x36,
+    0x78, 0x72, 0x6b, 0x45, 0x6d, 0x43, 0x4d, 0x67, 0x5a, 0x4b, 0x39, 0x46,
+    0x47, 0x71, 0x6b, 0x6a, 0x57, 0x5a, 0x43, 0x72, 0x58, 0x67, 0x7a, 0x54,
+    0x2f, 0x4c, 0x43, 0x72, 0x42, 0x62, 0x42, 0x6c, 0x44, 0x53, 0x67, 0x65,
+    0x46, 0x35, 0x39, 0x4e, 0x38, 0x0a, 0x39, 0x69, 0x46, 0x6f, 0x37, 0x2b,
+    0x72, 0x79, 0x55, 0x70, 0x39, 0x2f, 0x6b, 0x35, 0x44, 0x50, 0x41, 0x67,
+    0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x41,
+    0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77,
+    0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x50, 0x42, 0x67,
+    0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x0a, 0x42,
+    0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x42, 0x30, 0x47, 0x41,
+    0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x52, 0x67, 0x65,
+    0x32, 0x59, 0x61, 0x52, 0x51, 0x32, 0x58, 0x79, 0x6f, 0x6c, 0x51, 0x4c,
+    0x33, 0x30, 0x45, 0x7a, 0x54, 0x53, 0x6f, 0x2f, 0x2f, 0x7a, 0x39, 0x53,
+    0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39,
+    0x77, 0x30, 0x42, 0x0a, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43,
+    0x41, 0x51, 0x45, 0x41, 0x31, 0x6e, 0x50, 0x6e, 0x66, 0x45, 0x39, 0x32,
+    0x30, 0x49, 0x32, 0x2f, 0x37, 0x4c, 0x71, 0x69, 0x76, 0x6a, 0x54, 0x46,
+    0x4b, 0x44, 0x4b, 0x31, 0x66, 0x50, 0x78, 0x73, 0x6e, 0x43, 0x77, 0x72,
+    0x76, 0x51, 0x6d, 0x65, 0x55, 0x37, 0x39, 0x72, 0x58, 0x71, 0x6f, 0x52,
+    0x53, 0x4c, 0x62, 0x6c, 0x43, 0x4b, 0x4f, 0x7a, 0x0a, 0x79, 0x6a, 0x31,
+    0x68, 0x54, 0x64, 0x4e, 0x47, 0x43, 0x62, 0x4d, 0x2b, 0x77, 0x36, 0x44,
+    0x6a, 0x59, 0x31, 0x55, 0x62, 0x38, 0x72, 0x72, 0x76, 0x72, 0x54, 0x6e,
+    0x68, 0x51, 0x37, 0x6b, 0x34, 0x6f, 0x2b, 0x59, 0x76, 0x69, 0x69, 0x59,
+    0x37, 0x37, 0x36, 0x42, 0x51, 0x56, 0x76, 0x6e, 0x47, 0x43, 0x76, 0x30,
+    0x34, 0x7a, 0x63, 0x51, 0x4c, 0x63, 0x46, 0x47, 0x55, 0x6c, 0x35, 0x67,
+    0x45, 0x0a, 0x33, 0x38, 0x4e, 0x66, 0x6c, 0x4e, 0x55, 0x56, 0x79, 0x52,
+    0x52, 0x42, 0x6e, 0x4d, 0x52, 0x64, 0x64, 0x57, 0x51, 0x56, 0x44, 0x66,
+    0x39, 0x56, 0x4d, 0x4f, 0x79, 0x47, 0x6a, 0x2f, 0x38, 0x4e, 0x37, 0x79,
+    0x79, 0x35, 0x59, 0x30, 0x62, 0x32, 0x71, 0x76, 0x7a, 0x66, 0x76, 0x47,
+    0x6e, 0x39, 0x4c, 0x68, 0x4a, 0x49, 0x5a, 0x4a, 0x72, 0x67, 0x6c, 0x66,
+    0x43, 0x6d, 0x37, 0x79, 0x6d, 0x50, 0x0a, 0x41, 0x62, 0x45, 0x56, 0x74,
+    0x51, 0x77, 0x64, 0x70, 0x66, 0x35, 0x70, 0x4c, 0x47, 0x6b, 0x6b, 0x65,
+    0x42, 0x36, 0x7a, 0x70, 0x78, 0x78, 0x78, 0x59, 0x75, 0x37, 0x4b, 0x79,
+    0x4a, 0x65, 0x73, 0x46, 0x31, 0x32, 0x4b, 0x77, 0x76, 0x68, 0x48, 0x68,
+    0x6d, 0x34, 0x71, 0x78, 0x46, 0x59, 0x78, 0x6c, 0x64, 0x42, 0x6e, 0x69,
+    0x59, 0x55, 0x72, 0x2b, 0x57, 0x79, 0x6d, 0x58, 0x55, 0x61, 0x64, 0x0a,
+    0x44, 0x4b, 0x71, 0x43, 0x35, 0x4a, 0x6c, 0x52, 0x33, 0x58, 0x43, 0x33,
+    0x32, 0x31, 0x59, 0x39, 0x59, 0x65, 0x52, 0x71, 0x34, 0x56, 0x7a, 0x57,
+    0x39, 0x76, 0x34, 0x39, 0x33, 0x6b, 0x48, 0x4d, 0x42, 0x36, 0x35, 0x6a,
+    0x55, 0x72, 0x39, 0x54, 0x55, 0x2f, 0x51, 0x72, 0x36, 0x63, 0x66, 0x39,
+    0x74, 0x76, 0x65, 0x43, 0x58, 0x34, 0x58, 0x53, 0x51, 0x52, 0x6a, 0x62,
+    0x67, 0x62, 0x4d, 0x45, 0x0a, 0x48, 0x4d, 0x55, 0x66, 0x70, 0x49, 0x42,
+    0x76, 0x46, 0x53, 0x44, 0x4a, 0x33, 0x67, 0x79, 0x49, 0x43, 0x68, 0x33,
+    0x57, 0x5a, 0x6c, 0x58, 0x69, 0x2f, 0x45, 0x6a, 0x4a, 0x4b, 0x53, 0x5a,
+    0x70, 0x34, 0x41, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45,
+    0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41,
+    0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49,
+    0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x6c,
+    0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x3d, 0x47,
+    0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x55,
+    0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20,
+    0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x32,
+    0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20,
+    0x43, 0x4e, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67,
+    0x6e, 0x20, 0x4f, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69,
+    0x67, 0x6e, 0x20, 0x4f, 0x55, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+    0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
+    0x20, 0x2d, 0x20, 0x52, 0x32, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65,
+    0x6c, 0x3a, 0x20, 0x22, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69,
+    0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d,
+    0x20, 0x52, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61,
+    0x6c, 0x3a, 0x20, 0x34, 0x38, 0x33, 0x35, 0x37, 0x30, 0x33, 0x32, 0x37,
+    0x38, 0x34, 0x35, 0x39, 0x36, 0x38, 0x32, 0x38, 0x38, 0x35, 0x36, 0x35,
+    0x38, 0x31, 0x32, 0x35, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x39, 0x34, 0x3a, 0x31, 0x34, 0x3a, 0x37, 0x37, 0x3a, 0x37, 0x65, 0x3a,
+    0x33, 0x65, 0x3a, 0x35, 0x65, 0x3a, 0x66, 0x64, 0x3a, 0x38, 0x66, 0x3a,
+    0x33, 0x30, 0x3a, 0x62, 0x64, 0x3a, 0x34, 0x31, 0x3a, 0x62, 0x30, 0x3a,
+    0x63, 0x66, 0x3a, 0x65, 0x37, 0x3a, 0x64, 0x30, 0x3a, 0x33, 0x30, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x35, 0x3a, 0x65,
+    0x30, 0x3a, 0x61, 0x62, 0x3a, 0x62, 0x36, 0x3a, 0x31, 0x33, 0x3a, 0x38,
+    0x35, 0x3a, 0x31, 0x32, 0x3a, 0x32, 0x37, 0x3a, 0x31, 0x63, 0x3a, 0x30,
+    0x34, 0x3a, 0x66, 0x38, 0x3a, 0x35, 0x66, 0x3a, 0x64, 0x64, 0x3a, 0x64,
+    0x65, 0x3a, 0x33, 0x38, 0x3a, 0x65, 0x34, 0x3a, 0x62, 0x37, 0x3a, 0x32,
+    0x34, 0x3a, 0x32, 0x65, 0x3a, 0x66, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48,
+    0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x61, 0x3a, 0x34, 0x32, 0x3a,
+    0x64, 0x64, 0x3a, 0x34, 0x31, 0x3a, 0x37, 0x34, 0x3a, 0x35, 0x66, 0x3a,
+    0x64, 0x30, 0x3a, 0x62, 0x38, 0x3a, 0x31, 0x65, 0x3a, 0x62, 0x39, 0x3a,
+    0x30, 0x32, 0x3a, 0x33, 0x36, 0x3a, 0x32, 0x63, 0x3a, 0x66, 0x39, 0x3a,
+    0x64, 0x38, 0x3a, 0x62, 0x66, 0x3a, 0x37, 0x31, 0x3a, 0x39, 0x64, 0x3a,
+    0x61, 0x31, 0x3a, 0x62, 0x64, 0x3a, 0x31, 0x62, 0x3a, 0x31, 0x65, 0x3a,
+    0x66, 0x63, 0x3a, 0x39, 0x34, 0x3a, 0x36, 0x66, 0x3a, 0x35, 0x62, 0x3a,
+    0x34, 0x63, 0x3a, 0x39, 0x39, 0x3a, 0x66, 0x34, 0x3a, 0x32, 0x63, 0x3a,
+    0x31, 0x62, 0x3a, 0x39, 0x65, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42,
+    0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49,
+    0x49, 0x44, 0x75, 0x6a, 0x43, 0x43, 0x41, 0x71, 0x4b, 0x67, 0x41, 0x77,
+    0x49, 0x42, 0x41, 0x67, 0x49, 0x4c, 0x42, 0x41, 0x41, 0x41, 0x41, 0x41,
+    0x41, 0x42, 0x44, 0x34, 0x59, 0x6d, 0x35, 0x67, 0x30, 0x77, 0x44, 0x51,
+    0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51,
+    0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x54, 0x44, 0x45, 0x67, 0x4d, 0x42,
+    0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x58, 0x52,
+    0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, 0x55, 0x32, 0x6c, 0x6e, 0x62,
+    0x69, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x49,
+    0x43, 0x30, 0x67, 0x55, 0x6a, 0x49, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x43, 0x6b, 0x64, 0x73, 0x62,
+    0x32, 0x4a, 0x68, 0x62, 0x46, 0x4e, 0x70, 0x0a, 0x5a, 0x32, 0x34, 0x78,
+    0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54,
+    0x43, 0x6b, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62, 0x46, 0x4e, 0x70,
+    0x5a, 0x32, 0x34, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x59, 0x78,
+    0x4d, 0x6a, 0x45, 0x31, 0x4d, 0x44, 0x67, 0x77, 0x4d, 0x44, 0x41, 0x77,
+    0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x45, 0x78, 0x4d, 0x6a, 0x45, 0x31,
+    0x0a, 0x4d, 0x44, 0x67, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x6a, 0x42,
+    0x4d, 0x4d, 0x53, 0x41, 0x77, 0x48, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x4c, 0x45, 0x78, 0x64, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x78,
+    0x54, 0x61, 0x57, 0x64, 0x75, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51,
+    0x67, 0x51, 0x30, 0x45, 0x67, 0x4c, 0x53, 0x42, 0x53, 0x4d, 0x6a, 0x45,
+    0x54, 0x4d, 0x42, 0x45, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68,
+    0x4d, 0x4b, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, 0x55, 0x32,
+    0x6c, 0x6e, 0x62, 0x6a, 0x45, 0x54, 0x4d, 0x42, 0x45, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x41, 0x78, 0x4d, 0x4b, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d,
+    0x46, 0x73, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x6a, 0x43, 0x43, 0x41, 0x53,
+    0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x0a, 0x68,
+    0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67,
+    0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67,
+    0x67, 0x45, 0x42, 0x41, 0x4b, 0x62, 0x50, 0x4a, 0x41, 0x36, 0x2b, 0x4c,
+    0x6d, 0x38, 0x6f, 0x6d, 0x55, 0x56, 0x43, 0x78, 0x4b, 0x73, 0x2b, 0x49,
+    0x56, 0x53, 0x62, 0x43, 0x39, 0x4e, 0x2f, 0x68, 0x48, 0x44, 0x36, 0x45,
+    0x72, 0x50, 0x4c, 0x0a, 0x76, 0x34, 0x64, 0x66, 0x78, 0x6e, 0x2b, 0x47,
+    0x30, 0x37, 0x49, 0x77, 0x58, 0x4e, 0x62, 0x39, 0x72, 0x66, 0x46, 0x37,
+    0x33, 0x4f, 0x58, 0x34, 0x59, 0x4a, 0x59, 0x4a, 0x6b, 0x68, 0x44, 0x31,
+    0x30, 0x46, 0x50, 0x65, 0x2b, 0x33, 0x74, 0x2b, 0x63, 0x34, 0x69, 0x73,
+    0x55, 0x6f, 0x68, 0x37, 0x53, 0x71, 0x62, 0x4b, 0x53, 0x61, 0x5a, 0x65,
+    0x71, 0x4b, 0x65, 0x4d, 0x57, 0x68, 0x47, 0x38, 0x0a, 0x65, 0x6f, 0x4c,
+    0x72, 0x76, 0x6f, 0x7a, 0x70, 0x73, 0x36, 0x79, 0x57, 0x4a, 0x51, 0x65,
+    0x58, 0x53, 0x70, 0x6b, 0x71, 0x42, 0x79, 0x2b, 0x30, 0x48, 0x6e, 0x65,
+    0x2f, 0x69, 0x67, 0x2b, 0x31, 0x41, 0x6e, 0x77, 0x62, 0x6c, 0x72, 0x6a,
+    0x46, 0x75, 0x54, 0x6f, 0x73, 0x76, 0x4e, 0x59, 0x53, 0x75, 0x65, 0x74,
+    0x5a, 0x66, 0x65, 0x4c, 0x51, 0x42, 0x6f, 0x5a, 0x66, 0x58, 0x6b, 0x6c,
+    0x71, 0x0a, 0x74, 0x54, 0x6c, 0x65, 0x69, 0x44, 0x54, 0x73, 0x76, 0x48,
+    0x67, 0x4d, 0x43, 0x4a, 0x69, 0x45, 0x62, 0x4b, 0x6a, 0x4e, 0x53, 0x37,
+    0x53, 0x67, 0x66, 0x51, 0x78, 0x35, 0x54, 0x66, 0x43, 0x34, 0x4c, 0x63,
+    0x73, 0x68, 0x79, 0x74, 0x56, 0x73, 0x57, 0x33, 0x33, 0x68, 0x6f, 0x43,
+    0x6d, 0x45, 0x6f, 0x66, 0x6e, 0x54, 0x6c, 0x45, 0x6e, 0x4c, 0x4a, 0x47,
+    0x4b, 0x52, 0x49, 0x4c, 0x7a, 0x64, 0x0a, 0x43, 0x39, 0x58, 0x5a, 0x7a,
+    0x50, 0x6e, 0x71, 0x4a, 0x77, 0x6f, 0x72, 0x63, 0x35, 0x48, 0x47, 0x6e,
+    0x52, 0x75, 0x73, 0x79, 0x4d, 0x76, 0x6f, 0x34, 0x4b, 0x44, 0x30, 0x4c,
+    0x35, 0x43, 0x4c, 0x54, 0x66, 0x75, 0x77, 0x4e, 0x68, 0x76, 0x32, 0x47,
+    0x58, 0x71, 0x46, 0x34, 0x47, 0x33, 0x79, 0x59, 0x52, 0x4f, 0x49, 0x58,
+    0x4a, 0x2f, 0x67, 0x6b, 0x77, 0x70, 0x52, 0x6c, 0x34, 0x70, 0x61, 0x0a,
+    0x7a, 0x71, 0x2b, 0x72, 0x31, 0x66, 0x65, 0x71, 0x43, 0x61, 0x70, 0x67,
+    0x76, 0x64, 0x7a, 0x5a, 0x58, 0x39, 0x39, 0x79, 0x71, 0x57, 0x41, 0x54,
+    0x58, 0x67, 0x41, 0x42, 0x79, 0x55, 0x72, 0x36, 0x50, 0x36, 0x54, 0x71,
+    0x42, 0x77, 0x4d, 0x68, 0x41, 0x6f, 0x36, 0x43, 0x79, 0x67, 0x50, 0x43,
+    0x6d, 0x34, 0x38, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4f, 0x42,
+    0x6e, 0x44, 0x43, 0x42, 0x0a, 0x6d, 0x54, 0x41, 0x4f, 0x42, 0x67, 0x4e,
+    0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d,
+    0x43, 0x41, 0x51, 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30,
+    0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45,
+    0x42, 0x2f, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34,
+    0x45, 0x46, 0x67, 0x51, 0x55, 0x6d, 0x2b, 0x49, 0x48, 0x0a, 0x56, 0x32,
+    0x63, 0x63, 0x48, 0x73, 0x42, 0x71, 0x42, 0x74, 0x35, 0x5a, 0x74, 0x4a,
+    0x6f, 0x74, 0x33, 0x39, 0x77, 0x5a, 0x68, 0x69, 0x34, 0x77, 0x4e, 0x67,
+    0x59, 0x44, 0x56, 0x52, 0x30, 0x66, 0x42, 0x43, 0x38, 0x77, 0x4c, 0x54,
+    0x41, 0x72, 0x6f, 0x43, 0x6d, 0x67, 0x4a, 0x34, 0x59, 0x6c, 0x61, 0x48,
+    0x52, 0x30, 0x63, 0x44, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x79, 0x62, 0x43,
+    0x35, 0x6e, 0x0a, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x78, 0x7a, 0x61,
+    0x57, 0x64, 0x75, 0x4c, 0x6d, 0x35, 0x6c, 0x64, 0x43, 0x39, 0x79, 0x62,
+    0x32, 0x39, 0x30, 0x4c, 0x58, 0x49, 0x79, 0x4c, 0x6d, 0x4e, 0x79, 0x62,
+    0x44, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47,
+    0x44, 0x41, 0x57, 0x67, 0x42, 0x53, 0x62, 0x34, 0x67, 0x64, 0x58, 0x5a,
+    0x78, 0x77, 0x65, 0x77, 0x47, 0x6f, 0x47, 0x0a, 0x33, 0x6c, 0x6d, 0x30,
+    0x6d, 0x69, 0x33, 0x66, 0x33, 0x42, 0x6d, 0x47, 0x4c, 0x6a, 0x41, 0x4e,
+    0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42,
+    0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41,
+    0x6d, 0x59, 0x46, 0x54, 0x68, 0x78, 0x78, 0x6f, 0x6c, 0x34, 0x61, 0x52,
+    0x37, 0x4f, 0x42, 0x4b, 0x75, 0x45, 0x51, 0x4c, 0x71, 0x34, 0x47, 0x73,
+    0x0a, 0x4a, 0x30, 0x2f, 0x57, 0x77, 0x62, 0x67, 0x63, 0x51, 0x33, 0x69,
+    0x7a, 0x44, 0x4a, 0x72, 0x38, 0x36, 0x69, 0x77, 0x38, 0x62, 0x6d, 0x45,
+    0x62, 0x54, 0x55, 0x73, 0x70, 0x39, 0x5a, 0x38, 0x46, 0x48, 0x53, 0x62,
+    0x42, 0x75, 0x4f, 0x6d, 0x44, 0x41, 0x47, 0x4a, 0x46, 0x74, 0x71, 0x6b,
+    0x49, 0x6b, 0x37, 0x6d, 0x70, 0x4d, 0x30, 0x73, 0x59, 0x6d, 0x73, 0x4c,
+    0x34, 0x68, 0x34, 0x68, 0x4f, 0x0a, 0x32, 0x39, 0x31, 0x78, 0x4e, 0x42,
+    0x72, 0x42, 0x56, 0x4e, 0x70, 0x47, 0x50, 0x2b, 0x44, 0x54, 0x4b, 0x71,
+    0x74, 0x74, 0x56, 0x43, 0x4c, 0x31, 0x4f, 0x6d, 0x4c, 0x4e, 0x49, 0x47,
+    0x2b, 0x36, 0x4b, 0x59, 0x6e, 0x58, 0x33, 0x5a, 0x48, 0x75, 0x30, 0x31,
+    0x79, 0x69, 0x50, 0x71, 0x46, 0x62, 0x51, 0x66, 0x58, 0x66, 0x35, 0x57,
+    0x52, 0x44, 0x4c, 0x65, 0x6e, 0x56, 0x4f, 0x61, 0x76, 0x53, 0x0a, 0x6f,
+    0x74, 0x2b, 0x33, 0x69, 0x39, 0x44, 0x41, 0x67, 0x42, 0x6b, 0x63, 0x52,
+    0x63, 0x41, 0x74, 0x6a, 0x4f, 0x6a, 0x34, 0x4c, 0x61, 0x52, 0x30, 0x56,
+    0x6b, 0x6e, 0x46, 0x42, 0x62, 0x56, 0x50, 0x46, 0x64, 0x35, 0x75, 0x52,
+    0x48, 0x67, 0x35, 0x68, 0x36, 0x68, 0x2b, 0x75, 0x2f, 0x4e, 0x35, 0x47,
+    0x4a, 0x47, 0x37, 0x39, 0x47, 0x2b, 0x64, 0x77, 0x66, 0x43, 0x4d, 0x4e,
+    0x59, 0x78, 0x64, 0x0a, 0x41, 0x66, 0x76, 0x44, 0x62, 0x62, 0x6e, 0x76,
+    0x52, 0x47, 0x31, 0x35, 0x52, 0x6a, 0x46, 0x2b, 0x43, 0x76, 0x36, 0x70,
+    0x67, 0x73, 0x48, 0x2f, 0x37, 0x36, 0x74, 0x75, 0x49, 0x4d, 0x52, 0x51,
+    0x79, 0x56, 0x2b, 0x64, 0x54, 0x5a, 0x73, 0x58, 0x6a, 0x41, 0x7a, 0x6c,
+    0x41, 0x63, 0x6d, 0x67, 0x51, 0x57, 0x70, 0x7a, 0x55, 0x2f, 0x71, 0x6c,
+    0x55, 0x4c, 0x52, 0x75, 0x4a, 0x51, 0x2f, 0x37, 0x0a, 0x54, 0x42, 0x6a,
+    0x30, 0x2f, 0x56, 0x4c, 0x5a, 0x6a, 0x6d, 0x6d, 0x78, 0x36, 0x42, 0x45,
+    0x50, 0x33, 0x6f, 0x6a, 0x59, 0x2b, 0x78, 0x31, 0x4a, 0x39, 0x36, 0x72,
+    0x65, 0x6c, 0x63, 0x38, 0x67, 0x65, 0x4d, 0x4a, 0x67, 0x45, 0x74, 0x73,
+    0x6c, 0x51, 0x49, 0x78, 0x71, 0x2f, 0x48, 0x35, 0x43, 0x4f, 0x45, 0x42,
+    0x6b, 0x45, 0x76, 0x65, 0x65, 0x67, 0x65, 0x47, 0x54, 0x4c, 0x67, 0x3d,
+    0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65,
+    0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+    0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x63, 0x65, 0x72,
+    0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x20, 0x4f, 0x3d, 0x56, 0x61, 0x6c,
+    0x69, 0x43, 0x65, 0x72, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20,
+    0x4f, 0x55, 0x3d, 0x56, 0x61, 0x6c, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20,
+    0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x31, 0x20, 0x50, 0x6f, 0x6c, 0x69,
+    0x63, 0x79, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f,
+    0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a,
+    0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43,
+    0x4e, 0x3d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+    0x2e, 0x76, 0x61, 0x6c, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f,
+    0x6d, 0x2f, 0x20, 0x4f, 0x3d, 0x56, 0x61, 0x6c, 0x69, 0x43, 0x65, 0x72,
+    0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56,
+    0x61, 0x6c, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73,
+    0x73, 0x20, 0x31, 0x20, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x56,
+    0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
+    0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61,
+    0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x56, 0x61, 0x6c, 0x69, 0x43, 0x65,
+    0x72, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x31, 0x20, 0x56,
+    0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a,
+    0x20, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x35,
+    0x3a, 0x35, 0x38, 0x3a, 0x61, 0x62, 0x3a, 0x31, 0x35, 0x3a, 0x61, 0x64,
+    0x3a, 0x35, 0x37, 0x3a, 0x36, 0x63, 0x3a, 0x31, 0x65, 0x3a, 0x61, 0x38,
+    0x3a, 0x61, 0x37, 0x3a, 0x62, 0x35, 0x3a, 0x36, 0x39, 0x3a, 0x61, 0x63,
+    0x3a, 0x62, 0x66, 0x3a, 0x66, 0x66, 0x3a, 0x65, 0x62, 0x0a, 0x23, 0x20,
+    0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x35, 0x3a, 0x64, 0x66, 0x3a,
+    0x37, 0x34, 0x3a, 0x33, 0x63, 0x3a, 0x62, 0x36, 0x3a, 0x30, 0x31, 0x3a,
+    0x63, 0x34, 0x3a, 0x39, 0x62, 0x3a, 0x39, 0x38, 0x3a, 0x34, 0x33, 0x3a,
+    0x64, 0x63, 0x3a, 0x61, 0x62, 0x3a, 0x38, 0x63, 0x3a, 0x65, 0x38, 0x3a,
+    0x36, 0x61, 0x3a, 0x38, 0x31, 0x3a, 0x31, 0x30, 0x3a, 0x39, 0x66, 0x3a,
+    0x65, 0x34, 0x3a, 0x38, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32,
+    0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x66, 0x34, 0x3a, 0x63, 0x31, 0x3a, 0x34, 0x39,
+    0x3a, 0x35, 0x35, 0x3a, 0x31, 0x61, 0x3a, 0x33, 0x30, 0x3a, 0x31, 0x33,
+    0x3a, 0x61, 0x33, 0x3a, 0x35, 0x62, 0x3a, 0x63, 0x37, 0x3a, 0x62, 0x66,
+    0x3a, 0x66, 0x65, 0x3a, 0x31, 0x37, 0x3a, 0x61, 0x37, 0x3a, 0x66, 0x33,
+    0x3a, 0x34, 0x34, 0x3a, 0x39, 0x62, 0x3a, 0x63, 0x31, 0x3a, 0x61, 0x62,
+    0x3a, 0x35, 0x62, 0x3a, 0x35, 0x61, 0x3a, 0x30, 0x61, 0x3a, 0x65, 0x37,
+    0x3a, 0x34, 0x62, 0x3a, 0x30, 0x36, 0x3a, 0x63, 0x32, 0x3a, 0x33, 0x62,
+    0x3a, 0x39, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x34, 0x63, 0x3a, 0x30, 0x31,
+    0x3a, 0x30, 0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47,
+    0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41,
+    0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43,
+    0x35, 0x7a, 0x43, 0x43, 0x41, 0x6c, 0x41, 0x43, 0x41, 0x51, 0x45, 0x77,
+    0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e,
+    0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x67, 0x62, 0x73, 0x78,
+    0x4a, 0x44, 0x41, 0x69, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54,
+    0x47, 0x31, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x44, 0x5a, 0x58, 0x4a, 0x30,
+    0x0a, 0x49, 0x46, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x6b, 0x59, 0x58, 0x52,
+    0x70, 0x62, 0x32, 0x34, 0x67, 0x54, 0x6d, 0x56, 0x30, 0x64, 0x32, 0x39,
+    0x79, 0x61, 0x7a, 0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x43, 0x68, 0x4d, 0x4f, 0x56, 0x6d, 0x46, 0x73, 0x61, 0x55, 0x4e,
+    0x6c, 0x63, 0x6e, 0x51, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34,
+    0x78, 0x4e, 0x54, 0x41, 0x7a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41,
+    0x73, 0x54, 0x4c, 0x46, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x44, 0x5a, 0x58,
+    0x4a, 0x30, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44,
+    0x45, 0x67, 0x55, 0x47, 0x39, 0x73, 0x61, 0x57, 0x4e, 0x35, 0x49, 0x46,
+    0x5a, 0x68, 0x62, 0x47, 0x6c, 0x6b, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32,
+    0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x0a, 0x61,
+    0x58, 0x52, 0x35, 0x4d, 0x53, 0x45, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x44, 0x45, 0x78, 0x68, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f,
+    0x69, 0x38, 0x76, 0x64, 0x33, 0x64, 0x33, 0x4c, 0x6e, 0x5a, 0x68, 0x62,
+    0x47, 0x6c, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x4c, 0x6d, 0x4e, 0x76, 0x62,
+    0x53, 0x38, 0x78, 0x49, 0x44, 0x41, 0x65, 0x42, 0x67, 0x6b, 0x71, 0x68,
+    0x6b, 0x69, 0x47, 0x0a, 0x39, 0x77, 0x30, 0x42, 0x43, 0x51, 0x45, 0x57,
+    0x45, 0x57, 0x6c, 0x75, 0x5a, 0x6d, 0x39, 0x41, 0x64, 0x6d, 0x46, 0x73,
+    0x61, 0x57, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74,
+    0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x6b, 0x35, 0x4d, 0x44, 0x59, 0x79,
+    0x4e, 0x54, 0x49, 0x79, 0x4d, 0x6a, 0x4d, 0x30, 0x4f, 0x46, 0x6f, 0x58,
+    0x44, 0x54, 0x45, 0x35, 0x4d, 0x44, 0x59, 0x79, 0x0a, 0x4e, 0x54, 0x49,
+    0x79, 0x4d, 0x6a, 0x4d, 0x30, 0x4f, 0x46, 0x6f, 0x77, 0x67, 0x62, 0x73,
+    0x78, 0x4a, 0x44, 0x41, 0x69, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63,
+    0x54, 0x47, 0x31, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x44, 0x5a, 0x58, 0x4a,
+    0x30, 0x49, 0x46, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x6b, 0x59, 0x58, 0x52,
+    0x70, 0x62, 0x32, 0x34, 0x67, 0x54, 0x6d, 0x56, 0x30, 0x64, 0x32, 0x39,
+    0x79, 0x0a, 0x61, 0x7a, 0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x43, 0x68, 0x4d, 0x4f, 0x56, 0x6d, 0x46, 0x73, 0x61, 0x55,
+    0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79,
+    0x34, 0x78, 0x4e, 0x54, 0x41, 0x7a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41,
+    0x73, 0x54, 0x4c, 0x46, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x44, 0x5a, 0x58,
+    0x4a, 0x30, 0x49, 0x45, 0x4e, 0x73, 0x0a, 0x59, 0x58, 0x4e, 0x7a, 0x49,
+    0x44, 0x45, 0x67, 0x55, 0x47, 0x39, 0x73, 0x61, 0x57, 0x4e, 0x35, 0x49,
+    0x46, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x6b, 0x59, 0x58, 0x52, 0x70, 0x62,
+    0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61,
+    0x58, 0x52, 0x35, 0x4d, 0x53, 0x45, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x44, 0x45, 0x78, 0x68, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x0a,
+    0x4f, 0x69, 0x38, 0x76, 0x64, 0x33, 0x64, 0x33, 0x4c, 0x6e, 0x5a, 0x68,
+    0x62, 0x47, 0x6c, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x4c, 0x6d, 0x4e, 0x76,
+    0x62, 0x53, 0x38, 0x78, 0x49, 0x44, 0x41, 0x65, 0x42, 0x67, 0x6b, 0x71,
+    0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x43, 0x51, 0x45, 0x57,
+    0x45, 0x57, 0x6c, 0x75, 0x5a, 0x6d, 0x39, 0x41, 0x64, 0x6d, 0x46, 0x73,
+    0x61, 0x57, 0x4e, 0x6c, 0x0a, 0x63, 0x6e, 0x51, 0x75, 0x59, 0x32, 0x39,
+    0x74, 0x4d, 0x49, 0x47, 0x66, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71,
+    0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55,
+    0x41, 0x41, 0x34, 0x47, 0x4e, 0x41, 0x44, 0x43, 0x42, 0x69, 0x51, 0x4b,
+    0x42, 0x67, 0x51, 0x44, 0x59, 0x57, 0x59, 0x4a, 0x36, 0x69, 0x62, 0x69,
+    0x57, 0x75, 0x71, 0x59, 0x76, 0x61, 0x47, 0x39, 0x59, 0x0a, 0x4c, 0x71,
+    0x64, 0x55, 0x48, 0x41, 0x5a, 0x75, 0x39, 0x4f, 0x71, 0x4e, 0x53, 0x4c,
+    0x77, 0x78, 0x6c, 0x42, 0x66, 0x77, 0x38, 0x30, 0x36, 0x38, 0x73, 0x72,
+    0x67, 0x31, 0x6b, 0x6e, 0x61, 0x77, 0x30, 0x4b, 0x57, 0x6c, 0x41, 0x64,
+    0x63, 0x41, 0x41, 0x78, 0x49, 0x69, 0x47, 0x51, 0x6a, 0x34, 0x2f, 0x78,
+    0x45, 0x6a, 0x6d, 0x38, 0x34, 0x48, 0x39, 0x62, 0x39, 0x70, 0x47, 0x69,
+    0x62, 0x2b, 0x0a, 0x54, 0x75, 0x6e, 0x52, 0x66, 0x35, 0x30, 0x73, 0x51,
+    0x42, 0x31, 0x5a, 0x61, 0x47, 0x36, 0x6d, 0x2b, 0x46, 0x69, 0x77, 0x6e,
+    0x52, 0x71, 0x50, 0x30, 0x7a, 0x2f, 0x78, 0x33, 0x42, 0x6b, 0x47, 0x67,
+    0x61, 0x67, 0x4f, 0x34, 0x44, 0x72, 0x64, 0x79, 0x46, 0x4e, 0x46, 0x43,
+    0x51, 0x62, 0x6d, 0x44, 0x33, 0x44, 0x44, 0x2b, 0x6b, 0x43, 0x6d, 0x44,
+    0x75, 0x4a, 0x57, 0x42, 0x51, 0x38, 0x59, 0x0a, 0x54, 0x66, 0x77, 0x67,
+    0x67, 0x74, 0x46, 0x7a, 0x56, 0x58, 0x53, 0x4e, 0x64, 0x6e, 0x4b, 0x67,
+    0x48, 0x5a, 0x30, 0x64, 0x77, 0x4e, 0x30, 0x2f, 0x63, 0x51, 0x49, 0x44,
+    0x41, 0x51, 0x41, 0x42, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47,
+    0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41,
+    0x41, 0x34, 0x47, 0x42, 0x41, 0x46, 0x42, 0x6f, 0x50, 0x55, 0x6e, 0x30,
+    0x0a, 0x4c, 0x42, 0x77, 0x47, 0x6c, 0x4e, 0x2b, 0x56, 0x59, 0x48, 0x2b,
+    0x57, 0x65, 0x78, 0x66, 0x2b, 0x54, 0x33, 0x47, 0x74, 0x5a, 0x4d, 0x6a,
+    0x64, 0x64, 0x39, 0x4c, 0x76, 0x57, 0x56, 0x58, 0x6f, 0x50, 0x2b, 0x69,
+    0x4f, 0x42, 0x53, 0x6f, 0x68, 0x38, 0x67, 0x66, 0x53, 0x74, 0x61, 0x64,
+    0x53, 0x2f, 0x70, 0x79, 0x78, 0x74, 0x75, 0x4a, 0x62, 0x64, 0x78, 0x64,
+    0x41, 0x36, 0x6e, 0x4c, 0x57, 0x0a, 0x49, 0x38, 0x73, 0x6f, 0x67, 0x54,
+    0x4c, 0x44, 0x41, 0x48, 0x6b, 0x59, 0x37, 0x46, 0x6b, 0x58, 0x69, 0x63,
+    0x6e, 0x47, 0x61, 0x68, 0x35, 0x78, 0x79, 0x66, 0x32, 0x33, 0x64, 0x4b,
+    0x55, 0x6c, 0x52, 0x57, 0x6e, 0x46, 0x53, 0x4b, 0x73, 0x5a, 0x34, 0x55,
+    0x57, 0x4b, 0x4a, 0x57, 0x73, 0x5a, 0x37, 0x75, 0x57, 0x37, 0x45, 0x76,
+    0x56, 0x2f, 0x39, 0x36, 0x61, 0x4e, 0x55, 0x63, 0x50, 0x77, 0x0a, 0x6e,
+    0x58, 0x53, 0x33, 0x71, 0x54, 0x36, 0x67, 0x70, 0x66, 0x2b, 0x32, 0x53,
+    0x51, 0x4d, 0x54, 0x32, 0x69, 0x4c, 0x4d, 0x37, 0x58, 0x47, 0x43, 0x4b,
+    0x35, 0x6e, 0x50, 0x4f, 0x72, 0x66, 0x31, 0x4c, 0x58, 0x4c, 0x49, 0x0a,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52,
+    0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a,
+    0x20, 0x43, 0x4e, 0x3d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+    0x77, 0x77, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e,
+    0x63, 0x6f, 0x6d, 0x2f, 0x20, 0x4f, 0x3d, 0x56, 0x61, 0x6c, 0x69, 0x43,
+    0x65, 0x72, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55,
+    0x3d, 0x56, 0x61, 0x6c, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x43, 0x6c,
+    0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79,
+    0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+    0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20,
+    0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d,
+    0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76,
+    0x61, 0x6c, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+    0x20, 0x4f, 0x3d, 0x56, 0x61, 0x6c, 0x69, 0x43, 0x65, 0x72, 0x74, 0x2c,
+    0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x61, 0x6c,
+    0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20,
+    0x32, 0x20, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x56, 0x61, 0x6c,
+    0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65,
+    0x6c, 0x3a, 0x20, 0x22, 0x56, 0x61, 0x6c, 0x69, 0x43, 0x65, 0x72, 0x74,
+    0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x56, 0x41, 0x22,
+    0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31,
+    0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x39, 0x3a, 0x32,
+    0x33, 0x3a, 0x37, 0x35, 0x3a, 0x39, 0x62, 0x3a, 0x62, 0x61, 0x3a, 0x34,
+    0x39, 0x3a, 0x33, 0x36, 0x3a, 0x36, 0x65, 0x3a, 0x33, 0x31, 0x3a, 0x63,
+    0x32, 0x3a, 0x64, 0x62, 0x3a, 0x66, 0x32, 0x3a, 0x65, 0x37, 0x3a, 0x36,
+    0x36, 0x3a, 0x62, 0x61, 0x3a, 0x38, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48,
+    0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x33, 0x31, 0x3a, 0x37, 0x61, 0x3a, 0x32, 0x61,
+    0x3a, 0x64, 0x30, 0x3a, 0x37, 0x66, 0x3a, 0x32, 0x62, 0x3a, 0x33, 0x33,
+    0x3a, 0x35, 0x65, 0x3a, 0x66, 0x35, 0x3a, 0x61, 0x31, 0x3a, 0x63, 0x33,
+    0x3a, 0x34, 0x65, 0x3a, 0x34, 0x62, 0x3a, 0x35, 0x37, 0x3a, 0x65, 0x38,
+    0x3a, 0x62, 0x37, 0x3a, 0x64, 0x38, 0x3a, 0x66, 0x31, 0x3a, 0x66, 0x63,
+    0x3a, 0x61, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x35, 0x38, 0x3a, 0x64, 0x30, 0x3a, 0x31, 0x37, 0x3a, 0x32,
+    0x37, 0x3a, 0x39, 0x63, 0x3a, 0x64, 0x34, 0x3a, 0x64, 0x63, 0x3a, 0x36,
+    0x33, 0x3a, 0x61, 0x62, 0x3a, 0x64, 0x64, 0x3a, 0x62, 0x31, 0x3a, 0x39,
+    0x36, 0x3a, 0x61, 0x36, 0x3a, 0x63, 0x39, 0x3a, 0x39, 0x30, 0x3a, 0x36,
+    0x63, 0x3a, 0x33, 0x30, 0x3a, 0x63, 0x34, 0x3a, 0x65, 0x30, 0x3a, 0x38,
+    0x37, 0x3a, 0x38, 0x33, 0x3a, 0x65, 0x61, 0x3a, 0x65, 0x38, 0x3a, 0x63,
+    0x31, 0x3a, 0x36, 0x30, 0x3a, 0x39, 0x39, 0x3a, 0x35, 0x34, 0x3a, 0x64,
+    0x36, 0x3a, 0x39, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x35, 0x39, 0x3a, 0x36,
+    0x62, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x35, 0x7a,
+    0x43, 0x43, 0x41, 0x6c, 0x41, 0x43, 0x41, 0x51, 0x45, 0x77, 0x44, 0x51,
+    0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51,
+    0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x67, 0x62, 0x73, 0x78, 0x4a, 0x44,
+    0x41, 0x69, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x47, 0x31,
+    0x5a, 0x68, 0x62, 0x47, 0x6c, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x0a, 0x49,
+    0x46, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x6b, 0x59, 0x58, 0x52, 0x70, 0x62,
+    0x32, 0x34, 0x67, 0x54, 0x6d, 0x56, 0x30, 0x64, 0x32, 0x39, 0x79, 0x61,
+    0x7a, 0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43,
+    0x68, 0x4d, 0x4f, 0x56, 0x6d, 0x46, 0x73, 0x61, 0x55, 0x4e, 0x6c, 0x63,
+    0x6e, 0x51, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x4e,
+    0x54, 0x41, 0x7a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54,
+    0x4c, 0x46, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x44, 0x5a, 0x58, 0x4a, 0x30,
+    0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44, 0x49, 0x67,
+    0x55, 0x47, 0x39, 0x73, 0x61, 0x57, 0x4e, 0x35, 0x49, 0x46, 0x5a, 0x68,
+    0x62, 0x47, 0x6c, 0x6b, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67,
+    0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x0a, 0x61, 0x58, 0x52,
+    0x35, 0x4d, 0x53, 0x45, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x44, 0x45, 0x78, 0x68, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69, 0x38,
+    0x76, 0x64, 0x33, 0x64, 0x33, 0x4c, 0x6e, 0x5a, 0x68, 0x62, 0x47, 0x6c,
+    0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x53, 0x38,
+    0x78, 0x49, 0x44, 0x41, 0x65, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69,
+    0x47, 0x0a, 0x39, 0x77, 0x30, 0x42, 0x43, 0x51, 0x45, 0x57, 0x45, 0x57,
+    0x6c, 0x75, 0x5a, 0x6d, 0x39, 0x41, 0x64, 0x6d, 0x46, 0x73, 0x61, 0x57,
+    0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4d, 0x42,
+    0x34, 0x58, 0x44, 0x54, 0x6b, 0x35, 0x4d, 0x44, 0x59, 0x79, 0x4e, 0x6a,
+    0x41, 0x77, 0x4d, 0x54, 0x6b, 0x31, 0x4e, 0x46, 0x6f, 0x58, 0x44, 0x54,
+    0x45, 0x35, 0x4d, 0x44, 0x59, 0x79, 0x0a, 0x4e, 0x6a, 0x41, 0x77, 0x4d,
+    0x54, 0x6b, 0x31, 0x4e, 0x46, 0x6f, 0x77, 0x67, 0x62, 0x73, 0x78, 0x4a,
+    0x44, 0x41, 0x69, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x47,
+    0x31, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x49,
+    0x46, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x6b, 0x59, 0x58, 0x52, 0x70, 0x62,
+    0x32, 0x34, 0x67, 0x54, 0x6d, 0x56, 0x30, 0x64, 0x32, 0x39, 0x79, 0x0a,
+    0x61, 0x7a, 0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x43, 0x68, 0x4d, 0x4f, 0x56, 0x6d, 0x46, 0x73, 0x61, 0x55, 0x4e, 0x6c,
+    0x63, 0x6e, 0x51, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78,
+    0x4e, 0x54, 0x41, 0x7a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54,
+    0x4c, 0x46, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x44, 0x5a, 0x58, 0x4a, 0x30,
+    0x49, 0x45, 0x4e, 0x73, 0x0a, 0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44, 0x49,
+    0x67, 0x55, 0x47, 0x39, 0x73, 0x61, 0x57, 0x4e, 0x35, 0x49, 0x46, 0x5a,
+    0x68, 0x62, 0x47, 0x6c, 0x6b, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34,
+    0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52,
+    0x35, 0x4d, 0x53, 0x45, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x44, 0x45, 0x78, 0x68, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x0a, 0x4f, 0x69,
+    0x38, 0x76, 0x64, 0x33, 0x64, 0x33, 0x4c, 0x6e, 0x5a, 0x68, 0x62, 0x47,
+    0x6c, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x53,
+    0x38, 0x78, 0x49, 0x44, 0x41, 0x65, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b,
+    0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x43, 0x51, 0x45, 0x57, 0x45, 0x57,
+    0x6c, 0x75, 0x5a, 0x6d, 0x39, 0x41, 0x64, 0x6d, 0x46, 0x73, 0x61, 0x57,
+    0x4e, 0x6c, 0x0a, 0x63, 0x6e, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4d,
+    0x49, 0x47, 0x66, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53,
+    0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41,
+    0x34, 0x47, 0x4e, 0x41, 0x44, 0x43, 0x42, 0x69, 0x51, 0x4b, 0x42, 0x67,
+    0x51, 0x44, 0x4f, 0x4f, 0x6e, 0x48, 0x4b, 0x35, 0x61, 0x76, 0x49, 0x57,
+    0x5a, 0x4a, 0x56, 0x31, 0x36, 0x76, 0x59, 0x0a, 0x64, 0x41, 0x37, 0x35,
+    0x37, 0x74, 0x6e, 0x32, 0x56, 0x55, 0x64, 0x5a, 0x5a, 0x55, 0x63, 0x4f,
+    0x42, 0x56, 0x58, 0x63, 0x36, 0x35, 0x67, 0x32, 0x50, 0x46, 0x78, 0x54,
+    0x58, 0x64, 0x4d, 0x77, 0x7a, 0x7a, 0x6a, 0x73, 0x76, 0x55, 0x47, 0x4a,
+    0x37, 0x53, 0x56, 0x43, 0x43, 0x53, 0x52, 0x72, 0x43, 0x6c, 0x36, 0x7a,
+    0x66, 0x4e, 0x31, 0x53, 0x4c, 0x55, 0x7a, 0x6d, 0x31, 0x4e, 0x5a, 0x39,
+    0x0a, 0x57, 0x6c, 0x6d, 0x70, 0x5a, 0x64, 0x52, 0x4a, 0x45, 0x79, 0x30,
+    0x6b, 0x54, 0x52, 0x78, 0x51, 0x62, 0x37, 0x58, 0x42, 0x68, 0x56, 0x51,
+    0x37, 0x2f, 0x6e, 0x48, 0x6b, 0x30, 0x31, 0x78, 0x43, 0x2b, 0x59, 0x44,
+    0x67, 0x6b, 0x52, 0x6f, 0x4b, 0x57, 0x7a, 0x6b, 0x32, 0x5a, 0x2f, 0x4d,
+    0x2f, 0x56, 0x58, 0x77, 0x62, 0x50, 0x37, 0x52, 0x66, 0x5a, 0x48, 0x4d,
+    0x30, 0x34, 0x37, 0x51, 0x53, 0x0a, 0x76, 0x34, 0x64, 0x6b, 0x2b, 0x4e,
+    0x6f, 0x53, 0x2f, 0x7a, 0x63, 0x6e, 0x77, 0x62, 0x4e, 0x44, 0x75, 0x2b,
+    0x39, 0x37, 0x62, 0x69, 0x35, 0x70, 0x39, 0x77, 0x49, 0x44, 0x41, 0x51,
+    0x41, 0x42, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49,
+    0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x41, 0x34,
+    0x47, 0x42, 0x41, 0x44, 0x74, 0x2f, 0x55, 0x47, 0x39, 0x76, 0x0a, 0x55,
+    0x4a, 0x53, 0x5a, 0x53, 0x57, 0x49, 0x34, 0x4f, 0x42, 0x39, 0x4c, 0x2b,
+    0x4b, 0x58, 0x49, 0x50, 0x71, 0x65, 0x43, 0x67, 0x66, 0x59, 0x72, 0x78,
+    0x2b, 0x6a, 0x46, 0x7a, 0x75, 0x67, 0x36, 0x45, 0x49, 0x4c, 0x4c, 0x47,
+    0x41, 0x43, 0x4f, 0x54, 0x62, 0x32, 0x6f, 0x57, 0x48, 0x2b, 0x68, 0x65,
+    0x51, 0x43, 0x31, 0x75, 0x2b, 0x6d, 0x4e, 0x72, 0x30, 0x48, 0x5a, 0x44,
+    0x7a, 0x54, 0x75, 0x0a, 0x49, 0x59, 0x45, 0x5a, 0x6f, 0x44, 0x4a, 0x4a,
+    0x4b, 0x50, 0x54, 0x45, 0x6a, 0x6c, 0x62, 0x56, 0x55, 0x6a, 0x50, 0x39,
+    0x55, 0x4e, 0x56, 0x2b, 0x6d, 0x57, 0x77, 0x44, 0x35, 0x4d, 0x6c, 0x4d,
+    0x2f, 0x4d, 0x74, 0x73, 0x71, 0x32, 0x61, 0x7a, 0x53, 0x69, 0x47, 0x4d,
+    0x35, 0x62, 0x55, 0x4d, 0x4d, 0x6a, 0x34, 0x51, 0x73, 0x73, 0x78, 0x73,
+    0x6f, 0x64, 0x79, 0x61, 0x6d, 0x45, 0x77, 0x43, 0x0a, 0x57, 0x2f, 0x50,
+    0x4f, 0x75, 0x5a, 0x36, 0x6c, 0x63, 0x67, 0x35, 0x4b, 0x74, 0x7a, 0x38,
+    0x38, 0x35, 0x68, 0x5a, 0x6f, 0x2b, 0x4c, 0x37, 0x74, 0x64, 0x45, 0x79,
+    0x38, 0x57, 0x39, 0x56, 0x69, 0x48, 0x30, 0x50, 0x64, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49,
+    0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a,
+    0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43,
+    0x4e, 0x3d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+    0x2e, 0x76, 0x61, 0x6c, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f,
+    0x6d, 0x2f, 0x20, 0x4f, 0x3d, 0x56, 0x61, 0x6c, 0x69, 0x43, 0x65, 0x72,
+    0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56,
+    0x61, 0x6c, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73,
+    0x73, 0x20, 0x33, 0x20, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x56,
+    0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
+    0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75,
+    0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x68, 0x74,
+    0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x61, 0x6c,
+    0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x20, 0x4f,
+    0x3d, 0x56, 0x61, 0x6c, 0x69, 0x43, 0x65, 0x72, 0x74, 0x2c, 0x20, 0x49,
+    0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x61, 0x6c, 0x69, 0x43,
+    0x65, 0x72, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20,
+    0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64,
+    0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+    0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a,
+    0x20, 0x22, 0x52, 0x53, 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43,
+    0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x31,
+    0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20,
+    0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x32, 0x3a,
+    0x36, 0x66, 0x3a, 0x35, 0x33, 0x3a, 0x62, 0x37, 0x3a, 0x65, 0x65, 0x3a,
+    0x34, 0x30, 0x3a, 0x64, 0x62, 0x3a, 0x34, 0x61, 0x3a, 0x36, 0x38, 0x3a,
+    0x65, 0x37, 0x3a, 0x66, 0x61, 0x3a, 0x31, 0x38, 0x3a, 0x64, 0x39, 0x3a,
+    0x31, 0x30, 0x3a, 0x34, 0x62, 0x3a, 0x37, 0x32, 0x0a, 0x23, 0x20, 0x53,
+    0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x39, 0x3a, 0x62, 0x64, 0x3a, 0x38,
+    0x63, 0x3a, 0x66, 0x34, 0x3a, 0x39, 0x63, 0x3a, 0x64, 0x33, 0x3a, 0x30,
+    0x30, 0x3a, 0x66, 0x62, 0x3a, 0x35, 0x39, 0x3a, 0x32, 0x65, 0x3a, 0x31,
+    0x37, 0x3a, 0x39, 0x33, 0x3a, 0x63, 0x61, 0x3a, 0x35, 0x35, 0x3a, 0x36,
+    0x61, 0x3a, 0x66, 0x33, 0x3a, 0x65, 0x63, 0x3a, 0x61, 0x61, 0x3a, 0x33,
+    0x35, 0x3a, 0x66, 0x62, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35,
+    0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x62, 0x63, 0x3a, 0x32, 0x33, 0x3a, 0x66, 0x39, 0x3a,
+    0x38, 0x61, 0x3a, 0x33, 0x31, 0x3a, 0x33, 0x63, 0x3a, 0x62, 0x39, 0x3a,
+    0x32, 0x64, 0x3a, 0x65, 0x33, 0x3a, 0x62, 0x62, 0x3a, 0x66, 0x63, 0x3a,
+    0x33, 0x61, 0x3a, 0x35, 0x61, 0x3a, 0x39, 0x66, 0x3a, 0x34, 0x34, 0x3a,
+    0x36, 0x31, 0x3a, 0x61, 0x63, 0x3a, 0x33, 0x39, 0x3a, 0x34, 0x39, 0x3a,
+    0x34, 0x63, 0x3a, 0x34, 0x61, 0x3a, 0x65, 0x31, 0x3a, 0x35, 0x61, 0x3a,
+    0x39, 0x65, 0x3a, 0x39, 0x64, 0x3a, 0x66, 0x31, 0x3a, 0x33, 0x31, 0x3a,
+    0x65, 0x39, 0x3a, 0x39, 0x62, 0x3a, 0x37, 0x33, 0x3a, 0x30, 0x31, 0x3a,
+    0x39, 0x61, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49,
+    0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54,
+    0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x35,
+    0x7a, 0x43, 0x43, 0x41, 0x6c, 0x41, 0x43, 0x41, 0x51, 0x45, 0x77, 0x44,
+    0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41,
+    0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x67, 0x62, 0x73, 0x78, 0x4a,
+    0x44, 0x41, 0x69, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x47,
+    0x31, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x0a,
+    0x49, 0x46, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x6b, 0x59, 0x58, 0x52, 0x70,
+    0x62, 0x32, 0x34, 0x67, 0x54, 0x6d, 0x56, 0x30, 0x64, 0x32, 0x39, 0x79,
+    0x61, 0x7a, 0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x43, 0x68, 0x4d, 0x4f, 0x56, 0x6d, 0x46, 0x73, 0x61, 0x55, 0x4e, 0x6c,
+    0x63, 0x6e, 0x51, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78,
+    0x4e, 0x54, 0x41, 0x7a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73,
+    0x54, 0x4c, 0x46, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x44, 0x5a, 0x58, 0x4a,
+    0x30, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44, 0x4d,
+    0x67, 0x55, 0x47, 0x39, 0x73, 0x61, 0x57, 0x4e, 0x35, 0x49, 0x46, 0x5a,
+    0x68, 0x62, 0x47, 0x6c, 0x6b, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34,
+    0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x0a, 0x61, 0x58,
+    0x52, 0x35, 0x4d, 0x53, 0x45, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x44, 0x45, 0x78, 0x68, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69,
+    0x38, 0x76, 0x64, 0x33, 0x64, 0x33, 0x4c, 0x6e, 0x5a, 0x68, 0x62, 0x47,
+    0x6c, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x53,
+    0x38, 0x78, 0x49, 0x44, 0x41, 0x65, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b,
+    0x69, 0x47, 0x0a, 0x39, 0x77, 0x30, 0x42, 0x43, 0x51, 0x45, 0x57, 0x45,
+    0x57, 0x6c, 0x75, 0x5a, 0x6d, 0x39, 0x41, 0x64, 0x6d, 0x46, 0x73, 0x61,
+    0x57, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4d,
+    0x42, 0x34, 0x58, 0x44, 0x54, 0x6b, 0x35, 0x4d, 0x44, 0x59, 0x79, 0x4e,
+    0x6a, 0x41, 0x77, 0x4d, 0x6a, 0x49, 0x7a, 0x4d, 0x31, 0x6f, 0x58, 0x44,
+    0x54, 0x45, 0x35, 0x4d, 0x44, 0x59, 0x79, 0x0a, 0x4e, 0x6a, 0x41, 0x77,
+    0x4d, 0x6a, 0x49, 0x7a, 0x4d, 0x31, 0x6f, 0x77, 0x67, 0x62, 0x73, 0x78,
+    0x4a, 0x44, 0x41, 0x69, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54,
+    0x47, 0x31, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x44, 0x5a, 0x58, 0x4a, 0x30,
+    0x49, 0x46, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x6b, 0x59, 0x58, 0x52, 0x70,
+    0x62, 0x32, 0x34, 0x67, 0x54, 0x6d, 0x56, 0x30, 0x64, 0x32, 0x39, 0x79,
+    0x0a, 0x61, 0x7a, 0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x43, 0x68, 0x4d, 0x4f, 0x56, 0x6d, 0x46, 0x73, 0x61, 0x55, 0x4e,
+    0x6c, 0x63, 0x6e, 0x51, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34,
+    0x78, 0x4e, 0x54, 0x41, 0x7a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73,
+    0x54, 0x4c, 0x46, 0x5a, 0x68, 0x62, 0x47, 0x6c, 0x44, 0x5a, 0x58, 0x4a,
+    0x30, 0x49, 0x45, 0x4e, 0x73, 0x0a, 0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44,
+    0x4d, 0x67, 0x55, 0x47, 0x39, 0x73, 0x61, 0x57, 0x4e, 0x35, 0x49, 0x46,
+    0x5a, 0x68, 0x62, 0x47, 0x6c, 0x6b, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32,
+    0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58,
+    0x52, 0x35, 0x4d, 0x53, 0x45, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x44, 0x45, 0x78, 0x68, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x0a, 0x4f,
+    0x69, 0x38, 0x76, 0x64, 0x33, 0x64, 0x33, 0x4c, 0x6e, 0x5a, 0x68, 0x62,
+    0x47, 0x6c, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x4c, 0x6d, 0x4e, 0x76, 0x62,
+    0x53, 0x38, 0x78, 0x49, 0x44, 0x41, 0x65, 0x42, 0x67, 0x6b, 0x71, 0x68,
+    0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x43, 0x51, 0x45, 0x57, 0x45,
+    0x57, 0x6c, 0x75, 0x5a, 0x6d, 0x39, 0x41, 0x64, 0x6d, 0x46, 0x73, 0x61,
+    0x57, 0x4e, 0x6c, 0x0a, 0x63, 0x6e, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74,
+    0x4d, 0x49, 0x47, 0x66, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47,
+    0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41,
+    0x41, 0x34, 0x47, 0x4e, 0x41, 0x44, 0x43, 0x42, 0x69, 0x51, 0x4b, 0x42,
+    0x67, 0x51, 0x44, 0x6a, 0x6d, 0x46, 0x47, 0x57, 0x48, 0x4f, 0x6a, 0x56,
+    0x73, 0x51, 0x61, 0x42, 0x61, 0x6c, 0x66, 0x44, 0x0a, 0x63, 0x6e, 0x57,
+    0x54, 0x71, 0x38, 0x2b, 0x65, 0x70, 0x76, 0x7a, 0x7a, 0x46, 0x6c, 0x4c,
+    0x57, 0x4c, 0x55, 0x32, 0x66, 0x4e, 0x55, 0x53, 0x6f, 0x4c, 0x67, 0x52,
+    0x4e, 0x42, 0x30, 0x6d, 0x4b, 0x4f, 0x43, 0x6e, 0x31, 0x64, 0x7a, 0x66,
+    0x6e, 0x74, 0x36, 0x74, 0x64, 0x33, 0x7a, 0x5a, 0x78, 0x46, 0x4a, 0x6d,
+    0x50, 0x33, 0x4d, 0x4b, 0x53, 0x38, 0x65, 0x64, 0x67, 0x6b, 0x70, 0x66,
+    0x73, 0x0a, 0x32, 0x45, 0x6a, 0x63, 0x76, 0x38, 0x45, 0x43, 0x49, 0x4d,
+    0x59, 0x6b, 0x70, 0x43, 0x68, 0x4d, 0x4d, 0x46, 0x70, 0x32, 0x62, 0x62,
+    0x46, 0x63, 0x38, 0x39, 0x33, 0x65, 0x6e, 0x68, 0x42, 0x78, 0x6f, 0x59,
+    0x6a, 0x48, 0x57, 0x35, 0x74, 0x42, 0x62, 0x63, 0x71, 0x77, 0x75, 0x49,
+    0x34, 0x56, 0x37, 0x71, 0x30, 0x7a, 0x4b, 0x38, 0x39, 0x48, 0x42, 0x46,
+    0x78, 0x31, 0x63, 0x51, 0x71, 0x59, 0x0a, 0x4a, 0x4a, 0x67, 0x70, 0x70,
+    0x30, 0x6c, 0x5a, 0x70, 0x64, 0x33, 0x34, 0x74, 0x30, 0x4e, 0x69, 0x59,
+    0x66, 0x50, 0x54, 0x34, 0x74, 0x42, 0x56, 0x50, 0x77, 0x49, 0x44, 0x41,
+    0x51, 0x41, 0x42, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53,
+    0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x41,
+    0x34, 0x47, 0x42, 0x41, 0x46, 0x61, 0x37, 0x41, 0x6c, 0x69, 0x45, 0x0a,
+    0x5a, 0x77, 0x67, 0x73, 0x33, 0x78, 0x2f, 0x62, 0x65, 0x30, 0x6b, 0x7a,
+    0x39, 0x64, 0x4e, 0x6e, 0x6e, 0x66, 0x53, 0x30, 0x43, 0x68, 0x43, 0x7a,
+    0x79, 0x63, 0x55, 0x73, 0x34, 0x70, 0x4a, 0x71, 0x63, 0x58, 0x67, 0x6e,
+    0x38, 0x6e, 0x43, 0x44, 0x51, 0x74, 0x4d, 0x2b, 0x7a, 0x36, 0x6c, 0x55,
+    0x39, 0x50, 0x48, 0x59, 0x6b, 0x68, 0x61, 0x4d, 0x30, 0x51, 0x54, 0x4c,
+    0x53, 0x36, 0x76, 0x4a, 0x0a, 0x6e, 0x30, 0x57, 0x75, 0x50, 0x49, 0x71,
+    0x70, 0x73, 0x48, 0x45, 0x7a, 0x58, 0x63, 0x6a, 0x46, 0x56, 0x39, 0x2b,
+    0x76, 0x71, 0x44, 0x57, 0x7a, 0x66, 0x34, 0x6d, 0x48, 0x36, 0x65, 0x67,
+    0x6c, 0x6b, 0x72, 0x68, 0x2f, 0x68, 0x58, 0x71, 0x75, 0x31, 0x72, 0x77,
+    0x65, 0x4e, 0x31, 0x67, 0x71, 0x5a, 0x38, 0x6d, 0x52, 0x7a, 0x79, 0x71,
+    0x42, 0x50, 0x75, 0x33, 0x47, 0x4f, 0x64, 0x2f, 0x41, 0x0a, 0x50, 0x68,
+    0x6d, 0x63, 0x47, 0x63, 0x77, 0x54, 0x54, 0x59, 0x4a, 0x42, 0x74, 0x59,
+    0x7a, 0x65, 0x34, 0x44, 0x31, 0x67, 0x43, 0x43, 0x41, 0x50, 0x52, 0x58,
+    0x35, 0x72, 0x6f, 0x6e, 0x2b, 0x6a, 0x6a, 0x42, 0x58, 0x75, 0x0a, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54,
+    0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20,
+    0x43, 0x4e, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20,
+    0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c,
+    0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43,
+    0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+    0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d,
+    0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69,
+    0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d,
+    0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75,
+    0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x28,
+    0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x56, 0x65, 0x72, 0x69,
+    0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d,
+    0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+    0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79,
+    0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20,
+    0x43, 0x4e, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20,
+    0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c,
+    0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43,
+    0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+    0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d,
+    0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69,
+    0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d,
+    0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75,
+    0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x28,
+    0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x56, 0x65, 0x72, 0x69,
+    0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d,
+    0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+    0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79,
+    0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x56,
+    0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73,
+    0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50,
+    0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+    0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74,
+    0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x22,
+    0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x32,
+    0x30, 0x36, 0x36, 0x38, 0x34, 0x36, 0x39, 0x36, 0x32, 0x37, 0x39, 0x34,
+    0x37, 0x32, 0x33, 0x31, 0x30, 0x32, 0x35, 0x34, 0x32, 0x37, 0x37, 0x38,
+    0x37, 0x30, 0x31, 0x38, 0x30, 0x39, 0x36, 0x36, 0x37, 0x32, 0x33, 0x34,
+    0x31, 0x35, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x64,
+    0x3a, 0x36, 0x38, 0x3a, 0x62, 0x36, 0x3a, 0x61, 0x37, 0x3a, 0x63, 0x37,
+    0x3a, 0x63, 0x34, 0x3a, 0x63, 0x65, 0x3a, 0x37, 0x35, 0x3a, 0x65, 0x30,
+    0x3a, 0x31, 0x64, 0x3a, 0x34, 0x66, 0x3a, 0x35, 0x37, 0x3a, 0x34, 0x34,
+    0x3a, 0x36, 0x31, 0x3a, 0x39, 0x32, 0x3a, 0x30, 0x39, 0x0a, 0x23, 0x20,
+    0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x33, 0x3a, 0x32, 0x64, 0x3a,
+    0x30, 0x64, 0x3a, 0x34, 0x35, 0x3a, 0x35, 0x33, 0x3a, 0x34, 0x62, 0x3a,
+    0x36, 0x39, 0x3a, 0x39, 0x37, 0x3a, 0x63, 0x64, 0x3a, 0x62, 0x32, 0x3a,
+    0x64, 0x35, 0x3a, 0x63, 0x33, 0x3a, 0x33, 0x39, 0x3a, 0x65, 0x32, 0x3a,
+    0x35, 0x35, 0x3a, 0x37, 0x36, 0x3a, 0x36, 0x30, 0x3a, 0x39, 0x62, 0x3a,
+    0x35, 0x63, 0x3a, 0x63, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32,
+    0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x65, 0x62, 0x3a, 0x30, 0x34, 0x3a, 0x63, 0x66,
+    0x3a, 0x35, 0x65, 0x3a, 0x62, 0x31, 0x3a, 0x66, 0x33, 0x3a, 0x39, 0x61,
+    0x3a, 0x66, 0x61, 0x3a, 0x37, 0x36, 0x3a, 0x32, 0x66, 0x3a, 0x32, 0x62,
+    0x3a, 0x62, 0x31, 0x3a, 0x32, 0x30, 0x3a, 0x66, 0x32, 0x3a, 0x39, 0x36,
+    0x3a, 0x63, 0x62, 0x3a, 0x61, 0x35, 0x3a, 0x32, 0x30, 0x3a, 0x63, 0x31,
+    0x3a, 0x62, 0x39, 0x3a, 0x37, 0x64, 0x3a, 0x62, 0x31, 0x3a, 0x35, 0x38,
+    0x3a, 0x39, 0x35, 0x3a, 0x36, 0x35, 0x3a, 0x62, 0x38, 0x3a, 0x31, 0x63,
+    0x3a, 0x62, 0x39, 0x3a, 0x61, 0x31, 0x3a, 0x37, 0x62, 0x3a, 0x37, 0x32,
+    0x3a, 0x34, 0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47,
+    0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41,
+    0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45,
+    0x47, 0x6a, 0x43, 0x43, 0x41, 0x77, 0x49, 0x43, 0x45, 0x51, 0x43, 0x62,
+    0x66, 0x67, 0x5a, 0x4a, 0x6f, 0x7a, 0x35, 0x69, 0x75, 0x64, 0x58, 0x75,
+    0x6b, 0x45, 0x68, 0x78, 0x4b, 0x65, 0x39, 0x58, 0x4d, 0x41, 0x30, 0x47,
+    0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42,
+    0x42, 0x51, 0x55, 0x41, 0x4d, 0x49, 0x48, 0x4b, 0x4d, 0x51, 0x73, 0x77,
+    0x0a, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a,
+    0x56, 0x55, 0x7a, 0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x43, 0x68, 0x4d, 0x4f, 0x56, 0x6d, 0x56, 0x79, 0x61, 0x56, 0x4e,
+    0x70, 0x5a, 0x32, 0x34, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34,
+    0x78, 0x48, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73,
+    0x54, 0x46, 0x6c, 0x5a, 0x6c, 0x0a, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57,
+    0x64, 0x75, 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45,
+    0x35, 0x6c, 0x64, 0x48, 0x64, 0x76, 0x63, 0x6d, 0x73, 0x78, 0x4f, 0x6a,
+    0x41, 0x34, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x4d, 0x53,
+    0x68, 0x6a, 0x4b, 0x53, 0x41, 0x78, 0x4f, 0x54, 0x6b, 0x35, 0x49, 0x46,
+    0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x0a, 0x4c,
+    0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30, 0x67, 0x52,
+    0x6d, 0x39, 0x79, 0x49, 0x47, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63,
+    0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, 0x58, 0x4e, 0x6c, 0x49,
+    0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x52, 0x54, 0x42, 0x44, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x50, 0x46, 0x5a, 0x6c, 0x63,
+    0x6d, 0x6c, 0x54, 0x0a, 0x61, 0x57, 0x64, 0x75, 0x49, 0x45, 0x4e, 0x73,
+    0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44, 0x4d, 0x67, 0x55, 0x48, 0x56, 0x69,
+    0x62, 0x47, 0x6c, 0x6a, 0x49, 0x46, 0x42, 0x79, 0x61, 0x57, 0x31, 0x68,
+    0x63, 0x6e, 0x6b, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d,
+    0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42,
+    0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x0a, 0x64, 0x48, 0x6b,
+    0x67, 0x4c, 0x53, 0x42, 0x48, 0x4d, 0x7a, 0x41, 0x65, 0x46, 0x77, 0x30,
+    0x35, 0x4f, 0x54, 0x45, 0x77, 0x4d, 0x44, 0x45, 0x77, 0x4d, 0x44, 0x41,
+    0x77, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4e, 0x6a, 0x41,
+    0x33, 0x4d, 0x54, 0x59, 0x79, 0x4d, 0x7a, 0x55, 0x35, 0x4e, 0x54, 0x6c,
+    0x61, 0x4d, 0x49, 0x48, 0x4b, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59,
+    0x44, 0x0a, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a,
+    0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68,
+    0x4d, 0x4f, 0x56, 0x6d, 0x56, 0x79, 0x61, 0x56, 0x4e, 0x70, 0x5a, 0x32,
+    0x34, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x48, 0x7a,
+    0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x46, 0x6c,
+    0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x0a, 0x61, 0x57, 0x64, 0x75, 0x49,
+    0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x35, 0x6c, 0x64,
+    0x48, 0x64, 0x76, 0x63, 0x6d, 0x73, 0x78, 0x4f, 0x6a, 0x41, 0x34, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x4d, 0x53, 0x68, 0x6a, 0x4b,
+    0x53, 0x41, 0x78, 0x4f, 0x54, 0x6b, 0x35, 0x49, 0x46, 0x5a, 0x6c, 0x63,
+    0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x4c, 0x43, 0x42, 0x4a, 0x0a,
+    0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30, 0x67, 0x52, 0x6d, 0x39, 0x79,
+    0x49, 0x47, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x36,
+    0x5a, 0x57, 0x51, 0x67, 0x64, 0x58, 0x4e, 0x6c, 0x49, 0x47, 0x39, 0x75,
+    0x62, 0x48, 0x6b, 0x78, 0x52, 0x54, 0x42, 0x44, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x4d, 0x54, 0x50, 0x46, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54,
+    0x61, 0x57, 0x64, 0x75, 0x0a, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e,
+    0x7a, 0x49, 0x44, 0x4d, 0x67, 0x55, 0x48, 0x56, 0x69, 0x62, 0x47, 0x6c,
+    0x6a, 0x49, 0x46, 0x42, 0x79, 0x61, 0x57, 0x31, 0x68, 0x63, 0x6e, 0x6b,
+    0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e,
+    0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52,
+    0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x0a, 0x4c, 0x53,
+    0x42, 0x48, 0x4d, 0x7a, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51,
+    0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51,
+    0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44,
+    0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4d,
+    0x75, 0x36, 0x6e, 0x46, 0x4c, 0x38, 0x65, 0x42, 0x38, 0x61, 0x48, 0x6d,
+    0x38, 0x62, 0x0a, 0x4e, 0x33, 0x4f, 0x39, 0x2b, 0x4d, 0x6c, 0x72, 0x6c,
+    0x42, 0x49, 0x77, 0x54, 0x2f, 0x41, 0x32, 0x52, 0x2f, 0x58, 0x51, 0x6b,
+    0x51, 0x72, 0x31, 0x46, 0x38, 0x69, 0x6c, 0x59, 0x63, 0x45, 0x57, 0x51,
+    0x45, 0x33, 0x37, 0x69, 0x6d, 0x47, 0x51, 0x35, 0x58, 0x59, 0x67, 0x77,
+    0x52, 0x45, 0x47, 0x66, 0x61, 0x73, 0x73, 0x62, 0x71, 0x62, 0x31, 0x45,
+    0x55, 0x47, 0x4f, 0x2b, 0x69, 0x32, 0x74, 0x0a, 0x4b, 0x6d, 0x46, 0x5a,
+    0x70, 0x47, 0x63, 0x6d, 0x54, 0x4e, 0x44, 0x6f, 0x76, 0x46, 0x4a, 0x62,
+    0x63, 0x43, 0x41, 0x45, 0x57, 0x4e, 0x46, 0x36, 0x79, 0x61, 0x52, 0x70,
+    0x76, 0x49, 0x4d, 0x58, 0x5a, 0x4b, 0x30, 0x46, 0x69, 0x37, 0x7a, 0x51,
+    0x57, 0x4d, 0x36, 0x4e, 0x6a, 0x50, 0x58, 0x72, 0x38, 0x45, 0x4a, 0x4a,
+    0x43, 0x35, 0x32, 0x58, 0x4a, 0x32, 0x63, 0x79, 0x62, 0x75, 0x47, 0x75,
+    0x0a, 0x6b, 0x78, 0x55, 0x63, 0x63, 0x4c, 0x77, 0x67, 0x54, 0x53, 0x38,
+    0x59, 0x33, 0x70, 0x4b, 0x49, 0x36, 0x47, 0x79, 0x46, 0x56, 0x78, 0x45,
+    0x61, 0x36, 0x58, 0x37, 0x6a, 0x4a, 0x68, 0x46, 0x55, 0x6f, 0x6b, 0x57,
+    0x57, 0x56, 0x59, 0x50, 0x4b, 0x4d, 0x49, 0x6e, 0x6f, 0x33, 0x4e, 0x69,
+    0x6a, 0x37, 0x53, 0x71, 0x41, 0x50, 0x33, 0x39, 0x35, 0x5a, 0x56, 0x63,
+    0x2b, 0x46, 0x53, 0x42, 0x6d, 0x0a, 0x43, 0x43, 0x2b, 0x56, 0x6b, 0x37,
+    0x2b, 0x71, 0x52, 0x79, 0x2b, 0x6f, 0x52, 0x70, 0x66, 0x77, 0x45, 0x75,
+    0x4c, 0x2b, 0x77, 0x67, 0x6f, 0x72, 0x55, 0x65, 0x5a, 0x32, 0x35, 0x72,
+    0x64, 0x47, 0x74, 0x2b, 0x49, 0x4e, 0x70, 0x73, 0x79, 0x6f, 0x77, 0x30,
+    0x78, 0x5a, 0x56, 0x59, 0x6e, 0x6d, 0x36, 0x46, 0x4e, 0x63, 0x48, 0x4f,
+    0x71, 0x64, 0x38, 0x47, 0x49, 0x57, 0x43, 0x36, 0x66, 0x4a, 0x0a, 0x58,
+    0x77, 0x7a, 0x77, 0x33, 0x73, 0x4a, 0x32, 0x7a, 0x71, 0x2f, 0x33, 0x61,
+    0x76, 0x4c, 0x36, 0x51, 0x61, 0x61, 0x69, 0x4d, 0x78, 0x54, 0x4a, 0x35,
+    0x58, 0x70, 0x6a, 0x30, 0x35, 0x35, 0x69, 0x4e, 0x39, 0x57, 0x46, 0x5a,
+    0x5a, 0x34, 0x4f, 0x35, 0x6c, 0x4d, 0x6b, 0x64, 0x42, 0x74, 0x65, 0x48,
+    0x52, 0x4a, 0x54, 0x57, 0x38, 0x63, 0x73, 0x35, 0x34, 0x4e, 0x4a, 0x4f,
+    0x78, 0x57, 0x75, 0x0a, 0x69, 0x6d, 0x69, 0x35, 0x56, 0x35, 0x63, 0x43,
+    0x41, 0x77, 0x45, 0x41, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71,
+    0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46,
+    0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x45, 0x52, 0x53, 0x57,
+    0x77, 0x61, 0x75, 0x53, 0x43, 0x50, 0x63, 0x2f, 0x4c, 0x38, 0x6d, 0x79,
+    0x2f, 0x75, 0x52, 0x61, 0x6e, 0x32, 0x54, 0x65, 0x0a, 0x32, 0x79, 0x46,
+    0x50, 0x68, 0x70, 0x6b, 0x30, 0x64, 0x6a, 0x5a, 0x58, 0x33, 0x64, 0x41,
+    0x56, 0x4c, 0x38, 0x57, 0x74, 0x66, 0x78, 0x55, 0x66, 0x4e, 0x32, 0x4a,
+    0x7a, 0x50, 0x74, 0x54, 0x6e, 0x58, 0x38, 0x34, 0x58, 0x41, 0x39, 0x73,
+    0x31, 0x2b, 0x69, 0x76, 0x62, 0x72, 0x6d, 0x41, 0x4a, 0x58, 0x78, 0x35,
+    0x66, 0x6a, 0x32, 0x36, 0x37, 0x43, 0x7a, 0x33, 0x71, 0x57, 0x68, 0x4d,
+    0x65, 0x0a, 0x44, 0x47, 0x42, 0x76, 0x74, 0x63, 0x43, 0x31, 0x49, 0x79,
+    0x49, 0x75, 0x42, 0x77, 0x76, 0x4c, 0x71, 0x58, 0x54, 0x4c, 0x52, 0x37,
+    0x73, 0x64, 0x77, 0x64, 0x65, 0x6c, 0x61, 0x38, 0x77, 0x76, 0x30, 0x6b,
+    0x4c, 0x39, 0x53, 0x64, 0x32, 0x6e, 0x69, 0x63, 0x39, 0x54, 0x75, 0x74,
+    0x6f, 0x41, 0x57, 0x69, 0x69, 0x2f, 0x67, 0x74, 0x2f, 0x34, 0x75, 0x68,
+    0x4d, 0x64, 0x55, 0x49, 0x61, 0x43, 0x0a, 0x2f, 0x59, 0x34, 0x77, 0x6a,
+    0x79, 0x6c, 0x47, 0x73, 0x42, 0x34, 0x39, 0x4e, 0x64, 0x6f, 0x34, 0x59,
+    0x68, 0x59, 0x59, 0x53, 0x71, 0x33, 0x6d, 0x74, 0x6c, 0x46, 0x73, 0x33,
+    0x71, 0x39, 0x69, 0x36, 0x77, 0x48, 0x51, 0x48, 0x69, 0x54, 0x2b, 0x65,
+    0x6f, 0x38, 0x53, 0x47, 0x68, 0x4a, 0x6f, 0x75, 0x50, 0x74, 0x6d, 0x6d,
+    0x52, 0x51, 0x55, 0x52, 0x56, 0x79, 0x75, 0x35, 0x36, 0x35, 0x70, 0x0a,
+    0x46, 0x34, 0x45, 0x72, 0x57, 0x6a, 0x66, 0x4a, 0x58, 0x69, 0x72, 0x30,
+    0x78, 0x75, 0x4b, 0x68, 0x58, 0x46, 0x53, 0x62, 0x70, 0x6c, 0x51, 0x41,
+    0x7a, 0x2f, 0x44, 0x78, 0x77, 0x63, 0x65, 0x59, 0x4d, 0x42, 0x6f, 0x37,
+    0x4e, 0x68, 0x62, 0x62, 0x6f, 0x32, 0x37, 0x71, 0x2f, 0x61, 0x32, 0x79,
+    0x77, 0x74, 0x72, 0x76, 0x41, 0x6b, 0x63, 0x54, 0x69, 0x73, 0x44, 0x78,
+    0x73, 0x7a, 0x47, 0x74, 0x0a, 0x54, 0x78, 0x7a, 0x68, 0x54, 0x35, 0x79,
+    0x76, 0x44, 0x77, 0x79, 0x64, 0x39, 0x33, 0x67, 0x4e, 0x32, 0x50, 0x51,
+    0x31, 0x56, 0x6f, 0x44, 0x61, 0x74, 0x32, 0x30, 0x58, 0x6a, 0x35, 0x30,
+    0x65, 0x67, 0x57, 0x54, 0x68, 0x2f, 0x73, 0x56, 0x46, 0x75, 0x71, 0x31,
+    0x72, 0x75, 0x51, 0x70, 0x36, 0x54, 0x6b, 0x39, 0x4c, 0x68, 0x4f, 0x35,
+    0x4c, 0x38, 0x58, 0x33, 0x64, 0x45, 0x51, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49,
+    0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a,
+    0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43,
+    0x4e, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43,
+    0x6c, 0x61, 0x73, 0x73, 0x20, 0x34, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69,
+    0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65,
+    0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+    0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20,
+    0x47, 0x33, 0x20, 0x4f, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+    0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56,
+    0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73,
+    0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x28, 0x63,
+    0x29, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53,
+    0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20,
+    0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a,
+    0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a,
+    0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43,
+    0x4e, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43,
+    0x6c, 0x61, 0x73, 0x73, 0x20, 0x34, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69,
+    0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65,
+    0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+    0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20,
+    0x47, 0x33, 0x20, 0x4f, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+    0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56,
+    0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73,
+    0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x28, 0x63,
+    0x29, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53,
+    0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20,
+    0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a,
+    0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a,
+    0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x56, 0x65,
+    0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73,
+    0x20, 0x34, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72,
+    0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+    0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x22, 0x0a,
+    0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x33, 0x31,
+    0x34, 0x35, 0x33, 0x31, 0x39, 0x37, 0x32, 0x37, 0x31, 0x31, 0x39, 0x30,
+    0x39, 0x34, 0x31, 0x33, 0x37, 0x34, 0x33, 0x30, 0x37, 0x35, 0x30, 0x39,
+    0x36, 0x30, 0x33, 0x39, 0x33, 0x37, 0x38, 0x39, 0x33, 0x35, 0x35, 0x31,
+    0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x62, 0x3a,
+    0x63, 0x38, 0x3a, 0x66, 0x32, 0x3a, 0x32, 0x37, 0x3a, 0x32, 0x65, 0x3a,
+    0x62, 0x31, 0x3a, 0x65, 0x61, 0x3a, 0x36, 0x61, 0x3a, 0x32, 0x39, 0x3a,
+    0x32, 0x33, 0x3a, 0x35, 0x64, 0x3a, 0x66, 0x65, 0x3a, 0x35, 0x36, 0x3a,
+    0x33, 0x65, 0x3a, 0x33, 0x33, 0x3a, 0x64, 0x66, 0x0a, 0x23, 0x20, 0x53,
+    0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x38, 0x3a, 0x65, 0x63, 0x3a, 0x38,
+    0x63, 0x3a, 0x38, 0x37, 0x3a, 0x39, 0x32, 0x3a, 0x36, 0x39, 0x3a, 0x63,
+    0x62, 0x3a, 0x34, 0x62, 0x3a, 0x61, 0x62, 0x3a, 0x33, 0x39, 0x3a, 0x65,
+    0x39, 0x3a, 0x38, 0x64, 0x3a, 0x37, 0x65, 0x3a, 0x35, 0x37, 0x3a, 0x36,
+    0x37, 0x3a, 0x66, 0x33, 0x3a, 0x31, 0x34, 0x3a, 0x39, 0x35, 0x3a, 0x37,
+    0x33, 0x3a, 0x39, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35,
+    0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x65, 0x33, 0x3a, 0x38, 0x39, 0x3a, 0x33, 0x36, 0x3a,
+    0x30, 0x64, 0x3a, 0x30, 0x66, 0x3a, 0x64, 0x62, 0x3a, 0x61, 0x65, 0x3a,
+    0x62, 0x33, 0x3a, 0x64, 0x32, 0x3a, 0x35, 0x30, 0x3a, 0x35, 0x38, 0x3a,
+    0x34, 0x62, 0x3a, 0x34, 0x37, 0x3a, 0x33, 0x30, 0x3a, 0x33, 0x31, 0x3a,
+    0x34, 0x65, 0x3a, 0x32, 0x32, 0x3a, 0x32, 0x66, 0x3a, 0x33, 0x39, 0x3a,
+    0x63, 0x31, 0x3a, 0x35, 0x36, 0x3a, 0x61, 0x30, 0x3a, 0x32, 0x30, 0x3a,
+    0x31, 0x34, 0x3a, 0x34, 0x65, 0x3a, 0x38, 0x64, 0x3a, 0x39, 0x36, 0x3a,
+    0x30, 0x35, 0x3a, 0x36, 0x31, 0x3a, 0x37, 0x39, 0x3a, 0x31, 0x35, 0x3a,
+    0x30, 0x36, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49,
+    0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54,
+    0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x47,
+    0x6a, 0x43, 0x43, 0x41, 0x77, 0x49, 0x43, 0x45, 0x51, 0x44, 0x73, 0x6f,
+    0x4b, 0x65, 0x4c, 0x62, 0x6e, 0x56, 0x71, 0x41, 0x63, 0x2f, 0x45, 0x66,
+    0x4d, 0x77, 0x76, 0x6c, 0x46, 0x37, 0x58, 0x4d, 0x41, 0x30, 0x47, 0x43,
+    0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42,
+    0x51, 0x55, 0x41, 0x4d, 0x49, 0x48, 0x4b, 0x4d, 0x51, 0x73, 0x77, 0x0a,
+    0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56,
+    0x55, 0x7a, 0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x43, 0x68, 0x4d, 0x4f, 0x56, 0x6d, 0x56, 0x79, 0x61, 0x56, 0x4e, 0x70,
+    0x5a, 0x32, 0x34, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78,
+    0x48, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54,
+    0x46, 0x6c, 0x5a, 0x6c, 0x0a, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64,
+    0x75, 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x35,
+    0x6c, 0x64, 0x48, 0x64, 0x76, 0x63, 0x6d, 0x73, 0x78, 0x4f, 0x6a, 0x41,
+    0x34, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x4d, 0x53, 0x68,
+    0x6a, 0x4b, 0x53, 0x41, 0x78, 0x4f, 0x54, 0x6b, 0x35, 0x49, 0x46, 0x5a,
+    0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x0a, 0x4c, 0x43,
+    0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30, 0x67, 0x52, 0x6d,
+    0x39, 0x79, 0x49, 0x47, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d,
+    0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, 0x58, 0x4e, 0x6c, 0x49, 0x47,
+    0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x52, 0x54, 0x42, 0x44, 0x42, 0x67,
+    0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x50, 0x46, 0x5a, 0x6c, 0x63, 0x6d,
+    0x6c, 0x54, 0x0a, 0x61, 0x57, 0x64, 0x75, 0x49, 0x45, 0x4e, 0x73, 0x59,
+    0x58, 0x4e, 0x7a, 0x49, 0x44, 0x51, 0x67, 0x55, 0x48, 0x56, 0x69, 0x62,
+    0x47, 0x6c, 0x6a, 0x49, 0x46, 0x42, 0x79, 0x61, 0x57, 0x31, 0x68, 0x63,
+    0x6e, 0x6b, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61,
+    0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64,
+    0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x0a, 0x64, 0x48, 0x6b, 0x67,
+    0x4c, 0x53, 0x42, 0x48, 0x4d, 0x7a, 0x41, 0x65, 0x46, 0x77, 0x30, 0x35,
+    0x4f, 0x54, 0x45, 0x77, 0x4d, 0x44, 0x45, 0x77, 0x4d, 0x44, 0x41, 0x77,
+    0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4e, 0x6a, 0x41, 0x33,
+    0x4d, 0x54, 0x59, 0x79, 0x4d, 0x7a, 0x55, 0x35, 0x4e, 0x54, 0x6c, 0x61,
+    0x4d, 0x49, 0x48, 0x4b, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44,
+    0x0a, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45,
+    0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d,
+    0x4f, 0x56, 0x6d, 0x56, 0x79, 0x61, 0x56, 0x4e, 0x70, 0x5a, 0x32, 0x34,
+    0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x48, 0x7a, 0x41,
+    0x64, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x46, 0x6c, 0x5a,
+    0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x0a, 0x61, 0x57, 0x64, 0x75, 0x49, 0x46,
+    0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x35, 0x6c, 0x64, 0x48,
+    0x64, 0x76, 0x63, 0x6d, 0x73, 0x78, 0x4f, 0x6a, 0x41, 0x34, 0x42, 0x67,
+    0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x4d, 0x53, 0x68, 0x6a, 0x4b, 0x53,
+    0x41, 0x78, 0x4f, 0x54, 0x6b, 0x35, 0x49, 0x46, 0x5a, 0x6c, 0x63, 0x6d,
+    0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x4c, 0x43, 0x42, 0x4a, 0x0a, 0x62,
+    0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30, 0x67, 0x52, 0x6d, 0x39, 0x79, 0x49,
+    0x47, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x36, 0x5a,
+    0x57, 0x51, 0x67, 0x64, 0x58, 0x4e, 0x6c, 0x49, 0x47, 0x39, 0x75, 0x62,
+    0x48, 0x6b, 0x78, 0x52, 0x54, 0x42, 0x44, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x4d, 0x54, 0x50, 0x46, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61,
+    0x57, 0x64, 0x75, 0x0a, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a,
+    0x49, 0x44, 0x51, 0x67, 0x55, 0x48, 0x56, 0x69, 0x62, 0x47, 0x6c, 0x6a,
+    0x49, 0x46, 0x42, 0x79, 0x61, 0x57, 0x31, 0x68, 0x63, 0x6e, 0x6b, 0x67,
+    0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68,
+    0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f,
+    0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x0a, 0x4c, 0x53, 0x42,
+    0x48, 0x4d, 0x7a, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59,
+    0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45,
+    0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43,
+    0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4b, 0x33,
+    0x4c, 0x70, 0x52, 0x46, 0x70, 0x78, 0x6c, 0x6d, 0x72, 0x38, 0x59, 0x2b,
+    0x31, 0x0a, 0x47, 0x51, 0x39, 0x57, 0x7a, 0x73, 0x79, 0x31, 0x48, 0x79,
+    0x44, 0x6b, 0x6e, 0x69, 0x59, 0x6c, 0x53, 0x2b, 0x42, 0x7a, 0x5a, 0x59,
+    0x6c, 0x5a, 0x33, 0x74, 0x43, 0x44, 0x35, 0x50, 0x55, 0x50, 0x74, 0x62,
+    0x75, 0x74, 0x38, 0x58, 0x7a, 0x6f, 0x49, 0x66, 0x7a, 0x6b, 0x36, 0x41,
+    0x7a, 0x75, 0x66, 0x45, 0x55, 0x69, 0x47, 0x58, 0x61, 0x53, 0x74, 0x42,
+    0x4f, 0x33, 0x49, 0x46, 0x73, 0x4a, 0x0a, 0x2b, 0x6d, 0x47, 0x75, 0x71,
+    0x50, 0x4b, 0x6c, 0x6a, 0x59, 0x58, 0x43, 0x4b, 0x74, 0x62, 0x65, 0x5a,
+    0x6a, 0x62, 0x53, 0x6d, 0x77, 0x4c, 0x30, 0x71, 0x4a, 0x4a, 0x67, 0x66,
+    0x4a, 0x78, 0x70, 0x74, 0x49, 0x38, 0x6b, 0x48, 0x74, 0x43, 0x47, 0x55,
+    0x76, 0x59, 0x79, 0x6e, 0x45, 0x46, 0x59, 0x48, 0x69, 0x4b, 0x39, 0x7a,
+    0x55, 0x56, 0x69, 0x6c, 0x51, 0x68, 0x75, 0x30, 0x47, 0x62, 0x64, 0x0a,
+    0x55, 0x36, 0x4c, 0x4d, 0x38, 0x42, 0x44, 0x63, 0x56, 0x48, 0x4f, 0x4c,
+    0x42, 0x4b, 0x46, 0x47, 0x4d, 0x7a, 0x4e, 0x63, 0x46, 0x30, 0x43, 0x35,
+    0x6e, 0x6b, 0x33, 0x54, 0x38, 0x37, 0x35, 0x56, 0x67, 0x2b, 0x69, 0x78,
+    0x69, 0x59, 0x35, 0x61, 0x66, 0x4a, 0x71, 0x57, 0x49, 0x70, 0x41, 0x37,
+    0x69, 0x43, 0x58, 0x79, 0x30, 0x6c, 0x4f, 0x49, 0x41, 0x67, 0x77, 0x4c,
+    0x65, 0x50, 0x4c, 0x6d, 0x0a, 0x4e, 0x78, 0x64, 0x4c, 0x4d, 0x45, 0x59,
+    0x48, 0x35, 0x49, 0x42, 0x74, 0x70, 0x74, 0x69, 0x57, 0x4c, 0x75, 0x67,
+    0x73, 0x2b, 0x42, 0x47, 0x7a, 0x4f, 0x41, 0x31, 0x6d, 0x70, 0x70, 0x76,
+    0x71, 0x79, 0x53, 0x4e, 0x62, 0x32, 0x34, 0x37, 0x69, 0x38, 0x78, 0x4f,
+    0x4f, 0x47, 0x6c, 0x6b, 0x74, 0x71, 0x67, 0x4c, 0x77, 0x37, 0x4b, 0x53,
+    0x48, 0x5a, 0x74, 0x7a, 0x42, 0x50, 0x2f, 0x58, 0x59, 0x0a, 0x75, 0x66,
+    0x54, 0x73, 0x67, 0x73, 0x62, 0x53, 0x50, 0x5a, 0x55, 0x64, 0x35, 0x63,
+    0x42, 0x50, 0x68, 0x4d, 0x6e, 0x5a, 0x6f, 0x30, 0x51, 0x6f, 0x42, 0x6d,
+    0x72, 0x58, 0x52, 0x61, 0x7a, 0x77, 0x61, 0x32, 0x72, 0x76, 0x54, 0x6c,
+    0x2f, 0x34, 0x45, 0x59, 0x49, 0x65, 0x4f, 0x47, 0x4d, 0x30, 0x5a, 0x6c,
+    0x44, 0x55, 0x50, 0x70, 0x4e, 0x7a, 0x2b, 0x6a, 0x44, 0x44, 0x5a, 0x71,
+    0x33, 0x2f, 0x0a, 0x6b, 0x79, 0x32, 0x58, 0x37, 0x77, 0x4d, 0x43, 0x41,
+    0x77, 0x45, 0x41, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68,
+    0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41,
+    0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x6a, 0x2f, 0x6f, 0x6c, 0x61,
+    0x30, 0x39, 0x62, 0x35, 0x4b, 0x52, 0x4f, 0x4a, 0x31, 0x57, 0x72, 0x49,
+    0x68, 0x56, 0x5a, 0x50, 0x4d, 0x71, 0x31, 0x0a, 0x43, 0x74, 0x52, 0x4b,
+    0x32, 0x36, 0x76, 0x64, 0x6f, 0x56, 0x39, 0x54, 0x78, 0x61, 0x42, 0x58,
+    0x4f, 0x63, 0x4c, 0x4f, 0x52, 0x79, 0x75, 0x2b, 0x4f, 0x73, 0x68, 0x57,
+    0x76, 0x38, 0x4c, 0x5a, 0x4a, 0x78, 0x41, 0x36, 0x73, 0x51, 0x55, 0x38,
+    0x77, 0x48, 0x63, 0x78, 0x75, 0x7a, 0x72, 0x54, 0x42, 0x58, 0x74, 0x74,
+    0x6d, 0x68, 0x77, 0x77, 0x6a, 0x49, 0x44, 0x4c, 0x6b, 0x35, 0x4d, 0x71,
+    0x0a, 0x67, 0x36, 0x73, 0x46, 0x55, 0x59, 0x49, 0x43, 0x41, 0x42, 0x46,
+    0x6e, 0x61, 0x2f, 0x4f, 0x49, 0x59, 0x55, 0x64, 0x66, 0x41, 0x35, 0x50,
+    0x56, 0x57, 0x77, 0x33, 0x67, 0x38, 0x64, 0x53, 0x68, 0x4d, 0x6a, 0x57,
+    0x46, 0x73, 0x6a, 0x72, 0x62, 0x73, 0x49, 0x4b, 0x72, 0x30, 0x63, 0x73,
+    0x4b, 0x76, 0x45, 0x2b, 0x4d, 0x57, 0x38, 0x56, 0x4c, 0x41, 0x44, 0x73,
+    0x66, 0x4b, 0x6f, 0x4b, 0x6d, 0x0a, 0x66, 0x6a, 0x61, 0x46, 0x33, 0x48,
+    0x34, 0x38, 0x5a, 0x77, 0x43, 0x31, 0x35, 0x44, 0x74, 0x53, 0x34, 0x4b,
+    0x6a, 0x72, 0x58, 0x52, 0x58, 0x35, 0x78, 0x6d, 0x33, 0x77, 0x72, 0x52,
+    0x30, 0x4f, 0x68, 0x62, 0x65, 0x70, 0x6d, 0x6e, 0x4d, 0x55, 0x57, 0x6c,
+    0x75, 0x50, 0x51, 0x53, 0x6a, 0x41, 0x31, 0x65, 0x67, 0x74, 0x54, 0x61,
+    0x52, 0x65, 0x7a, 0x61, 0x72, 0x5a, 0x37, 0x63, 0x37, 0x63, 0x0a, 0x32,
+    0x4e, 0x55, 0x38, 0x51, 0x68, 0x30, 0x58, 0x77, 0x52, 0x4a, 0x64, 0x52,
+    0x54, 0x6a, 0x44, 0x4f, 0x50, 0x50, 0x38, 0x68, 0x53, 0x36, 0x44, 0x52,
+    0x6b, 0x69, 0x79, 0x31, 0x79, 0x42, 0x66, 0x6b, 0x6a, 0x61, 0x50, 0x35,
+    0x33, 0x6b, 0x50, 0x6d, 0x46, 0x36, 0x5a, 0x36, 0x50, 0x44, 0x51, 0x70,
+    0x4c, 0x76, 0x31, 0x55, 0x37, 0x30, 0x71, 0x7a, 0x6c, 0x6d, 0x77, 0x72,
+    0x32, 0x35, 0x2f, 0x0a, 0x62, 0x4c, 0x76, 0x53, 0x48, 0x67, 0x43, 0x77,
+    0x49, 0x65, 0x33, 0x34, 0x51, 0x57, 0x4b, 0x43, 0x75, 0x64, 0x69, 0x79,
+    0x78, 0x4c, 0x74, 0x47, 0x55, 0x50, 0x4d, 0x78, 0x78, 0x59, 0x38, 0x42,
+    0x71, 0x48, 0x54, 0x72, 0x39, 0x58, 0x67, 0x6e, 0x32, 0x75, 0x66, 0x33,
+    0x5a, 0x6b, 0x50, 0x7a, 0x6e, 0x6f, 0x4d, 0x2b, 0x49, 0x4b, 0x72, 0x44,
+    0x4e, 0x57, 0x43, 0x52, 0x7a, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a,
+    0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74,
+    0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76,
+    0x65, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+    0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+    0x74, 0x79, 0x20, 0x4f, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74,
+    0x2e, 0x6e, 0x65, 0x74, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e,
+    0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f,
+    0x43, 0x50, 0x53, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x20,
+    0x62, 0x79, 0x20, 0x72, 0x65, 0x66, 0x2e, 0x20, 0x28, 0x6c, 0x69, 0x6d,
+    0x69, 0x74, 0x73, 0x20, 0x6c, 0x69, 0x61, 0x62, 0x2e, 0x29, 0x2f, 0x28,
+    0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x45, 0x6e, 0x74, 0x72,
+    0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x4c, 0x69, 0x6d, 0x69,
+    0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63,
+    0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73,
+    0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65,
+    0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74,
+    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
+    0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x45, 0x6e,
+    0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x4f, 0x55,
+    0x3d, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74,
+    0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, 0x53, 0x20, 0x69, 0x6e, 0x63,
+    0x6f, 0x72, 0x70, 0x2e, 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, 0x66, 0x2e,
+    0x20, 0x28, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x20, 0x6c, 0x69, 0x61,
+    0x62, 0x2e, 0x29, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x39,
+    0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74,
+    0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x4c,
+    0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, 0x6e, 0x74, 0x72, 0x75,
+    0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72,
+    0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x22,
+    0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x39,
+    0x32, 0x37, 0x36, 0x35, 0x30, 0x33, 0x37, 0x31, 0x0a, 0x23, 0x20, 0x4d,
+    0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x64, 0x66, 0x3a, 0x66, 0x32, 0x3a, 0x38, 0x30,
+    0x3a, 0x37, 0x33, 0x3a, 0x63, 0x63, 0x3a, 0x66, 0x31, 0x3a, 0x65, 0x36,
+    0x3a, 0x36, 0x31, 0x3a, 0x37, 0x33, 0x3a, 0x66, 0x63, 0x3a, 0x66, 0x35,
+    0x3a, 0x34, 0x32, 0x3a, 0x65, 0x39, 0x3a, 0x63, 0x35, 0x3a, 0x37, 0x63,
+    0x3a, 0x65, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x39, 0x39, 0x3a, 0x61, 0x36, 0x3a, 0x39, 0x62, 0x3a, 0x65, 0x36, 0x3a,
+    0x31, 0x61, 0x3a, 0x66, 0x65, 0x3a, 0x38, 0x38, 0x3a, 0x36, 0x62, 0x3a,
+    0x34, 0x64, 0x3a, 0x32, 0x62, 0x3a, 0x38, 0x32, 0x3a, 0x30, 0x30, 0x3a,
+    0x37, 0x63, 0x3a, 0x62, 0x38, 0x3a, 0x35, 0x34, 0x3a, 0x66, 0x63, 0x3a,
+    0x33, 0x31, 0x3a, 0x37, 0x65, 0x3a, 0x31, 0x35, 0x3a, 0x33, 0x39, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x32,
+    0x3a, 0x66, 0x32, 0x3a, 0x34, 0x30, 0x3a, 0x32, 0x37, 0x3a, 0x38, 0x63,
+    0x3a, 0x35, 0x36, 0x3a, 0x34, 0x63, 0x3a, 0x34, 0x64, 0x3a, 0x64, 0x38,
+    0x3a, 0x62, 0x66, 0x3a, 0x37, 0x64, 0x3a, 0x39, 0x64, 0x3a, 0x34, 0x66,
+    0x3a, 0x36, 0x66, 0x3a, 0x33, 0x36, 0x3a, 0x36, 0x65, 0x3a, 0x61, 0x38,
+    0x3a, 0x39, 0x34, 0x3a, 0x64, 0x32, 0x3a, 0x32, 0x66, 0x3a, 0x35, 0x66,
+    0x3a, 0x33, 0x34, 0x3a, 0x64, 0x39, 0x3a, 0x38, 0x39, 0x3a, 0x61, 0x39,
+    0x3a, 0x38, 0x33, 0x3a, 0x61, 0x63, 0x3a, 0x65, 0x63, 0x3a, 0x32, 0x66,
+    0x3a, 0x66, 0x66, 0x3a, 0x65, 0x64, 0x3a, 0x35, 0x30, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52,
+    0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x32, 0x44, 0x43, 0x43, 0x42, 0x45,
+    0x47, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x45, 0x4e, 0x30,
+    0x72, 0x53, 0x51, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b,
+    0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44,
+    0x43, 0x42, 0x77, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x0a, 0x56, 0x56, 0x4d, 0x78, 0x46,
+    0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x43,
+    0x30, 0x56, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x75, 0x62,
+    0x6d, 0x56, 0x30, 0x4d, 0x54, 0x73, 0x77, 0x4f, 0x51, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x4c, 0x45, 0x7a, 0x4a, 0x33, 0x64, 0x33, 0x63, 0x75, 0x5a,
+    0x57, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x35, 0x75, 0x0a,
+    0x5a, 0x58, 0x51, 0x76, 0x51, 0x31, 0x42, 0x54, 0x49, 0x47, 0x6c, 0x75,
+    0x59, 0x32, 0x39, 0x79, 0x63, 0x43, 0x34, 0x67, 0x59, 0x6e, 0x6b, 0x67,
+    0x63, 0x6d, 0x56, 0x6d, 0x4c, 0x69, 0x41, 0x6f, 0x62, 0x47, 0x6c, 0x74,
+    0x61, 0x58, 0x52, 0x7a, 0x49, 0x47, 0x78, 0x70, 0x59, 0x57, 0x49, 0x75,
+    0x4b, 0x54, 0x45, 0x6c, 0x4d, 0x43, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x43, 0x78, 0x4d, 0x63, 0x0a, 0x4b, 0x47, 0x4d, 0x70, 0x49, 0x44, 0x45,
+    0x35, 0x4f, 0x54, 0x6b, 0x67, 0x52, 0x57, 0x35, 0x30, 0x63, 0x6e, 0x56,
+    0x7a, 0x64, 0x43, 0x35, 0x75, 0x5a, 0x58, 0x51, 0x67, 0x54, 0x47, 0x6c,
+    0x74, 0x61, 0x58, 0x52, 0x6c, 0x5a, 0x44, 0x45, 0x36, 0x4d, 0x44, 0x67,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x78, 0x52, 0x57, 0x35,
+    0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x35, 0x75, 0x0a, 0x5a, 0x58,
+    0x51, 0x67, 0x55, 0x32, 0x56, 0x6a, 0x64, 0x58, 0x4a, 0x6c, 0x49, 0x46,
+    0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x6c, 0x63, 0x69, 0x42, 0x44, 0x5a, 0x58,
+    0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57,
+    0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d,
+    0x6c, 0x30, 0x65, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, 0x35, 0x4f, 0x54,
+    0x41, 0x31, 0x0a, 0x4d, 0x6a, 0x55, 0x78, 0x4e, 0x6a, 0x41, 0x35, 0x4e,
+    0x44, 0x42, 0x61, 0x46, 0x77, 0x30, 0x78, 0x4f, 0x54, 0x41, 0x31, 0x4d,
+    0x6a, 0x55, 0x78, 0x4e, 0x6a, 0x4d, 0x35, 0x4e, 0x44, 0x42, 0x61, 0x4d,
+    0x49, 0x48, 0x44, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x55, 0x4d,
+    0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x43, 0x68, 0x4d, 0x4c,
+    0x52, 0x57, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x35, 0x75,
+    0x5a, 0x58, 0x51, 0x78, 0x4f, 0x7a, 0x41, 0x35, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x73, 0x54, 0x4d, 0x6e, 0x64, 0x33, 0x64, 0x79, 0x35, 0x6c,
+    0x62, 0x6e, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4c, 0x6d, 0x35, 0x6c,
+    0x64, 0x43, 0x39, 0x44, 0x55, 0x46, 0x4d, 0x67, 0x61, 0x57, 0x35, 0x6a,
+    0x0a, 0x62, 0x33, 0x4a, 0x77, 0x4c, 0x69, 0x42, 0x69, 0x65, 0x53, 0x42,
+    0x79, 0x5a, 0x57, 0x59, 0x75, 0x49, 0x43, 0x68, 0x73, 0x61, 0x57, 0x31,
+    0x70, 0x64, 0x48, 0x4d, 0x67, 0x62, 0x47, 0x6c, 0x68, 0x59, 0x69, 0x34,
+    0x70, 0x4d, 0x53, 0x55, 0x77, 0x49, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x4c, 0x45, 0x78, 0x77, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x54, 0x6b,
+    0x35, 0x4f, 0x53, 0x42, 0x46, 0x0a, 0x62, 0x6e, 0x52, 0x79, 0x64, 0x58,
+    0x4e, 0x30, 0x4c, 0x6d, 0x35, 0x6c, 0x64, 0x43, 0x42, 0x4d, 0x61, 0x57,
+    0x31, 0x70, 0x64, 0x47, 0x56, 0x6b, 0x4d, 0x54, 0x6f, 0x77, 0x4f, 0x41,
+    0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x7a, 0x46, 0x46, 0x62, 0x6e,
+    0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4c, 0x6d, 0x35, 0x6c, 0x64, 0x43,
+    0x42, 0x54, 0x5a, 0x57, 0x4e, 0x31, 0x63, 0x6d, 0x55, 0x67, 0x0a, 0x55,
+    0x32, 0x56, 0x79, 0x64, 0x6d, 0x56, 0x79, 0x49, 0x45, 0x4e, 0x6c, 0x63,
+    0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62,
+    0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61,
+    0x58, 0x52, 0x35, 0x4d, 0x49, 0x47, 0x64, 0x4d, 0x41, 0x30, 0x47, 0x43,
+    0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41,
+    0x51, 0x55, 0x41, 0x0a, 0x41, 0x34, 0x47, 0x4c, 0x41, 0x44, 0x43, 0x42,
+    0x68, 0x77, 0x4b, 0x42, 0x67, 0x51, 0x44, 0x4e, 0x4b, 0x49, 0x4d, 0x30,
+    0x56, 0x42, 0x75, 0x4a, 0x38, 0x77, 0x2b, 0x76, 0x4e, 0x35, 0x45, 0x78,
+    0x2f, 0x36, 0x38, 0x78, 0x59, 0x4d, 0x6d, 0x6f, 0x36, 0x4c, 0x49, 0x51,
+    0x61, 0x4f, 0x32, 0x66, 0x35, 0x35, 0x4d, 0x32, 0x38, 0x51, 0x70, 0x6b,
+    0x75, 0x30, 0x66, 0x31, 0x42, 0x42, 0x63, 0x2f, 0x0a, 0x49, 0x30, 0x64,
+    0x4e, 0x78, 0x53, 0x63, 0x5a, 0x67, 0x53, 0x59, 0x4d, 0x56, 0x48, 0x49,
+    0x4e, 0x69, 0x43, 0x33, 0x5a, 0x48, 0x35, 0x6f, 0x53, 0x6e, 0x37, 0x79,
+    0x7a, 0x63, 0x64, 0x4f, 0x41, 0x47, 0x54, 0x39, 0x48, 0x5a, 0x6e, 0x75,
+    0x4d, 0x4e, 0x53, 0x6a, 0x53, 0x75, 0x51, 0x72, 0x66, 0x4a, 0x4e, 0x71,
+    0x63, 0x31, 0x6c, 0x42, 0x35, 0x67, 0x58, 0x70, 0x61, 0x30, 0x7a, 0x66,
+    0x33, 0x0a, 0x77, 0x6b, 0x72, 0x59, 0x4b, 0x5a, 0x49, 0x6d, 0x5a, 0x4e,
+    0x48, 0x6b, 0x6d, 0x47, 0x77, 0x36, 0x41, 0x49, 0x72, 0x31, 0x4e, 0x4a,
+    0x74, 0x6c, 0x2b, 0x4f, 0x33, 0x6a, 0x45, 0x50, 0x2f, 0x39, 0x75, 0x45,
+    0x6c, 0x59, 0x33, 0x4b, 0x44, 0x65, 0x67, 0x6a, 0x6c, 0x72, 0x67, 0x62,
+    0x45, 0x57, 0x47, 0x57, 0x47, 0x35, 0x56, 0x4c, 0x62, 0x6d, 0x51, 0x77,
+    0x49, 0x42, 0x41, 0x36, 0x4f, 0x43, 0x0a, 0x41, 0x64, 0x63, 0x77, 0x67,
+    0x67, 0x48, 0x54, 0x4d, 0x42, 0x45, 0x47, 0x43, 0x57, 0x43, 0x47, 0x53,
+    0x41, 0x47, 0x47, 0x2b, 0x45, 0x49, 0x42, 0x41, 0x51, 0x51, 0x45, 0x41,
+    0x77, 0x49, 0x41, 0x42, 0x7a, 0x43, 0x43, 0x41, 0x52, 0x6b, 0x47, 0x41,
+    0x31, 0x55, 0x64, 0x48, 0x77, 0x53, 0x43, 0x41, 0x52, 0x41, 0x77, 0x67,
+    0x67, 0x45, 0x4d, 0x4d, 0x49, 0x48, 0x65, 0x6f, 0x49, 0x48, 0x62, 0x0a,
+    0x6f, 0x49, 0x48, 0x59, 0x70, 0x49, 0x48, 0x56, 0x4d, 0x49, 0x48, 0x53,
+    0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47,
+    0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4c, 0x52, 0x57, 0x35, 0x30,
+    0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x35, 0x75, 0x5a, 0x58, 0x51, 0x78,
+    0x4f, 0x7a, 0x41, 0x35, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73,
+    0x54, 0x4d, 0x6e, 0x64, 0x33, 0x64, 0x79, 0x35, 0x6c, 0x62, 0x6e, 0x52,
+    0x79, 0x64, 0x58, 0x4e, 0x30, 0x4c, 0x6d, 0x35, 0x6c, 0x64, 0x43, 0x39,
+    0x44, 0x55, 0x46, 0x4d, 0x67, 0x61, 0x57, 0x35, 0x6a, 0x62, 0x33, 0x4a,
+    0x77, 0x4c, 0x69, 0x42, 0x69, 0x65, 0x53, 0x42, 0x79, 0x5a, 0x57, 0x59,
+    0x75, 0x49, 0x43, 0x68, 0x73, 0x61, 0x57, 0x31, 0x70, 0x0a, 0x64, 0x48,
+    0x4d, 0x67, 0x62, 0x47, 0x6c, 0x68, 0x59, 0x69, 0x34, 0x70, 0x4d, 0x53,
+    0x55, 0x77, 0x49, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78,
+    0x77, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x54, 0x6b, 0x35, 0x4f, 0x53,
+    0x42, 0x46, 0x62, 0x6e, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4c, 0x6d,
+    0x35, 0x6c, 0x64, 0x43, 0x42, 0x4d, 0x61, 0x57, 0x31, 0x70, 0x64, 0x47,
+    0x56, 0x6b, 0x0a, 0x4d, 0x54, 0x6f, 0x77, 0x4f, 0x41, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x44, 0x45, 0x7a, 0x46, 0x46, 0x62, 0x6e, 0x52, 0x79, 0x64,
+    0x58, 0x4e, 0x30, 0x4c, 0x6d, 0x35, 0x6c, 0x64, 0x43, 0x42, 0x54, 0x5a,
+    0x57, 0x4e, 0x31, 0x63, 0x6d, 0x55, 0x67, 0x55, 0x32, 0x56, 0x79, 0x64,
+    0x6d, 0x56, 0x79, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a,
+    0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x0a, 0x62, 0x32, 0x34, 0x67,
+    0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35,
+    0x4d, 0x51, 0x30, 0x77, 0x43, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44,
+    0x45, 0x77, 0x52, 0x44, 0x55, 0x6b, 0x77, 0x78, 0x4d, 0x43, 0x6d, 0x67,
+    0x4a, 0x36, 0x41, 0x6c, 0x68, 0x69, 0x4e, 0x6f, 0x64, 0x48, 0x52, 0x77,
+    0x4f, 0x69, 0x38, 0x76, 0x64, 0x33, 0x64, 0x33, 0x4c, 0x6d, 0x56, 0x75,
+    0x0a, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x75, 0x62, 0x6d, 0x56,
+    0x30, 0x4c, 0x30, 0x4e, 0x53, 0x54, 0x43, 0x39, 0x75, 0x5a, 0x58, 0x51,
+    0x78, 0x4c, 0x6d, 0x4e, 0x79, 0x62, 0x44, 0x41, 0x72, 0x42, 0x67, 0x4e,
+    0x56, 0x48, 0x52, 0x41, 0x45, 0x4a, 0x44, 0x41, 0x69, 0x67, 0x41, 0x38,
+    0x78, 0x4f, 0x54, 0x6b, 0x35, 0x4d, 0x44, 0x55, 0x79, 0x4e, 0x54, 0x45,
+    0x32, 0x4d, 0x44, 0x6b, 0x30, 0x0a, 0x4d, 0x46, 0x71, 0x42, 0x44, 0x7a,
+    0x49, 0x77, 0x4d, 0x54, 0x6b, 0x77, 0x4e, 0x54, 0x49, 0x31, 0x4d, 0x54,
+    0x59, 0x77, 0x4f, 0x54, 0x51, 0x77, 0x57, 0x6a, 0x41, 0x4c, 0x42, 0x67,
+    0x4e, 0x56, 0x48, 0x51, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51,
+    0x59, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6a, 0x42, 0x42,
+    0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x38, 0x42, 0x64, 0x69, 0x0a, 0x45,
+    0x31, 0x55, 0x39, 0x73, 0x2f, 0x38, 0x4b, 0x41, 0x47, 0x76, 0x37, 0x55,
+    0x49, 0x53, 0x58, 0x38, 0x2b, 0x31, 0x69, 0x30, 0x42, 0x6f, 0x77, 0x48,
+    0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46,
+    0x50, 0x41, 0x58, 0x59, 0x68, 0x4e, 0x56, 0x50, 0x62, 0x50, 0x2f, 0x43,
+    0x67, 0x42, 0x72, 0x2b, 0x31, 0x43, 0x45, 0x6c, 0x2f, 0x50, 0x74, 0x59,
+    0x74, 0x41, 0x61, 0x0a, 0x4d, 0x41, 0x77, 0x47, 0x41, 0x31, 0x55, 0x64,
+    0x45, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77,
+    0x47, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x5a, 0x39,
+    0x42, 0x30, 0x45, 0x41, 0x42, 0x41, 0x77, 0x77, 0x43, 0x68, 0x73, 0x45,
+    0x56, 0x6a, 0x51, 0x75, 0x4d, 0x41, 0x4d, 0x43, 0x42, 0x4a, 0x41, 0x77,
+    0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x0a, 0x68, 0x76, 0x63,
+    0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x59, 0x45,
+    0x41, 0x6b, 0x4e, 0x77, 0x77, 0x41, 0x76, 0x70, 0x6b, 0x64, 0x4d, 0x4b,
+    0x6e, 0x43, 0x71, 0x56, 0x38, 0x49, 0x59, 0x30, 0x30, 0x46, 0x36, 0x6a,
+    0x37, 0x52, 0x77, 0x37, 0x2f, 0x4a, 0x58, 0x79, 0x4e, 0x45, 0x77, 0x72,
+    0x37, 0x35, 0x4a, 0x69, 0x31, 0x37, 0x34, 0x7a, 0x34, 0x78, 0x52, 0x41,
+    0x4e, 0x0a, 0x39, 0x35, 0x4b, 0x2b, 0x38, 0x63, 0x50, 0x56, 0x31, 0x5a,
+    0x56, 0x71, 0x42, 0x4c, 0x73, 0x73, 0x7a, 0x69, 0x59, 0x32, 0x5a, 0x63,
+    0x67, 0x78, 0x78, 0x75, 0x66, 0x75, 0x50, 0x2b, 0x4e, 0x58, 0x64, 0x59,
+    0x52, 0x36, 0x45, 0x65, 0x39, 0x47, 0x54, 0x78, 0x6a, 0x30, 0x30, 0x35,
+    0x69, 0x37, 0x71, 0x49, 0x63, 0x79, 0x75, 0x6e, 0x4c, 0x32, 0x50, 0x4f,
+    0x49, 0x39, 0x6e, 0x39, 0x63, 0x64, 0x0a, 0x32, 0x63, 0x4e, 0x67, 0x51,
+    0x34, 0x78, 0x59, 0x44, 0x69, 0x4b, 0x57, 0x4c, 0x32, 0x4b, 0x6a, 0x4c,
+    0x42, 0x2b, 0x36, 0x72, 0x51, 0x58, 0x76, 0x71, 0x7a, 0x4a, 0x34, 0x68,
+    0x36, 0x42, 0x55, 0x63, 0x78, 0x6d, 0x31, 0x58, 0x41, 0x58, 0x35, 0x55,
+    0x6a, 0x35, 0x74, 0x4c, 0x55, 0x55, 0x4c, 0x39, 0x77, 0x71, 0x54, 0x36,
+    0x75, 0x30, 0x47, 0x2b, 0x62, 0x49, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23,
+    0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d,
+    0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20,
+    0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+    0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20,
+    0x28, 0x32, 0x30, 0x34, 0x38, 0x29, 0x20, 0x4f, 0x3d, 0x45, 0x6e, 0x74,
+    0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x4f, 0x55, 0x3d,
+    0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e,
+    0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, 0x53, 0x5f, 0x32, 0x30, 0x34, 0x38,
+    0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x20, 0x62, 0x79, 0x20,
+    0x72, 0x65, 0x66, 0x2e, 0x20, 0x28, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73,
+    0x20, 0x6c, 0x69, 0x61, 0x62, 0x2e, 0x29, 0x2f, 0x28, 0x63, 0x29, 0x20,
+    0x31, 0x39, 0x39, 0x39, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74,
+    0x2e, 0x6e, 0x65, 0x74, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64,
+    0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20,
+    0x43, 0x4e, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e,
+    0x65, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+    0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+    0x74, 0x79, 0x20, 0x28, 0x32, 0x30, 0x34, 0x38, 0x29, 0x20, 0x4f, 0x3d,
+    0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20,
+    0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75,
+    0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, 0x53, 0x5f, 0x32,
+    0x30, 0x34, 0x38, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x20,
+    0x62, 0x79, 0x20, 0x72, 0x65, 0x66, 0x2e, 0x20, 0x28, 0x6c, 0x69, 0x6d,
+    0x69, 0x74, 0x73, 0x20, 0x6c, 0x69, 0x61, 0x62, 0x2e, 0x29, 0x2f, 0x28,
+    0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x45, 0x6e, 0x74, 0x72,
+    0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x4c, 0x69, 0x6d, 0x69,
+    0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a,
+    0x20, 0x22, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65,
+    0x74, 0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x32, 0x30,
+    0x34, 0x38, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65,
+    0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53,
+    0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x39, 0x34, 0x36, 0x30, 0x35,
+    0x39, 0x36, 0x32, 0x32, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x62, 0x61, 0x3a, 0x32, 0x31, 0x3a, 0x65, 0x61, 0x3a, 0x32, 0x30, 0x3a,
+    0x64, 0x36, 0x3a, 0x64, 0x64, 0x3a, 0x64, 0x62, 0x3a, 0x38, 0x66, 0x3a,
+    0x63, 0x31, 0x3a, 0x35, 0x37, 0x3a, 0x38, 0x62, 0x3a, 0x34, 0x30, 0x3a,
+    0x61, 0x64, 0x3a, 0x61, 0x31, 0x3a, 0x66, 0x63, 0x3a, 0x66, 0x63, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x30, 0x3a, 0x31,
+    0x64, 0x3a, 0x36, 0x32, 0x3a, 0x64, 0x30, 0x3a, 0x37, 0x62, 0x3a, 0x34,
+    0x34, 0x3a, 0x39, 0x64, 0x3a, 0x35, 0x63, 0x3a, 0x35, 0x63, 0x3a, 0x30,
+    0x33, 0x3a, 0x35, 0x63, 0x3a, 0x39, 0x38, 0x3a, 0x65, 0x61, 0x3a, 0x36,
+    0x31, 0x3a, 0x66, 0x61, 0x3a, 0x34, 0x34, 0x3a, 0x33, 0x63, 0x3a, 0x32,
+    0x61, 0x3a, 0x35, 0x38, 0x3a, 0x66, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48,
+    0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x31, 0x3a, 0x63, 0x33, 0x3a,
+    0x33, 0x39, 0x3a, 0x65, 0x61, 0x3a, 0x32, 0x37, 0x3a, 0x38, 0x34, 0x3a,
+    0x65, 0x62, 0x3a, 0x38, 0x37, 0x3a, 0x30, 0x66, 0x3a, 0x39, 0x33, 0x3a,
+    0x34, 0x66, 0x3a, 0x63, 0x35, 0x3a, 0x36, 0x33, 0x3a, 0x34, 0x65, 0x3a,
+    0x34, 0x61, 0x3a, 0x61, 0x39, 0x3a, 0x61, 0x64, 0x3a, 0x35, 0x35, 0x3a,
+    0x30, 0x35, 0x3a, 0x30, 0x31, 0x3a, 0x36, 0x34, 0x3a, 0x30, 0x31, 0x3a,
+    0x66, 0x32, 0x3a, 0x36, 0x34, 0x3a, 0x36, 0x35, 0x3a, 0x64, 0x33, 0x3a,
+    0x37, 0x61, 0x3a, 0x35, 0x37, 0x3a, 0x34, 0x36, 0x3a, 0x36, 0x33, 0x3a,
+    0x33, 0x35, 0x3a, 0x39, 0x66, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42,
+    0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49,
+    0x49, 0x45, 0x58, 0x44, 0x43, 0x43, 0x41, 0x30, 0x53, 0x67, 0x41, 0x77,
+    0x49, 0x42, 0x41, 0x67, 0x49, 0x45, 0x4f, 0x47, 0x4f, 0x35, 0x5a, 0x6a,
+    0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77,
+    0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x43, 0x42, 0x74, 0x44,
+    0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68,
+    0x4d, 0x4c, 0x0a, 0x52, 0x57, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64,
+    0x43, 0x35, 0x75, 0x5a, 0x58, 0x51, 0x78, 0x51, 0x44, 0x41, 0x2b, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x55, 0x4e, 0x33, 0x64, 0x33, 0x64,
+    0x79, 0x35, 0x6c, 0x62, 0x6e, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4c,
+    0x6d, 0x35, 0x6c, 0x64, 0x43, 0x39, 0x44, 0x55, 0x46, 0x4e, 0x66, 0x4d,
+    0x6a, 0x41, 0x30, 0x4f, 0x43, 0x42, 0x70, 0x0a, 0x62, 0x6d, 0x4e, 0x76,
+    0x63, 0x6e, 0x41, 0x75, 0x49, 0x47, 0x4a, 0x35, 0x49, 0x48, 0x4a, 0x6c,
+    0x5a, 0x69, 0x34, 0x67, 0x4b, 0x47, 0x78, 0x70, 0x62, 0x57, 0x6c, 0x30,
+    0x63, 0x79, 0x42, 0x73, 0x61, 0x57, 0x46, 0x69, 0x4c, 0x69, 0x6b, 0x78,
+    0x4a, 0x54, 0x41, 0x6a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54,
+    0x48, 0x43, 0x68, 0x6a, 0x4b, 0x53, 0x41, 0x78, 0x4f, 0x54, 0x6b, 0x35,
+    0x0a, 0x49, 0x45, 0x56, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51,
+    0x75, 0x62, 0x6d, 0x56, 0x30, 0x49, 0x45, 0x78, 0x70, 0x62, 0x57, 0x6c,
+    0x30, 0x5a, 0x57, 0x51, 0x78, 0x4d, 0x7a, 0x41, 0x78, 0x42, 0x67, 0x4e,
+    0x56, 0x42, 0x41, 0x4d, 0x54, 0x4b, 0x6b, 0x56, 0x75, 0x64, 0x48, 0x4a,
+    0x31, 0x63, 0x33, 0x51, 0x75, 0x62, 0x6d, 0x56, 0x30, 0x49, 0x45, 0x4e,
+    0x6c, 0x63, 0x6e, 0x52, 0x70, 0x0a, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58,
+    0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47,
+    0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x49, 0x43, 0x67, 0x79, 0x4d, 0x44,
+    0x51, 0x34, 0x4b, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, 0x35, 0x4f, 0x54,
+    0x45, 0x79, 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x7a, 0x55, 0x77, 0x4e, 0x54,
+    0x46, 0x61, 0x46, 0x77, 0x30, 0x78, 0x4f, 0x54, 0x45, 0x79, 0x0a, 0x4d,
+    0x6a, 0x51, 0x78, 0x4f, 0x44, 0x49, 0x77, 0x4e, 0x54, 0x46, 0x61, 0x4d,
+    0x49, 0x47, 0x30, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x4b, 0x45, 0x77, 0x74, 0x46, 0x62, 0x6e, 0x52, 0x79, 0x64,
+    0x58, 0x4e, 0x30, 0x4c, 0x6d, 0x35, 0x6c, 0x64, 0x44, 0x46, 0x41, 0x4d,
+    0x44, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x51, 0x33, 0x64,
+    0x33, 0x64, 0x33, 0x0a, 0x4c, 0x6d, 0x56, 0x75, 0x64, 0x48, 0x4a, 0x31,
+    0x63, 0x33, 0x51, 0x75, 0x62, 0x6d, 0x56, 0x30, 0x4c, 0x30, 0x4e, 0x51,
+    0x55, 0x31, 0x38, 0x79, 0x4d, 0x44, 0x51, 0x34, 0x49, 0x47, 0x6c, 0x75,
+    0x59, 0x32, 0x39, 0x79, 0x63, 0x43, 0x34, 0x67, 0x59, 0x6e, 0x6b, 0x67,
+    0x63, 0x6d, 0x56, 0x6d, 0x4c, 0x69, 0x41, 0x6f, 0x62, 0x47, 0x6c, 0x74,
+    0x61, 0x58, 0x52, 0x7a, 0x49, 0x47, 0x78, 0x70, 0x0a, 0x59, 0x57, 0x49,
+    0x75, 0x4b, 0x54, 0x45, 0x6c, 0x4d, 0x43, 0x4d, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x43, 0x78, 0x4d, 0x63, 0x4b, 0x47, 0x4d, 0x70, 0x49, 0x44, 0x45,
+    0x35, 0x4f, 0x54, 0x6b, 0x67, 0x52, 0x57, 0x35, 0x30, 0x63, 0x6e, 0x56,
+    0x7a, 0x64, 0x43, 0x35, 0x75, 0x5a, 0x58, 0x51, 0x67, 0x54, 0x47, 0x6c,
+    0x74, 0x61, 0x58, 0x52, 0x6c, 0x5a, 0x44, 0x45, 0x7a, 0x4d, 0x44, 0x45,
+    0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x71, 0x52, 0x57,
+    0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x35, 0x75, 0x5a, 0x58,
+    0x51, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57,
+    0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58,
+    0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x4b, 0x44,
+    0x49, 0x77, 0x4e, 0x44, 0x67, 0x70, 0x0a, 0x4d, 0x49, 0x49, 0x42, 0x49,
+    0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39,
+    0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41,
+    0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41,
+    0x51, 0x45, 0x41, 0x72, 0x55, 0x31, 0x4c, 0x71, 0x52, 0x4b, 0x47, 0x73,
+    0x75, 0x71, 0x6a, 0x49, 0x41, 0x63, 0x56, 0x46, 0x6d, 0x51, 0x71, 0x0a,
+    0x4b, 0x30, 0x76, 0x52, 0x76, 0x77, 0x74, 0x4b, 0x54, 0x59, 0x37, 0x74,
+    0x67, 0x48, 0x61, 0x6c, 0x5a, 0x37, 0x64, 0x34, 0x51, 0x4d, 0x42, 0x7a,
+    0x51, 0x73, 0x68, 0x6f, 0x77, 0x4e, 0x74, 0x54, 0x4b, 0x39, 0x31, 0x65,
+    0x75, 0x48, 0x61, 0x59, 0x4e, 0x5a, 0x4f, 0x4c, 0x47, 0x70, 0x31, 0x38,
+    0x45, 0x7a, 0x6f, 0x4f, 0x48, 0x31, 0x75, 0x33, 0x48, 0x73, 0x2f, 0x6c,
+    0x4a, 0x42, 0x51, 0x65, 0x0a, 0x73, 0x59, 0x47, 0x70, 0x6a, 0x58, 0x32,
+    0x34, 0x7a, 0x47, 0x74, 0x4c, 0x41, 0x2f, 0x45, 0x43, 0x44, 0x4e, 0x79,
+    0x72, 0x70, 0x55, 0x41, 0x6b, 0x41, 0x48, 0x39, 0x30, 0x6c, 0x4b, 0x47,
+    0x64, 0x43, 0x43, 0x6d, 0x7a, 0x69, 0x41, 0x76, 0x31, 0x68, 0x33, 0x65,
+    0x64, 0x56, 0x63, 0x33, 0x6b, 0x77, 0x33, 0x37, 0x58, 0x61, 0x6d, 0x53,
+    0x72, 0x68, 0x52, 0x53, 0x47, 0x6c, 0x56, 0x75, 0x58, 0x0a, 0x4d, 0x6c,
+    0x42, 0x76, 0x50, 0x63, 0x69, 0x36, 0x5a, 0x67, 0x7a, 0x6a, 0x2f, 0x4c,
+    0x32, 0x34, 0x53, 0x63, 0x46, 0x32, 0x69, 0x55, 0x6b, 0x5a, 0x2f, 0x63,
+    0x43, 0x6f, 0x76, 0x59, 0x6d, 0x6a, 0x5a, 0x79, 0x2f, 0x47, 0x6e, 0x37,
+    0x78, 0x78, 0x47, 0x57, 0x43, 0x34, 0x4c, 0x65, 0x6b, 0x73, 0x79, 0x5a,
+    0x42, 0x32, 0x5a, 0x6e, 0x75, 0x55, 0x34, 0x71, 0x39, 0x34, 0x31, 0x6d,
+    0x56, 0x54, 0x0a, 0x58, 0x54, 0x7a, 0x57, 0x6e, 0x4c, 0x4c, 0x50, 0x4b,
+    0x51, 0x50, 0x35, 0x4c, 0x36, 0x52, 0x51, 0x73, 0x74, 0x52, 0x49, 0x7a,
+    0x67, 0x55, 0x79, 0x56, 0x59, 0x72, 0x39, 0x73, 0x6d, 0x52, 0x4d, 0x44,
+    0x75, 0x53, 0x59, 0x42, 0x33, 0x58, 0x62, 0x66, 0x39, 0x2b, 0x35, 0x43,
+    0x46, 0x56, 0x67, 0x68, 0x54, 0x41, 0x70, 0x2b, 0x58, 0x74, 0x49, 0x70,
+    0x47, 0x6d, 0x47, 0x34, 0x7a, 0x55, 0x2f, 0x0a, 0x48, 0x6f, 0x5a, 0x64,
+    0x65, 0x6e, 0x6f, 0x56, 0x76, 0x65, 0x38, 0x41, 0x6a, 0x68, 0x55, 0x69,
+    0x56, 0x42, 0x63, 0x41, 0x6b, 0x43, 0x61, 0x54, 0x76, 0x41, 0x35, 0x4a,
+    0x61, 0x4a, 0x47, 0x2f, 0x2b, 0x45, 0x66, 0x54, 0x6e, 0x5a, 0x56, 0x43,
+    0x77, 0x51, 0x35, 0x4e, 0x33, 0x32, 0x38, 0x6d, 0x7a, 0x38, 0x4d, 0x59,
+    0x49, 0x57, 0x4a, 0x6d, 0x51, 0x33, 0x44, 0x57, 0x31, 0x63, 0x41, 0x48,
+    0x0a, 0x34, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x33, 0x51,
+    0x77, 0x63, 0x6a, 0x41, 0x52, 0x42, 0x67, 0x6c, 0x67, 0x68, 0x6b, 0x67,
+    0x42, 0x68, 0x76, 0x68, 0x43, 0x41, 0x51, 0x45, 0x45, 0x42, 0x41, 0x4d,
+    0x43, 0x41, 0x41, 0x63, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30,
+    0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x56, 0x65, 0x53,
+    0x42, 0x30, 0x52, 0x47, 0x41, 0x0a, 0x76, 0x74, 0x69, 0x4a, 0x75, 0x51,
+    0x69, 0x6a, 0x4d, 0x66, 0x6d, 0x68, 0x4a, 0x41, 0x6b, 0x57, 0x75, 0x58,
+    0x41, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42,
+    0x59, 0x45, 0x46, 0x46, 0x58, 0x6b, 0x67, 0x64, 0x45, 0x52, 0x67, 0x4c,
+    0x37, 0x59, 0x69, 0x62, 0x6b, 0x49, 0x6f, 0x7a, 0x48, 0x35, 0x6f, 0x53,
+    0x51, 0x4a, 0x46, 0x72, 0x6c, 0x77, 0x4d, 0x42, 0x30, 0x47, 0x0a, 0x43,
+    0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x32, 0x66, 0x51, 0x64, 0x42, 0x41,
+    0x41, 0x51, 0x51, 0x4d, 0x41, 0x34, 0x62, 0x43, 0x46, 0x59, 0x31, 0x4c,
+    0x6a, 0x41, 0x36, 0x4e, 0x43, 0x34, 0x77, 0x41, 0x77, 0x49, 0x45, 0x6b,
+    0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39,
+    0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41,
+    0x51, 0x45, 0x41, 0x0a, 0x57, 0x55, 0x65, 0x73, 0x49, 0x59, 0x53, 0x4b,
+    0x46, 0x38, 0x6d, 0x63, 0x69, 0x56, 0x4d, 0x65, 0x75, 0x6f, 0x43, 0x46,
+    0x47, 0x73, 0x59, 0x38, 0x54, 0x6a, 0x36, 0x78, 0x6e, 0x4c, 0x5a, 0x38,
+    0x78, 0x70, 0x4a, 0x64, 0x47, 0x47, 0x51, 0x43, 0x34, 0x39, 0x4d, 0x47,
+    0x43, 0x42, 0x46, 0x68, 0x66, 0x47, 0x50, 0x6a, 0x4b, 0x35, 0x30, 0x78,
+    0x41, 0x33, 0x42, 0x32, 0x30, 0x71, 0x4d, 0x6f, 0x0a, 0x6f, 0x50, 0x53,
+    0x37, 0x6d, 0x6d, 0x4e, 0x7a, 0x37, 0x57, 0x33, 0x6c, 0x4b, 0x74, 0x76,
+    0x74, 0x46, 0x4b, 0x6b, 0x72, 0x78, 0x6a, 0x59, 0x52, 0x30, 0x43, 0x76,
+    0x72, 0x42, 0x34, 0x75, 0x6c, 0x32, 0x70, 0x35, 0x63, 0x47, 0x5a, 0x31,
+    0x57, 0x45, 0x76, 0x56, 0x55, 0x4b, 0x63, 0x67, 0x46, 0x37, 0x62, 0x49,
+    0x53, 0x4b, 0x6f, 0x33, 0x30, 0x41, 0x78, 0x76, 0x2f, 0x35, 0x35, 0x49,
+    0x51, 0x0a, 0x68, 0x37, 0x41, 0x36, 0x74, 0x63, 0x4f, 0x64, 0x42, 0x54,
+    0x63, 0x53, 0x6f, 0x38, 0x66, 0x30, 0x46, 0x62, 0x6e, 0x56, 0x70, 0x44,
+    0x6b, 0x57, 0x6d, 0x31, 0x4d, 0x36, 0x49, 0x35, 0x48, 0x78, 0x71, 0x49,
+    0x4b, 0x69, 0x61, 0x6f, 0x68, 0x6f, 0x77, 0x58, 0x6b, 0x43, 0x49, 0x72,
+    0x79, 0x71, 0x70, 0x74, 0x61, 0x75, 0x33, 0x37, 0x41, 0x55, 0x58, 0x37,
+    0x69, 0x48, 0x30, 0x4e, 0x31, 0x38, 0x0a, 0x66, 0x33, 0x76, 0x2f, 0x72,
+    0x78, 0x7a, 0x50, 0x35, 0x74, 0x73, 0x48, 0x72, 0x56, 0x37, 0x62, 0x68,
+    0x5a, 0x33, 0x51, 0x4b, 0x77, 0x30, 0x7a, 0x32, 0x77, 0x54, 0x52, 0x35,
+    0x6b, 0x6c, 0x41, 0x45, 0x79, 0x74, 0x32, 0x2b, 0x7a, 0x37, 0x70, 0x6e,
+    0x49, 0x6b, 0x50, 0x46, 0x63, 0x34, 0x59, 0x73, 0x49, 0x56, 0x34, 0x49,
+    0x55, 0x39, 0x72, 0x54, 0x77, 0x37, 0x36, 0x4e, 0x6d, 0x66, 0x4e, 0x0a,
+    0x42, 0x2f, 0x4c, 0x2f, 0x43, 0x4e, 0x44, 0x69, 0x33, 0x74, 0x6d, 0x2f,
+    0x4b, 0x71, 0x2b, 0x34, 0x68, 0x34, 0x59, 0x68, 0x50, 0x41, 0x54, 0x4b,
+    0x74, 0x35, 0x52, 0x6f, 0x66, 0x38, 0x38, 0x38, 0x36, 0x5a, 0x6a, 0x58,
+    0x4f, 0x50, 0x2f, 0x73, 0x77, 0x4e, 0x6c, 0x51, 0x38, 0x43, 0x35, 0x4c,
+    0x57, 0x4b, 0x35, 0x47, 0x62, 0x39, 0x41, 0x75, 0x77, 0x32, 0x44, 0x61,
+    0x63, 0x6c, 0x56, 0x79, 0x0a, 0x76, 0x55, 0x78, 0x46, 0x6e, 0x6d, 0x47,
+    0x36, 0x76, 0x34, 0x53, 0x42, 0x6b, 0x67, 0x50, 0x52, 0x30, 0x6d, 0x6c,
+    0x38, 0x78, 0x51, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45,
+    0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41,
+    0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49,
+    0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x42, 0x61,
+    0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x43, 0x79, 0x62, 0x65,
+    0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+    0x4f, 0x3d, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x20,
+    0x4f, 0x55, 0x3d, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73,
+    0x74, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a,
+    0x20, 0x43, 0x4e, 0x3d, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72,
+    0x65, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74,
+    0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x42, 0x61, 0x6c, 0x74,
+    0x69, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x79, 0x62,
+    0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x4c, 0x61,
+    0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d,
+    0x6f, 0x72, 0x65, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75,
+    0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x0a, 0x23, 0x20, 0x53,
+    0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x33, 0x33, 0x35, 0x35, 0x34,
+    0x36, 0x31, 0x37, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69,
+    0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61,
+    0x63, 0x3a, 0x62, 0x36, 0x3a, 0x39, 0x34, 0x3a, 0x61, 0x35, 0x3a, 0x39,
+    0x63, 0x3a, 0x31, 0x37, 0x3a, 0x65, 0x30, 0x3a, 0x64, 0x37, 0x3a, 0x39,
+    0x31, 0x3a, 0x35, 0x32, 0x3a, 0x39, 0x62, 0x3a, 0x62, 0x31, 0x3a, 0x39,
+    0x37, 0x3a, 0x30, 0x36, 0x3a, 0x61, 0x36, 0x3a, 0x65, 0x34, 0x0a, 0x23,
+    0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x34, 0x3a, 0x64, 0x65,
+    0x3a, 0x32, 0x30, 0x3a, 0x64, 0x30, 0x3a, 0x35, 0x65, 0x3a, 0x36, 0x36,
+    0x3a, 0x66, 0x63, 0x3a, 0x35, 0x33, 0x3a, 0x66, 0x65, 0x3a, 0x31, 0x61,
+    0x3a, 0x35, 0x30, 0x3a, 0x38, 0x38, 0x3a, 0x32, 0x63, 0x3a, 0x37, 0x38,
+    0x3a, 0x64, 0x62, 0x3a, 0x32, 0x38, 0x3a, 0x35, 0x32, 0x3a, 0x63, 0x61,
+    0x3a, 0x65, 0x34, 0x3a, 0x37, 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41,
+    0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x36, 0x3a, 0x61, 0x66, 0x3a, 0x35,
+    0x37, 0x3a, 0x61, 0x39, 0x3a, 0x66, 0x36, 0x3a, 0x37, 0x36, 0x3a, 0x62,
+    0x30, 0x3a, 0x61, 0x62, 0x3a, 0x31, 0x32, 0x3a, 0x36, 0x30, 0x3a, 0x39,
+    0x35, 0x3a, 0x61, 0x61, 0x3a, 0x35, 0x65, 0x3a, 0x62, 0x61, 0x3a, 0x64,
+    0x65, 0x3a, 0x66, 0x32, 0x3a, 0x32, 0x61, 0x3a, 0x62, 0x33, 0x3a, 0x31,
+    0x31, 0x3a, 0x31, 0x39, 0x3a, 0x64, 0x36, 0x3a, 0x34, 0x34, 0x3a, 0x61,
+    0x63, 0x3a, 0x39, 0x35, 0x3a, 0x63, 0x64, 0x3a, 0x34, 0x62, 0x3a, 0x39,
+    0x33, 0x3a, 0x64, 0x62, 0x3a, 0x66, 0x33, 0x3a, 0x66, 0x32, 0x3a, 0x36,
+    0x61, 0x3a, 0x65, 0x62, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45,
+    0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43,
+    0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49,
+    0x44, 0x64, 0x7a, 0x43, 0x43, 0x41, 0x6c, 0x2b, 0x67, 0x41, 0x77, 0x49,
+    0x42, 0x41, 0x67, 0x49, 0x45, 0x41, 0x67, 0x41, 0x41, 0x75, 0x54, 0x41,
+    0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30,
+    0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x61, 0x4d, 0x51, 0x73,
+    0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a,
+    0x4a, 0x0a, 0x52, 0x54, 0x45, 0x53, 0x4d, 0x42, 0x41, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x43, 0x68, 0x4d, 0x4a, 0x51, 0x6d, 0x46, 0x73, 0x64, 0x47,
+    0x6c, 0x74, 0x62, 0x33, 0x4a, 0x6c, 0x4d, 0x52, 0x4d, 0x77, 0x45, 0x51,
+    0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x77, 0x70, 0x44, 0x65, 0x57,
+    0x4a, 0x6c, 0x63, 0x6c, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4d, 0x53,
+    0x49, 0x77, 0x49, 0x41, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, 0x44, 0x45,
+    0x78, 0x6c, 0x43, 0x59, 0x57, 0x78, 0x30, 0x61, 0x57, 0x31, 0x76, 0x63,
+    0x6d, 0x55, 0x67, 0x51, 0x33, 0x6c, 0x69, 0x5a, 0x58, 0x4a, 0x55, 0x63,
+    0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x4d,
+    0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x77, 0x4d, 0x44, 0x55, 0x78, 0x4d,
+    0x6a, 0x45, 0x34, 0x4e, 0x44, 0x59, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x0a,
+    0x44, 0x54, 0x49, 0x31, 0x4d, 0x44, 0x55, 0x78, 0x4d, 0x6a, 0x49, 0x7a,
+    0x4e, 0x54, 0x6b, 0x77, 0x4d, 0x46, 0x6f, 0x77, 0x57, 0x6a, 0x45, 0x4c,
+    0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43,
+    0x53, 0x55, 0x55, 0x78, 0x45, 0x6a, 0x41, 0x51, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x6f, 0x54, 0x43, 0x55, 0x4a, 0x68, 0x62, 0x48, 0x52, 0x70,
+    0x62, 0x57, 0x39, 0x79, 0x0a, 0x5a, 0x54, 0x45, 0x54, 0x4d, 0x42, 0x45,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x4b, 0x51, 0x33, 0x6c,
+    0x69, 0x5a, 0x58, 0x4a, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x44, 0x45,
+    0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d,
+    0x5a, 0x51, 0x6d, 0x46, 0x73, 0x64, 0x47, 0x6c, 0x74, 0x62, 0x33, 0x4a,
+    0x6c, 0x49, 0x45, 0x4e, 0x35, 0x59, 0x6d, 0x56, 0x79, 0x0a, 0x56, 0x48,
+    0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x44,
+    0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f,
+    0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51,
+    0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51,
+    0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4b, 0x4d, 0x45, 0x75, 0x79,
+    0x4b, 0x72, 0x0a, 0x6d, 0x44, 0x31, 0x58, 0x36, 0x43, 0x5a, 0x79, 0x6d,
+    0x72, 0x56, 0x35, 0x31, 0x43, 0x6e, 0x69, 0x34, 0x65, 0x69, 0x56, 0x67,
+    0x4c, 0x47, 0x77, 0x34, 0x31, 0x75, 0x4f, 0x4b, 0x79, 0x6d, 0x61, 0x5a,
+    0x4e, 0x2b, 0x68, 0x58, 0x65, 0x32, 0x77, 0x43, 0x51, 0x56, 0x74, 0x32,
+    0x79, 0x67, 0x75, 0x7a, 0x6d, 0x4b, 0x69, 0x59, 0x76, 0x36, 0x30, 0x69,
+    0x4e, 0x6f, 0x53, 0x36, 0x7a, 0x6a, 0x72, 0x0a, 0x49, 0x5a, 0x33, 0x41,
+    0x51, 0x53, 0x73, 0x42, 0x55, 0x6e, 0x75, 0x49, 0x64, 0x39, 0x4d, 0x63,
+    0x6a, 0x38, 0x65, 0x36, 0x75, 0x59, 0x69, 0x31, 0x61, 0x67, 0x6e, 0x6e,
+    0x63, 0x2b, 0x67, 0x52, 0x51, 0x4b, 0x66, 0x52, 0x7a, 0x4d, 0x70, 0x69,
+    0x6a, 0x53, 0x33, 0x6c, 0x6a, 0x77, 0x75, 0x6d, 0x55, 0x4e, 0x4b, 0x6f,
+    0x55, 0x4d, 0x4d, 0x6f, 0x36, 0x76, 0x57, 0x72, 0x4a, 0x59, 0x65, 0x4b,
+    0x0a, 0x6d, 0x70, 0x59, 0x63, 0x71, 0x57, 0x65, 0x34, 0x50, 0x77, 0x7a,
+    0x56, 0x39, 0x2f, 0x6c, 0x53, 0x45, 0x79, 0x2f, 0x43, 0x47, 0x39, 0x56,
+    0x77, 0x63, 0x50, 0x43, 0x50, 0x77, 0x42, 0x4c, 0x4b, 0x42, 0x73, 0x75,
+    0x61, 0x34, 0x64, 0x6e, 0x4b, 0x4d, 0x33, 0x70, 0x33, 0x31, 0x76, 0x6a,
+    0x73, 0x75, 0x66, 0x46, 0x6f, 0x52, 0x45, 0x4a, 0x49, 0x45, 0x39, 0x4c,
+    0x41, 0x77, 0x71, 0x53, 0x75, 0x0a, 0x58, 0x6d, 0x44, 0x2b, 0x74, 0x71,
+    0x59, 0x46, 0x2f, 0x4c, 0x54, 0x64, 0x42, 0x31, 0x6b, 0x43, 0x31, 0x46,
+    0x6b, 0x59, 0x6d, 0x47, 0x50, 0x31, 0x70, 0x57, 0x50, 0x67, 0x6b, 0x41,
+    0x78, 0x39, 0x58, 0x62, 0x49, 0x47, 0x65, 0x76, 0x4f, 0x46, 0x36, 0x75,
+    0x76, 0x55, 0x41, 0x36, 0x35, 0x65, 0x68, 0x44, 0x35, 0x66, 0x2f, 0x78,
+    0x58, 0x74, 0x61, 0x62, 0x7a, 0x35, 0x4f, 0x54, 0x5a, 0x79, 0x0a, 0x64,
+    0x63, 0x39, 0x33, 0x55, 0x6b, 0x33, 0x7a, 0x79, 0x5a, 0x41, 0x73, 0x75,
+    0x54, 0x33, 0x6c, 0x79, 0x53, 0x4e, 0x54, 0x50, 0x78, 0x38, 0x6b, 0x6d,
+    0x43, 0x46, 0x63, 0x42, 0x35, 0x6b, 0x70, 0x76, 0x63, 0x59, 0x36, 0x37,
+    0x4f, 0x64, 0x75, 0x68, 0x6a, 0x70, 0x72, 0x6c, 0x33, 0x52, 0x6a, 0x4d,
+    0x37, 0x31, 0x6f, 0x47, 0x44, 0x48, 0x77, 0x65, 0x49, 0x31, 0x32, 0x76,
+    0x2f, 0x79, 0x65, 0x0a, 0x6a, 0x6c, 0x30, 0x71, 0x68, 0x71, 0x64, 0x4e,
+    0x6b, 0x4e, 0x77, 0x6e, 0x47, 0x6a, 0x6b, 0x43, 0x41, 0x77, 0x45, 0x41,
+    0x41, 0x61, 0x4e, 0x46, 0x4d, 0x45, 0x4d, 0x77, 0x48, 0x51, 0x59, 0x44,
+    0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4f, 0x57, 0x64,
+    0x57, 0x54, 0x43, 0x43, 0x52, 0x31, 0x6a, 0x4d, 0x72, 0x50, 0x6f, 0x49,
+    0x56, 0x44, 0x61, 0x47, 0x65, 0x7a, 0x71, 0x31, 0x0a, 0x42, 0x45, 0x33,
+    0x77, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45,
+    0x42, 0x2f, 0x77, 0x51, 0x49, 0x4d, 0x41, 0x59, 0x42, 0x41, 0x66, 0x38,
+    0x43, 0x41, 0x51, 0x4d, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30,
+    0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45,
+    0x47, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62,
+    0x33, 0x0a, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x41, 0x34,
+    0x49, 0x42, 0x41, 0x51, 0x43, 0x46, 0x44, 0x46, 0x32, 0x4f, 0x35, 0x47,
+    0x39, 0x52, 0x61, 0x45, 0x49, 0x46, 0x6f, 0x4e, 0x32, 0x37, 0x54, 0x79,
+    0x63, 0x6c, 0x68, 0x41, 0x4f, 0x39, 0x39, 0x32, 0x54, 0x39, 0x4c, 0x64,
+    0x63, 0x77, 0x34, 0x36, 0x51, 0x51, 0x46, 0x2b, 0x76, 0x61, 0x4b, 0x53,
+    0x6d, 0x32, 0x65, 0x54, 0x39, 0x32, 0x0a, 0x39, 0x68, 0x6b, 0x54, 0x49,
+    0x37, 0x67, 0x51, 0x43, 0x76, 0x6c, 0x59, 0x70, 0x4e, 0x52, 0x68, 0x63,
+    0x4c, 0x30, 0x45, 0x59, 0x57, 0x6f, 0x53, 0x69, 0x68, 0x66, 0x56, 0x43,
+    0x72, 0x33, 0x46, 0x76, 0x44, 0x42, 0x38, 0x31, 0x75, 0x6b, 0x4d, 0x4a,
+    0x59, 0x32, 0x47, 0x51, 0x45, 0x2f, 0x73, 0x7a, 0x4b, 0x4e, 0x2b, 0x4f,
+    0x4d, 0x59, 0x33, 0x45, 0x55, 0x2f, 0x74, 0x33, 0x57, 0x67, 0x78, 0x0a,
+    0x6a, 0x6b, 0x7a, 0x53, 0x73, 0x77, 0x46, 0x30, 0x37, 0x72, 0x35, 0x31,
+    0x58, 0x67, 0x64, 0x49, 0x47, 0x6e, 0x39, 0x77, 0x2f, 0x78, 0x5a, 0x63,
+    0x68, 0x4d, 0x42, 0x35, 0x68, 0x62, 0x67, 0x46, 0x2f, 0x58, 0x2b, 0x2b,
+    0x5a, 0x52, 0x47, 0x6a, 0x44, 0x38, 0x41, 0x43, 0x74, 0x50, 0x68, 0x53,
+    0x4e, 0x7a, 0x6b, 0x45, 0x31, 0x61, 0x6b, 0x78, 0x65, 0x68, 0x69, 0x2f,
+    0x6f, 0x43, 0x72, 0x30, 0x0a, 0x45, 0x70, 0x6e, 0x33, 0x6f, 0x30, 0x57,
+    0x43, 0x34, 0x7a, 0x78, 0x65, 0x39, 0x5a, 0x32, 0x65, 0x74, 0x63, 0x69,
+    0x65, 0x66, 0x43, 0x37, 0x49, 0x70, 0x4a, 0x35, 0x4f, 0x43, 0x42, 0x52,
+    0x4c, 0x62, 0x66, 0x31, 0x77, 0x62, 0x57, 0x73, 0x61, 0x59, 0x37, 0x31,
+    0x6b, 0x35, 0x68, 0x2b, 0x33, 0x7a, 0x76, 0x44, 0x79, 0x6e, 0x79, 0x36,
+    0x37, 0x47, 0x37, 0x66, 0x79, 0x55, 0x49, 0x68, 0x7a, 0x0a, 0x6b, 0x73,
+    0x4c, 0x69, 0x34, 0x78, 0x61, 0x4e, 0x6d, 0x6a, 0x49, 0x43, 0x71, 0x34,
+    0x34, 0x59, 0x33, 0x65, 0x6b, 0x51, 0x45, 0x65, 0x35, 0x2b, 0x4e, 0x61,
+    0x75, 0x51, 0x72, 0x7a, 0x34, 0x77, 0x6c, 0x48, 0x72, 0x51, 0x4d, 0x7a,
+    0x32, 0x6e, 0x5a, 0x51, 0x2f, 0x31, 0x2f, 0x49, 0x36, 0x65, 0x59, 0x73,
+    0x39, 0x48, 0x52, 0x43, 0x77, 0x42, 0x58, 0x62, 0x73, 0x64, 0x74, 0x54,
+    0x4c, 0x53, 0x0a, 0x52, 0x39, 0x49, 0x34, 0x4c, 0x74, 0x44, 0x2b, 0x67,
+    0x64, 0x77, 0x79, 0x61, 0x68, 0x36, 0x31, 0x37, 0x6a, 0x7a, 0x56, 0x2f,
+    0x4f, 0x65, 0x42, 0x48, 0x52, 0x6e, 0x44, 0x4a, 0x45, 0x4c, 0x71, 0x59,
+    0x7a, 0x6d, 0x70, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73,
+    0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45, 0x71, 0x75, 0x69,
+    0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x47,
+    0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x65, 0x42, 0x75, 0x73, 0x69, 0x6e,
+    0x65, 0x73, 0x73, 0x20, 0x43, 0x41, 0x2d, 0x31, 0x20, 0x4f, 0x3d, 0x45,
+    0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72,
+    0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62,
+    0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45, 0x71, 0x75,
+    0x69, 0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20,
+    0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x65, 0x42, 0x75, 0x73, 0x69,
+    0x6e, 0x65, 0x73, 0x73, 0x20, 0x43, 0x41, 0x2d, 0x31, 0x20, 0x4f, 0x3d,
+    0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75,
+    0x72, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61,
+    0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61,
+    0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x47, 0x6c, 0x6f,
+    0x62, 0x61, 0x6c, 0x20, 0x65, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73,
+    0x73, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69,
+    0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x38, 0x66, 0x3a, 0x35, 0x64, 0x3a, 0x37, 0x37, 0x3a, 0x30, 0x36,
+    0x3a, 0x32, 0x37, 0x3a, 0x63, 0x34, 0x3a, 0x39, 0x38, 0x3a, 0x33, 0x63,
+    0x3a, 0x35, 0x62, 0x3a, 0x39, 0x33, 0x3a, 0x37, 0x38, 0x3a, 0x65, 0x37,
+    0x3a, 0x64, 0x37, 0x3a, 0x37, 0x64, 0x3a, 0x39, 0x62, 0x3a, 0x63, 0x63,
+    0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x65, 0x3a,
+    0x37, 0x38, 0x3a, 0x34, 0x61, 0x3a, 0x31, 0x30, 0x3a, 0x31, 0x63, 0x3a,
+    0x38, 0x32, 0x3a, 0x36, 0x35, 0x3a, 0x63, 0x63, 0x3a, 0x32, 0x64, 0x3a,
+    0x65, 0x31, 0x3a, 0x66, 0x31, 0x3a, 0x36, 0x64, 0x3a, 0x34, 0x37, 0x3a,
+    0x62, 0x34, 0x3a, 0x34, 0x30, 0x3a, 0x63, 0x61, 0x3a, 0x64, 0x39, 0x3a,
+    0x30, 0x61, 0x3a, 0x31, 0x39, 0x3a, 0x34, 0x35, 0x0a, 0x23, 0x20, 0x53,
+    0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x66, 0x3a, 0x30, 0x62,
+    0x3a, 0x36, 0x32, 0x3a, 0x65, 0x61, 0x3a, 0x62, 0x35, 0x3a, 0x65, 0x33,
+    0x3a, 0x35, 0x33, 0x3a, 0x65, 0x61, 0x3a, 0x36, 0x35, 0x3a, 0x32, 0x31,
+    0x3a, 0x36, 0x35, 0x3a, 0x31, 0x36, 0x3a, 0x35, 0x38, 0x3a, 0x66, 0x62,
+    0x3a, 0x62, 0x36, 0x3a, 0x35, 0x33, 0x3a, 0x35, 0x39, 0x3a, 0x66, 0x34,
+    0x3a, 0x34, 0x33, 0x3a, 0x32, 0x38, 0x3a, 0x30, 0x61, 0x3a, 0x34, 0x61,
+    0x3a, 0x66, 0x62, 0x3a, 0x64, 0x31, 0x3a, 0x30, 0x34, 0x3a, 0x64, 0x37,
+    0x3a, 0x37, 0x64, 0x3a, 0x31, 0x30, 0x3a, 0x66, 0x39, 0x3a, 0x66, 0x30,
+    0x3a, 0x34, 0x63, 0x3a, 0x30, 0x37, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d,
+    0x49, 0x49, 0x43, 0x6b, 0x44, 0x43, 0x43, 0x41, 0x66, 0x6d, 0x67, 0x41,
+    0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42,
+    0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41,
+    0x51, 0x51, 0x46, 0x41, 0x44, 0x42, 0x61, 0x4d, 0x51, 0x73, 0x77, 0x43,
+    0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55,
+    0x7a, 0x45, 0x63, 0x0a, 0x4d, 0x42, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x43, 0x68, 0x4d, 0x54, 0x52, 0x58, 0x46, 0x31, 0x61, 0x57, 0x5a, 0x68,
+    0x65, 0x43, 0x42, 0x54, 0x5a, 0x57, 0x4e, 0x31, 0x63, 0x6d, 0x55, 0x67,
+    0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x74, 0x4d, 0x43, 0x73, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x6b, 0x52, 0x58, 0x46, 0x31,
+    0x61, 0x57, 0x5a, 0x68, 0x65, 0x43, 0x42, 0x54, 0x0a, 0x5a, 0x57, 0x4e,
+    0x31, 0x63, 0x6d, 0x55, 0x67, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46,
+    0x73, 0x49, 0x47, 0x56, 0x43, 0x64, 0x58, 0x4e, 0x70, 0x62, 0x6d, 0x56,
+    0x7a, 0x63, 0x79, 0x42, 0x44, 0x51, 0x53, 0x30, 0x78, 0x4d, 0x42, 0x34,
+    0x58, 0x44, 0x54, 0x6b, 0x35, 0x4d, 0x44, 0x59, 0x79, 0x4d, 0x54, 0x41,
+    0x30, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x49,
+    0x77, 0x0a, 0x4d, 0x44, 0x59, 0x79, 0x4d, 0x54, 0x41, 0x30, 0x4d, 0x44,
+    0x41, 0x77, 0x4d, 0x46, 0x6f, 0x77, 0x57, 0x6a, 0x45, 0x4c, 0x4d, 0x41,
+    0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56,
+    0x4d, 0x78, 0x48, 0x44, 0x41, 0x61, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41,
+    0x6f, 0x54, 0x45, 0x30, 0x56, 0x78, 0x64, 0x57, 0x6c, 0x6d, 0x59, 0x58,
+    0x67, 0x67, 0x55, 0x32, 0x56, 0x6a, 0x0a, 0x64, 0x58, 0x4a, 0x6c, 0x49,
+    0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x4c, 0x54, 0x41, 0x72, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x4a, 0x45, 0x56, 0x78, 0x64,
+    0x57, 0x6c, 0x6d, 0x59, 0x58, 0x67, 0x67, 0x55, 0x32, 0x56, 0x6a, 0x64,
+    0x58, 0x4a, 0x6c, 0x49, 0x45, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62,
+    0x43, 0x42, 0x6c, 0x51, 0x6e, 0x56, 0x7a, 0x61, 0x57, 0x35, 0x6c, 0x0a,
+    0x63, 0x33, 0x4d, 0x67, 0x51, 0x30, 0x45, 0x74, 0x4d, 0x54, 0x43, 0x42,
+    0x6e, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47,
+    0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x42,
+    0x6a, 0x51, 0x41, 0x77, 0x67, 0x59, 0x6b, 0x43, 0x67, 0x59, 0x45, 0x41,
+    0x75, 0x75, 0x63, 0x58, 0x6b, 0x41, 0x4a, 0x6c, 0x73, 0x54, 0x52, 0x56,
+    0x50, 0x45, 0x6e, 0x43, 0x0a, 0x55, 0x64, 0x58, 0x66, 0x70, 0x39, 0x45,
+    0x33, 0x6a, 0x39, 0x48, 0x6e, 0x67, 0x58, 0x4e, 0x42, 0x55, 0x6d, 0x43,
+    0x62, 0x6e, 0x61, 0x45, 0x58, 0x4a, 0x6e, 0x69, 0x74, 0x78, 0x37, 0x48,
+    0x6f, 0x4a, 0x70, 0x51, 0x79, 0x74, 0x64, 0x34, 0x7a, 0x6a, 0x54, 0x6f,
+    0x76, 0x32, 0x2f, 0x4b, 0x61, 0x65, 0x6c, 0x70, 0x7a, 0x6d, 0x4b, 0x4e,
+    0x63, 0x36, 0x66, 0x75, 0x4b, 0x63, 0x78, 0x74, 0x63, 0x0a, 0x35, 0x38,
+    0x4f, 0x2f, 0x67, 0x47, 0x7a, 0x4e, 0x71, 0x66, 0x54, 0x57, 0x4b, 0x38,
+    0x44, 0x33, 0x2b, 0x5a, 0x6d, 0x71, 0x59, 0x36, 0x4b, 0x78, 0x52, 0x77,
+    0x49, 0x50, 0x31, 0x4f, 0x52, 0x52, 0x4f, 0x68, 0x49, 0x38, 0x62, 0x49,
+    0x70, 0x61, 0x56, 0x49, 0x52, 0x77, 0x32, 0x38, 0x48, 0x46, 0x6b, 0x4d,
+    0x39, 0x79, 0x52, 0x63, 0x75, 0x6f, 0x57, 0x63, 0x44, 0x4e, 0x4d, 0x35,
+    0x30, 0x2f, 0x0a, 0x6f, 0x35, 0x62, 0x72, 0x68, 0x54, 0x4d, 0x68, 0x48,
+    0x44, 0x34, 0x65, 0x50, 0x6d, 0x42, 0x75, 0x64, 0x70, 0x78, 0x6e, 0x68,
+    0x63, 0x58, 0x49, 0x77, 0x32, 0x45, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41,
+    0x61, 0x4e, 0x6d, 0x4d, 0x47, 0x51, 0x77, 0x45, 0x51, 0x59, 0x4a, 0x59,
+    0x49, 0x5a, 0x49, 0x41, 0x59, 0x62, 0x34, 0x51, 0x67, 0x45, 0x42, 0x42,
+    0x41, 0x51, 0x44, 0x41, 0x67, 0x41, 0x48, 0x0a, 0x4d, 0x41, 0x38, 0x47,
+    0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46,
+    0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x48, 0x77, 0x59, 0x44,
+    0x56, 0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55,
+    0x76, 0x71, 0x69, 0x67, 0x64, 0x48, 0x4a, 0x51, 0x61, 0x30, 0x53, 0x33,
+    0x79, 0x53, 0x50, 0x59, 0x2b, 0x36, 0x6a, 0x2f, 0x73, 0x31, 0x64, 0x72,
+    0x0a, 0x61, 0x47, 0x77, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30,
+    0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4c, 0x36, 0x6f, 0x6f, 0x48, 0x52,
+    0x79, 0x55, 0x47, 0x74, 0x45, 0x74, 0x38, 0x6b, 0x6a, 0x32, 0x50, 0x75,
+    0x6f, 0x2f, 0x37, 0x4e, 0x58, 0x61, 0x32, 0x68, 0x73, 0x4d, 0x41, 0x30,
+    0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45,
+    0x42, 0x42, 0x41, 0x55, 0x41, 0x0a, 0x41, 0x34, 0x47, 0x42, 0x41, 0x44,
+    0x44, 0x69, 0x41, 0x56, 0x47, 0x71, 0x78, 0x2b, 0x70, 0x66, 0x32, 0x72,
+    0x6e, 0x51, 0x5a, 0x51, 0x38, 0x77, 0x31, 0x6a, 0x37, 0x61, 0x44, 0x52,
+    0x52, 0x4a, 0x62, 0x70, 0x47, 0x54, 0x4a, 0x78, 0x51, 0x78, 0x37, 0x38,
+    0x54, 0x33, 0x4c, 0x55, 0x58, 0x34, 0x37, 0x4d, 0x65, 0x2f, 0x6f, 0x6b,
+    0x45, 0x4e, 0x49, 0x37, 0x53, 0x53, 0x2b, 0x52, 0x6b, 0x41, 0x0a, 0x5a,
+    0x37, 0x30, 0x42, 0x72, 0x38, 0x33, 0x67, 0x63, 0x66, 0x78, 0x61, 0x7a,
+    0x32, 0x54, 0x45, 0x34, 0x4a, 0x61, 0x59, 0x30, 0x4b, 0x4e, 0x41, 0x34,
+    0x67, 0x47, 0x4b, 0x37, 0x79, 0x63, 0x48, 0x38, 0x57, 0x55, 0x42, 0x69,
+    0x6b, 0x51, 0x74, 0x42, 0x6d, 0x56, 0x31, 0x55, 0x73, 0x43, 0x47, 0x45,
+    0x43, 0x41, 0x68, 0x58, 0x32, 0x78, 0x72, 0x44, 0x32, 0x79, 0x75, 0x43,
+    0x52, 0x79, 0x76, 0x0a, 0x38, 0x71, 0x49, 0x59, 0x4e, 0x4d, 0x52, 0x31,
+    0x70, 0x48, 0x4d, 0x63, 0x38, 0x59, 0x33, 0x63, 0x37, 0x36, 0x33, 0x35,
+    0x73, 0x33, 0x61, 0x30, 0x6b, 0x72, 0x2f, 0x63, 0x6c, 0x52, 0x41, 0x65,
+    0x76, 0x73, 0x76, 0x49, 0x4f, 0x31, 0x71, 0x45, 0x59, 0x42, 0x6c, 0x57,
+    0x6c, 0x4b, 0x6c, 0x56, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e,
+    0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54,
+    0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73,
+    0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45, 0x71, 0x75,
+    0x69, 0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20,
+    0x65, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x43, 0x41,
+    0x2d, 0x31, 0x20, 0x4f, 0x3d, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78,
+    0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+    0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20,
+    0x43, 0x4e, 0x3d, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x20, 0x53,
+    0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x65, 0x42, 0x75, 0x73, 0x69, 0x6e,
+    0x65, 0x73, 0x73, 0x20, 0x43, 0x41, 0x2d, 0x31, 0x20, 0x4f, 0x3d, 0x45,
+    0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72,
+    0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62,
+    0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78,
+    0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x65, 0x42, 0x75, 0x73,
+    0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x43, 0x41, 0x20, 0x31, 0x22, 0x0a,
+    0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x34, 0x0a,
+    0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x34, 0x3a, 0x39, 0x63,
+    0x3a, 0x65, 0x66, 0x3a, 0x32, 0x65, 0x3a, 0x34, 0x34, 0x3a, 0x66, 0x63,
+    0x3a, 0x63, 0x36, 0x3a, 0x38, 0x66, 0x3a, 0x35, 0x32, 0x3a, 0x30, 0x37,
+    0x3a, 0x64, 0x30, 0x3a, 0x35, 0x31, 0x3a, 0x37, 0x33, 0x3a, 0x38, 0x66,
+    0x3a, 0x63, 0x62, 0x3a, 0x33, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41,
+    0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x64, 0x61, 0x3a, 0x34, 0x30, 0x3a, 0x31, 0x38, 0x3a,
+    0x38, 0x62, 0x3a, 0x39, 0x31, 0x3a, 0x38, 0x39, 0x3a, 0x61, 0x33, 0x3a,
+    0x65, 0x64, 0x3a, 0x65, 0x65, 0x3a, 0x61, 0x65, 0x3a, 0x64, 0x61, 0x3a,
+    0x39, 0x37, 0x3a, 0x66, 0x65, 0x3a, 0x32, 0x66, 0x3a, 0x39, 0x64, 0x3a,
+    0x66, 0x35, 0x3a, 0x62, 0x37, 0x3a, 0x64, 0x31, 0x3a, 0x38, 0x61, 0x3a,
+    0x34, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x63, 0x66, 0x3a, 0x35, 0x36, 0x3a, 0x66, 0x66, 0x3a, 0x34, 0x36,
+    0x3a, 0x61, 0x34, 0x3a, 0x61, 0x31, 0x3a, 0x38, 0x36, 0x3a, 0x31, 0x30,
+    0x3a, 0x39, 0x64, 0x3a, 0x64, 0x39, 0x3a, 0x36, 0x35, 0x3a, 0x38, 0x34,
+    0x3a, 0x62, 0x35, 0x3a, 0x65, 0x65, 0x3a, 0x62, 0x35, 0x3a, 0x38, 0x61,
+    0x3a, 0x35, 0x31, 0x3a, 0x30, 0x63, 0x3a, 0x34, 0x32, 0x3a, 0x37, 0x35,
+    0x3a, 0x62, 0x30, 0x3a, 0x65, 0x35, 0x3a, 0x66, 0x39, 0x3a, 0x34, 0x66,
+    0x3a, 0x34, 0x30, 0x3a, 0x62, 0x62, 0x3a, 0x61, 0x65, 0x3a, 0x38, 0x36,
+    0x3a, 0x35, 0x65, 0x3a, 0x31, 0x39, 0x3a, 0x66, 0x36, 0x3a, 0x37, 0x33,
+    0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20,
+    0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x67, 0x6a, 0x43,
+    0x43, 0x41, 0x65, 0x75, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49,
+    0x42, 0x42, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69,
+    0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x51, 0x46, 0x41, 0x44, 0x42,
+    0x54, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x63, 0x0a, 0x4d, 0x42,
+    0x6f, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x54, 0x52, 0x58,
+    0x46, 0x31, 0x61, 0x57, 0x5a, 0x68, 0x65, 0x43, 0x42, 0x54, 0x5a, 0x57,
+    0x4e, 0x31, 0x63, 0x6d, 0x55, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a,
+    0x45, 0x6d, 0x4d, 0x43, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78,
+    0x4d, 0x64, 0x52, 0x58, 0x46, 0x31, 0x61, 0x57, 0x5a, 0x68, 0x65, 0x43,
+    0x42, 0x54, 0x0a, 0x5a, 0x57, 0x4e, 0x31, 0x63, 0x6d, 0x55, 0x67, 0x5a,
+    0x55, 0x4a, 0x31, 0x63, 0x32, 0x6c, 0x75, 0x5a, 0x58, 0x4e, 0x7a, 0x49,
+    0x45, 0x4e, 0x42, 0x4c, 0x54, 0x45, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4f,
+    0x54, 0x6b, 0x77, 0x4e, 0x6a, 0x49, 0x78, 0x4d, 0x44, 0x51, 0x77, 0x4d,
+    0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x41, 0x77, 0x4e,
+    0x6a, 0x49, 0x78, 0x4d, 0x44, 0x51, 0x77, 0x0a, 0x4d, 0x44, 0x41, 0x77,
+    0x57, 0x6a, 0x42, 0x54, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44,
+    0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x63,
+    0x4d, 0x42, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x54,
+    0x52, 0x58, 0x46, 0x31, 0x61, 0x57, 0x5a, 0x68, 0x65, 0x43, 0x42, 0x54,
+    0x5a, 0x57, 0x4e, 0x31, 0x63, 0x6d, 0x55, 0x67, 0x53, 0x57, 0x35, 0x6a,
+    0x0a, 0x4c, 0x6a, 0x45, 0x6d, 0x4d, 0x43, 0x51, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x41, 0x78, 0x4d, 0x64, 0x52, 0x58, 0x46, 0x31, 0x61, 0x57, 0x5a,
+    0x68, 0x65, 0x43, 0x42, 0x54, 0x5a, 0x57, 0x4e, 0x31, 0x63, 0x6d, 0x55,
+    0x67, 0x5a, 0x55, 0x4a, 0x31, 0x63, 0x32, 0x6c, 0x75, 0x5a, 0x58, 0x4e,
+    0x7a, 0x49, 0x45, 0x4e, 0x42, 0x4c, 0x54, 0x45, 0x77, 0x67, 0x5a, 0x38,
+    0x77, 0x44, 0x51, 0x59, 0x4a, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76,
+    0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x59,
+    0x30, 0x41, 0x4d, 0x49, 0x47, 0x4a, 0x41, 0x6f, 0x47, 0x42, 0x41, 0x4d,
+    0x34, 0x76, 0x47, 0x62, 0x77, 0x58, 0x74, 0x33, 0x66, 0x65, 0x6b, 0x36,
+    0x6c, 0x66, 0x57, 0x67, 0x30, 0x58, 0x54, 0x7a, 0x51, 0x61, 0x44, 0x4a,
+    0x6a, 0x30, 0x49, 0x74, 0x6c, 0x5a, 0x31, 0x4d, 0x52, 0x6f, 0x0a, 0x52,
+    0x76, 0x43, 0x30, 0x4e, 0x63, 0x57, 0x46, 0x41, 0x79, 0x44, 0x47, 0x72,
+    0x30, 0x57, 0x6c, 0x49, 0x56, 0x46, 0x46, 0x51, 0x65, 0x73, 0x57, 0x57,
+    0x44, 0x59, 0x79, 0x62, 0x2b, 0x4a, 0x51, 0x59, 0x6d, 0x54, 0x35, 0x2f,
+    0x56, 0x47, 0x63, 0x71, 0x69, 0x54, 0x5a, 0x39, 0x4a, 0x32, 0x44, 0x4b,
+    0x6f, 0x63, 0x4b, 0x49, 0x64, 0x4d, 0x53, 0x4f, 0x44, 0x52, 0x73, 0x6a,
+    0x51, 0x42, 0x75, 0x0a, 0x57, 0x71, 0x44, 0x5a, 0x51, 0x75, 0x34, 0x61,
+    0x49, 0x5a, 0x58, 0x35, 0x55, 0x6b, 0x78, 0x56, 0x57, 0x73, 0x55, 0x50,
+    0x4f, 0x45, 0x39, 0x47, 0x2b, 0x6d, 0x33, 0x34, 0x4c, 0x6a, 0x58, 0x57,
+    0x48, 0x58, 0x7a, 0x72, 0x34, 0x76, 0x43, 0x77, 0x64, 0x59, 0x44, 0x49,
+    0x71, 0x52, 0x4f, 0x73, 0x76, 0x6f, 0x6a, 0x76, 0x4f, 0x6d, 0x36, 0x72,
+    0x58, 0x79, 0x6f, 0x34, 0x59, 0x67, 0x4b, 0x77, 0x0a, 0x45, 0x6e, 0x76,
+    0x2b, 0x6a, 0x36, 0x59, 0x44, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47,
+    0x6a, 0x5a, 0x6a, 0x42, 0x6b, 0x4d, 0x42, 0x45, 0x47, 0x43, 0x57, 0x43,
+    0x47, 0x53, 0x41, 0x47, 0x47, 0x2b, 0x45, 0x49, 0x42, 0x41, 0x51, 0x51,
+    0x45, 0x41, 0x77, 0x49, 0x41, 0x42, 0x7a, 0x41, 0x50, 0x42, 0x67, 0x4e,
+    0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41,
+    0x44, 0x0a, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31,
+    0x55, 0x64, 0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, 0x61, 0x41, 0x46, 0x45,
+    0x70, 0x34, 0x4d, 0x6c, 0x49, 0x52, 0x32, 0x31, 0x6b, 0x57, 0x4e, 0x6c,
+    0x37, 0x66, 0x77, 0x52, 0x51, 0x32, 0x51, 0x47, 0x70, 0x48, 0x66, 0x45,
+    0x79, 0x68, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67,
+    0x51, 0x57, 0x42, 0x42, 0x52, 0x4b, 0x0a, 0x65, 0x44, 0x4a, 0x53, 0x45,
+    0x64, 0x74, 0x5a, 0x46, 0x6a, 0x5a, 0x65, 0x33, 0x38, 0x45, 0x55, 0x4e,
+    0x6b, 0x42, 0x71, 0x52, 0x33, 0x78, 0x4d, 0x6f, 0x54, 0x41, 0x4e, 0x42,
+    0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41,
+    0x51, 0x51, 0x46, 0x41, 0x41, 0x4f, 0x42, 0x67, 0x51, 0x42, 0x31, 0x57,
+    0x36, 0x69, 0x62, 0x41, 0x78, 0x48, 0x6d, 0x36, 0x56, 0x5a, 0x4d, 0x0a,
+    0x7a, 0x66, 0x6d, 0x70, 0x54, 0x4d, 0x41, 0x4e, 0x6d, 0x76, 0x50, 0x4d,
+    0x5a, 0x57, 0x6e, 0x6d, 0x4a, 0x58, 0x62, 0x4d, 0x57, 0x62, 0x66, 0x57,
+    0x56, 0x4d, 0x4d, 0x64, 0x7a, 0x5a, 0x6d, 0x73, 0x47, 0x64, 0x32, 0x30,
+    0x68, 0x64, 0x58, 0x67, 0x50, 0x66, 0x78, 0x69, 0x49, 0x4b, 0x65, 0x45,
+    0x53, 0x31, 0x68, 0x6c, 0x38, 0x65, 0x4c, 0x35, 0x6c, 0x53, 0x45, 0x2f,
+    0x39, 0x64, 0x52, 0x2b, 0x0a, 0x57, 0x42, 0x35, 0x48, 0x68, 0x31, 0x51,
+    0x2b, 0x57, 0x4b, 0x47, 0x31, 0x74, 0x66, 0x67, 0x71, 0x37, 0x33, 0x48,
+    0x6e, 0x76, 0x4d, 0x50, 0x32, 0x73, 0x55, 0x6c, 0x47, 0x34, 0x74, 0x65,
+    0x67, 0x61, 0x2b, 0x56, 0x57, 0x65, 0x70, 0x6f, 0x6e, 0x6d, 0x48, 0x78,
+    0x47, 0x59, 0x68, 0x54, 0x6e, 0x79, 0x66, 0x78, 0x75, 0x41, 0x78, 0x4a,
+    0x35, 0x67, 0x44, 0x67, 0x64, 0x53, 0x49, 0x4b, 0x4e, 0x0a, 0x2f, 0x42,
+    0x66, 0x2b, 0x4b, 0x70, 0x59, 0x72, 0x74, 0x57, 0x4b, 0x6d, 0x70, 0x6a,
+    0x32, 0x39, 0x66, 0x35, 0x4a, 0x5a, 0x7a, 0x56, 0x6f, 0x71, 0x67, 0x72,
+    0x49, 0x33, 0x65, 0x51, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43,
+    0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20,
+    0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x4f, 0x3d, 0x45, 0x71,
+    0x75, 0x69, 0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65,
+    0x20, 0x4f, 0x55, 0x3d, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x20,
+    0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x65, 0x42, 0x75, 0x73, 0x69,
+    0x6e, 0x65, 0x73, 0x73, 0x20, 0x43, 0x41, 0x2d, 0x32, 0x0a, 0x23, 0x20,
+    0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x4f, 0x3d, 0x45,
+    0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72,
+    0x65, 0x20, 0x4f, 0x55, 0x3d, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78,
+    0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x65, 0x42, 0x75, 0x73,
+    0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x43, 0x41, 0x2d, 0x32, 0x0a, 0x23,
+    0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, 0x71, 0x75,
+    0x69, 0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20,
+    0x65, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x43, 0x41,
+    0x20, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c,
+    0x3a, 0x20, 0x39, 0x33, 0x30, 0x31, 0x34, 0x30, 0x30, 0x38, 0x35, 0x0a,
+    0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x61, 0x3a, 0x62, 0x66,
+    0x3a, 0x62, 0x66, 0x3a, 0x36, 0x34, 0x3a, 0x39, 0x37, 0x3a, 0x64, 0x61,
+    0x3a, 0x39, 0x38, 0x3a, 0x31, 0x64, 0x3a, 0x36, 0x66, 0x3a, 0x63, 0x36,
+    0x3a, 0x30, 0x38, 0x3a, 0x33, 0x61, 0x3a, 0x39, 0x35, 0x3a, 0x37, 0x30,
+    0x3a, 0x33, 0x33, 0x3a, 0x63, 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41,
+    0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x33, 0x39, 0x3a, 0x34, 0x66, 0x3a, 0x66, 0x36, 0x3a,
+    0x38, 0x35, 0x3a, 0x30, 0x62, 0x3a, 0x30, 0x36, 0x3a, 0x62, 0x65, 0x3a,
+    0x35, 0x32, 0x3a, 0x65, 0x35, 0x3a, 0x31, 0x38, 0x3a, 0x35, 0x36, 0x3a,
+    0x63, 0x63, 0x3a, 0x31, 0x30, 0x3a, 0x65, 0x31, 0x3a, 0x38, 0x30, 0x3a,
+    0x65, 0x38, 0x3a, 0x38, 0x32, 0x3a, 0x62, 0x33, 0x3a, 0x38, 0x35, 0x3a,
+    0x63, 0x63, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x32, 0x66, 0x3a, 0x32, 0x37, 0x3a, 0x34, 0x65, 0x3a, 0x34, 0x38,
+    0x3a, 0x61, 0x62, 0x3a, 0x61, 0x34, 0x3a, 0x61, 0x63, 0x3a, 0x37, 0x62,
+    0x3a, 0x37, 0x36, 0x3a, 0x35, 0x39, 0x3a, 0x33, 0x33, 0x3a, 0x31, 0x30,
+    0x3a, 0x31, 0x37, 0x3a, 0x37, 0x35, 0x3a, 0x35, 0x30, 0x3a, 0x36, 0x64,
+    0x3a, 0x63, 0x33, 0x3a, 0x30, 0x65, 0x3a, 0x65, 0x33, 0x3a, 0x38, 0x65,
+    0x3a, 0x66, 0x36, 0x3a, 0x61, 0x63, 0x3a, 0x64, 0x35, 0x3a, 0x63, 0x30,
+    0x3a, 0x34, 0x39, 0x3a, 0x33, 0x32, 0x3a, 0x63, 0x66, 0x3a, 0x65, 0x30,
+    0x3a, 0x34, 0x31, 0x3a, 0x32, 0x33, 0x3a, 0x34, 0x32, 0x3a, 0x32, 0x30,
+    0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20,
+    0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x49, 0x44, 0x43,
+    0x43, 0x41, 0x6f, 0x6d, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49,
+    0x45, 0x4e, 0x33, 0x44, 0x50, 0x74, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b,
+    0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55,
+    0x46, 0x41, 0x44, 0x42, 0x4f, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59,
+    0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x0a, 0x55, 0x7a,
+    0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68,
+    0x4d, 0x4f, 0x52, 0x58, 0x46, 0x31, 0x61, 0x57, 0x5a, 0x68, 0x65, 0x43,
+    0x42, 0x54, 0x5a, 0x57, 0x4e, 0x31, 0x63, 0x6d, 0x55, 0x78, 0x4a, 0x6a,
+    0x41, 0x6b, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x48, 0x55,
+    0x56, 0x78, 0x64, 0x57, 0x6c, 0x6d, 0x59, 0x58, 0x67, 0x67, 0x55, 0x32,
+    0x56, 0x6a, 0x0a, 0x64, 0x58, 0x4a, 0x6c, 0x49, 0x47, 0x56, 0x43, 0x64,
+    0x58, 0x4e, 0x70, 0x62, 0x6d, 0x56, 0x7a, 0x63, 0x79, 0x42, 0x44, 0x51,
+    0x53, 0x30, 0x79, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x6b, 0x35, 0x4d,
+    0x44, 0x59, 0x79, 0x4d, 0x7a, 0x45, 0x79, 0x4d, 0x54, 0x51, 0x30, 0x4e,
+    0x56, 0x6f, 0x58, 0x44, 0x54, 0x45, 0x35, 0x4d, 0x44, 0x59, 0x79, 0x4d,
+    0x7a, 0x45, 0x79, 0x4d, 0x54, 0x51, 0x30, 0x0a, 0x4e, 0x56, 0x6f, 0x77,
+    0x54, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x7a, 0x41, 0x56,
+    0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x6b, 0x56, 0x78,
+    0x64, 0x57, 0x6c, 0x6d, 0x59, 0x58, 0x67, 0x67, 0x55, 0x32, 0x56, 0x6a,
+    0x64, 0x58, 0x4a, 0x6c, 0x4d, 0x53, 0x59, 0x77, 0x4a, 0x41, 0x59, 0x44,
+    0x0a, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x31, 0x46, 0x63, 0x58, 0x56,
+    0x70, 0x5a, 0x6d, 0x46, 0x34, 0x49, 0x46, 0x4e, 0x6c, 0x59, 0x33, 0x56,
+    0x79, 0x5a, 0x53, 0x42, 0x6c, 0x51, 0x6e, 0x56, 0x7a, 0x61, 0x57, 0x35,
+    0x6c, 0x63, 0x33, 0x4d, 0x67, 0x51, 0x30, 0x45, 0x74, 0x4d, 0x6a, 0x43,
+    0x42, 0x6e, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69,
+    0x47, 0x39, 0x77, 0x30, 0x42, 0x0a, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41,
+    0x4f, 0x42, 0x6a, 0x51, 0x41, 0x77, 0x67, 0x59, 0x6b, 0x43, 0x67, 0x59,
+    0x45, 0x41, 0x35, 0x44, 0x6b, 0x35, 0x6b, 0x78, 0x35, 0x53, 0x42, 0x68,
+    0x73, 0x6f, 0x4e, 0x76, 0x69, 0x79, 0x6f, 0x79, 0x6e, 0x46, 0x37, 0x59,
+    0x36, 0x79, 0x45, 0x62, 0x33, 0x2b, 0x36, 0x2b, 0x65, 0x30, 0x64, 0x4d,
+    0x4b, 0x50, 0x2f, 0x77, 0x58, 0x6e, 0x32, 0x5a, 0x30, 0x47, 0x0a, 0x76,
+    0x78, 0x4c, 0x49, 0x50, 0x77, 0x37, 0x79, 0x31, 0x74, 0x45, 0x6b, 0x73,
+    0x68, 0x48, 0x65, 0x30, 0x58, 0x4d, 0x4a, 0x69, 0x74, 0x53, 0x78, 0x4c,
+    0x4a, 0x67, 0x4a, 0x44, 0x52, 0x35, 0x51, 0x52, 0x72, 0x4b, 0x44, 0x70,
+    0x6b, 0x57, 0x4e, 0x59, 0x6d, 0x69, 0x37, 0x68, 0x52, 0x73, 0x67, 0x63,
+    0x44, 0x4b, 0x71, 0x51, 0x4d, 0x32, 0x6d, 0x6c, 0x6c, 0x2f, 0x45, 0x63,
+    0x54, 0x63, 0x2f, 0x0a, 0x42, 0x50, 0x4f, 0x33, 0x51, 0x53, 0x51, 0x35,
+    0x42, 0x78, 0x6f, 0x65, 0x4c, 0x6d, 0x46, 0x59, 0x6f, 0x42, 0x49, 0x4c,
+    0x35, 0x61, 0x58, 0x66, 0x78, 0x61, 0x76, 0x71, 0x4e, 0x33, 0x48, 0x4d,
+    0x48, 0x4d, 0x67, 0x33, 0x4f, 0x72, 0x6d, 0x58, 0x55, 0x71, 0x65, 0x73,
+    0x78, 0x57, 0x6f, 0x6b, 0x6c, 0x45, 0x36, 0x63, 0x65, 0x38, 0x2f, 0x41,
+    0x61, 0x74, 0x62, 0x66, 0x49, 0x62, 0x30, 0x43, 0x0a, 0x41, 0x77, 0x45,
+    0x41, 0x41, 0x61, 0x4f, 0x43, 0x41, 0x51, 0x6b, 0x77, 0x67, 0x67, 0x45,
+    0x46, 0x4d, 0x48, 0x41, 0x47, 0x41, 0x31, 0x55, 0x64, 0x48, 0x77, 0x52,
+    0x70, 0x4d, 0x47, 0x63, 0x77, 0x5a, 0x61, 0x42, 0x6a, 0x6f, 0x47, 0x47,
+    0x6b, 0x58, 0x7a, 0x42, 0x64, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59,
+    0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45,
+    0x58, 0x0a, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68,
+    0x4d, 0x4f, 0x52, 0x58, 0x46, 0x31, 0x61, 0x57, 0x5a, 0x68, 0x65, 0x43,
+    0x42, 0x54, 0x5a, 0x57, 0x4e, 0x31, 0x63, 0x6d, 0x55, 0x78, 0x4a, 0x6a,
+    0x41, 0x6b, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x48, 0x55,
+    0x56, 0x78, 0x64, 0x57, 0x6c, 0x6d, 0x59, 0x58, 0x67, 0x67, 0x55, 0x32,
+    0x56, 0x6a, 0x64, 0x58, 0x4a, 0x6c, 0x0a, 0x49, 0x47, 0x56, 0x43, 0x64,
+    0x58, 0x4e, 0x70, 0x62, 0x6d, 0x56, 0x7a, 0x63, 0x79, 0x42, 0x44, 0x51,
+    0x53, 0x30, 0x79, 0x4d, 0x51, 0x30, 0x77, 0x43, 0x77, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x44, 0x45, 0x77, 0x52, 0x44, 0x55, 0x6b, 0x77, 0x78, 0x4d,
+    0x42, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x41, 0x51, 0x54, 0x4d,
+    0x42, 0x47, 0x42, 0x44, 0x7a, 0x49, 0x77, 0x4d, 0x54, 0x6b, 0x77, 0x0a,
+    0x4e, 0x6a, 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x78, 0x4e, 0x44, 0x51, 0x31,
+    0x57, 0x6a, 0x41, 0x4c, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x45,
+    0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x48, 0x77, 0x59, 0x44,
+    0x56, 0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55,
+    0x55, 0x4a, 0x34, 0x4c, 0x36, 0x71, 0x39, 0x65, 0x75, 0x53, 0x42, 0x49,
+    0x70, 0x6c, 0x42, 0x71, 0x0a, 0x79, 0x2f, 0x33, 0x59, 0x49, 0x48, 0x71,
+    0x6e, 0x67, 0x6e, 0x59, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30,
+    0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x46, 0x43, 0x65, 0x43, 0x2b, 0x71,
+    0x76, 0x58, 0x72, 0x6b, 0x67, 0x53, 0x4b, 0x5a, 0x51, 0x61, 0x73, 0x76,
+    0x39, 0x32, 0x43, 0x42, 0x36, 0x70, 0x34, 0x4a, 0x32, 0x4d, 0x41, 0x77,
+    0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x51, 0x46, 0x0a, 0x4d, 0x41,
+    0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x47, 0x67, 0x59, 0x4a, 0x4b, 0x6f,
+    0x5a, 0x49, 0x68, 0x76, 0x5a, 0x39, 0x42, 0x30, 0x45, 0x41, 0x42, 0x41,
+    0x30, 0x77, 0x43, 0x78, 0x73, 0x46, 0x56, 0x6a, 0x4d, 0x75, 0x4d, 0x47,
+    0x4d, 0x44, 0x41, 0x67, 0x62, 0x41, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53,
+    0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51,
+    0x55, 0x41, 0x0a, 0x41, 0x34, 0x47, 0x42, 0x41, 0x41, 0x79, 0x47, 0x67,
+    0x71, 0x33, 0x6f, 0x54, 0x68, 0x72, 0x31, 0x6a, 0x6f, 0x6b, 0x6e, 0x34,
+    0x6a, 0x56, 0x59, 0x50, 0x53, 0x6d, 0x30, 0x42, 0x34, 0x38, 0x32, 0x55,
+    0x4a, 0x57, 0x2f, 0x62, 0x73, 0x47, 0x65, 0x36, 0x38, 0x53, 0x51, 0x73,
+    0x6f, 0x57, 0x6f, 0x75, 0x37, 0x64, 0x43, 0x34, 0x41, 0x38, 0x48, 0x4f,
+    0x64, 0x2f, 0x37, 0x6e, 0x70, 0x43, 0x79, 0x0a, 0x30, 0x63, 0x45, 0x2b,
+    0x55, 0x35, 0x38, 0x44, 0x52, 0x4c, 0x42, 0x2b, 0x53, 0x2f, 0x52, 0x76,
+    0x35, 0x48, 0x77, 0x66, 0x35, 0x2b, 0x4b, 0x78, 0x35, 0x4c, 0x69, 0x61,
+    0x37, 0x38, 0x4f, 0x39, 0x7a, 0x74, 0x34, 0x4c, 0x4d, 0x6a, 0x54, 0x5a,
+    0x33, 0x69, 0x6a, 0x74, 0x4d, 0x32, 0x76, 0x45, 0x31, 0x4e, 0x63, 0x39,
+    0x45, 0x6c, 0x69, 0x72, 0x66, 0x51, 0x6b, 0x74, 0x79, 0x33, 0x44, 0x31,
+    0x0a, 0x45, 0x34, 0x71, 0x55, 0x6f, 0x53, 0x65, 0x6b, 0x31, 0x6e, 0x44,
+    0x46, 0x62, 0x5a, 0x53, 0x31, 0x79, 0x58, 0x32, 0x64, 0x6f, 0x4e, 0x4c,
+    0x47, 0x43, 0x45, 0x6e, 0x5a, 0x5a, 0x70, 0x75, 0x6d, 0x30, 0x2f, 0x51,
+    0x4c, 0x33, 0x4d, 0x55, 0x6d, 0x56, 0x2b, 0x47, 0x52, 0x4d, 0x4f, 0x72,
+    0x4e, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65,
+    0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75,
+    0x73, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x31, 0x20, 0x43,
+    0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x41, 0x64, 0x64,
+    0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, 0x42, 0x20, 0x4f, 0x55, 0x3d,
+    0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x54, 0x54, 0x50,
+    0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x0a, 0x23, 0x20, 0x53,
+    0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41,
+    0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73,
+    0x73, 0x20, 0x31, 0x20, 0x43, 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+    0x4f, 0x3d, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41,
+    0x42, 0x20, 0x4f, 0x55, 0x3d, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73,
+    0x74, 0x20, 0x54, 0x54, 0x50, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72,
+    0x6b, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22,
+    0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4c, 0x6f, 0x77,
+    0x2d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69,
+    0x63, 0x65, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x0a, 0x23, 0x20,
+    0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23, 0x20,
+    0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x65, 0x3a, 0x34, 0x32, 0x3a, 0x39,
+    0x35, 0x3a, 0x30, 0x32, 0x3a, 0x33, 0x33, 0x3a, 0x39, 0x32, 0x3a, 0x36,
+    0x62, 0x3a, 0x62, 0x39, 0x3a, 0x35, 0x66, 0x3a, 0x63, 0x30, 0x3a, 0x37,
+    0x66, 0x3a, 0x64, 0x61, 0x3a, 0x64, 0x36, 0x3a, 0x62, 0x32, 0x3a, 0x34,
+    0x62, 0x3a, 0x66, 0x63, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x63, 0x63, 0x3a, 0x61, 0x62, 0x3a, 0x30, 0x65, 0x3a, 0x61, 0x30,
+    0x3a, 0x34, 0x63, 0x3a, 0x32, 0x33, 0x3a, 0x30, 0x31, 0x3a, 0x64, 0x36,
+    0x3a, 0x36, 0x39, 0x3a, 0x37, 0x62, 0x3a, 0x64, 0x64, 0x3a, 0x33, 0x37,
+    0x3a, 0x39, 0x66, 0x3a, 0x63, 0x64, 0x3a, 0x31, 0x32, 0x3a, 0x65, 0x62,
+    0x3a, 0x32, 0x34, 0x3a, 0x65, 0x33, 0x3a, 0x39, 0x34, 0x3a, 0x39, 0x64,
+    0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69,
+    0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38,
+    0x63, 0x3a, 0x37, 0x32, 0x3a, 0x30, 0x39, 0x3a, 0x32, 0x37, 0x3a, 0x39,
+    0x61, 0x3a, 0x63, 0x30, 0x3a, 0x34, 0x65, 0x3a, 0x32, 0x37, 0x3a, 0x35,
+    0x65, 0x3a, 0x31, 0x36, 0x3a, 0x64, 0x30, 0x3a, 0x37, 0x66, 0x3a, 0x64,
+    0x33, 0x3a, 0x62, 0x37, 0x3a, 0x37, 0x35, 0x3a, 0x65, 0x38, 0x3a, 0x30,
+    0x31, 0x3a, 0x35, 0x34, 0x3a, 0x62, 0x35, 0x3a, 0x39, 0x36, 0x3a, 0x38,
+    0x30, 0x3a, 0x34, 0x36, 0x3a, 0x65, 0x33, 0x3a, 0x31, 0x66, 0x3a, 0x35,
+    0x32, 0x3a, 0x64, 0x64, 0x3a, 0x32, 0x35, 0x3a, 0x37, 0x36, 0x3a, 0x36,
+    0x33, 0x3a, 0x32, 0x34, 0x3a, 0x65, 0x39, 0x3a, 0x61, 0x37, 0x0a, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45,
+    0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x47, 0x44, 0x43, 0x43, 0x41,
+    0x77, 0x43, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41,
+    0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39,
+    0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x6c, 0x4d,
+    0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45,
+    0x77, 0x4a, 0x54, 0x52, 0x54, 0x45, 0x55, 0x0a, 0x4d, 0x42, 0x49, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4c, 0x51, 0x57, 0x52, 0x6b,
+    0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x51, 0x55, 0x49, 0x78,
+    0x48, 0x54, 0x41, 0x62, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54,
+    0x46, 0x45, 0x46, 0x6b, 0x5a, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30,
+    0x49, 0x46, 0x52, 0x55, 0x55, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33,
+    0x0a, 0x62, 0x33, 0x4a, 0x72, 0x4d, 0x53, 0x45, 0x77, 0x48, 0x77, 0x59,
+    0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x68, 0x42, 0x5a, 0x47, 0x52,
+    0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x44, 0x62, 0x47, 0x46,
+    0x7a, 0x63, 0x79, 0x41, 0x78, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x46, 0x4a,
+    0x76, 0x62, 0x33, 0x51, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x41,
+    0x77, 0x4e, 0x54, 0x4d, 0x77, 0x0a, 0x4d, 0x54, 0x41, 0x7a, 0x4f, 0x44,
+    0x4d, 0x78, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x41, 0x77, 0x4e, 0x54,
+    0x4d, 0x77, 0x4d, 0x54, 0x41, 0x7a, 0x4f, 0x44, 0x4d, 0x78, 0x57, 0x6a,
+    0x42, 0x6c, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x47, 0x45, 0x77, 0x4a, 0x54, 0x52, 0x54, 0x45, 0x55, 0x4d, 0x42,
+    0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4c, 0x0a, 0x51,
+    0x57, 0x52, 0x6b, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x51,
+    0x55, 0x49, 0x78, 0x48, 0x54, 0x41, 0x62, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x73, 0x54, 0x46, 0x45, 0x46, 0x6b, 0x5a, 0x46, 0x52, 0x79, 0x64,
+    0x58, 0x4e, 0x30, 0x49, 0x46, 0x52, 0x55, 0x55, 0x43, 0x42, 0x4f, 0x5a,
+    0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x4d, 0x53, 0x45, 0x77, 0x48,
+    0x77, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x68, 0x42,
+    0x5a, 0x47, 0x52, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x44,
+    0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, 0x41, 0x78, 0x49, 0x45, 0x4e, 0x42,
+    0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x77, 0x67, 0x67, 0x45, 0x69,
+    0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33,
+    0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x0a, 0x41, 0x34, 0x49,
+    0x42, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49,
+    0x42, 0x41, 0x51, 0x43, 0x57, 0x6c, 0x74, 0x51, 0x68, 0x53, 0x57, 0x44,
+    0x69, 0x61, 0x2b, 0x68, 0x42, 0x42, 0x77, 0x7a, 0x65, 0x78, 0x4f, 0x44,
+    0x63, 0x45, 0x79, 0x50, 0x4e, 0x77, 0x54, 0x58, 0x48, 0x2b, 0x39, 0x5a,
+    0x4f, 0x45, 0x51, 0x70, 0x6e, 0x58, 0x76, 0x55, 0x47, 0x57, 0x32, 0x75,
+    0x6c, 0x0a, 0x43, 0x44, 0x74, 0x62, 0x4b, 0x52, 0x59, 0x36, 0x35, 0x34,
+    0x65, 0x79, 0x4e, 0x41, 0x62, 0x46, 0x76, 0x41, 0x57, 0x6c, 0x41, 0x33,
+    0x79, 0x43, 0x79, 0x79, 0x6b, 0x51, 0x72, 0x75, 0x47, 0x49, 0x67, 0x62,
+    0x33, 0x57, 0x6e, 0x74, 0x50, 0x2b, 0x4c, 0x56, 0x62, 0x42, 0x46, 0x63,
+    0x37, 0x6a, 0x4a, 0x70, 0x30, 0x56, 0x4c, 0x68, 0x44, 0x37, 0x42, 0x6f,
+    0x38, 0x77, 0x42, 0x4e, 0x36, 0x6e, 0x0a, 0x74, 0x47, 0x4f, 0x30, 0x2f,
+    0x37, 0x47, 0x63, 0x72, 0x6a, 0x79, 0x76, 0x64, 0x37, 0x5a, 0x57, 0x78,
+    0x62, 0x57, 0x72, 0x6f, 0x75, 0x6c, 0x70, 0x4f, 0x6a, 0x30, 0x4f, 0x4d,
+    0x33, 0x6b, 0x79, 0x50, 0x33, 0x43, 0x43, 0x6b, 0x70, 0x6c, 0x68, 0x62,
+    0x59, 0x30, 0x77, 0x43, 0x49, 0x39, 0x78, 0x50, 0x36, 0x5a, 0x49, 0x56,
+    0x78, 0x6e, 0x34, 0x4a, 0x64, 0x78, 0x4c, 0x5a, 0x6c, 0x79, 0x6c, 0x0a,
+    0x64, 0x49, 0x2b, 0x59, 0x72, 0x73, 0x6a, 0x35, 0x77, 0x41, 0x59, 0x69,
+    0x35, 0x36, 0x78, 0x7a, 0x33, 0x36, 0x55, 0x75, 0x2b, 0x31, 0x4c, 0x63,
+    0x73, 0x52, 0x56, 0x6c, 0x49, 0x50, 0x6f, 0x31, 0x5a, 0x6d, 0x6e, 0x65,
+    0x33, 0x79, 0x7a, 0x78, 0x62, 0x72, 0x77, 0x77, 0x32, 0x79, 0x77, 0x6b,
+    0x45, 0x74, 0x76, 0x72, 0x4e, 0x54, 0x56, 0x6f, 0x6b, 0x4d, 0x73, 0x41,
+    0x73, 0x4a, 0x63, 0x68, 0x0a, 0x50, 0x58, 0x51, 0x68, 0x49, 0x32, 0x55,
+    0x30, 0x4b, 0x37, 0x74, 0x34, 0x57, 0x61, 0x50, 0x57, 0x34, 0x58, 0x59,
+    0x35, 0x6d, 0x71, 0x52, 0x4a, 0x6a, 0x6f, 0x78, 0x30, 0x72, 0x32, 0x36,
+    0x6b, 0x6d, 0x71, 0x50, 0x5a, 0x6d, 0x39, 0x49, 0x34, 0x58, 0x4a, 0x75,
+    0x69, 0x47, 0x4d, 0x78, 0x31, 0x49, 0x34, 0x53, 0x2b, 0x36, 0x2b, 0x4a,
+    0x4e, 0x4d, 0x33, 0x47, 0x4f, 0x47, 0x76, 0x44, 0x43, 0x0a, 0x2b, 0x4d,
+    0x63, 0x64, 0x6f, 0x71, 0x30, 0x44, 0x6c, 0x79, 0x7a, 0x34, 0x7a, 0x79,
+    0x58, 0x47, 0x39, 0x72, 0x67, 0x6b, 0x4d, 0x62, 0x46, 0x6a, 0x58, 0x5a,
+    0x4a, 0x2f, 0x59, 0x2f, 0x41, 0x6c, 0x79, 0x56, 0x4d, 0x75, 0x48, 0x37,
+    0x39, 0x4e, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x67, 0x64,
+    0x49, 0x77, 0x67, 0x63, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52,
+    0x30, 0x4f, 0x0a, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4a, 0x57, 0x78, 0x74,
+    0x50, 0x43, 0x55, 0x74, 0x72, 0x33, 0x48, 0x32, 0x74, 0x45, 0x52, 0x43,
+    0x53, 0x47, 0x2b, 0x77, 0x61, 0x39, 0x4a, 0x2f, 0x52, 0x42, 0x37, 0x4d,
+    0x41, 0x73, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x51, 0x45, 0x41,
+    0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48,
+    0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x0a, 0x42, 0x54, 0x41, 0x44,
+    0x41, 0x51, 0x48, 0x2f, 0x4d, 0x49, 0x47, 0x50, 0x42, 0x67, 0x4e, 0x56,
+    0x48, 0x53, 0x4d, 0x45, 0x67, 0x59, 0x63, 0x77, 0x67, 0x59, 0x53, 0x41,
+    0x46, 0x4a, 0x57, 0x78, 0x74, 0x50, 0x43, 0x55, 0x74, 0x72, 0x33, 0x48,
+    0x32, 0x74, 0x45, 0x52, 0x43, 0x53, 0x47, 0x2b, 0x77, 0x61, 0x39, 0x4a,
+    0x2f, 0x52, 0x42, 0x37, 0x6f, 0x57, 0x6d, 0x6b, 0x5a, 0x7a, 0x42, 0x6c,
+    0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x47, 0x45, 0x77, 0x4a, 0x54, 0x52, 0x54, 0x45, 0x55, 0x4d, 0x42, 0x49,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4c, 0x51, 0x57, 0x52,
+    0x6b, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x51, 0x55, 0x49,
+    0x78, 0x48, 0x54, 0x41, 0x62, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73,
+    0x54, 0x46, 0x45, 0x46, 0x6b, 0x0a, 0x5a, 0x46, 0x52, 0x79, 0x64, 0x58,
+    0x4e, 0x30, 0x49, 0x46, 0x52, 0x55, 0x55, 0x43, 0x42, 0x4f, 0x5a, 0x58,
+    0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x4d, 0x53, 0x45, 0x77, 0x48, 0x77,
+    0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x68, 0x42, 0x5a, 0x47,
+    0x52, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x44, 0x62, 0x47,
+    0x46, 0x7a, 0x63, 0x79, 0x41, 0x78, 0x49, 0x45, 0x4e, 0x42, 0x0a, 0x49,
+    0x46, 0x4a, 0x76, 0x62, 0x33, 0x53, 0x43, 0x41, 0x51, 0x45, 0x77, 0x44,
+    0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41,
+    0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41,
+    0x43, 0x78, 0x74, 0x5a, 0x42, 0x73, 0x66, 0x7a, 0x51, 0x33, 0x64, 0x75,
+    0x51, 0x48, 0x36, 0x6c, 0x6d, 0x4d, 0x30, 0x4d, 0x6b, 0x68, 0x48, 0x6d,
+    0x61, 0x36, 0x58, 0x0a, 0x37, 0x66, 0x31, 0x79, 0x46, 0x71, 0x5a, 0x7a,
+    0x52, 0x31, 0x72, 0x30, 0x36, 0x39, 0x33, 0x70, 0x39, 0x64, 0x62, 0x37,
+    0x52, 0x63, 0x77, 0x70, 0x69, 0x55, 0x52, 0x64, 0x76, 0x30, 0x59, 0x35,
+    0x50, 0x65, 0x6a, 0x75, 0x76, 0x45, 0x31, 0x55, 0x68, 0x68, 0x34, 0x64,
+    0x62, 0x4f, 0x4d, 0x58, 0x4a, 0x30, 0x50, 0x68, 0x69, 0x56, 0x59, 0x72,
+    0x71, 0x57, 0x39, 0x79, 0x54, 0x6b, 0x6b, 0x7a, 0x0a, 0x34, 0x33, 0x4a,
+    0x38, 0x4b, 0x69, 0x4f, 0x61, 0x76, 0x44, 0x37, 0x2f, 0x4b, 0x43, 0x72,
+    0x74, 0x6f, 0x2f, 0x38, 0x63, 0x49, 0x37, 0x70, 0x44, 0x56, 0x77, 0x6c,
+    0x6e, 0x54, 0x55, 0x74, 0x69, 0x42, 0x69, 0x33, 0x34, 0x2f, 0x32, 0x79,
+    0x64, 0x59, 0x42, 0x37, 0x59, 0x48, 0x45, 0x74, 0x39, 0x74, 0x54, 0x45,
+    0x76, 0x32, 0x64, 0x42, 0x38, 0x58, 0x66, 0x6a, 0x65, 0x61, 0x34, 0x4d,
+    0x59, 0x0a, 0x65, 0x44, 0x64, 0x58, 0x4c, 0x2b, 0x67, 0x7a, 0x42, 0x32,
+    0x66, 0x66, 0x48, 0x73, 0x64, 0x72, 0x4b, 0x70, 0x56, 0x32, 0x72, 0x6f,
+    0x39, 0x58, 0x6f, 0x2f, 0x44, 0x30, 0x55, 0x72, 0x53, 0x70, 0x55, 0x77,
+    0x6a, 0x50, 0x34, 0x45, 0x2f, 0x54, 0x65, 0x6c, 0x4f, 0x4c, 0x2f, 0x62,
+    0x73, 0x63, 0x56, 0x6a, 0x62, 0x79, 0x2f, 0x72, 0x4b, 0x32, 0x35, 0x58,
+    0x61, 0x37, 0x31, 0x53, 0x4a, 0x6c, 0x0a, 0x70, 0x7a, 0x2f, 0x2b, 0x30,
+    0x57, 0x61, 0x74, 0x43, 0x37, 0x78, 0x72, 0x6d, 0x59, 0x62, 0x76, 0x50,
+    0x33, 0x33, 0x7a, 0x47, 0x44, 0x4c, 0x4b, 0x65, 0x38, 0x62, 0x6a, 0x71,
+    0x32, 0x52, 0x47, 0x6c, 0x66, 0x67, 0x6d, 0x61, 0x64, 0x6c, 0x56, 0x67,
+    0x33, 0x73, 0x73, 0x6c, 0x67, 0x66, 0x2f, 0x57, 0x53, 0x78, 0x45, 0x6f,
+    0x38, 0x62, 0x6c, 0x36, 0x61, 0x6e, 0x63, 0x6f, 0x57, 0x4f, 0x41, 0x0a,
+    0x57, 0x69, 0x46, 0x65, 0x49, 0x63, 0x39, 0x54, 0x56, 0x50, 0x43, 0x36,
+    0x62, 0x34, 0x6e, 0x62, 0x71, 0x4b, 0x71, 0x56, 0x7a, 0x34, 0x76, 0x6a,
+    0x63, 0x63, 0x77, 0x65, 0x47, 0x79, 0x42, 0x45, 0x43, 0x4d, 0x42, 0x36,
+    0x74, 0x6b, 0x44, 0x39, 0x78, 0x4f, 0x51, 0x31, 0x34, 0x52, 0x30, 0x57,
+    0x48, 0x4e, 0x43, 0x38, 0x4b, 0x34, 0x37, 0x57, 0x63, 0x64, 0x6b, 0x3d,
+    0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45,
+    0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72,
+    0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73,
+    0x74, 0x20, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x43,
+    0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x41, 0x64, 0x64,
+    0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, 0x42, 0x20, 0x4f, 0x55, 0x3d,
+    0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74,
+    0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50, 0x20, 0x4e, 0x65,
+    0x74, 0x77, 0x6f, 0x72, 0x6b, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a,
+    0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x64, 0x64, 0x54,
+    0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61,
+    0x6c, 0x20, 0x43, 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d,
+    0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, 0x42, 0x20,
+    0x4f, 0x55, 0x3d, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20,
+    0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50,
+    0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x0a, 0x23, 0x20, 0x4c,
+    0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, 0x64, 0x64, 0x54, 0x72,
+    0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
+    0x20, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72,
+    0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x31, 0x64, 0x3a, 0x33, 0x35, 0x3a, 0x35, 0x34, 0x3a, 0x30,
+    0x34, 0x3a, 0x38, 0x35, 0x3a, 0x37, 0x38, 0x3a, 0x62, 0x30, 0x3a, 0x33,
+    0x66, 0x3a, 0x34, 0x32, 0x3a, 0x34, 0x32, 0x3a, 0x34, 0x64, 0x3a, 0x62,
+    0x66, 0x3a, 0x32, 0x30, 0x3a, 0x37, 0x33, 0x3a, 0x30, 0x61, 0x3a, 0x33,
+    0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x32,
+    0x3a, 0x66, 0x61, 0x3a, 0x66, 0x33, 0x3a, 0x65, 0x32, 0x3a, 0x39, 0x31,
+    0x3a, 0x34, 0x33, 0x3a, 0x35, 0x34, 0x3a, 0x36, 0x38, 0x3a, 0x36, 0x30,
+    0x3a, 0x37, 0x38, 0x3a, 0x35, 0x37, 0x3a, 0x36, 0x39, 0x3a, 0x34, 0x64,
+    0x3a, 0x66, 0x35, 0x3a, 0x65, 0x34, 0x3a, 0x35, 0x62, 0x3a, 0x36, 0x38,
+    0x3a, 0x38, 0x35, 0x3a, 0x31, 0x38, 0x3a, 0x36, 0x38, 0x0a, 0x23, 0x20,
+    0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x38, 0x3a, 0x37,
+    0x66, 0x3a, 0x61, 0x34, 0x3a, 0x35, 0x31, 0x3a, 0x33, 0x38, 0x3a, 0x32,
+    0x32, 0x3a, 0x37, 0x38, 0x3a, 0x66, 0x66, 0x3a, 0x66, 0x30, 0x3a, 0x63,
+    0x38, 0x3a, 0x62, 0x31, 0x3a, 0x31, 0x66, 0x3a, 0x38, 0x64, 0x3a, 0x34,
+    0x33, 0x3a, 0x64, 0x35, 0x3a, 0x37, 0x36, 0x3a, 0x36, 0x37, 0x3a, 0x31,
+    0x63, 0x3a, 0x36, 0x65, 0x3a, 0x62, 0x32, 0x3a, 0x62, 0x63, 0x3a, 0x65,
+    0x61, 0x3a, 0x62, 0x34, 0x3a, 0x31, 0x33, 0x3a, 0x66, 0x62, 0x3a, 0x38,
+    0x33, 0x3a, 0x64, 0x39, 0x3a, 0x36, 0x35, 0x3a, 0x64, 0x30, 0x3a, 0x36,
+    0x64, 0x3a, 0x32, 0x66, 0x3a, 0x66, 0x32, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49,
+    0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a,
+    0x4d, 0x49, 0x49, 0x45, 0x4e, 0x6a, 0x43, 0x43, 0x41, 0x78, 0x36, 0x67,
+    0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e,
+    0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42,
+    0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x76, 0x4d, 0x51, 0x73, 0x77,
+    0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x54,
+    0x52, 0x54, 0x45, 0x55, 0x0a, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x43, 0x68, 0x4d, 0x4c, 0x51, 0x57, 0x52, 0x6b, 0x56, 0x48, 0x4a,
+    0x31, 0x63, 0x33, 0x51, 0x67, 0x51, 0x55, 0x49, 0x78, 0x4a, 0x6a, 0x41,
+    0x6b, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x48, 0x55, 0x46,
+    0x6b, 0x5a, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x56,
+    0x34, 0x64, 0x47, 0x56, 0x79, 0x62, 0x6d, 0x46, 0x73, 0x0a, 0x49, 0x46,
+    0x52, 0x55, 0x55, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33,
+    0x4a, 0x72, 0x4d, 0x53, 0x49, 0x77, 0x49, 0x41, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x44, 0x45, 0x78, 0x6c, 0x42, 0x5a, 0x47, 0x52, 0x55, 0x63, 0x6e,
+    0x56, 0x7a, 0x64, 0x43, 0x42, 0x46, 0x65, 0x48, 0x52, 0x6c, 0x63, 0x6d,
+    0x35, 0x68, 0x62, 0x43, 0x42, 0x44, 0x51, 0x53, 0x42, 0x53, 0x62, 0x32,
+    0x39, 0x30, 0x0a, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x77, 0x4d,
+    0x44, 0x55, 0x7a, 0x4d, 0x44, 0x45, 0x77, 0x4e, 0x44, 0x67, 0x7a, 0x4f,
+    0x46, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x77, 0x4d, 0x44, 0x55, 0x7a, 0x4d,
+    0x44, 0x45, 0x77, 0x4e, 0x44, 0x67, 0x7a, 0x4f, 0x46, 0x6f, 0x77, 0x62,
+    0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42,
+    0x68, 0x4d, 0x43, 0x55, 0x30, 0x55, 0x78, 0x0a, 0x46, 0x44, 0x41, 0x53,
+    0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x43, 0x30, 0x46, 0x6b,
+    0x5a, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x46, 0x43,
+    0x4d, 0x53, 0x59, 0x77, 0x4a, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c,
+    0x45, 0x78, 0x31, 0x42, 0x5a, 0x47, 0x52, 0x55, 0x63, 0x6e, 0x56, 0x7a,
+    0x64, 0x43, 0x42, 0x46, 0x65, 0x48, 0x52, 0x6c, 0x63, 0x6d, 0x35, 0x68,
+    0x0a, 0x62, 0x43, 0x42, 0x55, 0x56, 0x46, 0x41, 0x67, 0x54, 0x6d, 0x56,
+    0x30, 0x64, 0x32, 0x39, 0x79, 0x61, 0x7a, 0x45, 0x69, 0x4d, 0x43, 0x41,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x5a, 0x51, 0x57, 0x52,
+    0x6b, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x52, 0x58, 0x68,
+    0x30, 0x5a, 0x58, 0x4a, 0x75, 0x59, 0x57, 0x77, 0x67, 0x51, 0x30, 0x45,
+    0x67, 0x55, 0x6d, 0x39, 0x76, 0x0a, 0x64, 0x44, 0x43, 0x43, 0x41, 0x53,
+    0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76,
+    0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67,
+    0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67,
+    0x45, 0x42, 0x41, 0x4c, 0x66, 0x33, 0x47, 0x6a, 0x50, 0x6d, 0x38, 0x67,
+    0x41, 0x45, 0x4c, 0x54, 0x6e, 0x67, 0x54, 0x6c, 0x76, 0x74, 0x0a, 0x48,
+    0x37, 0x78, 0x73, 0x44, 0x38, 0x32, 0x31, 0x2b, 0x69, 0x4f, 0x32, 0x7a,
+    0x74, 0x36, 0x62, 0x45, 0x54, 0x4f, 0x58, 0x70, 0x43, 0x6c, 0x4d, 0x66,
+    0x5a, 0x4f, 0x66, 0x76, 0x55, 0x71, 0x38, 0x6b, 0x2b, 0x30, 0x44, 0x47,
+    0x75, 0x4f, 0x50, 0x7a, 0x2b, 0x56, 0x74, 0x55, 0x46, 0x72, 0x57, 0x6c,
+    0x79, 0x6d, 0x55, 0x57, 0x6f, 0x43, 0x77, 0x53, 0x58, 0x72, 0x62, 0x4c,
+    0x70, 0x58, 0x39, 0x0a, 0x75, 0x4d, 0x71, 0x2f, 0x4e, 0x7a, 0x67, 0x74,
+    0x48, 0x6a, 0x36, 0x52, 0x51, 0x61, 0x31, 0x77, 0x56, 0x73, 0x66, 0x77,
+    0x54, 0x7a, 0x2f, 0x6f, 0x4d, 0x70, 0x35, 0x30, 0x79, 0x73, 0x69, 0x51,
+    0x56, 0x4f, 0x6e, 0x47, 0x58, 0x77, 0x39, 0x34, 0x6e, 0x5a, 0x70, 0x41,
+    0x50, 0x41, 0x36, 0x73, 0x59, 0x61, 0x70, 0x65, 0x46, 0x49, 0x2b, 0x65,
+    0x68, 0x36, 0x46, 0x71, 0x55, 0x4e, 0x7a, 0x58, 0x0a, 0x6d, 0x6b, 0x36,
+    0x76, 0x42, 0x62, 0x4f, 0x6d, 0x63, 0x5a, 0x53, 0x63, 0x63, 0x62, 0x4e,
+    0x51, 0x59, 0x41, 0x72, 0x48, 0x45, 0x35, 0x30, 0x34, 0x42, 0x34, 0x59,
+    0x43, 0x71, 0x4f, 0x6d, 0x6f, 0x61, 0x53, 0x59, 0x59, 0x6b, 0x4b, 0x74,
+    0x4d, 0x73, 0x45, 0x38, 0x6a, 0x71, 0x7a, 0x70, 0x50, 0x68, 0x4e, 0x6a,
+    0x66, 0x7a, 0x70, 0x2f, 0x68, 0x61, 0x57, 0x2b, 0x37, 0x31, 0x30, 0x4c,
+    0x58, 0x0a, 0x61, 0x30, 0x54, 0x6b, 0x78, 0x36, 0x33, 0x75, 0x62, 0x55,
+    0x46, 0x66, 0x63, 0x6c, 0x70, 0x78, 0x43, 0x44, 0x65, 0x7a, 0x65, 0x57,
+    0x57, 0x6b, 0x57, 0x61, 0x43, 0x55, 0x4e, 0x2f, 0x63, 0x41, 0x4c, 0x77,
+    0x33, 0x43, 0x6b, 0x6e, 0x4c, 0x61, 0x30, 0x44, 0x68, 0x79, 0x32, 0x78,
+    0x53, 0x6f, 0x52, 0x63, 0x52, 0x64, 0x4b, 0x6e, 0x32, 0x33, 0x74, 0x4e,
+    0x62, 0x45, 0x37, 0x71, 0x7a, 0x4e, 0x0a, 0x45, 0x30, 0x53, 0x33, 0x79,
+    0x53, 0x76, 0x64, 0x51, 0x77, 0x41, 0x6c, 0x2b, 0x6d, 0x47, 0x35, 0x61,
+    0x57, 0x70, 0x59, 0x49, 0x78, 0x47, 0x33, 0x70, 0x7a, 0x4f, 0x50, 0x56,
+    0x6e, 0x56, 0x5a, 0x39, 0x63, 0x30, 0x70, 0x31, 0x30, 0x61, 0x33, 0x43,
+    0x69, 0x74, 0x6c, 0x74, 0x74, 0x4e, 0x43, 0x62, 0x78, 0x57, 0x79, 0x75,
+    0x48, 0x76, 0x37, 0x37, 0x2b, 0x6c, 0x64, 0x55, 0x39, 0x55, 0x30, 0x0a,
+    0x57, 0x69, 0x63, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4f, 0x42,
+    0x33, 0x44, 0x43, 0x42, 0x32, 0x54, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56,
+    0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x72, 0x62, 0x32, 0x59,
+    0x65, 0x6a, 0x53, 0x30, 0x4a, 0x76, 0x66, 0x36, 0x78, 0x43, 0x5a, 0x55,
+    0x37, 0x77, 0x4f, 0x39, 0x34, 0x43, 0x54, 0x4c, 0x56, 0x42, 0x6f, 0x77,
+    0x43, 0x77, 0x59, 0x44, 0x0a, 0x56, 0x52, 0x30, 0x50, 0x42, 0x41, 0x51,
+    0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55,
+    0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d,
+    0x42, 0x41, 0x66, 0x38, 0x77, 0x67, 0x5a, 0x6b, 0x47, 0x41, 0x31, 0x55,
+    0x64, 0x49, 0x77, 0x53, 0x42, 0x6b, 0x54, 0x43, 0x42, 0x6a, 0x6f, 0x41,
+    0x55, 0x72, 0x62, 0x32, 0x59, 0x65, 0x6a, 0x53, 0x30, 0x0a, 0x4a, 0x76,
+    0x66, 0x36, 0x78, 0x43, 0x5a, 0x55, 0x37, 0x77, 0x4f, 0x39, 0x34, 0x43,
+    0x54, 0x4c, 0x56, 0x42, 0x71, 0x68, 0x63, 0x36, 0x52, 0x78, 0x4d, 0x47,
+    0x38, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41,
+    0x59, 0x54, 0x41, 0x6c, 0x4e, 0x46, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67,
+    0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x74, 0x42, 0x5a, 0x47,
+    0x52, 0x55, 0x0a, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x42, 0x51,
+    0x6a, 0x45, 0x6d, 0x4d, 0x43, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43,
+    0x78, 0x4d, 0x64, 0x51, 0x57, 0x52, 0x6b, 0x56, 0x48, 0x4a, 0x31, 0x63,
+    0x33, 0x51, 0x67, 0x52, 0x58, 0x68, 0x30, 0x5a, 0x58, 0x4a, 0x75, 0x59,
+    0x57, 0x77, 0x67, 0x56, 0x46, 0x52, 0x51, 0x49, 0x45, 0x35, 0x6c, 0x64,
+    0x48, 0x64, 0x76, 0x63, 0x6d, 0x73, 0x78, 0x0a, 0x49, 0x6a, 0x41, 0x67,
+    0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x47, 0x55, 0x46, 0x6b,
+    0x5a, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x56, 0x34,
+    0x64, 0x47, 0x56, 0x79, 0x62, 0x6d, 0x46, 0x73, 0x49, 0x45, 0x4e, 0x42,
+    0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x53, 0x43, 0x41, 0x51, 0x45, 0x77,
+    0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e,
+    0x0a, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45,
+    0x42, 0x41, 0x4c, 0x43, 0x62, 0x34, 0x49, 0x55, 0x6c, 0x77, 0x74, 0x59,
+    0x6a, 0x34, 0x67, 0x2b, 0x57, 0x42, 0x70, 0x4b, 0x64, 0x51, 0x5a, 0x69,
+    0x63, 0x32, 0x59, 0x52, 0x35, 0x67, 0x64, 0x6b, 0x65, 0x57, 0x78, 0x51,
+    0x48, 0x49, 0x7a, 0x5a, 0x6c, 0x6a, 0x37, 0x44, 0x59, 0x64, 0x37, 0x75,
+    0x73, 0x51, 0x57, 0x78, 0x48, 0x0a, 0x59, 0x49, 0x4e, 0x52, 0x73, 0x50,
+    0x6b, 0x79, 0x50, 0x65, 0x66, 0x38, 0x39, 0x69, 0x59, 0x54, 0x78, 0x34,
+    0x41, 0x57, 0x70, 0x62, 0x39, 0x61, 0x2f, 0x49, 0x66, 0x50, 0x65, 0x48,
+    0x6d, 0x4a, 0x49, 0x5a, 0x72, 0x69, 0x54, 0x41, 0x63, 0x4b, 0x68, 0x6a,
+    0x57, 0x38, 0x38, 0x74, 0x35, 0x52, 0x78, 0x4e, 0x4b, 0x57, 0x74, 0x39,
+    0x78, 0x2b, 0x54, 0x75, 0x35, 0x77, 0x2f, 0x52, 0x77, 0x35, 0x0a, 0x36,
+    0x77, 0x77, 0x43, 0x55, 0x52, 0x51, 0x74, 0x6a, 0x72, 0x30, 0x57, 0x34,
+    0x4d, 0x48, 0x66, 0x52, 0x6e, 0x58, 0x6e, 0x4a, 0x4b, 0x33, 0x73, 0x39,
+    0x45, 0x4b, 0x30, 0x68, 0x5a, 0x4e, 0x77, 0x45, 0x47, 0x65, 0x36, 0x6e,
+    0x51, 0x59, 0x31, 0x53, 0x68, 0x6a, 0x54, 0x4b, 0x33, 0x72, 0x4d, 0x55,
+    0x55, 0x4b, 0x68, 0x65, 0x6d, 0x50, 0x52, 0x35, 0x72, 0x75, 0x68, 0x78,
+    0x53, 0x76, 0x43, 0x0a, 0x4e, 0x72, 0x34, 0x54, 0x44, 0x65, 0x61, 0x39,
+    0x59, 0x33, 0x35, 0x35, 0x65, 0x36, 0x63, 0x4a, 0x44, 0x55, 0x43, 0x72,
+    0x61, 0x74, 0x32, 0x50, 0x69, 0x73, 0x50, 0x32, 0x39, 0x6f, 0x77, 0x61,
+    0x51, 0x67, 0x56, 0x52, 0x31, 0x45, 0x58, 0x31, 0x6e, 0x36, 0x64, 0x69,
+    0x49, 0x57, 0x67, 0x56, 0x49, 0x45, 0x4d, 0x38, 0x6d, 0x65, 0x64, 0x38,
+    0x76, 0x53, 0x54, 0x59, 0x71, 0x5a, 0x45, 0x58, 0x0a, 0x63, 0x34, 0x67,
+    0x2f, 0x56, 0x68, 0x73, 0x78, 0x4f, 0x42, 0x69, 0x30, 0x63, 0x51, 0x2b,
+    0x61, 0x7a, 0x63, 0x67, 0x4f, 0x6e, 0x6f, 0x34, 0x75, 0x47, 0x2b, 0x47,
+    0x4d, 0x6d, 0x49, 0x50, 0x4c, 0x48, 0x7a, 0x48, 0x78, 0x52, 0x45, 0x7a,
+    0x47, 0x42, 0x48, 0x4e, 0x4a, 0x64, 0x6d, 0x41, 0x50, 0x78, 0x2f, 0x69,
+    0x39, 0x46, 0x34, 0x42, 0x72, 0x4c, 0x75, 0x6e, 0x4d, 0x54, 0x41, 0x35,
+    0x61, 0x0a, 0x6d, 0x6e, 0x6b, 0x50, 0x49, 0x41, 0x6f, 0x75, 0x31, 0x5a,
+    0x35, 0x6a, 0x4a, 0x68, 0x35, 0x56, 0x6b, 0x70, 0x54, 0x59, 0x67, 0x68,
+    0x64, 0x61, 0x65, 0x39, 0x43, 0x38, 0x78, 0x34, 0x39, 0x4f, 0x68, 0x67,
+    0x51, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20,
+    0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75,
+    0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x64, 0x64, 0x54, 0x72,
+    0x75, 0x73, 0x74, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x43,
+    0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x41, 0x64, 0x64,
+    0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, 0x42, 0x20, 0x4f, 0x55, 0x3d,
+    0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x54, 0x54, 0x50,
+    0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x0a, 0x23, 0x20, 0x53,
+    0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41,
+    0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x75, 0x62, 0x6c,
+    0x69, 0x63, 0x20, 0x43, 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f,
+    0x3d, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, 0x42,
+    0x20, 0x4f, 0x55, 0x3d, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74,
+    0x20, 0x54, 0x54, 0x50, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
+    0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41,
+    0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x75, 0x62, 0x6c,
+    0x69, 0x63, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20,
+    0x52, 0x6f, 0x6f, 0x74, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69,
+    0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x63, 0x31, 0x3a, 0x36, 0x32, 0x3a, 0x33, 0x65, 0x3a, 0x32, 0x33,
+    0x3a, 0x63, 0x35, 0x3a, 0x38, 0x32, 0x3a, 0x37, 0x33, 0x3a, 0x39, 0x63,
+    0x3a, 0x30, 0x33, 0x3a, 0x35, 0x39, 0x3a, 0x34, 0x62, 0x3a, 0x32, 0x62,
+    0x3a, 0x65, 0x39, 0x3a, 0x37, 0x37, 0x3a, 0x34, 0x39, 0x3a, 0x37, 0x66,
+    0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x61, 0x3a,
+    0x62, 0x36, 0x3a, 0x32, 0x38, 0x3a, 0x34, 0x38, 0x3a, 0x35, 0x65, 0x3a,
+    0x37, 0x38, 0x3a, 0x66, 0x62, 0x3a, 0x66, 0x33, 0x3a, 0x61, 0x64, 0x3a,
+    0x39, 0x65, 0x3a, 0x37, 0x39, 0x3a, 0x31, 0x30, 0x3a, 0x64, 0x64, 0x3a,
+    0x36, 0x62, 0x3a, 0x64, 0x66, 0x3a, 0x39, 0x39, 0x3a, 0x37, 0x32, 0x3a,
+    0x32, 0x63, 0x3a, 0x39, 0x36, 0x3a, 0x65, 0x35, 0x0a, 0x23, 0x20, 0x53,
+    0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x37, 0x3a, 0x39, 0x31,
+    0x3a, 0x63, 0x61, 0x3a, 0x30, 0x37, 0x3a, 0x34, 0x39, 0x3a, 0x62, 0x32,
+    0x3a, 0x30, 0x37, 0x3a, 0x38, 0x32, 0x3a, 0x61, 0x61, 0x3a, 0x64, 0x33,
+    0x3a, 0x63, 0x37, 0x3a, 0x64, 0x37, 0x3a, 0x62, 0x64, 0x3a, 0x30, 0x63,
+    0x3a, 0x64, 0x66, 0x3a, 0x63, 0x39, 0x3a, 0x34, 0x38, 0x3a, 0x35, 0x38,
+    0x3a, 0x33, 0x35, 0x3a, 0x38, 0x34, 0x3a, 0x33, 0x65, 0x3a, 0x62, 0x32,
+    0x3a, 0x64, 0x37, 0x3a, 0x39, 0x39, 0x3a, 0x36, 0x30, 0x3a, 0x30, 0x39,
+    0x3a, 0x63, 0x65, 0x3a, 0x34, 0x33, 0x3a, 0x61, 0x62, 0x3a, 0x36, 0x63,
+    0x3a, 0x36, 0x39, 0x3a, 0x32, 0x37, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d,
+    0x49, 0x49, 0x45, 0x46, 0x54, 0x43, 0x43, 0x41, 0x76, 0x32, 0x67, 0x41,
+    0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42,
+    0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41,
+    0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x6b, 0x4d, 0x51, 0x73, 0x77, 0x43,
+    0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x54, 0x52,
+    0x54, 0x45, 0x55, 0x0a, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x43, 0x68, 0x4d, 0x4c, 0x51, 0x57, 0x52, 0x6b, 0x56, 0x48, 0x4a, 0x31,
+    0x63, 0x33, 0x51, 0x67, 0x51, 0x55, 0x49, 0x78, 0x48, 0x54, 0x41, 0x62,
+    0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x46, 0x45, 0x46, 0x6b,
+    0x5a, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x46, 0x52, 0x55,
+    0x55, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x0a, 0x62, 0x33, 0x4a,
+    0x72, 0x4d, 0x53, 0x41, 0x77, 0x48, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x44, 0x45, 0x78, 0x64, 0x42, 0x5a, 0x47, 0x52, 0x55, 0x63, 0x6e, 0x56,
+    0x7a, 0x64, 0x43, 0x42, 0x51, 0x64, 0x57, 0x4a, 0x73, 0x61, 0x57, 0x4d,
+    0x67, 0x51, 0x30, 0x45, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x44, 0x41,
+    0x65, 0x46, 0x77, 0x30, 0x77, 0x4d, 0x44, 0x41, 0x31, 0x4d, 0x7a, 0x41,
+    0x78, 0x0a, 0x4d, 0x44, 0x51, 0x78, 0x4e, 0x54, 0x42, 0x61, 0x46, 0x77,
+    0x30, 0x79, 0x4d, 0x44, 0x41, 0x31, 0x4d, 0x7a, 0x41, 0x78, 0x4d, 0x44,
+    0x51, 0x78, 0x4e, 0x54, 0x42, 0x61, 0x4d, 0x47, 0x51, 0x78, 0x43, 0x7a,
+    0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c,
+    0x4e, 0x46, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x4b, 0x45, 0x77, 0x74, 0x42, 0x0a, 0x5a, 0x47, 0x52, 0x55, 0x63,
+    0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x42, 0x51, 0x6a, 0x45, 0x64, 0x4d,
+    0x42, 0x73, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x55, 0x51,
+    0x57, 0x52, 0x6b, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x56,
+    0x46, 0x52, 0x51, 0x49, 0x45, 0x35, 0x6c, 0x64, 0x48, 0x64, 0x76, 0x63,
+    0x6d, 0x73, 0x78, 0x49, 0x44, 0x41, 0x65, 0x42, 0x67, 0x4e, 0x56, 0x0a,
+    0x42, 0x41, 0x4d, 0x54, 0x46, 0x30, 0x46, 0x6b, 0x5a, 0x46, 0x52, 0x79,
+    0x64, 0x58, 0x4e, 0x30, 0x49, 0x46, 0x42, 0x31, 0x59, 0x6d, 0x78, 0x70,
+    0x59, 0x79, 0x42, 0x44, 0x51, 0x53, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30,
+    0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71,
+    0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46,
+    0x41, 0x41, 0x4f, 0x43, 0x0a, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49,
+    0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x36, 0x52, 0x6f,
+    0x77, 0x6a, 0x34, 0x4f, 0x49, 0x46, 0x4d, 0x45, 0x67, 0x32, 0x44, 0x79,
+    0x62, 0x6a, 0x78, 0x74, 0x2b, 0x41, 0x33, 0x53, 0x37, 0x32, 0x6d, 0x6e,
+    0x54, 0x52, 0x71, 0x58, 0x34, 0x6a, 0x73, 0x49, 0x4d, 0x45, 0x5a, 0x42,
+    0x52, 0x70, 0x53, 0x39, 0x6d, 0x56, 0x45, 0x42, 0x56, 0x0a, 0x36, 0x74,
+    0x73, 0x66, 0x53, 0x6c, 0x62, 0x75, 0x6e, 0x79, 0x4e, 0x75, 0x39, 0x44,
+    0x6e, 0x4c, 0x6f, 0x62, 0x6c, 0x76, 0x38, 0x6e, 0x37, 0x35, 0x58, 0x59,
+    0x63, 0x6d, 0x59, 0x5a, 0x34, 0x63, 0x2b, 0x4f, 0x4c, 0x73, 0x70, 0x6f,
+    0x48, 0x34, 0x49, 0x63, 0x55, 0x6b, 0x7a, 0x42, 0x45, 0x4d, 0x50, 0x39,
+    0x73, 0x6d, 0x63, 0x6e, 0x72, 0x48, 0x41, 0x5a, 0x63, 0x48, 0x46, 0x2f,
+    0x6e, 0x58, 0x0a, 0x47, 0x43, 0x77, 0x77, 0x66, 0x51, 0x35, 0x36, 0x48,
+    0x6d, 0x49, 0x65, 0x78, 0x6b, 0x76, 0x41, 0x2f, 0x58, 0x31, 0x69, 0x64,
+    0x39, 0x4e, 0x45, 0x48, 0x69, 0x66, 0x32, 0x50, 0x30, 0x74, 0x45, 0x73,
+    0x37, 0x63, 0x34, 0x32, 0x54, 0x6b, 0x66, 0x59, 0x4e, 0x56, 0x52, 0x6b,
+    0x6e, 0x4d, 0x44, 0x74, 0x41, 0x42, 0x70, 0x34, 0x2f, 0x4d, 0x55, 0x54,
+    0x75, 0x37, 0x52, 0x33, 0x41, 0x6e, 0x50, 0x0a, 0x64, 0x7a, 0x52, 0x47,
+    0x55, 0x4c, 0x44, 0x34, 0x45, 0x66, 0x4c, 0x2b, 0x4f, 0x48, 0x6e, 0x33,
+    0x42, 0x7a, 0x6e, 0x2b, 0x55, 0x5a, 0x4b, 0x58, 0x43, 0x31, 0x73, 0x49,
+    0x58, 0x7a, 0x53, 0x47, 0x41, 0x61, 0x32, 0x49, 0x6c, 0x2b, 0x74, 0x6d,
+    0x7a, 0x56, 0x37, 0x52, 0x2f, 0x39, 0x78, 0x39, 0x38, 0x6f, 0x54, 0x61,
+    0x75, 0x6e, 0x65, 0x74, 0x33, 0x49, 0x41, 0x49, 0x78, 0x36, 0x65, 0x48,
+    0x0a, 0x31, 0x6c, 0x57, 0x66, 0x6c, 0x32, 0x72, 0x6f, 0x79, 0x42, 0x46,
+    0x6b, 0x75, 0x75, 0x63, 0x5a, 0x4b, 0x54, 0x38, 0x52, 0x73, 0x33, 0x69,
+    0x51, 0x68, 0x43, 0x42, 0x53, 0x57, 0x78, 0x48, 0x76, 0x65, 0x4e, 0x43,
+    0x44, 0x39, 0x74, 0x56, 0x49, 0x6b, 0x4e, 0x41, 0x77, 0x48, 0x4d, 0x2b,
+    0x41, 0x2b, 0x57, 0x44, 0x2b, 0x65, 0x65, 0x53, 0x49, 0x38, 0x74, 0x30,
+    0x41, 0x36, 0x35, 0x52, 0x46, 0x0a, 0x36, 0x32, 0x57, 0x55, 0x61, 0x55,
+    0x43, 0x36, 0x77, 0x4e, 0x57, 0x30, 0x75, 0x4c, 0x70, 0x39, 0x42, 0x42,
+    0x47, 0x6f, 0x36, 0x7a, 0x45, 0x46, 0x6c, 0x70, 0x52, 0x4f, 0x57, 0x43,
+    0x47, 0x4f, 0x6e, 0x39, 0x42, 0x67, 0x2f, 0x51, 0x49, 0x44, 0x41, 0x51,
+    0x41, 0x42, 0x6f, 0x34, 0x48, 0x52, 0x4d, 0x49, 0x48, 0x4f, 0x4d, 0x42,
+    0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x0a, 0x42,
+    0x42, 0x53, 0x42, 0x50, 0x6a, 0x66, 0x59, 0x6b, 0x72, 0x41, 0x66, 0x64,
+    0x35, 0x39, 0x63, 0x74, 0x4b, 0x74, 0x7a, 0x71, 0x75, 0x66, 0x32, 0x4e,
+    0x47, 0x41, 0x76, 0x2b, 0x6a, 0x41, 0x4c, 0x42, 0x67, 0x4e, 0x56, 0x48,
+    0x51, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x44,
+    0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42,
+    0x41, 0x55, 0x77, 0x0a, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x43, 0x42,
+    0x6a, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6a, 0x42, 0x49, 0x47, 0x47,
+    0x4d, 0x49, 0x47, 0x44, 0x67, 0x42, 0x53, 0x42, 0x50, 0x6a, 0x66, 0x59,
+    0x6b, 0x72, 0x41, 0x66, 0x64, 0x35, 0x39, 0x63, 0x74, 0x4b, 0x74, 0x7a,
+    0x71, 0x75, 0x66, 0x32, 0x4e, 0x47, 0x41, 0x76, 0x2b, 0x71, 0x46, 0x6f,
+    0x70, 0x47, 0x59, 0x77, 0x5a, 0x44, 0x45, 0x4c, 0x0a, 0x4d, 0x41, 0x6b,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x55, 0x30, 0x55,
+    0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f,
+    0x54, 0x43, 0x30, 0x46, 0x6b, 0x5a, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e,
+    0x30, 0x49, 0x45, 0x46, 0x43, 0x4d, 0x52, 0x30, 0x77, 0x47, 0x77, 0x59,
+    0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x52, 0x42, 0x5a, 0x47, 0x52,
+    0x55, 0x0a, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x55, 0x56, 0x46,
+    0x41, 0x67, 0x54, 0x6d, 0x56, 0x30, 0x64, 0x32, 0x39, 0x79, 0x61, 0x7a,
+    0x45, 0x67, 0x4d, 0x42, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78,
+    0x4d, 0x58, 0x51, 0x57, 0x52, 0x6b, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33,
+    0x51, 0x67, 0x55, 0x48, 0x56, 0x69, 0x62, 0x47, 0x6c, 0x6a, 0x49, 0x45,
+    0x4e, 0x42, 0x49, 0x46, 0x4a, 0x76, 0x0a, 0x62, 0x33, 0x53, 0x43, 0x41,
+    0x51, 0x45, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68,
+    0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x67,
+    0x67, 0x45, 0x42, 0x41, 0x41, 0x50, 0x33, 0x46, 0x55, 0x72, 0x34, 0x4a,
+    0x4e, 0x6f, 0x6a, 0x56, 0x68, 0x61, 0x54, 0x64, 0x74, 0x30, 0x32, 0x4b,
+    0x4c, 0x6d, 0x75, 0x47, 0x37, 0x6a, 0x44, 0x38, 0x57, 0x53, 0x36, 0x0a,
+    0x49, 0x42, 0x68, 0x34, 0x6c, 0x53, 0x6b, 0x6e, 0x56, 0x77, 0x57, 0x38,
+    0x66, 0x43, 0x72, 0x30, 0x75, 0x56, 0x46, 0x56, 0x32, 0x6f, 0x63, 0x43,
+    0x33, 0x67, 0x38, 0x57, 0x46, 0x7a, 0x48, 0x34, 0x71, 0x6e, 0x6b, 0x75,
+    0x43, 0x52, 0x4f, 0x37, 0x72, 0x37, 0x49, 0x67, 0x47, 0x52, 0x4c, 0x6c,
+    0x6b, 0x2f, 0x6c, 0x4c, 0x2b, 0x59, 0x50, 0x6f, 0x52, 0x4e, 0x57, 0x79,
+    0x51, 0x53, 0x57, 0x2f, 0x0a, 0x69, 0x48, 0x56, 0x76, 0x2f, 0x78, 0x44,
+    0x38, 0x53, 0x6c, 0x54, 0x51, 0x58, 0x2f, 0x44, 0x36, 0x37, 0x7a, 0x5a,
+    0x7a, 0x66, 0x52, 0x73, 0x32, 0x52, 0x63, 0x59, 0x68, 0x62, 0x62, 0x51,
+    0x56, 0x75, 0x45, 0x37, 0x50, 0x6e, 0x46, 0x79, 0x6c, 0x50, 0x56, 0x6f,
+    0x41, 0x6a, 0x67, 0x62, 0x6a, 0x50, 0x47, 0x73, 0x79, 0x65, 0x2f, 0x4b,
+    0x66, 0x38, 0x4c, 0x62, 0x39, 0x33, 0x2f, 0x41, 0x6f, 0x0a, 0x47, 0x45,
+    0x6a, 0x77, 0x78, 0x72, 0x7a, 0x51, 0x76, 0x7a, 0x53, 0x41, 0x6c, 0x73,
+    0x4a, 0x4b, 0x73, 0x57, 0x32, 0x4f, 0x78, 0x35, 0x42, 0x46, 0x33, 0x69,
+    0x39, 0x6e, 0x72, 0x45, 0x55, 0x45, 0x6f, 0x33, 0x72, 0x63, 0x56, 0x5a,
+    0x4c, 0x4a, 0x52, 0x32, 0x62, 0x59, 0x47, 0x6f, 0x7a, 0x48, 0x37, 0x5a,
+    0x78, 0x4f, 0x6d, 0x75, 0x41, 0x53, 0x75, 0x37, 0x56, 0x71, 0x54, 0x49,
+    0x54, 0x68, 0x0a, 0x34, 0x53, 0x49, 0x4e, 0x68, 0x77, 0x42, 0x6b, 0x2f,
+    0x6f, 0x78, 0x39, 0x59, 0x6a, 0x6c, 0x6c, 0x70, 0x75, 0x39, 0x43, 0x74,
+    0x6f, 0x41, 0x6c, 0x45, 0x6d, 0x45, 0x42, 0x71, 0x43, 0x51, 0x54, 0x63,
+    0x41, 0x41, 0x52, 0x4a, 0x6c, 0x2f, 0x36, 0x4e, 0x56, 0x44, 0x46, 0x53,
+    0x4d, 0x77, 0x47, 0x52, 0x2b, 0x67, 0x6e, 0x32, 0x48, 0x43, 0x4e, 0x58,
+    0x32, 0x54, 0x6d, 0x6f, 0x55, 0x51, 0x6d, 0x0a, 0x58, 0x69, 0x4c, 0x73,
+    0x6b, 0x73, 0x33, 0x2f, 0x51, 0x70, 0x70, 0x45, 0x49, 0x57, 0x31, 0x63,
+    0x78, 0x65, 0x4d, 0x69, 0x48, 0x56, 0x39, 0x48, 0x45, 0x75, 0x66, 0x4f,
+    0x58, 0x31, 0x33, 0x36, 0x32, 0x4b, 0x71, 0x78, 0x4d, 0x79, 0x33, 0x5a,
+    0x64, 0x76, 0x4a, 0x4f, 0x4f, 0x6a, 0x4d, 0x4d, 0x4b, 0x37, 0x4d, 0x74,
+    0x6b, 0x41, 0x59, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e,
+    0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54,
+    0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73,
+    0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x64, 0x64,
+    0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x51, 0x75, 0x61, 0x6c, 0x69, 0x66,
+    0x69, 0x65, 0x64, 0x20, 0x43, 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+    0x4f, 0x3d, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41,
+    0x42, 0x20, 0x4f, 0x55, 0x3d, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73,
+    0x74, 0x20, 0x54, 0x54, 0x50, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72,
+    0x6b, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a,
+    0x20, 0x43, 0x4e, 0x3d, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74,
+    0x20, 0x51, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x43,
+    0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x41, 0x64, 0x64,
+    0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, 0x42, 0x20, 0x4f, 0x55, 0x3d,
+    0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x54, 0x54, 0x50,
+    0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x0a, 0x23, 0x20, 0x4c,
+    0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, 0x64, 0x64, 0x54, 0x72,
+    0x75, 0x73, 0x74, 0x20, 0x51, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65,
+    0x64, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+    0x65, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x0a, 0x23, 0x20, 0x53,
+    0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23, 0x20, 0x4d,
+    0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x32, 0x37, 0x3a, 0x65, 0x63, 0x3a, 0x33, 0x39,
+    0x3a, 0x34, 0x37, 0x3a, 0x63, 0x64, 0x3a, 0x64, 0x61, 0x3a, 0x35, 0x61,
+    0x3a, 0x61, 0x66, 0x3a, 0x65, 0x32, 0x3a, 0x39, 0x61, 0x3a, 0x30, 0x31,
+    0x3a, 0x36, 0x35, 0x3a, 0x32, 0x31, 0x3a, 0x61, 0x39, 0x3a, 0x34, 0x63,
+    0x3a, 0x62, 0x62, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x34, 0x64, 0x3a, 0x32, 0x33, 0x3a, 0x37, 0x38, 0x3a, 0x65, 0x63, 0x3a,
+    0x39, 0x31, 0x3a, 0x39, 0x35, 0x3a, 0x33, 0x39, 0x3a, 0x62, 0x35, 0x3a,
+    0x30, 0x30, 0x3a, 0x37, 0x66, 0x3a, 0x37, 0x35, 0x3a, 0x38, 0x66, 0x3a,
+    0x30, 0x33, 0x3a, 0x33, 0x62, 0x3a, 0x32, 0x31, 0x3a, 0x31, 0x65, 0x3a,
+    0x63, 0x35, 0x3a, 0x34, 0x64, 0x3a, 0x38, 0x62, 0x3a, 0x63, 0x66, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x30,
+    0x3a, 0x39, 0x35, 0x3a, 0x32, 0x31, 0x3a, 0x30, 0x38, 0x3a, 0x30, 0x35,
+    0x3a, 0x64, 0x62, 0x3a, 0x34, 0x62, 0x3a, 0x62, 0x63, 0x3a, 0x33, 0x35,
+    0x3a, 0x35, 0x65, 0x3a, 0x34, 0x34, 0x3a, 0x32, 0x38, 0x3a, 0x64, 0x38,
+    0x3a, 0x66, 0x64, 0x3a, 0x36, 0x65, 0x3a, 0x63, 0x32, 0x3a, 0x63, 0x64,
+    0x3a, 0x65, 0x33, 0x3a, 0x61, 0x62, 0x3a, 0x35, 0x66, 0x3a, 0x62, 0x39,
+    0x3a, 0x37, 0x61, 0x3a, 0x39, 0x39, 0x3a, 0x34, 0x32, 0x3a, 0x39, 0x38,
+    0x3a, 0x38, 0x65, 0x3a, 0x62, 0x38, 0x3a, 0x66, 0x34, 0x3a, 0x64, 0x63,
+    0x3a, 0x64, 0x30, 0x3a, 0x36, 0x30, 0x3a, 0x31, 0x36, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52,
+    0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x48, 0x6a, 0x43, 0x43, 0x41, 0x77,
+    0x61, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x54,
+    0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77,
+    0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x6e, 0x4d, 0x51,
+    0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77,
+    0x4a, 0x54, 0x52, 0x54, 0x45, 0x55, 0x0a, 0x4d, 0x42, 0x49, 0x47, 0x41,
+    0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4c, 0x51, 0x57, 0x52, 0x6b, 0x56,
+    0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x51, 0x55, 0x49, 0x78, 0x48,
+    0x54, 0x41, 0x62, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x46,
+    0x45, 0x46, 0x6b, 0x5a, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49,
+    0x46, 0x52, 0x55, 0x55, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x0a,
+    0x62, 0x33, 0x4a, 0x72, 0x4d, 0x53, 0x4d, 0x77, 0x49, 0x51, 0x59, 0x44,
+    0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x70, 0x42, 0x5a, 0x47, 0x52, 0x55,
+    0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x52, 0x64, 0x57, 0x46, 0x73,
+    0x61, 0x57, 0x5a, 0x70, 0x5a, 0x57, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67,
+    0x55, 0x6d, 0x39, 0x76, 0x64, 0x44, 0x41, 0x65, 0x46, 0x77, 0x30, 0x77,
+    0x4d, 0x44, 0x41, 0x31, 0x0a, 0x4d, 0x7a, 0x41, 0x78, 0x4d, 0x44, 0x51,
+    0x30, 0x4e, 0x54, 0x42, 0x61, 0x46, 0x77, 0x30, 0x79, 0x4d, 0x44, 0x41,
+    0x31, 0x4d, 0x7a, 0x41, 0x78, 0x4d, 0x44, 0x51, 0x30, 0x4e, 0x54, 0x42,
+    0x61, 0x4d, 0x47, 0x63, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e,
+    0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x4e, 0x46, 0x4d, 0x52, 0x51,
+    0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x0a, 0x45, 0x77,
+    0x74, 0x42, 0x5a, 0x47, 0x52, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43,
+    0x42, 0x42, 0x51, 0x6a, 0x45, 0x64, 0x4d, 0x42, 0x73, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x43, 0x78, 0x4d, 0x55, 0x51, 0x57, 0x52, 0x6b, 0x56, 0x48,
+    0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x56, 0x46, 0x52, 0x51, 0x49, 0x45,
+    0x35, 0x6c, 0x64, 0x48, 0x64, 0x76, 0x63, 0x6d, 0x73, 0x78, 0x49, 0x7a,
+    0x41, 0x68, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x47,
+    0x6b, 0x46, 0x6b, 0x5a, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49,
+    0x46, 0x46, 0x31, 0x59, 0x57, 0x78, 0x70, 0x5a, 0x6d, 0x6c, 0x6c, 0x5a,
+    0x43, 0x42, 0x44, 0x51, 0x53, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x4d,
+    0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68,
+    0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x0a, 0x41, 0x51, 0x45, 0x46,
+    0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42,
+    0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x35, 0x42, 0x36, 0x61,
+    0x2f, 0x74, 0x77, 0x4a, 0x57, 0x6f, 0x65, 0x6b, 0x6e, 0x30, 0x65, 0x2b,
+    0x45, 0x56, 0x2b, 0x76, 0x68, 0x44, 0x54, 0x62, 0x59, 0x6a, 0x78, 0x35,
+    0x65, 0x4c, 0x66, 0x70, 0x4d, 0x4c, 0x58, 0x73, 0x44, 0x42, 0x77, 0x71,
+    0x0a, 0x78, 0x42, 0x62, 0x2f, 0x34, 0x4f, 0x78, 0x78, 0x36, 0x34, 0x72,
+    0x31, 0x45, 0x57, 0x37, 0x74, 0x54, 0x77, 0x32, 0x52, 0x30, 0x68, 0x49,
+    0x59, 0x4c, 0x55, 0x6b, 0x56, 0x41, 0x63, 0x4b, 0x6b, 0x49, 0x68, 0x50,
+    0x48, 0x45, 0x57, 0x54, 0x2f, 0x49, 0x68, 0x4b, 0x61, 0x75, 0x59, 0x35,
+    0x63, 0x4c, 0x77, 0x6a, 0x50, 0x63, 0x57, 0x71, 0x7a, 0x5a, 0x77, 0x46,
+    0x5a, 0x38, 0x56, 0x31, 0x47, 0x0a, 0x38, 0x37, 0x42, 0x34, 0x70, 0x66,
+    0x59, 0x4f, 0x51, 0x6e, 0x72, 0x6a, 0x66, 0x78, 0x76, 0x4d, 0x30, 0x50,
+    0x43, 0x33, 0x4b, 0x50, 0x30, 0x71, 0x36, 0x70, 0x36, 0x7a, 0x73, 0x4c,
+    0x6b, 0x45, 0x71, 0x76, 0x33, 0x32, 0x78, 0x37, 0x53, 0x78, 0x75, 0x43,
+    0x71, 0x67, 0x2b, 0x31, 0x6a, 0x78, 0x47, 0x61, 0x42, 0x76, 0x63, 0x43,
+    0x56, 0x2b, 0x50, 0x6d, 0x6c, 0x4b, 0x66, 0x77, 0x38, 0x69, 0x0a, 0x32,
+    0x4f, 0x2b, 0x74, 0x43, 0x42, 0x47, 0x61, 0x4b, 0x5a, 0x6e, 0x68, 0x71,
+    0x6b, 0x52, 0x46, 0x6d, 0x68, 0x4a, 0x65, 0x50, 0x70, 0x31, 0x74, 0x55,
+    0x76, 0x7a, 0x6e, 0x6f, 0x44, 0x31, 0x6f, 0x4c, 0x2f, 0x42, 0x4c, 0x63,
+    0x48, 0x77, 0x54, 0x4f, 0x4b, 0x32, 0x38, 0x46, 0x53, 0x58, 0x78, 0x31,
+    0x73, 0x36, 0x72, 0x6f, 0x73, 0x41, 0x78, 0x31, 0x69, 0x2b, 0x66, 0x34,
+    0x50, 0x38, 0x55, 0x0a, 0x57, 0x66, 0x79, 0x45, 0x6b, 0x39, 0x6d, 0x48,
+    0x66, 0x45, 0x78, 0x55, 0x45, 0x2b, 0x75, 0x66, 0x30, 0x53, 0x30, 0x52,
+    0x2b, 0x42, 0x67, 0x36, 0x4f, 0x74, 0x34, 0x6c, 0x32, 0x66, 0x66, 0x54,
+    0x51, 0x4f, 0x32, 0x6b, 0x42, 0x68, 0x4c, 0x45, 0x4f, 0x2b, 0x47, 0x52,
+    0x77, 0x56, 0x59, 0x31, 0x38, 0x42, 0x54, 0x63, 0x5a, 0x54, 0x59, 0x4a,
+    0x62, 0x71, 0x75, 0x6b, 0x42, 0x38, 0x63, 0x31, 0x0a, 0x30, 0x63, 0x49,
+    0x44, 0x4d, 0x7a, 0x5a, 0x62, 0x64, 0x53, 0x5a, 0x74, 0x51, 0x76, 0x45,
+    0x53, 0x61, 0x30, 0x4e, 0x76, 0x53, 0x33, 0x47, 0x55, 0x2b, 0x6a, 0x51,
+    0x64, 0x37, 0x52, 0x4e, 0x75, 0x79, 0x6f, 0x42, 0x2f, 0x6d, 0x43, 0x39,
+    0x73, 0x75, 0x57, 0x58, 0x59, 0x36, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41,
+    0x42, 0x6f, 0x34, 0x48, 0x55, 0x4d, 0x49, 0x48, 0x52, 0x4d, 0x42, 0x30,
+    0x47, 0x0a, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42,
+    0x51, 0x35, 0x6c, 0x59, 0x74, 0x69, 0x69, 0x31, 0x7a, 0x4a, 0x31, 0x49,
+    0x43, 0x36, 0x57, 0x41, 0x2b, 0x58, 0x50, 0x78, 0x55, 0x49, 0x51, 0x38,
+    0x79, 0x59, 0x70, 0x7a, 0x41, 0x4c, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51,
+    0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x44, 0x77,
+    0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x0a, 0x41, 0x51, 0x48, 0x2f, 0x42,
+    0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x43, 0x42, 0x6b,
+    0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6a, 0x42, 0x49, 0x47, 0x4a, 0x4d,
+    0x49, 0x47, 0x47, 0x67, 0x42, 0x51, 0x35, 0x6c, 0x59, 0x74, 0x69, 0x69,
+    0x31, 0x7a, 0x4a, 0x31, 0x49, 0x43, 0x36, 0x57, 0x41, 0x2b, 0x58, 0x50,
+    0x78, 0x55, 0x49, 0x51, 0x38, 0x79, 0x59, 0x70, 0x36, 0x46, 0x72, 0x0a,
+    0x70, 0x47, 0x6b, 0x77, 0x5a, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x55, 0x30, 0x55, 0x78,
+    0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54,
+    0x43, 0x30, 0x46, 0x6b, 0x5a, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30,
+    0x49, 0x45, 0x46, 0x43, 0x4d, 0x52, 0x30, 0x77, 0x47, 0x77, 0x59, 0x44,
+    0x56, 0x51, 0x51, 0x4c, 0x0a, 0x45, 0x78, 0x52, 0x42, 0x5a, 0x47, 0x52,
+    0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x55, 0x56, 0x46, 0x41,
+    0x67, 0x54, 0x6d, 0x56, 0x30, 0x64, 0x32, 0x39, 0x79, 0x61, 0x7a, 0x45,
+    0x6a, 0x4d, 0x43, 0x45, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d,
+    0x61, 0x51, 0x57, 0x52, 0x6b, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51,
+    0x67, 0x55, 0x58, 0x56, 0x68, 0x62, 0x47, 0x6c, 0x6d, 0x0a, 0x61, 0x57,
+    0x56, 0x6b, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33,
+    0x53, 0x43, 0x41, 0x51, 0x45, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f,
+    0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51,
+    0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x42, 0x6d, 0x72, 0x64, 0x65,
+    0x72, 0x34, 0x69, 0x32, 0x56, 0x68, 0x6c, 0x52, 0x4f, 0x36, 0x61, 0x51,
+    0x54, 0x76, 0x0a, 0x68, 0x73, 0x6f, 0x54, 0x6f, 0x4d, 0x65, 0x71, 0x54,
+    0x32, 0x51, 0x62, 0x50, 0x78, 0x6a, 0x32, 0x71, 0x43, 0x30, 0x73, 0x56,
+    0x59, 0x38, 0x46, 0x74, 0x7a, 0x44, 0x71, 0x51, 0x6d, 0x6f, 0x64, 0x77,
+    0x43, 0x56, 0x52, 0x4c, 0x61, 0x65, 0x2f, 0x44, 0x4c, 0x50, 0x74, 0x37,
+    0x77, 0x68, 0x2f, 0x62, 0x44, 0x78, 0x47, 0x47, 0x75, 0x6f, 0x59, 0x51,
+    0x39, 0x39, 0x32, 0x7a, 0x50, 0x6c, 0x6d, 0x0a, 0x68, 0x70, 0x77, 0x73,
+    0x61, 0x50, 0x58, 0x70, 0x46, 0x2f, 0x67, 0x78, 0x73, 0x78, 0x6a, 0x45,
+    0x31, 0x6b, 0x68, 0x39, 0x49, 0x30, 0x78, 0x6f, 0x77, 0x58, 0x36, 0x37,
+    0x41, 0x52, 0x52, 0x76, 0x78, 0x64, 0x6c, 0x75, 0x33, 0x72, 0x73, 0x45,
+    0x51, 0x6d, 0x72, 0x34, 0x39, 0x6c, 0x78, 0x39, 0x35, 0x64, 0x72, 0x36,
+    0x68, 0x2b, 0x73, 0x4e, 0x4e, 0x56, 0x4a, 0x6e, 0x30, 0x4a, 0x36, 0x58,
+    0x0a, 0x64, 0x67, 0x57, 0x54, 0x50, 0x35, 0x58, 0x48, 0x41, 0x65, 0x5a,
+    0x70, 0x56, 0x54, 0x68, 0x2f, 0x45, 0x47, 0x47, 0x5a, 0x79, 0x65, 0x4e,
+    0x66, 0x70, 0x73, 0x6f, 0x2b, 0x67, 0x6d, 0x4e, 0x49, 0x71, 0x75, 0x49,
+    0x49, 0x53, 0x44, 0x36, 0x71, 0x38, 0x72, 0x4b, 0x46, 0x59, 0x71, 0x61,
+    0x30, 0x70, 0x39, 0x6d, 0x39, 0x4e, 0x35, 0x78, 0x6f, 0x74, 0x53, 0x31,
+    0x57, 0x66, 0x62, 0x43, 0x33, 0x0a, 0x50, 0x36, 0x43, 0x78, 0x42, 0x39,
+    0x62, 0x70, 0x54, 0x39, 0x7a, 0x65, 0x52, 0x58, 0x45, 0x77, 0x4d, 0x6e,
+    0x38, 0x62, 0x4c, 0x67, 0x6e, 0x35, 0x76, 0x31, 0x4b, 0x68, 0x37, 0x73,
+    0x4b, 0x41, 0x50, 0x67, 0x5a, 0x63, 0x4c, 0x6c, 0x56, 0x41, 0x77, 0x52,
+    0x76, 0x31, 0x63, 0x45, 0x57, 0x77, 0x33, 0x46, 0x33, 0x36, 0x39, 0x6e,
+    0x4a, 0x61, 0x64, 0x39, 0x4a, 0x6a, 0x7a, 0x63, 0x39, 0x59, 0x0a, 0x69,
+    0x51, 0x42, 0x43, 0x59, 0x7a, 0x39, 0x35, 0x4f, 0x64, 0x42, 0x45, 0x73,
+    0x49, 0x4a, 0x75, 0x51, 0x52, 0x6e, 0x6f, 0x33, 0x65, 0x44, 0x42, 0x69,
+    0x46, 0x72, 0x52, 0x48, 0x6e, 0x47, 0x54, 0x48, 0x79, 0x51, 0x77, 0x64,
+    0x4f, 0x55, 0x65, 0x71, 0x4e, 0x34, 0x38, 0x4a, 0x7a, 0x64, 0x2f, 0x67,
+    0x36, 0x36, 0x65, 0x64, 0x38, 0x2f, 0x77, 0x4d, 0x4c, 0x48, 0x2f, 0x53,
+    0x35, 0x6e, 0x6f, 0x0a, 0x78, 0x71, 0x45, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a,
+    0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f,
+    0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+    0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+    0x79, 0x20, 0x4f, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c,
+    0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77,
+    0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74,
+    0x2f, 0x43, 0x50, 0x53, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6f,
+    0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20,
+    0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x2f, 0x28, 0x63,
+    0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75,
+    0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53,
+    0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45,
+    0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+    0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+    0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20,
+    0x4f, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49,
+    0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x65,
+    0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x43,
+    0x50, 0x53, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70,
+    0x6f, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x72, 0x65,
+    0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x2f, 0x28, 0x63, 0x29, 0x20,
+    0x32, 0x30, 0x30, 0x36, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74,
+    0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62,
+    0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74,
+    0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+    0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72,
+    0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x31, 0x36, 0x34, 0x36, 0x36, 0x30,
+    0x38, 0x32, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69,
+    0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64,
+    0x36, 0x3a, 0x61, 0x35, 0x3a, 0x63, 0x33, 0x3a, 0x65, 0x64, 0x3a, 0x35,
+    0x64, 0x3a, 0x64, 0x64, 0x3a, 0x33, 0x65, 0x3a, 0x30, 0x30, 0x3a, 0x63,
+    0x31, 0x3a, 0x33, 0x64, 0x3a, 0x38, 0x37, 0x3a, 0x39, 0x32, 0x3a, 0x31,
+    0x66, 0x3a, 0x31, 0x64, 0x3a, 0x33, 0x66, 0x3a, 0x65, 0x34, 0x0a, 0x23,
+    0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x33, 0x3a, 0x31, 0x65,
+    0x3a, 0x62, 0x31, 0x3a, 0x62, 0x37, 0x3a, 0x34, 0x30, 0x3a, 0x65, 0x33,
+    0x3a, 0x36, 0x63, 0x3a, 0x38, 0x34, 0x3a, 0x30, 0x32, 0x3a, 0x64, 0x61,
+    0x3a, 0x64, 0x63, 0x3a, 0x33, 0x37, 0x3a, 0x64, 0x34, 0x3a, 0x34, 0x64,
+    0x3a, 0x66, 0x35, 0x3a, 0x64, 0x34, 0x3a, 0x36, 0x37, 0x3a, 0x34, 0x39,
+    0x3a, 0x35, 0x32, 0x3a, 0x66, 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41,
+    0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x33, 0x3a, 0x63, 0x31, 0x3a, 0x37,
+    0x36, 0x3a, 0x34, 0x33, 0x3a, 0x34, 0x66, 0x3a, 0x31, 0x62, 0x3a, 0x63,
+    0x36, 0x3a, 0x64, 0x35, 0x3a, 0x61, 0x64, 0x3a, 0x66, 0x34, 0x3a, 0x35,
+    0x62, 0x3a, 0x30, 0x65, 0x3a, 0x37, 0x36, 0x3a, 0x65, 0x37, 0x3a, 0x32,
+    0x37, 0x3a, 0x32, 0x38, 0x3a, 0x37, 0x63, 0x3a, 0x38, 0x64, 0x3a, 0x65,
+    0x35, 0x3a, 0x37, 0x36, 0x3a, 0x31, 0x36, 0x3a, 0x63, 0x31, 0x3a, 0x65,
+    0x36, 0x3a, 0x65, 0x36, 0x3a, 0x31, 0x34, 0x3a, 0x31, 0x61, 0x3a, 0x32,
+    0x62, 0x3a, 0x32, 0x63, 0x3a, 0x62, 0x63, 0x3a, 0x37, 0x64, 0x3a, 0x38,
+    0x65, 0x3a, 0x34, 0x63, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45,
+    0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43,
+    0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49,
+    0x45, 0x6b, 0x54, 0x43, 0x43, 0x41, 0x33, 0x6d, 0x67, 0x41, 0x77, 0x49,
+    0x42, 0x41, 0x67, 0x49, 0x45, 0x52, 0x57, 0x74, 0x51, 0x56, 0x44, 0x41,
+    0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30,
+    0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x43, 0x42, 0x73, 0x44, 0x45,
+    0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d,
+    0x43, 0x0a, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x6a, 0x41, 0x55, 0x42, 0x67,
+    0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x55, 0x56, 0x75, 0x64, 0x48,
+    0x4a, 0x31, 0x63, 0x33, 0x51, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79,
+    0x34, 0x78, 0x4f, 0x54, 0x41, 0x33, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41,
+    0x73, 0x54, 0x4d, 0x48, 0x64, 0x33, 0x64, 0x79, 0x35, 0x6c, 0x62, 0x6e,
+    0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x0a, 0x4c, 0x6d, 0x35, 0x6c, 0x64,
+    0x43, 0x39, 0x44, 0x55, 0x46, 0x4d, 0x67, 0x61, 0x58, 0x4d, 0x67, 0x61,
+    0x57, 0x35, 0x6a, 0x62, 0x33, 0x4a, 0x77, 0x62, 0x33, 0x4a, 0x68, 0x64,
+    0x47, 0x56, 0x6b, 0x49, 0x47, 0x4a, 0x35, 0x49, 0x48, 0x4a, 0x6c, 0x5a,
+    0x6d, 0x56, 0x79, 0x5a, 0x57, 0x35, 0x6a, 0x5a, 0x54, 0x45, 0x66, 0x4d,
+    0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x57, 0x0a,
+    0x4b, 0x47, 0x4d, 0x70, 0x49, 0x44, 0x49, 0x77, 0x4d, 0x44, 0x59, 0x67,
+    0x52, 0x57, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x77, 0x67,
+    0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x74, 0x4d, 0x43, 0x73, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x6b, 0x52, 0x57, 0x35, 0x30,
+    0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30,
+    0x49, 0x45, 0x4e, 0x6c, 0x0a, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c,
+    0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56,
+    0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x42, 0x34,
+    0x58, 0x44, 0x54, 0x41, 0x32, 0x4d, 0x54, 0x45, 0x79, 0x4e, 0x7a, 0x49,
+    0x77, 0x4d, 0x6a, 0x4d, 0x30, 0x4d, 0x6c, 0x6f, 0x58, 0x44, 0x54, 0x49,
+    0x32, 0x4d, 0x54, 0x45, 0x79, 0x4e, 0x7a, 0x49, 0x77, 0x0a, 0x4e, 0x54,
+    0x4d, 0x30, 0x4d, 0x6c, 0x6f, 0x77, 0x67, 0x62, 0x41, 0x78, 0x43, 0x7a,
+    0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c,
+    0x56, 0x54, 0x4d, 0x52, 0x59, 0x77, 0x46, 0x41, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x4b, 0x45, 0x77, 0x31, 0x46, 0x62, 0x6e, 0x52, 0x79, 0x64, 0x58,
+    0x4e, 0x30, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x54,
+    0x6b, 0x77, 0x0a, 0x4e, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45,
+    0x7a, 0x42, 0x33, 0x64, 0x33, 0x63, 0x75, 0x5a, 0x57, 0x35, 0x30, 0x63,
+    0x6e, 0x56, 0x7a, 0x64, 0x43, 0x35, 0x75, 0x5a, 0x58, 0x51, 0x76, 0x51,
+    0x31, 0x42, 0x54, 0x49, 0x47, 0x6c, 0x7a, 0x49, 0x47, 0x6c, 0x75, 0x59,
+    0x32, 0x39, 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, 0x58, 0x52, 0x6c, 0x5a,
+    0x43, 0x42, 0x69, 0x65, 0x53, 0x42, 0x79, 0x0a, 0x5a, 0x57, 0x5a, 0x6c,
+    0x63, 0x6d, 0x56, 0x75, 0x59, 0x32, 0x55, 0x78, 0x48, 0x7a, 0x41, 0x64,
+    0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x46, 0x69, 0x68, 0x6a,
+    0x4b, 0x53, 0x41, 0x79, 0x4d, 0x44, 0x41, 0x32, 0x49, 0x45, 0x56, 0x75,
+    0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x73, 0x49, 0x45, 0x6c, 0x75,
+    0x59, 0x79, 0x34, 0x78, 0x4c, 0x54, 0x41, 0x72, 0x42, 0x67, 0x4e, 0x56,
+    0x0a, 0x42, 0x41, 0x4d, 0x54, 0x4a, 0x45, 0x56, 0x75, 0x64, 0x48, 0x4a,
+    0x31, 0x63, 0x33, 0x51, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42,
+    0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46,
+    0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68,
+    0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, 0x43, 0x43, 0x41, 0x53, 0x49,
+    0x77, 0x44, 0x51, 0x59, 0x4a, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76,
+    0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67,
+    0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67,
+    0x45, 0x42, 0x41, 0x4c, 0x61, 0x56, 0x74, 0x6b, 0x4e, 0x43, 0x2b, 0x73,
+    0x5a, 0x74, 0x4b, 0x6d, 0x39, 0x49, 0x33, 0x35, 0x52, 0x4d, 0x4f, 0x56,
+    0x63, 0x46, 0x37, 0x73, 0x4e, 0x35, 0x45, 0x55, 0x46, 0x6f, 0x0a, 0x4e,
+    0x75, 0x33, 0x73, 0x2f, 0x70, 0x6f, 0x42, 0x6a, 0x36, 0x45, 0x34, 0x4b,
+    0x50, 0x7a, 0x33, 0x45, 0x45, 0x5a, 0x6d, 0x4c, 0x6b, 0x30, 0x65, 0x47,
+    0x72, 0x45, 0x61, 0x54, 0x73, 0x62, 0x52, 0x77, 0x4a, 0x57, 0x49, 0x73,
+    0x4d, 0x6e, 0x2f, 0x4d, 0x59, 0x73, 0x7a, 0x41, 0x39, 0x75, 0x33, 0x67,
+    0x33, 0x73, 0x2b, 0x49, 0x49, 0x52, 0x65, 0x37, 0x62, 0x4a, 0x57, 0x4b,
+    0x4b, 0x66, 0x34, 0x0a, 0x34, 0x4c, 0x6c, 0x41, 0x63, 0x54, 0x66, 0x46,
+    0x79, 0x30, 0x63, 0x4f, 0x6c, 0x79, 0x70, 0x6f, 0x77, 0x43, 0x4b, 0x56,
+    0x59, 0x68, 0x58, 0x62, 0x52, 0x39, 0x6e, 0x31, 0x30, 0x43, 0x76, 0x2f,
+    0x67, 0x6b, 0x76, 0x4a, 0x72, 0x54, 0x37, 0x65, 0x54, 0x4e, 0x75, 0x51,
+    0x67, 0x46, 0x41, 0x2f, 0x43, 0x59, 0x71, 0x45, 0x41, 0x4f, 0x77, 0x77,
+    0x43, 0x6a, 0x30, 0x59, 0x7a, 0x66, 0x76, 0x39, 0x0a, 0x4b, 0x6c, 0x6d,
+    0x61, 0x49, 0x35, 0x55, 0x58, 0x4c, 0x45, 0x57, 0x65, 0x48, 0x32, 0x35,
+    0x44, 0x65, 0x57, 0x30, 0x4d, 0x58, 0x4a, 0x6a, 0x2b, 0x53, 0x4b, 0x66,
+    0x46, 0x49, 0x30, 0x64, 0x63, 0x58, 0x76, 0x31, 0x75, 0x35, 0x78, 0x36,
+    0x30, 0x39, 0x6d, 0x68, 0x46, 0x30, 0x59, 0x61, 0x44, 0x57, 0x36, 0x4b,
+    0x4b, 0x6a, 0x62, 0x48, 0x6a, 0x4b, 0x59, 0x44, 0x2b, 0x4a, 0x58, 0x47,
+    0x49, 0x0a, 0x72, 0x62, 0x36, 0x38, 0x6a, 0x36, 0x78, 0x53, 0x6c, 0x6b,
+    0x75, 0x71, 0x55, 0x59, 0x33, 0x6b, 0x45, 0x7a, 0x45, 0x5a, 0x36, 0x45,
+    0x35, 0x4e, 0x6e, 0x39, 0x75, 0x73, 0x73, 0x32, 0x72, 0x56, 0x76, 0x44,
+    0x6c, 0x55, 0x63, 0x63, 0x70, 0x36, 0x65, 0x6e, 0x2b, 0x51, 0x33, 0x58,
+    0x30, 0x64, 0x67, 0x4e, 0x6d, 0x42, 0x75, 0x31, 0x6b, 0x6d, 0x77, 0x68,
+    0x48, 0x2b, 0x35, 0x70, 0x50, 0x69, 0x0a, 0x39, 0x34, 0x44, 0x6b, 0x5a,
+    0x66, 0x73, 0x30, 0x4e, 0x77, 0x34, 0x70, 0x67, 0x48, 0x42, 0x4e, 0x72,
+    0x7a, 0x69, 0x47, 0x4c, 0x70, 0x35, 0x2f, 0x56, 0x36, 0x2b, 0x65, 0x46,
+    0x36, 0x37, 0x72, 0x48, 0x4d, 0x73, 0x6f, 0x49, 0x56, 0x2b, 0x32, 0x48,
+    0x4e, 0x6a, 0x6e, 0x6f, 0x67, 0x51, 0x69, 0x2b, 0x64, 0x50, 0x61, 0x32,
+    0x4d, 0x73, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4f, 0x42, 0x0a,
+    0x73, 0x44, 0x43, 0x42, 0x72, 0x54, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56,
+    0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43,
+    0x41, 0x51, 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54,
+    0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42,
+    0x2f, 0x7a, 0x41, 0x72, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x41, 0x45,
+    0x4a, 0x44, 0x41, 0x69, 0x0a, 0x67, 0x41, 0x38, 0x79, 0x4d, 0x44, 0x41,
+    0x32, 0x4d, 0x54, 0x45, 0x79, 0x4e, 0x7a, 0x49, 0x77, 0x4d, 0x6a, 0x4d,
+    0x30, 0x4d, 0x6c, 0x71, 0x42, 0x44, 0x7a, 0x49, 0x77, 0x4d, 0x6a, 0x59,
+    0x78, 0x4d, 0x54, 0x49, 0x33, 0x4d, 0x6a, 0x41, 0x31, 0x4d, 0x7a, 0x51,
+    0x79, 0x57, 0x6a, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d,
+    0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x52, 0x6f, 0x0a, 0x6b, 0x4f,
+    0x52, 0x6e, 0x70, 0x4b, 0x5a, 0x54, 0x67, 0x4d, 0x65, 0x47, 0x5a, 0x71,
+    0x54, 0x78, 0x39, 0x30, 0x74, 0x44, 0x2b, 0x34, 0x53, 0x39, 0x62, 0x54,
+    0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67,
+    0x51, 0x55, 0x61, 0x4a, 0x44, 0x6b, 0x5a, 0x36, 0x53, 0x6d, 0x55, 0x34,
+    0x44, 0x48, 0x68, 0x6d, 0x61, 0x6b, 0x38, 0x66, 0x64, 0x4c, 0x51, 0x2f,
+    0x75, 0x45, 0x0a, 0x76, 0x57, 0x30, 0x77, 0x48, 0x51, 0x59, 0x4a, 0x4b,
+    0x6f, 0x5a, 0x49, 0x68, 0x76, 0x5a, 0x39, 0x42, 0x30, 0x45, 0x41, 0x42,
+    0x42, 0x41, 0x77, 0x44, 0x68, 0x73, 0x49, 0x56, 0x6a, 0x63, 0x75, 0x4d,
+    0x54, 0x6f, 0x30, 0x4c, 0x6a, 0x41, 0x44, 0x41, 0x67, 0x53, 0x51, 0x4d,
+    0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44,
+    0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x0a, 0x41, 0x34, 0x49, 0x42,
+    0x41, 0x51, 0x43, 0x54, 0x31, 0x44, 0x43, 0x77, 0x31, 0x77, 0x4d, 0x67,
+    0x4b, 0x74, 0x44, 0x35, 0x59, 0x2b, 0x69, 0x52, 0x44, 0x41, 0x55, 0x67,
+    0x71, 0x56, 0x38, 0x5a, 0x79, 0x6e, 0x74, 0x79, 0x54, 0x74, 0x53, 0x78,
+    0x32, 0x39, 0x43, 0x57, 0x2b, 0x31, 0x52, 0x61, 0x47, 0x53, 0x77, 0x4d,
+    0x43, 0x50, 0x65, 0x79, 0x76, 0x49, 0x57, 0x6f, 0x6e, 0x58, 0x39, 0x74,
+    0x0a, 0x4f, 0x31, 0x4b, 0x7a, 0x4b, 0x74, 0x76, 0x6e, 0x31, 0x49, 0x53,
+    0x4d, 0x59, 0x2f, 0x59, 0x50, 0x79, 0x79, 0x59, 0x42, 0x6b, 0x56, 0x42,
+    0x73, 0x39, 0x46, 0x38, 0x55, 0x34, 0x70, 0x4e, 0x30, 0x77, 0x42, 0x4f,
+    0x65, 0x4d, 0x44, 0x70, 0x51, 0x34, 0x37, 0x52, 0x67, 0x78, 0x52, 0x7a,
+    0x77, 0x49, 0x6b, 0x53, 0x4e, 0x63, 0x55, 0x65, 0x73, 0x79, 0x42, 0x72,
+    0x4a, 0x36, 0x5a, 0x75, 0x61, 0x0a, 0x41, 0x47, 0x41, 0x54, 0x2f, 0x33,
+    0x42, 0x2b, 0x58, 0x78, 0x46, 0x4e, 0x53, 0x52, 0x75, 0x7a, 0x46, 0x56,
+    0x4a, 0x37, 0x79, 0x56, 0x54, 0x61, 0x76, 0x35, 0x32, 0x56, 0x72, 0x32,
+    0x75, 0x61, 0x32, 0x4a, 0x37, 0x70, 0x38, 0x65, 0x52, 0x44, 0x6a, 0x65,
+    0x49, 0x52, 0x52, 0x44, 0x71, 0x2f, 0x72, 0x37, 0x32, 0x44, 0x51, 0x6e,
+    0x4e, 0x53, 0x69, 0x36, 0x71, 0x37, 0x70, 0x79, 0x6e, 0x50, 0x0a, 0x39,
+    0x57, 0x51, 0x63, 0x43, 0x6b, 0x33, 0x52, 0x76, 0x4b, 0x71, 0x73, 0x6e,
+    0x79, 0x72, 0x51, 0x2f, 0x33, 0x39, 0x2f, 0x32, 0x6e, 0x33, 0x71, 0x73,
+    0x65, 0x30, 0x77, 0x4a, 0x63, 0x47, 0x45, 0x32, 0x6a, 0x54, 0x53, 0x57,
+    0x33, 0x69, 0x44, 0x56, 0x75, 0x79, 0x63, 0x4e, 0x73, 0x4d, 0x6d, 0x34,
+    0x68, 0x48, 0x32, 0x5a, 0x30, 0x6b, 0x64, 0x6b, 0x71, 0x75, 0x4d, 0x2b,
+    0x2b, 0x76, 0x2f, 0x0a, 0x65, 0x75, 0x36, 0x46, 0x53, 0x71, 0x64, 0x51,
+    0x67, 0x50, 0x43, 0x6e, 0x58, 0x45, 0x71, 0x55, 0x4c, 0x6c, 0x38, 0x46,
+    0x6d, 0x54, 0x78, 0x53, 0x51, 0x65, 0x44, 0x4e, 0x74, 0x47, 0x50, 0x50,
+    0x41, 0x55, 0x4f, 0x36, 0x6e, 0x49, 0x50, 0x63, 0x6a, 0x32, 0x41, 0x37,
+    0x38, 0x31, 0x71, 0x30, 0x74, 0x48, 0x75, 0x75, 0x32, 0x67, 0x75, 0x51,
+    0x4f, 0x48, 0x58, 0x76, 0x67, 0x52, 0x31, 0x6d, 0x0a, 0x30, 0x76, 0x64,
+    0x58, 0x63, 0x44, 0x61, 0x7a, 0x76, 0x2f, 0x77, 0x6f, 0x72, 0x33, 0x45,
+    0x6c, 0x68, 0x56, 0x73, 0x54, 0x2f, 0x68, 0x35, 0x2f, 0x57, 0x72, 0x51,
+    0x38, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65,
+    0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75,
+    0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41,
+    0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20,
+    0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65,
+    0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72,
+    0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43,
+    0x41, 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74,
+    0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65,
+    0x6c, 0x3a, 0x20, 0x22, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74,
+    0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x22, 0x0a,
+    0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x34,
+    0x34, 0x34, 0x37, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x66, 0x37, 0x3a, 0x37, 0x35, 0x3a, 0x61, 0x62, 0x3a, 0x32, 0x39, 0x3a,
+    0x66, 0x62, 0x3a, 0x35, 0x31, 0x3a, 0x34, 0x65, 0x3a, 0x62, 0x37, 0x3a,
+    0x37, 0x37, 0x3a, 0x35, 0x65, 0x3a, 0x66, 0x66, 0x3a, 0x30, 0x35, 0x3a,
+    0x33, 0x63, 0x3a, 0x39, 0x39, 0x3a, 0x38, 0x65, 0x3a, 0x66, 0x35, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x65, 0x3a, 0x32,
+    0x38, 0x3a, 0x66, 0x34, 0x3a, 0x61, 0x34, 0x3a, 0x66, 0x66, 0x3a, 0x65,
+    0x35, 0x3a, 0x62, 0x39, 0x3a, 0x32, 0x66, 0x3a, 0x61, 0x33, 0x3a, 0x63,
+    0x35, 0x3a, 0x30, 0x33, 0x3a, 0x64, 0x31, 0x3a, 0x61, 0x33, 0x3a, 0x34,
+    0x39, 0x3a, 0x61, 0x37, 0x3a, 0x66, 0x39, 0x3a, 0x39, 0x36, 0x3a, 0x32,
+    0x61, 0x3a, 0x38, 0x32, 0x3a, 0x31, 0x32, 0x0a, 0x23, 0x20, 0x53, 0x48,
+    0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x66, 0x66, 0x3a, 0x38, 0x35, 0x3a,
+    0x36, 0x61, 0x3a, 0x32, 0x64, 0x3a, 0x32, 0x35, 0x3a, 0x31, 0x64, 0x3a,
+    0x63, 0x64, 0x3a, 0x38, 0x38, 0x3a, 0x64, 0x33, 0x3a, 0x36, 0x36, 0x3a,
+    0x35, 0x36, 0x3a, 0x66, 0x34, 0x3a, 0x35, 0x30, 0x3a, 0x31, 0x32, 0x3a,
+    0x36, 0x37, 0x3a, 0x39, 0x38, 0x3a, 0x63, 0x66, 0x3a, 0x61, 0x62, 0x3a,
+    0x61, 0x61, 0x3a, 0x64, 0x65, 0x3a, 0x34, 0x30, 0x3a, 0x37, 0x39, 0x3a,
+    0x39, 0x63, 0x3a, 0x37, 0x32, 0x3a, 0x32, 0x64, 0x3a, 0x65, 0x34, 0x3a,
+    0x64, 0x32, 0x3a, 0x62, 0x35, 0x3a, 0x64, 0x62, 0x3a, 0x33, 0x36, 0x3a,
+    0x61, 0x37, 0x3a, 0x33, 0x61, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42,
+    0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49,
+    0x49, 0x44, 0x56, 0x44, 0x43, 0x43, 0x41, 0x6a, 0x79, 0x67, 0x41, 0x77,
+    0x49, 0x42, 0x41, 0x67, 0x49, 0x44, 0x41, 0x6a, 0x52, 0x57, 0x4d, 0x41,
+    0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51,
+    0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x4d, 0x45, 0x49, 0x78, 0x43, 0x7a,
+    0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c,
+    0x56, 0x54, 0x0a, 0x4d, 0x52, 0x59, 0x77, 0x46, 0x41, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x4b, 0x45, 0x77, 0x31, 0x48, 0x5a, 0x57, 0x39, 0x55, 0x63,
+    0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d,
+    0x52, 0x73, 0x77, 0x47, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45,
+    0x78, 0x4a, 0x48, 0x5a, 0x57, 0x39, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64,
+    0x43, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, 0x0a, 0x59, 0x57, 0x77, 0x67,
+    0x51, 0x30, 0x45, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x49, 0x77,
+    0x4e, 0x54, 0x49, 0x78, 0x4d, 0x44, 0x51, 0x77, 0x4d, 0x44, 0x41, 0x77,
+    0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x49, 0x77, 0x4e, 0x54, 0x49, 0x78,
+    0x4d, 0x44, 0x51, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x6a, 0x42, 0x43,
+    0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47,
+    0x0a, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x57, 0x4d, 0x42, 0x51,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4e, 0x52, 0x32, 0x56,
+    0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x53, 0x57, 0x35,
+    0x6a, 0x4c, 0x6a, 0x45, 0x62, 0x4d, 0x42, 0x6b, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x41, 0x78, 0x4d, 0x53, 0x52, 0x32, 0x56, 0x76, 0x56, 0x48, 0x4a,
+    0x31, 0x63, 0x33, 0x51, 0x67, 0x0a, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d,
+    0x46, 0x73, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a,
+    0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77,
+    0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51,
+    0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51,
+    0x45, 0x41, 0x32, 0x73, 0x77, 0x59, 0x59, 0x7a, 0x44, 0x39, 0x0a, 0x39,
+    0x42, 0x63, 0x6a, 0x47, 0x6c, 0x5a, 0x2b, 0x57, 0x39, 0x38, 0x38, 0x62,
+    0x44, 0x6a, 0x6b, 0x63, 0x62, 0x64, 0x34, 0x6b, 0x64, 0x53, 0x38, 0x6f,
+    0x64, 0x68, 0x4d, 0x2b, 0x4b, 0x68, 0x44, 0x74, 0x67, 0x50, 0x70, 0x54,
+    0x53, 0x45, 0x48, 0x43, 0x49, 0x6a, 0x61, 0x57, 0x43, 0x39, 0x6d, 0x4f,
+    0x53, 0x6d, 0x39, 0x42, 0x58, 0x69, 0x4c, 0x6e, 0x54, 0x6a, 0x6f, 0x42,
+    0x62, 0x64, 0x71, 0x0a, 0x66, 0x6e, 0x47, 0x6b, 0x35, 0x73, 0x52, 0x67,
+    0x70, 0x72, 0x44, 0x76, 0x67, 0x4f, 0x53, 0x4a, 0x4b, 0x41, 0x2b, 0x65,
+    0x4a, 0x64, 0x62, 0x74, 0x67, 0x2f, 0x4f, 0x74, 0x70, 0x70, 0x48, 0x48,
+    0x6d, 0x4d, 0x6c, 0x43, 0x47, 0x44, 0x55, 0x55, 0x6e, 0x61, 0x32, 0x59,
+    0x52, 0x70, 0x49, 0x75, 0x54, 0x38, 0x72, 0x78, 0x68, 0x30, 0x50, 0x42,
+    0x46, 0x70, 0x56, 0x58, 0x4c, 0x56, 0x44, 0x76, 0x0a, 0x69, 0x53, 0x32,
+    0x41, 0x65, 0x6c, 0x65, 0x74, 0x38, 0x75, 0x35, 0x66, 0x61, 0x39, 0x49,
+    0x41, 0x6a, 0x62, 0x6b, 0x55, 0x2b, 0x42, 0x51, 0x56, 0x4e, 0x64, 0x6e,
+    0x41, 0x52, 0x71, 0x4e, 0x37, 0x63, 0x73, 0x69, 0x52, 0x76, 0x38, 0x6c,
+    0x56, 0x4b, 0x38, 0x33, 0x51, 0x6c, 0x7a, 0x36, 0x63, 0x4a, 0x6d, 0x54,
+    0x4d, 0x33, 0x38, 0x36, 0x44, 0x47, 0x58, 0x48, 0x4b, 0x54, 0x75, 0x62,
+    0x55, 0x0a, 0x31, 0x58, 0x75, 0x70, 0x47, 0x63, 0x31, 0x56, 0x33, 0x73,
+    0x6a, 0x73, 0x30, 0x6c, 0x34, 0x34, 0x55, 0x2b, 0x56, 0x63, 0x54, 0x34,
+    0x77, 0x74, 0x2f, 0x6c, 0x41, 0x6a, 0x4e, 0x76, 0x78, 0x6d, 0x35, 0x73,
+    0x75, 0x4f, 0x70, 0x44, 0x6b, 0x5a, 0x41, 0x4c, 0x65, 0x56, 0x41, 0x6a,
+    0x6d, 0x52, 0x43, 0x77, 0x37, 0x2b, 0x4f, 0x43, 0x37, 0x52, 0x48, 0x51,
+    0x57, 0x61, 0x39, 0x6b, 0x30, 0x2b, 0x0a, 0x62, 0x77, 0x38, 0x48, 0x48,
+    0x61, 0x38, 0x73, 0x48, 0x6f, 0x39, 0x67, 0x4f, 0x65, 0x4c, 0x36, 0x4e,
+    0x6c, 0x4d, 0x54, 0x4f, 0x64, 0x52, 0x65, 0x4a, 0x69, 0x76, 0x62, 0x50,
+    0x61, 0x67, 0x55, 0x76, 0x54, 0x4c, 0x72, 0x47, 0x41, 0x4d, 0x6f, 0x55,
+    0x67, 0x52, 0x78, 0x35, 0x61, 0x73, 0x7a, 0x50, 0x65, 0x45, 0x34, 0x75,
+    0x77, 0x63, 0x32, 0x68, 0x47, 0x4b, 0x63, 0x65, 0x65, 0x6f, 0x57, 0x0a,
+    0x4d, 0x50, 0x52, 0x66, 0x77, 0x43, 0x76, 0x6f, 0x63, 0x57, 0x76, 0x6b,
+    0x2b, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x31, 0x4d, 0x77,
+    0x55, 0x54, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42,
+    0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f,
+    0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57,
+    0x42, 0x42, 0x54, 0x41, 0x0a, 0x65, 0x70, 0x68, 0x6f, 0x6a, 0x59, 0x6e,
+    0x37, 0x71, 0x77, 0x56, 0x6b, 0x44, 0x42, 0x46, 0x39, 0x71, 0x6e, 0x31,
+    0x6c, 0x75, 0x4d, 0x72, 0x4d, 0x54, 0x6a, 0x41, 0x66, 0x42, 0x67, 0x4e,
+    0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x54,
+    0x41, 0x65, 0x70, 0x68, 0x6f, 0x6a, 0x59, 0x6e, 0x37, 0x71, 0x77, 0x56,
+    0x6b, 0x44, 0x42, 0x46, 0x39, 0x71, 0x6e, 0x31, 0x6c, 0x0a, 0x75, 0x4d,
+    0x72, 0x4d, 0x54, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b,
+    0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41,
+    0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x4e, 0x65, 0x4d, 0x70, 0x61, 0x75,
+    0x55, 0x76, 0x58, 0x56, 0x53, 0x4f, 0x4b, 0x56, 0x43, 0x55, 0x6e, 0x35,
+    0x6b, 0x61, 0x46, 0x4f, 0x53, 0x50, 0x65, 0x43, 0x70, 0x69, 0x6c, 0x4b,
+    0x49, 0x6e, 0x0a, 0x5a, 0x35, 0x37, 0x51, 0x7a, 0x78, 0x70, 0x65, 0x52,
+    0x2b, 0x6e, 0x42, 0x73, 0x71, 0x54, 0x50, 0x33, 0x55, 0x45, 0x61, 0x42,
+    0x55, 0x36, 0x62, 0x53, 0x2b, 0x35, 0x4b, 0x62, 0x31, 0x56, 0x53, 0x73,
+    0x79, 0x53, 0x68, 0x4e, 0x77, 0x72, 0x72, 0x5a, 0x48, 0x59, 0x71, 0x4c,
+    0x69, 0x7a, 0x7a, 0x2f, 0x54, 0x74, 0x31, 0x6b, 0x4c, 0x2f, 0x36, 0x63,
+    0x64, 0x6a, 0x48, 0x50, 0x54, 0x66, 0x53, 0x0a, 0x74, 0x51, 0x57, 0x56,
+    0x59, 0x72, 0x6d, 0x6d, 0x33, 0x6f, 0x6b, 0x39, 0x4e, 0x6e, 0x73, 0x34,
+    0x64, 0x30, 0x69, 0x58, 0x72, 0x4b, 0x59, 0x67, 0x6a, 0x79, 0x36, 0x6d,
+    0x79, 0x51, 0x7a, 0x43, 0x73, 0x70, 0x6c, 0x46, 0x41, 0x4d, 0x66, 0x4f,
+    0x45, 0x56, 0x45, 0x69, 0x49, 0x75, 0x43, 0x6c, 0x36, 0x72, 0x59, 0x56,
+    0x53, 0x41, 0x6c, 0x6b, 0x36, 0x6c, 0x35, 0x50, 0x64, 0x50, 0x63, 0x46,
+    0x0a, 0x50, 0x73, 0x65, 0x4b, 0x55, 0x67, 0x7a, 0x62, 0x46, 0x62, 0x53,
+    0x39, 0x62, 0x5a, 0x76, 0x6c, 0x78, 0x72, 0x46, 0x55, 0x61, 0x4b, 0x6e,
+    0x6a, 0x61, 0x5a, 0x43, 0x32, 0x6d, 0x71, 0x55, 0x50, 0x75, 0x4c, 0x6b,
+    0x2f, 0x49, 0x48, 0x32, 0x75, 0x53, 0x72, 0x57, 0x34, 0x6e, 0x4f, 0x51,
+    0x64, 0x74, 0x71, 0x76, 0x6d, 0x6c, 0x4b, 0x58, 0x42, 0x78, 0x34, 0x4f,
+    0x74, 0x32, 0x2f, 0x55, 0x6e, 0x0a, 0x68, 0x77, 0x34, 0x45, 0x62, 0x4e,
+    0x58, 0x2f, 0x33, 0x61, 0x42, 0x64, 0x37, 0x59, 0x64, 0x53, 0x74, 0x79,
+    0x73, 0x56, 0x41, 0x71, 0x34, 0x35, 0x70, 0x6d, 0x70, 0x30, 0x36, 0x64,
+    0x72, 0x45, 0x35, 0x37, 0x78, 0x4e, 0x4e, 0x42, 0x36, 0x70, 0x58, 0x45,
+    0x30, 0x7a, 0x58, 0x35, 0x49, 0x4a, 0x4c, 0x34, 0x68, 0x6d, 0x58, 0x58,
+    0x65, 0x58, 0x78, 0x78, 0x31, 0x32, 0x45, 0x36, 0x6e, 0x56, 0x0a, 0x35,
+    0x66, 0x45, 0x57, 0x43, 0x52, 0x45, 0x31, 0x31, 0x61, 0x7a, 0x62, 0x4a,
+    0x48, 0x46, 0x77, 0x4c, 0x4a, 0x68, 0x57, 0x43, 0x39, 0x6b, 0x58, 0x74,
+    0x4e, 0x48, 0x6a, 0x55, 0x53, 0x74, 0x65, 0x64, 0x65, 0x6a, 0x56, 0x30,
+    0x4e, 0x78, 0x50, 0x4e, 0x4f, 0x33, 0x43, 0x42, 0x57, 0x61, 0x41, 0x6f,
+    0x63, 0x76, 0x6d, 0x4d, 0x77, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23,
+    0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d,
+    0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f,
+    0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x32, 0x20, 0x4f, 0x3d, 0x47,
+    0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+    0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20,
+    0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20,
+    0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x32, 0x20,
+    0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49,
+    0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a,
+    0x20, 0x22, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47,
+    0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x32, 0x22, 0x0a,
+    0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a,
+    0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x65, 0x3a, 0x34, 0x30,
+    0x3a, 0x61, 0x37, 0x3a, 0x36, 0x63, 0x3a, 0x64, 0x65, 0x3a, 0x30, 0x33,
+    0x3a, 0x35, 0x64, 0x3a, 0x38, 0x66, 0x3a, 0x64, 0x31, 0x3a, 0x30, 0x66,
+    0x3a, 0x65, 0x34, 0x3a, 0x64, 0x31, 0x3a, 0x38, 0x64, 0x3a, 0x66, 0x39,
+    0x3a, 0x36, 0x63, 0x3a, 0x61, 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41,
+    0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x61, 0x39, 0x3a, 0x65, 0x39, 0x3a, 0x37, 0x38, 0x3a,
+    0x30, 0x38, 0x3a, 0x31, 0x34, 0x3a, 0x33, 0x37, 0x3a, 0x35, 0x38, 0x3a,
+    0x38, 0x38, 0x3a, 0x66, 0x32, 0x3a, 0x30, 0x35, 0x3a, 0x31, 0x39, 0x3a,
+    0x62, 0x30, 0x3a, 0x36, 0x64, 0x3a, 0x32, 0x62, 0x3a, 0x30, 0x64, 0x3a,
+    0x32, 0x62, 0x3a, 0x36, 0x30, 0x3a, 0x31, 0x36, 0x3a, 0x39, 0x30, 0x3a,
+    0x37, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x63, 0x61, 0x3a, 0x32, 0x64, 0x3a, 0x38, 0x32, 0x3a, 0x61, 0x30,
+    0x3a, 0x38, 0x36, 0x3a, 0x37, 0x37, 0x3a, 0x30, 0x37, 0x3a, 0x32, 0x66,
+    0x3a, 0x38, 0x61, 0x3a, 0x62, 0x36, 0x3a, 0x37, 0x36, 0x3a, 0x34, 0x66,
+    0x3a, 0x66, 0x30, 0x3a, 0x33, 0x35, 0x3a, 0x36, 0x37, 0x3a, 0x36, 0x63,
+    0x3a, 0x66, 0x65, 0x3a, 0x33, 0x65, 0x3a, 0x35, 0x65, 0x3a, 0x33, 0x32,
+    0x3a, 0x35, 0x65, 0x3a, 0x30, 0x31, 0x3a, 0x32, 0x31, 0x3a, 0x37, 0x32,
+    0x3a, 0x64, 0x66, 0x3a, 0x33, 0x66, 0x3a, 0x39, 0x32, 0x3a, 0x30, 0x39,
+    0x3a, 0x36, 0x64, 0x3a, 0x62, 0x37, 0x3a, 0x39, 0x62, 0x3a, 0x38, 0x35,
+    0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20,
+    0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x5a, 0x6a, 0x43,
+    0x43, 0x41, 0x6b, 0x36, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49,
+    0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69,
+    0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42,
+    0x45, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x57, 0x0a, 0x4d, 0x42,
+    0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4e, 0x52, 0x32,
+    0x56, 0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x53, 0x57,
+    0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x64, 0x4d, 0x42, 0x73, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x41, 0x78, 0x4d, 0x55, 0x52, 0x32, 0x56, 0x76, 0x56, 0x48,
+    0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d,
+    0x46, 0x73, 0x0a, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x44, 0x49, 0x77, 0x48,
+    0x68, 0x63, 0x4e, 0x4d, 0x44, 0x51, 0x77, 0x4d, 0x7a, 0x41, 0x30, 0x4d,
+    0x44, 0x55, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d,
+    0x54, 0x6b, 0x77, 0x4d, 0x7a, 0x41, 0x30, 0x4d, 0x44, 0x55, 0x77, 0x4d,
+    0x44, 0x41, 0x77, 0x57, 0x6a, 0x42, 0x45, 0x4d, 0x51, 0x73, 0x77, 0x43,
+    0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x0a, 0x45, 0x77, 0x4a, 0x56,
+    0x55, 0x7a, 0x45, 0x57, 0x4d, 0x42, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x43, 0x68, 0x4d, 0x4e, 0x52, 0x32, 0x56, 0x76, 0x56, 0x48, 0x4a, 0x31,
+    0x63, 0x33, 0x51, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x64,
+    0x4d, 0x42, 0x73, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x55,
+    0x52, 0x32, 0x56, 0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67,
+    0x0a, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, 0x49, 0x45, 0x4e,
+    0x42, 0x49, 0x44, 0x49, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4d, 0x41, 0x30,
+    0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45,
+    0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77, 0x41,
+    0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x44,
+    0x76, 0x50, 0x45, 0x31, 0x41, 0x0a, 0x50, 0x52, 0x44, 0x66, 0x4f, 0x31,
+    0x4d, 0x41, 0x34, 0x57, 0x66, 0x2b, 0x6c, 0x47, 0x41, 0x56, 0x50, 0x6f,
+    0x57, 0x49, 0x38, 0x59, 0x6b, 0x4e, 0x6b, 0x4d, 0x67, 0x6f, 0x49, 0x35,
+    0x6b, 0x46, 0x36, 0x43, 0x73, 0x67, 0x6e, 0x63, 0x62, 0x7a, 0x59, 0x45,
+    0x62, 0x59, 0x77, 0x62, 0x4c, 0x56, 0x6a, 0x44, 0x48, 0x5a, 0x33, 0x43,
+    0x42, 0x35, 0x4a, 0x49, 0x47, 0x2f, 0x4e, 0x54, 0x4c, 0x38, 0x0a, 0x59,
+    0x32, 0x6e, 0x62, 0x73, 0x53, 0x70, 0x72, 0x37, 0x69, 0x46, 0x59, 0x38,
+    0x67, 0x6a, 0x70, 0x65, 0x4d, 0x74, 0x76, 0x79, 0x2f, 0x77, 0x57, 0x55,
+    0x73, 0x69, 0x52, 0x78, 0x50, 0x38, 0x39, 0x63, 0x39, 0x36, 0x78, 0x50,
+    0x71, 0x66, 0x43, 0x66, 0x57, 0x62, 0x42, 0x39, 0x58, 0x35, 0x53, 0x4a,
+    0x42, 0x72, 0x69, 0x31, 0x57, 0x65, 0x52, 0x30, 0x49, 0x49, 0x51, 0x31,
+    0x33, 0x68, 0x4c, 0x0a, 0x54, 0x79, 0x74, 0x43, 0x4f, 0x62, 0x31, 0x6b,
+    0x4c, 0x55, 0x43, 0x67, 0x73, 0x42, 0x44, 0x54, 0x4f, 0x45, 0x68, 0x47,
+    0x69, 0x4b, 0x45, 0x4d, 0x75, 0x7a, 0x6f, 0x7a, 0x4b, 0x6d, 0x4b, 0x59,
+    0x2b, 0x77, 0x43, 0x64, 0x45, 0x31, 0x6c, 0x2f, 0x62, 0x7a, 0x74, 0x79,
+    0x71, 0x75, 0x36, 0x6d, 0x44, 0x34, 0x62, 0x35, 0x42, 0x57, 0x48, 0x71,
+    0x5a, 0x33, 0x38, 0x4d, 0x4e, 0x35, 0x61, 0x4c, 0x0a, 0x35, 0x6d, 0x6b,
+    0x57, 0x52, 0x78, 0x48, 0x43, 0x4a, 0x31, 0x6b, 0x44, 0x73, 0x36, 0x5a,
+    0x67, 0x77, 0x69, 0x46, 0x41, 0x56, 0x76, 0x71, 0x67, 0x78, 0x33, 0x30,
+    0x36, 0x45, 0x2b, 0x50, 0x73, 0x56, 0x38, 0x65, 0x7a, 0x31, 0x71, 0x36,
+    0x64, 0x69, 0x59, 0x44, 0x33, 0x41, 0x65, 0x63, 0x73, 0x39, 0x70, 0x59,
+    0x72, 0x45, 0x77, 0x31, 0x35, 0x4c, 0x4e, 0x6e, 0x41, 0x35, 0x49, 0x5a,
+    0x37, 0x0a, 0x53, 0x34, 0x77, 0x4d, 0x63, 0x6f, 0x4b, 0x4b, 0x2b, 0x78,
+    0x66, 0x4e, 0x41, 0x47, 0x77, 0x36, 0x45, 0x7a, 0x79, 0x77, 0x68, 0x49,
+    0x64, 0x4c, 0x46, 0x6e, 0x6f, 0x70, 0x73, 0x6b, 0x2f, 0x62, 0x48, 0x64,
+    0x51, 0x4c, 0x38, 0x32, 0x59, 0x33, 0x76, 0x64, 0x6a, 0x32, 0x56, 0x37,
+    0x74, 0x65, 0x4a, 0x48, 0x71, 0x34, 0x50, 0x49, 0x75, 0x35, 0x2b, 0x70,
+    0x49, 0x61, 0x47, 0x6f, 0x53, 0x65, 0x0a, 0x32, 0x48, 0x53, 0x50, 0x71,
+    0x68, 0x74, 0x2f, 0x58, 0x76, 0x54, 0x2b, 0x52, 0x53, 0x49, 0x68, 0x41,
+    0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x59, 0x7a, 0x42, 0x68, 0x4d,
+    0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f,
+    0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x48,
+    0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x0a,
+    0x46, 0x48, 0x45, 0x34, 0x4e, 0x76, 0x49, 0x43, 0x4d, 0x56, 0x4e, 0x48,
+    0x4b, 0x32, 0x36, 0x36, 0x5a, 0x55, 0x61, 0x70, 0x45, 0x42, 0x56, 0x59,
+    0x49, 0x41, 0x55, 0x4a, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64,
+    0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, 0x61, 0x41, 0x46, 0x48, 0x45, 0x34,
+    0x4e, 0x76, 0x49, 0x43, 0x4d, 0x56, 0x4e, 0x48, 0x4b, 0x32, 0x36, 0x36,
+    0x5a, 0x55, 0x61, 0x70, 0x0a, 0x45, 0x42, 0x56, 0x59, 0x49, 0x41, 0x55,
+    0x4a, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45,
+    0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x68, 0x6a, 0x41,
+    0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30,
+    0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45,
+    0x41, 0x41, 0x2f, 0x65, 0x31, 0x4b, 0x36, 0x74, 0x64, 0x0a, 0x45, 0x50,
+    0x78, 0x37, 0x73, 0x72, 0x4a, 0x65, 0x72, 0x4a, 0x73, 0x4f, 0x66, 0x6c,
+    0x4e, 0x34, 0x57, 0x54, 0x35, 0x43, 0x42, 0x50, 0x35, 0x31, 0x6f, 0x36,
+    0x32, 0x73, 0x67, 0x55, 0x37, 0x58, 0x41, 0x6f, 0x74, 0x65, 0x78, 0x43,
+    0x33, 0x49, 0x55, 0x6e, 0x62, 0x48, 0x4c, 0x42, 0x2f, 0x38, 0x67, 0x54,
+    0x4b, 0x59, 0x30, 0x55, 0x76, 0x47, 0x6b, 0x70, 0x4d, 0x7a, 0x4e, 0x54,
+    0x45, 0x76, 0x0a, 0x2f, 0x4e, 0x67, 0x64, 0x52, 0x4e, 0x33, 0x67, 0x67,
+    0x58, 0x2b, 0x64, 0x36, 0x59, 0x76, 0x68, 0x5a, 0x4a, 0x46, 0x69, 0x43,
+    0x7a, 0x6b, 0x49, 0x6a, 0x4b, 0x78, 0x30, 0x6e, 0x56, 0x6e, 0x5a, 0x65,
+    0x6c, 0x6c, 0x53, 0x6c, 0x78, 0x47, 0x35, 0x46, 0x6e, 0x74, 0x76, 0x52,
+    0x64, 0x4f, 0x57, 0x32, 0x54, 0x46, 0x39, 0x41, 0x6a, 0x59, 0x50, 0x6e,
+    0x44, 0x74, 0x75, 0x7a, 0x79, 0x77, 0x4e, 0x0a, 0x41, 0x30, 0x5a, 0x46,
+    0x36, 0x36, 0x44, 0x30, 0x66, 0x30, 0x68, 0x45, 0x78, 0x67, 0x68, 0x41,
+    0x7a, 0x4e, 0x34, 0x62, 0x63, 0x4c, 0x55, 0x70, 0x72, 0x62, 0x71, 0x4c,
+    0x4f, 0x7a, 0x52, 0x6c, 0x64, 0x52, 0x74, 0x78, 0x49, 0x52, 0x30, 0x73,
+    0x46, 0x41, 0x71, 0x77, 0x6c, 0x70, 0x57, 0x34, 0x31, 0x75, 0x72, 0x79,
+    0x5a, 0x66, 0x73, 0x70, 0x75, 0x6b, 0x2f, 0x71, 0x6b, 0x5a, 0x4e, 0x30,
+    0x0a, 0x61, 0x62, 0x62, 0x79, 0x2f, 0x2b, 0x45, 0x61, 0x30, 0x41, 0x7a,
+    0x52, 0x64, 0x6f, 0x58, 0x4c, 0x69, 0x69, 0x57, 0x39, 0x6c, 0x31, 0x34,
+    0x73, 0x62, 0x78, 0x57, 0x5a, 0x4a, 0x75, 0x65, 0x32, 0x4b, 0x66, 0x38,
+    0x69, 0x37, 0x4d, 0x6b, 0x43, 0x78, 0x31, 0x59, 0x41, 0x7a, 0x55, 0x6d,
+    0x35, 0x73, 0x32, 0x78, 0x37, 0x55, 0x77, 0x51, 0x61, 0x34, 0x71, 0x6a,
+    0x4a, 0x71, 0x68, 0x49, 0x46, 0x0a, 0x49, 0x38, 0x4c, 0x4f, 0x35, 0x37,
+    0x73, 0x45, 0x41, 0x73, 0x7a, 0x41, 0x52, 0x36, 0x4c, 0x6b, 0x78, 0x43,
+    0x6b, 0x76, 0x57, 0x30, 0x56, 0x58, 0x69, 0x56, 0x48, 0x75, 0x50, 0x4f,
+    0x74, 0x53, 0x43, 0x50, 0x38, 0x48, 0x4e, 0x52, 0x36, 0x66, 0x4e, 0x57,
+    0x70, 0x48, 0x53, 0x6c, 0x61, 0x59, 0x30, 0x56, 0x71, 0x46, 0x48, 0x34,
+    0x7a, 0x31, 0x49, 0x72, 0x2b, 0x72, 0x7a, 0x6f, 0x50, 0x7a, 0x0a, 0x34,
+    0x69, 0x49, 0x70, 0x72, 0x6e, 0x32, 0x44, 0x51, 0x4b, 0x69, 0x36, 0x62,
+    0x41, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73,
+    0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, 0x54,
+    0x72, 0x75, 0x73, 0x74, 0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73,
+    0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54,
+    0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20,
+    0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d,
+    0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x55, 0x6e, 0x69,
+    0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d,
+    0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63,
+    0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22,
+    0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x55, 0x6e, 0x69,
+    0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23,
+    0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23,
+    0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x32, 0x3a, 0x36, 0x35, 0x3a,
+    0x35, 0x38, 0x3a, 0x38, 0x62, 0x3a, 0x61, 0x32, 0x3a, 0x31, 0x61, 0x3a,
+    0x33, 0x31, 0x3a, 0x37, 0x32, 0x3a, 0x37, 0x33, 0x3a, 0x36, 0x38, 0x3a,
+    0x35, 0x63, 0x3a, 0x62, 0x34, 0x3a, 0x61, 0x35, 0x3a, 0x37, 0x61, 0x3a,
+    0x30, 0x37, 0x3a, 0x34, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x65, 0x36, 0x3a, 0x32, 0x31, 0x3a, 0x66, 0x33, 0x3a, 0x33,
+    0x35, 0x3a, 0x34, 0x33, 0x3a, 0x37, 0x39, 0x3a, 0x30, 0x35, 0x3a, 0x39,
+    0x61, 0x3a, 0x34, 0x62, 0x3a, 0x36, 0x38, 0x3a, 0x33, 0x30, 0x3a, 0x39,
+    0x64, 0x3a, 0x38, 0x61, 0x3a, 0x32, 0x66, 0x3a, 0x37, 0x34, 0x3a, 0x32,
+    0x32, 0x3a, 0x31, 0x35, 0x3a, 0x38, 0x37, 0x3a, 0x65, 0x63, 0x3a, 0x37,
+    0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x61, 0x30, 0x3a, 0x34, 0x35, 0x3a, 0x39, 0x62, 0x3a, 0x39, 0x66, 0x3a,
+    0x36, 0x33, 0x3a, 0x62, 0x32, 0x3a, 0x32, 0x35, 0x3a, 0x35, 0x39, 0x3a,
+    0x66, 0x35, 0x3a, 0x66, 0x61, 0x3a, 0x35, 0x64, 0x3a, 0x34, 0x63, 0x3a,
+    0x36, 0x64, 0x3a, 0x62, 0x33, 0x3a, 0x66, 0x39, 0x3a, 0x66, 0x37, 0x3a,
+    0x32, 0x66, 0x3a, 0x66, 0x31, 0x3a, 0x39, 0x33, 0x3a, 0x34, 0x32, 0x3a,
+    0x30, 0x33, 0x3a, 0x33, 0x35, 0x3a, 0x37, 0x38, 0x3a, 0x66, 0x30, 0x3a,
+    0x37, 0x33, 0x3a, 0x62, 0x66, 0x3a, 0x31, 0x64, 0x3a, 0x31, 0x62, 0x3a,
+    0x34, 0x36, 0x3a, 0x63, 0x62, 0x3a, 0x62, 0x39, 0x3a, 0x31, 0x32, 0x0a,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x61, 0x44, 0x43, 0x43,
+    0x41, 0x31, 0x43, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42,
+    0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47,
+    0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x46,
+    0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47,
+    0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x57, 0x0a, 0x4d, 0x42, 0x51,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4e, 0x52, 0x32, 0x56,
+    0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x53, 0x57, 0x35,
+    0x6a, 0x4c, 0x6a, 0x45, 0x65, 0x4d, 0x42, 0x77, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x41, 0x78, 0x4d, 0x56, 0x52, 0x32, 0x56, 0x76, 0x56, 0x48, 0x4a,
+    0x31, 0x63, 0x33, 0x51, 0x67, 0x56, 0x57, 0x35, 0x70, 0x64, 0x6d, 0x56,
+    0x79, 0x0a, 0x63, 0x32, 0x46, 0x73, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x42,
+    0x34, 0x58, 0x44, 0x54, 0x41, 0x30, 0x4d, 0x44, 0x4d, 0x77, 0x4e, 0x44,
+    0x41, 0x31, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54,
+    0x49, 0x35, 0x4d, 0x44, 0x4d, 0x77, 0x4e, 0x44, 0x41, 0x31, 0x4d, 0x44,
+    0x41, 0x77, 0x4d, 0x46, 0x6f, 0x77, 0x52, 0x54, 0x45, 0x4c, 0x4d, 0x41,
+    0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x42, 0x68, 0x4d, 0x43, 0x56,
+    0x56, 0x4d, 0x78, 0x46, 0x6a, 0x41, 0x55, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x6f, 0x54, 0x44, 0x55, 0x64, 0x6c, 0x62, 0x31, 0x52, 0x79, 0x64,
+    0x58, 0x4e, 0x30, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x48,
+    0x6a, 0x41, 0x63, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x46,
+    0x55, 0x64, 0x6c, 0x62, 0x31, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x0a,
+    0x49, 0x46, 0x56, 0x75, 0x61, 0x58, 0x5a, 0x6c, 0x63, 0x6e, 0x4e, 0x68,
+    0x62, 0x43, 0x42, 0x44, 0x51, 0x54, 0x43, 0x43, 0x41, 0x69, 0x49, 0x77,
+    0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e,
+    0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x50,
+    0x41, 0x44, 0x43, 0x43, 0x41, 0x67, 0x6f, 0x43, 0x67, 0x67, 0x49, 0x42,
+    0x41, 0x4b, 0x59, 0x56, 0x0a, 0x56, 0x61, 0x43, 0x6a, 0x78, 0x75, 0x41,
+    0x66, 0x6a, 0x4a, 0x30, 0x68, 0x55, 0x4e, 0x66, 0x42, 0x76, 0x69, 0x74,
+    0x62, 0x74, 0x61, 0x53, 0x65, 0x6f, 0x64, 0x6c, 0x79, 0x57, 0x4c, 0x30,
+    0x41, 0x47, 0x30, 0x79, 0x2f, 0x59, 0x63, 0x6b, 0x55, 0x48, 0x55, 0x57,
+    0x43, 0x71, 0x38, 0x59, 0x64, 0x67, 0x4e, 0x59, 0x39, 0x36, 0x78, 0x43,
+    0x63, 0x4f, 0x71, 0x39, 0x74, 0x4a, 0x50, 0x69, 0x38, 0x0a, 0x63, 0x51,
+    0x47, 0x65, 0x42, 0x76, 0x56, 0x38, 0x58, 0x78, 0x37, 0x42, 0x44, 0x6c,
+    0x58, 0x4b, 0x67, 0x35, 0x70, 0x5a, 0x4d, 0x4b, 0x34, 0x5a, 0x79, 0x7a,
+    0x42, 0x49, 0x6c, 0x65, 0x30, 0x69, 0x4e, 0x34, 0x33, 0x30, 0x53, 0x70,
+    0x70, 0x79, 0x5a, 0x6a, 0x36, 0x74, 0x6c, 0x63, 0x44, 0x67, 0x46, 0x67,
+    0x44, 0x67, 0x45, 0x42, 0x38, 0x72, 0x4d, 0x51, 0x37, 0x58, 0x6c, 0x46,
+    0x54, 0x54, 0x0a, 0x51, 0x6a, 0x4f, 0x67, 0x4e, 0x42, 0x30, 0x65, 0x52,
+    0x58, 0x62, 0x64, 0x54, 0x38, 0x6f, 0x59, 0x4e, 0x2b, 0x79, 0x46, 0x46,
+    0x58, 0x6f, 0x5a, 0x43, 0x50, 0x7a, 0x56, 0x78, 0x35, 0x7a, 0x77, 0x38,
+    0x71, 0x6b, 0x75, 0x45, 0x4b, 0x6d, 0x53, 0x35, 0x6a, 0x31, 0x59, 0x50,
+    0x61, 0x6b, 0x57, 0x61, 0x44, 0x77, 0x76, 0x64, 0x53, 0x45, 0x59, 0x66,
+    0x79, 0x68, 0x33, 0x70, 0x65, 0x46, 0x68, 0x0a, 0x46, 0x37, 0x65, 0x6d,
+    0x36, 0x66, 0x67, 0x65, 0x6d, 0x64, 0x74, 0x7a, 0x62, 0x76, 0x51, 0x4b,
+    0x6f, 0x69, 0x46, 0x73, 0x37, 0x74, 0x71, 0x71, 0x68, 0x5a, 0x4a, 0x6d,
+    0x72, 0x2f, 0x5a, 0x36, 0x61, 0x34, 0x4c, 0x61, 0x75, 0x69, 0x49, 0x49,
+    0x4e, 0x51, 0x2f, 0x50, 0x51, 0x76, 0x45, 0x31, 0x2b, 0x6d, 0x72, 0x75,
+    0x66, 0x69, 0x73, 0x6c, 0x7a, 0x44, 0x6f, 0x52, 0x35, 0x47, 0x32, 0x76,
+    0x0a, 0x63, 0x37, 0x4a, 0x32, 0x48, 0x61, 0x33, 0x51, 0x73, 0x6e, 0x68,
+    0x6e, 0x47, 0x71, 0x51, 0x35, 0x48, 0x46, 0x45, 0x4c, 0x5a, 0x31, 0x61,
+    0x44, 0x2f, 0x54, 0x68, 0x64, 0x44, 0x63, 0x37, 0x64, 0x38, 0x4c, 0x73,
+    0x72, 0x6c, 0x68, 0x2f, 0x65, 0x65, 0x7a, 0x4a, 0x53, 0x2f, 0x52, 0x32,
+    0x37, 0x74, 0x51, 0x61, 0x68, 0x73, 0x69, 0x46, 0x65, 0x70, 0x64, 0x61,
+    0x56, 0x61, 0x48, 0x2f, 0x77, 0x0a, 0x6d, 0x5a, 0x37, 0x63, 0x52, 0x51,
+    0x67, 0x2b, 0x35, 0x39, 0x49, 0x4a, 0x44, 0x54, 0x57, 0x55, 0x33, 0x59,
+    0x42, 0x4f, 0x55, 0x35, 0x66, 0x58, 0x74, 0x51, 0x6c, 0x45, 0x49, 0x47,
+    0x51, 0x57, 0x46, 0x77, 0x4d, 0x43, 0x54, 0x46, 0x4d, 0x4e, 0x61, 0x4e,
+    0x37, 0x56, 0x71, 0x6e, 0x4a, 0x4e, 0x6b, 0x32, 0x32, 0x43, 0x44, 0x74,
+    0x75, 0x63, 0x76, 0x63, 0x2b, 0x30, 0x38, 0x31, 0x78, 0x64, 0x0a, 0x56,
+    0x48, 0x70, 0x70, 0x43, 0x5a, 0x62, 0x57, 0x32, 0x78, 0x48, 0x42, 0x6a,
+    0x58, 0x57, 0x6f, 0x74, 0x4d, 0x38, 0x35, 0x79, 0x4d, 0x34, 0x38, 0x76,
+    0x43, 0x52, 0x38, 0x35, 0x6d, 0x4c, 0x4b, 0x34, 0x62, 0x31, 0x39, 0x70,
+    0x37, 0x31, 0x58, 0x5a, 0x51, 0x76, 0x6b, 0x2f, 0x69, 0x58, 0x74, 0x74,
+    0x6d, 0x6b, 0x51, 0x33, 0x43, 0x67, 0x61, 0x52, 0x72, 0x30, 0x42, 0x48,
+    0x64, 0x43, 0x58, 0x0a, 0x74, 0x65, 0x47, 0x59, 0x4f, 0x38, 0x41, 0x33,
+    0x5a, 0x4e, 0x59, 0x39, 0x6c, 0x4f, 0x34, 0x4c, 0x34, 0x66, 0x55, 0x6f,
+    0x72, 0x67, 0x74, 0x57, 0x76, 0x33, 0x47, 0x4c, 0x49, 0x79, 0x6c, 0x42,
+    0x6a, 0x6f, 0x62, 0x46, 0x53, 0x31, 0x4a, 0x37, 0x32, 0x48, 0x47, 0x72,
+    0x48, 0x34, 0x6f, 0x56, 0x70, 0x6a, 0x75, 0x44, 0x57, 0x74, 0x64, 0x59,
+    0x41, 0x56, 0x48, 0x47, 0x54, 0x45, 0x48, 0x5a, 0x0a, 0x66, 0x39, 0x68,
+    0x42, 0x5a, 0x33, 0x4b, 0x69, 0x4b, 0x4e, 0x39, 0x67, 0x67, 0x36, 0x6d,
+    0x65, 0x79, 0x48, 0x76, 0x38, 0x55, 0x33, 0x4e, 0x79, 0x57, 0x66, 0x57,
+    0x54, 0x65, 0x68, 0x64, 0x32, 0x44, 0x73, 0x37, 0x33, 0x35, 0x56, 0x7a,
+    0x5a, 0x43, 0x31, 0x55, 0x30, 0x6f, 0x71, 0x70, 0x62, 0x74, 0x57, 0x70,
+    0x55, 0x35, 0x78, 0x50, 0x4b, 0x56, 0x2b, 0x79, 0x58, 0x62, 0x66, 0x52,
+    0x65, 0x0a, 0x42, 0x69, 0x39, 0x46, 0x69, 0x31, 0x6a, 0x55, 0x49, 0x78,
+    0x61, 0x53, 0x35, 0x42, 0x5a, 0x75, 0x4b, 0x47, 0x4e, 0x5a, 0x4d, 0x4e,
+    0x39, 0x51, 0x41, 0x5a, 0x78, 0x6a, 0x69, 0x52, 0x71, 0x66, 0x32, 0x78,
+    0x65, 0x55, 0x67, 0x6e, 0x41, 0x33, 0x77, 0x79, 0x53, 0x65, 0x6d, 0x6b,
+    0x66, 0x57, 0x57, 0x73, 0x70, 0x4f, 0x71, 0x47, 0x6d, 0x4a, 0x63, 0x68,
+    0x2b, 0x52, 0x62, 0x4e, 0x74, 0x2b, 0x0a, 0x6e, 0x68, 0x75, 0x74, 0x78,
+    0x78, 0x39, 0x7a, 0x33, 0x53, 0x78, 0x50, 0x47, 0x57, 0x58, 0x39, 0x66,
+    0x35, 0x4e, 0x41, 0x45, 0x43, 0x37, 0x53, 0x38, 0x4f, 0x30, 0x38, 0x6e,
+    0x69, 0x34, 0x6f, 0x50, 0x6d, 0x6b, 0x6d, 0x4d, 0x38, 0x56, 0x37, 0x41,
+    0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x59, 0x7a, 0x42, 0x68, 0x4d,
+    0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x0a,
+    0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77,
+    0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45,
+    0x46, 0x4e, 0x71, 0x37, 0x4c, 0x71, 0x71, 0x77, 0x44, 0x4c, 0x69, 0x49,
+    0x4a, 0x6c, 0x46, 0x30, 0x58, 0x47, 0x30, 0x44, 0x30, 0x38, 0x44, 0x59,
+    0x6a, 0x33, 0x72, 0x57, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64,
+    0x49, 0x77, 0x51, 0x59, 0x0a, 0x4d, 0x42, 0x61, 0x41, 0x46, 0x4e, 0x71,
+    0x37, 0x4c, 0x71, 0x71, 0x77, 0x44, 0x4c, 0x69, 0x49, 0x4a, 0x6c, 0x46,
+    0x30, 0x58, 0x47, 0x30, 0x44, 0x30, 0x38, 0x44, 0x59, 0x6a, 0x33, 0x72,
+    0x57, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45,
+    0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x68, 0x6a, 0x41,
+    0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x0a, 0x39, 0x77,
+    0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67,
+    0x45, 0x41, 0x4d, 0x58, 0x6a, 0x6d, 0x78, 0x37, 0x58, 0x66, 0x75, 0x4a,
+    0x52, 0x41, 0x79, 0x58, 0x48, 0x45, 0x71, 0x44, 0x58, 0x73, 0x52, 0x68,
+    0x33, 0x43, 0x68, 0x66, 0x4d, 0x6f, 0x57, 0x49, 0x61, 0x77, 0x43, 0x2f,
+    0x79, 0x4f, 0x73, 0x6a, 0x6d, 0x50, 0x52, 0x46, 0x57, 0x72, 0x5a, 0x49,
+    0x52, 0x63, 0x0a, 0x61, 0x61, 0x6e, 0x51, 0x6d, 0x6a, 0x67, 0x38, 0x2b,
+    0x75, 0x55, 0x66, 0x4e, 0x65, 0x56, 0x45, 0x34, 0x34, 0x42, 0x35, 0x6c,
+    0x47, 0x69, 0x6b, 0x75, 0x38, 0x53, 0x66, 0x50, 0x65, 0x45, 0x30, 0x7a,
+    0x54, 0x42, 0x47, 0x69, 0x31, 0x51, 0x72, 0x6c, 0x61, 0x58, 0x76, 0x39,
+    0x7a, 0x2b, 0x5a, 0x68, 0x50, 0x30, 0x31, 0x35, 0x73, 0x38, 0x78, 0x78,
+    0x74, 0x78, 0x71, 0x76, 0x36, 0x66, 0x58, 0x0a, 0x49, 0x77, 0x6a, 0x68,
+    0x6d, 0x46, 0x37, 0x44, 0x57, 0x67, 0x68, 0x32, 0x71, 0x61, 0x61, 0x76,
+    0x64, 0x79, 0x2b, 0x33, 0x59, 0x4c, 0x31, 0x45, 0x52, 0x6d, 0x72, 0x76,
+    0x6c, 0x2f, 0x39, 0x7a, 0x6c, 0x63, 0x47, 0x4f, 0x36, 0x4a, 0x50, 0x37,
+    0x2f, 0x54, 0x47, 0x33, 0x37, 0x46, 0x63, 0x52, 0x45, 0x55, 0x57, 0x62,
+    0x4d, 0x50, 0x45, 0x61, 0x69, 0x44, 0x6e, 0x42, 0x54, 0x7a, 0x79, 0x6e,
+    0x0a, 0x41, 0x4e, 0x58, 0x48, 0x2f, 0x4b, 0x74, 0x74, 0x67, 0x43, 0x4a,
+    0x77, 0x70, 0x51, 0x7a, 0x67, 0x58, 0x51, 0x51, 0x70, 0x41, 0x76, 0x76,
+    0x4c, 0x6f, 0x4a, 0x48, 0x52, 0x66, 0x4e, 0x62, 0x44, 0x66, 0x6c, 0x44,
+    0x56, 0x6e, 0x56, 0x69, 0x2b, 0x51, 0x54, 0x6a, 0x72, 0x75, 0x58, 0x55,
+    0x38, 0x46, 0x64, 0x6d, 0x62, 0x79, 0x55, 0x71, 0x44, 0x57, 0x63, 0x44,
+    0x61, 0x55, 0x2f, 0x30, 0x7a, 0x0a, 0x75, 0x7a, 0x59, 0x59, 0x6d, 0x34,
+    0x55, 0x50, 0x46, 0x64, 0x33, 0x75, 0x4c, 0x61, 0x78, 0x32, 0x6b, 0x37,
+    0x6e, 0x5a, 0x41, 0x59, 0x31, 0x49, 0x45, 0x4b, 0x6a, 0x37, 0x39, 0x54,
+    0x69, 0x47, 0x38, 0x64, 0x73, 0x4b, 0x78, 0x72, 0x32, 0x45, 0x6f, 0x79,
+    0x4e, 0x42, 0x33, 0x74, 0x5a, 0x33, 0x62, 0x34, 0x58, 0x55, 0x68, 0x52,
+    0x78, 0x51, 0x34, 0x4b, 0x35, 0x52, 0x69, 0x72, 0x71, 0x4e, 0x0a, 0x50,
+    0x6e, 0x62, 0x69, 0x75, 0x63, 0x6f, 0x6e, 0x38, 0x6c, 0x2b, 0x66, 0x37,
+    0x32, 0x35, 0x5a, 0x44, 0x51, 0x62, 0x59, 0x4b, 0x78, 0x65, 0x6b, 0x30,
+    0x6e, 0x78, 0x72, 0x75, 0x31, 0x38, 0x55, 0x47, 0x6b, 0x69, 0x50, 0x47,
+    0x6b, 0x7a, 0x6e, 0x73, 0x30, 0x63, 0x63, 0x6a, 0x6b, 0x78, 0x46, 0x4b,
+    0x79, 0x44, 0x75, 0x53, 0x4e, 0x2f, 0x6e, 0x33, 0x51, 0x6d, 0x4f, 0x47,
+    0x4b, 0x6a, 0x61, 0x0a, 0x51, 0x49, 0x32, 0x53, 0x4a, 0x68, 0x46, 0x54,
+    0x59, 0x58, 0x4e, 0x64, 0x36, 0x37, 0x33, 0x6e, 0x78, 0x45, 0x30, 0x70,
+    0x4e, 0x32, 0x48, 0x72, 0x72, 0x44, 0x6b, 0x74, 0x5a, 0x79, 0x34, 0x57,
+    0x31, 0x76, 0x55, 0x41, 0x67, 0x34, 0x57, 0x68, 0x7a, 0x48, 0x39, 0x32,
+    0x78, 0x48, 0x33, 0x6b, 0x74, 0x30, 0x74, 0x6d, 0x37, 0x77, 0x4e, 0x46,
+    0x59, 0x47, 0x6d, 0x32, 0x44, 0x46, 0x4b, 0x57, 0x0a, 0x6b, 0x6f, 0x52,
+    0x65, 0x70, 0x71, 0x4f, 0x31, 0x70, 0x44, 0x34, 0x72, 0x32, 0x63, 0x7a,
+    0x59, 0x47, 0x30, 0x65, 0x71, 0x38, 0x6b, 0x54, 0x61, 0x54, 0x2f, 0x6b,
+    0x44, 0x36, 0x50, 0x41, 0x55, 0x79, 0x7a, 0x2f, 0x7a, 0x67, 0x39, 0x37,
+    0x51, 0x77, 0x56, 0x54, 0x6a, 0x74, 0x2b, 0x67, 0x4b, 0x4e, 0x30, 0x32,
+    0x4c, 0x49, 0x46, 0x6b, 0x44, 0x4d, 0x42, 0x6d, 0x68, 0x4c, 0x4d, 0x69,
+    0x39, 0x0a, 0x45, 0x52, 0x2f, 0x66, 0x72, 0x73, 0x6c, 0x4b, 0x78, 0x66,
+    0x4d, 0x6e, 0x5a, 0x6d, 0x61, 0x47, 0x72, 0x47, 0x69, 0x52, 0x2f, 0x39,
+    0x6e, 0x6d, 0x55, 0x78, 0x77, 0x50, 0x69, 0x31, 0x78, 0x70, 0x5a, 0x51,
+    0x6f, 0x6d, 0x79, 0x42, 0x34, 0x30, 0x77, 0x31, 0x31, 0x52, 0x65, 0x39,
+    0x65, 0x70, 0x6e, 0x41, 0x61, 0x68, 0x4e, 0x74, 0x33, 0x56, 0x69, 0x5a,
+    0x53, 0x38, 0x32, 0x65, 0x51, 0x74, 0x0a, 0x44, 0x46, 0x34, 0x4a, 0x62,
+    0x41, 0x69, 0x58, 0x66, 0x4b, 0x4d, 0x39, 0x66, 0x4a, 0x50, 0x2f, 0x50,
+    0x36, 0x45, 0x55, 0x70, 0x38, 0x2b, 0x31, 0x58, 0x65, 0x76, 0x62, 0x32,
+    0x78, 0x7a, 0x45, 0x64, 0x74, 0x2b, 0x49, 0x75, 0x62, 0x31, 0x46, 0x42,
+    0x5a, 0x55, 0x62, 0x72, 0x76, 0x78, 0x47, 0x61, 0x6b, 0x79, 0x76, 0x53,
+    0x4f, 0x50, 0x4f, 0x72, 0x67, 0x2f, 0x53, 0x66, 0x75, 0x76, 0x6d, 0x0a,
+    0x62, 0x4a, 0x78, 0x50, 0x67, 0x57, 0x70, 0x36, 0x5a, 0x4b, 0x79, 0x37,
+    0x50, 0x74, 0x58, 0x6e, 0x79, 0x33, 0x59, 0x75, 0x78, 0x61, 0x64, 0x49,
+    0x77, 0x56, 0x79, 0x51, 0x44, 0x38, 0x76, 0x49, 0x50, 0x2f, 0x72, 0x6d,
+    0x4d, 0x75, 0x47, 0x4e, 0x47, 0x32, 0x2b, 0x6b, 0x35, 0x6f, 0x37, 0x59,
+    0x2b, 0x53, 0x6c, 0x49, 0x69, 0x73, 0x35, 0x7a, 0x2f, 0x69, 0x77, 0x3d,
+    0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45,
+    0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72,
+    0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73,
+    0x74, 0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20,
+    0x43, 0x41, 0x20, 0x32, 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72,
+    0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53,
+    0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47,
+    0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x55, 0x6e, 0x69, 0x76,
+    0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x32, 0x20, 0x4f,
+    0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e,
+    0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20,
+    0x22, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x55, 0x6e,
+    0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x32,
+    0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20,
+    0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x34, 0x3a,
+    0x66, 0x63, 0x3a, 0x62, 0x38, 0x3a, 0x64, 0x30, 0x3a, 0x33, 0x36, 0x3a,
+    0x64, 0x62, 0x3a, 0x39, 0x65, 0x3a, 0x31, 0x34, 0x3a, 0x62, 0x33, 0x3a,
+    0x63, 0x32, 0x3a, 0x66, 0x32, 0x3a, 0x64, 0x62, 0x3a, 0x38, 0x66, 0x3a,
+    0x65, 0x34, 0x3a, 0x39, 0x34, 0x3a, 0x63, 0x37, 0x0a, 0x23, 0x20, 0x53,
+    0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x37, 0x3a, 0x39, 0x61, 0x3a, 0x31,
+    0x39, 0x3a, 0x37, 0x62, 0x3a, 0x34, 0x31, 0x3a, 0x38, 0x35, 0x3a, 0x34,
+    0x35, 0x3a, 0x33, 0x35, 0x3a, 0x30, 0x63, 0x3a, 0x61, 0x36, 0x3a, 0x30,
+    0x33, 0x3a, 0x36, 0x39, 0x3a, 0x66, 0x33, 0x3a, 0x33, 0x63, 0x3a, 0x32,
+    0x65, 0x3a, 0x61, 0x66, 0x3a, 0x34, 0x37, 0x3a, 0x34, 0x66, 0x3a, 0x32,
+    0x30, 0x3a, 0x37, 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35,
+    0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x61, 0x30, 0x3a, 0x32, 0x33, 0x3a, 0x34, 0x66, 0x3a,
+    0x33, 0x62, 0x3a, 0x63, 0x38, 0x3a, 0x35, 0x32, 0x3a, 0x37, 0x63, 0x3a,
+    0x61, 0x35, 0x3a, 0x36, 0x32, 0x3a, 0x38, 0x65, 0x3a, 0x65, 0x63, 0x3a,
+    0x38, 0x31, 0x3a, 0x61, 0x64, 0x3a, 0x35, 0x64, 0x3a, 0x36, 0x39, 0x3a,
+    0x38, 0x39, 0x3a, 0x35, 0x64, 0x3a, 0x61, 0x35, 0x3a, 0x36, 0x38, 0x3a,
+    0x30, 0x64, 0x3a, 0x63, 0x39, 0x3a, 0x31, 0x64, 0x3a, 0x31, 0x63, 0x3a,
+    0x62, 0x38, 0x3a, 0x34, 0x37, 0x3a, 0x37, 0x66, 0x3a, 0x33, 0x33, 0x3a,
+    0x66, 0x38, 0x3a, 0x37, 0x38, 0x3a, 0x62, 0x39, 0x3a, 0x35, 0x62, 0x3a,
+    0x30, 0x62, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49,
+    0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54,
+    0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x62,
+    0x44, 0x43, 0x43, 0x41, 0x31, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41,
+    0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68,
+    0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41,
+    0x44, 0x42, 0x48, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x57, 0x0a,
+    0x4d, 0x42, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4e,
+    0x52, 0x32, 0x56, 0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67,
+    0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x67, 0x4d, 0x42, 0x34, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x58, 0x52, 0x32, 0x56, 0x76,
+    0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x56, 0x57, 0x35, 0x70,
+    0x64, 0x6d, 0x56, 0x79, 0x0a, 0x63, 0x32, 0x46, 0x73, 0x49, 0x45, 0x4e,
+    0x42, 0x49, 0x44, 0x49, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x51,
+    0x77, 0x4d, 0x7a, 0x41, 0x30, 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x44, 0x41,
+    0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x6b, 0x77, 0x4d, 0x7a, 0x41,
+    0x30, 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x6a, 0x42,
+    0x48, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x0a, 0x56, 0x51,
+    0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x57, 0x4d, 0x42,
+    0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4e, 0x52, 0x32,
+    0x56, 0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x53, 0x57,
+    0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x67, 0x4d, 0x42, 0x34, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x41, 0x78, 0x4d, 0x58, 0x52, 0x32, 0x56, 0x76, 0x56, 0x48,
+    0x4a, 0x31, 0x0a, 0x63, 0x33, 0x51, 0x67, 0x56, 0x57, 0x35, 0x70, 0x64,
+    0x6d, 0x56, 0x79, 0x63, 0x32, 0x46, 0x73, 0x49, 0x45, 0x4e, 0x42, 0x49,
+    0x44, 0x49, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43,
+    0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41,
+    0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67,
+    0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x0a, 0x41, 0x51, 0x43, 0x7a,
+    0x56, 0x46, 0x4c, 0x42, 0x79, 0x54, 0x37, 0x79, 0x32, 0x64, 0x79, 0x78,
+    0x55, 0x78, 0x70, 0x5a, 0x4b, 0x65, 0x65, 0x78, 0x77, 0x30, 0x55, 0x6f,
+    0x35, 0x64, 0x66, 0x52, 0x37, 0x63, 0x58, 0x46, 0x53, 0x36, 0x47, 0x71,
+    0x64, 0x48, 0x74, 0x58, 0x72, 0x30, 0x6f, 0x6d, 0x2f, 0x4e, 0x6a, 0x31,
+    0x58, 0x71, 0x64, 0x75, 0x47, 0x64, 0x74, 0x30, 0x44, 0x45, 0x38, 0x31,
+    0x0a, 0x57, 0x7a, 0x49, 0x4c, 0x41, 0x65, 0x50, 0x62, 0x36, 0x33, 0x70,
+    0x33, 0x4e, 0x65, 0x71, 0x71, 0x57, 0x75, 0x44, 0x57, 0x36, 0x4b, 0x46,
+    0x58, 0x6c, 0x50, 0x43, 0x51, 0x6f, 0x33, 0x52, 0x57, 0x6c, 0x45, 0x51,
+    0x77, 0x41, 0x78, 0x35, 0x63, 0x54, 0x69, 0x75, 0x46, 0x4a, 0x6e, 0x53,
+    0x43, 0x65, 0x67, 0x78, 0x32, 0x6f, 0x47, 0x39, 0x4e, 0x7a, 0x6b, 0x45,
+    0x74, 0x6f, 0x42, 0x55, 0x47, 0x0a, 0x46, 0x46, 0x2b, 0x33, 0x51, 0x73,
+    0x31, 0x37, 0x6a, 0x31, 0x68, 0x68, 0x4e, 0x4e, 0x77, 0x71, 0x43, 0x50,
+    0x6b, 0x75, 0x77, 0x77, 0x47, 0x6d, 0x49, 0x6b, 0x51, 0x63, 0x54, 0x41,
+    0x65, 0x43, 0x35, 0x6c, 0x76, 0x4f, 0x30, 0x45, 0x70, 0x38, 0x42, 0x4e,
+    0x4d, 0x5a, 0x63, 0x79, 0x66, 0x77, 0x71, 0x70, 0x68, 0x2f, 0x4c, 0x71,
+    0x39, 0x4f, 0x36, 0x34, 0x63, 0x65, 0x4a, 0x48, 0x64, 0x71, 0x0a, 0x58,
+    0x62, 0x62, 0x6f, 0x57, 0x30, 0x57, 0x36, 0x33, 0x4d, 0x4f, 0x68, 0x42,
+    0x57, 0x39, 0x57, 0x6a, 0x6f, 0x38, 0x51, 0x4a, 0x71, 0x56, 0x4a, 0x77,
+    0x79, 0x37, 0x58, 0x51, 0x59, 0x63, 0x69, 0x34, 0x45, 0x2b, 0x47, 0x79,
+    0x6d, 0x43, 0x31, 0x36, 0x71, 0x46, 0x6a, 0x77, 0x41, 0x47, 0x58, 0x45,
+    0x48, 0x6d, 0x39, 0x41, 0x44, 0x77, 0x53, 0x62, 0x53, 0x73, 0x56, 0x73,
+    0x61, 0x78, 0x4c, 0x0a, 0x73, 0x65, 0x34, 0x59, 0x75, 0x55, 0x36, 0x57,
+    0x33, 0x4e, 0x78, 0x32, 0x2f, 0x7a, 0x75, 0x2b, 0x7a, 0x31, 0x38, 0x44,
+    0x77, 0x50, 0x77, 0x37, 0x36, 0x4c, 0x35, 0x47, 0x47, 0x2f, 0x2f, 0x61,
+    0x51, 0x4d, 0x4a, 0x53, 0x39, 0x2f, 0x37, 0x6a, 0x4f, 0x76, 0x64, 0x71,
+    0x64, 0x7a, 0x58, 0x51, 0x32, 0x6f, 0x33, 0x72, 0x58, 0x68, 0x68, 0x71,
+    0x4d, 0x63, 0x63, 0x65, 0x75, 0x6a, 0x77, 0x62, 0x0a, 0x4b, 0x4e, 0x5a,
+    0x72, 0x56, 0x4d, 0x61, 0x71, 0x57, 0x39, 0x65, 0x69, 0x4c, 0x42, 0x73,
+    0x5a, 0x7a, 0x4b, 0x49, 0x43, 0x39, 0x70, 0x74, 0x5a, 0x76, 0x54, 0x64,
+    0x72, 0x68, 0x72, 0x56, 0x74, 0x67, 0x72, 0x72, 0x59, 0x36, 0x73, 0x6c,
+    0x57, 0x76, 0x4b, 0x6b, 0x32, 0x57, 0x50, 0x30, 0x2b, 0x47, 0x66, 0x50,
+    0x74, 0x44, 0x43, 0x61, 0x70, 0x6b, 0x7a, 0x6a, 0x34, 0x54, 0x38, 0x46,
+    0x64, 0x0a, 0x49, 0x67, 0x62, 0x51, 0x6c, 0x2b, 0x72, 0x68, 0x72, 0x63,
+    0x5a, 0x56, 0x34, 0x49, 0x45, 0x72, 0x4b, 0x49, 0x4d, 0x36, 0x2b, 0x76,
+    0x52, 0x37, 0x49, 0x56, 0x45, 0x41, 0x76, 0x6c, 0x49, 0x34, 0x7a, 0x73,
+    0x31, 0x6d, 0x65, 0x61, 0x6a, 0x30, 0x67, 0x56, 0x62, 0x69, 0x30, 0x49,
+    0x4d, 0x4a, 0x52, 0x31, 0x46, 0x62, 0x55, 0x47, 0x72, 0x50, 0x32, 0x30,
+    0x67, 0x61, 0x58, 0x54, 0x37, 0x33, 0x0a, 0x79, 0x2f, 0x5a, 0x6c, 0x39,
+    0x32, 0x7a, 0x78, 0x6c, 0x66, 0x67, 0x43, 0x4f, 0x7a, 0x4a, 0x57, 0x67,
+    0x6a, 0x6c, 0x36, 0x57, 0x37, 0x30, 0x76, 0x69, 0x52, 0x75, 0x2f, 0x6f,
+    0x62, 0x54, 0x6f, 0x2f, 0x33, 0x2b, 0x4e, 0x6a, 0x4e, 0x38, 0x44, 0x38,
+    0x57, 0x42, 0x4f, 0x57, 0x42, 0x46, 0x4d, 0x36, 0x36, 0x4d, 0x2f, 0x45,
+    0x43, 0x75, 0x44, 0x6d, 0x67, 0x46, 0x7a, 0x32, 0x5a, 0x52, 0x74, 0x0a,
+    0x68, 0x41, 0x41, 0x6e, 0x5a, 0x71, 0x7a, 0x77, 0x63, 0x45, 0x41, 0x4a,
+    0x51, 0x70, 0x4b, 0x74, 0x54, 0x35, 0x4d, 0x4e, 0x59, 0x51, 0x6c, 0x52,
+    0x4a, 0x4e, 0x69, 0x53, 0x31, 0x51, 0x75, 0x55, 0x59, 0x62, 0x4b, 0x48,
+    0x73, 0x75, 0x33, 0x2f, 0x6d, 0x6a, 0x58, 0x2f, 0x68, 0x56, 0x54, 0x4b,
+    0x37, 0x55, 0x52, 0x44, 0x72, 0x42, 0x73, 0x38, 0x46, 0x6d, 0x74, 0x49,
+    0x53, 0x67, 0x6f, 0x63, 0x0a, 0x51, 0x49, 0x67, 0x66, 0x6b, 0x73, 0x49,
+    0x4c, 0x41, 0x41, 0x58, 0x2f, 0x38, 0x73, 0x67, 0x43, 0x53, 0x71, 0x53,
+    0x71, 0x71, 0x63, 0x79, 0x5a, 0x6c, 0x70, 0x77, 0x76, 0x57, 0x4f, 0x42,
+    0x39, 0x34, 0x62, 0x36, 0x37, 0x42, 0x39, 0x78, 0x66, 0x42, 0x48, 0x4a,
+    0x63, 0x4d, 0x54, 0x54, 0x44, 0x37, 0x46, 0x38, 0x74, 0x34, 0x44, 0x31,
+    0x6b, 0x6b, 0x43, 0x4c, 0x6d, 0x30, 0x65, 0x79, 0x34, 0x0a, 0x4c, 0x74,
+    0x31, 0x5a, 0x72, 0x74, 0x6d, 0x68, 0x4e, 0x37, 0x39, 0x55, 0x4e, 0x64,
+    0x78, 0x7a, 0x4d, 0x6b, 0x2b, 0x4d, 0x42, 0x42, 0x34, 0x7a, 0x73, 0x73,
+    0x6c, 0x47, 0x38, 0x64, 0x68, 0x63, 0x79, 0x46, 0x56, 0x51, 0x79, 0x57,
+    0x69, 0x39, 0x71, 0x4c, 0x6f, 0x32, 0x43, 0x51, 0x49, 0x44, 0x41, 0x51,
+    0x41, 0x42, 0x6f, 0x32, 0x4d, 0x77, 0x59, 0x54, 0x41, 0x50, 0x42, 0x67,
+    0x4e, 0x56, 0x0a, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42,
+    0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x42, 0x30, 0x47, 0x41,
+    0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x52, 0x32, 0x38,
+    0x31, 0x58, 0x68, 0x2b, 0x71, 0x51, 0x32, 0x2b, 0x2f, 0x43, 0x66, 0x58,
+    0x47, 0x4a, 0x78, 0x37, 0x54, 0x7a, 0x30, 0x52, 0x7a, 0x67, 0x51, 0x4b,
+    0x7a, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x53, 0x4d, 0x45,
+    0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x52, 0x32, 0x38, 0x31, 0x58, 0x68,
+    0x2b, 0x71, 0x51, 0x32, 0x2b, 0x2f, 0x43, 0x66, 0x58, 0x47, 0x4a, 0x78,
+    0x37, 0x54, 0x7a, 0x30, 0x52, 0x7a, 0x67, 0x51, 0x4b, 0x7a, 0x41, 0x4f,
+    0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45,
+    0x42, 0x41, 0x4d, 0x43, 0x41, 0x59, 0x59, 0x77, 0x44, 0x51, 0x59, 0x4a,
+    0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45,
+    0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x42, 0x41, 0x47, 0x62,
+    0x42, 0x78, 0x69, 0x50, 0x7a, 0x32, 0x65, 0x41, 0x75, 0x62, 0x6c, 0x2f,
+    0x6f, 0x7a, 0x36, 0x36, 0x77, 0x73, 0x43, 0x56, 0x4e, 0x4b, 0x2f, 0x67,
+    0x37, 0x57, 0x4a, 0x74, 0x41, 0x4a, 0x44, 0x64, 0x61, 0x79, 0x36, 0x73,
+    0x57, 0x53, 0x66, 0x2b, 0x7a, 0x0a, 0x64, 0x58, 0x6b, 0x7a, 0x6f, 0x53,
+    0x39, 0x74, 0x63, 0x42, 0x63, 0x30, 0x6b, 0x66, 0x35, 0x6e, 0x66, 0x6f,
+    0x2f, 0x73, 0x6d, 0x2b, 0x56, 0x65, 0x67, 0x71, 0x6c, 0x56, 0x48, 0x79,
+    0x2f, 0x63, 0x31, 0x46, 0x45, 0x48, 0x45, 0x76, 0x36, 0x73, 0x46, 0x6a,
+    0x34, 0x73, 0x4e, 0x63, 0x5a, 0x6a, 0x2f, 0x4e, 0x77, 0x51, 0x36, 0x77,
+    0x32, 0x6a, 0x71, 0x74, 0x42, 0x38, 0x7a, 0x4e, 0x48, 0x51, 0x0a, 0x4c,
+    0x31, 0x45, 0x75, 0x78, 0x42, 0x52, 0x61, 0x33, 0x75, 0x67, 0x5a, 0x34,
+    0x54, 0x37, 0x47, 0x7a, 0x4b, 0x51, 0x70, 0x35, 0x79, 0x36, 0x45, 0x71,
+    0x67, 0x59, 0x77, 0x65, 0x48, 0x5a, 0x55, 0x63, 0x79, 0x69, 0x59, 0x57,
+    0x54, 0x6a, 0x67, 0x41, 0x41, 0x31, 0x69, 0x30, 0x30, 0x4a, 0x39, 0x49,
+    0x5a, 0x2b, 0x75, 0x50, 0x54, 0x71, 0x4d, 0x31, 0x66, 0x70, 0x33, 0x44,
+    0x52, 0x67, 0x72, 0x0a, 0x46, 0x67, 0x35, 0x66, 0x4e, 0x75, 0x48, 0x38,
+    0x4b, 0x72, 0x55, 0x77, 0x4a, 0x4d, 0x2f, 0x67, 0x59, 0x77, 0x78, 0x37,
+    0x57, 0x42, 0x72, 0x2b, 0x6d, 0x62, 0x70, 0x43, 0x45, 0x72, 0x47, 0x52,
+    0x39, 0x48, 0x78, 0x6f, 0x34, 0x73, 0x6a, 0x6f, 0x72, 0x79, 0x7a, 0x71,
+    0x79, 0x58, 0x36, 0x75, 0x75, 0x79, 0x6f, 0x39, 0x44, 0x52, 0x58, 0x63,
+    0x4e, 0x4a, 0x57, 0x32, 0x47, 0x48, 0x53, 0x6f, 0x0a, 0x61, 0x67, 0x2f,
+    0x48, 0x74, 0x50, 0x51, 0x54, 0x78, 0x4f, 0x52, 0x62, 0x37, 0x51, 0x72,
+    0x53, 0x70, 0x4a, 0x64, 0x4d, 0x4b, 0x75, 0x30, 0x76, 0x62, 0x42, 0x4b,
+    0x4a, 0x50, 0x66, 0x45, 0x6e, 0x63, 0x4b, 0x70, 0x71, 0x41, 0x31, 0x49,
+    0x68, 0x6e, 0x30, 0x43, 0x6f, 0x5a, 0x31, 0x44, 0x79, 0x38, 0x31, 0x6f,
+    0x66, 0x33, 0x39, 0x38, 0x6a, 0x39, 0x74, 0x78, 0x34, 0x54, 0x75, 0x61,
+    0x59, 0x0a, 0x54, 0x31, 0x55, 0x36, 0x55, 0x2b, 0x50, 0x76, 0x38, 0x76,
+    0x53, 0x66, 0x78, 0x33, 0x7a, 0x59, 0x57, 0x4b, 0x38, 0x70, 0x49, 0x70,
+    0x65, 0x34, 0x34, 0x4c, 0x32, 0x52, 0x4c, 0x72, 0x42, 0x32, 0x37, 0x46,
+    0x63, 0x52, 0x7a, 0x2b, 0x38, 0x70, 0x52, 0x50, 0x50, 0x70, 0x68, 0x58,
+    0x70, 0x67, 0x59, 0x2b, 0x52, 0x64, 0x4d, 0x34, 0x6b, 0x58, 0x32, 0x54,
+    0x47, 0x71, 0x32, 0x74, 0x62, 0x7a, 0x0a, 0x47, 0x44, 0x56, 0x79, 0x7a,
+    0x34, 0x63, 0x72, 0x4c, 0x32, 0x4d, 0x6a, 0x68, 0x46, 0x32, 0x45, 0x6a,
+    0x44, 0x39, 0x58, 0x6f, 0x49, 0x6a, 0x38, 0x6d, 0x5a, 0x45, 0x6f, 0x4a,
+    0x6d, 0x6d, 0x5a, 0x31, 0x49, 0x2b, 0x58, 0x52, 0x4c, 0x36, 0x4f, 0x31,
+    0x55, 0x69, 0x78, 0x70, 0x43, 0x67, 0x70, 0x38, 0x52, 0x57, 0x30, 0x34,
+    0x65, 0x57, 0x65, 0x33, 0x66, 0x69, 0x50, 0x70, 0x6d, 0x38, 0x6d, 0x0a,
+    0x31, 0x77, 0x6b, 0x38, 0x4f, 0x68, 0x77, 0x52, 0x44, 0x71, 0x5a, 0x73,
+    0x4e, 0x2f, 0x65, 0x74, 0x52, 0x49, 0x63, 0x73, 0x4b, 0x4d, 0x66, 0x59,
+    0x64, 0x49, 0x4b, 0x7a, 0x30, 0x47, 0x39, 0x4b, 0x56, 0x37, 0x73, 0x31,
+    0x4b, 0x53, 0x65, 0x67, 0x69, 0x2b, 0x67, 0x68, 0x70, 0x34, 0x64, 0x6b,
+    0x4e, 0x6c, 0x33, 0x4d, 0x32, 0x42, 0x61, 0x73, 0x78, 0x37, 0x49, 0x6e,
+    0x51, 0x4a, 0x4a, 0x56, 0x0a, 0x4f, 0x43, 0x69, 0x4e, 0x55, 0x57, 0x37,
+    0x64, 0x46, 0x47, 0x64, 0x54, 0x62, 0x48, 0x46, 0x63, 0x4a, 0x6f, 0x52,
+    0x4e, 0x64, 0x56, 0x71, 0x32, 0x66, 0x6d, 0x42, 0x57, 0x71, 0x55, 0x32,
+    0x74, 0x2b, 0x35, 0x73, 0x65, 0x6c, 0x2f, 0x4d, 0x4e, 0x32, 0x64, 0x4b,
+    0x58, 0x56, 0x48, 0x66, 0x61, 0x50, 0x52, 0x4b, 0x33, 0x34, 0x42, 0x37,
+    0x76, 0x43, 0x41, 0x61, 0x73, 0x2b, 0x59, 0x57, 0x48, 0x0a, 0x36, 0x61,
+    0x4c, 0x63, 0x72, 0x33, 0x34, 0x59, 0x45, 0x6f, 0x50, 0x39, 0x56, 0x68,
+    0x64, 0x42, 0x4c, 0x74, 0x55, 0x70, 0x67, 0x6e, 0x32, 0x5a, 0x39, 0x44,
+    0x48, 0x32, 0x63, 0x61, 0x6e, 0x50, 0x4c, 0x41, 0x45, 0x6e, 0x70, 0x51,
+    0x57, 0x35, 0x71, 0x72, 0x4a, 0x49, 0x54, 0x69, 0x72, 0x76, 0x6e, 0x35,
+    0x4e, 0x53, 0x55, 0x5a, 0x55, 0x38, 0x55, 0x6e, 0x4f, 0x4f, 0x56, 0x6b,
+    0x77, 0x58, 0x0a, 0x51, 0x4d, 0x41, 0x4a, 0x4b, 0x4f, 0x53, 0x4c, 0x61,
+    0x6b, 0x68, 0x54, 0x32, 0x2b, 0x7a, 0x4e, 0x56, 0x56, 0x58, 0x78, 0x78,
+    0x76, 0x6a, 0x70, 0x6f, 0x69, 0x78, 0x4d, 0x70, 0x74, 0x45, 0x6d, 0x58,
+    0x33, 0x36, 0x76, 0x57, 0x6b, 0x7a, 0x61, 0x48, 0x36, 0x62, 0x79, 0x48,
+    0x43, 0x78, 0x2b, 0x72, 0x67, 0x49, 0x57, 0x30, 0x6c, 0x62, 0x51, 0x4c,
+    0x31, 0x64, 0x54, 0x52, 0x2b, 0x69, 0x53, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23,
+    0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d,
+    0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x20, 0x4f, 0x6e, 0x6c, 0x69,
+    0x6e, 0x65, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
+    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
+    0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x31, 0x20, 0x4f, 0x3d,
+    0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x20, 0x4f, 0x6e, 0x6c, 0x69,
+    0x6e, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75,
+    0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x6d,
+    0x65, 0x72, 0x69, 0x63, 0x61, 0x20, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65,
+    0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+    0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x31, 0x20, 0x4f, 0x3d, 0x41, 0x6d,
+    0x65, 0x72, 0x69, 0x63, 0x61, 0x20, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65,
+    0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65,
+    0x6c, 0x3a, 0x20, 0x22, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x20,
+    0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+    0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+    0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20,
+    0x31, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a,
+    0x20, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x34,
+    0x3a, 0x66, 0x31, 0x3a, 0x30, 0x38, 0x3a, 0x61, 0x64, 0x3a, 0x39, 0x64,
+    0x3a, 0x66, 0x61, 0x3a, 0x36, 0x34, 0x3a, 0x65, 0x32, 0x3a, 0x38, 0x39,
+    0x3a, 0x65, 0x37, 0x3a, 0x31, 0x63, 0x3a, 0x63, 0x66, 0x3a, 0x61, 0x38,
+    0x3a, 0x61, 0x64, 0x3a, 0x37, 0x64, 0x3a, 0x35, 0x65, 0x0a, 0x23, 0x20,
+    0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x39, 0x3a, 0x32, 0x31, 0x3a,
+    0x63, 0x31, 0x3a, 0x31, 0x35, 0x3a, 0x63, 0x31, 0x3a, 0x35, 0x64, 0x3a,
+    0x30, 0x65, 0x3a, 0x63, 0x61, 0x3a, 0x35, 0x63, 0x3a, 0x63, 0x62, 0x3a,
+    0x35, 0x62, 0x3a, 0x63, 0x34, 0x3a, 0x66, 0x30, 0x3a, 0x37, 0x64, 0x3a,
+    0x32, 0x31, 0x3a, 0x64, 0x38, 0x3a, 0x30, 0x35, 0x3a, 0x30, 0x62, 0x3a,
+    0x35, 0x36, 0x3a, 0x36, 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32,
+    0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x37, 0x37, 0x3a, 0x34, 0x30, 0x3a, 0x37, 0x33,
+    0x3a, 0x31, 0x32, 0x3a, 0x63, 0x36, 0x3a, 0x33, 0x61, 0x3a, 0x31, 0x35,
+    0x3a, 0x33, 0x64, 0x3a, 0x35, 0x62, 0x3a, 0x63, 0x30, 0x3a, 0x30, 0x62,
+    0x3a, 0x34, 0x65, 0x3a, 0x35, 0x31, 0x3a, 0x37, 0x35, 0x3a, 0x39, 0x63,
+    0x3a, 0x64, 0x66, 0x3a, 0x64, 0x61, 0x3a, 0x63, 0x32, 0x3a, 0x33, 0x37,
+    0x3a, 0x64, 0x63, 0x3a, 0x32, 0x61, 0x3a, 0x33, 0x33, 0x3a, 0x62, 0x36,
+    0x3a, 0x37, 0x39, 0x3a, 0x34, 0x36, 0x3a, 0x65, 0x39, 0x3a, 0x38, 0x65,
+    0x3a, 0x39, 0x62, 0x3a, 0x66, 0x61, 0x3a, 0x36, 0x38, 0x3a, 0x30, 0x61,
+    0x3a, 0x65, 0x33, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47,
+    0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41,
+    0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44,
+    0x70, 0x44, 0x43, 0x43, 0x41, 0x6f, 0x79, 0x67, 0x41, 0x77, 0x49, 0x42,
+    0x41, 0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71,
+    0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46,
+    0x41, 0x44, 0x42, 0x6a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44,
+    0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x63,
+    0x0a, 0x4d, 0x42, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d,
+    0x54, 0x51, 0x57, 0x31, 0x6c, 0x63, 0x6d, 0x6c, 0x6a, 0x59, 0x53, 0x42,
+    0x50, 0x62, 0x6d, 0x78, 0x70, 0x62, 0x6d, 0x55, 0x67, 0x53, 0x57, 0x35,
+    0x6a, 0x4c, 0x6a, 0x45, 0x32, 0x4d, 0x44, 0x51, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x41, 0x78, 0x4d, 0x74, 0x51, 0x57, 0x31, 0x6c, 0x63, 0x6d, 0x6c,
+    0x6a, 0x59, 0x53, 0x42, 0x50, 0x0a, 0x62, 0x6d, 0x78, 0x70, 0x62, 0x6d,
+    0x55, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x5a, 0x58,
+    0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57,
+    0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d,
+    0x6c, 0x30, 0x65, 0x53, 0x41, 0x78, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54,
+    0x41, 0x79, 0x4d, 0x44, 0x55, 0x79, 0x4f, 0x44, 0x41, 0x32, 0x0a, 0x4d,
+    0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x4d, 0x33, 0x4d,
+    0x54, 0x45, 0x78, 0x4f, 0x54, 0x49, 0x77, 0x4e, 0x44, 0x4d, 0x77, 0x4d,
+    0x46, 0x6f, 0x77, 0x59, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41,
+    0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x48,
+    0x44, 0x41, 0x61, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x45,
+    0x30, 0x46, 0x74, 0x0a, 0x5a, 0x58, 0x4a, 0x70, 0x59, 0x32, 0x45, 0x67,
+    0x54, 0x32, 0x35, 0x73, 0x61, 0x57, 0x35, 0x6c, 0x49, 0x45, 0x6c, 0x75,
+    0x59, 0x79, 0x34, 0x78, 0x4e, 0x6a, 0x41, 0x30, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x4d, 0x54, 0x4c, 0x55, 0x46, 0x74, 0x5a, 0x58, 0x4a, 0x70,
+    0x59, 0x32, 0x45, 0x67, 0x54, 0x32, 0x35, 0x73, 0x61, 0x57, 0x35, 0x6c,
+    0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x0a, 0x51, 0x32, 0x56,
+    0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c,
+    0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a,
+    0x70, 0x64, 0x48, 0x6b, 0x67, 0x4d, 0x54, 0x43, 0x43, 0x41, 0x53, 0x49,
+    0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63,
+    0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45,
+    0x50, 0x0a, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67,
+    0x45, 0x42, 0x41, 0x4b, 0x67, 0x76, 0x36, 0x4b, 0x52, 0x70, 0x42, 0x67,
+    0x4e, 0x48, 0x77, 0x2b, 0x6b, 0x71, 0x6d, 0x50, 0x38, 0x5a, 0x6f, 0x6e,
+    0x43, 0x61, 0x78, 0x6c, 0x43, 0x79, 0x66, 0x71, 0x58, 0x66, 0x61, 0x45,
+    0x30, 0x62, 0x66, 0x41, 0x2b, 0x32, 0x6c, 0x32, 0x68, 0x39, 0x4c, 0x61,
+    0x61, 0x4c, 0x6c, 0x2b, 0x6c, 0x6b, 0x0a, 0x68, 0x73, 0x6d, 0x6a, 0x37,
+    0x36, 0x43, 0x47, 0x76, 0x32, 0x42, 0x6c, 0x6e, 0x45, 0x74, 0x55, 0x69,
+    0x4d, 0x4a, 0x49, 0x78, 0x55, 0x6f, 0x35, 0x76, 0x78, 0x54, 0x6a, 0x57,
+    0x56, 0x58, 0x6c, 0x47, 0x62, 0x52, 0x30, 0x79, 0x4c, 0x51, 0x46, 0x4f,
+    0x56, 0x77, 0x57, 0x70, 0x65, 0x4b, 0x56, 0x42, 0x65, 0x41, 0x53, 0x72,
+    0x6c, 0x6d, 0x4c, 0x6f, 0x6a, 0x4e, 0x6f, 0x57, 0x42, 0x79, 0x6d, 0x0a,
+    0x31, 0x42, 0x57, 0x33, 0x32, 0x4a, 0x2f, 0x58, 0x33, 0x48, 0x47, 0x72,
+    0x66, 0x70, 0x71, 0x2f, 0x6d, 0x34, 0x34, 0x7a, 0x44, 0x79, 0x4c, 0x39,
+    0x48, 0x79, 0x37, 0x6e, 0x42, 0x7a, 0x62, 0x76, 0x59, 0x6a, 0x6e, 0x46,
+    0x33, 0x63, 0x75, 0x36, 0x4a, 0x52, 0x51, 0x6a, 0x33, 0x67, 0x7a, 0x47,
+    0x50, 0x54, 0x7a, 0x4f, 0x67, 0x67, 0x6a, 0x6d, 0x5a, 0x6a, 0x37, 0x61,
+    0x55, 0x54, 0x73, 0x57, 0x0a, 0x4f, 0x71, 0x4d, 0x46, 0x66, 0x36, 0x44,
+    0x63, 0x68, 0x39, 0x57, 0x63, 0x2f, 0x48, 0x4b, 0x70, 0x6f, 0x48, 0x31,
+    0x34, 0x35, 0x4c, 0x63, 0x78, 0x56, 0x52, 0x35, 0x6c, 0x75, 0x39, 0x52,
+    0x68, 0x73, 0x43, 0x46, 0x67, 0x37, 0x52, 0x41, 0x79, 0x63, 0x73, 0x57,
+    0x53, 0x4a, 0x52, 0x37, 0x34, 0x6b, 0x45, 0x6f, 0x59, 0x65, 0x45, 0x66,
+    0x66, 0x66, 0x6a, 0x41, 0x33, 0x50, 0x6c, 0x41, 0x62, 0x0a, 0x32, 0x78,
+    0x7a, 0x54, 0x61, 0x35, 0x71, 0x47, 0x55, 0x77, 0x65, 0x77, 0x37, 0x36,
+    0x77, 0x47, 0x65, 0x50, 0x69, 0x45, 0x6d, 0x66, 0x34, 0x68, 0x6a, 0x55,
+    0x79, 0x41, 0x74, 0x67, 0x79, 0x43, 0x39, 0x6d, 0x5a, 0x77, 0x65, 0x52,
+    0x72, 0x54, 0x54, 0x36, 0x50, 0x50, 0x38, 0x63, 0x39, 0x47, 0x73, 0x45,
+    0x73, 0x50, 0x50, 0x74, 0x32, 0x49, 0x59, 0x72, 0x69, 0x4d, 0x71, 0x51,
+    0x6b, 0x6f, 0x0a, 0x4f, 0x33, 0x72, 0x48, 0x6c, 0x2b, 0x45, 0x65, 0x35,
+    0x66, 0x53, 0x66, 0x77, 0x4d, 0x43, 0x75, 0x4a, 0x4b, 0x44, 0x49, 0x6f,
+    0x64, 0x6b, 0x50, 0x31, 0x6e, 0x73, 0x6d, 0x67, 0x6d, 0x6b, 0x79, 0x50,
+    0x61, 0x63, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, 0x6a, 0x4d,
+    0x47, 0x45, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41,
+    0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x0a, 0x41, 0x77, 0x45, 0x42,
+    0x2f, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45,
+    0x46, 0x67, 0x51, 0x55, 0x41, 0x4b, 0x33, 0x5a, 0x6f, 0x2f, 0x5a, 0x35,
+    0x39, 0x6d, 0x35, 0x30, 0x71, 0x58, 0x38, 0x7a, 0x50, 0x59, 0x45, 0x58,
+    0x31, 0x30, 0x7a, 0x50, 0x4d, 0x39, 0x34, 0x77, 0x48, 0x77, 0x59, 0x44,
+    0x56, 0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55,
+    0x0a, 0x41, 0x4b, 0x33, 0x5a, 0x6f, 0x2f, 0x5a, 0x35, 0x39, 0x6d, 0x35,
+    0x30, 0x71, 0x58, 0x38, 0x7a, 0x50, 0x59, 0x45, 0x58, 0x31, 0x30, 0x7a,
+    0x50, 0x4d, 0x39, 0x34, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30,
+    0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x47,
+    0x47, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62,
+    0x33, 0x44, 0x51, 0x45, 0x42, 0x0a, 0x42, 0x51, 0x55, 0x41, 0x41, 0x34,
+    0x49, 0x42, 0x41, 0x51, 0x42, 0x38, 0x69, 0x74, 0x45, 0x66, 0x47, 0x44,
+    0x65, 0x43, 0x34, 0x4c, 0x69, 0x77, 0x6f, 0x2b, 0x31, 0x57, 0x6c, 0x63,
+    0x68, 0x69, 0x59, 0x5a, 0x77, 0x46, 0x6f, 0x73, 0x33, 0x43, 0x59, 0x69,
+    0x5a, 0x68, 0x7a, 0x52, 0x41, 0x57, 0x31, 0x38, 0x79, 0x30, 0x5a, 0x54,
+    0x54, 0x51, 0x45, 0x59, 0x71, 0x74, 0x71, 0x4b, 0x6b, 0x46, 0x0a, 0x5a,
+    0x75, 0x39, 0x30, 0x38, 0x32, 0x31, 0x66, 0x6e, 0x5a, 0x6d, 0x76, 0x39,
+    0x6f, 0x76, 0x37, 0x36, 0x31, 0x4b, 0x79, 0x42, 0x5a, 0x69, 0x69, 0x62,
+    0x79, 0x72, 0x46, 0x56, 0x4c, 0x30, 0x6c, 0x76, 0x56, 0x2b, 0x75, 0x79,
+    0x49, 0x62, 0x71, 0x52, 0x69, 0x7a, 0x42, 0x73, 0x37, 0x33, 0x42, 0x36,
+    0x55, 0x6c, 0x77, 0x47, 0x42, 0x61, 0x58, 0x43, 0x42, 0x4f, 0x4d, 0x49,
+    0x4f, 0x41, 0x62, 0x0a, 0x4c, 0x6a, 0x70, 0x48, 0x79, 0x78, 0x37, 0x6b,
+    0x41, 0x44, 0x43, 0x56, 0x57, 0x2f, 0x52, 0x46, 0x6f, 0x38, 0x41, 0x61,
+    0x73, 0x41, 0x46, 0x4f, 0x71, 0x37, 0x33, 0x41, 0x49, 0x32, 0x35, 0x6a,
+    0x50, 0x34, 0x42, 0x4b, 0x78, 0x51, 0x66, 0x74, 0x33, 0x4f, 0x4a, 0x76,
+    0x78, 0x38, 0x46, 0x69, 0x38, 0x65, 0x4e, 0x79, 0x31, 0x67, 0x54, 0x49,
+    0x64, 0x47, 0x63, 0x4c, 0x2b, 0x6f, 0x69, 0x72, 0x0a, 0x6f, 0x51, 0x48,
+    0x49, 0x62, 0x2f, 0x41, 0x55, 0x72, 0x39, 0x4b, 0x5a, 0x7a, 0x56, 0x47,
+    0x54, 0x66, 0x75, 0x30, 0x75, 0x4f, 0x4d, 0x65, 0x39, 0x7a, 0x6b, 0x5a,
+    0x51, 0x50, 0x58, 0x4c, 0x6a, 0x65, 0x53, 0x57, 0x64, 0x6d, 0x34, 0x67,
+    0x72, 0x45, 0x43, 0x44, 0x64, 0x70, 0x62, 0x67, 0x79, 0x6e, 0x34, 0x33,
+    0x67, 0x4b, 0x64, 0x38, 0x68, 0x64, 0x49, 0x61, 0x43, 0x32, 0x79, 0x2b,
+    0x43, 0x0a, 0x4d, 0x4d, 0x62, 0x48, 0x4e, 0x59, 0x61, 0x7a, 0x2b, 0x5a,
+    0x5a, 0x66, 0x52, 0x74, 0x73, 0x4d, 0x52, 0x66, 0x33, 0x7a, 0x55, 0x4d,
+    0x4e, 0x76, 0x78, 0x73, 0x4e, 0x49, 0x72, 0x55, 0x61, 0x6d, 0x34, 0x53,
+    0x64, 0x48, 0x43, 0x68, 0x30, 0x4f, 0x6d, 0x37, 0x62, 0x43, 0x64, 0x33,
+    0x39, 0x6a, 0x38, 0x75, 0x42, 0x39, 0x47, 0x72, 0x37, 0x38, 0x34, 0x4e,
+    0x2f, 0x58, 0x78, 0x36, 0x64, 0x73, 0x0a, 0x73, 0x50, 0x6d, 0x75, 0x75,
+    0x6a, 0x7a, 0x39, 0x64, 0x4c, 0x51, 0x52, 0x36, 0x46, 0x67, 0x4e, 0x67,
+    0x4c, 0x7a, 0x54, 0x71, 0x49, 0x41, 0x36, 0x6d, 0x65, 0x31, 0x31, 0x7a,
+    0x45, 0x5a, 0x37, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73,
+    0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x6d, 0x65, 0x72,
+    0x69, 0x63, 0x61, 0x20, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x52,
+    0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+    0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+    0x69, 0x74, 0x79, 0x20, 0x32, 0x20, 0x4f, 0x3d, 0x41, 0x6d, 0x65, 0x72,
+    0x69, 0x63, 0x61, 0x20, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x49,
+    0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63,
+    0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
+    0x61, 0x20, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x52, 0x6f, 0x6f,
+    0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+    0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+    0x79, 0x20, 0x32, 0x20, 0x4f, 0x3d, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
+    0x61, 0x20, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x49, 0x6e, 0x63,
+    0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22,
+    0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x20, 0x4f, 0x6e, 0x6c, 0x69,
+    0x6e, 0x65, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
+    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
+    0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x32, 0x22, 0x0a, 0x23,
+    0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23,
+    0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x36, 0x3a, 0x65, 0x64, 0x3a,
+    0x33, 0x63, 0x3a, 0x63, 0x61, 0x3a, 0x65, 0x32, 0x3a, 0x36, 0x36, 0x3a,
+    0x30, 0x66, 0x3a, 0x61, 0x66, 0x3a, 0x31, 0x30, 0x3a, 0x34, 0x33, 0x3a,
+    0x30, 0x64, 0x3a, 0x37, 0x37, 0x3a, 0x39, 0x62, 0x3a, 0x30, 0x34, 0x3a,
+    0x30, 0x39, 0x3a, 0x62, 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x38, 0x35, 0x3a, 0x62, 0x35, 0x3a, 0x66, 0x66, 0x3a, 0x36,
+    0x37, 0x3a, 0x39, 0x62, 0x3a, 0x30, 0x63, 0x3a, 0x37, 0x39, 0x3a, 0x39,
+    0x36, 0x3a, 0x31, 0x66, 0x3a, 0x63, 0x38, 0x3a, 0x36, 0x65, 0x3a, 0x34,
+    0x34, 0x3a, 0x32, 0x32, 0x3a, 0x30, 0x30, 0x3a, 0x34, 0x36, 0x3a, 0x31,
+    0x33, 0x3a, 0x64, 0x62, 0x3a, 0x31, 0x37, 0x3a, 0x39, 0x32, 0x3a, 0x38,
+    0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x37, 0x64, 0x3a, 0x33, 0x62, 0x3a, 0x34, 0x36, 0x3a, 0x35, 0x61, 0x3a,
+    0x36, 0x30, 0x3a, 0x31, 0x34, 0x3a, 0x65, 0x35, 0x3a, 0x32, 0x36, 0x3a,
+    0x63, 0x30, 0x3a, 0x61, 0x66, 0x3a, 0x66, 0x63, 0x3a, 0x65, 0x65, 0x3a,
+    0x32, 0x31, 0x3a, 0x32, 0x37, 0x3a, 0x64, 0x32, 0x3a, 0x33, 0x31, 0x3a,
+    0x31, 0x37, 0x3a, 0x32, 0x37, 0x3a, 0x61, 0x64, 0x3a, 0x38, 0x31, 0x3a,
+    0x31, 0x63, 0x3a, 0x32, 0x36, 0x3a, 0x38, 0x34, 0x3a, 0x32, 0x64, 0x3a,
+    0x30, 0x30, 0x3a, 0x36, 0x61, 0x3a, 0x66, 0x33, 0x3a, 0x37, 0x33, 0x3a,
+    0x30, 0x36, 0x3a, 0x63, 0x63, 0x3a, 0x38, 0x30, 0x3a, 0x62, 0x64, 0x0a,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x70, 0x44, 0x43, 0x43,
+    0x41, 0x34, 0x79, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42,
+    0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47,
+    0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x6a,
+    0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47,
+    0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x63, 0x0a, 0x4d, 0x42, 0x6f,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x54, 0x51, 0x57, 0x31,
+    0x6c, 0x63, 0x6d, 0x6c, 0x6a, 0x59, 0x53, 0x42, 0x50, 0x62, 0x6d, 0x78,
+    0x70, 0x62, 0x6d, 0x55, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45,
+    0x32, 0x4d, 0x44, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d,
+    0x74, 0x51, 0x57, 0x31, 0x6c, 0x63, 0x6d, 0x6c, 0x6a, 0x59, 0x53, 0x42,
+    0x50, 0x0a, 0x62, 0x6d, 0x78, 0x70, 0x62, 0x6d, 0x55, 0x67, 0x55, 0x6d,
+    0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57,
+    0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45,
+    0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x53,
+    0x41, 0x79, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x79, 0x4d, 0x44,
+    0x55, 0x79, 0x4f, 0x44, 0x41, 0x32, 0x0a, 0x4d, 0x44, 0x41, 0x77, 0x4d,
+    0x46, 0x6f, 0x58, 0x44, 0x54, 0x4d, 0x33, 0x4d, 0x44, 0x6b, 0x79, 0x4f,
+    0x54, 0x45, 0x30, 0x4d, 0x44, 0x67, 0x77, 0x4d, 0x46, 0x6f, 0x77, 0x59,
+    0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42,
+    0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x48, 0x44, 0x41, 0x61, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x45, 0x30, 0x46, 0x74, 0x0a,
+    0x5a, 0x58, 0x4a, 0x70, 0x59, 0x32, 0x45, 0x67, 0x54, 0x32, 0x35, 0x73,
+    0x61, 0x57, 0x35, 0x6c, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78,
+    0x4e, 0x6a, 0x41, 0x30, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54,
+    0x4c, 0x55, 0x46, 0x74, 0x5a, 0x58, 0x4a, 0x70, 0x59, 0x32, 0x45, 0x67,
+    0x54, 0x32, 0x35, 0x73, 0x61, 0x57, 0x35, 0x6c, 0x49, 0x46, 0x4a, 0x76,
+    0x62, 0x33, 0x51, 0x67, 0x0a, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c,
+    0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42,
+    0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b,
+    0x67, 0x4d, 0x6a, 0x43, 0x43, 0x41, 0x69, 0x49, 0x77, 0x44, 0x51, 0x59,
+    0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45,
+    0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x50, 0x0a, 0x41, 0x44,
+    0x43, 0x43, 0x41, 0x67, 0x6f, 0x43, 0x67, 0x67, 0x49, 0x42, 0x41, 0x4d,
+    0x78, 0x42, 0x52, 0x52, 0x33, 0x70, 0x50, 0x55, 0x30, 0x51, 0x39, 0x6f,
+    0x79, 0x78, 0x51, 0x63, 0x6e, 0x67, 0x58, 0x73, 0x73, 0x4e, 0x74, 0x37,
+    0x39, 0x48, 0x63, 0x39, 0x50, 0x77, 0x56, 0x55, 0x33, 0x64, 0x78, 0x67,
+    0x7a, 0x36, 0x73, 0x57, 0x59, 0x46, 0x61, 0x73, 0x31, 0x34, 0x74, 0x4e,
+    0x77, 0x43, 0x0a, 0x32, 0x30, 0x36, 0x42, 0x38, 0x39, 0x65, 0x6e, 0x66,
+    0x48, 0x47, 0x38, 0x64, 0x57, 0x4f, 0x67, 0x58, 0x65, 0x4d, 0x48, 0x44,
+    0x45, 0x6a, 0x73, 0x4a, 0x63, 0x51, 0x44, 0x49, 0x50, 0x54, 0x2f, 0x44,
+    0x6a, 0x73, 0x53, 0x2f, 0x35, 0x75, 0x4e, 0x34, 0x63, 0x62, 0x56, 0x47,
+    0x37, 0x52, 0x74, 0x49, 0x75, 0x4f, 0x78, 0x32, 0x33, 0x38, 0x68, 0x5a,
+    0x4b, 0x2b, 0x47, 0x76, 0x46, 0x63, 0x69, 0x0a, 0x4b, 0x74, 0x5a, 0x48,
+    0x67, 0x56, 0x64, 0x45, 0x67, 0x6c, 0x5a, 0x54, 0x76, 0x59, 0x59, 0x55,
+    0x41, 0x51, 0x76, 0x38, 0x66, 0x33, 0x53, 0x6b, 0x57, 0x71, 0x37, 0x78,
+    0x75, 0x68, 0x47, 0x31, 0x6d, 0x31, 0x68, 0x61, 0x67, 0x4c, 0x51, 0x33,
+    0x65, 0x41, 0x6b, 0x7a, 0x66, 0x44, 0x4a, 0x48, 0x41, 0x31, 0x7a, 0x45,
+    0x70, 0x59, 0x4e, 0x49, 0x39, 0x46, 0x64, 0x57, 0x62, 0x6f, 0x45, 0x32,
+    0x0a, 0x4a, 0x78, 0x68, 0x50, 0x37, 0x4a, 0x73, 0x6f, 0x77, 0x74, 0x53,
+    0x30, 0x31, 0x33, 0x77, 0x4d, 0x50, 0x67, 0x77, 0x72, 0x33, 0x38, 0x6f,
+    0x45, 0x31, 0x38, 0x61, 0x4f, 0x36, 0x6c, 0x68, 0x4f, 0x71, 0x4b, 0x53,
+    0x6c, 0x47, 0x42, 0x78, 0x73, 0x52, 0x5a, 0x69, 0x6a, 0x51, 0x64, 0x45,
+    0x74, 0x30, 0x73, 0x64, 0x74, 0x6a, 0x52, 0x6e, 0x78, 0x72, 0x58, 0x6d,
+    0x33, 0x67, 0x54, 0x2b, 0x39, 0x0a, 0x42, 0x6f, 0x49, 0x6e, 0x4c, 0x52,
+    0x42, 0x59, 0x42, 0x62, 0x56, 0x34, 0x42, 0x62, 0x6b, 0x76, 0x32, 0x77,
+    0x78, 0x72, 0x6b, 0x4a, 0x42, 0x2b, 0x46, 0x46, 0x6b, 0x34, 0x75, 0x35,
+    0x51, 0x6b, 0x45, 0x2b, 0x58, 0x52, 0x6e, 0x52, 0x54, 0x66, 0x30, 0x34,
+    0x4a, 0x4e, 0x52, 0x76, 0x43, 0x41, 0x4f, 0x56, 0x49, 0x79, 0x44, 0x2b,
+    0x4f, 0x45, 0x73, 0x6e, 0x70, 0x44, 0x38, 0x6c, 0x37, 0x65, 0x0a, 0x58,
+    0x7a, 0x38, 0x64, 0x33, 0x65, 0x4f, 0x79, 0x47, 0x36, 0x43, 0x68, 0x4b,
+    0x69, 0x4d, 0x44, 0x62, 0x69, 0x34, 0x42, 0x46, 0x59, 0x64, 0x63, 0x70,
+    0x6e, 0x56, 0x31, 0x78, 0x35, 0x64, 0x68, 0x76, 0x74, 0x36, 0x47, 0x33,
+    0x4e, 0x52, 0x49, 0x32, 0x37, 0x30, 0x71, 0x76, 0x30, 0x70, 0x56, 0x32,
+    0x75, 0x68, 0x39, 0x55, 0x50, 0x75, 0x30, 0x67, 0x42, 0x65, 0x34, 0x6c,
+    0x4c, 0x38, 0x42, 0x0a, 0x50, 0x65, 0x72, 0x61, 0x75, 0x6e, 0x7a, 0x67,
+    0x57, 0x47, 0x63, 0x58, 0x75, 0x56, 0x6a, 0x67, 0x69, 0x49, 0x5a, 0x47,
+    0x5a, 0x32, 0x79, 0x64, 0x45, 0x45, 0x64, 0x59, 0x4d, 0x74, 0x41, 0x31,
+    0x66, 0x48, 0x6b, 0x71, 0x6b, 0x4b, 0x4a, 0x61, 0x45, 0x42, 0x45, 0x6a,
+    0x4e, 0x61, 0x30, 0x76, 0x7a, 0x4f, 0x52, 0x4b, 0x57, 0x36, 0x66, 0x49,
+    0x4a, 0x2f, 0x4b, 0x44, 0x33, 0x6c, 0x36, 0x37, 0x0a, 0x58, 0x6e, 0x66,
+    0x6e, 0x36, 0x4b, 0x56, 0x75, 0x59, 0x38, 0x49, 0x4e, 0x58, 0x57, 0x48,
+    0x51, 0x6a, 0x4e, 0x4a, 0x73, 0x57, 0x69, 0x45, 0x4f, 0x79, 0x69, 0x69,
+    0x6a, 0x7a, 0x69, 0x72, 0x70, 0x6c, 0x63, 0x64, 0x49, 0x7a, 0x35, 0x5a,
+    0x76, 0x48, 0x5a, 0x49, 0x6c, 0x79, 0x4d, 0x62, 0x47, 0x77, 0x63, 0x45,
+    0x4d, 0x42, 0x61, 0x77, 0x6d, 0x78, 0x4e, 0x4a, 0x31, 0x30, 0x75, 0x45,
+    0x71, 0x0a, 0x5a, 0x38, 0x41, 0x39, 0x57, 0x36, 0x57, 0x61, 0x36, 0x38,
+    0x39, 0x37, 0x47, 0x71, 0x69, 0x64, 0x46, 0x45, 0x58, 0x6c, 0x44, 0x36,
+    0x43, 0x61, 0x5a, 0x64, 0x34, 0x76, 0x4b, 0x4c, 0x33, 0x4f, 0x62, 0x35,
+    0x52, 0x6d, 0x67, 0x30, 0x67, 0x70, 0x32, 0x4f, 0x70, 0x6c, 0x6a, 0x4b,
+    0x2b, 0x54, 0x32, 0x57, 0x53, 0x66, 0x56, 0x56, 0x63, 0x6d, 0x76, 0x32,
+    0x2f, 0x4c, 0x4e, 0x7a, 0x47, 0x5a, 0x0a, 0x6f, 0x32, 0x43, 0x37, 0x48,
+    0x4b, 0x32, 0x4a, 0x4e, 0x44, 0x4a, 0x69, 0x75, 0x45, 0x4d, 0x68, 0x42,
+    0x6e, 0x49, 0x4d, 0x6f, 0x56, 0x78, 0x74, 0x52, 0x73, 0x58, 0x36, 0x4b,
+    0x63, 0x38, 0x77, 0x33, 0x6f, 0x6e, 0x63, 0x63, 0x56, 0x76, 0x64, 0x74,
+    0x6a, 0x63, 0x2b, 0x33, 0x31, 0x44, 0x31, 0x75, 0x41, 0x63, 0x6c, 0x4a,
+    0x75, 0x57, 0x38, 0x74, 0x66, 0x34, 0x38, 0x41, 0x72, 0x4f, 0x33, 0x0a,
+    0x2b, 0x4c, 0x35, 0x44, 0x77, 0x59, 0x63, 0x52, 0x6c, 0x4a, 0x34, 0x6a,
+    0x62, 0x42, 0x65, 0x4b, 0x75, 0x49, 0x6f, 0x6e, 0x44, 0x46, 0x52, 0x48,
+    0x38, 0x4b, 0x6d, 0x7a, 0x77, 0x49, 0x43, 0x4d, 0x6f, 0x43, 0x66, 0x72,
+    0x48, 0x52, 0x6e, 0x6a, 0x42, 0x34, 0x35, 0x33, 0x63, 0x4d, 0x6f, 0x72,
+    0x39, 0x48, 0x31, 0x32, 0x34, 0x48, 0x68, 0x6e, 0x41, 0x67, 0x4d, 0x42,
+    0x41, 0x41, 0x47, 0x6a, 0x0a, 0x59, 0x7a, 0x42, 0x68, 0x4d, 0x41, 0x38,
+    0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51,
+    0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x48, 0x51, 0x59,
+    0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x45, 0x31,
+    0x46, 0x77, 0x57, 0x67, 0x34, 0x75, 0x33, 0x4f, 0x70, 0x61, 0x61, 0x45,
+    0x67, 0x35, 0x2b, 0x33, 0x31, 0x49, 0x71, 0x45, 0x6a, 0x0a, 0x46, 0x4e,
+    0x65, 0x65, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x49, 0x77,
+    0x51, 0x59, 0x4d, 0x42, 0x61, 0x41, 0x46, 0x45, 0x31, 0x46, 0x77, 0x57,
+    0x67, 0x34, 0x75, 0x33, 0x4f, 0x70, 0x61, 0x61, 0x45, 0x67, 0x35, 0x2b,
+    0x33, 0x31, 0x49, 0x71, 0x45, 0x6a, 0x46, 0x4e, 0x65, 0x65, 0x4d, 0x41,
+    0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77,
+    0x51, 0x45, 0x0a, 0x41, 0x77, 0x49, 0x42, 0x68, 0x6a, 0x41, 0x4e, 0x42,
+    0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41,
+    0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, 0x5a,
+    0x32, 0x73, 0x47, 0x75, 0x56, 0x39, 0x46, 0x4f, 0x79, 0x70, 0x4c, 0x4d,
+    0x37, 0x50, 0x6d, 0x47, 0x32, 0x74, 0x5a, 0x54, 0x69, 0x4c, 0x4d, 0x75,
+    0x62, 0x65, 0x6b, 0x4a, 0x63, 0x6d, 0x6e, 0x0a, 0x78, 0x50, 0x42, 0x55,
+    0x6c, 0x67, 0x74, 0x6b, 0x38, 0x37, 0x46, 0x59, 0x54, 0x31, 0x35, 0x52,
+    0x2f, 0x4c, 0x4b, 0x58, 0x65, 0x79, 0x64, 0x6c, 0x77, 0x75, 0x58, 0x4b,
+    0x35, 0x77, 0x30, 0x4d, 0x4a, 0x58, 0x74, 0x69, 0x34, 0x2f, 0x71, 0x66,
+    0x74, 0x49, 0x65, 0x33, 0x52, 0x55, 0x61, 0x76, 0x67, 0x36, 0x57, 0x58,
+    0x53, 0x49, 0x79, 0x6c, 0x76, 0x66, 0x45, 0x57, 0x4b, 0x35, 0x74, 0x32,
+    0x0a, 0x4c, 0x48, 0x6f, 0x31, 0x59, 0x47, 0x77, 0x52, 0x67, 0x4a, 0x66,
+    0x4d, 0x71, 0x5a, 0x4a, 0x53, 0x35, 0x69, 0x76, 0x6d, 0x61, 0x65, 0x32,
+    0x70, 0x2b, 0x44, 0x59, 0x74, 0x4c, 0x48, 0x65, 0x2f, 0x59, 0x55, 0x6a,
+    0x52, 0x59, 0x77, 0x75, 0x35, 0x57, 0x31, 0x4c, 0x74, 0x47, 0x4c, 0x42,
+    0x44, 0x51, 0x69, 0x4b, 0x6d, 0x73, 0x58, 0x65, 0x75, 0x33, 0x6d, 0x6e,
+    0x46, 0x7a, 0x63, 0x63, 0x63, 0x0a, 0x6f, 0x62, 0x47, 0x6c, 0x48, 0x42,
+    0x44, 0x37, 0x47, 0x4c, 0x34, 0x61, 0x63, 0x4e, 0x33, 0x42, 0x6b, 0x6b,
+    0x75, 0x2b, 0x4b, 0x56, 0x71, 0x64, 0x50, 0x7a, 0x57, 0x2b, 0x35, 0x58,
+    0x31, 0x52, 0x2b, 0x46, 0x58, 0x67, 0x4a, 0x58, 0x55, 0x6a, 0x68, 0x78,
+    0x35, 0x63, 0x33, 0x4c, 0x71, 0x64, 0x73, 0x4b, 0x79, 0x7a, 0x61, 0x64,
+    0x73, 0x58, 0x67, 0x38, 0x6e, 0x33, 0x33, 0x67, 0x79, 0x38, 0x0a, 0x43,
+    0x4e, 0x79, 0x52, 0x6e, 0x71, 0x6a, 0x51, 0x31, 0x78, 0x55, 0x33, 0x63,
+    0x36, 0x55, 0x31, 0x75, 0x50, 0x78, 0x2b, 0x78, 0x55, 0x52, 0x41, 0x42,
+    0x73, 0x50, 0x72, 0x2b, 0x43, 0x4b, 0x41, 0x58, 0x45, 0x66, 0x4f, 0x41,
+    0x75, 0x4d, 0x52, 0x6e, 0x30, 0x54, 0x2f, 0x2f, 0x5a, 0x6f, 0x79, 0x7a,
+    0x48, 0x31, 0x6b, 0x55, 0x51, 0x37, 0x72, 0x56, 0x79, 0x5a, 0x32, 0x4f,
+    0x75, 0x4d, 0x65, 0x0a, 0x49, 0x6a, 0x7a, 0x43, 0x70, 0x6a, 0x62, 0x64,
+    0x47, 0x65, 0x2b, 0x6e, 0x2f, 0x42, 0x4c, 0x7a, 0x4a, 0x73, 0x42, 0x5a,
+    0x4d, 0x59, 0x56, 0x4d, 0x6e, 0x4e, 0x6a, 0x50, 0x33, 0x36, 0x54, 0x4d,
+    0x7a, 0x43, 0x6d, 0x54, 0x2f, 0x35, 0x52, 0x74, 0x64, 0x6c, 0x77, 0x54,
+    0x43, 0x4a, 0x66, 0x79, 0x37, 0x61, 0x55, 0x4c, 0x54, 0x64, 0x33, 0x6f,
+    0x79, 0x57, 0x67, 0x4f, 0x5a, 0x74, 0x4d, 0x41, 0x0a, 0x44, 0x6a, 0x4d,
+    0x53, 0x57, 0x37, 0x79, 0x56, 0x35, 0x54, 0x4b, 0x51, 0x71, 0x4c, 0x50,
+    0x47, 0x62, 0x49, 0x4f, 0x74, 0x64, 0x2b, 0x36, 0x4c, 0x66, 0x6e, 0x36,
+    0x78, 0x71, 0x61, 0x76, 0x54, 0x34, 0x66, 0x47, 0x32, 0x77, 0x4c, 0x48,
+    0x71, 0x69, 0x4d, 0x44, 0x6e, 0x30, 0x35, 0x44, 0x70, 0x4b, 0x4a, 0x4b,
+    0x55, 0x65, 0x32, 0x68, 0x37, 0x6c, 0x79, 0x6f, 0x4b, 0x5a, 0x79, 0x32,
+    0x46, 0x0a, 0x41, 0x6a, 0x67, 0x51, 0x35, 0x41, 0x4e, 0x68, 0x31, 0x4e,
+    0x6f, 0x6c, 0x4e, 0x73, 0x63, 0x49, 0x57, 0x43, 0x32, 0x68, 0x70, 0x31,
+    0x47, 0x76, 0x4d, 0x41, 0x70, 0x4a, 0x39, 0x61, 0x5a, 0x70, 0x68, 0x77,
+    0x63, 0x74, 0x52, 0x45, 0x5a, 0x32, 0x6a, 0x69, 0x72, 0x6c, 0x6d, 0x6a,
+    0x76, 0x58, 0x47, 0x4b, 0x4c, 0x38, 0x6e, 0x44, 0x67, 0x51, 0x7a, 0x4d,
+    0x59, 0x37, 0x30, 0x72, 0x55, 0x58, 0x0a, 0x4f, 0x6d, 0x2f, 0x39, 0x72,
+    0x69, 0x57, 0x39, 0x39, 0x58, 0x4a, 0x5a, 0x5a, 0x4c, 0x46, 0x30, 0x4b,
+    0x6a, 0x68, 0x66, 0x47, 0x45, 0x7a, 0x66, 0x7a, 0x33, 0x45, 0x45, 0x57,
+    0x6a, 0x62, 0x55, 0x76, 0x79, 0x2b, 0x5a, 0x6e, 0x4f, 0x6a, 0x5a, 0x75,
+    0x72, 0x47, 0x56, 0x35, 0x67, 0x4a, 0x4c, 0x49, 0x61, 0x46, 0x62, 0x31,
+    0x63, 0x46, 0x50, 0x6a, 0x36, 0x35, 0x70, 0x62, 0x56, 0x50, 0x62, 0x0a,
+    0x41, 0x5a, 0x4f, 0x31, 0x58, 0x42, 0x34, 0x59, 0x33, 0x57, 0x52, 0x61,
+    0x79, 0x68, 0x67, 0x6f, 0x50, 0x6d, 0x4d, 0x45, 0x45, 0x66, 0x30, 0x63,
+    0x6a, 0x51, 0x41, 0x50, 0x75, 0x44, 0x66, 0x66, 0x5a, 0x34, 0x71, 0x64,
+    0x5a, 0x71, 0x6b, 0x43, 0x61, 0x70, 0x48, 0x2f, 0x45, 0x38, 0x6f, 0x76,
+    0x58, 0x59, 0x4f, 0x38, 0x68, 0x35, 0x4e, 0x73, 0x33, 0x43, 0x52, 0x52,
+    0x46, 0x67, 0x51, 0x6c, 0x0a, 0x5a, 0x76, 0x71, 0x7a, 0x32, 0x63, 0x4b,
+    0x36, 0x4b, 0x62, 0x36, 0x61, 0x53, 0x44, 0x69, 0x43, 0x6d, 0x66, 0x53,
+    0x2f, 0x4f, 0x30, 0x6f, 0x78, 0x47, 0x66, 0x6d, 0x2f, 0x6a, 0x69, 0x45,
+    0x7a, 0x46, 0x4d, 0x70, 0x50, 0x56, 0x46, 0x2f, 0x37, 0x7a, 0x76, 0x75,
+    0x50, 0x63, 0x58, 0x2f, 0x39, 0x58, 0x68, 0x6d, 0x67, 0x44, 0x30, 0x75,
+    0x52, 0x75, 0x4d, 0x52, 0x55, 0x76, 0x41, 0x61, 0x77, 0x0a, 0x52, 0x59,
+    0x38, 0x6d, 0x6b, 0x61, 0x4b, 0x4f, 0x2f, 0x71, 0x6b, 0x3d, 0x0a, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54,
+    0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20,
+    0x43, 0x4e, 0x3d, 0x41, 0x41, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+    0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69,
+    0x63, 0x65, 0x73, 0x20, 0x4f, 0x3d, 0x43, 0x6f, 0x6d, 0x6f, 0x64, 0x6f,
+    0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a,
+    0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43,
+    0x4e, 0x3d, 0x41, 0x41, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+    0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
+    0x65, 0x73, 0x20, 0x4f, 0x3d, 0x43, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x20,
+    0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23,
+    0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x6f, 0x6d,
+    0x6f, 0x64, 0x6f, 0x20, 0x41, 0x41, 0x41, 0x20, 0x53, 0x65, 0x72, 0x76,
+    0x69, 0x63, 0x65, 0x73, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x22, 0x0a, 0x23,
+    0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23,
+    0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x39, 0x3a, 0x37, 0x39, 0x3a,
+    0x30, 0x34, 0x3a, 0x62, 0x30, 0x3a, 0x65, 0x62, 0x3a, 0x38, 0x37, 0x3a,
+    0x31, 0x39, 0x3a, 0x61, 0x63, 0x3a, 0x34, 0x37, 0x3a, 0x62, 0x30, 0x3a,
+    0x62, 0x63, 0x3a, 0x31, 0x31, 0x3a, 0x35, 0x31, 0x3a, 0x39, 0x62, 0x3a,
+    0x37, 0x34, 0x3a, 0x64, 0x30, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x64, 0x31, 0x3a, 0x65, 0x62, 0x3a, 0x32, 0x33, 0x3a, 0x61,
+    0x34, 0x3a, 0x36, 0x64, 0x3a, 0x31, 0x37, 0x3a, 0x64, 0x36, 0x3a, 0x38,
+    0x66, 0x3a, 0x64, 0x39, 0x3a, 0x32, 0x35, 0x3a, 0x36, 0x34, 0x3a, 0x63,
+    0x32, 0x3a, 0x66, 0x31, 0x3a, 0x66, 0x31, 0x3a, 0x36, 0x30, 0x3a, 0x31,
+    0x37, 0x3a, 0x36, 0x34, 0x3a, 0x64, 0x38, 0x3a, 0x65, 0x33, 0x3a, 0x34,
+    0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x64, 0x37, 0x3a, 0x61, 0x37, 0x3a, 0x61, 0x30, 0x3a, 0x66, 0x62, 0x3a,
+    0x35, 0x64, 0x3a, 0x37, 0x65, 0x3a, 0x32, 0x37, 0x3a, 0x33, 0x31, 0x3a,
+    0x64, 0x37, 0x3a, 0x37, 0x31, 0x3a, 0x65, 0x39, 0x3a, 0x34, 0x38, 0x3a,
+    0x34, 0x65, 0x3a, 0x62, 0x63, 0x3a, 0x64, 0x65, 0x3a, 0x66, 0x37, 0x3a,
+    0x31, 0x64, 0x3a, 0x35, 0x66, 0x3a, 0x30, 0x63, 0x3a, 0x33, 0x65, 0x3a,
+    0x30, 0x61, 0x3a, 0x32, 0x39, 0x3a, 0x34, 0x38, 0x3a, 0x37, 0x38, 0x3a,
+    0x32, 0x62, 0x3a, 0x63, 0x38, 0x3a, 0x33, 0x65, 0x3a, 0x65, 0x30, 0x3a,
+    0x65, 0x61, 0x3a, 0x36, 0x39, 0x3a, 0x39, 0x65, 0x3a, 0x66, 0x34, 0x0a,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x4d, 0x6a, 0x43, 0x43,
+    0x41, 0x78, 0x71, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42,
+    0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47,
+    0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x37,
+    0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47,
+    0x45, 0x77, 0x4a, 0x48, 0x51, 0x6a, 0x45, 0x62, 0x0a, 0x4d, 0x42, 0x6b,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x53, 0x52, 0x33, 0x4a,
+    0x6c, 0x59, 0x58, 0x52, 0x6c, 0x63, 0x69, 0x42, 0x4e, 0x59, 0x57, 0x35,
+    0x6a, 0x61, 0x47, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x79, 0x4d, 0x52, 0x41,
+    0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x64,
+    0x54, 0x59, 0x57, 0x78, 0x6d, 0x62, 0x33, 0x4a, 0x6b, 0x4d, 0x52, 0x6f,
+    0x77, 0x0a, 0x47, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42,
+    0x46, 0x44, 0x62, 0x32, 0x31, 0x76, 0x5a, 0x47, 0x38, 0x67, 0x51, 0x30,
+    0x45, 0x67, 0x54, 0x47, 0x6c, 0x74, 0x61, 0x58, 0x52, 0x6c, 0x5a, 0x44,
+    0x45, 0x68, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77,
+    0x77, 0x59, 0x51, 0x55, 0x46, 0x42, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e,
+    0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x0a, 0x59, 0x58, 0x52, 0x6c, 0x49,
+    0x46, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, 0x7a, 0x4d,
+    0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x30, 0x4d, 0x44, 0x45, 0x77, 0x4d,
+    0x54, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44,
+    0x54, 0x49, 0x34, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x7a, 0x4e,
+    0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x65, 0x7a, 0x45, 0x4c, 0x0a,
+    0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43,
+    0x52, 0x30, 0x49, 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x67, 0x4d, 0x45, 0x6b, 0x64, 0x79, 0x5a, 0x57, 0x46, 0x30,
+    0x5a, 0x58, 0x49, 0x67, 0x54, 0x57, 0x46, 0x75, 0x59, 0x32, 0x68, 0x6c,
+    0x63, 0x33, 0x52, 0x6c, 0x63, 0x6a, 0x45, 0x51, 0x4d, 0x41, 0x34, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x0a, 0x42, 0x77, 0x77, 0x48, 0x55, 0x32, 0x46,
+    0x73, 0x5a, 0x6d, 0x39, 0x79, 0x5a, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x52, 0x51, 0x32, 0x39,
+    0x74, 0x62, 0x32, 0x52, 0x76, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x45, 0x78,
+    0x70, 0x62, 0x57, 0x6c, 0x30, 0x5a, 0x57, 0x51, 0x78, 0x49, 0x54, 0x41,
+    0x66, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x0a, 0x47, 0x45,
+    0x46, 0x42, 0x51, 0x53, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57,
+    0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, 0x53, 0x42, 0x54, 0x5a, 0x58,
+    0x4a, 0x32, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x7a, 0x43, 0x43, 0x41, 0x53,
+    0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76,
+    0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67,
+    0x45, 0x50, 0x0a, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67,
+    0x67, 0x45, 0x42, 0x41, 0x4c, 0x35, 0x41, 0x6e, 0x66, 0x52, 0x75, 0x34,
+    0x65, 0x70, 0x32, 0x68, 0x78, 0x78, 0x4e, 0x52, 0x55, 0x53, 0x4f, 0x76,
+    0x6b, 0x62, 0x49, 0x67, 0x77, 0x61, 0x64, 0x77, 0x53, 0x72, 0x2b, 0x47,
+    0x42, 0x2b, 0x4f, 0x35, 0x41, 0x4c, 0x36, 0x38, 0x36, 0x74, 0x64, 0x55,
+    0x49, 0x6f, 0x57, 0x4d, 0x51, 0x75, 0x61, 0x0a, 0x42, 0x74, 0x44, 0x46,
+    0x63, 0x43, 0x4c, 0x4e, 0x53, 0x53, 0x31, 0x55, 0x59, 0x38, 0x79, 0x32,
+    0x62, 0x6d, 0x68, 0x47, 0x43, 0x31, 0x50, 0x71, 0x79, 0x30, 0x77, 0x6b,
+    0x77, 0x4c, 0x78, 0x79, 0x54, 0x75, 0x72, 0x78, 0x46, 0x61, 0x37, 0x30,
+    0x56, 0x4a, 0x6f, 0x53, 0x43, 0x73, 0x4e, 0x36, 0x73, 0x6a, 0x4e, 0x67,
+    0x34, 0x74, 0x71, 0x4a, 0x56, 0x66, 0x4d, 0x69, 0x57, 0x50, 0x50, 0x65,
+    0x0a, 0x33, 0x4d, 0x2f, 0x76, 0x67, 0x34, 0x61, 0x69, 0x6a, 0x4a, 0x52,
+    0x50, 0x6e, 0x32, 0x6a, 0x79, 0x6d, 0x4a, 0x42, 0x47, 0x68, 0x43, 0x66,
+    0x48, 0x64, 0x72, 0x2f, 0x6a, 0x7a, 0x44, 0x55, 0x73, 0x69, 0x31, 0x34,
+    0x48, 0x5a, 0x47, 0x57, 0x43, 0x77, 0x45, 0x69, 0x77, 0x71, 0x4a, 0x48,
+    0x35, 0x59, 0x5a, 0x39, 0x32, 0x49, 0x46, 0x43, 0x6f, 0x6b, 0x63, 0x64,
+    0x6d, 0x74, 0x65, 0x74, 0x34, 0x0a, 0x59, 0x67, 0x4e, 0x57, 0x38, 0x49,
+    0x6f, 0x61, 0x45, 0x2b, 0x6f, 0x78, 0x6f, 0x78, 0x36, 0x67, 0x6d, 0x66,
+    0x30, 0x34, 0x39, 0x76, 0x59, 0x6e, 0x4d, 0x6c, 0x68, 0x76, 0x42, 0x2f,
+    0x56, 0x72, 0x75, 0x50, 0x73, 0x55, 0x4b, 0x36, 0x2b, 0x33, 0x71, 0x73,
+    0x7a, 0x57, 0x59, 0x31, 0x39, 0x7a, 0x6a, 0x4e, 0x6f, 0x46, 0x6d, 0x61,
+    0x67, 0x34, 0x71, 0x4d, 0x73, 0x58, 0x65, 0x44, 0x5a, 0x52, 0x0a, 0x72,
+    0x4f, 0x6d, 0x65, 0x39, 0x48, 0x67, 0x36, 0x6a, 0x63, 0x38, 0x50, 0x32,
+    0x55, 0x4c, 0x69, 0x6d, 0x41, 0x79, 0x72, 0x4c, 0x35, 0x38, 0x4f, 0x41,
+    0x64, 0x37, 0x76, 0x6e, 0x35, 0x6c, 0x4a, 0x38, 0x53, 0x33, 0x66, 0x72,
+    0x48, 0x52, 0x4e, 0x47, 0x35, 0x69, 0x31, 0x52, 0x38, 0x58, 0x6c, 0x4b,
+    0x64, 0x48, 0x35, 0x6b, 0x42, 0x6a, 0x48, 0x59, 0x70, 0x79, 0x2b, 0x67,
+    0x38, 0x63, 0x6d, 0x0a, 0x65, 0x7a, 0x36, 0x4b, 0x4a, 0x63, 0x66, 0x41,
+    0x33, 0x5a, 0x33, 0x6d, 0x4e, 0x57, 0x67, 0x51, 0x49, 0x4a, 0x32, 0x50,
+    0x32, 0x4e, 0x37, 0x53, 0x77, 0x34, 0x53, 0x63, 0x44, 0x56, 0x37, 0x6f,
+    0x4c, 0x38, 0x6b, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4f, 0x42,
+    0x77, 0x44, 0x43, 0x42, 0x76, 0x54, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56,
+    0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x0a, 0x6f, 0x42, 0x45,
+    0x4b, 0x49, 0x7a, 0x36, 0x57, 0x38, 0x51, 0x66, 0x73, 0x34, 0x71, 0x38,
+    0x70, 0x37, 0x34, 0x4b, 0x6c, 0x66, 0x39, 0x41, 0x77, 0x70, 0x4c, 0x51,
+    0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48,
+    0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x41, 0x38,
+    0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51,
+    0x46, 0x0a, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x65, 0x77,
+    0x59, 0x44, 0x56, 0x52, 0x30, 0x66, 0x42, 0x48, 0x51, 0x77, 0x63, 0x6a,
+    0x41, 0x34, 0x6f, 0x44, 0x61, 0x67, 0x4e, 0x49, 0x59, 0x79, 0x61, 0x48,
+    0x52, 0x30, 0x63, 0x44, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x79, 0x62, 0x43,
+    0x35, 0x6a, 0x62, 0x32, 0x31, 0x76, 0x5a, 0x47, 0x39, 0x6a, 0x59, 0x53,
+    0x35, 0x6a, 0x62, 0x32, 0x30, 0x76, 0x0a, 0x51, 0x55, 0x46, 0x42, 0x51,
+    0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64,
+    0x47, 0x56, 0x54, 0x5a, 0x58, 0x4a, 0x32, 0x61, 0x57, 0x4e, 0x6c, 0x63,
+    0x79, 0x35, 0x6a, 0x63, 0x6d, 0x77, 0x77, 0x4e, 0x71, 0x41, 0x30, 0x6f,
+    0x44, 0x4b, 0x47, 0x4d, 0x47, 0x68, 0x30, 0x64, 0x48, 0x41, 0x36, 0x4c,
+    0x79, 0x39, 0x6a, 0x63, 0x6d, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x0a,
+    0x62, 0x32, 0x52, 0x76, 0x4c, 0x6d, 0x35, 0x6c, 0x64, 0x43, 0x39, 0x42,
+    0x51, 0x55, 0x46, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70,
+    0x59, 0x32, 0x46, 0x30, 0x5a, 0x56, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70,
+    0x59, 0x32, 0x56, 0x7a, 0x4c, 0x6d, 0x4e, 0x79, 0x62, 0x44, 0x41, 0x4e,
+    0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42,
+    0x41, 0x51, 0x55, 0x46, 0x0a, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45,
+    0x41, 0x43, 0x46, 0x62, 0x38, 0x41, 0x76, 0x43, 0x62, 0x36, 0x50, 0x2b,
+    0x6b, 0x2b, 0x74, 0x5a, 0x37, 0x78, 0x6b, 0x53, 0x41, 0x7a, 0x6b, 0x2f,
+    0x45, 0x78, 0x66, 0x59, 0x41, 0x57, 0x4d, 0x79, 0x6d, 0x74, 0x72, 0x77,
+    0x55, 0x53, 0x57, 0x67, 0x45, 0x64, 0x75, 0x6a, 0x6d, 0x37, 0x6c, 0x33,
+    0x73, 0x41, 0x67, 0x39, 0x67, 0x31, 0x6f, 0x31, 0x51, 0x0a, 0x47, 0x45,
+    0x38, 0x6d, 0x54, 0x67, 0x48, 0x6a, 0x35, 0x72, 0x43, 0x6c, 0x37, 0x72,
+    0x2b, 0x38, 0x64, 0x46, 0x52, 0x42, 0x76, 0x2f, 0x33, 0x38, 0x45, 0x72,
+    0x6a, 0x48, 0x54, 0x31, 0x72, 0x30, 0x69, 0x57, 0x41, 0x46, 0x66, 0x32,
+    0x43, 0x33, 0x42, 0x55, 0x72, 0x7a, 0x39, 0x76, 0x48, 0x43, 0x76, 0x38,
+    0x53, 0x35, 0x64, 0x49, 0x61, 0x32, 0x4c, 0x58, 0x31, 0x72, 0x7a, 0x4e,
+    0x4c, 0x7a, 0x0a, 0x52, 0x74, 0x30, 0x76, 0x78, 0x75, 0x42, 0x71, 0x77,
+    0x38, 0x4d, 0x30, 0x41, 0x79, 0x78, 0x39, 0x6c, 0x74, 0x31, 0x61, 0x77,
+    0x67, 0x36, 0x6e, 0x43, 0x70, 0x6e, 0x42, 0x42, 0x59, 0x75, 0x72, 0x44,
+    0x43, 0x2f, 0x7a, 0x58, 0x44, 0x72, 0x50, 0x62, 0x44, 0x64, 0x56, 0x43,
+    0x59, 0x66, 0x65, 0x55, 0x30, 0x42, 0x73, 0x57, 0x4f, 0x2f, 0x38, 0x74,
+    0x71, 0x74, 0x6c, 0x62, 0x67, 0x54, 0x32, 0x0a, 0x47, 0x39, 0x77, 0x38,
+    0x34, 0x46, 0x6f, 0x56, 0x78, 0x70, 0x37, 0x5a, 0x38, 0x56, 0x6c, 0x49,
+    0x4d, 0x43, 0x46, 0x6c, 0x41, 0x32, 0x7a, 0x73, 0x36, 0x53, 0x46, 0x7a,
+    0x37, 0x4a, 0x73, 0x44, 0x6f, 0x65, 0x41, 0x33, 0x72, 0x61, 0x41, 0x56,
+    0x47, 0x49, 0x2f, 0x36, 0x75, 0x67, 0x4c, 0x4f, 0x70, 0x79, 0x79, 0x70,
+    0x45, 0x42, 0x4d, 0x73, 0x31, 0x4f, 0x55, 0x49, 0x4a, 0x71, 0x73, 0x69,
+    0x0a, 0x6c, 0x32, 0x44, 0x34, 0x6b, 0x46, 0x35, 0x30, 0x31, 0x4b, 0x4b,
+    0x61, 0x55, 0x37, 0x33, 0x79, 0x71, 0x57, 0x6a, 0x67, 0x6f, 0x6d, 0x37,
+    0x43, 0x31, 0x32, 0x79, 0x78, 0x6f, 0x77, 0x2b, 0x65, 0x76, 0x2b, 0x74,
+    0x6f, 0x35, 0x31, 0x62, 0x79, 0x72, 0x76, 0x4c, 0x6a, 0x4b, 0x7a, 0x67,
+    0x36, 0x43, 0x59, 0x47, 0x31, 0x61, 0x34, 0x58, 0x58, 0x76, 0x69, 0x33,
+    0x74, 0x50, 0x78, 0x71, 0x33, 0x0a, 0x73, 0x6d, 0x50, 0x69, 0x39, 0x57,
+    0x49, 0x73, 0x67, 0x74, 0x52, 0x71, 0x41, 0x45, 0x46, 0x51, 0x38, 0x54,
+    0x6d, 0x44, 0x6e, 0x35, 0x58, 0x70, 0x4e, 0x70, 0x61, 0x59, 0x62, 0x67,
+    0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20,
+    0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75,
+    0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x65, 0x63, 0x75, 0x72,
+    0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+    0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x4f,
+    0x3d, 0x43, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x20, 0x43, 0x41, 0x20, 0x4c,
+    0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62,
+    0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x65, 0x63,
+    0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+    0x61, 0x74, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
+    0x20, 0x4f, 0x3d, 0x43, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x20, 0x43, 0x41,
+    0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x4c,
+    0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x6f, 0x6d, 0x6f, 0x64,
+    0x6f, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72,
+    0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x22, 0x0a,
+    0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a,
+    0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x33, 0x3a, 0x64, 0x39,
+    0x3a, 0x62, 0x64, 0x3a, 0x61, 0x65, 0x3a, 0x39, 0x66, 0x3a, 0x61, 0x63,
+    0x3a, 0x36, 0x37, 0x3a, 0x32, 0x34, 0x3a, 0x62, 0x33, 0x3a, 0x63, 0x38,
+    0x3a, 0x31, 0x62, 0x3a, 0x35, 0x32, 0x3a, 0x65, 0x31, 0x3a, 0x62, 0x39,
+    0x3a, 0x61, 0x39, 0x3a, 0x62, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41,
+    0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x34, 0x61, 0x3a, 0x36, 0x35, 0x3a, 0x64, 0x35, 0x3a,
+    0x66, 0x34, 0x3a, 0x31, 0x64, 0x3a, 0x65, 0x66, 0x3a, 0x33, 0x39, 0x3a,
+    0x62, 0x38, 0x3a, 0x62, 0x38, 0x3a, 0x39, 0x30, 0x3a, 0x34, 0x61, 0x3a,
+    0x34, 0x61, 0x3a, 0x64, 0x33, 0x3a, 0x36, 0x34, 0x3a, 0x38, 0x31, 0x3a,
+    0x33, 0x33, 0x3a, 0x63, 0x66, 0x3a, 0x63, 0x37, 0x3a, 0x61, 0x31, 0x3a,
+    0x64, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x62, 0x64, 0x3a, 0x38, 0x31, 0x3a, 0x63, 0x65, 0x3a, 0x33, 0x62,
+    0x3a, 0x34, 0x66, 0x3a, 0x36, 0x35, 0x3a, 0x39, 0x31, 0x3a, 0x64, 0x31,
+    0x3a, 0x31, 0x61, 0x3a, 0x36, 0x37, 0x3a, 0x62, 0x35, 0x3a, 0x66, 0x63,
+    0x3a, 0x37, 0x61, 0x3a, 0x34, 0x37, 0x3a, 0x66, 0x64, 0x3a, 0x65, 0x66,
+    0x3a, 0x32, 0x35, 0x3a, 0x35, 0x32, 0x3a, 0x31, 0x62, 0x3a, 0x66, 0x39,
+    0x3a, 0x61, 0x61, 0x3a, 0x34, 0x65, 0x3a, 0x31, 0x38, 0x3a, 0x62, 0x39,
+    0x3a, 0x65, 0x33, 0x3a, 0x64, 0x66, 0x3a, 0x32, 0x65, 0x3a, 0x33, 0x34,
+    0x3a, 0x61, 0x37, 0x3a, 0x38, 0x30, 0x3a, 0x33, 0x62, 0x3a, 0x65, 0x38,
+    0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20,
+    0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x50, 0x7a, 0x43,
+    0x43, 0x41, 0x79, 0x65, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49,
+    0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69,
+    0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42,
+    0x2b, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x47, 0x45, 0x77, 0x4a, 0x48, 0x51, 0x6a, 0x45, 0x62, 0x0a, 0x4d, 0x42,
+    0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x53, 0x52, 0x33,
+    0x4a, 0x6c, 0x59, 0x58, 0x52, 0x6c, 0x63, 0x69, 0x42, 0x4e, 0x59, 0x57,
+    0x35, 0x6a, 0x61, 0x47, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x79, 0x4d, 0x52,
+    0x41, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41,
+    0x64, 0x54, 0x59, 0x57, 0x78, 0x6d, 0x62, 0x33, 0x4a, 0x6b, 0x4d, 0x52,
+    0x6f, 0x77, 0x0a, 0x47, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44,
+    0x42, 0x46, 0x44, 0x62, 0x32, 0x31, 0x76, 0x5a, 0x47, 0x38, 0x67, 0x51,
+    0x30, 0x45, 0x67, 0x54, 0x47, 0x6c, 0x74, 0x61, 0x58, 0x52, 0x6c, 0x5a,
+    0x44, 0x45, 0x6b, 0x4d, 0x43, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41,
+    0x77, 0x77, 0x62, 0x55, 0x32, 0x56, 0x6a, 0x64, 0x58, 0x4a, 0x6c, 0x49,
+    0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x0a, 0x5a, 0x6d, 0x6c, 0x6a,
+    0x59, 0x58, 0x52, 0x6c, 0x49, 0x46, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70,
+    0x59, 0x32, 0x56, 0x7a, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x30,
+    0x4d, 0x44, 0x45, 0x77, 0x4d, 0x54, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77,
+    0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x34, 0x4d, 0x54, 0x49, 0x7a,
+    0x4d, 0x54, 0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77,
+    0x0a, 0x66, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x30, 0x49, 0x78, 0x47, 0x7a, 0x41,
+    0x5a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x4d, 0x45, 0x6b, 0x64,
+    0x79, 0x5a, 0x57, 0x46, 0x30, 0x5a, 0x58, 0x49, 0x67, 0x54, 0x57, 0x46,
+    0x75, 0x59, 0x32, 0x68, 0x6c, 0x63, 0x33, 0x52, 0x6c, 0x63, 0x6a, 0x45,
+    0x51, 0x4d, 0x41, 0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, 0x77,
+    0x77, 0x48, 0x55, 0x32, 0x46, 0x73, 0x5a, 0x6d, 0x39, 0x79, 0x5a, 0x44,
+    0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67,
+    0x77, 0x52, 0x51, 0x32, 0x39, 0x74, 0x62, 0x32, 0x52, 0x76, 0x49, 0x45,
+    0x4e, 0x42, 0x49, 0x45, 0x78, 0x70, 0x62, 0x57, 0x6c, 0x30, 0x5a, 0x57,
+    0x51, 0x78, 0x4a, 0x44, 0x41, 0x69, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42,
+    0x41, 0x4d, 0x4d, 0x47, 0x31, 0x4e, 0x6c, 0x59, 0x33, 0x56, 0x79, 0x5a,
+    0x53, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59,
+    0x32, 0x46, 0x30, 0x5a, 0x53, 0x42, 0x54, 0x5a, 0x58, 0x4a, 0x32, 0x61,
+    0x57, 0x4e, 0x6c, 0x63, 0x7a, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44,
+    0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41,
+    0x51, 0x45, 0x42, 0x0a, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50,
+    0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42,
+    0x41, 0x4d, 0x42, 0x78, 0x4d, 0x34, 0x4b, 0x4b, 0x30, 0x48, 0x44, 0x72,
+    0x63, 0x34, 0x65, 0x43, 0x51, 0x4e, 0x55, 0x64, 0x35, 0x4d, 0x76, 0x4a,
+    0x44, 0x6b, 0x4b, 0x51, 0x2b, 0x64, 0x34, 0x30, 0x75, 0x61, 0x47, 0x36,
+    0x45, 0x66, 0x51, 0x6c, 0x68, 0x66, 0x50, 0x4d, 0x0a, 0x63, 0x6d, 0x33,
+    0x79, 0x65, 0x35, 0x64, 0x72, 0x73, 0x77, 0x66, 0x78, 0x64, 0x79, 0x53,
+    0x52, 0x58, 0x79, 0x57, 0x50, 0x39, 0x6e, 0x51, 0x39, 0x35, 0x49, 0x44,
+    0x43, 0x2b, 0x44, 0x77, 0x4e, 0x38, 0x37, 0x39, 0x41, 0x36, 0x76, 0x66,
+    0x49, 0x55, 0x74, 0x46, 0x79, 0x62, 0x2b, 0x2f, 0x49, 0x71, 0x30, 0x47,
+    0x34, 0x62, 0x69, 0x34, 0x58, 0x4b, 0x70, 0x56, 0x70, 0x44, 0x4d, 0x33,
+    0x53, 0x0a, 0x48, 0x70, 0x52, 0x37, 0x4c, 0x5a, 0x51, 0x64, 0x71, 0x6e,
+    0x58, 0x58, 0x73, 0x35, 0x6a, 0x4c, 0x72, 0x4c, 0x78, 0x6b, 0x55, 0x30,
+    0x43, 0x38, 0x6a, 0x36, 0x79, 0x73, 0x4e, 0x73, 0x74, 0x63, 0x72, 0x62,
+    0x76, 0x64, 0x34, 0x4a, 0x51, 0x58, 0x37, 0x4e, 0x46, 0x63, 0x30, 0x4c,
+    0x2f, 0x76, 0x70, 0x5a, 0x58, 0x4a, 0x6b, 0x4d, 0x57, 0x77, 0x72, 0x50,
+    0x73, 0x62, 0x51, 0x39, 0x39, 0x36, 0x0a, 0x43, 0x46, 0x32, 0x33, 0x75,
+    0x50, 0x4a, 0x41, 0x47, 0x79, 0x73, 0x6e, 0x6e, 0x6c, 0x44, 0x4f, 0x58,
+    0x6d, 0x57, 0x43, 0x69, 0x49, 0x78, 0x65, 0x30, 0x30, 0x34, 0x4d, 0x65,
+    0x75, 0x6f, 0x49, 0x6b, 0x62, 0x59, 0x32, 0x71, 0x69, 0x74, 0x43, 0x2b,
+    0x2b, 0x72, 0x43, 0x6f, 0x7a, 0x6e, 0x6c, 0x32, 0x79, 0x59, 0x34, 0x72,
+    0x59, 0x73, 0x4b, 0x37, 0x68, 0x6c, 0x6a, 0x78, 0x78, 0x77, 0x6b, 0x0a,
+    0x33, 0x77, 0x4e, 0x34, 0x32, 0x75, 0x62, 0x71, 0x77, 0x55, 0x63, 0x61,
+    0x43, 0x77, 0x74, 0x47, 0x43, 0x64, 0x30, 0x43, 0x2f, 0x4e, 0x37, 0x4c,
+    0x68, 0x31, 0x2f, 0x58, 0x4d, 0x47, 0x4e, 0x6f, 0x6f, 0x61, 0x37, 0x63,
+    0x4d, 0x71, 0x47, 0x36, 0x76, 0x76, 0x35, 0x45, 0x71, 0x32, 0x69, 0x32,
+    0x70, 0x52, 0x63, 0x56, 0x2f, 0x62, 0x33, 0x56, 0x70, 0x36, 0x65, 0x61,
+    0x35, 0x45, 0x51, 0x7a, 0x0a, 0x36, 0x59, 0x69, 0x4f, 0x2f, 0x4f, 0x31,
+    0x52, 0x36, 0x35, 0x4e, 0x78, 0x54, 0x71, 0x30, 0x42, 0x35, 0x30, 0x53,
+    0x4f, 0x71, 0x79, 0x33, 0x4c, 0x71, 0x50, 0x34, 0x42, 0x53, 0x55, 0x6a,
+    0x77, 0x77, 0x4e, 0x33, 0x48, 0x61, 0x4e, 0x69, 0x53, 0x2f, 0x6a, 0x30,
+    0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4f, 0x42, 0x78, 0x7a, 0x43,
+    0x42, 0x78, 0x44, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x51,
+    0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x50, 0x4e, 0x69, 0x54, 0x69, 0x4d,
+    0x4c, 0x41, 0x67, 0x67, 0x6e, 0x4d, 0x41, 0x5a, 0x6b, 0x47, 0x6b, 0x79,
+    0x44, 0x70, 0x6e, 0x6e, 0x41, 0x4a, 0x59, 0x30, 0x38, 0x77, 0x44, 0x67,
+    0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41,
+    0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31,
+    0x55, 0x64, 0x0a, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d,
+    0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x67, 0x59, 0x45, 0x47, 0x41,
+    0x31, 0x55, 0x64, 0x48, 0x77, 0x52, 0x36, 0x4d, 0x48, 0x67, 0x77, 0x4f,
+    0x36, 0x41, 0x35, 0x6f, 0x44, 0x65, 0x47, 0x4e, 0x57, 0x68, 0x30, 0x64,
+    0x48, 0x41, 0x36, 0x4c, 0x79, 0x39, 0x6a, 0x63, 0x6d, 0x77, 0x75, 0x59,
+    0x32, 0x39, 0x74, 0x62, 0x32, 0x52, 0x76, 0x0a, 0x59, 0x32, 0x45, 0x75,
+    0x59, 0x32, 0x39, 0x74, 0x4c, 0x31, 0x4e, 0x6c, 0x59, 0x33, 0x56, 0x79,
+    0x5a, 0x55, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a,
+    0x59, 0x58, 0x52, 0x6c, 0x55, 0x32, 0x56, 0x79, 0x64, 0x6d, 0x6c, 0x6a,
+    0x5a, 0x58, 0x4d, 0x75, 0x59, 0x33, 0x4a, 0x73, 0x4d, 0x44, 0x6d, 0x67,
+    0x4e, 0x36, 0x41, 0x31, 0x68, 0x6a, 0x4e, 0x6f, 0x64, 0x48, 0x52, 0x77,
+    0x0a, 0x4f, 0x69, 0x38, 0x76, 0x59, 0x33, 0x4a, 0x73, 0x4c, 0x6d, 0x4e,
+    0x76, 0x62, 0x57, 0x39, 0x6b, 0x62, 0x79, 0x35, 0x75, 0x5a, 0x58, 0x51,
+    0x76, 0x55, 0x32, 0x56, 0x6a, 0x64, 0x58, 0x4a, 0x6c, 0x51, 0x32, 0x56,
+    0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x56,
+    0x54, 0x5a, 0x58, 0x4a, 0x32, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x79, 0x35,
+    0x6a, 0x63, 0x6d, 0x77, 0x77, 0x0a, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f,
+    0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51,
+    0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x49, 0x63, 0x42, 0x62, 0x53,
+    0x4d, 0x64, 0x66, 0x6c, 0x73, 0x58, 0x66, 0x63, 0x46, 0x68, 0x4d, 0x73,
+    0x2b, 0x50, 0x35, 0x2f, 0x4f, 0x4b, 0x6c, 0x46, 0x6c, 0x6d, 0x34, 0x4a,
+    0x34, 0x6f, 0x71, 0x46, 0x37, 0x54, 0x74, 0x2f, 0x51, 0x30, 0x0a, 0x35,
+    0x71, 0x6f, 0x35, 0x73, 0x70, 0x63, 0x57, 0x78, 0x59, 0x4a, 0x76, 0x4d,
+    0x71, 0x54, 0x70, 0x6a, 0x4f, 0x65, 0x76, 0x2f, 0x65, 0x2f, 0x43, 0x36,
+    0x4c, 0x6c, 0x4c, 0x71, 0x71, 0x50, 0x30, 0x35, 0x74, 0x71, 0x4e, 0x5a,
+    0x53, 0x48, 0x37, 0x75, 0x6f, 0x44, 0x72, 0x4a, 0x69, 0x69, 0x46, 0x47,
+    0x76, 0x34, 0x35, 0x6a, 0x4e, 0x35, 0x62, 0x42, 0x41, 0x53, 0x30, 0x56,
+    0x50, 0x6d, 0x6a, 0x0a, 0x5a, 0x35, 0x35, 0x42, 0x2b, 0x67, 0x6c, 0x53,
+    0x7a, 0x41, 0x56, 0x49, 0x71, 0x4d, 0x6b, 0x2f, 0x49, 0x51, 0x51, 0x65,
+    0x7a, 0x6b, 0x68, 0x72, 0x2f, 0x49, 0x58, 0x6f, 0x77, 0x6e, 0x75, 0x76,
+    0x66, 0x37, 0x66, 0x4d, 0x2b, 0x46, 0x38, 0x36, 0x2f, 0x54, 0x58, 0x47,
+    0x44, 0x65, 0x2b, 0x58, 0x33, 0x45, 0x79, 0x72, 0x45, 0x65, 0x46, 0x72,
+    0x79, 0x7a, 0x48, 0x52, 0x62, 0x50, 0x74, 0x49, 0x0a, 0x67, 0x4b, 0x76,
+    0x63, 0x6e, 0x44, 0x65, 0x34, 0x49, 0x52, 0x52, 0x4c, 0x44, 0x58, 0x45,
+    0x39, 0x37, 0x49, 0x4d, 0x7a, 0x62, 0x74, 0x46, 0x75, 0x4d, 0x68, 0x62,
+    0x73, 0x6d, 0x4d, 0x63, 0x57, 0x69, 0x31, 0x6d, 0x6d, 0x4e, 0x4b, 0x73,
+    0x46, 0x56, 0x79, 0x32, 0x54, 0x39, 0x36, 0x6f, 0x54, 0x79, 0x39, 0x49,
+    0x54, 0x34, 0x72, 0x63, 0x75, 0x4f, 0x38, 0x31, 0x72, 0x55, 0x42, 0x63,
+    0x4a, 0x0a, 0x61, 0x44, 0x36, 0x31, 0x4a, 0x6c, 0x66, 0x75, 0x74, 0x75,
+    0x43, 0x32, 0x33, 0x62, 0x6b, 0x70, 0x67, 0x48, 0x6c, 0x39, 0x6a, 0x36,
+    0x50, 0x77, 0x70, 0x43, 0x69, 0x6b, 0x46, 0x63, 0x53, 0x46, 0x39, 0x43,
+    0x66, 0x55, 0x61, 0x37, 0x2f, 0x6c, 0x58, 0x4f, 0x52, 0x6c, 0x41, 0x6e,
+    0x5a, 0x55, 0x74, 0x4f, 0x4d, 0x33, 0x5a, 0x69, 0x54, 0x54, 0x47, 0x57,
+    0x48, 0x49, 0x55, 0x68, 0x44, 0x6c, 0x0a, 0x69, 0x7a, 0x65, 0x61, 0x75,
+    0x61, 0x6e, 0x35, 0x48, 0x62, 0x2f, 0x71, 0x6d, 0x5a, 0x4a, 0x68, 0x6c,
+    0x76, 0x38, 0x42, 0x7a, 0x61, 0x46, 0x66, 0x44, 0x62, 0x78, 0x78, 0x76,
+    0x41, 0x36, 0x73, 0x43, 0x78, 0x31, 0x48, 0x52, 0x52, 0x33, 0x42, 0x37,
+    0x48, 0x7a, 0x73, 0x2f, 0x53, 0x6b, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23,
+    0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d,
+    0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x43, 0x65, 0x72, 0x74,
+    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76,
+    0x69, 0x63, 0x65, 0x73, 0x20, 0x4f, 0x3d, 0x43, 0x6f, 0x6d, 0x6f, 0x64,
+    0x6f, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64,
+    0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20,
+    0x43, 0x4e, 0x3d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x43,
+    0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53,
+    0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x4f, 0x3d, 0x43, 0x6f,
+    0x6d, 0x6f, 0x64, 0x6f, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69,
+    0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a,
+    0x20, 0x22, 0x43, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x20, 0x54, 0x72, 0x75,
+    0x73, 0x74, 0x65, 0x64, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
+    0x73, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65,
+    0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44,
+    0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x39, 0x31, 0x3a, 0x31, 0x62, 0x3a, 0x33, 0x66, 0x3a,
+    0x36, 0x65, 0x3a, 0x63, 0x64, 0x3a, 0x39, 0x65, 0x3a, 0x61, 0x62, 0x3a,
+    0x65, 0x65, 0x3a, 0x30, 0x37, 0x3a, 0x66, 0x65, 0x3a, 0x31, 0x66, 0x3a,
+    0x37, 0x31, 0x3a, 0x64, 0x32, 0x3a, 0x62, 0x33, 0x3a, 0x36, 0x31, 0x3a,
+    0x32, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69,
+    0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65,
+    0x31, 0x3a, 0x39, 0x66, 0x3a, 0x65, 0x33, 0x3a, 0x30, 0x65, 0x3a, 0x38,
+    0x62, 0x3a, 0x38, 0x34, 0x3a, 0x36, 0x30, 0x3a, 0x39, 0x65, 0x3a, 0x38,
+    0x30, 0x3a, 0x39, 0x62, 0x3a, 0x31, 0x37, 0x3a, 0x30, 0x64, 0x3a, 0x37,
+    0x32, 0x3a, 0x61, 0x38, 0x3a, 0x63, 0x35, 0x3a, 0x62, 0x61, 0x3a, 0x36,
+    0x65, 0x3a, 0x31, 0x34, 0x3a, 0x30, 0x39, 0x3a, 0x62, 0x64, 0x0a, 0x23,
+    0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x66, 0x3a,
+    0x30, 0x36, 0x3a, 0x65, 0x35, 0x3a, 0x35, 0x36, 0x3a, 0x38, 0x31, 0x3a,
+    0x64, 0x34, 0x3a, 0x39, 0x36, 0x3a, 0x66, 0x35, 0x3a, 0x62, 0x65, 0x3a,
+    0x31, 0x36, 0x3a, 0x39, 0x65, 0x3a, 0x62, 0x35, 0x3a, 0x33, 0x38, 0x3a,
+    0x39, 0x66, 0x3a, 0x39, 0x66, 0x3a, 0x32, 0x62, 0x3a, 0x38, 0x66, 0x3a,
+    0x66, 0x36, 0x3a, 0x31, 0x65, 0x3a, 0x31, 0x37, 0x3a, 0x30, 0x38, 0x3a,
+    0x64, 0x66, 0x3a, 0x36, 0x38, 0x3a, 0x38, 0x31, 0x3a, 0x37, 0x32, 0x3a,
+    0x34, 0x38, 0x3a, 0x34, 0x39, 0x3a, 0x63, 0x64, 0x3a, 0x35, 0x64, 0x3a,
+    0x32, 0x37, 0x3a, 0x63, 0x62, 0x3a, 0x36, 0x39, 0x0a, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54,
+    0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x0a, 0x4d, 0x49, 0x49, 0x45, 0x51, 0x7a, 0x43, 0x43, 0x41, 0x79, 0x75,
+    0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x54, 0x41,
+    0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30,
+    0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x2f, 0x4d, 0x51, 0x73,
+    0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a,
+    0x48, 0x51, 0x6a, 0x45, 0x62, 0x0a, 0x4d, 0x42, 0x6b, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x43, 0x41, 0x77, 0x53, 0x52, 0x33, 0x4a, 0x6c, 0x59, 0x58,
+    0x52, 0x6c, 0x63, 0x69, 0x42, 0x4e, 0x59, 0x57, 0x35, 0x6a, 0x61, 0x47,
+    0x56, 0x7a, 0x64, 0x47, 0x56, 0x79, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67,
+    0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x64, 0x54, 0x59, 0x57,
+    0x78, 0x6d, 0x62, 0x33, 0x4a, 0x6b, 0x4d, 0x52, 0x6f, 0x77, 0x0a, 0x47,
+    0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x46, 0x44, 0x62,
+    0x32, 0x31, 0x76, 0x5a, 0x47, 0x38, 0x67, 0x51, 0x30, 0x45, 0x67, 0x54,
+    0x47, 0x6c, 0x74, 0x61, 0x58, 0x52, 0x6c, 0x5a, 0x44, 0x45, 0x6c, 0x4d,
+    0x43, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x63, 0x56,
+    0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x6c, 0x5a, 0x43, 0x42, 0x44, 0x5a,
+    0x58, 0x4a, 0x30, 0x0a, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30,
+    0x5a, 0x53, 0x42, 0x54, 0x5a, 0x58, 0x4a, 0x32, 0x61, 0x57, 0x4e, 0x6c,
+    0x63, 0x7a, 0x41, 0x65, 0x46, 0x77, 0x30, 0x77, 0x4e, 0x44, 0x41, 0x78,
+    0x4d, 0x44, 0x45, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x42, 0x61,
+    0x46, 0x77, 0x30, 0x79, 0x4f, 0x44, 0x45, 0x79, 0x4d, 0x7a, 0x45, 0x79,
+    0x4d, 0x7a, 0x55, 0x35, 0x4e, 0x54, 0x6c, 0x61, 0x0a, 0x4d, 0x48, 0x38,
+    0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59,
+    0x54, 0x41, 0x6b, 0x64, 0x43, 0x4d, 0x52, 0x73, 0x77, 0x47, 0x51, 0x59,
+    0x44, 0x56, 0x51, 0x51, 0x49, 0x44, 0x42, 0x4a, 0x48, 0x63, 0x6d, 0x56,
+    0x68, 0x64, 0x47, 0x56, 0x79, 0x49, 0x45, 0x31, 0x68, 0x62, 0x6d, 0x4e,
+    0x6f, 0x5a, 0x58, 0x4e, 0x30, 0x5a, 0x58, 0x49, 0x78, 0x45, 0x44, 0x41,
+    0x4f, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x4d, 0x42, 0x31,
+    0x4e, 0x68, 0x62, 0x47, 0x5a, 0x76, 0x63, 0x6d, 0x51, 0x78, 0x47, 0x6a,
+    0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55,
+    0x4e, 0x76, 0x62, 0x57, 0x39, 0x6b, 0x62, 0x79, 0x42, 0x44, 0x51, 0x53,
+    0x42, 0x4d, 0x61, 0x57, 0x31, 0x70, 0x64, 0x47, 0x56, 0x6b, 0x4d, 0x53,
+    0x55, 0x77, 0x49, 0x77, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, 0x44, 0x44,
+    0x42, 0x78, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x6b, 0x49,
+    0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59,
+    0x58, 0x52, 0x6c, 0x49, 0x46, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70, 0x59,
+    0x32, 0x56, 0x7a, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42,
+    0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x0a,
+    0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41,
+    0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41,
+    0x33, 0x33, 0x46, 0x76, 0x4e, 0x6c, 0x68, 0x54, 0x57, 0x76, 0x49, 0x32,
+    0x56, 0x46, 0x65, 0x41, 0x78, 0x48, 0x51, 0x49, 0x49, 0x4f, 0x30, 0x59,
+    0x66, 0x79, 0x6f, 0x64, 0x35, 0x6a, 0x57, 0x61, 0x48, 0x69, 0x57, 0x73,
+    0x6e, 0x4f, 0x57, 0x57, 0x0a, 0x66, 0x6e, 0x4a, 0x53, 0x6f, 0x42, 0x56,
+    0x43, 0x32, 0x31, 0x6e, 0x64, 0x5a, 0x48, 0x6f, 0x61, 0x30, 0x4c, 0x68,
+    0x37, 0x33, 0x54, 0x6b, 0x56, 0x76, 0x46, 0x56, 0x49, 0x78, 0x4f, 0x30,
+    0x36, 0x41, 0x4f, 0x6f, 0x78, 0x45, 0x62, 0x72, 0x79, 0x63, 0x58, 0x51,
+    0x61, 0x5a, 0x37, 0x6a, 0x50, 0x4d, 0x38, 0x79, 0x6f, 0x4d, 0x61, 0x2b,
+    0x6a, 0x34, 0x39, 0x64, 0x2f, 0x76, 0x7a, 0x4d, 0x74, 0x0a, 0x54, 0x47,
+    0x6f, 0x38, 0x37, 0x49, 0x76, 0x44, 0x6b, 0x74, 0x4a, 0x54, 0x64, 0x79,
+    0x52, 0x30, 0x6e, 0x41, 0x64, 0x75, 0x63, 0x50, 0x79, 0x39, 0x43, 0x31,
+    0x74, 0x32, 0x75, 0x6c, 0x2f, 0x79, 0x2f, 0x39, 0x63, 0x33, 0x53, 0x30,
+    0x70, 0x67, 0x65, 0x50, 0x66, 0x77, 0x2b, 0x73, 0x70, 0x77, 0x74, 0x4f,
+    0x70, 0x5a, 0x71, 0x71, 0x50, 0x4f, 0x53, 0x43, 0x2b, 0x70, 0x77, 0x37,
+    0x49, 0x4c, 0x0a, 0x66, 0x68, 0x64, 0x79, 0x46, 0x67, 0x79, 0x6d, 0x42,
+    0x77, 0x77, 0x62, 0x4f, 0x4d, 0x2f, 0x4a, 0x59, 0x72, 0x63, 0x2f, 0x6f,
+    0x4a, 0x4f, 0x6c, 0x68, 0x30, 0x48, 0x79, 0x74, 0x33, 0x42, 0x41, 0x64,
+    0x39, 0x69, 0x2b, 0x46, 0x48, 0x7a, 0x6a, 0x71, 0x4d, 0x42, 0x36, 0x6a,
+    0x75, 0x6c, 0x6a, 0x61, 0x74, 0x45, 0x50, 0x6d, 0x73, 0x62, 0x53, 0x39,
+    0x49, 0x73, 0x36, 0x46, 0x41, 0x52, 0x57, 0x0a, 0x31, 0x4f, 0x32, 0x34,
+    0x7a, 0x47, 0x37, 0x31, 0x2b, 0x2b, 0x49, 0x73, 0x57, 0x4c, 0x31, 0x2f,
+    0x54, 0x32, 0x73, 0x72, 0x39, 0x32, 0x41, 0x6b, 0x57, 0x43, 0x54, 0x4f,
+    0x4a, 0x75, 0x38, 0x30, 0x6b, 0x54, 0x72, 0x56, 0x34, 0x34, 0x48, 0x51,
+    0x73, 0x76, 0x41, 0x45, 0x41, 0x74, 0x64, 0x62, 0x74, 0x7a, 0x36, 0x53,
+    0x72, 0x47, 0x73, 0x53, 0x69, 0x76, 0x6e, 0x6b, 0x42, 0x62, 0x41, 0x37,
+    0x0a, 0x6b, 0x55, 0x6c, 0x63, 0x73, 0x75, 0x74, 0x54, 0x36, 0x76, 0x69,
+    0x66, 0x52, 0x34, 0x62, 0x75, 0x76, 0x35, 0x58, 0x41, 0x77, 0x41, 0x61,
+    0x66, 0x30, 0x6c, 0x74, 0x65, 0x45, 0x52, 0x76, 0x30, 0x78, 0x77, 0x51,
+    0x31, 0x4b, 0x64, 0x4a, 0x56, 0x58, 0x4f, 0x54, 0x74, 0x36, 0x77, 0x49,
+    0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x34, 0x48, 0x4a, 0x4d, 0x49, 0x48,
+    0x47, 0x4d, 0x42, 0x30, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67,
+    0x51, 0x57, 0x42, 0x42, 0x54, 0x46, 0x65, 0x31, 0x69, 0x39, 0x37, 0x64,
+    0x6f, 0x6c, 0x61, 0x64, 0x4c, 0x33, 0x57, 0x52, 0x61, 0x6f, 0x73, 0x7a,
+    0x4c, 0x41, 0x65, 0x79, 0x64, 0x62, 0x39, 0x44, 0x41, 0x4f, 0x42, 0x67,
+    0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41,
+    0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x0a, 0x56,
+    0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41,
+    0x77, 0x45, 0x42, 0x2f, 0x7a, 0x43, 0x42, 0x67, 0x77, 0x59, 0x44, 0x56,
+    0x52, 0x30, 0x66, 0x42, 0x48, 0x77, 0x77, 0x65, 0x6a, 0x41, 0x38, 0x6f,
+    0x44, 0x71, 0x67, 0x4f, 0x49, 0x59, 0x32, 0x61, 0x48, 0x52, 0x30, 0x63,
+    0x44, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x79, 0x62, 0x43, 0x35, 0x6a, 0x62,
+    0x32, 0x31, 0x76, 0x0a, 0x5a, 0x47, 0x39, 0x6a, 0x59, 0x53, 0x35, 0x6a,
+    0x62, 0x32, 0x30, 0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x6c,
+    0x5a, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a,
+    0x59, 0x58, 0x52, 0x6c, 0x55, 0x32, 0x56, 0x79, 0x64, 0x6d, 0x6c, 0x6a,
+    0x5a, 0x58, 0x4d, 0x75, 0x59, 0x33, 0x4a, 0x73, 0x4d, 0x44, 0x71, 0x67,
+    0x4f, 0x4b, 0x41, 0x32, 0x68, 0x6a, 0x52, 0x6f, 0x0a, 0x64, 0x48, 0x52,
+    0x77, 0x4f, 0x69, 0x38, 0x76, 0x59, 0x33, 0x4a, 0x73, 0x4c, 0x6d, 0x4e,
+    0x76, 0x62, 0x57, 0x39, 0x6b, 0x62, 0x79, 0x35, 0x75, 0x5a, 0x58, 0x51,
+    0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x6c, 0x5a, 0x45, 0x4e,
+    0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52,
+    0x6c, 0x55, 0x32, 0x56, 0x79, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d,
+    0x75, 0x0a, 0x59, 0x33, 0x4a, 0x73, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53,
+    0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51,
+    0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x44, 0x49, 0x6b, 0x34,
+    0x45, 0x37, 0x69, 0x62, 0x53, 0x76, 0x75, 0x49, 0x51, 0x53, 0x54, 0x49,
+    0x33, 0x53, 0x38, 0x4e, 0x74, 0x77, 0x75, 0x6c, 0x65, 0x47, 0x46, 0x54,
+    0x51, 0x51, 0x75, 0x53, 0x39, 0x2f, 0x0a, 0x48, 0x72, 0x43, 0x6f, 0x69,
+    0x57, 0x43, 0x68, 0x69, 0x73, 0x4a, 0x33, 0x44, 0x46, 0x42, 0x4b, 0x6d,
+    0x77, 0x43, 0x4c, 0x32, 0x49, 0x76, 0x30, 0x51, 0x65, 0x4c, 0x51, 0x67,
+    0x34, 0x70, 0x4b, 0x48, 0x42, 0x51, 0x47, 0x73, 0x4b, 0x4e, 0x6f, 0x42,
+    0x58, 0x41, 0x78, 0x4d, 0x4b, 0x64, 0x54, 0x6d, 0x77, 0x37, 0x70, 0x53,
+    0x71, 0x42, 0x59, 0x61, 0x57, 0x63, 0x4f, 0x72, 0x70, 0x33, 0x32, 0x0a,
+    0x70, 0x53, 0x78, 0x42, 0x76, 0x7a, 0x77, 0x47, 0x61, 0x2b, 0x52, 0x5a,
+    0x7a, 0x47, 0x30, 0x51, 0x38, 0x5a, 0x5a, 0x76, 0x48, 0x39, 0x2f, 0x30,
+    0x42, 0x41, 0x4b, 0x6b, 0x6e, 0x30, 0x55, 0x2b, 0x79, 0x4e, 0x6a, 0x36,
+    0x4e, 0x6b, 0x5a, 0x45, 0x55, 0x44, 0x2b, 0x43, 0x6c, 0x35, 0x45, 0x66,
+    0x4b, 0x4e, 0x73, 0x59, 0x45, 0x59, 0x77, 0x71, 0x35, 0x47, 0x57, 0x44,
+    0x56, 0x78, 0x49, 0x53, 0x0a, 0x6a, 0x42, 0x63, 0x2f, 0x6c, 0x44, 0x62,
+    0x2b, 0x58, 0x62, 0x44, 0x41, 0x42, 0x48, 0x63, 0x54, 0x75, 0x50, 0x51,
+    0x56, 0x31, 0x54, 0x38, 0x34, 0x7a, 0x4a, 0x51, 0x36, 0x56, 0x64, 0x43,
+    0x73, 0x6d, 0x50, 0x57, 0x36, 0x41, 0x46, 0x2f, 0x67, 0x68, 0x68, 0x6d,
+    0x42, 0x65, 0x43, 0x38, 0x6f, 0x77, 0x48, 0x37, 0x54, 0x7a, 0x45, 0x49,
+    0x4b, 0x39, 0x61, 0x35, 0x51, 0x6f, 0x4e, 0x45, 0x2b, 0x0a, 0x78, 0x71,
+    0x46, 0x78, 0x37, 0x44, 0x2b, 0x67, 0x49, 0x49, 0x78, 0x6d, 0x4f, 0x6f,
+    0x6d, 0x30, 0x6a, 0x74, 0x54, 0x59, 0x73, 0x55, 0x30, 0x6c, 0x52, 0x2b,
+    0x34, 0x76, 0x69, 0x4d, 0x69, 0x31, 0x34, 0x51, 0x56, 0x46, 0x77, 0x4c,
+    0x34, 0x55, 0x63, 0x64, 0x35, 0x36, 0x2f, 0x59, 0x35, 0x37, 0x66, 0x55,
+    0x30, 0x49, 0x6c, 0x71, 0x55, 0x53, 0x63, 0x2f, 0x41, 0x74, 0x79, 0x6a,
+    0x63, 0x6e, 0x0a, 0x64, 0x42, 0x49, 0x6e, 0x54, 0x4d, 0x75, 0x32, 0x6c,
+    0x2b, 0x6e, 0x5a, 0x72, 0x67, 0x68, 0x74, 0x57, 0x6a, 0x6c, 0x41, 0x33,
+    0x51, 0x56, 0x48, 0x64, 0x57, 0x70, 0x61, 0x49, 0x62, 0x4f, 0x6a, 0x47,
+    0x4d, 0x39, 0x4f, 0x39, 0x79, 0x35, 0x58, 0x74, 0x35, 0x68, 0x77, 0x58,
+    0x73, 0x6a, 0x45, 0x65, 0x4c, 0x42, 0x69, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23,
+    0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d,
+    0x55, 0x54, 0x4e, 0x20, 0x2d, 0x20, 0x44, 0x41, 0x54, 0x41, 0x43, 0x6f,
+    0x72, 0x70, 0x20, 0x53, 0x47, 0x43, 0x20, 0x4f, 0x3d, 0x54, 0x68, 0x65,
+    0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e,
+    0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x4f, 0x55, 0x3d, 0x68, 0x74,
+    0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75, 0x73, 0x65,
+    0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23,
+    0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x55, 0x54, 0x4e, 0x20, 0x2d, 0x20, 0x44, 0x41, 0x54, 0x41, 0x43,
+    0x6f, 0x72, 0x70, 0x20, 0x53, 0x47, 0x43, 0x20, 0x4f, 0x3d, 0x54, 0x68,
+    0x65, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20,
+    0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x4f, 0x55, 0x3d, 0x68,
+    0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75, 0x73,
+    0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a,
+    0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x55, 0x54,
+    0x4e, 0x20, 0x44, 0x41, 0x54, 0x41, 0x43, 0x6f, 0x72, 0x70, 0x20, 0x53,
+    0x47, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x22, 0x0a,
+    0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x39, 0x31,
+    0x33, 0x37, 0x34, 0x32, 0x39, 0x34, 0x35, 0x34, 0x32, 0x38, 0x38, 0x34,
+    0x36, 0x38, 0x39, 0x38, 0x35, 0x35, 0x31, 0x36, 0x37, 0x35, 0x37, 0x37,
+    0x36, 0x38, 0x30, 0x32, 0x34, 0x31, 0x30, 0x37, 0x37, 0x36, 0x30, 0x39,
+    0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x33, 0x3a, 0x61,
+    0x35, 0x3a, 0x33, 0x65, 0x3a, 0x37, 0x37, 0x3a, 0x32, 0x31, 0x3a, 0x36,
+    0x64, 0x3a, 0x61, 0x63, 0x3a, 0x34, 0x61, 0x3a, 0x63, 0x30, 0x3a, 0x63,
+    0x39, 0x3a, 0x66, 0x62, 0x3a, 0x64, 0x35, 0x3a, 0x34, 0x31, 0x3a, 0x33,
+    0x64, 0x3a, 0x63, 0x61, 0x3a, 0x30, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48,
+    0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x35, 0x38, 0x3a, 0x31, 0x31, 0x3a, 0x39, 0x66,
+    0x3a, 0x30, 0x65, 0x3a, 0x31, 0x32, 0x3a, 0x38, 0x32, 0x3a, 0x38, 0x37,
+    0x3a, 0x65, 0x61, 0x3a, 0x35, 0x30, 0x3a, 0x66, 0x64, 0x3a, 0x64, 0x39,
+    0x3a, 0x38, 0x37, 0x3a, 0x34, 0x35, 0x3a, 0x36, 0x66, 0x3a, 0x34, 0x66,
+    0x3a, 0x37, 0x38, 0x3a, 0x64, 0x63, 0x3a, 0x66, 0x61, 0x3a, 0x64, 0x36,
+    0x3a, 0x64, 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x38, 0x35, 0x3a, 0x66, 0x62, 0x3a, 0x32, 0x66, 0x3a, 0x39,
+    0x31, 0x3a, 0x64, 0x64, 0x3a, 0x31, 0x32, 0x3a, 0x32, 0x37, 0x3a, 0x35,
+    0x61, 0x3a, 0x30, 0x31, 0x3a, 0x34, 0x35, 0x3a, 0x62, 0x36, 0x3a, 0x33,
+    0x36, 0x3a, 0x35, 0x33, 0x3a, 0x34, 0x66, 0x3a, 0x38, 0x34, 0x3a, 0x30,
+    0x32, 0x3a, 0x34, 0x61, 0x3a, 0x64, 0x36, 0x3a, 0x38, 0x62, 0x3a, 0x36,
+    0x39, 0x3a, 0x62, 0x38, 0x3a, 0x65, 0x65, 0x3a, 0x38, 0x38, 0x3a, 0x36,
+    0x38, 0x3a, 0x34, 0x66, 0x3a, 0x66, 0x37, 0x3a, 0x31, 0x31, 0x3a, 0x33,
+    0x37, 0x3a, 0x35, 0x38, 0x3a, 0x30, 0x35, 0x3a, 0x62, 0x33, 0x3a, 0x34,
+    0x38, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x58, 0x6a,
+    0x43, 0x43, 0x41, 0x30, 0x61, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67,
+    0x49, 0x51, 0x52, 0x4c, 0x34, 0x4d, 0x69, 0x31, 0x41, 0x41, 0x49, 0x62,
+    0x51, 0x52, 0x30, 0x79, 0x70, 0x6f, 0x42, 0x71, 0x6d, 0x74, 0x61, 0x54,
+    0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77,
+    0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x6b,
+    0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42,
+    0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x54, 0x41, 0x6c, 0x56, 0x55, 0x4d,
+    0x52, 0x63, 0x77, 0x46, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x45,
+    0x77, 0x35, 0x54, 0x59, 0x57, 0x78, 0x30, 0x49, 0x45, 0x78, 0x68, 0x61,
+    0x32, 0x55, 0x67, 0x0a, 0x51, 0x32, 0x6c, 0x30, 0x65, 0x54, 0x45, 0x65,
+    0x4d, 0x42, 0x77, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x56,
+    0x56, 0x47, 0x68, 0x6c, 0x49, 0x46, 0x56, 0x54, 0x52, 0x56, 0x4a, 0x55,
+    0x55, 0x6c, 0x56, 0x54, 0x56, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33,
+    0x62, 0x33, 0x4a, 0x72, 0x4d, 0x53, 0x45, 0x77, 0x48, 0x77, 0x59, 0x44,
+    0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x68, 0x6f, 0x0a, 0x64, 0x48, 0x52,
+    0x77, 0x4f, 0x69, 0x38, 0x76, 0x64, 0x33, 0x64, 0x33, 0x4c, 0x6e, 0x56,
+    0x7a, 0x5a, 0x58, 0x4a, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x35,
+    0x6a, 0x62, 0x32, 0x30, 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, 0x67, 0x4e,
+    0x56, 0x42, 0x41, 0x4d, 0x54, 0x45, 0x6c, 0x56, 0x55, 0x54, 0x69, 0x41,
+    0x74, 0x49, 0x45, 0x52, 0x42, 0x56, 0x45, 0x46, 0x44, 0x62, 0x33, 0x4a,
+    0x77, 0x0a, 0x49, 0x46, 0x4e, 0x48, 0x51, 0x7a, 0x41, 0x65, 0x46, 0x77,
+    0x30, 0x35, 0x4f, 0x54, 0x41, 0x32, 0x4d, 0x6a, 0x51, 0x78, 0x4f, 0x44,
+    0x55, 0x33, 0x4d, 0x6a, 0x46, 0x61, 0x46, 0x77, 0x30, 0x78, 0x4f, 0x54,
+    0x41, 0x32, 0x4d, 0x6a, 0x51, 0x78, 0x4f, 0x54, 0x41, 0x32, 0x4d, 0x7a,
+    0x42, 0x61, 0x4d, 0x49, 0x47, 0x54, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51,
+    0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x0a, 0x45, 0x77, 0x4a, 0x56, 0x55,
+    0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43,
+    0x42, 0x4d, 0x43, 0x56, 0x56, 0x51, 0x78, 0x46, 0x7a, 0x41, 0x56, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x44, 0x6c, 0x4e, 0x68, 0x62,
+    0x48, 0x51, 0x67, 0x54, 0x47, 0x46, 0x72, 0x5a, 0x53, 0x42, 0x44, 0x61,
+    0x58, 0x52, 0x35, 0x4d, 0x52, 0x34, 0x77, 0x48, 0x41, 0x59, 0x44, 0x0a,
+    0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x56, 0x55, 0x61, 0x47, 0x55, 0x67,
+    0x56, 0x56, 0x4e, 0x46, 0x55, 0x6c, 0x52, 0x53, 0x56, 0x56, 0x4e, 0x55,
+    0x49, 0x45, 0x35, 0x6c, 0x64, 0x48, 0x64, 0x76, 0x63, 0x6d, 0x73, 0x78,
+    0x49, 0x54, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54,
+    0x47, 0x47, 0x68, 0x30, 0x64, 0x48, 0x41, 0x36, 0x4c, 0x79, 0x39, 0x33,
+    0x64, 0x33, 0x63, 0x75, 0x0a, 0x64, 0x58, 0x4e, 0x6c, 0x63, 0x6e, 0x52,
+    0x79, 0x64, 0x58, 0x4e, 0x30, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x54, 0x45,
+    0x62, 0x4d, 0x42, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d,
+    0x53, 0x56, 0x56, 0x52, 0x4f, 0x49, 0x43, 0x30, 0x67, 0x52, 0x45, 0x46,
+    0x55, 0x51, 0x55, 0x4e, 0x76, 0x63, 0x6e, 0x41, 0x67, 0x55, 0x30, 0x64,
+    0x44, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x0a, 0x42, 0x67,
+    0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51,
+    0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49,
+    0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x33, 0x2b,
+    0x35, 0x59, 0x45, 0x4b, 0x49, 0x72, 0x62, 0x6c, 0x58, 0x45, 0x6a, 0x72,
+    0x38, 0x75, 0x52, 0x67, 0x6e, 0x6e, 0x34, 0x41, 0x67, 0x50, 0x4c, 0x69,
+    0x74, 0x36, 0x0a, 0x45, 0x35, 0x51, 0x62, 0x76, 0x66, 0x61, 0x32, 0x67,
+    0x49, 0x35, 0x6c, 0x42, 0x5a, 0x4d, 0x41, 0x48, 0x72, 0x79, 0x76, 0x34,
+    0x67, 0x2b, 0x4f, 0x47, 0x51, 0x30, 0x53, 0x52, 0x2b, 0x79, 0x73, 0x72,
+    0x61, 0x50, 0x36, 0x4c, 0x6e, 0x44, 0x34, 0x33, 0x6d, 0x37, 0x37, 0x56,
+    0x6b, 0x49, 0x56, 0x6e, 0x69, 0x35, 0x63, 0x37, 0x79, 0x50, 0x65, 0x49,
+    0x62, 0x6b, 0x46, 0x64, 0x69, 0x63, 0x5a, 0x0a, 0x44, 0x30, 0x2f, 0x57,
+    0x77, 0x35, 0x79, 0x30, 0x76, 0x70, 0x51, 0x5a, 0x59, 0x2f, 0x4b, 0x6d,
+    0x45, 0x51, 0x72, 0x72, 0x55, 0x30, 0x69, 0x63, 0x76, 0x76, 0x49, 0x70,
+    0x4f, 0x78, 0x62, 0x6f, 0x47, 0x71, 0x42, 0x4d, 0x70, 0x73, 0x6e, 0x30,
+    0x47, 0x46, 0x6c, 0x6f, 0x77, 0x48, 0x44, 0x79, 0x55, 0x77, 0x44, 0x41,
+    0x58, 0x6c, 0x43, 0x43, 0x70, 0x56, 0x5a, 0x76, 0x4e, 0x76, 0x6c, 0x4b,
+    0x0a, 0x34, 0x45, 0x53, 0x47, 0x6f, 0x45, 0x31, 0x4f, 0x31, 0x6b, 0x64,
+    0x75, 0x53, 0x55, 0x72, 0x4c, 0x5a, 0x39, 0x65, 0x6d, 0x78, 0x41, 0x57,
+    0x35, 0x6a, 0x68, 0x37, 0x30, 0x2f, 0x50, 0x2f, 0x4e, 0x35, 0x7a, 0x62,
+    0x67, 0x6e, 0x41, 0x56, 0x73, 0x73, 0x6a, 0x4d, 0x69, 0x46, 0x64, 0x43,
+    0x30, 0x34, 0x4d, 0x77, 0x58, 0x77, 0x4c, 0x4c, 0x41, 0x39, 0x50, 0x34,
+    0x79, 0x50, 0x79, 0x6b, 0x71, 0x0a, 0x6c, 0x58, 0x76, 0x59, 0x38, 0x71,
+    0x64, 0x4f, 0x44, 0x31, 0x52, 0x38, 0x6f, 0x51, 0x32, 0x41, 0x73, 0x77,
+    0x6b, 0x44, 0x77, 0x66, 0x39, 0x63, 0x33, 0x56, 0x36, 0x61, 0x50, 0x72,
+    0x79, 0x75, 0x76, 0x45, 0x65, 0x4b, 0x61, 0x71, 0x35, 0x78, 0x79, 0x68,
+    0x2b, 0x78, 0x4b, 0x72, 0x68, 0x66, 0x51, 0x67, 0x55, 0x4c, 0x37, 0x45,
+    0x59, 0x77, 0x30, 0x58, 0x49, 0x4c, 0x79, 0x75, 0x6c, 0x57, 0x0a, 0x62,
+    0x66, 0x58, 0x76, 0x33, 0x33, 0x69, 0x2b, 0x59, 0x62, 0x71, 0x79, 0x70,
+    0x61, 0x34, 0x45, 0x54, 0x4c, 0x79, 0x6f, 0x72, 0x47, 0x6b, 0x56, 0x6c,
+    0x37, 0x33, 0x76, 0x36, 0x37, 0x53, 0x4d, 0x76, 0x7a, 0x58, 0x34, 0x31,
+    0x4d, 0x50, 0x52, 0x4b, 0x41, 0x35, 0x63, 0x4f, 0x70, 0x39, 0x77, 0x47,
+    0x44, 0x4d, 0x67, 0x64, 0x38, 0x53, 0x69, 0x72, 0x77, 0x49, 0x44, 0x41,
+    0x51, 0x41, 0x42, 0x0a, 0x6f, 0x34, 0x47, 0x72, 0x4d, 0x49, 0x47, 0x6f,
+    0x4d, 0x41, 0x73, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x51, 0x45,
+    0x41, 0x77, 0x49, 0x42, 0x78, 0x6a, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56,
+    0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44,
+    0x41, 0x51, 0x48, 0x2f, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64,
+    0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x52, 0x54, 0x0a, 0x4d, 0x74, 0x47,
+    0x7a, 0x7a, 0x33, 0x2f, 0x36, 0x34, 0x50, 0x47, 0x67, 0x58, 0x59, 0x56,
+    0x4f, 0x6b, 0x74, 0x4b, 0x65, 0x52, 0x52, 0x32, 0x30, 0x54, 0x7a, 0x41,
+    0x39, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x38, 0x45, 0x4e, 0x6a, 0x41,
+    0x30, 0x4d, 0x44, 0x4b, 0x67, 0x4d, 0x4b, 0x41, 0x75, 0x68, 0x69, 0x78,
+    0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69, 0x38, 0x76, 0x59, 0x33, 0x4a,
+    0x73, 0x0a, 0x4c, 0x6e, 0x56, 0x7a, 0x5a, 0x58, 0x4a, 0x30, 0x63, 0x6e,
+    0x56, 0x7a, 0x64, 0x43, 0x35, 0x6a, 0x62, 0x32, 0x30, 0x76, 0x56, 0x56,
+    0x52, 0x4f, 0x4c, 0x55, 0x52, 0x42, 0x56, 0x45, 0x46, 0x44, 0x62, 0x33,
+    0x4a, 0x77, 0x55, 0x30, 0x64, 0x44, 0x4c, 0x6d, 0x4e, 0x79, 0x62, 0x44,
+    0x41, 0x71, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x55, 0x45, 0x49, 0x7a,
+    0x41, 0x68, 0x42, 0x67, 0x67, 0x72, 0x0a, 0x42, 0x67, 0x45, 0x46, 0x42,
+    0x51, 0x63, 0x44, 0x41, 0x51, 0x59, 0x4b, 0x4b, 0x77, 0x59, 0x42, 0x42,
+    0x41, 0x47, 0x43, 0x4e, 0x77, 0x6f, 0x44, 0x41, 0x77, 0x59, 0x4a, 0x59,
+    0x49, 0x5a, 0x49, 0x41, 0x59, 0x62, 0x34, 0x51, 0x67, 0x51, 0x42, 0x4d,
+    0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44,
+    0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x0a,
+    0x41, 0x51, 0x41, 0x6e, 0x4e, 0x5a, 0x63, 0x41, 0x69, 0x6f, 0x73, 0x6f,
+    0x76, 0x63, 0x59, 0x7a, 0x4d, 0x42, 0x34, 0x70, 0x2f, 0x4f, 0x4c, 0x33,
+    0x31, 0x5a, 0x6a, 0x55, 0x51, 0x4c, 0x74, 0x67, 0x79, 0x72, 0x2b, 0x72,
+    0x46, 0x79, 0x77, 0x4a, 0x4e, 0x6e, 0x39, 0x51, 0x2b, 0x6b, 0x48, 0x63,
+    0x72, 0x70, 0x59, 0x36, 0x43, 0x69, 0x4d, 0x2b, 0x69, 0x56, 0x6e, 0x4a,
+    0x6f, 0x77, 0x66, 0x74, 0x0a, 0x47, 0x7a, 0x65, 0x74, 0x2f, 0x48, 0x79,
+    0x2b, 0x55, 0x55, 0x6c, 0x61, 0x33, 0x6a, 0x6f, 0x4b, 0x56, 0x41, 0x67,
+    0x57, 0x52, 0x63, 0x4b, 0x5a, 0x73, 0x59, 0x66, 0x4e, 0x6a, 0x47, 0x6a,
+    0x67, 0x61, 0x51, 0x50, 0x70, 0x78, 0x45, 0x36, 0x59, 0x73, 0x6a, 0x75,
+    0x4d, 0x46, 0x72, 0x4d, 0x4f, 0x6f, 0x41, 0x79, 0x59, 0x55, 0x4a, 0x75,
+    0x54, 0x71, 0x58, 0x41, 0x4a, 0x79, 0x43, 0x79, 0x6a, 0x0a, 0x6a, 0x39,
+    0x38, 0x43, 0x35, 0x4f, 0x42, 0x78, 0x4f, 0x76, 0x47, 0x30, 0x49, 0x33,
+    0x4b, 0x67, 0x71, 0x67, 0x48, 0x66, 0x33, 0x35, 0x67, 0x2b, 0x46, 0x46,
+    0x43, 0x67, 0x4d, 0x53, 0x61, 0x39, 0x4b, 0x4f, 0x6c, 0x61, 0x4d, 0x43,
+    0x5a, 0x31, 0x2b, 0x58, 0x74, 0x67, 0x48, 0x49, 0x33, 0x7a, 0x7a, 0x56,
+    0x41, 0x6d, 0x62, 0x51, 0x51, 0x6e, 0x6d, 0x74, 0x2f, 0x56, 0x44, 0x55,
+    0x56, 0x48, 0x0a, 0x4b, 0x57, 0x73, 0x73, 0x35, 0x6e, 0x62, 0x5a, 0x71,
+    0x53, 0x6c, 0x39, 0x4d, 0x74, 0x33, 0x4a, 0x4e, 0x6a, 0x79, 0x39, 0x72,
+    0x6a, 0x58, 0x78, 0x45, 0x5a, 0x34, 0x64, 0x75, 0x35, 0x41, 0x2f, 0x45,
+    0x6b, 0x64, 0x4f, 0x6a, 0x74, 0x64, 0x2b, 0x44, 0x32, 0x4a, 0x7a, 0x48,
+    0x56, 0x49, 0x6d, 0x4f, 0x42, 0x77, 0x59, 0x53, 0x66, 0x30, 0x77, 0x64,
+    0x4a, 0x72, 0x45, 0x35, 0x53, 0x49, 0x76, 0x0a, 0x32, 0x4d, 0x43, 0x4e,
+    0x37, 0x5a, 0x46, 0x36, 0x54, 0x41, 0x43, 0x50, 0x63, 0x6e, 0x39, 0x64,
+    0x32, 0x74, 0x30, 0x62, 0x69, 0x30, 0x56, 0x72, 0x35, 0x39, 0x31, 0x70,
+    0x6c, 0x36, 0x6a, 0x46, 0x56, 0x6b, 0x77, 0x50, 0x44, 0x50, 0x61, 0x66,
+    0x65, 0x70, 0x45, 0x33, 0x39, 0x70, 0x65, 0x43, 0x34, 0x4e, 0x31, 0x78,
+    0x61, 0x66, 0x39, 0x32, 0x50, 0x32, 0x42, 0x4e, 0x50, 0x4d, 0x2f, 0x33,
+    0x0a, 0x6d, 0x66, 0x6e, 0x47, 0x56, 0x2f, 0x54, 0x4a, 0x56, 0x54, 0x6c,
+    0x34, 0x75, 0x69, 0x78, 0x35, 0x79, 0x61, 0x61, 0x49, 0x4b, 0x2f, 0x51,
+    0x49, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65,
+    0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53,
+    0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64,
+    0x77, 0x61, 0x72, 0x65, 0x20, 0x4f, 0x3d, 0x54, 0x68, 0x65, 0x20, 0x55,
+    0x53, 0x45, 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74,
+    0x77, 0x6f, 0x72, 0x6b, 0x20, 0x4f, 0x55, 0x3d, 0x68, 0x74, 0x74, 0x70,
+    0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74,
+    0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x53,
+    0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x55,
+    0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74,
+    0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x20, 0x4f, 0x3d,
+    0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52, 0x55, 0x53,
+    0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x4f, 0x55,
+    0x3d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
+    0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f,
+    0x6d, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22,
+    0x55, 0x54, 0x4e, 0x20, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73,
+    0x74, 0x20, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x20, 0x52,
+    0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65,
+    0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x39, 0x31, 0x33, 0x37, 0x34, 0x32,
+    0x39, 0x34, 0x35, 0x34, 0x32, 0x38, 0x38, 0x34, 0x37, 0x30, 0x34, 0x30,
+    0x32, 0x32, 0x32, 0x36, 0x37, 0x30, 0x33, 0x39, 0x32, 0x32, 0x31, 0x31,
+    0x38, 0x34, 0x35, 0x33, 0x31, 0x31, 0x39, 0x37, 0x0a, 0x23, 0x20, 0x4d,
+    0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x34, 0x63, 0x3a, 0x35, 0x36, 0x3a, 0x34, 0x31,
+    0x3a, 0x65, 0x35, 0x3a, 0x30, 0x64, 0x3a, 0x62, 0x62, 0x3a, 0x32, 0x62,
+    0x3a, 0x65, 0x38, 0x3a, 0x63, 0x61, 0x3a, 0x61, 0x33, 0x3a, 0x65, 0x64,
+    0x3a, 0x31, 0x38, 0x3a, 0x30, 0x38, 0x3a, 0x61, 0x64, 0x3a, 0x34, 0x33,
+    0x3a, 0x33, 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x30, 0x34, 0x3a, 0x38, 0x33, 0x3a, 0x65, 0x64, 0x3a, 0x33, 0x33, 0x3a,
+    0x39, 0x39, 0x3a, 0x61, 0x63, 0x3a, 0x33, 0x36, 0x3a, 0x30, 0x38, 0x3a,
+    0x30, 0x35, 0x3a, 0x38, 0x37, 0x3a, 0x32, 0x32, 0x3a, 0x65, 0x64, 0x3a,
+    0x62, 0x63, 0x3a, 0x35, 0x65, 0x3a, 0x34, 0x36, 0x3a, 0x30, 0x30, 0x3a,
+    0x65, 0x33, 0x3a, 0x62, 0x65, 0x3a, 0x66, 0x39, 0x3a, 0x64, 0x37, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x65,
+    0x3a, 0x61, 0x35, 0x3a, 0x34, 0x37, 0x3a, 0x34, 0x31, 0x3a, 0x64, 0x30,
+    0x3a, 0x30, 0x34, 0x3a, 0x36, 0x36, 0x3a, 0x37, 0x65, 0x3a, 0x65, 0x64,
+    0x3a, 0x31, 0x62, 0x3a, 0x34, 0x38, 0x3a, 0x31, 0x36, 0x3a, 0x36, 0x33,
+    0x3a, 0x34, 0x61, 0x3a, 0x61, 0x33, 0x3a, 0x61, 0x37, 0x3a, 0x39, 0x65,
+    0x3a, 0x36, 0x65, 0x3a, 0x34, 0x62, 0x3a, 0x39, 0x36, 0x3a, 0x39, 0x35,
+    0x3a, 0x30, 0x66, 0x3a, 0x38, 0x32, 0x3a, 0x37, 0x39, 0x3a, 0x64, 0x61,
+    0x3a, 0x66, 0x63, 0x3a, 0x38, 0x64, 0x3a, 0x39, 0x62, 0x3a, 0x64, 0x38,
+    0x3a, 0x38, 0x31, 0x3a, 0x32, 0x31, 0x3a, 0x33, 0x37, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52,
+    0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x64, 0x44, 0x43, 0x43, 0x41, 0x31,
+    0x79, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x52, 0x4c,
+    0x34, 0x4d, 0x69, 0x31, 0x41, 0x41, 0x4a, 0x4c, 0x51, 0x52, 0x30, 0x7a,
+    0x59, 0x71, 0x2f, 0x6d, 0x55, 0x4b, 0x2f, 0x54, 0x41, 0x4e, 0x42, 0x67,
+    0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51,
+    0x55, 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x6c, 0x7a, 0x45, 0x4c, 0x4d,
+    0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56,
+    0x56, 0x4d, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x67, 0x54, 0x41, 0x6c, 0x56, 0x55, 0x4d, 0x52, 0x63, 0x77, 0x46,
+    0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x45, 0x77, 0x35, 0x54, 0x59,
+    0x57, 0x78, 0x30, 0x49, 0x45, 0x78, 0x68, 0x61, 0x32, 0x55, 0x67, 0x0a,
+    0x51, 0x32, 0x6c, 0x30, 0x65, 0x54, 0x45, 0x65, 0x4d, 0x42, 0x77, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x56, 0x56, 0x47, 0x68, 0x6c,
+    0x49, 0x46, 0x56, 0x54, 0x52, 0x56, 0x4a, 0x55, 0x55, 0x6c, 0x56, 0x54,
+    0x56, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72,
+    0x4d, 0x53, 0x45, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c,
+    0x45, 0x78, 0x68, 0x6f, 0x0a, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69, 0x38,
+    0x76, 0x64, 0x33, 0x64, 0x33, 0x4c, 0x6e, 0x56, 0x7a, 0x5a, 0x58, 0x4a,
+    0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x35, 0x6a, 0x62, 0x32, 0x30,
+    0x78, 0x48, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d,
+    0x54, 0x46, 0x6c, 0x56, 0x55, 0x54, 0x69, 0x31, 0x56, 0x55, 0x30, 0x56,
+    0x53, 0x52, 0x6d, 0x6c, 0x79, 0x63, 0x33, 0x51, 0x74, 0x0a, 0x53, 0x47,
+    0x46, 0x79, 0x5a, 0x48, 0x64, 0x68, 0x63, 0x6d, 0x55, 0x77, 0x48, 0x68,
+    0x63, 0x4e, 0x4f, 0x54, 0x6b, 0x77, 0x4e, 0x7a, 0x41, 0x35, 0x4d, 0x54,
+    0x67, 0x78, 0x4d, 0x44, 0x51, 0x79, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x54,
+    0x6b, 0x77, 0x4e, 0x7a, 0x41, 0x35, 0x4d, 0x54, 0x67, 0x78, 0x4f, 0x54,
+    0x49, 0x79, 0x57, 0x6a, 0x43, 0x42, 0x6c, 0x7a, 0x45, 0x4c, 0x4d, 0x41,
+    0x6b, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56,
+    0x56, 0x4d, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x67, 0x54, 0x41, 0x6c, 0x56, 0x55, 0x4d, 0x52, 0x63, 0x77, 0x46,
+    0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x45, 0x77, 0x35, 0x54, 0x59,
+    0x57, 0x78, 0x30, 0x49, 0x45, 0x78, 0x68, 0x61, 0x32, 0x55, 0x67, 0x51,
+    0x32, 0x6c, 0x30, 0x65, 0x54, 0x45, 0x65, 0x0a, 0x4d, 0x42, 0x77, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x56, 0x56, 0x47, 0x68, 0x6c,
+    0x49, 0x46, 0x56, 0x54, 0x52, 0x56, 0x4a, 0x55, 0x55, 0x6c, 0x56, 0x54,
+    0x56, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72,
+    0x4d, 0x53, 0x45, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c,
+    0x45, 0x78, 0x68, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69, 0x38, 0x76,
+    0x0a, 0x64, 0x33, 0x64, 0x33, 0x4c, 0x6e, 0x56, 0x7a, 0x5a, 0x58, 0x4a,
+    0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x35, 0x6a, 0x62, 0x32, 0x30,
+    0x78, 0x48, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d,
+    0x54, 0x46, 0x6c, 0x56, 0x55, 0x54, 0x69, 0x31, 0x56, 0x55, 0x30, 0x56,
+    0x53, 0x52, 0x6d, 0x6c, 0x79, 0x63, 0x33, 0x51, 0x74, 0x53, 0x47, 0x46,
+    0x79, 0x5a, 0x48, 0x64, 0x68, 0x0a, 0x63, 0x6d, 0x55, 0x77, 0x67, 0x67,
+    0x45, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49,
+    0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34,
+    0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f,
+    0x49, 0x42, 0x41, 0x51, 0x43, 0x78, 0x39, 0x38, 0x4d, 0x34, 0x50, 0x37,
+    0x53, 0x6f, 0x66, 0x38, 0x38, 0x35, 0x67, 0x6c, 0x46, 0x6e, 0x0a, 0x30,
+    0x47, 0x32, 0x66, 0x30, 0x76, 0x39, 0x59, 0x38, 0x2b, 0x65, 0x66, 0x4b,
+    0x2b, 0x77, 0x4e, 0x69, 0x56, 0x53, 0x5a, 0x75, 0x54, 0x69, 0x5a, 0x46,
+    0x76, 0x66, 0x67, 0x49, 0x58, 0x6c, 0x49, 0x77, 0x72, 0x74, 0x68, 0x64,
+    0x42, 0x4b, 0x57, 0x48, 0x54, 0x78, 0x71, 0x63, 0x74, 0x55, 0x38, 0x45,
+    0x47, 0x63, 0x36, 0x4f, 0x65, 0x30, 0x72, 0x45, 0x38, 0x31, 0x6d, 0x36,
+    0x35, 0x55, 0x4a, 0x0a, 0x4d, 0x36, 0x52, 0x73, 0x6c, 0x37, 0x48, 0x6f,
+    0x78, 0x75, 0x7a, 0x42, 0x64, 0x58, 0x6d, 0x63, 0x52, 0x6c, 0x36, 0x4e,
+    0x71, 0x39, 0x42, 0x71, 0x2f, 0x62, 0x6b, 0x71, 0x56, 0x52, 0x63, 0x51,
+    0x56, 0x4c, 0x4d, 0x5a, 0x38, 0x4a, 0x72, 0x32, 0x38, 0x62, 0x46, 0x64,
+    0x74, 0x71, 0x64, 0x74, 0x2b, 0x2b, 0x42, 0x78, 0x46, 0x32, 0x75, 0x69,
+    0x69, 0x50, 0x73, 0x41, 0x33, 0x2f, 0x34, 0x61, 0x0a, 0x4d, 0x58, 0x63,
+    0x4d, 0x6d, 0x67, 0x46, 0x36, 0x73, 0x54, 0x4c, 0x6a, 0x4b, 0x77, 0x45,
+    0x48, 0x4f, 0x47, 0x37, 0x44, 0x70, 0x56, 0x34, 0x6a, 0x76, 0x45, 0x57,
+    0x62, 0x65, 0x31, 0x44, 0x42, 0x79, 0x54, 0x43, 0x50, 0x32, 0x2b, 0x55,
+    0x72, 0x65, 0x74, 0x4e, 0x62, 0x2b, 0x7a, 0x4e, 0x41, 0x48, 0x71, 0x44,
+    0x56, 0x6d, 0x42, 0x65, 0x38, 0x69, 0x34, 0x66, 0x44, 0x69, 0x64, 0x4e,
+    0x64, 0x0a, 0x6f, 0x49, 0x36, 0x79, 0x71, 0x71, 0x72, 0x32, 0x6a, 0x6d,
+    0x6d, 0x49, 0x42, 0x73, 0x58, 0x36, 0x69, 0x53, 0x48, 0x7a, 0x43, 0x4a,
+    0x31, 0x70, 0x4c, 0x67, 0x6b, 0x7a, 0x6d, 0x79, 0x6b, 0x4e, 0x52, 0x67,
+    0x2b, 0x4d, 0x7a, 0x45, 0x6b, 0x30, 0x73, 0x47, 0x6c, 0x52, 0x76, 0x66,
+    0x6b, 0x47, 0x7a, 0x57, 0x69, 0x74, 0x5a, 0x6b, 0x79, 0x38, 0x50, 0x71,
+    0x78, 0x68, 0x76, 0x51, 0x71, 0x49, 0x0a, 0x44, 0x73, 0x6a, 0x66, 0x50,
+    0x65, 0x35, 0x38, 0x42, 0x45, 0x79, 0x64, 0x43, 0x6c, 0x35, 0x72, 0x6b,
+    0x64, 0x62, 0x75, 0x78, 0x2b, 0x30, 0x6f, 0x6a, 0x61, 0x74, 0x4e, 0x68,
+    0x34, 0x6c, 0x7a, 0x30, 0x47, 0x36, 0x6b, 0x30, 0x42, 0x34, 0x57, 0x69,
+    0x78, 0x54, 0x68, 0x64, 0x6b, 0x51, 0x44, 0x66, 0x32, 0x4f, 0x73, 0x35,
+    0x4d, 0x31, 0x4a, 0x6e, 0x4d, 0x57, 0x53, 0x39, 0x4b, 0x73, 0x79, 0x0a,
+    0x6f, 0x55, 0x68, 0x62, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a,
+    0x67, 0x62, 0x6b, 0x77, 0x67, 0x62, 0x59, 0x77, 0x43, 0x77, 0x59, 0x44,
+    0x56, 0x52, 0x30, 0x50, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x48, 0x47,
+    0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42,
+    0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77,
+    0x48, 0x51, 0x59, 0x44, 0x0a, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59,
+    0x45, 0x46, 0x4b, 0x46, 0x79, 0x58, 0x79, 0x59, 0x62, 0x4b, 0x4a, 0x68,
+    0x44, 0x6c, 0x56, 0x30, 0x48, 0x4e, 0x39, 0x57, 0x46, 0x6c, 0x70, 0x31,
+    0x4c, 0x30, 0x73, 0x4e, 0x46, 0x4d, 0x45, 0x51, 0x47, 0x41, 0x31, 0x55,
+    0x64, 0x48, 0x77, 0x51, 0x39, 0x4d, 0x44, 0x73, 0x77, 0x4f, 0x61, 0x41,
+    0x33, 0x6f, 0x44, 0x57, 0x47, 0x4d, 0x32, 0x68, 0x30, 0x0a, 0x64, 0x48,
+    0x41, 0x36, 0x4c, 0x79, 0x39, 0x6a, 0x63, 0x6d, 0x77, 0x75, 0x64, 0x58,
+    0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4c, 0x6d,
+    0x4e, 0x76, 0x62, 0x53, 0x39, 0x56, 0x56, 0x45, 0x34, 0x74, 0x56, 0x56,
+    0x4e, 0x46, 0x55, 0x6b, 0x5a, 0x70, 0x63, 0x6e, 0x4e, 0x30, 0x4c, 0x55,
+    0x68, 0x68, 0x63, 0x6d, 0x52, 0x33, 0x59, 0x58, 0x4a, 0x6c, 0x4c, 0x6d,
+    0x4e, 0x79, 0x0a, 0x62, 0x44, 0x41, 0x78, 0x42, 0x67, 0x4e, 0x56, 0x48,
+    0x53, 0x55, 0x45, 0x4b, 0x6a, 0x41, 0x6f, 0x42, 0x67, 0x67, 0x72, 0x42,
+    0x67, 0x45, 0x46, 0x42, 0x51, 0x63, 0x44, 0x41, 0x51, 0x59, 0x49, 0x4b,
+    0x77, 0x59, 0x42, 0x42, 0x51, 0x55, 0x48, 0x41, 0x77, 0x55, 0x47, 0x43,
+    0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x77, 0x4d, 0x47, 0x42,
+    0x67, 0x67, 0x72, 0x42, 0x67, 0x45, 0x46, 0x0a, 0x42, 0x51, 0x63, 0x44,
+    0x42, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47,
+    0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43,
+    0x41, 0x51, 0x45, 0x41, 0x52, 0x78, 0x6b, 0x50, 0x33, 0x6e, 0x54, 0x47,
+    0x6d, 0x5a, 0x65, 0x76, 0x2f, 0x4b, 0x30, 0x6f, 0x58, 0x6e, 0x57, 0x4f,
+    0x36, 0x79, 0x31, 0x6e, 0x37, 0x6b, 0x35, 0x37, 0x4b, 0x39, 0x63, 0x4d,
+    0x0a, 0x2f, 0x2f, 0x62, 0x65, 0x79, 0x31, 0x57, 0x69, 0x43, 0x75, 0x46,
+    0x4d, 0x56, 0x47, 0x57, 0x54, 0x59, 0x47, 0x75, 0x66, 0x45, 0x70, 0x79,
+    0x74, 0x58, 0x6f, 0x4d, 0x73, 0x36, 0x31, 0x71, 0x75, 0x77, 0x4f, 0x51,
+    0x74, 0x39, 0x41, 0x42, 0x6a, 0x48, 0x62, 0x6a, 0x41, 0x62, 0x50, 0x4c,
+    0x50, 0x53, 0x62, 0x74, 0x4e, 0x6b, 0x32, 0x38, 0x47, 0x70, 0x67, 0x6f,
+    0x69, 0x73, 0x6b, 0x6c, 0x69, 0x0a, 0x43, 0x45, 0x37, 0x2f, 0x79, 0x4d,
+    0x67, 0x55, 0x73, 0x6f, 0x67, 0x57, 0x58, 0x65, 0x63, 0x42, 0x35, 0x42,
+    0x4b, 0x56, 0x35, 0x55, 0x55, 0x30, 0x73, 0x34, 0x74, 0x70, 0x76, 0x63,
+    0x2b, 0x30, 0x68, 0x59, 0x39, 0x31, 0x55, 0x5a, 0x35, 0x39, 0x4f, 0x6a,
+    0x67, 0x36, 0x46, 0x45, 0x67, 0x53, 0x78, 0x76, 0x75, 0x6e, 0x4f, 0x78,
+    0x71, 0x4e, 0x44, 0x59, 0x4a, 0x41, 0x42, 0x2b, 0x67, 0x45, 0x0a, 0x43,
+    0x4a, 0x43, 0x68, 0x69, 0x63, 0x73, 0x5a, 0x55, 0x4e, 0x2f, 0x4b, 0x48,
+    0x41, 0x47, 0x38, 0x48, 0x51, 0x51, 0x5a, 0x65, 0x78, 0x42, 0x32, 0x6c,
+    0x7a, 0x76, 0x75, 0x6b, 0x4a, 0x44, 0x4b, 0x78, 0x41, 0x34, 0x66, 0x46,
+    0x6d, 0x35, 0x31, 0x37, 0x7a, 0x50, 0x34, 0x30, 0x32, 0x39, 0x62, 0x48,
+    0x70, 0x62, 0x6a, 0x34, 0x48, 0x52, 0x33, 0x64, 0x48, 0x75, 0x4b, 0x6f,
+    0x6d, 0x34, 0x74, 0x0a, 0x33, 0x58, 0x62, 0x57, 0x4f, 0x54, 0x43, 0x43,
+    0x38, 0x4b, 0x75, 0x63, 0x55, 0x76, 0x49, 0x71, 0x78, 0x36, 0x39, 0x4a,
+    0x58, 0x6e, 0x37, 0x48, 0x61, 0x4f, 0x57, 0x43, 0x67, 0x63, 0x68, 0x71,
+    0x4a, 0x2f, 0x6b, 0x6e, 0x69, 0x43, 0x72, 0x56, 0x57, 0x46, 0x43, 0x56,
+    0x48, 0x2f, 0x41, 0x37, 0x48, 0x46, 0x65, 0x37, 0x66, 0x52, 0x51, 0x35,
+    0x59, 0x69, 0x75, 0x61, 0x79, 0x5a, 0x53, 0x53, 0x0a, 0x4b, 0x71, 0x4d,
+    0x69, 0x44, 0x50, 0x2b, 0x4a, 0x4a, 0x6e, 0x31, 0x66, 0x49, 0x79, 0x74,
+    0x48, 0x31, 0x78, 0x55, 0x64, 0x71, 0x57, 0x71, 0x65, 0x55, 0x51, 0x30,
+    0x71, 0x55, 0x5a, 0x36, 0x42, 0x2b, 0x64, 0x51, 0x37, 0x58, 0x6e, 0x41,
+    0x53, 0x66, 0x78, 0x41, 0x79, 0x6e, 0x42, 0x36, 0x37, 0x6e, 0x66, 0x68,
+    0x6d, 0x71, 0x41, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45,
+    0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41,
+    0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49,
+    0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x58, 0x52,
+    0x61, 0x6d, 0x70, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43,
+    0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+    0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f,
+    0x3d, 0x58, 0x52, 0x61, 0x6d, 0x70, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72,
+    0x69, 0x74, 0x79, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
+    0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e,
+    0x78, 0x72, 0x61, 0x6d, 0x70, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
+    0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a,
+    0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x58, 0x52, 0x61, 0x6d,
+    0x70, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72,
+    0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41,
+    0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x58,
+    0x52, 0x61, 0x6d, 0x70, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
+    0x79, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x49,
+    0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x78, 0x72,
+    0x61, 0x6d, 0x70, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2e,
+    0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a,
+    0x20, 0x22, 0x58, 0x52, 0x61, 0x6d, 0x70, 0x20, 0x47, 0x6c, 0x6f, 0x62,
+    0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x0a,
+    0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x30,
+    0x37, 0x31, 0x30, 0x38, 0x39, 0x30, 0x38, 0x38, 0x30, 0x33, 0x36, 0x35,
+    0x31, 0x35, 0x30, 0x39, 0x36, 0x39, 0x32, 0x39, 0x38, 0x30, 0x31, 0x32,
+    0x34, 0x32, 0x33, 0x33, 0x37, 0x34, 0x35, 0x30, 0x31, 0x34, 0x39, 0x35,
+    0x37, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x31, 0x3a,
+    0x30, 0x62, 0x3a, 0x34, 0x34, 0x3a, 0x62, 0x33, 0x3a, 0x63, 0x61, 0x3a,
+    0x31, 0x30, 0x3a, 0x64, 0x38, 0x3a, 0x30, 0x30, 0x3a, 0x36, 0x65, 0x3a,
+    0x39, 0x64, 0x3a, 0x30, 0x66, 0x3a, 0x64, 0x38, 0x3a, 0x30, 0x66, 0x3a,
+    0x39, 0x32, 0x3a, 0x30, 0x61, 0x3a, 0x64, 0x31, 0x0a, 0x23, 0x20, 0x53,
+    0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x38, 0x3a, 0x30, 0x31, 0x3a, 0x38,
+    0x36, 0x3a, 0x64, 0x31, 0x3a, 0x65, 0x62, 0x3a, 0x39, 0x63, 0x3a, 0x38,
+    0x36, 0x3a, 0x61, 0x35, 0x3a, 0x34, 0x31, 0x3a, 0x30, 0x34, 0x3a, 0x63,
+    0x66, 0x3a, 0x33, 0x30, 0x3a, 0x35, 0x34, 0x3a, 0x66, 0x33, 0x3a, 0x34,
+    0x63, 0x3a, 0x35, 0x32, 0x3a, 0x62, 0x37, 0x3a, 0x65, 0x35, 0x3a, 0x35,
+    0x38, 0x3a, 0x63, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35,
+    0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x63, 0x65, 0x3a, 0x63, 0x64, 0x3a, 0x64, 0x63, 0x3a,
+    0x39, 0x30, 0x3a, 0x35, 0x30, 0x3a, 0x39, 0x39, 0x3a, 0x64, 0x38, 0x3a,
+    0x64, 0x61, 0x3a, 0x64, 0x66, 0x3a, 0x63, 0x35, 0x3a, 0x62, 0x31, 0x3a,
+    0x64, 0x32, 0x3a, 0x30, 0x39, 0x3a, 0x62, 0x37, 0x3a, 0x33, 0x37, 0x3a,
+    0x63, 0x62, 0x3a, 0x65, 0x32, 0x3a, 0x63, 0x31, 0x3a, 0x38, 0x63, 0x3a,
+    0x66, 0x62, 0x3a, 0x32, 0x63, 0x3a, 0x31, 0x30, 0x3a, 0x63, 0x30, 0x3a,
+    0x66, 0x66, 0x3a, 0x30, 0x62, 0x3a, 0x63, 0x66, 0x3a, 0x30, 0x64, 0x3a,
+    0x33, 0x32, 0x3a, 0x38, 0x36, 0x3a, 0x66, 0x63, 0x3a, 0x31, 0x61, 0x3a,
+    0x61, 0x32, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49,
+    0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54,
+    0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x4d,
+    0x44, 0x43, 0x43, 0x41, 0x78, 0x69, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41,
+    0x67, 0x49, 0x51, 0x55, 0x4a, 0x52, 0x73, 0x37, 0x42, 0x6a, 0x71, 0x31,
+    0x5a, 0x78, 0x4e, 0x31, 0x5a, 0x66, 0x76, 0x64, 0x59, 0x2b, 0x67, 0x72,
+    0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39,
+    0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a,
+    0x67, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x48, 0x6a, 0x41, 0x63,
+    0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x46, 0x58, 0x64, 0x33,
+    0x64, 0x79, 0x35, 0x34, 0x63, 0x6d, 0x46, 0x74, 0x63, 0x48, 0x4e, 0x6c,
+    0x59, 0x33, 0x56, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4c, 0x6d, 0x4e, 0x76,
+    0x62, 0x54, 0x45, 0x6b, 0x0a, 0x4d, 0x43, 0x49, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x43, 0x68, 0x4d, 0x62, 0x57, 0x46, 0x4a, 0x68, 0x62, 0x58, 0x41,
+    0x67, 0x55, 0x32, 0x56, 0x6a, 0x64, 0x58, 0x4a, 0x70, 0x64, 0x48, 0x6b,
+    0x67, 0x55, 0x32, 0x56, 0x79, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d,
+    0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d, 0x53, 0x30, 0x77, 0x4b, 0x77, 0x59,
+    0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x79, 0x52, 0x59, 0x0a, 0x55, 0x6d,
+    0x46, 0x74, 0x63, 0x43, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57,
+    0x77, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57,
+    0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58,
+    0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, 0x48, 0x68,
+    0x63, 0x4e, 0x4d, 0x44, 0x51, 0x78, 0x4d, 0x54, 0x41, 0x78, 0x4d, 0x54,
+    0x63, 0x78, 0x0a, 0x4e, 0x44, 0x41, 0x30, 0x57, 0x68, 0x63, 0x4e, 0x4d,
+    0x7a, 0x55, 0x77, 0x4d, 0x54, 0x41, 0x78, 0x4d, 0x44, 0x55, 0x7a, 0x4e,
+    0x7a, 0x45, 0x35, 0x57, 0x6a, 0x43, 0x42, 0x67, 0x6a, 0x45, 0x4c, 0x4d,
+    0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56,
+    0x56, 0x4d, 0x78, 0x48, 0x6a, 0x41, 0x63, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x73, 0x54, 0x46, 0x58, 0x64, 0x33, 0x0a, 0x64, 0x79, 0x35, 0x34,
+    0x63, 0x6d, 0x46, 0x74, 0x63, 0x48, 0x4e, 0x6c, 0x59, 0x33, 0x56, 0x79,
+    0x61, 0x58, 0x52, 0x35, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x54, 0x45, 0x6b,
+    0x4d, 0x43, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x62,
+    0x57, 0x46, 0x4a, 0x68, 0x62, 0x58, 0x41, 0x67, 0x55, 0x32, 0x56, 0x6a,
+    0x64, 0x58, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x55, 0x32, 0x56, 0x79,
+    0x0a, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d, 0x67, 0x53, 0x57, 0x35,
+    0x6a, 0x4d, 0x53, 0x30, 0x77, 0x4b, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x44, 0x45, 0x79, 0x52, 0x59, 0x55, 0x6d, 0x46, 0x74, 0x63, 0x43, 0x42,
+    0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x77, 0x67, 0x51, 0x32, 0x56,
+    0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c,
+    0x76, 0x62, 0x69, 0x42, 0x42, 0x0a, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33,
+    0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4d, 0x41,
+    0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51,
+    0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77,
+    0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51,
+    0x43, 0x59, 0x4a, 0x42, 0x36, 0x39, 0x46, 0x62, 0x53, 0x36, 0x0a, 0x33,
+    0x38, 0x65, 0x4d, 0x70, 0x53, 0x65, 0x32, 0x4f, 0x41, 0x74, 0x70, 0x38,
+    0x37, 0x5a, 0x4f, 0x71, 0x43, 0x77, 0x75, 0x49, 0x52, 0x31, 0x63, 0x52,
+    0x4e, 0x38, 0x68, 0x58, 0x58, 0x34, 0x6a, 0x64, 0x50, 0x35, 0x65, 0x66,
+    0x72, 0x52, 0x4b, 0x74, 0x36, 0x61, 0x74, 0x48, 0x36, 0x37, 0x67, 0x42,
+    0x68, 0x62, 0x69, 0x6d, 0x31, 0x76, 0x5a, 0x5a, 0x33, 0x52, 0x72, 0x58,
+    0x59, 0x43, 0x50, 0x0a, 0x4b, 0x5a, 0x32, 0x47, 0x47, 0x39, 0x6d, 0x63,
+    0x44, 0x5a, 0x68, 0x74, 0x64, 0x68, 0x41, 0x6f, 0x57, 0x4f, 0x52, 0x6c,
+    0x73, 0x48, 0x39, 0x4b, 0x6d, 0x48, 0x6d, 0x66, 0x34, 0x4d, 0x4d, 0x78,
+    0x66, 0x6f, 0x41, 0x72, 0x74, 0x59, 0x7a, 0x41, 0x51, 0x44, 0x73, 0x52,
+    0x68, 0x74, 0x44, 0x4c, 0x6f, 0x6f, 0x59, 0x32, 0x59, 0x4b, 0x54, 0x56,
+    0x4d, 0x49, 0x4a, 0x74, 0x32, 0x57, 0x37, 0x51, 0x0a, 0x44, 0x78, 0x49,
+    0x45, 0x4d, 0x35, 0x64, 0x66, 0x54, 0x32, 0x46, 0x61, 0x38, 0x4f, 0x54,
+    0x35, 0x6b, 0x61, 0x76, 0x6e, 0x48, 0x54, 0x75, 0x38, 0x36, 0x4d, 0x2f,
+    0x30, 0x61, 0x79, 0x30, 0x30, 0x66, 0x4f, 0x4a, 0x49, 0x59, 0x52, 0x79,
+    0x4f, 0x38, 0x32, 0x46, 0x45, 0x7a, 0x47, 0x2b, 0x67, 0x53, 0x71, 0x6d,
+    0x55, 0x73, 0x45, 0x33, 0x61, 0x35, 0x36, 0x6b, 0x30, 0x65, 0x6e, 0x49,
+    0x34, 0x0a, 0x71, 0x45, 0x48, 0x4d, 0x50, 0x4a, 0x51, 0x52, 0x66, 0x65,
+    0x76, 0x49, 0x70, 0x6f, 0x79, 0x33, 0x68, 0x73, 0x76, 0x4b, 0x4d, 0x7a,
+    0x76, 0x5a, 0x50, 0x54, 0x65, 0x4c, 0x2b, 0x33, 0x6f, 0x2b, 0x68, 0x69,
+    0x7a, 0x6e, 0x63, 0x39, 0x63, 0x4b, 0x56, 0x36, 0x78, 0x6b, 0x6d, 0x78,
+    0x6e, 0x72, 0x39, 0x41, 0x38, 0x45, 0x43, 0x49, 0x71, 0x73, 0x41, 0x78,
+    0x63, 0x5a, 0x5a, 0x50, 0x52, 0x61, 0x0a, 0x4a, 0x53, 0x4b, 0x4e, 0x4e,
+    0x43, 0x79, 0x79, 0x39, 0x6d, 0x67, 0x64, 0x45, 0x6d, 0x33, 0x54, 0x69,
+    0x68, 0x34, 0x55, 0x32, 0x73, 0x53, 0x50, 0x70, 0x75, 0x49, 0x6a, 0x68,
+    0x64, 0x56, 0x36, 0x44, 0x62, 0x31, 0x71, 0x34, 0x4f, 0x6e, 0x73, 0x37,
+    0x42, 0x65, 0x37, 0x51, 0x68, 0x74, 0x6e, 0x71, 0x69, 0x58, 0x74, 0x52,
+    0x59, 0x4d, 0x68, 0x2f, 0x4d, 0x48, 0x4a, 0x66, 0x4e, 0x56, 0x69, 0x0a,
+    0x50, 0x76, 0x72, 0x79, 0x78, 0x53, 0x33, 0x54, 0x2f, 0x64, 0x52, 0x6c,
+    0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x67, 0x5a, 0x38, 0x77,
+    0x67, 0x5a, 0x77, 0x77, 0x45, 0x77, 0x59, 0x4a, 0x4b, 0x77, 0x59, 0x42,
+    0x42, 0x41, 0x47, 0x43, 0x4e, 0x78, 0x51, 0x43, 0x42, 0x41, 0x59, 0x65,
+    0x42, 0x41, 0x42, 0x44, 0x41, 0x45, 0x45, 0x77, 0x43, 0x77, 0x59, 0x44,
+    0x56, 0x52, 0x30, 0x50, 0x0a, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x47,
+    0x47, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45,
+    0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38,
+    0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59,
+    0x45, 0x46, 0x4d, 0x5a, 0x50, 0x6f, 0x6a, 0x30, 0x47, 0x59, 0x34, 0x51,
+    0x4a, 0x6e, 0x4d, 0x35, 0x69, 0x35, 0x41, 0x53, 0x73, 0x0a, 0x6a, 0x56,
+    0x79, 0x31, 0x36, 0x62, 0x59, 0x62, 0x4d, 0x44, 0x59, 0x47, 0x41, 0x31,
+    0x55, 0x64, 0x48, 0x77, 0x51, 0x76, 0x4d, 0x43, 0x30, 0x77, 0x4b, 0x36,
+    0x41, 0x70, 0x6f, 0x43, 0x65, 0x47, 0x4a, 0x57, 0x68, 0x30, 0x64, 0x48,
+    0x41, 0x36, 0x4c, 0x79, 0x39, 0x6a, 0x63, 0x6d, 0x77, 0x75, 0x65, 0x48,
+    0x4a, 0x68, 0x62, 0x58, 0x42, 0x7a, 0x5a, 0x57, 0x4e, 0x31, 0x63, 0x6d,
+    0x6c, 0x30, 0x0a, 0x65, 0x53, 0x35, 0x6a, 0x62, 0x32, 0x30, 0x76, 0x57,
+    0x45, 0x64, 0x44, 0x51, 0x53, 0x35, 0x6a, 0x63, 0x6d, 0x77, 0x77, 0x45,
+    0x41, 0x59, 0x4a, 0x4b, 0x77, 0x59, 0x42, 0x42, 0x41, 0x47, 0x43, 0x4e,
+    0x78, 0x55, 0x42, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x45, 0x77, 0x44,
+    0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41,
+    0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x0a, 0x67, 0x67, 0x45, 0x42,
+    0x41, 0x4a, 0x45, 0x56, 0x4f, 0x51, 0x4d, 0x42, 0x47, 0x32, 0x66, 0x37,
+    0x53, 0x68, 0x7a, 0x35, 0x43, 0x6d, 0x42, 0x62, 0x6f, 0x64, 0x70, 0x4e,
+    0x6c, 0x32, 0x4c, 0x35, 0x4a, 0x46, 0x4d, 0x6e, 0x31, 0x34, 0x4a, 0x6b,
+    0x54, 0x70, 0x41, 0x75, 0x77, 0x30, 0x6b, 0x62, 0x4b, 0x35, 0x72, 0x63,
+    0x2f, 0x4b, 0x68, 0x34, 0x5a, 0x7a, 0x58, 0x78, 0x48, 0x66, 0x41, 0x52,
+    0x0a, 0x76, 0x62, 0x64, 0x49, 0x34, 0x78, 0x44, 0x32, 0x44, 0x64, 0x38,
+    0x2f, 0x30, 0x73, 0x6d, 0x32, 0x71, 0x6c, 0x57, 0x6b, 0x53, 0x4c, 0x6f,
+    0x43, 0x32, 0x39, 0x35, 0x5a, 0x4c, 0x68, 0x56, 0x62, 0x4f, 0x35, 0x30,
+    0x57, 0x66, 0x55, 0x66, 0x58, 0x4e, 0x2b, 0x70, 0x66, 0x54, 0x58, 0x59,
+    0x53, 0x4e, 0x72, 0x73, 0x66, 0x31, 0x36, 0x47, 0x42, 0x42, 0x45, 0x59,
+    0x67, 0x6f, 0x79, 0x78, 0x74, 0x0a, 0x71, 0x5a, 0x34, 0x42, 0x66, 0x6a,
+    0x38, 0x70, 0x7a, 0x67, 0x43, 0x54, 0x33, 0x2f, 0x33, 0x4a, 0x6b, 0x6e,
+    0x4f, 0x4a, 0x69, 0x57, 0x53, 0x65, 0x35, 0x79, 0x76, 0x6b, 0x48, 0x4a,
+    0x45, 0x73, 0x30, 0x72, 0x6e, 0x4f, 0x66, 0x63, 0x35, 0x76, 0x4d, 0x5a,
+    0x6e, 0x54, 0x35, 0x72, 0x37, 0x53, 0x48, 0x70, 0x44, 0x77, 0x43, 0x52,
+    0x52, 0x35, 0x58, 0x43, 0x4f, 0x72, 0x54, 0x64, 0x4c, 0x61, 0x0a, 0x49,
+    0x52, 0x39, 0x4e, 0x6d, 0x58, 0x6d, 0x64, 0x34, 0x63, 0x38, 0x6e, 0x6e,
+    0x78, 0x43, 0x62, 0x48, 0x49, 0x67, 0x4e, 0x73, 0x49, 0x70, 0x6b, 0x51,
+    0x54, 0x47, 0x34, 0x44, 0x6d, 0x79, 0x51, 0x4a, 0x4b, 0x53, 0x62, 0x58,
+    0x48, 0x47, 0x50, 0x75, 0x72, 0x74, 0x2b, 0x48, 0x42, 0x76, 0x62, 0x61,
+    0x6f, 0x41, 0x50, 0x49, 0x62, 0x7a, 0x70, 0x32, 0x36, 0x61, 0x33, 0x51,
+    0x50, 0x53, 0x79, 0x0a, 0x69, 0x36, 0x6d, 0x78, 0x35, 0x4f, 0x2b, 0x61,
+    0x47, 0x74, 0x41, 0x39, 0x61, 0x5a, 0x6e, 0x75, 0x71, 0x43, 0x69, 0x6a,
+    0x34, 0x54, 0x79, 0x7a, 0x38, 0x4c, 0x49, 0x52, 0x6e, 0x4d, 0x39, 0x38,
+    0x51, 0x4f, 0x62, 0x64, 0x35, 0x30, 0x4e, 0x39, 0x6f, 0x74, 0x67, 0x36,
+    0x74, 0x61, 0x6d, 0x4e, 0x38, 0x6a, 0x53, 0x5a, 0x78, 0x4e, 0x51, 0x51,
+    0x34, 0x51, 0x62, 0x39, 0x43, 0x59, 0x51, 0x51, 0x0a, 0x4f, 0x2b, 0x37,
+    0x45, 0x54, 0x50, 0x54, 0x73, 0x4a, 0x33, 0x78, 0x43, 0x77, 0x6e, 0x52,
+    0x38, 0x67, 0x6f, 0x6f, 0x4a, 0x79, 0x62, 0x51, 0x44, 0x4a, 0x62, 0x77,
+    0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65,
+    0x72, 0x3a, 0x20, 0x4f, 0x3d, 0x54, 0x68, 0x65, 0x20, 0x47, 0x6f, 0x20,
+    0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2c,
+    0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x47, 0x6f, 0x20,
+    0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20,
+    0x32, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+    0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+    0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a,
+    0x20, 0x4f, 0x3d, 0x54, 0x68, 0x65, 0x20, 0x47, 0x6f, 0x20, 0x44, 0x61,
+    0x64, 0x64, 0x79, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2c, 0x20, 0x49,
+    0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x47, 0x6f, 0x20, 0x44, 0x61,
+    0x64, 0x64, 0x79, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20,
+    0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+    0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a,
+    0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x6f,
+    0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73,
+    0x20, 0x32, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72,
+    0x69, 0x61, 0x6c, 0x3a, 0x20, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x39, 0x31, 0x3a, 0x64, 0x65, 0x3a, 0x30, 0x36, 0x3a, 0x32,
+    0x35, 0x3a, 0x61, 0x62, 0x3a, 0x64, 0x61, 0x3a, 0x66, 0x64, 0x3a, 0x33,
+    0x32, 0x3a, 0x31, 0x37, 0x3a, 0x30, 0x63, 0x3a, 0x62, 0x62, 0x3a, 0x32,
+    0x35, 0x3a, 0x31, 0x37, 0x3a, 0x32, 0x61, 0x3a, 0x38, 0x34, 0x3a, 0x36,
+    0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x37,
+    0x3a, 0x39, 0x36, 0x3a, 0x62, 0x61, 0x3a, 0x65, 0x36, 0x3a, 0x33, 0x66,
+    0x3a, 0x31, 0x38, 0x3a, 0x30, 0x31, 0x3a, 0x65, 0x32, 0x3a, 0x37, 0x37,
+    0x3a, 0x32, 0x36, 0x3a, 0x31, 0x62, 0x3a, 0x61, 0x30, 0x3a, 0x64, 0x37,
+    0x3a, 0x37, 0x37, 0x3a, 0x37, 0x30, 0x3a, 0x30, 0x32, 0x3a, 0x38, 0x66,
+    0x3a, 0x32, 0x30, 0x3a, 0x65, 0x65, 0x3a, 0x65, 0x34, 0x0a, 0x23, 0x20,
+    0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x33, 0x3a, 0x38,
+    0x34, 0x3a, 0x36, 0x62, 0x3a, 0x66, 0x32, 0x3a, 0x34, 0x62, 0x3a, 0x39,
+    0x65, 0x3a, 0x39, 0x33, 0x3a, 0x63, 0x61, 0x3a, 0x36, 0x34, 0x3a, 0x32,
+    0x37, 0x3a, 0x34, 0x63, 0x3a, 0x30, 0x65, 0x3a, 0x63, 0x36, 0x3a, 0x37,
+    0x63, 0x3a, 0x31, 0x65, 0x3a, 0x63, 0x63, 0x3a, 0x35, 0x65, 0x3a, 0x30,
+    0x32, 0x3a, 0x34, 0x66, 0x3a, 0x66, 0x63, 0x3a, 0x61, 0x63, 0x3a, 0x64,
+    0x32, 0x3a, 0x64, 0x37, 0x3a, 0x34, 0x30, 0x3a, 0x31, 0x39, 0x3a, 0x33,
+    0x35, 0x3a, 0x30, 0x65, 0x3a, 0x38, 0x31, 0x3a, 0x66, 0x65, 0x3a, 0x35,
+    0x34, 0x3a, 0x36, 0x61, 0x3a, 0x65, 0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49,
+    0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a,
+    0x4d, 0x49, 0x49, 0x45, 0x41, 0x44, 0x43, 0x43, 0x41, 0x75, 0x69, 0x67,
+    0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x44, 0x41, 0x4e,
+    0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42,
+    0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x6a, 0x4d, 0x51, 0x73, 0x77,
+    0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56,
+    0x55, 0x7a, 0x45, 0x68, 0x0a, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x43, 0x68, 0x4d, 0x59, 0x56, 0x47, 0x68, 0x6c, 0x49, 0x45, 0x64,
+    0x76, 0x49, 0x45, 0x52, 0x68, 0x5a, 0x47, 0x52, 0x35, 0x49, 0x45, 0x64,
+    0x79, 0x62, 0x33, 0x56, 0x77, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d,
+    0x75, 0x4d, 0x54, 0x45, 0x77, 0x4c, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x4c, 0x45, 0x79, 0x68, 0x48, 0x62, 0x79, 0x42, 0x45, 0x0a, 0x59, 0x57,
+    0x52, 0x6b, 0x65, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79,
+    0x41, 0x79, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d,
+    0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58,
+    0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x42,
+    0x34, 0x58, 0x44, 0x54, 0x41, 0x30, 0x4d, 0x44, 0x59, 0x79, 0x4f, 0x54,
+    0x45, 0x33, 0x0a, 0x4d, 0x44, 0x59, 0x79, 0x4d, 0x46, 0x6f, 0x58, 0x44,
+    0x54, 0x4d, 0x30, 0x4d, 0x44, 0x59, 0x79, 0x4f, 0x54, 0x45, 0x33, 0x4d,
+    0x44, 0x59, 0x79, 0x4d, 0x46, 0x6f, 0x77, 0x59, 0x7a, 0x45, 0x4c, 0x4d,
+    0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56,
+    0x56, 0x4d, 0x78, 0x49, 0x54, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x6f, 0x54, 0x47, 0x46, 0x52, 0x6f, 0x0a, 0x5a, 0x53, 0x42, 0x48,
+    0x62, 0x79, 0x42, 0x45, 0x59, 0x57, 0x52, 0x6b, 0x65, 0x53, 0x42, 0x48,
+    0x63, 0x6d, 0x39, 0x31, 0x63, 0x43, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a,
+    0x4c, 0x6a, 0x45, 0x78, 0x4d, 0x43, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x43, 0x78, 0x4d, 0x6f, 0x52, 0x32, 0x38, 0x67, 0x52, 0x47, 0x46, 0x6b,
+    0x5a, 0x48, 0x6b, 0x67, 0x51, 0x32, 0x78, 0x68, 0x63, 0x33, 0x4d, 0x67,
+    0x0a, 0x4d, 0x69, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a,
+    0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46,
+    0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, 0x43,
+    0x43, 0x41, 0x53, 0x41, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a,
+    0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41,
+    0x44, 0x67, 0x67, 0x45, 0x4e, 0x0a, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51,
+    0x67, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4e, 0x36, 0x64, 0x31, 0x2b,
+    0x70, 0x58, 0x47, 0x45, 0x6d, 0x68, 0x57, 0x2b, 0x76, 0x58, 0x58, 0x30,
+    0x69, 0x47, 0x36, 0x72, 0x37, 0x64, 0x2f, 0x2b, 0x54, 0x76, 0x5a, 0x78,
+    0x7a, 0x30, 0x5a, 0x57, 0x69, 0x7a, 0x56, 0x33, 0x47, 0x67, 0x58, 0x6e,
+    0x65, 0x37, 0x37, 0x5a, 0x74, 0x4a, 0x36, 0x58, 0x43, 0x41, 0x0a, 0x50,
+    0x56, 0x59, 0x59, 0x59, 0x77, 0x68, 0x76, 0x32, 0x76, 0x4c, 0x4d, 0x30,
+    0x44, 0x39, 0x2f, 0x41, 0x6c, 0x51, 0x69, 0x56, 0x42, 0x44, 0x59, 0x73,
+    0x6f, 0x48, 0x55, 0x77, 0x48, 0x55, 0x39, 0x53, 0x33, 0x2f, 0x48, 0x64,
+    0x38, 0x4d, 0x2b, 0x65, 0x4b, 0x73, 0x61, 0x41, 0x37, 0x55, 0x67, 0x61,
+    0x79, 0x39, 0x71, 0x4b, 0x37, 0x48, 0x46, 0x69, 0x48, 0x37, 0x45, 0x75,
+    0x78, 0x36, 0x77, 0x0a, 0x77, 0x64, 0x68, 0x46, 0x4a, 0x32, 0x2b, 0x71,
+    0x4e, 0x31, 0x6a, 0x33, 0x68, 0x79, 0x62, 0x58, 0x32, 0x43, 0x33, 0x32,
+    0x71, 0x52, 0x65, 0x33, 0x48, 0x33, 0x49, 0x32, 0x54, 0x71, 0x59, 0x58,
+    0x50, 0x32, 0x57, 0x59, 0x6b, 0x74, 0x73, 0x71, 0x62, 0x6c, 0x32, 0x69,
+    0x2f, 0x6f, 0x6a, 0x67, 0x43, 0x39, 0x35, 0x2f, 0x35, 0x59, 0x30, 0x56,
+    0x34, 0x65, 0x76, 0x4c, 0x4f, 0x74, 0x58, 0x69, 0x0a, 0x45, 0x71, 0x49,
+    0x54, 0x4c, 0x64, 0x69, 0x4f, 0x72, 0x31, 0x38, 0x53, 0x50, 0x61, 0x41,
+    0x49, 0x42, 0x51, 0x69, 0x32, 0x58, 0x4b, 0x56, 0x6c, 0x4f, 0x41, 0x52,
+    0x46, 0x6d, 0x52, 0x36, 0x6a, 0x59, 0x47, 0x42, 0x30, 0x78, 0x55, 0x47,
+    0x6c, 0x63, 0x6d, 0x49, 0x62, 0x59, 0x73, 0x55, 0x66, 0x62, 0x31, 0x38,
+    0x61, 0x51, 0x72, 0x34, 0x43, 0x55, 0x57, 0x57, 0x6f, 0x72, 0x69, 0x4d,
+    0x59, 0x0a, 0x61, 0x76, 0x78, 0x34, 0x41, 0x36, 0x6c, 0x4e, 0x66, 0x34,
+    0x44, 0x44, 0x2b, 0x71, 0x74, 0x61, 0x2f, 0x4b, 0x46, 0x41, 0x70, 0x4d,
+    0x6f, 0x5a, 0x46, 0x76, 0x36, 0x79, 0x79, 0x4f, 0x39, 0x65, 0x63, 0x77,
+    0x33, 0x75, 0x64, 0x37, 0x32, 0x61, 0x39, 0x6e, 0x6d, 0x59, 0x76, 0x4c,
+    0x45, 0x48, 0x5a, 0x36, 0x49, 0x56, 0x44, 0x64, 0x32, 0x67, 0x57, 0x4d,
+    0x5a, 0x45, 0x65, 0x77, 0x6f, 0x2b, 0x0a, 0x59, 0x69, 0x68, 0x66, 0x75,
+    0x6b, 0x45, 0x48, 0x55, 0x31, 0x6a, 0x50, 0x45, 0x58, 0x34, 0x34, 0x64,
+    0x4d, 0x58, 0x34, 0x2f, 0x37, 0x56, 0x70, 0x6b, 0x49, 0x2b, 0x45, 0x64,
+    0x4f, 0x71, 0x58, 0x47, 0x36, 0x38, 0x43, 0x41, 0x51, 0x4f, 0x6a, 0x67,
+    0x63, 0x41, 0x77, 0x67, 0x62, 0x30, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56,
+    0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4e, 0x4c, 0x45, 0x0a,
+    0x73, 0x4e, 0x4b, 0x52, 0x31, 0x45, 0x77, 0x52, 0x63, 0x62, 0x4e, 0x68,
+    0x79, 0x7a, 0x32, 0x68, 0x2f, 0x74, 0x32, 0x6f, 0x61, 0x74, 0x54, 0x6a,
+    0x4d, 0x49, 0x47, 0x4e, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45,
+    0x67, 0x59, 0x55, 0x77, 0x67, 0x59, 0x4b, 0x41, 0x46, 0x4e, 0x4c, 0x45,
+    0x73, 0x4e, 0x4b, 0x52, 0x31, 0x45, 0x77, 0x52, 0x63, 0x62, 0x4e, 0x68,
+    0x79, 0x7a, 0x32, 0x68, 0x0a, 0x2f, 0x74, 0x32, 0x6f, 0x61, 0x74, 0x54,
+    0x6a, 0x6f, 0x57, 0x65, 0x6b, 0x5a, 0x54, 0x42, 0x6a, 0x4d, 0x51, 0x73,
+    0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a,
+    0x56, 0x55, 0x7a, 0x45, 0x68, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x43, 0x68, 0x4d, 0x59, 0x56, 0x47, 0x68, 0x6c, 0x49, 0x45, 0x64,
+    0x76, 0x49, 0x45, 0x52, 0x68, 0x5a, 0x47, 0x52, 0x35, 0x0a, 0x49, 0x45,
+    0x64, 0x79, 0x62, 0x33, 0x56, 0x77, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d,
+    0x4d, 0x75, 0x4d, 0x54, 0x45, 0x77, 0x4c, 0x77, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x4c, 0x45, 0x79, 0x68, 0x48, 0x62, 0x79, 0x42, 0x45, 0x59, 0x57,
+    0x52, 0x6b, 0x65, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79,
+    0x41, 0x79, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d,
+    0x6c, 0x6a, 0x0a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51,
+    0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x67,
+    0x67, 0x45, 0x41, 0x4d, 0x41, 0x77, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45,
+    0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x44,
+    0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41,
+    0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x0a, 0x67, 0x67, 0x45, 0x42,
+    0x41, 0x44, 0x4a, 0x4c, 0x38, 0x37, 0x4c, 0x4b, 0x50, 0x70, 0x48, 0x38,
+    0x45, 0x73, 0x61, 0x68, 0x42, 0x34, 0x79, 0x4f, 0x64, 0x36, 0x41, 0x7a,
+    0x42, 0x68, 0x52, 0x63, 0x6b, 0x42, 0x34, 0x59, 0x39, 0x77, 0x69, 0x6d,
+    0x50, 0x51, 0x6f, 0x5a, 0x2b, 0x59, 0x65, 0x41, 0x45, 0x57, 0x35, 0x70,
+    0x35, 0x4a, 0x59, 0x58, 0x4d, 0x50, 0x38, 0x30, 0x6b, 0x57, 0x4e, 0x79,
+    0x0a, 0x4f, 0x4f, 0x37, 0x4d, 0x48, 0x41, 0x47, 0x6a, 0x48, 0x5a, 0x51,
+    0x6f, 0x70, 0x44, 0x48, 0x32, 0x65, 0x73, 0x52, 0x55, 0x31, 0x2f, 0x62,
+    0x6c, 0x4d, 0x56, 0x67, 0x44, 0x6f, 0x73, 0x7a, 0x4f, 0x59, 0x74, 0x75,
+    0x55, 0x52, 0x58, 0x4f, 0x31, 0x76, 0x30, 0x58, 0x4a, 0x4a, 0x4c, 0x58,
+    0x56, 0x67, 0x67, 0x4b, 0x74, 0x49, 0x33, 0x6c, 0x70, 0x6a, 0x62, 0x69,
+    0x32, 0x54, 0x63, 0x37, 0x50, 0x0a, 0x54, 0x4d, 0x6f, 0x7a, 0x49, 0x2b,
+    0x67, 0x63, 0x69, 0x4b, 0x71, 0x64, 0x69, 0x30, 0x46, 0x75, 0x46, 0x73,
+    0x6b, 0x67, 0x35, 0x59, 0x6d, 0x65, 0x7a, 0x54, 0x76, 0x61, 0x63, 0x50,
+    0x64, 0x2b, 0x6d, 0x53, 0x59, 0x67, 0x46, 0x46, 0x51, 0x6c, 0x71, 0x32,
+    0x35, 0x7a, 0x68, 0x65, 0x61, 0x62, 0x49, 0x5a, 0x30, 0x4b, 0x62, 0x49,
+    0x49, 0x4f, 0x71, 0x50, 0x6a, 0x43, 0x44, 0x50, 0x6f, 0x51, 0x0a, 0x48,
+    0x6d, 0x79, 0x57, 0x37, 0x34, 0x63, 0x4e, 0x78, 0x41, 0x39, 0x68, 0x69,
+    0x36, 0x33, 0x75, 0x67, 0x79, 0x75, 0x56, 0x2b, 0x49, 0x36, 0x53, 0x68,
+    0x48, 0x49, 0x35, 0x36, 0x79, 0x44, 0x71, 0x67, 0x2b, 0x32, 0x44, 0x7a,
+    0x5a, 0x64, 0x75, 0x43, 0x4c, 0x7a, 0x72, 0x54, 0x69, 0x61, 0x32, 0x63,
+    0x79, 0x76, 0x6b, 0x30, 0x2f, 0x5a, 0x4d, 0x2f, 0x69, 0x5a, 0x78, 0x34,
+    0x6d, 0x45, 0x52, 0x0a, 0x64, 0x45, 0x72, 0x2f, 0x56, 0x78, 0x71, 0x48,
+    0x44, 0x33, 0x56, 0x49, 0x4c, 0x73, 0x39, 0x52, 0x61, 0x52, 0x65, 0x67,
+    0x41, 0x68, 0x4a, 0x68, 0x6c, 0x64, 0x58, 0x52, 0x51, 0x4c, 0x49, 0x51,
+    0x54, 0x4f, 0x37, 0x45, 0x72, 0x42, 0x42, 0x44, 0x70, 0x71, 0x57, 0x65,
+    0x43, 0x74, 0x57, 0x56, 0x59, 0x70, 0x6f, 0x4e, 0x7a, 0x34, 0x69, 0x43,
+    0x78, 0x54, 0x49, 0x4d, 0x35, 0x43, 0x75, 0x66, 0x0a, 0x52, 0x65, 0x59,
+    0x4e, 0x6e, 0x79, 0x69, 0x63, 0x73, 0x62, 0x6b, 0x71, 0x57, 0x6c, 0x65,
+    0x74, 0x4e, 0x77, 0x2b, 0x76, 0x48, 0x58, 0x2f, 0x62, 0x76, 0x5a, 0x38,
+    0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65,
+    0x72, 0x3a, 0x20, 0x4f, 0x3d, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65,
+    0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67,
+    0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55,
+    0x3d, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x43,
+    0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+    0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74,
+    0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62,
+    0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x4f, 0x3d, 0x53, 0x74, 0x61, 0x72,
+    0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f,
+    0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+    0x20, 0x4f, 0x55, 0x3d, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c,
+    0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, 0x65,
+    0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+    0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20,
+    0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x53, 0x74, 0x61, 0x72,
+    0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20,
+    0x32, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69,
+    0x61, 0x6c, 0x3a, 0x20, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x33, 0x32, 0x3a, 0x34, 0x61, 0x3a, 0x34, 0x62, 0x3a, 0x62, 0x62,
+    0x3a, 0x63, 0x38, 0x3a, 0x36, 0x33, 0x3a, 0x36, 0x39, 0x3a, 0x39, 0x62,
+    0x3a, 0x62, 0x65, 0x3a, 0x37, 0x34, 0x3a, 0x39, 0x61, 0x3a, 0x63, 0x36,
+    0x3a, 0x64, 0x64, 0x3a, 0x31, 0x64, 0x3a, 0x34, 0x36, 0x3a, 0x32, 0x34,
+    0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x64, 0x3a,
+    0x37, 0x65, 0x3a, 0x31, 0x63, 0x3a, 0x32, 0x38, 0x3a, 0x62, 0x30, 0x3a,
+    0x36, 0x34, 0x3a, 0x65, 0x66, 0x3a, 0x38, 0x66, 0x3a, 0x36, 0x30, 0x3a,
+    0x30, 0x33, 0x3a, 0x34, 0x30, 0x3a, 0x32, 0x30, 0x3a, 0x31, 0x34, 0x3a,
+    0x63, 0x33, 0x3a, 0x64, 0x30, 0x3a, 0x65, 0x33, 0x3a, 0x33, 0x37, 0x3a,
+    0x30, 0x65, 0x3a, 0x62, 0x35, 0x3a, 0x38, 0x61, 0x0a, 0x23, 0x20, 0x53,
+    0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x34, 0x3a, 0x36, 0x35,
+    0x3a, 0x66, 0x61, 0x3a, 0x32, 0x30, 0x3a, 0x35, 0x33, 0x3a, 0x39, 0x37,
+    0x3a, 0x62, 0x38, 0x3a, 0x37, 0x36, 0x3a, 0x66, 0x61, 0x3a, 0x61, 0x36,
+    0x3a, 0x66, 0x30, 0x3a, 0x61, 0x39, 0x3a, 0x39, 0x35, 0x3a, 0x38, 0x65,
+    0x3a, 0x35, 0x35, 0x3a, 0x39, 0x30, 0x3a, 0x65, 0x34, 0x3a, 0x30, 0x66,
+    0x3a, 0x63, 0x63, 0x3a, 0x37, 0x66, 0x3a, 0x61, 0x61, 0x3a, 0x34, 0x66,
+    0x3a, 0x62, 0x37, 0x3a, 0x63, 0x32, 0x3a, 0x63, 0x38, 0x3a, 0x36, 0x37,
+    0x3a, 0x37, 0x35, 0x3a, 0x32, 0x31, 0x3a, 0x66, 0x62, 0x3a, 0x35, 0x66,
+    0x3a, 0x62, 0x36, 0x3a, 0x35, 0x38, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d,
+    0x49, 0x49, 0x45, 0x44, 0x7a, 0x43, 0x43, 0x41, 0x76, 0x65, 0x67, 0x41,
+    0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x44, 0x41, 0x4e, 0x42,
+    0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41,
+    0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x6f, 0x4d, 0x51, 0x73, 0x77, 0x43,
+    0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55,
+    0x7a, 0x45, 0x6c, 0x0a, 0x4d, 0x43, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x43, 0x68, 0x4d, 0x63, 0x55, 0x33, 0x52, 0x68, 0x63, 0x6d, 0x5a, 0x70,
+    0x5a, 0x57, 0x78, 0x6b, 0x49, 0x46, 0x52, 0x6c, 0x59, 0x32, 0x68, 0x75,
+    0x62, 0x32, 0x78, 0x76, 0x5a, 0x32, 0x6c, 0x6c, 0x63, 0x79, 0x77, 0x67,
+    0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x79, 0x4d, 0x44, 0x41, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x70, 0x0a, 0x55, 0x33, 0x52,
+    0x68, 0x63, 0x6d, 0x5a, 0x70, 0x5a, 0x57, 0x78, 0x6b, 0x49, 0x45, 0x4e,
+    0x73, 0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44, 0x49, 0x67, 0x51, 0x32, 0x56,
+    0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c,
+    0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a,
+    0x70, 0x64, 0x48, 0x6b, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x51,
+    0x77, 0x0a, 0x4e, 0x6a, 0x49, 0x35, 0x4d, 0x54, 0x63, 0x7a, 0x4f, 0x54,
+    0x45, 0x32, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x51, 0x77, 0x4e, 0x6a,
+    0x49, 0x35, 0x4d, 0x54, 0x63, 0x7a, 0x4f, 0x54, 0x45, 0x32, 0x57, 0x6a,
+    0x42, 0x6f, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x6c, 0x4d, 0x43,
+    0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x43, 0x68, 0x4d, 0x63, 0x55,
+    0x33, 0x52, 0x68, 0x63, 0x6d, 0x5a, 0x70, 0x5a, 0x57, 0x78, 0x6b, 0x49,
+    0x46, 0x52, 0x6c, 0x59, 0x32, 0x68, 0x75, 0x62, 0x32, 0x78, 0x76, 0x5a,
+    0x32, 0x6c, 0x6c, 0x63, 0x79, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c,
+    0x6a, 0x45, 0x79, 0x4d, 0x44, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43,
+    0x78, 0x4d, 0x70, 0x55, 0x33, 0x52, 0x68, 0x63, 0x6d, 0x5a, 0x70, 0x0a,
+    0x5a, 0x57, 0x78, 0x6b, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a,
+    0x49, 0x44, 0x49, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d,
+    0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42,
+    0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77,
+    0x67, 0x67, 0x45, 0x67, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47,
+    0x53, 0x49, 0x62, 0x33, 0x0a, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55,
+    0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x51, 0x41, 0x77, 0x67, 0x67, 0x45,
+    0x49, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x43, 0x33, 0x4d, 0x73, 0x6a,
+    0x2b, 0x36, 0x58, 0x47, 0x6d, 0x42, 0x49, 0x57, 0x74, 0x44, 0x42, 0x46,
+    0x6b, 0x33, 0x38, 0x35, 0x4e, 0x37, 0x38, 0x67, 0x44, 0x47, 0x49, 0x63,
+    0x2f, 0x6f, 0x61, 0x76, 0x37, 0x50, 0x4b, 0x61, 0x66, 0x0a, 0x38, 0x4d,
+    0x4f, 0x68, 0x32, 0x74, 0x54, 0x59, 0x62, 0x69, 0x74, 0x54, 0x6b, 0x50,
+    0x73, 0x6b, 0x70, 0x44, 0x36, 0x45, 0x38, 0x4a, 0x37, 0x6f, 0x58, 0x2b,
+    0x7a, 0x6c, 0x4a, 0x30, 0x54, 0x31, 0x4b, 0x4b, 0x59, 0x2f, 0x65, 0x39,
+    0x37, 0x67, 0x4b, 0x76, 0x44, 0x49, 0x72, 0x31, 0x4d, 0x76, 0x6e, 0x73,
+    0x6f, 0x46, 0x41, 0x5a, 0x4d, 0x65, 0x6a, 0x32, 0x59, 0x63, 0x4f, 0x61,
+    0x64, 0x4e, 0x0a, 0x2b, 0x6c, 0x71, 0x32, 0x63, 0x77, 0x51, 0x6c, 0x5a,
+    0x75, 0x74, 0x33, 0x66, 0x2b, 0x64, 0x5a, 0x78, 0x6b, 0x71, 0x5a, 0x4a,
+    0x52, 0x52, 0x55, 0x36, 0x79, 0x62, 0x48, 0x38, 0x33, 0x38, 0x5a, 0x31,
+    0x54, 0x42, 0x77, 0x6a, 0x36, 0x2b, 0x77, 0x52, 0x69, 0x72, 0x2f, 0x72,
+    0x65, 0x73, 0x70, 0x37, 0x64, 0x65, 0x66, 0x71, 0x67, 0x53, 0x48, 0x6f,
+    0x39, 0x54, 0x35, 0x69, 0x61, 0x55, 0x30, 0x0a, 0x58, 0x39, 0x74, 0x44,
+    0x6b, 0x59, 0x49, 0x32, 0x32, 0x57, 0x59, 0x38, 0x73, 0x62, 0x69, 0x35,
+    0x67, 0x76, 0x32, 0x63, 0x4f, 0x6a, 0x34, 0x51, 0x79, 0x44, 0x76, 0x76,
+    0x42, 0x6d, 0x56, 0x6d, 0x65, 0x70, 0x73, 0x5a, 0x47, 0x44, 0x33, 0x2f,
+    0x63, 0x56, 0x45, 0x38, 0x4d, 0x43, 0x35, 0x66, 0x76, 0x6a, 0x31, 0x33,
+    0x63, 0x37, 0x4a, 0x64, 0x42, 0x6d, 0x7a, 0x44, 0x49, 0x31, 0x61, 0x61,
+    0x0a, 0x4b, 0x34, 0x55, 0x6d, 0x6b, 0x68, 0x79, 0x6e, 0x41, 0x72, 0x50,
+    0x6b, 0x50, 0x77, 0x32, 0x76, 0x43, 0x48, 0x6d, 0x43, 0x75, 0x44, 0x59,
+    0x39, 0x36, 0x70, 0x7a, 0x54, 0x4e, 0x62, 0x4f, 0x38, 0x61, 0x63, 0x72,
+    0x31, 0x7a, 0x4a, 0x33, 0x6f, 0x2f, 0x57, 0x53, 0x4e, 0x46, 0x34, 0x41,
+    0x7a, 0x62, 0x6c, 0x35, 0x4b, 0x58, 0x5a, 0x6e, 0x4a, 0x48, 0x6f, 0x65,
+    0x30, 0x6e, 0x52, 0x72, 0x41, 0x0a, 0x31, 0x57, 0x34, 0x54, 0x4e, 0x53,
+    0x4e, 0x65, 0x33, 0x35, 0x74, 0x66, 0x50, 0x65, 0x2f, 0x57, 0x39, 0x33,
+    0x62, 0x43, 0x36, 0x6a, 0x36, 0x37, 0x65, 0x41, 0x30, 0x63, 0x51, 0x6d,
+    0x64, 0x72, 0x42, 0x4e, 0x6a, 0x34, 0x31, 0x74, 0x70, 0x76, 0x69, 0x2f,
+    0x4a, 0x45, 0x6f, 0x41, 0x47, 0x72, 0x41, 0x67, 0x45, 0x44, 0x6f, 0x34,
+    0x48, 0x46, 0x4d, 0x49, 0x48, 0x43, 0x4d, 0x42, 0x30, 0x47, 0x0a, 0x41,
+    0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x53, 0x2f, 0x58,
+    0x37, 0x66, 0x52, 0x7a, 0x74, 0x30, 0x66, 0x68, 0x76, 0x52, 0x62, 0x56,
+    0x61, 0x7a, 0x63, 0x31, 0x78, 0x44, 0x43, 0x44, 0x71, 0x6d, 0x49, 0x35,
+    0x7a, 0x43, 0x42, 0x6b, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6a, 0x42,
+    0x49, 0x47, 0x4b, 0x4d, 0x49, 0x47, 0x48, 0x67, 0x42, 0x53, 0x2f, 0x58,
+    0x37, 0x66, 0x52, 0x0a, 0x7a, 0x74, 0x30, 0x66, 0x68, 0x76, 0x52, 0x62,
+    0x56, 0x61, 0x7a, 0x63, 0x31, 0x78, 0x44, 0x43, 0x44, 0x71, 0x6d, 0x49,
+    0x35, 0x36, 0x46, 0x73, 0x70, 0x47, 0x6f, 0x77, 0x61, 0x44, 0x45, 0x4c,
+    0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43,
+    0x56, 0x56, 0x4d, 0x78, 0x4a, 0x54, 0x41, 0x6a, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x6f, 0x54, 0x48, 0x46, 0x4e, 0x30, 0x0a, 0x59, 0x58, 0x4a,
+    0x6d, 0x61, 0x57, 0x56, 0x73, 0x5a, 0x43, 0x42, 0x55, 0x5a, 0x57, 0x4e,
+    0x6f, 0x62, 0x6d, 0x39, 0x73, 0x62, 0x32, 0x64, 0x70, 0x5a, 0x58, 0x4d,
+    0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x4d, 0x6a, 0x41,
+    0x77, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x4b, 0x56, 0x4e,
+    0x30, 0x59, 0x58, 0x4a, 0x6d, 0x61, 0x57, 0x56, 0x73, 0x5a, 0x43, 0x42,
+    0x44, 0x0a, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, 0x41, 0x79, 0x49, 0x45,
+    0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58,
+    0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47,
+    0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x67, 0x67, 0x45, 0x41, 0x4d, 0x41,
+    0x77, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x51, 0x46, 0x4d, 0x41,
+    0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x0a, 0x44, 0x51, 0x59, 0x4a, 0x4b,
+    0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42,
+    0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x41, 0x57, 0x64, 0x50,
+    0x34, 0x69, 0x64, 0x30, 0x63, 0x6b, 0x61, 0x56, 0x61, 0x47, 0x73, 0x61,
+    0x66, 0x50, 0x7a, 0x57, 0x64, 0x71, 0x62, 0x41, 0x59, 0x63, 0x61, 0x54,
+    0x31, 0x65, 0x70, 0x6f, 0x58, 0x6b, 0x4a, 0x4b, 0x74, 0x76, 0x33, 0x0a,
+    0x4c, 0x37, 0x49, 0x65, 0x7a, 0x4d, 0x64, 0x65, 0x61, 0x74, 0x69, 0x44,
+    0x68, 0x36, 0x47, 0x58, 0x37, 0x30, 0x6b, 0x31, 0x50, 0x6e, 0x63, 0x47,
+    0x51, 0x56, 0x68, 0x69, 0x76, 0x34, 0x35, 0x59, 0x75, 0x41, 0x70, 0x6e,
+    0x50, 0x2b, 0x79, 0x7a, 0x33, 0x53, 0x46, 0x6d, 0x48, 0x38, 0x6c, 0x55,
+    0x2b, 0x6e, 0x4c, 0x4d, 0x50, 0x55, 0x78, 0x41, 0x32, 0x49, 0x47, 0x76,
+    0x64, 0x35, 0x36, 0x44, 0x0a, 0x65, 0x72, 0x75, 0x69, 0x78, 0x2f, 0x55,
+    0x30, 0x46, 0x34, 0x37, 0x5a, 0x45, 0x55, 0x44, 0x30, 0x2f, 0x43, 0x77,
+    0x71, 0x54, 0x52, 0x56, 0x2f, 0x70, 0x32, 0x4a, 0x64, 0x4c, 0x69, 0x58,
+    0x54, 0x41, 0x41, 0x73, 0x67, 0x47, 0x68, 0x31, 0x6f, 0x2b, 0x52, 0x65,
+    0x34, 0x39, 0x4c, 0x32, 0x4c, 0x37, 0x53, 0x68, 0x5a, 0x33, 0x55, 0x30,
+    0x57, 0x69, 0x78, 0x65, 0x44, 0x79, 0x4c, 0x4a, 0x6c, 0x0a, 0x78, 0x79,
+    0x31, 0x36, 0x70, 0x61, 0x71, 0x38, 0x55, 0x34, 0x5a, 0x74, 0x33, 0x56,
+    0x65, 0x6b, 0x79, 0x76, 0x67, 0x67, 0x51, 0x51, 0x74, 0x6f, 0x38, 0x50,
+    0x54, 0x37, 0x64, 0x4c, 0x35, 0x57, 0x58, 0x58, 0x70, 0x35, 0x39, 0x66,
+    0x6b, 0x64, 0x68, 0x65, 0x4d, 0x74, 0x6c, 0x62, 0x37, 0x31, 0x63, 0x5a,
+    0x42, 0x44, 0x7a, 0x49, 0x30, 0x66, 0x6d, 0x67, 0x41, 0x4b, 0x68, 0x79,
+    0x6e, 0x70, 0x0a, 0x56, 0x53, 0x4a, 0x59, 0x41, 0x43, 0x50, 0x71, 0x34,
+    0x78, 0x4a, 0x44, 0x4b, 0x56, 0x74, 0x48, 0x43, 0x4e, 0x32, 0x4d, 0x51,
+    0x57, 0x70, 0x6c, 0x42, 0x71, 0x6a, 0x6c, 0x49, 0x61, 0x70, 0x42, 0x74,
+    0x4a, 0x55, 0x68, 0x6c, 0x62, 0x6c, 0x39, 0x30, 0x54, 0x53, 0x72, 0x45,
+    0x39, 0x61, 0x74, 0x76, 0x4e, 0x7a, 0x69, 0x50, 0x54, 0x6e, 0x4e, 0x76,
+    0x54, 0x35, 0x31, 0x63, 0x4b, 0x45, 0x59, 0x0a, 0x57, 0x51, 0x50, 0x4a,
+    0x49, 0x72, 0x53, 0x50, 0x6e, 0x4e, 0x56, 0x65, 0x4b, 0x74, 0x65, 0x6c,
+    0x74, 0x74, 0x51, 0x4b, 0x62, 0x66, 0x69, 0x33, 0x51, 0x42, 0x46, 0x47,
+    0x6d, 0x68, 0x39, 0x35, 0x44, 0x6d, 0x4b, 0x2f, 0x44, 0x35, 0x66, 0x73,
+    0x34, 0x43, 0x38, 0x66, 0x46, 0x35, 0x51, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a,
+    0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x65,
+    0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+    0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d,
+    0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64,
+    0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20,
+    0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, 0x74,
+    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69, 0x67, 0x6e,
+    0x69, 0x6e, 0x67, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63,
+    0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43,
+    0x6f, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+    0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+    0x74, 0x79, 0x20, 0x4f, 0x3d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f,
+    0x6d, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x53, 0x65,
+    0x63, 0x75, 0x72, 0x65, 0x20, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c,
+    0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
+    0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x0a, 0x23, 0x20, 0x4c,
+    0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x53, 0x74, 0x61, 0x72, 0x74,
+    0x43, 0x6f, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+    0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+    0x69, 0x74, 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61,
+    0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x32, 0x32, 0x3a, 0x34, 0x64, 0x3a, 0x38, 0x66, 0x3a, 0x38, 0x61, 0x3a,
+    0x66, 0x63, 0x3a, 0x66, 0x37, 0x3a, 0x33, 0x35, 0x3a, 0x63, 0x32, 0x3a,
+    0x62, 0x62, 0x3a, 0x35, 0x37, 0x3a, 0x33, 0x34, 0x3a, 0x39, 0x30, 0x3a,
+    0x37, 0x62, 0x3a, 0x38, 0x62, 0x3a, 0x32, 0x32, 0x3a, 0x31, 0x36, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x65, 0x3a, 0x32,
+    0x62, 0x3a, 0x66, 0x37, 0x3a, 0x66, 0x32, 0x3a, 0x30, 0x33, 0x3a, 0x31,
+    0x62, 0x3a, 0x39, 0x36, 0x3a, 0x66, 0x33, 0x3a, 0x38, 0x63, 0x3a, 0x65,
+    0x36, 0x3a, 0x63, 0x34, 0x3a, 0x64, 0x38, 0x3a, 0x61, 0x38, 0x3a, 0x35,
+    0x64, 0x3a, 0x33, 0x65, 0x3a, 0x32, 0x64, 0x3a, 0x35, 0x38, 0x3a, 0x34,
+    0x37, 0x3a, 0x36, 0x61, 0x3a, 0x30, 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48,
+    0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x37, 0x3a, 0x36, 0x36, 0x3a,
+    0x61, 0x39, 0x3a, 0x62, 0x65, 0x3a, 0x66, 0x32, 0x3a, 0x64, 0x34, 0x3a,
+    0x30, 0x37, 0x3a, 0x31, 0x63, 0x3a, 0x38, 0x36, 0x3a, 0x33, 0x61, 0x3a,
+    0x33, 0x31, 0x3a, 0x61, 0x61, 0x3a, 0x34, 0x39, 0x3a, 0x32, 0x30, 0x3a,
+    0x65, 0x38, 0x3a, 0x31, 0x33, 0x3a, 0x62, 0x32, 0x3a, 0x64, 0x31, 0x3a,
+    0x39, 0x38, 0x3a, 0x36, 0x30, 0x3a, 0x38, 0x63, 0x3a, 0x62, 0x37, 0x3a,
+    0x62, 0x37, 0x3a, 0x63, 0x66, 0x3a, 0x65, 0x32, 0x3a, 0x31, 0x31, 0x3a,
+    0x34, 0x33, 0x3a, 0x62, 0x38, 0x3a, 0x33, 0x36, 0x3a, 0x64, 0x66, 0x3a,
+    0x30, 0x39, 0x3a, 0x65, 0x61, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42,
+    0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49,
+    0x49, 0x48, 0x79, 0x54, 0x43, 0x43, 0x42, 0x62, 0x47, 0x67, 0x41, 0x77,
+    0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67,
+    0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51,
+    0x55, 0x46, 0x41, 0x44, 0x42, 0x39, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51,
+    0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x4a, 0x54, 0x44,
+    0x45, 0x57, 0x0a, 0x4d, 0x42, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43,
+    0x68, 0x4d, 0x4e, 0x55, 0x33, 0x52, 0x68, 0x63, 0x6e, 0x52, 0x44, 0x62,
+    0x32, 0x30, 0x67, 0x54, 0x48, 0x52, 0x6b, 0x4c, 0x6a, 0x45, 0x72, 0x4d,
+    0x43, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x69, 0x55,
+    0x32, 0x56, 0x6a, 0x64, 0x58, 0x4a, 0x6c, 0x49, 0x45, 0x52, 0x70, 0x5a,
+    0x32, 0x6c, 0x30, 0x59, 0x57, 0x77, 0x67, 0x0a, 0x51, 0x32, 0x56, 0x79,
+    0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x55, 0x67,
+    0x55, 0x32, 0x6c, 0x6e, 0x62, 0x6d, 0x6c, 0x75, 0x5a, 0x7a, 0x45, 0x70,
+    0x4d, 0x43, 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x67,
+    0x55, 0x33, 0x52, 0x68, 0x63, 0x6e, 0x52, 0x44, 0x62, 0x32, 0x30, 0x67,
+    0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68,
+    0x0a, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52,
+    0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, 0x48, 0x68, 0x63,
+    0x4e, 0x4d, 0x44, 0x59, 0x77, 0x4f, 0x54, 0x45, 0x33, 0x4d, 0x54, 0x6b,
+    0x30, 0x4e, 0x6a, 0x4d, 0x32, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x59,
+    0x77, 0x4f, 0x54, 0x45, 0x33, 0x4d, 0x54, 0x6b, 0x30, 0x4e, 0x6a, 0x4d,
+    0x32, 0x57, 0x6a, 0x42, 0x39, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51,
+    0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x4a, 0x54, 0x44,
+    0x45, 0x57, 0x4d, 0x42, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68,
+    0x4d, 0x4e, 0x55, 0x33, 0x52, 0x68, 0x63, 0x6e, 0x52, 0x44, 0x62, 0x32,
+    0x30, 0x67, 0x54, 0x48, 0x52, 0x6b, 0x4c, 0x6a, 0x45, 0x72, 0x4d, 0x43,
+    0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x69, 0x0a, 0x55,
+    0x32, 0x56, 0x6a, 0x64, 0x58, 0x4a, 0x6c, 0x49, 0x45, 0x52, 0x70, 0x5a,
+    0x32, 0x6c, 0x30, 0x59, 0x57, 0x77, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64,
+    0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x55, 0x67, 0x55,
+    0x32, 0x6c, 0x6e, 0x62, 0x6d, 0x6c, 0x75, 0x5a, 0x7a, 0x45, 0x70, 0x4d,
+    0x43, 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x67, 0x55,
+    0x33, 0x52, 0x68, 0x0a, 0x63, 0x6e, 0x52, 0x44, 0x62, 0x32, 0x30, 0x67,
+    0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68,
+    0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f,
+    0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, 0x67, 0x67, 0x49, 0x69,
+    0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33,
+    0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x0a, 0x41, 0x34, 0x49,
+    0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49,
+    0x43, 0x41, 0x51, 0x44, 0x42, 0x69, 0x4e, 0x73, 0x4a, 0x76, 0x47, 0x78,
+    0x47, 0x66, 0x48, 0x69, 0x66, 0x6c, 0x58, 0x75, 0x31, 0x4d, 0x35, 0x44,
+    0x79, 0x63, 0x6d, 0x4c, 0x57, 0x77, 0x54, 0x59, 0x67, 0x49, 0x69, 0x52,
+    0x65, 0x7a, 0x75, 0x6c, 0x33, 0x38, 0x6b, 0x4d, 0x4b, 0x6f, 0x67, 0x5a,
+    0x6b, 0x0a, 0x70, 0x4d, 0x79, 0x4f, 0x4e, 0x76, 0x67, 0x34, 0x35, 0x69,
+    0x50, 0x77, 0x62, 0x6d, 0x32, 0x78, 0x50, 0x4e, 0x31, 0x79, 0x6f, 0x34,
+    0x55, 0x63, 0x6f, 0x64, 0x4d, 0x39, 0x74, 0x44, 0x4d, 0x72, 0x30, 0x79,
+    0x2b, 0x76, 0x2f, 0x75, 0x71, 0x77, 0x51, 0x56, 0x6c, 0x6e, 0x74, 0x73,
+    0x51, 0x47, 0x66, 0x51, 0x71, 0x65, 0x64, 0x49, 0x58, 0x57, 0x65, 0x55,
+    0x79, 0x41, 0x4e, 0x33, 0x72, 0x66, 0x0a, 0x4f, 0x51, 0x56, 0x53, 0x57,
+    0x66, 0x66, 0x30, 0x47, 0x30, 0x5a, 0x44, 0x70, 0x4e, 0x4b, 0x46, 0x68,
+    0x64, 0x4c, 0x44, 0x63, 0x66, 0x4e, 0x31, 0x59, 0x6a, 0x53, 0x36, 0x4c,
+    0x49, 0x70, 0x2f, 0x48, 0x6f, 0x2f, 0x75, 0x37, 0x54, 0x54, 0x51, 0x45,
+    0x63, 0x65, 0x57, 0x7a, 0x56, 0x49, 0x39, 0x75, 0x6a, 0x50, 0x57, 0x33,
+    0x55, 0x33, 0x65, 0x43, 0x7a, 0x74, 0x4b, 0x53, 0x35, 0x2f, 0x43, 0x0a,
+    0x4a, 0x69, 0x2f, 0x36, 0x74, 0x52, 0x59, 0x63, 0x63, 0x6a, 0x56, 0x33,
+    0x79, 0x6a, 0x78, 0x64, 0x35, 0x73, 0x72, 0x68, 0x4a, 0x6f, 0x73, 0x61,
+    0x4e, 0x6e, 0x5a, 0x63, 0x41, 0x64, 0x74, 0x30, 0x46, 0x43, 0x58, 0x2b,
+    0x37, 0x62, 0x57, 0x67, 0x69, 0x41, 0x2f, 0x64, 0x65, 0x4d, 0x6f, 0x74,
+    0x48, 0x77, 0x65, 0x58, 0x4d, 0x41, 0x45, 0x74, 0x63, 0x6e, 0x6e, 0x36,
+    0x52, 0x74, 0x59, 0x54, 0x0a, 0x4b, 0x71, 0x69, 0x35, 0x70, 0x71, 0x75,
+    0x44, 0x53, 0x52, 0x33, 0x6c, 0x38, 0x75, 0x2f, 0x64, 0x35, 0x41, 0x47,
+    0x4f, 0x47, 0x41, 0x71, 0x50, 0x59, 0x31, 0x4d, 0x57, 0x68, 0x57, 0x4b,
+    0x70, 0x44, 0x68, 0x6b, 0x36, 0x7a, 0x4c, 0x56, 0x6d, 0x70, 0x73, 0x4a,
+    0x72, 0x64, 0x41, 0x66, 0x6b, 0x4b, 0x2b, 0x46, 0x32, 0x50, 0x72, 0x52,
+    0x74, 0x32, 0x50, 0x5a, 0x45, 0x34, 0x58, 0x4e, 0x69, 0x0a, 0x48, 0x7a,
+    0x76, 0x45, 0x76, 0x71, 0x42, 0x54, 0x56, 0x69, 0x56, 0x73, 0x55, 0x51,
+    0x6e, 0x33, 0x71, 0x71, 0x76, 0x4b, 0x76, 0x33, 0x62, 0x39, 0x62, 0x5a,
+    0x76, 0x7a, 0x6e, 0x64, 0x75, 0x2f, 0x50, 0x57, 0x61, 0x38, 0x44, 0x46,
+    0x61, 0x71, 0x72, 0x35, 0x68, 0x49, 0x6c, 0x54, 0x70, 0x4c, 0x33, 0x36,
+    0x64, 0x59, 0x55, 0x4e, 0x6b, 0x34, 0x64, 0x61, 0x6c, 0x62, 0x36, 0x6b,
+    0x4d, 0x4d, 0x0a, 0x41, 0x76, 0x2b, 0x5a, 0x36, 0x2b, 0x68, 0x73, 0x54,
+    0x58, 0x42, 0x62, 0x4b, 0x57, 0x57, 0x63, 0x33, 0x61, 0x70, 0x64, 0x7a,
+    0x4b, 0x38, 0x42, 0x4d, 0x65, 0x77, 0x4d, 0x36, 0x39, 0x4b, 0x4e, 0x36,
+    0x4f, 0x71, 0x63, 0x65, 0x2b, 0x5a, 0x75, 0x39, 0x79, 0x64, 0x6d, 0x44,
+    0x42, 0x70, 0x49, 0x31, 0x32, 0x35, 0x43, 0x34, 0x7a, 0x2f, 0x65, 0x49,
+    0x54, 0x35, 0x37, 0x34, 0x51, 0x31, 0x77, 0x0a, 0x2b, 0x32, 0x4f, 0x71,
+    0x71, 0x47, 0x77, 0x61, 0x56, 0x4c, 0x52, 0x63, 0x4a, 0x58, 0x72, 0x4a,
+    0x6f, 0x73, 0x6d, 0x4c, 0x46, 0x71, 0x61, 0x37, 0x4c, 0x48, 0x34, 0x58,
+    0x58, 0x67, 0x56, 0x4e, 0x57, 0x47, 0x34, 0x53, 0x48, 0x51, 0x48, 0x75,
+    0x45, 0x68, 0x41, 0x4e, 0x78, 0x6a, 0x4a, 0x2f, 0x47, 0x50, 0x2f, 0x38,
+    0x39, 0x50, 0x72, 0x4e, 0x62, 0x70, 0x48, 0x6f, 0x4e, 0x6b, 0x6d, 0x2b,
+    0x0a, 0x47, 0x6b, 0x68, 0x70, 0x69, 0x38, 0x4b, 0x57, 0x54, 0x52, 0x6f,
+    0x53, 0x73, 0x6d, 0x6b, 0x58, 0x77, 0x51, 0x71, 0x51, 0x31, 0x76, 0x70,
+    0x35, 0x49, 0x6b, 0x69, 0x2f, 0x75, 0x6e, 0x74, 0x70, 0x2b, 0x48, 0x44,
+    0x48, 0x2b, 0x6e, 0x6f, 0x33, 0x32, 0x4e, 0x67, 0x4e, 0x30, 0x6e, 0x5a,
+    0x50, 0x56, 0x2f, 0x2b, 0x51, 0x74, 0x2b, 0x4f, 0x52, 0x30, 0x74, 0x33,
+    0x76, 0x77, 0x6d, 0x43, 0x33, 0x0a, 0x5a, 0x7a, 0x72, 0x64, 0x2f, 0x71,
+    0x71, 0x63, 0x38, 0x4e, 0x53, 0x4c, 0x66, 0x33, 0x49, 0x69, 0x7a, 0x73,
+    0x61, 0x66, 0x6c, 0x37, 0x62, 0x34, 0x72, 0x34, 0x71, 0x67, 0x45, 0x4b,
+    0x6a, 0x5a, 0x2b, 0x78, 0x6a, 0x47, 0x74, 0x72, 0x56, 0x63, 0x55, 0x6a,
+    0x79, 0x4a, 0x74, 0x68, 0x6b, 0x71, 0x63, 0x77, 0x45, 0x4b, 0x44, 0x77,
+    0x4f, 0x7a, 0x45, 0x6d, 0x44, 0x79, 0x65, 0x69, 0x2b, 0x42, 0x0a, 0x32,
+    0x36, 0x4e, 0x75, 0x2f, 0x79, 0x59, 0x77, 0x6c, 0x2f, 0x57, 0x4c, 0x33,
+    0x59, 0x6c, 0x58, 0x74, 0x71, 0x30, 0x39, 0x73, 0x36, 0x38, 0x72, 0x78,
+    0x62, 0x64, 0x32, 0x41, 0x76, 0x43, 0x6c, 0x31, 0x69, 0x75, 0x61, 0x68,
+    0x68, 0x51, 0x71, 0x63, 0x76, 0x62, 0x6a, 0x4d, 0x34, 0x78, 0x64, 0x43,
+    0x55, 0x73, 0x54, 0x33, 0x37, 0x75, 0x4d, 0x64, 0x42, 0x4e, 0x53, 0x53,
+    0x77, 0x49, 0x44, 0x0a, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x34, 0x49, 0x43,
+    0x55, 0x6a, 0x43, 0x43, 0x41, 0x6b, 0x34, 0x77, 0x44, 0x41, 0x59, 0x44,
+    0x56, 0x52, 0x30, 0x54, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42,
+    0x2f, 0x7a, 0x41, 0x4c, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x45,
+    0x42, 0x41, 0x4d, 0x43, 0x41, 0x61, 0x34, 0x77, 0x48, 0x51, 0x59, 0x44,
+    0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x0a, 0x46, 0x45, 0x34,
+    0x4c, 0x37, 0x78, 0x71, 0x6b, 0x51, 0x46, 0x75, 0x6c, 0x46, 0x32, 0x6d,
+    0x48, 0x4d, 0x4d, 0x6f, 0x30, 0x61, 0x45, 0x50, 0x51, 0x51, 0x61, 0x37,
+    0x79, 0x4d, 0x47, 0x51, 0x47, 0x41, 0x31, 0x55, 0x64, 0x48, 0x77, 0x52,
+    0x64, 0x4d, 0x46, 0x73, 0x77, 0x4c, 0x4b, 0x41, 0x71, 0x6f, 0x43, 0x69,
+    0x47, 0x4a, 0x6d, 0x68, 0x30, 0x64, 0x48, 0x41, 0x36, 0x4c, 0x79, 0x39,
+    0x6a, 0x0a, 0x5a, 0x58, 0x4a, 0x30, 0x4c, 0x6e, 0x4e, 0x30, 0x59, 0x58,
+    0x4a, 0x30, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x6d, 0x39, 0x79, 0x5a, 0x79,
+    0x39, 0x7a, 0x5a, 0x6e, 0x4e, 0x6a, 0x59, 0x53, 0x31, 0x6a, 0x63, 0x6d,
+    0x77, 0x75, 0x59, 0x33, 0x4a, 0x73, 0x4d, 0x43, 0x75, 0x67, 0x4b, 0x61,
+    0x41, 0x6e, 0x68, 0x69, 0x56, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69,
+    0x38, 0x76, 0x59, 0x33, 0x4a, 0x73, 0x0a, 0x4c, 0x6e, 0x4e, 0x30, 0x59,
+    0x58, 0x4a, 0x30, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x6d, 0x39, 0x79, 0x5a,
+    0x79, 0x39, 0x7a, 0x5a, 0x6e, 0x4e, 0x6a, 0x59, 0x53, 0x31, 0x6a, 0x63,
+    0x6d, 0x77, 0x75, 0x59, 0x33, 0x4a, 0x73, 0x4d, 0x49, 0x49, 0x42, 0x58,
+    0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x67, 0x42, 0x49, 0x49, 0x42, 0x56,
+    0x44, 0x43, 0x43, 0x41, 0x56, 0x41, 0x77, 0x67, 0x67, 0x46, 0x4d, 0x0a,
+    0x42, 0x67, 0x73, 0x72, 0x42, 0x67, 0x45, 0x45, 0x41, 0x59, 0x47, 0x31,
+    0x4e, 0x77, 0x45, 0x42, 0x41, 0x54, 0x43, 0x43, 0x41, 0x54, 0x73, 0x77,
+    0x4c, 0x77, 0x59, 0x49, 0x4b, 0x77, 0x59, 0x42, 0x42, 0x51, 0x55, 0x48,
+    0x41, 0x67, 0x45, 0x57, 0x49, 0x32, 0x68, 0x30, 0x64, 0x48, 0x41, 0x36,
+    0x4c, 0x79, 0x39, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x4c, 0x6e, 0x4e, 0x30,
+    0x59, 0x58, 0x4a, 0x30, 0x0a, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x6d, 0x39,
+    0x79, 0x5a, 0x79, 0x39, 0x77, 0x62, 0x32, 0x78, 0x70, 0x59, 0x33, 0x6b,
+    0x75, 0x63, 0x47, 0x52, 0x6d, 0x4d, 0x44, 0x55, 0x47, 0x43, 0x43, 0x73,
+    0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x77, 0x49, 0x42, 0x46, 0x69, 0x6c,
+    0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69, 0x38, 0x76, 0x59, 0x32, 0x56,
+    0x79, 0x64, 0x43, 0x35, 0x7a, 0x64, 0x47, 0x46, 0x79, 0x0a, 0x64, 0x47,
+    0x4e, 0x76, 0x62, 0x53, 0x35, 0x76, 0x63, 0x6d, 0x63, 0x76, 0x61, 0x57,
+    0x35, 0x30, 0x5a, 0x58, 0x4a, 0x74, 0x5a, 0x57, 0x52, 0x70, 0x59, 0x58,
+    0x52, 0x6c, 0x4c, 0x6e, 0x42, 0x6b, 0x5a, 0x6a, 0x43, 0x42, 0x30, 0x41,
+    0x59, 0x49, 0x4b, 0x77, 0x59, 0x42, 0x42, 0x51, 0x55, 0x48, 0x41, 0x67,
+    0x49, 0x77, 0x67, 0x63, 0x4d, 0x77, 0x4a, 0x78, 0x59, 0x67, 0x55, 0x33,
+    0x52, 0x68, 0x0a, 0x63, 0x6e, 0x51, 0x67, 0x51, 0x32, 0x39, 0x74, 0x62,
+    0x57, 0x56, 0x79, 0x59, 0x32, 0x6c, 0x68, 0x62, 0x43, 0x41, 0x6f, 0x55,
+    0x33, 0x52, 0x68, 0x63, 0x6e, 0x52, 0x44, 0x62, 0x32, 0x30, 0x70, 0x49,
+    0x45, 0x78, 0x30, 0x5a, 0x43, 0x34, 0x77, 0x41, 0x77, 0x49, 0x42, 0x41,
+    0x52, 0x71, 0x42, 0x6c, 0x30, 0x78, 0x70, 0x62, 0x57, 0x6c, 0x30, 0x5a,
+    0x57, 0x51, 0x67, 0x54, 0x47, 0x6c, 0x68, 0x0a, 0x59, 0x6d, 0x6c, 0x73,
+    0x61, 0x58, 0x52, 0x35, 0x4c, 0x43, 0x42, 0x79, 0x5a, 0x57, 0x46, 0x6b,
+    0x49, 0x48, 0x52, 0x6f, 0x5a, 0x53, 0x42, 0x7a, 0x5a, 0x57, 0x4e, 0x30,
+    0x61, 0x57, 0x39, 0x75, 0x49, 0x43, 0x70, 0x4d, 0x5a, 0x57, 0x64, 0x68,
+    0x62, 0x43, 0x42, 0x4d, 0x61, 0x57, 0x31, 0x70, 0x64, 0x47, 0x46, 0x30,
+    0x61, 0x57, 0x39, 0x75, 0x63, 0x79, 0x6f, 0x67, 0x62, 0x32, 0x59, 0x67,
+    0x0a, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x46, 0x4e, 0x30, 0x59, 0x58, 0x4a,
+    0x30, 0x51, 0x32, 0x39, 0x74, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52,
+    0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34,
+    0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52,
+    0x35, 0x49, 0x46, 0x42, 0x76, 0x62, 0x47, 0x6c, 0x6a, 0x65, 0x53, 0x42,
+    0x68, 0x64, 0x6d, 0x46, 0x70, 0x0a, 0x62, 0x47, 0x46, 0x69, 0x62, 0x47,
+    0x55, 0x67, 0x59, 0x58, 0x51, 0x67, 0x61, 0x48, 0x52, 0x30, 0x63, 0x44,
+    0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x75, 0x63, 0x33,
+    0x52, 0x68, 0x63, 0x6e, 0x52, 0x6a, 0x62, 0x32, 0x30, 0x75, 0x62, 0x33,
+    0x4a, 0x6e, 0x4c, 0x33, 0x42, 0x76, 0x62, 0x47, 0x6c, 0x6a, 0x65, 0x53,
+    0x35, 0x77, 0x5a, 0x47, 0x59, 0x77, 0x45, 0x51, 0x59, 0x4a, 0x0a, 0x59,
+    0x49, 0x5a, 0x49, 0x41, 0x59, 0x62, 0x34, 0x51, 0x67, 0x45, 0x42, 0x42,
+    0x41, 0x51, 0x44, 0x41, 0x67, 0x41, 0x48, 0x4d, 0x44, 0x67, 0x47, 0x43,
+    0x57, 0x43, 0x47, 0x53, 0x41, 0x47, 0x47, 0x2b, 0x45, 0x49, 0x42, 0x44,
+    0x51, 0x51, 0x72, 0x46, 0x69, 0x6c, 0x54, 0x64, 0x47, 0x46, 0x79, 0x64,
+    0x45, 0x4e, 0x76, 0x62, 0x53, 0x42, 0x47, 0x63, 0x6d, 0x56, 0x6c, 0x49,
+    0x46, 0x4e, 0x54, 0x0a, 0x54, 0x43, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30,
+    0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75,
+    0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30,
+    0x65, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47,
+    0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43,
+    0x41, 0x67, 0x45, 0x41, 0x46, 0x6d, 0x79, 0x5a, 0x0a, 0x39, 0x47, 0x59,
+    0x4d, 0x4e, 0x50, 0x58, 0x51, 0x68, 0x56, 0x35, 0x39, 0x43, 0x75, 0x7a,
+    0x61, 0x45, 0x45, 0x34, 0x34, 0x48, 0x46, 0x37, 0x66, 0x70, 0x69, 0x55,
+    0x46, 0x53, 0x35, 0x45, 0x79, 0x77, 0x65, 0x67, 0x37, 0x38, 0x54, 0x33,
+    0x64, 0x52, 0x41, 0x6c, 0x62, 0x42, 0x30, 0x6d, 0x4b, 0x4b, 0x63, 0x74,
+    0x6d, 0x41, 0x72, 0x65, 0x78, 0x6d, 0x76, 0x63, 0x6c, 0x6d, 0x41, 0x6b,
+    0x38, 0x0a, 0x6a, 0x68, 0x76, 0x68, 0x33, 0x54, 0x61, 0x48, 0x4b, 0x30,
+    0x75, 0x37, 0x61, 0x4e, 0x4d, 0x35, 0x5a, 0x6a, 0x32, 0x67, 0x4a, 0x73,
+    0x66, 0x79, 0x4f, 0x5a, 0x45, 0x64, 0x55, 0x61, 0x75, 0x43, 0x65, 0x33,
+    0x37, 0x56, 0x7a, 0x6c, 0x72, 0x6b, 0x34, 0x67, 0x4e, 0x58, 0x63, 0x47,
+    0x6d, 0x58, 0x43, 0x50, 0x6c, 0x65, 0x57, 0x4b, 0x59, 0x4b, 0x33, 0x34,
+    0x77, 0x47, 0x6d, 0x6b, 0x55, 0x57, 0x0a, 0x46, 0x6a, 0x67, 0x4b, 0x58,
+    0x6c, 0x66, 0x32, 0x59, 0x73, 0x64, 0x36, 0x41, 0x67, 0x58, 0x6d, 0x76,
+    0x42, 0x36, 0x31, 0x38, 0x70, 0x37, 0x30, 0x71, 0x53, 0x6d, 0x44, 0x2b,
+    0x4c, 0x49, 0x55, 0x34, 0x32, 0x34, 0x6f, 0x68, 0x30, 0x54, 0x44, 0x6b,
+    0x42, 0x72, 0x65, 0x4f, 0x4b, 0x6b, 0x38, 0x72, 0x45, 0x4e, 0x4e, 0x5a,
+    0x45, 0x58, 0x4f, 0x33, 0x53, 0x69, 0x70, 0x58, 0x50, 0x4a, 0x7a, 0x0a,
+    0x65, 0x77, 0x54, 0x34, 0x46, 0x2b, 0x69, 0x72, 0x73, 0x66, 0x4d, 0x75,
+    0x58, 0x47, 0x52, 0x75, 0x63, 0x7a, 0x45, 0x36, 0x45, 0x72, 0x69, 0x38,
+    0x73, 0x78, 0x48, 0x6b, 0x66, 0x59, 0x2b, 0x42, 0x55, 0x5a, 0x6f, 0x37,
+    0x6a, 0x59, 0x6e, 0x30, 0x54, 0x5a, 0x4e, 0x6d, 0x65, 0x7a, 0x77, 0x44,
+    0x37, 0x64, 0x4f, 0x61, 0x48, 0x5a, 0x72, 0x7a, 0x5a, 0x56, 0x44, 0x31,
+    0x6f, 0x4e, 0x42, 0x31, 0x0a, 0x6e, 0x79, 0x2b, 0x76, 0x38, 0x4f, 0x71,
+    0x43, 0x51, 0x35, 0x6a, 0x34, 0x61, 0x5a, 0x79, 0x4a, 0x65, 0x63, 0x52,
+    0x44, 0x6a, 0x6b, 0x5a, 0x79, 0x34, 0x32, 0x51, 0x32, 0x45, 0x71, 0x2f,
+    0x33, 0x4a, 0x52, 0x34, 0x34, 0x69, 0x5a, 0x42, 0x33, 0x66, 0x73, 0x4e,
+    0x72, 0x61, 0x72, 0x6e, 0x44, 0x79, 0x30, 0x52, 0x4c, 0x72, 0x48, 0x69,
+    0x51, 0x69, 0x2b, 0x66, 0x48, 0x4c, 0x42, 0x35, 0x4c, 0x0a, 0x45, 0x55,
+    0x54, 0x49, 0x4e, 0x46, 0x49, 0x6e, 0x7a, 0x51, 0x70, 0x64, 0x6e, 0x34,
+    0x58, 0x42, 0x69, 0x64, 0x55, 0x61, 0x65, 0x50, 0x4b, 0x56, 0x45, 0x46,
+    0x4d, 0x79, 0x33, 0x59, 0x43, 0x45, 0x5a, 0x6e, 0x58, 0x5a, 0x74, 0x57,
+    0x67, 0x6f, 0x2b, 0x32, 0x45, 0x75, 0x76, 0x6f, 0x53, 0x6f, 0x4f, 0x4d,
+    0x43, 0x5a, 0x45, 0x6f, 0x61, 0x6c, 0x48, 0x6d, 0x64, 0x6b, 0x72, 0x51,
+    0x59, 0x75, 0x0a, 0x4c, 0x36, 0x6c, 0x77, 0x68, 0x63, 0x65, 0x57, 0x44,
+    0x33, 0x79, 0x4a, 0x5a, 0x66, 0x57, 0x4f, 0x51, 0x31, 0x51, 0x4f, 0x71,
+    0x39, 0x32, 0x6c, 0x67, 0x44, 0x6d, 0x55, 0x59, 0x4d, 0x41, 0x30, 0x79,
+    0x5a, 0x5a, 0x77, 0x4c, 0x4b, 0x4d, 0x53, 0x39, 0x52, 0x39, 0x49, 0x65,
+    0x37, 0x30, 0x63, 0x66, 0x6d, 0x75, 0x33, 0x6e, 0x5a, 0x44, 0x30, 0x49,
+    0x6a, 0x75, 0x75, 0x2b, 0x50, 0x77, 0x71, 0x0a, 0x79, 0x76, 0x71, 0x43,
+    0x55, 0x71, 0x44, 0x76, 0x72, 0x30, 0x74, 0x56, 0x6b, 0x2b, 0x76, 0x42,
+    0x74, 0x66, 0x41, 0x69, 0x69, 0x36, 0x77, 0x30, 0x54, 0x69, 0x59, 0x69,
+    0x42, 0x4b, 0x47, 0x48, 0x4c, 0x48, 0x56, 0x4b, 0x74, 0x2b, 0x56, 0x39,
+    0x45, 0x39, 0x65, 0x34, 0x44, 0x47, 0x54, 0x41, 0x4e, 0x74, 0x4c, 0x4a,
+    0x4c, 0x34, 0x59, 0x53, 0x6a, 0x43, 0x4d, 0x4a, 0x77, 0x52, 0x75, 0x43,
+    0x0a, 0x4f, 0x33, 0x4e, 0x4a, 0x6f, 0x32, 0x70, 0x58, 0x68, 0x35, 0x54,
+    0x6c, 0x31, 0x6e, 0x6a, 0x46, 0x6d, 0x55, 0x4e, 0x6a, 0x34, 0x30, 0x33,
+    0x67, 0x64, 0x79, 0x33, 0x68, 0x5a, 0x5a, 0x6c, 0x79, 0x61, 0x51, 0x51,
+    0x61, 0x52, 0x77, 0x6e, 0x6d, 0x44, 0x77, 0x46, 0x57, 0x4a, 0x50, 0x73,
+    0x66, 0x76, 0x77, 0x35, 0x35, 0x71, 0x56, 0x67, 0x75, 0x75, 0x63, 0x51,
+    0x4a, 0x41, 0x58, 0x36, 0x56, 0x0a, 0x75, 0x6d, 0x30, 0x41, 0x42, 0x6a,
+    0x36, 0x79, 0x36, 0x6b, 0x6f, 0x51, 0x4f, 0x64, 0x6a, 0x51, 0x4b, 0x2f,
+    0x57, 0x2f, 0x37, 0x48, 0x57, 0x2f, 0x6c, 0x77, 0x4c, 0x46, 0x43, 0x52,
+    0x73, 0x49, 0x33, 0x46, 0x55, 0x33, 0x34, 0x6f, 0x48, 0x37, 0x4e, 0x34,
+    0x52, 0x44, 0x59, 0x69, 0x44, 0x4b, 0x35, 0x31, 0x5a, 0x4c, 0x5a, 0x65,
+    0x72, 0x2b, 0x62, 0x4d, 0x45, 0x6b, 0x6b, 0x79, 0x53, 0x68, 0x0a, 0x4e,
+    0x4f, 0x73, 0x46, 0x2f, 0x35, 0x6f, 0x69, 0x72, 0x70, 0x74, 0x39, 0x50,
+    0x2f, 0x46, 0x6c, 0x55, 0x51, 0x71, 0x6d, 0x4d, 0x47, 0x71, 0x7a, 0x39,
+    0x49, 0x67, 0x63, 0x67, 0x41, 0x33, 0x38, 0x63, 0x6f, 0x72, 0x6f, 0x67,
+    0x31, 0x34, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73,
+    0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69,
+    0x43, 0x65, 0x72, 0x74, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x65, 0x64,
+    0x20, 0x49, 0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20,
+    0x4f, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49,
+    0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69,
+    0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23,
+    0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x41, 0x73,
+    0x73, 0x75, 0x72, 0x65, 0x64, 0x20, 0x49, 0x44, 0x20, 0x52, 0x6f, 0x6f,
+    0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43,
+    0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x77,
+    0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e,
+    0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a,
+    0x20, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x41,
+    0x73, 0x73, 0x75, 0x72, 0x65, 0x64, 0x20, 0x49, 0x44, 0x20, 0x52, 0x6f,
+    0x6f, 0x74, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72,
+    0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x37, 0x31, 0x35, 0x34, 0x37, 0x31,
+    0x37, 0x39, 0x33, 0x34, 0x31, 0x32, 0x30, 0x35, 0x38, 0x37, 0x38, 0x36,
+    0x32, 0x31, 0x36, 0x37, 0x37, 0x39, 0x34, 0x39, 0x31, 0x34, 0x30, 0x37,
+    0x31, 0x34, 0x32, 0x35, 0x30, 0x38, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44,
+    0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x38, 0x37, 0x3a, 0x63, 0x65, 0x3a, 0x30, 0x62, 0x3a,
+    0x37, 0x62, 0x3a, 0x32, 0x61, 0x3a, 0x30, 0x65, 0x3a, 0x34, 0x39, 0x3a,
+    0x30, 0x30, 0x3a, 0x65, 0x31, 0x3a, 0x35, 0x38, 0x3a, 0x37, 0x31, 0x3a,
+    0x39, 0x62, 0x3a, 0x33, 0x37, 0x3a, 0x61, 0x38, 0x3a, 0x39, 0x33, 0x3a,
+    0x37, 0x32, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69,
+    0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30,
+    0x35, 0x3a, 0x36, 0x33, 0x3a, 0x62, 0x38, 0x3a, 0x36, 0x33, 0x3a, 0x30,
+    0x64, 0x3a, 0x36, 0x32, 0x3a, 0x64, 0x37, 0x3a, 0x35, 0x61, 0x3a, 0x62,
+    0x62, 0x3a, 0x63, 0x38, 0x3a, 0x61, 0x62, 0x3a, 0x31, 0x65, 0x3a, 0x34,
+    0x62, 0x3a, 0x64, 0x66, 0x3a, 0x62, 0x35, 0x3a, 0x61, 0x38, 0x3a, 0x39,
+    0x39, 0x3a, 0x62, 0x32, 0x3a, 0x34, 0x64, 0x3a, 0x34, 0x33, 0x0a, 0x23,
+    0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x65, 0x3a,
+    0x39, 0x30, 0x3a, 0x39, 0x39, 0x3a, 0x62, 0x35, 0x3a, 0x30, 0x31, 0x3a,
+    0x35, 0x65, 0x3a, 0x38, 0x66, 0x3a, 0x34, 0x38, 0x3a, 0x36, 0x63, 0x3a,
+    0x30, 0x30, 0x3a, 0x62, 0x63, 0x3a, 0x65, 0x61, 0x3a, 0x39, 0x64, 0x3a,
+    0x31, 0x31, 0x3a, 0x31, 0x65, 0x3a, 0x65, 0x37, 0x3a, 0x32, 0x31, 0x3a,
+    0x66, 0x61, 0x3a, 0x62, 0x61, 0x3a, 0x33, 0x35, 0x3a, 0x35, 0x61, 0x3a,
+    0x38, 0x39, 0x3a, 0x62, 0x63, 0x3a, 0x66, 0x31, 0x3a, 0x64, 0x66, 0x3a,
+    0x36, 0x39, 0x3a, 0x35, 0x36, 0x3a, 0x31, 0x65, 0x3a, 0x33, 0x64, 0x3a,
+    0x63, 0x36, 0x3a, 0x33, 0x32, 0x3a, 0x35, 0x63, 0x0a, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54,
+    0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x0a, 0x4d, 0x49, 0x49, 0x44, 0x74, 0x7a, 0x43, 0x43, 0x41, 0x70, 0x2b,
+    0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x44, 0x4f, 0x66,
+    0x67, 0x35, 0x52, 0x66, 0x59, 0x52, 0x76, 0x36, 0x50, 0x35, 0x57, 0x44,
+    0x38, 0x47, 0x2f, 0x41, 0x77, 0x4f, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b,
+    0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55,
+    0x46, 0x41, 0x44, 0x42, 0x6c, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51,
+    0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a,
+    0x45, 0x56, 0x4d, 0x42, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68,
+    0x4d, 0x4d, 0x52, 0x47, 0x6c, 0x6e, 0x61, 0x55, 0x4e, 0x6c, 0x63, 0x6e,
+    0x51, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77,
+    0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x42, 0x33, 0x0a, 0x64,
+    0x33, 0x63, 0x75, 0x5a, 0x47, 0x6c, 0x6e, 0x61, 0x57, 0x4e, 0x6c, 0x63,
+    0x6e, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4d, 0x53, 0x51, 0x77, 0x49,
+    0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x74, 0x45, 0x61,
+    0x57, 0x64, 0x70, 0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x42, 0x42, 0x63,
+    0x33, 0x4e, 0x31, 0x63, 0x6d, 0x56, 0x6b, 0x49, 0x45, 0x6c, 0x45, 0x49,
+    0x46, 0x4a, 0x76, 0x0a, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x77,
+    0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x59, 0x78, 0x4d, 0x54, 0x45, 0x77,
+    0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e,
+    0x4d, 0x7a, 0x45, 0x78, 0x4d, 0x54, 0x45, 0x77, 0x4d, 0x44, 0x41, 0x77,
+    0x4d, 0x44, 0x41, 0x77, 0x57, 0x6a, 0x42, 0x6c, 0x4d, 0x51, 0x73, 0x77,
+    0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x0a, 0x45, 0x77, 0x4a,
+    0x56, 0x55, 0x7a, 0x45, 0x56, 0x4d, 0x42, 0x4d, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x43, 0x68, 0x4d, 0x4d, 0x52, 0x47, 0x6c, 0x6e, 0x61, 0x55, 0x4e,
+    0x6c, 0x63, 0x6e, 0x51, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d, 0x52, 0x6b,
+    0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x42,
+    0x33, 0x64, 0x33, 0x63, 0x75, 0x5a, 0x47, 0x6c, 0x6e, 0x61, 0x57, 0x4e,
+    0x6c, 0x0a, 0x63, 0x6e, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4d, 0x53,
+    0x51, 0x77, 0x49, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78,
+    0x74, 0x45, 0x61, 0x57, 0x64, 0x70, 0x51, 0x32, 0x56, 0x79, 0x64, 0x43,
+    0x42, 0x42, 0x63, 0x33, 0x4e, 0x31, 0x63, 0x6d, 0x56, 0x6b, 0x49, 0x45,
+    0x6c, 0x45, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30,
+    0x45, 0x77, 0x67, 0x67, 0x45, 0x69, 0x0a, 0x4d, 0x41, 0x30, 0x47, 0x43,
+    0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41,
+    0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67,
+    0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x43, 0x74, 0x44,
+    0x68, 0x58, 0x4f, 0x35, 0x45, 0x4f, 0x41, 0x58, 0x4c, 0x47, 0x48, 0x38,
+    0x37, 0x64, 0x67, 0x2b, 0x58, 0x45, 0x53, 0x70, 0x61, 0x37, 0x63, 0x0a,
+    0x4a, 0x70, 0x53, 0x49, 0x71, 0x76, 0x54, 0x4f, 0x39, 0x53, 0x41, 0x35,
+    0x4b, 0x46, 0x68, 0x67, 0x44, 0x50, 0x69, 0x41, 0x32, 0x71, 0x6b, 0x56,
+    0x6c, 0x54, 0x4a, 0x68, 0x50, 0x4c, 0x57, 0x78, 0x4b, 0x49, 0x53, 0x4b,
+    0x69, 0x74, 0x79, 0x66, 0x43, 0x67, 0x79, 0x44, 0x46, 0x33, 0x71, 0x50,
+    0x6b, 0x4b, 0x79, 0x4b, 0x35, 0x33, 0x6c, 0x54, 0x58, 0x44, 0x47, 0x45,
+    0x4b, 0x76, 0x59, 0x50, 0x0a, 0x6d, 0x44, 0x49, 0x32, 0x64, 0x73, 0x7a,
+    0x65, 0x33, 0x54, 0x79, 0x6f, 0x6f, 0x75, 0x39, 0x71, 0x2b, 0x79, 0x48,
+    0x79, 0x55, 0x6d, 0x48, 0x66, 0x6e, 0x79, 0x44, 0x58, 0x48, 0x2b, 0x4b,
+    0x78, 0x32, 0x66, 0x34, 0x59, 0x5a, 0x4e, 0x49, 0x53, 0x57, 0x31, 0x2f,
+    0x35, 0x57, 0x42, 0x67, 0x31, 0x76, 0x45, 0x66, 0x4e, 0x6f, 0x54, 0x62,
+    0x35, 0x61, 0x33, 0x2f, 0x55, 0x73, 0x44, 0x67, 0x2b, 0x0a, 0x77, 0x52,
+    0x76, 0x44, 0x6a, 0x44, 0x50, 0x5a, 0x32, 0x43, 0x38, 0x59, 0x2f, 0x69,
+    0x67, 0x50, 0x73, 0x36, 0x65, 0x44, 0x31, 0x73, 0x4e, 0x75, 0x52, 0x4d,
+    0x42, 0x68, 0x4e, 0x5a, 0x59, 0x57, 0x2f, 0x6c, 0x6d, 0x63, 0x69, 0x33,
+    0x5a, 0x74, 0x31, 0x2f, 0x47, 0x69, 0x53, 0x77, 0x30, 0x72, 0x2f, 0x77,
+    0x74, 0x79, 0x32, 0x70, 0x35, 0x67, 0x30, 0x49, 0x36, 0x51, 0x4e, 0x63,
+    0x5a, 0x34, 0x0a, 0x56, 0x59, 0x63, 0x67, 0x6f, 0x63, 0x2f, 0x6c, 0x62,
+    0x51, 0x72, 0x49, 0x53, 0x58, 0x77, 0x78, 0x6d, 0x44, 0x4e, 0x73, 0x49,
+    0x75, 0x6d, 0x48, 0x30, 0x44, 0x4a, 0x61, 0x6f, 0x72, 0x6f, 0x54, 0x67,
+    0x68, 0x48, 0x74, 0x4f, 0x52, 0x65, 0x64, 0x6d, 0x54, 0x70, 0x79, 0x6f,
+    0x65, 0x62, 0x36, 0x70, 0x4e, 0x6e, 0x56, 0x46, 0x7a, 0x46, 0x31, 0x72,
+    0x6f, 0x56, 0x39, 0x49, 0x71, 0x34, 0x2f, 0x0a, 0x41, 0x55, 0x61, 0x47,
+    0x39, 0x69, 0x68, 0x35, 0x79, 0x4c, 0x48, 0x61, 0x35, 0x46, 0x63, 0x58,
+    0x78, 0x48, 0x34, 0x63, 0x44, 0x72, 0x43, 0x30, 0x6b, 0x71, 0x5a, 0x57,
+    0x73, 0x37, 0x32, 0x79, 0x6c, 0x2b, 0x32, 0x71, 0x70, 0x2f, 0x43, 0x33,
+    0x78, 0x61, 0x67, 0x2f, 0x6c, 0x52, 0x62, 0x51, 0x2f, 0x36, 0x47, 0x57,
+    0x36, 0x77, 0x68, 0x66, 0x47, 0x48, 0x64, 0x50, 0x41, 0x67, 0x4d, 0x42,
+    0x0a, 0x41, 0x41, 0x47, 0x6a, 0x59, 0x7a, 0x42, 0x68, 0x4d, 0x41, 0x34,
+    0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51,
+    0x45, 0x41, 0x77, 0x49, 0x42, 0x68, 0x6a, 0x41, 0x50, 0x42, 0x67, 0x4e,
+    0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41,
+    0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55,
+    0x64, 0x44, 0x67, 0x51, 0x57, 0x0a, 0x42, 0x42, 0x52, 0x46, 0x36, 0x36,
+    0x4b, 0x76, 0x39, 0x4a, 0x4c, 0x4c, 0x67, 0x6a, 0x45, 0x74, 0x55, 0x59,
+    0x75, 0x6e, 0x70, 0x79, 0x47, 0x64, 0x38, 0x32, 0x33, 0x49, 0x44, 0x7a,
+    0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44,
+    0x41, 0x57, 0x67, 0x42, 0x52, 0x46, 0x36, 0x36, 0x4b, 0x76, 0x39, 0x4a,
+    0x4c, 0x4c, 0x67, 0x6a, 0x45, 0x74, 0x55, 0x59, 0x75, 0x6e, 0x0a, 0x70,
+    0x79, 0x47, 0x64, 0x38, 0x32, 0x33, 0x49, 0x44, 0x7a, 0x41, 0x4e, 0x42,
+    0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41,
+    0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x6f,
+    0x67, 0x36, 0x38, 0x33, 0x2b, 0x4c, 0x74, 0x38, 0x4f, 0x4e, 0x79, 0x63,
+    0x33, 0x70, 0x6b, 0x6c, 0x4c, 0x2f, 0x33, 0x63, 0x6d, 0x62, 0x59, 0x4d,
+    0x75, 0x52, 0x43, 0x0a, 0x64, 0x57, 0x4b, 0x75, 0x68, 0x2b, 0x76, 0x79,
+    0x31, 0x64, 0x6e, 0x65, 0x56, 0x72, 0x4f, 0x66, 0x7a, 0x4d, 0x34, 0x55,
+    0x4b, 0x4c, 0x6b, 0x4e, 0x6c, 0x32, 0x42, 0x63, 0x45, 0x6b, 0x78, 0x59,
+    0x35, 0x4e, 0x4d, 0x39, 0x67, 0x30, 0x6c, 0x46, 0x57, 0x4a, 0x63, 0x31,
+    0x61, 0x52, 0x71, 0x6f, 0x52, 0x2b, 0x70, 0x57, 0x78, 0x6e, 0x6d, 0x72,
+    0x45, 0x74, 0x68, 0x6e, 0x67, 0x59, 0x54, 0x66, 0x0a, 0x66, 0x77, 0x6b,
+    0x38, 0x6c, 0x4f, 0x61, 0x34, 0x4a, 0x69, 0x77, 0x67, 0x76, 0x54, 0x32,
+    0x7a, 0x4b, 0x49, 0x6e, 0x33, 0x58, 0x2f, 0x38, 0x69, 0x34, 0x70, 0x65,
+    0x45, 0x48, 0x2b, 0x6c, 0x6c, 0x37, 0x34, 0x66, 0x67, 0x33, 0x38, 0x46,
+    0x6e, 0x53, 0x62, 0x4e, 0x64, 0x36, 0x37, 0x49, 0x4a, 0x4b, 0x75, 0x73,
+    0x6d, 0x37, 0x58, 0x69, 0x2b, 0x66, 0x54, 0x38, 0x72, 0x38, 0x37, 0x63,
+    0x6d, 0x0a, 0x4e, 0x57, 0x31, 0x66, 0x69, 0x51, 0x47, 0x32, 0x53, 0x56,
+    0x75, 0x66, 0x41, 0x51, 0x57, 0x62, 0x71, 0x7a, 0x30, 0x6c, 0x77, 0x63,
+    0x79, 0x32, 0x66, 0x38, 0x4c, 0x78, 0x62, 0x34, 0x62, 0x47, 0x2b, 0x6d,
+    0x52, 0x6f, 0x36, 0x34, 0x45, 0x74, 0x6c, 0x4f, 0x74, 0x43, 0x74, 0x2f,
+    0x71, 0x4d, 0x48, 0x74, 0x31, 0x69, 0x38, 0x62, 0x35, 0x51, 0x5a, 0x37,
+    0x64, 0x73, 0x76, 0x66, 0x50, 0x78, 0x0a, 0x48, 0x32, 0x73, 0x4d, 0x4e,
+    0x67, 0x63, 0x57, 0x66, 0x7a, 0x64, 0x38, 0x71, 0x56, 0x74, 0x74, 0x65,
+    0x76, 0x45, 0x53, 0x52, 0x6d, 0x43, 0x44, 0x31, 0x79, 0x63, 0x45, 0x76,
+    0x6b, 0x76, 0x4f, 0x6c, 0x37, 0x37, 0x44, 0x5a, 0x79, 0x70, 0x6f, 0x45,
+    0x64, 0x2b, 0x41, 0x35, 0x77, 0x77, 0x7a, 0x5a, 0x72, 0x38, 0x54, 0x44,
+    0x52, 0x52, 0x75, 0x38, 0x33, 0x38, 0x66, 0x59, 0x78, 0x41, 0x65, 0x0a,
+    0x2b, 0x6f, 0x30, 0x62, 0x4a, 0x57, 0x31, 0x73, 0x6a, 0x36, 0x57, 0x33,
+    0x59, 0x51, 0x47, 0x78, 0x30, 0x71, 0x4d, 0x6d, 0x6f, 0x52, 0x42, 0x78,
+    0x6e, 0x61, 0x33, 0x69, 0x77, 0x2f, 0x6e, 0x44, 0x6d, 0x56, 0x47, 0x33,
+    0x4b, 0x77, 0x63, 0x49, 0x7a, 0x69, 0x37, 0x6d, 0x55, 0x4c, 0x4b, 0x6e,
+    0x2b, 0x67, 0x70, 0x46, 0x4c, 0x36, 0x4c, 0x77, 0x38, 0x67, 0x3d, 0x3d,
+    0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45,
+    0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72,
+    0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72,
+    0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f,
+    0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43,
+    0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x77,
+    0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e,
+    0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63,
+    0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65,
+    0x72, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f,
+    0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x44, 0x69, 0x67, 0x69,
+    0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d,
+    0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74,
+    0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c,
+    0x3a, 0x20, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20,
+    0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+    0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c,
+    0x3a, 0x20, 0x31, 0x30, 0x39, 0x34, 0x34, 0x37, 0x31, 0x39, 0x35, 0x39,
+    0x38, 0x39, 0x35, 0x32, 0x30, 0x34, 0x30, 0x33, 0x37, 0x34, 0x39, 0x35,
+    0x31, 0x38, 0x33, 0x32, 0x39, 0x36, 0x33, 0x37, 0x39, 0x34, 0x34, 0x35,
+    0x34, 0x33, 0x34, 0x36, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x37, 0x39, 0x3a, 0x65, 0x34, 0x3a, 0x61, 0x39, 0x3a, 0x38, 0x34, 0x3a,
+    0x30, 0x64, 0x3a, 0x37, 0x64, 0x3a, 0x33, 0x61, 0x3a, 0x39, 0x36, 0x3a,
+    0x64, 0x37, 0x3a, 0x63, 0x30, 0x3a, 0x34, 0x66, 0x3a, 0x65, 0x32, 0x3a,
+    0x34, 0x33, 0x3a, 0x34, 0x63, 0x3a, 0x38, 0x39, 0x3a, 0x32, 0x65, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x38, 0x3a, 0x39,
+    0x38, 0x3a, 0x35, 0x64, 0x3a, 0x33, 0x61, 0x3a, 0x36, 0x35, 0x3a, 0x65,
+    0x35, 0x3a, 0x65, 0x35, 0x3a, 0x63, 0x34, 0x3a, 0x62, 0x32, 0x3a, 0x64,
+    0x37, 0x3a, 0x64, 0x36, 0x3a, 0x36, 0x64, 0x3a, 0x34, 0x30, 0x3a, 0x63,
+    0x36, 0x3a, 0x64, 0x64, 0x3a, 0x32, 0x66, 0x3a, 0x62, 0x31, 0x3a, 0x39,
+    0x63, 0x3a, 0x35, 0x34, 0x3a, 0x33, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48,
+    0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x33, 0x3a, 0x34, 0x38, 0x3a,
+    0x61, 0x30, 0x3a, 0x65, 0x39, 0x3a, 0x34, 0x34, 0x3a, 0x34, 0x63, 0x3a,
+    0x37, 0x38, 0x3a, 0x63, 0x62, 0x3a, 0x32, 0x36, 0x3a, 0x35, 0x65, 0x3a,
+    0x30, 0x35, 0x3a, 0x38, 0x64, 0x3a, 0x35, 0x65, 0x3a, 0x38, 0x39, 0x3a,
+    0x34, 0x34, 0x3a, 0x62, 0x34, 0x3a, 0x64, 0x38, 0x3a, 0x34, 0x66, 0x3a,
+    0x39, 0x36, 0x3a, 0x36, 0x32, 0x3a, 0x62, 0x64, 0x3a, 0x32, 0x36, 0x3a,
+    0x64, 0x62, 0x3a, 0x32, 0x35, 0x3a, 0x37, 0x66, 0x3a, 0x38, 0x39, 0x3a,
+    0x33, 0x34, 0x3a, 0x61, 0x34, 0x3a, 0x34, 0x33, 0x3a, 0x63, 0x37, 0x3a,
+    0x30, 0x31, 0x3a, 0x36, 0x31, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42,
+    0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49,
+    0x49, 0x44, 0x72, 0x7a, 0x43, 0x43, 0x41, 0x70, 0x65, 0x67, 0x41, 0x77,
+    0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x43, 0x44, 0x76, 0x67, 0x56, 0x70,
+    0x42, 0x43, 0x52, 0x72, 0x47, 0x68, 0x64, 0x57, 0x72, 0x4a, 0x57, 0x5a,
+    0x48, 0x48, 0x53, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b,
+    0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44,
+    0x42, 0x68, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x56, 0x4d,
+    0x42, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4d, 0x52,
+    0x47, 0x6c, 0x6e, 0x61, 0x55, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x67, 0x53,
+    0x57, 0x35, 0x6a, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x4c, 0x45, 0x78, 0x42, 0x33, 0x0a, 0x64, 0x33, 0x63, 0x75,
+    0x5a, 0x47, 0x6c, 0x6e, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x75,
+    0x59, 0x32, 0x39, 0x74, 0x4d, 0x53, 0x41, 0x77, 0x48, 0x67, 0x59, 0x44,
+    0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x64, 0x45, 0x61, 0x57, 0x64, 0x70,
+    0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69,
+    0x59, 0x57, 0x77, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44,
+    0x0a, 0x51, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, 0x77, 0x4e, 0x6a, 0x45,
+    0x78, 0x4d, 0x54, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x42,
+    0x61, 0x46, 0x77, 0x30, 0x7a, 0x4d, 0x54, 0x45, 0x78, 0x4d, 0x54, 0x41,
+    0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x42, 0x61, 0x4d, 0x47, 0x45,
+    0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59,
+    0x54, 0x41, 0x6c, 0x56, 0x54, 0x0a, 0x4d, 0x52, 0x55, 0x77, 0x45, 0x77,
+    0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x78, 0x45, 0x61, 0x57,
+    0x64, 0x70, 0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x42, 0x4a, 0x62, 0x6d,
+    0x4d, 0x78, 0x47, 0x54, 0x41, 0x58, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41,
+    0x73, 0x54, 0x45, 0x48, 0x64, 0x33, 0x64, 0x79, 0x35, 0x6b, 0x61, 0x57,
+    0x64, 0x70, 0x59, 0x32, 0x56, 0x79, 0x64, 0x43, 0x35, 0x6a, 0x0a, 0x62,
+    0x32, 0x30, 0x78, 0x49, 0x44, 0x41, 0x65, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x4d, 0x54, 0x46, 0x30, 0x52, 0x70, 0x5a, 0x32, 0x6c, 0x44, 0x5a,
+    0x58, 0x4a, 0x30, 0x49, 0x45, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62,
+    0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d,
+    0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68,
+    0x6b, 0x69, 0x47, 0x0a, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46,
+    0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42,
+    0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x34, 0x6a, 0x76, 0x68,
+    0x45, 0x58, 0x4c, 0x65, 0x71, 0x4b, 0x54, 0x54, 0x6f, 0x31, 0x65, 0x71,
+    0x55, 0x4b, 0x4b, 0x50, 0x43, 0x33, 0x65, 0x51, 0x79, 0x61, 0x4b, 0x6c,
+    0x37, 0x68, 0x4c, 0x4f, 0x6c, 0x6c, 0x73, 0x42, 0x0a, 0x43, 0x53, 0x44,
+    0x4d, 0x41, 0x5a, 0x4f, 0x6e, 0x54, 0x6a, 0x43, 0x33, 0x55, 0x2f, 0x64,
+    0x44, 0x78, 0x47, 0x6b, 0x41, 0x56, 0x35, 0x33, 0x69, 0x6a, 0x53, 0x4c,
+    0x64, 0x68, 0x77, 0x5a, 0x41, 0x41, 0x49, 0x45, 0x4a, 0x7a, 0x73, 0x34,
+    0x62, 0x67, 0x37, 0x2f, 0x66, 0x7a, 0x54, 0x74, 0x78, 0x52, 0x75, 0x4c,
+    0x57, 0x5a, 0x73, 0x63, 0x46, 0x73, 0x33, 0x59, 0x6e, 0x46, 0x6f, 0x39,
+    0x37, 0x0a, 0x6e, 0x68, 0x36, 0x56, 0x66, 0x65, 0x36, 0x33, 0x53, 0x4b,
+    0x4d, 0x49, 0x32, 0x74, 0x61, 0x76, 0x65, 0x67, 0x77, 0x35, 0x42, 0x6d,
+    0x56, 0x2f, 0x53, 0x6c, 0x30, 0x66, 0x76, 0x42, 0x66, 0x34, 0x71, 0x37,
+    0x37, 0x75, 0x4b, 0x4e, 0x64, 0x30, 0x66, 0x33, 0x70, 0x34, 0x6d, 0x56,
+    0x6d, 0x46, 0x61, 0x47, 0x35, 0x63, 0x49, 0x7a, 0x4a, 0x4c, 0x76, 0x30,
+    0x37, 0x41, 0x36, 0x46, 0x70, 0x74, 0x0a, 0x34, 0x33, 0x43, 0x2f, 0x64,
+    0x78, 0x43, 0x2f, 0x2f, 0x41, 0x48, 0x32, 0x68, 0x64, 0x6d, 0x6f, 0x52,
+    0x42, 0x42, 0x59, 0x4d, 0x71, 0x6c, 0x31, 0x47, 0x4e, 0x58, 0x52, 0x6f,
+    0x72, 0x35, 0x48, 0x34, 0x69, 0x64, 0x71, 0x39, 0x4a, 0x6f, 0x7a, 0x2b,
+    0x45, 0x6b, 0x49, 0x59, 0x49, 0x76, 0x55, 0x58, 0x37, 0x51, 0x36, 0x68,
+    0x4c, 0x2b, 0x68, 0x71, 0x6b, 0x70, 0x4d, 0x66, 0x54, 0x37, 0x50, 0x0a,
+    0x54, 0x31, 0x39, 0x73, 0x64, 0x6c, 0x36, 0x67, 0x53, 0x7a, 0x65, 0x52,
+    0x6e, 0x74, 0x77, 0x69, 0x35, 0x6d, 0x33, 0x4f, 0x46, 0x42, 0x71, 0x4f,
+    0x61, 0x73, 0x76, 0x2b, 0x7a, 0x62, 0x4d, 0x55, 0x5a, 0x42, 0x66, 0x48,
+    0x57, 0x79, 0x6d, 0x65, 0x4d, 0x72, 0x2f, 0x79, 0x37, 0x76, 0x72, 0x54,
+    0x43, 0x30, 0x4c, 0x55, 0x71, 0x37, 0x64, 0x42, 0x4d, 0x74, 0x6f, 0x4d,
+    0x31, 0x4f, 0x2f, 0x34, 0x0a, 0x67, 0x64, 0x57, 0x37, 0x6a, 0x56, 0x67,
+    0x2f, 0x74, 0x52, 0x76, 0x6f, 0x53, 0x53, 0x69, 0x69, 0x63, 0x4e, 0x6f,
+    0x78, 0x42, 0x4e, 0x33, 0x33, 0x73, 0x68, 0x62, 0x79, 0x54, 0x41, 0x70,
+    0x4f, 0x42, 0x36, 0x6a, 0x74, 0x53, 0x6a, 0x31, 0x65, 0x74, 0x58, 0x2b,
+    0x6a, 0x6b, 0x4d, 0x4f, 0x76, 0x4a, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41,
+    0x42, 0x6f, 0x32, 0x4d, 0x77, 0x59, 0x54, 0x41, 0x4f, 0x0a, 0x42, 0x67,
+    0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41,
+    0x4d, 0x43, 0x41, 0x59, 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52,
+    0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77,
+    0x45, 0x42, 0x2f, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51,
+    0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x41, 0x39, 0x35, 0x51, 0x4e, 0x56,
+    0x62, 0x52, 0x0a, 0x54, 0x4c, 0x74, 0x6d, 0x38, 0x4b, 0x50, 0x69, 0x47,
+    0x78, 0x76, 0x44, 0x6c, 0x37, 0x49, 0x39, 0x30, 0x56, 0x55, 0x77, 0x48,
+    0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46,
+    0x6f, 0x41, 0x55, 0x41, 0x39, 0x35, 0x51, 0x4e, 0x56, 0x62, 0x52, 0x54,
+    0x4c, 0x74, 0x6d, 0x38, 0x4b, 0x50, 0x69, 0x47, 0x78, 0x76, 0x44, 0x6c,
+    0x37, 0x49, 0x39, 0x30, 0x56, 0x55, 0x77, 0x0a, 0x44, 0x51, 0x59, 0x4a,
+    0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46,
+    0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4d, 0x75, 0x63,
+    0x4e, 0x36, 0x70, 0x49, 0x45, 0x78, 0x49, 0x4b, 0x2b, 0x74, 0x31, 0x45,
+    0x6e, 0x45, 0x39, 0x53, 0x73, 0x50, 0x54, 0x66, 0x72, 0x67, 0x54, 0x31,
+    0x65, 0x58, 0x6b, 0x49, 0x6f, 0x79, 0x51, 0x59, 0x2f, 0x45, 0x73, 0x72,
+    0x0a, 0x68, 0x4d, 0x41, 0x74, 0x75, 0x64, 0x58, 0x48, 0x2f, 0x76, 0x54,
+    0x42, 0x48, 0x31, 0x6a, 0x4c, 0x75, 0x47, 0x32, 0x63, 0x65, 0x6e, 0x54,
+    0x6e, 0x6d, 0x43, 0x6d, 0x72, 0x45, 0x62, 0x58, 0x6a, 0x63, 0x4b, 0x43,
+    0x68, 0x7a, 0x55, 0x79, 0x49, 0x6d, 0x5a, 0x4f, 0x4d, 0x6b, 0x58, 0x44,
+    0x69, 0x71, 0x77, 0x38, 0x63, 0x76, 0x70, 0x4f, 0x70, 0x2f, 0x32, 0x50,
+    0x56, 0x35, 0x41, 0x64, 0x67, 0x0a, 0x30, 0x36, 0x4f, 0x2f, 0x6e, 0x56,
+    0x73, 0x4a, 0x38, 0x64, 0x57, 0x4f, 0x34, 0x31, 0x50, 0x30, 0x6a, 0x6d,
+    0x50, 0x36, 0x50, 0x36, 0x66, 0x62, 0x74, 0x47, 0x62, 0x66, 0x59, 0x6d,
+    0x62, 0x57, 0x30, 0x57, 0x35, 0x42, 0x6a, 0x66, 0x49, 0x74, 0x74, 0x65,
+    0x70, 0x33, 0x53, 0x70, 0x2b, 0x64, 0x57, 0x4f, 0x49, 0x72, 0x57, 0x63,
+    0x42, 0x41, 0x49, 0x2b, 0x30, 0x74, 0x4b, 0x49, 0x4a, 0x46, 0x0a, 0x50,
+    0x6e, 0x6c, 0x55, 0x6b, 0x69, 0x61, 0x59, 0x34, 0x49, 0x42, 0x49, 0x71,
+    0x44, 0x66, 0x76, 0x38, 0x4e, 0x5a, 0x35, 0x59, 0x42, 0x62, 0x65, 0x72,
+    0x4f, 0x67, 0x4f, 0x7a, 0x57, 0x36, 0x73, 0x52, 0x42, 0x63, 0x34, 0x4c,
+    0x30, 0x6e, 0x61, 0x34, 0x55, 0x55, 0x2b, 0x4b, 0x72, 0x6b, 0x32, 0x55,
+    0x38, 0x38, 0x36, 0x55, 0x41, 0x62, 0x33, 0x4c, 0x75, 0x6a, 0x45, 0x56,
+    0x30, 0x6c, 0x73, 0x0a, 0x59, 0x53, 0x45, 0x59, 0x31, 0x51, 0x53, 0x74,
+    0x65, 0x44, 0x77, 0x73, 0x4f, 0x6f, 0x42, 0x72, 0x70, 0x2b, 0x75, 0x76,
+    0x46, 0x52, 0x54, 0x70, 0x32, 0x49, 0x6e, 0x42, 0x75, 0x54, 0x68, 0x73,
+    0x34, 0x70, 0x46, 0x73, 0x69, 0x76, 0x39, 0x6b, 0x75, 0x58, 0x63, 0x6c,
+    0x56, 0x7a, 0x44, 0x41, 0x47, 0x79, 0x53, 0x6a, 0x34, 0x64, 0x7a, 0x70,
+    0x33, 0x30, 0x64, 0x38, 0x74, 0x62, 0x51, 0x6b, 0x0a, 0x43, 0x41, 0x55,
+    0x77, 0x37, 0x43, 0x32, 0x39, 0x43, 0x37, 0x39, 0x46, 0x76, 0x31, 0x43,
+    0x35, 0x71, 0x66, 0x50, 0x72, 0x6d, 0x41, 0x45, 0x53, 0x72, 0x63, 0x69,
+    0x49, 0x78, 0x70, 0x67, 0x30, 0x58, 0x34, 0x30, 0x4b, 0x50, 0x4d, 0x62,
+    0x70, 0x31, 0x5a, 0x57, 0x56, 0x62, 0x64, 0x34, 0x3d, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49,
+    0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a,
+    0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43,
+    0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48,
+    0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63,
+    0x65, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
+    0x20, 0x4f, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20,
+    0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64,
+    0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a,
+    0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43,
+    0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48,
+    0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63,
+    0x65, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
+    0x20, 0x4f, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20,
+    0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64,
+    0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a,
+    0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x44, 0x69,
+    0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48, 0x69, 0x67, 0x68, 0x20,
+    0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x45, 0x56,
+    0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20,
+    0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x33, 0x35, 0x35, 0x33,
+    0x34, 0x30, 0x30, 0x30, 0x37, 0x36, 0x34, 0x31, 0x30, 0x35, 0x34, 0x37,
+    0x39, 0x31, 0x39, 0x37, 0x32, 0x34, 0x37, 0x33, 0x30, 0x37, 0x33, 0x34,
+    0x33, 0x37, 0x38, 0x31, 0x30, 0x30, 0x30, 0x38, 0x37, 0x0a, 0x23, 0x20,
+    0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x34, 0x3a, 0x37, 0x34, 0x3a, 0x64,
+    0x65, 0x3a, 0x35, 0x37, 0x3a, 0x35, 0x63, 0x3a, 0x33, 0x39, 0x3a, 0x62,
+    0x32, 0x3a, 0x64, 0x33, 0x3a, 0x39, 0x63, 0x3a, 0x38, 0x35, 0x3a, 0x38,
+    0x33, 0x3a, 0x63, 0x35, 0x3a, 0x63, 0x30, 0x3a, 0x36, 0x35, 0x3a, 0x34,
+    0x39, 0x3a, 0x38, 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x35, 0x66, 0x3a, 0x62, 0x37, 0x3a, 0x65, 0x65, 0x3a, 0x30, 0x36,
+    0x3a, 0x33, 0x33, 0x3a, 0x65, 0x32, 0x3a, 0x35, 0x39, 0x3a, 0x64, 0x62,
+    0x3a, 0x61, 0x64, 0x3a, 0x30, 0x63, 0x3a, 0x34, 0x63, 0x3a, 0x39, 0x61,
+    0x3a, 0x65, 0x36, 0x3a, 0x64, 0x33, 0x3a, 0x38, 0x66, 0x3a, 0x31, 0x61,
+    0x3a, 0x36, 0x31, 0x3a, 0x63, 0x37, 0x3a, 0x64, 0x63, 0x3a, 0x32, 0x35,
+    0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69,
+    0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37,
+    0x34, 0x3a, 0x33, 0x31, 0x3a, 0x65, 0x35, 0x3a, 0x66, 0x34, 0x3a, 0x63,
+    0x33, 0x3a, 0x63, 0x31, 0x3a, 0x63, 0x65, 0x3a, 0x34, 0x36, 0x3a, 0x39,
+    0x30, 0x3a, 0x37, 0x37, 0x3a, 0x34, 0x66, 0x3a, 0x30, 0x62, 0x3a, 0x36,
+    0x31, 0x3a, 0x65, 0x30, 0x3a, 0x35, 0x34, 0x3a, 0x34, 0x30, 0x3a, 0x38,
+    0x38, 0x3a, 0x33, 0x62, 0x3a, 0x61, 0x39, 0x3a, 0x61, 0x30, 0x3a, 0x31,
+    0x65, 0x3a, 0x64, 0x30, 0x3a, 0x30, 0x62, 0x3a, 0x61, 0x36, 0x3a, 0x61,
+    0x62, 0x3a, 0x64, 0x37, 0x3a, 0x38, 0x30, 0x3a, 0x36, 0x65, 0x3a, 0x64,
+    0x33, 0x3a, 0x62, 0x31, 0x3a, 0x31, 0x38, 0x3a, 0x63, 0x66, 0x0a, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45,
+    0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x78, 0x54, 0x43, 0x43, 0x41,
+    0x71, 0x32, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x41,
+    0x71, 0x78, 0x63, 0x4a, 0x6d, 0x6f, 0x4c, 0x51, 0x4a, 0x75, 0x50, 0x43,
+    0x33, 0x6e, 0x79, 0x72, 0x6b, 0x59, 0x6c, 0x64, 0x7a, 0x41, 0x4e, 0x42,
+    0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41,
+    0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x73, 0x0a, 0x4d, 0x51, 0x73, 0x77,
+    0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56,
+    0x55, 0x7a, 0x45, 0x56, 0x4d, 0x42, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x43, 0x68, 0x4d, 0x4d, 0x52, 0x47, 0x6c, 0x6e, 0x61, 0x55, 0x4e, 0x6c,
+    0x63, 0x6e, 0x51, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d, 0x52, 0x6b, 0x77,
+    0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x42, 0x33,
+    0x0a, 0x64, 0x33, 0x63, 0x75, 0x5a, 0x47, 0x6c, 0x6e, 0x61, 0x57, 0x4e,
+    0x6c, 0x63, 0x6e, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4d, 0x53, 0x73,
+    0x77, 0x4b, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x79, 0x4a,
+    0x45, 0x61, 0x57, 0x64, 0x70, 0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x42,
+    0x49, 0x61, 0x57, 0x64, 0x6f, 0x49, 0x45, 0x46, 0x7a, 0x63, 0x33, 0x56,
+    0x79, 0x59, 0x57, 0x35, 0x6a, 0x0a, 0x5a, 0x53, 0x42, 0x46, 0x56, 0x69,
+    0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x42,
+    0x34, 0x58, 0x44, 0x54, 0x41, 0x32, 0x4d, 0x54, 0x45, 0x78, 0x4d, 0x44,
+    0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54,
+    0x4d, 0x78, 0x4d, 0x54, 0x45, 0x78, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44,
+    0x41, 0x77, 0x4d, 0x46, 0x6f, 0x77, 0x62, 0x44, 0x45, 0x4c, 0x0a, 0x4d,
+    0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56,
+    0x56, 0x4d, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x6f, 0x54, 0x44, 0x45, 0x52, 0x70, 0x5a, 0x32, 0x6c, 0x44, 0x5a,
+    0x58, 0x4a, 0x30, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x7a, 0x45, 0x5a, 0x4d,
+    0x42, 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x51, 0x64,
+    0x33, 0x64, 0x33, 0x0a, 0x4c, 0x6d, 0x52, 0x70, 0x5a, 0x32, 0x6c, 0x6a,
+    0x5a, 0x58, 0x4a, 0x30, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x54, 0x45, 0x72,
+    0x4d, 0x43, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x69,
+    0x52, 0x47, 0x6c, 0x6e, 0x61, 0x55, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x67,
+    0x53, 0x47, 0x6c, 0x6e, 0x61, 0x43, 0x42, 0x42, 0x63, 0x33, 0x4e, 0x31,
+    0x63, 0x6d, 0x46, 0x75, 0x59, 0x32, 0x55, 0x67, 0x0a, 0x52, 0x56, 0x59,
+    0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x54, 0x43,
+    0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a,
+    0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41,
+    0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f,
+    0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4d, 0x62, 0x4d, 0x35, 0x58, 0x50,
+    0x6d, 0x0a, 0x2b, 0x39, 0x53, 0x37, 0x35, 0x53, 0x30, 0x74, 0x4d, 0x71,
+    0x62, 0x66, 0x35, 0x59, 0x45, 0x2f, 0x79, 0x63, 0x30, 0x6c, 0x53, 0x62,
+    0x5a, 0x78, 0x4b, 0x73, 0x50, 0x56, 0x6c, 0x44, 0x52, 0x6e, 0x6f, 0x67,
+    0x6f, 0x63, 0x73, 0x46, 0x39, 0x70, 0x70, 0x6b, 0x43, 0x78, 0x78, 0x4c,
+    0x65, 0x79, 0x6a, 0x39, 0x43, 0x59, 0x70, 0x4b, 0x6c, 0x42, 0x57, 0x54,
+    0x72, 0x54, 0x33, 0x4a, 0x54, 0x57, 0x0a, 0x50, 0x4e, 0x74, 0x30, 0x4f,
+    0x4b, 0x52, 0x4b, 0x7a, 0x45, 0x30, 0x6c, 0x67, 0x76, 0x64, 0x4b, 0x70,
+    0x56, 0x4d, 0x53, 0x4f, 0x4f, 0x37, 0x7a, 0x53, 0x57, 0x31, 0x78, 0x6b,
+    0x58, 0x35, 0x6a, 0x74, 0x71, 0x75, 0x6d, 0x58, 0x38, 0x4f, 0x6b, 0x68,
+    0x50, 0x68, 0x50, 0x59, 0x6c, 0x47, 0x2b, 0x2b, 0x4d, 0x58, 0x73, 0x32,
+    0x7a, 0x69, 0x53, 0x34, 0x77, 0x62, 0x6c, 0x43, 0x4a, 0x45, 0x4d, 0x0a,
+    0x78, 0x43, 0x68, 0x42, 0x56, 0x66, 0x76, 0x4c, 0x57, 0x6f, 0x6b, 0x56,
+    0x66, 0x6e, 0x48, 0x6f, 0x4e, 0x62, 0x39, 0x4e, 0x63, 0x67, 0x6b, 0x39,
+    0x76, 0x6a, 0x6f, 0x34, 0x55, 0x46, 0x74, 0x33, 0x4d, 0x52, 0x75, 0x4e,
+    0x73, 0x38, 0x63, 0x6b, 0x52, 0x5a, 0x71, 0x6e, 0x72, 0x47, 0x30, 0x41,
+    0x46, 0x46, 0x6f, 0x45, 0x74, 0x37, 0x6f, 0x54, 0x36, 0x31, 0x45, 0x4b,
+    0x6d, 0x45, 0x46, 0x42, 0x0a, 0x49, 0x6b, 0x35, 0x6c, 0x59, 0x59, 0x65,
+    0x42, 0x51, 0x56, 0x43, 0x6d, 0x65, 0x56, 0x79, 0x4a, 0x33, 0x68, 0x6c,
+    0x4b, 0x56, 0x39, 0x55, 0x75, 0x35, 0x6c, 0x30, 0x63, 0x55, 0x79, 0x78,
+    0x2b, 0x6d, 0x4d, 0x30, 0x61, 0x42, 0x68, 0x61, 0x6b, 0x61, 0x48, 0x50,
+    0x51, 0x4e, 0x41, 0x51, 0x54, 0x58, 0x4b, 0x46, 0x78, 0x30, 0x31, 0x70,
+    0x38, 0x56, 0x64, 0x74, 0x65, 0x5a, 0x4f, 0x45, 0x33, 0x0a, 0x68, 0x7a,
+    0x42, 0x57, 0x42, 0x4f, 0x55, 0x52, 0x74, 0x43, 0x6d, 0x41, 0x45, 0x76,
+    0x46, 0x35, 0x4f, 0x59, 0x69, 0x69, 0x41, 0x68, 0x46, 0x38, 0x4a, 0x32,
+    0x61, 0x33, 0x69, 0x4c, 0x64, 0x34, 0x38, 0x73, 0x6f, 0x4b, 0x71, 0x44,
+    0x69, 0x72, 0x43, 0x6d, 0x54, 0x43, 0x76, 0x32, 0x5a, 0x64, 0x6c, 0x59,
+    0x54, 0x42, 0x6f, 0x53, 0x55, 0x65, 0x68, 0x31, 0x30, 0x61, 0x55, 0x41,
+    0x73, 0x67, 0x0a, 0x45, 0x73, 0x78, 0x42, 0x75, 0x32, 0x34, 0x4c, 0x55,
+    0x54, 0x69, 0x34, 0x53, 0x38, 0x73, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41,
+    0x61, 0x4e, 0x6a, 0x4d, 0x47, 0x45, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56,
+    0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41,
+    0x67, 0x47, 0x47, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45,
+    0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x0a, 0x4d, 0x41, 0x4d, 0x42,
+    0x41, 0x66, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f,
+    0x42, 0x42, 0x59, 0x45, 0x46, 0x4c, 0x45, 0x2b, 0x77, 0x32, 0x6b, 0x44,
+    0x2b, 0x4c, 0x39, 0x48, 0x41, 0x64, 0x53, 0x59, 0x4a, 0x68, 0x6f, 0x49,
+    0x41, 0x75, 0x39, 0x6a, 0x5a, 0x43, 0x76, 0x44, 0x4d, 0x42, 0x38, 0x47,
+    0x41, 0x31, 0x55, 0x64, 0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, 0x61, 0x41,
+    0x0a, 0x46, 0x4c, 0x45, 0x2b, 0x77, 0x32, 0x6b, 0x44, 0x2b, 0x4c, 0x39,
+    0x48, 0x41, 0x64, 0x53, 0x59, 0x4a, 0x68, 0x6f, 0x49, 0x41, 0x75, 0x39,
+    0x6a, 0x5a, 0x43, 0x76, 0x44, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71,
+    0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55,
+    0x41, 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x41, 0x63, 0x47, 0x67, 0x61,
+    0x58, 0x33, 0x4e, 0x65, 0x63, 0x0a, 0x6e, 0x7a, 0x79, 0x49, 0x5a, 0x67,
+    0x59, 0x49, 0x56, 0x79, 0x48, 0x62, 0x49, 0x55, 0x66, 0x34, 0x4b, 0x6d,
+    0x65, 0x71, 0x76, 0x78, 0x67, 0x79, 0x64, 0x6b, 0x41, 0x51, 0x56, 0x38,
+    0x47, 0x4b, 0x38, 0x33, 0x72, 0x5a, 0x45, 0x57, 0x57, 0x4f, 0x4e, 0x66,
+    0x71, 0x65, 0x2f, 0x45, 0x57, 0x31, 0x6e, 0x74, 0x6c, 0x4d, 0x4d, 0x55,
+    0x75, 0x34, 0x6b, 0x65, 0x68, 0x44, 0x4c, 0x49, 0x36, 0x7a, 0x0a, 0x65,
+    0x4d, 0x37, 0x62, 0x34, 0x31, 0x4e, 0x35, 0x63, 0x64, 0x62, 0x6c, 0x49,
+    0x5a, 0x51, 0x42, 0x32, 0x6c, 0x57, 0x48, 0x6d, 0x69, 0x52, 0x6b, 0x39,
+    0x6f, 0x70, 0x6d, 0x7a, 0x4e, 0x36, 0x63, 0x4e, 0x38, 0x32, 0x6f, 0x4e,
+    0x4c, 0x46, 0x70, 0x6d, 0x79, 0x50, 0x49, 0x6e, 0x6e, 0x67, 0x69, 0x4b,
+    0x33, 0x42, 0x44, 0x34, 0x31, 0x56, 0x48, 0x4d, 0x57, 0x45, 0x5a, 0x37,
+    0x31, 0x6a, 0x46, 0x0a, 0x68, 0x53, 0x39, 0x4f, 0x4d, 0x50, 0x61, 0x67,
+    0x4d, 0x52, 0x59, 0x6a, 0x79, 0x4f, 0x66, 0x69, 0x5a, 0x52, 0x59, 0x7a,
+    0x79, 0x37, 0x38, 0x61, 0x47, 0x36, 0x41, 0x39, 0x2b, 0x4d, 0x70, 0x65,
+    0x69, 0x7a, 0x47, 0x4c, 0x59, 0x41, 0x69, 0x4a, 0x4c, 0x51, 0x77, 0x47,
+    0x58, 0x46, 0x4b, 0x33, 0x78, 0x50, 0x6b, 0x4b, 0x6d, 0x4e, 0x45, 0x56,
+    0x58, 0x35, 0x38, 0x53, 0x76, 0x6e, 0x77, 0x32, 0x0a, 0x59, 0x7a, 0x69,
+    0x39, 0x52, 0x4b, 0x52, 0x2f, 0x35, 0x43, 0x59, 0x72, 0x43, 0x73, 0x53,
+    0x58, 0x61, 0x51, 0x33, 0x70, 0x6a, 0x4f, 0x4c, 0x41, 0x45, 0x46, 0x65,
+    0x34, 0x79, 0x48, 0x59, 0x53, 0x6b, 0x56, 0x58, 0x79, 0x53, 0x47, 0x6e,
+    0x59, 0x76, 0x43, 0x6f, 0x43, 0x57, 0x77, 0x39, 0x45, 0x31, 0x43, 0x41,
+    0x78, 0x32, 0x2f, 0x53, 0x36, 0x63, 0x43, 0x5a, 0x64, 0x6b, 0x47, 0x43,
+    0x65, 0x0a, 0x76, 0x45, 0x73, 0x58, 0x43, 0x53, 0x2b, 0x30, 0x79, 0x78,
+    0x35, 0x44, 0x61, 0x4d, 0x6b, 0x48, 0x4a, 0x38, 0x48, 0x53, 0x58, 0x50,
+    0x66, 0x71, 0x49, 0x62, 0x6c, 0x6f, 0x45, 0x70, 0x77, 0x38, 0x6e, 0x4c,
+    0x2b, 0x65, 0x2f, 0x49, 0x42, 0x63, 0x6d, 0x32, 0x50, 0x4e, 0x37, 0x45,
+    0x65, 0x71, 0x4a, 0x53, 0x64, 0x6e, 0x6f, 0x44, 0x66, 0x7a, 0x41, 0x49,
+    0x4a, 0x39, 0x56, 0x4e, 0x65, 0x70, 0x0a, 0x2b, 0x4f, 0x6b, 0x75, 0x45,
+    0x36, 0x4e, 0x33, 0x36, 0x42, 0x39, 0x4b, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23,
+    0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d,
+    0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69,
+    0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+    0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+    0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72,
+    0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53,
+    0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47,
+    0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, 0x6d,
+    0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+    0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+    0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75,
+    0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61,
+    0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75,
+    0x73, 0x74, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43,
+    0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+    0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a,
+    0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x33, 0x32,
+    0x37, 0x39, 0x38, 0x32, 0x32, 0x36, 0x35, 0x35, 0x31, 0x32, 0x35, 0x36,
+    0x39, 0x36, 0x33, 0x33, 0x32, 0x34, 0x33, 0x31, 0x33, 0x38, 0x30, 0x36,
+    0x34, 0x33, 0x36, 0x39, 0x38, 0x31, 0x39, 0x38, 0x32, 0x33, 0x36, 0x39,
+    0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x32, 0x3a, 0x32,
+    0x36, 0x3a, 0x63, 0x33, 0x3a, 0x30, 0x31, 0x3a, 0x35, 0x65, 0x3a, 0x30,
+    0x38, 0x3a, 0x33, 0x30, 0x3a, 0x33, 0x37, 0x3a, 0x34, 0x33, 0x3a, 0x61,
+    0x39, 0x3a, 0x64, 0x30, 0x3a, 0x37, 0x64, 0x3a, 0x63, 0x66, 0x3a, 0x33,
+    0x37, 0x3a, 0x65, 0x36, 0x3a, 0x62, 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48,
+    0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x33, 0x32, 0x3a, 0x33, 0x63, 0x3a, 0x31, 0x31,
+    0x3a, 0x38, 0x65, 0x3a, 0x31, 0x62, 0x3a, 0x66, 0x37, 0x3a, 0x62, 0x38,
+    0x3a, 0x62, 0x36, 0x3a, 0x35, 0x32, 0x3a, 0x35, 0x34, 0x3a, 0x65, 0x32,
+    0x3a, 0x65, 0x32, 0x3a, 0x31, 0x30, 0x3a, 0x30, 0x64, 0x3a, 0x64, 0x36,
+    0x3a, 0x30, 0x32, 0x3a, 0x39, 0x30, 0x3a, 0x33, 0x37, 0x3a, 0x66, 0x30,
+    0x3a, 0x39, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x33, 0x37, 0x3a, 0x64, 0x35, 0x3a, 0x31, 0x30, 0x3a, 0x30,
+    0x36, 0x3a, 0x63, 0x35, 0x3a, 0x31, 0x32, 0x3a, 0x65, 0x61, 0x3a, 0x61,
+    0x62, 0x3a, 0x36, 0x32, 0x3a, 0x36, 0x34, 0x3a, 0x32, 0x31, 0x3a, 0x66,
+    0x31, 0x3a, 0x65, 0x63, 0x3a, 0x38, 0x63, 0x3a, 0x39, 0x32, 0x3a, 0x30,
+    0x31, 0x3a, 0x33, 0x66, 0x3a, 0x63, 0x35, 0x3a, 0x66, 0x38, 0x3a, 0x32,
+    0x61, 0x3a, 0x65, 0x39, 0x3a, 0x38, 0x65, 0x3a, 0x65, 0x35, 0x3a, 0x33,
+    0x33, 0x3a, 0x65, 0x62, 0x3a, 0x34, 0x36, 0x3a, 0x31, 0x39, 0x3a, 0x62,
+    0x38, 0x3a, 0x64, 0x65, 0x3a, 0x62, 0x34, 0x3a, 0x64, 0x30, 0x3a, 0x36,
+    0x63, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x66, 0x44,
+    0x43, 0x43, 0x41, 0x6d, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67,
+    0x49, 0x51, 0x47, 0x4b, 0x79, 0x31, 0x61, 0x76, 0x31, 0x70, 0x74, 0x68,
+    0x55, 0x36, 0x59, 0x32, 0x79, 0x76, 0x32, 0x76, 0x72, 0x45, 0x6f, 0x54,
+    0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77,
+    0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x59, 0x0a, 0x4d,
+    0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45,
+    0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x57, 0x4d, 0x42, 0x51, 0x47, 0x41,
+    0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4e, 0x52, 0x32, 0x56, 0x76, 0x56,
+    0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c,
+    0x6a, 0x45, 0x78, 0x4d, 0x43, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41,
+    0x78, 0x4d, 0x6f, 0x0a, 0x52, 0x32, 0x56, 0x76, 0x56, 0x48, 0x4a, 0x31,
+    0x63, 0x33, 0x51, 0x67, 0x55, 0x48, 0x4a, 0x70, 0x62, 0x57, 0x46, 0x79,
+    0x65, 0x53, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70,
+    0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, 0x31,
+    0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, 0x41, 0x65,
+    0x46, 0x77, 0x30, 0x77, 0x4e, 0x6a, 0x45, 0x78, 0x0a, 0x4d, 0x6a, 0x63,
+    0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30,
+    0x7a, 0x4e, 0x6a, 0x41, 0x33, 0x4d, 0x54, 0x59, 0x79, 0x4d, 0x7a, 0x55,
+    0x35, 0x4e, 0x54, 0x6c, 0x61, 0x4d, 0x46, 0x67, 0x78, 0x43, 0x7a, 0x41,
+    0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56,
+    0x54, 0x4d, 0x52, 0x59, 0x77, 0x46, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x4b, 0x0a, 0x45, 0x77, 0x31, 0x48, 0x5a, 0x57, 0x39, 0x55, 0x63, 0x6e,
+    0x56, 0x7a, 0x64, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x54,
+    0x45, 0x77, 0x4c, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x79,
+    0x68, 0x48, 0x5a, 0x57, 0x39, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43,
+    0x42, 0x51, 0x63, 0x6d, 0x6c, 0x74, 0x59, 0x58, 0x4a, 0x35, 0x49, 0x45,
+    0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x0a, 0x5a, 0x6d, 0x6c, 0x6a, 0x59,
+    0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61,
+    0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x49, 0x49, 0x42, 0x49,
+    0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39,
+    0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41,
+    0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x0a,
+    0x41, 0x51, 0x45, 0x41, 0x76, 0x72, 0x67, 0x56, 0x65, 0x2f, 0x2f, 0x55,
+    0x66, 0x48, 0x31, 0x6e, 0x72, 0x59, 0x4e, 0x6b, 0x65, 0x38, 0x68, 0x43,
+    0x55, 0x79, 0x33, 0x66, 0x39, 0x6f, 0x51, 0x49, 0x49, 0x47, 0x48, 0x57,
+    0x41, 0x56, 0x6c, 0x71, 0x6e, 0x45, 0x51, 0x52, 0x72, 0x2b, 0x39, 0x32,
+    0x2f, 0x5a, 0x56, 0x2b, 0x7a, 0x6d, 0x45, 0x77, 0x75, 0x33, 0x71, 0x44,
+    0x58, 0x77, 0x4b, 0x39, 0x0a, 0x41, 0x57, 0x62, 0x4b, 0x37, 0x68, 0x57,
+    0x4e, 0x62, 0x36, 0x45, 0x77, 0x6e, 0x4c, 0x32, 0x68, 0x68, 0x5a, 0x36,
+    0x55, 0x4f, 0x76, 0x4e, 0x57, 0x69, 0x41, 0x41, 0x78, 0x7a, 0x39, 0x6a,
+    0x75, 0x61, 0x70, 0x59, 0x43, 0x32, 0x65, 0x30, 0x44, 0x6a, 0x50, 0x74,
+    0x31, 0x62, 0x65, 0x66, 0x71, 0x75, 0x46, 0x55, 0x57, 0x42, 0x52, 0x61,
+    0x61, 0x39, 0x4f, 0x42, 0x65, 0x73, 0x59, 0x6a, 0x41, 0x0a, 0x5a, 0x49,
+    0x56, 0x63, 0x46, 0x55, 0x32, 0x49, 0x78, 0x37, 0x65, 0x36, 0x34, 0x48,
+    0x58, 0x70, 0x72, 0x51, 0x55, 0x39, 0x6e, 0x63, 0x65, 0x4a, 0x53, 0x4f,
+    0x43, 0x37, 0x4b, 0x4d, 0x67, 0x44, 0x34, 0x54, 0x43, 0x54, 0x5a, 0x46,
+    0x35, 0x53, 0x77, 0x46, 0x6c, 0x77, 0x49, 0x6a, 0x56, 0x58, 0x69, 0x49,
+    0x72, 0x78, 0x6c, 0x51, 0x71, 0x44, 0x31, 0x37, 0x77, 0x78, 0x63, 0x77,
+    0x45, 0x30, 0x0a, 0x37, 0x65, 0x39, 0x47, 0x63, 0x65, 0x42, 0x72, 0x41,
+    0x71, 0x67, 0x31, 0x63, 0x6d, 0x75, 0x58, 0x6d, 0x32, 0x62, 0x67, 0x79,
+    0x78, 0x78, 0x35, 0x58, 0x39, 0x67, 0x61, 0x42, 0x47, 0x67, 0x65, 0x52,
+    0x77, 0x4c, 0x6d, 0x6e, 0x57, 0x44, 0x69, 0x4e, 0x70, 0x63, 0x42, 0x33,
+    0x38, 0x34, 0x31, 0x6b, 0x74, 0x2b, 0x2b, 0x5a, 0x38, 0x64, 0x74, 0x64,
+    0x31, 0x6b, 0x37, 0x6a, 0x35, 0x33, 0x57, 0x0a, 0x6b, 0x42, 0x57, 0x55,
+    0x76, 0x45, 0x49, 0x30, 0x45, 0x4d, 0x45, 0x35, 0x2b, 0x62, 0x45, 0x6e,
+    0x50, 0x6e, 0x37, 0x57, 0x69, 0x6e, 0x58, 0x46, 0x73, 0x71, 0x2b, 0x57,
+    0x30, 0x36, 0x4c, 0x65, 0x6d, 0x2b, 0x53, 0x59, 0x76, 0x6e, 0x33, 0x68,
+    0x36, 0x59, 0x47, 0x74, 0x74, 0x6d, 0x2f, 0x38, 0x31, 0x77, 0x37, 0x61,
+    0x34, 0x44, 0x53, 0x77, 0x44, 0x52, 0x70, 0x33, 0x35, 0x2b, 0x4d, 0x49,
+    0x0a, 0x6d, 0x4f, 0x39, 0x59, 0x2b, 0x70, 0x79, 0x45, 0x74, 0x7a, 0x61,
+    0x76, 0x77, 0x74, 0x2b, 0x73, 0x30, 0x76, 0x51, 0x51, 0x42, 0x6e, 0x42,
+    0x78, 0x4e, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49,
+    0x77, 0x51, 0x44, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d,
+    0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48,
+    0x2f, 0x4d, 0x41, 0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77,
+    0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a,
+    0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67,
+    0x51, 0x55, 0x4c, 0x4e, 0x56, 0x51, 0x51, 0x5a, 0x63, 0x56, 0x69, 0x2f,
+    0x43, 0x50, 0x4e, 0x6d, 0x46, 0x62, 0x53, 0x76, 0x74, 0x72, 0x32, 0x5a,
+    0x6e, 0x4a, 0x4d, 0x35, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x0a, 0x4b,
+    0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42,
+    0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x46, 0x70, 0x77, 0x66,
+    0x79, 0x7a, 0x64, 0x74, 0x7a, 0x52, 0x50, 0x39, 0x59, 0x5a, 0x52, 0x71,
+    0x53, 0x61, 0x2b, 0x53, 0x37, 0x69, 0x71, 0x38, 0x58, 0x45, 0x4e, 0x33,
+    0x47, 0x48, 0x48, 0x6f, 0x4f, 0x6f, 0x30, 0x48, 0x6e, 0x70, 0x33, 0x44,
+    0x77, 0x51, 0x31, 0x0a, 0x36, 0x43, 0x65, 0x50, 0x62, 0x4a, 0x43, 0x2f,
+    0x6b, 0x52, 0x59, 0x6b, 0x52, 0x6a, 0x35, 0x4b, 0x54, 0x73, 0x34, 0x72,
+    0x46, 0x74, 0x55, 0x4c, 0x55, 0x68, 0x33, 0x38, 0x48, 0x32, 0x65, 0x69,
+    0x41, 0x6b, 0x55, 0x78, 0x54, 0x38, 0x37, 0x7a, 0x2b, 0x67, 0x4f, 0x6e,
+    0x65, 0x5a, 0x31, 0x54, 0x61, 0x74, 0x6e, 0x61, 0x59, 0x7a, 0x72, 0x34,
+    0x67, 0x4e, 0x66, 0x54, 0x6d, 0x65, 0x47, 0x6c, 0x0a, 0x34, 0x62, 0x37,
+    0x55, 0x56, 0x58, 0x47, 0x59, 0x4e, 0x54, 0x71, 0x2b, 0x6b, 0x2b, 0x71,
+    0x75, 0x72, 0x55, 0x4b, 0x79, 0x6b, 0x47, 0x2f, 0x67, 0x2f, 0x43, 0x46,
+    0x4e, 0x4e, 0x57, 0x4d, 0x7a, 0x69, 0x55, 0x6e, 0x57, 0x6d, 0x30, 0x37,
+    0x4b, 0x78, 0x2b, 0x64, 0x4f, 0x43, 0x51, 0x44, 0x33, 0x32, 0x73, 0x66,
+    0x76, 0x6d, 0x57, 0x4b, 0x5a, 0x64, 0x37, 0x61, 0x56, 0x49, 0x6c, 0x36,
+    0x4b, 0x0a, 0x6f, 0x4b, 0x76, 0x30, 0x75, 0x48, 0x69, 0x59, 0x79, 0x6a,
+    0x67, 0x5a, 0x6d, 0x63, 0x6c, 0x79, 0x6e, 0x6e, 0x6a, 0x4e, 0x53, 0x36,
+    0x79, 0x76, 0x47, 0x61, 0x42, 0x7a, 0x45, 0x69, 0x33, 0x38, 0x77, 0x6b,
+    0x47, 0x36, 0x67, 0x5a, 0x48, 0x61, 0x46, 0x6c, 0x6f, 0x78, 0x74, 0x2f,
+    0x6d, 0x30, 0x63, 0x59, 0x41, 0x53, 0x53, 0x4a, 0x6c, 0x79, 0x63, 0x31,
+    0x70, 0x5a, 0x55, 0x38, 0x46, 0x6a, 0x0a, 0x55, 0x6a, 0x50, 0x74, 0x70,
+    0x38, 0x6e, 0x53, 0x4f, 0x51, 0x4a, 0x77, 0x2b, 0x75, 0x43, 0x78, 0x51,
+    0x6d, 0x59, 0x70, 0x71, 0x70, 0x74, 0x52, 0x37, 0x54, 0x42, 0x55, 0x49,
+    0x68, 0x52, 0x66, 0x32, 0x61, 0x73, 0x64, 0x77, 0x65, 0x53, 0x55, 0x38,
+    0x50, 0x6a, 0x31, 0x4b, 0x2f, 0x66, 0x71, 0x79, 0x6e, 0x68, 0x47, 0x31,
+    0x72, 0x69, 0x52, 0x2f, 0x61, 0x59, 0x4e, 0x4b, 0x78, 0x6f, 0x55, 0x0a,
+    0x41, 0x54, 0x36, 0x41, 0x38, 0x45, 0x4b, 0x67, 0x6c, 0x51, 0x64, 0x65,
+    0x62, 0x63, 0x33, 0x4d, 0x53, 0x36, 0x52, 0x46, 0x6a, 0x61, 0x73, 0x53,
+    0x36, 0x4c, 0x50, 0x65, 0x57, 0x75, 0x57, 0x67, 0x66, 0x4f, 0x67, 0x50,
+    0x49, 0x68, 0x31, 0x61, 0x36, 0x56, 0x6b, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a,
+    0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x69, 0x6d,
+    0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20,
+    0x4f, 0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e,
+    0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+    0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76,
+    0x69, 0x63, 0x65, 0x73, 0x20, 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f,
+    0x6e, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x74,
+    0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20,
+    0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72,
+    0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c,
+    0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a,
+    0x20, 0x43, 0x4e, 0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50,
+    0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+    0x43, 0x41, 0x20, 0x4f, 0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c,
+    0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x65, 0x72,
+    0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53,
+    0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, 0x69, 0x76, 0x69,
+    0x73, 0x69, 0x6f, 0x6e, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30,
+    0x36, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e,
+    0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74,
+    0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20,
+    0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c,
+    0x3a, 0x20, 0x22, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72,
+    0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43,
+    0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a,
+    0x20, 0x36, 0x39, 0x35, 0x32, 0x39, 0x31, 0x38, 0x31, 0x39, 0x39, 0x32,
+    0x30, 0x33, 0x39, 0x32, 0x30, 0x33, 0x35, 0x36, 0x36, 0x32, 0x39, 0x38,
+    0x39, 0x35, 0x33, 0x37, 0x38, 0x37, 0x37, 0x31, 0x32, 0x39, 0x34, 0x30,
+    0x39, 0x30, 0x39, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69,
+    0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38,
+    0x63, 0x3a, 0x63, 0x61, 0x3a, 0x64, 0x63, 0x3a, 0x30, 0x62, 0x3a, 0x32,
+    0x32, 0x3a, 0x63, 0x65, 0x3a, 0x66, 0x35, 0x3a, 0x62, 0x65, 0x3a, 0x37,
+    0x32, 0x3a, 0x61, 0x63, 0x3a, 0x34, 0x31, 0x3a, 0x31, 0x61, 0x3a, 0x31,
+    0x31, 0x3a, 0x61, 0x38, 0x3a, 0x64, 0x38, 0x3a, 0x31, 0x32, 0x0a, 0x23,
+    0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x31, 0x3a, 0x63, 0x36,
+    0x3a, 0x64, 0x36, 0x3a, 0x65, 0x65, 0x3a, 0x33, 0x65, 0x3a, 0x38, 0x61,
+    0x3a, 0x63, 0x38, 0x3a, 0x36, 0x33, 0x3a, 0x38, 0x34, 0x3a, 0x65, 0x35,
+    0x3a, 0x34, 0x38, 0x3a, 0x63, 0x32, 0x3a, 0x39, 0x39, 0x3a, 0x32, 0x39,
+    0x3a, 0x35, 0x63, 0x3a, 0x37, 0x35, 0x3a, 0x36, 0x63, 0x3a, 0x38, 0x31,
+    0x3a, 0x37, 0x62, 0x3a, 0x38, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41,
+    0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x64, 0x3a, 0x37, 0x32, 0x3a, 0x32,
+    0x66, 0x3a, 0x38, 0x31, 0x3a, 0x61, 0x39, 0x3a, 0x63, 0x31, 0x3a, 0x31,
+    0x33, 0x3a, 0x63, 0x30, 0x3a, 0x37, 0x39, 0x3a, 0x31, 0x64, 0x3a, 0x66,
+    0x31, 0x3a, 0x33, 0x36, 0x3a, 0x61, 0x32, 0x3a, 0x39, 0x36, 0x3a, 0x36,
+    0x64, 0x3a, 0x62, 0x32, 0x3a, 0x36, 0x63, 0x3a, 0x39, 0x35, 0x3a, 0x30,
+    0x61, 0x3a, 0x39, 0x37, 0x3a, 0x31, 0x64, 0x3a, 0x62, 0x34, 0x3a, 0x36,
+    0x62, 0x3a, 0x34, 0x31, 0x3a, 0x39, 0x39, 0x3a, 0x66, 0x34, 0x3a, 0x65,
+    0x61, 0x3a, 0x35, 0x34, 0x3a, 0x62, 0x37, 0x3a, 0x38, 0x62, 0x3a, 0x66,
+    0x62, 0x3a, 0x39, 0x66, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45,
+    0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43,
+    0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49,
+    0x45, 0x49, 0x44, 0x43, 0x43, 0x41, 0x77, 0x69, 0x67, 0x41, 0x77, 0x49,
+    0x42, 0x41, 0x67, 0x49, 0x51, 0x4e, 0x45, 0x37, 0x56, 0x56, 0x79, 0x44,
+    0x56, 0x37, 0x65, 0x78, 0x4a, 0x39, 0x43, 0x2f, 0x4f, 0x4e, 0x39, 0x73,
+    0x72, 0x62, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69,
+    0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x43,
+    0x42, 0x0a, 0x71, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x54,
+    0x41, 0x54, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x48,
+    0x52, 0x6f, 0x59, 0x58, 0x64, 0x30, 0x5a, 0x53, 0x77, 0x67, 0x53, 0x57,
+    0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x6f, 0x4d, 0x43, 0x59, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x43, 0x78, 0x4d, 0x66, 0x0a, 0x51, 0x32, 0x56, 0x79, 0x64,
+    0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62,
+    0x69, 0x42, 0x54, 0x5a, 0x58, 0x4a, 0x32, 0x61, 0x57, 0x4e, 0x6c, 0x63,
+    0x79, 0x42, 0x45, 0x61, 0x58, 0x5a, 0x70, 0x63, 0x32, 0x6c, 0x76, 0x62,
+    0x6a, 0x45, 0x34, 0x4d, 0x44, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43,
+    0x78, 0x4d, 0x76, 0x4b, 0x47, 0x4d, 0x70, 0x49, 0x44, 0x49, 0x77, 0x0a,
+    0x4d, 0x44, 0x59, 0x67, 0x64, 0x47, 0x68, 0x68, 0x64, 0x33, 0x52, 0x6c,
+    0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30, 0x67,
+    0x52, 0x6d, 0x39, 0x79, 0x49, 0x47, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76,
+    0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, 0x58, 0x4e, 0x6c,
+    0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x48, 0x7a, 0x41, 0x64,
+    0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x4d, 0x54, 0x46, 0x6e, 0x52,
+    0x6f, 0x59, 0x58, 0x64, 0x30, 0x5a, 0x53, 0x42, 0x51, 0x63, 0x6d, 0x6c,
+    0x74, 0x59, 0x58, 0x4a, 0x35, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51,
+    0x67, 0x51, 0x30, 0x45, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x59,
+    0x78, 0x4d, 0x54, 0x45, 0x33, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41,
+    0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x59, 0x77, 0x0a, 0x4e, 0x7a,
+    0x45, 0x32, 0x4d, 0x6a, 0x4d, 0x31, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a,
+    0x43, 0x42, 0x71, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x54,
+    0x41, 0x54, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x48,
+    0x52, 0x6f, 0x59, 0x58, 0x64, 0x30, 0x5a, 0x53, 0x77, 0x67, 0x53, 0x57,
+    0x35, 0x6a, 0x0a, 0x4c, 0x6a, 0x45, 0x6f, 0x4d, 0x43, 0x59, 0x47, 0x41,
+    0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x66, 0x51, 0x32, 0x56, 0x79, 0x64,
+    0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62,
+    0x69, 0x42, 0x54, 0x5a, 0x58, 0x4a, 0x32, 0x61, 0x57, 0x4e, 0x6c, 0x63,
+    0x79, 0x42, 0x45, 0x61, 0x58, 0x5a, 0x70, 0x63, 0x32, 0x6c, 0x76, 0x62,
+    0x6a, 0x45, 0x34, 0x4d, 0x44, 0x59, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45,
+    0x43, 0x78, 0x4d, 0x76, 0x4b, 0x47, 0x4d, 0x70, 0x49, 0x44, 0x49, 0x77,
+    0x4d, 0x44, 0x59, 0x67, 0x64, 0x47, 0x68, 0x68, 0x64, 0x33, 0x52, 0x6c,
+    0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30, 0x67,
+    0x52, 0x6d, 0x39, 0x79, 0x49, 0x47, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76,
+    0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, 0x58, 0x4e, 0x6c,
+    0x0a, 0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x48, 0x7a, 0x41,
+    0x64, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x46, 0x6e, 0x52,
+    0x6f, 0x59, 0x58, 0x64, 0x30, 0x5a, 0x53, 0x42, 0x51, 0x63, 0x6d, 0x6c,
+    0x74, 0x59, 0x58, 0x4a, 0x35, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51,
+    0x67, 0x51, 0x30, 0x45, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4d, 0x41, 0x30,
+    0x47, 0x43, 0x53, 0x71, 0x47, 0x0a, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51,
+    0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77,
+    0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51,
+    0x43, 0x73, 0x6f, 0x50, 0x44, 0x37, 0x67, 0x46, 0x6e, 0x55, 0x6e, 0x4d,
+    0x65, 0x6b, 0x7a, 0x35, 0x32, 0x68, 0x57, 0x58, 0x4d, 0x4a, 0x45, 0x45,
+    0x55, 0x4d, 0x44, 0x53, 0x78, 0x75, 0x61, 0x50, 0x46, 0x73, 0x0a, 0x57,
+    0x30, 0x68, 0x6f, 0x53, 0x56, 0x6b, 0x33, 0x2f, 0x41, 0x73, 0x7a, 0x47,
+    0x63, 0x4a, 0x33, 0x66, 0x38, 0x77, 0x51, 0x4c, 0x5a, 0x55, 0x30, 0x48,
+    0x4f, 0x62, 0x72, 0x54, 0x51, 0x6d, 0x6e, 0x48, 0x4e, 0x4b, 0x34, 0x79,
+    0x5a, 0x63, 0x32, 0x41, 0x72, 0x65, 0x4a, 0x31, 0x43, 0x52, 0x66, 0x42,
+    0x73, 0x44, 0x4d, 0x52, 0x4a, 0x53, 0x55, 0x6a, 0x51, 0x4a, 0x69, 0x62,
+    0x2b, 0x74, 0x61, 0x0a, 0x33, 0x52, 0x47, 0x4e, 0x4b, 0x4a, 0x70, 0x63,
+    0x68, 0x4a, 0x41, 0x51, 0x65, 0x67, 0x32, 0x39, 0x64, 0x47, 0x59, 0x76,
+    0x61, 0x6a, 0x69, 0x67, 0x34, 0x74, 0x56, 0x55, 0x52, 0x4f, 0x73, 0x64,
+    0x42, 0x35, 0x38, 0x48, 0x75, 0x6d, 0x2f, 0x75, 0x36, 0x66, 0x31, 0x4f,
+    0x43, 0x79, 0x6e, 0x31, 0x50, 0x6f, 0x53, 0x67, 0x41, 0x66, 0x47, 0x63,
+    0x71, 0x2f, 0x67, 0x63, 0x66, 0x6f, 0x6d, 0x6b, 0x0a, 0x36, 0x4b, 0x48,
+    0x59, 0x63, 0x57, 0x55, 0x4e, 0x6f, 0x31, 0x46, 0x37, 0x37, 0x72, 0x7a,
+    0x53, 0x49, 0x6d, 0x41, 0x4e, 0x75, 0x56, 0x75, 0x64, 0x33, 0x37, 0x72,
+    0x38, 0x55, 0x56, 0x73, 0x4c, 0x72, 0x35, 0x69, 0x79, 0x36, 0x53, 0x37,
+    0x70, 0x42, 0x4f, 0x68, 0x69, 0x68, 0x39, 0x34, 0x72, 0x79, 0x4e, 0x64,
+    0x4f, 0x77, 0x55, 0x78, 0x6b, 0x48, 0x74, 0x33, 0x50, 0x68, 0x31, 0x69,
+    0x36, 0x0a, 0x53, 0x6b, 0x2f, 0x4b, 0x61, 0x41, 0x63, 0x64, 0x48, 0x4a,
+    0x31, 0x4b, 0x78, 0x74, 0x55, 0x76, 0x6b, 0x63, 0x78, 0x38, 0x63, 0x58,
+    0x49, 0x63, 0x78, 0x63, 0x42, 0x6e, 0x36, 0x7a, 0x4c, 0x39, 0x79, 0x5a,
+    0x4a, 0x63, 0x6c, 0x4e, 0x71, 0x46, 0x77, 0x4a, 0x75, 0x2f, 0x55, 0x33,
+    0x30, 0x72, 0x43, 0x66, 0x53, 0x4d, 0x6e, 0x5a, 0x45, 0x66, 0x6c, 0x32,
+    0x70, 0x53, 0x79, 0x39, 0x34, 0x4a, 0x0a, 0x4e, 0x71, 0x52, 0x33, 0x32,
+    0x48, 0x75, 0x48, 0x55, 0x45, 0x54, 0x56, 0x50, 0x6d, 0x34, 0x70, 0x61,
+    0x66, 0x73, 0x35, 0x53, 0x53, 0x59, 0x65, 0x43, 0x61, 0x57, 0x41, 0x65,
+    0x30, 0x41, 0x74, 0x36, 0x2b, 0x67, 0x6e, 0x68, 0x63, 0x6e, 0x2b, 0x59,
+    0x66, 0x31, 0x2b, 0x35, 0x6e, 0x79, 0x58, 0x48, 0x64, 0x57, 0x64, 0x41,
+    0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x0a,
+    0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42,
+    0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77,
+    0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f,
+    0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x30, 0x47,
+    0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x52, 0x37,
+    0x57, 0x30, 0x58, 0x50, 0x0a, 0x72, 0x38, 0x37, 0x4c, 0x65, 0x76, 0x30,
+    0x78, 0x6b, 0x68, 0x70, 0x71, 0x74, 0x76, 0x4e, 0x47, 0x36, 0x31, 0x64,
+    0x49, 0x55, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69,
+    0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f,
+    0x43, 0x41, 0x51, 0x45, 0x41, 0x65, 0x52, 0x48, 0x41, 0x53, 0x37, 0x4f,
+    0x52, 0x74, 0x76, 0x7a, 0x77, 0x36, 0x57, 0x66, 0x55, 0x0a, 0x44, 0x57,
+    0x35, 0x46, 0x76, 0x6c, 0x58, 0x6f, 0x6b, 0x39, 0x4c, 0x4f, 0x41, 0x7a,
+    0x2f, 0x74, 0x32, 0x69, 0x57, 0x77, 0x48, 0x56, 0x66, 0x4c, 0x48, 0x6a,
+    0x70, 0x32, 0x6f, 0x45, 0x7a, 0x73, 0x55, 0x48, 0x62, 0x6f, 0x5a, 0x48,
+    0x49, 0x4d, 0x70, 0x4b, 0x6e, 0x78, 0x75, 0x49, 0x76, 0x57, 0x31, 0x6f,
+    0x65, 0x45, 0x75, 0x7a, 0x4c, 0x6c, 0x51, 0x52, 0x48, 0x41, 0x64, 0x39,
+    0x6d, 0x7a, 0x0a, 0x59, 0x4a, 0x33, 0x72, 0x47, 0x39, 0x58, 0x52, 0x62,
+    0x6b, 0x52, 0x45, 0x71, 0x61, 0x59, 0x42, 0x37, 0x46, 0x56, 0x69, 0x48,
+    0x58, 0x65, 0x34, 0x58, 0x49, 0x35, 0x49, 0x53, 0x58, 0x79, 0x63, 0x4f,
+    0x31, 0x63, 0x52, 0x72, 0x4b, 0x31, 0x7a, 0x4e, 0x34, 0x34, 0x76, 0x65,
+    0x46, 0x79, 0x51, 0x61, 0x45, 0x66, 0x5a, 0x59, 0x47, 0x44, 0x6d, 0x2f,
+    0x41, 0x63, 0x39, 0x49, 0x69, 0x41, 0x58, 0x0a, 0x78, 0x50, 0x63, 0x57,
+    0x36, 0x63, 0x54, 0x59, 0x63, 0x76, 0x6e, 0x49, 0x63, 0x33, 0x7a, 0x66,
+    0x46, 0x69, 0x38, 0x56, 0x71, 0x54, 0x37, 0x39, 0x61, 0x69, 0x65, 0x32,
+    0x6f, 0x65, 0x74, 0x61, 0x75, 0x70, 0x67, 0x66, 0x31, 0x65, 0x4e, 0x4e,
+    0x5a, 0x41, 0x71, 0x64, 0x45, 0x38, 0x68, 0x68, 0x75, 0x76, 0x55, 0x35,
+    0x48, 0x49, 0x65, 0x36, 0x75, 0x4c, 0x31, 0x37, 0x49, 0x6e, 0x2f, 0x32,
+    0x0a, 0x2f, 0x71, 0x78, 0x41, 0x65, 0x65, 0x57, 0x73, 0x45, 0x47, 0x38,
+    0x39, 0x6a, 0x78, 0x74, 0x35, 0x64, 0x6f, 0x76, 0x45, 0x4e, 0x37, 0x4d,
+    0x68, 0x47, 0x49, 0x54, 0x6c, 0x4e, 0x67, 0x44, 0x72, 0x59, 0x79, 0x43,
+    0x5a, 0x75, 0x65, 0x6e, 0x2b, 0x4d, 0x77, 0x53, 0x37, 0x51, 0x63, 0x6a,
+    0x42, 0x41, 0x76, 0x6c, 0x45, 0x59, 0x79, 0x43, 0x65, 0x67, 0x63, 0x35,
+    0x43, 0x30, 0x39, 0x59, 0x2f, 0x0a, 0x4c, 0x48, 0x62, 0x54, 0x59, 0x35,
+    0x78, 0x5a, 0x33, 0x59, 0x2b, 0x6d, 0x34, 0x51, 0x36, 0x67, 0x4c, 0x6b,
+    0x48, 0x33, 0x4c, 0x70, 0x56, 0x48, 0x7a, 0x37, 0x7a, 0x39, 0x4d, 0x2f,
+    0x50, 0x32, 0x43, 0x32, 0x46, 0x2b, 0x66, 0x70, 0x45, 0x72, 0x67, 0x55,
+    0x66, 0x43, 0x4a, 0x7a, 0x44, 0x75, 0x70, 0x78, 0x42, 0x64, 0x4e, 0x34,
+    0x39, 0x63, 0x4f, 0x53, 0x76, 0x6b, 0x42, 0x50, 0x42, 0x37, 0x0a, 0x6a,
+    0x56, 0x61, 0x4d, 0x61, 0x41, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23,
+    0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d,
+    0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61,
+    0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
+    0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74,
+    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
+    0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35,
+    0x20, 0x4f, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c,
+    0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x65, 0x72,
+    0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20,
+    0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x28, 0x63, 0x29, 0x20,
+    0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+    0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f,
+    0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64,
+    0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20,
+    0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d,
+    0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61,
+    0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
+    0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74,
+    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
+    0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35,
+    0x20, 0x4f, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c,
+    0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x65, 0x72,
+    0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20,
+    0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x28, 0x63, 0x29, 0x20,
+    0x32, 0x30, 0x30, 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+    0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f,
+    0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64,
+    0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20,
+    0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x56, 0x65, 0x72, 0x69,
+    0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33,
+    0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d,
+    0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+    0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+    0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x22, 0x0a, 0x23, 0x20,
+    0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x33, 0x33, 0x30, 0x33,
+    0x37, 0x36, 0x34, 0x34, 0x31, 0x36, 0x37, 0x35, 0x36, 0x38, 0x30, 0x35,
+    0x38, 0x39, 0x37, 0x30, 0x31, 0x36, 0x34, 0x37, 0x31, 0x39, 0x34, 0x37,
+    0x35, 0x36, 0x37, 0x36, 0x31, 0x30, 0x31, 0x34, 0x35, 0x30, 0x0a, 0x23,
+    0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x62, 0x3a, 0x31, 0x37, 0x3a,
+    0x65, 0x34, 0x3a, 0x33, 0x31, 0x3a, 0x36, 0x37, 0x3a, 0x33, 0x65, 0x3a,
+    0x65, 0x32, 0x3a, 0x30, 0x39, 0x3a, 0x66, 0x65, 0x3a, 0x34, 0x35, 0x3a,
+    0x35, 0x37, 0x3a, 0x39, 0x33, 0x3a, 0x66, 0x33, 0x3a, 0x30, 0x61, 0x3a,
+    0x66, 0x61, 0x3a, 0x31, 0x63, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x34, 0x65, 0x3a, 0x62, 0x36, 0x3a, 0x64, 0x35, 0x3a, 0x37,
+    0x38, 0x3a, 0x34, 0x39, 0x3a, 0x39, 0x62, 0x3a, 0x31, 0x63, 0x3a, 0x63,
+    0x66, 0x3a, 0x35, 0x66, 0x3a, 0x35, 0x38, 0x3a, 0x31, 0x65, 0x3a, 0x61,
+    0x64, 0x3a, 0x35, 0x36, 0x3a, 0x62, 0x65, 0x3a, 0x33, 0x64, 0x3a, 0x39,
+    0x62, 0x3a, 0x36, 0x37, 0x3a, 0x34, 0x34, 0x3a, 0x61, 0x35, 0x3a, 0x65,
+    0x35, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x39, 0x61, 0x3a, 0x63, 0x66, 0x3a, 0x61, 0x62, 0x3a, 0x37, 0x65, 0x3a,
+    0x34, 0x33, 0x3a, 0x63, 0x38, 0x3a, 0x64, 0x38, 0x3a, 0x38, 0x30, 0x3a,
+    0x64, 0x30, 0x3a, 0x36, 0x62, 0x3a, 0x32, 0x36, 0x3a, 0x32, 0x61, 0x3a,
+    0x39, 0x34, 0x3a, 0x64, 0x65, 0x3a, 0x65, 0x65, 0x3a, 0x65, 0x34, 0x3a,
+    0x62, 0x34, 0x3a, 0x36, 0x35, 0x3a, 0x39, 0x39, 0x3a, 0x38, 0x39, 0x3a,
+    0x63, 0x33, 0x3a, 0x64, 0x30, 0x3a, 0x63, 0x61, 0x3a, 0x66, 0x31, 0x3a,
+    0x39, 0x62, 0x3a, 0x61, 0x66, 0x3a, 0x36, 0x34, 0x3a, 0x30, 0x35, 0x3a,
+    0x65, 0x34, 0x3a, 0x31, 0x61, 0x3a, 0x62, 0x37, 0x3a, 0x64, 0x66, 0x0a,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x30, 0x7a, 0x43, 0x43,
+    0x41, 0x37, 0x75, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51,
+    0x47, 0x4e, 0x72, 0x52, 0x6e, 0x69, 0x5a, 0x39, 0x36, 0x4c, 0x74, 0x4b,
+    0x49, 0x56, 0x6a, 0x4e, 0x7a, 0x47, 0x73, 0x37, 0x53, 0x6a, 0x41, 0x4e,
+    0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42,
+    0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x79, 0x6a, 0x45,
+    0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d,
+    0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x7a, 0x41, 0x56, 0x42, 0x67, 0x4e,
+    0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x6c, 0x5a, 0x6c, 0x63, 0x6d, 0x6c,
+    0x54, 0x61, 0x57, 0x64, 0x75, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d,
+    0x75, 0x4d, 0x52, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x4c, 0x0a, 0x45, 0x78, 0x5a, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32,
+    0x6c, 0x6e, 0x62, 0x69, 0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43,
+    0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x4d, 0x54,
+    0x6f, 0x77, 0x4f, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x7a,
+    0x45, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x6a, 0x41, 0x77, 0x4e, 0x69,
+    0x42, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x0a, 0x55, 0x32, 0x6c, 0x6e, 0x62,
+    0x69, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x69, 0x41, 0x74, 0x49,
+    0x45, 0x5a, 0x76, 0x63, 0x69, 0x42, 0x68, 0x64, 0x58, 0x52, 0x6f, 0x62,
+    0x33, 0x4a, 0x70, 0x65, 0x6d, 0x56, 0x6b, 0x49, 0x48, 0x56, 0x7a, 0x5a,
+    0x53, 0x42, 0x76, 0x62, 0x6d, 0x78, 0x35, 0x4d, 0x55, 0x55, 0x77, 0x51,
+    0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x7a, 0x78, 0x57, 0x0a,
+    0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x44,
+    0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, 0x41, 0x7a, 0x49, 0x46, 0x42, 0x31,
+    0x59, 0x6d, 0x78, 0x70, 0x59, 0x79, 0x42, 0x51, 0x63, 0x6d, 0x6c, 0x74,
+    0x59, 0x58, 0x4a, 0x35, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70,
+    0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67,
+    0x51, 0x58, 0x56, 0x30, 0x0a, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52,
+    0x35, 0x49, 0x43, 0x30, 0x67, 0x52, 0x7a, 0x55, 0x77, 0x48, 0x68, 0x63,
+    0x4e, 0x4d, 0x44, 0x59, 0x78, 0x4d, 0x54, 0x41, 0x34, 0x4d, 0x44, 0x41,
+    0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x59,
+    0x77, 0x4e, 0x7a, 0x45, 0x32, 0x4d, 0x6a, 0x4d, 0x31, 0x4f, 0x54, 0x55,
+    0x35, 0x57, 0x6a, 0x43, 0x42, 0x79, 0x6a, 0x45, 0x4c, 0x0a, 0x4d, 0x41,
+    0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56,
+    0x4d, 0x78, 0x46, 0x7a, 0x41, 0x56, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41,
+    0x6f, 0x54, 0x44, 0x6c, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57,
+    0x64, 0x75, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x52,
+    0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78,
+    0x5a, 0x57, 0x0a, 0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62,
+    0x69, 0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4f, 0x5a,
+    0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x4d, 0x54, 0x6f, 0x77, 0x4f,
+    0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x7a, 0x45, 0x6f, 0x59,
+    0x79, 0x6b, 0x67, 0x4d, 0x6a, 0x41, 0x77, 0x4e, 0x69, 0x42, 0x57, 0x5a,
+    0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x0a, 0x62, 0x69, 0x77, 0x67,
+    0x53, 0x57, 0x35, 0x6a, 0x4c, 0x69, 0x41, 0x74, 0x49, 0x45, 0x5a, 0x76,
+    0x63, 0x69, 0x42, 0x68, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70,
+    0x65, 0x6d, 0x56, 0x6b, 0x49, 0x48, 0x56, 0x7a, 0x5a, 0x53, 0x42, 0x76,
+    0x62, 0x6d, 0x78, 0x35, 0x4d, 0x55, 0x55, 0x77, 0x51, 0x77, 0x59, 0x44,
+    0x56, 0x51, 0x51, 0x44, 0x45, 0x7a, 0x78, 0x57, 0x5a, 0x58, 0x4a, 0x70,
+    0x0a, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x44, 0x62, 0x47, 0x46,
+    0x7a, 0x63, 0x79, 0x41, 0x7a, 0x49, 0x46, 0x42, 0x31, 0x59, 0x6d, 0x78,
+    0x70, 0x59, 0x79, 0x42, 0x51, 0x63, 0x6d, 0x6c, 0x74, 0x59, 0x58, 0x4a,
+    0x35, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c,
+    0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56,
+    0x30, 0x61, 0x47, 0x39, 0x79, 0x0a, 0x61, 0x58, 0x52, 0x35, 0x49, 0x43,
+    0x30, 0x67, 0x52, 0x7a, 0x55, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4d, 0x41,
+    0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51,
+    0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77,
+    0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51,
+    0x43, 0x76, 0x4a, 0x41, 0x67, 0x49, 0x4b, 0x58, 0x6f, 0x31, 0x0a, 0x6e,
+    0x6d, 0x41, 0x4d, 0x71, 0x75, 0x64, 0x4c, 0x4f, 0x30, 0x37, 0x63, 0x66,
+    0x4c, 0x77, 0x38, 0x52, 0x52, 0x79, 0x37, 0x4b, 0x2b, 0x44, 0x2b, 0x4b,
+    0x51, 0x4c, 0x35, 0x56, 0x77, 0x69, 0x6a, 0x5a, 0x49, 0x55, 0x56, 0x4a,
+    0x2f, 0x58, 0x78, 0x72, 0x63, 0x67, 0x78, 0x69, 0x56, 0x30, 0x69, 0x36,
+    0x43, 0x71, 0x71, 0x70, 0x6b, 0x4b, 0x7a, 0x6a, 0x2f, 0x69, 0x35, 0x56,
+    0x62, 0x65, 0x78, 0x0a, 0x74, 0x30, 0x75, 0x7a, 0x2f, 0x6f, 0x39, 0x2b,
+    0x42, 0x31, 0x66, 0x73, 0x37, 0x30, 0x50, 0x62, 0x5a, 0x6d, 0x49, 0x56,
+    0x59, 0x63, 0x39, 0x67, 0x44, 0x61, 0x54, 0x59, 0x33, 0x76, 0x6a, 0x67,
+    0x77, 0x32, 0x49, 0x49, 0x50, 0x56, 0x51, 0x54, 0x36, 0x30, 0x6e, 0x4b,
+    0x57, 0x56, 0x53, 0x46, 0x4a, 0x75, 0x55, 0x72, 0x6a, 0x78, 0x75, 0x66,
+    0x36, 0x2f, 0x57, 0x68, 0x6b, 0x63, 0x49, 0x7a, 0x0a, 0x53, 0x64, 0x68,
+    0x44, 0x59, 0x32, 0x70, 0x53, 0x53, 0x39, 0x4b, 0x50, 0x36, 0x48, 0x42,
+    0x52, 0x54, 0x64, 0x47, 0x4a, 0x61, 0x58, 0x76, 0x48, 0x63, 0x50, 0x61,
+    0x7a, 0x33, 0x42, 0x4a, 0x30, 0x32, 0x33, 0x74, 0x64, 0x53, 0x31, 0x62,
+    0x54, 0x6c, 0x72, 0x38, 0x56, 0x64, 0x36, 0x47, 0x77, 0x39, 0x4b, 0x49,
+    0x6c, 0x38, 0x71, 0x38, 0x63, 0x6b, 0x6d, 0x63, 0x59, 0x35, 0x66, 0x51,
+    0x47, 0x0a, 0x42, 0x4f, 0x2b, 0x51, 0x75, 0x65, 0x51, 0x41, 0x35, 0x4e,
+    0x30, 0x36, 0x74, 0x52, 0x6e, 0x2f, 0x41, 0x72, 0x72, 0x30, 0x50, 0x4f,
+    0x37, 0x67, 0x69, 0x2b, 0x73, 0x33, 0x69, 0x2b, 0x7a, 0x30, 0x31, 0x36,
+    0x7a, 0x79, 0x39, 0x76, 0x41, 0x39, 0x72, 0x39, 0x31, 0x31, 0x6b, 0x54,
+    0x4d, 0x5a, 0x48, 0x52, 0x78, 0x41, 0x79, 0x33, 0x51, 0x6b, 0x47, 0x53,
+    0x47, 0x54, 0x32, 0x52, 0x54, 0x2b, 0x0a, 0x72, 0x43, 0x70, 0x53, 0x78,
+    0x34, 0x2f, 0x56, 0x42, 0x45, 0x6e, 0x6b, 0x6a, 0x57, 0x4e, 0x48, 0x69,
+    0x44, 0x78, 0x70, 0x67, 0x38, 0x76, 0x2b, 0x52, 0x37, 0x30, 0x72, 0x66,
+    0x6b, 0x2f, 0x46, 0x6c, 0x61, 0x34, 0x4f, 0x6e, 0x64, 0x54, 0x52, 0x51,
+    0x38, 0x42, 0x6e, 0x63, 0x2b, 0x4d, 0x55, 0x43, 0x48, 0x37, 0x6c, 0x50,
+    0x35, 0x39, 0x7a, 0x75, 0x44, 0x4d, 0x4b, 0x7a, 0x31, 0x30, 0x2f, 0x0a,
+    0x4e, 0x49, 0x65, 0x57, 0x69, 0x75, 0x35, 0x54, 0x36, 0x43, 0x55, 0x56,
+    0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x67, 0x62, 0x49, 0x77,
+    0x67, 0x61, 0x38, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54,
+    0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42,
+    0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42,
+    0x41, 0x66, 0x38, 0x45, 0x0a, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59,
+    0x77, 0x62, 0x51, 0x59, 0x49, 0x4b, 0x77, 0x59, 0x42, 0x42, 0x51, 0x55,
+    0x48, 0x41, 0x51, 0x77, 0x45, 0x59, 0x54, 0x42, 0x66, 0x6f, 0x56, 0x32,
+    0x67, 0x57, 0x7a, 0x42, 0x5a, 0x4d, 0x46, 0x63, 0x77, 0x56, 0x52, 0x59,
+    0x4a, 0x61, 0x57, 0x31, 0x68, 0x5a, 0x32, 0x55, 0x76, 0x5a, 0x32, 0x6c,
+    0x6d, 0x4d, 0x43, 0x45, 0x77, 0x48, 0x7a, 0x41, 0x48, 0x0a, 0x42, 0x67,
+    0x55, 0x72, 0x44, 0x67, 0x4d, 0x43, 0x47, 0x67, 0x51, 0x55, 0x6a, 0x2b,
+    0x58, 0x54, 0x47, 0x6f, 0x61, 0x73, 0x6a, 0x59, 0x35, 0x72, 0x77, 0x38,
+    0x2b, 0x41, 0x61, 0x74, 0x52, 0x49, 0x47, 0x43, 0x78, 0x37, 0x47, 0x53,
+    0x34, 0x77, 0x4a, 0x52, 0x59, 0x6a, 0x61, 0x48, 0x52, 0x30, 0x63, 0x44,
+    0x6f, 0x76, 0x4c, 0x32, 0x78, 0x76, 0x5a, 0x32, 0x38, 0x75, 0x64, 0x6d,
+    0x56, 0x79, 0x0a, 0x61, 0x58, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x75, 0x59,
+    0x32, 0x39, 0x74, 0x4c, 0x33, 0x5a, 0x7a, 0x62, 0x47, 0x39, 0x6e, 0x62,
+    0x79, 0x35, 0x6e, 0x61, 0x57, 0x59, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56,
+    0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x48, 0x2f, 0x54, 0x5a,
+    0x61, 0x66, 0x43, 0x33, 0x65, 0x79, 0x37, 0x38, 0x44, 0x41, 0x4a, 0x38,
+    0x30, 0x4d, 0x35, 0x2b, 0x67, 0x4b, 0x76, 0x0a, 0x4d, 0x7a, 0x45, 0x7a,
+    0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33,
+    0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42,
+    0x41, 0x51, 0x43, 0x54, 0x4a, 0x45, 0x6f, 0x77, 0x58, 0x32, 0x4c, 0x50,
+    0x32, 0x42, 0x71, 0x59, 0x4c, 0x7a, 0x33, 0x71, 0x33, 0x4a, 0x6b, 0x74,
+    0x76, 0x58, 0x66, 0x32, 0x70, 0x58, 0x6b, 0x69, 0x4f, 0x4f, 0x7a, 0x45,
+    0x0a, 0x70, 0x36, 0x42, 0x34, 0x45, 0x71, 0x31, 0x69, 0x44, 0x6b, 0x56,
+    0x77, 0x5a, 0x4d, 0x58, 0x6e, 0x6c, 0x32, 0x59, 0x74, 0x6d, 0x41, 0x6c,
+    0x2b, 0x58, 0x36, 0x2f, 0x57, 0x7a, 0x43, 0x68, 0x6c, 0x38, 0x67, 0x47,
+    0x71, 0x43, 0x42, 0x70, 0x48, 0x33, 0x76, 0x6e, 0x35, 0x66, 0x4a, 0x4a,
+    0x61, 0x43, 0x47, 0x6b, 0x67, 0x44, 0x64, 0x6b, 0x2b, 0x62, 0x57, 0x34,
+    0x38, 0x44, 0x57, 0x37, 0x59, 0x0a, 0x35, 0x67, 0x61, 0x52, 0x51, 0x42,
+    0x69, 0x35, 0x2b, 0x4d, 0x48, 0x74, 0x33, 0x39, 0x74, 0x42, 0x71, 0x75,
+    0x43, 0x57, 0x49, 0x4d, 0x6e, 0x4e, 0x5a, 0x42, 0x55, 0x34, 0x67, 0x63,
+    0x6d, 0x55, 0x37, 0x71, 0x4b, 0x45, 0x4b, 0x51, 0x73, 0x54, 0x62, 0x34,
+    0x37, 0x62, 0x44, 0x4e, 0x30, 0x6c, 0x41, 0x74, 0x75, 0x6b, 0x69, 0x78,
+    0x6c, 0x45, 0x30, 0x6b, 0x46, 0x36, 0x42, 0x57, 0x6c, 0x4b, 0x0a, 0x57,
+    0x45, 0x39, 0x67, 0x79, 0x6e, 0x36, 0x43, 0x61, 0x67, 0x73, 0x43, 0x71,
+    0x69, 0x55, 0x58, 0x4f, 0x62, 0x58, 0x62, 0x66, 0x2b, 0x65, 0x45, 0x5a,
+    0x53, 0x71, 0x56, 0x69, 0x72, 0x32, 0x47, 0x33, 0x6c, 0x36, 0x42, 0x46,
+    0x6f, 0x4d, 0x74, 0x45, 0x4d, 0x7a, 0x65, 0x2f, 0x61, 0x69, 0x43, 0x4b,
+    0x6d, 0x30, 0x6f, 0x48, 0x77, 0x30, 0x4c, 0x78, 0x4f, 0x58, 0x6e, 0x47,
+    0x69, 0x59, 0x5a, 0x0a, 0x34, 0x66, 0x51, 0x52, 0x62, 0x78, 0x43, 0x31,
+    0x6c, 0x66, 0x7a, 0x6e, 0x51, 0x67, 0x55, 0x79, 0x32, 0x38, 0x36, 0x64,
+    0x55, 0x56, 0x34, 0x6f, 0x74, 0x70, 0x36, 0x46, 0x30, 0x31, 0x76, 0x76,
+    0x70, 0x58, 0x31, 0x46, 0x51, 0x48, 0x4b, 0x4f, 0x74, 0x77, 0x35, 0x72,
+    0x44, 0x67, 0x62, 0x37, 0x4d, 0x7a, 0x56, 0x49, 0x63, 0x62, 0x69, 0x64,
+    0x4a, 0x34, 0x76, 0x45, 0x5a, 0x56, 0x38, 0x4e, 0x0a, 0x68, 0x6e, 0x61,
+    0x63, 0x52, 0x48, 0x72, 0x32, 0x6c, 0x56, 0x7a, 0x32, 0x58, 0x54, 0x49,
+    0x49, 0x4d, 0x36, 0x52, 0x55, 0x74, 0x68, 0x67, 0x2f, 0x61, 0x46, 0x7a,
+    0x79, 0x51, 0x6b, 0x71, 0x46, 0x4f, 0x46, 0x53, 0x44, 0x58, 0x39, 0x48,
+    0x6f, 0x4c, 0x50, 0x4b, 0x73, 0x45, 0x64, 0x61, 0x6f, 0x37, 0x57, 0x4e,
+    0x71, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65,
+    0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f,
+    0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+    0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+    0x20, 0x4f, 0x3d, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x41,
+    0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53,
+    0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43,
+    0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+    0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x43, 0x4f, 0x4d, 0x4f,
+    0x44, 0x4f, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65,
+    0x64, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22,
+    0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+    0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74,
+    0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65,
+    0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x30, 0x34, 0x33, 0x35, 0x30,
+    0x35, 0x31, 0x33, 0x36, 0x34, 0x38, 0x32, 0x34, 0x39, 0x32, 0x33, 0x32,
+    0x39, 0x34, 0x31, 0x39, 0x39, 0x38, 0x35, 0x30, 0x38, 0x39, 0x38, 0x35,
+    0x38, 0x33, 0x34, 0x34, 0x36, 0x34, 0x35, 0x37, 0x33, 0x0a, 0x23, 0x20,
+    0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x63, 0x3a, 0x34, 0x38, 0x3a, 0x64,
+    0x63, 0x3a, 0x66, 0x37, 0x3a, 0x34, 0x32, 0x3a, 0x37, 0x32, 0x3a, 0x65,
+    0x63, 0x3a, 0x35, 0x36, 0x3a, 0x39, 0x34, 0x3a, 0x36, 0x64, 0x3a, 0x31,
+    0x63, 0x3a, 0x63, 0x63, 0x3a, 0x37, 0x31, 0x3a, 0x33, 0x35, 0x3a, 0x38,
+    0x30, 0x3a, 0x37, 0x35, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x36, 0x36, 0x3a, 0x33, 0x31, 0x3a, 0x62, 0x66, 0x3a, 0x39, 0x65,
+    0x3a, 0x66, 0x37, 0x3a, 0x34, 0x66, 0x3a, 0x39, 0x65, 0x3a, 0x62, 0x36,
+    0x3a, 0x63, 0x39, 0x3a, 0x64, 0x35, 0x3a, 0x61, 0x36, 0x3a, 0x30, 0x63,
+    0x3a, 0x62, 0x61, 0x3a, 0x36, 0x61, 0x3a, 0x62, 0x65, 0x3a, 0x64, 0x31,
+    0x3a, 0x66, 0x37, 0x3a, 0x62, 0x64, 0x3a, 0x65, 0x66, 0x3a, 0x37, 0x62,
+    0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69,
+    0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30,
+    0x63, 0x3a, 0x32, 0x63, 0x3a, 0x64, 0x36, 0x3a, 0x33, 0x64, 0x3a, 0x66,
+    0x37, 0x3a, 0x38, 0x30, 0x3a, 0x36, 0x66, 0x3a, 0x61, 0x33, 0x3a, 0x39,
+    0x39, 0x3a, 0x65, 0x64, 0x3a, 0x65, 0x38, 0x3a, 0x30, 0x39, 0x3a, 0x31,
+    0x31, 0x3a, 0x36, 0x62, 0x3a, 0x35, 0x37, 0x3a, 0x35, 0x62, 0x3a, 0x66,
+    0x38, 0x3a, 0x37, 0x39, 0x3a, 0x38, 0x39, 0x3a, 0x66, 0x30, 0x3a, 0x36,
+    0x35, 0x3a, 0x31, 0x38, 0x3a, 0x66, 0x39, 0x3a, 0x38, 0x30, 0x3a, 0x38,
+    0x63, 0x3a, 0x38, 0x36, 0x3a, 0x30, 0x35, 0x3a, 0x30, 0x33, 0x3a, 0x31,
+    0x37, 0x3a, 0x38, 0x62, 0x3a, 0x61, 0x66, 0x3a, 0x36, 0x36, 0x0a, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45,
+    0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x48, 0x54, 0x43, 0x43, 0x41,
+    0x77, 0x57, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x54,
+    0x6f, 0x45, 0x74, 0x69, 0x6f, 0x4a, 0x6c, 0x34, 0x41, 0x73, 0x43, 0x37,
+    0x6a, 0x34, 0x31, 0x41, 0x6b, 0x62, 0x6c, 0x50, 0x54, 0x41, 0x4e, 0x42,
+    0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41,
+    0x51, 0x55, 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x67, 0x54, 0x45, 0x4c,
+    0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43,
+    0x52, 0x30, 0x49, 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x67, 0x54, 0x45, 0x6b, 0x64, 0x79, 0x5a, 0x57, 0x46, 0x30,
+    0x5a, 0x58, 0x49, 0x67, 0x54, 0x57, 0x46, 0x75, 0x59, 0x32, 0x68, 0x6c,
+    0x63, 0x33, 0x52, 0x6c, 0x63, 0x6a, 0x45, 0x51, 0x4d, 0x41, 0x34, 0x47,
+    0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, 0x78, 0x4d, 0x48, 0x55, 0x32, 0x46,
+    0x73, 0x5a, 0x6d, 0x39, 0x79, 0x5a, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x52, 0x51, 0x30, 0x39,
+    0x4e, 0x54, 0x30, 0x52, 0x50, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x45, 0x78,
+    0x70, 0x62, 0x57, 0x6c, 0x30, 0x5a, 0x57, 0x51, 0x78, 0x4a, 0x7a, 0x41,
+    0x6c, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x4d, 0x54, 0x48, 0x6b,
+    0x4e, 0x50, 0x54, 0x55, 0x39, 0x45, 0x54, 0x79, 0x42, 0x44, 0x5a, 0x58,
+    0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57,
+    0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d,
+    0x6c, 0x30, 0x65, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, 0x77, 0x4e, 0x6a,
+    0x45, 0x79, 0x4d, 0x44, 0x45, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x0a, 0x4d,
+    0x44, 0x42, 0x61, 0x46, 0x77, 0x30, 0x79, 0x4f, 0x54, 0x45, 0x79, 0x4d,
+    0x7a, 0x45, 0x79, 0x4d, 0x7a, 0x55, 0x35, 0x4e, 0x54, 0x6c, 0x61, 0x4d,
+    0x49, 0x47, 0x42, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x48, 0x51, 0x6a, 0x45, 0x62, 0x4d,
+    0x42, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x42, 0x4d, 0x53, 0x52,
+    0x33, 0x4a, 0x6c, 0x0a, 0x59, 0x58, 0x52, 0x6c, 0x63, 0x69, 0x42, 0x4e,
+    0x59, 0x57, 0x35, 0x6a, 0x61, 0x47, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x79,
+    0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48,
+    0x45, 0x77, 0x64, 0x54, 0x59, 0x57, 0x78, 0x6d, 0x62, 0x33, 0x4a, 0x6b,
+    0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b,
+    0x45, 0x78, 0x46, 0x44, 0x54, 0x30, 0x31, 0x50, 0x0a, 0x52, 0x45, 0x38,
+    0x67, 0x51, 0x30, 0x45, 0x67, 0x54, 0x47, 0x6c, 0x74, 0x61, 0x58, 0x52,
+    0x6c, 0x5a, 0x44, 0x45, 0x6e, 0x4d, 0x43, 0x55, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x41, 0x78, 0x4d, 0x65, 0x51, 0x30, 0x39, 0x4e, 0x54, 0x30, 0x52,
+    0x50, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c,
+    0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56,
+    0x30, 0x0a, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x49,
+    0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b,
+    0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41,
+    0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67,
+    0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x30, 0x45, 0x43, 0x4c, 0x69, 0x33,
+    0x4c, 0x6a, 0x6b, 0x52, 0x76, 0x33, 0x0a, 0x55, 0x63, 0x45, 0x62, 0x56,
+    0x41, 0x53, 0x59, 0x30, 0x36, 0x6d, 0x2f, 0x77, 0x65, 0x61, 0x4b, 0x58,
+    0x54, 0x75, 0x48, 0x2b, 0x37, 0x75, 0x49, 0x7a, 0x67, 0x33, 0x6a, 0x4c,
+    0x7a, 0x38, 0x47, 0x6c, 0x76, 0x43, 0x69, 0x4b, 0x56, 0x43, 0x5a, 0x72,
+    0x74, 0x73, 0x37, 0x6f, 0x56, 0x65, 0x77, 0x64, 0x46, 0x46, 0x78, 0x7a,
+    0x65, 0x31, 0x43, 0x6b, 0x55, 0x31, 0x42, 0x2f, 0x71, 0x6e, 0x49, 0x0a,
+    0x32, 0x47, 0x71, 0x47, 0x64, 0x30, 0x53, 0x37, 0x57, 0x57, 0x61, 0x58,
+    0x55, 0x46, 0x36, 0x30, 0x31, 0x43, 0x78, 0x77, 0x52, 0x4d, 0x2f, 0x61,
+    0x4e, 0x35, 0x56, 0x43, 0x61, 0x54, 0x77, 0x77, 0x78, 0x48, 0x47, 0x7a,
+    0x55, 0x76, 0x41, 0x68, 0x54, 0x61, 0x48, 0x59, 0x75, 0x6a, 0x6c, 0x38,
+    0x48, 0x4a, 0x36, 0x6a, 0x4a, 0x4a, 0x33, 0x79, 0x67, 0x78, 0x61, 0x59,
+    0x71, 0x68, 0x5a, 0x38, 0x0a, 0x51, 0x35, 0x73, 0x56, 0x57, 0x37, 0x65,
+    0x75, 0x4e, 0x4a, 0x48, 0x2b, 0x31, 0x47, 0x49, 0x6d, 0x47, 0x45, 0x61,
+    0x61, 0x50, 0x2b, 0x76, 0x42, 0x2b, 0x66, 0x47, 0x51, 0x56, 0x2b, 0x75,
+    0x73, 0x65, 0x67, 0x32, 0x4c, 0x32, 0x33, 0x49, 0x77, 0x61, 0x6d, 0x62,
+    0x56, 0x34, 0x45, 0x61, 0x6a, 0x63, 0x4e, 0x78, 0x6f, 0x32, 0x66, 0x38,
+    0x45, 0x53, 0x49, 0x6c, 0x33, 0x33, 0x72, 0x58, 0x70, 0x0a, 0x2b, 0x32,
+    0x64, 0x74, 0x51, 0x65, 0x6d, 0x38, 0x4f, 0x62, 0x30, 0x79, 0x32, 0x57,
+    0x49, 0x43, 0x38, 0x62, 0x47, 0x6f, 0x50, 0x57, 0x34, 0x33, 0x6e, 0x4f,
+    0x49, 0x76, 0x34, 0x74, 0x4f, 0x69, 0x4a, 0x6f, 0x76, 0x47, 0x75, 0x46,
+    0x56, 0x44, 0x69, 0x4f, 0x45, 0x6a, 0x50, 0x71, 0x58, 0x53, 0x4a, 0x44,
+    0x6c, 0x71, 0x52, 0x36, 0x73, 0x41, 0x31, 0x4b, 0x47, 0x7a, 0x71, 0x53,
+    0x58, 0x2b, 0x0a, 0x44, 0x54, 0x2b, 0x6e, 0x48, 0x62, 0x72, 0x54, 0x55,
+    0x63, 0x45, 0x4c, 0x70, 0x4e, 0x71, 0x73, 0x4f, 0x4f, 0x39, 0x56, 0x55,
+    0x43, 0x51, 0x46, 0x5a, 0x55, 0x61, 0x54, 0x4e, 0x45, 0x38, 0x74, 0x6a,
+    0x61, 0x33, 0x47, 0x31, 0x43, 0x45, 0x5a, 0x30, 0x6f, 0x37, 0x4b, 0x42,
+    0x57, 0x46, 0x78, 0x42, 0x33, 0x4e, 0x48, 0x35, 0x59, 0x6f, 0x5a, 0x45,
+    0x72, 0x30, 0x45, 0x54, 0x63, 0x35, 0x4f, 0x0a, 0x6e, 0x4b, 0x56, 0x49,
+    0x72, 0x4c, 0x73, 0x6d, 0x39, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42,
+    0x6f, 0x34, 0x47, 0x4f, 0x4d, 0x49, 0x47, 0x4c, 0x4d, 0x42, 0x30, 0x47,
+    0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x51, 0x4c,
+    0x57, 0x4f, 0x57, 0x4c, 0x78, 0x6b, 0x77, 0x56, 0x4e, 0x36, 0x52, 0x41,
+    0x71, 0x54, 0x43, 0x70, 0x49, 0x62, 0x35, 0x48, 0x4e, 0x6c, 0x70, 0x57,
+    0x0a, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38,
+    0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59,
+    0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48,
+    0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x42,
+    0x4a, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x38, 0x45, 0x51, 0x6a, 0x42,
+    0x41, 0x4d, 0x44, 0x36, 0x67, 0x0a, 0x50, 0x4b, 0x41, 0x36, 0x68, 0x6a,
+    0x68, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69, 0x38, 0x76, 0x59, 0x33,
+    0x4a, 0x73, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x57, 0x39, 0x6b, 0x62, 0x32,
+    0x4e, 0x68, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x53, 0x39, 0x44, 0x54, 0x30,
+    0x31, 0x50, 0x52, 0x45, 0x39, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57,
+    0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x0a, 0x51,
+    0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4c,
+    0x6d, 0x4e, 0x79, 0x62, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68,
+    0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41,
+    0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x50, 0x70, 0x69, 0x65, 0x6d,
+    0x2f, 0x59, 0x62, 0x36, 0x64, 0x63, 0x35, 0x74, 0x33, 0x69, 0x75, 0x48,
+    0x58, 0x49, 0x59, 0x0a, 0x53, 0x64, 0x4f, 0x48, 0x35, 0x45, 0x4f, 0x43,
+    0x36, 0x7a, 0x2f, 0x4a, 0x71, 0x76, 0x57, 0x6f, 0x74, 0x65, 0x39, 0x56,
+    0x66, 0x43, 0x46, 0x53, 0x5a, 0x66, 0x6e, 0x56, 0x44, 0x65, 0x46, 0x73,
+    0x39, 0x44, 0x36, 0x4d, 0x6b, 0x33, 0x4f, 0x52, 0x4c, 0x67, 0x4c, 0x45,
+    0x54, 0x67, 0x64, 0x78, 0x62, 0x38, 0x43, 0x50, 0x4f, 0x47, 0x45, 0x49,
+    0x71, 0x42, 0x36, 0x42, 0x43, 0x73, 0x41, 0x76, 0x0a, 0x49, 0x43, 0x39,
+    0x42, 0x69, 0x35, 0x48, 0x63, 0x53, 0x45, 0x57, 0x38, 0x38, 0x63, 0x62,
+    0x65, 0x75, 0x6e, 0x5a, 0x72, 0x4d, 0x38, 0x67, 0x41, 0x4c, 0x54, 0x46,
+    0x47, 0x54, 0x4f, 0x33, 0x6e, 0x6e, 0x63, 0x2b, 0x49, 0x6c, 0x50, 0x38,
+    0x7a, 0x77, 0x46, 0x62, 0x6f, 0x4a, 0x49, 0x59, 0x6d, 0x75, 0x4e, 0x67,
+    0x34, 0x4f, 0x4e, 0x38, 0x71, 0x61, 0x39, 0x30, 0x53, 0x7a, 0x4d, 0x63,
+    0x2f, 0x0a, 0x52, 0x78, 0x64, 0x4d, 0x6f, 0x73, 0x49, 0x47, 0x6c, 0x67,
+    0x6e, 0x57, 0x32, 0x2f, 0x34, 0x2f, 0x50, 0x45, 0x5a, 0x42, 0x33, 0x31,
+    0x6a, 0x69, 0x56, 0x67, 0x38, 0x38, 0x4f, 0x38, 0x45, 0x63, 0x6b, 0x7a,
+    0x58, 0x5a, 0x4f, 0x46, 0x4b, 0x73, 0x37, 0x73, 0x6a, 0x73, 0x4c, 0x6a,
+    0x42, 0x4f, 0x6c, 0x44, 0x57, 0x30, 0x4a, 0x42, 0x39, 0x4c, 0x65, 0x47,
+    0x6e, 0x61, 0x38, 0x67, 0x49, 0x34, 0x0a, 0x7a, 0x4a, 0x56, 0x53, 0x6b,
+    0x2f, 0x42, 0x77, 0x4a, 0x56, 0x6d, 0x63, 0x49, 0x47, 0x66, 0x45, 0x37,
+    0x76, 0x6d, 0x4c, 0x56, 0x32, 0x48, 0x30, 0x6b, 0x6e, 0x5a, 0x39, 0x50,
+    0x34, 0x53, 0x4e, 0x56, 0x62, 0x66, 0x6f, 0x35, 0x61, 0x7a, 0x56, 0x38,
+    0x66, 0x55, 0x5a, 0x56, 0x71, 0x5a, 0x61, 0x2b, 0x35, 0x41, 0x63, 0x72,
+    0x35, 0x50, 0x72, 0x35, 0x52, 0x7a, 0x55, 0x5a, 0x35, 0x64, 0x64, 0x0a,
+    0x42, 0x41, 0x36, 0x2b, 0x43, 0x34, 0x4f, 0x6d, 0x46, 0x34, 0x4f, 0x35,
+    0x4d, 0x42, 0x4b, 0x67, 0x78, 0x54, 0x4d, 0x56, 0x42, 0x62, 0x6b, 0x4e,
+    0x2b, 0x38, 0x63, 0x46, 0x64, 0x75, 0x50, 0x59, 0x53, 0x6f, 0x33, 0x38,
+    0x4e, 0x42, 0x65, 0x6a, 0x78, 0x69, 0x45, 0x6f, 0x76, 0x6a, 0x42, 0x46,
+    0x4d, 0x52, 0x37, 0x48, 0x65, 0x4c, 0x35, 0x59, 0x59, 0x54, 0x69, 0x73,
+    0x4f, 0x2b, 0x49, 0x42, 0x0a, 0x5a, 0x51, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49,
+    0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a,
+    0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43,
+    0x4e, 0x3d, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f,
+    0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65, 0x72, 0x74,
+    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x4e, 0x65, 0x74, 0x77,
+    0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e,
+    0x73, 0x20, 0x4c, 0x2e, 0x4c, 0x2e, 0x43, 0x2e, 0x0a, 0x23, 0x20, 0x53,
+    0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x4e,
+    0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74,
+    0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+    0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+    0x74, 0x79, 0x20, 0x4f, 0x3d, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
+    0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x4c,
+    0x2e, 0x4c, 0x2e, 0x43, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65,
+    0x6c, 0x3a, 0x20, 0x22, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
+    0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65,
+    0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75,
+    0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53,
+    0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x31, 0x36, 0x36, 0x39,
+    0x37, 0x39, 0x31, 0x35, 0x31, 0x35, 0x32, 0x39, 0x33, 0x37, 0x34, 0x39,
+    0x37, 0x34, 0x39, 0x30, 0x34, 0x33, 0x37, 0x35, 0x35, 0x36, 0x33, 0x38,
+    0x36, 0x38, 0x31, 0x32, 0x34, 0x38, 0x37, 0x39, 0x30, 0x34, 0x0a, 0x23,
+    0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x33, 0x3a, 0x66, 0x33, 0x3a,
+    0x61, 0x36, 0x3a, 0x31, 0x36, 0x3a, 0x63, 0x30, 0x3a, 0x66, 0x61, 0x3a,
+    0x36, 0x62, 0x3a, 0x31, 0x64, 0x3a, 0x35, 0x39, 0x3a, 0x62, 0x31, 0x3a,
+    0x32, 0x64, 0x3a, 0x39, 0x36, 0x3a, 0x34, 0x64, 0x3a, 0x30, 0x65, 0x3a,
+    0x31, 0x31, 0x3a, 0x32, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x37, 0x34, 0x3a, 0x66, 0x38, 0x3a, 0x61, 0x33, 0x3a, 0x63,
+    0x33, 0x3a, 0x65, 0x66, 0x3a, 0x65, 0x37, 0x3a, 0x62, 0x33, 0x3a, 0x39,
+    0x30, 0x3a, 0x30, 0x36, 0x3a, 0x34, 0x62, 0x3a, 0x38, 0x33, 0x3a, 0x39,
+    0x30, 0x3a, 0x33, 0x63, 0x3a, 0x32, 0x31, 0x3a, 0x36, 0x34, 0x3a, 0x36,
+    0x30, 0x3a, 0x32, 0x30, 0x3a, 0x65, 0x35, 0x3a, 0x64, 0x66, 0x3a, 0x63,
+    0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x31, 0x35, 0x3a, 0x66, 0x30, 0x3a, 0x62, 0x61, 0x3a, 0x30, 0x30, 0x3a,
+    0x61, 0x33, 0x3a, 0x61, 0x63, 0x3a, 0x37, 0x61, 0x3a, 0x66, 0x33, 0x3a,
+    0x61, 0x63, 0x3a, 0x38, 0x38, 0x3a, 0x34, 0x63, 0x3a, 0x30, 0x37, 0x3a,
+    0x32, 0x62, 0x3a, 0x31, 0x30, 0x3a, 0x31, 0x31, 0x3a, 0x61, 0x30, 0x3a,
+    0x37, 0x37, 0x3a, 0x62, 0x64, 0x3a, 0x37, 0x37, 0x3a, 0x63, 0x30, 0x3a,
+    0x39, 0x37, 0x3a, 0x66, 0x34, 0x3a, 0x30, 0x31, 0x3a, 0x36, 0x34, 0x3a,
+    0x62, 0x32, 0x3a, 0x66, 0x38, 0x3a, 0x35, 0x39, 0x3a, 0x38, 0x61, 0x3a,
+    0x62, 0x64, 0x3a, 0x38, 0x33, 0x3a, 0x38, 0x36, 0x3a, 0x30, 0x63, 0x0a,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x35, 0x6a, 0x43, 0x43,
+    0x41, 0x73, 0x36, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51,
+    0x56, 0x38, 0x73, 0x7a, 0x62, 0x38, 0x4a, 0x63, 0x46, 0x75, 0x5a, 0x48,
+    0x46, 0x68, 0x66, 0x6a, 0x6b, 0x44, 0x46, 0x6f, 0x34, 0x44, 0x41, 0x4e,
+    0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42,
+    0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x69, 0x0a, 0x4d, 0x51, 0x73,
+    0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a,
+    0x56, 0x55, 0x7a, 0x45, 0x68, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x43, 0x68, 0x4d, 0x59, 0x54, 0x6d, 0x56, 0x30, 0x64, 0x32, 0x39,
+    0x79, 0x61, 0x79, 0x42, 0x54, 0x62, 0x32, 0x78, 0x31, 0x64, 0x47, 0x6c,
+    0x76, 0x62, 0x6e, 0x4d, 0x67, 0x54, 0x43, 0x35, 0x4d, 0x4c, 0x6b, 0x4d,
+    0x75, 0x0a, 0x4d, 0x54, 0x41, 0x77, 0x4c, 0x67, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x44, 0x45, 0x79, 0x64, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33,
+    0x4a, 0x72, 0x49, 0x46, 0x4e, 0x76, 0x62, 0x48, 0x56, 0x30, 0x61, 0x57,
+    0x39, 0x75, 0x63, 0x79, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57,
+    0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, 0x53, 0x42, 0x42, 0x64, 0x58,
+    0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x0a, 0x64, 0x48, 0x6b, 0x77, 0x48,
+    0x68, 0x63, 0x4e, 0x4d, 0x44, 0x59, 0x78, 0x4d, 0x6a, 0x41, 0x78, 0x4d,
+    0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d,
+    0x6a, 0x6b, 0x78, 0x4d, 0x6a, 0x4d, 0x78, 0x4d, 0x6a, 0x4d, 0x31, 0x4f,
+    0x54, 0x55, 0x35, 0x57, 0x6a, 0x42, 0x69, 0x4d, 0x51, 0x73, 0x77, 0x43,
+    0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x0a,
+    0x55, 0x7a, 0x45, 0x68, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x43, 0x68, 0x4d, 0x59, 0x54, 0x6d, 0x56, 0x30, 0x64, 0x32, 0x39, 0x79,
+    0x61, 0x79, 0x42, 0x54, 0x62, 0x32, 0x78, 0x31, 0x64, 0x47, 0x6c, 0x76,
+    0x62, 0x6e, 0x4d, 0x67, 0x54, 0x43, 0x35, 0x4d, 0x4c, 0x6b, 0x4d, 0x75,
+    0x4d, 0x54, 0x41, 0x77, 0x4c, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44,
+    0x45, 0x79, 0x64, 0x4f, 0x0a, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a,
+    0x72, 0x49, 0x46, 0x4e, 0x76, 0x62, 0x48, 0x56, 0x30, 0x61, 0x57, 0x39,
+    0x75, 0x63, 0x79, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a,
+    0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, 0x53, 0x42, 0x42, 0x64, 0x58, 0x52,
+    0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, 0x67, 0x67, 0x45,
+    0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x0a, 0x53, 0x49,
+    0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34,
+    0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f,
+    0x49, 0x42, 0x41, 0x51, 0x44, 0x6b, 0x76, 0x48, 0x36, 0x53, 0x4d, 0x47,
+    0x33, 0x47, 0x32, 0x49, 0x34, 0x72, 0x43, 0x37, 0x78, 0x47, 0x7a, 0x75,
+    0x41, 0x6e, 0x6c, 0x74, 0x37, 0x65, 0x2b, 0x66, 0x6f, 0x53, 0x30, 0x7a,
+    0x77, 0x7a, 0x0a, 0x63, 0x37, 0x4d, 0x45, 0x4c, 0x37, 0x78, 0x78, 0x6a,
+    0x4f, 0x57, 0x66, 0x74, 0x69, 0x4a, 0x67, 0x50, 0x6c, 0x39, 0x64, 0x7a,
+    0x67, 0x6e, 0x2f, 0x67, 0x67, 0x77, 0x62, 0x6d, 0x6c, 0x46, 0x51, 0x47,
+    0x69, 0x61, 0x4a, 0x33, 0x64, 0x56, 0x68, 0x58, 0x52, 0x6e, 0x63, 0x45,
+    0x67, 0x38, 0x74, 0x43, 0x71, 0x4a, 0x44, 0x58, 0x52, 0x66, 0x51, 0x4e,
+    0x4a, 0x49, 0x67, 0x36, 0x6e, 0x50, 0x50, 0x0a, 0x4f, 0x43, 0x77, 0x47,
+    0x4a, 0x67, 0x6c, 0x36, 0x63, 0x76, 0x66, 0x36, 0x55, 0x44, 0x4c, 0x34,
+    0x77, 0x70, 0x50, 0x54, 0x61, 0x61, 0x49, 0x6a, 0x7a, 0x6b, 0x47, 0x78,
+    0x7a, 0x4f, 0x54, 0x56, 0x48, 0x7a, 0x62, 0x52, 0x69, 0x6a, 0x72, 0x34,
+    0x6a, 0x47, 0x50, 0x69, 0x46, 0x46, 0x6c, 0x70, 0x37, 0x51, 0x33, 0x54,
+    0x66, 0x32, 0x76, 0x6f, 0x75, 0x41, 0x50, 0x6c, 0x54, 0x32, 0x72, 0x6c,
+    0x0a, 0x6d, 0x47, 0x4e, 0x70, 0x53, 0x41, 0x57, 0x2b, 0x4c, 0x76, 0x38,
+    0x7a, 0x74, 0x75, 0x6d, 0x58, 0x57, 0x57, 0x6e, 0x34, 0x5a, 0x78, 0x6d,
+    0x75, 0x6b, 0x32, 0x47, 0x57, 0x52, 0x42, 0x58, 0x54, 0x63, 0x72, 0x41,
+    0x2f, 0x76, 0x47, 0x70, 0x39, 0x37, 0x45, 0x68, 0x2f, 0x6a, 0x63, 0x4f,
+    0x72, 0x71, 0x6e, 0x45, 0x72, 0x55, 0x32, 0x6c, 0x42, 0x55, 0x7a, 0x53,
+    0x31, 0x73, 0x4c, 0x6e, 0x46, 0x0a, 0x42, 0x67, 0x72, 0x45, 0x73, 0x45,
+    0x58, 0x31, 0x51, 0x56, 0x31, 0x75, 0x69, 0x55, 0x56, 0x37, 0x50, 0x54,
+    0x73, 0x6d, 0x6a, 0x48, 0x54, 0x43, 0x35, 0x64, 0x4c, 0x52, 0x66, 0x62,
+    0x49, 0x52, 0x31, 0x50, 0x74, 0x59, 0x4d, 0x69, 0x4b, 0x61, 0x67, 0x4d,
+    0x6e, 0x63, 0x2f, 0x51, 0x7a, 0x70, 0x66, 0x31, 0x34, 0x44, 0x6c, 0x38,
+    0x34, 0x37, 0x41, 0x42, 0x53, 0x48, 0x4a, 0x33, 0x41, 0x34, 0x0a, 0x71,
+    0x59, 0x35, 0x75, 0x73, 0x79, 0x64, 0x32, 0x6d, 0x46, 0x48, 0x67, 0x42,
+    0x65, 0x4d, 0x68, 0x71, 0x78, 0x72, 0x56, 0x68, 0x53, 0x49, 0x38, 0x4b,
+    0x62, 0x57, 0x61, 0x46, 0x73, 0x57, 0x41, 0x71, 0x50, 0x53, 0x37, 0x61,
+    0x7a, 0x43, 0x50, 0x4c, 0x30, 0x59, 0x43, 0x6f, 0x72, 0x45, 0x4d, 0x49,
+    0x75, 0x44, 0x54, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x67,
+    0x5a, 0x63, 0x77, 0x0a, 0x67, 0x5a, 0x51, 0x77, 0x48, 0x51, 0x59, 0x44,
+    0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x43, 0x45, 0x77,
+    0x79, 0x66, 0x73, 0x41, 0x31, 0x30, 0x36, 0x59, 0x32, 0x6f, 0x65, 0x71,
+    0x4b, 0x74, 0x43, 0x6e, 0x4c, 0x72, 0x46, 0x41, 0x4d, 0x61, 0x64, 0x4d,
+    0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42,
+    0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x0a, 0x42, 0x6a, 0x41,
+    0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38,
+    0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x46, 0x49,
+    0x47, 0x41, 0x31, 0x55, 0x64, 0x48, 0x77, 0x52, 0x4c, 0x4d, 0x45, 0x6b,
+    0x77, 0x52, 0x36, 0x42, 0x46, 0x6f, 0x45, 0x4f, 0x47, 0x51, 0x57, 0x68,
+    0x30, 0x64, 0x48, 0x41, 0x36, 0x4c, 0x79, 0x39, 0x6a, 0x63, 0x6d, 0x77,
+    0x75, 0x0a, 0x62, 0x6d, 0x56, 0x30, 0x63, 0x32, 0x39, 0x73, 0x63, 0x33,
+    0x4e, 0x73, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x53, 0x39, 0x4f, 0x5a, 0x58,
+    0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x55, 0x32, 0x39, 0x73, 0x64, 0x58,
+    0x52, 0x70, 0x62, 0x32, 0x35, 0x7a, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47,
+    0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x56, 0x42, 0x64, 0x58,
+    0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x0a, 0x64, 0x48, 0x6b, 0x75, 0x59,
+    0x33, 0x4a, 0x73, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53,
+    0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x41,
+    0x34, 0x49, 0x42, 0x41, 0x51, 0x43, 0x37, 0x72, 0x6b, 0x76, 0x6e, 0x74,
+    0x31, 0x66, 0x72, 0x66, 0x36, 0x6f, 0x74, 0x74, 0x33, 0x4e, 0x48, 0x68,
+    0x57, 0x72, 0x42, 0x35, 0x4b, 0x55, 0x64, 0x35, 0x4f, 0x63, 0x38, 0x0a,
+    0x36, 0x66, 0x52, 0x5a, 0x5a, 0x58, 0x65, 0x31, 0x65, 0x6c, 0x74, 0x61,
+    0x6a, 0x53, 0x55, 0x32, 0x34, 0x48, 0x71, 0x58, 0x4c, 0x6a, 0x6a, 0x41,
+    0x56, 0x32, 0x43, 0x44, 0x6d, 0x41, 0x61, 0x44, 0x6e, 0x37, 0x6c, 0x32,
+    0x65, 0x6d, 0x35, 0x51, 0x34, 0x4c, 0x71, 0x49, 0x4c, 0x50, 0x78, 0x46,
+    0x7a, 0x42, 0x69, 0x77, 0x6d, 0x5a, 0x56, 0x52, 0x44, 0x75, 0x77, 0x64,
+    0x75, 0x49, 0x6a, 0x2f, 0x0a, 0x68, 0x31, 0x41, 0x63, 0x67, 0x73, 0x4c,
+    0x6a, 0x34, 0x44, 0x4b, 0x41, 0x76, 0x36, 0x41, 0x4c, 0x52, 0x38, 0x6a,
+    0x44, 0x4d, 0x65, 0x2b, 0x5a, 0x5a, 0x7a, 0x4b, 0x41, 0x54, 0x78, 0x63,
+    0x68, 0x65, 0x51, 0x78, 0x70, 0x58, 0x4e, 0x35, 0x65, 0x4e, 0x4b, 0x34,
+    0x43, 0x74, 0x53, 0x62, 0x71, 0x55, 0x4e, 0x39, 0x2f, 0x47, 0x47, 0x55,
+    0x73, 0x79, 0x66, 0x4a, 0x6a, 0x34, 0x61, 0x6b, 0x48, 0x0a, 0x2f, 0x6e,
+    0x78, 0x78, 0x48, 0x32, 0x73, 0x7a, 0x4a, 0x47, 0x6f, 0x65, 0x42, 0x66,
+    0x63, 0x46, 0x61, 0x4d, 0x42, 0x71, 0x45, 0x73, 0x73, 0x75, 0x58, 0x6d,
+    0x48, 0x4c, 0x72, 0x69, 0x6a, 0x54, 0x66, 0x73, 0x4b, 0x30, 0x5a, 0x70,
+    0x45, 0x6d, 0x58, 0x7a, 0x77, 0x75, 0x4a, 0x46, 0x2f, 0x4c, 0x57, 0x41,
+    0x2f, 0x72, 0x4b, 0x4f, 0x79, 0x76, 0x45, 0x5a, 0x62, 0x7a, 0x33, 0x48,
+    0x74, 0x76, 0x0a, 0x77, 0x4b, 0x65, 0x49, 0x38, 0x6c, 0x4e, 0x33, 0x73,
+    0x32, 0x42, 0x65, 0x72, 0x71, 0x34, 0x6f, 0x32, 0x6a, 0x55, 0x73, 0x62,
+    0x7a, 0x52, 0x46, 0x30, 0x79, 0x62, 0x68, 0x33, 0x75, 0x78, 0x62, 0x54,
+    0x79, 0x64, 0x72, 0x46, 0x6e, 0x79, 0x39, 0x52, 0x41, 0x51, 0x59, 0x67,
+    0x72, 0x4f, 0x4a, 0x65, 0x52, 0x63, 0x51, 0x63, 0x54, 0x31, 0x36, 0x6f,
+    0x68, 0x5a, 0x4f, 0x39, 0x51, 0x48, 0x4e, 0x0a, 0x70, 0x47, 0x78, 0x6c,
+    0x61, 0x4b, 0x46, 0x4a, 0x64, 0x6c, 0x78, 0x44, 0x79, 0x64, 0x69, 0x38,
+    0x4e, 0x6d, 0x64, 0x73, 0x70, 0x5a, 0x53, 0x31, 0x31, 0x4d, 0x79, 0x35,
+    0x76, 0x57, 0x6f, 0x31, 0x56, 0x69, 0x48, 0x65, 0x32, 0x4d, 0x50, 0x72,
+    0x2b, 0x38, 0x75, 0x6b, 0x59, 0x45, 0x79, 0x77, 0x56, 0x61, 0x43, 0x67,
+    0x65, 0x31, 0x65, 0x79, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e,
+    0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54,
+    0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73,
+    0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x4f, 0x4d,
+    0x4f, 0x44, 0x4f, 0x20, 0x45, 0x43, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74,
+    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
+    0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x43, 0x4f,
+    0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69,
+    0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63,
+    0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f,
+    0x20, 0x45, 0x43, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+    0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+    0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x43, 0x4f, 0x4d, 0x4f, 0x44,
+    0x4f, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64,
+    0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43,
+    0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x45, 0x43, 0x43, 0x20, 0x43, 0x65,
+    0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+    0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a, 0x23,
+    0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x34, 0x31, 0x35,
+    0x37, 0x38, 0x32, 0x38, 0x33, 0x38, 0x36, 0x37, 0x30, 0x38, 0x36, 0x36,
+    0x39, 0x32, 0x36, 0x33, 0x38, 0x32, 0x35, 0x36, 0x39, 0x32, 0x31, 0x35,
+    0x38, 0x39, 0x37, 0x30, 0x37, 0x39, 0x33, 0x38, 0x30, 0x39, 0x30, 0x0a,
+    0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x63, 0x3a, 0x36, 0x32,
+    0x3a, 0x66, 0x66, 0x3a, 0x37, 0x34, 0x3a, 0x39, 0x64, 0x3a, 0x33, 0x31,
+    0x3a, 0x35, 0x33, 0x3a, 0x35, 0x65, 0x3a, 0x36, 0x38, 0x3a, 0x34, 0x61,
+    0x3a, 0x64, 0x35, 0x3a, 0x37, 0x38, 0x3a, 0x61, 0x61, 0x3a, 0x31, 0x65,
+    0x3a, 0x62, 0x66, 0x3a, 0x32, 0x33, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41,
+    0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x39, 0x66, 0x3a, 0x37, 0x34, 0x3a, 0x34, 0x65, 0x3a,
+    0x39, 0x66, 0x3a, 0x32, 0x62, 0x3a, 0x34, 0x64, 0x3a, 0x62, 0x61, 0x3a,
+    0x65, 0x63, 0x3a, 0x30, 0x66, 0x3a, 0x33, 0x31, 0x3a, 0x32, 0x63, 0x3a,
+    0x35, 0x30, 0x3a, 0x62, 0x36, 0x3a, 0x35, 0x36, 0x3a, 0x33, 0x62, 0x3a,
+    0x38, 0x65, 0x3a, 0x32, 0x64, 0x3a, 0x39, 0x33, 0x3a, 0x63, 0x33, 0x3a,
+    0x31, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x31, 0x37, 0x3a, 0x39, 0x33, 0x3a, 0x39, 0x32, 0x3a, 0x37, 0x61,
+    0x3a, 0x30, 0x36, 0x3a, 0x31, 0x34, 0x3a, 0x35, 0x34, 0x3a, 0x39, 0x37,
+    0x3a, 0x38, 0x39, 0x3a, 0x61, 0x64, 0x3a, 0x63, 0x65, 0x3a, 0x32, 0x66,
+    0x3a, 0x38, 0x66, 0x3a, 0x33, 0x34, 0x3a, 0x66, 0x37, 0x3a, 0x66, 0x30,
+    0x3a, 0x62, 0x36, 0x3a, 0x36, 0x64, 0x3a, 0x30, 0x66, 0x3a, 0x33, 0x61,
+    0x3a, 0x65, 0x33, 0x3a, 0x61, 0x33, 0x3a, 0x62, 0x38, 0x3a, 0x34, 0x64,
+    0x3a, 0x32, 0x31, 0x3a, 0x65, 0x63, 0x3a, 0x31, 0x35, 0x3a, 0x64, 0x62,
+    0x3a, 0x62, 0x61, 0x3a, 0x34, 0x66, 0x3a, 0x61, 0x64, 0x3a, 0x63, 0x37,
+    0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20,
+    0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x69, 0x54, 0x43,
+    0x43, 0x41, 0x67, 0x2b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49,
+    0x51, 0x48, 0x30, 0x65, 0x76, 0x71, 0x6d, 0x49, 0x41, 0x63, 0x46, 0x42,
+    0x55, 0x54, 0x41, 0x47, 0x65, 0x6d, 0x32, 0x4f, 0x5a, 0x4b, 0x6a, 0x41,
+    0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51,
+    0x44, 0x41, 0x7a, 0x43, 0x42, 0x68, 0x54, 0x45, 0x4c, 0x0a, 0x4d, 0x41,
+    0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x30,
+    0x49, 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41,
+    0x67, 0x54, 0x45, 0x6b, 0x64, 0x79, 0x5a, 0x57, 0x46, 0x30, 0x5a, 0x58,
+    0x49, 0x67, 0x54, 0x57, 0x46, 0x75, 0x59, 0x32, 0x68, 0x6c, 0x63, 0x33,
+    0x52, 0x6c, 0x63, 0x6a, 0x45, 0x51, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x0a, 0x42, 0x78, 0x4d, 0x48, 0x55, 0x32, 0x46, 0x73, 0x5a,
+    0x6d, 0x39, 0x79, 0x5a, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41,
+    0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x52, 0x51, 0x30, 0x39, 0x4e, 0x54,
+    0x30, 0x52, 0x50, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x45, 0x78, 0x70, 0x62,
+    0x57, 0x6c, 0x30, 0x5a, 0x57, 0x51, 0x78, 0x4b, 0x7a, 0x41, 0x70, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x0a, 0x49, 0x6b, 0x4e, 0x50,
+    0x54, 0x55, 0x39, 0x45, 0x54, 0x79, 0x42, 0x46, 0x51, 0x30, 0x4d, 0x67,
+    0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68,
+    0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f,
+    0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, 0x48, 0x68, 0x63, 0x4e,
+    0x4d, 0x44, 0x67, 0x77, 0x4d, 0x7a, 0x41, 0x32, 0x4d, 0x44, 0x41, 0x77,
+    0x0a, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x67,
+    0x77, 0x4d, 0x54, 0x45, 0x34, 0x4d, 0x6a, 0x4d, 0x31, 0x4f, 0x54, 0x55,
+    0x35, 0x57, 0x6a, 0x43, 0x42, 0x68, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x30, 0x49,
+    0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67,
+    0x54, 0x45, 0x6b, 0x64, 0x79, 0x0a, 0x5a, 0x57, 0x46, 0x30, 0x5a, 0x58,
+    0x49, 0x67, 0x54, 0x57, 0x46, 0x75, 0x59, 0x32, 0x68, 0x6c, 0x63, 0x33,
+    0x52, 0x6c, 0x63, 0x6a, 0x45, 0x51, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x42, 0x78, 0x4d, 0x48, 0x55, 0x32, 0x46, 0x73, 0x5a, 0x6d,
+    0x39, 0x79, 0x5a, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x43, 0x68, 0x4d, 0x52, 0x51, 0x30, 0x39, 0x4e, 0x0a, 0x54,
+    0x30, 0x52, 0x50, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x45, 0x78, 0x70, 0x62,
+    0x57, 0x6c, 0x30, 0x5a, 0x57, 0x51, 0x78, 0x4b, 0x7a, 0x41, 0x70, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x49, 0x6b, 0x4e, 0x50, 0x54,
+    0x55, 0x39, 0x45, 0x54, 0x79, 0x42, 0x46, 0x51, 0x30, 0x4d, 0x67, 0x51,
+    0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64,
+    0x47, 0x6c, 0x76, 0x0a, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f,
+    0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, 0x64, 0x6a, 0x41, 0x51,
+    0x42, 0x67, 0x63, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x49, 0x42,
+    0x42, 0x67, 0x55, 0x72, 0x67, 0x51, 0x51, 0x41, 0x49, 0x67, 0x4e, 0x69,
+    0x41, 0x41, 0x51, 0x44, 0x52, 0x33, 0x73, 0x76, 0x64, 0x63, 0x6d, 0x43,
+    0x46, 0x59, 0x58, 0x37, 0x64, 0x65, 0x53, 0x52, 0x0a, 0x46, 0x74, 0x53,
+    0x72, 0x59, 0x70, 0x6e, 0x31, 0x50, 0x6c, 0x49, 0x4c, 0x42, 0x73, 0x35,
+    0x42, 0x41, 0x48, 0x2b, 0x58, 0x34, 0x51, 0x6f, 0x6b, 0x50, 0x42, 0x30,
+    0x42, 0x42, 0x4f, 0x34, 0x39, 0x30, 0x6f, 0x30, 0x4a, 0x6c, 0x77, 0x7a,
+    0x67, 0x64, 0x65, 0x54, 0x36, 0x2b, 0x33, 0x65, 0x4b, 0x4b, 0x76, 0x55,
+    0x44, 0x59, 0x45, 0x73, 0x32, 0x69, 0x78, 0x59, 0x6a, 0x46, 0x71, 0x30,
+    0x4a, 0x0a, 0x63, 0x66, 0x52, 0x4b, 0x39, 0x43, 0x68, 0x51, 0x74, 0x50,
+    0x36, 0x49, 0x48, 0x47, 0x34, 0x2f, 0x62, 0x43, 0x38, 0x76, 0x43, 0x56,
+    0x6c, 0x62, 0x70, 0x56, 0x73, 0x4c, 0x4d, 0x35, 0x6e, 0x69, 0x77, 0x7a,
+    0x32, 0x4a, 0x2b, 0x57, 0x6f, 0x73, 0x37, 0x37, 0x4c, 0x54, 0x42, 0x75,
+    0x6d, 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31,
+    0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x0a, 0x42, 0x42, 0x52, 0x31, 0x63,
+    0x61, 0x63, 0x5a, 0x53, 0x42, 0x6d, 0x38, 0x6e, 0x5a, 0x33, 0x71, 0x51,
+    0x55, 0x66, 0x66, 0x6c, 0x4d, 0x52, 0x49, 0x64, 0x35, 0x6e, 0x54, 0x65,
+    0x54, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41,
+    0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x44,
+    0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x0a,
+    0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4b,
+    0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44,
+    0x41, 0x77, 0x4e, 0x6f, 0x41, 0x44, 0x42, 0x6c, 0x41, 0x6a, 0x45, 0x41,
+    0x37, 0x77, 0x4e, 0x62, 0x65, 0x71, 0x79, 0x33, 0x65, 0x41, 0x70, 0x79,
+    0x74, 0x34, 0x6a, 0x66, 0x2f, 0x37, 0x56, 0x47, 0x46, 0x41, 0x6b, 0x4b,
+    0x2b, 0x71, 0x44, 0x6d, 0x0a, 0x66, 0x51, 0x6a, 0x47, 0x47, 0x6f, 0x65,
+    0x39, 0x47, 0x4b, 0x68, 0x7a, 0x76, 0x53, 0x62, 0x4b, 0x59, 0x41, 0x79,
+    0x64, 0x7a, 0x70, 0x6d, 0x66, 0x7a, 0x31, 0x77, 0x50, 0x4d, 0x4f, 0x47,
+    0x2b, 0x46, 0x44, 0x48, 0x71, 0x41, 0x6a, 0x41, 0x55, 0x39, 0x4a, 0x4d,
+    0x38, 0x53, 0x61, 0x63, 0x7a, 0x65, 0x70, 0x42, 0x47, 0x52, 0x37, 0x4e,
+    0x6a, 0x66, 0x52, 0x4f, 0x62, 0x54, 0x72, 0x64, 0x76, 0x0a, 0x47, 0x44,
+    0x65, 0x41, 0x55, 0x2f, 0x37, 0x64, 0x49, 0x4f, 0x41, 0x31, 0x6d, 0x6a,
+    0x62, 0x52, 0x78, 0x77, 0x47, 0x35, 0x35, 0x74, 0x7a, 0x64, 0x38, 0x2f,
+    0x38, 0x64, 0x4c, 0x44, 0x6f, 0x57, 0x56, 0x39, 0x6d, 0x53, 0x4f, 0x64,
+    0x59, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20,
+    0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75,
+    0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x54, 0x43, 0x20, 0x54, 0x72,
+    0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x43, 0x6c,
+    0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, 0x41, 0x20, 0x49, 0x49, 0x20,
+    0x4f, 0x3d, 0x54, 0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65,
+    0x6e, 0x74, 0x65, 0x72, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x20, 0x4f, 0x55,
+    0x3d, 0x54, 0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e,
+    0x74, 0x65, 0x72, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20,
+    0x43, 0x41, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74,
+    0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x54, 0x43, 0x20, 0x54, 0x72, 0x75, 0x73,
+    0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x43, 0x6c, 0x61, 0x73,
+    0x73, 0x20, 0x32, 0x20, 0x43, 0x41, 0x20, 0x49, 0x49, 0x20, 0x4f, 0x3d,
+    0x54, 0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74,
+    0x65, 0x72, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x20, 0x4f, 0x55, 0x3d, 0x54,
+    0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65,
+    0x72, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, 0x41,
+    0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x54,
+    0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65,
+    0x72, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, 0x41,
+    0x20, 0x49, 0x49, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61,
+    0x6c, 0x3a, 0x20, 0x39, 0x34, 0x31, 0x33, 0x38, 0x39, 0x30, 0x32, 0x38,
+    0x32, 0x30, 0x33, 0x34, 0x35, 0x33, 0x38, 0x36, 0x36, 0x37, 0x38, 0x32,
+    0x31, 0x30, 0x33, 0x34, 0x30, 0x36, 0x39, 0x39, 0x32, 0x34, 0x34, 0x33,
+    0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x65, 0x3a, 0x37,
+    0x38, 0x3a, 0x33, 0x33, 0x3a, 0x35, 0x63, 0x3a, 0x35, 0x39, 0x3a, 0x37,
+    0x38, 0x3a, 0x30, 0x31, 0x3a, 0x36, 0x65, 0x3a, 0x31, 0x38, 0x3a, 0x65,
+    0x61, 0x3a, 0x62, 0x39, 0x3a, 0x33, 0x36, 0x3a, 0x61, 0x30, 0x3a, 0x62,
+    0x39, 0x3a, 0x32, 0x65, 0x3a, 0x32, 0x33, 0x0a, 0x23, 0x20, 0x53, 0x48,
+    0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x61, 0x65, 0x3a, 0x35, 0x30, 0x3a, 0x38, 0x33,
+    0x3a, 0x65, 0x64, 0x3a, 0x37, 0x63, 0x3a, 0x66, 0x34, 0x3a, 0x35, 0x63,
+    0x3a, 0x62, 0x63, 0x3a, 0x38, 0x66, 0x3a, 0x36, 0x31, 0x3a, 0x63, 0x36,
+    0x3a, 0x32, 0x31, 0x3a, 0x66, 0x65, 0x3a, 0x36, 0x38, 0x3a, 0x35, 0x64,
+    0x3a, 0x37, 0x39, 0x3a, 0x34, 0x32, 0x3a, 0x32, 0x31, 0x3a, 0x31, 0x35,
+    0x3a, 0x36, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x65, 0x36, 0x3a, 0x62, 0x38, 0x3a, 0x66, 0x38, 0x3a, 0x37,
+    0x36, 0x3a, 0x36, 0x34, 0x3a, 0x38, 0x35, 0x3a, 0x66, 0x38, 0x3a, 0x30,
+    0x37, 0x3a, 0x61, 0x65, 0x3a, 0x37, 0x66, 0x3a, 0x38, 0x64, 0x3a, 0x61,
+    0x63, 0x3a, 0x31, 0x36, 0x3a, 0x37, 0x30, 0x3a, 0x34, 0x36, 0x3a, 0x31,
+    0x66, 0x3a, 0x30, 0x37, 0x3a, 0x63, 0x30, 0x3a, 0x61, 0x31, 0x3a, 0x33,
+    0x65, 0x3a, 0x65, 0x66, 0x3a, 0x33, 0x61, 0x3a, 0x31, 0x66, 0x3a, 0x66,
+    0x37, 0x3a, 0x31, 0x37, 0x3a, 0x35, 0x33, 0x3a, 0x38, 0x64, 0x3a, 0x37,
+    0x61, 0x3a, 0x62, 0x61, 0x3a, 0x64, 0x33, 0x3a, 0x39, 0x31, 0x3a, 0x62,
+    0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x71, 0x6a,
+    0x43, 0x43, 0x41, 0x35, 0x4b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67,
+    0x49, 0x4f, 0x4c, 0x6d, 0x6f, 0x41, 0x41, 0x51, 0x41, 0x43, 0x48, 0x39,
+    0x64, 0x53, 0x49, 0x53, 0x77, 0x52, 0x58, 0x44, 0x73, 0x77, 0x44, 0x51,
+    0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51,
+    0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x64, 0x6a, 0x45, 0x4c, 0x0a, 0x4d,
+    0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52,
+    0x45, 0x55, 0x78, 0x48, 0x44, 0x41, 0x61, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x6f, 0x54, 0x45, 0x31, 0x52, 0x44, 0x49, 0x46, 0x52, 0x79, 0x64,
+    0x58, 0x4e, 0x30, 0x51, 0x32, 0x56, 0x75, 0x64, 0x47, 0x56, 0x79, 0x49,
+    0x45, 0x64, 0x74, 0x59, 0x6b, 0x67, 0x78, 0x49, 0x6a, 0x41, 0x67, 0x42,
+    0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x73, 0x54, 0x47, 0x56, 0x52, 0x44,
+    0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x51, 0x32, 0x56, 0x75,
+    0x64, 0x47, 0x56, 0x79, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a,
+    0x49, 0x44, 0x49, 0x67, 0x51, 0x30, 0x45, 0x78, 0x4a, 0x54, 0x41, 0x6a,
+    0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x48, 0x46, 0x52, 0x44,
+    0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x0a, 0x51, 0x32, 0x56,
+    0x75, 0x64, 0x47, 0x56, 0x79, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e,
+    0x7a, 0x49, 0x44, 0x49, 0x67, 0x51, 0x30, 0x45, 0x67, 0x53, 0x55, 0x6b,
+    0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x59, 0x77, 0x4d, 0x54, 0x45,
+    0x79, 0x4d, 0x54, 0x51, 0x7a, 0x4f, 0x44, 0x51, 0x7a, 0x57, 0x68, 0x63,
+    0x4e, 0x4d, 0x6a, 0x55, 0x78, 0x4d, 0x6a, 0x4d, 0x78, 0x4d, 0x6a, 0x49,
+    0x31, 0x0a, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, 0x42, 0x32, 0x4d, 0x51,
+    0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77,
+    0x4a, 0x45, 0x52, 0x54, 0x45, 0x63, 0x4d, 0x42, 0x6f, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x43, 0x68, 0x4d, 0x54, 0x56, 0x45, 0x4d, 0x67, 0x56, 0x48,
+    0x4a, 0x31, 0x63, 0x33, 0x52, 0x44, 0x5a, 0x57, 0x35, 0x30, 0x5a, 0x58,
+    0x49, 0x67, 0x52, 0x32, 0x31, 0x69, 0x0a, 0x53, 0x44, 0x45, 0x69, 0x4d,
+    0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x5a, 0x56,
+    0x45, 0x4d, 0x67, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x44, 0x5a,
+    0x57, 0x35, 0x30, 0x5a, 0x58, 0x49, 0x67, 0x51, 0x32, 0x78, 0x68, 0x63,
+    0x33, 0x4d, 0x67, 0x4d, 0x69, 0x42, 0x44, 0x51, 0x54, 0x45, 0x6c, 0x4d,
+    0x43, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x63, 0x0a,
+    0x56, 0x45, 0x4d, 0x67, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x44,
+    0x5a, 0x57, 0x35, 0x30, 0x5a, 0x58, 0x49, 0x67, 0x51, 0x32, 0x78, 0x68,
+    0x63, 0x33, 0x4d, 0x67, 0x4d, 0x69, 0x42, 0x44, 0x51, 0x53, 0x42, 0x4a,
+    0x53, 0x54, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a,
+    0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42,
+    0x42, 0x51, 0x41, 0x44, 0x0a, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43,
+    0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4b, 0x75,
+    0x41, 0x68, 0x35, 0x75, 0x4f, 0x38, 0x4d, 0x4e, 0x38, 0x68, 0x39, 0x66,
+    0x6f, 0x4a, 0x49, 0x49, 0x52, 0x73, 0x7a, 0x7a, 0x64, 0x51, 0x32, 0x4c,
+    0x75, 0x2b, 0x4d, 0x4e, 0x46, 0x32, 0x75, 0x6a, 0x68, 0x6f, 0x46, 0x2f,
+    0x52, 0x4b, 0x72, 0x4c, 0x71, 0x6b, 0x32, 0x6a, 0x66, 0x0a, 0x74, 0x4d,
+    0x6a, 0x57, 0x51, 0x2b, 0x6e, 0x45, 0x64, 0x56, 0x6c, 0x2f, 0x2f, 0x4f,
+    0x45, 0x64, 0x2b, 0x44, 0x46, 0x77, 0x49, 0x78, 0x75, 0x49, 0x6e, 0x69,
+    0x65, 0x35, 0x65, 0x2f, 0x30, 0x36, 0x30, 0x73, 0x6d, 0x70, 0x36, 0x52,
+    0x51, 0x76, 0x6b, 0x4c, 0x34, 0x44, 0x55, 0x73, 0x46, 0x4a, 0x7a, 0x66,
+    0x62, 0x39, 0x35, 0x41, 0x68, 0x6d, 0x43, 0x31, 0x65, 0x4b, 0x6f, 0x6b,
+    0x4b, 0x67, 0x0a, 0x75, 0x4e, 0x56, 0x2f, 0x61, 0x56, 0x79, 0x51, 0x4d,
+    0x72, 0x4b, 0x58, 0x44, 0x63, 0x70, 0x4b, 0x33, 0x45, 0x59, 0x2b, 0x41,
+    0x6c, 0x57, 0x4a, 0x55, 0x2b, 0x4d, 0x61, 0x57, 0x73, 0x73, 0x32, 0x78,
+    0x67, 0x64, 0x57, 0x39, 0x34, 0x7a, 0x50, 0x45, 0x66, 0x52, 0x4d, 0x75,
+    0x7a, 0x42, 0x77, 0x42, 0x4a, 0x57, 0x6c, 0x39, 0x6a, 0x6d, 0x4d, 0x2f,
+    0x58, 0x4f, 0x42, 0x43, 0x48, 0x32, 0x4a, 0x0a, 0x58, 0x6a, 0x49, 0x65,
+    0x49, 0x71, 0x6b, 0x69, 0x52, 0x55, 0x75, 0x77, 0x5a, 0x69, 0x34, 0x77,
+    0x7a, 0x4a, 0x39, 0x6c, 0x2f, 0x66, 0x7a, 0x4c, 0x67, 0x61, 0x6e, 0x78,
+    0x34, 0x44, 0x75, 0x76, 0x6f, 0x34, 0x62, 0x52, 0x69, 0x65, 0x72, 0x45,
+    0x52, 0x58, 0x6c, 0x51, 0x58, 0x61, 0x37, 0x70, 0x49, 0x58, 0x53, 0x53,
+    0x54, 0x59, 0x74, 0x5a, 0x67, 0x6f, 0x2b, 0x55, 0x34, 0x2b, 0x6c, 0x4b,
+    0x0a, 0x38, 0x65, 0x64, 0x4a, 0x73, 0x42, 0x54, 0x6a, 0x39, 0x57, 0x4c,
+    0x4c, 0x31, 0x58, 0x4b, 0x39, 0x48, 0x37, 0x6e, 0x53, 0x6e, 0x36, 0x44,
+    0x4e, 0x71, 0x50, 0x6f, 0x42, 0x79, 0x4e, 0x6b, 0x4e, 0x33, 0x39, 0x72,
+    0x38, 0x52, 0x35, 0x32, 0x7a, 0x79, 0x46, 0x54, 0x66, 0x53, 0x55, 0x72,
+    0x78, 0x49, 0x61, 0x6e, 0x2b, 0x47, 0x45, 0x37, 0x75, 0x53, 0x4e, 0x51,
+    0x5a, 0x75, 0x2b, 0x39, 0x39, 0x0a, 0x35, 0x4f, 0x4b, 0x64, 0x79, 0x31,
+    0x75, 0x32, 0x62, 0x76, 0x2f, 0x6a, 0x7a, 0x56, 0x72, 0x6e, 0x64, 0x49,
+    0x49, 0x46, 0x75, 0x6f, 0x41, 0x6c, 0x4f, 0x4d, 0x76, 0x6b, 0x61, 0x5a,
+    0x36, 0x76, 0x51, 0x61, 0x6f, 0x61, 0x68, 0x50, 0x55, 0x43, 0x41, 0x77,
+    0x45, 0x41, 0x41, 0x61, 0x4f, 0x43, 0x41, 0x54, 0x51, 0x77, 0x67, 0x67,
+    0x45, 0x77, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x0a, 0x45,
+    0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41,
+    0x66, 0x38, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41,
+    0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d,
+    0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42,
+    0x42, 0x54, 0x6a, 0x71, 0x31, 0x52, 0x4d, 0x67, 0x4b, 0x48, 0x62, 0x56,
+    0x6b, 0x4f, 0x33, 0x0a, 0x6b, 0x55, 0x72, 0x4c, 0x38, 0x34, 0x4a, 0x36,
+    0x45, 0x31, 0x77, 0x49, 0x71, 0x7a, 0x43, 0x42, 0x37, 0x51, 0x59, 0x44,
+    0x56, 0x52, 0x30, 0x66, 0x42, 0x49, 0x48, 0x6c, 0x4d, 0x49, 0x48, 0x69,
+    0x4d, 0x49, 0x48, 0x66, 0x6f, 0x49, 0x48, 0x63, 0x6f, 0x49, 0x48, 0x5a,
+    0x68, 0x6a, 0x56, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69, 0x38, 0x76,
+    0x64, 0x33, 0x64, 0x33, 0x4c, 0x6e, 0x52, 0x79, 0x0a, 0x64, 0x58, 0x4e,
+    0x30, 0x59, 0x32, 0x56, 0x75, 0x64, 0x47, 0x56, 0x79, 0x4c, 0x6d, 0x52,
+    0x6c, 0x4c, 0x32, 0x4e, 0x79, 0x62, 0x43, 0x39, 0x32, 0x4d, 0x69, 0x39,
+    0x30, 0x59, 0x31, 0x39, 0x6a, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x31, 0x38,
+    0x79, 0x58, 0x32, 0x4e, 0x68, 0x58, 0x30, 0x6c, 0x4a, 0x4c, 0x6d, 0x4e,
+    0x79, 0x62, 0x49, 0x61, 0x42, 0x6e, 0x32, 0x78, 0x6b, 0x59, 0x58, 0x41,
+    0x36, 0x0a, 0x4c, 0x79, 0x39, 0x33, 0x64, 0x33, 0x63, 0x75, 0x64, 0x48,
+    0x4a, 0x31, 0x63, 0x33, 0x52, 0x6a, 0x5a, 0x57, 0x35, 0x30, 0x5a, 0x58,
+    0x49, 0x75, 0x5a, 0x47, 0x55, 0x76, 0x51, 0x30, 0x34, 0x39, 0x56, 0x45,
+    0x4d, 0x6c, 0x4d, 0x6a, 0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x45,
+    0x4e, 0x6c, 0x62, 0x6e, 0x52, 0x6c, 0x63, 0x69, 0x55, 0x79, 0x4d, 0x45,
+    0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x0a, 0x4a, 0x54, 0x49, 0x77, 0x4d,
+    0x69, 0x55, 0x79, 0x4d, 0x45, 0x4e, 0x42, 0x4a, 0x54, 0x49, 0x77, 0x53,
+    0x55, 0x6b, 0x73, 0x54, 0x7a, 0x31, 0x55, 0x51, 0x79, 0x55, 0x79, 0x4d,
+    0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x51, 0x32, 0x56, 0x75, 0x64,
+    0x47, 0x56, 0x79, 0x4a, 0x54, 0x49, 0x77, 0x52, 0x32, 0x31, 0x69, 0x53,
+    0x43, 0x78, 0x50, 0x56, 0x54, 0x31, 0x79, 0x62, 0x32, 0x39, 0x30, 0x0a,
+    0x59, 0x32, 0x56, 0x79, 0x64, 0x48, 0x4d, 0x73, 0x52, 0x45, 0x4d, 0x39,
+    0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x6a, 0x5a, 0x57, 0x35, 0x30,
+    0x5a, 0x58, 0x49, 0x73, 0x52, 0x45, 0x4d, 0x39, 0x5a, 0x47, 0x55, 0x2f,
+    0x59, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68,
+    0x64, 0x47, 0x56, 0x53, 0x5a, 0x58, 0x5a, 0x76, 0x59, 0x32, 0x46, 0x30,
+    0x61, 0x57, 0x39, 0x75, 0x0a, 0x54, 0x47, 0x6c, 0x7a, 0x64, 0x44, 0x39,
+    0x69, 0x59, 0x58, 0x4e, 0x6c, 0x50, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b,
+    0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55,
+    0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x6a, 0x4e, 0x66,
+    0x66, 0x66, 0x75, 0x34, 0x62, 0x67, 0x42, 0x43, 0x7a, 0x67, 0x2f, 0x58,
+    0x62, 0x45, 0x65, 0x70, 0x72, 0x53, 0x36, 0x69, 0x53, 0x0a, 0x47, 0x4e,
+    0x6e, 0x33, 0x42, 0x7a, 0x6e, 0x31, 0x4c, 0x4c, 0x34, 0x47, 0x64, 0x58,
+    0x70, 0x6f, 0x55, 0x78, 0x55, 0x63, 0x36, 0x6b, 0x72, 0x74, 0x58, 0x76,
+    0x77, 0x6a, 0x73, 0x68, 0x4f, 0x67, 0x30, 0x77, 0x6e, 0x2f, 0x39, 0x76,
+    0x59, 0x75, 0x61, 0x30, 0x46, 0x78, 0x65, 0x63, 0x33, 0x69, 0x62, 0x66,
+    0x32, 0x75, 0x57, 0x57, 0x75, 0x46, 0x48, 0x62, 0x68, 0x4f, 0x49, 0x70,
+    0x72, 0x74, 0x0a, 0x5a, 0x6a, 0x6c, 0x75, 0x53, 0x35, 0x54, 0x6d, 0x56,
+    0x66, 0x77, 0x4c, 0x47, 0x34, 0x74, 0x33, 0x77, 0x56, 0x4d, 0x54, 0x5a,
+    0x6f, 0x6e, 0x5a, 0x4b, 0x4e, 0x61, 0x4c, 0x38, 0x30, 0x56, 0x4b, 0x59,
+    0x37, 0x66, 0x39, 0x65, 0x77, 0x74, 0x68, 0x58, 0x62, 0x68, 0x74, 0x76,
+    0x73, 0x50, 0x63, 0x57, 0x33, 0x6e, 0x53, 0x37, 0x59, 0x62, 0x6c, 0x6f,
+    0x6b, 0x32, 0x2b, 0x58, 0x6e, 0x52, 0x38, 0x0a, 0x61, 0x75, 0x30, 0x57,
+    0x4f, 0x42, 0x39, 0x2f, 0x57, 0x49, 0x46, 0x61, 0x47, 0x75, 0x73, 0x79,
+    0x69, 0x43, 0x32, 0x79, 0x38, 0x7a, 0x6c, 0x33, 0x67, 0x4b, 0x39, 0x65,
+    0x74, 0x6d, 0x46, 0x31, 0x4b, 0x64, 0x73, 0x6a, 0x54, 0x59, 0x6a, 0x4b,
+    0x55, 0x43, 0x6a, 0x4c, 0x68, 0x64, 0x4c, 0x54, 0x45, 0x4b, 0x4a, 0x5a,
+    0x62, 0x74, 0x4f, 0x54, 0x56, 0x41, 0x42, 0x36, 0x6f, 0x6b, 0x61, 0x56,
+    0x0a, 0x68, 0x67, 0x57, 0x63, 0x71, 0x52, 0x6d, 0x59, 0x35, 0x54, 0x46,
+    0x79, 0x44, 0x41, 0x44, 0x69, 0x5a, 0x39, 0x6c, 0x41, 0x34, 0x43, 0x51,
+    0x7a, 0x65, 0x32, 0x38, 0x73, 0x75, 0x56, 0x79, 0x72, 0x5a, 0x5a, 0x30,
+    0x73, 0x72, 0x48, 0x62, 0x71, 0x4e, 0x5a, 0x6e, 0x31, 0x6c, 0x37, 0x6b,
+    0x50, 0x4a, 0x4f, 0x7a, 0x48, 0x64, 0x69, 0x45, 0x6f, 0x5a, 0x61, 0x35,
+    0x58, 0x36, 0x41, 0x65, 0x49, 0x0a, 0x64, 0x55, 0x70, 0x57, 0x6f, 0x4e,
+    0x49, 0x46, 0x4f, 0x71, 0x54, 0x6d, 0x6a, 0x5a, 0x4b, 0x49, 0x4c, 0x50,
+    0x50, 0x79, 0x34, 0x63, 0x48, 0x47, 0x59, 0x64, 0x74, 0x42, 0x78, 0x63,
+    0x65, 0x62, 0x39, 0x77, 0x34, 0x61, 0x55, 0x55, 0x58, 0x43, 0x59, 0x57,
+    0x76, 0x63, 0x5a, 0x43, 0x63, 0x58, 0x6a, 0x46, 0x71, 0x33, 0x32, 0x6e,
+    0x51, 0x6f, 0x7a, 0x5a, 0x66, 0x6b, 0x76, 0x51, 0x3d, 0x3d, 0x0a, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54,
+    0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20,
+    0x43, 0x4e, 0x3d, 0x54, 0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43,
+    0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20,
+    0x33, 0x20, 0x43, 0x41, 0x20, 0x49, 0x49, 0x20, 0x4f, 0x3d, 0x54, 0x43,
+    0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72,
+    0x20, 0x47, 0x6d, 0x62, 0x48, 0x20, 0x4f, 0x55, 0x3d, 0x54, 0x43, 0x20,
+    0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20,
+    0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x43, 0x41, 0x0a, 0x23,
+    0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x54, 0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e,
+    0x74, 0x65, 0x72, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20,
+    0x43, 0x41, 0x20, 0x49, 0x49, 0x20, 0x4f, 0x3d, 0x54, 0x43, 0x20, 0x54,
+    0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x47,
+    0x6d, 0x62, 0x48, 0x20, 0x4f, 0x55, 0x3d, 0x54, 0x43, 0x20, 0x54, 0x72,
+    0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x43, 0x6c,
+    0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x43, 0x41, 0x0a, 0x23, 0x20, 0x4c,
+    0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x54, 0x43, 0x20, 0x54, 0x72,
+    0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x43, 0x6c,
+    0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x43, 0x41, 0x20, 0x49, 0x49, 0x22,
+    0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31,
+    0x35, 0x30, 0x36, 0x35, 0x32, 0x33, 0x35, 0x31, 0x31, 0x34, 0x31, 0x37,
+    0x37, 0x31, 0x35, 0x36, 0x33, 0x38, 0x37, 0x37, 0x32, 0x32, 0x32, 0x30,
+    0x35, 0x33, 0x30, 0x30, 0x32, 0x30, 0x37, 0x39, 0x39, 0x0a, 0x23, 0x20,
+    0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x36, 0x3a, 0x35, 0x66, 0x3a, 0x61,
+    0x61, 0x3a, 0x38, 0x30, 0x3a, 0x36, 0x31, 0x3a, 0x31, 0x32, 0x3a, 0x31,
+    0x37, 0x3a, 0x66, 0x36, 0x3a, 0x36, 0x37, 0x3a, 0x32, 0x31, 0x3a, 0x65,
+    0x36, 0x3a, 0x32, 0x62, 0x3a, 0x36, 0x64, 0x3a, 0x36, 0x31, 0x3a, 0x35,
+    0x36, 0x3a, 0x38, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x38, 0x30, 0x3a, 0x32, 0x35, 0x3a, 0x65, 0x66, 0x3a, 0x66, 0x34,
+    0x3a, 0x36, 0x65, 0x3a, 0x37, 0x30, 0x3a, 0x63, 0x38, 0x3a, 0x64, 0x34,
+    0x3a, 0x37, 0x32, 0x3a, 0x32, 0x34, 0x3a, 0x36, 0x35, 0x3a, 0x38, 0x34,
+    0x3a, 0x66, 0x65, 0x3a, 0x34, 0x30, 0x3a, 0x33, 0x62, 0x3a, 0x38, 0x61,
+    0x3a, 0x38, 0x64, 0x3a, 0x36, 0x61, 0x3a, 0x64, 0x62, 0x3a, 0x66, 0x35,
+    0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69,
+    0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38,
+    0x64, 0x3a, 0x61, 0x30, 0x3a, 0x38, 0x34, 0x3a, 0x66, 0x63, 0x3a, 0x66,
+    0x39, 0x3a, 0x39, 0x63, 0x3a, 0x65, 0x30, 0x3a, 0x37, 0x37, 0x3a, 0x32,
+    0x32, 0x3a, 0x66, 0x38, 0x3a, 0x39, 0x62, 0x3a, 0x33, 0x32, 0x3a, 0x30,
+    0x35, 0x3a, 0x39, 0x33, 0x3a, 0x39, 0x38, 0x3a, 0x30, 0x36, 0x3a, 0x66,
+    0x61, 0x3a, 0x35, 0x63, 0x3a, 0x62, 0x38, 0x3a, 0x31, 0x31, 0x3a, 0x65,
+    0x31, 0x3a, 0x63, 0x38, 0x3a, 0x31, 0x33, 0x3a, 0x66, 0x36, 0x3a, 0x61,
+    0x31, 0x3a, 0x30, 0x38, 0x3a, 0x63, 0x37, 0x3a, 0x64, 0x33, 0x3a, 0x33,
+    0x36, 0x3a, 0x62, 0x33, 0x3a, 0x34, 0x30, 0x3a, 0x38, 0x65, 0x0a, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45,
+    0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x71, 0x6a, 0x43, 0x43, 0x41,
+    0x35, 0x4b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x4f, 0x53,
+    0x6b, 0x63, 0x41, 0x41, 0x51, 0x41, 0x43, 0x35, 0x61, 0x42, 0x64, 0x31,
+    0x6a, 0x38, 0x41, 0x55, 0x62, 0x38, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b,
+    0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42,
+    0x51, 0x41, 0x77, 0x64, 0x6a, 0x45, 0x4c, 0x0a, 0x4d, 0x41, 0x6b, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x45, 0x55, 0x78,
+    0x48, 0x44, 0x41, 0x61, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54,
+    0x45, 0x31, 0x52, 0x44, 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30,
+    0x51, 0x32, 0x56, 0x75, 0x64, 0x47, 0x56, 0x79, 0x49, 0x45, 0x64, 0x74,
+    0x59, 0x6b, 0x67, 0x78, 0x49, 0x6a, 0x41, 0x67, 0x42, 0x67, 0x4e, 0x56,
+    0x0a, 0x42, 0x41, 0x73, 0x54, 0x47, 0x56, 0x52, 0x44, 0x49, 0x46, 0x52,
+    0x79, 0x64, 0x58, 0x4e, 0x30, 0x51, 0x32, 0x56, 0x75, 0x64, 0x47, 0x56,
+    0x79, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44, 0x4d,
+    0x67, 0x51, 0x30, 0x45, 0x78, 0x4a, 0x54, 0x41, 0x6a, 0x42, 0x67, 0x4e,
+    0x56, 0x42, 0x41, 0x4d, 0x54, 0x48, 0x46, 0x52, 0x44, 0x49, 0x46, 0x52,
+    0x79, 0x64, 0x58, 0x4e, 0x30, 0x0a, 0x51, 0x32, 0x56, 0x75, 0x64, 0x47,
+    0x56, 0x79, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44,
+    0x4d, 0x67, 0x51, 0x30, 0x45, 0x67, 0x53, 0x55, 0x6b, 0x77, 0x48, 0x68,
+    0x63, 0x4e, 0x4d, 0x44, 0x59, 0x77, 0x4d, 0x54, 0x45, 0x79, 0x4d, 0x54,
+    0x51, 0x30, 0x4d, 0x54, 0x55, 0x33, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a,
+    0x55, 0x78, 0x4d, 0x6a, 0x4d, 0x78, 0x4d, 0x6a, 0x49, 0x31, 0x0a, 0x4f,
+    0x54, 0x55, 0x35, 0x57, 0x6a, 0x42, 0x32, 0x4d, 0x51, 0x73, 0x77, 0x43,
+    0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x45, 0x52,
+    0x54, 0x45, 0x63, 0x4d, 0x42, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43,
+    0x68, 0x4d, 0x54, 0x56, 0x45, 0x4d, 0x67, 0x56, 0x48, 0x4a, 0x31, 0x63,
+    0x33, 0x52, 0x44, 0x5a, 0x57, 0x35, 0x30, 0x5a, 0x58, 0x49, 0x67, 0x52,
+    0x32, 0x31, 0x69, 0x0a, 0x53, 0x44, 0x45, 0x69, 0x4d, 0x43, 0x41, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x5a, 0x56, 0x45, 0x4d, 0x67,
+    0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x44, 0x5a, 0x57, 0x35, 0x30,
+    0x5a, 0x58, 0x49, 0x67, 0x51, 0x32, 0x78, 0x68, 0x63, 0x33, 0x4d, 0x67,
+    0x4d, 0x79, 0x42, 0x44, 0x51, 0x54, 0x45, 0x6c, 0x4d, 0x43, 0x4d, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x63, 0x0a, 0x56, 0x45, 0x4d,
+    0x67, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x44, 0x5a, 0x57, 0x35,
+    0x30, 0x5a, 0x58, 0x49, 0x67, 0x51, 0x32, 0x78, 0x68, 0x63, 0x33, 0x4d,
+    0x67, 0x4d, 0x79, 0x42, 0x44, 0x51, 0x53, 0x42, 0x4a, 0x53, 0x54, 0x43,
+    0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a,
+    0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41,
+    0x44, 0x0a, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51,
+    0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4c, 0x54, 0x67, 0x75, 0x31,
+    0x47, 0x37, 0x4f, 0x56, 0x79, 0x4c, 0x42, 0x4d, 0x56, 0x4d, 0x65, 0x52,
+    0x77, 0x6a, 0x68, 0x6a, 0x45, 0x51, 0x59, 0x30, 0x4e, 0x56, 0x4a, 0x7a,
+    0x2f, 0x47, 0x52, 0x63, 0x65, 0x6b, 0x50, 0x65, 0x77, 0x4a, 0x44, 0x52,
+    0x6f, 0x65, 0x49, 0x4d, 0x4a, 0x57, 0x0a, 0x48, 0x74, 0x34, 0x62, 0x4e,
+    0x77, 0x63, 0x77, 0x49, 0x69, 0x39, 0x76, 0x38, 0x51, 0x62, 0x78, 0x71,
+    0x36, 0x33, 0x57, 0x79, 0x4b, 0x74, 0x68, 0x6f, 0x79, 0x39, 0x44, 0x78,
+    0x4c, 0x43, 0x79, 0x4c, 0x66, 0x7a, 0x44, 0x6c, 0x6d, 0x6c, 0x37, 0x66,
+    0x6f, 0x72, 0x6b, 0x7a, 0x4d, 0x41, 0x35, 0x45, 0x70, 0x42, 0x43, 0x59,
+    0x4d, 0x6e, 0x4d, 0x4e, 0x57, 0x6a, 0x75, 0x32, 0x6c, 0x2b, 0x51, 0x0a,
+    0x56, 0x6c, 0x2f, 0x4e, 0x48, 0x45, 0x31, 0x62, 0x57, 0x45, 0x6e, 0x72,
+    0x44, 0x67, 0x46, 0x50, 0x5a, 0x50, 0x6f, 0x73, 0x50, 0x49, 0x6c, 0x59,
+    0x32, 0x43, 0x38, 0x75, 0x34, 0x72, 0x42, 0x6f, 0x36, 0x53, 0x49, 0x37,
+    0x64, 0x59, 0x6e, 0x57, 0x52, 0x42, 0x70, 0x6c, 0x38, 0x68, 0x75, 0x58,
+    0x4a, 0x68, 0x30, 0x6f, 0x62, 0x61, 0x7a, 0x6f, 0x76, 0x56, 0x6b, 0x64,
+    0x4b, 0x79, 0x54, 0x32, 0x0a, 0x31, 0x6f, 0x51, 0x44, 0x5a, 0x6f, 0x67,
+    0x6b, 0x41, 0x48, 0x68, 0x67, 0x38, 0x66, 0x69, 0x72, 0x2f, 0x67, 0x4b,
+    0x79, 0x61, 0x2f, 0x73, 0x69, 0x2b, 0x7a, 0x58, 0x6d, 0x46, 0x74, 0x47,
+    0x74, 0x39, 0x69, 0x34, 0x53, 0x35, 0x50, 0x6f, 0x31, 0x61, 0x75, 0x55,
+    0x5a, 0x75, 0x56, 0x33, 0x62, 0x4f, 0x78, 0x34, 0x61, 0x2b, 0x39, 0x50,
+    0x2f, 0x46, 0x52, 0x51, 0x49, 0x32, 0x41, 0x6c, 0x71, 0x0a, 0x75, 0x6b,
+    0x57, 0x64, 0x46, 0x48, 0x6c, 0x67, 0x66, 0x61, 0x39, 0x41, 0x69, 0x67,
+    0x64, 0x7a, 0x73, 0x35, 0x4f, 0x57, 0x30, 0x33, 0x51, 0x30, 0x6a, 0x54,
+    0x6f, 0x33, 0x4b, 0x64, 0x35, 0x63, 0x37, 0x50, 0x58, 0x75, 0x4c, 0x6a,
+    0x48, 0x43, 0x49, 0x4e, 0x79, 0x2b, 0x38, 0x55, 0x39, 0x2f, 0x49, 0x31,
+    0x4c, 0x5a, 0x57, 0x2b, 0x4a, 0x6b, 0x32, 0x5a, 0x79, 0x71, 0x42, 0x77,
+    0x69, 0x31, 0x0a, 0x52, 0x62, 0x33, 0x52, 0x30, 0x44, 0x48, 0x42, 0x71,
+    0x31, 0x53, 0x66, 0x71, 0x64, 0x4c, 0x44, 0x59, 0x6d, 0x41, 0x44, 0x38,
+    0x62, 0x73, 0x35, 0x53, 0x70, 0x4a, 0x4b, 0x50, 0x51, 0x71, 0x35, 0x6e,
+    0x63, 0x57, 0x67, 0x2f, 0x6a, 0x63, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41,
+    0x61, 0x4f, 0x43, 0x41, 0x54, 0x51, 0x77, 0x67, 0x67, 0x45, 0x77, 0x4d,
+    0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x0a, 0x45, 0x77, 0x45, 0x42,
+    0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77,
+    0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f,
+    0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x30, 0x47,
+    0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x54, 0x55,
+    0x6f, 0x76, 0x79, 0x66, 0x73, 0x38, 0x50, 0x59, 0x41, 0x39, 0x4e, 0x58,
+    0x0a, 0x58, 0x41, 0x65, 0x6b, 0x30, 0x43, 0x53, 0x6e, 0x77, 0x50, 0x49,
+    0x41, 0x31, 0x44, 0x43, 0x42, 0x37, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30,
+    0x66, 0x42, 0x49, 0x48, 0x6c, 0x4d, 0x49, 0x48, 0x69, 0x4d, 0x49, 0x48,
+    0x66, 0x6f, 0x49, 0x48, 0x63, 0x6f, 0x49, 0x48, 0x5a, 0x68, 0x6a, 0x56,
+    0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69, 0x38, 0x76, 0x64, 0x33, 0x64,
+    0x33, 0x4c, 0x6e, 0x52, 0x79, 0x0a, 0x64, 0x58, 0x4e, 0x30, 0x59, 0x32,
+    0x56, 0x75, 0x64, 0x47, 0x56, 0x79, 0x4c, 0x6d, 0x52, 0x6c, 0x4c, 0x32,
+    0x4e, 0x79, 0x62, 0x43, 0x39, 0x32, 0x4d, 0x69, 0x39, 0x30, 0x59, 0x31,
+    0x39, 0x6a, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x31, 0x38, 0x7a, 0x58, 0x32,
+    0x4e, 0x68, 0x58, 0x30, 0x6c, 0x4a, 0x4c, 0x6d, 0x4e, 0x79, 0x62, 0x49,
+    0x61, 0x42, 0x6e, 0x32, 0x78, 0x6b, 0x59, 0x58, 0x41, 0x36, 0x0a, 0x4c,
+    0x79, 0x39, 0x33, 0x64, 0x33, 0x63, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63,
+    0x33, 0x52, 0x6a, 0x5a, 0x57, 0x35, 0x30, 0x5a, 0x58, 0x49, 0x75, 0x5a,
+    0x47, 0x55, 0x76, 0x51, 0x30, 0x34, 0x39, 0x56, 0x45, 0x4d, 0x6c, 0x4d,
+    0x6a, 0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x45, 0x4e, 0x6c, 0x62,
+    0x6e, 0x52, 0x6c, 0x63, 0x69, 0x55, 0x79, 0x4d, 0x45, 0x4e, 0x73, 0x59,
+    0x58, 0x4e, 0x7a, 0x0a, 0x4a, 0x54, 0x49, 0x77, 0x4d, 0x79, 0x55, 0x79,
+    0x4d, 0x45, 0x4e, 0x42, 0x4a, 0x54, 0x49, 0x77, 0x53, 0x55, 0x6b, 0x73,
+    0x54, 0x7a, 0x31, 0x55, 0x51, 0x79, 0x55, 0x79, 0x4d, 0x46, 0x52, 0x79,
+    0x64, 0x58, 0x4e, 0x30, 0x51, 0x32, 0x56, 0x75, 0x64, 0x47, 0x56, 0x79,
+    0x4a, 0x54, 0x49, 0x77, 0x52, 0x32, 0x31, 0x69, 0x53, 0x43, 0x78, 0x50,
+    0x56, 0x54, 0x31, 0x79, 0x62, 0x32, 0x39, 0x30, 0x0a, 0x59, 0x32, 0x56,
+    0x79, 0x64, 0x48, 0x4d, 0x73, 0x52, 0x45, 0x4d, 0x39, 0x64, 0x48, 0x4a,
+    0x31, 0x63, 0x33, 0x52, 0x6a, 0x5a, 0x57, 0x35, 0x30, 0x5a, 0x58, 0x49,
+    0x73, 0x52, 0x45, 0x4d, 0x39, 0x5a, 0x47, 0x55, 0x2f, 0x59, 0x32, 0x56,
+    0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x56,
+    0x53, 0x5a, 0x58, 0x5a, 0x76, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39,
+    0x75, 0x0a, 0x54, 0x47, 0x6c, 0x7a, 0x64, 0x44, 0x39, 0x69, 0x59, 0x58,
+    0x4e, 0x6c, 0x50, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b,
+    0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41,
+    0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x4e, 0x6d, 0x44, 0x6b, 0x63, 0x50,
+    0x63, 0x47, 0x49, 0x45, 0x50, 0x5a, 0x49, 0x78, 0x70, 0x43, 0x38, 0x76,
+    0x69, 0x6a, 0x73, 0x72, 0x6c, 0x4e, 0x0a, 0x69, 0x72, 0x54, 0x7a, 0x77,
+    0x70, 0x70, 0x56, 0x4d, 0x58, 0x7a, 0x45, 0x4f, 0x32, 0x65, 0x61, 0x74,
+    0x4e, 0x39, 0x4e, 0x44, 0x6f, 0x71, 0x54, 0x53, 0x68, 0x65, 0x4c, 0x47,
+    0x34, 0x33, 0x4b, 0x69, 0x65, 0x48, 0x50, 0x4f, 0x68, 0x36, 0x73, 0x48,
+    0x66, 0x47, 0x63, 0x4d, 0x72, 0x53, 0x4f, 0x57, 0x58, 0x61, 0x69, 0x51,
+    0x59, 0x55, 0x6c, 0x4e, 0x36, 0x41, 0x54, 0x30, 0x50, 0x56, 0x38, 0x0a,
+    0x54, 0x74, 0x58, 0x71, 0x6c, 0x75, 0x4a, 0x75, 0x63, 0x73, 0x47, 0x37,
+    0x4b, 0x76, 0x35, 0x73, 0x62, 0x76, 0x69, 0x52, 0x6d, 0x45, 0x62, 0x38,
+    0x79, 0x52, 0x74, 0x58, 0x57, 0x2b, 0x72, 0x49, 0x47, 0x6a, 0x73, 0x2f,
+    0x73, 0x46, 0x47, 0x59, 0x50, 0x41, 0x66, 0x61, 0x4c, 0x46, 0x6b, 0x42,
+    0x32, 0x6f, 0x74, 0x45, 0x36, 0x4f, 0x46, 0x30, 0x2f, 0x61, 0x64, 0x6f,
+    0x33, 0x56, 0x53, 0x36, 0x0a, 0x67, 0x30, 0x62, 0x73, 0x79, 0x45, 0x61,
+    0x31, 0x2b, 0x4b, 0x2b, 0x58, 0x77, 0x44, 0x73, 0x4a, 0x48, 0x49, 0x2f,
+    0x4f, 0x63, 0x70, 0x59, 0x39, 0x4d, 0x31, 0x5a, 0x77, 0x76, 0x4a, 0x62,
+    0x4c, 0x32, 0x4e, 0x56, 0x39, 0x49, 0x4a, 0x71, 0x44, 0x6e, 0x78, 0x72,
+    0x63, 0x4f, 0x66, 0x48, 0x46, 0x63, 0x71, 0x4d, 0x52, 0x41, 0x2f, 0x30,
+    0x37, 0x51, 0x6c, 0x49, 0x70, 0x32, 0x2b, 0x67, 0x42, 0x0a, 0x39, 0x35,
+    0x74, 0x65, 0x6a, 0x4e, 0x61, 0x4e, 0x68, 0x6b, 0x34, 0x5a, 0x2b, 0x72,
+    0x77, 0x63, 0x76, 0x73, 0x55, 0x68, 0x70, 0x59, 0x65, 0x65, 0x65, 0x43,
+    0x34, 0x32, 0x32, 0x77, 0x6c, 0x78, 0x6f, 0x33, 0x49, 0x30, 0x2b, 0x47,
+    0x7a, 0x6a, 0x42, 0x67, 0x6e, 0x79, 0x58, 0x6c, 0x61, 0x6c, 0x30, 0x39,
+    0x32, 0x59, 0x2b, 0x74, 0x54, 0x6d, 0x42, 0x76, 0x54, 0x77, 0x74, 0x69,
+    0x42, 0x6a, 0x0a, 0x53, 0x2b, 0x6f, 0x70, 0x76, 0x61, 0x71, 0x43, 0x5a,
+    0x68, 0x37, 0x37, 0x67, 0x61, 0x71, 0x6e, 0x4e, 0x36, 0x30, 0x54, 0x47,
+    0x4f, 0x61, 0x53, 0x77, 0x34, 0x48, 0x42, 0x4d, 0x37, 0x75, 0x49, 0x48,
+    0x71, 0x48, 0x6e, 0x34, 0x72, 0x53, 0x39, 0x4d, 0x57, 0x77, 0x4f, 0x55,
+    0x54, 0x31, 0x76, 0x2b, 0x35, 0x5a, 0x57, 0x67, 0x4f, 0x49, 0x32, 0x46,
+    0x39, 0x48, 0x63, 0x35, 0x41, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23,
+    0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d,
+    0x54, 0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74,
+    0x65, 0x72, 0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c,
+    0x20, 0x43, 0x41, 0x20, 0x49, 0x20, 0x4f, 0x3d, 0x54, 0x43, 0x20, 0x54,
+    0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x47,
+    0x6d, 0x62, 0x48, 0x20, 0x4f, 0x55, 0x3d, 0x54, 0x43, 0x20, 0x54, 0x72,
+    0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x55, 0x6e,
+    0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x0a, 0x23,
+    0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x54, 0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e,
+    0x74, 0x65, 0x72, 0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61,
+    0x6c, 0x20, 0x43, 0x41, 0x20, 0x49, 0x20, 0x4f, 0x3d, 0x54, 0x43, 0x20,
+    0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20,
+    0x47, 0x6d, 0x62, 0x48, 0x20, 0x4f, 0x55, 0x3d, 0x54, 0x43, 0x20, 0x54,
+    0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x55,
+    0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x0a,
+    0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x54, 0x43,
+    0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72,
+    0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x43,
+    0x41, 0x20, 0x49, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61,
+    0x6c, 0x3a, 0x20, 0x36, 0x30, 0x31, 0x30, 0x32, 0x34, 0x38, 0x34, 0x32,
+    0x30, 0x34, 0x32, 0x31, 0x38, 0x39, 0x30, 0x33, 0x35, 0x32, 0x39, 0x35,
+    0x36, 0x31, 0x39, 0x35, 0x38, 0x34, 0x37, 0x33, 0x34, 0x37, 0x32, 0x36,
+    0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x35, 0x3a, 0x65,
+    0x31, 0x3a, 0x61, 0x35, 0x3a, 0x37, 0x32, 0x3a, 0x63, 0x35, 0x3a, 0x61,
+    0x39, 0x3a, 0x33, 0x36, 0x3a, 0x36, 0x34, 0x3a, 0x34, 0x30, 0x3a, 0x39,
+    0x65, 0x3a, 0x66, 0x35, 0x3a, 0x65, 0x34, 0x3a, 0x35, 0x38, 0x3a, 0x38,
+    0x34, 0x3a, 0x36, 0x37, 0x3a, 0x38, 0x63, 0x0a, 0x23, 0x20, 0x53, 0x48,
+    0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x36, 0x62, 0x3a, 0x32, 0x66, 0x3a, 0x33, 0x34,
+    0x3a, 0x61, 0x64, 0x3a, 0x38, 0x39, 0x3a, 0x35, 0x38, 0x3a, 0x62, 0x65,
+    0x3a, 0x36, 0x32, 0x3a, 0x66, 0x64, 0x3a, 0x62, 0x30, 0x3a, 0x36, 0x62,
+    0x3a, 0x35, 0x63, 0x3a, 0x63, 0x65, 0x3a, 0x62, 0x62, 0x3a, 0x39, 0x64,
+    0x3a, 0x64, 0x39, 0x3a, 0x34, 0x66, 0x3a, 0x34, 0x65, 0x3a, 0x33, 0x39,
+    0x3a, 0x66, 0x33, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x65, 0x62, 0x3a, 0x66, 0x33, 0x3a, 0x63, 0x30, 0x3a, 0x32,
+    0x61, 0x3a, 0x38, 0x37, 0x3a, 0x38, 0x39, 0x3a, 0x62, 0x31, 0x3a, 0x66,
+    0x62, 0x3a, 0x37, 0x64, 0x3a, 0x35, 0x31, 0x3a, 0x31, 0x39, 0x3a, 0x39,
+    0x35, 0x3a, 0x64, 0x36, 0x3a, 0x36, 0x33, 0x3a, 0x62, 0x37, 0x3a, 0x32,
+    0x39, 0x3a, 0x30, 0x36, 0x3a, 0x64, 0x39, 0x3a, 0x31, 0x33, 0x3a, 0x63,
+    0x65, 0x3a, 0x30, 0x64, 0x3a, 0x35, 0x65, 0x3a, 0x31, 0x30, 0x3a, 0x35,
+    0x36, 0x3a, 0x38, 0x61, 0x3a, 0x38, 0x61, 0x3a, 0x37, 0x37, 0x3a, 0x65,
+    0x32, 0x3a, 0x35, 0x38, 0x3a, 0x36, 0x31, 0x3a, 0x36, 0x37, 0x3a, 0x65,
+    0x37, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x33, 0x54,
+    0x43, 0x43, 0x41, 0x73, 0x57, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67,
+    0x49, 0x4f, 0x48, 0x61, 0x49, 0x41, 0x41, 0x51, 0x41, 0x43, 0x37, 0x4c,
+    0x64, 0x67, 0x67, 0x48, 0x69, 0x4e, 0x74, 0x67, 0x59, 0x77, 0x44, 0x51,
+    0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51,
+    0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x65, 0x54, 0x45, 0x4c, 0x0a, 0x4d,
+    0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52,
+    0x45, 0x55, 0x78, 0x48, 0x44, 0x41, 0x61, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x6f, 0x54, 0x45, 0x31, 0x52, 0x44, 0x49, 0x46, 0x52, 0x79, 0x64,
+    0x58, 0x4e, 0x30, 0x51, 0x32, 0x56, 0x75, 0x64, 0x47, 0x56, 0x79, 0x49,
+    0x45, 0x64, 0x74, 0x59, 0x6b, 0x67, 0x78, 0x4a, 0x44, 0x41, 0x69, 0x42,
+    0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x73, 0x54, 0x47, 0x31, 0x52, 0x44,
+    0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x51, 0x32, 0x56, 0x75,
+    0x64, 0x47, 0x56, 0x79, 0x49, 0x46, 0x56, 0x75, 0x61, 0x58, 0x5a, 0x6c,
+    0x63, 0x6e, 0x4e, 0x68, 0x62, 0x43, 0x42, 0x44, 0x51, 0x54, 0x45, 0x6d,
+    0x4d, 0x43, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x64,
+    0x56, 0x45, 0x4d, 0x67, 0x56, 0x48, 0x4a, 0x31, 0x0a, 0x63, 0x33, 0x52,
+    0x44, 0x5a, 0x57, 0x35, 0x30, 0x5a, 0x58, 0x49, 0x67, 0x56, 0x57, 0x35,
+    0x70, 0x64, 0x6d, 0x56, 0x79, 0x63, 0x32, 0x46, 0x73, 0x49, 0x45, 0x4e,
+    0x42, 0x49, 0x45, 0x6b, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x59,
+    0x77, 0x4d, 0x7a, 0x49, 0x79, 0x4d, 0x54, 0x55, 0x31, 0x4e, 0x44, 0x49,
+    0x34, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x55, 0x78, 0x4d, 0x6a, 0x4d,
+    0x78, 0x0a, 0x4d, 0x6a, 0x49, 0x31, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a,
+    0x42, 0x35, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x47, 0x45, 0x77, 0x4a, 0x45, 0x52, 0x54, 0x45, 0x63, 0x4d, 0x42,
+    0x6f, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x54, 0x56, 0x45,
+    0x4d, 0x67, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x44, 0x5a, 0x57,
+    0x35, 0x30, 0x5a, 0x58, 0x49, 0x67, 0x0a, 0x52, 0x32, 0x31, 0x69, 0x53,
+    0x44, 0x45, 0x6b, 0x4d, 0x43, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43,
+    0x78, 0x4d, 0x62, 0x56, 0x45, 0x4d, 0x67, 0x56, 0x48, 0x4a, 0x31, 0x63,
+    0x33, 0x52, 0x44, 0x5a, 0x57, 0x35, 0x30, 0x5a, 0x58, 0x49, 0x67, 0x56,
+    0x57, 0x35, 0x70, 0x64, 0x6d, 0x56, 0x79, 0x63, 0x32, 0x46, 0x73, 0x49,
+    0x45, 0x4e, 0x42, 0x4d, 0x53, 0x59, 0x77, 0x4a, 0x41, 0x59, 0x44, 0x0a,
+    0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x31, 0x55, 0x51, 0x79, 0x42, 0x55,
+    0x63, 0x6e, 0x56, 0x7a, 0x64, 0x45, 0x4e, 0x6c, 0x62, 0x6e, 0x52, 0x6c,
+    0x63, 0x69, 0x42, 0x56, 0x62, 0x6d, 0x6c, 0x32, 0x5a, 0x58, 0x4a, 0x7a,
+    0x59, 0x57, 0x77, 0x67, 0x51, 0x30, 0x45, 0x67, 0x53, 0x54, 0x43, 0x43,
+    0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49,
+    0x68, 0x76, 0x63, 0x4e, 0x0a, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41,
+    0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f,
+    0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4b, 0x52, 0x33, 0x49, 0x35, 0x5a,
+    0x45, 0x72, 0x35, 0x44, 0x30, 0x4d, 0x61, 0x63, 0x51, 0x39, 0x43, 0x61,
+    0x48, 0x6e, 0x50, 0x4d, 0x34, 0x32, 0x51, 0x39, 0x65, 0x33, 0x73, 0x39,
+    0x42, 0x36, 0x44, 0x47, 0x74, 0x78, 0x6e, 0x53, 0x52, 0x0a, 0x4a, 0x4a,
+    0x5a, 0x34, 0x48, 0x67, 0x6d, 0x67, 0x6d, 0x35, 0x71, 0x56, 0x53, 0x6b,
+    0x72, 0x31, 0x59, 0x6e, 0x77, 0x43, 0x71, 0x4d, 0x71, 0x73, 0x2b, 0x31,
+    0x6f, 0x45, 0x64, 0x6a, 0x6e, 0x65, 0x58, 0x2f, 0x48, 0x35, 0x73, 0x37,
+    0x2f, 0x7a, 0x41, 0x31, 0x68, 0x56, 0x30, 0x71, 0x71, 0x33, 0x34, 0x77,
+    0x51, 0x69, 0x30, 0x66, 0x69, 0x55, 0x32, 0x69, 0x49, 0x49, 0x41, 0x49,
+    0x33, 0x54, 0x0a, 0x66, 0x43, 0x5a, 0x64, 0x7a, 0x48, 0x64, 0x35, 0x35,
+    0x79, 0x78, 0x34, 0x4f, 0x61, 0x67, 0x6d, 0x63, 0x77, 0x36, 0x69, 0x58,
+    0x53, 0x56, 0x70, 0x68, 0x55, 0x39, 0x56, 0x44, 0x70, 0x72, 0x76, 0x78,
+    0x72, 0x6c, 0x45, 0x34, 0x56, 0x63, 0x39, 0x33, 0x78, 0x39, 0x55, 0x49,
+    0x75, 0x56, 0x76, 0x5a, 0x61, 0x6f, 0x7a, 0x68, 0x44, 0x72, 0x7a, 0x7a,
+    0x6e, 0x71, 0x2b, 0x56, 0x5a, 0x65, 0x75, 0x0a, 0x6a, 0x52, 0x49, 0x50,
+    0x46, 0x44, 0x50, 0x69, 0x55, 0x48, 0x44, 0x44, 0x53, 0x59, 0x63, 0x54,
+    0x76, 0x46, 0x48, 0x65, 0x31, 0x35, 0x67, 0x53, 0x57, 0x75, 0x38, 0x36,
+    0x67, 0x7a, 0x4f, 0x53, 0x42, 0x6e, 0x57, 0x4c, 0x6b, 0x6e, 0x77, 0x53,
+    0x61, 0x48, 0x74, 0x77, 0x61, 0x67, 0x2b, 0x31, 0x6d, 0x37, 0x5a, 0x33,
+    0x57, 0x30, 0x68, 0x5a, 0x6e, 0x65, 0x54, 0x76, 0x57, 0x71, 0x33, 0x7a,
+    0x0a, 0x77, 0x5a, 0x37, 0x55, 0x31, 0x30, 0x56, 0x4f, 0x79, 0x6c, 0x59,
+    0x30, 0x49, 0x62, 0x77, 0x2b, 0x46, 0x31, 0x74, 0x76, 0x64, 0x77, 0x78,
+    0x49, 0x41, 0x55, 0x4d, 0x70, 0x73, 0x4e, 0x30, 0x2f, 0x6c, 0x6d, 0x37,
+    0x6d, 0x6c, 0x61, 0x6f, 0x4d, 0x77, 0x43, 0x43, 0x32, 0x2f, 0x54, 0x34,
+    0x32, 0x4a, 0x35, 0x7a, 0x6a, 0x58, 0x4d, 0x39, 0x4f, 0x67, 0x64, 0x77,
+    0x5a, 0x75, 0x35, 0x47, 0x51, 0x0a, 0x66, 0x65, 0x7a, 0x6d, 0x6c, 0x77,
+    0x51, 0x65, 0x6b, 0x38, 0x77, 0x69, 0x53, 0x64, 0x65, 0x58, 0x68, 0x72,
+    0x59, 0x54, 0x43, 0x6a, 0x78, 0x44, 0x49, 0x33, 0x64, 0x2b, 0x38, 0x4e,
+    0x7a, 0x6d, 0x7a, 0x53, 0x51, 0x66, 0x4f, 0x34, 0x4f, 0x62, 0x4e, 0x44,
+    0x71, 0x44, 0x4e, 0x4f, 0x4d, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61,
+    0x4e, 0x6a, 0x4d, 0x47, 0x45, 0x77, 0x48, 0x77, 0x59, 0x44, 0x0a, 0x56,
+    0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x6b,
+    0x71, 0x52, 0x31, 0x4c, 0x4b, 0x53, 0x65, 0x76, 0x6f, 0x46, 0x45, 0x36,
+    0x33, 0x6e, 0x38, 0x69, 0x73, 0x57, 0x56, 0x70, 0x65, 0x73, 0x51, 0x64,
+    0x58, 0x4d, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41,
+    0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f,
+    0x7a, 0x41, 0x4f, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42,
+    0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x59, 0x59, 0x77,
+    0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45,
+    0x46, 0x4a, 0x4b, 0x6b, 0x64, 0x53, 0x79, 0x6b, 0x6e, 0x72, 0x36, 0x42,
+    0x52, 0x4f, 0x74, 0x35, 0x2f, 0x49, 0x72, 0x46, 0x6c, 0x61, 0x58, 0x72,
+    0x45, 0x48, 0x56, 0x7a, 0x4d, 0x41, 0x30, 0x47, 0x0a, 0x43, 0x53, 0x71,
+    0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55,
+    0x41, 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x41, 0x6f, 0x30, 0x75, 0x43,
+    0x47, 0x31, 0x65, 0x62, 0x34, 0x65, 0x2f, 0x43, 0x58, 0x33, 0x43, 0x4a,
+    0x72, 0x4f, 0x35, 0x55, 0x55, 0x56, 0x67, 0x38, 0x52, 0x4d, 0x4b, 0x57,
+    0x61, 0x54, 0x7a, 0x71, 0x77, 0x4f, 0x75, 0x41, 0x47, 0x79, 0x32, 0x58,
+    0x31, 0x0a, 0x37, 0x63, 0x61, 0x58, 0x4a, 0x2f, 0x34, 0x6c, 0x38, 0x6c,
+    0x66, 0x6d, 0x58, 0x70, 0x57, 0x4d, 0x50, 0x6d, 0x52, 0x67, 0x46, 0x56,
+    0x70, 0x2f, 0x4c, 0x77, 0x30, 0x42, 0x78, 0x62, 0x46, 0x67, 0x2f, 0x55,
+    0x55, 0x31, 0x7a, 0x2f, 0x43, 0x79, 0x76, 0x77, 0x62, 0x5a, 0x37, 0x31,
+    0x71, 0x2b, 0x73, 0x32, 0x49, 0x68, 0x74, 0x4e, 0x65, 0x72, 0x4e, 0x58,
+    0x78, 0x54, 0x50, 0x71, 0x59, 0x6e, 0x0a, 0x38, 0x61, 0x45, 0x74, 0x32,
+    0x68, 0x6f, 0x6a, 0x6e, 0x63, 0x7a, 0x64, 0x37, 0x44, 0x77, 0x74, 0x6e,
+    0x69, 0x63, 0x30, 0x58, 0x51, 0x2f, 0x43, 0x4e, 0x6e, 0x6d, 0x38, 0x79,
+    0x55, 0x70, 0x69, 0x4c, 0x65, 0x31, 0x72, 0x32, 0x58, 0x31, 0x42, 0x51,
+    0x33, 0x79, 0x32, 0x71, 0x73, 0x72, 0x74, 0x59, 0x62, 0x45, 0x33, 0x67,
+    0x68, 0x55, 0x4a, 0x47, 0x6f, 0x6f, 0x57, 0x4d, 0x4e, 0x6a, 0x73, 0x0a,
+    0x79, 0x64, 0x5a, 0x48, 0x63, 0x6e, 0x68, 0x4c, 0x45, 0x45, 0x59, 0x55,
+    0x6a, 0x6c, 0x38, 0x4f, 0x72, 0x2b, 0x7a, 0x48, 0x4c, 0x36, 0x73, 0x51,
+    0x31, 0x37, 0x62, 0x78, 0x62, 0x75, 0x79, 0x47, 0x73, 0x73, 0x4c, 0x6f,
+    0x44, 0x5a, 0x4a, 0x7a, 0x33, 0x4b, 0x4c, 0x30, 0x44, 0x7a, 0x71, 0x2f,
+    0x59, 0x53, 0x4d, 0x51, 0x69, 0x5a, 0x78, 0x49, 0x51, 0x47, 0x35, 0x77,
+    0x41, 0x4c, 0x50, 0x54, 0x0a, 0x75, 0x6a, 0x64, 0x45, 0x57, 0x42, 0x46,
+    0x36, 0x41, 0x6d, 0x71, 0x49, 0x38, 0x44, 0x63, 0x30, 0x38, 0x42, 0x6e,
+    0x70, 0x72, 0x4e, 0x52, 0x6c, 0x63, 0x2f, 0x5a, 0x70, 0x6a, 0x47, 0x53,
+    0x55, 0x4f, 0x6e, 0x6d, 0x46, 0x4b, 0x62, 0x41, 0x57, 0x4b, 0x77, 0x79,
+    0x43, 0x50, 0x77, 0x61, 0x63, 0x78, 0x2f, 0x30, 0x51, 0x4b, 0x35, 0x34,
+    0x50, 0x4c, 0x4c, 0x61, 0x65, 0x34, 0x78, 0x57, 0x2f, 0x0a, 0x32, 0x54,
+    0x59, 0x63, 0x75, 0x69, 0x55, 0x61, 0x55, 0x6a, 0x30, 0x61, 0x37, 0x43,
+    0x49, 0x4d, 0x48, 0x4f, 0x43, 0x6b, 0x6f, 0x6a, 0x33, 0x77, 0x36, 0x44,
+    0x6e, 0x50, 0x67, 0x63, 0x42, 0x37, 0x37, 0x56, 0x30, 0x66, 0x62, 0x38,
+    0x58, 0x51, 0x43, 0x39, 0x65, 0x59, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43,
+    0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20,
+    0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43,
+    0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c,
+    0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d,
+    0x43, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20,
+    0x49, 0x6e, 0x63, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63,
+    0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x79, 0x62, 0x65, 0x72, 0x74,
+    0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20,
+    0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x43, 0x79, 0x62, 0x65, 0x72,
+    0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x0a, 0x23,
+    0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x79, 0x62,
+    0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62,
+    0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x0a, 0x23, 0x20, 0x53,
+    0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x34, 0x38, 0x33, 0x35, 0x37,
+    0x30, 0x33, 0x32, 0x37, 0x38, 0x34, 0x35, 0x39, 0x36, 0x38, 0x32, 0x38,
+    0x37, 0x37, 0x34, 0x38, 0x34, 0x33, 0x36, 0x30, 0x0a, 0x23, 0x20, 0x4d,
+    0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x37, 0x32, 0x3a, 0x65, 0x34, 0x3a, 0x34, 0x61,
+    0x3a, 0x38, 0x37, 0x3a, 0x65, 0x33, 0x3a, 0x36, 0x39, 0x3a, 0x34, 0x30,
+    0x3a, 0x38, 0x30, 0x3a, 0x37, 0x37, 0x3a, 0x65, 0x61, 0x3a, 0x62, 0x63,
+    0x3a, 0x65, 0x33, 0x3a, 0x66, 0x34, 0x3a, 0x66, 0x66, 0x3a, 0x66, 0x30,
+    0x3a, 0x65, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x35, 0x66, 0x3a, 0x34, 0x33, 0x3a, 0x65, 0x35, 0x3a, 0x62, 0x31, 0x3a,
+    0x62, 0x66, 0x3a, 0x66, 0x38, 0x3a, 0x37, 0x38, 0x3a, 0x38, 0x63, 0x3a,
+    0x61, 0x63, 0x3a, 0x31, 0x63, 0x3a, 0x63, 0x37, 0x3a, 0x63, 0x61, 0x3a,
+    0x34, 0x61, 0x3a, 0x39, 0x61, 0x3a, 0x63, 0x36, 0x3a, 0x32, 0x32, 0x3a,
+    0x32, 0x62, 0x3a, 0x63, 0x63, 0x3a, 0x33, 0x34, 0x3a, 0x63, 0x36, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x36,
+    0x3a, 0x30, 0x61, 0x3a, 0x64, 0x66, 0x3a, 0x30, 0x30, 0x3a, 0x36, 0x33,
+    0x3a, 0x65, 0x39, 0x3a, 0x36, 0x33, 0x3a, 0x35, 0x36, 0x3a, 0x37, 0x35,
+    0x3a, 0x30, 0x63, 0x3a, 0x32, 0x39, 0x3a, 0x36, 0x35, 0x3a, 0x64, 0x64,
+    0x3a, 0x30, 0x61, 0x3a, 0x30, 0x38, 0x3a, 0x36, 0x37, 0x3a, 0x64, 0x61,
+    0x3a, 0x30, 0x62, 0x3a, 0x39, 0x63, 0x3a, 0x62, 0x64, 0x3a, 0x36, 0x65,
+    0x3a, 0x37, 0x37, 0x3a, 0x37, 0x31, 0x3a, 0x34, 0x61, 0x3a, 0x65, 0x61,
+    0x3a, 0x66, 0x62, 0x3a, 0x32, 0x33, 0x3a, 0x34, 0x39, 0x3a, 0x61, 0x62,
+    0x3a, 0x33, 0x39, 0x3a, 0x33, 0x64, 0x3a, 0x61, 0x33, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52,
+    0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x6f, 0x54, 0x43, 0x43, 0x41, 0x6f,
+    0x6d, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x4c, 0x42, 0x41,
+    0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x44, 0x34, 0x57, 0x71, 0x4c, 0x55,
+    0x67, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76,
+    0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x4f, 0x7a,
+    0x45, 0x59, 0x4d, 0x42, 0x59, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x43,
+    0x68, 0x4d, 0x50, 0x51, 0x33, 0x6c, 0x69, 0x5a, 0x58, 0x4a, 0x30, 0x63,
+    0x6e, 0x56, 0x7a, 0x64, 0x43, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d,
+    0x52, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45,
+    0x78, 0x5a, 0x44, 0x65, 0x57, 0x4a, 0x6c, 0x63, 0x6e, 0x52, 0x79, 0x64,
+    0x58, 0x4e, 0x30, 0x49, 0x45, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x0a,
+    0x62, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x4d, 0x42, 0x34, 0x58,
+    0x44, 0x54, 0x41, 0x32, 0x4d, 0x54, 0x49, 0x78, 0x4e, 0x54, 0x41, 0x34,
+    0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x78,
+    0x4d, 0x54, 0x49, 0x78, 0x4e, 0x54, 0x41, 0x34, 0x4d, 0x44, 0x41, 0x77,
+    0x4d, 0x46, 0x6f, 0x77, 0x4f, 0x7a, 0x45, 0x59, 0x4d, 0x42, 0x59, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x0a, 0x43, 0x68, 0x4d, 0x50, 0x51, 0x33, 0x6c,
+    0x69, 0x5a, 0x58, 0x4a, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x77,
+    0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d, 0x52, 0x38, 0x77, 0x48, 0x51, 0x59,
+    0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x5a, 0x44, 0x65, 0x57, 0x4a,
+    0x6c, 0x63, 0x6e, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x64,
+    0x73, 0x62, 0x32, 0x4a, 0x68, 0x62, 0x43, 0x42, 0x53, 0x0a, 0x62, 0x32,
+    0x39, 0x30, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67,
+    0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51,
+    0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49,
+    0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x2b, 0x4d,
+    0x69, 0x38, 0x76, 0x52, 0x52, 0x51, 0x5a, 0x68, 0x50, 0x2f, 0x38, 0x4e,
+    0x4e, 0x35, 0x0a, 0x37, 0x43, 0x50, 0x79, 0x74, 0x78, 0x72, 0x48, 0x6a,
+    0x6f, 0x58, 0x78, 0x45, 0x6e, 0x4f, 0x6d, 0x47, 0x61, 0x6f, 0x51, 0x32,
+    0x35, 0x79, 0x69, 0x5a, 0x58, 0x52, 0x61, 0x64, 0x7a, 0x35, 0x52, 0x66,
+    0x56, 0x62, 0x32, 0x33, 0x43, 0x4f, 0x32, 0x31, 0x4f, 0x31, 0x66, 0x57,
+    0x4c, 0x45, 0x33, 0x54, 0x64, 0x56, 0x4a, 0x44, 0x6d, 0x37, 0x31, 0x61,
+    0x6f, 0x66, 0x57, 0x30, 0x6f, 0x7a, 0x53, 0x0a, 0x4a, 0x38, 0x62, 0x69,
+    0x2f, 0x7a, 0x61, 0x66, 0x6d, 0x47, 0x57, 0x67, 0x45, 0x30, 0x37, 0x47,
+    0x4b, 0x6d, 0x53, 0x62, 0x31, 0x5a, 0x41, 0x53, 0x7a, 0x78, 0x51, 0x47,
+    0x39, 0x44, 0x76, 0x6a, 0x31, 0x43, 0x69, 0x2b, 0x36, 0x41, 0x37, 0x34,
+    0x71, 0x30, 0x35, 0x49, 0x6c, 0x47, 0x32, 0x4f, 0x6c, 0x54, 0x45, 0x51,
+    0x58, 0x4f, 0x32, 0x69, 0x4c, 0x62, 0x33, 0x56, 0x4f, 0x6d, 0x32, 0x79,
+    0x0a, 0x48, 0x4c, 0x74, 0x67, 0x77, 0x45, 0x5a, 0x4c, 0x41, 0x66, 0x56,
+    0x4a, 0x72, 0x6e, 0x35, 0x47, 0x69, 0x74, 0x42, 0x30, 0x6a, 0x61, 0x45,
+    0x4d, 0x41, 0x73, 0x37, 0x75, 0x2f, 0x4f, 0x65, 0x50, 0x75, 0x47, 0x74,
+    0x6d, 0x38, 0x33, 0x39, 0x45, 0x41, 0x4c, 0x39, 0x6d, 0x4a, 0x52, 0x51,
+    0x72, 0x33, 0x52, 0x41, 0x77, 0x48, 0x51, 0x65, 0x57, 0x50, 0x30, 0x33,
+    0x32, 0x61, 0x37, 0x69, 0x50, 0x0a, 0x74, 0x33, 0x73, 0x4d, 0x70, 0x54,
+    0x6a, 0x72, 0x33, 0x6b, 0x66, 0x62, 0x31, 0x56, 0x30, 0x35, 0x2f, 0x49,
+    0x69, 0x6e, 0x38, 0x39, 0x63, 0x71, 0x64, 0x50, 0x48, 0x6f, 0x57, 0x71,
+    0x49, 0x37, 0x6e, 0x31, 0x43, 0x36, 0x70, 0x6f, 0x78, 0x46, 0x4e, 0x63,
+    0x4a, 0x51, 0x5a, 0x5a, 0x58, 0x63, 0x59, 0x34, 0x4c, 0x76, 0x33, 0x62,
+    0x39, 0x33, 0x54, 0x5a, 0x78, 0x69, 0x79, 0x57, 0x4e, 0x7a, 0x0a, 0x46,
+    0x74, 0x41, 0x70, 0x44, 0x30, 0x6d, 0x70, 0x53, 0x50, 0x43, 0x7a, 0x71,
+    0x72, 0x64, 0x73, 0x78, 0x61, 0x63, 0x77, 0x4f, 0x55, 0x42, 0x64, 0x72,
+    0x73, 0x54, 0x69, 0x58, 0x53, 0x5a, 0x54, 0x38, 0x4d, 0x34, 0x63, 0x49,
+    0x77, 0x68, 0x68, 0x71, 0x4a, 0x51, 0x5a, 0x75, 0x67, 0x52, 0x69, 0x51,
+    0x4f, 0x77, 0x66, 0x4f, 0x48, 0x42, 0x33, 0x45, 0x67, 0x5a, 0x78, 0x70,
+    0x7a, 0x41, 0x59, 0x0a, 0x58, 0x53, 0x55, 0x6e, 0x70, 0x51, 0x49, 0x44,
+    0x41, 0x51, 0x41, 0x42, 0x6f, 0x34, 0x47, 0x6c, 0x4d, 0x49, 0x47, 0x69,
+    0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42,
+    0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x50,
+    0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45,
+    0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x0a, 0x4d, 0x42, 0x30,
+    0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x53,
+    0x32, 0x43, 0x48, 0x73, 0x4e, 0x65, 0x73, 0x79, 0x73, 0x49, 0x45, 0x79,
+    0x47, 0x56, 0x6a, 0x4a, 0x65, 0x7a, 0x36, 0x74, 0x75, 0x68, 0x53, 0x31,
+    0x77, 0x56, 0x7a, 0x41, 0x2f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x38,
+    0x45, 0x4f, 0x44, 0x41, 0x32, 0x4d, 0x44, 0x53, 0x67, 0x4d, 0x71, 0x41,
+    0x77, 0x0a, 0x68, 0x69, 0x35, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69,
+    0x38, 0x76, 0x64, 0x33, 0x64, 0x33, 0x4d, 0x69, 0x35, 0x77, 0x64, 0x57,
+    0x4a, 0x73, 0x61, 0x57, 0x4d, 0x74, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33,
+    0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x32, 0x4e, 0x79, 0x62, 0x43,
+    0x39, 0x6a, 0x64, 0x43, 0x39, 0x6a, 0x64, 0x48, 0x4a, 0x76, 0x62, 0x33,
+    0x51, 0x75, 0x59, 0x33, 0x4a, 0x73, 0x0a, 0x4d, 0x42, 0x38, 0x47, 0x41,
+    0x31, 0x55, 0x64, 0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, 0x61, 0x41, 0x46,
+    0x4c, 0x59, 0x49, 0x65, 0x77, 0x31, 0x36, 0x7a, 0x4b, 0x77, 0x67, 0x54,
+    0x49, 0x5a, 0x57, 0x4d, 0x6c, 0x37, 0x50, 0x71, 0x32, 0x36, 0x46, 0x4c,
+    0x58, 0x42, 0x58, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53,
+    0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x0a,
+    0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x42, 0x57, 0x37, 0x77, 0x6f, 0x6a,
+    0x6f, 0x46, 0x52, 0x4f, 0x6c, 0x5a, 0x66, 0x4a, 0x2b, 0x49, 0x6e, 0x61,
+    0x52, 0x63, 0x48, 0x55, 0x6f, 0x77, 0x41, 0x6c, 0x39, 0x42, 0x38, 0x54,
+    0x71, 0x37, 0x65, 0x6a, 0x68, 0x56, 0x68, 0x70, 0x77, 0x6a, 0x43, 0x74,
+    0x32, 0x42, 0x57, 0x4b, 0x4c, 0x65, 0x50, 0x4a, 0x7a, 0x59, 0x46, 0x61,
+    0x2b, 0x48, 0x4d, 0x6a, 0x0a, 0x57, 0x71, 0x64, 0x38, 0x42, 0x66, 0x50,
+    0x39, 0x49, 0x6a, 0x73, 0x4f, 0x30, 0x51, 0x62, 0x45, 0x32, 0x7a, 0x5a,
+    0x4d, 0x63, 0x77, 0x53, 0x4f, 0x35, 0x62, 0x41, 0x69, 0x35, 0x4d, 0x58,
+    0x7a, 0x4c, 0x71, 0x58, 0x5a, 0x49, 0x2b, 0x4f, 0x34, 0x54, 0x6b, 0x6f,
+    0x67, 0x70, 0x32, 0x34, 0x43, 0x4a, 0x4a, 0x38, 0x69, 0x59, 0x47, 0x64,
+    0x37, 0x69, 0x78, 0x31, 0x79, 0x43, 0x63, 0x55, 0x78, 0x0a, 0x58, 0x4f,
+    0x6c, 0x35, 0x6e, 0x34, 0x42, 0x48, 0x50, 0x61, 0x32, 0x68, 0x43, 0x77,
+    0x63, 0x55, 0x50, 0x55, 0x66, 0x2f, 0x41, 0x32, 0x6b, 0x61, 0x44, 0x41,
+    0x74, 0x45, 0x35, 0x32, 0x4d, 0x6c, 0x70, 0x33, 0x2b, 0x79, 0x79, 0x62,
+    0x68, 0x32, 0x68, 0x4f, 0x30, 0x6a, 0x39, 0x6e, 0x30, 0x48, 0x71, 0x30,
+    0x56, 0x2b, 0x30, 0x39, 0x2b, 0x7a, 0x76, 0x2b, 0x6d, 0x4b, 0x74, 0x73,
+    0x32, 0x6f, 0x0a, 0x6f, 0x6d, 0x63, 0x72, 0x55, 0x74, 0x57, 0x33, 0x5a,
+    0x66, 0x41, 0x35, 0x54, 0x47, 0x4f, 0x67, 0x6b, 0x58, 0x6d, 0x54, 0x55,
+    0x67, 0x39, 0x55, 0x33, 0x59, 0x4f, 0x37, 0x6e, 0x39, 0x47, 0x50, 0x70,
+    0x31, 0x4e, 0x7a, 0x77, 0x38, 0x76, 0x2f, 0x4d, 0x4f, 0x78, 0x38, 0x42,
+    0x4c, 0x6a, 0x59, 0x52, 0x42, 0x2b, 0x54, 0x58, 0x33, 0x45, 0x4a, 0x49,
+    0x72, 0x64, 0x75, 0x50, 0x75, 0x6f, 0x63, 0x0a, 0x41, 0x30, 0x36, 0x64,
+    0x47, 0x69, 0x42, 0x68, 0x2b, 0x34, 0x45, 0x33, 0x37, 0x46, 0x37, 0x38,
+    0x43, 0x6b, 0x57, 0x72, 0x31, 0x2b, 0x63, 0x58, 0x56, 0x64, 0x43, 0x67,
+    0x36, 0x6d, 0x43, 0x62, 0x70, 0x76, 0x62, 0x6a, 0x6a, 0x46, 0x73, 0x70,
+    0x77, 0x67, 0x5a, 0x67, 0x46, 0x4a, 0x30, 0x74, 0x6c, 0x30, 0x79, 0x70,
+    0x6b, 0x78, 0x57, 0x64, 0x59, 0x63, 0x51, 0x42, 0x58, 0x30, 0x6a, 0x57,
+    0x0a, 0x57, 0x4c, 0x31, 0x57, 0x4d, 0x52, 0x4a, 0x4f, 0x45, 0x63, 0x67,
+    0x68, 0x34, 0x4c, 0x4d, 0x52, 0x6b, 0x57, 0x58, 0x62, 0x74, 0x4b, 0x61,
+    0x49, 0x4f, 0x4d, 0x35, 0x56, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45,
+    0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41,
+    0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49,
+    0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65,
+    0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61,
+    0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+    0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+    0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x47, 0x65,
+    0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20,
+    0x4f, 0x55, 0x3d, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20,
+    0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63,
+    0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f,
+    0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63,
+    0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75,
+    0x73, 0x74, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43,
+    0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+    0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d,
+    0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75,
+    0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x28,
+    0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x47, 0x65, 0x6f, 0x54,
+    0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20,
+    0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a,
+    0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a,
+    0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x65,
+    0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61,
+    0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+    0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+    0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x22, 0x0a, 0x23, 0x20, 0x53,
+    0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x32, 0x38, 0x38, 0x30, 0x39,
+    0x31, 0x30, 0x35, 0x37, 0x36, 0x39, 0x39, 0x32, 0x38, 0x35, 0x36, 0x34,
+    0x33, 0x31, 0x33, 0x39, 0x38, 0x34, 0x30, 0x38, 0x35, 0x32, 0x30, 0x39,
+    0x39, 0x37, 0x35, 0x38, 0x38, 0x35, 0x35, 0x39, 0x39, 0x0a, 0x23, 0x20,
+    0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x35, 0x3a, 0x65, 0x38, 0x3a, 0x33,
+    0x34, 0x3a, 0x33, 0x36, 0x3a, 0x63, 0x39, 0x3a, 0x31, 0x30, 0x3a, 0x34,
+    0x34, 0x3a, 0x35, 0x38, 0x3a, 0x34, 0x38, 0x3a, 0x37, 0x30, 0x3a, 0x36,
+    0x64, 0x3a, 0x32, 0x65, 0x3a, 0x38, 0x33, 0x3a, 0x64, 0x34, 0x3a, 0x62,
+    0x38, 0x3a, 0x30, 0x35, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x30, 0x33, 0x3a, 0x39, 0x65, 0x3a, 0x65, 0x64, 0x3a, 0x62, 0x38,
+    0x3a, 0x30, 0x62, 0x3a, 0x65, 0x37, 0x3a, 0x61, 0x30, 0x3a, 0x33, 0x63,
+    0x3a, 0x36, 0x39, 0x3a, 0x35, 0x33, 0x3a, 0x38, 0x39, 0x3a, 0x33, 0x62,
+    0x3a, 0x32, 0x30, 0x3a, 0x64, 0x32, 0x3a, 0x64, 0x39, 0x3a, 0x33, 0x32,
+    0x3a, 0x33, 0x61, 0x3a, 0x34, 0x63, 0x3a, 0x32, 0x61, 0x3a, 0x66, 0x64,
+    0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69,
+    0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62,
+    0x34, 0x3a, 0x37, 0x38, 0x3a, 0x62, 0x38, 0x3a, 0x31, 0x32, 0x3a, 0x32,
+    0x35, 0x3a, 0x30, 0x64, 0x3a, 0x66, 0x38, 0x3a, 0x37, 0x38, 0x3a, 0x36,
+    0x33, 0x3a, 0x35, 0x63, 0x3a, 0x32, 0x61, 0x3a, 0x61, 0x37, 0x3a, 0x65,
+    0x63, 0x3a, 0x37, 0x64, 0x3a, 0x31, 0x35, 0x3a, 0x35, 0x65, 0x3a, 0x61,
+    0x61, 0x3a, 0x36, 0x32, 0x3a, 0x35, 0x65, 0x3a, 0x65, 0x38, 0x3a, 0x32,
+    0x39, 0x3a, 0x31, 0x36, 0x3a, 0x65, 0x32, 0x3a, 0x63, 0x64, 0x3a, 0x32,
+    0x39, 0x3a, 0x34, 0x33, 0x3a, 0x36, 0x31, 0x3a, 0x38, 0x38, 0x3a, 0x36,
+    0x63, 0x3a, 0x64, 0x31, 0x3a, 0x66, 0x62, 0x3a, 0x64, 0x34, 0x0a, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45,
+    0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x2f, 0x6a, 0x43, 0x43, 0x41,
+    0x75, 0x61, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x46,
+    0x61, 0x78, 0x75, 0x6c, 0x42, 0x6d, 0x79, 0x65, 0x55, 0x74, 0x42, 0x39,
+    0x69, 0x65, 0x70, 0x77, 0x78, 0x67, 0x50, 0x48, 0x7a, 0x41, 0x4e, 0x42,
+    0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41,
+    0x51, 0x73, 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x6d, 0x44, 0x45, 0x4c,
+    0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43,
+    0x56, 0x56, 0x4d, 0x78, 0x46, 0x6a, 0x41, 0x55, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x6f, 0x54, 0x44, 0x55, 0x64, 0x6c, 0x62, 0x31, 0x52, 0x79,
+    0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78,
+    0x4f, 0x54, 0x41, 0x33, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54,
+    0x0a, 0x4d, 0x43, 0x68, 0x6a, 0x4b, 0x53, 0x41, 0x79, 0x4d, 0x44, 0x41,
+    0x34, 0x49, 0x45, 0x64, 0x6c, 0x62, 0x31, 0x52, 0x79, 0x64, 0x58, 0x4e,
+    0x30, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x67, 0x4c, 0x53, 0x42,
+    0x47, 0x62, 0x33, 0x49, 0x67, 0x59, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39,
+    0x79, 0x61, 0x58, 0x70, 0x6c, 0x5a, 0x43, 0x42, 0x31, 0x63, 0x32, 0x55,
+    0x67, 0x62, 0x32, 0x35, 0x73, 0x0a, 0x65, 0x54, 0x45, 0x32, 0x4d, 0x44,
+    0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x74, 0x52, 0x32,
+    0x56, 0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x55, 0x48,
+    0x4a, 0x70, 0x62, 0x57, 0x46, 0x79, 0x65, 0x53, 0x42, 0x44, 0x5a, 0x58,
+    0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57,
+    0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x0a, 0x63,
+    0x6d, 0x6c, 0x30, 0x65, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x7a, 0x4d,
+    0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x34, 0x4d, 0x44, 0x51, 0x77, 0x4d,
+    0x6a, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44,
+    0x54, 0x4d, 0x33, 0x4d, 0x54, 0x49, 0x77, 0x4d, 0x54, 0x49, 0x7a, 0x4e,
+    0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x67, 0x5a, 0x67, 0x78, 0x43,
+    0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54,
+    0x41, 0x6c, 0x56, 0x54, 0x4d, 0x52, 0x59, 0x77, 0x46, 0x41, 0x59, 0x44,
+    0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x31, 0x48, 0x5a, 0x57, 0x39, 0x55,
+    0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75,
+    0x4d, 0x54, 0x6b, 0x77, 0x4e, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c,
+    0x45, 0x7a, 0x41, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x0a, 0x4d, 0x6a, 0x41,
+    0x77, 0x4f, 0x43, 0x42, 0x48, 0x5a, 0x57, 0x39, 0x55, 0x63, 0x6e, 0x56,
+    0x7a, 0x64, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30,
+    0x67, 0x52, 0x6d, 0x39, 0x79, 0x49, 0x47, 0x46, 0x31, 0x64, 0x47, 0x68,
+    0x76, 0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, 0x58, 0x4e,
+    0x6c, 0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x4e, 0x6a, 0x41,
+    0x30, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x4c, 0x55,
+    0x64, 0x6c, 0x62, 0x31, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x46,
+    0x42, 0x79, 0x61, 0x57, 0x31, 0x68, 0x63, 0x6e, 0x6b, 0x67, 0x51, 0x32,
+    0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47,
+    0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33,
+    0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x0a, 0x4c, 0x53, 0x42, 0x48, 0x4d,
+    0x7a, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b,
+    0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42,
+    0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41,
+    0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4e, 0x7a, 0x69, 0x58,
+    0x6d, 0x4a, 0x59, 0x48, 0x54, 0x4e, 0x58, 0x4f, 0x54, 0x49, 0x7a, 0x0a,
+    0x2b, 0x75, 0x76, 0x4c, 0x68, 0x34, 0x79, 0x6e, 0x31, 0x45, 0x72, 0x64,
+    0x42, 0x6f, 0x6a, 0x71, 0x5a, 0x49, 0x34, 0x78, 0x6d, 0x4b, 0x55, 0x34,
+    0x6b, 0x42, 0x36, 0x59, 0x7a, 0x79, 0x35, 0x6a, 0x4b, 0x2f, 0x42, 0x47,
+    0x76, 0x45, 0x53, 0x79, 0x69, 0x61, 0x48, 0x41, 0x4b, 0x41, 0x78, 0x4a,
+    0x63, 0x43, 0x47, 0x56, 0x6e, 0x32, 0x54, 0x41, 0x70, 0x70, 0x4d, 0x53,
+    0x41, 0x6d, 0x55, 0x6d, 0x0a, 0x68, 0x73, 0x61, 0x6c, 0x69, 0x66, 0x44,
+    0x36, 0x31, 0x34, 0x53, 0x67, 0x63, 0x4b, 0x39, 0x50, 0x47, 0x70, 0x63,
+    0x2f, 0x42, 0x6b, 0x54, 0x56, 0x79, 0x65, 0x74, 0x79, 0x45, 0x48, 0x33,
+    0x6b, 0x4d, 0x53, 0x6a, 0x37, 0x48, 0x47, 0x48, 0x6d, 0x4b, 0x41, 0x64,
+    0x45, 0x63, 0x35, 0x49, 0x69, 0x61, 0x61, 0x63, 0x44, 0x69, 0x47, 0x79,
+    0x64, 0x59, 0x38, 0x68, 0x53, 0x32, 0x70, 0x67, 0x6e, 0x0a, 0x35, 0x77,
+    0x68, 0x4d, 0x63, 0x44, 0x36, 0x30, 0x79, 0x52, 0x4c, 0x42, 0x78, 0x57,
+    0x65, 0x44, 0x58, 0x54, 0x50, 0x7a, 0x41, 0x78, 0x48, 0x73, 0x61, 0x74,
+    0x42, 0x54, 0x34, 0x74, 0x47, 0x36, 0x4e, 0x6d, 0x43, 0x55, 0x67, 0x4c,
+    0x74, 0x68, 0x59, 0x32, 0x78, 0x62, 0x46, 0x33, 0x37, 0x66, 0x51, 0x4a,
+    0x51, 0x65, 0x71, 0x77, 0x33, 0x43, 0x49, 0x53, 0x68, 0x77, 0x69, 0x50,
+    0x2f, 0x57, 0x0a, 0x4a, 0x6d, 0x78, 0x73, 0x59, 0x41, 0x51, 0x6c, 0x54,
+    0x6c, 0x56, 0x2b, 0x66, 0x65, 0x2b, 0x2f, 0x6c, 0x45, 0x6a, 0x65, 0x74,
+    0x78, 0x33, 0x64, 0x63, 0x49, 0x30, 0x46, 0x58, 0x34, 0x69, 0x6c, 0x6d,
+    0x2f, 0x4c, 0x43, 0x37, 0x75, 0x72, 0x52, 0x51, 0x45, 0x46, 0x74, 0x59,
+    0x6a, 0x67, 0x64, 0x56, 0x67, 0x62, 0x46, 0x41, 0x30, 0x64, 0x52, 0x49,
+    0x42, 0x6e, 0x38, 0x65, 0x78, 0x41, 0x4c, 0x0a, 0x44, 0x6d, 0x4b, 0x75,
+    0x64, 0x6c, 0x57, 0x2f, 0x58, 0x33, 0x65, 0x2b, 0x50, 0x6b, 0x6b, 0x42,
+    0x55, 0x7a, 0x32, 0x59, 0x4a, 0x51, 0x4e, 0x32, 0x4a, 0x46, 0x6f, 0x64,
+    0x74, 0x4e, 0x75, 0x4a, 0x36, 0x6e, 0x6e, 0x6c, 0x74, 0x72, 0x4d, 0x37,
+    0x50, 0x37, 0x70, 0x4d, 0x4b, 0x45, 0x46, 0x2f, 0x42, 0x71, 0x78, 0x71,
+    0x6a, 0x73, 0x48, 0x51, 0x39, 0x67, 0x55, 0x64, 0x66, 0x65, 0x5a, 0x43,
+    0x0a, 0x68, 0x75, 0x4f, 0x6c, 0x31, 0x55, 0x63, 0x43, 0x41, 0x77, 0x45,
+    0x41, 0x41, 0x61, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77, 0x44, 0x77, 0x59,
+    0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55,
+    0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e,
+    0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d,
+    0x43, 0x41, 0x51, 0x59, 0x77, 0x0a, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52,
+    0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4d, 0x52, 0x35, 0x79, 0x6f,
+    0x36, 0x68, 0x54, 0x67, 0x4d, 0x64, 0x48, 0x4e, 0x78, 0x72, 0x32, 0x7a,
+    0x46, 0x62, 0x6c, 0x44, 0x34, 0x2f, 0x4d, 0x48, 0x38, 0x74, 0x4d, 0x41,
+    0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51,
+    0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x0a, 0x41,
+    0x51, 0x41, 0x74, 0x78, 0x52, 0x50, 0x50, 0x56, 0x6f, 0x42, 0x37, 0x65,
+    0x6e, 0x69, 0x39, 0x6e, 0x36, 0x34, 0x73, 0x6d, 0x65, 0x66, 0x76, 0x32,
+    0x74, 0x2b, 0x55, 0x58, 0x67, 0x6c, 0x70, 0x70, 0x2b, 0x64, 0x75, 0x61,
+    0x49, 0x79, 0x39, 0x63, 0x72, 0x35, 0x48, 0x71, 0x51, 0x36, 0x58, 0x45,
+    0x72, 0x68, 0x4b, 0x38, 0x57, 0x54, 0x54, 0x4f, 0x64, 0x38, 0x6c, 0x4e,
+    0x4e, 0x54, 0x42, 0x0a, 0x7a, 0x55, 0x36, 0x42, 0x38, 0x41, 0x38, 0x45,
+    0x78, 0x43, 0x53, 0x7a, 0x4e, 0x4a, 0x62, 0x47, 0x70, 0x71, 0x6f, 0x77,
+    0x33, 0x32, 0x68, 0x68, 0x63, 0x39, 0x66, 0x35, 0x6a, 0x6f, 0x57, 0x4a,
+    0x37, 0x77, 0x35, 0x65, 0x6c, 0x53, 0x68, 0x4b, 0x4b, 0x69, 0x65, 0x50,
+    0x45, 0x49, 0x34, 0x75, 0x66, 0x49, 0x62, 0x45, 0x41, 0x70, 0x37, 0x61,
+    0x44, 0x48, 0x64, 0x6c, 0x44, 0x6b, 0x51, 0x4e, 0x0a, 0x6b, 0x76, 0x33,
+    0x39, 0x73, 0x78, 0x59, 0x32, 0x2b, 0x68, 0x45, 0x4e, 0x48, 0x59, 0x77,
+    0x4f, 0x42, 0x34, 0x6c, 0x71, 0x4b, 0x56, 0x62, 0x33, 0x63, 0x76, 0x54,
+    0x64, 0x46, 0x5a, 0x78, 0x33, 0x4e, 0x57, 0x5a, 0x58, 0x71, 0x78, 0x4e,
+    0x54, 0x32, 0x49, 0x37, 0x42, 0x51, 0x4d, 0x58, 0x58, 0x45, 0x78, 0x5a,
+    0x61, 0x63, 0x73, 0x65, 0x33, 0x61, 0x51, 0x48, 0x45, 0x65, 0x72, 0x47,
+    0x44, 0x0a, 0x41, 0x57, 0x68, 0x39, 0x6a, 0x55, 0x47, 0x68, 0x6c, 0x42,
+    0x6a, 0x42, 0x4a, 0x56, 0x7a, 0x38, 0x38, 0x50, 0x36, 0x44, 0x41, 0x6f,
+    0x64, 0x38, 0x44, 0x51, 0x33, 0x50, 0x4c, 0x67, 0x68, 0x63, 0x53, 0x6b,
+    0x41, 0x4e, 0x50, 0x75, 0x79, 0x42, 0x59, 0x65, 0x59, 0x6b, 0x32, 0x38,
+    0x72, 0x67, 0x44, 0x69, 0x30, 0x48, 0x73, 0x6a, 0x35, 0x57, 0x33, 0x49,
+    0x33, 0x31, 0x51, 0x59, 0x55, 0x48, 0x0a, 0x53, 0x4a, 0x73, 0x4d, 0x43,
+    0x38, 0x74, 0x4a, 0x50, 0x33, 0x33, 0x73, 0x74, 0x2f, 0x33, 0x4c, 0x6a,
+    0x57, 0x65, 0x4a, 0x47, 0x71, 0x76, 0x74, 0x75, 0x78, 0x36, 0x6a, 0x41,
+    0x41, 0x67, 0x49, 0x46, 0x79, 0x71, 0x43, 0x58, 0x44, 0x46, 0x64, 0x52,
+    0x6f, 0x6f, 0x74, 0x44, 0x34, 0x61, 0x62, 0x64, 0x4e, 0x6c, 0x46, 0x2b,
+    0x39, 0x52, 0x41, 0x73, 0x58, 0x71, 0x71, 0x61, 0x43, 0x32, 0x47, 0x0a,
+    0x73, 0x70, 0x6b, 0x69, 0x34, 0x63, 0x45, 0x72, 0x78, 0x35, 0x7a, 0x34,
+    0x38, 0x31, 0x2b, 0x6f, 0x67, 0x68, 0x4c, 0x72, 0x47, 0x52, 0x45, 0x74,
+    0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45,
+    0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72,
+    0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20,
+    0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+    0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x74,
+    0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20,
+    0x4f, 0x55, 0x3d, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x37, 0x20,
+    0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+    0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f,
+    0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e,
+    0x6c, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74,
+    0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20,
+    0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+    0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x74,
+    0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20,
+    0x4f, 0x55, 0x3d, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x37, 0x20,
+    0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+    0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f,
+    0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e,
+    0x6c, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20,
+    0x22, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x69, 0x6d,
+    0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20,
+    0x2d, 0x20, 0x47, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69,
+    0x61, 0x6c, 0x3a, 0x20, 0x37, 0x31, 0x37, 0x35, 0x38, 0x33, 0x32, 0x30,
+    0x36, 0x37, 0x32, 0x38, 0x32, 0x35, 0x34, 0x31, 0x30, 0x30, 0x32, 0x30,
+    0x36, 0x36, 0x31, 0x36, 0x32, 0x31, 0x30, 0x38, 0x35, 0x32, 0x35, 0x36,
+    0x34, 0x37, 0x32, 0x34, 0x30, 0x36, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x37, 0x34, 0x3a, 0x39, 0x64, 0x3a, 0x65, 0x61, 0x3a, 0x36,
+    0x30, 0x3a, 0x32, 0x34, 0x3a, 0x63, 0x34, 0x3a, 0x66, 0x64, 0x3a, 0x32,
+    0x32, 0x3a, 0x35, 0x33, 0x3a, 0x33, 0x65, 0x3a, 0x63, 0x63, 0x3a, 0x33,
+    0x61, 0x3a, 0x37, 0x32, 0x3a, 0x64, 0x39, 0x3a, 0x32, 0x39, 0x3a, 0x34,
+    0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x61,
+    0x3a, 0x64, 0x62, 0x3a, 0x62, 0x63, 0x3a, 0x32, 0x32, 0x3a, 0x32, 0x33,
+    0x3a, 0x38, 0x66, 0x3a, 0x63, 0x34, 0x3a, 0x30, 0x31, 0x3a, 0x61, 0x31,
+    0x3a, 0x32, 0x37, 0x3a, 0x62, 0x62, 0x3a, 0x33, 0x38, 0x3a, 0x64, 0x64,
+    0x3a, 0x66, 0x34, 0x3a, 0x31, 0x64, 0x3a, 0x64, 0x62, 0x3a, 0x30, 0x38,
+    0x3a, 0x39, 0x65, 0x3a, 0x66, 0x30, 0x3a, 0x31, 0x32, 0x0a, 0x23, 0x20,
+    0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x34, 0x3a, 0x33,
+    0x31, 0x3a, 0x30, 0x64, 0x3a, 0x35, 0x30, 0x3a, 0x61, 0x66, 0x3a, 0x31,
+    0x38, 0x3a, 0x61, 0x36, 0x3a, 0x34, 0x34, 0x3a, 0x37, 0x31, 0x3a, 0x39,
+    0x30, 0x3a, 0x33, 0x37, 0x3a, 0x32, 0x61, 0x3a, 0x38, 0x36, 0x3a, 0x61,
+    0x66, 0x3a, 0x61, 0x66, 0x3a, 0x38, 0x62, 0x3a, 0x39, 0x35, 0x3a, 0x31,
+    0x66, 0x3a, 0x66, 0x62, 0x3a, 0x34, 0x33, 0x3a, 0x31, 0x64, 0x3a, 0x38,
+    0x33, 0x3a, 0x37, 0x66, 0x3a, 0x31, 0x65, 0x3a, 0x35, 0x36, 0x3a, 0x38,
+    0x38, 0x3a, 0x62, 0x34, 0x3a, 0x35, 0x39, 0x3a, 0x37, 0x31, 0x3a, 0x65,
+    0x64, 0x3a, 0x31, 0x35, 0x3a, 0x35, 0x37, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49,
+    0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a,
+    0x4d, 0x49, 0x49, 0x43, 0x69, 0x44, 0x43, 0x43, 0x41, 0x67, 0x32, 0x67,
+    0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x4e, 0x66, 0x77, 0x6d,
+    0x58, 0x4e, 0x6d, 0x45, 0x54, 0x38, 0x6b, 0x39, 0x4a, 0x6a, 0x31, 0x58,
+    0x6d, 0x36, 0x37, 0x58, 0x56, 0x6a, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71,
+    0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x7a, 0x43, 0x42,
+    0x68, 0x44, 0x45, 0x4c, 0x0a, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x54, 0x41,
+    0x54, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x48, 0x52,
+    0x6f, 0x59, 0x58, 0x64, 0x30, 0x5a, 0x53, 0x77, 0x67, 0x53, 0x57, 0x35,
+    0x6a, 0x4c, 0x6a, 0x45, 0x34, 0x4d, 0x44, 0x59, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x43, 0x78, 0x4d, 0x76, 0x4b, 0x47, 0x4d, 0x70, 0x0a, 0x49, 0x44,
+    0x49, 0x77, 0x4d, 0x44, 0x63, 0x67, 0x64, 0x47, 0x68, 0x68, 0x64, 0x33,
+    0x52, 0x6c, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43,
+    0x30, 0x67, 0x52, 0x6d, 0x39, 0x79, 0x49, 0x47, 0x46, 0x31, 0x64, 0x47,
+    0x68, 0x76, 0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, 0x58,
+    0x4e, 0x6c, 0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x4a, 0x44,
+    0x41, 0x69, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x47,
+    0x33, 0x52, 0x6f, 0x59, 0x58, 0x64, 0x30, 0x5a, 0x53, 0x42, 0x51, 0x63,
+    0x6d, 0x6c, 0x74, 0x59, 0x58, 0x4a, 0x35, 0x49, 0x46, 0x4a, 0x76, 0x62,
+    0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4c, 0x53, 0x42, 0x48, 0x4d,
+    0x6a, 0x41, 0x65, 0x46, 0x77, 0x30, 0x77, 0x4e, 0x7a, 0x45, 0x78, 0x4d,
+    0x44, 0x55, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x0a, 0x4d, 0x44, 0x42, 0x61,
+    0x46, 0x77, 0x30, 0x7a, 0x4f, 0x44, 0x41, 0x78, 0x4d, 0x54, 0x67, 0x79,
+    0x4d, 0x7a, 0x55, 0x35, 0x4e, 0x54, 0x6c, 0x61, 0x4d, 0x49, 0x47, 0x45,
+    0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47,
+    0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x56, 0x4d, 0x42, 0x4d, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4d, 0x64, 0x47, 0x68, 0x68,
+    0x0a, 0x64, 0x33, 0x52, 0x6c, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d,
+    0x75, 0x4d, 0x54, 0x67, 0x77, 0x4e, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x4c, 0x45, 0x79, 0x38, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x6a, 0x41,
+    0x77, 0x4e, 0x79, 0x42, 0x30, 0x61, 0x47, 0x46, 0x33, 0x64, 0x47, 0x55,
+    0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x67, 0x4c, 0x53, 0x42,
+    0x47, 0x62, 0x33, 0x49, 0x67, 0x0a, 0x59, 0x58, 0x56, 0x30, 0x61, 0x47,
+    0x39, 0x79, 0x61, 0x58, 0x70, 0x6c, 0x5a, 0x43, 0x42, 0x31, 0x63, 0x32,
+    0x55, 0x67, 0x62, 0x32, 0x35, 0x73, 0x65, 0x54, 0x45, 0x6b, 0x4d, 0x43,
+    0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x62, 0x64, 0x47,
+    0x68, 0x68, 0x64, 0x33, 0x52, 0x6c, 0x49, 0x46, 0x42, 0x79, 0x61, 0x57,
+    0x31, 0x68, 0x63, 0x6e, 0x6b, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x0a, 0x64,
+    0x43, 0x42, 0x44, 0x51, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x79, 0x4d,
+    0x48, 0x59, 0x77, 0x45, 0x41, 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a,
+    0x6a, 0x30, 0x43, 0x41, 0x51, 0x59, 0x46, 0x4b, 0x34, 0x45, 0x45, 0x41,
+    0x43, 0x49, 0x44, 0x59, 0x67, 0x41, 0x45, 0x6f, 0x74, 0x57, 0x63, 0x67,
+    0x6e, 0x75, 0x56, 0x6e, 0x66, 0x46, 0x53, 0x65, 0x49, 0x66, 0x2b, 0x69,
+    0x68, 0x61, 0x2f, 0x0a, 0x42, 0x65, 0x62, 0x66, 0x6f, 0x77, 0x4a, 0x50,
+    0x44, 0x51, 0x66, 0x47, 0x41, 0x46, 0x47, 0x36, 0x44, 0x41, 0x4a, 0x53,
+    0x4c, 0x53, 0x4b, 0x6b, 0x51, 0x6a, 0x6e, 0x45, 0x2f, 0x6f, 0x2f, 0x71,
+    0x79, 0x63, 0x47, 0x2b, 0x31, 0x45, 0x33, 0x2f, 0x6e, 0x33, 0x71, 0x65,
+    0x34, 0x72, 0x46, 0x38, 0x6d, 0x71, 0x32, 0x6e, 0x68, 0x67, 0x6c, 0x7a,
+    0x68, 0x39, 0x48, 0x6e, 0x6d, 0x75, 0x4e, 0x36, 0x0a, 0x70, 0x61, 0x70,
+    0x75, 0x2b, 0x37, 0x71, 0x7a, 0x63, 0x4d, 0x42, 0x6e, 0x69, 0x4b, 0x49,
+    0x31, 0x31, 0x4b, 0x4f, 0x61, 0x73, 0x66, 0x32, 0x74, 0x77, 0x75, 0x38,
+    0x78, 0x2b, 0x71, 0x69, 0x35, 0x38, 0x2f, 0x73, 0x49, 0x78, 0x70, 0x48,
+    0x52, 0x2b, 0x79, 0x6d, 0x56, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41,
+    0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38,
+    0x45, 0x0a, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41,
+    0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77,
+    0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x64, 0x42, 0x67,
+    0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x6d, 0x74,
+    0x67, 0x41, 0x4d, 0x41, 0x44, 0x6e, 0x61, 0x33, 0x2b, 0x46, 0x47, 0x4f,
+    0x36, 0x4c, 0x74, 0x73, 0x36, 0x4b, 0x0a, 0x44, 0x50, 0x67, 0x52, 0x34,
+    0x62, 0x73, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a,
+    0x6a, 0x30, 0x45, 0x41, 0x77, 0x4d, 0x44, 0x61, 0x51, 0x41, 0x77, 0x5a,
+    0x67, 0x49, 0x78, 0x41, 0x4e, 0x33, 0x34, 0x34, 0x46, 0x64, 0x48, 0x57,
+    0x36, 0x66, 0x6d, 0x43, 0x73, 0x4f, 0x39, 0x39, 0x59, 0x43, 0x4b, 0x6c,
+    0x7a, 0x55, 0x4e, 0x47, 0x34, 0x6b, 0x38, 0x56, 0x49, 0x5a, 0x33, 0x0a,
+    0x4b, 0x4d, 0x71, 0x68, 0x39, 0x48, 0x6e, 0x65, 0x74, 0x65, 0x59, 0x34,
+    0x73, 0x50, 0x42, 0x6c, 0x63, 0x49, 0x78, 0x2f, 0x41, 0x6c, 0x54, 0x43,
+    0x76, 0x2f, 0x2f, 0x59, 0x6f, 0x54, 0x37, 0x5a, 0x7a, 0x77, 0x49, 0x78,
+    0x41, 0x4d, 0x53, 0x4e, 0x6c, 0x50, 0x7a, 0x63, 0x55, 0x39, 0x4c, 0x63,
+    0x6e, 0x58, 0x67, 0x57, 0x48, 0x78, 0x55, 0x7a, 0x49, 0x31, 0x4e, 0x53,
+    0x34, 0x31, 0x6f, 0x78, 0x0a, 0x58, 0x5a, 0x33, 0x4b, 0x72, 0x72, 0x30,
+    0x54, 0x4b, 0x55, 0x51, 0x4e, 0x4a, 0x31, 0x75, 0x6f, 0x35, 0x32, 0x69,
+    0x63, 0x45, 0x76, 0x64, 0x59, 0x50, 0x79, 0x35, 0x79, 0x41, 0x6c, 0x65,
+    0x6a, 0x6a, 0x36, 0x45, 0x55, 0x4c, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49,
+    0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a,
+    0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43,
+    0x4e, 0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x69,
+    0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
+    0x20, 0x2d, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x74, 0x68, 0x61, 0x77,
+    0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d,
+    0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+    0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44,
+    0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2f, 0x28, 0x63, 0x29, 0x20,
+    0x32, 0x30, 0x30, 0x38, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c,
+    0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20,
+    0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75,
+    0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75,
+    0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x74, 0x68,
+    0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79,
+    0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47,
+    0x33, 0x20, 0x4f, 0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20,
+    0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x65, 0x72, 0x74,
+    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65,
+    0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, 0x69, 0x76, 0x69, 0x73,
+    0x69, 0x6f, 0x6e, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x38,
+    0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63,
+    0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f,
+    0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a,
+    0x20, 0x22, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x69,
+    0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
+    0x20, 0x2d, 0x20, 0x47, 0x33, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72,
+    0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x36, 0x31, 0x34, 0x31,
+    0x35, 0x37, 0x30, 0x35, 0x36, 0x36, 0x38, 0x31, 0x32, 0x39, 0x39, 0x38,
+    0x30, 0x35, 0x35, 0x35, 0x36, 0x34, 0x37, 0x36, 0x32, 0x37, 0x35, 0x39,
+    0x39, 0x35, 0x34, 0x31, 0x34, 0x37, 0x37, 0x39, 0x0a, 0x23, 0x20, 0x4d,
+    0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x66, 0x62, 0x3a, 0x31, 0x62, 0x3a, 0x35, 0x64,
+    0x3a, 0x34, 0x33, 0x3a, 0x38, 0x61, 0x3a, 0x39, 0x34, 0x3a, 0x63, 0x64,
+    0x3a, 0x34, 0x34, 0x3a, 0x63, 0x36, 0x3a, 0x37, 0x36, 0x3a, 0x66, 0x32,
+    0x3a, 0x34, 0x33, 0x3a, 0x34, 0x62, 0x3a, 0x34, 0x37, 0x3a, 0x65, 0x37,
+    0x3a, 0x33, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x66, 0x31, 0x3a, 0x38, 0x62, 0x3a, 0x35, 0x33, 0x3a, 0x38, 0x64, 0x3a,
+    0x31, 0x62, 0x3a, 0x65, 0x39, 0x3a, 0x30, 0x33, 0x3a, 0x62, 0x36, 0x3a,
+    0x61, 0x36, 0x3a, 0x66, 0x30, 0x3a, 0x35, 0x36, 0x3a, 0x34, 0x33, 0x3a,
+    0x35, 0x62, 0x3a, 0x31, 0x37, 0x3a, 0x31, 0x35, 0x3a, 0x38, 0x39, 0x3a,
+    0x63, 0x61, 0x3a, 0x66, 0x33, 0x3a, 0x36, 0x62, 0x3a, 0x66, 0x32, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x62,
+    0x3a, 0x30, 0x33, 0x3a, 0x66, 0x34, 0x3a, 0x35, 0x38, 0x3a, 0x30, 0x37,
+    0x3a, 0x61, 0x64, 0x3a, 0x37, 0x30, 0x3a, 0x66, 0x32, 0x3a, 0x31, 0x62,
+    0x3a, 0x66, 0x63, 0x3a, 0x32, 0x63, 0x3a, 0x61, 0x65, 0x3a, 0x37, 0x31,
+    0x3a, 0x63, 0x39, 0x3a, 0x66, 0x64, 0x3a, 0x65, 0x34, 0x3a, 0x36, 0x30,
+    0x3a, 0x34, 0x63, 0x3a, 0x30, 0x36, 0x3a, 0x34, 0x63, 0x3a, 0x66, 0x35,
+    0x3a, 0x66, 0x66, 0x3a, 0x62, 0x36, 0x3a, 0x38, 0x36, 0x3a, 0x62, 0x61,
+    0x3a, 0x65, 0x35, 0x3a, 0x64, 0x62, 0x3a, 0x61, 0x61, 0x3a, 0x64, 0x37,
+    0x3a, 0x66, 0x64, 0x3a, 0x64, 0x33, 0x3a, 0x34, 0x63, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52,
+    0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x4b, 0x6a, 0x43, 0x43, 0x41, 0x78,
+    0x4b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x59, 0x41,
+    0x47, 0x58, 0x74, 0x30, 0x61, 0x6e, 0x36, 0x72, 0x53, 0x30, 0x6d, 0x74,
+    0x5a, 0x4c, 0x4c, 0x2f, 0x65, 0x51, 0x2b, 0x7a, 0x41, 0x4e, 0x42, 0x67,
+    0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51,
+    0x73, 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x72, 0x6a, 0x45, 0x4c, 0x4d,
+    0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56,
+    0x56, 0x4d, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x6f, 0x54, 0x44, 0x48, 0x52, 0x6f, 0x59, 0x58, 0x64, 0x30, 0x5a,
+    0x53, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x6f, 0x4d,
+    0x43, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x66, 0x0a,
+    0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68,
+    0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x54, 0x5a, 0x58, 0x4a, 0x32,
+    0x61, 0x57, 0x4e, 0x6c, 0x63, 0x79, 0x42, 0x45, 0x61, 0x58, 0x5a, 0x70,
+    0x63, 0x32, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x34, 0x4d, 0x44, 0x59, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x76, 0x4b, 0x47, 0x4d, 0x70,
+    0x49, 0x44, 0x49, 0x77, 0x0a, 0x4d, 0x44, 0x67, 0x67, 0x64, 0x47, 0x68,
+    0x68, 0x64, 0x33, 0x52, 0x6c, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d,
+    0x75, 0x49, 0x43, 0x30, 0x67, 0x52, 0x6d, 0x39, 0x79, 0x49, 0x47, 0x46,
+    0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51,
+    0x67, 0x64, 0x58, 0x4e, 0x6c, 0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b,
+    0x78, 0x4a, 0x44, 0x41, 0x69, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41,
+    0x4d, 0x54, 0x47, 0x33, 0x52, 0x6f, 0x59, 0x58, 0x64, 0x30, 0x5a, 0x53,
+    0x42, 0x51, 0x63, 0x6d, 0x6c, 0x74, 0x59, 0x58, 0x4a, 0x35, 0x49, 0x46,
+    0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4c, 0x53,
+    0x42, 0x48, 0x4d, 0x7a, 0x41, 0x65, 0x46, 0x77, 0x30, 0x77, 0x4f, 0x44,
+    0x41, 0x30, 0x4d, 0x44, 0x49, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44,
+    0x42, 0x61, 0x0a, 0x46, 0x77, 0x30, 0x7a, 0x4e, 0x7a, 0x45, 0x79, 0x4d,
+    0x44, 0x45, 0x79, 0x4d, 0x7a, 0x55, 0x35, 0x4e, 0x54, 0x6c, 0x61, 0x4d,
+    0x49, 0x47, 0x75, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x56, 0x4d,
+    0x42, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4d, 0x64,
+    0x47, 0x68, 0x68, 0x64, 0x33, 0x52, 0x6c, 0x0a, 0x4c, 0x43, 0x42, 0x4a,
+    0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x53, 0x67, 0x77, 0x4a, 0x67, 0x59, 0x44,
+    0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x39, 0x44, 0x5a, 0x58, 0x4a, 0x30,
+    0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75,
+    0x49, 0x46, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, 0x7a,
+    0x49, 0x45, 0x52, 0x70, 0x64, 0x6d, 0x6c, 0x7a, 0x61, 0x57, 0x39, 0x75,
+    0x0a, 0x4d, 0x54, 0x67, 0x77, 0x4e, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x4c, 0x45, 0x79, 0x38, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x6a, 0x41,
+    0x77, 0x4f, 0x43, 0x42, 0x30, 0x61, 0x47, 0x46, 0x33, 0x64, 0x47, 0x55,
+    0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x67, 0x4c, 0x53, 0x42,
+    0x47, 0x62, 0x33, 0x49, 0x67, 0x59, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39,
+    0x79, 0x61, 0x58, 0x70, 0x6c, 0x0a, 0x5a, 0x43, 0x42, 0x31, 0x63, 0x32,
+    0x55, 0x67, 0x62, 0x32, 0x35, 0x73, 0x65, 0x54, 0x45, 0x6b, 0x4d, 0x43,
+    0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x62, 0x64, 0x47,
+    0x68, 0x68, 0x64, 0x33, 0x52, 0x6c, 0x49, 0x46, 0x42, 0x79, 0x61, 0x57,
+    0x31, 0x68, 0x63, 0x6e, 0x6b, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43,
+    0x42, 0x44, 0x51, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x7a, 0x0a, 0x4d,
+    0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68,
+    0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41,
+    0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43,
+    0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x73, 0x72, 0x38, 0x6e, 0x4c,
+    0x50, 0x76, 0x62, 0x32, 0x46, 0x76, 0x64, 0x65, 0x48, 0x73, 0x62, 0x6e,
+    0x6e, 0x64, 0x6d, 0x0a, 0x67, 0x63, 0x73, 0x2b, 0x76, 0x48, 0x79, 0x75,
+    0x38, 0x36, 0x59, 0x6e, 0x6d, 0x6a, 0x53, 0x6a, 0x61, 0x44, 0x46, 0x78,
+    0x4f, 0x44, 0x4e, 0x69, 0x35, 0x50, 0x4e, 0x78, 0x5a, 0x6e, 0x6d, 0x78,
+    0x71, 0x57, 0x57, 0x6a, 0x70, 0x59, 0x76, 0x56, 0x6a, 0x32, 0x41, 0x74,
+    0x50, 0x30, 0x4c, 0x4d, 0x71, 0x6d, 0x73, 0x79, 0x77, 0x43, 0x50, 0x4c,
+    0x4c, 0x45, 0x48, 0x64, 0x35, 0x4e, 0x2f, 0x38, 0x0a, 0x59, 0x5a, 0x7a,
+    0x69, 0x63, 0x37, 0x49, 0x69, 0x6c, 0x52, 0x46, 0x44, 0x47, 0x46, 0x2f,
+    0x45, 0x74, 0x68, 0x39, 0x58, 0x62, 0x41, 0x6f, 0x46, 0x57, 0x43, 0x4c,
+    0x49, 0x4e, 0x6b, 0x77, 0x36, 0x66, 0x4b, 0x58, 0x52, 0x7a, 0x34, 0x61,
+    0x76, 0x69, 0x4b, 0x64, 0x45, 0x41, 0x68, 0x4e, 0x30, 0x63, 0x58, 0x4d,
+    0x4b, 0x51, 0x6c, 0x6b, 0x43, 0x2b, 0x42, 0x73, 0x55, 0x61, 0x30, 0x4c,
+    0x66, 0x0a, 0x62, 0x31, 0x2b, 0x36, 0x61, 0x34, 0x4b, 0x69, 0x6e, 0x56,
+    0x76, 0x6e, 0x53, 0x72, 0x30, 0x65, 0x41, 0x58, 0x4c, 0x62, 0x53, 0x33,
+    0x54, 0x6f, 0x4f, 0x33, 0x39, 0x2f, 0x66, 0x52, 0x38, 0x45, 0x74, 0x43,
+    0x61, 0x62, 0x34, 0x4c, 0x52, 0x61, 0x72, 0x45, 0x63, 0x39, 0x56, 0x62,
+    0x6a, 0x58, 0x73, 0x43, 0x5a, 0x53, 0x4b, 0x41, 0x45, 0x78, 0x51, 0x47,
+    0x62, 0x59, 0x32, 0x53, 0x53, 0x39, 0x0a, 0x39, 0x69, 0x72, 0x59, 0x37,
+    0x43, 0x46, 0x4a, 0x58, 0x4a, 0x76, 0x32, 0x65, 0x75, 0x6c, 0x2f, 0x56,
+    0x54, 0x56, 0x2b, 0x6c, 0x6d, 0x75, 0x4e, 0x6b, 0x35, 0x4d, 0x6e, 0x79,
+    0x35, 0x4b, 0x37, 0x36, 0x71, 0x78, 0x41, 0x77, 0x4a, 0x2f, 0x43, 0x2b,
+    0x49, 0x44, 0x50, 0x58, 0x66, 0x52, 0x61, 0x33, 0x4d, 0x35, 0x30, 0x68,
+    0x71, 0x59, 0x2b, 0x62, 0x41, 0x74, 0x54, 0x79, 0x72, 0x32, 0x53, 0x0a,
+    0x7a, 0x68, 0x6b, 0x47, 0x63, 0x75, 0x59, 0x4d, 0x58, 0x44, 0x68, 0x70,
+    0x78, 0x77, 0x54, 0x57, 0x76, 0x47, 0x7a, 0x4f, 0x57, 0x2f, 0x62, 0x33,
+    0x61, 0x4a, 0x7a, 0x63, 0x4a, 0x52, 0x56, 0x49, 0x69, 0x4b, 0x48, 0x70,
+    0x71, 0x66, 0x69, 0x59, 0x6e, 0x4f, 0x44, 0x7a, 0x31, 0x54, 0x45, 0x6f,
+    0x59, 0x52, 0x46, 0x73, 0x5a, 0x35, 0x61, 0x4e, 0x4f, 0x5a, 0x6e, 0x4c,
+    0x77, 0x6b, 0x55, 0x6b, 0x0a, 0x4f, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41,
+    0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x50, 0x42, 0x67, 0x4e,
+    0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41,
+    0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55,
+    0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49,
+    0x42, 0x42, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x51,
+    0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x72, 0x57, 0x79, 0x71, 0x6c, 0x47,
+    0x43, 0x63, 0x37, 0x65, 0x54, 0x2f, 0x2b, 0x6a, 0x34, 0x4b, 0x64, 0x43,
+    0x74, 0x6a, 0x41, 0x2f, 0x65, 0x32, 0x57, 0x62, 0x38, 0x77, 0x44, 0x51,
+    0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51,
+    0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x42,
+    0x70, 0x41, 0x0a, 0x32, 0x4a, 0x56, 0x6c, 0x72, 0x41, 0x6d, 0x53, 0x69,
+    0x63, 0x59, 0x35, 0x39, 0x42, 0x44, 0x6c, 0x71, 0x51, 0x35, 0x6d, 0x55,
+    0x31, 0x31, 0x34, 0x33, 0x76, 0x6f, 0x6b, 0x6b, 0x62, 0x76, 0x6e, 0x52,
+    0x46, 0x48, 0x66, 0x78, 0x68, 0x59, 0x30, 0x43, 0x75, 0x39, 0x71, 0x52,
+    0x46, 0x48, 0x71, 0x4b, 0x77, 0x65, 0x4b, 0x41, 0x33, 0x72, 0x44, 0x36,
+    0x7a, 0x38, 0x4b, 0x4c, 0x46, 0x49, 0x57, 0x0a, 0x6f, 0x43, 0x74, 0x44,
+    0x75, 0x53, 0x57, 0x51, 0x50, 0x33, 0x43, 0x70, 0x4d, 0x79, 0x56, 0x74,
+    0x52, 0x52, 0x6f, 0x6f, 0x4f, 0x79, 0x66, 0x50, 0x71, 0x73, 0x4d, 0x70,
+    0x51, 0x68, 0x76, 0x66, 0x4f, 0x30, 0x7a, 0x41, 0x4d, 0x7a, 0x52, 0x62,
+    0x51, 0x59, 0x69, 0x2f, 0x61, 0x79, 0x74, 0x6c, 0x72, 0x79, 0x6a, 0x76,
+    0x73, 0x76, 0x58, 0x44, 0x71, 0x6d, 0x62, 0x4f, 0x65, 0x31, 0x62, 0x75,
+    0x0a, 0x74, 0x38, 0x6a, 0x4c, 0x5a, 0x38, 0x48, 0x4a, 0x6e, 0x42, 0x6f,
+    0x59, 0x75, 0x4d, 0x54, 0x44, 0x53, 0x51, 0x50, 0x78, 0x59, 0x41, 0x35,
+    0x51, 0x7a, 0x55, 0x62, 0x46, 0x38, 0x33, 0x64, 0x35, 0x39, 0x37, 0x59,
+    0x56, 0x34, 0x44, 0x6a, 0x62, 0x78, 0x79, 0x38, 0x6f, 0x6f, 0x41, 0x77,
+    0x2f, 0x64, 0x79, 0x5a, 0x30, 0x32, 0x53, 0x55, 0x53, 0x32, 0x6a, 0x48,
+    0x61, 0x47, 0x68, 0x37, 0x63, 0x0a, 0x4b, 0x55, 0x47, 0x52, 0x49, 0x6a,
+    0x78, 0x70, 0x70, 0x37, 0x73, 0x43, 0x38, 0x72, 0x5a, 0x63, 0x4a, 0x77,
+    0x4f, 0x4a, 0x39, 0x41, 0x62, 0x71, 0x6d, 0x2b, 0x52, 0x79, 0x67, 0x75,
+    0x4f, 0x68, 0x43, 0x63, 0x48, 0x70, 0x41, 0x42, 0x6e, 0x54, 0x50, 0x74,
+    0x52, 0x77, 0x61, 0x37, 0x70, 0x78, 0x70, 0x71, 0x70, 0x59, 0x72, 0x76,
+    0x53, 0x37, 0x36, 0x57, 0x79, 0x32, 0x37, 0x34, 0x66, 0x4d, 0x0a, 0x6d,
+    0x37, 0x76, 0x2f, 0x4f, 0x65, 0x5a, 0x57, 0x59, 0x64, 0x4d, 0x4b, 0x70,
+    0x38, 0x52, 0x63, 0x54, 0x47, 0x42, 0x37, 0x42, 0x58, 0x63, 0x6d, 0x65,
+    0x72, 0x2f, 0x59, 0x42, 0x31, 0x49, 0x73, 0x59, 0x76, 0x64, 0x77, 0x59,
+    0x39, 0x6b, 0x35, 0x76, 0x47, 0x38, 0x63, 0x77, 0x6e, 0x6e, 0x63, 0x64,
+    0x69, 0x6d, 0x76, 0x7a, 0x73, 0x55, 0x73, 0x5a, 0x41, 0x52, 0x65, 0x69,
+    0x44, 0x5a, 0x75, 0x0a, 0x4d, 0x64, 0x52, 0x41, 0x47, 0x6d, 0x49, 0x30,
+    0x4e, 0x6a, 0x38, 0x31, 0x41, 0x61, 0x36, 0x73, 0x59, 0x36, 0x41, 0x3d,
+    0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45,
+    0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72,
+    0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73,
+    0x74, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65,
+    0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+    0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20,
+    0x47, 0x32, 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73,
+    0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x28, 0x63,
+    0x29, 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x47, 0x65, 0x6f, 0x54, 0x72,
+    0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46,
+    0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65,
+    0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23,
+    0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72,
+    0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+    0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f,
+    0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e,
+    0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30,
+    0x30, 0x37, 0x20, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20,
+    0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61,
+    0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73,
+    0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62,
+    0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73,
+    0x74, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65,
+    0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+    0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20,
+    0x47, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c,
+    0x3a, 0x20, 0x38, 0x30, 0x36, 0x38, 0x32, 0x38, 0x36, 0x33, 0x32, 0x30,
+    0x33, 0x33, 0x38, 0x31, 0x30, 0x36, 0x35, 0x37, 0x38, 0x32, 0x31, 0x37,
+    0x37, 0x39, 0x30, 0x38, 0x37, 0x35, 0x31, 0x37, 0x39, 0x34, 0x36, 0x31,
+    0x39, 0x32, 0x34, 0x33, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x30, 0x31, 0x3a, 0x35, 0x65, 0x3a, 0x64, 0x38, 0x3a, 0x36, 0x62, 0x3a,
+    0x62, 0x64, 0x3a, 0x36, 0x66, 0x3a, 0x33, 0x64, 0x3a, 0x38, 0x65, 0x3a,
+    0x61, 0x31, 0x3a, 0x33, 0x31, 0x3a, 0x66, 0x38, 0x3a, 0x31, 0x32, 0x3a,
+    0x65, 0x30, 0x3a, 0x39, 0x38, 0x3a, 0x37, 0x33, 0x3a, 0x36, 0x61, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x64, 0x3a, 0x31,
+    0x37, 0x3a, 0x38, 0x34, 0x3a, 0x64, 0x35, 0x3a, 0x33, 0x37, 0x3a, 0x66,
+    0x33, 0x3a, 0x30, 0x33, 0x3a, 0x37, 0x64, 0x3a, 0x65, 0x63, 0x3a, 0x37,
+    0x30, 0x3a, 0x66, 0x65, 0x3a, 0x35, 0x37, 0x3a, 0x38, 0x62, 0x3a, 0x35,
+    0x31, 0x3a, 0x39, 0x61, 0x3a, 0x39, 0x39, 0x3a, 0x65, 0x36, 0x3a, 0x31,
+    0x30, 0x3a, 0x64, 0x37, 0x3a, 0x62, 0x30, 0x0a, 0x23, 0x20, 0x53, 0x48,
+    0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x65, 0x3a, 0x64, 0x62, 0x3a,
+    0x37, 0x61, 0x3a, 0x63, 0x34, 0x3a, 0x33, 0x62, 0x3a, 0x38, 0x32, 0x3a,
+    0x61, 0x30, 0x3a, 0x36, 0x61, 0x3a, 0x38, 0x37, 0x3a, 0x36, 0x31, 0x3a,
+    0x65, 0x38, 0x3a, 0x64, 0x37, 0x3a, 0x62, 0x65, 0x3a, 0x34, 0x39, 0x3a,
+    0x37, 0x39, 0x3a, 0x65, 0x62, 0x3a, 0x66, 0x32, 0x3a, 0x36, 0x31, 0x3a,
+    0x31, 0x66, 0x3a, 0x37, 0x64, 0x3a, 0x64, 0x37, 0x3a, 0x39, 0x62, 0x3a,
+    0x66, 0x39, 0x3a, 0x31, 0x63, 0x3a, 0x31, 0x63, 0x3a, 0x36, 0x62, 0x3a,
+    0x35, 0x36, 0x3a, 0x36, 0x61, 0x3a, 0x32, 0x31, 0x3a, 0x39, 0x65, 0x3a,
+    0x64, 0x37, 0x3a, 0x36, 0x36, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42,
+    0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49,
+    0x49, 0x43, 0x72, 0x6a, 0x43, 0x43, 0x41, 0x6a, 0x57, 0x67, 0x41, 0x77,
+    0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x50, 0x4c, 0x4c, 0x30, 0x53, 0x41,
+    0x6f, 0x41, 0x34, 0x76, 0x37, 0x72, 0x4a, 0x44, 0x74, 0x65, 0x59, 0x44,
+    0x37, 0x44, 0x61, 0x7a, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b,
+    0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x7a, 0x43, 0x42, 0x6d, 0x44,
+    0x45, 0x4c, 0x0a, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42,
+    0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x6a, 0x41, 0x55, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x55, 0x64, 0x6c, 0x62,
+    0x31, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x6c, 0x75, 0x59,
+    0x79, 0x34, 0x78, 0x4f, 0x54, 0x41, 0x33, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x73, 0x54, 0x4d, 0x43, 0x68, 0x6a, 0x0a, 0x4b, 0x53, 0x41, 0x79,
+    0x4d, 0x44, 0x41, 0x33, 0x49, 0x45, 0x64, 0x6c, 0x62, 0x31, 0x52, 0x79,
+    0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x67,
+    0x4c, 0x53, 0x42, 0x47, 0x62, 0x33, 0x49, 0x67, 0x59, 0x58, 0x56, 0x30,
+    0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x70, 0x6c, 0x5a, 0x43, 0x42, 0x31,
+    0x63, 0x32, 0x55, 0x67, 0x62, 0x32, 0x35, 0x73, 0x65, 0x54, 0x45, 0x32,
+    0x0a, 0x4d, 0x44, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d,
+    0x74, 0x52, 0x32, 0x56, 0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51,
+    0x67, 0x55, 0x48, 0x4a, 0x70, 0x62, 0x57, 0x46, 0x79, 0x65, 0x53, 0x42,
+    0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46,
+    0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68,
+    0x76, 0x63, 0x6d, 0x6c, 0x30, 0x0a, 0x65, 0x53, 0x41, 0x74, 0x49, 0x45,
+    0x63, 0x79, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x33, 0x4d, 0x54,
+    0x45, 0x77, 0x4e, 0x54, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46,
+    0x6f, 0x58, 0x44, 0x54, 0x4d, 0x34, 0x4d, 0x44, 0x45, 0x78, 0x4f, 0x44,
+    0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x67, 0x5a,
+    0x67, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42,
+    0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x52, 0x59, 0x77, 0x46,
+    0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x31, 0x48, 0x5a,
+    0x57, 0x39, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4a, 0x62,
+    0x6d, 0x4d, 0x75, 0x4d, 0x54, 0x6b, 0x77, 0x4e, 0x77, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x4c, 0x45, 0x7a, 0x41, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d,
+    0x6a, 0x41, 0x77, 0x0a, 0x4e, 0x79, 0x42, 0x48, 0x5a, 0x57, 0x39, 0x55,
+    0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75,
+    0x49, 0x43, 0x30, 0x67, 0x52, 0x6d, 0x39, 0x79, 0x49, 0x47, 0x46, 0x31,
+    0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67,
+    0x64, 0x58, 0x4e, 0x6c, 0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78,
+    0x4e, 0x6a, 0x41, 0x30, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x4d,
+    0x54, 0x4c, 0x55, 0x64, 0x6c, 0x62, 0x31, 0x52, 0x79, 0x64, 0x58, 0x4e,
+    0x30, 0x49, 0x46, 0x42, 0x79, 0x61, 0x57, 0x31, 0x68, 0x63, 0x6e, 0x6b,
+    0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e,
+    0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52,
+    0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x4c, 0x53, 0x42,
+    0x48, 0x0a, 0x4d, 0x6a, 0x42, 0x32, 0x4d, 0x42, 0x41, 0x47, 0x42, 0x79,
+    0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x42, 0x53,
+    0x75, 0x42, 0x42, 0x41, 0x41, 0x69, 0x41, 0x32, 0x49, 0x41, 0x42, 0x42,
+    0x57, 0x78, 0x36, 0x50, 0x30, 0x44, 0x46, 0x55, 0x50, 0x6c, 0x72, 0x4f,
+    0x75, 0x48, 0x4e, 0x78, 0x46, 0x69, 0x37, 0x39, 0x4b, 0x44, 0x4e, 0x6c,
+    0x4a, 0x39, 0x52, 0x56, 0x63, 0x4c, 0x0a, 0x53, 0x6f, 0x31, 0x37, 0x56,
+    0x44, 0x73, 0x36, 0x62, 0x6c, 0x38, 0x56, 0x41, 0x73, 0x42, 0x51, 0x70,
+    0x73, 0x38, 0x6c, 0x4c, 0x33, 0x33, 0x4b, 0x53, 0x4c, 0x6a, 0x48, 0x55,
+    0x47, 0x4d, 0x63, 0x4b, 0x69, 0x45, 0x49, 0x66, 0x4a, 0x6f, 0x32, 0x32,
+    0x41, 0x76, 0x2b, 0x30, 0x53, 0x62, 0x46, 0x57, 0x44, 0x45, 0x77, 0x4b,
+    0x43, 0x58, 0x7a, 0x58, 0x56, 0x32, 0x6a, 0x75, 0x4c, 0x61, 0x6c, 0x0a,
+    0x74, 0x4a, 0x4c, 0x74, 0x62, 0x43, 0x79, 0x66, 0x36, 0x39, 0x31, 0x44,
+    0x69, 0x61, 0x49, 0x38, 0x53, 0x30, 0x69, 0x52, 0x48, 0x56, 0x44, 0x73,
+    0x4a, 0x74, 0x2f, 0x57, 0x59, 0x43, 0x36, 0x39, 0x49, 0x61, 0x4e, 0x43,
+    0x4d, 0x45, 0x41, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54,
+    0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42,
+    0x2f, 0x7a, 0x41, 0x4f, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38,
+    0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59,
+    0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59,
+    0x45, 0x46, 0x42, 0x56, 0x66, 0x4e, 0x56, 0x64, 0x52, 0x56, 0x66, 0x73,
+    0x6c, 0x73, 0x71, 0x30, 0x44, 0x61, 0x66, 0x77, 0x42, 0x6f, 0x2f, 0x71,
+    0x2b, 0x45, 0x56, 0x58, 0x56, 0x4d, 0x41, 0x6f, 0x47, 0x0a, 0x43, 0x43,
+    0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x44, 0x41, 0x32,
+    0x63, 0x41, 0x4d, 0x47, 0x51, 0x43, 0x4d, 0x47, 0x53, 0x57, 0x57, 0x61,
+    0x62, 0x6f, 0x43, 0x64, 0x36, 0x4c, 0x75, 0x76, 0x70, 0x61, 0x69, 0x49,
+    0x6a, 0x77, 0x48, 0x35, 0x48, 0x54, 0x52, 0x71, 0x6a, 0x79, 0x53, 0x6b,
+    0x77, 0x43, 0x59, 0x2f, 0x74, 0x73, 0x58, 0x7a, 0x6a, 0x62, 0x4c, 0x6b,
+    0x47, 0x54, 0x0a, 0x71, 0x51, 0x37, 0x6d, 0x6e, 0x64, 0x77, 0x78, 0x48,
+    0x4c, 0x4b, 0x67, 0x70, 0x78, 0x67, 0x63, 0x65, 0x65, 0x48, 0x48, 0x4e,
+    0x67, 0x49, 0x77, 0x4f, 0x6c, 0x61, 0x76, 0x6d, 0x6e, 0x52, 0x73, 0x39,
+    0x76, 0x75, 0x44, 0x34, 0x44, 0x50, 0x54, 0x43, 0x46, 0x2b, 0x68, 0x6e,
+    0x4d, 0x4a, 0x62, 0x6e, 0x30, 0x62, 0x57, 0x74, 0x73, 0x75, 0x52, 0x42,
+    0x6d, 0x4f, 0x69, 0x42, 0x75, 0x63, 0x7a, 0x0a, 0x72, 0x44, 0x36, 0x6f,
+    0x67, 0x52, 0x4c, 0x51, 0x79, 0x37, 0x72, 0x51, 0x6b, 0x67, 0x75, 0x32,
+    0x6e, 0x70, 0x61, 0x71, 0x42, 0x41, 0x2b, 0x4b, 0x0a, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a,
+    0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x55, 0x6e,
+    0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+    0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+    0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+    0x20, 0x4f, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c,
+    0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x65, 0x72,
+    0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20,
+    0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x28, 0x63, 0x29, 0x20,
+    0x32, 0x30, 0x30, 0x38, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+    0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f,
+    0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64,
+    0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20,
+    0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d,
+    0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x55, 0x6e, 0x69,
+    0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+    0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+    0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20,
+    0x4f, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20,
+    0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x65, 0x72, 0x69,
+    0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e,
+    0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32,
+    0x30, 0x30, 0x38, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e,
+    0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72,
+    0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20,
+    0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x4c,
+    0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x56, 0x65, 0x72, 0x69, 0x53,
+    0x69, 0x67, 0x6e, 0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61,
+    0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+    0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74,
+    0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65,
+    0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x38, 0x35, 0x32, 0x30, 0x39, 0x35,
+    0x37, 0x34, 0x37, 0x33, 0x34, 0x30, 0x38, 0x34, 0x35, 0x38, 0x31, 0x39,
+    0x31, 0x37, 0x37, 0x36, 0x33, 0x37, 0x35, 0x32, 0x36, 0x34, 0x34, 0x30,
+    0x33, 0x31, 0x37, 0x32, 0x36, 0x38, 0x37, 0x37, 0x0a, 0x23, 0x20, 0x4d,
+    0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x38, 0x65, 0x3a, 0x61, 0x64, 0x3a, 0x62, 0x35,
+    0x3a, 0x30, 0x31, 0x3a, 0x61, 0x61, 0x3a, 0x34, 0x64, 0x3a, 0x38, 0x31,
+    0x3a, 0x65, 0x34, 0x3a, 0x38, 0x63, 0x3a, 0x31, 0x64, 0x3a, 0x64, 0x31,
+    0x3a, 0x65, 0x31, 0x3a, 0x31, 0x34, 0x3a, 0x30, 0x30, 0x3a, 0x39, 0x35,
+    0x3a, 0x31, 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x33, 0x36, 0x3a, 0x37, 0x39, 0x3a, 0x63, 0x61, 0x3a, 0x33, 0x35, 0x3a,
+    0x36, 0x36, 0x3a, 0x38, 0x37, 0x3a, 0x37, 0x32, 0x3a, 0x33, 0x30, 0x3a,
+    0x34, 0x64, 0x3a, 0x33, 0x30, 0x3a, 0x61, 0x35, 0x3a, 0x66, 0x62, 0x3a,
+    0x38, 0x37, 0x3a, 0x33, 0x62, 0x3a, 0x30, 0x66, 0x3a, 0x61, 0x37, 0x3a,
+    0x37, 0x62, 0x3a, 0x62, 0x37, 0x3a, 0x30, 0x64, 0x3a, 0x35, 0x34, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x33,
+    0x3a, 0x39, 0x39, 0x3a, 0x35, 0x36, 0x3a, 0x31, 0x31, 0x3a, 0x32, 0x37,
+    0x3a, 0x61, 0x35, 0x3a, 0x37, 0x31, 0x3a, 0x32, 0x35, 0x3a, 0x64, 0x65,
+    0x3a, 0x38, 0x63, 0x3a, 0x65, 0x66, 0x3a, 0x65, 0x61, 0x3a, 0x36, 0x31,
+    0x3a, 0x30, 0x64, 0x3a, 0x64, 0x66, 0x3a, 0x32, 0x66, 0x3a, 0x61, 0x30,
+    0x3a, 0x37, 0x38, 0x3a, 0x62, 0x35, 0x3a, 0x63, 0x38, 0x3a, 0x30, 0x36,
+    0x3a, 0x37, 0x66, 0x3a, 0x34, 0x65, 0x3a, 0x38, 0x32, 0x3a, 0x38, 0x32,
+    0x3a, 0x39, 0x30, 0x3a, 0x62, 0x66, 0x3a, 0x62, 0x38, 0x3a, 0x36, 0x30,
+    0x3a, 0x65, 0x38, 0x3a, 0x34, 0x62, 0x3a, 0x33, 0x63, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52,
+    0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x75, 0x54, 0x43, 0x43, 0x41, 0x36,
+    0x47, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x51, 0x42,
+    0x72, 0x45, 0x5a, 0x43, 0x47, 0x7a, 0x45, 0x79, 0x45, 0x44, 0x44, 0x72,
+    0x76, 0x6b, 0x45, 0x68, 0x72, 0x46, 0x48, 0x54, 0x41, 0x4e, 0x42, 0x67,
+    0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51,
+    0x73, 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x76, 0x54, 0x45, 0x4c, 0x4d,
+    0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56,
+    0x56, 0x4d, 0x78, 0x46, 0x7a, 0x41, 0x56, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x6f, 0x54, 0x44, 0x6c, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61,
+    0x57, 0x64, 0x75, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d,
+    0x52, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x0a,
+    0x45, 0x78, 0x5a, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e,
+    0x62, 0x69, 0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4f,
+    0x5a, 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x4d, 0x54, 0x6f, 0x77,
+    0x4f, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x7a, 0x45, 0x6f,
+    0x59, 0x79, 0x6b, 0x67, 0x4d, 0x6a, 0x41, 0x77, 0x4f, 0x43, 0x42, 0x57,
+    0x5a, 0x58, 0x4a, 0x70, 0x0a, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x77,
+    0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x69, 0x41, 0x74, 0x49, 0x45, 0x5a,
+    0x76, 0x63, 0x69, 0x42, 0x68, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a,
+    0x70, 0x65, 0x6d, 0x56, 0x6b, 0x49, 0x48, 0x56, 0x7a, 0x5a, 0x53, 0x42,
+    0x76, 0x62, 0x6d, 0x78, 0x35, 0x4d, 0x54, 0x67, 0x77, 0x4e, 0x67, 0x59,
+    0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x79, 0x39, 0x57, 0x0a, 0x5a, 0x58,
+    0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x56, 0x62, 0x6d,
+    0x6c, 0x32, 0x5a, 0x58, 0x4a, 0x7a, 0x59, 0x57, 0x77, 0x67, 0x55, 0x6d,
+    0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57,
+    0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45,
+    0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54,
+    0x41, 0x65, 0x0a, 0x46, 0x77, 0x30, 0x77, 0x4f, 0x44, 0x41, 0x30, 0x4d,
+    0x44, 0x49, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x42, 0x61, 0x46,
+    0x77, 0x30, 0x7a, 0x4e, 0x7a, 0x45, 0x79, 0x4d, 0x44, 0x45, 0x79, 0x4d,
+    0x7a, 0x55, 0x35, 0x4e, 0x54, 0x6c, 0x61, 0x4d, 0x49, 0x47, 0x39, 0x4d,
+    0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45,
+    0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x58, 0x0a, 0x4d, 0x42, 0x55, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4f, 0x56, 0x6d, 0x56, 0x79,
+    0x61, 0x56, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x73, 0x49, 0x45, 0x6c, 0x75,
+    0x59, 0x79, 0x34, 0x78, 0x48, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x73, 0x54, 0x46, 0x6c, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54,
+    0x61, 0x57, 0x64, 0x75, 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30,
+    0x0a, 0x49, 0x45, 0x35, 0x6c, 0x64, 0x48, 0x64, 0x76, 0x63, 0x6d, 0x73,
+    0x78, 0x4f, 0x6a, 0x41, 0x34, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73,
+    0x54, 0x4d, 0x53, 0x68, 0x6a, 0x4b, 0x53, 0x41, 0x79, 0x4d, 0x44, 0x41,
+    0x34, 0x49, 0x46, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64,
+    0x75, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30,
+    0x67, 0x52, 0x6d, 0x39, 0x79, 0x0a, 0x49, 0x47, 0x46, 0x31, 0x64, 0x47,
+    0x68, 0x76, 0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, 0x58,
+    0x4e, 0x6c, 0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x4f, 0x44,
+    0x41, 0x32, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x4c, 0x31,
+    0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x49, 0x46,
+    0x56, 0x75, 0x61, 0x58, 0x5a, 0x6c, 0x63, 0x6e, 0x4e, 0x68, 0x0a, 0x62,
+    0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x6c, 0x63,
+    0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62,
+    0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61,
+    0x58, 0x52, 0x35, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42,
+    0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41,
+    0x51, 0x45, 0x46, 0x0a, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41,
+    0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41,
+    0x78, 0x32, 0x45, 0x33, 0x58, 0x72, 0x45, 0x42, 0x4e, 0x4e, 0x74, 0x69,
+    0x31, 0x78, 0x57, 0x62, 0x2f, 0x31, 0x68, 0x61, 0x6a, 0x43, 0x4d, 0x6a,
+    0x31, 0x6d, 0x43, 0x4f, 0x6b, 0x64, 0x65, 0x51, 0x6d, 0x49, 0x4e, 0x36,
+    0x35, 0x6c, 0x67, 0x5a, 0x4f, 0x49, 0x7a, 0x46, 0x0a, 0x39, 0x75, 0x56,
+    0x6b, 0x68, 0x62, 0x53, 0x69, 0x63, 0x66, 0x76, 0x74, 0x76, 0x62, 0x6e,
+    0x61, 0x7a, 0x55, 0x30, 0x41, 0x74, 0x4d, 0x67, 0x74, 0x63, 0x36, 0x58,
+    0x48, 0x61, 0x58, 0x47, 0x56, 0x48, 0x7a, 0x6b, 0x38, 0x73, 0x6b, 0x51,
+    0x48, 0x6e, 0x4f, 0x67, 0x4f, 0x2b, 0x6b, 0x31, 0x4b, 0x78, 0x43, 0x48,
+    0x66, 0x4b, 0x57, 0x47, 0x50, 0x4d, 0x69, 0x4a, 0x68, 0x67, 0x73, 0x57,
+    0x48, 0x0a, 0x48, 0x32, 0x36, 0x4d, 0x66, 0x46, 0x38, 0x57, 0x49, 0x46,
+    0x46, 0x45, 0x30, 0x58, 0x42, 0x50, 0x56, 0x2b, 0x72, 0x6a, 0x48, 0x4f,
+    0x50, 0x4d, 0x65, 0x65, 0x35, 0x59, 0x32, 0x41, 0x37, 0x43, 0x73, 0x30,
+    0x57, 0x54, 0x77, 0x43, 0x7a, 0x6e, 0x6d, 0x68, 0x63, 0x72, 0x65, 0x77,
+    0x41, 0x33, 0x65, 0x6b, 0x45, 0x7a, 0x65, 0x4f, 0x45, 0x7a, 0x34, 0x76,
+    0x4d, 0x51, 0x47, 0x6e, 0x2b, 0x48, 0x0a, 0x4c, 0x4c, 0x37, 0x32, 0x39,
+    0x66, 0x64, 0x43, 0x34, 0x75, 0x57, 0x2f, 0x68, 0x32, 0x4b, 0x4a, 0x58,
+    0x77, 0x42, 0x4c, 0x33, 0x38, 0x58, 0x64, 0x35, 0x48, 0x56, 0x45, 0x4d,
+    0x6b, 0x45, 0x36, 0x48, 0x6e, 0x46, 0x75, 0x61, 0x63, 0x73, 0x4c, 0x64,
+    0x55, 0x59, 0x49, 0x30, 0x63, 0x72, 0x53, 0x4b, 0x35, 0x58, 0x51, 0x7a,
+    0x2f, 0x75, 0x35, 0x51, 0x47, 0x74, 0x6b, 0x6a, 0x46, 0x64, 0x4e, 0x0a,
+    0x2f, 0x42, 0x4d, 0x52, 0x65, 0x59, 0x54, 0x74, 0x58, 0x6c, 0x54, 0x32,
+    0x4e, 0x4a, 0x38, 0x49, 0x41, 0x66, 0x4d, 0x51, 0x4a, 0x51, 0x59, 0x58,
+    0x53, 0x74, 0x72, 0x78, 0x48, 0x58, 0x70, 0x6d, 0x61, 0x35, 0x68, 0x67,
+    0x5a, 0x71, 0x54, 0x5a, 0x37, 0x39, 0x49, 0x75, 0x67, 0x76, 0x48, 0x77,
+    0x37, 0x77, 0x6e, 0x71, 0x52, 0x4d, 0x6b, 0x56, 0x61, 0x75, 0x49, 0x44,
+    0x62, 0x6a, 0x50, 0x54, 0x0a, 0x72, 0x4a, 0x39, 0x56, 0x41, 0x4d, 0x66,
+    0x32, 0x43, 0x47, 0x71, 0x55, 0x75, 0x56, 0x2f, 0x63, 0x34, 0x44, 0x50,
+    0x78, 0x68, 0x47, 0x44, 0x35, 0x57, 0x79, 0x63, 0x52, 0x74, 0x50, 0x77,
+    0x57, 0x38, 0x72, 0x74, 0x57, 0x61, 0x6f, 0x41, 0x6c, 0x6a, 0x51, 0x49,
+    0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x34, 0x47, 0x79, 0x4d, 0x49, 0x47,
+    0x76, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x0a, 0x45, 0x77,
+    0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66,
+    0x38, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51,
+    0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x47,
+    0x30, 0x47, 0x43, 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x77,
+    0x45, 0x4d, 0x42, 0x47, 0x45, 0x77, 0x58, 0x36, 0x46, 0x64, 0x6f, 0x46,
+    0x73, 0x77, 0x0a, 0x57, 0x54, 0x42, 0x58, 0x4d, 0x46, 0x55, 0x57, 0x43,
+    0x57, 0x6c, 0x74, 0x59, 0x57, 0x64, 0x6c, 0x4c, 0x32, 0x64, 0x70, 0x5a,
+    0x6a, 0x41, 0x68, 0x4d, 0x42, 0x38, 0x77, 0x42, 0x77, 0x59, 0x46, 0x4b,
+    0x77, 0x34, 0x44, 0x41, 0x68, 0x6f, 0x45, 0x46, 0x49, 0x2f, 0x6c, 0x30,
+    0x78, 0x71, 0x47, 0x72, 0x49, 0x32, 0x4f, 0x61, 0x38, 0x50, 0x50, 0x67,
+    0x47, 0x72, 0x55, 0x53, 0x42, 0x67, 0x73, 0x0a, 0x65, 0x78, 0x6b, 0x75,
+    0x4d, 0x43, 0x55, 0x57, 0x49, 0x32, 0x68, 0x30, 0x64, 0x48, 0x41, 0x36,
+    0x4c, 0x79, 0x39, 0x73, 0x62, 0x32, 0x64, 0x76, 0x4c, 0x6e, 0x5a, 0x6c,
+    0x63, 0x6d, 0x6c, 0x7a, 0x61, 0x57, 0x64, 0x75, 0x4c, 0x6d, 0x4e, 0x76,
+    0x62, 0x53, 0x39, 0x32, 0x63, 0x32, 0x78, 0x76, 0x5a, 0x32, 0x38, 0x75,
+    0x5a, 0x32, 0x6c, 0x6d, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64,
+    0x0a, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x53, 0x32, 0x64, 0x2f, 0x70,
+    0x70, 0x53, 0x45, 0x65, 0x66, 0x55, 0x78, 0x4c, 0x56, 0x77, 0x75, 0x6f,
+    0x48, 0x4d, 0x6e, 0x59, 0x48, 0x30, 0x5a, 0x63, 0x48, 0x47, 0x54, 0x41,
+    0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30,
+    0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45,
+    0x41, 0x53, 0x76, 0x6a, 0x34, 0x0a, 0x73, 0x41, 0x50, 0x6d, 0x4c, 0x47,
+    0x64, 0x37, 0x35, 0x4a, 0x52, 0x33, 0x59, 0x38, 0x78, 0x75, 0x54, 0x50,
+    0x6c, 0x39, 0x44, 0x67, 0x33, 0x63, 0x79, 0x4c, 0x6b, 0x31, 0x75, 0x58,
+    0x42, 0x50, 0x59, 0x2f, 0x6f, 0x6b, 0x2b, 0x6d, 0x79, 0x44, 0x6a, 0x45,
+    0x65, 0x64, 0x4f, 0x32, 0x50, 0x7a, 0x6d, 0x76, 0x6c, 0x32, 0x4d, 0x70,
+    0x57, 0x52, 0x73, 0x58, 0x65, 0x38, 0x72, 0x4a, 0x71, 0x2b, 0x0a, 0x73,
+    0x65, 0x51, 0x78, 0x49, 0x63, 0x61, 0x42, 0x6c, 0x56, 0x5a, 0x61, 0x44,
+    0x72, 0x48, 0x43, 0x31, 0x4c, 0x47, 0x6d, 0x57, 0x61, 0x7a, 0x78, 0x59,
+    0x38, 0x75, 0x34, 0x54, 0x42, 0x31, 0x5a, 0x6b, 0x45, 0x72, 0x76, 0x6b,
+    0x42, 0x59, 0x6f, 0x48, 0x31, 0x71, 0x75, 0x45, 0x50, 0x75, 0x42, 0x55,
+    0x44, 0x67, 0x4d, 0x62, 0x4d, 0x7a, 0x78, 0x50, 0x63, 0x50, 0x31, 0x59,
+    0x2b, 0x4f, 0x7a, 0x0a, 0x34, 0x79, 0x48, 0x4a, 0x4a, 0x44, 0x6e, 0x70,
+    0x2f, 0x52, 0x56, 0x6d, 0x52, 0x76, 0x51, 0x62, 0x45, 0x64, 0x42, 0x4e,
+    0x63, 0x36, 0x4e, 0x39, 0x52, 0x76, 0x6b, 0x39, 0x37, 0x61, 0x68, 0x66,
+    0x59, 0x74, 0x54, 0x78, 0x50, 0x2f, 0x6a, 0x67, 0x64, 0x46, 0x63, 0x72,
+    0x47, 0x4a, 0x32, 0x42, 0x74, 0x4d, 0x51, 0x6f, 0x32, 0x70, 0x53, 0x58,
+    0x70, 0x58, 0x44, 0x72, 0x72, 0x42, 0x32, 0x2b, 0x0a, 0x42, 0x78, 0x48,
+    0x77, 0x31, 0x64, 0x76, 0x64, 0x35, 0x59, 0x7a, 0x77, 0x31, 0x54, 0x4b,
+    0x77, 0x67, 0x2b, 0x5a, 0x58, 0x34, 0x6f, 0x2b, 0x2f, 0x76, 0x71, 0x47,
+    0x71, 0x76, 0x7a, 0x30, 0x64, 0x74, 0x64, 0x51, 0x34, 0x36, 0x74, 0x65,
+    0x77, 0x58, 0x44, 0x70, 0x50, 0x61, 0x6a, 0x2b, 0x50, 0x77, 0x47, 0x5a,
+    0x73, 0x59, 0x36, 0x72, 0x70, 0x32, 0x61, 0x51, 0x57, 0x39, 0x49, 0x48,
+    0x52, 0x0a, 0x6c, 0x52, 0x51, 0x4f, 0x66, 0x63, 0x32, 0x56, 0x4e, 0x4e,
+    0x6e, 0x53, 0x6a, 0x33, 0x42, 0x7a, 0x67, 0x58, 0x75, 0x63, 0x66, 0x72,
+    0x32, 0x59, 0x59, 0x64, 0x68, 0x46, 0x68, 0x35, 0x69, 0x51, 0x78, 0x65,
+    0x75, 0x47, 0x4d, 0x4d, 0x59, 0x31, 0x76, 0x2f, 0x44, 0x2f, 0x77, 0x31,
+    0x57, 0x49, 0x67, 0x30, 0x76, 0x76, 0x42, 0x5a, 0x49, 0x47, 0x63, 0x66,
+    0x4b, 0x34, 0x6d, 0x4a, 0x4f, 0x33, 0x0a, 0x37, 0x4d, 0x32, 0x43, 0x59,
+    0x66, 0x45, 0x34, 0x35, 0x6b, 0x2b, 0x58, 0x6d, 0x43, 0x70, 0x61, 0x6a,
+    0x51, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73,
+    0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x56, 0x65, 0x72, 0x69,
+    0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33,
+    0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d,
+    0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+    0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+    0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x34, 0x20, 0x4f, 0x3d, 0x56,
+    0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63,
+    0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+    0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77,
+    0x6f, 0x72, 0x6b, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x37,
+    0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49,
+    0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75,
+    0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65,
+    0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a,
+    0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x56, 0x65, 0x72, 0x69,
+    0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33,
+    0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d,
+    0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+    0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+    0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x34, 0x20, 0x4f, 0x3d, 0x56,
+    0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63,
+    0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+    0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77,
+    0x6f, 0x72, 0x6b, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x37,
+    0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49,
+    0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75,
+    0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65,
+    0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65,
+    0x6c, 0x3a, 0x20, 0x22, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e,
+    0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62,
+    0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20,
+    0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+    0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20,
+    0x2d, 0x20, 0x47, 0x34, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69,
+    0x61, 0x6c, 0x3a, 0x20, 0x36, 0x33, 0x31, 0x34, 0x33, 0x34, 0x38, 0x34,
+    0x33, 0x34, 0x38, 0x31, 0x35, 0x33, 0x35, 0x30, 0x36, 0x36, 0x36, 0x35,
+    0x33, 0x31, 0x31, 0x39, 0x38, 0x35, 0x35, 0x30, 0x31, 0x34, 0x35, 0x38,
+    0x36, 0x34, 0x30, 0x30, 0x35, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x33, 0x61, 0x3a, 0x35, 0x32, 0x3a, 0x65, 0x31, 0x3a, 0x65,
+    0x37, 0x3a, 0x66, 0x64, 0x3a, 0x36, 0x66, 0x3a, 0x33, 0x61, 0x3a, 0x65,
+    0x33, 0x3a, 0x36, 0x66, 0x3a, 0x66, 0x33, 0x3a, 0x36, 0x66, 0x3a, 0x39,
+    0x39, 0x3a, 0x31, 0x62, 0x3a, 0x66, 0x39, 0x3a, 0x32, 0x32, 0x3a, 0x34,
+    0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x32,
+    0x3a, 0x64, 0x35, 0x3a, 0x64, 0x38, 0x3a, 0x64, 0x66, 0x3a, 0x38, 0x66,
+    0x3a, 0x30, 0x32, 0x3a, 0x33, 0x31, 0x3a, 0x64, 0x31, 0x3a, 0x38, 0x64,
+    0x3a, 0x66, 0x37, 0x3a, 0x39, 0x64, 0x3a, 0x62, 0x37, 0x3a, 0x63, 0x66,
+    0x3a, 0x38, 0x61, 0x3a, 0x32, 0x64, 0x3a, 0x36, 0x34, 0x3a, 0x63, 0x39,
+    0x3a, 0x33, 0x66, 0x3a, 0x36, 0x63, 0x3a, 0x33, 0x61, 0x0a, 0x23, 0x20,
+    0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x39, 0x3a, 0x64,
+    0x64, 0x3a, 0x64, 0x37, 0x3a, 0x65, 0x61, 0x3a, 0x39, 0x30, 0x3a, 0x62,
+    0x62, 0x3a, 0x35, 0x37, 0x3a, 0x63, 0x39, 0x3a, 0x33, 0x65, 0x3a, 0x31,
+    0x33, 0x3a, 0x35, 0x64, 0x3a, 0x63, 0x38, 0x3a, 0x35, 0x65, 0x3a, 0x61,
+    0x36, 0x3a, 0x66, 0x63, 0x3a, 0x64, 0x35, 0x3a, 0x34, 0x38, 0x3a, 0x30,
+    0x62, 0x3a, 0x36, 0x30, 0x3a, 0x33, 0x32, 0x3a, 0x33, 0x39, 0x3a, 0x62,
+    0x64, 0x3a, 0x63, 0x34, 0x3a, 0x35, 0x34, 0x3a, 0x66, 0x63, 0x3a, 0x37,
+    0x35, 0x3a, 0x38, 0x62, 0x3a, 0x32, 0x61, 0x3a, 0x32, 0x36, 0x3a, 0x63,
+    0x66, 0x3a, 0x37, 0x66, 0x3a, 0x37, 0x39, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49,
+    0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a,
+    0x4d, 0x49, 0x49, 0x44, 0x68, 0x44, 0x43, 0x43, 0x41, 0x77, 0x71, 0x67,
+    0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x4c, 0x34, 0x44, 0x2b,
+    0x49, 0x34, 0x77, 0x4f, 0x49, 0x67, 0x39, 0x49, 0x5a, 0x78, 0x49, 0x6f,
+    0x6b, 0x59, 0x65, 0x73, 0x73, 0x7a, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71,
+    0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x7a, 0x43, 0x42,
+    0x79, 0x6a, 0x45, 0x4c, 0x0a, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x7a, 0x41,
+    0x56, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x6c, 0x5a,
+    0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x4c, 0x43, 0x42,
+    0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x52, 0x38, 0x77, 0x48, 0x51, 0x59,
+    0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x5a, 0x57, 0x0a, 0x5a, 0x58,
+    0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x55, 0x63, 0x6e,
+    0x56, 0x7a, 0x64, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33,
+    0x4a, 0x72, 0x4d, 0x54, 0x6f, 0x77, 0x4f, 0x41, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x4c, 0x45, 0x7a, 0x45, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x6a,
+    0x41, 0x77, 0x4e, 0x79, 0x42, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32,
+    0x6c, 0x6e, 0x0a, 0x62, 0x69, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c,
+    0x69, 0x41, 0x74, 0x49, 0x45, 0x5a, 0x76, 0x63, 0x69, 0x42, 0x68, 0x64,
+    0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x65, 0x6d, 0x56, 0x6b, 0x49,
+    0x48, 0x56, 0x7a, 0x5a, 0x53, 0x42, 0x76, 0x62, 0x6d, 0x78, 0x35, 0x4d,
+    0x55, 0x55, 0x77, 0x51, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45,
+    0x7a, 0x78, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x0a, 0x55, 0x32, 0x6c, 0x6e,
+    0x62, 0x69, 0x42, 0x44, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, 0x41, 0x7a,
+    0x49, 0x46, 0x42, 0x31, 0x59, 0x6d, 0x78, 0x70, 0x59, 0x79, 0x42, 0x51,
+    0x63, 0x6d, 0x6c, 0x74, 0x59, 0x58, 0x4a, 0x35, 0x49, 0x45, 0x4e, 0x6c,
+    0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70,
+    0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79,
+    0x0a, 0x61, 0x58, 0x52, 0x35, 0x49, 0x43, 0x30, 0x67, 0x52, 0x7a, 0x51,
+    0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x63, 0x78, 0x4d, 0x54, 0x41,
+    0x31, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63,
+    0x4e, 0x4d, 0x7a, 0x67, 0x77, 0x4d, 0x54, 0x45, 0x34, 0x4d, 0x6a, 0x4d,
+    0x31, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, 0x43, 0x42, 0x79, 0x6a, 0x45,
+    0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68,
+    0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x7a, 0x41, 0x56, 0x42, 0x67,
+    0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x6c, 0x5a, 0x6c, 0x63, 0x6d,
+    0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d,
+    0x4d, 0x75, 0x4d, 0x52, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x4c, 0x45, 0x78, 0x5a, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x0a, 0x55,
+    0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64,
+    0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x4d,
+    0x54, 0x6f, 0x77, 0x4f, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45,
+    0x7a, 0x45, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x6a, 0x41, 0x77, 0x4e,
+    0x79, 0x42, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62,
+    0x69, 0x77, 0x67, 0x0a, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x69, 0x41, 0x74,
+    0x49, 0x45, 0x5a, 0x76, 0x63, 0x69, 0x42, 0x68, 0x64, 0x58, 0x52, 0x6f,
+    0x62, 0x33, 0x4a, 0x70, 0x65, 0x6d, 0x56, 0x6b, 0x49, 0x48, 0x56, 0x7a,
+    0x5a, 0x53, 0x42, 0x76, 0x62, 0x6d, 0x78, 0x35, 0x4d, 0x55, 0x55, 0x77,
+    0x51, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x7a, 0x78, 0x57,
+    0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x0a, 0x62, 0x69, 0x42,
+    0x44, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, 0x41, 0x7a, 0x49, 0x46, 0x42,
+    0x31, 0x59, 0x6d, 0x78, 0x70, 0x59, 0x79, 0x42, 0x51, 0x63, 0x6d, 0x6c,
+    0x74, 0x59, 0x58, 0x4a, 0x35, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52,
+    0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34,
+    0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52,
+    0x35, 0x0a, 0x49, 0x43, 0x30, 0x67, 0x52, 0x7a, 0x51, 0x77, 0x64, 0x6a,
+    0x41, 0x51, 0x42, 0x67, 0x63, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51,
+    0x49, 0x42, 0x42, 0x67, 0x55, 0x72, 0x67, 0x51, 0x51, 0x41, 0x49, 0x67,
+    0x4e, 0x69, 0x41, 0x41, 0x53, 0x6e, 0x56, 0x6e, 0x70, 0x38, 0x55, 0x74,
+    0x70, 0x6b, 0x6d, 0x77, 0x34, 0x74, 0x58, 0x4e, 0x68, 0x65, 0x72, 0x4a,
+    0x49, 0x39, 0x2f, 0x67, 0x48, 0x6d, 0x0a, 0x47, 0x55, 0x6f, 0x39, 0x46,
+    0x41, 0x4e, 0x4c, 0x2b, 0x6d, 0x41, 0x6e, 0x49, 0x4e, 0x6d, 0x44, 0x69,
+    0x57, 0x6e, 0x36, 0x56, 0x4d, 0x61, 0x61, 0x47, 0x46, 0x35, 0x56, 0x4b,
+    0x6d, 0x54, 0x65, 0x42, 0x76, 0x61, 0x4e, 0x53, 0x6a, 0x75, 0x74, 0x45,
+    0x44, 0x78, 0x6c, 0x50, 0x5a, 0x43, 0x49, 0x42, 0x49, 0x6e, 0x67, 0x4d,
+    0x47, 0x47, 0x7a, 0x72, 0x6c, 0x30, 0x42, 0x70, 0x33, 0x76, 0x65, 0x0a,
+    0x66, 0x4c, 0x4b, 0x2b, 0x79, 0x6d, 0x56, 0x68, 0x41, 0x49, 0x61, 0x75,
+    0x32, 0x6f, 0x39, 0x37, 0x30, 0x49, 0x6d, 0x74, 0x54, 0x52, 0x31, 0x5a,
+    0x6d, 0x6b, 0x47, 0x78, 0x76, 0x45, 0x65, 0x41, 0x33, 0x4a, 0x35, 0x69,
+    0x77, 0x2f, 0x6d, 0x6a, 0x67, 0x62, 0x49, 0x77, 0x67, 0x61, 0x38, 0x77,
+    0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f,
+    0x42, 0x41, 0x55, 0x77, 0x0a, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41,
+    0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38,
+    0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x62, 0x51, 0x59,
+    0x49, 0x4b, 0x77, 0x59, 0x42, 0x42, 0x51, 0x55, 0x48, 0x41, 0x51, 0x77,
+    0x45, 0x59, 0x54, 0x42, 0x66, 0x6f, 0x56, 0x32, 0x67, 0x57, 0x7a, 0x42,
+    0x5a, 0x4d, 0x46, 0x63, 0x77, 0x56, 0x52, 0x59, 0x4a, 0x0a, 0x61, 0x57,
+    0x31, 0x68, 0x5a, 0x32, 0x55, 0x76, 0x5a, 0x32, 0x6c, 0x6d, 0x4d, 0x43,
+    0x45, 0x77, 0x48, 0x7a, 0x41, 0x48, 0x42, 0x67, 0x55, 0x72, 0x44, 0x67,
+    0x4d, 0x43, 0x47, 0x67, 0x51, 0x55, 0x6a, 0x2b, 0x58, 0x54, 0x47, 0x6f,
+    0x61, 0x73, 0x6a, 0x59, 0x35, 0x72, 0x77, 0x38, 0x2b, 0x41, 0x61, 0x74,
+    0x52, 0x49, 0x47, 0x43, 0x78, 0x37, 0x47, 0x53, 0x34, 0x77, 0x4a, 0x52,
+    0x59, 0x6a, 0x0a, 0x61, 0x48, 0x52, 0x30, 0x63, 0x44, 0x6f, 0x76, 0x4c,
+    0x32, 0x78, 0x76, 0x5a, 0x32, 0x38, 0x75, 0x64, 0x6d, 0x56, 0x79, 0x61,
+    0x58, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c,
+    0x33, 0x5a, 0x7a, 0x62, 0x47, 0x39, 0x6e, 0x62, 0x79, 0x35, 0x6e, 0x61,
+    0x57, 0x59, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42,
+    0x42, 0x59, 0x45, 0x46, 0x4c, 0x4d, 0x57, 0x0a, 0x6b, 0x66, 0x33, 0x75,
+    0x70, 0x6d, 0x37, 0x6b, 0x74, 0x53, 0x35, 0x4a, 0x6a, 0x34, 0x64, 0x34,
+    0x67, 0x59, 0x44, 0x73, 0x35, 0x62, 0x47, 0x31, 0x4d, 0x41, 0x6f, 0x47,
+    0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x44,
+    0x41, 0x32, 0x67, 0x41, 0x4d, 0x47, 0x55, 0x43, 0x4d, 0x47, 0x59, 0x68,
+    0x44, 0x42, 0x67, 0x6d, 0x59, 0x46, 0x6f, 0x34, 0x65, 0x31, 0x5a, 0x43,
+    0x0a, 0x34, 0x4b, 0x66, 0x38, 0x4e, 0x6f, 0x52, 0x52, 0x6b, 0x53, 0x41,
+    0x73, 0x64, 0x6b, 0x31, 0x44, 0x50, 0x63, 0x51, 0x64, 0x68, 0x43, 0x50,
+    0x51, 0x72, 0x4e, 0x5a, 0x38, 0x4e, 0x51, 0x62, 0x4f, 0x7a, 0x57, 0x6d,
+    0x39, 0x6b, 0x41, 0x33, 0x62, 0x62, 0x45, 0x68, 0x43, 0x48, 0x51, 0x36,
+    0x71, 0x51, 0x67, 0x49, 0x78, 0x41, 0x4a, 0x77, 0x39, 0x53, 0x44, 0x6b,
+    0x6a, 0x4f, 0x56, 0x67, 0x61, 0x0a, 0x46, 0x52, 0x4a, 0x5a, 0x61, 0x70,
+    0x37, 0x76, 0x31, 0x56, 0x6d, 0x79, 0x48, 0x56, 0x49, 0x73, 0x6d, 0x58,
+    0x48, 0x4e, 0x78, 0x79, 0x6e, 0x66, 0x47, 0x79, 0x70, 0x68, 0x65, 0x33,
+    0x48, 0x52, 0x33, 0x76, 0x50, 0x41, 0x35, 0x51, 0x30, 0x36, 0x53, 0x71,
+    0x6f, 0x74, 0x70, 0x39, 0x69, 0x47, 0x4b, 0x74, 0x30, 0x75, 0x45, 0x41,
+    0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20,
+    0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75,
+    0x65, 0x72, 0x3a, 0x20, 0x4f, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69,
+    0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d,
+    0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c,
+    0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43,
+    0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+    0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23,
+    0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x4f, 0x3d,
+    0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e,
+    0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20,
+    0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69,
+    0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+    0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+    0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c,
+    0x3a, 0x20, 0x22, 0x56, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x20,
+    0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c,
+    0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43,
+    0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+    0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a,
+    0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x38, 0x30,
+    0x35, 0x30, 0x37, 0x35, 0x37, 0x32, 0x37, 0x32, 0x32, 0x38, 0x36, 0x32,
+    0x34, 0x38, 0x35, 0x35, 0x31, 0x35, 0x33, 0x30, 0x36, 0x34, 0x32, 0x39,
+    0x39, 0x34, 0x30, 0x36, 0x39, 0x31, 0x33, 0x30, 0x39, 0x32, 0x34, 0x36,
+    0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x66, 0x3a, 0x35,
+    0x61, 0x3a, 0x66, 0x31, 0x3a, 0x33, 0x33, 0x3a, 0x65, 0x66, 0x3a, 0x66,
+    0x31, 0x3a, 0x63, 0x64, 0x3a, 0x62, 0x62, 0x3a, 0x35, 0x31, 0x3a, 0x30,
+    0x32, 0x3a, 0x65, 0x65, 0x3a, 0x31, 0x32, 0x3a, 0x31, 0x34, 0x3a, 0x34,
+    0x62, 0x3a, 0x39, 0x36, 0x3a, 0x63, 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48,
+    0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x61, 0x31, 0x3a, 0x64, 0x62, 0x3a, 0x36, 0x33,
+    0x3a, 0x39, 0x33, 0x3a, 0x39, 0x31, 0x3a, 0x36, 0x66, 0x3a, 0x31, 0x37,
+    0x3a, 0x65, 0x34, 0x3a, 0x31, 0x38, 0x3a, 0x35, 0x35, 0x3a, 0x30, 0x39,
+    0x3a, 0x34, 0x30, 0x3a, 0x30, 0x34, 0x3a, 0x31, 0x35, 0x3a, 0x63, 0x37,
+    0x3a, 0x30, 0x32, 0x3a, 0x34, 0x30, 0x3a, 0x62, 0x30, 0x3a, 0x61, 0x65,
+    0x3a, 0x36, 0x62, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x61, 0x34, 0x3a, 0x62, 0x36, 0x3a, 0x62, 0x33, 0x3a, 0x39,
+    0x39, 0x3a, 0x36, 0x66, 0x3a, 0x63, 0x32, 0x3a, 0x66, 0x33, 0x3a, 0x30,
+    0x36, 0x3a, 0x62, 0x33, 0x3a, 0x66, 0x64, 0x3a, 0x38, 0x36, 0x3a, 0x38,
+    0x31, 0x3a, 0x62, 0x64, 0x3a, 0x36, 0x33, 0x3a, 0x34, 0x31, 0x3a, 0x33,
+    0x64, 0x3a, 0x38, 0x63, 0x3a, 0x35, 0x30, 0x3a, 0x30, 0x39, 0x3a, 0x63,
+    0x63, 0x3a, 0x34, 0x66, 0x3a, 0x61, 0x33, 0x3a, 0x32, 0x39, 0x3a, 0x63,
+    0x32, 0x3a, 0x63, 0x63, 0x3a, 0x66, 0x30, 0x3a, 0x65, 0x32, 0x3a, 0x66,
+    0x61, 0x3a, 0x31, 0x62, 0x3a, 0x31, 0x34, 0x3a, 0x30, 0x33, 0x3a, 0x30,
+    0x35, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x50, 0x44,
+    0x43, 0x43, 0x41, 0x61, 0x55, 0x43, 0x45, 0x44, 0x79, 0x52, 0x4d, 0x63,
+    0x73, 0x66, 0x39, 0x74, 0x41, 0x62, 0x44, 0x70, 0x71, 0x34, 0x30, 0x45,
+    0x53, 0x2f, 0x45, 0x72, 0x34, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f,
+    0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51,
+    0x41, 0x77, 0x58, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x0a, 0x41,
+    0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46,
+    0x7a, 0x41, 0x56, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44,
+    0x6c, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x4c,
+    0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x54, 0x63, 0x77, 0x4e,
+    0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x79, 0x35, 0x44, 0x62,
+    0x47, 0x46, 0x7a, 0x0a, 0x63, 0x79, 0x41, 0x7a, 0x49, 0x46, 0x42, 0x31,
+    0x59, 0x6d, 0x78, 0x70, 0x59, 0x79, 0x42, 0x51, 0x63, 0x6d, 0x6c, 0x74,
+    0x59, 0x58, 0x4a, 0x35, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70,
+    0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67,
+    0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35,
+    0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x6b, 0x32, 0x0a, 0x4d, 0x44, 0x45,
+    0x79, 0x4f, 0x54, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f,
+    0x58, 0x44, 0x54, 0x49, 0x34, 0x4d, 0x44, 0x67, 0x77, 0x4d, 0x6a, 0x49,
+    0x7a, 0x4e, 0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x58, 0x7a, 0x45,
+    0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d,
+    0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x7a, 0x41, 0x56, 0x42, 0x67, 0x4e,
+    0x56, 0x0a, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x6c, 0x5a, 0x6c, 0x63, 0x6d,
+    0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d,
+    0x4d, 0x75, 0x4d, 0x54, 0x63, 0x77, 0x4e, 0x51, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x4c, 0x45, 0x79, 0x35, 0x44, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79,
+    0x41, 0x7a, 0x49, 0x46, 0x42, 0x31, 0x59, 0x6d, 0x78, 0x70, 0x59, 0x79,
+    0x42, 0x51, 0x63, 0x6d, 0x6c, 0x74, 0x0a, 0x59, 0x58, 0x4a, 0x35, 0x49,
+    0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59,
+    0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61,
+    0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x49, 0x47, 0x66, 0x4d,
+    0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44,
+    0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x47, 0x4e, 0x0a,
+    0x41, 0x44, 0x43, 0x42, 0x69, 0x51, 0x4b, 0x42, 0x67, 0x51, 0x44, 0x4a,
+    0x58, 0x46, 0x6d, 0x65, 0x38, 0x68, 0x75, 0x4b, 0x41, 0x52, 0x53, 0x30,
+    0x45, 0x4e, 0x38, 0x45, 0x51, 0x4e, 0x76, 0x6a, 0x56, 0x36, 0x39, 0x71,
+    0x52, 0x55, 0x43, 0x50, 0x68, 0x41, 0x77, 0x4c, 0x30, 0x54, 0x50, 0x5a,
+    0x32, 0x52, 0x48, 0x50, 0x37, 0x67, 0x4a, 0x59, 0x48, 0x79, 0x58, 0x33,
+    0x4b, 0x71, 0x68, 0x45, 0x0a, 0x42, 0x61, 0x72, 0x73, 0x41, 0x78, 0x39,
+    0x34, 0x66, 0x35, 0x36, 0x54, 0x75, 0x5a, 0x6f, 0x41, 0x71, 0x69, 0x4e,
+    0x39, 0x31, 0x71, 0x79, 0x46, 0x6f, 0x6d, 0x4e, 0x46, 0x78, 0x33, 0x49,
+    0x6e, 0x7a, 0x50, 0x52, 0x4d, 0x78, 0x6e, 0x56, 0x78, 0x30, 0x6a, 0x6e,
+    0x76, 0x54, 0x30, 0x4c, 0x77, 0x64, 0x64, 0x38, 0x4b, 0x6b, 0x4d, 0x61,
+    0x4f, 0x49, 0x47, 0x2b, 0x59, 0x44, 0x2f, 0x69, 0x73, 0x0a, 0x49, 0x31,
+    0x39, 0x77, 0x4b, 0x54, 0x61, 0x6b, 0x79, 0x59, 0x62, 0x6e, 0x73, 0x5a,
+    0x6f, 0x67, 0x79, 0x31, 0x4f, 0x6c, 0x68, 0x65, 0x63, 0x39, 0x76, 0x6e,
+    0x32, 0x61, 0x2f, 0x69, 0x52, 0x46, 0x4d, 0x39, 0x78, 0x32, 0x46, 0x65,
+    0x30, 0x50, 0x6f, 0x6e, 0x46, 0x6b, 0x54, 0x47, 0x55, 0x75, 0x67, 0x57,
+    0x68, 0x46, 0x70, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x4d, 0x41,
+    0x30, 0x47, 0x0a, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44,
+    0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x41, 0x34, 0x47, 0x42, 0x41,
+    0x42, 0x42, 0x79, 0x55, 0x71, 0x6b, 0x46, 0x46, 0x42, 0x6b, 0x79, 0x43,
+    0x45, 0x48, 0x77, 0x78, 0x57, 0x73, 0x4b, 0x7a, 0x48, 0x34, 0x50, 0x49,
+    0x52, 0x6e, 0x4e, 0x35, 0x47, 0x66, 0x63, 0x58, 0x36, 0x6b, 0x62, 0x35,
+    0x73, 0x72, 0x6f, 0x63, 0x35, 0x30, 0x69, 0x0a, 0x32, 0x4a, 0x68, 0x75,
+    0x63, 0x77, 0x4e, 0x68, 0x6b, 0x63, 0x56, 0x38, 0x73, 0x45, 0x56, 0x41,
+    0x62, 0x6b, 0x53, 0x64, 0x6a, 0x62, 0x43, 0x78, 0x6c, 0x6e, 0x52, 0x68,
+    0x4c, 0x51, 0x32, 0x70, 0x52, 0x64, 0x4b, 0x6b, 0x6b, 0x69, 0x72, 0x57,
+    0x6d, 0x6e, 0x57, 0x58, 0x62, 0x6a, 0x39, 0x54, 0x2f, 0x55, 0x57, 0x5a,
+    0x59, 0x42, 0x32, 0x6f, 0x4b, 0x30, 0x7a, 0x35, 0x58, 0x71, 0x63, 0x4a,
+    0x0a, 0x32, 0x48, 0x55, 0x77, 0x31, 0x39, 0x4a, 0x6c, 0x59, 0x44, 0x31,
+    0x6e, 0x31, 0x6b, 0x68, 0x56, 0x64, 0x57, 0x6b, 0x2f, 0x6b, 0x66, 0x56,
+    0x49, 0x43, 0x30, 0x64, 0x70, 0x49, 0x6d, 0x6d, 0x43, 0x6c, 0x72, 0x37,
+    0x4a, 0x79, 0x44, 0x69, 0x47, 0x53, 0x6e, 0x6f, 0x73, 0x63, 0x78, 0x6c,
+    0x49, 0x61, 0x55, 0x35, 0x72, 0x66, 0x47, 0x57, 0x2f, 0x44, 0x2f, 0x78,
+    0x77, 0x7a, 0x6f, 0x69, 0x51, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45,
+    0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41,
+    0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49,
+    0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x6c,
+    0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x3d, 0x47,
+    0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x55,
+    0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20,
+    0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x33,
+    0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20,
+    0x43, 0x4e, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67,
+    0x6e, 0x20, 0x4f, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69,
+    0x67, 0x6e, 0x20, 0x4f, 0x55, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+    0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
+    0x20, 0x2d, 0x20, 0x52, 0x33, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65,
+    0x6c, 0x3a, 0x20, 0x22, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69,
+    0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d,
+    0x20, 0x52, 0x33, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61,
+    0x6c, 0x3a, 0x20, 0x34, 0x38, 0x33, 0x35, 0x37, 0x30, 0x33, 0x32, 0x37,
+    0x38, 0x34, 0x35, 0x39, 0x37, 0x35, 0x39, 0x34, 0x32, 0x36, 0x32, 0x30,
+    0x39, 0x39, 0x35, 0x34, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x63, 0x35, 0x3a, 0x64, 0x66, 0x3a, 0x62, 0x38, 0x3a, 0x34, 0x39, 0x3a,
+    0x63, 0x61, 0x3a, 0x30, 0x35, 0x3a, 0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a,
+    0x65, 0x65, 0x3a, 0x32, 0x64, 0x3a, 0x62, 0x61, 0x3a, 0x31, 0x61, 0x3a,
+    0x63, 0x33, 0x3a, 0x33, 0x65, 0x3a, 0x62, 0x30, 0x3a, 0x32, 0x38, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65,
+    0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x36, 0x3a, 0x39,
+    0x62, 0x3a, 0x35, 0x36, 0x3a, 0x31, 0x31, 0x3a, 0x34, 0x38, 0x3a, 0x66,
+    0x30, 0x3a, 0x31, 0x63, 0x3a, 0x37, 0x37, 0x3a, 0x63, 0x35, 0x3a, 0x34,
+    0x35, 0x3a, 0x37, 0x38, 0x3a, 0x63, 0x31, 0x3a, 0x30, 0x39, 0x3a, 0x32,
+    0x36, 0x3a, 0x64, 0x66, 0x3a, 0x35, 0x62, 0x3a, 0x38, 0x35, 0x3a, 0x36,
+    0x39, 0x3a, 0x37, 0x36, 0x3a, 0x61, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x48,
+    0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x62, 0x3a, 0x62, 0x35, 0x3a,
+    0x32, 0x32, 0x3a, 0x64, 0x37, 0x3a, 0x62, 0x37, 0x3a, 0x66, 0x31, 0x3a,
+    0x32, 0x37, 0x3a, 0x61, 0x64, 0x3a, 0x36, 0x61, 0x3a, 0x30, 0x31, 0x3a,
+    0x31, 0x33, 0x3a, 0x38, 0x36, 0x3a, 0x35, 0x62, 0x3a, 0x64, 0x66, 0x3a,
+    0x31, 0x63, 0x3a, 0x64, 0x34, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x65, 0x3a,
+    0x37, 0x64, 0x3a, 0x30, 0x37, 0x3a, 0x35, 0x39, 0x3a, 0x61, 0x66, 0x3a,
+    0x36, 0x33, 0x3a, 0x35, 0x61, 0x3a, 0x37, 0x63, 0x3a, 0x66, 0x34, 0x3a,
+    0x37, 0x32, 0x3a, 0x30, 0x64, 0x3a, 0x63, 0x39, 0x3a, 0x36, 0x33, 0x3a,
+    0x63, 0x35, 0x3a, 0x33, 0x62, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42,
+    0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49,
+    0x49, 0x44, 0x58, 0x7a, 0x43, 0x43, 0x41, 0x6b, 0x65, 0x67, 0x41, 0x77,
+    0x49, 0x42, 0x41, 0x67, 0x49, 0x4c, 0x42, 0x41, 0x41, 0x41, 0x41, 0x41,
+    0x41, 0x42, 0x49, 0x56, 0x68, 0x54, 0x43, 0x4b, 0x49, 0x77, 0x44, 0x51,
+    0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51,
+    0x45, 0x4c, 0x42, 0x51, 0x41, 0x77, 0x54, 0x44, 0x45, 0x67, 0x4d, 0x42,
+    0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x58, 0x52,
+    0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, 0x55, 0x32, 0x6c, 0x6e, 0x62,
+    0x69, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x49,
+    0x43, 0x30, 0x67, 0x55, 0x6a, 0x4d, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42,
+    0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x43, 0x6b, 0x64, 0x73, 0x62,
+    0x32, 0x4a, 0x68, 0x62, 0x46, 0x4e, 0x70, 0x0a, 0x5a, 0x32, 0x34, 0x78,
+    0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54,
+    0x43, 0x6b, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62, 0x46, 0x4e, 0x70,
+    0x5a, 0x32, 0x34, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x6b, 0x77,
+    0x4d, 0x7a, 0x45, 0x34, 0x4d, 0x54, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77,
+    0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x6b, 0x77, 0x4d, 0x7a, 0x45, 0x34,
+    0x0a, 0x4d, 0x54, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x6a, 0x42,
+    0x4d, 0x4d, 0x53, 0x41, 0x77, 0x48, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x4c, 0x45, 0x78, 0x64, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x78,
+    0x54, 0x61, 0x57, 0x64, 0x75, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51,
+    0x67, 0x51, 0x30, 0x45, 0x67, 0x4c, 0x53, 0x42, 0x53, 0x4d, 0x7a, 0x45,
+    0x54, 0x4d, 0x42, 0x45, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68,
+    0x4d, 0x4b, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, 0x55, 0x32,
+    0x6c, 0x6e, 0x62, 0x6a, 0x45, 0x54, 0x4d, 0x42, 0x45, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x41, 0x78, 0x4d, 0x4b, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d,
+    0x46, 0x73, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x6a, 0x43, 0x43, 0x41, 0x53,
+    0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x0a, 0x68,
+    0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67,
+    0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67,
+    0x67, 0x45, 0x42, 0x41, 0x4d, 0x77, 0x6c, 0x64, 0x70, 0x42, 0x35, 0x42,
+    0x6e, 0x67, 0x69, 0x46, 0x76, 0x58, 0x41, 0x67, 0x37, 0x61, 0x45, 0x79,
+    0x69, 0x69, 0x65, 0x2f, 0x51, 0x56, 0x32, 0x45, 0x63, 0x57, 0x74, 0x69,
+    0x48, 0x4c, 0x38, 0x0a, 0x52, 0x67, 0x4a, 0x44, 0x78, 0x37, 0x4b, 0x4b,
+    0x6e, 0x51, 0x52, 0x66, 0x4a, 0x4d, 0x73, 0x75, 0x53, 0x2b, 0x46, 0x67,
+    0x67, 0x6b, 0x62, 0x68, 0x55, 0x71, 0x73, 0x4d, 0x67, 0x55, 0x64, 0x77,
+    0x62, 0x4e, 0x31, 0x6b, 0x30, 0x65, 0x76, 0x31, 0x4c, 0x4b, 0x4d, 0x50,
+    0x67, 0x6a, 0x30, 0x4d, 0x4b, 0x36, 0x36, 0x58, 0x31, 0x37, 0x59, 0x55,
+    0x68, 0x68, 0x42, 0x35, 0x75, 0x7a, 0x73, 0x54, 0x0a, 0x67, 0x48, 0x65,
+    0x4d, 0x43, 0x4f, 0x46, 0x4a, 0x30, 0x6d, 0x70, 0x69, 0x4c, 0x78, 0x39,
+    0x65, 0x2b, 0x70, 0x5a, 0x6f, 0x33, 0x34, 0x6b, 0x6e, 0x6c, 0x54, 0x69,
+    0x66, 0x42, 0x74, 0x63, 0x2b, 0x79, 0x63, 0x73, 0x6d, 0x57, 0x51, 0x31,
+    0x7a, 0x33, 0x72, 0x44, 0x49, 0x36, 0x53, 0x59, 0x4f, 0x67, 0x78, 0x58,
+    0x47, 0x37, 0x31, 0x75, 0x4c, 0x30, 0x67, 0x52, 0x67, 0x79, 0x6b, 0x6d,
+    0x6d, 0x0a, 0x4b, 0x50, 0x5a, 0x70, 0x4f, 0x2f, 0x62, 0x4c, 0x79, 0x43,
+    0x69, 0x52, 0x35, 0x5a, 0x32, 0x4b, 0x59, 0x56, 0x63, 0x33, 0x72, 0x48,
+    0x51, 0x55, 0x33, 0x48, 0x54, 0x67, 0x4f, 0x75, 0x35, 0x79, 0x4c, 0x79,
+    0x36, 0x63, 0x2b, 0x39, 0x43, 0x37, 0x76, 0x2f, 0x55, 0x39, 0x41, 0x4f,
+    0x45, 0x47, 0x4d, 0x2b, 0x69, 0x43, 0x4b, 0x36, 0x35, 0x54, 0x70, 0x6a,
+    0x6f, 0x57, 0x63, 0x34, 0x7a, 0x64, 0x0a, 0x51, 0x51, 0x34, 0x67, 0x4f,
+    0x73, 0x43, 0x30, 0x70, 0x36, 0x48, 0x70, 0x73, 0x6b, 0x2b, 0x51, 0x4c,
+    0x6a, 0x4a, 0x67, 0x36, 0x56, 0x66, 0x4c, 0x75, 0x51, 0x53, 0x53, 0x61,
+    0x47, 0x6a, 0x6c, 0x4f, 0x43, 0x5a, 0x67, 0x64, 0x62, 0x4b, 0x66, 0x64,
+    0x2f, 0x2b, 0x52, 0x46, 0x4f, 0x2b, 0x75, 0x49, 0x45, 0x6e, 0x38, 0x72,
+    0x55, 0x41, 0x56, 0x53, 0x4e, 0x45, 0x43, 0x4d, 0x57, 0x45, 0x5a, 0x0a,
+    0x58, 0x72, 0x69, 0x58, 0x37, 0x36, 0x31, 0x33, 0x74, 0x32, 0x53, 0x61,
+    0x65, 0x72, 0x39, 0x66, 0x77, 0x52, 0x50, 0x76, 0x6d, 0x32, 0x4c, 0x37,
+    0x44, 0x57, 0x7a, 0x67, 0x56, 0x47, 0x6b, 0x57, 0x71, 0x51, 0x50, 0x61,
+    0x62, 0x75, 0x6d, 0x44, 0x6b, 0x33, 0x46, 0x32, 0x78, 0x6d, 0x6d, 0x46,
+    0x67, 0x68, 0x63, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, 0x43,
+    0x4d, 0x45, 0x41, 0x77, 0x0a, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30,
+    0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45,
+    0x47, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45,
+    0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38,
+    0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59,
+    0x45, 0x46, 0x49, 0x2f, 0x77, 0x53, 0x33, 0x2b, 0x6f, 0x0a, 0x4c, 0x6b,
+    0x55, 0x6b, 0x72, 0x6b, 0x31, 0x51, 0x2b, 0x6d, 0x4f, 0x61, 0x69, 0x39,
+    0x37, 0x69, 0x33, 0x52, 0x75, 0x38, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53,
+    0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77,
+    0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x42, 0x4c, 0x51, 0x4e,
+    0x76, 0x41, 0x55, 0x4b, 0x72, 0x2b, 0x79, 0x41, 0x7a, 0x76, 0x39, 0x35,
+    0x5a, 0x55, 0x0a, 0x52, 0x55, 0x6d, 0x37, 0x6c, 0x67, 0x41, 0x4a, 0x51,
+    0x61, 0x79, 0x7a, 0x45, 0x34, 0x61, 0x47, 0x4b, 0x41, 0x63, 0x7a, 0x79,
+    0x6d, 0x76, 0x6d, 0x64, 0x4c, 0x6d, 0x36, 0x41, 0x43, 0x32, 0x75, 0x70,
+    0x41, 0x72, 0x54, 0x39, 0x66, 0x48, 0x78, 0x44, 0x34, 0x71, 0x2f, 0x63,
+    0x32, 0x64, 0x4b, 0x67, 0x38, 0x64, 0x45, 0x65, 0x33, 0x6a, 0x67, 0x72,
+    0x32, 0x35, 0x73, 0x62, 0x77, 0x4d, 0x70, 0x0a, 0x6a, 0x6a, 0x4d, 0x35,
+    0x52, 0x63, 0x4f, 0x4f, 0x35, 0x4c, 0x6c, 0x58, 0x62, 0x4b, 0x72, 0x38,
+    0x45, 0x70, 0x62, 0x73, 0x55, 0x38, 0x59, 0x74, 0x35, 0x43, 0x52, 0x73,
+    0x75, 0x5a, 0x52, 0x6a, 0x2b, 0x39, 0x78, 0x54, 0x61, 0x47, 0x64, 0x57,
+    0x50, 0x6f, 0x4f, 0x34, 0x7a, 0x7a, 0x55, 0x68, 0x77, 0x38, 0x6c, 0x6f,
+    0x2f, 0x73, 0x37, 0x61, 0x77, 0x6c, 0x4f, 0x71, 0x7a, 0x4a, 0x43, 0x4b,
+    0x0a, 0x36, 0x66, 0x42, 0x64, 0x52, 0x6f, 0x79, 0x56, 0x33, 0x58, 0x70,
+    0x59, 0x4b, 0x42, 0x6f, 0x76, 0x48, 0x64, 0x37, 0x4e, 0x41, 0x44, 0x64,
+    0x42, 0x6a, 0x2b, 0x31, 0x45, 0x62, 0x64, 0x64, 0x54, 0x4b, 0x4a, 0x64,
+    0x2b, 0x38, 0x32, 0x63, 0x45, 0x48, 0x68, 0x58, 0x58, 0x69, 0x70, 0x61,
+    0x30, 0x30, 0x39, 0x35, 0x4d, 0x4a, 0x36, 0x52, 0x4d, 0x47, 0x33, 0x4e,
+    0x7a, 0x64, 0x76, 0x51, 0x58, 0x0a, 0x6d, 0x63, 0x49, 0x66, 0x65, 0x67,
+    0x37, 0x6a, 0x4c, 0x51, 0x69, 0x74, 0x43, 0x68, 0x77, 0x73, 0x2f, 0x7a,
+    0x79, 0x72, 0x56, 0x51, 0x34, 0x50, 0x6b, 0x58, 0x34, 0x32, 0x36, 0x38,
+    0x4e, 0x58, 0x53, 0x62, 0x37, 0x68, 0x4c, 0x69, 0x31, 0x38, 0x59, 0x49,
+    0x76, 0x44, 0x51, 0x56, 0x45, 0x54, 0x49, 0x35, 0x33, 0x4f, 0x39, 0x7a,
+    0x4a, 0x72, 0x6c, 0x41, 0x47, 0x6f, 0x6d, 0x65, 0x63, 0x73, 0x0a, 0x4d,
+    0x78, 0x38, 0x36, 0x4f, 0x79, 0x58, 0x53, 0x68, 0x6b, 0x44, 0x4f, 0x4f,
+    0x79, 0x79, 0x47, 0x65, 0x4d, 0x6c, 0x68, 0x4c, 0x78, 0x53, 0x36, 0x37,
+    0x74, 0x74, 0x56, 0x62, 0x39, 0x2b, 0x45, 0x37, 0x67, 0x55, 0x4a, 0x54,
+    0x62, 0x30, 0x6f, 0x32, 0x48, 0x4c, 0x4f, 0x30, 0x32, 0x4a, 0x51, 0x5a,
+    0x52, 0x37, 0x72, 0x6b, 0x70, 0x65, 0x44, 0x4d, 0x64, 0x6d, 0x7a, 0x74,
+    0x63, 0x70, 0x48, 0x0a, 0x57, 0x44, 0x39, 0x66, 0x0a, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a,
+    0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x54, 0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e,
+    0x74, 0x65, 0x72, 0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61,
+    0x6c, 0x20, 0x43, 0x41, 0x20, 0x49, 0x49, 0x49, 0x20, 0x4f, 0x3d, 0x54,
+    0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65,
+    0x72, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x20, 0x4f, 0x55, 0x3d, 0x54, 0x43,
+    0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72,
+    0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x43,
+    0x41, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a,
+    0x20, 0x43, 0x4e, 0x3d, 0x54, 0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74,
+    0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x55, 0x6e, 0x69, 0x76, 0x65,
+    0x72, 0x73, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x49, 0x49, 0x49, 0x20,
+    0x4f, 0x3d, 0x54, 0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65,
+    0x6e, 0x74, 0x65, 0x72, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x20, 0x4f, 0x55,
+    0x3d, 0x54, 0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e,
+    0x74, 0x65, 0x72, 0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61,
+    0x6c, 0x20, 0x43, 0x41, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c,
+    0x3a, 0x20, 0x22, 0x54, 0x43, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43,
+    0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72,
+    0x73, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x49, 0x49, 0x49, 0x22, 0x0a,
+    0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x32, 0x30,
+    0x31, 0x30, 0x38, 0x38, 0x39, 0x39, 0x39, 0x33, 0x39, 0x38, 0x33, 0x35,
+    0x30, 0x37, 0x33, 0x34, 0x36, 0x34, 0x36, 0x30, 0x35, 0x33, 0x33, 0x34,
+    0x30, 0x37, 0x39, 0x30, 0x32, 0x39, 0x36, 0x34, 0x0a, 0x23, 0x20, 0x4d,
+    0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x39, 0x66, 0x3a, 0x64, 0x64, 0x3a, 0x64, 0x62,
+    0x3a, 0x61, 0x62, 0x3a, 0x66, 0x66, 0x3a, 0x38, 0x65, 0x3a, 0x66, 0x66,
+    0x3a, 0x34, 0x35, 0x3a, 0x32, 0x31, 0x3a, 0x35, 0x66, 0x3a, 0x66, 0x30,
+    0x3a, 0x36, 0x63, 0x3a, 0x39, 0x64, 0x3a, 0x38, 0x66, 0x3a, 0x66, 0x65,
+    0x3a, 0x32, 0x62, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x39, 0x36, 0x3a, 0x35, 0x36, 0x3a, 0x63, 0x64, 0x3a, 0x37, 0x62, 0x3a,
+    0x35, 0x37, 0x3a, 0x39, 0x36, 0x3a, 0x39, 0x38, 0x3a, 0x39, 0x35, 0x3a,
+    0x64, 0x30, 0x3a, 0x65, 0x31, 0x3a, 0x34, 0x31, 0x3a, 0x34, 0x36, 0x3a,
+    0x36, 0x38, 0x3a, 0x30, 0x36, 0x3a, 0x66, 0x62, 0x3a, 0x62, 0x38, 0x3a,
+    0x63, 0x36, 0x3a, 0x31, 0x31, 0x3a, 0x30, 0x36, 0x3a, 0x38, 0x37, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x30,
+    0x3a, 0x39, 0x62, 0x3a, 0x34, 0x61, 0x3a, 0x38, 0x37, 0x3a, 0x66, 0x36,
+    0x3a, 0x63, 0x61, 0x3a, 0x35, 0x36, 0x3a, 0x63, 0x39, 0x3a, 0x33, 0x31,
+    0x3a, 0x36, 0x39, 0x3a, 0x61, 0x61, 0x3a, 0x61, 0x39, 0x3a, 0x39, 0x63,
+    0x3a, 0x36, 0x64, 0x3a, 0x39, 0x38, 0x3a, 0x38, 0x38, 0x3a, 0x35, 0x34,
+    0x3a, 0x64, 0x37, 0x3a, 0x38, 0x39, 0x3a, 0x32, 0x62, 0x3a, 0x64, 0x35,
+    0x3a, 0x34, 0x33, 0x3a, 0x37, 0x65, 0x3a, 0x32, 0x64, 0x3a, 0x30, 0x37,
+    0x3a, 0x62, 0x32, 0x3a, 0x39, 0x63, 0x3a, 0x62, 0x65, 0x3a, 0x64, 0x61,
+    0x3a, 0x35, 0x35, 0x3a, 0x64, 0x33, 0x3a, 0x35, 0x64, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52,
+    0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x34, 0x54, 0x43, 0x43, 0x41, 0x73,
+    0x6d, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x4f, 0x59, 0x79,
+    0x55, 0x41, 0x41, 0x51, 0x41, 0x43, 0x46, 0x49, 0x30, 0x7a, 0x46, 0x51,
+    0x4c, 0x6b, 0x62, 0x50, 0x51, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f,
+    0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51,
+    0x41, 0x77, 0x65, 0x7a, 0x45, 0x4c, 0x0a, 0x4d, 0x41, 0x6b, 0x47, 0x41,
+    0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x45, 0x55, 0x78, 0x48,
+    0x44, 0x41, 0x61, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x45,
+    0x31, 0x52, 0x44, 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x51,
+    0x32, 0x56, 0x75, 0x64, 0x47, 0x56, 0x79, 0x49, 0x45, 0x64, 0x74, 0x59,
+    0x6b, 0x67, 0x78, 0x4a, 0x44, 0x41, 0x69, 0x42, 0x67, 0x4e, 0x56, 0x0a,
+    0x42, 0x41, 0x73, 0x54, 0x47, 0x31, 0x52, 0x44, 0x49, 0x46, 0x52, 0x79,
+    0x64, 0x58, 0x4e, 0x30, 0x51, 0x32, 0x56, 0x75, 0x64, 0x47, 0x56, 0x79,
+    0x49, 0x46, 0x56, 0x75, 0x61, 0x58, 0x5a, 0x6c, 0x63, 0x6e, 0x4e, 0x68,
+    0x62, 0x43, 0x42, 0x44, 0x51, 0x54, 0x45, 0x6f, 0x4d, 0x43, 0x59, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x66, 0x56, 0x45, 0x4d, 0x67,
+    0x56, 0x48, 0x4a, 0x31, 0x0a, 0x63, 0x33, 0x52, 0x44, 0x5a, 0x57, 0x35,
+    0x30, 0x5a, 0x58, 0x49, 0x67, 0x56, 0x57, 0x35, 0x70, 0x64, 0x6d, 0x56,
+    0x79, 0x63, 0x32, 0x46, 0x73, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x45, 0x6c,
+    0x4a, 0x53, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, 0x77, 0x4f, 0x54, 0x41,
+    0x35, 0x4d, 0x44, 0x6b, 0x77, 0x4f, 0x44, 0x45, 0x31, 0x4d, 0x6a, 0x64,
+    0x61, 0x46, 0x77, 0x30, 0x79, 0x4f, 0x54, 0x45, 0x79, 0x0a, 0x4d, 0x7a,
+    0x45, 0x79, 0x4d, 0x7a, 0x55, 0x35, 0x4e, 0x54, 0x6c, 0x61, 0x4d, 0x48,
+    0x73, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41,
+    0x59, 0x54, 0x41, 0x6b, 0x52, 0x46, 0x4d, 0x52, 0x77, 0x77, 0x47, 0x67,
+    0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x4e, 0x55, 0x51, 0x79,
+    0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x45, 0x4e, 0x6c, 0x62, 0x6e,
+    0x52, 0x6c, 0x0a, 0x63, 0x69, 0x42, 0x48, 0x62, 0x57, 0x4a, 0x49, 0x4d,
+    0x53, 0x51, 0x77, 0x49, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45,
+    0x78, 0x74, 0x55, 0x51, 0x79, 0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64,
+    0x45, 0x4e, 0x6c, 0x62, 0x6e, 0x52, 0x6c, 0x63, 0x69, 0x42, 0x56, 0x62,
+    0x6d, 0x6c, 0x32, 0x5a, 0x58, 0x4a, 0x7a, 0x59, 0x57, 0x77, 0x67, 0x51,
+    0x30, 0x45, 0x78, 0x4b, 0x44, 0x41, 0x6d, 0x0a, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x4d, 0x54, 0x48, 0x31, 0x52, 0x44, 0x49, 0x46, 0x52, 0x79,
+    0x64, 0x58, 0x4e, 0x30, 0x51, 0x32, 0x56, 0x75, 0x64, 0x47, 0x56, 0x79,
+    0x49, 0x46, 0x56, 0x75, 0x61, 0x58, 0x5a, 0x6c, 0x63, 0x6e, 0x4e, 0x68,
+    0x62, 0x43, 0x42, 0x44, 0x51, 0x53, 0x42, 0x4a, 0x53, 0x55, 0x6b, 0x77,
+    0x67, 0x67, 0x45, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47,
+    0x0a, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55,
+    0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45,
+    0x4b, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x44, 0x43, 0x32, 0x70, 0x78,
+    0x69, 0x73, 0x4c, 0x6c, 0x78, 0x45, 0x72, 0x41, 0x4c, 0x79, 0x42, 0x70,
+    0x58, 0x73, 0x71, 0x36, 0x44, 0x46, 0x4a, 0x6d, 0x7a, 0x4e, 0x45, 0x75,
+    0x62, 0x6b, 0x4b, 0x4c, 0x46, 0x0a, 0x35, 0x2b, 0x63, 0x76, 0x41, 0x71,
+    0x42, 0x4e, 0x4c, 0x61, 0x54, 0x36, 0x68, 0x64, 0x71, 0x62, 0x4a, 0x59,
+    0x55, 0x74, 0x51, 0x43, 0x67, 0x67, 0x62, 0x65, 0x72, 0x67, 0x76, 0x62,
+    0x46, 0x49, 0x67, 0x79, 0x49, 0x70, 0x52, 0x4a, 0x39, 0x4f, 0x67, 0x2b,
+    0x34, 0x31, 0x55, 0x52, 0x4e, 0x7a, 0x64, 0x4e, 0x57, 0x38, 0x38, 0x6a,
+    0x42, 0x6d, 0x6c, 0x46, 0x50, 0x41, 0x51, 0x44, 0x59, 0x76, 0x0a, 0x44,
+    0x49, 0x52, 0x6c, 0x7a, 0x67, 0x39, 0x75, 0x77, 0x6c, 0x69, 0x54, 0x36,
+    0x43, 0x77, 0x4c, 0x4f, 0x75, 0x6e, 0x42, 0x6a, 0x76, 0x76, 0x79, 0x61,
+    0x38, 0x6f, 0x38, 0x34, 0x70, 0x78, 0x4f, 0x6a, 0x75, 0x54, 0x35, 0x66,
+    0x64, 0x4d, 0x6e, 0x6e, 0x78, 0x76, 0x56, 0x5a, 0x33, 0x69, 0x48, 0x4c,
+    0x58, 0x38, 0x4c, 0x52, 0x37, 0x50, 0x48, 0x36, 0x4d, 0x6c, 0x49, 0x66,
+    0x4b, 0x38, 0x76, 0x0a, 0x7a, 0x41, 0x72, 0x5a, 0x51, 0x65, 0x2b, 0x66,
+    0x2f, 0x70, 0x72, 0x68, 0x73, 0x71, 0x37, 0x35, 0x55, 0x37, 0x58, 0x6c,
+    0x36, 0x55, 0x61, 0x66, 0x59, 0x4f, 0x50, 0x66, 0x6a, 0x64, 0x4e, 0x2f,
+    0x2b, 0x35, 0x5a, 0x2b, 0x73, 0x37, 0x56, 0x79, 0x2b, 0x45, 0x75, 0x74,
+    0x43, 0x48, 0x6e, 0x4e, 0x61, 0x59, 0x6c, 0x41, 0x4a, 0x2f, 0x55, 0x71,
+    0x77, 0x61, 0x31, 0x44, 0x37, 0x4b, 0x52, 0x54, 0x0a, 0x79, 0x47, 0x47,
+    0x32, 0x39, 0x39, 0x4a, 0x35, 0x4b, 0x6d, 0x63, 0x59, 0x64, 0x6b, 0x68,
+    0x74, 0x57, 0x79, 0x55, 0x42, 0x30, 0x53, 0x62, 0x46, 0x74, 0x31, 0x64,
+    0x70, 0x49, 0x78, 0x56, 0x62, 0x59, 0x59, 0x71, 0x74, 0x38, 0x42, 0x73,
+    0x74, 0x32, 0x61, 0x39, 0x63, 0x38, 0x53, 0x61, 0x51, 0x61, 0x61, 0x6e,
+    0x56, 0x44, 0x45, 0x44, 0x31, 0x4d, 0x34, 0x42, 0x44, 0x6a, 0x35, 0x79,
+    0x6a, 0x0a, 0x64, 0x69, 0x70, 0x46, 0x74, 0x4b, 0x2b, 0x2f, 0x66, 0x7a,
+    0x36, 0x48, 0x50, 0x33, 0x62, 0x46, 0x7a, 0x53, 0x72, 0x65, 0x49, 0x4d,
+    0x55, 0x57, 0x57, 0x4d, 0x76, 0x35, 0x47, 0x2f, 0x55, 0x50, 0x79, 0x77,
+    0x30, 0x52, 0x55, 0x6d, 0x53, 0x34, 0x30, 0x6e, 0x5a, 0x69, 0x64, 0x34,
+    0x50, 0x78, 0x57, 0x4a, 0x2f, 0x2f, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41,
+    0x47, 0x6a, 0x59, 0x7a, 0x42, 0x68, 0x0a, 0x4d, 0x42, 0x38, 0x47, 0x41,
+    0x31, 0x55, 0x64, 0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, 0x61, 0x41, 0x46,
+    0x46, 0x62, 0x6e, 0x34, 0x56, 0x73, 0x6c, 0x51, 0x34, 0x44, 0x67, 0x39,
+    0x6f, 0x7a, 0x68, 0x63, 0x62, 0x79, 0x4f, 0x35, 0x59, 0x41, 0x76, 0x78,
+    0x45, 0x6a, 0x69, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45,
+    0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x0a,
+    0x41, 0x66, 0x38, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50,
+    0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47,
+    0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57,
+    0x42, 0x42, 0x52, 0x57, 0x35, 0x2b, 0x46, 0x62, 0x4a, 0x55, 0x4f, 0x41,
+    0x34, 0x50, 0x61, 0x4d, 0x34, 0x58, 0x47, 0x38, 0x6a, 0x75, 0x57, 0x41,
+    0x4c, 0x38, 0x52, 0x49, 0x0a, 0x34, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b,
+    0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55,
+    0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x67, 0x38, 0x65,
+    0x76, 0x36, 0x6e, 0x39, 0x4e, 0x43, 0x6a, 0x77, 0x35, 0x73, 0x57, 0x69,
+    0x2b, 0x65, 0x32, 0x32, 0x4a, 0x4c, 0x75, 0x6d, 0x7a, 0x43, 0x65, 0x63,
+    0x59, 0x56, 0x34, 0x32, 0x46, 0x6d, 0x68, 0x66, 0x7a, 0x0a, 0x64, 0x6b,
+    0x4a, 0x51, 0x45, 0x77, 0x2f, 0x48, 0x6b, 0x47, 0x38, 0x7a, 0x72, 0x63,
+    0x56, 0x4a, 0x59, 0x43, 0x74, 0x73, 0x53, 0x56, 0x67, 0x5a, 0x31, 0x4f,
+    0x4b, 0x2b, 0x74, 0x37, 0x2b, 0x72, 0x53, 0x62, 0x79, 0x55, 0x79, 0x4b,
+    0x75, 0x2b, 0x4b, 0x47, 0x77, 0x57, 0x61, 0x4f, 0x44, 0x49, 0x6c, 0x30,
+    0x59, 0x67, 0x6f, 0x47, 0x68, 0x6e, 0x59, 0x49, 0x67, 0x35, 0x49, 0x46,
+    0x48, 0x59, 0x0a, 0x61, 0x41, 0x45, 0x52, 0x7a, 0x71, 0x66, 0x32, 0x45,
+    0x51, 0x66, 0x32, 0x37, 0x4f, 0x79, 0x73, 0x47, 0x68, 0x2b, 0x79, 0x5a,
+    0x6d, 0x35, 0x57, 0x5a, 0x32, 0x42, 0x36, 0x64, 0x46, 0x37, 0x41, 0x62,
+    0x5a, 0x63, 0x32, 0x72, 0x72, 0x55, 0x4e, 0x58, 0x57, 0x5a, 0x7a, 0x77,
+    0x43, 0x55, 0x79, 0x52, 0x64, 0x68, 0x4b, 0x42, 0x67, 0x65, 0x50, 0x78,
+    0x4c, 0x63, 0x48, 0x73, 0x55, 0x30, 0x47, 0x0a, 0x44, 0x65, 0x47, 0x6c,
+    0x36, 0x2f, 0x52, 0x31, 0x79, 0x72, 0x71, 0x63, 0x30, 0x4c, 0x32, 0x7a,
+    0x30, 0x7a, 0x49, 0x6b, 0x54, 0x4f, 0x35, 0x2b, 0x34, 0x6e, 0x59, 0x45,
+    0x53, 0x30, 0x6c, 0x54, 0x32, 0x50, 0x4c, 0x70, 0x56, 0x44, 0x50, 0x38,
+    0x35, 0x58, 0x45, 0x66, 0x50, 0x52, 0x52, 0x63, 0x6c, 0x6b, 0x76, 0x78,
+    0x4f, 0x76, 0x49, 0x41, 0x75, 0x32, 0x79, 0x30, 0x2b, 0x70, 0x5a, 0x56,
+    0x0a, 0x43, 0x49, 0x67, 0x4a, 0x77, 0x63, 0x79, 0x52, 0x47, 0x53, 0x6d,
+    0x77, 0x49, 0x43, 0x33, 0x2f, 0x79, 0x7a, 0x69, 0x6b, 0x51, 0x4f, 0x45,
+    0x58, 0x76, 0x6e, 0x6c, 0x68, 0x67, 0x50, 0x38, 0x48, 0x41, 0x34, 0x5a,
+    0x4d, 0x54, 0x6e, 0x73, 0x47, 0x6e, 0x78, 0x47, 0x47, 0x6a, 0x59, 0x6e,
+    0x75, 0x4a, 0x38, 0x54, 0x62, 0x34, 0x72, 0x77, 0x5a, 0x6a, 0x67, 0x76,
+    0x44, 0x77, 0x78, 0x50, 0x48, 0x0a, 0x4c, 0x51, 0x4e, 0x6a, 0x4f, 0x39,
+    0x50, 0x6f, 0x35, 0x4b, 0x49, 0x71, 0x77, 0x6f, 0x49, 0x49, 0x6c, 0x42,
+    0x5a, 0x55, 0x38, 0x4f, 0x38, 0x66, 0x4a, 0x35, 0x41, 0x6c, 0x75, 0x41,
+    0x30, 0x4f, 0x4b, 0x42, 0x74, 0x48, 0x64, 0x30, 0x65, 0x39, 0x48, 0x4b,
+    0x67, 0x6c, 0x38, 0x5a, 0x53, 0x30, 0x5a, 0x67, 0x3d, 0x3d, 0x0a, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54,
+    0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20,
+    0x43, 0x4e, 0x3d, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20,
+    0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+    0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+    0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x47, 0x6f,
+    0x44, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49,
+    0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63,
+    0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64,
+    0x64, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
+    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f,
+    0x3d, 0x47, 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
+    0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62,
+    0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64,
+    0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+    0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+    0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x22, 0x0a, 0x23,
+    0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x30, 0x0a, 0x23,
+    0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x30, 0x3a, 0x33, 0x61, 0x3a,
+    0x62, 0x63, 0x3a, 0x32, 0x32, 0x3a, 0x63, 0x31, 0x3a, 0x65, 0x36, 0x3a,
+    0x66, 0x62, 0x3a, 0x38, 0x64, 0x3a, 0x39, 0x62, 0x3a, 0x33, 0x62, 0x3a,
+    0x32, 0x37, 0x3a, 0x34, 0x61, 0x3a, 0x33, 0x32, 0x3a, 0x31, 0x62, 0x3a,
+    0x39, 0x61, 0x3a, 0x30, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31,
+    0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x3a, 0x20, 0x34, 0x37, 0x3a, 0x62, 0x65, 0x3a, 0x61, 0x62, 0x3a, 0x63,
+    0x39, 0x3a, 0x32, 0x32, 0x3a, 0x65, 0x61, 0x3a, 0x65, 0x38, 0x3a, 0x30,
+    0x65, 0x3a, 0x37, 0x38, 0x3a, 0x37, 0x38, 0x3a, 0x33, 0x34, 0x3a, 0x36,
+    0x32, 0x3a, 0x61, 0x37, 0x3a, 0x39, 0x66, 0x3a, 0x34, 0x35, 0x3a, 0x63,
+    0x32, 0x3a, 0x35, 0x34, 0x3a, 0x66, 0x64, 0x3a, 0x65, 0x36, 0x3a, 0x38,
+    0x62, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x34, 0x35, 0x3a, 0x31, 0x34, 0x3a, 0x30, 0x62, 0x3a, 0x33, 0x32, 0x3a,
+    0x34, 0x37, 0x3a, 0x65, 0x62, 0x3a, 0x39, 0x63, 0x3a, 0x63, 0x38, 0x3a,
+    0x63, 0x35, 0x3a, 0x62, 0x34, 0x3a, 0x66, 0x30, 0x3a, 0x64, 0x37, 0x3a,
+    0x62, 0x35, 0x3a, 0x33, 0x30, 0x3a, 0x39, 0x31, 0x3a, 0x66, 0x37, 0x3a,
+    0x33, 0x32, 0x3a, 0x39, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x39, 0x65, 0x3a,
+    0x36, 0x65, 0x3a, 0x35, 0x61, 0x3a, 0x36, 0x33, 0x3a, 0x65, 0x32, 0x3a,
+    0x37, 0x34, 0x3a, 0x39, 0x64, 0x3a, 0x64, 0x33, 0x3a, 0x61, 0x63, 0x3a,
+    0x61, 0x39, 0x3a, 0x31, 0x39, 0x3a, 0x38, 0x65, 0x3a, 0x64, 0x61, 0x0a,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x78, 0x54, 0x43, 0x43,
+    0x41, 0x71, 0x32, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42,
+    0x41, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47,
+    0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x43, 0x42,
+    0x67, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x0a, 0x45, 0x44, 0x41,
+    0x4f, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x54, 0x42, 0x30, 0x46,
+    0x79, 0x61, 0x58, 0x70, 0x76, 0x62, 0x6d, 0x45, 0x78, 0x45, 0x7a, 0x41,
+    0x52, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x43, 0x6c, 0x4e,
+    0x6a, 0x62, 0x33, 0x52, 0x30, 0x63, 0x32, 0x52, 0x68, 0x62, 0x47, 0x55,
+    0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f,
+    0x54, 0x0a, 0x45, 0x55, 0x64, 0x76, 0x52, 0x47, 0x46, 0x6b, 0x5a, 0x48,
+    0x6b, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d,
+    0x4d, 0x75, 0x4d, 0x54, 0x45, 0x77, 0x4c, 0x77, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x44, 0x45, 0x79, 0x68, 0x48, 0x62, 0x79, 0x42, 0x45, 0x59, 0x57,
+    0x52, 0x6b, 0x65, 0x53, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45,
+    0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x0a, 0x5a, 0x6d, 0x6c, 0x6a, 0x59,
+    0x58, 0x52, 0x6c, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63,
+    0x6d, 0x6c, 0x30, 0x65, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x79, 0x4d,
+    0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x35, 0x4d, 0x44, 0x6b, 0x77, 0x4d,
+    0x54, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44,
+    0x54, 0x4d, 0x33, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x7a, 0x0a,
+    0x4e, 0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x67, 0x59, 0x4d, 0x78,
+    0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54,
+    0x41, 0x6c, 0x56, 0x54, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44,
+    0x56, 0x51, 0x51, 0x49, 0x45, 0x77, 0x64, 0x42, 0x63, 0x6d, 0x6c, 0x36,
+    0x62, 0x32, 0x35, 0x68, 0x4d, 0x52, 0x4d, 0x77, 0x45, 0x51, 0x59, 0x44,
+    0x56, 0x51, 0x51, 0x48, 0x0a, 0x45, 0x77, 0x70, 0x54, 0x59, 0x32, 0x39,
+    0x30, 0x64, 0x48, 0x4e, 0x6b, 0x59, 0x57, 0x78, 0x6c, 0x4d, 0x52, 0x6f,
+    0x77, 0x47, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x46,
+    0x48, 0x62, 0x30, 0x52, 0x68, 0x5a, 0x47, 0x52, 0x35, 0x4c, 0x6d, 0x4e,
+    0x76, 0x62, 0x53, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45,
+    0x78, 0x4d, 0x43, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x41, 0x78,
+    0x4d, 0x6f, 0x52, 0x32, 0x38, 0x67, 0x52, 0x47, 0x46, 0x6b, 0x5a, 0x48,
+    0x6b, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x5a, 0x58,
+    0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, 0x53,
+    0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48,
+    0x6b, 0x67, 0x4c, 0x53, 0x42, 0x48, 0x4d, 0x6a, 0x43, 0x43, 0x41, 0x53,
+    0x49, 0x77, 0x0a, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68,
+    0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67,
+    0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67,
+    0x67, 0x45, 0x42, 0x41, 0x4c, 0x39, 0x78, 0x59, 0x67, 0x6a, 0x78, 0x2b,
+    0x6c, 0x6b, 0x30, 0x39, 0x78, 0x76, 0x4a, 0x47, 0x4b, 0x50, 0x33, 0x67,
+    0x45, 0x6c, 0x59, 0x36, 0x53, 0x4b, 0x44, 0x0a, 0x45, 0x36, 0x62, 0x46,
+    0x49, 0x45, 0x4d, 0x42, 0x4f, 0x34, 0x54, 0x78, 0x35, 0x6f, 0x56, 0x4a,
+    0x6e, 0x79, 0x66, 0x71, 0x39, 0x6f, 0x51, 0x62, 0x54, 0x71, 0x43, 0x30,
+    0x32, 0x33, 0x43, 0x59, 0x78, 0x7a, 0x49, 0x42, 0x73, 0x51, 0x55, 0x2b,
+    0x42, 0x30, 0x37, 0x75, 0x39, 0x50, 0x70, 0x50, 0x4c, 0x31, 0x6b, 0x77,
+    0x49, 0x75, 0x65, 0x72, 0x47, 0x56, 0x5a, 0x72, 0x34, 0x6f, 0x41, 0x48,
+    0x0a, 0x2f, 0x50, 0x4d, 0x57, 0x64, 0x59, 0x41, 0x35, 0x55, 0x58, 0x76,
+    0x6c, 0x2b, 0x54, 0x57, 0x32, 0x64, 0x45, 0x36, 0x70, 0x6a, 0x59, 0x49,
+    0x54, 0x35, 0x4c, 0x59, 0x2f, 0x71, 0x51, 0x4f, 0x44, 0x2b, 0x71, 0x4b,
+    0x2b, 0x69, 0x68, 0x56, 0x71, 0x66, 0x39, 0x34, 0x4c, 0x77, 0x37, 0x59,
+    0x5a, 0x46, 0x41, 0x58, 0x4b, 0x36, 0x73, 0x4f, 0x6f, 0x42, 0x4a, 0x51,
+    0x37, 0x52, 0x6e, 0x77, 0x79, 0x0a, 0x44, 0x66, 0x4d, 0x41, 0x5a, 0x69,
+    0x4c, 0x49, 0x6a, 0x57, 0x6c, 0x74, 0x4e, 0x6f, 0x77, 0x52, 0x47, 0x4c,
+    0x66, 0x54, 0x73, 0x68, 0x78, 0x67, 0x74, 0x44, 0x6a, 0x36, 0x41, 0x6f,
+    0x7a, 0x4f, 0x30, 0x39, 0x31, 0x47, 0x42, 0x39, 0x34, 0x4b, 0x50, 0x75,
+    0x74, 0x64, 0x66, 0x4d, 0x68, 0x38, 0x2b, 0x37, 0x41, 0x72, 0x55, 0x36,
+    0x53, 0x53, 0x59, 0x6d, 0x6c, 0x52, 0x4a, 0x51, 0x56, 0x68, 0x0a, 0x47,
+    0x6b, 0x53, 0x42, 0x6a, 0x43, 0x79, 0x70, 0x51, 0x35, 0x59, 0x6a, 0x33,
+    0x36, 0x77, 0x36, 0x67, 0x5a, 0x6f, 0x4f, 0x4b, 0x63, 0x55, 0x63, 0x71,
+    0x65, 0x6c, 0x64, 0x48, 0x72, 0x61, 0x65, 0x6e, 0x6a, 0x41, 0x4b, 0x4f,
+    0x63, 0x37, 0x78, 0x69, 0x49, 0x44, 0x37, 0x53, 0x31, 0x33, 0x4d, 0x4d,
+    0x75, 0x79, 0x46, 0x59, 0x6b, 0x4d, 0x6c, 0x4e, 0x41, 0x4a, 0x57, 0x4a,
+    0x77, 0x47, 0x52, 0x0a, 0x74, 0x44, 0x74, 0x77, 0x4b, 0x6a, 0x39, 0x75,
+    0x73, 0x65, 0x69, 0x63, 0x69, 0x41, 0x46, 0x39, 0x6e, 0x39, 0x54, 0x35,
+    0x32, 0x31, 0x4e, 0x74, 0x59, 0x4a, 0x32, 0x2f, 0x4c, 0x4f, 0x64, 0x59,
+    0x71, 0x37, 0x68, 0x66, 0x52, 0x76, 0x7a, 0x4f, 0x78, 0x42, 0x73, 0x44,
+    0x50, 0x41, 0x6e, 0x72, 0x53, 0x54, 0x46, 0x63, 0x61, 0x55, 0x61, 0x7a,
+    0x34, 0x45, 0x63, 0x43, 0x41, 0x77, 0x45, 0x41, 0x0a, 0x41, 0x61, 0x4e,
+    0x43, 0x4d, 0x45, 0x41, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30,
+    0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45,
+    0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38,
+    0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59,
+    0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59,
+    0x45, 0x0a, 0x46, 0x44, 0x71, 0x61, 0x68, 0x51, 0x63, 0x51, 0x5a, 0x79,
+    0x69, 0x32, 0x37, 0x2f, 0x61, 0x39, 0x42, 0x55, 0x46, 0x75, 0x49, 0x4d,
+    0x47, 0x55, 0x32, 0x67, 0x2f, 0x65, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53,
+    0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77,
+    0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x43, 0x5a, 0x32, 0x31,
+    0x31, 0x35, 0x31, 0x66, 0x6d, 0x58, 0x0a, 0x57, 0x57, 0x63, 0x44, 0x59,
+    0x66, 0x46, 0x2b, 0x4f, 0x77, 0x59, 0x78, 0x64, 0x53, 0x32, 0x68, 0x49,
+    0x49, 0x35, 0x50, 0x5a, 0x59, 0x65, 0x30, 0x39, 0x36, 0x61, 0x63, 0x76,
+    0x4e, 0x6a, 0x70, 0x4c, 0x39, 0x44, 0x62, 0x57, 0x75, 0x37, 0x50, 0x64,
+    0x49, 0x78, 0x7a, 0x74, 0x44, 0x68, 0x43, 0x32, 0x67, 0x56, 0x37, 0x2b,
+    0x41, 0x4a, 0x31, 0x75, 0x50, 0x32, 0x6c, 0x73, 0x64, 0x65, 0x75, 0x0a,
+    0x39, 0x74, 0x66, 0x65, 0x45, 0x38, 0x74, 0x54, 0x45, 0x48, 0x36, 0x4b,
+    0x52, 0x74, 0x47, 0x58, 0x2b, 0x72, 0x63, 0x75, 0x4b, 0x78, 0x47, 0x72,
+    0x6b, 0x4c, 0x41, 0x6e, 0x67, 0x50, 0x6e, 0x6f, 0x6e, 0x31, 0x72, 0x70,
+    0x4e, 0x35, 0x2b, 0x72, 0x35, 0x4e, 0x39, 0x73, 0x73, 0x34, 0x55, 0x58,
+    0x6e, 0x54, 0x33, 0x5a, 0x4a, 0x45, 0x39, 0x35, 0x6b, 0x54, 0x58, 0x57,
+    0x58, 0x77, 0x54, 0x72, 0x0a, 0x67, 0x49, 0x4f, 0x72, 0x6d, 0x67, 0x49,
+    0x74, 0x74, 0x52, 0x44, 0x30, 0x32, 0x4a, 0x44, 0x48, 0x42, 0x48, 0x4e,
+    0x41, 0x37, 0x58, 0x49, 0x6c, 0x6f, 0x4b, 0x6d, 0x66, 0x37, 0x4a, 0x36,
+    0x72, 0x61, 0x42, 0x4b, 0x5a, 0x56, 0x38, 0x61, 0x50, 0x45, 0x6a, 0x6f,
+    0x4a, 0x70, 0x4c, 0x31, 0x45, 0x2f, 0x51, 0x59, 0x56, 0x4e, 0x38, 0x47,
+    0x62, 0x35, 0x44, 0x4b, 0x6a, 0x37, 0x54, 0x6a, 0x6f, 0x0a, 0x32, 0x47,
+    0x54, 0x7a, 0x4c, 0x48, 0x34, 0x55, 0x2f, 0x41, 0x4c, 0x71, 0x6e, 0x38,
+    0x33, 0x2f, 0x42, 0x32, 0x67, 0x58, 0x32, 0x79, 0x4b, 0x51, 0x4f, 0x43,
+    0x31, 0x36, 0x6a, 0x64, 0x46, 0x55, 0x38, 0x57, 0x6e, 0x6a, 0x58, 0x7a,
+    0x50, 0x4b, 0x65, 0x6a, 0x31, 0x37, 0x43, 0x75, 0x50, 0x4b, 0x66, 0x31,
+    0x38, 0x35, 0x35, 0x65, 0x4a, 0x31, 0x75, 0x73, 0x56, 0x32, 0x47, 0x44,
+    0x50, 0x4f, 0x0a, 0x4c, 0x50, 0x41, 0x76, 0x54, 0x4b, 0x33, 0x33, 0x73,
+    0x65, 0x66, 0x4f, 0x54, 0x36, 0x6a, 0x45, 0x6d, 0x30, 0x70, 0x55, 0x42,
+    0x73, 0x56, 0x2f, 0x66, 0x64, 0x55, 0x49, 0x44, 0x2b, 0x49, 0x63, 0x2f,
+    0x6e, 0x34, 0x58, 0x75, 0x4b, 0x78, 0x65, 0x39, 0x74, 0x51, 0x57, 0x73,
+    0x6b, 0x4d, 0x4a, 0x44, 0x45, 0x33, 0x32, 0x70, 0x32, 0x75, 0x30, 0x6d,
+    0x59, 0x52, 0x6c, 0x79, 0x6e, 0x71, 0x49, 0x0a, 0x34, 0x75, 0x4a, 0x45,
+    0x76, 0x6c, 0x7a, 0x33, 0x36, 0x68, 0x7a, 0x31, 0x0a, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a,
+    0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x52,
+    0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+    0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+    0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x53, 0x74, 0x61,
+    0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e,
+    0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63,
+    0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a,
+    0x20, 0x43, 0x4e, 0x3d, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c,
+    0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+    0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+    0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d,
+    0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65,
+    0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20,
+    0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c,
+    0x3a, 0x20, 0x22, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64,
+    0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+    0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+    0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x22, 0x0a, 0x23, 0x20,
+    0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x30, 0x0a, 0x23, 0x20,
+    0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x36, 0x3a, 0x33, 0x39, 0x3a, 0x38,
+    0x31, 0x3a, 0x63, 0x36, 0x3a, 0x35, 0x32, 0x3a, 0x37, 0x65, 0x3a, 0x39,
+    0x36, 0x3a, 0x36, 0x39, 0x3a, 0x66, 0x63, 0x3a, 0x66, 0x63, 0x3a, 0x63,
+    0x61, 0x3a, 0x36, 0x36, 0x3a, 0x65, 0x64, 0x3a, 0x30, 0x35, 0x3a, 0x66,
+    0x32, 0x3a, 0x39, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x62, 0x35, 0x3a, 0x31, 0x63, 0x3a, 0x30, 0x36, 0x3a, 0x37, 0x63,
+    0x3a, 0x65, 0x65, 0x3a, 0x32, 0x62, 0x3a, 0x30, 0x63, 0x3a, 0x33, 0x64,
+    0x3a, 0x66, 0x38, 0x3a, 0x35, 0x35, 0x3a, 0x61, 0x62, 0x3a, 0x32, 0x64,
+    0x3a, 0x39, 0x32, 0x3a, 0x66, 0x34, 0x3a, 0x66, 0x65, 0x3a, 0x33, 0x39,
+    0x3a, 0x64, 0x34, 0x3a, 0x65, 0x37, 0x3a, 0x30, 0x66, 0x3a, 0x30, 0x65,
+    0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69,
+    0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32,
+    0x63, 0x3a, 0x65, 0x31, 0x3a, 0x63, 0x62, 0x3a, 0x30, 0x62, 0x3a, 0x66,
+    0x39, 0x3a, 0x64, 0x32, 0x3a, 0x66, 0x39, 0x3a, 0x65, 0x31, 0x3a, 0x30,
+    0x32, 0x3a, 0x39, 0x39, 0x3a, 0x33, 0x66, 0x3a, 0x62, 0x65, 0x3a, 0x32,
+    0x31, 0x3a, 0x35, 0x31, 0x3a, 0x35, 0x32, 0x3a, 0x63, 0x33, 0x3a, 0x62,
+    0x32, 0x3a, 0x64, 0x64, 0x3a, 0x30, 0x63, 0x3a, 0x61, 0x62, 0x3a, 0x64,
+    0x65, 0x3a, 0x31, 0x63, 0x3a, 0x36, 0x38, 0x3a, 0x65, 0x35, 0x3a, 0x33,
+    0x31, 0x3a, 0x39, 0x62, 0x3a, 0x38, 0x33, 0x3a, 0x39, 0x31, 0x3a, 0x35,
+    0x34, 0x3a, 0x64, 0x62, 0x3a, 0x62, 0x37, 0x3a, 0x66, 0x35, 0x0a, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45,
+    0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x33, 0x54, 0x43, 0x43, 0x41,
+    0x73, 0x57, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41,
+    0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39,
+    0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x43, 0x42, 0x6a,
+    0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42,
+    0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x0a, 0x45, 0x44, 0x41, 0x4f,
+    0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x54, 0x42, 0x30, 0x46, 0x79,
+    0x61, 0x58, 0x70, 0x76, 0x62, 0x6d, 0x45, 0x78, 0x45, 0x7a, 0x41, 0x52,
+    0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x43, 0x6c, 0x4e, 0x6a,
+    0x62, 0x33, 0x52, 0x30, 0x63, 0x32, 0x52, 0x68, 0x62, 0x47, 0x55, 0x78,
+    0x4a, 0x54, 0x41, 0x6a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54,
+    0x0a, 0x48, 0x46, 0x4e, 0x30, 0x59, 0x58, 0x4a, 0x6d, 0x61, 0x57, 0x56,
+    0x73, 0x5a, 0x43, 0x42, 0x55, 0x5a, 0x57, 0x4e, 0x6f, 0x62, 0x6d, 0x39,
+    0x73, 0x62, 0x32, 0x64, 0x70, 0x5a, 0x58, 0x4d, 0x73, 0x49, 0x45, 0x6c,
+    0x75, 0x59, 0x79, 0x34, 0x78, 0x4d, 0x6a, 0x41, 0x77, 0x42, 0x67, 0x4e,
+    0x56, 0x42, 0x41, 0x4d, 0x54, 0x4b, 0x56, 0x4e, 0x30, 0x59, 0x58, 0x4a,
+    0x6d, 0x61, 0x57, 0x56, 0x73, 0x0a, 0x5a, 0x43, 0x42, 0x53, 0x62, 0x32,
+    0x39, 0x30, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d,
+    0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47,
+    0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x53, 0x41, 0x74, 0x49, 0x45,
+    0x63, 0x79, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x35, 0x4d, 0x44,
+    0x6b, 0x77, 0x4d, 0x54, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x0a, 0x4d,
+    0x46, 0x6f, 0x58, 0x44, 0x54, 0x4d, 0x33, 0x4d, 0x54, 0x49, 0x7a, 0x4d,
+    0x54, 0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x67,
+    0x59, 0x38, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x52, 0x41, 0x77, 0x44,
+    0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, 0x45, 0x77, 0x64, 0x42, 0x63,
+    0x6d, 0x6c, 0x36, 0x0a, 0x62, 0x32, 0x35, 0x68, 0x4d, 0x52, 0x4d, 0x77,
+    0x45, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x45, 0x77, 0x70, 0x54,
+    0x59, 0x32, 0x39, 0x30, 0x64, 0x48, 0x4e, 0x6b, 0x59, 0x57, 0x78, 0x6c,
+    0x4d, 0x53, 0x55, 0x77, 0x49, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b,
+    0x45, 0x78, 0x78, 0x54, 0x64, 0x47, 0x46, 0x79, 0x5a, 0x6d, 0x6c, 0x6c,
+    0x62, 0x47, 0x51, 0x67, 0x56, 0x47, 0x56, 0x6a, 0x0a, 0x61, 0x47, 0x35,
+    0x76, 0x62, 0x47, 0x39, 0x6e, 0x61, 0x57, 0x56, 0x7a, 0x4c, 0x43, 0x42,
+    0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x54, 0x49, 0x77, 0x4d, 0x41, 0x59,
+    0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x79, 0x6c, 0x54, 0x64, 0x47, 0x46,
+    0x79, 0x5a, 0x6d, 0x6c, 0x6c, 0x62, 0x47, 0x51, 0x67, 0x55, 0x6d, 0x39,
+    0x76, 0x64, 0x43, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a,
+    0x70, 0x0a, 0x59, 0x32, 0x46, 0x30, 0x5a, 0x53, 0x42, 0x42, 0x64, 0x58,
+    0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x4c, 0x53,
+    0x42, 0x48, 0x4d, 0x6a, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51,
+    0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51,
+    0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44,
+    0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x0a, 0x67, 0x67, 0x45, 0x42, 0x41,
+    0x4c, 0x33, 0x74, 0x77, 0x51, 0x50, 0x38, 0x39, 0x6f, 0x2f, 0x38, 0x41,
+    0x72, 0x46, 0x76, 0x57, 0x35, 0x39, 0x49, 0x32, 0x5a, 0x31, 0x35, 0x34,
+    0x71, 0x4b, 0x33, 0x41, 0x32, 0x46, 0x57, 0x47, 0x4d, 0x4e, 0x48, 0x74,
+    0x74, 0x66, 0x4b, 0x50, 0x54, 0x55, 0x75, 0x69, 0x55, 0x50, 0x33, 0x6f,
+    0x57, 0x6d, 0x62, 0x33, 0x6f, 0x6f, 0x61, 0x2f, 0x52, 0x4d, 0x67, 0x0a,
+    0x6e, 0x4c, 0x52, 0x4a, 0x64, 0x7a, 0x49, 0x70, 0x56, 0x76, 0x32, 0x35,
+    0x37, 0x49, 0x7a, 0x64, 0x49, 0x76, 0x70, 0x79, 0x33, 0x43, 0x64, 0x68,
+    0x6c, 0x2b, 0x37, 0x32, 0x57, 0x6f, 0x54, 0x73, 0x62, 0x68, 0x6d, 0x35,
+    0x69, 0x53, 0x7a, 0x63, 0x68, 0x46, 0x76, 0x56, 0x64, 0x50, 0x74, 0x72,
+    0x58, 0x38, 0x57, 0x4a, 0x70, 0x52, 0x42, 0x53, 0x69, 0x55, 0x5a, 0x56,
+    0x39, 0x4c, 0x68, 0x31, 0x0a, 0x48, 0x4f, 0x5a, 0x2f, 0x35, 0x46, 0x53,
+    0x75, 0x53, 0x2f, 0x68, 0x56, 0x63, 0x6c, 0x63, 0x43, 0x47, 0x66, 0x67,
+    0x58, 0x63, 0x56, 0x6e, 0x72, 0x48, 0x69, 0x67, 0x48, 0x64, 0x4d, 0x57,
+    0x64, 0x53, 0x4c, 0x35, 0x73, 0x74, 0x50, 0x53, 0x6b, 0x73, 0x50, 0x4e,
+    0x6b, 0x4e, 0x33, 0x6d, 0x53, 0x77, 0x4f, 0x78, 0x47, 0x58, 0x6e, 0x2f,
+    0x68, 0x62, 0x56, 0x4e, 0x4d, 0x59, 0x71, 0x2f, 0x4e, 0x0a, 0x48, 0x77,
+    0x74, 0x6a, 0x75, 0x7a, 0x71, 0x64, 0x2b, 0x2f, 0x78, 0x35, 0x41, 0x4a,
+    0x68, 0x68, 0x64, 0x4d, 0x38, 0x6d, 0x67, 0x6b, 0x42, 0x6a, 0x38, 0x37,
+    0x4a, 0x79, 0x61, 0x68, 0x6b, 0x4e, 0x6d, 0x63, 0x72, 0x55, 0x44, 0x6e,
+    0x58, 0x4d, 0x4e, 0x2f, 0x75, 0x4c, 0x69, 0x63, 0x46, 0x5a, 0x38, 0x57,
+    0x4a, 0x2f, 0x58, 0x37, 0x4e, 0x66, 0x5a, 0x54, 0x44, 0x34, 0x70, 0x37,
+    0x64, 0x4e, 0x0a, 0x64, 0x6c, 0x6f, 0x65, 0x64, 0x6c, 0x34, 0x30, 0x77,
+    0x4f, 0x69, 0x57, 0x56, 0x70, 0x6d, 0x4b, 0x73, 0x2f, 0x42, 0x2f, 0x70,
+    0x4d, 0x32, 0x39, 0x33, 0x44, 0x49, 0x78, 0x66, 0x4a, 0x48, 0x50, 0x34,
+    0x46, 0x38, 0x52, 0x2b, 0x47, 0x75, 0x71, 0x53, 0x56, 0x7a, 0x52, 0x6d,
+    0x5a, 0x54, 0x52, 0x6f, 0x75, 0x4e, 0x6a, 0x57, 0x77, 0x6c, 0x32, 0x74,
+    0x56, 0x5a, 0x69, 0x34, 0x55, 0x74, 0x30, 0x0a, 0x48, 0x5a, 0x62, 0x55,
+    0x4a, 0x74, 0x51, 0x49, 0x42, 0x46, 0x6e, 0x51, 0x6d, 0x41, 0x34, 0x4f,
+    0x35, 0x74, 0x37, 0x38, 0x77, 0x2b, 0x77, 0x66, 0x6b, 0x50, 0x45, 0x43,
+    0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77,
+    0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f,
+    0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f,
+    0x0a, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38,
+    0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x48, 0x51, 0x59,
+    0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x48, 0x77,
+    0x4d, 0x4d, 0x68, 0x2b, 0x6e, 0x32, 0x54, 0x42, 0x2f, 0x78, 0x48, 0x31,
+    0x6f, 0x6f, 0x32, 0x4b, 0x6f, 0x6f, 0x63, 0x36, 0x72, 0x42, 0x31, 0x73,
+    0x6e, 0x4d, 0x41, 0x30, 0x47, 0x0a, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49,
+    0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, 0x34,
+    0x49, 0x42, 0x41, 0x51, 0x41, 0x52, 0x57, 0x66, 0x6f, 0x6c, 0x54, 0x77,
+    0x4e, 0x76, 0x6c, 0x4a, 0x6b, 0x37, 0x6d, 0x68, 0x2b, 0x43, 0x68, 0x54,
+    0x6e, 0x55, 0x64, 0x67, 0x57, 0x55, 0x58, 0x75, 0x45, 0x6f, 0x6b, 0x32,
+    0x31, 0x69, 0x58, 0x51, 0x6e, 0x43, 0x6f, 0x4b, 0x6a, 0x55, 0x0a, 0x73,
+    0x48, 0x55, 0x34, 0x38, 0x54, 0x52, 0x71, 0x6e, 0x65, 0x53, 0x66, 0x69,
+    0x6f, 0x59, 0x6d, 0x55, 0x65, 0x59, 0x73, 0x30, 0x63, 0x59, 0x74, 0x62,
+    0x70, 0x55, 0x67, 0x53, 0x70, 0x49, 0x42, 0x37, 0x4c, 0x69, 0x4b, 0x5a,
+    0x33, 0x73, 0x78, 0x34, 0x6d, 0x63, 0x75, 0x6a, 0x4a, 0x55, 0x44, 0x4a,
+    0x69, 0x35, 0x44, 0x6e, 0x55, 0x6f, 0x78, 0x39, 0x67, 0x36, 0x31, 0x44,
+    0x4c, 0x75, 0x33, 0x0a, 0x34, 0x6a, 0x64, 0x2f, 0x49, 0x72, 0x6f, 0x41,
+    0x6f, 0x77, 0x35, 0x37, 0x55, 0x76, 0x74, 0x72, 0x75, 0x7a, 0x76, 0x45,
+    0x30, 0x33, 0x6c, 0x52, 0x54, 0x73, 0x32, 0x51, 0x39, 0x47, 0x63, 0x48,
+    0x47, 0x63, 0x67, 0x38, 0x52, 0x6e, 0x6f, 0x4e, 0x41, 0x58, 0x33, 0x46,
+    0x57, 0x4f, 0x64, 0x74, 0x35, 0x6f, 0x55, 0x77, 0x46, 0x35, 0x6f, 0x6b,
+    0x78, 0x42, 0x44, 0x67, 0x42, 0x50, 0x66, 0x67, 0x0a, 0x38, 0x6e, 0x2f,
+    0x55, 0x71, 0x67, 0x72, 0x2f, 0x51, 0x68, 0x30, 0x33, 0x37, 0x5a, 0x54,
+    0x6c, 0x5a, 0x46, 0x6b, 0x53, 0x49, 0x48, 0x63, 0x34, 0x30, 0x7a, 0x49,
+    0x2b, 0x4f, 0x49, 0x46, 0x31, 0x6c, 0x6e, 0x50, 0x36, 0x61, 0x49, 0x2b,
+    0x78, 0x79, 0x38, 0x34, 0x66, 0x78, 0x65, 0x7a, 0x36, 0x6e, 0x48, 0x37,
+    0x50, 0x66, 0x72, 0x48, 0x78, 0x42, 0x79, 0x32, 0x32, 0x2f, 0x4c, 0x2f,
+    0x4b, 0x0a, 0x70, 0x4c, 0x2f, 0x51, 0x6c, 0x77, 0x56, 0x4b, 0x76, 0x4f,
+    0x6f, 0x59, 0x4b, 0x41, 0x4b, 0x51, 0x76, 0x56, 0x52, 0x34, 0x43, 0x53,
+    0x46, 0x78, 0x30, 0x39, 0x46, 0x39, 0x48, 0x64, 0x6b, 0x57, 0x73, 0x4b,
+    0x6c, 0x68, 0x50, 0x64, 0x41, 0x4b, 0x41, 0x43, 0x4c, 0x38, 0x78, 0x33,
+    0x76, 0x4c, 0x43, 0x57, 0x52, 0x46, 0x43, 0x7a, 0x74, 0x41, 0x67, 0x66,
+    0x64, 0x39, 0x66, 0x44, 0x4c, 0x31, 0x0a, 0x6d, 0x4d, 0x70, 0x59, 0x6a,
+    0x6e, 0x30, 0x71, 0x37, 0x70, 0x42, 0x5a, 0x63, 0x32, 0x54, 0x35, 0x4e,
+    0x6e, 0x52, 0x65, 0x4a, 0x61, 0x48, 0x31, 0x5a, 0x67, 0x55, 0x75, 0x66,
+    0x7a, 0x6b, 0x56, 0x71, 0x53, 0x72, 0x37, 0x55, 0x49, 0x75, 0x4f, 0x68,
+    0x57, 0x6e, 0x30, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73,
+    0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x74, 0x61, 0x72,
+    0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
+    0x65, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
+    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f,
+    0x3d, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54,
+    0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c,
+    0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a,
+    0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x74, 0x61, 0x72,
+    0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
+    0x65, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
+    0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f,
+    0x3d, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54,
+    0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c,
+    0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65,
+    0x6c, 0x3a, 0x20, 0x22, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c,
+    0x64, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x52,
+    0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+    0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+    0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65,
+    0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44,
+    0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x31, 0x37, 0x3a, 0x33, 0x35, 0x3a, 0x37, 0x34, 0x3a,
+    0x61, 0x66, 0x3a, 0x37, 0x62, 0x3a, 0x36, 0x31, 0x3a, 0x31, 0x63, 0x3a,
+    0x65, 0x62, 0x3a, 0x66, 0x34, 0x3a, 0x66, 0x39, 0x3a, 0x33, 0x63, 0x3a,
+    0x65, 0x32, 0x3a, 0x65, 0x65, 0x3a, 0x34, 0x30, 0x3a, 0x66, 0x39, 0x3a,
+    0x61, 0x32, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69,
+    0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39,
+    0x32, 0x3a, 0x35, 0x61, 0x3a, 0x38, 0x66, 0x3a, 0x38, 0x64, 0x3a, 0x32,
+    0x63, 0x3a, 0x36, 0x64, 0x3a, 0x30, 0x34, 0x3a, 0x65, 0x30, 0x3a, 0x36,
+    0x36, 0x3a, 0x35, 0x66, 0x3a, 0x35, 0x39, 0x3a, 0x36, 0x61, 0x3a, 0x66,
+    0x66, 0x3a, 0x32, 0x32, 0x3a, 0x64, 0x38, 0x3a, 0x36, 0x33, 0x3a, 0x65,
+    0x38, 0x3a, 0x32, 0x35, 0x3a, 0x36, 0x66, 0x3a, 0x33, 0x66, 0x0a, 0x23,
+    0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x36, 0x3a,
+    0x38, 0x64, 0x3a, 0x36, 0x39, 0x3a, 0x30, 0x35, 0x3a, 0x61, 0x32, 0x3a,
+    0x63, 0x38, 0x3a, 0x38, 0x37, 0x3a, 0x30, 0x38, 0x3a, 0x61, 0x34, 0x3a,
+    0x62, 0x33, 0x3a, 0x30, 0x32, 0x3a, 0x35, 0x31, 0x3a, 0x39, 0x30, 0x3a,
+    0x65, 0x64, 0x3a, 0x63, 0x66, 0x3a, 0x65, 0x64, 0x3a, 0x62, 0x31, 0x3a,
+    0x39, 0x37, 0x3a, 0x34, 0x61, 0x3a, 0x36, 0x30, 0x3a, 0x36, 0x61, 0x3a,
+    0x31, 0x33, 0x3a, 0x63, 0x36, 0x3a, 0x65, 0x35, 0x3a, 0x32, 0x39, 0x3a,
+    0x30, 0x66, 0x3a, 0x63, 0x62, 0x3a, 0x32, 0x61, 0x3a, 0x65, 0x36, 0x3a,
+    0x33, 0x65, 0x3a, 0x64, 0x61, 0x3a, 0x62, 0x35, 0x0a, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54,
+    0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x0a, 0x4d, 0x49, 0x49, 0x44, 0x37, 0x7a, 0x43, 0x43, 0x41, 0x74, 0x65,
+    0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x44, 0x41,
+    0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30,
+    0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x43, 0x42, 0x6d, 0x44, 0x45,
+    0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d,
+    0x43, 0x56, 0x56, 0x4d, 0x78, 0x0a, 0x45, 0x44, 0x41, 0x4f, 0x42, 0x67,
+    0x4e, 0x56, 0x42, 0x41, 0x67, 0x54, 0x42, 0x30, 0x46, 0x79, 0x61, 0x58,
+    0x70, 0x76, 0x62, 0x6d, 0x45, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67,
+    0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x43, 0x6c, 0x4e, 0x6a, 0x62, 0x33,
+    0x52, 0x30, 0x63, 0x32, 0x52, 0x68, 0x62, 0x47, 0x55, 0x78, 0x4a, 0x54,
+    0x41, 0x6a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x0a, 0x48,
+    0x46, 0x4e, 0x30, 0x59, 0x58, 0x4a, 0x6d, 0x61, 0x57, 0x56, 0x73, 0x5a,
+    0x43, 0x42, 0x55, 0x5a, 0x57, 0x4e, 0x6f, 0x62, 0x6d, 0x39, 0x73, 0x62,
+    0x32, 0x64, 0x70, 0x5a, 0x58, 0x4d, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59,
+    0x79, 0x34, 0x78, 0x4f, 0x7a, 0x41, 0x35, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x4d, 0x54, 0x4d, 0x6c, 0x4e, 0x30, 0x59, 0x58, 0x4a, 0x6d, 0x61,
+    0x57, 0x56, 0x73, 0x0a, 0x5a, 0x43, 0x42, 0x54, 0x5a, 0x58, 0x4a, 0x32,
+    0x61, 0x57, 0x4e, 0x6c, 0x63, 0x79, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30,
+    0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a,
+    0x59, 0x58, 0x52, 0x6c, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76,
+    0x63, 0x6d, 0x6c, 0x30, 0x65, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x79,
+    0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x35, 0x0a, 0x4d, 0x44, 0x6b,
+    0x77, 0x4d, 0x54, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f,
+    0x58, 0x44, 0x54, 0x4d, 0x33, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x49,
+    0x7a, 0x4e, 0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x67, 0x5a, 0x67,
+    0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59,
+    0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59,
+    0x44, 0x0a, 0x56, 0x51, 0x51, 0x49, 0x45, 0x77, 0x64, 0x42, 0x63, 0x6d,
+    0x6c, 0x36, 0x62, 0x32, 0x35, 0x68, 0x4d, 0x52, 0x4d, 0x77, 0x45, 0x51,
+    0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x45, 0x77, 0x70, 0x54, 0x59, 0x32,
+    0x39, 0x30, 0x64, 0x48, 0x4e, 0x6b, 0x59, 0x57, 0x78, 0x6c, 0x4d, 0x53,
+    0x55, 0x77, 0x49, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78,
+    0x78, 0x54, 0x64, 0x47, 0x46, 0x79, 0x0a, 0x5a, 0x6d, 0x6c, 0x6c, 0x62,
+    0x47, 0x51, 0x67, 0x56, 0x47, 0x56, 0x6a, 0x61, 0x47, 0x35, 0x76, 0x62,
+    0x47, 0x39, 0x6e, 0x61, 0x57, 0x56, 0x7a, 0x4c, 0x43, 0x42, 0x4a, 0x62,
+    0x6d, 0x4d, 0x75, 0x4d, 0x54, 0x73, 0x77, 0x4f, 0x51, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x44, 0x45, 0x7a, 0x4a, 0x54, 0x64, 0x47, 0x46, 0x79, 0x5a,
+    0x6d, 0x6c, 0x6c, 0x62, 0x47, 0x51, 0x67, 0x55, 0x32, 0x56, 0x79, 0x0a,
+    0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d, 0x67, 0x55, 0x6d, 0x39, 0x76,
+    0x64, 0x43, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70,
+    0x59, 0x32, 0x46, 0x30, 0x5a, 0x53, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f,
+    0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x4c, 0x53, 0x42, 0x48,
+    0x4d, 0x6a, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a,
+    0x4b, 0x6f, 0x5a, 0x49, 0x0a, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45,
+    0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43,
+    0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4e, 0x55,
+    0x4d, 0x4f, 0x73, 0x51, 0x71, 0x2b, 0x55, 0x37, 0x69, 0x39, 0x62, 0x34,
+    0x5a, 0x6c, 0x31, 0x2b, 0x4f, 0x69, 0x46, 0x4f, 0x78, 0x48, 0x7a, 0x2f,
+    0x4c, 0x7a, 0x35, 0x38, 0x67, 0x45, 0x32, 0x30, 0x70, 0x0a, 0x4f, 0x73,
+    0x67, 0x50, 0x66, 0x54, 0x7a, 0x33, 0x61, 0x33, 0x59, 0x34, 0x59, 0x39,
+    0x6b, 0x32, 0x59, 0x4b, 0x69, 0x62, 0x58, 0x6c, 0x77, 0x41, 0x67, 0x4c,
+    0x49, 0x76, 0x57, 0x58, 0x2f, 0x32, 0x68, 0x2f, 0x6b, 0x6c, 0x51, 0x34,
+    0x62, 0x6e, 0x61, 0x52, 0x74, 0x53, 0x6d, 0x70, 0x44, 0x68, 0x63, 0x65,
+    0x50, 0x59, 0x4c, 0x51, 0x31, 0x4f, 0x62, 0x2f, 0x62, 0x49, 0x53, 0x64,
+    0x6d, 0x32, 0x0a, 0x38, 0x78, 0x70, 0x57, 0x72, 0x69, 0x75, 0x32, 0x64,
+    0x42, 0x54, 0x72, 0x7a, 0x2f, 0x73, 0x6d, 0x34, 0x78, 0x71, 0x36, 0x48,
+    0x5a, 0x59, 0x75, 0x61, 0x6a, 0x74, 0x59, 0x6c, 0x49, 0x6c, 0x48, 0x56,
+    0x76, 0x38, 0x6c, 0x6f, 0x4a, 0x4e, 0x77, 0x55, 0x34, 0x50, 0x61, 0x68,
+    0x48, 0x51, 0x55, 0x77, 0x32, 0x65, 0x65, 0x42, 0x47, 0x67, 0x36, 0x33,
+    0x34, 0x35, 0x41, 0x57, 0x68, 0x31, 0x4b, 0x0a, 0x54, 0x73, 0x39, 0x44,
+    0x6b, 0x54, 0x76, 0x6e, 0x56, 0x74, 0x59, 0x41, 0x63, 0x4d, 0x74, 0x53,
+    0x37, 0x6e, 0x74, 0x39, 0x72, 0x6a, 0x72, 0x6e, 0x76, 0x44, 0x48, 0x35,
+    0x52, 0x66, 0x62, 0x43, 0x59, 0x4d, 0x38, 0x54, 0x57, 0x51, 0x49, 0x72,
+    0x67, 0x4d, 0x77, 0x30, 0x52, 0x39, 0x2b, 0x35, 0x33, 0x70, 0x42, 0x6c,
+    0x62, 0x51, 0x4c, 0x50, 0x4c, 0x4a, 0x47, 0x6d, 0x70, 0x75, 0x66, 0x65,
+    0x0a, 0x68, 0x52, 0x68, 0x4a, 0x66, 0x47, 0x5a, 0x4f, 0x6f, 0x7a, 0x70,
+    0x74, 0x71, 0x62, 0x58, 0x75, 0x4e, 0x43, 0x36, 0x36, 0x44, 0x51, 0x4f,
+    0x34, 0x4d, 0x39, 0x39, 0x48, 0x36, 0x37, 0x46, 0x72, 0x6a, 0x53, 0x58,
+    0x5a, 0x6d, 0x38, 0x36, 0x42, 0x30, 0x55, 0x56, 0x47, 0x4d, 0x70, 0x5a,
+    0x77, 0x68, 0x39, 0x34, 0x43, 0x44, 0x6b, 0x6c, 0x44, 0x68, 0x62, 0x5a,
+    0x73, 0x63, 0x37, 0x74, 0x6b, 0x0a, 0x36, 0x6d, 0x46, 0x42, 0x72, 0x4d,
+    0x6e, 0x55, 0x56, 0x4e, 0x2b, 0x48, 0x4c, 0x38, 0x63, 0x69, 0x73, 0x69,
+    0x62, 0x4d, 0x6e, 0x31, 0x6c, 0x55, 0x61, 0x4a, 0x2f, 0x38, 0x76, 0x69,
+    0x6f, 0x76, 0x78, 0x46, 0x55, 0x63, 0x64, 0x55, 0x42, 0x67, 0x46, 0x34,
+    0x55, 0x43, 0x56, 0x54, 0x6d, 0x4c, 0x66, 0x77, 0x55, 0x43, 0x41, 0x77,
+    0x45, 0x41, 0x41, 0x61, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77, 0x0a, 0x44,
+    0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42,
+    0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x42,
+    0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42,
+    0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56,
+    0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4a, 0x78, 0x66, 0x41,
+    0x4e, 0x2b, 0x71, 0x0a, 0x41, 0x64, 0x63, 0x77, 0x4b, 0x7a, 0x69, 0x49,
+    0x6f, 0x72, 0x68, 0x74, 0x53, 0x70, 0x7a, 0x79, 0x45, 0x5a, 0x47, 0x44,
+    0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33,
+    0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42,
+    0x41, 0x51, 0x42, 0x4c, 0x4e, 0x71, 0x61, 0x45, 0x64, 0x32, 0x6e, 0x64,
+    0x4f, 0x78, 0x6d, 0x66, 0x5a, 0x79, 0x4d, 0x49, 0x0a, 0x62, 0x77, 0x35,
+    0x68, 0x79, 0x66, 0x32, 0x45, 0x33, 0x46, 0x2f, 0x59, 0x4e, 0x6f, 0x48,
+    0x4e, 0x32, 0x42, 0x74, 0x42, 0x4c, 0x5a, 0x39, 0x67, 0x33, 0x63, 0x63,
+    0x61, 0x61, 0x4e, 0x6e, 0x52, 0x62, 0x6f, 0x62, 0x68, 0x69, 0x43, 0x50,
+    0x50, 0x45, 0x39, 0x35, 0x44, 0x7a, 0x2b, 0x49, 0x30, 0x73, 0x77, 0x53,
+    0x64, 0x48, 0x79, 0x6e, 0x56, 0x76, 0x2f, 0x68, 0x65, 0x79, 0x4e, 0x58,
+    0x42, 0x0a, 0x76, 0x65, 0x36, 0x53, 0x62, 0x7a, 0x4a, 0x30, 0x38, 0x70,
+    0x47, 0x43, 0x4c, 0x37, 0x32, 0x43, 0x51, 0x6e, 0x71, 0x74, 0x4b, 0x72,
+    0x63, 0x67, 0x66, 0x55, 0x32, 0x38, 0x65, 0x6c, 0x55, 0x53, 0x77, 0x68,
+    0x58, 0x71, 0x76, 0x66, 0x64, 0x71, 0x6c, 0x53, 0x35, 0x73, 0x64, 0x4a,
+    0x2f, 0x50, 0x48, 0x4c, 0x54, 0x79, 0x78, 0x51, 0x47, 0x6a, 0x68, 0x64,
+    0x42, 0x79, 0x50, 0x71, 0x31, 0x7a, 0x0a, 0x71, 0x77, 0x75, 0x62, 0x64,
+    0x51, 0x78, 0x74, 0x52, 0x62, 0x65, 0x4f, 0x6c, 0x4b, 0x79, 0x57, 0x4e,
+    0x37, 0x57, 0x67, 0x30, 0x49, 0x38, 0x56, 0x52, 0x77, 0x37, 0x6a, 0x36,
+    0x49, 0x50, 0x64, 0x6a, 0x2f, 0x33, 0x76, 0x51, 0x51, 0x46, 0x33, 0x7a,
+    0x43, 0x65, 0x70, 0x59, 0x6f, 0x55, 0x7a, 0x38, 0x6a, 0x63, 0x49, 0x37,
+    0x33, 0x48, 0x50, 0x64, 0x77, 0x62, 0x65, 0x79, 0x42, 0x6b, 0x64, 0x0a,
+    0x69, 0x45, 0x44, 0x50, 0x66, 0x55, 0x59, 0x64, 0x2f, 0x78, 0x37, 0x48,
+    0x34, 0x63, 0x37, 0x2f, 0x49, 0x39, 0x76, 0x47, 0x2b, 0x6f, 0x31, 0x56,
+    0x54, 0x71, 0x6b, 0x43, 0x35, 0x30, 0x63, 0x52, 0x52, 0x6a, 0x37, 0x30,
+    0x2f, 0x62, 0x31, 0x37, 0x4b, 0x53, 0x61, 0x37, 0x71, 0x57, 0x46, 0x69,
+    0x4e, 0x79, 0x69, 0x32, 0x4c, 0x53, 0x72, 0x32, 0x45, 0x49, 0x5a, 0x6b,
+    0x79, 0x58, 0x43, 0x6e, 0x0a, 0x30, 0x71, 0x32, 0x33, 0x4b, 0x58, 0x42,
+    0x35, 0x36, 0x6a, 0x7a, 0x61, 0x59, 0x79, 0x57, 0x66, 0x2f, 0x57, 0x69,
+    0x33, 0x4d, 0x4f, 0x78, 0x77, 0x2b, 0x33, 0x57, 0x4b, 0x74, 0x32, 0x31,
+    0x67, 0x5a, 0x37, 0x49, 0x65, 0x79, 0x4c, 0x6e, 0x70, 0x32, 0x4b, 0x68,
+    0x76, 0x41, 0x6f, 0x74, 0x6e, 0x44, 0x55, 0x30, 0x6d, 0x56, 0x33, 0x48,
+    0x61, 0x49, 0x50, 0x7a, 0x42, 0x53, 0x6c, 0x43, 0x4e, 0x0a, 0x73, 0x53,
+    0x69, 0x36, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20,
+    0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75,
+    0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x66, 0x66, 0x69, 0x72,
+    0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65,
+    0x72, 0x63, 0x69, 0x61, 0x6c, 0x20, 0x4f, 0x3d, 0x41, 0x66, 0x66, 0x69,
+    0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x53, 0x75,
+    0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x66,
+    0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f,
+    0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c, 0x20, 0x4f, 0x3d, 0x41,
+    0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23,
+    0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, 0x66, 0x66,
+    0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f, 0x6d,
+    0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c, 0x22, 0x0a, 0x23, 0x20, 0x53,
+    0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x38, 0x36, 0x30, 0x38, 0x33,
+    0x35, 0x35, 0x39, 0x37, 0x37, 0x39, 0x36, 0x34, 0x31, 0x33, 0x38, 0x38,
+    0x37, 0x36, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x32,
+    0x3a, 0x39, 0x32, 0x3a, 0x62, 0x61, 0x3a, 0x35, 0x62, 0x3a, 0x65, 0x66,
+    0x3a, 0x63, 0x64, 0x3a, 0x38, 0x61, 0x3a, 0x36, 0x66, 0x3a, 0x61, 0x36,
+    0x3a, 0x33, 0x64, 0x3a, 0x35, 0x35, 0x3a, 0x66, 0x39, 0x3a, 0x38, 0x34,
+    0x3a, 0x66, 0x36, 0x3a, 0x64, 0x36, 0x3a, 0x62, 0x37, 0x0a, 0x23, 0x20,
+    0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x66, 0x39, 0x3a, 0x62, 0x35, 0x3a,
+    0x62, 0x36, 0x3a, 0x33, 0x32, 0x3a, 0x34, 0x35, 0x3a, 0x35, 0x66, 0x3a,
+    0x39, 0x63, 0x3a, 0x62, 0x65, 0x3a, 0x65, 0x63, 0x3a, 0x35, 0x37, 0x3a,
+    0x35, 0x66, 0x3a, 0x38, 0x30, 0x3a, 0x64, 0x63, 0x3a, 0x65, 0x39, 0x3a,
+    0x36, 0x65, 0x3a, 0x32, 0x63, 0x3a, 0x63, 0x37, 0x3a, 0x62, 0x32, 0x3a,
+    0x37, 0x38, 0x3a, 0x62, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32,
+    0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x30, 0x33, 0x3a, 0x37, 0x36, 0x3a, 0x61, 0x62,
+    0x3a, 0x31, 0x64, 0x3a, 0x35, 0x34, 0x3a, 0x63, 0x35, 0x3a, 0x66, 0x39,
+    0x3a, 0x38, 0x30, 0x3a, 0x33, 0x63, 0x3a, 0x65, 0x34, 0x3a, 0x62, 0x32,
+    0x3a, 0x65, 0x32, 0x3a, 0x30, 0x31, 0x3a, 0x61, 0x30, 0x3a, 0x65, 0x65,
+    0x3a, 0x37, 0x65, 0x3a, 0x65, 0x66, 0x3a, 0x37, 0x62, 0x3a, 0x35, 0x37,
+    0x3a, 0x62, 0x36, 0x3a, 0x33, 0x36, 0x3a, 0x65, 0x38, 0x3a, 0x61, 0x39,
+    0x3a, 0x33, 0x63, 0x3a, 0x39, 0x62, 0x3a, 0x38, 0x64, 0x3a, 0x34, 0x38,
+    0x3a, 0x36, 0x30, 0x3a, 0x63, 0x39, 0x3a, 0x36, 0x66, 0x3a, 0x35, 0x66,
+    0x3a, 0x61, 0x37, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47,
+    0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41,
+    0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44,
+    0x54, 0x44, 0x43, 0x43, 0x41, 0x6a, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42,
+    0x41, 0x67, 0x49, 0x49, 0x64, 0x33, 0x63, 0x47, 0x4a, 0x79, 0x61, 0x70,
+    0x73, 0x58, 0x77, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49,
+    0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x77,
+    0x52, 0x44, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x0a, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x44, 0x41,
+    0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x43, 0x30, 0x46,
+    0x6d, 0x5a, 0x6d, 0x6c, 0x79, 0x62, 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e,
+    0x30, 0x4d, 0x52, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51,
+    0x44, 0x44, 0x42, 0x5a, 0x42, 0x5a, 0x6d, 0x5a, 0x70, 0x63, 0x6d, 0x31,
+    0x55, 0x63, 0x6e, 0x56, 0x7a, 0x0a, 0x64, 0x43, 0x42, 0x44, 0x62, 0x32,
+    0x31, 0x74, 0x5a, 0x58, 0x4a, 0x6a, 0x61, 0x57, 0x46, 0x73, 0x4d, 0x42,
+    0x34, 0x58, 0x44, 0x54, 0x45, 0x77, 0x4d, 0x44, 0x45, 0x79, 0x4f, 0x54,
+    0x45, 0x30, 0x4d, 0x44, 0x59, 0x77, 0x4e, 0x6c, 0x6f, 0x58, 0x44, 0x54,
+    0x4d, 0x77, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x45, 0x30, 0x4d, 0x44,
+    0x59, 0x77, 0x4e, 0x6c, 0x6f, 0x77, 0x52, 0x44, 0x45, 0x4c, 0x0a, 0x4d,
+    0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56,
+    0x56, 0x4d, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42,
+    0x41, 0x6f, 0x4d, 0x43, 0x30, 0x46, 0x6d, 0x5a, 0x6d, 0x6c, 0x79, 0x62,
+    0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4d, 0x52, 0x38, 0x77, 0x48,
+    0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, 0x5a, 0x42, 0x5a,
+    0x6d, 0x5a, 0x70, 0x0a, 0x63, 0x6d, 0x31, 0x55, 0x63, 0x6e, 0x56, 0x7a,
+    0x64, 0x43, 0x42, 0x44, 0x62, 0x32, 0x31, 0x74, 0x5a, 0x58, 0x4a, 0x6a,
+    0x61, 0x57, 0x46, 0x73, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e,
+    0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42,
+    0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41,
+    0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x0a, 0x41, 0x51, 0x45,
+    0x41, 0x39, 0x68, 0x74, 0x50, 0x5a, 0x77, 0x63, 0x72, 0x6f, 0x52, 0x58,
+    0x31, 0x42, 0x69, 0x4c, 0x4c, 0x48, 0x77, 0x47, 0x79, 0x34, 0x33, 0x4e,
+    0x46, 0x42, 0x6b, 0x52, 0x4a, 0x4c, 0x4c, 0x74, 0x4a, 0x4a, 0x52, 0x54,
+    0x57, 0x7a, 0x73, 0x4f, 0x33, 0x71, 0x79, 0x78, 0x50, 0x78, 0x6b, 0x45,
+    0x79, 0x6c, 0x46, 0x66, 0x36, 0x45, 0x71, 0x64, 0x62, 0x44, 0x75, 0x4b,
+    0x50, 0x0a, 0x48, 0x78, 0x36, 0x47, 0x47, 0x61, 0x65, 0x71, 0x74, 0x53,
+    0x32, 0x35, 0x58, 0x77, 0x32, 0x4b, 0x77, 0x71, 0x2b, 0x46, 0x4e, 0x58,
+    0x6b, 0x79, 0x4c, 0x62, 0x73, 0x63, 0x59, 0x6a, 0x66, 0x79, 0x73, 0x56,
+    0x74, 0x4b, 0x50, 0x63, 0x72, 0x4e, 0x63, 0x56, 0x2f, 0x70, 0x51, 0x72,
+    0x36, 0x55, 0x36, 0x4d, 0x6a, 0x65, 0x2b, 0x53, 0x4a, 0x49, 0x5a, 0x4d,
+    0x62, 0x6c, 0x71, 0x38, 0x59, 0x72, 0x0a, 0x62, 0x61, 0x30, 0x46, 0x38,
+    0x50, 0x72, 0x56, 0x43, 0x38, 0x2b, 0x61, 0x35, 0x66, 0x42, 0x51, 0x70,
+    0x49, 0x73, 0x37, 0x52, 0x36, 0x55, 0x6a, 0x57, 0x33, 0x70, 0x36, 0x2b,
+    0x44, 0x4d, 0x2f, 0x75, 0x4f, 0x2b, 0x5a, 0x6c, 0x2b, 0x4d, 0x67, 0x77,
+    0x64, 0x59, 0x6f, 0x69, 0x63, 0x2b, 0x55, 0x2b, 0x37, 0x6c, 0x46, 0x37,
+    0x65, 0x4e, 0x41, 0x46, 0x78, 0x48, 0x55, 0x64, 0x50, 0x41, 0x4c, 0x0a,
+    0x4d, 0x65, 0x49, 0x72, 0x4a, 0x6d, 0x71, 0x62, 0x54, 0x46, 0x65, 0x75,
+    0x72, 0x43, 0x41, 0x2b, 0x75, 0x6b, 0x56, 0x36, 0x42, 0x66, 0x4f, 0x39,
+    0x6d, 0x32, 0x6b, 0x56, 0x72, 0x6e, 0x31, 0x4f, 0x49, 0x47, 0x50, 0x45,
+    0x4e, 0x58, 0x59, 0x36, 0x42, 0x77, 0x4c, 0x4a, 0x4e, 0x2f, 0x33, 0x48,
+    0x52, 0x2b, 0x37, 0x6f, 0x38, 0x58, 0x59, 0x64, 0x63, 0x78, 0x58, 0x79,
+    0x6c, 0x36, 0x53, 0x31, 0x0a, 0x79, 0x48, 0x70, 0x35, 0x32, 0x55, 0x4b,
+    0x71, 0x4b, 0x33, 0x39, 0x63, 0x2f, 0x73, 0x34, 0x6d, 0x54, 0x36, 0x4e,
+    0x6d, 0x67, 0x54, 0x57, 0x76, 0x52, 0x4c, 0x70, 0x55, 0x48, 0x68, 0x77,
+    0x77, 0x4d, 0x6d, 0x57, 0x64, 0x35, 0x6a, 0x79, 0x54, 0x58, 0x6c, 0x42,
+    0x4f, 0x65, 0x75, 0x4d, 0x36, 0x31, 0x47, 0x37, 0x4d, 0x47, 0x76, 0x76,
+    0x35, 0x30, 0x6a, 0x65, 0x75, 0x4a, 0x43, 0x71, 0x72, 0x0a, 0x56, 0x77,
+    0x4d, 0x69, 0x4b, 0x41, 0x31, 0x4a, 0x64, 0x58, 0x2b, 0x33, 0x4b, 0x4e,
+    0x70, 0x31, 0x76, 0x34, 0x37, 0x6a, 0x33, 0x41, 0x35, 0x35, 0x4d, 0x51,
+    0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44,
+    0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67,
+    0x51, 0x55, 0x6e, 0x5a, 0x50, 0x47, 0x55, 0x34, 0x74, 0x65, 0x79, 0x71,
+    0x38, 0x2f, 0x0a, 0x6e, 0x78, 0x34, 0x50, 0x35, 0x5a, 0x6d, 0x56, 0x76,
+    0x43, 0x54, 0x32, 0x6c, 0x49, 0x38, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56,
+    0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41,
+    0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48,
+    0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41,
+    0x51, 0x59, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x0a, 0x4b, 0x6f, 0x5a, 0x49,
+    0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44,
+    0x67, 0x67, 0x45, 0x42, 0x41, 0x46, 0x69, 0x73, 0x39, 0x41, 0x51, 0x4f,
+    0x7a, 0x63, 0x41, 0x4e, 0x2f, 0x77, 0x72, 0x39, 0x31, 0x4c, 0x6f, 0x57,
+    0x58, 0x79, 0x6d, 0x39, 0x65, 0x32, 0x69, 0x5a, 0x57, 0x45, 0x6e, 0x53,
+    0x74, 0x42, 0x30, 0x33, 0x54, 0x58, 0x38, 0x6e, 0x66, 0x55, 0x59, 0x47,
+    0x0a, 0x58, 0x55, 0x50, 0x47, 0x68, 0x69, 0x34, 0x2b, 0x63, 0x37, 0x49,
+    0x6d, 0x66, 0x55, 0x2b, 0x54, 0x71, 0x62, 0x62, 0x45, 0x4b, 0x70, 0x71,
+    0x72, 0x49, 0x5a, 0x63, 0x55, 0x73, 0x64, 0x36, 0x4d, 0x30, 0x36, 0x75,
+    0x4a, 0x46, 0x64, 0x68, 0x72, 0x4a, 0x4e, 0x54, 0x78, 0x46, 0x71, 0x37,
+    0x59, 0x70, 0x46, 0x7a, 0x55, 0x66, 0x31, 0x47, 0x4f, 0x37, 0x52, 0x67,
+    0x42, 0x73, 0x5a, 0x4e, 0x6a, 0x0a, 0x76, 0x62, 0x7a, 0x34, 0x59, 0x59,
+    0x43, 0x61, 0x6e, 0x72, 0x48, 0x4f, 0x51, 0x6e, 0x44, 0x69, 0x71, 0x58,
+    0x30, 0x47, 0x4a, 0x58, 0x30, 0x6e, 0x6f, 0x66, 0x35, 0x76, 0x37, 0x4c,
+    0x4d, 0x65, 0x4a, 0x4e, 0x72, 0x6a, 0x53, 0x31, 0x55, 0x61, 0x41, 0x44,
+    0x73, 0x31, 0x74, 0x44, 0x76, 0x5a, 0x31, 0x31, 0x30, 0x77, 0x2f, 0x59,
+    0x45, 0x54, 0x69, 0x66, 0x4c, 0x43, 0x42, 0x69, 0x76, 0x74, 0x0a, 0x5a,
+    0x38, 0x53, 0x4f, 0x79, 0x55, 0x4f, 0x79, 0x58, 0x47, 0x73, 0x56, 0x69,
+    0x51, 0x4b, 0x38, 0x59, 0x76, 0x78, 0x4f, 0x38, 0x72, 0x55, 0x7a, 0x71,
+    0x72, 0x4a, 0x76, 0x30, 0x77, 0x71, 0x69, 0x55, 0x4f, 0x50, 0x32, 0x4f,
+    0x2b, 0x67, 0x75, 0x52, 0x4d, 0x4c, 0x62, 0x5a, 0x6a, 0x69, 0x70, 0x4d,
+    0x31, 0x5a, 0x49, 0x38, 0x57, 0x30, 0x62, 0x4d, 0x34, 0x30, 0x4e, 0x6a,
+    0x44, 0x39, 0x67, 0x0a, 0x4e, 0x35, 0x33, 0x54, 0x79, 0x6d, 0x31, 0x2b,
+    0x4e, 0x48, 0x34, 0x4e, 0x6e, 0x33, 0x4a, 0x32, 0x69, 0x78, 0x75, 0x66,
+    0x63, 0x76, 0x31, 0x53, 0x4e, 0x55, 0x46, 0x46, 0x41, 0x70, 0x59, 0x76,
+    0x48, 0x4c, 0x4b, 0x61, 0x63, 0x30, 0x6b, 0x68, 0x73, 0x55, 0x6c, 0x48,
+    0x52, 0x55, 0x65, 0x30, 0x37, 0x32, 0x6f, 0x30, 0x45, 0x63, 0x6c, 0x4e,
+    0x6d, 0x73, 0x78, 0x5a, 0x74, 0x39, 0x59, 0x43, 0x0a, 0x6e, 0x6c, 0x70,
+    0x4f, 0x5a, 0x62, 0x57, 0x55, 0x72, 0x68, 0x76, 0x66, 0x4b, 0x62, 0x41,
+    0x57, 0x38, 0x62, 0x38, 0x41, 0x6e, 0x67, 0x63, 0x36, 0x46, 0x32, 0x53,
+    0x31, 0x42, 0x4c, 0x55, 0x6a, 0x49, 0x5a, 0x6b, 0x4b, 0x6c, 0x54, 0x75,
+    0x58, 0x66, 0x4f, 0x38, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45,
+    0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41,
+    0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49,
+    0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x66,
+    0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65,
+    0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x4f, 0x3d, 0x41,
+    0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23,
+    0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74,
+    0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x20,
+    0x4f, 0x3d, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73,
+    0x74, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22,
+    0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20,
+    0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x22, 0x0a,
+    0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x38, 0x39,
+    0x35, 0x37, 0x33, 0x38, 0x32, 0x38, 0x32, 0x37, 0x32, 0x30, 0x36, 0x35,
+    0x34, 0x37, 0x37, 0x35, 0x37, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x34, 0x32, 0x3a, 0x36, 0x35, 0x3a, 0x63, 0x61, 0x3a, 0x62, 0x65,
+    0x3a, 0x30, 0x31, 0x3a, 0x39, 0x61, 0x3a, 0x39, 0x61, 0x3a, 0x34, 0x63,
+    0x3a, 0x61, 0x39, 0x3a, 0x38, 0x63, 0x3a, 0x34, 0x31, 0x3a, 0x34, 0x39,
+    0x3a, 0x63, 0x64, 0x3a, 0x63, 0x30, 0x3a, 0x64, 0x35, 0x3a, 0x37, 0x66,
+    0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x39, 0x3a,
+    0x33, 0x36, 0x3a, 0x32, 0x31, 0x3a, 0x30, 0x32, 0x3a, 0x38, 0x62, 0x3a,
+    0x32, 0x30, 0x3a, 0x65, 0x64, 0x3a, 0x30, 0x32, 0x3a, 0x66, 0x35, 0x3a,
+    0x36, 0x36, 0x3a, 0x63, 0x35, 0x3a, 0x33, 0x32, 0x3a, 0x64, 0x31, 0x3a,
+    0x64, 0x36, 0x3a, 0x65, 0x64, 0x3a, 0x39, 0x30, 0x3a, 0x39, 0x66, 0x3a,
+    0x34, 0x35, 0x3a, 0x30, 0x30, 0x3a, 0x32, 0x66, 0x0a, 0x23, 0x20, 0x53,
+    0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x61, 0x3a, 0x38, 0x31,
+    0x3a, 0x65, 0x63, 0x3a, 0x35, 0x61, 0x3a, 0x39, 0x32, 0x3a, 0x39, 0x37,
+    0x3a, 0x37, 0x37, 0x3a, 0x66, 0x31, 0x3a, 0x34, 0x35, 0x3a, 0x39, 0x30,
+    0x3a, 0x34, 0x61, 0x3a, 0x66, 0x33, 0x3a, 0x38, 0x64, 0x3a, 0x35, 0x64,
+    0x3a, 0x35, 0x30, 0x3a, 0x39, 0x66, 0x3a, 0x36, 0x36, 0x3a, 0x62, 0x35,
+    0x3a, 0x65, 0x32, 0x3a, 0x63, 0x35, 0x3a, 0x38, 0x66, 0x3a, 0x63, 0x64,
+    0x3a, 0x62, 0x35, 0x3a, 0x33, 0x31, 0x3a, 0x30, 0x35, 0x3a, 0x38, 0x62,
+    0x3a, 0x30, 0x65, 0x3a, 0x31, 0x37, 0x3a, 0x66, 0x33, 0x3a, 0x66, 0x30,
+    0x3a, 0x62, 0x34, 0x3a, 0x31, 0x62, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d,
+    0x49, 0x49, 0x44, 0x54, 0x44, 0x43, 0x43, 0x41, 0x6a, 0x53, 0x67, 0x41,
+    0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x49, 0x66, 0x45, 0x38, 0x45, 0x4f,
+    0x52, 0x7a, 0x55, 0x6d, 0x53, 0x30, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b,
+    0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42,
+    0x51, 0x41, 0x77, 0x52, 0x44, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41,
+    0x31, 0x55, 0x45, 0x0a, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78,
+    0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d,
+    0x43, 0x30, 0x46, 0x6d, 0x5a, 0x6d, 0x6c, 0x79, 0x62, 0x56, 0x52, 0x79,
+    0x64, 0x58, 0x4e, 0x30, 0x4d, 0x52, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44,
+    0x56, 0x51, 0x51, 0x44, 0x44, 0x42, 0x5a, 0x42, 0x5a, 0x6d, 0x5a, 0x70,
+    0x63, 0x6d, 0x31, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x0a, 0x64, 0x43, 0x42,
+    0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x61, 0x57, 0x35,
+    0x6e, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x77, 0x4d, 0x44, 0x45,
+    0x79, 0x4f, 0x54, 0x45, 0x30, 0x4d, 0x44, 0x67, 0x79, 0x4e, 0x46, 0x6f,
+    0x58, 0x44, 0x54, 0x4d, 0x77, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x45,
+    0x30, 0x4d, 0x44, 0x67, 0x79, 0x4e, 0x46, 0x6f, 0x77, 0x52, 0x44, 0x45,
+    0x4c, 0x0a, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68,
+    0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67,
+    0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x43, 0x30, 0x46, 0x6d, 0x5a, 0x6d,
+    0x6c, 0x79, 0x62, 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4d, 0x52,
+    0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42,
+    0x5a, 0x42, 0x5a, 0x6d, 0x5a, 0x70, 0x0a, 0x63, 0x6d, 0x31, 0x55, 0x63,
+    0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62,
+    0x33, 0x4a, 0x72, 0x61, 0x57, 0x35, 0x6e, 0x4d, 0x49, 0x49, 0x42, 0x49,
+    0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39,
+    0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41,
+    0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x0a,
+    0x41, 0x51, 0x45, 0x41, 0x74, 0x49, 0x54, 0x4d, 0x4d, 0x78, 0x63, 0x75,
+    0x61, 0x35, 0x52, 0x73, 0x61, 0x32, 0x46, 0x53, 0x6f, 0x4f, 0x75, 0x6a,
+    0x7a, 0x33, 0x6d, 0x55, 0x54, 0x4f, 0x57, 0x55, 0x67, 0x4a, 0x6e, 0x4c,
+    0x56, 0x57, 0x52, 0x45, 0x5a, 0x59, 0x39, 0x6e, 0x5a, 0x4f, 0x49, 0x47,
+    0x34, 0x31, 0x77, 0x33, 0x53, 0x66, 0x59, 0x76, 0x6d, 0x34, 0x53, 0x45,
+    0x48, 0x69, 0x33, 0x79, 0x0a, 0x59, 0x4a, 0x30, 0x77, 0x54, 0x73, 0x79,
+    0x45, 0x68, 0x65, 0x49, 0x73, 0x7a, 0x78, 0x36, 0x65, 0x2f, 0x6a, 0x61,
+    0x72, 0x4d, 0x33, 0x63, 0x31, 0x52, 0x4e, 0x67, 0x31, 0x6c, 0x68, 0x6f,
+    0x39, 0x4e, 0x75, 0x68, 0x36, 0x44, 0x74, 0x6a, 0x56, 0x52, 0x36, 0x46,
+    0x71, 0x61, 0x59, 0x76, 0x5a, 0x2f, 0x4c, 0x73, 0x36, 0x72, 0x6e, 0x6c,
+    0x61, 0x31, 0x66, 0x54, 0x57, 0x63, 0x62, 0x75, 0x61, 0x0a, 0x6b, 0x43,
+    0x4e, 0x72, 0x6d, 0x72, 0x65, 0x49, 0x64, 0x49, 0x63, 0x4d, 0x48, 0x6c,
+    0x2b, 0x35, 0x6e, 0x69, 0x33, 0x36, 0x71, 0x31, 0x4d, 0x72, 0x33, 0x4c,
+    0x74, 0x32, 0x50, 0x70, 0x4e, 0x4d, 0x43, 0x41, 0x69, 0x4d, 0x48, 0x71,
+    0x49, 0x6a, 0x48, 0x4e, 0x52, 0x71, 0x72, 0x53, 0x4b, 0x36, 0x6d, 0x51,
+    0x45, 0x75, 0x62, 0x57, 0x58, 0x4c, 0x76, 0x69, 0x52, 0x6d, 0x56, 0x53,
+    0x52, 0x4c, 0x0a, 0x51, 0x45, 0x53, 0x78, 0x47, 0x39, 0x66, 0x68, 0x77,
+    0x6f, 0x58, 0x41, 0x33, 0x68, 0x41, 0x2f, 0x50, 0x65, 0x32, 0x34, 0x2f,
+    0x50, 0x48, 0x78, 0x49, 0x31, 0x50, 0x63, 0x76, 0x32, 0x57, 0x58, 0x62,
+    0x39, 0x6e, 0x35, 0x51, 0x48, 0x47, 0x4e, 0x66, 0x62, 0x32, 0x56, 0x31,
+    0x4d, 0x36, 0x2b, 0x6f, 0x46, 0x34, 0x6e, 0x49, 0x39, 0x37, 0x39, 0x70,
+    0x74, 0x41, 0x6d, 0x44, 0x67, 0x41, 0x70, 0x0a, 0x36, 0x7a, 0x78, 0x47,
+    0x38, 0x44, 0x31, 0x67, 0x76, 0x7a, 0x39, 0x51, 0x30, 0x74, 0x77, 0x6d,
+    0x51, 0x56, 0x47, 0x65, 0x46, 0x44, 0x64, 0x43, 0x42, 0x4b, 0x4e, 0x77,
+    0x56, 0x36, 0x67, 0x62, 0x68, 0x2b, 0x30, 0x74, 0x2b, 0x6e, 0x76, 0x75,
+    0x6a, 0x41, 0x72, 0x6a, 0x71, 0x57, 0x61, 0x4a, 0x47, 0x63, 0x74, 0x42,
+    0x2b, 0x64, 0x31, 0x45, 0x4e, 0x6d, 0x48, 0x50, 0x34, 0x6e, 0x64, 0x47,
+    0x0a, 0x79, 0x48, 0x33, 0x32, 0x39, 0x4a, 0x4b, 0x42, 0x4e, 0x76, 0x33,
+    0x62, 0x4e, 0x50, 0x46, 0x79, 0x66, 0x76, 0x4d, 0x4d, 0x46, 0x72, 0x32,
+    0x30, 0x46, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49,
+    0x77, 0x51, 0x44, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34,
+    0x45, 0x46, 0x67, 0x51, 0x55, 0x42, 0x78, 0x2f, 0x53, 0x35, 0x35, 0x7a,
+    0x61, 0x77, 0x6d, 0x36, 0x69, 0x0a, 0x51, 0x4c, 0x53, 0x77, 0x65, 0x6c,
+    0x41, 0x51, 0x55, 0x48, 0x54, 0x45, 0x79, 0x4c, 0x30, 0x77, 0x44, 0x77,
+    0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41,
+    0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67,
+    0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41,
+    0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x0a, 0x4b,
+    0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42,
+    0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x49, 0x6c, 0x58, 0x73,
+    0x68, 0x5a, 0x36, 0x71, 0x4d, 0x4c, 0x39, 0x31, 0x74, 0x6d, 0x62, 0x6d,
+    0x7a, 0x54, 0x43, 0x6e, 0x4c, 0x51, 0x79, 0x46, 0x45, 0x32, 0x6e, 0x70,
+    0x4e, 0x2f, 0x73, 0x76, 0x71, 0x65, 0x2b, 0x2b, 0x45, 0x50, 0x62, 0x6b,
+    0x54, 0x66, 0x4f, 0x0a, 0x74, 0x44, 0x49, 0x75, 0x55, 0x46, 0x55, 0x61,
+    0x4e, 0x55, 0x35, 0x32, 0x51, 0x33, 0x45, 0x67, 0x37, 0x35, 0x4e, 0x33,
+    0x54, 0x68, 0x56, 0x77, 0x4c, 0x6f, 0x66, 0x44, 0x77, 0x52, 0x31, 0x74,
+    0x33, 0x4d, 0x75, 0x31, 0x4a, 0x39, 0x51, 0x73, 0x56, 0x74, 0x46, 0x53,
+    0x55, 0x7a, 0x70, 0x45, 0x30, 0x6e, 0x50, 0x49, 0x78, 0x42, 0x73, 0x46,
+    0x5a, 0x56, 0x70, 0x69, 0x6b, 0x70, 0x7a, 0x75, 0x0a, 0x51, 0x59, 0x30,
+    0x78, 0x32, 0x2b, 0x63, 0x30, 0x36, 0x6c, 0x6b, 0x68, 0x31, 0x51, 0x46,
+    0x36, 0x31, 0x32, 0x53, 0x34, 0x5a, 0x44, 0x6e, 0x4e, 0x79, 0x65, 0x32,
+    0x76, 0x37, 0x55, 0x73, 0x44, 0x53, 0x4b, 0x65, 0x67, 0x6d, 0x51, 0x47,
+    0x41, 0x33, 0x47, 0x57, 0x6a, 0x4e, 0x71, 0x35, 0x6c, 0x57, 0x55, 0x68,
+    0x50, 0x67, 0x6b, 0x76, 0x49, 0x5a, 0x66, 0x46, 0x58, 0x48, 0x65, 0x56,
+    0x5a, 0x0a, 0x4c, 0x67, 0x6f, 0x2f, 0x62, 0x4e, 0x6a, 0x52, 0x39, 0x65,
+    0x55, 0x4a, 0x74, 0x47, 0x78, 0x55, 0x41, 0x41, 0x72, 0x67, 0x46, 0x55,
+    0x32, 0x48, 0x64, 0x57, 0x32, 0x33, 0x57, 0x4a, 0x5a, 0x61, 0x33, 0x57,
+    0x33, 0x53, 0x41, 0x4b, 0x44, 0x30, 0x6d, 0x30, 0x69, 0x2b, 0x77, 0x7a,
+    0x65, 0x6b, 0x75, 0x6a, 0x62, 0x67, 0x66, 0x49, 0x65, 0x46, 0x6c, 0x78,
+    0x6f, 0x56, 0x6f, 0x74, 0x34, 0x75, 0x0a, 0x6f, 0x6c, 0x75, 0x39, 0x72,
+    0x78, 0x6a, 0x35, 0x6b, 0x46, 0x44, 0x4e, 0x63, 0x46, 0x6e, 0x34, 0x4a,
+    0x32, 0x64, 0x48, 0x79, 0x38, 0x65, 0x67, 0x42, 0x7a, 0x70, 0x39, 0x30,
+    0x53, 0x78, 0x64, 0x62, 0x42, 0x6b, 0x36, 0x5a, 0x72, 0x56, 0x39, 0x2f,
+    0x5a, 0x46, 0x76, 0x67, 0x72, 0x47, 0x2b, 0x43, 0x4a, 0x50, 0x62, 0x46,
+    0x45, 0x66, 0x78, 0x6f, 0x6a, 0x66, 0x48, 0x52, 0x5a, 0x34, 0x38, 0x0a,
+    0x78, 0x33, 0x65, 0x76, 0x5a, 0x4b, 0x69, 0x54, 0x33, 0x2f, 0x5a, 0x70,
+    0x67, 0x34, 0x4a, 0x67, 0x38, 0x6b, 0x6c, 0x43, 0x4e, 0x4f, 0x31, 0x61,
+    0x41, 0x46, 0x53, 0x46, 0x48, 0x42, 0x59, 0x32, 0x6b, 0x67, 0x78, 0x63,
+    0x2b, 0x71, 0x61, 0x74, 0x76, 0x39, 0x73, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
+    0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a,
+    0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74,
+    0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x4f, 0x3d, 0x41,
+    0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23,
+    0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e,
+    0x3d, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74,
+    0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x4f, 0x3d, 0x41,
+    0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23,
+    0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, 0x66, 0x66,
+    0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x65,
+    0x6d, 0x69, 0x75, 0x6d, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69,
+    0x61, 0x6c, 0x3a, 0x20, 0x37, 0x38, 0x39, 0x33, 0x37, 0x30, 0x36, 0x35,
+    0x34, 0x30, 0x37, 0x33, 0x34, 0x33, 0x35, 0x32, 0x31, 0x31, 0x30, 0x0a,
+    0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x34, 0x3a, 0x35, 0x64,
+    0x3a, 0x30, 0x65, 0x3a, 0x34, 0x38, 0x3a, 0x62, 0x36, 0x3a, 0x61, 0x63,
+    0x3a, 0x32, 0x38, 0x3a, 0x33, 0x30, 0x3a, 0x34, 0x65, 0x3a, 0x30, 0x61,
+    0x3a, 0x62, 0x63, 0x3a, 0x66, 0x39, 0x3a, 0x33, 0x38, 0x3a, 0x31, 0x36,
+    0x3a, 0x38, 0x37, 0x3a, 0x35, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41,
+    0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x64, 0x38, 0x3a, 0x61, 0x36, 0x3a, 0x33, 0x33, 0x3a,
+    0x32, 0x63, 0x3a, 0x65, 0x30, 0x3a, 0x30, 0x33, 0x3a, 0x36, 0x66, 0x3a,
+    0x62, 0x31, 0x3a, 0x38, 0x35, 0x3a, 0x66, 0x36, 0x3a, 0x36, 0x33, 0x3a,
+    0x34, 0x66, 0x3a, 0x37, 0x64, 0x3a, 0x36, 0x61, 0x3a, 0x30, 0x36, 0x3a,
+    0x36, 0x35, 0x3a, 0x32, 0x36, 0x3a, 0x33, 0x32, 0x3a, 0x32, 0x38, 0x3a,
+    0x32, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x37, 0x30, 0x3a, 0x61, 0x37, 0x3a, 0x33, 0x66, 0x3a, 0x37, 0x66,
+    0x3a, 0x33, 0x37, 0x3a, 0x36, 0x62, 0x3a, 0x36, 0x30, 0x3a, 0x30, 0x37,
+    0x3a, 0x34, 0x32, 0x3a, 0x34, 0x38, 0x3a, 0x39, 0x30, 0x3a, 0x34, 0x35,
+    0x3a, 0x33, 0x34, 0x3a, 0x62, 0x31, 0x3a, 0x31, 0x34, 0x3a, 0x38, 0x32,
+    0x3a, 0x64, 0x35, 0x3a, 0x62, 0x66, 0x3a, 0x30, 0x65, 0x3a, 0x36, 0x39,
+    0x3a, 0x38, 0x65, 0x3a, 0x63, 0x63, 0x3a, 0x34, 0x39, 0x3a, 0x38, 0x64,
+    0x3a, 0x66, 0x35, 0x3a, 0x32, 0x35, 0x3a, 0x37, 0x37, 0x3a, 0x65, 0x62,
+    0x3a, 0x66, 0x32, 0x3a, 0x65, 0x39, 0x3a, 0x33, 0x62, 0x3a, 0x39, 0x61,
+    0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20,
+    0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x52, 0x6a, 0x43,
+    0x43, 0x41, 0x79, 0x36, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49,
+    0x49, 0x62, 0x59, 0x77, 0x55, 0x52, 0x72, 0x47, 0x6d, 0x43, 0x75, 0x34,
+    0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63,
+    0x4e, 0x41, 0x51, 0x45, 0x4d, 0x42, 0x51, 0x41, 0x77, 0x51, 0x54, 0x45,
+    0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x42, 0x68,
+    0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67,
+    0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x43, 0x30, 0x46, 0x6d, 0x5a, 0x6d,
+    0x6c, 0x79, 0x62, 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4d, 0x52,
+    0x77, 0x77, 0x47, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42,
+    0x4e, 0x42, 0x5a, 0x6d, 0x5a, 0x70, 0x63, 0x6d, 0x31, 0x55, 0x63, 0x6e,
+    0x56, 0x7a, 0x0a, 0x64, 0x43, 0x42, 0x51, 0x63, 0x6d, 0x56, 0x74, 0x61,
+    0x58, 0x56, 0x74, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x77, 0x4d,
+    0x44, 0x45, 0x79, 0x4f, 0x54, 0x45, 0x30, 0x4d, 0x54, 0x41, 0x7a, 0x4e,
+    0x6c, 0x6f, 0x58, 0x44, 0x54, 0x51, 0x77, 0x4d, 0x54, 0x49, 0x7a, 0x4d,
+    0x54, 0x45, 0x30, 0x4d, 0x54, 0x41, 0x7a, 0x4e, 0x6c, 0x6f, 0x77, 0x51,
+    0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45,
+    0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x44, 0x41, 0x53,
+    0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x43, 0x30, 0x46, 0x6d,
+    0x5a, 0x6d, 0x6c, 0x79, 0x62, 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30,
+    0x4d, 0x52, 0x77, 0x77, 0x47, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44,
+    0x44, 0x42, 0x4e, 0x42, 0x5a, 0x6d, 0x5a, 0x70, 0x63, 0x6d, 0x31, 0x55,
+    0x0a, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x51, 0x63, 0x6d, 0x56,
+    0x74, 0x61, 0x58, 0x56, 0x74, 0x4d, 0x49, 0x49, 0x43, 0x49, 0x6a, 0x41,
+    0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30,
+    0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x38,
+    0x41, 0x4d, 0x49, 0x49, 0x43, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x67, 0x45,
+    0x41, 0x78, 0x42, 0x4c, 0x66, 0x0a, 0x71, 0x56, 0x2f, 0x2b, 0x51, 0x64,
+    0x33, 0x64, 0x39, 0x5a, 0x2b, 0x4b, 0x34, 0x2f, 0x61, 0x73, 0x34, 0x54,
+    0x78, 0x34, 0x6d, 0x72, 0x7a, 0x59, 0x38, 0x48, 0x39, 0x36, 0x6f, 0x44,
+    0x4d, 0x71, 0x33, 0x49, 0x30, 0x67, 0x57, 0x36, 0x34, 0x74, 0x62, 0x2b,
+    0x65, 0x54, 0x32, 0x54, 0x5a, 0x77, 0x61, 0x6d, 0x6a, 0x50, 0x6a, 0x6c,
+    0x47, 0x6a, 0x68, 0x56, 0x74, 0x6e, 0x42, 0x4b, 0x41, 0x51, 0x0a, 0x4a,
+    0x47, 0x39, 0x64, 0x4b, 0x49, 0x4c, 0x42, 0x6c, 0x31, 0x66, 0x59, 0x53,
+    0x43, 0x6b, 0x54, 0x74, 0x75, 0x47, 0x2b, 0x6b, 0x55, 0x33, 0x66, 0x68,
+    0x51, 0x78, 0x54, 0x47, 0x4a, 0x6f, 0x65, 0x4a, 0x4b, 0x4a, 0x50, 0x6a,
+    0x2f, 0x43, 0x69, 0x68, 0x51, 0x76, 0x4c, 0x39, 0x43, 0x6c, 0x2f, 0x30,
+    0x71, 0x52, 0x59, 0x37, 0x69, 0x5a, 0x4e, 0x79, 0x61, 0x71, 0x6f, 0x65,
+    0x35, 0x72, 0x5a, 0x0a, 0x2b, 0x6a, 0x6a, 0x65, 0x52, 0x46, 0x63, 0x56,
+    0x35, 0x66, 0x69, 0x4d, 0x79, 0x4e, 0x6c, 0x49, 0x34, 0x67, 0x30, 0x57,
+    0x4a, 0x78, 0x30, 0x65, 0x79, 0x49, 0x4f, 0x46, 0x4a, 0x62, 0x65, 0x36,
+    0x71, 0x6c, 0x56, 0x42, 0x7a, 0x41, 0x4d, 0x69, 0x53, 0x79, 0x32, 0x52,
+    0x6a, 0x59, 0x76, 0x6d, 0x69, 0x61, 0x39, 0x6d, 0x78, 0x2b, 0x6e, 0x2f,
+    0x4b, 0x2b, 0x6b, 0x38, 0x72, 0x4e, 0x72, 0x53, 0x0a, 0x73, 0x38, 0x50,
+    0x68, 0x61, 0x4a, 0x79, 0x4a, 0x2b, 0x48, 0x6f, 0x41, 0x56, 0x74, 0x37,
+    0x30, 0x56, 0x5a, 0x56, 0x73, 0x2b, 0x37, 0x70, 0x6b, 0x33, 0x57, 0x4b,
+    0x4c, 0x33, 0x77, 0x74, 0x33, 0x4d, 0x75, 0x74, 0x69, 0x7a, 0x43, 0x61,
+    0x61, 0x6d, 0x37, 0x75, 0x71, 0x59, 0x6f, 0x4e, 0x4d, 0x74, 0x41, 0x5a,
+    0x36, 0x4d, 0x4d, 0x67, 0x70, 0x76, 0x2b, 0x30, 0x47, 0x54, 0x5a, 0x65,
+    0x35, 0x0a, 0x48, 0x4d, 0x51, 0x78, 0x4b, 0x39, 0x56, 0x66, 0x76, 0x46,
+    0x4d, 0x53, 0x46, 0x35, 0x79, 0x5a, 0x56, 0x79, 0x6c, 0x6d, 0x64, 0x32,
+    0x45, 0x68, 0x4d, 0x51, 0x63, 0x75, 0x4a, 0x55, 0x6d, 0x64, 0x47, 0x50,
+    0x4c, 0x75, 0x38, 0x79, 0x74, 0x78, 0x6a, 0x4c, 0x57, 0x36, 0x4f, 0x51,
+    0x64, 0x4a, 0x64, 0x2f, 0x7a, 0x76, 0x4c, 0x70, 0x4b, 0x51, 0x42, 0x59,
+    0x30, 0x74, 0x4c, 0x33, 0x64, 0x37, 0x0a, 0x37, 0x30, 0x4f, 0x2f, 0x4e,
+    0x62, 0x75, 0x61, 0x32, 0x50, 0x6c, 0x7a, 0x70, 0x79, 0x7a, 0x79, 0x30,
+    0x46, 0x66, 0x75, 0x4b, 0x45, 0x34, 0x6d, 0x58, 0x34, 0x2b, 0x51, 0x61,
+    0x41, 0x6b, 0x76, 0x75, 0x50, 0x6a, 0x63, 0x42, 0x75, 0x6b, 0x75, 0x6d,
+    0x6a, 0x35, 0x52, 0x70, 0x39, 0x45, 0x69, 0x78, 0x41, 0x71, 0x6e, 0x4f,
+    0x45, 0x68, 0x73, 0x73, 0x2f, 0x6e, 0x2f, 0x66, 0x61, 0x75, 0x47, 0x0a,
+    0x56, 0x2b, 0x4f, 0x36, 0x31, 0x6f, 0x56, 0x34, 0x64, 0x37, 0x70, 0x44,
+    0x36, 0x6b, 0x68, 0x2f, 0x39, 0x74, 0x69, 0x2b, 0x49, 0x32, 0x30, 0x65,
+    0x76, 0x39, 0x45, 0x32, 0x62, 0x46, 0x68, 0x63, 0x38, 0x65, 0x36, 0x6b,
+    0x47, 0x56, 0x51, 0x61, 0x39, 0x51, 0x50, 0x53, 0x64, 0x75, 0x62, 0x68,
+    0x6a, 0x4c, 0x30, 0x38, 0x73, 0x39, 0x4e, 0x49, 0x53, 0x2b, 0x4c, 0x49,
+    0x2b, 0x48, 0x2b, 0x53, 0x0a, 0x71, 0x48, 0x5a, 0x47, 0x6e, 0x45, 0x4a,
+    0x6c, 0x50, 0x71, 0x51, 0x65, 0x77, 0x51, 0x63, 0x44, 0x57, 0x6b, 0x59,
+    0x74, 0x75, 0x4a, 0x66, 0x7a, 0x74, 0x39, 0x57, 0x79, 0x56, 0x53, 0x48,
+    0x76, 0x75, 0x74, 0x78, 0x4d, 0x41, 0x4a, 0x66, 0x37, 0x46, 0x4a, 0x55,
+    0x6e, 0x4d, 0x37, 0x2f, 0x6f, 0x51, 0x30, 0x64, 0x47, 0x30, 0x67, 0x69,
+    0x5a, 0x46, 0x6d, 0x41, 0x37, 0x6d, 0x6e, 0x37, 0x53, 0x0a, 0x35, 0x75,
+    0x30, 0x34, 0x36, 0x75, 0x77, 0x42, 0x48, 0x6a, 0x78, 0x49, 0x56, 0x6b,
+    0x6b, 0x4a, 0x78, 0x30, 0x77, 0x33, 0x41, 0x4a, 0x36, 0x49, 0x44, 0x73,
+    0x42, 0x7a, 0x34, 0x57, 0x39, 0x6d, 0x36, 0x58, 0x4a, 0x48, 0x4d, 0x44,
+    0x34, 0x51, 0x35, 0x51, 0x73, 0x44, 0x79, 0x5a, 0x70, 0x43, 0x41, 0x47,
+    0x7a, 0x46, 0x6c, 0x48, 0x35, 0x68, 0x78, 0x49, 0x72, 0x66, 0x66, 0x34,
+    0x49, 0x61, 0x0a, 0x43, 0x31, 0x6e, 0x45, 0x57, 0x54, 0x4a, 0x33, 0x73,
+    0x37, 0x78, 0x67, 0x61, 0x56, 0x59, 0x35, 0x2f, 0x62, 0x51, 0x47, 0x65,
+    0x79, 0x7a, 0x57, 0x5a, 0x44, 0x62, 0x5a, 0x76, 0x55, 0x6a, 0x74, 0x68,
+    0x42, 0x39, 0x2b, 0x70, 0x53, 0x4b, 0x50, 0x4b, 0x72, 0x68, 0x43, 0x39,
+    0x49, 0x4b, 0x33, 0x31, 0x46, 0x4f, 0x51, 0x65, 0x45, 0x34, 0x74, 0x47,
+    0x76, 0x32, 0x42, 0x62, 0x30, 0x54, 0x58, 0x0a, 0x4f, 0x77, 0x46, 0x30,
+    0x6c, 0x6b, 0x4c, 0x67, 0x41, 0x4f, 0x49, 0x75, 0x61, 0x2b, 0x72, 0x46,
+    0x37, 0x6e, 0x4b, 0x73, 0x75, 0x37, 0x2f, 0x2b, 0x36, 0x71, 0x71, 0x6f,
+    0x2b, 0x4e, 0x7a, 0x32, 0x73, 0x6e, 0x6d, 0x4b, 0x74, 0x6d, 0x63, 0x43,
+    0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77,
+    0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45,
+    0x0a, 0x46, 0x4a, 0x33, 0x41, 0x5a, 0x36, 0x59, 0x4d, 0x49, 0x74, 0x6b,
+    0x6d, 0x39, 0x55, 0x57, 0x72, 0x70, 0x6d, 0x56, 0x53, 0x45, 0x53, 0x66,
+    0x59, 0x52, 0x61, 0x78, 0x6a, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55,
+    0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d,
+    0x42, 0x41, 0x66, 0x38, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30,
+    0x50, 0x41, 0x51, 0x48, 0x2f, 0x0a, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67,
+    0x45, 0x47, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49,
+    0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x44, 0x41, 0x55, 0x41, 0x41, 0x34,
+    0x49, 0x43, 0x41, 0x51, 0x43, 0x7a, 0x56, 0x30, 0x30, 0x51, 0x59, 0x6b,
+    0x34, 0x36, 0x35, 0x4b, 0x7a, 0x71, 0x75, 0x42, 0x79, 0x76, 0x4d, 0x69,
+    0x50, 0x49, 0x73, 0x30, 0x6c, 0x61, 0x55, 0x5a, 0x78, 0x32, 0x0a, 0x4b,
+    0x49, 0x31, 0x35, 0x71, 0x6c, 0x64, 0x47, 0x46, 0x39, 0x58, 0x31, 0x55,
+    0x76, 0x61, 0x33, 0x52, 0x4f, 0x67, 0x49, 0x52, 0x4c, 0x38, 0x59, 0x68,
+    0x4e, 0x49, 0x4c, 0x67, 0x4d, 0x33, 0x46, 0x45, 0x76, 0x30, 0x41, 0x56,
+    0x51, 0x56, 0x68, 0x68, 0x30, 0x48, 0x63, 0x74, 0x53, 0x53, 0x65, 0x50,
+    0x4d, 0x54, 0x59, 0x79, 0x50, 0x74, 0x77, 0x6e, 0x69, 0x39, 0x34, 0x6c,
+    0x6f, 0x4d, 0x67, 0x0a, 0x4e, 0x74, 0x35, 0x38, 0x44, 0x32, 0x6b, 0x54,
+    0x69, 0x4b, 0x56, 0x31, 0x4e, 0x70, 0x67, 0x49, 0x70, 0x73, 0x62, 0x66,
+    0x72, 0x4d, 0x37, 0x6a, 0x57, 0x4e, 0x61, 0x33, 0x50, 0x74, 0x36, 0x36,
+    0x38, 0x2b, 0x73, 0x30, 0x51, 0x4e, 0x69, 0x69, 0x67, 0x66, 0x56, 0x34,
+    0x50, 0x79, 0x2f, 0x56, 0x70, 0x66, 0x7a, 0x5a, 0x6f, 0x74, 0x52, 0x65,
+    0x42, 0x41, 0x34, 0x58, 0x72, 0x66, 0x35, 0x42, 0x0a, 0x38, 0x4f, 0x57,
+    0x79, 0x63, 0x76, 0x70, 0x45, 0x67, 0x6a, 0x4e, 0x43, 0x36, 0x43, 0x31,
+    0x59, 0x39, 0x31, 0x61, 0x4d, 0x59, 0x6a, 0x2b, 0x36, 0x51, 0x72, 0x43,
+    0x63, 0x44, 0x46, 0x78, 0x2b, 0x4c, 0x6d, 0x55, 0x6d, 0x58, 0x46, 0x4e,
+    0x50, 0x41, 0x4c, 0x4a, 0x34, 0x66, 0x71, 0x45, 0x4e, 0x6d, 0x53, 0x32,
+    0x4e, 0x75, 0x42, 0x32, 0x4f, 0x6f, 0x73, 0x53, 0x77, 0x2f, 0x57, 0x44,
+    0x51, 0x0a, 0x4d, 0x4b, 0x53, 0x4f, 0x79, 0x41, 0x52, 0x69, 0x71, 0x63,
+    0x54, 0x74, 0x4e, 0x64, 0x35, 0x36, 0x6c, 0x2b, 0x30, 0x4f, 0x4f, 0x46,
+    0x36, 0x53, 0x4c, 0x35, 0x4e, 0x77, 0x70, 0x61, 0x6d, 0x63, 0x62, 0x36,
+    0x64, 0x39, 0x45, 0x78, 0x31, 0x2b, 0x78, 0x67, 0x68, 0x49, 0x73, 0x56,
+    0x35, 0x6e, 0x36, 0x31, 0x45, 0x49, 0x4a, 0x65, 0x6e, 0x6d, 0x4a, 0x57,
+    0x74, 0x53, 0x4b, 0x5a, 0x47, 0x63, 0x0a, 0x30, 0x6a, 0x6c, 0x7a, 0x43,
+    0x46, 0x66, 0x65, 0x6d, 0x51, 0x61, 0x30, 0x57, 0x35, 0x30, 0x51, 0x42,
+    0x75, 0x48, 0x43, 0x41, 0x4b, 0x69, 0x34, 0x48, 0x45, 0x6f, 0x43, 0x43,
+    0x68, 0x54, 0x51, 0x77, 0x55, 0x48, 0x4b, 0x2b, 0x34, 0x77, 0x31, 0x49,
+    0x58, 0x32, 0x43, 0x4f, 0x50, 0x4b, 0x70, 0x56, 0x4a, 0x45, 0x5a, 0x4e,
+    0x5a, 0x4f, 0x55, 0x62, 0x57, 0x6f, 0x36, 0x78, 0x62, 0x4c, 0x51, 0x0a,
+    0x75, 0x34, 0x6d, 0x47, 0x6b, 0x2b, 0x69, 0x62, 0x79, 0x51, 0x38, 0x36,
+    0x70, 0x33, 0x71, 0x34, 0x6f, 0x66, 0x42, 0x34, 0x52, 0x76, 0x72, 0x38,
+    0x4e, 0x79, 0x2f, 0x6c, 0x69, 0x6f, 0x54, 0x7a, 0x33, 0x2f, 0x34, 0x45,
+    0x32, 0x61, 0x46, 0x6f, 0x6f, 0x43, 0x38, 0x6b, 0x34, 0x67, 0x6d, 0x56,
+    0x42, 0x74, 0x57, 0x56, 0x79, 0x75, 0x45, 0x6b, 0x6c, 0x75, 0x74, 0x38,
+    0x39, 0x70, 0x4d, 0x46, 0x0a, 0x75, 0x2b, 0x31, 0x7a, 0x36, 0x53, 0x33,
+    0x52, 0x64, 0x54, 0x6e, 0x58, 0x35, 0x79, 0x54, 0x62, 0x32, 0x45, 0x35,
+    0x66, 0x51, 0x34, 0x2b, 0x65, 0x30, 0x42, 0x51, 0x35, 0x76, 0x31, 0x56,
+    0x77, 0x53, 0x4a, 0x6c, 0x58, 0x4d, 0x62, 0x53, 0x63, 0x37, 0x6b, 0x71,
+    0x59, 0x41, 0x35, 0x59, 0x77, 0x48, 0x32, 0x41, 0x47, 0x37, 0x68, 0x73,
+    0x6a, 0x2f, 0x6f, 0x46, 0x67, 0x49, 0x78, 0x70, 0x48, 0x0a, 0x59, 0x6f,
+    0x57, 0x6c, 0x7a, 0x42, 0x6b, 0x30, 0x67, 0x47, 0x2b, 0x7a, 0x72, 0x42,
+    0x72, 0x6a, 0x6e, 0x2f, 0x42, 0x37, 0x53, 0x4b, 0x33, 0x56, 0x41, 0x64,
+    0x6c, 0x6e, 0x74, 0x71, 0x6c, 0x79, 0x6b, 0x2b, 0x6f, 0x74, 0x5a, 0x72,
+    0x57, 0x79, 0x75, 0x4f, 0x51, 0x39, 0x50, 0x4c, 0x4c, 0x76, 0x54, 0x49,
+    0x7a, 0x71, 0x36, 0x77, 0x65, 0x2f, 0x71, 0x7a, 0x57, 0x61, 0x56, 0x59,
+    0x61, 0x38, 0x0a, 0x47, 0x4b, 0x61, 0x31, 0x71, 0x46, 0x36, 0x30, 0x67,
+    0x32, 0x78, 0x72, 0x61, 0x55, 0x44, 0x54, 0x6e, 0x39, 0x7a, 0x78, 0x77,
+    0x32, 0x6c, 0x72, 0x75, 0x65, 0x46, 0x74, 0x43, 0x66, 0x54, 0x78, 0x71,
+    0x6c, 0x42, 0x32, 0x43, 0x6e, 0x70, 0x39, 0x65, 0x68, 0x65, 0x68, 0x56,
+    0x5a, 0x5a, 0x43, 0x6d, 0x54, 0x45, 0x4a, 0x33, 0x57, 0x41, 0x52, 0x6a,
+    0x51, 0x55, 0x77, 0x66, 0x75, 0x61, 0x4f, 0x0a, 0x52, 0x74, 0x47, 0x64,
+    0x46, 0x4e, 0x72, 0x48, 0x46, 0x2b, 0x51, 0x46, 0x6c, 0x6f, 0x7a, 0x45,
+    0x4a, 0x4c, 0x55, 0x62, 0x7a, 0x78, 0x51, 0x48, 0x73, 0x6b, 0x44, 0x34,
+    0x6f, 0x35, 0x35, 0x42, 0x68, 0x72, 0x77, 0x45, 0x30, 0x47, 0x75, 0x57,
+    0x79, 0x43, 0x71, 0x41, 0x4e, 0x50, 0x32, 0x2f, 0x37, 0x77, 0x61, 0x6a,
+    0x33, 0x56, 0x6a, 0x46, 0x68, 0x54, 0x30, 0x2b, 0x6a, 0x2f, 0x36, 0x65,
+    0x0a, 0x4b, 0x65, 0x43, 0x32, 0x75, 0x41, 0x6c, 0x6f, 0x47, 0x52, 0x77,
+    0x59, 0x51, 0x77, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45,
+    0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41,
+    0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49,
+    0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x66,
+    0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72,
+    0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x45, 0x43, 0x43, 0x20, 0x4f, 0x3d,
+    0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a,
+    0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43,
+    0x4e, 0x3d, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73,
+    0x74, 0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x45, 0x43,
+    0x43, 0x20, 0x4f, 0x3d, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72,
+    0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a,
+    0x20, 0x22, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73,
+    0x74, 0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x45, 0x43,
+    0x43, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a,
+    0x20, 0x38, 0x34, 0x30, 0x31, 0x32, 0x32, 0x34, 0x39, 0x30, 0x37, 0x38,
+    0x36, 0x31, 0x34, 0x39, 0x30, 0x32, 0x36, 0x30, 0x0a, 0x23, 0x20, 0x4d,
+    0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x3a, 0x20, 0x36, 0x34, 0x3a, 0x62, 0x30, 0x3a, 0x30, 0x39,
+    0x3a, 0x35, 0x35, 0x3a, 0x63, 0x66, 0x3a, 0x62, 0x31, 0x3a, 0x64, 0x35,
+    0x3a, 0x39, 0x39, 0x3a, 0x65, 0x32, 0x3a, 0x62, 0x65, 0x3a, 0x31, 0x33,
+    0x3a, 0x61, 0x62, 0x3a, 0x61, 0x36, 0x3a, 0x35, 0x64, 0x3a, 0x65, 0x61,
+    0x3a, 0x34, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46,
+    0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20,
+    0x62, 0x38, 0x3a, 0x32, 0x33, 0x3a, 0x36, 0x62, 0x3a, 0x30, 0x30, 0x3a,
+    0x32, 0x66, 0x3a, 0x31, 0x64, 0x3a, 0x31, 0x36, 0x3a, 0x38, 0x36, 0x3a,
+    0x35, 0x33, 0x3a, 0x30, 0x31, 0x3a, 0x35, 0x35, 0x3a, 0x36, 0x63, 0x3a,
+    0x31, 0x31, 0x3a, 0x61, 0x34, 0x3a, 0x33, 0x37, 0x3a, 0x63, 0x61, 0x3a,
+    0x65, 0x62, 0x3a, 0x66, 0x66, 0x3a, 0x63, 0x33, 0x3a, 0x62, 0x62, 0x0a,
+    0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e,
+    0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x64,
+    0x3a, 0x37, 0x31, 0x3a, 0x66, 0x64, 0x3a, 0x66, 0x36, 0x3a, 0x64, 0x61,
+    0x3a, 0x39, 0x37, 0x3a, 0x65, 0x34, 0x3a, 0x63, 0x66, 0x3a, 0x36, 0x32,
+    0x3a, 0x64, 0x31, 0x3a, 0x36, 0x34, 0x3a, 0x37, 0x61, 0x3a, 0x64, 0x64,
+    0x3a, 0x32, 0x35, 0x3a, 0x38, 0x31, 0x3a, 0x62, 0x30, 0x3a, 0x37, 0x64,
+    0x3a, 0x37, 0x39, 0x3a, 0x61, 0x64, 0x3a, 0x66, 0x38, 0x3a, 0x33, 0x39,
+    0x3a, 0x37, 0x65, 0x3a, 0x62, 0x34, 0x3a, 0x65, 0x63, 0x3a, 0x62, 0x61,
+    0x3a, 0x39, 0x63, 0x3a, 0x35, 0x65, 0x3a, 0x38, 0x34, 0x3a, 0x38, 0x38,
+    0x3a, 0x38, 0x32, 0x3a, 0x31, 0x34, 0x3a, 0x32, 0x33, 0x0a, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52,
+    0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x42, 0x2f, 0x6a, 0x43, 0x43, 0x41, 0x59,
+    0x57, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x49, 0x64, 0x4a,
+    0x63, 0x6c, 0x69, 0x73, 0x63, 0x2f, 0x65, 0x6c, 0x51, 0x77, 0x43, 0x67,
+    0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77,
+    0x4d, 0x77, 0x52, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31,
+    0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x0a, 0x56, 0x56, 0x4d, 0x78, 0x46,
+    0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x43,
+    0x30, 0x46, 0x6d, 0x5a, 0x6d, 0x6c, 0x79, 0x62, 0x56, 0x52, 0x79, 0x64,
+    0x58, 0x4e, 0x30, 0x4d, 0x53, 0x41, 0x77, 0x48, 0x67, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x44, 0x44, 0x42, 0x64, 0x42, 0x5a, 0x6d, 0x5a, 0x70, 0x63,
+    0x6d, 0x31, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x51, 0x0a,
+    0x63, 0x6d, 0x56, 0x74, 0x61, 0x58, 0x56, 0x74, 0x49, 0x45, 0x56, 0x44,
+    0x51, 0x7a, 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4d, 0x44, 0x41, 0x78,
+    0x4d, 0x6a, 0x6b, 0x78, 0x4e, 0x44, 0x49, 0x77, 0x4d, 0x6a, 0x52, 0x61,
+    0x46, 0x77, 0x30, 0x30, 0x4d, 0x44, 0x45, 0x79, 0x4d, 0x7a, 0x45, 0x78,
+    0x4e, 0x44, 0x49, 0x77, 0x4d, 0x6a, 0x52, 0x61, 0x4d, 0x45, 0x55, 0x78,
+    0x43, 0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59,
+    0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59,
+    0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, 0x74, 0x42, 0x5a, 0x6d, 0x5a,
+    0x70, 0x63, 0x6d, 0x31, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x44, 0x45,
+    0x67, 0x4d, 0x42, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77,
+    0x58, 0x51, 0x57, 0x5a, 0x6d, 0x61, 0x58, 0x4a, 0x74, 0x0a, 0x56, 0x48,
+    0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x55, 0x48, 0x4a, 0x6c, 0x62, 0x57,
+    0x6c, 0x31, 0x62, 0x53, 0x42, 0x46, 0x51, 0x30, 0x4d, 0x77, 0x64, 0x6a,
+    0x41, 0x51, 0x42, 0x67, 0x63, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51,
+    0x49, 0x42, 0x42, 0x67, 0x55, 0x72, 0x67, 0x51, 0x51, 0x41, 0x49, 0x67,
+    0x4e, 0x69, 0x41, 0x41, 0x51, 0x4e, 0x4d, 0x46, 0x34, 0x62, 0x46, 0x5a,
+    0x30, 0x44, 0x0a, 0x30, 0x4b, 0x46, 0x35, 0x4e, 0x62, 0x63, 0x36, 0x50,
+    0x4a, 0x4a, 0x36, 0x79, 0x68, 0x55, 0x63, 0x7a, 0x57, 0x4c, 0x7a, 0x6e,
+    0x43, 0x5a, 0x63, 0x42, 0x7a, 0x33, 0x6c, 0x56, 0x50, 0x71, 0x6a, 0x31,
+    0x73, 0x77, 0x53, 0x36, 0x76, 0x51, 0x55, 0x58, 0x2b, 0x69, 0x4f, 0x47,
+    0x61, 0x73, 0x76, 0x4c, 0x6b, 0x6a, 0x6d, 0x72, 0x42, 0x68, 0x44, 0x65,
+    0x4b, 0x7a, 0x51, 0x4e, 0x38, 0x4f, 0x39, 0x0a, 0x73, 0x73, 0x30, 0x73,
+    0x35, 0x6b, 0x66, 0x69, 0x47, 0x75, 0x5a, 0x6a, 0x75, 0x44, 0x30, 0x75,
+    0x4c, 0x33, 0x6a, 0x45, 0x54, 0x39, 0x76, 0x30, 0x44, 0x36, 0x52, 0x6f,
+    0x54, 0x46, 0x56, 0x79, 0x61, 0x35, 0x55, 0x64, 0x54, 0x68, 0x68, 0x43,
+    0x6c, 0x58, 0x6a, 0x4d, 0x4e, 0x7a, 0x79, 0x52, 0x34, 0x70, 0x74, 0x6c,
+    0x4b, 0x79, 0x6d, 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x42, 0x30, 0x47,
+    0x0a, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x53,
+    0x61, 0x72, 0x79, 0x6c, 0x36, 0x77, 0x42, 0x45, 0x31, 0x4e, 0x53, 0x5a,
+    0x52, 0x4d, 0x41, 0x44, 0x44, 0x61, 0x76, 0x35, 0x41, 0x31, 0x61, 0x37,
+    0x57, 0x50, 0x44, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d,
+    0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48,
+    0x2f, 0x4d, 0x41, 0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77,
+    0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a,
+    0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51,
+    0x51, 0x44, 0x41, 0x77, 0x4e, 0x6e, 0x41, 0x44, 0x42, 0x6b, 0x41, 0x6a,
+    0x41, 0x58, 0x43, 0x66, 0x4f, 0x48, 0x69, 0x46, 0x42, 0x61, 0x72, 0x38,
+    0x6a, 0x41, 0x51, 0x72, 0x39, 0x48, 0x58, 0x2f, 0x56, 0x73, 0x0a, 0x61,
+    0x6f, 0x62, 0x67, 0x78, 0x43, 0x64, 0x30, 0x35, 0x44, 0x68, 0x54, 0x31,
+    0x77, 0x56, 0x2f, 0x47, 0x7a, 0x54, 0x6a, 0x78, 0x69, 0x2b, 0x7a, 0x79,
+    0x67, 0x6b, 0x38, 0x4e, 0x35, 0x33, 0x58, 0x35, 0x37, 0x68, 0x47, 0x38,
+    0x66, 0x32, 0x68, 0x34, 0x6e, 0x45, 0x43, 0x4d, 0x45, 0x4a, 0x5a, 0x68,
+    0x30, 0x50, 0x55, 0x55, 0x64, 0x2b, 0x36, 0x30, 0x77, 0x6b, 0x79, 0x57,
+    0x73, 0x36, 0x49, 0x0a, 0x66, 0x6c, 0x63, 0x39, 0x6e, 0x46, 0x39, 0x43,
+    0x61, 0x2f, 0x55, 0x48, 0x4c, 0x62, 0x58, 0x77, 0x67, 0x70, 0x50, 0x35,
+    0x57, 0x57, 0x2b, 0x75, 0x5a, 0x50, 0x70, 0x59, 0x35, 0x59, 0x73, 0x65,
+    0x34, 0x32, 0x4f, 0x2b, 0x74, 0x59, 0x48, 0x4e, 0x62, 0x77, 0x4b, 0x4d,
+    0x65, 0x51, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e,
+    0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54,
+    0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73,
+    0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x74, 0x61,
+    0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+    0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x53, 0x74, 0x61, 0x72,
+    0x74, 0x43, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x20, 0x4f, 0x55,
+    0x3d, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x44, 0x69, 0x67, 0x69,
+    0x74, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+    0x61, 0x74, 0x65, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x0a,
+    0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43,
+    0x4e, 0x3d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43,
+    0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+    0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f,
+    0x3d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x4c, 0x74,
+    0x64, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65,
+    0x20, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72,
+    0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69, 0x67,
+    0x6e, 0x69, 0x6e, 0x67, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c,
+    0x3a, 0x20, 0x22, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20,
+    0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+    0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22,
+    0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x34,
+    0x35, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67,
+    0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x39, 0x3a,
+    0x33, 0x62, 0x3a, 0x30, 0x64, 0x3a, 0x38, 0x34, 0x3a, 0x34, 0x31, 0x3a,
+    0x66, 0x63, 0x3a, 0x61, 0x34, 0x3a, 0x37, 0x36, 0x3a, 0x37, 0x39, 0x3a,
+    0x32, 0x33, 0x3a, 0x30, 0x38, 0x3a, 0x35, 0x37, 0x3a, 0x64, 0x65, 0x3a,
+    0x31, 0x30, 0x3a, 0x31, 0x39, 0x3a, 0x31, 0x36, 0x0a, 0x23, 0x20, 0x53,
+    0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x33, 0x3a, 0x66, 0x31, 0x3a, 0x33,
+    0x33, 0x3a, 0x33, 0x66, 0x3a, 0x65, 0x32, 0x3a, 0x34, 0x32, 0x3a, 0x62,
+    0x66, 0x3a, 0x63, 0x66, 0x3a, 0x63, 0x35, 0x3a, 0x64, 0x31, 0x3a, 0x34,
+    0x65, 0x3a, 0x38, 0x66, 0x3a, 0x33, 0x39, 0x3a, 0x34, 0x32, 0x3a, 0x39,
+    0x38, 0x3a, 0x34, 0x30, 0x3a, 0x36, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x64,
+    0x31, 0x3a, 0x61, 0x30, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35,
+    0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x3a, 0x20, 0x65, 0x31, 0x3a, 0x37, 0x38, 0x3a, 0x39, 0x30, 0x3a,
+    0x65, 0x65, 0x3a, 0x30, 0x39, 0x3a, 0x61, 0x33, 0x3a, 0x66, 0x62, 0x3a,
+    0x66, 0x34, 0x3a, 0x66, 0x34, 0x3a, 0x38, 0x62, 0x3a, 0x39, 0x63, 0x3a,
+    0x34, 0x31, 0x3a, 0x34, 0x61, 0x3a, 0x31, 0x37, 0x3a, 0x64, 0x36, 0x3a,
+    0x33, 0x37, 0x3a, 0x62, 0x37, 0x3a, 0x61, 0x35, 0x3a, 0x30, 0x36, 0x3a,
+    0x34, 0x37, 0x3a, 0x65, 0x39, 0x3a, 0x62, 0x63, 0x3a, 0x37, 0x35, 0x3a,
+    0x32, 0x33, 0x3a, 0x32, 0x32, 0x3a, 0x37, 0x32, 0x3a, 0x37, 0x66, 0x3a,
+    0x63, 0x63, 0x3a, 0x31, 0x37, 0x3a, 0x34, 0x32, 0x3a, 0x61, 0x39, 0x3a,
+    0x31, 0x31, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49,
+    0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54,
+    0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x48, 0x68,
+    0x7a, 0x43, 0x43, 0x42, 0x57, 0x2b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41,
+    0x67, 0x49, 0x42, 0x4c, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68,
+    0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41,
+    0x44, 0x42, 0x39, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x4a, 0x54, 0x44, 0x45, 0x57, 0x0a,
+    0x4d, 0x42, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4e,
+    0x55, 0x33, 0x52, 0x68, 0x63, 0x6e, 0x52, 0x44, 0x62, 0x32, 0x30, 0x67,
+    0x54, 0x48, 0x52, 0x6b, 0x4c, 0x6a, 0x45, 0x72, 0x4d, 0x43, 0x6b, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x69, 0x55, 0x32, 0x56, 0x6a,
+    0x64, 0x58, 0x4a, 0x6c, 0x49, 0x45, 0x52, 0x70, 0x5a, 0x32, 0x6c, 0x30,
+    0x59, 0x57, 0x77, 0x67, 0x0a, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c,
+    0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x55, 0x67, 0x55, 0x32, 0x6c,
+    0x6e, 0x62, 0x6d, 0x6c, 0x75, 0x5a, 0x7a, 0x45, 0x70, 0x4d, 0x43, 0x63,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x67, 0x55, 0x33, 0x52,
+    0x68, 0x63, 0x6e, 0x52, 0x44, 0x62, 0x32, 0x30, 0x67, 0x51, 0x32, 0x56,
+    0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x0a, 0x64, 0x47,
+    0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33,
+    0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44,
+    0x59, 0x77, 0x4f, 0x54, 0x45, 0x33, 0x4d, 0x54, 0x6b, 0x30, 0x4e, 0x6a,
+    0x4d, 0x33, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x59, 0x77, 0x4f, 0x54,
+    0x45, 0x33, 0x4d, 0x54, 0x6b, 0x30, 0x4e, 0x6a, 0x4d, 0x32, 0x57, 0x6a,
+    0x42, 0x39, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56,
+    0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x4a, 0x54, 0x44, 0x45, 0x57, 0x4d,
+    0x42, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4e, 0x55,
+    0x33, 0x52, 0x68, 0x63, 0x6e, 0x52, 0x44, 0x62, 0x32, 0x30, 0x67, 0x54,
+    0x48, 0x52, 0x6b, 0x4c, 0x6a, 0x45, 0x72, 0x4d, 0x43, 0x6b, 0x47, 0x41,
+    0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x69, 0x0a, 0x55, 0x32, 0x56, 0x6a,
+    0x64, 0x58, 0x4a, 0x6c, 0x49, 0x45, 0x52, 0x70, 0x5a, 0x32, 0x6c, 0x30,
+    0x59, 0x57, 0x77, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d,
+    0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x55, 0x67, 0x55, 0x32, 0x6c, 0x6e,
+    0x62, 0x6d, 0x6c, 0x75, 0x5a, 0x7a, 0x45, 0x70, 0x4d, 0x43, 0x63, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x67, 0x55, 0x33, 0x52, 0x68,
+    0x0a, 0x63, 0x6e, 0x52, 0x44, 0x62, 0x32, 0x30, 0x67, 0x51, 0x32, 0x56,
+    0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c,
+    0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a,
+    0x70, 0x64, 0x48, 0x6b, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30,
+    0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45,
+    0x42, 0x41, 0x51, 0x55, 0x41, 0x0a, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77,
+    0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51,
+    0x44, 0x42, 0x69, 0x4e, 0x73, 0x4a, 0x76, 0x47, 0x78, 0x47, 0x66, 0x48,
+    0x69, 0x66, 0x6c, 0x58, 0x75, 0x31, 0x4d, 0x35, 0x44, 0x79, 0x63, 0x6d,
+    0x4c, 0x57, 0x77, 0x54, 0x59, 0x67, 0x49, 0x69, 0x52, 0x65, 0x7a, 0x75,
+    0x6c, 0x33, 0x38, 0x6b, 0x4d, 0x4b, 0x6f, 0x67, 0x5a, 0x6b, 0x0a, 0x70,
+    0x4d, 0x79, 0x4f, 0x4e, 0x76, 0x67, 0x34, 0x35, 0x69, 0x50, 0x77, 0x62,
+    0x6d, 0x32, 0x78, 0x50, 0x4e, 0x31, 0x79, 0x6f, 0x34, 0x55, 0x63, 0x6f,
+    0x64, 0x4d, 0x39, 0x74, 0x44, 0x4d, 0x72, 0x30, 0x79, 0x2b, 0x76, 0x2f,
+    0x75, 0x71, 0x77, 0x51, 0x56, 0x6c, 0x6e, 0x74, 0x73, 0x51, 0x47, 0x66,
+    0x51, 0x71, 0x65, 0x64, 0x49, 0x58, 0x57, 0x65, 0x55, 0x79, 0x41, 0x4e,
+    0x33, 0x72, 0x66, 0x0a, 0x4f, 0x51, 0x56, 0x53, 0x57, 0x66, 0x66, 0x30,
+    0x47, 0x30, 0x5a, 0x44, 0x70, 0x4e, 0x4b, 0x46, 0x68, 0x64, 0x4c, 0x44,
+    0x63, 0x66, 0x4e, 0x31, 0x59, 0x6a, 0x53, 0x36, 0x4c, 0x49, 0x70, 0x2f,
+    0x48, 0x6f, 0x2f, 0x75, 0x37, 0x54, 0x54, 0x51, 0x45, 0x63, 0x65, 0x57,
+    0x7a, 0x56, 0x49, 0x39, 0x75, 0x6a, 0x50, 0x57, 0x33, 0x55, 0x33, 0x65,
+    0x43, 0x7a, 0x74, 0x4b, 0x53, 0x35, 0x2f, 0x43, 0x0a, 0x4a, 0x69, 0x2f,
+    0x36, 0x74, 0x52, 0x59, 0x63, 0x63, 0x6a, 0x56, 0x33, 0x79, 0x6a, 0x78,
+    0x64, 0x35, 0x73, 0x72, 0x68, 0x4a, 0x6f, 0x73, 0x61, 0x4e, 0x6e, 0x5a,
+    0x63, 0x41, 0x64, 0x74, 0x30, 0x46, 0x43, 0x58, 0x2b, 0x37, 0x62, 0x57,
+    0x67, 0x69, 0x41, 0x2f, 0x64, 0x65, 0x4d, 0x6f, 0x74, 0x48, 0x77, 0x65,
+    0x58, 0x4d, 0x41, 0x45, 0x74, 0x63, 0x6e, 0x6e, 0x36, 0x52, 0x74, 0x59,
+    0x54, 0x0a, 0x4b, 0x71, 0x69, 0x35, 0x70, 0x71, 0x75, 0x44, 0x53, 0x52,
+    0x33, 0x6c, 0x38, 0x75, 0x2f, 0x64, 0x35, 0x41, 0x47, 0x4f, 0x47, 0x41,
+    0x71, 0x50, 0x59, 0x31, 0x4d, 0x57, 0x68, 0x57, 0x4b, 0x70, 0x44, 0x68,
+    0x6b, 0x36, 0x7a, 0x4c, 0x56, 0x6d, 0x70, 0x73, 0x4a, 0x72, 0x64, 0x41,
+    0x66, 0x6b, 0x4b, 0x2b, 0x46, 0x32, 0x50, 0x72, 0x52, 0x74, 0x32, 0x50,
+    0x5a, 0x45, 0x34, 0x58, 0x4e, 0x69, 0x0a, 0x48, 0x7a, 0x76, 0x45, 0x76,
+    0x71, 0x42, 0x54, 0x56, 0x69, 0x56, 0x73, 0x55, 0x51, 0x6e, 0x33, 0x71,
+    0x71, 0x76, 0x4b, 0x76, 0x33, 0x62, 0x39, 0x62, 0x5a, 0x76, 0x7a, 0x6e,
+    0x64, 0x75, 0x2f, 0x50, 0x57, 0x61, 0x38, 0x44, 0x46, 0x61, 0x71, 0x72,
+    0x35, 0x68, 0x49, 0x6c, 0x54, 0x70, 0x4c, 0x33, 0x36, 0x64, 0x59, 0x55,
+    0x4e, 0x6b, 0x34, 0x64, 0x61, 0x6c, 0x62, 0x36, 0x6b, 0x4d, 0x4d, 0x0a,
+    0x41, 0x76, 0x2b, 0x5a, 0x36, 0x2b, 0x68, 0x73, 0x54, 0x58, 0x42, 0x62,
+    0x4b, 0x57, 0x57, 0x63, 0x33, 0x61, 0x70, 0x64, 0x7a, 0x4b, 0x38, 0x42,
+    0x4d, 0x65, 0x77, 0x4d, 0x36, 0x39, 0x4b, 0x4e, 0x36, 0x4f, 0x71, 0x63,
+    0x65, 0x2b, 0x5a, 0x75, 0x39, 0x79, 0x64, 0x6d, 0x44, 0x42, 0x70, 0x49,
+    0x31, 0x32, 0x35, 0x43, 0x34, 0x7a, 0x2f, 0x65, 0x49, 0x54, 0x35, 0x37,
+    0x34, 0x51, 0x31, 0x77, 0x0a, 0x2b, 0x32, 0x4f, 0x71, 0x71, 0x47, 0x77,
+    0x61, 0x56, 0x4c, 0x52, 0x63, 0x4a, 0x58, 0x72, 0x4a, 0x6f, 0x73, 0x6d,
+    0x4c, 0x46, 0x71, 0x61, 0x37, 0x4c, 0x48, 0x34, 0x58, 0x58, 0x67, 0x56,
+    0x4e, 0x57, 0x47, 0x34, 0x53, 0x48, 0x51, 0x48, 0x75, 0x45, 0x68, 0x41,
+    0x4e, 0x78, 0x6a, 0x4a, 0x2f, 0x47, 0x50, 0x2f, 0x38, 0x39, 0x50, 0x72,
+    0x4e, 0x62, 0x70, 0x48, 0x6f, 0x4e, 0x6b, 0x6d, 0x2b, 0x0a, 0x47, 0x6b,
+    0x68, 0x70, 0x69, 0x38, 0x4b, 0x57, 0x54, 0x52, 0x6f, 0x53, 0x73, 0x6d,
+    0x6b, 0x58, 0x77, 0x51, 0x71, 0x51, 0x31, 0x76, 0x70, 0x35, 0x49, 0x6b,
+    0x69, 0x2f, 0x75, 0x6e, 0x74, 0x70, 0x2b, 0x48, 0x44, 0x48, 0x2b, 0x6e,
+    0x6f, 0x33, 0x32, 0x4e, 0x67, 0x4e, 0x30, 0x6e, 0x5a, 0x50, 0x56, 0x2f,
+    0x2b, 0x51, 0x74, 0x2b, 0x4f, 0x52, 0x30, 0x74, 0x33, 0x76, 0x77, 0x6d,
+    0x43, 0x33, 0x0a, 0x5a, 0x7a, 0x72, 0x64, 0x2f, 0x71, 0x71, 0x63, 0x38,
+    0x4e, 0x53, 0x4c, 0x66, 0x33, 0x49, 0x69, 0x7a, 0x73, 0x61, 0x66, 0x6c,
+    0x37, 0x62, 0x34, 0x72, 0x34, 0x71, 0x67, 0x45, 0x4b, 0x6a, 0x5a, 0x2b,
+    0x78, 0x6a, 0x47, 0x74, 0x72, 0x56, 0x63, 0x55, 0x6a, 0x79, 0x4a, 0x74,
+    0x68, 0x6b, 0x71, 0x63, 0x77, 0x45, 0x4b, 0x44, 0x77, 0x4f, 0x7a, 0x45,
+    0x6d, 0x44, 0x79, 0x65, 0x69, 0x2b, 0x42, 0x0a, 0x32, 0x36, 0x4e, 0x75,
+    0x2f, 0x79, 0x59, 0x77, 0x6c, 0x2f, 0x57, 0x4c, 0x33, 0x59, 0x6c, 0x58,
+    0x74, 0x71, 0x30, 0x39, 0x73, 0x36, 0x38, 0x72, 0x78, 0x62, 0x64, 0x32,
+    0x41, 0x76, 0x43, 0x6c, 0x31, 0x69, 0x75, 0x61, 0x68, 0x68, 0x51, 0x71,
+    0x63, 0x76, 0x62, 0x6a, 0x4d, 0x34, 0x78, 0x64, 0x43, 0x55, 0x73, 0x54,
+    0x33, 0x37, 0x75, 0x4d, 0x64, 0x42, 0x4e, 0x53, 0x53, 0x77, 0x49, 0x44,
+    0x0a, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x34, 0x49, 0x43, 0x45, 0x44, 0x43,
+    0x43, 0x41, 0x67, 0x77, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30,
+    0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45,
+    0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38,
+    0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59,
+    0x77, 0x48, 0x51, 0x59, 0x44, 0x0a, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42,
+    0x59, 0x45, 0x46, 0x45, 0x34, 0x4c, 0x37, 0x78, 0x71, 0x6b, 0x51, 0x46,
+    0x75, 0x6c, 0x46, 0x32, 0x6d, 0x48, 0x4d, 0x4d, 0x6f, 0x30, 0x61, 0x45,
+    0x50, 0x51, 0x51, 0x61, 0x37, 0x79, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31,
+    0x55, 0x64, 0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, 0x61, 0x41, 0x46, 0x45,
+    0x34, 0x4c, 0x37, 0x78, 0x71, 0x6b, 0x51, 0x46, 0x75, 0x6c, 0x0a, 0x46,
+    0x32, 0x6d, 0x48, 0x4d, 0x4d, 0x6f, 0x30, 0x61, 0x45, 0x50, 0x51, 0x51,
+    0x61, 0x37, 0x79, 0x4d, 0x49, 0x49, 0x42, 0x57, 0x67, 0x59, 0x44, 0x56,
+    0x52, 0x30, 0x67, 0x42, 0x49, 0x49, 0x42, 0x55, 0x54, 0x43, 0x43, 0x41,
+    0x55, 0x30, 0x77, 0x67, 0x67, 0x46, 0x4a, 0x42, 0x67, 0x73, 0x72, 0x42,
+    0x67, 0x45, 0x45, 0x41, 0x59, 0x47, 0x31, 0x4e, 0x77, 0x45, 0x42, 0x41,
+    0x54, 0x43, 0x43, 0x0a, 0x41, 0x54, 0x67, 0x77, 0x4c, 0x67, 0x59, 0x49,
+    0x4b, 0x77, 0x59, 0x42, 0x42, 0x51, 0x55, 0x48, 0x41, 0x67, 0x45, 0x57,
+    0x49, 0x6d, 0x68, 0x30, 0x64, 0x48, 0x41, 0x36, 0x4c, 0x79, 0x39, 0x33,
+    0x64, 0x33, 0x63, 0x75, 0x63, 0x33, 0x52, 0x68, 0x63, 0x6e, 0x52, 0x7a,
+    0x63, 0x32, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x33, 0x42, 0x76,
+    0x62, 0x47, 0x6c, 0x6a, 0x65, 0x53, 0x35, 0x77, 0x0a, 0x5a, 0x47, 0x59,
+    0x77, 0x4e, 0x41, 0x59, 0x49, 0x4b, 0x77, 0x59, 0x42, 0x42, 0x51, 0x55,
+    0x48, 0x41, 0x67, 0x45, 0x57, 0x4b, 0x47, 0x68, 0x30, 0x64, 0x48, 0x41,
+    0x36, 0x4c, 0x79, 0x39, 0x33, 0x64, 0x33, 0x63, 0x75, 0x63, 0x33, 0x52,
+    0x68, 0x63, 0x6e, 0x52, 0x7a, 0x63, 0x32, 0x77, 0x75, 0x59, 0x32, 0x39,
+    0x74, 0x4c, 0x32, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x79, 0x62, 0x57, 0x56,
+    0x6b, 0x0a, 0x61, 0x57, 0x46, 0x30, 0x5a, 0x53, 0x35, 0x77, 0x5a, 0x47,
+    0x59, 0x77, 0x67, 0x63, 0x38, 0x47, 0x43, 0x43, 0x73, 0x47, 0x41, 0x51,
+    0x55, 0x46, 0x42, 0x77, 0x49, 0x43, 0x4d, 0x49, 0x48, 0x43, 0x4d, 0x43,
+    0x63, 0x57, 0x49, 0x46, 0x4e, 0x30, 0x59, 0x58, 0x4a, 0x30, 0x49, 0x45,
+    0x4e, 0x76, 0x62, 0x57, 0x31, 0x6c, 0x63, 0x6d, 0x4e, 0x70, 0x59, 0x57,
+    0x77, 0x67, 0x4b, 0x46, 0x4e, 0x30, 0x0a, 0x59, 0x58, 0x4a, 0x30, 0x51,
+    0x32, 0x39, 0x74, 0x4b, 0x53, 0x42, 0x4d, 0x64, 0x47, 0x51, 0x75, 0x4d,
+    0x41, 0x4d, 0x43, 0x41, 0x51, 0x45, 0x61, 0x67, 0x5a, 0x5a, 0x4d, 0x61,
+    0x57, 0x31, 0x70, 0x64, 0x47, 0x56, 0x6b, 0x49, 0x45, 0x78, 0x70, 0x59,
+    0x57, 0x4a, 0x70, 0x62, 0x47, 0x6c, 0x30, 0x65, 0x53, 0x77, 0x67, 0x63,
+    0x6d, 0x56, 0x68, 0x5a, 0x43, 0x42, 0x30, 0x61, 0x47, 0x55, 0x67, 0x0a,
+    0x63, 0x32, 0x56, 0x6a, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x41, 0x71,
+    0x54, 0x47, 0x56, 0x6e, 0x59, 0x57, 0x77, 0x67, 0x54, 0x47, 0x6c, 0x74,
+    0x61, 0x58, 0x52, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6e, 0x4d, 0x71,
+    0x49, 0x47, 0x39, 0x6d, 0x49, 0x48, 0x52, 0x6f, 0x5a, 0x53, 0x42, 0x54,
+    0x64, 0x47, 0x46, 0x79, 0x64, 0x45, 0x4e, 0x76, 0x62, 0x53, 0x42, 0x44,
+    0x5a, 0x58, 0x4a, 0x30, 0x0a, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46,
+    0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68,
+    0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x53, 0x42, 0x51, 0x62, 0x32, 0x78,
+    0x70, 0x59, 0x33, 0x6b, 0x67, 0x59, 0x58, 0x5a, 0x68, 0x61, 0x57, 0x78,
+    0x68, 0x59, 0x6d, 0x78, 0x6c, 0x49, 0x47, 0x46, 0x30, 0x49, 0x47, 0x68,
+    0x30, 0x64, 0x48, 0x41, 0x36, 0x4c, 0x79, 0x39, 0x33, 0x0a, 0x64, 0x33,
+    0x63, 0x75, 0x63, 0x33, 0x52, 0x68, 0x63, 0x6e, 0x52, 0x7a, 0x63, 0x32,
+    0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x33, 0x42, 0x76, 0x62, 0x47,
+    0x6c, 0x6a, 0x65, 0x53, 0x35, 0x77, 0x5a, 0x47, 0x59, 0x77, 0x45, 0x51,
+    0x59, 0x4a, 0x59, 0x49, 0x5a, 0x49, 0x41, 0x59, 0x62, 0x34, 0x51, 0x67,
+    0x45, 0x42, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x41, 0x48, 0x4d, 0x44,
+    0x67, 0x47, 0x0a, 0x43, 0x57, 0x43, 0x47, 0x53, 0x41, 0x47, 0x47, 0x2b,
+    0x45, 0x49, 0x42, 0x44, 0x51, 0x51, 0x72, 0x46, 0x69, 0x6c, 0x54, 0x64,
+    0x47, 0x46, 0x79, 0x64, 0x45, 0x4e, 0x76, 0x62, 0x53, 0x42, 0x47, 0x63,
+    0x6d, 0x56, 0x6c, 0x49, 0x46, 0x4e, 0x54, 0x54, 0x43, 0x42, 0x44, 0x5a,
+    0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61,
+    0x57, 0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x0a, 0x64, 0x47, 0x68, 0x76,
+    0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71,
+    0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46,
+    0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, 0x6a, 0x6f, 0x2f, 0x6e,
+    0x33, 0x4a, 0x52, 0x35, 0x66, 0x50, 0x47, 0x46, 0x66, 0x35, 0x39, 0x4a,
+    0x62, 0x32, 0x76, 0x4b, 0x58, 0x66, 0x75, 0x4d, 0x2f, 0x67, 0x54, 0x46,
+    0x0a, 0x77, 0x57, 0x4c, 0x52, 0x66, 0x55, 0x4b, 0x4b, 0x76, 0x46, 0x4f,
+    0x33, 0x6c, 0x41, 0x4e, 0x6d, 0x4d, 0x44, 0x2b, 0x78, 0x35, 0x77, 0x71,
+    0x6e, 0x55, 0x43, 0x42, 0x56, 0x4a, 0x58, 0x39, 0x32, 0x65, 0x68, 0x51,
+    0x4e, 0x36, 0x77, 0x51, 0x4f, 0x51, 0x4f, 0x59, 0x2b, 0x32, 0x49, 0x69,
+    0x72, 0x42, 0x79, 0x65, 0x44, 0x71, 0x58, 0x57, 0x6d, 0x4e, 0x33, 0x50,
+    0x48, 0x2f, 0x55, 0x76, 0x53, 0x0a, 0x54, 0x61, 0x30, 0x58, 0x51, 0x4d,
+    0x68, 0x47, 0x76, 0x6a, 0x74, 0x2f, 0x55, 0x66, 0x7a, 0x44, 0x74, 0x67,
+    0x55, 0x78, 0x33, 0x4d, 0x32, 0x46, 0x49, 0x6b, 0x35, 0x78, 0x74, 0x2f,
+    0x4a, 0x78, 0x58, 0x72, 0x41, 0x61, 0x78, 0x72, 0x71, 0x54, 0x69, 0x33,
+    0x69, 0x53, 0x53, 0x6f, 0x58, 0x34, 0x65, 0x41, 0x2b, 0x44, 0x2f, 0x69,
+    0x2b, 0x74, 0x4c, 0x50, 0x66, 0x6b, 0x70, 0x4c, 0x73, 0x74, 0x0a, 0x30,
+    0x4f, 0x63, 0x4e, 0x4f, 0x72, 0x67, 0x2b, 0x7a, 0x76, 0x5a, 0x34, 0x39,
+    0x71, 0x35, 0x48, 0x4a, 0x4d, 0x71, 0x6a, 0x4e, 0x54, 0x62, 0x4f, 0x78,
+    0x38, 0x61, 0x48, 0x6d, 0x4e, 0x72, 0x73, 0x2b, 0x2b, 0x6d, 0x79, 0x7a,
+    0x69, 0x65, 0x62, 0x69, 0x4d, 0x4d, 0x45, 0x6f, 0x66, 0x59, 0x4c, 0x57,
+    0x57, 0x69, 0x76, 0x79, 0x64, 0x73, 0x51, 0x44, 0x30, 0x33, 0x32, 0x5a,
+    0x47, 0x4e, 0x63, 0x0a, 0x70, 0x52, 0x4a, 0x76, 0x6b, 0x72, 0x4b, 0x54,
+    0x6c, 0x4d, 0x65, 0x49, 0x46, 0x77, 0x36, 0x54, 0x74, 0x6e, 0x35, 0x69,
+    0x69, 0x35, 0x42, 0x2f, 0x71, 0x30, 0x36, 0x66, 0x2f, 0x4f, 0x4e, 0x31,
+    0x46, 0x45, 0x38, 0x71, 0x4d, 0x74, 0x39, 0x62, 0x44, 0x65, 0x44, 0x31,
+    0x65, 0x35, 0x4d, 0x4e, 0x71, 0x36, 0x48, 0x50, 0x68, 0x2b, 0x47, 0x6c,
+    0x42, 0x45, 0x58, 0x6f, 0x50, 0x42, 0x4b, 0x6c, 0x0a, 0x43, 0x63, 0x57,
+    0x77, 0x30, 0x62, 0x64, 0x54, 0x38, 0x32, 0x41, 0x55, 0x75, 0x6f, 0x56,
+    0x70, 0x61, 0x69, 0x46, 0x38, 0x48, 0x33, 0x56, 0x68, 0x46, 0x79, 0x41,
+    0x58, 0x65, 0x32, 0x77, 0x37, 0x51, 0x53, 0x6c, 0x63, 0x34, 0x61, 0x78,
+    0x61, 0x30, 0x63, 0x32, 0x4d, 0x6d, 0x2b, 0x74, 0x67, 0x48, 0x52, 0x6e,
+    0x73, 0x39, 0x2b, 0x57, 0x77, 0x32, 0x76, 0x6c, 0x35, 0x47, 0x4b, 0x56,
+    0x46, 0x0a, 0x50, 0x30, 0x6c, 0x44, 0x56, 0x39, 0x4c, 0x64, 0x4a, 0x4e,
+    0x55, 0x73, 0x6f, 0x2f, 0x32, 0x52, 0x6a, 0x53, 0x65, 0x31, 0x35, 0x65,
+    0x73, 0x55, 0x42, 0x70, 0x70, 0x4d, 0x65, 0x79, 0x47, 0x37, 0x4f, 0x71,
+    0x30, 0x77, 0x42, 0x68, 0x6a, 0x41, 0x32, 0x4d, 0x46, 0x72, 0x4c, 0x48,
+    0x39, 0x5a, 0x58, 0x46, 0x32, 0x52, 0x73, 0x58, 0x41, 0x69, 0x56, 0x2b,
+    0x75, 0x4b, 0x61, 0x30, 0x68, 0x4b, 0x0a, 0x31, 0x51, 0x38, 0x70, 0x37,
+    0x4d, 0x5a, 0x41, 0x77, 0x43, 0x2b, 0x49, 0x54, 0x47, 0x67, 0x42, 0x46,
+    0x33, 0x66, 0x30, 0x4a, 0x42, 0x6c, 0x50, 0x76, 0x66, 0x72, 0x68, 0x73,
+    0x69, 0x41, 0x68, 0x53, 0x39, 0x30, 0x61, 0x32, 0x43, 0x6c, 0x39, 0x71,
+    0x72, 0x6a, 0x65, 0x56, 0x4f, 0x77, 0x68, 0x56, 0x59, 0x42, 0x73, 0x48,
+    0x76, 0x55, 0x77, 0x79, 0x4b, 0x4d, 0x51, 0x35, 0x62, 0x4c, 0x6d, 0x0a,
+    0x4b, 0x68, 0x51, 0x78, 0x77, 0x34, 0x55, 0x74, 0x6a, 0x4a, 0x69, 0x78,
+    0x68, 0x6c, 0x70, 0x50, 0x69, 0x56, 0x6b, 0x74, 0x75, 0x63, 0x66, 0x33,
+    0x48, 0x4d, 0x69, 0x4b, 0x66, 0x38, 0x43, 0x64, 0x42, 0x55, 0x72, 0x6d,
+    0x51, 0x6b, 0x39, 0x69, 0x6f, 0x32, 0x30, 0x70, 0x70, 0x42, 0x2b, 0x46,
+    0x71, 0x39, 0x76, 0x6c, 0x67, 0x63, 0x69, 0x74, 0x4b, 0x6a, 0x31, 0x4d,
+    0x58, 0x56, 0x75, 0x45, 0x0a, 0x4a, 0x6e, 0x48, 0x45, 0x68, 0x56, 0x35,
+    0x78, 0x4a, 0x4d, 0x71, 0x6c, 0x47, 0x32, 0x7a, 0x59, 0x59, 0x64, 0x4d,
+    0x61, 0x34, 0x46, 0x54, 0x62, 0x7a, 0x72, 0x71, 0x70, 0x4d, 0x72, 0x55,
+    0x69, 0x39, 0x6e, 0x4e, 0x42, 0x43, 0x56, 0x32, 0x34, 0x46, 0x31, 0x30,
+    0x4f, 0x44, 0x35, 0x6d, 0x51, 0x31, 0x6b, 0x66, 0x61, 0x62, 0x77, 0x6f,
+    0x36, 0x59, 0x69, 0x67, 0x55, 0x5a, 0x34, 0x4c, 0x5a, 0x0a, 0x38, 0x64,
+    0x43, 0x41, 0x57, 0x5a, 0x76, 0x4c, 0x4d, 0x64, 0x69, 0x62, 0x44, 0x34,
+    0x78, 0x33, 0x54, 0x72, 0x56, 0x6f, 0x69, 0x76, 0x4a, 0x73, 0x39, 0x69,
+    0x51, 0x4f, 0x4c, 0x57, 0x78, 0x77, 0x78, 0x58, 0x50, 0x52, 0x33, 0x68,
+    0x54, 0x51, 0x63, 0x59, 0x2b, 0x32, 0x30, 0x33, 0x73, 0x43, 0x39, 0x75,
+    0x4f, 0x34, 0x31, 0x41, 0x6c, 0x75, 0x61, 0x35, 0x35, 0x31, 0x68, 0x44,
+    0x6e, 0x6d, 0x0a, 0x66, 0x79, 0x57, 0x6c, 0x38, 0x6b, 0x67, 0x41, 0x77,
+    0x4b, 0x51, 0x42, 0x32, 0x6a, 0x38, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23,
+    0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d,
+    0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x65, 0x72,
+    0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41,
+    0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, 0x20,
+    0x4f, 0x3d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x4c,
+    0x74, 0x64, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63,
+    0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43,
+    0x6f, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+    0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+    0x74, 0x79, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x53, 0x74, 0x61, 0x72,
+    0x74, 0x43, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x0a, 0x23, 0x20,
+    0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x53, 0x74, 0x61, 0x72,
+    0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+    0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+    0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53,
+    0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x35, 0x39, 0x0a, 0x23, 0x20,
+    0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x38, 0x3a, 0x34, 0x62, 0x3a, 0x66,
+    0x62, 0x3a, 0x39, 0x65, 0x3a, 0x36, 0x34, 0x3a, 0x38, 0x32, 0x3a, 0x30,
+    0x61, 0x3a, 0x64, 0x33, 0x3a, 0x62, 0x38, 0x3a, 0x34, 0x63, 0x3a, 0x36,
+    0x32, 0x3a, 0x66, 0x33, 0x3a, 0x36, 0x34, 0x3a, 0x66, 0x32, 0x3a, 0x39,
+    0x30, 0x3a, 0x36, 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20,
+    0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a,
+    0x20, 0x33, 0x31, 0x3a, 0x66, 0x31, 0x3a, 0x66, 0x64, 0x3a, 0x36, 0x38,
+    0x3a, 0x32, 0x32, 0x3a, 0x36, 0x33, 0x3a, 0x32, 0x30, 0x3a, 0x65, 0x65,
+    0x3a, 0x63, 0x36, 0x3a, 0x33, 0x62, 0x3a, 0x33, 0x66, 0x3a, 0x39, 0x64,
+    0x3a, 0x65, 0x61, 0x3a, 0x34, 0x61, 0x3a, 0x33, 0x65, 0x3a, 0x35, 0x33,
+    0x3a, 0x37, 0x63, 0x3a, 0x37, 0x63, 0x3a, 0x33, 0x39, 0x3a, 0x31, 0x37,
+    0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69,
+    0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63,
+    0x37, 0x3a, 0x62, 0x61, 0x3a, 0x36, 0x35, 0x3a, 0x36, 0x37, 0x3a, 0x64,
+    0x65, 0x3a, 0x39, 0x33, 0x3a, 0x61, 0x37, 0x3a, 0x39, 0x38, 0x3a, 0x61,
+    0x65, 0x3a, 0x31, 0x66, 0x3a, 0x61, 0x61, 0x3a, 0x37, 0x39, 0x3a, 0x31,
+    0x65, 0x3a, 0x37, 0x31, 0x3a, 0x32, 0x64, 0x3a, 0x33, 0x37, 0x3a, 0x38,
+    0x66, 0x3a, 0x61, 0x65, 0x3a, 0x31, 0x66, 0x3a, 0x39, 0x33, 0x3a, 0x63,
+    0x34, 0x3a, 0x33, 0x39, 0x3a, 0x37, 0x66, 0x3a, 0x65, 0x61, 0x3a, 0x34,
+    0x34, 0x3a, 0x31, 0x62, 0x3a, 0x62, 0x37, 0x3a, 0x63, 0x62, 0x3a, 0x65,
+    0x36, 0x3a, 0x66, 0x64, 0x3a, 0x35, 0x39, 0x3a, 0x39, 0x35, 0x0a, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45,
+    0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x59, 0x7a, 0x43, 0x43, 0x41,
+    0x30, 0x75, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x4f,
+    0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39,
+    0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x54, 0x4d,
+    0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45,
+    0x77, 0x4a, 0x4a, 0x54, 0x44, 0x45, 0x57, 0x0a, 0x4d, 0x42, 0x51, 0x47,
+    0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4e, 0x55, 0x33, 0x52, 0x68,
+    0x63, 0x6e, 0x52, 0x44, 0x62, 0x32, 0x30, 0x67, 0x54, 0x48, 0x52, 0x6b,
+    0x4c, 0x6a, 0x45, 0x73, 0x4d, 0x43, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x45,
+    0x41, 0x78, 0x4d, 0x6a, 0x55, 0x33, 0x52, 0x68, 0x63, 0x6e, 0x52, 0x44,
+    0x62, 0x32, 0x30, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d,
+    0x0a, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42,
+    0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b,
+    0x67, 0x52, 0x7a, 0x49, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x41,
+    0x77, 0x4d, 0x54, 0x41, 0x78, 0x4d, 0x44, 0x45, 0x77, 0x4d, 0x44, 0x41,
+    0x78, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x6b, 0x78, 0x4d, 0x6a, 0x4d,
+    0x78, 0x4d, 0x6a, 0x4d, 0x31, 0x0a, 0x4f, 0x54, 0x41, 0x78, 0x57, 0x6a,
+    0x42, 0x54, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x47, 0x45, 0x77, 0x4a, 0x4a, 0x54, 0x44, 0x45, 0x57, 0x4d, 0x42,
+    0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4e, 0x55, 0x33,
+    0x52, 0x68, 0x63, 0x6e, 0x52, 0x44, 0x62, 0x32, 0x30, 0x67, 0x54, 0x48,
+    0x52, 0x6b, 0x4c, 0x6a, 0x45, 0x73, 0x4d, 0x43, 0x6f, 0x47, 0x0a, 0x41,
+    0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x6a, 0x55, 0x33, 0x52, 0x68, 0x63,
+    0x6e, 0x52, 0x44, 0x62, 0x32, 0x30, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64,
+    0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62,
+    0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64,
+    0x48, 0x6b, 0x67, 0x52, 0x7a, 0x49, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d,
+    0x41, 0x30, 0x47, 0x0a, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33,
+    0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43,
+    0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43,
+    0x41, 0x51, 0x43, 0x32, 0x69, 0x54, 0x5a, 0x62, 0x42, 0x37, 0x63, 0x67,
+    0x4e, 0x72, 0x32, 0x43, 0x75, 0x2b, 0x45, 0x57, 0x49, 0x41, 0x4f, 0x56,
+    0x65, 0x71, 0x38, 0x4f, 0x6f, 0x31, 0x58, 0x4a, 0x0a, 0x4a, 0x5a, 0x6c,
+    0x4b, 0x78, 0x64, 0x42, 0x57, 0x51, 0x59, 0x65, 0x51, 0x54, 0x53, 0x46,
+    0x67, 0x70, 0x42, 0x53, 0x48, 0x4f, 0x38, 0x33, 0x39, 0x73, 0x6a, 0x36,
+    0x30, 0x5a, 0x77, 0x4e, 0x71, 0x37, 0x65, 0x45, 0x50, 0x53, 0x38, 0x43,
+    0x52, 0x68, 0x58, 0x42, 0x46, 0x34, 0x45, 0x4b, 0x65, 0x33, 0x69, 0x6b,
+    0x6a, 0x31, 0x41, 0x45, 0x4e, 0x6f, 0x42, 0x42, 0x35, 0x75, 0x4e, 0x73,
+    0x44, 0x0a, 0x76, 0x66, 0x4f, 0x70, 0x4c, 0x39, 0x48, 0x47, 0x34, 0x41,
+    0x2f, 0x4c, 0x6e, 0x6f, 0x6f, 0x55, 0x43, 0x72, 0x69, 0x39, 0x39, 0x6c,
+    0x5a, 0x69, 0x38, 0x63, 0x56, 0x79, 0x74, 0x6a, 0x49, 0x6c, 0x32, 0x62,
+    0x4c, 0x7a, 0x76, 0x57, 0x58, 0x46, 0x44, 0x53, 0x78, 0x75, 0x31, 0x5a,
+    0x4a, 0x76, 0x47, 0x49, 0x73, 0x41, 0x51, 0x52, 0x53, 0x43, 0x62, 0x30,
+    0x41, 0x67, 0x4a, 0x6e, 0x6f, 0x6f, 0x0a, 0x44, 0x2f, 0x55, 0x65, 0x66,
+    0x79, 0x66, 0x33, 0x6c, 0x4c, 0x45, 0x33, 0x50, 0x62, 0x66, 0x48, 0x6b,
+    0x66, 0x66, 0x69, 0x41, 0x65, 0x7a, 0x39, 0x6c, 0x49, 0x6e, 0x68, 0x7a,
+    0x47, 0x37, 0x54, 0x4e, 0x74, 0x59, 0x4b, 0x47, 0x58, 0x6d, 0x75, 0x31,
+    0x7a, 0x53, 0x43, 0x5a, 0x66, 0x39, 0x38, 0x51, 0x72, 0x75, 0x32, 0x33,
+    0x51, 0x75, 0x6d, 0x4e, 0x4b, 0x39, 0x4c, 0x59, 0x50, 0x35, 0x2f, 0x0a,
+    0x51, 0x30, 0x6b, 0x47, 0x69, 0x34, 0x78, 0x44, 0x75, 0x46, 0x62, 0x79,
+    0x32, 0x58, 0x38, 0x68, 0x51, 0x78, 0x66, 0x71, 0x70, 0x30, 0x69, 0x56,
+    0x41, 0x58, 0x56, 0x31, 0x36, 0x69, 0x75, 0x6c, 0x51, 0x35, 0x58, 0x71,
+    0x46, 0x59, 0x53, 0x64, 0x43, 0x49, 0x30, 0x6d, 0x62, 0x6c, 0x57, 0x62,
+    0x71, 0x39, 0x7a, 0x53, 0x4f, 0x64, 0x49, 0x78, 0x48, 0x57, 0x44, 0x69,
+    0x72, 0x4d, 0x78, 0x57, 0x0a, 0x52, 0x53, 0x54, 0x31, 0x48, 0x46, 0x53,
+    0x72, 0x37, 0x6f, 0x62, 0x64, 0x6c, 0x6a, 0x4b, 0x46, 0x2b, 0x45, 0x78,
+    0x50, 0x36, 0x4a, 0x56, 0x32, 0x74, 0x67, 0x58, 0x64, 0x4e, 0x69, 0x4e,
+    0x6e, 0x76, 0x50, 0x38, 0x56, 0x34, 0x73, 0x6f, 0x37, 0x35, 0x71, 0x62,
+    0x73, 0x4f, 0x2b, 0x77, 0x6d, 0x45, 0x54, 0x52, 0x49, 0x6a, 0x66, 0x61,
+    0x41, 0x4b, 0x78, 0x6f, 0x6a, 0x41, 0x75, 0x75, 0x4b, 0x0a, 0x48, 0x44,
+    0x70, 0x32, 0x4b, 0x6e, 0x74, 0x57, 0x46, 0x68, 0x78, 0x79, 0x4b, 0x72,
+    0x4f, 0x71, 0x34, 0x32, 0x43, 0x6c, 0x41, 0x4a, 0x38, 0x45, 0x6d, 0x2b,
+    0x4a, 0x76, 0x48, 0x68, 0x52, 0x59, 0x57, 0x36, 0x56, 0x73, 0x69, 0x31,
+    0x67, 0x38, 0x77, 0x37, 0x70, 0x4f, 0x4f, 0x6c, 0x7a, 0x33, 0x34, 0x5a,
+    0x59, 0x72, 0x50, 0x75, 0x38, 0x48, 0x76, 0x4b, 0x54, 0x6c, 0x58, 0x63,
+    0x78, 0x4e, 0x0a, 0x6e, 0x77, 0x33, 0x68, 0x33, 0x4b, 0x71, 0x37, 0x34,
+    0x57, 0x34, 0x61, 0x37, 0x49, 0x2f, 0x68, 0x74, 0x6b, 0x78, 0x4e, 0x65,
+    0x58, 0x4a, 0x64, 0x46, 0x7a, 0x55, 0x4c, 0x48, 0x64, 0x66, 0x42, 0x52,
+    0x39, 0x71, 0x57, 0x4a, 0x4f, 0x44, 0x51, 0x63, 0x71, 0x68, 0x61, 0x58,
+    0x32, 0x59, 0x74, 0x45, 0x4e, 0x77, 0x76, 0x4b, 0x68, 0x4f, 0x75, 0x4a,
+    0x76, 0x34, 0x4b, 0x48, 0x42, 0x6e, 0x4d, 0x0a, 0x30, 0x44, 0x34, 0x4c,
+    0x6e, 0x4d, 0x67, 0x4a, 0x4c, 0x76, 0x6c, 0x62, 0x6c, 0x6e, 0x70, 0x48,
+    0x6e, 0x4f, 0x6c, 0x36, 0x38, 0x77, 0x56, 0x51, 0x64, 0x4a, 0x56, 0x7a,
+    0x6e, 0x6a, 0x41, 0x4a, 0x38, 0x35, 0x65, 0x43, 0x58, 0x75, 0x61, 0x50,
+    0x4f, 0x51, 0x67, 0x65, 0x57, 0x65, 0x55, 0x31, 0x46, 0x45, 0x49, 0x54,
+    0x2f, 0x77, 0x43, 0x63, 0x39, 0x37, 0x36, 0x71, 0x55, 0x4d, 0x2f, 0x69,
+    0x0a, 0x55, 0x55, 0x6a, 0x58, 0x75, 0x47, 0x2b, 0x76, 0x2b, 0x45, 0x35,
+    0x2b, 0x4d, 0x35, 0x69, 0x53, 0x46, 0x47, 0x49, 0x36, 0x64, 0x57, 0x50,
+    0x50, 0x65, 0x2f, 0x72, 0x65, 0x67, 0x6a, 0x75, 0x70, 0x75, 0x7a, 0x6e,
+    0x69, 0x78, 0x4c, 0x30, 0x73, 0x41, 0x41, 0x37, 0x49, 0x46, 0x36, 0x77,
+    0x54, 0x37, 0x30, 0x30, 0x6c, 0x6a, 0x74, 0x69, 0x7a, 0x6b, 0x43, 0x2b,
+    0x70, 0x32, 0x69, 0x6c, 0x39, 0x0a, 0x48, 0x61, 0x39, 0x30, 0x4f, 0x72,
+    0x49, 0x6e, 0x77, 0x4d, 0x45, 0x65, 0x50, 0x6e, 0x57, 0x6a, 0x46, 0x71,
+    0x6d, 0x76, 0x65, 0x69, 0x4a, 0x64, 0x6e, 0x78, 0x4d, 0x61, 0x7a, 0x36,
+    0x65, 0x67, 0x36, 0x2b, 0x4f, 0x47, 0x43, 0x74, 0x50, 0x39, 0x35, 0x70,
+    0x61, 0x56, 0x31, 0x79, 0x50, 0x49, 0x4e, 0x39, 0x33, 0x45, 0x66, 0x4b,
+    0x6f, 0x32, 0x72, 0x4a, 0x67, 0x61, 0x45, 0x72, 0x48, 0x67, 0x0a, 0x54,
+    0x75, 0x69, 0x78, 0x4f, 0x2f, 0x58, 0x57, 0x62, 0x2f, 0x45, 0x77, 0x31,
+    0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51,
+    0x44, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41,
+    0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d,
+    0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f,
+    0x77, 0x51, 0x45, 0x0a, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x64,
+    0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55,
+    0x53, 0x38, 0x57, 0x30, 0x51, 0x47, 0x75, 0x74, 0x48, 0x4c, 0x4f, 0x6c,
+    0x48, 0x47, 0x56, 0x75, 0x52, 0x6a, 0x61, 0x4a, 0x68, 0x77, 0x55, 0x4d,
+    0x44, 0x72, 0x59, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49,
+    0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x0a, 0x42, 0x51, 0x41,
+    0x44, 0x67, 0x67, 0x49, 0x42, 0x41, 0x48, 0x4e, 0x58, 0x50, 0x79, 0x7a,
+    0x56, 0x6c, 0x54, 0x4a, 0x2b, 0x4e, 0x39, 0x75, 0x57, 0x6b, 0x75, 0x73,
+    0x5a, 0x58, 0x6e, 0x35, 0x54, 0x35, 0x30, 0x48, 0x73, 0x45, 0x62, 0x5a,
+    0x48, 0x37, 0x37, 0x58, 0x65, 0x37, 0x58, 0x52, 0x63, 0x78, 0x66, 0x47,
+    0x4f, 0x53, 0x65, 0x44, 0x38, 0x62, 0x70, 0x6b, 0x54, 0x7a, 0x5a, 0x2b,
+    0x4b, 0x0a, 0x32, 0x73, 0x30, 0x36, 0x43, 0x74, 0x67, 0x36, 0x57, 0x67,
+    0x6b, 0x2f, 0x58, 0x7a, 0x54, 0x51, 0x4c, 0x77, 0x50, 0x53, 0x5a, 0x68,
+    0x30, 0x61, 0x76, 0x5a, 0x79, 0x51, 0x4e, 0x38, 0x67, 0x4d, 0x6a, 0x67,
+    0x64, 0x61, 0x6c, 0x45, 0x56, 0x47, 0x4b, 0x75, 0x61, 0x2b, 0x65, 0x74,
+    0x71, 0x68, 0x71, 0x61, 0x52, 0x70, 0x45, 0x70, 0x4b, 0x77, 0x66, 0x54,
+    0x62, 0x55, 0x52, 0x49, 0x66, 0x58, 0x0a, 0x55, 0x66, 0x45, 0x70, 0x59,
+    0x39, 0x5a, 0x31, 0x7a, 0x52, 0x62, 0x6b, 0x4a, 0x34, 0x6b, 0x64, 0x2b,
+    0x4d, 0x49, 0x79, 0x53, 0x50, 0x33, 0x62, 0x6d, 0x64, 0x43, 0x50, 0x58,
+    0x31, 0x52, 0x30, 0x7a, 0x4b, 0x78, 0x6e, 0x4e, 0x42, 0x46, 0x69, 0x32,
+    0x51, 0x77, 0x4b, 0x4e, 0x34, 0x66, 0x52, 0x6f, 0x78, 0x64, 0x49, 0x6a,
+    0x74, 0x49, 0x58, 0x48, 0x66, 0x62, 0x58, 0x2f, 0x64, 0x74, 0x6c, 0x0a,
+    0x36, 0x2f, 0x32, 0x6f, 0x31, 0x50, 0x58, 0x57, 0x54, 0x36, 0x52, 0x62,
+    0x64, 0x65, 0x6a, 0x46, 0x30, 0x6d, 0x43, 0x79, 0x32, 0x77, 0x6c, 0x2b,
+    0x4a, 0x59, 0x74, 0x37, 0x75, 0x6c, 0x4b, 0x53, 0x6e, 0x6a, 0x37, 0x6f,
+    0x78, 0x58, 0x65, 0x68, 0x50, 0x4f, 0x42, 0x4b, 0x63, 0x32, 0x74, 0x68,
+    0x7a, 0x34, 0x62, 0x63, 0x51, 0x2f, 0x2f, 0x2f, 0x49, 0x66, 0x34, 0x6a,
+    0x58, 0x53, 0x52, 0x4b, 0x0a, 0x39, 0x64, 0x4e, 0x74, 0x44, 0x32, 0x49,
+    0x45, 0x42, 0x56, 0x65, 0x43, 0x32, 0x6d, 0x36, 0x6b, 0x4d, 0x79, 0x56,
+    0x35, 0x53, 0x79, 0x35, 0x55, 0x47, 0x59, 0x76, 0x4d, 0x4c, 0x44, 0x30,
+    0x77, 0x36, 0x64, 0x45, 0x47, 0x2f, 0x2b, 0x67, 0x79, 0x52, 0x72, 0x36,
+    0x31, 0x4d, 0x33, 0x5a, 0x33, 0x71, 0x41, 0x46, 0x64, 0x6c, 0x73, 0x48,
+    0x42, 0x31, 0x62, 0x36, 0x75, 0x4a, 0x63, 0x44, 0x4a, 0x0a, 0x48, 0x67,
+    0x6f, 0x4a, 0x49, 0x49, 0x69, 0x68, 0x44, 0x73, 0x6e, 0x7a, 0x62, 0x30,
+    0x32, 0x43, 0x56, 0x41, 0x41, 0x67, 0x70, 0x39, 0x4b, 0x50, 0x35, 0x44,
+    0x6c, 0x55, 0x46, 0x79, 0x36, 0x4e, 0x48, 0x72, 0x67, 0x62, 0x75, 0x78,
+    0x75, 0x39, 0x6d, 0x6b, 0x34, 0x37, 0x45, 0x44, 0x54, 0x63, 0x6e, 0x49,
+    0x68, 0x54, 0x37, 0x36, 0x49, 0x78, 0x57, 0x31, 0x68, 0x50, 0x6b, 0x57,
+    0x4c, 0x49, 0x0a, 0x77, 0x70, 0x71, 0x61, 0x7a, 0x52, 0x56, 0x64, 0x4f,
+    0x4b, 0x6e, 0x57, 0x76, 0x76, 0x67, 0x54, 0x74, 0x5a, 0x38, 0x53, 0x61,
+    0x66, 0x4a, 0x51, 0x59, 0x71, 0x7a, 0x37, 0x46, 0x7a, 0x66, 0x30, 0x37,
+    0x72, 0x68, 0x31, 0x5a, 0x32, 0x41, 0x51, 0x2b, 0x34, 0x4e, 0x51, 0x2b,
+    0x55, 0x53, 0x31, 0x64, 0x5a, 0x78, 0x41, 0x46, 0x37, 0x4c, 0x2b, 0x2f,
+    0x58, 0x6c, 0x64, 0x62, 0x6c, 0x68, 0x59, 0x0a, 0x58, 0x7a, 0x44, 0x38,
+    0x41, 0x4b, 0x36, 0x76, 0x4d, 0x38, 0x45, 0x4f, 0x54, 0x6d, 0x79, 0x36,
+    0x70, 0x36, 0x61, 0x68, 0x66, 0x7a, 0x4c, 0x62, 0x4f, 0x4f, 0x43, 0x78,
+    0x63, 0x68, 0x63, 0x4b, 0x4b, 0x35, 0x48, 0x73, 0x61, 0x6d, 0x4d, 0x6d,
+    0x37, 0x59, 0x6e, 0x55, 0x65, 0x4d, 0x78, 0x30, 0x48, 0x67, 0x58, 0x34,
+    0x61, 0x2f, 0x36, 0x4d, 0x61, 0x6e, 0x59, 0x35, 0x4b, 0x61, 0x35, 0x6c,
+    0x0a, 0x49, 0x78, 0x4b, 0x56, 0x43, 0x43, 0x49, 0x63, 0x6c, 0x38, 0x35,
+    0x62, 0x42, 0x75, 0x34, 0x4d, 0x34, 0x72, 0x75, 0x38, 0x48, 0x30, 0x53,
+    0x54, 0x39, 0x74, 0x67, 0x34, 0x52, 0x51, 0x55, 0x68, 0x37, 0x65, 0x53,
+    0x74, 0x71, 0x78, 0x4b, 0x32, 0x41, 0x36, 0x52, 0x43, 0x4c, 0x69, 0x33,
+    0x45, 0x43, 0x54, 0x6f, 0x44, 0x5a, 0x32, 0x6d, 0x45, 0x6d, 0x75, 0x46,
+    0x5a, 0x6b, 0x49, 0x6f, 0x6f, 0x0a, 0x68, 0x64, 0x56, 0x64, 0x64, 0x4c,
+    0x48, 0x52, 0x44, 0x69, 0x42, 0x59, 0x6d, 0x78, 0x4f, 0x6c, 0x73, 0x47,
+    0x4f, 0x6d, 0x37, 0x58, 0x74, 0x48, 0x2f, 0x55, 0x56, 0x56, 0x4d, 0x4b,
+    0x54, 0x75, 0x6d, 0x74, 0x54, 0x6d, 0x34, 0x6f, 0x66, 0x76, 0x6d, 0x4d,
+    0x6b, 0x79, 0x67, 0x68, 0x45, 0x70, 0x49, 0x72, 0x77, 0x41, 0x43, 0x6a,
+    0x46, 0x65, 0x4c, 0x51, 0x2f, 0x41, 0x6a, 0x75, 0x6c, 0x72, 0x0a, 0x73,
+    0x6f, 0x38, 0x75, 0x42, 0x74, 0x6a, 0x52, 0x6b, 0x63, 0x66, 0x47, 0x45,
+    0x76, 0x52, 0x4d, 0x2f, 0x54, 0x41, 0x58, 0x77, 0x38, 0x48, 0x61, 0x4f,
+    0x46, 0x76, 0x6a, 0x71, 0x65, 0x72, 0x6d, 0x6f, 0x62, 0x70, 0x35, 0x37,
+    0x33, 0x50, 0x59, 0x74, 0x6c, 0x4e, 0x58, 0x4c, 0x66, 0x62, 0x51, 0x34,
+    0x64, 0x64, 0x49, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44,
+    0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a};
+unsigned int grpc_google_root_certs_size = 134862;
diff --git a/src/core/security/google_root_certs.h b/src/core/security/google_root_certs.h
new file mode 100644
index 0000000..4bcfadd
--- /dev/null
+++ b/src/core/security/google_root_certs.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SECURITY_GOOGLE_ROOT_CERTS_H__
+#define __GRPC_INTERNAL_SECURITY_GOOGLE_ROOT_CERTS_H__
+
+extern unsigned char grpc_google_root_certs[];
+extern unsigned int grpc_google_root_certs_size;
+
+#endif  /* __GRPC_INTERNAL_SECURITY_GOOGLE_ROOT_CERTS_H__ */
diff --git a/src/core/security/secure_transport_setup.c b/src/core/security/secure_transport_setup.c
new file mode 100644
index 0000000..bc2e469
--- /dev/null
+++ b/src/core/security/secure_transport_setup.c
@@ -0,0 +1,289 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/security/secure_transport_setup.h"
+
+#include <string.h>
+
+#include "src/core/endpoint/secure_endpoint.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+
+#define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256
+
+typedef struct {
+  grpc_security_context *ctx;
+  tsi_handshaker *handshaker;
+  unsigned char *handshake_buffer;
+  size_t handshake_buffer_size;
+  grpc_endpoint *endpoint;
+  gpr_slice_buffer left_overs;
+  grpc_secure_transport_setup_done_cb cb;
+  void *user_data;
+} grpc_secure_transport_setup;
+
+static void on_handshake_data_received_from_peer(void *setup, gpr_slice *slices,
+                                                 size_t nslices,
+                                                 grpc_endpoint_cb_status error);
+
+static void on_handshake_data_sent_to_peer(void *setup,
+                                           grpc_endpoint_cb_status error);
+
+static void secure_transport_setup_done(grpc_secure_transport_setup *s,
+                                        int is_success) {
+  if (is_success) {
+    s->cb(s->user_data, GRPC_SECURITY_OK, s->endpoint);
+  } else {
+    if (s->endpoint != NULL) {
+      grpc_endpoint_shutdown(s->endpoint);
+      grpc_endpoint_destroy(s->endpoint);
+    }
+    s->cb(s->user_data, GRPC_SECURITY_ERROR, NULL);
+  }
+  if (s->handshaker != NULL) tsi_handshaker_destroy(s->handshaker);
+  if (s->handshake_buffer != NULL) gpr_free(s->handshake_buffer);
+  gpr_slice_buffer_destroy(&s->left_overs);
+  grpc_security_context_unref(s->ctx);
+  gpr_free(s);
+}
+
+static void on_peer_checked(void *user_data, grpc_security_status status) {
+  grpc_secure_transport_setup *s = user_data;
+  tsi_frame_protector *protector;
+  tsi_result result;
+  if (status != GRPC_SECURITY_OK) {
+    gpr_log(GPR_ERROR, "Error checking peer.");
+    secure_transport_setup_done(s, 0);
+    return;
+  }
+  result =
+      tsi_handshaker_create_frame_protector(s->handshaker, NULL, &protector);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Frame protector creation failed with error %s.",
+            tsi_result_to_string(result));
+    secure_transport_setup_done(s, 0);
+    return;
+  }
+  s->endpoint = grpc_secure_endpoint_create(
+      protector, s->endpoint, s->left_overs.slices, s->left_overs.count);
+  secure_transport_setup_done(s, 1);
+  return;
+}
+
+static void check_peer(grpc_secure_transport_setup *s) {
+  grpc_security_status peer_status;
+  tsi_peer peer;
+  tsi_result result = tsi_handshaker_extract_peer(s->handshaker, &peer);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Peer extraction failed with error %s",
+            tsi_result_to_string(result));
+    secure_transport_setup_done(s, 0);
+    return;
+  }
+  peer_status =
+      grpc_security_context_check_peer(s->ctx, &peer, on_peer_checked, s);
+  tsi_peer_destruct(&peer);
+  if (peer_status == GRPC_SECURITY_ERROR) {
+    gpr_log(GPR_ERROR, "Peer check failed.");
+    secure_transport_setup_done(s, 0);
+    return;
+  } else if (peer_status == GRPC_SECURITY_OK) {
+    on_peer_checked(s, peer_status);
+  }
+}
+
+static void send_handshake_bytes_to_peer(grpc_secure_transport_setup *s) {
+  size_t offset = 0;
+  tsi_result result = TSI_OK;
+  gpr_slice to_send;
+  grpc_endpoint_write_status write_status;
+
+  do {
+    uint32_t to_send_size = s->handshake_buffer_size - offset;
+    result = tsi_handshaker_get_bytes_to_send_to_peer(
+        s->handshaker, s->handshake_buffer + offset, &to_send_size);
+    offset += to_send_size;
+    if (result == TSI_INCOMPLETE_DATA) {
+      s->handshake_buffer_size *= 2;
+      s->handshake_buffer =
+          gpr_realloc(s->handshake_buffer, s->handshake_buffer_size);
+    }
+  } while (result == TSI_INCOMPLETE_DATA);
+
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Handshake failed with error %s",
+            tsi_result_to_string(result));
+    secure_transport_setup_done(s, 0);
+    return;
+  }
+
+  to_send =
+      gpr_slice_from_copied_buffer((const char *)s->handshake_buffer, offset);
+  /* TODO(klempner,jboeuf): This should probably use the client setup
+         deadline */
+  write_status =
+      grpc_endpoint_write(s->endpoint, &to_send, 1,
+                          on_handshake_data_sent_to_peer, s, gpr_inf_future);
+  if (write_status == GRPC_ENDPOINT_WRITE_ERROR) {
+    gpr_log(GPR_ERROR, "Could not send handshake data to peer.");
+    secure_transport_setup_done(s, 0);
+  } else if (write_status == GRPC_ENDPOINT_WRITE_DONE) {
+    on_handshake_data_sent_to_peer(s, GRPC_ENDPOINT_CB_OK);
+  }
+}
+
+static void cleanup_slices(gpr_slice *slices, size_t num_slices) {
+  size_t i;
+  for (i = 0; i < num_slices; i++) {
+    gpr_slice_unref(slices[i]);
+  }
+}
+
+static void on_handshake_data_received_from_peer(
+    void *setup, gpr_slice *slices, size_t nslices,
+    grpc_endpoint_cb_status error) {
+  grpc_secure_transport_setup *s = setup;
+  uint32_t consumed_slice_size = 0;
+  tsi_result result = TSI_OK;
+  size_t i;
+  size_t num_left_overs;
+  int has_left_overs_in_current_slice = 0;
+
+  if (error != GRPC_ENDPOINT_CB_OK) {
+    gpr_log(GPR_ERROR, "Read failed.");
+    cleanup_slices(slices, nslices);
+    secure_transport_setup_done(s, 0);
+    return;
+  }
+
+  for (i = 0; i < nslices; i++) {
+    consumed_slice_size = GPR_SLICE_LENGTH(slices[i]);
+    result = tsi_handshaker_process_bytes_from_peer(
+        s->handshaker, GPR_SLICE_START_PTR(slices[i]), &consumed_slice_size);
+    if (!tsi_handshaker_is_in_progress(s->handshaker)) break;
+  }
+
+  if (tsi_handshaker_is_in_progress(s->handshaker)) {
+    /* We may need more data. */
+    if (result == TSI_INCOMPLETE_DATA) {
+      /* TODO(klempner,jboeuf): This should probably use the client setup
+         deadline */
+      grpc_endpoint_notify_on_read(s->endpoint,
+                                   on_handshake_data_received_from_peer, setup,
+                                   gpr_inf_future);
+      cleanup_slices(slices, nslices);
+      return;
+    } else {
+      send_handshake_bytes_to_peer(s);
+      cleanup_slices(slices, nslices);
+      return;
+    }
+  }
+
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Handshake failed with error %s",
+            tsi_result_to_string(result));
+    cleanup_slices(slices, nslices);
+    secure_transport_setup_done(s, 0);
+    return;
+  }
+
+  /* Handshake is done and successful this point. */
+  has_left_overs_in_current_slice =
+      (consumed_slice_size < GPR_SLICE_LENGTH(slices[i]));
+  num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) + nslices - i - 1;
+  if (num_left_overs == 0) {
+    cleanup_slices(slices, nslices);
+    check_peer(s);
+    return;
+  }
+  cleanup_slices(slices, nslices - num_left_overs);
+
+  /* Put the leftovers in our buffer (ownership transfered). */
+  if (has_left_overs_in_current_slice) {
+    gpr_slice_buffer_add(&s->left_overs,
+                         gpr_slice_split_tail(&slices[i], consumed_slice_size));
+    gpr_slice_unref(slices[i]); /* split_tail above increments refcount. */
+  }
+  gpr_slice_buffer_addn(&s->left_overs, &slices[i + 1],
+                        num_left_overs - has_left_overs_in_current_slice);
+  check_peer(s);
+}
+
+/* If setup is NULL, the setup is done. */
+static void on_handshake_data_sent_to_peer(void *setup,
+                                           grpc_endpoint_cb_status error) {
+  grpc_secure_transport_setup *s = setup;
+
+  /* Make sure that write is OK. */
+  if (error != GRPC_ENDPOINT_CB_OK) {
+    gpr_log(GPR_ERROR, "Write failed with error %d.", error);
+    if (setup != NULL) secure_transport_setup_done(s, 0);
+    return;
+  }
+
+  /* We may be done. */
+  if (tsi_handshaker_is_in_progress(s->handshaker)) {
+    /* TODO(klempner,jboeuf): This should probably use the client setup
+       deadline */
+    grpc_endpoint_notify_on_read(s->endpoint,
+                                 on_handshake_data_received_from_peer, setup,
+                                 gpr_inf_future);
+  } else {
+    check_peer(s);
+  }
+}
+
+void grpc_setup_secure_transport(grpc_security_context *ctx,
+                                 grpc_endpoint *nonsecure_endpoint,
+                                 grpc_secure_transport_setup_done_cb cb,
+                                 void *user_data) {
+  grpc_security_status result = GRPC_SECURITY_OK;
+  grpc_secure_transport_setup *s =
+      gpr_malloc(sizeof(grpc_secure_transport_setup));
+  memset(s, 0, sizeof(grpc_secure_transport_setup));
+  result = grpc_security_context_create_handshaker(ctx, &s->handshaker);
+  if (result != GRPC_SECURITY_OK) {
+    secure_transport_setup_done(s, 0);
+    return;
+  }
+  s->ctx = grpc_security_context_ref(ctx);
+  s->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
+  s->handshake_buffer = gpr_malloc(s->handshake_buffer_size);
+  s->endpoint = nonsecure_endpoint;
+  s->user_data = user_data;
+  s->cb = cb;
+  gpr_slice_buffer_init(&s->left_overs);
+  send_handshake_bytes_to_peer(s);
+}
diff --git a/src/core/security/secure_transport_setup.h b/src/core/security/secure_transport_setup.h
new file mode 100644
index 0000000..1a20fa9
--- /dev/null
+++ b/src/core/security/secure_transport_setup.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SECURITY_SECURE_TRANSPORT_SETUP_H__
+#define __GRPC_INTERNAL_SECURITY_SECURE_TRANSPORT_SETUP_H__
+
+#include "src/core/endpoint/endpoint.h"
+#include "src/core/security/security_context.h"
+
+/* --- Secure transport setup --- */
+
+/* Ownership of the secure_endpoint is transfered. */
+typedef void (*grpc_secure_transport_setup_done_cb)(
+    void *user_data, grpc_security_status status,
+    grpc_endpoint *secure_endpoint);
+
+/* Calls the callback upon completion. */
+void grpc_setup_secure_transport(grpc_security_context *ctx,
+                                 grpc_endpoint *nonsecure_endpoint,
+                                 grpc_secure_transport_setup_done_cb cb,
+                                 void *user_data);
+
+#endif  /* __GRPC_INTERNAL_SECURITY_SECURE_TRANSPORT_SETUP_H__ */
diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c
new file mode 100644
index 0000000..beda64c
--- /dev/null
+++ b/src/core/security/security_context.c
@@ -0,0 +1,497 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/security/security_context.h"
+
+#include <string.h>
+
+#include "src/core/endpoint/secure_endpoint.h"
+#include "src/core/security/credentials.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/support/string.h>
+
+#include "src/core/tsi/fake_transport_security.h"
+#include "src/core/tsi/ssl_transport_security.h"
+
+/* -- Constants. -- */
+
+#define GRPC_ALPN_PROTOCOL_STRING "h2-15"
+/* Defines the cipher suites that we accept. All these cipher suites are
+   compliant with TLS 1.2 and use an RSA public key. We prefer GCM over CBC
+   and ECDHE-RSA over just RSA. */
+#define GRPC_SSL_CIPHER_SUITES                                                 \
+  "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:AES128-GCM-SHA256:" \
+  "AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:AES128-"  \
+  "SHA256:AES256-SHA256"
+
+/* -- Common methods. -- */
+
+grpc_security_status grpc_security_context_create_handshaker(
+    grpc_security_context *ctx, tsi_handshaker **handshaker) {
+  if (ctx == NULL || handshaker == NULL) return GRPC_SECURITY_ERROR;
+  return ctx->vtable->create_handshaker(ctx, handshaker);
+}
+
+grpc_security_status grpc_security_context_check_peer(
+    grpc_security_context *ctx, const tsi_peer *peer,
+    grpc_security_check_peer_cb cb, void *user_data) {
+  if (ctx == NULL) return GRPC_SECURITY_ERROR;
+  return ctx->vtable->check_peer(ctx, peer, cb, user_data);
+}
+
+void grpc_security_context_unref(grpc_security_context *ctx) {
+  if (ctx == NULL) return;
+  if (gpr_unref(&ctx->refcount)) ctx->vtable->destroy(ctx);
+}
+
+grpc_security_context *grpc_security_context_ref(grpc_security_context *ctx) {
+  if (ctx == NULL) return NULL;
+  gpr_ref(&ctx->refcount);
+  return ctx;
+}
+
+static void context_pointer_arg_destroy(void *p) {
+  grpc_security_context_unref(p);
+}
+
+static void *context_pointer_arg_copy(void *p) {
+  return grpc_security_context_ref(p);
+}
+
+grpc_arg grpc_security_context_to_arg(grpc_security_context *ctx) {
+  grpc_arg result;
+  result.type = GRPC_ARG_POINTER;
+  result.key = GRPC_SECURITY_CONTEXT_ARG;
+  result.value.pointer.destroy = context_pointer_arg_destroy;
+  result.value.pointer.copy = context_pointer_arg_copy;
+  result.value.pointer.p = ctx;
+  return result;
+}
+
+grpc_security_context *grpc_security_context_from_arg(
+    const grpc_arg *arg) {
+  if (strcmp(arg->key, GRPC_SECURITY_CONTEXT_ARG)) return NULL;
+  if (arg->type != GRPC_ARG_POINTER) {
+    gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
+            GRPC_SECURITY_CONTEXT_ARG);
+    return NULL;
+  }
+  return arg->value.pointer.p;
+}
+
+grpc_security_context *grpc_find_security_context_in_args(
+    const grpc_channel_args *args) {
+  size_t i;
+  if (args == NULL) return NULL;
+  for (i = 0; i < args->num_args; i++) {
+    grpc_security_context *ctx = grpc_security_context_from_arg(&args->args[i]);
+    if (ctx != NULL) return ctx;
+  }
+  return NULL;
+}
+
+static int check_request_metadata_only_creds(grpc_credentials *creds) {
+  if (creds != NULL && !grpc_credentials_has_request_metadata_only(creds)) {
+    gpr_log(GPR_ERROR,
+            "Incompatible credentials for channel security context: needs to "
+            "only set request metadata.");
+    return 0;
+  }
+  return 1;
+}
+
+/* -- Fake implementation. -- */
+
+static void fake_channel_destroy(grpc_security_context *ctx) {
+  grpc_channel_security_context *c = (grpc_channel_security_context *)ctx;
+  grpc_credentials_unref(c->request_metadata_only_creds);
+  gpr_free(ctx);
+}
+
+static void fake_server_destroy(grpc_security_context *ctx) {
+  gpr_free(ctx);
+}
+
+static grpc_security_status fake_channel_create_handshaker(
+    grpc_security_context *ctx, tsi_handshaker **handshaker) {
+  *handshaker = tsi_create_fake_handshaker(1);
+  return GRPC_SECURITY_OK;
+}
+
+static grpc_security_status fake_server_create_handshaker(
+    grpc_security_context *ctx, tsi_handshaker **handshaker) {
+  *handshaker = tsi_create_fake_handshaker(0);
+  return GRPC_SECURITY_OK;
+}
+
+static grpc_security_status fake_check_peer(grpc_security_context *ctx,
+                                            const tsi_peer *peer,
+                                            grpc_security_check_peer_cb cb,
+                                            void *user_data) {
+  const char *prop_name;
+  if (peer->property_count != 1) {
+    gpr_log(GPR_ERROR, "Fake peers should only have 1 property.");
+    return GRPC_SECURITY_ERROR;
+  }
+  prop_name = peer->properties[0].name;
+  if (prop_name == NULL ||
+      strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) {
+    gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.",
+            prop_name == NULL ? "<EMPTY>" : prop_name);
+    return GRPC_SECURITY_ERROR;
+  }
+  if (peer->properties[0].type != TSI_PEER_PROPERTY_TYPE_STRING) {
+    gpr_log(GPR_ERROR, "Invalid type of cert type property.");
+    return GRPC_SECURITY_ERROR;
+  }
+  if (strncmp(peer->properties[0].value.string.data, TSI_FAKE_CERTIFICATE_TYPE,
+              peer->properties[0].value.string.length)) {
+    gpr_log(GPR_ERROR, "Invalid value for cert type property.");
+    return GRPC_SECURITY_ERROR;
+  }
+  return GRPC_SECURITY_OK;
+}
+
+static grpc_security_context_vtable fake_channel_vtable = {
+    fake_channel_destroy, fake_channel_create_handshaker, fake_check_peer};
+
+static grpc_security_context_vtable fake_server_vtable = {
+    fake_server_destroy, fake_server_create_handshaker, fake_check_peer};
+
+grpc_channel_security_context *grpc_fake_channel_security_context_create(
+    grpc_credentials *request_metadata_only_creds) {
+  grpc_channel_security_context *c =
+      gpr_malloc(sizeof(grpc_channel_security_context));
+  gpr_ref_init(&c->base.refcount, 1);
+  c->base.is_client_side = 1;
+  c->base.vtable = &fake_channel_vtable;
+  GPR_ASSERT(check_request_metadata_only_creds(request_metadata_only_creds));
+  c->request_metadata_only_creds =
+      grpc_credentials_ref(request_metadata_only_creds);
+  return c;
+}
+
+grpc_security_context *grpc_fake_server_security_context_create(void) {
+  grpc_security_context *c = gpr_malloc(sizeof(grpc_security_context));
+  gpr_ref_init(&c->refcount, 1);
+  c->vtable = &fake_server_vtable;
+  return c;
+}
+
+/* --- Ssl implementation. --- */
+
+typedef struct {
+  grpc_channel_security_context base;
+  tsi_ssl_handshaker_factory *handshaker_factory;
+  char *secure_peer_name;
+} grpc_ssl_channel_security_context;
+
+typedef struct {
+  grpc_security_context base;
+  tsi_ssl_handshaker_factory *handshaker_factory;
+} grpc_ssl_server_security_context;
+
+static void ssl_channel_destroy(grpc_security_context *ctx) {
+  grpc_ssl_channel_security_context *c =
+      (grpc_ssl_channel_security_context *)ctx;
+  grpc_credentials_unref(c->base.request_metadata_only_creds);
+  if (c->handshaker_factory != NULL) {
+    tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
+  }
+  if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name);
+  gpr_free(ctx);
+}
+
+static void ssl_server_destroy(grpc_security_context *ctx) {
+  grpc_ssl_server_security_context *c =
+      (grpc_ssl_server_security_context *)ctx;
+  if (c->handshaker_factory != NULL) {
+    tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
+  }
+  gpr_free(ctx);
+}
+
+static grpc_security_status ssl_create_handshaker(
+    tsi_ssl_handshaker_factory *handshaker_factory, int is_client,
+    const char *secure_peer_name, tsi_handshaker **handshaker) {
+  tsi_result result = TSI_OK;
+  if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR;
+  result = tsi_ssl_handshaker_factory_create_handshaker(
+      handshaker_factory, is_client ? secure_peer_name : NULL, handshaker);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
+            tsi_result_to_string(result));
+    return GRPC_SECURITY_ERROR;
+  }
+  return GRPC_SECURITY_OK;
+}
+
+static grpc_security_status ssl_channel_create_handshaker(
+    grpc_security_context *ctx, tsi_handshaker **handshaker) {
+  grpc_ssl_channel_security_context *c =
+      (grpc_ssl_channel_security_context *)ctx;
+  return ssl_create_handshaker(c->handshaker_factory, 1, c->secure_peer_name,
+                               handshaker);
+}
+
+static grpc_security_status ssl_server_create_handshaker(
+    grpc_security_context *ctx, tsi_handshaker **handshaker) {
+  grpc_ssl_server_security_context *c =
+      (grpc_ssl_server_security_context *)ctx;
+  return ssl_create_handshaker(c->handshaker_factory, 0, NULL, handshaker);
+}
+
+static grpc_security_status ssl_check_peer(const char *secure_peer_name,
+                                           const tsi_peer *peer) {
+  /* Check the ALPN. */
+  const tsi_peer_property *p =
+      tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
+  if (p == NULL || p->type != TSI_PEER_PROPERTY_TYPE_STRING) {
+    gpr_log(GPR_ERROR, "Invalid or missing selected ALPN property.");
+    return GRPC_SECURITY_ERROR;
+  }
+  if (strncmp(GRPC_ALPN_PROTOCOL_STRING, p->value.string.data,
+              p->value.string.length)) {
+    gpr_log(GPR_ERROR, "Invalid ALPN value.");
+    return GRPC_SECURITY_ERROR;
+  }
+
+  /* Check the peer name if specified. */
+  if (secure_peer_name != NULL &&
+      !tsi_ssl_peer_matches_name(peer, secure_peer_name)) {
+    gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate",
+            secure_peer_name);
+    return GRPC_SECURITY_ERROR;
+  }
+  return GRPC_SECURITY_OK;
+}
+
+static grpc_security_status ssl_channel_check_peer(
+    grpc_security_context *ctx, const tsi_peer *peer,
+    grpc_security_check_peer_cb cb, void *user_data) {
+  grpc_ssl_channel_security_context *c =
+      (grpc_ssl_channel_security_context *)ctx;
+  return ssl_check_peer(c->secure_peer_name, peer);
+}
+
+static grpc_security_status ssl_server_check_peer(
+    grpc_security_context *ctx, const tsi_peer *peer,
+    grpc_security_check_peer_cb cb, void *user_data) {
+  /* TODO(jboeuf): Find a way to expose the peer to the authorization layer. */
+  return ssl_check_peer(NULL, peer);
+}
+
+static grpc_security_context_vtable ssl_channel_vtable = {
+    ssl_channel_destroy, ssl_channel_create_handshaker, ssl_channel_check_peer};
+
+static grpc_security_context_vtable ssl_server_vtable = {
+    ssl_server_destroy, ssl_server_create_handshaker, ssl_server_check_peer};
+
+grpc_security_status grpc_ssl_channel_security_context_create(
+    grpc_credentials *request_metadata_only_creds,
+    const grpc_ssl_config *config, const char *secure_peer_name,
+    grpc_channel_security_context **ctx) {
+  const char *alpn_protocol_string = GRPC_ALPN_PROTOCOL_STRING;
+  unsigned char alpn_protocol_string_len =
+      (unsigned char)strlen(alpn_protocol_string);
+  tsi_result result = TSI_OK;
+  grpc_ssl_channel_security_context *c;
+
+  if (config == NULL || secure_peer_name == NULL ||
+      config->pem_root_certs == NULL) {
+    gpr_log(GPR_ERROR, "An ssl channel needs a secure name and root certs.");
+    return GRPC_SECURITY_ERROR;
+  }
+  if (!check_request_metadata_only_creds(request_metadata_only_creds)) {
+    return GRPC_SECURITY_ERROR;
+  }
+
+  c = gpr_malloc(sizeof(grpc_ssl_channel_security_context));
+  memset(c, 0, sizeof(grpc_ssl_channel_security_context));
+
+  gpr_ref_init(&c->base.base.refcount, 1);
+  c->base.base.vtable = &ssl_channel_vtable;
+  c->base.base.is_client_side = 1;
+  c->base.request_metadata_only_creds =
+      grpc_credentials_ref(request_metadata_only_creds);
+  if (secure_peer_name != NULL) {
+    c->secure_peer_name = gpr_strdup(secure_peer_name);
+  }
+  result = tsi_create_ssl_client_handshaker_factory(
+      config->pem_private_key, config->pem_private_key_size,
+      config->pem_cert_chain, config->pem_cert_chain_size,
+      config->pem_root_certs, config->pem_root_certs_size,
+      GRPC_SSL_CIPHER_SUITES, (const unsigned char **)&alpn_protocol_string,
+      &alpn_protocol_string_len, 1, &c->handshaker_factory);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
+            tsi_result_to_string(result));
+    ssl_channel_destroy(&c->base.base);
+    *ctx = NULL;
+    return GRPC_SECURITY_ERROR;
+  }
+  *ctx = &c->base;
+  return GRPC_SECURITY_OK;
+}
+
+grpc_security_status grpc_ssl_server_security_context_create(
+    const grpc_ssl_config *config, grpc_security_context **ctx) {
+  const char *alpn_protocol_string = GRPC_ALPN_PROTOCOL_STRING;
+  unsigned char alpn_protocol_string_len =
+      (unsigned char)strlen(alpn_protocol_string);
+  tsi_result result = TSI_OK;
+  grpc_ssl_server_security_context *c;
+
+  if (config == NULL || config->pem_private_key == NULL ||
+      config->pem_cert_chain == NULL) {
+    gpr_log(GPR_ERROR, "An SSL server needs a key and a cert.");
+    return GRPC_SECURITY_ERROR;
+  }
+  c = gpr_malloc(sizeof(grpc_ssl_server_security_context));
+  memset(c, 0, sizeof(grpc_ssl_server_security_context));
+
+  gpr_ref_init(&c->base.refcount, 1);
+  c->base.vtable = &ssl_server_vtable;
+  result = tsi_create_ssl_server_handshaker_factory(
+      (const unsigned char **)&config->pem_private_key,
+      (const gpr_uint32 *)&config->pem_private_key_size,
+      (const unsigned char **)&config->pem_cert_chain,
+      (const gpr_uint32 *)&config->pem_cert_chain_size, 1,
+      config->pem_root_certs, config->pem_root_certs_size,
+      GRPC_SSL_CIPHER_SUITES, (const unsigned char **)&alpn_protocol_string,
+      &alpn_protocol_string_len, 1, &c->handshaker_factory);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
+            tsi_result_to_string(result));
+    ssl_server_destroy(&c->base);
+    *ctx = NULL;
+    return GRPC_SECURITY_ERROR;
+  }
+  *ctx = &c->base;
+  return GRPC_SECURITY_OK;
+}
+
+
+
+/* -- High level objects. -- */
+
+static grpc_channel *grpc_ssl_channel_create(grpc_credentials *creds,
+                                             const grpc_ssl_config *config,
+                                             const char *target,
+                                             const grpc_channel_args *args) {
+  grpc_channel_security_context *ctx = NULL;
+  grpc_channel *channel = NULL;
+  grpc_security_status status = GRPC_SECURITY_OK;
+  size_t i = 0;
+  const char *secure_peer_name = target;
+  for (i = 0; i < args->num_args; i++) {
+    grpc_arg *arg = &args->args[i];
+    if (!strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) &&
+        arg->type == GRPC_ARG_STRING) {
+      secure_peer_name = arg->value.string;
+      break;
+    }
+  }
+  status = grpc_ssl_channel_security_context_create(creds, config,
+                                                    secure_peer_name, &ctx);
+  if (status != GRPC_SECURITY_OK) {
+    return NULL; /* TODO(ctiller): return lame channel. */
+  }
+  channel = grpc_secure_channel_create_internal(target, args, ctx);
+  grpc_security_context_unref(&ctx->base);
+  return channel;
+}
+
+
+grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
+                                         const char *target,
+                                         const grpc_channel_args *args) {
+  if (grpc_credentials_has_request_metadata_only(creds)) {
+    gpr_log(GPR_ERROR,
+            "Credentials is insufficient to create a secure channel.");
+    return NULL; /* TODO(ctiller): return lame channel. */
+  }
+  if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
+    return grpc_ssl_channel_create(NULL, grpc_ssl_credentials_get_config(creds),
+                                   target, args);
+  } else if (!strcmp(creds->type,
+                     GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY)) {
+    grpc_channel_security_context *ctx =
+        grpc_fake_channel_security_context_create(NULL);
+    grpc_channel *channel =
+        grpc_secure_channel_create_internal(target, args, ctx);
+    grpc_security_context_unref(&ctx->base);
+    return channel;
+  } else if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE)) {
+    return NULL; /* TODO(jboeuf) Implement. */
+  } else {
+    gpr_log(GPR_ERROR,
+            "Unknown credentials type %s for creating a secure channel.");
+    return NULL; /* TODO(ctiller): return lame channel. */
+  }
+}
+
+grpc_channel *grpc_default_secure_channel_create(
+    const char *target, const grpc_channel_args *args) {
+  return grpc_secure_channel_create(grpc_default_credentials_create(), target,
+                                    args);
+}
+
+grpc_server *grpc_secure_server_create(grpc_server_credentials *creds,
+                                       grpc_completion_queue *cq,
+                                       const grpc_channel_args *args) {
+  grpc_security_status status = GRPC_SECURITY_ERROR;
+  grpc_security_context *ctx = NULL;
+  grpc_server *server = NULL;
+  if (creds == NULL) return NULL; /* TODO(ctiller): Return lame server. */
+  if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
+    status = grpc_ssl_server_security_context_create(
+        grpc_ssl_server_credentials_get_config(creds), &ctx);
+  } else if (!strcmp(creds->type,
+                     GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY)) {
+    ctx = grpc_fake_server_security_context_create();
+    status = GRPC_SECURITY_OK;
+  } else {
+    gpr_log(GPR_ERROR,
+            "Unable to create secure server with credentials of type %s.",
+            creds->type);
+  }
+  if (status != GRPC_SECURITY_OK) {
+    return NULL; /* TODO(ctiller): Return lame server. */
+  }
+  server = grpc_secure_server_create_internal(cq, args, ctx);
+  grpc_security_context_unref(ctx);
+  return server;
+}
diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h
new file mode 100644
index 0000000..59c9bbd
--- /dev/null
+++ b/src/core/security/security_context.h
@@ -0,0 +1,176 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SECURITY_SECURITY_CONTEXT_H__
+#define __GRPC_INTERNAL_SECURITY_SECURITY_CONTEXT_H__
+
+#include <grpc/grpc_security.h>
+#include "src/core/endpoint/endpoint.h"
+#include "src/core/security/credentials.h"
+#include "src/core/tsi/transport_security_interface.h"
+
+/* --- status enum. --- */
+
+typedef enum {
+  GRPC_SECURITY_OK = 0,
+  GRPC_SECURITY_PENDING,
+  GRPC_SECURITY_ERROR
+} grpc_security_status;
+
+/* --- security_context object. ---
+
+    A security context object represents away to configure the underlying
+    transport security mechanism and check the resulting trusted peer.  */
+
+typedef struct grpc_security_context grpc_security_context;
+
+#define GRPC_SECURITY_CONTEXT_ARG "grpc.security_context"
+
+typedef void (*grpc_security_check_peer_cb)(void *user_data,
+                                            grpc_security_status status);
+
+typedef struct {
+  void (*destroy)(grpc_security_context *ctx);
+  grpc_security_status (*create_handshaker)(grpc_security_context *ctx,
+                                            tsi_handshaker **handshaker);
+  grpc_security_status (*check_peer)(grpc_security_context *ctx,
+                                     const tsi_peer *peer,
+                                     grpc_security_check_peer_cb,
+                                     void *user_data);
+} grpc_security_context_vtable;
+
+struct grpc_security_context {
+  const grpc_security_context_vtable *vtable;
+  gpr_refcount refcount;
+  int is_client_side;
+};
+
+/* Increments the refcount. */
+grpc_security_context *grpc_security_context_ref(grpc_security_context *ctx);
+
+/* Decrements the refcount and destroys the object if it reaches 0. */
+void grpc_security_context_unref(grpc_security_context *ctx);
+
+/* Handshake creation. */
+grpc_security_status grpc_security_context_create_handshaker(
+    grpc_security_context *ctx, tsi_handshaker **handshaker);
+
+/* Check the peer.
+   Implementations can choose to check the peer either synchronously or
+   asynchronously. In the first case, a successful will return
+   GRPC_SECURITY_OK. In the asynchronous case, the call will return
+   GRPC_SECURITY_PENDING unless an error is detected early on.
+
+   Note:
+   Asynchronous implementations of this interface should make a copy of the
+   fields of the peer they want to check as there is no guarantee on the
+   lifetime of the peer object beyond this call.
+*/
+grpc_security_status grpc_security_context_check_peer(
+    grpc_security_context *ctx, const tsi_peer *peer,
+    grpc_security_check_peer_cb cb, void *user_data);
+
+/* Util to encapsulate the context in a channel arg. */
+grpc_arg grpc_security_context_to_arg(grpc_security_context *ctx);
+
+/* Util to get the context from a channel arg. */
+grpc_security_context *grpc_security_context_from_arg(const grpc_arg *arg);
+
+/* Util to find the context from channel args. */
+grpc_security_context *grpc_find_security_context_in_args(
+    const grpc_channel_args *args);
+
+/* --- channel_security_context object. ---
+
+    A channel security context object represents away to configure the
+    underlying transport security mechanism on the client side.  */
+
+typedef struct grpc_channel_security_context grpc_channel_security_context;
+
+struct grpc_channel_security_context {
+  grpc_security_context base;  /* requires is_client_side to be non 0. */
+  grpc_credentials *request_metadata_only_creds;
+};
+
+/* --- Creation security contexts. --- */
+
+/* For TESTING ONLY!
+   Creates a fake context that emulates real channel security.  */
+grpc_channel_security_context *grpc_fake_channel_security_context_create(
+    grpc_credentials *request_metadata_only_creds);
+
+/* For TESTING ONLY!
+   Creates a fake context that emulates real server security.  */
+grpc_security_context *grpc_fake_server_security_context_create(void);
+
+/* Creates an SSL channel_security_context.
+   - request_metadata_only_creds is the credentials object which metadata
+     will be sent with each request. This parameter can be NULL.
+   - config is the SSL config to be used for the SSL channel establishment.
+   - is_client should be 0 for a server or a non-0 value for a client.
+   - secure_peer_name is the secure peer name that should be checked in
+     grpc_channel_security_context_check_peer. This parameter may be NULL in
+     which case the peer name will not be checked. Note that if this parameter
+     is not NULL, then, pem_root_certs should not be NULL either.
+   - ctx is a pointer on the context to be created.
+  This function returns GRPC_SECURITY_OK in case of success or a
+  specific error code otherwise.
+*/
+grpc_security_status grpc_ssl_channel_security_context_create(
+    grpc_credentials *request_metadata_only_creds,
+    const grpc_ssl_config *config, const char *secure_peer_name,
+    grpc_channel_security_context **ctx);
+
+/* Creates an SSL server_security_context.
+   - config is the SSL config to be used for the SSL channel establishment.
+   - ctx is a pointer on the context to be created.
+  This function returns GRPC_SECURITY_OK in case of success or a
+  specific error code otherwise.
+*/
+grpc_security_status grpc_ssl_server_security_context_create(
+    const grpc_ssl_config *config, grpc_security_context **ctx);
+
+
+/* --- Creation of high level objects. --- */
+
+/* Secure client channel creation. */
+grpc_channel *grpc_secure_channel_create_internal(
+    const char *target, const grpc_channel_args *args,
+    grpc_channel_security_context *ctx);
+
+/* Secure server creation. */
+grpc_server *grpc_secure_server_create_internal(
+    grpc_completion_queue *cq, const grpc_channel_args *args,
+    grpc_security_context *ctx);
+
+#endif  /* __GRPC_INTERNAL_SECURITY_SECURITY_CONTEXT_H__ */
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
new file mode 100644
index 0000000..bce27ec
--- /dev/null
+++ b/src/core/security/server_secure_chttp2.c
@@ -0,0 +1,141 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+
+#include "src/core/channel/http_filter.h"
+#include "src/core/channel/http_server_filter.h"
+#include "src/core/endpoint/resolve_address.h"
+#include "src/core/endpoint/tcp_server.h"
+#include "src/core/security/security_context.h"
+#include "src/core/security/secure_transport_setup.h"
+#include "src/core/surface/server.h"
+#include "src/core/surface/surface_em.h"
+#include "src/core/transport/chttp2_transport.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+static grpc_transport_setup_result setup_transport(void *server,
+                                                   grpc_transport *transport,
+                                                   grpc_mdctx *mdctx) {
+  static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter,
+                                                       &grpc_http_filter};
+  return grpc_server_setup_transport(server, transport, extra_filters,
+                                     GPR_ARRAY_SIZE(extra_filters), mdctx);
+}
+
+static void on_secure_transport_setup_done(void *server,
+                                           grpc_security_status status,
+                                           grpc_endpoint *secure_endpoint) {
+  if (status == GRPC_SECURITY_OK) {
+    grpc_create_chttp2_transport(
+        setup_transport, server, grpc_server_get_channel_args(server),
+        secure_endpoint, NULL, 0, grpc_mdctx_create(), 0);
+  } else {
+    gpr_log(GPR_ERROR, "Secure transport failed with error %d", status);
+  }
+}
+
+static void on_accept(void *server, grpc_endpoint *tcp) {
+  const grpc_channel_args *args = grpc_server_get_channel_args(server);
+  grpc_security_context *ctx = grpc_find_security_context_in_args(args);
+  GPR_ASSERT(ctx);
+  grpc_setup_secure_transport(ctx, tcp, on_secure_transport_setup_done,
+                              server);
+}
+
+/* Note: the following code is the same with server_chttp2.c */
+
+/* Server callback: start listening on our ports */
+static void start(grpc_server *server, void *tcpp) {
+  grpc_tcp_server *tcp = tcpp;
+  grpc_tcp_server_start(tcp, on_accept, server);
+}
+
+/* Server callback: destroy the tcp listener (so we don't generate further
+   callbacks) */
+static void destroy(grpc_server *server, void *tcpp) {
+  grpc_tcp_server *tcp = tcpp;
+  grpc_tcp_server_destroy(tcp);
+}
+
+int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr) {
+  grpc_resolved_addresses *resolved = NULL;
+  grpc_tcp_server *tcp = NULL;
+  size_t i;
+  int count = 0;
+
+  resolved = grpc_blocking_resolve_address(addr, "https");
+  if (!resolved) {
+    goto error;
+  }
+
+  tcp = grpc_tcp_server_create(grpc_surface_em());
+  if (!tcp) {
+    goto error;
+  }
+
+  for (i = 0; i < resolved->naddrs; i++) {
+    if (grpc_tcp_server_add_port(tcp,
+                                 (struct sockaddr *)&resolved->addrs[i].addr,
+                                 resolved->addrs[i].len) >= 0) {
+      count++;
+    }
+  }
+  if (count == 0) {
+    gpr_log(GPR_ERROR, "No address added out of total %d resolved",
+            resolved->naddrs);
+    goto error;
+  }
+  if (count != resolved->naddrs) {
+    gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved",
+            count, resolved->naddrs);
+  }
+  grpc_resolved_addresses_destroy(resolved);
+
+  /* Register with the server only upon success */
+  grpc_server_add_listener(server, tcp, start, destroy);
+
+  return 1;
+
+/* Error path: cleanup and return */
+error:
+  if (resolved) {
+    grpc_resolved_addresses_destroy(resolved);
+  }
+  if (tcp) {
+    grpc_tcp_server_destroy(tcp);
+  }
+  return 0;
+}
diff --git a/src/core/statistics/census_init.c b/src/core/statistics/census_init.c
new file mode 100644
index 0000000..340214f
--- /dev/null
+++ b/src/core/statistics/census_init.c
@@ -0,0 +1,37 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/statistics/census_interface.h"
+
+void census_init() {}
+void census_shutdown() {}
diff --git a/src/core/statistics/census_interface.h b/src/core/statistics/census_interface.h
new file mode 100644
index 0000000..7618387
--- /dev/null
+++ b/src/core/statistics/census_interface.h
@@ -0,0 +1,76 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_STATISTICS_CENSUS_INTERFACE_H__
+#define __GRPC_INTERNAL_STATISTICS_CENSUS_INTERFACE_H__
+
+#include <grpc/support/port_platform.h>
+
+/* Maximum length of an individual census trace annotation. */
+#define CENSUS_MAX_ANNOTATION_LENGTH 200
+
+/* Structure of a census op id. Define as structure because 64bit integer is not
+   available on every platform for C89. */
+typedef struct census_op_id {
+  gpr_uint32 upper;
+  gpr_uint32 lower;
+} census_op_id;
+
+typedef struct census_rpc_stats census_rpc_stats;
+
+/* Initializes Census library. No-op if Census is already initialized. */
+void census_init();
+
+/* Shutdown Census Library. */
+void census_shutdown();
+
+/* Annotates grpc method name on a census_op_id. The method name has the format
+   of <full quantified rpc service name>/<rpc function name>. Returns 0 iff
+   op_id and method_name are all valid. op_id is valid after its creation and
+   before calling census_tracing_end_op().
+
+   TODO(hongyu): Figure out valid characters set for service name and command
+   name and document requirements here.*/
+int census_add_method_tag(census_op_id op_id, const char* method_name);
+
+/* Annotates tracing information to a specific op_id.
+   Up to CENSUS_MAX_ANNOTATION_LENGTH bytes are recorded. */
+void census_tracing_print(census_op_id op_id, const char* annotation);
+
+/* Starts tracing for an RPC. Returns a locally unique census_op_id */
+census_op_id census_tracing_start_op();
+
+/* Ends tracing. Calling this function will invalidate the input op_id. */
+void census_tracing_end_op(census_op_id op_id);
+
+#endif  /* __GRPC_INTERNAL_STATISTICS_CENSUS_INTERFACE_H__ */
diff --git a/src/core/statistics/census_rpc_stats.c b/src/core/statistics/census_rpc_stats.c
new file mode 100644
index 0000000..28101ac
--- /dev/null
+++ b/src/core/statistics/census_rpc_stats.c
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+
+#include "src/core/statistics/census_interface.h"
+#include "src/core/statistics/census_rpc_stats.h"
+#include <grpc/support/alloc.h>
+
+census_rpc_stats* census_rpc_stats_create_empty() {
+  census_rpc_stats* ret =
+      (census_rpc_stats*)gpr_malloc(sizeof(census_rpc_stats));
+  memset(ret, 0, sizeof(census_rpc_stats));
+  return ret;
+}
+
+void census_aggregated_rpc_stats_destroy(census_aggregated_rpc_stats* data) {}
+
+void census_record_rpc_client_stats(census_op_id op_id,
+                                    const census_rpc_stats* stats) {}
+
+void census_record_rpc_server_stats(census_op_id op_id,
+                                    const census_rpc_stats* stats) {}
+
+void census_get_server_stats(census_aggregated_rpc_stats* data) {}
+
+void census_get_client_stats(census_aggregated_rpc_stats* data) {}
diff --git a/src/core/statistics/census_rpc_stats.h b/src/core/statistics/census_rpc_stats.h
new file mode 100644
index 0000000..6ab7614
--- /dev/null
+++ b/src/core/statistics/census_rpc_stats.h
@@ -0,0 +1,89 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_STATISTICS_CENSUS_RPC_STATS_H__
+#define __GRPC_INTERNAL_STATISTICS_CENSUS_RPC_STATS_H__
+
+#include "src/core/statistics/census_interface.h"
+#include <grpc/support/port_platform.h>
+
+struct census_rpc_stats {
+  gpr_uint64 cnt;
+  gpr_uint64 rpc_error_cnt;
+  gpr_uint64 app_error_cnt;
+  double elapsed_time_ms;
+  double api_request_bytes;
+  double wire_request_bytes;
+  double api_response_bytes;
+  double wire_response_bytes;
+};
+
+/* Creates an empty rpc stats object on heap. */
+census_rpc_stats* census_rpc_stats_create_empty();
+
+typedef struct census_per_service_per_method_rpc_stats {
+  const char* service;
+  const char* method;
+  census_rpc_stats data;
+} census_per_service_per_method_rpc_stats;
+
+typedef struct census_aggregated_rpc_stats {
+  int num_entries;
+  census_per_service_per_method_rpc_stats* stats;
+} census_aggregated_rpc_stats;
+
+/* Deletes aggregated data. */
+void census_aggregated_rpc_stats_destroy(census_aggregated_rpc_stats* data);
+
+/* Records client side stats of a rpc. */
+void census_record_rpc_client_stats(census_op_id op_id,
+                                    const census_rpc_stats* stats);
+
+/* Records server side stats of a rpc. */
+void census_record_rpc_server_stats(census_op_id op_id,
+                                    const census_rpc_stats* stats);
+
+/* The following two functions are intended for inprocess query of
+   per-service per-method stats from grpc implementations. */
+
+/* Populates *data_map with server side aggregated per-service per-method
+   stats.
+   DO NOT CALL from outside of grpc code. */
+void census_get_server_stats(census_aggregated_rpc_stats* data_map);
+
+/* Populates *data_map with client side aggregated per-service per-method
+   stats.
+   DO NOT CALL from outside of grpc code. */
+void census_get_client_stats(census_aggregated_rpc_stats* data_map);
+
+#endif  /* __GRPC_INTERNAL_STATISTICS_CENSUS_RPC_STATS_H__ */
diff --git a/src/core/statistics/census_tracing.c b/src/core/statistics/census_tracing.c
new file mode 100644
index 0000000..d0c9032
--- /dev/null
+++ b/src/core/statistics/census_tracing.c
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/statistics/census_interface.h"
+
+census_op_id census_tracing_start_op() {
+  census_op_id empty_op_id = {0, 0};
+  return empty_op_id;
+}
+
+int census_add_method_tag(census_op_id op_id, const char* method_name) {
+  return 0;
+}
+
+void census_tracing_print(census_op_id op_id, const char* annotation) {}
+
+void census_tracing_end_op(census_op_id op_id) {}
diff --git a/src/core/statistics/hash_table.c b/src/core/statistics/hash_table.c
new file mode 100644
index 0000000..f0105ee
--- /dev/null
+++ b/src/core/statistics/hash_table.c
@@ -0,0 +1,303 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/statistics/hash_table.h"
+
+#include <stdio.h>
+#include <stddef.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/port_platform.h>
+
+#define CENSUS_HT_NUM_BUCKETS 1999
+
+/* A single hash table data entry */
+typedef struct ht_entry {
+  census_ht_key key;
+  void* data;
+  struct ht_entry* next;
+} ht_entry;
+
+/* hash table bucket */
+typedef struct bucket {
+  /* NULL if bucket is empty */
+  ht_entry* next;
+  /* -1 if all buckets are empty. */
+  gpr_int32 prev_non_empty_bucket;
+  /* -1 if all buckets are empty. */
+  gpr_int32 next_non_empty_bucket;
+} bucket;
+
+struct unresizable_hash_table {
+  /* Number of entries in the table */
+  size_t size;
+  /* Number of buckets */
+  gpr_uint32 num_buckets;
+  /* Array of buckets initialized at creation time. Memory consumption is
+     16 bytes per bucket on a 64-bit platform. */
+  bucket* buckets;
+  /* Index of the first non-empty bucket. -1 iff size == 0. */
+  gpr_int32 first_non_empty_bucket;
+  /* Index of the last non_empty bucket. -1 iff size == 0. */
+  gpr_int32 last_non_empty_bucket;
+  /* Immutable options of this hash table, initialized at creation time. */
+  census_ht_option options;
+};
+
+typedef struct entry_locator {
+  gpr_int32 bucket_idx;
+  int is_first_in_chain;
+  int found;
+  ht_entry* prev_entry;
+} entry_locator;
+
+/* Asserts if option is not valid. */
+void check_options(const census_ht_option* option) {
+  GPR_ASSERT(option != NULL);
+  GPR_ASSERT(option->num_buckets > 0);
+  GPR_ASSERT(option->key_type == CENSUS_HT_UINT64 ||
+             option->key_type == CENSUS_HT_POINTER);
+  if (option->key_type == CENSUS_HT_UINT64) {
+    GPR_ASSERT(option->hash == NULL);
+  } else if (option->key_type == CENSUS_HT_POINTER) {
+    GPR_ASSERT(option->hash != NULL);
+    GPR_ASSERT(option->compare_keys != NULL);
+  }
+}
+
+#define REMOVE_NEXT(options, ptr) \
+  do {                            \
+    ht_entry* tmp = (ptr)->next;  \
+    (ptr)->next = tmp->next;      \
+    delete_entry(options, tmp);   \
+  } while (0)
+
+static void delete_entry(const census_ht_option* opt, ht_entry* p) {
+  if (opt->delete_data != NULL) {
+    opt->delete_data(p->data);
+  }
+  if (opt->delete_key != NULL) {
+    opt->delete_key(p->key.ptr);
+  }
+  gpr_free(p);
+}
+
+static gpr_uint64 hash(const census_ht_option* opt, census_ht_key key) {
+  return opt->key_type == CENSUS_HT_UINT64 ? key.val : opt->hash(key.ptr);
+}
+
+census_ht* census_ht_create(const census_ht_option* option) {
+  int i;
+  census_ht* ret = NULL;
+  check_options(option);
+  ret = (census_ht*)gpr_malloc(sizeof(census_ht));
+  ret->size = 0;
+  ret->num_buckets = option->num_buckets;
+  ret->buckets = (bucket*)gpr_malloc(sizeof(bucket) * ret->num_buckets);
+  ret->options = *option;
+  /* initialize each bucket */
+  for (i = 0; i < ret->options.num_buckets; i++) {
+    ret->buckets[i].prev_non_empty_bucket = -1;
+    ret->buckets[i].next_non_empty_bucket = -1;
+    ret->buckets[i].next = NULL;
+  }
+  return ret;
+}
+
+static gpr_int32 find_bucket_idx(const census_ht* ht, census_ht_key key) {
+  return hash(&ht->options, key) % ht->num_buckets;
+}
+
+static int keys_match(const census_ht_option* opt, const ht_entry* p,
+                      const census_ht_key key) {
+  if (opt->key_type == CENSUS_HT_UINT64) return p->key.val == key.val;
+  if (opt->key_type == CENSUS_HT_POINTER)
+    return !opt->compare_keys((p->key).ptr, key.ptr);
+  return 0;
+}
+
+static entry_locator ht_find(const census_ht* ht, census_ht_key key) {
+  entry_locator loc = {0, 0, 0, NULL};
+  gpr_int32 idx = 0;
+  ht_entry* ptr = NULL;
+  GPR_ASSERT(ht != NULL);
+  idx = find_bucket_idx(ht, key);
+  ptr = ht->buckets[idx].next;
+  if (ptr == NULL) {
+    /* bucket is empty */
+    return loc;
+  }
+  if (keys_match(&ht->options, ptr, key)) {
+    loc.bucket_idx = idx;
+    loc.is_first_in_chain = 1;
+    loc.found = 1;
+    return loc;
+  } else {
+    for (; ptr->next != NULL; ptr = ptr->next) {
+      if (keys_match(&ht->options, ptr->next, key)) {
+        loc.bucket_idx = idx;
+        loc.is_first_in_chain = 0;
+        loc.found = 1;
+        loc.prev_entry = ptr;
+        return loc;
+      }
+    }
+  }
+  /* Could not find the key */
+  return loc;
+}
+
+void* census_ht_find(const census_ht* ht, census_ht_key key) {
+  entry_locator loc = ht_find(ht, key);
+  if (loc.found == 0) {
+    return NULL;
+  }
+  return loc.is_first_in_chain ? ht->buckets[loc.bucket_idx].next->data
+                               : loc.prev_entry->next->data;
+}
+
+void census_ht_insert(census_ht* ht, census_ht_key key, void* data) {
+  gpr_int32 idx = find_bucket_idx(ht, key);
+  ht_entry* ptr = NULL;
+  entry_locator loc = ht_find(ht, key);
+  if (loc.found) {
+    /* Replace old value with new value. */
+    ptr = loc.is_first_in_chain ? ht->buckets[loc.bucket_idx].next
+                                : loc.prev_entry->next;
+    if (ht->options.delete_data != NULL) {
+      ht->options.delete_data(ptr->data);
+    }
+    ptr->data = data;
+    return;
+  }
+
+  /* first entry in the table. */
+  if (ht->size == 0) {
+    ht->buckets[idx].next_non_empty_bucket = -1;
+    ht->buckets[idx].prev_non_empty_bucket = -1;
+    ht->first_non_empty_bucket = idx;
+    ht->last_non_empty_bucket = idx;
+  } else if (ht->buckets[idx].next == NULL) {
+    /* first entry in the bucket. */
+    ht->buckets[ht->last_non_empty_bucket].next_non_empty_bucket = idx;
+    ht->buckets[idx].prev_non_empty_bucket = ht->last_non_empty_bucket;
+    ht->buckets[idx].next_non_empty_bucket = -1;
+    ht->last_non_empty_bucket = idx;
+  }
+  ptr = (ht_entry*)gpr_malloc(sizeof(ht_entry));
+  ptr->key = key;
+  ptr->data = data;
+  ptr->next = ht->buckets[idx].next;
+  ht->buckets[idx].next = ptr;
+  ht->size++;
+}
+
+void census_ht_erase(census_ht* ht, census_ht_key key) {
+  entry_locator loc = ht_find(ht, key);
+  if (loc.found == 0) {
+    /* noop if not found */
+    return;
+  }
+  ht->size--;
+  if (loc.is_first_in_chain) {
+    bucket* b = &ht->buckets[loc.bucket_idx];
+    GPR_ASSERT(b->next != NULL);
+    /* The only entry in the bucket */
+    if (b->next->next == NULL) {
+      int prev = b->prev_non_empty_bucket;
+      int next = b->next_non_empty_bucket;
+      if (prev != -1) {
+        ht->buckets[prev].next_non_empty_bucket = next;
+      } else {
+        ht->first_non_empty_bucket = next;
+      }
+      if (next != -1) {
+        ht->buckets[next].prev_non_empty_bucket = prev;
+      } else {
+        ht->last_non_empty_bucket = prev;
+      }
+    }
+    REMOVE_NEXT(&ht->options, b);
+  } else {
+    GPR_ASSERT(loc.prev_entry->next != NULL);
+    REMOVE_NEXT(&ht->options, loc.prev_entry);
+  }
+}
+
+/* Returns NULL if input table is empty. */
+census_ht_kv* census_ht_get_all_elements(const census_ht* ht, size_t* num) {
+  census_ht_kv* ret = NULL;
+  int i = 0;
+  gpr_int32 idx = -1;
+  GPR_ASSERT(ht != NULL && num != NULL);
+  *num = ht->size;
+  if (*num == 0) {
+    return NULL;
+  }
+
+  ret = (census_ht_kv*)gpr_malloc(sizeof(census_ht_kv) * ht->size);
+  idx = ht->first_non_empty_bucket;
+  while (idx >= 0) {
+    ht_entry* ptr = ht->buckets[idx].next;
+    for (; ptr != NULL; ptr = ptr->next) {
+      ret[i].k = ptr->key;
+      ret[i].v = ptr->data;
+      i++;
+    }
+    idx = ht->buckets[idx].next_non_empty_bucket;
+  }
+  return ret;
+}
+
+static void ht_delete_entry_chain(const census_ht_option* options,
+                                  ht_entry* first) {
+  if (first == NULL) {
+    return;
+  }
+  if (first->next != NULL) {
+    ht_delete_entry_chain(options, first->next);
+  }
+  delete_entry(options, first);
+}
+
+void census_ht_destroy(census_ht* ht) {
+  int i;
+  for (i = 0; i < ht->num_buckets; ++i) {
+    ht_delete_entry_chain(&ht->options, ht->buckets[i].next);
+  }
+  gpr_free(ht->buckets);
+  gpr_free(ht);
+}
+
+size_t census_ht_get_size(const census_ht* ht) { return ht->size; }
diff --git a/src/core/statistics/hash_table.h b/src/core/statistics/hash_table.h
new file mode 100644
index 0000000..5c9a3fa
--- /dev/null
+++ b/src/core/statistics/hash_table.h
@@ -0,0 +1,131 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_STATISTICS_HASH_TABLE_H_
+#define __GRPC_INTERNAL_STATISTICS_HASH_TABLE_H_
+
+#include <stddef.h>
+
+#include <grpc/support/port_platform.h>
+
+/* A chain based hash table with fixed number of buckets.
+   Your probably shouldn't use this code directly. It is implemented for the
+   use case in census trace store and stats store, where number of entries in
+   the table is in the scale of upto several thousands, entries are added and
+   removed from the table very frequently (~100k/s), the frequency of find()
+   operations is roughly several times of the frequency of insert() and erase()
+   Comparing to find(), the insert(), erase() and get_all_entries() operations
+   are much less freqent (<1/s).
+
+   Per bucket memory overhead is about (8 + sizeof(intptr_t) bytes.
+   Per entry memory overhead is about (8 + 2 * sizeof(intptr_t) bytes.
+
+   All functions are not thread-safe. Synchronization will be provided in the
+   upper layer (in trace store and stats store).
+*/
+
+/* Opaque hash table struct */
+typedef struct unresizable_hash_table census_ht;
+
+/* Currently, the hash_table can take two types of keys. (uint64 for trace
+   store and const char* for stats store). */
+typedef union {
+  gpr_uint64 val;
+  void* ptr;
+} census_ht_key;
+
+typedef enum census_ht_key_type {
+  CENSUS_HT_UINT64 = 0,
+  CENSUS_HT_POINTER = 1
+} census_ht_key_type;
+
+typedef struct census_ht_option {
+  /* Type of hash key */
+  census_ht_key_type key_type;
+  /* Desired number of buckets, preferably a prime number */
+  gpr_int32 num_buckets;
+  /* Fucntion to calculate uint64 hash value of the key. Only takes effect if
+     key_type is POINTER. */
+  gpr_uint64 (*hash)(const void*);
+  /* Function to compare two keys, returns 0 iff equal. Only takes effect if
+     key_type is POINTER */
+  int (*compare_keys)(const void* k1, const void* k2);
+  /* Value deleter. NULL if no specialized delete function is needed. */
+  void (*delete_data)(void*);
+  /* Key deleter. NULL if table does not own the key. (e.g. key is part of the
+     value or key is not owned by the table.) */
+  void (*delete_key)(void*);
+} census_ht_option;
+
+/* Creates a hashtable with fixed number of buckets according to the settings
+   specified in 'options' arg. Function pointers "hash" and "compare_keys" must
+   be provided if key_type is POINTER. Asserts if fail to create. */
+census_ht* census_ht_create(const census_ht_option* options);
+
+/* Deletes hash table instance. Frees all dynamic memory owned by ht.*/
+void census_ht_destroy(census_ht* ht);
+
+/* Inserts the input key-val pair into hash_table. If an entry with the same key
+   exists in the table, the corresponding value will be overwritten by the input
+   val. */
+void census_ht_insert(census_ht* ht, census_ht_key key, void* val);
+
+/* Returns pointer to data, returns NULL if not found. */
+void* census_ht_find(const census_ht* ht, census_ht_key key);
+
+/* Erase hash table entry with input key. Noop if key is not found. */
+void census_ht_erase(census_ht* ht, census_ht_key key);
+
+typedef struct census_ht_kv {
+  census_ht_key k;
+  void* v;
+} census_ht_kv;
+
+/* Returns an array of pointers to all values in the hash table. Order of the
+   elements can be arbitrary. Sets 'num' to the size of returned array. Caller
+   owns returned array. */
+census_ht_kv* census_ht_get_all_elements(const census_ht* ht, size_t* num);
+
+/* Returns number of elements kept. */
+size_t census_ht_get_size(const census_ht* ht);
+
+/* Functor applied on each key-value pair while iterating through entries in the
+   table. The functor should not mutate data. */
+typedef void (*census_ht_itr_cb)(census_ht_key key, const void* val_ptr,
+                                 void* state);
+
+/* Iterates through all key-value pairs in the hash_table. The callback function
+   should not invalidate data entries. */
+gpr_uint64 census_ht_for_all(const census_ht* ht, census_ht_itr_cb);
+
+#endif /* __GRPC_INTERNAL_STATISTICS_HASH_TABLE_H_ */
diff --git a/src/core/statistics/log.c b/src/core/statistics/log.c
new file mode 100644
index 0000000..43a8653
--- /dev/null
+++ b/src/core/statistics/log.c
@@ -0,0 +1,617 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Available log space is divided up in blocks of
+   CENSUS_LOG_2_MAX_RECORD_SIZE bytes. A block can be in one of the
+   following three data structures:
+   - Free blocks (free_block_list)
+   - Blocks with unread data (dirty_block_list)
+   - Blocks currently attached to cores (core_local_blocks[])
+
+   census_log_start_write() moves a block from core_local_blocks[] to the
+   end of dirty_block_list when block:
+   - is out-of-space OR
+   - has an incomplete record (an incomplete record occurs when a thread calls
+     census_log_start_write() and is context-switched before calling
+     census_log_end_write()
+   So, blocks in dirty_block_list are ordered, from oldest to newest, by time
+   when block is detached from the core.
+
+   census_log_read_next() first iterates over dirty_block_list and then
+   core_local_blocks[]. It moves completely read blocks from dirty_block_list
+   to free_block_list. Blocks in core_local_blocks[] are not freed, even when
+   completely read.
+
+   If log is configured to discard old records and free_block_list is empty,
+   census_log_start_write() iterates over dirty_block_list to allocate a
+   new block. It moves the oldest available block (no pending read/write) to
+   core_local_blocks[].
+
+   core_local_block_struct is used to implement a map from core id to the block
+   associated with that core. This mapping is advisory. It is possible that the
+   block returned by this mapping is no longer associated with that core. This
+   mapping is updated, lazily, by census_log_start_write().
+
+   Locking in block struct:
+
+   Exclusive g_log.lock must be held before calling any functions operatong on
+   block structs except census_log_start_write() and
+   census_log_end_write().
+
+   Writes to a block are serialized via writer_lock.
+   census_log_start_write() acquires this lock and
+   census_log_end_write() releases it. On failure to acquire the lock,
+   writer allocates a new block for the current core and updates
+   core_local_block accordingly.
+
+   Simultaneous read and write access is allowed. Reader can safely read up to
+   committed bytes (bytes_committed).
+
+   reader_lock protects the block, currently being read, from getting recycled.
+   start_read() acquires reader_lock and end_read() releases the lock.
+
+   Read/write access to a block is disabled via try_disable_access(). It returns
+   with both writer_lock and reader_lock held. These locks are subsequently
+   released by enable_access() to enable access to the block.
+
+   A note on naming: Most function/struct names are prepended by cl_
+   (shorthand for census_log). Further, functions that manipulate structures
+   include the name of the structure, which will be passed as the first
+   argument. E.g. cl_block_initialize() will initialize a cl_block.
+*/
+#include "src/core/statistics/log.h"
+#include <string.h>
+#include "src/core/support/cpu.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/atm.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/sync.h>
+
+/* End of platform specific code */
+
+typedef struct census_log_block_list_struct {
+  struct census_log_block_list_struct* next;
+  struct census_log_block_list_struct* prev;
+  struct census_log_block* block;
+} cl_block_list_struct;
+
+typedef struct census_log_block {
+  /* Pointer to underlying buffer */
+  char* buffer;
+  gpr_atm writer_lock;
+  gpr_atm reader_lock;
+  /* Keeps completely written bytes. Declared atomic because accessed
+     simultaneously by reader and writer. */
+  gpr_atm bytes_committed;
+  /* Bytes already read */
+  gpr_int32 bytes_read;
+  /* Links for list */
+  cl_block_list_struct link;
+  /* We want this structure to be cacheline aligned. We assume the following
+     sizes for the various parts on 32/64bit systems:
+     type                 32b size    64b size
+     char*                   4           8
+     3x gpr_atm             12          24
+     gpr_int32               4           8 (assumes padding)
+     cl_block_list_struct   12          24
+     TOTAL                  32          64
+
+     Depending on the size of our cacheline and the architecture, we
+     selectively add char buffering to this structure. The size is checked
+     via assert in census_log_initialize(). */
+#if defined(GPR_ARCH_64)
+#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 64)
+#else
+#if defined(GPR_ARCH_32)
+#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 32)
+#else
+#error "Unknown architecture"
+#endif
+#endif
+#if CL_BLOCK_PAD_SIZE > 0
+  char padding[CL_BLOCK_PAD_SIZE];
+#endif
+} cl_block;
+
+/* A list of cl_blocks, doubly-linked through cl_block::link. */
+typedef struct census_log_block_list {
+  gpr_int32 count;  /* Number of items in list. */
+  cl_block_list_struct ht;  /* head/tail of linked list. */
+} cl_block_list;
+
+/* Cacheline aligned block pointers to avoid false sharing. Block pointer must
+   be initialized via set_block(), before calling other functions */
+typedef struct census_log_core_local_block {
+  gpr_atm block;
+  /* Ensure cachline alignment: we assume sizeof(gpr_atm) == 4 or 8 */
+#if defined(GPR_ARCH_64)
+#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 8)
+#else
+#if defined(GPR_ARCH_32)
+#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 4)
+#else
+#error "Unknown architecture"
+#endif
+#endif
+#if CL_CORE_LOCAL_BLOCK_PAD_SIZE > 0
+  char padding[CL_CORE_LOCAL_BLOCK_PAD_SIZE];
+#endif
+} cl_core_local_block;
+
+struct census_log {
+  int discard_old_records;
+  /* Number of cores (aka hardware-contexts) */
+  int num_cores;
+  /* number of CENSUS_LOG_2_MAX_RECORD_SIZE blocks in log */
+  gpr_int32 num_blocks;
+  cl_block* blocks;  /* Block metadata. */
+  cl_core_local_block* core_local_blocks;  /* Keeps core to block mappings. */
+  gpr_mu lock;
+  int initialized;  /* has log been initialized? */
+  /* Keeps the state of the reader iterator. A value of 0 indicates that
+     iterator has reached the end. census_log_init_reader() resets the
+     value to num_core to restart iteration. */
+  gpr_int32 read_iterator_state;
+  /* Points to the block being read. If non-NULL, the block is locked for
+     reading (block_being_read_->reader_lock is held). */
+  cl_block* block_being_read;
+  /* A non-zero value indicates that log is full. */
+  gpr_atm is_full;
+  char* buffer;
+  cl_block_list free_block_list;
+  cl_block_list dirty_block_list;
+  gpr_atm out_of_space_count;
+};
+
+/* Single internal log */
+static struct census_log g_log;
+
+/* Functions that operate on an atomic memory location used as a lock */
+
+/* Returns non-zero if lock is acquired */
+static int cl_try_lock(gpr_atm* lock) {
+  return gpr_atm_acq_cas(lock, 0, 1);
+}
+
+static void cl_unlock(gpr_atm* lock) {
+  gpr_atm_rel_store(lock, 0);
+}
+
+
+/* Functions that operate on cl_core_local_block's */
+
+static void cl_core_local_block_set_block(cl_core_local_block* clb,
+                                          cl_block* block) {
+  gpr_atm_rel_store(&clb->block, (gpr_atm)block);
+}
+
+static cl_block* cl_core_local_block_get_block(cl_core_local_block* clb) {
+  return (cl_block*)gpr_atm_acq_load(&clb->block);
+}
+
+
+/* Functions that operate on cl_block_list_struct's */
+
+static void cl_block_list_struct_initialize(cl_block_list_struct* bls,
+                                            cl_block* block) {
+  bls->next = bls->prev = bls;
+  bls->block = block;
+}
+
+
+/* Functions that operate on cl_block_list's */
+
+static void cl_block_list_initialize(cl_block_list* list) {
+  list->count = 0;
+  cl_block_list_struct_initialize(&list->ht, NULL);
+}
+
+/* Returns head of *this, or NULL if empty. */
+static cl_block* cl_block_list_head(cl_block_list* list) {
+  return list->ht.next->block;
+}
+
+/* Insert element *e after *pos. */
+static void cl_block_list_insert(cl_block_list* list,
+                                 cl_block_list_struct* pos,
+                                 cl_block_list_struct* e) {
+  list->count++;
+  e->next = pos->next;
+  e->prev = pos;
+  e->next->prev = e;
+  e->prev->next = e;
+}
+
+/* Insert block at the head of the list */
+static void cl_block_list_insert_at_head(cl_block_list* list,
+                                         cl_block* block) {
+  cl_block_list_insert(list, &list->ht, &block->link);
+}
+
+/* Insert block at the tail of the list */
+static void cl_block_list_insert_at_tail(cl_block_list* list,
+                                         cl_block* block) {
+  cl_block_list_insert(list, list->ht.prev, &block->link);
+}
+
+/* Removes block *b. Requires *b be in the list. */
+static void cl_block_list_remove(cl_block_list* list, cl_block* b) {
+  list->count--;
+  b->link.next->prev = b->link.prev;
+  b->link.prev->next = b->link.next;
+}
+
+
+/* Functions that operate on cl_block's */
+
+static void cl_block_initialize(cl_block* block, char* buffer) {
+  block->buffer = buffer;
+  gpr_atm_rel_store(&block->writer_lock, 0);
+  gpr_atm_rel_store(&block->reader_lock, 0);
+  gpr_atm_rel_store(&block->bytes_committed, 0);
+  block->bytes_read = 0;
+  cl_block_list_struct_initialize(&block->link, block);
+}
+
+/* Guards against exposing partially written buffer to the reader. */
+static void cl_block_set_bytes_committed(cl_block* block,
+                                         gpr_int32 bytes_committed) {
+  gpr_atm_rel_store(&block->bytes_committed, bytes_committed);
+}
+
+static gpr_int32 cl_block_get_bytes_committed(cl_block* block) {
+  return gpr_atm_acq_load(&block->bytes_committed);
+}
+
+/* Tries to disable future read/write access to this block. Succeeds if:
+   - no in-progress write AND
+   - no in-progress read AND
+   - 'discard_data' set to true OR no unread data
+   On success, clears the block state and returns with writer_lock_ and
+   reader_lock_ held. These locks are released by a subsequent
+   cl_block_access_enable() call. */
+static int cl_block_try_disable_access(cl_block* block, int discard_data) {
+  if (!cl_try_lock(&block->writer_lock)) {
+    return 0;
+  }
+  if (!cl_try_lock(&block->reader_lock)) {
+    cl_unlock(&block->writer_lock);
+    return 0;
+  }
+  if (!discard_data &&
+      (block->bytes_read != cl_block_get_bytes_committed(block))) {
+    cl_unlock(&block->reader_lock);
+    cl_unlock(&block->writer_lock);
+    return 0;
+  }
+  cl_block_set_bytes_committed(block, 0);
+  block->bytes_read = 0;
+  return 1;
+}
+
+static void cl_block_enable_access(cl_block* block) {
+  cl_unlock(&block->reader_lock);
+  cl_unlock(&block->writer_lock);
+}
+
+/* Returns with writer_lock held. */
+static void* cl_block_start_write(cl_block* block, size_t size) {
+  gpr_int32 bytes_committed;
+  if (!cl_try_lock(&block->writer_lock)) {
+    return NULL;
+  }
+  bytes_committed = cl_block_get_bytes_committed(block);
+  if (bytes_committed + size > CENSUS_LOG_MAX_RECORD_SIZE) {
+    cl_unlock(&block->writer_lock);
+    return NULL;
+  }
+  return block->buffer + bytes_committed;
+}
+
+/* Releases writer_lock and increments committed bytes by 'bytes_written'.
+  'bytes_written' must be <= 'size' specified in the corresponding
+  StartWrite() call. This function is thread-safe. */
+static void cl_block_end_write(cl_block* block, size_t bytes_written) {
+  cl_block_set_bytes_committed(
+      block, cl_block_get_bytes_committed(block) + bytes_written);
+  cl_unlock(&block->writer_lock);
+}
+
+/* Returns a pointer to the first unread byte in buffer. The number of bytes
+   available are returned in 'bytes_available'. Acquires reader lock that is
+   released by a subsequent cl_block_end_read() call. Returns NULL if:
+   - read in progress
+   - no data available */
+static void* cl_block_start_read(cl_block* block, size_t* bytes_available) {
+  void* record;
+  if (!cl_try_lock(&block->reader_lock)) {
+    return NULL;
+  }
+  /* bytes_committed may change from under us. Use bytes_available to update
+     bytes_read below. */
+  *bytes_available = cl_block_get_bytes_committed(block) - block->bytes_read;
+  if (*bytes_available == 0) {
+    cl_unlock(&block->reader_lock);
+    return NULL;
+  }
+  record = block->buffer + block->bytes_read;
+  block->bytes_read += *bytes_available;
+  return record;
+}
+
+static void cl_block_end_read(cl_block* block) {
+  cl_unlock(&block->reader_lock);
+}
+
+
+/* Internal functions operating on g_log */
+
+/* Allocates a new free block (or recycles an available dirty block if log is
+   configured to discard old records). Returns NULL if out-of-space. */
+static cl_block* cl_allocate_block() {
+  cl_block* block = cl_block_list_head(&g_log.free_block_list);
+  if (block != NULL) {
+    cl_block_list_remove(&g_log.free_block_list, block);
+    return block;
+  }
+  if (!g_log.discard_old_records) {
+    /* No free block and log is configured to keep old records. */
+    return NULL;
+  }
+  /* Recycle dirty block. Start from the oldest. */
+  for (block = cl_block_list_head(&g_log.dirty_block_list); block != NULL;
+       block = block->link.next->block) {
+    if (cl_block_try_disable_access(block, 1 /* discard data */)) {
+      cl_block_list_remove(&g_log.dirty_block_list, block);
+      return block;
+    }
+  }
+  return NULL;
+}
+
+/* Allocates a new block and updates core id => block mapping. 'old_block'
+   points to the block that the caller thinks is attached to
+   'core_id'. 'old_block' may be NULL. Returns non-zero if:
+   - allocated a new block OR
+   - 'core_id' => 'old_block' mapping changed (another thread allocated a
+     block before lock was acquired). */
+static int cl_allocate_core_local_block(gpr_int32 core_id,
+                                        cl_block* old_block) {
+  /* Now that we have the lock, check if core-local mapping has changed. */
+  cl_core_local_block* core_local_block = &g_log.core_local_blocks[core_id];
+  cl_block* block = cl_core_local_block_get_block(core_local_block);
+  if ((block != NULL) && (block != old_block)) {
+    return 1;
+  }
+  if (block != NULL) {
+    cl_core_local_block_set_block(core_local_block, NULL);
+    cl_block_list_insert_at_tail(&g_log.dirty_block_list, block);
+  }
+  block = cl_allocate_block();
+  if (block == NULL) {
+    gpr_atm_rel_store(&g_log.is_full, 1);
+    return 0;
+  }
+  cl_core_local_block_set_block(core_local_block, block);
+  cl_block_enable_access(block);
+  return 1;
+}
+
+static cl_block* cl_get_block(void* record) {
+  gpr_uintptr p = (gpr_uintptr)((char*)record - g_log.buffer);
+  gpr_uintptr index = p >> CENSUS_LOG_2_MAX_RECORD_SIZE;
+  return &g_log.blocks[index];
+}
+
+/* Gets the next block to read and tries to free 'prev' block (if not NULL).
+   Returns NULL if reached the end. */
+static cl_block* cl_next_block_to_read(cl_block* prev) {
+  cl_block* block = NULL;
+  if (g_log.read_iterator_state == g_log.num_cores) {
+    /* We are traversing dirty list; find the next dirty block. */
+    if (prev != NULL) {
+      /* Try to free the previous block if there is no unread data. This block
+         may have unread data if previously incomplete record completed between
+         read_next() calls. */
+      block = prev->link.next->block;
+      if (cl_block_try_disable_access(prev, 0 /* do not discard data */)) {
+        cl_block_list_remove(&g_log.dirty_block_list, prev);
+        cl_block_list_insert_at_head(&g_log.free_block_list, prev);
+        gpr_atm_rel_store(&g_log.is_full, 0);
+      }
+    } else {
+      block = cl_block_list_head(&g_log.dirty_block_list);
+    }
+    if (block != NULL) {
+      return block;
+    }
+    /* We are done with the dirty list; moving on to core-local blocks. */
+  }
+  while (g_log.read_iterator_state > 0) {
+    g_log.read_iterator_state--;
+    block = cl_core_local_block_get_block(
+        &g_log.core_local_blocks[g_log.read_iterator_state]);
+    if (block != NULL) {
+      return block;
+    }
+  }
+  return NULL;
+}
+
+/* External functions: primary stats_log interface */
+void census_log_initialize(size_t size_in_mb, int discard_old_records) {
+  gpr_int32 ix;
+  /* check cacheline alignment */
+  GPR_ASSERT(sizeof(cl_block) % GPR_CACHELINE_SIZE == 0);
+  GPR_ASSERT(sizeof(cl_core_local_block) % GPR_CACHELINE_SIZE == 0);
+  GPR_ASSERT(!g_log.initialized);
+  g_log.discard_old_records = discard_old_records;
+  g_log.num_cores = gpr_cpu_num_cores();
+  if (size_in_mb < 1 || size_in_mb > 1000) {
+    gpr_log(GPR_ERROR, "Invalid size for stats_log: using 1MB default");
+    size_in_mb = 1;
+  }
+  g_log.num_blocks = (size_in_mb << 20) >> CENSUS_LOG_2_MAX_RECORD_SIZE;
+  gpr_mu_init(&g_log.lock);
+  g_log.read_iterator_state = 0;
+  g_log.block_being_read = NULL;
+  gpr_atm_rel_store(&g_log.is_full, 0);
+  g_log.core_local_blocks = (cl_core_local_block*)gpr_malloc_aligned(
+      g_log.num_cores * sizeof(cl_core_local_block), GPR_CACHELINE_SIZE);
+  memset(g_log.core_local_blocks, 0,
+         g_log.num_cores * sizeof(cl_core_local_block));
+  g_log.blocks = (cl_block*)gpr_malloc_aligned(
+      g_log.num_blocks * sizeof(cl_block), GPR_CACHELINE_SIZE);
+  memset(g_log.blocks, 0, g_log.num_blocks * sizeof(cl_block));
+  g_log.buffer = gpr_malloc(g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE);
+  memset(g_log.buffer, 0, g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE);
+  cl_block_list_initialize(&g_log.free_block_list);
+  cl_block_list_initialize(&g_log.dirty_block_list);
+  for (ix = 0; ix < g_log.num_blocks; ++ix) {
+    cl_block* block = g_log.blocks + ix;
+    cl_block_initialize(block,
+                         g_log.buffer + (CENSUS_LOG_MAX_RECORD_SIZE * ix));
+    cl_block_try_disable_access(block, 1 /* discard data */);
+    cl_block_list_insert_at_tail(&g_log.free_block_list, block);
+  }
+  gpr_atm_rel_store(&g_log.out_of_space_count, 0);
+  g_log.initialized = 1;
+}
+
+void census_log_shutdown() {
+  GPR_ASSERT(g_log.initialized);
+  gpr_mu_destroy(&g_log.lock);
+  gpr_free_aligned(g_log.core_local_blocks);
+  g_log.core_local_blocks = NULL;
+  gpr_free_aligned(g_log.blocks);
+  g_log.blocks = NULL;
+  gpr_free(g_log.buffer);
+  g_log.buffer = NULL;
+  g_log.initialized = 0;
+}
+
+void* census_log_start_write(size_t size) {
+  /* Used to bound number of times block allocation is attempted. */
+  gpr_int32 attempts_remaining = g_log.num_blocks;
+  /* TODO(aveitch): move this inside the do loop when current_cpu is fixed */
+  gpr_int32 core_id = gpr_cpu_current_cpu();
+  GPR_ASSERT(g_log.initialized);
+  if (size > CENSUS_LOG_MAX_RECORD_SIZE) {
+    return NULL;
+  }
+  do {
+    int allocated;
+    void* record = NULL;
+    cl_block* block =
+        cl_core_local_block_get_block(&g_log.core_local_blocks[core_id]);
+    if (block && (record = cl_block_start_write(block, size))) {
+      return record;
+    }
+    /* Need to allocate a new block. We are here if:
+       - No block associated with the core OR
+       - Write in-progress on the block OR
+       - block is out of space */
+    if (gpr_atm_acq_load(&g_log.is_full)) {
+      gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1);
+      return NULL;
+    }
+    gpr_mu_lock(&g_log.lock);
+    allocated = cl_allocate_core_local_block(core_id, block);
+    gpr_mu_unlock(&g_log.lock);
+    if (!allocated) {
+      gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1);
+      return NULL;
+    }
+  } while (attempts_remaining--);
+  /* Give up. */
+  gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1);
+  return NULL;
+}
+
+void census_log_end_write(void* record, size_t bytes_written) {
+  GPR_ASSERT(g_log.initialized);
+  cl_block_end_write(cl_get_block(record), bytes_written);
+}
+
+void census_log_init_reader() {
+  GPR_ASSERT(g_log.initialized);
+  gpr_mu_lock(&g_log.lock);
+  /* If a block is locked for reading unlock it. */
+  if (g_log.block_being_read != NULL) {
+    cl_block_end_read(g_log.block_being_read);
+    g_log.block_being_read = NULL;
+  }
+  g_log.read_iterator_state = g_log.num_cores;
+  gpr_mu_unlock(&g_log.lock);
+}
+
+const void* census_log_read_next(size_t* bytes_available) {
+  GPR_ASSERT(g_log.initialized);
+  gpr_mu_lock(&g_log.lock);
+  if (g_log.block_being_read != NULL) {
+    cl_block_end_read(g_log.block_being_read);
+  }
+  do {
+    g_log.block_being_read = cl_next_block_to_read(g_log.block_being_read);
+    if (g_log.block_being_read != NULL) {
+      void* record = cl_block_start_read(g_log.block_being_read,
+                                          bytes_available);
+      if (record != NULL) {
+        gpr_mu_unlock(&g_log.lock);
+        return record;
+      }
+    }
+  } while (g_log.block_being_read != NULL);
+  gpr_mu_unlock(&g_log.lock);
+  return NULL;
+}
+
+size_t census_log_remaining_space() {
+  size_t space;
+  GPR_ASSERT(g_log.initialized);
+  gpr_mu_lock(&g_log.lock);
+  if (g_log.discard_old_records) {
+    /* Remaining space is not meaningful; just return the entire log space. */
+    space = g_log.num_blocks << CENSUS_LOG_2_MAX_RECORD_SIZE;
+  } else {
+    space = g_log.free_block_list.count * CENSUS_LOG_MAX_RECORD_SIZE;
+  }
+  gpr_mu_unlock(&g_log.lock);
+  return space;
+}
+
+int census_log_out_of_space_count() {
+  GPR_ASSERT(g_log.initialized);
+  return gpr_atm_acq_load(&g_log.out_of_space_count);
+}
diff --git a/src/core/statistics/log.h b/src/core/statistics/log.h
new file mode 100644
index 0000000..e9c745c
--- /dev/null
+++ b/src/core/statistics/log.h
@@ -0,0 +1,89 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_STATISTICS_LOG_H__
+#define __GRPC_INTERNAL_STATISTICS_LOG_H__
+
+#include <stddef.h>
+
+/* Maximum record size, in bytes. */
+#define CENSUS_LOG_2_MAX_RECORD_SIZE 14 /* 2^14 = 16KB */
+#define CENSUS_LOG_MAX_RECORD_SIZE (1 << CENSUS_LOG_2_MAX_RECORD_SIZE)
+
+/* Initialize the statistics logging subsystem with the given log size. If
+   discard_old_records is non-zero, then new records will displace older
+   ones when the log is full. This function must be called before any other
+   census_log functions.
+*/
+void census_log_initialize(size_t size_in_mb, int discard_old_records);
+
+/* Shutdown the logging subsystem. Caller must ensure that:
+   - no in progress or future call to any census_log functions
+   - no incomplete records
+*/
+void census_log_shutdown();
+
+/* Allocates and returns a 'size' bytes record and marks it in use. A
+   subsequent census_log_end_write() marks the record complete. The
+   'bytes_written' census_log_end_write() argument must be <=
+   'size'. Returns NULL if out-of-space AND:
+       - log is configured to keep old records OR
+       - all blocks are pinned by incomplete records.
+*/
+void* census_log_start_write(size_t size);
+
+void census_log_end_write(void* record, size_t bytes_written);
+
+/* census_log_read_next() iterates over blocks with data and for each block
+   returns a pointer to the first unread byte. The number of bytes that can be
+   read are returned in 'bytes_available'. Reader is expected to read all
+   available data. Reading the data consumes it i.e. it cannot be read again.
+   census_log_read_next() returns NULL if the end is reached i.e last block
+   is read. census_log_init_reader() starts the iteration or aborts the
+   current iteration.
+*/
+void census_log_init_reader();
+const void* census_log_read_next(size_t* bytes_available);
+
+/* Returns estimated remaining space across all blocks, in bytes. If log is
+   configured to discard old records, returns total log space. Otherwise,
+   returns space available in empty blocks (partially filled blocks are
+   treated as full).
+*/
+size_t census_log_remaining_space();
+
+/* Returns the number of times gprc_stats_log_start_write() failed due to
+   out-of-space. */
+int census_log_out_of_space_count();
+
+#endif  /* __GRPC_INTERNAL_STATISTICS_LOG_H__ */
diff --git a/src/core/statistics/window_stats.c b/src/core/statistics/window_stats.c
new file mode 100644
index 0000000..be53d81
--- /dev/null
+++ b/src/core/statistics/window_stats.c
@@ -0,0 +1,317 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/statistics/window_stats.h"
+#include <math.h>
+#include <stddef.h>
+#include <string.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+
+/* typedefs make typing long names easier. Use cws (for census_window_stats) */
+typedef census_window_stats_stat_info cws_stat_info;
+typedef struct census_window_stats_sum cws_sum;
+
+/* Each interval is composed of a number of buckets, which hold a count of
+   entries and a single statistic */
+typedef struct census_window_stats_bucket {
+  gpr_int64 count;
+  void* statistic;
+} cws_bucket;
+
+/* Each interval has a set of buckets, and the variables needed to keep
+   track of their current state */
+typedef struct census_window_stats_interval_stats {
+  /* The buckets. There will be 'granularity' + 1 of these. */
+  cws_bucket* buckets;
+  /* Index of the bucket containing the smallest time interval. */
+  int bottom_bucket;
+  /* The smallest time storable in the current window. */
+  gpr_int64 bottom;
+  /* The largest time storable in the current window + 1ns */
+  gpr_int64 top;
+  /* The width of each bucket in ns. */
+  gpr_int64 width;
+} cws_interval_stats;
+
+typedef struct census_window_stats {
+  /* Number of intervals. */
+  int nintervals;
+  /* Number of buckets in each interval. 'granularity' + 1. */
+  int nbuckets;
+  /* Record of stat_info. */
+  cws_stat_info stat_info;
+  /* Stats for each interval. */
+  cws_interval_stats* interval_stats;
+  /* The time the newset stat was recorded. */
+  gpr_int64 newest_time;
+} window_stats;
+
+/* Calculate an actual bucket index from a logical index 'IDX'. Other
+   parameters supply information on the interval struct and overall stats. */
+#define BUCKET_IDX(IS, IDX, WSTATS) \
+  ((IS->bottom_bucket + (IDX)) % WSTATS->nbuckets)
+
+/* The maximum seconds value we can have in a valid timespec. More than this
+   will result in overflow in timespec_to_ns(). This works out to ~292 years.
+   TODO: consider using doubles instead of int64. */
+static gpr_int64 max_seconds =
+    (GPR_INT64_MAX - GPR_NS_PER_SEC) / GPR_NS_PER_SEC;
+
+static gpr_int64 timespec_to_ns(const gpr_timespec ts) {
+  if (ts.tv_sec > max_seconds) {
+    return GPR_INT64_MAX - 1;
+  }
+  return (gpr_int64)ts.tv_sec * GPR_NS_PER_SEC + ts.tv_nsec;
+}
+
+static void cws_initialize_statistic(void* statistic,
+                                     const cws_stat_info* stat_info) {
+  if (stat_info->stat_initialize == NULL) {
+    memset(statistic, 0, stat_info->stat_size);
+  } else {
+    stat_info->stat_initialize(statistic);
+  }
+}
+
+/* Create and initialize a statistic */
+static void* cws_create_statistic(const cws_stat_info* stat_info) {
+  void* stat = gpr_malloc(stat_info->stat_size);
+  cws_initialize_statistic(stat, stat_info);
+  return stat;
+}
+
+window_stats* census_window_stats_create(int nintervals,
+                                         const gpr_timespec intervals[],
+                                         int granularity,
+                                         const cws_stat_info* stat_info) {
+  window_stats* ret;
+  int i;
+  /* validate inputs */
+  GPR_ASSERT(nintervals > 0 && granularity > 2 && intervals != NULL &&
+             stat_info != NULL);
+  for (i = 0; i < nintervals; i++) {
+    gpr_int64 ns = timespec_to_ns(intervals[i]);
+    GPR_ASSERT(intervals[i].tv_sec >= 0 && intervals[i].tv_nsec >= 0 &&
+               intervals[i].tv_nsec < GPR_NS_PER_SEC && ns >= 100 &&
+               granularity * 10 <= ns);
+  }
+  /* Allocate and initialize relevant data structures */
+  ret = (window_stats*)gpr_malloc(sizeof(window_stats));
+  ret->nintervals = nintervals;
+  ret->nbuckets = granularity + 1;
+  ret->stat_info = *stat_info;
+  ret->interval_stats =
+      (cws_interval_stats*)gpr_malloc(nintervals * sizeof(cws_interval_stats));
+  for (i = 0; i < nintervals; i++) {
+    gpr_int64 size_ns = timespec_to_ns(intervals[i]);
+    cws_interval_stats* is = ret->interval_stats + i;
+    cws_bucket* buckets = is->buckets =
+        (cws_bucket*)gpr_malloc(ret->nbuckets * sizeof(cws_bucket));
+    int b;
+    for (b = 0; b < ret->nbuckets; b++) {
+      buckets[b].statistic = cws_create_statistic(stat_info);
+      buckets[b].count = 0;
+    }
+    is->bottom_bucket = 0;
+    is->bottom = 0;
+    is->width = size_ns / granularity;
+    /* Check for possible overflow issues, and maximize interval size if the
+       user requested something large enough. */
+    if (GPR_INT64_MAX - is->width > size_ns) {
+      is->top = size_ns + is->width;
+    } else {
+      is->top = GPR_INT64_MAX;
+      is->width = GPR_INT64_MAX / (granularity + 1);
+    }
+    /* If size doesn't divide evenly, we can have a width slightly too small;
+       better to have it slightly large. */
+    if ((size_ns - (granularity + 1) * is->width) > 0) {
+      is->width += 1;
+    }
+  }
+  ret->newest_time = 0;
+  return ret;
+}
+
+/* When we try adding a measurement above the current interval range, we
+   need to "shift" the buckets sufficiently to cover the new range. */
+static void cws_shift_buckets(const window_stats* wstats,
+                              cws_interval_stats* is, gpr_int64 when_ns) {
+  int i;
+  /* number of bucket time widths to "shift" */
+  int shift;
+  /* number of buckets to clear */
+  int nclear;
+  GPR_ASSERT(when_ns >= is->top);
+  /* number of bucket time widths to "shift" */
+  shift = ((when_ns - is->top) / is->width) + 1;
+  /* number of buckets to clear - limited by actual number of buckets */
+  nclear = GPR_MIN(shift, wstats->nbuckets);
+  for (i = 0; i < nclear; i++) {
+    int b = BUCKET_IDX(is, i, wstats);
+    is->buckets[b].count = 0;
+    cws_initialize_statistic(is->buckets[b].statistic, &wstats->stat_info);
+  }
+  /* adjust top/bottom times and current bottom bucket */
+  is->bottom_bucket = BUCKET_IDX(is, shift, wstats);
+  is->top += shift * is->width;
+  is->bottom += shift * is->width;
+}
+
+void census_window_stats_add(window_stats* wstats, const gpr_timespec when,
+                             const void* stat_value) {
+  int i;
+  gpr_int64 when_ns = timespec_to_ns(when);
+  GPR_ASSERT(wstats->interval_stats != NULL);
+  for (i = 0; i < wstats->nintervals; i++) {
+    cws_interval_stats* is = wstats->interval_stats + i;
+    cws_bucket* bucket;
+    if (when_ns < is->bottom) { /* Below smallest time in interval: drop */
+      continue;
+    }
+    if (when_ns >= is->top) { /* above limit: shift buckets */
+      cws_shift_buckets(wstats, is, when_ns);
+    }
+    /* Add the stat. */
+    GPR_ASSERT(is->bottom <= when_ns && when_ns < is->top);
+    bucket = is->buckets +
+             BUCKET_IDX(is, (when_ns - is->bottom) / is->width, wstats);
+    bucket->count++;
+    wstats->stat_info.stat_add(bucket->statistic, stat_value);
+  }
+  if (when_ns > wstats->newest_time) {
+    wstats->newest_time = when_ns;
+  }
+}
+
+/* Add a specific bucket contents to an accumulating total. */
+static void cws_add_bucket_to_sum(cws_sum* sum, const cws_bucket* bucket,
+                                  const cws_stat_info* stat_info) {
+  sum->count += bucket->count;
+  stat_info->stat_add(sum->statistic, bucket->statistic);
+}
+
+/* Add a proportion to an accumulating sum. */
+static void cws_add_proportion_to_sum(double p, cws_sum* sum,
+                                      const cws_bucket* bucket,
+                                      const cws_stat_info* stat_info) {
+  sum->count += p * bucket->count;
+  stat_info->stat_add_proportion(p, sum->statistic, bucket->statistic);
+}
+
+void census_window_stats_get_sums(const window_stats* wstats,
+                                  const gpr_timespec when, cws_sum sums[]) {
+  int i;
+  gpr_int64 when_ns = timespec_to_ns(when);
+  GPR_ASSERT(wstats->interval_stats != NULL);
+  for (i = 0; i < wstats->nintervals; i++) {
+    int when_bucket;
+    int new_bucket;
+    double last_proportion = 1.0;
+    double bottom_proportion;
+    cws_interval_stats* is = wstats->interval_stats + i;
+    cws_sum* sum = sums + i;
+    sum->count = 0;
+    cws_initialize_statistic(sum->statistic, &wstats->stat_info);
+    if (when_ns < is->bottom) {
+      continue;
+    }
+    if (when_ns >= is->top) {
+      cws_shift_buckets(wstats, is, when_ns);
+    }
+    /* Calculating the appropriate amount of which buckets to use can get
+       complicated. Essentially there are two cases:
+       1) if the "top" bucket (new_bucket, where the newest additions to the
+          stats recorded are entered) corresponds to 'when', then we need
+          to take a proportion of it - (if when < newest_time) or the full
+          thing. We also (possibly) need to take a corresponding
+          proportion of the bottom bucket.
+       2) Other cases, we just take a straight proportion.
+    */
+    when_bucket = (when_ns - is->bottom) / is->width;
+    new_bucket = (wstats->newest_time - is->bottom) / is->width;
+    if (new_bucket == when_bucket) {
+      gpr_int64 bottom_bucket_time = is->bottom + when_bucket * is->width;
+      if (when_ns < wstats->newest_time) {
+        last_proportion = (double)(when_ns - bottom_bucket_time) /
+                          (double)(wstats->newest_time - bottom_bucket_time);
+        bottom_proportion =
+            (double)(is->width - (when_ns - bottom_bucket_time)) / is->width;
+      } else {
+        bottom_proportion =
+            (double)(is->width - (wstats->newest_time - bottom_bucket_time)) /
+            is->width;
+      }
+    } else {
+      last_proportion =
+          (double)(when_ns + 1 - is->bottom - when_bucket * is->width) /
+          is->width;
+      bottom_proportion = 1.0 - last_proportion;
+    }
+    cws_add_proportion_to_sum(last_proportion, sum,
+                              is->buckets + BUCKET_IDX(is, when_bucket, wstats),
+                              &wstats->stat_info);
+    if (when_bucket != 0) { /* last bucket isn't also bottom bucket */
+      int b;
+      /* Add all of "bottom" bucket if we are looking at a subset of the
+         full interval, or a proportion if we are adding full interval. */
+      cws_add_proportion_to_sum(
+          (when_bucket == wstats->nbuckets - 1 ? bottom_proportion : 1.0), sum,
+          is->buckets + is->bottom_bucket, &wstats->stat_info);
+      /* Add all the remaining buckets (everything but top and bottom). */
+      for (b = 1; b < when_bucket; b++) {
+        cws_add_bucket_to_sum(sum, is->buckets + BUCKET_IDX(is, b, wstats),
+                              &wstats->stat_info);
+      }
+    }
+  }
+}
+
+void census_window_stats_destroy(window_stats* wstats) {
+  int i;
+  GPR_ASSERT(wstats->interval_stats != NULL);
+  for (i = 0; i < wstats->nintervals; i++) {
+    int b;
+    for (b = 0; b < wstats->nbuckets; b++) {
+      gpr_free(wstats->interval_stats[i].buckets[b].statistic);
+    }
+    gpr_free(wstats->interval_stats[i].buckets);
+  }
+  gpr_free(wstats->interval_stats);
+  /* Ensure any use-after free triggers assert. */
+  wstats->interval_stats = NULL;
+  gpr_free(wstats);
+}
diff --git a/src/core/statistics/window_stats.h b/src/core/statistics/window_stats.h
new file mode 100644
index 0000000..677f400
--- /dev/null
+++ b/src/core/statistics/window_stats.h
@@ -0,0 +1,173 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_STATISTICS_WINDOW_STATS_H_
+#define __GRPC_INTERNAL_STATISTICS_WINDOW_STATS_H_
+
+#include <grpc/support/time.h>
+
+/* Keep rolling sums of a user-defined statistic (containing a number of
+   measurements) over a a number of time intervals ("windows"). For example,
+   you can use a window_stats object to answer questions such as
+   "Approximately how many RPCs/s did I receive over the past minute, and
+   approximately how many bytes did I send out over that period?".
+
+   The type of data to record, and the time intervals to keep are specified
+   when creating the object via a call to census_window_stats_create().
+
+   A window's interval is divided into one or more "buckets"; the interval
+   must be divisible by the number of buckets. Internally, these buckets
+   control the granularity of window_stats' measurements. Increasing the
+   number of buckets lets the object respond more quickly to changes in the
+   overall rate of data added into the object, at the cost of additional
+   memory usage.
+
+   Here's some code which keeps one minute/hour measurements for two values
+   (latency in seconds and bytes transferred), with each interval divided into
+   4 buckets.
+
+    typedef struct my_stat {
+      double latency;
+      int bytes;
+    } my_stat;
+
+    void add_my_stat(void* base, const void* addme) {
+      my_stat* b = (my_stat*)base;
+      const my_stat* a = (const my_stat*)addme;
+      b->latency += a->latency;
+      b->bytes += a->bytes;
+    }
+
+    void add_proportion_my_stat(double p, void* base, const void* addme) {
+      (my_stat*)result->latency += p * (const my_stat*)base->latency;
+      (my_stat*)result->bytes += p * (const my_stat*)base->bytes;
+    }
+
+    #define kNumIntervals 2
+    #define kMinInterval 0
+    #define kHourInterval 1
+    #define kNumBuckets 4
+
+    const struct census_window_stats_stat_info kMyStatInfo
+        = { sizeof(my_stat), NULL, add_my_stat, add_proportion_my_stat };
+    gpr_timespec intervals[kNumIntervals] = {{60, 0}, {3600, 0}};
+    my_stat stat;
+    my_stat sums[kNumIntervals];
+    census_window_stats_sums result[kNumIntervals];
+    struct census_window_stats* stats
+        = census_window_stats_create(kNumIntervals, intervals, kNumBuckets,
+                                     &kMyStatInfo);
+    // Record a new event, taking 15.3ms, transferring 1784 bytes.
+    stat.latency = 0.153;
+    stat.bytes = 1784;
+    census_window_stats_add(stats, gpr_now(), &stat);
+    // Get sums and print them out
+    result[kMinInterval].statistic = &sums[kMinInterval];
+    result[kHourInterval].statistic = &sums[kHourInterval];
+    census_window_stats_get_sums(stats, gpr_now(), result);
+    printf("%d events/min, average time %gs, average bytes %g\n",
+           result[kMinInterval].count,
+           (my_stat*)result[kMinInterval].statistic->latency /
+             result[kMinInterval].count,
+           (my_stat*)result[kMinInterval].statistic->bytes /
+             result[kMinInterval].count
+          );
+    printf("%d events/hr, average time %gs, average bytes %g\n",
+           result[kHourInterval].count,
+           (my_stat*)result[kHourInterval].statistic->latency /
+             result[kHourInterval].count,
+           (my_stat*)result[kHourInterval].statistic->bytes /
+             result[kHourInterval].count
+          );
+*/
+
+/* Opaque structure for representing window_stats object */
+struct census_window_stats;
+
+/* Information provided by API user on the information they want to record */
+typedef struct census_window_stats_stat_info {
+  /* Number of bytes in user-defined object. */
+  size_t stat_size;
+  /* Function to initialize a user-defined statistics object. If this is set
+   * to NULL, then the object will be zero-initialized. */
+  void (*stat_initialize)(void* stat);
+  /* Function to add one user-defined statistics object ('addme') to 'base' */
+  void (*stat_add)(void* base, const void* addme);
+  /* As for previous function, but only add a proportion 'p'. This API will
+     currently only use 'p' values in the range [0,1], but other values are
+     possible in the future, and should be supported. */
+  void (*stat_add_proportion)(double p, void* base, const void* addme);
+} census_window_stats_stat_info;
+
+/* Create a new window_stats object. 'nintervals' is the number of
+   'intervals', and must be >=1. 'granularity' is the number of buckets, with
+   a larger number using more memory, but providing greater accuracy of
+   results. 'granularity should be > 2. We also require that each interval be
+   at least 10 * 'granularity' nanoseconds in size. 'stat_info' contains
+   information about the statistic to be gathered. Intervals greater than ~192
+   years will be treated as essentially infinite in size. This function will
+   GPR_ASSERT() if the object cannot be created or any of the parameters have
+   invalid values. This function is thread-safe. */
+struct census_window_stats* census_window_stats_create(
+    int nintervals, const gpr_timespec intervals[], int granularity,
+    const census_window_stats_stat_info* stat_info);
+
+/* Add a new measurement (in 'stat_value'), as of a given time ('when').
+   This function is thread-compatible. */
+void census_window_stats_add(struct census_window_stats* wstats,
+                             const gpr_timespec when, const void* stat_value);
+
+/* Structure used to record a single intervals sum for a given statistic */
+typedef struct census_window_stats_sum {
+  /* Total count of samples. Note that because some internal interpolation
+   is performed, the count of samples returned for each interval may not be an
+   integral value. */
+  double count;
+  /* Sum for statistic */
+  void* statistic;
+} census_window_stats_sums;
+
+/* Retrieve a set of all values stored in a window_stats object 'wstats'. The
+   number of 'sums' MUST be the same as the number 'nintervals' used in
+   census_window_stats_create(). This function is thread-compatible. */
+void census_window_stats_get_sums(const struct census_window_stats* wstats,
+                                  const gpr_timespec when,
+                                  struct census_window_stats_sum sums[]);
+
+/* Destroy a window_stats object. Once this function has been called, the
+   object will no longer be usable from any of the above functions (and
+   calling them will most likely result in a NULL-pointer dereference or
+   assertion failure). This function is thread-compatible. */
+void census_window_stats_destroy(struct census_window_stats* wstats);
+
+#endif /* __GRPC_INTERNAL_STATISTICS_WINDOW_STATS_H_ */
diff --git a/src/core/support/alloc.c b/src/core/support/alloc.c
new file mode 100644
index 0000000..658408f
--- /dev/null
+++ b/src/core/support/alloc.c
@@ -0,0 +1,67 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/alloc.h>
+
+#include <stdlib.h>
+#include <grpc/support/port_platform.h>
+
+void *gpr_malloc(size_t size) {
+  void *p = malloc(size);
+  if (!p) {
+    abort();
+  }
+  return p;
+}
+
+void gpr_free(void *p) { free(p); }
+
+void *gpr_realloc(void *p, size_t size) {
+  p = realloc(p, size);
+  if (!p) {
+    abort();
+  }
+  return p;
+}
+
+void *gpr_malloc_aligned(size_t size, size_t alignment) {
+  size_t extra = alignment - 1 + sizeof(void *);
+  void *p = gpr_malloc(size + extra);
+  void **ret = (void **)(((gpr_uintptr)p + extra) & ~(alignment - 1));
+  ret[-1] = p;
+  return (void *)ret;
+}
+
+void gpr_free_aligned(void *ptr) {
+  free(((void **)ptr)[-1]);
+}
diff --git a/src/core/support/cancellable.c b/src/core/support/cancellable.c
new file mode 100644
index 0000000..5596413
--- /dev/null
+++ b/src/core/support/cancellable.c
@@ -0,0 +1,156 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Implementation for gpr_cancellable */
+
+#include <grpc/support/atm.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+
+void gpr_cancellable_init(gpr_cancellable *c) {
+  gpr_mu_init(&c->mu);
+  c->cancelled = 0;
+  c->waiters.next = &c->waiters;
+  c->waiters.prev = &c->waiters;
+  c->waiters.mu = NULL;
+  c->waiters.cv = NULL;
+}
+
+void gpr_cancellable_destroy(gpr_cancellable *c) { gpr_mu_destroy(&c->mu); }
+
+int gpr_cancellable_is_cancelled(gpr_cancellable *c) {
+  return gpr_atm_acq_load(&c->cancelled) != 0;
+}
+
+/* Threads in gpr_cv_cancellable_wait(cv, mu, ..., c) place themselves on a
+   linked list c->waiters of gpr_cancellable_list_ before waiting on their
+   condition variables.  They check for cancellation while holding *mu.  Thus,
+   to wake a thread from gpr_cv_cancellable_wait(), it suffices to:
+      - set c->cancelled
+      - acquire and release *mu
+      - gpr_cv_broadcast(cv)
+
+   However, gpr_cancellable_cancel() may not use gpr_mu_lock(mu), since the
+   caller may already hold *mu---a possible deadlock.  (If we knew the caller
+   did not hold *mu, care would still be needed, because c->mu follows *mu in
+   the locking order, so *mu could not be acquired while holding c->mu---which
+   is needed to iterate over c->waiters.)
+
+   Therefore, gpr_cancellable_cancel() uses gpr_mu_trylock() rather than
+   gpr_mu_lock(), and retries until either gpr_mu_trylock() succeeds or the
+   thread leaves gpr_cv_cancellable_wait() for other reasons.  In the first
+   case, gpr_cancellable_cancel() removes the entry from the waiters list; in
+   the second, the waiting thread removes itself from the list.
+
+   A one-entry cache of mutexes and condition variables processed is kept to
+   avoid doing the same work again and again if many threads are blocked in the
+   same place.  However, it's important to broadcast on a condition variable if
+   the corresponding mutex has been locked successfully, even if the condition
+   variable has been signalled before.  */
+
+void gpr_cancellable_cancel(gpr_cancellable *c) {
+  if (!gpr_cancellable_is_cancelled(c)) {
+    int failures;
+    int backoff = 1;
+    do {
+      struct gpr_cancellable_list_ *l;
+      struct gpr_cancellable_list_ *nl;
+      gpr_mu *omu = 0; /* one-element cache of a processed gpr_mu */
+      gpr_cv *ocv = 0; /* one-element cache of a processd gpr_cv */
+      gpr_mu_lock(&c->mu);
+      gpr_atm_rel_store(&c->cancelled, 1);
+      failures = 0;
+      for (l = c->waiters.next; l != &c->waiters; l = nl) {
+        nl = l->next;
+        if (omu != l->mu) {
+          omu = l->mu;
+          if (gpr_mu_trylock(l->mu)) {
+            gpr_mu_unlock(l->mu);
+            l->next->prev = l->prev; /* remove *l from list */
+            l->prev->next = l->next;
+            /* allow unconditional dequeue in gpr_cv_cancellable_wait() */
+            l->next = l;
+            l->prev = l;
+            ocv = 0; /* force broadcast */
+          } else {
+            failures++;
+          }
+        }
+        if (ocv != l->cv) {
+          ocv = l->cv;
+          gpr_cv_broadcast(l->cv);
+        }
+      }
+      gpr_mu_unlock(&c->mu);
+      if (failures != 0) {
+        if (backoff < 10) {
+          volatile int i;
+          for (i = 0; i != (1 << backoff); i++) {
+          }
+          backoff++;
+        } else {
+          gpr_event ev;
+          gpr_event_init(&ev);
+          gpr_event_wait(&ev,
+                         gpr_time_add(gpr_now(), gpr_time_from_micros(1000)));
+        }
+      }
+    } while (failures != 0);
+  }
+}
+
+int gpr_cv_cancellable_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline,
+                            gpr_cancellable *c) {
+  gpr_int32 timeout;
+  gpr_mu_lock(&c->mu);
+  timeout = gpr_cancellable_is_cancelled(c);
+  if (!timeout) {
+    struct gpr_cancellable_list_ le;
+    le.mu = mu;
+    le.cv = cv;
+    le.next = c->waiters.next;
+    le.prev = &c->waiters;
+    le.next->prev = &le;
+    le.prev->next = &le;
+    gpr_mu_unlock(&c->mu);
+    timeout = gpr_cv_wait(cv, mu, abs_deadline);
+    gpr_mu_lock(&c->mu);
+    le.next->prev = le.prev;
+    le.prev->next = le.next;
+    if (!timeout) {
+      timeout = gpr_cancellable_is_cancelled(c);
+    }
+  }
+  gpr_mu_unlock(&c->mu);
+  return timeout;
+}
diff --git a/src/core/support/cmdline.c b/src/core/support/cmdline.c
new file mode 100644
index 0000000..ff163a1
--- /dev/null
+++ b/src/core/support/cmdline.c
@@ -0,0 +1,292 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/cmdline.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+
+typedef enum { ARGTYPE_INT, ARGTYPE_BOOL, ARGTYPE_STRING } argtype;
+
+typedef struct arg {
+  const char *name;
+  const char *help;
+  argtype type;
+  void *value;
+  struct arg *next;
+} arg;
+
+struct gpr_cmdline {
+  const char *description;
+  arg *args;
+  const char *argv0;
+
+  const char *extra_arg_name;
+  const char *extra_arg_help;
+  void (*extra_arg)(void *user_data, const char *arg);
+  void *extra_arg_user_data;
+
+  void (*state)(gpr_cmdline *cl, char *arg);
+  arg *cur_arg;
+};
+
+static void normal_state(gpr_cmdline *cl, char *arg);
+
+gpr_cmdline *gpr_cmdline_create(const char *description) {
+  gpr_cmdline *cl = gpr_malloc(sizeof(gpr_cmdline));
+  memset(cl, 0, sizeof(gpr_cmdline));
+
+  cl->description = description;
+  cl->state = normal_state;
+
+  return cl;
+}
+
+void gpr_cmdline_destroy(gpr_cmdline *cl) {
+  while (cl->args) {
+    arg *a = cl->args;
+    cl->args = a->next;
+    gpr_free(a);
+  }
+  gpr_free(cl);
+}
+
+static void add_arg(gpr_cmdline *cl, const char *name, const char *help,
+                    argtype type, void *value) {
+  arg *a;
+
+  for (a = cl->args; a; a = a->next) {
+    GPR_ASSERT(0 != strcmp(a->name, name));
+  }
+
+  a = gpr_malloc(sizeof(arg));
+  memset(a, 0, sizeof(arg));
+  a->name = name;
+  a->help = help;
+  a->type = type;
+  a->value = value;
+  a->next = cl->args;
+  cl->args = a;
+}
+
+void gpr_cmdline_add_int(gpr_cmdline *cl, const char *name, const char *help,
+                         int *value) {
+  add_arg(cl, name, help, ARGTYPE_INT, value);
+}
+
+void gpr_cmdline_add_flag(gpr_cmdline *cl, const char *name, const char *help,
+                          int *value) {
+  add_arg(cl, name, help, ARGTYPE_BOOL, value);
+}
+
+void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name, const char *help,
+                            char **value) {
+  add_arg(cl, name, help, ARGTYPE_STRING, value);
+}
+
+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) {
+  GPR_ASSERT(!cl->extra_arg);
+  GPR_ASSERT(on_extra_arg);
+
+  cl->extra_arg = on_extra_arg;
+  cl->extra_arg_user_data = user_data;
+  cl->extra_arg_name = name;
+  cl->extra_arg_help = help;
+}
+
+static void print_usage_and_die(gpr_cmdline *cl) {
+  /* TODO(ctiller): make this prettier */
+  arg *a;
+  const char *name = strrchr(cl->argv0, '/');
+  if (name) {
+    name++;
+  } else {
+    name = cl->argv0;
+  }
+  fprintf(stderr, "Usage: %s", name);
+  for (a = cl->args; a; a = a->next) {
+    switch (a->type) {
+      case ARGTYPE_BOOL:
+        fprintf(stderr, " [--%s|--no-%s]", a->name, a->name);
+        break;
+      case ARGTYPE_STRING:
+        fprintf(stderr, " [--%s=string]", a->name);
+        break;
+      case ARGTYPE_INT:
+        fprintf(stderr, " [--%s=int]", a->name);
+        break;
+    }
+  }
+  if (cl->extra_arg) {
+    fprintf(stderr, " [%s...]", cl->extra_arg_name);
+  }
+  fprintf(stderr, "\n");
+  exit(1);
+}
+
+static void extra_state(gpr_cmdline *cl, char *arg) {
+  if (!cl->extra_arg) print_usage_and_die(cl);
+  cl->extra_arg(cl->extra_arg_user_data, arg);
+}
+
+static arg *find_arg(gpr_cmdline *cl, char *name) {
+  arg *a;
+
+  for (a = cl->args; a; a = a->next) {
+    if (0 == strcmp(a->name, name)) {
+      break;
+    }
+  }
+
+  if (!a) {
+    fprintf(stderr, "Unknown argument: %s\n", name);
+    print_usage_and_die(cl);
+  }
+
+  return a;
+}
+
+static void value_state(gpr_cmdline *cl, char *arg) {
+  long intval;
+  char *end;
+
+  GPR_ASSERT(cl->cur_arg);
+
+  switch (cl->cur_arg->type) {
+    case ARGTYPE_INT:
+      intval = strtol(arg, &end, 0);
+      if (*end || intval < INT_MIN || intval > INT_MAX) {
+        fprintf(stderr, "expected integer, got '%s' for %s\n", arg,
+                cl->cur_arg->name);
+        print_usage_and_die(cl);
+      }
+      *(int *)cl->cur_arg->value = intval;
+      break;
+    case ARGTYPE_BOOL:
+      if (0 == strcmp(arg, "1") || 0 == strcmp(arg, "true")) {
+        *(int *)cl->cur_arg->value = 1;
+      } else if (0 == strcmp(arg, "0") || 0 == strcmp(arg, "false")) {
+        *(int *)cl->cur_arg->value = 0;
+      } else {
+        fprintf(stderr, "expected boolean, got '%s' for %s\n", arg,
+                cl->cur_arg->name);
+        print_usage_and_die(cl);
+      }
+      break;
+    case ARGTYPE_STRING:
+      *(char **)cl->cur_arg->value = arg;
+      break;
+  }
+
+  cl->state = normal_state;
+}
+
+static void normal_state(gpr_cmdline *cl, char *arg) {
+  char *eq = NULL;
+  char *tmp = NULL;
+  char *arg_name = NULL;
+
+  if (0 == strcmp(arg, "-help") || 0 == strcmp(arg, "--help") ||
+      0 == strcmp(arg, "-h")) {
+    print_usage_and_die(cl);
+  }
+
+  cl->cur_arg = NULL;
+
+  if (arg[0] == '-') {
+    if (arg[1] == '-') {
+      if (arg[2] == 0) {
+        /* handle '--' to move to just extra args */
+        cl->state = extra_state;
+        return;
+      }
+      arg += 2;
+    } else {
+      arg += 1;
+    }
+    /* first byte of arg is now past the leading '-' or '--' */
+    if (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-') {
+      /* arg is of the form '--no-foo' - it's a flag disable */
+      arg += 3;
+      cl->cur_arg = find_arg(cl, arg);
+      if (cl->cur_arg->type != ARGTYPE_BOOL) {
+        fprintf(stderr, "%s is not a flag argument\n", arg);
+        print_usage_and_die(cl);
+      }
+      *(int *)cl->cur_arg->value = 0;
+      return; /* early out */
+    }
+    eq = strchr(arg, '=');
+    if (eq != NULL) {
+      /* copy the string into a temp buffer and extract the name */
+      tmp = arg_name = gpr_malloc(eq - arg + 1);
+      memcpy(arg_name, arg, eq - arg);
+      arg_name[eq - arg] = 0;
+    } else {
+      arg_name = arg;
+    }
+    cl->cur_arg = find_arg(cl, arg_name);
+    if (eq != NULL) {
+      /* arg was of the type --foo=value, parse the value */
+      value_state(cl, eq + 1);
+    } else if (cl->cur_arg->type != ARGTYPE_BOOL) {
+      /* flag types don't have a '--foo value' variant, other types do */
+      cl->state = value_state;
+    } else {
+      /* flag parameter: just set the value */
+      *(int *)cl->cur_arg->value = 1;
+    }
+  } else {
+    extra_state(cl, arg);
+  }
+
+  gpr_free(tmp);
+}
+
+void gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv) {
+  int i;
+
+  GPR_ASSERT(argc >= 1);
+  cl->argv0 = argv[0];
+
+  for (i = 1; i < argc; i++) {
+    cl->state(cl, argv[i]);
+  }
+}
diff --git a/src/core/support/cpu.h b/src/core/support/cpu.h
new file mode 100644
index 0000000..6ac0db3
--- /dev/null
+++ b/src/core/support/cpu.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SUPPORT_CPU_H__
+#define __GRPC_INTERNAL_SUPPORT_CPU_H__
+
+/* Interface providing CPU information for currently running system */
+
+/* Return the number of CPU cores on the current system. Will return 0 if
+   if information is not available. */
+int gpr_cpu_num_cores();
+
+/* Return the CPU on which the current thread is executing; N.B. This should
+   be considered advisory only - it is possible that the thread is switched
+   to a different CPU at any time. Returns a value in range
+   [0, gpr_cpu_num_cores() - 1] */
+int gpr_cpu_current_cpu();
+
+#endif  /* __GRPC_INTERNAL_SUPPORT_CPU_H__ */
diff --git a/src/core/support/cpu_posix.c b/src/core/support/cpu_posix.c
new file mode 100644
index 0000000..82d58de
--- /dev/null
+++ b/src/core/support/cpu_posix.c
@@ -0,0 +1,71 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/support/cpu.h"
+
+#ifdef __linux__
+#include <errno.h>
+#include <unistd.h>
+#define _GNU_SOURCE
+#define __USE_GNU
+#define __USE_MISC
+#include <sched.h>
+#undef _GNU_SOURCE
+#undef __USE_GNU
+#undef __USE_MISC
+#include <string.h>
+
+#include <grpc/support/log.h>
+
+int gpr_cpu_num_cores() {
+  static int ncpus = 0;
+  if (ncpus == 0) {
+    ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+    if (ncpus < 1) {
+      gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1");
+      ncpus = 1;
+    }
+  }
+  return ncpus;
+}
+
+int gpr_cpu_current_cpu() {
+  int cpu = sched_getcpu();
+  if (cpu < 0) {
+    gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno));
+    return 0;
+  }
+  return cpu;
+}
+
+#endif /* __linux__ */
diff --git a/src/core/support/histogram.c b/src/core/support/histogram.c
new file mode 100644
index 0000000..a3ecd3e
--- /dev/null
+++ b/src/core/support/histogram.c
@@ -0,0 +1,226 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/histogram.h>
+
+#include <math.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+/* Histograms are stored with exponentially increasing bucket sizes.
+   The first bucket is [0, m) where m = 1 + resolution
+   Bucket n (n>=1) contains [m**n, m**(n+1))
+   There are sufficient buckets to reach max_bucket_start */
+
+struct gpr_histogram {
+  /* Sum of all values seen so far */
+  double sum;
+  /* Sum of squares of all values seen so far */
+  double sum_of_squares;
+  /* number of values seen so far */
+  double count;
+  /* m in the description */
+  double multiplier;
+  double one_on_log_multiplier;
+  /* minimum value seen */
+  double min_seen;
+  /* maximum value seen */
+  double max_seen;
+  /* maximum representable value */
+  double max_possible;
+  /* number of buckets */
+  size_t num_buckets;
+  /* the buckets themselves */
+  gpr_uint32 *buckets;
+};
+
+/* determine a bucket index given a value - does no bounds checking */
+static size_t bucket_for_unchecked(gpr_histogram *h, double x) {
+  return (size_t)(log(x) * h->one_on_log_multiplier);
+}
+
+/* bounds checked version of the above */
+static size_t bucket_for(gpr_histogram *h, double x) {
+  size_t bucket = bucket_for_unchecked(h, GPR_CLAMP(x, 0, h->max_possible));
+  GPR_ASSERT(bucket >= 0);
+  GPR_ASSERT(bucket < h->num_buckets);
+  return bucket;
+}
+
+/* at what value does a bucket start? */
+static double bucket_start(gpr_histogram *h, double x) {
+  return pow(h->multiplier, x);
+}
+
+gpr_histogram *gpr_histogram_create(double resolution,
+                                    double max_bucket_start) {
+  gpr_histogram *h = gpr_malloc(sizeof(gpr_histogram));
+  GPR_ASSERT(resolution > 0.0);
+  GPR_ASSERT(max_bucket_start > resolution);
+  h->sum = 0.0;
+  h->sum_of_squares = 0.0;
+  h->multiplier = 1.0 + resolution;
+  h->one_on_log_multiplier = 1.0 / log(1.0 + resolution);
+  h->max_possible = max_bucket_start;
+  h->count = 0.0;
+  h->min_seen = max_bucket_start;
+  h->max_seen = 0.0;
+  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 = gpr_malloc(sizeof(gpr_uint32) * h->num_buckets);
+  memset(h->buckets, 0, sizeof(gpr_uint32) * h->num_buckets);
+  return h;
+}
+
+void gpr_histogram_destroy(gpr_histogram *h) {
+  gpr_free(h->buckets);
+  gpr_free(h);
+}
+
+void gpr_histogram_add(gpr_histogram *h, double x) {
+  h->sum += x;
+  h->sum_of_squares += x * x;
+  h->count++;
+  if (x < h->min_seen) {
+    h->min_seen = x;
+  }
+  if (x > h->max_seen) {
+    h->max_seen = x;
+  }
+  h->buckets[bucket_for(h, x)]++;
+}
+
+int gpr_histogram_merge(gpr_histogram *dst, gpr_histogram *src) {
+  int i;
+  if ((dst->num_buckets != src->num_buckets) ||
+      (dst->multiplier != src->multiplier)) {
+    /* Fail because these histograms don't match */
+    return 0;
+  }
+  dst->sum += src->sum;
+  dst->sum_of_squares += src->sum_of_squares;
+  dst->count += src->count;
+  if (src->min_seen < dst->min_seen) {
+    dst->min_seen = src->min_seen;
+  }
+  if (src->max_seen > dst->max_seen) {
+    dst->max_seen = src->max_seen;
+  }
+  for (i = 0; i < dst->num_buckets; i++) {
+    dst->buckets[i] += src->buckets[i];
+  }
+  return 1;
+}
+
+static double threshold_for_count_below(gpr_histogram *h, double count_below) {
+  double count_so_far;
+  double lower_bound;
+  double upper_bound;
+  int lower_idx;
+  int upper_idx;
+
+  GPR_ASSERT(h->count >= 1);
+
+  if (count_below <= 0) {
+    return h->min_seen;
+  }
+  if (count_below >= h->count) {
+    return h->max_seen;
+  }
+
+  /* find the lowest bucket that gets us above count_below */
+  count_so_far = 0.0;
+  for (lower_idx = 0; lower_idx < h->num_buckets; lower_idx++) {
+    count_so_far += h->buckets[lower_idx];
+    if (count_so_far >= count_below) {
+      break;
+    }
+  }
+  if (count_so_far == count_below) {
+    /* this bucket hits the threshold exactly... we should be midway through
+       any run of zero values following the bucket */
+    for (upper_idx = lower_idx + 1; upper_idx < h->num_buckets; upper_idx++) {
+      if (h->buckets[upper_idx]) {
+        break;
+      }
+    }
+    return (bucket_start(h, lower_idx) + bucket_start(h, upper_idx)) / 2.0;
+  } else {
+    /* treat values as uniform throughout the bucket, and find where this value
+       should lie */
+    lower_bound = bucket_start(h, lower_idx);
+    upper_bound = bucket_start(h, lower_idx + 1);
+    return GPR_CLAMP(upper_bound -
+                         (upper_bound - lower_bound) *
+                             (count_so_far - count_below) /
+                             h->buckets[lower_idx],
+                     h->min_seen, h->max_seen);
+  }
+}
+
+double gpr_histogram_percentile(gpr_histogram *h, double percentile) {
+  return threshold_for_count_below(h, h->count * percentile / 100.0);
+}
+
+double gpr_histogram_mean(gpr_histogram *h) {
+  GPR_ASSERT(h->count);
+  return h->sum / h->count;
+}
+
+double gpr_histogram_stddev(gpr_histogram *h) {
+  return sqrt(gpr_histogram_variance(h));
+}
+
+double gpr_histogram_variance(gpr_histogram *h) {
+  if (h->count == 0) return 0.0;
+  return (h->sum_of_squares * h->count - h->sum * h->sum) /
+         (h->count * h->count);
+}
+
+double gpr_histogram_maximum(gpr_histogram *h) { return h->max_seen; }
+
+double gpr_histogram_minimum(gpr_histogram *h) { return h->min_seen; }
+
+double gpr_histogram_count(gpr_histogram *h) { return h->count; }
+
+double gpr_histogram_sum(gpr_histogram *h) { return h->sum; }
+
+double gpr_histogram_sum_of_squares(gpr_histogram *h) {
+  return h->sum_of_squares;
+}
diff --git a/src/core/support/host_port.c b/src/core/support/host_port.c
new file mode 100644
index 0000000..0250055
--- /dev/null
+++ b/src/core/support/host_port.c
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/host_port.h>
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+
+int gpr_join_host_port(char **out, const char *host, int port) {
+  if (host[0] != '[' && strchr(host, ':') != NULL) {
+    /* IPv6 literals must be enclosed in brackets. */
+    return gpr_asprintf(out, "[%s]:%d", host, port);
+  } else {
+    /* Ordinary non-bracketed host:port. */
+    return gpr_asprintf(out, "%s:%d", host, port);
+  }
+}
diff --git a/src/core/support/log.c b/src/core/support/log.c
new file mode 100644
index 0000000..79321f7
--- /dev/null
+++ b/src/core/support/log.c
@@ -0,0 +1,48 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/log.h>
+
+#include <stdio.h>
+
+const char *gpr_log_severity_string(gpr_log_severity severity) {
+  switch (severity) {
+    case GPR_LOG_SEVERITY_DEBUG:
+      return "D";
+    case GPR_LOG_SEVERITY_INFO:
+      return "I";
+    case GPR_LOG_SEVERITY_ERROR:
+      return "E";
+  }
+  return "UNKNOWN";
+}
diff --git a/src/core/support/log_android.c b/src/core/support/log_android.c
new file mode 100644
index 0000000..9e2b034
--- /dev/null
+++ b/src/core/support/log_android.c
@@ -0,0 +1,86 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_ANDROID
+
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <android/log.h>
+
+static android_LogPriority severity_to_log_priority(gpr_log_severity severity) {
+  switch (severity) {
+    case GPR_LOG_SEVERITY_DEBUG:
+      return ANDROID_LOG_DEBUG;
+    case GPR_LOG_SEVERITY_INFO:
+      return ANDROID_LOG_INFO;
+    case GPR_LOG_SEVERITY_ERROR:
+      return ANDROID_LOG_ERROR;
+  }
+  return ANDROID_LOG_DEFAULT;
+}
+
+void gpr_log(const char *file, int line, gpr_log_severity severity,
+             const char *format, ...) {
+  char *final_slash;
+  const char *display_file;
+  char *prefix = NULL;
+  char *suffix = NULL;
+  char *output = NULL;
+  va_list args;
+  va_start(args, format);
+
+  final_slash = strrchr(file, '/');
+  if (final_slash == NULL)
+    display_file = file;
+  else
+    display_file = final_slash + 1;
+
+  asprintf(&prefix, "%s:%d] ", display_file, line);
+  vasprintf(&suffix, format, args);
+  asprintf(&output, "%s%s", prefix, suffix);
+  va_end(args);
+
+  __android_log_write(severity_to_log_priority(severity), "GRPC", output);
+
+  /* allocated by asprintf => use free, not gpr_free */
+  free(prefix);
+  free(suffix);
+  free(output);
+}
+
+#endif /* GPR_ANDROID */
diff --git a/src/core/support/log_linux.c b/src/core/support/log_linux.c
new file mode 100644
index 0000000..e39e2cc
--- /dev/null
+++ b/src/core/support/log_linux.c
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+#define _POSIX_SOURCE
+#define _GNU_SOURCE
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_LINUX
+
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <linux/unistd.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+static long gettid() { return syscall(__NR_gettid); }
+
+void gpr_log(const char *file, int line, gpr_log_severity severity,
+             const char *format, ...) {
+  char *final_slash;
+  const char *display_file;
+  char time_buffer[64];
+  gpr_timespec now = gpr_now();
+  struct tm tm;
+  va_list args;
+  va_start(args, format);
+
+  final_slash = strrchr(file, '/');
+  if (final_slash == NULL)
+    display_file = file;
+  else
+    display_file = final_slash + 1;
+
+  if (!localtime_r(&now.tv_sec, &tm)) {
+    strcpy(time_buffer, "error:localtime");
+  } else if (0 ==
+             strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) {
+    strcpy(time_buffer, "error:strftime");
+  }
+
+  flockfile(stderr);
+  fprintf(stderr, "%s%s.%09d %7ld %s:%d] ", gpr_log_severity_string(severity),
+          time_buffer, (int)(now.tv_nsec), gettid(), display_file, line);
+  vfprintf(stderr, format, args);
+  fputc('\n', stderr);
+  funlockfile(stderr);
+
+  va_end(args);
+}
+
+#endif
diff --git a/src/core/support/log_posix.c b/src/core/support/log_posix.c
new file mode 100644
index 0000000..68882f7
--- /dev/null
+++ b/src/core/support/log_posix.c
@@ -0,0 +1,83 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+#define _POSIX_SOURCE
+#define _GNU_SOURCE
+#include <grpc/support/port_platform.h>
+
+#if defined(GPR_POSIX_LOG)
+
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+
+static long gettid() { return pthread_self(); }
+
+void gpr_log(const char *file, int line, gpr_log_severity severity,
+             const char *format, ...) {
+  char *final_slash;
+  const char *display_file;
+  char time_buffer[64];
+  gpr_timespec now = gpr_now();
+  struct tm tm;
+  va_list args;
+  va_start(args, format);
+
+  final_slash = strrchr(file, '/');
+  if (final_slash == NULL)
+    display_file = file;
+  else
+    display_file = final_slash + 1;
+
+  if (!localtime_r(&now.tv_sec, &tm)) {
+    strcpy(time_buffer, "error:localtime");
+  } else if (0 ==
+             strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) {
+    strcpy(time_buffer, "error:strftime");
+  }
+
+  flockfile(stderr);
+  fprintf(stderr, "%s%s.%09d %7ld %s:%d] ", gpr_log_severity_string(severity),
+          time_buffer, (int)(now.tv_nsec), gettid(), display_file, line);
+  vfprintf(stderr, format, args);
+  fputc('\n', stderr);
+  funlockfile(stderr);
+
+  va_end(args);
+}
+
+#endif /* defined(GPR_POSIX_LOG) */
diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c
new file mode 100644
index 0000000..f5710fa
--- /dev/null
+++ b/src/core/support/log_win32.c
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include <grpc/support/log.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+/* Simple starter implementation */
+void gpr_log(char *file, int line, gpr_log_severity severity, char *format,
+             ...) {
+  va_list args;
+  va_start(args, format);
+
+  fprintf(stderr, "%s %s:%d: ", gpr_log_severity_string(severity), file, line);
+  vfprintf(stderr, format, args);
+  fputc('\n', stderr);
+
+  va_end(args);
+}
+
+#endif
diff --git a/src/core/support/murmur_hash.c b/src/core/support/murmur_hash.c
new file mode 100644
index 0000000..5d30263
--- /dev/null
+++ b/src/core/support/murmur_hash.c
@@ -0,0 +1,94 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/support/murmur_hash.h"
+
+#define ROTL32(x, r) ((x) << (r)) | ((x) >> (32 - (r)))
+
+#define FMIX32(h)    \
+  (h) ^= (h) >> 16;  \
+  (h) *= 0x85ebca6b; \
+  (h) ^= (h) >> 13;  \
+  (h) *= 0xc2b2ae35; \
+  (h) ^= (h) >> 16;
+
+/* Block read - if your platform needs to do endian-swapping or can only
+   handle aligned reads, do the conversion here */
+#define GETBLOCK32(p, i) (p)[(i)]
+
+gpr_uint32 gpr_murmur_hash3(const void* key, size_t len, gpr_uint32 seed) {
+  const gpr_uint8* data = (const gpr_uint8*)key;
+  const int nblocks = len / 4;
+  int i;
+
+  gpr_uint32 h1 = seed;
+  gpr_uint32 k1 = 0;
+
+  const gpr_uint32 c1 = 0xcc9e2d51;
+  const gpr_uint32 c2 = 0x1b873593;
+
+  const gpr_uint32* blocks = (const uint32_t*)(data + nblocks * 4);
+  const uint8_t* tail = (const uint8_t*)(data + nblocks * 4);
+
+  /* body */
+  for (i = -nblocks; i; i++) {
+    gpr_uint32 k1 = GETBLOCK32(blocks, i);
+
+    k1 *= c1;
+    k1 = ROTL32(k1, 15);
+    k1 *= c2;
+
+    h1 ^= k1;
+    h1 = ROTL32(h1, 13);
+    h1 = h1 * 5 + 0xe6546b64;
+  }
+
+  /* tail */
+  switch (len & 3) {
+    case 3:
+      k1 ^= tail[2] << 16;
+    case 2:
+      k1 ^= tail[1] << 8;
+    case 1:
+      k1 ^= tail[0];
+      k1 *= c1;
+      k1 = ROTL32(k1, 15);
+      k1 *= c2;
+      h1 ^= k1;
+  };
+
+  /* finalization */
+  h1 ^= len;
+  FMIX32(h1);
+  return h1;
+}
diff --git a/src/core/support/murmur_hash.h b/src/core/support/murmur_hash.h
new file mode 100644
index 0000000..5643717
--- /dev/null
+++ b/src/core/support/murmur_hash.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SUPPORT_MURMUR_HASH_H__
+#define __GRPC_INTERNAL_SUPPORT_MURMUR_HASH_H__
+
+#include <grpc/support/port_platform.h>
+
+#include <stddef.h>
+
+/* compute the hash of key (length len) */
+gpr_uint32 gpr_murmur_hash3(const void *key, size_t len, gpr_uint32 seed);
+
+#endif  /* __GRPC_INTERNAL_SUPPORT_MURMUR_HASH_H__ */
diff --git a/src/core/support/slice.c b/src/core/support/slice.c
new file mode 100644
index 0000000..fcdeb47
--- /dev/null
+++ b/src/core/support/slice.c
@@ -0,0 +1,325 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+
+#include <string.h>
+
+gpr_slice gpr_empty_slice() {
+  gpr_slice out;
+  out.refcount = 0;
+  out.data.inlined.length = 0;
+  return out;
+}
+
+gpr_slice gpr_slice_ref(gpr_slice slice) {
+  if (slice.refcount) {
+    slice.refcount->ref(slice.refcount);
+  }
+  return slice;
+}
+
+void gpr_slice_unref(gpr_slice slice) {
+  if (slice.refcount) {
+    slice.refcount->unref(slice.refcount);
+  }
+}
+
+/* gpr_slice_new support structures - we create a refcount object extended
+   with the user provided data pointer & destroy function */
+typedef struct new_slice_refcount {
+  gpr_slice_refcount rc;
+  gpr_refcount refs;
+  void (*user_destroy)(void *);
+  void *user_data;
+} new_slice_refcount;
+
+static void new_slice_ref(void *p) {
+  new_slice_refcount *r = p;
+  gpr_ref(&r->refs);
+}
+
+static void new_slice_unref(void *p) {
+  new_slice_refcount *r = p;
+  if (gpr_unref(&r->refs)) {
+    r->user_destroy(r->user_data);
+    gpr_free(r);
+  }
+}
+
+gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) {
+  gpr_slice slice;
+  new_slice_refcount *rc = gpr_malloc(sizeof(new_slice_refcount));
+  gpr_ref_init(&rc->refs, 1);
+  rc->rc.ref = new_slice_ref;
+  rc->rc.unref = new_slice_unref;
+  rc->user_destroy = destroy;
+  rc->user_data = p;
+
+  slice.refcount = &rc->rc;
+  slice.data.refcounted.bytes = p;
+  slice.data.refcounted.length = len;
+  return slice;
+}
+
+/* gpr_slice_new_with_len support structures - we create a refcount object
+   extended with the user provided data pointer & destroy function */
+typedef struct new_with_len_slice_refcount {
+  gpr_slice_refcount rc;
+  gpr_refcount refs;
+  void *user_data;
+  size_t user_length;
+  void (*user_destroy)(void *, size_t);
+} new_with_len_slice_refcount;
+
+static void new_with_len_ref(void *p) {
+  new_with_len_slice_refcount *r = p;
+  gpr_ref(&r->refs);
+}
+
+static void new_with_len_unref(void *p) {
+  new_with_len_slice_refcount *r = p;
+  if (gpr_unref(&r->refs)) {
+    r->user_destroy(r->user_data, r->user_length);
+    gpr_free(r);
+  }
+}
+
+gpr_slice gpr_slice_new_with_len(void *p, size_t len,
+                                 void (*destroy)(void *, size_t)) {
+  gpr_slice slice;
+  new_with_len_slice_refcount *rc =
+      gpr_malloc(sizeof(new_with_len_slice_refcount));
+  gpr_ref_init(&rc->refs, 1);
+  rc->rc.ref = new_with_len_ref;
+  rc->rc.unref = new_with_len_unref;
+  rc->user_destroy = destroy;
+  rc->user_data = p;
+  rc->user_length = len;
+
+  slice.refcount = &rc->rc;
+  slice.data.refcounted.bytes = p;
+  slice.data.refcounted.length = len;
+  return slice;
+}
+
+gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t length) {
+  gpr_slice slice = gpr_slice_malloc(length);
+  memcpy(GPR_SLICE_START_PTR(slice), source, length);
+  return slice;
+}
+
+gpr_slice gpr_slice_from_copied_string(const char *source) {
+  return gpr_slice_from_copied_buffer(source, strlen(source));
+}
+
+typedef struct {
+  gpr_slice_refcount base;
+  gpr_refcount refs;
+} malloc_refcount;
+
+static void malloc_ref(void *p) {
+  malloc_refcount *r = p;
+  gpr_ref(&r->refs);
+}
+
+static void malloc_unref(void *p) {
+  malloc_refcount *r = p;
+  if (gpr_unref(&r->refs)) {
+    gpr_free(r);
+  }
+}
+
+gpr_slice gpr_slice_malloc(size_t length) {
+  gpr_slice slice;
+
+  if (length > sizeof(slice.data.inlined.bytes)) {
+    /* Memory layout used by the slice created here:
+
+       +-----------+----------------------------------------------------------+
+       | refcount  | bytes                                                    |
+       +-----------+----------------------------------------------------------+
+
+       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 = gpr_malloc(sizeof(malloc_refcount) + length);
+
+    /* Initial refcount on rc is 1 - and it's up to the caller to release
+       this reference. */
+    gpr_ref_init(&rc->refs, 1);
+
+    rc->base.ref = malloc_ref;
+    rc->base.unref = malloc_unref;
+
+    /* Build up the slice to be returned. */
+    /* 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 = (gpr_uint8 *)(rc + 1);
+    /* And the length of the block is set to the requested length */
+    slice.data.refcounted.length = length;
+  } else {
+    /* small slice: just inline the data */
+    slice.refcount = NULL;
+    slice.data.inlined.length = length;
+  }
+  return slice;
+}
+
+gpr_slice gpr_slice_sub_no_ref(gpr_slice source, size_t begin, size_t end) {
+  gpr_slice subset;
+
+  if (source.refcount) {
+    /* Enforce preconditions */
+    GPR_ASSERT(source.data.refcounted.length >= begin);
+    GPR_ASSERT(source.data.refcounted.length >= end);
+    GPR_ASSERT(end >= begin);
+
+    /* Build the result */
+    subset.refcount = source.refcount;
+    /* Point into the source array */
+    subset.data.refcounted.bytes = source.data.refcounted.bytes + begin;
+    subset.data.refcounted.length = end - begin;
+  } else {
+    subset.refcount = NULL;
+    subset.data.inlined.length = end - begin;
+    memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin,
+           end - begin);
+  }
+  return subset;
+}
+
+gpr_slice gpr_slice_sub(gpr_slice source, size_t begin, size_t end) {
+  gpr_slice subset;
+
+  if (end - begin <= sizeof(subset.data.inlined.bytes)) {
+    subset.refcount = NULL;
+    subset.data.inlined.length = end - begin;
+    memcpy(subset.data.inlined.bytes, GPR_SLICE_START_PTR(source) + begin,
+           end - begin);
+  } else {
+    subset = gpr_slice_sub_no_ref(source, begin, end);
+    /* Bump the refcount */
+    subset.refcount->ref(subset.refcount);
+  }
+  return subset;
+}
+
+gpr_slice gpr_slice_split_tail(gpr_slice *source, size_t split) {
+  gpr_slice tail;
+
+  if (source->refcount == NULL) {
+    /* inlined data, copy it out */
+    GPR_ASSERT(source->data.inlined.length >= split);
+    tail.refcount = NULL;
+    tail.data.inlined.length = source->data.inlined.length - split;
+    memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split,
+           tail.data.inlined.length);
+    source->data.inlined.length = split;
+  } else {
+    size_t tail_length = source->data.refcounted.length - split;
+    GPR_ASSERT(source->data.refcounted.length >= split);
+    if (tail_length < sizeof(tail.data.inlined.bytes)) {
+      /* Copy out the bytes - it'll be cheaper than refcounting */
+      tail.refcount = NULL;
+      tail.data.inlined.length = tail_length;
+      memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split,
+             tail_length);
+    } else {
+      /* Build the result */
+      tail.refcount = source->refcount;
+      /* Bump the refcount */
+      tail.refcount->ref(tail.refcount);
+      /* Point into the source array */
+      tail.data.refcounted.bytes = source->data.refcounted.bytes + split;
+      tail.data.refcounted.length = tail_length;
+    }
+    source->data.refcounted.length = split;
+  }
+
+  return tail;
+}
+
+gpr_slice gpr_slice_split_head(gpr_slice *source, size_t split) {
+  gpr_slice head;
+
+  if (source->refcount == NULL) {
+    GPR_ASSERT(source->data.inlined.length >= split);
+
+    head.refcount = NULL;
+    head.data.inlined.length = split;
+    memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split);
+    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 = NULL;
+    head.data.inlined.length = split;
+    memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split);
+    source->data.refcounted.bytes += split;
+    source->data.refcounted.length -= split;
+  } else {
+    GPR_ASSERT(source->data.refcounted.length >= split);
+
+    /* Build the result */
+    head.refcount = source->refcount;
+    /* Bump the refcount */
+    head.refcount->ref(head.refcount);
+    /* Point into the source array */
+    head.data.refcounted.bytes = source->data.refcounted.bytes;
+    head.data.refcounted.length = split;
+    source->data.refcounted.bytes += split;
+    source->data.refcounted.length -= split;
+  }
+
+  return head;
+}
+
+int gpr_slice_cmp(gpr_slice a, gpr_slice b) {
+  int d = GPR_SLICE_LENGTH(a) - GPR_SLICE_LENGTH(b);
+  if (d != 0) return d;
+  return memcmp(GPR_SLICE_START_PTR(a), GPR_SLICE_START_PTR(b),
+                GPR_SLICE_LENGTH(a));
+}
+
+int gpr_slice_str_cmp(gpr_slice a, const char *b) {
+  size_t b_length = strlen(b);
+  int d = GPR_SLICE_LENGTH(a) - b_length;
+  if (d != 0) return d;
+  return memcmp(GPR_SLICE_START_PTR(a), b, b_length);
+}
diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c
new file mode 100644
index 0000000..2ade049
--- /dev/null
+++ b/src/core/support/slice_buffer.c
@@ -0,0 +1,155 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/slice_buffer.h>
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+/* initial allocation size (# of slices) */
+#define INITIAL_CAPACITY 4
+/* grow a buffer; requires INITIAL_CAPACITY > 1 */
+#define GROW(x) (3 * (x) / 2)
+
+void gpr_slice_buffer_init(gpr_slice_buffer *sb) {
+  sb->count = 0;
+  sb->length = 0;
+  sb->capacity = INITIAL_CAPACITY;
+  sb->slices = gpr_malloc(sizeof(gpr_slice) * INITIAL_CAPACITY);
+}
+
+void gpr_slice_buffer_destroy(gpr_slice_buffer *sb) {
+  gpr_slice_buffer_reset_and_unref(sb);
+  gpr_free(sb->slices);
+}
+
+gpr_uint8 *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, int n) {
+  gpr_slice *back;
+  gpr_uint8 *out;
+
+  sb->length += n;
+
+  if (sb->count == 0) goto add_new;
+  back = &sb->slices[sb->count - 1];
+  if (back->refcount) goto add_new;
+  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 += n;
+  return out;
+
+add_new:
+  if (sb->count == sb->capacity) {
+    sb->capacity = GROW(sb->capacity);
+    GPR_ASSERT(sb->capacity > sb->count);
+    sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
+  }
+  back = &sb->slices[sb->count];
+  sb->count++;
+  back->refcount = NULL;
+  back->data.inlined.length = n;
+  return back->data.inlined.bytes;
+}
+
+size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice s) {
+  size_t out = sb->count;
+  if (out == sb->capacity) {
+    sb->capacity = GROW(sb->capacity);
+    GPR_ASSERT(sb->capacity > sb->count);
+    sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
+  }
+  sb->slices[out] = s;
+  sb->length += GPR_SLICE_LENGTH(s);
+  sb->count = out + 1;
+  return out;
+}
+
+void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) {
+  size_t n = sb->count;
+  /* if both the last slice in the slice buffer and the slice being added
+     are inlined (that is, that they carry their data inside the slice data
+     structure), and the back slice is not full, then concatenate directly
+     into the back slice, preventing many small slices being passed into
+     writes */
+  if (!s.refcount && n) {
+    gpr_slice *back = &sb->slices[n - 1];
+    if (!back->refcount && back->data.inlined.length < GPR_SLICE_INLINED_SIZE) {
+      if (s.data.inlined.length + back->data.inlined.length <=
+          GPR_SLICE_INLINED_SIZE) {
+        memcpy(back->data.inlined.bytes + back->data.inlined.length,
+               s.data.inlined.bytes, s.data.inlined.length);
+        back->data.inlined.length += s.data.inlined.length;
+      } else {
+        size_t cp1 = GPR_SLICE_INLINED_SIZE - back->data.inlined.length;
+        memcpy(back->data.inlined.bytes + back->data.inlined.length,
+               s.data.inlined.bytes, cp1);
+        back->data.inlined.length = GPR_SLICE_INLINED_SIZE;
+        if (n == sb->capacity) {
+          sb->capacity = GROW(sb->capacity);
+          GPR_ASSERT(sb->capacity > sb->count);
+          sb->slices =
+              gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
+        }
+        back = &sb->slices[n];
+        sb->count = n + 1;
+        back->refcount = NULL;
+        back->data.inlined.length = s.data.inlined.length - cp1;
+        memcpy(back->data.inlined.bytes, s.data.inlined.bytes + cp1,
+               s.data.inlined.length - cp1);
+      }
+      sb->length += s.data.inlined.length;
+      return; /* early out */
+    }
+  }
+  gpr_slice_buffer_add_indexed(sb, s);
+}
+
+void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *s, size_t n) {
+  size_t i;
+  for (i = 0; i < n; i++) {
+    gpr_slice_buffer_add(sb, s[i]);
+  }
+}
+
+void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb) {
+  size_t i;
+
+  for (i = 0; i < sb->count; i++) {
+    gpr_slice_unref(sb->slices[i]);
+  }
+
+  sb->count = 0;
+  sb->length = 0;
+}
diff --git a/src/core/support/string.c b/src/core/support/string.c
new file mode 100644
index 0000000..b1f0795
--- /dev/null
+++ b/src/core/support/string.c
@@ -0,0 +1,124 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/string.h>
+
+#include <ctype.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/useful.h>
+
+char *gpr_strdup(const char *src) {
+  char *dst;
+  size_t len;
+
+  if (!src) {
+    return NULL;
+  }
+
+  len = strlen(src) + 1;
+  dst = gpr_malloc(len);
+
+  memcpy(dst, src, len);
+
+  return dst;
+}
+
+typedef struct {
+  size_t capacity;
+  size_t length;
+  char *data;
+} hexout;
+
+static hexout hexout_create() {
+  hexout r = {0, 0, NULL};
+  return r;
+}
+
+static void hexout_append(hexout *out, char c) {
+  if (out->length == out->capacity) {
+    out->capacity = GPR_MAX(8, 2 * out->capacity);
+    out->data = gpr_realloc(out->data, out->capacity);
+  }
+  out->data[out->length++] = c;
+}
+
+char *gpr_hexdump(const char *buf, size_t len, gpr_uint32 flags) {
+  static const char hex[16] = "0123456789abcdef";
+  hexout out = hexout_create();
+
+  const gpr_uint8 *const beg = (const gpr_uint8 *)buf;
+  const gpr_uint8 *const end = beg + len;
+  const gpr_uint8 *cur;
+
+  for (cur = beg; cur != end; ++cur) {
+    if (cur != beg) hexout_append(&out, ' ');
+    hexout_append(&out, hex[*cur >> 4]);
+    hexout_append(&out, hex[*cur & 0xf]);
+  }
+
+  if (flags & GPR_HEXDUMP_PLAINTEXT) {
+    cur = beg;
+    if (len) hexout_append(&out, ' ');
+    hexout_append(&out, '\'');
+    for (cur = beg; cur != end; ++cur) {
+      hexout_append(&out, isprint(*cur) ? *cur : '.');
+    }
+    hexout_append(&out, '\'');
+  }
+
+  hexout_append(&out, 0);
+
+  return out.data;
+}
+
+int gpr_parse_bytes_to_uint32(const char *buf, size_t len, gpr_uint32 *result) {
+  gpr_uint32 out = 0;
+  gpr_uint32 new;
+  size_t i;
+
+  if (len == 0) return 0; /* must have some bytes */
+
+  for (i = 0; i < len; i++) {
+    if (buf[i] < '0' || buf[i] > '9') return 0; /* bad char */
+    new = 10 * out + (buf[i] - '0');
+    if (new < out) return 0; /* overflow */
+    out = new;
+  }
+
+  *result = out;
+  return 1;
+}
diff --git a/src/core/support/string_posix.c b/src/core/support/string_posix.c
new file mode 100644
index 0000000..d1da379
--- /dev/null
+++ b/src/core/support/string_posix.c
@@ -0,0 +1,86 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Posix code for gpr snprintf support. */
+
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200112L
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+int gpr_asprintf(char **strp, const char *format, ...) {
+  va_list args;
+  int ret;
+  char buf[64];
+  size_t strp_buflen;
+
+  /* Use a constant-sized buffer to determine the length. */
+  va_start(args, format);
+  ret = vsnprintf(buf, sizeof(buf), format, args);
+  va_end(args);
+  if (!(0 <= ret && ret < ~(size_t)0)) {
+    *strp = NULL;
+    return -1;
+  }
+
+  /* Allocate a new buffer, with space for the NUL terminator. */
+  strp_buflen = (size_t)ret + 1;
+  if ((*strp = gpr_malloc(strp_buflen)) == NULL) {
+    /* This shouldn't happen, because gpr_malloc() calls abort(). */
+    return -1;
+  }
+
+  /* Return early if we have all the bytes. */
+  if (strp_buflen <= sizeof(buf)) {
+    memcpy(*strp, buf, strp_buflen);
+    return ret;
+  }
+
+  /* Try again using the larger buffer. */
+  va_start(args, format);
+  ret = vsnprintf(*strp, strp_buflen, format, args);
+  va_end(args);
+  if (ret == strp_buflen - 1) {
+    return ret;
+  }
+
+  /* This should never happen. */
+  gpr_free(*strp);
+  *strp = NULL;
+  return -1;
+}
diff --git a/src/core/support/sync.c b/src/core/support/sync.c
new file mode 100644
index 0000000..40e5465
--- /dev/null
+++ b/src/core/support/sync.c
@@ -0,0 +1,135 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Generic implementation of synchronization primitives. */
+
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/atm.h>
+
+/* Number of mutexes to allocate for events, to avoid lock contention.
+   Should be a prime. */
+enum { event_sync_partitions = 31 };
+
+/* Event are partitioned by address to avoid lock contention. */
+static struct sync_array_s {
+  gpr_mu mu;
+  gpr_cv cv;
+} sync_array[event_sync_partitions];
+
+/* This routine is executed once on first use, via event_once */
+static gpr_once event_once = GPR_ONCE_INIT;
+static void event_initialize(void) {
+  int i;
+  for (i = 0; i != event_sync_partitions; i++) {
+    gpr_mu_init(&sync_array[i].mu);
+    gpr_cv_init(&sync_array[i].cv);
+  }
+}
+
+/* Hash ev into an element of sync_array[]. */
+static struct sync_array_s *hash(gpr_event *ev) {
+  return &sync_array[((gpr_uintptr)ev) % event_sync_partitions];
+}
+
+void gpr_event_init(gpr_event *ev) {
+  gpr_once_init(&event_once, &event_initialize);
+  ev->state = 0;
+}
+
+void gpr_event_set(gpr_event *ev, void *value) {
+  struct sync_array_s *s = hash(ev);
+  gpr_mu_lock(&s->mu);
+  GPR_ASSERT(gpr_atm_acq_load(&ev->state) == 0);
+  GPR_ASSERT(value != NULL);
+  gpr_atm_rel_store(&ev->state, (gpr_atm)value);
+  gpr_cv_broadcast(&s->cv);
+  gpr_mu_unlock(&s->mu);
+}
+
+void *gpr_event_get(gpr_event *ev) {
+  return (void *)gpr_atm_acq_load(&ev->state);
+}
+
+void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline) {
+  void *result = (void *)gpr_atm_acq_load(&ev->state);
+  if (result == NULL) {
+    struct sync_array_s *s = hash(ev);
+    gpr_mu_lock(&s->mu);
+    do {
+      result = (void *)gpr_atm_acq_load(&ev->state);
+    } while (result == NULL && !gpr_cv_wait(&s->cv, &s->mu, abs_deadline));
+    gpr_mu_unlock(&s->mu);
+  }
+  return result;
+}
+
+void *gpr_event_cancellable_wait(gpr_event *ev, gpr_timespec abs_deadline,
+                                 gpr_cancellable *c) {
+  void *result = (void *)gpr_atm_acq_load(&ev->state);
+  if (result == NULL) {
+    struct sync_array_s *s = hash(ev);
+    gpr_mu_lock(&s->mu);
+    do {
+      result = (void *)gpr_atm_acq_load(&ev->state);
+    } while (result == NULL &&
+             !gpr_cv_cancellable_wait(&s->cv, &s->mu, abs_deadline, c));
+    gpr_mu_unlock(&s->mu);
+  }
+  return result;
+}
+
+void gpr_ref_init(gpr_refcount *r, int n) { gpr_atm_rel_store(&r->count, n); }
+
+void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); }
+
+void gpr_refn(gpr_refcount *r, int n) {
+  gpr_atm_no_barrier_fetch_add(&r->count, n);
+}
+
+int gpr_unref(gpr_refcount *r) {
+  return gpr_atm_full_fetch_add(&r->count, -1) == 1;
+}
+
+void gpr_stats_init(gpr_stats_counter *c, gpr_intptr n) {
+  gpr_atm_rel_store(&c->value, n);
+}
+
+void gpr_stats_inc(gpr_stats_counter *c, gpr_intptr inc) {
+  gpr_atm_no_barrier_fetch_add(&c->value, inc);
+}
+
+gpr_intptr gpr_stats_read(const gpr_stats_counter *c) {
+  /* don't need acquire-load, but we have no no-barrier load yet */
+  return gpr_atm_acq_load(&c->value);
+}
diff --git a/src/core/support/sync_posix.c b/src/core/support/sync_posix.c
new file mode 100644
index 0000000..257a7fb
--- /dev/null
+++ b/src/core/support/sync_posix.c
@@ -0,0 +1,82 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Posix gpr synchroization support code. */
+
+#include <errno.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+
+void gpr_mu_init(gpr_mu *mu) { GPR_ASSERT(pthread_mutex_init(mu, NULL) == 0); }
+
+void gpr_mu_destroy(gpr_mu *mu) { GPR_ASSERT(pthread_mutex_destroy(mu) == 0); }
+
+void gpr_mu_lock(gpr_mu *mu) { GPR_ASSERT(pthread_mutex_lock(mu) == 0); }
+
+void gpr_mu_unlock(gpr_mu *mu) { GPR_ASSERT(pthread_mutex_unlock(mu) == 0); }
+
+int gpr_mu_trylock(gpr_mu *mu) {
+  int err = pthread_mutex_trylock(mu);
+  GPR_ASSERT(err == 0 || err == EBUSY);
+  return err == 0;
+}
+
+/*----------------------------------------*/
+
+void gpr_cv_init(gpr_cv *cv) { GPR_ASSERT(pthread_cond_init(cv, NULL) == 0); }
+
+void gpr_cv_destroy(gpr_cv *cv) { GPR_ASSERT(pthread_cond_destroy(cv) == 0); }
+
+int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) {
+  int err = 0;
+  if (gpr_time_cmp(abs_deadline, gpr_inf_future) == 0) {
+    err = pthread_cond_wait(cv, mu);
+  } else {
+    err = pthread_cond_timedwait(cv, mu, &abs_deadline);
+  }
+  GPR_ASSERT(err == 0 || err == ETIMEDOUT || err == EAGAIN);
+  return err == ETIMEDOUT;
+}
+
+void gpr_cv_signal(gpr_cv *cv) { GPR_ASSERT(pthread_cond_signal(cv) == 0); }
+
+void gpr_cv_broadcast(gpr_cv *cv) {
+  GPR_ASSERT(pthread_cond_broadcast(cv) == 0);
+}
+
+/*----------------------------------------*/
+
+void gpr_once_init(gpr_once *once, void (*init_function)(void)) {
+  GPR_ASSERT(pthread_once(once, init_function) == 0);
+}
diff --git a/src/core/support/sync_win32.c b/src/core/support/sync_win32.c
new file mode 100644
index 0000000..63dd4eb
--- /dev/null
+++ b/src/core/support/sync_win32.c
@@ -0,0 +1,120 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Win32 code for gpr synchronization support. */
+
+#define _WIN32_WINNT 0x0600
+#include <windows.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+
+void gpr_mu_init(gpr_mu *mu) {
+  InitializeCriticalSection(&mu->cs);
+  mu->locked = 0;
+}
+
+void gpr_mu_destroy(gpr_mu *mu) { DeleteCriticalSection(&mu->cs); }
+
+void gpr_mu_lock(gpr_mu *mu) {
+  EnterCriticalSection(&mu->cs);
+  GPR_ASSERT(!mu->locked);
+  mu->locked = 1;
+}
+
+void gpr_mu_unlock(gpr_mu *mu) {
+  mu->locked = 0;
+  LeaveCriticalSection(&mu->cs);
+}
+
+int gpr_mu_trylock(gpr_mu *mu) {
+  int result = TryEnterCriticalSection(&mu->cs);
+  if (result) {
+    if (mu->locked) {                /* This thread already holds the lock. */
+      LeaveCriticalSection(&mu->cs); /* Decrement lock count. */
+      result = 0;                    /* Indicate failure */
+    }
+    mu->locked = 1;
+  }
+  return result;
+}
+
+/*----------------------------------------*/
+
+void gpr_cv_init(gpr_cv *cv) { InitializeConditionVariable(cv); }
+
+void gpr_cv_destroy(gpr_cv *cv) {
+  /* Condition variables don't need destruction in Win32. */
+}
+
+int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) {
+  int timeout = 0;
+  if (gpr_time_cmp(abs_deadline, gpr_inf_future) == 0) {
+    SleepConditionVariableCS(cv, &mu->cs, INFINITE);
+  } else {
+    gpr_timespec now = gpr_now();
+    gpr_int64 now_ms = now.tv_sec * 1000 + now.tv_nsec / 1000000;
+    gpr_int64 deadline_ms =
+        abs_deadline.tv_sec * 1000 + abs_deadline.tv_nsec / 1000000;
+    if (now_ms >= deadline_ms) {
+      timeout = 1;
+    } else {
+      timeout =
+          (SleepConditionVariableCS(cv, &mu->cs, deadline_ms - now_ms) == 0 &&
+           GetLastError() == ERROR_TIMEOUT);
+    }
+  }
+  return timeout;
+}
+
+void gpr_cv_signal(gpr_cv *cv) { WakeConditionVariable(cv); }
+
+void gpr_cv_broadcast(gpr_cv *cv) { WakeAllConditionVariable(cv); }
+
+/*----------------------------------------*/
+
+static void *dummy;
+struct run_once_func_arg {
+  void (*init_function)(void);
+};
+static int run_once_func(gpr_once *once, void *v, void **pv) {
+  struct run_once_func_arg *arg = v;
+  (*arg->init_function)();
+  return 1;
+}
+
+void gpr_once_init(gpr_once *once, void (*init_function)(void)) {
+  struct run_once_func_arg arg;
+  arg.init_function = init_function;
+  InitOnceExecuteOnce(once, &run_once_func, &arg, &dummy);
+}
diff --git a/src/core/support/thd_internal.h b/src/core/support/thd_internal.h
new file mode 100644
index 0000000..519177a
--- /dev/null
+++ b/src/core/support/thd_internal.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SUPPORT_THD_INTERNAL_H__
+#define __GRPC_INTERNAL_SUPPORT_THD_INTERNAL_H__
+
+/* Internal interfaces between modules within the gpr support library.  */
+
+#endif  /* __GRPC_INTERNAL_SUPPORT_THD_INTERNAL_H__ */
diff --git a/src/core/support/thd_posix.c b/src/core/support/thd_posix.c
new file mode 100644
index 0000000..c86eea4
--- /dev/null
+++ b/src/core/support/thd_posix.c
@@ -0,0 +1,78 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Posix implementation for gpr threads. */
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+
+struct thd_arg {
+  void (*body)(void *arg); /* body of a thread */
+  void *arg;               /* argument to a thread */
+};
+
+/* Body of every thread started via gpr_thd_new. */
+static void *thread_body(void *v) {
+  struct thd_arg a = *(struct thd_arg *)v;
+  gpr_free(v);
+  (*a.body)(a.arg);
+  return NULL;
+}
+
+int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
+                const gpr_thd_options *options) {
+  int thread_started;
+  pthread_attr_t attr;
+  struct thd_arg *a = gpr_malloc(sizeof(*a));
+  a->body = thd_body;
+  a->arg = arg;
+
+  GPR_ASSERT(pthread_attr_init(&attr) == 0);
+  GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0);
+  thread_started = (pthread_create(t, &attr, &thread_body, a) == 0);
+  GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
+  if (!thread_started) {
+    gpr_free(a);
+  }
+  return thread_started;
+}
+
+gpr_thd_options gpr_thd_options_default(void) {
+  gpr_thd_options options;
+  memset(&options, 0, sizeof(options));
+  return options;
+}
diff --git a/src/core/support/thd_win32.c b/src/core/support/thd_win32.c
new file mode 100644
index 0000000..8440479
--- /dev/null
+++ b/src/core/support/thd_win32.c
@@ -0,0 +1,80 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Posix implementation for gpr threads. */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include <windows.h>
+#include <string.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/thd.h>
+
+struct thd_arg {
+  void (*body)(void *arg); /* body of a thread */
+  void *arg;               /* argument to a thread */
+};
+
+/* Body of every thread started via gpr_thd_new. */
+static DWORD thread_body(void *v) {
+  struct thd_arg a = *(struct thd_arg *)v;
+  gpr_free(v);
+  (*a.body)(a.arg);
+  return 0;
+}
+
+int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
+                const gpr_thd_options *options) {
+  HANDLE handle;
+  struct thd_arg *a = gpr_malloc(sizeof(*a));
+  a->body = thd_body;
+  a->arg = arg;
+  *t = 0;
+  handle = CreateThread(NULL, 64 * 1024, &thread_body, a, 0, NULL);
+  if (handle == NULL) {
+    gpr_free(a);
+  } else {
+    CloseHandle(handle); /* threads are "detached" */
+  }
+  return handle != NULL;
+}
+
+gpr_thd_options gpr_thd_options_default(void) {
+  gpr_thd_options options;
+  memset(&options, 0, sizeof(options));
+  return options;
+}
+
+#endif /* GPR_WIN32 */
diff --git a/src/core/support/time.c b/src/core/support/time.c
new file mode 100644
index 0000000..1d8765f
--- /dev/null
+++ b/src/core/support/time.c
@@ -0,0 +1,243 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Generic implementation of time calls. */
+
+#include <grpc/support/time.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <grpc/support/log.h>
+
+int gpr_time_cmp(gpr_timespec a, gpr_timespec b) {
+  int cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec);
+  if (cmp == 0) {
+    cmp = (a.tv_nsec > b.tv_nsec) - (a.tv_nsec < b.tv_nsec);
+  }
+  return cmp;
+}
+
+/* There's no standard TIME_T_MIN and TIME_T_MAX, so we construct them.  The
+   following assumes that signed types are two's-complement and that bytes are
+   8 bits.  */
+
+/* The top bit of integral type t. */
+#define TOP_BIT_OF_TYPE(t) (((gpr_uintmax)1) << ((8 * sizeof(t)) - 1))
+
+/* Return whether integral type t is signed. */
+#define TYPE_IS_SIGNED(t) (((t)1) > (t) ~(t)0)
+
+/* The minimum and maximum value of integral type t. */
+#define TYPE_MIN(t) ((t)(TYPE_IS_SIGNED(t) ? TOP_BIT_OF_TYPE(t) : 0))
+#define TYPE_MAX(t)                                 \
+  ((t)(TYPE_IS_SIGNED(t) ? (TOP_BIT_OF_TYPE(t) - 1) \
+                         : ((TOP_BIT_OF_TYPE(t) - 1) << 1) + 1))
+
+const gpr_timespec gpr_time_0 = {0, 0};
+const gpr_timespec gpr_inf_future = {TYPE_MAX(time_t), 0};
+const gpr_timespec gpr_inf_past = {TYPE_MIN(time_t), 0};
+
+/* TODO(ctiller): consider merging _nanos, _micros, _millis into a single
+   function for maintainability. Similarly for _seconds, _minutes, and _hours */
+
+gpr_timespec gpr_time_from_nanos(long ns) {
+  gpr_timespec result;
+  if (ns == LONG_MAX) {
+    result = gpr_inf_future;
+  } else if (ns == LONG_MIN) {
+    result = gpr_inf_past;
+  } else if (ns >= 0) {
+    result.tv_sec = ns / 1000000000;
+    result.tv_nsec = ns - result.tv_sec * 1000000000;
+  } else {
+    /* Calculation carefully formulated to avoid any possible under/overflow. */
+    result.tv_sec = (-(999999999 - (ns + 1000000000)) / 1000000000) - 1;
+    result.tv_nsec = ns - result.tv_sec * 1000000000;
+  }
+  return result;
+}
+
+gpr_timespec gpr_time_from_micros(long us) {
+  gpr_timespec result;
+  if (us == LONG_MAX) {
+    result = gpr_inf_future;
+  } else if (us == LONG_MIN) {
+    result = gpr_inf_past;
+  } else if (us >= 0) {
+    result.tv_sec = us / 1000000;
+    result.tv_nsec = (us - result.tv_sec * 1000000) * 1000;
+  } else {
+    /* Calculation carefully formulated to avoid any possible under/overflow. */
+    result.tv_sec = (-(999999 - (us + 1000000)) / 1000000) - 1;
+    result.tv_nsec = (us - result.tv_sec * 1000000) * 1000;
+  }
+  return result;
+}
+
+gpr_timespec gpr_time_from_millis(long ms) {
+  gpr_timespec result;
+  if (ms == LONG_MAX) {
+    result = gpr_inf_future;
+  } else if (ms == LONG_MIN) {
+    result = gpr_inf_past;
+  } else if (ms >= 0) {
+    result.tv_sec = ms / 1000;
+    result.tv_nsec = (ms - result.tv_sec * 1000) * 1000000;
+  } else {
+    /* Calculation carefully formulated to avoid any possible under/overflow. */
+    result.tv_sec = (-(999 - (ms + 1000)) / 1000) - 1;
+    result.tv_nsec = (ms - result.tv_sec * 1000) * 1000000;
+  }
+  return result;
+}
+
+gpr_timespec gpr_time_from_seconds(long s) {
+  gpr_timespec result;
+  if (s == LONG_MAX) {
+    result = gpr_inf_future;
+  } else if (s == LONG_MIN) {
+    result = gpr_inf_past;
+  } else {
+    result.tv_sec = s;
+    result.tv_nsec = 0;
+  }
+  return result;
+}
+
+gpr_timespec gpr_time_from_minutes(long m) {
+  gpr_timespec result;
+  if (m >= LONG_MAX / 60) {
+    result = gpr_inf_future;
+  } else if (m <= LONG_MIN / 60) {
+    result = gpr_inf_past;
+  } else {
+    result.tv_sec = m * 60;
+    result.tv_nsec = 0;
+  }
+  return result;
+}
+
+gpr_timespec gpr_time_from_hours(long h) {
+  gpr_timespec result;
+  if (h >= LONG_MAX / 3600) {
+    result = gpr_inf_future;
+  } else if (h <= LONG_MIN / 3600) {
+    result = gpr_inf_past;
+  } else {
+    result.tv_sec = h * 3600;
+    result.tv_nsec = 0;
+  }
+  return result;
+}
+
+gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) {
+  gpr_timespec sum;
+  int inc = 0;
+  sum.tv_nsec = a.tv_nsec + b.tv_nsec;
+  if (sum.tv_nsec >= 1000000000) {
+    sum.tv_nsec -= 1000000000;
+    inc++;
+  }
+  if (a.tv_sec == TYPE_MAX(time_t) || a.tv_sec == TYPE_MIN(time_t)) {
+    sum = a;
+  } else if (b.tv_sec == TYPE_MAX(time_t) ||
+             (b.tv_sec >= 0 && a.tv_sec >= TYPE_MAX(time_t) - b.tv_sec)) {
+    sum = gpr_inf_future;
+  } else if (b.tv_sec == TYPE_MIN(time_t) ||
+             (b.tv_sec <= 0 && a.tv_sec <= TYPE_MIN(time_t) - b.tv_sec)) {
+    sum = gpr_inf_past;
+  } else {
+    sum.tv_sec = a.tv_sec + b.tv_sec;
+    if (inc != 0 && sum.tv_sec == TYPE_MAX(time_t) - 1) {
+      sum = gpr_inf_future;
+    } else {
+      sum.tv_sec += inc;
+    }
+  }
+  return sum;
+}
+
+gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) {
+  gpr_timespec diff;
+  int dec = 0;
+  diff.tv_nsec = a.tv_nsec - b.tv_nsec;
+  if (diff.tv_nsec < 0) {
+    diff.tv_nsec += 1000000000;
+    dec++;
+  }
+  if (a.tv_sec == TYPE_MAX(time_t) || a.tv_sec == TYPE_MIN(time_t)) {
+    diff = a;
+  } else if (b.tv_sec == TYPE_MIN(time_t) ||
+             (b.tv_sec <= 0 && a.tv_sec >= TYPE_MAX(time_t) + b.tv_sec)) {
+    diff = gpr_inf_future;
+  } else if (b.tv_sec == TYPE_MAX(time_t) ||
+             (b.tv_sec >= 0 && a.tv_sec <= TYPE_MIN(time_t) + b.tv_sec)) {
+    diff = gpr_inf_past;
+  } else {
+    diff.tv_sec = a.tv_sec - b.tv_sec;
+    if (dec != 0 && diff.tv_sec == TYPE_MIN(time_t) + 1) {
+      diff = gpr_inf_past;
+    } else {
+      diff.tv_sec -= dec;
+    }
+  }
+  return diff;
+}
+
+int gpr_time_similar(gpr_timespec a, gpr_timespec b, gpr_timespec threshold) {
+  int cmp_ab;
+
+  cmp_ab = gpr_time_cmp(a, b);
+  if (cmp_ab == 0) return 1;
+  if (cmp_ab < 0) {
+    return gpr_time_cmp(gpr_time_sub(b, a), threshold) <= 0;
+  } else {
+    return gpr_time_cmp(gpr_time_sub(a, b), threshold) <= 0;
+  }
+}
+
+struct timeval gpr_timeval_from_timespec(gpr_timespec t) {
+  /* TODO(klempner): Consider whether this should round up, since it is likely
+     to be used for delays */
+  struct timeval tv;
+  tv.tv_sec = t.tv_sec;
+  tv.tv_usec = t.tv_nsec / 1000;
+  return tv;
+}
+
+gpr_timespec gpr_timespec_from_timeval(struct timeval t) {
+  gpr_timespec ts;
+  ts.tv_sec = t.tv_sec;
+  ts.tv_nsec = t.tv_usec * 1000;
+  return ts;
+}
diff --git a/src/core/support/time_posix.c b/src/core/support/time_posix.c
new file mode 100644
index 0000000..e7b79d1
--- /dev/null
+++ b/src/core/support/time_posix.c
@@ -0,0 +1,81 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Posix code for gpr time support. */
+
+/* So we get nanosleep and clock_* */
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 199309L
+#endif
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <grpc/support/time.h>
+
+#if _POSIX_TIMERS > 0
+gpr_timespec gpr_now(void) {
+  gpr_timespec now;
+  clock_gettime(CLOCK_REALTIME, &now);
+  return now;
+}
+#else
+/* For some reason Apple's OSes haven't implemented clock_gettime. */
+/* TODO(klempner): Add special handling for Apple. */
+gpr_timespec gpr_now(void) {
+  gpr_timespec now;
+  struct timeval now_tv;
+  gettimeofday(&now_tv, NULL);
+  now.tv_sec = now_tv.tv_sec;
+  now.tv_nsec = now_tv.tv_usec / 1000;
+  return now;
+}
+#endif
+
+void gpr_sleep_until(gpr_timespec until) {
+  gpr_timespec now;
+  gpr_timespec delta;
+
+  for (;;) {
+    /* We could simplify by using clock_nanosleep instead, but it might be
+     * slightly less portable. */
+    now = gpr_now();
+    if (gpr_time_cmp(until, now) <= 0) {
+      return;
+    }
+
+    delta = gpr_time_sub(until, now);
+    if (nanosleep(&delta, NULL) == 0) {
+      break;
+    }
+  }
+}
diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c
new file mode 100644
index 0000000..4258091
--- /dev/null
+++ b/src/core/support/time_win32.c
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Win32 code for gpr time support. */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include <grpc/support/time.h>
+#include <windows.h>
+
+gpr_timespec gpr_now(void) {
+  gpr_timespec now_tv;
+  struct _timeb64 now_tb;
+  _ftime64(&now_tb);
+  now_tv.tv_sec = now_tb.time;
+  now_tv.tv_nsec = now_tb.millitm * 1000000;
+  return now_tv;
+}
+
+#endif /* GPR_WIN32 */
diff --git a/src/core/surface/byte_buffer.c b/src/core/surface/byte_buffer.c
new file mode 100644
index 0000000..27a6c6e
--- /dev/null
+++ b/src/core/surface/byte_buffer.c
@@ -0,0 +1,68 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/byte_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+grpc_byte_buffer *grpc_byte_buffer_create(gpr_slice *slices, size_t nslices) {
+  size_t i;
+  grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer));
+
+  bb->type = GRPC_BB_SLICE_BUFFER;
+  gpr_slice_buffer_init(&bb->data.slice_buffer);
+  for (i = 0; i < nslices; i++) {
+    gpr_slice_ref(slices[i]);
+    gpr_slice_buffer_add(&bb->data.slice_buffer, slices[i]);
+  }
+
+  return bb;
+}
+
+void grpc_byte_buffer_destroy(grpc_byte_buffer *bb) {
+  switch (bb->type) {
+    case GRPC_BB_SLICE_BUFFER:
+      gpr_slice_buffer_destroy(&bb->data.slice_buffer);
+      break;
+  }
+  free(bb);
+}
+
+size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) {
+  switch (bb->type) {
+    case GRPC_BB_SLICE_BUFFER:
+      return bb->data.slice_buffer.length;
+  }
+  gpr_log(GPR_ERROR, "should never reach here");
+  abort();
+}
diff --git a/src/core/surface/byte_buffer_reader.c b/src/core/surface/byte_buffer_reader.c
new file mode 100644
index 0000000..18500b8
--- /dev/null
+++ b/src/core/surface/byte_buffer_reader.c
@@ -0,0 +1,74 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/byte_buffer_reader.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/byte_buffer.h>
+
+grpc_byte_buffer_reader *grpc_byte_buffer_reader_create(
+    grpc_byte_buffer *buffer) {
+  grpc_byte_buffer_reader *reader = malloc(sizeof(grpc_byte_buffer_reader));
+  reader->buffer = buffer;
+  switch (buffer->type) {
+    case GRPC_BB_SLICE_BUFFER:
+      reader->current.index = 0;
+  }
+  return reader;
+}
+
+int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
+                                 gpr_slice *slice) {
+  grpc_byte_buffer *buffer = reader->buffer;
+  gpr_slice_buffer *slice_buffer;
+  switch (buffer->type) {
+    case GRPC_BB_SLICE_BUFFER:
+      slice_buffer = &buffer->data.slice_buffer;
+      if (reader->current.index < slice_buffer->count) {
+        *slice = gpr_slice_ref(slice_buffer->slices[reader->current.index]);
+        reader->current.index += 1;
+        return 1;
+      } else {
+        return 0;
+      }
+      break;
+  }
+  return 0;
+}
+
+void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader) {
+  free(reader);
+}
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
new file mode 100644
index 0000000..63d408d
--- /dev/null
+++ b/src/core/surface/call.c
@@ -0,0 +1,835 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/surface/call.h"
+#include "src/core/channel/channel_stack.h"
+#include "src/core/channel/metadata_buffer.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+#include "src/core/surface/channel.h"
+#include "src/core/surface/completion_queue.h"
+#include "src/core/surface/surface_em.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define INVALID_TAG ((void *)0xdeadbeef)
+
+/* Pending read queue
+
+   This data structure tracks reads that need to be presented to the completion
+   queue but are waiting for the application to ask for them. */
+
+#define INITIAL_PENDING_READ_COUNT 4
+
+typedef struct {
+  grpc_byte_buffer *byte_buffer;
+  void *user_data;
+  void (*on_finish)(void *user_data, grpc_op_error error);
+} pending_read;
+
+/* TODO(ctiller): inline an element or two into this struct to avoid per-call
+                  allocations */
+typedef struct {
+  pending_read *data;
+  size_t count;
+  size_t capacity;
+} pending_read_array;
+
+typedef struct {
+  size_t drain_pos;
+  pending_read_array filling;
+  pending_read_array draining;
+} pending_read_queue;
+
+static void pra_init(pending_read_array *array) {
+  array->data = gpr_malloc(sizeof(pending_read) * INITIAL_PENDING_READ_COUNT);
+  array->count = 0;
+  array->capacity = INITIAL_PENDING_READ_COUNT;
+}
+
+static void pra_destroy(pending_read_array *array,
+                        size_t finish_starting_from) {
+  size_t i;
+  for (i = finish_starting_from; i < array->count; i++) {
+    array->data[i].on_finish(array->data[i].user_data, GRPC_OP_ERROR);
+  }
+  gpr_free(array->data);
+}
+
+/* Append an operation to an array, expanding as needed */
+static void pra_push(pending_read_array *a, grpc_byte_buffer *buffer,
+                     void (*on_finish)(void *user_data, grpc_op_error error),
+                     void *user_data) {
+  if (a->count == a->capacity) {
+    a->capacity *= 2;
+    a->data = gpr_realloc(a->data, sizeof(pending_read) * a->capacity);
+  }
+  a->data[a->count].byte_buffer = buffer;
+  a->data[a->count].user_data = user_data;
+  a->data[a->count].on_finish = on_finish;
+  a->count++;
+}
+
+static void prq_init(pending_read_queue *q) {
+  q->drain_pos = 0;
+  pra_init(&q->filling);
+  pra_init(&q->draining);
+}
+
+static void prq_destroy(pending_read_queue *q) {
+  pra_destroy(&q->filling, 0);
+  pra_destroy(&q->draining, q->drain_pos);
+}
+
+static int prq_is_empty(pending_read_queue *q) {
+  return (q->drain_pos == q->draining.count && q->filling.count == 0);
+}
+
+static void prq_push(pending_read_queue *q, grpc_byte_buffer *buffer,
+                     void (*on_finish)(void *user_data, grpc_op_error error),
+                     void *user_data) {
+  pra_push(&q->filling, buffer, on_finish, user_data);
+}
+
+/* Take the first queue element and move it to the completion queue. Do nothing
+   if q is empty */
+static int prq_pop_to_cq(pending_read_queue *q, void *tag, grpc_call *call,
+                         grpc_completion_queue *cq) {
+  pending_read_array temp_array;
+  pending_read *pr;
+
+  if (q->drain_pos == q->draining.count) {
+    if (q->filling.count == 0) {
+      return 0;
+    }
+    q->draining.count = 0;
+    q->drain_pos = 0;
+    /* swap arrays */
+    temp_array = q->filling;
+    q->filling = q->draining;
+    q->draining = temp_array;
+  }
+
+  pr = q->draining.data + q->drain_pos;
+  q->drain_pos++;
+  grpc_cq_end_read(cq, tag, call, pr->on_finish, pr->user_data,
+                   pr->byte_buffer);
+  return 1;
+}
+
+/* grpc_call proper */
+
+/* the state of a call, based upon which functions have been called against
+   said call */
+typedef enum { CALL_CREATED, CALL_STARTED, CALL_FINISHED } call_state;
+
+struct grpc_call {
+  grpc_completion_queue *cq;
+  grpc_channel *channel;
+  grpc_mdctx *metadata_context;
+
+  call_state state;
+  gpr_uint8 is_client;
+  gpr_uint8 have_write;
+  grpc_metadata_buffer incoming_metadata;
+
+  /* protects variables in this section */
+  gpr_mu read_mu;
+  gpr_uint8 reads_done;
+  gpr_uint8 received_finish;
+  gpr_uint8 received_metadata;
+  gpr_uint8 have_read;
+  gpr_uint8 have_alarm;
+  /* The current outstanding read message tag (only valid if have_read == 1) */
+  void *read_tag;
+  void *metadata_tag;
+  void *finished_tag;
+  pending_read_queue prq;
+
+  grpc_em_alarm alarm;
+
+  /* The current outstanding send message/context/invoke/end tag (only valid if
+     have_write == 1) */
+  void *write_tag;
+
+  /* The final status of the call */
+  grpc_status_code status_code;
+  grpc_mdstr *status_details;
+
+  gpr_refcount internal_refcount;
+};
+
+#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call)+1))
+#define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1)
+#define CALL_ELEM_FROM_CALL(call, idx) \
+  grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx)
+#define CALL_FROM_TOP_ELEM(top_elem) \
+  CALL_FROM_CALL_STACK(grpc_call_stack_from_top_element(top_elem))
+
+static void do_nothing(void *ignored, grpc_op_error also_ignored) {}
+
+grpc_call *grpc_call_create(grpc_channel *channel,
+                            const void *server_transport_data) {
+  grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel);
+  grpc_call *call =
+      gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
+  call->cq = NULL;
+  call->channel = channel;
+  grpc_channel_internal_ref(channel);
+  call->metadata_context = grpc_channel_get_metadata_context(channel);
+  call->state = CALL_CREATED;
+  call->is_client = (server_transport_data == NULL);
+  call->write_tag = INVALID_TAG;
+  call->read_tag = INVALID_TAG;
+  call->metadata_tag = INVALID_TAG;
+  call->finished_tag = INVALID_TAG;
+  call->have_read = 0;
+  call->have_write = 0;
+  call->have_alarm = 0;
+  call->received_metadata = 0;
+  call->status_code =
+      server_transport_data != NULL ? GRPC_STATUS_OK : GRPC_STATUS_UNKNOWN;
+  call->status_details = NULL;
+  call->received_finish = 0;
+  call->reads_done = 0;
+  grpc_metadata_buffer_init(&call->incoming_metadata);
+  gpr_ref_init(&call->internal_refcount, 1);
+  grpc_call_stack_init(channel_stack, server_transport_data,
+                       CALL_STACK_FROM_CALL(call));
+  prq_init(&call->prq);
+  gpr_mu_init(&call->read_mu);
+  return call;
+}
+
+void grpc_call_internal_ref(grpc_call *c) { gpr_ref(&c->internal_refcount); }
+
+void grpc_call_internal_unref(grpc_call *c) {
+  if (gpr_unref(&c->internal_refcount)) {
+    grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c));
+    grpc_metadata_buffer_destroy(&c->incoming_metadata, GRPC_OP_OK);
+    if (c->status_details) {
+      grpc_mdstr_unref(c->status_details);
+    }
+    prq_destroy(&c->prq);
+    gpr_mu_destroy(&c->read_mu);
+    grpc_channel_internal_unref(c->channel);
+    gpr_free(c);
+  }
+}
+
+void grpc_call_destroy(grpc_call *c) {
+  gpr_mu_lock(&c->read_mu);
+  if (c->have_alarm) {
+    void *arg_was;
+    grpc_em_alarm_cancel(&c->alarm, &arg_was);
+    c->have_alarm = 0;
+  }
+  gpr_mu_unlock(&c->read_mu);
+  grpc_call_internal_unref(c);
+}
+
+grpc_call_error grpc_call_cancel(grpc_call *c) {
+  grpc_call_element *elem;
+  grpc_call_op op;
+
+  op.type = GRPC_CANCEL_OP;
+  op.dir = GRPC_CALL_DOWN;
+  op.flags = 0;
+  op.done_cb = do_nothing;
+  op.user_data = NULL;
+
+  elem = CALL_ELEM_FROM_CALL(c, 0);
+  elem->filter->call_op(elem, &op);
+
+  return GRPC_CALL_OK;
+}
+
+void grpc_call_execute_op(grpc_call *call, grpc_call_op *op) {
+  grpc_call_element *elem;
+  GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
+  elem = CALL_ELEM_FROM_CALL(call, 0);
+  elem->filter->call_op(elem, op);
+}
+
+grpc_call_error grpc_call_add_metadata(grpc_call *call, grpc_metadata *metadata,
+                                       gpr_uint32 flags) {
+  grpc_call_element *elem;
+  grpc_call_op op;
+
+  if (call->state >= CALL_STARTED) {
+    return GRPC_CALL_ERROR_ALREADY_INVOKED;
+  }
+
+  op.type = GRPC_SEND_METADATA;
+  op.dir = GRPC_CALL_DOWN;
+  op.flags = flags;
+  op.done_cb = do_nothing;
+  op.user_data = NULL;
+  op.data.metadata = grpc_mdelem_from_string_and_buffer(
+      call->metadata_context, metadata->key, (gpr_uint8 *)metadata->value,
+      metadata->value_length);
+
+  elem = CALL_ELEM_FROM_CALL(call, 0);
+  elem->filter->call_op(elem, &op);
+
+  return GRPC_CALL_OK;
+}
+
+static void done_invoke(void *user_data, grpc_op_error error) {
+  grpc_call *call = user_data;
+  void *tag = call->write_tag;
+
+  GPR_ASSERT(call->have_write);
+  call->have_write = 0;
+  call->write_tag = INVALID_TAG;
+  grpc_cq_end_invoke_accepted(call->cq, tag, call, NULL, NULL, error);
+}
+
+static void finish_call(grpc_call *call) {
+  grpc_status status;
+  status.code = call->status_code;
+  status.details = call->status_details
+                       ? (char *)grpc_mdstr_as_c_string(call->status_details)
+                       : NULL;
+  grpc_cq_end_finished(call->cq, call->finished_tag, call, NULL, NULL, status);
+}
+
+grpc_call_error grpc_call_start_invoke(grpc_call *call,
+                                       grpc_completion_queue *cq,
+                                       void *invoke_accepted_tag,
+                                       void *metadata_read_tag,
+                                       void *finished_tag, gpr_uint32 flags) {
+  grpc_call_element *elem;
+  grpc_call_op op;
+
+  /* validate preconditions */
+  if (!call->is_client) {
+    gpr_log(GPR_ERROR, "can only call %s on clients", __FUNCTION__);
+    return GRPC_CALL_ERROR_NOT_ON_SERVER;
+  }
+
+  if (call->state >= CALL_STARTED || call->cq) {
+    gpr_log(GPR_ERROR, "call is already invoked");
+    return GRPC_CALL_ERROR_ALREADY_INVOKED;
+  }
+
+  if (call->have_write) {
+    gpr_log(GPR_ERROR, "can only have one pending write operation at a time");
+    return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+  }
+
+  if (call->have_read) {
+    gpr_log(GPR_ERROR, "can only have one pending read operation at a time");
+    return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+  }
+
+  if (flags & GRPC_WRITE_NO_COMPRESS) {
+    return GRPC_CALL_ERROR_INVALID_FLAGS;
+  }
+
+  /* inform the completion queue of an incoming operation */
+  grpc_cq_begin_op(cq, call, GRPC_FINISHED);
+  grpc_cq_begin_op(cq, call, GRPC_CLIENT_METADATA_READ);
+  grpc_cq_begin_op(cq, call, GRPC_INVOKE_ACCEPTED);
+
+  gpr_mu_lock(&call->read_mu);
+
+  /* update state */
+  call->cq = cq;
+  call->state = CALL_STARTED;
+  call->finished_tag = finished_tag;
+
+  if (call->received_finish) {
+    /* handle early cancellation */
+    grpc_cq_end_invoke_accepted(call->cq, invoke_accepted_tag, call, NULL, NULL,
+                                GRPC_OP_ERROR);
+    grpc_cq_end_client_metadata_read(call->cq, metadata_read_tag, call, NULL,
+                                     NULL, 0, NULL);
+    finish_call(call);
+
+    /* early out.. unlock & return */
+    gpr_mu_unlock(&call->read_mu);
+    return GRPC_CALL_OK;
+  }
+
+  call->write_tag = invoke_accepted_tag;
+  call->metadata_tag = metadata_read_tag;
+
+  call->have_write = 1;
+
+  gpr_mu_unlock(&call->read_mu);
+
+  /* call down the filter stack */
+  op.type = GRPC_SEND_START;
+  op.dir = GRPC_CALL_DOWN;
+  op.flags = flags;
+  op.done_cb = done_invoke;
+  op.user_data = call;
+
+  elem = CALL_ELEM_FROM_CALL(call, 0);
+  elem->filter->call_op(elem, &op);
+
+  return GRPC_CALL_OK;
+}
+
+grpc_call_error grpc_call_accept(grpc_call *call, grpc_completion_queue *cq,
+                                 void *finished_tag, gpr_uint32 flags) {
+  grpc_call_element *elem;
+  grpc_call_op op;
+
+  /* validate preconditions */
+  if (call->is_client) {
+    gpr_log(GPR_ERROR, "can only call %s on servers", __FUNCTION__);
+    return GRPC_CALL_ERROR_NOT_ON_CLIENT;
+  }
+
+  if (call->state >= CALL_STARTED) {
+    gpr_log(GPR_ERROR, "call is already invoked");
+    return GRPC_CALL_ERROR_ALREADY_INVOKED;
+  }
+
+  if (flags & GRPC_WRITE_NO_COMPRESS) {
+    return GRPC_CALL_ERROR_INVALID_FLAGS;
+  }
+
+  /* inform the completion queue of an incoming operation (corresponding to
+     finished_tag) */
+  grpc_cq_begin_op(cq, call, GRPC_FINISHED);
+
+  /* update state */
+  gpr_mu_lock(&call->read_mu);
+  call->state = CALL_STARTED;
+  call->cq = cq;
+  call->finished_tag = finished_tag;
+  if (prq_is_empty(&call->prq) && call->received_finish) {
+    finish_call(call);
+
+    /* early out.. unlock & return */
+    gpr_mu_unlock(&call->read_mu);
+    return GRPC_CALL_OK;
+  }
+  gpr_mu_unlock(&call->read_mu);
+
+  /* call down */
+  op.type = GRPC_SEND_START;
+  op.dir = GRPC_CALL_DOWN;
+  op.flags = flags;
+  op.done_cb = do_nothing;
+  op.user_data = NULL;
+
+  elem = CALL_ELEM_FROM_CALL(call, 0);
+  elem->filter->call_op(elem, &op);
+
+  return GRPC_CALL_OK;
+}
+
+static void done_writes_done(void *user_data, grpc_op_error error) {
+  grpc_call *call = user_data;
+  void *tag = call->write_tag;
+
+  GPR_ASSERT(call->have_write);
+  call->have_write = 0;
+  call->write_tag = INVALID_TAG;
+  grpc_cq_end_finish_accepted(call->cq, tag, call, NULL, NULL, error);
+}
+
+static void done_write(void *user_data, grpc_op_error error) {
+  grpc_call *call = user_data;
+  void *tag = call->write_tag;
+
+  GPR_ASSERT(call->have_write);
+  call->have_write = 0;
+  call->write_tag = INVALID_TAG;
+  grpc_cq_end_write_accepted(call->cq, tag, call, NULL, NULL, error);
+}
+
+void grpc_call_client_initial_metadata_complete(
+    grpc_call_element *surface_element) {
+  grpc_call *call = grpc_call_from_top_element(surface_element);
+  size_t count;
+  grpc_metadata *elements;
+
+  gpr_mu_lock(&call->read_mu);
+  count = grpc_metadata_buffer_count(&call->incoming_metadata);
+  elements = grpc_metadata_buffer_extract_elements(&call->incoming_metadata);
+
+  GPR_ASSERT(!call->received_metadata);
+  grpc_cq_end_client_metadata_read(call->cq, call->metadata_tag, call,
+                                   grpc_metadata_buffer_cleanup_elements,
+                                   elements, count, elements);
+  call->received_metadata = 1;
+  call->metadata_tag = INVALID_TAG;
+  gpr_mu_unlock(&call->read_mu);
+}
+
+static void request_more_data(grpc_call *call) {
+  grpc_call_element *elem;
+  grpc_call_op op;
+
+  /* call down */
+  op.type = GRPC_REQUEST_DATA;
+  op.dir = GRPC_CALL_DOWN;
+  op.flags = 0;
+  op.done_cb = do_nothing;
+  op.user_data = NULL;
+
+  elem = CALL_ELEM_FROM_CALL(call, 0);
+  elem->filter->call_op(elem, &op);
+}
+
+grpc_call_error grpc_call_start_read(grpc_call *call, void *tag) {
+  gpr_uint8 request_more = 0;
+
+  switch (call->state) {
+    case CALL_CREATED:
+      return GRPC_CALL_ERROR_NOT_INVOKED;
+    case CALL_STARTED:
+      break;
+    case CALL_FINISHED:
+      return GRPC_CALL_ERROR_ALREADY_FINISHED;
+  }
+
+  gpr_mu_lock(&call->read_mu);
+
+  if (call->have_read) {
+    gpr_mu_unlock(&call->read_mu);
+    return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+  }
+
+  grpc_cq_begin_op(call->cq, call, GRPC_READ);
+
+  if (!prq_pop_to_cq(&call->prq, tag, call, call->cq)) {
+    if (call->reads_done) {
+      grpc_cq_end_read(call->cq, tag, call, do_nothing, NULL, NULL);
+    } else {
+      call->read_tag = tag;
+      call->have_read = 1;
+      request_more = 1;
+    }
+  } else if (prq_is_empty(&call->prq) && call->received_finish) {
+    finish_call(call);
+  }
+
+  gpr_mu_unlock(&call->read_mu);
+
+  if (request_more) {
+    request_more_data(call);
+  }
+
+  return GRPC_CALL_OK;
+}
+
+grpc_call_error grpc_call_start_write(grpc_call *call,
+                                      grpc_byte_buffer *byte_buffer, void *tag,
+                                      gpr_uint32 flags) {
+  grpc_call_element *elem;
+  grpc_call_op op;
+
+  switch (call->state) {
+    case CALL_CREATED:
+      return GRPC_CALL_ERROR_NOT_INVOKED;
+    case CALL_STARTED:
+      break;
+    case CALL_FINISHED:
+      return GRPC_CALL_ERROR_ALREADY_FINISHED;
+  }
+
+  if (call->have_write) {
+    return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+  }
+
+  grpc_cq_begin_op(call->cq, call, GRPC_WRITE_ACCEPTED);
+
+  /* for now we do no buffering, so a NULL byte_buffer can have no impact
+     on our behavior -- succeed immediately */
+  /* TODO(ctiller): if flags & GRPC_WRITE_BUFFER_HINT == 0, this indicates a
+     flush, and that flush should be propogated down from here */
+  if (byte_buffer == NULL) {
+    grpc_cq_end_write_accepted(call->cq, tag, call, NULL, NULL, GRPC_OP_OK);
+    return GRPC_CALL_OK;
+  }
+
+  call->write_tag = tag;
+  call->have_write = 1;
+
+  op.type = GRPC_SEND_MESSAGE;
+  op.dir = GRPC_CALL_DOWN;
+  op.flags = flags;
+  op.done_cb = done_write;
+  op.user_data = call;
+  op.data.message = byte_buffer;
+
+  elem = CALL_ELEM_FROM_CALL(call, 0);
+  elem->filter->call_op(elem, &op);
+
+  return GRPC_CALL_OK;
+}
+
+grpc_call_error grpc_call_writes_done(grpc_call *call, void *tag) {
+  grpc_call_element *elem;
+  grpc_call_op op;
+
+  if (!call->is_client) {
+    return GRPC_CALL_ERROR_NOT_ON_SERVER;
+  }
+
+  switch (call->state) {
+    case CALL_CREATED:
+      return GRPC_CALL_ERROR_NOT_INVOKED;
+    case CALL_FINISHED:
+      return GRPC_CALL_ERROR_ALREADY_FINISHED;
+    case CALL_STARTED:
+      break;
+  }
+
+  if (call->have_write) {
+    return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+  }
+
+  grpc_cq_begin_op(call->cq, call, GRPC_FINISH_ACCEPTED);
+
+  call->write_tag = tag;
+  call->have_write = 1;
+
+  op.type = GRPC_SEND_FINISH;
+  op.dir = GRPC_CALL_DOWN;
+  op.flags = 0;
+  op.done_cb = done_writes_done;
+  op.user_data = call;
+
+  elem = CALL_ELEM_FROM_CALL(call, 0);
+  elem->filter->call_op(elem, &op);
+
+  return GRPC_CALL_OK;
+}
+
+grpc_call_error grpc_call_start_write_status(grpc_call *call,
+                                             grpc_status status, void *tag) {
+  grpc_call_element *elem;
+  grpc_call_op op;
+
+  if (call->is_client) {
+    return GRPC_CALL_ERROR_NOT_ON_CLIENT;
+  }
+
+  switch (call->state) {
+    case CALL_CREATED:
+      return GRPC_CALL_ERROR_NOT_INVOKED;
+    case CALL_FINISHED:
+      return GRPC_CALL_ERROR_ALREADY_FINISHED;
+    case CALL_STARTED:
+      break;
+  }
+
+  if (call->have_write) {
+    return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+  }
+
+  elem = CALL_ELEM_FROM_CALL(call, 0);
+
+  if (status.details && status.details[0]) {
+    grpc_mdelem *md = grpc_mdelem_from_strings(call->metadata_context,
+                                               "grpc-message", status.details);
+
+    op.type = GRPC_SEND_METADATA;
+    op.dir = GRPC_CALL_DOWN;
+    op.flags = 0;
+    op.done_cb = do_nothing;
+    op.user_data = NULL;
+    op.data.metadata = md;
+    elem->filter->call_op(elem, &op);
+  }
+
+  /* always send status */
+  {
+    grpc_mdelem *md;
+    char buffer[32];
+    sprintf(buffer, "%d", status.code);
+    md =
+        grpc_mdelem_from_strings(call->metadata_context, "grpc-status", buffer);
+
+    op.type = GRPC_SEND_METADATA;
+    op.dir = GRPC_CALL_DOWN;
+    op.flags = 0;
+    op.done_cb = do_nothing;
+    op.user_data = NULL;
+    op.data.metadata = md;
+    elem->filter->call_op(elem, &op);
+  }
+
+  grpc_cq_begin_op(call->cq, call, GRPC_FINISH_ACCEPTED);
+
+  call->state = CALL_FINISHED;
+  call->write_tag = tag;
+  call->have_write = 1;
+
+  op.type = GRPC_SEND_FINISH;
+  op.dir = GRPC_CALL_DOWN;
+  op.flags = 0;
+  op.done_cb = done_writes_done;
+  op.user_data = call;
+
+  elem->filter->call_op(elem, &op);
+
+  return GRPC_CALL_OK;
+}
+
+/* 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 gpr_uint32 decode_status(grpc_mdelem *md) {
+  gpr_uint32 status;
+  void *user_data = grpc_mdelem_get_user_data(md, destroy_status);
+  if (user_data) {
+    status = ((gpr_uint32)(gpr_intptr)user_data) - STATUS_OFFSET;
+  } else {
+    if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
+                                   GPR_SLICE_LENGTH(md->value->slice),
+                                   &status)) {
+      status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
+    }
+    grpc_mdelem_set_user_data(md, destroy_status,
+                              (void *)(gpr_intptr)(status + STATUS_OFFSET));
+  }
+  return status;
+}
+
+void grpc_call_recv_metadata(grpc_call_element *elem, grpc_call_op *op) {
+  grpc_call *call = CALL_FROM_TOP_ELEM(elem);
+  grpc_mdelem *md = op->data.metadata;
+  grpc_mdstr *key = md->key;
+  if (key == grpc_channel_get_status_string(call->channel)) {
+    call->status_code = decode_status(md);
+    grpc_mdelem_unref(md);
+    op->done_cb(op->user_data, GRPC_OP_OK);
+  } else if (key == grpc_channel_get_message_string(call->channel)) {
+    if (call->status_details) {
+      grpc_mdstr_unref(call->status_details);
+    }
+    call->status_details = grpc_mdstr_ref(md->value);
+    grpc_mdelem_unref(md);
+    op->done_cb(op->user_data, GRPC_OP_OK);
+  } else {
+    grpc_metadata_buffer_queue(&call->incoming_metadata, op);
+  }
+}
+
+void grpc_call_recv_finish(grpc_call_element *elem, int is_full_close) {
+  grpc_call *call = CALL_FROM_TOP_ELEM(elem);
+
+  gpr_mu_lock(&call->read_mu);
+
+  if (call->have_read) {
+    grpc_cq_end_read(call->cq, call->read_tag, call, do_nothing, NULL, NULL);
+    call->read_tag = INVALID_TAG;
+    call->have_read = 0;
+  }
+  if (call->is_client && !call->received_metadata && call->cq) {
+    size_t count;
+    grpc_metadata *elements;
+
+    call->received_metadata = 1;
+
+    count = grpc_metadata_buffer_count(&call->incoming_metadata);
+    elements = grpc_metadata_buffer_extract_elements(&call->incoming_metadata);
+    grpc_cq_end_client_metadata_read(call->cq, call->metadata_tag, call,
+                                     grpc_metadata_buffer_cleanup_elements,
+                                     elements, count, elements);
+  }
+  if (is_full_close) {
+    if (call->have_alarm) {
+      void *arg_was;
+      grpc_em_alarm_cancel(&call->alarm, &arg_was);
+      call->have_alarm = 0;
+    }
+    call->received_finish = 1;
+    if (prq_is_empty(&call->prq) && call->cq != NULL) {
+      finish_call(call);
+    }
+  } else {
+    call->reads_done = 1;
+  }
+  gpr_mu_unlock(&call->read_mu);
+}
+
+void grpc_call_recv_message(grpc_call_element *elem, grpc_byte_buffer *message,
+                            void (*on_finish)(void *user_data,
+                                              grpc_op_error error),
+                            void *user_data) {
+  grpc_call *call = CALL_FROM_TOP_ELEM(elem);
+
+  gpr_mu_lock(&call->read_mu);
+  if (call->have_read) {
+    grpc_cq_end_read(call->cq, call->read_tag, call, on_finish, user_data,
+                     message);
+    call->read_tag = INVALID_TAG;
+    call->have_read = 0;
+  } else {
+    prq_push(&call->prq, message, on_finish, user_data);
+  }
+  gpr_mu_unlock(&call->read_mu);
+}
+
+grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
+  return CALL_FROM_TOP_ELEM(elem);
+}
+
+grpc_metadata_buffer *grpc_call_get_metadata_buffer(grpc_call *call) {
+  return &call->incoming_metadata;
+}
+
+static void call_alarm(void *arg, grpc_em_cb_status status) {
+  grpc_call *call = arg;
+  if (status == GRPC_CALLBACK_SUCCESS) {
+    grpc_call_cancel(call);
+  }
+  grpc_call_internal_unref(call);
+}
+
+void grpc_call_set_deadline(grpc_call_element *elem, gpr_timespec deadline) {
+  grpc_call *call = CALL_FROM_TOP_ELEM(elem);
+
+  if (call->have_alarm) {
+    gpr_log(GPR_ERROR, "Attempt to set deadline alarm twice");
+  }
+  grpc_call_internal_ref(call);
+  call->have_alarm = 1;
+  grpc_em_alarm_init(&call->alarm, grpc_surface_em(), call_alarm, call);
+  grpc_em_alarm_add(&call->alarm, deadline);
+}
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
new file mode 100644
index 0000000..2c785a5
--- /dev/null
+++ b/src/core/surface/call.h
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SURFACE_CALL_H__
+#define __GRPC_INTERNAL_SURFACE_CALL_H__
+
+#include "src/core/channel/channel_stack.h"
+#include "src/core/channel/metadata_buffer.h"
+#include <grpc/grpc.h>
+
+grpc_call *grpc_call_create(grpc_channel *channel,
+                            const void *server_transport_data);
+
+void grpc_call_internal_ref(grpc_call *call);
+void grpc_call_internal_unref(grpc_call *call);
+
+/* Helpers for grpc_client, grpc_server filters to publish received data to
+   the completion queue/surface layer */
+void grpc_call_recv_metadata(grpc_call_element *surface_element,
+                             grpc_call_op *op);
+void grpc_call_recv_message(
+    grpc_call_element *surface_element, grpc_byte_buffer *message,
+    void (*on_finish)(void *user_data, grpc_op_error error), void *user_data);
+void grpc_call_recv_finish(grpc_call_element *surface_element,
+                           int is_full_close);
+
+void grpc_call_execute_op(grpc_call *call, grpc_call_op *op);
+
+/* Called when it's known that the initial batch of metadata is complete on the
+   client side (must not be called on the server) */
+void grpc_call_client_initial_metadata_complete(
+    grpc_call_element *surface_element);
+
+void grpc_call_set_deadline(grpc_call_element *surface_element,
+                            gpr_timespec deadline);
+
+/* Given the top call_element, get the call object. */
+grpc_call *grpc_call_from_top_element(grpc_call_element *surface_element);
+
+/* Get the metadata buffer. */
+grpc_metadata_buffer *grpc_call_get_metadata_buffer(grpc_call *call);
+
+#endif  /* __GRPC_INTERNAL_SURFACE_CALL_H__ */
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
new file mode 100644
index 0000000..ff99425
--- /dev/null
+++ b/src/core/surface/channel.c
@@ -0,0 +1,152 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/surface/channel.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/core/surface/call.h"
+#include "src/core/surface/client.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+struct grpc_channel {
+  int is_client;
+  gpr_refcount refs;
+  grpc_mdctx *metadata_context;
+  grpc_mdstr *grpc_status_string;
+  grpc_mdstr *grpc_message_string;
+};
+
+#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c)+1))
+
+grpc_channel *grpc_channel_create_from_filters(
+    const grpc_channel_filter **filters, size_t num_filters,
+    const grpc_channel_args *args, grpc_mdctx *mdctx, int is_client) {
+  size_t size =
+      sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters);
+  grpc_channel *channel = gpr_malloc(size);
+  channel->is_client = is_client;
+  /* decremented by grpc_channel_destroy */
+  gpr_ref_init(&channel->refs, 1);
+  channel->metadata_context = mdctx;
+  channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status");
+  channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message");
+  grpc_channel_stack_init(filters, num_filters, args, channel->metadata_context,
+                          CHANNEL_STACK_FROM_CHANNEL(channel));
+  return channel;
+}
+
+static void do_nothing(void *ignored, grpc_op_error error) {}
+
+grpc_call *grpc_channel_create_call(grpc_channel *channel, const char *method,
+                                    const char *host,
+                                    gpr_timespec absolute_deadline) {
+  grpc_call *call;
+  grpc_metadata md;
+
+  if (!channel->is_client) {
+    gpr_log(GPR_ERROR, "Cannot create a call on the server.");
+    return NULL;
+  }
+
+  call = grpc_call_create(channel, NULL);
+
+#define ADDMD(k, v)                       \
+  do {                                    \
+    md.key = (k);                         \
+    md.value = (char *)(v);               \
+    md.value_length = strlen((v));        \
+    grpc_call_add_metadata(call, &md, 0); \
+  } while (0)
+  ADDMD(":method", "POST");
+  ADDMD(":scheme", "grpc");
+  ADDMD(":path", method);
+  ADDMD(":authority", host);
+  ADDMD("content-type", "application/grpc");
+  if (0 != gpr_time_cmp(absolute_deadline, gpr_inf_future)) {
+    grpc_call_op op;
+    op.type = GRPC_SEND_DEADLINE;
+    op.dir = GRPC_CALL_DOWN;
+    op.flags = 0;
+    op.data.deadline = absolute_deadline;
+    op.done_cb = do_nothing;
+    op.user_data = NULL;
+    grpc_call_execute_op(call, &op);
+  }
+
+  return call;
+}
+
+void grpc_channel_internal_ref(grpc_channel *channel) {
+  gpr_ref(&channel->refs);
+}
+
+void grpc_channel_internal_unref(grpc_channel *channel) {
+  if (gpr_unref(&channel->refs)) {
+    grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
+    grpc_mdstr_unref(channel->grpc_status_string);
+    grpc_mdstr_unref(channel->grpc_message_string);
+    grpc_mdctx_orphan(channel->metadata_context);
+    gpr_free(channel);
+  }
+}
+
+void grpc_channel_destroy(grpc_channel *channel) {
+  grpc_channel_op op;
+  grpc_channel_element *elem;
+
+  op.type = GRPC_CHANNEL_SHUTDOWN;
+  op.dir = GRPC_CALL_DOWN;
+  elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
+  elem->filter->channel_op(elem, &op);
+
+  grpc_channel_internal_unref(channel);
+}
+
+grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) {
+  return CHANNEL_STACK_FROM_CHANNEL(channel);
+}
+
+grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel) {
+  return channel->metadata_context;
+}
+
+grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel) {
+  return channel->grpc_status_string;
+}
+
+grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel) {
+  return channel->grpc_message_string;
+}
diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h
new file mode 100644
index 0000000..11d4939
--- /dev/null
+++ b/src/core/surface/channel.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SURFACE_CHANNEL_H__
+#define __GRPC_INTERNAL_SURFACE_CHANNEL_H__
+
+#include "src/core/channel/channel_stack.h"
+
+grpc_channel *grpc_channel_create_from_filters(
+    const grpc_channel_filter **filters, size_t count,
+    const grpc_channel_args *args, grpc_mdctx *mdctx, int is_client);
+
+grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
+grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel);
+grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel);
+grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel);
+
+void grpc_channel_internal_ref(grpc_channel *channel);
+void grpc_channel_internal_unref(grpc_channel *channel);
+
+#endif  /* __GRPC_INTERNAL_SURFACE_CHANNEL_H__ */
diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c
new file mode 100644
index 0000000..ec1c847
--- /dev/null
+++ b/src/core/surface/channel_create.c
@@ -0,0 +1,213 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/core/channel/census_filter.h"
+#include "src/core/channel/channel_args.h"
+#include "src/core/channel/client_channel.h"
+#include "src/core/channel/client_setup.h"
+#include "src/core/channel/connected_channel.h"
+#include "src/core/channel/http_client_filter.h"
+#include "src/core/channel/http_filter.h"
+#include "src/core/endpoint/resolve_address.h"
+#include "src/core/endpoint/tcp.h"
+#include "src/core/endpoint/tcp_client.h"
+#include "src/core/surface/channel.h"
+#include "src/core/surface/client.h"
+#include "src/core/surface/surface_em.h"
+#include "src/core/transport/chttp2_transport.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/useful.h>
+
+typedef struct setup setup;
+
+/* A single setup request (started via initiate) */
+typedef struct {
+  grpc_client_setup_request *cs_request;
+  setup *setup;
+  /* Resolved addresses, or null if resolution not yet completed */
+  grpc_resolved_addresses *resolved;
+  /* which address in resolved should we pick for the next connection attempt */
+  size_t resolved_index;
+} request;
+
+/* Global setup logic (may be running many simultaneous setup requests, but
+   with only one 'active' */
+struct setup {
+  const char *target;
+  grpc_transport_setup_callback setup_callback;
+  void *setup_user_data;
+  grpc_em *em;
+};
+
+static int maybe_try_next_resolved(request *r);
+
+static void done(request *r, int was_successful) {
+  grpc_client_setup_request_finish(r->cs_request, was_successful);
+  if (r->resolved) {
+    grpc_resolved_addresses_destroy(r->resolved);
+  }
+  gpr_free(r);
+}
+
+/* connection callback: tcp is either valid, or null on error */
+static void on_connect(void *rp, grpc_endpoint *tcp) {
+  request *r = rp;
+
+  if (!grpc_client_setup_request_should_continue(r->cs_request)) {
+    if (tcp) {
+      grpc_endpoint_shutdown(tcp);
+      grpc_endpoint_destroy(tcp);
+    }
+    done(r, 0);
+    return;
+  }
+
+  if (!tcp) {
+    if (!maybe_try_next_resolved(r)) {
+      done(r, 0);
+      return;
+    } else {
+      return;
+    }
+  } else {
+    grpc_create_chttp2_transport(
+        r->setup->setup_callback, r->setup->setup_user_data,
+        grpc_client_setup_get_channel_args(r->cs_request), tcp, NULL, 0,
+        grpc_client_setup_get_mdctx(r->cs_request), 1);
+    done(r, 1);
+    return;
+  }
+}
+
+/* attempt to connect to the next available resolved address */
+static int maybe_try_next_resolved(request *r) {
+  grpc_resolved_address *addr;
+  if (!r->resolved) return 0;
+  if (r->resolved_index == r->resolved->naddrs) return 0;
+  addr = &r->resolved->addrs[r->resolved_index++];
+  grpc_tcp_client_connect(on_connect, r, r->setup->em,
+                          (struct sockaddr *)&addr->addr, addr->len,
+                          grpc_client_setup_request_deadline(r->cs_request));
+  return 1;
+}
+
+/* callback for when our target address has been resolved */
+static void on_resolved(void *rp, grpc_resolved_addresses *resolved) {
+  request *r = rp;
+
+  /* if we're not still the active request, abort */
+  if (!grpc_client_setup_request_should_continue(r->cs_request)) {
+    if (resolved) {
+      grpc_resolved_addresses_destroy(resolved);
+    }
+    done(r, 0);
+    return;
+  }
+
+  if (!resolved) {
+    done(r, 0);
+    return;
+  } else {
+    r->resolved = resolved;
+    r->resolved_index = 0;
+    if (!maybe_try_next_resolved(r)) {
+      done(r, 0);
+    }
+  }
+}
+
+static void initiate_setup(void *sp, grpc_client_setup_request *cs_request) {
+  request *r = gpr_malloc(sizeof(request));
+  r->setup = sp;
+  r->cs_request = cs_request;
+  r->resolved = NULL;
+  r->resolved_index = 0;
+  /* TODO(klempner): Make grpc_resolve_address respect deadline */
+  grpc_resolve_address(r->setup->target, "http", on_resolved, r);
+}
+
+static void done_setup(void *sp) {
+  setup *s = sp;
+  gpr_free((void *)s->target);
+  gpr_free(s);
+}
+
+static grpc_transport_setup_result complete_setup(void *channel_stack,
+                                                  grpc_transport *transport,
+                                                  grpc_mdctx *mdctx) {
+  static grpc_channel_filter const *extra_filters[] = {&grpc_http_client_filter,
+                                                       &grpc_http_filter};
+  return grpc_client_channel_transport_setup_complete(
+      channel_stack, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters),
+      mdctx);
+}
+
+/* Create a client channel:
+   Asynchronously: - resolve target
+                   - connect to it (trying alternatives as presented)
+                   - perform handshakes */
+grpc_channel *grpc_channel_create(const char *target,
+                                  const grpc_channel_args *args) {
+  setup *s = gpr_malloc(sizeof(setup));
+  grpc_mdctx *mdctx = grpc_mdctx_create();
+  grpc_channel *channel = NULL;
+#define MAX_FILTERS 3
+  const grpc_channel_filter *filters[MAX_FILTERS];
+  int n = 0;
+  filters[n++] = &grpc_client_surface_filter;
+  if (grpc_channel_args_is_census_enabled(args)) {
+    filters[n++] = &grpc_client_census_filter;
+  }
+  filters[n++] = &grpc_client_channel_filter;
+  GPR_ASSERT(n <= MAX_FILTERS);
+  channel = grpc_channel_create_from_filters(filters, n, args, mdctx, 1);
+
+  s->target = gpr_strdup(target);
+  s->em = grpc_surface_em();
+  s->setup_callback = complete_setup;
+  s->setup_user_data = grpc_channel_get_channel_stack(channel);
+
+  grpc_client_setup_create_and_attach(grpc_channel_get_channel_stack(channel),
+                                      args, mdctx, initiate_setup, done_setup,
+                                      s, s->em);
+
+  return channel;
+}
diff --git a/src/core/surface/client.c b/src/core/surface/client.c
new file mode 100644
index 0000000..26abffa
--- /dev/null
+++ b/src/core/surface/client.c
@@ -0,0 +1,115 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/surface/client.h"
+
+#include "src/core/surface/call.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+
+typedef struct { void *unused; } call_data;
+
+typedef struct { void *unused; } channel_data;
+
+static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+
+  switch (op->type) {
+    case GRPC_SEND_DEADLINE:
+      grpc_call_set_deadline(elem, op->data.deadline);
+      grpc_call_next_op(elem, op);
+      break;
+    case GRPC_RECV_METADATA:
+      grpc_call_recv_metadata(elem, op);
+      break;
+    case GRPC_RECV_DEADLINE:
+      gpr_log(GPR_ERROR, "Deadline received by client (ignored)");
+      break;
+    case GRPC_RECV_MESSAGE:
+      grpc_call_recv_message(elem, op->data.message, op->done_cb,
+                             op->user_data);
+      break;
+    case GRPC_RECV_HALF_CLOSE:
+      grpc_call_recv_finish(elem, 0);
+      break;
+    case GRPC_RECV_FINISH:
+      grpc_call_recv_finish(elem, 1);
+      break;
+    case GRPC_RECV_END_OF_INITIAL_METADATA:
+      grpc_call_client_initial_metadata_complete(elem);
+      break;
+    default:
+      GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
+      grpc_call_next_op(elem, op);
+  }
+}
+
+static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+  switch (op->type) {
+    case GRPC_ACCEPT_CALL:
+      gpr_log(GPR_ERROR, "Client cannot accept new calls");
+      break;
+    case GRPC_TRANSPORT_CLOSED:
+      gpr_log(GPR_ERROR, "Transport closed");
+      break;
+    default:
+      GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
+      grpc_channel_next_op(elem, op);
+  }
+}
+
+static void init_call_elem(grpc_call_element *elem,
+                           const void *transport_server_data) {}
+
+static void destroy_call_elem(grpc_call_element *elem) {}
+
+static void init_channel_elem(grpc_channel_element *elem,
+                              const grpc_channel_args *args, grpc_mdctx *mdctx,
+                              int is_first, int is_last) {
+  GPR_ASSERT(is_first);
+  GPR_ASSERT(!is_last);
+}
+
+static void destroy_channel_elem(grpc_channel_element *elem) {
+}
+
+const grpc_channel_filter grpc_client_surface_filter = {
+    call_op,              channel_op,
+
+    sizeof(call_data),    init_call_elem,    destroy_call_elem,
+
+    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
+
+    "client",
+};
diff --git a/src/core/surface/client.h b/src/core/surface/client.h
new file mode 100644
index 0000000..eb56727
--- /dev/null
+++ b/src/core/surface/client.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SURFACE_CLIENT_H__
+#define __GRPC_INTERNAL_SURFACE_CLIENT_H__
+
+#include "src/core/channel/channel_stack.h"
+
+extern const grpc_channel_filter grpc_client_surface_filter;
+
+#endif  /* __GRPC_INTERNAL_SURFACE_CLIENT_H__ */
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
new file mode 100644
index 0000000..a7d6115
--- /dev/null
+++ b/src/core/surface/completion_queue.c
@@ -0,0 +1,392 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/surface/completion_queue.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "src/core/eventmanager/em.h"
+#include "src/core/surface/call.h"
+#include "src/core/surface/event_string.h"
+#include "src/core/surface/surface_em.h"
+#include "src/core/surface/surface_trace.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/atm.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+
+#define NUM_TAG_BUCKETS 31
+
+/* A single event: extends grpc_event to form a linked list with a destruction
+   function (on_finish) that is hidden from outside this module */
+typedef struct event {
+  grpc_event base;
+  grpc_event_finish_func on_finish;
+  void *on_finish_user_data;
+  struct event *queue_next;
+  struct event *queue_prev;
+  struct event *bucket_next;
+  struct event *bucket_prev;
+} event;
+
+/* Completion queue structure */
+struct grpc_completion_queue {
+  grpc_em *em;
+  int allow_polling;
+
+  /* When refs drops to zero, we are in shutdown mode, and will be destroyable
+     once all queued events are drained */
+  gpr_refcount refs;
+  /* 0 initially, 1 once we've begun shutting down */
+  int shutdown;
+  /* Head of a linked list of queued events (prev points to the last element) */
+  event *queue;
+  /* Fixed size chained hash table of events for pluck() */
+  event *buckets[NUM_TAG_BUCKETS];
+
+#ifndef NDEBUG
+  /* Debug support: track which operations are in flight at any given time */
+  gpr_atm pending_op_count[GRPC_COMPLETION_DO_NOT_USE];
+#endif
+};
+
+/* Default do-nothing on_finish function */
+static void null_on_finish(void *user_data, grpc_op_error error) {}
+
+grpc_completion_queue *grpc_completion_queue_create() {
+  grpc_completion_queue *cc = gpr_malloc(sizeof(grpc_completion_queue));
+  memset(cc, 0, sizeof(*cc));
+  /* Initial ref is dropped by grpc_completion_queue_shutdown */
+  gpr_ref_init(&cc->refs, 1);
+  cc->em = grpc_surface_em();
+  cc->allow_polling = 1;
+  return cc;
+}
+
+void grpc_completion_queue_dont_poll_test_only(grpc_completion_queue *cc) {
+  cc->allow_polling = 0;
+}
+
+/* Create and append an event to the queue. Returns the event so that its data
+   members can be filled in.
+   Requires cc->em->mu locked. */
+static event *add_locked(grpc_completion_queue *cc, grpc_completion_type type,
+                         void *tag, grpc_call *call,
+                         grpc_event_finish_func on_finish, void *user_data) {
+  event *ev = gpr_malloc(sizeof(event));
+  gpr_intptr bucket = ((gpr_intptr)tag) % NUM_TAG_BUCKETS;
+  GPR_ASSERT(!cc->shutdown);
+  ev->base.type = type;
+  ev->base.tag = tag;
+  ev->base.call = call;
+  ev->on_finish = on_finish ? on_finish : null_on_finish;
+  ev->on_finish_user_data = user_data;
+  if (cc->queue == NULL) {
+    cc->queue = ev->queue_next = ev->queue_prev = ev;
+  } else {
+    ev->queue_next = cc->queue;
+    ev->queue_prev = cc->queue->queue_prev;
+    ev->queue_next->queue_prev = ev->queue_prev->queue_next = ev;
+  }
+  if (cc->buckets[bucket] == NULL) {
+    cc->buckets[bucket] = ev->bucket_next = ev->bucket_prev = ev;
+  } else {
+    ev->bucket_next = cc->buckets[bucket];
+    ev->bucket_prev = cc->buckets[bucket]->bucket_prev;
+    ev->bucket_next->bucket_prev = ev->bucket_prev->bucket_next = ev;
+  }
+  gpr_cv_broadcast(&cc->em->cv);
+  return ev;
+}
+
+void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call,
+                      grpc_completion_type type) {
+  gpr_ref(&cc->refs);
+  if (call) grpc_call_internal_ref(call);
+#ifndef NDEBUG
+  gpr_atm_no_barrier_fetch_add(&cc->pending_op_count[type], 1);
+#endif
+}
+
+/* Signal the end of an operation - if this is the last waiting-to-be-queued
+   event, then enter shutdown mode */
+static void end_op_locked(grpc_completion_queue *cc,
+                          grpc_completion_type type) {
+#ifndef NDEBUG
+  GPR_ASSERT(gpr_atm_full_fetch_add(&cc->pending_op_count[type], -1) > 0);
+#endif
+  if (gpr_unref(&cc->refs)) {
+    GPR_ASSERT(!cc->shutdown);
+    cc->shutdown = 1;
+    gpr_cv_broadcast(&cc->em->cv);
+  }
+}
+
+void grpc_cq_end_read(grpc_completion_queue *cc, void *tag, grpc_call *call,
+                      grpc_event_finish_func on_finish, void *user_data,
+                      grpc_byte_buffer *read) {
+  event *ev;
+  gpr_mu_lock(&cc->em->mu);
+  ev = add_locked(cc, GRPC_READ, tag, call, on_finish, user_data);
+  ev->base.data.read = read;
+  end_op_locked(cc, GRPC_READ);
+  gpr_mu_unlock(&cc->em->mu);
+}
+
+void grpc_cq_end_invoke_accepted(grpc_completion_queue *cc, void *tag,
+                                 grpc_call *call,
+                                 grpc_event_finish_func on_finish,
+                                 void *user_data, grpc_op_error error) {
+  event *ev;
+  gpr_mu_lock(&cc->em->mu);
+  ev = add_locked(cc, GRPC_INVOKE_ACCEPTED, tag, call, on_finish, user_data);
+  ev->base.data.invoke_accepted = error;
+  end_op_locked(cc, GRPC_INVOKE_ACCEPTED);
+  gpr_mu_unlock(&cc->em->mu);
+}
+
+void grpc_cq_end_write_accepted(grpc_completion_queue *cc, void *tag,
+                                grpc_call *call,
+                                grpc_event_finish_func on_finish,
+                                void *user_data, grpc_op_error error) {
+  event *ev;
+  gpr_mu_lock(&cc->em->mu);
+  ev = add_locked(cc, GRPC_WRITE_ACCEPTED, tag, call, on_finish, user_data);
+  ev->base.data.write_accepted = error;
+  end_op_locked(cc, GRPC_WRITE_ACCEPTED);
+  gpr_mu_unlock(&cc->em->mu);
+}
+
+void grpc_cq_end_finish_accepted(grpc_completion_queue *cc, void *tag,
+                                 grpc_call *call,
+                                 grpc_event_finish_func on_finish,
+                                 void *user_data, grpc_op_error error) {
+  event *ev;
+  gpr_mu_lock(&cc->em->mu);
+  ev = add_locked(cc, GRPC_FINISH_ACCEPTED, tag, call, on_finish, user_data);
+  ev->base.data.finish_accepted = error;
+  end_op_locked(cc, GRPC_FINISH_ACCEPTED);
+  gpr_mu_unlock(&cc->em->mu);
+}
+
+void grpc_cq_end_client_metadata_read(grpc_completion_queue *cc, void *tag,
+                                      grpc_call *call,
+                                      grpc_event_finish_func on_finish,
+                                      void *user_data, size_t count,
+                                      grpc_metadata *elements) {
+  event *ev;
+  gpr_mu_lock(&cc->em->mu);
+  ev = add_locked(cc, GRPC_CLIENT_METADATA_READ, tag, call, on_finish,
+                  user_data);
+  ev->base.data.client_metadata_read.count = count;
+  ev->base.data.client_metadata_read.elements = elements;
+  end_op_locked(cc, GRPC_CLIENT_METADATA_READ);
+  gpr_mu_unlock(&cc->em->mu);
+}
+
+void grpc_cq_end_finished(grpc_completion_queue *cc, void *tag, grpc_call *call,
+                          grpc_event_finish_func on_finish, void *user_data,
+                          grpc_status status) {
+  event *ev;
+  gpr_mu_lock(&cc->em->mu);
+  ev = add_locked(cc, GRPC_FINISHED, tag, call, on_finish, user_data);
+  ev->base.data.finished = status;
+  end_op_locked(cc, GRPC_FINISHED);
+  gpr_mu_unlock(&cc->em->mu);
+}
+
+void grpc_cq_end_new_rpc(grpc_completion_queue *cc, void *tag, grpc_call *call,
+                         grpc_event_finish_func on_finish, void *user_data,
+                         const char *method, const char *host,
+                         gpr_timespec deadline, size_t metadata_count,
+                         grpc_metadata *metadata_elements) {
+  event *ev;
+  gpr_mu_lock(&cc->em->mu);
+  ev = add_locked(cc, GRPC_SERVER_RPC_NEW, tag, call, on_finish, user_data);
+  ev->base.data.server_rpc_new.method = method;
+  ev->base.data.server_rpc_new.host = host;
+  ev->base.data.server_rpc_new.deadline = deadline;
+  ev->base.data.server_rpc_new.metadata_count = metadata_count;
+  ev->base.data.server_rpc_new.metadata_elements = metadata_elements;
+  end_op_locked(cc, GRPC_SERVER_RPC_NEW);
+  gpr_mu_unlock(&cc->em->mu);
+}
+
+/* Create a GRPC_QUEUE_SHUTDOWN event without queuing it anywhere */
+static event *create_shutdown_event() {
+  event *ev = gpr_malloc(sizeof(event));
+  ev->base.type = GRPC_QUEUE_SHUTDOWN;
+  ev->base.call = NULL;
+  ev->base.tag = NULL;
+  ev->on_finish = null_on_finish;
+  return ev;
+}
+
+grpc_event *grpc_completion_queue_next(grpc_completion_queue *cc,
+                                       gpr_timespec deadline) {
+  event *ev = NULL;
+
+  gpr_mu_lock(&cc->em->mu);
+  for (;;) {
+    if (cc->queue != NULL) {
+      gpr_intptr bucket;
+      ev = cc->queue;
+      bucket = ((gpr_intptr)ev->base.tag) % NUM_TAG_BUCKETS;
+      cc->queue = ev->queue_next;
+      ev->queue_next->queue_prev = ev->queue_prev;
+      ev->queue_prev->queue_next = ev->queue_next;
+      ev->bucket_next->bucket_prev = ev->bucket_prev;
+      ev->bucket_prev->bucket_next = ev->bucket_next;
+      if (ev == cc->buckets[bucket]) {
+        cc->buckets[bucket] = ev->bucket_next;
+        if (ev == cc->buckets[bucket]) {
+          cc->buckets[bucket] = NULL;
+        }
+      }
+      if (cc->queue == ev) {
+        cc->queue = NULL;
+      }
+      break;
+    }
+    if (cc->shutdown) {
+      ev = create_shutdown_event();
+      break;
+    }
+    if (cc->allow_polling && grpc_em_work(cc->em, deadline)) {
+      continue;
+    }
+    if (gpr_cv_wait(&cc->em->cv, &cc->em->mu, deadline)) {
+      gpr_mu_unlock(&cc->em->mu);
+      return NULL;
+    }
+  }
+  gpr_mu_unlock(&cc->em->mu);
+  GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ev->base);
+  return &ev->base;
+}
+
+static event *pluck_event(grpc_completion_queue *cc, void *tag) {
+  gpr_intptr bucket = ((gpr_intptr)tag) % NUM_TAG_BUCKETS;
+  event *ev = cc->buckets[bucket];
+  if (ev == NULL) return NULL;
+  do {
+    if (ev->base.tag == tag) {
+      ev->queue_next->queue_prev = ev->queue_prev;
+      ev->queue_prev->queue_next = ev->queue_next;
+      ev->bucket_next->bucket_prev = ev->bucket_prev;
+      ev->bucket_prev->bucket_next = ev->bucket_next;
+      if (ev == cc->buckets[bucket]) {
+        cc->buckets[bucket] = ev->bucket_next;
+        if (ev == cc->buckets[bucket]) {
+          cc->buckets[bucket] = NULL;
+        }
+      }
+      if (cc->queue == ev) {
+        cc->queue = ev->queue_next;
+        if (cc->queue == ev) {
+          cc->queue = NULL;
+        }
+      }
+      return ev;
+    }
+    ev = ev->bucket_next;
+  } while (ev != cc->buckets[bucket]);
+  return NULL;
+}
+
+grpc_event *grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
+                                        gpr_timespec deadline) {
+  event *ev = NULL;
+
+  gpr_mu_lock(&cc->em->mu);
+  for (;;) {
+    if ((ev = pluck_event(cc, tag))) {
+      break;
+    }
+    if (cc->shutdown) {
+      ev = create_shutdown_event();
+      break;
+    }
+    if (cc->allow_polling && grpc_em_work(cc->em, deadline)) {
+      continue;
+    }
+    if (gpr_cv_wait(&cc->em->cv, &cc->em->mu, deadline)) {
+      gpr_mu_unlock(&cc->em->mu);
+      return NULL;
+    }
+  }
+  gpr_mu_unlock(&cc->em->mu);
+  GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ev->base);
+  return &ev->base;
+}
+
+/* Shutdown simply drops a ref that we reserved at creation time; if we drop
+   to zero here, then enter shutdown mode and wake up any waiters */
+void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
+  if (gpr_unref(&cc->refs)) {
+    gpr_mu_lock(&cc->em->mu);
+    GPR_ASSERT(!cc->shutdown);
+    cc->shutdown = 1;
+    gpr_cv_broadcast(&cc->em->cv);
+    gpr_mu_unlock(&cc->em->mu);
+  }
+}
+
+void grpc_completion_queue_destroy(grpc_completion_queue *cc) {
+  GPR_ASSERT(cc->queue == NULL);
+  gpr_free(cc);
+}
+
+void grpc_event_finish(grpc_event *base) {
+  event *ev = (event *)base;
+  ev->on_finish(ev->on_finish_user_data, GRPC_OP_OK);
+  if (ev->base.call) {
+    grpc_call_internal_unref(ev->base.call);
+  }
+  gpr_free(ev);
+}
+
+void grpc_cq_dump_pending_ops(grpc_completion_queue *cc) {
+#ifndef NDEBUG
+  char tmp[256];
+  char *p = tmp;
+  int i;
+
+  for (i = 0; i < GRPC_COMPLETION_DO_NOT_USE; i++) {
+    p += sprintf(p, " %d", (int)cc->pending_op_count[i]);
+  }
+
+  gpr_log(GPR_INFO, "pending ops:%s", tmp);
+#endif
+}
diff --git a/src/core/surface/completion_queue.h b/src/core/surface/completion_queue.h
new file mode 100644
index 0000000..0fe5765
--- /dev/null
+++ b/src/core/surface/completion_queue.h
@@ -0,0 +1,102 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SURFACE_COMPLETION_QUEUE_H__
+#define __GRPC_INTERNAL_SURFACE_COMPLETION_QUEUE_H__
+
+/* Internal API for completion channels */
+
+#include <grpc/grpc.h>
+
+/* A finish func is executed whenever the event consumer calls
+   grpc_event_finish */
+typedef void (*grpc_event_finish_func)(void *user_data, grpc_op_error error);
+
+/* Flag that an operation is beginning: the completion channel will not finish
+   shutdown until a corrensponding grpc_cq_end_* call is made */
+void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call,
+                      grpc_completion_type type);
+
+/* grpc_cq_end_* functions pair with a grpc_cq_begin_op
+
+   grpc_cq_end_* common arguments:
+   cc        - the completion channel to queue on
+   tag       - the user supplied operation tag
+   on_finish - grpc_event_finish_func that is called during grpc_event_finish
+               can be NULL to not get a callback
+   user_data - user_data parameter to be passed to on_finish
+
+   Other parameters match the data member of grpc_event */
+
+/* Queue a GRPC_READ operation */
+void grpc_cq_end_read(grpc_completion_queue *cc, void *tag, grpc_call *call,
+                      grpc_event_finish_func on_finish, void *user_data,
+                      grpc_byte_buffer *read);
+/* Queue a GRPC_INVOKE_ACCEPTED operation */
+void grpc_cq_end_invoke_accepted(grpc_completion_queue *cc, void *tag,
+                                 grpc_call *call,
+                                 grpc_event_finish_func on_finish,
+                                 void *user_data, grpc_op_error error);
+/* Queue a GRPC_WRITE_ACCEPTED operation */
+void grpc_cq_end_write_accepted(grpc_completion_queue *cc, void *tag,
+                                grpc_call *call,
+                                grpc_event_finish_func on_finish,
+                                void *user_data, grpc_op_error error);
+/* Queue a GRPC_FINISH_ACCEPTED operation */
+void grpc_cq_end_finish_accepted(grpc_completion_queue *cc, void *tag,
+                                 grpc_call *call,
+                                 grpc_event_finish_func on_finish,
+                                 void *user_data, grpc_op_error error);
+/* Queue a GRPC_CLIENT_METADATA_READ operation */
+void grpc_cq_end_client_metadata_read(grpc_completion_queue *cc, void *tag,
+                                      grpc_call *call,
+                                      grpc_event_finish_func on_finish,
+                                      void *user_data, size_t count,
+                                      grpc_metadata *elements);
+
+void grpc_cq_end_finished(grpc_completion_queue *cc, void *tag, grpc_call *call,
+                          grpc_event_finish_func on_finish, void *user_data,
+                          grpc_status status);
+
+void grpc_cq_end_new_rpc(grpc_completion_queue *cc, void *tag, grpc_call *call,
+                         grpc_event_finish_func on_finish, void *user_data,
+                         const char *method, const char *host,
+                         gpr_timespec deadline, size_t metadata_count,
+                         grpc_metadata *metadata_elements);
+
+/* disable polling for some tests */
+void grpc_completion_queue_dont_poll_test_only(grpc_completion_queue *cc);
+
+void grpc_cq_dump_pending_ops(grpc_completion_queue *cc);
+
+#endif  /* __GRPC_INTERNAL_SURFACE_COMPLETION_QUEUE_H__ */
diff --git a/src/core/surface/event_string.c b/src/core/surface/event_string.c
new file mode 100644
index 0000000..0a6a81d
--- /dev/null
+++ b/src/core/surface/event_string.c
@@ -0,0 +1,119 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/surface/event_string.h"
+
+#include <stdio.h>
+
+#include <grpc/support/string.h>
+#include <grpc/byte_buffer.h>
+
+static size_t addhdr(char *p, grpc_event *ev) {
+  return sprintf(p, "tag:%p call:%p", ev->tag, (void *)ev->call);
+}
+
+static const char *errstr(grpc_op_error err) {
+  switch (err) {
+    case GRPC_OP_OK:
+      return "OK";
+    case GRPC_OP_ERROR:
+      return "ERROR";
+  }
+  return "UNKNOWN_UNKNOWN";
+}
+
+static size_t adderr(char *p, grpc_op_error err) {
+  return sprintf(p, " err=%s", errstr(err));
+}
+
+char *grpc_event_string(grpc_event *ev) {
+  char buffer[1024];
+  char *p = buffer;
+
+  if (ev == NULL) return gpr_strdup("null");
+
+  switch (ev->type) {
+    case GRPC_QUEUE_SHUTDOWN:
+      p += sprintf(p, "QUEUE_SHUTDOWN");
+      break;
+    case GRPC_READ:
+      p += sprintf(p, "READ: ");
+      p += addhdr(p, ev);
+      if (ev->data.read) {
+        p += sprintf(p, " %d bytes",
+                     (int)grpc_byte_buffer_length(ev->data.read));
+      } else {
+        p += sprintf(p, " end-of-stream");
+      }
+      break;
+    case GRPC_INVOKE_ACCEPTED:
+      p += sprintf(p, "INVOKE_ACCEPTED: ");
+      p += addhdr(p, ev);
+      p += adderr(p, ev->data.invoke_accepted);
+      break;
+    case GRPC_WRITE_ACCEPTED:
+      p += sprintf(p, "WRITE_ACCEPTED: ");
+      p += addhdr(p, ev);
+      p += adderr(p, ev->data.write_accepted);
+      break;
+    case GRPC_FINISH_ACCEPTED:
+      p += sprintf(p, "FINISH_ACCEPTED: ");
+      p += addhdr(p, ev);
+      p += adderr(p, ev->data.write_accepted);
+      break;
+    case GRPC_CLIENT_METADATA_READ:
+      p += sprintf(p, "CLIENT_METADATA_READ: ");
+      p += addhdr(p, ev);
+      p += sprintf(p, " %d elements", (int)ev->data.client_metadata_read.count);
+      break;
+    case GRPC_FINISHED:
+      p += sprintf(p, "FINISHED: ");
+      p += addhdr(p, ev);
+      p += sprintf(p, " status_code=%d details='%s'", ev->data.finished.code,
+                   ev->data.finished.details);
+      break;
+    case GRPC_SERVER_RPC_NEW:
+      p += sprintf(p, "SERVER_RPC_NEW: ");
+      p += addhdr(p, ev);
+      p += sprintf(p, " method='%s' host='%s' %d metadata elements",
+                   ev->data.server_rpc_new.method, ev->data.server_rpc_new.host,
+                   (int)ev->data.server_rpc_new.metadata_count);
+      break;
+    case GRPC_COMPLETION_DO_NOT_USE:
+      p += sprintf(p, "DO_NOT_USE (this is a bug)");
+      p += addhdr(p, ev);
+      break;
+  }
+
+  return gpr_strdup(buffer);
+}
diff --git a/src/core/surface/event_string.h b/src/core/surface/event_string.h
new file mode 100644
index 0000000..30b693e
--- /dev/null
+++ b/src/core/surface/event_string.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SURFACE_EVENT_STRING_H__
+#define __GRPC_INTERNAL_SURFACE_EVENT_STRING_H__
+
+#include <grpc/grpc.h>
+
+/* Returns a string describing an event. Must be later freed with gpr_free() */
+char *grpc_event_string(grpc_event *ev);
+
+#endif  /* __GRPC_INTERNAL_SURFACE_EVENT_STRING_H__ */
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
new file mode 100644
index 0000000..92c0ac8
--- /dev/null
+++ b/src/core/surface/init.c
@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+#include "src/core/statistics/census_interface.h"
+#include "src/core/surface/surface_em.h"
+
+void grpc_init() {
+  grpc_surface_em_init();
+  census_init();
+}
+
+void grpc_shutdown() {
+  grpc_surface_em_shutdown();
+  census_shutdown();
+}
diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c
new file mode 100644
index 0000000..18921c4
--- /dev/null
+++ b/src/core/surface/lame_client.c
@@ -0,0 +1,94 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/surface/lame_client.h"
+
+#include "src/core/channel/channel_stack.h"
+#include "src/core/surface/channel.h"
+#include "src/core/surface/call.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+
+typedef struct { void *unused; } call_data;
+
+typedef struct { void *unused; } channel_data;
+
+static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+
+  switch (op->type) {
+    case GRPC_SEND_START:
+      grpc_call_recv_finish(elem, 1);
+      break;
+    case GRPC_SEND_METADATA:
+      grpc_mdelem_unref(op->data.metadata);
+      break;
+    default:
+      break;
+  }
+
+  op->done_cb(op->user_data, GRPC_OP_ERROR);
+}
+
+static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {}
+
+static void init_call_elem(grpc_call_element *elem,
+                           const void *transport_server_data) {}
+
+static void destroy_call_elem(grpc_call_element *elem) {}
+
+static void init_channel_elem(grpc_channel_element *elem,
+                              const grpc_channel_args *args, grpc_mdctx *mdctx,
+                              int is_first, int is_last) {
+  GPR_ASSERT(is_first);
+  GPR_ASSERT(is_last);
+}
+
+static void destroy_channel_elem(grpc_channel_element *elem) {}
+
+static const grpc_channel_filter lame_filter = {
+    call_op, channel_op,
+
+    sizeof(call_data), init_call_elem, destroy_call_elem,
+
+    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
+
+    "lame-client",
+};
+
+grpc_channel *grpc_lame_client_channel_create() {
+  static const grpc_channel_filter *filters[] = {&lame_filter};
+  return grpc_channel_create_from_filters(filters, 1, NULL, grpc_mdctx_create(),
+                                          1);
+}
diff --git a/src/core/surface/lame_client.h b/src/core/surface/lame_client.h
new file mode 100644
index 0000000..74b9707
--- /dev/null
+++ b/src/core/surface/lame_client.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SURFACE_LAME_CLIENT_H_
+#define __GRPC_INTERNAL_SURFACE_LAME_CLIENT_H_
+
+#include <grpc/grpc.h>
+
+/* Create a lame client: this client fails every operation attempted on it. */
+grpc_channel *grpc_lame_client_channel_create();
+
+#endif /* __GRPC_INTERNAL_SURFACE_LAME_CLIENT_H_ */
diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
new file mode 100644
index 0000000..f330b83
--- /dev/null
+++ b/src/core/surface/secure_channel_create.c
@@ -0,0 +1,243 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/core/channel/census_filter.h"
+#include "src/core/channel/channel_args.h"
+#include "src/core/channel/client_channel.h"
+#include "src/core/channel/client_setup.h"
+#include "src/core/channel/connected_channel.h"
+#include "src/core/channel/http_client_filter.h"
+#include "src/core/channel/http_filter.h"
+#include "src/core/endpoint/resolve_address.h"
+#include "src/core/endpoint/tcp.h"
+#include "src/core/endpoint/tcp_client.h"
+#include "src/core/security/auth.h"
+#include "src/core/security/security_context.h"
+#include "src/core/security/secure_transport_setup.h"
+#include "src/core/surface/channel.h"
+#include "src/core/surface/client.h"
+#include "src/core/surface/surface_em.h"
+#include "src/core/transport/chttp2_transport.h"
+#include <grpc/grpc_security.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/useful.h>
+#include "src/core/tsi/transport_security_interface.h"
+
+typedef struct setup setup;
+
+/* A single setup request (started via initiate) */
+typedef struct {
+  grpc_client_setup_request *cs_request;
+  setup *setup;
+  /* Resolved addresses, or null if resolution not yet completed. */
+  grpc_resolved_addresses *resolved;
+  /* which address in resolved should we pick for the next connection attempt */
+  size_t resolved_index;
+} request;
+
+struct setup {
+  grpc_channel_security_context *security_context;
+  const char *target;
+  grpc_transport_setup_callback setup_callback;
+  void *setup_user_data;
+  grpc_em *em;
+};
+
+static int maybe_try_next_resolved(request *r);
+
+static void done(request *r, int was_successful) {
+  grpc_client_setup_request_finish(r->cs_request, was_successful);
+  if (r->resolved) {
+    grpc_resolved_addresses_destroy(r->resolved);
+  }
+  gpr_free(r);
+}
+
+static void on_secure_transport_setup_done(void *rp,
+                                           grpc_security_status status,
+                                           grpc_endpoint *secure_endpoint) {
+  request *r = rp;
+  if (status != GRPC_SECURITY_OK) {
+    gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status);
+    done(r, 0);
+  } else {
+    grpc_create_chttp2_transport(
+        r->setup->setup_callback, r->setup->setup_user_data,
+        grpc_client_setup_get_channel_args(r->cs_request), secure_endpoint,
+        NULL, 0, grpc_client_setup_get_mdctx(r->cs_request), 1);
+    done(r, 1);
+  }
+}
+
+/* connection callback: tcp is either valid, or null on error */
+static void on_connect(void *rp, grpc_endpoint *tcp) {
+  request *r = rp;
+
+  if (!grpc_client_setup_request_should_continue(r->cs_request)) {
+    if (tcp) {
+      grpc_endpoint_shutdown(tcp);
+      grpc_endpoint_destroy(tcp);
+    }
+    done(r, 0);
+    return;
+  }
+
+  if (!tcp) {
+    if (!maybe_try_next_resolved(r)) {
+      done(r, 0);
+      return;
+    } else {
+      return;
+    }
+  } else {
+    grpc_setup_secure_transport(&r->setup->security_context->base, tcp,
+                                on_secure_transport_setup_done, r);
+  }
+}
+
+/* attempt to connect to the next available resolved address */
+static int maybe_try_next_resolved(request *r) {
+  grpc_resolved_address *addr;
+  if (!r->resolved) return 0;
+  if (r->resolved_index == r->resolved->naddrs) return 0;
+  addr = &r->resolved->addrs[r->resolved_index++];
+  grpc_tcp_client_connect(on_connect, r, r->setup->em,
+                          (struct sockaddr *)&addr->addr, addr->len,
+                          grpc_client_setup_request_deadline(r->cs_request));
+  return 1;
+}
+
+/* callback for when our target address has been resolved */
+static void on_resolved(void *rp, grpc_resolved_addresses *resolved) {
+  request *r = rp;
+
+  /* if we're not still the active request, abort */
+  if (!grpc_client_setup_request_should_continue(r->cs_request)) {
+    if (resolved) {
+      grpc_resolved_addresses_destroy(resolved);
+    }
+    done(r, 0);
+    return;
+  }
+
+  if (!resolved) {
+    done(r, 0);
+    return;
+  } else {
+    r->resolved = resolved;
+    r->resolved_index = 0;
+    if (!maybe_try_next_resolved(r)) {
+      done(r, 0);
+    }
+  }
+}
+
+static void initiate_setup(void *sp, grpc_client_setup_request *cs_request) {
+  request *r = gpr_malloc(sizeof(request));
+  r->setup = sp;
+  r->cs_request = cs_request;
+  r->resolved = NULL;
+  r->resolved_index = 0;
+  /* TODO(klempner): Make grpc_resolve_address respect deadline */
+  grpc_resolve_address(r->setup->target, "https", on_resolved, r);
+}
+
+static void done_setup(void *sp) {
+  setup *s = sp;
+  gpr_free((void *)s->target);
+  grpc_security_context_unref(&s->security_context->base);
+  gpr_free(s);
+}
+
+static grpc_transport_setup_result complete_setup(void *channel_stack,
+                                                  grpc_transport *transport,
+                                                  grpc_mdctx *mdctx) {
+  static grpc_channel_filter const *extra_filters[] = {&grpc_http_client_filter,
+                                                       &grpc_http_filter};
+  return grpc_client_channel_transport_setup_complete(
+      channel_stack, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters),
+      mdctx);
+}
+
+/* Create a secure client channel:
+   Asynchronously: - resolve target
+                   - connect to it (trying alternatives as presented)
+                   - perform handshakes */
+grpc_channel *grpc_secure_channel_create_internal(
+    const char *target, const grpc_channel_args *args,
+    grpc_channel_security_context *context) {
+  setup *s;
+  grpc_channel *channel;
+  grpc_arg context_arg;
+  grpc_channel_args *args_copy;
+  grpc_mdctx *mdctx = grpc_mdctx_create();
+#define MAX_FILTERS 4
+  const grpc_channel_filter *filters[MAX_FILTERS];
+  int n = 0;
+  if (grpc_find_security_context_in_args(args) != NULL) {
+    gpr_log(GPR_ERROR, "Cannot set security context in channel args.");
+  }
+
+  s = gpr_malloc(sizeof(setup));
+  context_arg = grpc_security_context_to_arg(&context->base);
+  args_copy = grpc_channel_args_copy_and_add(args, &context_arg);
+  filters[n++] = &grpc_client_surface_filter;
+  if (grpc_channel_args_is_census_enabled(args)) {
+    filters[n++] = &grpc_client_census_filter;
+  }
+  filters[n++] = &grpc_client_auth_filter;
+  filters[n++] = &grpc_client_channel_filter;
+  GPR_ASSERT(n <= MAX_FILTERS);
+  channel = grpc_channel_create_from_filters(filters, n, args_copy, mdctx, 1);
+  grpc_channel_args_destroy(args_copy);
+
+  s->target = gpr_strdup(target);
+  s->em = grpc_surface_em();
+  s->setup_callback = complete_setup;
+  s->setup_user_data = grpc_channel_get_channel_stack(channel);
+  s->security_context =
+      (grpc_channel_security_context *)grpc_security_context_ref(
+          &context->base);
+  grpc_client_setup_create_and_attach(grpc_channel_get_channel_stack(channel),
+                                      args, mdctx, initiate_setup, done_setup,
+                                      s, s->em);
+  return channel;
+}
diff --git a/src/core/surface/secure_server_create.c b/src/core/surface/secure_server_create.c
new file mode 100644
index 0000000..bf0f623
--- /dev/null
+++ b/src/core/surface/secure_server_create.c
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+
+#include "src/core/channel/channel_args.h"
+#include "src/core/security/security_context.h"
+#include "src/core/surface/completion_queue.h"
+#include "src/core/surface/server.h"
+#include <grpc/support/log.h>
+
+grpc_server *grpc_secure_server_create_internal(
+    grpc_completion_queue *cq, const grpc_channel_args *args,
+    grpc_security_context *context) {
+  grpc_arg context_arg;
+  grpc_channel_args *args_copy;
+  grpc_server *server;
+  if (grpc_find_security_context_in_args(args) != NULL) {
+    gpr_log(GPR_ERROR, "Cannot set security context in channel args.");
+  }
+
+  context_arg = grpc_security_context_to_arg(context);
+  args_copy = grpc_channel_args_copy_and_add(args, &context_arg);
+  server = grpc_server_create_from_filters(cq, NULL, 0, args_copy);
+  grpc_channel_args_destroy(args_copy);
+  return server;
+}
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
new file mode 100644
index 0000000..99d66ff
--- /dev/null
+++ b/src/core/surface/server.c
@@ -0,0 +1,609 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/surface/server.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/core/channel/census_filter.h"
+#include "src/core/channel/channel_args.h"
+#include "src/core/channel/connected_channel.h"
+#include "src/core/surface/call.h"
+#include "src/core/surface/channel.h"
+#include "src/core/surface/completion_queue.h"
+#include "src/core/surface/surface_em.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+#include <grpc/support/useful.h>
+
+typedef enum { PENDING_START, ALL_CALLS, CALL_LIST_COUNT } call_list;
+
+typedef struct listener {
+  void *arg;
+  void (*start)(grpc_server *server, void *arg);
+  void (*destroy)(grpc_server *server, void *arg);
+  struct listener *next;
+} listener;
+
+typedef struct call_data call_data;
+typedef struct channel_data channel_data;
+
+struct channel_data {
+  grpc_server *server;
+  grpc_channel *channel;
+  /* linked list of all channels on a server */
+  channel_data *next;
+  channel_data *prev;
+};
+
+struct grpc_server {
+  size_t channel_filter_count;
+  const grpc_channel_filter **channel_filters;
+  grpc_channel_args *channel_args;
+  grpc_completion_queue *cq;
+  grpc_em *em;
+
+  gpr_mu mu;
+
+  void **tags;
+  size_t ntags;
+  size_t tag_cap;
+
+  gpr_uint8 shutdown;
+
+  call_data *lists[CALL_LIST_COUNT];
+  channel_data root_channel_data;
+
+  listener *listeners;
+  gpr_refcount internal_refcount;
+};
+
+typedef struct {
+  call_data *next;
+  call_data *prev;
+} call_link;
+
+typedef enum {
+  /* waiting for metadata */
+  NOT_STARTED,
+  /* inital metadata read, not flow controlled in yet */
+  PENDING,
+  /* flow controlled in, on completion queue */
+  ACTIVATED,
+  /* cancelled before being queued */
+  ZOMBIED
+} call_state;
+
+struct call_data {
+  grpc_call *call;
+
+  call_state state;
+  gpr_timespec deadline;
+
+  gpr_uint8 included[CALL_LIST_COUNT];
+  call_link links[CALL_LIST_COUNT];
+};
+
+#define SERVER_FROM_CALL_ELEM(elem) \
+  (((channel_data *)(elem)->channel_data)->server)
+
+static void do_nothing(void *unused, grpc_op_error ignored) {}
+
+static int call_list_join(grpc_server *server, call_data *call,
+                          call_list list) {
+  if (call->included[list]) return 0;
+  call->included[list] = 1;
+  if (!server->lists[list]) {
+    server->lists[list] = call;
+    call->links[list].next = call->links[list].prev = call;
+  } else {
+    call->links[list].next = server->lists[list];
+    call->links[list].prev = server->lists[list]->links[list].prev;
+    call->links[list].next->links[list].prev =
+        call->links[list].prev->links[list].next = call;
+  }
+  return 1;
+}
+
+static call_data *call_list_remove_head(grpc_server *server, call_list list) {
+  call_data *out = server->lists[list];
+  if (out) {
+    out->included[list] = 0;
+    if (out->links[list].next == out) {
+      server->lists[list] = NULL;
+    } else {
+      server->lists[list] = out->links[list].next;
+      out->links[list].next->links[list].prev = out->links[list].prev;
+      out->links[list].prev->links[list].next = out->links[list].next;
+    }
+  }
+  return out;
+}
+
+static int call_list_remove(grpc_server *server, call_data *call,
+                            call_list list) {
+  if (!call->included[list]) return 0;
+  call->included[list] = 0;
+  if (server->lists[list] == call) {
+    server->lists[list] = call->links[list].next;
+    if (server->lists[list] == call) {
+      server->lists[list] = NULL;
+      return 1;
+    }
+  }
+  GPR_ASSERT(server->lists[list] != call);
+  call->links[list].next->links[list].prev = call->links[list].prev;
+  call->links[list].prev->links[list].next = call->links[list].next;
+  return 1;
+}
+
+static void server_ref(grpc_server *server) {
+  gpr_ref(&server->internal_refcount);
+}
+
+static void server_unref(grpc_server *server) {
+  if (gpr_unref(&server->internal_refcount)) {
+    grpc_channel_args_destroy(server->channel_args);
+    gpr_mu_destroy(&server->mu);
+    gpr_free(server->channel_filters);
+    gpr_free(server->tags);
+    gpr_free(server);
+  }
+}
+
+static int is_channel_orphaned(channel_data *chand) {
+  return chand->next == chand;
+}
+
+static void orphan_channel(channel_data *chand) {
+  chand->next->prev = chand->prev;
+  chand->prev->next = chand->next;
+  chand->next = chand->prev = chand;
+}
+
+static void finish_destroy_channel(void *cd, grpc_em_cb_status status) {
+  channel_data *chand = cd;
+  grpc_server *server = chand->server;
+  /*gpr_log(GPR_INFO, "destroy channel %p", chand->channel);*/
+  grpc_channel_destroy(chand->channel);
+  server_unref(server);
+}
+
+static void destroy_channel(channel_data *chand) {
+  if (is_channel_orphaned(chand)) return;
+  GPR_ASSERT(chand->server != NULL);
+  orphan_channel(chand);
+  server_ref(chand->server);
+  grpc_em_add_callback(chand->server->em, finish_destroy_channel, chand);
+}
+
+static void queue_new_rpc(grpc_server *server, call_data *calld, void *tag) {
+  grpc_call *call = calld->call;
+  grpc_metadata_buffer *mdbuf = grpc_call_get_metadata_buffer(call);
+  size_t count = grpc_metadata_buffer_count(mdbuf);
+  grpc_metadata *elements = grpc_metadata_buffer_extract_elements(mdbuf);
+  const char *host = NULL;
+  const char *method = NULL;
+  size_t i;
+  grpc_metadata status_md;
+
+  for (i = 0; i < count; i++) {
+    if (0 == strcmp(elements[i].key, ":authority")) {
+      host = elements[i].value;
+    } else if (0 == strcmp(elements[i].key, ":path")) {
+      method = elements[i].value;
+    }
+  }
+
+  status_md.key = ":status";
+  status_md.value = "200";
+  status_md.value_length = 3;
+  grpc_call_add_metadata(call, &status_md, GRPC_WRITE_BUFFER_HINT);
+
+  grpc_call_internal_ref(call);
+  grpc_cq_end_new_rpc(server->cq, tag, call,
+                      grpc_metadata_buffer_cleanup_elements, elements, method,
+                      host, calld->deadline, count, elements);
+}
+
+static void start_new_rpc(grpc_call_element *elem) {
+  channel_data *chand = elem->channel_data;
+  call_data *calld = elem->call_data;
+  grpc_server *server = chand->server;
+
+  gpr_mu_lock(&server->mu);
+  if (server->ntags) {
+    calld->state = ACTIVATED;
+    queue_new_rpc(server, calld, server->tags[--server->ntags]);
+  } else {
+    calld->state = PENDING;
+    call_list_join(server, calld, PENDING_START);
+  }
+  gpr_mu_unlock(&server->mu);
+}
+
+static void kill_zombie(void *elem, grpc_em_cb_status status) {
+  grpc_call_destroy(grpc_call_from_top_element(elem));
+}
+
+static void finish_rpc(grpc_call_element *elem, int is_full_close) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  gpr_mu_lock(&chand->server->mu);
+  switch (calld->state) {
+    case ACTIVATED:
+      grpc_call_recv_finish(elem, is_full_close);
+      break;
+    case PENDING:
+      if (!is_full_close) {
+        grpc_call_recv_finish(elem, is_full_close);
+        break;
+      }
+      call_list_remove(chand->server, calld, PENDING_START);
+    /* fallthrough intended */
+    case NOT_STARTED:
+      calld->state = ZOMBIED;
+      grpc_em_add_callback(chand->server->em, kill_zombie, elem);
+      break;
+    case ZOMBIED:
+      break;
+  }
+  gpr_mu_unlock(&chand->server->mu);
+}
+
+static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+  switch (op->type) {
+    case GRPC_RECV_METADATA:
+      grpc_call_recv_metadata(elem, op);
+      break;
+    case GRPC_RECV_END_OF_INITIAL_METADATA:
+      start_new_rpc(elem);
+      break;
+    case GRPC_RECV_MESSAGE:
+      grpc_call_recv_message(elem, op->data.message, op->done_cb,
+                             op->user_data);
+      break;
+    case GRPC_RECV_HALF_CLOSE:
+      finish_rpc(elem, 0);
+      break;
+    case GRPC_RECV_FINISH:
+      finish_rpc(elem, 1);
+      break;
+    case GRPC_RECV_DEADLINE:
+      grpc_call_set_deadline(elem, op->data.deadline);
+      ((call_data *)elem->call_data)->deadline = op->data.deadline;
+      break;
+    default:
+      GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
+      grpc_call_next_op(elem, op);
+      break;
+  }
+}
+
+static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+  channel_data *chand = elem->channel_data;
+
+  switch (op->type) {
+    case GRPC_ACCEPT_CALL:
+      /* create a call */
+      grpc_call_create(chand->channel,
+                       op->data.accept_call.transport_server_data);
+      break;
+    case GRPC_TRANSPORT_CLOSED:
+      /* if the transport is closed for a server channel, we destroy the
+         channel */
+      gpr_mu_lock(&chand->server->mu);
+      server_ref(chand->server);
+      destroy_channel(chand);
+      gpr_mu_unlock(&chand->server->mu);
+      server_unref(chand->server);
+      break;
+    default:
+      GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
+      grpc_channel_next_op(elem, op);
+      break;
+  }
+}
+
+static void finish_shutdown_channel(void *cd, grpc_em_cb_status status) {
+  channel_data *chand = cd;
+  grpc_channel_op op;
+  op.type = GRPC_CHANNEL_SHUTDOWN;
+  op.dir = GRPC_CALL_DOWN;
+  channel_op(grpc_channel_stack_element(
+                 grpc_channel_get_channel_stack(chand->channel), 0),
+             &op);
+  grpc_channel_internal_unref(chand->channel);
+}
+
+static void shutdown_channel(channel_data *chand) {
+  grpc_channel_internal_ref(chand->channel);
+  grpc_em_add_callback(chand->server->em, finish_shutdown_channel, chand);
+}
+
+static void init_call_elem(grpc_call_element *elem,
+                           const void *server_transport_data) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  memset(calld, 0, sizeof(call_data));
+  calld->deadline = gpr_inf_future;
+  calld->call = grpc_call_from_top_element(elem);
+
+  gpr_mu_lock(&chand->server->mu);
+  call_list_join(chand->server, calld, ALL_CALLS);
+  gpr_mu_unlock(&chand->server->mu);
+
+  server_ref(chand->server);
+}
+
+static void destroy_call_elem(grpc_call_element *elem) {
+  channel_data *chand = elem->channel_data;
+  int i;
+
+  gpr_mu_lock(&chand->server->mu);
+  for (i = 0; i < CALL_LIST_COUNT; i++) {
+    call_list_remove(chand->server, elem->call_data, i);
+  }
+  gpr_mu_unlock(&chand->server->mu);
+
+  server_unref(chand->server);
+}
+
+static void init_channel_elem(grpc_channel_element *elem,
+                              const grpc_channel_args *args,
+                              grpc_mdctx *metadata_context, int is_first,
+                              int is_last) {
+  channel_data *chand = elem->channel_data;
+  GPR_ASSERT(is_first);
+  GPR_ASSERT(!is_last);
+  chand->server = NULL;
+  chand->channel = NULL;
+  chand->next = chand->prev = chand;
+}
+
+static void destroy_channel_elem(grpc_channel_element *elem) {
+  channel_data *chand = elem->channel_data;
+  if (chand->server) {
+    gpr_mu_lock(&chand->server->mu);
+    chand->next->prev = chand->prev;
+    chand->prev->next = chand->next;
+    chand->next = chand->prev = chand;
+    gpr_mu_unlock(&chand->server->mu);
+    server_unref(chand->server);
+  }
+}
+
+static const grpc_channel_filter server_surface_filter = {
+    call_op,              channel_op,
+
+    sizeof(call_data),    init_call_elem,    destroy_call_elem,
+
+    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
+
+    "server",
+};
+
+static void early_terminate_requested_calls(grpc_completion_queue *cq,
+                                            void **tags, size_t ntags) {
+  size_t i;
+
+  for (i = 0; i < ntags; i++) {
+    grpc_cq_end_new_rpc(cq, tags[i], NULL, do_nothing, NULL, NULL, NULL,
+                        gpr_inf_past, 0, NULL);
+  }
+}
+
+grpc_server *grpc_server_create_from_filters(grpc_completion_queue *cq,
+                                             grpc_channel_filter **filters,
+                                             size_t filter_count,
+                                             const grpc_channel_args *args) {
+  size_t i;
+  int census_enabled = grpc_channel_args_is_census_enabled(args);
+
+  grpc_server *server = gpr_malloc(sizeof(grpc_server));
+  memset(server, 0, sizeof(grpc_server));
+
+  gpr_mu_init(&server->mu);
+
+  server->cq = cq;
+  server->em = grpc_surface_em();
+  /* decremented by grpc_server_destroy */
+  gpr_ref_init(&server->internal_refcount, 1);
+  server->root_channel_data.next = server->root_channel_data.prev =
+      &server->root_channel_data;
+
+  /* Server filter stack is:
+
+     server_surface_filter - for making surface API calls
+     grpc_server_census_filter (optional) - for stats collection and tracing
+     {passed in filter stack}
+     grpc_connected_channel_filter - for interfacing with transports */
+  server->channel_filter_count = filter_count + 1 + census_enabled;
+  server->channel_filters =
+      gpr_malloc(server->channel_filter_count * sizeof(grpc_channel_filter *));
+  server->channel_filters[0] = &server_surface_filter;
+  if (census_enabled) {
+    server->channel_filters[1] = &grpc_server_census_filter;
+  }
+  for (i = 0; i < filter_count; i++) {
+    server->channel_filters[i + 1 + census_enabled] = filters[i];
+  }
+
+  server->channel_args = grpc_channel_args_copy(args);
+
+  return server;
+}
+
+void grpc_server_start(grpc_server *server) {
+  listener *l;
+
+  for (l = server->listeners; l; l = l->next) {
+    l->start(server, l->arg);
+  }
+}
+
+grpc_transport_setup_result grpc_server_setup_transport(
+    grpc_server *s, grpc_transport *transport,
+    grpc_channel_filter const **extra_filters, size_t num_extra_filters,
+    grpc_mdctx *mdctx) {
+  size_t num_filters = s->channel_filter_count + num_extra_filters + 1;
+  grpc_channel_filter const **filters =
+      gpr_malloc(sizeof(grpc_channel_filter *) * num_filters);
+  size_t i;
+  grpc_channel *channel;
+  channel_data *chand;
+
+  for (i = 0; i < s->channel_filter_count; i++) {
+    filters[i] = s->channel_filters[i];
+  }
+  for (; i < s->channel_filter_count + num_extra_filters; i++) {
+    filters[i] = extra_filters[i - s->channel_filter_count];
+  }
+  filters[i] = &grpc_connected_channel_filter;
+
+  channel = grpc_channel_create_from_filters(filters, num_filters,
+                                             s->channel_args, mdctx, 0);
+  chand = (channel_data *)grpc_channel_stack_element(
+              grpc_channel_get_channel_stack(channel), 0)->channel_data;
+  chand->server = s;
+  server_ref(s);
+  chand->channel = channel;
+
+  gpr_mu_lock(&s->mu);
+  chand->next = &s->root_channel_data;
+  chand->prev = chand->next->prev;
+  chand->next->prev = chand->prev->next = chand;
+  gpr_mu_unlock(&s->mu);
+
+  gpr_free(filters);
+
+  return grpc_connected_channel_bind_transport(
+      grpc_channel_get_channel_stack(channel), transport);
+}
+
+void grpc_server_shutdown(grpc_server *server) {
+  /* TODO(ctiller): send goaway, etc */
+  listener *l;
+  void **tags;
+  size_t ntags;
+
+  /* lock, and gather up some stuff to do */
+  gpr_mu_lock(&server->mu);
+  if (server->shutdown) {
+    gpr_mu_unlock(&server->mu);
+    return;
+  }
+
+  tags = server->tags;
+  ntags = server->ntags;
+  server->tags = NULL;
+  server->ntags = 0;
+
+  server->shutdown = 1;
+  gpr_mu_unlock(&server->mu);
+
+  /* terminate all the requested calls */
+  early_terminate_requested_calls(server->cq, tags, ntags);
+  gpr_free(tags);
+
+  /* Shutdown listeners */
+  for (l = server->listeners; l; l = l->next) {
+    l->destroy(server, l->arg);
+  }
+  while (server->listeners) {
+    l = server->listeners;
+    server->listeners = l->next;
+    gpr_free(l);
+  }
+}
+
+void grpc_server_destroy(grpc_server *server) {
+  channel_data *c;
+  gpr_mu_lock(&server->mu);
+  for (c = server->root_channel_data.next; c != &server->root_channel_data;
+       c = c->next) {
+    shutdown_channel(c);
+  }
+  gpr_mu_unlock(&server->mu);
+
+  server_unref(server);
+}
+
+void grpc_server_add_listener(grpc_server *server, void *arg,
+                              void (*start)(grpc_server *server, void *arg),
+                              void (*destroy)(grpc_server *server, void *arg)) {
+  listener *l = gpr_malloc(sizeof(listener));
+  l->arg = arg;
+  l->start = start;
+  l->destroy = destroy;
+  l->next = server->listeners;
+  server->listeners = l;
+}
+
+grpc_call_error grpc_server_request_call(grpc_server *server, void *tag_new) {
+  call_data *calld;
+
+  grpc_cq_begin_op(server->cq, NULL, GRPC_SERVER_RPC_NEW);
+
+  gpr_mu_lock(&server->mu);
+
+  if (server->shutdown) {
+    gpr_mu_unlock(&server->mu);
+    early_terminate_requested_calls(server->cq, &tag_new, 1);
+    return GRPC_CALL_OK;
+  }
+
+  calld = call_list_remove_head(server, PENDING_START);
+  if (calld) {
+    GPR_ASSERT(calld->state == PENDING);
+    calld->state = ACTIVATED;
+    queue_new_rpc(server, calld, tag_new);
+  } else {
+    if (server->tag_cap == server->ntags) {
+      server->tag_cap = GPR_MAX(3 * server->tag_cap / 2, server->tag_cap + 1);
+      server->tags =
+          gpr_realloc(server->tags, sizeof(void *) * server->tag_cap);
+    }
+    server->tags[server->ntags++] = tag_new;
+  }
+  gpr_mu_unlock(&server->mu);
+
+  return GRPC_CALL_OK;
+}
+
+const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) {
+  return server->channel_args;
+}
diff --git a/src/core/surface/server.h b/src/core/surface/server.h
new file mode 100644
index 0000000..f0773ab
--- /dev/null
+++ b/src/core/surface/server.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SURFACE_SERVER_H__
+#define __GRPC_INTERNAL_SURFACE_SERVER_H__
+
+#include "src/core/channel/channel_stack.h"
+#include <grpc/grpc.h>
+#include "src/core/transport/transport.h"
+
+/* Create a server */
+grpc_server *grpc_server_create_from_filters(grpc_completion_queue *cq,
+                                             grpc_channel_filter **filters,
+                                             size_t filter_count,
+                                             const grpc_channel_args *args);
+
+/* Add a listener to the server: when the server starts, it will call start,
+   and when it shuts down, it will call destroy */
+void grpc_server_add_listener(grpc_server *server, void *listener,
+                              void (*start)(grpc_server *server, void *arg),
+                              void (*destroy)(grpc_server *server, void *arg));
+
+/* Setup a transport - creates a channel stack, binds the transport to the
+   server */
+grpc_transport_setup_result grpc_server_setup_transport(
+    grpc_server *server, grpc_transport *transport,
+    grpc_channel_filter const **extra_filters, size_t num_extra_filters,
+    grpc_mdctx *mdctx);
+
+const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server);
+
+#endif  /* __GRPC_INTERNAL_SURFACE_SERVER_H__ */
diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c
new file mode 100644
index 0000000..24c5757
--- /dev/null
+++ b/src/core/surface/server_chttp2.c
@@ -0,0 +1,123 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+
+#include "src/core/channel/http_filter.h"
+#include "src/core/channel/http_server_filter.h"
+#include "src/core/endpoint/resolve_address.h"
+#include "src/core/endpoint/tcp_server.h"
+#include "src/core/surface/server.h"
+#include "src/core/surface/surface_em.h"
+#include "src/core/transport/chttp2_transport.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+static grpc_transport_setup_result setup_transport(void *server,
+                                                   grpc_transport *transport,
+                                                   grpc_mdctx *mdctx) {
+  static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter,
+                                                       &grpc_http_filter};
+  return grpc_server_setup_transport(server, transport, extra_filters,
+                                     GPR_ARRAY_SIZE(extra_filters), mdctx);
+}
+
+static void new_transport(void *server, grpc_endpoint *tcp) {
+  grpc_create_chttp2_transport(setup_transport, server,
+                               grpc_server_get_channel_args(server), tcp, NULL,
+                               0, grpc_mdctx_create(), 0);
+}
+
+/* Server callback: start listening on our ports */
+static void start(grpc_server *server, void *tcpp) {
+  grpc_tcp_server *tcp = tcpp;
+  grpc_tcp_server_start(tcp, new_transport, server);
+}
+
+/* Server callback: destroy the tcp listener (so we don't generate further
+   callbacks) */
+static void destroy(grpc_server *server, void *tcpp) {
+  grpc_tcp_server *tcp = tcpp;
+  grpc_tcp_server_destroy(tcp);
+}
+
+int grpc_server_add_http2_port(grpc_server *server, const char *addr) {
+  grpc_resolved_addresses *resolved = NULL;
+  grpc_tcp_server *tcp = NULL;
+  size_t i;
+  int count = 0;
+
+  resolved = grpc_blocking_resolve_address(addr, "http");
+  if (!resolved) {
+    goto error;
+  }
+
+  tcp = grpc_tcp_server_create(grpc_surface_em());
+  if (!tcp) {
+    goto error;
+  }
+
+  for (i = 0; i < resolved->naddrs; i++) {
+    if (grpc_tcp_server_add_port(tcp,
+                                 (struct sockaddr *)&resolved->addrs[i].addr,
+                                 resolved->addrs[i].len) >= 0) {
+      count++;
+    }
+  }
+  if (count == 0) {
+    gpr_log(GPR_ERROR, "No address added out of total %d resolved",
+            resolved->naddrs);
+    goto error;
+  }
+  if (count != resolved->naddrs) {
+    gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved",
+            count, resolved->naddrs);
+  }
+  grpc_resolved_addresses_destroy(resolved);
+
+  /* Register with the server only upon success */
+  grpc_server_add_listener(server, tcp, start, destroy);
+
+  return 1;
+
+/* Error path: cleanup and return */
+error:
+  if (resolved) {
+    grpc_resolved_addresses_destroy(resolved);
+  }
+  if (tcp) {
+    grpc_tcp_server_destroy(tcp);
+  }
+  return 0;
+}
diff --git a/src/core/surface/server_create.c b/src/core/surface/server_create.c
new file mode 100644
index 0000000..dcc6ce1
--- /dev/null
+++ b/src/core/surface/server_create.c
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+#include "src/core/surface/completion_queue.h"
+#include "src/core/surface/server.h"
+
+grpc_server *grpc_server_create(grpc_completion_queue *cq,
+                                const grpc_channel_args *args) {
+  return grpc_server_create_from_filters(cq, NULL, 0, args);
+}
diff --git a/src/core/surface/surface_em.c b/src/core/surface/surface_em.c
new file mode 100644
index 0000000..e1785d1
--- /dev/null
+++ b/src/core/surface/surface_em.c
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/surface/surface_em.h"
+#include <grpc/support/log.h>
+
+static int initialized = 0;
+static grpc_em em;
+
+grpc_em *grpc_surface_em() {
+  GPR_ASSERT(initialized && "call grpc_init()");
+  return &em;
+}
+
+void grpc_surface_em_init() {
+  GPR_ASSERT(!initialized);
+  initialized = 1;
+  grpc_em_init(&em);
+}
+
+void grpc_surface_em_shutdown() {
+  GPR_ASSERT(initialized);
+  grpc_em_destroy(&em);
+  initialized = 0;
+}
diff --git a/src/core/surface/surface_em.h b/src/core/surface/surface_em.h
new file mode 100644
index 0000000..165f42f
--- /dev/null
+++ b/src/core/surface/surface_em.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SURFACE_SURFACE_EM_H__
+#define __GRPC_INTERNAL_SURFACE_SURFACE_EM_H__
+
+#include "src/core/eventmanager/em.h"
+
+/* Returns a global singleton event manager for
+   the surface apis, and is passed down to channels and
+   transports as needed. */
+grpc_em *grpc_surface_em();
+
+void grpc_surface_em_init();
+void grpc_surface_em_shutdown();
+
+#endif  /* __GRPC_INTERNAL_SURFACE_SURFACE_EM_H__ */
diff --git a/src/core/surface/surface_trace.h b/src/core/surface/surface_trace.h
new file mode 100644
index 0000000..f6f9acf
--- /dev/null
+++ b/src/core/surface/surface_trace.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_SURFACE_SURFACE_TRACE_H__
+#define __GRPC_INTERNAL_SURFACE_SURFACE_TRACE_H__
+
+#include <grpc/support/log.h>
+
+/* #define GRPC_ENABLE_SURFACE_TRACE 1 */
+
+#ifdef GRPC_ENABLE_SURFACE_TRACE
+#define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event)    \
+  do {                                                  \
+    char *_ev = grpc_event_string(event);               \
+    gpr_log(GPR_INFO, "RETURN_EVENT[%p]: %s", cq, _ev); \
+    gpr_free(_ev);                                      \
+  } while (0)
+#else
+#define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event) \
+  do {                                               \
+  } while (0)
+#endif
+
+#endif  /* __GRPC_INTERNAL_SURFACE_SURFACE_TRACE_H__ */
diff --git a/src/core/transport/chttp2/frame.h b/src/core/transport/chttp2/frame.h
new file mode 100644
index 0000000..7c0bbe0
--- /dev/null
+++ b/src/core/transport/chttp2/frame.h
@@ -0,0 +1,74 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_H__
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_H__
+
+#include <grpc/support/port_platform.h>
+
+/* Common definitions for frame handling in the chttp2 transport */
+
+typedef enum {
+  GRPC_CHTTP2_PARSE_OK,
+  GRPC_CHTTP2_STREAM_ERROR,
+  GRPC_CHTTP2_CONNECTION_ERROR
+} grpc_chttp2_parse_error;
+
+typedef struct {
+  gpr_uint8 end_of_stream;
+  gpr_uint8 need_flush_reads;
+  gpr_uint8 metadata_boundary;
+  gpr_uint8 ack_settings;
+  gpr_uint8 send_ping_ack;
+  gpr_uint8 process_ping_reply;
+
+  gpr_uint32 window_update;
+} grpc_chttp2_parse_state;
+
+#define GRPC_CHTTP2_FRAME_DATA 0
+#define GRPC_CHTTP2_FRAME_HEADER 1
+#define GRPC_CHTTP2_FRAME_CONTINUATION 9
+#define GRPC_CHTTP2_FRAME_RST_STREAM 3
+#define GRPC_CHTTP2_FRAME_SETTINGS 4
+#define GRPC_CHTTP2_FRAME_PING 6
+#define GRPC_CHTTP2_FRAME_WINDOW_UPDATE 8
+
+#define GRPC_CHTTP2_MAX_PAYLOAD_LENGTH ((1 << 14) - 1)
+
+#define GRPC_CHTTP2_DATA_FLAG_END_STREAM 1
+#define GRPC_CHTTP2_FLAG_ACK 1
+#define GRPC_CHTTP2_DATA_FLAG_END_HEADERS 4
+#define GRPC_CHTTP2_DATA_FLAG_PADDED 8
+#define GRPC_CHTTP2_FLAG_HAS_PRIORITY 0x20
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_H__ */
diff --git a/src/core/transport/chttp2/frame_data.c b/src/core/transport/chttp2/frame_data.c
new file mode 100644
index 0000000..fbd3b6c
--- /dev/null
+++ b/src/core/transport/chttp2/frame_data.c
@@ -0,0 +1,164 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/frame_data.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+#include <grpc/support/useful.h>
+#include "src/core/transport/transport.h"
+
+grpc_chttp2_parse_error grpc_chttp2_data_parser_init(
+    grpc_chttp2_data_parser *parser) {
+  parser->state = GRPC_CHTTP2_DATA_FH_0;
+  grpc_sopb_init(&parser->incoming_sopb);
+  return GRPC_CHTTP2_PARSE_OK;
+}
+
+void grpc_chttp2_data_parser_destroy(grpc_chttp2_data_parser *parser) {
+  grpc_sopb_destroy(&parser->incoming_sopb);
+}
+
+grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
+    grpc_chttp2_data_parser *parser, gpr_uint8 flags) {
+  if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
+    gpr_log(GPR_ERROR, "unsupported data flags: 0x%02x", flags);
+    return GRPC_CHTTP2_STREAM_ERROR;
+  }
+
+  if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
+    parser->is_last_frame = 1;
+  } else {
+    parser->is_last_frame = 0;
+  }
+
+  return GRPC_CHTTP2_PARSE_OK;
+}
+
+grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
+    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice,
+    int is_last) {
+  gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
+  gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
+  gpr_uint8 *cur = beg;
+  grpc_chttp2_data_parser *p = parser;
+
+  if (is_last && p->is_last_frame) {
+    state->end_of_stream = 1;
+    state->need_flush_reads = 1;
+  }
+
+  if (cur == end) {
+    return GRPC_CHTTP2_PARSE_OK;
+  }
+
+  switch (p->state) {
+  fh_0:
+    case GRPC_CHTTP2_DATA_FH_0:
+      p->frame_type = *cur;
+      if (++cur == end) {
+        p->state = GRPC_CHTTP2_DATA_FH_1;
+        return GRPC_CHTTP2_PARSE_OK;
+      }
+      switch (p->frame_type) {
+        case 0:
+          break;
+        case 1:
+          gpr_log(GPR_ERROR, "Compressed GRPC frames not yet supported");
+          return GRPC_CHTTP2_STREAM_ERROR;
+        default:
+          gpr_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type);
+          return GRPC_CHTTP2_STREAM_ERROR;
+      }
+    /* fallthrough */
+    case GRPC_CHTTP2_DATA_FH_1:
+      p->frame_size = ((gpr_uint32)*cur) << 24;
+      if (++cur == end) {
+        p->state = GRPC_CHTTP2_DATA_FH_2;
+        return GRPC_CHTTP2_PARSE_OK;
+      }
+    /* fallthrough */
+    case GRPC_CHTTP2_DATA_FH_2:
+      p->frame_size |= ((gpr_uint32)*cur) << 16;
+      if (++cur == end) {
+        p->state = GRPC_CHTTP2_DATA_FH_3;
+        return GRPC_CHTTP2_PARSE_OK;
+      }
+    /* fallthrough */
+    case GRPC_CHTTP2_DATA_FH_3:
+      p->frame_size |= ((gpr_uint32)*cur) << 8;
+      if (++cur == end) {
+        p->state = GRPC_CHTTP2_DATA_FH_4;
+        return GRPC_CHTTP2_PARSE_OK;
+      }
+    /* fallthrough */
+    case GRPC_CHTTP2_DATA_FH_4:
+      p->frame_size |= ((gpr_uint32)*cur);
+      p->state = GRPC_CHTTP2_DATA_FRAME;
+      ++cur;
+      state->need_flush_reads = 1;
+      grpc_sopb_add_begin_message(&p->incoming_sopb, p->frame_size, 0);
+    /* fallthrough */
+    case GRPC_CHTTP2_DATA_FRAME:
+      if (cur == end) {
+        return GRPC_CHTTP2_PARSE_OK;
+      } else if (end - cur == p->frame_size) {
+        state->need_flush_reads = 1;
+        grpc_sopb_add_slice(&p->incoming_sopb,
+                            gpr_slice_sub(slice, cur - beg, end - beg));
+        p->state = GRPC_CHTTP2_DATA_FH_0;
+        return GRPC_CHTTP2_PARSE_OK;
+      } else if (end - cur > p->frame_size) {
+        state->need_flush_reads = 1;
+        grpc_sopb_add_slice(
+            &p->incoming_sopb,
+            gpr_slice_sub(slice, cur - beg, cur + p->frame_size - beg));
+        cur += p->frame_size;
+        goto fh_0; /* loop */
+      } else {
+        state->need_flush_reads = 1;
+        grpc_sopb_add_slice(&p->incoming_sopb,
+                            gpr_slice_sub(slice, cur - beg, end - beg));
+        p->frame_size -= (end - cur);
+        return GRPC_CHTTP2_PARSE_OK;
+      }
+  }
+
+  gpr_log(GPR_ERROR, "should never reach here");
+  abort();
+  return GRPC_CHTTP2_CONNECTION_ERROR;
+}
+
diff --git a/src/core/transport/chttp2/frame_data.h b/src/core/transport/chttp2/frame_data.h
new file mode 100644
index 0000000..abe26da
--- /dev/null
+++ b/src/core/transport/chttp2/frame_data.h
@@ -0,0 +1,80 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_DATA_H__
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_DATA_H__
+
+/* Parser for GRPC streams embedded in DATA frames */
+
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
+#include "src/core/transport/stream_op.h"
+#include "src/core/transport/chttp2/frame.h"
+
+typedef enum {
+  GRPC_CHTTP2_DATA_FH_0,
+  GRPC_CHTTP2_DATA_FH_1,
+  GRPC_CHTTP2_DATA_FH_2,
+  GRPC_CHTTP2_DATA_FH_3,
+  GRPC_CHTTP2_DATA_FH_4,
+  GRPC_CHTTP2_DATA_FRAME
+} grpc_chttp2_stream_state;
+
+typedef struct {
+  grpc_chttp2_stream_state state;
+  gpr_uint8 is_last_frame;
+  gpr_uint8 frame_type;
+  gpr_uint32 frame_size;
+
+  grpc_stream_op_buffer incoming_sopb;
+} grpc_chttp2_data_parser;
+
+/* initialize per-stream state for data frame parsing */
+grpc_chttp2_parse_error grpc_chttp2_data_parser_init(
+    grpc_chttp2_data_parser *parser);
+
+void grpc_chttp2_data_parser_destroy(grpc_chttp2_data_parser *parser);
+
+/* start processing a new data frame */
+grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
+    grpc_chttp2_data_parser *parser, gpr_uint8 flags);
+
+/* handle a slice of a data frame - is_last indicates the last slice of a
+   frame */
+grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
+    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last);
+
+/* create a slice with an empty data frame and is_last set */
+gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id);
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_DATA_H__ */
diff --git a/src/core/transport/chttp2/frame_ping.c b/src/core/transport/chttp2/frame_ping.c
new file mode 100644
index 0000000..9556c0c
--- /dev/null
+++ b/src/core/transport/chttp2/frame_ping.c
@@ -0,0 +1,93 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/frame_ping.h"
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+
+gpr_slice grpc_chttp2_ping_create(gpr_uint8 ack, gpr_uint8 *opaque_8bytes) {
+  gpr_slice slice = gpr_slice_malloc(9 + 8);
+  gpr_uint8 *p = GPR_SLICE_START_PTR(slice);
+
+  *p++ = 0;
+  *p++ = 0;
+  *p++ = 8;
+  *p++ = GRPC_CHTTP2_FRAME_PING;
+  *p++ = ack ? 1 : 0;
+  *p++ = 0;
+  *p++ = 0;
+  *p++ = 0;
+  *p++ = 0;
+  memcpy(p, opaque_8bytes, 8);
+
+  return slice;
+}
+
+grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame(
+    grpc_chttp2_ping_parser *parser, gpr_uint32 length, gpr_uint8 flags) {
+  if (flags & 0xfe || length != 8) {
+    gpr_log(GPR_ERROR, "invalid ping: length=%d, flags=%02x", length, flags);
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  }
+  parser->byte = 0;
+  parser->is_ack = flags;
+  return GRPC_CHTTP2_PARSE_OK;
+}
+
+grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
+    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice,
+    int is_last) {
+  gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
+  gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
+  gpr_uint8 *cur = beg;
+  grpc_chttp2_ping_parser *p = parser;
+
+  while (p->byte != 8 && cur != end) {
+    p->opaque_8bytes[p->byte] = *cur;
+    cur++;
+    p->byte++;
+  }
+
+  if (p->byte == 8) {
+    GPR_ASSERT(is_last);
+    if (p->is_ack) {
+      state->process_ping_reply = 1;
+    } else {
+      state->send_ping_ack = 1;
+    }
+  }
+
+  return GRPC_CHTTP2_PARSE_OK;
+}
diff --git a/src/core/transport/chttp2/frame_ping.h b/src/core/transport/chttp2/frame_ping.h
new file mode 100644
index 0000000..a64d536
--- /dev/null
+++ b/src/core/transport/chttp2/frame_ping.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_PING_H__
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_PING_H__
+
+#include <grpc/support/slice.h>
+#include "src/core/transport/chttp2/frame.h"
+
+typedef struct {
+  gpr_uint8 byte;
+  gpr_uint8 is_ack;
+  gpr_uint8 opaque_8bytes[8];
+} grpc_chttp2_ping_parser;
+
+gpr_slice grpc_chttp2_ping_create(gpr_uint8 ack, gpr_uint8 *opaque_8bytes);
+
+grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame(
+    grpc_chttp2_ping_parser *parser, gpr_uint32 length, gpr_uint8 flags);
+grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
+    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last);
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_PING_H__ */
diff --git a/src/core/transport/chttp2/frame_rst_stream.c b/src/core/transport/chttp2/frame_rst_stream.c
new file mode 100644
index 0000000..825e156
--- /dev/null
+++ b/src/core/transport/chttp2/frame_rst_stream.c
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/frame_rst_stream.h"
+#include "src/core/transport/chttp2/frame.h"
+
+gpr_slice grpc_chttp2_rst_stream_create(gpr_uint32 id, gpr_uint32 code) {
+  gpr_slice slice = gpr_slice_malloc(13);
+  gpr_uint8 *p = GPR_SLICE_START_PTR(slice);
+
+  *p++ = 0;
+  *p++ = 0;
+  *p++ = 4;
+  *p++ = GRPC_CHTTP2_FRAME_RST_STREAM;
+  *p++ = 0;
+  *p++ = id >> 24;
+  *p++ = id >> 16;
+  *p++ = id >> 8;
+  *p++ = id;
+  *p++ = code >> 24;
+  *p++ = code >> 16;
+  *p++ = code >> 8;
+  *p++ = code;
+
+  return slice;
+}
diff --git a/src/core/transport/chttp2/frame_rst_stream.h b/src/core/transport/chttp2/frame_rst_stream.h
new file mode 100644
index 0000000..78aea0f
--- /dev/null
+++ b/src/core/transport/chttp2/frame_rst_stream.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H__
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H__
+
+#include <grpc/support/slice.h>
+
+gpr_slice grpc_chttp2_rst_stream_create(gpr_uint32 stream_id, gpr_uint32 code);
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H__ */
diff --git a/src/core/transport/chttp2/frame_settings.c b/src/core/transport/chttp2/frame_settings.c
new file mode 100644
index 0000000..488b96a
--- /dev/null
+++ b/src/core/transport/chttp2/frame_settings.c
@@ -0,0 +1,227 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/frame_settings.h"
+
+#include <string.h>
+
+#include "src/core/transport/chttp2/frame.h"
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+/* HTTP/2 mandated initial connection settings */
+const grpc_chttp2_setting_parameters
+    grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {
+        {NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
+        {"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff,
+         GRPC_CHTTP2_CLAMP_INVALID_VALUE},
+        {"ENABLE_PUSH", 1, 0, 1, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
+        {"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu,
+         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
+        {"INITIAL_WINDOW_SIZE", 65535, 0, 0xffffffffu,
+         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
+        {"MAX_FRAME_SIZE", 16384, 16384, 16777215,
+         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
+        {"MAX_HEADER_LIST_SIZE", 0xffffffffu, 0, 0xffffffffu,
+         GRPC_CHTTP2_CLAMP_INVALID_VALUE},
+};
+
+static gpr_uint8 *fill_header(gpr_uint8 *out, gpr_uint32 length,
+                              gpr_uint8 flags) {
+  *out++ = length >> 16;
+  *out++ = length >> 8;
+  *out++ = length;
+  *out++ = GRPC_CHTTP2_FRAME_SETTINGS;
+  *out++ = flags;
+  *out++ = 0;
+  *out++ = 0;
+  *out++ = 0;
+  *out++ = 0;
+  return out;
+}
+
+gpr_slice grpc_chttp2_settings_create(gpr_uint32 *old, const gpr_uint32 *new,
+                                      size_t count) {
+  size_t i;
+  size_t n = 0;
+  gpr_slice output;
+  gpr_uint8 *p;
+
+  for (i = 0; i < count; i++) {
+    n += (new[i] != old[i]);
+  }
+
+  output = gpr_slice_malloc(9 + 6 * n);
+  p = fill_header(GPR_SLICE_START_PTR(output), 6 * n, 0);
+
+  for (i = 0; i < count; i++) {
+    if (new[i] != old[i]) {
+      GPR_ASSERT(i);
+      *p++ = i >> 8;
+      *p++ = i;
+      *p++ = new[i] >> 24;
+      *p++ = new[i] >> 16;
+      *p++ = new[i] >> 8;
+      *p++ = new[i];
+      old[i] = new[i];
+    }
+  }
+
+  GPR_ASSERT(p == GPR_SLICE_END_PTR(output));
+
+  return output;
+}
+
+gpr_slice grpc_chttp2_settings_ack_create() {
+  gpr_slice output = gpr_slice_malloc(9);
+  fill_header(GPR_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK);
+  return output;
+}
+
+grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
+    grpc_chttp2_settings_parser *parser, gpr_uint32 length, gpr_uint8 flags,
+    gpr_uint32 *settings) {
+  parser->target_settings = settings;
+  memcpy(parser->incoming_settings, settings,
+         GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
+  parser->is_ack = 0;
+  parser->state = GRPC_CHTTP2_SPS_ID0;
+  if (flags == GRPC_CHTTP2_FLAG_ACK) {
+    parser->is_ack = 1;
+    if (length != 0) {
+      gpr_log(GPR_ERROR, "non-empty settings ack frame received");
+      return GRPC_CHTTP2_CONNECTION_ERROR;
+    }
+    return GRPC_CHTTP2_PARSE_OK;
+  } else if (flags != 0) {
+    gpr_log(GPR_ERROR, "invalid flags on settings frame");
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  } else if (length % 6 != 0) {
+    gpr_log(GPR_ERROR, "settings frames must be a multiple of six bytes");
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  } else {
+    return GRPC_CHTTP2_PARSE_OK;
+  }
+}
+
+grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
+    void *p, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last) {
+  grpc_chttp2_settings_parser *parser = p;
+  const gpr_uint8 *cur = GPR_SLICE_START_PTR(slice);
+  const gpr_uint8 *end = GPR_SLICE_END_PTR(slice);
+
+  if (parser->is_ack) {
+    return GRPC_CHTTP2_PARSE_OK;
+  }
+
+  for (;;) {
+    switch (parser->state) {
+      case GRPC_CHTTP2_SPS_ID0:
+        if (cur == end) {
+          parser->state = GRPC_CHTTP2_SPS_ID0;
+          if (is_last) {
+            memcpy(parser->target_settings, parser->incoming_settings,
+                   GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
+            state->ack_settings = 1;
+          }
+          return GRPC_CHTTP2_PARSE_OK;
+        }
+        parser->id = ((gpr_uint16)*cur) << 8;
+        cur++;
+      /* fallthrough */
+      case GRPC_CHTTP2_SPS_ID1:
+        if (cur == end) {
+          parser->state = GRPC_CHTTP2_SPS_ID1;
+          return GRPC_CHTTP2_PARSE_OK;
+        }
+        parser->id |= (*cur);
+        cur++;
+      /* fallthrough */
+      case GRPC_CHTTP2_SPS_VAL0:
+        if (cur == end) {
+          parser->state = GRPC_CHTTP2_SPS_VAL0;
+          return GRPC_CHTTP2_PARSE_OK;
+        }
+        parser->value = ((gpr_uint32)*cur) << 24;
+        cur++;
+      /* fallthrough */
+      case GRPC_CHTTP2_SPS_VAL1:
+        if (cur == end) {
+          parser->state = GRPC_CHTTP2_SPS_VAL1;
+          return GRPC_CHTTP2_PARSE_OK;
+        }
+        parser->value |= ((gpr_uint32)*cur) << 16;
+        cur++;
+      /* fallthrough */
+      case GRPC_CHTTP2_SPS_VAL2:
+        if (cur == end) {
+          parser->state = GRPC_CHTTP2_SPS_VAL2;
+          return GRPC_CHTTP2_PARSE_OK;
+        }
+        parser->value |= ((gpr_uint32)*cur) << 8;
+        cur++;
+      /* fallthrough */
+      case GRPC_CHTTP2_SPS_VAL3:
+        if (cur == end) {
+          parser->state = GRPC_CHTTP2_SPS_VAL3;
+          return GRPC_CHTTP2_PARSE_OK;
+        } else {
+          parser->state = GRPC_CHTTP2_SPS_ID0;
+        }
+        parser->value |= *cur;
+        cur++;
+
+        if (parser->id > 0 && parser->id < GRPC_CHTTP2_NUM_SETTINGS) {
+          const grpc_chttp2_setting_parameters *sp =
+              &grpc_chttp2_settings_parameters[parser->id];
+          if (parser->value < sp->min_value || parser->value > sp->max_value) {
+            switch (sp->invalid_value_behavior) {
+              case GRPC_CHTTP2_CLAMP_INVALID_VALUE:
+                parser->value =
+                    GPR_CLAMP(parser->value, sp->min_value, sp->max_value);
+                break;
+              case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE:
+                gpr_log(GPR_ERROR, "invalid value %u passed for %s",
+                        parser->value, sp->name);
+                return GRPC_CHTTP2_CONNECTION_ERROR;
+            }
+          }
+          parser->incoming_settings[parser->id] = parser->value;
+        } else {
+          gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)",
+                  parser->id, parser->value);
+        }
+        break;
+    }
+  }
+}
diff --git a/src/core/transport/chttp2/frame_settings.h b/src/core/transport/chttp2/frame_settings.h
new file mode 100644
index 0000000..74e2b4f
--- /dev/null
+++ b/src/core/transport/chttp2/frame_settings.h
@@ -0,0 +1,99 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_SETTINGS_H__
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_SETTINGS_H__
+
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice.h>
+#include "src/core/transport/chttp2/frame.h"
+
+typedef enum {
+  GRPC_CHTTP2_SPS_ID0,
+  GRPC_CHTTP2_SPS_ID1,
+  GRPC_CHTTP2_SPS_VAL0,
+  GRPC_CHTTP2_SPS_VAL1,
+  GRPC_CHTTP2_SPS_VAL2,
+  GRPC_CHTTP2_SPS_VAL3
+} grpc_chttp2_settings_parse_state;
+
+/* The things HTTP/2 defines as connection level settings */
+typedef enum {
+  GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE = 1,
+  GRPC_CHTTP2_SETTINGS_ENABLE_PUSH = 2,
+  GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 3,
+  GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 4,
+  GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE = 5,
+  GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 6,
+  GRPC_CHTTP2_NUM_SETTINGS
+} grpc_chttp2_setting_id;
+
+typedef struct {
+  grpc_chttp2_settings_parse_state state;
+  gpr_uint32 *target_settings;
+  gpr_uint8 is_ack;
+  gpr_uint16 id;
+  gpr_uint32 value;
+  gpr_uint32 incoming_settings[GRPC_CHTTP2_NUM_SETTINGS];
+} grpc_chttp2_settings_parser;
+
+typedef enum {
+  GRPC_CHTTP2_CLAMP_INVALID_VALUE,
+  GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE
+} grpc_chttp2_invalid_value_behavior;
+
+typedef struct {
+  const char *name;
+  gpr_uint32 default_value;
+  gpr_uint32 min_value;
+  gpr_uint32 max_value;
+  grpc_chttp2_invalid_value_behavior invalid_value_behavior;
+} grpc_chttp2_setting_parameters;
+
+/* HTTP/2 mandated connection setting parameters */
+extern const grpc_chttp2_setting_parameters
+    grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS];
+
+/* Create a settings frame by diffing old & new, and updating old to be new */
+gpr_slice grpc_chttp2_settings_create(gpr_uint32 *old, const gpr_uint32 *new,
+                                      size_t count);
+/* Create an ack settings frame */
+gpr_slice grpc_chttp2_settings_ack_create();
+
+grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
+    grpc_chttp2_settings_parser *parser, gpr_uint32 length, gpr_uint8 flags,
+    gpr_uint32 *settings);
+grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
+    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last);
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_SETTINGS_H__ */
diff --git a/src/core/transport/chttp2/frame_window_update.c b/src/core/transport/chttp2/frame_window_update.c
new file mode 100644
index 0000000..f61714f
--- /dev/null
+++ b/src/core/transport/chttp2/frame_window_update.c
@@ -0,0 +1,99 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/frame_window_update.h"
+
+#include <grpc/support/log.h>
+
+gpr_slice grpc_chttp2_window_update_create(gpr_uint32 id,
+                                           gpr_uint32 window_update) {
+  gpr_slice slice = gpr_slice_malloc(13);
+  gpr_uint8 *p = GPR_SLICE_START_PTR(slice);
+
+  GPR_ASSERT(window_update);
+
+  *p++ = 0;
+  *p++ = 0;
+  *p++ = 4;
+  *p++ = GRPC_CHTTP2_FRAME_WINDOW_UPDATE;
+  *p++ = 0;
+  *p++ = id >> 24;
+  *p++ = id >> 16;
+  *p++ = id >> 8;
+  *p++ = id;
+  *p++ = window_update >> 24;
+  *p++ = window_update >> 16;
+  *p++ = window_update >> 8;
+  *p++ = window_update;
+
+  return slice;
+}
+
+grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame(
+    grpc_chttp2_window_update_parser *parser, gpr_uint32 length,
+    gpr_uint8 flags) {
+  if (flags || length != 4) {
+    gpr_log(GPR_ERROR, "invalid window update: length=%d, flags=%02x", length,
+            flags);
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  }
+  parser->byte = 0;
+  parser->amount = 0;
+  return GRPC_CHTTP2_PARSE_OK;
+}
+
+grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
+    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice,
+    int is_last) {
+  gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
+  gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
+  gpr_uint8 *cur = beg;
+  grpc_chttp2_window_update_parser *p = parser;
+
+  while (p->byte != 4 && cur != end) {
+    p->amount |= ((gpr_uint32)*cur) << (8 * (3 - p->byte));
+    cur++;
+    p->byte++;
+  }
+
+  if (p->byte == 4) {
+    if (p->amount == 0 || (p->amount & 0x80000000u)) {
+      gpr_log(GPR_ERROR, "invalid window update bytes: %d", p->amount);
+      return GRPC_CHTTP2_CONNECTION_ERROR;
+    }
+    GPR_ASSERT(is_last);
+    state->window_update = p->amount;
+  }
+
+  return GRPC_CHTTP2_PARSE_OK;
+}
diff --git a/src/core/transport/chttp2/frame_window_update.h b/src/core/transport/chttp2/frame_window_update.h
new file mode 100644
index 0000000..4b789fc
--- /dev/null
+++ b/src/core/transport/chttp2/frame_window_update.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H__
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H__
+
+#include <grpc/support/slice.h>
+#include "src/core/transport/chttp2/frame.h"
+
+typedef struct {
+  gpr_uint8 byte;
+  gpr_uint8 is_connection_update;
+  gpr_uint32 amount;
+} grpc_chttp2_window_update_parser;
+
+gpr_slice grpc_chttp2_window_update_create(gpr_uint32 id,
+                                           gpr_uint32 window_delta);
+
+grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame(
+    grpc_chttp2_window_update_parser *parser, gpr_uint32 length,
+    gpr_uint8 flags);
+grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
+    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last);
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H__ */
diff --git a/src/core/transport/chttp2/gen_hpack_tables.c b/src/core/transport/chttp2/gen_hpack_tables.c
new file mode 100644
index 0000000..cc94a73
--- /dev/null
+++ b/src/core/transport/chttp2/gen_hpack_tables.c
@@ -0,0 +1,589 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* generates constant tables for hpack.c */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <grpc/support/log.h>
+
+/*
+ * first byte LUT generation
+ */
+
+typedef struct {
+  const char *call;
+  /* bit prefix for the field type */
+  unsigned char prefix;
+  /* length of the bit prefix for the field type */
+  unsigned char prefix_length;
+  /* index value: 0 = all zeros, 2 = all ones, 1 otherwise */
+  unsigned char index;
+} spec;
+
+static const spec fields[] = {
+    {"INDEXED_FIELD", 0X80, 1, 1},
+    {"INDEXED_FIELD_X", 0X80, 1, 2},
+    {"LITHDR_INCIDX", 0X40, 2, 1},
+    {"LITHDR_INCIDX_X", 0X40, 2, 2},
+    {"LITHDR_INCIDX_V", 0X40, 2, 0},
+    {"LITHDR_NOTIDX", 0X00, 4, 1},
+    {"LITHDR_NOTIDX_X", 0X00, 4, 2},
+    {"LITHDR_NOTIDX_V", 0X00, 4, 0},
+    {"LITHDR_NVRIDX", 0X10, 4, 1},
+    {"LITHDR_NVRIDX_X", 0X10, 4, 2},
+    {"LITHDR_NVRIDX_V", 0X10, 4, 0},
+    {"MAX_TBL_SIZE", 0X20, 3, 1},
+    {"MAX_TBL_SIZE_X", 0X20, 3, 2},
+};
+
+static const int num_fields = sizeof(fields) / sizeof(*fields);
+
+static unsigned char prefix_mask(unsigned char prefix_len) {
+  unsigned char i;
+  unsigned char out = 0;
+  for (i = 0; i < prefix_len; i++) {
+    out |= 1 << (7 - i);
+  }
+  return out;
+}
+
+static unsigned char suffix_mask(unsigned char prefix_len) {
+  return ~prefix_mask(prefix_len);
+}
+
+static void generate_first_byte_lut() {
+  int i, j, n;
+  const spec *chrspec;
+  unsigned char suffix;
+
+  n = printf("static CALLTYPE first_byte[256] = {");
+  /* for each potential first byte of a header */
+  for (i = 0; i < 256; i++) {
+    /* find the field type that matches it */
+    chrspec = NULL;
+    for (j = 0; j < num_fields; j++) {
+      if ((prefix_mask(fields[j].prefix_length) & i) == fields[j].prefix) {
+        suffix = suffix_mask(fields[j].prefix_length) & i;
+        if (suffix == suffix_mask(fields[j].prefix_length)) {
+          if (fields[j].index != 2) continue;
+        } else if (suffix == 0) {
+          if (fields[j].index != 0) continue;
+        } else {
+          if (fields[j].index != 1) continue;
+        }
+        GPR_ASSERT(chrspec == NULL);
+        chrspec = &fields[j];
+      }
+    }
+    if (chrspec) {
+      n += printf("%s, ", chrspec->call);
+    } else {
+      n += printf("ILLEGAL, ");
+    }
+    /* make some small effort towards readable output */
+    if (n > 70) {
+      printf("\n  ");
+      n = 2;
+    }
+  }
+  printf("};\n");
+}
+
+/*
+ * Huffman decoder table generation
+ */
+
+#define NSYMS 257
+#define MAXHUFFSTATES 1024
+
+/* Constants pulled from the HPACK spec, and converted to C using the vim
+   command:
+   :%s/.*   \([0-9a-f]\+\)  \[ *\([0-9]\+\)\]/{0x\1, \2},/g */
+static const struct {
+  unsigned bits;
+  unsigned length;
+} huffsyms[NSYMS] = {
+      {0x1ff8, 13},
+      {0x7fffd8, 23},
+      {0xfffffe2, 28},
+      {0xfffffe3, 28},
+      {0xfffffe4, 28},
+      {0xfffffe5, 28},
+      {0xfffffe6, 28},
+      {0xfffffe7, 28},
+      {0xfffffe8, 28},
+      {0xffffea, 24},
+      {0x3ffffffc, 30},
+      {0xfffffe9, 28},
+      {0xfffffea, 28},
+      {0x3ffffffd, 30},
+      {0xfffffeb, 28},
+      {0xfffffec, 28},
+      {0xfffffed, 28},
+      {0xfffffee, 28},
+      {0xfffffef, 28},
+      {0xffffff0, 28},
+      {0xffffff1, 28},
+      {0xffffff2, 28},
+      {0x3ffffffe, 30},
+      {0xffffff3, 28},
+      {0xffffff4, 28},
+      {0xffffff5, 28},
+      {0xffffff6, 28},
+      {0xffffff7, 28},
+      {0xffffff8, 28},
+      {0xffffff9, 28},
+      {0xffffffa, 28},
+      {0xffffffb, 28},
+      {0x14, 6},
+      {0x3f8, 10},
+      {0x3f9, 10},
+      {0xffa, 12},
+      {0x1ff9, 13},
+      {0x15, 6},
+      {0xf8, 8},
+      {0x7fa, 11},
+      {0x3fa, 10},
+      {0x3fb, 10},
+      {0xf9, 8},
+      {0x7fb, 11},
+      {0xfa, 8},
+      {0x16, 6},
+      {0x17, 6},
+      {0x18, 6},
+      {0x0, 5},
+      {0x1, 5},
+      {0x2, 5},
+      {0x19, 6},
+      {0x1a, 6},
+      {0x1b, 6},
+      {0x1c, 6},
+      {0x1d, 6},
+      {0x1e, 6},
+      {0x1f, 6},
+      {0x5c, 7},
+      {0xfb, 8},
+      {0x7ffc, 15},
+      {0x20, 6},
+      {0xffb, 12},
+      {0x3fc, 10},
+      {0x1ffa, 13},
+      {0x21, 6},
+      {0x5d, 7},
+      {0x5e, 7},
+      {0x5f, 7},
+      {0x60, 7},
+      {0x61, 7},
+      {0x62, 7},
+      {0x63, 7},
+      {0x64, 7},
+      {0x65, 7},
+      {0x66, 7},
+      {0x67, 7},
+      {0x68, 7},
+      {0x69, 7},
+      {0x6a, 7},
+      {0x6b, 7},
+      {0x6c, 7},
+      {0x6d, 7},
+      {0x6e, 7},
+      {0x6f, 7},
+      {0x70, 7},
+      {0x71, 7},
+      {0x72, 7},
+      {0xfc, 8},
+      {0x73, 7},
+      {0xfd, 8},
+      {0x1ffb, 13},
+      {0x7fff0, 19},
+      {0x1ffc, 13},
+      {0x3ffc, 14},
+      {0x22, 6},
+      {0x7ffd, 15},
+      {0x3, 5},
+      {0x23, 6},
+      {0x4, 5},
+      {0x24, 6},
+      {0x5, 5},
+      {0x25, 6},
+      {0x26, 6},
+      {0x27, 6},
+      {0x6, 5},
+      {0x74, 7},
+      {0x75, 7},
+      {0x28, 6},
+      {0x29, 6},
+      {0x2a, 6},
+      {0x7, 5},
+      {0x2b, 6},
+      {0x76, 7},
+      {0x2c, 6},
+      {0x8, 5},
+      {0x9, 5},
+      {0x2d, 6},
+      {0x77, 7},
+      {0x78, 7},
+      {0x79, 7},
+      {0x7a, 7},
+      {0x7b, 7},
+      {0x7ffe, 15},
+      {0x7fc, 11},
+      {0x3ffd, 14},
+      {0x1ffd, 13},
+      {0xffffffc, 28},
+      {0xfffe6, 20},
+      {0x3fffd2, 22},
+      {0xfffe7, 20},
+      {0xfffe8, 20},
+      {0x3fffd3, 22},
+      {0x3fffd4, 22},
+      {0x3fffd5, 22},
+      {0x7fffd9, 23},
+      {0x3fffd6, 22},
+      {0x7fffda, 23},
+      {0x7fffdb, 23},
+      {0x7fffdc, 23},
+      {0x7fffdd, 23},
+      {0x7fffde, 23},
+      {0xffffeb, 24},
+      {0x7fffdf, 23},
+      {0xffffec, 24},
+      {0xffffed, 24},
+      {0x3fffd7, 22},
+      {0x7fffe0, 23},
+      {0xffffee, 24},
+      {0x7fffe1, 23},
+      {0x7fffe2, 23},
+      {0x7fffe3, 23},
+      {0x7fffe4, 23},
+      {0x1fffdc, 21},
+      {0x3fffd8, 22},
+      {0x7fffe5, 23},
+      {0x3fffd9, 22},
+      {0x7fffe6, 23},
+      {0x7fffe7, 23},
+      {0xffffef, 24},
+      {0x3fffda, 22},
+      {0x1fffdd, 21},
+      {0xfffe9, 20},
+      {0x3fffdb, 22},
+      {0x3fffdc, 22},
+      {0x7fffe8, 23},
+      {0x7fffe9, 23},
+      {0x1fffde, 21},
+      {0x7fffea, 23},
+      {0x3fffdd, 22},
+      {0x3fffde, 22},
+      {0xfffff0, 24},
+      {0x1fffdf, 21},
+      {0x3fffdf, 22},
+      {0x7fffeb, 23},
+      {0x7fffec, 23},
+      {0x1fffe0, 21},
+      {0x1fffe1, 21},
+      {0x3fffe0, 22},
+      {0x1fffe2, 21},
+      {0x7fffed, 23},
+      {0x3fffe1, 22},
+      {0x7fffee, 23},
+      {0x7fffef, 23},
+      {0xfffea, 20},
+      {0x3fffe2, 22},
+      {0x3fffe3, 22},
+      {0x3fffe4, 22},
+      {0x7ffff0, 23},
+      {0x3fffe5, 22},
+      {0x3fffe6, 22},
+      {0x7ffff1, 23},
+      {0x3ffffe0, 26},
+      {0x3ffffe1, 26},
+      {0xfffeb, 20},
+      {0x7fff1, 19},
+      {0x3fffe7, 22},
+      {0x7ffff2, 23},
+      {0x3fffe8, 22},
+      {0x1ffffec, 25},
+      {0x3ffffe2, 26},
+      {0x3ffffe3, 26},
+      {0x3ffffe4, 26},
+      {0x7ffffde, 27},
+      {0x7ffffdf, 27},
+      {0x3ffffe5, 26},
+      {0xfffff1, 24},
+      {0x1ffffed, 25},
+      {0x7fff2, 19},
+      {0x1fffe3, 21},
+      {0x3ffffe6, 26},
+      {0x7ffffe0, 27},
+      {0x7ffffe1, 27},
+      {0x3ffffe7, 26},
+      {0x7ffffe2, 27},
+      {0xfffff2, 24},
+      {0x1fffe4, 21},
+      {0x1fffe5, 21},
+      {0x3ffffe8, 26},
+      {0x3ffffe9, 26},
+      {0xffffffd, 28},
+      {0x7ffffe3, 27},
+      {0x7ffffe4, 27},
+      {0x7ffffe5, 27},
+      {0xfffec, 20},
+      {0xfffff3, 24},
+      {0xfffed, 20},
+      {0x1fffe6, 21},
+      {0x3fffe9, 22},
+      {0x1fffe7, 21},
+      {0x1fffe8, 21},
+      {0x7ffff3, 23},
+      {0x3fffea, 22},
+      {0x3fffeb, 22},
+      {0x1ffffee, 25},
+      {0x1ffffef, 25},
+      {0xfffff4, 24},
+      {0xfffff5, 24},
+      {0x3ffffea, 26},
+      {0x7ffff4, 23},
+      {0x3ffffeb, 26},
+      {0x7ffffe6, 27},
+      {0x3ffffec, 26},
+      {0x3ffffed, 26},
+      {0x7ffffe7, 27},
+      {0x7ffffe8, 27},
+      {0x7ffffe9, 27},
+      {0x7ffffea, 27},
+      {0x7ffffeb, 27},
+      {0xffffffe, 28},
+      {0x7ffffec, 27},
+      {0x7ffffed, 27},
+      {0x7ffffee, 27},
+      {0x7ffffef, 27},
+      {0x7fffff0, 27},
+      {0x3ffffee, 26},
+      {0x3fffffff, 30},
+};
+
+/* represents a set of symbols as an array of booleans indicating inclusion */
+typedef struct { char included[NSYMS]; } symset;
+/* represents a lookup table indexed by a nibble */
+typedef struct { int values[16]; } nibblelut;
+
+/* returns a symset that includes all possible symbols */
+static symset symset_all() {
+  symset x;
+  memset(x.included, 1, sizeof(x.included));
+  return x;
+}
+
+/* returns a symset that includes no symbols */
+static symset symset_none() {
+  symset x;
+  memset(x.included, 0, sizeof(x.included));
+  return x;
+}
+
+/* returns an empty nibblelut */
+static nibblelut nibblelut_empty() {
+  nibblelut x;
+  int i;
+  for (i = 0; i < 16; i++) {
+    x.values[i] = -1;
+  }
+  return x;
+}
+
+/* counts symbols in a symset - only used for debug builds */
+#ifndef NDEBUG
+static int nsyms(symset s) {
+  int i;
+  int c = 0;
+  for (i = 0; i < NSYMS; i++) {
+    c += s.included[i] != 0;
+  }
+  return c;
+}
+#endif
+
+/* global table of discovered huffman decoding states */
+static struct {
+  /* the bit offset that this state starts at */
+  int bitofs;
+  /* the set of symbols that this state started with */
+  symset syms;
+
+  /* lookup table for the next state */
+  nibblelut next;
+  /* lookup table for what to emit */
+  nibblelut emit;
+} huffstates[MAXHUFFSTATES];
+static int nhuffstates = 0;
+
+/* given a number of decoded bits and a set of symbols that are live,
+   return the index into the decoder table for this state.
+   set isnew to 1 if this state was previously undiscovered */
+static int state_index(int bitofs, symset syms, int *isnew) {
+  int i;
+  for (i = 0; i < nhuffstates; i++) {
+    if (huffstates[i].bitofs != bitofs) continue;
+    if (0 != memcmp(huffstates[i].syms.included, syms.included, NSYMS))
+      continue;
+    *isnew = 0;
+    return i;
+  }
+  GPR_ASSERT(nhuffstates != MAXHUFFSTATES);
+  i = nhuffstates++;
+  huffstates[i].bitofs = bitofs;
+  huffstates[i].syms = syms;
+  huffstates[i].next = nibblelut_empty();
+  huffstates[i].emit = nibblelut_empty();
+  *isnew = 1;
+  return i;
+}
+
+/* recursively build a decoding table
+
+   state   - the huffman state that we are trying to fill in
+   nibble  - the current nibble
+   nibbits - the number of bits in the nibble that have been filled in
+   bitofs  - the number of bits of symbol that have been decoded
+   emit    - the symbol to emit on this nibble (or -1 if no symbol has been
+             found)
+   syms    - the set of symbols that could be matched */
+static void build_dec_tbl(int state, int nibble, int nibbits, int bitofs,
+                          int emit, symset syms) {
+  int i;
+  int bit;
+
+  /* If we have four bits in the nibble we're looking at, then we can fill in
+     a slot in the lookup tables. */
+  if (nibbits == 4) {
+    int isnew;
+    /* Find the state that we are in: this may be a new state, in which case
+       we recurse to fill it in, or we may have already seen this state, in
+       which case the recursion terminates */
+    int st = state_index(bitofs, syms, &isnew);
+    GPR_ASSERT(huffstates[state].next.values[nibble] == -1);
+    huffstates[state].next.values[nibble] = st;
+    huffstates[state].emit.values[nibble] = emit;
+    if (isnew) {
+      build_dec_tbl(st, 0, 0, bitofs, -1, syms);
+    }
+    return;
+  }
+
+  assert(nsyms(syms));
+
+  /* A bit can be 0 or 1 */
+  for (bit = 0; bit < 2; bit++) {
+    /* walk over active symbols and see if they have this bit set */
+    symset nextsyms = symset_none();
+    for (i = 0; i < NSYMS; i++) {
+      if (!syms.included[i]) continue; /* disregard inactive symbols */
+      if (((huffsyms[i].bits >> (huffsyms[i].length - bitofs - 1)) & 1) ==
+          bit) {
+        /* the bit is set, include it in the next recursive set */
+        if (huffsyms[i].length == bitofs + 1) {
+          /* additionally, we've gotten to the end of a symbol - this is a
+             special recursion step: re-activate all the symbols, reset
+             bitofs to zero, and recurse */
+          build_dec_tbl(state, (nibble << 1) | bit, nibbits + 1, 0, i,
+                        symset_all());
+          /* skip the remainder of this loop */
+          goto next;
+        }
+        nextsyms.included[i] = 1;
+      }
+    }
+    /* recurse down for this bit */
+    build_dec_tbl(state, (nibble << 1) | bit, nibbits + 1, bitofs + 1, emit,
+                  nextsyms);
+  next:
+    ;
+  }
+}
+
+static nibblelut ctbl[MAXHUFFSTATES];
+static int nctbl;
+
+static int ctbl_idx(nibblelut x) {
+  int i;
+  for (i = 0; i < nctbl; i++) {
+    if (0 == memcmp(&x, ctbl + i, sizeof(nibblelut))) return i;
+  }
+  ctbl[i] = x;
+  nctbl++;
+  return i;
+}
+
+static void dump_ctbl(const char *name) {
+  int i, j;
+  printf("static const gpr_int16 %s[%d*16] = {\n", name, nctbl);
+  for (i = 0; i < nctbl; i++) {
+    for (j = 0; j < 16; j++) {
+      printf("%d,", ctbl[i].values[j]);
+    }
+    printf("\n");
+  }
+  printf("};\n");
+}
+
+static void generate_huff_tables() {
+  int i;
+  build_dec_tbl(state_index(0, symset_all(), &i), 0, 0, 0, -1, symset_all());
+
+  nctbl = 0;
+  printf("static const gpr_uint8 next_tbl[%d] = {", nhuffstates);
+  for (i = 0; i < nhuffstates; i++) {
+    printf("%d,", ctbl_idx(huffstates[i].next));
+  }
+  printf("};\n");
+  dump_ctbl("next_sub_tbl");
+
+  nctbl = 0;
+  printf("static const gpr_uint16 emit_tbl[%d] = {", nhuffstates);
+  for (i = 0; i < nhuffstates; i++) {
+    printf("%d,", ctbl_idx(huffstates[i].emit));
+  }
+  printf("};\n");
+  dump_ctbl("emit_sub_tbl");
+}
+
+int main(void) {
+  generate_huff_tables();
+  generate_first_byte_lut();
+
+  return 0;
+}
diff --git a/src/core/transport/chttp2/hpack_parser.c b/src/core/transport/chttp2/hpack_parser.c
new file mode 100644
index 0000000..33588a7
--- /dev/null
+++ b/src/core/transport/chttp2/hpack_parser.c
@@ -0,0 +1,1212 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/hpack_parser.h"
+
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
+#include "src/core/support/murmur_hash.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/string.h>
+#include <grpc/support/useful.h>
+
+/* How parsing works:
+
+   The parser object keeps track of a function pointer which represents the
+   current parse state.
+
+   Each time new bytes are presented, we call into the current state, which
+   recursively parses until all bytes in the given chunk are exhausted.
+
+   The parse state that terminates then saves its function pointer to be the
+   current state so that it can resume when more bytes are available.
+
+   It's expected that most optimizing compilers will turn this code into
+   a set of indirect jumps, and so not waste stack space. */
+
+/* forward declarations for parsing states */
+static int parse_begin(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                       const gpr_uint8 *end);
+static int parse_error(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                       const gpr_uint8 *end);
+
+static int parse_string_prefix(grpc_chttp2_hpack_parser *p,
+                               const gpr_uint8 *cur, const gpr_uint8 *end);
+static int parse_key_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                            const gpr_uint8 *end);
+static int parse_value_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                              const gpr_uint8 *end);
+
+static int parse_value0(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                        const gpr_uint8 *end);
+static int parse_value1(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                        const gpr_uint8 *end);
+static int parse_value2(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                        const gpr_uint8 *end);
+static int parse_value3(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                        const gpr_uint8 *end);
+static int parse_value4(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                        const gpr_uint8 *end);
+static int parse_value5up(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                          const gpr_uint8 *end);
+
+static int parse_indexed_field(grpc_chttp2_hpack_parser *p,
+                               const gpr_uint8 *cur, const gpr_uint8 *end);
+static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
+                                 const gpr_uint8 *cur, const gpr_uint8 *end);
+static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p,
+                               const gpr_uint8 *cur, const gpr_uint8 *end);
+static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
+                                 const gpr_uint8 *cur, const gpr_uint8 *end);
+static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+                                 const gpr_uint8 *cur, const gpr_uint8 *end);
+static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p,
+                               const gpr_uint8 *cur, const gpr_uint8 *end);
+static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
+                                 const gpr_uint8 *cur, const gpr_uint8 *end);
+static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+                                 const gpr_uint8 *cur, const gpr_uint8 *end);
+static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
+                               const gpr_uint8 *cur, const gpr_uint8 *end);
+static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
+                                 const gpr_uint8 *cur, const gpr_uint8 *end);
+static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+                                 const gpr_uint8 *cur, const gpr_uint8 *end);
+static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                              const gpr_uint8 *end);
+static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p,
+                                const gpr_uint8 *cur, const gpr_uint8 *end);
+
+/* we translate the first byte of a hpack field into one of these decoding
+   cases, then use a lookup table to jump directly to the appropriate parser.
+
+   _X => the integer index is all ones, meaning we need to do varint decoding
+   _V => the integer index is all zeros, meaning we need to decode an additional
+         string value */
+typedef enum {
+  INDEXED_FIELD,
+  INDEXED_FIELD_X,
+  LITHDR_INCIDX,
+  LITHDR_INCIDX_X,
+  LITHDR_INCIDX_V,
+  LITHDR_NOTIDX,
+  LITHDR_NOTIDX_X,
+  LITHDR_NOTIDX_V,
+  LITHDR_NVRIDX,
+  LITHDR_NVRIDX_X,
+  LITHDR_NVRIDX_V,
+  MAX_TBL_SIZE,
+  MAX_TBL_SIZE_X,
+  ILLEGAL
+} first_byte_type;
+
+/* jump table of parse state functions -- order must match first_byte_type
+   above */
+static const grpc_chttp2_hpack_parser_state first_byte_action[] = {
+    parse_indexed_field,   parse_indexed_field_x, parse_lithdr_incidx,
+    parse_lithdr_incidx_x, parse_lithdr_incidx_v, parse_lithdr_notidx,
+    parse_lithdr_notidx_x, parse_lithdr_notidx_v, parse_lithdr_nvridx,
+    parse_lithdr_nvridx_x, parse_lithdr_nvridx_v, parse_max_tbl_size,
+    parse_max_tbl_size_x,  parse_error};
+
+/* indexes the first byte to a parse state function - generated by
+   gen_hpack_tables.c */
+static const gpr_uint8 first_byte_lut[256] = {
+    LITHDR_NOTIDX_V, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX,
+    LITHDR_NOTIDX,   LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX,
+    LITHDR_NOTIDX,   LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX,
+    LITHDR_NOTIDX,   LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX_X,
+    LITHDR_NVRIDX_V, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
+    LITHDR_NVRIDX,   LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
+    LITHDR_NVRIDX,   LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
+    LITHDR_NVRIDX,   LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX_X,
+    ILLEGAL,         MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE_X,
+    LITHDR_INCIDX_V, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX_X,
+    ILLEGAL,         INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD_X,
+};
+
+/* state table for huffman decoding: given a state, gives an index/16 into
+   next_sub_tbl. Taking that index and adding the value of the nibble being
+   considered returns the next state.
+
+   generated by gen_hpack_tables.c */
+static const gpr_uint8 next_tbl[256] = {
+    0,  1,  2,  3,  4,  1,  2, 5,  6,  1, 7,  8,  1,  3,  3,  9,  10, 11, 1,  1,
+    1,  12, 1,  2,  13, 1,  1, 1,  1,  1, 1,  1,  1,  1,  1,  1,  1,  1,  1,  2,
+    14, 1,  15, 16, 1,  17, 1, 15, 2,  7, 3,  18, 19, 1,  1,  1,  1,  20, 1,  1,
+    1,  1,  1,  1,  1,  1,  1, 1,  15, 2, 2,  7,  21, 1,  22, 1,  1,  1,  1,  1,
+    1,  1,  1,  15, 2,  2,  2, 2,  2,  2, 23, 24, 25, 1,  1,  1,  1,  2,  2,  2,
+    26, 3,  3,  27, 10, 28, 1, 1,  1,  1, 1,  1,  2,  3,  29, 10, 30, 1,  1,  1,
+    1,  1,  1,  1,  1,  1,  1, 1,  1,  1, 1,  31, 1,  1,  1,  1,  1,  1,  1,  2,
+    2,  2,  2,  2,  2,  2,  2, 32, 1,  1, 15, 33, 1,  34, 35, 9,  36, 1,  1,  1,
+    1,  1,  1,  1,  37, 1,  1, 1,  1,  1, 1,  2,  2,  2,  2,  2,  2,  2,  26, 9,
+    38, 1,  1,  1,  1,  1,  1, 1,  15, 2, 2,  2,  2,  26, 3,  3,  39, 1,  1,  1,
+    1,  1,  1,  1,  1,  1,  1, 1,  2,  2, 2,  2,  2,  2,  7,  3,  3,  3,  40, 2,
+    41, 1,  1,  1,  42, 43, 1, 1,  44, 1, 1,  1,  1,  15, 2,  2,  2,  2,  2,  2,
+    3,  3,  3,  45, 46, 1,  1, 2,  2,  2, 35, 3,  3,  18, 47, 2,
+};
+/* next state, based upon current state and the current nibble: see above.
+   generated by gen_hpack_tables.c */
+static const gpr_int16 next_sub_tbl[48 * 16] = {
+    1,   204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217,
+    218, 2,   6,   10,  13,  14,  15,  16,  17,  2,   6,   10,  13,  14,  15,
+    16,  17,  3,   7,   11,  24,  3,   7,   11,  24,  3,   7,   11,  24,  3,
+    7,   11,  24,  4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,
+    4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   5,
+    199, 200, 201, 202, 203, 4,   8,   4,   8,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   9,   133, 134, 135, 136, 137, 138, 139, 140,
+    141, 142, 143, 144, 145, 146, 147, 3,   7,   11,  24,  3,   7,   11,  24,
+    4,   8,   4,   8,   4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   12,  132, 4,   8,   4,   8,   4,   8,
+    4,   8,   4,   8,   4,   8,   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,   18,  19,  20,  21,  4,   8,   4,
+    8,   4,   8,   4,   8,   4,   8,   0,   0,   0,   22,  23,  91,  25,  26,
+    27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  3,
+    7,   11,  24,  3,   7,   11,  24,  0,   0,   0,   0,   0,   41,  42,  43,
+    2,   6,   10,  13,  14,  15,  16,  17,  3,   7,   11,  24,  3,   7,   11,
+    24,  4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   0,   0,
+    44,  45,  2,   6,   10,  13,  14,  15,  16,  17,  46,  47,  48,  49,  50,
+    51,  52,  57,  4,   8,   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,   53,  54,  55,  56,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,
+    68,  69,  70,  71,  72,  74,  0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   73,  75,  76,  77,  78,  79,  80,  81,  82,
+    83,  84,  85,  86,  87,  88,  89,  90,  3,   7,   11,  24,  3,   7,   11,
+    24,  3,   7,   11,  24,  0,   0,   0,   0,   3,   7,   11,  24,  3,   7,
+    11,  24,  4,   8,   4,   8,   0,   0,   0,   92,  0,   0,   0,   93,  94,
+    95,  96,  97,  98,  99,  100, 101, 102, 103, 104, 105, 3,   7,   11,  24,
+    4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,
+    8,   4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 4,
+    8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   0,   0,
+    0,   117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
+    131, 2,   6,   10,  13,  14,  15,  16,  17,  4,   8,   4,   8,   4,   8,
+    4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   148,
+    149, 150, 151, 3,   7,   11,  24,  4,   8,   4,   8,   0,   0,   0,   0,
+    0,   0,   152, 153, 3,   7,   11,  24,  3,   7,   11,  24,  3,   7,   11,
+    24,  154, 155, 156, 164, 3,   7,   11,  24,  3,   7,   11,  24,  3,   7,
+    11,  24,  4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    157, 158, 159, 160, 161, 162, 163, 165, 166, 167, 168, 169, 170, 171, 172,
+    173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187,
+    188, 189, 190, 191, 192, 193, 194, 195, 196, 4,   8,   4,   8,   4,   8,
+    4,   8,   4,   8,   4,   8,   4,   8,   197, 198, 4,   8,   4,   8,   4,
+    8,   4,   8,   0,   0,   0,   0,   0,   0,   219, 220, 3,   7,   11,  24,
+    4,   8,   4,   8,   4,   8,   0,   0,   221, 222, 223, 224, 3,   7,   11,
+    24,  3,   7,   11,  24,  4,   8,   4,   8,   4,   8,   225, 228, 4,   8,
+    4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   226, 227, 229,
+    230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244,
+    4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   245, 246, 247, 248, 249, 250, 251, 252,
+    253, 254, 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   255,
+};
+/* emission table: indexed like next_tbl, ultimately gives the byte to be
+   emitted, or -1 for no byte, or 256 for end of stream
+
+   generated by gen_hpack_tables.c */
+static const gpr_uint16 emit_tbl[256] = {
+    0,   1,   2,   3,   4,   5,   6,   7,   0,   8,   9,   10,  11,  12,  13,
+    14,  15,  16,  17,  18,  19,  20,  21,  22,  0,   23,  24,  25,  26,  27,
+    28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,
+    43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  0,   55,  56,
+    57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  0,
+    71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,
+    86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99,  100,
+    101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
+    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
+    131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145,
+    146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 0,
+    160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174,
+    0,   175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
+    189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
+    204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218,
+    219, 220, 221, 0,   222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
+    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247,
+    248,
+};
+/* generated by gen_hpack_tables.c */
+static const gpr_int16 emit_sub_tbl[249 * 16] = {
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+    -1,  48,  48,  48,  48,  48,  48,  48,  48,  49,  49,  49,  49,  49,  49,
+    49,  49,  48,  48,  48,  48,  49,  49,  49,  49,  50,  50,  50,  50,  97,
+    97,  97,  97,  48,  48,  49,  49,  50,  50,  97,  97,  99,  99,  101, 101,
+    105, 105, 111, 111, 48,  49,  50,  97,  99,  101, 105, 111, 115, 116, -1,
+    -1,  -1,  -1,  -1,  -1,  32,  32,  32,  32,  32,  32,  32,  32,  37,  37,
+    37,  37,  37,  37,  37,  37,  99,  99,  99,  99,  101, 101, 101, 101, 105,
+    105, 105, 105, 111, 111, 111, 111, 115, 115, 116, 116, 32,  37,  45,  46,
+    47,  51,  52,  53,  54,  55,  56,  57,  61,  61,  61,  61,  61,  61,  61,
+    61,  65,  65,  65,  65,  65,  65,  65,  65,  115, 115, 115, 115, 116, 116,
+    116, 116, 32,  32,  37,  37,  45,  45,  46,  46,  61,  65,  95,  98,  100,
+    102, 103, 104, 108, 109, 110, 112, 114, 117, -1,  -1,  58,  58,  58,  58,
+    58,  58,  58,  58,  66,  66,  66,  66,  66,  66,  66,  66,  47,  47,  51,
+    51,  52,  52,  53,  53,  54,  54,  55,  55,  56,  56,  57,  57,  61,  61,
+    65,  65,  95,  95,  98,  98,  100, 100, 102, 102, 103, 103, 104, 104, 108,
+    108, 109, 109, 110, 110, 112, 112, 114, 114, 117, 117, 58,  66,  67,  68,
+    69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,
+    84,  85,  86,  87,  89,  106, 107, 113, 118, 119, 120, 121, 122, -1,  -1,
+    -1,  -1,  38,  38,  38,  38,  38,  38,  38,  38,  42,  42,  42,  42,  42,
+    42,  42,  42,  44,  44,  44,  44,  44,  44,  44,  44,  59,  59,  59,  59,
+    59,  59,  59,  59,  88,  88,  88,  88,  88,  88,  88,  88,  90,  90,  90,
+    90,  90,  90,  90,  90,  33,  33,  34,  34,  40,  40,  41,  41,  63,  63,
+    39,  43,  124, -1,  -1,  -1,  35,  35,  35,  35,  35,  35,  35,  35,  62,
+    62,  62,  62,  62,  62,  62,  62,  0,   0,   0,   0,   36,  36,  36,  36,
+    64,  64,  64,  64,  91,  91,  91,  91,  69,  69,  69,  69,  69,  69,  69,
+    69,  70,  70,  70,  70,  70,  70,  70,  70,  71,  71,  71,  71,  71,  71,
+    71,  71,  72,  72,  72,  72,  72,  72,  72,  72,  73,  73,  73,  73,  73,
+    73,  73,  73,  74,  74,  74,  74,  74,  74,  74,  74,  75,  75,  75,  75,
+    75,  75,  75,  75,  76,  76,  76,  76,  76,  76,  76,  76,  77,  77,  77,
+    77,  77,  77,  77,  77,  78,  78,  78,  78,  78,  78,  78,  78,  79,  79,
+    79,  79,  79,  79,  79,  79,  80,  80,  80,  80,  80,  80,  80,  80,  81,
+    81,  81,  81,  81,  81,  81,  81,  82,  82,  82,  82,  82,  82,  82,  82,
+    83,  83,  83,  83,  83,  83,  83,  83,  84,  84,  84,  84,  84,  84,  84,
+    84,  85,  85,  85,  85,  85,  85,  85,  85,  86,  86,  86,  86,  86,  86,
+    86,  86,  87,  87,  87,  87,  87,  87,  87,  87,  89,  89,  89,  89,  89,
+    89,  89,  89,  106, 106, 106, 106, 106, 106, 106, 106, 107, 107, 107, 107,
+    107, 107, 107, 107, 113, 113, 113, 113, 113, 113, 113, 113, 118, 118, 118,
+    118, 118, 118, 118, 118, 119, 119, 119, 119, 119, 119, 119, 119, 120, 120,
+    120, 120, 120, 120, 120, 120, 121, 121, 121, 121, 121, 121, 121, 121, 122,
+    122, 122, 122, 122, 122, 122, 122, 38,  38,  38,  38,  42,  42,  42,  42,
+    44,  44,  44,  44,  59,  59,  59,  59,  88,  88,  88,  88,  90,  90,  90,
+    90,  33,  34,  40,  41,  63,  -1,  -1,  -1,  39,  39,  39,  39,  39,  39,
+    39,  39,  43,  43,  43,  43,  43,  43,  43,  43,  124, 124, 124, 124, 124,
+    124, 124, 124, 35,  35,  35,  35,  62,  62,  62,  62,  0,   0,   36,  36,
+    64,  64,  91,  91,  93,  93,  126, 126, 94,  125, -1,  -1,  60,  60,  60,
+    60,  60,  60,  60,  60,  96,  96,  96,  96,  96,  96,  96,  96,  123, 123,
+    123, 123, 123, 123, 123, 123, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  92,
+    92,  92,  92,  92,  92,  92,  92,  195, 195, 195, 195, 195, 195, 195, 195,
+    208, 208, 208, 208, 208, 208, 208, 208, 128, 128, 128, 128, 130, 130, 130,
+    130, 131, 131, 131, 131, 162, 162, 162, 162, 184, 184, 184, 184, 194, 194,
+    194, 194, 224, 224, 224, 224, 226, 226, 226, 226, 153, 153, 161, 161, 167,
+    167, 172, 172, 176, 176, 177, 177, 179, 179, 209, 209, 216, 216, 217, 217,
+    227, 227, 229, 229, 230, 230, 129, 132, 133, 134, 136, 146, 154, 156, 160,
+    163, 164, 169, 170, 173, 178, 181, 185, 186, 187, 189, 190, 196, 198, 228,
+    232, 233, -1,  -1,  -1,  -1,  1,   1,   1,   1,   1,   1,   1,   1,   135,
+    135, 135, 135, 135, 135, 135, 135, 137, 137, 137, 137, 137, 137, 137, 137,
+    138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 139, 139, 139, 139, 139,
+    139, 140, 140, 140, 140, 140, 140, 140, 140, 141, 141, 141, 141, 141, 141,
+    141, 141, 143, 143, 143, 143, 143, 143, 143, 143, 147, 147, 147, 147, 147,
+    147, 147, 147, 149, 149, 149, 149, 149, 149, 149, 149, 150, 150, 150, 150,
+    150, 150, 150, 150, 151, 151, 151, 151, 151, 151, 151, 151, 152, 152, 152,
+    152, 152, 152, 152, 152, 155, 155, 155, 155, 155, 155, 155, 155, 157, 157,
+    157, 157, 157, 157, 157, 157, 158, 158, 158, 158, 158, 158, 158, 158, 165,
+    165, 165, 165, 165, 165, 165, 165, 166, 166, 166, 166, 166, 166, 166, 166,
+    168, 168, 168, 168, 168, 168, 168, 168, 174, 174, 174, 174, 174, 174, 174,
+    174, 175, 175, 175, 175, 175, 175, 175, 175, 180, 180, 180, 180, 180, 180,
+    180, 180, 182, 182, 182, 182, 182, 182, 182, 182, 183, 183, 183, 183, 183,
+    183, 183, 183, 188, 188, 188, 188, 188, 188, 188, 188, 191, 191, 191, 191,
+    191, 191, 191, 191, 197, 197, 197, 197, 197, 197, 197, 197, 231, 231, 231,
+    231, 231, 231, 231, 231, 239, 239, 239, 239, 239, 239, 239, 239, 9,   9,
+    9,   9,   142, 142, 142, 142, 144, 144, 144, 144, 145, 145, 145, 145, 148,
+    148, 148, 148, 159, 159, 159, 159, 171, 171, 171, 171, 206, 206, 206, 206,
+    215, 215, 215, 215, 225, 225, 225, 225, 236, 236, 236, 236, 237, 237, 237,
+    237, 199, 199, 207, 207, 234, 234, 235, 235, 192, 193, 200, 201, 202, 205,
+    210, 213, 218, 219, 238, 240, 242, 243, 255, -1,  203, 203, 203, 203, 203,
+    203, 203, 203, 204, 204, 204, 204, 204, 204, 204, 204, 211, 211, 211, 211,
+    211, 211, 211, 211, 212, 212, 212, 212, 212, 212, 212, 212, 214, 214, 214,
+    214, 214, 214, 214, 214, 221, 221, 221, 221, 221, 221, 221, 221, 222, 222,
+    222, 222, 222, 222, 222, 222, 223, 223, 223, 223, 223, 223, 223, 223, 241,
+    241, 241, 241, 241, 241, 241, 241, 244, 244, 244, 244, 244, 244, 244, 244,
+    245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246,
+    246, 247, 247, 247, 247, 247, 247, 247, 247, 248, 248, 248, 248, 248, 248,
+    248, 248, 250, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251,
+    251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253,
+    253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 2,   2,   2,
+    2,   3,   3,   3,   3,   4,   4,   4,   4,   5,   5,   5,   5,   6,   6,
+    6,   6,   7,   7,   7,   7,   8,   8,   8,   8,   11,  11,  11,  11,  12,
+    12,  12,  12,  14,  14,  14,  14,  15,  15,  15,  15,  16,  16,  16,  16,
+    17,  17,  17,  17,  18,  18,  18,  18,  19,  19,  19,  19,  20,  20,  20,
+    20,  21,  21,  21,  21,  23,  23,  23,  23,  24,  24,  24,  24,  25,  25,
+    25,  25,  26,  26,  26,  26,  27,  27,  27,  27,  28,  28,  28,  28,  29,
+    29,  29,  29,  30,  30,  30,  30,  31,  31,  31,  31,  127, 127, 127, 127,
+    220, 220, 220, 220, 249, 249, 249, 249, 10,  13,  22,  256, 93,  93,  93,
+    93,  126, 126, 126, 126, 94,  94,  125, 125, 60,  96,  123, -1,  92,  195,
+    208, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  128,
+    128, 128, 128, 128, 128, 128, 128, 130, 130, 130, 130, 130, 130, 130, 130,
+    131, 131, 131, 131, 131, 131, 131, 131, 162, 162, 162, 162, 162, 162, 162,
+    162, 184, 184, 184, 184, 184, 184, 184, 184, 194, 194, 194, 194, 194, 194,
+    194, 194, 224, 224, 224, 224, 224, 224, 224, 224, 226, 226, 226, 226, 226,
+    226, 226, 226, 153, 153, 153, 153, 161, 161, 161, 161, 167, 167, 167, 167,
+    172, 172, 172, 172, 176, 176, 176, 176, 177, 177, 177, 177, 179, 179, 179,
+    179, 209, 209, 209, 209, 216, 216, 216, 216, 217, 217, 217, 217, 227, 227,
+    227, 227, 229, 229, 229, 229, 230, 230, 230, 230, 129, 129, 132, 132, 133,
+    133, 134, 134, 136, 136, 146, 146, 154, 154, 156, 156, 160, 160, 163, 163,
+    164, 164, 169, 169, 170, 170, 173, 173, 178, 178, 181, 181, 185, 185, 186,
+    186, 187, 187, 189, 189, 190, 190, 196, 196, 198, 198, 228, 228, 232, 232,
+    233, 233, 1,   135, 137, 138, 139, 140, 141, 143, 147, 149, 150, 151, 152,
+    155, 157, 158, 165, 166, 168, 174, 175, 180, 182, 183, 188, 191, 197, 231,
+    239, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  9,   9,   9,
+    9,   9,   9,   9,   9,   142, 142, 142, 142, 142, 142, 142, 142, 144, 144,
+    144, 144, 144, 144, 144, 144, 145, 145, 145, 145, 145, 145, 145, 145, 148,
+    148, 148, 148, 148, 148, 148, 148, 159, 159, 159, 159, 159, 159, 159, 159,
+    171, 171, 171, 171, 171, 171, 171, 171, 206, 206, 206, 206, 206, 206, 206,
+    206, 215, 215, 215, 215, 215, 215, 215, 215, 225, 225, 225, 225, 225, 225,
+    225, 225, 236, 236, 236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 237,
+    237, 237, 237, 199, 199, 199, 199, 207, 207, 207, 207, 234, 234, 234, 234,
+    235, 235, 235, 235, 192, 192, 193, 193, 200, 200, 201, 201, 202, 202, 205,
+    205, 210, 210, 213, 213, 218, 218, 219, 219, 238, 238, 240, 240, 242, 242,
+    243, 243, 255, 255, 203, 204, 211, 212, 214, 221, 222, 223, 241, 244, 245,
+    246, 247, 248, 250, 251, 252, 253, 254, -1,  -1,  -1,  -1,  -1,  -1,  -1,
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  2,   2,   2,   2,   2,   2,   2,
+    2,   3,   3,   3,   3,   3,   3,   3,   3,   4,   4,   4,   4,   4,   4,
+    4,   4,   5,   5,   5,   5,   5,   5,   5,   5,   6,   6,   6,   6,   6,
+    6,   6,   6,   7,   7,   7,   7,   7,   7,   7,   7,   8,   8,   8,   8,
+    8,   8,   8,   8,   11,  11,  11,  11,  11,  11,  11,  11,  12,  12,  12,
+    12,  12,  12,  12,  12,  14,  14,  14,  14,  14,  14,  14,  14,  15,  15,
+    15,  15,  15,  15,  15,  15,  16,  16,  16,  16,  16,  16,  16,  16,  17,
+    17,  17,  17,  17,  17,  17,  17,  18,  18,  18,  18,  18,  18,  18,  18,
+    19,  19,  19,  19,  19,  19,  19,  19,  20,  20,  20,  20,  20,  20,  20,
+    20,  21,  21,  21,  21,  21,  21,  21,  21,  23,  23,  23,  23,  23,  23,
+    23,  23,  24,  24,  24,  24,  24,  24,  24,  24,  25,  25,  25,  25,  25,
+    25,  25,  25,  26,  26,  26,  26,  26,  26,  26,  26,  27,  27,  27,  27,
+    27,  27,  27,  27,  28,  28,  28,  28,  28,  28,  28,  28,  29,  29,  29,
+    29,  29,  29,  29,  29,  30,  30,  30,  30,  30,  30,  30,  30,  31,  31,
+    31,  31,  31,  31,  31,  31,  127, 127, 127, 127, 127, 127, 127, 127, 220,
+    220, 220, 220, 220, 220, 220, 220, 249, 249, 249, 249, 249, 249, 249, 249,
+    10,  10,  13,  13,  22,  22,  256, 256, 67,  67,  67,  67,  67,  67,  67,
+    67,  68,  68,  68,  68,  68,  68,  68,  68,  95,  95,  95,  95,  95,  95,
+    95,  95,  98,  98,  98,  98,  98,  98,  98,  98,  100, 100, 100, 100, 100,
+    100, 100, 100, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 103,
+    103, 103, 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, 108, 108, 108,
+    108, 108, 108, 108, 108, 109, 109, 109, 109, 109, 109, 109, 109, 110, 110,
+    110, 110, 110, 110, 110, 110, 112, 112, 112, 112, 112, 112, 112, 112, 114,
+    114, 114, 114, 114, 114, 114, 114, 117, 117, 117, 117, 117, 117, 117, 117,
+    58,  58,  58,  58,  66,  66,  66,  66,  67,  67,  67,  67,  68,  68,  68,
+    68,  69,  69,  69,  69,  70,  70,  70,  70,  71,  71,  71,  71,  72,  72,
+    72,  72,  73,  73,  73,  73,  74,  74,  74,  74,  75,  75,  75,  75,  76,
+    76,  76,  76,  77,  77,  77,  77,  78,  78,  78,  78,  79,  79,  79,  79,
+    80,  80,  80,  80,  81,  81,  81,  81,  82,  82,  82,  82,  83,  83,  83,
+    83,  84,  84,  84,  84,  85,  85,  85,  85,  86,  86,  86,  86,  87,  87,
+    87,  87,  89,  89,  89,  89,  106, 106, 106, 106, 107, 107, 107, 107, 113,
+    113, 113, 113, 118, 118, 118, 118, 119, 119, 119, 119, 120, 120, 120, 120,
+    121, 121, 121, 121, 122, 122, 122, 122, 38,  38,  42,  42,  44,  44,  59,
+    59,  88,  88,  90,  90,  -1,  -1,  -1,  -1,  33,  33,  33,  33,  33,  33,
+    33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  40,  40,  40,  40,  40,
+    40,  40,  40,  41,  41,  41,  41,  41,  41,  41,  41,  63,  63,  63,  63,
+    63,  63,  63,  63,  39,  39,  39,  39,  43,  43,  43,  43,  124, 124, 124,
+    124, 35,  35,  62,  62,  0,   36,  64,  91,  93,  126, -1,  -1,  94,  94,
+    94,  94,  94,  94,  94,  94,  125, 125, 125, 125, 125, 125, 125, 125, 60,
+    60,  60,  60,  96,  96,  96,  96,  123, 123, 123, 123, -1,  -1,  -1,  -1,
+    92,  92,  92,  92,  195, 195, 195, 195, 208, 208, 208, 208, 128, 128, 130,
+    130, 131, 131, 162, 162, 184, 184, 194, 194, 224, 224, 226, 226, 153, 161,
+    167, 172, 176, 177, 179, 209, 216, 217, 227, 229, 230, -1,  -1,  -1,  -1,
+    -1,  -1,  -1,  129, 129, 129, 129, 129, 129, 129, 129, 132, 132, 132, 132,
+    132, 132, 132, 132, 133, 133, 133, 133, 133, 133, 133, 133, 134, 134, 134,
+    134, 134, 134, 134, 134, 136, 136, 136, 136, 136, 136, 136, 136, 146, 146,
+    146, 146, 146, 146, 146, 146, 154, 154, 154, 154, 154, 154, 154, 154, 156,
+    156, 156, 156, 156, 156, 156, 156, 160, 160, 160, 160, 160, 160, 160, 160,
+    163, 163, 163, 163, 163, 163, 163, 163, 164, 164, 164, 164, 164, 164, 164,
+    164, 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170,
+    170, 170, 173, 173, 173, 173, 173, 173, 173, 173, 178, 178, 178, 178, 178,
+    178, 178, 178, 181, 181, 181, 181, 181, 181, 181, 181, 185, 185, 185, 185,
+    185, 185, 185, 185, 186, 186, 186, 186, 186, 186, 186, 186, 187, 187, 187,
+    187, 187, 187, 187, 187, 189, 189, 189, 189, 189, 189, 189, 189, 190, 190,
+    190, 190, 190, 190, 190, 190, 196, 196, 196, 196, 196, 196, 196, 196, 198,
+    198, 198, 198, 198, 198, 198, 198, 228, 228, 228, 228, 228, 228, 228, 228,
+    232, 232, 232, 232, 232, 232, 232, 232, 233, 233, 233, 233, 233, 233, 233,
+    233, 1,   1,   1,   1,   135, 135, 135, 135, 137, 137, 137, 137, 138, 138,
+    138, 138, 139, 139, 139, 139, 140, 140, 140, 140, 141, 141, 141, 141, 143,
+    143, 143, 143, 147, 147, 147, 147, 149, 149, 149, 149, 150, 150, 150, 150,
+    151, 151, 151, 151, 152, 152, 152, 152, 155, 155, 155, 155, 157, 157, 157,
+    157, 158, 158, 158, 158, 165, 165, 165, 165, 166, 166, 166, 166, 168, 168,
+    168, 168, 174, 174, 174, 174, 175, 175, 175, 175, 180, 180, 180, 180, 182,
+    182, 182, 182, 183, 183, 183, 183, 188, 188, 188, 188, 191, 191, 191, 191,
+    197, 197, 197, 197, 231, 231, 231, 231, 239, 239, 239, 239, 9,   9,   142,
+    142, 144, 144, 145, 145, 148, 148, 159, 159, 171, 171, 206, 206, 215, 215,
+    225, 225, 236, 236, 237, 237, 199, 207, 234, 235, 192, 192, 192, 192, 192,
+    192, 192, 192, 193, 193, 193, 193, 193, 193, 193, 193, 200, 200, 200, 200,
+    200, 200, 200, 200, 201, 201, 201, 201, 201, 201, 201, 201, 202, 202, 202,
+    202, 202, 202, 202, 202, 205, 205, 205, 205, 205, 205, 205, 205, 210, 210,
+    210, 210, 210, 210, 210, 210, 213, 213, 213, 213, 213, 213, 213, 213, 218,
+    218, 218, 218, 218, 218, 218, 218, 219, 219, 219, 219, 219, 219, 219, 219,
+    238, 238, 238, 238, 238, 238, 238, 238, 240, 240, 240, 240, 240, 240, 240,
+    240, 242, 242, 242, 242, 242, 242, 242, 242, 243, 243, 243, 243, 243, 243,
+    243, 243, 255, 255, 255, 255, 255, 255, 255, 255, 203, 203, 203, 203, 204,
+    204, 204, 204, 211, 211, 211, 211, 212, 212, 212, 212, 214, 214, 214, 214,
+    221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 241, 241, 241,
+    241, 244, 244, 244, 244, 245, 245, 245, 245, 246, 246, 246, 246, 247, 247,
+    247, 247, 248, 248, 248, 248, 250, 250, 250, 250, 251, 251, 251, 251, 252,
+    252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 2,   2,   3,   3,
+    4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   11,  11,  12,  12,  14,
+    14,  15,  15,  16,  16,  17,  17,  18,  18,  19,  19,  20,  20,  21,  21,
+    23,  23,  24,  24,  25,  25,  26,  26,  27,  27,  28,  28,  29,  29,  30,
+    30,  31,  31,  127, 127, 220, 220, 249, 249, -1,  -1,  10,  10,  10,  10,
+    10,  10,  10,  10,  13,  13,  13,  13,  13,  13,  13,  13,  22,  22,  22,
+    22,  22,  22,  22,  22,  256, 256, 256, 256, 256, 256, 256, 256, 45,  45,
+    45,  45,  45,  45,  45,  45,  46,  46,  46,  46,  46,  46,  46,  46,  47,
+    47,  47,  47,  47,  47,  47,  47,  51,  51,  51,  51,  51,  51,  51,  51,
+    52,  52,  52,  52,  52,  52,  52,  52,  53,  53,  53,  53,  53,  53,  53,
+    53,  54,  54,  54,  54,  54,  54,  54,  54,  55,  55,  55,  55,  55,  55,
+    55,  55,  56,  56,  56,  56,  56,  56,  56,  56,  57,  57,  57,  57,  57,
+    57,  57,  57,  50,  50,  50,  50,  50,  50,  50,  50,  97,  97,  97,  97,
+    97,  97,  97,  97,  99,  99,  99,  99,  99,  99,  99,  99,  101, 101, 101,
+    101, 101, 101, 101, 101, 105, 105, 105, 105, 105, 105, 105, 105, 111, 111,
+    111, 111, 111, 111, 111, 111, 115, 115, 115, 115, 115, 115, 115, 115, 116,
+    116, 116, 116, 116, 116, 116, 116, 32,  32,  32,  32,  37,  37,  37,  37,
+    45,  45,  45,  45,  46,  46,  46,  46,  47,  47,  47,  47,  51,  51,  51,
+    51,  52,  52,  52,  52,  53,  53,  53,  53,  54,  54,  54,  54,  55,  55,
+    55,  55,  56,  56,  56,  56,  57,  57,  57,  57,  61,  61,  61,  61,  65,
+    65,  65,  65,  95,  95,  95,  95,  98,  98,  98,  98,  100, 100, 100, 100,
+    102, 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, 104, 108, 108, 108,
+    108, 109, 109, 109, 109, 110, 110, 110, 110, 112, 112, 112, 112, 114, 114,
+    114, 114, 117, 117, 117, 117, 58,  58,  66,  66,  67,  67,  68,  68,  69,
+    69,  70,  70,  71,  71,  72,  72,  73,  73,  74,  74,  75,  75,  76,  76,
+    77,  77,  78,  78,  79,  79,  80,  80,  81,  81,  82,  82,  83,  83,  84,
+    84,  85,  85,  86,  86,  87,  87,  89,  89,  106, 106, 107, 107, 113, 113,
+    118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 38,  42,  44,  59,  88,
+    90,  -1,  -1,  33,  33,  33,  33,  34,  34,  34,  34,  40,  40,  40,  40,
+    41,  41,  41,  41,  63,  63,  63,  63,  39,  39,  43,  43,  124, 124, 35,
+    62,  -1,  -1,  -1,  -1,  0,   0,   0,   0,   0,   0,   0,   0,   36,  36,
+    36,  36,  36,  36,  36,  36,  64,  64,  64,  64,  64,  64,  64,  64,  91,
+    91,  91,  91,  91,  91,  91,  91,  93,  93,  93,  93,  93,  93,  93,  93,
+    126, 126, 126, 126, 126, 126, 126, 126, 94,  94,  94,  94,  125, 125, 125,
+    125, 60,  60,  96,  96,  123, 123, -1,  -1,  92,  92,  195, 195, 208, 208,
+    128, 130, 131, 162, 184, 194, 224, 226, -1,  -1,  153, 153, 153, 153, 153,
+    153, 153, 153, 161, 161, 161, 161, 161, 161, 161, 161, 167, 167, 167, 167,
+    167, 167, 167, 167, 172, 172, 172, 172, 172, 172, 172, 172, 176, 176, 176,
+    176, 176, 176, 176, 176, 177, 177, 177, 177, 177, 177, 177, 177, 179, 179,
+    179, 179, 179, 179, 179, 179, 209, 209, 209, 209, 209, 209, 209, 209, 216,
+    216, 216, 216, 216, 216, 216, 216, 217, 217, 217, 217, 217, 217, 217, 217,
+    227, 227, 227, 227, 227, 227, 227, 227, 229, 229, 229, 229, 229, 229, 229,
+    229, 230, 230, 230, 230, 230, 230, 230, 230, 129, 129, 129, 129, 132, 132,
+    132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 136, 136, 136, 136, 146,
+    146, 146, 146, 154, 154, 154, 154, 156, 156, 156, 156, 160, 160, 160, 160,
+    163, 163, 163, 163, 164, 164, 164, 164, 169, 169, 169, 169, 170, 170, 170,
+    170, 173, 173, 173, 173, 178, 178, 178, 178, 181, 181, 181, 181, 185, 185,
+    185, 185, 186, 186, 186, 186, 187, 187, 187, 187, 189, 189, 189, 189, 190,
+    190, 190, 190, 196, 196, 196, 196, 198, 198, 198, 198, 228, 228, 228, 228,
+    232, 232, 232, 232, 233, 233, 233, 233, 1,   1,   135, 135, 137, 137, 138,
+    138, 139, 139, 140, 140, 141, 141, 143, 143, 147, 147, 149, 149, 150, 150,
+    151, 151, 152, 152, 155, 155, 157, 157, 158, 158, 165, 165, 166, 166, 168,
+    168, 174, 174, 175, 175, 180, 180, 182, 182, 183, 183, 188, 188, 191, 191,
+    197, 197, 231, 231, 239, 239, 9,   142, 144, 145, 148, 159, 171, 206, 215,
+    225, 236, 237, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  199, 199,
+    199, 199, 199, 199, 199, 199, 207, 207, 207, 207, 207, 207, 207, 207, 234,
+    234, 234, 234, 234, 234, 234, 234, 235, 235, 235, 235, 235, 235, 235, 235,
+    192, 192, 192, 192, 193, 193, 193, 193, 200, 200, 200, 200, 201, 201, 201,
+    201, 202, 202, 202, 202, 205, 205, 205, 205, 210, 210, 210, 210, 213, 213,
+    213, 213, 218, 218, 218, 218, 219, 219, 219, 219, 238, 238, 238, 238, 240,
+    240, 240, 240, 242, 242, 242, 242, 243, 243, 243, 243, 255, 255, 255, 255,
+    203, 203, 204, 204, 211, 211, 212, 212, 214, 214, 221, 221, 222, 222, 223,
+    223, 241, 241, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 250, 250,
+    251, 251, 252, 252, 253, 253, 254, 254, 2,   3,   4,   5,   6,   7,   8,
+    11,  12,  14,  15,  16,  17,  18,  19,  20,  21,  23,  24,  25,  26,  27,
+    28,  29,  30,  31,  127, 220, 249, -1,  10,  10,  10,  10,  13,  13,  13,
+    13,  22,  22,  22,  22,  256, 256, 256, 256,
+};
+
+/* emission helpers */
+static void on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
+                   int add_to_table) {
+  if (add_to_table) {
+    grpc_mdelem_ref(md);
+    grpc_chttp2_hptbl_add(&p->table, md);
+  }
+  p->on_header(p->on_header_user_data, md);
+}
+
+static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p,
+                               grpc_chttp2_hpack_parser_string *str) {
+  grpc_mdstr *s = grpc_mdstr_from_buffer(p->table.mdctx, (gpr_uint8 *)str->str,
+                                         str->length);
+  str->length = 0;
+  return s;
+}
+
+/* jump to the next state */
+static int parse_next(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                      const gpr_uint8 *end) {
+  p->state = *p->next_state++;
+  return p->state(p, cur, end);
+}
+
+/* begin parsing a header: all functionality is encoded into lookup tables
+   above */
+static int parse_begin(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                       const gpr_uint8 *end) {
+  if (cur == end) {
+    p->state = parse_begin;
+    return 1;
+  }
+
+  return first_byte_action[first_byte_lut[*cur]](p, cur, end);
+}
+
+/* stream dependency and prioritization data: we just skip it */
+static int parse_stream_weight(grpc_chttp2_hpack_parser *p,
+                               const gpr_uint8 *cur, const gpr_uint8 *end) {
+  if (cur == end) {
+    p->state = parse_stream_weight;
+    return 1;
+  }
+
+  return parse_begin(p, cur + 1, end);
+}
+
+static int parse_stream_dep3(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                             const gpr_uint8 *end) {
+  if (cur == end) {
+    p->state = parse_stream_dep3;
+    return 1;
+  }
+
+  return parse_stream_weight(p, cur + 1, end);
+}
+
+static int parse_stream_dep2(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                             const gpr_uint8 *end) {
+  if (cur == end) {
+    p->state = parse_stream_dep2;
+    return 1;
+  }
+
+  return parse_stream_dep3(p, cur + 1, end);
+}
+
+static int parse_stream_dep1(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                             const gpr_uint8 *end) {
+  if (cur == end) {
+    p->state = parse_stream_dep1;
+    return 1;
+  }
+
+  return parse_stream_dep2(p, cur + 1, end);
+}
+
+static int parse_stream_dep0(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                             const gpr_uint8 *end) {
+  if (cur == end) {
+    p->state = parse_stream_dep0;
+    return 1;
+  }
+
+  return parse_stream_dep1(p, cur + 1, end);
+}
+
+/* emit an indexed field; for now just logs it to console; jumps to
+   begin the next field on completion */
+static int finish_indexed_field(grpc_chttp2_hpack_parser *p,
+                                const gpr_uint8 *cur, const gpr_uint8 *end) {
+  grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+  grpc_mdelem_ref(md);
+  on_hdr(p, md, 0);
+  return parse_begin(p, cur, end);
+}
+
+/* parse an indexed field with index < 127 */
+static int parse_indexed_field(grpc_chttp2_hpack_parser *p,
+                               const gpr_uint8 *cur, const gpr_uint8 *end) {
+  p->index = (*cur) & 0x7f;
+  return finish_indexed_field(p, cur + 1, end);
+}
+
+/* parse an indexed field with index >= 127 */
+static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
+                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      finish_indexed_field};
+  p->next_state = and_then;
+  p->index = 0x7f;
+  p->parsing.value = &p->index;
+  return parse_value0(p, cur + 1, end);
+}
+
+/* finish a literal header with incremental indexing: just log, and jump to '
+   begin */
+static int finish_lithdr_incidx(grpc_chttp2_hpack_parser *p,
+                                const gpr_uint8 *cur, const gpr_uint8 *end) {
+  grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+  on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
+                                              grpc_mdstr_ref(md->key),
+                                              take_string(p, &p->value)),
+         1);
+  return parse_begin(p, cur, end);
+}
+
+/* finish a literal header with incremental indexing with no index */
+static int finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+                                  const gpr_uint8 *cur, const gpr_uint8 *end) {
+  on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
+                                              take_string(p, &p->key),
+                                              take_string(p, &p->value)),
+         1);
+  return parse_begin(p, cur, end);
+}
+
+/* parse a literal header with incremental indexing; index < 63 */
+static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p,
+                               const gpr_uint8 *cur, const gpr_uint8 *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_value_string, finish_lithdr_incidx};
+  p->next_state = and_then;
+  p->index = (*cur) & 0x3f;
+  return parse_string_prefix(p, cur + 1, end);
+}
+
+/* parse a literal header with incremental indexing; index >= 63 */
+static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
+                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_string_prefix, parse_value_string, finish_lithdr_incidx};
+  p->next_state = and_then;
+  p->index = 0x3f;
+  p->parsing.value = &p->index;
+  return parse_value0(p, cur + 1, end);
+}
+
+/* parse a literal header with incremental indexing; index = 0 */
+static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_key_string, parse_string_prefix, parse_value_string,
+      finish_lithdr_incidx_v};
+  p->next_state = and_then;
+  return parse_string_prefix(p, cur + 1, end);
+}
+
+/* finish a literal header without incremental indexing */
+static int finish_lithdr_notidx(grpc_chttp2_hpack_parser *p,
+                                const gpr_uint8 *cur, const gpr_uint8 *end) {
+  grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+  on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
+                                              grpc_mdstr_ref(md->key),
+                                              take_string(p, &p->value)),
+         0);
+  return parse_begin(p, cur, end);
+}
+
+/* finish a literal header without incremental indexing with index = 0 */
+static int finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+                                  const gpr_uint8 *cur, const gpr_uint8 *end) {
+  on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
+                                              take_string(p, &p->key),
+                                              take_string(p, &p->value)),
+         0);
+  return parse_begin(p, cur, end);
+}
+
+/* parse a literal header without incremental indexing; index < 15 */
+static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p,
+                               const gpr_uint8 *cur, const gpr_uint8 *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_value_string, finish_lithdr_notidx};
+  p->next_state = and_then;
+  p->index = (*cur) & 0xf;
+  return parse_string_prefix(p, cur + 1, end);
+}
+
+/* parse a literal header without incremental indexing; index >= 15 */
+static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
+                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_string_prefix, parse_value_string, finish_lithdr_notidx};
+  p->next_state = and_then;
+  p->index = 0xf;
+  p->parsing.value = &p->index;
+  return parse_value0(p, cur + 1, end);
+}
+
+/* parse a literal header without incremental indexing; index == 0 */
+static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_key_string, parse_string_prefix, parse_value_string,
+      finish_lithdr_notidx_v};
+  p->next_state = and_then;
+  return parse_string_prefix(p, cur + 1, end);
+}
+
+/* finish a literal header that is never indexed */
+static int finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
+                                const gpr_uint8 *cur, const gpr_uint8 *end) {
+  grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+  on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
+                                              grpc_mdstr_ref(md->key),
+                                              take_string(p, &p->value)),
+         0);
+  return parse_begin(p, cur, end);
+}
+
+/* finish a literal header that is never indexed with an extra value */
+static int finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+                                  const gpr_uint8 *cur, const gpr_uint8 *end) {
+  on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
+                                              take_string(p, &p->key),
+                                              take_string(p, &p->value)),
+         0);
+  return parse_begin(p, cur, end);
+}
+
+/* parse a literal header that is never indexed; index < 15 */
+static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
+                               const gpr_uint8 *cur, const gpr_uint8 *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_value_string, finish_lithdr_nvridx};
+  p->next_state = and_then;
+  p->index = (*cur) & 0xf;
+  return parse_string_prefix(p, cur + 1, end);
+}
+
+/* parse a literal header that is never indexed; index >= 15 */
+static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
+                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_string_prefix, parse_value_string, finish_lithdr_nvridx};
+  p->next_state = and_then;
+  p->index = 0xf;
+  p->parsing.value = &p->index;
+  return parse_value0(p, cur + 1, end);
+}
+
+/* parse a literal header that is never indexed; index == 0 */
+static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_key_string, parse_string_prefix, parse_value_string,
+      finish_lithdr_nvridx_v};
+  p->next_state = and_then;
+  return parse_string_prefix(p, cur + 1, end);
+}
+
+/* finish parsing a max table size change */
+static int finish_max_tbl_size(grpc_chttp2_hpack_parser *p,
+                               const gpr_uint8 *cur, const gpr_uint8 *end) {
+  gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index);
+  abort(); /* not implemented */
+  return parse_begin(p, cur, end);
+}
+
+/* parse a max table size change, max size < 15 */
+static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                              const gpr_uint8 *end) {
+  p->index = (*cur) & 0xf;
+  return finish_max_tbl_size(p, cur + 1, end);
+}
+
+/* parse a max table size change, max size >= 15 */
+static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p,
+                                const gpr_uint8 *cur, const gpr_uint8 *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      finish_max_tbl_size};
+  p->next_state = and_then;
+  p->index = 0xf;
+  p->parsing.value = &p->index;
+  return parse_value0(p, cur + 1, end);
+}
+
+/* a parse error: jam the parse state into parse_error, and return error */
+static int parse_error(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                       const gpr_uint8 *end) {
+  p->state = parse_error;
+  return 0;
+}
+
+/* parse the 1st byte of a varint into p->parsing.value
+   no overflow is possible */
+static int parse_value0(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                        const gpr_uint8 *end) {
+  if (cur == end) {
+    p->state = parse_value0;
+    return 1;
+  }
+
+  *p->parsing.value += (*cur) & 0x7f;
+
+  if ((*cur) & 0x80) {
+    return parse_value1(p, cur + 1, end);
+  } else {
+    return parse_next(p, cur + 1, end);
+  }
+}
+
+/* parse the 2nd byte of a varint into p->parsing.value
+   no overflow is possible */
+static int parse_value1(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                        const gpr_uint8 *end) {
+  if (cur == end) {
+    p->state = parse_value1;
+    return 1;
+  }
+
+  *p->parsing.value += (((gpr_uint32)*cur) & 0x7f) << 7;
+
+  if ((*cur) & 0x80) {
+    return parse_value2(p, cur + 1, end);
+  } else {
+    return parse_next(p, cur + 1, end);
+  }
+}
+
+/* parse the 3rd byte of a varint into p->parsing.value
+   no overflow is possible */
+static int parse_value2(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                        const gpr_uint8 *end) {
+  if (cur == end) {
+    p->state = parse_value2;
+    return 1;
+  }
+
+  *p->parsing.value += (((gpr_uint32)*cur) & 0x7f) << 14;
+
+  if ((*cur) & 0x80) {
+    return parse_value3(p, cur + 1, end);
+  } else {
+    return parse_next(p, cur + 1, end);
+  }
+}
+
+/* parse the 4th byte of a varint into p->parsing.value
+   no overflow is possible */
+static int parse_value3(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                        const gpr_uint8 *end) {
+  if (cur == end) {
+    p->state = parse_value3;
+    return 1;
+  }
+
+  *p->parsing.value += (((gpr_uint32)*cur) & 0x7f) << 21;
+
+  if ((*cur) & 0x80) {
+    return parse_value4(p, cur + 1, end);
+  } else {
+    return parse_next(p, cur + 1, end);
+  }
+}
+
+/* parse the 5th byte of a varint into p->parsing.value
+   depending on the byte, we may overflow, and care must be taken */
+static int parse_value4(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                        const gpr_uint8 *end) {
+  gpr_uint8 c;
+  gpr_uint32 cur_value;
+  gpr_uint32 add_value;
+
+  if (cur == end) {
+    p->state = parse_value4;
+    return 1;
+  }
+
+  c = (*cur) & 0x7f;
+  if (c > 0xf) {
+    goto error;
+  }
+
+  cur_value = *p->parsing.value;
+  add_value = ((gpr_uint32)c) << 28;
+  if (add_value > 0xffffffffu - cur_value) {
+    goto error;
+  }
+
+  *p->parsing.value = cur_value + add_value;
+
+  if ((*cur) & 0x80) {
+    return parse_value5up(p, cur + 1, end);
+  } else {
+    return parse_next(p, cur + 1, end);
+  }
+
+error:
+  gpr_log(GPR_ERROR,
+          "integer overflow in hpack integer decoding: have 0x%08x, "
+          "got byte 0x%02x",
+          *p->parsing.value, *cur);
+  return parse_error(p, cur, end);
+}
+
+/* parse any trailing bytes in a varint: it's possible to append an arbitrary
+   number of 0x80's and not affect the value - a zero will terminate - and
+   anything else will overflow */
+static int parse_value5up(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                          const gpr_uint8 *end) {
+  while (cur != end && *cur == 0x80) {
+    ++cur;
+  }
+
+  if (cur == end) {
+    p->state = parse_value5up;
+    return 1;
+  }
+
+  if (*cur == 0) {
+    return parse_next(p, cur + 1, end);
+  }
+
+  gpr_log(GPR_ERROR,
+          "integer overflow in hpack integer decoding: have 0x%08x, "
+          "got byte 0x%02x sometime after byte 4");
+  return parse_error(p, cur, end);
+}
+
+/* parse a string prefix */
+static int parse_string_prefix(grpc_chttp2_hpack_parser *p,
+                               const gpr_uint8 *cur, const gpr_uint8 *end) {
+  if (cur == end) {
+    p->state = parse_string_prefix;
+    return 1;
+  }
+
+  p->strlen = (*cur) & 0x7f;
+  p->huff = (*cur) >> 7;
+  if (p->strlen == 0x7f) {
+    p->parsing.value = &p->strlen;
+    return parse_value0(p, cur + 1, end);
+  } else {
+    return parse_next(p, cur + 1, end);
+  }
+}
+
+/* append some bytes to a string */
+static void append_string(grpc_chttp2_hpack_parser_string *str,
+                          const gpr_uint8 *data, size_t length) {
+  if (length + str->length > str->capacity) {
+    str->capacity = str->length + length;
+    str->str = gpr_realloc(str->str, str->capacity);
+  }
+  memcpy(str->str + str->length, data, length);
+  str->length += length;
+}
+
+/* append a null terminator to a string */
+static void finish_str(grpc_chttp2_hpack_parser_string *str) {
+  gpr_uint8 terminator = 0;
+  append_string(str, &terminator, 1);
+  str->length--; /* don't actually count the null terminator */
+}
+
+/* decode a nibble from a huffman encoded stream */
+static void huff_nibble(grpc_chttp2_hpack_parser *p, gpr_uint8 nibble) {
+  gpr_int16 emit = emit_sub_tbl[16 * emit_tbl[p->huff_state] + nibble];
+  gpr_int16 next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble];
+  if (emit != -1) {
+    if (emit >= 0 && emit < 256) {
+      gpr_uint8 c = emit;
+      append_string(p->parsing.str, &c, 1);
+    } else {
+      assert(emit == 256);
+    }
+  }
+  p->huff_state = next;
+}
+
+/* decode full bytes from a huffman encoded stream */
+static void add_huff_bytes(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                           const gpr_uint8 *end) {
+  for (; cur != end; ++cur) {
+    huff_nibble(p, *cur >> 4);
+    huff_nibble(p, *cur & 0xf);
+  }
+}
+
+/* decode some string bytes based on the current decoding mode
+   (huffman or not) */
+static void add_str_bytes(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                          const gpr_uint8 *end) {
+  if (p->huff) {
+    add_huff_bytes(p, cur, end);
+  } else {
+    append_string(p->parsing.str, cur, end - cur);
+  }
+}
+
+/* parse a string - tries to do large chunks at a time */
+static int parse_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                        const gpr_uint8 *end) {
+  size_t remaining = p->strlen - p->strgot;
+  size_t given = end - cur;
+  if (remaining <= given) {
+    add_str_bytes(p, cur, cur + remaining);
+    finish_str(p->parsing.str);
+    return parse_next(p, cur + remaining, end);
+  } else {
+    add_str_bytes(p, cur, cur + given);
+    p->strgot += given;
+    p->state = parse_string;
+    return 1;
+  }
+}
+
+/* begin parsing a string - performs setup, calls parse_string */
+static int begin_parse_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                              const gpr_uint8 *end,
+                              grpc_chttp2_hpack_parser_string *str) {
+  p->strgot = 0;
+  str->length = 0;
+  p->parsing.str = str;
+  p->huff_state = 0;
+  return parse_string(p, cur, end);
+}
+
+/* parse the key string */
+static int parse_key_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                            const gpr_uint8 *end) {
+  return begin_parse_string(p, cur, end, &p->key);
+}
+
+/* parse the value string */
+static int parse_value_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
+                              const gpr_uint8 *end) {
+  return begin_parse_string(p, cur, end, &p->value);
+}
+
+/* PUBLIC INTERFACE */
+
+static void on_header_not_set(void *user_data, grpc_mdelem *md) {
+  char *keyhex =
+      gpr_hexdump(grpc_mdstr_as_c_string(md->key),
+                  GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT);
+  char *valuehex =
+      gpr_hexdump(grpc_mdstr_as_c_string(md->value),
+                  GPR_SLICE_LENGTH(md->value->slice), GPR_HEXDUMP_PLAINTEXT);
+  gpr_log(GPR_ERROR, "on_header callback not set; key=%s value=%s", keyhex,
+          valuehex);
+  gpr_free(keyhex);
+  gpr_free(valuehex);
+  grpc_mdelem_unref(md);
+  abort();
+}
+
+void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p,
+                                   grpc_mdctx *mdctx) {
+  p->on_header = on_header_not_set;
+  p->on_header_user_data = NULL;
+  p->state = parse_begin;
+  p->key.str = NULL;
+  p->key.capacity = 0;
+  p->key.length = 0;
+  p->value.str = NULL;
+  p->value.capacity = 0;
+  p->value.length = 0;
+  grpc_chttp2_hptbl_init(&p->table, mdctx);
+}
+
+void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) {
+  GPR_ASSERT(p->state == parse_begin);
+  p->state = parse_stream_dep0;
+}
+
+void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p) {
+  grpc_chttp2_hptbl_destroy(&p->table);
+  gpr_free(p->key.str);
+  gpr_free(p->value.str);
+}
+
+int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
+                                   const gpr_uint8 *beg, const gpr_uint8 *end) {
+  /* TODO(ctiller): limit the distance of end from beg, and perform multiple
+                    steps in the event of a large chunk of data to limit
+                    stack space usage when no tail call optimization is
+                    available */
+  return p->state(p, beg, end);
+}
+
+grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
+    void *hpack_parser, grpc_chttp2_parse_state *state, gpr_slice slice,
+    int is_last) {
+  grpc_chttp2_hpack_parser *parser = hpack_parser;
+  if (!grpc_chttp2_hpack_parser_parse(parser, GPR_SLICE_START_PTR(slice),
+                                      GPR_SLICE_END_PTR(slice))) {
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  }
+  if (is_last) {
+    if (parser->is_boundary && parser->state != parse_begin) {
+      gpr_log(GPR_ERROR,
+              "end of header frame not aligned with a hpack record boundary");
+      return GRPC_CHTTP2_CONNECTION_ERROR;
+    }
+    state->metadata_boundary = parser->is_boundary;
+    state->end_of_stream = parser->is_eof;
+    state->need_flush_reads = parser->is_eof;
+    parser->on_header = on_header_not_set;
+    parser->on_header_user_data = NULL;
+    parser->is_boundary = 0xde;
+    parser->is_eof = 0xde;
+  }
+  return GRPC_CHTTP2_PARSE_OK;
+}
diff --git a/src/core/transport/chttp2/hpack_parser.h b/src/core/transport/chttp2/hpack_parser.h
new file mode 100644
index 0000000..cf68042
--- /dev/null
+++ b/src/core/transport/chttp2/hpack_parser.h
@@ -0,0 +1,108 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_HPACK_PARSER_H__
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_HPACK_PARSER_H__
+
+#include <stddef.h>
+
+#include <grpc/support/port_platform.h>
+#include "src/core/transport/chttp2/frame.h"
+#include "src/core/transport/chttp2/hpack_table.h"
+#include "src/core/transport/metadata.h"
+
+typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser;
+
+typedef int (*grpc_chttp2_hpack_parser_state)(grpc_chttp2_hpack_parser *p,
+                                              const gpr_uint8 *beg,
+                                              const gpr_uint8 *end);
+
+typedef struct {
+  char *str;
+  gpr_uint32 length;
+  gpr_uint32 capacity;
+} grpc_chttp2_hpack_parser_string;
+
+struct grpc_chttp2_hpack_parser {
+  /* user specified callback for each header output */
+  void (*on_header)(void *user_data, grpc_mdelem *md);
+  void *on_header_user_data;
+
+  /* current parse state - or a function that implements it */
+  grpc_chttp2_hpack_parser_state state;
+  /* future states dependent on the opening op code */
+  const grpc_chttp2_hpack_parser_state *next_state;
+  /* the value we're currently parsing */
+  union {
+    gpr_uint32 *value;
+    grpc_chttp2_hpack_parser_string *str;
+  } parsing;
+  /* string parameters for each chunk */
+  grpc_chttp2_hpack_parser_string key;
+  grpc_chttp2_hpack_parser_string value;
+  /* parsed index */
+  gpr_uint32 index;
+  /* length of source bytes for the currently parsing string */
+  gpr_uint32 strlen;
+  /* number of source bytes read for the currently parsing string */
+  gpr_uint32 strgot;
+  /* huffman decoding state */
+  gpr_uint16 huff_state;
+  /* is the current string huffman encoded? */
+  gpr_uint8 huff;
+  /* set by higher layers, used by grpc_chttp2_header_parser_parse to signal
+     it should append a metadata boundary at the end of frame */
+  gpr_uint8 is_boundary;
+  gpr_uint8 is_eof;
+
+  /* hpack table */
+  grpc_chttp2_hptbl table;
+};
+
+void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p,
+                                   grpc_mdctx *mdctx);
+void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p);
+
+void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p);
+
+/* returns 1 on success, 0 on error */
+int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
+                                   const gpr_uint8 *beg, const gpr_uint8 *end);
+
+/* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for
+   the transport */
+grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
+    void *hpack_parser, grpc_chttp2_parse_state *state, gpr_slice slice,
+    int is_last);
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_HPACK_PARSER_H__ */
diff --git a/src/core/transport/chttp2/hpack_table.c b/src/core/transport/chttp2/hpack_table.c
new file mode 100644
index 0000000..8f2ebec
--- /dev/null
+++ b/src/core/transport/chttp2/hpack_table.c
@@ -0,0 +1,210 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/hpack_table.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include "src/core/support/murmur_hash.h"
+
+static struct {
+  const char *key;
+  const char *value;
+} static_table[] = {
+      /* 0: */ {NULL, NULL},
+      /* 1: */ {":authority", ""},
+      /* 2: */ {":method", "GET"},
+      /* 3: */ {":method", "POST"},
+      /* 4: */ {":path", "/"},
+      /* 5: */ {":path", "/index.html"},
+      /* 6: */ {":scheme", "http"},
+      /* 7: */ {":scheme", "https"},
+      /* 8: */ {":status", "200"},
+      /* 9: */ {":status", "204"},
+      /* 10: */ {":status", "206"},
+      /* 11: */ {":status", "304"},
+      /* 12: */ {":status", "400"},
+      /* 13: */ {":status", "404"},
+      /* 14: */ {":status", "500"},
+      /* 15: */ {"accept-charset", ""},
+      /* 16: */ {"accept-encoding", "gzip, deflate"},
+      /* 17: */ {"accept-language", ""},
+      /* 18: */ {"accept-ranges", ""},
+      /* 19: */ {"accept", ""},
+      /* 20: */ {"access-control-allow-origin", ""},
+      /* 21: */ {"age", ""},
+      /* 22: */ {"allow", ""},
+      /* 23: */ {"authorization", ""},
+      /* 24: */ {"cache-control", ""},
+      /* 25: */ {"content-disposition", ""},
+      /* 26: */ {"content-encoding", ""},
+      /* 27: */ {"content-language", ""},
+      /* 28: */ {"content-length", ""},
+      /* 29: */ {"content-location", ""},
+      /* 30: */ {"content-range", ""},
+      /* 31: */ {"content-type", ""},
+      /* 32: */ {"cookie", ""},
+      /* 33: */ {"date", ""},
+      /* 34: */ {"etag", ""},
+      /* 35: */ {"expect", ""},
+      /* 36: */ {"expires", ""},
+      /* 37: */ {"from", ""},
+      /* 38: */ {"host", ""},
+      /* 39: */ {"if-match", ""},
+      /* 40: */ {"if-modified-since", ""},
+      /* 41: */ {"if-none-match", ""},
+      /* 42: */ {"if-range", ""},
+      /* 43: */ {"if-unmodified-since", ""},
+      /* 44: */ {"last-modified", ""},
+      /* 45: */ {"link", ""},
+      /* 46: */ {"location", ""},
+      /* 47: */ {"max-forwards", ""},
+      /* 48: */ {"proxy-authenticate", ""},
+      /* 49: */ {"proxy-authorization", ""},
+      /* 50: */ {"range", ""},
+      /* 51: */ {"referer", ""},
+      /* 52: */ {"refresh", ""},
+      /* 53: */ {"retry-after", ""},
+      /* 54: */ {"server", ""},
+      /* 55: */ {"set-cookie", ""},
+      /* 56: */ {"strict-transport-security", ""},
+      /* 57: */ {"transfer-encoding", ""},
+      /* 58: */ {"user-agent", ""},
+      /* 59: */ {"vary", ""},
+      /* 60: */ {"via", ""},
+      /* 61: */ {"www-authenticate", ""},
+};
+
+void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx) {
+  size_t i;
+
+  memset(tbl, 0, sizeof(*tbl));
+  tbl->mdctx = mdctx;
+  tbl->max_bytes = GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE;
+  for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
+    tbl->static_ents[i - 1] = grpc_mdelem_from_strings(
+        mdctx, static_table[i].key, static_table[i].value);
+  }
+}
+
+void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl) {
+  size_t i;
+  for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
+    grpc_mdelem_unref(tbl->static_ents[i]);
+  }
+  for (i = 0; i < tbl->num_ents; i++) {
+    grpc_mdelem_unref(
+        tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT]);
+  }
+}
+
+grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
+                                      gpr_uint32 index) {
+  /* Static table comes first, just return an entry from it */
+  if (index <= GRPC_CHTTP2_LAST_STATIC_ENTRY) {
+    return tbl->static_ents[index - 1];
+  }
+  /* Otherwise, find the value in the list of valid entries */
+  index -= (GRPC_CHTTP2_LAST_STATIC_ENTRY + 1);
+  if (index < tbl->num_ents) {
+    gpr_uint32 offset = (tbl->num_ents - 1 - index + tbl->first_ent) %
+                        GRPC_CHTTP2_MAX_TABLE_COUNT;
+    return tbl->ents[offset];
+  }
+  /* Invalid entry: return error */
+  return NULL;
+}
+
+/* Evict one element from the table */
+static void evict1(grpc_chttp2_hptbl *tbl) {
+  grpc_mdelem *first_ent = tbl->ents[tbl->first_ent];
+  tbl->mem_used -= GPR_SLICE_LENGTH(first_ent->key->slice) +
+                   GPR_SLICE_LENGTH(first_ent->value->slice) +
+                   GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
+  tbl->first_ent = (tbl->first_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT;
+  tbl->num_ents--;
+  grpc_mdelem_unref(first_ent);
+}
+
+void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
+  /* determine how many bytes of buffer this entry represents */
+  gpr_uint16 elem_bytes = GPR_SLICE_LENGTH(md->key->slice) +
+                          GPR_SLICE_LENGTH(md->value->slice) +
+                          GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
+
+  /* we can't add elements bigger than the max table size */
+  assert(elem_bytes <= tbl->max_bytes);
+
+  /* evict entries to ensure no overflow */
+  while (elem_bytes > tbl->max_bytes - tbl->mem_used) {
+    evict1(tbl);
+  }
+
+  /* copy the finalized entry in */
+  tbl->ents[tbl->last_ent] = md;
+
+  /* update accounting values */
+  tbl->last_ent = (tbl->last_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT;
+  tbl->num_ents++;
+  tbl->mem_used += elem_bytes;
+}
+
+grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
+    const grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
+  grpc_chttp2_hptbl_find_result r = {0, 0};
+  int i;
+
+  /* See if the string is in the static table */
+  for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
+    grpc_mdelem *ent = tbl->static_ents[i];
+    if (md->key != ent->key) continue;
+    r.index = i + 1;
+    r.has_value = md->value == ent->value;
+    if (r.has_value) return r;
+  }
+
+  /* Scan the dynamic table */
+  for (i = 0; i < tbl->num_ents; i++) {
+    int idx = tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY;
+    grpc_mdelem *ent =
+        tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT];
+    if (md->key != ent->key) continue;
+    r.index = idx;
+    r.has_value = md->value == ent->value;
+    if (r.has_value) return r;
+  }
+
+  return r;
+}
diff --git a/src/core/transport/chttp2/hpack_table.h b/src/core/transport/chttp2/hpack_table.h
new file mode 100644
index 0000000..a3a07ad
--- /dev/null
+++ b/src/core/transport/chttp2/hpack_table.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_HPACK_TABLE_H__
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_HPACK_TABLE_H__
+
+#include "src/core/transport/metadata.h"
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice.h>
+
+/* HPACK header table */
+
+/* last index in the static table */
+#define GRPC_CHTTP2_LAST_STATIC_ENTRY 61
+
+/* Initial table size as per the spec */
+#define GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE 4096
+/* Maximum table size that we'll use */
+#define GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE
+/* Per entry overhead bytes as per the spec */
+#define GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD 32
+/* Maximum number of entries we could possibly fit in the table, given defined
+   overheads */
+#define GRPC_CHTTP2_MAX_TABLE_COUNT                                            \
+  ((GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) / \
+   GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD)
+
+/* hpack decoder table */
+typedef struct {
+  grpc_mdctx *mdctx;
+  /* the first used entry in ents */
+  gpr_uint16 first_ent;
+  /* the last used entry in ents */
+  gpr_uint16 last_ent;
+  /* how many entries are in the table */
+  gpr_uint16 num_ents;
+  /* the amount of memory used by the table, according to the hpack algorithm */
+  gpr_uint16 mem_used;
+  /* the max memory allowed to be used by the table, according to the hpack
+     algorithm */
+  gpr_uint16 max_bytes;
+  /* a circular buffer of headers - this is stored in the opposite order to
+     what hpack specifies, in order to simplify table management a little...
+     meaning lookups need to SUBTRACT from the end position */
+  grpc_mdelem *ents[GRPC_CHTTP2_MAX_TABLE_COUNT];
+  grpc_mdelem *static_ents[GRPC_CHTTP2_LAST_STATIC_ENTRY];
+} grpc_chttp2_hptbl;
+
+/* initialize a hpack table */
+void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx);
+void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl);
+
+/* lookup a table entry based on its hpack index */
+grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
+                                      gpr_uint32 index);
+/* add a table entry to the index */
+void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md);
+/* Find a key/value pair in the table... returns the index in the table of the
+   most similar entry, or 0 if the value was not found */
+typedef struct {
+  gpr_uint16 index;
+  gpr_uint8 has_value;
+} grpc_chttp2_hptbl_find_result;
+grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
+    const grpc_chttp2_hptbl *tbl, grpc_mdelem *md);
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_HPACK_TABLE_H__ */
diff --git a/src/core/transport/chttp2/hpack_tables.txt b/src/core/transport/chttp2/hpack_tables.txt
new file mode 100644
index 0000000..08842a0
--- /dev/null
+++ b/src/core/transport/chttp2/hpack_tables.txt
@@ -0,0 +1,66 @@
+Static table, from the spec:
+          +-------+-----------------------------+---------------+
+          | Index | Header Name                 | Header Value  |
+          +-------+-----------------------------+---------------+
+          | 1     | :authority                  |               |
+          | 2     | :method                     | GET           |
+          | 3     | :method                     | POST          |
+          | 4     | :path                       | /             |
+          | 5     | :path                       | /index.html   |
+          | 6     | :scheme                     | http          |
+          | 7     | :scheme                     | https         |
+          | 8     | :status                     | 200           |
+          | 9     | :status                     | 204           |
+          | 10    | :status                     | 206           |
+          | 11    | :status                     | 304           |
+          | 12    | :status                     | 400           |
+          | 13    | :status                     | 404           |
+          | 14    | :status                     | 500           |
+          | 15    | accept-charset              |               |
+          | 16    | accept-encoding             | gzip, deflate |
+          | 17    | accept-language             |               |
+          | 18    | accept-ranges               |               |
+          | 19    | accept                      |               |
+          | 20    | access-control-allow-origin |               |
+          | 21    | age                         |               |
+          | 22    | allow                       |               |
+          | 23    | authorization               |               |
+          | 24    | cache-control               |               |
+          | 25    | content-disposition         |               |
+          | 26    | content-encoding            |               |
+          | 27    | content-language            |               |
+          | 28    | content-length              |               |
+          | 29    | content-location            |               |
+          | 30    | content-range               |               |
+          | 31    | content-type                |               |
+          | 32    | cookie                      |               |
+          | 33    | date                        |               |
+          | 34    | etag                        |               |
+          | 35    | expect                      |               |
+          | 36    | expires                     |               |
+          | 37    | from                        |               |
+          | 38    | host                        |               |
+          | 39    | if-match                    |               |
+          | 40    | if-modified-since           |               |
+          | 41    | if-none-match               |               |
+          | 42    | if-range                    |               |
+          | 43    | if-unmodified-since         |               |
+          | 44    | last-modified               |               |
+          | 45    | link                        |               |
+          | 46    | location                    |               |
+          | 47    | max-forwards                |               |
+          | 48    | proxy-authenticate          |               |
+          | 49    | proxy-authorization         |               |
+          | 50    | range                       |               |
+          | 51    | referer                     |               |
+          | 52    | refresh                     |               |
+          | 53    | retry-after                 |               |
+          | 54    | server                      |               |
+          | 55    | set-cookie                  |               |
+          | 56    | strict-transport-security   |               |
+          | 57    | transfer-encoding           |               |
+          | 58    | user-agent                  |               |
+          | 59    | vary                        |               |
+          | 60    | via                         |               |
+          | 61    | www-authenticate            |               |
+          +-------+-----------------------------+---------------+
diff --git a/src/core/transport/chttp2/http2_errors.h b/src/core/transport/chttp2/http2_errors.h
new file mode 100644
index 0000000..d065422
--- /dev/null
+++ b/src/core/transport/chttp2/http2_errors.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_HTTP2_ERRORS_H__
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_HTTP2_ERRORS_H__
+
+/* error codes for RST_STREAM from http2 draft 14 section 7 */
+typedef enum {
+  GRPC_CHTTP2_NO_ERROR = 0x0,
+  GRPC_CHTTP2_PROTOCOL_ERROR = 0x1,
+  GRPC_CHTTP2_INTERNAL_ERROR = 0x2,
+  GRPC_CHTTP2_FLOW_CONTROL_ERROR = 0x3,
+  GRPC_CHTTP2_SETTINGS_TIMEOUT = 0x4,
+  GRPC_CHTTP2_STREAM_CLOSED = 0x5,
+  GRPC_CHTTP2_FRAME_SIZE_ERROR = 0x6,
+  GRPC_CHTTP2_REFUSED_STREAM = 0x7,
+  GRPC_CHTTP2_CANCEL = 0x8,
+  GRPC_CHTTP2_COMPRESSION_ERROR = 0x9,
+  GRPC_CHTTP2_CONNECT_ERROR = 0xa,
+  GRPC_CHTTP2_ENHANCE_YOUR_CALM = 0xb,
+  GRPC_CHTTP2_INADEQUATE_SECURITY = 0xc,
+  /* force use of a default clause */
+  GRPC_CHTTP2__ERROR_DO_NOT_USE = -1
+} grpc_chttp2_error_code;
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_HTTP2_ERRORS_H__ */
diff --git a/src/core/transport/chttp2/status_conversion.c b/src/core/transport/chttp2/status_conversion.c
new file mode 100644
index 0000000..7bd85e8
--- /dev/null
+++ b/src/core/transport/chttp2/status_conversion.c
@@ -0,0 +1,109 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/status_conversion.h"
+
+int grpc_chttp2_grpc_status_to_http2_error(grpc_status_code status) {
+  switch (status) {
+    case GRPC_STATUS_OK:
+      return GRPC_CHTTP2_NO_ERROR;
+    case GRPC_STATUS_CANCELLED:
+      return GRPC_CHTTP2_CANCEL;
+    case GRPC_STATUS_RESOURCE_EXHAUSTED:
+      return GRPC_CHTTP2_ENHANCE_YOUR_CALM;
+    case GRPC_STATUS_PERMISSION_DENIED:
+      return GRPC_CHTTP2_INADEQUATE_SECURITY;
+    case GRPC_STATUS_UNAVAILABLE:
+      return GRPC_CHTTP2_REFUSED_STREAM;
+    default:
+      return GRPC_CHTTP2_INTERNAL_ERROR;
+  }
+}
+
+grpc_status_code grpc_chttp2_http2_error_to_grpc_status(
+    grpc_chttp2_error_code error) {
+  switch (error) {
+    case GRPC_CHTTP2_NO_ERROR:
+      /* should never be received */
+      return GRPC_STATUS_INTERNAL;
+    case GRPC_CHTTP2_CANCEL:
+      return GRPC_STATUS_CANCELLED;
+    case GRPC_CHTTP2_ENHANCE_YOUR_CALM:
+      return GRPC_STATUS_RESOURCE_EXHAUSTED;
+    case GRPC_CHTTP2_INADEQUATE_SECURITY:
+      return GRPC_STATUS_PERMISSION_DENIED;
+    case GRPC_CHTTP2_REFUSED_STREAM:
+      return GRPC_STATUS_UNAVAILABLE;
+    default:
+      return GRPC_STATUS_INTERNAL;
+  }
+}
+
+grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status) {
+  switch (status) {
+    /* these HTTP2 status codes are called out explicitly in status.proto */
+    case 200:
+      return GRPC_STATUS_OK;
+    case 400:
+      return GRPC_STATUS_INVALID_ARGUMENT;
+    case 401:
+      return GRPC_STATUS_UNAUTHENTICATED;
+    case 403:
+      return GRPC_STATUS_PERMISSION_DENIED;
+    case 404:
+      return GRPC_STATUS_NOT_FOUND;
+    case 409:
+      return GRPC_STATUS_ABORTED;
+    case 412:
+      return GRPC_STATUS_FAILED_PRECONDITION;
+    case 429:
+      return GRPC_STATUS_RESOURCE_EXHAUSTED;
+    case 499:
+      return GRPC_STATUS_CANCELLED;
+    case 500:
+      return GRPC_STATUS_UNKNOWN;
+    case 501:
+      return GRPC_STATUS_UNIMPLEMENTED;
+    case 503:
+      return GRPC_STATUS_UNAVAILABLE;
+    case 504:
+      return GRPC_STATUS_DEADLINE_EXCEEDED;
+    /* everything else is unknown */
+    default:
+      return GRPC_STATUS_UNKNOWN;
+  }
+}
+
+int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status) {
+  return 200;
+}
diff --git a/src/core/transport/chttp2/status_conversion.h b/src/core/transport/chttp2/status_conversion.h
new file mode 100644
index 0000000..ae9e7f2
--- /dev/null
+++ b/src/core/transport/chttp2/status_conversion.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_STATUS_CONVERSION_H__
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_STATUS_CONVERSION_H__
+
+#include <grpc/grpc.h>
+#include "src/core/transport/chttp2/http2_errors.h"
+
+/* Conversion of grpc status codes to http2 error codes (for RST_STREAM) */
+grpc_chttp2_error_code grpc_chttp2_grpc_status_to_http2_error(
+    grpc_status_code status);
+grpc_status_code grpc_chttp2_http2_error_to_grpc_status(
+    grpc_chttp2_error_code error);
+
+/* Conversion of HTTP status codes (:status) to grpc status codes */
+grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status);
+int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status);
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_STATUS_CONVERSION_H__ */
diff --git a/src/core/transport/chttp2/stream_encoder.c b/src/core/transport/chttp2/stream_encoder.c
new file mode 100644
index 0000000..d46366d
--- /dev/null
+++ b/src/core/transport/chttp2/stream_encoder.c
@@ -0,0 +1,553 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/stream_encoder.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+#include "src/core/transport/chttp2/hpack_table.h"
+#include "src/core/transport/chttp2/timeout_encoding.h"
+#include "src/core/transport/chttp2/varint.h"
+
+#define HASH_FRAGMENT_1(x) ((x)&255)
+#define HASH_FRAGMENT_2(x) ((x >> 8) & 255)
+#define HASH_FRAGMENT_3(x) ((x >> 16) & 255)
+#define HASH_FRAGMENT_4(x) ((x >> 24) & 255)
+
+/* if the probability of this item being seen again is < 1/x then don't add
+   it to the table */
+#define ONE_ON_ADD_PROBABILITY 128
+/* don't consider adding anything bigger than this to the hpack table */
+#define MAX_DECODER_SPACE_USAGE 512
+
+/* what kind of frame our we encoding? */
+typedef enum { HEADER, DATA, NONE } frame_type;
+
+typedef struct {
+  frame_type cur_frame_type;
+  /* number of bytes in 'output' when we started the frame - used to calculate
+     frame length */
+  size_t output_length_at_start_of_frame;
+  /* index (in output) of the header for the current frame */
+  size_t header_idx;
+  /* was the last frame emitted a header? (if yes, we'll need a CONTINUATION */
+  gpr_uint8 last_was_header;
+  /* output stream id */
+  gpr_uint32 stream_id;
+  /* number of flow controlled bytes written */
+  gpr_uint32 output_size;
+  gpr_slice_buffer *output;
+} framer_state;
+
+/* fills p (which is expected to be 9 bytes long) with a data frame header */
+static void fill_header(gpr_uint8 *p, gpr_uint8 type, gpr_uint32 id,
+                        gpr_uint32 len, gpr_uint8 flags) {
+  *p++ = len >> 16;
+  *p++ = len >> 8;
+  *p++ = len;
+  *p++ = type;
+  *p++ = flags;
+  *p++ = id >> 24;
+  *p++ = id >> 16;
+  *p++ = id >> 8;
+  *p++ = id;
+}
+
+/* finish a frame - fill in the previously reserved header */
+static void finish_frame(framer_state *st, int is_header_boundary,
+                         int is_last_in_stream) {
+  gpr_uint8 type = 0xff;
+  switch (st->cur_frame_type) {
+    case HEADER:
+      type = st->last_was_header ? GRPC_CHTTP2_FRAME_CONTINUATION
+                                 : GRPC_CHTTP2_FRAME_HEADER;
+      st->last_was_header = 1;
+      break;
+    case DATA:
+      type = GRPC_CHTTP2_FRAME_DATA;
+      st->last_was_header = 0;
+      is_header_boundary = 0;
+      break;
+    case NONE:
+      return;
+  }
+  fill_header(GPR_SLICE_START_PTR(st->output->slices[st->header_idx]), type,
+              st->stream_id,
+              st->output->length - st->output_length_at_start_of_frame,
+              (is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) |
+                  (is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0));
+  st->cur_frame_type = NONE;
+}
+
+/* begin a new frame: reserve off header space, remember how many bytes we'd
+   output before beginning */
+static void begin_frame(framer_state *st, frame_type type) {
+  GPR_ASSERT(type != NONE);
+  GPR_ASSERT(st->cur_frame_type == NONE);
+  st->cur_frame_type = type;
+  st->header_idx =
+      gpr_slice_buffer_add_indexed(st->output, gpr_slice_malloc(9));
+  st->output_length_at_start_of_frame = st->output->length;
+}
+
+/* make sure that the current frame is of the type desired, and has sufficient
+   space to add at least about_to_add bytes -- finishes the current frame if
+   needed */
+static void ensure_frame_type(framer_state *st, frame_type type,
+                              int need_bytes) {
+  if (st->cur_frame_type == type &&
+      st->output->length - st->output_length_at_start_of_frame + need_bytes <=
+          GRPC_CHTTP2_MAX_PAYLOAD_LENGTH) {
+    return;
+  }
+  finish_frame(st, type != HEADER, 0);
+  begin_frame(st, type);
+}
+
+/* increment a filter count, halve all counts if one element reaches max */
+static void inc_filter(gpr_uint8 idx, gpr_uint32 *sum, gpr_uint8 *elems) {
+  elems[idx]++;
+  if (elems[idx] < 255) {
+    (*sum)++;
+  } else {
+    int i;
+    *sum = 0;
+    for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_FILTERS; i++) {
+      elems[i] /= 2;
+      (*sum) += elems[i];
+    }
+  }
+}
+
+static void add_header_data(framer_state *st, gpr_slice slice) {
+  size_t len = GPR_SLICE_LENGTH(slice);
+  size_t remaining;
+  if (len == 0) return;
+  ensure_frame_type(st, HEADER, 1);
+  remaining = GRPC_CHTTP2_MAX_PAYLOAD_LENGTH +
+              st->output_length_at_start_of_frame - st->output->length;
+  if (len <= remaining) {
+    gpr_slice_buffer_add(st->output, slice);
+  } else {
+    gpr_slice_buffer_add(st->output, gpr_slice_split_head(&slice, remaining));
+    add_header_data(st, slice);
+  }
+}
+
+static gpr_uint8 *add_tiny_header_data(framer_state *st, int len) {
+  ensure_frame_type(st, HEADER, len);
+  return gpr_slice_buffer_tiny_add(st->output, len);
+}
+
+static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
+  gpr_uint32 key_hash = elem->key->hash;
+  gpr_uint32 elem_hash = key_hash ^ elem->value->hash;
+  gpr_uint32 new_index = c->tail_remote_index + c->table_elems + 1;
+  gpr_uint32 elem_size = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
+                         GPR_SLICE_LENGTH(elem->value->slice);
+  int drop_ref;
+
+  /* Reserve space for this element in the remote table: if this overflows
+     the current table, drop elements until it fits, matching the decompressor
+     algorithm */
+  /* TODO(ctiller): constant */
+  while (c->table_size + elem_size > 4096) {
+    c->tail_remote_index++;
+    GPR_ASSERT(c->tail_remote_index > 0);
+    GPR_ASSERT(c->table_size >=
+               c->table_elem_size[c->tail_remote_index %
+                                  GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS]);
+    GPR_ASSERT(c->table_elems > 0);
+    c->table_size -= c->table_elem_size[c->tail_remote_index %
+                                        GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS];
+    c->table_elems--;
+  }
+  GPR_ASSERT(c->table_elems < GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS);
+  c->table_elem_size[new_index % GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS] =
+      elem_size;
+  c->table_size += elem_size;
+  c->table_elems++;
+
+  /* Store this element into {entries,indices}_elem */
+  if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem) {
+    /* already there: update with new index */
+    c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
+    drop_ref = 1;
+  } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem) {
+    /* already there (cuckoo): update with new index */
+    c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
+    drop_ref = 1;
+  } else if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == NULL) {
+    /* not there, but a free element: add */
+    c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = elem;
+    c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
+    drop_ref = 0;
+  } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == NULL) {
+    /* not there (cuckoo), but a free element: add */
+    c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = elem;
+    c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
+    drop_ref = 0;
+  } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] <
+             c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) {
+    /* not there: replace oldest */
+    grpc_mdelem_unref(c->entries_elems[HASH_FRAGMENT_2(elem_hash)]);
+    c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = elem;
+    c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
+    drop_ref = 0;
+  } else {
+    /* not there: replace oldest */
+    grpc_mdelem_unref(c->entries_elems[HASH_FRAGMENT_3(elem_hash)]);
+    c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = elem;
+    c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
+    drop_ref = 0;
+  }
+
+  /* do exactly the same for the key (so we can find by that again too) */
+
+  if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key) {
+    c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
+  } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key) {
+    c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
+  } else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == NULL) {
+    c->entries_keys[HASH_FRAGMENT_2(key_hash)] = grpc_mdstr_ref(elem->key);
+    c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
+  } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == NULL) {
+    c->entries_keys[HASH_FRAGMENT_3(key_hash)] = grpc_mdstr_ref(elem->key);
+    c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
+  } else if (c->indices_keys[HASH_FRAGMENT_2(key_hash)] <
+             c->indices_keys[HASH_FRAGMENT_3(key_hash)]) {
+    grpc_mdstr_unref(c->entries_keys[HASH_FRAGMENT_2(key_hash)]);
+    c->entries_keys[HASH_FRAGMENT_2(key_hash)] = grpc_mdstr_ref(elem->key);
+    c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
+  } else {
+    grpc_mdstr_unref(c->entries_keys[HASH_FRAGMENT_3(key_hash)]);
+    c->entries_keys[HASH_FRAGMENT_3(key_hash)] = grpc_mdstr_ref(elem->key);
+    c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
+  }
+
+  if (drop_ref) {
+    grpc_mdelem_unref(elem);
+  }
+}
+
+static void emit_indexed(grpc_chttp2_hpack_compressor *c, gpr_uint32 index,
+                         framer_state *st) {
+  int len = GRPC_CHTTP2_VARINT_LENGTH(index, 1);
+  GRPC_CHTTP2_WRITE_VARINT(index, 1, 0x80, add_tiny_header_data(st, len), len);
+}
+
+static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c,
+                               gpr_uint32 key_index, grpc_mdstr *value,
+                               framer_state *st) {
+  int len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2);
+  int len_val = GPR_SLICE_LENGTH(value->slice);
+  int len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
+  GRPC_CHTTP2_WRITE_VARINT(key_index, 2, 0x40,
+                           add_tiny_header_data(st, len_pfx), len_pfx);
+  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, 0x00,
+                           add_tiny_header_data(st, len_val_len), len_val_len);
+  add_header_data(st, gpr_slice_ref(value->slice));
+}
+
+static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c,
+                              gpr_uint32 key_index, grpc_mdstr *value,
+                              framer_state *st) {
+  int len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4);
+  int len_val = GPR_SLICE_LENGTH(value->slice);
+  int len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
+  GRPC_CHTTP2_WRITE_VARINT(key_index, 4, 0x00,
+                           add_tiny_header_data(st, len_pfx), len_pfx);
+  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, 0x00,
+                           add_tiny_header_data(st, len_val_len), len_val_len);
+  add_header_data(st, gpr_slice_ref(value->slice));
+}
+
+static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c,
+                                 grpc_mdstr *key, grpc_mdstr *value,
+                                 framer_state *st) {
+  int len_key = GPR_SLICE_LENGTH(key->slice);
+  int len_val = GPR_SLICE_LENGTH(value->slice);
+  int len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
+  int len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
+  *add_tiny_header_data(st, 1) = 0x40;
+  GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
+                           add_tiny_header_data(st, len_key_len), len_key_len);
+  add_header_data(st, gpr_slice_ref(key->slice));
+  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, 0x00,
+                           add_tiny_header_data(st, len_val_len), len_val_len);
+  add_header_data(st, gpr_slice_ref(value->slice));
+}
+
+static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
+                                grpc_mdstr *key, grpc_mdstr *value,
+                                framer_state *st) {
+  int len_key = GPR_SLICE_LENGTH(key->slice);
+  int len_val = GPR_SLICE_LENGTH(value->slice);
+  int len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
+  int len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
+  *add_tiny_header_data(st, 1) = 0x00;
+  GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
+                           add_tiny_header_data(st, len_key_len), len_key_len);
+  add_header_data(st, gpr_slice_ref(key->slice));
+  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, 0x00,
+                           add_tiny_header_data(st, len_val_len), len_val_len);
+  add_header_data(st, gpr_slice_ref(value->slice));
+}
+
+static gpr_uint32 dynidx(grpc_chttp2_hpack_compressor *c, gpr_uint32 index) {
+  return 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY + c->tail_remote_index +
+         c->table_elems - index;
+}
+
+/* encode an mdelem, taking ownership of it */
+static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
+                      framer_state *st) {
+  gpr_uint32 key_hash = elem->key->hash;
+  gpr_uint32 elem_hash = key_hash ^ elem->value->hash;
+  size_t decoder_space_usage;
+  int should_add_elem;
+
+  inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems);
+
+  /* is this elem currently in the decoders table? */
+
+  if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem &&
+      c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) {
+    /* HIT: complete element (first cuckoo hash) */
+    emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]),
+                 st);
+    grpc_mdelem_unref(elem);
+    return;
+  }
+
+  if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem &&
+      c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) {
+    /* HIT: complete element (second cuckoo hash) */
+    emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]),
+                 st);
+    grpc_mdelem_unref(elem);
+    return;
+  }
+
+  /* should this elem be in the table? */
+  decoder_space_usage = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
+                        GPR_SLICE_LENGTH(elem->value->slice);
+  should_add_elem = decoder_space_usage < MAX_DECODER_SPACE_USAGE &&
+                    c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
+                        c->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
+
+  /* no hits for the elem... maybe there's a key? */
+
+  if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key &&
+      c->indices_keys[HASH_FRAGMENT_2(key_hash)] > c->tail_remote_index) {
+    /* HIT: key (first cuckoo hash) */
+    if (should_add_elem) {
+      emit_lithdr_incidx(c,
+                         dynidx(c, c->indices_keys[HASH_FRAGMENT_2(key_hash)]),
+                         elem->value, st);
+      add_elem(c, elem);
+    } else {
+      emit_lithdr_noidx(c,
+                        dynidx(c, c->indices_keys[HASH_FRAGMENT_2(key_hash)]),
+                        elem->value, st);
+      grpc_mdelem_unref(elem);
+    }
+    return;
+  }
+
+  if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key &&
+      c->indices_keys[HASH_FRAGMENT_3(key_hash)] > c->tail_remote_index) {
+    /* HIT: key (first cuckoo hash) */
+    if (should_add_elem) {
+      emit_lithdr_incidx(c,
+                         dynidx(c, c->indices_keys[HASH_FRAGMENT_3(key_hash)]),
+                         elem->value, st);
+      add_elem(c, elem);
+    } else {
+      emit_lithdr_noidx(c,
+                        dynidx(c, c->indices_keys[HASH_FRAGMENT_3(key_hash)]),
+                        elem->value, st);
+      grpc_mdelem_unref(elem);
+    }
+    return;
+  }
+
+  /* no elem, key in the table... fall back to literal emission */
+
+  if (should_add_elem) {
+    emit_lithdr_incidx_v(c, elem->key, elem->value, st);
+    add_elem(c, elem);
+  } else {
+    emit_lithdr_noidx_v(c, elem->key, elem->value, st);
+    grpc_mdelem_unref(elem);
+  }
+}
+
+#define STRLEN_LIT(x) (sizeof(x) - 1)
+#define TIMEOUT_KEY "grpc-timeout"
+
+static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
+                         framer_state *st) {
+  char timeout_str[32];
+  grpc_chttp2_encode_timeout(gpr_time_sub(deadline, gpr_now()), timeout_str);
+  hpack_enc(c, grpc_mdelem_from_metadata_strings(
+                   c->mdctx, grpc_mdstr_ref(c->timeout_key_str),
+                   grpc_mdstr_from_string(c->mdctx, timeout_str)),
+            st);
+}
+
+gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id) {
+  gpr_slice slice = gpr_slice_malloc(9);
+  fill_header(GPR_SLICE_START_PTR(slice), GRPC_CHTTP2_FRAME_DATA, id, 0, 1);
+  return slice;
+}
+
+void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c,
+                                       grpc_mdctx *ctx) {
+  memset(c, 0, sizeof(*c));
+  c->mdctx = ctx;
+  c->timeout_key_str = grpc_mdstr_from_string(ctx, "grpc-timeout");
+}
+
+void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
+  int i;
+  for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) {
+    if (c->entries_keys[i]) grpc_mdstr_unref(c->entries_keys[i]);
+    if (c->entries_elems[i]) grpc_mdelem_unref(c->entries_elems[i]);
+  }
+  grpc_mdstr_unref(c->timeout_key_str);
+}
+
+gpr_uint32 grpc_chttp2_encode_some(grpc_stream_op *ops, size_t *ops_count,
+                                   int eof, gpr_slice_buffer *output,
+                                   gpr_uint32 max_bytes, gpr_uint32 stream_id,
+                                   grpc_chttp2_hpack_compressor *compressor) {
+  framer_state st;
+  gpr_slice slice;
+  grpc_stream_op *op;
+  gpr_uint32 max_take_size;
+  gpr_uint32 curop = 0;
+  gpr_uint32 nops = *ops_count;
+  gpr_uint8 *p;
+
+  GPR_ASSERT(stream_id != 0);
+
+  st.cur_frame_type = NONE;
+  st.last_was_header = 0;
+  st.stream_id = stream_id;
+  st.output = output;
+  st.output_size = 0;
+
+  while (curop < nops) {
+    GPR_ASSERT(st.output_size <= max_bytes);
+    op = &ops[curop];
+    switch (op->type) {
+      case GRPC_NO_OP:
+        curop++;
+        break;
+      case GRPC_OP_FLOW_CTL_CB:
+        op->data.flow_ctl_cb.cb(op->data.flow_ctl_cb.arg, GRPC_OP_OK);
+        curop++;
+        break;
+      case GRPC_OP_METADATA:
+        hpack_enc(compressor, op->data.metadata, &st);
+        curop++;
+        break;
+      case GRPC_OP_DEADLINE:
+        deadline_enc(compressor, op->data.deadline, &st);
+        curop++;
+        break;
+      case GRPC_OP_METADATA_BOUNDARY:
+        ensure_frame_type(&st, HEADER, 0);
+        finish_frame(&st, 1, 0);
+        st.last_was_header = 0; /* force a new header frame */
+        curop++;
+        break;
+      case GRPC_OP_BEGIN_MESSAGE:
+        /* begin op: for now we just convert the op to a slice and fall
+           through - this lets us reuse the slice framing code below */
+        slice = gpr_slice_malloc(5);
+        p = GPR_SLICE_START_PTR(slice);
+        p[0] = 0;
+        p[1] = op->data.begin_message.length >> 24;
+        p[2] = op->data.begin_message.length >> 16;
+        p[3] = op->data.begin_message.length >> 8;
+        p[4] = op->data.begin_message.length;
+        op->type = GRPC_OP_SLICE;
+        op->data.slice = slice;
+      /* fallthrough */
+      case GRPC_OP_SLICE:
+        slice = op->data.slice;
+        if (!GPR_SLICE_LENGTH(slice)) {
+          curop++;
+          break;
+        }
+        if (st.output_size == max_bytes) {
+          goto exit_loop;
+        }
+        if (st.cur_frame_type == DATA &&
+            st.output->length - st.output_length_at_start_of_frame ==
+                GRPC_CHTTP2_MAX_PAYLOAD_LENGTH) {
+          finish_frame(&st, 0, 0);
+        }
+        ensure_frame_type(&st, DATA, 1);
+        max_take_size =
+            GPR_MIN(max_bytes - st.output_size,
+                    GRPC_CHTTP2_MAX_PAYLOAD_LENGTH +
+                        st.output_length_at_start_of_frame - st.output->length);
+        if (GPR_SLICE_LENGTH(slice) > max_take_size) {
+          slice = gpr_slice_split_head(&op->data.slice, max_take_size);
+        } else {
+          /* consume this op immediately */
+          curop++;
+        }
+        st.output_size += GPR_SLICE_LENGTH(slice);
+        gpr_slice_buffer_add(output, slice);
+        break;
+    }
+  }
+exit_loop:
+  if (eof && st.cur_frame_type == NONE) {
+    begin_frame(&st, DATA);
+  }
+  finish_frame(&st, 1, eof && curop == nops);
+
+  nops -= curop;
+  *ops_count = nops;
+  memmove(ops, ops + curop, nops * sizeof(grpc_stream_op));
+
+  return st.output_size;
+}
diff --git a/src/core/transport/chttp2/stream_encoder.h b/src/core/transport/chttp2/stream_encoder.h
new file mode 100644
index 0000000..dad6469
--- /dev/null
+++ b/src/core/transport/chttp2/stream_encoder.h
@@ -0,0 +1,86 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_STREAM_ENCODER_H__
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_STREAM_ENCODER_H__
+
+#include "src/core/transport/chttp2/frame.h"
+#include "src/core/transport/metadata.h"
+#include "src/core/transport/stream_op.h"
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
+
+#define GRPC_CHTTP2_HPACKC_NUM_FILTERS 256
+#define GRPC_CHTTP2_HPACKC_NUM_VALUES 256
+#define GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS (4096 / 32)
+
+typedef struct {
+  gpr_uint32 filter_elems_sum;
+  /* one before the lowest usable table index */
+  gpr_uint32 tail_remote_index;
+  gpr_uint16 table_size;
+  gpr_uint16 table_elems;
+
+  /* filter tables for elems: this tables provides an approximate
+     popularity count for particular hashes, and are used to determine whether
+     a new literal should be added to the compression table or not.
+     They track a single integer that counts how often a particular value has
+     been seen. When that count reaches max (255), all values are halved. */
+  gpr_uint8 filter_elems[GRPC_CHTTP2_HPACKC_NUM_FILTERS];
+
+  /* metadata context */
+  grpc_mdctx *mdctx;
+  /* the string 'grpc-timeout' */
+  grpc_mdstr *timeout_key_str;
+
+  /* entry tables for keys & elems: these tables track values that have been
+     seen and *may* be in the decompressor table */
+  grpc_mdstr *entries_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
+  grpc_mdelem *entries_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
+  gpr_uint32 indices_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
+  gpr_uint32 indices_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
+
+  gpr_uint16 table_elem_size[GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS];
+} grpc_chttp2_hpack_compressor;
+
+void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c,
+                                       grpc_mdctx *mdctx);
+void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c);
+
+gpr_uint32 grpc_chttp2_encode_some(grpc_stream_op *ops, size_t *ops_count,
+                                   int eof, gpr_slice_buffer *output,
+                                   gpr_uint32 max_bytes, gpr_uint32 stream_id,
+                                   grpc_chttp2_hpack_compressor *compressor);
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_STREAM_ENCODER_H__ */
diff --git a/src/core/transport/chttp2/stream_map.c b/src/core/transport/chttp2/stream_map.c
new file mode 100644
index 0000000..9ac3a47
--- /dev/null
+++ b/src/core/transport/chttp2/stream_map.c
@@ -0,0 +1,154 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/stream_map.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+void grpc_chttp2_stream_map_init(grpc_chttp2_stream_map *map,
+                                 size_t initial_capacity) {
+  GPR_ASSERT(initial_capacity > 1);
+  map->keys = gpr_malloc(sizeof(gpr_uint32) * initial_capacity);
+  map->values = gpr_malloc(sizeof(void *) * initial_capacity);
+  map->count = 0;
+  map->free = 0;
+  map->capacity = initial_capacity;
+}
+
+void grpc_chttp2_stream_map_destroy(grpc_chttp2_stream_map *map) {
+  gpr_free(map->keys);
+  gpr_free(map->values);
+}
+
+static size_t compact(gpr_uint32 *keys, void **values, size_t count) {
+  size_t i, out;
+
+  for (i = 0, out = 0; i < count; i++) {
+    if (values[i]) {
+      keys[out] = keys[i];
+      values[out] = values[i];
+      out++;
+    }
+  }
+
+  return out;
+}
+
+void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, gpr_uint32 key,
+                                void *value) {
+  size_t count = map->count;
+  size_t capacity = map->capacity;
+  gpr_uint32 *keys = map->keys;
+  void **values = map->values;
+
+  GPR_ASSERT(count == 0 || keys[count - 1] < key);
+  GPR_ASSERT(value);
+
+  if (count == capacity) {
+    if (map->free > capacity / 4) {
+      count = compact(keys, values, count);
+      map->free = 0;
+    } else {
+      /* 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 = gpr_realloc(keys, capacity * sizeof(gpr_uint32));
+      map->values = values = gpr_realloc(values, capacity * sizeof(void *));
+    }
+  }
+
+  keys[count] = key;
+  values[count] = value;
+  map->count = count + 1;
+}
+
+static void **find(grpc_chttp2_stream_map *map, gpr_uint32 key) {
+  size_t min_idx = 0;
+  size_t max_idx = map->count;
+  size_t mid_idx;
+  gpr_uint32 *keys = map->keys;
+  void **values = map->values;
+  gpr_uint32 mid_key;
+
+  if (max_idx == 0) return NULL;
+
+  while (min_idx < max_idx) {
+    /* find the midpoint, avoiding overflow */
+    mid_idx = min_idx + ((max_idx - min_idx) / 2);
+    mid_key = keys[mid_idx];
+
+    if (mid_key < key) {
+      min_idx = mid_idx + 1;
+    } else if (mid_key > key) {
+      max_idx = mid_idx;
+    } else /* mid_key == key */ {
+      return &values[mid_idx];
+    }
+  }
+
+  return NULL;
+}
+
+void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map,
+                                    gpr_uint32 key) {
+  void **pvalue = find(map, key);
+  void *out = NULL;
+  if (pvalue != NULL) {
+    out = *pvalue;
+    *pvalue = NULL;
+    map->free += (out != NULL);
+  }
+  return out;
+}
+
+void *grpc_chttp2_stream_map_find(grpc_chttp2_stream_map *map, gpr_uint32 key) {
+  void **pvalue = find(map, key);
+  return pvalue != NULL ? *pvalue : NULL;
+}
+
+size_t grpc_chttp2_stream_map_size(grpc_chttp2_stream_map *map) {
+  return map->count - map->free;
+}
+
+void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map *map,
+                                     void (*f)(void *user_data, gpr_uint32 key,
+                                               void *value),
+                                     void *user_data) {
+  size_t i;
+
+  for (i = 0; i < map->count; i++) {
+    if (map->values[i]) {
+      f(user_data, map->keys[i], map->values[i]);
+    }
+  }
+}
diff --git a/src/core/transport/chttp2/stream_map.h b/src/core/transport/chttp2/stream_map.h
new file mode 100644
index 0000000..caaee30
--- /dev/null
+++ b/src/core/transport/chttp2/stream_map.h
@@ -0,0 +1,81 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_STREAM_MAP_H__
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_STREAM_MAP_H__
+
+#include <grpc/support/port_platform.h>
+
+#include <stddef.h>
+
+/* Data structure to map a gpr_uint32 to a data object (represented by a void*)
+
+   Represented as a sorted array of keys, and a corresponding array of values.
+   Lookups are performed with binary search.
+   Adds are restricted to strictly higher keys than previously seen (this is
+   guaranteed by http2). */
+typedef struct {
+  gpr_uint32 *keys;
+  void **values;
+  size_t count;
+  size_t free;
+  size_t capacity;
+} grpc_chttp2_stream_map;
+
+void grpc_chttp2_stream_map_init(grpc_chttp2_stream_map *map,
+                                 size_t initial_capacity);
+void grpc_chttp2_stream_map_destroy(grpc_chttp2_stream_map *map);
+
+/* Add a new key: given http2 semantics, new keys must always be greater than
+   existing keys - this is asserted */
+void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, gpr_uint32 key,
+                                void *value);
+
+/* Delete an existing key - returns the previous value of the key if it existed,
+   or NULL otherwise */
+void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map,
+                                    gpr_uint32 key);
+
+/* Return an existing key, or NULL if it does not exist */
+void *grpc_chttp2_stream_map_find(grpc_chttp2_stream_map *map, gpr_uint32 key);
+
+/* How many (populated) entries are in the stream map? */
+size_t grpc_chttp2_stream_map_size(grpc_chttp2_stream_map *map);
+
+/* Callback on each stream */
+void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map *map,
+                                     void (*f)(void *user_data, gpr_uint32 key,
+                                               void *value),
+                                     void *user_data);
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_STREAM_MAP_H__ */
diff --git a/src/core/transport/chttp2/timeout_encoding.c b/src/core/transport/chttp2/timeout_encoding.c
new file mode 100644
index 0000000..2706c36
--- /dev/null
+++ b/src/core/transport/chttp2/timeout_encoding.c
@@ -0,0 +1,176 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/timeout_encoding.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static int round_up(int x, int divisor) {
+  return (x / divisor + (x % divisor != 0)) * divisor;
+}
+
+/* round an integer up to the next value with three significant figures */
+static int round_up_to_three_sig_figs(int x) {
+  if (x < 1000) return x;
+  if (x < 10000) return round_up(x, 10);
+  if (x < 100000) return round_up(x, 100);
+  if (x < 1000000) return round_up(x, 1000);
+  if (x < 10000000) return round_up(x, 10000);
+  if (x < 100000000) return round_up(x, 100000);
+  if (x < 1000000000) return round_up(x, 1000000);
+  return round_up(x, 10000000);
+}
+
+/* encode our minimum viable timeout value */
+static void enc_tiny(char *buffer) { strcpy(buffer, "1n"); }
+
+static void enc_seconds(char *buffer, long sec) {
+  if (sec % 3600 == 0) {
+    sprintf(buffer, "%ldH", sec / 3600);
+  } else if (sec % 60 == 0) {
+    sprintf(buffer, "%ldM", sec / 60);
+  } else {
+    sprintf(buffer, "%ldS", sec);
+  }
+}
+
+static void enc_nanos(char *buffer, int x) {
+  x = round_up_to_three_sig_figs(x);
+  if (x < 100000) {
+    if (x % 1000 == 0) {
+      sprintf(buffer, "%du", x / 1000);
+    } else {
+      sprintf(buffer, "%dn", x);
+    }
+  } else if (x < 100000000) {
+    if (x % 1000000 == 0) {
+      sprintf(buffer, "%dm", x / 1000000);
+    } else {
+      sprintf(buffer, "%du", x / 1000);
+    }
+  } else if (x < 1000000000) {
+    sprintf(buffer, "%dm", x / 1000000);
+  } else {
+    /* note that this is only ever called with times of less than one second,
+       so if we reach here the time must have been rounded up to a whole second
+       (and no more) */
+    strcpy(buffer, "1S");
+  }
+}
+
+static void enc_micros(char *buffer, int x) {
+  x = round_up_to_three_sig_figs(x);
+  if (x < 100000) {
+    if (x % 1000 == 0) {
+      sprintf(buffer, "%dm", x / 1000);
+    } else {
+      sprintf(buffer, "%du", x);
+    }
+  } else if (x < 100000000) {
+    if (x % 1000000 == 0) {
+      sprintf(buffer, "%dS", x / 1000000);
+    } else {
+      sprintf(buffer, "%dm", x / 1000);
+    }
+  } else {
+    sprintf(buffer, "%dS", x / 1000000);
+  }
+}
+
+void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer) {
+  if (timeout.tv_sec < 0) {
+    enc_tiny(buffer);
+  } else if (timeout.tv_sec == 0) {
+    enc_nanos(buffer, timeout.tv_nsec);
+  } else if (timeout.tv_sec < 1000 && timeout.tv_nsec != 0) {
+    enc_micros(buffer,
+               timeout.tv_sec * 1000000 +
+                   (timeout.tv_nsec / 1000 + (timeout.tv_nsec % 1000 != 0)));
+  } else {
+    enc_seconds(buffer, timeout.tv_sec + (timeout.tv_nsec != 0));
+  }
+}
+
+static int is_all_whitespace(const char *p) {
+  while (*p == ' ') p++;
+  return *p == 0;
+}
+
+int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout) {
+  gpr_uint32 x = 0;
+  const char *p = buffer;
+  int have_digit = 0;
+  /* skip whitespace */
+  for (; *p == ' '; p++)
+    ;
+  /* decode numeric part */
+  for (; *p >= '0' && *p <= '9'; p++) {
+    gpr_uint32 xp = x * 10 + *p - '0';
+    have_digit = 1;
+    if (xp < x) {
+      *timeout = gpr_inf_future;
+      return 1;
+    }
+    x = xp;
+  }
+  if (!have_digit) return 0;
+  /* skip whitespace */
+  for (; *p == ' '; p++)
+    ;
+  /* decode unit specifier */
+  switch (*p) {
+    case 'n':
+      *timeout = gpr_time_from_nanos(x);
+      break;
+    case 'u':
+      *timeout = gpr_time_from_micros(x);
+      break;
+    case 'm':
+      *timeout = gpr_time_from_millis(x);
+      break;
+    case 'S':
+      *timeout = gpr_time_from_seconds(x);
+      break;
+    case 'M':
+      *timeout = gpr_time_from_minutes(x);
+      break;
+    case 'H':
+      *timeout = gpr_time_from_hours(x);
+      break;
+    default:
+      return 0;
+  }
+  p++;
+  return is_all_whitespace(p);
+}
diff --git a/src/core/transport/chttp2/timeout_encoding.h b/src/core/transport/chttp2/timeout_encoding.h
new file mode 100644
index 0000000..a458256
--- /dev/null
+++ b/src/core/transport/chttp2/timeout_encoding.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H_
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H_
+
+#include <grpc/support/time.h>
+
+/* Encode/decode timeouts to the GRPC over HTTP2 format;
+   encoding may round up arbitrarily */
+void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer);
+int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout);
+
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H_ */
diff --git a/src/core/transport/chttp2/varint.c b/src/core/transport/chttp2/varint.c
new file mode 100644
index 0000000..5d551be
--- /dev/null
+++ b/src/core/transport/chttp2/varint.c
@@ -0,0 +1,65 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/varint.h"
+
+int grpc_chttp2_hpack_varint_length(gpr_uint32 tail_value) {
+  if (tail_value < (1 << 7)) {
+    return 2;
+  } else if (tail_value < (1 << 14)) {
+    return 3;
+  } else if (tail_value < (1 << 21)) {
+    return 4;
+  } else if (tail_value < (1 << 28)) {
+    return 5;
+  } else {
+    return 6;
+  }
+}
+
+void grpc_chttp2_hpack_write_varint_tail(gpr_uint32 tail_value,
+                                         gpr_uint8* target, int tail_length) {
+  switch (tail_length) {
+    case 5:
+      target[4] = (gpr_uint8)((tail_value >> 28) | 0x80);
+    case 4:
+      target[3] = (gpr_uint8)((tail_value >> 21) | 0x80);
+    case 3:
+      target[2] = (gpr_uint8)((tail_value >> 14) | 0x80);
+    case 2:
+      target[1] = (gpr_uint8)((tail_value >> 7) | 0x80);
+    case 1:
+      target[0] = (gpr_uint8)((tail_value) | 0x80);
+  }
+  target[tail_length - 1] &= 0x7f;
+}
diff --git a/src/core/transport/chttp2/varint.h b/src/core/transport/chttp2/varint.h
new file mode 100644
index 0000000..7803902
--- /dev/null
+++ b/src/core/transport/chttp2/varint.h
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_VARINT_H__
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_VARINT_H__
+
+#include <grpc/support/port_platform.h>
+
+/* Helpers for hpack varint encoding */
+
+/* length of a value that needs varint tail encoding (it's bigger than can be
+   bitpacked into the opcode byte) - returned value includes the length of the
+   opcode byte */
+int grpc_chttp2_hpack_varint_length(gpr_uint32 tail_value);
+
+void grpc_chttp2_hpack_write_varint_tail(gpr_uint32 tail_value,
+                                         gpr_uint8* target, int tail_length);
+
+/* maximum value that can be bitpacked with the opcode if the opcode has a
+   prefix
+   of length prefix_bits */
+#define GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits) ((1 << (8 - (prefix_bits))) - 1)
+
+/* length required to bitpack a value */
+#define GRPC_CHTTP2_VARINT_LENGTH(n, prefix_bits) \
+  ((n) < GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits)   \
+       ? 1                                        \
+       : grpc_chttp2_hpack_varint_length(         \
+             (n)-GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits)))
+
+#define GRPC_CHTTP2_WRITE_VARINT(n, prefix_bits, prefix_or, target, length)   \
+  do {                                                                        \
+    gpr_uint8* tgt = target;                                                  \
+    if ((length) == 1) {                                                      \
+      (tgt)[0] = (prefix_or) | (n);                                           \
+    } else {                                                                  \
+      (tgt)[0] = (prefix_or) | GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits);        \
+      grpc_chttp2_hpack_write_varint_tail(                                    \
+          (n)-GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits), (tgt) + 1, (length)-1); \
+    }                                                                         \
+  } while (0)
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_VARINT_H__ */
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
new file mode 100644
index 0000000..8a6b427
--- /dev/null
+++ b/src/core/transport/chttp2_transport.c
@@ -0,0 +1,1615 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2_transport.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/support/string.h>
+#include <grpc/support/useful.h>
+#include "src/core/transport/transport_impl.h"
+#include "src/core/transport/chttp2/http2_errors.h"
+#include "src/core/transport/chttp2/hpack_parser.h"
+#include "src/core/transport/chttp2/frame_data.h"
+#include "src/core/transport/chttp2/frame_ping.h"
+#include "src/core/transport/chttp2/frame_rst_stream.h"
+#include "src/core/transport/chttp2/frame_settings.h"
+#include "src/core/transport/chttp2/frame_window_update.h"
+#include "src/core/transport/chttp2/status_conversion.h"
+#include "src/core/transport/chttp2/stream_encoder.h"
+#include "src/core/transport/chttp2/stream_map.h"
+#include "src/core/transport/chttp2/timeout_encoding.h"
+
+#define DEFAULT_WINDOW 65536
+#define MAX_WINDOW 0x7fffffffu
+
+#define CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
+#define CLIENT_CONNECT_STRLEN 24
+
+typedef struct transport transport;
+typedef struct stream stream;
+
+/* streams are kept in various linked lists depending on what things need to
+   happen to them... this enum labels each list */
+typedef enum {
+  /* streams that have pending writes */
+  WRITABLE = 0,
+  /* streams that want to send window updates */
+  WINDOW_UPDATE,
+  /* streams that are waiting to start because there are too many concurrent
+     streams on the connection */
+  WAITING_FOR_CONCURRENCY,
+  /* streams that want to callback the application */
+  PENDING_CALLBACKS,
+  /* streams that *ARE* calling back to the application */
+  EXECUTING_CALLBACKS,
+  STREAM_LIST_COUNT /* must be last */
+} stream_list_id;
+
+/* deframer state for the overall http2 stream of bytes */
+typedef enum {
+  /* prefix: one entry per http2 connection prefix byte */
+  DTS_CLIENT_PREFIX_0 = 0,
+  DTS_CLIENT_PREFIX_1,
+  DTS_CLIENT_PREFIX_2,
+  DTS_CLIENT_PREFIX_3,
+  DTS_CLIENT_PREFIX_4,
+  DTS_CLIENT_PREFIX_5,
+  DTS_CLIENT_PREFIX_6,
+  DTS_CLIENT_PREFIX_7,
+  DTS_CLIENT_PREFIX_8,
+  DTS_CLIENT_PREFIX_9,
+  DTS_CLIENT_PREFIX_10,
+  DTS_CLIENT_PREFIX_11,
+  DTS_CLIENT_PREFIX_12,
+  DTS_CLIENT_PREFIX_13,
+  DTS_CLIENT_PREFIX_14,
+  DTS_CLIENT_PREFIX_15,
+  DTS_CLIENT_PREFIX_16,
+  DTS_CLIENT_PREFIX_17,
+  DTS_CLIENT_PREFIX_18,
+  DTS_CLIENT_PREFIX_19,
+  DTS_CLIENT_PREFIX_20,
+  DTS_CLIENT_PREFIX_21,
+  DTS_CLIENT_PREFIX_22,
+  DTS_CLIENT_PREFIX_23,
+  /* frame header byte 0... */
+  /* must follow from the prefix states */
+  DTS_FH_0,
+  DTS_FH_1,
+  DTS_FH_2,
+  DTS_FH_3,
+  DTS_FH_4,
+  DTS_FH_5,
+  DTS_FH_6,
+  DTS_FH_7,
+  /* ... frame header byte 8 */
+  DTS_FH_8,
+  /* inside a http2 frame */
+  DTS_FRAME
+} deframe_transport_state;
+
+typedef struct {
+  stream *head;
+  stream *tail;
+} stream_list;
+
+typedef struct {
+  stream *next;
+  stream *prev;
+} stream_link;
+
+typedef enum {
+  ERROR_STATE_NONE,
+  ERROR_STATE_SEEN,
+  ERROR_STATE_NOTIFIED
+} error_state;
+
+/* We keep several sets of connection wide parameters */
+typedef enum {
+  /* The settings our peer has asked for (and we have acked) */
+  PEER_SETTINGS = 0,
+  /* The settings we'd like to have */
+  LOCAL_SETTINGS,
+  /* The settings we've published to our peer */
+  SENT_SETTINGS,
+  /* The settings the peer has acked */
+  ACKED_SETTINGS,
+  NUM_SETTING_SETS
+} setting_set;
+
+/* Outstanding ping request data */
+typedef struct {
+  gpr_uint8 id[8];
+  void (*cb)(void *user_data);
+  void *user_data;
+} outstanding_ping;
+
+struct transport {
+  grpc_transport base; /* must be first */
+  const grpc_transport_callbacks *cb;
+  void *cb_user_data;
+  grpc_endpoint *ep;
+  grpc_mdctx *metadata_context;
+  gpr_refcount refs;
+  gpr_uint8 is_client;
+
+  gpr_mu mu;
+  gpr_cv cv;
+
+  /* basic state management - what are we doing at the moment? */
+  gpr_uint8 reading;
+  gpr_uint8 writing;
+  gpr_uint8 calling_back;
+  error_state error_state;
+
+  /* stream indexing */
+  gpr_uint32 next_stream_id;
+
+  /* settings */
+  gpr_uint32 settings[NUM_SETTING_SETS][GRPC_CHTTP2_NUM_SETTINGS];
+  gpr_uint8 sent_local_settings;
+  gpr_uint8 dirtied_local_settings;
+
+  /* window management */
+  gpr_uint32 outgoing_window;
+  gpr_uint32 incoming_window;
+
+  /* deframing */
+  deframe_transport_state deframe_state;
+  gpr_uint8 incoming_frame_type;
+  gpr_uint8 incoming_frame_flags;
+  gpr_uint8 header_eof;
+  gpr_uint32 expect_continuation_stream_id;
+  gpr_uint32 incoming_frame_size;
+  gpr_uint32 incoming_stream_id;
+
+  /* hpack encoding */
+  grpc_chttp2_hpack_compressor hpack_compressor;
+
+  /* various parsers */
+  grpc_chttp2_hpack_parser hpack_parser;
+  /* simple one shot parsers */
+  union {
+    grpc_chttp2_window_update_parser window_update;
+    grpc_chttp2_settings_parser settings;
+    grpc_chttp2_ping_parser ping;
+  } simple_parsers;
+
+  /* state for a stream that's not yet been created */
+  grpc_stream_op_buffer new_stream_sopb;
+
+  /* active parser */
+  void *parser_data;
+  stream *incoming_stream;
+  grpc_chttp2_parse_error (*parser)(void *parser_user_data,
+                                    grpc_chttp2_parse_state *state,
+                                    gpr_slice slice, int is_last);
+
+  gpr_slice_buffer outbuf;
+  gpr_slice_buffer qbuf;
+
+  stream_list lists[STREAM_LIST_COUNT];
+  grpc_chttp2_stream_map stream_map;
+
+  /* metadata object cache */
+  grpc_mdstr *str_grpc_timeout;
+
+  /* pings */
+  outstanding_ping *pings;
+  size_t ping_count;
+  size_t ping_capacity;
+  gpr_int64 ping_counter;
+};
+
+struct stream {
+  gpr_uint32 id;
+
+  gpr_uint32 outgoing_window;
+  gpr_uint32 incoming_window;
+  gpr_uint8 write_closed;
+  gpr_uint8 read_closed;
+  gpr_uint8 cancelled;
+  gpr_uint8 allow_window_updates;
+  gpr_uint8 published_close;
+
+  stream_link links[STREAM_LIST_COUNT];
+  gpr_uint8 included[STREAM_LIST_COUNT];
+
+  grpc_stream_op_buffer outgoing_sopb;
+
+  grpc_chttp2_data_parser parser;
+
+  grpc_stream_state callback_state;
+  grpc_stream_op_buffer callback_sopb;
+};
+
+static const grpc_transport_vtable vtable;
+
+static void push_setting(transport *t, grpc_chttp2_setting_id id,
+                         gpr_uint32 value);
+
+static int prepare_callbacks(transport *t);
+static void run_callbacks(transport *t);
+
+static int prepare_write(transport *t);
+static void finish_write(void *t, grpc_endpoint_cb_status status);
+
+static void lock(transport *t);
+static void unlock(transport *t);
+
+static void drop_connection(transport *t);
+static void end_all_the_calls(transport *t);
+
+static stream *stream_list_remove_head(transport *t, stream_list_id id);
+static void stream_list_remove(transport *t, stream *s, stream_list_id id);
+static void stream_list_add_tail(transport *t, stream *s, stream_list_id id);
+static void stream_list_join(transport *t, stream *s, stream_list_id id);
+
+static void cancel_stream_id(transport *t, gpr_uint32 id,
+                             grpc_status_code local_status,
+                             grpc_chttp2_error_code error_code, int send_rst);
+static void cancel_stream(transport *t, stream *s,
+                          grpc_status_code local_status,
+                          grpc_chttp2_error_code error_code, int send_rst);
+static stream *lookup_stream(transport *t, gpr_uint32 id);
+static void remove_from_stream_map(transport *t, stream *s);
+static void maybe_start_some_streams(transport *t);
+
+static void become_skip_parser(transport *t);
+
+/*
+ * CONSTRUCTION/DESTRUCTION/REFCOUNTING
+ */
+
+static void unref_transport(transport *t) {
+  size_t i;
+
+  if (!gpr_unref(&t->refs)) return;
+
+  gpr_mu_lock(&t->mu);
+
+  GPR_ASSERT(t->ep == NULL);
+
+  gpr_slice_buffer_destroy(&t->outbuf);
+  gpr_slice_buffer_destroy(&t->qbuf);
+  grpc_chttp2_hpack_parser_destroy(&t->hpack_parser);
+  grpc_chttp2_hpack_compressor_destroy(&t->hpack_compressor);
+
+  grpc_mdstr_unref(t->str_grpc_timeout);
+
+  for (i = 0; i < STREAM_LIST_COUNT; i++) {
+    GPR_ASSERT(t->lists[i].head == NULL);
+    GPR_ASSERT(t->lists[i].tail == NULL);
+  }
+
+  GPR_ASSERT(grpc_chttp2_stream_map_size(&t->stream_map) == 0);
+
+  grpc_chttp2_stream_map_destroy(&t->stream_map);
+
+  gpr_mu_unlock(&t->mu);
+  gpr_mu_destroy(&t->mu);
+
+  /* callback remaining pings: they're not allowed to call into the transpot,
+     and maybe they hold resources that need to be freed */
+  for (i = 0; i < t->ping_count; i++) {
+    t->pings[i].cb(t->pings[i].user_data);
+  }
+  gpr_free(t->pings);
+
+  gpr_free(t);
+}
+
+static void ref_transport(transport *t) { gpr_ref(&t->refs); }
+
+static void init_transport(transport *t, grpc_transport_setup_callback setup,
+                           void *arg, const grpc_channel_args *channel_args,
+                           grpc_endpoint *ep, grpc_mdctx *mdctx,
+                           int is_client) {
+  size_t i;
+  int j;
+  grpc_transport_setup_result sr;
+
+  GPR_ASSERT(strlen(CLIENT_CONNECT_STRING) == CLIENT_CONNECT_STRLEN);
+
+  t->base.vtable = &vtable;
+  t->ep = ep;
+  /* one ref is for destroy, the other for when ep becomes NULL */
+  gpr_ref_init(&t->refs, 2);
+  gpr_mu_init(&t->mu);
+  gpr_cv_init(&t->cv);
+  t->metadata_context = mdctx;
+  t->str_grpc_timeout =
+      grpc_mdstr_from_string(t->metadata_context, "grpc-timeout");
+  t->reading = 1;
+  t->writing = 0;
+  t->error_state = ERROR_STATE_NONE;
+  t->next_stream_id = is_client ? 1 : 2;
+  t->is_client = is_client;
+  t->outgoing_window = DEFAULT_WINDOW;
+  t->incoming_window = DEFAULT_WINDOW;
+  t->deframe_state = is_client ? DTS_FH_0 : DTS_CLIENT_PREFIX_0;
+  t->expect_continuation_stream_id = 0;
+  t->pings = NULL;
+  t->ping_count = 0;
+  t->ping_capacity = 0;
+  t->ping_counter = gpr_now().tv_nsec;
+  grpc_chttp2_hpack_compressor_init(&t->hpack_compressor, mdctx);
+  gpr_slice_buffer_init(&t->outbuf);
+  gpr_slice_buffer_init(&t->qbuf);
+  if (is_client) {
+    gpr_slice_buffer_add(&t->qbuf,
+                         gpr_slice_from_copied_string(CLIENT_CONNECT_STRING));
+  }
+  /* 8 is a random stab in the dark as to a good initial size: it's small enough
+     that it shouldn't waste memory for infrequently used connections, yet
+     large enough that the exponential growth should happen nicely when it's
+     needed.
+     TODO(ctiller): tune this */
+  grpc_chttp2_stream_map_init(&t->stream_map, 8);
+  memset(&t->lists, 0, sizeof(t->lists));
+
+  /* copy in initial settings to all setting sets */
+  for (i = 0; i < NUM_SETTING_SETS; i++) {
+    for (j = 0; j < GRPC_CHTTP2_NUM_SETTINGS; j++) {
+      t->settings[i][j] = grpc_chttp2_settings_parameters[j].default_value;
+    }
+  }
+  t->dirtied_local_settings = 1;
+  t->sent_local_settings = 0;
+
+  /* configure http2 the way we like it */
+  if (t->is_client) {
+    push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
+    push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
+  }
+
+  if (channel_args) {
+    for (i = 0; i < channel_args->num_args; i++) {
+      if (0 ==
+          strcmp(channel_args->args[i].key, GRPC_ARG_MAX_CONCURRENT_STREAMS)) {
+        if (t->is_client) {
+          gpr_log(GPR_ERROR, "%s: is ignored on the client",
+                  GRPC_ARG_MAX_CONCURRENT_STREAMS);
+        } else if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
+          gpr_log(GPR_ERROR, "%s: must be an integer",
+                  GRPC_ARG_MAX_CONCURRENT_STREAMS);
+        } else {
+          push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
+                       channel_args->args[i].value.integer);
+        }
+      }
+    }
+  }
+
+  gpr_mu_lock(&t->mu);
+  t->calling_back = 1;
+  ref_transport(t);
+  gpr_mu_unlock(&t->mu);
+
+  sr = setup(arg, &t->base, t->metadata_context);
+
+  lock(t);
+  t->cb = sr.callbacks;
+  t->cb_user_data = sr.user_data;
+  grpc_chttp2_hpack_parser_init(&t->hpack_parser, t->metadata_context);
+  t->calling_back = 0;
+  gpr_cv_broadcast(&t->cv);
+  unlock(t);
+  unref_transport(t);
+}
+
+static void destroy_transport(grpc_transport *gt) {
+  transport *t = (transport *)gt;
+
+  gpr_mu_lock(&t->mu);
+  while (t->calling_back) {
+    gpr_cv_wait(&t->cv, &t->mu, gpr_inf_future);
+  }
+  t->cb = NULL;
+  gpr_mu_unlock(&t->mu);
+
+  unref_transport(t);
+}
+
+static void close_transport(grpc_transport *gt) {
+  transport *t = (transport *)gt;
+  gpr_mu_lock(&t->mu);
+  if (t->ep) {
+    grpc_endpoint_shutdown(t->ep);
+  }
+  gpr_mu_unlock(&t->mu);
+}
+
+static int init_stream(grpc_transport *gt, grpc_stream *gs,
+                       const void *server_data) {
+  transport *t = (transport *)gt;
+  stream *s = (stream *)gs;
+
+  ref_transport(t);
+
+  if (!server_data) {
+    lock(t);
+    s->id = 0;
+  } else {
+    s->id = (gpr_uint32)(gpr_uintptr)server_data;
+    t->incoming_stream = s;
+    grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
+  }
+
+  s->outgoing_window = DEFAULT_WINDOW;
+  s->incoming_window = DEFAULT_WINDOW;
+  s->write_closed = 0;
+  s->read_closed = 0;
+  s->cancelled = 0;
+  s->allow_window_updates = 0;
+  s->published_close = 0;
+  memset(&s->links, 0, sizeof(s->links));
+  memset(&s->included, 0, sizeof(s->included));
+  grpc_sopb_init(&s->outgoing_sopb);
+  grpc_chttp2_data_parser_init(&s->parser);
+  grpc_sopb_init(&s->callback_sopb);
+
+  if (!server_data) {
+    unlock(t);
+  }
+
+  return 0;
+}
+
+static void destroy_stream(grpc_transport *gt, grpc_stream *gs) {
+  transport *t = (transport *)gt;
+  stream *s = (stream *)gs;
+  size_t i;
+
+  gpr_mu_lock(&t->mu);
+
+  /* await pending callbacks
+     TODO(ctiller): this could be optimized to check if this stream is getting
+     callbacks */
+  while (t->calling_back) {
+    gpr_cv_wait(&t->cv, &t->mu, gpr_inf_future);
+  }
+
+  /* stop parsing if we're currently parsing this stream */
+  if (t->deframe_state == DTS_FRAME && t->incoming_stream_id == s->id &&
+      s->id != 0) {
+    become_skip_parser(t);
+  }
+
+  for (i = 0; i < STREAM_LIST_COUNT; i++) {
+    stream_list_remove(t, s, i);
+  }
+  remove_from_stream_map(t, s);
+
+  gpr_cv_broadcast(&t->cv);
+  gpr_mu_unlock(&t->mu);
+
+  grpc_sopb_destroy(&s->outgoing_sopb);
+  grpc_chttp2_data_parser_destroy(&s->parser);
+  grpc_sopb_destroy(&s->callback_sopb);
+
+  unref_transport(t);
+}
+
+/*
+ * LIST MANAGEMENT
+ */
+
+static stream *stream_list_remove_head(transport *t, stream_list_id id) {
+  stream *s = t->lists[id].head;
+  if (s) {
+    stream *new_head = s->links[id].next;
+    GPR_ASSERT(s->included[id]);
+    if (new_head) {
+      t->lists[id].head = new_head;
+      new_head->links[id].prev = NULL;
+    } else {
+      t->lists[id].head = NULL;
+      t->lists[id].tail = NULL;
+    }
+    s->included[id] = 0;
+  }
+  return s;
+}
+
+static void stream_list_remove(transport *t, stream *s, stream_list_id id) {
+  if (!s->included[id]) return;
+  s->included[id] = 0;
+  if (s->links[id].prev) {
+    s->links[id].prev->links[id].next = s->links[id].next;
+  } else {
+    GPR_ASSERT(t->lists[id].head == s);
+    t->lists[id].head = s->links[id].next;
+  }
+  if (s->links[id].next) {
+    s->links[id].next->links[id].prev = s->links[id].prev;
+  } else {
+    t->lists[id].tail = s->links[id].prev;
+  }
+}
+
+static void stream_list_add_tail(transport *t, stream *s, stream_list_id id) {
+  stream *old_tail;
+  GPR_ASSERT(!s->included[id]);
+  old_tail = t->lists[id].tail;
+  s->links[id].next = NULL;
+  s->links[id].prev = old_tail;
+  if (old_tail) {
+    old_tail->links[id].next = s;
+  } else {
+    s->links[id].prev = NULL;
+    t->lists[id].head = s;
+  }
+  t->lists[id].tail = s;
+  s->included[id] = 1;
+}
+
+static void stream_list_join(transport *t, stream *s, stream_list_id id) {
+  if (s->included[id]) {
+    return;
+  }
+  stream_list_add_tail(t, s, id);
+}
+
+static void remove_from_stream_map(transport *t, stream *s) {
+  if (s->id == 0) return;
+  if (grpc_chttp2_stream_map_delete(&t->stream_map, s->id)) {
+    maybe_start_some_streams(t);
+  }
+}
+
+/*
+ * LOCK MANAGEMENT
+ */
+
+/* We take a transport-global lock in response to calls coming in from above,
+   and in response to data being received from below. New data to be written
+   is always queued, as are callbacks to process data. During unlock() we
+   check our todo lists and initiate callbacks and flush writes. */
+
+static void lock(transport *t) { gpr_mu_lock(&t->mu); }
+
+static void unlock(transport *t) {
+  int start_write = 0;
+  int perform_callbacks = 0;
+  int call_closed = 0;
+  grpc_endpoint *ep = t->ep;
+
+  /* see if we need to trigger a write - and if so, get the data ready */
+  if (ep && !t->writing) {
+    t->writing = start_write = prepare_write(t);
+    if (start_write) {
+      ref_transport(t);
+    }
+  }
+
+  /* gather any callbacks that need to be made */
+  if (!t->calling_back && t->cb) {
+    perform_callbacks = prepare_callbacks(t);
+    if (perform_callbacks) {
+      t->calling_back = 1;
+    }
+    if (t->error_state == ERROR_STATE_SEEN) {
+      call_closed = 1;
+      t->calling_back = 1;
+      t->error_state = ERROR_STATE_NOTIFIED;
+    }
+  }
+
+  if (perform_callbacks || call_closed) {
+    ref_transport(t);
+  }
+
+  /* finally unlock */
+  gpr_mu_unlock(&t->mu);
+
+  /* perform some callbacks if necessary */
+  if (perform_callbacks) {
+    run_callbacks(t);
+  }
+
+  if (call_closed) {
+    t->cb->closed(t->cb_user_data, &t->base);
+  }
+
+  /* write some bytes if necessary */
+  while (start_write) {
+    switch (grpc_endpoint_write(ep, t->outbuf.slices, t->outbuf.count,
+                                finish_write, t, gpr_inf_future)) {
+      case GRPC_ENDPOINT_WRITE_DONE:
+        /* grab the lock directly without wrappers since we just want to
+           continue writes if we loop: no need to check read callbacks again */
+        gpr_mu_lock(&t->mu);
+        t->outbuf.count = 0;
+        t->outbuf.length = 0;
+        t->writing = start_write = prepare_write(t);
+        if (!start_write) {
+          if (!t->reading) {
+            grpc_endpoint_destroy(t->ep);
+            t->ep = NULL;
+            gpr_cv_broadcast(&t->cv);
+            /* endpoint ref: safe because we'll still have the ref for write */
+            unref_transport(t);
+          }
+        }
+        gpr_mu_unlock(&t->mu);
+        if (!start_write) {
+          unref_transport(t);
+        }
+        break;
+      case GRPC_ENDPOINT_WRITE_ERROR:
+        start_write = 0;
+        /* use the wrapper lock/unlock here as we drop_connection, causing
+           read callbacks to be queued (which will be cleared during unlock) */
+        lock(t);
+        t->outbuf.count = 0;
+        t->outbuf.length = 0;
+        t->writing = 0;
+        drop_connection(t);
+        if (!t->reading) {
+          grpc_endpoint_destroy(t->ep);
+          t->ep = NULL;
+          gpr_cv_broadcast(&t->cv);
+          /* endpoint ref: safe because we'll still have the ref for write */
+          unref_transport(t);
+        }
+        unlock(t);
+        unref_transport(t);
+        break;
+      case GRPC_ENDPOINT_WRITE_PENDING:
+        start_write = 0;
+        break;
+    }
+  }
+
+  if (perform_callbacks || call_closed) {
+    lock(t);
+    t->calling_back = 0;
+    gpr_cv_broadcast(&t->cv);
+    unlock(t);
+    unref_transport(t);
+  }
+}
+
+/*
+ * OUTPUT PROCESSING
+ */
+
+static void push_setting(transport *t, grpc_chttp2_setting_id id,
+                         gpr_uint32 value) {
+  const grpc_chttp2_setting_parameters *sp =
+      &grpc_chttp2_settings_parameters[id];
+  gpr_uint32 use_value = GPR_CLAMP(value, sp->min_value, sp->max_value);
+  if (use_value != value) {
+    gpr_log(GPR_INFO, "Requested parameter %s clamped from %d to %d", sp->name,
+            value, use_value);
+  }
+  if (use_value != t->settings[LOCAL_SETTINGS][id]) {
+    t->settings[LOCAL_SETTINGS][id] = use_value;
+    t->dirtied_local_settings = 1;
+  }
+}
+
+static void finish_write(void *tp, grpc_endpoint_cb_status error) {
+  transport *t = tp;
+
+  lock(t);
+  if (error != GRPC_ENDPOINT_CB_OK) {
+    drop_connection(t);
+  }
+  t->outbuf.count = 0;
+  t->outbuf.length = 0;
+  /* leave the writing flag up on shutdown to prevent further writes in unlock()
+     from starting */
+  t->writing = 0;
+  if (!t->reading) {
+    grpc_endpoint_destroy(t->ep);
+    t->ep = NULL;
+    gpr_cv_broadcast(&t->cv);
+    unref_transport(t); /* safe because we'll still have the ref for write */
+  }
+  unlock(t);
+
+  unref_transport(t);
+}
+
+static int prepare_write(transport *t) {
+  stream *s;
+  gpr_slice_buffer tempbuf;
+
+  /* simple writes are queued to qbuf, and flushed here */
+  tempbuf = t->qbuf;
+  t->qbuf = t->outbuf;
+  t->outbuf = tempbuf;
+  GPR_ASSERT(t->qbuf.count == 0);
+
+  if (t->dirtied_local_settings && !t->sent_local_settings) {
+    gpr_slice_buffer_add(
+        &t->outbuf, grpc_chttp2_settings_create(t->settings[SENT_SETTINGS],
+                                                t->settings[LOCAL_SETTINGS],
+                                                GRPC_CHTTP2_NUM_SETTINGS));
+    t->dirtied_local_settings = 0;
+    t->sent_local_settings = 1;
+  }
+
+  /* for each stream that's become writable, frame it's data (according to
+     available window sizes) and add to the output buffer */
+  while (t->outgoing_window && (s = stream_list_remove_head(t, WRITABLE))) {
+    gpr_uint32 written = grpc_chttp2_encode_some(
+        s->outgoing_sopb.ops, &s->outgoing_sopb.nops, s->write_closed,
+        &t->outbuf, GPR_MIN(t->outgoing_window, s->outgoing_window), s->id,
+        &t->hpack_compressor);
+    t->outgoing_window -= written;
+    s->outgoing_window -= written;
+
+    /* if there are no more writes to do and writes are closed, we need to
+       queue a callback to let the application know */
+    if (s->write_closed && s->outgoing_sopb.nops == 0) {
+      stream_list_join(t, s, PENDING_CALLBACKS);
+    }
+
+    /* if there are still writes to do and the stream still has window
+       available, then schedule a further write */
+    if (s->outgoing_sopb.nops && s->outgoing_window) {
+      GPR_ASSERT(!t->outgoing_window);
+      stream_list_add_tail(t, s, WRITABLE);
+    }
+  }
+
+  /* for each stream that wants to update its window, add that window here */
+  while ((s = stream_list_remove_head(t, WINDOW_UPDATE))) {
+    gpr_uint32 window_add = DEFAULT_WINDOW - s->incoming_window;
+    if (!s->read_closed && window_add) {
+      gpr_slice_buffer_add(&t->outbuf,
+                           grpc_chttp2_window_update_create(s->id, window_add));
+      s->incoming_window += window_add;
+    }
+  }
+
+  /* if the transport is ready to send a window update, do so here also */
+  if (t->incoming_window < DEFAULT_WINDOW / 2) {
+    gpr_uint32 window_add = DEFAULT_WINDOW - t->incoming_window;
+    gpr_slice_buffer_add(&t->outbuf,
+                         grpc_chttp2_window_update_create(0, window_add));
+    t->incoming_window += window_add;
+  }
+
+  return t->outbuf.length > 0;
+}
+
+static void maybe_start_some_streams(transport *t) {
+  while (
+      grpc_chttp2_stream_map_size(&t->stream_map) <
+      t->settings[PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]) {
+    stream *s = stream_list_remove_head(t, WAITING_FOR_CONCURRENCY);
+    if (!s) break;
+
+    GPR_ASSERT(s->id == 0);
+    s->id = t->next_stream_id;
+    t->next_stream_id += 2;
+    grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
+    stream_list_join(t, s, WRITABLE);
+  }
+}
+
+static void send_batch(grpc_transport *gt, grpc_stream *gs, grpc_stream_op *ops,
+                       size_t ops_count, int is_last) {
+  transport *t = (transport *)gt;
+  stream *s = (stream *)gs;
+
+  lock(t);
+
+  if (is_last) {
+    s->write_closed = 1;
+  }
+  if (!s->cancelled) {
+    grpc_sopb_append(&s->outgoing_sopb, ops, ops_count);
+    if (is_last && s->outgoing_sopb.nops == 0) {
+      if (s->id != 0) {
+        gpr_slice_buffer_add(&t->qbuf,
+                             grpc_chttp2_data_frame_create_empty_close(s->id));
+      }
+    } else if (s->id == 0) {
+      stream_list_join(t, s, WAITING_FOR_CONCURRENCY);
+      maybe_start_some_streams(t);
+    } else if (s->outgoing_window) {
+      stream_list_join(t, s, WRITABLE);
+    }
+  } else {
+    grpc_stream_ops_unref_owned_objects(ops, ops_count);
+  }
+  if (is_last && s->outgoing_sopb.nops == 0 && s->read_closed) {
+    stream_list_join(t, s, PENDING_CALLBACKS);
+  }
+
+  unlock(t);
+}
+
+static void abort_stream(grpc_transport *gt, grpc_stream *gs,
+                         grpc_status_code status) {
+  transport *t = (transport *)gt;
+  stream *s = (stream *)gs;
+
+  lock(t);
+  cancel_stream(t, s, status, grpc_chttp2_grpc_status_to_http2_error(status),
+                1);
+  unlock(t);
+}
+
+static void send_ping(grpc_transport *gt, void (*cb)(void *user_data),
+                      void *user_data) {
+  transport *t = (transport *)gt;
+  outstanding_ping *p;
+
+  lock(t);
+  if (t->ping_capacity == t->ping_count) {
+    t->ping_capacity = GPR_MAX(1, t->ping_capacity * 3 / 2);
+    t->pings =
+        gpr_realloc(t->pings, sizeof(outstanding_ping) * t->ping_capacity);
+  }
+  p = &t->pings[t->ping_count++];
+  p->id[0] = t->ping_counter >> 56;
+  p->id[1] = t->ping_counter >> 48;
+  p->id[2] = t->ping_counter >> 40;
+  p->id[3] = t->ping_counter >> 32;
+  p->id[4] = t->ping_counter >> 24;
+  p->id[5] = t->ping_counter >> 16;
+  p->id[6] = t->ping_counter >> 8;
+  p->id[7] = t->ping_counter;
+  p->cb = cb;
+  p->user_data = user_data;
+  gpr_slice_buffer_add(&t->qbuf, grpc_chttp2_ping_create(0, p->id));
+  unlock(t);
+}
+
+/*
+ * INPUT PROCESSING
+ */
+
+static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id,
+                                grpc_status_code local_status,
+                                grpc_chttp2_error_code error_code,
+                                int send_rst) {
+  char buffer[32];
+  int had_outgoing;
+
+  if (s) {
+    /* clear out any unreported input & output: nobody cares anymore */
+    grpc_sopb_reset(&s->parser.incoming_sopb);
+    had_outgoing = s->outgoing_sopb.nops != 0;
+    grpc_sopb_reset(&s->outgoing_sopb);
+    if (s->cancelled) {
+      send_rst = 0;
+    } else if (!s->read_closed || !s->write_closed || had_outgoing) {
+      s->cancelled = 1;
+      s->read_closed = 1;
+      s->write_closed = 1;
+
+      sprintf(buffer, "%d", local_status);
+      grpc_sopb_add_metadata(
+          &s->parser.incoming_sopb,
+          grpc_mdelem_from_strings(t->metadata_context, "grpc-status", buffer));
+
+      stream_list_join(t, s, PENDING_CALLBACKS);
+    }
+  }
+  if (!id) send_rst = 0;
+  if (send_rst) {
+    gpr_slice_buffer_add(&t->qbuf,
+                         grpc_chttp2_rst_stream_create(id, error_code));
+  }
+}
+
+static void cancel_stream_id(transport *t, gpr_uint32 id,
+                             grpc_status_code local_status,
+                             grpc_chttp2_error_code error_code, int send_rst) {
+  cancel_stream_inner(t, lookup_stream(t, id), id, local_status, error_code,
+                      send_rst);
+}
+
+static void cancel_stream(transport *t, stream *s,
+                          grpc_status_code local_status,
+                          grpc_chttp2_error_code error_code, int send_rst) {
+  cancel_stream_inner(t, s, s->id, local_status, error_code, send_rst);
+}
+
+static void cancel_stream_cb(void *user_data, gpr_uint32 id, void *stream) {
+  cancel_stream(user_data, stream, GRPC_STATUS_UNAVAILABLE,
+                GRPC_CHTTP2_INTERNAL_ERROR, 0);
+}
+
+static void end_all_the_calls(transport *t) {
+  grpc_chttp2_stream_map_for_each(&t->stream_map, cancel_stream_cb, t);
+}
+
+static void drop_connection(transport *t) {
+  if (t->error_state == ERROR_STATE_NONE) {
+    t->error_state = ERROR_STATE_SEEN;
+  }
+  end_all_the_calls(t);
+}
+
+static void maybe_join_window_updates(transport *t, stream *s) {
+  if (s->allow_window_updates && s->incoming_window < DEFAULT_WINDOW / 2) {
+    stream_list_join(t, s, WINDOW_UPDATE);
+  }
+}
+
+static void set_allow_window_updates(grpc_transport *tp, grpc_stream *sp,
+                                     int allow) {
+  transport *t = (transport *)tp;
+  stream *s = (stream *)sp;
+
+  lock(t);
+  s->allow_window_updates = allow;
+  if (allow) {
+    maybe_join_window_updates(t, s);
+  } else {
+    stream_list_remove(t, s, WINDOW_UPDATE);
+  }
+  unlock(t);
+}
+
+static grpc_chttp2_parse_error update_incoming_window(transport *t, stream *s) {
+  if (t->incoming_frame_size > t->incoming_window) {
+    gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
+            t->incoming_frame_size, t->incoming_window);
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  }
+
+  if (t->incoming_frame_size > s->incoming_window) {
+    gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
+            t->incoming_frame_size, s->incoming_window);
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  }
+
+  t->incoming_window -= t->incoming_frame_size;
+  s->incoming_window -= t->incoming_frame_size;
+
+  /* if the stream incoming window is getting low, schedule an update */
+  maybe_join_window_updates(t, s);
+
+  return GRPC_CHTTP2_PARSE_OK;
+}
+
+static stream *lookup_stream(transport *t, gpr_uint32 id) {
+  return grpc_chttp2_stream_map_find(&t->stream_map, id);
+}
+
+static grpc_chttp2_parse_error skip_parser(void *parser,
+                                           grpc_chttp2_parse_state *st,
+                                           gpr_slice slice, int is_last) {
+  return GRPC_CHTTP2_PARSE_OK;
+}
+
+static void skip_header(void *tp, grpc_mdelem *md) { grpc_mdelem_unref(md); }
+
+static int init_skip_frame(transport *t, int is_header) {
+  if (is_header) {
+    int is_eoh = t->expect_continuation_stream_id != 0;
+    t->parser = grpc_chttp2_header_parser_parse;
+    t->parser_data = &t->hpack_parser;
+    t->hpack_parser.on_header = skip_header;
+    t->hpack_parser.on_header_user_data = NULL;
+    t->hpack_parser.is_boundary = is_eoh;
+    t->hpack_parser.is_eof = is_eoh ? t->header_eof : 0;
+  } else {
+    t->parser = skip_parser;
+  }
+  return 1;
+}
+
+static void become_skip_parser(transport *t) {
+  init_skip_frame(t, t->parser == grpc_chttp2_header_parser_parse);
+}
+
+static int init_data_frame_parser(transport *t) {
+  stream *s = lookup_stream(t, t->incoming_stream_id);
+  grpc_chttp2_parse_error err = GRPC_CHTTP2_PARSE_OK;
+  if (!s || s->read_closed) return init_skip_frame(t, 0);
+  if (err == GRPC_CHTTP2_PARSE_OK) {
+    err = update_incoming_window(t, s);
+  }
+  if (err == GRPC_CHTTP2_PARSE_OK) {
+    err = grpc_chttp2_data_parser_begin_frame(&s->parser,
+                                              t->incoming_frame_flags);
+  }
+  switch (err) {
+    case GRPC_CHTTP2_PARSE_OK:
+      t->incoming_stream = s;
+      t->parser = grpc_chttp2_data_parser_parse;
+      t->parser_data = &s->parser;
+      return 1;
+    case GRPC_CHTTP2_STREAM_ERROR:
+      cancel_stream(t, s, grpc_chttp2_http2_error_to_grpc_status(
+                              GRPC_CHTTP2_INTERNAL_ERROR),
+                    GRPC_CHTTP2_INTERNAL_ERROR, 1);
+      return init_skip_frame(t, 0);
+    case GRPC_CHTTP2_CONNECTION_ERROR:
+      drop_connection(t);
+      return 0;
+  }
+  gpr_log(GPR_ERROR, "should never reach here");
+  abort();
+  return 0;
+}
+
+static void free_timeout(void *p) { gpr_free(p); }
+
+static void on_header(void *tp, grpc_mdelem *md) {
+  transport *t = tp;
+  stream *s = t->incoming_stream;
+
+  GPR_ASSERT(s);
+  stream_list_join(t, s, PENDING_CALLBACKS);
+  if (md->key == t->str_grpc_timeout) {
+    gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout);
+    if (!cached_timeout) {
+      /* not already parsed: parse it now, and store the result away */
+      cached_timeout = gpr_malloc(sizeof(gpr_timespec));
+      if (!grpc_chttp2_decode_timeout(grpc_mdstr_as_c_string(md->value),
+                                      cached_timeout)) {
+        gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'",
+                grpc_mdstr_as_c_string(md->value));
+        *cached_timeout = gpr_inf_future;
+      }
+      grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
+    }
+    grpc_sopb_add_deadline(&s->parser.incoming_sopb,
+                           gpr_time_add(gpr_now(), *cached_timeout));
+    grpc_mdelem_unref(md);
+  } else {
+    grpc_sopb_add_metadata(&s->parser.incoming_sopb, md);
+  }
+}
+
+static int init_header_frame_parser(transport *t, int is_continuation) {
+  int is_eoh =
+      (t->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0;
+  stream *s;
+
+  if (is_eoh) {
+    t->expect_continuation_stream_id = 0;
+  } else {
+    t->expect_continuation_stream_id = t->incoming_stream_id;
+  }
+
+  if (!is_continuation) {
+    t->header_eof =
+        (t->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0;
+  }
+
+  /* could be a new stream or an existing stream */
+  s = lookup_stream(t, t->incoming_stream_id);
+  if (!s) {
+    if (is_continuation) {
+      gpr_log(GPR_ERROR, "stream disbanded before CONTINUATION received");
+      return init_skip_frame(t, 1);
+    }
+    if (t->is_client) {
+      if ((t->incoming_stream_id & 1) &&
+          t->incoming_stream_id < t->next_stream_id) {
+        /* this is an old (probably cancelled) stream */
+      } else {
+        gpr_log(GPR_ERROR, "ignoring new stream creation on client");
+      }
+      return init_skip_frame(t, 1);
+    }
+    t->incoming_stream = NULL;
+    /* if stream is accepted, we set incoming_stream in init_stream */
+    t->cb->accept_stream(t->cb_user_data, &t->base,
+                         (void *)(gpr_uintptr)t->incoming_stream_id);
+    s = t->incoming_stream;
+    if (!s) {
+      gpr_log(GPR_ERROR, "stream not accepted");
+      return init_skip_frame(t, 1);
+    }
+  } else {
+    t->incoming_stream = s;
+  }
+  if (t->incoming_stream->read_closed) {
+    gpr_log(GPR_ERROR, "skipping already closed stream header");
+    t->incoming_stream = NULL;
+    return init_skip_frame(t, 1);
+  }
+  t->parser = grpc_chttp2_header_parser_parse;
+  t->parser_data = &t->hpack_parser;
+  t->hpack_parser.on_header = on_header;
+  t->hpack_parser.on_header_user_data = t;
+  t->hpack_parser.is_boundary = is_eoh;
+  t->hpack_parser.is_eof = 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);
+  }
+  return 1;
+}
+
+static int init_window_update_frame_parser(transport *t) {
+  int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_window_update_parser_begin_frame(
+                                       &t->simple_parsers.window_update,
+                                       t->incoming_frame_size,
+                                       t->incoming_frame_flags);
+  if (!ok) {
+    drop_connection(t);
+  }
+  t->parser = grpc_chttp2_window_update_parser_parse;
+  t->parser_data = &t->simple_parsers.window_update;
+  return ok;
+}
+
+static int init_ping_parser(transport *t) {
+  int ok = GRPC_CHTTP2_PARSE_OK ==
+           grpc_chttp2_ping_parser_begin_frame(&t->simple_parsers.ping,
+                                               t->incoming_frame_size,
+                                               t->incoming_frame_flags);
+  if (!ok) {
+    drop_connection(t);
+  }
+  t->parser = grpc_chttp2_ping_parser_parse;
+  t->parser_data = &t->simple_parsers.ping;
+  return ok;
+}
+
+static int init_settings_frame_parser(transport *t) {
+  int ok = GRPC_CHTTP2_PARSE_OK ==
+           grpc_chttp2_settings_parser_begin_frame(
+               &t->simple_parsers.settings, t->incoming_frame_size,
+               t->incoming_frame_flags, t->settings[PEER_SETTINGS]);
+  if (!ok) {
+    drop_connection(t);
+  }
+  if (t->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) {
+    memcpy(t->settings[ACKED_SETTINGS], t->settings[SENT_SETTINGS],
+           GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
+  }
+  t->parser = grpc_chttp2_settings_parser_parse;
+  t->parser_data = &t->simple_parsers.settings;
+  return ok;
+}
+
+static int init_frame_parser(transport *t) {
+  if (t->expect_continuation_stream_id != 0) {
+    if (t->incoming_frame_type != GRPC_CHTTP2_FRAME_CONTINUATION) {
+      gpr_log(GPR_ERROR, "Expected CONTINUATION frame, got frame type %02x",
+              t->incoming_frame_type);
+      return 0;
+    }
+    if (t->expect_continuation_stream_id != t->incoming_stream_id) {
+      gpr_log(GPR_ERROR,
+              "Expected CONTINUATION frame for stream %08x, got stream %08x",
+              t->expect_continuation_stream_id, t->incoming_stream_id);
+      return 0;
+    }
+    return init_header_frame_parser(t, 1);
+  }
+  switch (t->incoming_frame_type) {
+    case GRPC_CHTTP2_FRAME_DATA:
+      return init_data_frame_parser(t);
+    case GRPC_CHTTP2_FRAME_HEADER:
+      return init_header_frame_parser(t, 0);
+    case GRPC_CHTTP2_FRAME_CONTINUATION:
+      gpr_log(GPR_ERROR, "Unexpected CONTINUATION frame");
+      return 0;
+    case GRPC_CHTTP2_FRAME_RST_STREAM:
+      /* TODO(ctiller): actually parse the reason */
+      cancel_stream_id(
+          t, t->incoming_stream_id,
+          grpc_chttp2_http2_error_to_grpc_status(GRPC_CHTTP2_CANCEL),
+          GRPC_CHTTP2_CANCEL, 0);
+      return init_skip_frame(t, 0);
+    case GRPC_CHTTP2_FRAME_SETTINGS:
+      return init_settings_frame_parser(t);
+    case GRPC_CHTTP2_FRAME_WINDOW_UPDATE:
+      return init_window_update_frame_parser(t);
+    case GRPC_CHTTP2_FRAME_PING:
+      return init_ping_parser(t);
+    default:
+      gpr_log(GPR_ERROR, "Unknown frame type %02x", t->incoming_frame_type);
+      return init_skip_frame(t, 0);
+  }
+}
+
+static int is_window_update_legal(gpr_uint32 window_update, gpr_uint32 window) {
+  return window_update < MAX_WINDOW - window;
+}
+
+static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) {
+  grpc_chttp2_parse_state st;
+  size_t i;
+  memset(&st, 0, sizeof(st));
+  switch (t->parser(t->parser_data, &st, slice, is_last)) {
+    case GRPC_CHTTP2_PARSE_OK:
+      if (st.end_of_stream) {
+        t->incoming_stream->read_closed = 1;
+        stream_list_join(t, t->incoming_stream, PENDING_CALLBACKS);
+      }
+      if (st.need_flush_reads) {
+        stream_list_join(t, t->incoming_stream, PENDING_CALLBACKS);
+      }
+      if (st.metadata_boundary) {
+        grpc_sopb_add_metadata_boundary(
+            &t->incoming_stream->parser.incoming_sopb);
+        stream_list_join(t, t->incoming_stream, PENDING_CALLBACKS);
+      }
+      if (st.ack_settings) {
+        gpr_slice_buffer_add(&t->qbuf, grpc_chttp2_settings_ack_create());
+        maybe_start_some_streams(t);
+      }
+      if (st.send_ping_ack) {
+        gpr_slice_buffer_add(
+            &t->qbuf,
+            grpc_chttp2_ping_create(1, t->simple_parsers.ping.opaque_8bytes));
+      }
+      if (st.process_ping_reply) {
+        for (i = 0; i < t->ping_count; i++) {
+          if (0 ==
+              memcmp(t->pings[i].id, t->simple_parsers.ping.opaque_8bytes, 8)) {
+            t->pings[i].cb(t->pings[i].user_data);
+            memmove(&t->pings[i], &t->pings[i + 1],
+                    (t->ping_count - i - 1) * sizeof(outstanding_ping));
+            t->ping_count--;
+            break;
+          }
+        }
+      }
+      if (st.window_update) {
+        if (t->incoming_stream_id) {
+          /* if there was a stream id, this is for some stream */
+          stream *s = lookup_stream(t, t->incoming_stream_id);
+          if (s) {
+            int was_window_empty = s->outgoing_window == 0;
+            if (!is_window_update_legal(st.window_update, s->outgoing_window)) {
+              cancel_stream(t, s, grpc_chttp2_http2_error_to_grpc_status(
+                                      GRPC_CHTTP2_FLOW_CONTROL_ERROR),
+                            GRPC_CHTTP2_FLOW_CONTROL_ERROR, 1);
+            } else {
+              s->outgoing_window += st.window_update;
+              /* if this window update makes outgoing ops writable again,
+                 flag that */
+              if (was_window_empty && s->outgoing_sopb.nops) {
+                stream_list_join(t, s, WRITABLE);
+              }
+            }
+          }
+        } else {
+          /* transport level window update */
+          if (!is_window_update_legal(st.window_update, t->outgoing_window)) {
+            drop_connection(t);
+          } else {
+            t->outgoing_window += st.window_update;
+          }
+        }
+      }
+      return 1;
+    case GRPC_CHTTP2_STREAM_ERROR:
+      become_skip_parser(t);
+      cancel_stream_id(
+          t, t->incoming_stream_id,
+          grpc_chttp2_http2_error_to_grpc_status(GRPC_CHTTP2_INTERNAL_ERROR),
+          GRPC_CHTTP2_INTERNAL_ERROR, 1);
+      return 1;
+    case GRPC_CHTTP2_CONNECTION_ERROR:
+      drop_connection(t);
+      return 0;
+  }
+  gpr_log(GPR_ERROR, "should never reach here");
+  abort();
+  return 0;
+}
+
+static int process_read(transport *t, gpr_slice slice) {
+  gpr_uint8 *beg = GPR_SLICE_START_PTR(slice);
+  gpr_uint8 *end = GPR_SLICE_END_PTR(slice);
+  gpr_uint8 *cur = beg;
+
+  if (cur == end) return 1;
+
+  switch (t->deframe_state) {
+    case DTS_CLIENT_PREFIX_0:
+    case DTS_CLIENT_PREFIX_1:
+    case DTS_CLIENT_PREFIX_2:
+    case DTS_CLIENT_PREFIX_3:
+    case DTS_CLIENT_PREFIX_4:
+    case DTS_CLIENT_PREFIX_5:
+    case DTS_CLIENT_PREFIX_6:
+    case DTS_CLIENT_PREFIX_7:
+    case DTS_CLIENT_PREFIX_8:
+    case DTS_CLIENT_PREFIX_9:
+    case DTS_CLIENT_PREFIX_10:
+    case DTS_CLIENT_PREFIX_11:
+    case DTS_CLIENT_PREFIX_12:
+    case DTS_CLIENT_PREFIX_13:
+    case DTS_CLIENT_PREFIX_14:
+    case DTS_CLIENT_PREFIX_15:
+    case DTS_CLIENT_PREFIX_16:
+    case DTS_CLIENT_PREFIX_17:
+    case DTS_CLIENT_PREFIX_18:
+    case DTS_CLIENT_PREFIX_19:
+    case DTS_CLIENT_PREFIX_20:
+    case DTS_CLIENT_PREFIX_21:
+    case DTS_CLIENT_PREFIX_22:
+    case DTS_CLIENT_PREFIX_23:
+      while (cur != end && t->deframe_state != DTS_FH_0) {
+        if (*cur != CLIENT_CONNECT_STRING[t->deframe_state]) {
+          gpr_log(GPR_ERROR,
+                  "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
+                  "at byte %d",
+                  CLIENT_CONNECT_STRING[t->deframe_state],
+                  (int)(gpr_uint8)CLIENT_CONNECT_STRING[t->deframe_state], *cur,
+                  (int)*cur, t->deframe_state);
+          return 0;
+        }
+        ++cur;
+        ++t->deframe_state;
+      }
+      if (cur == end) {
+        return 1;
+      }
+    /* fallthrough */
+    dts_fh_0:
+    case DTS_FH_0:
+      GPR_ASSERT(cur < end);
+      t->incoming_frame_size = ((gpr_uint32)*cur) << 16;
+      if (++cur == end) {
+        t->deframe_state = DTS_FH_1;
+        return 1;
+      }
+    /* fallthrough */
+    case DTS_FH_1:
+      GPR_ASSERT(cur < end);
+      t->incoming_frame_size |= ((gpr_uint32)*cur) << 8;
+      if (++cur == end) {
+        t->deframe_state = DTS_FH_2;
+        return 1;
+      }
+    /* fallthrough */
+    case DTS_FH_2:
+      GPR_ASSERT(cur < end);
+      t->incoming_frame_size |= *cur;
+      if (++cur == end) {
+        t->deframe_state = DTS_FH_3;
+        return 1;
+      }
+    /* fallthrough */
+    case DTS_FH_3:
+      GPR_ASSERT(cur < end);
+      t->incoming_frame_type = *cur;
+      if (++cur == end) {
+        t->deframe_state = DTS_FH_4;
+        return 1;
+      }
+    /* fallthrough */
+    case DTS_FH_4:
+      GPR_ASSERT(cur < end);
+      t->incoming_frame_flags = *cur;
+      if (++cur == end) {
+        t->deframe_state = DTS_FH_5;
+        return 1;
+      }
+    /* fallthrough */
+    case DTS_FH_5:
+      GPR_ASSERT(cur < end);
+      t->incoming_stream_id = (((gpr_uint32)*cur) << 24) & 0x7f;
+      if (++cur == end) {
+        t->deframe_state = DTS_FH_6;
+        return 1;
+      }
+    /* fallthrough */
+    case DTS_FH_6:
+      GPR_ASSERT(cur < end);
+      t->incoming_stream_id |= ((gpr_uint32)*cur) << 16;
+      if (++cur == end) {
+        t->deframe_state = DTS_FH_7;
+        return 1;
+      }
+    /* fallthrough */
+    case DTS_FH_7:
+      GPR_ASSERT(cur < end);
+      t->incoming_stream_id |= ((gpr_uint32)*cur) << 8;
+      if (++cur == end) {
+        t->deframe_state = DTS_FH_8;
+        return 1;
+      }
+    /* fallthrough */
+    case DTS_FH_8:
+      GPR_ASSERT(cur < end);
+      t->incoming_stream_id |= ((gpr_uint32)*cur);
+      t->deframe_state = DTS_FRAME;
+      if (!init_frame_parser(t)) {
+        return 0;
+      }
+      if (t->incoming_frame_size == 0) {
+        if (!parse_frame_slice(t, gpr_empty_slice(), 1)) {
+          return 0;
+        }
+        if (++cur == end) {
+          t->deframe_state = DTS_FH_0;
+          return 1;
+        }
+        goto dts_fh_0; /* loop */
+      }
+      if (++cur == end) {
+        return 1;
+      }
+    /* fallthrough */
+    case DTS_FRAME:
+      GPR_ASSERT(cur < end);
+      if (end - cur == t->incoming_frame_size) {
+        if (!parse_frame_slice(
+                t, gpr_slice_sub_no_ref(slice, cur - beg, end - beg), 1)) {
+          return 0;
+        }
+        t->deframe_state = DTS_FH_0;
+        return 1;
+      } else if (end - cur > t->incoming_frame_size) {
+        if (!parse_frame_slice(
+                t, gpr_slice_sub_no_ref(slice, cur - beg,
+                                        cur + t->incoming_frame_size - beg),
+                1)) {
+          return 0;
+        }
+        cur += t->incoming_frame_size;
+        goto dts_fh_0; /* loop */
+      } else {
+        if (!parse_frame_slice(
+                t, gpr_slice_sub_no_ref(slice, cur - beg, end - beg), 0)) {
+          return 0;
+        }
+        t->incoming_frame_size -= (end - cur);
+        return 1;
+      }
+      gpr_log(GPR_ERROR, "should never reach here");
+      abort();
+  }
+
+  gpr_log(GPR_ERROR, "should never reach here");
+  abort();
+}
+
+/* tcp read callback */
+static void recv_data(void *tp, gpr_slice *slices, size_t nslices,
+                      grpc_endpoint_cb_status error) {
+  transport *t = tp;
+  size_t i;
+  int keep_reading = 0;
+
+  switch (error) {
+    case GRPC_ENDPOINT_CB_SHUTDOWN:
+    case GRPC_ENDPOINT_CB_EOF:
+    case GRPC_ENDPOINT_CB_ERROR:
+    case GRPC_ENDPOINT_CB_TIMED_OUT:
+      lock(t);
+      drop_connection(t);
+      t->reading = 0;
+      if (!t->writing && t->ep) {
+        grpc_endpoint_destroy(t->ep);
+        t->ep = NULL;
+        gpr_cv_broadcast(&t->cv);
+        unref_transport(t); /* safe as we still have a ref for read */
+      }
+      unlock(t);
+      unref_transport(t);
+      break;
+    case GRPC_ENDPOINT_CB_OK:
+      lock(t);
+      for (i = 0; i < nslices && process_read(t, slices[i]); i++)
+        ;
+      unlock(t);
+      keep_reading = 1;
+      break;
+  }
+
+  for (i = 0; i < nslices; i++) gpr_slice_unref(slices[i]);
+
+  if (keep_reading) {
+    grpc_endpoint_notify_on_read(t->ep, recv_data, t, gpr_inf_future);
+  }
+}
+
+/*
+ * CALLBACK LOOP
+ */
+
+static grpc_stream_state compute_state(gpr_uint8 write_closed,
+                                       gpr_uint8 read_closed) {
+  if (write_closed && read_closed) return GRPC_STREAM_CLOSED;
+  if (write_closed) return GRPC_STREAM_SEND_CLOSED;
+  if (read_closed) return GRPC_STREAM_RECV_CLOSED;
+  return GRPC_STREAM_OPEN;
+}
+
+static int prepare_callbacks(transport *t) {
+  stream *s;
+  grpc_stream_op_buffer temp_sopb;
+  int n = 0;
+  while ((s = stream_list_remove_head(t, PENDING_CALLBACKS))) {
+    int execute = 1;
+    temp_sopb = s->parser.incoming_sopb;
+    s->parser.incoming_sopb = s->callback_sopb;
+    s->callback_sopb = temp_sopb;
+
+    s->callback_state = compute_state(
+        s->write_closed && s->outgoing_sopb.nops == 0, s->read_closed);
+    if (s->callback_state == GRPC_STREAM_CLOSED) {
+      remove_from_stream_map(t, s);
+      if (s->published_close) {
+        execute = 0;
+      }
+      s->published_close = 1;
+    }
+
+    if (execute) {
+      stream_list_add_tail(t, s, EXECUTING_CALLBACKS);
+      n = 1;
+    }
+  }
+  return n;
+}
+
+static void run_callbacks(transport *t) {
+  stream *s;
+  while ((s = stream_list_remove_head(t, EXECUTING_CALLBACKS))) {
+    size_t nops = s->callback_sopb.nops;
+    s->callback_sopb.nops = 0;
+    t->cb->recv_batch(t->cb_user_data, &t->base, (grpc_stream *)s,
+                      s->callback_sopb.ops, nops, s->callback_state);
+  }
+}
+
+/*
+ * INTEGRATION GLUE
+ */
+
+static const grpc_transport_vtable vtable = {
+    sizeof(stream), init_stream, send_batch, set_allow_window_updates,
+    destroy_stream, abort_stream, close_transport, send_ping,
+    destroy_transport};
+
+void grpc_create_chttp2_transport(grpc_transport_setup_callback setup,
+                                  void *arg,
+                                  const grpc_channel_args *channel_args,
+                                  grpc_endpoint *ep, gpr_slice *slices,
+                                  size_t nslices, grpc_mdctx *mdctx,
+                                  int is_client) {
+  transport *t = gpr_malloc(sizeof(transport));
+  init_transport(t, setup, arg, channel_args, ep, mdctx, is_client);
+  ref_transport(t);
+  recv_data(t, slices, nslices, GRPC_ENDPOINT_CB_OK);
+}
diff --git a/src/core/transport/chttp2_transport.h b/src/core/transport/chttp2_transport.h
new file mode 100644
index 0000000..37eb84e
--- /dev/null
+++ b/src/core/transport/chttp2_transport.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_TRANSPORT_H__
+#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_TRANSPORT_H__
+
+#include "src/core/endpoint/tcp.h"
+#include "src/core/transport/transport.h"
+
+void grpc_create_chttp2_transport(grpc_transport_setup_callback setup,
+                                  void *arg,
+                                  const grpc_channel_args *channel_args,
+                                  grpc_endpoint *ep, gpr_slice *slices,
+                                  size_t nslices, grpc_mdctx *metadata_context,
+                                  int is_client);
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_TRANSPORT_H__ */
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
new file mode 100644
index 0000000..ceb77df
--- /dev/null
+++ b/src/core/transport/metadata.c
@@ -0,0 +1,525 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/metadata.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include "src/core/support/murmur_hash.h"
+#include <grpc/support/time.h>
+
+#define INITIAL_STRTAB_CAPACITY 4
+#define INITIAL_MDTAB_CAPACITY 4
+
+#define KV_HASH(key, value) ((key)->hash ^ (value)->hash)
+
+typedef struct internal_string {
+  /* must be byte compatible with grpc_mdstr */
+  gpr_slice slice;
+  gpr_uint32 hash;
+
+  /* private only data */
+  gpr_uint32 refs;
+  gpr_slice_refcount refcount;
+
+  grpc_mdctx *context;
+
+  struct internal_string *bucket_next;
+} internal_string;
+
+typedef struct internal_metadata {
+  /* must be byte compatible with grpc_mdelem */
+  internal_string *key;
+  internal_string *value;
+
+  /* private only data */
+  void *user_data;
+  void (*destroy_user_data)(void *user_data);
+
+  gpr_uint32 refs;
+  grpc_mdctx *context;
+  struct internal_metadata *bucket_next;
+} internal_metadata;
+
+struct grpc_mdctx {
+  gpr_uint32 hash_seed;
+  int orphaned;
+
+  gpr_mu mu;
+
+  internal_string **strtab;
+  size_t strtab_count;
+  size_t strtab_capacity;
+
+  internal_metadata **mdtab;
+  size_t mdtab_count;
+  size_t mdtab_free;
+  size_t mdtab_capacity;
+};
+
+static void internal_string_ref(internal_string *s);
+static void internal_string_unref(internal_string *s);
+static void discard_metadata(grpc_mdctx *ctx);
+static void gc_mdtab(grpc_mdctx *ctx);
+static void metadata_context_destroy(grpc_mdctx *ctx);
+
+static void lock(grpc_mdctx *ctx) { gpr_mu_lock(&ctx->mu); }
+
+static void unlock(grpc_mdctx *ctx) {
+  /* If the context has been orphaned we'd like to delete it soon. We check
+     conditions in unlock as it signals the end of mutations on a context.
+
+     We need to ensure all grpc_mdelem and grpc_mdstr elements have been deleted
+     first. This is equivalent to saying that both tables have zero counts,
+     which is equivalent to saying that strtab_count is zero (as mdelem's MUST
+     reference an mdstr for their key and value slots).
+
+     To encourage that to happen, we start discarding zero reference count
+     mdelems on every unlock (instead of the usual 'I'm too loaded' trigger
+     case), since otherwise we can be stuck waiting for a garbage collection
+     that will never happen. */
+  if (ctx->orphaned) {
+    /* uncomment if you're having trouble diagnosing an mdelem leak to make
+       things clearer (slows down destruction a lot, however) */
+    /* gc_mdtab(ctx); */
+    if (ctx->mdtab_count && ctx->mdtab_count == ctx->mdtab_free) {
+      discard_metadata(ctx);
+    }
+    if (ctx->strtab_count == 0) {
+      gpr_mu_unlock(&ctx->mu);
+      metadata_context_destroy(ctx);
+      return;
+    }
+  }
+  gpr_mu_unlock(&ctx->mu);
+}
+
+static void ref_md(internal_metadata *md) {
+  if (0 == md->refs++) {
+    md->context->mdtab_free--;
+  }
+}
+
+grpc_mdctx *grpc_mdctx_create_with_seed(gpr_uint32 seed) {
+  grpc_mdctx *ctx = gpr_malloc(sizeof(grpc_mdctx));
+
+  ctx->orphaned = 0;
+  ctx->hash_seed = seed;
+  gpr_mu_init(&ctx->mu);
+  ctx->strtab = gpr_malloc(sizeof(internal_string *) * INITIAL_STRTAB_CAPACITY);
+  memset(ctx->strtab, 0, sizeof(grpc_mdstr *) * INITIAL_STRTAB_CAPACITY);
+  ctx->strtab_count = 0;
+  ctx->strtab_capacity = INITIAL_STRTAB_CAPACITY;
+  ctx->mdtab = gpr_malloc(sizeof(internal_metadata *) * INITIAL_MDTAB_CAPACITY);
+  memset(ctx->mdtab, 0, sizeof(grpc_mdelem *) * INITIAL_MDTAB_CAPACITY);
+  ctx->mdtab_count = 0;
+  ctx->mdtab_capacity = INITIAL_MDTAB_CAPACITY;
+  ctx->mdtab_free = 0;
+
+  return ctx;
+}
+
+grpc_mdctx *grpc_mdctx_create() {
+  /* This seed is used to prevent remote connections from controlling hash table
+   * collisions. It needs to be somewhat unpredictable to a remote connection.
+   */
+  return grpc_mdctx_create_with_seed(gpr_now().tv_nsec);
+}
+
+static void discard_metadata(grpc_mdctx *ctx) {
+  size_t i;
+  internal_metadata *next, *cur;
+
+  for (i = 0; i < ctx->mdtab_capacity; i++) {
+    cur = ctx->mdtab[i];
+    while (cur) {
+      GPR_ASSERT(cur->refs == 0);
+      next = cur->bucket_next;
+      internal_string_unref(cur->key);
+      internal_string_unref(cur->value);
+      if (cur->user_data) {
+        cur->destroy_user_data(cur->user_data);
+      }
+      gpr_free(cur);
+      cur = next;
+      ctx->mdtab_free--;
+      ctx->mdtab_count--;
+    }
+    ctx->mdtab[i] = NULL;
+  }
+}
+
+static void metadata_context_destroy(grpc_mdctx *ctx) {
+  gpr_mu_lock(&ctx->mu);
+  GPR_ASSERT(ctx->strtab_count == 0);
+  GPR_ASSERT(ctx->mdtab_count == 0);
+  GPR_ASSERT(ctx->mdtab_free == 0);
+  gpr_free(ctx->strtab);
+  gpr_free(ctx->mdtab);
+  gpr_mu_unlock(&ctx->mu);
+  gpr_mu_destroy(&ctx->mu);
+  gpr_free(ctx);
+}
+
+void grpc_mdctx_orphan(grpc_mdctx *ctx) {
+  lock(ctx);
+  GPR_ASSERT(!ctx->orphaned);
+  ctx->orphaned = 1;
+  unlock(ctx);
+}
+
+static void grow_strtab(grpc_mdctx *ctx) {
+  size_t capacity = ctx->strtab_capacity * 2;
+  size_t i;
+  internal_string **strtab = gpr_malloc(sizeof(internal_string *) * capacity);
+  internal_string *s, *next;
+  memset(strtab, 0, sizeof(internal_string *) * capacity);
+
+  for (i = 0; i < ctx->strtab_capacity; i++) {
+    for (s = ctx->strtab[i]; s; s = next) {
+      next = s->bucket_next;
+      s->bucket_next = strtab[s->hash % capacity];
+      strtab[s->hash % capacity] = s;
+    }
+  }
+
+  gpr_free(ctx->strtab);
+  ctx->strtab = strtab;
+  ctx->strtab_capacity = capacity;
+}
+
+static void internal_destroy_string(internal_string *is) {
+  internal_string **prev_next;
+  internal_string *cur;
+  grpc_mdctx *ctx = is->context;
+  for (prev_next = &ctx->strtab[is->hash % ctx->strtab_capacity],
+      cur = *prev_next;
+       cur != is; prev_next = &cur->bucket_next, cur = cur->bucket_next)
+    ;
+  *prev_next = cur->bucket_next;
+  ctx->strtab_count--;
+  gpr_free(is);
+}
+
+static void internal_string_ref(internal_string *s) { ++s->refs; }
+
+static void internal_string_unref(internal_string *s) {
+  GPR_ASSERT(s->refs > 0);
+  if (0 == --s->refs) {
+    internal_destroy_string(s);
+  }
+}
+
+static void slice_ref(void *p) {
+  internal_string *is =
+      (internal_string *)((char *)p - offsetof(internal_string, refcount));
+  grpc_mdctx *ctx = is->context;
+  lock(ctx);
+  internal_string_ref(is);
+  unlock(ctx);
+}
+
+static void slice_unref(void *p) {
+  internal_string *is =
+      (internal_string *)((char *)p - offsetof(internal_string, refcount));
+  grpc_mdctx *ctx = is->context;
+  lock(ctx);
+  internal_string_unref(is);
+  unlock(ctx);
+}
+
+grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str) {
+  return grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)str, strlen(str));
+}
+
+grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice) {
+  grpc_mdstr *result = grpc_mdstr_from_buffer(ctx, GPR_SLICE_START_PTR(slice),
+                                              GPR_SLICE_LENGTH(slice));
+  gpr_slice_unref(slice);
+  return result;
+}
+
+grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *buf,
+                                   size_t length) {
+  gpr_uint32 hash = gpr_murmur_hash3(buf, length, ctx->hash_seed);
+  internal_string *s;
+
+  lock(ctx);
+
+  /* search for an existing string */
+  for (s = ctx->strtab[hash % ctx->strtab_capacity]; s; s = s->bucket_next) {
+    if (s->hash == hash && GPR_SLICE_LENGTH(s->slice) == length &&
+        0 == memcmp(buf, GPR_SLICE_START_PTR(s->slice), length)) {
+      internal_string_ref(s);
+      unlock(ctx);
+      return (grpc_mdstr *)s;
+    }
+  }
+
+  /* not found: create a new string */
+  if (length + 1 < GPR_SLICE_INLINED_SIZE) {
+    /* string data goes directly into the slice */
+    s = gpr_malloc(sizeof(internal_string));
+    s->refs = 1;
+    s->slice.refcount = NULL;
+    memcpy(s->slice.data.inlined.bytes, buf, length);
+    s->slice.data.inlined.bytes[length] = 0;
+    s->slice.data.inlined.length = length;
+  } else {
+    /* string data goes after the internal_string header, and we +1 for null
+       terminator */
+    s = gpr_malloc(sizeof(internal_string) + length + 1);
+    s->refs = 1;
+    s->refcount.ref = slice_ref;
+    s->refcount.unref = slice_unref;
+    s->slice.refcount = &s->refcount;
+    s->slice.data.refcounted.bytes = (gpr_uint8 *)(s + 1);
+    s->slice.data.refcounted.length = length;
+    memcpy(s->slice.data.refcounted.bytes, buf, length);
+    /* add a null terminator for cheap c string conversion when desired */
+    s->slice.data.refcounted.bytes[length] = 0;
+  }
+  s->hash = hash;
+  s->context = ctx;
+  s->bucket_next = ctx->strtab[hash % ctx->strtab_capacity];
+  ctx->strtab[hash % ctx->strtab_capacity] = s;
+
+  ctx->strtab_count++;
+
+  if (ctx->strtab_count > ctx->strtab_capacity * 2) {
+    grow_strtab(ctx);
+  }
+
+  unlock(ctx);
+
+  return (grpc_mdstr *)s;
+}
+
+static void gc_mdtab(grpc_mdctx *ctx) {
+  size_t i;
+  internal_metadata **prev_next;
+  internal_metadata *md, *next;
+
+  for (i = 0; i < ctx->mdtab_capacity; i++) {
+    prev_next = &ctx->mdtab[i];
+    for (md = ctx->mdtab[i]; md; md = next) {
+      next = md->bucket_next;
+      if (md->refs == 0) {
+        internal_string_unref(md->key);
+        internal_string_unref(md->value);
+        if (md->user_data) {
+          md->destroy_user_data(md->user_data);
+        }
+        gpr_free(md);
+        *prev_next = next;
+        ctx->mdtab_free--;
+        ctx->mdtab_count--;
+      } else {
+        prev_next = &md->bucket_next;
+      }
+    }
+  }
+
+  GPR_ASSERT(ctx->mdtab_free == 0);
+}
+
+static void grow_mdtab(grpc_mdctx *ctx) {
+  size_t capacity = ctx->mdtab_capacity * 2;
+  size_t i;
+  internal_metadata **mdtab =
+      gpr_malloc(sizeof(internal_metadata *) * capacity);
+  internal_metadata *md, *next;
+  gpr_uint32 hash;
+  memset(mdtab, 0, sizeof(internal_metadata *) * capacity);
+
+  for (i = 0; i < ctx->mdtab_capacity; i++) {
+    for (md = ctx->mdtab[i]; md; md = next) {
+      hash = KV_HASH(md->key, md->value);
+      next = md->bucket_next;
+      md->bucket_next = mdtab[hash % capacity];
+      mdtab[hash % capacity] = md;
+    }
+  }
+
+  gpr_free(ctx->mdtab);
+  ctx->mdtab = mdtab;
+  ctx->mdtab_capacity = capacity;
+}
+
+static void rehash_mdtab(grpc_mdctx *ctx) {
+  if (ctx->mdtab_free > ctx->mdtab_capacity / 4) {
+    gc_mdtab(ctx);
+  } else {
+    grow_mdtab(ctx);
+  }
+}
+
+grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
+                                               grpc_mdstr *mkey,
+                                               grpc_mdstr *mvalue) {
+  internal_string *key = (internal_string *)mkey;
+  internal_string *value = (internal_string *)mvalue;
+  gpr_uint32 hash = KV_HASH(mkey, mvalue);
+  internal_metadata *md;
+
+  GPR_ASSERT(key->context == ctx);
+  GPR_ASSERT(value->context == ctx);
+
+  lock(ctx);
+
+  /* search for an existing pair */
+  for (md = ctx->mdtab[hash % ctx->mdtab_capacity]; md; md = md->bucket_next) {
+    if (md->key == key && md->value == value) {
+      ref_md(md);
+      internal_string_unref(key);
+      internal_string_unref(value);
+      unlock(ctx);
+      return (grpc_mdelem *)md;
+    }
+  }
+
+  /* not found: create a new pair */
+  md = gpr_malloc(sizeof(internal_metadata));
+  md->refs = 1;
+  md->context = ctx;
+  md->key = key;
+  md->value = value;
+  md->user_data = NULL;
+  md->destroy_user_data = NULL;
+  md->bucket_next = ctx->mdtab[hash % ctx->mdtab_capacity];
+  ctx->mdtab[hash % ctx->mdtab_capacity] = md;
+  ctx->mdtab_count++;
+
+  if (ctx->mdtab_count > ctx->mdtab_capacity * 2) {
+    rehash_mdtab(ctx);
+  }
+
+  unlock(ctx);
+
+  return (grpc_mdelem *)md;
+}
+
+grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key,
+                                      const char *value) {
+  return grpc_mdelem_from_metadata_strings(ctx,
+                                           grpc_mdstr_from_string(ctx, key),
+                                           grpc_mdstr_from_string(ctx, value));
+}
+
+grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
+                                     gpr_slice value) {
+  return grpc_mdelem_from_metadata_strings(ctx, grpc_mdstr_from_slice(ctx, key),
+                                           grpc_mdstr_from_slice(ctx, value));
+}
+
+grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx,
+                                                const char *key,
+                                                const gpr_uint8 *value,
+                                                size_t value_length) {
+  return grpc_mdelem_from_metadata_strings(
+      ctx, grpc_mdstr_from_string(ctx, key),
+      grpc_mdstr_from_buffer(ctx, value, value_length));
+}
+
+grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd) {
+  internal_metadata *md = (internal_metadata *)gmd;
+  grpc_mdctx *ctx = md->context;
+  lock(ctx);
+  ref_md(md);
+  unlock(ctx);
+  return gmd;
+}
+
+void grpc_mdelem_unref(grpc_mdelem *gmd) {
+  internal_metadata *md = (internal_metadata *)gmd;
+  grpc_mdctx *ctx = md->context;
+  lock(ctx);
+  GPR_ASSERT(md->refs);
+  if (0 == --md->refs) {
+    ctx->mdtab_free++;
+  }
+  unlock(ctx);
+}
+
+const char *grpc_mdstr_as_c_string(grpc_mdstr *s) {
+  return (const char *)GPR_SLICE_START_PTR(s->slice);
+}
+
+grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs) {
+  internal_string *s = (internal_string *)gs;
+  grpc_mdctx *ctx = s->context;
+  lock(ctx);
+  internal_string_ref(s);
+  unlock(ctx);
+  return gs;
+}
+
+void grpc_mdstr_unref(grpc_mdstr *gs) {
+  internal_string *s = (internal_string *)gs;
+  grpc_mdctx *ctx = s->context;
+  lock(ctx);
+  internal_string_unref(s);
+  unlock(ctx);
+}
+
+size_t grpc_mdctx_get_mdtab_capacity_test_only(grpc_mdctx *ctx) {
+  return ctx->mdtab_capacity;
+}
+
+size_t grpc_mdctx_get_mdtab_count_test_only(grpc_mdctx *ctx) {
+  return ctx->mdtab_count;
+}
+
+size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *ctx) {
+  return ctx->mdtab_free;
+}
+
+void *grpc_mdelem_get_user_data(grpc_mdelem *md,
+                                void (*if_destroy_func)(void *)) {
+  internal_metadata *im = (internal_metadata *)md;
+  return im->destroy_user_data == if_destroy_func ? im->user_data : NULL;
+}
+
+void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
+                               void *user_data) {
+  internal_metadata *im = (internal_metadata *)md;
+  GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
+  if (im->destroy_user_data) {
+    im->destroy_user_data(im->user_data);
+  }
+  im->destroy_user_data = destroy_func;
+  im->user_data = user_data;
+}
diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h
new file mode 100644
index 0000000..4b87f70
--- /dev/null
+++ b/src/core/transport/metadata.h
@@ -0,0 +1,132 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_METADATA_H__
+#define __GRPC_INTERNAL_TRANSPORT_METADATA_H__
+
+#include <grpc/support/slice.h>
+
+/* This file provides a mechanism for tracking metadata through the grpc stack.
+   It's not intended for consumption outside of the library.
+
+   Metadata is tracked in the context of a grpc_mdctx. For the time being there
+   is one of these per-channel, avoiding cross channel interference with memory
+   use and lock contention.
+
+   The context tracks unique strings (grpc_mdstr) and pairs of strings
+   (grpc_mdelem). Any of these objects can be checked for equality by comparing
+   their pointers. These objects are reference counted.
+
+   grpc_mdelem can additionally store a (non-NULL) user data pointer. This
+   pointer is intended to be used to cache semantic meaning of a metadata
+   element. For example, an OAuth token may cache the credentials it represents
+   and the time at which it expires in the mdelem user data.
+
+   Combining this metadata cache and the hpack compression table allows us to
+   simply lookup complete preparsed objects quickly, incurring a few atomic
+   ops per metadata element on the fast path.
+
+   grpc_mdelem instances MAY live longer than their refcount implies, and are
+   garbage collected periodically, meaning cached data can easily outlive a
+   single request. */
+
+/* Forward declarations */
+typedef struct grpc_mdctx grpc_mdctx;
+typedef struct grpc_mdstr grpc_mdstr;
+typedef struct grpc_mdelem grpc_mdelem;
+
+/* if changing this, make identical changes in internal_string in metadata.c */
+struct grpc_mdstr {
+  const gpr_slice slice;
+  const gpr_uint32 hash;
+  /* there is a private part to this in metadata.c */
+};
+
+/* if changing this, make identical changes in internal_metadata in
+   metadata.c */
+struct grpc_mdelem {
+  grpc_mdstr *const key;
+  grpc_mdstr *const value;
+  /* there is a private part to this in metadata.c */
+};
+
+/* Create/orphan a metadata context */
+grpc_mdctx *grpc_mdctx_create();
+grpc_mdctx *grpc_mdctx_create_with_seed(gpr_uint32 seed);
+void grpc_mdctx_orphan(grpc_mdctx *mdctx);
+
+/* Test only accessors to internal state - only for testing this code - do not
+   rely on it outside of metadata_test.c */
+size_t grpc_mdctx_get_mdtab_capacity_test_only(grpc_mdctx *mdctx);
+size_t grpc_mdctx_get_mdtab_count_test_only(grpc_mdctx *mdctx);
+size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *mdctx);
+
+/* Constructors for grpc_mdstr instances; take a variety of data types that
+   clients may have handy */
+grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str);
+grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice);
+grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *str,
+                                   size_t length);
+
+/* Constructors for grpc_mdelem instances; take a variety of data types that
+   clients may have handy */
+grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx, grpc_mdstr *key,
+                                               grpc_mdstr *value);
+grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key,
+                                      const char *value);
+grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
+                                     gpr_slice value);
+grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx,
+                                                const char *key,
+                                                const gpr_uint8 *value,
+                                                size_t value_length);
+
+/* Mutator and accessor for grpc_mdelem user data. The destructor function
+   is used as a type tag and is checked during user_data fetch. */
+void *grpc_mdelem_get_user_data(grpc_mdelem *md,
+                                void (*if_destroy_func)(void *));
+void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
+                               void *user_data);
+
+/* Reference counting */
+grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s);
+void grpc_mdstr_unref(grpc_mdstr *s);
+
+grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md);
+void grpc_mdelem_unref(grpc_mdelem *md);
+
+/* Recover a char* from a grpc_mdstr. The returned string is null terminated.
+   Does not promise that the returned string has no embedded nulls however. */
+const char *grpc_mdstr_as_c_string(grpc_mdstr *s);
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_METADATA_H__ */
diff --git a/src/core/transport/stream_op.c b/src/core/transport/stream_op.c
new file mode 100644
index 0000000..c77c8cd
--- /dev/null
+++ b/src/core/transport/stream_op.c
@@ -0,0 +1,165 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/stream_op.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include <string.h>
+
+/* Initial number of operations to allocate */
+#define INITIAL_SLOTS 8
+/* Exponential growth function: Given x, return a larger x.
+   Currently we grow by 1.5 times upon reallocation.
+   Assumes INITIAL_SLOTS > 1 */
+#define GROW(x) (3 * (x) / 2)
+
+void grpc_sopb_init(grpc_stream_op_buffer *sopb) {
+  sopb->ops = gpr_malloc(sizeof(grpc_stream_op) * INITIAL_SLOTS);
+  GPR_ASSERT(sopb->ops);
+  sopb->nops = 0;
+  sopb->capacity = INITIAL_SLOTS;
+}
+
+void grpc_sopb_destroy(grpc_stream_op_buffer *sopb) {
+  grpc_stream_ops_unref_owned_objects(sopb->ops, sopb->nops);
+  gpr_free(sopb->ops);
+}
+
+void grpc_sopb_reset(grpc_stream_op_buffer *sopb) {
+  grpc_stream_ops_unref_owned_objects(sopb->ops, sopb->nops);
+  sopb->nops = 0;
+}
+
+void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops) {
+  int i;
+  for (i = 0; i < nops; i++) {
+    switch (ops[i].type) {
+      case GRPC_OP_SLICE:
+        gpr_slice_unref(ops[i].data.slice);
+        break;
+      case GRPC_OP_METADATA:
+        grpc_mdelem_unref(ops[i].data.metadata);
+        break;
+      case GRPC_OP_FLOW_CTL_CB:
+        ops[i].data.flow_ctl_cb.cb(ops[i].data.flow_ctl_cb.arg, GRPC_OP_ERROR);
+        break;
+      case GRPC_NO_OP:
+      case GRPC_OP_DEADLINE:
+      case GRPC_OP_METADATA_BOUNDARY:
+      case GRPC_OP_BEGIN_MESSAGE:
+        break;
+    }
+  }
+}
+
+static void expand(grpc_stream_op_buffer *sopb) {
+  sopb->capacity = GROW(sopb->capacity);
+  sopb->ops = gpr_realloc(sopb->ops, sizeof(grpc_stream_op) * sopb->capacity);
+  GPR_ASSERT(sopb->ops);
+}
+
+static grpc_stream_op *add(grpc_stream_op_buffer *sopb) {
+  grpc_stream_op *out;
+
+  if (sopb->nops == sopb->capacity) {
+    expand(sopb);
+  }
+  out = sopb->ops + sopb->nops;
+  sopb->nops++;
+  return out;
+}
+
+void grpc_sopb_add_no_op(grpc_stream_op_buffer *sopb) {
+  add(sopb)->type = GRPC_NO_OP;
+}
+
+void grpc_sopb_add_begin_message(grpc_stream_op_buffer *sopb, gpr_uint32 length,
+                                 gpr_uint32 flags) {
+  grpc_stream_op *op = add(sopb);
+  op->type = GRPC_OP_BEGIN_MESSAGE;
+  op->data.begin_message.length = length;
+  op->data.begin_message.flags = flags;
+}
+
+void grpc_sopb_add_metadata_boundary(grpc_stream_op_buffer *sopb) {
+  grpc_stream_op *op = add(sopb);
+  op->type = GRPC_OP_METADATA_BOUNDARY;
+}
+
+void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb, grpc_mdelem *md) {
+  grpc_stream_op *op = add(sopb);
+  op->type = GRPC_OP_METADATA;
+  op->data.metadata = md;
+}
+
+void grpc_sopb_add_deadline(grpc_stream_op_buffer *sopb,
+                            gpr_timespec deadline) {
+  grpc_stream_op *op = add(sopb);
+  op->type = GRPC_OP_DEADLINE;
+  op->data.deadline = deadline;
+}
+
+void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice) {
+  grpc_stream_op *op = add(sopb);
+  op->type = GRPC_OP_SLICE;
+  op->data.slice = slice;
+}
+
+void grpc_sopb_add_flow_ctl_cb(grpc_stream_op_buffer *sopb,
+                               void (*cb)(void *arg, grpc_op_error error),
+                               void *arg) {
+  grpc_stream_op *op = add(sopb);
+  op->type = GRPC_OP_FLOW_CTL_CB;
+  op->data.flow_ctl_cb.cb = cb;
+  op->data.flow_ctl_cb.arg = arg;
+}
+
+void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops,
+                      size_t nops) {
+  size_t orig_nops = sopb->nops;
+  size_t new_nops = orig_nops + nops;
+
+  if (new_nops > sopb->capacity) {
+    size_t new_capacity = GROW(sopb->capacity);
+    if (new_capacity < new_nops) {
+      new_capacity = new_nops;
+    }
+    sopb->ops = gpr_realloc(sopb->ops, sizeof(grpc_stream_op) * new_capacity);
+    sopb->capacity = new_capacity;
+  }
+
+  memcpy(sopb->ops + orig_nops, ops, sizeof(grpc_stream_op) * nops);
+  sopb->nops = new_nops;
+}
diff --git a/src/core/transport/stream_op.h b/src/core/transport/stream_op.h
new file mode 100644
index 0000000..be60bc2
--- /dev/null
+++ b/src/core/transport/stream_op.h
@@ -0,0 +1,128 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_STREAM_OP_H__
+#define __GRPC_INTERNAL_TRANSPORT_STREAM_OP_H__
+
+#include <grpc/grpc.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/time.h>
+#include "src/core/transport/metadata.h"
+
+/* Operations that can be performed on a stream.
+   Used by grpc_stream_op. */
+typedef enum grpc_stream_op_code {
+  /* Do nothing code. Useful if rewriting a batch to exclude some operations.
+     Must be ignored by receivers */
+  GRPC_NO_OP,
+  GRPC_OP_METADATA,
+  GRPC_OP_DEADLINE,
+  GRPC_OP_METADATA_BOUNDARY,
+  /* Begin a message/metadata element/status - as defined by
+     grpc_message_type. */
+  GRPC_OP_BEGIN_MESSAGE,
+  /* Add a slice of data to the current message/metadata element/status.
+     Must not overflow the forward declared length. */
+  GRPC_OP_SLICE,
+  /* Call some function once this operation has passed flow control. */
+  GRPC_OP_FLOW_CTL_CB
+} grpc_stream_op_code;
+
+/* Arguments for GRPC_OP_BEGIN */
+typedef struct grpc_begin_message {
+  /* How many bytes of data will this message contain */
+  gpr_uint32 length;
+  /* Write flags for the message: see grpc.h GRPC_WRITE_xxx */
+  gpr_uint32 flags;
+} grpc_begin_message;
+
+/* Arguments for GRPC_OP_FLOW_CTL_CB */
+typedef struct grpc_flow_ctl_cb {
+  void (*cb)(void *arg, grpc_op_error error);
+  void *arg;
+} grpc_flow_ctl_cb;
+
+/* Represents a single operation performed on a stream/transport */
+typedef struct grpc_stream_op {
+  /* the operation to be applied */
+  enum grpc_stream_op_code type;
+  /* the arguments to this operation. union fields are named according to the
+     associated op-code */
+  union {
+    grpc_begin_message begin_message;
+    grpc_mdelem *metadata;
+    gpr_timespec deadline;
+    gpr_slice slice;
+    grpc_flow_ctl_cb flow_ctl_cb;
+  } data;
+} grpc_stream_op;
+
+/* A stream op buffer is a wrapper around stream operations that is dynamically
+   extendable.
+   TODO(ctiller): inline a few elements into the struct, to avoid common case
+                  per-call allocations. */
+typedef struct grpc_stream_op_buffer {
+  grpc_stream_op *ops;
+  size_t nops;
+  size_t capacity;
+} grpc_stream_op_buffer;
+
+/* Initialize a stream op buffer */
+void grpc_sopb_init(grpc_stream_op_buffer *sopb);
+/* Destroy a stream op buffer */
+void grpc_sopb_destroy(grpc_stream_op_buffer *sopb);
+/* Reset a sopb to no elements */
+void grpc_sopb_reset(grpc_stream_op_buffer *sopb);
+
+void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops);
+
+/* Append a GRPC_NO_OP to a buffer */
+void grpc_sopb_add_no_op(grpc_stream_op_buffer *sopb);
+/* Append a GRPC_OP_BEGIN to a buffer */
+void grpc_sopb_add_begin_message(grpc_stream_op_buffer *sopb, gpr_uint32 length,
+                                 gpr_uint32 flags);
+void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb, grpc_mdelem *metadata);
+void grpc_sopb_add_deadline(grpc_stream_op_buffer *sopb, gpr_timespec deadline);
+void grpc_sopb_add_metadata_boundary(grpc_stream_op_buffer *sopb);
+/* Append a GRPC_SLICE to a buffer - does not ref/unref the slice */
+void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice);
+/* Append a GRPC_OP_FLOW_CTL_CB to a buffer */
+void grpc_sopb_add_flow_ctl_cb(grpc_stream_op_buffer *sopb,
+                               void (*cb)(void *arg, grpc_op_error error),
+                               void *arg);
+/* Append a buffer to a buffer - does not ref/unref any internal objects */
+void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops,
+                      size_t nops);
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_STREAM_OP_H__ */
diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c
new file mode 100644
index 0000000..d3291bb
--- /dev/null
+++ b/src/core/transport/transport.c
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/transport.h"
+#include "src/core/transport/transport_impl.h"
+
+size_t grpc_transport_stream_size(grpc_transport *transport) {
+  return transport->vtable->sizeof_stream;
+}
+
+void grpc_transport_close(grpc_transport *transport) {
+  transport->vtable->close(transport);
+}
+
+void grpc_transport_destroy(grpc_transport *transport) {
+  transport->vtable->destroy(transport);
+}
+
+int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream,
+                               const void *server_data) {
+  return transport->vtable->init_stream(transport, stream, server_data);
+}
+
+void grpc_transport_send_batch(grpc_transport *transport, grpc_stream *stream,
+                               grpc_stream_op *ops, size_t nops, int is_last) {
+  transport->vtable->send_batch(transport, stream, ops, nops, is_last);
+}
+
+void grpc_transport_set_allow_window_updates(grpc_transport *transport,
+                                             grpc_stream *stream, int allow) {
+  transport->vtable->set_allow_window_updates(transport, stream, allow);
+}
+
+void grpc_transport_destroy_stream(grpc_transport *transport,
+                                   grpc_stream *stream) {
+  transport->vtable->destroy_stream(transport, stream);
+}
+
+void grpc_transport_abort_stream(grpc_transport *transport, grpc_stream *stream,
+                                 grpc_status_code status) {
+  transport->vtable->abort_stream(transport, stream, status);
+}
+
+void grpc_transport_ping(grpc_transport *transport, void (*cb)(void *user_data),
+                         void *user_data) {
+  transport->vtable->ping(transport, cb, user_data);
+}
+
+void grpc_transport_setup_cancel(grpc_transport_setup *setup) {
+  setup->vtable->cancel(setup);
+}
+
+void grpc_transport_setup_initiate(grpc_transport_setup *setup) {
+  setup->vtable->initiate(setup);
+}
diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h
new file mode 100644
index 0000000..1872947
--- /dev/null
+++ b/src/core/transport/transport.h
@@ -0,0 +1,245 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_TRANSPORT_H__
+#define __GRPC_INTERNAL_TRANSPORT_TRANSPORT_H__
+
+#include <stddef.h>
+
+#include "src/core/transport/stream_op.h"
+
+/* forward declarations */
+typedef struct grpc_transport grpc_transport;
+typedef struct grpc_transport_callbacks grpc_transport_callbacks;
+
+/* grpc_stream doesn't actually exist. It's used as a typesafe
+   opaque pointer for whatever data the transport wants to track
+   for a stream. */
+typedef struct grpc_stream grpc_stream;
+
+/* Represents the send/recv closed state of a stream. */
+typedef enum grpc_stream_state {
+  /* the stream is open for sends and receives */
+  GRPC_STREAM_OPEN,
+  /* the stream is closed for sends, but may still receive data */
+  GRPC_STREAM_SEND_CLOSED,
+  /* the stream is closed for receives, but may still send data */
+  GRPC_STREAM_RECV_CLOSED,
+  /* the stream is closed for both sends and receives */
+  GRPC_STREAM_CLOSED
+} grpc_stream_state;
+
+/* Callbacks made from the transport to the upper layers of grpc. */
+struct grpc_transport_callbacks {
+  /* Allocate a buffer to receive data into.
+     It's safe to call grpc_slice_new() to do this, but performance minded
+     proxies may want to carefully place data into optimal locations for
+     transports.
+     This function must return a valid, non-empty slice.
+
+     Arguments:
+       user_data - the transport user data set at transport creation time
+       transport - the grpc_transport instance making this call
+       stream    - the grpc_stream instance the buffer will be used for, or
+                   NULL if this is not known
+       size_hint - how big of a buffer would the transport optimally like?
+                   the actual returned buffer can be smaller or larger than
+                   size_hint as the implementation finds convenient */
+  struct gpr_slice (*alloc_recv_buffer)(void *user_data,
+                                        grpc_transport *transport,
+                                        grpc_stream *stream, size_t size_hint);
+
+  /* Initialize a new stream on behalf of the transport.
+     Must result in a call to
+     grpc_transport_init_stream(transport, ..., request) in the same call
+     stack.
+     Must not result in any other calls to the transport.
+
+     Arguments:
+       user_data     - the transport user data set at transport creation time
+       transport     - the grpc_transport instance making this call
+       request       - request parameters for this stream (owned by the caller)
+       server_data   - opaque transport dependent argument that should be passed
+                       to grpc_transport_init_stream
+     */
+  void (*accept_stream)(void *user_data, grpc_transport *transport,
+                        const void *server_data);
+
+  /* Process a set of stream ops that have been received by the transport.
+     Called by network threads, so must be careful not to block on network
+     activity.
+
+     If final_state == GRPC_STREAM_CLOSED, the upper layers should arrange to
+     call grpc_transport_destroy_stream.
+
+     Ownership of any objects contained in ops is transferred to the callee.
+
+     Arguments:
+       user_data   - the transport user data set at transport creation time
+       transport   - the grpc_transport instance making this call
+       stream      - the stream this data was received for
+       ops         - stream operations that are part of this batch
+       ops_count   - the number of stream operations in this batch
+       final_state - the state of the stream as of the final operation in this
+                     batch */
+  void (*recv_batch)(void *user_data, grpc_transport *transport,
+                     grpc_stream *stream, grpc_stream_op *ops, size_t ops_count,
+                     grpc_stream_state final_state);
+
+  /* The transport has been closed */
+  void (*closed)(void *user_data, grpc_transport *transport);
+};
+
+/* Returns the amount of memory required to store a grpc_stream for this
+   transport */
+size_t grpc_transport_stream_size(grpc_transport *transport);
+
+/* Initialize transport data for a stream.
+
+   Returns 0 on success, any other (transport-defined) value for failure.
+
+   Arguments:
+     transport   - the transport on which to create this stream
+     stream      - a pointer to uninitialized memory to initialize
+     server_data - either NULL for a client initiated stream, or a pointer
+                   supplied from the accept_stream callback function */
+int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream,
+                               const void *server_data);
+
+/* Destroy transport data for a stream.
+
+   Requires: a recv_batch with final_state == GRPC_STREAM_CLOSED has been
+   received by the up-layer. Must not be called in the same call stack as
+   recv_frame.
+
+   Arguments:
+     transport - the transport on which to create this stream
+     stream    - the grpc_stream to destroy (memory is still owned by the
+                 caller, but any child memory must be cleaned up) */
+void grpc_transport_destroy_stream(grpc_transport *transport,
+                                   grpc_stream *stream);
+
+/* Enable/disable incoming data for a stream.
+
+   This effectively disables new window becoming available for a given stream,
+   but does not prevent existing window from being consumed by a sender: the
+   caller must still be prepared to receive some additional data after this
+   call.
+
+   Arguments:
+     transport - the transport on which to create this stream
+     stream    - the grpc_stream to destroy (memory is still owned by the
+                 caller, but any child memory must be cleaned up)
+     allow     - is it allowed that new window be opened up? */
+void grpc_transport_set_allow_window_updates(grpc_transport *transport,
+                                             grpc_stream *stream, int allow);
+
+/* Send a batch of operations on a transport
+
+   Takes ownership of any objects contained in ops.
+
+   Arguments:
+     transport - the transport on which to initiate the stream
+     stream    - the stream on which to send the operations. This must be
+                 non-NULL and previously initialized by the same transport.
+     ops       - an array of operations to apply to the stream - can be NULL
+                 if ops_count == 0.
+     ops_count - the number of elements in ops
+     is_last   - is this the last batch of operations to be sent out */
+void grpc_transport_send_batch(grpc_transport *transport, grpc_stream *stream,
+                               grpc_stream_op *ops, size_t ops_count,
+                               int is_last);
+
+/* Send a ping on a transport
+
+   Calls cb with user data when a response is received.
+   cb *MAY* be called with arbitrary transport level locks held. It is not safe
+   to call into the transport during cb. */
+void grpc_transport_ping(grpc_transport *transport, void (*cb)(void *user_data),
+                         void *user_data);
+
+/* Abort a stream
+
+   Terminate reading and writing for a stream. A final recv_batch with no
+   operations and final_state == GRPC_STREAM_CLOSED will be received locally,
+   and no more data will be presented to the up-layer.
+
+   TODO(ctiller): consider adding a HTTP/2 reason to this function. */
+void grpc_transport_abort_stream(grpc_transport *transport, grpc_stream *stream,
+                                 grpc_status_code status);
+
+/* Close a transport. Aborts all open streams. */
+void grpc_transport_close(struct grpc_transport *transport);
+
+/* Destroy the transport */
+void grpc_transport_destroy(struct grpc_transport *transport);
+
+/* Return type for grpc_transport_setup_callback */
+typedef struct grpc_transport_setup_result {
+  void *user_data;
+  const grpc_transport_callbacks *callbacks;
+} grpc_transport_setup_result;
+
+/* Given a transport, return callbacks for that transport. Used to finalize
+   setup as a transport is being created */
+typedef grpc_transport_setup_result (*grpc_transport_setup_callback)(
+    void *setup_arg, grpc_transport *transport, grpc_mdctx *mdctx);
+
+typedef struct grpc_transport_setup grpc_transport_setup;
+typedef struct grpc_transport_setup_vtable grpc_transport_setup_vtable;
+
+struct grpc_transport_setup_vtable {
+  void (*initiate)(grpc_transport_setup *setup);
+  void (*cancel)(grpc_transport_setup *setup);
+};
+
+/* Transport setup is an asynchronous utility interface for client channels to
+   establish connections. It's transport agnostic. */
+struct grpc_transport_setup {
+  const grpc_transport_setup_vtable *vtable;
+};
+
+/* Initiate transport setup: e.g. for TCP+DNS trigger a resolve of the name
+   given at transport construction time, create the tcp connection, perform
+   handshakes, and call some grpc_transport_setup_result function provided at
+   setup construction time.
+   This *may* be implemented as a no-op if the setup process monitors something
+   continuously. */
+void grpc_transport_setup_initiate(grpc_transport_setup *setup);
+/* Cancel transport setup. After this returns, no new transports should be
+   created, and all pending transport setup callbacks should be completed.
+   After this call completes, setup should be considered invalid (this can be
+   used as a destruction call by setup). */
+void grpc_transport_setup_cancel(grpc_transport_setup *setup);
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_TRANSPORT_H__ */
diff --git a/src/core/transport/transport_impl.h b/src/core/transport/transport_impl.h
new file mode 100644
index 0000000..6acdbf2
--- /dev/null
+++ b/src/core/transport/transport_impl.h
@@ -0,0 +1,80 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_INTERNAL_TRANSPORT_TRANSPORT_IMPL_H__
+#define __GRPC_INTERNAL_TRANSPORT_TRANSPORT_IMPL_H__
+
+#include "src/core/transport/transport.h"
+
+typedef struct grpc_transport_vtable {
+  /* Memory required for a single stream element - this is allocated by upper
+     layers and initialized by the transport */
+  size_t sizeof_stream; /* = sizeof(transport stream) */
+
+  /* implementation of grpc_transport_init_stream */
+  int (*init_stream)(grpc_transport *self, grpc_stream *stream,
+                     const void *server_data);
+
+  /* implementation of grpc_transport_send_batch */
+  void (*send_batch)(grpc_transport *self, grpc_stream *stream,
+                     grpc_stream_op *ops, size_t ops_count, int is_last);
+
+  /* implementation of grpc_transport_set_allow_window_updates */
+  void (*set_allow_window_updates)(grpc_transport *self, grpc_stream *stream,
+                                   int allow);
+
+  /* implementation of grpc_transport_destroy_stream */
+  void (*destroy_stream)(grpc_transport *self, grpc_stream *stream);
+
+  /* implementation of grpc_transport_abort_stream */
+  void (*abort_stream)(grpc_transport *self, grpc_stream *stream,
+                       grpc_status_code status);
+
+  /* implementation of grpc_transport_close */
+  void (*close)(grpc_transport *self);
+
+  /* implementation of grpc_transport_ping */
+  void (*ping)(grpc_transport *self, void (*cb)(void *user_data),
+               void *user_data);
+
+  /* implementation of grpc_transport_destroy */
+  void (*destroy)(grpc_transport *self);
+} grpc_transport_vtable;
+
+/* an instance of a grpc transport */
+struct grpc_transport {
+  /* pointer to a vtable defining operations on this transport */
+  const grpc_transport_vtable *vtable;
+};
+
+#endif  /* __GRPC_INTERNAL_TRANSPORT_TRANSPORT_IMPL_H__ */
diff --git a/src/core/tsi/fake_transport_security.c b/src/core/tsi/fake_transport_security.c
new file mode 100644
index 0000000..7807e71
--- /dev/null
+++ b/src/core/tsi/fake_transport_security.c
@@ -0,0 +1,515 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/tsi/fake_transport_security.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include "src/core/tsi/transport_security.h"
+
+/* --- Constants. ---*/
+#define TSI_FAKE_FRAME_HEADER_SIZE 4
+#define TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE 64
+#define TSI_FAKE_DEFAULT_FRAME_SIZE 16384
+
+/* --- Structure definitions. ---*/
+
+/* a frame is encoded like this:
+   | size |     data    |
+   where the size field value is the size of the size field plus the size of
+   the data encoded in little endian on 4 bytes.  */
+typedef struct {
+  unsigned char* data;
+  uint32_t size;
+  uint32_t allocated_size;
+  uint32_t offset;
+  int needs_draining;
+} tsi_fake_frame;
+
+typedef enum {
+  TSI_FAKE_CLIENT_INIT = 0,
+  TSI_FAKE_SERVER_INIT = 1,
+  TSI_FAKE_CLIENT_FINISHED = 2,
+  TSI_FAKE_SERVER_FINISHED = 3,
+  TSI_FAKE_HANDSHAKE_MESSAGE_MAX = 4
+} tsi_fake_handshake_message;
+
+typedef struct {
+  tsi_handshaker base;
+  int is_client;
+  tsi_fake_handshake_message next_message_to_send;
+  int needs_incoming_message;
+  tsi_fake_frame incoming;
+  tsi_fake_frame outgoing;
+  tsi_result result;
+} tsi_fake_handshaker;
+
+typedef struct {
+  tsi_frame_protector base;
+  tsi_fake_frame protect_frame;
+  tsi_fake_frame unprotect_frame;
+  uint32_t max_frame_size;
+} tsi_fake_frame_protector;
+
+
+/* --- Utils. ---*/
+
+static const char* tsi_fake_handshake_message_strings[] = {
+    "CLIENT_INIT", "SERVER_INIT", "CLIENT_FINISHED", "SERVER_FINISHED"};
+
+static const char* tsi_fake_handshake_message_to_string(int msg) {
+  if (msg < 0 || msg >= TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
+    gpr_log(GPR_ERROR, "Invalid message %d", msg);
+    return "UNKNOWN";
+  }
+  return tsi_fake_handshake_message_strings[msg];
+}
+
+static tsi_result tsi_fake_handshake_message_from_string(
+    const char* msg_string, tsi_fake_handshake_message* msg) {
+  int i;
+  for (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]))) {
+      *msg = i;
+      return TSI_OK;
+    }
+  }
+  gpr_log(GPR_ERROR, "Invalid handshake message.");
+  return TSI_DATA_CORRUPTED;
+}
+
+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));
+}
+
+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;
+}
+
+static void tsi_fake_frame_reset(tsi_fake_frame* frame, int needs_draining) {
+  frame->offset = 0;
+  frame->needs_draining = needs_draining;
+  if (!needs_draining) frame->size = 0;
+}
+
+/* Returns 1 if successful, 0 otherwise. */
+static int tsi_fake_frame_ensure_size(tsi_fake_frame* frame) {
+  if (frame->data == NULL) {
+    frame->allocated_size = frame->size;
+    frame->data = malloc(frame->allocated_size);
+    if (frame->data == NULL) return 0;
+  } else if (frame->size > frame->allocated_size) {
+    unsigned char* new_data = realloc(frame->data, frame->size);
+    if (new_data == NULL) {
+      free(frame->data);
+      frame->data = NULL;
+      return 0;
+    }
+    frame->data = new_data;
+    frame->allocated_size = frame->size;
+  }
+  return 1;
+}
+
+/* This method should not be called if frame->needs_framing is not 0.  */
+static tsi_result fill_frame_from_bytes(const unsigned char* incoming_bytes,
+                                        uint32_t* incoming_bytes_size,
+                                        tsi_fake_frame* frame) {
+  uint32_t available_size = *incoming_bytes_size;
+  uint32_t to_read_size = 0;
+  const unsigned char* bytes_cursor = incoming_bytes;
+
+  if (frame->needs_draining) return TSI_INTERNAL_ERROR;
+  if (frame->data == NULL) {
+    frame->allocated_size = TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE;
+    frame->data = malloc(frame->allocated_size);
+    if (frame->data == NULL) return TSI_OUT_OF_RESOURCES;
+  }
+
+  if (frame->offset < TSI_FAKE_FRAME_HEADER_SIZE) {
+    to_read_size = TSI_FAKE_FRAME_HEADER_SIZE - frame->offset;
+    if (to_read_size > available_size) {
+      /* Just fill what we can and exit. */
+      memcpy(frame->data + frame->offset, bytes_cursor, available_size);
+      bytes_cursor += available_size;
+      frame->offset += available_size;
+      *incoming_bytes_size = bytes_cursor - incoming_bytes;
+      return TSI_INCOMPLETE_DATA;
+    }
+    memcpy(frame->data + frame->offset, bytes_cursor, to_read_size);
+    bytes_cursor += to_read_size;
+    frame->offset += to_read_size;
+    available_size -= to_read_size;
+    frame->size = load32_little_endian(frame->data);
+    if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES;
+  }
+
+  to_read_size = frame->size - frame->offset;
+  if (to_read_size > available_size) {
+    memcpy(frame->data + frame->offset, bytes_cursor, available_size);
+    frame->offset += available_size;
+    bytes_cursor += available_size;
+    *incoming_bytes_size = 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 = bytes_cursor - incoming_bytes;
+  tsi_fake_frame_reset(frame, 1 /* needs_draining */);
+  return TSI_OK;
+}
+
+/* This method should not be called if frame->needs_framing is 0.  */
+static tsi_result drain_frame_to_bytes(unsigned char* outgoing_bytes,
+                                       uint32_t* outgoing_bytes_size,
+                                       tsi_fake_frame* frame) {
+  uint32_t to_write_size = frame->size - frame->offset;
+  if (!frame->needs_draining) return TSI_INTERNAL_ERROR;
+  if (*outgoing_bytes_size < to_write_size) {
+    memcpy(outgoing_bytes, frame->data + frame->offset, *outgoing_bytes_size);
+    frame->offset += *outgoing_bytes_size;
+    return TSI_INCOMPLETE_DATA;
+  }
+  memcpy(outgoing_bytes, frame->data + frame->offset, to_write_size);
+  *outgoing_bytes_size = to_write_size;
+  tsi_fake_frame_reset(frame, 0 /* needs_draining */);
+  return TSI_OK;
+}
+
+static tsi_result bytes_to_frame(unsigned char* bytes, uint32_t bytes_size,
+                                 tsi_fake_frame* frame) {
+  frame->offset = 0;
+  frame->size = bytes_size + TSI_FAKE_FRAME_HEADER_SIZE;
+  if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES;
+  store32_little_endian(frame->size, frame->data);
+  memcpy(frame->data + TSI_FAKE_FRAME_HEADER_SIZE, bytes, bytes_size);
+  tsi_fake_frame_reset(frame, 1 /* needs draining */);
+  return TSI_OK;
+}
+
+static void tsi_fake_frame_destruct(tsi_fake_frame* frame) {
+  if (frame->data != NULL) free(frame->data);
+}
+
+/* --- tsi_frame_protector methods implementation. ---*/
+
+static tsi_result fake_protector_protect(
+    tsi_frame_protector* self, const unsigned char* unprotected_bytes,
+    uint32_t* unprotected_bytes_size, unsigned char* protected_output_frames,
+    uint32_t* protected_output_frames_size) {
+  tsi_result result = TSI_OK;
+  tsi_fake_frame_protector* impl = (tsi_fake_frame_protector*)self;
+  unsigned char frame_header[TSI_FAKE_FRAME_HEADER_SIZE];
+  tsi_fake_frame* frame = &impl->protect_frame;
+  uint32_t saved_output_size = *protected_output_frames_size;
+  uint32_t drained_size = 0;
+  uint32_t* num_bytes_written = protected_output_frames_size;
+  *num_bytes_written = 0;
+
+  /* Try to drain first. */
+  if (frame->needs_draining) {
+    drained_size = saved_output_size - *num_bytes_written;
+    result = drain_frame_to_bytes(protected_output_frames,
+                                  &drained_size, frame);
+    *num_bytes_written += drained_size;
+    protected_output_frames += drained_size;
+    if (result != TSI_OK) {
+      if (result == TSI_INCOMPLETE_DATA) {
+        *unprotected_bytes_size = 0;
+        result = TSI_OK;
+      }
+      return result;
+    }
+  }
+
+  /* Now process the unprotected_bytes. */
+  if (frame->needs_draining) return TSI_INTERNAL_ERROR;
+  if (frame->size == 0) {
+    /* New frame, create a header. */
+    uint32_t written_in_frame_size = 0;
+    store32_little_endian(impl->max_frame_size, frame_header);
+    written_in_frame_size = TSI_FAKE_FRAME_HEADER_SIZE;
+    result = fill_frame_from_bytes(frame_header, &written_in_frame_size, frame);
+    if (result != TSI_INCOMPLETE_DATA) {
+      gpr_log(GPR_ERROR, "fill_frame_from_bytes returned %s",
+              tsi_result_to_string(result));
+      return result;
+    }
+  }
+  result = fill_frame_from_bytes(unprotected_bytes, unprotected_bytes_size,
+                                 frame);
+  if (result != TSI_OK) {
+    if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
+    return result;
+  }
+
+  /* Try to drain again. */
+  if (!frame->needs_draining) return TSI_INTERNAL_ERROR;
+  if (frame->offset != 0) return TSI_INTERNAL_ERROR;
+  drained_size = saved_output_size - *num_bytes_written;
+  result = drain_frame_to_bytes(protected_output_frames, &drained_size, frame);
+  *num_bytes_written += drained_size;
+  if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
+  return result;
+}
+
+static tsi_result fake_protector_protect_flush(
+    tsi_frame_protector* self, unsigned char* protected_output_frames,
+    uint32_t* protected_output_frames_size, uint32_t* still_pending_size) {
+  tsi_result result = TSI_OK;
+  tsi_fake_frame_protector* impl = (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(frame->size, frame->data);  /* Overwrite header. */
+  }
+  result = drain_frame_to_bytes(protected_output_frames,
+                                protected_output_frames_size, frame);
+  if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
+  *still_pending_size = frame->size - frame->offset;
+  return result;
+}
+
+static tsi_result fake_protector_unprotect(
+    tsi_frame_protector* self, const unsigned char* protected_frames_bytes,
+    uint32_t* protected_frames_bytes_size, unsigned char* unprotected_bytes,
+    uint32_t* unprotected_bytes_size) {
+  tsi_result result = TSI_OK;
+  tsi_fake_frame_protector* impl = (tsi_fake_frame_protector*)self;
+  tsi_fake_frame* frame = &impl->unprotect_frame;
+  uint32_t saved_output_size = *unprotected_bytes_size;
+  uint32_t drained_size = 0;
+  uint32_t* num_bytes_written = unprotected_bytes_size;
+  *num_bytes_written = 0;
+
+  /* Try to drain first. */
+  if (frame->needs_draining) {
+    /* Go past the header if needed. */
+    if (frame->offset == 0) frame->offset = TSI_FAKE_FRAME_HEADER_SIZE;
+    drained_size = saved_output_size - *num_bytes_written;
+    result = drain_frame_to_bytes(unprotected_bytes, &drained_size,
+                                  frame);
+    unprotected_bytes += drained_size;
+    *num_bytes_written += drained_size;
+    if (result != TSI_OK) {
+      if (result == TSI_INCOMPLETE_DATA) {
+        *protected_frames_bytes_size = 0;
+        result = TSI_OK;
+      }
+      return result;
+    }
+  }
+
+  /* Now process the protected_bytes. */
+  if (frame->needs_draining) return TSI_INTERNAL_ERROR;
+  result = fill_frame_from_bytes(protected_frames_bytes,
+                                 protected_frames_bytes_size, frame);
+  if (result != TSI_OK) {
+    if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
+    return result;
+  }
+
+  /* Try to drain again. */
+  if (!frame->needs_draining) return TSI_INTERNAL_ERROR;
+  if (frame->offset != 0) return TSI_INTERNAL_ERROR;
+  frame->offset = TSI_FAKE_FRAME_HEADER_SIZE;  /* Go past the header. */
+  drained_size = saved_output_size - *num_bytes_written;
+  result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame);
+  *num_bytes_written += drained_size;
+  if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
+  return result;
+}
+
+static void fake_protector_destroy(tsi_frame_protector* self) {
+  tsi_fake_frame_protector* impl = (tsi_fake_frame_protector*)self;
+  tsi_fake_frame_destruct(&impl->protect_frame);
+  tsi_fake_frame_destruct(&impl->unprotect_frame);
+  free(self);
+}
+
+static const tsi_frame_protector_vtable frame_protector_vtable = {
+    fake_protector_protect, fake_protector_protect_flush,
+    fake_protector_unprotect, fake_protector_destroy,
+};
+
+/* --- tsi_handshaker methods implementation. ---*/
+
+static tsi_result fake_handshaker_get_bytes_to_send_to_peer(
+    tsi_handshaker* self, unsigned char* bytes, uint32_t* bytes_size) {
+  tsi_fake_handshaker* impl = (tsi_fake_handshaker*)self;
+  tsi_result result = TSI_OK;
+  if (impl->needs_incoming_message || impl->result == TSI_OK) {
+    *bytes_size = 0;
+    return TSI_OK;
+  }
+  if (!impl->outgoing.needs_draining) {
+    int next_message_to_send = impl->next_message_to_send + 2;
+    const char* msg_string =
+        tsi_fake_handshake_message_to_string(impl->next_message_to_send);
+    result = bytes_to_frame((unsigned char*)msg_string, strlen(msg_string),
+                            &impl->outgoing);
+    if (result != TSI_OK) return result;
+    if (next_message_to_send > TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
+      next_message_to_send = TSI_FAKE_HANDSHAKE_MESSAGE_MAX;
+    }
+    gpr_log(GPR_INFO, "%s prepared %s.", impl->is_client ? "Client" : "Server",
+            tsi_fake_handshake_message_to_string(impl->next_message_to_send));
+    impl->next_message_to_send = next_message_to_send;
+  }
+  result = drain_frame_to_bytes(bytes, bytes_size, &impl->outgoing);
+  if (result != TSI_OK) return result;
+  if (!impl->is_client &&
+      impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
+    /* We're done. */
+    gpr_log(GPR_INFO, "Server is done.");
+    impl->result = TSI_OK;
+  } else {
+    impl->needs_incoming_message = 1;
+  }
+  return TSI_OK;
+}
+
+static tsi_result fake_handshaker_process_bytes_from_peer(
+    tsi_handshaker* self, const unsigned char* bytes, uint32_t* bytes_size) {
+  tsi_result result = TSI_OK;
+  tsi_fake_handshaker* impl = (tsi_fake_handshaker*)self;
+  int expected_msg = impl->next_message_to_send - 1;
+  tsi_fake_handshake_message received_msg;
+
+  if (!impl->needs_incoming_message || impl->result == TSI_OK) {
+    *bytes_size = 0;
+    return TSI_OK;
+  }
+  result = fill_frame_from_bytes(bytes, bytes_size, &impl->incoming);
+  if (result != TSI_OK) return result;
+
+  /* We now have a complete frame. */
+  result = tsi_fake_handshake_message_from_string(
+      (const char*)impl->incoming.data + TSI_FAKE_FRAME_HEADER_SIZE,
+      &received_msg);
+  if (result != TSI_OK) {
+    impl->result = result;
+    return result;
+  }
+  if (received_msg != expected_msg) {
+    gpr_log(GPR_ERROR, "Invalid received message (%s instead of %s)",
+            tsi_fake_handshake_message_to_string(received_msg),
+            tsi_fake_handshake_message_to_string(expected_msg));
+  }
+  gpr_log(GPR_INFO, "%s received %s.", impl->is_client ? "Client" : "Server",
+          tsi_fake_handshake_message_to_string(received_msg));
+  tsi_fake_frame_reset(&impl->incoming, 0 /* needs_draining */);
+  impl->needs_incoming_message = 0;
+  if (impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
+    /* We're done. */
+    gpr_log(GPR_INFO, "%s is done.", impl->is_client ? "Client" : "Server");
+    impl->result = TSI_OK;
+  }
+  return TSI_OK;
+}
+
+static tsi_result fake_handshaker_get_result(tsi_handshaker* self) {
+  tsi_fake_handshaker* impl = (tsi_fake_handshaker*)self;
+  return impl->result;
+}
+
+static tsi_result fake_handshaker_extract_peer(tsi_handshaker* self,
+                                               tsi_peer* peer) {
+  tsi_result result = tsi_construct_peer(1, peer);
+  if (result != TSI_OK) return result;
+  result = tsi_construct_string_peer_property_from_cstring(
+      TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_FAKE_CERTIFICATE_TYPE,
+      &peer->properties[0]);
+  if (result != TSI_OK) tsi_peer_destruct(peer);
+  return result;
+}
+
+static tsi_result fake_handshaker_create_frame_protector(
+    tsi_handshaker* self, uint32_t* max_protected_frame_size,
+    tsi_frame_protector** protector) {
+  *protector = tsi_create_fake_protector(max_protected_frame_size);
+  if (*protector == NULL) return TSI_OUT_OF_RESOURCES;
+  return TSI_OK;
+}
+
+static void fake_handshaker_destroy(tsi_handshaker* self) {
+  tsi_fake_handshaker* impl = (tsi_fake_handshaker*)self;
+  tsi_fake_frame_destruct(&impl->incoming);
+  tsi_fake_frame_destruct(&impl->outgoing);
+  free(self);
+}
+
+static const tsi_handshaker_vtable handshaker_vtable = {
+    fake_handshaker_get_bytes_to_send_to_peer,
+    fake_handshaker_process_bytes_from_peer,
+    fake_handshaker_get_result,
+    fake_handshaker_extract_peer,
+    fake_handshaker_create_frame_protector,
+    fake_handshaker_destroy,
+};
+
+tsi_handshaker* tsi_create_fake_handshaker(int is_client) {
+  tsi_fake_handshaker* impl = calloc(1, sizeof(tsi_fake_handshaker));
+  impl->base.vtable = &handshaker_vtable;
+  impl->is_client = is_client;
+  impl->result = TSI_HANDSHAKE_IN_PROGRESS;
+  if (is_client) {
+    impl->needs_incoming_message = 0;
+    impl->next_message_to_send = TSI_FAKE_CLIENT_INIT;
+  } else {
+    impl->needs_incoming_message = 1;
+    impl->next_message_to_send = TSI_FAKE_SERVER_INIT;
+  }
+  return &impl->base;
+}
+
+tsi_frame_protector* tsi_create_fake_protector(
+    uint32_t* max_protected_frame_size) {
+  tsi_fake_frame_protector* impl = calloc(1, sizeof(tsi_fake_frame_protector));
+  if (impl == NULL) return NULL;
+  impl->max_frame_size = (max_protected_frame_size == NULL)
+                             ? TSI_FAKE_DEFAULT_FRAME_SIZE
+                             : *max_protected_frame_size;
+  impl->base.vtable = &frame_protector_vtable;
+  return &impl->base;
+}
diff --git a/src/core/tsi/fake_transport_security.h b/src/core/tsi/fake_transport_security.h
new file mode 100644
index 0000000..075d518
--- /dev/null
+++ b/src/core/tsi/fake_transport_security.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __FAKE_TRANSPORT_SECURITY_H_
+#define __FAKE_TRANSPORT_SECURITY_H_
+
+#include "src/core/tsi/transport_security_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for FAKE certs. */
+#define TSI_FAKE_CERTIFICATE_TYPE "FAKE"
+
+/* Creates a fake handshaker that will create a fake frame protector.
+
+   No cryptography is performed in these objects. They just simulate handshake
+   messages going back and forth for the handshaker and do some framing on
+   cleartext data for the protector.  */
+tsi_handshaker* tsi_create_fake_handshaker(int is_client);
+
+
+/* Creates a protector directly without going through the handshake phase. */
+tsi_frame_protector* tsi_create_fake_protector(
+    uint32_t* max_protected_frame_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __FAKE_TRANSPORT_SECURITY_H_ */
diff --git a/src/core/tsi/fake_transport_security_test.cc b/src/core/tsi/fake_transport_security_test.cc
new file mode 100644
index 0000000..0ae88e0
--- /dev/null
+++ b/src/core/tsi/fake_transport_security_test.cc
@@ -0,0 +1,151 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/tsi/fake_transport_security.h"
+
+#include "src/core/tsi/transport_security_test_lib.h"
+#include <gtest/gtest.h>
+#include "util/random/permute-inl.h"
+
+namespace {
+
+void CheckStringPeerProperty(const tsi_peer& peer, int property_index,
+                             const char* expected_name,
+                             const char* expected_value) {
+  EXPECT_LT(property_index, peer.property_count);
+  const tsi_peer_property* property = &peer.properties[property_index];
+  EXPECT_EQ(TSI_PEER_PROPERTY_TYPE_STRING, property->type);
+  EXPECT_EQ(string(expected_name), string(property->name));
+  EXPECT_EQ(string(expected_value),
+            string(property->value.string.data, property->value.string.length));
+}
+
+class FakeTransportSecurityTest : public tsi::test::TransportSecurityTest {
+ protected:
+  void SetupHandshakers() override {
+    client_handshaker_.reset(tsi_create_fake_handshaker(1));
+    server_handshaker_.reset(tsi_create_fake_handshaker(0));
+  }
+
+  void CheckPeer(tsi_handshaker* handshaker) {
+    tsi_peer peer;
+    EXPECT_EQ(TSI_OK, tsi_handshaker_extract_peer(handshaker, &peer));
+    EXPECT_EQ(1, peer.property_count);
+    CheckStringPeerProperty(peer, 0, TSI_CERTIFICATE_TYPE_PEER_PROPERTY,
+                            TSI_FAKE_CERTIFICATE_TYPE);
+    tsi_peer_destruct(&peer);
+  }
+
+  void CheckHandshakeResults() override {
+    CheckPeer(client_handshaker_.get());
+    CheckPeer(server_handshaker_.get());
+  }
+
+  const tsi::test::TestConfig* config() {
+    return &config_;
+  }
+
+  tsi::test::TestConfig config_;
+};
+
+TEST_F(FakeTransportSecurityTest, Handshake) {
+  PerformHandshake();
+}
+
+TEST_F(FakeTransportSecurityTest, HandshakeSmallBuffer) {
+  config_.handshake_buffer_size = 3;
+  PerformHandshake();
+}
+TEST_F(FakeTransportSecurityTest, PingPong) {
+  PingPong();
+}
+
+TEST_F(FakeTransportSecurityTest, RoundTrip) {
+  config_.client_message = big_message_;
+  config_.server_message = small_message_;
+  DoRoundTrip();
+}
+
+TEST_F(FakeTransportSecurityTest, RoundTripSmallMessageBuffer) {
+  config_.message_buffer_allocated_size = 42;
+  config_.client_message = big_message_;
+  config_.server_message = small_message_;
+  DoRoundTrip();
+}
+
+TEST_F(FakeTransportSecurityTest, RoundTripSmallProtectedBufferSize) {
+  config_.protected_buffer_size = 37;
+  config_.client_message = big_message_;
+  config_.server_message = small_message_;
+  DoRoundTrip();
+}
+
+TEST_F(FakeTransportSecurityTest, RoundTripSmallReadBufferSize) {
+  config_.read_buffer_allocated_size = 41;
+  config_.client_message = big_message_;
+  config_.server_message = small_message_;
+  DoRoundTrip();
+}
+
+TEST_F(FakeTransportSecurityTest, RoundTripSmallClientFrames) {
+  config_.set_client_max_output_protected_frame_size(39);
+  config_.client_message = big_message_;
+  config_.server_message = small_message_;
+  DoRoundTrip();
+}
+
+TEST_F(FakeTransportSecurityTest, RoundTripSmallServerFrames) {
+  config_.set_server_max_output_protected_frame_size(43);
+  config_.client_message = small_message_;
+  config_.server_message = big_message_;
+  DoRoundTrip();
+}
+
+TEST_F(FakeTransportSecurityTest, RoundTripOddBufferSizes) {
+  int odd_sizes[] = {33, 67, 135, 271, 523};
+  RandomPermutation<int> permute(odd_sizes, arraysize(odd_sizes),
+                                 random_.get());
+  permute.Permute();
+  LOG(ERROR) << odd_sizes[0] << "\t" << odd_sizes[1] << "\t" << odd_sizes[2]
+             << "\t" << odd_sizes[3] << "\t" << odd_sizes[4];
+  config_.message_buffer_allocated_size = odd_sizes[0];
+  config_.protected_buffer_size = odd_sizes[1];
+  config_.read_buffer_allocated_size = odd_sizes[2];
+  config_.set_client_max_output_protected_frame_size(odd_sizes[3]);
+  config_.set_server_max_output_protected_frame_size(odd_sizes[4]);
+  config_.client_message = big_message_;
+  config_.server_message = small_message_;
+  DoRoundTrip();
+}
+
+}  // namespace
diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c
new file mode 100644
index 0000000..7bd178b
--- /dev/null
+++ b/src/core/tsi/ssl_transport_security.c
@@ -0,0 +1,1294 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/tsi/ssl_transport_security.h"
+
+#include <limits.h>
+#include <pthread.h>
+
+#include <grpc/support/log.h>
+#include "src/core/tsi/transport_security.h"
+
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+/* --- Constants. ---*/
+
+#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384
+#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024
+
+/* TODO(jboeuf): I have not found a way to get this number dynamically from the
+ * SSL structure. This is what we would ultimately want though... */
+#define TSI_SSL_MAX_PROTECTION_OVERHEAD 100
+
+
+/* --- Structure definitions. ---*/
+
+struct tsi_ssl_handshaker_factory {
+  tsi_result (*create_handshaker)(tsi_ssl_handshaker_factory* self,
+                                  const char* server_name_indication,
+                                  tsi_handshaker** handshaker);
+  void (*destroy)(tsi_ssl_handshaker_factory* self);
+};
+
+typedef struct {
+  tsi_ssl_handshaker_factory base;
+  SSL_CTX* ssl_context;
+} tsi_ssl_client_handshaker_factory;
+
+typedef struct {
+  tsi_ssl_handshaker_factory base;
+
+  /* Several contexts to support SNI.
+     The tsi_peer array contains the subject names of the server certificates
+     associated with the contexts at the same index.  */
+  SSL_CTX** ssl_contexts;
+  tsi_peer* ssl_context_x509_subject_names;
+  uint32_t ssl_context_count;
+  unsigned char* alpn_protocol_list;
+  uint32_t alpn_protocol_list_length;
+} tsi_ssl_server_handshaker_factory;
+
+typedef struct {
+  tsi_handshaker base;
+  SSL* ssl;
+  BIO* into_ssl;
+  BIO* from_ssl;
+  tsi_result result;
+} tsi_ssl_handshaker;
+
+typedef struct {
+  tsi_frame_protector base;
+  SSL* ssl;
+  BIO* into_ssl;
+  BIO* from_ssl;
+  unsigned char* buffer;
+  uint32_t buffer_size;
+  uint32_t buffer_offset;
+} tsi_ssl_frame_protector;
+
+
+/* --- Library Initialization. ---*/
+
+static pthread_once_t init_openssl_once = PTHREAD_ONCE_INIT;
+
+static void init_openssl(void) {
+  SSL_library_init();
+  SSL_load_error_strings();
+  OpenSSL_add_all_algorithms();
+}
+
+/* --- Ssl utils. ---*/
+
+static const char* ssl_error_string(int error) {
+  switch (error) {
+    case SSL_ERROR_NONE:
+      return "SSL_ERROR_NONE";
+    case SSL_ERROR_ZERO_RETURN:
+      return "SSL_ERROR_ZERO_RETURN";
+    case SSL_ERROR_WANT_READ:
+      return "SSL_ERROR_WANT_READ";
+    case SSL_ERROR_WANT_WRITE:
+      return "SSL_ERROR_WANT_WRITE";
+    case SSL_ERROR_WANT_CONNECT:
+      return "SSL_ERROR_WANT_CONNECT";
+    case SSL_ERROR_WANT_ACCEPT:
+      return "SSL_ERROR_WANT_ACCEPT";
+    case SSL_ERROR_WANT_X509_LOOKUP:
+      return "SSL_ERROR_WANT_X509_LOOKUP";
+    case SSL_ERROR_SYSCALL:
+      return "SSL_ERROR_SYSCALL";
+    case SSL_ERROR_SSL:
+      return "SSL_ERROR_SSL";
+    default:
+      return "Unknown error";
+  }
+}
+
+/* TODO(jboeuf): Remove when we are past the debugging phase with this code. */
+static void ssl_log_where_info(const SSL* ssl, int where, int flag,
+                               const char* msg) {
+  if (where & flag) {
+    gpr_log(GPR_INFO, "%20.20s - %30.30s  - %5.10s", msg,
+            SSL_state_string_long(ssl), SSL_state_string(ssl));
+  }
+}
+
+/* Used for debugging. TODO(jboeuf): Remove when code is mature enough. */
+static void ssl_info_callback(const SSL* ssl, int where, int ret) {
+  if (ret == 0) {
+    gpr_log(GPR_ERROR, "ssl_info_callback: error occured.\n");
+    return;
+  }
+
+  ssl_log_where_info(ssl, where, SSL_CB_LOOP, "LOOP");
+  ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_START, "HANDSHAKE START");
+  ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_DONE, "HANDSHAKE DONE");
+}
+
+/* Gets the subject CN from an X509 cert. */
+static tsi_result ssl_get_x509_common_name(X509* cert, unsigned char** utf8,
+                                           uint32_t* utf8_size) {
+  int common_name_index = -1;
+  X509_NAME_ENTRY* common_name_entry = NULL;
+  ASN1_STRING* common_name_asn1 = NULL;
+  X509_NAME* subject_name = X509_get_subject_name(cert);
+  int utf8_returned_size = 0;
+  if (subject_name == NULL) {
+    gpr_log(GPR_ERROR, "Could not get subject name from certificate.");
+    return TSI_NOT_FOUND;
+  }
+  common_name_index =
+      X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1);
+  if (common_name_index == -1) {
+    gpr_log(GPR_ERROR,
+            "Could not get common name of subject from certificate.");
+    return TSI_NOT_FOUND;
+  }
+  common_name_entry = X509_NAME_get_entry(subject_name, common_name_index);
+  if (common_name_entry == NULL) {
+    gpr_log(GPR_ERROR, "Could not get common name entry from certificate.");
+    return TSI_INTERNAL_ERROR;
+  }
+  common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
+  if (common_name_asn1 == NULL) {
+    gpr_log(GPR_ERROR,
+            "Could not get common name entry asn1 from certificate.");
+    return TSI_INTERNAL_ERROR;
+  }
+  utf8_returned_size = ASN1_STRING_to_UTF8(utf8, common_name_asn1);
+  if (utf8_returned_size < 0) {
+    gpr_log(GPR_ERROR, "Could not extract utf8 from asn1 string.");
+    return TSI_OUT_OF_RESOURCES;
+  }
+  *utf8_size = utf8_returned_size;
+  return TSI_OK;
+}
+
+/* Gets the subject CN of an X509 cert as a tsi_peer_property. */
+static tsi_result peer_property_from_x509_common_name(
+    X509* cert, tsi_peer_property* property) {
+  unsigned char* common_name;
+  uint32_t common_name_size;
+  tsi_result result =
+      ssl_get_x509_common_name(cert, &common_name, &common_name_size);
+  if (result != TSI_OK) return result;
+  result = tsi_construct_string_peer_property(
+      TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, (const char*)common_name,
+      common_name_size, property);
+  OPENSSL_free(common_name);
+  return result;
+}
+
+/* Gets the subject SANs from an X509 cert as a tsi_peer_property. */
+static tsi_result peer_property_from_x509_subject_alt_names(
+    X509* cert, tsi_peer_property* property) {
+  int i = 0;
+  int subject_alt_name_count = 0;
+  tsi_result result = TSI_OK;
+  GENERAL_NAMES* subject_alt_names =
+      X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
+  if (subject_alt_names == NULL) {
+    /* Empty list. */
+    return tsi_construct_list_peer_property(
+        TSI_X509_SUBJECT_ALTERNATIVE_NAMES_PEER_PROPERTY, 0, property);
+  }
+
+  subject_alt_name_count = sk_GENERAL_NAME_num(subject_alt_names);
+  result = tsi_construct_list_peer_property(
+      TSI_X509_SUBJECT_ALTERNATIVE_NAMES_PEER_PROPERTY, subject_alt_name_count,
+      property);
+  if (result != TSI_OK) return result;
+
+  /* Reset for DNS entries filtering. */
+  subject_alt_name_count = property->value.list.child_count;
+  property->value.list.child_count = 0;
+
+  for (i = 0; i < subject_alt_name_count; i++) {
+    tsi_peer_property* child_property = NULL;
+    GENERAL_NAME* subject_alt_name =
+        sk_GENERAL_NAME_value(subject_alt_names, i);
+    /* Filter out the non-dns entries names. */
+    if (subject_alt_name->type == GEN_DNS) {
+      unsigned char* dns_name = NULL;
+      int dns_name_size =
+          ASN1_STRING_to_UTF8(&dns_name, subject_alt_name->d.dNSName);
+      if (dns_name_size < 0) {
+        gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string.");
+        result = TSI_INTERNAL_ERROR;
+        break;
+      }
+      child_property =
+          &property->value.list.children[property->value.list.child_count++];
+      result = tsi_construct_string_peer_property(
+          NULL, (const char*)dns_name, dns_name_size, child_property);
+      OPENSSL_free(dns_name);
+      if (result != TSI_OK) break;
+    }
+  }
+  if (result != TSI_OK) tsi_peer_property_destruct(property);
+  sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free);
+  return TSI_OK;
+}
+
+/* Gets information about the peer's X509 cert as a tsi_peer object. */
+static tsi_result peer_from_x509(X509* cert, int include_certificate_type,
+                                 tsi_peer* peer) {
+  /* TODO(jboeuf): Maybe add more properties. */
+  uint32_t property_count = include_certificate_type ? 3 : 2;
+  tsi_result result  = tsi_construct_peer(property_count, peer);
+  if (result != TSI_OK) return result;
+  do {
+    result = peer_property_from_x509_common_name(cert, &peer->properties[0]);
+    if (result != TSI_OK) break;
+    result =
+        peer_property_from_x509_subject_alt_names(cert, &peer->properties[1]);
+    if (result != TSI_OK) break;
+    if (include_certificate_type) {
+      result = tsi_construct_string_peer_property_from_cstring(
+          TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
+          &peer->properties[2]);
+      if (result != TSI_OK) break;
+    }
+  } while (0);
+
+  if (result != TSI_OK) tsi_peer_destruct(peer);
+  return result;
+}
+
+/* Performs an SSL_read and handle errors. */
+static tsi_result do_ssl_read(SSL* ssl, unsigned char* unprotected_bytes,
+                              uint32_t* unprotected_bytes_size) {
+  int read_from_ssl = SSL_read(ssl, unprotected_bytes,
+                               *unprotected_bytes_size);
+  if (read_from_ssl == 0) {
+    gpr_log(GPR_ERROR, "SSL_read returned 0 unexpectedly.");
+    return TSI_INTERNAL_ERROR;
+  }
+  if (read_from_ssl < 0) {
+    read_from_ssl = SSL_get_error(ssl, read_from_ssl);
+    switch (read_from_ssl) {
+      case SSL_ERROR_WANT_READ:
+        /* We need more data to finish the frame. */
+        *unprotected_bytes_size = 0;
+        return TSI_OK;
+      case SSL_ERROR_WANT_WRITE:
+        gpr_log(
+            GPR_ERROR,
+            "Peer tried to renegotiate SSL connection. This is unsupported.");
+        return TSI_UNIMPLEMENTED;
+      case SSL_ERROR_SSL:
+        gpr_log(GPR_ERROR, "Corruption detected.");
+        return TSI_DATA_CORRUPTED;
+      default:
+        gpr_log(GPR_ERROR, "SSL_read failed with error %s.",
+                ssl_error_string(read_from_ssl));
+        return TSI_PROTOCOL_FAILURE;
+    }
+  }
+  *unprotected_bytes_size = read_from_ssl;
+  return TSI_OK;
+}
+
+/* Performs an SSL_write and handle errors. */
+static tsi_result do_ssl_write(SSL* ssl, unsigned char* unprotected_bytes,
+                               uint32_t unprotected_bytes_size) {
+  int ssl_write_result =
+      SSL_write(ssl, unprotected_bytes, 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) {
+      gpr_log(GPR_ERROR,
+              "Peer tried to renegotiate SSL connection. This is unsupported.");
+      return TSI_UNIMPLEMENTED;
+    } else {
+      gpr_log(GPR_ERROR, "SSL_write failed with error %s.",
+              ssl_error_string(ssl_write_result));
+      return TSI_INTERNAL_ERROR;
+    }
+  }
+  return TSI_OK;
+}
+
+/* Loads an in-memory PEM certificate chain into the SSL context. */
+static tsi_result ssl_ctx_use_certificate_chain(
+    SSL_CTX* context, const unsigned char* pem_cert_chain,
+    uint32_t pem_cert_chain_size) {
+  tsi_result result = TSI_OK;
+  X509* certificate = NULL;
+  BIO* pem = BIO_new_mem_buf((void*)pem_cert_chain, pem_cert_chain_size);
+  if (pem == NULL) return TSI_OUT_OF_RESOURCES;
+
+  do {
+    certificate = PEM_read_bio_X509_AUX(pem, NULL, NULL, "");
+    if (certificate == NULL) {
+      result = TSI_INVALID_ARGUMENT;
+      break;
+    }
+    if (!SSL_CTX_use_certificate(context, certificate)) {
+      result = TSI_INVALID_ARGUMENT;
+      break;
+    }
+    while (1) {
+      X509* certificate_authority = PEM_read_bio_X509(pem, NULL, NULL, "");
+      if (certificate_authority == NULL) break;  /* Done reading. */
+      if (!SSL_CTX_add_extra_chain_cert(context, certificate_authority)) {
+        X509_free(certificate_authority);
+        result = TSI_INVALID_ARGUMENT;
+        break;
+      }
+      /* We don't need to free certificate_authority as its ownership has been
+         transfered to the context. That is not the case for certificate though.
+      */
+    }
+  } while (0);
+
+  if (certificate != NULL) X509_free(certificate);
+  BIO_free(pem);
+  return result;
+}
+
+/* Loads an in-memory PEM private key into the SSL context. */
+static tsi_result ssl_ctx_use_private_key(SSL_CTX* context,
+                                          const unsigned char* pem_key,
+                                          uint32_t pem_key_size) {
+  tsi_result result = TSI_OK;
+  EVP_PKEY* private_key = NULL;
+  BIO* pem = BIO_new_mem_buf((void*)pem_key, pem_key_size);
+  if (pem == NULL) return TSI_OUT_OF_RESOURCES;
+  do {
+    private_key = PEM_read_bio_PrivateKey(pem, NULL, NULL, "");
+    if (private_key == NULL) {
+      result = TSI_INVALID_ARGUMENT;
+      break;
+    }
+    if (!SSL_CTX_use_PrivateKey(context, private_key)) {
+      result = TSI_INVALID_ARGUMENT;
+      break;
+    }
+  } while (0);
+  if (private_key != NULL) EVP_PKEY_free(private_key);
+  BIO_free(pem);
+  return result;
+}
+
+/* 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 unsigned char* pem_roots,
+    uint32_t pem_roots_size, STACK_OF(X509_NAME)** root_names) {
+  tsi_result result = TSI_OK;
+  uint32_t num_roots = 0;
+  X509* root = NULL;
+  X509_NAME* root_name = NULL;
+  BIO* pem = BIO_new_mem_buf((void*)pem_roots, pem_roots_size);
+  X509_STORE* root_store = SSL_CTX_get_cert_store(context);
+  if (root_store == NULL) return TSI_INVALID_ARGUMENT;
+  if (pem == NULL) return TSI_OUT_OF_RESOURCES;
+  if (root_names != NULL) {
+    *root_names = sk_X509_NAME_new_null();
+    if (*root_names == NULL) return TSI_OUT_OF_RESOURCES;
+  }
+
+  while (1) {
+    root = PEM_read_bio_X509_AUX(pem, NULL, NULL, "");
+    if (root == NULL) break;  /* We're at the end of stream. */
+    if (root_names != NULL) {
+      root_name = X509_get_subject_name(root);
+      if (root_name == NULL) {
+        gpr_log(GPR_ERROR, "Could not get name from root certificate.");
+        result = TSI_INVALID_ARGUMENT;
+        break;
+      }
+      root_name = X509_NAME_dup(root_name);
+      if (root_name == NULL) {
+        result = TSI_OUT_OF_RESOURCES;
+        break;
+      }
+      sk_X509_NAME_push(*root_names, root_name);
+      root_name = NULL;
+    }
+    if (!X509_STORE_add_cert(root_store, root)) {
+      gpr_log(GPR_ERROR, "Could not add root certificate to ssl context.");
+      result = TSI_INTERNAL_ERROR;
+      break;
+    }
+    X509_free(root);
+    num_roots++;
+  }
+
+  if (num_roots == 0) {
+    gpr_log(GPR_ERROR, "Could not load any root certificate.");
+    result = TSI_INVALID_ARGUMENT;
+  }
+
+  if (result != TSI_OK) {
+    if (root != NULL) X509_free(root);
+    if (root_names != NULL) {
+      sk_X509_NAME_pop_free(*root_names, X509_NAME_free);
+      *root_names = NULL;
+      if (root_name != NULL) X509_NAME_free(root_name);
+    }
+  }
+  BIO_free(pem);
+  return result;
+}
+
+
+/* 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(
+    SSL_CTX* context, const unsigned char* pem_private_key,
+    uint32_t pem_private_key_size,
+    const unsigned char* pem_certificate_chain,
+    uint32_t pem_certificate_chain_size, const char* cipher_list) {
+  tsi_result result = TSI_OK;
+  if (pem_certificate_chain != NULL) {
+    result = ssl_ctx_use_certificate_chain(context, pem_certificate_chain,
+                                           pem_certificate_chain_size);
+    if (result != TSI_OK) {
+      gpr_log(GPR_ERROR, "Invalid cert chain file.");
+      return result;
+    }
+  }
+  if (pem_private_key != NULL) {
+    result =
+        ssl_ctx_use_private_key(context, pem_private_key, pem_private_key_size);
+    if (result != TSI_OK || !SSL_CTX_check_private_key(context)) {
+      gpr_log(GPR_ERROR, "Invalid private key.");
+      return result != TSI_OK ? result : TSI_INVALID_ARGUMENT;
+    }
+  }
+  if ((cipher_list != NULL) && !SSL_CTX_set_cipher_list(context, cipher_list)) {
+    gpr_log(GPR_ERROR, "Invalid cipher list: %s.", cipher_list);
+    return TSI_INVALID_ARGUMENT;
+  }
+  {
+    EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+    if (!SSL_CTX_set_tmp_ecdh(context, ecdh)) {
+      gpr_log(GPR_ERROR, "Could not set ephemeral ECDH key.");
+      result = TSI_INTERNAL_ERROR;
+    }
+    SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
+    EC_KEY_free(ecdh);
+  }
+  return TSI_OK;
+}
+
+/* Extracts the CN and the SANs from an X509 cert as a peer object. */
+static tsi_result extract_x509_subject_names_from_pem_cert(
+    const unsigned char* pem_cert, uint32_t pem_cert_size, tsi_peer* peer) {
+  tsi_result result = TSI_OK;
+  X509* cert = NULL;
+  BIO* pem = BIO_new_mem_buf((void*)pem_cert, pem_cert_size);
+  if (pem == NULL)  return TSI_OUT_OF_RESOURCES;
+
+  cert = PEM_read_bio_X509(pem, NULL, NULL, "");
+  if (cert == NULL) {
+      gpr_log(GPR_ERROR, "Invalid certificate");
+      result = TSI_INVALID_ARGUMENT;
+  } else {
+    result = peer_from_x509(cert, 0, peer);
+  }
+  if (cert != NULL) X509_free(cert);
+  BIO_free(pem);
+  return result;
+}
+
+/* Builds the alpn protocol name list according to rfc 7301. */
+static tsi_result build_alpn_protocol_name_list(
+    const unsigned char** alpn_protocols,
+    const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols,
+    unsigned char** protocol_name_list, uint32_t* protocol_name_list_length) {
+  uint16_t i;
+  unsigned char* current;
+  *protocol_name_list = NULL;
+  *protocol_name_list_length = 0;
+  for (i = 0; i < num_alpn_protocols; i++) {
+    if (alpn_protocols_lengths[i] == 0) {
+      gpr_log(GPR_ERROR, "Invalid 0-length protocol name.");
+      return TSI_INVALID_ARGUMENT;
+    }
+    *protocol_name_list_length += alpn_protocols_lengths[i] + 1;
+  }
+  *protocol_name_list = malloc(*protocol_name_list_length);
+  if (*protocol_name_list == NULL) return TSI_OUT_OF_RESOURCES;
+  current = *protocol_name_list;
+  for (i = 0; i < num_alpn_protocols; i++) {
+    *(current++) = alpn_protocols_lengths[i];
+    memcpy(current, alpn_protocols[i], alpn_protocols_lengths[i]);
+    current += alpn_protocols_lengths[i];
+  }
+  /* Safety check. */
+  if ((current - *protocol_name_list) != *protocol_name_list_length) {
+    return TSI_INTERNAL_ERROR;
+  }
+  return TSI_OK;
+}
+
+/* --- tsi_frame_protector methods implementation. ---*/
+
+static tsi_result ssl_protector_protect(
+    tsi_frame_protector* self, const unsigned char* unprotected_bytes,
+    uint32_t* unprotected_bytes_size,
+    unsigned char* protected_output_frames,
+    uint32_t* protected_output_frames_size) {
+  tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self;
+  int read_from_ssl;
+  uint32_t available;
+  tsi_result result = TSI_OK;
+
+  /* First see if we have some pending data in the SSL BIO. */
+  uint32_t pending_in_ssl = BIO_ctrl_pending(impl->from_ssl);
+  if (pending_in_ssl > 0) {
+    *unprotected_bytes_size = 0;
+    read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
+                             *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 = read_from_ssl;
+    return TSI_OK;
+  }
+
+  /* Now see if we can send a complete frame. */
+  available = impl->buffer_size - impl->buffer_offset;
+  if (available > *unprotected_bytes_size) {
+    /* If we cannot, just copy the data in our internal buffer. */
+    memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes,
+           *unprotected_bytes_size);
+    impl->buffer_offset += *unprotected_bytes_size;
+    *protected_output_frames_size = 0;
+    return TSI_OK;
+  }
+
+  /* If we can, prepare the buffer, send it to SSL_write and read. */
+  memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes, available);
+  result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_size);
+  if (result != TSI_OK) return result;
+
+  read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
+                           *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 = read_from_ssl;
+  *unprotected_bytes_size = available;
+  impl->buffer_offset = 0;
+  return TSI_OK;
+}
+
+static tsi_result ssl_protector_protect_flush(
+    tsi_frame_protector* self, unsigned char* protected_output_frames,
+    uint32_t* protected_output_frames_size,
+    uint32_t* still_pending_size) {
+  tsi_result result = TSI_OK;
+  tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self;
+  int read_from_ssl = 0;
+
+  if (impl->buffer_offset != 0) {
+    result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_offset);
+    if (result != TSI_OK) return result;
+    impl->buffer_offset = 0;
+  }
+
+  *still_pending_size = BIO_ctrl_pending(impl->from_ssl);
+  if (*still_pending_size == 0) return TSI_OK;
+
+  read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
+                           *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 = read_from_ssl;
+  *still_pending_size = BIO_ctrl_pending(impl->from_ssl);
+  return TSI_OK;
+}
+
+static tsi_result ssl_protector_unprotect(
+    tsi_frame_protector* self, const unsigned char* protected_frames_bytes,
+    uint32_t* protected_frames_bytes_size,
+    unsigned char* unprotected_bytes,
+    uint32_t* unprotected_bytes_size) {
+  tsi_result result = TSI_OK;
+  int written_into_ssl = 0;
+  uint32_t output_bytes_size = *unprotected_bytes_size;
+  uint32_t output_bytes_offset = 0;
+  tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self;
+
+  /* First, try to read remaining data from ssl. */
+  result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
+  if (result != TSI_OK)  return result;
+  if (*unprotected_bytes_size == output_bytes_size) {
+    /* We have read everything we could and cannot process any more input. */
+    *protected_frames_bytes_size = 0;
+    return TSI_OK;
+  }
+  output_bytes_offset = *unprotected_bytes_size;
+  unprotected_bytes += output_bytes_offset;
+  *unprotected_bytes_size = output_bytes_size - output_bytes_offset;
+
+  /* Then, try to write some data to ssl. */
+  written_into_ssl = BIO_write(
+      impl->into_ssl, protected_frames_bytes, *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 = written_into_ssl;
+
+  /* Now try to read some data again. */
+  result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
+  if (result == TSI_OK) {
+    /* Don't forget to output the total number of bytes read. */
+    *unprotected_bytes_size += output_bytes_offset;
+  }
+  return result;
+}
+
+static void ssl_protector_destroy(tsi_frame_protector* self) {
+  tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self;
+  if (impl->buffer != NULL) free(impl->buffer);
+  if (impl->ssl != NULL) SSL_free(impl->ssl);
+  free(self);
+}
+
+static const tsi_frame_protector_vtable frame_protector_vtable = {
+    ssl_protector_protect,
+    ssl_protector_protect_flush,
+    ssl_protector_unprotect,
+    ssl_protector_destroy,
+};
+
+
+/* --- tsi_handshaker methods implementation. ---*/
+
+static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(
+    tsi_handshaker* self, unsigned char* bytes, uint32_t* bytes_size) {
+  tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
+  int bytes_read_from_ssl = 0;
+  if (bytes == NULL || bytes_size == NULL || *bytes_size == 0 ||
+      *bytes_size > INT_MAX) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  bytes_read_from_ssl = BIO_read(impl->from_ssl, bytes, *bytes_size);
+  if (bytes_read_from_ssl < 0) {
+    *bytes_size = 0;
+    if (!BIO_should_retry(impl->from_ssl)) {
+      impl->result = TSI_INTERNAL_ERROR;
+      return impl->result;
+    } else {
+      return TSI_OK;
+    }
+  }
+  *bytes_size = (uint32_t)bytes_read_from_ssl;
+  return BIO_ctrl_pending(impl->from_ssl) == 0 ? TSI_OK : TSI_INCOMPLETE_DATA;
+}
+
+static tsi_result ssl_handshaker_get_result(tsi_handshaker* self) {
+  tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
+  if ((impl->result == TSI_HANDSHAKE_IN_PROGRESS) &&
+      SSL_is_init_finished(impl->ssl)) {
+    impl->result = TSI_OK;
+  }
+  return impl->result;
+}
+
+static tsi_result ssl_handshaker_process_bytes_from_peer(
+    tsi_handshaker* self, const unsigned char* bytes,
+    uint32_t* bytes_size) {
+  tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
+  int bytes_written_into_ssl_size = 0;
+  if (bytes == NULL || bytes_size == 0 || *bytes_size > INT_MAX) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  bytes_written_into_ssl_size = BIO_write(impl->into_ssl, bytes, *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 = bytes_written_into_ssl_size;
+
+  if (!tsi_handshaker_is_in_progress(self)) {
+    impl->result = TSI_OK;
+    return impl->result;
+  } else {
+    /* Get ready to get some bytes from SSL. */
+    int ssl_result = SSL_do_handshake(impl->ssl);
+    ssl_result = SSL_get_error(impl->ssl, ssl_result);
+    switch (ssl_result) {
+      case SSL_ERROR_WANT_READ:
+        if (BIO_ctrl_pending(impl->from_ssl) == 0) {
+          /* We need more data. */
+          return TSI_INCOMPLETE_DATA;
+        } else {
+          return TSI_OK;
+        }
+      case SSL_ERROR_NONE:
+        return TSI_OK;
+      default: {
+        char err_str[256];
+        ERR_error_string_n(ERR_get_error(), err_str, sizeof(err_str));
+        gpr_log(GPR_ERROR, "Handshake failed with fatal error %s: %s.",
+                ssl_error_string(ssl_result), err_str);
+        impl->result = TSI_PROTOCOL_FAILURE;
+        return impl->result;
+      }
+    }
+  }
+}
+
+static tsi_result ssl_handshaker_extract_peer(tsi_handshaker* self,
+                                              tsi_peer* peer) {
+  tsi_result result = TSI_OK;
+  const unsigned char* alpn_selected;
+  unsigned int alpn_selected_len;
+  tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
+  X509* peer_cert = SSL_get_peer_certificate(impl->ssl);
+  if (peer_cert != NULL) {
+    result = peer_from_x509(peer_cert, 1, peer);
+    X509_free(peer_cert);
+    if (result != TSI_OK) return result;
+  }
+  SSL_get0_alpn_selected(impl->ssl, &alpn_selected, &alpn_selected_len);
+  if (alpn_selected != NULL) {
+    uint32_t i;
+    tsi_peer_property* new_properties =
+        calloc(1, sizeof(tsi_peer_property) * (peer->property_count + 1));
+    if (new_properties == NULL) return TSI_OUT_OF_RESOURCES;
+    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) {
+      free(new_properties);
+      return result;
+    }
+    if (peer->properties != NULL) free(peer->properties);
+    peer->property_count++;
+    peer->properties = new_properties;
+  }
+  return result;
+}
+
+static tsi_result ssl_handshaker_create_frame_protector(
+    tsi_handshaker* self, uint32_t* max_output_protected_frame_size,
+    tsi_frame_protector** protector) {
+  uint32_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_frame_protector* protector_impl =
+      calloc(1, sizeof(tsi_ssl_frame_protector));
+  if (protector_impl == NULL) {
+    return TSI_OUT_OF_RESOURCES;
+  }
+
+  if (max_output_protected_frame_size != NULL) {
+    if (*max_output_protected_frame_size >
+        TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND) {
+      *max_output_protected_frame_size =
+          TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
+    } else if (*max_output_protected_frame_size <
+               TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND) {
+      *max_output_protected_frame_size =
+          TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND;
+    }
+    actual_max_output_protected_frame_size = *max_output_protected_frame_size;
+  }
+  protector_impl->buffer_size =
+      actual_max_output_protected_frame_size - TSI_SSL_MAX_PROTECTION_OVERHEAD;
+  protector_impl->buffer = malloc(protector_impl->buffer_size);
+  if (protector_impl->buffer == NULL) {
+    gpr_log(GPR_ERROR,
+            "Could not allocated buffer for tsi_ssl_frame_protector.");
+    free(protector_impl);
+    return TSI_INTERNAL_ERROR;
+  }
+
+  /* Transfer ownership of ssl to the frame protector. It is OK as the caller
+   * cannot call anything else but destroy on the handshaker after this call. */
+  protector_impl->ssl = impl->ssl;
+  impl->ssl = NULL;
+  protector_impl->into_ssl = impl->into_ssl;
+  protector_impl->from_ssl = impl->from_ssl;
+
+  protector_impl->base.vtable = &frame_protector_vtable;
+  *protector = &protector_impl->base;
+  return TSI_OK;
+}
+
+static void ssl_handshaker_destroy(tsi_handshaker* self) {
+  tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
+  SSL_free(impl->ssl); /* The BIO objects are owned by ssl */
+  free(impl);
+}
+
+static const tsi_handshaker_vtable handshaker_vtable = {
+    ssl_handshaker_get_bytes_to_send_to_peer,
+    ssl_handshaker_process_bytes_from_peer,
+    ssl_handshaker_get_result,
+    ssl_handshaker_extract_peer,
+    ssl_handshaker_create_frame_protector,
+    ssl_handshaker_destroy,
+};
+
+
+/* --- tsi_ssl_handshaker_factory common methods. --- */
+
+tsi_result tsi_ssl_handshaker_factory_create_handshaker(
+    tsi_ssl_handshaker_factory* self, const char* server_name_indication,
+    tsi_handshaker** handshaker) {
+  if (self == NULL || handshaker == NULL) return TSI_INVALID_ARGUMENT;
+  return self->create_handshaker(self, server_name_indication, handshaker);
+}
+
+void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory* self) {
+  if (self == NULL) return;
+  self->destroy(self);
+}
+
+static tsi_result create_tsi_ssl_handshaker(SSL_CTX* ctx, int is_client,
+                                            const char* server_name_indication,
+                                            tsi_handshaker** handshaker) {
+  SSL* ssl = SSL_new(ctx);
+  BIO* into_ssl = NULL;
+  BIO* from_ssl = NULL;
+  tsi_ssl_handshaker* impl = NULL;
+  *handshaker = NULL;
+  if (ctx == NULL) {
+    gpr_log(GPR_ERROR, "SSL Context is null. Should never happen.");
+    return TSI_INTERNAL_ERROR;
+  }
+  if (ssl == NULL) {
+    return TSI_OUT_OF_RESOURCES;
+  }
+  SSL_set_info_callback(ssl, ssl_info_callback);
+
+  into_ssl = BIO_new(BIO_s_mem());
+  from_ssl = BIO_new(BIO_s_mem());
+  if (into_ssl == NULL || from_ssl == NULL) {
+    gpr_log(GPR_ERROR, "BIO_new failed.");
+    SSL_free(ssl);
+    if (into_ssl != NULL) BIO_free(into_ssl);
+    if (from_ssl != NULL) BIO_free(into_ssl);
+    return TSI_OUT_OF_RESOURCES;
+  }
+  SSL_set_bio(ssl, into_ssl, from_ssl);
+  if (is_client) {
+    int ssl_result;
+    SSL_set_connect_state(ssl);
+    if (server_name_indication != NULL) {
+      if (!SSL_set_tlsext_host_name(ssl, server_name_indication)) {
+        gpr_log(GPR_ERROR, "Invalid server name indication %s.",
+                server_name_indication);
+        SSL_free(ssl);
+        return TSI_INTERNAL_ERROR;
+      }
+    }
+    ssl_result = SSL_do_handshake(ssl);
+    ssl_result = SSL_get_error(ssl, ssl_result);
+    if (ssl_result != SSL_ERROR_WANT_READ) {
+      gpr_log(GPR_ERROR,
+              "Unexpected error received from first SSL_do_handshake call: %s",
+              ssl_error_string(ssl_result));
+      SSL_free(ssl);
+      return TSI_INTERNAL_ERROR;
+    }
+  } else {
+    SSL_set_accept_state(ssl);
+  }
+
+  impl = calloc(1, sizeof(tsi_ssl_handshaker));
+  if (impl == NULL) {
+    SSL_free(ssl);
+    return TSI_OUT_OF_RESOURCES;
+  }
+  impl->ssl = ssl;
+  impl->into_ssl = into_ssl;
+  impl->from_ssl = from_ssl;
+  impl->result = TSI_HANDSHAKE_IN_PROGRESS;
+  impl->base.vtable = &handshaker_vtable;
+  *handshaker = &impl->base;
+  return TSI_OK;
+}
+
+
+/* --- tsi_ssl__client_handshaker_factory methods implementation. --- */
+
+static tsi_result ssl_client_handshaker_factory_create_handshaker(
+    tsi_ssl_handshaker_factory* self, const char* server_name_indication,
+    tsi_handshaker** handshaker) {
+  tsi_ssl_client_handshaker_factory* impl =
+      (tsi_ssl_client_handshaker_factory*)self;
+  return create_tsi_ssl_handshaker(impl->ssl_context, 1, server_name_indication,
+                                   handshaker);
+}
+
+static void ssl_client_handshaker_factory_destroy(
+    tsi_ssl_handshaker_factory* self) {
+  tsi_ssl_client_handshaker_factory* impl =
+      (tsi_ssl_client_handshaker_factory*)self;
+  SSL_CTX_free(impl->ssl_context);
+  free(impl);
+}
+
+
+/* --- tsi_ssl_server_handshaker_factory methods implementation. --- */
+
+static tsi_result ssl_server_handshaker_factory_create_handshaker(
+    tsi_ssl_handshaker_factory* self, const char* server_name_indication,
+    tsi_handshaker** handshaker) {
+  tsi_ssl_server_handshaker_factory* impl =
+      (tsi_ssl_server_handshaker_factory*)self;
+  if (impl->ssl_context_count == 0 || server_name_indication != NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  /* Create the handshaker with the first context. We will switch if needed
+     because of SNI in ssl_server_handshaker_factory_servername_callback.  */
+  return create_tsi_ssl_handshaker(impl->ssl_contexts[0], 0, NULL, handshaker);
+}
+
+static void ssl_server_handshaker_factory_destroy(
+    tsi_ssl_handshaker_factory* self) {
+  tsi_ssl_server_handshaker_factory* impl =
+      (tsi_ssl_server_handshaker_factory*)self;
+  uint32_t i;
+  for (i = 0; i < impl->ssl_context_count; i++) {
+    if (impl->ssl_contexts[i] != NULL) {
+      SSL_CTX_free(impl->ssl_contexts[i]);
+      tsi_peer_destruct(&impl->ssl_context_x509_subject_names[i]);
+    }
+  }
+  if (impl->ssl_contexts != NULL) free(impl->ssl_contexts);
+  if (impl->ssl_context_x509_subject_names != NULL) {
+    free(impl->ssl_context_x509_subject_names);
+  }
+  if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list);
+  free(impl);
+}
+
+static int does_entry_match_name(const char* entry, uint32_t entry_length,
+                                 const char* name) {
+  const char* name_subdomain = NULL;
+  if (entry_length == 0) return 0;
+  if (!strncmp(name, entry, entry_length) && (strlen(name) == entry_length)) {
+    return 1;  /* Perfect match. */
+  }
+  if (entry[0] != '*') return 0;
+
+  /* Wildchar subdomain matching. */
+  if (entry_length < 3 || entry[1] != '.') {  /* At least *.x */
+    gpr_log(GPR_ERROR, "Invalid wildchar entry.");
+    return 0;
+  }
+  name_subdomain = strchr(name, '.');
+  if (name_subdomain == NULL || strlen(name_subdomain) < 2) return 0;
+  name_subdomain++;  /* Starts after the dot. */
+  entry += 2;  /* Remove *. */
+  entry_length -= 2;
+  return (!strncmp(entry, name_subdomain, entry_length) &&
+          (strlen(name_subdomain) == entry_length));
+}
+
+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;
+  uint32_t i = 0;
+  const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+  if (servername == NULL || strlen(servername) == 0) {
+    return SSL_TLSEXT_ERR_NOACK;
+  }
+
+  for (i = 0; i < impl->ssl_context_count; i++) {
+    if (tsi_ssl_peer_matches_name(&impl->ssl_context_x509_subject_names[i],
+                                  servername)) {
+      SSL_set_SSL_CTX(ssl, impl->ssl_contexts[i]);
+      return SSL_TLSEXT_ERR_OK;
+    }
+  }
+  gpr_log(GPR_ERROR, "No match found for server name: %s.", servername);
+  return SSL_TLSEXT_ERR_ALERT_WARNING;
+}
+
+static int server_handshaker_factory_alpn_callback(
+    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;
+  const unsigned char* client_current = in;
+  while ((client_current - in) < inlen) {
+    unsigned char client_current_len = *(client_current++);
+    const unsigned char* server_current = factory->alpn_protocol_list;
+    while ((server_current - factory->alpn_protocol_list) <
+           factory->alpn_protocol_list_length) {
+      unsigned char server_current_len = *(server_current++);
+      if ((client_current_len == server_current_len) &&
+          !memcmp(client_current, server_current, server_current_len)) {
+        *out = server_current;
+        *outlen = server_current_len;
+        return SSL_TLSEXT_ERR_OK;
+      }
+      server_current += server_current_len;
+    }
+    client_current += client_current_len;
+  }
+  return SSL_TLSEXT_ERR_NOACK;
+}
+
+
+/* --- tsi_ssl_handshaker_factory constructors. --- */
+
+tsi_result tsi_create_ssl_client_handshaker_factory(
+    const unsigned char* pem_private_key, uint32_t pem_private_key_size,
+    const unsigned char* pem_cert_chain, uint32_t pem_cert_chain_size,
+    const unsigned char* pem_root_certs, uint32_t pem_root_certs_size,
+    const char* cipher_list, const unsigned char** alpn_protocols,
+    const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols,
+    tsi_ssl_handshaker_factory** factory) {
+  SSL_CTX* ssl_context = NULL;
+  tsi_ssl_client_handshaker_factory* impl = NULL;
+  tsi_result result = TSI_OK;
+
+  pthread_once(&init_openssl_once, init_openssl);
+
+  if (factory == NULL) return TSI_INVALID_ARGUMENT;
+  *factory = NULL;
+  if (pem_root_certs == NULL) return TSI_INVALID_ARGUMENT;
+
+  ssl_context = SSL_CTX_new(TLSv1_2_method());
+  if (ssl_context == NULL) {
+    gpr_log(GPR_ERROR, "Could not create ssl context.");
+    return TSI_INVALID_ARGUMENT;
+  }
+  do {
+    result =
+        populate_ssl_context(ssl_context, pem_private_key, pem_private_key_size,
+                             pem_cert_chain, pem_cert_chain_size, cipher_list);
+    if (result != TSI_OK) break;
+    result = ssl_ctx_load_verification_certs(ssl_context, pem_root_certs,
+                                             pem_root_certs_size, NULL);
+    if (result != TSI_OK) {
+      gpr_log(GPR_ERROR, "Cannot load server root certificates.");
+      break;
+    }
+
+    if (num_alpn_protocols != 0) {
+      unsigned char* alpn_protocol_list = NULL;
+      uint32_t alpn_protocol_list_length = 0;
+      int ssl_failed;
+      result = build_alpn_protocol_name_list(
+          alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
+          &alpn_protocol_list, &alpn_protocol_list_length);
+      if (result != TSI_OK) {
+        gpr_log(GPR_ERROR, "Building alpn list failed with error %s.",
+                tsi_result_to_string(result));
+        break;
+      }
+      ssl_failed = SSL_CTX_set_alpn_protos(ssl_context, alpn_protocol_list,
+                                           alpn_protocol_list_length);
+      free(alpn_protocol_list);
+      if (ssl_failed) {
+        gpr_log(GPR_ERROR, "Could not set alpn protocol list to context.");
+        result = TSI_INVALID_ARGUMENT;
+        break;
+      }
+    }
+  } while (0);
+  if (result != TSI_OK) {
+    SSL_CTX_free(ssl_context);
+    return result;
+  }
+  SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, NULL);
+  /* TODO(jboeuf): Add revocation verification. */
+
+  impl = calloc(1, sizeof(tsi_ssl_client_handshaker_factory));
+  if (impl == NULL) {
+    SSL_CTX_free(ssl_context);
+    return TSI_OUT_OF_RESOURCES;
+  }
+  impl->ssl_context = ssl_context;
+  impl->base.create_handshaker =
+      ssl_client_handshaker_factory_create_handshaker;
+  impl->base.destroy = ssl_client_handshaker_factory_destroy;
+  *factory = &impl->base;
+  return TSI_OK;
+}
+
+tsi_result tsi_create_ssl_server_handshaker_factory(
+    const unsigned char** pem_private_keys,
+    const uint32_t* pem_private_keys_sizes,
+    const unsigned char** pem_cert_chains,
+    const uint32_t* pem_cert_chains_sizes, uint32_t key_cert_pair_count,
+    const unsigned char* pem_client_root_certs,
+    uint32_t pem_client_root_certs_size, const char* cipher_list,
+    const unsigned char** alpn_protocols,
+    const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols,
+    tsi_ssl_handshaker_factory** factory) {
+  tsi_ssl_server_handshaker_factory* impl = NULL;
+  tsi_result result = TSI_OK;
+  uint32_t i = 0;
+
+  pthread_once(&init_openssl_once, init_openssl);
+
+  if (factory == NULL) return TSI_INVALID_ARGUMENT;
+  *factory = NULL;
+  if (key_cert_pair_count == 0 || pem_private_keys == NULL ||
+      pem_cert_chains == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+
+  impl = calloc(1, sizeof(tsi_ssl_server_handshaker_factory));
+  if (impl == NULL) return TSI_OUT_OF_RESOURCES;
+  impl->base.create_handshaker =
+      ssl_server_handshaker_factory_create_handshaker;
+  impl->base.destroy = ssl_server_handshaker_factory_destroy;
+  impl->ssl_contexts = calloc(key_cert_pair_count, sizeof(SSL_CTX*));
+  impl->ssl_context_x509_subject_names =
+      calloc(key_cert_pair_count, sizeof(tsi_peer));
+  if (impl->ssl_contexts == NULL ||
+      impl->ssl_context_x509_subject_names == NULL) {
+    tsi_ssl_handshaker_factory_destroy(&impl->base);
+    return TSI_OUT_OF_RESOURCES;
+  }
+  impl->ssl_context_count = key_cert_pair_count;
+
+  if (num_alpn_protocols > 0) {
+    result = build_alpn_protocol_name_list(
+        alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
+        &impl->alpn_protocol_list, &impl->alpn_protocol_list_length);
+    if (result != TSI_OK) {
+      tsi_ssl_handshaker_factory_destroy(&impl->base);
+      return result;
+    }
+  }
+
+  for (i = 0; i < key_cert_pair_count; i++) {
+    do {
+      impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method());
+      if (impl->ssl_contexts[i] == NULL) {
+        gpr_log(GPR_ERROR, "Could not create ssl context.");
+        result = TSI_OUT_OF_RESOURCES;
+        break;
+      }
+      result = populate_ssl_context(
+          impl->ssl_contexts[i], pem_private_keys[i], pem_private_keys_sizes[i],
+          pem_cert_chains[i], pem_cert_chains_sizes[i], cipher_list);
+      if (result != TSI_OK) break;
+
+      if (pem_client_root_certs != NULL) {
+        STACK_OF(X509_NAME)* root_names = NULL;
+        result = ssl_ctx_load_verification_certs(
+            impl->ssl_contexts[i], pem_client_root_certs,
+            pem_client_root_certs_size, &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);
+        SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER, NULL);
+        /* TODO(jboeuf): Add revocation verification. */
+      }
+
+      result = extract_x509_subject_names_from_pem_cert(
+          pem_cert_chains[i], pem_cert_chains_sizes[i],
+          &impl->ssl_context_x509_subject_names[i]);
+      if (result != TSI_OK) break;
+
+      SSL_CTX_set_tlsext_servername_callback(
+          impl->ssl_contexts[i],
+          ssl_server_handshaker_factory_servername_callback);
+      SSL_CTX_set_tlsext_servername_arg(impl->ssl_contexts[i], impl);
+      SSL_CTX_set_alpn_select_cb(impl->ssl_contexts[i],
+                                 server_handshaker_factory_alpn_callback, impl);
+    } while (0);
+
+    if (result != TSI_OK) {
+      tsi_ssl_handshaker_factory_destroy(&impl->base);
+      return result;
+    }
+  }
+  *factory = &impl->base;
+  return TSI_OK;
+}
+
+/* --- tsi_ssl utils. --- */
+
+int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name) {
+  uint32_t i = 0;
+  const tsi_peer_property* property = tsi_peer_get_property_by_name(
+      peer, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY);
+  if (property == NULL ||
+      property->type != TSI_PEER_PROPERTY_TYPE_STRING) {
+    gpr_log(GPR_ERROR,
+            "Invalid x509 subject common name property.");
+    return 0;
+  }
+  if (does_entry_match_name(property->value.string.data,
+                            property->value.string.length, name)) {
+    return 1;
+  }
+
+  property = tsi_peer_get_property_by_name(
+      peer, TSI_X509_SUBJECT_ALTERNATIVE_NAMES_PEER_PROPERTY);
+  if (property == NULL || property->type != TSI_PEER_PROPERTY_TYPE_LIST) {
+    gpr_log(GPR_ERROR,
+            "Invalid x509 subject alternative names property.");
+    return 0;
+  }
+
+  for (i = 0; i < property->value.list.child_count; i++) {
+    const tsi_peer_property* alt_name_property =
+        &property->value.list.children[i];
+    if (alt_name_property->type != TSI_PEER_PROPERTY_TYPE_STRING) {
+      gpr_log(GPR_ERROR, "Invalid x509 subject alternative name property.");
+      return 0;
+    }
+    if (does_entry_match_name(alt_name_property->value.string.data,
+                              alt_name_property->value.string.length, name)) {
+      return 1;
+    }
+  }
+  return 0;  /* Not found. */
+}
diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h
new file mode 100644
index 0000000..2ed3ed8
--- /dev/null
+++ b/src/core/tsi/ssl_transport_security.h
@@ -0,0 +1,159 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __SSL_TRANSPORT_SECURITY_H_
+#define __SSL_TRANSPORT_SECURITY_H_
+
+#include "src/core/tsi/transport_security_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for X509 certs. */
+#define TSI_X509_CERTIFICATE_TYPE "X509"
+
+/* --- tsi_ssl_handshaker_factory object ---
+
+   This object creates tsi_handshaker objects implemented in terms of the
+   TLS 1.2 specificiation.  */
+
+typedef struct tsi_ssl_handshaker_factory tsi_ssl_handshaker_factory;
+
+/* Creates a client handshaker factory.
+   - pem_private_key is the buffer containing the PEM encoding of the client's
+     private key. This parameter can be NULL if the client does not have a
+     private key.
+   - pem_private_key_size is the size of the associated buffer.
+   - pem_cert_chain is the buffer containing the PEM encoding of the client's
+     certificate chain. This parameter can be NULL if the client does not have
+     a certificate chain.
+   - pem_cert_chain_size is the size of the associated buffer.
+   - pem_roots_cert is the buffer containing the PEM encoding of the server
+     root certificates. This parameter cannot be NULL.
+   - pem_roots_cert_size is the size of the associated buffer.
+   - 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.
+   - alpn_protocols is an array containing the protocol names that the
+     handshakers created with this factory support. This parameter can be NULL.
+   - alpn_protocols_lengths is an array containing the lengths of the alpn
+     protocols specified in alpn_protocols. This parameter can be NULL.
+   - 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.
+   - 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(
+    const unsigned char* pem_private_key, uint32_t pem_private_key_size,
+    const unsigned char* pem_cert_chain, uint32_t pem_cert_chain_size,
+    const unsigned char* pem_root_certs, uint32_t pem_root_certs_size,
+    const char* cipher_suites, const unsigned char** alpn_protocols,
+    const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols,
+    tsi_ssl_handshaker_factory** factory);
+
+/* Creates a server handshaker factory.
+   - version indicates which version of the specification to use.
+   - pem_private_keys is an array containing the PEM encoding of the server's
+     private keys.  This parameter cannot be NULL. The size of the array is
+     given by the key_cert_pair_count parameter.
+   - pem_private_keys_sizes is the array containing the sizes of the associated
+     buffers.
+   - pem_cert_chains is an array containing the PEM encoding of the server's
+     cert chains.  This parameter cannot be NULL. The size of the array is
+     given by the key_cert_pair_count parameter.
+   - pem_cert_chains_sizes is the array containing the sizes of the associated
+     buffers.
+   - key_cert_pair_count indicates the number of items in the private_key_files
+     and cert_chain_files parameters.
+   - pem_client_roots is the buffer containing the PEM encoding of the client
+     root certificates. This parameter may be NULL in which case the server
+     will not ask the client to authenticate itself with a certificate (server-
+     only authentication mode).
+   - pem_client_roots_size is the size of the associated buffer.
+   - 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.
+   - alpn_protocols is an array containing the protocol names that the
+     handshakers created with this factory support. This parameter can be NULL.
+   - alpn_protocols_lengths is an array containing the lengths of the alpn
+     protocols specified in alpn_protocols. This parameter can be NULL.
+   - 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.
+   - 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(
+    const unsigned char** pem_private_keys,
+    const uint32_t* pem_private_keys_sizes,
+    const unsigned char** pem_cert_chains,
+    const uint32_t* pem_cert_chains_sizes, uint32_t key_cert_pair_count,
+    const unsigned char* pem_client_root_certs,
+    uint32_t pem_client_root_certs_size, const char* cipher_suites,
+    const unsigned char** alpn_protocols,
+    const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols,
+    tsi_ssl_handshaker_factory** factory);
+
+/* Creates a handshaker.
+  - self is the factory from which the handshaker will be created.
+  - server_name_indication indicates the name of the server the client is
+    trying to connect to which will be relayed to the server using the SNI
+    extension.
+    This parameter must be NULL for a server handshaker factory.
+  - handhshaker is the address of the handshaker 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_ssl_handshaker_factory_create_handshaker(
+    tsi_ssl_handshaker_factory* self, const char* server_name_indication,
+    tsi_handshaker** handshaker);
+
+/* Destroys the handshaker factory. WARNING: it is unsafe to destroy a factory
+   while handshakers created with this factory are still in use.  */
+void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory* self);
+
+/* Util that checks that an ssl peer matches a specific name. */
+int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __SSL_TRANSPORT_SECURITY_H_ */
diff --git a/src/core/tsi/ssl_transport_security_test.cc b/src/core/tsi/ssl_transport_security_test.cc
new file mode 100644
index 0000000..a759403
--- /dev/null
+++ b/src/core/tsi/ssl_transport_security_test.cc
@@ -0,0 +1,534 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <memory>
+
+#include "base/commandlineflags.h"
+#include "file/base/helpers.h"
+#include "file/base/options.pb.h"
+#include "file/base/path.h"
+#include "src/core/tsi/transport_security_test_lib.h"
+#include "src/core/tsi/ssl_transport_security.h"
+#include "util/random/permute-inl.h"
+
+namespace {
+
+const char kTestCredsDir[] =
+    "/internal/tsi/test_creds/";
+
+enum AlpnMode {
+  NO_ALPN,
+  ALPN_CLIENT_NO_SERVER,
+  ALPN_SERVER_NO_CLIENT,
+  ALPN_CLIENT_SERVER_OK,
+  ALPN_CLIENT_SERVER_MISMATCH
+};
+
+class SslTestConfig : public tsi::test::TestConfig {
+ public:
+  SslTestConfig()
+      : do_client_authentication(false),
+        subject_name_indication(nullptr),
+        use_bad_client_cert(false),
+        use_bad_server_cert(false),
+        alpn_mode(NO_ALPN) {}
+  bool do_client_authentication;
+  const char* subject_name_indication;
+  bool use_bad_client_cert;
+  bool use_bad_server_cert;
+  AlpnMode alpn_mode;
+};
+
+struct TsiSslHandshakerFactoryDeleter {
+  inline void operator()(tsi_ssl_handshaker_factory* ptr) {
+    tsi_ssl_handshaker_factory_destroy(ptr);
+  }
+};
+typedef std::unique_ptr<tsi_ssl_handshaker_factory,
+                        TsiSslHandshakerFactoryDeleter>
+    TsiSslHandshakerFactoryUniquePtr;
+
+class SslTransportSecurityTest : public tsi::test::TransportSecurityTest {
+ protected:
+  void CheckSubjectAltName(const tsi_peer_property& property,
+                           const string& expected_subject_alt_name) {
+    EXPECT_EQ(property.type, TSI_PEER_PROPERTY_TYPE_STRING);
+    EXPECT_EQ(property.name, nullptr);
+    EXPECT_EQ(
+        string(property.value.string.data, property.value.string.length),
+        expected_subject_alt_name);
+  }
+
+  const tsi_peer_property* CheckBasicAuthenticatedPeerAndGetCommonName(
+      const tsi_peer* peer) {
+    const tsi_peer_property* property =
+        tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY);
+    EXPECT_NE(property, nullptr);
+    EXPECT_EQ(property->type, TSI_PEER_PROPERTY_TYPE_STRING);
+    EXPECT_EQ(
+        string(property->value.string.data, property->value.string.length),
+        string(TSI_X509_CERTIFICATE_TYPE));
+    property = tsi_peer_get_property_by_name(
+        peer, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY);
+    EXPECT_EQ(property->type, TSI_PEER_PROPERTY_TYPE_STRING);
+    return property;
+  }
+
+  void CheckServer0Peer(tsi_peer* peer) {
+    const tsi_peer_property* property =
+        CheckBasicAuthenticatedPeerAndGetCommonName(peer);
+    EXPECT_EQ(
+        string(property->value.string.data, property->value.string.length),
+        string("*.test.google.com.au"));
+    property = tsi_peer_get_property_by_name(
+        peer, TSI_X509_SUBJECT_ALTERNATIVE_NAMES_PEER_PROPERTY);
+    EXPECT_EQ(property->type, TSI_PEER_PROPERTY_TYPE_LIST);
+    EXPECT_EQ(property->value.list.child_count, 0);
+    EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "foo.test.google.com.au"));
+    EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "bar.test.google.com.au"));
+    EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "bar.test.google.blah"));
+    EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "foo.bar.test.google.com.au"));
+    EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "test.google.com.au"));
+    tsi_peer_destruct(peer);
+  }
+
+  void CheckServer1Peer(tsi_peer* peer) {
+    const tsi_peer_property* property =
+        CheckBasicAuthenticatedPeerAndGetCommonName(peer);
+    EXPECT_EQ(
+        string(property->value.string.data, property->value.string.length),
+        string("*.test.google.com"));
+    property = tsi_peer_get_property_by_name(
+        peer, TSI_X509_SUBJECT_ALTERNATIVE_NAMES_PEER_PROPERTY);
+    EXPECT_EQ(property->type, TSI_PEER_PROPERTY_TYPE_LIST);
+    EXPECT_EQ(property->value.list.child_count, 3);
+    CheckSubjectAltName(property->value.list.children[0], "*.test.google.fr");
+    CheckSubjectAltName(property->value.list.children[1],
+                        "waterzooi.test.google.be");
+    CheckSubjectAltName(property->value.list.children[2], "*.test.youtube.com");
+    EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "foo.test.google.com"));
+    EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "bar.test.google.fr"));
+    EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "waterzooi.test.google.be"));
+    EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "foo.test.youtube.com"));
+    EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "bar.foo.test.google.com"));
+    EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "test.google.fr"));
+    EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "tartines.test.google.be"));
+    EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "tartines.youtube.com"));
+    tsi_peer_destruct(peer);
+  }
+
+  void CheckClientPeer(tsi_peer* peer, bool is_authenticated) {
+    if (!is_authenticated) {
+      EXPECT_EQ(peer->property_count,
+                config_.alpn_mode == ALPN_CLIENT_SERVER_OK ? 1 : 0);
+    } else {
+      const tsi_peer_property* property =
+          CheckBasicAuthenticatedPeerAndGetCommonName(peer);
+      EXPECT_EQ(
+          string(property->value.string.data, property->value.string.length),
+          string("testclient"));
+    }
+    tsi_peer_destruct(peer);
+  }
+
+  void SetupHandshakers() override {
+    tsi_ssl_handshaker_factory* client_handshaker_factory;
+    const unsigned char* client_cert = NULL;
+    unsigned int client_cert_size = 0;
+    const unsigned char* client_key = NULL;
+    unsigned int client_key_size = 0;
+    if (config_.do_client_authentication) {
+      if (config_.use_bad_client_cert) {
+        client_cert =
+            reinterpret_cast<const unsigned char*>(badclient_cert_.data());
+        client_cert_size = badclient_cert_.size();
+        client_key =
+            reinterpret_cast<const unsigned char*>(badclient_key_.data());
+        client_key_size = badclient_key_.size();
+      } else {
+        client_cert =
+            reinterpret_cast<const unsigned char*>(client_cert_.data());
+        client_cert_size = client_cert_.size();
+        client_key = reinterpret_cast<const unsigned char*>(client_key_.data());
+        client_key_size = client_key_.size();
+      }
+    }
+    const unsigned char** client_alpn_protocols(nullptr);
+    const unsigned char* client_alpn_protocols_lengths(nullptr);
+    uint16_t num_client_alpn_protocols = 0;
+    if (config_.alpn_mode == ALPN_CLIENT_NO_SERVER ||
+        config_.alpn_mode == ALPN_CLIENT_SERVER_OK ||
+        config_.alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) {
+      client_alpn_protocols =
+          reinterpret_cast<const unsigned char**>(&client_alpn_protocols_[0]);
+      client_alpn_protocols_lengths = &client_alpn_protocols_lengths_[0];
+      num_client_alpn_protocols = client_alpn_protocols_.size();
+    }
+
+    EXPECT_EQ(tsi_create_ssl_client_handshaker_factory(
+                  client_key, client_key_size, client_cert, client_cert_size,
+                  reinterpret_cast<const unsigned char*>(root_certs_.data()),
+                  root_certs_.size(), NULL, client_alpn_protocols,
+                  client_alpn_protocols_lengths, num_client_alpn_protocols,
+                  &client_handshaker_factory),
+              TSI_OK);
+    client_handshaker_factory_.reset(client_handshaker_factory);
+
+    const unsigned char** server_alpn_protocols(nullptr);
+    const unsigned char* server_alpn_protocols_lengths(nullptr);
+    uint16_t num_server_alpn_protocols = 0;
+    if (config_.alpn_mode == ALPN_SERVER_NO_CLIENT ||
+        config_.alpn_mode == ALPN_CLIENT_SERVER_OK ||
+        config_.alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) {
+      server_alpn_protocols =
+          reinterpret_cast<const unsigned char**>(&server_alpn_protocols_[0]);
+      server_alpn_protocols_lengths = &server_alpn_protocols_lengths_[0];
+      num_server_alpn_protocols = server_alpn_protocols_.size();
+      if (config_.alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) {
+        // Remove the last element that is common.
+        num_server_alpn_protocols--;
+      }
+    }
+    tsi_ssl_handshaker_factory* server_handshaker_factory;
+    EXPECT_EQ(
+        tsi_create_ssl_server_handshaker_factory(
+            config_.use_bad_server_cert ? &badserver_keys_[0]
+                                        : &server_keys_[0],
+            config_.use_bad_server_cert ? &badserver_keys_sizes_[0]
+                                        : &server_keys_sizes_[0],
+            config_.use_bad_server_cert ? &badserver_certs_[0]
+                                        : &server_certs_[0],
+            config_.use_bad_server_cert ? &badserver_certs_sizes_[0]
+                                        : &server_certs_sizes_[0],
+            config_.use_bad_server_cert ? badserver_keys_.size()
+                                        : server_keys_.size(),
+            config_.do_client_authentication
+                ? reinterpret_cast<const unsigned char*>(root_certs_.data())
+                : NULL,
+            config_.do_client_authentication ? root_certs_.size() : 0, NULL,
+            server_alpn_protocols, server_alpn_protocols_lengths,
+            num_server_alpn_protocols, &server_handshaker_factory),
+        TSI_OK);
+    server_handshaker_factory_.reset(server_handshaker_factory);
+
+    tsi_handshaker* client_handshaker;
+    EXPECT_EQ(tsi_ssl_handshaker_factory_create_handshaker(
+                  client_handshaker_factory, config_.subject_name_indication,
+                  &client_handshaker),
+              TSI_OK);
+    client_handshaker_.reset(client_handshaker);
+
+    tsi_handshaker* server_handshaker;
+    EXPECT_EQ(tsi_ssl_handshaker_factory_create_handshaker(
+                  server_handshaker_factory, NULL, &server_handshaker),
+              TSI_OK);
+    server_handshaker_.reset(server_handshaker);
+  }
+
+  void CheckAlpn(const tsi_peer* peer) {
+    const tsi_peer_property* alpn_property =
+        tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
+    if (config_.alpn_mode != ALPN_CLIENT_SERVER_OK) {
+      EXPECT_EQ(nullptr, alpn_property);
+    } else {
+      EXPECT_NE(nullptr, alpn_property);
+      EXPECT_EQ(TSI_PEER_PROPERTY_TYPE_STRING, alpn_property->type);
+      string expected_match("baz");
+      EXPECT_EQ(expected_match, string(alpn_property->value.string.data,
+                                       alpn_property->value.string.length));
+    }
+  }
+
+  void CheckHandshakeResults() override {
+    tsi_peer peer;
+
+    bool expect_success =
+        !(config_.use_bad_server_cert ||
+          (config_.use_bad_client_cert && config_.do_client_authentication));
+    tsi_result result = tsi_handshaker_get_result(client_handshaker_.get());
+    EXPECT_NE(result, TSI_HANDSHAKE_IN_PROGRESS);
+    if (expect_success) {
+      EXPECT_EQ(result, TSI_OK);
+      EXPECT_EQ(tsi_handshaker_extract_peer(client_handshaker_.get(), &peer),
+                TSI_OK);
+      CheckAlpn(&peer);
+      // TODO(jboeuf): This is a bit fragile. Maybe revisit.
+      if (config_.subject_name_indication != nullptr) {
+        CheckServer1Peer(&peer);
+      } else {
+        CheckServer0Peer(&peer);
+      }
+    } else {
+      EXPECT_NE(result, TSI_OK);
+      EXPECT_NE(tsi_handshaker_extract_peer(client_handshaker_.get(), &peer),
+                TSI_OK);
+    }
+
+    result = tsi_handshaker_get_result(server_handshaker_.get());
+    EXPECT_NE(result, TSI_HANDSHAKE_IN_PROGRESS);
+    if (expect_success) {
+      EXPECT_EQ(result, TSI_OK);
+      EXPECT_EQ(tsi_handshaker_extract_peer(server_handshaker_.get(), &peer),
+                TSI_OK);
+      CheckAlpn(&peer);
+      CheckClientPeer(&peer, config_.do_client_authentication);
+    } else {
+      EXPECT_NE(result, TSI_OK);
+      EXPECT_NE(tsi_handshaker_extract_peer(server_handshaker_.get(), &peer),
+                TSI_OK);
+    }
+  }
+
+  const tsi::test::TestConfig* config() override {
+    return &config_;
+  }
+
+  SslTransportSecurityTest()
+      : client_alpn_protocols_({"foo", "toto", "baz"}),
+        server_alpn_protocols_({"boooo", "far", "baz"}),
+        client_alpn_protocols_lengths_({3, 4, 3}),
+        server_alpn_protocols_lengths_({5, 3, 3}) {
+    CHECK_OK(file::GetContents(
+        file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "badserver.key"),
+        &badserver_key_, file::Options()));
+    CHECK_OK(file::GetContents(
+        file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "badserver.pem"),
+        &badserver_cert_, file::Options()));
+    CHECK_OK(file::GetContents(
+        file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "badclient.key"),
+        &badclient_key_, file::Options()));
+    CHECK_OK(file::GetContents(
+        file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "badclient.pem"),
+        &badclient_cert_, file::Options()));
+    CHECK_OK(file::GetContents(
+        file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "server0.key"),
+        &server0_key_, file::Options()));
+    CHECK_OK(file::GetContents(
+        file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "server0.pem"),
+        &server0_cert_, file::Options()));
+    CHECK_OK(file::GetContents(
+        file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "server1.key"),
+        &server1_key_, file::Options()));
+    CHECK_OK(file::GetContents(
+        file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "server1.pem"),
+        &server1_cert_, file::Options()));
+    CHECK_OK(file::GetContents(
+        file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "client.key"),
+        &client_key_, file::Options()));
+    CHECK_OK(file::GetContents(
+        file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "client.pem"),
+        &client_cert_, file::Options()));
+    CHECK_OK(file::GetContents(
+        file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "ca.pem"),
+        &root_certs_, file::Options()));
+    badserver_keys_.push_back(
+        reinterpret_cast<const unsigned char*>(badserver_key_.data()));
+    badserver_certs_.push_back(
+        reinterpret_cast<const unsigned char*>(badserver_cert_.data()));
+    server_keys_.push_back(
+        reinterpret_cast<const unsigned char*>(server0_key_.data()));
+    server_keys_.push_back(
+        reinterpret_cast<const unsigned char*>(server1_key_.data()));
+    server_certs_.push_back(
+        reinterpret_cast<const unsigned char*>(server0_cert_.data()));
+    server_certs_.push_back(
+        reinterpret_cast<const unsigned char*>(server1_cert_.data()));
+    badserver_keys_sizes_.push_back(badserver_key_.size());
+    badserver_certs_sizes_.push_back(badserver_cert_.size());
+    server_keys_sizes_.push_back(server0_key_.size());
+    server_keys_sizes_.push_back(server1_key_.size());
+    server_certs_sizes_.push_back(server0_cert_.size());
+    server_certs_sizes_.push_back(server1_cert_.size());
+  }
+
+  string badserver_key_;
+  string badserver_cert_;
+  string badclient_key_;
+  string badclient_cert_;
+  string server0_key_;
+  string server0_cert_;
+  string server1_key_;
+  string server1_cert_;
+  string client_key_;
+  string client_cert_;
+  string root_certs_;
+  std::vector<const unsigned char*> badserver_keys_;
+  std::vector<const unsigned char*> badserver_certs_;
+  std::vector<const unsigned char*> server_keys_;
+  std::vector<const unsigned char*> server_certs_;
+  std::vector<unsigned int> badserver_keys_sizes_;
+  std::vector<unsigned int> badserver_certs_sizes_;
+  std::vector<unsigned int> server_keys_sizes_;
+  std::vector<unsigned int> server_certs_sizes_;
+  TsiSslHandshakerFactoryUniquePtr client_handshaker_factory_;
+  TsiSslHandshakerFactoryUniquePtr server_handshaker_factory_;
+  std::vector<const char*> client_alpn_protocols_;
+  std::vector<const char*> server_alpn_protocols_;
+  std::vector<unsigned char> client_alpn_protocols_lengths_;
+  std::vector<unsigned char> server_alpn_protocols_lengths_;
+  string matched_alpn_;
+  SslTestConfig config_;
+};
+
+
+TEST_F(SslTransportSecurityTest, LoadInvalidRoots) {
+  tsi_ssl_handshaker_factory* client_handshaker_factory;
+  string invalid_roots("Invalid roots!");
+  EXPECT_EQ(
+      TSI_INVALID_ARGUMENT,
+      tsi_create_ssl_client_handshaker_factory(
+          NULL, 0, NULL, 0,
+          reinterpret_cast<const unsigned char*>(invalid_roots.data()),
+          invalid_roots.size(), NULL, NULL, 0, 0, &client_handshaker_factory));
+}
+
+TEST_F(SslTransportSecurityTest, Handshake) {
+  PerformHandshake();
+}
+
+TEST_F(SslTransportSecurityTest, HandshakeClientAuthentication) {
+  config_.do_client_authentication = true;
+  PerformHandshake();
+}
+
+TEST_F(SslTransportSecurityTest, HandshakeSmallBuffer) {
+  config_.handshake_buffer_size = 128;
+  PerformHandshake();
+}
+
+TEST_F(SslTransportSecurityTest, HandshakeSNIExactDomain) {
+  // server1 cert contains waterzooi.test.google.be in SAN.
+  config_.subject_name_indication = "waterzooi.test.google.be";
+  PerformHandshake();
+}
+
+TEST_F(SslTransportSecurityTest, HandshakeSNIWildstarDomain) {
+  // server1 cert contains *.test.google.fr in SAN.
+  config_.subject_name_indication = "juju.test.google.fr";
+  PerformHandshake();
+}
+
+TEST_F(SslTransportSecurityTest, BadServerCertFailure) {
+  config_.use_bad_server_cert = true;
+  PerformHandshake();
+}
+
+TEST_F(SslTransportSecurityTest, BadClientCertFailure) {
+  config_.use_bad_client_cert = true;
+  config_.do_client_authentication = true;
+  PerformHandshake();
+}
+
+TEST_F(SslTransportSecurityTest, AlpnClientNoServer) {
+  config_.alpn_mode = ALPN_CLIENT_NO_SERVER;
+  PerformHandshake();
+}
+
+TEST_F(SslTransportSecurityTest, AlpnServerNoClient) {
+  config_.alpn_mode = ALPN_SERVER_NO_CLIENT;
+  PerformHandshake();
+}
+
+TEST_F(SslTransportSecurityTest, AlpnClientServeMismatch) {
+  config_.alpn_mode = ALPN_CLIENT_SERVER_MISMATCH;
+  PerformHandshake();
+}
+
+TEST_F(SslTransportSecurityTest, AlpnClientServerOk) {
+  config_.alpn_mode = ALPN_CLIENT_SERVER_OK;
+  PerformHandshake();
+}
+
+TEST_F(SslTransportSecurityTest, PingPong) {
+  PingPong();
+}
+
+TEST_F(SslTransportSecurityTest, RoundTrip) {
+  config_.client_message = big_message_;
+  config_.server_message = small_message_;
+  DoRoundTrip();
+}
+
+TEST_F(SslTransportSecurityTest, RoundTripSmallMessageBuffer) {
+  config_.message_buffer_allocated_size = 42;
+  config_.client_message = big_message_;
+  config_.server_message = small_message_;
+  DoRoundTrip();
+}
+
+TEST_F(SslTransportSecurityTest, RoundTripSmallProtectedBufferSize) {
+  config_.protected_buffer_size = 37;
+  config_.client_message = big_message_;
+  config_.server_message = small_message_;
+  DoRoundTrip();
+}
+
+TEST_F(SslTransportSecurityTest, RoundTripSmallReadBufferSize) {
+  config_.read_buffer_allocated_size = 41;
+  config_.client_message = big_message_;
+  config_.server_message = small_message_;
+  DoRoundTrip();
+}
+
+TEST_F(SslTransportSecurityTest, RoundTripSmallClientFrames) {
+  config_.set_client_max_output_protected_frame_size(39);
+  config_.client_message = big_message_;
+  config_.server_message = small_message_;
+  DoRoundTrip();
+}
+
+TEST_F(SslTransportSecurityTest, RoundTripSmallServerFrames) {
+  config_.set_server_max_output_protected_frame_size(43);
+  config_.client_message = small_message_;
+  config_.server_message = big_message_;
+  DoRoundTrip();
+}
+
+TEST_F(SslTransportSecurityTest, RoundTripOddBufferSizes) {
+  int odd_sizes[] = {33, 67, 135, 271, 523};
+  RandomPermutation<int> permute(odd_sizes, arraysize(odd_sizes),
+                                 random_.get());
+  permute.Permute();
+  LOG(ERROR) << odd_sizes[0] << "\t" << odd_sizes[1] << "\t" << odd_sizes[2]
+             << "\t" << odd_sizes[3] << "\t" << odd_sizes[4];
+  config_.message_buffer_allocated_size = odd_sizes[0];
+  config_.protected_buffer_size = odd_sizes[1];
+  config_.read_buffer_allocated_size = odd_sizes[2];
+  config_.set_client_max_output_protected_frame_size(odd_sizes[3]);
+  config_.set_server_max_output_protected_frame_size(odd_sizes[4]);
+  config_.client_message = big_message_;
+  config_.server_message = small_message_;
+  DoRoundTrip();
+}
+
+}  // namespace
diff --git a/src/core/tsi/test_creds/README b/src/core/tsi/test_creds/README
new file mode 100644
index 0000000..eb8482d
--- /dev/null
+++ b/src/core/tsi/test_creds/README
@@ -0,0 +1,62 @@
+The test credentials (CONFIRMEDTESTKEY) have been generated with the following
+commands:
+
+Bad credentials (badclient.* / badserver.*):
+============================================
+
+These are self-signed certificates:
+
+$ openssl req -x509 -newkey rsa:1024 -keyout badserver.key -out badserver.pem \
+  -days 3650 -nodes
+
+When prompted for certificate information, everything is default except the
+common name which is set to badserver.test.google.com.
+
+
+Valid test credentials:
+=======================
+
+The ca is self-signed:
+----------------------
+
+$ openssl req -x509 -new -newkey rsa:1024 -nodes -out ca.pem -config ca-openssl.cnf -days 3650 -extensions v3_req
+When prompted for certificate information, everything is default.
+
+client is issued by CA:
+-----------------------
+
+$ openssl genrsa -out client.key.rsa 1024
+$ openssl pkcs8 -topk8 -in client.key.rsa -out client.key -nocrypt
+$ rm client.key.rsa
+$ openssl req -new -key client.key -out client.csr
+
+When prompted for certificate information, everything is default except the
+common name which is set to testclient.
+
+$ openssl ca -in client.csr -out client.pem
+
+server0 is issued by CA:
+------------------------
+
+$ openssl genrsa -out server0.key.rsa 1024
+$ openssl pkcs8 -topk8 -in server0.key.rsa -out server0.key -nocrypt
+$ rm server0.key.rsa
+$ openssl req -new -key server0.key -out server0.csr
+
+When prompted for certificate information, everything is default except the
+common name which is set to *.test.google.com.au.
+
+$ openssl ca -in server0.csr -out server0.pem
+
+server1 is issued by CA with a special config for subject alternative names:
+----------------------------------------------------------------------------
+
+$ openssl genrsa -out server1.key.rsa 1024
+$ openssl pkcs8 -topk8 -in server1.key.rsa -out server1.key -nocrypt
+$ rm server1.key.rsa
+$ openssl req -new -key server1.key -out server1.csr -config server1-openssl.cnf
+
+When prompted for certificate information, everything is default except the
+common name which is set to *.test.google.com.
+
+$ openssl ca -in server1.csr -out server1.pem
diff --git a/src/core/tsi/test_creds/badclient.key b/src/core/tsi/test_creds/badclient.key
new file mode 100644
index 0000000..5832685
--- /dev/null
+++ b/src/core/tsi/test_creds/badclient.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALJfYnFn4nkj52WF
+E5W2qUxCfjsEFyuXYYKS/07UPWsv3gpZhtjXgdeGL+dpwEBC0IRDBfGnkMp6YY5S
+O7rnEz0X3r/fvgYy+dEl2jnaA6zgc7RzMGl9U11d56gP9FiDC2190mvP/hpq2xLZ
+CTbIximpmaoQyxuuH1bbYunesIG/AgMBAAECgYAdqJCEzMIyZE7oaW0tOpcB0BiP
+FYoIvH4BKRH8eHvR476mt+YdDhBP1scGUmYeCT4Ej+RgHv2LPTgVYwT9eciP2+E/
+CBCNRel0Sw9JepwW0r+jWJtDY1pp6YXAgNRGX2UflvUsT+o9lZvagf9moLTMyGvU
+uLFnsyfLim1B4vXvWQJBANouZllXGZoSrZLtR3VgV4tzRQvJxu84kLeIk64Ov47X
+pHVBMTRBfzPEhbBodjr1m5OLaVLqkFcXftzRCrbWoKsCQQDRSoLLXOiLrtJ3DLJC
+rX7Y8wrHZrqk5bMdZLGa/UX8RanhVw3+Xp+urd1711umeNJfzu/MCk4a1KkG/CU0
+rqs9AkA4cSx1DD1JSG+yxMNpsAS1xJomFIrsM9vsPt7FdndDwrF+y+CovhDkGYDk
+RAHh+svGfZg/pQK2JRPimAmHhzqFAkEAu6Ya70s2FUeB3Mu9aJs2CD6hg3dQEVkB
+53DI7TX48d9kGW58VX1xnqS02LyWqAPcW5qm1kLHFLdndaPNmBaj4QJBAJugl367
+9d9t/QLTSuULLaoYv2vJT3s1y9HN89EoaDDEkPVfQu6GVEXgIBtim1sI/VPSzI8H
+aXvaTUwblFWSM70=
+-----END PRIVATE KEY-----
diff --git a/src/core/tsi/test_creds/badclient.pem b/src/core/tsi/test_creds/badclient.pem
new file mode 100644
index 0000000..1785970
--- /dev/null
+++ b/src/core/tsi/test_creds/badclient.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICoDCCAgmgAwIBAgIJANIz2/zoRiapMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQxIjAgBgNVBAMMGWJhZGNsaWVudC50ZXN0Lmdvb2dsZS5j
+b20wHhcNMTQwNzI4MjAwODI1WhcNMjQwNzI1MjAwODI1WjBpMQswCQYDVQQGEwJB
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMSIwIAYDVQQDDBliYWRjbGllbnQudGVzdC5nb29nbGUuY29tMIGf
+MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyX2JxZ+J5I+dlhROVtqlMQn47BBcr
+l2GCkv9O1D1rL94KWYbY14HXhi/nacBAQtCEQwXxp5DKemGOUju65xM9F96/374G
+MvnRJdo52gOs4HO0czBpfVNdXeeoD/RYgwttfdJrz/4aatsS2Qk2yMYpqZmqEMsb
+rh9W22Lp3rCBvwIDAQABo1AwTjAdBgNVHQ4EFgQU523AJMR8Ds9V8fhf7gu1i0MM
+UqAwHwYDVR0jBBgwFoAU523AJMR8Ds9V8fhf7gu1i0MMUqAwDAYDVR0TBAUwAwEB
+/zANBgkqhkiG9w0BAQUFAAOBgQCI/tvSBYH1iyfLaCTBKwpdj36+MkR9EeJJmImx
+X+bjhKWXwsBX4PDMWvdusr++QGUYtyoya+hfYMXRhXua39mD54xgloQNuu9REDwX
+Ffto+aOw3BcYducz6ofxicFK/Y2VeXDurSMpRv5TfGf2Qr6eOOdaRhj6ed7BibHk
+X1VGZA==
+-----END CERTIFICATE-----
diff --git a/src/core/tsi/test_creds/badserver.key b/src/core/tsi/test_creds/badserver.key
new file mode 100644
index 0000000..abfbde1
--- /dev/null
+++ b/src/core/tsi/test_creds/badserver.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKeZ1e1y29cmBKaW
+oIUwJ5neOJUjx+eD/3nRPe+dvLXEd9+db0fG5RYRR0S3mF1Ywuj4PIxlTW2YprUS
+oGSw+tcqWNIzxv94HjwYFkkvER3AblXcDBh0P2zAkzg+nf9AcAsMh0QpDTyrXtMl
+gqryjq1/vkhFofKMMbY+aXJdG6OBAgMBAAECgYAAgaB51S0A22aMMkxN2rVj6530
+JWWHN4jgD1fGj41wZyWNkWYyq1Ep3ed/N6bIMWp1VbqpGe0/9YQba/D8HOTFHGRt
+72YXnP1e/ds8cxU4x4j1vvqSPtXpMmkiXfXijOvCl9mrMH2xjghFAt6/1Nb9xo1m
+VdcOB8OdSuOIw6CI+QJBAN5FZUbS+bRXDWII/FaAih1DBpwCxhYEN+TXPJBxSen6
+kOzGt5g+mB6YqRMZ/qshshwPq7bsgFGfJ2lIdS2t3GsCQQDBCKifV5AAkOdOUrkK
+HvoX3qnVmyIA8CyvWLcIWpfZ76QAYh0q0StedKdOMXaB1jTeSJ2KU1nlss7UD1Yw
+VbrDAkAwjMHpbW3jiVw//Kx5jIwehiRscWKpLnSzBJyTBFvbwsJjJai2lX2OuVO8
++2GYKb0Iyhd81j3VFkl6grwtpRtPAkB7+n+yt555fpfRKjhGU9b09cHGu7h/OcK5
+bBVCfE0DYHLI/DsXgPiF1g6Onh4rDdUu3xyv9xDKAqnscV099hHZAkEAvcFBfXZs
+tk18N+bUcvXTdZjzZbfLCHlJmwPIspZ8G/6Pn63deg4GVYoCvTwGruah+8y734Ph
+7PskfPgUQlB7Ag==
+-----END PRIVATE KEY-----
diff --git a/src/core/tsi/test_creds/badserver.pem b/src/core/tsi/test_creds/badserver.pem
new file mode 100644
index 0000000..983c979
--- /dev/null
+++ b/src/core/tsi/test_creds/badserver.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICoDCCAgmgAwIBAgIJAPdqwqsKNy81MA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQxIjAgBgNVBAMMGWJhZHNlcnZlci50ZXN0Lmdvb2dsZS5j
+b20wHhcNMTQwNzI4MjAwODU0WhcNMjQwNzI1MjAwODU0WjBpMQswCQYDVQQGEwJB
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMSIwIAYDVQQDDBliYWRzZXJ2ZXIudGVzdC5nb29nbGUuY29tMIGf
+MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnmdXtctvXJgSmlqCFMCeZ3jiVI8fn
+g/950T3vnby1xHffnW9HxuUWEUdEt5hdWMLo+DyMZU1tmKa1EqBksPrXKljSM8b/
+eB48GBZJLxEdwG5V3AwYdD9swJM4Pp3/QHALDIdEKQ08q17TJYKq8o6tf75IRaHy
+jDG2PmlyXRujgQIDAQABo1AwTjAdBgNVHQ4EFgQU3u/qvHr9knMBeZyAD7mAA/ec
+8cUwHwYDVR0jBBgwFoAU3u/qvHr9knMBeZyAD7mAA/ec8cUwDAYDVR0TBAUwAwEB
+/zANBgkqhkiG9w0BAQUFAAOBgQA/FmR1SGLguxCCfhp4CYCbrAePSyPWDi48gTwj
+vVZf/OMxdVu/H8sBYFf27BjbrEugAw16DElFtgTZ83pLb2BvkUgb6vBUK5sEkgmh
+z88zBsgDp8aCf4STDOLFZMBh/E9ZKkm1zogbEmlTjFp/ceSpa2gNv7OuN4WiorOh
+Wvw40g==
+-----END CERTIFICATE-----
diff --git a/src/core/tsi/test_creds/ca-openssl.cnf b/src/core/tsi/test_creds/ca-openssl.cnf
new file mode 100644
index 0000000..e97b945
--- /dev/null
+++ b/src/core/tsi/test_creds/ca-openssl.cnf
@@ -0,0 +1,17 @@
+[req]
+distinguished_name  = req_distinguished_name
+req_extensions = v3_req
+
+[req_distinguished_name]
+countryName           = Country Name (2 letter code)
+countryName_default = AU
+stateOrProvinceName   = State or Province Name (full name)
+stateOrProvinceName_default = Some-State
+organizationName          = Organization Name (eg, company)
+organizationName_default = Internet Widgits Pty Ltd
+commonName            = Common Name (eg, YOUR name)
+commonName_default = testca
+
+[v3_req]
+basicConstraints = CA:true
+keyUsage = critical, keyCertSign
diff --git a/src/core/tsi/test_creds/ca.key b/src/core/tsi/test_creds/ca.key
new file mode 100644
index 0000000..03c4f95
--- /dev/null
+++ b/src/core/tsi/test_creds/ca.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMBA3wVeTGHZR1Ry
+e/i+J8a2cu5gXwFV6TnObzGM7bLFCO5i9v4mLo4iFzPsHmWDUxKS3Y8iXbu0eYBl
+LoNY0lSvxDx33O+DuwMmVN+DzSD+Eod9zfvwOWHsazYCZT2PhNxnVWIuJXViY4JA
+HUGodjx+QAi6yCAurUZGvYXGgZSBAgMBAAECgYAxRi8i9BlFlufGSBVoGmydbJOm
+bwLKl9dP3o33ODSP9hok5y6A0w5plWk3AJSF1hPLleK9VcSKYGYnt0clmPVHF35g
+bx2rVK8dOT0mn7rz9Zr70jcSz1ETA2QonHZ+Y+niLmcic9At6hRtWiewblUmyFQm
+GwggIzi7LOyEUHrEcQJBAOXxyQvnLvtKzXiqcsW/K6rExqVJVk+KF0fzzVyMzTJx
+HRBxUVgvGdEJT7j+7P2kcTyafve0BBzDSPIaDyiJ+Y0CQQDWCb7jASFSbu5M3Zcd
+Gkr4ZKN1XO3VLQX10b22bQYdF45hrTN2tnzRvVUR4q86VVnXmiGiTqmLkXcA2WWf
+pHfFAkAhv9olUBo6MeF0i3frBEMRfm41hk0PwZHnMqZ6pgPcGnQMnMU2rzsXzkkQ
+OwJnvAIOxhJKovZTjmofdqmw5odlAkBYVUdRWjsNUTjJwj3GRf6gyq/nFMYWz3EB
+RWFdM1ttkDYzu45ctO2IhfHg4sPceDMO1s6AtKQmNI9/azkUjITdAkApNa9yFRzc
+TBaDNPd5KVd58LVIzoPQ6i7uMHteLXJUWqSroji6S3s4gKMFJ/dO+ZXIlgQgfJJJ
+ZDL4cdrdkeoM
+-----END PRIVATE KEY-----
diff --git a/src/core/tsi/test_creds/ca.pem b/src/core/tsi/test_creds/ca.pem
new file mode 100644
index 0000000..6c8511a
--- /dev/null
+++ b/src/core/tsi/test_creds/ca.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
+Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
+YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
+BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
++L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
+g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
+Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
+sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
+oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
+Dfcog5wrJytaQ6UA0wE=
+-----END CERTIFICATE-----
diff --git a/src/core/tsi/test_creds/client.key b/src/core/tsi/test_creds/client.key
new file mode 100644
index 0000000..f48d073
--- /dev/null
+++ b/src/core/tsi/test_creds/client.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAOxUR9uhvhbeVUIM
+s5WbH0px0mehl2+6sZpNjzvE2KimZpHzMJHukVH0Ffkvhs0b8+S5Ut9VNUAqd3IM
+JCCAEGtRNoQhM1t9Yr2zAckSvbRacp+FL/Cj9eDmyo00KsVGaeefA4Dh4OW+ZhkT
+NKcldXqkSuj1sEf244JZYuqZp6/tAgMBAAECgYEAi2NSVqpZMafE5YYUTcMGe6QS
+k2jtpsqYgggI2RnLJ/2tNZwYI5pwP8QVSbnMaiF4gokD5hGdrNDfTnb2v+yIwYEH
+0w8+oG7Z81KodsiZSIDJfTGsAZhVNwOz9y0VD8BBZZ1/274Zh52AUKLjZS/ZwIbS
+W2ywya855dPnH/wj+0ECQQD9X8D920kByTNHhBG18biAEZ4pxs9f0OAG8333eVcI
+w2lJDLsYDZrCB2ocgA3lUdozlzPC7YDYw8reg0tkiRY5AkEA7sdNzOeQsQRn7++5
+0bP9DtT/iON1gbfxRzCfCfXdoOtfQWIzTePWtURt9X/5D9NofI0Rg5W2oGy/MLe5
+/sXHVQJBAIup5XrJDkQywNZyAUU2ecn2bCWBFjwtqd+LBmuMciI9fOKsZtEKZrz/
+U0lkeMRoSwvXE8wmGLjjrAbdfohrXFkCQQDZEx/LtIl6JINJQiswVe0tWr6k+ASP
+1WXoTm+HYpoF/XUvv9LccNF1IazFj34hwRQwhx7w/V52Ieb+p0jUMYGxAkEAjDhd
+9pBO1fKXWiXzi9ZKfoyTNcUq3eBSVKwPG2nItg5ycXengjT5sgcWDnciIzW7BIVI
+JiqOszq9GWESErAatg==
+-----END PRIVATE KEY-----
diff --git a/src/core/tsi/test_creds/client.pem b/src/core/tsi/test_creds/client.pem
new file mode 100644
index 0000000..e332091
--- /dev/null
+++ b/src/core/tsi/test_creds/client.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICHzCCAYgCAQEwDQYJKoZIhvcNAQEFBQAwVjELMAkGA1UEBhMCQVUxEzARBgNV
+BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
+ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTE0MDcxNzIzNTYwMloXDTI0MDcxNDIzNTYw
+MlowWjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKdGVzdGNsaWVudDCB
+nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA7FRH26G+Ft5VQgyzlZsfSnHSZ6GX
+b7qxmk2PO8TYqKZmkfMwke6RUfQV+S+GzRvz5LlS31U1QCp3cgwkIIAQa1E2hCEz
+W31ivbMByRK9tFpyn4Uv8KP14ObKjTQqxUZp558DgOHg5b5mGRM0pyV1eqRK6PWw
+R/bjglli6pmnr+0CAwEAATANBgkqhkiG9w0BAQUFAAOBgQAStSm5PM7ubROiKK6/
+T2FkKlhiTOx+Ryenm3Eio59emq+jXl+1nhPySX5G2PQzSR5vd1dIhwgZSR4Gyttk
+tRZ57k/NI1brUW8joiEOMJA/Mr7H7asx7wIRYDE91Fs8GkKWd5LhoPAQj+qdG35C
+OO+svdkmqH0KZo320ZUqdl2ooQ==
+-----END CERTIFICATE-----
diff --git a/src/core/tsi/test_creds/server0.key b/src/core/tsi/test_creds/server0.key
new file mode 100644
index 0000000..add153c
--- /dev/null
+++ b/src/core/tsi/test_creds/server0.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANOmffupIGC8YDau
+rOF4eKnHwPszgpkkhWzKsVxhNDBxCVYx4TEjG0XWIO0iyRXupZbUC+7N/8HnEVNa
+8F1jYhng14Iiq99cNQbbnuHHhIztmpocrJTxmnhGzoAnRa1Tb+GnAuRoIHRA/V2c
+VUE9tbikQugFx/SPgXAw6tfWB+YvAgMBAAECgYEAoEq9qzUBgoHoVEGiSPiWWe8g
+5p6yUA1qx2QTQyWTAwT4z0DjjfVKmG99bFsl8+hTnJFnoCp/gnjflEOROwkjp5kG
+m0drqOPx1jeipJjpXYTBu49h+WpZ1PF+KhVtxsIm3OOCvh67iWaKyyOVb5Og8aiR
+jl6dn/TdG/dlGD8AfUECQQDuNMle6p0oU8amC6O9wIMBroxx2nFstzE6O35PLEzG
+/tj0kxxn9Jp2TS9mGaLCzSuXmpjlF4+NOWiBPkrLC2TfAkEA43Xg7uEUkaJAz2/W
+m1lIBTLt+4rIQY/2emh33bDcA+rv8rwwrMMIv17/xPx7bs49YqGG5xufD+Rwl6TL
+qFXYsQJAPrOwagax1aKvwJeBw3oAQhoTKAkLIEXcdGqipe6QSzVcIIz0xjxxyEAr
+AOIwoLxnBCISqwMXq2H4K0UdZPMb2wJAdhdYLY1L6YRMk6XjzImg25oidisKZweA
+FvMv8DgHMj2CUAqmVrt3SivfLH1M9C09L3zfFhOAFHcsgX58gav4MQJBANSBnrHj
+tIq4l8z79CPUIuu3QyeEh+XwY8s5qE5CNTck0U59lzp9NvENHbkx3KO896TTerko
++8bXHMLkJkHPXms=
+-----END PRIVATE KEY-----
diff --git a/src/core/tsi/test_creds/server0.pem b/src/core/tsi/test_creds/server0.pem
new file mode 100644
index 0000000..ade75d8
--- /dev/null
+++ b/src/core/tsi/test_creds/server0.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICHDCCAYUCAQQwDQYJKoZIhvcNAQEFBQAwVjELMAkGA1UEBhMCQVUxEzARBgNV
+BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
+ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTE0MDcyMjE3NTk0OVoXDTI0MDcxOTE3NTk0
+OVowVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxFDASBgNVBAoM
+C0dvb2dsZSBJbmMuMR0wGwYDVQQDDBQqLnRlc3QuZ29vZ2xlLmNvbS5hdTCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA06Z9+6kgYLxgNq6s4Xh4qcfA+zOCmSSF
+bMqxXGE0MHEJVjHhMSMbRdYg7SLJFe6lltQL7s3/wecRU1rwXWNiGeDXgiKr31w1
+Btue4ceEjO2amhyslPGaeEbOgCdFrVNv4acC5GggdED9XZxVQT21uKRC6AXH9I+B
+cDDq19YH5i8CAwEAATANBgkqhkiG9w0BAQUFAAOBgQBtfR5qXG9TTI8YcYh7sA4V
+GeNoplp0x6p7OG0NLvbJqAkUnkvjIkk1m1R2AUHhbkxzx6G75JIOoNJcWrCzywBA
+BIsaTdmnNysf/s1hQJuD3IHiVb+7Ji0jhttnJlYcMid4o0tJO/a2E9YUxR+9cg0i
+obb+Ql3qsvKdWBC1dDLDLw==
+-----END CERTIFICATE-----
diff --git a/src/core/tsi/test_creds/server1-openssl.cnf b/src/core/tsi/test_creds/server1-openssl.cnf
new file mode 100644
index 0000000..8a02108
--- /dev/null
+++ b/src/core/tsi/test_creds/server1-openssl.cnf
@@ -0,0 +1,26 @@
+[req]
+distinguished_name  = req_distinguished_name
+req_extensions     = v3_req
+
+[req_distinguished_name]
+countryName           = Country Name (2 letter code)
+countryName_default   = US
+stateOrProvinceName   = State or Province Name (full name)
+stateOrProvinceName_default = Illinois
+localityName          = Locality Name (eg, city)
+localityName_default  = Chicago
+organizationName          = Organization Name (eg, company)
+organizationName_default  = Example, Co.
+commonName            = Common Name (eg, YOUR name)
+commonName_max        = 64
+
+[v3_req]
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+subjectAltName = @alt_names
+
+[alt_names]
+DNS.1 = *.test.google.fr
+DNS.2 = waterzooi.test.google.be
+DNS.3 = *.test.youtube.com
+IP.1 = "192.168.1.3"
diff --git a/src/core/tsi/test_creds/server1.key b/src/core/tsi/test_creds/server1.key
new file mode 100644
index 0000000..143a5b8
--- /dev/null
+++ b/src/core/tsi/test_creds/server1.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
+M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
+3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
+AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
+V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
+tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
+dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
+K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
+81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
+DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
+aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
+ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
+XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
+F98XJ7tIFfJq
+-----END PRIVATE KEY-----
diff --git a/src/core/tsi/test_creds/server1.pem b/src/core/tsi/test_creds/server1.pem
new file mode 100644
index 0000000..8e582e5
--- /dev/null
+++ b/src/core/tsi/test_creds/server1.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5
+MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
+BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl
+c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs
+JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO
+RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30
+3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL
+BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6
+b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ
+KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS
+wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e
+aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s=
+-----END CERTIFICATE-----
diff --git a/src/core/tsi/transport_security.c b/src/core/tsi/transport_security.c
new file mode 100644
index 0000000..94252e3
--- /dev/null
+++ b/src/core/tsi/transport_security.c
@@ -0,0 +1,372 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/tsi/transport_security.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* --- Utils. --- */
+
+char* tsi_strdup(const char* src) {
+  char* dst;
+  uint32_t len;
+  if (!src) return NULL;
+  len = strlen(src) + 1;
+  dst = malloc(len);
+  if (!dst)  return NULL;
+  memcpy(dst, src, len);
+  return dst;
+}
+
+/* --- tsi_result common implementation. --- */
+
+const char* tsi_result_to_string(tsi_result result) {
+  switch (result) {
+    case TSI_OK:
+      return "TSI_OK";
+    case TSI_UNKNOWN_ERROR:
+      return "TSI_UNKNOWN_ERROR";
+    case TSI_INVALID_ARGUMENT:
+      return "TSI_INVALID_ARGUMENT";
+    case TSI_PERMISSION_DENIED:
+      return "TSI_PERMISSION_DENIED";
+    case TSI_INCOMPLETE_DATA:
+      return "TSI_INCOMPLETE_DATA";
+    case TSI_FAILED_PRECONDITION:
+      return "TSI_FAILED_PRECONDITION";
+    case TSI_UNIMPLEMENTED:
+      return "TSI_UNIMPLEMENTED";
+    case TSI_INTERNAL_ERROR:
+      return "TSI_INTERNAL_ERROR";
+    case TSI_DATA_CORRUPTED:
+      return "TSI_DATA_CORRUPTED";
+    case TSI_NOT_FOUND:
+      return "TSI_NOT_FOUND";
+    case TSI_PROTOCOL_FAILURE:
+      return "TSI_PROTOCOL_FAILURE";
+    case TSI_HANDSHAKE_IN_PROGRESS:
+      return "TSI_HANDSHAKE_IN_PROGRESS";
+    case TSI_OUT_OF_RESOURCES:
+      return "TSI_OUT_OF_RESOURCES";
+    default:
+      return "UNKNOWN";
+  }
+}
+
+
+/* --- tsi_frame_protector common implementation. ---
+
+   Calls specific implementation after state/input validation. */
+
+tsi_result tsi_frame_protector_protect(
+    tsi_frame_protector* self,
+    const unsigned char* unprotected_bytes,
+    uint32_t* unprotected_bytes_size,
+    unsigned char* protected_output_frames,
+    uint32_t* protected_output_frames_size) {
+  if (self == NULL || unprotected_bytes == NULL ||
+      unprotected_bytes_size == NULL || protected_output_frames == NULL ||
+      protected_output_frames_size == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  return self->vtable->protect(self, unprotected_bytes, unprotected_bytes_size,
+                               protected_output_frames,
+                               protected_output_frames_size);
+}
+
+tsi_result tsi_frame_protector_protect_flush(
+    tsi_frame_protector* self,
+    unsigned char* protected_output_frames,
+    uint32_t* protected_output_frames_size,
+    uint32_t* still_pending_size) {
+  if (self == NULL || protected_output_frames == NULL ||
+      protected_output_frames == NULL || still_pending_size == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  return self->vtable->protect_flush(self, protected_output_frames,
+                                     protected_output_frames_size,
+                                     still_pending_size);
+}
+
+tsi_result tsi_frame_protector_unprotect(
+    tsi_frame_protector* self,
+    const unsigned char* protected_frames_bytes,
+    uint32_t* protected_frames_bytes_size,
+    unsigned char* unprotected_bytes,
+    uint32_t* unprotected_bytes_size) {
+  if (self == NULL || protected_frames_bytes == NULL ||
+      protected_frames_bytes_size == NULL || unprotected_bytes == NULL ||
+      unprotected_bytes_size == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  return self->vtable->unprotect(self, protected_frames_bytes,
+                                 protected_frames_bytes_size, unprotected_bytes,
+                                 unprotected_bytes_size);
+}
+
+void tsi_frame_protector_destroy(tsi_frame_protector* self) {
+  if (self == NULL) return;
+  self->vtable->destroy(self);
+}
+
+
+/* --- tsi_handshaker common implementation. ---
+
+   Calls specific implementation after state/input validation. */
+
+tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self,
+                                                    unsigned char* bytes,
+                                                    uint32_t* bytes_size) {
+  if (self == NULL) return TSI_INVALID_ARGUMENT;
+  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
+  return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size);
+}
+
+
+tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker* self,
+                                                  const unsigned char* bytes,
+                                                  uint32_t* bytes_size) {
+  if (self == NULL) return TSI_INVALID_ARGUMENT;
+  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
+  return self->vtable->process_bytes_from_peer(self, bytes, bytes_size);
+}
+
+tsi_result tsi_handshaker_get_result(tsi_handshaker* self) {
+  if (self == NULL) return TSI_INVALID_ARGUMENT;
+  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
+  return self->vtable->get_result(self);
+}
+
+tsi_result tsi_handshaker_extract_peer(tsi_handshaker* self, tsi_peer* peer) {
+  if (self == NULL || peer == NULL) return TSI_INVALID_ARGUMENT;
+  memset(peer, 0, sizeof(tsi_peer));
+  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
+  if (tsi_handshaker_get_result(self) != TSI_OK) {
+    return TSI_FAILED_PRECONDITION;
+  }
+  return self->vtable->extract_peer(self, peer);
+}
+
+tsi_result tsi_handshaker_create_frame_protector(
+    tsi_handshaker* self,
+    uint32_t* max_protected_frame_size,
+    tsi_frame_protector** protector) {
+  tsi_result result;
+  if (self == NULL || protector == NULL) return TSI_INVALID_ARGUMENT;
+  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
+  if (tsi_handshaker_get_result(self) != TSI_OK) {
+    return TSI_FAILED_PRECONDITION;
+  }
+  result = self->vtable->create_frame_protector(self, max_protected_frame_size,
+                                                protector);
+  if (result == TSI_OK) {
+    self->frame_protector_created = 1;
+  }
+  return result;
+}
+
+void tsi_handshaker_destroy(tsi_handshaker* self) {
+  if (self == NULL) return;
+  self->vtable->destroy(self);
+}
+
+
+/* --- tsi_peer implementation. --- */
+
+const tsi_peer_property* tsi_peer_get_property_by_name(const tsi_peer* self,
+                                                       const char* name) {
+  uint32_t i;
+  if (self == NULL) return NULL;
+  for (i = 0; i < self->property_count; i++) {
+    const tsi_peer_property* property = &self->properties[i];
+    if (name == NULL && property->name == NULL) {
+      return property;
+    }
+    if (name != NULL && property->name != NULL &&
+        !strcmp(property->name, name)) {
+      return property;
+    }
+  }
+  return NULL;
+}
+
+tsi_peer_property tsi_init_peer_property(void) {
+  tsi_peer_property property;
+  memset(&property, 0, sizeof(tsi_peer_property));
+  return property;
+}
+
+
+static void tsi_peer_destroy_list_property(tsi_peer_property* children,
+                                           uint32_t child_count) {
+  uint32_t i;
+  for (i = 0; i < child_count; i++) {
+    tsi_peer_property_destruct(&children[i]);
+  }
+  free(children);
+}
+
+void tsi_peer_property_destruct(tsi_peer_property* property) {
+  if (property->name != NULL) {
+    free(property->name);
+  }
+  switch (property->type) {
+    case TSI_PEER_PROPERTY_TYPE_STRING:
+      if (property->value.string.data != NULL) {
+        free(property->value.string.data);
+      }
+      break;
+    case TSI_PEER_PROPERTY_TYPE_LIST:
+      tsi_peer_destroy_list_property(property->value.list.children,
+                                     property->value.list.child_count);
+    default:
+      /* Nothing to free. */
+      break;
+  }
+  *property = tsi_init_peer_property();  /* Reset everything to 0. */
+}
+
+void tsi_peer_destruct(tsi_peer* self) {
+  if (self == NULL) return;
+  if (self->properties != NULL) {
+    tsi_peer_destroy_list_property(self->properties, self->property_count);
+    self->properties = NULL;
+  }
+  self->property_count = 0;
+}
+
+tsi_result tsi_construct_signed_integer_peer_property(
+    const char* name, int64_t value, tsi_peer_property* property) {
+  *property = tsi_init_peer_property();
+  property->type = TSI_PEER_PROPERTY_TYPE_SIGNED_INTEGER;
+  if (name != NULL) {
+    property->name = tsi_strdup(name);
+    if (property->name == NULL) return TSI_OUT_OF_RESOURCES;
+  }
+  property->value.signed_int = value;
+  return TSI_OK;
+}
+
+tsi_result tsi_construct_unsigned_integer_peer_property(
+    const char* name, uint64_t value, tsi_peer_property* property) {
+  *property = tsi_init_peer_property();
+  property->type = TSI_PEER_PROPERTY_TYPE_UNSIGNED_INTEGER;
+  if (name != NULL) {
+    property->name = tsi_strdup(name);
+    if (property->name == NULL) return TSI_OUT_OF_RESOURCES;
+  }
+  property->value.unsigned_int = value;
+  return TSI_OK;
+}
+
+tsi_result tsi_construct_real_peer_property(const char* name, double value,
+                                            tsi_peer_property* property) {
+  *property = tsi_init_peer_property();
+  property->type = TSI_PEER_PROPERTY_TYPE_REAL;
+  if (name != NULL) {
+    property->name = tsi_strdup(name);
+    if (property->name == NULL) return TSI_OUT_OF_RESOURCES;
+  }
+  property->value.real = value;
+  return TSI_OK;
+}
+
+tsi_result tsi_construct_allocated_string_peer_property(
+    const char* name, uint32_t value_length, tsi_peer_property* property) {
+  *property = tsi_init_peer_property();
+  property->type = TSI_PEER_PROPERTY_TYPE_STRING;
+  if (name != NULL) {
+    property->name = tsi_strdup(name);
+    if (property->name == NULL) return TSI_OUT_OF_RESOURCES;
+  }
+  if (value_length > 0) {
+    property->value.string.data = calloc(1, value_length);
+    if (property->value.string.data == NULL) {
+      tsi_peer_property_destruct(property);
+      return TSI_OUT_OF_RESOURCES;
+    }
+    property->value.string.length = value_length;
+  }
+  return TSI_OK;
+}
+
+tsi_result tsi_construct_string_peer_property_from_cstring(
+    const char* name, const char* value, tsi_peer_property* property) {
+  return tsi_construct_string_peer_property(name, value, strlen(value),
+                                            property);
+}
+
+tsi_result tsi_construct_string_peer_property(const char* name,
+                                              const char* value,
+                                              uint32_t value_length,
+                                              tsi_peer_property* property) {
+  tsi_result result = tsi_construct_allocated_string_peer_property(
+      name, value_length, property);
+  if (result != TSI_OK) return result;
+  if (value_length > 0) {
+    memcpy(property->value.string.data, value, value_length);
+  }
+  return TSI_OK;
+}
+
+tsi_result tsi_construct_list_peer_property(const char* name,
+                                            uint32_t child_count,
+                                            tsi_peer_property* property) {
+  *property = tsi_init_peer_property();
+  property->type = TSI_PEER_PROPERTY_TYPE_LIST;
+  if (name != NULL) {
+    property->name = tsi_strdup(name);
+    if (property->name == NULL) return TSI_OUT_OF_RESOURCES;
+  }
+  if (child_count > 0) {
+    property->value.list.children =
+        calloc(child_count, sizeof(tsi_peer_property));
+    if (property->value.list.children == NULL) {
+      tsi_peer_property_destruct(property);
+      return TSI_OUT_OF_RESOURCES;
+    }
+    property->value.list.child_count = child_count;
+  }
+  return TSI_OK;
+}
+
+tsi_result tsi_construct_peer(uint32_t property_count, tsi_peer* peer) {
+  memset(peer, 0, sizeof(tsi_peer));
+  if (property_count > 0) {
+    peer->properties = calloc(property_count, sizeof(tsi_peer_property));
+    if (peer->properties == NULL) return TSI_OUT_OF_RESOURCES;
+    peer->property_count = property_count;
+  }
+  return TSI_OK;
+}
diff --git a/src/core/tsi/transport_security.h b/src/core/tsi/transport_security.h
new file mode 100644
index 0000000..cf9a2b0
--- /dev/null
+++ b/src/core/tsi/transport_security.h
@@ -0,0 +1,118 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TRANSPORT_SECURITY_H_
+#define __TRANSPORT_SECURITY_H_
+
+#include "src/core/tsi/transport_security_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Base for tsi_frame_protector implementations.
+   See transport_security_interface.h for documentation. */
+typedef struct {
+  tsi_result (*protect)(tsi_frame_protector* self,
+                        const unsigned char* unprotected_bytes,
+                        uint32_t* unprotected_bytes_size,
+                        unsigned char* protected_output_frames,
+                        uint32_t* protected_output_frames_size);
+  tsi_result (*protect_flush)(tsi_frame_protector* self,
+                              unsigned char* protected_output_frames,
+                              uint32_t* protected_output_frames_size,
+                              uint32_t* still_pending_size);
+  tsi_result (*unprotect)(tsi_frame_protector* self,
+                          const unsigned char* protected_frames_bytes,
+                          uint32_t* protected_frames_bytes_size,
+                          unsigned char* unprotected_bytes,
+                          uint32_t* unprotected_bytes_size);
+  void (*destroy)(tsi_frame_protector* self);
+} tsi_frame_protector_vtable;
+
+struct tsi_frame_protector {
+  const tsi_frame_protector_vtable* vtable;
+};
+
+/* Base for tsi_handshaker implementations.
+   See transport_security_interface.h for documentation. */
+typedef struct {
+  tsi_result (*get_bytes_to_send_to_peer)(tsi_handshaker* self,
+                                          unsigned char* bytes,
+                                          uint32_t* bytes_size);
+  tsi_result (*process_bytes_from_peer)(tsi_handshaker* self,
+                                        const unsigned char* bytes,
+                                        uint32_t* bytes_size);
+  tsi_result (*get_result)(tsi_handshaker* self);
+  tsi_result (*extract_peer)(tsi_handshaker* self, tsi_peer* peer);
+  tsi_result (*create_frame_protector)(tsi_handshaker* self,
+                                       uint32_t* max_protected_frame_size,
+                                       tsi_frame_protector** protector);
+  void (*destroy)(tsi_handshaker* self);
+} tsi_handshaker_vtable;
+
+struct tsi_handshaker {
+  const tsi_handshaker_vtable* vtable;
+  int frame_protector_created;
+};
+
+/* Peer and property construction/destruction functions. */
+tsi_result tsi_construct_peer(uint32_t property_count, tsi_peer* peer);
+tsi_peer_property tsi_init_peer_property(void);
+void tsi_peer_property_destruct(tsi_peer_property* property);
+tsi_result tsi_construct_signed_integer_peer_property(
+    const char* name, int64_t value, tsi_peer_property* property);
+tsi_result tsi_construct_unsigned_integer_peer_property(
+    const char* name, uint64_t value, tsi_peer_property* property);
+tsi_result tsi_construct_real_peer_property(const char* name, double value,
+                                            tsi_peer_property* property);
+tsi_result tsi_construct_string_peer_property(const char* name,
+                                              const char* value,
+                                              uint32_t value_length,
+                                              tsi_peer_property* property);
+tsi_result tsi_construct_allocated_string_peer_property(
+    const char* name, uint32_t value_length, tsi_peer_property* property);
+tsi_result tsi_construct_string_peer_property_from_cstring(
+    const char* name, const char* value, tsi_peer_property* property);
+tsi_result tsi_construct_list_peer_property(const char* name,
+                                            uint32_t child_count,
+                                            tsi_peer_property* property);
+
+/* Utils. */
+char* tsi_strdup(const char* src);  /* Sadly, no strdup in C89. */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __TRANSPORT_SECURITY_H_ */
diff --git a/src/core/tsi/transport_security_interface.h b/src/core/tsi/transport_security_interface.h
new file mode 100644
index 0000000..6be72c7
--- /dev/null
+++ b/src/core/tsi/transport_security_interface.h
@@ -0,0 +1,389 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TRANSPORT_SECURITY_INTERFACE_H_
+#define __TRANSPORT_SECURITY_INTERFACE_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* --- tsi result ---  */
+
+typedef enum {
+  TSI_OK = 0,
+  TSI_UNKNOWN_ERROR = 1,
+  TSI_INVALID_ARGUMENT = 2,
+  TSI_PERMISSION_DENIED = 3,
+  TSI_INCOMPLETE_DATA = 4,
+  TSI_FAILED_PRECONDITION = 5,
+  TSI_UNIMPLEMENTED = 6,
+  TSI_INTERNAL_ERROR = 7,
+  TSI_DATA_CORRUPTED = 8,
+  TSI_NOT_FOUND = 9,
+  TSI_PROTOCOL_FAILURE = 10,
+  TSI_HANDSHAKE_IN_PROGRESS = 11,
+  TSI_OUT_OF_RESOURCES = 12
+} tsi_result;
+
+const char* tsi_result_to_string(tsi_result result);
+
+
+/* --- tsi_frame_protector object ---
+
+  This object protects and unprotects buffers once the handshake is done.
+  Implementations of this object must be thread compatible.  */
+
+typedef struct tsi_frame_protector tsi_frame_protector;
+
+/* Outputs protected frames.
+   - unprotected_bytes is an input only parameter and points to the data
+     to be protected.
+   - unprotected_bytes_size is an input/output parameter used by the caller to
+     specify how many bytes are available in unprotected_bytes. The output
+     value is the number of bytes consumed during the call.
+   - protected_output_frames points to a buffer allocated by the caller that
+     will be written.
+   - protected_output_frames_size is an input/output parameter used by the
+     caller to specify how many bytes are available in protected_output_frames.
+     As an output, this value indicates the number of bytes written.
+   - This method returns TSI_OK in case of success or a specific error code in
+     case of failure. Note that even if all the input unprotected bytes are
+     consumed, they may not have been processed into the returned protected
+     output frames. The caller should call the protect_flush method
+     to make sure that there are no more protected bytes buffered in the
+     protector.
+
+   A typical way to call this method would be:
+
+   ------------------------------------------------------------------------
+   unsigned char protected_buffer[4096];
+   uint32_t protected_buffer_size = sizeof(protected_buffer);
+   tsi_result result = TSI_OK;
+   while (message_size > 0) {
+     uint32_t protected_buffer_size_to_send = protected_buffer_size;
+     uint32_t processed_message_size = message_size;
+     result = tsi_frame_protector_protect(protector,
+                                          message_bytes,
+                                          &processed_message_size,
+                                          protected_buffer,
+                                          &protected_buffer_size_to_send);
+     if (result != TSI_OK) break;
+     send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send);
+     message_bytes += processed_message_size;
+     message_size -= processed_message_size;
+
+     // Don't forget to flush.
+     if (message_size == 0) {
+       uint32_t still_pending_size;
+       do {
+         protected_buffer_size_to_send = protected_buffer_size;
+         result = tsi_frame_protector_protect_flush(
+             protector, protected_buffer,
+             &protected_buffer_size_to_send, &still_pending_size);
+         if (result != TSI_OK) break;
+         send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send);
+       } while (still_pending_size > 0);
+     }
+   }
+
+   if (result != TSI_OK) HandleError(result);
+   ------------------------------------------------------------------------  */
+tsi_result tsi_frame_protector_protect(
+    tsi_frame_protector* self,
+    const unsigned char* unprotected_bytes,
+    uint32_t* unprotected_bytes_size,
+    unsigned char* protected_output_frames,
+    uint32_t* protected_output_frames_size);
+
+/* Indicates that we need to flush the bytes buffered in the protector and get
+   the resulting frame.
+   - protected_output_frames points to a buffer allocated by the caller that
+     will be written.
+   - protected_output_frames_size is an input/output parameter used by the
+     caller to specify how many bytes are available in protected_output_frames.
+   - still_pending_bytes is an output parameter indicating the number of bytes
+     that still need to be flushed from the protector.*/
+tsi_result tsi_frame_protector_protect_flush(
+    tsi_frame_protector* self,
+    unsigned char* protected_output_frames,
+    uint32_t* protected_output_frames_size,
+    uint32_t* still_pending_size);
+
+/* Outputs unprotected bytes.
+   - protected_frames_bytes is an input only parameter and points to the
+     protected frames to be unprotected.
+   - protected_frames_bytes_size is an input/output only parameter used by the
+     caller to specify how many bytes are available in protected_bytes. The
+     output value is the number of bytes consumed during the call.
+     Implementations will buffer up to a frame of protected data.
+   - unprotected_bytes points to a buffer allocated by the caller that will be
+     written.
+   - unprotected_bytes_size is an input/output parameter used by the caller to
+     specify how many bytes are available in unprotected_bytes. This
+     value is expected to be at most max_protected_frame_size minus overhead
+     which means that max_protected_frame_size is a safe bet. The output value
+     is the number of bytes actually written.
+
+   - This method returns TSI_OK in case of success. Success includes cases where
+     there is not enough data to output a frame in which case
+     unprotected_bytes_size will be set to 0 and cases where the internal buffer
+     needs to be read before new protected data can be processed in which case
+     protected_frames_size will be set to 0.  */
+tsi_result tsi_frame_protector_unprotect(
+    tsi_frame_protector* self,
+    const unsigned char* protected_frames_bytes,
+    uint32_t* protected_frames_bytes_size,
+    unsigned char* unprotected_bytes,
+    uint32_t* unprotected_bytes_size);
+
+/* Destroys the tsi_frame_protector object.  */
+void tsi_frame_protector_destroy(tsi_frame_protector* self);
+
+
+/* --- tsi_peer objects ---
+
+   tsi_peer objects are a set of properties. The peer owns the properties.  */
+
+/* This property is of type TSI_PEER_PROPERTY_STRING.  */
+#define TSI_CERTIFICATE_TYPE_PEER_PROPERTY "certificate_type"
+
+/* This property is of type TSI_PEER_PROPERTY_STRING.  */
+#define TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY "x509_subject_common_name"
+
+/* This property is of type TSI_PEER_PROPERTY_LIST and the children contain
+   unnamed (name == NULL) properties of type TSI_PEER_PROPERTY_STRING.  */
+#define TSI_X509_SUBJECT_ALTERNATIVE_NAMES_PEER_PROPERTY \
+  "x509_subject_alternative_names"
+
+/* This property is of type TSI_PEER_PROPERTY_STRING. */
+#define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol"
+
+/* This property is of type TSI_PEER_PROPERTY_STRING.  */
+#define TSI_MDB_USER_NAME_PEER_PROPERTY "mdb_user_name"
+
+/* This property is of type TSI_PEER_PROPERTY_SIGNED_INTEGER.  */
+#define TSI_MDB_GAIA_ID_PEER_PROPERTY "mdb_gaia_id"
+
+/* Properties of type TSI_PEER_PROPERTY_TYPE_STRING may contain NULL characters
+   just like C++ strings. The length field gives the length of the string.  */
+typedef enum {
+  TSI_PEER_PROPERTY_TYPE_SIGNED_INTEGER,
+  TSI_PEER_PROPERTY_TYPE_UNSIGNED_INTEGER,
+  TSI_PEER_PROPERTY_TYPE_REAL,
+  TSI_PEER_PROPERTY_TYPE_STRING,
+  TSI_PEER_PROPERTY_TYPE_LIST
+} tsi_peer_property_type;
+
+/* The relevant field in the union value is dictated by the type field.
+   name may be NULL in case of an unnamed property. */
+typedef struct tsi_peer_property {
+  char* name;
+  tsi_peer_property_type type;
+  union {
+    int64_t signed_int;
+    uint64_t unsigned_int;
+    double real;
+    struct {
+      char* data;
+      uint32_t length;
+    } string;
+    struct {
+      struct tsi_peer_property* children;
+      uint32_t child_count;
+    } list;
+  } value;
+} tsi_peer_property;
+
+typedef struct {
+  tsi_peer_property* properties;
+  uint32_t property_count;
+} tsi_peer;
+
+/* Gets the first property with the specified name. Iteration over the
+   properties of the peer should be used if the client of the API is expecting
+   several properties with the same name.
+   Returns NULL if there is no corresponding property.  */
+const tsi_peer_property* tsi_peer_get_property_by_name(const tsi_peer* self,
+                                                       const char* name);
+
+/* Destructs the tsi_peer object. */
+void tsi_peer_destruct(tsi_peer* self);
+
+/* --- tsi_handshaker objects ----
+
+   Implementations of this object must be thread compatible.
+
+   A typical usage of this object would be:
+
+   ------------------------------------------------------------------------
+   tsi_result result = TSI_OK;
+   unsigned char buf[4096];
+   uint32_t buf_offset;
+   uint32_t buf_size;
+   while (1) {
+     // See if we need to send some bytes to the peer.
+     do {
+       uint32_t buf_size_to_send = sizeof(buf);
+       result = tsi_handshaker_get_bytes_to_send_to_peer(handshaker, buf,
+                                                         &buf_size_to_send);
+       if (buf_size_to_send > 0) send_bytes_to_peer(buf, buf_size_to_send);
+     } while (result == TSI_INCOMPLETE_DATA);
+     if (result != TSI_OK) return result;
+     if (!tsi_handshaker_is_in_progress(handshaker)) break;
+
+     do {
+       // Read bytes from the peer.
+       buf_size = sizeof(buf);
+       buf_offset = 0;
+       read_bytes_from_peer(buf, &buf_size);
+       if (buf_size == 0) break;
+
+       // Process the bytes from the peer. We have to be careful as these bytes
+       // may contain non-handshake data (protected data). If this is the case,
+       // we will exit from the loop with buf_size > 0.
+       uint32_t consumed_by_handshaker = buf_size;
+       result = tsi_handshaker_process_bytes_from_peer(
+           handshaker, buf, &consumed_by_handshaker);
+       buf_size -= consumed_by_handshaker;
+       buf_offset += consumed_by_handshaker;
+     } while (result == TSI_INCOMPLETE_DATA);
+
+     if (result != TSI_OK) return result;
+     if (!tsi_handshaker_is_in_progress(handshaker)) break;
+   }
+
+   // Check the Peer.
+   tsi_peer peer;
+   do {
+     result = tsi_handshaker_extract_peer(handshaker, &peer);
+     if (result != TSI_OK) break;
+     result = check_peer(&peer);
+   } while (0);
+   tsi_peer_destruct(&peer);
+   if (result != TSI_OK) return result;
+
+   // Create the protector.
+   tsi_frame_protector* protector = NULL;
+   result = tsi_handshaker_create_frame_protector(handshaker, NULL,
+                                                  &protector);
+   if (result != TSI_OK) return result;
+
+   // Do not forget to unprotect outstanding data if any.
+   if (buf_size > 0) {
+     result = tsi_frame_protector_unprotect(protector, buf + buf_offset,
+                                            buf_size, ..., ...);
+     ....
+   }
+   ...
+   ------------------------------------------------------------------------   */
+typedef struct tsi_handshaker tsi_handshaker;
+
+/* Gets bytes that need to be sent to the peer.
+   - bytes is the buffer that will be written with the data to be sent to the
+     peer.
+   - bytes_size is an input/output parameter specifying the capacity of the
+     bytes parameter as input and the number of bytes written as output.
+   Returns TSI_OK if all the data to send to the peer has been written or if
+   nothing has to be sent to the peer (in which base bytes_size outputs to 0),
+   otherwise returns TSI_INCOMPLETE_DATA which indicates that this method
+   needs to be called again to get all the bytes to send to the peer (there
+   was more data to write than the specified bytes_size). In case of a fatal
+   error in the handshake, another specific error code is returned.  */
+tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self,
+                                                    unsigned char* bytes,
+                                                    uint32_t* bytes_size);
+
+/* Processes bytes received from the peer.
+   - bytes is the buffer containing the data.
+   - bytes_size is an input/output parameter specifying the size of the data as
+     input and the number of bytes consumed as output.
+   Return TSI_OK if the handshake has all the data it needs to process,
+   otherwise return TSI_INCOMPLETE_DATA which indicates that this method
+   needs to be called again to complete the data needed for processing. In
+   case of a fatal error in the handshake, another specific error code is
+   returned.  */
+tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker* self,
+                                                  const unsigned char* bytes,
+                                                  uint32_t* bytes_size);
+
+/* Gets the result of the handshaker.
+   Returns TSI_OK if the hanshake completed successfully and there has been no
+   errors. Returns TSI_HANDSHAKE_IN_PROGRESS if the handshaker is not done yet
+   but no error has been encountered so far. Otherwise the handshaker failed
+   with the returned error.  */
+tsi_result tsi_handshaker_get_result(tsi_handshaker* self);
+
+/* Returns 1 if the handshake is in progress, 0 otherwise.  */
+#define tsi_handshaker_is_in_progress(h) \
+  (tsi_handshaker_get_result((h)) == TSI_HANDSHAKE_IN_PROGRESS)
+
+
+/* This method may return TSI_FAILED_PRECONDITION if
+   tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise
+   assuming the handshaker is not in a fatal error state.
+   The caller is responsible for destructing the peer.  */
+tsi_result tsi_handshaker_extract_peer(tsi_handshaker* self, tsi_peer* peer);
+
+/* This method creates a tsi_frame_protector object after the handshake phase
+   is done. After this method has been called successfully, the only method
+   that can be called on this object is Destroy.
+   - max_output_protected_frame_size is an input/output parameter specifying the
+     desired max output protected frame size as input and outputing the actual
+     max output frame size as the output. Passing NULL is OK and will result in
+     the implementation choosing the default maximum protected frame size. Note
+     that this size only applies to outgoing frames (generated with
+     tsi_frame_protector_protect) and not incoming frames (input of
+     tsi_frame_protector_unprotect).
+   - protector is an output parameter pointing to the newly created
+     tsi_frame_protector object.
+   This method may return TSI_FAILED_PRECONDITION if
+   tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise assuming
+   the handshaker is not in a fatal error state.
+   The caller is responsible for destroying the protector.  */
+tsi_result tsi_handshaker_create_frame_protector(
+    tsi_handshaker* self,
+    uint32_t* max_output_protected_frame_size,
+    tsi_frame_protector** protector);
+
+/* This method releases the tsi_handshaker object. After this method is called,
+   no other method can be called on the object.  */
+void tsi_handshaker_destroy(tsi_handshaker* self);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __TRANSPORT_SECURITY_INTERFACE_H_ */
diff --git a/src/core/tsi/transport_security_test_lib.cc b/src/core/tsi/transport_security_test_lib.cc
new file mode 100644
index 0000000..1b630c9
--- /dev/null
+++ b/src/core/tsi/transport_security_test_lib.cc
@@ -0,0 +1,363 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/tsi/transport_security_test_lib.h"
+
+#include <memory>
+
+#include "base/commandlineflags.h"
+#include "src/core/tsi/transport_security_interface.h"
+#include "strings/escaping.h"
+#include "strings/strcat.h"
+#include <gtest/gtest.h>
+#include "util/random/mt_random.h"
+
+namespace {
+
+const char kPingRequest[] = "Ping";
+const char kPongResponse[] = "Pong";
+const int kBigMessageSize = 17000;
+
+}  // namespace
+
+namespace tsi {
+namespace test {
+
+TransportSecurityTest::TransportSecurityTest() : random_(new MTRandom()) {
+  small_message_ = "Chapi Chapo";
+  big_message_ = RandomString(kBigMessageSize);
+}
+
+string TransportSecurityTest::RandomString(int size) {
+  std::unique_ptr<char[]> buffer(new char[size]);
+  for (int i = 0; i < size; i++) {
+    buffer[i] = random_->Rand8();
+  }
+  return string(buffer.get(), size);
+}
+
+void TransportSecurityTest::SendBytesToPeer(bool is_client, unsigned char* buf,
+                                            unsigned int buf_size) {
+  string& channel = is_client ? to_server_channel_ : to_client_channel_;
+  LOG(INFO) << (is_client ? "Client:" : "Server") << " sending " << buf_size
+            << " bytes to peer.";
+  channel.append(reinterpret_cast<const char*>(buf), buf_size);
+}
+
+void TransportSecurityTest::ReadBytesFromPeer(bool is_client,
+                                              unsigned char* buf,
+                                              unsigned int* buf_size) {
+  string& channel = is_client ? to_client_channel_ : to_server_channel_;
+  unsigned int to_read =
+      *buf_size < channel.size() ? *buf_size : channel.size();
+  memcpy(buf, channel.data(), to_read);
+  *buf_size = to_read;
+  channel.erase(0, to_read);
+  LOG(INFO) << (is_client ? "Client:" : "Server") << " read " << to_read
+            << " bytes from peer.";
+}
+
+void TransportSecurityTest::DoHandshakeStep(bool is_client,
+                                            unsigned int buf_allocated_size,
+                                            tsi_handshaker* handshaker,
+                                            string* remaining_bytes) {
+  tsi_result result = TSI_OK;
+  std::unique_ptr<unsigned char[]> buf(new unsigned char[buf_allocated_size]);
+  unsigned int buf_offset;
+  unsigned int buf_size;
+  // See if we need to send some bytes to the peer.
+  do {
+    unsigned int buf_size_to_send = buf_allocated_size;
+    result = tsi_handshaker_get_bytes_to_send_to_peer(handshaker, buf.get(),
+                                                      &buf_size_to_send);
+    if (buf_size_to_send > 0) {
+      SendBytesToPeer(is_client, buf.get(), buf_size_to_send);
+    }
+  } while (result == TSI_INCOMPLETE_DATA);
+  if (!tsi_handshaker_is_in_progress(handshaker)) return;
+
+  do {
+    //  Read bytes from the peer.
+    buf_size = buf_allocated_size;
+    buf_offset = 0;
+    ReadBytesFromPeer(is_client, buf.get(), &buf_size);
+    if (buf_size == 0) break;
+
+    // Process the bytes from the peer. We have to be careful as these bytes
+    // may contain non-handshake data (protected data). If this is the case,
+    // we will exit from the loop with buf_size > 0.
+    unsigned int consumed_by_handshaker = buf_size;
+    result = tsi_handshaker_process_bytes_from_peer(handshaker, buf.get(),
+                                                    &consumed_by_handshaker);
+    buf_size -= consumed_by_handshaker;
+    buf_offset += consumed_by_handshaker;
+  } while (result == TSI_INCOMPLETE_DATA);
+
+  if (!tsi_handshaker_is_in_progress(handshaker)) {
+    remaining_bytes->assign(
+        reinterpret_cast<const char*>(buf.get()) + buf_offset, buf_size);
+  }
+}
+
+void TransportSecurityTest::PerformHandshake() {
+  SetupHandshakers();
+  string remaining_bytes;
+  do {
+    DoHandshakeStep(true, config()->handshake_buffer_size,
+                    client_handshaker_.get(), &remaining_bytes);
+    EXPECT_EQ(0, remaining_bytes.size());
+    DoHandshakeStep(false, config()->handshake_buffer_size,
+                    server_handshaker_.get(), &remaining_bytes);
+    EXPECT_EQ(0, remaining_bytes.size());
+  } while (tsi_handshaker_is_in_progress(client_handshaker_.get()) ||
+           tsi_handshaker_is_in_progress(server_handshaker_.get()));
+  CheckHandshakeResults();
+}
+
+void TransportSecurityTest::SendMessageToPeer(
+    bool is_client, tsi_frame_protector* protector, const string& message,
+    unsigned int protected_buffer_size) {
+  std::unique_ptr<unsigned char[]> protected_buffer(
+      new unsigned char[protected_buffer_size]);
+  unsigned int message_size = message.size();
+  const unsigned char* message_bytes =
+      reinterpret_cast<const unsigned char*>(message.data());
+  tsi_result result = TSI_OK;
+  while (message_size > 0 && result == TSI_OK) {
+    unsigned int protected_buffer_size_to_send = protected_buffer_size;
+    unsigned int processed_message_size = message_size;
+    result = tsi_frame_protector_protect(
+        protector, message_bytes, &processed_message_size,
+        protected_buffer.get(), &protected_buffer_size_to_send);
+    EXPECT_EQ(TSI_OK, result);
+    SendBytesToPeer(is_client, protected_buffer.get(),
+                    protected_buffer_size_to_send);
+    message_bytes += processed_message_size;
+    message_size -= processed_message_size;
+
+    // Flush if we're done.
+    if (message_size == 0) {
+      unsigned int still_pending_size;
+      do {
+        protected_buffer_size_to_send = protected_buffer_size;
+        result = tsi_frame_protector_protect_flush(
+            protector, protected_buffer.get(), &protected_buffer_size_to_send,
+            &still_pending_size);
+        EXPECT_EQ(TSI_OK, result);
+        SendBytesToPeer(is_client, protected_buffer.get(),
+                        protected_buffer_size_to_send);
+      } while (still_pending_size > 0 && result == TSI_OK);
+      EXPECT_EQ(TSI_OK, result);
+    }
+  }
+  EXPECT_EQ(TSI_OK, result);
+}
+
+void TransportSecurityTest::ReceiveMessageFromPeer(
+    bool is_client, tsi_frame_protector* protector,
+    unsigned int read_buf_allocated_size,
+    unsigned int message_buf_allocated_size, string* message) {
+  std::unique_ptr<unsigned char[]> read_buffer(
+      new unsigned char[read_buf_allocated_size]);
+  unsigned int read_offset = 0;
+  unsigned int read_from_peer_size = 0;
+  std::unique_ptr<unsigned char[]> message_buffer(
+      new unsigned char[message_buf_allocated_size]);
+  tsi_result result = TSI_OK;
+  bool done = false;
+  while (!done && result == TSI_OK) {
+    if (read_from_peer_size == 0) {
+      read_from_peer_size = read_buf_allocated_size;
+      ReadBytesFromPeer(is_client, read_buffer.get(), &read_from_peer_size);
+      read_offset = 0;
+    }
+    if (read_from_peer_size == 0) done = true;
+    unsigned int message_buffer_size;
+    do {
+      message_buffer_size = message_buf_allocated_size;
+      unsigned int processed_size = read_from_peer_size;
+      result = tsi_frame_protector_unprotect(
+          protector, read_buffer.get() + read_offset, &processed_size,
+          message_buffer.get(), &message_buffer_size);
+      EXPECT_EQ(TSI_OK, result);
+      if (message_buffer_size > 0) {
+        LOG(INFO) << "Wrote " << message_buffer_size << " bytes to message.";
+        message->append(reinterpret_cast<const char*>(message_buffer.get()),
+                        message_buffer_size);
+      }
+      read_offset += processed_size;
+      read_from_peer_size -= processed_size;
+    } while ((read_from_peer_size > 0 || message_buffer_size > 0) &&
+             result == TSI_OK);
+    EXPECT_EQ(TSI_OK, result);
+  }
+  EXPECT_EQ(TSI_OK, result);
+}
+
+void TransportSecurityTest::DoRoundTrip(const string& request,
+                                        const string& response) {
+  PerformHandshake();
+
+  tsi_frame_protector* client_frame_protector;
+  tsi_frame_protector* server_frame_protector;
+  unsigned int client_max_output_protected_frame_size =
+      config()->client_max_output_protected_frame_size();
+  EXPECT_EQ(TSI_OK,
+            tsi_handshaker_create_frame_protector(
+                client_handshaker_.get(),
+                config()->use_client_default_max_output_protected_frame_size()
+                    ? nullptr
+                    : &client_max_output_protected_frame_size,
+                &client_frame_protector));
+
+  unsigned int server_max_output_protected_frame_size =
+      config()->server_max_output_protected_frame_size();
+  EXPECT_EQ(TSI_OK,
+            tsi_handshaker_create_frame_protector(
+                server_handshaker_.get(),
+                config()->use_server_default_max_output_protected_frame_size()
+                    ? nullptr
+                    : &server_max_output_protected_frame_size,
+                &server_frame_protector));
+
+  SendMessageToPeer(true, client_frame_protector, request,
+                    config()->protected_buffer_size);
+  string retrieved_request;
+  ReceiveMessageFromPeer(
+      false, server_frame_protector, config()->read_buffer_allocated_size,
+      config()->message_buffer_allocated_size, &retrieved_request);
+  EXPECT_EQ(request.size(), retrieved_request.size());
+  EXPECT_EQ(strings::b2a_hex(request), strings::b2a_hex(retrieved_request));
+
+  SendMessageToPeer(false, server_frame_protector, response,
+                    config()->protected_buffer_size);
+  string retrieved_response;
+  ReceiveMessageFromPeer(
+      true, client_frame_protector, config()->read_buffer_allocated_size,
+      config()->message_buffer_allocated_size, &retrieved_response);
+  EXPECT_EQ(response.size(), retrieved_response.size());
+  EXPECT_EQ(strings::b2a_hex(response), strings::b2a_hex(retrieved_response));
+
+  tsi_frame_protector_destroy(client_frame_protector);
+  tsi_frame_protector_destroy(server_frame_protector);
+}
+
+void TransportSecurityTest::DoRoundTrip() {
+  DoRoundTrip(config()->client_message, config()->server_message);
+}
+void TransportSecurityTest::PingPong() {
+  PerformHandshake();
+
+  unsigned char to_server[4096];
+  unsigned char to_client[4096];
+  unsigned int max_frame_size = sizeof(to_client);
+  tsi_frame_protector* client_frame_protector;
+  tsi_frame_protector* server_frame_protector;
+  EXPECT_EQ(
+      tsi_handshaker_create_frame_protector(
+          client_handshaker_.get(), &max_frame_size, &client_frame_protector),
+      TSI_OK);
+  EXPECT_EQ(max_frame_size, sizeof(to_client));
+  EXPECT_EQ(
+      tsi_handshaker_create_frame_protector(
+          server_handshaker_.get(), &max_frame_size, &server_frame_protector),
+      TSI_OK);
+  EXPECT_EQ(max_frame_size, sizeof(to_client));
+
+  // Send Ping.
+  unsigned int ping_length = strlen(kPingRequest);
+  unsigned int protected_size = sizeof(to_server);
+  EXPECT_EQ(tsi_frame_protector_protect(
+                client_frame_protector,
+                reinterpret_cast<const unsigned char*>(kPingRequest),
+                &ping_length, to_server, &protected_size),
+            TSI_OK);
+  EXPECT_EQ(ping_length, strlen(kPingRequest));
+  EXPECT_EQ(protected_size, 0);
+  protected_size = sizeof(to_server);
+  unsigned int still_pending_size;
+  EXPECT_EQ(
+      tsi_frame_protector_protect_flush(client_frame_protector, to_server,
+                                        &protected_size, &still_pending_size),
+      TSI_OK);
+  EXPECT_EQ(still_pending_size, 0);
+  EXPECT_GT(protected_size, strlen(kPingRequest));
+
+  // Receive Ping.
+  unsigned int unprotected_size = sizeof(to_server);
+  unsigned int saved_protected_size = protected_size;
+  EXPECT_EQ(tsi_frame_protector_unprotect(server_frame_protector, to_server,
+                                          &protected_size, to_server,
+                                          &unprotected_size),
+            TSI_OK);
+  EXPECT_EQ(saved_protected_size, protected_size);
+  EXPECT_EQ(ping_length, unprotected_size);
+  EXPECT_EQ(string(kPingRequest),
+            string(reinterpret_cast<const char*>(to_server), unprotected_size));
+
+  // Send back Pong.
+  unsigned int pong_length = strlen(kPongResponse);
+  protected_size = sizeof(to_client);
+  EXPECT_EQ(tsi_frame_protector_protect(
+                server_frame_protector,
+                reinterpret_cast<const unsigned char*>(kPongResponse),
+                &pong_length, to_client, &protected_size),
+            TSI_OK);
+  EXPECT_EQ(pong_length, strlen(kPongResponse));
+  EXPECT_EQ(protected_size, 0);
+  protected_size = sizeof(to_client);
+  EXPECT_EQ(
+      tsi_frame_protector_protect_flush(server_frame_protector, to_client,
+                                        &protected_size, &still_pending_size),
+      TSI_OK);
+  EXPECT_EQ(still_pending_size, 0);
+  EXPECT_GT(protected_size, strlen(kPongResponse));
+
+  // Receive Pong.
+  unprotected_size = sizeof(to_server);
+  saved_protected_size = protected_size;
+  EXPECT_EQ(tsi_frame_protector_unprotect(client_frame_protector, to_client,
+                                          &protected_size, to_client,
+                                          &unprotected_size),
+            TSI_OK);
+  EXPECT_EQ(saved_protected_size, protected_size);
+  EXPECT_EQ(pong_length, unprotected_size);
+  EXPECT_EQ(string(kPongResponse),
+            string(reinterpret_cast<const char*>(to_client), unprotected_size));
+
+  tsi_frame_protector_destroy(client_frame_protector);
+  tsi_frame_protector_destroy(server_frame_protector);
+}
+
+}  // namespace test
+}  // namespace tsi
diff --git a/src/core/tsi/transport_security_test_lib.h b/src/core/tsi/transport_security_test_lib.h
new file mode 100644
index 0000000..8c9c764
--- /dev/null
+++ b/src/core/tsi/transport_security_test_lib.h
@@ -0,0 +1,154 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TRANSPORT_SECURITY_TEST_LIB_H_
+#define __TRANSPORT_SECURITY_TEST_LIB_H_
+
+#include <memory>
+
+#include "base/commandlineflags.h"
+#include "src/core/tsi/transport_security_interface.h"
+#include "strings/strcat.h"
+#include <gtest/gtest.h>
+#include "util/random/mt_random.h"
+
+namespace tsi {
+namespace test {
+
+class TestConfig {
+ public:
+  TestConfig()
+      : client_message("Chapi Chapo"),
+        server_message("Chapi Chapo"),
+        handshake_buffer_size(4096),
+        read_buffer_allocated_size(4096),
+        message_buffer_allocated_size(4096),
+        protected_buffer_size(16384),
+        use_client_default_max_output_protected_frame_size_(true),
+        use_server_default_max_output_protected_frame_size_(true),
+        client_max_output_protected_frame_size_(0),
+        server_max_output_protected_frame_size_(0) {}
+
+  void set_client_max_output_protected_frame_size(unsigned int size) {
+    use_client_default_max_output_protected_frame_size_ = false;
+    client_max_output_protected_frame_size_ = size;
+  }
+  void set_server_max_output_protected_frame_size(unsigned int size) {
+    use_server_default_max_output_protected_frame_size_ = false;
+    server_max_output_protected_frame_size_ = size;
+  }
+  bool use_client_default_max_output_protected_frame_size() const {
+    return use_client_default_max_output_protected_frame_size_;
+  }
+  bool use_server_default_max_output_protected_frame_size() const {
+    return use_server_default_max_output_protected_frame_size_;
+  }
+  unsigned int client_max_output_protected_frame_size() const {
+    return client_max_output_protected_frame_size_;
+  }
+  unsigned int server_max_output_protected_frame_size() const {
+    return server_max_output_protected_frame_size_;
+  }
+
+  string client_message;
+  string server_message;
+  unsigned int handshake_buffer_size;
+  unsigned int read_buffer_allocated_size;
+  unsigned int message_buffer_allocated_size;
+  unsigned int protected_buffer_size;
+
+ private:
+  bool use_client_default_max_output_protected_frame_size_;
+  bool use_server_default_max_output_protected_frame_size_;
+  unsigned int client_max_output_protected_frame_size_;
+  unsigned int server_max_output_protected_frame_size_;
+};
+
+
+struct TsiHandshakerDeleter {
+  inline void operator()(tsi_handshaker* ptr) { tsi_handshaker_destroy(ptr); }
+};
+typedef std::unique_ptr<tsi_handshaker, TsiHandshakerDeleter>
+    TsiHandshakerUniquePtr;
+
+class TransportSecurityTest : public ::testing::Test {
+ protected:
+  TransportSecurityTest();
+  virtual ~TransportSecurityTest() {}
+  virtual const TestConfig* config() = 0;
+  string RandomString(int size);
+  virtual void SetupHandshakers() = 0;
+  // An implementation-specific verification of the validity of the handshake.
+  virtual void CheckHandshakeResults() = 0;
+  // Do a full handshake.
+  void PerformHandshake();
+  // Send a protected message between the client and server.
+  void SendMessageToPeer(bool is_client, tsi_frame_protector* protector,
+                         const string& message,
+                         unsigned int protected_buffer_size);
+  void ReceiveMessageFromPeer(bool is_client, tsi_frame_protector* protector,
+                              unsigned int read_buf_allocated_size,
+                              unsigned int message_buf_allocated_size,
+                              string* message);
+
+  // A simple test that does a handshake and sends a message back and forth
+  void PingPong();
+  // A complicated test that can be configured by modifying config().
+  void DoRoundTrip();
+
+  TsiHandshakerUniquePtr client_handshaker_;
+  TsiHandshakerUniquePtr server_handshaker_;
+
+  string small_message_;
+  string big_message_;
+  std::unique_ptr<RandomBase> random_;
+
+ private:
+  // Functions to send raw bytes between the client and server.
+  void SendBytesToPeer(bool is_client, unsigned char* buf,
+                       unsigned int buf_size);
+  void ReadBytesFromPeer(bool is_client, unsigned char* buf,
+                         unsigned int* buf_size);
+  // Do a single step of the handshake.
+  void DoHandshakeStep(bool is_client, unsigned int buf_allocated_size,
+                       tsi_handshaker* handshaker, string* remaining_bytes);
+  void DoRoundTrip(const string& request, const string& response);
+
+  string to_server_channel_;
+  string to_client_channel_;
+};
+
+}  // namespace test
+}  // namespace tsi
+
+#endif  // __TRANSPORT_SECURITY_TEST_LIB_H_
diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc
new file mode 100644
index 0000000..7a75291
--- /dev/null
+++ b/src/cpp/client/channel.cc
@@ -0,0 +1,212 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/cpp/client/channel.h"
+
+#include <chrono>
+#include <string>
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/time.h>
+
+#include "src/cpp/rpc_method.h"
+#include "src/cpp/proto/proto_utils.h"
+#include "src/cpp/stream/stream_context.h"
+#include "src/cpp/util/time.h"
+#include <grpc++/config.h>
+#include <google/protobuf/message.h>
+#include <grpc++/client_context.h>
+#include <grpc++/status.h>
+
+namespace grpc {
+
+Channel::Channel(const grpc::string& target) : target_(target) {
+  c_channel_ = grpc_channel_create(target_.c_str(), nullptr);
+}
+
+Channel::~Channel() { grpc_channel_destroy(c_channel_); }
+
+namespace {
+// Poll one event from the compeletion queue. Return false when an error
+// occured or the polled type is not expected. If a finished event has been
+// polled, set finished and set status if it has not been set.
+bool NextEvent(grpc_completion_queue* cq, grpc_completion_type expected_type,
+               bool* finished, bool* status_set, Status* status,
+               google::protobuf::Message* result) {
+  // We rely on the c layer to enforce deadline and thus do not use deadline
+  // here.
+  grpc_event* ev = grpc_completion_queue_next(cq, gpr_inf_future);
+  if (!ev) {
+    return false;
+  }
+  bool ret = ev->type == expected_type;
+  switch (ev->type) {
+    case GRPC_INVOKE_ACCEPTED:
+      ret = ret && (ev->data.invoke_accepted == GRPC_OP_OK);
+      break;
+    case GRPC_READ:
+      ret = ret && (ev->data.read != nullptr);
+      if (ret && !DeserializeProto(ev->data.read, result)) {
+        *status_set = true;
+        *status =
+            Status(StatusCode::DATA_LOSS, "Failed to parse response proto.");
+        ret = false;
+      }
+      break;
+    case GRPC_WRITE_ACCEPTED:
+      ret = ret && (ev->data.write_accepted == GRPC_OP_OK);
+      break;
+    case GRPC_FINISH_ACCEPTED:
+      ret = ret && (ev->data.finish_accepted == GRPC_OP_OK);
+      break;
+    case GRPC_CLIENT_METADATA_READ:
+      break;
+    case GRPC_FINISHED:
+      *finished = true;
+      if (!*status_set) {
+        *status_set = true;
+        StatusCode error_code = static_cast<StatusCode>(ev->data.finished.code);
+        grpc::string details(
+            ev->data.finished.details ? ev->data.finished.details : "");
+        *status = Status(error_code, details);
+      }
+      break;
+    default:
+      gpr_log(GPR_ERROR, "Dropping unhandled event with type %d", ev->type);
+      break;
+  }
+  grpc_event_finish(ev);
+  return ret;
+}
+
+// If finished is not true, get final status by polling until a finished
+// event is obtained.
+void GetFinalStatus(grpc_completion_queue* cq, bool status_set, bool finished,
+                    Status* status) {
+  while (!finished) {
+    NextEvent(cq, GRPC_FINISHED, &finished, &status_set, status, nullptr);
+  }
+}
+
+}  // namespace
+
+// TODO(yangg) more error handling
+Status Channel::StartBlockingRpc(const RpcMethod& method,
+                                 ClientContext* context,
+                                 const google::protobuf::Message& request,
+                                 google::protobuf::Message* result) {
+  Status status;
+  bool status_set = false;
+  bool finished = false;
+  gpr_timespec absolute_deadline;
+  AbsoluteDeadlineTimepoint2Timespec(context->absolute_deadline(),
+                                     &absolute_deadline);
+  grpc_call* call = grpc_channel_create_call(c_channel_, method.name(),
+                                             // FIXME(yangg)
+                                             "localhost", absolute_deadline);
+  context->set_call(call);
+  grpc_completion_queue* cq = grpc_completion_queue_create();
+  context->set_cq(cq);
+  // add_metadata from context
+  //
+  // invoke
+  GPR_ASSERT(grpc_call_start_invoke(call, cq, call, call, call,
+                                    GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
+  if (!NextEvent(cq, GRPC_INVOKE_ACCEPTED, &status_set, &finished, &status,
+                 nullptr)) {
+    GetFinalStatus(cq, finished, status_set, &status);
+    return status;
+  }
+  // write request
+  grpc_byte_buffer* write_buffer = nullptr;
+  bool success = SerializeProto(request, &write_buffer);
+  if (!success) {
+    grpc_call_cancel(call);
+    status_set = true;
+    status =
+        Status(StatusCode::DATA_LOSS, "Failed to serialize request proto.");
+    GetFinalStatus(cq, finished, status_set, &status);
+    return status;
+  }
+  GPR_ASSERT(grpc_call_start_write(call, write_buffer, call,
+                                   GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
+  grpc_byte_buffer_destroy(write_buffer);
+  if (!NextEvent(cq, GRPC_WRITE_ACCEPTED, &finished, &status_set, &status,
+                 nullptr)) {
+    GetFinalStatus(cq, finished, status_set, &status);
+    return status;
+  }
+  // writes done
+  GPR_ASSERT(grpc_call_writes_done(call, call) == GRPC_CALL_OK);
+  if (!NextEvent(cq, GRPC_FINISH_ACCEPTED, &finished, &status_set, &status,
+                 nullptr)) {
+    GetFinalStatus(cq, finished, status_set, &status);
+    return status;
+  }
+  // start read metadata
+  //
+  if (!NextEvent(cq, GRPC_CLIENT_METADATA_READ, &finished, &status_set, &status,
+                 nullptr)) {
+    GetFinalStatus(cq, finished, status_set, &status);
+    return status;
+  }
+  // start read
+  GPR_ASSERT(grpc_call_start_read(call, call) == GRPC_CALL_OK);
+  if (!NextEvent(cq, GRPC_READ, &finished, &status_set, &status, result)) {
+    GetFinalStatus(cq, finished, status_set, &status);
+    return status;
+  }
+  // wait status
+  GetFinalStatus(cq, finished, status_set, &status);
+  return status;
+}
+
+StreamContextInterface* Channel::CreateStream(const RpcMethod& method,
+                                              ClientContext* context,
+                                              const google::protobuf::Message* request,
+                                              google::protobuf::Message* result) {
+  gpr_timespec absolute_deadline;
+  AbsoluteDeadlineTimepoint2Timespec(context->absolute_deadline(),
+                                     &absolute_deadline);
+  grpc_call* call = grpc_channel_create_call(c_channel_, method.name(),
+                                             // FIXME(yangg)
+                                             "localhost", absolute_deadline);
+  context->set_call(call);
+  grpc_completion_queue* cq = grpc_completion_queue_create();
+  context->set_cq(cq);
+  return new StreamContext(method, context, request, result);
+}
+
+}  // namespace grpc
diff --git a/src/cpp/client/channel.h b/src/cpp/client/channel.h
new file mode 100644
index 0000000..a97d35e
--- /dev/null
+++ b/src/cpp/client/channel.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_INTERNAL_CLIENT_CHANNEL_H__
+#define __GRPCPP_INTERNAL_CLIENT_CHANNEL_H__
+
+#include <grpc++/channel_interface.h>
+#include <grpc++/config.h>
+
+struct grpc_channel;
+
+namespace grpc {
+class StreamContextInterface;
+
+class Channel : public ChannelInterface {
+ public:
+  explicit Channel(const grpc::string& target);
+  ~Channel() override;
+
+  Status StartBlockingRpc(const RpcMethod& method, ClientContext* context,
+                          const google::protobuf::Message& request,
+                          google::protobuf::Message* result) override;
+
+  StreamContextInterface* CreateStream(const RpcMethod& method,
+                                       ClientContext* context,
+                                       const google::protobuf::Message* request,
+                                       google::protobuf::Message* result) override;
+
+ protected:
+  // TODO(yangg) remove this section when we have the general ssl channel API
+  Channel() {}
+  void set_c_channel(grpc_channel* channel) { c_channel_ = channel; }
+
+ private:
+  const grpc::string target_;
+  grpc_channel* c_channel_;  // owned
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_INTERNAL_CLIENT_CHANNEL_H__
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
new file mode 100644
index 0000000..78774a7
--- /dev/null
+++ b/src/cpp/client/client_context.cc
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc++/client_context.h>
+
+#include <grpc/grpc.h>
+
+using std::chrono::system_clock;
+
+namespace grpc {
+
+ClientContext::ClientContext()
+    : call_(nullptr),
+      cq_(nullptr),
+      absolute_deadline_(system_clock::time_point::max()) {}
+
+ClientContext::~ClientContext() {
+  if (call_) {
+    grpc_call_destroy(call_);
+  }
+  if (cq_) {
+    grpc_completion_queue_shutdown(cq_);
+    grpc_completion_queue_destroy(cq_);
+  }
+}
+
+void ClientContext::set_absolute_deadline(
+    const system_clock::time_point& deadline) {
+  absolute_deadline_ = deadline;
+}
+
+system_clock::time_point ClientContext::absolute_deadline() {
+  return absolute_deadline_;
+}
+
+void ClientContext::AddMetadata(const grpc::string& meta_key,
+                                const grpc::string& meta_value) {
+  return;
+}
+
+void ClientContext::StartCancel() {}
+
+}  // namespace grpc
diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc
new file mode 100644
index 0000000..ea2b6a7
--- /dev/null
+++ b/src/cpp/client/create_channel.cc
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <memory>
+#include <string>
+
+#include "src/cpp/client/channel.h"
+#include <grpc++/channel_interface.h>
+#include <grpc++/create_channel.h>
+
+namespace grpc {
+
+std::shared_ptr<ChannelInterface> CreateChannel(const grpc::string& target) {
+  return std::shared_ptr<ChannelInterface>(new Channel(target));
+}
+
+}  // namespace grpc
diff --git a/src/cpp/client/credentials.cc b/src/cpp/client/credentials.cc
new file mode 100644
index 0000000..18fa4fa
--- /dev/null
+++ b/src/cpp/client/credentials.cc
@@ -0,0 +1,90 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <string>
+
+#include <grpc/grpc_security.h>
+
+#include <grpc++/credentials.h>
+
+namespace grpc {
+
+Credentials::Credentials(grpc_credentials* c_creds) : creds_(c_creds) {}
+
+Credentials::~Credentials() { grpc_credentials_release(creds_); }
+grpc_credentials* Credentials::GetRawCreds() { return creds_; }
+
+std::unique_ptr<Credentials> CredentialsFactory::DefaultCredentials() {
+  grpc_credentials* c_creds = grpc_default_credentials_create();
+  std::unique_ptr<Credentials> cpp_creds(new Credentials(c_creds));
+  return cpp_creds;
+}
+
+// Builds SSL Credentials given SSL specific options
+std::unique_ptr<Credentials> CredentialsFactory::SslCredentials(
+    const SslCredentialsOptions& options) {
+  grpc_credentials* c_creds = grpc_ssl_credentials_create(
+      reinterpret_cast<const unsigned char*>(options.pem_root_certs.c_str()),
+      options.pem_root_certs.size(),
+      reinterpret_cast<const unsigned char*>(options.pem_private_key.c_str()),
+      options.pem_private_key.size(),
+      reinterpret_cast<const unsigned char*>(options.pem_cert_chain.c_str()),
+      options.pem_cert_chain.size());
+  std::unique_ptr<Credentials> cpp_creds(new Credentials(c_creds));
+  return cpp_creds;
+}
+
+// Builds credentials for use when running in GCE
+std::unique_ptr<Credentials> CredentialsFactory::ComputeEngineCredentials() {
+  grpc_credentials* c_creds = grpc_compute_engine_credentials_create();
+  std::unique_ptr<Credentials> cpp_creds(new Credentials(c_creds));
+  return cpp_creds;
+}
+
+
+// Combines two credentials objects into a composite credentials.
+std::unique_ptr<Credentials> CredentialsFactory::ComposeCredentials(
+    const std::unique_ptr<Credentials>& creds1,
+    const std::unique_ptr<Credentials>& creds2) {
+  // Note that we are not saving unique_ptrs to the two credentials
+  // passed in here. This is OK because the underlying C objects (i.e.,
+  // creds1 and creds2) into grpc_composite_credentials_create will see their
+  // refcounts incremented.
+  grpc_credentials* c_creds = grpc_composite_credentials_create(
+      creds1->GetRawCreds(), creds2->GetRawCreds());
+  std::unique_ptr<Credentials> cpp_creds(new Credentials(c_creds));
+  return cpp_creds;
+}
+
+}  // namespace grpc
diff --git a/src/cpp/client/internal_stub.cc b/src/cpp/client/internal_stub.cc
new file mode 100644
index 0000000..ec88ba5
--- /dev/null
+++ b/src/cpp/client/internal_stub.cc
@@ -0,0 +1,36 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/cpp/client/internal_stub.h"
+
+namespace grpc {}  // namespace grpc
diff --git a/src/cpp/client/internal_stub.h b/src/cpp/client/internal_stub.h
new file mode 100644
index 0000000..0eaa717
--- /dev/null
+++ b/src/cpp/client/internal_stub.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_INTERNAL_CLIENT_INTERNAL_STUB_H__
+#define __GRPCPP_INTERNAL_CLIENT_INTERNAL_STUB_H__
+
+#include <memory>
+
+#include <grpc++/channel_interface.h>
+
+namespace grpc {
+
+class InternalStub {
+ public:
+  InternalStub() {}
+  virtual ~InternalStub() {}
+
+  void set_channel(const std::shared_ptr<ChannelInterface>& channel) {
+    channel_ = channel;
+  }
+
+  ChannelInterface* channel() { return channel_.get(); }
+
+ private:
+  std::shared_ptr<ChannelInterface> channel_;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_INTERNAL_CLIENT_INTERNAL_STUB_H__
diff --git a/src/cpp/proto/proto_utils.cc b/src/cpp/proto/proto_utils.cc
new file mode 100644
index 0000000..255d146
--- /dev/null
+++ b/src/cpp/proto/proto_utils.cc
@@ -0,0 +1,71 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/cpp/proto/proto_utils.h"
+#include <grpc++/config.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/slice.h>
+#include <google/protobuf/message.h>
+
+namespace grpc {
+
+bool SerializeProto(const google::protobuf::Message& msg, grpc_byte_buffer** bp) {
+  grpc::string msg_str;
+  bool success = msg.SerializeToString(&msg_str);
+  if (success) {
+    gpr_slice slice =
+        gpr_slice_from_copied_buffer(msg_str.data(), msg_str.length());
+    *bp = grpc_byte_buffer_create(&slice, 1);
+    gpr_slice_unref(slice);
+  }
+  return success;
+}
+
+bool DeserializeProto(grpc_byte_buffer* buffer, google::protobuf::Message* msg) {
+  grpc::string msg_string;
+  grpc_byte_buffer_reader* reader = grpc_byte_buffer_reader_create(buffer);
+  gpr_slice slice;
+  while (grpc_byte_buffer_reader_next(reader, &slice)) {
+    const char* data = reinterpret_cast<const char*>(
+        slice.refcount ? slice.data.refcounted.bytes
+                       : slice.data.inlined.bytes);
+    msg_string.append(data, slice.refcount ? slice.data.refcounted.length
+                                           : slice.data.inlined.length);
+    gpr_slice_unref(slice);
+  }
+  grpc_byte_buffer_reader_destroy(reader);
+  return msg->ParseFromString(msg_string);
+}
+
+}  // namespace grpc
diff --git a/src/cpp/proto/proto_utils.h b/src/cpp/proto/proto_utils.h
new file mode 100644
index 0000000..11471f1
--- /dev/null
+++ b/src/cpp/proto/proto_utils.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_INTERNAL_PROTO_PROTO_UTILS_H__
+#define __GRPCPP_INTERNAL_PROTO_PROTO_UTILS_H__
+
+struct grpc_byte_buffer;
+namespace google {
+namespace protobuf {
+class Message;
+}
+}
+
+namespace grpc {
+
+// Serialize the msg into a buffer created inside the function. The caller
+// should destroy the returned buffer when done with it. If serialization fails,
+// false is returned and buffer is left unchanged.
+bool SerializeProto(const google::protobuf::Message& msg, grpc_byte_buffer** buffer);
+
+// The caller keeps ownership of buffer and msg.
+bool DeserializeProto(grpc_byte_buffer* buffer, google::protobuf::Message* msg);
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_INTERNAL_PROTO_PROTO_UTILS_H__
diff --git a/src/cpp/rpc_method.cc b/src/cpp/rpc_method.cc
new file mode 100644
index 0000000..8067f42
--- /dev/null
+++ b/src/cpp/rpc_method.cc
@@ -0,0 +1,36 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/cpp/rpc_method.h"
+
+namespace grpc {}  // namespace grpc
diff --git a/src/cpp/rpc_method.h b/src/cpp/rpc_method.h
new file mode 100644
index 0000000..24a34be
--- /dev/null
+++ b/src/cpp/rpc_method.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_INTERNAL_RPC_METHOD_H__
+#define __GRPCPP_INTERNAL_RPC_METHOD_H__
+
+namespace google {
+namespace protobuf {
+class Message;
+}
+}
+
+namespace grpc {
+
+class RpcMethod {
+ public:
+  enum RpcType {
+    NORMAL_RPC = 0,
+    CLIENT_STREAMING,  // request streaming
+    SERVER_STREAMING,  // response streaming
+    BIDI_STREAMING
+  };
+
+  explicit RpcMethod(const char* name)
+      : name_(name), method_type_(NORMAL_RPC) {}
+  RpcMethod(const char* name, RpcType type) : name_(name), method_type_(type) {}
+
+  const char *name() const { return name_; }
+
+  RpcType method_type() const { return method_type_; }
+
+ private:
+  const char *name_;
+  const RpcType method_type_;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_INTERNAL_RPC_METHOD_H__
diff --git a/src/cpp/server/async_server.cc b/src/cpp/server/async_server.cc
new file mode 100644
index 0000000..aae2c82
--- /dev/null
+++ b/src/cpp/server/async_server.cc
@@ -0,0 +1,89 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc++/async_server.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpc++/completion_queue.h>
+
+namespace grpc {
+
+AsyncServer::AsyncServer(CompletionQueue* cc)
+    : started_(false), shutdown_(false) {
+  server_ = grpc_server_create(cc->cq(), nullptr);
+}
+
+AsyncServer::~AsyncServer() {
+  std::unique_lock<std::mutex> lock(shutdown_mu_);
+  if (started_ && !shutdown_) {
+    lock.unlock();
+    Shutdown();
+  }
+  grpc_server_destroy(server_);
+}
+
+void AsyncServer::AddPort(const grpc::string& addr) {
+  GPR_ASSERT(!started_);
+  int success = grpc_server_add_http2_port(server_, addr.c_str());
+  GPR_ASSERT(success);
+}
+
+void AsyncServer::Start() {
+  GPR_ASSERT(!started_);
+  started_ = true;
+  grpc_server_start(server_);
+}
+
+void AsyncServer::RequestOneRpc() {
+  GPR_ASSERT(started_);
+  std::unique_lock<std::mutex> lock(shutdown_mu_);
+  if (shutdown_) {
+    return;
+  }
+  lock.unlock();
+  grpc_call_error err = grpc_server_request_call(server_, nullptr);
+  GPR_ASSERT(err == GRPC_CALL_OK);
+}
+
+void AsyncServer::Shutdown() {
+  std::unique_lock<std::mutex> lock(shutdown_mu_);
+  if (started_ && !shutdown_) {
+    shutdown_ = true;
+    lock.unlock();
+    // TODO(yangg) should we shutdown without start?
+    grpc_server_shutdown(server_);
+  }
+}
+
+}  // namespace grpc
diff --git a/src/cpp/server/async_server_context.cc b/src/cpp/server/async_server_context.cc
new file mode 100644
index 0000000..b231f4b
--- /dev/null
+++ b/src/cpp/server/async_server_context.cc
@@ -0,0 +1,101 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc++/async_server_context.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include "src/cpp/proto/proto_utils.h"
+#include <google/protobuf/message.h>
+#include <grpc++/status.h>
+
+namespace grpc {
+
+AsyncServerContext::AsyncServerContext(
+    grpc_call* call, const grpc::string& method, const grpc::string& host,
+    system_clock::time_point absolute_deadline)
+    : method_(method),
+      host_(host),
+      absolute_deadline_(absolute_deadline),
+      request_(nullptr),
+      call_(call) {
+}
+
+AsyncServerContext::~AsyncServerContext() { grpc_call_destroy(call_); }
+
+void AsyncServerContext::Accept(grpc_completion_queue* cq) {
+  grpc_call_accept(call_, cq, this, 0);
+}
+
+bool AsyncServerContext::StartRead(google::protobuf::Message* request) {
+  GPR_ASSERT(request);
+  request_ = request;
+  grpc_call_error err = grpc_call_start_read(call_, this);
+  return err == GRPC_CALL_OK;
+}
+
+bool AsyncServerContext::StartWrite(const google::protobuf::Message& response,
+                                    int flags) {
+  grpc_byte_buffer* buffer = nullptr;
+  if (!SerializeProto(response, &buffer)) {
+    return false;
+  }
+  grpc_call_error err = grpc_call_start_write(call_, buffer, this, flags);
+  grpc_byte_buffer_destroy(buffer);
+  return err == GRPC_CALL_OK;
+}
+
+namespace {
+grpc_status TranslateStatus(const Status& status) {
+  grpc_status c_status;
+  // TODO(yangg)
+  c_status.code = GRPC_STATUS_OK;
+  c_status.details = nullptr;
+  return c_status;
+}
+}  // namespace
+
+bool AsyncServerContext::StartWriteStatus(const Status& status) {
+  grpc_status c_status = TranslateStatus(status);
+  grpc_call_error err = grpc_call_start_write_status(call_, c_status, this);
+  return err == GRPC_CALL_OK;
+}
+
+bool AsyncServerContext::ParseRead(grpc_byte_buffer* read_buffer) {
+  GPR_ASSERT(request_);
+  bool success = DeserializeProto(read_buffer, request_);
+  request_ = nullptr;
+  return success;
+}
+
+}  // namespace grpc
diff --git a/src/cpp/server/completion_queue.cc b/src/cpp/server/completion_queue.cc
new file mode 100644
index 0000000..04eb301
--- /dev/null
+++ b/src/cpp/server/completion_queue.cc
@@ -0,0 +1,113 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+// TODO(yangg) maybe move to internal/common
+#include <grpc++/completion_queue.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include "src/cpp/util/time.h"
+#include <grpc++/async_server_context.h>
+
+namespace grpc {
+
+CompletionQueue::CompletionQueue() { cq_ = grpc_completion_queue_create(); }
+
+CompletionQueue::~CompletionQueue() { grpc_completion_queue_destroy(cq_); }
+
+void CompletionQueue::Shutdown() { grpc_completion_queue_shutdown(cq_); }
+
+CompletionQueue::CompletionType CompletionQueue::Next(void** tag) {
+  grpc_event* ev;
+  CompletionType return_type;
+  bool success;
+
+  ev = grpc_completion_queue_next(cq_, gpr_inf_future);
+  if (!ev) {
+    gpr_log(GPR_ERROR, "no next event in queue");
+    abort();
+  }
+  switch (ev->type) {
+    case GRPC_QUEUE_SHUTDOWN:
+      return_type = QUEUE_CLOSED;
+      break;
+    case GRPC_READ:
+      *tag = ev->tag;
+      if (ev->data.read) {
+        success =
+            static_cast<AsyncServerContext*>(ev->tag)->ParseRead(ev->data.read);
+        return_type = success ? SERVER_READ_OK : SERVER_READ_ERROR;
+      } else {
+        return_type = SERVER_READ_ERROR;
+      }
+      break;
+    case GRPC_WRITE_ACCEPTED:
+      *tag = ev->tag;
+      if (ev->data.write_accepted != GRPC_OP_ERROR) {
+        return_type = SERVER_WRITE_OK;
+      } else {
+        return_type = SERVER_WRITE_ERROR;
+      }
+      break;
+    case GRPC_SERVER_RPC_NEW:
+      GPR_ASSERT(!ev->tag);
+      // Finishing the pending new rpcs after the server has been shutdown.
+      if (!ev->call) {
+        *tag = nullptr;
+      } else {
+        *tag = new AsyncServerContext(ev->call, ev->data.server_rpc_new.method,
+                                      ev->data.server_rpc_new.host,
+                                      AbsoluteDeadlineTimespec2Timepoint(
+                                          ev->data.server_rpc_new.deadline));
+      }
+      return_type = SERVER_RPC_NEW;
+      break;
+    case GRPC_FINISHED:
+      *tag = ev->tag;
+      return_type = RPC_END;
+      break;
+    case GRPC_FINISH_ACCEPTED:
+      *tag = ev->tag;
+      return_type = HALFCLOSE_OK;
+      break;
+    default:
+      // We do not handle client side messages now
+      gpr_log(GPR_ERROR, "client-side messages aren't supported yet");
+      abort();
+  }
+  grpc_event_finish(ev);
+  return return_type;
+}
+
+}  // namespace grpc
diff --git a/src/cpp/server/rpc_service_method.h b/src/cpp/server/rpc_service_method.h
new file mode 100644
index 0000000..ac2badd
--- /dev/null
+++ b/src/cpp/server/rpc_service_method.h
@@ -0,0 +1,131 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_INTERNAL_SERVER_RPC_SERVICE_METHOD_H__
+#define __GRPCPP_INTERNAL_SERVER_RPC_SERVICE_METHOD_H__
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "src/cpp/rpc_method.h"
+#include <google/protobuf/message.h>
+#include <grpc++/status.h>
+
+namespace grpc {
+
+// TODO(rocking): we might need to split this file into multiple ones.
+
+// Base class for running an RPC handler.
+class MethodHandler {
+ public:
+  virtual ~MethodHandler() {}
+  struct HandlerParameter {
+    HandlerParameter(const google::protobuf::Message* req, google::protobuf::Message* resp)
+        : request(req), response(resp) {}
+    const google::protobuf::Message* request;
+    google::protobuf::Message* response;
+  };
+  virtual ::grpc::Status RunHandler(const HandlerParameter& param) = 0;
+};
+
+// 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<::grpc::Status(
+                       ServiceType*, const RequestType*, ResponseType*)> func,
+                   ServiceType* service)
+      : func_(func), service_(service) {}
+
+  ::grpc::Status RunHandler(const HandlerParameter& param) final {
+    // Invoke application function, cast proto messages to their actual types.
+    return func_(service_, dynamic_cast<const RequestType*>(param.request),
+                 dynamic_cast<ResponseType*>(param.response));
+  }
+
+ private:
+  // Application provided rpc handler function.
+  std::function<::grpc::Status(ServiceType*, const RequestType*, ResponseType*)>
+      func_;
+  // The class the above handler function lives in.
+  ServiceType* service_;
+};
+
+// Server side rpc method class
+class RpcServiceMethod : public RpcMethod {
+ public:
+  // Takes ownership of the handler and two prototype objects.
+  RpcServiceMethod(const char* name, MethodHandler* handler,
+                   google::protobuf::Message* request_prototype,
+                   google::protobuf::Message* response_prototype)
+      : RpcMethod(name),
+        handler_(handler),
+        request_prototype_(request_prototype),
+        response_prototype_(response_prototype) {}
+
+  MethodHandler* handler() { return handler_.get(); }
+
+  google::protobuf::Message* AllocateRequestProto() { return request_prototype_->New(); }
+  google::protobuf::Message* AllocateResponseProto() {
+    return response_prototype_->New();
+  }
+
+ private:
+  std::unique_ptr<MethodHandler> handler_;
+  std::unique_ptr<google::protobuf::Message> request_prototype_;
+  std::unique_ptr<google::protobuf::Message> response_prototype_;
+};
+
+// This class contains all the method information for an rpc service. It is
+// used for registering a service on a grpc server.
+class RpcService {
+ public:
+  // Takes ownership.
+  void AddMethod(RpcServiceMethod* method) {
+    methods_.push_back(std::unique_ptr<RpcServiceMethod>(method));
+  }
+
+  RpcServiceMethod* GetMethod(int i) {
+    return methods_[i].get();
+  }
+  int GetMethodCount() const { return methods_.size(); }
+
+ private:
+  std::vector<std::unique_ptr<RpcServiceMethod>> methods_;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_INTERNAL_SERVER_RPC_SERVICE_METHOD_H__
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
new file mode 100644
index 0000000..9bf4073
--- /dev/null
+++ b/src/cpp/server/server.cc
@@ -0,0 +1,166 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc++/server.h>
+#include <utility>
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include "src/cpp/server/rpc_service_method.h"
+#include "src/cpp/server/server_rpc_handler.h"
+#include "src/cpp/server/thread_pool.h"
+#include <grpc++/async_server_context.h>
+#include <grpc++/completion_queue.h>
+
+namespace grpc {
+
+// TODO(rocking): consider a better default value like num of cores.
+static const int kNumThreads = 4;
+
+Server::Server(ThreadPoolInterface* thread_pool)
+    : started_(false),
+      shutdown_(false),
+      num_running_cb_(0),
+      thread_pool_(thread_pool == nullptr ? new ThreadPool(kNumThreads)
+                                          : thread_pool),
+      thread_pool_owned_(thread_pool == nullptr) {
+  server_ = grpc_server_create(cq_.cq(), nullptr);
+}
+
+Server::Server() {
+  // Should not be called.
+  GPR_ASSERT(false);
+}
+
+Server::~Server() {
+  std::unique_lock<std::mutex> lock(mu_);
+  if (started_ && !shutdown_) {
+    lock.unlock();
+    Shutdown();
+  }
+  grpc_server_destroy(server_);
+  if (thread_pool_owned_) {
+    delete thread_pool_;
+  }
+}
+
+void Server::RegisterService(RpcService* service) {
+  for (int i = 0; i < service->GetMethodCount(); ++i) {
+    RpcServiceMethod* method = service->GetMethod(i);
+    method_map_.insert(std::make_pair(method->name(), method));
+  }
+}
+
+void Server::AddPort(const grpc::string& addr) {
+  GPR_ASSERT(!started_);
+  int success = grpc_server_add_http2_port(server_, addr.c_str());
+  GPR_ASSERT(success);
+}
+
+void Server::Start() {
+  GPR_ASSERT(!started_);
+  started_ = true;
+  grpc_server_start(server_);
+
+  // Start processing rpcs.
+  ScheduleCallback();
+}
+
+void Server::AllowOneRpc() {
+  GPR_ASSERT(started_);
+  grpc_call_error err = grpc_server_request_call(server_, nullptr);
+  GPR_ASSERT(err == GRPC_CALL_OK);
+}
+
+void Server::Shutdown() {
+  {
+    std::unique_lock<std::mutex> lock(mu_);
+    if (started_ && !shutdown_) {
+      shutdown_ = true;
+      grpc_server_shutdown(server_);
+
+      // Wait for running callbacks to finish.
+      while (num_running_cb_ != 0) {
+        callback_cv_.wait(lock);
+      }
+    }
+  }
+
+  // Shutdown the completion queue.
+  cq_.Shutdown();
+  void* tag = nullptr;
+  CompletionQueue::CompletionType t = cq_.Next(&tag);
+  GPR_ASSERT(t == CompletionQueue::QUEUE_CLOSED);
+}
+
+void Server::ScheduleCallback() {
+  {
+    std::unique_lock<std::mutex> lock(mu_);
+    num_running_cb_++;
+  }
+  std::function<void()> callback = std::bind(&Server::RunRpc, this);
+  thread_pool_->ScheduleCallback(callback);
+}
+
+void Server::RunRpc() {
+  // Wait for one more incoming rpc.
+  void* tag = nullptr;
+  AllowOneRpc();
+  CompletionQueue::CompletionType t = cq_.Next(&tag);
+  GPR_ASSERT(t == CompletionQueue::SERVER_RPC_NEW);
+
+  AsyncServerContext* server_context = static_cast<AsyncServerContext*>(tag);
+  // server_context could be nullptr during server shutdown.
+  if (server_context != nullptr) {
+    // Schedule a new callback to handle more rpcs.
+    ScheduleCallback();
+
+    RpcServiceMethod* method = nullptr;
+    auto iter = method_map_.find(server_context->method());
+    if (iter != method_map_.end()) {
+      method = iter->second;
+    }
+    ServerRpcHandler rpc_handler(server_context, method);
+    rpc_handler.StartRpc();
+  }
+
+  {
+    std::unique_lock<std::mutex> lock(mu_);
+    num_running_cb_--;
+    if (shutdown_) {
+      callback_cv_.notify_all();
+    }
+  }
+}
+
+}  // namespace grpc
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
new file mode 100644
index 0000000..d5d0689
--- /dev/null
+++ b/src/cpp/server/server_builder.cc
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc++/server_builder.h>
+
+#include <grpc++/server.h>
+
+namespace grpc {
+
+ServerBuilder::ServerBuilder() : thread_pool_(nullptr) {}
+
+void ServerBuilder::RegisterService(RpcService* service) {
+  services_.push_back(service);
+}
+
+void ServerBuilder::AddPort(const grpc::string& addr) {
+  ports_.push_back(addr);
+}
+
+void ServerBuilder::SetThreadPool(ThreadPoolInterface* thread_pool) {
+  thread_pool_ = thread_pool;
+}
+
+std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
+  std::unique_ptr<Server> server(new Server(thread_pool_));
+  for (auto* service : services_) {
+    server->RegisterService(service);
+  }
+  for (auto& port : ports_) {
+    server->AddPort(port);
+  }
+  server->Start();
+  return server;
+}
+
+}  // namespace grpc
diff --git a/src/cpp/server/server_rpc_handler.cc b/src/cpp/server/server_rpc_handler.cc
new file mode 100644
index 0000000..2d5a081
--- /dev/null
+++ b/src/cpp/server/server_rpc_handler.cc
@@ -0,0 +1,108 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/cpp/server/server_rpc_handler.h"
+
+#include <grpc/support/log.h>
+#include "src/cpp/server/rpc_service_method.h"
+#include <grpc++/async_server_context.h>
+
+namespace grpc {
+
+ServerRpcHandler::ServerRpcHandler(AsyncServerContext* server_context,
+                                   RpcServiceMethod* method)
+    : server_context_(server_context),
+      method_(method) {
+}
+
+void ServerRpcHandler::StartRpc() {
+  // Start the rpc on this dedicated completion queue.
+  server_context_->Accept(cq_.cq());
+
+  if (method_ == nullptr) {
+    // Method not supported, finish the rpc with error.
+    // TODO(rocking): do we need to call read to consume the request?
+    FinishRpc(Status(StatusCode::UNIMPLEMENTED, "No such method."));
+    return;
+  }
+
+  // Allocate request and response.
+  std::unique_ptr<google::protobuf::Message> request(method_->AllocateRequestProto());
+  std::unique_ptr<google::protobuf::Message> response(method_->AllocateResponseProto());
+
+  // Read request
+  server_context_->StartRead(request.get());
+  auto type = WaitForNextEvent();
+  GPR_ASSERT(type == CompletionQueue::SERVER_READ_OK);
+
+  // Run the application's rpc handler
+  MethodHandler* handler = method_->handler();
+  Status status = handler->RunHandler(
+      MethodHandler::HandlerParameter(request.get(), response.get()));
+
+  if (status.IsOk()) {
+    // Send the response if we get an ok status.
+    server_context_->StartWrite(*response, 0);
+    type = WaitForNextEvent();
+    if (type != CompletionQueue::SERVER_WRITE_OK) {
+      status = Status(StatusCode::INTERNAL, "Error writing response.");
+    }
+  }
+
+  FinishRpc(status);
+}
+
+CompletionQueue::CompletionType ServerRpcHandler::WaitForNextEvent() {
+  void* tag = nullptr;
+  CompletionQueue::CompletionType type = cq_.Next(&tag);
+  if (type != CompletionQueue::QUEUE_CLOSED &&
+      type != CompletionQueue::RPC_END) {
+    GPR_ASSERT(static_cast<AsyncServerContext*>(tag) == server_context_.get());
+  }
+  return type;
+}
+
+void ServerRpcHandler::FinishRpc(const Status& status) {
+  server_context_->StartWriteStatus(status);
+  CompletionQueue::CompletionType type = WaitForNextEvent();
+  // TODO(rocking): do we care about this return type?
+
+  type = WaitForNextEvent();
+  GPR_ASSERT(type == CompletionQueue::RPC_END);
+
+  cq_.Shutdown();
+  type = WaitForNextEvent();
+  GPR_ASSERT(type == CompletionQueue::QUEUE_CLOSED);
+}
+
+}  // namespace grpc
diff --git a/src/cpp/server/server_rpc_handler.h b/src/cpp/server/server_rpc_handler.h
new file mode 100644
index 0000000..ca48fd7
--- /dev/null
+++ b/src/cpp/server/server_rpc_handler.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_INTERNAL_SERVER_SERVER_RPC_HANDLER_H__
+#define __GRPCPP_INTERNAL_SERVER_SERVER_RPC_HANDLER_H__
+
+#include <memory>
+
+#include <grpc++/completion_queue.h>
+#include <grpc++/status.h>
+
+namespace grpc {
+
+class AsyncServerContext;
+class RpcServiceMethod;
+
+class ServerRpcHandler {
+ public:
+  // Takes ownership of server_context.
+  ServerRpcHandler(AsyncServerContext* server_context,
+                   RpcServiceMethod* method);
+
+  void StartRpc();
+
+ private:
+  CompletionQueue::CompletionType WaitForNextEvent();
+  void FinishRpc(const Status& status);
+
+  std::unique_ptr<AsyncServerContext> server_context_;
+  RpcServiceMethod* method_;
+  CompletionQueue cq_;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_INTERNAL_SERVER_SERVER_RPC_HANDLER_H__
diff --git a/src/cpp/server/thread_pool.cc b/src/cpp/server/thread_pool.cc
new file mode 100644
index 0000000..ce364c4
--- /dev/null
+++ b/src/cpp/server/thread_pool.cc
@@ -0,0 +1,77 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/cpp/server/thread_pool.h"
+
+namespace grpc {
+
+ThreadPool::ThreadPool(int num_threads) {
+  for (int i = 0; i < num_threads; i++) {
+    threads_.push_back(std::thread([=]() {
+      for (;;) {
+        std::unique_lock<std::mutex> lock(mu_);
+        // Wait until work is available or we are shutting down.
+        cv_.wait(lock, [=]() { return shutdown_ || !callbacks_.empty(); });
+        // Drain callbacks before considering shutdown to ensure all work
+        // gets completed.
+        if (!callbacks_.empty()) {
+          auto cb = callbacks_.front();
+          callbacks_.pop();
+          lock.unlock();
+          cb();
+        } else if (shutdown_) {
+          return;
+        }
+      }
+    }));
+  }
+}
+
+ThreadPool::~ThreadPool() {
+  {
+    std::lock_guard<std::mutex> lock(mu_);
+    shutdown_ = true;
+    cv_.notify_all();
+  }
+  for (auto& t : threads_) {
+    t.join();
+  }
+}
+
+void ThreadPool::ScheduleCallback(const std::function<void()>& callback) {
+  std::lock_guard<std::mutex> lock(mu_);
+  callbacks_.push(callback);
+  cv_.notify_all();
+}
+
+}  // namespace grpc
diff --git a/src/cpp/server/thread_pool.h b/src/cpp/server/thread_pool.h
new file mode 100644
index 0000000..6fc71d6
--- /dev/null
+++ b/src/cpp/server/thread_pool.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_INTERNAL_SERVER_THREAD_POOL_H__
+#define __GRPCPP_INTERNAL_SERVER_THREAD_POOL_H__
+
+#include <grpc++/thread_pool_interface.h>
+
+#include <condition_variable>
+#include <thread>
+#include <mutex>
+#include <queue>
+#include <vector>
+
+namespace grpc {
+
+class ThreadPool : public ThreadPoolInterface {
+ public:
+  explicit ThreadPool(int num_threads);
+  ~ThreadPool();
+
+  void ScheduleCallback(const std::function<void()>& callback) final;
+
+ private:
+  std::mutex mu_;
+  std::condition_variable cv_;
+  bool shutdown_ = false;
+  std::queue<std::function<void()>> callbacks_;
+  std::vector<std::thread> threads_;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_INTERNAL_SERVER_THREAD_POOL_H__
diff --git a/src/cpp/stream/stream_context.cc b/src/cpp/stream/stream_context.cc
new file mode 100644
index 0000000..07e771f
--- /dev/null
+++ b/src/cpp/stream/stream_context.cc
@@ -0,0 +1,276 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/cpp/stream/stream_context.h"
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include "src/cpp/rpc_method.h"
+#include "src/cpp/proto/proto_utils.h"
+#include "src/cpp/util/time.h"
+#include <grpc++/client_context.h>
+#include <grpc++/config.h>
+#include <google/protobuf/message.h>
+
+namespace grpc {
+
+// Client only ctor
+StreamContext::StreamContext(const RpcMethod& method, ClientContext* context,
+                             const google::protobuf::Message* request,
+                             google::protobuf::Message* result)
+    : is_client_(true),
+      method_(&method),
+      context_(context),
+      request_(request),
+      result_(result),
+      invoke_ev_(nullptr),
+      read_ev_(nullptr),
+      write_ev_(nullptr),
+      reading_(false),
+      writing_(false),
+      got_read_(false),
+      got_write_(false),
+      peer_halfclosed_(false),
+      self_halfclosed_(false),
+      stream_finished_(false),
+      waiting_(false) {
+  GPR_ASSERT(method_->method_type() != RpcMethod::RpcType::NORMAL_RPC);
+}
+
+StreamContext::~StreamContext() { cq_poller_.join(); }
+
+void StreamContext::PollingLoop() {
+  grpc_event* ev = nullptr;
+  gpr_timespec absolute_deadline;
+  AbsoluteDeadlineTimepoint2Timespec(context_->absolute_deadline(),
+                                     &absolute_deadline);
+  std::condition_variable* cv_to_notify = nullptr;
+  std::unique_lock<std::mutex> lock(mu_, std::defer_lock);
+  while (1) {
+    cv_to_notify = nullptr;
+    lock.lock();
+    if (stream_finished_ && !reading_ && !writing_) {
+      return;
+    }
+    lock.unlock();
+    ev = grpc_completion_queue_next(context_->cq(), absolute_deadline);
+    lock.lock();
+    if (!ev) {
+      stream_finished_ = true;
+      final_status_ = Status(StatusCode::DEADLINE_EXCEEDED);
+      std::condition_variable* cvs[3] = {reading_ ? &read_cv_ : nullptr,
+                                         writing_ ? &write_cv_ : nullptr,
+                                         waiting_ ? &finish_cv_ : nullptr};
+      got_read_ = reading_;
+      got_write_ = writing_;
+      read_ev_ = nullptr;
+      write_ev_ = nullptr;
+      lock.unlock();
+      for (int i = 0; i < 3; i++) {
+        if (cvs[i]) cvs[i]->notify_one();
+      }
+      break;
+    }
+    switch (ev->type) {
+      case GRPC_READ:
+        GPR_ASSERT(reading_);
+        got_read_ = true;
+        read_ev_ = ev;
+        cv_to_notify = &read_cv_;
+        reading_ = false;
+        break;
+      case GRPC_FINISH_ACCEPTED:
+      case GRPC_WRITE_ACCEPTED:
+        got_write_ = true;
+        write_ev_ = ev;
+        cv_to_notify = &write_cv_;
+        writing_ = false;
+        break;
+      case GRPC_FINISHED: {
+        grpc::string error_details(
+            ev->data.finished.details ? ev->data.finished.details : "");
+        final_status_ = Status(static_cast<StatusCode>(ev->data.finished.code),
+                               error_details);
+        grpc_event_finish(ev);
+        stream_finished_ = true;
+        if (waiting_) {
+          cv_to_notify = &finish_cv_;
+        }
+        break;
+      }
+      case GRPC_INVOKE_ACCEPTED:
+        invoke_ev_ = ev;
+        cv_to_notify = &invoke_cv_;
+        break;
+      case GRPC_CLIENT_METADATA_READ:
+        grpc_event_finish(ev);
+        break;
+      default:
+        grpc_event_finish(ev);
+        // not handling other types now
+        gpr_log(GPR_ERROR, "unknown event type");
+        abort();
+    }
+    lock.unlock();
+    if (cv_to_notify) {
+      cv_to_notify->notify_one();
+    }
+  }
+}
+
+void StreamContext::Start(bool buffered) {
+  // TODO(yangg) handle metadata send path
+  int flag = buffered ? GRPC_WRITE_BUFFER_HINT : 0;
+  grpc_call_error error = grpc_call_start_invoke(
+      context_->call(), context_->cq(), this, this, this, flag);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  // kicks off the poller thread
+  cq_poller_ = std::thread(&StreamContext::PollingLoop, this);
+  std::unique_lock<std::mutex> lock(mu_);
+  while (!invoke_ev_) {
+    invoke_cv_.wait(lock);
+  }
+  lock.unlock();
+  GPR_ASSERT(invoke_ev_->data.invoke_accepted == GRPC_OP_OK);
+  grpc_event_finish(invoke_ev_);
+}
+
+namespace {
+// Wait for got_event with event_cv protected by mu, return event.
+grpc_event* WaitForEvent(bool* got_event, std::condition_variable* event_cv,
+                         std::mutex* mu, grpc_event** event) {
+  std::unique_lock<std::mutex> lock(*mu);
+  while (*got_event == false) {
+    event_cv->wait(lock);
+  }
+  *got_event = false;
+  return *event;
+}
+}  // namespace
+
+bool StreamContext::Read(google::protobuf::Message* msg) {
+  std::unique_lock<std::mutex> lock(mu_);
+  if (stream_finished_) {
+    peer_halfclosed_ = true;
+    return false;
+  }
+  reading_ = true;
+  lock.unlock();
+
+  grpc_call_error err = grpc_call_start_read(context_->call(), this);
+  GPR_ASSERT(err == GRPC_CALL_OK);
+
+  grpc_event* ev = WaitForEvent(&got_read_, &read_cv_, &mu_, &read_ev_);
+  if (!ev) {
+    return false;
+  }
+  GPR_ASSERT(ev->type == GRPC_READ);
+  bool ret = true;
+  if (ev->data.read) {
+    if (!DeserializeProto(ev->data.read, msg)) {
+      ret = false;  // parse error
+                    // TODO(yangg) cancel the stream.
+    }
+  } else {
+    ret = false;
+    peer_halfclosed_ = true;
+  }
+  grpc_event_finish(ev);
+  return ret;
+}
+
+bool StreamContext::Write(const google::protobuf::Message* msg, bool is_last) {
+  bool ret = true;
+  grpc_event* ev = nullptr;
+
+  std::unique_lock<std::mutex> lock(mu_);
+  if (stream_finished_) {
+    self_halfclosed_ = true;
+    return false;
+  }
+  writing_ = true;
+  lock.unlock();
+
+  if (msg) {
+    grpc_byte_buffer* out_buf = nullptr;
+    if (!SerializeProto(*msg, &out_buf)) {
+      FinishStream(Status(StatusCode::INVALID_ARGUMENT,
+                          "Failed to serialize request proto"),
+                   true);
+      return false;
+    }
+    int flag = is_last ? GRPC_WRITE_BUFFER_HINT : 0;
+    grpc_call_error err =
+        grpc_call_start_write(context_->call(), out_buf, this, flag);
+    grpc_byte_buffer_destroy(out_buf);
+    GPR_ASSERT(err == GRPC_CALL_OK);
+
+    ev = WaitForEvent(&got_write_, &write_cv_, &mu_, &write_ev_);
+    if (!ev) {
+      return false;
+    }
+    GPR_ASSERT(ev->type == GRPC_WRITE_ACCEPTED);
+
+    ret = ev->data.write_accepted == GRPC_OP_OK;
+    grpc_event_finish(ev);
+  }
+  if (is_last) {
+    grpc_call_error err = grpc_call_writes_done(context_->call(), this);
+    GPR_ASSERT(err == GRPC_CALL_OK);
+    ev = WaitForEvent(&got_write_, &write_cv_, &mu_, &write_ev_);
+    if (!ev) {
+      return false;
+    }
+    GPR_ASSERT(ev->type == GRPC_FINISH_ACCEPTED);
+    grpc_event_finish(ev);
+    self_halfclosed_ = true;
+  }
+  return ret;
+}
+
+const Status& StreamContext::Wait() {
+  std::unique_lock<std::mutex> lock(mu_);
+  // TODO(yangg) if not halfclosed cancel the stream
+  GPR_ASSERT(self_halfclosed_);
+  GPR_ASSERT(peer_halfclosed_);
+  GPR_ASSERT(!waiting_);
+  waiting_ = true;
+  while (!stream_finished_) {
+    finish_cv_.wait(lock);
+  }
+  return final_status_;
+}
+
+void StreamContext::FinishStream(const Status& status, bool send) { return; }
+
+}  // namespace grpc
diff --git a/src/cpp/stream/stream_context.h b/src/cpp/stream/stream_context.h
new file mode 100644
index 0000000..b7f462f
--- /dev/null
+++ b/src/cpp/stream/stream_context.h
@@ -0,0 +1,105 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_INTERNAL_STREAM_STREAM_CONTEXT_H__
+#define __GRPCPP_INTERNAL_STREAM_STREAM_CONTEXT_H__
+
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+
+#include <grpc++/status.h>
+#include <grpc++/stream_context_interface.h>
+
+namespace google {
+namespace protobuf {
+class Message;
+}
+}
+
+struct grpc_event;
+
+namespace grpc {
+class ClientContext;
+class RpcMethod;
+
+class StreamContext : public StreamContextInterface {
+ public:
+  StreamContext(const RpcMethod& method, ClientContext* context,
+                const google::protobuf::Message* request, google::protobuf::Message* result);
+  ~StreamContext();
+  // Start the stream, if there is a final write following immediately, set
+  // buffered so that the messages can be sent in batch.
+  void Start(bool buffered) override;
+  bool Read(google::protobuf::Message* msg) override;
+  bool Write(const google::protobuf::Message* msg, bool is_last) override;
+  const Status& Wait() override;
+  void FinishStream(const Status& status, bool send) override;
+
+  const google::protobuf::Message* request() override { return request_; }
+  google::protobuf::Message* response() override { return result_; }
+
+ private:
+  void PollingLoop();
+  bool BlockingStart();
+  bool is_client_;
+  const RpcMethod* method_;         // not owned
+  ClientContext* context_;          // now owned
+  const google::protobuf::Message* request_;  // not owned
+  google::protobuf::Message* result_;         // not owned
+
+  std::thread cq_poller_;
+  std::mutex mu_;
+  std::condition_variable invoke_cv_;
+  std::condition_variable read_cv_;
+  std::condition_variable write_cv_;
+  std::condition_variable finish_cv_;
+  grpc_event* invoke_ev_;
+  // TODO(yangg) make these two into queues to support concurrent reads and
+  // writes
+  grpc_event* read_ev_;
+  grpc_event* write_ev_;
+  bool reading_;
+  bool writing_;
+  bool got_read_;
+  bool got_write_;
+  bool peer_halfclosed_;
+  bool self_halfclosed_;
+  bool stream_finished_;
+  bool waiting_;
+  Status final_status_;
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_INTERNAL_STREAM_STREAM_CONTEXT_H__
diff --git a/src/cpp/util/status.cc b/src/cpp/util/status.cc
new file mode 100644
index 0000000..66be26d
--- /dev/null
+++ b/src/cpp/util/status.cc
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <grpc++/status.h>
+
+namespace grpc {
+
+const Status& Status::OK = Status();
+const Status& Status::Cancelled = Status(StatusCode::CANCELLED);
+
+}  // namespace grpc
diff --git a/src/cpp/util/time.cc b/src/cpp/util/time.cc
new file mode 100644
index 0000000..207bebf
--- /dev/null
+++ b/src/cpp/util/time.cc
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/cpp/util/time.h"
+
+#include <grpc/support/time.h>
+
+using std::chrono::duration_cast;
+using std::chrono::nanoseconds;
+using std::chrono::seconds;
+using std::chrono::system_clock;
+
+namespace grpc {
+
+void AbsoluteDeadlineTimepoint2Timespec(const system_clock::time_point& from,
+                                        gpr_timespec* to) {
+  system_clock::duration deadline = from.time_since_epoch();
+  seconds secs = duration_cast<seconds>(deadline);
+  nanoseconds nsecs = duration_cast<nanoseconds>(deadline - secs);
+  to->tv_sec = secs.count();
+  to->tv_nsec = nsecs.count();
+}
+
+system_clock::time_point AbsoluteDeadlineTimespec2Timepoint(gpr_timespec t) {
+  system_clock::time_point tp;
+  tp += seconds(t.tv_sec);
+  tp += nanoseconds(t.tv_nsec);
+  return tp;
+}
+
+}  // namespace grpc
diff --git a/src/cpp/util/time.h b/src/cpp/util/time.h
new file mode 100644
index 0000000..c21fba7
--- /dev/null
+++ b/src/cpp/util/time.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_INTERNAL_UTIL_TIME_H__
+#define __GRPCPP_INTERNAL_UTIL_TIME_H__
+
+#include <chrono>
+
+#include <grpc/support/time.h>
+
+namespace grpc {
+
+// from and to should be absolute time.
+void AbsoluteDeadlineTimepoint2Timespec(
+    const std::chrono::system_clock::time_point& from, gpr_timespec* to);
+
+std::chrono::system_clock::time_point AbsoluteDeadlineTimespec2Timepoint(
+    gpr_timespec t);
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_INTERNAL_UTIL_TIME_H__
diff --git a/templates/Makefile.template b/templates/Makefile.template
new file mode 100644
index 0000000..680941b
--- /dev/null
+++ b/templates/Makefile.template
@@ -0,0 +1,411 @@
+# GRPC global makefile
+# This currently builds C and C++ code.
+<%!
+  from copy import deepcopy
+  import re
+
+  def excluded(filename, exclude_res):
+    for r in exclude_res:
+      if r.match(filename):
+        return True
+    return False
+%>
+
+<%
+  altlibs = []
+  for lib in libs:
+    for alt in lib.get('alternates', []):
+      new = deepcopy(lib)
+      new.name = alt.name
+      new.alternates = []
+      exclude_res = [re.compile(str) for str in alt.get('exclude_res', [])]
+
+      src = [file for file in new.get('src', []) if not excluded(file, exclude_res)]
+      src.extend(alt.get('include_src', []))
+      new.src = src
+
+      headers = [file for file in new.get('headers', []) if not excluded(file, exclude_res)]
+      headers.extend(alt.get('include_headers', []))
+      new.headers = headers
+
+      public_headers = [file for file in new.get('public_headers', []) if not excluded(file, exclude_res)]
+      public_headers.extend(alt.get('include_public_headers', []))
+      new.public_headers = public_headers
+
+      for prop in alt.properties:
+        new[prop.name] = prop.value
+
+      altlibs.append(new)
+  libs.extend(altlibs)
+
+  protos_dict = {}
+  proto_re = re.compile('\.proto$')
+  for lib in libs:
+    for src in lib.src:
+      if proto_re.match(src):
+        protos_dict[src] = True
+  for tgt in targets:
+    for src in tgt.src:
+      if proto_re.match(src):
+        protos_dict[src] = True
+
+  protos = []
+  for k, v in protos_dict:
+    protos.append(k)
+%>
+
+# General settings.
+# You may want to change these depending on your system.
+
+prefix ?= /usr/local
+
+PROTOC = protoc
+CC = gcc
+CXX = g++
+LD = gcc
+LDXX = g++
+AR = ar
+STRIP = strip --strip-unneeded
+INSTALL = install -D
+RM = rm -f
+
+ifeq ($(DEBUG),)
+CPPFLAGS += -O2
+DEFINES += NDEBUG
+else
+CPPFLAGS += -O0
+DEFINES += _DEBUG DEBUG
+endif
+
+CFLAGS += -std=c89 -pedantic
+CXXFLAGS += -std=c++11
+CPPFLAGS += -g -fPIC -Wall -Werror -Wno-long-long
+LDFLAGS += -g -pthread -fPIC
+
+INCLUDES = . include gens
+LIBS = rt m z event event_pthreads pthread
+LIBSXX = protobuf
+LIBS_SECURE = ssl crypto dl
+
+ifneq ($(wildcard /usr/src/gtest/src/gtest-all.cc),)
+GTEST_LIB = /usr/src/gtest/src/gtest-all.cc -I/usr/src/gtest
+else
+GTEST_LIB = -lgtest
+endif
+
+ifeq ($(V),1)
+E = @:
+Q =
+else
+E = @echo
+Q = @
+endif
+
+VERSION = ${settings.version.major}.${settings.version.minor}.${settings.version.micro}.${settings.version.build}
+
+CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
+CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
+
+LDFLAGS += $(ARCH_FLAGS)
+LDLIBS += $(addprefix -l, $(LIBS))
+LDLIBSXX += $(addprefix -l, $(LIBSXX))
+LDLIBS_SECURE += $(addprefix -l, $(LIBS_SECURE))
+
+.SECONDARY = %.pb.h %.pb.cc
+
+all: static shared\
+% for tgt in targets:
+% if tgt.build == 'all':
+ bins/${tgt.name}\
+% endif
+% endfor
+
+
+static: make_dirs dep\
+% for lib in libs:
+% if lib.build == 'all':
+ libs/lib${lib.name}.a\
+% endif
+% endfor
+
+
+shared: make_dirs dep\
+% for lib in libs:
+% if lib.build == 'all':
+ libs/lib${lib.name}.so.$(VERSION)\
+% endif
+% endfor
+
+
+privatelibs: make_dirs dep\
+% for lib in libs:
+% if lib.build == 'private':
+ libs/lib${lib.name}.a\
+% endif
+% endfor
+
+
+buildtests: privatelibs\
+% for tgt in targets:
+% if tgt.build == 'test':
+ bins/${tgt.name}\
+% endif
+% endfor
+
+
+buildtests_c: privatelibs\
+% for tgt in targets:
+% if tgt.build == 'test' and not tgt.get('c++', False):
+ bins/${tgt.name}\
+% endif
+% endfor
+
+
+tests: buildtests
+% for tgt in targets:
+% if tgt.build == 'test' and tgt.get('run', True):
+	$(E) "[RUN]     Testing ${tgt.name}"
+	$(Q) ./bins/${tgt.name} || ( echo test ${tgt.name} failed ; exit 1 )
+% endif
+% endfor
+
+
+tools: privatelibs\
+% for tgt in targets:
+% if tgt.build == 'tool':
+ bins/${tgt.name}\
+% endif
+% endfor
+
+
+buildbenchmarks: privatelibs\
+% for tgt in targets:
+% if tgt.build == 'benchmark':
+ bins/${tgt.name}\
+% endif
+% endfor
+
+
+benchmarks: buildbenchmarks
+
+make_dirs:
+	$(Q) mkdir -p libs
+	$(Q) mkdir -p bins
+	$(Q) mkdir -p gens
+
+strip: strip-static strip-shared
+
+strip-static: static
+% for lib in libs:
+% if lib.build == "all":
+	$(E) "[STRIP]   Stripping lib${lib.name}.a"
+	$(Q) $(STRIP) libs/lib${lib.name}.a
+% endif
+% endfor
+
+strip-shared: shared
+% for lib in libs:
+% if lib.build == "all":
+	$(E) "[STRIP]   Stripping lib${lib.name}.so"
+	$(Q) $(STRIP) libs/lib${lib.name}.so.$(VERSION)
+% endif
+% endfor
+
+gens/%.pb.cc : %.proto
+	$(E) "[PROTOC]  Generating protobuf CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --cpp_out=gens $<
+
+deps/%.dep : %.c
+	$(E) "[DEP]     Generating dependencies for $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(CC) $(CFLAGS) $(CPPFLAGS_NO_ARCH) -MG -M $< > $@
+
+deps/%.dep : gens/%.pb.cc
+	$(E) "[DEP]     Generating dependencies for $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS_NO_ARCH) -MG -M $< > $@
+
+deps/%.dep : %.cc
+	$(E) "[DEP]     Generating dependencies for $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS_NO_ARCH) -MG -M $< > $@
+
+objs/%.o : %.c
+	$(E) "[C]       Compiling $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+objs/%.o : gens/%.pb.cc
+	$(E) "[CXX]     Compiling $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+objs/%.o : %.cc
+	$(E) "[CXX]     Compiling $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+dep:\
+% for lib in libs:
+ deps_lib${lib.name}\
+% endfor
+% for tgt in targets:
+ deps_${tgt.name}\
+% endfor
+
+
+install: install-headers install-static install-shared
+
+install-headers:
+	$(E) "[INSTALL] Installing public headers"
+	$(Q) $(foreach h, $(PUBLIC_HEADERS), $(INSTALL) $(h) $(prefix)/$(h) && ) exit 0 || exit 1
+
+install-static: static strip-static
+% for lib in libs:
+% if lib.build == "all":
+	$(E) "[INSTALL] Installing lib${lib.name}.a"
+	$(Q) $(INSTALL) libs/lib${lib.name}.a $(prefix)/lib/lib${lib.name}.a
+% endif
+% endfor
+
+install-shared: shared strip-shared
+% for lib in libs:
+% if lib.build == "all":
+	$(E) "[INSTALL] Installing lib${lib.name}.so"
+	$(Q) $(INSTALL) libs/lib${lib.name}.so.$(VERSION) $(prefix)/lib/lib${lib.name}.so.$(VERSION)
+% endif
+% endfor
+
+clean:\
+% for lib in libs:
+ clean_lib${lib.name}\
+% endfor
+% for tgt in targets:
+ clean_${tgt.name}\
+% endfor
+
+	$(Q) $(RM) -r deps objs libs bins gens
+
+
+# The various libraries
+
+% for lib in libs:
+${makelib(lib)}
+% endfor
+
+
+# All of the test targets
+
+% for tgt in targets:
+${maketarget(tgt)}
+% endfor
+
+<%def name="makelib(lib)">
+LIB${lib.name.upper()}_SRC = \\
+
+% for src in lib.src:
+    ${src} \\
+
+% endfor
+
+% if "public_headers" in lib:
+PUBLIC_HEADERS += \\
+
+% for hdr in lib.public_headers:
+    ${hdr} \\
+
+% endfor
+% endif
+
+LIB${lib.name.upper()}_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(LIB${lib.name.upper()}_SRC))))
+LIB${lib.name.upper()}_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(LIB${lib.name.upper()}_SRC))))
+
+libs/lib${lib.name}.a: $(LIB${lib.name.upper()}_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) $(AR) rcs libs/lib${lib.name}.a $(LIB${lib.name.upper()}_OBJS)
+
+% if lib.build == "all":
+libs/lib${lib.name}.so.$(VERSION): $(LIB${lib.name.upper()}_OBJS)
+	$(E) "[LD]      Linking $@"
+% if lib.get('c++', False):
+	$(Q) $(LDXX) $(LDFLAGS) -shared -Wl,-soname,lib${lib.name}.so.${settings.version.major} \
+% else:
+	$(Q) $(LD) $(LDFLAGS) -shared -Wl,-soname,lib${lib.name}.so.${settings.version.major} \
+% endif
+-o libs/lib${lib.name}.so.$(VERSION) $(LIB${lib.name.upper()}_OBJS) $(LDLIBS)\
+% if lib.secure:
+ $(LDLIBS_SECURE)
+% endif
+% endif
+
+
+deps_lib${lib.name}: $(LIB${lib.name.upper()}_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(LIB${lib.name.upper()}_DEPS)
+endif
+
+clean_lib${lib.name}:
+	$(E) "[CLEAN]   Cleaning lib${lib.name} files"
+	$(Q) $(RM) $(LIB${lib.name.upper()}_OBJS)
+	$(Q) $(RM) $(LIB${lib.name.upper()}_DEPS)
+	$(Q) $(RM) libs/lib${lib.name}.a
+	$(Q) $(RM) libs/lib${lib.name}.so.$(VERSION)
+</%def>
+
+<%def name="maketarget(tgt)">
+${tgt.name.upper()}_SRC = \\
+
+% for src in tgt.src:
+    ${src} \\
+
+% endfor
+
+${tgt.name.upper()}_OBJS = $(addprefix objs/, $(addsuffix .o, $(basename $(${tgt.name.upper()}_SRC))))
+${tgt.name.upper()}_DEPS = $(addprefix deps/, $(addsuffix .dep, $(basename $(${tgt.name.upper()}_SRC))))
+
+bins/${tgt.name}: $(${tgt.name.upper()}_OBJS)\
+% for dep in tgt.deps:
+ libs/lib${dep}.a\
+% endfor
+
+	$(E) "[LD]      Linking $@"
+% if tgt.get("c++", False):
+	$(Q) $(LDXX) $(LDFLAGS) $(${tgt.name.upper()}_OBJS) $(GTEST_LIB) -Llibs\
+% else:
+	$(Q) $(LD) $(LDFLAGS) $(${tgt.name.upper()}_OBJS) -Llibs\
+% endif
+% for dep in tgt.deps:
+ -l${dep}\
+% endfor
+% if tgt.get("c++", False):
+ $(LDLIBSXX)\
+% endif
+ $(LDLIBS)\
+% if tgt.get('secure', True):
+ $(LDLIBS_SECURE)\
+% endif
+ -o bins/${tgt.name}
+
+deps_${tgt.name}: $(${tgt.name.upper()}_DEPS)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(${tgt.name.upper()}_DEPS)
+endif
+
+clean_${tgt.name}:
+	$(E) "[CLEAN]   Cleaning ${tgt.name} files"
+	$(Q) $(RM) $(${tgt.name.upper()}_OBJS)
+	$(Q) $(RM) $(${tgt.name.upper()}_DEPS)
+	$(Q) $(RM) bins/${tgt.name}
+</%def>
+
+.PHONY: all strip tools buildtests tests make_dirs install clean\
+% for lib in libs:
+ deps_lib${lib.name} clean_lib${lib.name}\
+% endfor
+% for tgt in targets:
+ deps_${tgt.name} clean_${tgt.name}\
+% endfor
+
diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c
new file mode 100644
index 0000000..44ede2f
--- /dev/null
+++ b/test/core/channel/channel_stack_test.c
@@ -0,0 +1,139 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/channel/channel_stack.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+#define LOG_TEST_NAME() gpr_log(GPR_INFO, "%s", __FUNCTION__)
+
+static void channel_init_func(grpc_channel_element *elem,
+                              const grpc_channel_args *args,
+                              grpc_mdctx *metadata_context, int is_first,
+                              int is_last) {
+  GPR_ASSERT(args->num_args == 1);
+  GPR_ASSERT(args->args[0].type == GRPC_ARG_INTEGER);
+  GPR_ASSERT(0 == strcmp(args->args[0].key, "test_key"));
+  GPR_ASSERT(args->args[0].value.integer == 42);
+  GPR_ASSERT(is_first);
+  GPR_ASSERT(is_last);
+  *(int *)(elem->channel_data) = 0;
+}
+
+static void call_init_func(grpc_call_element *elem,
+                           const void *server_transport_data) {
+  ++*(int *)(elem->channel_data);
+  *(int *)(elem->call_data) = 0;
+}
+
+static void channel_destroy_func(grpc_channel_element *elem) {}
+
+static void call_destroy_func(grpc_call_element *elem) {
+  ++*(int *)(elem->channel_data);
+}
+
+static void call_func(grpc_call_element *elem, grpc_call_op *op) {
+  ++*(int *)(elem->call_data);
+}
+
+static void channel_func(grpc_channel_element *elem, grpc_channel_op *op) {
+  ++*(int *)(elem->channel_data);
+}
+
+static void test_create_channel_stack() {
+  const grpc_channel_filter filter = {
+      call_func,   channel_func,
+
+      sizeof(int), call_init_func,    call_destroy_func,
+
+      sizeof(int), channel_init_func, channel_destroy_func,
+  };
+  const grpc_channel_filter *filters = &filter;
+  grpc_channel_stack *channel_stack;
+  grpc_call_stack *call_stack;
+  grpc_channel_element *channel_elem;
+  grpc_call_element *call_elem;
+  grpc_arg arg;
+  grpc_channel_args chan_args;
+  grpc_mdctx *metadata_context;
+  int *channel_data;
+  int *call_data;
+
+  LOG_TEST_NAME();
+
+  metadata_context = grpc_mdctx_create();
+
+  arg.type = GRPC_ARG_INTEGER;
+  arg.key = "test_key";
+  arg.value.integer = 42;
+
+  chan_args.num_args = 1;
+  chan_args.args = &arg;
+
+  channel_stack = gpr_malloc(grpc_channel_stack_size(&filters, 1));
+  grpc_channel_stack_init(&filters, 1, &chan_args, metadata_context,
+                          channel_stack);
+  GPR_ASSERT(channel_stack->count == 1);
+  channel_elem = grpc_channel_stack_element(channel_stack, 0);
+  channel_data = (int *)channel_elem->channel_data;
+  GPR_ASSERT(*channel_data == 0);
+
+  call_stack = gpr_malloc(channel_stack->call_stack_size);
+  grpc_call_stack_init(channel_stack, NULL, call_stack);
+  GPR_ASSERT(call_stack->count == 1);
+  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;
+  GPR_ASSERT(*call_data == 0);
+  GPR_ASSERT(*channel_data == 1);
+
+  grpc_call_stack_destroy(call_stack);
+  gpr_free(call_stack);
+  GPR_ASSERT(*channel_data == 2);
+
+  grpc_channel_stack_destroy(channel_stack);
+  gpr_free(channel_stack);
+
+  grpc_mdctx_orphan(metadata_context);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_create_channel_stack();
+  return 0;
+}
diff --git a/test/core/channel/metadata_buffer_test.c b/test/core/channel/metadata_buffer_test.c
new file mode 100644
index 0000000..4a60b53
--- /dev/null
+++ b/test/core/channel/metadata_buffer_test.c
@@ -0,0 +1,194 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/channel/metadata_buffer.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/* construct a buffer with some prefix followed by an integer converted to
+   a string */
+static gpr_slice construct_buffer(size_t prefix_length, size_t index) {
+  gpr_slice buffer = gpr_slice_malloc(prefix_length + 32);
+  memset(GPR_SLICE_START_PTR(buffer), 'a', prefix_length);
+  GPR_SLICE_SET_LENGTH(
+      buffer, prefix_length +
+                  sprintf((char *)GPR_SLICE_START_PTR(buffer) + prefix_length,
+                          "%d", (int)index));
+  return buffer;
+}
+
+static void do_nothing(void *ignored, grpc_op_error also_ignored) {}
+
+/* we need a fake channel & call stack, which is defined here */
+
+/* a fake channel needs to track some information about the test */
+typedef struct {
+  size_t key_prefix_len;
+  size_t value_prefix_len;
+} channel_data;
+
+static void fail_call_op(grpc_call_element *elem, grpc_call_op *op) { abort(); }
+
+/* verify that the metadata passed on during flush is the same as we expect */
+static void expect_call_op(grpc_call_element *elem, grpc_call_op *op) {
+  size_t *n = elem->call_data;
+  channel_data *cd = elem->channel_data;
+  gpr_slice key = construct_buffer(cd->key_prefix_len, *n);
+  gpr_slice value = construct_buffer(cd->value_prefix_len, *n);
+
+  GPR_ASSERT(op->type == GRPC_SEND_METADATA);
+  GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
+  GPR_ASSERT(op->flags == *n);
+  GPR_ASSERT(op->done_cb == do_nothing);
+  GPR_ASSERT(op->user_data == (void *)(gpr_uintptr) * n);
+  GPR_ASSERT(0 == gpr_slice_cmp(op->data.metadata->key->slice, key));
+  GPR_ASSERT(0 == gpr_slice_cmp(op->data.metadata->value->slice, value));
+
+  ++*n;
+
+  gpr_slice_unref(key);
+  gpr_slice_unref(value);
+  grpc_mdelem_unref(op->data.metadata);
+}
+
+static void fail_channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+  abort();
+}
+
+static void init_call_elem(grpc_call_element *elem,
+                           const void *transport_server_data) {
+  *(size_t *)elem->call_data = 0;
+}
+
+static void destroy_call_elem(grpc_call_element *elem) {}
+
+static void init_channel_elem(grpc_channel_element *elem,
+                              const grpc_channel_args *args, grpc_mdctx *mdctx,
+                              int is_first, int is_last) {}
+
+static void destroy_channel_elem(grpc_channel_element *elem) {}
+
+static const grpc_channel_filter top_filter = {
+    fail_call_op,      fail_channel_op,     sizeof(size_t),
+    init_call_elem,    destroy_call_elem,   sizeof(channel_data),
+    init_channel_elem, destroy_channel_elem};
+
+static const grpc_channel_filter bottom_filter = {
+    expect_call_op,    fail_channel_op,     sizeof(size_t),
+    init_call_elem,    destroy_call_elem,   sizeof(channel_data),
+    init_channel_elem, destroy_channel_elem};
+
+static const grpc_channel_filter *filters[2] = {&top_filter, &bottom_filter};
+
+/* run a test with differently sized keys, and values, some number of times. */
+static void test_case(size_t key_prefix_len, size_t value_prefix_len,
+                      size_t num_calls) {
+  size_t i;
+  size_t got_calls;
+  grpc_metadata_buffer buffer;
+  grpc_channel_stack *stk;
+  grpc_call_stack *call;
+  grpc_mdctx *mdctx;
+
+  gpr_log(GPR_INFO, "Test %d calls, {key,value}_prefix_len = {%d, %d}",
+          (int)num_calls, (int)key_prefix_len, (int)value_prefix_len);
+
+  mdctx = grpc_mdctx_create();
+
+  grpc_metadata_buffer_init(&buffer);
+
+  /* queue metadata elements */
+  for (i = 0; i < num_calls; i++) {
+    grpc_call_op op;
+    gpr_slice key = construct_buffer(key_prefix_len, i);
+    gpr_slice value = construct_buffer(value_prefix_len, i);
+
+    op.type = GRPC_SEND_METADATA;
+    op.dir = GRPC_CALL_DOWN;
+    op.flags = i;
+    op.data.metadata = grpc_mdelem_from_slices(mdctx, key, value);
+    op.done_cb = do_nothing;
+    op.user_data = (void *)(gpr_uintptr) i;
+
+    grpc_metadata_buffer_queue(&buffer, &op);
+  }
+
+  /* construct a test channel, call stack */
+  stk = gpr_malloc(grpc_channel_stack_size(filters, 2));
+  grpc_channel_stack_init(filters, 2, NULL, mdctx, stk);
+
+  for (i = 0; i < 2; i++) {
+    channel_data *cd =
+        (channel_data *)grpc_channel_stack_element(stk, i)->channel_data;
+    cd->key_prefix_len = key_prefix_len;
+    cd->value_prefix_len = value_prefix_len;
+  }
+
+  call = gpr_malloc(stk->call_stack_size);
+  grpc_call_stack_init(stk, NULL, call);
+
+  /* flush out metadata, verifying each element (see expect_call_op) */
+  grpc_metadata_buffer_flush(&buffer, grpc_call_stack_element(call, 0));
+
+  /* verify expect_call_op was called an appropriate number of times */
+  got_calls = *(size_t *)grpc_call_stack_element(call, 1)->call_data;
+  GPR_ASSERT(num_calls == got_calls);
+
+  /* clean up the things */
+  grpc_call_stack_destroy(call);
+  gpr_free(call);
+  grpc_channel_stack_destroy(stk);
+  gpr_free(stk);
+
+  grpc_metadata_buffer_destroy(&buffer, GRPC_OP_OK);
+  grpc_mdctx_orphan(mdctx);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_case(0, 0, 0);
+  test_case(0, 0, 1);
+  test_case(0, 0, 2);
+  test_case(0, 0, 10000);
+  test_case(10, 10, 1);
+  test_case(10, 10, 2);
+  test_case(10, 10, 10000);
+  test_case(100, 100, 1);
+  test_case(100, 100, 2);
+  test_case(100, 100, 10000);
+  return 0;
+}
diff --git a/test/core/compression/message_compress_test.c b/test/core/compression/message_compress_test.c
new file mode 100644
index 0000000..583f187
--- /dev/null
+++ b/test/core/compression/message_compress_test.c
@@ -0,0 +1,193 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/compression/message_compress.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "test/core/util/test_config.h"
+#include "src/core/support/murmur_hash.h"
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+#include "test/core/util/slice_splitter.h"
+
+typedef enum { ONE_A = 0, ONE_KB_A, ONE_MB_A, TEST_VALUE_COUNT } test_value;
+
+typedef enum {
+  SHOULD_NOT_COMPRESS,
+  SHOULD_COMPRESS,
+  MAYBE_COMPRESSES
+} compressability;
+
+static void assert_passthrough(gpr_slice value,
+                               grpc_compression_algorithm algorithm,
+                               grpc_slice_split_mode uncompressed_split_mode,
+                               grpc_slice_split_mode compressed_split_mode,
+                               compressability compress_result_check) {
+  gpr_slice_buffer input;
+  gpr_slice_buffer compressed_raw;
+  gpr_slice_buffer compressed;
+  gpr_slice_buffer output;
+  gpr_slice final;
+  int was_compressed;
+
+  gpr_log(GPR_INFO,
+          "assert_passthrough: value_length=%d value_hash=0x%08x "
+          "algorithm='%s' uncompressed_split='%s' compressed_split='%s'",
+          GPR_SLICE_LENGTH(value), gpr_murmur_hash3(GPR_SLICE_START_PTR(value),
+                                                    GPR_SLICE_LENGTH(value), 0),
+          grpc_compression_algorithm_name(algorithm),
+          grpc_slice_split_mode_name(uncompressed_split_mode),
+          grpc_slice_split_mode_name(compressed_split_mode));
+
+  gpr_slice_buffer_init(&input);
+  gpr_slice_buffer_init(&compressed_raw);
+  gpr_slice_buffer_init(&compressed);
+  gpr_slice_buffer_init(&output);
+
+  grpc_split_slices_to_buffer(uncompressed_split_mode, &value, 1, &input);
+
+  was_compressed = grpc_msg_compress(algorithm, &input, &compressed_raw);
+  GPR_ASSERT(input.count > 0);
+
+  switch (compress_result_check) {
+    case SHOULD_NOT_COMPRESS:
+      GPR_ASSERT(was_compressed == 0);
+      break;
+    case SHOULD_COMPRESS:
+      GPR_ASSERT(was_compressed == 1);
+      break;
+    case MAYBE_COMPRESSES:
+      /* no check */
+      break;
+  }
+
+  grpc_split_slice_buffer(compressed_split_mode, &compressed_raw, &compressed);
+
+  GPR_ASSERT(grpc_msg_decompress(
+      was_compressed ? algorithm : GRPC_COMPRESS_NONE, &compressed, &output));
+
+  final = grpc_slice_merge(output.slices, output.count);
+  GPR_ASSERT(0 == gpr_slice_cmp(value, final));
+
+  gpr_slice_buffer_destroy(&input);
+  gpr_slice_buffer_destroy(&compressed);
+  gpr_slice_buffer_destroy(&compressed_raw);
+  gpr_slice_buffer_destroy(&output);
+  gpr_slice_unref(final);
+}
+
+static gpr_slice repeated(char c, size_t length) {
+  gpr_slice out = gpr_slice_malloc(length);
+  memset(GPR_SLICE_START_PTR(out), c, length);
+  return out;
+}
+
+static compressability get_compressability(
+    test_value id, grpc_compression_algorithm algorithm) {
+  if (algorithm == GRPC_COMPRESS_NONE) return SHOULD_NOT_COMPRESS;
+  switch (id) {
+    case ONE_A:
+      return SHOULD_NOT_COMPRESS;
+    case ONE_KB_A:
+    case ONE_MB_A:
+      return SHOULD_COMPRESS;
+    case TEST_VALUE_COUNT:
+      abort();
+      break;
+  }
+  return MAYBE_COMPRESSES;
+}
+
+static gpr_slice create_test_value(test_value id) {
+  switch (id) {
+    case ONE_A:
+      return gpr_slice_from_copied_string("a");
+    case ONE_KB_A:
+      return repeated('a', 1024);
+    case ONE_MB_A:
+      return repeated('a', 1024 * 1024);
+    case TEST_VALUE_COUNT:
+      abort();
+      break;
+  }
+  return gpr_slice_from_copied_string("bad value");
+}
+
+static void test_bad_data() {
+  gpr_slice_buffer input;
+  gpr_slice_buffer output;
+  int i;
+
+  gpr_slice_buffer_init(&input);
+  gpr_slice_buffer_init(&output);
+  gpr_slice_buffer_add(&input, gpr_slice_from_copied_string(
+                                   "this is not valid compressed input"));
+
+  for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) {
+    if (i == GRPC_COMPRESS_NONE) continue;
+    GPR_ASSERT(0 == grpc_msg_decompress(i, &input, &output));
+    GPR_ASSERT(0 == output.count);
+  }
+
+  gpr_slice_buffer_destroy(&input);
+  gpr_slice_buffer_destroy(&output);
+}
+
+int main(int argc, char **argv) {
+  int i, j, k, m;
+  grpc_slice_split_mode uncompressed_split_modes[] = {
+      GRPC_SLICE_SPLIT_IDENTITY, GRPC_SLICE_SPLIT_ONE_BYTE};
+  grpc_slice_split_mode compressed_split_modes[] = {GRPC_SLICE_SPLIT_MERGE_ALL,
+                                                    GRPC_SLICE_SPLIT_IDENTITY,
+                                                    GRPC_SLICE_SPLIT_ONE_BYTE};
+
+  grpc_test_init(argc, argv);
+
+  for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) {
+    for (j = 0; j < GPR_ARRAY_SIZE(uncompressed_split_modes); j++) {
+      for (k = 0; k < GPR_ARRAY_SIZE(compressed_split_modes); k++) {
+        for (m = 0; m < TEST_VALUE_COUNT; m++) {
+          gpr_slice slice = create_test_value(m);
+          assert_passthrough(slice, i, j, k, get_compressability(m, i));
+          gpr_slice_unref(slice);
+        }
+      }
+    }
+  }
+
+  test_bad_data();
+
+  return 0;
+}
diff --git a/test/core/echo/client.c b/test/core/echo/client.c
new file mode 100644
index 0000000..1905863
--- /dev/null
+++ b/test/core/echo/client.c
@@ -0,0 +1,139 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <grpc/byte_buffer.h>
+#include "test/core/util/test_config.h"
+
+enum { WRITE_SLICE_LENGTH = 1024, TOTAL_BYTES = 102400 };
+
+/* Start write the next slice, fill slice.data[0..length - 1] with first % 256,
+   (first + 1) % 256, ... (first + length - 1) % 256.
+   Produce a GRPC_WRITE_ACCEPTED event  */
+static void start_write_next_slice(grpc_call *call, int first, int length) {
+  int i = 0;
+  grpc_byte_buffer *byte_buffer = NULL;
+  gpr_slice slice = gpr_slice_malloc(length);
+  for (i = 0; i < length; i++)
+    GPR_SLICE_START_PTR(slice)[i] = (first + i) % 256;
+  byte_buffer = grpc_byte_buffer_create(&slice, 1);
+  GPR_ASSERT(grpc_call_start_write(call, byte_buffer, (void *)1, 0) ==
+             GRPC_CALL_OK);
+  gpr_slice_unref(slice);
+  grpc_byte_buffer_destroy(byte_buffer);
+}
+
+int main(int argc, char **argv) {
+  grpc_channel *channel = NULL;
+  grpc_call *call = NULL;
+  grpc_event *ev = NULL;
+  grpc_byte_buffer_reader *bb_reader = NULL;
+  grpc_completion_queue *cq = NULL;
+  int bytes_written = 0;
+  int bytes_read = 0;
+  int i = 0;
+  int waiting_finishes;
+  gpr_slice read_slice;
+
+  grpc_test_init(argc, argv);
+
+  grpc_init();
+
+  cq = grpc_completion_queue_create();
+
+  GPR_ASSERT(argc == 2);
+  channel = grpc_channel_create(argv[1], NULL);
+  call = grpc_channel_create_call(channel, "/foo", "localhost", gpr_inf_future);
+  GPR_ASSERT(grpc_call_start_invoke(call, cq, (void *)1, (void *)1, (void *)1,
+                                    0) == GRPC_CALL_OK);
+  ev = grpc_completion_queue_next(cq, gpr_inf_future);
+  GPR_ASSERT(ev->data.invoke_accepted == GRPC_OP_OK);
+  grpc_event_finish(ev);
+
+  start_write_next_slice(call, bytes_written, WRITE_SLICE_LENGTH);
+  bytes_written += WRITE_SLICE_LENGTH;
+  GPR_ASSERT(grpc_call_start_read(call, (void *)1) == GRPC_CALL_OK);
+  waiting_finishes = 2;
+  while (waiting_finishes) {
+    ev = grpc_completion_queue_next(cq, gpr_inf_future);
+    switch (ev->type) {
+      case GRPC_WRITE_ACCEPTED:
+        if (bytes_written < TOTAL_BYTES) {
+          start_write_next_slice(call, bytes_written, WRITE_SLICE_LENGTH);
+          bytes_written += WRITE_SLICE_LENGTH;
+        } else {
+          GPR_ASSERT(grpc_call_writes_done(call, (void *)1) == GRPC_CALL_OK);
+        }
+        break;
+      case GRPC_CLIENT_METADATA_READ:
+        break;
+      case GRPC_READ:
+        bb_reader = grpc_byte_buffer_reader_create(ev->data.read);
+        while (grpc_byte_buffer_reader_next(bb_reader, &read_slice)) {
+          for (i = 0; i < GPR_SLICE_LENGTH(read_slice); i++) {
+            GPR_ASSERT(GPR_SLICE_START_PTR(read_slice)[i] == bytes_read % 256);
+            bytes_read++;
+          }
+          gpr_slice_unref(read_slice);
+        }
+        grpc_byte_buffer_reader_destroy(bb_reader);
+        if (bytes_read < TOTAL_BYTES) {
+          GPR_ASSERT(grpc_call_start_read(call, (void *)1) == GRPC_CALL_OK);
+        }
+        break;
+      case GRPC_FINISHED:
+      case GRPC_FINISH_ACCEPTED:
+        waiting_finishes--;
+        break;
+      default:
+        GPR_ASSERT(0 && "unexpected event");
+        break;
+    }
+    grpc_event_finish(ev);
+  }
+  GPR_ASSERT(bytes_read == TOTAL_BYTES);
+  gpr_log(GPR_INFO, "All data have been successfully echoed");
+
+  grpc_call_destroy(call);
+  grpc_channel_destroy(channel);
+  grpc_completion_queue_destroy(cq);
+
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/echo/echo_test.c b/test/core/echo/echo_test.c
new file mode 100644
index 0000000..c699f1e
--- /dev/null
+++ b/test/core/echo/echo_test.c
@@ -0,0 +1,106 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+#define _POSIX_SOURCE
+#include <unistd.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/string.h>
+#include "test/core/util/port.h"
+
+static const char *const kHosts[] = {
+    "127.0.0.1", "::1", "::ffff:127.0.0.1", "localhost",
+};
+
+int main(int argc, char **argv) {
+  char *me = argv[0];
+  char *lslash = strrchr(me, '/');
+  char root[1024];
+  int port = grpc_pick_unused_port_or_die();
+  char *args[3];
+  int status;
+  pid_t svr, cli;
+  int i;
+  /* figure out where we are */
+  if (lslash) {
+    memcpy(root, me, lslash - me);
+    root[lslash - me] = 0;
+  } else {
+    strcpy(root, ".");
+  }
+  /* start the server */
+  svr = fork();
+  if (svr == 0) {
+    gpr_asprintf(&args[0], "%s/echo_server", root);
+    gpr_join_host_port(&args[1], "::", port);
+    args[2] = 0;
+    execv(args[0], args);
+
+    gpr_free(args[0]);
+    gpr_free(args[1]);
+    return 1;
+  }
+  /* wait a little */
+  sleep(2);
+  /* start the clients */
+  for (i = 0; i < sizeof(kHosts) / sizeof(*kHosts); i++) {
+    cli = fork();
+    if (cli == 0) {
+      gpr_asprintf(&args[0], "%s/echo_client", root);
+      gpr_join_host_port(&args[1], kHosts[i], port);
+      args[2] = 0;
+      execv(args[0], args);
+
+      gpr_free(args[0]);
+      gpr_free(args[1]);
+      return 1;
+    }
+    /* wait for client */
+    printf("waiting for client: %s\n", kHosts[i]);
+    if (waitpid(cli, &status, 0) == -1) return 2;
+    if (!WIFEXITED(status)) return 4;
+    if (WEXITSTATUS(status)) return WEXITSTATUS(status);
+  }
+  /* wait for server */
+  printf("checking server\n");
+  if (waitpid(svr, &status, WNOHANG) != 0) return 2;
+  kill(svr, SIGKILL);
+  return 0;
+}
diff --git a/test/core/echo/server.c b/test/core/echo/server.c
new file mode 100644
index 0000000..77383f8
--- /dev/null
+++ b/test/core/echo/server.c
@@ -0,0 +1,149 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "test/core/util/test_config.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+#include <grpc/support/time.h>
+#include "test/core/util/port.h"
+
+static grpc_completion_queue *cq;
+static grpc_server *server;
+
+static const grpc_status status_ok = {GRPC_STATUS_OK, NULL};
+
+typedef struct {
+  gpr_refcount pending_ops;
+  gpr_intmax bytes_read;
+} call_state;
+
+static void request_call() {
+  call_state *tag = gpr_malloc(sizeof(*tag));
+  gpr_ref_init(&tag->pending_ops, 2);
+  tag->bytes_read = 0;
+  grpc_server_request_call(server, tag);
+}
+
+static void assert_read_ok(call_state *s, grpc_byte_buffer *b) {
+  grpc_byte_buffer_reader *bb_reader = NULL;
+  gpr_slice read_slice;
+  int i;
+
+  bb_reader = grpc_byte_buffer_reader_create(b);
+  while (grpc_byte_buffer_reader_next(bb_reader, &read_slice)) {
+    for (i = 0; i < GPR_SLICE_LENGTH(read_slice); i++) {
+      GPR_ASSERT(GPR_SLICE_START_PTR(read_slice)[i] == s->bytes_read % 256);
+      s->bytes_read++;
+    }
+    gpr_slice_unref(read_slice);
+  }
+  grpc_byte_buffer_reader_destroy(bb_reader);
+}
+
+int main(int argc, char **argv) {
+  grpc_event *ev;
+  char *addr;
+  call_state *s;
+
+  grpc_test_init(argc, argv);
+
+  grpc_init();
+  srand(clock());
+
+  if (argc == 2) {
+    addr = gpr_strdup(argv[1]);
+  } else {
+    gpr_join_host_port(&addr, "::", grpc_pick_unused_port_or_die());
+  }
+  gpr_log(GPR_INFO, "creating server on: %s", addr);
+
+  cq = grpc_completion_queue_create();
+  server = grpc_server_create(cq, NULL);
+  GPR_ASSERT(grpc_server_add_http2_port(server, addr));
+  gpr_free(addr);
+  grpc_server_start(server);
+
+  request_call();
+
+  for (;;) {
+    ev = grpc_completion_queue_next(cq, gpr_inf_future);
+    GPR_ASSERT(ev);
+    s = ev->tag;
+    switch (ev->type) {
+      case GRPC_SERVER_RPC_NEW:
+        /* initial ops are already started in request_call */
+        grpc_call_accept(ev->call, cq, s, GRPC_WRITE_BUFFER_HINT);
+        GPR_ASSERT(grpc_call_start_read(ev->call, s) == GRPC_CALL_OK);
+        request_call();
+        break;
+      case GRPC_WRITE_ACCEPTED:
+        GPR_ASSERT(ev->data.write_accepted == GRPC_OP_OK);
+        GPR_ASSERT(grpc_call_start_read(ev->call, s) == GRPC_CALL_OK);
+        break;
+      case GRPC_READ:
+        if (ev->data.read) {
+          assert_read_ok(ev->tag, ev->data.read);
+          GPR_ASSERT(grpc_call_start_write(ev->call, ev->data.read, s,
+                                           GRPC_WRITE_BUFFER_HINT) ==
+                     GRPC_CALL_OK);
+        } else {
+          GPR_ASSERT(grpc_call_start_write_status(ev->call, status_ok, s) ==
+                     GRPC_CALL_OK);
+        }
+        break;
+      case GRPC_FINISH_ACCEPTED:
+      case GRPC_FINISHED:
+        if (gpr_unref(&s->pending_ops)) {
+          grpc_call_destroy(ev->call);
+          gpr_free(s);
+        }
+        break;
+      default:
+        abort();
+    }
+    grpc_event_finish(ev);
+  }
+
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/end2end/README b/test/core/end2end/README
new file mode 100644
index 0000000..31598b6
--- /dev/null
+++ b/test/core/end2end/README
@@ -0,0 +1,10 @@
+Each fixture (under fixtures/) is paired with each test (under tests/) and
+forms a complete end-to-end test.
+
+To add a new test or fixture:
+- add the code to the relevant directory
+- update gen_build_json.py to reflect the change
+- regenerate projects
+// MOE:begin_strip
+- update net/grpc/c/BUILD to reflect the change
+// MOE:end_strip
\ No newline at end of file
diff --git a/test/core/end2end/cq_verifier.c b/test/core/end2end/cq_verifier.c
new file mode 100644
index 0000000..aebb8b4
--- /dev/null
+++ b/test/core/end2end/cq_verifier.c
@@ -0,0 +1,473 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/cq_verifier.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "src/core/surface/event_string.h"
+#include <grpc/byte_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+
+/* a set of metadata we expect to find on an event */
+typedef struct metadata {
+  size_t count;
+  size_t cap;
+  const char **keys;
+  const char **values;
+} metadata;
+
+/* details what we expect to find on a single event - and forms a linked
+   list to detail other expectations */
+typedef struct expectation {
+  struct expectation *next;
+  struct expectation *prev;
+  grpc_completion_type type;
+  void *tag;
+  union {
+    grpc_op_error finish_accepted;
+    grpc_op_error write_accepted;
+    grpc_op_error invoke_accepted;
+    struct {
+      const char *method;
+      const char *host;
+      gpr_timespec deadline;
+      grpc_call **output_call;
+      metadata *metadata;
+    } server_rpc_new;
+    metadata *client_metadata_read;
+    struct {
+      grpc_status status;
+      metadata *metadata;
+    } finished;
+    gpr_slice *read;
+  } data;
+} expectation;
+
+/* the verifier itself */
+struct cq_verifier {
+  /* bound completion queue */
+  grpc_completion_queue *cq;
+  /* the root/sentinal expectation */
+  expectation expect;
+};
+
+cq_verifier *cq_verifier_create(grpc_completion_queue *cq) {
+  cq_verifier *v = gpr_malloc(sizeof(cq_verifier));
+  v->expect.type = GRPC_COMPLETION_DO_NOT_USE;
+  v->expect.tag = NULL;
+  v->expect.next = &v->expect;
+  v->expect.prev = &v->expect;
+  v->cq = cq;
+  return v;
+}
+
+void cq_verifier_destroy(cq_verifier *v) {
+  cq_verify(v);
+  gpr_free(v);
+}
+
+static int has_metadata(const grpc_metadata *md, size_t count, const char *key,
+                        const char *value) {
+  size_t i;
+  for (i = 0; i < count; i++) {
+    if (0 == strcmp(key, md[i].key) && strlen(value) == md[i].value_length &&
+        0 == memcmp(md[i].value, value, md[i].value_length)) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+static void verify_and_destroy_metadata(metadata *md, grpc_metadata *elems,
+                                        size_t count) {
+  size_t i;
+  for (i = 0; i < md->count; i++) {
+    GPR_ASSERT(has_metadata(elems, count, md->keys[i], md->values[i]));
+  }
+  gpr_free(md->keys);
+  gpr_free(md->values);
+  gpr_free(md);
+}
+
+static gpr_slice merge_slices(gpr_slice *slices, int nslices) {
+  size_t i;
+  size_t len = 0;
+  gpr_uint8 *cursor;
+  gpr_slice out;
+
+  for (i = 0; i < nslices; i++) {
+    len += GPR_SLICE_LENGTH(slices[i]);
+  }
+
+  out = gpr_slice_malloc(len);
+  cursor = GPR_SLICE_START_PTR(out);
+
+  for (i = 0; i < nslices; i++) {
+    memcpy(cursor, GPR_SLICE_START_PTR(slices[i]), GPR_SLICE_LENGTH(slices[i]));
+    cursor += GPR_SLICE_LENGTH(slices[i]);
+  }
+
+  return out;
+}
+
+static int byte_buffer_eq_slice(grpc_byte_buffer *bb, gpr_slice b) {
+  gpr_slice a =
+      merge_slices(bb->data.slice_buffer.slices, bb->data.slice_buffer.count);
+  int ok = GPR_SLICE_LENGTH(a) == GPR_SLICE_LENGTH(b) &&
+           0 == memcmp(GPR_SLICE_START_PTR(a), GPR_SLICE_START_PTR(b),
+                       GPR_SLICE_LENGTH(a));
+  gpr_slice_unref(a);
+  gpr_slice_unref(b);
+  return ok;
+}
+
+static int string_equivalent(const char *a, const char *b) {
+  if (a == NULL) return b == NULL || b[0] == 0;
+  if (b == NULL) return a[0] == 0;
+  return strcmp(a, b) == 0;
+}
+
+static void verify_matches(expectation *e, grpc_event *ev) {
+  GPR_ASSERT(e->type == ev->type);
+  switch (e->type) {
+    case GRPC_FINISH_ACCEPTED:
+      GPR_ASSERT(e->data.finish_accepted == ev->data.finish_accepted);
+      break;
+    case GRPC_WRITE_ACCEPTED:
+      GPR_ASSERT(e->data.write_accepted == ev->data.write_accepted);
+      break;
+    case GRPC_INVOKE_ACCEPTED:
+      GPR_ASSERT(e->data.invoke_accepted == ev->data.invoke_accepted);
+      break;
+    case GRPC_SERVER_RPC_NEW:
+      GPR_ASSERT(string_equivalent(e->data.server_rpc_new.method,
+                                   ev->data.server_rpc_new.method));
+      GPR_ASSERT(string_equivalent(e->data.server_rpc_new.host,
+                                   ev->data.server_rpc_new.host));
+      GPR_ASSERT(gpr_time_cmp(e->data.server_rpc_new.deadline,
+                              ev->data.server_rpc_new.deadline) <= 0);
+      *e->data.server_rpc_new.output_call = ev->call;
+      verify_and_destroy_metadata(e->data.server_rpc_new.metadata,
+                                  ev->data.server_rpc_new.metadata_elements,
+                                  ev->data.server_rpc_new.metadata_count);
+      break;
+    case GRPC_CLIENT_METADATA_READ:
+      verify_and_destroy_metadata(e->data.client_metadata_read,
+                                  ev->data.client_metadata_read.elements,
+                                  ev->data.client_metadata_read.count);
+      break;
+    case GRPC_FINISHED:
+      if (e->data.finished.status.code != GRPC_STATUS__DO_NOT_USE) {
+        GPR_ASSERT(e->data.finished.status.code == ev->data.finished.code);
+        GPR_ASSERT(string_equivalent(e->data.finished.status.details,
+                                     ev->data.finished.details));
+      }
+      verify_and_destroy_metadata(e->data.finished.metadata, NULL, 0);
+      break;
+    case GRPC_QUEUE_SHUTDOWN:
+      gpr_log(GPR_ERROR, "premature queue shutdown");
+      abort();
+      break;
+    case GRPC_READ:
+      if (e->data.read) {
+        GPR_ASSERT(byte_buffer_eq_slice(ev->data.read, *e->data.read));
+        gpr_free(e->data.read);
+      } else {
+        GPR_ASSERT(ev->data.read == NULL);
+      }
+      break;
+    case GRPC_COMPLETION_DO_NOT_USE:
+      gpr_log(GPR_ERROR, "not implemented");
+      abort();
+      break;
+  }
+}
+
+static char *metadata_expectation_string(metadata *md) {
+  size_t len;
+  size_t i;
+  char *out;
+  char *p;
+
+  if (!md) return gpr_strdup("nil");
+
+  for (len = 0, i = 0; i < md->count; i++) {
+    len += strlen(md->keys[i]);
+    len += strlen(md->values[i]);
+  }
+  len += 3 + md->count;
+
+  p = out = gpr_malloc(len);
+  *p++ = '{';
+  for (i = 0; i < md->count; i++) {
+    if (i) *p++ = ',';
+    p += sprintf(p, "%s:%s", md->keys[i], md->values[i]);
+  }
+  *p++ = '}';
+  *p++ = 0;
+  return out;
+}
+
+static size_t expectation_to_string(char *out, expectation *e) {
+  gpr_timespec timeout;
+  char *str = NULL;
+  size_t len;
+
+  switch (e->type) {
+    case GRPC_FINISH_ACCEPTED:
+      return sprintf(out, "GRPC_FINISH_ACCEPTED result=%d",
+                     e->data.finish_accepted);
+    case GRPC_WRITE_ACCEPTED:
+      return sprintf(out, "GRPC_WRITE_ACCEPTED result=%d",
+                     e->data.write_accepted);
+    case GRPC_INVOKE_ACCEPTED:
+      return sprintf(out, "GRPC_INVOKE_ACCEPTED result=%d",
+                     e->data.invoke_accepted);
+    case GRPC_SERVER_RPC_NEW:
+      timeout = gpr_time_sub(e->data.server_rpc_new.deadline, gpr_now());
+      return sprintf(out, "GRPC_SERVER_RPC_NEW method=%s host=%s timeout=%fsec",
+                     e->data.server_rpc_new.method, e->data.server_rpc_new.host,
+                     timeout.tv_sec + 1e-9 * timeout.tv_nsec);
+    case GRPC_CLIENT_METADATA_READ:
+      str = metadata_expectation_string(e->data.client_metadata_read);
+      len = sprintf(out, "GRPC_CLIENT_METADATA_READ %s", str);
+      gpr_free(str);
+      return len;
+    case GRPC_FINISHED:
+      str = metadata_expectation_string(e->data.finished.metadata);
+      len = sprintf(out, "GRPC_FINISHED code=%d details=%s %s",
+                    e->data.finished.status.code,
+                    e->data.finished.status.details, str);
+      gpr_free(str);
+      return len;
+    case GRPC_READ:
+      if (e->data.read) {
+        str =
+            gpr_hexdump((char *)GPR_SLICE_START_PTR(*e->data.read),
+                        GPR_SLICE_LENGTH(*e->data.read), GPR_HEXDUMP_PLAINTEXT);
+      }
+      len = sprintf(out, "GRPC_READ data=%s", str);
+      gpr_free(str);
+      return len;
+    case GRPC_COMPLETION_DO_NOT_USE:
+    case GRPC_QUEUE_SHUTDOWN:
+      gpr_log(GPR_ERROR, "not implemented");
+      abort();
+      break;
+  }
+  return 0;
+}
+
+static char *expectations_to_string(cq_verifier *v) {
+  /* allocate a large buffer: we're about to crash anyway */
+  char *buffer = gpr_malloc(32 * 1024 * 1024);
+  char *p = buffer;
+  expectation *e;
+
+  for (e = v->expect.next; e != &v->expect; e = e->next) {
+    p += expectation_to_string(p, e);
+    *p++ = '\n';
+  }
+
+  *p = 0;
+  return buffer;
+}
+
+static void fail_no_event_received(cq_verifier *v) {
+  char *expectations = expectations_to_string(v);
+  gpr_log(GPR_ERROR, "no event received, but expected:\n%s", expectations);
+  gpr_free(expectations);
+  abort();
+}
+
+void cq_verify(cq_verifier *v) {
+  gpr_timespec deadline =
+      gpr_time_add(gpr_now(), gpr_time_from_micros(10 * GPR_US_PER_SEC));
+  grpc_event *ev;
+  expectation *e;
+
+  char have_tags[512] = {0};
+  char *phave = have_tags;
+
+  while (v->expect.next != &v->expect) {
+    ev = grpc_completion_queue_next(v->cq, deadline);
+    if (!ev) {
+      fail_no_event_received(v);
+    }
+
+    for (e = v->expect.next; e != &v->expect; e = e->next) {
+      phave += sprintf(phave, " %p", e->tag);
+      if (e->tag == ev->tag) {
+        verify_matches(e, ev);
+        e->next->prev = e->prev;
+        e->prev->next = e->next;
+        gpr_free(e);
+        break;
+      }
+    }
+    if (e == &v->expect) {
+      char *s = grpc_event_string(ev);
+      gpr_log(GPR_ERROR, "event not found: %s", s);
+      gpr_log(GPR_ERROR, "have tags:%s", have_tags);
+      gpr_free(s);
+      abort();
+    }
+
+    grpc_event_finish(ev);
+  }
+}
+
+void cq_verify_empty(cq_verifier *v) {
+  gpr_timespec deadline =
+      gpr_time_add(gpr_now(), gpr_time_from_micros(3000000));
+  grpc_event *ev;
+
+  GPR_ASSERT(v->expect.next == &v->expect && "expectation queue must be empty");
+
+  ev = grpc_completion_queue_next(v->cq, deadline);
+  GPR_ASSERT(ev == NULL);
+}
+
+static expectation *add(cq_verifier *v, grpc_completion_type type, void *tag) {
+  expectation *e = gpr_malloc(sizeof(expectation));
+  e->type = type;
+  e->tag = tag;
+  e->next = &v->expect;
+  e->prev = e->next->prev;
+  e->next->prev = e->prev->next = e;
+  return e;
+}
+
+static metadata *metadata_from_args(va_list args) {
+  metadata *md = gpr_malloc(sizeof(metadata));
+  const char *key, *value;
+  md->count = 0;
+  md->cap = 0;
+  md->keys = NULL;
+  md->values = NULL;
+
+  for (;;) {
+    key = va_arg(args, const char *);
+    if (!key) return md;
+    value = va_arg(args, const char *);
+    GPR_ASSERT(value);
+
+    if (md->cap == md->count) {
+      md->cap = GPR_MAX(md->cap + 1, md->cap * 3 / 2);
+      md->keys = gpr_realloc(md->keys, sizeof(const char *) * md->cap);
+      md->values = gpr_realloc(md->values, sizeof(const char *) * md->cap);
+    }
+    md->keys[md->count] = key;
+    md->values[md->count] = value;
+    md->count++;
+  }
+}
+
+void cq_expect_invoke_accepted(cq_verifier *v, void *tag,
+                               grpc_op_error result) {
+  add(v, GRPC_INVOKE_ACCEPTED, tag)->data.invoke_accepted = result;
+}
+
+void cq_expect_write_accepted(cq_verifier *v, void *tag, grpc_op_error result) {
+  add(v, GRPC_WRITE_ACCEPTED, tag)->data.write_accepted = result;
+}
+
+void cq_expect_finish_accepted(cq_verifier *v, void *tag,
+                               grpc_op_error result) {
+  add(v, GRPC_FINISH_ACCEPTED, tag)->data.finish_accepted = result;
+}
+
+void cq_expect_read(cq_verifier *v, void *tag, gpr_slice bytes) {
+  expectation *e = add(v, GRPC_READ, tag);
+  e->data.read = gpr_malloc(sizeof(gpr_slice));
+  *e->data.read = bytes;
+}
+
+void cq_expect_empty_read(cq_verifier *v, void *tag) {
+  expectation *e = add(v, GRPC_READ, tag);
+  e->data.read = NULL;
+}
+
+void cq_expect_server_rpc_new(cq_verifier *v, grpc_call **output_call,
+                              void *tag, const char *method, const char *host,
+                              gpr_timespec deadline, ...) {
+  va_list args;
+  expectation *e = add(v, GRPC_SERVER_RPC_NEW, tag);
+  e->data.server_rpc_new.method = method;
+  e->data.server_rpc_new.host = host;
+  e->data.server_rpc_new.deadline = deadline;
+  e->data.server_rpc_new.output_call = output_call;
+
+  va_start(args, deadline);
+  e->data.server_rpc_new.metadata = metadata_from_args(args);
+  va_end(args);
+}
+
+void cq_expect_client_metadata_read(cq_verifier *v, void *tag, ...) {
+  va_list args;
+  expectation *e = add(v, GRPC_CLIENT_METADATA_READ, tag);
+
+  va_start(args, tag);
+  e->data.client_metadata_read = metadata_from_args(args);
+  va_end(args);
+}
+
+static void finished_internal(cq_verifier *v, void *tag, grpc_status status,
+                              va_list args) {
+  expectation *e = add(v, GRPC_FINISHED, tag);
+  e->data.finished.status = status;
+  e->data.finished.metadata = metadata_from_args(args);
+}
+
+void cq_expect_finished_with_status(cq_verifier *v, void *tag,
+                                    grpc_status status, ...) {
+  va_list args;
+  va_start(args, status);
+  finished_internal(v, tag, status, args);
+  va_end(args);
+}
+
+void cq_expect_finished(cq_verifier *v, void *tag, ...) {
+  va_list args;
+  grpc_status status = {GRPC_STATUS__DO_NOT_USE, NULL};
+  va_start(args, tag);
+  finished_internal(v, tag, status, args);
+  va_end(args);
+}
diff --git a/test/core/end2end/cq_verifier.h b/test/core/end2end/cq_verifier.h
new file mode 100644
index 0000000..60f56bd
--- /dev/null
+++ b/test/core/end2end/cq_verifier.h
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_TEST_END2END_CQ_VERIFIER_H__
+#define __GRPC_TEST_END2END_CQ_VERIFIER_H__
+
+#include <grpc/grpc.h>
+
+/* A cq_verifier can verify that expected events arrive in a timely fashion
+   on a single completion queue */
+
+typedef struct cq_verifier cq_verifier;
+
+/* construct/destroy a cq_verifier */
+cq_verifier *cq_verifier_create(grpc_completion_queue *cq);
+void cq_verifier_destroy(cq_verifier *v);
+
+/* ensure all expected events (and only those events) are present on the
+   bound completion queue */
+void cq_verify(cq_verifier *v);
+
+/* ensure that the completion queue is empty */
+void cq_verify_empty(cq_verifier *v);
+
+/* Various expectation matchers
+   Any functions taking ... expect a NULL terminated list of key/value pairs
+   (each pair using two parameter slots) of metadata that MUST be present in
+   the event. */
+void cq_expect_invoke_accepted(cq_verifier *v, void *tag, grpc_op_error result);
+void cq_expect_write_accepted(cq_verifier *v, void *tag, grpc_op_error result);
+void cq_expect_finish_accepted(cq_verifier *v, void *tag, grpc_op_error result);
+void cq_expect_read(cq_verifier *v, void *tag, gpr_slice bytes);
+void cq_expect_empty_read(cq_verifier *v, void *tag);
+/* *output_call is set the the server call instance */
+void cq_expect_server_rpc_new(cq_verifier *v, grpc_call **output_call,
+                              void *tag, const char *method, const char *host,
+                              gpr_timespec deadline, ...);
+void cq_expect_client_metadata_read(cq_verifier *v, void *tag, ...);
+void cq_expect_finished_with_status(cq_verifier *v, void *tag,
+                                    grpc_status status, ...);
+void cq_expect_finished(cq_verifier *v, void *tag, ...);
+
+#endif  /* __GRPC_TEST_END2END_CQ_VERIFIER_H__ */
diff --git a/test/core/end2end/data/ca_cert.c b/test/core/end2end/data/ca_cert.c
new file mode 100644
index 0000000..458b7f0
--- /dev/null
+++ b/test/core/end2end/data/ca_cert.c
@@ -0,0 +1,102 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+unsigned char test_ca_cert[] = {
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x49, 0x7a, 0x43, 0x43,
+    0x41, 0x59, 0x77, 0x43, 0x43, 0x51, 0x43, 0x46, 0x54, 0x62, 0x46, 0x37,
+    0x58, 0x4e, 0x53, 0x76, 0x76, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71,
+    0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46,
+    0x41, 0x44, 0x42, 0x57, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44,
+    0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x42, 0x0a, 0x56, 0x54, 0x45,
+    0x54, 0x4d, 0x42, 0x45, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77,
+    0x4b, 0x55, 0x32, 0x39, 0x74, 0x5a, 0x53, 0x31, 0x54, 0x64, 0x47, 0x46,
+    0x30, 0x5a, 0x54, 0x45, 0x68, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55,
+    0x45, 0x43, 0x67, 0x77, 0x59, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x58, 0x4a,
+    0x75, 0x5a, 0x58, 0x51, 0x67, 0x56, 0x32, 0x6c, 0x6b, 0x5a, 0x32, 0x6c,
+    0x30, 0x0a, 0x63, 0x79, 0x42, 0x51, 0x64, 0x48, 0x6b, 0x67, 0x54, 0x48,
+    0x52, 0x6b, 0x4d, 0x51, 0x38, 0x77, 0x44, 0x51, 0x59, 0x44, 0x56, 0x51,
+    0x51, 0x44, 0x44, 0x41, 0x5a, 0x30, 0x5a, 0x58, 0x4e, 0x30, 0x59, 0x32,
+    0x45, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x51, 0x77, 0x4e, 0x7a,
+    0x45, 0x33, 0x4d, 0x6a, 0x4d, 0x78, 0x4e, 0x7a, 0x55, 0x78, 0x57, 0x68,
+    0x63, 0x4e, 0x4d, 0x6a, 0x51, 0x77, 0x0a, 0x4e, 0x7a, 0x45, 0x30, 0x4d,
+    0x6a, 0x4d, 0x78, 0x4e, 0x7a, 0x55, 0x78, 0x57, 0x6a, 0x42, 0x57, 0x4d,
+    0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45,
+    0x77, 0x4a, 0x42, 0x56, 0x54, 0x45, 0x54, 0x4d, 0x42, 0x45, 0x47, 0x41,
+    0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x4b, 0x55, 0x32, 0x39, 0x74, 0x5a,
+    0x53, 0x31, 0x54, 0x64, 0x47, 0x46, 0x30, 0x5a, 0x54, 0x45, 0x68, 0x0a,
+    0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x59,
+    0x53, 0x57, 0x35, 0x30, 0x5a, 0x58, 0x4a, 0x75, 0x5a, 0x58, 0x51, 0x67,
+    0x56, 0x32, 0x6c, 0x6b, 0x5a, 0x32, 0x6c, 0x30, 0x63, 0x79, 0x42, 0x51,
+    0x64, 0x48, 0x6b, 0x67, 0x54, 0x48, 0x52, 0x6b, 0x4d, 0x51, 0x38, 0x77,
+    0x44, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x41, 0x5a, 0x30,
+    0x5a, 0x58, 0x4e, 0x30, 0x0a, 0x59, 0x32, 0x45, 0x77, 0x67, 0x5a, 0x38,
+    0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63,
+    0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x59, 0x30,
+    0x41, 0x4d, 0x49, 0x47, 0x4a, 0x41, 0x6f, 0x47, 0x42, 0x41, 0x4d, 0x42,
+    0x41, 0x33, 0x77, 0x56, 0x65, 0x54, 0x47, 0x48, 0x5a, 0x52, 0x31, 0x52,
+    0x79, 0x65, 0x2f, 0x69, 0x2b, 0x4a, 0x38, 0x61, 0x32, 0x0a, 0x63, 0x75,
+    0x35, 0x67, 0x58, 0x77, 0x46, 0x56, 0x36, 0x54, 0x6e, 0x4f, 0x62, 0x7a,
+    0x47, 0x4d, 0x37, 0x62, 0x4c, 0x46, 0x43, 0x4f, 0x35, 0x69, 0x39, 0x76,
+    0x34, 0x6d, 0x4c, 0x6f, 0x34, 0x69, 0x46, 0x7a, 0x50, 0x73, 0x48, 0x6d,
+    0x57, 0x44, 0x55, 0x78, 0x4b, 0x53, 0x33, 0x59, 0x38, 0x69, 0x58, 0x62,
+    0x75, 0x30, 0x65, 0x59, 0x42, 0x6c, 0x4c, 0x6f, 0x4e, 0x59, 0x30, 0x6c,
+    0x53, 0x76, 0x0a, 0x78, 0x44, 0x78, 0x33, 0x33, 0x4f, 0x2b, 0x44, 0x75,
+    0x77, 0x4d, 0x6d, 0x56, 0x4e, 0x2b, 0x44, 0x7a, 0x53, 0x44, 0x2b, 0x45,
+    0x6f, 0x64, 0x39, 0x7a, 0x66, 0x76, 0x77, 0x4f, 0x57, 0x48, 0x73, 0x61,
+    0x7a, 0x59, 0x43, 0x5a, 0x54, 0x32, 0x50, 0x68, 0x4e, 0x78, 0x6e, 0x56,
+    0x57, 0x49, 0x75, 0x4a, 0x58, 0x56, 0x69, 0x59, 0x34, 0x4a, 0x41, 0x48,
+    0x55, 0x47, 0x6f, 0x64, 0x6a, 0x78, 0x2b, 0x0a, 0x51, 0x41, 0x69, 0x36,
+    0x79, 0x43, 0x41, 0x75, 0x72, 0x55, 0x5a, 0x47, 0x76, 0x59, 0x58, 0x47,
+    0x67, 0x5a, 0x53, 0x42, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x45, 0x77,
+    0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e,
+    0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x59, 0x45, 0x41,
+    0x51, 0x6f, 0x51, 0x56, 0x44, 0x38, 0x62, 0x77, 0x64, 0x74, 0x57, 0x4a,
+    0x0a, 0x41, 0x6e, 0x69, 0x47, 0x42, 0x77, 0x63, 0x43, 0x66, 0x71, 0x59,
+    0x79, 0x48, 0x2b, 0x2f, 0x4b, 0x70, 0x41, 0x31, 0x30, 0x41, 0x63, 0x65,
+    0x62, 0x4a, 0x56, 0x56, 0x54, 0x79, 0x59, 0x62, 0x59, 0x76, 0x49, 0x39,
+    0x51, 0x38, 0x64, 0x36, 0x52, 0x53, 0x56, 0x75, 0x34, 0x50, 0x5a, 0x79,
+    0x39, 0x4f, 0x41, 0x4c, 0x48, 0x52, 0x2f, 0x51, 0x72, 0x57, 0x42, 0x64,
+    0x59, 0x54, 0x41, 0x79, 0x7a, 0x0a, 0x66, 0x4e, 0x41, 0x6d, 0x63, 0x32,
+    0x63, 0x6d, 0x64, 0x6b, 0x53, 0x52, 0x4a, 0x7a, 0x6a, 0x68, 0x49, 0x61,
+    0x4f, 0x73, 0x74, 0x6e, 0x51, 0x79, 0x31, 0x4a, 0x2b, 0x46, 0x6b, 0x30,
+    0x54, 0x39, 0x58, 0x79, 0x76, 0x51, 0x74, 0x71, 0x34, 0x39, 0x39, 0x79,
+    0x46, 0x62, 0x71, 0x39, 0x78, 0x6f, 0x67, 0x55, 0x56, 0x6c, 0x45, 0x47,
+    0x48, 0x36, 0x32, 0x78, 0x50, 0x36, 0x76, 0x48, 0x30, 0x59, 0x0a, 0x35,
+    0x75, 0x6b, 0x4b, 0x2f, 0x2f, 0x64, 0x43, 0x50, 0x41, 0x7a, 0x41, 0x31,
+    0x31, 0x59, 0x75, 0x58, 0x32, 0x72, 0x6e, 0x65, 0x78, 0x30, 0x4a, 0x68,
+    0x75, 0x54, 0x51, 0x66, 0x63, 0x49, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
+    0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
+    0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a};
+unsigned int test_ca_cert_size = 802;
diff --git a/test/core/end2end/data/server1_cert.c b/test/core/end2end/data/server1_cert.c
new file mode 100644
index 0000000..da1d366
--- /dev/null
+++ b/test/core/end2end/data/server1_cert.c
@@ -0,0 +1,116 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+unsigned char test_server1_cert[] = {
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6d, 0x7a, 0x43, 0x43,
+    0x41, 0x67, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42,
+    0x41, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47,
+    0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x57,
+    0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47,
+    0x45, 0x77, 0x4a, 0x42, 0x56, 0x54, 0x45, 0x54, 0x0a, 0x4d, 0x42, 0x45,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x4b, 0x55, 0x32, 0x39,
+    0x74, 0x5a, 0x53, 0x31, 0x54, 0x64, 0x47, 0x46, 0x30, 0x5a, 0x54, 0x45,
+    0x68, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77,
+    0x59, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x58, 0x4a, 0x75, 0x5a, 0x58, 0x51,
+    0x67, 0x56, 0x32, 0x6c, 0x6b, 0x5a, 0x32, 0x6c, 0x30, 0x63, 0x79, 0x42,
+    0x51, 0x0a, 0x64, 0x48, 0x6b, 0x67, 0x54, 0x48, 0x52, 0x6b, 0x4d, 0x51,
+    0x38, 0x77, 0x44, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x41,
+    0x5a, 0x30, 0x5a, 0x58, 0x4e, 0x30, 0x59, 0x32, 0x45, 0x77, 0x48, 0x68,
+    0x63, 0x4e, 0x4d, 0x54, 0x51, 0x77, 0x4e, 0x7a, 0x49, 0x79, 0x4d, 0x44,
+    0x59, 0x77, 0x4d, 0x44, 0x55, 0x33, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a,
+    0x51, 0x77, 0x4e, 0x7a, 0x45, 0x35, 0x0a, 0x4d, 0x44, 0x59, 0x77, 0x4d,
+    0x44, 0x55, 0x33, 0x57, 0x6a, 0x42, 0x6b, 0x4d, 0x51, 0x73, 0x77, 0x43,
+    0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55,
+    0x7a, 0x45, 0x52, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43,
+    0x42, 0x4d, 0x49, 0x53, 0x57, 0x78, 0x73, 0x61, 0x57, 0x35, 0x76, 0x61,
+    0x58, 0x4d, 0x78, 0x45, 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x0a,
+    0x42, 0x41, 0x63, 0x54, 0x42, 0x30, 0x4e, 0x6f, 0x61, 0x57, 0x4e, 0x68,
+    0x5a, 0x32, 0x38, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x6f, 0x54, 0x43, 0x30, 0x64, 0x76, 0x62, 0x32, 0x64, 0x73,
+    0x5a, 0x53, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x52, 0x6f, 0x77,
+    0x47, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x46, 0x42, 0x45, 0x71,
+    0x4c, 0x6e, 0x52, 0x6c, 0x0a, 0x63, 0x33, 0x51, 0x75, 0x5a, 0x32, 0x39,
+    0x76, 0x5a, 0x32, 0x78, 0x6c, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x54, 0x43,
+    0x42, 0x6e, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69,
+    0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f,
+    0x42, 0x6a, 0x51, 0x41, 0x77, 0x67, 0x59, 0x6b, 0x43, 0x67, 0x59, 0x45,
+    0x41, 0x34, 0x63, 0x4d, 0x56, 0x4a, 0x79, 0x67, 0x73, 0x0a, 0x4a, 0x55,
+    0x6d, 0x6c, 0x67, 0x4d, 0x4d, 0x7a, 0x67, 0x64, 0x69, 0x30, 0x68, 0x31,
+    0x58, 0x6f, 0x43, 0x52, 0x37, 0x2b, 0x77, 0x77, 0x31, 0x70, 0x6f, 0x70,
+    0x30, 0x34, 0x4f, 0x4d, 0x4d, 0x79, 0x79, 0x37, 0x48, 0x2f, 0x69, 0x30,
+    0x50, 0x4a, 0x32, 0x57, 0x36, 0x59, 0x33, 0x35, 0x2b, 0x62, 0x34, 0x43,
+    0x4d, 0x38, 0x51, 0x72, 0x6b, 0x59, 0x65, 0x45, 0x61, 0x66, 0x55, 0x47,
+    0x44, 0x4f, 0x0a, 0x52, 0x59, 0x58, 0x36, 0x79, 0x56, 0x2f, 0x63, 0x48,
+    0x47, 0x47, 0x73, 0x44, 0x2f, 0x78, 0x30, 0x32, 0x79, 0x65, 0x36, 0x65,
+    0x79, 0x31, 0x55, 0x44, 0x74, 0x6b, 0x47, 0x41, 0x44, 0x2f, 0x6d, 0x70,
+    0x44, 0x45, 0x78, 0x38, 0x59, 0x43, 0x72, 0x6a, 0x41, 0x63, 0x31, 0x56,
+    0x66, 0x76, 0x74, 0x38, 0x46, 0x6b, 0x36, 0x43, 0x6e, 0x31, 0x57, 0x56,
+    0x49, 0x78, 0x56, 0x2f, 0x4a, 0x33, 0x30, 0x0a, 0x33, 0x78, 0x6a, 0x42,
+    0x73, 0x46, 0x67, 0x42, 0x79, 0x51, 0x35, 0x35, 0x52, 0x42, 0x70, 0x31,
+    0x4f, 0x4c, 0x5a, 0x66, 0x56, 0x4c, 0x6f, 0x36, 0x41, 0x6c, 0x65, 0x42,
+    0x44, 0x53, 0x62, 0x63, 0x78, 0x61, 0x45, 0x43, 0x41, 0x77, 0x45, 0x41,
+    0x41, 0x61, 0x4e, 0x72, 0x4d, 0x47, 0x6b, 0x77, 0x43, 0x51, 0x59, 0x44,
+    0x56, 0x52, 0x30, 0x54, 0x42, 0x41, 0x49, 0x77, 0x41, 0x44, 0x41, 0x4c,
+    0x0a, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x45, 0x42, 0x41, 0x4d,
+    0x43, 0x42, 0x65, 0x41, 0x77, 0x54, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30,
+    0x52, 0x42, 0x45, 0x67, 0x77, 0x52, 0x6f, 0x49, 0x51, 0x4b, 0x69, 0x35,
+    0x30, 0x5a, 0x58, 0x4e, 0x30, 0x4c, 0x6d, 0x64, 0x76, 0x62, 0x32, 0x64,
+    0x73, 0x5a, 0x53, 0x35, 0x6d, 0x63, 0x6f, 0x49, 0x59, 0x64, 0x32, 0x46,
+    0x30, 0x5a, 0x58, 0x4a, 0x36, 0x0a, 0x62, 0x32, 0x39, 0x70, 0x4c, 0x6e,
+    0x52, 0x6c, 0x63, 0x33, 0x51, 0x75, 0x5a, 0x32, 0x39, 0x76, 0x5a, 0x32,
+    0x78, 0x6c, 0x4c, 0x6d, 0x4a, 0x6c, 0x67, 0x68, 0x49, 0x71, 0x4c, 0x6e,
+    0x52, 0x6c, 0x63, 0x33, 0x51, 0x75, 0x65, 0x57, 0x39, 0x31, 0x64, 0x48,
+    0x56, 0x69, 0x5a, 0x53, 0x35, 0x6a, 0x62, 0x32, 0x32, 0x48, 0x42, 0x4d,
+    0x43, 0x6f, 0x41, 0x51, 0x4d, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x0a, 0x4b,
+    0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42,
+    0x51, 0x41, 0x44, 0x67, 0x59, 0x45, 0x41, 0x4d, 0x32, 0x49, 0x69, 0x30,
+    0x4c, 0x67, 0x54, 0x47, 0x62, 0x4a, 0x31, 0x6a, 0x34, 0x6f, 0x71, 0x58,
+    0x39, 0x62, 0x78, 0x56, 0x63, 0x78, 0x6d, 0x2b, 0x2f, 0x52, 0x35, 0x59,
+    0x66, 0x38, 0x6f, 0x69, 0x30, 0x61, 0x5a, 0x71, 0x54, 0x4a, 0x6c, 0x6e,
+    0x4c, 0x59, 0x53, 0x0a, 0x77, 0x58, 0x63, 0x42, 0x79, 0x6b, 0x78, 0x54,
+    0x78, 0x31, 0x38, 0x31, 0x73, 0x37, 0x57, 0x79, 0x66, 0x4a, 0x34, 0x39,
+    0x57, 0x77, 0x72, 0x59, 0x58, 0x6f, 0x37, 0x38, 0x7a, 0x54, 0x44, 0x41,
+    0x6e, 0x66, 0x31, 0x6d, 0x61, 0x30, 0x66, 0x50, 0x71, 0x33, 0x65, 0x34,
+    0x6d, 0x70, 0x73, 0x70, 0x76, 0x79, 0x6e, 0x64, 0x4c, 0x68, 0x31, 0x61,
+    0x2b, 0x4f, 0x61, 0x72, 0x48, 0x61, 0x31, 0x65, 0x0a, 0x61, 0x54, 0x30,
+    0x44, 0x49, 0x49, 0x59, 0x6b, 0x37, 0x71, 0x65, 0x45, 0x61, 0x31, 0x59,
+    0x63, 0x56, 0x6c, 0x6a, 0x78, 0x32, 0x4b, 0x79, 0x4c, 0x64, 0x30, 0x72,
+    0x31, 0x42, 0x42, 0x41, 0x66, 0x72, 0x77, 0x79, 0x47, 0x61, 0x45, 0x50,
+    0x56, 0x65, 0x4a, 0x51, 0x56, 0x59, 0x57, 0x61, 0x4f, 0x4a, 0x52, 0x55,
+    0x32, 0x77, 0x65, 0x2f, 0x4b, 0x44, 0x34, 0x6f, 0x6a, 0x66, 0x39, 0x73,
+    0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43,
+    0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
+    0x2d, 0x2d, 0x2d, 0x0a};
+unsigned int test_server1_cert_size = 964;
diff --git a/test/core/end2end/data/server1_key.c b/test/core/end2end/data/server1_key.c
new file mode 100644
index 0000000..3540505
--- /dev/null
+++ b/test/core/end2end/data/server1_key.c
@@ -0,0 +1,109 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+unsigned char test_server1_key[] = {
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x52,
+    0x53, 0x41, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b,
+    0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43,
+    0x57, 0x77, 0x49, 0x42, 0x41, 0x41, 0x4b, 0x42, 0x67, 0x51, 0x44, 0x68,
+    0x77, 0x78, 0x55, 0x6e, 0x4b, 0x43, 0x77, 0x6c, 0x53, 0x61, 0x57, 0x41,
+    0x77, 0x7a, 0x4f, 0x42, 0x32, 0x4c, 0x53, 0x48, 0x56, 0x65, 0x67, 0x4a,
+    0x48, 0x76, 0x37, 0x44, 0x44, 0x57, 0x6d, 0x69, 0x6e, 0x54, 0x67, 0x34,
+    0x77, 0x7a, 0x4c, 0x4c, 0x73, 0x66, 0x2b, 0x4c, 0x51, 0x38, 0x6e, 0x5a,
+    0x0a, 0x62, 0x70, 0x6a, 0x66, 0x6e, 0x35, 0x76, 0x67, 0x49, 0x7a, 0x78,
+    0x43, 0x75, 0x52, 0x68, 0x34, 0x52, 0x70, 0x39, 0x51, 0x59, 0x4d, 0x35,
+    0x46, 0x68, 0x66, 0x72, 0x4a, 0x58, 0x39, 0x77, 0x63, 0x59, 0x61, 0x77,
+    0x50, 0x2f, 0x48, 0x54, 0x62, 0x4a, 0x37, 0x70, 0x37, 0x4c, 0x56, 0x51,
+    0x4f, 0x32, 0x51, 0x59, 0x41, 0x50, 0x2b, 0x61, 0x6b, 0x4d, 0x54, 0x48,
+    0x78, 0x67, 0x4b, 0x75, 0x4d, 0x0a, 0x42, 0x7a, 0x56, 0x56, 0x2b, 0x2b,
+    0x33, 0x77, 0x57, 0x54, 0x6f, 0x4b, 0x66, 0x56, 0x5a, 0x55, 0x6a, 0x46,
+    0x58, 0x38, 0x6e, 0x66, 0x54, 0x66, 0x47, 0x4d, 0x47, 0x77, 0x57, 0x41,
+    0x48, 0x4a, 0x44, 0x6e, 0x6c, 0x45, 0x47, 0x6e, 0x55, 0x34, 0x74, 0x6c,
+    0x39, 0x55, 0x75, 0x6a, 0x6f, 0x43, 0x56, 0x34, 0x45, 0x4e, 0x4a, 0x74,
+    0x7a, 0x46, 0x6f, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x0a, 0x41,
+    0x6f, 0x47, 0x41, 0x4a, 0x2b, 0x36, 0x68, 0x70, 0x7a, 0x4e, 0x72, 0x32,
+    0x34, 0x79, 0x54, 0x51, 0x5a, 0x74, 0x46, 0x57, 0x51, 0x70, 0x44, 0x70,
+    0x45, 0x79, 0x46, 0x70, 0x6c, 0x64, 0x64, 0x4b, 0x4a, 0x4d, 0x4f, 0x78,
+    0x44, 0x79, 0x61, 0x33, 0x53, 0x39, 0x70, 0x70, 0x4b, 0x33, 0x76, 0x54,
+    0x57, 0x72, 0x49, 0x49, 0x54, 0x56, 0x32, 0x78, 0x4e, 0x63, 0x75, 0x63,
+    0x77, 0x37, 0x49, 0x0a, 0x63, 0x65, 0x54, 0x62, 0x64, 0x79, 0x72, 0x47,
+    0x73, 0x79, 0x6a, 0x73, 0x55, 0x30, 0x2f, 0x48, 0x64, 0x43, 0x63, 0x49,
+    0x66, 0x39, 0x79, 0x6d, 0x32, 0x6a, 0x66, 0x6d, 0x47, 0x4c, 0x55, 0x77,
+    0x6d, 0x79, 0x68, 0x6c, 0x74, 0x4b, 0x56, 0x77, 0x30, 0x51, 0x59, 0x63,
+    0x46, 0x42, 0x30, 0x58, 0x4c, 0x6b, 0x63, 0x30, 0x6e, 0x49, 0x35, 0x59,
+    0x76, 0x45, 0x59, 0x6f, 0x65, 0x56, 0x44, 0x67, 0x0a, 0x6f, 0x6d, 0x5a,
+    0x49, 0x58, 0x6e, 0x31, 0x45, 0x33, 0x45, 0x57, 0x2b, 0x73, 0x53, 0x49,
+    0x57, 0x53, 0x62, 0x6b, 0x4d, 0x75, 0x39, 0x62, 0x59, 0x32, 0x6b, 0x73,
+    0x74, 0x4b, 0x58, 0x52, 0x32, 0x55, 0x5a, 0x6d, 0x4d, 0x67, 0x57, 0x44,
+    0x74, 0x6d, 0x42, 0x45, 0x50, 0x4d, 0x61, 0x45, 0x43, 0x51, 0x51, 0x44,
+    0x36, 0x79, 0x54, 0x34, 0x54, 0x41, 0x5a, 0x4d, 0x35, 0x68, 0x47, 0x42,
+    0x62, 0x0a, 0x63, 0x69, 0x42, 0x4b, 0x67, 0x4d, 0x55, 0x50, 0x36, 0x50,
+    0x77, 0x4f, 0x68, 0x50, 0x68, 0x4f, 0x4d, 0x50, 0x49, 0x76, 0x69, 0x6a,
+    0x4f, 0x35, 0x30, 0x41, 0x69, 0x75, 0x36, 0x69, 0x75, 0x43, 0x56, 0x38,
+    0x38, 0x6c, 0x31, 0x51, 0x49, 0x79, 0x33, 0x38, 0x67, 0x57, 0x56, 0x68,
+    0x78, 0x6a, 0x4e, 0x72, 0x71, 0x36, 0x50, 0x33, 0x34, 0x36, 0x6a, 0x34,
+    0x49, 0x42, 0x67, 0x2b, 0x6b, 0x42, 0x0a, 0x39, 0x61, 0x6c, 0x77, 0x70,
+    0x43, 0x4f, 0x44, 0x41, 0x6b, 0x45, 0x41, 0x35, 0x6e, 0x53, 0x6e, 0x6d,
+    0x39, 0x6b, 0x36, 0x79, 0x6b, 0x59, 0x65, 0x51, 0x57, 0x4e, 0x53, 0x30,
+    0x66, 0x4e, 0x57, 0x69, 0x52, 0x69, 0x6e, 0x43, 0x64, 0x6c, 0x32, 0x33,
+    0x41, 0x37, 0x75, 0x73, 0x44, 0x47, 0x53, 0x75, 0x4b, 0x4b, 0x6c, 0x6d,
+    0x30, 0x31, 0x39, 0x69, 0x6f, 0x6d, 0x4a, 0x2f, 0x52, 0x67, 0x64, 0x0a,
+    0x4d, 0x4b, 0x44, 0x4f, 0x70, 0x30, 0x71, 0x2f, 0x32, 0x4f, 0x6f, 0x73,
+    0x74, 0x62, 0x74, 0x65, 0x4f, 0x57, 0x4d, 0x32, 0x4d, 0x52, 0x46, 0x66,
+    0x34, 0x6a, 0x4d, 0x48, 0x33, 0x77, 0x79, 0x56, 0x43, 0x77, 0x4a, 0x41,
+    0x66, 0x41, 0x64, 0x6a, 0x4a, 0x38, 0x73, 0x7a, 0x6f, 0x4e, 0x4b, 0x54,
+    0x52, 0x53, 0x61, 0x67, 0x53, 0x62, 0x68, 0x39, 0x76, 0x57, 0x79, 0x67,
+    0x6e, 0x42, 0x32, 0x76, 0x0a, 0x49, 0x42, 0x79, 0x63, 0x36, 0x6c, 0x34,
+    0x54, 0x54, 0x75, 0x5a, 0x51, 0x4a, 0x52, 0x47, 0x7a, 0x43, 0x76, 0x65,
+    0x61, 0x66, 0x7a, 0x39, 0x6c, 0x6f, 0x76, 0x75, 0x42, 0x33, 0x57, 0x6f,
+    0x68, 0x43, 0x41, 0x42, 0x64, 0x51, 0x52, 0x64, 0x39, 0x75, 0x6b, 0x43,
+    0x58, 0x4c, 0x32, 0x43, 0x70, 0x73, 0x45, 0x70, 0x71, 0x7a, 0x6b, 0x61,
+    0x66, 0x4f, 0x51, 0x4a, 0x41, 0x4a, 0x55, 0x6a, 0x63, 0x0a, 0x55, 0x53,
+    0x65, 0x64, 0x44, 0x6c, 0x71, 0x33, 0x7a, 0x47, 0x5a, 0x77, 0x59, 0x4d,
+    0x31, 0x59, 0x77, 0x38, 0x64, 0x38, 0x52, 0x75, 0x69, 0x72, 0x42, 0x55,
+    0x46, 0x5a, 0x4e, 0x71, 0x4a, 0x65, 0x6c, 0x59, 0x61, 0x69, 0x2b, 0x6e,
+    0x52, 0x59, 0x43, 0x6c, 0x44, 0x6b, 0x52, 0x56, 0x46, 0x67, 0x62, 0x35,
+    0x79, 0x6b, 0x73, 0x6f, 0x59, 0x79, 0x63, 0x62, 0x71, 0x35, 0x54, 0x78,
+    0x47, 0x6f, 0x0a, 0x56, 0x65, 0x71, 0x4b, 0x4f, 0x76, 0x67, 0x50, 0x70,
+    0x6a, 0x34, 0x52, 0x57, 0x50, 0x48, 0x6c, 0x4c, 0x77, 0x4a, 0x41, 0x47,
+    0x55, 0x4d, 0x6b, 0x33, 0x62, 0x71, 0x54, 0x39, 0x31, 0x78, 0x42, 0x55,
+    0x43, 0x6e, 0x4c, 0x52, 0x73, 0x2f, 0x76, 0x66, 0x6f, 0x43, 0x70, 0x48,
+    0x70, 0x67, 0x36, 0x65, 0x79, 0x77, 0x51, 0x54, 0x42, 0x44, 0x41, 0x56,
+    0x36, 0x78, 0x6b, 0x79, 0x7a, 0x34, 0x61, 0x0a, 0x52, 0x48, 0x33, 0x49,
+    0x37, 0x2f, 0x2b, 0x79, 0x6a, 0x33, 0x5a, 0x78, 0x52, 0x32, 0x4a, 0x6f,
+    0x57, 0x48, 0x67, 0x55, 0x77, 0x5a, 0x37, 0x6c, 0x5a, 0x6b, 0x31, 0x56,
+    0x6e, 0x68, 0x66, 0x66, 0x46, 0x79, 0x65, 0x37, 0x53, 0x42, 0x58, 0x79,
+    0x61, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e,
+    0x44, 0x20, 0x52, 0x53, 0x41, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54,
+    0x45, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a};
+unsigned int test_server1_key_size = 887;
diff --git a/test/core/end2end/data/ssl_test_data.h b/test/core/end2end/data/ssl_test_data.h
new file mode 100644
index 0000000..75263b8
--- /dev/null
+++ b/test/core/end2end/data/ssl_test_data.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_TEST_END2END_DATA_SSL_TEST_DATA_H__
+#define __GRPC_TEST_END2END_DATA_SSL_TEST_DATA_H__
+
+extern unsigned char test_ca_cert[];
+extern unsigned int test_ca_cert_size;
+extern unsigned char test_server1_cert[];
+extern unsigned int test_server1_cert_size;
+extern unsigned char test_server1_key[];
+extern unsigned int test_server1_key_size;
+
+#endif  /* __GRPC_TEST_END2END_DATA_SSL_TEST_DATA_H__ */
diff --git a/test/core/end2end/end2end_tests.c b/test/core/end2end/end2end_tests.c
new file mode 100644
index 0000000..7174d09
--- /dev/null
+++ b/test/core/end2end/end2end_tests.c
@@ -0,0 +1,1285 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+static void test_no_op(grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void simple_request_body(grpc_end2end_test_fixture f) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(4)));
+  cq_expect_finish_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s, f.server_cq, tag(102), 0));
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(5)));
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(5), GRPC_OP_OK);
+  cq_verify(v_server);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+/* an alternative ordering of the simple request body */
+static void simple_request_body2(grpc_end2end_test_fixture f) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(4)));
+  cq_expect_finish_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s, f.server_cq, tag(102), 0));
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(5)));
+  cq_expect_finish_accepted(v_server, tag(5), GRPC_OP_OK);
+  cq_verify(v_server);
+
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+static void test_invoke_simple_request(
+    grpc_end2end_test_config config, const char *name,
+    void (*body)(grpc_end2end_test_fixture f)) {
+  char fullname[64];
+  grpc_end2end_test_fixture f;
+
+  sprintf(fullname, "%s/%s", __FUNCTION__, name);
+
+  f = begin_test(config, fullname, NULL, NULL);
+  body(f);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void test_invoke_10_simple_requests(grpc_end2end_test_config config) {
+  int i;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  for (i = 0; i < 10; i++) {
+    simple_request_body(f);
+    gpr_log(GPR_INFO, "Passed simple request %d", i);
+  }
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void simple_delayed_request_body(grpc_end2end_test_config config,
+                                        grpc_end2end_test_fixture *f,
+                                        grpc_channel_args *client_args,
+                                        grpc_channel_args *server_args,
+                                        long delay_us) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f->client_cq);
+  cq_verifier *v_server = cq_verifier_create(f->server_cq);
+
+  config.init_client(f, client_args);
+
+  c = grpc_channel_create_call(f->client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_invoke(c, f->client_cq, tag(1),
+                                                    tag(2), tag(3), 0));
+  gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_micros(delay_us)));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+
+  config.init_server(f, server_args);
+
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(4)));
+  cq_expect_finish_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f->server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s, f->server_cq, tag(102), 0));
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(5)));
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(5), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+static void test_simple_delayed_request_short(grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f;
+
+  gpr_log(GPR_INFO, "%s/%s", __FUNCTION__, config.name);
+  f = config.create_fixture(NULL, NULL);
+  simple_delayed_request_body(config, &f, NULL, NULL, 100000);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void test_simple_delayed_request_long(grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f;
+
+  gpr_log(GPR_INFO, "%s/%s", __FUNCTION__, config.name);
+  f = config.create_fixture(NULL, NULL);
+  /* This timeout should be longer than a single retry */
+  simple_delayed_request_body(config, &f, NULL, NULL, 1500000);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+/* Client sends a request with payload, server reads then returns status. */
+static void test_invoke_request_with_payload(grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_slice payload_slice = gpr_slice_from_copied_string("hello world");
+  grpc_byte_buffer *payload = grpc_byte_buffer_create(&payload_slice, 1);
+  gpr_timespec deadline = five_seconds_time();
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  /* byte buffer holds the slice, we can unref it already */
+  gpr_slice_unref(payload_slice);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_write(c, payload, tag(4), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(payload);
+  cq_expect_write_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  grpc_call_accept(s, f.server_cq, tag(102), 0);
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(s, tag(4)));
+  cq_expect_read(v_server, tag(4), gpr_slice_from_copied_string("hello world"));
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(5)));
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(6)));
+  cq_expect_finish_accepted(v_client, tag(5), GRPC_OP_OK);
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(6), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+/* test the case when there is a pending message at the client side,
+   writes_done should not return a status without a start_read.
+   Note: this test will last for 3s. Do not run in a loop. */
+static void test_writes_done_hangs_with_pending_read(
+    grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
+  gpr_slice response_payload_slice = gpr_slice_from_copied_string("hello you");
+  grpc_byte_buffer *request_payload =
+      grpc_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer *response_payload =
+      grpc_byte_buffer_create(&response_payload_slice, 1);
+  gpr_timespec deadline = five_seconds_time();
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  /* byte buffer holds the slice, we can unref it already */
+  gpr_slice_unref(request_payload_slice);
+  gpr_slice_unref(response_payload_slice);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write(c, request_payload, tag(4), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(request_payload);
+  cq_expect_write_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  grpc_call_accept(s, f.server_cq, tag(102), 0);
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(s, tag(5)));
+  cq_expect_read(v_server, tag(5), gpr_slice_from_copied_string("hello world"));
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write(s, response_payload, tag(6), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(response_payload);
+  cq_expect_write_accepted(v_server, tag(6), GRPC_OP_OK);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(6)));
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(7)));
+
+  cq_expect_finish_accepted(v_client, tag(6), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  /* does not return status because there is a pending message to be read */
+  cq_verify_empty(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(c, tag(8)));
+  cq_expect_read(v_client, tag(8), gpr_slice_from_copied_string("hello you"));
+  cq_verify(v_client);
+
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(7), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+static void request_response_with_payload(grpc_end2end_test_fixture f) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
+  gpr_slice response_payload_slice = gpr_slice_from_copied_string("hello you");
+  grpc_byte_buffer *request_payload =
+      grpc_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer *response_payload =
+      grpc_byte_buffer_create(&response_payload_slice, 1);
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  /* byte buffer holds the slice, we can unref it already */
+  gpr_slice_unref(request_payload_slice);
+  gpr_slice_unref(response_payload_slice);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write(c, request_payload, tag(4), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(request_payload);
+  cq_expect_write_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  grpc_call_accept(s, f.server_cq, tag(102), 0);
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(s, tag(5)));
+  cq_expect_read(v_server, tag(5), gpr_slice_from_copied_string("hello world"));
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write(s, response_payload, tag(6), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(response_payload);
+  cq_expect_write_accepted(v_server, tag(6), GRPC_OP_OK);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(c, tag(7)));
+  cq_expect_read(v_client, tag(7), gpr_slice_from_copied_string("hello you"));
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(8)));
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(9)));
+
+  cq_expect_finish_accepted(v_client, tag(8), GRPC_OP_OK);
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(9), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+/* Client sends a request with payload, server reads then returns a response
+   payload and status. */
+static void test_invoke_request_response_with_payload(
+    grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  request_response_with_payload(f);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void test_invoke_10_request_response_with_payload(
+    grpc_end2end_test_config config) {
+  int i;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  for (i = 0; i < 10; i++) {
+    request_response_with_payload(f);
+  }
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+/* allow cancellation by either grpc_call_cancel, or by wait_for_deadline (which
+ * does nothing) */
+typedef grpc_call_error (*canceller)(grpc_call *call);
+
+static grpc_call_error wait_for_deadline(grpc_call *call) {
+  return GRPC_CALL_OK;
+}
+
+/* Cancel and do nothing */
+static void test_cancel_in_a_vacuum(grpc_end2end_test_config config,
+                                    canceller call_cancel) {
+  grpc_call *c;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK == call_cancel(c));
+
+  grpc_call_destroy(c);
+
+  cq_verifier_destroy(v_client);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+/* Cancel before invoke */
+static void test_cancel_before_invoke(grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  grpc_status chk_status = {GRPC_STATUS_CANCELLED, NULL};
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_cancel(c));
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_ERROR);
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_expect_finished_with_status(v_client, tag(3), chk_status, NULL);
+  cq_verify(v_client);
+
+  grpc_call_destroy(c);
+
+  cq_verifier_destroy(v_client);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+/* Cancel after invoke, no payload */
+static void test_cancel_after_invoke(grpc_end2end_test_config config,
+                                     canceller call_cancel) {
+  grpc_call *c;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  grpc_status chk_status = {GRPC_STATUS_CANCELLED, NULL};
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == call_cancel(c));
+
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_expect_finished_with_status(v_client, tag(3), chk_status, NULL);
+  cq_verify(v_client);
+
+  grpc_call_destroy(c);
+
+  cq_verifier_destroy(v_client);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+/* Cancel after accept, no payload */
+static void test_cancel_after_accept(grpc_end2end_test_config config,
+                                     canceller call_cancel) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  grpc_status chk_status = {GRPC_STATUS_CANCELLED, NULL};
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s, f.server_cq, tag(102), 0));
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == call_cancel(c));
+
+  cq_expect_finished_with_status(v_client, tag(3), chk_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finished_with_status(v_server, tag(102), chk_status, NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+/* Cancel after accept with a writes closed, no payload */
+static void test_cancel_after_accept_and_writes_closed(
+    grpc_end2end_test_config config, canceller call_cancel) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  grpc_status chk_status = {GRPC_STATUS_CANCELLED, NULL};
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s, f.server_cq, tag(102), 0));
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(4)));
+  cq_expect_finish_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(s, tag(101)));
+  cq_expect_empty_read(v_server, tag(101));
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == call_cancel(c));
+
+  cq_expect_finished_with_status(v_client, tag(3), chk_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finished_with_status(v_server, tag(102), chk_status, NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+/* Request/response with metadata and payload.*/
+static void test_request_response_with_metadata_and_payload(
+    grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
+  gpr_slice response_payload_slice = gpr_slice_from_copied_string("hello you");
+  grpc_byte_buffer *request_payload =
+      grpc_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer *response_payload =
+      grpc_byte_buffer_create(&response_payload_slice, 1);
+  gpr_timespec deadline = five_seconds_time();
+  grpc_metadata meta1 = {"key1", "val1", 4};
+  grpc_metadata meta2 = {"key2", "val2", 4};
+  grpc_metadata meta3 = {"key3", "val3", 4};
+  grpc_metadata meta4 = {"key4", "val4", 4};
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+
+  /* byte buffer holds the slice, we can unref it already */
+  gpr_slice_unref(request_payload_slice);
+  gpr_slice_unref(response_payload_slice);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  /* add multiple metadata */
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_add_metadata(c, &meta1, 0));
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_add_metadata(c, &meta2, 0));
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write(c, request_payload, tag(4), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(request_payload);
+  cq_expect_write_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, "key1", "val1", "key2", "val2", NULL);
+  cq_verify(v_server);
+
+  /* add multiple metadata */
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_add_metadata(s, &meta3, 0));
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_add_metadata(s, &meta4, 0));
+
+  grpc_call_accept(s, f.server_cq, tag(102), 0);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(s, tag(5)));
+  cq_expect_read(v_server, tag(5), gpr_slice_from_copied_string("hello world"));
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write(s, response_payload, tag(6), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(response_payload);
+  cq_expect_write_accepted(v_server, tag(6), GRPC_OP_OK);
+  cq_verify(v_server);
+
+  /* fetch metadata.. */
+  cq_expect_client_metadata_read(v_client, tag(2), "key3", "val3", "key4",
+                                 "val4", NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(c, tag(7)));
+  cq_expect_read(v_client, tag(7), gpr_slice_from_copied_string("hello you"));
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(8)));
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(9)));
+
+  cq_expect_finish_accepted(v_client, tag(8), GRPC_OP_OK);
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(9), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+/* Request with a large amount of metadata.*/
+static void test_request_with_large_metadata(grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_OK, NULL};
+  gpr_timespec deadline = five_seconds_time();
+  grpc_metadata meta;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  const int large_size = 64 * 1024;
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+
+  meta.key = "key";
+  meta.value = gpr_malloc(large_size + 1);
+  memset(meta.value, 'a', large_size);
+  meta.value[large_size] = 0;
+  meta.value_length = large_size;
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  /* add the metadata */
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_add_metadata(c, &meta, 0));
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, "key", meta.value, NULL);
+  cq_verify(v_server);
+
+  grpc_call_accept(s, f.server_cq, tag(102), 0);
+
+  /* fetch metadata.. */
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(8)));
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(9)));
+
+  cq_expect_finish_accepted(v_client, tag(8), GRPC_OP_OK);
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(9), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+
+  gpr_free(meta.value);
+}
+
+/* Client pings and server pongs. Repeat messages rounds before finishing. */
+static void test_pingpong_streaming(grpc_end2end_test_config config,
+                                    int messages) {
+  int i;
+  grpc_call *c;
+  grpc_call *s = NULL;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
+  gpr_slice response_payload_slice = gpr_slice_from_copied_string("hello you");
+  grpc_byte_buffer *request_payload = NULL;
+  grpc_byte_buffer *response_payload = NULL;
+  gpr_timespec deadline = n_seconds_time(messages * 5);
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  gpr_log(GPR_INFO, "testing with %d message pairs.", messages);
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+  grpc_call_accept(s, f.server_cq, tag(102), 0);
+
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  for (i = 0; i < messages; i++) {
+    request_payload = grpc_byte_buffer_create(&request_payload_slice, 1);
+    GPR_ASSERT(GRPC_CALL_OK ==
+               grpc_call_start_write(c, request_payload, tag(2), 0));
+    /* destroy byte buffer early to ensure async code keeps track of its
+       contents
+       correctly */
+    grpc_byte_buffer_destroy(request_payload);
+    cq_expect_write_accepted(v_client, tag(2), GRPC_OP_OK);
+    cq_verify(v_client);
+
+    GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(s, tag(3)));
+    cq_expect_read(v_server, tag(3),
+                   gpr_slice_from_copied_string("hello world"));
+    cq_verify(v_server);
+
+    response_payload = grpc_byte_buffer_create(&response_payload_slice, 1);
+    GPR_ASSERT(GRPC_CALL_OK ==
+               grpc_call_start_write(s, response_payload, tag(4), 0));
+    /* destroy byte buffer early to ensure async code keeps track of its
+       contents
+       correctly */
+    grpc_byte_buffer_destroy(response_payload);
+    cq_expect_write_accepted(v_server, tag(4), GRPC_OP_OK);
+    cq_verify(v_server);
+
+    GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(c, tag(5)));
+    cq_expect_read(v_client, tag(5), gpr_slice_from_copied_string("hello you"));
+    cq_verify(v_client);
+  }
+
+  gpr_slice_unref(request_payload_slice);
+  gpr_slice_unref(response_payload_slice);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(6)));
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(7)));
+
+  cq_expect_finish_accepted(v_client, tag(6), GRPC_OP_OK);
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(7), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+static void test_early_server_shutdown_finishes_tags(
+    grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  grpc_call *s = (void *)1;
+
+  /* upon shutdown, the server should finish all requested calls indicating
+     no new call */
+  grpc_server_request_call(f.server, tag(1000));
+  grpc_server_shutdown(f.server);
+  cq_expect_server_rpc_new(v_server, &s, tag(1000), NULL, NULL, gpr_inf_past,
+                           NULL);
+  cq_verify(v_server);
+  GPR_ASSERT(s == NULL);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+  cq_verifier_destroy(v_server);
+}
+
+static void test_early_server_shutdown_finishes_inflight_calls(
+    grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status expect_status = {GRPC_STATUS_UNAVAILABLE, NULL};
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(4)));
+  cq_expect_finish_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s, f.server_cq, tag(102), 0));
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  /* shutdown and destroy the server */
+  shutdown_server(&f);
+
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(s);
+
+  cq_expect_finished_with_status(v_client, tag(3), expect_status, NULL);
+  cq_verify(v_client);
+
+  grpc_call_destroy(c);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void test_max_concurrent_streams(grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f;
+  grpc_arg server_arg;
+  grpc_channel_args server_args;
+  grpc_call *c1;
+  grpc_call *c2;
+  grpc_call *s1;
+  grpc_call *s2;
+  gpr_timespec deadline;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  cq_verifier *v_client;
+  cq_verifier *v_server;
+
+  server_arg.key = GRPC_ARG_MAX_CONCURRENT_STREAMS;
+  server_arg.type = GRPC_ARG_INTEGER;
+  server_arg.value.integer = 1;
+
+  server_args.num_args = 1;
+  server_args.args = &server_arg;
+
+  f = begin_test(config, __FUNCTION__, NULL, &server_args);
+  v_client = cq_verifier_create(f.client_cq);
+  v_server = cq_verifier_create(f.server_cq);
+
+  /* perform a ping-pong to ensure that settings have had a chance to round
+     trip */
+  simple_request_body(f);
+  /* perform another one to make sure that the one stream case still works */
+  simple_request_body(f);
+
+  /* start two requests - ensuring that the second is not accepted until
+     the first completes */
+  deadline = five_seconds_time();
+  c1 = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c1);
+  c2 = grpc_channel_create_call(f.client, "/bar", "test.google.com", deadline);
+  GPR_ASSERT(c1);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_invoke(c1, f.client_cq, tag(300),
+                                                    tag(301), tag(302), 0));
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_invoke(c2, f.client_cq, tag(400),
+                                                    tag(401), tag(402), 0));
+  cq_expect_invoke_accepted(v_client, tag(300), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c1, tag(303)));
+  cq_expect_finish_accepted(v_client, tag(303), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  cq_expect_server_rpc_new(v_server, &s1, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s1, f.server_cq, tag(102), 0));
+  cq_expect_client_metadata_read(v_client, tag(301), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s1, send_status, tag(103)));
+  cq_expect_finish_accepted(v_server, tag(103), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  /* first request is finished, we should be able to start the second */
+  cq_expect_finished_with_status(v_client, tag(302), send_status, NULL);
+  cq_expect_invoke_accepted(v_client, tag(400), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c2, tag(403)));
+  cq_expect_finish_accepted(v_client, tag(403), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(200)));
+  cq_expect_server_rpc_new(v_server, &s2, tag(200), "/bar", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s2, f.server_cq, tag(202), 0));
+  cq_expect_client_metadata_read(v_client, tag(401), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s2, send_status, tag(203)));
+  cq_expect_finish_accepted(v_server, tag(203), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(202), NULL);
+  cq_verify(v_server);
+
+  cq_expect_finished_with_status(v_client, tag(402), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+
+  grpc_call_destroy(c1);
+  grpc_call_destroy(s1);
+  grpc_call_destroy(c2);
+  grpc_call_destroy(s2);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static gpr_slice large_slice() {
+  gpr_slice slice = gpr_slice_malloc(1000000);
+  memset(GPR_SLICE_START_PTR(slice), 0xab, GPR_SLICE_LENGTH(slice));
+  return slice;
+}
+
+static void test_invoke_large_request(grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_slice request_payload_slice = large_slice();
+  grpc_byte_buffer *request_payload =
+      grpc_byte_buffer_create(&request_payload_slice, 1);
+  gpr_timespec deadline = five_seconds_time();
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  /* byte buffer holds the slice, we can unref it already */
+  gpr_slice_unref(request_payload_slice);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write(c, request_payload, tag(4), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(request_payload);
+  /* write should not be accepted until the server is willing to read the
+     request (as this request is very large) */
+  cq_verify_empty(v_client);
+
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  grpc_call_accept(s, f.server_cq, tag(102), 0);
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(s, tag(5)));
+  /* now the write can be accepted */
+  cq_expect_write_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+  cq_expect_read(v_server, tag(5), large_slice());
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(8)));
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(9)));
+
+  cq_expect_finish_accepted(v_client, tag(8), GRPC_OP_OK);
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(9), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  int i;
+  canceller cancellers[2] = {grpc_call_cancel, wait_for_deadline};
+
+  test_no_op(config);
+  test_invoke_simple_request(config, "simple_request_body",
+                             simple_request_body);
+  test_invoke_simple_request(config, "simple_request_body2",
+                             simple_request_body2);
+  test_invoke_10_simple_requests(config);
+  if (config.feature_mask & FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION) {
+    test_simple_delayed_request_short(config);
+    test_simple_delayed_request_long(config);
+  }
+  test_invoke_request_with_payload(config);
+  test_request_response_with_metadata_and_payload(config);
+  test_request_with_large_metadata(config);
+  test_writes_done_hangs_with_pending_read(config);
+  test_invoke_request_response_with_payload(config);
+  test_invoke_10_request_response_with_payload(config);
+  test_early_server_shutdown_finishes_tags(config);
+  test_early_server_shutdown_finishes_inflight_calls(config);
+  test_max_concurrent_streams(config);
+  test_invoke_large_request(config);
+  for (i = 0; i < GPR_ARRAY_SIZE(cancellers); i++) {
+    test_cancel_in_a_vacuum(config, cancellers[i]);
+    test_cancel_after_invoke(config, cancellers[i]);
+    test_cancel_after_accept(config, cancellers[i]);
+    test_cancel_after_accept_and_writes_closed(config, cancellers[i]);
+  }
+  test_cancel_before_invoke(config);
+  for (i = 1; i < 10; i++) {
+    test_pingpong_streaming(config, i);
+  }
+}
diff --git a/test/core/end2end/end2end_tests.h b/test/core/end2end/end2end_tests.h
new file mode 100644
index 0000000..b509b1a
--- /dev/null
+++ b/test/core/end2end/end2end_tests.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_TEST_END2END_END2END_TESTS_H__
+#define __GRPC_TEST_END2END_END2END_TESTS_H__
+
+#include <grpc/grpc.h>
+
+typedef struct grpc_end2end_test_fixture grpc_end2end_test_fixture;
+typedef struct grpc_end2end_test_config grpc_end2end_test_config;
+
+#define FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION 1
+
+struct grpc_end2end_test_fixture {
+  grpc_completion_queue *server_cq;
+  grpc_completion_queue *client_cq;
+  grpc_server *server;
+  grpc_channel *client;
+  void *fixture_data;
+};
+
+struct grpc_end2end_test_config {
+  const char *name;
+  gpr_uint32 feature_mask;
+  grpc_end2end_test_fixture (*create_fixture)(grpc_channel_args *client_args,
+                                              grpc_channel_args *server_args);
+  void (*init_client)(grpc_end2end_test_fixture *f,
+                      grpc_channel_args *client_args);
+  void (*init_server)(grpc_end2end_test_fixture *f,
+                      grpc_channel_args *server_args);
+  void (*tear_down_data)(grpc_end2end_test_fixture *f);
+};
+
+void grpc_end2end_tests(grpc_end2end_test_config config);
+
+#endif  /* __GRPC_TEST_END2END_END2END_TESTS_H__ */
diff --git a/test/core/end2end/fixtures/chttp2_fake_security.c b/test/core/end2end/fixtures/chttp2_fake_security.c
new file mode 100644
index 0000000..a1f29de
--- /dev/null
+++ b/test/core/end2end/fixtures/chttp2_fake_security.c
@@ -0,0 +1,139 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "src/core/channel/channel_args.h"
+#include "src/core/eventmanager/em.h"
+#include "src/core/security/credentials.h"
+#include "src/core/security/security_context.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+#include "test/core/util/port.h"
+#include "test/core/end2end/data/ssl_test_data.h"
+
+
+static grpc_em em;
+
+typedef struct fullstack_secure_fixture_data {
+  char *localaddr;
+} fullstack_secure_fixture_data;
+
+static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
+    grpc_channel_args *client_args, grpc_channel_args *server_args) {
+  grpc_end2end_test_fixture f;
+  int port = grpc_pick_unused_port_or_die();
+  fullstack_secure_fixture_data *ffd =
+      gpr_malloc(sizeof(fullstack_secure_fixture_data));
+
+  gpr_join_host_port(&ffd->localaddr, "localhost", port);
+
+  f.fixture_data = ffd;
+  f.client_cq = grpc_completion_queue_create();
+  f.server_cq = grpc_completion_queue_create();
+
+  return f;
+}
+
+static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f,
+                                                grpc_channel_args *client_args,
+                                                grpc_credentials *creds) {
+  fullstack_secure_fixture_data *ffd = f->fixture_data;
+  f->client = grpc_secure_channel_create(creds, ffd->localaddr, client_args);
+  GPR_ASSERT(f->client != NULL);
+  grpc_credentials_release(creds);
+}
+
+static void chttp2_init_server_secure_fullstack(
+    grpc_end2end_test_fixture *f, grpc_channel_args *server_args,
+    grpc_server_credentials *server_creds) {
+  fullstack_secure_fixture_data *ffd = f->fixture_data;
+  f->server =
+      grpc_secure_server_create(server_creds, f->server_cq, server_args);
+  grpc_server_credentials_release(server_creds);
+  grpc_server_add_secure_http2_port(f->server, ffd->localaddr);
+  grpc_server_start(f->server);
+}
+
+void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
+  fullstack_secure_fixture_data *ffd = f->fixture_data;
+  gpr_free(ffd->localaddr);
+  gpr_free(ffd);
+}
+
+static void chttp2_init_client_fake_secure_fullstack(
+    grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
+  grpc_credentials *fake_ts_creds =
+      grpc_fake_transport_security_credentials_create();
+  chttp2_init_client_secure_fullstack(f, client_args, fake_ts_creds);
+}
+
+static void chttp2_init_server_fake_secure_fullstack(
+    grpc_end2end_test_fixture *f, grpc_channel_args *server_args) {
+  grpc_server_credentials *fake_ts_creds =
+      grpc_fake_transport_security_server_credentials_create();
+  chttp2_init_server_secure_fullstack(f, server_args, fake_ts_creds);
+}
+
+/* All test configurations */
+
+static grpc_end2end_test_config configs[] = {
+    {"chttp2/fake_secure_fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION,
+     chttp2_create_fixture_secure_fullstack,
+     chttp2_init_client_fake_secure_fullstack,
+     chttp2_init_server_fake_secure_fullstack,
+     chttp2_tear_down_secure_fullstack},
+};
+
+int main(int argc, char **argv) {
+  size_t i;
+  grpc_test_init(argc, argv);
+
+
+  grpc_init();
+  grpc_em_init(&em);
+
+  for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
+    grpc_end2end_tests(configs[i]);
+  }
+
+  GPR_ASSERT(grpc_em_destroy(&em) == GRPC_EM_OK);
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/end2end/fixtures/chttp2_fullstack.c b/test/core/end2end/fixtures/chttp2_fullstack.c
new file mode 100644
index 0000000..da75d61
--- /dev/null
+++ b/test/core/end2end/fixtures/chttp2_fullstack.c
@@ -0,0 +1,123 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "src/core/channel/client_channel.h"
+#include "src/core/channel/connected_channel.h"
+#include "src/core/channel/http_filter.h"
+#include "src/core/channel/http_server_filter.h"
+#include "src/core/eventmanager/em.h"
+#include "src/core/surface/channel.h"
+#include "src/core/surface/client.h"
+#include "src/core/surface/server.h"
+#include "src/core/surface/surface_em.h"
+#include "src/core/transport/chttp2_transport.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 "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+typedef struct fullstack_fixture_data {
+  char *localaddr;
+} fullstack_fixture_data;
+
+static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
+    grpc_channel_args *client_args, grpc_channel_args *server_args) {
+  grpc_end2end_test_fixture f;
+  int port = grpc_pick_unused_port_or_die();
+  fullstack_fixture_data *ffd = gpr_malloc(sizeof(fullstack_fixture_data));
+
+  gpr_join_host_port(&ffd->localaddr, "localhost", port);
+
+  f.fixture_data = ffd;
+  f.client_cq = grpc_completion_queue_create();
+  f.server_cq = grpc_completion_queue_create();
+
+  return f;
+}
+
+void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
+                                  grpc_channel_args *client_args) {
+  fullstack_fixture_data *ffd = f->fixture_data;
+  f->client = grpc_channel_create(ffd->localaddr, client_args);
+}
+
+void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
+                                  grpc_channel_args *server_args) {
+  fullstack_fixture_data *ffd = f->fixture_data;
+  f->server = grpc_server_create(f->server_cq, server_args);
+  grpc_server_add_http2_port(f->server, ffd->localaddr);
+  grpc_server_start(f->server);
+}
+
+void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
+  fullstack_fixture_data *ffd = f->fixture_data;
+  gpr_free(ffd->localaddr);
+  gpr_free(ffd);
+}
+
+/* All test configurations */
+static grpc_end2end_test_config configs[] = {
+    {"chttp2/fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION,
+     chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
+     chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
+};
+
+int main(int argc, char **argv) {
+  size_t i;
+
+  grpc_test_init(argc, argv);
+  grpc_init();
+
+  for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
+    grpc_end2end_tests(configs[i]);
+  }
+
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
new file mode 100644
index 0000000..2dd3ce9
--- /dev/null
+++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
@@ -0,0 +1,146 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "src/core/channel/channel_args.h"
+#include "src/core/eventmanager/em.h"
+#include "src/core/security/credentials.h"
+#include "src/core/security/security_context.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+#include "test/core/util/port.h"
+#include "test/core/end2end/data/ssl_test_data.h"
+
+
+static grpc_em em;
+
+typedef struct fullstack_secure_fixture_data {
+  char *localaddr;
+} fullstack_secure_fixture_data;
+
+static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
+    grpc_channel_args *client_args, grpc_channel_args *server_args) {
+  grpc_end2end_test_fixture f;
+  int port = grpc_pick_unused_port_or_die();
+  fullstack_secure_fixture_data *ffd =
+      gpr_malloc(sizeof(fullstack_secure_fixture_data));
+
+  gpr_join_host_port(&ffd->localaddr, "localhost", port);
+
+  f.fixture_data = ffd;
+  f.client_cq = grpc_completion_queue_create();
+  f.server_cq = grpc_completion_queue_create();
+
+  return f;
+}
+
+static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f,
+                                                grpc_channel_args *client_args,
+                                                grpc_credentials *creds) {
+  fullstack_secure_fixture_data *ffd = f->fixture_data;
+  f->client = grpc_secure_channel_create(creds, ffd->localaddr, client_args);
+  GPR_ASSERT(f->client != NULL);
+  grpc_credentials_release(creds);
+}
+
+static void chttp2_init_server_secure_fullstack(
+    grpc_end2end_test_fixture *f, grpc_channel_args *server_args,
+    grpc_server_credentials *server_creds) {
+  fullstack_secure_fixture_data *ffd = f->fixture_data;
+  f->server =
+      grpc_secure_server_create(server_creds, f->server_cq, server_args);
+  grpc_server_credentials_release(server_creds);
+  grpc_server_add_secure_http2_port(f->server, ffd->localaddr);
+  grpc_server_start(f->server);
+}
+
+void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
+  fullstack_secure_fixture_data *ffd = f->fixture_data;
+  gpr_free(ffd->localaddr);
+  gpr_free(ffd);
+}
+
+static void chttp2_init_client_simple_ssl_secure_fullstack(
+    grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
+  grpc_credentials *ssl_creds = grpc_ssl_credentials_create(
+      test_ca_cert, test_ca_cert_size, NULL, 0, NULL, 0);
+  grpc_arg ssl_name_override = {GRPC_ARG_STRING,
+                                GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
+                                {"foo.test.google.com"}};
+  grpc_channel_args *new_client_args =
+      grpc_channel_args_copy_and_add(client_args, &ssl_name_override);
+  chttp2_init_client_secure_fullstack(f, new_client_args, ssl_creds);
+  grpc_channel_args_destroy(new_client_args);
+}
+
+static void chttp2_init_server_simple_ssl_secure_fullstack(
+    grpc_end2end_test_fixture *f, grpc_channel_args *server_args) {
+  grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create(
+      NULL, 0, test_server1_key, test_server1_key_size, test_server1_cert,
+      test_server1_cert_size);
+  chttp2_init_server_secure_fullstack(f, server_args, ssl_creds);
+}
+
+/* All test configurations */
+
+static grpc_end2end_test_config configs[] = {
+    {"chttp2/simple_ssl_fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION,
+     chttp2_create_fixture_secure_fullstack,
+     chttp2_init_client_simple_ssl_secure_fullstack,
+     chttp2_init_server_simple_ssl_secure_fullstack,
+     chttp2_tear_down_secure_fullstack},
+};
+
+int main(int argc, char **argv) {
+  size_t i;
+  grpc_test_init(argc, argv);
+
+
+  grpc_init();
+  grpc_em_init(&em);
+
+  for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
+    grpc_end2end_tests(configs[i]);
+  }
+
+  GPR_ASSERT(grpc_em_destroy(&em) == GRPC_EM_OK);
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c
new file mode 100644
index 0000000..22720c5
--- /dev/null
+++ b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c
@@ -0,0 +1,146 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "src/core/channel/channel_args.h"
+#include "src/core/eventmanager/em.h"
+#include "src/core/security/credentials.h"
+#include "src/core/security/security_context.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+#include "test/core/util/port.h"
+#include "test/core/end2end/data/ssl_test_data.h"
+
+
+static grpc_em em;
+
+typedef struct fullstack_secure_fixture_data {
+  char *localaddr;
+} fullstack_secure_fixture_data;
+
+static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
+    grpc_channel_args *client_args, grpc_channel_args *server_args) {
+  grpc_end2end_test_fixture f;
+  int port = grpc_pick_unused_port_or_die();
+  fullstack_secure_fixture_data *ffd =
+      gpr_malloc(sizeof(fullstack_secure_fixture_data));
+
+  gpr_join_host_port(&ffd->localaddr, "localhost", port);
+
+  f.fixture_data = ffd;
+  f.client_cq = grpc_completion_queue_create();
+  f.server_cq = grpc_completion_queue_create();
+
+  return f;
+}
+
+static void chttp2_init_server_secure_fullstack(
+    grpc_end2end_test_fixture *f, grpc_channel_args *server_args,
+    grpc_server_credentials *server_creds) {
+  fullstack_secure_fixture_data *ffd = f->fixture_data;
+  f->server =
+      grpc_secure_server_create(server_creds, f->server_cq, server_args);
+  grpc_server_credentials_release(server_creds);
+  grpc_server_add_secure_http2_port(f->server, ffd->localaddr);
+  grpc_server_start(f->server);
+}
+
+void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
+  fullstack_secure_fixture_data *ffd = f->fixture_data;
+  gpr_free(ffd->localaddr);
+  gpr_free(ffd);
+}
+
+static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack(
+    grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
+  /* TODO(jboeuf): Replace with composite credentials when those are
+     implemented. */
+  grpc_channel_security_context *client_ctx = NULL;
+  fullstack_secure_fixture_data *ffd = f->fixture_data;
+  grpc_ssl_config config;
+  grpc_credentials *oauth2 =
+      grpc_fake_oauth2_credentials_create("Bearer aaslkfjs424535asdf", 1);
+  memset(&config, 0, sizeof(grpc_ssl_config));
+  config.pem_root_certs = test_ca_cert;
+  config.pem_root_certs_size = test_ca_cert_size;
+  GPR_ASSERT(grpc_ssl_channel_security_context_create(
+                 oauth2, &config, "foo.test.google.com", &client_ctx) ==
+             GRPC_SECURITY_OK);
+  f->client = grpc_secure_channel_create_internal(ffd->localaddr, client_args,
+                                                  client_ctx);
+  grpc_security_context_unref(&client_ctx->base);
+  grpc_credentials_unref(oauth2);
+}
+
+static void chttp2_init_server_simple_ssl_secure_fullstack(
+    grpc_end2end_test_fixture *f, grpc_channel_args *server_args) {
+  grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create(
+      NULL, 0, test_server1_key, test_server1_key_size, test_server1_cert,
+      test_server1_cert_size);
+  chttp2_init_server_secure_fullstack(f, server_args, ssl_creds);
+}
+
+/* All test configurations */
+
+static grpc_end2end_test_config configs[] = {
+    {"chttp2/simple_ssl_with_oauth2_fullstack",
+     FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION,
+     chttp2_create_fixture_secure_fullstack,
+     chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack,
+     chttp2_init_server_simple_ssl_secure_fullstack,
+     chttp2_tear_down_secure_fullstack},
+};
+
+int main(int argc, char **argv) {
+  size_t i;
+  grpc_test_init(argc, argv);
+
+
+  grpc_init();
+  grpc_em_init(&em);
+
+  for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
+    grpc_end2end_tests(configs[i]);
+  }
+
+  GPR_ASSERT(grpc_em_destroy(&em) == GRPC_EM_OK);
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/end2end/fixtures/chttp2_socket_pair.c b/test/core/end2end/fixtures/chttp2_socket_pair.c
new file mode 100644
index 0000000..593ff78
--- /dev/null
+++ b/test/core/end2end/fixtures/chttp2_socket_pair.c
@@ -0,0 +1,169 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "src/core/channel/client_channel.h"
+#include "src/core/channel/connected_channel.h"
+#include "src/core/channel/http_filter.h"
+#include "src/core/channel/http_server_filter.h"
+#include "src/core/eventmanager/em.h"
+#include "src/core/surface/channel.h"
+#include "src/core/surface/client.h"
+#include "src/core/surface/server.h"
+#include "src/core/surface/surface_em.h"
+#include "src/core/transport/chttp2_transport.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 "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+static void create_sockets(int sv[2]) {
+  int flags;
+  GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
+  flags = fcntl(sv[0], F_GETFL, 0);
+  GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0);
+  flags = fcntl(sv[1], F_GETFL, 0);
+  GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
+}
+
+/* chttp2 transport that is immediately available (used for testing
+   connected_channel without a client_channel */
+
+static grpc_transport_setup_result server_setup_transport(
+    void *ts, grpc_transport *transport, grpc_mdctx *mdctx) {
+  grpc_end2end_test_fixture *f = ts;
+  static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter,
+                                                       &grpc_http_filter};
+  return grpc_server_setup_transport(f->server, transport, extra_filters,
+                                     GPR_ARRAY_SIZE(extra_filters), mdctx);
+}
+
+typedef struct {
+  grpc_end2end_test_fixture *f;
+  grpc_channel_args *client_args;
+} sp_client_setup;
+
+static grpc_transport_setup_result client_setup_transport(
+    void *ts, grpc_transport *transport, grpc_mdctx *mdctx) {
+  sp_client_setup *cs = ts;
+
+  const grpc_channel_filter *filters[] = {&grpc_client_surface_filter,
+                                          &grpc_connected_channel_filter};
+  size_t nfilters = sizeof(filters) / sizeof(*filters);
+  grpc_channel *channel = grpc_channel_create_from_filters(
+      filters, nfilters, cs->client_args, mdctx, 1);
+
+  cs->f->client = channel;
+
+  return grpc_connected_channel_bind_transport(
+      grpc_channel_get_channel_stack(channel), transport);
+}
+
+typedef struct socketpair_fixture_data { int sv[2]; } socketpair_fixture_data;
+
+static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
+    grpc_channel_args *client_args, grpc_channel_args *server_args) {
+  socketpair_fixture_data *sfd = gpr_malloc(sizeof(socketpair_fixture_data));
+
+  grpc_end2end_test_fixture f;
+  f.fixture_data = sfd;
+  f.client_cq = grpc_completion_queue_create();
+  f.server_cq = grpc_completion_queue_create();
+  f.server = grpc_server_create_from_filters(f.server_cq, NULL, 0, server_args);
+  f.client = NULL;
+
+  create_sockets(sfd->sv);
+
+  return f;
+}
+
+static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f,
+                                          grpc_channel_args *client_args) {
+  socketpair_fixture_data *sfd = f->fixture_data;
+  grpc_endpoint *cli_tcp;
+  sp_client_setup cs;
+  cs.client_args = client_args;
+  cs.f = f;
+  cli_tcp = grpc_tcp_create_dbg(sfd->sv[0], grpc_surface_em(), 65536);
+  grpc_create_chttp2_transport(client_setup_transport, &cs, client_args,
+                               cli_tcp, NULL, 0, grpc_mdctx_create(), 1);
+  GPR_ASSERT(f->client);
+}
+
+static void chttp2_init_server_socketpair(grpc_end2end_test_fixture *f,
+                                          grpc_channel_args *server_args) {
+  socketpair_fixture_data *sfd = f->fixture_data;
+  grpc_endpoint *svr_tcp;
+  svr_tcp = grpc_tcp_create_dbg(sfd->sv[1], grpc_surface_em(), 65536);
+  grpc_create_chttp2_transport(server_setup_transport, f, server_args, svr_tcp,
+                               NULL, 0, grpc_mdctx_create(), 0);
+}
+
+static void chttp2_tear_down_socketpair(grpc_end2end_test_fixture *f) {
+  gpr_free(f->fixture_data);
+}
+
+/* All test configurations */
+static grpc_end2end_test_config configs[] = {
+    {"chttp2/socketpair", 0, chttp2_create_fixture_socketpair,
+     chttp2_init_client_socketpair, chttp2_init_server_socketpair,
+     chttp2_tear_down_socketpair},
+};
+
+int main(int argc, char **argv) {
+  size_t i;
+
+  grpc_test_init(argc, argv);
+  grpc_init();
+
+  for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
+    grpc_end2end_tests(configs[i]);
+  }
+
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/end2end/gen_build_json.py b/test/core/end2end/gen_build_json.py
new file mode 100755
index 0000000..0bcccbe
--- /dev/null
+++ b/test/core/end2end/gen_build_json.py
@@ -0,0 +1,82 @@
+import simplejson
+
+END2END_FIXTURES = [
+    'chttp2_fake_security',
+    'chttp2_fullstack',
+    'chttp2_simple_ssl_fullstack',
+    'chttp2_simple_ssl_with_oauth2_fullstack',
+    'chttp2_socket_pair',
+]
+
+
+END2END_TESTS = [
+    'cancel_after_accept',
+    'cancel_after_accept_and_writes_closed',
+    'cancel_after_invoke',
+    'cancel_before_invoke',
+    'cancel_in_a_vacuum',
+    'early_server_shutdown_finishes_inflight_calls',
+    'early_server_shutdown_finishes_tags',
+    'invoke_large_request',
+    'max_concurrent_streams',
+    'no_op',
+    'ping_pong_streaming',
+    'request_response_with_metadata_and_payload',
+    'request_response_with_payload',
+    'simple_delayed_request',
+    'simple_request',
+    'thread_stress_test',
+    'writes_done_hangs_with_pending_read',
+]
+
+
+def main():
+  json = {
+      '#': 'generated with test/end2end/gen_build_json.py',
+      'libs': [
+          {
+              'name': 'end2end_fixture_%s' % f,
+              'build': 'private',
+              'secure': True,
+              'src': ['test/core/end2end/fixtures/%s.c' % f]
+          }
+          for f in END2END_FIXTURES] + [
+          {
+              'name': 'end2end_test_%s' % t,
+              'build': 'private',
+              'secure': False,
+              'src': ['test/core/end2end/tests/%s.c' % t]
+          }
+          for t in END2END_TESTS] + [
+          {
+              'name': 'end2end_certs',
+              'build': 'private',
+              'src': [
+                  "test/core/end2end/data/ca_cert.c",
+                  "test/core/end2end/data/server1_cert.c",
+                  "test/core/end2end/data/server1_key.c"
+              ]
+          }
+          ],
+      'targets': [
+          {
+              'name': '%s_%s_test' % (f, t),
+              'build': 'test',
+              'src': [],
+              'deps': [
+                  'end2end_fixture_%s' % f,
+                  'end2end_test_%s' % t,
+                  'end2end_certs',
+                  'grpc_test_util',
+                  'grpc',
+                  'gpr'
+              ]
+          }
+      for f in END2END_FIXTURES
+      for t in END2END_TESTS]}
+  print simplejson.dumps(json, sort_keys=True, indent=2 * ' ')
+
+
+if __name__ == '__main__':
+  main()
+
diff --git a/test/core/end2end/no_server_test.c b/test/core/end2end/no_server_test.c
new file mode 100644
index 0000000..f081056
--- /dev/null
+++ b/test/core/end2end/no_server_test.c
@@ -0,0 +1,83 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/util/test_config.h"
+
+static void *tag(gpr_intptr i) { return (void *)i; }
+
+int main(int argc, char **argv) {
+  grpc_channel *chan;
+  grpc_call *call;
+  gpr_timespec timeout = gpr_time_from_micros(4000000);
+  gpr_timespec deadline = gpr_time_add(gpr_now(), timeout);
+  grpc_completion_queue *cq;
+  cq_verifier *cqv;
+  grpc_event *ev;
+  int done;
+  grpc_status expect_status = {GRPC_STATUS_CANCELLED, NULL};
+
+  grpc_test_init(argc, argv);
+  grpc_init();
+
+  cq = grpc_completion_queue_create();
+  cqv = cq_verifier_create(cq);
+
+  /* create a call, channel to a non existant server */
+  chan = grpc_channel_create("nonexistant:54321", NULL);
+  call = grpc_channel_create_call(chan, "/foo", "nonexistant", deadline);
+  GPR_ASSERT(grpc_call_start_invoke(call, cq, tag(1), tag(2), tag(3), 0) ==
+             GRPC_CALL_OK);
+  /* verify that all tags get completed */
+  cq_expect_invoke_accepted(cqv, tag(1), GRPC_OP_ERROR);
+  cq_expect_client_metadata_read(cqv, tag(2), NULL);
+  cq_expect_finished_with_status(cqv, tag(3), expect_status, NULL);
+  cq_verify(cqv);
+
+  grpc_completion_queue_shutdown(cq);
+  for (done = 0; !done;) {
+    ev = grpc_completion_queue_next(cq, gpr_inf_future);
+    done = ev->type == GRPC_QUEUE_SHUTDOWN;
+    grpc_event_finish(ev);
+  }
+  grpc_completion_queue_destroy(cq);
+  grpc_call_destroy(call);
+  grpc_channel_destroy(chan);
+  cq_verifier_destroy(cqv);
+
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c
new file mode 100644
index 0000000..c9c3a18
--- /dev/null
+++ b/test/core/end2end/tests/cancel_after_accept.c
@@ -0,0 +1,166 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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"
+
+/* allow cancellation by either grpc_call_cancel, or by wait_for_deadline (which
+ * does nothing) */
+typedef grpc_call_error (*canceller)(grpc_call *call);
+
+static grpc_call_error wait_for_deadline(grpc_call *call) {
+  return GRPC_CALL_OK;
+}
+
+enum { TIMEOUT = 200000 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+/* Cancel after accept, no payload */
+static void test_cancel_after_accept(grpc_end2end_test_config config,
+                                     canceller call_cancel) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  grpc_status chk_status = {GRPC_STATUS_CANCELLED, NULL};
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s, f.server_cq, tag(102), 0));
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == call_cancel(c));
+
+  cq_expect_finished_with_status(v_client, tag(3), chk_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finished_with_status(v_server, tag(102), chk_status, NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  int i;
+  canceller cancellers[2] = {grpc_call_cancel, wait_for_deadline};
+
+  for (i = 0; i < GPR_ARRAY_SIZE(cancellers); i++) {
+    test_cancel_after_accept(config, cancellers[i]);
+  }
+}
diff --git a/test/core/end2end/tests/cancel_after_accept_and_writes_closed.c b/test/core/end2end/tests/cancel_after_accept_and_writes_closed.c
new file mode 100644
index 0000000..904dabe
--- /dev/null
+++ b/test/core/end2end/tests/cancel_after_accept_and_writes_closed.c
@@ -0,0 +1,173 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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"
+
+/* allow cancellation by either grpc_call_cancel, or by wait_for_deadline (which
+ * does nothing) */
+typedef grpc_call_error (*canceller)(grpc_call *call);
+
+static grpc_call_error wait_for_deadline(grpc_call *call) {
+  return GRPC_CALL_OK;
+}
+
+enum { TIMEOUT = 200000 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+/* Cancel after accept with a writes closed, no payload */
+static void test_cancel_after_accept_and_writes_closed(
+    grpc_end2end_test_config config, canceller call_cancel) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  grpc_status chk_status = {GRPC_STATUS_CANCELLED, NULL};
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s, f.server_cq, tag(102), 0));
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(4)));
+  cq_expect_finish_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(s, tag(101)));
+  cq_expect_empty_read(v_server, tag(101));
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == call_cancel(c));
+
+  cq_expect_finished_with_status(v_client, tag(3), chk_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finished_with_status(v_server, tag(102), chk_status, NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  int i;
+  canceller cancellers[2] = {grpc_call_cancel, wait_for_deadline};
+
+  for (i = 0; i < GPR_ARRAY_SIZE(cancellers); i++) {
+    test_cancel_after_accept_and_writes_closed(config, cancellers[i]);
+  }
+}
diff --git a/test/core/end2end/tests/cancel_after_invoke.c b/test/core/end2end/tests/cancel_after_invoke.c
new file mode 100644
index 0000000..5920813
--- /dev/null
+++ b/test/core/end2end/tests/cancel_after_invoke.c
@@ -0,0 +1,150 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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"
+
+/* allow cancellation by either grpc_call_cancel, or by wait_for_deadline (which
+ * does nothing) */
+typedef grpc_call_error (*canceller)(grpc_call *call);
+
+static grpc_call_error wait_for_deadline(grpc_call *call) {
+  return GRPC_CALL_OK;
+}
+
+enum { TIMEOUT = 200000 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+/* Cancel after invoke, no payload */
+static void test_cancel_after_invoke(grpc_end2end_test_config config,
+                                     canceller call_cancel) {
+  grpc_call *c;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  grpc_status chk_status = {GRPC_STATUS_CANCELLED, NULL};
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == call_cancel(c));
+
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_expect_finished_with_status(v_client, tag(3), chk_status, NULL);
+  cq_verify(v_client);
+
+  grpc_call_destroy(c);
+
+  cq_verifier_destroy(v_client);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  int i;
+  canceller cancellers[2] = {grpc_call_cancel, wait_for_deadline};
+
+  for (i = 0; i < GPR_ARRAY_SIZE(cancellers); i++) {
+    test_cancel_after_invoke(config, cancellers[i]);
+  }
+}
diff --git a/test/core/end2end/tests/cancel_before_invoke.c b/test/core/end2end/tests/cancel_before_invoke.c
new file mode 100644
index 0000000..afffc2f
--- /dev/null
+++ b/test/core/end2end/tests/cancel_before_invoke.c
@@ -0,0 +1,138 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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"
+
+/* allow cancellation by either grpc_call_cancel, or by wait_for_deadline (which
+ * does nothing) */
+typedef grpc_call_error (*canceller)(grpc_call *call);
+
+enum { TIMEOUT = 200000 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+/* Cancel before invoke */
+static void test_cancel_before_invoke(grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  grpc_status chk_status = {GRPC_STATUS_CANCELLED, NULL};
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_cancel(c));
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_ERROR);
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_expect_finished_with_status(v_client, tag(3), chk_status, NULL);
+  cq_verify(v_client);
+
+  grpc_call_destroy(c);
+
+  cq_verifier_destroy(v_client);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  test_cancel_before_invoke(config);
+}
diff --git a/test/core/end2end/tests/cancel_in_a_vacuum.c b/test/core/end2end/tests/cancel_in_a_vacuum.c
new file mode 100644
index 0000000..1a4dfa7
--- /dev/null
+++ b/test/core/end2end/tests/cancel_in_a_vacuum.c
@@ -0,0 +1,138 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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"
+
+/* allow cancellation by either grpc_call_cancel, or by wait_for_deadline (which
+ * does nothing) */
+typedef grpc_call_error (*canceller)(grpc_call *call);
+
+static grpc_call_error wait_for_deadline(grpc_call *call) {
+  return GRPC_CALL_OK;
+}
+
+enum { TIMEOUT = 200000 };
+
+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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+/* Cancel and do nothing */
+static void test_cancel_in_a_vacuum(grpc_end2end_test_config config,
+                                    canceller call_cancel) {
+  grpc_call *c;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK == call_cancel(c));
+
+  grpc_call_destroy(c);
+
+  cq_verifier_destroy(v_client);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  int i;
+  canceller cancellers[2] = {grpc_call_cancel, wait_for_deadline};
+
+  for (i = 0; i < GPR_ARRAY_SIZE(cancellers); i++) {
+    test_cancel_in_a_vacuum(config, cancellers[i]);
+  }
+}
diff --git a/test/core/end2end/tests/early_server_shutdown_finishes_inflight_calls.c b/test/core/end2end/tests/early_server_shutdown_finishes_inflight_calls.c
new file mode 100644
index 0000000..8d73e2c
--- /dev/null
+++ b/test/core/end2end/tests/early_server_shutdown_finishes_inflight_calls.c
@@ -0,0 +1,158 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+static void test_early_server_shutdown_finishes_inflight_calls(
+    grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status expect_status = {GRPC_STATUS_UNAVAILABLE, NULL};
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(4)));
+  cq_expect_finish_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s, f.server_cq, tag(102), 0));
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  /* shutdown and destroy the server */
+  shutdown_server(&f);
+
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(s);
+
+  cq_expect_finished_with_status(v_client, tag(3), expect_status, NULL);
+  cq_verify(v_client);
+
+  grpc_call_destroy(c);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  test_early_server_shutdown_finishes_inflight_calls(config);
+}
diff --git a/test/core/end2end/tests/early_server_shutdown_finishes_tags.c b/test/core/end2end/tests/early_server_shutdown_finishes_tags.c
new file mode 100644
index 0000000..eb3eb7c
--- /dev/null
+++ b/test/core/end2end/tests/early_server_shutdown_finishes_tags.c
@@ -0,0 +1,127 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+static void test_early_server_shutdown_finishes_tags(
+    grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  grpc_call *s = (void *)1;
+
+  /* upon shutdown, the server should finish all requested calls indicating
+     no new call */
+  grpc_server_request_call(f.server, tag(1000));
+  grpc_server_shutdown(f.server);
+  cq_expect_server_rpc_new(v_server, &s, tag(1000), NULL, NULL, gpr_inf_past,
+                           NULL);
+  cq_verify(v_server);
+  GPR_ASSERT(s == NULL);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+  cq_verifier_destroy(v_server);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  test_early_server_shutdown_finishes_tags(config);
+}
diff --git a/test/core/end2end/tests/invoke_large_request.c b/test/core/end2end/tests/invoke_large_request.c
new file mode 100644
index 0000000..7a3cab3
--- /dev/null
+++ b/test/core/end2end/tests/invoke_large_request.c
@@ -0,0 +1,184 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+static gpr_slice large_slice() {
+  gpr_slice slice = gpr_slice_malloc(1000000);
+  memset(GPR_SLICE_START_PTR(slice), 0xab, GPR_SLICE_LENGTH(slice));
+  return slice;
+}
+
+static void test_invoke_large_request(grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_slice request_payload_slice = large_slice();
+  grpc_byte_buffer *request_payload =
+      grpc_byte_buffer_create(&request_payload_slice, 1);
+  gpr_timespec deadline = five_seconds_time();
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  /* byte buffer holds the slice, we can unref it already */
+  gpr_slice_unref(request_payload_slice);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write(c, request_payload, tag(4), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(request_payload);
+  /* write should not be accepted until the server is willing to read the
+     request (as this request is very large) */
+  cq_verify_empty(v_client);
+
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  grpc_call_accept(s, f.server_cq, tag(102), 0);
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(s, tag(5)));
+  /* now the write can be accepted */
+  cq_expect_write_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+  cq_expect_read(v_server, tag(5), large_slice());
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(8)));
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(9)));
+
+  cq_expect_finish_accepted(v_client, tag(8), GRPC_OP_OK);
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(9), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  test_invoke_large_request(config);
+}
diff --git a/test/core/end2end/tests/max_concurrent_streams.c b/test/core/end2end/tests/max_concurrent_streams.c
new file mode 100644
index 0000000..6b331a5
--- /dev/null
+++ b/test/core/end2end/tests/max_concurrent_streams.c
@@ -0,0 +1,257 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+static void simple_request_body(grpc_end2end_test_fixture f) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(4)));
+  cq_expect_finish_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s, f.server_cq, tag(102), 0));
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(5)));
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(5), GRPC_OP_OK);
+  cq_verify(v_server);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+static void test_max_concurrent_streams(grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f;
+  grpc_arg server_arg;
+  grpc_channel_args server_args;
+  grpc_call *c1;
+  grpc_call *c2;
+  grpc_call *s1;
+  grpc_call *s2;
+  gpr_timespec deadline;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  cq_verifier *v_client;
+  cq_verifier *v_server;
+
+  server_arg.key = GRPC_ARG_MAX_CONCURRENT_STREAMS;
+  server_arg.type = GRPC_ARG_INTEGER;
+  server_arg.value.integer = 1;
+
+  server_args.num_args = 1;
+  server_args.args = &server_arg;
+
+  f = begin_test(config, __FUNCTION__, NULL, &server_args);
+  v_client = cq_verifier_create(f.client_cq);
+  v_server = cq_verifier_create(f.server_cq);
+
+  /* perform a ping-pong to ensure that settings have had a chance to round
+     trip */
+  simple_request_body(f);
+  /* perform another one to make sure that the one stream case still works */
+  simple_request_body(f);
+
+  /* start two requests - ensuring that the second is not accepted until
+     the first completes */
+  deadline = five_seconds_time();
+  c1 = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c1);
+  c2 = grpc_channel_create_call(f.client, "/bar", "test.google.com", deadline);
+  GPR_ASSERT(c1);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_invoke(c1, f.client_cq, tag(300),
+                                                    tag(301), tag(302), 0));
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_invoke(c2, f.client_cq, tag(400),
+                                                    tag(401), tag(402), 0));
+  cq_expect_invoke_accepted(v_client, tag(300), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c1, tag(303)));
+  cq_expect_finish_accepted(v_client, tag(303), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  cq_expect_server_rpc_new(v_server, &s1, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s1, f.server_cq, tag(102), 0));
+  cq_expect_client_metadata_read(v_client, tag(301), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s1, send_status, tag(103)));
+  cq_expect_finish_accepted(v_server, tag(103), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  /* first request is finished, we should be able to start the second */
+  cq_expect_finished_with_status(v_client, tag(302), send_status, NULL);
+  cq_expect_invoke_accepted(v_client, tag(400), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c2, tag(403)));
+  cq_expect_finish_accepted(v_client, tag(403), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(200)));
+  cq_expect_server_rpc_new(v_server, &s2, tag(200), "/bar", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s2, f.server_cq, tag(202), 0));
+  cq_expect_client_metadata_read(v_client, tag(401), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s2, send_status, tag(203)));
+  cq_expect_finish_accepted(v_server, tag(203), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(202), NULL);
+  cq_verify(v_server);
+
+  cq_expect_finished_with_status(v_client, tag(402), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+
+  grpc_call_destroy(c1);
+  grpc_call_destroy(s1);
+  grpc_call_destroy(c2);
+  grpc_call_destroy(s2);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  test_max_concurrent_streams(config);
+}
diff --git a/test/core/end2end/tests/no_op.c b/test/core/end2end/tests/no_op.c
new file mode 100644
index 0000000..ca03103
--- /dev/null
+++ b/test/core/end2end/tests/no_op.c
@@ -0,0 +1,112 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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 };
+
+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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+static void test_no_op(grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  test_no_op(config);
+}
diff --git a/test/core/end2end/tests/ping_pong_streaming.c b/test/core/end2end/tests/ping_pong_streaming.c
new file mode 100644
index 0000000..84e7bb4
--- /dev/null
+++ b/test/core/end2end/tests/ping_pong_streaming.c
@@ -0,0 +1,201 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+/* Client pings and server pongs. Repeat messages rounds before finishing. */
+static void test_pingpong_streaming(grpc_end2end_test_config config,
+                                    int messages) {
+  int i;
+  grpc_call *c;
+  grpc_call *s = NULL;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
+  gpr_slice response_payload_slice = gpr_slice_from_copied_string("hello you");
+  grpc_byte_buffer *request_payload = NULL;
+  grpc_byte_buffer *response_payload = NULL;
+  gpr_timespec deadline = n_seconds_time(messages * 5);
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  gpr_log(GPR_INFO, "testing with %d message pairs.", messages);
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+  grpc_call_accept(s, f.server_cq, tag(102), 0);
+
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  for (i = 0; i < messages; i++) {
+    request_payload = grpc_byte_buffer_create(&request_payload_slice, 1);
+    GPR_ASSERT(GRPC_CALL_OK ==
+               grpc_call_start_write(c, request_payload, tag(2), 0));
+    /* destroy byte buffer early to ensure async code keeps track of its
+       contents
+       correctly */
+    grpc_byte_buffer_destroy(request_payload);
+    cq_expect_write_accepted(v_client, tag(2), GRPC_OP_OK);
+    cq_verify(v_client);
+
+    GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(s, tag(3)));
+    cq_expect_read(v_server, tag(3),
+                   gpr_slice_from_copied_string("hello world"));
+    cq_verify(v_server);
+
+    response_payload = grpc_byte_buffer_create(&response_payload_slice, 1);
+    GPR_ASSERT(GRPC_CALL_OK ==
+               grpc_call_start_write(s, response_payload, tag(4), 0));
+    /* destroy byte buffer early to ensure async code keeps track of its
+       contents
+       correctly */
+    grpc_byte_buffer_destroy(response_payload);
+    cq_expect_write_accepted(v_server, tag(4), GRPC_OP_OK);
+    cq_verify(v_server);
+
+    GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(c, tag(5)));
+    cq_expect_read(v_client, tag(5), gpr_slice_from_copied_string("hello you"));
+    cq_verify(v_client);
+  }
+
+  gpr_slice_unref(request_payload_slice);
+  gpr_slice_unref(response_payload_slice);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(6)));
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(7)));
+
+  cq_expect_finish_accepted(v_client, tag(6), GRPC_OP_OK);
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(7), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  int i;
+
+  for (i = 1; i < 10; i++) {
+    test_pingpong_streaming(config, i);
+  }
+}
diff --git a/test/core/end2end/tests/request_response_with_metadata_and_payload.c b/test/core/end2end/tests/request_response_with_metadata_and_payload.c
new file mode 100644
index 0000000..4cb5679
--- /dev/null
+++ b/test/core/end2end/tests/request_response_with_metadata_and_payload.c
@@ -0,0 +1,208 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+/* Request/response with metadata and payload.*/
+static void test_request_response_with_metadata_and_payload(
+    grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
+  gpr_slice response_payload_slice = gpr_slice_from_copied_string("hello you");
+  grpc_byte_buffer *request_payload =
+      grpc_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer *response_payload =
+      grpc_byte_buffer_create(&response_payload_slice, 1);
+  gpr_timespec deadline = five_seconds_time();
+  grpc_metadata meta1 = {"key1", "val1", 4};
+  grpc_metadata meta2 = {"key2", "val2", 4};
+  grpc_metadata meta3 = {"key3", "val3", 4};
+  grpc_metadata meta4 = {"key4", "val4", 4};
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+
+  /* byte buffer holds the slice, we can unref it already */
+  gpr_slice_unref(request_payload_slice);
+  gpr_slice_unref(response_payload_slice);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  /* add multiple metadata */
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_add_metadata(c, &meta1, 0));
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_add_metadata(c, &meta2, 0));
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write(c, request_payload, tag(4), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(request_payload);
+  cq_expect_write_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, "key1", "val1", "key2", "val2", NULL);
+  cq_verify(v_server);
+
+  /* add multiple metadata */
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_add_metadata(s, &meta3, 0));
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_add_metadata(s, &meta4, 0));
+
+  grpc_call_accept(s, f.server_cq, tag(102), 0);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(s, tag(5)));
+  cq_expect_read(v_server, tag(5), gpr_slice_from_copied_string("hello world"));
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write(s, response_payload, tag(6), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(response_payload);
+  cq_expect_write_accepted(v_server, tag(6), GRPC_OP_OK);
+  cq_verify(v_server);
+
+  /* fetch metadata.. */
+  cq_expect_client_metadata_read(v_client, tag(2), "key3", "val3", "key4",
+                                 "val4", NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(c, tag(7)));
+  cq_expect_read(v_client, tag(7), gpr_slice_from_copied_string("hello you"));
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(8)));
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(9)));
+
+  cq_expect_finish_accepted(v_client, tag(8), GRPC_OP_OK);
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(9), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  test_request_response_with_metadata_and_payload(config);
+}
diff --git a/test/core/end2end/tests/request_response_with_payload.c b/test/core/end2end/tests/request_response_with_payload.c
new file mode 100644
index 0000000..fb9b59a
--- /dev/null
+++ b/test/core/end2end/tests/request_response_with_payload.c
@@ -0,0 +1,207 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+static void request_response_with_payload(grpc_end2end_test_fixture f) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
+  gpr_slice response_payload_slice = gpr_slice_from_copied_string("hello you");
+  grpc_byte_buffer *request_payload =
+      grpc_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer *response_payload =
+      grpc_byte_buffer_create(&response_payload_slice, 1);
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  /* byte buffer holds the slice, we can unref it already */
+  gpr_slice_unref(request_payload_slice);
+  gpr_slice_unref(response_payload_slice);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write(c, request_payload, tag(4), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(request_payload);
+  cq_expect_write_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  grpc_call_accept(s, f.server_cq, tag(102), 0);
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(s, tag(5)));
+  cq_expect_read(v_server, tag(5), gpr_slice_from_copied_string("hello world"));
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write(s, response_payload, tag(6), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(response_payload);
+  cq_expect_write_accepted(v_server, tag(6), GRPC_OP_OK);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(c, tag(7)));
+  cq_expect_read(v_client, tag(7), gpr_slice_from_copied_string("hello you"));
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(8)));
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(9)));
+
+  cq_expect_finish_accepted(v_client, tag(8), GRPC_OP_OK);
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(9), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+/* Client sends a request with payload, server reads then returns a response
+   payload and status. */
+static void test_invoke_request_response_with_payload(
+    grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  request_response_with_payload(f);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void test_invoke_10_request_response_with_payload(
+    grpc_end2end_test_config config) {
+  int i;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  for (i = 0; i < 10; i++) {
+    request_response_with_payload(f);
+  }
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  test_invoke_request_response_with_payload(config);
+  test_invoke_10_request_response_with_payload(config);
+}
diff --git a/test/core/end2end/tests/request_with_large_metadata.c b/test/core/end2end/tests/request_with_large_metadata.c
new file mode 100644
index 0000000..ccdee40
--- /dev/null
+++ b/test/core/end2end/tests/request_with_large_metadata.c
@@ -0,0 +1,172 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+/* Request with a large amount of metadata.*/
+static void test_request_with_large_metadata(grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_OK, NULL};
+  gpr_timespec deadline = five_seconds_time();
+  grpc_metadata meta;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  const int large_size = 64 * 1024;
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+
+  meta.key = "key";
+  meta.value = gpr_malloc(large_size + 1);
+  memset(meta.value, 'a', large_size);
+  meta.value[large_size] = 0;
+  meta.value_length = large_size;
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  /* add the metadata */
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_add_metadata(c, &meta, 0));
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, "key", meta.value, NULL);
+  cq_verify(v_server);
+
+  grpc_call_accept(s, f.server_cq, tag(102), 0);
+
+  /* fetch metadata.. */
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(8)));
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(9)));
+
+  cq_expect_finish_accepted(v_client, tag(8), GRPC_OP_OK);
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(9), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+
+  gpr_free(meta.value);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  test_request_with_large_metadata(config);
+}
diff --git a/test/core/end2end/tests/request_with_payload.c b/test/core/end2end/tests/request_with_payload.c
new file mode 100644
index 0000000..38a29e3
--- /dev/null
+++ b/test/core/end2end/tests/request_with_payload.c
@@ -0,0 +1,171 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+/* Client sends a request with payload, server reads then returns status. */
+static void test_invoke_request_with_payload(grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_slice payload_slice = gpr_slice_from_copied_string("hello world");
+  grpc_byte_buffer *payload = grpc_byte_buffer_create(&payload_slice, 1);
+  gpr_timespec deadline = five_seconds_time();
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  /* byte buffer holds the slice, we can unref it already */
+  gpr_slice_unref(payload_slice);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_write(c, payload, tag(4), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(payload);
+  cq_expect_write_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  grpc_call_accept(s, f.server_cq, tag(102), 0);
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(s, tag(4)));
+  cq_expect_read(v_server, tag(4), gpr_slice_from_copied_string("hello world"));
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(5)));
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(6)));
+  cq_expect_finish_accepted(v_client, tag(5), GRPC_OP_OK);
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(6), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  test_invoke_request_with_payload(config);
+}
diff --git a/test/core/end2end/tests/simple_delayed_request.c b/test/core/end2end/tests/simple_delayed_request.c
new file mode 100644
index 0000000..dde6eb6
--- /dev/null
+++ b/test/core/end2end/tests/simple_delayed_request.c
@@ -0,0 +1,174 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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 };
+
+static void *tag(gpr_intptr t) { return (void *)t; }
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+static void simple_delayed_request_body(grpc_end2end_test_config config,
+                                        grpc_end2end_test_fixture *f,
+                                        grpc_channel_args *client_args,
+                                        grpc_channel_args *server_args,
+                                        long delay_us) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f->client_cq);
+  cq_verifier *v_server = cq_verifier_create(f->server_cq);
+
+  config.init_client(f, client_args);
+
+  c = grpc_channel_create_call(f->client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_invoke(c, f->client_cq, tag(1),
+                                                    tag(2), tag(3), 0));
+  gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_micros(delay_us)));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+
+  config.init_server(f, server_args);
+
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(4)));
+  cq_expect_finish_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f->server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s, f->server_cq, tag(102), 0));
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(5)));
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(5), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+static void test_simple_delayed_request_short(grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f;
+
+  gpr_log(GPR_INFO, "%s/%s", __FUNCTION__, config.name);
+  f = config.create_fixture(NULL, NULL);
+  simple_delayed_request_body(config, &f, NULL, NULL, 100000);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void test_simple_delayed_request_long(grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f;
+
+  gpr_log(GPR_INFO, "%s/%s", __FUNCTION__, config.name);
+  f = config.create_fixture(NULL, NULL);
+  /* This timeout should be longer than a single retry */
+  simple_delayed_request_body(config, &f, NULL, NULL, 1500000);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  if (config.feature_mask & FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION) {
+    test_simple_delayed_request_short(config);
+    test_simple_delayed_request_long(config);
+  }
+}
diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c
new file mode 100644
index 0000000..15214ff
--- /dev/null
+++ b/test/core/end2end/tests/simple_request.c
@@ -0,0 +1,231 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+static void simple_request_body(grpc_end2end_test_fixture f) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(4)));
+  cq_expect_finish_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s, f.server_cq, tag(102), 0));
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(5)));
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(5), GRPC_OP_OK);
+  cq_verify(v_server);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+/* an alternative ordering of the simple request body */
+static void simple_request_body2(grpc_end2end_test_fixture f) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(4)));
+  cq_expect_finish_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s, f.server_cq, tag(102), 0));
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(5)));
+  cq_expect_finish_accepted(v_server, tag(5), GRPC_OP_OK);
+  cq_verify(v_server);
+
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+static void test_invoke_simple_request(
+    grpc_end2end_test_config config, const char *name,
+    void (*body)(grpc_end2end_test_fixture f)) {
+  char fullname[64];
+  grpc_end2end_test_fixture f;
+
+  sprintf(fullname, "%s/%s", __FUNCTION__, name);
+
+  f = begin_test(config, fullname, NULL, NULL);
+  body(f);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void test_invoke_10_simple_requests(grpc_end2end_test_config config) {
+  int i;
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  for (i = 0; i < 10; i++) {
+    simple_request_body(f);
+    gpr_log(GPR_INFO, "Passed simple request %d", i);
+  }
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  test_invoke_simple_request(config, "simple_request_body",
+                             simple_request_body);
+  test_invoke_simple_request(config, "simple_request_body2",
+                             simple_request_body2);
+  test_invoke_10_simple_requests(config);
+}
diff --git a/test/core/end2end/tests/thread_stress_test.c b/test/core/end2end/tests/thread_stress_test.c
new file mode 100644
index 0000000..44b250f
--- /dev/null
+++ b/test/core/end2end/tests/thread_stress_test.c
@@ -0,0 +1,325 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <string.h>
+
+#include "src/core/surface/event_string.h"
+#include "src/core/surface/completion_queue.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <grpc/support/thd.h>
+
+#define SERVER_THREADS 16
+#define CLIENT_THREADS 16
+
+static grpc_end2end_test_fixture g_fixture;
+static gpr_timespec g_test_end_time;
+static gpr_event g_client_done[CLIENT_THREADS];
+static gpr_event g_server_done[SERVER_THREADS];
+static gpr_mu g_mu;
+static int g_active_requests;
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+/* Drain pending events on a completion queue until it's ready to destroy.
+   Does some post-processing to safely release memory on some of the events. */
+static void drain_cq(int client, grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  char *evstr;
+  int done = 0;
+  char *name = client ? "client" : "server";
+  while (!done) {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    if (!ev) {
+      gpr_log(GPR_ERROR, "waiting for %s cq to drain", name);
+      grpc_cq_dump_pending_ops(cq);
+      continue;
+    }
+
+    evstr = grpc_event_string(ev);
+    gpr_log(GPR_INFO, "got late %s event: %s", name, evstr);
+    gpr_free(evstr);
+
+    type = ev->type;
+    switch (type) {
+      case GRPC_SERVER_RPC_NEW:
+        gpr_free(ev->tag);
+        if (ev->call) {
+          grpc_call_destroy(ev->call);
+        }
+        break;
+      case GRPC_FINISHED:
+        grpc_call_destroy(ev->call);
+        break;
+      case GRPC_QUEUE_SHUTDOWN:
+        done = 1;
+        break;
+      case GRPC_READ:
+      case GRPC_WRITE_ACCEPTED:
+        if (!client && gpr_unref(ev->tag)) {
+          gpr_free(ev->tag);
+        }
+      default:
+        break;
+    }
+    grpc_event_finish(ev);
+  }
+}
+
+/* Kick off a new request - assumes g_mu taken */
+static void start_request() {
+  grpc_call *call = grpc_channel_create_call(
+      g_fixture.client, "/Foo", "test.google.com", g_test_end_time);
+  g_active_requests++;
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_invoke(call, g_fixture.client_cq,
+                                                    NULL, NULL, NULL, 0));
+}
+
+/* Async client: handle sending requests, reading responses, and starting
+   new requests when old ones finish */
+static void client_thread(void *p) {
+  int id = (gpr_intptr)p;
+  grpc_event *ev;
+  gpr_slice slice = gpr_slice_malloc(100);
+  grpc_byte_buffer *buf;
+  char *estr;
+  memset(GPR_SLICE_START_PTR(slice), id, GPR_SLICE_LENGTH(slice));
+
+  buf = grpc_byte_buffer_create(&slice, 1);
+  gpr_slice_unref(slice);
+
+  for (;;) {
+    ev = grpc_completion_queue_next(g_fixture.client_cq, n_seconds_time(1));
+    if (ev) {
+      switch (ev->type) {
+        default:
+          estr = grpc_event_string(ev);
+          gpr_log(GPR_ERROR, "unexpected event: %s", estr);
+          gpr_free(estr);
+          break;
+        case GRPC_INVOKE_ACCEPTED:
+          /* better not keep going if the invoke failed */
+          if (ev->data.invoke_accepted == GRPC_OP_OK) {
+            GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(ev->call, NULL));
+            GPR_ASSERT(GRPC_CALL_OK ==
+                       grpc_call_start_write(ev->call, buf, NULL, 0));
+          }
+          break;
+        case GRPC_READ:
+          break;
+        case GRPC_WRITE_ACCEPTED:
+          GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(ev->call, NULL));
+          break;
+        case GRPC_FINISH_ACCEPTED:
+          break;
+        case GRPC_CLIENT_METADATA_READ:
+          break;
+        case GRPC_FINISHED:
+          /* kick off a new request if the test should still be running */
+          gpr_mu_lock(&g_mu);
+          g_active_requests--;
+          if (gpr_time_cmp(gpr_now(), g_test_end_time) < 0) {
+            start_request();
+          }
+          gpr_mu_unlock(&g_mu);
+          grpc_call_destroy(ev->call);
+          break;
+      }
+      grpc_event_finish(ev);
+    }
+    gpr_mu_lock(&g_mu);
+    if (g_active_requests == 0) {
+      gpr_mu_unlock(&g_mu);
+      break;
+    }
+    gpr_mu_unlock(&g_mu);
+  }
+
+  grpc_byte_buffer_destroy(buf);
+  gpr_event_set(&g_client_done[id], (void *)1);
+}
+
+/* Request a new server call. We tag them with a ref-count that starts at two,
+   and decrements after each of: a read completes and a write completes.
+   When it drops to zero, we write status */
+static void request_server_call() {
+  gpr_refcount *rc = gpr_malloc(sizeof(gpr_refcount));
+  gpr_ref_init(rc, 2);
+  grpc_server_request_call(g_fixture.server, rc);
+}
+
+static void maybe_end_server_call(grpc_call *call, gpr_refcount *rc) {
+  grpc_status ok_status = {GRPC_STATUS_OK, NULL};
+  if (gpr_unref(rc)) {
+    GPR_ASSERT(GRPC_CALL_OK ==
+               grpc_call_start_write_status(call, ok_status, NULL));
+    gpr_free(rc);
+  }
+}
+
+static void server_thread(void *p) {
+  int id = (gpr_intptr)p;
+  grpc_event *ev;
+  gpr_slice slice = gpr_slice_malloc(100);
+  grpc_byte_buffer *buf;
+  char *estr;
+  memset(GPR_SLICE_START_PTR(slice), id, GPR_SLICE_LENGTH(slice));
+
+  request_server_call();
+
+  buf = grpc_byte_buffer_create(&slice, 1);
+  gpr_slice_unref(slice);
+
+  for (;;) {
+    ev = grpc_completion_queue_next(g_fixture.server_cq, n_seconds_time(1));
+    if (ev) {
+      switch (ev->type) {
+        default:
+          estr = grpc_event_string(ev);
+          gpr_log(GPR_ERROR, "unexpected event: %s", estr);
+          gpr_free(estr);
+          break;
+        case GRPC_SERVER_RPC_NEW:
+          if (ev->call) {
+            GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(ev->call,
+                                                        g_fixture.server_cq,
+                                                        ev->tag, 0));
+            GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(ev->call, ev->tag));
+            GPR_ASSERT(GRPC_CALL_OK ==
+                       grpc_call_start_write(ev->call, buf, ev->tag, 0));
+          } else {
+            gpr_free(ev->tag);
+          }
+          break;
+        case GRPC_READ:
+          if (ev->data.read) {
+            GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(ev->call, ev->tag));
+          } else {
+            maybe_end_server_call(ev->call, ev->tag);
+          }
+          break;
+        case GRPC_WRITE_ACCEPTED:
+          maybe_end_server_call(ev->call, ev->tag);
+          break;
+        case GRPC_FINISH_ACCEPTED:
+          break;
+        case GRPC_FINISHED:
+          grpc_call_destroy(ev->call);
+          request_server_call();
+          break;
+      }
+      grpc_event_finish(ev);
+    }
+    gpr_mu_lock(&g_mu);
+    if (g_active_requests == 0) {
+      gpr_mu_unlock(&g_mu);
+      break;
+    }
+    gpr_mu_unlock(&g_mu);
+  }
+
+  grpc_byte_buffer_destroy(buf);
+  gpr_event_set(&g_server_done[id], (void *)1);
+}
+
+static void run_test(grpc_end2end_test_config config, int requests_in_flight) {
+  int i;
+  gpr_thd_id thd_id;
+
+  gpr_log(GPR_INFO, "thread_test/%s @ %d requests", config.name,
+          requests_in_flight);
+
+  /* setup client, server */
+  g_fixture = config.create_fixture(NULL, NULL);
+  config.init_client(&g_fixture, NULL);
+  config.init_server(&g_fixture, NULL);
+
+  /* schedule end time */
+  g_test_end_time = n_seconds_time(5);
+
+  g_active_requests = 0;
+  gpr_mu_init(&g_mu);
+
+  /* kick off threads */
+  for (i = 0; i < CLIENT_THREADS; i++) {
+    gpr_event_init(&g_client_done[i]);
+    gpr_thd_new(&thd_id, client_thread, (void *)(gpr_intptr)i, NULL);
+  }
+  for (i = 0; i < SERVER_THREADS; i++) {
+    gpr_event_init(&g_server_done[i]);
+    gpr_thd_new(&thd_id, server_thread, (void *)(gpr_intptr)i, NULL);
+  }
+
+  /* start requests */
+  gpr_mu_lock(&g_mu);
+  for (i = 0; i < requests_in_flight; i++) {
+    start_request();
+  }
+  gpr_mu_unlock(&g_mu);
+
+  /* await completion */
+  for (i = 0; i < CLIENT_THREADS; i++) {
+    gpr_event_wait(&g_client_done[i], gpr_inf_future);
+  }
+  for (i = 0; i < SERVER_THREADS; i++) {
+    gpr_event_wait(&g_server_done[i], gpr_inf_future);
+  }
+
+  /* shutdown the things */
+  grpc_server_shutdown(g_fixture.server);
+  grpc_server_destroy(g_fixture.server);
+  grpc_channel_destroy(g_fixture.client);
+
+  grpc_completion_queue_shutdown(g_fixture.server_cq);
+  drain_cq(0, g_fixture.server_cq);
+  grpc_completion_queue_destroy(g_fixture.server_cq);
+  grpc_completion_queue_shutdown(g_fixture.client_cq);
+  drain_cq(1, g_fixture.client_cq);
+  grpc_completion_queue_destroy(g_fixture.client_cq);
+
+  config.tear_down_data(&g_fixture);
+
+  gpr_mu_destroy(&g_mu);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  run_test(config, 1000);
+}
diff --git a/test/core/end2end/tests/writes_done_hangs_with_pending_read.c b/test/core/end2end/tests/writes_done_hangs_with_pending_read.c
new file mode 100644
index 0000000..555d7b9
--- /dev/null
+++ b/test/core/end2end/tests/writes_done_hangs_with_pending_read.c
@@ -0,0 +1,198 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/byte_buffer.h>
+#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 };
+
+static void *tag(gpr_intptr 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, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
+}
+
+static gpr_timespec five_seconds_time() { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type type;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    GPR_ASSERT(ev);
+    type = ev->type;
+    grpc_event_finish(ev);
+  } while (type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown(f->server);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->server_cq);
+  drain_cq(f->server_cq);
+  grpc_completion_queue_destroy(f->server_cq);
+  grpc_completion_queue_shutdown(f->client_cq);
+  drain_cq(f->client_cq);
+  grpc_completion_queue_destroy(f->client_cq);
+}
+
+/* test the case when there is a pending message at the client side,
+   writes_done should not return a status without a start_read.
+   Note: this test will last for 3s. Do not run in a loop. */
+static void test_writes_done_hangs_with_pending_read(
+    grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_status send_status = {GRPC_STATUS_UNIMPLEMENTED, "xyz"};
+  gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
+  gpr_slice response_payload_slice = gpr_slice_from_copied_string("hello you");
+  grpc_byte_buffer *request_payload =
+      grpc_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer *response_payload =
+      grpc_byte_buffer_create(&response_payload_slice, 1);
+  gpr_timespec deadline = five_seconds_time();
+  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+
+  /* byte buffer holds the slice, we can unref it already */
+  gpr_slice_unref(request_payload_slice);
+  gpr_slice_unref(response_payload_slice);
+
+  c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
+  GPR_ASSERT(c);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
+  cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write(c, request_payload, tag(4), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(request_payload);
+  cq_expect_write_accepted(v_client, tag(4), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
+  cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
+                           deadline, NULL);
+  cq_verify(v_server);
+
+  grpc_call_accept(s, f.server_cq, tag(102), 0);
+  cq_expect_client_metadata_read(v_client, tag(2), NULL);
+  cq_verify(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(s, tag(5)));
+  cq_expect_read(v_server, tag(5), gpr_slice_from_copied_string("hello world"));
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write(s, response_payload, tag(6), 0));
+  /* destroy byte buffer early to ensure async code keeps track of its contents
+     correctly */
+  grpc_byte_buffer_destroy(response_payload);
+  cq_expect_write_accepted(v_server, tag(6), GRPC_OP_OK);
+  cq_verify(v_server);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(6)));
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_write_status(s, send_status, tag(7)));
+
+  cq_expect_finish_accepted(v_client, tag(6), GRPC_OP_OK);
+  cq_verify(v_client);
+
+  /* does not return status because there is a pending message to be read */
+  cq_verify_empty(v_client);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_read(c, tag(8)));
+  cq_expect_read(v_client, tag(8), gpr_slice_from_copied_string("hello you"));
+  cq_verify(v_client);
+
+  cq_expect_finished_with_status(v_client, tag(3), send_status, NULL);
+  cq_verify(v_client);
+
+  cq_expect_finish_accepted(v_server, tag(7), GRPC_OP_OK);
+  cq_expect_finished(v_server, tag(102), NULL);
+  cq_verify(v_server);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+
+  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(v_server);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  test_writes_done_hangs_with_pending_read(config);
+}
diff --git a/test/core/endpoint/endpoint_tests.c b/test/core/endpoint/endpoint_tests.c
new file mode 100644
index 0000000..9cc0eaa
--- /dev/null
+++ b/test/core/endpoint/endpoint_tests.c
@@ -0,0 +1,433 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/endpoint/endpoint_tests.h"
+
+#include <sys/types.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+
+/*
+   General test notes:
+
+   All tests which write data into an endpoint write i%256 into byte i, which
+   is verified by readers.
+
+   In general there are a few interesting things to vary which may lead to
+   exercising different codepaths in an implementation:
+   1. Total amount of data written to the endpoint
+   2. Size of slice allocations
+   3. Amount of data we read from or write to the endpoint at once
+
+   The tests here tend to parameterize these where applicable.
+
+*/
+
+ssize_t count_and_unref_slices(gpr_slice *slices, size_t nslices,
+                               int *current_data) {
+  ssize_t num_bytes = 0;
+  int i;
+  int j;
+  unsigned char *buf;
+  for (i = 0; i < nslices; ++i) {
+    buf = GPR_SLICE_START_PTR(slices[i]);
+    for (j = 0; j < GPR_SLICE_LENGTH(slices[i]); ++j) {
+      GPR_ASSERT(buf[j] == *current_data);
+      *current_data = (*current_data + 1) % 256;
+    }
+    num_bytes += GPR_SLICE_LENGTH(slices[i]);
+    gpr_slice_unref(slices[i]);
+  }
+  return num_bytes;
+}
+
+static grpc_endpoint_test_fixture begin_test(grpc_endpoint_test_config config,
+                                             const char *test_name,
+                                             ssize_t slice_size) {
+  gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
+  return config.create_fixture(slice_size);
+}
+
+static void end_test(grpc_endpoint_test_config config) { config.clean_up(); }
+
+static gpr_slice *allocate_blocks(ssize_t num_bytes, ssize_t slice_size,
+                                  size_t *num_blocks, int *current_data) {
+  ssize_t nslices = num_bytes / slice_size + (num_bytes % slice_size ? 1 : 0);
+  gpr_slice *slices = malloc(sizeof(gpr_slice) * nslices);
+  ssize_t num_bytes_left = num_bytes;
+  int i;
+  int j;
+  unsigned char *buf;
+  *num_blocks = nslices;
+
+  for (i = 0; i < nslices; ++i) {
+    slices[i] = gpr_slice_malloc(slice_size > num_bytes_left ? num_bytes_left
+                                                             : slice_size);
+    num_bytes_left -= GPR_SLICE_LENGTH(slices[i]);
+    buf = GPR_SLICE_START_PTR(slices[i]);
+    for (j = 0; j < GPR_SLICE_LENGTH(slices[i]); ++j) {
+      buf[j] = *current_data;
+      *current_data = (*current_data + 1) % 256;
+    }
+  }
+  GPR_ASSERT(num_bytes_left == 0);
+  return slices;
+}
+
+struct read_and_write_test_state {
+  grpc_endpoint *read_ep;
+  grpc_endpoint *write_ep;
+  gpr_mu mu;
+  gpr_cv cv;
+  ssize_t target_bytes;
+  ssize_t bytes_read;
+  ssize_t current_write_size;
+  ssize_t bytes_written;
+  int current_read_data;
+  int current_write_data;
+  int read_done;
+  int write_done;
+};
+
+static void read_and_write_test_read_handler(void *data, gpr_slice *slices,
+                                             size_t nslices,
+                                             grpc_endpoint_cb_status error) {
+  struct read_and_write_test_state *state = data;
+  GPR_ASSERT(error != GRPC_ENDPOINT_CB_ERROR);
+  if (error == GRPC_ENDPOINT_CB_SHUTDOWN) {
+    gpr_log(GPR_INFO, "Read handler shutdown");
+    gpr_mu_lock(&state->mu);
+    state->read_done = 1;
+    gpr_cv_signal(&state->cv);
+    gpr_mu_unlock(&state->mu);
+    return;
+  }
+
+  state->bytes_read +=
+      count_and_unref_slices(slices, nslices, &state->current_read_data);
+  if (state->bytes_read == state->target_bytes) {
+    gpr_log(GPR_INFO, "Read handler done");
+    gpr_mu_lock(&state->mu);
+    state->read_done = 1;
+    gpr_cv_signal(&state->cv);
+    gpr_mu_unlock(&state->mu);
+  } else {
+    grpc_endpoint_notify_on_read(
+        state->read_ep, read_and_write_test_read_handler, data, gpr_inf_future);
+  }
+}
+
+static void read_and_write_test_write_handler(void *data,
+                                              grpc_endpoint_cb_status error) {
+  struct read_and_write_test_state *state = data;
+  gpr_slice *slices = NULL;
+  size_t nslices;
+  grpc_endpoint_write_status write_status;
+
+  GPR_ASSERT(error != GRPC_ENDPOINT_CB_ERROR);
+
+  if (error == GRPC_ENDPOINT_CB_SHUTDOWN) {
+    gpr_log(GPR_INFO, "Write handler shutdown");
+    gpr_mu_lock(&state->mu);
+    state->write_done = 1;
+    gpr_cv_signal(&state->cv);
+    gpr_mu_unlock(&state->mu);
+    return;
+  }
+
+  for (;;) {
+    /* Need to do inline writes until they don't succeed synchronously or we
+       finish writing */
+    state->bytes_written += state->current_write_size;
+    if (state->target_bytes - state->bytes_written <
+        state->current_write_size) {
+      state->current_write_size = state->target_bytes - state->bytes_written;
+    }
+    if (state->current_write_size == 0) {
+      break;
+    }
+
+    slices = allocate_blocks(state->current_write_size, 8192, &nslices,
+                             &state->current_write_data);
+    write_status = grpc_endpoint_write(state->write_ep, slices, nslices,
+                                       read_and_write_test_write_handler, state,
+                                       gpr_inf_future);
+    GPR_ASSERT(write_status != GRPC_ENDPOINT_WRITE_ERROR);
+    free(slices);
+    if (write_status == GRPC_ENDPOINT_WRITE_PENDING) {
+      return;
+    }
+  }
+  GPR_ASSERT(state->bytes_written == state->target_bytes);
+
+  gpr_log(GPR_INFO, "Write handler done");
+  gpr_mu_lock(&state->mu);
+  state->write_done = 1;
+  gpr_cv_signal(&state->cv);
+  gpr_mu_unlock(&state->mu);
+}
+
+/* Do both reading and writing using the grpc_endpoint API.
+
+   This also includes a test of the shutdown behavior.
+ */
+static void read_and_write_test(grpc_endpoint_test_config config,
+                                ssize_t num_bytes, ssize_t write_size,
+                                ssize_t slice_size, int shutdown) {
+  struct read_and_write_test_state state;
+  gpr_timespec rel_deadline = {20, 0};
+  gpr_timespec deadline = gpr_time_add(gpr_now(), rel_deadline);
+  grpc_endpoint_test_fixture f = begin_test(config, __FUNCTION__, slice_size);
+
+  if (shutdown) {
+    gpr_log(GPR_INFO, "Start read and write shutdown test");
+  } else {
+    gpr_log(GPR_INFO, "Start read and write test with %d bytes, slice size %d",
+            num_bytes, slice_size);
+  }
+
+  gpr_mu_init(&state.mu);
+  gpr_cv_init(&state.cv);
+
+  state.read_ep = f.client_ep;
+  state.write_ep = f.server_ep;
+  state.target_bytes = num_bytes;
+  state.bytes_read = 0;
+  state.current_write_size = write_size;
+  state.bytes_written = 0;
+  state.read_done = 0;
+  state.write_done = 0;
+  state.current_read_data = 0;
+  state.current_write_data = 0;
+
+  /* Get started by pretending an initial write completed */
+  state.bytes_written -= state.current_write_size;
+  read_and_write_test_write_handler(&state, GRPC_ENDPOINT_CB_OK);
+
+  grpc_endpoint_notify_on_read(state.read_ep, read_and_write_test_read_handler,
+                               &state, gpr_inf_future);
+
+  if (shutdown) {
+    grpc_endpoint_shutdown(state.read_ep);
+    grpc_endpoint_shutdown(state.write_ep);
+  }
+
+  gpr_mu_lock(&state.mu);
+  while (!state.read_done || !state.write_done) {
+    GPR_ASSERT(gpr_cv_wait(&state.cv, &state.mu, deadline) == 0);
+  }
+  gpr_mu_unlock(&state.mu);
+
+  grpc_endpoint_destroy(state.read_ep);
+  grpc_endpoint_destroy(state.write_ep);
+  gpr_mu_destroy(&state.mu);
+  gpr_cv_destroy(&state.cv);
+  end_test(config);
+}
+
+struct timeout_test_state {
+  gpr_event io_done;
+};
+
+static void read_timeout_test_read_handler(void *data, gpr_slice *slices,
+                                           size_t nslices,
+                                           grpc_endpoint_cb_status error) {
+  struct timeout_test_state *state = data;
+  GPR_ASSERT(error == GRPC_ENDPOINT_CB_TIMED_OUT);
+  gpr_event_set(&state->io_done, (void *)1);
+}
+
+static void read_timeout_test(grpc_endpoint_test_config config,
+                              ssize_t slice_size) {
+  gpr_timespec timeout = gpr_time_from_micros(10000);
+  gpr_timespec read_deadline = gpr_time_add(gpr_now(), timeout);
+  gpr_timespec test_deadline =
+      gpr_time_add(gpr_now(), gpr_time_from_micros(2000000));
+  struct timeout_test_state state;
+  grpc_endpoint_test_fixture f = begin_test(config, __FUNCTION__, slice_size);
+
+  gpr_event_init(&state.io_done);
+
+  grpc_endpoint_notify_on_read(f.client_ep, read_timeout_test_read_handler,
+                               &state, read_deadline);
+  GPR_ASSERT(gpr_event_wait(&state.io_done, test_deadline));
+  grpc_endpoint_destroy(f.client_ep);
+  grpc_endpoint_destroy(f.server_ep);
+  end_test(config);
+}
+
+static void write_timeout_test_write_handler(void *data,
+                                             grpc_endpoint_cb_status error) {
+  struct timeout_test_state *state = data;
+  GPR_ASSERT(error == GRPC_ENDPOINT_CB_TIMED_OUT);
+  gpr_event_set(&state->io_done, (void *)1);
+}
+
+static void write_timeout_test(grpc_endpoint_test_config config,
+                               ssize_t slice_size) {
+  gpr_timespec timeout = gpr_time_from_micros(10000);
+  gpr_timespec write_deadline = gpr_time_add(gpr_now(), timeout);
+  gpr_timespec test_deadline =
+      gpr_time_add(gpr_now(), gpr_time_from_micros(2000000));
+  struct timeout_test_state state;
+  int current_data = 1;
+  gpr_slice *slices;
+  size_t nblocks;
+  size_t size;
+  grpc_endpoint_test_fixture f = begin_test(config, __FUNCTION__, slice_size);
+
+  gpr_event_init(&state.io_done);
+
+  /* TODO(klempner): Factor this out with the equivalent code in tcp_test.c */
+  for (size = 1;; size *= 2) {
+    slices = allocate_blocks(size, 1, &nblocks, &current_data);
+    switch (grpc_endpoint_write(f.client_ep, slices, nblocks,
+                                write_timeout_test_write_handler, &state,
+                                write_deadline)) {
+      case GRPC_ENDPOINT_WRITE_DONE:
+        break;
+      case GRPC_ENDPOINT_WRITE_ERROR:
+        gpr_log(GPR_ERROR, "error writing");
+        abort();
+      case GRPC_ENDPOINT_WRITE_PENDING:
+        GPR_ASSERT(gpr_event_wait(&state.io_done, test_deadline));
+        gpr_free(slices);
+        goto exit;
+    }
+    gpr_free(slices);
+  }
+exit:
+  grpc_endpoint_destroy(f.client_ep);
+  grpc_endpoint_destroy(f.server_ep);
+  end_test(config);
+}
+
+typedef struct {
+  gpr_event ev;
+  grpc_endpoint *ep;
+} shutdown_during_write_test_state;
+
+static void shutdown_during_write_test_read_handler(
+    void *user_data, gpr_slice *slices, size_t nslices,
+    grpc_endpoint_cb_status error) {
+  size_t i;
+  shutdown_during_write_test_state *st = user_data;
+
+  for (i = 0; i < nslices; i++) {
+    gpr_slice_unref(slices[i]);
+  }
+
+  if (error != GRPC_ENDPOINT_CB_OK) {
+    grpc_endpoint_destroy(st->ep);
+    gpr_event_set(&st->ev, (void *)(gpr_intptr)error);
+  } else {
+    grpc_endpoint_notify_on_read(st->ep,
+                                 shutdown_during_write_test_read_handler,
+                                 user_data, gpr_inf_future);
+  }
+}
+
+static void shutdown_during_write_test_write_handler(
+    void *user_data, grpc_endpoint_cb_status error) {
+  shutdown_during_write_test_state *st = user_data;
+  gpr_log(GPR_INFO, "shutdown_during_write_test_write_handler: error = %d",
+          error);
+  grpc_endpoint_destroy(st->ep);
+  gpr_event_set(&st->ev, (void *)(gpr_intptr)error);
+}
+
+static void shutdown_during_write_test(grpc_endpoint_test_config config,
+                                       ssize_t slice_size) {
+  /* test that shutdown with a pending write creates no leaks */
+  gpr_timespec deadline;
+  size_t size;
+  size_t nblocks;
+  int current_data = 1;
+  shutdown_during_write_test_state read_st;
+  shutdown_during_write_test_state write_st;
+  gpr_slice *slices;
+  grpc_endpoint_test_fixture f = begin_test(config, __FUNCTION__, slice_size);
+
+  gpr_log(GPR_INFO, "testing shutdown during a write");
+
+  read_st.ep = f.client_ep;
+  write_st.ep = f.server_ep;
+  gpr_event_init(&read_st.ev);
+  gpr_event_init(&write_st.ev);
+
+#if 0
+  read_st.ep = grpc_tcp_create(sv[1], &em);
+  write_st.ep = grpc_tcp_create(sv[0], &em);
+#endif
+
+  grpc_endpoint_notify_on_read(read_st.ep,
+                               shutdown_during_write_test_read_handler,
+                               &read_st, gpr_inf_future);
+  for (size = 1;; size *= 2) {
+    slices = allocate_blocks(size, 1, &nblocks, &current_data);
+    switch (grpc_endpoint_write(write_st.ep, slices, nblocks,
+                                shutdown_during_write_test_write_handler,
+                                &write_st, gpr_inf_future)) {
+      case GRPC_ENDPOINT_WRITE_DONE:
+        break;
+      case GRPC_ENDPOINT_WRITE_ERROR:
+        gpr_log(GPR_ERROR, "error writing");
+        abort();
+      case GRPC_ENDPOINT_WRITE_PENDING:
+        grpc_endpoint_shutdown(write_st.ep);
+        deadline =
+            gpr_time_add(gpr_now(), gpr_time_from_micros(10 * GPR_US_PER_SEC));
+        GPR_ASSERT(gpr_event_wait(&write_st.ev, deadline));
+        GPR_ASSERT(gpr_event_wait(&read_st.ev, deadline));
+        gpr_free(slices);
+        end_test(config);
+        return;
+    }
+    gpr_free(slices);
+  }
+
+  gpr_log(GPR_ERROR, "should never reach here");
+  abort();
+}
+
+void grpc_endpoint_tests(grpc_endpoint_test_config config) {
+  read_and_write_test(config, 10000000, 100000, 8192, 0);
+  read_and_write_test(config, 1000000, 100000, 1, 0);
+  read_and_write_test(config, 100000000, 100000, 1, 1);
+  read_timeout_test(config, 1000);
+  write_timeout_test(config, 1000);
+  shutdown_during_write_test(config, 1000);
+}
diff --git a/test/core/endpoint/endpoint_tests.h b/test/core/endpoint/endpoint_tests.h
new file mode 100644
index 0000000..79ee759
--- /dev/null
+++ b/test/core/endpoint/endpoint_tests.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_TEST_ENDPOINT_ENDPOINT_TESTS_H__
+#define __GRPC_TEST_ENDPOINT_ENDPOINT_TESTS_H__
+
+#include <sys/types.h>
+
+#include "src/core/endpoint/endpoint.h"
+
+typedef struct grpc_endpoint_test_config grpc_endpoint_test_config;
+typedef struct grpc_endpoint_test_fixture grpc_endpoint_test_fixture;
+
+struct grpc_endpoint_test_fixture {
+  grpc_endpoint *client_ep;
+  grpc_endpoint *server_ep;
+};
+
+struct grpc_endpoint_test_config {
+  const char *name;
+  grpc_endpoint_test_fixture (*create_fixture)(ssize_t slice_size);
+  void (*clean_up)();
+};
+
+void grpc_endpoint_tests(grpc_endpoint_test_config config);
+
+#endif  /* __GRPC_TEST_ENDPOINT_ENDPOINT_TESTS_H__ */
diff --git a/test/core/endpoint/resolve_address_test.c b/test/core/endpoint/resolve_address_test.c
new file mode 100644
index 0000000..1e208d3
--- /dev/null
+++ b/test/core/endpoint/resolve_address_test.c
@@ -0,0 +1,135 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/endpoint/resolve_address.h"
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+static gpr_timespec test_deadline() {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(100000000));
+}
+
+static void must_succeed(void* evp, grpc_resolved_addresses* p) {
+  GPR_ASSERT(p);
+  GPR_ASSERT(p->naddrs >= 1);
+  grpc_resolved_addresses_destroy(p);
+  gpr_event_set(evp, (void*)1);
+}
+
+static void must_fail(void* evp, grpc_resolved_addresses* p) {
+  GPR_ASSERT(!p);
+  gpr_event_set(evp, (void*)1);
+}
+
+static void test_localhost() {
+  gpr_event ev;
+  gpr_event_init(&ev);
+  grpc_resolve_address("localhost:1", NULL, must_succeed, &ev);
+  GPR_ASSERT(gpr_event_wait(&ev, test_deadline()));
+}
+
+static void test_default_port() {
+  gpr_event ev;
+  gpr_event_init(&ev);
+  grpc_resolve_address("localhost", "1", must_succeed, &ev);
+  GPR_ASSERT(gpr_event_wait(&ev, test_deadline()));
+}
+
+static void test_missing_default_port() {
+  gpr_event ev;
+  gpr_event_init(&ev);
+  grpc_resolve_address("localhost", NULL, must_fail, &ev);
+  GPR_ASSERT(gpr_event_wait(&ev, test_deadline()));
+}
+
+static void test_ipv6_with_port() {
+  gpr_event ev;
+  gpr_event_init(&ev);
+  grpc_resolve_address("[2001:db8::1]:1", NULL, must_succeed, &ev);
+  GPR_ASSERT(gpr_event_wait(&ev, test_deadline()));
+}
+
+static void test_ipv6_without_port() {
+  const char* const kCases[] = {
+      "2001:db8::1", "2001:db8::1.2.3.4", "[2001:db8::1]",
+  };
+  int i;
+  for (i = 0; i < sizeof(kCases) / sizeof(*kCases); i++) {
+    gpr_event ev;
+    gpr_event_init(&ev);
+    grpc_resolve_address(kCases[i], "80", must_succeed, &ev);
+    GPR_ASSERT(gpr_event_wait(&ev, test_deadline()));
+  }
+}
+
+static void test_invalid_ip_addresses() {
+  const char* const kCases[] = {
+      "293.283.1238.3:1", "[2001:db8::11111]:1",
+  };
+  int i;
+  for (i = 0; i < sizeof(kCases) / sizeof(*kCases); i++) {
+    gpr_event ev;
+    gpr_event_init(&ev);
+    grpc_resolve_address(kCases[i], NULL, must_fail, &ev);
+    GPR_ASSERT(gpr_event_wait(&ev, test_deadline()));
+  }
+}
+
+static void test_unparseable_hostports() {
+  const char* const kCases[] = {
+      "[", "[::1", "[::1]bad", "[1.2.3.4]", "[localhost]", "[localhost]:1",
+  };
+  int i;
+  for (i = 0; i < sizeof(kCases) / sizeof(*kCases); i++) {
+    gpr_event ev;
+    gpr_event_init(&ev);
+    grpc_resolve_address(kCases[i], "1", must_fail, &ev);
+    GPR_ASSERT(gpr_event_wait(&ev, test_deadline()));
+  }
+}
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+
+  test_localhost();
+  test_default_port();
+  test_missing_default_port();
+  test_ipv6_with_port();
+  test_ipv6_without_port();
+  test_invalid_ip_addresses();
+  test_unparseable_hostports();
+
+  return 0;
+}
diff --git a/test/core/endpoint/secure_endpoint_test.c b/test/core/endpoint/secure_endpoint_test.c
new file mode 100644
index 0000000..9fc2511
--- /dev/null
+++ b/test/core/endpoint/secure_endpoint_test.c
@@ -0,0 +1,222 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "endpoint_tests.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "src/core/endpoint/secure_endpoint.h"
+#include "src/core/endpoint/tcp.h"
+#include "src/core/eventmanager/em.h"
+#include "src/core/tsi/fake_transport_security.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+grpc_em g_em;
+
+static void create_sockets(int sv[2]) {
+  int flags;
+  GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
+  flags = fcntl(sv[0], F_GETFL, 0);
+  GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0);
+  flags = fcntl(sv[1], F_GETFL, 0);
+  GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
+}
+
+static grpc_endpoint_test_fixture secure_endpoint_create_fixture_tcp_socketpair(
+    ssize_t slice_size, gpr_slice *leftover_slices, size_t leftover_nslices) {
+  int sv[2];
+  tsi_frame_protector *fake_read_protector = tsi_create_fake_protector(NULL);
+  tsi_frame_protector *fake_write_protector = tsi_create_fake_protector(NULL);
+  grpc_endpoint_test_fixture f;
+  grpc_endpoint *tcp_read;
+  grpc_endpoint *tcp_write;
+
+  create_sockets(sv);
+  grpc_em_init(&g_em);
+  tcp_read = grpc_tcp_create_dbg(sv[0], &g_em, slice_size);
+  tcp_write = grpc_tcp_create(sv[1], &g_em);
+
+  if (leftover_nslices == 0) {
+    f.client_ep =
+        grpc_secure_endpoint_create(fake_read_protector, tcp_read, NULL, 0);
+  } else {
+    int i;
+    tsi_result result;
+    gpr_uint32 still_pending_size;
+    size_t total_buffer_size = 8192;
+    size_t buffer_size = total_buffer_size;
+    gpr_uint8 *encrypted_buffer = gpr_malloc(buffer_size);
+    gpr_uint8 *cur = encrypted_buffer;
+    gpr_slice encrypted_leftover;
+    for (i = 0; i < leftover_nslices; i++) {
+      gpr_slice plain = leftover_slices[i];
+      gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(plain);
+      size_t message_size = GPR_SLICE_LENGTH(plain);
+      while (message_size > 0) {
+        gpr_uint32 protected_buffer_size_to_send = buffer_size;
+        gpr_uint32 processed_message_size = message_size;
+        result = tsi_frame_protector_protect(
+            fake_write_protector, message_bytes, &processed_message_size, cur,
+            &protected_buffer_size_to_send);
+        GPR_ASSERT(result == TSI_OK);
+        message_bytes += processed_message_size;
+        message_size -= processed_message_size;
+        cur += protected_buffer_size_to_send;
+        buffer_size -= protected_buffer_size_to_send;
+
+        GPR_ASSERT(buffer_size >= 0);
+      }
+      gpr_slice_unref(plain);
+    }
+    do {
+      gpr_uint32 protected_buffer_size_to_send = buffer_size;
+      result = tsi_frame_protector_protect_flush(fake_write_protector, cur,
+                                                 &protected_buffer_size_to_send,
+                                                 &still_pending_size);
+      GPR_ASSERT(result == TSI_OK);
+      cur += protected_buffer_size_to_send;
+      buffer_size -= protected_buffer_size_to_send;
+      GPR_ASSERT(buffer_size >= 0);
+    } while (still_pending_size > 0);
+    encrypted_leftover = gpr_slice_from_copied_buffer(
+        (const char *)encrypted_buffer, total_buffer_size - buffer_size);
+    f.client_ep = grpc_secure_endpoint_create(fake_read_protector, tcp_read,
+                                              &encrypted_leftover, 1);
+    gpr_slice_unref(encrypted_leftover);
+    gpr_free(encrypted_buffer);
+  }
+
+  f.server_ep =
+      grpc_secure_endpoint_create(fake_write_protector, tcp_write, NULL, 0);
+  return f;
+}
+
+static grpc_endpoint_test_fixture
+secure_endpoint_create_fixture_tcp_socketpair_noleftover(ssize_t slice_size) {
+  return secure_endpoint_create_fixture_tcp_socketpair(slice_size, NULL, 0);
+}
+
+static grpc_endpoint_test_fixture
+secure_endpoint_create_fixture_tcp_socketpair_leftover(ssize_t slice_size) {
+  gpr_slice s =
+      gpr_slice_from_copied_string("hello world 12345678900987654321");
+  grpc_endpoint_test_fixture f;
+
+  f = secure_endpoint_create_fixture_tcp_socketpair(slice_size, &s, 1);
+  return f;
+}
+
+static void clean_up() { grpc_em_destroy(&g_em); }
+
+static grpc_endpoint_test_config configs[] = {
+    {"secure_ep/tcp_socketpair",
+     secure_endpoint_create_fixture_tcp_socketpair_noleftover, clean_up},
+    {"secure_ep/tcp_socketpair_leftover",
+     secure_endpoint_create_fixture_tcp_socketpair_leftover, clean_up},
+};
+
+static void verify_leftover(void *user_data, gpr_slice *slices, size_t nslices,
+                            grpc_endpoint_cb_status error) {
+  gpr_slice s =
+      gpr_slice_from_copied_string("hello world 12345678900987654321");
+
+  GPR_ASSERT(error == GRPC_ENDPOINT_CB_OK);
+  GPR_ASSERT(nslices == 1);
+
+  GPR_ASSERT(0 == gpr_slice_cmp(s, slices[0]));
+  gpr_slice_unref(slices[0]);
+  gpr_slice_unref(s);
+  *(int *)user_data = 1;
+}
+
+static void test_leftover(grpc_endpoint_test_config config,
+                          ssize_t slice_size) {
+  grpc_endpoint_test_fixture f = config.create_fixture(slice_size);
+  int verified = 0;
+  gpr_log(GPR_INFO, "Start test left over");
+
+  grpc_endpoint_notify_on_read(f.client_ep, verify_leftover, &verified,
+                               gpr_inf_future);
+  GPR_ASSERT(verified == 1);
+
+  grpc_endpoint_shutdown(f.client_ep);
+  grpc_endpoint_shutdown(f.server_ep);
+  grpc_endpoint_destroy(f.client_ep);
+  grpc_endpoint_destroy(f.server_ep);
+  clean_up();
+}
+
+static void destroy_early(void *user_data, gpr_slice *slices, size_t nslices,
+                          grpc_endpoint_cb_status error) {
+  grpc_endpoint_test_fixture *f = user_data;
+  gpr_slice s =
+      gpr_slice_from_copied_string("hello world 12345678900987654321");
+
+  GPR_ASSERT(error == GRPC_ENDPOINT_CB_OK);
+  GPR_ASSERT(nslices == 1);
+
+  grpc_endpoint_shutdown(f->client_ep);
+  grpc_endpoint_destroy(f->client_ep);
+
+  GPR_ASSERT(0 == gpr_slice_cmp(s, slices[0]));
+  gpr_slice_unref(slices[0]);
+  gpr_slice_unref(s);
+}
+
+/* test which destroys the ep before finishing reading */
+static void test_destroy_ep_early(grpc_endpoint_test_config config,
+                                  ssize_t slice_size) {
+  grpc_endpoint_test_fixture f = config.create_fixture(slice_size);
+  gpr_log(GPR_INFO, "Start test destroy early");
+
+  grpc_endpoint_notify_on_read(f.client_ep, destroy_early, &f, gpr_inf_future);
+
+  grpc_endpoint_shutdown(f.server_ep);
+  grpc_endpoint_destroy(f.server_ep);
+  clean_up();
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+
+  grpc_endpoint_tests(configs[0]);
+  test_leftover(configs[1], 1);
+  test_destroy_ep_early(configs[1], 1);
+
+  return 0;
+}
diff --git a/test/core/endpoint/tcp_client_test.c b/test/core/endpoint/tcp_client_test.c
new file mode 100644
index 0000000..10138e6
--- /dev/null
+++ b/test/core/endpoint/tcp_client_test.c
@@ -0,0 +1,177 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/endpoint/tcp_client.h"
+
+#include <errno.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "src/core/eventmanager/em.h"
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+
+static grpc_em em;
+
+static gpr_timespec test_deadline() {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(1000000));
+}
+
+static void must_succeed(void *arg, grpc_endpoint *tcp) {
+  GPR_ASSERT(tcp);
+  grpc_endpoint_shutdown(tcp);
+  grpc_endpoint_destroy(tcp);
+  gpr_event_set(arg, (void *)1);
+}
+
+static void must_fail(void *arg, grpc_endpoint *tcp) {
+  GPR_ASSERT(!tcp);
+  gpr_event_set(arg, (void *)1);
+}
+
+void test_succeeds() {
+  struct sockaddr_in addr;
+  socklen_t addr_len = sizeof(addr);
+  int svr_fd;
+  int r;
+  gpr_event ev;
+
+  gpr_event_init(&ev);
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+
+  /* create a dummy server */
+  svr_fd = socket(AF_INET, SOCK_STREAM, 0);
+  GPR_ASSERT(svr_fd >= 0);
+  GPR_ASSERT(0 == bind(svr_fd, (struct sockaddr *)&addr, addr_len));
+  GPR_ASSERT(0 == listen(svr_fd, 1));
+
+  /* connect to it */
+  GPR_ASSERT(getsockname(svr_fd, (struct sockaddr *)&addr, &addr_len) == 0);
+  grpc_tcp_client_connect(must_succeed, &ev, &em, (struct sockaddr *)&addr,
+                          addr_len, gpr_inf_future);
+
+  /* await the connection */
+  do {
+    addr_len = sizeof(addr);
+    r = accept(svr_fd, (struct sockaddr *)&addr, &addr_len);
+  } while (r == -1 && errno == EINTR);
+  GPR_ASSERT(r >= 0);
+  close(r);
+
+  /* wait for the connection callback to finish */
+  GPR_ASSERT(gpr_event_wait(&ev, test_deadline()));
+}
+
+void test_fails() {
+  struct sockaddr_in addr;
+  socklen_t addr_len = sizeof(addr);
+  gpr_event ev;
+
+  gpr_event_init(&ev);
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+
+  /* connect to a broken address */
+  grpc_tcp_client_connect(must_fail, &ev, &em, (struct sockaddr *)&addr,
+                          addr_len, gpr_inf_future);
+
+  /* wait for the connection callback to finish */
+  GPR_ASSERT(gpr_event_wait(&ev, test_deadline()));
+}
+
+void test_times_out() {
+  struct sockaddr_in addr;
+  socklen_t addr_len = sizeof(addr);
+  int svr_fd;
+#define NUM_CLIENT_CONNECTS 10
+  int client_fd[NUM_CLIENT_CONNECTS];
+  int i;
+  int r;
+  gpr_event ev;
+  gpr_timespec connect_deadline;
+
+  gpr_event_init(&ev);
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+
+  /* create a dummy server */
+  svr_fd = socket(AF_INET, SOCK_STREAM, 0);
+  GPR_ASSERT(svr_fd >= 0);
+  GPR_ASSERT(0 == bind(svr_fd, (struct sockaddr *)&addr, addr_len));
+  GPR_ASSERT(0 == listen(svr_fd, 1));
+  /* Get its address */
+  GPR_ASSERT(getsockname(svr_fd, (struct sockaddr *)&addr, &addr_len) == 0);
+
+  /* tie up the listen buffer, which is somewhat arbitrarily sized. */
+  for (i = 0; i < NUM_CLIENT_CONNECTS; ++i) {
+    client_fd[i] = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
+    do {
+      r = connect(client_fd[i], (struct sockaddr *)&addr, addr_len);
+    } while (r == -1 && errno == EINTR);
+    GPR_ASSERT(r < 0);
+    GPR_ASSERT(errno == EWOULDBLOCK || errno == EINPROGRESS);
+  }
+
+  /* connect to dummy server address */
+
+  connect_deadline = gpr_time_add(gpr_now(), gpr_time_from_micros(1000000));
+
+  grpc_tcp_client_connect(must_fail, &ev, &em, (struct sockaddr *)&addr,
+                          addr_len, connect_deadline);
+  /* Make sure the event doesn't trigger early */
+  GPR_ASSERT(!gpr_event_wait(
+                 &ev, gpr_time_add(gpr_now(), gpr_time_from_micros(500000))));
+  /* Now wait until it should have triggered */
+  sleep(1);
+
+  /* wait for the connection callback to finish */
+  GPR_ASSERT(gpr_event_wait(&ev, test_deadline()));
+  close(svr_fd);
+  for (i = 0; i < NUM_CLIENT_CONNECTS; ++i) {
+    close(client_fd[i]);
+  }
+}
+
+int main(void) {
+  grpc_em_init(&em);
+  test_succeeds();
+  test_fails();
+  test_times_out();
+  return 0;
+}
diff --git a/test/core/endpoint/tcp_server_test.c b/test/core/endpoint/tcp_server_test.c
new file mode 100644
index 0000000..10e2c36
--- /dev/null
+++ b/test/core/endpoint/tcp_server_test.c
@@ -0,0 +1,168 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/endpoint/tcp_server.h"
+#include "src/core/eventmanager/em.h"
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+#include <netinet/in.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LOG_TEST() gpr_log(GPR_INFO, "%s", __FUNCTION__)
+
+static grpc_em em;
+
+static gpr_mu mu;
+static gpr_cv cv;
+static int nconnects = 0;
+
+static void on_connect(void *arg, grpc_endpoint *tcp) {
+  grpc_endpoint_shutdown(tcp);
+  grpc_endpoint_destroy(tcp);
+
+  gpr_mu_lock(&mu);
+  nconnects++;
+  gpr_cv_broadcast(&cv);
+  gpr_mu_unlock(&mu);
+}
+
+static void test_no_op() {
+  grpc_tcp_server *s = grpc_tcp_server_create(&em);
+  grpc_tcp_server_destroy(s);
+}
+
+static void test_no_op_with_start() {
+  grpc_tcp_server *s = grpc_tcp_server_create(&em);
+  LOG_TEST();
+  grpc_tcp_server_start(s, on_connect, NULL);
+  grpc_tcp_server_destroy(s);
+}
+
+static void test_no_op_with_port() {
+  struct sockaddr_in addr;
+  grpc_tcp_server *s = grpc_tcp_server_create(&em);
+  LOG_TEST();
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  GPR_ASSERT(
+      grpc_tcp_server_add_port(s, (struct sockaddr *)&addr, sizeof(addr)) >= 0);
+
+  grpc_tcp_server_destroy(s);
+}
+
+static void test_no_op_with_port_and_start() {
+  struct sockaddr_in addr;
+  grpc_tcp_server *s = grpc_tcp_server_create(&em);
+  LOG_TEST();
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  GPR_ASSERT(
+      grpc_tcp_server_add_port(s, (struct sockaddr *)&addr, sizeof(addr)) >= 0);
+
+  grpc_tcp_server_start(s, on_connect, NULL);
+
+  grpc_tcp_server_destroy(s);
+}
+
+static void test_connect(int n) {
+  struct sockaddr_in addr;
+  socklen_t addr_len = sizeof(addr);
+  int svrfd, clifd;
+  grpc_tcp_server *s = grpc_tcp_server_create(&em);
+  int nconnects_before;
+  gpr_timespec deadline;
+  int i;
+  LOG_TEST();
+  gpr_log(GPR_INFO, "clients=%d", n);
+
+  gpr_mu_lock(&mu);
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  svrfd = grpc_tcp_server_add_port(s, (struct sockaddr *)&addr, addr_len);
+  GPR_ASSERT(svrfd >= 0);
+
+  GPR_ASSERT(getsockname(svrfd, (struct sockaddr *)&addr, &addr_len) == 0);
+  GPR_ASSERT(addr_len == sizeof(addr));
+
+  grpc_tcp_server_start(s, on_connect, NULL);
+
+  for (i = 0; i < n; i++) {
+    deadline = gpr_time_add(gpr_now(), gpr_time_from_micros(10000000));
+
+    nconnects_before = nconnects;
+    clifd = socket(AF_INET, SOCK_STREAM, 0);
+    GPR_ASSERT(clifd >= 0);
+    GPR_ASSERT(connect(clifd, (struct sockaddr *)&addr, addr_len) == 0);
+
+    while (nconnects == nconnects_before) {
+      GPR_ASSERT(gpr_cv_wait(&cv, &mu, deadline) == 0);
+    }
+
+    GPR_ASSERT(nconnects == nconnects_before + 1);
+    close(clifd);
+
+    if (i != n - 1) {
+      sleep(1);
+    }
+  }
+
+  gpr_mu_unlock(&mu);
+
+  grpc_tcp_server_destroy(s);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  grpc_em_init(&em);
+  gpr_mu_init(&mu);
+  gpr_cv_init(&cv);
+
+  test_no_op();
+  test_no_op_with_start();
+  test_no_op_with_port();
+  test_no_op_with_port_and_start();
+  test_connect(1);
+  test_connect(10);
+
+  grpc_em_destroy(&em);
+  gpr_mu_destroy(&mu);
+  gpr_cv_destroy(&cv);
+  return 0;
+}
diff --git a/test/core/endpoint/tcp_test.c b/test/core/endpoint/tcp_test.c
new file mode 100644
index 0000000..7dbc278
--- /dev/null
+++ b/test/core/endpoint/tcp_test.c
@@ -0,0 +1,517 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/endpoint/tcp.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "src/core/eventmanager/em.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+#include "test/core/util/test_config.h"
+#include "test/core/endpoint/endpoint_tests.h"
+
+/*
+   General test notes:
+
+   All tests which write data into a socket write i%256 into byte i, which is
+   verified by readers.
+
+   In general there are a few interesting things to vary which may lead to
+   exercising different codepaths in an implementation:
+   1. Total amount of data written to the socket
+   2. Size of slice allocations
+   3. Amount of data we read from or write to the socket at once
+
+   The tests here tend to parameterize these where applicable.
+
+ */
+
+grpc_em g_em;
+
+static void create_sockets(int sv[2]) {
+  int flags;
+  GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
+  flags = fcntl(sv[0], F_GETFL, 0);
+  GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0);
+  flags = fcntl(sv[1], F_GETFL, 0);
+  GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
+}
+
+static ssize_t fill_socket(int fd) {
+  ssize_t write_bytes;
+  ssize_t total_bytes = 0;
+  int i;
+  unsigned char buf[256];
+  for (i = 0; i < 256; ++i) {
+    buf[i] = i;
+  }
+  do {
+    write_bytes = write(fd, buf, 256);
+    if (write_bytes > 0) {
+      total_bytes += write_bytes;
+    }
+  } while (write_bytes >= 0 || errno == EINTR);
+  GPR_ASSERT(errno == EAGAIN);
+  return total_bytes;
+}
+
+static size_t fill_socket_partial(int fd, size_t bytes) {
+  ssize_t write_bytes;
+  size_t total_bytes = 0;
+  unsigned char *buf = malloc(bytes);
+  int i;
+  for (i = 0; i < bytes; ++i) {
+    buf[i] = i % 256;
+  }
+
+  do {
+    write_bytes = write(fd, buf, bytes - total_bytes);
+    if (write_bytes > 0) {
+      total_bytes += write_bytes;
+    }
+  } while ((write_bytes >= 0 || errno == EINTR) && bytes > total_bytes);
+
+  gpr_free(buf);
+
+  return total_bytes;
+}
+
+struct read_socket_state {
+  grpc_endpoint *ep;
+  gpr_mu mu;
+  gpr_cv cv;
+  size_t read_bytes;
+  ssize_t target_read_bytes;
+};
+
+static ssize_t count_and_unref_slices(gpr_slice *slices, size_t nslices,
+                                      int *current_data) {
+  ssize_t num_bytes = 0;
+  int i;
+  int j;
+  unsigned char *buf;
+  for (i = 0; i < nslices; ++i) {
+    buf = GPR_SLICE_START_PTR(slices[i]);
+    for (j = 0; j < GPR_SLICE_LENGTH(slices[i]); ++j) {
+      GPR_ASSERT(buf[j] == *current_data);
+      *current_data = (*current_data + 1) % 256;
+    }
+    num_bytes += GPR_SLICE_LENGTH(slices[i]);
+    gpr_slice_unref(slices[i]);
+  }
+  return num_bytes;
+}
+
+static void read_cb(void *user_data, gpr_slice *slices, size_t nslices,
+                    grpc_endpoint_cb_status error) {
+  struct read_socket_state *state = (struct read_socket_state *)user_data;
+  ssize_t read_bytes;
+  int current_data = 0;
+
+  GPR_ASSERT(error == GRPC_ENDPOINT_CB_OK);
+
+  gpr_mu_lock(&state->mu);
+  read_bytes = count_and_unref_slices(slices, nslices, &current_data);
+  state->read_bytes += read_bytes;
+  gpr_log(GPR_INFO, "Read %d bytes of %d", read_bytes,
+          state->target_read_bytes);
+  if (state->read_bytes >= state->target_read_bytes) {
+    gpr_cv_signal(&state->cv);
+  } else {
+    grpc_endpoint_notify_on_read(state->ep, read_cb, state, gpr_inf_future);
+  }
+  gpr_mu_unlock(&state->mu);
+}
+
+/* Write to a socket, then read from it using the grpc_tcp API. */
+static void read_test(ssize_t num_bytes, ssize_t slice_size) {
+  int sv[2];
+  grpc_em em;
+  grpc_endpoint *ep;
+  struct read_socket_state state;
+  ssize_t written_bytes;
+  gpr_timespec rel_deadline = {20, 0};
+  gpr_timespec deadline = gpr_time_add(gpr_now(), rel_deadline);
+
+  gpr_log(GPR_INFO, "Read test of size %d, slice size %d", num_bytes,
+          slice_size);
+
+  create_sockets(sv);
+  grpc_em_init(&em);
+
+  ep = grpc_tcp_create_dbg(sv[1], &em, slice_size);
+  written_bytes = fill_socket_partial(sv[0], num_bytes);
+  gpr_log(GPR_INFO, "Wrote %d bytes", written_bytes);
+
+  gpr_mu_init(&state.mu);
+  gpr_cv_init(&state.cv);
+  state.ep = ep;
+  state.read_bytes = 0;
+  state.target_read_bytes = written_bytes;
+
+  grpc_endpoint_notify_on_read(ep, read_cb, &state, gpr_inf_future);
+
+  gpr_mu_lock(&state.mu);
+  for (;;) {
+    GPR_ASSERT(gpr_cv_wait(&state.cv, &state.mu, deadline) == 0);
+    if (state.read_bytes >= state.target_read_bytes) {
+      break;
+    }
+  }
+  GPR_ASSERT(state.read_bytes == state.target_read_bytes);
+  gpr_mu_unlock(&state.mu);
+
+  grpc_endpoint_destroy(ep);
+
+  grpc_em_destroy(&em);
+  gpr_mu_destroy(&state.mu);
+  gpr_cv_destroy(&state.cv);
+}
+
+/* Write to a socket until it fills up, then read from it using the grpc_tcp
+   API. */
+static void large_read_test(ssize_t slice_size) {
+  int sv[2];
+  grpc_em em;
+  grpc_endpoint *ep;
+  struct read_socket_state state;
+  ssize_t written_bytes;
+  gpr_timespec rel_deadline = {20, 0};
+  gpr_timespec deadline = gpr_time_add(gpr_now(), rel_deadline);
+
+  gpr_log(GPR_INFO, "Start large read test, slice size %d", slice_size);
+
+  create_sockets(sv);
+  grpc_em_init(&em);
+
+  ep = grpc_tcp_create_dbg(sv[1], &em, slice_size);
+  written_bytes = fill_socket(sv[0]);
+  gpr_log(GPR_INFO, "Wrote %d bytes", written_bytes);
+
+  gpr_mu_init(&state.mu);
+  gpr_cv_init(&state.cv);
+  state.ep = ep;
+  state.read_bytes = 0;
+  state.target_read_bytes = written_bytes;
+
+  grpc_endpoint_notify_on_read(ep, read_cb, &state, gpr_inf_future);
+
+  gpr_mu_lock(&state.mu);
+  for (;;) {
+    GPR_ASSERT(gpr_cv_wait(&state.cv, &state.mu, deadline) == 0);
+    if (state.read_bytes >= state.target_read_bytes) {
+      break;
+    }
+  }
+  GPR_ASSERT(state.read_bytes == state.target_read_bytes);
+  gpr_mu_unlock(&state.mu);
+
+  grpc_endpoint_destroy(ep);
+
+  grpc_em_destroy(&em);
+  gpr_mu_destroy(&state.mu);
+  gpr_cv_destroy(&state.cv);
+}
+
+struct write_socket_state {
+  grpc_endpoint *ep;
+  gpr_mu mu;
+  gpr_cv cv;
+  int write_done;
+};
+
+static gpr_slice *allocate_blocks(ssize_t num_bytes, ssize_t slice_size,
+                                  size_t *num_blocks, int *current_data) {
+  ssize_t nslices = num_bytes / slice_size + (num_bytes % slice_size ? 1 : 0);
+  gpr_slice *slices = gpr_malloc(sizeof(gpr_slice) * nslices);
+  ssize_t num_bytes_left = num_bytes;
+  int i;
+  int j;
+  unsigned char *buf;
+  *num_blocks = nslices;
+
+  for (i = 0; i < nslices; ++i) {
+    slices[i] = gpr_slice_malloc(slice_size > num_bytes_left ? num_bytes_left
+                                                             : slice_size);
+    num_bytes_left -= GPR_SLICE_LENGTH(slices[i]);
+    buf = GPR_SLICE_START_PTR(slices[i]);
+    for (j = 0; j < GPR_SLICE_LENGTH(slices[i]); ++j) {
+      buf[j] = *current_data;
+      *current_data = (*current_data + 1) % 256;
+    }
+  }
+  GPR_ASSERT(num_bytes_left == 0);
+  return slices;
+}
+
+static void write_done(void *user_data /* write_socket_state */,
+                       grpc_endpoint_cb_status error) {
+  struct write_socket_state *state = (struct write_socket_state *)user_data;
+  gpr_log(GPR_INFO, "Write done callback called");
+  gpr_mu_lock(&state->mu);
+  gpr_log(GPR_INFO, "Signalling write done");
+  state->write_done = 1;
+  gpr_cv_signal(&state->cv);
+  gpr_mu_unlock(&state->mu);
+}
+
+void drain_socket_blocking(int fd, size_t num_bytes, size_t read_size) {
+  unsigned char *buf = malloc(read_size);
+  ssize_t bytes_read;
+  size_t bytes_left = num_bytes;
+  int flags;
+  int current = 0;
+  int i;
+
+  flags = fcntl(fd, F_GETFL, 0);
+  GPR_ASSERT(fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == 0);
+
+  for (;;) {
+    do {
+      bytes_read =
+          read(fd, buf, bytes_left > read_size ? read_size : bytes_left);
+    } while (bytes_read < 0 && errno == EINTR);
+    GPR_ASSERT(bytes_read >= 0);
+    for (i = 0; i < bytes_read; ++i) {
+      GPR_ASSERT(buf[i] == current);
+      current = (current + 1) % 256;
+    }
+    bytes_left -= bytes_read;
+    if (bytes_left == 0) break;
+  }
+  flags = fcntl(fd, F_GETFL, 0);
+  GPR_ASSERT(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0);
+
+  gpr_free(buf);
+}
+
+static ssize_t drain_socket(int fd) {
+  ssize_t read_bytes;
+  ssize_t total_bytes = 0;
+  unsigned char buf[256];
+  int current = 0;
+  int i;
+  do {
+    read_bytes = read(fd, buf, 256);
+    if (read_bytes > 0) {
+      total_bytes += read_bytes;
+      for (i = 0; i < read_bytes; ++i) {
+        GPR_ASSERT(buf[i] == current);
+        current = (current + 1) % 256;
+      }
+    }
+  } while (read_bytes >= 0 || errno == EINTR);
+  GPR_ASSERT(errno == EAGAIN);
+  return total_bytes;
+}
+
+/* Write to a socket using the grpc_tcp API, then drain it directly.
+   Note that if the write does not complete immediately we need to drain the
+   socket in parallel with the read. */
+static void write_test(ssize_t num_bytes, ssize_t slice_size) {
+  int sv[2];
+  grpc_em em;
+  grpc_endpoint *ep;
+  struct write_socket_state state;
+  ssize_t read_bytes;
+  size_t num_blocks;
+  gpr_slice *slices;
+  int current_data = 0;
+  gpr_timespec rel_deadline = {20, 0};
+  gpr_timespec deadline = gpr_time_add(gpr_now(), rel_deadline);
+
+  gpr_log(GPR_INFO, "Start write test with %d bytes, slice size %d", num_bytes,
+          slice_size);
+
+  create_sockets(sv);
+  grpc_em_init(&em);
+
+  ep = grpc_tcp_create(sv[1], &em);
+
+  gpr_mu_init(&state.mu);
+  gpr_cv_init(&state.cv);
+  state.ep = ep;
+  state.write_done = 0;
+
+  slices = allocate_blocks(num_bytes, slice_size, &num_blocks, &current_data);
+
+  if (grpc_endpoint_write(ep, slices, num_blocks, write_done, &state,
+                          gpr_inf_future) == GRPC_ENDPOINT_WRITE_DONE) {
+    /* Write completed immediately */
+    read_bytes = drain_socket(sv[0]);
+    GPR_ASSERT(read_bytes == num_bytes);
+  } else {
+    drain_socket_blocking(sv[0], num_bytes, num_bytes);
+    gpr_mu_lock(&state.mu);
+    for (;;) {
+      if (state.write_done) {
+        break;
+      }
+      GPR_ASSERT(gpr_cv_wait(&state.cv, &state.mu, deadline) == 0);
+    }
+    gpr_mu_unlock(&state.mu);
+  }
+
+  grpc_endpoint_destroy(ep);
+  grpc_em_destroy(&em);
+  gpr_mu_destroy(&state.mu);
+  gpr_cv_destroy(&state.cv);
+  gpr_free(slices);
+}
+
+static void read_done_for_write_error(void *ud, gpr_slice *slices,
+                                      size_t nslices,
+                                      grpc_endpoint_cb_status error) {
+  GPR_ASSERT(error != GRPC_ENDPOINT_CB_OK);
+  GPR_ASSERT(nslices == 0);
+}
+
+/* Write to a socket using the grpc_tcp API, then drain it directly.
+   Note that if the write does not complete immediately we need to drain the
+   socket in parallel with the read. */
+static void write_error_test(ssize_t num_bytes, ssize_t slice_size) {
+  int sv[2];
+  grpc_em em;
+  grpc_endpoint *ep;
+  struct write_socket_state state;
+  size_t num_blocks;
+  gpr_slice *slices;
+  int current_data = 0;
+  gpr_timespec rel_deadline = {20, 0};
+  gpr_timespec deadline = gpr_time_add(gpr_now(), rel_deadline);
+
+  gpr_log(GPR_INFO, "Start write error test with %d bytes, slice size %d",
+          num_bytes, slice_size);
+
+  create_sockets(sv);
+  grpc_em_init(&em);
+
+  ep = grpc_tcp_create(sv[1], &em);
+  close(sv[0]);
+
+  gpr_mu_init(&state.mu);
+  gpr_cv_init(&state.cv);
+  state.ep = ep;
+  state.write_done = 0;
+
+  slices = allocate_blocks(num_bytes, slice_size, &num_blocks, &current_data);
+
+  switch (grpc_endpoint_write(ep, slices, num_blocks, write_done, &state,
+                              gpr_inf_future)) {
+    case GRPC_ENDPOINT_WRITE_DONE:
+    case GRPC_ENDPOINT_WRITE_ERROR:
+      /* Write completed immediately */
+      break;
+    case GRPC_ENDPOINT_WRITE_PENDING:
+      grpc_endpoint_notify_on_read(ep, read_done_for_write_error, NULL,
+                                   gpr_inf_future);
+      gpr_mu_lock(&state.mu);
+      for (;;) {
+        if (state.write_done) {
+          break;
+        }
+        GPR_ASSERT(gpr_cv_wait(&state.cv, &state.mu, deadline) == 0);
+      }
+      gpr_mu_unlock(&state.mu);
+      break;
+  }
+
+  grpc_endpoint_destroy(ep);
+  grpc_em_destroy(&em);
+  gpr_mu_destroy(&state.mu);
+  gpr_cv_destroy(&state.cv);
+  free(slices);
+}
+
+void run_tests() {
+  int i = 0;
+
+  read_test(100, 8192);
+  read_test(10000, 8192);
+  read_test(10000, 137);
+  read_test(10000, 1);
+  large_read_test(8192);
+  large_read_test(1);
+
+  write_test(100, 8192);
+  write_test(100, 1);
+  write_test(100000, 8192);
+  write_test(100000, 1);
+  write_test(100000, 137);
+
+  for (i = 1; i < 1000; i = GPR_MAX(i + 1, i * 5 / 4)) {
+    write_error_test(40320, i);
+  }
+
+  for (i = 1; i < 1000; i = GPR_MAX(i + 1, i * 5 / 4)) {
+    write_test(40320, i);
+  }
+}
+
+static void clean_up() { grpc_em_destroy(&g_em); }
+
+static grpc_endpoint_test_fixture create_fixture_tcp_socketpair(
+    ssize_t slice_size) {
+  int sv[2];
+  grpc_endpoint_test_fixture f;
+
+  create_sockets(sv);
+  grpc_em_init(&g_em);
+  f.client_ep = grpc_tcp_create_dbg(sv[0], &g_em, slice_size);
+  f.server_ep = grpc_tcp_create(sv[1], &g_em);
+
+  return f;
+}
+
+static grpc_endpoint_test_config configs[] = {
+    {"tcp/tcp_socketpair", create_fixture_tcp_socketpair, clean_up},
+};
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  /* disable SIGPIPE */
+  signal(SIGPIPE, SIG_IGN);
+  run_tests();
+  grpc_endpoint_tests(configs[0]);
+
+  return 0;
+}
diff --git a/test/core/eventmanager/em_pipe_test.c b/test/core/eventmanager/em_pipe_test.c
new file mode 100644
index 0000000..5411142
--- /dev/null
+++ b/test/core/eventmanager/em_pipe_test.c
@@ -0,0 +1,200 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Test grpc_em_fd with pipe. The test creates a pipe with non-blocking mode,
+   sends a stream of bytes through the pipe, and verifies that all bytes are
+   received. */
+#include "src/core/eventmanager/em.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+/* Operation for fcntl() to set pipe buffer size. */
+#ifndef F_SETPIPE_SZ
+#define F_SETPIPE_SZ (1024 + 7)
+#endif
+
+#define TOTAL_WRITE 3 /* total number of times that the write buffer is full. \
+                         */
+#define BUF_SIZE 1024
+char read_buf[BUF_SIZE];
+char write_buf[BUF_SIZE];
+
+typedef struct {
+  int fd[2];
+  grpc_em em;
+  grpc_em_fd read_em_fd;
+  grpc_em_fd write_em_fd;
+  int num_write; /* number of times that the write buffer is full*/
+  ssize_t bytes_written_total; /* total number of bytes written to the pipe */
+  ssize_t bytes_read_total;    /* total number of bytes read from the pipe */
+  pthread_mutex_t mu;          /* protect cv and done */
+  pthread_cond_t cv;           /* signaled when read finished */
+  int done;                    /* set to 1 when read finished */
+} async_pipe;
+
+void write_shutdown_cb(void *arg, /*async_pipe*/
+                       enum grpc_em_cb_status status) {
+  async_pipe *ap = arg;
+  close(ap->fd[1]);
+  grpc_em_fd_destroy(&ap->write_em_fd);
+}
+
+void write_cb(void *arg, /*async_pipe*/ enum grpc_em_cb_status status) {
+  async_pipe *ap = arg;
+  ssize_t bytes_written = 0;
+
+  if (status == GRPC_CALLBACK_CANCELLED) {
+    write_shutdown_cb(arg, GRPC_CALLBACK_SUCCESS);
+    return;
+  }
+
+  do {
+    bytes_written = write(ap->fd[1], write_buf, BUF_SIZE);
+    if (bytes_written > 0) ap->bytes_written_total += bytes_written;
+  } while (bytes_written > 0);
+
+  if (errno == EAGAIN) {
+    if (ap->num_write < TOTAL_WRITE) {
+      ap->num_write++;
+      grpc_em_fd_notify_on_write(&ap->write_em_fd, write_cb, ap,
+                                 gpr_inf_future);
+    } else {
+      /* Note that this could just shut down directly; doing a trip through the
+         shutdown path serves only a demonstration of the API. */
+      grpc_em_fd_shutdown(&ap->write_em_fd);
+      grpc_em_fd_notify_on_write(&ap->write_em_fd, write_cb, ap,
+                                 gpr_inf_future);
+    }
+  } else {
+    GPR_ASSERT(0 && strcat("unknown errno: ", strerror(errno)));
+  }
+}
+
+void read_shutdown_cb(void *arg, /*async_pipe*/ enum grpc_em_cb_status status) {
+  async_pipe *ap = arg;
+  close(ap->fd[0]);
+  grpc_em_fd_destroy(&ap->read_em_fd);
+  pthread_mutex_lock(&ap->mu);
+  if (ap->done == 0) {
+    ap->done = 1;
+    pthread_cond_signal(&ap->cv);
+  }
+  pthread_mutex_unlock(&ap->mu);
+}
+
+void read_cb(void *arg, /*async_pipe*/ enum grpc_em_cb_status status) {
+  async_pipe *ap = arg;
+  ssize_t bytes_read = 0;
+
+  if (status == GRPC_CALLBACK_CANCELLED) {
+    read_shutdown_cb(arg, GRPC_CALLBACK_SUCCESS);
+    return;
+  }
+
+  do {
+    bytes_read = read(ap->fd[0], read_buf, BUF_SIZE);
+    if (bytes_read > 0) ap->bytes_read_total += bytes_read;
+  } while (bytes_read > 0);
+
+  if (bytes_read == 0) {
+    /* Note that this could just shut down directly; doing a trip through the
+       shutdown path serves only a demonstration of the API. */
+    grpc_em_fd_shutdown(&ap->read_em_fd);
+    grpc_em_fd_notify_on_read(&ap->read_em_fd, read_cb, ap, gpr_inf_future);
+  } else if (bytes_read == -1) {
+    if (errno == EAGAIN) {
+      grpc_em_fd_notify_on_read(&ap->read_em_fd, read_cb, ap, gpr_inf_future);
+    } else {
+      GPR_ASSERT(0 && strcat("unknown errno: ", strerror(errno)));
+    }
+  }
+}
+
+void dummy_cb(void *arg, /*async_pipe*/ enum grpc_em_cb_status status) {}
+
+void async_pipe_init(async_pipe *ap) {
+  int i;
+
+  ap->num_write = 0;
+  ap->bytes_written_total = 0;
+  ap->bytes_read_total = 0;
+
+  pthread_mutex_init(&ap->mu, NULL);
+  pthread_cond_init(&ap->cv, NULL);
+  ap->done = 0;
+
+  GPR_ASSERT(0 == pipe(ap->fd));
+  for (i = 0; i < 2; i++) {
+    int flags = fcntl(ap->fd[i], F_GETFL, 0);
+    GPR_ASSERT(fcntl(ap->fd[i], F_SETFL, flags | O_NONBLOCK) == 0);
+    GPR_ASSERT(fcntl(ap->fd[i], F_SETPIPE_SZ, 4096) == 4096);
+  }
+
+  grpc_em_init(&ap->em);
+  grpc_em_fd_init(&ap->read_em_fd, &ap->em, ap->fd[0]);
+  grpc_em_fd_init(&ap->write_em_fd, &ap->em, ap->fd[1]);
+}
+
+static void async_pipe_start(async_pipe *ap) {
+  grpc_em_fd_notify_on_read(&ap->read_em_fd, read_cb, ap, gpr_inf_future);
+  grpc_em_fd_notify_on_write(&ap->write_em_fd, write_cb, ap, gpr_inf_future);
+}
+
+static void async_pipe_wait_destroy(async_pipe *ap) {
+  pthread_mutex_lock(&ap->mu);
+  while (!ap->done) pthread_cond_wait(&ap->cv, &ap->mu);
+  pthread_mutex_unlock(&ap->mu);
+  pthread_mutex_destroy(&ap->mu);
+  pthread_cond_destroy(&ap->cv);
+
+  grpc_em_destroy(&ap->em);
+}
+
+int main(int argc, char **argv) {
+  async_pipe ap;
+  grpc_test_init(argc, argv);
+  async_pipe_init(&ap);
+  async_pipe_start(&ap);
+  async_pipe_wait_destroy(&ap);
+  GPR_ASSERT(ap.bytes_read_total == ap.bytes_written_total);
+  gpr_log(GPR_INFO, "read total bytes %d", ap.bytes_read_total);
+  return 0;
+}
diff --git a/test/core/eventmanager/em_test.c b/test/core/eventmanager/em_test.c
new file mode 100644
index 0000000..2bcfe86
--- /dev/null
+++ b/test/core/eventmanager/em_test.c
@@ -0,0 +1,725 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Test gRPC event manager with a simple TCP upload server and client. */
+#include "src/core/eventmanager/em.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+/* buffer size used to send and receive data.
+   1024 is the minimal value to set TCP send and receive buffer. */
+#define BUF_SIZE 1024
+
+/* Create a test socket with the right properties for testing.
+   port is the TCP port to listen or connect to.
+   Return a socket FD and sockaddr_in. */
+static void create_test_socket(int port, int *socket_fd,
+                               struct sockaddr_in *sin) {
+  int fd;
+  int one = 1;
+  int buf_size = BUF_SIZE;
+  int flags;
+
+  fd = socket(AF_INET, SOCK_STREAM, 0);
+  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+  /* Reset the size of socket send buffer to the minimal value to facilitate
+     buffer filling up and triggering notify_on_write  */
+  GPR_ASSERT(
+      setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size)) != -1);
+  GPR_ASSERT(
+      setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size)) != -1);
+  /* Make fd non-blocking */
+  flags = fcntl(fd, F_GETFL, 0);
+  GPR_ASSERT(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0);
+  *socket_fd = fd;
+
+  /* Use local address for test */
+  sin->sin_family = AF_INET;
+  sin->sin_addr.s_addr = 0;
+  sin->sin_port = htons(port);
+}
+
+/* Dummy gRPC callback */
+void no_op_cb(void *arg, enum grpc_em_cb_status status) {}
+
+/* =======An upload server to test notify_on_read===========
+   The server simply reads and counts a stream of bytes. */
+
+/* An upload server. */
+typedef struct {
+  grpc_em em;               /* event manger used by the sever */
+  grpc_em_fd em_fd;         /* listening fd */
+  ssize_t read_bytes_total; /* total number of received bytes */
+  gpr_mu mu;                /* protect done and done_cv */
+  gpr_cv done_cv;           /* signaled when a server finishes serving */
+  int done;                 /* set to 1 when a server finishes serving */
+} server;
+
+static void server_init(server *sv) {
+  GPR_ASSERT(grpc_em_init(&sv->em) == GRPC_EM_OK);
+  sv->read_bytes_total = 0;
+  gpr_mu_init(&sv->mu);
+  gpr_cv_init(&sv->done_cv);
+  sv->done = 0;
+}
+
+/* An upload session.
+   Created when a new upload request arrives in the server. */
+typedef struct {
+  server *sv;              /* not owned by a single session */
+  grpc_em_fd em_fd;        /* fd to read upload bytes */
+  char read_buf[BUF_SIZE]; /* buffer to store upload bytes */
+} session;
+
+/* Called when an upload session can be safely shutdown.
+   Close session FD and start to shutdown listen FD. */
+static void session_shutdown_cb(void *arg, /*session*/
+                                enum grpc_em_cb_status status) {
+  session *se = arg;
+  server *sv = se->sv;
+  grpc_em_fd_destroy(&se->em_fd);
+  gpr_free(se);
+  /* Start to shutdown listen fd. */
+  grpc_em_fd_shutdown(&sv->em_fd);
+}
+
+/* Called when data become readable in a session. */
+static void session_read_cb(void *arg, /*session*/
+                            enum grpc_em_cb_status status) {
+  session *se = arg;
+  int fd = grpc_em_fd_get(&se->em_fd);
+
+  ssize_t read_once = 0;
+  ssize_t read_total = 0;
+
+  if (status == GRPC_CALLBACK_CANCELLED) {
+    close(fd);
+    session_shutdown_cb(arg, GRPC_CALLBACK_SUCCESS);
+    return;
+  }
+
+  do {
+    read_once = read(fd, se->read_buf, BUF_SIZE);
+    if (read_once > 0) read_total += read_once;
+  } while (read_once > 0);
+  se->sv->read_bytes_total += read_total;
+
+  /* read() returns 0 to indicate the TCP connection was closed by the client.
+     read(fd, read_buf, 0) also returns 0 which should never be called as such.
+     It is possible to read nothing due to spurious edge event or data has
+     been drained, In such a case, read() returns -1 and set errno to EAGAIN. */
+  if (read_once == 0) {
+    grpc_em_fd_shutdown(&se->em_fd);
+    grpc_em_fd_notify_on_read(&se->em_fd, session_read_cb, se, gpr_inf_future);
+  } else if (read_once == -1) {
+    if (errno == EAGAIN) {
+      /* An edge triggered event is cached in the kernel until next poll.
+         In the current single thread implementation, session_read_cb is called
+         in the polling thread, such that polling only happens after this
+         callback, and will catch read edge event if data is available again
+         before notify_on_read.
+         TODO(chenw): in multi-threaded version, callback and polling can be
+         run in different threads. polling may catch a persist read edge event
+         before notify_on_read is called.  */
+      GPR_ASSERT(grpc_em_fd_notify_on_read(&se->em_fd, session_read_cb, se,
+                                           gpr_inf_future) == GRPC_EM_OK);
+    } else {
+      gpr_log(GPR_ERROR, "Unhandled read error %s", strerror(errno));
+      GPR_ASSERT(0);
+    }
+  }
+}
+
+/* Called when the listen FD can be safely shutdown.
+   Close listen FD and signal that server can be shutdown. */
+static void listen_shutdown_cb(void *arg /*server*/,
+                               enum grpc_em_cb_status status) {
+  server *sv = arg;
+
+  close(grpc_em_fd_get(&sv->em_fd));
+  grpc_em_fd_destroy(&sv->em_fd);
+
+  gpr_mu_lock(&sv->mu);
+  sv->done = 1;
+  gpr_cv_signal(&sv->done_cv);
+  gpr_mu_unlock(&sv->mu);
+}
+
+/* Called when a new TCP connection request arrives in the listening port. */
+static void listen_cb(void *arg, /*=sv_arg*/
+                      enum grpc_em_cb_status status) {
+  server *sv = arg;
+  int fd;
+  int flags;
+  session *se;
+  struct sockaddr_storage ss;
+  socklen_t slen = sizeof(ss);
+  struct grpc_em_fd *listen_em_fd = &sv->em_fd;
+
+  if (status == GRPC_CALLBACK_CANCELLED) {
+    listen_shutdown_cb(arg, GRPC_CALLBACK_SUCCESS);
+    return;
+  }
+
+  fd = accept(grpc_em_fd_get(listen_em_fd), (struct sockaddr *)&ss, &slen);
+  GPR_ASSERT(fd >= 0);
+  GPR_ASSERT(fd < FD_SETSIZE);
+  flags = fcntl(fd, F_GETFL, 0);
+  fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+  se = gpr_malloc(sizeof(*se));
+  se->sv = sv;
+  GPR_ASSERT(grpc_em_fd_init(&se->em_fd, &sv->em, fd) == GRPC_EM_OK);
+  GPR_ASSERT(grpc_em_fd_notify_on_read(&se->em_fd, session_read_cb, se,
+                                       gpr_inf_future) == GRPC_EM_OK);
+
+  GPR_ASSERT(grpc_em_fd_notify_on_read(listen_em_fd, listen_cb, sv,
+                                       gpr_inf_future) == GRPC_EM_OK);
+}
+
+/* Max number of connections pending to be accepted by listen(). */
+#define MAX_NUM_FD 1024
+
+/* Start a test server, return the TCP listening port bound to listen_fd.
+   listen_cb() is registered to be interested in reading from listen_fd.
+   When connection request arrives, listen_cb() is called to accept the
+   connection request. */
+static int server_start(server *sv) {
+  int port = 0;
+  int fd;
+  struct sockaddr_in sin;
+  socklen_t addr_len;
+
+  create_test_socket(port, &fd, &sin);
+  addr_len = sizeof(sin);
+  GPR_ASSERT(bind(fd, (struct sockaddr *)&sin, addr_len) == 0);
+  GPR_ASSERT(getsockname(fd, (struct sockaddr *)&sin, &addr_len) == GRPC_EM_OK);
+  port = ntohs(sin.sin_port);
+  GPR_ASSERT(listen(fd, MAX_NUM_FD) == 0);
+
+  GPR_ASSERT(grpc_em_fd_init(&sv->em_fd, &sv->em, fd) == GRPC_EM_OK);
+  /* Register to be interested in reading from listen_fd. */
+  GPR_ASSERT(grpc_em_fd_notify_on_read(&sv->em_fd, listen_cb, sv,
+                                       gpr_inf_future) == GRPC_EM_OK);
+
+  return port;
+}
+
+/* Wait and shutdown a sever. */
+static void server_wait_and_shutdown(server *sv) {
+  gpr_mu_lock(&sv->mu);
+  while (!sv->done) gpr_cv_wait(&sv->done_cv, &sv->mu, gpr_inf_future);
+  gpr_mu_unlock(&sv->mu);
+
+  gpr_mu_destroy(&sv->mu);
+  gpr_cv_destroy(&sv->done_cv);
+
+  GPR_ASSERT(grpc_em_destroy(&sv->em) == GRPC_EM_OK);
+}
+
+/* ===An upload client to test notify_on_write=== */
+
+/* Client write buffer size */
+#define CLIENT_WRITE_BUF_SIZE 10
+/* Total number of times that the client fills up the write buffer */
+#define CLIENT_TOTAL_WRITE_CNT 3
+
+/* An upload client. */
+typedef struct {
+  grpc_em em;
+  grpc_em_fd em_fd;
+  char write_buf[CLIENT_WRITE_BUF_SIZE];
+  ssize_t write_bytes_total;
+  /* Number of times that the client fills up the write buffer and calls
+     notify_on_write to schedule another write. */
+  int client_write_cnt;
+
+  gpr_mu mu;      /* protect done and done_cv */
+  gpr_cv done_cv; /* signaled when a client finishes sending */
+  int done;       /* set to 1 when a client finishes sending */
+} client;
+
+static void client_init(client *cl) {
+  GPR_ASSERT(grpc_em_init(&cl->em) == GRPC_EM_OK);
+  memset(cl->write_buf, 0, sizeof(cl->write_buf));
+  cl->write_bytes_total = 0;
+  cl->client_write_cnt = 0;
+  gpr_mu_init(&cl->mu);
+  gpr_cv_init(&cl->done_cv);
+  cl->done = 0;
+}
+
+/* Called when a client upload session is ready to shutdown. */
+static void client_session_shutdown_cb(void *arg /*client*/,
+                                       enum grpc_em_cb_status status) {
+  client *cl = arg;
+  grpc_em_fd_destroy(&cl->em_fd);
+  gpr_mu_lock(&cl->mu);
+  cl->done = 1;
+  gpr_cv_signal(&cl->done_cv);
+  gpr_mu_unlock(&cl->mu);
+}
+
+/* Write as much as possible, then register notify_on_write. */
+static void client_session_write(void *arg, /*client*/
+                                 enum grpc_em_cb_status status) {
+  client *cl = arg;
+  int fd = grpc_em_fd_get(&cl->em_fd);
+  ssize_t write_once = 0;
+
+  if (status == GRPC_CALLBACK_CANCELLED) {
+    client_session_shutdown_cb(arg, GRPC_CALLBACK_SUCCESS);
+    return;
+  }
+
+  do {
+    write_once = write(fd, cl->write_buf, CLIENT_WRITE_BUF_SIZE);
+    if (write_once > 0) cl->write_bytes_total += write_once;
+  } while (write_once > 0);
+
+  if (errno == EAGAIN) {
+    gpr_mu_lock(&cl->mu);
+    if (cl->client_write_cnt < CLIENT_TOTAL_WRITE_CNT) {
+      GPR_ASSERT(grpc_em_fd_notify_on_write(&cl->em_fd, client_session_write,
+                                            cl, gpr_inf_future) == GRPC_EM_OK);
+      cl->client_write_cnt++;
+    } else {
+      close(fd);
+      grpc_em_fd_shutdown(&cl->em_fd);
+      grpc_em_fd_notify_on_write(&cl->em_fd, client_session_write, cl,
+                                 gpr_inf_future);
+    }
+    gpr_mu_unlock(&cl->mu);
+  } else {
+    gpr_log(GPR_ERROR, "unknown errno %s", strerror(errno));
+    GPR_ASSERT(0);
+  }
+}
+
+/* Start a client to send a stream of bytes. */
+static void client_start(client *cl, int port) {
+  int fd;
+  struct sockaddr_in sin;
+  create_test_socket(port, &fd, &sin);
+  if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == -1 &&
+      errno != EINPROGRESS) {
+    gpr_log(GPR_ERROR, "Failed to connect to the server");
+    GPR_ASSERT(0);
+  }
+
+  GPR_ASSERT(grpc_em_fd_init(&cl->em_fd, &cl->em, fd) == GRPC_EM_OK);
+
+  client_session_write(cl, GRPC_CALLBACK_SUCCESS);
+}
+
+/* Wait for the signal to shutdown a client. */
+static void client_wait_and_shutdown(client *cl) {
+  gpr_mu_lock(&cl->mu);
+  while (!cl->done) gpr_cv_wait(&cl->done_cv, &cl->mu, gpr_inf_future);
+  gpr_mu_unlock(&cl->mu);
+
+  gpr_mu_destroy(&cl->mu);
+  gpr_cv_destroy(&cl->done_cv);
+
+  GPR_ASSERT(grpc_em_destroy(&cl->em) == GRPC_EM_OK);
+}
+
+/* Test grpc_em_fd. Start an upload server and client, upload a stream of
+   bytes from the client to the server, and verify that the total number of
+   sent bytes is equal to the total number of received bytes. */
+static void test_grpc_em_fd() {
+  server sv;
+  client cl;
+  int port;
+
+  server_init(&sv);
+  port = server_start(&sv);
+  client_init(&cl);
+  client_start(&cl, port);
+  client_wait_and_shutdown(&cl);
+  server_wait_and_shutdown(&sv);
+  GPR_ASSERT(sv.read_bytes_total == cl.write_bytes_total);
+  gpr_log(GPR_INFO, "Total read bytes %d", sv.read_bytes_total);
+}
+
+typedef struct fd_change_data {
+  gpr_mu mu;
+  gpr_cv cv;
+  void (*cb_that_ran)(void *, enum grpc_em_cb_status);
+} fd_change_data;
+
+void init_change_data(fd_change_data *fdc) {
+  gpr_mu_init(&fdc->mu);
+  gpr_cv_init(&fdc->cv);
+  fdc->cb_that_ran = NULL;
+}
+
+void destroy_change_data(fd_change_data *fdc) {
+  gpr_mu_destroy(&fdc->mu);
+  gpr_cv_destroy(&fdc->cv);
+}
+
+static void first_read_callback(void *arg /* fd_change_data */,
+                                enum grpc_em_cb_status status) {
+  fd_change_data *fdc = arg;
+
+  gpr_mu_lock(&fdc->mu);
+  fdc->cb_that_ran = first_read_callback;
+  gpr_cv_signal(&fdc->cv);
+  gpr_mu_unlock(&fdc->mu);
+}
+
+static void second_read_callback(void *arg /* fd_change_data */,
+                                 enum grpc_em_cb_status status) {
+  fd_change_data *fdc = arg;
+
+  gpr_mu_lock(&fdc->mu);
+  fdc->cb_that_ran = second_read_callback;
+  gpr_cv_signal(&fdc->cv);
+  gpr_mu_unlock(&fdc->mu);
+}
+
+/* Test that changing the callback we use for notify_on_read actually works.
+   Note that we have two different but almost identical callbacks above -- the
+   point is to have two different function pointers and two different data
+   pointers and make sure that changing both really works. */
+static void test_grpc_em_fd_change() {
+  grpc_em em;
+  grpc_em_fd em_fd;
+  fd_change_data a, b;
+  int flags;
+  int sv[2];
+  char data;
+  int result;
+
+  init_change_data(&a);
+  init_change_data(&b);
+
+  GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
+  flags = fcntl(sv[0], F_GETFL, 0);
+  GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0);
+  flags = fcntl(sv[1], F_GETFL, 0);
+  GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
+
+  grpc_em_init(&em);
+  grpc_em_fd_init(&em_fd, &em, sv[0]);
+
+  /* Register the first callback, then make its FD readable */
+  grpc_em_fd_notify_on_read(&em_fd, first_read_callback, &a, gpr_inf_future);
+  data = 0;
+  result = write(sv[1], &data, 1);
+  GPR_ASSERT(result == 1);
+
+  /* And now wait for it to run. */
+  gpr_mu_lock(&a.mu);
+  while (a.cb_that_ran == NULL) {
+    gpr_cv_wait(&a.cv, &a.mu, gpr_inf_future);
+  }
+  GPR_ASSERT(a.cb_that_ran == first_read_callback);
+  gpr_mu_unlock(&a.mu);
+
+  /* And drain the socket so we can generate a new read edge */
+  result = read(sv[0], &data, 1);
+  GPR_ASSERT(result == 1);
+
+  /* Now register a second callback with distinct change data, and do the same
+     thing again. */
+  grpc_em_fd_notify_on_read(&em_fd, second_read_callback, &b, gpr_inf_future);
+  data = 0;
+  result = write(sv[1], &data, 1);
+  GPR_ASSERT(result == 1);
+
+  gpr_mu_lock(&b.mu);
+  while (b.cb_that_ran == NULL) {
+    gpr_cv_wait(&b.cv, &b.mu, gpr_inf_future);
+  }
+  /* Except now we verify that second_read_callback ran instead */
+  GPR_ASSERT(b.cb_that_ran == second_read_callback);
+  gpr_mu_unlock(&b.mu);
+
+  grpc_em_fd_destroy(&em_fd);
+  grpc_em_destroy(&em);
+  destroy_change_data(&a);
+  destroy_change_data(&b);
+  close(sv[0]);
+  close(sv[1]);
+}
+
+void timeout_callback(void *arg, enum grpc_em_cb_status status) {
+  if (status == GRPC_CALLBACK_TIMED_OUT) {
+    gpr_event_set(arg, (void *)1);
+  } else {
+    gpr_event_set(arg, (void *)2);
+  }
+}
+
+void test_grpc_em_fd_notify_timeout() {
+  grpc_em em;
+  grpc_em_fd em_fd;
+  gpr_event ev;
+  int flags;
+  int sv[2];
+  gpr_timespec timeout;
+  gpr_timespec deadline;
+
+  gpr_event_init(&ev);
+
+  GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
+  flags = fcntl(sv[0], F_GETFL, 0);
+  GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0);
+  flags = fcntl(sv[1], F_GETFL, 0);
+  GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
+
+  grpc_em_init(&em);
+  grpc_em_fd_init(&em_fd, &em, sv[0]);
+
+  timeout = gpr_time_from_micros(1000000);
+  deadline = gpr_time_add(gpr_now(), timeout);
+
+  grpc_em_fd_notify_on_read(&em_fd, timeout_callback, &ev, deadline);
+
+  GPR_ASSERT(gpr_event_wait(&ev, gpr_time_add(deadline, timeout)));
+
+  GPR_ASSERT(gpr_event_get(&ev) == (void *)1);
+  grpc_em_fd_destroy(&em_fd);
+  grpc_em_destroy(&em);
+  close(sv[0]);
+  close(sv[1]);
+}
+
+typedef struct {
+  grpc_em *em;
+  gpr_cv cv;
+  gpr_mu mu;
+  int counter;
+  int done_success_ctr;
+  int done_cancel_ctr;
+  int done;
+  gpr_event fcb_arg;
+  grpc_em_cb_status status;
+} alarm_arg;
+
+static void followup_cb(void *arg, grpc_em_cb_status status) {
+  gpr_event_set((gpr_event *)arg, arg);
+}
+
+/* Called when an alarm expires. */
+static void alarm_cb(void *arg /* alarm_arg */, grpc_em_cb_status status) {
+  alarm_arg *a = arg;
+  gpr_mu_lock(&a->mu);
+  if (status == GRPC_CALLBACK_SUCCESS) {
+    a->counter++;
+    a->done_success_ctr++;
+  } else if (status == GRPC_CALLBACK_CANCELLED) {
+    a->done_cancel_ctr++;
+  } else {
+    GPR_ASSERT(0);
+  }
+  a->done = 1;
+  a->status = status;
+  gpr_cv_signal(&a->cv);
+  gpr_mu_unlock(&a->mu);
+  grpc_em_add_callback(a->em, followup_cb, &a->fcb_arg);
+}
+
+/* Test grpc_em_alarm add and cancel. */
+static void test_grpc_em_alarm() {
+  struct grpc_em em;
+  struct grpc_em_alarm alarm;
+  struct grpc_em_alarm alarm_to_cancel;
+  gpr_timespec tv0 = {0, 1};
+  /* Timeout on the alarm cond. var, so make big enough to absorb time
+     deviations. Otherwise, operations after wait will not be properly ordered
+   */
+  gpr_timespec tv1 = gpr_time_from_micros(200000);
+  gpr_timespec tv2 = {0, 1};
+  gpr_timespec alarm_deadline;
+  gpr_timespec followup_deadline;
+
+  alarm_arg *cancel_arg = NULL;
+  alarm_arg arg;
+  alarm_arg arg2;
+  void *fdone;
+
+  GPR_ASSERT(grpc_em_init(&em) == GRPC_EM_OK);
+
+  arg.em = &em;
+  arg.counter = 0;
+  arg.status = GRPC_CALLBACK_DO_NOT_USE;
+  arg.done_success_ctr = 0;
+  arg.done_cancel_ctr = 0;
+  arg.done = 0;
+  gpr_mu_init(&arg.mu);
+  gpr_cv_init(&arg.cv);
+  gpr_event_init(&arg.fcb_arg);
+
+  GPR_ASSERT(grpc_em_alarm_init(&alarm, &em, alarm_cb, &arg) == GRPC_EM_OK);
+  GPR_ASSERT(grpc_em_alarm_add(&alarm, gpr_time_add(tv0, gpr_now())) ==
+             GRPC_EM_OK);
+
+  alarm_deadline = gpr_time_add(gpr_now(), tv1);
+  gpr_mu_lock(&arg.mu);
+  while (arg.done == 0) {
+    gpr_cv_wait(&arg.cv, &arg.mu, alarm_deadline);
+  }
+  gpr_mu_unlock(&arg.mu);
+
+  followup_deadline = gpr_time_add(gpr_now(), tv1);
+  fdone = gpr_event_wait(&arg.fcb_arg, followup_deadline);
+
+  if (arg.counter != 1) {
+    gpr_log(GPR_ERROR, "Alarm callback not called");
+    GPR_ASSERT(0);
+  } else if (arg.done_success_ctr != 1) {
+    gpr_log(GPR_ERROR, "Alarm done callback not called with success");
+    GPR_ASSERT(0);
+  } else if (arg.done_cancel_ctr != 0) {
+    gpr_log(GPR_ERROR, "Alarm done callback called with cancel");
+    GPR_ASSERT(0);
+  } else if (arg.status == GRPC_CALLBACK_DO_NOT_USE) {
+    gpr_log(GPR_ERROR, "Alarm callback without status");
+    GPR_ASSERT(0);
+  } else {
+    gpr_log(GPR_INFO, "Alarm callback called successfully");
+  }
+
+  if (fdone != (void *)&arg.fcb_arg) {
+    gpr_log(GPR_ERROR, "Followup callback #1 not invoked properly %p %p", fdone,
+            &arg.fcb_arg);
+    GPR_ASSERT(0);
+  }
+  gpr_cv_destroy(&arg.cv);
+  gpr_mu_destroy(&arg.mu);
+
+  arg2.em = &em;
+  arg2.counter = 0;
+  arg2.status = GRPC_CALLBACK_DO_NOT_USE;
+  arg2.done_success_ctr = 0;
+  arg2.done_cancel_ctr = 0;
+  arg2.done = 0;
+  gpr_mu_init(&arg2.mu);
+  gpr_cv_init(&arg2.cv);
+  gpr_event_init(&arg2.fcb_arg);
+
+  GPR_ASSERT(grpc_em_alarm_init(&alarm_to_cancel, &em, alarm_cb, &arg2) ==
+             GRPC_EM_OK);
+  GPR_ASSERT(grpc_em_alarm_add(&alarm_to_cancel,
+                               gpr_time_add(tv2, gpr_now())) == GRPC_EM_OK);
+  switch (grpc_em_alarm_cancel(&alarm_to_cancel, (void **)&cancel_arg)) {
+    case GRPC_EM_OK:
+      gpr_log(GPR_INFO, "Alarm cancel succeeded");
+      break;
+    case GRPC_EM_ERROR:
+      gpr_log(GPR_ERROR, "Alarm cancel failed");
+      GPR_ASSERT(0);
+      break;
+    case GRPC_EM_INVALID_ARGUMENTS:
+      gpr_log(GPR_ERROR, "Alarm cancel failed with bad response code");
+      gpr_log(GPR_ERROR, "Current value of triggered is %d\n",
+              (int)alarm_to_cancel.triggered);
+      GPR_ASSERT(0);
+      break;
+  }
+
+  alarm_deadline = gpr_time_add(gpr_now(), tv1);
+  gpr_mu_lock(&arg2.mu);
+  while (arg2.done == 0) {
+    gpr_cv_wait(&arg2.cv, &arg2.mu, alarm_deadline);
+  }
+  gpr_mu_unlock(&arg2.mu);
+
+  followup_deadline = gpr_time_add(gpr_now(), tv1);
+  fdone = gpr_event_wait(&arg2.fcb_arg, followup_deadline);
+
+  if (arg2.counter != arg2.done_success_ctr) {
+    gpr_log(GPR_ERROR, "Alarm callback called but didn't lead to done success");
+    GPR_ASSERT(0);
+  } else if (arg2.done_success_ctr && arg2.done_cancel_ctr) {
+    gpr_log(GPR_ERROR, "Alarm done callback called with success and cancel");
+    GPR_ASSERT(0);
+  } else if (arg2.done_cancel_ctr + arg2.done_success_ctr != 1) {
+    gpr_log(GPR_ERROR, "Alarm done callback called incorrect number of times");
+    GPR_ASSERT(0);
+  } else if (arg2.status == GRPC_CALLBACK_DO_NOT_USE) {
+    gpr_log(GPR_ERROR, "Alarm callback without status");
+    GPR_ASSERT(0);
+  } else if (arg2.done_success_ctr) {
+    gpr_log(GPR_INFO, "Alarm callback executed before cancel");
+    gpr_log(GPR_INFO, "Current value of triggered is %d\n",
+            (int)alarm_to_cancel.triggered);
+  } else if (arg2.done_cancel_ctr) {
+    gpr_log(GPR_INFO, "Alarm callback canceled");
+    gpr_log(GPR_INFO, "Current value of triggered is %d\n",
+            (int)alarm_to_cancel.triggered);
+  } else {
+    gpr_log(GPR_ERROR, "Alarm cancel test should not be here");
+    GPR_ASSERT(0);
+  }
+
+  if (cancel_arg != &arg2) {
+    gpr_log(GPR_ERROR, "Alarm cancel arg address wrong");
+    GPR_ASSERT(0);
+  }
+  if (fdone != (void *)&arg2.fcb_arg) {
+    gpr_log(GPR_ERROR, "Followup callback #2 not invoked properly %p %p", fdone,
+            &arg2.fcb_arg);
+    GPR_ASSERT(0);
+  }
+  gpr_cv_destroy(&arg2.cv);
+  gpr_mu_destroy(&arg2.mu);
+
+  GPR_ASSERT(grpc_em_destroy(&em) == GRPC_EM_OK);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_grpc_em_alarm();
+  test_grpc_em_fd();
+  test_grpc_em_fd_change();
+  test_grpc_em_fd_notify_timeout();
+  return 0;
+}
diff --git a/test/core/fling/client.c b/test/core/fling/client.c
new file mode 100644
index 0000000..cc661c3
--- /dev/null
+++ b/test/core/fling/client.c
@@ -0,0 +1,196 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/cmdline.h>
+#include <grpc/support/histogram.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+#include "test/core/util/grpc_profiler.h"
+#include "test/core/util/test_config.h"
+
+static gpr_histogram *histogram;
+static grpc_byte_buffer *the_buffer;
+static grpc_channel *channel;
+static grpc_completion_queue *cq;
+static grpc_call *call;
+
+static void init_ping_pong_request() {}
+
+static void step_ping_pong_request() {
+  call = grpc_channel_create_call(channel, "/Reflector/reflectUnary",
+                                  "localhost", gpr_inf_future);
+  GPR_ASSERT(grpc_call_start_invoke(call, cq, (void *)1, (void *)1, (void *)1,
+                                    GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
+  grpc_event_finish(grpc_completion_queue_next(cq, gpr_inf_future));
+  GPR_ASSERT(grpc_call_start_write(call, the_buffer, (void *)1,
+                                   GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
+  grpc_event_finish(grpc_completion_queue_next(cq, gpr_inf_future));
+  GPR_ASSERT(grpc_call_start_read(call, (void *)1) == GRPC_CALL_OK);
+  GPR_ASSERT(grpc_call_writes_done(call, (void *)1) == GRPC_CALL_OK);
+  grpc_event_finish(grpc_completion_queue_next(cq, gpr_inf_future));
+  grpc_event_finish(grpc_completion_queue_next(cq, gpr_inf_future));
+  grpc_event_finish(grpc_completion_queue_next(cq, gpr_inf_future));
+  grpc_event_finish(grpc_completion_queue_next(cq, gpr_inf_future));
+  grpc_call_destroy(call);
+  call = NULL;
+}
+
+static void init_ping_pong_stream() {
+  call = grpc_channel_create_call(channel, "/Reflector/reflectStream",
+                                  "localhost", gpr_inf_future);
+  GPR_ASSERT(grpc_call_start_invoke(call, cq, (void *)1, (void *)1, (void *)1,
+                                    0) == GRPC_CALL_OK);
+  grpc_event_finish(grpc_completion_queue_next(cq, gpr_inf_future));
+  grpc_event_finish(grpc_completion_queue_next(cq, gpr_inf_future));
+}
+
+static void step_ping_pong_stream() {
+  GPR_ASSERT(grpc_call_start_write(call, the_buffer, (void *)1, 0) ==
+             GRPC_CALL_OK);
+  GPR_ASSERT(grpc_call_start_read(call, (void *)1) == GRPC_CALL_OK);
+  grpc_event_finish(grpc_completion_queue_next(cq, gpr_inf_future));
+  grpc_event_finish(grpc_completion_queue_next(cq, gpr_inf_future));
+}
+
+static double now() {
+  gpr_timespec tv = gpr_now();
+  return 1e9 * tv.tv_sec + tv.tv_nsec;
+}
+
+typedef struct {
+  const char *name;
+  void (*init)();
+  void (*do_one_step)();
+} scenario;
+
+static const scenario scenarios[] = {
+    {"ping-pong-request", init_ping_pong_request, step_ping_pong_request},
+    {"ping-pong-stream", init_ping_pong_stream, step_ping_pong_stream},
+};
+
+int main(int argc, char **argv) {
+  gpr_slice slice = gpr_slice_from_copied_string("x");
+  double start, stop;
+  int i;
+
+  char *fake_argv[1];
+
+  int payload_size = 1;
+  int done;
+  int secure = 0;
+  char *target = "localhost:443";
+  gpr_cmdline *cl;
+  char *scenario_name = "ping-pong-request";
+  scenario sc = {NULL};
+
+  GPR_ASSERT(argc >= 1);
+  fake_argv[0] = argv[0];
+  grpc_test_init(1, fake_argv);
+
+  grpc_init();
+
+  cl = gpr_cmdline_create("fling client");
+  gpr_cmdline_add_int(cl, "payload_size", "Size of the payload to send",
+                      &payload_size);
+  gpr_cmdline_add_string(cl, "target", "Target host:port", &target);
+  gpr_cmdline_add_flag(cl, "secure", "Run with security?", &secure);
+  gpr_cmdline_add_string(cl, "scenario", "Scenario", &scenario_name);
+  gpr_cmdline_parse(cl, argc, argv);
+  gpr_cmdline_destroy(cl);
+
+  for (i = 0; i < GPR_ARRAY_SIZE(scenarios); i++) {
+    if (0 == strcmp(scenarios[i].name, scenario_name)) {
+      sc = scenarios[i];
+    }
+  }
+  if (!sc.name) {
+    fprintf(stderr, "unsupported scenario '%s'. Valid are:", scenario_name);
+    for (i = 0; i < GPR_ARRAY_SIZE(scenarios); i++) {
+      fprintf(stderr, " %s", scenarios[i].name);
+    }
+    return 1;
+  }
+
+  channel = grpc_channel_create(target, NULL);
+  cq = grpc_completion_queue_create();
+  the_buffer = grpc_byte_buffer_create(&slice, payload_size);
+  histogram = gpr_histogram_create(0.01, 60e9);
+  sc.init();
+
+  for (i = 0; i < 1000; i++) {
+    sc.do_one_step();
+  }
+
+  gpr_log(GPR_INFO, "start profiling");
+  grpc_profiler_start("client.prof");
+  for (i = 0; i < 100000; i++) {
+    start = now();
+    sc.do_one_step();
+    stop = now();
+    gpr_histogram_add(histogram, stop - start);
+  }
+  grpc_profiler_stop();
+
+  if (call) {
+    grpc_call_destroy(call);
+  }
+
+  grpc_channel_destroy(channel);
+  grpc_completion_queue_shutdown(cq);
+  done = 0;
+  while (!done) {
+    grpc_event *ev = grpc_completion_queue_next(cq, gpr_inf_future);
+    done = (ev->type == GRPC_QUEUE_SHUTDOWN);
+    grpc_event_finish(ev);
+  }
+  grpc_completion_queue_destroy(cq);
+  grpc_byte_buffer_destroy(the_buffer);
+  gpr_slice_unref(slice);
+
+  gpr_log(GPR_INFO, "latency (50/95/99/99.9): %f/%f/%f/%f",
+          gpr_histogram_percentile(histogram, 50),
+          gpr_histogram_percentile(histogram, 95),
+          gpr_histogram_percentile(histogram, 99),
+          gpr_histogram_percentile(histogram, 99.9));
+  gpr_histogram_destroy(histogram);
+
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/fling/fling_stream_test.c b/test/core/fling/fling_stream_test.c
new file mode 100644
index 0000000..14a31eb
--- /dev/null
+++ b/test/core/fling/fling_stream_test.c
@@ -0,0 +1,103 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+#define _POSIX_SOURCE
+#include <unistd.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/string.h>
+#include "test/core/util/port.h"
+
+int main(int argc, char **argv) {
+  char *me = argv[0];
+  char *lslash = strrchr(me, '/');
+  char root[1024];
+  int port = grpc_pick_unused_port_or_die();
+  char *args[10];
+  int status;
+  pid_t svr, cli;
+  /* figure out where we are */
+  if (lslash) {
+    memcpy(root, me, lslash - me);
+    root[lslash - me] = 0;
+  } else {
+    strcpy(root, ".");
+  }
+  /* start the server */
+  svr = fork();
+  if (svr == 0) {
+    gpr_asprintf(&args[0], "%s/fling_server", root);
+    args[1] = "--bind";
+    gpr_join_host_port(&args[2], "::", port);
+    args[3] = "--no-secure";
+    args[4] = 0;
+    execv(args[0], args);
+
+    gpr_free(args[0]);
+    gpr_free(args[2]);
+    return 1;
+  }
+  /* wait a little */
+  sleep(2);
+  /* start the client */
+  cli = fork();
+  if (cli == 0) {
+    gpr_asprintf(&args[0], "%s/fling_client", root);
+    args[1] = "--target";
+    gpr_join_host_port(&args[2], "127.0.0.1", port);
+    args[3] = "--scenario=ping-pong-stream";
+    args[4] = "--no-secure";
+    args[5] = 0;
+    execv(args[0], args);
+
+    gpr_free(args[0]);
+    gpr_free(args[2]);
+    return 1;
+  }
+  /* wait for completion */
+  printf("waiting for client\n");
+  if (waitpid(cli, &status, 0) == -1) return 2;
+  if (!WIFEXITED(status)) return 4;
+  if (WEXITSTATUS(status)) return WEXITSTATUS(status);
+  printf("checking server\n");
+  if (waitpid(svr, &status, WNOHANG) != 0) return 2;
+  kill(svr, SIGKILL);
+  return 0;
+}
diff --git a/test/core/fling/fling_test.c b/test/core/fling/fling_test.c
new file mode 100644
index 0000000..e5e63f9
--- /dev/null
+++ b/test/core/fling/fling_test.c
@@ -0,0 +1,103 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+#define _POSIX_SOURCE
+#include <unistd.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/string.h>
+#include "test/core/util/port.h"
+
+int main(int argc, char **argv) {
+  char *me = argv[0];
+  char *lslash = strrchr(me, '/');
+  char root[1024];
+  int port = grpc_pick_unused_port_or_die();
+  char *args[10];
+  int status;
+  pid_t svr, cli;
+  /* figure out where we are */
+  if (lslash) {
+    memcpy(root, me, lslash - me);
+    root[lslash - me] = 0;
+  } else {
+    strcpy(root, ".");
+  }
+  /* start the server */
+  svr = fork();
+  if (svr == 0) {
+    gpr_asprintf(&args[0], "%s/fling_server", root);
+    args[1] = "--bind";
+    gpr_join_host_port(&args[2], "::", port);
+    args[3] = "--no-secure";
+    args[4] = 0;
+    execv(args[0], args);
+
+    gpr_free(args[0]);
+    gpr_free(args[2]);
+    return 1;
+  }
+  /* wait a little */
+  sleep(2);
+  /* start the client */
+  cli = fork();
+  if (cli == 0) {
+    gpr_asprintf(&args[0], "%s/fling_client", root);
+    args[1] = "--target";
+    gpr_join_host_port(&args[2], "127.0.0.1", port);
+    args[3] = "--scenario=ping-pong-request";
+    args[4] = "--no-secure";
+    args[5] = 0;
+    execv(args[0], args);
+
+    gpr_free(args[0]);
+    gpr_free(args[2]);
+    return 1;
+  }
+  /* wait for completion */
+  printf("waiting for client\n");
+  if (waitpid(cli, &status, 0) == -1) return 2;
+  if (!WIFEXITED(status)) return 4;
+  if (WEXITSTATUS(status)) return WEXITSTATUS(status);
+  printf("checking server\n");
+  if (waitpid(svr, &status, WNOHANG) != 0) return 2;
+  kill(svr, SIGKILL);
+  return 0;
+}
diff --git a/test/core/fling/server.c b/test/core/fling/server.c
new file mode 100644
index 0000000..7a5d895
--- /dev/null
+++ b/test/core/fling/server.c
@@ -0,0 +1,159 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "test/core/util/grpc_profiler.h"
+#include "test/core/util/test_config.h"
+#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 "test/core/util/port.h"
+
+static grpc_completion_queue *cq;
+static grpc_server *server;
+static int done = 0;
+
+static const grpc_status status_ok = {GRPC_STATUS_OK, NULL};
+
+typedef struct {
+  gpr_refcount pending_ops;
+  gpr_uint32 flags;
+} call_state;
+
+static void request_call() {
+  call_state *s = gpr_malloc(sizeof(call_state));
+  gpr_ref_init(&s->pending_ops, 2);
+  grpc_server_request_call(server, s);
+}
+
+static void sigint_handler(int x) { done = 1; }
+
+int main(int argc, char **argv) {
+  grpc_event *ev;
+  call_state *s;
+  char *addr_buf = NULL;
+  gpr_cmdline *cl;
+
+  int secure = 0;
+  char *addr = NULL;
+
+  char *fake_argv[1];
+
+  GPR_ASSERT(argc >= 1);
+  fake_argv[0] = argv[0];
+  grpc_test_init(1, fake_argv);
+
+  grpc_init();
+  srand(clock());
+
+  cl = gpr_cmdline_create("fling server");
+  gpr_cmdline_add_string(cl, "bind", "Bind host:port", &addr);
+  gpr_cmdline_add_flag(cl, "secure", "Run with security?", &secure);
+  gpr_cmdline_parse(cl, argc, argv);
+  gpr_cmdline_destroy(cl);
+
+  if (addr == NULL) {
+    gpr_join_host_port(&addr_buf, "::", grpc_pick_unused_port_or_die());
+    addr = addr_buf;
+  }
+  gpr_log(GPR_INFO, "creating server on: %s", addr);
+
+  cq = grpc_completion_queue_create();
+  server = grpc_server_create(cq, NULL);
+  GPR_ASSERT(grpc_server_add_http2_port(server, addr));
+  grpc_server_start(server);
+
+  gpr_free(addr_buf);
+  addr = addr_buf = NULL;
+
+  request_call();
+
+  grpc_profiler_start("server.prof");
+  signal(SIGINT, sigint_handler);
+  while (!done) {
+    ev = grpc_completion_queue_next(
+        cq, gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)));
+    if (!ev) continue;
+    s = ev->tag;
+    switch (ev->type) {
+      case GRPC_SERVER_RPC_NEW:
+        /* initial ops are already started in request_call */
+        if (0 == strcmp(ev->data.server_rpc_new.method,
+                        "/Reflector/reflectStream")) {
+          s->flags = 0;
+        } else {
+          s->flags = GRPC_WRITE_BUFFER_HINT;
+        }
+        grpc_call_accept(ev->call, cq, s, s->flags);
+        GPR_ASSERT(grpc_call_start_read(ev->call, s) == GRPC_CALL_OK);
+        request_call();
+        break;
+      case GRPC_WRITE_ACCEPTED:
+        GPR_ASSERT(ev->data.write_accepted == GRPC_OP_OK);
+        GPR_ASSERT(grpc_call_start_read(ev->call, s) == GRPC_CALL_OK);
+        break;
+      case GRPC_READ:
+        if (ev->data.read) {
+          GPR_ASSERT(grpc_call_start_write(ev->call, ev->data.read, s,
+                                           s->flags) == GRPC_CALL_OK);
+        } else {
+          GPR_ASSERT(grpc_call_start_write_status(ev->call, status_ok, s) ==
+                     GRPC_CALL_OK);
+        }
+        break;
+      case GRPC_FINISH_ACCEPTED:
+      case GRPC_FINISHED:
+        if (gpr_unref(&s->pending_ops)) {
+          grpc_call_destroy(ev->call);
+          gpr_free(s);
+        }
+        break;
+      default:
+        abort();
+    }
+    grpc_event_finish(ev);
+  }
+  grpc_profiler_stop();
+
+  grpc_shutdown();
+  return 0;
+}
diff --git a/test/core/httpcli/format_request_test.c b/test/core/httpcli/format_request_test.c
new file mode 100644
index 0000000..12ea7fd
--- /dev/null
+++ b/test/core/httpcli/format_request_test.c
@@ -0,0 +1,166 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/httpcli/format_request.h"
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+static void test_format_get_request() {
+  grpc_httpcli_header hdr = {"x-yz", "abc"};
+  grpc_httpcli_request req;
+  gpr_slice slice;
+
+
+  memset(&req, 0, sizeof(req));
+  req.host = "example.com";
+  req.path = "/index.html";
+  req.hdr_count = 1;
+  req.hdrs = &hdr;
+
+  slice = grpc_httpcli_format_get_request(&req);
+
+  GPR_ASSERT(0 == gpr_slice_str_cmp(slice,
+                                    "GET /index.html HTTP/1.0\r\n"
+                                    "Host: example.com\r\n"
+                                    "Connection: close\r\n"
+                                    "User-Agent: " GRPC_HTTPCLI_USER_AGENT
+                                    "\r\n"
+                                    "x-yz: abc\r\n"
+                                    "\r\n"));
+
+  gpr_slice_unref(slice);
+}
+
+static void test_format_post_request() {
+  grpc_httpcli_header hdr = {"x-yz", "abc"};
+  grpc_httpcli_request req;
+  gpr_slice slice;
+  char body_bytes[] = "fake body";
+  size_t body_len = 9;
+
+  memset(&req, 0, sizeof(req));
+  req.host = "example.com";
+  req.path = "/index.html";
+  req.hdr_count = 1;
+  req.hdrs = &hdr;
+
+  slice = grpc_httpcli_format_post_request(&req, body_bytes, body_len);
+
+  GPR_ASSERT(0 == gpr_slice_str_cmp(slice,
+                                    "POST /index.html HTTP/1.0\r\n"
+                                    "Host: example.com\r\n"
+                                    "Connection: close\r\n"
+                                    "User-Agent: " GRPC_HTTPCLI_USER_AGENT
+                                    "\r\n"
+                                    "x-yz: abc\r\n"
+                                    "Content-Type: text/plain\r\n"
+                                    "Content-Length: 9\r\n"
+                                    "\r\n"
+                                    "fake body"));
+
+  gpr_slice_unref(slice);
+}
+
+static void test_format_post_request_no_body() {
+  grpc_httpcli_header hdr = {"x-yz", "abc"};
+  grpc_httpcli_request req;
+  gpr_slice slice;
+
+  memset(&req, 0, sizeof(req));
+  req.host = "example.com";
+  req.path = "/index.html";
+  req.hdr_count = 1;
+  req.hdrs = &hdr;
+
+  slice = grpc_httpcli_format_post_request(&req, NULL, 0);
+
+  GPR_ASSERT(0 == gpr_slice_str_cmp(slice,
+                                    "POST /index.html HTTP/1.0\r\n"
+                                    "Host: example.com\r\n"
+                                    "Connection: close\r\n"
+                                    "User-Agent: " GRPC_HTTPCLI_USER_AGENT
+                                    "\r\n"
+                                    "x-yz: abc\r\n"
+                                    "\r\n"));
+
+  gpr_slice_unref(slice);
+}
+
+static void test_format_post_request_content_type_override() {
+  grpc_httpcli_header hdrs[2];
+  grpc_httpcli_request req;
+  gpr_slice slice;
+  char body_bytes[] = "fake%20body";
+  size_t body_len = 11;
+
+  hdrs[0].key = "x-yz";
+  hdrs[0].value = "abc";
+  hdrs[1].key = "Content-Type";
+  hdrs[1].value = "application/x-www-form-urlencoded";
+  memset(&req, 0, sizeof(req));
+  req.host = "example.com";
+  req.path = "/index.html";
+  req.hdr_count = 2;
+  req.hdrs = hdrs;
+
+  slice = grpc_httpcli_format_post_request(&req, body_bytes, body_len);
+
+  GPR_ASSERT(0 == gpr_slice_str_cmp(
+                      slice,
+                      "POST /index.html HTTP/1.0\r\n"
+                      "Host: example.com\r\n"
+                      "Connection: close\r\n"
+                      "User-Agent: " GRPC_HTTPCLI_USER_AGENT
+                      "\r\n"
+                      "x-yz: abc\r\n"
+                      "Content-Type: application/x-www-form-urlencoded\r\n"
+                      "Content-Length: 11\r\n"
+                      "\r\n"
+                      "fake%20body"));
+
+  gpr_slice_unref(slice);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+
+  test_format_get_request();
+  test_format_post_request();
+  test_format_post_request_no_body();
+  test_format_post_request_content_type_override();
+
+  return 0;
+}
diff --git a/test/core/httpcli/httpcli_test.c b/test/core/httpcli/httpcli_test.c
new file mode 100644
index 0000000..5c0d87c
--- /dev/null
+++ b/test/core/httpcli/httpcli_test.c
@@ -0,0 +1,101 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/httpcli/httpcli.h"
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+static gpr_event g_done;
+static grpc_em g_em;
+
+static gpr_timespec n_seconds_time(int seconds) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(seconds * 1000000));
+}
+
+static void on_finish(void *arg, const grpc_httpcli_response *response) {
+  GPR_ASSERT(arg == (void *)42);
+  GPR_ASSERT(response);
+  GPR_ASSERT(response->status == 200);
+  gpr_event_set(&g_done, (void *)1);
+}
+
+static void test_get(int use_ssl) {
+  grpc_httpcli_request req;
+
+  gpr_log(GPR_INFO, "running %s with use_ssl=%d.", __FUNCTION__, (int)use_ssl);
+
+  gpr_event_init(&g_done);
+  memset(&req, 0, sizeof(req));
+  req.host = "www.google.com";
+  req.path = "/";
+  req.use_ssl = use_ssl;
+
+  grpc_httpcli_get(&req, n_seconds_time(15), &g_em, on_finish, (void *)42);
+  GPR_ASSERT(gpr_event_wait(&g_done, n_seconds_time(20)));
+}
+
+/*
+static void test_post(int use_ssl) {
+  grpc_httpcli_request req;
+
+  gpr_log(GPR_INFO, "running %s with use_ssl=%d.", __FUNCTION__, (int)use_ssl);
+
+  gpr_event_init(&g_done);
+  memset(&req, 0, sizeof(req));
+  req.host = "requestb.in";
+  req.path = "/1eamwr21";
+  req.use_ssl = use_ssl;
+
+  grpc_httpcli_post(&req, NULL, 0, n_seconds_time(15), &g_em, on_finish,
+                    (void *)42);
+  GPR_ASSERT(gpr_event_wait(&g_done, n_seconds_time(20)));
+}
+*/
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  grpc_em_init(&g_em);
+
+  test_get(0);
+  test_get(1);
+
+  /* test_post(0); */
+  /* test_post(1); */
+
+  grpc_em_destroy(&g_em);
+
+  return 0;
+}
diff --git a/test/core/httpcli/parser_test.c b/test/core/httpcli/parser_test.c
new file mode 100644
index 0000000..455f6a6
--- /dev/null
+++ b/test/core/httpcli/parser_test.c
@@ -0,0 +1,155 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/httpcli/parser.h"
+
+#include <stdarg.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+#include "test/core/util/slice_splitter.h"
+#include "test/core/util/test_config.h"
+
+static void test_succeeds(grpc_slice_split_mode split_mode, char *response,
+                          int expect_status, char *expect_body, ...) {
+  grpc_httpcli_parser parser;
+  gpr_slice input_slice = gpr_slice_from_copied_string(response);
+  size_t num_slices;
+  size_t i;
+  gpr_slice *slices;
+  va_list args;
+
+  grpc_split_slices(split_mode, &input_slice, 1, &slices, &num_slices);
+  gpr_slice_unref(input_slice);
+
+  grpc_httpcli_parser_init(&parser);
+
+  for (i = 0; i < num_slices; i++) {
+    GPR_ASSERT(grpc_httpcli_parser_parse(&parser, slices[i]));
+    gpr_slice_unref(slices[i]);
+  }
+  GPR_ASSERT(grpc_httpcli_parser_eof(&parser));
+
+  GPR_ASSERT(expect_status == parser.r.status);
+  if (expect_body != NULL) {
+    GPR_ASSERT(strlen(expect_body) == parser.r.body_length);
+    GPR_ASSERT(0 == memcmp(expect_body, parser.r.body, parser.r.body_length));
+  } else {
+    GPR_ASSERT(parser.r.body_length == 0);
+  }
+
+  va_start(args, expect_body);
+  i = 0;
+  for (;;) {
+    char *expect_key;
+    char *expect_value;
+    expect_key = va_arg(args, char *);
+    if (!expect_key) break;
+    GPR_ASSERT(i < parser.r.hdr_count);
+    expect_value = va_arg(args, char *);
+    GPR_ASSERT(expect_value);
+    GPR_ASSERT(0 == strcmp(expect_key, parser.r.hdrs[i].key));
+    GPR_ASSERT(0 == strcmp(expect_value, parser.r.hdrs[i].value));
+    i++;
+  }
+  va_end(args);
+  GPR_ASSERT(i == parser.r.hdr_count);
+
+  grpc_httpcli_parser_destroy(&parser);
+  gpr_free(slices);
+}
+
+static void test_fails(grpc_slice_split_mode split_mode, char *response) {
+  grpc_httpcli_parser parser;
+  gpr_slice input_slice = gpr_slice_from_copied_string(response);
+  size_t num_slices;
+  size_t i;
+  gpr_slice *slices;
+  int done = 0;
+
+  grpc_split_slices(split_mode, &input_slice, 1, &slices, &num_slices);
+  gpr_slice_unref(input_slice);
+
+  grpc_httpcli_parser_init(&parser);
+
+  for (i = 0; i < num_slices; i++) {
+    if (!done && !grpc_httpcli_parser_parse(&parser, slices[i])) {
+      done = 1;
+    }
+    gpr_slice_unref(slices[i]);
+  }
+  if (!done && !grpc_httpcli_parser_eof(&parser)) {
+    done = 1;
+  }
+  GPR_ASSERT(done);
+
+  grpc_httpcli_parser_destroy(&parser);
+  gpr_free(slices);
+}
+
+int main(int argc, char **argv) {
+  size_t i;
+  const grpc_slice_split_mode split_modes[] = {GRPC_SLICE_SPLIT_IDENTITY,
+                                               GRPC_SLICE_SPLIT_ONE_BYTE};
+
+  grpc_test_init(argc, argv);
+
+  for (i = 0; i < GPR_ARRAY_SIZE(split_modes); i++) {
+    test_succeeds(split_modes[i],
+                  "HTTP/1.0 200 OK\r\n"
+                  "xyz: abc\r\n"
+                  "\r\n"
+                  "hello world!",
+                  200, "hello world!", "xyz", "abc", NULL);
+    test_succeeds(split_modes[i],
+                  "HTTP/1.0 404 Not Found\r\n"
+                  "\r\n",
+                  404, NULL, NULL);
+    test_succeeds(split_modes[i],
+                  "HTTP/1.1 200 OK\r\n"
+                  "xyz: abc\r\n"
+                  "\r\n"
+                  "hello world!",
+                  200, "hello world!", "xyz", "abc", NULL);
+    test_fails(split_modes[i], "HTTP/1.0\r\n");
+    test_fails(split_modes[i], "HTTP/1.2\r\n");
+    test_fails(split_modes[i], "HTTP/1.0 000 XYX\r\n");
+    test_fails(split_modes[i], "HTTP/1.0 200 OK\n");
+    test_fails(split_modes[i], "HTTP/1.0 200 OK\r\n");
+    test_fails(split_modes[i], "HTTP/1.0 200 OK\r\nFoo x\r\n");
+  }
+
+  return 0;
+}
diff --git a/test/core/network_benchmarks/low_level_ping_pong.c b/test/core/network_benchmarks/low_level_ping_pong.c
new file mode 100644
index 0000000..93c66a9
--- /dev/null
+++ b/test/core/network_benchmarks/low_level_ping_pong.c
@@ -0,0 +1,626 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/*
+   Basic I/O ping-pong benchmarks.
+
+   The goal here is to establish lower bounds on how fast the stack could get by
+   measuring the cost of using various I/O strategies to do a basic
+   request-response loop.
+ */
+
+#include <errno.h>
+#include <netinet/ip.h>
+#include <poll.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef __linux__
+#include <sys/epoll.h>
+#endif
+#include <sys/socket.h>
+
+#include "src/core/endpoint/socket_utils.h"
+#include <grpc/support/cmdline.h>
+#include <grpc/support/histogram.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+
+typedef struct fd_pair {
+  int read_fd;
+  int write_fd;
+} fd_pair;
+
+typedef struct thread_args {
+  fd_pair fds;
+  size_t msg_size;
+  int (*read_bytes)(struct thread_args *args, char *buf);
+  int (*write_bytes)(struct thread_args *args, char *buf);
+  int (*setup)(struct thread_args *args);
+  int epoll_fd;
+} thread_args;
+
+/*
+   Read strategies
+
+   There are a number of read strategies, each of which has a blocking and
+   non-blocking version.
+ */
+
+/* Basic call to read() */
+static int read_bytes(int fd, char *buf, size_t read_size, int spin) {
+  int bytes_read = 0;
+  int err;
+  do {
+    err = read(fd, buf + bytes_read, read_size - bytes_read);
+    if (err < 0) {
+      if (errno == EINTR) {
+        continue;
+      } else {
+        if (errno == EAGAIN && spin == 1) {
+          continue;
+        }
+        gpr_log(GPR_ERROR, "Read failed: %s", strerror(errno));
+        return -1;
+      }
+    } else {
+      bytes_read += err;
+    }
+  } while (bytes_read < read_size);
+  return 0;
+}
+
+static int blocking_read_bytes(thread_args *args, char *buf) {
+  return read_bytes(args->fds.read_fd, buf, args->msg_size, 0);
+}
+
+static int spin_read_bytes(thread_args *args, char *buf) {
+  return read_bytes(args->fds.read_fd, buf, args->msg_size, 1);
+}
+
+/* Call poll() to monitor a non-blocking fd */
+static int poll_read_bytes(int fd, char *buf, size_t read_size, int spin) {
+  struct pollfd pfd;
+  size_t bytes_read = 0;
+  int err;
+
+  pfd.fd = fd;
+  pfd.events = POLLIN;
+  do {
+    err = poll(&pfd, 1, spin ? 0 : -1);
+    if (err < 0) {
+      if (errno == EINTR) {
+        continue;
+      } else {
+        gpr_log(GPR_ERROR, "Poll failed: %s", strerror(errno));
+        return -1;
+      }
+    }
+    if (err == 0 && spin) continue;
+    GPR_ASSERT(err == 1);
+    GPR_ASSERT(pfd.revents == POLLIN);
+    do {
+      err = read(fd, buf + bytes_read, read_size - bytes_read);
+    } while (err < 0 && errno == EINTR);
+    if (err < 0 && errno != EAGAIN) {
+      gpr_log(GPR_ERROR, "Read failed: %s", strerror(errno));
+      return -1;
+    }
+    bytes_read += err;
+  } while (bytes_read < read_size);
+  return 0;
+}
+
+static int poll_read_bytes_blocking(struct thread_args *args, char *buf) {
+  return poll_read_bytes(args->fds.read_fd, buf, args->msg_size, 0);
+}
+
+static int poll_read_bytes_spin(struct thread_args *args, char *buf) {
+  return poll_read_bytes(args->fds.read_fd, buf, args->msg_size, 1);
+}
+
+#ifdef __linux__
+/* Call epoll_wait() to monitor a non-blocking fd */
+static int epoll_read_bytes(struct thread_args *args, char *buf, int spin) {
+  struct epoll_event ev;
+  size_t bytes_read = 0;
+  int err;
+  size_t read_size = args->msg_size;
+
+  do {
+    err = epoll_wait(args->epoll_fd, &ev, 1, spin ? 0 : -1);
+    if (err < 0) {
+      if (errno == EINTR) continue;
+      gpr_log(GPR_ERROR, "epoll_wait failed: %s", strerror(errno));
+      return -1;
+    }
+    if (err == 0 && spin) continue;
+    GPR_ASSERT(err == 1);
+    GPR_ASSERT(ev.events & EPOLLIN);
+    GPR_ASSERT(ev.data.fd == args->fds.read_fd);
+    do {
+      do {
+        err = read(args->fds.read_fd, buf + bytes_read, read_size - bytes_read);
+      } while (err < 0 && errno == EINTR);
+      if (errno == EAGAIN) break;
+      bytes_read += err;
+      /* 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);
+  } while (bytes_read < read_size);
+  GPR_ASSERT(bytes_read == read_size);
+  return 0;
+}
+
+static int epoll_read_bytes_blocking(struct thread_args *args, char *buf) {
+  return epoll_read_bytes(args, buf, 0);
+}
+
+static int epoll_read_bytes_spin(struct thread_args *args, char *buf) {
+  return epoll_read_bytes(args, buf, 1);
+}
+#endif /* __linux__ */
+
+/* Write out bytes.
+   At this point we only have one strategy, since in the common case these
+   writes go directly out to the kernel.
+ */
+static int blocking_write_bytes(struct thread_args *args, char *buf) {
+  int bytes_written = 0;
+  int err;
+  size_t write_size = args->msg_size;
+  do {
+    err = write(args->fds.write_fd, buf + bytes_written,
+                write_size - bytes_written);
+    if (err < 0) {
+      if (errno == EINTR) {
+        continue;
+      } else {
+        gpr_log(GPR_ERROR, "Read failed: %s", strerror(errno));
+        return -1;
+      }
+    } else {
+      bytes_written += err;
+    }
+  } while (bytes_written < write_size);
+  return 0;
+}
+
+/*
+   Initialization code
+
+   These are called at the beginning of the client and server thread, depending
+   on the scenario we're using.
+ */
+static int set_socket_nonblocking(thread_args *args) {
+  if (!grpc_set_socket_nonblocking(args->fds.read_fd, 1)) {
+    gpr_log(GPR_ERROR, "Unable to set socket nonblocking: %s", strerror(errno));
+    return -1;
+  }
+  if (!grpc_set_socket_nonblocking(args->fds.write_fd, 1)) {
+    gpr_log(GPR_ERROR, "Unable to set socket nonblocking: %s", strerror(errno));
+    return -1;
+  }
+  return 0;
+}
+
+static int do_nothing(thread_args *args) { return 0; }
+
+/* Special case for epoll, where we need to create the fd ahead of time. */
+static int epoll_setup(thread_args *args) {
+  int epoll_fd;
+  struct epoll_event ev;
+  set_socket_nonblocking(args);
+  epoll_fd = epoll_create(1);
+  if (epoll_fd < 0) {
+    gpr_log(GPR_ERROR, "epoll_create: %s", strerror(errno));
+    return -1;
+  }
+
+  args->epoll_fd = epoll_fd;
+
+  ev.events = EPOLLIN | EPOLLET;
+  ev.data.fd = args->fds.read_fd;
+  if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, args->fds.read_fd, &ev) < 0) {
+    gpr_log(GPR_ERROR, "epoll_ctl: %s", strerror(errno));
+  }
+  return 0;
+}
+
+static void server_thread(thread_args *args) {
+  char *buf = malloc(args->msg_size);
+  if (args->setup(args) < 0) {
+    gpr_log(GPR_ERROR, "Setup failed");
+  }
+  for (;;) {
+    if (args->read_bytes(args, buf) < 0) {
+      gpr_log(GPR_ERROR, "Server read failed");
+      free(buf);
+      return;
+    }
+    if (args->write_bytes(args, buf) < 0) {
+      gpr_log(GPR_ERROR, "Server write failed");
+      free(buf);
+      return;
+    }
+  }
+}
+
+static void server_thread_wrap(void *arg) {
+  thread_args *args = arg;
+  server_thread(args);
+}
+
+static void print_histogram(gpr_histogram *histogram) {
+  /* TODO(klempner): Print more detailed information, such as detailed histogram
+     buckets */
+  gpr_log(GPR_INFO, "latency (50/95/99/99.9): %f/%f/%f/%f",
+          gpr_histogram_percentile(histogram, 50),
+          gpr_histogram_percentile(histogram, 95),
+          gpr_histogram_percentile(histogram, 99),
+          gpr_histogram_percentile(histogram, 99.9));
+}
+
+static double now() {
+  gpr_timespec tv = gpr_now();
+  return 1e9 * tv.tv_sec + tv.tv_nsec;
+}
+
+static void client_thread(thread_args *args) {
+  char *buf = calloc(args->msg_size, sizeof(char));
+  gpr_histogram *histogram = gpr_histogram_create(0.01, 60e9);
+  double start_time;
+  double end_time;
+  double interval;
+  const int kNumIters = 100000;
+  int i;
+
+  if (args->setup(args) < 0) {
+    gpr_log(GPR_ERROR, "Setup failed");
+  }
+  for (i = 0; i < kNumIters; ++i) {
+    start_time = now();
+    if (args->write_bytes(args, buf) < 0) {
+      gpr_log(GPR_ERROR, "Client write failed");
+      goto error;
+    }
+    if (args->read_bytes(args, buf) < 0) {
+      gpr_log(GPR_ERROR, "Client read failed");
+      goto error;
+    }
+    end_time = now();
+    if (i > kNumIters / 2) {
+      interval = end_time - start_time;
+      gpr_histogram_add(histogram, interval);
+    }
+  }
+  print_histogram(histogram);
+error:
+  free(buf);
+  gpr_histogram_destroy(histogram);
+}
+
+/* This roughly matches tcp_server's create_listening_socket */
+static int create_listening_socket(struct sockaddr *port, socklen_t len) {
+  int fd = socket(port->sa_family, SOCK_STREAM, 0);
+  if (fd < 0) {
+    gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
+    goto error;
+  }
+
+  if (!grpc_set_socket_cloexec(fd, 1) || !grpc_set_socket_low_latency(fd, 1) ||
+      !grpc_set_socket_reuse_addr(fd, 1)) {
+    gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
+            strerror(errno));
+    goto error;
+  }
+
+  if (bind(fd, port, len) < 0) {
+    gpr_log(GPR_ERROR, "bind: %s", strerror(errno));
+    goto error;
+  }
+
+  if (listen(fd, 1) < 0) {
+    gpr_log(GPR_ERROR, "listen: %s", strerror(errno));
+    goto error;
+  }
+
+  if (getsockname(fd, port, &len) < 0) {
+    gpr_log(GPR_ERROR, "getsockname: %s", strerror(errno));
+    goto error;
+  }
+
+  return fd;
+
+error:
+  if (fd >= 0) {
+    close(fd);
+  }
+  return -1;
+}
+
+static int connect_client(struct sockaddr *addr, int len) {
+  int fd = socket(addr->sa_family, SOCK_STREAM, 0);
+  int err;
+  if (fd < 0) {
+    gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
+    goto error;
+  }
+
+  if (!grpc_set_socket_cloexec(fd, 1) || !grpc_set_socket_low_latency(fd, 1)) {
+    gpr_log(GPR_ERROR, "Failed to configure socket");
+    goto error;
+  }
+
+  do {
+    err = connect(fd, addr, len);
+  } while (err < 0 && errno == EINTR);
+
+  if (err < 0) {
+    gpr_log(GPR_ERROR, "connect error: %s", strerror(errno));
+    goto error;
+  }
+  return fd;
+
+error:
+  if (fd >= 0) {
+    close(fd);
+  }
+  return -1;
+}
+
+static int accept_server(int listen_fd) {
+  int fd = accept(listen_fd, NULL, NULL);
+  if (fd < 0) {
+    gpr_log(GPR_ERROR, "Accept failed: %s", strerror(errno));
+    return -1;
+  }
+  return fd;
+}
+
+static int create_sockets_tcp(fd_pair *client_fds, fd_pair *server_fds) {
+  int listen_fd = -1;
+  int client_fd = -1;
+  int server_fd = -1;
+
+  struct sockaddr_in port;
+  struct sockaddr *sa_port = (struct sockaddr *)&port;
+
+  port.sin_family = AF_INET;
+  port.sin_port = 0;
+  port.sin_addr.s_addr = INADDR_ANY;
+
+  listen_fd = create_listening_socket(sa_port, sizeof(port));
+  if (listen_fd == -1) {
+    gpr_log(GPR_ERROR, "Listen failed");
+    goto error;
+  }
+
+  client_fd = connect_client(sa_port, sizeof(port));
+  if (client_fd == -1) {
+    gpr_log(GPR_ERROR, "Connect failed");
+    goto error;
+  }
+
+  server_fd = accept_server(listen_fd);
+  if (server_fd == -1) {
+    gpr_log(GPR_ERROR, "Accept failed");
+    goto error;
+  }
+
+  client_fds->read_fd = client_fd;
+  client_fds->write_fd = client_fd;
+  server_fds->read_fd = server_fd;
+  server_fds->write_fd = server_fd;
+  close(listen_fd);
+  return 0;
+
+error:
+  if (listen_fd != -1) {
+    close(listen_fd);
+  }
+  if (client_fd != -1) {
+    close(client_fd);
+  }
+  if (server_fd != -1) {
+    close(server_fd);
+  }
+  return -1;
+}
+
+static int create_sockets_socketpair(fd_pair *client_fds, fd_pair *server_fds) {
+  int fds[2];
+  if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
+    gpr_log(GPR_ERROR, "socketpair: %s", strerror(errno));
+    return -1;
+  }
+
+  client_fds->read_fd = fds[0];
+  client_fds->write_fd = fds[0];
+  server_fds->read_fd = fds[1];
+  server_fds->write_fd = fds[1];
+  return 0;
+}
+
+static int create_sockets_pipe(fd_pair *client_fds, fd_pair *server_fds) {
+  int cfds[2];
+  int sfds[2];
+  if (pipe(cfds) < 0) {
+    gpr_log(GPR_ERROR, "pipe: %s", strerror(errno));
+    return -1;
+  }
+
+  if (pipe(sfds) < 0) {
+    gpr_log(GPR_ERROR, "pipe: %s", strerror(errno));
+    return -1;
+  }
+
+  client_fds->read_fd = cfds[0];
+  client_fds->write_fd = cfds[1];
+  server_fds->read_fd = sfds[0];
+  server_fds->write_fd = sfds[1];
+  return 0;
+}
+
+static const char *read_strategy_usage =
+    "Strategy for doing reads, which is one of:\n"
+    "  blocking: blocking read calls\n"
+    "  same_thread_poll: poll() call on same thread \n"
+#ifdef __linux__
+    "  same_thread_epoll: epoll_wait() on same thread \n"
+#endif
+    "  spin_read: spinning non-blocking read() calls \n"
+    "  spin_poll: spinning 0 timeout poll() calls \n"
+#ifdef __linux__
+    "  spin_epoll: spinning 0 timeout epoll_wait() calls \n"
+#endif
+    "";
+
+static const char *socket_type_usage =
+    "Type of socket used, one of:\n"
+    "  tcp: fds are endpoints of a TCP connection\n"
+    "  socketpair: fds come from socketpair()\n"
+    "  pipe: fds come from pipe()\n";
+
+void print_usage(char *argv0) {
+  fprintf(stderr, "%s usage:\n\n", argv0);
+  fprintf(stderr, "%s read_strategy socket_type msg_size\n\n", argv0);
+  fprintf(stderr, "where read_strategy is one of:\n");
+  fprintf(stderr, "  blocking: blocking read calls\n");
+  fprintf(stderr, "  same_thread_poll: poll() call on same thread \n");
+#ifdef __linux__
+  fprintf(stderr, "  same_thread_epoll: epoll_wait() on same thread \n");
+#endif
+  fprintf(stderr, "  spin_read: spinning non-blocking read() calls \n");
+  fprintf(stderr, "  spin_poll: spinning 0 timeout poll() calls \n");
+#ifdef __linux__
+  fprintf(stderr, "  spin_epoll: spinning 0 timeout epoll_wait() calls \n");
+#endif
+  fprintf(stderr, "and socket_type is one of:\n");
+  fprintf(stderr, "  tcp: fds are endpoints of a TCP connection\n");
+  fprintf(stderr, "  socketpair: fds come from socketpair()\n");
+  fprintf(stderr, "  pipe: fds come from pipe()\n");
+}
+
+typedef struct test_strategy {
+  char *name;
+  int (*read_strategy)(struct thread_args *args, char *buf);
+  int (*setup)(struct thread_args *args);
+} test_strategy;
+
+static test_strategy test_strategies[] = {
+    {"blocking", blocking_read_bytes, do_nothing},
+    {"same_thread_poll", poll_read_bytes_blocking, set_socket_nonblocking},
+#ifdef __linux__
+    {"same_thread_epoll", epoll_read_bytes_blocking, epoll_setup},
+    {"spin_epoll", epoll_read_bytes_spin, epoll_setup},
+#endif /* __linux__ */
+    {"spin_read", spin_read_bytes, set_socket_nonblocking},
+    {"spin_poll", poll_read_bytes_spin, set_socket_nonblocking}};
+
+int main(int argc, char **argv) {
+  gpr_thd_id tid;
+  thread_args *client_args = malloc(sizeof(thread_args));
+  thread_args *server_args = malloc(sizeof(thread_args));
+  int msg_size = -1;
+  char *read_strategy = NULL;
+  char *socket_type = NULL;
+  int i;
+  const test_strategy *test_strategy = NULL;
+
+  gpr_cmdline *cmdline =
+      gpr_cmdline_create("low_level_ping_pong network benchmarking tool");
+
+  gpr_cmdline_add_int(cmdline, "msg_size", "Size of sent messages", &msg_size);
+  gpr_cmdline_add_string(cmdline, "read_strategy", read_strategy_usage,
+                         &read_strategy);
+  gpr_cmdline_add_string(cmdline, "socket_type", socket_type_usage,
+                         &socket_type);
+
+  gpr_cmdline_parse(cmdline, argc, argv);
+
+  if (read_strategy == NULL) {
+    read_strategy = "blocking";
+  }
+  if (socket_type == NULL) {
+    socket_type = "tcp";
+  }
+  if (msg_size == -1) {
+    msg_size = 50;
+  }
+
+  for (i = 0; i < sizeof(test_strategies) / sizeof(struct test_strategy); ++i) {
+    if (!strcmp(test_strategies[i].name, read_strategy)) {
+      test_strategy = &test_strategies[i];
+    }
+  }
+  if (test_strategy == NULL) {
+    fprintf(stderr, "Invalid read strategy %s\n", read_strategy);
+    return -1;
+  }
+
+  client_args->read_bytes = test_strategy->read_strategy;
+  client_args->write_bytes = blocking_write_bytes;
+  client_args->setup = test_strategy->setup;
+  server_args->read_bytes = test_strategy->read_strategy;
+  server_args->write_bytes = blocking_write_bytes;
+  server_args->setup = test_strategy->setup;
+
+  if (strcmp(socket_type, "tcp") == 0) {
+    create_sockets_tcp(&client_args->fds, &server_args->fds);
+  } else if (strcmp(socket_type, "socketpair") == 0) {
+    create_sockets_socketpair(&client_args->fds, &server_args->fds);
+  } else if (strcmp(socket_type, "pipe") == 0) {
+    create_sockets_pipe(&client_args->fds, &server_args->fds);
+  } else {
+    fprintf(stderr, "Invalid socket type %s\n", socket_type);
+    return -1;
+  }
+
+  if (msg_size <= 0) {
+    fprintf(stderr, "msg_size must be > 0\n");
+    print_usage(argv[0]);
+    return -1;
+  }
+
+  server_args->msg_size = msg_size;
+  client_args->msg_size = msg_size;
+
+  gpr_log(GPR_INFO, "Starting test %s %s %d", read_strategy, socket_type,
+          msg_size);
+
+  gpr_thd_new(&tid, server_thread_wrap, server_args, NULL);
+  client_thread(client_args);
+  gpr_cmdline_destroy(cmdline);
+  return 0;
+}
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
new file mode 100644
index 0000000..260b39b
--- /dev/null
+++ b/test/core/security/credentials_test.c
@@ -0,0 +1,167 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/security/credentials.h"
+
+#include "src/core/httpcli/httpcli.h"
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+#include <string.h>
+
+static grpc_httpcli_response http_response(int status, char *body) {
+  grpc_httpcli_response response;
+  memset(&response, 0, sizeof(grpc_httpcli_response));
+  response.status = status;
+  response.body = body;
+  response.body_length = strlen(body);
+  return response;
+}
+
+static void test_compute_engine_creds_parsing_ok(void) {
+  grpc_mdctx *ctx = grpc_mdctx_create();
+  grpc_mdelem *token_elem = NULL;
+  gpr_timespec token_lifetime;
+  grpc_httpcli_response response =
+      http_response(200,
+                    "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
+                    " \"expires_in\":3599, "
+                    " \"token_type\":\"Bearer\"}");
+  GPR_ASSERT(grpc_compute_engine_credentials_parse_server_response(
+                 &response, ctx, &token_elem, &token_lifetime) ==
+             GRPC_CREDENTIALS_OK);
+  GPR_ASSERT(token_lifetime.tv_sec == 3599);
+  GPR_ASSERT(token_lifetime.tv_nsec == 0);
+  GPR_ASSERT(!strcmp(grpc_mdstr_as_c_string(token_elem->key), "Authorization"));
+  GPR_ASSERT(!strcmp(grpc_mdstr_as_c_string(token_elem->value),
+                     "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"));
+  grpc_mdelem_unref(token_elem);
+  grpc_mdctx_orphan(ctx);
+}
+
+static void test_compute_engine_creds_parsing_bad_http_status(void) {
+  grpc_mdctx *ctx = grpc_mdctx_create();
+  grpc_mdelem *token_elem = NULL;
+  gpr_timespec token_lifetime;
+  grpc_httpcli_response response =
+      http_response(401,
+                    "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
+                    " \"expires_in\":3599, "
+                    " \"token_type\":\"Bearer\"}");
+  GPR_ASSERT(grpc_compute_engine_credentials_parse_server_response(
+                 &response, ctx, &token_elem, &token_lifetime) ==
+             GRPC_CREDENTIALS_ERROR);
+  grpc_mdctx_orphan(ctx);
+}
+
+static void test_compute_engine_creds_parsing_empty_http_body(void) {
+  grpc_mdctx *ctx = grpc_mdctx_create();
+  grpc_mdelem *token_elem = NULL;
+  gpr_timespec token_lifetime;
+  grpc_httpcli_response response = http_response(200, "");
+  GPR_ASSERT(grpc_compute_engine_credentials_parse_server_response(
+                 &response, ctx, &token_elem, &token_lifetime) ==
+             GRPC_CREDENTIALS_ERROR);
+  grpc_mdctx_orphan(ctx);
+}
+
+static void test_compute_engine_creds_parsing_invalid_json(void) {
+  grpc_mdctx *ctx = grpc_mdctx_create();
+  grpc_mdelem *token_elem = NULL;
+  gpr_timespec token_lifetime;
+  grpc_httpcli_response response =
+      http_response(200,
+                    "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
+                    " \"expires_in\":3599, "
+                    " \"token_type\":\"Bearer\"");
+  GPR_ASSERT(grpc_compute_engine_credentials_parse_server_response(
+                 &response, ctx, &token_elem, &token_lifetime) ==
+             GRPC_CREDENTIALS_ERROR);
+  grpc_mdctx_orphan(ctx);
+}
+
+static void test_compute_engine_creds_parsing_missing_token(void) {
+  grpc_mdctx *ctx = grpc_mdctx_create();
+  grpc_mdelem *token_elem = NULL;
+  gpr_timespec token_lifetime;
+  grpc_httpcli_response response = http_response(200,
+                                                 "{"
+                                                 " \"expires_in\":3599, "
+                                                 " \"token_type\":\"Bearer\"}");
+  GPR_ASSERT(grpc_compute_engine_credentials_parse_server_response(
+                 &response, ctx, &token_elem, &token_lifetime) ==
+             GRPC_CREDENTIALS_ERROR);
+  grpc_mdctx_orphan(ctx);
+}
+
+static void test_compute_engine_creds_parsing_missing_token_type(void) {
+  grpc_mdctx *ctx = grpc_mdctx_create();
+  grpc_mdelem *token_elem = NULL;
+  gpr_timespec token_lifetime;
+  grpc_httpcli_response response =
+      http_response(200,
+                    "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
+                    " \"expires_in\":3599, "
+                    "}");
+  GPR_ASSERT(grpc_compute_engine_credentials_parse_server_response(
+                 &response, ctx, &token_elem, &token_lifetime) ==
+             GRPC_CREDENTIALS_ERROR);
+  grpc_mdctx_orphan(ctx);
+}
+
+static void test_compute_engine_creds_parsing_missing_token_lifetime(void) {
+  grpc_mdctx *ctx = grpc_mdctx_create();
+  grpc_mdelem *token_elem = NULL;
+  gpr_timespec token_lifetime;
+  grpc_httpcli_response response =
+      http_response(200,
+                    "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
+                    " \"token_type\":\"Bearer\"}");
+  GPR_ASSERT(grpc_compute_engine_credentials_parse_server_response(
+                 &response, ctx, &token_elem, &token_lifetime) ==
+             GRPC_CREDENTIALS_ERROR);
+  grpc_mdctx_orphan(ctx);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_compute_engine_creds_parsing_ok();
+  test_compute_engine_creds_parsing_bad_http_status();
+  test_compute_engine_creds_parsing_empty_http_body();
+  test_compute_engine_creds_parsing_invalid_json();
+  test_compute_engine_creds_parsing_missing_token();
+  test_compute_engine_creds_parsing_missing_token_type();
+  test_compute_engine_creds_parsing_missing_token_lifetime();
+  return 0;
+}
diff --git a/test/core/statistics/census_stub_test.c b/test/core/statistics/census_stub_test.c
new file mode 100644
index 0000000..7d85550
--- /dev/null
+++ b/test/core/statistics/census_stub_test.c
@@ -0,0 +1,75 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "src/core/statistics/census_interface.h"
+#include "src/core/statistics/census_rpc_stats.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+/* Tests census noop stubs in a simulated rpc flow */
+void test_census_stubs() {
+  census_op_id op_id;
+  census_rpc_stats* stats = census_rpc_stats_create_empty();
+  census_aggregated_rpc_stats data_map;
+  /* Initializes census library at server start up time. */
+  census_init();
+  /* Starts tracing at the beginning of a rpc. */
+  op_id = census_tracing_start_op();
+  /* Appends custom annotations on a trace object. */
+  census_tracing_print(op_id, "annotation foo");
+  census_tracing_print(op_id, "annotation bar");
+  /* Appends method tag on the trace object. */
+  census_add_method_tag(op_id, "service_foo/method.bar");
+  /* Either record client side stats or server side stats associated with the
+     op_id. Here for testing purpose, we record both. */
+  census_record_rpc_client_stats(op_id, stats);
+  census_record_rpc_server_stats(op_id, stats);
+  /* Ends a tracing. */
+  census_tracing_end_op(op_id);
+  /* In process stats queries. */
+  census_get_server_stats(&data_map);
+  census_get_client_stats(&data_map);
+  census_aggregated_rpc_stats_destroy(&data_map);
+  gpr_free(stats);
+  census_shutdown();
+}
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  test_census_stubs();
+  return 0;
+}
diff --git a/test/core/statistics/hash_table_test.c b/test/core/statistics/hash_table_test.c
new file mode 100644
index 0000000..fb75de5
--- /dev/null
+++ b/test/core/statistics/hash_table_test.c
@@ -0,0 +1,288 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/core/statistics/hash_table.h"
+
+#include "src/core/support/murmur_hash.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+static gpr_uint64 hash64(const void* k) {
+  size_t len = strlen(k);
+  gpr_uint64 higher = gpr_murmur_hash3((const char*)k, len / 2, 0);
+  return higher << 32 |
+         gpr_murmur_hash3((const char*)(k) + len / 2, len - len / 2, 0);
+}
+
+static int cmp_str_keys(const void* k1, const void* k2) {
+  return strcmp((const char*)k1, (const char*)k2);
+}
+
+static gpr_uint64 force_collision(const void* k) {
+  return (1997 + hash64(k) % 3);
+}
+
+static void free_data(void* data) { gpr_free(data); }
+
+/* Basic tests that empty hash table can be created and destroyed. */
+static void test_create_table() {
+  /* Create table with uint64 key type */
+  census_ht* ht = NULL;
+  census_ht_option ht_options = {CENSUS_HT_UINT64, 1999, NULL, NULL, NULL,
+                                 NULL};
+  ht = census_ht_create(&ht_options);
+  GPR_ASSERT(ht != NULL);
+  GPR_ASSERT(census_ht_get_size(ht) == 0);
+  census_ht_destroy(ht);
+  /* Create table with pointer key type */
+  ht = NULL;
+  ht_options.key_type = CENSUS_HT_POINTER;
+  ht_options.hash = &hash64;
+  ht_options.compare_keys = &cmp_str_keys;
+  ht = census_ht_create(&ht_options);
+  GPR_ASSERT(ht != NULL);
+  GPR_ASSERT(census_ht_get_size(ht) == 0);
+  census_ht_destroy(ht);
+}
+
+static void test_table_with_int_key() {
+  census_ht_option opt = {CENSUS_HT_UINT64, 7, NULL, NULL, NULL, NULL};
+  census_ht* ht = census_ht_create(&opt);
+  gpr_uint64 i = 0;
+  gpr_uint64 sum_of_keys = 0;
+  size_t num_elements;
+  census_ht_kv* elements = NULL;
+  GPR_ASSERT(ht != NULL);
+  GPR_ASSERT(census_ht_get_size(ht) == 0);
+  elements = census_ht_get_all_elements(ht, &num_elements);
+  GPR_ASSERT(num_elements == 0);
+  GPR_ASSERT(elements == NULL);
+  for (i = 0; i < 20; ++i) {
+    census_ht_key key;
+    key.val = i;
+    census_ht_insert(ht, key, (void*)i);
+    GPR_ASSERT(census_ht_get_size(ht) == i + 1);
+  }
+  for (i = 0; i < 20; i++) {
+    gpr_uint64* val = NULL;
+    census_ht_key key;
+    key.val = i;
+    val = census_ht_find(ht, key);
+    GPR_ASSERT(val == (void*)i);
+  }
+  elements = census_ht_get_all_elements(ht, &num_elements);
+  GPR_ASSERT(elements != NULL);
+  GPR_ASSERT(num_elements == 20);
+  for (i = 0; i < num_elements; i++) {
+    sum_of_keys += elements[i].k.val;
+  }
+  GPR_ASSERT(sum_of_keys == 190);
+  gpr_free(elements);
+  census_ht_destroy(ht);
+}
+
+/* Test that there is no memory leak when keys and values are owned by table. */
+static void test_value_and_key_deleter() {
+  census_ht_option opt = {CENSUS_HT_POINTER, 7, &hash64, &cmp_str_keys,
+                          &free_data, &free_data};
+  census_ht* ht = census_ht_create(&opt);
+  census_ht_key key;
+  char* val;
+  key.ptr = gpr_malloc(100);
+  val = gpr_malloc(10);
+  strcpy(val, "value");
+  strcpy(key.ptr, "some string as a key");
+  GPR_ASSERT(ht != NULL);
+  GPR_ASSERT(census_ht_get_size(ht) == 0);
+  census_ht_insert(ht, key, val);
+  GPR_ASSERT(census_ht_get_size(ht) == 1);
+  census_ht_destroy(ht);
+}
+
+/* Test simple insert and erase operations. */
+static void test_simple_add_and_erase() {
+  census_ht_option opt = {CENSUS_HT_UINT64, 7, NULL, NULL, NULL, NULL};
+  census_ht* ht = census_ht_create(&opt);
+  GPR_ASSERT(ht != NULL);
+  GPR_ASSERT(census_ht_get_size(ht) == 0);
+  {
+    census_ht_key key;
+    int val = 3;
+    key.val = 2;
+    census_ht_insert(ht, key, (void*)&val);
+    GPR_ASSERT(census_ht_get_size(ht) == 1);
+    census_ht_erase(ht, key);
+    GPR_ASSERT(census_ht_get_size(ht) == 0);
+    /* Erasing a key from an empty table should be noop. */
+    census_ht_erase(ht, key);
+    GPR_ASSERT(census_ht_get_size(ht) == 0);
+    /* Erasing a non-existant key from a table should be noop. */
+    census_ht_insert(ht, key, (void*)&val);
+    key.val = 3;
+    census_ht_insert(ht, key, (void*)&val);
+    key.val = 9;
+    census_ht_insert(ht, key, (void*)&val);
+    GPR_ASSERT(census_ht_get_size(ht) == 3);
+    key.val = 1;
+    census_ht_erase(ht, key);
+    /* size unchanged after deleting non-existant key. */
+    GPR_ASSERT(census_ht_get_size(ht) == 3);
+    /* size decrease by 1 after deleting an existant key. */
+    key.val = 2;
+    census_ht_erase(ht, key);
+    GPR_ASSERT(census_ht_get_size(ht) == 2);
+  }
+  census_ht_destroy(ht);
+}
+
+static void test_insertion_and_deletion_with_high_collision_rate() {
+  census_ht_option opt = {CENSUS_HT_POINTER, 13, &force_collision,
+                          &cmp_str_keys, NULL, NULL};
+  census_ht* ht = census_ht_create(&opt);
+  char key_str[1000][10];
+  gpr_uint64 val = 0;
+  int i = 0;
+  for (i = 0; i < 1000; i++) {
+    census_ht_key key;
+    key.ptr = key_str[i];
+    sprintf(key_str[i], "%d", i);
+    census_ht_insert(ht, key, (void*)(&val));
+    printf("%d\n", i);
+    GPR_ASSERT(census_ht_get_size(ht) == (i + 1));
+  }
+  for (i = 0; i < 1000; i++) {
+    census_ht_key key;
+    key.ptr = key_str[i];
+    census_ht_erase(ht, key);
+    GPR_ASSERT(census_ht_get_size(ht) == (999 - i));
+  }
+  census_ht_destroy(ht);
+}
+
+static void test_table_with_string_key() {
+  census_ht_option opt = {CENSUS_HT_POINTER, 7, &hash64, &cmp_str_keys, NULL,
+                          NULL};
+  census_ht* ht = census_ht_create(&opt);
+  const char* keys[] = {"k1", "a", "000", "apple",
+                        "banana_a_long_long_long_banana", "%$", "111", "foo",
+                        "b"};
+  const int vals[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
+  int i = 0;
+  GPR_ASSERT(ht != NULL);
+  GPR_ASSERT(census_ht_get_size(ht) == 0);
+  for (i = 0; i < 9; i++) {
+    census_ht_key key;
+    key.ptr = (void*)(keys[i]);
+    census_ht_insert(ht, key, (void*)(vals + i));
+  }
+  GPR_ASSERT(census_ht_get_size(ht) == 9);
+  for (i = 0; i < 9; i++) {
+    census_ht_key key;
+    int* val_ptr;
+    key.ptr = (void*)(keys[i]);
+    val_ptr = census_ht_find(ht, key);
+    GPR_ASSERT(*val_ptr == vals[i]);
+  }
+  {
+    /* inserts duplicate keys */
+    census_ht_key key;
+    int* val_ptr = NULL;
+    key.ptr = (void*)(keys[2]);
+    census_ht_insert(ht, key, (void*)(vals + 8));
+    /* expect value to be over written by new insertion */
+    GPR_ASSERT(census_ht_get_size(ht) == 9);
+    val_ptr = census_ht_find(ht, key);
+    GPR_ASSERT(*val_ptr == vals[8]);
+  }
+  for (i = 0; i < 9; i++) {
+    census_ht_key key;
+    int* val_ptr;
+    gpr_uint32 expected_tbl_sz = 9 - i;
+    GPR_ASSERT(census_ht_get_size(ht) == expected_tbl_sz);
+    key.ptr = (void*)(keys[i]);
+    val_ptr = census_ht_find(ht, key);
+    GPR_ASSERT(val_ptr != NULL);
+    census_ht_erase(ht, key);
+    GPR_ASSERT(census_ht_get_size(ht) == expected_tbl_sz - 1);
+    val_ptr = census_ht_find(ht, key);
+    GPR_ASSERT(val_ptr == NULL);
+  }
+  census_ht_destroy(ht);
+}
+
+static void test_insertion_with_same_key() {
+  census_ht_option opt = {CENSUS_HT_UINT64, 11, NULL, NULL, NULL, NULL};
+  census_ht* ht = census_ht_create(&opt);
+  census_ht_key key;
+  const char vals[] = {'a', 'b', 'c'};
+  char* val_ptr;
+  key.val = 3;
+  census_ht_insert(ht, key, (void*)&(vals[0]));
+  GPR_ASSERT(census_ht_get_size(ht) == 1);
+  val_ptr = (char*)census_ht_find(ht, key);
+  GPR_ASSERT(val_ptr != NULL);
+  GPR_ASSERT(*val_ptr == 'a');
+  key.val = 4;
+  val_ptr = (char*)census_ht_find(ht, key);
+  GPR_ASSERT(val_ptr == NULL);
+  key.val = 3;
+  census_ht_insert(ht, key, (void*)&(vals[1]));
+  GPR_ASSERT(census_ht_get_size(ht) == 1);
+  val_ptr = (char*)census_ht_find(ht, key);
+  GPR_ASSERT(val_ptr != NULL);
+  GPR_ASSERT(*val_ptr == 'b');
+  census_ht_insert(ht, key, (void*)&(vals[2]));
+  GPR_ASSERT(census_ht_get_size(ht) == 1);
+  val_ptr = (char*)census_ht_find(ht, key);
+  GPR_ASSERT(val_ptr != NULL);
+  GPR_ASSERT(*val_ptr == 'c');
+  census_ht_destroy(ht);
+}
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  test_create_table();
+  test_simple_add_and_erase();
+  test_table_with_int_key();
+  test_table_with_string_key();
+  test_value_and_key_deleter();
+  test_insertion_with_same_key();
+  test_insertion_and_deletion_with_high_collision_rate();
+  return 0;
+}
diff --git a/test/core/statistics/log_tests.c b/test/core/statistics/log_tests.c
new file mode 100644
index 0000000..f0cbdbd
--- /dev/null
+++ b/test/core/statistics/log_tests.c
@@ -0,0 +1,568 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/statistics/log.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "src/core/support/cpu.h"
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+
+/* Fills in 'record' of size 'size'. Each byte in record is filled in with the
+   same value. The value is extracted from 'record' pointer. */
+static void write_record(char* record, size_t size) {
+  char data = (gpr_uintptr)record % 255;
+  memset(record, data, size);
+}
+
+/* Reads fixed size records. Returns the number of records read in
+   'num_records'. */
+static void read_records(size_t record_size, const char* buffer,
+                         size_t buffer_size, gpr_int32* num_records) {
+  gpr_int32 ix;
+  GPR_ASSERT(buffer_size >= record_size);
+  GPR_ASSERT(buffer_size % record_size == 0);
+  *num_records = buffer_size / record_size;
+  for (ix = 0; ix < *num_records; ++ix) {
+    gpr_int32 jx;
+    const char* record = buffer + (record_size * ix);
+    char data = (gpr_uintptr)record % 255;
+    for (jx = 0; jx < record_size; ++jx) {
+      GPR_ASSERT(data == record[jx]);
+    }
+  }
+}
+
+/* Tries to write the specified number of records. Stops when the log gets
+   full. Returns the number of records written. Spins for random
+   number of times, up to 'max_spin_count', between writes. */
+static size_t write_records_to_log(int writer_id, gpr_int32 record_size,
+                                   gpr_int32 num_records,
+                                   gpr_int32 max_spin_count) {
+  gpr_int32 ix;
+  int counter = 0;
+  for (ix = 0; ix < num_records; ++ix) {
+    gpr_int32 jx;
+    gpr_int32 spin_count = max_spin_count ? rand() % max_spin_count : 0;
+    char* record;
+    if (counter++ == num_records / 10) {
+      printf("   Writer %d: %d out of %d written\n", writer_id, ix,
+             num_records);
+      counter = 0;
+    }
+    record = (char*)(census_log_start_write(record_size));
+    if (record == NULL) {
+      return ix;
+    }
+    write_record(record, record_size);
+    census_log_end_write(record, record_size);
+    for (jx = 0; jx < spin_count; ++jx) {
+      GPR_ASSERT(jx >= 0);
+    }
+  }
+  return num_records;
+}
+
+/* Performs a single read iteration. Returns the number of records read. */
+static size_t perform_read_iteration(size_t record_size) {
+  const void* read_buffer = NULL;
+  size_t bytes_available;
+  size_t records_read = 0;
+  census_log_init_reader();
+  while ((read_buffer = census_log_read_next(&bytes_available))) {
+    gpr_int32 num_records = 0;
+    read_records(record_size, (const char*)read_buffer, bytes_available,
+                 &num_records);
+    records_read += num_records;
+  }
+  return records_read;
+}
+
+/* Asserts that the log is empty. */
+static void assert_log_empty() {
+  size_t bytes_available;
+  census_log_init_reader();
+  GPR_ASSERT(census_log_read_next(&bytes_available) == NULL);
+}
+
+/* Given log size and record size, computes the minimum usable space. */
+static size_t min_usable_space(size_t log_size, size_t record_size) {
+  gpr_int32 num_blocks = log_size / CENSUS_LOG_MAX_RECORD_SIZE;
+  gpr_int32 waste_per_block = CENSUS_LOG_MAX_RECORD_SIZE % record_size;
+  /* In the worst case, all except one core-local block is empty. */
+  return (log_size - ((gpr_cpu_num_cores() - 1) * CENSUS_LOG_MAX_RECORD_SIZE) -
+          ((num_blocks - gpr_cpu_num_cores() - 1) * waste_per_block));
+}
+
+/* Fills the log and verifies data. If 'no fragmentation' is true, records
+   are sized such that CENSUS_LOG_2_MAX_RECORD_SIZE is a multiple of record
+   size. If not a circular log, verifies that the number of records written
+   match the number of records read. */
+static void fill_log(size_t log_size, int no_fragmentation, int circular_log) {
+  int size;
+  gpr_int32 records_written;
+  gpr_int32 usable_space;
+  gpr_int32 records_read;
+  if (no_fragmentation) {
+    int log2size = rand() % (CENSUS_LOG_2_MAX_RECORD_SIZE + 1);
+    size = (1 << log2size);
+  } else {
+    while (1) {
+      size = 1 + (rand() % CENSUS_LOG_MAX_RECORD_SIZE);
+      if (CENSUS_LOG_MAX_RECORD_SIZE % size) {
+        break;
+      }
+    }
+  }
+  printf("   Fill record size: %d\n", size);
+  records_written = write_records_to_log(
+      0 /* writer id */, size, (log_size / size) * 2, 0 /* spin count */);
+  usable_space = min_usable_space(log_size, size);
+  GPR_ASSERT(usable_space > 0);
+  GPR_ASSERT(records_written * size >= usable_space);
+  records_read = perform_read_iteration(size);
+  if (!circular_log) {
+    GPR_ASSERT(records_written == records_read);
+  }
+  assert_log_empty();
+}
+
+/* Structure to pass args to writer_thread */
+typedef struct writer_thread_args {
+  /* Index of this thread in the writers vector. */
+  int index;
+  /* Record size. */
+  size_t record_size;
+  /* Number of records to write. */
+  gpr_int32 num_records;
+  /* Used to signal when writer is complete */
+  gpr_cv* done;
+  gpr_mu* mu;
+  int* count;
+} writer_thread_args;
+
+/* Writes the given number of records of random size (up to kMaxRecordSize) and
+   random data to the specified log. */
+static void writer_thread(void* arg) {
+  writer_thread_args* args = (writer_thread_args*)arg;
+  /* Maximum number of times to spin between writes. */
+  static const gpr_int32 MAX_SPIN_COUNT = 50;
+  int records_written = 0;
+  printf("   Writer: %d\n", args->index);
+  while (records_written < args->num_records) {
+    records_written += write_records_to_log(args->index, args->record_size,
+                                            args->num_records - records_written,
+                                            MAX_SPIN_COUNT);
+    if (records_written < args->num_records) {
+      /* Ran out of log space. Sleep for a bit and let the reader catch up.
+         This should never happen for circular logs. */
+      printf("   Writer stalled due to out-of-space: %d out of %d written\n",
+             records_written, args->num_records);
+      gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_micros(10000)));
+    }
+  }
+  /* Done. Decrement count and signal. */
+  gpr_mu_lock(args->mu);
+  (*args->count)--;
+  gpr_cv_broadcast(args->done);
+  printf("   Writer done: %d\n", args->index);
+  gpr_mu_unlock(args->mu);
+}
+
+/* struct to pass args to reader_thread */
+typedef struct reader_thread_args {
+  /* Record size. */
+  size_t record_size;
+  /* Interval between read iterations. */
+  gpr_int32 read_iteration_interval_in_msec;
+  /* Total number of records. */
+  gpr_int32 total_records;
+  /* Signalled when reader should stop. */
+  gpr_cv stop;
+  int stop_flag;
+  /* Used to signal when reader has finished */
+  gpr_cv* done;
+  gpr_mu* mu;
+  int running;
+} reader_thread_args;
+
+/* Reads and verifies the specified number of records. Reader can also be
+   stopped via gpr_cv_signal(&args->stop). Sleeps for 'read_interval_in_msec'
+   between read iterations. */
+static void reader_thread(void* arg) {
+  gpr_int32 records_read = 0;
+  reader_thread_args* args = (reader_thread_args*)arg;
+  gpr_int32 num_iterations = 0;
+  gpr_timespec interval;
+  int counter = 0;
+  printf("   Reader starting\n");
+  interval = gpr_time_from_micros(args->read_iteration_interval_in_msec * 1000);
+  gpr_mu_lock(args->mu);
+  while (!args->stop_flag && records_read < args->total_records) {
+    gpr_cv_wait(&args->stop, args->mu, interval);
+    if (!args->stop_flag) {
+      records_read += perform_read_iteration(args->record_size);
+      GPR_ASSERT(records_read <= args->total_records);
+      if (counter++ == 100000) {
+        printf("   Reader: %d out of %d read\n", records_read,
+               args->total_records);
+        counter = 0;
+      }
+      ++num_iterations;
+    }
+  }
+  /* Done */
+  args->running = 0;
+  gpr_cv_broadcast(args->done);
+  printf("   Reader: records: %d, iterations: %d\n", records_read,
+         num_iterations);
+  gpr_mu_unlock(args->mu);
+}
+
+/* Creates NUM_WRITERS writers where each writer writes NUM_RECORDS_PER_WRITER
+   records. Also, starts a reader that iterates over and reads blocks every
+   READ_ITERATION_INTERVAL_IN_MSEC. */
+/* Number of writers. */
+#define NUM_WRITERS 5
+static void multiple_writers_single_reader(int circular_log) {
+  /* Sleep interval between read iterations. */
+  static const gpr_int32 READ_ITERATION_INTERVAL_IN_MSEC = 10;
+  /* Number of records written by each writer. */
+  static const gpr_int32 NUM_RECORDS_PER_WRITER = 10 * 1024 * 1024;
+  /* Maximum record size. */
+  static const size_t MAX_RECORD_SIZE = 10;
+  int ix;
+  gpr_thd_id id;
+  gpr_cv writers_done;
+  int writers_count = NUM_WRITERS;
+  gpr_mu writers_mu; /* protects writers_done and writers_count */
+  writer_thread_args writers[NUM_WRITERS];
+  gpr_cv reader_done;
+  gpr_mu reader_mu; /* protects reader_done and reader.running */
+  reader_thread_args reader;
+  gpr_int32 record_size = 1 + rand() % MAX_RECORD_SIZE;
+  printf("   Record size: %d\n", record_size);
+  /* Create and start writers. */
+  gpr_cv_init(&writers_done);
+  gpr_mu_init(&writers_mu);
+  for (ix = 0; ix < NUM_WRITERS; ++ix) {
+    writers[ix].index = ix;
+    writers[ix].record_size = record_size;
+    writers[ix].num_records = NUM_RECORDS_PER_WRITER;
+    writers[ix].done = &writers_done;
+    writers[ix].count = &writers_count;
+    writers[ix].mu = &writers_mu;
+    gpr_thd_new(&id, &writer_thread, &writers[ix], NULL);
+  }
+  /* Start reader. */
+  reader.record_size = record_size;
+  reader.read_iteration_interval_in_msec = READ_ITERATION_INTERVAL_IN_MSEC;
+  reader.total_records = NUM_WRITERS * NUM_RECORDS_PER_WRITER;
+  reader.stop_flag = 0;
+  gpr_cv_init(&reader.stop);
+  gpr_cv_init(&reader_done);
+  reader.done = &reader_done;
+  gpr_mu_init(&reader_mu);
+  reader.mu = &reader_mu;
+  reader.running = 1;
+  gpr_thd_new(&id, &reader_thread, &reader, NULL);
+  /* Wait for writers to finish. */
+  gpr_mu_lock(&writers_mu);
+  while (writers_count != 0) {
+    gpr_cv_wait(&writers_done, &writers_mu, gpr_inf_future);
+  }
+  gpr_mu_unlock(&writers_mu);
+  gpr_mu_destroy(&writers_mu);
+  gpr_cv_destroy(&writers_done);
+  gpr_mu_lock(&reader_mu);
+  if (circular_log) {
+    /* Stop reader. */
+    reader.stop_flag = 1;
+    gpr_cv_signal(&reader.stop);
+  }
+  /* wait for reader to finish */
+  while (reader.running) {
+    gpr_cv_wait(&reader_done, &reader_mu, gpr_inf_future);
+  }
+  if (circular_log) {
+    /* Assert that there were no out-of-space errors. */
+    GPR_ASSERT(0 == census_log_out_of_space_count());
+  }
+  gpr_mu_unlock(&reader_mu);
+  gpr_mu_destroy(&reader_mu);
+  gpr_cv_destroy(&reader_done);
+  printf("   Reader: finished\n");
+}
+
+/* Log sizes to use for all tests. */
+#define LOG_SIZE_IN_MB 1
+#define LOG_SIZE_IN_BYTES (LOG_SIZE_IN_MB << 20)
+
+static void setup_test(int circular_log) {
+  census_log_initialize(LOG_SIZE_IN_MB, circular_log);
+  GPR_ASSERT(census_log_remaining_space() == LOG_SIZE_IN_BYTES);
+}
+
+/* Attempts to create a record of invalid size (size >
+   CENSUS_LOG_MAX_RECORD_SIZE). */
+void test_invalid_record_size() {
+  static const size_t INVALID_SIZE = CENSUS_LOG_MAX_RECORD_SIZE + 1;
+  static const size_t VALID_SIZE = 1;
+  void* record;
+  printf("Starting test: invalid record size\n");
+  setup_test(0);
+  record = census_log_start_write(INVALID_SIZE);
+  GPR_ASSERT(record == NULL);
+  /* Now try writing a valid record. */
+  record = census_log_start_write(VALID_SIZE);
+  GPR_ASSERT(record != NULL);
+  census_log_end_write(record, VALID_SIZE);
+  /* Verifies that available space went down by one block. In theory, this
+     check can fail if the thread is context switched to a new CPU during the
+     start_write execution (multiple blocks get allocated), but this has not
+     been observed in practice. */
+  GPR_ASSERT(LOG_SIZE_IN_BYTES - CENSUS_LOG_MAX_RECORD_SIZE ==
+             census_log_remaining_space());
+  census_log_shutdown();
+}
+
+/* Tests end_write() with a different size than what was specified in
+   start_write(). */
+void test_end_write_with_different_size() {
+  static const size_t START_WRITE_SIZE = 10;
+  static const size_t END_WRITE_SIZE = 7;
+  void* record_written;
+  const void* record_read;
+  size_t bytes_available;
+  printf("Starting test: end write with different size\n");
+  setup_test(0);
+  record_written = census_log_start_write(START_WRITE_SIZE);
+  GPR_ASSERT(record_written != NULL);
+  census_log_end_write(record_written, END_WRITE_SIZE);
+  census_log_init_reader();
+  record_read = census_log_read_next(&bytes_available);
+  GPR_ASSERT(record_written == record_read);
+  GPR_ASSERT(END_WRITE_SIZE == bytes_available);
+  assert_log_empty();
+  census_log_shutdown();
+}
+
+/* Verifies that pending records are not available via read_next(). */
+void test_read_pending_record() {
+  static const size_t PR_RECORD_SIZE = 1024;
+  size_t bytes_available;
+  const void* record_read;
+  void* record_written;
+  printf("Starting test: read pending record\n");
+  setup_test(0);
+  /* Start a write. */
+  record_written = census_log_start_write(PR_RECORD_SIZE);
+  GPR_ASSERT(record_written != NULL);
+  /* As write is pending, read should fail. */
+  census_log_init_reader();
+  record_read = census_log_read_next(&bytes_available);
+  GPR_ASSERT(record_read == NULL);
+  /* A read followed by end_write() should succeed. */
+  census_log_end_write(record_written, PR_RECORD_SIZE);
+  census_log_init_reader();
+  record_read = census_log_read_next(&bytes_available);
+  GPR_ASSERT(record_written == record_read);
+  GPR_ASSERT(PR_RECORD_SIZE == bytes_available);
+  assert_log_empty();
+  census_log_shutdown();
+}
+
+/* Tries reading beyond pending write. */
+void test_read_beyond_pending_record() {
+  /* Start a write. */
+  gpr_int32 incomplete_record_size = 10;
+  gpr_int32 complete_record_size = 20;
+  size_t bytes_available;
+  void* complete_record;
+  const void* record_read;
+  void* incomplete_record;
+  printf("Starting test: read beyond pending record\n");
+  setup_test(0);
+  incomplete_record = census_log_start_write(incomplete_record_size);
+  GPR_ASSERT(incomplete_record != NULL);
+  complete_record = census_log_start_write(complete_record_size);
+  GPR_ASSERT(complete_record != NULL);
+  GPR_ASSERT(complete_record != incomplete_record);
+  census_log_end_write(complete_record, complete_record_size);
+  /* Now iterate over blocks to read completed records. */
+  census_log_init_reader();
+  record_read = census_log_read_next(&bytes_available);
+  GPR_ASSERT(complete_record == record_read);
+  GPR_ASSERT(complete_record_size == bytes_available);
+  /* Complete first record. */
+  census_log_end_write(incomplete_record, incomplete_record_size);
+  /* Have read past the incomplete record, so read_next() should return NULL. */
+  /* NB: this test also assumes our thread did not get switched to a different
+     CPU between the two start_write calls */
+  record_read = census_log_read_next(&bytes_available);
+  GPR_ASSERT(record_read == NULL);
+  /* Reset reader to get the newly completed record. */
+  census_log_init_reader();
+  record_read = census_log_read_next(&bytes_available);
+  GPR_ASSERT(incomplete_record == record_read);
+  GPR_ASSERT(incomplete_record_size == bytes_available);
+  assert_log_empty();
+  census_log_shutdown();
+}
+
+/* Tests scenario where block being read is detached from a core and put on the
+   dirty list. */
+void test_detached_while_reading() {
+  static const size_t DWR_RECORD_SIZE = 10;
+  size_t bytes_available;
+  const void* record_read;
+  void* record_written;
+  gpr_int32 block_read = 0;
+  printf("Starting test: detached while reading\n");
+  setup_test(0);
+  /* Start a write. */
+  record_written = census_log_start_write(DWR_RECORD_SIZE);
+  GPR_ASSERT(record_written != NULL);
+  census_log_end_write(record_written, DWR_RECORD_SIZE);
+  /* Read this record. */
+  census_log_init_reader();
+  record_read = census_log_read_next(&bytes_available);
+  GPR_ASSERT(record_read != NULL);
+  GPR_ASSERT(DWR_RECORD_SIZE == bytes_available);
+  /* Now fill the log. This will move the block being read from core-local
+     array to the dirty list. */
+  while ((record_written = census_log_start_write(DWR_RECORD_SIZE))) {
+    census_log_end_write(record_written, DWR_RECORD_SIZE);
+  }
+
+  /* In this iteration, read_next() should only traverse blocks in the
+     core-local array. Therefore, we expect at most gpr_cpu_num_cores() more
+     blocks. As log is full, if read_next() is traversing the dirty list, we
+     will get more than gpr_cpu_num_cores() blocks. */
+  while ((record_read = census_log_read_next(&bytes_available))) {
+    ++block_read;
+    GPR_ASSERT(block_read <= gpr_cpu_num_cores());
+  }
+  census_log_shutdown();
+}
+
+/* Fills non-circular log with records sized such that size is a multiple of
+   CENSUS_LOG_MAX_RECORD_SIZE (no per-block fragmentation). */
+void test_fill_log_no_fragmentation() {
+  const int circular = 0;
+  printf("Starting test: fill log no fragmentation\n");
+  setup_test(circular);
+  fill_log(LOG_SIZE_IN_BYTES, 1 /* no fragmentation */, circular);
+  census_log_shutdown();
+}
+
+/* Fills circular log with records sized such that size is a multiple of
+   CENSUS_LOG_MAX_RECORD_SIZE (no per-block fragmentation). */
+void test_fill_circular_log_no_fragmentation() {
+  const int circular = 1;
+  printf("Starting test: fill circular log no fragmentation\n");
+  setup_test(circular);
+  fill_log(LOG_SIZE_IN_BYTES, 1 /* no fragmentation */, circular);
+  census_log_shutdown();
+}
+
+/* Fills non-circular log with records that may straddle end of a block. */
+void test_fill_log_with_straddling_records() {
+  const int circular = 0;
+  printf("Starting test: fill log with straddling records\n");
+  setup_test(circular);
+  fill_log(LOG_SIZE_IN_BYTES, 0 /* block straddling records */, circular);
+  census_log_shutdown();
+}
+
+/* Fills circular log with records that may straddle end of a block. */
+void test_fill_circular_log_with_straddling_records() {
+  const int circular = 1;
+  printf("Starting test: fill circular log with straddling records\n");
+  setup_test(circular);
+  fill_log(LOG_SIZE_IN_BYTES, 0 /* block straddling records */, circular);
+  census_log_shutdown();
+}
+
+/* Tests scenario where multiple writers and a single reader are using a log
+   that is configured to discard old records. */
+void test_multiple_writers_circular_log() {
+  const int circular = 1;
+  printf("Starting test: multiple writers circular log\n");
+  setup_test(circular);
+  multiple_writers_single_reader(circular);
+  census_log_shutdown();
+}
+
+/* Tests scenario where multiple writers and a single reader are using a log
+   that is configured to discard old records. */
+void test_multiple_writers() {
+  const int circular = 0;
+  printf("Starting test: multiple writers\n");
+  setup_test(circular);
+  multiple_writers_single_reader(circular);
+  census_log_shutdown();
+}
+
+void test_performance() {
+  int write_size = 1;
+  for (; write_size < CENSUS_LOG_MAX_RECORD_SIZE; write_size *= 2) {
+    gpr_timespec write_time;
+    gpr_timespec start_time;
+    double write_time_micro = 0.0;
+    int nrecords = 0;
+    setup_test(0);
+    start_time = gpr_now();
+    while (1) {
+      void* record = census_log_start_write(write_size);
+      if (record == NULL) {
+        break;
+      }
+      census_log_end_write(record, write_size);
+      nrecords++;
+    }
+    write_time = gpr_time_sub(gpr_now(), start_time);
+    write_time_micro = write_time.tv_sec * 1000000 + write_time.tv_nsec / 1000;
+    census_log_shutdown();
+    printf(
+        "Wrote %d %d byte records in %.3g microseconds: %g records/us "
+        "(%g ns/record), %g gigabytes/s\n",
+        nrecords, write_size, write_time_micro, nrecords / write_time_micro,
+        1000 * write_time_micro / nrecords,
+        (write_size * nrecords) / write_time_micro / 1000);
+  }
+}
diff --git a/test/core/statistics/log_tests.h b/test/core/statistics/log_tests.h
new file mode 100644
index 0000000..10993ac
--- /dev/null
+++ b/test/core/statistics/log_tests.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_TEST_STATISTICS_LOG_TESTS_H__
+#define __GRPC_TEST_STATISTICS_LOG_TESTS_H__
+
+void test_invalid_record_size();
+void test_end_write_with_different_size();
+void test_read_pending_record();
+void test_read_beyond_pending_record();
+void test_detached_while_reading();
+void test_fill_log_no_fragmentation();
+void test_fill_circular_log_no_fragmentation();
+void test_fill_log_with_straddling_records();
+void test_fill_circular_log_with_straddling_records();
+void test_multiple_writers_circular_log();
+void test_multiple_writers();
+void test_performance();
+
+#endif  /* __GRPC_TEST_STATISTICS_LOG_TESTS_H__ */
diff --git a/test/core/statistics/multiple_writers_circular_buffer_test.c b/test/core/statistics/multiple_writers_circular_buffer_test.c
new file mode 100644
index 0000000..0cd0d78
--- /dev/null
+++ b/test/core/statistics/multiple_writers_circular_buffer_test.c
@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/statistics/log_tests.h"
+
+#include <stdlib.h>
+
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  srand(gpr_now().tv_nsec);
+  test_multiple_writers_circular_log();
+  return 0;
+}
diff --git a/test/core/statistics/multiple_writers_test.c b/test/core/statistics/multiple_writers_test.c
new file mode 100644
index 0000000..b1f3be4
--- /dev/null
+++ b/test/core/statistics/multiple_writers_test.c
@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/statistics/log_tests.h"
+
+#include <stdlib.h>
+
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  srand(gpr_now().tv_nsec);
+  test_multiple_writers();
+  return 0;
+}
diff --git a/test/core/statistics/performance_test.c b/test/core/statistics/performance_test.c
new file mode 100644
index 0000000..9197dd5
--- /dev/null
+++ b/test/core/statistics/performance_test.c
@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "log_tests.h"
+
+#include <stdlib.h>
+
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  srand(gpr_now().tv_nsec);
+  test_performance();
+  return 0;
+}
diff --git a/test/core/statistics/quick_test.c b/test/core/statistics/quick_test.c
new file mode 100644
index 0000000..fe2b89a
--- /dev/null
+++ b/test/core/statistics/quick_test.c
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "log_tests.h"
+
+#include <stdlib.h>
+
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  srand(gpr_now().tv_nsec);
+  test_invalid_record_size();
+  test_end_write_with_different_size();
+  test_read_pending_record();
+  test_read_beyond_pending_record();
+  test_detached_while_reading();
+  test_fill_log_no_fragmentation();
+  test_fill_circular_log_no_fragmentation();
+  test_fill_log_with_straddling_records();
+  test_fill_circular_log_with_straddling_records();
+  return 0;
+}
diff --git a/test/core/statistics/window_stats_test.c b/test/core/statistics/window_stats_test.c
new file mode 100644
index 0000000..2bf93d8
--- /dev/null
+++ b/test/core/statistics/window_stats_test.c
@@ -0,0 +1,317 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/statistics/window_stats.h"
+#include <stdlib.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+typedef struct test_stat {
+  double value1;
+  int value2;
+} test_stat;
+
+void add_test_stat(void* base, const void* addme) {
+  test_stat* b = (test_stat*)base;
+  const test_stat* a = (const test_stat*)addme;
+  b->value1 += a->value1;
+  b->value2 += a->value2;
+}
+
+void add_proportion_test_stat(double p, void* base, const void* addme) {
+  test_stat* b = (test_stat*)base;
+  const test_stat* a = (const test_stat*)addme;
+  b->value1 += p * a->value1;
+  b->value2 += p * a->value2 + 0.5; /* +0.5 is poor mans (no c99) round() */
+}
+
+const struct census_window_stats_stat_info kMyStatInfo = {
+    sizeof(test_stat), NULL, add_test_stat, add_proportion_test_stat};
+
+const gpr_timespec kMilliSecInterval = {0, 1000000};
+const gpr_timespec kSecInterval = {1, 0};
+const gpr_timespec kMinInterval = {60, 0};
+const gpr_timespec kHourInterval = {3600, 0};
+const gpr_timespec kPrimeInterval = {0, 101};
+
+static int compare_double(double a, double b, double epsilon) {
+  if (a >= b) {
+    return (a > b + epsilon) ? 1 : 0;
+  } else {
+    return (b > a + epsilon) ? -1 : 0;
+  }
+}
+
+void empty_test() {
+  census_window_stats_sums result;
+  const gpr_timespec zero = {0, 0};
+  test_stat sum;
+  struct census_window_stats* stats =
+      census_window_stats_create(1, &kMinInterval, 5, &kMyStatInfo);
+  GPR_ASSERT(stats != NULL);
+  result.statistic = &sum;
+  census_window_stats_get_sums(stats, zero, &result);
+  GPR_ASSERT(result.count == 0 && sum.value1 == 0 && sum.value2 == 0);
+  census_window_stats_get_sums(stats, gpr_now(), &result);
+  GPR_ASSERT(result.count == 0 && sum.value1 == 0 && sum.value2 == 0);
+  census_window_stats_destroy(stats);
+}
+
+void one_interval_test() {
+  const test_stat value = {0.1, 4};
+  const double epsilon = 1e10 - 11;
+  gpr_timespec when = {0, 0};
+  census_window_stats_sums result;
+  test_stat sum;
+  /* granularity == 5 so width of internal windows should be 12s */
+  struct census_window_stats* stats =
+      census_window_stats_create(1, &kMinInterval, 5, &kMyStatInfo);
+  GPR_ASSERT(stats != NULL);
+  /* phase 1: insert a single value at t=0s, and check that various measurement
+     times result in expected output values */
+  census_window_stats_add(stats, when, &value);
+  result.statistic = &sum;
+  /* when = 0s, values extracted should be everything */
+  census_window_stats_get_sums(stats, when, &result);
+  GPR_ASSERT(compare_double(result.count, 1, epsilon) == 0 &&
+             compare_double(sum.value1, value.value1, epsilon) == 0 &&
+             sum.value2 == value.value2);
+  /* when = 6,30,60s, should be all of the data */
+  when.tv_sec = 6;
+  census_window_stats_get_sums(stats, when, &result);
+  GPR_ASSERT(compare_double(result.count, 1.0, epsilon) == 0 &&
+             compare_double(sum.value1, value.value1, epsilon) == 0 &&
+             sum.value2 == value.value2);
+  /* when == 30s,60s, should be all of the data */
+  when.tv_sec = 30;
+  census_window_stats_get_sums(stats, when, &result);
+  GPR_ASSERT(compare_double(result.count, 1.0, epsilon) == 0 &&
+             compare_double(sum.value1, value.value1, epsilon) == 0 &&
+             sum.value2 == value.value2);
+  when.tv_sec = 60;
+  census_window_stats_get_sums(stats, when, &result);
+  GPR_ASSERT(compare_double(result.count, 1.0, epsilon) == 0 &&
+             compare_double(sum.value1, value.value1, epsilon) == 0 &&
+             sum.value2 == value.value2);
+  /* when = 66s, should be half (only take half of bottom bucket) */
+  when.tv_sec = 66;
+  census_window_stats_get_sums(stats, when, &result);
+  GPR_ASSERT(compare_double(result.count, 0.5, epsilon) == 0 &&
+             compare_double(sum.value1, value.value1 / 2, epsilon) == 0 &&
+             sum.value2 == value.value2 / 2);
+  /* when = 72s, should be completely out of window */
+  when.tv_sec = 72;
+  census_window_stats_get_sums(stats, when, &result);
+  GPR_ASSERT(compare_double(result.count, 0, epsilon) == 0 &&
+             compare_double(sum.value1, 0, epsilon) == 0 && sum.value2 == 0);
+
+  /* phase 2: tear down and do as before, but inserting two values */
+  census_window_stats_destroy(stats);
+  stats = census_window_stats_create(1, &kMinInterval, 5, &kMyStatInfo);
+  GPR_ASSERT(stats != NULL);
+  when.tv_sec = 0;
+  when.tv_nsec = 17;
+  census_window_stats_add(stats, when, &value);
+  when.tv_sec = 1;
+  census_window_stats_add(stats, when, &value);
+  when.tv_sec = 0;
+  census_window_stats_get_sums(stats, when, &result);
+  GPR_ASSERT(compare_double(result.count, 0, epsilon) == 0 &&
+             compare_double(sum.value1, 0, epsilon) == 0 && sum.value2 == 0);
+  /* time = 3s, 30s, should get all data */
+  when.tv_sec = 3;
+  census_window_stats_get_sums(stats, when, &result);
+  GPR_ASSERT(compare_double(result.count, 2, epsilon) == 0 &&
+             compare_double(sum.value1, 2 * value.value1, epsilon) == 0 &&
+             sum.value2 == 2 * value.value2);
+  when.tv_sec = 30;
+  census_window_stats_get_sums(stats, when, &result);
+  GPR_ASSERT(compare_double(result.count, 2, epsilon) == 0 &&
+             compare_double(sum.value1, 2 * value.value1, epsilon) == 0 &&
+             sum.value2 == 2 * value.value2);
+
+  /* phase 3: insert into "middle" bucket, and force a shift, pushing out
+     the two values in bottom bucket */
+  when.tv_sec = 30;
+  census_window_stats_add(stats, when, &value);
+  when.tv_sec = 76;
+  census_window_stats_add(stats, when, &value);
+  when.tv_sec = 0;
+  census_window_stats_get_sums(stats, when, &result);
+  GPR_ASSERT(result.count == 0 && sum.value1 == 0 && sum.value2 == 0);
+  when.tv_sec = 30;
+  census_window_stats_get_sums(stats, when, &result);
+  /* half of the single value in the 30 second bucket */
+  GPR_ASSERT(compare_double(result.count, 0.5, epsilon) == 0 &&
+             compare_double(sum.value1, value.value1 / 2, epsilon) == 0 &&
+             sum.value2 == value.value2 / 2);
+  when.tv_sec = 74;
+  census_window_stats_get_sums(stats, when, &result);
+  /* half of the 76 second bucket, all of the 30 second bucket */
+  GPR_ASSERT(compare_double(result.count, 1.5, epsilon) == 0 &&
+             compare_double(sum.value1, value.value1 * 1.5, epsilon) == 0 &&
+             sum.value2 == value.value2 / 2 * 3);
+  when.tv_sec = 76;
+  census_window_stats_get_sums(stats, when, &result);
+  /* >=76s, get all of the 76 second bucket, all of the 30 second bucket */
+  GPR_ASSERT(compare_double(result.count, 2, epsilon) == 0 &&
+             compare_double(sum.value1, value.value1 * 2, epsilon) == 0 &&
+             sum.value2 == value.value2 * 2);
+  when.tv_sec = 78;
+  census_window_stats_get_sums(stats, when, &result);
+  /* half of the 76 second bucket, all of the 30 second bucket */
+  GPR_ASSERT(compare_double(result.count, 2, epsilon) == 0 &&
+             compare_double(sum.value1, value.value1 * 2, epsilon) == 0 &&
+             sum.value2 == value.value2 * 2);
+  census_window_stats_destroy(stats);
+}
+
+void many_interval_test() {
+  gpr_timespec intervals[4];
+  const test_stat value = {123.45, 8};
+  const double epsilon = 1e10 - 11;
+  gpr_timespec when = {3600, 0}; /* one hour */
+  census_window_stats_sums result[4];
+  test_stat sums[4];
+  int i;
+  struct census_window_stats* stats;
+  intervals[0] = kMilliSecInterval;
+  intervals[1] = kSecInterval;
+  intervals[2] = kMinInterval;
+  intervals[3] = kHourInterval;
+  for (i = 0; i < 4; i++) {
+    result[i].statistic = &sums[i];
+  }
+  stats = census_window_stats_create(4, intervals, 100, &kMyStatInfo);
+  GPR_ASSERT(stats != NULL);
+  /* add 10 stats within half of each time range */
+  for (i = 0; i < 10; i++) {
+    when.tv_sec += 180; /* covers 30 min of one hour range */
+    census_window_stats_add(stats, when, &value);
+  }
+  when.tv_sec += 120;
+  for (i = 0; i < 10; i++) {
+    when.tv_sec += 3; /* covers 30 sec of one minute range */
+    census_window_stats_add(stats, when, &value);
+  }
+  when.tv_sec += 2;
+  for (i = 0; i < 10; i++) {
+    when.tv_nsec += 50000000; /* covers 0.5s of 1s range */
+    census_window_stats_add(stats, when, &value);
+  }
+  when.tv_nsec += 2000000;
+  for (i = 0; i < 10; i++) {
+    when.tv_nsec += 50000; /* covers 0.5 ms of 1 ms range */
+    census_window_stats_add(stats, when, &value);
+  }
+  when.tv_nsec += 20000;
+  census_window_stats_get_sums(stats, when, result);
+  GPR_ASSERT(compare_double(result[0].count, 10, epsilon) == 0 &&
+             compare_double(sums[0].value1, value.value1 * 10, epsilon) == 0 &&
+             sums[0].value2 == value.value2 * 10);
+  when.tv_nsec += 20000000;
+  census_window_stats_get_sums(stats, when, result);
+  GPR_ASSERT(compare_double(result[1].count, 20, epsilon) == 0 &&
+             compare_double(sums[1].value1, value.value1 * 20, epsilon) == 0 &&
+             sums[1].value2 == value.value2 * 20);
+  when.tv_sec += 2;
+  census_window_stats_get_sums(stats, when, result);
+  GPR_ASSERT(compare_double(result[2].count, 30, epsilon) == 0 &&
+             compare_double(sums[2].value1, value.value1 * 30, epsilon) == 0 &&
+             sums[2].value2 == value.value2 * 30);
+  when.tv_sec += 72;
+  census_window_stats_get_sums(stats, when, result);
+  GPR_ASSERT(compare_double(result[3].count, 40, epsilon) == 0 &&
+             compare_double(sums[3].value1, value.value1 * 40, epsilon) == 0 &&
+             sums[3].value2 == value.value2 * 40);
+  census_window_stats_destroy(stats);
+}
+
+void rolling_time_test() {
+  const test_stat value = {0.1, 4};
+  gpr_timespec when = {0, 0};
+  census_window_stats_sums result;
+  test_stat sum;
+  int i;
+  gpr_timespec increment = {0, 0};
+  struct census_window_stats* stats =
+      census_window_stats_create(1, &kMinInterval, 7, &kMyStatInfo);
+  GPR_ASSERT(stats != NULL);
+  srand(gpr_now().tv_nsec);
+  for (i = 0; i < 100000; i++) {
+    increment.tv_nsec = rand() % 100000000; /* up to 1/10th second */
+    when = gpr_time_add(when, increment);
+    census_window_stats_add(stats, when, &value);
+  }
+  result.statistic = &sum;
+  census_window_stats_get_sums(stats, when, &result);
+  /* With 1/20th second average between samples, we expect 20*60 = 1200
+     samples on average. Make sure we are within 100 of that. */
+  GPR_ASSERT(compare_double(result.count, 1200, 100) == 0);
+  census_window_stats_destroy(stats);
+}
+#include <stdio.h>
+void infinite_interval_test() {
+  const test_stat value = {0.1, 4};
+  gpr_timespec when = {0, 0};
+  census_window_stats_sums result;
+  test_stat sum;
+  int i;
+  const int count = 100000;
+  gpr_timespec increment = {0, 0};
+  struct census_window_stats* stats =
+      census_window_stats_create(1, &gpr_inf_future, 10, &kMyStatInfo);
+  srand(gpr_now().tv_nsec);
+  for (i = 0; i < count; i++) {
+    increment.tv_sec = rand() % 21600; /* 6 hours */
+    when = gpr_time_add(when, increment);
+    census_window_stats_add(stats, when, &value);
+  }
+  result.statistic = &sum;
+  census_window_stats_get_sums(stats, when, &result);
+  /* The only thing it makes sense to compare for "infinite" periods is the
+     total counts */
+  GPR_ASSERT(result.count == count);
+  census_window_stats_destroy(stats);
+}
+
+int main(int argc, char* argv[]) {
+  grpc_test_init(argc, argv);
+  empty_test();
+  one_interval_test();
+  many_interval_test();
+  rolling_time_test();
+  infinite_interval_test();
+  return 0;
+}
diff --git a/test/core/support/cancellable_test.c b/test/core/support/cancellable_test.c
new file mode 100644
index 0000000..e90c999
--- /dev/null
+++ b/test/core/support/cancellable_test.c
@@ -0,0 +1,160 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Test of gpr_cancellable. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+struct test {
+  gpr_mu mu;
+  gpr_cv cv;
+  gpr_event ev;
+  gpr_event done;
+  gpr_cancellable cancel;
+  int n;
+};
+
+/* A thread body.   Wait until t->cancel is cancelledm then
+   decrement t->n.  If t->n becomes 0, set t->done.  */
+static void thd_body(void *v) {
+  struct test *t = v;
+  gpr_mu_lock(&t->mu);
+  while (!gpr_cv_cancellable_wait(&t->cv, &t->mu, gpr_inf_future, &t->cancel)) {
+  }
+  t->n--;
+  if (t->n == 0) {
+    gpr_event_set(&t->done, (void *)1);
+  }
+  gpr_mu_unlock(&t->mu);
+}
+
+static void test(void) {
+  int i;
+  gpr_thd_id thd;
+  struct test t;
+  int n = 1;
+  gpr_timespec interval;
+
+  gpr_mu_init(&t.mu);
+  gpr_cv_init(&t.cv);
+  gpr_event_init(&t.ev);
+  gpr_event_init(&t.done);
+  gpr_cancellable_init(&t.cancel);
+
+  /* A gpr_cancellable starts not cancelled. */
+  GPR_ASSERT(!gpr_cancellable_is_cancelled(&t.cancel));
+
+  /* Test timeout on event wait for uncancelled gpr_cancellable */
+  interval = gpr_now();
+  gpr_event_cancellable_wait(
+      &t.ev, gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)), &t.cancel);
+  interval = gpr_time_sub(gpr_now(), interval);
+  GPR_ASSERT(gpr_time_cmp(interval, gpr_time_from_micros(500000)) >= 0);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(2000000), interval) >= 0);
+
+  /* Test timeout on cv wait for uncancelled gpr_cancellable */
+  gpr_mu_lock(&t.mu);
+  interval = gpr_now();
+  while (!gpr_cv_cancellable_wait(
+             &t.cv, &t.mu,
+             gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)),
+             &t.cancel)) {
+  }
+  interval = gpr_time_sub(gpr_now(), interval);
+  GPR_ASSERT(gpr_time_cmp(interval, gpr_time_from_micros(500000)) >= 0);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(2000000), interval) >= 0);
+  gpr_mu_unlock(&t.mu);
+
+  /* Create some threads.  They all wait until cancelled; the last to finish
+     sets t.done.  */
+  t.n = n;
+  for (i = 0; i != n; i++) {
+    GPR_ASSERT(gpr_thd_new(&thd, &thd_body, &t, NULL));
+  }
+  /* Check that t.cancel still is not cancelled. */
+  GPR_ASSERT(!gpr_cancellable_is_cancelled(&t.cancel));
+
+  /* Wait a second, and check that no threads have finished waiting. */
+  gpr_mu_lock(&t.mu);
+  gpr_cv_wait(&t.cv, &t.mu,
+              gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)));
+  GPR_ASSERT(t.n == n);
+  gpr_mu_unlock(&t.mu);
+
+  /* Check that t.cancel still is not cancelled, but when
+     cancelled it retports that it is cacncelled. */
+  GPR_ASSERT(!gpr_cancellable_is_cancelled(&t.cancel));
+  gpr_cancellable_cancel(&t.cancel);
+  GPR_ASSERT(gpr_cancellable_is_cancelled(&t.cancel));
+
+  /* Wait for threads to finish. */
+  gpr_event_wait(&t.done, gpr_inf_future);
+  GPR_ASSERT(t.n == 0);
+
+  /* Test timeout on cv wait for cancelled gpr_cancellable */
+  gpr_mu_lock(&t.mu);
+  interval = gpr_now();
+  while (!gpr_cv_cancellable_wait(
+             &t.cv, &t.mu,
+             gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)),
+             &t.cancel)) {
+  }
+  interval = gpr_time_sub(gpr_now(), interval);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(100000), interval) >= 0);
+  gpr_mu_unlock(&t.mu);
+
+  /* Test timeout on event wait for cancelled gpr_cancellable */
+  interval = gpr_now();
+  gpr_event_cancellable_wait(
+      &t.ev, gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)), &t.cancel);
+  interval = gpr_time_sub(gpr_now(), interval);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(100000), interval) >= 0);
+
+  gpr_mu_destroy(&t.mu);
+  gpr_cv_destroy(&t.cv);
+  gpr_cancellable_destroy(&t.cancel);
+}
+
+/* ------------------------------------------------- */
+
+int main(int argc, char *argv[]) {
+  grpc_test_init(argc, argv);
+  test();
+  return 0;
+}
diff --git a/test/core/support/cmdline_test.c b/test/core/support/cmdline_test.c
new file mode 100644
index 0000000..91035a6
--- /dev/null
+++ b/test/core/support/cmdline_test.c
@@ -0,0 +1,293 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/cmdline.h>
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+#include "test/core/util/test_config.h"
+
+#define LOG_TEST() gpr_log(GPR_INFO, "%s", __FUNCTION__)
+
+static void test_simple_int() {
+  int x = 1;
+  gpr_cmdline *cl;
+  char *args[] = {(char *)__FUNCTION__, "-foo", "3"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_int(cl, "foo", NULL, &x);
+  GPR_ASSERT(x == 1);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(x == 3);
+  gpr_cmdline_destroy(cl);
+}
+
+static void test_eq_int() {
+  int x = 1;
+  gpr_cmdline *cl;
+  char *args[] = {(char *)__FUNCTION__, "-foo=3"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_int(cl, "foo", NULL, &x);
+  GPR_ASSERT(x == 1);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(x == 3);
+  gpr_cmdline_destroy(cl);
+}
+
+static void test_2dash_int() {
+  int x = 1;
+  gpr_cmdline *cl;
+  char *args[] = {(char *)__FUNCTION__, "--foo", "3"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_int(cl, "foo", NULL, &x);
+  GPR_ASSERT(x == 1);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(x == 3);
+  gpr_cmdline_destroy(cl);
+}
+
+static void test_2dash_eq_int() {
+  int x = 1;
+  gpr_cmdline *cl;
+  char *args[] = {(char *)__FUNCTION__, "--foo=3"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_int(cl, "foo", NULL, &x);
+  GPR_ASSERT(x == 1);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(x == 3);
+  gpr_cmdline_destroy(cl);
+}
+
+static void test_simple_string() {
+  char *x = NULL;
+  gpr_cmdline *cl;
+  char *args[] = {(char *)__FUNCTION__, "-foo", "3"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_string(cl, "foo", NULL, &x);
+  GPR_ASSERT(x == NULL);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(0 == strcmp(x, "3"));
+  gpr_cmdline_destroy(cl);
+}
+
+static void test_eq_string() {
+  char *x = NULL;
+  gpr_cmdline *cl;
+  char *args[] = {(char *)__FUNCTION__, "-foo=3"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_string(cl, "foo", NULL, &x);
+  GPR_ASSERT(x == NULL);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(0 == strcmp(x, "3"));
+  gpr_cmdline_destroy(cl);
+}
+
+static void test_2dash_string() {
+  char *x = NULL;
+  gpr_cmdline *cl;
+  char *args[] = {(char *)__FUNCTION__, "--foo", "3"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_string(cl, "foo", NULL, &x);
+  GPR_ASSERT(x == NULL);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(0 == strcmp(x, "3"));
+  gpr_cmdline_destroy(cl);
+}
+
+static void test_2dash_eq_string() {
+  char *x = NULL;
+  gpr_cmdline *cl;
+  char *args[] = {(char *)__FUNCTION__, "--foo=3"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_string(cl, "foo", NULL, &x);
+  GPR_ASSERT(x == NULL);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(0 == strcmp(x, "3"));
+  gpr_cmdline_destroy(cl);
+}
+
+static void test_flag_on() {
+  int x = 2;
+  gpr_cmdline *cl;
+  char *args[] = {(char *)__FUNCTION__, "--foo"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_flag(cl, "foo", NULL, &x);
+  GPR_ASSERT(x == 2);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(x == 1);
+  gpr_cmdline_destroy(cl);
+}
+
+static void test_flag_no() {
+  int x = 2;
+  gpr_cmdline *cl;
+  char *args[] = {(char *)__FUNCTION__, "--no-foo"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_flag(cl, "foo", NULL, &x);
+  GPR_ASSERT(x == 2);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(x == 0);
+  gpr_cmdline_destroy(cl);
+}
+
+static void test_flag_val_1() {
+  int x = 2;
+  gpr_cmdline *cl;
+  char *args[] = {(char *)__FUNCTION__, "--foo=1"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_flag(cl, "foo", NULL, &x);
+  GPR_ASSERT(x == 2);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(x == 1);
+  gpr_cmdline_destroy(cl);
+}
+
+static void test_flag_val_0() {
+  int x = 2;
+  gpr_cmdline *cl;
+  char *args[] = {(char *)__FUNCTION__, "--foo=0"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_flag(cl, "foo", NULL, &x);
+  GPR_ASSERT(x == 2);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(x == 0);
+  gpr_cmdline_destroy(cl);
+}
+
+static void test_flag_val_true() {
+  int x = 2;
+  gpr_cmdline *cl;
+  char *args[] = {(char *)__FUNCTION__, "--foo=true"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_flag(cl, "foo", NULL, &x);
+  GPR_ASSERT(x == 2);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(x == 1);
+  gpr_cmdline_destroy(cl);
+}
+
+static void test_flag_val_false() {
+  int x = 2;
+  gpr_cmdline *cl;
+  char *args[] = {(char *)__FUNCTION__, "--foo=false"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_flag(cl, "foo", NULL, &x);
+  GPR_ASSERT(x == 2);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(x == 0);
+  gpr_cmdline_destroy(cl);
+}
+
+static void test_many() {
+  char *str = NULL;
+  int x = 0;
+  int flag = 2;
+  gpr_cmdline *cl;
+
+  char *args[] = {(char *)__FUNCTION__, "--str", "hello", "-x=4", "-no-flag"};
+
+  LOG_TEST();
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_string(cl, "str", NULL, &str);
+  gpr_cmdline_add_int(cl, "x", NULL, &x);
+  gpr_cmdline_add_flag(cl, "flag", NULL, &flag);
+  gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+  GPR_ASSERT(x == 4);
+  GPR_ASSERT(0 == strcmp(str, "hello"));
+  GPR_ASSERT(flag == 0);
+  gpr_cmdline_destroy(cl);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_simple_int();
+  test_eq_int();
+  test_2dash_int();
+  test_2dash_eq_int();
+  test_simple_string();
+  test_eq_string();
+  test_2dash_string();
+  test_2dash_eq_string();
+  test_flag_on();
+  test_flag_no();
+  test_flag_val_1();
+  test_flag_val_0();
+  test_flag_val_true();
+  test_flag_val_false();
+  test_many();
+  return 0;
+}
diff --git a/test/core/support/histogram_test.c b/test/core/support/histogram_test.c
new file mode 100644
index 0000000..3b5fd73
--- /dev/null
+++ b/test/core/support/histogram_test.c
@@ -0,0 +1,178 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/histogram.h>
+#include <grpc/support/log.h>
+
+#define LOG_TEST() gpr_log(GPR_INFO, "%s", __FUNCTION__);
+
+static void test_no_op() {
+  gpr_histogram_destroy(gpr_histogram_create(0.01, 60e9));
+}
+
+static void expect_percentile(gpr_histogram *h, double percentile,
+                              double min_expect, double max_expect) {
+  double got = gpr_histogram_percentile(h, percentile);
+  gpr_log(GPR_INFO, "@%f%%, expect %f <= %f <= %f", percentile, min_expect, got,
+          max_expect);
+  GPR_ASSERT(min_expect <= got);
+  GPR_ASSERT(got <= max_expect);
+}
+
+static void test_simple() {
+  gpr_histogram *h;
+
+  LOG_TEST();
+
+  h = gpr_histogram_create(0.01, 60e9);
+  gpr_histogram_add(h, 10000);
+  gpr_histogram_add(h, 10000);
+  gpr_histogram_add(h, 11000);
+  gpr_histogram_add(h, 11000);
+
+  expect_percentile(h, 50, 10001, 10999);
+  GPR_ASSERT(gpr_histogram_mean(h) == 10500);
+
+  gpr_histogram_destroy(h);
+}
+
+static void test_percentile() {
+  gpr_histogram *h;
+  double last;
+  double i;
+  double cur;
+
+  LOG_TEST();
+
+  h = gpr_histogram_create(0.05, 1e9);
+  gpr_histogram_add(h, 2.5);
+  gpr_histogram_add(h, 2.5);
+  gpr_histogram_add(h, 8);
+  gpr_histogram_add(h, 4);
+
+  GPR_ASSERT(gpr_histogram_count(h) == 4);
+  GPR_ASSERT(gpr_histogram_minimum(h) == 2.5);
+  GPR_ASSERT(gpr_histogram_maximum(h) == 8);
+  GPR_ASSERT(gpr_histogram_sum(h) == 17);
+  GPR_ASSERT(gpr_histogram_sum_of_squares(h) == 92.5);
+  GPR_ASSERT(gpr_histogram_mean(h) == 4.25);
+  GPR_ASSERT(gpr_histogram_variance(h) == 5.0625);
+  GPR_ASSERT(gpr_histogram_stddev(h) == 2.25);
+
+  expect_percentile(h, -10, 2.5, 2.5);
+  expect_percentile(h, 0, 2.5, 2.5);
+  expect_percentile(h, 12.5, 2.5, 2.5);
+  expect_percentile(h, 25, 2.5, 2.5);
+  expect_percentile(h, 37.5, 2.5, 2.8);
+  expect_percentile(h, 50, 3.0, 3.5);
+  expect_percentile(h, 62.5, 3.5, 4.5);
+  expect_percentile(h, 75, 5, 7.9);
+  expect_percentile(h, 100, 8, 8);
+  expect_percentile(h, 110, 8, 8);
+
+  /* test monotonicity */
+  last = 0.0;
+  for (i = 0; i < 100.0; i += 0.01) {
+    cur = gpr_histogram_percentile(h, i);
+    GPR_ASSERT(cur >= last);
+    last = cur;
+  }
+
+  gpr_histogram_destroy(h);
+}
+
+static void test_merge() {
+  gpr_histogram *h1, *h2;
+  double last;
+  double i;
+  double cur;
+
+  LOG_TEST();
+
+  h1 = gpr_histogram_create(0.05, 1e9);
+  gpr_histogram_add(h1, 2.5);
+  gpr_histogram_add(h1, 2.5);
+  gpr_histogram_add(h1, 8);
+  gpr_histogram_add(h1, 4);
+
+  h2 = gpr_histogram_create(0.01, 1e9);
+  GPR_ASSERT(gpr_histogram_merge(h1, h2) == 0);
+  gpr_histogram_destroy(h2);
+
+  h2 = gpr_histogram_create(0.05, 1e10);
+  GPR_ASSERT(gpr_histogram_merge(h1, h2) == 0);
+  gpr_histogram_destroy(h2);
+
+  h2 = gpr_histogram_create(0.05, 1e9);
+  GPR_ASSERT(gpr_histogram_merge(h1, h2) == 1);
+  GPR_ASSERT(gpr_histogram_count(h1) == 4);
+  GPR_ASSERT(gpr_histogram_minimum(h1) == 2.5);
+  GPR_ASSERT(gpr_histogram_maximum(h1) == 8);
+  GPR_ASSERT(gpr_histogram_sum(h1) == 17);
+  GPR_ASSERT(gpr_histogram_sum_of_squares(h1) == 92.5);
+  GPR_ASSERT(gpr_histogram_mean(h1) == 4.25);
+  GPR_ASSERT(gpr_histogram_variance(h1) == 5.0625);
+  GPR_ASSERT(gpr_histogram_stddev(h1) == 2.25);
+  gpr_histogram_destroy(h2);
+
+  h2 = gpr_histogram_create(0.05, 1e9);
+  gpr_histogram_add(h2, 7.0);
+  gpr_histogram_add(h2, 17.0);
+  gpr_histogram_add(h2, 1.0);
+  GPR_ASSERT(gpr_histogram_merge(h1, h2) == 1);
+  GPR_ASSERT(gpr_histogram_count(h1) == 7);
+  GPR_ASSERT(gpr_histogram_minimum(h1) == 1.0);
+  GPR_ASSERT(gpr_histogram_maximum(h1) == 17.0);
+  GPR_ASSERT(gpr_histogram_sum(h1) == 42.0);
+  GPR_ASSERT(gpr_histogram_sum_of_squares(h1) == 431.5);
+  GPR_ASSERT(gpr_histogram_mean(h1) == 6.0);
+
+  /* test monotonicity */
+  last = 0.0;
+  for (i = 0; i < 100.0; i += 0.01) {
+    cur = gpr_histogram_percentile(h1, i);
+    GPR_ASSERT(cur >= last);
+    last = cur;
+  }
+
+  gpr_histogram_destroy(h1);
+  gpr_histogram_destroy(h2);
+}
+
+int main(void) {
+  test_no_op();
+  test_simple();
+  test_percentile();
+  test_merge();
+  return 0;
+}
diff --git a/test/core/support/host_port_test.c b/test/core/support/host_port_test.c
new file mode 100644
index 0000000..d1553c5
--- /dev/null
+++ b/test/core/support/host_port_test.c
@@ -0,0 +1,72 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+static void join_host_port_expect(const char *host, int port,
+                                  const char *expected) {
+  char *buf;
+  int len;
+  len = gpr_join_host_port(&buf, host, port);
+  GPR_ASSERT(strlen(expected) == len);
+  GPR_ASSERT(strcmp(expected, buf) == 0);
+  gpr_free(buf);
+}
+
+static void test_join_host_port() {
+  join_host_port_expect("foo", 101, "foo:101");
+  join_host_port_expect("", 102, ":102");
+  join_host_port_expect("1::2", 103, "[1::2]:103");
+  join_host_port_expect("[::1]", 104, "[::1]:104");
+}
+
+/* Garbage in, garbage out. */
+static void test_join_host_port_garbage() {
+  join_host_port_expect("[foo]", 105, "[foo]:105");
+  join_host_port_expect("[::", 106, "[:::106");
+  join_host_port_expect("::]", 107, "[::]]:107");
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+
+  test_join_host_port();
+  test_join_host_port_garbage();
+
+  return 0;
+}
diff --git a/test/core/support/log_test.c b/test/core/support/log_test.c
new file mode 100644
index 0000000..fbb7c21
--- /dev/null
+++ b/test/core/support/log_test.c
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  /* test logging at various verbosity levels */
+  gpr_log(GPR_DEBUG, "%s", "hello world");
+  gpr_log(GPR_INFO, "%s", "hello world");
+  gpr_log(GPR_ERROR, "%s", "hello world");
+  /* should succeed */
+  GPR_ASSERT(1);
+  /* TODO(ctiller): should we add a GPR_ASSERT failure test here */
+  return 0;
+}
diff --git a/test/core/support/murmur_hash_test.c b/test/core/support/murmur_hash_test.c
new file mode 100644
index 0000000..366bcb2
--- /dev/null
+++ b/test/core/support/murmur_hash_test.c
@@ -0,0 +1,87 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/support/murmur_hash.h"
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+#include <string.h>
+
+typedef gpr_uint32 (*hash_func)(const void *key, size_t len, gpr_uint32 seed);
+
+/* From smhasher:
+   This should hopefully be a thorough and uambiguous test of whether a hash
+   is correctly implemented on a given platform */
+
+static void verification_test(hash_func hash, gpr_uint32 expected) {
+  gpr_uint8 key[256];
+  gpr_uint32 hashes[256];
+  gpr_uint32 final = 0;
+  int i;
+
+  memset(key, 0, sizeof(key));
+  memset(hashes, 0, sizeof(hashes));
+
+  /* Hash keys of the form {0}, {0,1}, {0,1,2}... up to N=255,using 256-N as
+     the seed */
+
+  for (i = 0; i < 256; i++) {
+    key[i] = (uint8_t)i;
+    hashes[i] = hash(key, i, 256 - i);
+  }
+
+  /* Then hash the result array */
+
+  final = hash(hashes, sizeof(hashes), 0);
+
+  /* The first four bytes of that hash, interpreted as a little-endian integer,
+     is our
+     verification value */
+
+  if (expected != final) {
+    gpr_log(GPR_INFO, "Verification value 0x%08X : Failed! (Expected 0x%08x)",
+            final, expected);
+    abort();
+  } else {
+    gpr_log(GPR_INFO, "Verification value 0x%08X : Passed!", final);
+  }
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  /* basic tests to verify that things don't crash */
+  gpr_murmur_hash3("", 0, 0);
+  gpr_murmur_hash3("xyz", 3, 0);
+  verification_test(gpr_murmur_hash3, 0xB0F57EE3);
+  return 0;
+}
diff --git a/test/core/support/slice_buffer_test.c b/test/core/support/slice_buffer_test.c
new file mode 100644
index 0000000..030d1d4
--- /dev/null
+++ b/test/core/support/slice_buffer_test.c
@@ -0,0 +1,70 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+#include "test/core/util/test_config.h"
+
+int main(int argc, char **argv) {
+  gpr_slice_buffer buf;
+  gpr_slice aaa = gpr_slice_from_copied_string("aaa");
+  gpr_slice bb = gpr_slice_from_copied_string("bb");
+  size_t i;
+
+  grpc_test_init(argc, argv);
+  gpr_slice_buffer_init(&buf);
+  for (i = 0; i < 10; i++) {
+    gpr_slice_ref(aaa);
+    gpr_slice_ref(bb);
+    gpr_slice_buffer_add(&buf, aaa);
+    gpr_slice_buffer_add(&buf, bb);
+  }
+  GPR_ASSERT(buf.count > 0);
+  GPR_ASSERT(buf.length == 50);
+  gpr_slice_buffer_reset_and_unref(&buf);
+  GPR_ASSERT(buf.count == 0);
+  GPR_ASSERT(buf.length == 0);
+  for (i = 0; i < 10; i++) {
+    gpr_slice_ref(aaa);
+    gpr_slice_ref(bb);
+    gpr_slice_buffer_add(&buf, aaa);
+    gpr_slice_buffer_add(&buf, bb);
+  }
+  GPR_ASSERT(buf.count > 0);
+  GPR_ASSERT(buf.length == 50);
+  gpr_slice_unref(aaa);
+  gpr_slice_unref(bb);
+  gpr_slice_buffer_destroy(&buf);
+
+  return 0;
+}
diff --git a/test/core/support/slice_test.c b/test/core/support/slice_test.c
new file mode 100644
index 0000000..4044034
--- /dev/null
+++ b/test/core/support/slice_test.c
@@ -0,0 +1,227 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/slice.h>
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+#define LOG_TEST_NAME() gpr_log(GPR_INFO, "%s", __FUNCTION__);
+
+static void test_slice_malloc_returns_something_sensible() {
+  /* Calls gpr_slice_create for various lengths and verifies the internals for
+     consistency. */
+  size_t length;
+  size_t i;
+  gpr_slice slice;
+
+  LOG_TEST_NAME();
+
+  for (length = 0; length <= 1024; length++) {
+    slice = gpr_slice_malloc(length);
+    /* If there is a length, slice.data must be non-NULL. If length is zero
+       we don't care. */
+    if (length) {
+      GPR_ASSERT(GPR_SLICE_START_PTR(slice));
+    }
+    /* Returned slice length must be what was requested. */
+    GPR_ASSERT(GPR_SLICE_LENGTH(slice) == length);
+    /* If the slice has a refcount, it must be destroyable. */
+    if (slice.refcount) {
+      GPR_ASSERT(slice.refcount->ref != NULL);
+      GPR_ASSERT(slice.refcount->unref != NULL);
+    }
+    /* We must be able to write to every byte of the data */
+    for (i = 0; i < length; i++) {
+      GPR_SLICE_START_PTR(slice)[i] = (char)i;
+    }
+    /* And finally we must succeed in destroying the slice */
+    gpr_slice_unref(slice);
+  }
+}
+
+static void do_nothing(void *ignored) {}
+
+static void test_slice_new_returns_something_sensible() {
+  gpr_uint8 x;
+
+  gpr_slice slice = gpr_slice_new(&x, 1, do_nothing);
+  GPR_ASSERT(slice.refcount);
+  GPR_ASSERT(slice.data.refcounted.bytes == &x);
+  GPR_ASSERT(slice.data.refcounted.length == 1);
+  gpr_slice_unref(slice);
+}
+
+static int do_nothing_with_len_1_calls = 0;
+
+static void do_nothing_with_len_1(void *ignored, size_t len) {
+  GPR_ASSERT(len == 1);
+  do_nothing_with_len_1_calls++;
+}
+
+static void test_slice_new_with_len_returns_something_sensible() {
+  gpr_uint8 x;
+
+  gpr_slice slice = gpr_slice_new_with_len(&x, 1, do_nothing_with_len_1);
+  GPR_ASSERT(slice.refcount);
+  GPR_ASSERT(slice.data.refcounted.bytes == &x);
+  GPR_ASSERT(slice.data.refcounted.length == 1);
+  GPR_ASSERT(do_nothing_with_len_1_calls == 0);
+  gpr_slice_unref(slice);
+  GPR_ASSERT(do_nothing_with_len_1_calls == 1);
+}
+
+static void test_slice_sub_works(int length) {
+  gpr_slice slice;
+  gpr_slice sub;
+  int i, j, k;
+
+  LOG_TEST_NAME();
+  gpr_log(GPR_INFO, "length=%d", length);
+
+  /* Create a slice in which each byte is equal to the distance from it to the
+     beginning of the slice. */
+  slice = gpr_slice_malloc(length);
+  for (i = 0; i < length; i++) {
+    GPR_SLICE_START_PTR(slice)[i] = i;
+  }
+
+  /* Ensure that for all subsets length is correct and that we start on the
+     correct byte. Additionally check that no copies were made. */
+  for (i = 0; i < length; i++) {
+    for (j = i; j < length; j++) {
+      sub = gpr_slice_sub(slice, i, j);
+      GPR_ASSERT(GPR_SLICE_LENGTH(sub) == j - i);
+      for (k = 0; k < j - i; k++) {
+        GPR_ASSERT(GPR_SLICE_START_PTR(sub)[k] == (gpr_uint8)(i + k));
+      }
+      gpr_slice_unref(sub);
+    }
+  }
+  gpr_slice_unref(slice);
+}
+
+static void check_head_tail(gpr_slice slice, gpr_slice head, gpr_slice tail) {
+  GPR_ASSERT(GPR_SLICE_LENGTH(slice) ==
+             GPR_SLICE_LENGTH(head) + GPR_SLICE_LENGTH(tail));
+  GPR_ASSERT(0 == memcmp(GPR_SLICE_START_PTR(slice), GPR_SLICE_START_PTR(head),
+                         GPR_SLICE_LENGTH(head)));
+  GPR_ASSERT(0 == memcmp(GPR_SLICE_START_PTR(slice) + GPR_SLICE_LENGTH(head),
+                         GPR_SLICE_START_PTR(tail), GPR_SLICE_LENGTH(tail)));
+}
+
+static void test_slice_split_head_works(int length) {
+  gpr_slice slice;
+  gpr_slice head, tail;
+  int i;
+
+  LOG_TEST_NAME();
+  gpr_log(GPR_INFO, "length=%d", length);
+
+  /* Create a slice in which each byte is equal to the distance from it to the
+     beginning of the slice. */
+  slice = gpr_slice_malloc(length);
+  for (i = 0; i < length; i++) {
+    GPR_SLICE_START_PTR(slice)[i] = i;
+  }
+
+  /* Ensure that for all subsets length is correct and that we start on the
+     correct byte. Additionally check that no copies were made. */
+  for (i = 0; i < length; i++) {
+    tail = gpr_slice_ref(slice);
+    head = gpr_slice_split_head(&tail, i);
+    check_head_tail(slice, head, tail);
+    gpr_slice_unref(tail);
+    gpr_slice_unref(head);
+  }
+
+  gpr_slice_unref(slice);
+}
+
+static void test_slice_split_tail_works(int length) {
+  gpr_slice slice;
+  gpr_slice head, tail;
+  int i;
+
+  LOG_TEST_NAME();
+  gpr_log(GPR_INFO, "length=%d", length);
+
+  /* Create a slice in which each byte is equal to the distance from it to the
+     beginning of the slice. */
+  slice = gpr_slice_malloc(length);
+  for (i = 0; i < length; i++) {
+    GPR_SLICE_START_PTR(slice)[i] = i;
+  }
+
+  /* Ensure that for all subsets length is correct and that we start on the
+     correct byte. Additionally check that no copies were made. */
+  for (i = 0; i < length; i++) {
+    head = gpr_slice_ref(slice);
+    tail = gpr_slice_split_tail(&head, i);
+    check_head_tail(slice, head, tail);
+    gpr_slice_unref(tail);
+    gpr_slice_unref(head);
+  }
+
+  gpr_slice_unref(slice);
+}
+
+static void test_slice_from_copied_string_works() {
+  static const char *text = "HELLO WORLD!";
+  gpr_slice slice;
+
+  LOG_TEST_NAME();
+
+  slice = gpr_slice_from_copied_string(text);
+  GPR_ASSERT(strlen(text) == GPR_SLICE_LENGTH(slice));
+  GPR_ASSERT(0 ==
+             memcmp(text, GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice)));
+  gpr_slice_unref(slice);
+}
+
+int main(int argc, char **argv) {
+  int length;
+  grpc_test_init(argc, argv);
+  test_slice_malloc_returns_something_sensible();
+  test_slice_new_returns_something_sensible();
+  test_slice_new_with_len_returns_something_sensible();
+  for (length = 0; length < 128; length++) {
+    test_slice_sub_works(length);
+    test_slice_split_head_works(length);
+    test_slice_split_tail_works(length);
+  }
+  test_slice_from_copied_string_works();
+  return 0;
+}
diff --git a/test/core/support/string_test.c b/test/core/support/string_test.c
new file mode 100644
index 0000000..1e8039b
--- /dev/null
+++ b/test/core/support/string_test.c
@@ -0,0 +1,158 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/string.h>
+
+#include <stddef.h>
+#include <stdlib.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"
+
+#define LOG_TEST_NAME() gpr_log(GPR_INFO, "%s", __FUNCTION__)
+
+static void test_strdup() {
+  static const char *src1 = "hello world";
+  char *dst1;
+
+  LOG_TEST_NAME();
+
+  dst1 = gpr_strdup(src1);
+  GPR_ASSERT(0 == strcmp(src1, dst1));
+  gpr_free(dst1);
+
+  GPR_ASSERT(NULL == gpr_strdup(NULL));
+}
+
+static void expect_hexdump(const char *buf, size_t len, gpr_uint32 flags,
+                           const char *result) {
+  char *got = gpr_hexdump(buf, len, flags);
+  GPR_ASSERT(0 == strcmp(got, result));
+  gpr_free(got);
+}
+
+static void test_hexdump() {
+  LOG_TEST_NAME();
+  expect_hexdump("\x01", 1, 0, "01");
+  expect_hexdump("\x01", 1, GPR_HEXDUMP_PLAINTEXT, "01 '.'");
+  expect_hexdump("\x01\x02", 2, 0, "01 02");
+  expect_hexdump("\x01\x23\x45\x67\x89\xab\xcd\xef", 8, 0,
+                 "01 23 45 67 89 ab cd ef");
+  expect_hexdump("ab", 2, GPR_HEXDUMP_PLAINTEXT, "61 62 'ab'");
+}
+
+static void test_pu32_fail(const char *s) {
+  gpr_uint32 out;
+  GPR_ASSERT(!gpr_parse_bytes_to_uint32(s, strlen(s), &out));
+}
+
+static void test_pu32_succeed(const char *s, gpr_uint32 want) {
+  gpr_uint32 out;
+  GPR_ASSERT(gpr_parse_bytes_to_uint32(s, strlen(s), &out));
+  GPR_ASSERT(out == want);
+}
+
+static void test_parse_uint32() {
+  LOG_TEST_NAME();
+
+  test_pu32_fail("-1");
+  test_pu32_fail("a");
+  test_pu32_fail("");
+  test_pu32_succeed("0", 0);
+  test_pu32_succeed("1", 1);
+  test_pu32_succeed("2", 2);
+  test_pu32_succeed("3", 3);
+  test_pu32_succeed("4", 4);
+  test_pu32_succeed("5", 5);
+  test_pu32_succeed("6", 6);
+  test_pu32_succeed("7", 7);
+  test_pu32_succeed("8", 8);
+  test_pu32_succeed("9", 9);
+  test_pu32_succeed("10", 10);
+  test_pu32_succeed("11", 11);
+  test_pu32_succeed("12", 12);
+  test_pu32_succeed("13", 13);
+  test_pu32_succeed("14", 14);
+  test_pu32_succeed("15", 15);
+  test_pu32_succeed("16", 16);
+  test_pu32_succeed("17", 17);
+  test_pu32_succeed("18", 18);
+  test_pu32_succeed("19", 19);
+  test_pu32_succeed("1234567890", 1234567890);
+  test_pu32_succeed("4294967295", 4294967295u);
+  test_pu32_fail("4294967296");
+  test_pu32_fail("4294967297");
+  test_pu32_fail("4294967298");
+  test_pu32_fail("4294967299");
+}
+
+static void test_asprintf() {
+  char *buf;
+  int i, j;
+
+  LOG_TEST_NAME();
+
+  /* Print an empty string. */
+  GPR_ASSERT(gpr_asprintf(&buf, "") == 0);
+  GPR_ASSERT(buf[0] == '\0');
+  gpr_free(buf);
+
+  /* Print an invalid format. */
+  GPR_ASSERT(gpr_asprintf(&buf, "%") == -1);
+  GPR_ASSERT(buf == NULL);
+
+  /* Print strings of various lengths. */
+  for (i = 1; i < 100; i++) {
+    GPR_ASSERT(gpr_asprintf(&buf, "%0*d", i, 1) == i);
+
+    /* The buffer should resemble "000001\0". */
+    for (j = 0; j < i - 2; j++) {
+      GPR_ASSERT(buf[j] == '0');
+    }
+    GPR_ASSERT(buf[i - 1] == '1');
+    GPR_ASSERT(buf[i] == '\0');
+    gpr_free(buf);
+  }
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_strdup();
+  test_hexdump();
+  test_parse_uint32();
+  test_asprintf();
+  return 0;
+}
diff --git a/test/core/support/sync_test.c b/test/core/support/sync_test.c
new file mode 100644
index 0000000..93f9c4c
--- /dev/null
+++ b/test/core/support/sync_test.c
@@ -0,0 +1,451 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Test of gpr synchronization support. */
+
+#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 "test/core/util/test_config.h"
+
+/* ==================Example use of interface===================
+
+   A producer-consumer queue of up to N integers,
+   illustrating the use of the calls in this interface.  */
+
+#define N 4
+
+typedef struct queue {
+  gpr_cv non_empty; /* Signalled when length becomes non-zero. */
+  gpr_cv non_full;  /* Signalled when length becomes non-N. */
+  gpr_mu mu;        /* Protects all fields below.
+                        (That is, except during initialization or
+                        destruction, the fields below should be accessed
+                        only by a thread that holds mu.) */
+  int head;         /* Index of head of queue 0..N-1. */
+  int length;       /* Number of valid elements in queue 0..N. */
+  int elem[N];      /* elem[head .. head+length-1] are queue elements. */
+} queue;
+
+/* Initialize *q. */
+void queue_init(queue *q) {
+  gpr_mu_init(&q->mu);
+  gpr_cv_init(&q->non_empty);
+  gpr_cv_init(&q->non_full);
+  q->head = 0;
+  q->length = 0;
+}
+
+/* Free storage associated with *q. */
+void queue_destroy(queue *q) {
+  gpr_mu_destroy(&q->mu);
+  gpr_cv_destroy(&q->non_empty);
+  gpr_cv_destroy(&q->non_full);
+}
+
+/* Wait until there is room in *q, then append x to *q. */
+void queue_append(queue *q, int x) {
+  gpr_mu_lock(&q->mu);
+  /* To wait for a predicate without a deadline, loop on the negation of the
+     predicate, and use gpr_cv_wait(..., gpr_inf_future) inside the loop
+     to release the lock, wait, and reacquire on each iteration.  Code that
+     makes the condition true should use gpr_cv_broadcast() on the
+     corresponding condition variable.  The predicate must be on state
+     protected by the lock.  */
+  while (q->length == N) {
+    gpr_cv_wait(&q->non_full, &q->mu, gpr_inf_future);
+  }
+  if (q->length == 0) { /* Wake threads blocked in queue_remove(). */
+    /* It's normal to use gpr_cv_broadcast() or gpr_signal() while
+       holding the lock. */
+    gpr_cv_broadcast(&q->non_empty);
+  }
+  q->elem[(q->head + q->length) % N] = x;
+  q->length++;
+  gpr_mu_unlock(&q->mu);
+}
+
+/* If it can be done without blocking, append x to *q and return non-zero.
+   Otherwise return 0. */
+int queue_try_append(queue *q, int x) {
+  int result = 0;
+  if (gpr_mu_trylock(&q->mu)) {
+    if (q->length != N) {
+      if (q->length == 0) { /* Wake threads blocked in queue_remove(). */
+        gpr_cv_broadcast(&q->non_empty);
+      }
+      q->elem[(q->head + q->length) % N] = x;
+      q->length++;
+      result = 1;
+    }
+    gpr_mu_unlock(&q->mu);
+  }
+  return result;
+}
+
+/* Wait until the *q is non-empty or deadline abs_deadline passes.  If the
+   queue is non-empty, remove its head entry, place it in *head, and return
+   non-zero.  Otherwise return 0.  */
+int queue_remove(queue *q, int *head, gpr_timespec abs_deadline) {
+  int result = 0;
+  gpr_mu_lock(&q->mu);
+  /* To wait for a predicate with a deadline, loop on the negation of the
+     predicate or until gpr_cv_wait() returns true.  Code that makes
+     the condition true should use gpr_cv_broadcast() on the corresponding
+     condition variable.  The predicate must be on state protected by the
+     lock. */
+  while (q->length == 0 && !gpr_cv_wait(&q->non_empty, &q->mu, abs_deadline)) {
+  }
+  if (q->length != 0) { /* Queue is non-empty. */
+    result = 1;
+    if (q->length == N) { /* Wake threads blocked in queue_append(). */
+      gpr_cv_broadcast(&q->non_full);
+    }
+    *head = q->elem[q->head];
+    q->head = (q->head + 1) % N;
+    q->length--;
+  } /* else deadline exceeded */
+  gpr_mu_unlock(&q->mu);
+  return result;
+}
+
+/* ------------------------------------------------- */
+/* Tests for gpr_mu and gpr_cv, and the queue example. */
+struct test {
+  int threads; /* number of threads */
+
+  gpr_int64 iterations; /* number of iterations per thread */
+  gpr_int64 counter;
+  int thread_count; /* used to allocate thread ids */
+  int done;         /* threads not yet completed */
+
+  gpr_mu mu; /* protects iterations, counter, thread_count, done */
+
+  gpr_cv cv; /* signalling depends on test */
+
+  gpr_cv done_cv; /* signalled when done == 0 */
+
+  queue q;
+
+  gpr_stats_counter stats_counter;
+
+  gpr_refcount refcount;
+  gpr_refcount thread_refcount;
+  gpr_event event;
+};
+
+/* Return pointer to a new struct test. */
+static struct test *test_new(int threads, gpr_int64 iterations) {
+  struct test *m = gpr_malloc(sizeof(*m));
+  m->threads = threads;
+  m->iterations = iterations;
+  m->counter = 0;
+  m->thread_count = 0;
+  m->done = threads;
+  gpr_mu_init(&m->mu);
+  gpr_cv_init(&m->cv);
+  gpr_cv_init(&m->done_cv);
+  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_event_init(&m->event);
+  return m;
+}
+
+/* Return pointer to a new struct test. */
+static void test_destroy(struct test *m) {
+  gpr_mu_destroy(&m->mu);
+  gpr_cv_destroy(&m->cv);
+  gpr_cv_destroy(&m->done_cv);
+  queue_destroy(&m->q);
+  gpr_free(m);
+}
+
+/* Create m->threads 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, body, m, NULL));
+  }
+}
+
+/* Wait until all threads report done. */
+static void test_wait(struct test *m) {
+  gpr_mu_lock(&m->mu);
+  while (m->done != 0) {
+    gpr_cv_wait(&m->done_cv, &m->mu, gpr_inf_future);
+  }
+  gpr_mu_unlock(&m->mu);
+}
+
+/* Get an integer thread id in the raneg 0..threads-1 */
+static int thread_id(struct test *m) {
+  int id;
+  gpr_mu_lock(&m->mu);
+  id = m->thread_count++;
+  gpr_mu_unlock(&m->mu);
+  return id;
+}
+
+/* Indicate that a thread is done, by decrementing m->done
+   and signalling done_cv if m->done==0. */
+static void mark_thread_done(struct test *m) {
+  gpr_mu_lock(&m->mu);
+  GPR_ASSERT(m->done != 0);
+  m->done--;
+  if (m->done == 0) {
+    gpr_cv_signal(&m->done_cv);
+  }
+  gpr_mu_unlock(&m->mu);
+}
+
+/* Test several threads running (*body)(struct test *m) for increasing settings
+   of m->iterations, until about timeout_s to 2*timeout_s seconds have elapsed.
+   If extra!=NULL, run (*extra)(m) in an additional thread.  */
+static void test(const char *name, void (*body)(void *m),
+                 void (*extra)(void *m), int timeout_s) {
+  gpr_int64 iterations = 1024;
+  struct test *m;
+  gpr_timespec start = gpr_now();
+  gpr_timespec time_taken;
+  gpr_timespec deadline =
+      gpr_time_add(start, gpr_time_from_micros(timeout_s * 1000000));
+  fprintf(stderr, "%s:", name);
+  while (gpr_time_cmp(gpr_now(), deadline) < 0) {
+    iterations <<= 1;
+    fprintf(stderr, " %ld", (long)iterations);
+    m = test_new(10, iterations);
+    if (extra != NULL) {
+      gpr_thd_id id;
+      GPR_ASSERT(gpr_thd_new(&id, extra, m, NULL));
+      m->done++; /* one more thread to wait for */
+    }
+    test_create_threads(m, body);
+    test_wait(m);
+    if (m->counter != m->threads * m->iterations) {
+      fprintf(stderr, "counter %ld  threads %d  iterations %ld\n",
+              (long)m->counter, m->threads, (long)m->iterations);
+      GPR_ASSERT(0);
+    }
+    test_destroy(m);
+  }
+  time_taken = gpr_time_sub(gpr_now(), start);
+  fprintf(stderr, " done %ld.%09d s\n", (long)time_taken.tv_sec,
+          (int)time_taken.tv_nsec);
+}
+
+/* Increment m->counter on each iteration; then mark thread as done.  */
+static void inc(void *v /*=m*/) {
+  struct test *m = v;
+  gpr_int64 i;
+  for (i = 0; i != m->iterations; i++) {
+    gpr_mu_lock(&m->mu);
+    m->counter++;
+    gpr_mu_unlock(&m->mu);
+  }
+  mark_thread_done(m);
+}
+
+/* Increment m->counter under lock acquired with trylock, m->iterations times;
+   then mark thread as done.  */
+static void inctry(void *v /*=m*/) {
+  struct test *m = v;
+  gpr_int64 i;
+  for (i = 0; i != m->iterations;) {
+    if (gpr_mu_trylock(&m->mu)) {
+      m->counter++;
+      gpr_mu_unlock(&m->mu);
+      i++;
+    }
+  }
+  mark_thread_done(m);
+}
+
+/* Increment counter only when (m->counter%m->threads)==m->thread_id; then mark
+   thread as done.  */
+static void inc_by_turns(void *v /*=m*/) {
+  struct test *m = v;
+  gpr_int64 i;
+  int id = thread_id(m);
+  for (i = 0; i != m->iterations; i++) {
+    gpr_mu_lock(&m->mu);
+    while ((m->counter % m->threads) != id) {
+      gpr_cv_wait(&m->cv, &m->mu, gpr_inf_future);
+    }
+    m->counter++;
+    gpr_cv_broadcast(&m->cv);
+    gpr_mu_unlock(&m->mu);
+  }
+  mark_thread_done(m);
+}
+
+/* Wait a millisecond and increment counter on each iteration;
+   then mark thread as done. */
+static void inc_with_1ms_delay(void *v /*=m*/) {
+  struct test *m = v;
+  gpr_int64 i;
+  for (i = 0; i != m->iterations; i++) {
+    gpr_timespec deadline;
+    gpr_mu_lock(&m->mu);
+    deadline = gpr_time_add(gpr_now(), gpr_time_from_micros(1000));
+    while (!gpr_cv_wait(&m->cv, &m->mu, deadline)) {
+    }
+    m->counter++;
+    gpr_mu_unlock(&m->mu);
+  }
+  mark_thread_done(m);
+}
+
+/* Wait a millisecond and increment counter on each iteration, using an event
+   for timing; then mark thread as done. */
+static void inc_with_1ms_delay_event(void *v /*=m*/) {
+  struct test *m = v;
+  gpr_int64 i;
+  for (i = 0; i != m->iterations; i++) {
+    gpr_timespec deadline;
+    deadline = gpr_time_add(gpr_now(), gpr_time_from_micros(1000));
+    GPR_ASSERT(gpr_event_wait(&m->event, deadline) == NULL);
+    gpr_mu_lock(&m->mu);
+    m->counter++;
+    gpr_mu_unlock(&m->mu);
+  }
+  mark_thread_done(m);
+}
+
+/* Produce m->iterations elements on queue m->q, then mark thread as done.
+   Even threads use queue_append(), and odd threads use queue_try_append()
+   until it succeeds. */
+static void many_producers(void *v /*=m*/) {
+  struct test *m = v;
+  gpr_int64 i;
+  int x = thread_id(m);
+  if ((x & 1) == 0) {
+    for (i = 0; i != m->iterations; i++) {
+      queue_append(&m->q, 1);
+    }
+  } else {
+    for (i = 0; i != m->iterations; i++) {
+      while (!queue_try_append(&m->q, 1)) {
+      }
+    }
+  }
+  mark_thread_done(m);
+}
+
+/* Consume elements from m->q until m->threads*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 = v;
+  gpr_int64 n = m->iterations * m->threads;
+  gpr_int64 i;
+  int value;
+  for (i = 0; i != n; i++) {
+    queue_remove(&m->q, &value, gpr_inf_future);
+  }
+  gpr_mu_lock(&m->mu);
+  m->counter = n;
+  gpr_mu_unlock(&m->mu);
+  GPR_ASSERT(
+      !queue_remove(&m->q, &value,
+                    gpr_time_add(gpr_now(), gpr_time_from_micros(1000000))));
+  mark_thread_done(m);
+}
+
+/* Increment m->stats_counter m->iterations times, transfer counter value to
+   m->counter, then mark thread as done.  */
+static void statsinc(void *v /*=m*/) {
+  struct test *m = v;
+  gpr_int64 i;
+  for (i = 0; i != m->iterations; i++) {
+    gpr_stats_inc(&m->stats_counter, 1);
+  }
+  gpr_mu_lock(&m->mu);
+  m->counter = gpr_stats_read(&m->stats_counter);
+  gpr_mu_unlock(&m->mu);
+  mark_thread_done(m);
+}
+
+/* Increment m->refcount m->iterations times, decrement m->thread_refcount
+   once, and if it reaches zero, set m->event to (void*)1; then mark thread as
+   done.  */
+static void refinc(void *v /*=m*/) {
+  struct test *m = v;
+  gpr_int64 i;
+  for (i = 0; i != m->iterations; i++) {
+    gpr_ref(&m->refcount);
+  }
+  if (gpr_unref(&m->thread_refcount)) {
+    gpr_event_set(&m->event, (void *)1);
+  }
+  mark_thread_done(m);
+}
+
+/* Wait until m->event is set to (void *)1, then decrement m->refcount
+   m->stats_counter m->iterations 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 = v;
+  gpr_int64 n = m->iterations * m->threads;
+  gpr_int64 i;
+  GPR_ASSERT(gpr_event_wait(&m->event, gpr_inf_future) == (void *)1);
+  GPR_ASSERT(gpr_event_get(&m->event) == (void *)1);
+  for (i = 1; i != n; i++) {
+    GPR_ASSERT(!gpr_unref(&m->refcount));
+    m->counter++;
+  }
+  GPR_ASSERT(gpr_unref(&m->refcount));
+  m->counter++;
+  mark_thread_done(m);
+}
+
+/* ------------------------------------------------- */
+
+int main(int argc, char *argv[]) {
+  grpc_test_init(argc, argv);
+  test("mutex", &inc, NULL, 1);
+  test("mutex try", &inctry, NULL, 1);
+  test("cv", &inc_by_turns, NULL, 1);
+  test("timedcv", &inc_with_1ms_delay, NULL, 1);
+  test("queue", &many_producers, &consumer, 10);
+  test("stats_counter", &statsinc, NULL, 1);
+  test("refcount", &refinc, &refcheck, 1);
+  test("timedevent", &inc_with_1ms_delay_event, NULL, 1);
+  return 0;
+}
diff --git a/test/core/support/thd_test.c b/test/core/support/thd_test.c
new file mode 100644
index 0000000..c70e025
--- /dev/null
+++ b/test/core/support/thd_test.c
@@ -0,0 +1,90 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Test of gpr thread support. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+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 = 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 and wait for them. */
+static void test(void) {
+  int i;
+  gpr_thd_id thd;
+  struct test t;
+  int n = 1000;
+  gpr_mu_init(&t.mu);
+  gpr_cv_init(&t.done_cv);
+  t.n = n;
+  t.is_done = 0;
+  for (i = 0; i != n; i++) {
+    GPR_ASSERT(gpr_thd_new(&thd, &thd_body, &t, NULL));
+  }
+  gpr_mu_lock(&t.mu);
+  while (!t.is_done) {
+    gpr_cv_wait(&t.done_cv, &t.mu, gpr_inf_future);
+  }
+  gpr_mu_unlock(&t.mu);
+  GPR_ASSERT(t.n == 0);
+}
+
+/* ------------------------------------------------- */
+
+int main(int argc, char *argv[]) {
+  grpc_test_init(argc, argv);
+  test();
+  return 0;
+}
diff --git a/test/core/support/time_test.c b/test/core/support/time_test.c
new file mode 100644
index 0000000..d74d6a5
--- /dev/null
+++ b/test/core/support/time_test.c
@@ -0,0 +1,255 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 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.
+ *
+ */
+
+/* Test of gpr time support. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+static void to_fp(void *arg, const char *buf, int len) {
+  fwrite(buf, 1, len, (FILE *)arg);
+}
+
+/* Convert gpr_uintmax x to ascii base b (2..16), and write with
+   (*writer)(arg, ...), zero padding to "chars" digits).  */
+static void u_to_s(gpr_uintmax x, unsigned base, int chars,
+                   void (*writer)(void *arg, const char *buf, int len),
+                   void *arg) {
+  char buf[64];
+  char *p = buf + sizeof(buf);
+  do {
+    *--p = "0123456789abcdef"[x % base];
+    x /= base;
+    chars--;
+  } while (x != 0 || chars > 0);
+  (*writer)(arg, p, buf + sizeof(buf) - p);
+}
+
+/* Convert gpr_intmax x to ascii base b (2..16), and write with
+   (*writer)(arg, ...), zero padding to "chars" digits).  */
+static void i_to_s(gpr_intmax x, unsigned base, int chars,
+                   void (*writer)(void *arg, const char *buf, int len),
+                   void *arg) {
+  if (x < 0) {
+    (*writer)(arg, "-", 1);
+    u_to_s(-x, base, chars - 1, writer, arg);
+  } else {
+    u_to_s(x, base, chars, writer, arg);
+  }
+}
+
+/* Convert ts to ascii, and write with (*writer)(arg, ...).  */
+static void ts_to_s(gpr_timespec t,
+                    void (*writer)(void *arg, const char *buf, int len),
+                    void *arg) {
+  if (t.tv_sec < 0 && t.tv_nsec != 0) {
+    t.tv_sec++;
+    t.tv_nsec = 1000000000 - t.tv_nsec;
+  }
+  i_to_s(t.tv_sec, 10, 0, writer, arg);
+  (*writer)(arg, ".", 1);
+  i_to_s(t.tv_nsec, 10, 9, writer, arg);
+}
+
+static void test_values(void) {
+  int i;
+
+  gpr_timespec x = gpr_time_0;
+  GPR_ASSERT(x.tv_sec == 0 && x.tv_nsec == 0);
+
+  x = gpr_inf_future;
+  fprintf(stderr, "far future ");
+  u_to_s(x.tv_sec, 16, 16, &to_fp, stderr);
+  fprintf(stderr, "\n");
+  GPR_ASSERT(x.tv_sec >= INT_MAX);
+  fprintf(stderr, "far future ");
+  ts_to_s(x, &to_fp, stderr);
+  fprintf(stderr, "\n");
+
+  x = gpr_inf_past;
+  fprintf(stderr, "far past   ");
+  u_to_s(x.tv_sec, 16, 16, &to_fp, stderr);
+  fprintf(stderr, "\n");
+  GPR_ASSERT(x.tv_sec <= INT_MIN);
+  fprintf(stderr, "far past   ");
+  ts_to_s(x, &to_fp, stderr);
+  fprintf(stderr, "\n");
+
+  for (i = 1; i != 1000 * 1000 * 1000; i *= 10) {
+    x = gpr_time_from_micros(i);
+    GPR_ASSERT(x.tv_sec == i / GPR_US_PER_SEC &&
+               x.tv_nsec == (i % GPR_US_PER_SEC) * GPR_NS_PER_US);
+    x = gpr_time_from_nanos(i);
+    GPR_ASSERT(x.tv_sec == i / GPR_NS_PER_SEC &&
+               x.tv_nsec == (i % GPR_NS_PER_SEC));
+    x = gpr_time_from_millis(i);
+    GPR_ASSERT(x.tv_sec == i / GPR_MS_PER_SEC &&
+               x.tv_nsec == (i % GPR_MS_PER_SEC) * GPR_NS_PER_MS);
+  }
+
+  /* Test possible overflow in conversion of -ve values. */
+  x = gpr_time_from_micros(-(LONG_MAX - 999997));
+  GPR_ASSERT(x.tv_sec < 0);
+  GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < 1000000000);
+
+  x = gpr_time_from_nanos(-(LONG_MAX - 999999997));
+  GPR_ASSERT(x.tv_sec < 0);
+  GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < 1000000000);
+
+  x = gpr_time_from_millis(-(LONG_MAX - 997));
+  GPR_ASSERT(x.tv_sec < 0);
+  GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < 1000000000);
+
+  /* Test general -ve values. */
+  for (i = -1; i > -1000 * 1000 * 1000; i *= 7) {
+    x = gpr_time_from_micros(i);
+    GPR_ASSERT(x.tv_sec * GPR_US_PER_SEC + x.tv_nsec / GPR_NS_PER_US == i);
+    x = gpr_time_from_nanos(i);
+    GPR_ASSERT(x.tv_sec * GPR_NS_PER_SEC + x.tv_nsec == i);
+    x = gpr_time_from_millis(i);
+    GPR_ASSERT(x.tv_sec * GPR_MS_PER_SEC + x.tv_nsec / GPR_NS_PER_MS == i);
+  }
+}
+
+static void test_add_sub(void) {
+  int i;
+  int j;
+  int k;
+  /* Basic addition and subtraction. */
+  for (i = -100; i <= 100; i++) {
+    for (j = -100; j <= 100; j++) {
+      for (k = 1; k <= 10000000; k *= 10) {
+        int sum = i + j;
+        int diff = i - j;
+        gpr_timespec it = gpr_time_from_micros(i * k);
+        gpr_timespec jt = gpr_time_from_micros(j * k);
+        gpr_timespec sumt = gpr_time_add(it, jt);
+        gpr_timespec difft = gpr_time_sub(it, jt);
+        if (gpr_time_cmp(gpr_time_from_micros(sum * k), sumt) != 0) {
+          fprintf(stderr, "i %d  j %d  sum %d    sumt ", i, j, sum);
+          ts_to_s(sumt, &to_fp, stderr);
+          fprintf(stderr, "\n");
+          GPR_ASSERT(0);
+        }
+        if (gpr_time_cmp(gpr_time_from_micros(diff * k), difft) != 0) {
+          fprintf(stderr, "i %d  j %d  diff %d    diff ", i, j, diff);
+          ts_to_s(sumt, &to_fp, stderr);
+          fprintf(stderr, "\n");
+          GPR_ASSERT(0);
+        }
+      }
+    }
+  }
+}
+
+static void test_overflow(void) {
+  /* overflow */
+  gpr_timespec x = gpr_time_from_micros(1);
+  do {
+    x = gpr_time_add(x, x);
+  } while (gpr_time_cmp(x, gpr_inf_future) < 0);
+  GPR_ASSERT(gpr_time_cmp(x, gpr_inf_future) == 0);
+  x = gpr_time_from_micros(-1);
+  do {
+    x = gpr_time_add(x, x);
+  } while (gpr_time_cmp(x, gpr_inf_past) > 0);
+  GPR_ASSERT(gpr_time_cmp(x, gpr_inf_past) == 0);
+}
+
+static void test_sticky_infinities(void) {
+  int i;
+  int j;
+  int k;
+  static const gpr_timespec *infinity[] = {&gpr_inf_future, &gpr_inf_past};
+  static const gpr_timespec *addend[] = {&gpr_inf_future, &gpr_inf_past,
+                                         &gpr_time_0, NULL};
+
+  /* Infinities are sticky */
+  for (i = 0; i != sizeof(infinity) / sizeof(infinity[0]); i++) {
+    for (j = 0; j != sizeof(addend) / sizeof(addend[0]); j++) {
+      if (addend[j] == NULL) {
+        for (k = -200; k <= 200; k++) {
+          gpr_timespec y = gpr_time_from_micros(k * 100000);
+          gpr_timespec x = gpr_time_add(*infinity[i], y);
+          GPR_ASSERT(gpr_time_cmp(x, *infinity[i]) == 0);
+          x = gpr_time_sub(*infinity[i], y);
+          GPR_ASSERT(gpr_time_cmp(x, *infinity[i]) == 0);
+        }
+      } else {
+        gpr_timespec x = gpr_time_add(*infinity[i], *addend[j]);
+        GPR_ASSERT(gpr_time_cmp(x, *infinity[i]) == 0);
+        x = gpr_time_sub(*infinity[i], *addend[j]);
+        GPR_ASSERT(gpr_time_cmp(x, *infinity[i]) == 0);
+      }
+    }
+  }
+}
+
+static void test_similar() {
+  GPR_ASSERT(1 == gpr_time_similar(gpr_inf_future, gpr_inf_future, gpr_time_0));
+  GPR_ASSERT(1 == gpr_time_similar(gpr_inf_past, gpr_inf_past, gpr_time_0));
+  GPR_ASSERT(0 == gpr_time_similar(gpr_inf_past, gpr_inf_future, gpr_time_0));
+  GPR_ASSERT(0 == gpr_time_similar(gpr_inf_future, gpr_inf_past, gpr_time_0));
+  GPR_ASSERT(1 == gpr_time_similar(gpr_time_from_micros(10),
+                                   gpr_time_from_micros(10), gpr_time_0));
+  GPR_ASSERT(1 == gpr_time_similar(gpr_time_from_micros(10),
+                                   gpr_time_from_micros(15),
+                                   gpr_time_from_micros(10)));
+  GPR_ASSERT(1 == gpr_time_similar(gpr_time_from_micros(15),
+                                   gpr_time_from_micros(10),
+                                   gpr_time_from_micros(10)));
+  GPR_ASSERT(0 == gpr_time_similar(gpr_time_from_micros(10),
+                                   gpr_time_from_micros(25),
+                                   gpr_time_from_micros(10)));
+  GPR_ASSERT(0 == gpr_time_similar(gpr_time_from_micros(25),
+                                   gpr_time_from_micros(10),
+                                   gpr_time_from_micros(10)));
+}
+
+int main(int argc, char *argv[]) {
+  grpc_test_init(argc, argv);
+
+  test_values();
+  test_add_sub();
+  test_overflow();
+  test_sticky_infinities();
+  test_similar();
+  return 0;
+}
diff --git a/test/core/surface/byte_buffer_reader_test.c b/test/core/surface/byte_buffer_reader_test.c
new file mode 100644
index 0000000..bc5a512
--- /dev/null
+++ b/test/core/surface/byte_buffer_reader_test.c
@@ -0,0 +1,111 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/byte_buffer_reader.h>
+#include <grpc/byte_buffer.h>
+#include <grpc/support/slice.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 "test/core/util/test_config.h"
+
+#include <string.h>
+
+#define LOG_TEST() gpr_log(GPR_INFO, "%s", __FUNCTION__)
+
+static void test_create() {
+  grpc_byte_buffer *buffer;
+  grpc_byte_buffer_reader *reader;
+  gpr_slice empty = gpr_empty_slice();
+  LOG_TEST();
+  buffer = grpc_byte_buffer_create(&empty, 1);
+  reader = grpc_byte_buffer_reader_create(buffer);
+  grpc_byte_buffer_reader_destroy(reader);
+  grpc_byte_buffer_destroy(buffer);
+}
+
+static void test_read_one_slice() {
+  gpr_slice slice;
+  grpc_byte_buffer *buffer;
+  grpc_byte_buffer_reader *reader;
+  gpr_slice first_slice, second_slice;
+  int first_code, second_code;
+
+  LOG_TEST();
+  slice = gpr_slice_from_copied_string("test");
+  buffer = grpc_byte_buffer_create(&slice, 1);
+  gpr_slice_unref(slice);
+  reader = grpc_byte_buffer_reader_create(buffer);
+  first_code = grpc_byte_buffer_reader_next(reader, &first_slice);
+  GPR_ASSERT(first_code != 0);
+  GPR_ASSERT(memcmp(GPR_SLICE_START_PTR(first_slice), "test", 4) == 0);
+  gpr_slice_unref(first_slice);
+  second_code = grpc_byte_buffer_reader_next(reader, &second_slice);
+  GPR_ASSERT(second_code == 0);
+  grpc_byte_buffer_reader_destroy(reader);
+  grpc_byte_buffer_destroy(buffer);
+}
+
+static void test_read_one_slice_malloc() {
+  gpr_slice slice;
+  grpc_byte_buffer *buffer;
+  grpc_byte_buffer_reader *reader;
+  gpr_slice first_slice, second_slice;
+  int first_code, second_code;
+
+  LOG_TEST();
+  slice = gpr_slice_malloc(4);
+  memcpy(GPR_SLICE_START_PTR(slice), "test", 4);
+  buffer = grpc_byte_buffer_create(&slice, 1);
+  gpr_slice_unref(slice);
+  reader = grpc_byte_buffer_reader_create(buffer);
+  first_code = grpc_byte_buffer_reader_next(reader, &first_slice);
+  GPR_ASSERT(first_code != 0);
+  GPR_ASSERT(memcmp(GPR_SLICE_START_PTR(first_slice), "test", 4) == 0);
+  gpr_slice_unref(first_slice);
+  second_code = grpc_byte_buffer_reader_next(reader, &second_slice);
+  GPR_ASSERT(second_code == 0);
+  grpc_byte_buffer_reader_destroy(reader);
+  grpc_byte_buffer_destroy(buffer);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_create();
+  test_read_one_slice();
+  test_read_one_slice_malloc();
+  return 0;
+}
diff --git a/test/core/surface/completion_queue_benchmark.c b/test/core/surface/completion_queue_benchmark.c
new file mode 100644
index 0000000..5360d7c
--- /dev/null
+++ b/test/core/surface/completion_queue_benchmark.c
@@ -0,0 +1,168 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/surface/completion_queue.h"
+
+#include <math.h>
+#include <stdio.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+
+typedef struct test_thread_options {
+  gpr_event on_started;
+  gpr_event *start;
+  gpr_event on_finished;
+  grpc_completion_queue *cc;
+  int iterations;
+} test_thread_options;
+
+static void producer_thread(void *arg) {
+  test_thread_options *opt = arg;
+  int i;
+
+  gpr_event_set(&opt->on_started, (void *)(gpr_intptr) 1);
+  GPR_ASSERT(gpr_event_wait(opt->start, gpr_inf_future));
+
+  for (i = 0; i < opt->iterations; i++) {
+    grpc_cq_begin_op(opt->cc, NULL, GRPC_WRITE_ACCEPTED);
+    grpc_cq_end_write_accepted(opt->cc, (void *)(gpr_intptr) 1, NULL, NULL,
+                               NULL, GRPC_OP_OK);
+  }
+
+  gpr_event_set(&opt->on_finished, (void *)(gpr_intptr) 1);
+}
+
+static void consumer_thread(void *arg) {
+  test_thread_options *opt = arg;
+  grpc_event *ev;
+
+  gpr_event_set(&opt->on_started, (void *)(gpr_intptr) 1);
+  GPR_ASSERT(gpr_event_wait(opt->start, gpr_inf_future));
+
+  for (;;) {
+    ev = grpc_completion_queue_next(opt->cc, gpr_inf_future);
+    switch (ev->type) {
+      case GRPC_WRITE_ACCEPTED:
+        break;
+      case GRPC_QUEUE_SHUTDOWN:
+        gpr_event_set(&opt->on_finished, (void *)(gpr_intptr) 1);
+        return;
+      default:
+        gpr_log(GPR_ERROR, "Invalid event received: %d", ev->type);
+        abort();
+    }
+    grpc_event_finish(ev);
+  }
+}
+
+double ops_per_second(int consumers, int producers, int iterations) {
+  test_thread_options *options =
+      gpr_malloc((producers + consumers) * sizeof(test_thread_options));
+  gpr_event start = GPR_EVENT_INIT;
+  grpc_completion_queue *cc = grpc_completion_queue_create();
+  int i;
+  gpr_timespec t_start, t_end, t_delta;
+
+  /* start all threads: they will wait for phase1 */
+  for (i = 0; i < producers + consumers; i++) {
+    gpr_thd_id id;
+    gpr_event_init(&options[i].on_started);
+    gpr_event_init(&options[i].on_finished);
+    options[i].start = &start;
+    options[i].cc = cc;
+    options[i].iterations = iterations;
+    GPR_ASSERT(gpr_thd_new(&id,
+                           i < producers ? producer_thread : consumer_thread,
+                           options + i, NULL));
+    gpr_event_wait(&options[i].on_started, gpr_inf_future);
+  }
+
+  /* start the benchmark */
+  t_start = gpr_now();
+  gpr_event_set(&start, (void *)(gpr_intptr) 1);
+
+  /* wait for producers to finish */
+  for (i = 0; i < producers; i++) {
+    GPR_ASSERT(gpr_event_wait(&options[i].on_finished, gpr_inf_future));
+  }
+
+  /* in parallel, we shutdown the completion channel - all events should still
+     be consumed */
+  grpc_completion_queue_shutdown(cc);
+
+  /* join all threads */
+  for (i = producers; i < producers + consumers; i++) {
+    GPR_ASSERT(gpr_event_wait(&options[i].on_finished, gpr_inf_future));
+  }
+  t_end = gpr_now();
+
+  /* destroy the completion channel */
+  grpc_completion_queue_destroy(cc);
+
+  gpr_free(options);
+
+  t_delta = gpr_time_sub(t_end, t_start);
+  return (t_delta.tv_sec + 1e-9 * t_delta.tv_nsec) / (producers * iterations);
+}
+
+double ops_per_second_top(int consumers, int producers) {
+  return ops_per_second(consumers, producers, 1000000 / producers);
+}
+
+int main(void) {
+  const int counts[] = {1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 40, 64};
+  const int ncounts = sizeof(counts) / sizeof(*counts);
+  int i, j;
+
+  printf("\"\",");
+  for (i = 0; i < ncounts; i++) {
+    int producers = counts[i];
+    printf("%d%s", producers, i == ncounts - 1 ? "\n" : ",");
+  }
+
+  for (j = 0; j < ncounts; j++) {
+    int consumers = counts[j];
+    printf("%d,", consumers);
+    for (i = 0; i < ncounts; i++) {
+      int producers = counts[i];
+      printf("%f%s", ops_per_second_top(consumers, producers),
+             i == ncounts - 1 ? "\n" : ",");
+      fflush(stdout);
+    }
+  }
+
+  return 0;
+}
diff --git a/test/core/surface/completion_queue_test.c b/test/core/surface/completion_queue_test.c
new file mode 100644
index 0000000..6df159f
--- /dev/null
+++ b/test/core/surface/completion_queue_test.c
@@ -0,0 +1,435 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/surface/completion_queue.h"
+
+#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/surface/surface_em.h"
+#include "test/core/util/test_config.h"
+
+#define LOG_TEST() gpr_log(GPR_INFO, "%s", __FUNCTION__)
+
+static void increment_int_on_finish(void *user_data, grpc_op_error error) {
+  ++*(int *)user_data;
+}
+
+static void *create_test_tag() {
+  static gpr_intptr i = 0;
+  return (void *)(++i);
+}
+
+/* helper for tests to shutdown correctly and tersely */
+static void shutdown_and_destroy(grpc_completion_queue *cc) {
+  grpc_event *ev;
+  grpc_completion_queue_shutdown(cc);
+  ev = grpc_completion_queue_next(cc, gpr_inf_past);
+  GPR_ASSERT(ev != NULL);
+  GPR_ASSERT(ev->type == GRPC_QUEUE_SHUTDOWN);
+  grpc_event_finish(ev);
+  grpc_completion_queue_destroy(cc);
+}
+
+/* ensure we can create and destroy a completion channel */
+static void test_no_op() {
+  LOG_TEST();
+  shutdown_and_destroy(grpc_completion_queue_create());
+}
+
+static void test_wait_empty() {
+  grpc_completion_queue *cc;
+
+  LOG_TEST();
+
+  cc = grpc_completion_queue_create();
+  GPR_ASSERT(grpc_completion_queue_next(cc, gpr_now()) == NULL);
+  shutdown_and_destroy(cc);
+}
+
+static void test_cq_end_read() {
+  grpc_event *ev;
+  grpc_completion_queue *cc;
+  int on_finish_called = 0;
+  void *tag = create_test_tag();
+
+  LOG_TEST();
+
+  cc = grpc_completion_queue_create();
+
+  grpc_cq_begin_op(cc, NULL, GRPC_READ);
+  grpc_cq_end_read(cc, tag, NULL, increment_int_on_finish, &on_finish_called,
+                   NULL);
+
+  ev = grpc_completion_queue_next(cc, gpr_inf_past);
+  GPR_ASSERT(ev != NULL);
+  GPR_ASSERT(ev->type == GRPC_READ);
+  GPR_ASSERT(ev->tag == tag);
+  GPR_ASSERT(ev->data.read == NULL);
+  GPR_ASSERT(on_finish_called == 0);
+  grpc_event_finish(ev);
+  GPR_ASSERT(on_finish_called == 1);
+
+  shutdown_and_destroy(cc);
+}
+
+static void test_cq_end_invoke_accepted() {
+  grpc_event *ev;
+  grpc_completion_queue *cc;
+  int on_finish_called = 0;
+  void *tag = create_test_tag();
+
+  LOG_TEST();
+
+  cc = grpc_completion_queue_create();
+
+  grpc_cq_begin_op(cc, NULL, GRPC_INVOKE_ACCEPTED);
+  grpc_cq_end_invoke_accepted(cc, tag, NULL, increment_int_on_finish,
+                              &on_finish_called, GRPC_OP_OK);
+
+  ev = grpc_completion_queue_next(cc, gpr_inf_past);
+  GPR_ASSERT(ev != NULL);
+  GPR_ASSERT(ev->type == GRPC_INVOKE_ACCEPTED);
+  GPR_ASSERT(ev->tag == tag);
+  GPR_ASSERT(ev->data.invoke_accepted == GRPC_OP_OK);
+  GPR_ASSERT(on_finish_called == 0);
+  grpc_event_finish(ev);
+  GPR_ASSERT(on_finish_called == 1);
+
+  shutdown_and_destroy(cc);
+}
+
+static void test_cq_end_write_accepted() {
+  grpc_event *ev;
+  grpc_completion_queue *cc;
+  int on_finish_called = 0;
+  void *tag = create_test_tag();
+
+  LOG_TEST();
+
+  cc = grpc_completion_queue_create();
+
+  grpc_cq_begin_op(cc, NULL, GRPC_WRITE_ACCEPTED);
+  grpc_cq_end_write_accepted(cc, tag, NULL, increment_int_on_finish,
+                             &on_finish_called, GRPC_OP_OK);
+
+  ev = grpc_completion_queue_next(cc, gpr_inf_past);
+  GPR_ASSERT(ev != NULL);
+  GPR_ASSERT(ev->type == GRPC_WRITE_ACCEPTED);
+  GPR_ASSERT(ev->tag == tag);
+  GPR_ASSERT(ev->data.write_accepted == GRPC_OP_OK);
+  GPR_ASSERT(on_finish_called == 0);
+  grpc_event_finish(ev);
+  GPR_ASSERT(on_finish_called == 1);
+
+  shutdown_and_destroy(cc);
+}
+
+static void test_cq_end_finish_accepted() {
+  grpc_event *ev;
+  grpc_completion_queue *cc;
+  int on_finish_called = 0;
+  void *tag = create_test_tag();
+
+  LOG_TEST();
+
+  cc = grpc_completion_queue_create();
+
+  grpc_cq_begin_op(cc, NULL, GRPC_FINISH_ACCEPTED);
+  grpc_cq_end_finish_accepted(cc, tag, NULL, increment_int_on_finish,
+                              &on_finish_called, GRPC_OP_OK);
+
+  ev = grpc_completion_queue_next(cc, gpr_inf_past);
+  GPR_ASSERT(ev != NULL);
+  GPR_ASSERT(ev->type == GRPC_FINISH_ACCEPTED);
+  GPR_ASSERT(ev->tag == tag);
+  GPR_ASSERT(ev->data.finish_accepted == GRPC_OP_OK);
+  GPR_ASSERT(on_finish_called == 0);
+  grpc_event_finish(ev);
+  GPR_ASSERT(on_finish_called == 1);
+
+  shutdown_and_destroy(cc);
+}
+
+static void test_cq_end_client_metadata_read() {
+  grpc_event *ev;
+  grpc_completion_queue *cc;
+  int on_finish_called = 0;
+  void *tag = create_test_tag();
+
+  LOG_TEST();
+
+  cc = grpc_completion_queue_create();
+
+  grpc_cq_begin_op(cc, NULL, GRPC_CLIENT_METADATA_READ);
+  grpc_cq_end_client_metadata_read(cc, tag, NULL, increment_int_on_finish,
+                                   &on_finish_called, 0, NULL);
+
+  ev = grpc_completion_queue_next(cc, gpr_inf_past);
+  GPR_ASSERT(ev != NULL);
+  GPR_ASSERT(ev->type == GRPC_CLIENT_METADATA_READ);
+  GPR_ASSERT(ev->tag == tag);
+  GPR_ASSERT(ev->data.client_metadata_read.count == 0);
+  GPR_ASSERT(ev->data.client_metadata_read.elements == NULL);
+  GPR_ASSERT(on_finish_called == 0);
+  grpc_event_finish(ev);
+  GPR_ASSERT(on_finish_called == 1);
+
+  shutdown_and_destroy(cc);
+}
+
+static void test_pluck() {
+  grpc_event *ev;
+  grpc_completion_queue *cc;
+  void *tags[128];
+  int i, j;
+  int on_finish_called = 0;
+
+  LOG_TEST();
+
+  for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
+    tags[i] = create_test_tag();
+    for (j = 0; j < i; j++) {
+      GPR_ASSERT(tags[i] != tags[j]);
+    }
+  }
+
+  cc = grpc_completion_queue_create();
+
+  for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
+    grpc_cq_begin_op(cc, NULL, GRPC_WRITE_ACCEPTED);
+    grpc_cq_end_write_accepted(cc, tags[i], NULL, increment_int_on_finish,
+                               &on_finish_called, GRPC_OP_OK);
+  }
+
+  for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
+    ev = grpc_completion_queue_pluck(cc, tags[i], gpr_inf_past);
+    GPR_ASSERT(ev->tag == tags[i]);
+    grpc_event_finish(ev);
+  }
+
+  GPR_ASSERT(on_finish_called == GPR_ARRAY_SIZE(tags));
+
+  for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
+    grpc_cq_begin_op(cc, NULL, GRPC_WRITE_ACCEPTED);
+    grpc_cq_end_write_accepted(cc, tags[i], NULL, increment_int_on_finish,
+                               &on_finish_called, GRPC_OP_OK);
+  }
+
+  for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
+    ev = grpc_completion_queue_pluck(cc, tags[GPR_ARRAY_SIZE(tags) - i - 1],
+                                     gpr_inf_past);
+    GPR_ASSERT(ev->tag == tags[GPR_ARRAY_SIZE(tags) - i - 1]);
+    grpc_event_finish(ev);
+  }
+
+  GPR_ASSERT(on_finish_called == 2 * GPR_ARRAY_SIZE(tags));
+
+  shutdown_and_destroy(cc);
+}
+
+#define TEST_THREAD_EVENTS 10000
+
+typedef struct test_thread_options {
+  gpr_event on_started;
+  gpr_event *phase1;
+  gpr_event on_phase1_done;
+  gpr_event *phase2;
+  gpr_event on_finished;
+  int events_triggered;
+  int id;
+  grpc_completion_queue *cc;
+} test_thread_options;
+
+gpr_timespec ten_seconds_time() {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(10 * 1000000));
+}
+
+static void producer_thread(void *arg) {
+  test_thread_options *opt = arg;
+  int i;
+
+  gpr_log(GPR_INFO, "producer %d started", opt->id);
+  gpr_event_set(&opt->on_started, (void *)(gpr_intptr) 1);
+  GPR_ASSERT(gpr_event_wait(opt->phase1, ten_seconds_time()));
+
+  gpr_log(GPR_INFO, "producer %d phase 1", opt->id);
+  for (i = 0; i < TEST_THREAD_EVENTS; i++) {
+    grpc_cq_begin_op(opt->cc, NULL, GRPC_WRITE_ACCEPTED);
+  }
+
+  gpr_log(GPR_INFO, "producer %d phase 1 done", opt->id);
+  gpr_event_set(&opt->on_phase1_done, (void *)(gpr_intptr) 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_cq_end_write_accepted(opt->cc, (void *)(gpr_intptr) 1, NULL, NULL,
+                               NULL, GRPC_OP_OK);
+    opt->events_triggered++;
+  }
+
+  gpr_log(GPR_INFO, "producer %d phase 2 done", opt->id);
+  gpr_event_set(&opt->on_finished, (void *)(gpr_intptr) 1);
+}
+
+static void consumer_thread(void *arg) {
+  test_thread_options *opt = arg;
+  grpc_event *ev;
+
+  gpr_log(GPR_INFO, "consumer %d started", opt->id);
+  gpr_event_set(&opt->on_started, (void *)(gpr_intptr) 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 *)(gpr_intptr) 1);
+  GPR_ASSERT(gpr_event_wait(opt->phase2, ten_seconds_time()));
+
+  gpr_log(GPR_INFO, "consumer %d phase 2", opt->id);
+  for (;;) {
+    ev = grpc_completion_queue_next(opt->cc, ten_seconds_time());
+    GPR_ASSERT(ev);
+    switch (ev->type) {
+      case GRPC_WRITE_ACCEPTED:
+        GPR_ASSERT(ev->data.write_accepted == GRPC_OP_OK);
+        opt->events_triggered++;
+        grpc_event_finish(ev);
+        break;
+      case GRPC_QUEUE_SHUTDOWN:
+        gpr_log(GPR_INFO, "consumer %d phase 2 done", opt->id);
+        gpr_event_set(&opt->on_finished, (void *)(gpr_intptr) 1);
+        grpc_event_finish(ev);
+        return;
+      default:
+        gpr_log(GPR_ERROR, "Invalid event received: %d", ev->type);
+        abort();
+    }
+  }
+}
+
+static void test_threading(int producers, int consumers) {
+  test_thread_options *options =
+      gpr_malloc((producers + consumers) * sizeof(test_thread_options));
+  gpr_event phase1 = GPR_EVENT_INIT;
+  gpr_event phase2 = GPR_EVENT_INIT;
+  grpc_completion_queue *cc = grpc_completion_queue_create();
+  int i;
+  int total_consumed = 0;
+  static int optid = 101;
+
+  gpr_log(GPR_INFO, "%s: %d producers, %d consumers", __FUNCTION__, producers,
+          consumers);
+
+  grpc_completion_queue_dont_poll_test_only(cc);
+
+  /* start all threads: they will wait for phase1 */
+  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);
+    options[i].phase1 = &phase1;
+    options[i].phase2 = &phase2;
+    options[i].events_triggered = 0;
+    options[i].cc = cc;
+    options[i].id = optid++;
+    GPR_ASSERT(gpr_thd_new(&id,
+                           i < producers ? producer_thread : consumer_thread,
+                           options + i, NULL));
+    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 *)(gpr_intptr) 1);
+
+  gpr_log(GPR_INFO, "wait phase 1");
+  for (i = 0; i < producers + consumers; i++) {
+    GPR_ASSERT(gpr_event_wait(&options[i].on_phase1_done, ten_seconds_time()));
+  }
+  gpr_log(GPR_INFO, "done phase 1");
+
+  /* start phase2: operations will complete, and consumers will consume them */
+  gpr_log(GPR_INFO, "start phase 2");
+  gpr_event_set(&phase2, (void *)(gpr_intptr) 1);
+
+  /* in parallel, we shutdown the completion channel - all events should still
+     be consumed */
+  grpc_completion_queue_shutdown(cc);
+
+  /* join all threads */
+  gpr_log(GPR_INFO, "wait phase 2");
+  for (i = 0; i < producers + consumers; i++) {
+    GPR_ASSERT(gpr_event_wait(&options[i].on_finished, ten_seconds_time()));
+  }
+  gpr_log(GPR_INFO, "done phase 2");
+
+  /* destroy the completion channel */
+  grpc_completion_queue_destroy(cc);
+
+  /* verify that everything was produced and consumed */
+  for (i = 0; i < producers + consumers; i++) {
+    if (i < producers) {
+      GPR_ASSERT(options[i].events_triggered == TEST_THREAD_EVENTS);
+    } else {
+      total_consumed += options[i].events_triggered;
+    }
+  }
+  GPR_ASSERT(total_consumed == producers * TEST_THREAD_EVENTS);
+
+  gpr_free(options);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  grpc_surface_em_init();
+  test_no_op();
+  test_wait_empty();
+  test_cq_end_read();
+  test_cq_end_invoke_accepted();
+  test_cq_end_write_accepted();
+  test_cq_end_finish_accepted();
+  test_cq_end_client_metadata_read();
+  test_pluck();
+  test_threading(1, 1);
+  test_threading(1, 10);
+  test_threading(10, 1);
+  test_threading(10, 10);
+  grpc_surface_em_shutdown();
+  return 0;
+}
diff --git a/test/core/surface/lame_client_test.c b/test/core/surface/lame_client_test.c
new file mode 100644
index 0000000..0520a39
--- /dev/null
+++ b/test/core/surface/lame_client_test.c
@@ -0,0 +1,82 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/surface/lame_client.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/util/test_config.h"
+#include <grpc/support/log.h>
+
+static void *tag(gpr_intptr x) { return (void *)x; }
+
+int main(int argc, char **argv) {
+  grpc_channel *chan;
+  grpc_call *call;
+  grpc_metadata md = {"a", "b", 1};
+  grpc_completion_queue *cq;
+  cq_verifier *cqv;
+
+  grpc_test_init(argc, argv);
+  grpc_init();
+
+  chan = grpc_lame_client_channel_create();
+  GPR_ASSERT(chan);
+  call = grpc_channel_create_call(
+      chan, "/Foo", "anywhere",
+      gpr_time_add(gpr_now(), gpr_time_from_seconds(100)));
+  GPR_ASSERT(call);
+  cq = grpc_completion_queue_create();
+  cqv = cq_verifier_create(cq);
+
+  /* we should be able to add metadata */
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_add_metadata(call, &md, 0));
+
+  /* and invoke the call */
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_invoke(call, cq, tag(1), tag(2), tag(3), 0));
+
+  /* the call should immediately fail */
+  cq_expect_invoke_accepted(cqv, tag(1), GRPC_OP_ERROR);
+  cq_expect_client_metadata_read(cqv, tag(2), NULL);
+  cq_expect_finished(cqv, tag(3), NULL);
+  cq_verify(cqv);
+
+  grpc_call_destroy(call);
+  grpc_channel_destroy(chan);
+  cq_verifier_destroy(cqv);
+  grpc_completion_queue_destroy(cq);
+
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/transport/chttp2/hpack_parser_test.c b/test/core/transport/chttp2/hpack_parser_test.c
new file mode 100644
index 0000000..12f8b35
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_test.c
@@ -0,0 +1,223 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/hpack_parser.h"
+
+#include <stdarg.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+#include "test/core/util/parse_hexstring.h"
+#include "test/core/util/slice_splitter.h"
+#include "test/core/util/test_config.h"
+
+typedef struct { va_list args; } test_checker;
+
+static void onhdr(void *ud, grpc_mdelem *md) {
+  const char *ekey, *evalue;
+  test_checker *chk = ud;
+  ekey = va_arg(chk->args, char *);
+  GPR_ASSERT(ekey);
+  evalue = va_arg(chk->args, char *);
+  GPR_ASSERT(evalue);
+  GPR_ASSERT(gpr_slice_str_cmp(md->key->slice, ekey) == 0);
+  GPR_ASSERT(gpr_slice_str_cmp(md->value->slice, evalue) == 0);
+  grpc_mdelem_unref(md);
+}
+
+static void test_vector(grpc_chttp2_hpack_parser *parser,
+                        grpc_slice_split_mode mode, const char *hexstring,
+                        ... /* char *key, char *value */) {
+  gpr_slice input = parse_hexstring(hexstring);
+  gpr_slice *slices;
+  size_t nslices;
+  size_t i;
+  test_checker chk;
+
+  va_start(chk.args, hexstring);
+
+  parser->on_header = onhdr;
+  parser->on_header_user_data = &chk;
+
+  grpc_split_slices(mode, &input, 1, &slices, &nslices);
+  gpr_slice_unref(input);
+
+  for (i = 0; i < nslices; i++) {
+    GPR_ASSERT(grpc_chttp2_hpack_parser_parse(
+        parser, GPR_SLICE_START_PTR(slices[i]), GPR_SLICE_END_PTR(slices[i])));
+  }
+
+  for (i = 0; i < nslices; i++) {
+    gpr_slice_unref(slices[i]);
+  }
+  gpr_free(slices);
+
+  GPR_ASSERT(NULL == va_arg(chk.args, char *));
+
+  va_end(chk.args);
+}
+
+static void test_vectors(grpc_slice_split_mode mode) {
+  grpc_chttp2_hpack_parser parser;
+  grpc_mdctx *mdctx = grpc_mdctx_create();
+
+  grpc_chttp2_hpack_parser_init(&parser, mdctx);
+  /* D.2.1 */
+  test_vector(&parser, mode,
+              "400a 6375 7374 6f6d 2d6b 6579 0d63 7573"
+              "746f 6d2d 6865 6164 6572",
+              "custom-key", "custom-header", NULL);
+  /* D.2.2 */
+  test_vector(&parser, mode, "040c 2f73 616d 706c 652f 7061 7468", ":path",
+              "/sample/path", NULL);
+  /* D.2.3 */
+  test_vector(&parser, mode,
+              "1008 7061 7373 776f 7264 0673 6563 7265"
+              "74",
+              "password", "secret", NULL);
+  /* D.2.4 */
+  test_vector(&parser, mode, "82", ":method", "GET", NULL);
+  grpc_chttp2_hpack_parser_destroy(&parser);
+
+  grpc_chttp2_hpack_parser_init(&parser, mdctx);
+  /* D.3.1 */
+  test_vector(&parser, mode,
+              "8286 8441 0f77 7777 2e65 7861 6d70 6c65"
+              "2e63 6f6d",
+              ":method", "GET", ":scheme", "http", ":path", "/", ":authority",
+              "www.example.com", NULL);
+  /* D.3.2 */
+  test_vector(&parser, mode, "8286 84be 5808 6e6f 2d63 6163 6865", ":method",
+              "GET", ":scheme", "http", ":path", "/", ":authority",
+              "www.example.com", "cache-control", "no-cache", NULL);
+  /* D.3.3 */
+  test_vector(&parser, mode,
+              "8287 85bf 400a 6375 7374 6f6d 2d6b 6579"
+              "0c63 7573 746f 6d2d 7661 6c75 65",
+              ":method", "GET", ":scheme", "https", ":path", "/index.html",
+              ":authority", "www.example.com", "custom-key", "custom-value",
+              NULL);
+  grpc_chttp2_hpack_parser_destroy(&parser);
+
+  grpc_chttp2_hpack_parser_init(&parser, mdctx);
+  /* D.4.1 */
+  test_vector(&parser, mode,
+              "8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4"
+              "ff",
+              ":method", "GET", ":scheme", "http", ":path", "/", ":authority",
+              "www.example.com", NULL);
+  /* D.4.2 */
+  test_vector(&parser, mode, "8286 84be 5886 a8eb 1064 9cbf", ":method", "GET",
+              ":scheme", "http", ":path", "/", ":authority", "www.example.com",
+              "cache-control", "no-cache", NULL);
+  /* D.4.3 */
+  test_vector(&parser, mode,
+              "8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925"
+              "a849 e95b b8e8 b4bf",
+              ":method", "GET", ":scheme", "https", ":path", "/index.html",
+              ":authority", "www.example.com", "custom-key", "custom-value",
+              NULL);
+  grpc_chttp2_hpack_parser_destroy(&parser);
+
+  grpc_chttp2_hpack_parser_init(&parser, mdctx);
+  parser.table.max_bytes = 256;
+  /* D.5.1 */
+  test_vector(&parser, mode,
+              "4803 3330 3258 0770 7269 7661 7465 611d"
+              "4d6f 6e2c 2032 3120 4f63 7420 3230 3133"
+              "2032 303a 3133 3a32 3120 474d 546e 1768"
+              "7474 7073 3a2f 2f77 7777 2e65 7861 6d70"
+              "6c65 2e63 6f6d",
+              ":status", "302", "cache-control", "private", "date",
+              "Mon, 21 Oct 2013 20:13:21 GMT", "location",
+              "https://www.example.com", NULL);
+  /* D.5.2 */
+  test_vector(&parser, mode, "4803 3330 37c1 c0bf", ":status", "307",
+              "cache-control", "private", "date",
+              "Mon, 21 Oct 2013 20:13:21 GMT", "location",
+              "https://www.example.com", NULL);
+  /* D.5.3 */
+  test_vector(&parser, mode,
+              "88c1 611d 4d6f 6e2c 2032 3120 4f63 7420"
+              "3230 3133 2032 303a 3133 3a32 3220 474d"
+              "54c0 5a04 677a 6970 7738 666f 6f3d 4153"
+              "444a 4b48 514b 425a 584f 5157 454f 5049"
+              "5541 5851 5745 4f49 553b 206d 6178 2d61"
+              "6765 3d33 3630 303b 2076 6572 7369 6f6e"
+              "3d31",
+              ":status", "200", "cache-control", "private", "date",
+              "Mon, 21 Oct 2013 20:13:22 GMT", "location",
+              "https://www.example.com", "content-encoding", "gzip",
+              "set-cookie",
+              "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", NULL);
+  grpc_chttp2_hpack_parser_destroy(&parser);
+
+  grpc_chttp2_hpack_parser_init(&parser, mdctx);
+  parser.table.max_bytes = 256;
+  /* D.6.1 */
+  test_vector(&parser, mode,
+              "4882 6402 5885 aec3 771a 4b61 96d0 7abe"
+              "9410 54d4 44a8 2005 9504 0b81 66e0 82a6"
+              "2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8"
+              "e9ae 82ae 43d3",
+              ":status", "302", "cache-control", "private", "date",
+              "Mon, 21 Oct 2013 20:13:21 GMT", "location",
+              "https://www.example.com", NULL);
+  /* D.6.2 */
+  test_vector(&parser, mode, "4883 640e ffc1 c0bf", ":status", "307",
+              "cache-control", "private", "date",
+              "Mon, 21 Oct 2013 20:13:21 GMT", "location",
+              "https://www.example.com", NULL);
+  /* D.6.3 */
+  test_vector(&parser, mode,
+              "88c1 6196 d07a be94 1054 d444 a820 0595"
+              "040b 8166 e084 a62d 1bff c05a 839b d9ab"
+              "77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b"
+              "3960 d5af 2708 7f36 72c1 ab27 0fb5 291f"
+              "9587 3160 65c0 03ed 4ee5 b106 3d50 07",
+              ":status", "200", "cache-control", "private", "date",
+              "Mon, 21 Oct 2013 20:13:22 GMT", "location",
+              "https://www.example.com", "content-encoding", "gzip",
+              "set-cookie",
+              "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", NULL);
+  grpc_chttp2_hpack_parser_destroy(&parser);
+  grpc_mdctx_orphan(mdctx);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_vectors(GRPC_SLICE_SPLIT_MERGE_ALL);
+  test_vectors(GRPC_SLICE_SPLIT_ONE_BYTE);
+  return 0;
+}
diff --git a/test/core/transport/chttp2/hpack_table_test.c b/test/core/transport/chttp2/hpack_table_test.c
new file mode 100644
index 0000000..8810925
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_table_test.c
@@ -0,0 +1,269 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/hpack_table.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+#define LOG_TEST() gpr_log(GPR_INFO, "%s", __FUNCTION__)
+
+static void assert_str(const grpc_chttp2_hptbl *tbl, grpc_mdstr *mdstr,
+                       const char *str) {
+  GPR_ASSERT(gpr_slice_str_cmp(mdstr->slice, str) == 0);
+}
+
+static void assert_index(const grpc_chttp2_hptbl *tbl, int idx, const char *key,
+                         const char *value) {
+  grpc_mdelem *md = grpc_chttp2_hptbl_lookup(tbl, idx);
+  assert_str(tbl, md->key, key);
+  assert_str(tbl, md->value, value);
+}
+
+static void test_static_lookup() {
+  grpc_chttp2_hptbl tbl;
+  grpc_mdctx *mdctx;
+
+  mdctx = grpc_mdctx_create();
+  grpc_chttp2_hptbl_init(&tbl, mdctx);
+
+  LOG_TEST();
+  assert_index(&tbl, 1, ":authority", "");
+  assert_index(&tbl, 2, ":method", "GET");
+  assert_index(&tbl, 3, ":method", "POST");
+  assert_index(&tbl, 4, ":path", "/");
+  assert_index(&tbl, 5, ":path", "/index.html");
+  assert_index(&tbl, 6, ":scheme", "http");
+  assert_index(&tbl, 7, ":scheme", "https");
+  assert_index(&tbl, 8, ":status", "200");
+  assert_index(&tbl, 9, ":status", "204");
+  assert_index(&tbl, 10, ":status", "206");
+  assert_index(&tbl, 11, ":status", "304");
+  assert_index(&tbl, 12, ":status", "400");
+  assert_index(&tbl, 13, ":status", "404");
+  assert_index(&tbl, 14, ":status", "500");
+  assert_index(&tbl, 15, "accept-charset", "");
+  assert_index(&tbl, 16, "accept-encoding", "gzip, deflate");
+  assert_index(&tbl, 17, "accept-language", "");
+  assert_index(&tbl, 18, "accept-ranges", "");
+  assert_index(&tbl, 19, "accept", "");
+  assert_index(&tbl, 20, "access-control-allow-origin", "");
+  assert_index(&tbl, 21, "age", "");
+  assert_index(&tbl, 22, "allow", "");
+  assert_index(&tbl, 23, "authorization", "");
+  assert_index(&tbl, 24, "cache-control", "");
+  assert_index(&tbl, 25, "content-disposition", "");
+  assert_index(&tbl, 26, "content-encoding", "");
+  assert_index(&tbl, 27, "content-language", "");
+  assert_index(&tbl, 28, "content-length", "");
+  assert_index(&tbl, 29, "content-location", "");
+  assert_index(&tbl, 30, "content-range", "");
+  assert_index(&tbl, 31, "content-type", "");
+  assert_index(&tbl, 32, "cookie", "");
+  assert_index(&tbl, 33, "date", "");
+  assert_index(&tbl, 34, "etag", "");
+  assert_index(&tbl, 35, "expect", "");
+  assert_index(&tbl, 36, "expires", "");
+  assert_index(&tbl, 37, "from", "");
+  assert_index(&tbl, 38, "host", "");
+  assert_index(&tbl, 39, "if-match", "");
+  assert_index(&tbl, 40, "if-modified-since", "");
+  assert_index(&tbl, 41, "if-none-match", "");
+  assert_index(&tbl, 42, "if-range", "");
+  assert_index(&tbl, 43, "if-unmodified-since", "");
+  assert_index(&tbl, 44, "last-modified", "");
+  assert_index(&tbl, 45, "link", "");
+  assert_index(&tbl, 46, "location", "");
+  assert_index(&tbl, 47, "max-forwards", "");
+  assert_index(&tbl, 48, "proxy-authenticate", "");
+  assert_index(&tbl, 49, "proxy-authorization", "");
+  assert_index(&tbl, 50, "range", "");
+  assert_index(&tbl, 51, "referer", "");
+  assert_index(&tbl, 52, "refresh", "");
+  assert_index(&tbl, 53, "retry-after", "");
+  assert_index(&tbl, 54, "server", "");
+  assert_index(&tbl, 55, "set-cookie", "");
+  assert_index(&tbl, 56, "strict-transport-security", "");
+  assert_index(&tbl, 57, "transfer-encoding", "");
+  assert_index(&tbl, 58, "user-agent", "");
+  assert_index(&tbl, 59, "vary", "");
+  assert_index(&tbl, 60, "via", "");
+  assert_index(&tbl, 61, "www-authenticate", "");
+
+  grpc_chttp2_hptbl_destroy(&tbl);
+  grpc_mdctx_orphan(mdctx);
+}
+
+static void test_many_additions() {
+  grpc_chttp2_hptbl tbl;
+  int i;
+  char key[32];
+  char value[32];
+  grpc_mdctx *mdctx;
+
+  LOG_TEST();
+
+  mdctx = grpc_mdctx_create();
+  grpc_chttp2_hptbl_init(&tbl, mdctx);
+
+  for (i = 0; i < 1000000; i++) {
+    sprintf(key, "K:%d", i);
+    sprintf(value, "VALUE:%d", i);
+    grpc_chttp2_hptbl_add(&tbl, grpc_mdelem_from_strings(mdctx, key, value));
+    assert_index(&tbl, 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY, key, value);
+    if (i) {
+      sprintf(key, "K:%d", i - 1);
+      sprintf(value, "VALUE:%d", i - 1);
+      assert_index(&tbl, 2 + GRPC_CHTTP2_LAST_STATIC_ENTRY, key, value);
+    }
+  }
+
+  grpc_chttp2_hptbl_destroy(&tbl);
+  grpc_mdctx_orphan(mdctx);
+}
+
+static grpc_chttp2_hptbl_find_result find_simple(grpc_chttp2_hptbl *tbl,
+                                                 const char *key,
+                                                 const char *value) {
+  grpc_mdelem *md = grpc_mdelem_from_strings(tbl->mdctx, key, value);
+  grpc_chttp2_hptbl_find_result r = grpc_chttp2_hptbl_find(tbl, md);
+  grpc_mdelem_unref(md);
+  return r;
+}
+
+static void test_find() {
+  grpc_chttp2_hptbl tbl;
+  int i;
+  char buffer[32];
+  grpc_mdctx *mdctx;
+  grpc_chttp2_hptbl_find_result r;
+
+  LOG_TEST();
+
+  mdctx = grpc_mdctx_create();
+  grpc_chttp2_hptbl_init(&tbl, mdctx);
+  grpc_chttp2_hptbl_add(&tbl, grpc_mdelem_from_strings(mdctx, "abc", "xyz"));
+  grpc_chttp2_hptbl_add(&tbl, grpc_mdelem_from_strings(mdctx, "abc", "123"));
+  grpc_chttp2_hptbl_add(&tbl, grpc_mdelem_from_strings(mdctx, "x", "1"));
+
+  r = find_simple(&tbl, "abc", "123");
+  GPR_ASSERT(r.index == 2 + GRPC_CHTTP2_LAST_STATIC_ENTRY);
+  GPR_ASSERT(r.has_value == 1);
+
+  r = find_simple(&tbl, "abc", "xyz");
+  GPR_ASSERT(r.index == 3 + GRPC_CHTTP2_LAST_STATIC_ENTRY);
+  GPR_ASSERT(r.has_value == 1);
+
+  r = find_simple(&tbl, "x", "1");
+  GPR_ASSERT(r.index == 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY);
+  GPR_ASSERT(r.has_value == 1);
+
+  r = find_simple(&tbl, "x", "2");
+  GPR_ASSERT(r.index == 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY);
+  GPR_ASSERT(r.has_value == 0);
+
+  r = find_simple(&tbl, "vary", "some-vary-arg");
+  GPR_ASSERT(r.index == 59);
+  GPR_ASSERT(r.has_value == 0);
+
+  r = find_simple(&tbl, "accept-encoding", "gzip, deflate");
+  GPR_ASSERT(r.index == 16);
+  GPR_ASSERT(r.has_value == 1);
+
+  r = find_simple(&tbl, "accept-encoding", "gzip");
+  GPR_ASSERT(r.index == 16);
+  GPR_ASSERT(r.has_value == 0);
+
+  r = find_simple(&tbl, ":method", "GET");
+  GPR_ASSERT(r.index == 2);
+  GPR_ASSERT(r.has_value == 1);
+
+  r = find_simple(&tbl, ":method", "POST");
+  GPR_ASSERT(r.index == 3);
+  GPR_ASSERT(r.has_value == 1);
+
+  r = find_simple(&tbl, ":method", "PUT");
+  GPR_ASSERT(r.index == 2 || r.index == 3);
+  GPR_ASSERT(r.has_value == 0);
+
+  r = find_simple(&tbl, "this-does-not-exist", "");
+  GPR_ASSERT(r.index == 0);
+  GPR_ASSERT(r.has_value == 0);
+
+  /* overflow the string buffer, check find still works */
+  for (i = 0; i < 10000; i++) {
+    sprintf(buffer, "%d", i);
+    grpc_chttp2_hptbl_add(&tbl,
+                          grpc_mdelem_from_strings(mdctx, "test", buffer));
+  }
+
+  r = find_simple(&tbl, "abc", "123");
+  GPR_ASSERT(r.index == 0);
+  GPR_ASSERT(r.has_value == 0);
+
+  r = find_simple(&tbl, "test", "9999");
+  GPR_ASSERT(r.index == 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY);
+  GPR_ASSERT(r.has_value == 1);
+
+  r = find_simple(&tbl, "test", "9998");
+  GPR_ASSERT(r.index == 2 + GRPC_CHTTP2_LAST_STATIC_ENTRY);
+  GPR_ASSERT(r.has_value == 1);
+
+  for (i = 0; i < tbl.num_ents; i++) {
+    int expect = 9999 - i;
+    sprintf(buffer, "%d", expect);
+
+    r = find_simple(&tbl, "test", buffer);
+    GPR_ASSERT(r.index == i + 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY);
+    GPR_ASSERT(r.has_value == 1);
+  }
+
+  r = find_simple(&tbl, "test", "10000");
+  GPR_ASSERT(r.index != 0);
+  GPR_ASSERT(r.has_value == 0);
+
+  grpc_chttp2_hptbl_destroy(&tbl);
+  grpc_mdctx_orphan(mdctx);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_static_lookup();
+  test_many_additions();
+  test_find();
+  return 0;
+}
diff --git a/test/core/transport/chttp2/status_conversion_test.c b/test/core/transport/chttp2/status_conversion_test.c
new file mode 100644
index 0000000..bb5d7b8
--- /dev/null
+++ b/test/core/transport/chttp2/status_conversion_test.c
@@ -0,0 +1,138 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/status_conversion.h"
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+#define GRPC_STATUS_TO_HTTP2_ERROR(a, b) \
+  GPR_ASSERT(grpc_chttp2_grpc_status_to_http2_error(a) == (b))
+#define HTTP2_ERROR_TO_GRPC_STATUS(a, b) \
+  GPR_ASSERT(grpc_chttp2_http2_error_to_grpc_status(a) == (b))
+#define GRPC_STATUS_TO_HTTP2_STATUS(a, b) \
+  GPR_ASSERT(grpc_chttp2_grpc_status_to_http2_status(a) == (b))
+#define HTTP2_STATUS_TO_GRPC_STATUS(a, b) \
+  GPR_ASSERT(grpc_chttp2_http2_status_to_grpc_status(a) == (b))
+
+int main(int argc, char **argv) {
+  int i;
+
+  grpc_test_init(argc, argv);
+
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_OK, GRPC_CHTTP2_NO_ERROR);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_CANCELLED, GRPC_CHTTP2_CANCEL);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_UNKNOWN, GRPC_CHTTP2_INTERNAL_ERROR);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_INVALID_ARGUMENT,
+                             GRPC_CHTTP2_INTERNAL_ERROR);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_DEADLINE_EXCEEDED,
+                             GRPC_CHTTP2_INTERNAL_ERROR);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_NOT_FOUND, GRPC_CHTTP2_INTERNAL_ERROR);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_ALREADY_EXISTS,
+                             GRPC_CHTTP2_INTERNAL_ERROR);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_PERMISSION_DENIED,
+                             GRPC_CHTTP2_INADEQUATE_SECURITY);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_UNAUTHENTICATED,
+                             GRPC_CHTTP2_INTERNAL_ERROR);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_RESOURCE_EXHAUSTED,
+                             GRPC_CHTTP2_ENHANCE_YOUR_CALM);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_FAILED_PRECONDITION,
+                             GRPC_CHTTP2_INTERNAL_ERROR);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_ABORTED, GRPC_CHTTP2_INTERNAL_ERROR);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_OUT_OF_RANGE,
+                             GRPC_CHTTP2_INTERNAL_ERROR);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_UNIMPLEMENTED,
+                             GRPC_CHTTP2_INTERNAL_ERROR);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_INTERNAL, GRPC_CHTTP2_INTERNAL_ERROR);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_UNAVAILABLE,
+                             GRPC_CHTTP2_REFUSED_STREAM);
+  GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_DATA_LOSS, GRPC_CHTTP2_INTERNAL_ERROR);
+
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_OK, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_CANCELLED, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_UNKNOWN, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_INVALID_ARGUMENT, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_DEADLINE_EXCEEDED, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_NOT_FOUND, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_ALREADY_EXISTS, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_PERMISSION_DENIED, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_UNAUTHENTICATED, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_RESOURCE_EXHAUSTED, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_FAILED_PRECONDITION, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_ABORTED, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_OUT_OF_RANGE, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_UNIMPLEMENTED, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_INTERNAL, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_UNAVAILABLE, 200);
+  GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_DATA_LOSS, 200);
+
+  HTTP2_ERROR_TO_GRPC_STATUS(GRPC_CHTTP2_NO_ERROR, GRPC_STATUS_INTERNAL);
+  HTTP2_ERROR_TO_GRPC_STATUS(GRPC_CHTTP2_PROTOCOL_ERROR, GRPC_STATUS_INTERNAL);
+  HTTP2_ERROR_TO_GRPC_STATUS(GRPC_CHTTP2_INTERNAL_ERROR, GRPC_STATUS_INTERNAL);
+  HTTP2_ERROR_TO_GRPC_STATUS(GRPC_CHTTP2_FLOW_CONTROL_ERROR,
+                             GRPC_STATUS_INTERNAL);
+  HTTP2_ERROR_TO_GRPC_STATUS(GRPC_CHTTP2_SETTINGS_TIMEOUT,
+                             GRPC_STATUS_INTERNAL);
+  HTTP2_ERROR_TO_GRPC_STATUS(GRPC_CHTTP2_STREAM_CLOSED, GRPC_STATUS_INTERNAL);
+  HTTP2_ERROR_TO_GRPC_STATUS(GRPC_CHTTP2_FRAME_SIZE_ERROR,
+                             GRPC_STATUS_INTERNAL);
+  HTTP2_ERROR_TO_GRPC_STATUS(GRPC_CHTTP2_REFUSED_STREAM,
+                             GRPC_STATUS_UNAVAILABLE);
+  HTTP2_ERROR_TO_GRPC_STATUS(GRPC_CHTTP2_CANCEL, GRPC_STATUS_CANCELLED);
+  HTTP2_ERROR_TO_GRPC_STATUS(GRPC_CHTTP2_COMPRESSION_ERROR,
+                             GRPC_STATUS_INTERNAL);
+  HTTP2_ERROR_TO_GRPC_STATUS(GRPC_CHTTP2_CONNECT_ERROR, GRPC_STATUS_INTERNAL);
+  HTTP2_ERROR_TO_GRPC_STATUS(GRPC_CHTTP2_ENHANCE_YOUR_CALM,
+                             GRPC_STATUS_RESOURCE_EXHAUSTED);
+  HTTP2_ERROR_TO_GRPC_STATUS(GRPC_CHTTP2_INADEQUATE_SECURITY,
+                             GRPC_STATUS_PERMISSION_DENIED);
+
+  HTTP2_STATUS_TO_GRPC_STATUS(200, GRPC_STATUS_OK);
+  HTTP2_STATUS_TO_GRPC_STATUS(400, GRPC_STATUS_INVALID_ARGUMENT);
+  HTTP2_STATUS_TO_GRPC_STATUS(401, GRPC_STATUS_UNAUTHENTICATED);
+  HTTP2_STATUS_TO_GRPC_STATUS(403, GRPC_STATUS_PERMISSION_DENIED);
+  HTTP2_STATUS_TO_GRPC_STATUS(404, GRPC_STATUS_NOT_FOUND);
+  HTTP2_STATUS_TO_GRPC_STATUS(409, GRPC_STATUS_ABORTED);
+  HTTP2_STATUS_TO_GRPC_STATUS(412, GRPC_STATUS_FAILED_PRECONDITION);
+  HTTP2_STATUS_TO_GRPC_STATUS(429, GRPC_STATUS_RESOURCE_EXHAUSTED);
+  HTTP2_STATUS_TO_GRPC_STATUS(499, GRPC_STATUS_CANCELLED);
+  HTTP2_STATUS_TO_GRPC_STATUS(500, GRPC_STATUS_UNKNOWN);
+  HTTP2_STATUS_TO_GRPC_STATUS(503, GRPC_STATUS_UNAVAILABLE);
+  HTTP2_STATUS_TO_GRPC_STATUS(504, GRPC_STATUS_DEADLINE_EXCEEDED);
+
+  /* check all status values can be converted */
+  for (i = 0; i <= 999; i++) {
+    grpc_chttp2_http2_status_to_grpc_status(i);
+  }
+
+  return 0;
+}
diff --git a/test/core/transport/chttp2/stream_encoder_test.c b/test/core/transport/chttp2/stream_encoder_test.c
new file mode 100644
index 0000000..3ee11d9
--- /dev/null
+++ b/test/core/transport/chttp2/stream_encoder_test.c
@@ -0,0 +1,320 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/stream_encoder.h"
+
+#include <stdio.h>
+
+#include "src/core/transport/chttp2/hpack_parser.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+#include "test/core/util/parse_hexstring.h"
+#include "test/core/util/slice_splitter.h"
+#include "test/core/util/test_config.h"
+
+#define TEST(x) run_test(x, #x)
+
+grpc_mdctx *g_mdctx;
+grpc_chttp2_hpack_compressor g_compressor;
+int g_failure = 0;
+grpc_stream_op_buffer g_sopb;
+
+static gpr_slice create_test_slice(size_t length) {
+  gpr_slice slice = gpr_slice_malloc(length);
+  size_t i;
+  for (i = 0; i < length; i++) {
+    GPR_SLICE_START_PTR(slice)[i] = i;
+  }
+  return slice;
+}
+
+/* verify that the output generated by encoding the stream matches the
+   hexstring passed in */
+static void verify_sopb(size_t window_available, int eof,
+                        size_t expect_window_used, const char *expected) {
+  gpr_slice_buffer output;
+  gpr_slice merged;
+  gpr_slice expect = parse_hexstring(expected);
+  gpr_slice_buffer_init(&output);
+  GPR_ASSERT(expect_window_used ==
+             grpc_chttp2_encode_some(g_sopb.ops, &g_sopb.nops, eof, &output,
+                                     window_available, 0xdeadbeef,
+                                     &g_compressor));
+  merged = grpc_slice_merge(output.slices, output.count);
+  gpr_slice_buffer_destroy(&output);
+
+  if (0 != gpr_slice_cmp(merged, expect)) {
+    char *expect_str =
+        gpr_hexdump((char *)GPR_SLICE_START_PTR(expect),
+                    GPR_SLICE_LENGTH(expect), GPR_HEXDUMP_PLAINTEXT);
+    char *got_str =
+        gpr_hexdump((char *)GPR_SLICE_START_PTR(merged),
+                    GPR_SLICE_LENGTH(merged), GPR_HEXDUMP_PLAINTEXT);
+    gpr_log(GPR_ERROR, "mismatched output for %s", expected);
+    gpr_log(GPR_ERROR, "EXPECT: %s", expect_str);
+    gpr_log(GPR_ERROR, "GOT:    %s", got_str);
+    gpr_free(expect_str);
+    gpr_free(got_str);
+    g_failure = 1;
+  }
+
+  gpr_slice_unref(merged);
+  gpr_slice_unref(expect);
+}
+
+static void assert_result_ok(void *user_data, grpc_op_error error) {
+  GPR_ASSERT(error == GRPC_OP_OK);
+}
+
+static void test_small_data_framing() {
+  grpc_sopb_add_no_op(&g_sopb);
+  verify_sopb(10, 0, 0, "");
+
+  grpc_sopb_add_flow_ctl_cb(&g_sopb, assert_result_ok, NULL);
+  grpc_sopb_add_slice(&g_sopb, create_test_slice(3));
+  verify_sopb(10, 0, 3, "000003 0000 deadbeef 000102");
+
+  grpc_sopb_add_slice(&g_sopb, create_test_slice(4));
+  verify_sopb(10, 0, 4, "000004 0000 deadbeef 00010203");
+
+  grpc_sopb_add_slice(&g_sopb, create_test_slice(3));
+  grpc_sopb_add_slice(&g_sopb, create_test_slice(4));
+  verify_sopb(10, 0, 7, "000007 0000 deadbeef 000102 00010203");
+
+  grpc_sopb_add_slice(&g_sopb, create_test_slice(0));
+  grpc_sopb_add_slice(&g_sopb, create_test_slice(0));
+  grpc_sopb_add_slice(&g_sopb, create_test_slice(0));
+  grpc_sopb_add_slice(&g_sopb, create_test_slice(0));
+  grpc_sopb_add_slice(&g_sopb, create_test_slice(3));
+  verify_sopb(10, 0, 3, "000003 0000 deadbeef 000102");
+
+  verify_sopb(10, 1, 0, "000000 0001 deadbeef");
+
+  grpc_sopb_add_begin_message(&g_sopb, 255, 0);
+  verify_sopb(10, 0, 5, "000005 0000 deadbeef 00000000ff");
+}
+
+static void add_sopb_header(const char *key, const char *value) {
+  grpc_sopb_add_metadata(&g_sopb,
+                         grpc_mdelem_from_strings(g_mdctx, key, value));
+}
+
+static void test_basic_headers() {
+  int i;
+
+  add_sopb_header("a", "a");
+  verify_sopb(0, 0, 0, "000005 0104 deadbeef 40 0161 0161");
+
+  add_sopb_header("a", "a");
+  verify_sopb(0, 0, 0, "000001 0104 deadbeef be");
+
+  add_sopb_header("a", "a");
+  verify_sopb(0, 0, 0, "000001 0104 deadbeef be");
+
+  add_sopb_header("a", "a");
+  add_sopb_header("b", "c");
+  verify_sopb(0, 0, 0, "000006 0104 deadbeef be 40 0162 0163");
+
+  add_sopb_header("a", "a");
+  add_sopb_header("b", "c");
+  verify_sopb(0, 0, 0, "000002 0104 deadbeef bf be");
+
+  add_sopb_header("a", "d");
+  verify_sopb(0, 0, 0, "000004 0104 deadbeef 7f 00 0164");
+
+  /* flush out what's there to make a few values look very popular */
+  for (i = 0; i < 350; i++) {
+    add_sopb_header("a", "a");
+    add_sopb_header("b", "c");
+    add_sopb_header("a", "d");
+    verify_sopb(0, 0, 0, "000003 0104 deadbeef c0 bf be");
+  }
+
+  add_sopb_header("a", "a");
+  add_sopb_header("k", "v");
+  verify_sopb(0, 0, 0, "000006 0104 deadbeef c0 00 016b 0176");
+
+  add_sopb_header("a", "v");
+  /* this could be      000004 0104 deadbeef 0f 30 0176 also */
+  verify_sopb(0, 0, 0, "000004 0104 deadbeef 0f 2f 0176");
+}
+
+static void encode_int_to_str(int i, char *p) {
+  p[0] = 'a' + i % 26;
+  i /= 26;
+  GPR_ASSERT(i < 26);
+  p[1] = 'a' + i;
+  p[2] = 0;
+}
+
+static void test_decode_table_overflow() {
+  int i;
+  char key[3], value[3];
+  char expect[128];
+
+  for (i = 0; i < 114; i++) {
+    if (i > 0) {
+      add_sopb_header("aa", "ba");
+    }
+
+    encode_int_to_str(i, key);
+    encode_int_to_str(i + 1, value);
+
+    if (i + 61 >= 127) {
+      sprintf(expect, "000009 0104 deadbeef ff%02x 40 02%02x%02x 02%02x%02x",
+              i + 61 - 127, key[0], key[1], value[0], value[1]);
+    } else if (i > 0) {
+      sprintf(expect, "000008 0104 deadbeef %02x 40 02%02x%02x 02%02x%02x",
+              0x80 + 61 + i, key[0], key[1], value[0], value[1]);
+    } else {
+      sprintf(expect, "000007 0104 deadbeef 40 02%02x%02x 02%02x%02x", key[0],
+              key[1], value[0], value[1]);
+    }
+
+    add_sopb_header(key, value);
+    verify_sopb(0, 0, 0, expect);
+  }
+
+  /* if the above passes, then we must have just knocked this pair out of the
+     decoder stack, and so we'll be forced to re-encode it */
+  add_sopb_header("aa", "ba");
+  verify_sopb(0, 0, 0, "000007 0104 deadbeef 40 026161 026261");
+}
+
+static void randstr(char *p, int bufsz) {
+  int i;
+  int len = 1 + rand() % bufsz;
+  for (i = 0; i < len; i++) {
+    p[i] = 'a' + rand() % 26;
+  }
+  p[len] = 0;
+}
+
+typedef struct {
+  char key[300];
+  char value[300];
+  int got_hdr;
+} test_decode_random_header_state;
+
+static void chk_hdr(void *p, grpc_mdelem *el) {
+  test_decode_random_header_state *st = p;
+  GPR_ASSERT(0 == gpr_slice_str_cmp(el->key->slice, st->key));
+  GPR_ASSERT(0 == gpr_slice_str_cmp(el->value->slice, st->value));
+  st->got_hdr = 1;
+  grpc_mdelem_unref(el);
+}
+
+static void test_decode_random_headers_inner(int max_len) {
+  int i;
+  test_decode_random_header_state st;
+  gpr_slice_buffer output;
+  gpr_slice merged;
+  grpc_chttp2_hpack_parser parser;
+
+  grpc_chttp2_hpack_parser_init(&parser, g_mdctx);
+
+  gpr_log(GPR_INFO, "max_len = %d", max_len);
+
+  for (i = 0; i < 100000; i++) {
+    randstr(st.key, max_len);
+    randstr(st.value, max_len);
+
+    add_sopb_header(st.key, st.value);
+    gpr_slice_buffer_init(&output);
+    GPR_ASSERT(0 == grpc_chttp2_encode_some(g_sopb.ops, &g_sopb.nops, 0,
+                                            &output, 0, 0xdeadbeef,
+                                            &g_compressor));
+    merged = grpc_slice_merge(output.slices, output.count);
+    gpr_slice_buffer_destroy(&output);
+
+    st.got_hdr = 0;
+    parser.on_header = chk_hdr;
+    parser.on_header_user_data = &st;
+    grpc_chttp2_hpack_parser_parse(&parser, GPR_SLICE_START_PTR(merged) + 9,
+                                   GPR_SLICE_END_PTR(merged));
+    GPR_ASSERT(st.got_hdr);
+
+    gpr_slice_unref(merged);
+  }
+
+  grpc_chttp2_hpack_parser_destroy(&parser);
+}
+
+#define DECL_TEST_DECODE_RANDOM_HEADERS(n)       \
+  static void test_decode_random_headers_##n() { \
+    test_decode_random_headers_inner(n);         \
+  }                                              \
+  int keeps_formatting_correct_##n
+
+DECL_TEST_DECODE_RANDOM_HEADERS(1);
+DECL_TEST_DECODE_RANDOM_HEADERS(2);
+DECL_TEST_DECODE_RANDOM_HEADERS(3);
+DECL_TEST_DECODE_RANDOM_HEADERS(5);
+DECL_TEST_DECODE_RANDOM_HEADERS(8);
+DECL_TEST_DECODE_RANDOM_HEADERS(13);
+DECL_TEST_DECODE_RANDOM_HEADERS(21);
+DECL_TEST_DECODE_RANDOM_HEADERS(34);
+DECL_TEST_DECODE_RANDOM_HEADERS(55);
+DECL_TEST_DECODE_RANDOM_HEADERS(89);
+DECL_TEST_DECODE_RANDOM_HEADERS(144);
+
+static void run_test(void (*test)(), const char *name) {
+  gpr_log(GPR_INFO, "RUN TEST: %s", name);
+  g_mdctx = grpc_mdctx_create_with_seed(0);
+  grpc_chttp2_hpack_compressor_init(&g_compressor, g_mdctx);
+  grpc_sopb_init(&g_sopb);
+  test();
+  grpc_chttp2_hpack_compressor_destroy(&g_compressor);
+  grpc_mdctx_orphan(g_mdctx);
+  grpc_sopb_destroy(&g_sopb);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  TEST(test_small_data_framing);
+  TEST(test_basic_headers);
+  TEST(test_decode_table_overflow);
+  TEST(test_decode_random_headers_1);
+  TEST(test_decode_random_headers_2);
+  TEST(test_decode_random_headers_3);
+  TEST(test_decode_random_headers_5);
+  TEST(test_decode_random_headers_8);
+  TEST(test_decode_random_headers_13);
+  TEST(test_decode_random_headers_21);
+  TEST(test_decode_random_headers_34);
+  TEST(test_decode_random_headers_55);
+  TEST(test_decode_random_headers_89);
+  TEST(test_decode_random_headers_144);
+  return g_failure;
+}
diff --git a/test/core/transport/chttp2/stream_map_test.c b/test/core/transport/chttp2/stream_map_test.c
new file mode 100644
index 0000000..459ef2a
--- /dev/null
+++ b/test/core/transport/chttp2/stream_map_test.c
@@ -0,0 +1,228 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/stream_map.h"
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+#define LOG_TEST() gpr_log(GPR_INFO, "%s", __FUNCTION__)
+
+/* test creation & destruction */
+static void test_no_op() {
+  grpc_chttp2_stream_map map;
+
+  LOG_TEST();
+
+  grpc_chttp2_stream_map_init(&map, 8);
+  grpc_chttp2_stream_map_destroy(&map);
+}
+
+/* test lookup on an empty map */
+static void test_empty_find() {
+  grpc_chttp2_stream_map map;
+
+  LOG_TEST();
+
+  grpc_chttp2_stream_map_init(&map, 8);
+  GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 39128));
+  grpc_chttp2_stream_map_destroy(&map);
+}
+
+/* test it's safe to delete twice */
+static void test_double_deletion() {
+  grpc_chttp2_stream_map map;
+
+  LOG_TEST();
+
+  grpc_chttp2_stream_map_init(&map, 8);
+  GPR_ASSERT(0 == grpc_chttp2_stream_map_size(&map));
+  grpc_chttp2_stream_map_add(&map, 1, (void *)1);
+  GPR_ASSERT((void *)1 == grpc_chttp2_stream_map_find(&map, 1));
+  GPR_ASSERT(1 == grpc_chttp2_stream_map_size(&map));
+  GPR_ASSERT((void *)1 == grpc_chttp2_stream_map_delete(&map, 1));
+  GPR_ASSERT(0 == grpc_chttp2_stream_map_size(&map));
+  GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 1));
+  GPR_ASSERT(NULL == grpc_chttp2_stream_map_delete(&map, 1));
+  GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 1));
+  GPR_ASSERT(NULL == grpc_chttp2_stream_map_delete(&map, 1));
+  GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 1));
+  GPR_ASSERT(NULL == grpc_chttp2_stream_map_delete(&map, 1));
+  GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 1));
+  grpc_chttp2_stream_map_destroy(&map);
+}
+
+/* test add & lookup */
+static void test_basic_add_find(size_t n) {
+  grpc_chttp2_stream_map map;
+  size_t i;
+  size_t got;
+
+  LOG_TEST();
+  gpr_log(GPR_INFO, "n = %d", n);
+
+  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 *)(gpr_uintptr)i);
+  }
+  GPR_ASSERT(n == grpc_chttp2_stream_map_size(&map));
+  GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 0));
+  GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, n + 1));
+  for (i = 1; i <= n; i++) {
+    got = (gpr_uintptr)grpc_chttp2_stream_map_find(&map, i);
+    GPR_ASSERT(i == got);
+  }
+  grpc_chttp2_stream_map_destroy(&map);
+}
+
+/* verify that for_each gets the right values during test_delete_evens_XXX */
+static void verify_for_each(void *user_data, gpr_uint32 stream_id, void *ptr) {
+  size_t *for_each_check = user_data;
+  GPR_ASSERT(ptr);
+  GPR_ASSERT(*for_each_check == stream_id);
+  *for_each_check += 2;
+}
+
+static void check_delete_evens(grpc_chttp2_stream_map *map, size_t n) {
+  size_t for_each_check = 1;
+  size_t i;
+  size_t got;
+
+  GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(map, 0));
+  GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(map, n + 1));
+  for (i = 1; i <= n; i++) {
+    if (i & 1) {
+      got = (gpr_uintptr)grpc_chttp2_stream_map_find(map, i);
+      GPR_ASSERT(i == got);
+    } else {
+      GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(map, i));
+    }
+  }
+
+  grpc_chttp2_stream_map_for_each(map, verify_for_each, &for_each_check);
+  if (n & 1) {
+    GPR_ASSERT(for_each_check == n + 2);
+  } else {
+    GPR_ASSERT(for_each_check == n + 1);
+  }
+}
+
+/* add a bunch of keys, delete the even ones, and make sure the map is
+   consistent */
+static void test_delete_evens_sweep(size_t n) {
+  grpc_chttp2_stream_map map;
+  size_t i;
+
+  LOG_TEST();
+  gpr_log(GPR_INFO, "n = %d", n);
+
+  grpc_chttp2_stream_map_init(&map, 8);
+  for (i = 1; i <= n; i++) {
+    grpc_chttp2_stream_map_add(&map, i, (void *)(gpr_uintptr)i);
+  }
+  for (i = 1; i <= n; i++) {
+    if ((i & 1) == 0) {
+      GPR_ASSERT((void *)i == grpc_chttp2_stream_map_delete(&map, i));
+    }
+  }
+  check_delete_evens(&map, n);
+  grpc_chttp2_stream_map_destroy(&map);
+}
+
+/* add a bunch of keys, delete the even ones immediately, and make sure the map
+   is consistent */
+static void test_delete_evens_incremental(size_t n) {
+  grpc_chttp2_stream_map map;
+  size_t i;
+
+  LOG_TEST();
+  gpr_log(GPR_INFO, "n = %d", n);
+
+  grpc_chttp2_stream_map_init(&map, 8);
+  for (i = 1; i <= n; i++) {
+    grpc_chttp2_stream_map_add(&map, i, (void *)(gpr_uintptr)i);
+    if ((i & 1) == 0) {
+      grpc_chttp2_stream_map_delete(&map, i);
+    }
+  }
+  check_delete_evens(&map, n);
+  grpc_chttp2_stream_map_destroy(&map);
+}
+
+/* add a bunch of keys, delete old ones after some time, ensure the
+   backing array does not grow */
+static void test_periodic_compaction(size_t n) {
+  grpc_chttp2_stream_map map;
+  size_t i;
+  size_t del;
+
+  LOG_TEST();
+  gpr_log(GPR_INFO, "n = %d", n);
+
+  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 *)i);
+    if (i > 8) {
+      del = i - 8;
+      GPR_ASSERT((void *)del == grpc_chttp2_stream_map_delete(&map, del));
+    }
+  }
+  GPR_ASSERT(map.capacity == 16);
+  grpc_chttp2_stream_map_destroy(&map);
+}
+
+int main(int argc, char **argv) {
+  int n = 1;
+  int prev = 1;
+  int tmp;
+
+  grpc_test_init(argc, argv);
+
+  test_no_op();
+  test_empty_find();
+  test_double_deletion();
+
+  while (n < 10000000) {
+    test_basic_add_find(n);
+    test_delete_evens_sweep(n);
+    test_delete_evens_incremental(n);
+    test_periodic_compaction(n);
+
+    tmp = n;
+    n += prev;
+    prev = tmp;
+  }
+
+  return 0;
+}
diff --git a/test/core/transport/chttp2/timeout_encoding_test.c b/test/core/transport/chttp2/timeout_encoding_test.c
new file mode 100644
index 0000000..793d2b9
--- /dev/null
+++ b/test/core/transport/chttp2/timeout_encoding_test.c
@@ -0,0 +1,140 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/chttp2/timeout_encoding.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+#include "test/core/util/test_config.h"
+
+#define LOG_TEST() gpr_log(GPR_INFO, "%s", __FUNCTION__)
+
+static void assert_encodes_as(gpr_timespec ts, const char *s) {
+  char buffer[32];
+  grpc_chttp2_encode_timeout(ts, buffer);
+  gpr_log(GPR_INFO, "check '%s' == '%s'", buffer, s);
+  GPR_ASSERT(0 == strcmp(buffer, s));
+}
+
+void test_encoding() {
+  LOG_TEST();
+  assert_encodes_as(gpr_time_from_micros(-1), "1n");
+  assert_encodes_as(gpr_time_from_seconds(-10), "1n");
+  assert_encodes_as(gpr_time_from_nanos(10), "10n");
+  assert_encodes_as(gpr_time_from_nanos(999999999), "1S");
+  assert_encodes_as(gpr_time_from_micros(1), "1u");
+  assert_encodes_as(gpr_time_from_micros(10), "10u");
+  assert_encodes_as(gpr_time_from_micros(100), "100u");
+  assert_encodes_as(gpr_time_from_micros(890), "890u");
+  assert_encodes_as(gpr_time_from_micros(900), "900u");
+  assert_encodes_as(gpr_time_from_micros(901), "901u");
+  assert_encodes_as(gpr_time_from_millis(1), "1m");
+  assert_encodes_as(gpr_time_from_millis(2), "2m");
+  assert_encodes_as(gpr_time_from_micros(10001), "10100u");
+  assert_encodes_as(gpr_time_from_micros(999999), "1S");
+  assert_encodes_as(gpr_time_from_millis(1000), "1S");
+  assert_encodes_as(gpr_time_from_millis(2000), "2S");
+  assert_encodes_as(gpr_time_from_millis(2500), "2500m");
+  assert_encodes_as(gpr_time_from_millis(59900), "59900m");
+  assert_encodes_as(gpr_time_from_seconds(50), "50S");
+  assert_encodes_as(gpr_time_from_seconds(59), "59S");
+  assert_encodes_as(gpr_time_from_seconds(60), "1M");
+  assert_encodes_as(gpr_time_from_seconds(80), "80S");
+  assert_encodes_as(gpr_time_from_seconds(90), "90S");
+  assert_encodes_as(gpr_time_from_minutes(2), "2M");
+  assert_encodes_as(gpr_time_from_minutes(20), "20M");
+  assert_encodes_as(gpr_time_from_hours(1), "1H");
+  assert_encodes_as(gpr_time_from_hours(10), "10H");
+  assert_encodes_as(gpr_time_from_seconds(1000000000), "1000000000S");
+}
+
+static void assert_decodes_as(const char *buffer, gpr_timespec expected) {
+  gpr_timespec got;
+  gpr_log(GPR_INFO, "check decoding '%s'", buffer);
+  GPR_ASSERT(1 == grpc_chttp2_decode_timeout(buffer, &got));
+  GPR_ASSERT(0 == gpr_time_cmp(got, expected));
+}
+
+void decode_suite(char ext, gpr_timespec (*answer)(long x)) {
+  long test_vals[] = {1,       12,       123,       1234,     12345,   123456,
+                      1234567, 12345678, 123456789, 98765432, 9876543, 987654,
+                      98765,   9876,     987,       98,       9};
+  int i;
+  char input[32];
+  for (i = 0; i < GPR_ARRAY_SIZE(test_vals); i++) {
+    sprintf(input, "%ld%c", test_vals[i], ext);
+    assert_decodes_as(input, answer(test_vals[i]));
+    sprintf(input, "   %ld%c", test_vals[i], ext);
+    assert_decodes_as(input, answer(test_vals[i]));
+    sprintf(input, "%ld %c", test_vals[i], ext);
+    assert_decodes_as(input, answer(test_vals[i]));
+    sprintf(input, "%ld %c  ", test_vals[i], ext);
+    assert_decodes_as(input, answer(test_vals[i]));
+  }
+}
+
+void test_decoding() {
+  LOG_TEST();
+  decode_suite('n', gpr_time_from_nanos);
+  decode_suite('u', gpr_time_from_micros);
+  decode_suite('m', gpr_time_from_millis);
+  decode_suite('S', gpr_time_from_seconds);
+  decode_suite('M', gpr_time_from_minutes);
+  decode_suite('H', gpr_time_from_hours);
+  assert_decodes_as("1000000000000000000000u", gpr_inf_future);
+}
+
+void test_decoding_fails() {
+  gpr_timespec x;
+  LOG_TEST();
+  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("", &x));
+  GPR_ASSERT(0 == grpc_chttp2_decode_timeout(" ", &x));
+  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("x", &x));
+  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("1", &x));
+  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("1x", &x));
+  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("1ux", &x));
+  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("!", &x));
+  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("n1", &x));
+  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("-1u", &x));
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_encoding();
+  test_decoding();
+  test_decoding_fails();
+  return 0;
+}
diff --git a/test/core/transport/chttp2_transport_end2end_test.c b/test/core/transport/chttp2_transport_end2end_test.c
new file mode 100644
index 0000000..4a16789
--- /dev/null
+++ b/test/core/transport/chttp2_transport_end2end_test.c
@@ -0,0 +1,139 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "transport_end2end_tests.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "test/core/util/test_config.h"
+#include "src/core/eventmanager/em.h"
+#include "src/core/transport/chttp2_transport.h"
+#include <grpc/support/log.h>
+
+static grpc_em em;
+
+static void create_sockets(int sv[2]) {
+  int flags;
+  GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
+  flags = fcntl(sv[0], F_GETFL, 0);
+  GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0);
+  flags = fcntl(sv[1], F_GETFL, 0);
+  GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
+}
+
+/* Wrapper to create an http2 transport pair */
+static int create_http2_transport_for_test(
+    grpc_transport_setup_callback client_setup_transport,
+    void *client_setup_arg,
+    grpc_transport_setup_callback server_setup_transport,
+    void *server_setup_arg, size_t slice_size, grpc_mdctx *mdctx) {
+  int sv[2];
+  grpc_endpoint *svr_ep, *cli_ep;
+
+  create_sockets(sv);
+  svr_ep = grpc_tcp_create_dbg(sv[1], &em, slice_size);
+  cli_ep = grpc_tcp_create_dbg(sv[0], &em, slice_size);
+
+  grpc_create_chttp2_transport(client_setup_transport, client_setup_arg, NULL,
+                               cli_ep, NULL, 0, mdctx, 1);
+  grpc_create_chttp2_transport(server_setup_transport, server_setup_arg, NULL,
+                               svr_ep, NULL, 0, mdctx, 0);
+
+  return 0;
+}
+
+static int create_http2_transport_for_test_small_slices(
+    grpc_transport_setup_callback client_setup_transport,
+    void *client_setup_arg,
+    grpc_transport_setup_callback server_setup_transport,
+    void *server_setup_arg, grpc_mdctx *mdctx) {
+  return create_http2_transport_for_test(
+      client_setup_transport, client_setup_arg, server_setup_transport,
+      server_setup_arg, 1, mdctx);
+}
+
+static int create_http2_transport_for_test_medium_slices(
+    grpc_transport_setup_callback client_setup_transport,
+    void *client_setup_arg,
+    grpc_transport_setup_callback server_setup_transport,
+    void *server_setup_arg, grpc_mdctx *mdctx) {
+  return create_http2_transport_for_test(
+      client_setup_transport, client_setup_arg, server_setup_transport,
+      server_setup_arg, 8192, mdctx);
+}
+
+static int create_http2_transport_for_test_large_slices(
+    grpc_transport_setup_callback client_setup_transport,
+    void *client_setup_arg,
+    grpc_transport_setup_callback server_setup_transport,
+    void *server_setup_arg, grpc_mdctx *mdctx) {
+  return create_http2_transport_for_test(
+      client_setup_transport, client_setup_arg, server_setup_transport,
+      server_setup_arg, 1024 * 1024, mdctx);
+}
+
+/* All configurations to be tested */
+grpc_transport_test_config fixture_configs[] = {
+    {"chttp2_on_socketpair/small",
+     create_http2_transport_for_test_small_slices},
+    {"chttp2_on_socketpair/medium",
+     create_http2_transport_for_test_medium_slices},
+    {"chttp2_on_socketpair/large",
+     create_http2_transport_for_test_large_slices},
+};
+
+/* Driver function: run the test suite for each test configuration */
+int main(int argc, char **argv) {
+  size_t i;
+
+  /* disable SIGPIPE */
+  signal(SIGPIPE, SIG_IGN);
+
+  grpc_test_init(argc, argv);
+  grpc_em_init(&em);
+
+  for (i = 0; i < sizeof(fixture_configs) / sizeof(*fixture_configs); i++) {
+    grpc_transport_end2end_tests(&fixture_configs[i]);
+  }
+
+  grpc_em_destroy(&em);
+
+  gpr_log(GPR_INFO, "exiting");
+  return 0;
+}
diff --git a/test/core/transport/metadata_test.c b/test/core/transport/metadata_test.c
new file mode 100644
index 0000000..d71628a
--- /dev/null
+++ b/test/core/transport/metadata_test.c
@@ -0,0 +1,258 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/metadata.h"
+
+#include <stdio.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+#define LOG_TEST() gpr_log(GPR_INFO, "%s", __FUNCTION__)
+
+/* a large number */
+#define MANY 1000000
+
+static void test_no_op() {
+  grpc_mdctx *ctx;
+
+  LOG_TEST();
+
+  ctx = grpc_mdctx_create();
+  grpc_mdctx_orphan(ctx);
+}
+
+static void test_create_string() {
+  grpc_mdctx *ctx;
+  grpc_mdstr *s1, *s2, *s3;
+
+  LOG_TEST();
+
+  ctx = grpc_mdctx_create();
+  s1 = grpc_mdstr_from_string(ctx, "hello");
+  s2 = grpc_mdstr_from_string(ctx, "hello");
+  s3 = grpc_mdstr_from_string(ctx, "very much not hello");
+  GPR_ASSERT(s1 == s2);
+  GPR_ASSERT(s3 != s1);
+  GPR_ASSERT(gpr_slice_str_cmp(s1->slice, "hello") == 0);
+  GPR_ASSERT(gpr_slice_str_cmp(s3->slice, "very much not hello") == 0);
+  grpc_mdstr_unref(s1);
+  grpc_mdstr_unref(s2);
+  grpc_mdctx_orphan(ctx);
+  grpc_mdstr_unref(s3);
+}
+
+static void test_create_metadata() {
+  grpc_mdctx *ctx;
+  grpc_mdelem *m1, *m2, *m3;
+
+  LOG_TEST();
+
+  ctx = grpc_mdctx_create();
+  m1 = grpc_mdelem_from_strings(ctx, "a", "b");
+  m2 = grpc_mdelem_from_strings(ctx, "a", "b");
+  m3 = grpc_mdelem_from_strings(ctx, "a", "c");
+  GPR_ASSERT(m1 == m2);
+  GPR_ASSERT(m3 != m1);
+  GPR_ASSERT(m3->key == m1->key);
+  GPR_ASSERT(m3->value != m1->value);
+  GPR_ASSERT(gpr_slice_str_cmp(m1->key->slice, "a") == 0);
+  GPR_ASSERT(gpr_slice_str_cmp(m1->value->slice, "b") == 0);
+  GPR_ASSERT(gpr_slice_str_cmp(m3->value->slice, "c") == 0);
+  grpc_mdelem_unref(m1);
+  grpc_mdelem_unref(m2);
+  grpc_mdelem_unref(m3);
+  grpc_mdctx_orphan(ctx);
+}
+
+static void test_create_many_ephemeral_metadata() {
+  grpc_mdctx *ctx;
+  char buffer[256];
+  long i;
+  size_t mdtab_capacity_before;
+
+  LOG_TEST();
+
+  ctx = grpc_mdctx_create();
+  mdtab_capacity_before = grpc_mdctx_get_mdtab_capacity_test_only(ctx);
+  /* add, and immediately delete a bunch of different elements */
+  for (i = 0; i < MANY; i++) {
+    sprintf(buffer, "%ld", i);
+    grpc_mdelem_unref(grpc_mdelem_from_strings(ctx, "a", buffer));
+  }
+  /* capacity should not grow */
+  GPR_ASSERT(mdtab_capacity_before ==
+             grpc_mdctx_get_mdtab_capacity_test_only(ctx));
+  grpc_mdctx_orphan(ctx);
+}
+
+static void test_create_many_persistant_metadata() {
+  grpc_mdctx *ctx;
+  char buffer[256];
+  long i;
+  grpc_mdelem **created = gpr_malloc(sizeof(grpc_mdelem *) * MANY);
+  grpc_mdelem *md;
+
+  LOG_TEST();
+
+  ctx = grpc_mdctx_create();
+  /* add phase */
+  for (i = 0; i < MANY; i++) {
+    sprintf(buffer, "%ld", i);
+    created[i] = grpc_mdelem_from_strings(ctx, "a", buffer);
+  }
+  /* verify phase */
+  for (i = 0; i < MANY; i++) {
+    sprintf(buffer, "%ld", i);
+    md = grpc_mdelem_from_strings(ctx, "a", buffer);
+    GPR_ASSERT(md == created[i]);
+    grpc_mdelem_unref(md);
+  }
+  /* cleanup phase */
+  for (i = 0; i < MANY; i++) {
+    grpc_mdelem_unref(created[i]);
+  }
+  grpc_mdctx_orphan(ctx);
+
+  gpr_free(created);
+}
+
+static void test_spin_creating_the_same_thing() {
+  grpc_mdctx *ctx;
+
+  LOG_TEST();
+
+  ctx = grpc_mdctx_create();
+  GPR_ASSERT(grpc_mdctx_get_mdtab_count_test_only(ctx) == 0);
+  GPR_ASSERT(grpc_mdctx_get_mdtab_free_test_only(ctx) == 0);
+
+  grpc_mdelem_unref(grpc_mdelem_from_strings(ctx, "a", "b"));
+  GPR_ASSERT(grpc_mdctx_get_mdtab_count_test_only(ctx) == 1);
+  GPR_ASSERT(grpc_mdctx_get_mdtab_free_test_only(ctx) == 1);
+
+  grpc_mdelem_unref(grpc_mdelem_from_strings(ctx, "a", "b"));
+  GPR_ASSERT(grpc_mdctx_get_mdtab_count_test_only(ctx) == 1);
+  GPR_ASSERT(grpc_mdctx_get_mdtab_free_test_only(ctx) == 1);
+
+  grpc_mdelem_unref(grpc_mdelem_from_strings(ctx, "a", "b"));
+  GPR_ASSERT(grpc_mdctx_get_mdtab_count_test_only(ctx) == 1);
+  GPR_ASSERT(grpc_mdctx_get_mdtab_free_test_only(ctx) == 1);
+
+  grpc_mdctx_orphan(ctx);
+}
+
+static void test_things_stick_around() {
+  grpc_mdctx *ctx;
+  int i, j;
+  char buffer[64];
+  int nstrs = 10000;
+  grpc_mdstr **strs = gpr_malloc(sizeof(grpc_mdstr *) * nstrs);
+  int *shuf = gpr_malloc(sizeof(int) * nstrs);
+  grpc_mdstr *test;
+
+  LOG_TEST();
+
+  ctx = grpc_mdctx_create();
+
+  for (i = 0; i < nstrs; i++) {
+    sprintf(buffer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%dx", i);
+    strs[i] = grpc_mdstr_from_string(ctx, buffer);
+    shuf[i] = i;
+  }
+
+  for (i = 0; i < nstrs; i++) {
+    grpc_mdstr_ref(strs[i]);
+    grpc_mdstr_unref(strs[i]);
+  }
+
+  for (i = 0; i < nstrs; i++) {
+    int p = rand() % nstrs;
+    int q = rand() % nstrs;
+    int temp = shuf[p];
+    shuf[p] = shuf[q];
+    shuf[q] = temp;
+  }
+
+  for (i = 0; i < nstrs; i++) {
+    grpc_mdstr_unref(strs[shuf[i]]);
+    for (j = i + 1; j < nstrs; j++) {
+      sprintf(buffer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%dx", shuf[j]);
+      test = grpc_mdstr_from_string(ctx, buffer);
+      GPR_ASSERT(test == strs[shuf[j]]);
+      grpc_mdstr_unref(test);
+    }
+  }
+
+  grpc_mdctx_orphan(ctx);
+  gpr_free(strs);
+  gpr_free(shuf);
+}
+
+static void test_slices_work() {
+  /* ensure no memory leaks when switching representation from mdstr to slice */
+  grpc_mdctx *ctx;
+  grpc_mdstr *str;
+  gpr_slice slice;
+
+  LOG_TEST();
+
+  ctx = grpc_mdctx_create();
+
+  str = grpc_mdstr_from_string(
+      ctx, "123456789012345678901234567890123456789012345678901234567890");
+  slice = gpr_slice_ref(str->slice);
+  grpc_mdstr_unref(str);
+  gpr_slice_unref(slice);
+
+  str = grpc_mdstr_from_string(
+      ctx, "123456789012345678901234567890123456789012345678901234567890");
+  slice = gpr_slice_ref(str->slice);
+  gpr_slice_unref(slice);
+  grpc_mdstr_unref(str);
+
+  grpc_mdctx_orphan(ctx);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_no_op();
+  test_create_string();
+  test_create_metadata();
+  test_create_many_ephemeral_metadata();
+  test_create_many_persistant_metadata();
+  test_spin_creating_the_same_thing();
+  test_things_stick_around();
+  test_slices_work();
+  return 0;
+}
diff --git a/test/core/transport/stream_op_test.c b/test/core/transport/stream_op_test.c
new file mode 100644
index 0000000..0d1122c
--- /dev/null
+++ b/test/core/transport/stream_op_test.c
@@ -0,0 +1,125 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/transport/stream_op.h"
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+static void flow_ctl_cb_fails(void *ignored, grpc_op_error error) {
+  GPR_ASSERT(error == GRPC_OP_ERROR);
+}
+
+static void assert_slices_equal(gpr_slice a, gpr_slice b) {
+  GPR_ASSERT(a.refcount == b.refcount);
+  if (a.refcount) {
+    GPR_ASSERT(a.data.refcounted.bytes == b.data.refcounted.bytes);
+    GPR_ASSERT(a.data.refcounted.length == b.data.refcounted.length);
+  } else {
+    GPR_ASSERT(a.data.inlined.length == b.data.inlined.length);
+    GPR_ASSERT(0 == memcmp(a.data.inlined.bytes, b.data.inlined.bytes,
+                           a.data.inlined.length));
+  }
+}
+
+int main(int argc, char **argv) {
+  /* some basic test data */
+  gpr_slice test_slice_1 = gpr_slice_malloc(1);
+  gpr_slice test_slice_2 = gpr_slice_malloc(2);
+  gpr_slice test_slice_3 = gpr_slice_malloc(3);
+  gpr_slice test_slice_4 = gpr_slice_malloc(4);
+  char x;
+  int i;
+
+  grpc_stream_op_buffer buf;
+  grpc_stream_op_buffer buf2;
+
+  grpc_test_init(argc, argv);
+  /* initialize one of our buffers */
+  grpc_sopb_init(&buf);
+  /* it should start out empty */
+  GPR_ASSERT(buf.nops == 0);
+
+  /* add some data to the buffer */
+  grpc_sopb_add_begin_message(&buf, 1, 2);
+  grpc_sopb_add_slice(&buf, test_slice_1);
+  grpc_sopb_add_slice(&buf, test_slice_2);
+  grpc_sopb_add_slice(&buf, test_slice_3);
+  grpc_sopb_add_slice(&buf, test_slice_4);
+  grpc_sopb_add_flow_ctl_cb(&buf, flow_ctl_cb_fails, &x);
+  grpc_sopb_add_no_op(&buf);
+
+  /* verify that the data went in ok */
+  GPR_ASSERT(buf.nops == 7);
+  GPR_ASSERT(buf.ops[0].type == GRPC_OP_BEGIN_MESSAGE);
+  GPR_ASSERT(buf.ops[0].data.begin_message.length == 1);
+  GPR_ASSERT(buf.ops[0].data.begin_message.flags == 2);
+  GPR_ASSERT(buf.ops[1].type == GRPC_OP_SLICE);
+  assert_slices_equal(buf.ops[1].data.slice, test_slice_1);
+  GPR_ASSERT(buf.ops[2].type == GRPC_OP_SLICE);
+  assert_slices_equal(buf.ops[2].data.slice, test_slice_2);
+  GPR_ASSERT(buf.ops[3].type == GRPC_OP_SLICE);
+  assert_slices_equal(buf.ops[3].data.slice, test_slice_3);
+  GPR_ASSERT(buf.ops[4].type == GRPC_OP_SLICE);
+  assert_slices_equal(buf.ops[4].data.slice, test_slice_4);
+  GPR_ASSERT(buf.ops[5].type == GRPC_OP_FLOW_CTL_CB);
+  GPR_ASSERT(buf.ops[5].data.flow_ctl_cb.cb == flow_ctl_cb_fails);
+  GPR_ASSERT(buf.ops[5].data.flow_ctl_cb.arg == &x);
+  GPR_ASSERT(buf.ops[6].type == GRPC_NO_OP);
+
+  /* initialize the second buffer */
+  grpc_sopb_init(&buf2);
+  /* add a no-op, and then the original buffer */
+  grpc_sopb_add_no_op(&buf2);
+  grpc_sopb_append(&buf2, buf.ops, buf.nops);
+  /* should be one element bigger than the original */
+  GPR_ASSERT(buf2.nops == buf.nops + 1);
+  GPR_ASSERT(buf2.ops[0].type == GRPC_NO_OP);
+  /* and the tail should be the same */
+  for (i = 0; i < buf.nops; i++) {
+    GPR_ASSERT(buf2.ops[i + 1].type == buf.ops[i].type);
+  }
+
+  /* destroy the buffers */
+  grpc_sopb_destroy(&buf);
+  grpc_sopb_destroy(&buf2);
+
+  gpr_slice_unref(test_slice_1);
+  gpr_slice_unref(test_slice_2);
+  gpr_slice_unref(test_slice_3);
+  gpr_slice_unref(test_slice_4);
+
+  return 0;
+}
diff --git a/test/core/transport/transport_end2end_tests.c b/test/core/transport/transport_end2end_tests.c
new file mode 100644
index 0000000..ce6fbcf
--- /dev/null
+++ b/test/core/transport/transport_end2end_tests.c
@@ -0,0 +1,926 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/transport/transport_end2end_tests.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "src/core/transport/transport.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+
+enum { REQUEST_DEADLINE = 200000 }; /* valgrind need a large value */
+
+static grpc_mdctx *g_metadata_context;
+
+static gpr_once g_pending_ops_init = GPR_ONCE_INIT;
+static gpr_mu g_mu;
+static gpr_cv g_cv;
+static int g_pending_ops;
+
+/* Defines a suite of tests that all GRPC transports should be able to pass */
+
+/******************************************************************************
+ * Testing framework
+ */
+
+/* Forward declarations */
+typedef struct test_fixture test_fixture;
+
+/* User data passed to the transport and handed to each callback */
+typedef struct test_user_data { test_fixture *fixture; } test_user_data;
+
+/* A message we expect to receive (forms a singly linked list with next) */
+typedef struct expected_message {
+  /* The next message expected */
+  struct expected_message *next;
+  /* The (owned) data that we expect to receive */
+  gpr_uint8 *data;
+  /* The length of the expected message */
+  size_t length;
+  /* How many bytes of the expected message have we received? */
+  size_t read_pos;
+  /* Have we received the GRPC_OP_BEGIN for this message */
+  int begun;
+} expected_message;
+
+/* Metadata we expect to receive */
+typedef struct expected_metadata {
+  struct expected_metadata *next;
+  struct expected_metadata *prev;
+  grpc_mdelem *metadata;
+} expected_metadata;
+
+/* Tracks a stream for a test. Forms a doubly-linked list with (prev, next) */
+typedef struct test_stream {
+  /* The owning fixture */
+  test_fixture *fixture;
+  /* The transport client stream */
+  grpc_stream *client_stream;
+  /* The transport server stream */
+  grpc_stream *server_stream;
+  /* Linked lists of messages expected on client and server */
+  expected_message *client_expected_messages;
+  expected_message *server_expected_messages;
+  expected_metadata *client_expected_metadata;
+  expected_metadata *server_expected_metadata;
+
+  /* Test streams are linked in the fixture */
+  struct test_stream *next;
+  struct test_stream *prev;
+} test_stream;
+
+/* A test_fixture tracks all transport state and expectations for a test */
+struct test_fixture {
+  gpr_mu mu;
+  gpr_cv cv; /* broadcast when expectation state has changed */
+
+  /* The transport instances */
+  grpc_transport *client_transport;
+  grpc_transport *server_transport;
+  /* User data for the transport instances - pointers to these are passed
+     to the transport. */
+  test_user_data client_ud;
+  test_user_data server_ud;
+
+  /* A pointer to the head of the tracked streams list, or NULL if no streams
+     are open */
+  test_stream *streams;
+};
+
+static void expect_metadata(test_stream *s, int from_client, const char *key,
+                            const char *value);
+
+/* Convert some number of seconds into a gpr_timespec that many seconds in the
+   future */
+static gpr_timespec deadline_from_seconds(double deadline_seconds) {
+  return gpr_time_add(gpr_now(), gpr_time_from_micros(deadline_seconds * 1e6));
+}
+
+/* Init a test_user_data instance */
+static void init_user_data(test_user_data *ud, test_fixture *f,
+                           grpc_transport_test_config *config, int is_client) {
+  ud->fixture = f;
+}
+
+/* Implements the alloc_recv_buffer transport callback */
+static gpr_slice alloc_recv_buffer(void *user_data, grpc_transport *transport,
+                                   grpc_stream *stream, size_t size_hint) {
+  return gpr_slice_malloc(size_hint);
+}
+
+static void pending_ops_cleanup() {
+  gpr_mu_destroy(&g_mu);
+  gpr_cv_destroy(&g_cv);
+}
+
+static void pending_ops_init() {
+  gpr_mu_init(&g_mu);
+  gpr_cv_init(&g_cv);
+  atexit(pending_ops_cleanup);
+}
+
+static void use_pending_ops() {
+  gpr_once_init(&g_pending_ops_init, pending_ops_init);
+}
+
+static void add_pending_op() {
+  use_pending_ops();
+  gpr_mu_lock(&g_mu);
+  g_pending_ops++;
+  gpr_mu_unlock(&g_mu);
+}
+
+static void end_pending_op() {
+  gpr_mu_lock(&g_mu);
+  g_pending_ops--;
+  gpr_cv_broadcast(&g_cv);
+  gpr_mu_unlock(&g_mu);
+}
+
+static void wait_pending_ops() {
+  use_pending_ops();
+  gpr_mu_lock(&g_mu);
+  while (g_pending_ops > 0) {
+    gpr_cv_wait(&g_cv, &g_mu, gpr_inf_future);
+  }
+  gpr_mu_unlock(&g_mu);
+}
+
+/* Implements the create_stream transport callback */
+static void create_stream(void *user_data, grpc_transport *transport,
+                          const void *server_data) {
+  test_user_data *ud = user_data;
+  test_fixture *f = ud->fixture;
+  test_stream *stream;
+
+  GPR_ASSERT(ud == &f->server_ud);
+  GPR_ASSERT(transport == f->server_transport);
+
+  gpr_mu_lock(&f->mu);
+
+  /* Search streams for the peer to this stream */
+  if (!f->streams) goto done;
+  /* found the expecting stream */
+  stream = f->streams;
+  stream->server_stream = gpr_malloc(grpc_transport_stream_size(transport));
+  grpc_transport_init_stream(transport, stream->server_stream, server_data);
+
+done:
+  /* wakeup begin_stream, and maybe wait_and_verify */
+  gpr_cv_broadcast(&f->cv);
+  gpr_mu_unlock(&f->mu);
+}
+
+/* Search fixture streams for the test_stream instance holding a given transport
+   stream */
+static test_stream *find_test_stream(test_fixture *f, grpc_stream *stream) {
+  test_stream *s;
+
+  GPR_ASSERT(f->streams);
+  s = f->streams;
+  do {
+    if (s->client_stream == stream || s->server_stream == stream) {
+      return s;
+    }
+  } while (s != f->streams);
+
+  GPR_ASSERT(0 && "found");
+  return NULL;
+}
+
+/* Stringify a grpc_stream_state for debugging */
+static const char *state_name(grpc_stream_state state) {
+  switch (state) {
+    case GRPC_STREAM_OPEN:
+      return "GRPC_STREAM_OPEN";
+    case GRPC_STREAM_RECV_CLOSED:
+      return "GRPC_STREAM_RECV_CLOSED";
+    case GRPC_STREAM_SEND_CLOSED:
+      return "GRPC_STREAM_SEND_CLOSED";
+    case GRPC_STREAM_CLOSED:
+      return "GRPC_STREAM_CLOSED";
+  }
+  GPR_ASSERT(0 && "reachable");
+  return NULL;
+}
+
+typedef struct {
+  grpc_transport *transport;
+  grpc_stream *stream;
+} destroy_stream_args;
+
+static void destroy_stream(void *p) {
+  destroy_stream_args *a = p;
+  grpc_transport_destroy_stream(a->transport, a->stream);
+  gpr_free(a->stream);
+  gpr_free(a);
+  end_pending_op();
+}
+
+static void recv_batch(void *user_data, grpc_transport *transport,
+                       grpc_stream *stream, grpc_stream_op *ops,
+                       size_t ops_count, grpc_stream_state final_state) {
+  test_user_data *ud = user_data;
+  test_fixture *f = ud->fixture;
+  test_stream *s;
+  /* Pointer to the root pointer of either client or server expected messages;
+     not a simple pointer as we may need to manipulate the list (on receipt
+     of messages */
+  expected_message **expect_root_message;
+  expected_metadata **expect_root_metadata;
+  expected_metadata *emd;
+  size_t i, j;
+  char *hexstr1, *hexstr2;
+  int repeats = 0;
+
+  gpr_mu_lock(&f->mu);
+
+  s = find_test_stream(f, stream);
+  expect_root_message = s->client_stream == stream
+                            ? &s->client_expected_messages
+                            : &s->server_expected_messages;
+  expect_root_metadata = s->client_stream == stream
+                             ? &s->client_expected_metadata
+                             : &s->server_expected_metadata;
+
+  /* Debug log */
+  gpr_log(GPR_DEBUG, "recv_batch: %d ops on %s final_state=%s", ops_count,
+          s->client_stream == stream ? "client" : "server",
+          state_name(final_state));
+#define CLEAR_REPEATS                           \
+  if (repeats) {                                \
+    gpr_log(GPR_DEBUG, "  + %d more", repeats); \
+    repeats = 0;                                \
+  }
+  for (i = 0; i < ops_count; i++) {
+    switch (ops[i].type) {
+      case GRPC_NO_OP:
+        CLEAR_REPEATS;
+        gpr_log(GPR_DEBUG, "  [%02d] GRPC_NO_OP", i);
+        break;
+      case GRPC_OP_METADATA_BOUNDARY:
+        CLEAR_REPEATS;
+        gpr_log(GPR_DEBUG, "  [%02d] GRPC_OP_METADATA_BOUNDARY", i);
+        break;
+      case GRPC_OP_METADATA:
+        CLEAR_REPEATS;
+        hexstr1 =
+            gpr_hexdump(grpc_mdstr_as_c_string(ops[i].data.metadata->key),
+                        GPR_SLICE_LENGTH(ops[i].data.metadata->key->slice),
+                        GPR_HEXDUMP_PLAINTEXT);
+        hexstr2 =
+            gpr_hexdump(grpc_mdstr_as_c_string(ops[i].data.metadata->value),
+                        GPR_SLICE_LENGTH(ops[i].data.metadata->value->slice),
+                        GPR_HEXDUMP_PLAINTEXT);
+        gpr_log(GPR_DEBUG, "  [%02d] GRPC_OP_METADATA key=%s value=%s", i,
+                hexstr1, hexstr2);
+        gpr_free(hexstr1);
+        gpr_free(hexstr2);
+        break;
+      case GRPC_OP_BEGIN_MESSAGE:
+        CLEAR_REPEATS;
+        gpr_log(GPR_DEBUG, "  [%02d] GRPC_OP_BEGIN_MESSAGE len=%d", i,
+                ops[i].data.begin_message.length);
+        break;
+      case GRPC_OP_DEADLINE:
+        CLEAR_REPEATS;
+        gpr_log(GPR_DEBUG, "  [%02d] GRPC_OP_DEADLINE value=%d.%09d", i,
+                ops[i].data.deadline.tv_sec, ops[i].data.deadline.tv_nsec);
+        break;
+      case GRPC_OP_SLICE:
+        if (i && ops[i - 1].type == GRPC_OP_SLICE &&
+            GPR_SLICE_LENGTH(ops[i - 1].data.slice) ==
+                GPR_SLICE_LENGTH(ops[i].data.slice)) {
+          repeats++;
+        } else {
+          CLEAR_REPEATS;
+          gpr_log(GPR_DEBUG, "  [%02d] GRPC_OP_SLICE len=%d", i,
+                  GPR_SLICE_LENGTH(ops[i].data.slice));
+        }
+        break;
+      case GRPC_OP_FLOW_CTL_CB:
+        CLEAR_REPEATS;
+        gpr_log(GPR_DEBUG, "  [%02d] GRPC_OP_FLOW_CTL_CB", i);
+        break;
+    }
+  }
+  CLEAR_REPEATS;
+
+  /* Iterate over operations, and verify them against expectations */
+  for (i = 0; i < ops_count; i++) {
+    switch (ops[i].type) {
+      case GRPC_NO_OP:
+        break;
+      case GRPC_OP_METADATA_BOUNDARY:
+        break;
+      case GRPC_OP_METADATA:
+        GPR_ASSERT(*expect_root_metadata && "must be expecting metadata");
+        emd = *expect_root_metadata;
+        if (emd == NULL) {
+          gpr_log(GPR_ERROR, "metadata not found");
+          abort();
+        }
+        do {
+          if (emd->metadata == ops[i].data.metadata) {
+            if (emd == *expect_root_metadata) {
+              if (emd->next == emd) {
+                *expect_root_metadata = NULL;
+              } else {
+                *expect_root_metadata = emd->next;
+              }
+            }
+            emd->next->prev = emd->prev;
+            emd->prev->next = emd->next;
+            grpc_mdelem_unref(emd->metadata);
+            grpc_mdelem_unref(ops[i].data.metadata);
+            gpr_free(emd);
+            emd = NULL;
+            break;
+          }
+          emd = emd->next;
+        } while (emd != *expect_root_metadata);
+        if (emd) {
+          gpr_log(GPR_ERROR, "metadata not found");
+          abort();
+        }
+        break;
+      case GRPC_OP_BEGIN_MESSAGE:
+        GPR_ASSERT(*expect_root_message && "must be expecting a message");
+        GPR_ASSERT((*expect_root_message)->read_pos == 0 &&
+                   "must be at the start of a message");
+        GPR_ASSERT((*expect_root_message)->begun == 0 &&
+                   "can only BEGIN a message once");
+        GPR_ASSERT((*expect_root_message)->length ==
+                       ops[i].data.begin_message.length &&
+                   "message lengths must match");
+        (*expect_root_message)->begun = 1;
+        break;
+      case GRPC_OP_SLICE:
+        GPR_ASSERT(*expect_root_message && "must be expecting a message");
+        GPR_ASSERT((*expect_root_message)->begun == 1 &&
+                   "must have begun a message");
+        GPR_ASSERT((*expect_root_message)->read_pos +
+                           GPR_SLICE_LENGTH(ops[i].data.slice) <=
+                       (*expect_root_message)->length &&
+                   "must not send more data than expected");
+        for (j = 0; j < GPR_SLICE_LENGTH(ops[i].data.slice); j++) {
+          GPR_ASSERT((*expect_root_message)
+                             ->data[(*expect_root_message)->read_pos + j] ==
+                         GPR_SLICE_START_PTR(ops[i].data.slice)[j] &&
+                     "must send the correct message");
+        }
+        (*expect_root_message)->read_pos += GPR_SLICE_LENGTH(ops[i].data.slice);
+        if ((*expect_root_message)->read_pos ==
+            (*expect_root_message)->length) {
+          expected_message *great_success = *expect_root_message;
+          *expect_root_message = great_success->next;
+          gpr_free(great_success->data);
+          gpr_free(great_success);
+        }
+        gpr_slice_unref(ops[i].data.slice);
+        break;
+      case GRPC_OP_FLOW_CTL_CB:
+        GPR_ASSERT(0 && "allowed");
+        break;
+      case GRPC_OP_DEADLINE:
+        GPR_ASSERT(0 && "implemented");
+        break;
+    }
+  }
+
+  /* If the stream has become fully closed then we must destroy the transport
+     part of the stream */
+  if (final_state == GRPC_STREAM_CLOSED) {
+    destroy_stream_args *dsa = gpr_malloc(sizeof(destroy_stream_args));
+    gpr_thd_id id;
+    dsa->transport = transport;
+    dsa->stream = stream;
+    /* start a thread after incrementing a pending op counter (so we can wait
+       at test completion */
+    add_pending_op();
+    gpr_thd_new(&id, destroy_stream, dsa, NULL);
+    if (stream == s->client_stream) {
+      GPR_ASSERT(s->client_expected_messages == NULL &&
+                 "must receive all expected messages");
+      s->client_stream = NULL;
+    } else {
+      GPR_ASSERT(s->server_expected_messages == NULL &&
+                 "must receive all expected messages");
+      s->server_stream = NULL;
+    }
+    /* And if both the client and the server report fully closed, we can
+       unlink the stream object entirely */
+    if (s->client_stream == NULL && s->server_stream == NULL) {
+      s->next->prev = s->prev;
+      s->prev->next = s->next;
+      if (s == f->streams) {
+        if (s->next == f->streams) {
+          f->streams = NULL;
+        } else {
+          f->streams = s->next;
+        }
+      }
+    }
+  }
+
+  /* wakeup wait_and_verify */
+  gpr_cv_broadcast(&f->cv);
+  gpr_mu_unlock(&f->mu);
+}
+
+static void close_transport(void *user_data, grpc_transport *transport) {}
+
+static grpc_transport_callbacks transport_callbacks = {
+    alloc_recv_buffer, create_stream, recv_batch, close_transport};
+
+/* Helper for tests to create a stream.
+   Arguments:
+     s - uninitialized test_stream struct to begin
+     f - test fixture to associate this stream with
+     method, host, deadline_seconds - header fields for the stream */
+static void begin_stream(test_stream *s, test_fixture *f, const char *method,
+                         const char *host, double deadline_seconds) {
+  /* Deadline to initiate the stream (prevents the tests from hanging
+     forever) */
+  gpr_timespec deadline = deadline_from_seconds(10.0);
+  grpc_stream_op_buffer sopb;
+
+  grpc_sopb_init(&sopb);
+
+  gpr_mu_lock(&f->mu);
+
+  s->fixture = f;
+  s->client_stream =
+      gpr_malloc(grpc_transport_stream_size(f->client_transport));
+  /* server stream will be set once it's received by the peer transport */
+  s->server_stream = NULL;
+  s->client_expected_messages = NULL;
+  s->server_expected_messages = NULL;
+  s->client_expected_metadata = NULL;
+  s->server_expected_metadata = NULL;
+
+  if (f->streams) {
+    s->next = f->streams;
+    s->prev = s->next->prev;
+    s->next->prev = s->prev->next = s;
+  } else {
+    s->next = s->prev = s;
+  }
+  f->streams = s;
+
+  gpr_mu_unlock(&f->mu);
+
+  GPR_ASSERT(0 == grpc_transport_init_stream(f->client_transport,
+                                             s->client_stream, NULL));
+
+#define ADDMD(k, v)                                                           \
+  do {                                                                        \
+    grpc_mdelem *md = grpc_mdelem_from_strings(g_metadata_context, (k), (v)); \
+    grpc_sopb_add_metadata(&sopb, md);                                        \
+    expect_metadata(s, 1, (k), (v));                                          \
+  } while (0)
+
+  ADDMD(":path", method);
+  ADDMD(":authority", host);
+  ADDMD(":method", "POST");
+  grpc_transport_send_batch(f->client_transport, s->client_stream, sopb.ops,
+                            sopb.nops, 0);
+  sopb.nops = 0;
+
+  grpc_sopb_destroy(&sopb);
+
+  /* wait for the server side stream to be created */
+  gpr_mu_lock(&f->mu);
+  while (s->server_stream == NULL) {
+    GPR_ASSERT(0 == gpr_cv_wait(&f->cv, &f->mu, deadline));
+  }
+  gpr_mu_unlock(&f->mu);
+}
+
+static grpc_transport_setup_result setup_transport(
+    test_fixture *f, grpc_transport **set_transport, void *user_data,
+    grpc_transport *transport) {
+  grpc_transport_setup_result result;
+
+  gpr_mu_lock(&f->mu);
+  *set_transport = transport;
+  gpr_cv_broadcast(&f->cv);
+  gpr_mu_unlock(&f->mu);
+
+  result.callbacks = &transport_callbacks;
+  result.user_data = user_data;
+  return result;
+}
+
+static grpc_transport_setup_result setup_server_transport(
+    void *arg, grpc_transport *transport, grpc_mdctx *mdctx) {
+  test_fixture *f = arg;
+  return setup_transport(f, &f->server_transport, &f->server_ud, transport);
+}
+
+static grpc_transport_setup_result setup_client_transport(
+    void *arg, grpc_transport *transport, grpc_mdctx *mdctx) {
+  test_fixture *f = arg;
+  return setup_transport(f, &f->client_transport, &f->client_ud, transport);
+}
+
+/* Begin a test
+
+   Arguments:
+     f      - uninitialized test_fixture struct
+     config - test configuration for this test
+     name   - the name of this test */
+static void begin_test(test_fixture *f, grpc_transport_test_config *config,
+                       const char *name) {
+  gpr_timespec timeout = gpr_time_add(gpr_now(), gpr_time_from_micros(100e6));
+
+  gpr_log(GPR_INFO, "BEGIN: %s/%s", name, config->name);
+
+  gpr_mu_init(&f->mu);
+  gpr_cv_init(&f->cv);
+
+  f->streams = NULL;
+
+  init_user_data(&f->client_ud, f, config, 1);
+  init_user_data(&f->server_ud, f, config, 0);
+
+  f->client_transport = NULL;
+  f->server_transport = NULL;
+
+  GPR_ASSERT(0 ==
+             config->create_transport(setup_client_transport, f,
+                                      setup_server_transport, f,
+                                      g_metadata_context));
+
+  gpr_mu_lock(&f->mu);
+  while (!f->client_transport || !f->server_transport) {
+    GPR_ASSERT(gpr_cv_wait(&f->cv, &f->mu, timeout));
+  }
+  gpr_mu_unlock(&f->mu);
+}
+
+/* Enumerate expected messages on a stream */
+static void enumerate_expected_messages(
+    test_stream *s, expected_message *root, const char *stream_tag,
+    void (*cb)(void *user, const char *fmt, ...), void *user) {
+  expected_message *msg;
+
+  for (msg = root; msg; msg = msg->next) {
+    cb(user,
+       "Waiting for message to finish: "
+       "length=%zu read_pos=%zu begun=%d",
+       msg->length, msg->read_pos);
+  }
+}
+
+/* Walk through everything that is still waiting to happen, and call 'cb' with
+   userdata 'user' for that expectation. */
+static void enumerate_expectations(test_fixture *f,
+                                   void (*cb)(void *user, const char *fmt, ...),
+                                   void *user) {
+  test_stream *stream;
+
+  if (f->streams) {
+    stream = f->streams;
+    do {
+      cb(user,
+         "Waiting for request to close: "
+         "client=%p, server=%p",
+         stream->client_stream, stream->server_stream);
+      enumerate_expected_messages(stream, stream->client_expected_messages,
+                                  "client", cb, user);
+      enumerate_expected_messages(stream, stream->server_expected_messages,
+                                  "server", cb, user);
+      stream = stream->next;
+    } while (stream != f->streams);
+  }
+}
+
+/* Callback for enumerate_expectations, that increments an integer each time
+   an expectation is seen */
+static void increment_expectation_count(void *p, const char *fmt, ...) {
+  ++*(int *)p;
+}
+
+/* Returns the count of pending expectations in a fixture. Requires mu taken */
+static int count_expectations(test_fixture *f) {
+  int n = 0;
+  enumerate_expectations(f, increment_expectation_count, &n);
+  return n;
+}
+
+/* Callback for enumerate_expectations that adds an expectation to the log */
+static void dump_expectation(void *p, const char *fmt, ...) {
+  char buffer[256];
+  va_list args;
+  va_start(args, fmt);
+
+  vsprintf(buffer, fmt, args);
+  gpr_log(GPR_INFO, "EXPECTED: %s", buffer);
+
+  va_end(args);
+}
+
+/* Add all pending expectations to the log */
+static void dump_expectations(test_fixture *f) {
+  enumerate_expectations(f, dump_expectation, NULL);
+}
+
+/* Wait until all expectations are completed, or crash */
+static void wait_and_verify(test_fixture *f) {
+  gpr_timespec deadline = deadline_from_seconds(10.0);
+
+  gpr_mu_lock(&f->mu);
+  while (count_expectations(f) > 0) {
+    gpr_log(GPR_INFO, "waiting for expectations to complete");
+    if (gpr_cv_wait(&f->cv, &f->mu, deadline)) {
+      gpr_log(GPR_ERROR, "Timeout waiting for expectation completion");
+      dump_expectations(f);
+      gpr_mu_unlock(&f->mu);
+      abort();
+    }
+  }
+  gpr_mu_unlock(&f->mu);
+}
+
+/* Finish a test */
+static void end_test(test_fixture *f) {
+  wait_and_verify(f);
+
+  grpc_transport_close(f->client_transport);
+  grpc_transport_close(f->server_transport);
+  grpc_transport_destroy(f->client_transport);
+  grpc_transport_destroy(f->server_transport);
+
+  wait_pending_ops();
+}
+
+/* Generate a test slice filled with {0,1,2,3,...,255,0,1,2,3,4,...} */
+static gpr_slice generate_test_data(size_t length) {
+  gpr_slice slice = gpr_slice_malloc(length);
+  int i;
+  for (i = 0; i < length; i++) {
+    GPR_SLICE_START_PTR(slice)[i] = i;
+  }
+  return slice;
+}
+
+/* Add an expected message to the end of a list with root root */
+static void append_expected_message(expected_message **root,
+                                    expected_message *message) {
+  expected_message *end;
+
+  if (!*root) {
+    *root = message;
+    return;
+  }
+
+  for (end = *root; end->next; end = end->next)
+    ;
+  end->next = message;
+}
+
+/* Add an expected message on stream 's''.
+   If from_client==1, expect it on the server, otherwise expect it on the client
+   Variadic parameters are a NULL-terminated list of pointers to slices that
+   should be expected as payload */
+static void expect_message(test_stream *s, int from_client,
+                           /* gpr_slice* */...) {
+  va_list args;
+  gpr_slice *slice;
+  size_t capacity = 32;
+  size_t length = 0;
+  gpr_uint8 *buffer = gpr_malloc(capacity);
+  expected_message *e;
+
+  va_start(args, from_client);
+  while ((slice = va_arg(args, gpr_slice *))) {
+    while (GPR_SLICE_LENGTH(*slice) + length > capacity) {
+      capacity *= 2;
+      buffer = gpr_realloc(buffer, capacity);
+    }
+    memcpy(buffer + length, GPR_SLICE_START_PTR(*slice),
+           GPR_SLICE_LENGTH(*slice));
+    length += GPR_SLICE_LENGTH(*slice);
+  }
+  va_end(args);
+
+  e = gpr_malloc(sizeof(expected_message));
+  e->data = buffer;
+  e->length = length;
+  e->read_pos = 0;
+  e->begun = 0;
+  e->next = NULL;
+
+  gpr_mu_lock(&s->fixture->mu);
+  append_expected_message(
+      from_client ? &s->server_expected_messages : &s->client_expected_messages,
+      e);
+  gpr_mu_unlock(&s->fixture->mu);
+}
+
+static void expect_metadata(test_stream *s, int from_client, const char *key,
+                            const char *value) {
+  expected_metadata *e = gpr_malloc(sizeof(expected_metadata));
+  expected_metadata **root =
+      from_client ? &s->server_expected_metadata : &s->client_expected_metadata;
+  e->metadata = grpc_mdelem_from_strings(g_metadata_context, key, value);
+  gpr_mu_lock(&s->fixture->mu);
+  if (!*root) {
+    *root = e;
+    e->next = e->prev = e;
+  } else {
+    e->next = *root;
+    e->prev = e->next->prev;
+    e->next->prev = e->prev->next = e;
+  }
+  gpr_mu_unlock(&s->fixture->mu);
+}
+
+/******************************************************************************
+ * Actual unit tests
+ */
+
+/* Test that we can create, begin, and end a test */
+static void test_no_op(grpc_transport_test_config *config) {
+  test_fixture f;
+  begin_test(&f, config, __FUNCTION__);
+  end_test(&f);
+}
+
+/* Test that a request can be initiated and terminated normally */
+static void test_simple_request(grpc_transport_test_config *config) {
+  test_fixture f;
+  test_stream s;
+
+  begin_test(&f, config, __FUNCTION__);
+  begin_stream(&s, &f, "/Test", "foo.google.com", 10);
+  grpc_transport_send_batch(f.client_transport, s.client_stream, NULL, 0, 1);
+  grpc_transport_send_batch(f.server_transport, s.server_stream, NULL, 0, 1);
+  end_test(&f);
+}
+
+/* Test that a request can be aborted by the client */
+static void test_can_abort_client(grpc_transport_test_config *config) {
+  test_fixture f;
+  test_stream s;
+
+  begin_test(&f, config, __FUNCTION__);
+  begin_stream(&s, &f, "/Test", "foo.google.com", 10);
+  expect_metadata(&s, 0, "grpc-status", "1");
+  expect_metadata(&s, 1, "grpc-status", "1");
+  grpc_transport_abort_stream(f.client_transport, s.client_stream,
+                              GRPC_STATUS_CANCELLED);
+  end_test(&f);
+}
+
+/* Test that a request can be aborted by the server */
+static void test_can_abort_server(grpc_transport_test_config *config) {
+  test_fixture f;
+  test_stream s;
+
+  begin_test(&f, config, __FUNCTION__);
+  begin_stream(&s, &f, "/Test", "foo.google.com", 10);
+  expect_metadata(&s, 0, "grpc-status", "1");
+  expect_metadata(&s, 1, "grpc-status", "1");
+  grpc_transport_abort_stream(f.server_transport, s.server_stream,
+                              GRPC_STATUS_CANCELLED);
+  end_test(&f);
+}
+
+/* Test that a request can be sent with payload */
+static void test_request_with_data(grpc_transport_test_config *config,
+                                   size_t message_length) {
+  test_fixture f;
+  test_stream s;
+  gpr_slice data = generate_test_data(message_length);
+  grpc_stream_op_buffer sopb;
+
+  grpc_sopb_init(&sopb);
+  begin_test(&f, config, __FUNCTION__);
+  gpr_log(GPR_INFO, "message_length = %d", message_length);
+  begin_stream(&s, &f, "/Test", "foo.google.com", 10);
+  expect_message(&s, 1, &data, NULL);
+  grpc_sopb_add_begin_message(&sopb, message_length, 0);
+  grpc_sopb_add_slice(&sopb, data);
+  grpc_transport_set_allow_window_updates(f.server_transport, s.server_stream,
+                                          1);
+  grpc_transport_send_batch(f.client_transport, s.client_stream, sopb.ops,
+                            sopb.nops, 1);
+  sopb.nops = 0;
+  grpc_transport_send_batch(f.server_transport, s.server_stream, NULL, 0, 1);
+  end_test(&f);
+  grpc_sopb_destroy(&sopb);
+}
+
+/* Increment an integer pointed to by x - used for verifying flow control */
+static void increment_int(void *x, grpc_op_error error) { ++*(int *)x; }
+
+/* Test that flow control callbacks are made at appropriate times */
+static void test_request_with_flow_ctl_cb(grpc_transport_test_config *config,
+                                          size_t message_length) {
+  test_fixture f;
+  test_stream s;
+  int flow_ctl_called = 0;
+  gpr_slice data = generate_test_data(message_length);
+  grpc_stream_op_buffer sopb;
+
+  grpc_sopb_init(&sopb);
+  begin_test(&f, config, __FUNCTION__);
+  gpr_log(GPR_INFO, "length=%d", message_length);
+  begin_stream(&s, &f, "/Test", "foo.google.com", 10);
+  expect_message(&s, 1, &data, NULL);
+  grpc_sopb_add_begin_message(&sopb, message_length, 0);
+  grpc_sopb_add_slice(&sopb, data);
+  grpc_sopb_add_flow_ctl_cb(&sopb, increment_int, &flow_ctl_called);
+  grpc_transport_set_allow_window_updates(f.server_transport, s.server_stream,
+                                          1);
+  grpc_transport_send_batch(f.client_transport, s.client_stream, sopb.ops,
+                            sopb.nops, 1);
+  sopb.nops = 0;
+  grpc_transport_send_batch(f.server_transport, s.server_stream, NULL, 0, 1);
+  end_test(&f);
+  GPR_ASSERT(flow_ctl_called == 1);
+  grpc_sopb_destroy(&sopb);
+}
+
+/* Set an event on ping response */
+static void ping_cb(void *p) { gpr_event_set(p, (void *)1); }
+
+/* Test that pinging gets a response */
+static void test_ping(grpc_transport_test_config *config) {
+  test_fixture f;
+  gpr_event ev;
+
+  begin_test(&f, config, __FUNCTION__);
+  gpr_event_init(&ev);
+
+  grpc_transport_ping(f.client_transport, ping_cb, &ev);
+  GPR_ASSERT(gpr_event_wait(&ev, deadline_from_seconds(10)));
+
+  end_test(&f);
+}
+
+/******************************************************************************
+ * Test driver
+ */
+
+static const size_t interesting_message_lengths[] = {
+    1, 100, 10000, 100000, 1000000,
+};
+
+void grpc_transport_end2end_tests(grpc_transport_test_config *config) {
+  int i;
+
+  g_metadata_context = grpc_mdctx_create();
+
+  test_no_op(config);
+  test_simple_request(config);
+  test_can_abort_client(config);
+  test_can_abort_server(config);
+  test_ping(config);
+  for (i = 0; i < GPR_ARRAY_SIZE(interesting_message_lengths); i++) {
+    test_request_with_data(config, interesting_message_lengths[i]);
+    test_request_with_flow_ctl_cb(config, interesting_message_lengths[i]);
+  }
+
+  grpc_mdctx_orphan(g_metadata_context);
+
+  gpr_log(GPR_INFO, "tests completed ok");
+}
diff --git a/test/core/transport/transport_end2end_tests.h b/test/core/transport/transport_end2end_tests.h
new file mode 100644
index 0000000..322034f
--- /dev/null
+++ b/test/core/transport/transport_end2end_tests.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_TEST_TRANSPORT_TRANSPORT_END2END_TESTS_H__
+#define __GRPC_TEST_TRANSPORT_TRANSPORT_END2END_TESTS_H__
+
+#include "src/core/transport/transport.h"
+
+/* Defines a suite of tests that all GRPC transports should be able to pass */
+
+/* A test configuration has a name and a factory method */
+typedef struct grpc_transport_test_config {
+  /* The name of this configuration */
+  char *name;
+  /* Create a transport
+     Returns 0 on success
+
+     Arguments:
+       OUT: client           - the created client half of the transport
+       IN:  client_callbacks - callback structure to be used by the client
+                               transport
+       IN:  client_user_data - user data pointer to be passed into each client
+                               callback
+       OUT: server           - the created server half of the transport
+       IN:  server_callbacks - callback structure to be used by the server
+                               transport
+       IN:  server_user_data - user data pointer to be passed into each
+                               server */
+  int (*create_transport)(grpc_transport_setup_callback client_setup,
+                          void *client_arg,
+                          grpc_transport_setup_callback server_setup,
+                          void *server_arg, grpc_mdctx *mdctx);
+} grpc_transport_test_config;
+
+/* Run the test suite on one configuration */
+void grpc_transport_end2end_tests(grpc_transport_test_config *config);
+
+#endif  /* __GRPC_TEST_TRANSPORT_TRANSPORT_END2END_TESTS_H__ */
diff --git a/test/core/util/grpc_profiler.c b/test/core/util/grpc_profiler.c
new file mode 100644
index 0000000..e135743
--- /dev/null
+++ b/test/core/util/grpc_profiler.c
@@ -0,0 +1,38 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/util/grpc_profiler.h"
+
+void grpc_profiler_start(const char *filename) {}
+
+void grpc_profiler_stop() {}
diff --git a/test/core/util/grpc_profiler.h b/test/core/util/grpc_profiler.h
new file mode 100644
index 0000000..7cc4733
--- /dev/null
+++ b/test/core/util/grpc_profiler.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_TEST_UTIL_GRPC_PROFILER_H__
+#define __GRPC_TEST_UTIL_GRPC_PROFILER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /*  __cplusplus */
+
+void grpc_profiler_start(const char *filename);
+void grpc_profiler_stop();
+
+#ifdef __cplusplus
+}
+#endif /*  __cplusplus */
+
+#endif  /* __GRPC_TEST_UTIL_GRPC_PROFILER_H__ */
diff --git a/test/core/util/parse_hexstring.c b/test/core/util/parse_hexstring.c
new file mode 100644
index 0000000..888d03b
--- /dev/null
+++ b/test/core/util/parse_hexstring.c
@@ -0,0 +1,70 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/util/parse_hexstring.h"
+#include <grpc/support/log.h>
+
+gpr_slice parse_hexstring(const char *hexstring) {
+  int nibbles = 0;
+  const char *p = 0;
+  gpr_uint8 *out;
+  gpr_uint8 temp;
+  gpr_slice slice;
+
+  for (p = hexstring; *p; p++) {
+    nibbles += (*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f');
+  }
+
+  GPR_ASSERT((nibbles & 1) == 0);
+
+  slice = gpr_slice_malloc(nibbles / 2);
+  out = GPR_SLICE_START_PTR(slice);
+
+  nibbles = 0;
+  temp = 0;
+  for (p = hexstring; *p; p++) {
+    if (*p >= '0' && *p <= '9') {
+      temp = (temp << 4) | (*p - '0');
+      nibbles++;
+    } else if (*p >= 'a' && *p <= 'f') {
+      temp = (temp << 4) | (*p - 'a' + 10);
+      nibbles++;
+    }
+    if (nibbles == 2) {
+      *out++ = temp;
+      nibbles = 0;
+    }
+  }
+
+  return slice;
+}
diff --git a/test/core/util/parse_hexstring.h b/test/core/util/parse_hexstring.h
new file mode 100644
index 0000000..7477986
--- /dev/null
+++ b/test/core/util/parse_hexstring.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_TEST_UTIL_PARSE_HEXSTRING_H_
+#define __GRPC_TEST_UTIL_PARSE_HEXSTRING_H_
+
+#include <grpc/support/slice.h>
+
+gpr_slice parse_hexstring(const char *hexstring);
+
+#endif /* __GRPC_TEST_UTIL_PARSE_HEXSTRING_H_ */
diff --git a/test/core/util/port.c b/test/core/util/port.c
new file mode 100644
index 0000000..133b53f
--- /dev/null
+++ b/test/core/util/port.c
@@ -0,0 +1,145 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/util/port.h"
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/support/log.h>
+
+#define NUM_RANDOM_PORTS_TO_PICK 100
+
+static int is_port_available(int *port, int is_tcp) {
+  const int proto = is_tcp ? IPPROTO_TCP : 0;
+  const int fd = socket(AF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM, proto);
+  int one = 1;
+  struct sockaddr_in addr;
+  socklen_t alen = sizeof(addr);
+  int actual_port;
+
+  GPR_ASSERT(*port >= 0);
+  GPR_ASSERT(*port <= 65535);
+  if (fd < 0) {
+    gpr_log(GPR_ERROR, "socket() failed: %s", strerror(errno));
+    return 0;
+  }
+
+  /* Reuseaddr lets us start up a server immediately after it exits */
+  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
+    gpr_log(GPR_ERROR, "setsockopt() failed: %s", strerror(errno));
+    close(fd);
+    return 0;
+  }
+
+  /* Try binding to port */
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = INADDR_ANY;
+  addr.sin_port = htons(*port);
+  if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+    gpr_log(GPR_DEBUG, "bind(port=%d) failed: %s", *port, strerror(errno));
+    close(fd);
+    return 0;
+  }
+
+  /* Get the bound port number */
+  if (getsockname(fd, (struct sockaddr *)&addr, &alen) < 0) {
+    gpr_log(GPR_ERROR, "getsockname() failed: %s", strerror(errno));
+    close(fd);
+    return 0;
+  }
+  GPR_ASSERT(alen <= sizeof(addr));
+  actual_port = ntohs(addr.sin_port);
+  GPR_ASSERT(actual_port > 0);
+  if (*port == 0) {
+    *port = actual_port;
+  } else {
+    GPR_ASSERT(*port == actual_port);
+  }
+
+  close(fd);
+  return 1;
+}
+
+int grpc_pick_unused_port() {
+  /* We repeatedly pick a port and then see whether or not it is
+     available for use both as a TCP socket and a UDP socket.  First, we
+     pick a random large port number.  For subsequent
+     iterations, we bind to an anonymous port and let the OS pick the
+     port number.  The random port picking reduces the probability of
+     races with other processes on kernels that want to reuse the same
+     port numbers over and over. */
+
+  /* In alternating iterations we try UDP ports before TCP ports UDP
+     ports -- it could be the case that this machine has been using up
+     UDP ports and they are scarcer. */
+
+  /* Type of port to first pick in next iteration */
+  int is_tcp = 1;
+  int try
+    = 0;
+
+  for (;;) {
+    int port = try
+      < NUM_RANDOM_PORTS_TO_PICK ? rand() % (65536 - 30000) + 30000 : 0;
+    if (!is_port_available(&port, is_tcp)) {
+      continue;
+    }
+    GPR_ASSERT(port > 0);
+    /* Check that the port # is free for the other type of socket also */
+    if (!is_port_available(&port, !is_tcp)) {
+      /* In the next iteration try to bind to the other type first
+         because perhaps it is more rare. */
+      is_tcp = !is_tcp;
+      continue;
+    }
+
+    /* TODO(ctiller): consider caching this port in some structure, to avoid
+                      handing it out again */
+
+    return port;
+  }
+
+  /* The port iterator reached the end without finding a suitable port. */
+  return 0;
+}
+
+int grpc_pick_unused_port_or_die() {
+  int port = grpc_pick_unused_port();
+  GPR_ASSERT(port > 0);
+  return port;
+}
diff --git a/test/core/util/port.h b/test/core/util/port.h
new file mode 100644
index 0000000..d06f047
--- /dev/null
+++ b/test/core/util/port.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_TEST_UTIL_PORT_H__
+#define __GRPC_TEST_UTIL_PORT_H__
+
+/* pick a port number that is currently unused by either tcp or udp. return
+   0 on failure. */
+int grpc_pick_unused_port();
+/* pick a port number that is currently unused by either tcp or udp. abort
+   on failure. */
+int grpc_pick_unused_port_or_die();
+
+#endif  /* __GRPC_TEST_UTIL_PORT_H__ */
diff --git a/test/core/util/slice_splitter.c b/test/core/util/slice_splitter.c
new file mode 100644
index 0000000..1682ef4
--- /dev/null
+++ b/test/core/util/slice_splitter.c
@@ -0,0 +1,138 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/util/slice_splitter.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/useful.h>
+
+const char *grpc_slice_split_mode_name(grpc_slice_split_mode mode) {
+  switch (mode) {
+    case GRPC_SLICE_SPLIT_IDENTITY:
+      return "identity";
+    case GRPC_SLICE_SPLIT_MERGE_ALL:
+      return "merge_all";
+    case GRPC_SLICE_SPLIT_ONE_BYTE:
+      return "one_byte";
+  }
+  return "error";
+}
+
+void grpc_split_slices(grpc_slice_split_mode mode, gpr_slice *src_slices,
+                       size_t src_slice_count, gpr_slice **dst_slices,
+                       size_t *dst_slice_count) {
+  size_t i, j;
+  size_t length;
+
+  switch (mode) {
+    case GRPC_SLICE_SPLIT_IDENTITY:
+      *dst_slice_count = src_slice_count;
+      *dst_slices = gpr_malloc(sizeof(gpr_slice) * src_slice_count);
+      for (i = 0; i < src_slice_count; i++) {
+        (*dst_slices)[i] = src_slices[i];
+        gpr_slice_ref((*dst_slices)[i]);
+      }
+      break;
+    case GRPC_SLICE_SPLIT_MERGE_ALL:
+      *dst_slice_count = 1;
+      length = 0;
+      for (i = 0; i < src_slice_count; i++) {
+        length += GPR_SLICE_LENGTH(src_slices[i]);
+      }
+      *dst_slices = gpr_malloc(sizeof(gpr_slice));
+      **dst_slices = gpr_slice_malloc(length);
+      length = 0;
+      for (i = 0; i < src_slice_count; i++) {
+        memcpy(GPR_SLICE_START_PTR(**dst_slices) + length,
+               GPR_SLICE_START_PTR(src_slices[i]),
+               GPR_SLICE_LENGTH(src_slices[i]));
+        length += GPR_SLICE_LENGTH(src_slices[i]);
+      }
+      break;
+    case GRPC_SLICE_SPLIT_ONE_BYTE:
+      length = 0;
+      for (i = 0; i < src_slice_count; i++) {
+        length += GPR_SLICE_LENGTH(src_slices[i]);
+      }
+      *dst_slice_count = length;
+      *dst_slices = gpr_malloc(sizeof(gpr_slice) * length);
+      length = 0;
+      for (i = 0; i < src_slice_count; i++) {
+        for (j = 0; j < GPR_SLICE_LENGTH(src_slices[i]); j++) {
+          (*dst_slices)[length] = gpr_slice_sub(src_slices[i], j, j + 1);
+          length++;
+        }
+      }
+      break;
+  }
+}
+
+void grpc_split_slices_to_buffer(grpc_slice_split_mode mode,
+                                 gpr_slice *src_slices, size_t src_slice_count,
+                                 gpr_slice_buffer *dst) {
+  gpr_slice *slices;
+  size_t nslices;
+  size_t i;
+  grpc_split_slices(mode, src_slices, src_slice_count, &slices, &nslices);
+  for (i = 0; i < nslices; i++) {
+    /* add indexed to avoid re-merging split slices */
+    gpr_slice_buffer_add_indexed(dst, slices[i]);
+  }
+  gpr_free(slices);
+}
+
+void grpc_split_slice_buffer(grpc_slice_split_mode mode, gpr_slice_buffer *src,
+                             gpr_slice_buffer *dst) {
+  grpc_split_slices_to_buffer(mode, src->slices, src->count, dst);
+}
+
+gpr_slice grpc_slice_merge(gpr_slice *slices, size_t nslices) {
+  gpr_uint8 *out = NULL;
+  size_t length = 0;
+  size_t capacity = 0;
+  size_t i;
+
+  for (i = 0; i < nslices; i++) {
+    if (GPR_SLICE_LENGTH(slices[i]) + length > capacity) {
+      capacity = GPR_MAX(capacity * 2, GPR_SLICE_LENGTH(slices[i]) + length);
+      out = gpr_realloc(out, capacity);
+    }
+    memcpy(out + length, GPR_SLICE_START_PTR(slices[i]),
+           GPR_SLICE_LENGTH(slices[i]));
+    length += GPR_SLICE_LENGTH(slices[i]);
+  }
+
+  return gpr_slice_new(out, length, gpr_free);
+}
diff --git a/test/core/util/slice_splitter.h b/test/core/util/slice_splitter.h
new file mode 100644
index 0000000..bff4515
--- /dev/null
+++ b/test/core/util/slice_splitter.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_TEST_UTIL_SLICE_SPLITTER_H__
+#define __GRPC_TEST_UTIL_SLICE_SPLITTER_H__
+
+/* utility function to split/merge slices together to help create test
+   cases */
+
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
+
+typedef enum {
+  /* merge all input slices into a single slice */
+  GRPC_SLICE_SPLIT_MERGE_ALL,
+  /* leave slices as is */
+  GRPC_SLICE_SPLIT_IDENTITY,
+  /* split slices into one byte chunks */
+  GRPC_SLICE_SPLIT_ONE_BYTE
+} grpc_slice_split_mode;
+
+/* allocates *dst_slices; caller must unref all slices in dst_slices then free
+   it */
+void grpc_split_slices(grpc_slice_split_mode mode, gpr_slice *src_slices,
+                       size_t src_slice_count, gpr_slice **dst_slices,
+                       size_t *dst_slice_count);
+
+void grpc_split_slices_to_buffer(grpc_slice_split_mode mode,
+                                 gpr_slice *src_slices, size_t src_slice_count,
+                                 gpr_slice_buffer *dst);
+void grpc_split_slice_buffer(grpc_slice_split_mode mode, gpr_slice_buffer *src,
+                             gpr_slice_buffer *dst);
+
+gpr_slice grpc_slice_merge(gpr_slice *slices, size_t nslices);
+
+const char *grpc_slice_split_mode_name(grpc_slice_split_mode mode);
+
+#endif  /* __GRPC_TEST_UTIL_SLICE_SPLITTER_H__ */
diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c
new file mode 100644
index 0000000..993014a
--- /dev/null
+++ b/test/core/util/test_config.c
@@ -0,0 +1,36 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/util/test_config.h"
+
+void grpc_test_init(int argc, char **argv) {}
diff --git a/test/core/util/test_config.h b/test/core/util/test_config.h
new file mode 100644
index 0000000..8ada77b
--- /dev/null
+++ b/test/core/util/test_config.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_TEST_UTIL_TEST_CONFIG_H__
+#define __GRPC_TEST_UTIL_TEST_CONFIG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /*  __cplusplus */
+
+void grpc_test_init(int argc, char **argv);
+
+#ifdef __cplusplus
+}
+#endif /*  __cplusplus */
+
+#endif  /* __GRPC_TEST_UTIL_TEST_CONFIG_H__ */
diff --git a/test/cpp/end2end/async_test_server.cc b/test/cpp/end2end/async_test_server.cc
new file mode 100644
index 0000000..0a40dbb
--- /dev/null
+++ b/test/cpp/end2end/async_test_server.cc
@@ -0,0 +1,155 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/cpp/end2end/async_test_server.h"
+
+#include <chrono>
+
+#include <grpc/support/log.h>
+#include "src/cpp/proto/proto_utils.h"
+#include "test/cpp/util/echo.pb.h"
+#include <grpc++/async_server.h>
+#include <grpc++/async_server_context.h>
+#include <grpc++/completion_queue.h>
+#include <grpc++/status.h>
+#include <gtest/gtest.h>
+
+using grpc::cpp::test::util::EchoRequest;
+using grpc::cpp::test::util::EchoResponse;
+
+using std::chrono::duration_cast;
+using std::chrono::microseconds;
+using std::chrono::seconds;
+using std::chrono::system_clock;
+
+namespace grpc {
+namespace testing {
+
+AsyncTestServer::AsyncTestServer() : server_(&cq_), cq_drained_(false) {}
+
+AsyncTestServer::~AsyncTestServer() {}
+
+void AsyncTestServer::AddPort(const grpc::string& addr) {
+  server_.AddPort(addr);
+}
+
+void AsyncTestServer::Start() { server_.Start(); }
+
+// Return true if deadline actual is within 0.5s from expected.
+bool DeadlineMatched(const system_clock::time_point& actual,
+                     const system_clock::time_point& expected) {
+  microseconds diff_usecs = duration_cast<microseconds>(expected - actual);
+  gpr_log(GPR_INFO, "diff_usecs= %d", diff_usecs.count());
+  return diff_usecs.count() < 500000 && diff_usecs.count() > -500000;
+}
+
+void AsyncTestServer::RequestOneRpc() { server_.RequestOneRpc(); }
+
+void AsyncTestServer::MainLoop() {
+  EchoRequest request;
+  EchoResponse response;
+  void* tag = nullptr;
+
+  RequestOneRpc();
+
+  while (true) {
+    CompletionQueue::CompletionType t = cq_.Next(&tag);
+    AsyncServerContext* server_context = static_cast<AsyncServerContext*>(tag);
+    switch (t) {
+      case CompletionQueue::SERVER_RPC_NEW:
+        gpr_log(GPR_INFO, "SERVER_RPC_NEW %p", server_context);
+        if (server_context) {
+          EXPECT_EQ(server_context->method(), "/foo");
+          EXPECT_EQ(server_context->host(), "localhost");
+          // TODO(ctiller): verify deadline
+          server_context->Accept(cq_.cq());
+          // Handle only one rpc at a time.
+          RequestOneRpc();
+          server_context->StartRead(&request);
+        }
+        break;
+      case CompletionQueue::RPC_END:
+        gpr_log(GPR_INFO, "RPC_END %p", server_context);
+        delete server_context;
+        break;
+      case CompletionQueue::SERVER_READ_OK:
+        gpr_log(GPR_INFO, "SERVER_READ_OK %p", server_context);
+        response.set_message(request.message());
+        server_context->StartWrite(response, 0);
+        break;
+      case CompletionQueue::SERVER_READ_ERROR:
+        gpr_log(GPR_INFO, "SERVER_READ_ERROR %p", server_context);
+        server_context->StartWriteStatus(Status::OK);
+        break;
+      case CompletionQueue::HALFCLOSE_OK:
+        gpr_log(GPR_INFO, "HALFCLOSE_OK %p", server_context);
+        // Do nothing, just wait for RPC_END.
+        break;
+      case CompletionQueue::SERVER_WRITE_OK:
+        gpr_log(GPR_INFO, "SERVER_WRITE_OK %p", server_context);
+        server_context->StartRead(&request);
+        break;
+      case CompletionQueue::SERVER_WRITE_ERROR:
+        EXPECT_TRUE(0);
+        break;
+      case CompletionQueue::QUEUE_CLOSED: {
+        gpr_log(GPR_INFO, "QUEUE_CLOSED");
+        HandleQueueClosed();
+        return;
+      }
+      default:
+        EXPECT_TRUE(0);
+        break;
+    }
+  }
+}
+
+void AsyncTestServer::HandleQueueClosed() {
+  std::unique_lock<std::mutex> lock(cq_drained_mu_);
+  cq_drained_ = true;
+  cq_drained_cv_.notify_all();
+}
+
+void AsyncTestServer::Shutdown() {
+  // The server need to be shut down before cq_ as grpc_server flushes all
+  // pending requested calls to the completion queue at shutdown.
+  server_.Shutdown();
+  cq_.Shutdown();
+  std::unique_lock<std::mutex> lock(cq_drained_mu_);
+  while (!cq_drained_) {
+    cq_drained_cv_.wait(lock);
+  }
+}
+
+}  // namespace testing
+}  // namespace grpc
diff --git a/test/cpp/end2end/async_test_server.h b/test/cpp/end2end/async_test_server.h
new file mode 100644
index 0000000..a277061
--- /dev/null
+++ b/test/cpp/end2end/async_test_server.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_TEST_END2END_ASYNC_TEST_SERVER_H__
+#define __GRPCPP_TEST_END2END_ASYNC_TEST_SERVER_H__
+
+#include <condition_variable>
+#include <mutex>
+#include <string>
+
+#include <grpc++/async_server.h>
+#include <grpc++/completion_queue.h>
+
+namespace grpc {
+
+namespace testing {
+
+class AsyncTestServer {
+ public:
+  AsyncTestServer();
+  virtual ~AsyncTestServer();
+
+  void AddPort(const grpc::string& addr);
+  void Start();
+  void RequestOneRpc();
+  virtual void MainLoop();
+  void Shutdown();
+
+  CompletionQueue* completion_queue() { return &cq_; }
+
+ protected:
+  void HandleQueueClosed();
+
+ private:
+  CompletionQueue cq_;
+  AsyncServer server_;
+  bool cq_drained_;
+  std::mutex cq_drained_mu_;
+  std::condition_variable cq_drained_cv_;
+};
+
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // __GRPCPP_TEST_END2END_ASYNC_TEST_SERVER_H__
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
new file mode 100644
index 0000000..255e29e
--- /dev/null
+++ b/test/cpp/end2end/end2end_test.cc
@@ -0,0 +1,125 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <thread>
+#include "src/cpp/server/rpc_service_method.h"
+#include "test/cpp/util/echo.pb.h"
+#include "net/util/netutil.h"
+#include <grpc++/channel_interface.h>
+#include <grpc++/client_context.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/server.h>
+#include <grpc++/server_builder.h>
+#include <grpc++/status.h>
+#include <gtest/gtest.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/thd.h>
+
+using grpc::cpp::test::util::EchoRequest;
+using grpc::cpp::test::util::EchoResponse;
+using grpc::cpp::test::util::TestService;
+
+namespace grpc {
+
+class TestServiceImpl : public TestService::Service {
+ public:
+  Status Echo(const EchoRequest* request, EchoResponse* response) {
+    response->set_message(request->message());
+    return Status::OK;
+  }
+};
+
+class End2endTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    int port = PickUnusedPortOrDie();
+    server_address_ << "localhost:" << port;
+    // Setup server
+    ServerBuilder builder;
+    builder.AddPort(server_address_.str());
+    builder.RegisterService(service.service());
+    server_ = builder.BuildAndStart();
+  }
+
+  void TearDown() override {
+    server_->Shutdown();
+  }
+
+  std::unique_ptr<Server> server_;
+  std::ostringstream server_address_;
+  TestServiceImpl service;
+};
+
+static void SendRpc(const grpc::string& server_address, int num_rpcs) {
+  std::shared_ptr<ChannelInterface> channel =
+      CreateChannel(server_address);
+  TestService::Stub* stub = TestService::NewStub(channel);
+  EchoRequest request;
+  EchoResponse response;
+  request.set_message("Hello");
+
+  for (int i = 0; i < num_rpcs; ++i) {
+    ClientContext context;
+    Status s = stub->Echo(&context, request, &response);
+    EXPECT_EQ(response.message(), request.message());
+    EXPECT_TRUE(s.IsOk());
+  }
+
+  delete stub;
+}
+
+TEST_F(End2endTest, SimpleRpc) {
+  SendRpc(server_address_.str(), 1);
+}
+
+TEST_F(End2endTest, MultipleRpcs) {
+  vector<std::thread*> threads;
+  for (int i = 0; i < 10; ++i) {
+    threads.push_back(new std::thread(SendRpc, server_address_.str(), 10));
+  }
+  for (int i = 0; i < 10; ++i) {
+    threads[i]->join();
+    delete threads[i];
+  }
+}
+
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  grpc_init();
+  ::testing::InitGoogleTest(&argc, argv);
+  int result = RUN_ALL_TESTS();
+  grpc_shutdown();
+  return result;
+}
diff --git a/test/cpp/end2end/sync_client_async_server_test.cc b/test/cpp/end2end/sync_client_async_server_test.cc
new file mode 100644
index 0000000..f9ac6f2
--- /dev/null
+++ b/test/cpp/end2end/sync_client_async_server_test.cc
@@ -0,0 +1,237 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <chrono>
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include <grpc/grpc.h>
+#include <grpc/support/thd.h>
+#include "src/cpp/client/internal_stub.h"
+#include "src/cpp/rpc_method.h"
+#include "test/cpp/util/echo.pb.h"
+#include "net/util/netutil.h"
+#include <grpc++/channel_interface.h>
+#include <grpc++/client_context.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/status.h>
+#include <grpc++/stream.h>
+#include "test/cpp/end2end/async_test_server.h"
+#include <gtest/gtest.h>
+
+using grpc::cpp::test::util::EchoRequest;
+using grpc::cpp::test::util::EchoResponse;
+
+using std::chrono::duration_cast;
+using std::chrono::microseconds;
+using std::chrono::seconds;
+using std::chrono::system_clock;
+
+using grpc::testing::AsyncTestServer;
+
+namespace grpc {
+namespace {
+
+void ServerLoop(void* s) {
+  AsyncTestServer* server = static_cast<AsyncTestServer*>(s);
+  server->MainLoop();
+}
+
+class End2endTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    int port = PickUnusedPortOrDie();
+    // TODO(yangg) protobuf has a StringPrintf, maybe use that
+    std::ostringstream oss;
+    oss << "[::]:" << port;
+    // Setup server
+    server_.reset(new AsyncTestServer());
+    server_->AddPort(oss.str());
+    server_->Start();
+
+    RunServerThread();
+
+    // Setup client
+    oss.str("");
+    oss << "127.0.0.1:" << port;
+    std::shared_ptr<ChannelInterface> channel = CreateChannel(oss.str());
+    stub_.set_channel(channel);
+  }
+
+  void RunServerThread() {
+    gpr_thd_id id;
+    EXPECT_TRUE(gpr_thd_new(&id, ServerLoop, server_.get(), NULL));
+  }
+
+  void TearDown() override {
+    server_->Shutdown();
+  }
+
+  std::unique_ptr<AsyncTestServer> server_;
+  InternalStub stub_;
+};
+
+TEST_F(End2endTest, NoOpTest) { EXPECT_TRUE(stub_.channel() != nullptr); }
+
+TEST_F(End2endTest, SimpleRpc) {
+  EchoRequest request;
+  request.set_message("hello");
+  EchoResponse result;
+  ClientContext context;
+  RpcMethod method("/foo");
+  std::chrono::system_clock::time_point deadline =
+      std::chrono::system_clock::now() + std::chrono::seconds(10);
+  context.set_absolute_deadline(deadline);
+  Status s =
+      stub_.channel()->StartBlockingRpc(method, &context, request, &result);
+  EXPECT_EQ(result.message(), request.message());
+  EXPECT_TRUE(s.IsOk());
+}
+
+TEST_F(End2endTest, KSequentialSimpleRpcs) {
+  int k = 3;
+  for (int i = 0; i < k; i++) {
+    EchoRequest request;
+    request.set_message("hello");
+    EchoResponse result;
+    ClientContext context;
+    RpcMethod method("/foo");
+    std::chrono::system_clock::time_point deadline =
+        std::chrono::system_clock::now() + std::chrono::seconds(10);
+    context.set_absolute_deadline(deadline);
+    Status s =
+        stub_.channel()->StartBlockingRpc(method, &context, request, &result);
+    EXPECT_EQ(result.message(), request.message());
+    EXPECT_TRUE(s.IsOk());
+  }
+}
+
+TEST_F(End2endTest, OnePingpongBidiStream) {
+  EchoRequest request;
+  request.set_message("hello");
+  EchoResponse result;
+  ClientContext context;
+  RpcMethod method("/foo", RpcMethod::RpcType::BIDI_STREAMING);
+  std::chrono::system_clock::time_point deadline =
+      std::chrono::system_clock::now() + std::chrono::seconds(10);
+  context.set_absolute_deadline(deadline);
+  StreamContextInterface* stream_interface =
+      stub_.channel()->CreateStream(method, &context, nullptr, nullptr);
+  std::unique_ptr<ClientReaderWriter<EchoRequest, EchoResponse>> stream(
+      new ClientReaderWriter<EchoRequest, EchoResponse>(stream_interface));
+  EXPECT_TRUE(stream->Write(request));
+  EXPECT_TRUE(stream->Read(&result));
+  stream->WritesDone();
+  EXPECT_FALSE(stream->Read(&result));
+  Status s = stream->Wait();
+  EXPECT_EQ(result.message(), request.message());
+  EXPECT_TRUE(s.IsOk());
+}
+
+TEST_F(End2endTest, TwoPingpongBidiStream) {
+  EchoRequest request;
+  request.set_message("hello");
+  EchoResponse result;
+  ClientContext context;
+  RpcMethod method("/foo", RpcMethod::RpcType::BIDI_STREAMING);
+  std::chrono::system_clock::time_point deadline =
+      std::chrono::system_clock::now() + std::chrono::seconds(10);
+  context.set_absolute_deadline(deadline);
+  StreamContextInterface* stream_interface =
+      stub_.channel()->CreateStream(method, &context, nullptr, nullptr);
+  std::unique_ptr<ClientReaderWriter<EchoRequest, EchoResponse>> stream(
+      new ClientReaderWriter<EchoRequest, EchoResponse>(stream_interface));
+  EXPECT_TRUE(stream->Write(request));
+  EXPECT_TRUE(stream->Read(&result));
+  EXPECT_EQ(result.message(), request.message());
+  EXPECT_TRUE(stream->Write(request));
+  EXPECT_TRUE(stream->Read(&result));
+  EXPECT_EQ(result.message(), request.message());
+  stream->WritesDone();
+  EXPECT_FALSE(stream->Read(&result));
+  Status s = stream->Wait();
+  EXPECT_TRUE(s.IsOk());
+}
+
+TEST_F(End2endTest, OnePingpongClientStream) {
+  EchoRequest request;
+  request.set_message("hello");
+  EchoResponse result;
+  ClientContext context;
+  RpcMethod method("/foo", RpcMethod::RpcType::CLIENT_STREAMING);
+  std::chrono::system_clock::time_point deadline =
+      std::chrono::system_clock::now() + std::chrono::seconds(10);
+  context.set_absolute_deadline(deadline);
+  StreamContextInterface* stream_interface =
+      stub_.channel()->CreateStream(method, &context, nullptr, &result);
+  std::unique_ptr<ClientWriter<EchoRequest>> stream(
+      new ClientWriter<EchoRequest>(stream_interface));
+  EXPECT_TRUE(stream->Write(request));
+  stream->WritesDone();
+  Status s = stream->Wait();
+  EXPECT_EQ(result.message(), request.message());
+  EXPECT_TRUE(s.IsOk());
+}
+
+TEST_F(End2endTest, OnePingpongServerStream) {
+  EchoRequest request;
+  request.set_message("hello");
+  EchoResponse result;
+  ClientContext context;
+  RpcMethod method("/foo", RpcMethod::RpcType::SERVER_STREAMING);
+  std::chrono::system_clock::time_point deadline =
+      std::chrono::system_clock::now() + std::chrono::seconds(10);
+  context.set_absolute_deadline(deadline);
+  StreamContextInterface* stream_interface =
+      stub_.channel()->CreateStream(method, &context, &request, nullptr);
+  std::unique_ptr<ClientReader<EchoResponse>> stream(
+      new ClientReader<EchoResponse>(stream_interface));
+  EXPECT_TRUE(stream->Read(&result));
+  EXPECT_FALSE(stream->Read(nullptr));
+  Status s = stream->Wait();
+  EXPECT_EQ(result.message(), request.message());
+  EXPECT_TRUE(s.IsOk());
+}
+
+}  // namespace
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  grpc_init();
+  ::testing::InitGoogleTest(&argc, argv);
+  int result = RUN_ALL_TESTS();
+  grpc_shutdown();
+  return result;
+}
diff --git a/test/cpp/server/thread_pool_test.cc b/test/cpp/server/thread_pool_test.cc
new file mode 100644
index 0000000..cae1a10
--- /dev/null
+++ b/test/cpp/server/thread_pool_test.cc
@@ -0,0 +1,77 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+
+#include "src/cpp/server/thread_pool.h"
+#include <gtest/gtest.h>
+
+namespace grpc {
+
+class ThreadPoolTest : public ::testing::Test {
+ public:
+  ThreadPoolTest() : thread_pool_(4) {}
+
+ protected:
+  ThreadPool thread_pool_;
+};
+
+void Callback(std::mutex* mu, std::condition_variable* cv, bool* done) {
+  std::unique_lock<std::mutex> lock(*mu);
+  *done = true;
+  cv->notify_all();
+}
+
+TEST_F(ThreadPoolTest, ScheduleCallback) {
+  std::mutex mu;
+  std::condition_variable cv;
+  bool done = false;
+  std::function<void()> callback = std::bind(Callback, &mu, &cv, &done);
+  thread_pool_.ScheduleCallback(callback);
+
+  // Wait for the callback to finish.
+  std::unique_lock<std::mutex> lock(mu);
+  while (!done) {
+    cv.wait(lock);
+  }
+}
+
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  int result = RUN_ALL_TESTS();
+  return result;
+}
diff --git a/test/cpp/util/echo.proto b/test/cpp/util/echo.proto
new file mode 100644
index 0000000..37ae6b9
--- /dev/null
+++ b/test/cpp/util/echo.proto
@@ -0,0 +1,15 @@
+syntax = "proto2";
+
+package grpc.cpp.test.util;
+
+message EchoRequest {
+  optional string message = 1;
+}
+
+message EchoResponse {
+  optional string message = 1;
+}
+
+service TestService {
+  rpc Echo(EchoRequest) returns (EchoResponse) {}
+}
diff --git a/test/cpp/util/status_test.cc b/test/cpp/util/status_test.cc
new file mode 100644
index 0000000..1f37167
--- /dev/null
+++ b/test/cpp/util/status_test.cc
@@ -0,0 +1,77 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <grpc++/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/test_ssl_channel.cc b/test/cpp/util/test_ssl_channel.cc
new file mode 100644
index 0000000..bf4a2d6
--- /dev/null
+++ b/test/cpp/util/test_ssl_channel.cc
@@ -0,0 +1,59 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/cpp/util/test_ssl_channel.h"
+
+#include <grpc/support/log.h>
+extern "C" {
+#include "src/core/channel/channel_args.h"
+#include <grpc/grpc_security.h>
+}
+
+#include "test/core/end2end/data/ssl_test_data.h"
+
+namespace grpc {
+
+TestSslChannel::TestSslChannel(const grpc::string& target) {
+  grpc_credentials* ssl_creds = grpc_ssl_credentials_create(
+      test_ca_cert, test_ca_cert_size, NULL, 0, NULL, 0);
+  grpc_arg ssl_name_override = {
+      GRPC_ARG_STRING,
+      const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
+      {const_cast<char*>("foo.test.google.com")}};
+  grpc_channel_args client_args = {1, &ssl_name_override};
+  set_c_channel(
+      grpc_secure_channel_create(ssl_creds, target.c_str(), &client_args));
+  grpc_credentials_release(ssl_creds);
+}
+
+}  // namespace grpc
diff --git a/test/cpp/util/test_ssl_channel.h b/test/cpp/util/test_ssl_channel.h
new file mode 100644
index 0000000..28905dc
--- /dev/null
+++ b/test/cpp/util/test_ssl_channel.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPCPP_TEST_UTIL_TEST_SSL_CHANNEL_H__
+#define __GRPCPP_TEST_UTIL_TEST_SSL_CHANNEL_H__
+
+#include <string>
+
+#include "src/cpp/client/channel.h"
+
+struct grpc_channel;
+
+namespace grpc {
+class StreamContextInterface;
+
+// The channel is used to test against test gfe or interop binaries with ssl
+// support.
+class TestSslChannel : public Channel {
+ public:
+  explicit TestSslChannel(const grpc::string& target);
+};
+
+}  // namespace grpc
+
+#endif  // __GRPCPP_TEST_UTIL_TEST_SSL_CHANNEL_H__
diff --git a/test/cpp/util/time_test.cc b/test/cpp/util/time_test.cc
new file mode 100644
index 0000000..4c633f3
--- /dev/null
+++ b/test/cpp/util/time_test.cc
@@ -0,0 +1,68 @@
+/*
+ *
+ * Copyright 2014, Google 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 Google 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include "src/cpp/util/time.h"
+
+#include <chrono>
+
+#include <grpc/support/time.h>
+#include <gtest/gtest.h>
+
+using std::chrono::duration_cast;
+using std::chrono::microseconds;
+using std::chrono::system_clock;
+
+namespace grpc {
+namespace {
+
+class TimeTest : public ::testing::Test {};
+
+TEST_F(TimeTest, AbsolutePointTest) {
+  long us = 10000000L;
+  gpr_timespec ts = gpr_time_from_micros(us);
+  system_clock::time_point tp{microseconds(us)};
+  system_clock::time_point tp_converted =
+      AbsoluteDeadlineTimespec2Timepoint(ts);
+  gpr_timespec ts_converted;
+  AbsoluteDeadlineTimepoint2Timespec(tp_converted, &ts_converted);
+  EXPECT_TRUE(ts.tv_sec == ts_converted.tv_sec);
+  EXPECT_TRUE(ts.tv_nsec == ts_converted.tv_nsec);
+  system_clock::time_point tp_converted_2 =
+      AbsoluteDeadlineTimespec2Timepoint(ts_converted);
+  EXPECT_TRUE(tp == tp_converted);
+  EXPECT_TRUE(tp == tp_converted_2);
+}
+
+}  // namespace
+}  // namespace grpc
diff --git a/third_party/cJSON/LICENSE b/third_party/cJSON/LICENSE
new file mode 100644
index 0000000..fa0a438
--- /dev/null
+++ b/third_party/cJSON/LICENSE
@@ -0,0 +1,20 @@
+  Copyright (c) 2009 Dave Gamble
+ 
+  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.
+
diff --git a/third_party/cJSON/README b/third_party/cJSON/README
new file mode 100644
index 0000000..7531c04
--- /dev/null
+++ b/third_party/cJSON/README
@@ -0,0 +1,247 @@
+/*
+  Copyright (c) 2009 Dave Gamble
+
+  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.
+*/
+
+Welcome to cJSON.
+
+cJSON aims to be the dumbest possible parser that you can get your job done with.
+It's a single file of C, and a single header file.
+
+JSON is described best here: http://www.json.org/
+It's like XML, but fat-free. You use it to move data around, store things, or just
+generally represent your program's state.
+
+
+First up, how do I build?
+Add cJSON.c to your project, and put cJSON.h somewhere in the header search path.
+For example, to build the test app:
+
+gcc cJSON.c test.c -o test -lm
+./test
+
+
+As a library, cJSON exists to take away as much legwork as it can, but not get in your way.
+As a point of pragmatism (i.e. ignoring the truth), I'm going to say that you can use it
+in one of two modes: Auto and Manual. Let's have a quick run-through.
+
+
+I lifted some JSON from this page: http://www.json.org/fatfree.html
+That page inspired me to write cJSON, which is a parser that tries to share the same
+philosophy as JSON itself. Simple, dumb, out of the way.
+
+Some JSON:
+{
+    "name": "Jack (\"Bee\") Nimble", 
+    "format": {
+        "type":       "rect", 
+        "width":      1920, 
+        "height":     1080, 
+        "interlace":  false, 
+        "frame rate": 24
+    }
+}
+
+Assume that you got this from a file, a webserver, or magic JSON elves, whatever,
+you have a char * to it. Everything is a cJSON struct.
+Get it parsed:
+	cJSON *root = cJSON_Parse(my_json_string);
+
+This is an object. We're in C. We don't have objects. But we do have structs.
+What's the framerate?
+
+	cJSON *format = cJSON_GetObjectItem(root,"format");
+	int framerate = cJSON_GetObjectItem(format,"frame rate")->valueint;
+
+
+Want to change the framerate?
+	cJSON_GetObjectItem(format,"frame rate")->valueint=25;
+	
+Back to disk?
+	char *rendered=cJSON_Print(root);
+
+Finished? Delete the root (this takes care of everything else).
+	cJSON_Delete(root);
+
+That's AUTO mode. If you're going to use Auto mode, you really ought to check pointers
+before you dereference them. If you want to see how you'd build this struct in code?
+	cJSON *root,*fmt;
+	root=cJSON_CreateObject();	
+	cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
+	cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject());
+	cJSON_AddStringToObject(fmt,"type",		"rect");
+	cJSON_AddNumberToObject(fmt,"width",		1920);
+	cJSON_AddNumberToObject(fmt,"height",		1080);
+	cJSON_AddFalseToObject (fmt,"interlace");
+	cJSON_AddNumberToObject(fmt,"frame rate",	24);
+
+Hopefully we can agree that's not a lot of code? There's no overhead, no unnecessary setup.
+Look at test.c for a bunch of nice examples, mostly all ripped off the json.org site, and
+a few from elsewhere.
+
+What about manual mode? First up you need some detail.
+Let's cover how the cJSON objects represent the JSON data.
+cJSON doesn't distinguish arrays from objects in handling; just type.
+Each cJSON has, potentially, a child, siblings, value, a name.
+
+The root object has: Object Type and a Child
+The Child has name "name", with value "Jack ("Bee") Nimble", and a sibling:
+Sibling has type Object, name "format", and a child.
+That child has type String, name "type", value "rect", and a sibling:
+Sibling has type Number, name "width", value 1920, and a sibling:
+Sibling has type Number, name "height", value 1080, and a sibling:
+Sibling hs type False, name "interlace", and a sibling:
+Sibling has type Number, name "frame rate", value 24
+
+Here's the structure:
+typedef struct cJSON {
+	struct cJSON *next,*prev;
+	struct cJSON *child;
+
+	int type;
+
+	char *valuestring;
+	int valueint;
+	double valuedouble;
+
+	char *string;
+} cJSON;
+
+By default all values are 0 unless set by virtue of being meaningful.
+
+next/prev is a doubly linked list of siblings. next takes you to your sibling,
+prev takes you back from your sibling to you.
+Only objects and arrays have a "child", and it's the head of the doubly linked list.
+A "child" entry will have prev==0, but next potentially points on. The last sibling has next=0.
+The type expresses Null/True/False/Number/String/Array/Object, all of which are #defined in
+cJSON.h
+
+A Number has valueint and valuedouble. If you're expecting an int, read valueint, if not read
+valuedouble.
+
+Any entry which is in the linked list which is the child of an object will have a "string"
+which is the "name" of the entry. When I said "name" in the above example, that's "string".
+"string" is the JSON name for the 'variable name' if you will.
+
+Now you can trivially walk the lists, recursively, and parse as you please.
+You can invoke cJSON_Parse to get cJSON to parse for you, and then you can take
+the root object, and traverse the structure (which is, formally, an N-tree),
+and tokenise as you please. If you wanted to build a callback style parser, this is how
+you'd do it (just an example, since these things are very specific):
+
+void parse_and_callback(cJSON *item,const char *prefix)
+{
+	while (item)
+	{
+		char *newprefix=malloc(strlen(prefix)+strlen(item->name)+2);
+		sprintf(newprefix,"%s/%s",prefix,item->name);
+		int dorecurse=callback(newprefix, item->type, item);
+		if (item->child && dorecurse) parse_and_callback(item->child,newprefix);
+		item=item->next;
+		free(newprefix);
+	}
+}
+
+The prefix process will build you a separated list, to simplify your callback handling.
+The 'dorecurse' flag would let the callback decide to handle sub-arrays on it's own, or
+let you invoke it per-item. For the item above, your callback might look like this:
+
+int callback(const char *name,int type,cJSON *item)
+{
+	if (!strcmp(name,"name"))	{ /* populate name */ }
+	else if (!strcmp(name,"format/type")	{ /* handle "rect" */ }
+	else if (!strcmp(name,"format/width")	{ /* 800 */ }
+	else if (!strcmp(name,"format/height")	{ /* 600 */ }
+	else if (!strcmp(name,"format/interlace")	{ /* false */ }
+	else if (!strcmp(name,"format/frame rate")	{ /* 24 */ }
+	return 1;
+}
+
+Alternatively, you might like to parse iteratively.
+You'd use:
+
+void parse_object(cJSON *item)
+{
+	int i; for (i=0;i<cJSON_GetArraySize(item);i++)
+	{
+		cJSON *subitem=cJSON_GetArrayItem(item,i);
+		// handle subitem.	
+	}
+}
+
+Or, for PROPER manual mode:
+
+void parse_object(cJSON *item)
+{
+	cJSON *subitem=item->child;
+	while (subitem)
+	{
+		// handle subitem
+		if (subitem->child) parse_object(subitem->child);
+		
+		subitem=subitem->next;
+	}
+}
+
+Of course, this should look familiar, since this is just a stripped-down version
+of the callback-parser.
+
+This should cover most uses you'll find for parsing. The rest should be possible
+to infer.. and if in doubt, read the source! There's not a lot of it! ;)
+
+
+In terms of constructing JSON data, the example code above is the right way to do it.
+You can, of course, hand your sub-objects to other functions to populate.
+Also, if you find a use for it, you can manually build the objects.
+For instance, suppose you wanted to build an array of objects?
+
+cJSON *objects[24];
+
+cJSON *Create_array_of_anything(cJSON **items,int num)
+{
+	int i;cJSON *prev, *root=cJSON_CreateArray();
+	for (i=0;i<24;i++)
+	{
+		if (!i)	root->child=objects[i];
+		else	prev->next=objects[i], objects[i]->prev=prev;
+		prev=objects[i];
+	}
+	return root;
+}
+	
+and simply: Create_array_of_anything(objects,24);
+
+cJSON doesn't make any assumptions about what order you create things in.
+You can attach the objects, as above, and later add children to each
+of those objects.
+
+As soon as you call cJSON_Print, it renders the structure to text.
+
+
+
+The test.c code shows how to handle a bunch of typical cases. If you uncomment
+the code, it'll load, parse and print a bunch of test files, also from json.org,
+which are more complex than I'd care to try and stash into a const char array[].
+
+
+Enjoy cJSON!
+
+
+- Dave Gamble, Aug 2009
diff --git a/third_party/cJSON/cJSON.c b/third_party/cJSON/cJSON.c
new file mode 100644
index 0000000..fe446d6
--- /dev/null
+++ b/third_party/cJSON/cJSON.c
@@ -0,0 +1,596 @@
+/*
+  Copyright (c) 2009 Dave Gamble
+
+  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.
+*/
+
+/* cJSON */
+/* JSON parser in C. */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <float.h>
+#include <limits.h>
+#include <ctype.h>
+#include "cJSON.h"
+
+static const char *ep;
+
+const char *cJSON_GetErrorPtr(void) {return ep;}
+
+static int cJSON_strcasecmp(const char *s1,const char *s2)
+{
+	if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
+	for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)	if(*s1 == 0)	return 0;
+	return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
+}
+
+static void *(*cJSON_malloc)(size_t sz) = malloc;
+static void (*cJSON_free)(void *ptr) = free;
+
+static char* cJSON_strdup(const char* str)
+{
+      size_t len;
+      char* copy;
+
+      len = strlen(str) + 1;
+      if (!(copy = (char*)cJSON_malloc(len))) return 0;
+      memcpy(copy,str,len);
+      return copy;
+}
+
+void cJSON_InitHooks(cJSON_Hooks* hooks)
+{
+    if (!hooks) { /* Reset hooks */
+        cJSON_malloc = malloc;
+        cJSON_free = free;
+        return;
+    }
+
+	cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
+	cJSON_free	 = (hooks->free_fn)?hooks->free_fn:free;
+}
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item(void)
+{
+	cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
+	if (node) memset(node,0,sizeof(cJSON));
+	return node;
+}
+
+/* Delete a cJSON structure. */
+void cJSON_Delete(cJSON *c)
+{
+	cJSON *next;
+	while (c)
+	{
+		next=c->next;
+		if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
+		if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
+		if (c->string) cJSON_free(c->string);
+		cJSON_free(c);
+		c=next;
+	}
+}
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static const char *parse_number(cJSON *item,const char *num)
+{
+	double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
+
+	if (*num=='-') sign=-1,num++;	/* Has sign? */
+	if (*num=='0') num++;			/* is zero */
+	if (*num>='1' && *num<='9')	do	n=(n*10.0)+(*num++ -'0');	while (*num>='0' && *num<='9');	/* Number? */
+	if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;		do	n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}	/* Fractional part? */
+	if (*num=='e' || *num=='E')		/* Exponent? */
+	{	num++;if (*num=='+') num++;	else if (*num=='-') signsubscale=-1,num++;		/* With sign? */
+		while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');	/* Number? */
+	}
+
+	n=sign*n*pow(10.0,(scale+subscale*signsubscale));	/* number = +/- number.fraction * 10^+/- exponent */
+	
+	item->valuedouble=n;
+	item->valueint=(int)n;
+	item->type=cJSON_Number;
+	return num;
+}
+
+/* Render the number nicely from the given item into a string. */
+static char *print_number(cJSON *item)
+{
+	char *str;
+	double d=item->valuedouble;
+	if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
+	{
+		str=(char*)cJSON_malloc(21);	/* 2^64+1 can be represented in 21 chars. */
+		if (str) sprintf(str,"%d",item->valueint);
+	}
+	else
+	{
+		str=(char*)cJSON_malloc(64);	/* This is a nice tradeoff. */
+		if (str)
+		{
+			if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
+			else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)			sprintf(str,"%e",d);
+			else												sprintf(str,"%f",d);
+		}
+	}
+	return str;
+}
+
+static unsigned parse_hex4(const char *str)
+{
+	unsigned h=0;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	h=h<<4;str++;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	h=h<<4;str++;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	h=h<<4;str++;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	return h;
+}
+
+/* Parse the input text into an unescaped cstring, and populate item. */
+static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+static const char *parse_string(cJSON *item,const char *str)
+{
+	const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
+	if (*str!='\"') {ep=str;return 0;}	/* not a string! */
+	
+	while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++;	/* Skip escaped quotes. */
+	
+	out=(char*)cJSON_malloc(len+1);	/* This is how long we need for the string, roughly. */
+	if (!out) return 0;
+	
+	ptr=str+1;ptr2=out;
+	while (*ptr!='\"' && *ptr)
+	{
+		if (*ptr!='\\') *ptr2++=*ptr++;
+		else
+		{
+			ptr++;
+			switch (*ptr)
+			{
+				case 'b': *ptr2++='\b';	break;
+				case 'f': *ptr2++='\f';	break;
+				case 'n': *ptr2++='\n';	break;
+				case 'r': *ptr2++='\r';	break;
+				case 't': *ptr2++='\t';	break;
+				case 'u':	 /* transcode utf16 to utf8. */
+					uc=parse_hex4(ptr+1);ptr+=4;	/* get the unicode char. */
+
+					if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)	break;	/* check for invalid.	*/
+
+					if (uc>=0xD800 && uc<=0xDBFF)	/* UTF16 surrogate pairs.	*/
+					{
+						if (ptr[1]!='\\' || ptr[2]!='u')	break;	/* missing second-half of surrogate.	*/
+						uc2=parse_hex4(ptr+3);ptr+=6;
+						if (uc2<0xDC00 || uc2>0xDFFF)		break;	/* invalid second-half of surrogate.	*/
+						uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
+					}
+
+					len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
+					
+					switch (len) {
+						case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+						case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+						case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+						case 1: *--ptr2 =(uc | firstByteMark[len]);
+					}
+					ptr2+=len;
+					break;
+				default:  *ptr2++=*ptr; break;
+			}
+			ptr++;
+		}
+	}
+	*ptr2=0;
+	if (*ptr=='\"') ptr++;
+	item->valuestring=out;
+	item->type=cJSON_String;
+	return ptr;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static char *print_string_ptr(const char *str)
+{
+	const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
+	
+	if (!str) return cJSON_strdup("");
+	ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
+	
+	out=(char*)cJSON_malloc(len+3);
+	if (!out) return 0;
+
+	ptr2=out;ptr=str;
+	*ptr2++='\"';
+	while (*ptr)
+	{
+		if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
+		else
+		{
+			*ptr2++='\\';
+			switch (token=*ptr++)
+			{
+				case '\\':	*ptr2++='\\';	break;
+				case '\"':	*ptr2++='\"';	break;
+				case '\b':	*ptr2++='b';	break;
+				case '\f':	*ptr2++='f';	break;
+				case '\n':	*ptr2++='n';	break;
+				case '\r':	*ptr2++='r';	break;
+				case '\t':	*ptr2++='t';	break;
+				default: sprintf(ptr2,"u%04x",token);ptr2+=5;	break;	/* escape and print */
+			}
+		}
+	}
+	*ptr2++='\"';*ptr2++=0;
+	return out;
+}
+/* Invote print_string_ptr (which is useful) on an item. */
+static char *print_string(cJSON *item)	{return print_string_ptr(item->valuestring);}
+
+/* Predeclare these prototypes. */
+static const char *parse_value(cJSON *item,const char *value);
+static char *print_value(cJSON *item,int depth,int fmt);
+static const char *parse_array(cJSON *item,const char *value);
+static char *print_array(cJSON *item,int depth,int fmt);
+static const char *parse_object(cJSON *item,const char *value);
+static char *print_object(cJSON *item,int depth,int fmt);
+
+/* Utility to jump whitespace and cr/lf */
+static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
+
+/* Parse an object - create a new root, and populate. */
+cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
+{
+	const char *end=0;
+	cJSON *c=cJSON_New_Item();
+	ep=0;
+	if (!c) return 0;       /* memory fail */
+
+	end=parse_value(c,skip(value));
+	if (!end)	{cJSON_Delete(c);return 0;}	/* parse failure. ep is set. */
+
+	/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+	if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
+	if (return_parse_end) *return_parse_end=end;
+	return c;
+}
+/* Default options for cJSON_Parse */
+cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
+
+/* Render a cJSON item/entity/structure to text. */
+char *cJSON_Print(cJSON *item)				{return print_value(item,0,1);}
+char *cJSON_PrintUnformatted(cJSON *item)	{return print_value(item,0,0);}
+
+/* Parser core - when encountering text, process appropriately. */
+static const char *parse_value(cJSON *item,const char *value)
+{
+	if (!value)						return 0;	/* Fail on null. */
+	if (!strncmp(value,"null",4))	{ item->type=cJSON_NULL;  return value+4; }
+	if (!strncmp(value,"false",5))	{ item->type=cJSON_False; return value+5; }
+	if (!strncmp(value,"true",4))	{ item->type=cJSON_True; item->valueint=1;	return value+4; }
+	if (*value=='\"')				{ return parse_string(item,value); }
+	if (*value=='-' || (*value>='0' && *value<='9'))	{ return parse_number(item,value); }
+	if (*value=='[')				{ return parse_array(item,value); }
+	if (*value=='{')				{ return parse_object(item,value); }
+
+	ep=value;return 0;	/* failure. */
+}
+
+/* Render a value to text. */
+static char *print_value(cJSON *item,int depth,int fmt)
+{
+	char *out=0;
+	if (!item) return 0;
+	switch ((item->type)&255)
+	{
+		case cJSON_NULL:	out=cJSON_strdup("null");	break;
+		case cJSON_False:	out=cJSON_strdup("false");break;
+		case cJSON_True:	out=cJSON_strdup("true"); break;
+		case cJSON_Number:	out=print_number(item);break;
+		case cJSON_String:	out=print_string(item);break;
+		case cJSON_Array:	out=print_array(item,depth,fmt);break;
+		case cJSON_Object:	out=print_object(item,depth,fmt);break;
+	}
+	return out;
+}
+
+/* Build an array from input text. */
+static const char *parse_array(cJSON *item,const char *value)
+{
+	cJSON *child;
+	if (*value!='[')	{ep=value;return 0;}	/* not an array! */
+
+	item->type=cJSON_Array;
+	value=skip(value+1);
+	if (*value==']') return value+1;	/* empty array. */
+
+	item->child=child=cJSON_New_Item();
+	if (!item->child) return 0;		 /* memory fail */
+	value=skip(parse_value(child,skip(value)));	/* skip any spacing, get the value. */
+	if (!value) return 0;
+
+	while (*value==',')
+	{
+		cJSON *new_item;
+		if (!(new_item=cJSON_New_Item())) return 0; 	/* memory fail */
+		child->next=new_item;new_item->prev=child;child=new_item;
+		value=skip(parse_value(child,skip(value+1)));
+		if (!value) return 0;	/* memory fail */
+	}
+
+	if (*value==']') return value+1;	/* end of array */
+	ep=value;return 0;	/* malformed. */
+}
+
+/* Render an array to text */
+static char *print_array(cJSON *item,int depth,int fmt)
+{
+	char **entries;
+	char *out=0,*ptr,*ret;int len=5;
+	cJSON *child=item->child;
+	int numentries=0,i=0,fail=0;
+	
+	/* How many entries in the array? */
+	while (child) numentries++,child=child->next;
+	/* Explicitly handle numentries==0 */
+	if (!numentries)
+	{
+		out=(char*)cJSON_malloc(3);
+		if (out) strcpy(out,"[]");
+		return out;
+	}
+	/* Allocate an array to hold the values for each */
+	entries=(char**)cJSON_malloc(numentries*sizeof(char*));
+	if (!entries) return 0;
+	memset(entries,0,numentries*sizeof(char*));
+	/* Retrieve all the results: */
+	child=item->child;
+	while (child && !fail)
+	{
+		ret=print_value(child,depth+1,fmt);
+		entries[i++]=ret;
+		if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
+		child=child->next;
+	}
+	
+	/* If we didn't fail, try to malloc the output string */
+	if (!fail) out=(char*)cJSON_malloc(len);
+	/* If that fails, we fail. */
+	if (!out) fail=1;
+
+	/* Handle failure. */
+	if (fail)
+	{
+		for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
+		cJSON_free(entries);
+		return 0;
+	}
+	
+	/* Compose the output array. */
+	*out='[';
+	ptr=out+1;*ptr=0;
+	for (i=0;i<numentries;i++)
+	{
+		strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
+		if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
+		cJSON_free(entries[i]);
+	}
+	cJSON_free(entries);
+	*ptr++=']';*ptr++=0;
+	return out;	
+}
+
+/* Build an object from the text. */
+static const char *parse_object(cJSON *item,const char *value)
+{
+	cJSON *child;
+	if (*value!='{')	{ep=value;return 0;}	/* not an object! */
+	
+	item->type=cJSON_Object;
+	value=skip(value+1);
+	if (*value=='}') return value+1;	/* empty array. */
+	
+	item->child=child=cJSON_New_Item();
+	if (!item->child) return 0;
+	value=skip(parse_string(child,skip(value)));
+	if (!value) return 0;
+	child->string=child->valuestring;child->valuestring=0;
+	if (*value!=':') {ep=value;return 0;}	/* fail! */
+	value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */
+	if (!value) return 0;
+	
+	while (*value==',')
+	{
+		cJSON *new_item;
+		if (!(new_item=cJSON_New_Item()))	return 0; /* memory fail */
+		child->next=new_item;new_item->prev=child;child=new_item;
+		value=skip(parse_string(child,skip(value+1)));
+		if (!value) return 0;
+		child->string=child->valuestring;child->valuestring=0;
+		if (*value!=':') {ep=value;return 0;}	/* fail! */
+		value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */
+		if (!value) return 0;
+	}
+	
+	if (*value=='}') return value+1;	/* end of array */
+	ep=value;return 0;	/* malformed. */
+}
+
+/* Render an object to text. */
+static char *print_object(cJSON *item,int depth,int fmt)
+{
+	char **entries=0,**names=0;
+	char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
+	cJSON *child=item->child;
+	int numentries=0,fail=0;
+	/* Count the number of entries. */
+	while (child) numentries++,child=child->next;
+	/* Explicitly handle empty object case */
+	if (!numentries)
+	{
+		out=(char*)cJSON_malloc(fmt?depth+4:3);
+		if (!out)	return 0;
+		ptr=out;*ptr++='{';
+		if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
+		*ptr++='}';*ptr++=0;
+		return out;
+	}
+	/* Allocate space for the names and the objects */
+	entries=(char**)cJSON_malloc(numentries*sizeof(char*));
+	if (!entries) return 0;
+	names=(char**)cJSON_malloc(numentries*sizeof(char*));
+	if (!names) {cJSON_free(entries);return 0;}
+	memset(entries,0,sizeof(char*)*numentries);
+	memset(names,0,sizeof(char*)*numentries);
+
+	/* Collect all the results into our arrays: */
+	child=item->child;depth++;if (fmt) len+=depth;
+	while (child)
+	{
+		names[i]=str=print_string_ptr(child->string);
+		entries[i++]=ret=print_value(child,depth,fmt);
+		if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
+		child=child->next;
+	}
+	
+	/* Try to allocate the output string */
+	if (!fail) out=(char*)cJSON_malloc(len);
+	if (!out) fail=1;
+
+	/* Handle failure */
+	if (fail)
+	{
+		for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
+		cJSON_free(names);cJSON_free(entries);
+		return 0;
+	}
+	
+	/* Compose the output: */
+	*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
+	for (i=0;i<numentries;i++)
+	{
+		if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
+		strcpy(ptr,names[i]);ptr+=strlen(names[i]);
+		*ptr++=':';if (fmt) *ptr++='\t';
+		strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
+		if (i!=numentries-1) *ptr++=',';
+		if (fmt) *ptr++='\n';*ptr=0;
+		cJSON_free(names[i]);cJSON_free(entries[i]);
+	}
+	
+	cJSON_free(names);cJSON_free(entries);
+	if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
+	*ptr++='}';*ptr++=0;
+	return out;	
+}
+
+/* Get Array size/item / object item. */
+int    cJSON_GetArraySize(cJSON *array)							{cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
+cJSON *cJSON_GetArrayItem(cJSON *array,int item)				{cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;}
+cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)	{cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
+/* Utility for handling references. */
+static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
+
+/* Add item to array/object. */
+void   cJSON_AddItemToArray(cJSON *array, cJSON *item)						{cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
+void   cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)	{if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
+void	cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)						{cJSON_AddItemToArray(array,create_reference(item));}
+void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)	{cJSON_AddItemToObject(object,string,create_reference(item));}
+
+cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)			{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
+	if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
+void   cJSON_DeleteItemFromArray(cJSON *array,int which)			{cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
+cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
+void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
+
+/* Replace array/object items with new ones. */
+void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)		{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
+	newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
+	if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
+void   cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
+
+/* Create basic types: */
+cJSON *cJSON_CreateNull(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
+cJSON *cJSON_CreateTrue(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
+cJSON *cJSON_CreateFalse(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
+cJSON *cJSON_CreateBool(int b)					{cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
+cJSON *cJSON_CreateNumber(double num)			{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
+cJSON *cJSON_CreateString(const char *string)	{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
+cJSON *cJSON_CreateArray(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
+cJSON *cJSON_CreateObject(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
+
+/* Create Arrays: */
+cJSON *cJSON_CreateIntArray(const int *numbers,int count)		{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateFloatArray(const float *numbers,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateDoubleArray(const double *numbers,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateStringArray(const char **strings,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+
+/* Duplication */
+cJSON *cJSON_Duplicate(cJSON *item,int recurse)
+{
+	cJSON *newitem,*cptr,*nptr=0,*newchild;
+	/* Bail on bad ptr */
+	if (!item) return 0;
+	/* Create new item */
+	newitem=cJSON_New_Item();
+	if (!newitem) return 0;
+	/* Copy over all vars */
+	newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
+	if (item->valuestring)	{newitem->valuestring=cJSON_strdup(item->valuestring);	if (!newitem->valuestring)	{cJSON_Delete(newitem);return 0;}}
+	if (item->string)		{newitem->string=cJSON_strdup(item->string);			if (!newitem->string)		{cJSON_Delete(newitem);return 0;}}
+	/* If non-recursive, then we're done! */
+	if (!recurse) return newitem;
+	/* Walk the ->next chain for the child. */
+	cptr=item->child;
+	while (cptr)
+	{
+		newchild=cJSON_Duplicate(cptr,1);		/* Duplicate (with recurse) each item in the ->next chain */
+		if (!newchild) {cJSON_Delete(newitem);return 0;}
+		if (nptr)	{nptr->next=newchild,newchild->prev=nptr;nptr=newchild;}	/* If newitem->child already set, then crosswire ->prev and ->next and move on */
+		else		{newitem->child=newchild;nptr=newchild;}					/* Set newitem->child and move to it */
+		cptr=cptr->next;
+	}
+	return newitem;
+}
+
+void cJSON_Minify(char *json)
+{
+	char *into=json;
+	while (*json)
+	{
+		if (*json==' ') json++;
+		else if (*json=='\t') json++;	/* Whitespace characters. */
+		else if (*json=='\r') json++;
+		else if (*json=='\n') json++;
+		else if (*json=='/' && json[1]=='/')  while (*json && *json!='\n') json++;	/* double-slash comments, to end of line. */
+		else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;}	/* multiline comments. */
+		else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */
+		else *into++=*json++;			/* All other characters. */
+	}
+	*into=0;	/* and null-terminate. */
+}
diff --git a/third_party/cJSON/cJSON.h b/third_party/cJSON/cJSON.h
new file mode 100644
index 0000000..9bfc54f
--- /dev/null
+++ b/third_party/cJSON/cJSON.h
@@ -0,0 +1,143 @@
+/*
+  Copyright (c) 2009 Dave Gamble
+
+  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.
+*/
+
+#ifndef cJSON__h
+#define cJSON__h
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* cJSON Types: */
+#define cJSON_False 0
+#define cJSON_True 1
+#define cJSON_NULL 2
+#define cJSON_Number 3
+#define cJSON_String 4
+#define cJSON_Array 5
+#define cJSON_Object 6
+
+#define cJSON_IsReference 256
+
+/* The cJSON structure: */
+typedef struct cJSON {
+	struct cJSON *next,*prev;	/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+	struct cJSON *child;		/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+
+	int type;					/* The type of the item, as above. */
+
+	char *valuestring;			/* The item's string, if type==cJSON_String */
+	int valueint;				/* The item's number, if type==cJSON_Number */
+	double valuedouble;			/* The item's number, if type==cJSON_Number */
+
+	char *string;				/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+} cJSON;
+
+typedef struct cJSON_Hooks {
+      void *(*malloc_fn)(size_t sz);
+      void (*free_fn)(void *ptr);
+} cJSON_Hooks;
+
+/* Supply malloc, realloc and free functions to cJSON */
+extern void cJSON_InitHooks(cJSON_Hooks* hooks);
+
+
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
+extern cJSON *cJSON_Parse(const char *value);
+/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
+extern char  *cJSON_Print(cJSON *item);
+/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
+extern char  *cJSON_PrintUnformatted(cJSON *item);
+/* Delete a cJSON entity and all subentities. */
+extern void   cJSON_Delete(cJSON *c);
+
+/* Returns the number of items in an array (or object). */
+extern int	  cJSON_GetArraySize(cJSON *array);
+/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
+extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
+/* Get item "string" from object. Case insensitive. */
+extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
+
+/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
+extern const char *cJSON_GetErrorPtr(void);
+
+/* These calls create a cJSON item of the appropriate type. */
+extern cJSON *cJSON_CreateNull(void);
+extern cJSON *cJSON_CreateTrue(void);
+extern cJSON *cJSON_CreateFalse(void);
+extern cJSON *cJSON_CreateBool(int b);
+extern cJSON *cJSON_CreateNumber(double num);
+extern cJSON *cJSON_CreateString(const char *string);
+extern cJSON *cJSON_CreateArray(void);
+extern cJSON *cJSON_CreateObject(void);
+
+/* These utilities create an Array of count items. */
+extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
+extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
+extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
+extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
+
+/* Append item to the specified array/object. */
+extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
+extern void	cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
+/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
+extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+extern void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
+
+/* Remove/Detatch items from Arrays/Objects. */
+extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
+extern void   cJSON_DeleteItemFromArray(cJSON *array,int which);
+extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
+extern void   cJSON_DeleteItemFromObject(cJSON *object,const char *string);
+
+/* Update array items. */
+extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
+extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+
+/* Duplicate a cJSON item */
+extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
+/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
+need to be released. With recurse!=0, it will duplicate any children connected to the item.
+The item->next and ->prev pointers are always zero on return from Duplicate. */
+
+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
+extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
+
+extern void cJSON_Minify(char *json);
+
+/* Macros for creating things quickly. */
+#define cJSON_AddNullToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateNull())
+#define cJSON_AddTrueToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
+#define cJSON_AddFalseToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
+#define cJSON_AddBoolToObject(object,name,b)	cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
+#define cJSON_AddNumberToObject(object,name,n)	cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
+#define cJSON_AddStringToObject(object,name,s)	cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
+
+/* When assigning an integer value, it needs to be propagated to valuedouble too. */
+#define cJSON_SetIntValue(object,val)			((object)?(object)->valueint=(object)->valuedouble=(val):(val))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/cJSON/test.c b/third_party/cJSON/test.c
new file mode 100644
index 0000000..b308a92
--- /dev/null
+++ b/third_party/cJSON/test.c
@@ -0,0 +1,156 @@
+/*
+  Copyright (c) 2009 Dave Gamble
+ 
+  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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "cJSON.h"
+
+/* Parse text to JSON, then render back to text, and print! */
+void doit(char *text)
+{
+	char *out;cJSON *json;
+	
+	json=cJSON_Parse(text);
+	if (!json) {printf("Error before: [%s]\n",cJSON_GetErrorPtr());}
+	else
+	{
+		out=cJSON_Print(json);
+		cJSON_Delete(json);
+		printf("%s\n",out);
+		free(out);
+	}
+}
+
+/* Read a file, parse, render back, etc. */
+void dofile(char *filename)
+{
+	FILE *f=fopen(filename,"rb");fseek(f,0,SEEK_END);long len=ftell(f);fseek(f,0,SEEK_SET);
+	char *data=(char*)malloc(len+1);fread(data,1,len,f);fclose(f);
+	doit(data);
+	free(data);
+}
+
+/* Used by some code below as an example datatype. */
+struct record {const char *precision;double lat,lon;const char *address,*city,*state,*zip,*country; };
+
+/* Create a bunch of objects as demonstration. */
+void create_objects()
+{
+	cJSON *root,*fmt,*img,*thm,*fld;char *out;int i;	/* declare a few. */
+
+	/* Here we construct some JSON standards, from the JSON site. */
+	
+	/* Our "Video" datatype: */
+	root=cJSON_CreateObject();	
+	cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
+	cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject());
+	cJSON_AddStringToObject(fmt,"type",		"rect");
+	cJSON_AddNumberToObject(fmt,"width",		1920);
+	cJSON_AddNumberToObject(fmt,"height",		1080);
+	cJSON_AddFalseToObject (fmt,"interlace");
+	cJSON_AddNumberToObject(fmt,"frame rate",	24);
+	
+	out=cJSON_Print(root);	cJSON_Delete(root);	printf("%s\n",out);	free(out);	/* Print to text, Delete the cJSON, print it, release the string. */
+
+	/* Our "days of the week" array: */
+	const char *strings[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
+	root=cJSON_CreateStringArray(strings,7);
+
+	out=cJSON_Print(root);	cJSON_Delete(root);	printf("%s\n",out);	free(out);
+
+	/* Our matrix: */
+	int numbers[3][3]={{0,-1,0},{1,0,0},{0,0,1}};
+	root=cJSON_CreateArray();
+	for (i=0;i<3;i++) cJSON_AddItemToArray(root,cJSON_CreateIntArray(numbers[i],3));
+
+/*	cJSON_ReplaceItemInArray(root,1,cJSON_CreateString("Replacement")); */
+	
+	out=cJSON_Print(root);	cJSON_Delete(root);	printf("%s\n",out);	free(out);
+
+
+	/* Our "gallery" item: */
+	int ids[4]={116,943,234,38793};
+	root=cJSON_CreateObject();
+	cJSON_AddItemToObject(root, "Image", img=cJSON_CreateObject());
+	cJSON_AddNumberToObject(img,"Width",800);
+	cJSON_AddNumberToObject(img,"Height",600);
+	cJSON_AddStringToObject(img,"Title","View from 15th Floor");
+	cJSON_AddItemToObject(img, "Thumbnail", thm=cJSON_CreateObject());
+	cJSON_AddStringToObject(thm, "Url", "http:/*www.example.com/image/481989943");
+	cJSON_AddNumberToObject(thm,"Height",125);
+	cJSON_AddStringToObject(thm,"Width","100");
+	cJSON_AddItemToObject(img,"IDs", cJSON_CreateIntArray(ids,4));
+
+	out=cJSON_Print(root);	cJSON_Delete(root);	printf("%s\n",out);	free(out);
+
+	/* Our array of "records": */
+	struct record fields[2]={
+		{"zip",37.7668,-1.223959e+2,"","SAN FRANCISCO","CA","94107","US"},
+		{"zip",37.371991,-1.22026e+2,"","SUNNYVALE","CA","94085","US"}};
+
+	root=cJSON_CreateArray();
+	for (i=0;i<2;i++)
+	{
+		cJSON_AddItemToArray(root,fld=cJSON_CreateObject());
+		cJSON_AddStringToObject(fld, "precision", fields[i].precision);
+		cJSON_AddNumberToObject(fld, "Latitude", fields[i].lat);
+		cJSON_AddNumberToObject(fld, "Longitude", fields[i].lon);
+		cJSON_AddStringToObject(fld, "Address", fields[i].address);
+		cJSON_AddStringToObject(fld, "City", fields[i].city);
+		cJSON_AddStringToObject(fld, "State", fields[i].state);
+		cJSON_AddStringToObject(fld, "Zip", fields[i].zip);
+		cJSON_AddStringToObject(fld, "Country", fields[i].country);
+	}
+	
+/*	cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root,1),"City",cJSON_CreateIntArray(ids,4)); */
+	
+	out=cJSON_Print(root);	cJSON_Delete(root);	printf("%s\n",out);	free(out);
+
+}
+
+int main (int argc, const char * argv[]) {
+	/* a bunch of json: */
+	char text1[]="{\n\"name\": \"Jack (\\\"Bee\\\") Nimble\", \n\"format\": {\"type\":       \"rect\", \n\"width\":      1920, \n\"height\":     1080, \n\"interlace\":  false,\"frame rate\": 24\n}\n}";	
+	char text2[]="[\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]";
+	char text3[]="[\n    [0, -1, 0],\n    [1, 0, 0],\n    [0, 0, 1]\n	]\n";
+	char text4[]="{\n		\"Image\": {\n			\"Width\":  800,\n			\"Height\": 600,\n			\"Title\":  \"View from 15th Floor\",\n			\"Thumbnail\": {\n				\"Url\":    \"http:/*www.example.com/image/481989943\",\n				\"Height\": 125,\n				\"Width\":  \"100\"\n			},\n			\"IDs\": [116, 943, 234, 38793]\n		}\n	}";
+	char text5[]="[\n	 {\n	 \"precision\": \"zip\",\n	 \"Latitude\":  37.7668,\n	 \"Longitude\": -122.3959,\n	 \"Address\":   \"\",\n	 \"City\":      \"SAN FRANCISCO\",\n	 \"State\":     \"CA\",\n	 \"Zip\":       \"94107\",\n	 \"Country\":   \"US\"\n	 },\n	 {\n	 \"precision\": \"zip\",\n	 \"Latitude\":  37.371991,\n	 \"Longitude\": -122.026020,\n	 \"Address\":   \"\",\n	 \"City\":      \"SUNNYVALE\",\n	 \"State\":     \"CA\",\n	 \"Zip\":       \"94085\",\n	 \"Country\":   \"US\"\n	 }\n	 ]";
+
+	/* Process each json textblock by parsing, then rebuilding: */
+	doit(text1);
+	doit(text2);	
+	doit(text3);
+	doit(text4);
+	doit(text5);
+
+	/* Parse standard testfiles: */
+/*	dofile("../../tests/test1"); */
+/*	dofile("../../tests/test2"); */
+/*	dofile("../../tests/test3"); */
+/*	dofile("../../tests/test4"); */
+/*	dofile("../../tests/test5"); */
+
+	/* Now some samplecode for building objects concisely: */
+	create_objects();
+	
+	return 0;
+}
diff --git a/third_party/cJSON/tests/test1 b/third_party/cJSON/tests/test1
new file mode 100644
index 0000000..eacfbf5
--- /dev/null
+++ b/third_party/cJSON/tests/test1
@@ -0,0 +1,22 @@
+{
+    "glossary": {
+        "title": "example glossary",
+		"GlossDiv": {
+            "title": "S",
+			"GlossList": {
+                "GlossEntry": {
+                    "ID": "SGML",
+					"SortAs": "SGML",
+					"GlossTerm": "Standard Generalized Markup Language",
+					"Acronym": "SGML",
+					"Abbrev": "ISO 8879:1986",
+					"GlossDef": {
+                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
+						"GlossSeeAlso": ["GML", "XML"]
+                    },
+					"GlossSee": "markup"
+                }
+            }
+        }
+    }
+}
diff --git a/third_party/cJSON/tests/test2 b/third_party/cJSON/tests/test2
new file mode 100644
index 0000000..5600991
--- /dev/null
+++ b/third_party/cJSON/tests/test2
@@ -0,0 +1,11 @@
+{"menu": {
+  "id": "file",
+  "value": "File",
+  "popup": {
+    "menuitem": [
+      {"value": "New", "onclick": "CreateNewDoc()"},
+      {"value": "Open", "onclick": "OpenDoc()"},
+      {"value": "Close", "onclick": "CloseDoc()"}
+    ]
+  }
+}}
diff --git a/third_party/cJSON/tests/test3 b/third_party/cJSON/tests/test3
new file mode 100644
index 0000000..5662b37
--- /dev/null
+++ b/third_party/cJSON/tests/test3
@@ -0,0 +1,26 @@
+{"widget": {
+    "debug": "on",
+    "window": {
+        "title": "Sample Konfabulator Widget",
+        "name": "main_window",
+        "width": 500,
+        "height": 500
+    },
+    "image": { 
+        "src": "Images/Sun.png",
+        "name": "sun1",
+        "hOffset": 250,
+        "vOffset": 250,
+        "alignment": "center"
+    },
+    "text": {
+        "data": "Click Here",
+        "size": 36,
+        "style": "bold",
+        "name": "text1",
+        "hOffset": 250,
+        "vOffset": 100,
+        "alignment": "center",
+        "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+    }
+}}    
\ No newline at end of file
diff --git a/third_party/cJSON/tests/test4 b/third_party/cJSON/tests/test4
new file mode 100644
index 0000000..d540b57
--- /dev/null
+++ b/third_party/cJSON/tests/test4
@@ -0,0 +1,88 @@
+{"web-app": {
+  "servlet": [   
+    {
+      "servlet-name": "cofaxCDS",
+      "servlet-class": "org.cofax.cds.CDSServlet",
+      "init-param": {
+        "configGlossary:installationAt": "Philadelphia, PA",
+        "configGlossary:adminEmail": "ksm@pobox.com",
+        "configGlossary:poweredBy": "Cofax",
+        "configGlossary:poweredByIcon": "/images/cofax.gif",
+        "configGlossary:staticPath": "/content/static",
+        "templateProcessorClass": "org.cofax.WysiwygTemplate",
+        "templateLoaderClass": "org.cofax.FilesTemplateLoader",
+        "templatePath": "templates",
+        "templateOverridePath": "",
+        "defaultListTemplate": "listTemplate.htm",
+        "defaultFileTemplate": "articleTemplate.htm",
+        "useJSP": false,
+        "jspListTemplate": "listTemplate.jsp",
+        "jspFileTemplate": "articleTemplate.jsp",
+        "cachePackageTagsTrack": 200,
+        "cachePackageTagsStore": 200,
+        "cachePackageTagsRefresh": 60,
+        "cacheTemplatesTrack": 100,
+        "cacheTemplatesStore": 50,
+        "cacheTemplatesRefresh": 15,
+        "cachePagesTrack": 200,
+        "cachePagesStore": 100,
+        "cachePagesRefresh": 10,
+        "cachePagesDirtyRead": 10,
+        "searchEngineListTemplate": "forSearchEnginesList.htm",
+        "searchEngineFileTemplate": "forSearchEngines.htm",
+        "searchEngineRobotsDb": "WEB-INF/robots.db",
+        "useDataStore": true,
+        "dataStoreClass": "org.cofax.SqlDataStore",
+        "redirectionClass": "org.cofax.SqlRedirection",
+        "dataStoreName": "cofax",
+        "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
+        "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
+        "dataStoreUser": "sa",
+        "dataStorePassword": "dataStoreTestQuery",
+        "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
+        "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
+        "dataStoreInitConns": 10,
+        "dataStoreMaxConns": 100,
+        "dataStoreConnUsageLimit": 100,
+        "dataStoreLogLevel": "debug",
+        "maxUrlLength": 500}},
+    {
+      "servlet-name": "cofaxEmail",
+      "servlet-class": "org.cofax.cds.EmailServlet",
+      "init-param": {
+      "mailHost": "mail1",
+      "mailHostOverride": "mail2"}},
+    {
+      "servlet-name": "cofaxAdmin",
+      "servlet-class": "org.cofax.cds.AdminServlet"},
+ 
+    {
+      "servlet-name": "fileServlet",
+      "servlet-class": "org.cofax.cds.FileServlet"},
+    {
+      "servlet-name": "cofaxTools",
+      "servlet-class": "org.cofax.cms.CofaxToolsServlet",
+      "init-param": {
+        "templatePath": "toolstemplates/",
+        "log": 1,
+        "logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
+        "logMaxSize": "",
+        "dataLog": 1,
+        "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
+        "dataLogMaxSize": "",
+        "removePageCache": "/content/admin/remove?cache=pages&id=",
+        "removeTemplateCache": "/content/admin/remove?cache=templates&id=",
+        "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
+        "lookInContext": 1,
+        "adminGroupID": 4,
+        "betaServer": true}}],
+  "servlet-mapping": {
+    "cofaxCDS": "/",
+    "cofaxEmail": "/cofaxutil/aemail/*",
+    "cofaxAdmin": "/admin/*",
+    "fileServlet": "/static/*",
+    "cofaxTools": "/tools/*"},
+ 
+  "taglib": {
+    "taglib-uri": "cofax.tld",
+    "taglib-location": "/WEB-INF/tlds/cofax.tld"}}}
\ No newline at end of file
diff --git a/third_party/cJSON/tests/test5 b/third_party/cJSON/tests/test5
new file mode 100644
index 0000000..49980ca
--- /dev/null
+++ b/third_party/cJSON/tests/test5
@@ -0,0 +1,27 @@
+{"menu": {
+    "header": "SVG Viewer",
+    "items": [
+        {"id": "Open"},
+        {"id": "OpenNew", "label": "Open New"},
+        null,
+        {"id": "ZoomIn", "label": "Zoom In"},
+        {"id": "ZoomOut", "label": "Zoom Out"},
+        {"id": "OriginalView", "label": "Original View"},
+        null,
+        {"id": "Quality"},
+        {"id": "Pause"},
+        {"id": "Mute"},
+        null,
+        {"id": "Find", "label": "Find..."},
+        {"id": "FindAgain", "label": "Find Again"},
+        {"id": "Copy"},
+        {"id": "CopyAgain", "label": "Copy Again"},
+        {"id": "CopySVG", "label": "Copy SVG"},
+        {"id": "ViewSVG", "label": "View SVG"},
+        {"id": "ViewSource", "label": "View Source"},
+        {"id": "SaveAs", "label": "Save As"},
+        null,
+        {"id": "Help"},
+        {"id": "About", "label": "About Adobe CVG Viewer..."}
+    ]
+}}