/* The MIT License (MIT) Copyright (c) 2013-2020 Winlin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include using namespace std; #include #include #include #include #include #include #include #include #include #include class MockMSegmentsReader : public ISrsReader { public: vector in_bytes; public: MockMSegmentsReader(); virtual ~MockMSegmentsReader(); public: virtual void append(string b) { in_bytes.push_back(b); } virtual srs_error_t read(void* buf, size_t size, ssize_t* nread); }; MockMSegmentsReader::MockMSegmentsReader() { } MockMSegmentsReader::~MockMSegmentsReader() { } srs_error_t MockMSegmentsReader::read(void* buf, size_t size, ssize_t* nread) { srs_error_t err = srs_success; for (;;) { if (in_bytes.empty() || size <= 0) { return srs_error_new(-1, "EOF"); } string v = in_bytes[0]; if (v.empty()) { in_bytes.erase(in_bytes.begin()); continue; } int nn = srs_min(size, v.length()); memcpy(buf, v.data(), nn); if (nread) { *nread = nn; } if (nn < (int)v.length()) { in_bytes[0] = string(v.data() + nn, v.length() - nn); } else { in_bytes.erase(in_bytes.begin()); } break; } return err; } MockResponseWriter::MockResponseWriter() { w = new SrsHttpResponseWriter(&io); w->hf = this; } MockResponseWriter::~MockResponseWriter() { srs_freep(w); } srs_error_t MockResponseWriter::final_request() { return w->final_request(); } SrsHttpHeader* MockResponseWriter::header() { return w->header(); } srs_error_t MockResponseWriter::write(char* data, int size) { return w->write(data, size); } srs_error_t MockResponseWriter::writev(const iovec* iov, int iovcnt, ssize_t* pnwrite) { return w->writev(iov, iovcnt, pnwrite); } void MockResponseWriter::write_header(int code) { w->write_header(code); } srs_error_t MockResponseWriter::filter(SrsHttpHeader* h) { h->del("Content-Type"); h->del("Server"); h->del("Connection"); h->del("Location"); h->del("Content-Range"); h->del("Access-Control-Allow-Origin"); h->del("Access-Control-Allow-Methods"); h->del("Access-Control-Expose-Headers"); h->del("Access-Control-Allow-Headers"); return srs_success; } string mock_http_response(int status, string content) { stringstream ss; ss << "HTTP/1.1 " << status << " " << srs_generate_http_status_text(status) << "\r\n" << "Content-Length: " << content.length() << "\r\n" << "\r\n" << content; return ss.str(); } string mock_http_response2(int status, string content) { stringstream ss; ss << "HTTP/1.1 " << status << " " << srs_generate_http_status_text(status) << "\r\n" << "Transfer-Encoding: chunked" << "\r\n" << "\r\n" << content; return ss.str(); } class MockFileReaderFactory : public ISrsFileReaderFactory { public: string bytes; MockFileReaderFactory(string data) { bytes = data; } virtual ~MockFileReaderFactory() { } virtual SrsFileReader* create_file_reader() { return new MockSrsFileReader((const char*)bytes.data(), (int)bytes.length()); } }; class MockHttpHandler : virtual public ISrsHttpHandler, virtual public ISrsHttpMatchHijacker { public: string bytes; MockHttpHandler(string data) { bytes = data; } virtual ~MockHttpHandler() { } virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* /*r*/) { return w->write((char*)bytes.data(), (int)bytes.length()); } virtual srs_error_t hijack(ISrsHttpMessage* /*r*/, ISrsHttpHandler** ph) { if (ph) { *ph = this; } return srs_success; } }; bool _mock_srs_path_always_exists(std::string /*path*/) { return true; } bool _mock_srs_path_not_exists(std::string /*path*/) { return false; } VOID TEST(ProtocolHTTPTest, StatusCode2Text) { EXPECT_STREQ(SRS_CONSTS_HTTP_OK_str, srs_generate_http_status_text(SRS_CONSTS_HTTP_OK).c_str()); EXPECT_STREQ("Status Unknown", srs_generate_http_status_text(999).c_str()); EXPECT_FALSE(srs_go_http_body_allowd(SRS_CONSTS_HTTP_Continue)); EXPECT_FALSE(srs_go_http_body_allowd(SRS_CONSTS_HTTP_OK-1)); EXPECT_FALSE(srs_go_http_body_allowd(SRS_CONSTS_HTTP_NoContent)); EXPECT_FALSE(srs_go_http_body_allowd(SRS_CONSTS_HTTP_NotModified)); EXPECT_TRUE(srs_go_http_body_allowd(SRS_CONSTS_HTTP_OK)); } VOID TEST(ProtocolHTTPTest, ResponseDetect) { EXPECT_STREQ("application/octet-stream", srs_go_http_detect(NULL, 0).c_str()); EXPECT_STREQ("application/octet-stream", srs_go_http_detect((char*)"Hello, world!", 0).c_str()); } VOID TEST(ProtocolHTTPTest, ResponseWriter) { srs_error_t err; // Directly final_request, should work. if (true) { MockResponseWriter w; w.header()->set_content_length(0); HELPER_ASSERT_SUCCESS(w.final_request()); } // Directly final_request, should work. if (true) { MockResponseWriter w; HELPER_ASSERT_SUCCESS(w.final_request()); } // When content-length is set, we could write multiple parts. if (true) { MockResponseWriter w; char msg[] = "Hello, world!"; w.header()->set_content_length(sizeof(msg) - 1); HELPER_EXPECT_SUCCESS(w.write((char*)msg, 5)); HELPER_EXPECT_SUCCESS(w.write((char*)(msg+5), 2)); HELPER_EXPECT_SUCCESS(w.write((char*)(msg+7), 5)); HELPER_EXPECT_SUCCESS(w.write((char*)(msg+12), 1)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } // If directly write string, response with content-length. if (true) { MockResponseWriter w; char msg[] = "Hello, world!"; HELPER_EXPECT_SUCCESS(w.write((char*)msg, sizeof(msg) - 1)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } // Response with specified length string, response with content-length. if (true) { MockResponseWriter w; char msg[] = "Hello, world!"; w.header()->set_content_type("text/plain; charset=utf-8"); w.header()->set_content_length(sizeof(msg) - 1); w.write_header(SRS_CONSTS_HTTP_OK); HELPER_EXPECT_SUCCESS(w.write((char*)msg, sizeof(msg) - 1)); HELPER_ASSERT_SUCCESS(w.final_request()); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } // If set content-length to 0 then final_request, send an empty resonse with content-length 0. if (true) { MockResponseWriter w; w.header()->set_content_length(0); w.write_header(SRS_CONSTS_HTTP_OK); HELPER_ASSERT_SUCCESS(w.final_request()); __MOCK_HTTP_EXPECT_STREQ(200, "", w); } // If set content-length to 0 then write, send an empty resonse with content-length 0. if (true) { MockResponseWriter w; w.header()->set_content_length(0); w.write_header(SRS_CONSTS_HTTP_OK); HELPER_EXPECT_SUCCESS(w.write(NULL, 0)); __MOCK_HTTP_EXPECT_STREQ(200, "", w); } // If write_header without content-length, enter chunked encoding mode. if (true) { MockResponseWriter w; w.header()->set_content_type("application/octet-stream"); w.write_header(SRS_CONSTS_HTTP_OK); HELPER_EXPECT_SUCCESS(w.write((char*)"Hello", 5)); HELPER_EXPECT_SUCCESS(w.write((char*)", world!", 8)); HELPER_ASSERT_SUCCESS(w.final_request()); __MOCK_HTTP_EXPECT_STREQ2(200, "5\r\nHello\r\n8\r\n, world!\r\n0\r\n\r\n", w); } if (true) { MockResponseWriter w; w.header()->set_content_type("application/octet-stream"); w.write_header(SRS_CONSTS_HTTP_OK); HELPER_EXPECT_SUCCESS(w.write((char*)"Hello, world!", 13)); HELPER_ASSERT_SUCCESS(w.final_request()); __MOCK_HTTP_EXPECT_STREQ2(200, "d\r\nHello, world!\r\n0\r\n\r\n", w); } if (true) { MockResponseWriter w; w.header()->set_content_type("application/octet-stream"); w.write_header(SRS_CONSTS_HTTP_OK); HELPER_EXPECT_SUCCESS(w.write((char*)"Hello, world!", 13)); HELPER_ASSERT_SUCCESS(w.final_request()); __MOCK_HTTP_EXPECT_STREQ2(200, "d\r\nHello, world!\r\n0\r\n\r\n", w); } // If directly write empty string, sent an empty response with content-length 0 if (true) { MockResponseWriter w; HELPER_EXPECT_SUCCESS(w.write(NULL, 0)); __MOCK_HTTP_EXPECT_STREQ(200, "", w); } // If directly final request, response with EOF of chunked. if (true) { MockResponseWriter w; HELPER_ASSERT_SUCCESS(w.final_request()); __MOCK_HTTP_EXPECT_STREQ2(200, "0\r\n\r\n", w); } } VOID TEST(ProtocolHTTPTest, ChunkSmallBuffer) { srs_error_t err; // No chunk end flag, error. if (true) { MockMSegmentsReader io; io.append(mock_http_response2(200, "0d\r\n")); io.append("Hello, world!\r\n"); SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); char buf[32]; ssize_t nread = 0; ISrsHttpResponseReader* r = msg->body_reader(); HELPER_ARRAY_INIT(buf, sizeof(buf), 0); HELPER_ASSERT_SUCCESS(r->read(buf, 32, &nread)); EXPECT_EQ(13, nread); EXPECT_STREQ("Hello, world!", buf); err = r->read(buf, 32, &nread); EXPECT_EQ(-1, srs_error_code(err)); srs_freep(err); srs_freep(msg); } // Read util EOF(nread=0) or err(ERROR_HTTP_RESPONSE_EOF). if (true) { MockMSegmentsReader io; io.append(mock_http_response2(200, "0d\r\n")); io.append("Hello, world!\r\n0\r\n\r\n"); SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); char buf[32]; ssize_t nread = 0; ISrsHttpResponseReader* r = msg->body_reader(); HELPER_ARRAY_INIT(buf, sizeof(buf), 0); HELPER_ASSERT_SUCCESS(r->read(buf, 32, &nread)); EXPECT_EQ(13, nread); EXPECT_STREQ("Hello, world!", buf); HELPER_ASSERT_SUCCESS(r->read(buf, 32, &nread)); EXPECT_EQ(0, nread); err = r->read(buf, 32, &nread); EXPECT_EQ(ERROR_HTTP_RESPONSE_EOF, srs_error_code(err)); srs_freep(err); srs_freep(msg); } // In this case, we only got header complete, no body start event. if (true) { MockMSegmentsReader io; io.append(mock_http_response2(200, "0d\r\n")); io.append("Hello, world!\r\n0\r\n\r\n"); SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); char buf[32]; ssize_t nread = 0; ISrsHttpResponseReader* r = msg->body_reader(); HELPER_ARRAY_INIT(buf, sizeof(buf), 0); HELPER_ASSERT_SUCCESS(r->read(buf, 32, &nread)); EXPECT_EQ(13, nread); EXPECT_STREQ("Hello, world!", buf); srs_freep(msg); } } VOID TEST(ProtocolHTTPTest, ClientSmallBuffer) { srs_error_t err; // The chunk content is sent in multiple parts. if (true) { MockMSegmentsReader io; io.append(mock_http_response2(200, "0d\r\n")); io.append("Hello,"); io.append(" world!"); io.append("\r\n0\r\n\r\n"); SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); char buf[32]; ssize_t nread = 0; ISrsHttpResponseReader* r = msg->body_reader(); HELPER_ARRAY_INIT(buf, sizeof(buf), 0); HELPER_ASSERT_SUCCESS(r->read(buf, 32, &nread)); EXPECT_EQ(6, nread); EXPECT_STREQ("Hello,", buf); HELPER_ARRAY_INIT(buf, sizeof(buf), 0); HELPER_ASSERT_SUCCESS(r->read(buf, 32, &nread)); EXPECT_EQ(7, nread); EXPECT_STREQ(" world!", buf); srs_freep(msg); } // The chunk size is sent separately before chunk content. if (true) { MockMSegmentsReader io; io.append(mock_http_response2(200, "0d\r\n")); io.append("Hello, world!\r\n0\r\n\r\n"); SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); char buf[32]; ssize_t nread = 0; ISrsHttpResponseReader* r = msg->body_reader(); HELPER_ARRAY_INIT(buf, sizeof(buf), 0); HELPER_ASSERT_SUCCESS(r->read(buf, 32, &nread)); EXPECT_EQ(13, nread); EXPECT_STREQ("Hello, world!", buf); srs_freep(msg); } // If buffer is smaller than chunk, we could read N times to get the whole chunk. if (true) { MockBufferIO io; io.append(mock_http_response2(200, "0d\r\nHello, world!\r\n0\r\n\r\n")); SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); char buf[32]; ssize_t nread = 0; ISrsHttpResponseReader* r = msg->body_reader(); HELPER_ARRAY_INIT(buf, sizeof(buf), 0); HELPER_ASSERT_SUCCESS(r->read(buf, 5, &nread)); EXPECT_EQ(5, nread); EXPECT_STREQ("Hello", buf); HELPER_ARRAY_INIT(buf, sizeof(buf), 0); HELPER_ASSERT_SUCCESS(r->read(buf, 7, &nread)); EXPECT_EQ(7, nread); EXPECT_STREQ(", world", buf); HELPER_ARRAY_INIT(buf, sizeof(buf), 0); HELPER_ASSERT_SUCCESS(r->read(buf, 7, &nread)); EXPECT_EQ(1, nread); EXPECT_STREQ("!", buf); HELPER_ASSERT_SUCCESS(r->read(buf, 7, &nread)); EXPECT_EQ(0, nread); srs_freep(msg); } } VOID TEST(ProtocolHTTPTest, ClientRequest) { srs_error_t err; // Normal case, with chunked encoding. if (true) { MockBufferIO io; io.append(mock_http_response2(200, "0d\r\nHello, world!\r\n0\r\n\r\n")); SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); string res; HELPER_ASSERT_SUCCESS(msg->body_read_all(res)); EXPECT_EQ(200, msg->status_code()); EXPECT_STREQ("Hello, world!", res.c_str()); srs_freep(msg); } if (true) { MockBufferIO io; io.append(mock_http_response2(200, "6\r\nHello!\r\n0\r\n\r\n")); SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); string res; HELPER_ASSERT_SUCCESS(msg->body_read_all(res)); EXPECT_EQ(200, msg->status_code()); EXPECT_STREQ("Hello!", res.c_str()); srs_freep(msg); } // Normal case, with specified content-length. if (true) { MockBufferIO io; io.append(mock_http_response(200, "Hello, world!")); SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); string res; HELPER_ASSERT_SUCCESS(msg->body_read_all(res)); EXPECT_EQ(200, msg->status_code()); EXPECT_STREQ("Hello, world!", res.c_str()); srs_freep(msg); } } VOID TEST(ProtocolHTTPTest, ResponseHTTPError) { srs_error_t err; if (true) { MockResponseWriter w; HELPER_EXPECT_SUCCESS(srs_go_http_error(&w, SRS_CONSTS_HTTP_Found)); __MOCK_HTTP_EXPECT_STREQ(302, "Found", w); } if (true) { MockResponseWriter w; HELPER_EXPECT_SUCCESS(srs_go_http_error(&w, SRS_CONSTS_HTTP_InternalServerError)); __MOCK_HTTP_EXPECT_STREQ(500, "Internal Server Error", w); } if (true) { MockResponseWriter w; HELPER_EXPECT_SUCCESS(srs_go_http_error(&w, SRS_CONSTS_HTTP_ServiceUnavailable)); __MOCK_HTTP_EXPECT_STREQ(503, "Service Unavailable", w); } } VOID TEST(ProtocolHTTPTest, HTTPHeader) { SrsHttpHeader h; h.set("Server", "SRS"); EXPECT_STREQ("SRS", h.get("Server").c_str()); EXPECT_EQ(1, h.count()); stringstream ss; h.write(ss); EXPECT_STREQ("Server: SRS\r\n", ss.str().c_str()); h.del("Server"); EXPECT_TRUE(h.get("Server").empty()); EXPECT_EQ(0, h.count()); EXPECT_EQ(-1, h.content_length()); h.set_content_length(0); EXPECT_EQ(0, h.content_length()); EXPECT_EQ(1, h.count()); h.set_content_length(1024); EXPECT_EQ(1024, h.content_length()); h.set_content_type("text/plain"); EXPECT_STREQ("text/plain", h.content_type().c_str()); EXPECT_EQ(2, h.count()); SrsJsonObject* o = SrsJsonAny::object(); h.dumps(o); EXPECT_EQ(2, o->count()); srs_freep(o); } VOID TEST(ProtocolHTTPTest, HTTPServerMuxerVhost) { srs_error_t err; // For vhost. if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/", h0)); MockHttpHandler* h1 = new MockHttpHandler("Done"); HELPER_ASSERT_SUCCESS(s.handle("ossrs.net/api/", h1)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); SrsHttpHeader h; h.set("Host", "ossrs.net"); r.set_header(&h, false); HELPER_ASSERT_SUCCESS(r.set_url("/api/", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Done", w); } // For vhost. if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/api/", h0)); MockHttpHandler* h1 = new MockHttpHandler("Done"); HELPER_ASSERT_SUCCESS(s.handle("ossrs.net/api/", h1)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); SrsHttpHeader h; h.set("Host", "ossrs.net"); r.set_header(&h, false); HELPER_ASSERT_SUCCESS(r.set_url("/api/", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Done", w); } } VOID TEST(ProtocolHTTPTest, HTTPServerMuxerImplicitHandler) { srs_error_t err; // Implicit handler. if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h1 = new MockHttpHandler("Done"); HELPER_ASSERT_SUCCESS(s.handle("/api", h1)); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/api/", h0)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/api", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Done", w); } // Fail if explicit handler exists. if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/api/", h0)); MockHttpHandler* h1 = new MockHttpHandler("Done"); HELPER_EXPECT_FAILED(s.handle("/api/", h1)); } // Explicit handler will overwrite the implicit handler. if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/api/", h0)); MockHttpHandler* h1 = new MockHttpHandler("Done"); HELPER_ASSERT_SUCCESS(s.handle("/api", h1)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/api", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Done", w); } // Implicit handler. if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/api/", h0)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/api", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(302, "Redirect to /api/", w); } } VOID TEST(ProtocolHTTPTest, HTTPServerMuxerHijack) { srs_error_t err; // For hijacker, notify all. if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler h1("Done"); s.hijack(&h1); MockHttpHandler h0("Hello, world!"); s.hijack(&h0); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/home/index.html", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } // For hijacker, notify all. if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler h0("Hello, world!"); s.hijack(&h0); MockHttpHandler h1("Done"); s.hijack(&h1); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/home/index.html", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Done", w); } if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler hroot("Hello, world!"); s.hijack(&hroot); s.unhijack(&hroot); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(404, "Not Found", w); } if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler hroot("Hello, world!"); s.hijack(&hroot); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } } VOID TEST(ProtocolHTTPTest, HTTPServerMuxerBasic) { srs_error_t err; // Ignore if not enabled. if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/", h0)); MockHttpHandler* h1 = new MockHttpHandler("Done"); HELPER_ASSERT_SUCCESS(s.handle("/api/", h1)); h1->entry->enabled = false; MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/api/index.html", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } // Empty pattern, failed. if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_EXPECT_FAILED(s.handle("", h0)); } // If not endswith '/', exactly match. if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/", h0)); MockHttpHandler* h1 = new MockHttpHandler("Done"); HELPER_ASSERT_SUCCESS(s.handle("/home", h1)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/home/index.html", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } // If endswith '/', match any. if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/", h0)); MockHttpHandler* h1 = new MockHttpHandler("Done"); HELPER_ASSERT_SUCCESS(s.handle("/home/", h1)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/home/index.html", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Done", w); } if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/", h0)); MockHttpHandler* h1 = new MockHttpHandler("Done"); HELPER_ASSERT_SUCCESS(s.handle("/api/v1", h1)); MockHttpHandler* h2 = new MockHttpHandler("Another one"); HELPER_ASSERT_SUCCESS(s.handle("/apis/", h2)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/apis/v1/echo", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Another one", w); } if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/", h0)); MockHttpHandler* h1 = new MockHttpHandler("Done"); HELPER_ASSERT_SUCCESS(s.handle("/api/v1/", h1)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/apis/v1/echo", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/api/", h0)); MockHttpHandler* h1 = new MockHttpHandler("Done"); HELPER_ASSERT_SUCCESS(s.handle("/api/v1/", h1)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/api/v1/echo", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Done", w); } if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/api/", h0)); MockHttpHandler* h1 = new MockHttpHandler("Done"); HELPER_ASSERT_SUCCESS(s.handle("/apis/", h1)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/apis/v1/echo", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Done", w); } if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* h0 = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/", h0)); MockHttpHandler* h1 = new MockHttpHandler("Done"); HELPER_ASSERT_SUCCESS(s.handle("/index.html", h1)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Done", w); } if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* hroot = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/", hroot)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false)); HELPER_ASSERT_SUCCESS(s.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } } VOID TEST(ProtocolHTTPTest, HTTPServerMuxerCORS) { srs_error_t err; // If CORS enabled, response others with ok except OPTIONS if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* hroot = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/", hroot)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); r.set_basic(HTTP_REQUEST, HTTP_POST, 200, -1); HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false)); SrsHttpCorsMux cs; HELPER_ASSERT_SUCCESS(cs.initialize(&s, true)); HELPER_ASSERT_SUCCESS(cs.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } // If CORS enabled, response OPTIONS with ok if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* hroot = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/", hroot)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); r.set_basic(HTTP_REQUEST, HTTP_OPTIONS, 200, -1); HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false)); SrsHttpCorsMux cs; HELPER_ASSERT_SUCCESS(cs.initialize(&s, true)); HELPER_ASSERT_SUCCESS(cs.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "", w); } // If CORS not enabled, response content except OPTIONS. if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* hroot = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/", hroot)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); r.set_basic(HTTP_REQUEST, HTTP_POST, 200, -1); HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false)); SrsHttpCorsMux cs; HELPER_ASSERT_SUCCESS(cs.initialize(&s, false)); HELPER_ASSERT_SUCCESS(cs.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } // If CORS not enabled, response error for options. if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* hroot = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/", hroot)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); r.set_basic(HTTP_REQUEST, HTTP_OPTIONS, 200, -1); HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false)); SrsHttpCorsMux cs; HELPER_ASSERT_SUCCESS(cs.initialize(&s, false)); HELPER_ASSERT_SUCCESS(cs.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(405, "", w); } if (true) { SrsHttpServeMux s; HELPER_ASSERT_SUCCESS(s.initialize()); MockHttpHandler* hroot = new MockHttpHandler("Hello, world!"); HELPER_ASSERT_SUCCESS(s.handle("/", hroot)); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false)); SrsHttpCorsMux cs; HELPER_ASSERT_SUCCESS(cs.initialize(&s, true)); HELPER_ASSERT_SUCCESS(cs.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } } VOID TEST(ProtocolHTTPTest, VodStreamHandlers) { srs_error_t err; if (true) { SrsHttpMuxEntry e; e.pattern = "/"; string fs; int nn_flv_prefix = 0; if (true) { char flv_header[13]; nn_flv_prefix += sizeof(flv_header); HELPER_ARRAY_INIT(flv_header, 13, 0); fs.append(flv_header, 13); } if (true) { uint8_t tag[15] = {9}; nn_flv_prefix += sizeof(tag); HELPER_ARRAY_INIT(tag+1, 14, 0); fs.append((const char*)tag, sizeof(tag)); } if (true) { uint8_t tag[15] = {8}; nn_flv_prefix += sizeof(tag); HELPER_ARRAY_INIT(tag+1, 14, 0); fs.append((const char*)tag, sizeof(tag)); } string flv_content = "Hello, world!"; fs.append(flv_content); SrsVodStream h("/tmp"); h.set_fs_factory(new MockFileReaderFactory(fs)); h.set_path_check(_mock_srs_path_always_exists); h.entry = &e; MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.flv?start=" + srs_int2str(nn_flv_prefix + 2), false)); HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r)); // We only compare the last content, ignore HTTP and FLV header. string av2 = HELPER_BUFFER2STR(&w.io.out_buffer); string av = av2.substr(av2.length() - flv_content.length() + 2); string ev2 = mock_http_response(200, "llo, world!"); string ev = ev2.substr(ev2.length() - flv_content.length() + 2); EXPECT_STREQ(ev.c_str(), av.c_str()); } if (true) { SrsHttpMuxEntry e; e.pattern = "/"; SrsVodStream h("/tmp"); h.set_fs_factory(new MockFileReaderFactory("Hello, world!")); h.set_path_check(_mock_srs_path_always_exists); h.entry = &e; MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.mp4?range=2-3", false)); HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(206, "ll", w); } if (true) { SrsHttpMuxEntry e; e.pattern = "/"; SrsVodStream h("/tmp"); h.set_fs_factory(new MockFileReaderFactory("Hello, world!")); h.set_path_check(_mock_srs_path_always_exists); h.entry = &e; MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.mp4?bytes=2-5", false)); HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(206, "llo,", w); } // Invalid format of range, use static file handler. if (true) { SrsHttpMuxEntry e; e.pattern = "/"; SrsVodStream h("/tmp"); h.set_fs_factory(new MockFileReaderFactory("Hello, world!")); h.set_path_check(_mock_srs_path_always_exists); h.entry = &e; MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.mp4?range=2", false)); HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } // No range, use static file handler. if (true) { SrsHttpMuxEntry e; e.pattern = "/"; SrsVodStream h("/tmp"); h.set_fs_factory(new MockFileReaderFactory("Hello, world!")); h.set_path_check(_mock_srs_path_always_exists); h.entry = &e; MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.mp4", false)); HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } } VOID TEST(ProtocolHTTPTest, BasicHandlers) { srs_error_t err; if (true) { SrsHttpMuxEntry e; e.pattern = "/"; SrsHttpFileServer h("/tmp"); h.set_fs_factory(new MockFileReaderFactory("Hello, world!")); h.set_path_check(_mock_srs_path_always_exists); h.entry = &e; MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.mp4?range=0", false)); HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } if (true) { SrsHttpMuxEntry e; e.pattern = "/"; SrsHttpFileServer h("/tmp"); h.set_fs_factory(new MockFileReaderFactory("Hello, world!")); h.set_path_check(_mock_srs_path_always_exists); h.entry = &e; MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.mp4", false)); HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } if (true) { SrsHttpMuxEntry e; e.pattern = "/"; SrsHttpFileServer h("/tmp"); h.set_fs_factory(new MockFileReaderFactory("Hello, world!")); h.set_path_check(_mock_srs_path_always_exists); h.entry = &e; MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.mp4?range=12-3", false)); HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } if (true) { SrsHttpMuxEntry e; e.pattern = "/"; SrsHttpFileServer h("/tmp"); h.set_fs_factory(new MockFileReaderFactory("Hello, world!")); h.set_path_check(_mock_srs_path_always_exists); h.entry = &e; MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.mp4?range=2-3", false)); HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } if (true) { SrsHttpMuxEntry e; e.pattern = "/"; SrsHttpFileServer h("/tmp"); h.set_fs_factory(new MockFileReaderFactory("Hello, world!")); h.set_path_check(_mock_srs_path_always_exists); h.entry = &e; MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.flv?start=2", false)); HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } if (true) { SrsHttpMuxEntry e; e.pattern = "/"; SrsHttpFileServer h("/tmp"); h.set_fs_factory(new MockFileReaderFactory("Hello, world!")); h.set_path_check(_mock_srs_path_always_exists); h.entry = &e; MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.flv", false)); HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } if (true) { SrsHttpMuxEntry e; e.pattern = "/"; SrsHttpFileServer h("/tmp"); h.set_fs_factory(new MockFileReaderFactory("Hello, world!")); h.set_path_check(_mock_srs_path_always_exists); h.entry = &e; MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false)); HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w); } if (true) { SrsHttpMuxEntry e; e.pattern = "/"; SrsHttpFileServer h("/tmp"); h.set_fs_factory(new MockFileReaderFactory("Hello, world!")); h.set_path_check(_mock_srs_path_not_exists); h.entry = &e; MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false)); HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(404, "Not Found", w); } if (true) { EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp", "/", "/").c_str()); EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp", "/", "/index.html").c_str()); EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp/", "/", "/index.html").c_str()); EXPECT_STREQ("/tmp/ndex.html", srs_http_fs_fullpath("/tmp/", "//", "/index.html").c_str()); EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp/", "/api", "/api/index.html").c_str()); EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp/", "ossrs.net/api", "/api/index.html").c_str()); EXPECT_STREQ("/tmp/views/index.html", srs_http_fs_fullpath("/tmp/", "/api", "/api/views/index.html").c_str()); EXPECT_STREQ("/tmp/index.html", srs_http_fs_fullpath("/tmp/", "/api/", "/api/index.html").c_str()); EXPECT_STREQ("/tmp/ndex.html", srs_http_fs_fullpath("/tmp/", "/api//", "/api/index.html").c_str()); } if (true) { SrsHttpRedirectHandler h("/api", 500); EXPECT_FALSE(h.is_not_found()); MockResponseWriter w; SrsHttpMessage r(NULL, NULL); HELPER_ASSERT_SUCCESS(r.set_url("/api?v=2.0", false)); HELPER_ASSERT_SUCCESS(h.serve_http(&w, &r)); __MOCK_HTTP_EXPECT_STREQ(500, "Redirect to /api?v=2.0", w); } if (true) { SrsHttpNotFoundHandler h; MockResponseWriter w; HELPER_ASSERT_SUCCESS(h.serve_http(&w, NULL)); __MOCK_HTTP_EXPECT_STREQ(404, "Not Found", w); EXPECT_TRUE(h.is_not_found()); } } VOID TEST(ProtocolHTTPTest, MSegmentsReader) { srs_error_t err; MockMSegmentsReader r; r.in_bytes.push_back("GET /api/v1/versions HTTP/1.1\r\n"); r.in_bytes.push_back("Host: ossrs.net\r\n"); if (true) { char buf[1024]; HELPER_ARRAY_INIT(buf, 1024, 0); ssize_t nn = 0; HELPER_EXPECT_SUCCESS(r.read(buf, 1024, &nn)); ASSERT_EQ(31, nn); EXPECT_STREQ("GET /api/v1/versions HTTP/1.1\r\n", buf); } if (true) { char buf[1024]; HELPER_ARRAY_INIT(buf, 1024, 0); ssize_t nn = 0; HELPER_EXPECT_SUCCESS(r.read(buf, 1024, &nn)); ASSERT_EQ(17, nn); EXPECT_STREQ("Host: ossrs.net\r\n", buf); } } VOID TEST(ProtocolHTTPTest, HTTPMessageParser) { srs_error_t err; if (true) { MockMSegmentsReader r; r.in_bytes.push_back("GET /api/v1/versions HTTP/1.1\r\n"); r.in_bytes.push_back("Host: ossrs"); r.in_bytes.push_back(".net\r"); r.in_bytes.push_back("\n"); r.in_bytes.push_back("\r\n"); SrsHttpParser p; HELPER_ASSERT_SUCCESS(p.initialize(HTTP_REQUEST, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(p.parse_message(&r, &msg)); EXPECT_TRUE(msg->is_http_get()); EXPECT_STREQ("/api/v1/versions", msg->path().c_str()); EXPECT_STREQ("ossrs.net", msg->host().c_str()); srs_freep(msg); } if (true) { MockMSegmentsReader r; r.in_bytes.push_back("GET /api/v1/versions HTTP/1.1\r\n"); r.in_bytes.push_back("Host: ossrs"); r.in_bytes.push_back(".net\r\n"); r.in_bytes.push_back("\r\n"); SrsHttpParser p; HELPER_ASSERT_SUCCESS(p.initialize(HTTP_REQUEST, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(p.parse_message(&r, &msg)); EXPECT_TRUE(msg->is_http_get()); EXPECT_STREQ("/api/v1/versions", msg->path().c_str()); EXPECT_STREQ("ossrs.net", msg->host().c_str()); srs_freep(msg); } if (true) { MockMSegmentsReader r; r.in_bytes.push_back("GET /api/v1/versions HTTP/1.1\r\n"); r.in_bytes.push_back("User-Agent: curl/7.54.0\r\n"); r.in_bytes.push_back("Host: ossrs"); r.in_bytes.push_back(".net\r\n"); r.in_bytes.push_back("\r\n"); SrsHttpParser p; HELPER_ASSERT_SUCCESS(p.initialize(HTTP_REQUEST, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(p.parse_message(&r, &msg)); EXPECT_TRUE(msg->is_http_get()); EXPECT_STREQ("/api/v1/versions", msg->path().c_str()); EXPECT_STREQ("ossrs.net", msg->host().c_str()); EXPECT_STREQ("curl/7.54.0", msg->header()->get("User-Agent").c_str()); srs_freep(msg); } if (true) { MockMSegmentsReader r; r.in_bytes.push_back("GET /api/v1/versions HTTP/1.1\r\n"); r.in_bytes.push_back("User-"); r.in_bytes.push_back("Agent: curl/7.54.0\r\n"); r.in_bytes.push_back("Host: ossrs"); r.in_bytes.push_back(".net\r\n"); r.in_bytes.push_back("\r\n"); SrsHttpParser p; HELPER_ASSERT_SUCCESS(p.initialize(HTTP_REQUEST, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(p.parse_message(&r, &msg)); EXPECT_TRUE(msg->is_http_get()); EXPECT_STREQ("/api/v1/versions", msg->path().c_str()); EXPECT_STREQ("ossrs.net", msg->host().c_str()); EXPECT_STREQ("curl/7.54.0", msg->header()->get("User-Agent").c_str()); srs_freep(msg); } if (true) { MockMSegmentsReader r; r.in_bytes.push_back("GET /api/v1/versions HTTP/1.1\r\n"); r.in_bytes.push_back("User-"); r.in_bytes.push_back("Agent: curl"); r.in_bytes.push_back("/7.54.0\r\n"); r.in_bytes.push_back("Host: ossrs"); r.in_bytes.push_back(".net\r\n"); r.in_bytes.push_back("\r\n"); SrsHttpParser p; HELPER_ASSERT_SUCCESS(p.initialize(HTTP_REQUEST, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(p.parse_message(&r, &msg)); EXPECT_TRUE(msg->is_http_get()); EXPECT_STREQ("/api/v1/versions", msg->path().c_str()); EXPECT_STREQ("ossrs.net", msg->host().c_str()); EXPECT_STREQ("curl/7.54.0", msg->header()->get("User-Agent").c_str()); srs_freep(msg); } if (true) { MockMSegmentsReader r; r.in_bytes.push_back("GET /api/v1/versions HTTP/1.1\r\n"); r.in_bytes.push_back("Host: ossrs.net\r\n"); r.in_bytes.push_back("\r\n"); SrsHttpParser p; HELPER_ASSERT_SUCCESS(p.initialize(HTTP_REQUEST, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(p.parse_message(&r, &msg)); EXPECT_TRUE(msg->is_http_get()); EXPECT_STREQ("/api/v1/versions", msg->path().c_str()); EXPECT_STREQ("ossrs.net", msg->host().c_str()); srs_freep(msg); } } VOID TEST(ProtocolHTTPTest, VhostInQuery) { srs_error_t err; if (true) { SrsHttpHeader h; SrsHttpMessage m; HELPER_ASSERT_SUCCESS(m.set_url("/api/v1?vhost=rt.ossrs.net&token=xxx", false)); m.set_header(&h, false); EXPECT_STREQ("rt.ossrs.net", m.host().c_str()); } if (true) { SrsHttpHeader h; SrsHttpMessage m; HELPER_ASSERT_SUCCESS(m.set_url("/api/v1?vhost=rt.ossrs.net&&token=xxx", false)); m.set_header(&h, false); EXPECT_STREQ("rt.ossrs.net", m.host().c_str()); } if (true) { SrsHttpHeader h; h.set("Host", "ossrs.net:-1"); SrsHttpMessage m; HELPER_ASSERT_SUCCESS(m.set_url("/api/v1?vhost=rt.ossrs.net", false)); m.set_header(&h, false); EXPECT_STREQ("rt.ossrs.net", m.host().c_str()); } if (true) { SrsHttpHeader h; SrsHttpMessage m; HELPER_ASSERT_SUCCESS(m.set_url("/api/v1?vhost=ossrs.net", false)); m.set_header(&h, false); EXPECT_STREQ("ossrs.net", m.host().c_str()); } if (true) { SrsHttpHeader h; h.set("Host", "ossrs.net"); SrsHttpMessage m; m.set_header(&h, false); HELPER_ASSERT_SUCCESS(m.set_url("/api/v1", false)); EXPECT_STREQ("ossrs.net", m.host().c_str()); } } VOID TEST(ProtocolHTTPTest, HTTPMessageUpdate) { srs_error_t err; if (true) { SrsHttpHeader h; SrsHttpMessage m; HELPER_ASSERT_SUCCESS(m.set_url("/api/v1?vhost=ossrs.net", false)); m.set_header(&h, false); EXPECT_STREQ("ossrs.net", m.host().c_str()); } if (true) { SrsHttpHeader h; h.set("Host", "ossrs.net:-1"); SrsHttpMessage m; m.set_header(&h, false); HELPER_EXPECT_FAILED(m.set_url("/api/v1", false)); } // Port use 80 if error. if (true) { SrsHttpHeader h; h.set("Host", "ossrs.net:0"); SrsHttpMessage m; m.set_header(&h, false); HELPER_ASSERT_SUCCESS(m.set_url("/api/v1", false)); EXPECT_EQ(80, m.port()); } // Port default to 80. if (true) { SrsHttpHeader h; h.set("Host", "ossrs.net"); SrsHttpMessage m; m.set_header(&h, false); HELPER_ASSERT_SUCCESS(m.set_url("/api/v1", false)); EXPECT_EQ(80, m.port()); } // For port not 80. if (true) { SrsHttpHeader h; h.set("Host", "ossrs.net:8080"); SrsHttpMessage m; m.set_header(&h, false); HELPER_ASSERT_SUCCESS(m.set_url("/api/v1", false)); EXPECT_EQ(8080, m.port()); } // The host is overwrite by header. if (true) { SrsHttpHeader h; h.set("Host", "ossrs.net"); SrsHttpMessage m; HELPER_ASSERT_SUCCESS(m.set_url("/api/v1", false)); m.set_header(&h, false); EXPECT_STRNE("ossrs.net", m.host().c_str()); } // The host is overwrite by header. if (true) { SrsHttpHeader h; h.set("Host", "ossrs.net"); SrsHttpMessage m; m.set_header(&h, false); HELPER_ASSERT_SUCCESS(m.set_url("/api/v1", false)); EXPECT_STREQ("ossrs.net", m.host().c_str()); } // The content-length is overwrite by header. if (true) { SrsHttpHeader h; h.set("Content-Length", "10"); SrsHttpMessage m; m.set_header(&h, false); m.set_basic(HTTP_REQUEST, HTTP_POST, 200, 2); EXPECT_EQ(10, m.content_length()); } // The content-length is overwrite by header. if (true) { SrsHttpHeader h; h.set("Content-Length", "10"); SrsHttpMessage m; m.set_basic(HTTP_REQUEST, HTTP_POST, 200, 2); m.set_header(&h, false); EXPECT_EQ(10, m.content_length()); } if (true) { SrsHttpHeader h; h.set("Content-Length", "abc"); SrsHttpMessage m; m.set_header(&h, false); EXPECT_EQ(0, m.content_length()); } if (true) { SrsHttpHeader h; h.set("Content-Length", "10"); SrsHttpMessage m; m.set_header(&h, false); EXPECT_EQ(10, m.content_length()); } if (true) { SrsHttpHeader h; h.set("Content-Length", "0"); SrsHttpMessage m; m.set_header(&h, false); EXPECT_EQ(0, m.content_length()); } if (true) { SrsHttpMessage m; m.set_basic(HTTP_REQUEST, HTTP_POST, 200, 0); EXPECT_EQ(0, m.content_length()); } if (true) { SrsHttpMessage m; EXPECT_EQ(-1, m.content_length()); } } VOID TEST(ProtocolHTTPTest, GetOriginalIP) { if (true) { SrsHttpHeader h; h.set("X-Forwarded-For", "10.11.12.13"); SrsHttpMessage m; m.set_header(&h, false); EXPECT_STREQ("10.11.12.13", srs_get_original_ip(&m).c_str()); } if (true) { SrsHttpHeader h; h.set("X-Forwarded-For", "192.193.194.195,10.11.12.13"); SrsHttpMessage m; m.set_header(&h, false); EXPECT_STREQ("192.193.194.195", srs_get_original_ip(&m).c_str()); } if (true) { SrsHttpHeader h; h.set("X-Real-IP", "172.14.42.78"); SrsHttpMessage m; m.set_header(&h, false); EXPECT_STREQ("172.14.42.78", srs_get_original_ip(&m).c_str()); } if (true) { SrsHttpHeader h; h.set("X-Real-IP", "172.14.42.79:15425"); SrsHttpMessage m; m.set_header(&h, false); EXPECT_STREQ("172.14.42.79", srs_get_original_ip(&m).c_str()); } if (true) { SrsHttpHeader h; SrsHttpMessage m; m.set_header(&h, false); EXPECT_STREQ("", srs_get_original_ip(&m).c_str()); } } VOID TEST(ProtocolHTTPTest, ParsingLargeMessages) { srs_error_t err; uint8_t data[] = { 0x50, 0x4f, 0x53, 0x54, 0x20, 0x2f, 0x6a, 0x61, 0x6e, 0x75, 0x73, 0x2f, 0x32, 0x35, 0x38, 0x30, 0x34, 0x39, 0x32, 0x38, 0x30, 0x38, 0x36, 0x34, 0x32, 0x39, 0x31, 0x31, 0x39, 0x30, 0x32, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x33, 0x33, 0x2e, 0x31, 0x38, 0x2e, 0x34, 0x2e, 0x31, 0x32, 0x33, 0x3a, 0x31, 0x39, 0x38, 0x35, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x47, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x33, 0x31, 0x35, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, 0x69, 0x70, 0x0d, 0x0a, 0x0d, 0x0a, 0x7b, 0x22, 0x6a, 0x61, 0x6e, 0x75, 0x73, 0x22, 0x3a, 0x22, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x22, 0x2c, 0x22, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x33, 0x39, 0x39, 0x62, 0x31, 0x33, 0x33, 0x63, 0x31, 0x38, 0x35, 0x62, 0x65, 0x64, 0x66, 0x66, 0x37, 0x66, 0x35, 0x39, 0x35, 0x33, 0x65, 0x38, 0x39, 0x64, 0x31, 0x61, 0x62, 0x62, 0x61, 0x35, 0x22, 0x2c, 0x22, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x30, 0x64, 0x69, 0x65, 0x31, 0x61, 0x6f, 0x36, 0x65, 0x35, 0x35, 0x64, 0x30, 0x72, 0x66, 0x66, 0x78, 0x6b, 0x31, 0x33, 0x79, 0x6d, 0x78, 0x66, 0x30, 0x6d, 0x30, 0x37, 0x62, 0x66, 0x6f, 0x67, 0x22, 0x2c, 0x22, 0x72, 0x70, 0x63, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x69, 0x67, 0x22, 0x2c, 0x22, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x22, 0x3a, 0x22, 0x6a, 0x61, 0x6e, 0x75, 0x73, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x2c, 0x22, 0x6f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x5f, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x64, 0x64, 0x30, 0x66, 0x32, 0x33, 0x31, 0x39, 0x62, 0x34, 0x37, 0x63, 0x65, 0x35, 0x38, 0x64, 0x65, 0x63, 0x65, 0x38, 0x64, 0x64, 0x34, 0x64, 0x36, 0x64, 0x65, 0x62, 0x64, 0x38, 0x65, 0x33, 0x22, 0x2c, 0x22, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x2d, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x22, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x2d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x6d, 0x75, 0x78, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x22, 0x63, 0x61, 0x6c, 0x6c, 0x49, 0x44, 0x22, 0x3a, 0x22, 0x30, 0x62, 0x61, 0x66, 0x7a, 0x34, 0x36, 0x6a, 0x76, 0x76, 0x34, 0x61, 0x30, 0x6a, 0x34, 0x6b, 0x70, 0x35, 0x68, 0x69, 0x64, 0x6e, 0x77, 0x6a, 0x30, 0x61, 0x65, 0x31, 0x66, 0x6e, 0x70, 0x65, 0x22, 0x7d, 0x50, 0x4f, 0x53, 0x54, 0x20, 0x2f, 0x6a, 0x61, 0x6e, 0x75, 0x73, 0x2f, 0x32, 0x35, 0x38, 0x30, 0x34, 0x39, 0x32, 0x38, 0x30, 0x38, 0x36, 0x34, 0x32, 0x39, 0x31, 0x31, 0x39, 0x30, 0x32, 0x2f, 0x31, 0x31, 0x31, 0x32, 0x34, 0x36, 0x37, 0x34, 0x36, 0x33, 0x37, 0x34, 0x34, 0x39, 0x36, 0x37, 0x31, 0x32, 0x32, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x33, 0x33, 0x2e, 0x31, 0x38, 0x2e, 0x34, 0x2e, 0x31, 0x32, 0x33, 0x3a, 0x31, 0x39, 0x38, 0x35, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x47, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x36, 0x38, 0x33, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, 0x69, 0x70, 0x0d, 0x0a, 0x0d, 0x0a, 0x7b, 0x22, 0x6a, 0x61, 0x6e, 0x75, 0x73, 0x22, 0x3a, 0x22, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2c, 0x22, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x38, 0x35, 0x63, 0x37, 0x36, 0x62, 0x62, 0x33, 0x39, 0x37, 0x34, 0x33, 0x38, 0x39, 0x36, 0x64, 0x35, 0x37, 0x61, 0x31, 0x63, 0x38, 0x36, 0x66, 0x34, 0x64, 0x30, 0x31, 0x65, 0x30, 0x30, 0x61, 0x22, 0x2c, 0x22, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x30, 0x64, 0x69, 0x65, 0x31, 0x61, 0x6f, 0x36, 0x65, 0x35, 0x35, 0x64, 0x30, 0x72, 0x66, 0x66, 0x78, 0x6b, 0x31, 0x33, 0x79, 0x6d, 0x78, 0x66, 0x30, 0x6d, 0x30, 0x37, 0x62, 0x66, 0x6f, 0x67, 0x22, 0x2c, 0x22, 0x72, 0x70, 0x63, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x69, 0x67, 0x22, 0x2c, 0x22, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x3a, 0x7b, 0x22, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x22, 0x6a, 0x6f, 0x69, 0x6e, 0x22, 0x2c, 0x22, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x3a, 0x39, 0x39, 0x38, 0x31, 0x2c, 0x22, 0x70, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x22, 0x2c, 0x22, 0x66, 0x65, 0x65, 0x64, 0x22, 0x3a, 0x31, 0x32, 0x37, 0x39, 0x33, 0x36, 0x37, 0x31, 0x33, 0x33, 0x35, 0x39, 0x39, 0x35, 0x34, 0x33, 0x32, 0x39, 0x36, 0x2c, 0x22, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x22, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x22, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x5f, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x22, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x5f, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6d, 0x73, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x3a, 0x22, 0x38, 0x4f, 0x33, 0x72, 0x44, 0x46, 0x70, 0x32, 0x51, 0x57, 0x77, 0x47, 0x42, 0x43, 0x78, 0x69, 0x4a, 0x36, 0x45, 0x4e, 0x65, 0x36, 0x4f, 0x6f, 0x73, 0x4e, 0x53, 0x47, 0x51, 0x77, 0x65, 0x47, 0x32, 0x66, 0x33, 0x6d, 0x22, 0x2c, 0x22, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x3a, 0x22, 0x62, 0x31, 0x36, 0x64, 0x32, 0x37, 0x36, 0x63, 0x2d, 0x34, 0x64, 0x61, 0x33, 0x2d, 0x34, 0x66, 0x35, 0x39, 0x2d, 0x39, 0x66, 0x37, 0x35, 0x2d, 0x35, 0x66, 0x33, 0x61, 0x31, 0x32, 0x32, 0x38, 0x66, 0x39, 0x31, 0x34, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x22, 0x2c, 0x22, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x73, 0x75, 0x62, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x45, 0x4e, 0x47, 0x49, 0x4e, 0x45, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x6d, 0x73, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x3a, 0x22, 0x38, 0x4f, 0x33, 0x72, 0x44, 0x46, 0x70, 0x32, 0x51, 0x57, 0x77, 0x47, 0x42, 0x43, 0x78, 0x69, 0x4a, 0x36, 0x45, 0x4e, 0x65, 0x36, 0x4f, 0x6f, 0x73, 0x4e, 0x53, 0x47, 0x51, 0x77, 0x65, 0x47, 0x32, 0x66, 0x33, 0x6d, 0x22, 0x2c, 0x22, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x3a, 0x22, 0x31, 0x30, 0x33, 0x36, 0x33, 0x61, 0x65, 0x39, 0x2d, 0x64, 0x34, 0x39, 0x37, 0x2d, 0x34, 0x33, 0x66, 0x32, 0x2d, 0x39, 0x32, 0x38, 0x38, 0x2d, 0x37, 0x61, 0x32, 0x37, 0x31, 0x65, 0x65, 0x31, 0x64, 0x63, 0x30, 0x61, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x22, 0x2c, 0x22, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x73, 0x75, 0x62, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x53, 0x44, 0x5f, 0x33, 0x36, 0x30, 0x5f, 0x36, 0x34, 0x30, 0x50, 0x5f, 0x31, 0x35, 0x22, 0x7d, 0x5d, 0x7d, 0x7d, 0x50, 0x4f, 0x53, 0x54, 0x20, 0x2f, 0x6a, 0x61, 0x6e, 0x75, 0x73, 0x2f, 0x32, 0x35, 0x38, 0x30, 0x34, 0x39, 0x32, 0x38, 0x30, 0x38, 0x36, 0x34, 0x32, 0x39, 0x31, 0x31, 0x39, 0x30, 0x32, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x33, 0x33, 0x2e, 0x31, 0x38, 0x2e, 0x34, 0x2e, 0x31, 0x32, 0x33, 0x3a, 0x31, 0x39, 0x38, 0x35, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x47, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x33, 0x31, 0x35, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, 0x69, 0x70, 0x0d, 0x0a, 0x0d, 0x0a, 0x7b, 0x22, 0x6a, 0x61, 0x6e, 0x75, 0x73, 0x22, 0x3a, 0x22, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x22, 0x2c, 0x22, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x39, 0x37, 0x34, 0x31, 0x65, 0x32, 0x39, 0x36, 0x61, 0x32, 0x34, 0x30, 0x61, 0x33, 0x65, 0x63, 0x61, 0x65, 0x66, 0x39, 0x64, 0x32, 0x63, 0x66, 0x62, 0x39, 0x36, 0x39, 0x36, 0x38, 0x22, 0x2c, 0x22, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x30, 0x6f, 0x77, 0x65, 0x67, 0x75, 0x35, 0x6f, 0x74, 0x66, 0x75, 0x30, 0x68, 0x64, 0x67, 0x6e, 0x68, 0x72, 0x6d, 0x6d, 0x76, 0x34, 0x63, 0x30, 0x79, 0x6b, 0x35, 0x67, 0x6e, 0x74, 0x38, 0x39, 0x22, 0x2c, 0x22, 0x72, 0x70, 0x63, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x69, 0x67, 0x22, 0x2c, 0x22, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x22, 0x3a, 0x22, 0x6a, 0x61, 0x6e, 0x75, 0x73, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x2c, 0x22, 0x6f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x5f, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x37, 0x35, 0x65, 0x36, 0x64, 0x37, 0x38, 0x32, 0x39, 0x61, 0x30, 0x32, 0x30, 0x63, 0x36, 0x30, 0x37, 0x61, 0x30, 0x38, 0x34, 0x37, 0x63, 0x32, 0x63, 0x62, 0x36, 0x37, 0x38, 0x65, 0x34, 0x35, 0x22, 0x2c, 0x22, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x2d, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x22, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x2d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x6d, 0x75, 0x78, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x22, 0x63, 0x61, 0x6c, 0x6c, 0x49, 0x44, 0x22, 0x3a, 0x22, 0x30, 0x34, 0x31, 0x67, 0x67, 0x6d, 0x77, 0x6f, 0x69, 0x30, 0x30, 0x68, 0x30, 0x71, 0x31, 0x6c, 0x72, 0x67, 0x79, 0x69, 0x30, 0x77, 0x6e, 0x30, 0x39, 0x75, 0x39, 0x37, 0x65, 0x66, 0x6f, 0x70, 0x22, 0x7d, 0x50, 0x4f, 0x53, 0x54, 0x20, 0x2f, 0x6a, 0x61, 0x6e, 0x75, 0x73, 0x2f, 0x32, 0x35, 0x38, 0x30, 0x34, 0x39, 0x32, 0x38, 0x30, 0x38, 0x36, 0x34, 0x32, 0x39, 0x31, 0x31, 0x39, 0x30, 0x32, 0x2f, 0x34, 0x32, 0x36, 0x38, 0x30, 0x33, 0x37, 0x39, 0x33, 0x30, 0x36, 0x34, 0x39, 0x33, 0x33, 0x36, 0x30, 0x38, 0x36, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x33, 0x33, 0x2e, 0x31, 0x38, 0x2e, 0x34, 0x2e, 0x31, 0x32, 0x33, 0x3a, 0x31, 0x39, 0x38, 0x35, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x47, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x32, 0x35, 0x35, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, 0x69, 0x70, 0x0d, 0x0a, 0x0d, 0x0a, 0x7b, 0x22, 0x6a, 0x61, 0x6e, 0x75, 0x73, 0x22, 0x3a, 0x22, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2c, 0x22, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x34, 0x35, 0x33, 0x61, 0x63, 0x63, 0x30, 0x33, 0x62, 0x34, 0x34, 0x32, 0x34, 0x61, 0x33, 0x37, 0x35, 0x37, 0x31, 0x61, 0x30, 0x36, 0x38, 0x65, 0x64, 0x39, 0x35, 0x39, 0x37, 0x36, 0x37, 0x34, 0x22, 0x2c, 0x22, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x30, 0x6f, 0x77, 0x65, 0x67, 0x75, 0x35, 0x6f, 0x74, 0x66, 0x75, 0x30, 0x68, 0x64, 0x67, 0x6e, 0x68, 0x72, 0x6d, 0x6d, 0x76, 0x34, 0x63, 0x30, 0x79, 0x6b, 0x35, 0x67, 0x6e, 0x74, 0x38, 0x39, 0x22, 0x2c, 0x22, 0x72, 0x70, 0x63, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x69, 0x67, 0x22, 0x2c, 0x22, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x3a, 0x7b, 0x22, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x22, 0x6a, 0x6f, 0x69, 0x6e, 0x22, 0x2c, 0x22, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x3a, 0x39, 0x39, 0x38, 0x31, 0x2c, 0x22, 0x70, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x22, 0x2c, 0x22, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x22, 0x3a, 0x22, 0x39, 0x61, 0x37, 0x62, 0x34, 0x22, 0x2c, 0x22, 0x66, 0x65, 0x65, 0x64, 0x5f, 0x69, 0x64, 0x22, 0x3a, 0x31, 0x32, 0x37, 0x39, 0x33, 0x36, 0x37, 0x35, 0x33, 0x31, 0x39, 0x30, 0x33, 0x32, 0x33, 0x34, 0x30, 0x34, 0x38, 0x7d, 0x7d, 0x50, 0x4f, 0x53, 0x54, 0x20, 0x2f, 0x6a, 0x61, 0x6e, 0x75, 0x73, 0x2f, 0x32, 0x35, 0x38, 0x30, 0x34, 0x39, 0x32, 0x38, 0x30, 0x38, 0x36, 0x34, 0x32, 0x39, 0x31, 0x31, 0x39, 0x30, 0x32, 0x2f, 0x34, 0x32, 0x36, 0x38, 0x30, 0x33, 0x37, 0x39, 0x33, 0x30, 0x36, 0x34, 0x39, 0x33, 0x33, 0x36, 0x30, 0x38, 0x36, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x33, 0x33, 0x2e, 0x31, 0x38, 0x2e, 0x34, 0x2e, 0x31, 0x32, 0x33, 0x3a, 0x31, 0x39, 0x38, 0x35, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x47, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x36, 0x33, 0x31, 0x37, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, 0x69, 0x70, 0x0d, 0x0a, 0x0d, 0x0a, 0x7b, 0x22, 0x6a, 0x61, 0x6e, 0x75, 0x73, 0x22, 0x3a, 0x22, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2c, 0x22, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x61, 0x39, 0x65, 0x37, 0x64, 0x32, 0x31, 0x62, 0x36, 0x62, 0x33, 0x63, 0x61, 0x63, 0x66, 0x64, 0x33, 0x65, 0x36, 0x35, 0x32, 0x62, 0x33, 0x39, 0x39, 0x62, 0x64, 0x34, 0x34, 0x64, 0x30, 0x35, 0x22, 0x2c, 0x22, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x30, 0x6f, 0x77, 0x65, 0x67, 0x75, 0x35, 0x6f, 0x74, 0x66, 0x75, 0x30, 0x68, 0x64, 0x67, 0x6e, 0x68, 0x72, 0x6d, 0x6d, 0x76, 0x34, 0x63, 0x30, 0x79, 0x6b, 0x35, 0x67, 0x6e, 0x74, 0x38, 0x39, 0x22, 0x2c, 0x22, 0x72, 0x70, 0x63, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x69, 0x67, 0x22, 0x2c, 0x22, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x3a, 0x7b, 0x22, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x22, 0x2c, 0x22, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x22, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6d, 0x73, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x3a, 0x22, 0x76, 0x72, 0x79, 0x33, 0x6b, 0x78, 0x38, 0x4f, 0x44, 0x50, 0x77, 0x48, 0x45, 0x55, 0x71, 0x74, 0x67, 0x34, 0x6a, 0x51, 0x65, 0x37, 0x6d, 0x63, 0x4b, 0x5a, 0x58, 0x6d, 0x34, 0x41, 0x6b, 0x79, 0x54, 0x4f, 0x49, 0x42, 0x22, 0x2c, 0x22, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x3a, 0x22, 0x66, 0x31, 0x31, 0x34, 0x31, 0x62, 0x61, 0x31, 0x2d, 0x37, 0x62, 0x36, 0x65, 0x2d, 0x34, 0x30, 0x30, 0x30, 0x2d, 0x38, 0x64, 0x38, 0x37, 0x2d, 0x38, 0x39, 0x34, 0x63, 0x63, 0x62, 0x36, 0x63, 0x63, 0x66, 0x37, 0x38, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x22, 0x2c, 0x22, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x73, 0x75, 0x62, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x22, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x22, 0x2c, 0x22, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x45, 0x4e, 0x47, 0x49, 0x4e, 0x45, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x6d, 0x73, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x3a, 0x22, 0x76, 0x72, 0x79, 0x33, 0x6b, 0x78, 0x38, 0x4f, 0x44, 0x50, 0x77, 0x48, 0x45, 0x55, 0x71, 0x74, 0x67, 0x34, 0x6a, 0x51, 0x65, 0x37, 0x6d, 0x63, 0x4b, 0x5a, 0x58, 0x6d, 0x34, 0x41, 0x6b, 0x79, 0x54, 0x4f, 0x49, 0x42, 0x22, 0x2c, 0x22, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x3a, 0x22, 0x37, 0x63, 0x37, 0x31, 0x37, 0x66, 0x36, 0x39, 0x2d, 0x62, 0x63, 0x33, 0x35, 0x2d, 0x34, 0x30, 0x38, 0x39, 0x2d, 0x38, 0x34, 0x63, 0x65, 0x2d, 0x34, 0x31, 0x65, 0x61, 0x38, 0x65, 0x31, 0x63, 0x34, 0x33, 0x39, 0x31, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x22, 0x2c, 0x22, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x73, 0x75, 0x62, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x22, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x22, 0x2c, 0x22, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x53, 0x44, 0x5f, 0x33, 0x36, 0x30, 0x5f, 0x36, 0x34, 0x30, 0x50, 0x5f, 0x31, 0x35, 0x22, 0x2c, 0x22, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x22, 0x7d, 0x5d, 0x7d, 0x2c, 0x22, 0x6a, 0x73, 0x65, 0x70, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x22, 0x2c, 0x22, 0x73, 0x64, 0x70, 0x22, 0x3a, 0x22, 0x76, 0x3d, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x6f, 0x3d, 0x2d, 0x20, 0x39, 0x34, 0x30, 0x30, 0x30, 0x38, 0x34, 0x31, 0x31, 0x37, 0x30, 0x30, 0x34, 0x34, 0x37, 0x33, 0x30, 0x37, 0x20, 0x32, 0x20, 0x49, 0x4e, 0x20, 0x49, 0x50, 0x34, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x5c, 0x72, 0x5c, 0x6e, 0x73, 0x3d, 0x2d, 0x5c, 0x72, 0x5c, 0x6e, 0x74, 0x3d, 0x30, 0x20, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x3a, 0x42, 0x55, 0x4e, 0x44, 0x4c, 0x45, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x6d, 0x73, 0x69, 0x64, 0x2d, 0x73, 0x65, 0x6d, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x3a, 0x20, 0x57, 0x4d, 0x53, 0x20, 0x76, 0x72, 0x79, 0x33, 0x6b, 0x78, 0x38, 0x4f, 0x44, 0x50, 0x77, 0x48, 0x45, 0x55, 0x71, 0x74, 0x67, 0x34, 0x6a, 0x51, 0x65, 0x37, 0x6d, 0x63, 0x4b, 0x5a, 0x58, 0x6d, 0x34, 0x41, 0x6b, 0x79, 0x54, 0x4f, 0x49, 0x42, 0x5c, 0x72, 0x5c, 0x6e, 0x6d, 0x3d, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x39, 0x20, 0x55, 0x44, 0x50, 0x2f, 0x54, 0x4c, 0x53, 0x2f, 0x52, 0x54, 0x50, 0x2f, 0x53, 0x41, 0x56, 0x50, 0x46, 0x20, 0x31, 0x31, 0x31, 0x20, 0x31, 0x30, 0x33, 0x20, 0x31, 0x30, 0x34, 0x20, 0x39, 0x20, 0x30, 0x20, 0x38, 0x20, 0x31, 0x30, 0x36, 0x20, 0x31, 0x30, 0x35, 0x20, 0x31, 0x33, 0x20, 0x31, 0x31, 0x30, 0x20, 0x31, 0x31, 0x32, 0x20, 0x31, 0x31, 0x33, 0x20, 0x31, 0x32, 0x36, 0x5c, 0x72, 0x5c, 0x6e, 0x63, 0x3d, 0x49, 0x4e, 0x20, 0x49, 0x50, 0x34, 0x20, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x3a, 0x39, 0x20, 0x49, 0x4e, 0x20, 0x49, 0x50, 0x34, 0x20, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x69, 0x63, 0x65, 0x2d, 0x75, 0x66, 0x72, 0x61, 0x67, 0x3a, 0x67, 0x4b, 0x2f, 0x62, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x69, 0x63, 0x65, 0x2d, 0x70, 0x77, 0x64, 0x3a, 0x36, 0x49, 0x42, 0x68, 0x6c, 0x50, 0x6e, 0x61, 0x38, 0x73, 0x7a, 0x32, 0x59, 0x76, 0x64, 0x6a, 0x6e, 0x33, 0x6a, 0x34, 0x49, 0x57, 0x73, 0x4d, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x69, 0x63, 0x65, 0x2d, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x74, 0x72, 0x69, 0x63, 0x6b, 0x6c, 0x65, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x73, 0x68, 0x61, 0x2d, 0x32, 0x35, 0x36, 0x20, 0x33, 0x43, 0x3a, 0x32, 0x43, 0x3a, 0x37, 0x42, 0x3a, 0x45, 0x39, 0x3a, 0x33, 0x45, 0x3a, 0x38, 0x44, 0x3a, 0x32, 0x39, 0x3a, 0x44, 0x38, 0x3a, 0x44, 0x42, 0x3a, 0x39, 0x36, 0x3a, 0x38, 0x46, 0x3a, 0x41, 0x41, 0x3a, 0x42, 0x31, 0x3a, 0x34, 0x32, 0x3a, 0x35, 0x32, 0x3a, 0x34, 0x46, 0x3a, 0x37, 0x36, 0x3a, 0x37, 0x31, 0x3a, 0x43, 0x44, 0x3a, 0x34, 0x42, 0x3a, 0x38, 0x31, 0x3a, 0x34, 0x36, 0x3a, 0x39, 0x35, 0x3a, 0x33, 0x36, 0x3a, 0x33, 0x38, 0x3a, 0x33, 0x45, 0x3a, 0x36, 0x37, 0x3a, 0x45, 0x41, 0x3a, 0x41, 0x43, 0x3a, 0x41, 0x42, 0x3a, 0x37, 0x46, 0x3a, 0x31, 0x35, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x65, 0x74, 0x75, 0x70, 0x3a, 0x61, 0x63, 0x74, 0x70, 0x61, 0x73, 0x73, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x6d, 0x69, 0x64, 0x3a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x65, 0x78, 0x74, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x20, 0x75, 0x72, 0x6e, 0x3a, 0x69, 0x65, 0x74, 0x66, 0x3a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x72, 0x74, 0x70, 0x2d, 0x68, 0x64, 0x72, 0x65, 0x78, 0x74, 0x3a, 0x73, 0x73, 0x72, 0x63, 0x2d, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2d, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x65, 0x78, 0x74, 0x6d, 0x61, 0x70, 0x3a, 0x32, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x72, 0x74, 0x70, 0x2d, 0x68, 0x64, 0x72, 0x65, 0x78, 0x74, 0x2f, 0x61, 0x62, 0x73, 0x2d, 0x73, 0x65, 0x6e, 0x64, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x65, 0x78, 0x74, 0x6d, 0x61, 0x70, 0x3a, 0x33, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x69, 0x64, 0x2f, 0x64, 0x72, 0x61, 0x66, 0x74, 0x2d, 0x68, 0x6f, 0x6c, 0x6d, 0x65, 0x72, 0x2d, 0x72, 0x6d, 0x63, 0x61, 0x74, 0x2d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x77, 0x69, 0x64, 0x65, 0x2d, 0x63, 0x63, 0x2d, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2d, 0x30, 0x31, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x65, 0x6e, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x6d, 0x75, 0x78, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x31, 0x31, 0x20, 0x6f, 0x70, 0x75, 0x73, 0x2f, 0x34, 0x38, 0x30, 0x30, 0x30, 0x2f, 0x32, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x31, 0x31, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x63, 0x63, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x69, 0x6e, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x3d, 0x31, 0x30, 0x3b, 0x75, 0x73, 0x65, 0x69, 0x6e, 0x62, 0x61, 0x6e, 0x64, 0x66, 0x65, 0x63, 0x3d, 0x31, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x30, 0x33, 0x20, 0x49, 0x53, 0x41, 0x43, 0x2f, 0x31, 0x36, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x30, 0x34, 0x20, 0x49, 0x53, 0x41, 0x43, 0x2f, 0x33, 0x32, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x39, 0x20, 0x47, 0x37, 0x32, 0x32, 0x2f, 0x38, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x30, 0x20, 0x50, 0x43, 0x4d, 0x55, 0x2f, 0x38, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x38, 0x20, 0x50, 0x43, 0x4d, 0x41, 0x2f, 0x38, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x30, 0x36, 0x20, 0x43, 0x4e, 0x2f, 0x33, 0x32, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x30, 0x35, 0x20, 0x43, 0x4e, 0x2f, 0x31, 0x36, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x33, 0x20, 0x43, 0x4e, 0x2f, 0x38, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x31, 0x30, 0x20, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2f, 0x34, 0x38, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x31, 0x32, 0x20, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2f, 0x33, 0x32, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x31, 0x33, 0x20, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2f, 0x31, 0x36, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x32, 0x36, 0x20, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2f, 0x38, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x73, 0x72, 0x63, 0x3a, 0x33, 0x34, 0x39, 0x34, 0x31, 0x34, 0x31, 0x34, 0x31, 0x30, 0x20, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x33, 0x4c, 0x75, 0x6d, 0x55, 0x62, 0x6a, 0x6c, 0x70, 0x50, 0x4d, 0x79, 0x77, 0x45, 0x31, 0x52, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x73, 0x72, 0x63, 0x3a, 0x33, 0x34, 0x39, 0x34, 0x31, 0x34, 0x31, 0x34, 0x31, 0x30, 0x20, 0x6d, 0x73, 0x69, 0x64, 0x3a, 0x76, 0x72, 0x79, 0x33, 0x6b, 0x78, 0x38, 0x4f, 0x44, 0x50, 0x77, 0x48, 0x45, 0x55, 0x71, 0x74, 0x67, 0x34, 0x6a, 0x51, 0x65, 0x37, 0x6d, 0x63, 0x4b, 0x5a, 0x58, 0x6d, 0x34, 0x41, 0x6b, 0x79, 0x54, 0x4f, 0x49, 0x42, 0x20, 0x66, 0x31, 0x31, 0x34, 0x31, 0x62, 0x61, 0x31, 0x2d, 0x37, 0x62, 0x36, 0x65, 0x2d, 0x34, 0x30, 0x30, 0x30, 0x2d, 0x38, 0x64, 0x38, 0x37, 0x2d, 0x38, 0x39, 0x34, 0x63, 0x63, 0x62, 0x36, 0x63, 0x63, 0x66, 0x37, 0x38, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x73, 0x72, 0x63, 0x3a, 0x33, 0x34, 0x39, 0x34, 0x31, 0x34, 0x31, 0x34, 0x31, 0x30, 0x20, 0x6d, 0x73, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x76, 0x72, 0x79, 0x33, 0x6b, 0x78, 0x38, 0x4f, 0x44, 0x50, 0x77, 0x48, 0x45, 0x55, 0x71, 0x74, 0x67, 0x34, 0x6a, 0x51, 0x65, 0x37, 0x6d, 0x63, 0x4b, 0x5a, 0x58, 0x6d, 0x34, 0x41, 0x6b, 0x79, 0x54, 0x4f, 0x49, 0x42, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x73, 0x72, 0x63, 0x3a, 0x33, 0x34, 0x39, 0x34, 0x31, 0x34, 0x31, 0x34, 0x31, 0x30, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x66, 0x31, 0x31, 0x34, 0x31, 0x62, 0x61, 0x31, 0x2d, 0x37, 0x62, 0x36, 0x65, 0x2d, 0x34, 0x30, 0x30, 0x30, 0x2d, 0x38, 0x64, 0x38, 0x37, 0x2d, 0x38, 0x39, 0x34, 0x63, 0x63, 0x62, 0x36, 0x63, 0x63, 0x66, 0x37, 0x38, 0x5c, 0x72, 0x5c, 0x6e, 0x6d, 0x3d, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x20, 0x39, 0x20, 0x55, 0x44, 0x50, 0x2f, 0x54, 0x4c, 0x53, 0x2f, 0x52, 0x54, 0x50, 0x2f, 0x53, 0x41, 0x56, 0x50, 0x46, 0x20, 0x39, 0x36, 0x20, 0x39, 0x37, 0x20, 0x39, 0x38, 0x20, 0x39, 0x39, 0x20, 0x31, 0x30, 0x30, 0x20, 0x31, 0x30, 0x31, 0x20, 0x31, 0x30, 0x32, 0x20, 0x31, 0x32, 0x32, 0x20, 0x31, 0x32, 0x37, 0x20, 0x31, 0x32, 0x31, 0x20, 0x31, 0x32, 0x35, 0x20, 0x31, 0x30, 0x37, 0x20, 0x31, 0x30, 0x38, 0x20, 0x31, 0x30, 0x39, 0x20, 0x31, 0x32, 0x34, 0x20, 0x31, 0x32, 0x30, 0x20, 0x31, 0x32, 0x33, 0x20, 0x31, 0x31, 0x39, 0x20, 0x31, 0x31, 0x34, 0x20, 0x31, 0x31, 0x35, 0x20, 0x31, 0x31, 0x36, 0x5c, 0x72, 0x5c, 0x6e, 0x63, 0x3d, 0x49, 0x4e, 0x20, 0x49, 0x50, 0x34, 0x20, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x3a, 0x39, 0x20, 0x49, 0x4e, 0x20, 0x49, 0x50, 0x34, 0x20, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x69, 0x63, 0x65, 0x2d, 0x75, 0x66, 0x72, 0x61, 0x67, 0x3a, 0x67, 0x4b, 0x2f, 0x62, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x69, 0x63, 0x65, 0x2d, 0x70, 0x77, 0x64, 0x3a, 0x36, 0x49, 0x42, 0x68, 0x6c, 0x50, 0x6e, 0x61, 0x38, 0x73, 0x7a, 0x32, 0x59, 0x76, 0x64, 0x6a, 0x6e, 0x33, 0x6a, 0x34, 0x49, 0x57, 0x73, 0x4d, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x69, 0x63, 0x65, 0x2d, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x74, 0x72, 0x69, 0x63, 0x6b, 0x6c, 0x65, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x73, 0x68, 0x61, 0x2d, 0x32, 0x35, 0x36, 0x20, 0x33, 0x43, 0x3a, 0x32, 0x43, 0x3a, 0x37, 0x42, 0x3a, 0x45, 0x39, 0x3a, 0x33, 0x45, 0x3a, 0x38, 0x44, 0x3a, 0x32, 0x39, 0x3a, 0x44, 0x38, 0x3a, 0x44, 0x42, 0x3a, 0x39, 0x36, 0x3a, 0x38, 0x46, 0x3a, 0x41, 0x41, 0x3a, 0x42, 0x31, 0x3a, 0x34, 0x32, 0x3a, 0x35, 0x32, 0x3a, 0x34, 0x46, 0x3a, 0x37, 0x36, 0x3a, 0x37, 0x31, 0x3a, 0x43, 0x44, 0x3a, 0x34, 0x42, 0x3a, 0x38, 0x31, 0x3a, 0x34, 0x36, 0x3a, 0x39, 0x35, 0x3a, 0x33, 0x36, 0x3a, 0x33, 0x38, 0x3a, 0x33, 0x45, 0x3a, 0x36, 0x37, 0x3a, 0x45, 0x41, 0x3a, 0x41, 0x43, 0x3a, 0x41, 0x42, 0x3a, 0x37, 0x46, 0x3a, 0x31, 0x35, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x65, 0x74, 0x75, 0x70, 0x3a, 0x61, 0x63, 0x74, 0x70, 0x61, 0x73, 0x73, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x6d, 0x69, 0x64, 0x3a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x65, 0x78, 0x74, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x34, 0x20, 0x75, 0x72, 0x6e, 0x3a, 0x69, 0x65, 0x74, 0x66, 0x3a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x72, 0x74, 0x70, 0x2d, 0x68, 0x64, 0x72, 0x65, 0x78, 0x74, 0x3a, 0x74, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x65, 0x78, 0x74, 0x6d, 0x61, 0x70, 0x3a, 0x32, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x72, 0x74, 0x70, 0x2d, 0x68, 0x64, 0x72, 0x65, 0x78, 0x74, 0x2f, 0x61, 0x62, 0x73, 0x2d, 0x73, 0x65, 0x6e, 0x64, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x65, 0x78, 0x74, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x33, 0x20, 0x75, 0x72, 0x6e, 0x3a, 0x33, 0x67, 0x70, 0x70, 0x3a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2d, 0x6f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x65, 0x78, 0x74, 0x6d, 0x61, 0x70, 0x3a, 0x33, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x69, 0x64, 0x2f, 0x64, 0x72, 0x61, 0x66, 0x74, 0x2d, 0x68, 0x6f, 0x6c, 0x6d, 0x65, 0x72, 0x2d, 0x72, 0x6d, 0x63, 0x61, 0x74, 0x2d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x77, 0x69, 0x64, 0x65, 0x2d, 0x63, 0x63, 0x2d, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2d, 0x30, 0x31, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x65, 0x78, 0x74, 0x6d, 0x61, 0x70, 0x3a, 0x35, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x72, 0x74, 0x70, 0x2d, 0x68, 0x64, 0x72, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2d, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x65, 0x78, 0x74, 0x6d, 0x61, 0x70, 0x3a, 0x36, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x72, 0x74, 0x70, 0x2d, 0x68, 0x64, 0x72, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x65, 0x78, 0x74, 0x6d, 0x61, 0x70, 0x3a, 0x37, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x72, 0x74, 0x70, 0x2d, 0x68, 0x64, 0x72, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2d, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x65, 0x78, 0x74, 0x6d, 0x61, 0x70, 0x3a, 0x38, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2f, 0x64, 0x72, 0x61, 0x66, 0x74, 0x2d, 0x69, 0x65, 0x74, 0x66, 0x2d, 0x61, 0x76, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x2d, 0x30, 0x37, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x65, 0x78, 0x74, 0x6d, 0x61, 0x70, 0x3a, 0x39, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x72, 0x74, 0x70, 0x2d, 0x68, 0x64, 0x72, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x65, 0x6e, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x6d, 0x75, 0x78, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x72, 0x73, 0x69, 0x7a, 0x65, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x39, 0x36, 0x20, 0x56, 0x50, 0x38, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x39, 0x36, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x2d, 0x72, 0x65, 0x6d, 0x62, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x39, 0x36, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x63, 0x63, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x39, 0x36, 0x20, 0x63, 0x63, 0x6d, 0x20, 0x66, 0x69, 0x72, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x39, 0x36, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x39, 0x36, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x20, 0x70, 0x6c, 0x69, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x39, 0x37, 0x20, 0x72, 0x74, 0x78, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x39, 0x37, 0x20, 0x61, 0x70, 0x74, 0x3d, 0x39, 0x36, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x39, 0x38, 0x20, 0x56, 0x50, 0x39, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x39, 0x38, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x2d, 0x72, 0x65, 0x6d, 0x62, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x39, 0x38, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x63, 0x63, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x39, 0x38, 0x20, 0x63, 0x63, 0x6d, 0x20, 0x66, 0x69, 0x72, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x39, 0x38, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x39, 0x38, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x20, 0x70, 0x6c, 0x69, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x39, 0x38, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x69, 0x64, 0x3d, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x39, 0x39, 0x20, 0x72, 0x74, 0x78, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x39, 0x39, 0x20, 0x61, 0x70, 0x74, 0x3d, 0x39, 0x38, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x30, 0x30, 0x20, 0x56, 0x50, 0x39, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x30, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x2d, 0x72, 0x65, 0x6d, 0x62, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x30, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x63, 0x63, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x30, 0x20, 0x63, 0x63, 0x6d, 0x20, 0x66, 0x69, 0x72, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x30, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x30, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x20, 0x70, 0x6c, 0x69, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x30, 0x30, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x69, 0x64, 0x3d, 0x32, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x30, 0x31, 0x20, 0x72, 0x74, 0x78, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x30, 0x31, 0x20, 0x61, 0x70, 0x74, 0x3d, 0x31, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x30, 0x32, 0x20, 0x48, 0x32, 0x36, 0x34, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x32, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x2d, 0x72, 0x65, 0x6d, 0x62, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x32, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x63, 0x63, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x32, 0x20, 0x63, 0x63, 0x6d, 0x20, 0x66, 0x69, 0x72, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x32, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x32, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x20, 0x70, 0x6c, 0x69, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x30, 0x32, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2d, 0x61, 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x3d, 0x31, 0x3b, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6d, 0x6f, 0x64, 0x65, 0x3d, 0x31, 0x3b, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2d, 0x69, 0x64, 0x3d, 0x34, 0x32, 0x30, 0x30, 0x31, 0x66, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x32, 0x32, 0x20, 0x72, 0x74, 0x78, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x32, 0x32, 0x20, 0x61, 0x70, 0x74, 0x3d, 0x31, 0x30, 0x32, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x32, 0x37, 0x20, 0x48, 0x32, 0x36, 0x34, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x37, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x2d, 0x72, 0x65, 0x6d, 0x62, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x37, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x63, 0x63, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x37, 0x20, 0x63, 0x63, 0x6d, 0x20, 0x66, 0x69, 0x72, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x37, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x37, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x20, 0x70, 0x6c, 0x69, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x32, 0x37, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2d, 0x61, 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x3d, 0x31, 0x3b, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6d, 0x6f, 0x64, 0x65, 0x3d, 0x30, 0x3b, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2d, 0x69, 0x64, 0x3d, 0x34, 0x32, 0x30, 0x30, 0x31, 0x66, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x32, 0x31, 0x20, 0x72, 0x74, 0x78, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x32, 0x31, 0x20, 0x61, 0x70, 0x74, 0x3d, 0x31, 0x32, 0x37, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x32, 0x35, 0x20, 0x48, 0x32, 0x36, 0x34, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x35, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x2d, 0x72, 0x65, 0x6d, 0x62, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x35, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x63, 0x63, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x35, 0x20, 0x63, 0x63, 0x6d, 0x20, 0x66, 0x69, 0x72, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x35, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x35, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x20, 0x70, 0x6c, 0x69, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x32, 0x35, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2d, 0x61, 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x3d, 0x31, 0x3b, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6d, 0x6f, 0x64, 0x65, 0x3d, 0x31, 0x3b, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2d, 0x69, 0x64, 0x3d, 0x34, 0x32, 0x65, 0x30, 0x31, 0x66, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x30, 0x37, 0x20, 0x72, 0x74, 0x78, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x30, 0x37, 0x20, 0x61, 0x70, 0x74, 0x3d, 0x31, 0x32, 0x35, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x30, 0x38, 0x20, 0x48, 0x32, 0x36, 0x34, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x38, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x2d, 0x72, 0x65, 0x6d, 0x62, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x38, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x63, 0x63, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x38, 0x20, 0x63, 0x63, 0x6d, 0x20, 0x66, 0x69, 0x72, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x38, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x30, 0x38, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x20, 0x70, 0x6c, 0x69, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x30, 0x38, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2d, 0x61, 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x3d, 0x31, 0x3b, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6d, 0x6f, 0x64, 0x65, 0x3d, 0x30, 0x3b, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2d, 0x69, 0x64, 0x3d, 0x34, 0x32, 0x65, 0x30, 0x31, 0x66, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x30, 0x39, 0x20, 0x72, 0x74, 0x78, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x30, 0x39, 0x20, 0x61, 0x70, 0x74, 0x3d, 0x31, 0x30, 0x38, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x32, 0x34, 0x20, 0x48, 0x32, 0x36, 0x34, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x34, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x2d, 0x72, 0x65, 0x6d, 0x62, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x34, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x63, 0x63, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x34, 0x20, 0x63, 0x63, 0x6d, 0x20, 0x66, 0x69, 0x72, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x34, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x34, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x20, 0x70, 0x6c, 0x69, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x32, 0x34, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2d, 0x61, 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x3d, 0x31, 0x3b, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6d, 0x6f, 0x64, 0x65, 0x3d, 0x31, 0x3b, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2d, 0x69, 0x64, 0x3d, 0x34, 0x64, 0x30, 0x30, 0x33, 0x32, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x32, 0x30, 0x20, 0x72, 0x74, 0x78, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x32, 0x30, 0x20, 0x61, 0x70, 0x74, 0x3d, 0x31, 0x32, 0x34, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x32, 0x33, 0x20, 0x48, 0x32, 0x36, 0x34, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x33, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x2d, 0x72, 0x65, 0x6d, 0x62, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x33, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x63, 0x63, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x33, 0x20, 0x63, 0x63, 0x6d, 0x20, 0x66, 0x69, 0x72, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x33, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x63, 0x70, 0x2d, 0x66, 0x62, 0x3a, 0x31, 0x32, 0x33, 0x20, 0x6e, 0x61, 0x63, 0x6b, 0x20, 0x70, 0x6c, 0x69, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x32, 0x33, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2d, 0x61, 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x3d, 0x31, 0x3b, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6d, 0x6f, 0x64, 0x65, 0x3d, 0x31, 0x3b, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2d, 0x69, 0x64, 0x3d, 0x36, 0x34, 0x30, 0x30, 0x33, 0x32, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x31, 0x39, 0x20, 0x72, 0x74, 0x78, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x31, 0x39, 0x20, 0x61, 0x70, 0x74, 0x3d, 0x31, 0x32, 0x33, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x31, 0x34, 0x20, 0x72, 0x65, 0x64, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x31, 0x35, 0x20, 0x72, 0x74, 0x78, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x66, 0x6d, 0x74, 0x70, 0x3a, 0x31, 0x31, 0x35, 0x20, 0x61, 0x70, 0x74, 0x3d, 0x31, 0x31, 0x34, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x72, 0x74, 0x70, 0x6d, 0x61, 0x70, 0x3a, 0x31, 0x31, 0x36, 0x20, 0x75, 0x6c, 0x70, 0x66, 0x65, 0x63, 0x2f, 0x39, 0x30, 0x30, 0x30, 0x30, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x73, 0x72, 0x63, 0x2d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x3a, 0x46, 0x49, 0x44, 0x20, 0x31, 0x34, 0x34, 0x33, 0x36, 0x34, 0x38, 0x35, 0x32, 0x33, 0x20, 0x31, 0x30, 0x39, 0x31, 0x38, 0x39, 0x32, 0x33, 0x39, 0x39, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x73, 0x72, 0x63, 0x3a, 0x31, 0x34, 0x34, 0x33, 0x36, 0x34, 0x38, 0x35, 0x32, 0x33, 0x20, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x33, 0x4c, 0x75, 0x6d, 0x55, 0x62, 0x6a, 0x6c, 0x70, 0x50, 0x4d, 0x79, 0x77, 0x45, 0x31, 0x52, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x73, 0x72, 0x63, 0x3a, 0x31, 0x34, 0x34, 0x33, 0x36, 0x34, 0x38, 0x35, 0x32, 0x33, 0x20, 0x6d, 0x73, 0x69, 0x64, 0x3a, 0x76, 0x72, 0x79, 0x33, 0x6b, 0x78, 0x38, 0x4f, 0x44, 0x50, 0x77, 0x48, 0x45, 0x55, 0x71, 0x74, 0x67, 0x34, 0x6a, 0x51, 0x65, 0x37, 0x6d, 0x63, 0x4b, 0x5a, 0x58, 0x6d, 0x34, 0x41, 0x6b, 0x79, 0x54, 0x4f, 0x49, 0x42, 0x20, 0x37, 0x63, 0x37, 0x31, 0x37, 0x66, 0x36, 0x39, 0x2d, 0x62, 0x63, 0x33, 0x35, 0x2d, 0x34, 0x30, 0x38, 0x39, 0x2d, 0x38, 0x34, 0x63, 0x65, 0x2d, 0x34, 0x31, 0x65, 0x61, 0x38, 0x65, 0x31, 0x63, 0x34, 0x33, 0x39, 0x31, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x73, 0x72, 0x63, 0x3a, 0x31, 0x34, 0x34, 0x33, 0x36, 0x34, 0x38, 0x35, 0x32, 0x33, 0x20, 0x6d, 0x73, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x76, 0x72, 0x79, 0x33, 0x6b, 0x78, 0x38, 0x4f, 0x44, 0x50, 0x77, 0x48, 0x45, 0x55, 0x71, 0x74, 0x67, 0x34, 0x6a, 0x51, 0x65, 0x37, 0x6d, 0x63, 0x4b, 0x5a, 0x58, 0x6d, 0x34, 0x41, 0x6b, 0x79, 0x54, 0x4f, 0x49, 0x42, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x73, 0x72, 0x63, 0x3a, 0x31, 0x34, 0x34, 0x33, 0x36, 0x34, 0x38, 0x35, 0x32, 0x33, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x37, 0x63, 0x37, 0x31, 0x37, 0x66, 0x36, 0x39, 0x2d, 0x62, 0x63, 0x33, 0x35, 0x2d, 0x34, 0x30, 0x38, 0x39, 0x2d, 0x38, 0x34, 0x63, 0x65, 0x2d, 0x34, 0x31, 0x65, 0x61, 0x38, 0x65, 0x31, 0x63, 0x34, 0x33, 0x39, 0x31, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x73, 0x72, 0x63, 0x3a, 0x31, 0x30, 0x39, 0x31, 0x38, 0x39, 0x32, 0x33, 0x39, 0x39, 0x20, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x33, 0x4c, 0x75, 0x6d, 0x55, 0x62, 0x6a, 0x6c, 0x70, 0x50, 0x4d, 0x79, 0x77, 0x45, 0x31, 0x52, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x73, 0x72, 0x63, 0x3a, 0x31, 0x30, 0x39, 0x31, 0x38, 0x39, 0x32, 0x33, 0x39, 0x39, 0x20, 0x6d, 0x73, 0x69, 0x64, 0x3a, 0x76, 0x72, 0x79, 0x33, 0x6b, 0x78, 0x38, 0x4f, 0x44, 0x50, 0x77, 0x48, 0x45, 0x55, 0x71, 0x74, 0x67, 0x34, 0x6a, 0x51, 0x65, 0x37, 0x6d, 0x63, 0x4b, 0x5a, 0x58, 0x6d, 0x34, 0x41, 0x6b, 0x79, 0x54, 0x4f, 0x49, 0x42, 0x20, 0x37, 0x63, 0x37, 0x31, 0x37, 0x66, 0x36, 0x39, 0x2d, 0x62, 0x63, 0x33, 0x35, 0x2d, 0x34, 0x30, 0x38, 0x39, 0x2d, 0x38, 0x34, 0x63, 0x65, 0x2d, 0x34, 0x31, 0x65, 0x61, 0x38, 0x65, 0x31, 0x63, 0x34, 0x33, 0x39, 0x31, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x73, 0x72, 0x63, 0x3a, 0x31, 0x30, 0x39, 0x31, 0x38, 0x39, 0x32, 0x33, 0x39, 0x39, 0x20, 0x6d, 0x73, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x76, 0x72, 0x79, 0x33, 0x6b, 0x78, 0x38, 0x4f, 0x44, 0x50, 0x77, 0x48, 0x45, 0x55, 0x71, 0x74, 0x67, 0x34, 0x6a, 0x51, 0x65, 0x37, 0x6d, 0x63, 0x4b, 0x5a, 0x58, 0x6d, 0x34, 0x41, 0x6b, 0x79, 0x54, 0x4f, 0x49, 0x42, 0x5c, 0x72, 0x5c, 0x6e, 0x61, 0x3d, 0x73, 0x73, 0x72, 0x63, 0x3a, 0x31, 0x30, 0x39, 0x31, 0x38, 0x39, 0x32, 0x33, 0x39, 0x39, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x37, 0x63, 0x37, 0x31, 0x37, 0x66, 0x36, 0x39, 0x2d, 0x62, 0x63, 0x33, 0x35, 0x2d, 0x34, 0x30, 0x38, 0x39, 0x2d, 0x38, 0x34, 0x63, 0x65, 0x2d, 0x34, 0x31, 0x65, 0x61, 0x38, 0x65, 0x31, 0x63, 0x34, 0x33, 0x39, 0x31, 0x5c, 0x72, 0x5c, 0x6e, 0x22, 0x7d, 0x7d, 0x50, 0x4f, 0x53, 0x54, 0x20, 0x2f, 0x6a, 0x61, 0x6e, 0x75, 0x73, 0x2f, 0x32, 0x35, 0x38, 0x30, 0x34, 0x39, 0x32, 0x38, 0x30, 0x38, 0x36, 0x34, 0x32, 0x39, 0x31, 0x31, 0x39, 0x30, 0x32, 0x2f, 0x34, 0x32, 0x36, 0x38, 0x30, 0x33, 0x37, 0x39, 0x33, 0x30, 0x36, 0x34, 0x39, 0x33, 0x33, 0x36, 0x30, 0x38, 0x36, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x33, 0x33, 0x2e, 0x31, 0x38, 0x2e, 0x34, 0x2e, 0x31, 0x32, 0x33, 0x3a, 0x31, 0x39, 0x38, 0x35, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x47, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x33, 0x35, 0x34, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, 0x69, 0x70, 0x0d, 0x0a, 0x0d, 0x0a, 0x7b, 0x22, 0x6a, 0x61, 0x6e, 0x75, 0x73, 0x22, 0x3a, 0x22, 0x74, 0x72, 0x69, 0x63, 0x6b, 0x6c, 0x65, 0x22, 0x2c, 0x22, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x62, 0x33, 0x31, 0x38, 0x65, 0x30, 0x32, 0x65, 0x32, 0x35, 0x34, 0x39, 0x35, 0x33, 0x30, 0x33, 0x61, 0x66, 0x39, 0x37, 0x66, 0x64, 0x36, 0x38, 0x38, 0x39, 0x35, 0x65, 0x35, 0x30, 0x62, 0x64, 0x22, 0x2c, 0x22, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x30, 0x6f, 0x77, 0x65, 0x67, 0x75, 0x35, 0x6f, 0x74, 0x66, 0x75, 0x30, 0x68, 0x64, 0x67, 0x6e, 0x68, 0x72, 0x6d, 0x6d, 0x76, 0x34, 0x63, 0x30, 0x79, 0x6b, 0x35, 0x67, 0x6e, 0x74, 0x38, 0x39, 0x22, 0x2c, 0x22, 0x72, 0x70, 0x63, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x69, 0x67, 0x22, 0x2c, 0x22, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x73, 0x64, 0x70, 0x4d, 0x4c, 0x69, 0x6e, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x73, 0x64, 0x70, 0x4d, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x22, 0x2c, 0x22, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x22, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x32, 0x35, 0x31, 0x30, 0x36, 0x35, 0x35, 0x31, 0x30, 0x39, 0x20, 0x31, 0x20, 0x75, 0x64, 0x70, 0x20, 0x34, 0x31, 0x38, 0x38, 0x35, 0x36, 0x39, 0x35, 0x20, 0x31, 0x31, 0x2e, 0x31, 0x33, 0x33, 0x2e, 0x31, 0x37, 0x32, 0x2e, 0x32, 0x34, 0x31, 0x20, 0x31, 0x30, 0x38, 0x30, 0x31, 0x20, 0x74, 0x79, 0x70, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x72, 0x61, 0x64, 0x64, 0x72, 0x20, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x20, 0x72, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x30, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x30, 0x20, 0x75, 0x66, 0x72, 0x61, 0x67, 0x20, 0x67, 0x4b, 0x2f, 0x62, 0x20, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2d, 0x69, 0x64, 0x20, 0x31, 0x20, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2d, 0x63, 0x6f, 0x73, 0x74, 0x20, 0x31, 0x30, 0x22, 0x7d, 0x7d }; uint8_t* p = data; MockBufferIO io; SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_REQUEST, false)); if (true) { // First message, 144 header + 315 body. io.append(p, 144 + 315); p += 144 + 315; ISrsHttpMessage* msg = NULL; SrsAutoFree(ISrsHttpMessage, msg); HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); EXPECT_EQ(315, msg->content_length()); string body; HELPER_ASSERT_SUCCESS(msg->body_read_all(body)); EXPECT_EQ(315, (int)body.length()); } if (true) { // Second message, 164 header + 683 body. io.append(p, 164 + 683); p += 164 + 683; ISrsHttpMessage* msg = NULL; SrsAutoFree(ISrsHttpMessage, msg); HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); EXPECT_EQ(683, msg->content_length()); string body; HELPER_ASSERT_SUCCESS(msg->body_read_all(body)); EXPECT_EQ(683, (int)body.length()); } if (true) { // Thrid message, 144 header + 315 body. io.append(p, 144 + 315); p += 144 + 315; ISrsHttpMessage* msg = NULL; SrsAutoFree(ISrsHttpMessage, msg); HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); EXPECT_EQ(315, msg->content_length()); string body; HELPER_ASSERT_SUCCESS(msg->body_read_all(body)); EXPECT_EQ(315, (int)body.length()); } if (true) { // Forth message, 164 header + 255 body. io.append(p, 164 + 255); p += 164 + 255; ISrsHttpMessage* msg = NULL; SrsAutoFree(ISrsHttpMessage, msg); HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); EXPECT_EQ(255, msg->content_length()); string body; HELPER_ASSERT_SUCCESS(msg->body_read_all(body)); EXPECT_EQ(255, (int)body.length()); } if (true) { // Fifth message, 165 header + 6317 body. MockMSegmentsReader r; // First, we got 4k bytes, then got the left bytes, to simulate the network read. r.in_bytes.push_back(string((char*)p, 4096)); p += 4096; r.in_bytes.push_back(string((char*)p, 165 + 6317 - 4096)); p += 165 + 6317 - 4096; ISrsHttpMessage* msg = NULL; SrsAutoFree(ISrsHttpMessage, msg); HELPER_ASSERT_SUCCESS(hp.parse_message(&r, &msg)); EXPECT_EQ(6317, msg->content_length()); string body; HELPER_ASSERT_SUCCESS(msg->body_read_all(body)); EXPECT_EQ(6317, (int)body.length()); } if (true) { // Last message, 164 header + 354 body. io.append(p, 164 + 354); p += 164 + 354; EXPECT_EQ((int)sizeof(data), p - data); ISrsHttpMessage* msg = NULL; SrsAutoFree(ISrsHttpMessage, msg); HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); EXPECT_EQ(354, msg->content_length()); string body; HELPER_ASSERT_SUCCESS(msg->body_read_all(body)); EXPECT_EQ(354, (int)body.length()); } }