aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/channel/call_op_string.c155
-rw-r--r--src/core/channel/census_filter.c189
-rw-r--r--src/core/channel/census_filter.h44
-rw-r--r--src/core/channel/channel_args.c112
-rw-r--r--src/core/channel/channel_args.h54
-rw-r--r--src/core/channel/channel_stack.c223
-rw-r--r--src/core/channel/channel_stack.h288
-rw-r--r--src/core/channel/client_channel.c641
-rw-r--r--src/core/channel/client_channel.h62
-rw-r--r--src/core/channel/client_setup.c239
-rw-r--r--src/core/channel/client_setup.h68
-rw-r--r--src/core/channel/connected_channel.c501
-rw-r--r--src/core/channel/connected_channel.h49
-rw-r--r--src/core/channel/http_client_filter.c143
-rw-r--r--src/core/channel/http_client_filter.h42
-rw-r--r--src/core/channel/http_filter.c139
-rw-r--r--src/core/channel/http_filter.h43
-rw-r--r--src/core/channel/http_server_filter.c150
-rw-r--r--src/core/channel/http_server_filter.h42
-rw-r--r--src/core/channel/metadata_buffer.c198
-rw-r--r--src/core/channel/metadata_buffer.h70
-rw-r--r--src/core/channel/noop_filter.c138
-rw-r--r--src/core/channel/noop_filter.h44
-rw-r--r--src/core/compression/algorithm.c49
-rw-r--r--src/core/compression/algorithm.h49
-rw-r--r--src/core/compression/message_compress.c193
-rw-r--r--src/core/compression/message_compress.h52
-rw-r--r--src/core/endpoint/endpoint.c49
-rw-r--r--src/core/endpoint/endpoint.h99
-rw-r--r--src/core/endpoint/resolve_address.c195
-rw-r--r--src/core/endpoint/resolve_address.h67
-rw-r--r--src/core/endpoint/secure_endpoint.c335
-rw-r--r--src/core/endpoint/secure_endpoint.h47
-rw-r--r--src/core/endpoint/socket_utils.c105
-rw-r--r--src/core/endpoint/socket_utils.h58
-rw-r--r--src/core/endpoint/socket_utils_linux.c52
-rw-r--r--src/core/endpoint/socket_utils_posix.c61
-rw-r--r--src/core/endpoint/tcp.c570
-rw-r--r--src/core/endpoint/tcp.h55
-rw-r--r--src/core/endpoint/tcp_client.c170
-rw-r--r--src/core/endpoint/tcp_client.h50
-rw-r--r--src/core/endpoint/tcp_server.c282
-rw-r--r--src/core/endpoint/tcp_server.h64
-rw-r--r--src/core/eventmanager/em.c664
-rw-r--r--src/core/eventmanager/em.h350
-rw-r--r--src/core/eventmanager/em_posix.c56
-rw-r--r--src/core/eventmanager/em_win32.c38
-rw-r--r--src/core/httpcli/format_request.c121
-rw-r--r--src/core/httpcli/format_request.h45
-rw-r--r--src/core/httpcli/httpcli.c259
-rw-r--r--src/core/httpcli/httpcli.h104
-rw-r--r--src/core/httpcli/httpcli_security_context.c128
-rw-r--r--src/core/httpcli/httpcli_security_context.h43
-rw-r--r--src/core/httpcli/parser.c212
-rw-r--r--src/core/httpcli/parser.h64
-rw-r--r--src/core/security/auth.c160
-rw-r--r--src/core/security/auth.h41
-rw-r--r--src/core/security/credentials.c534
-rw-r--r--src/core/security/credentials.h125
-rw-r--r--src/core/security/google_root_certs.c11277
-rw-r--r--src/core/security/google_root_certs.h40
-rw-r--r--src/core/security/secure_transport_setup.c289
-rw-r--r--src/core/security/secure_transport_setup.h53
-rw-r--r--src/core/security/security_context.c497
-rw-r--r--src/core/security/security_context.h176
-rw-r--r--src/core/security/server_secure_chttp2.c141
-rw-r--r--src/core/statistics/census_init.c37
-rw-r--r--src/core/statistics/census_interface.h76
-rw-r--r--src/core/statistics/census_rpc_stats.c57
-rw-r--r--src/core/statistics/census_rpc_stats.h89
-rw-r--r--src/core/statistics/census_tracing.c47
-rw-r--r--src/core/statistics/hash_table.c303
-rw-r--r--src/core/statistics/hash_table.h131
-rw-r--r--src/core/statistics/log.c617
-rw-r--r--src/core/statistics/log.h89
-rw-r--r--src/core/statistics/window_stats.c317
-rw-r--r--src/core/statistics/window_stats.h173
-rw-r--r--src/core/support/alloc.c67
-rw-r--r--src/core/support/cancellable.c156
-rw-r--r--src/core/support/cmdline.c292
-rw-r--r--src/core/support/cpu.h49
-rw-r--r--src/core/support/cpu_posix.c71
-rw-r--r--src/core/support/histogram.c226
-rw-r--r--src/core/support/host_port.c49
-rw-r--r--src/core/support/log.c48
-rw-r--r--src/core/support/log_android.c86
-rw-r--r--src/core/support/log_linux.c85
-rw-r--r--src/core/support/log_posix.c83
-rw-r--r--src/core/support/log_win32.c55
-rw-r--r--src/core/support/murmur_hash.c94
-rw-r--r--src/core/support/murmur_hash.h44
-rw-r--r--src/core/support/slice.c325
-rw-r--r--src/core/support/slice_buffer.c155
-rw-r--r--src/core/support/string.c124
-rw-r--r--src/core/support/string_posix.c86
-rw-r--r--src/core/support/sync.c135
-rw-r--r--src/core/support/sync_posix.c82
-rw-r--r--src/core/support/sync_win32.c120
-rw-r--r--src/core/support/thd_internal.h39
-rw-r--r--src/core/support/thd_posix.c78
-rw-r--r--src/core/support/thd_win32.c80
-rw-r--r--src/core/support/time.c243
-rw-r--r--src/core/support/time_posix.c81
-rw-r--r--src/core/support/time_win32.c52
-rw-r--r--src/core/surface/byte_buffer.c68
-rw-r--r--src/core/surface/byte_buffer_reader.c74
-rw-r--r--src/core/surface/call.c835
-rw-r--r--src/core/surface/call.h73
-rw-r--r--src/core/surface/channel.c152
-rw-r--r--src/core/surface/channel.h51
-rw-r--r--src/core/surface/channel_create.c213
-rw-r--r--src/core/surface/client.c115
-rw-r--r--src/core/surface/client.h41
-rw-r--r--src/core/surface/completion_queue.c392
-rw-r--r--src/core/surface/completion_queue.h102
-rw-r--r--src/core/surface/event_string.c119
-rw-r--r--src/core/surface/event_string.h42
-rw-r--r--src/core/surface/init.c46
-rw-r--r--src/core/surface/lame_client.c94
-rw-r--r--src/core/surface/lame_client.h42
-rw-r--r--src/core/surface/secure_channel_create.c243
-rw-r--r--src/core/surface/secure_server_create.c57
-rw-r--r--src/core/surface/server.c609
-rw-r--r--src/core/surface/server.h62
-rw-r--r--src/core/surface/server_chttp2.c123
-rw-r--r--src/core/surface/server_create.c41
-rw-r--r--src/core/surface/surface_em.c55
-rw-r--r--src/core/surface/surface_em.h47
-rw-r--r--src/core/surface/surface_trace.h54
-rw-r--r--src/core/transport/chttp2/frame.h74
-rw-r--r--src/core/transport/chttp2/frame_data.c164
-rw-r--r--src/core/transport/chttp2/frame_data.h80
-rw-r--r--src/core/transport/chttp2/frame_ping.c93
-rw-r--r--src/core/transport/chttp2/frame_ping.h53
-rw-r--r--src/core/transport/chttp2/frame_rst_stream.c56
-rw-r--r--src/core/transport/chttp2/frame_rst_stream.h41
-rw-r--r--src/core/transport/chttp2/frame_settings.c227
-rw-r--r--src/core/transport/chttp2/frame_settings.h99
-rw-r--r--src/core/transport/chttp2/frame_window_update.c99
-rw-r--r--src/core/transport/chttp2/frame_window_update.h55
-rw-r--r--src/core/transport/chttp2/gen_hpack_tables.c589
-rw-r--r--src/core/transport/chttp2/hpack_parser.c1212
-rw-r--r--src/core/transport/chttp2/hpack_parser.h108
-rw-r--r--src/core/transport/chttp2/hpack_table.c210
-rw-r--r--src/core/transport/chttp2/hpack_table.h97
-rw-r--r--src/core/transport/chttp2/hpack_tables.txt66
-rw-r--r--src/core/transport/chttp2/http2_errors.h56
-rw-r--r--src/core/transport/chttp2/status_conversion.c109
-rw-r--r--src/core/transport/chttp2/status_conversion.h50
-rw-r--r--src/core/transport/chttp2/stream_encoder.c553
-rw-r--r--src/core/transport/chttp2/stream_encoder.h86
-rw-r--r--src/core/transport/chttp2/stream_map.c154
-rw-r--r--src/core/transport/chttp2/stream_map.h81
-rw-r--r--src/core/transport/chttp2/timeout_encoding.c176
-rw-r--r--src/core/transport/chttp2/timeout_encoding.h44
-rw-r--r--src/core/transport/chttp2/varint.c65
-rw-r--r--src/core/transport/chttp2/varint.h73
-rw-r--r--src/core/transport/chttp2_transport.c1615
-rw-r--r--src/core/transport/chttp2_transport.h47
-rw-r--r--src/core/transport/metadata.c525
-rw-r--r--src/core/transport/metadata.h132
-rw-r--r--src/core/transport/stream_op.c165
-rw-r--r--src/core/transport/stream_op.h128
-rw-r--r--src/core/transport/transport.c85
-rw-r--r--src/core/transport/transport.h245
-rw-r--r--src/core/transport/transport_impl.h80
-rw-r--r--src/core/tsi/fake_transport_security.c515
-rw-r--r--src/core/tsi/fake_transport_security.h62
-rw-r--r--src/core/tsi/fake_transport_security_test.cc151
-rw-r--r--src/core/tsi/ssl_transport_security.c1294
-rw-r--r--src/core/tsi/ssl_transport_security.h159
-rw-r--r--src/core/tsi/ssl_transport_security_test.cc534
-rw-r--r--src/core/tsi/test_creds/README62
-rw-r--r--src/core/tsi/test_creds/badclient.key16
-rw-r--r--src/core/tsi/test_creds/badclient.pem17
-rw-r--r--src/core/tsi/test_creds/badserver.key16
-rw-r--r--src/core/tsi/test_creds/badserver.pem17
-rw-r--r--src/core/tsi/test_creds/ca-openssl.cnf17
-rw-r--r--src/core/tsi/test_creds/ca.key16
-rw-r--r--src/core/tsi/test_creds/ca.pem15
-rw-r--r--src/core/tsi/test_creds/client.key16
-rw-r--r--src/core/tsi/test_creds/client.pem14
-rw-r--r--src/core/tsi/test_creds/server0.key16
-rw-r--r--src/core/tsi/test_creds/server0.pem14
-rw-r--r--src/core/tsi/test_creds/server1-openssl.cnf26
-rw-r--r--src/core/tsi/test_creds/server1.key16
-rw-r--r--src/core/tsi/test_creds/server1.pem16
-rw-r--r--src/core/tsi/transport_security.c372
-rw-r--r--src/core/tsi/transport_security.h118
-rw-r--r--src/core/tsi/transport_security_interface.h389
-rw-r--r--src/core/tsi/transport_security_test_lib.cc363
-rw-r--r--src/core/tsi/transport_security_test_lib.h154
192 files changed, 42541 insertions, 0 deletions
diff --git a/src/core/channel/call_op_string.c b/src/core/channel/call_op_string.c
new file mode 100644
index 0000000000..4a98cbfbbb
--- /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 0000000000..4285b284ce
--- /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 0000000000..5b2c01ca9b
--- /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 0000000000..36312e54de
--- /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 0000000000..cf38d5d01f
--- /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 0000000000..a403db35c2
--- /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 0000000000..0ae1005e67
--- /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 0000000000..90563683d5
--- /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 0000000000..576af64ec7
--- /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 0000000000..c667e39d9c
--- /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 0000000000..862c1325a3
--- /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 0000000000..336472e740
--- /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 0000000000..660ea7ad89
--- /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 0000000000..b82c7352d3
--- /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 0000000000..f939cbd351
--- /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 0000000000..b5c154144e
--- /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 0000000000..89ad482d35
--- /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 0000000000..b176064813
--- /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 0000000000..5b475432aa
--- /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 0000000000..75fd90b707
--- /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 0000000000..818b290ce2
--- /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 0000000000..705df4a707
--- /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 0000000000..4057ff7ac9
--- /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 0000000000..0b5576f70a
--- /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 0000000000..05895a889e
--- /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 0000000000..1787ccd7d8
--- /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 0000000000..af8a0a5d75
--- /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 0000000000..07353751b0
--- /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 0000000000..14d9a56d55
--- /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 0000000000..aa21954c6d
--- /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 0000000000..cc32c47cef
--- /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 0000000000..4fab0faa03
--- /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 0000000000..971170afed
--- /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 0000000000..9c2540bcbf
--- /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 0000000000..545d678eab
--- /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 0000000000..479675ec7d
--- /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 0000000000..262d606af9
--- /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 0000000000..39367e80f6
--- /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 0000000000..6507b2f6ef
--- /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 0000000000..01a0c3f23d
--- /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 0000000000..2a8b8ee217
--- /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 0000000000..2f386ce045
--- /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 0000000000..99cb83e181
--- /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 0000000000..e02d56c0a1
--- /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 0000000000..32d37a5b98
--- /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 0000000000..af449342f0
--- /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 0000000000..4d5c3b5126
--- /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 0000000000..7a44f1266f
--- /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 0000000000..988f872563
--- /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 0000000000..6c0a688390
--- /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 0000000000..aef0edfdd4
--- /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 0000000000..c7b9b330f0
--- /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 0000000000..c267622e60
--- /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 0000000000..1f0c5167de
--- /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 0000000000..e2c24a9993
--- /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 0000000000..6480dd2239
--- /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 0000000000..0b279f8740
--- /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 0000000000..969a97369c
--- /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 0000000000..1432611ec6
--- /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 0000000000..669d637ddf
--- /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 0000000000..4bcfaddcdb
--- /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 0000000000..bc2e469af6
--- /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 0000000000..1a20fa9a80
--- /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 0000000000..beda64cba2
--- /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 0000000000..59c9bbdf34
--- /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 0000000000..bce27ec3ab
--- /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 0000000000..340214f8f5
--- /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 0000000000..7618387ee2
--- /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 0000000000..28101ac734
--- /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 0000000000..6ab7614805
--- /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 0000000000..d0c9032837
--- /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 0000000000..f0105ee683
--- /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 0000000000..5c9a3fa0b4
--- /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 0000000000..43a8653de6
--- /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 0000000000..e9c745cac0
--- /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 0000000000..be53d818a0
--- /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 0000000000..677f40031e
--- /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 0000000000..658408f334
--- /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 0000000000..5596413fba
--- /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 0000000000..ff163a1f6c
--- /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 0000000000..6ac0db35e5
--- /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 0000000000..82d58de2b4
--- /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 0000000000..a3ecd3e152
--- /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 0000000000..02500551fc
--- /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 0000000000..79321f7ffe
--- /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 0000000000..9e2b03471f
--- /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 0000000000..e39e2cc166
--- /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 0000000000..68882f7e89
--- /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 0000000000..f5710fa179
--- /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 0000000000..5d30263e52
--- /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 0000000000..5643717cd2
--- /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 0000000000..fcdeb478fb
--- /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 0000000000..2ade049c89
--- /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 0000000000..b1f0795846
--- /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 0000000000..d1da37923f
--- /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 0000000000..40e5465e5d
--- /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 0000000000..257a7fbf4e
--- /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 0000000000..63dd4eb708
--- /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 0000000000..519177a555
--- /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 0000000000..c86eea415d
--- /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 0000000000..8440479520
--- /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 0000000000..1d8765f8cc
--- /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 0000000000..e7b79d10b1
--- /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 0000000000..425809144c
--- /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 0000000000..27a6c6e33d
--- /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 0000000000..18500b83e8
--- /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 0000000000..63d408d2d5
--- /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 0000000000..2c785a59fc
--- /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 0000000000..ff994257f4
--- /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 0000000000..11d4939916
--- /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 0000000000..ec1c8477fa
--- /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 0000000000..26abffa817
--- /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 0000000000..eb567276e2
--- /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 0000000000..a7d611579f
--- /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 0000000000..0fe576588a
--- /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 0000000000..0a6a81d18e
--- /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 0000000000..30b693e95c
--- /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 0000000000..92c0ac880d
--- /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 0000000000..18921c44dd
--- /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 0000000000..74b9707202
--- /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 0000000000..f330b83521
--- /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 0000000000..bf0f62367f
--- /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 0000000000..99d66ffb2d
--- /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 0000000000..f0773ab9d5
--- /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 0000000000..24c5757166
--- /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 0000000000..dcc6ce1ccc
--- /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 0000000000..e1785d1a44
--- /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 0000000000..165f42f868
--- /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 0000000000..f6f9acfd9c
--- /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 0000000000..7c0bbe026b
--- /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 0000000000..fbd3b6cabf
--- /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 0000000000..abe26dab76
--- /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 0000000000..9556c0cae8
--- /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 0000000000..a64d53644b
--- /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 0000000000..825e156e46
--- /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 0000000000..78aea0f26a
--- /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 0000000000..488b96a728
--- /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 0000000000..74e2b4fa22
--- /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 0000000000..f61714f52b
--- /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 0000000000..4b789fcc4a
--- /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 0000000000..cc94a737ca
--- /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 0000000000..33588a73d4
--- /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 0000000000..cf68042fbd
--- /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 0000000000..8f2ebecfeb
--- /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 0000000000..a3a07ad014
--- /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 0000000000..08842a0267
--- /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 0000000000..d065422c6f
--- /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 0000000000..7bd85e8b29
--- /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 0000000000..ae9e7f2ca3
--- /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 0000000000..d46366d8b2
--- /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 0000000000..dad64697a5
--- /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 0000000000..9ac3a4750d
--- /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 0000000000..caaee30676
--- /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 0000000000..2706c369a6
--- /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 0000000000..a4582566ad
--- /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 0000000000..5d551be642
--- /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 0000000000..780390238f
--- /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 0000000000..8a6b427559
--- /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 0000000000..37eb84ed02
--- /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 0000000000..ceb77df34d
--- /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 0000000000..4b87f70e31
--- /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 0000000000..c77c8cde1f
--- /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 0000000000..be60bc2da6
--- /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 0000000000..d3291bbbb9
--- /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 0000000000..1872947208
--- /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 0000000000..6acdbf2525
--- /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 0000000000..7807e71949
--- /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 0000000000..075d51871b
--- /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 0000000000..0ae88e0c9a
--- /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 0000000000..7bd178b372
--- /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 0000000000..2ed3ed861b
--- /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 0000000000..a759403126
--- /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 0000000000..eb8482d648
--- /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 0000000000..5832685122
--- /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 0000000000..1785970221
--- /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 0000000000..abfbde10ff
--- /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 0000000000..983c979f31
--- /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 0000000000..e97b945e4b
--- /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 0000000000..03c4f950e3
--- /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 0000000000..6c8511a73c
--- /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 0000000000..f48d0735d9
--- /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 0000000000..e332091019
--- /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 0000000000..add153c9ae
--- /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 0000000000..ade75d8563
--- /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 0000000000..8a02108289
--- /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 0000000000..143a5b8765
--- /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 0000000000..8e582e571f
--- /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 0000000000..94252e36d0
--- /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 0000000000..cf9a2b0195
--- /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 0000000000..6be72c753a
--- /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 0000000000..1b630c9578
--- /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 0000000000..8c9c764c91
--- /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_