From 49049f9592574386dd40eddc16facbae9bf6441f Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Mon, 24 Aug 2026 14:53:48 -0400 Subject: [PATCH 01/23] chore: Merge all downstream wasm tests to prepare for refactoring --- .cspell.config.yaml | 2 + src/test/app/Wasm_test.cpp | 1384 +++++++++- .../all_host_functions/src/lib.rs | 26 +- src/test/app/wasm_fixtures/copyFixtures.py | 17 +- src/test/app/wasm_fixtures/disableFloat.wat | 34 + src/test/app/wasm_fixtures/fib.c | 11 + .../wasm_fixtures/fixture_functions_5k.cpp | 2240 +++++++++++++++++ .../app/wasm_fixtures/fixture_locals_10k.cpp | 2128 ++++++++++++++++ src/test/app/wasm_fixtures/fixtures.cpp | 745 ++++++ src/test/app/wasm_fixtures/fixtures.h | 73 + src/test/app/wasm_fixtures/float_0/Cargo.lock | 171 ++ src/test/app/wasm_fixtures/float_0/Cargo.toml | 21 + src/test/app/wasm_fixtures/float_0/src/lib.rs | 70 + .../app/wasm_fixtures/float_tests/Cargo.lock | 171 ++ .../app/wasm_fixtures/float_tests/Cargo.toml | 21 + .../app/wasm_fixtures/float_tests/src/lib.rs | 1112 ++++++++ src/test/app/wasm_fixtures/infiniteLoop.c | 7 + src/test/app/wasm_fixtures/thousand1_params.c | 264 ++ src/test/app/wasm_fixtures/thousand_params.c | 262 ++ .../wasm_fixtures/wat/custom_page_sizes.wat | 13 + .../app/wasm_fixtures/wat/deep_recursion.wat | 29 + .../app/wasm_fixtures/wat/functions_5k.zip | Bin 0 -> 29665 bytes src/test/app/wasm_fixtures/wat/locals_10k.zip | Bin 0 -> 82559 bytes src/test/app/wasm_fixtures/wat/memory64.wat | 21 + .../wat/memory_end_of_word_over_limit.wat | 28 + .../wat/memory_grow_0_page_more_than_8MB.wat | 29 + .../wasm_fixtures/wat/memory_grow_0_to_1.wat | 26 + .../wat/memory_grow_1_page_more_than_8MB.wat | 29 + .../wasm_fixtures/wat/memory_grow_1_to_0.wat | 33 + .../wat/memory_init_1_page_more_than_8MB.wat | 27 + .../wat/memory_last_byte_of_8MB.wat | 26 + .../wat/memory_negative_address.wat | 23 + .../wat/memory_offset_over_limit.wat | 27 + .../wat/memory_pointer_at_limit.wat | 22 + .../wat/memory_pointer_over_limit.wat | 23 + .../app/wasm_fixtures/wat/multi_memory.wat | 16 + .../app/wasm_fixtures/wat/opc_reserved.wat | 98 + .../wat/proposal_bulk_memory.wat | 25 + .../wat/proposal_extended_const.wat | 15 + .../wat/proposal_float_to_int.wat | 18 + .../wat/proposal_gc_struct_new.wat | 12 + .../wat/proposal_multi_value.wat | 22 + .../wat/proposal_mutable_global.wat | 25 + .../wasm_fixtures/wat/proposal_ref_types.wat | 18 + .../wasm_fixtures/wat/proposal_sign_ext.wat | 18 + .../wasm_fixtures/wat/proposal_stringref.wat | 1 + .../wasm_fixtures/wat/proposal_tail_call.wat | 15 + src/test/app/wasm_fixtures/wat/start_loop.wat | 22 + .../wasm_fixtures/wat/table_0_elements.wat | 10 + .../app/wasm_fixtures/wat/table_2_tables.wat | 24 + .../wasm_fixtures/wat/table_64_elements.wat | 25 + .../wasm_fixtures/wat/table_65_elements.wat | 25 + .../app/wasm_fixtures/wat/table_uint_max.wat | 15 + .../wasm_fixtures/wat/trap_divide_by_0.wat | 15 + .../wat/trap_func_signature_mismatch.wat | 33 + .../wasm_fixtures/wat/trap_int_overflow.wat | 18 + .../app/wasm_fixtures/wat/trap_null_call.wat | 22 + .../wasm_fixtures/wat/trap_unreachable.wat | 12 + .../app/wasm_fixtures/wat/wasi_get_time.wat | 38 + src/test/app/wasm_fixtures/wat/wasi_print.wat | 59 + .../app/wasm_fixtures/wat/wide_arithmetic.wat | 22 + 61 files changed, 9704 insertions(+), 34 deletions(-) create mode 100644 src/test/app/wasm_fixtures/disableFloat.wat create mode 100644 src/test/app/wasm_fixtures/fib.c create mode 100644 src/test/app/wasm_fixtures/fixture_functions_5k.cpp create mode 100644 src/test/app/wasm_fixtures/fixture_locals_10k.cpp create mode 100644 src/test/app/wasm_fixtures/float_0/Cargo.lock create mode 100644 src/test/app/wasm_fixtures/float_0/Cargo.toml create mode 100644 src/test/app/wasm_fixtures/float_0/src/lib.rs create mode 100644 src/test/app/wasm_fixtures/float_tests/Cargo.lock create mode 100644 src/test/app/wasm_fixtures/float_tests/Cargo.toml create mode 100644 src/test/app/wasm_fixtures/float_tests/src/lib.rs create mode 100644 src/test/app/wasm_fixtures/infiniteLoop.c create mode 100644 src/test/app/wasm_fixtures/thousand1_params.c create mode 100644 src/test/app/wasm_fixtures/thousand_params.c create mode 100644 src/test/app/wasm_fixtures/wat/custom_page_sizes.wat create mode 100644 src/test/app/wasm_fixtures/wat/deep_recursion.wat create mode 100644 src/test/app/wasm_fixtures/wat/functions_5k.zip create mode 100644 src/test/app/wasm_fixtures/wat/locals_10k.zip create mode 100644 src/test/app/wasm_fixtures/wat/memory64.wat create mode 100644 src/test/app/wasm_fixtures/wat/memory_end_of_word_over_limit.wat create mode 100644 src/test/app/wasm_fixtures/wat/memory_grow_0_page_more_than_8MB.wat create mode 100644 src/test/app/wasm_fixtures/wat/memory_grow_0_to_1.wat create mode 100644 src/test/app/wasm_fixtures/wat/memory_grow_1_page_more_than_8MB.wat create mode 100644 src/test/app/wasm_fixtures/wat/memory_grow_1_to_0.wat create mode 100644 src/test/app/wasm_fixtures/wat/memory_init_1_page_more_than_8MB.wat create mode 100644 src/test/app/wasm_fixtures/wat/memory_last_byte_of_8MB.wat create mode 100644 src/test/app/wasm_fixtures/wat/memory_negative_address.wat create mode 100644 src/test/app/wasm_fixtures/wat/memory_offset_over_limit.wat create mode 100644 src/test/app/wasm_fixtures/wat/memory_pointer_at_limit.wat create mode 100644 src/test/app/wasm_fixtures/wat/memory_pointer_over_limit.wat create mode 100644 src/test/app/wasm_fixtures/wat/multi_memory.wat create mode 100644 src/test/app/wasm_fixtures/wat/opc_reserved.wat create mode 100644 src/test/app/wasm_fixtures/wat/proposal_bulk_memory.wat create mode 100644 src/test/app/wasm_fixtures/wat/proposal_extended_const.wat create mode 100644 src/test/app/wasm_fixtures/wat/proposal_float_to_int.wat create mode 100644 src/test/app/wasm_fixtures/wat/proposal_gc_struct_new.wat create mode 100644 src/test/app/wasm_fixtures/wat/proposal_multi_value.wat create mode 100644 src/test/app/wasm_fixtures/wat/proposal_mutable_global.wat create mode 100644 src/test/app/wasm_fixtures/wat/proposal_ref_types.wat create mode 100644 src/test/app/wasm_fixtures/wat/proposal_sign_ext.wat create mode 100644 src/test/app/wasm_fixtures/wat/proposal_stringref.wat create mode 100644 src/test/app/wasm_fixtures/wat/proposal_tail_call.wat create mode 100644 src/test/app/wasm_fixtures/wat/start_loop.wat create mode 100644 src/test/app/wasm_fixtures/wat/table_0_elements.wat create mode 100644 src/test/app/wasm_fixtures/wat/table_2_tables.wat create mode 100644 src/test/app/wasm_fixtures/wat/table_64_elements.wat create mode 100644 src/test/app/wasm_fixtures/wat/table_65_elements.wat create mode 100644 src/test/app/wasm_fixtures/wat/table_uint_max.wat create mode 100644 src/test/app/wasm_fixtures/wat/trap_divide_by_0.wat create mode 100644 src/test/app/wasm_fixtures/wat/trap_func_signature_mismatch.wat create mode 100644 src/test/app/wasm_fixtures/wat/trap_int_overflow.wat create mode 100644 src/test/app/wasm_fixtures/wat/trap_null_call.wat create mode 100644 src/test/app/wasm_fixtures/wat/trap_unreachable.wat create mode 100644 src/test/app/wasm_fixtures/wat/wasi_get_time.wat create mode 100644 src/test/app/wasm_fixtures/wat/wasi_print.wat create mode 100644 src/test/app/wasm_fixtures/wat/wide_arithmetic.wat diff --git a/.cspell.config.yaml b/.cspell.config.yaml index 95b457272c..a1b15d3bcf 100644 --- a/.cspell.config.yaml +++ b/.cspell.config.yaml @@ -7,6 +7,8 @@ ignorePaths: - cmake/** - LICENSE.md - .clang-tidy + - src/test/app/wasm_fixtures/**/*.wat + - src/test/app/wasm_fixtures/*.c language: en allowCompoundWords: true # TODO (#6334) ignoreRandomStrings: true diff --git a/src/test/app/Wasm_test.cpp b/src/test/app/Wasm_test.cpp index 939fc815c3..17188ea7ee 100644 --- a/src/test/app/Wasm_test.cpp +++ b/src/test/app/Wasm_test.cpp @@ -1,4 +1,5 @@ #include +#include #ifdef _DEBUG // #define DEBUG_OUTPUT 1 #endif @@ -16,14 +17,32 @@ #include +#include +#include #include +#include #include +#include #include #include -#include +#include namespace xrpl::test { +bool +testGetDataIncrement(); + +using Add_proto = int32_t(int32_t, int32_t); +static wasm_trap_t* +add(HostFunctions&, wasm_val_vec_t const* params, wasm_val_vec_t const* results) +{ + int32_t const val1 = params->data[0].of.i32; + int32_t const val2 = params->data[1].of.i32; + // printf("Host function \"Add\": %d + %d\n", Val1, Val2); + results->data[0] = WASM_I32_VAL(val1 + val2); + return nullptr; +} + std::vector hexToBytes(std::string const& hex) { @@ -31,9 +50,111 @@ hexToBytes(std::string const& hex) return Bytes(ws.begin(), ws.end()); } +template +unsigned +uleb128(IT& it, T val) +{ + unsigned count = 0; + do + { + std::uint8_t byte = val & 0x7f; + val >>= 7; + if (val) + byte |= 0x80; + *it++ = byte; + ++count; + } while (val != 0); + + return count; +} + +template +std::pair +uleb128(IT&& it) +{ + static_assert(sizeof(*it) == 1, "invalid iterator type"); + std::uint64_t val = 0; + std::uint64_t byte = 0; + unsigned shift = 0; + unsigned count = 0; + + do + { + if (shift > (sizeof(std::uint64_t) * 8) - 7) + return {0, 0}; + byte = *it++; + val |= (byte & 0x7F) << shift; + shift += 7; + ++count; + } while (byte >= 0x80); + + return {val, count}; +} + +static std::pair +getSection(Bytes const& module, std::uint8_t n) +{ + static std::uint8_t const kHdr[] = {0x00, 0x61, 0x73, 0x6D}; + static std::uint8_t const kVer[] = {0x01, 0x00, 0x00, 0x00}; + static std::uint8_t const kLastSec = 12; + + // sections: + // 0: "Custom", 1: "Type", 2: "Import", 3: "Function", 4: "Table", 5: "Memory", 6: "Global", + // 7: "Export", 8: "Start", 9: "Element", 10: "Code", 11: "Data", 12: "DataCount" + + if (module.size() < sizeof(kHdr) + sizeof(kVer) + 2) + return {0, 0}; + if (memcmp(module.data(), kHdr, sizeof(kHdr)) != 0) + return {0, 0}; + if (memcmp(module.data() + sizeof(kHdr), kVer, sizeof(kVer)) != 0) + return {0, 0}; + + unsigned pos = sizeof(kHdr) + sizeof(kVer); // sections start + for (; pos < module.size();) + { + auto const start = pos; + std::uint8_t const byte = module[pos++]; + if (byte > kLastSec) + return {0, 0}; + + auto [sz, cnt] = uleb128(module.cbegin() + pos); + if (cnt == 0u) + return {0, 0}; + if (pos + cnt + sz > module.size()) + return {0, 0}; + pos += cnt + sz; + + if (byte == n) + return {start, pos}; + } + return {0, 0}; +} + +static std::optional +runFinishFunction(std::string const& code) +{ + auto& engine = WasmEngine::instance(); + auto const wasm = hexToBytes(code); + HostFunctions hfs; + auto const re = engine.run(wasm, hfs, 10'000'000, escrowFunctionName); + if (re.has_value()) + { + return std::optional(re->result); + } + + return std::nullopt; +} + +static bool +finishFunctionReturns(std::string const& code, int32_t expected) +{ + auto const result = runFinishFunction(code); + return result.has_value() && *result == expected; +} + struct Wasm_test : public beast::unit_test::Suite { - void + static void checkResult( std::expected, WasmTER> re, int32_t expectedResult, @@ -48,6 +169,59 @@ struct Wasm_test : public beast::unit_test::Suite } } + void + testGetDataHelperFunctions() + { + testcase("getData helper functions"); + BEAST_EXPECT(testGetDataIncrement()); + } + + void + testWasmLib() + { + testcase("wasm lib test"); + // clang-format off + /* The WASM module buffer. */ + Bytes const wasm = {/* WASM header */ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + /* Type section */ + 0x01, 0x07, 0x01, + /* function type {i32, i32} -> {i32} */ + 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, + /* Import section */ + 0x02, 0x13, 0x01, + /* module name: "extern" */ + 0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E, + /* extern name: "func-add" */ + 0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64, + /* import desc: func 0 */ + 0x00, 0x00, + /* Function section */ + 0x03, 0x02, 0x01, 0x00, + /* Export section */ + 0x07, 0x0A, 0x01, + /* export name: "addTwo" */ + 0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F, + /* export desc: func 0 */ + 0x00, 0x01, + /* Code section */ + 0x0A, 0x0A, 0x01, + /* code body */ + 0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B}; + // clang-format on + auto& vm = WasmEngine::instance(); + + HostFunctions hfs; + ImportVec imports; + WasmImpFunc(imports, "func-add", add, hfs); + + auto re = vm.run(wasm, hfs, 10'000'000, "addTwo", wasmParams(1234, 5678), imports); + + // if (res) printf("invokeAdd get the result: %d\n", res.value()); + + checkResult(re, 6'912, 59); + } + void testBadWasm() { @@ -56,13 +230,13 @@ struct Wasm_test : public beast::unit_test::Suite using namespace test::jtx; Env const env{*this}; - HostFunctions hfs(env.journal); + HostFunctions const hfs(env.journal); { auto wasm = hexToBytes("00000000"); std::string const funcName("mock_escrow"); - auto re = runEscrowWasm(wasm, hfs, 15, funcName); + auto re = runEscrowWasm(wasm, hfs, 15, funcName, {}); BEAST_EXPECT(!re); } @@ -70,7 +244,7 @@ struct Wasm_test : public beast::unit_test::Suite auto wasm = hexToBytes("00112233445566778899AA"); std::string const funcName("mock_escrow"); - auto const re = preflightEscrowWasm(wasm, env.journal, funcName); + auto const re = preflightEscrowWasm(wasm, hfs, funcName); BEAST_EXPECT(!isTesSuccess(re)); } @@ -91,11 +265,190 @@ struct Wasm_test : public beast::unit_test::Suite "732b087369676e2d6578742b0f7265666572656e63652d74797065732b0a" "6d756c746976616c7565"); - auto const re = preflightEscrowWasm(badWasm, env.journal, escrowFunctionName); + auto const re = preflightEscrowWasm(badWasm, hfs, escrowFunctionName); BEAST_EXPECT(!isTesSuccess(re)); } } + void + testWasmLedgerSqn() + { + testcase("Wasm get ledger sequence"); + + auto ledgerSqnWasm = hexToBytes(kLedgerSqnWasmHex); + + using namespace test::jtx; + + Env env{*this}; + TestLedgerDataProvider hfs(env); + ImportVec imports; + WASM_IMPORT_FUNC2(imports, getLedgerSqn, "ldgr_index", hfs, 33); + auto& engine = WasmEngine::instance(); + + auto re = + engine.run(ledgerSqnWasm, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal); + + checkResult(re, 0, 440); + + env.close(); + env.close(); + + // empty module, throwing exception + re = engine.run({}, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal); + BEAST_EXPECT(!re); + env.close(); + } + + void + testImpExp() + { + testcase("Wasm import/export functions"); + + auto impExpWasm = hexToBytes(kImpExpHex); + + using namespace test::jtx; + + Env env{*this}; + TestLedgerDataProvider hfs(env); + ImportVec imports; + WASM_IMPORT_FUNC2(imports, getLedgerSqn, "get_ledger_sqn", hfs, 33); + WASM_IMPORT_FUNC2(imports, getParentLedgerHash, "get_parent_ledger_hash", hfs, 60); + auto& engine = WasmEngine::instance(); + + // Test exp_func1() - should return 1 + auto re = engine.run(impExpWasm, hfs, 1'000'000, "exp_func1", {}, imports, env.journal); + checkResult(re, 1, 30); + + // Test exp_func2(5) - should return 2 * 5 = 10 + re = engine.run( + impExpWasm, hfs, 1'000'000, "exp_func2", wasmParams(5), imports, env.journal); + checkResult(re, 10, 52); + + // Test test_imports() - should call get_ledger_sqn and get_parent_ledger_hash + re = engine.run(impExpWasm, hfs, 1'000'000, "test_imports", {}, imports, env.journal); + // Should return the ledger sequence number (3 by default in test env) + checkResult(re, 3, 294); + + // Test corrupted import/export sections - invert each byte and expect failure + testcase("Wasm import/export section corruption"); + { + // Import section(#2): bytes [26, 79) - 53 bytes + // Export section(#7): bytes [90, 141) - 51 bytes + auto [importStart, importEnd] = getSection(impExpWasm, 2); + auto [exportStart, exportEnd] = getSection(impExpWasm, 7); + + BEAST_EXPECTS(importStart == 26, std::to_string(importStart)); + BEAST_EXPECTS(importEnd == 79, std::to_string(importEnd)); + BEAST_EXPECTS(exportStart == 90, std::to_string(exportStart)); + BEAST_EXPECTS(exportEnd == 141, std::to_string(exportEnd)); + + auto testInv = [&](unsigned i) { + auto corruptedWasm = impExpWasm; + corruptedWasm[i] = ~corruptedWasm[i]; // Invert byte + + // Try to run any function - should fail due to corruption + auto result = engine.run( + corruptedWasm, hfs, 1'000'000, "exp_func1", {}, imports, env.journal); + BEAST_EXPECT(!result); + }; + + // Test each byte in import section + for (unsigned i = importStart; i < importEnd; ++i) + testInv(i); + + // Test each byte in export section + for (unsigned i = exportStart; i < exportEnd; ++i) + testInv(i); + } + + env.close(); + } + + void + testWasmFib() + { + testcase("Wasm fibo"); + + auto const fibWasm = hexToBytes(kFibWasmHex); + auto& engine = WasmEngine::instance(); + HostFunctions hfs; + + auto const re = engine.run(fibWasm, hfs, 10'000'000, "fib", wasmParams(10)); + + checkResult(re, 55, 1'137); + } + + void + testHFCost() + { + testcase("wasm test host functions cost"); + + using namespace test::jtx; + + Env env(*this); + { + auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex); + + auto& engine = WasmEngine::instance(); + + TestHostFunctions hfs(env); + auto imp = createWasmImport(hfs); + for (auto& i : imp) + i.second.second.gas = 0; + + auto re = engine.run( + allHostFuncWasm, hfs, 1'000'000, escrowFunctionName, {}, imp, env.journal); + + checkResult(re, 1, 30'760); + + env.close(); + } + + env.close(); + env.close(); + env.close(); + env.close(); + env.close(); + + { + auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex); + + auto& engine = WasmEngine::instance(); + + TestHostFunctions hfs(env); + auto const imp = createWasmImport(hfs); + + auto re = engine.run( + allHostFuncWasm, hfs, 1'000'000, escrowFunctionName, {}, imp, env.journal); + + checkResult(re, 1, 48'580); + + env.close(); + } + + // not enough gas + { + auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex); + + auto& engine = WasmEngine::instance(); + + TestHostFunctions hfs(env); + auto const imp = createWasmImport(hfs); + + auto re = + engine.run(allHostFuncWasm, hfs, 200, escrowFunctionName, {}, imp, env.journal); + + if (BEAST_EXPECT(!re)) + { + // Running out of gas now terminates with tecOUT_OF_GAS (was + // previously collapsed into tecFAILED_PROCESSING). + BEAST_EXPECTS(re.error().ter == tecOUT_OF_GAS, transToken(re.error().ter)); + } + + env.close(); + } + } + void testEscrowWasmDN() { @@ -106,32 +459,32 @@ struct Wasm_test : public beast::unit_test::Suite using namespace test::jtx; Env env{*this}; { - TestHostFunctions hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName); + TestHostFunctions const hfs(env); + auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {}); checkResult(re, 1, 48'580); } { // Invalid gas limit (0) should be rejected (boundary condition) - TestHostFunctions hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, -1, escrowFunctionName); + TestHostFunctions const hfs(env); + auto re = runEscrowWasm(allHFWasm, hfs, -1, escrowFunctionName, {}); BEAST_EXPECT(!re.has_value()); BEAST_EXPECT(re.error().ter == temBAD_AMOUNT); } { // Invalid gas limit (-1) should be rejected - TestHostFunctions hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, 0, escrowFunctionName); + TestHostFunctions const hfs(env); + auto re = runEscrowWasm(allHFWasm, hfs, 0, escrowFunctionName, {}); BEAST_EXPECT(!re.has_value()); BEAST_EXPECT(re.error().ter == temBAD_AMOUNT); } { // max() gas - TestHostFunctions hfs(env); + TestHostFunctions const hfs(env); auto re = runEscrowWasm( - allHFWasm, hfs, std::numeric_limits::max(), escrowFunctionName); + allHFWasm, hfs, std::numeric_limits::max(), escrowFunctionName, {}); checkResult(re, 1, 48'580); } @@ -148,8 +501,8 @@ struct Wasm_test : public beast::unit_test::Suite } }; - FieldNotFoundHostFunctions hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName); + FieldNotFoundHostFunctions const hfs(env); + auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {}); checkResult(re, -201, 28'329); } @@ -166,12 +519,143 @@ struct Wasm_test : public beast::unit_test::Suite } }; - OversizedFieldHostFunctions hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName); + OversizedFieldHostFunctions const hfs(env); + auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {}); checkResult(re, -201, 28'329); } + +// This test use log output, so DEBUG_OUTPUT must be disabled. +#ifndef DEBUG_OUTPUT + { // fail because recursion too deep + + auto const deepWasm = hexToBytes(kDeepRecursionHex); + + TestHostFunctionsSink hfs(env); + std::string const funcName(escrowFunctionName); + auto re = runEscrowWasm(deepWasm, hfs, 1'000'000'000, funcName, {}); + BEAST_EXPECT(!re && re.error().ter); + // std::cout << "bad case (deep recursion) result " << re.error() + // << std::endl; + + auto const& sink = hfs.getSink(); + auto countSubstr = [](std::string const& str, std::string const& substr) { + std::size_t pos = 0; + int occurrences = 0; + while ((pos = str.find(substr, pos)) != std::string::npos) + { + occurrences++; + pos += substr.length(); + } + return occurrences; + }; + + auto const s = sink.messages().str(); + BEAST_EXPECT(countSubstr(s, "WASMI Error: failure to call func") == 1); + BEAST_EXPECT(countSubstr(s, "TrapCode(StackOverflow)") > 0); + } +#endif + + { // infinite loop + auto const infiniteLoopWasm = hexToBytes(kInfiniteLoopWasmHex); + std::string const funcName("loop"); + TestHostFunctions const hfs(env); + + // infinite loop should be caught and fail + auto const re = runEscrowWasm(infiniteLoopWasm, hfs, 1'000'000, funcName, {}); + if (BEAST_EXPECT(!re.has_value())) + { + BEAST_EXPECT(re.error().ter == tecOUT_OF_GAS); + } + } + + { + // expected import not provided + auto const lgrSqnWasm = hexToBytes(kLedgerSqnWasmHex); + TestLedgerDataProvider hfs(env); + ImportVec imports; + WASM_IMPORT_FUNC2(imports, getLedgerSqn, "get_ledger_sqn2", hfs); + + auto& engine = WasmEngine::instance(); + + auto re = engine.run( + lgrSqnWasm, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal); + + BEAST_EXPECT(!re); + } + + { + // HF unsync between import and VM + auto const lgrSqnWasm = hexToBytes(kLedgerSqnWasmHex); + TestLedgerDataProvider hfs(env); + TestLedgerDataProvider const hfs2(env); + ImportVec imports; + WASM_IMPORT_FUNC2(imports, getLedgerSqn, "get_ledger_sqn", hfs2); + + auto& engine = WasmEngine::instance(); + + auto re = engine.run( + lgrSqnWasm, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal); + + BEAST_EXPECT(!re); + } + + { + // bad function name + auto const lgrSqnWasm = hexToBytes(kLedgerSqnWasmHex); + TestLedgerDataProvider hfs(env); + ImportVec imports; + WASM_IMPORT_FUNC2(imports, getLedgerSqn, "get_ledger_sqn", hfs); + + auto& engine = WasmEngine::instance(); + auto re = engine.run(lgrSqnWasm, hfs, 1'000'000, "func1", {}, imports, env.journal); + + BEAST_EXPECT(!re); + } } + // TODO: testFloat is disabled until the float fixtures are regenerated. + // + // kFloatTestsWasmHex and kFloat0Hex were built against the old trace ABI, + // where the trace_* host functions returned i32. They now return void, so + // neither module instantiates and both blocks below fail with tecINTERNAL. + // + // Regenerating them is not just a rebuild: float_tests/ and float_0/ are + // still pinned to xrpl-wasm-stdlib @ "renames" and use APIs that no longer + // exist on xrpl-common-stdlib @ "error-and-trace" + // (FLOAT_ROUNDING_MODES_TO_NEAREST became RoundingMode, + // core::locator::Locator moved to fields::locator::Locator, and + // trace_data/DataRepr became trace_float/trace_hex). The fixture sources + // have to be ported first. The expected gas costs below are also stale and + // will need recomputing once the modules run again. + // + // void + // testFloat() + // { + // testcase("float point"); + // + // std::string const funcName(escrowFunctionName); + // + // using namespace test::jtx; + // + // Env env(*this); + // { + // auto const floatTestWasm = hexToBytes(kFloatTestsWasmHex); + // + // TestHostFunctions hfs(env); + // auto re = runEscrowWasm(floatTestWasm, hfs, 200'000, funcName, + // {}); checkResult(re, 1, 134'402); env.close(); + // } + // + // { + // auto const float0Wasm = hexToBytes(kFloat0Hex); + // + // TestHostFunctions hfs(env); + // auto re = runEscrowWasm(float0Wasm, hfs, 100'000, funcName, {}); + // checkResult(re, 1, 2'775); + // env.close(); + // } + // } + void testCodecovWasm() { @@ -182,14 +666,286 @@ struct Wasm_test : public beast::unit_test::Suite Env env{*this}; auto const codecovWasm = hexToBytes(kCodecovTestsWasmHex); - TestHostFunctions hfs(env); + TestHostFunctions const hfs(env); auto const allowance = 125'667; - auto re = runEscrowWasm(codecovWasm, hfs, allowance, escrowFunctionName); + auto re = runEscrowWasm(codecovWasm, hfs, allowance, escrowFunctionName, {}); checkResult(re, 1, allowance); } + void + testDisabledFloat() + { + testcase("disabled float"); + + using namespace test::jtx; + Env env{*this}; + + auto disabledFloatWasm = hexToBytes(kDisabledFloatHex); + std::string const funcName(escrowFunctionName); + TestHostFunctions const hfs(env); + + { + // f32 set constant, opcode disabled exception + auto const re = runEscrowWasm(disabledFloatWasm, hfs, 1'000'000, funcName, {}); + if (BEAST_EXPECT(!re.has_value())) + { + BEAST_EXPECT(re.error().ter == tecFAILED_PROCESSING); + } + } + + { + // f32 add, can't create module exception + disabledFloatWasm[0x11e] = 0x92; + auto const re = runEscrowWasm(disabledFloatWasm, hfs, 1'000'000, funcName, {}); + if (BEAST_EXPECT(!re.has_value())) + { + BEAST_EXPECT(re.error().ter == tecFAILED_PROCESSING); + } + } + } + + void + testWasmMemory() + { + testcase("Wasm additional memory limit tests"); + BEAST_EXPECT(finishFunctionReturns(kMemoryPointerAtLimitHex, 1)); + BEAST_EXPECT(!runFinishFunction(kMemoryPointerOverLimitHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kMemoryOffsetOverLimitHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kMemoryEndOfWordOverLimitHex).has_value()); + BEAST_EXPECT(finishFunctionReturns(kMemoryGrow0To1PageHex, 1)); + BEAST_EXPECT(finishFunctionReturns(kMemoryGrow1To0PageHex, -1)); + BEAST_EXPECT(finishFunctionReturns(kMemoryLastByteOf8MbHex, 1)); + BEAST_EXPECT(finishFunctionReturns(kMemoryGrow1MoreThan8MbHex, -1)); + BEAST_EXPECT(finishFunctionReturns(kMemoryGrow0MoreThan8MbHex, 1)); + BEAST_EXPECT(!runFinishFunction(kMemoryInit1MoreThan8MbHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kMemoryNegativeAddressHex).has_value()); + } + + void + testWasmTable() + { + testcase("Wasm table limit tests"); + BEAST_EXPECT(finishFunctionReturns(kTable64ElementsHex, 1)); + BEAST_EXPECT(!runFinishFunction(kTable65ElementsHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kTable2TablesHex).has_value()); + BEAST_EXPECT(finishFunctionReturns(kTable0ElementsHex, 1)); + BEAST_EXPECT(!runFinishFunction(kTableUintMaxHex).has_value()); + } + + void + testWasmProposal() + { + testcase("Wasm disabled proposal tests"); + BEAST_EXPECT(!runFinishFunction(kProposalMutableGlobalHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kProposalGcStructNewHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kProposalMultiValueHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kProposalSignExtHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kProposalFloatToIntHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kProposalBulkMemoryHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kProposalRefTypesHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kProposalTailCallHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kProposalExtendedConstHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kProposalMultiMemoryHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kProposalCustomPageSizesHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kProposalMemory64Hex).has_value()); + BEAST_EXPECT(!runFinishFunction(kProposalWideArithmeticHex).has_value()); + } + + void + testWasmTrap() + { + testcase("Wasm trap tests"); + BEAST_EXPECT(!runFinishFunction(kTrapDivideBy0Hex).has_value()); + BEAST_EXPECT(!runFinishFunction(kTrapIntOverflowHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kTrapUnreachableHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kTrapNullCallHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kTrapFuncSigMismatchHex).has_value()); + } + + void + testWasmWasi() + { + testcase("Wasm Wasi tests"); + BEAST_EXPECT(!runFinishFunction(kWasiGetTimeHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kWasiPrintHex).has_value()); + } + + void + testWasmSectionCorruption() + { + testcase("Wasm Section Corruption tests"); + BEAST_EXPECT(!runFinishFunction(kBadMagicNumberHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kBadVersionNumberHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kLyingHeaderHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kNeverEndingNumberHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kVectorLieHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kSectionOrderingHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kGhostPayloadHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kJunkAfterSectionHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kInvalidSectionIdHex).has_value()); + BEAST_EXPECT(!runFinishFunction(kLocalVariableBombHex).has_value()); + } + + void + testStartFunctionLoop() + { + testcase("infinite loop in start function"); + + using namespace test::jtx; + Env env(*this); + + auto const startLoopWasm = hexToBytes(kStartLoopHex); + TestLedgerDataProvider hfs(env); + ImportVec const imports; + + auto& engine = WasmEngine::instance(); + auto checkRes = + engine.check(startLoopWasm, hfs, escrowFunctionName, {}, imports, env.journal); + BEAST_EXPECTS(checkRes == tesSUCCESS, transToken(checkRes)); + + auto result = + engine.run(startLoopWasm, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal); + auto resultTer = result.error().ter; + BEAST_EXPECTS(resultTer == tecFAILED_PROCESSING, transToken(resultTer)); + } + + void + testBadAlign() + { + testcase("Wasm Bad Align"); + + // bad_align.c + auto const badAlignWasm = hexToBytes(kBadAlignWasmHex); + + using namespace test::jtx; + + Env env{*this}; + TestHostFunctions hfs(env); + auto imports = createWasmImport(hfs); + + { // Calls float_from_uint with bad alignment. + // Can be checked through codecov + auto& engine = WasmEngine::instance(); + + auto re = engine.run(badAlignWasm, hfs, 1'000'000, "test", {}, imports, env.journal); + if (BEAST_EXPECTS(re, transToken(re.error().ter))) + { + BEAST_EXPECTS(re->result == 0x47308594, std::to_string(re->result)); + } + } + + env.close(); + } + + void + testReturnType() + { + using namespace test::jtx; + Env env(*this); + TestHostFunctions hfs(env); + + testcase("Wasm invalid return type"); + + // return int64. + { // (module + // (memory (export "memory") 1) + // (func (export "finish") (result i64) + // i64.const 0x100000000)) + auto const wasmHex = + "0061736d010000000105016000017e030201000503010001" + "071302066d656d6f727902000666696e69736800000a0a01" + "08004280808080100b"; + auto const wasm = hexToBytes(wasmHex); + auto const re = runEscrowWasm(wasm, hfs, 100'000, escrowFunctionName, {}); + BEAST_EXPECT(!re); + } + + // return void. wasmi return execution error + { //(module + // (type (;0;) (func)) + // (func (;0;) (type 0) + // return) + // (memory (;0;) 1) + // (export "memory" (memory 0)) + // (export "finish" (func 0))) + auto const wasmHex = + "0061736d01000000010401600000030201000503010001071302066d656d6f" + "727902000666696e69736800000a050103000f0b"; + auto const wasm = hexToBytes(wasmHex); + auto const re = runEscrowWasm(wasm, hfs, 100'000, escrowFunctionName, {}); + BEAST_EXPECT(!re); + } + + // return i32, i32. wasmi doesn't create module + { //(module + // (memory (export "memory") 1) + // (func (export "finish") (result i32 i32) + // i32.const 0x10000000 + // i32.const 0x100000FF)) + auto const wasmHex = + "0061736d010000000106016000027f7f030201000503010001071302066d65" + "6d6f727902000666696e69736800000a10010e0041808080800141ff818080" + "010b"; + auto const wasm = hexToBytes(wasmHex); + auto const re = runEscrowWasm(wasm, hfs, 100'000, escrowFunctionName, {}); + BEAST_EXPECT(!re); + } + } + + void + testParameterType() + { + using namespace test::jtx; + Env env(*this); + TestHostFunctions hfs(env); + + testcase("Wasm invalid params"); + + // (module + // (memory (export "memory") 1) + // (func $test1 (export "test1") (param i32) (result i32) + // i32.const 1000) + // (func $test2 (export "test2") (param i32 i32) (result i32) + // i32.const 1001)) + auto const wasmHex = + "0061736d01000000010c0260017f017f60027f7f017f03030200010503010001071a03066d656d6f727902" + "00057465737431000005746573743200010a0d02050041e8070b050041e9070b"; + auto const wasm = hexToBytes(wasmHex); + + // good params, module is working properly + { + auto const re = runEscrowWasm(wasm, hfs, 100'000, "test2", wasmParams(2, 10)); + BEAST_EXPECT(re && re->result == 1001 && re->cost == 37); + } + + // no params + { + auto const re = runEscrowWasm(wasm, hfs, 100'000, "test1", {}); + BEAST_EXPECT(!re); + } + + // more params + { + auto const re = runEscrowWasm(wasm, hfs, 100'000, "test1", wasmParams(0, 1)); + BEAST_EXPECT(!re); + } + + // less params + { + auto const re = runEscrowWasm(wasm, hfs, 100'000, "test2", wasmParams(1)); + BEAST_EXPECT(!re); + } + + // invalid type + { + auto const re = + runEscrowWasm(wasm, hfs, 100'000, "test1", wasmParams(std::int64_t(15))); + BEAST_EXPECT(!re); + } + } + void testSwapBytes() { @@ -244,13 +1000,601 @@ struct Wasm_test : public beast::unit_test::Suite BEAST_EXPECT(b6 == swapDataI16); } + void + testManyParams() + { + testcase("Wasm Many params"); + + auto const params1k = hexToBytes(kThousandParamsHex); + auto const params1k1 = hexToBytes(kThousand1ParamsHex); + + using namespace test::jtx; + + Env env{*this}; + TestHostFunctions hfs(env); + auto imports = createWasmImport(hfs); + + // add 1k parameter (max that wasmi support) + std::vector params; + params.reserve(1000); + for (int i = 0; i < 1000; ++i) + params.push_back({.type = WasmTypes::WtI32, .of = {.i32 = 2 * i}}); + + auto& engine = WasmEngine::instance(); + { + auto re = engine.run(params1k, hfs, 1'000'000, "test", params, imports, env.journal); + BEAST_EXPECT(re && re->result == 999000); + } + + // add 1 more parameter, module can't be created now + params.push_back({.type = WasmTypes::WtI32, .of = {.i32 = 2 * 1000}}); + { + auto re = engine.run(params1k1, hfs, 1'000'000, "test", params, imports, env.journal); + BEAST_EXPECT(!re); + } + + // function that create 10k local variables + auto const locals10k = hexToBytes(kLocals10kHex); + { + auto re = engine.run( + locals10k, hfs, 1'000'000, "test", wasmParams(0, 1), imports, env.journal); + BEAST_EXPECT(re && re->result == 890'489'442); + } + + // module has 5k functions + auto const functions5k = hexToBytes(kFunctions5kHex); + { + auto re = engine.run( + functions5k, hfs, 1'000'000, "test0001", wasmParams(2, 3), imports, env.journal); + BEAST_EXPECT(re && re->result == 5); + } + + env.close(); + } + + void + testOpcodes() + { + using namespace test::jtx; + + unsigned const reserved = 64; + std::uint8_t const nop = 0x01; + std::array const codeMarker = { + nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop}; + auto const opcReserved = hexToBytes(kOpcReservedHex); + + Env env{*this}; + auto& engine = WasmEngine::instance(); + + TestHostFunctions hfs(env); + auto imports = createWasmImport(hfs); + env.close(); + + { + auto run = [&](std::vector const& code, + bool good = false, + int64_t cost = -1, + std::source_location const location = std::source_location::current()) { + auto const lineStr = " (" + std::to_string(location.line()) + ")"; + auto re = + engine.run(code, hfs, 1'000'000, "all_instructions", {}, imports, env.journal); + if (BEAST_EXPECTS(re.has_value() == good, transToken(re.error().ter) + lineStr) && + good) + BEAST_EXPECTS(re->cost == cost, std::to_string(re->cost) + lineStr); + }; + + // 1 byte instruction + auto test = [&](std::uint8_t start, + std::uint8_t finish, + bool good = false, + int64_t cost = -1, + std::source_location const location = std::source_location::current()) { + auto const lineStr = " (" + std::to_string(location.line()) + ")"; + auto code = opcReserved; + auto codeRange = std::ranges::search(code, codeMarker); + if (!BEAST_EXPECTS(!codeRange.empty(), lineStr)) + return; + + auto it = codeRange.begin(); + for (std::uint16_t i = start; i <= finish; ++i) + { + *it = i; + run(code, good, cost, location); + } + }; + + // 2 bytes instruction + auto test2 = [&](std::uint8_t major, + std::uint16_t start, + std::uint16_t finish, + bool good = false, + int64_t cost = -1, + std::source_location const location = + std::source_location::current()) { + auto const lineStr = " (" + std::to_string(location.line()) + ")"; + auto code = opcReserved; + auto codeRange = std::ranges::search(code, codeMarker); + if (!BEAST_EXPECTS(!codeRange.empty(), lineStr)) + return; + + auto it = codeRange.begin(); + *it++ = major; + for (std::uint16_t i = start; i <= finish; ++i) + { + auto it2 = it; + uleb128(it2, i); + run(code, good, cost, location); + } + }; + + // multibytes instructions + auto testMB = [&](std::vector const& codeSnap, + bool good = false, + int64_t cost = -1, + std::source_location const location = + std::source_location::current()) { + auto const lineStr = " (" + std::to_string(location.line()) + ")"; + auto code = opcReserved; + auto codeRange = std::ranges::search(code, codeMarker); + if (!BEAST_EXPECTS(!codeRange.empty(), lineStr)) + return; + + if (!BEAST_EXPECTS(codeSnap.size() < reserved, lineStr)) + return; + auto it = codeRange.begin(); + for (auto x : codeSnap) + *it++ = x; + run(code, good, cost, location); + }; + + // normal run + testcase("Wasm reserved opcodes main"); + test(nop, nop, true, 534); + + // reserved main + test(0x06, 0x0A); + test(0x12, 0x19); + test(0x25, 0x27); + test(0xC0, 0xFA); + test(0xFF, 0xFF); + + // reserved gc, string + testcase("Wasm reserved opcodes gc"); + test2(0xFB, 0x00, 0xBF); // not supported by compiler + + // reserved FC + testcase("Wasm reserved opcodes FC"); + test2(0xFC, 0x00, 0x07); // floats, disabled + test2(0xFC, 0x12, 0x1F); + + // reserved SIMD + testcase("Wasm reserved opcodes SIMD"); + test2(0xFD, 0x9A, 0x9A); + test2(0xFD, 0xA2, 0xA2); + test2(0xFD, 0xA5, 0xA6); + test2(0xFD, 0xAF, 0xB0); + test2(0xFD, 0xB2, 0xB4); + test2(0xFD, 0xB8, 0xB8); + test2(0xFD, 0xC2, 0xC2); + test2(0xFD, 0xC5, 0xC6); + test2(0xFD, 0xCF, 0xD0); + test2(0xFD, 0xD2, 0xD4); + test2(0xFD, 0xE2, 0xE2); + test2(0xFD, 0xEE, 0xEE); + test2(0xFD, 0x115, 0x12F); + + testcase("Wasm opcodes THREADS"); + test2(0xFE, 0x00, 0x4F); // not supported by compiler + + // FC mem instructions + testMB({0x41, 0x00, 0x41, 0x00, 0x41, 0x04, 0xFC, 0x08, 0x00, 0x00}); // memory.init + testMB({0xFC, 0x09, 0x00}); // data.drop + testMB({0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0xFC, 0x0A, 0x00, 0x00}); // memory.copy + testMB({0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0xFC, 0x0B, 0x00}); // memory.fill + testMB({0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0xFC, 0x0C, 0x00, 0x00}); // table.init + testMB({0xFC, 0x0D, 0x00}); // elem.drop + testMB({0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0xFC, 0x0E, 0x00, 0x00}); // table.copy + testMB({0xD2, 0x00, 0x41, 0x00, 0xFC, 0x0F, 0x00, 0x1A}); // table.grow + testMB({0x1A, 0xFC, 0x10, 0x00, 0x1A}); // table.size + testMB({0x41, 0x00, 0xD2, 0x00, 0x41, 0x00, 0xFC, 0x11, 0x00}); // table.fill + + testcase("Wasm opcodes SIMD"); + // clang-format off + + // generated by auggie + // SIMD instructions + testMB({0x41, 0x00, 0xFD, 0x00, 0x04, 0x00, 0x1A}); // v128.load + testMB({0x41, 0x00, 0xFD, 0x01, 0x03, 0x00, 0x1A}); // v128.load8x8_s + testMB({0x41, 0x00, 0xFD, 0x02, 0x03, 0x00, 0x1A}); // v128.load8x8_u + testMB({0x41, 0x00, 0xFD, 0x03, 0x03, 0x00, 0x1A}); // v128.load16x4_s + testMB({0x41, 0x00, 0xFD, 0x04, 0x03, 0x00, 0x1A}); // v128.load16x4_u + testMB({0x41, 0x00, 0xFD, 0x05, 0x03, 0x00, 0x1A}); // v128.load32x2_s + testMB({0x41, 0x00, 0xFD, 0x06, 0x03, 0x00, 0x1A}); // v128.load32x2_u + testMB({0x41, 0x00, 0xFD, 0x07, 0x00, 0x00, 0x1A}); // v128.load8_splat + testMB({0x41, 0x00, 0xFD, 0x08, 0x01, 0x00, 0x1A}); // v128.load16_splat + testMB({0x41, 0x00, 0xFD, 0x09, 0x02, 0x00, 0x1A}); // v128.load32_splat + testMB({0x41, 0x00, 0xFD, 0x0A, 0x03, 0x00, 0x1A}); // v128.load64_splat + testMB({0x41, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0B, 0x04, 0x00}); // v128.store + testMB({0xFD, 0x0C, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1A}); // v128.const + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0D, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x1A}); // i8x16.shuffle + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0E, 0x1A}); // i8x16.swizzle + testMB({0x41, 0x2A, 0xFD, 0x0F, 0x1A}); // i8x16.splat + testMB({0x41, 0x2A, 0xFD, 0x10, 0x1A}); // i16x8.splat + testMB({0x41, 0x2A, 0xFD, 0x11, 0x1A}); // i32x4.splat + testMB({0x42, 0x2A, 0xFD, 0x12, 0x1A}); // i64x2.splat + + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x15, 0x00, 0x1A}); // i8x16.extract_lane_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x16, 0x00, 0x1A}); // i8x16.extract_lane_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x2A, 0xFD, 0x17, 0x00, 0x1A}); // i8x16.replace_lane + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x18, 0x00, 0x1A}); // i16x8.extract_lane_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x19, 0x00, 0x1A}); // i16x8.extract_lane_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x2A, 0xFD, 0x1A, 0x00, 0x1A}); // i16x8.replace_lane + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x1B, 0x00, 0x1A}); // i32x4.extract_lane + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x2A, 0xFD, 0x1C, 0x00, 0x1A}); // i32x4.replace_lane + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x1D, 0x00, 0x1A}); // i64x2.extract_lane + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x2A, 0xFD, 0x1E, 0x00, 0x1A}); // i64x2.replace_lane + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x1F, 0x00, 0x1A}); // f32x4.extract_lane + testMB( + {0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x80, 0x3F, 0xFD, 0x20, 0x00, 0x1A}); // f32x4.replace_lane + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x21, 0x00, 0x1A}); // f64x2.extract_lane + testMB( + {0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0xFD, 0x22, 0x00, 0x1A}); // f64x2.replace_lane + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x23, 0x1A}); // i8x16.eq + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x24, 0x1A}); // i8x16.ne + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x25, 0x1A}); // i8x16.lt_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x26, 0x1A}); // i8x16.lt_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x27, 0x1A}); // i8x16.gt_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x28, 0x1A}); // i8x16.gt_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x29, 0x1A}); // i8x16.le_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x2A, 0x1A}); // i8x16.le_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x2B, 0x1A}); // i8x16.ge_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x2C, 0x1A}); // i8x16.ge_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x2D, 0x1A}); // i16x8.eq + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x2E, 0x1A}); // i16x8.ne + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x2F, 0x1A}); // i16x8.lt_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x30, 0x1A}); // i16x8.lt_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x31, 0x1A}); // i16x8.gt_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x32, 0x1A}); // i16x8.gt_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x33, 0x1A}); // i16x8.le_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x34, 0x1A}); // i16x8.le_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x35, 0x1A}); // i16x8.ge_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x36, 0x1A}); // i16x8.ge_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x37, 0x1A}); // i32x4.eq + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x38, 0x1A}); // i32x4.ne + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x39, 0x1A}); // i32x4.lt_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x3A, 0x1A}); // i32x4.lt_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x3B, 0x1A}); // i32x4.gt_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x3C, 0x1A}); // i32x4.gt_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x3D, 0x1A}); // i32x4.le_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x3E, 0x1A}); // i32x4.le_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x3F, 0x1A}); // i32x4.ge_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x40, 0x1A}); // i32x4.ge_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x4D, 0x1A}); // v128.not + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x4E, 0x1A}); // v128.and + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x4F, 0x1A}); // v128.andnot + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x50, 0x1A}); // v128.or + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x51, 0x1A}); // v128.xor + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x52, 0x1A}); // v128.bitselect + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x53, 0x1A}); // v128.any_true + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x60, 0x1A}); // i8x16.abs + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x61, 0x1A}); // i8x16.neg + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x62, 0x1A}); // i8x16.popcnt + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x63, 0x1A}); // i8x16.all_true + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x64, 0x1A}); // i8x16.bitmask + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0x6B, 0x1A}); // i8x16.shl + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0x6C, 0x1A}); // i8x16.shr_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0x6D, 0x1A}); // i8x16.shr_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x6E, 0x1A}); // i8x16.add + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x6F, 0x1A}); // i8x16.add_sat_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x70, 0x1A}); // i8x16.add_sat_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x71, 0x1A}); // i8x16.sub + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x72, 0x1A}); // i8x16.sub_sat_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x73, 0x1A}); // i8x16.sub_sat_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x76, 0x1A}); // i8x16.min_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x77, 0x1A}); // i8x16.min_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x78, 0x1A}); // i8x16.max_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x79, 0x1A}); // i8x16.max_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x7B, 0x1A}); // i8x16.avgr_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x80, 0x01, 0x1A}); // i16x8.abs + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x81, 0x01, 0x1A}); // i16x8.neg + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x83, 0x01, 0x1A}); // i16x8.all_true + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x84, 0x01, 0x1A}); // i16x8.bitmask + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0x8B, 0x01, 0x1A}); // i16x8.shl + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0x8C, 0x01, 0x1A}); // i16x8.shr_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0x8D, 0x01, 0x1A}); // i16x8.shr_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x8E, 0x01, 0x1A}); // i16x8.add + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x8F, 0x01, 0x1A}); // i16x8.add_sat_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x90, 0x01, 0x1A}); // i16x8.add_sat_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x91, 0x01, 0x1A}); // i16x8.sub + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x92, 0x01, 0x1A}); // i16x8.sub_sat_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x93, 0x01, 0x1A}); // i16x8.sub_sat_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x95, 0x01, 0x1A}); // i16x8.mul + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x96, 0x01, 0x1A}); // i16x8.min_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x97, 0x01, 0x1A}); // i16x8.min_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x98, 0x01, 0x1A}); // i16x8.max_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x99, 0x01, 0x1A}); // i16x8.max_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x9B, 0x01, 0x1A}); // i16x8.avgr_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xA0, 0x01, 0x1A}); // i32x4.abs + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xA1, 0x01, 0x1A}); // i32x4.neg + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xA3, 0x01, 0x1A}); // i32x4.all_true + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xA4, 0x01, 0x1A}); // i32x4.bitmask + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0xAB, 0x01, 0x1A}); // i32x4.shl + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0xAC, 0x01, 0x1A}); // i32x4.shr_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0xAD, 0x01, 0x1A}); // i32x4.shr_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xAE, 0x01, 0x1A}); // i32x4.add + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xB1, 0x01, 0x1A}); // i32x4.sub + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xB5, 0x01, 0x1A}); // i32x4.mul + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xB6, 0x01, 0x1A}); // i32x4.min_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xB7, 0x01, 0x1A}); // i32x4.min_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xB8, 0x01, 0x1A}); // i32x4.max_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xB9, 0x01, 0x1A}); // i32x4.max_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xBA, 0x01, 0x1A}); // i32x4.dot_i16x8_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xC0, 0x01, 0x1A}); // i64x2.abs + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xC1, 0x01, 0x1A}); // i64x2.neg + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xC3, 0x01, 0x1A}); // i64x2.all_true + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xC4, 0x01, 0x1A}); // i64x2.bitmask + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0xCB, 0x01, 0x1A}); // i64x2.shl + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0xCC, 0x01, 0x1A}); // i64x2.shr_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0xCD, 0x01, 0x1A}); // i64x2.shr_u + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xCE, 0x01, 0x1A}); // i64x2.add + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xD1, 0x01, 0x1A}); // i64x2.sub + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xD5, 0x01, 0x1A}); // i64x2.mul + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xD6, 0x01, 0x1A}); // i64x2.eq + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xD7, 0x01, 0x1A}); // i64x2.ne + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xD8, 0x01, 0x1A}); // i64x2.lt_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xD9, 0x01, 0x1A}); // i64x2.gt_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xDA, 0x01, 0x1A}); // i64x2.le_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xDB, 0x01, 0x1A}); // i64x2.ge_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xF8, 0x01, 0x1A}); // i32x4.trunc_sat_f32x4_s + testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xF9, 0x01, 0x1A}); // i32x4.trunc_sat_f32x4_u + + // clang-format on + } + } + void run() override { + using namespace test::jtx; + + testGetDataHelperFunctions(); + testWasmLib(); testBadWasm(); + testWasmLedgerSqn(); + testImpExp(); + + testWasmFib(); + + testHFCost(); testEscrowWasmDN(); + // TODO: re-enable once the float fixtures are regenerated (see above) + // testFloat(); + testCodecovWasm(); + // TODO: broken, fix after Rust re-arch + // testDisabledFloat(); + + testWasmMemory(); + testWasmTable(); + testWasmProposal(); + testWasmTrap(); + testWasmWasi(); + testWasmSectionCorruption(); + + // TODO: broken, fix after Rust re-arch + // testStartFunctionLoop(); + testBadAlign(); + testReturnType(); testSwapBytes(); + testManyParams(); + testParameterType(); + + testOpcodes(); } }; diff --git a/src/test/app/wasm_fixtures/all_host_functions/src/lib.rs b/src/test/app/wasm_fixtures/all_host_functions/src/lib.rs index 586e950e39..a593f3cb83 100644 --- a/src/test/app/wasm_fixtures/all_host_functions/src/lib.rs +++ b/src/test/app/wasm_fixtures/all_host_functions/src/lib.rs @@ -379,7 +379,7 @@ fn test_any_ledger_object_functions() -> i32 { let escrow_finish = EscrowFinish; let account_id = escrow_finish.get_account().unwrap(); - // Test 4.1: cache_ledger_obj() - Cache a ledger object + // Test 4.1: cache_le() - Cache a ledger object let mut keylet_buffer = [0u8; 32]; let keylet_result = unsafe { host::accountroot_id( @@ -402,7 +402,7 @@ fn test_any_ledger_object_functions() -> i32 { if cache_result <= 0 { let _ = trace_num( - "INFO: cache_ledger_obj failed (expected with test fixtures):", + "INFO: cache_le failed (expected with test fixtures):", cache_result as i64, ); // Test fixtures may not contain the account object - this is expected @@ -411,7 +411,7 @@ fn test_any_ledger_object_functions() -> i32 { // Test 4.2-4.5 with invalid slot (should fail gracefully) let mut test_buffer = [0u8; 32]; - // Test get_ledger_obj_field with invalid slot + // Test le_field with invalid slot let field_result = unsafe { host::le_field( 1, @@ -422,12 +422,12 @@ fn test_any_ledger_object_functions() -> i32 { }; if field_result < 0 { let _ = trace_num( - "INFO: get_ledger_obj_field failed as expected (no cached object):", + "INFO: le_field failed as expected (no cached object):", field_result as i64, ); } - // Test get_ledger_obj_nested_field with invalid slot + // Test le_inner_field with invalid slot let locator = [ 0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, ]; // Two int32s in little-endian: [1, 0] @@ -442,16 +442,16 @@ fn test_any_ledger_object_functions() -> i32 { }; if nested_result < 0 { let _ = trace_num( - "INFO: get_ledger_obj_nested_field failed as expected:", + "INFO: le_inner_field failed as expected:", nested_result as i64, ); } - // Test get_ledger_obj_array_len with invalid slot + // Test le_inner_arr_len with invalid slot let array_result = unsafe { host::le_arr_len(1, sfield::Signers.into()) }; if array_result < 0 { let _ = trace_num( - "INFO: get_ledger_obj_array_len failed as expected:", + "INFO: le_inner_arr_len failed as expected:", array_result as i64, ); } @@ -474,7 +474,7 @@ fn test_any_ledger_object_functions() -> i32 { let slot = cache_result; let _ = trace_num("Successfully cached object in slot:", slot as i64); - // Test 4.2: get_ledger_obj_field() - Access field from cached object + // Test 4.2: le_field() - Access field from cached object let mut cached_balance_buffer = [0u8; 8]; let cached_balance_result = unsafe { host::le_field( @@ -487,7 +487,7 @@ fn test_any_ledger_object_functions() -> i32 { if cached_balance_result <= 0 { let _ = trace_num( - "INFO: get_ledger_obj_field(Balance) failed:", + "INFO: le_field(Balance) failed:", cached_balance_result as i64, ); } else if cached_balance_result == 8 { @@ -510,7 +510,7 @@ fn test_any_ledger_object_functions() -> i32 { ); } - // Test 4.3: get_ledger_obj_nested_field() - Nested field from cached object + // Test 4.3: le_inner_field() - Nested field from cached object let locator = [ 0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, ]; // Two int32s in little-endian: [1, 0] @@ -527,7 +527,7 @@ fn test_any_ledger_object_functions() -> i32 { if cached_nested_result < 0 { let _ = trace_num( - "INFO: get_ledger_obj_nested_field not applicable:", + "INFO: le_inner_field not applicable:", cached_nested_result as i64, ); } else { @@ -538,7 +538,7 @@ fn test_any_ledger_object_functions() -> i32 { ); } - // Test 4.4: get_ledger_obj_array_len() - Array length from cached object + // Test 4.4: le_inner_arr_len() - Array length from cached object let cached_array_len = unsafe { host::le_arr_len(slot, sfield::Signers.into()) }; let _ = trace_num( "Cached object Signers array length:", diff --git a/src/test/app/wasm_fixtures/copyFixtures.py b/src/test/app/wasm_fixtures/copyFixtures.py index 8e457b71e2..23d116cbef 100644 --- a/src/test/app/wasm_fixtures/copyFixtures.py +++ b/src/test/app/wasm_fixtures/copyFixtures.py @@ -185,13 +185,28 @@ def process_c(project_name): def wat_to_wasm(wat_path, wasm_path): - build_cmd = ["wat2wasm", wat_path, "-o", wasm_path] + build_cmd = ["wat2wasm", "--enable-all", wat_path, "-o", wasm_path] try: subprocess.run(build_cmd, check=True) print(f"WASM file for {os.path.basename(wat_path)} has been built.") + return except FileNotFoundError: print("exec error: wat2wasm is required to build WAT fixtures") sys.exit(1) + except subprocess.CalledProcessError: + # wat2wasm (wabt) does not support some proposal text syntax such as + # the GC instructions, so fall back to wasm-tools which does. + pass + + fallback_cmd = ["wasm-tools", "parse", wat_path, "-o", wasm_path] + try: + subprocess.run(fallback_cmd, check=True) + print( + f"WASM file for {os.path.basename(wat_path)} has been built with wasm-tools." + ) + except FileNotFoundError: + print("exec error: wasm-tools is required to build this WAT fixture") + sys.exit(1) except subprocess.CalledProcessError as e: print(f"exec error: {e}") sys.exit(1) diff --git a/src/test/app/wasm_fixtures/disableFloat.wat b/src/test/app/wasm_fixtures/disableFloat.wat new file mode 100644 index 0000000000..5e09371ee9 --- /dev/null +++ b/src/test/app/wasm_fixtures/disableFloat.wat @@ -0,0 +1,34 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (func (;0;) (type 0)) + (func (;1;) (type 1) (result i32) + f32.const -2048 + f32.const 2050 + f32.sub + drop + i32.const 1) + (memory (;0;) 2) + (global (;0;) i32 (i32.const 1024)) + (global (;1;) i32 (i32.const 1024)) + (global (;2;) i32 (i32.const 2048)) + (global (;3;) i32 (i32.const 2048)) + (global (;4;) i32 (i32.const 67584)) + (global (;5;) i32 (i32.const 1024)) + (global (;6;) i32 (i32.const 67584)) + (global (;7;) i32 (i32.const 131072)) + (global (;8;) i32 (i32.const 0)) + (global (;9;) i32 (i32.const 1)) + (export "memory" (memory 0)) + (export "__wasm_call_ctors" (func 0)) + (export "escrow_finish" (func 1)) + (export "buf" (global 0)) + (export "__dso_handle" (global 1)) + (export "__data_end" (global 2)) + (export "__stack_low" (global 3)) + (export "__stack_high" (global 4)) + (export "__global_base" (global 5)) + (export "__heap_base" (global 6)) + (export "__heap_end" (global 7)) + (export "__memory_base" (global 8)) + (export "__table_base" (global 9))) diff --git a/src/test/app/wasm_fixtures/fib.c b/src/test/app/wasm_fixtures/fib.c new file mode 100644 index 0000000000..e45cc4fe6c --- /dev/null +++ b/src/test/app/wasm_fixtures/fib.c @@ -0,0 +1,11 @@ +// typedef long long mint; +typedef int mint; + +mint fib(mint n) +{ + if (!n) + return 0; + if (n <= 2) + return 1; + return fib(n - 1) + fib(n - 2); +} diff --git a/src/test/app/wasm_fixtures/fixture_functions_5k.cpp b/src/test/app/wasm_fixtures/fixture_functions_5k.cpp new file mode 100644 index 0000000000..d65f602eec --- /dev/null +++ b/src/test/app/wasm_fixtures/fixture_functions_5k.cpp @@ -0,0 +1,2240 @@ +// TODO: consider moving these to separate files (and figure out the build) + +#include + +#include + +extern std::string const kFunctions5kHex = + "0061736d0100000001070160027f7f017f038a27882700000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000007e2d303882708" + "7465737430303030000008746573743030303100010874657374303030320002087465737430303033000308746573" + "7430303034000408746573743030303500050874657374303030360006087465737430303037000708746573743030" + "303800080874657374303030390009087465737430303130000a087465737430303131000b08746573743030313200" + "0c087465737430303133000d087465737430303134000e087465737430303135000f08746573743030313600100874" + "6573743030313700110874657374303031380012087465737430303139001308746573743030323000140874657374" + "3030323100150874657374303032320016087465737430303233001708746573743030323400180874657374303032" + "350019087465737430303236001a087465737430303237001b087465737430303238001c087465737430303239001d" + "087465737430303330001e087465737430303331001f08746573743030333200200874657374303033330021087465" + "7374303033340022087465737430303335002308746573743030333600240874657374303033370025087465737430" + "3033380026087465737430303339002708746573743030343000280874657374303034310029087465737430303432" + "002a087465737430303433002b087465737430303434002c087465737430303435002d087465737430303436002e08" + "7465737430303437002f08746573743030343800300874657374303034390031087465737430303530003208746573" + "7430303531003308746573743030353200340874657374303035330035087465737430303534003608746573743030" + "3535003708746573743030353600380874657374303035370039087465737430303538003a08746573743030353900" + "3b087465737430303630003c087465737430303631003d087465737430303632003e087465737430303633003f0874" + "6573743030363400400874657374303036350041087465737430303636004208746573743030363700430874657374" + "3030363800440874657374303036390045087465737430303730004608746573743030373100470874657374303037" + "3200480874657374303037330049087465737430303734004a087465737430303735004b087465737430303736004c" + "087465737430303737004d087465737430303738004e087465737430303739004f0874657374303038300050087465" + "7374303038310051087465737430303832005208746573743030383300530874657374303038340054087465737430" + "3038350055087465737430303836005608746573743030383700570874657374303038380058087465737430303839" + "0059087465737430303930005a087465737430303931005b087465737430303932005c087465737430303933005d08" + "7465737430303934005e087465737430303935005f0874657374303039360060087465737430303937006108746573" + "7430303938006208746573743030393900630874657374303130300064087465737430313031006508746573743031" + "3032006608746573743031303300670874657374303130340068087465737430313035006908746573743031303600" + "6a087465737430313037006b087465737430313038006c087465737430313039006d087465737430313130006e0874" + "65737430313131006f0874657374303131320070087465737430313133007108746573743031313400720874657374" + "3031313500730874657374303131360074087465737430313137007508746573743031313800760874657374303131" + "39007708746573743031323000780874657374303132310079087465737430313232007a087465737430313233007b" + "087465737430313234007c087465737430313235007d087465737430313236007e087465737430313237007f087465" + "7374303132380080010874657374303132390081010874657374303133300082010874657374303133310083010874" + "6573743031333200840108746573743031333300850108746573743031333400860108746573743031333500870108" + "7465737430313336008801087465737430313337008901087465737430313338008a01087465737430313339008b01" + "087465737430313430008c01087465737430313431008d01087465737430313432008e01087465737430313433008f" + "0108746573743031343400900108746573743031343500910108746573743031343600920108746573743031343700" + "9301087465737430313438009401087465737430313439009501087465737430313530009601087465737430313531" + "009701087465737430313532009801087465737430313533009901087465737430313534009a010874657374303135" + "35009b01087465737430313536009c01087465737430313537009d01087465737430313538009e0108746573743031" + "3539009f0108746573743031363000a00108746573743031363100a10108746573743031363200a201087465737430" + "31363300a30108746573743031363400a40108746573743031363500a50108746573743031363600a6010874657374" + "3031363700a70108746573743031363800a80108746573743031363900a90108746573743031373000aa0108746573" + "743031373100ab0108746573743031373200ac0108746573743031373300ad0108746573743031373400ae01087465" + "73743031373500af0108746573743031373600b00108746573743031373700b10108746573743031373800b2010874" + "6573743031373900b30108746573743031383000b40108746573743031383100b50108746573743031383200b60108" + "746573743031383300b70108746573743031383400b80108746573743031383500b90108746573743031383600ba01" + "08746573743031383700bb0108746573743031383800bc0108746573743031383900bd0108746573743031393000be" + "0108746573743031393100bf0108746573743031393200c00108746573743031393300c10108746573743031393400" + "c20108746573743031393500c30108746573743031393600c40108746573743031393700c501087465737430313938" + "00c60108746573743031393900c70108746573743032303000c80108746573743032303100c9010874657374303230" + "3200ca0108746573743032303300cb0108746573743032303400cc0108746573743032303500cd0108746573743032" + "303600ce0108746573743032303700cf0108746573743032303800d00108746573743032303900d101087465737430" + "32313000d20108746573743032313100d30108746573743032313200d40108746573743032313300d5010874657374" + "3032313400d60108746573743032313500d70108746573743032313600d80108746573743032313700d90108746573" + "743032313800da0108746573743032313900db0108746573743032323000dc0108746573743032323100dd01087465" + "73743032323200de0108746573743032323300df0108746573743032323400e00108746573743032323500e1010874" + "6573743032323600e20108746573743032323700e30108746573743032323800e40108746573743032323900e50108" + "746573743032333000e60108746573743032333100e70108746573743032333200e80108746573743032333300e901" + "08746573743032333400ea0108746573743032333500eb0108746573743032333600ec0108746573743032333700ed" + "0108746573743032333800ee0108746573743032333900ef0108746573743032343000f00108746573743032343100" + "f10108746573743032343200f20108746573743032343300f30108746573743032343400f401087465737430323435" + "00f50108746573743032343600f60108746573743032343700f70108746573743032343800f8010874657374303234" + "3900f90108746573743032353000fa0108746573743032353100fb0108746573743032353200fc0108746573743032" + "353300fd0108746573743032353400fe0108746573743032353500ff01087465737430323536008002087465737430" + "3235370081020874657374303235380082020874657374303235390083020874657374303236300084020874657374" + "3032363100850208746573743032363200860208746573743032363300870208746573743032363400880208746573" + "7430323635008902087465737430323636008a02087465737430323637008b02087465737430323638008c02087465" + "737430323639008d02087465737430323730008e02087465737430323731008f020874657374303237320090020874" + "6573743032373300910208746573743032373400920208746573743032373500930208746573743032373600940208" + "7465737430323737009502087465737430323738009602087465737430323739009702087465737430323830009802" + "087465737430323831009902087465737430323832009a02087465737430323833009b02087465737430323834009c" + "02087465737430323835009d02087465737430323836009e02087465737430323837009f0208746573743032383800" + "a00208746573743032383900a10208746573743032393000a20208746573743032393100a302087465737430323932" + "00a40208746573743032393300a50208746573743032393400a60208746573743032393500a7020874657374303239" + "3600a80208746573743032393700a90208746573743032393800aa0208746573743032393900ab0208746573743033" + "303000ac0208746573743033303100ad0208746573743033303200ae0208746573743033303300af02087465737430" + "33303400b00208746573743033303500b10208746573743033303600b20208746573743033303700b3020874657374" + "3033303800b40208746573743033303900b50208746573743033313000b60208746573743033313100b70208746573" + "743033313200b80208746573743033313300b90208746573743033313400ba0208746573743033313500bb02087465" + "73743033313600bc0208746573743033313700bd0208746573743033313800be0208746573743033313900bf020874" + "6573743033323000c00208746573743033323100c10208746573743033323200c20208746573743033323300c30208" + "746573743033323400c40208746573743033323500c50208746573743033323600c60208746573743033323700c702" + "08746573743033323800c80208746573743033323900c90208746573743033333000ca0208746573743033333100cb" + "0208746573743033333200cc0208746573743033333300cd0208746573743033333400ce0208746573743033333500" + "cf0208746573743033333600d00208746573743033333700d10208746573743033333800d202087465737430333339" + "00d30208746573743033343000d40208746573743033343100d50208746573743033343200d6020874657374303334" + "3300d70208746573743033343400d80208746573743033343500d90208746573743033343600da0208746573743033" + "343700db0208746573743033343800dc0208746573743033343900dd0208746573743033353000de02087465737430" + "33353100df0208746573743033353200e00208746573743033353300e10208746573743033353400e2020874657374" + "3033353500e30208746573743033353600e40208746573743033353700e50208746573743033353800e60208746573" + "743033353900e70208746573743033363000e80208746573743033363100e90208746573743033363200ea02087465" + "73743033363300eb0208746573743033363400ec0208746573743033363500ed0208746573743033363600ee020874" + "6573743033363700ef0208746573743033363800f00208746573743033363900f10208746573743033373000f20208" + "746573743033373100f30208746573743033373200f40208746573743033373300f50208746573743033373400f602" + "08746573743033373500f70208746573743033373600f80208746573743033373700f90208746573743033373800fa" + "0208746573743033373900fb0208746573743033383000fc0208746573743033383100fd0208746573743033383200" + "fe0208746573743033383300ff02087465737430333834008003087465737430333835008103087465737430333836" + "0082030874657374303338370083030874657374303338380084030874657374303338390085030874657374303339" + "3000860308746573743033393100870308746573743033393200880308746573743033393300890308746573743033" + "3934008a03087465737430333935008b03087465737430333936008c03087465737430333937008d03087465737430" + "333938008e03087465737430333939008f030874657374303430300090030874657374303430310091030874657374" + "3034303200920308746573743034303300930308746573743034303400940308746573743034303500950308746573" + "7430343036009603087465737430343037009703087465737430343038009803087465737430343039009903087465" + "737430343130009a03087465737430343131009b03087465737430343132009c03087465737430343133009d030874" + "65737430343134009e03087465737430343135009f0308746573743034313600a00308746573743034313700a10308" + "746573743034313800a20308746573743034313900a30308746573743034323000a40308746573743034323100a503" + "08746573743034323200a60308746573743034323300a70308746573743034323400a80308746573743034323500a9" + "0308746573743034323600aa0308746573743034323700ab0308746573743034323800ac0308746573743034323900" + "ad0308746573743034333000ae0308746573743034333100af0308746573743034333200b003087465737430343333" + "00b10308746573743034333400b20308746573743034333500b30308746573743034333600b4030874657374303433" + "3700b50308746573743034333800b60308746573743034333900b70308746573743034343000b80308746573743034" + "343100b90308746573743034343200ba0308746573743034343300bb0308746573743034343400bc03087465737430" + "34343500bd0308746573743034343600be0308746573743034343700bf0308746573743034343800c0030874657374" + "3034343900c10308746573743034353000c20308746573743034353100c30308746573743034353200c40308746573" + "743034353300c50308746573743034353400c60308746573743034353500c70308746573743034353600c803087465" + "73743034353700c90308746573743034353800ca0308746573743034353900cb0308746573743034363000cc030874" + "6573743034363100cd0308746573743034363200ce0308746573743034363300cf0308746573743034363400d00308" + "746573743034363500d10308746573743034363600d20308746573743034363700d30308746573743034363800d403" + "08746573743034363900d50308746573743034373000d60308746573743034373100d70308746573743034373200d8" + "0308746573743034373300d90308746573743034373400da0308746573743034373500db0308746573743034373600" + "dc0308746573743034373700dd0308746573743034373800de0308746573743034373900df03087465737430343830" + "00e00308746573743034383100e10308746573743034383200e20308746573743034383300e3030874657374303438" + "3400e40308746573743034383500e50308746573743034383600e60308746573743034383700e70308746573743034" + "383800e80308746573743034383900e90308746573743034393000ea0308746573743034393100eb03087465737430" + "34393200ec0308746573743034393300ed0308746573743034393400ee0308746573743034393500ef030874657374" + "3034393600f00308746573743034393700f10308746573743034393800f20308746573743034393900f30308746573" + "743035303000f40308746573743035303100f50308746573743035303200f60308746573743035303300f703087465" + "73743035303400f80308746573743035303500f90308746573743035303600fa0308746573743035303700fb030874" + "6573743035303800fc0308746573743035303900fd0308746573743035313000fe0308746573743035313100ff0308" + "7465737430353132008004087465737430353133008104087465737430353134008204087465737430353135008304" + "0874657374303531360084040874657374303531370085040874657374303531380086040874657374303531390087" + "04087465737430353230008804087465737430353231008904087465737430353232008a0408746573743035323300" + "8b04087465737430353234008c04087465737430353235008d04087465737430353236008e04087465737430353237" + "008f040874657374303532380090040874657374303532390091040874657374303533300092040874657374303533" + "3100930408746573743035333200940408746573743035333300950408746573743035333400960408746573743035" + "3335009704087465737430353336009804087465737430353337009904087465737430353338009a04087465737430" + "353339009b04087465737430353430009c04087465737430353431009d04087465737430353432009e040874657374" + "30353433009f0408746573743035343400a00408746573743035343500a10408746573743035343600a20408746573" + "743035343700a30408746573743035343800a40408746573743035343900a50408746573743035353000a604087465" + "73743035353100a70408746573743035353200a80408746573743035353300a90408746573743035353400aa040874" + "6573743035353500ab0408746573743035353600ac0408746573743035353700ad0408746573743035353800ae0408" + "746573743035353900af0408746573743035363000b00408746573743035363100b10408746573743035363200b204" + "08746573743035363300b30408746573743035363400b40408746573743035363500b50408746573743035363600b6" + "0408746573743035363700b70408746573743035363800b80408746573743035363900b90408746573743035373000" + "ba0408746573743035373100bb0408746573743035373200bc0408746573743035373300bd04087465737430353734" + "00be0408746573743035373500bf0408746573743035373600c00408746573743035373700c1040874657374303537" + "3800c20408746573743035373900c30408746573743035383000c40408746573743035383100c50408746573743035" + "383200c60408746573743035383300c70408746573743035383400c80408746573743035383500c904087465737430" + "35383600ca0408746573743035383700cb0408746573743035383800cc0408746573743035383900cd040874657374" + "3035393000ce0408746573743035393100cf0408746573743035393200d00408746573743035393300d10408746573" + "743035393400d20408746573743035393500d30408746573743035393600d40408746573743035393700d504087465" + "73743035393800d60408746573743035393900d70408746573743036303000d80408746573743036303100d9040874" + "6573743036303200da0408746573743036303300db0408746573743036303400dc0408746573743036303500dd0408" + "746573743036303600de0408746573743036303700df0408746573743036303800e00408746573743036303900e104" + "08746573743036313000e20408746573743036313100e30408746573743036313200e40408746573743036313300e5" + "0408746573743036313400e60408746573743036313500e70408746573743036313600e80408746573743036313700" + "e90408746573743036313800ea0408746573743036313900eb0408746573743036323000ec04087465737430363231" + "00ed0408746573743036323200ee0408746573743036323300ef0408746573743036323400f0040874657374303632" + "3500f10408746573743036323600f20408746573743036323700f30408746573743036323800f40408746573743036" + "323900f50408746573743036333000f60408746573743036333100f70408746573743036333200f804087465737430" + "36333300f90408746573743036333400fa0408746573743036333500fb0408746573743036333600fc040874657374" + "3036333700fd0408746573743036333800fe0408746573743036333900ff0408746573743036343000800508746573" + "7430363431008105087465737430363432008205087465737430363433008305087465737430363434008405087465" + "7374303634350085050874657374303634360086050874657374303634370087050874657374303634380088050874" + "65737430363439008905087465737430363530008a05087465737430363531008b05087465737430363532008c0508" + "7465737430363533008d05087465737430363534008e05087465737430363535008f05087465737430363536009005" + "0874657374303635370091050874657374303635380092050874657374303635390093050874657374303636300094" + "0508746573743036363100950508746573743036363200960508746573743036363300970508746573743036363400" + "9805087465737430363635009905087465737430363636009a05087465737430363637009b05087465737430363638" + "009c05087465737430363639009d05087465737430363730009e05087465737430363731009f050874657374303637" + "3200a00508746573743036373300a10508746573743036373400a20508746573743036373500a30508746573743036" + "373600a40508746573743036373700a50508746573743036373800a60508746573743036373900a705087465737430" + "36383000a80508746573743036383100a90508746573743036383200aa0508746573743036383300ab050874657374" + "3036383400ac0508746573743036383500ad0508746573743036383600ae0508746573743036383700af0508746573" + "743036383800b00508746573743036383900b10508746573743036393000b20508746573743036393100b305087465" + "73743036393200b40508746573743036393300b50508746573743036393400b60508746573743036393500b7050874" + "6573743036393600b80508746573743036393700b90508746573743036393800ba0508746573743036393900bb0508" + "746573743037303000bc0508746573743037303100bd0508746573743037303200be0508746573743037303300bf05" + "08746573743037303400c00508746573743037303500c10508746573743037303600c20508746573743037303700c3" + "0508746573743037303800c40508746573743037303900c50508746573743037313000c60508746573743037313100" + "c70508746573743037313200c80508746573743037313300c90508746573743037313400ca05087465737430373135" + "00cb0508746573743037313600cc0508746573743037313700cd0508746573743037313800ce050874657374303731" + "3900cf0508746573743037323000d00508746573743037323100d10508746573743037323200d20508746573743037" + "323300d30508746573743037323400d40508746573743037323500d50508746573743037323600d605087465737430" + "37323700d70508746573743037323800d80508746573743037323900d90508746573743037333000da050874657374" + "3037333100db0508746573743037333200dc0508746573743037333300dd0508746573743037333400de0508746573" + "743037333500df0508746573743037333600e00508746573743037333700e10508746573743037333800e205087465" + "73743037333900e30508746573743037343000e40508746573743037343100e50508746573743037343200e6050874" + "6573743037343300e70508746573743037343400e80508746573743037343500e90508746573743037343600ea0508" + "746573743037343700eb0508746573743037343800ec0508746573743037343900ed0508746573743037353000ee05" + "08746573743037353100ef0508746573743037353200f00508746573743037353300f10508746573743037353400f2" + "0508746573743037353500f30508746573743037353600f40508746573743037353700f50508746573743037353800" + "f60508746573743037353900f70508746573743037363000f80508746573743037363100f905087465737430373632" + "00fa0508746573743037363300fb0508746573743037363400fc0508746573743037363500fd050874657374303736" + "3600fe0508746573743037363700ff0508746573743037363800800608746573743037363900810608746573743037" + "3730008206087465737430373731008306087465737430373732008406087465737430373733008506087465737430" + "3737340086060874657374303737350087060874657374303737360088060874657374303737370089060874657374" + "30373738008a06087465737430373739008b06087465737430373830008c06087465737430373831008d0608746573" + "7430373832008e06087465737430373833008f06087465737430373834009006087465737430373835009106087465" + "7374303738360092060874657374303738370093060874657374303738380094060874657374303738390095060874" + "6573743037393000960608746573743037393100970608746573743037393200980608746573743037393300990608" + "7465737430373934009a06087465737430373935009b06087465737430373936009c06087465737430373937009d06" + "087465737430373938009e06087465737430373939009f0608746573743038303000a00608746573743038303100a1" + "0608746573743038303200a20608746573743038303300a30608746573743038303400a40608746573743038303500" + "a50608746573743038303600a60608746573743038303700a70608746573743038303800a806087465737430383039" + "00a90608746573743038313000aa0608746573743038313100ab0608746573743038313200ac060874657374303831" + "3300ad0608746573743038313400ae0608746573743038313500af0608746573743038313600b00608746573743038" + "313700b10608746573743038313800b20608746573743038313900b30608746573743038323000b406087465737430" + "38323100b50608746573743038323200b60608746573743038323300b70608746573743038323400b8060874657374" + "3038323500b90608746573743038323600ba0608746573743038323700bb0608746573743038323800bc0608746573" + "743038323900bd0608746573743038333000be0608746573743038333100bf0608746573743038333200c006087465" + "73743038333300c10608746573743038333400c20608746573743038333500c30608746573743038333600c4060874" + "6573743038333700c50608746573743038333800c60608746573743038333900c70608746573743038343000c80608" + "746573743038343100c90608746573743038343200ca0608746573743038343300cb0608746573743038343400cc06" + "08746573743038343500cd0608746573743038343600ce0608746573743038343700cf0608746573743038343800d0" + "0608746573743038343900d10608746573743038353000d20608746573743038353100d30608746573743038353200" + "d40608746573743038353300d50608746573743038353400d60608746573743038353500d706087465737430383536" + "00d80608746573743038353700d90608746573743038353800da0608746573743038353900db060874657374303836" + "3000dc0608746573743038363100dd0608746573743038363200de0608746573743038363300df0608746573743038" + "363400e00608746573743038363500e10608746573743038363600e20608746573743038363700e306087465737430" + "38363800e40608746573743038363900e50608746573743038373000e60608746573743038373100e7060874657374" + "3038373200e80608746573743038373300e90608746573743038373400ea0608746573743038373500eb0608746573" + "743038373600ec0608746573743038373700ed0608746573743038373800ee0608746573743038373900ef06087465" + "73743038383000f00608746573743038383100f10608746573743038383200f20608746573743038383300f3060874" + "6573743038383400f40608746573743038383500f50608746573743038383600f60608746573743038383700f70608" + "746573743038383800f80608746573743038383900f90608746573743038393000fa0608746573743038393100fb06" + "08746573743038393200fc0608746573743038393300fd0608746573743038393400fe0608746573743038393500ff" + "0608746573743038393600800708746573743038393700810708746573743038393800820708746573743038393900" + "8307087465737430393030008407087465737430393031008507087465737430393032008607087465737430393033" + "008707087465737430393034008807087465737430393035008907087465737430393036008a070874657374303930" + "37008b07087465737430393038008c07087465737430393039008d07087465737430393130008e0708746573743039" + "3131008f07087465737430393132009007087465737430393133009107087465737430393134009207087465737430" + "3931350093070874657374303931360094070874657374303931370095070874657374303931380096070874657374" + "30393139009707087465737430393230009807087465737430393231009907087465737430393232009a0708746573" + "7430393233009b07087465737430393234009c07087465737430393235009d07087465737430393236009e07087465" + "737430393237009f0708746573743039323800a00708746573743039323900a10708746573743039333000a2070874" + "6573743039333100a30708746573743039333200a40708746573743039333300a50708746573743039333400a60708" + "746573743039333500a70708746573743039333600a80708746573743039333700a90708746573743039333800aa07" + "08746573743039333900ab0708746573743039343000ac0708746573743039343100ad0708746573743039343200ae" + "0708746573743039343300af0708746573743039343400b00708746573743039343500b10708746573743039343600" + "b20708746573743039343700b30708746573743039343800b40708746573743039343900b507087465737430393530" + "00b60708746573743039353100b70708746573743039353200b80708746573743039353300b9070874657374303935" + "3400ba0708746573743039353500bb0708746573743039353600bc0708746573743039353700bd0708746573743039" + "353800be0708746573743039353900bf0708746573743039363000c00708746573743039363100c107087465737430" + "39363200c20708746573743039363300c30708746573743039363400c40708746573743039363500c5070874657374" + "3039363600c60708746573743039363700c70708746573743039363800c80708746573743039363900c90708746573" + "743039373000ca0708746573743039373100cb0708746573743039373200cc0708746573743039373300cd07087465" + "73743039373400ce0708746573743039373500cf0708746573743039373600d00708746573743039373700d1070874" + "6573743039373800d20708746573743039373900d30708746573743039383000d40708746573743039383100d50708" + "746573743039383200d60708746573743039383300d70708746573743039383400d80708746573743039383500d907" + "08746573743039383600da0708746573743039383700db0708746573743039383800dc0708746573743039383900dd" + "0708746573743039393000de0708746573743039393100df0708746573743039393200e00708746573743039393300" + "e10708746573743039393400e20708746573743039393500e30708746573743039393600e407087465737430393937" + "00e50708746573743039393800e60708746573743039393900e70708746573743130303000e8070874657374313030" + "3100e90708746573743130303200ea0708746573743130303300eb0708746573743130303400ec0708746573743130" + "303500ed0708746573743130303600ee0708746573743130303700ef0708746573743130303800f007087465737431" + "30303900f10708746573743130313000f20708746573743130313100f30708746573743130313200f4070874657374" + "3130313300f50708746573743130313400f60708746573743130313500f70708746573743130313600f80708746573" + "743130313700f90708746573743130313800fa0708746573743130313900fb0708746573743130323000fc07087465" + "73743130323100fd0708746573743130323200fe0708746573743130323300ff070874657374313032340080080874" + "6573743130323500810808746573743130323600820808746573743130323700830808746573743130323800840808" + "7465737431303239008508087465737431303330008608087465737431303331008708087465737431303332008808" + "087465737431303333008908087465737431303334008a08087465737431303335008b08087465737431303336008c" + "08087465737431303337008d08087465737431303338008e08087465737431303339008f0808746573743130343000" + "9008087465737431303431009108087465737431303432009208087465737431303433009308087465737431303434" + "0094080874657374313034350095080874657374313034360096080874657374313034370097080874657374313034" + "38009808087465737431303439009908087465737431303530009a08087465737431303531009b0808746573743130" + "3532009c08087465737431303533009d08087465737431303534009e08087465737431303535009f08087465737431" + "30353600a00808746573743130353700a10808746573743130353800a20808746573743130353900a3080874657374" + "3130363000a40808746573743130363100a50808746573743130363200a60808746573743130363300a70808746573" + "743130363400a80808746573743130363500a90808746573743130363600aa0808746573743130363700ab08087465" + "73743130363800ac0808746573743130363900ad0808746573743130373000ae0808746573743130373100af080874" + "6573743130373200b00808746573743130373300b10808746573743130373400b20808746573743130373500b30808" + "746573743130373600b40808746573743130373700b50808746573743130373800b60808746573743130373900b708" + "08746573743130383000b80808746573743130383100b90808746573743130383200ba0808746573743130383300bb" + "0808746573743130383400bc0808746573743130383500bd0808746573743130383600be0808746573743130383700" + "bf0808746573743130383800c00808746573743130383900c10808746573743130393000c208087465737431303931" + "00c30808746573743130393200c40808746573743130393300c50808746573743130393400c6080874657374313039" + "3500c70808746573743130393600c80808746573743130393700c90808746573743130393800ca0808746573743130" + "393900cb0808746573743131303000cc0808746573743131303100cd0808746573743131303200ce08087465737431" + "31303300cf0808746573743131303400d00808746573743131303500d10808746573743131303600d2080874657374" + "3131303700d30808746573743131303800d40808746573743131303900d50808746573743131313000d60808746573" + "743131313100d70808746573743131313200d80808746573743131313300d90808746573743131313400da08087465" + "73743131313500db0808746573743131313600dc0808746573743131313700dd0808746573743131313800de080874" + "6573743131313900df0808746573743131323000e00808746573743131323100e10808746573743131323200e20808" + "746573743131323300e30808746573743131323400e40808746573743131323500e50808746573743131323600e608" + "08746573743131323700e70808746573743131323800e80808746573743131323900e90808746573743131333000ea" + "0808746573743131333100eb0808746573743131333200ec0808746573743131333300ed0808746573743131333400" + "ee0808746573743131333500ef0808746573743131333600f00808746573743131333700f108087465737431313338" + "00f20808746573743131333900f30808746573743131343000f40808746573743131343100f5080874657374313134" + "3200f60808746573743131343300f70808746573743131343400f80808746573743131343500f90808746573743131" + "343600fa0808746573743131343700fb0808746573743131343800fc0808746573743131343900fd08087465737431" + "31353000fe0808746573743131353100ff080874657374313135320080090874657374313135330081090874657374" + "3131353400820908746573743131353500830908746573743131353600840908746573743131353700850908746573" + "7431313538008609087465737431313539008709087465737431313630008809087465737431313631008909087465" + "737431313632008a09087465737431313633008b09087465737431313634008c09087465737431313635008d090874" + "65737431313636008e09087465737431313637008f0908746573743131363800900908746573743131363900910908" + "7465737431313730009209087465737431313731009309087465737431313732009409087465737431313733009509" + "0874657374313137340096090874657374313137350097090874657374313137360098090874657374313137370099" + "09087465737431313738009a09087465737431313739009b09087465737431313830009c0908746573743131383100" + "9d09087465737431313832009e09087465737431313833009f0908746573743131383400a009087465737431313835" + "00a10908746573743131383600a20908746573743131383700a30908746573743131383800a4090874657374313138" + "3900a50908746573743131393000a60908746573743131393100a70908746573743131393200a80908746573743131" + "393300a90908746573743131393400aa0908746573743131393500ab0908746573743131393600ac09087465737431" + "31393700ad0908746573743131393800ae0908746573743131393900af0908746573743132303000b0090874657374" + "3132303100b10908746573743132303200b20908746573743132303300b30908746573743132303400b40908746573" + "743132303500b50908746573743132303600b60908746573743132303700b70908746573743132303800b809087465" + "73743132303900b90908746573743132313000ba0908746573743132313100bb0908746573743132313200bc090874" + "6573743132313300bd0908746573743132313400be0908746573743132313500bf0908746573743132313600c00908" + "746573743132313700c10908746573743132313800c20908746573743132313900c30908746573743132323000c409" + "08746573743132323100c50908746573743132323200c60908746573743132323300c70908746573743132323400c8" + "0908746573743132323500c90908746573743132323600ca0908746573743132323700cb0908746573743132323800" + "cc0908746573743132323900cd0908746573743132333000ce0908746573743132333100cf09087465737431323332" + "00d00908746573743132333300d10908746573743132333400d20908746573743132333500d3090874657374313233" + "3600d40908746573743132333700d50908746573743132333800d60908746573743132333900d70908746573743132" + "343000d80908746573743132343100d90908746573743132343200da0908746573743132343300db09087465737431" + "32343400dc0908746573743132343500dd0908746573743132343600de0908746573743132343700df090874657374" + "3132343800e00908746573743132343900e10908746573743132353000e20908746573743132353100e30908746573" + "743132353200e40908746573743132353300e50908746573743132353400e60908746573743132353500e709087465" + "73743132353600e80908746573743132353700e90908746573743132353800ea0908746573743132353900eb090874" + "6573743132363000ec0908746573743132363100ed0908746573743132363200ee0908746573743132363300ef0908" + "746573743132363400f00908746573743132363500f10908746573743132363600f20908746573743132363700f309" + "08746573743132363800f40908746573743132363900f50908746573743132373000f60908746573743132373100f7" + "0908746573743132373200f80908746573743132373300f90908746573743132373400fa0908746573743132373500" + "fb0908746573743132373600fc0908746573743132373700fd0908746573743132373800fe09087465737431323739" + "00ff0908746573743132383000800a08746573743132383100810a08746573743132383200820a0874657374313238" + "3300830a08746573743132383400840a08746573743132383500850a08746573743132383600860a08746573743132" + "383700870a08746573743132383800880a08746573743132383900890a087465737431323930008a0a087465737431" + "323931008b0a087465737431323932008c0a087465737431323933008d0a087465737431323934008e0a0874657374" + "31323935008f0a08746573743132393600900a08746573743132393700910a08746573743132393800920a08746573" + "743132393900930a08746573743133303000940a08746573743133303100950a08746573743133303200960a087465" + "73743133303300970a08746573743133303400980a08746573743133303500990a087465737431333036009a0a0874" + "65737431333037009b0a087465737431333038009c0a087465737431333039009d0a087465737431333130009e0a08" + "7465737431333131009f0a08746573743133313200a00a08746573743133313300a10a08746573743133313400a20a" + "08746573743133313500a30a08746573743133313600a40a08746573743133313700a50a08746573743133313800a6" + "0a08746573743133313900a70a08746573743133323000a80a08746573743133323100a90a08746573743133323200" + "aa0a08746573743133323300ab0a08746573743133323400ac0a08746573743133323500ad0a087465737431333236" + "00ae0a08746573743133323700af0a08746573743133323800b00a08746573743133323900b10a0874657374313333" + "3000b20a08746573743133333100b30a08746573743133333200b40a08746573743133333300b50a08746573743133" + "333400b60a08746573743133333500b70a08746573743133333600b80a08746573743133333700b90a087465737431" + "33333800ba0a08746573743133333900bb0a08746573743133343000bc0a08746573743133343100bd0a0874657374" + "3133343200be0a08746573743133343300bf0a08746573743133343400c00a08746573743133343500c10a08746573" + "743133343600c20a08746573743133343700c30a08746573743133343800c40a08746573743133343900c50a087465" + "73743133353000c60a08746573743133353100c70a08746573743133353200c80a08746573743133353300c90a0874" + "6573743133353400ca0a08746573743133353500cb0a08746573743133353600cc0a08746573743133353700cd0a08" + "746573743133353800ce0a08746573743133353900cf0a08746573743133363000d00a08746573743133363100d10a" + "08746573743133363200d20a08746573743133363300d30a08746573743133363400d40a08746573743133363500d5" + "0a08746573743133363600d60a08746573743133363700d70a08746573743133363800d80a08746573743133363900" + "d90a08746573743133373000da0a08746573743133373100db0a08746573743133373200dc0a087465737431333733" + "00dd0a08746573743133373400de0a08746573743133373500df0a08746573743133373600e00a0874657374313337" + "3700e10a08746573743133373800e20a08746573743133373900e30a08746573743133383000e40a08746573743133" + "383100e50a08746573743133383200e60a08746573743133383300e70a08746573743133383400e80a087465737431" + "33383500e90a08746573743133383600ea0a08746573743133383700eb0a08746573743133383800ec0a0874657374" + "3133383900ed0a08746573743133393000ee0a08746573743133393100ef0a08746573743133393200f00a08746573" + "743133393300f10a08746573743133393400f20a08746573743133393500f30a08746573743133393600f40a087465" + "73743133393700f50a08746573743133393800f60a08746573743133393900f70a08746573743134303000f80a0874" + "6573743134303100f90a08746573743134303200fa0a08746573743134303300fb0a08746573743134303400fc0a08" + "746573743134303500fd0a08746573743134303600fe0a08746573743134303700ff0a08746573743134303800800b" + "08746573743134303900810b08746573743134313000820b08746573743134313100830b0874657374313431320084" + "0b08746573743134313300850b08746573743134313400860b08746573743134313500870b08746573743134313600" + "880b08746573743134313700890b087465737431343138008a0b087465737431343139008b0b087465737431343230" + "008c0b087465737431343231008d0b087465737431343232008e0b087465737431343233008f0b0874657374313432" + "3400900b08746573743134323500910b08746573743134323600920b08746573743134323700930b08746573743134" + "323800940b08746573743134323900950b08746573743134333000960b08746573743134333100970b087465737431" + "34333200980b08746573743134333300990b087465737431343334009a0b087465737431343335009b0b0874657374" + "31343336009c0b087465737431343337009d0b087465737431343338009e0b087465737431343339009f0b08746573" + "743134343000a00b08746573743134343100a10b08746573743134343200a20b08746573743134343300a30b087465" + "73743134343400a40b08746573743134343500a50b08746573743134343600a60b08746573743134343700a70b0874" + "6573743134343800a80b08746573743134343900a90b08746573743134353000aa0b08746573743134353100ab0b08" + "746573743134353200ac0b08746573743134353300ad0b08746573743134353400ae0b08746573743134353500af0b" + "08746573743134353600b00b08746573743134353700b10b08746573743134353800b20b08746573743134353900b3" + "0b08746573743134363000b40b08746573743134363100b50b08746573743134363200b60b08746573743134363300" + "b70b08746573743134363400b80b08746573743134363500b90b08746573743134363600ba0b087465737431343637" + "00bb0b08746573743134363800bc0b08746573743134363900bd0b08746573743134373000be0b0874657374313437" + "3100bf0b08746573743134373200c00b08746573743134373300c10b08746573743134373400c20b08746573743134" + "373500c30b08746573743134373600c40b08746573743134373700c50b08746573743134373800c60b087465737431" + "34373900c70b08746573743134383000c80b08746573743134383100c90b08746573743134383200ca0b0874657374" + "3134383300cb0b08746573743134383400cc0b08746573743134383500cd0b08746573743134383600ce0b08746573" + "743134383700cf0b08746573743134383800d00b08746573743134383900d10b08746573743134393000d20b087465" + "73743134393100d30b08746573743134393200d40b08746573743134393300d50b08746573743134393400d60b0874" + "6573743134393500d70b08746573743134393600d80b08746573743134393700d90b08746573743134393800da0b08" + "746573743134393900db0b08746573743135303000dc0b08746573743135303100dd0b08746573743135303200de0b" + "08746573743135303300df0b08746573743135303400e00b08746573743135303500e10b08746573743135303600e2" + "0b08746573743135303700e30b08746573743135303800e40b08746573743135303900e50b08746573743135313000" + "e60b08746573743135313100e70b08746573743135313200e80b08746573743135313300e90b087465737431353134" + "00ea0b08746573743135313500eb0b08746573743135313600ec0b08746573743135313700ed0b0874657374313531" + "3800ee0b08746573743135313900ef0b08746573743135323000f00b08746573743135323100f10b08746573743135" + "323200f20b08746573743135323300f30b08746573743135323400f40b08746573743135323500f50b087465737431" + "35323600f60b08746573743135323700f70b08746573743135323800f80b08746573743135323900f90b0874657374" + "3135333000fa0b08746573743135333100fb0b08746573743135333200fc0b08746573743135333300fd0b08746573" + "743135333400fe0b08746573743135333500ff0b08746573743135333600800c08746573743135333700810c087465" + "73743135333800820c08746573743135333900830c08746573743135343000840c08746573743135343100850c0874" + "6573743135343200860c08746573743135343300870c08746573743135343400880c08746573743135343500890c08" + "7465737431353436008a0c087465737431353437008b0c087465737431353438008c0c087465737431353439008d0c" + "087465737431353530008e0c087465737431353531008f0c08746573743135353200900c0874657374313535330091" + "0c08746573743135353400920c08746573743135353500930c08746573743135353600940c08746573743135353700" + "950c08746573743135353800960c08746573743135353900970c08746573743135363000980c087465737431353631" + "00990c087465737431353632009a0c087465737431353633009b0c087465737431353634009c0c0874657374313536" + "35009d0c087465737431353636009e0c087465737431353637009f0c08746573743135363800a00c08746573743135" + "363900a10c08746573743135373000a20c08746573743135373100a30c08746573743135373200a40c087465737431" + "35373300a50c08746573743135373400a60c08746573743135373500a70c08746573743135373600a80c0874657374" + "3135373700a90c08746573743135373800aa0c08746573743135373900ab0c08746573743135383000ac0c08746573" + "743135383100ad0c08746573743135383200ae0c08746573743135383300af0c08746573743135383400b00c087465" + "73743135383500b10c08746573743135383600b20c08746573743135383700b30c08746573743135383800b40c0874" + "6573743135383900b50c08746573743135393000b60c08746573743135393100b70c08746573743135393200b80c08" + "746573743135393300b90c08746573743135393400ba0c08746573743135393500bb0c08746573743135393600bc0c" + "08746573743135393700bd0c08746573743135393800be0c08746573743135393900bf0c08746573743136303000c0" + "0c08746573743136303100c10c08746573743136303200c20c08746573743136303300c30c08746573743136303400" + "c40c08746573743136303500c50c08746573743136303600c60c08746573743136303700c70c087465737431363038" + "00c80c08746573743136303900c90c08746573743136313000ca0c08746573743136313100cb0c0874657374313631" + "3200cc0c08746573743136313300cd0c08746573743136313400ce0c08746573743136313500cf0c08746573743136" + "313600d00c08746573743136313700d10c08746573743136313800d20c08746573743136313900d30c087465737431" + "36323000d40c08746573743136323100d50c08746573743136323200d60c08746573743136323300d70c0874657374" + "3136323400d80c08746573743136323500d90c08746573743136323600da0c08746573743136323700db0c08746573" + "743136323800dc0c08746573743136323900dd0c08746573743136333000de0c08746573743136333100df0c087465" + "73743136333200e00c08746573743136333300e10c08746573743136333400e20c08746573743136333500e30c0874" + "6573743136333600e40c08746573743136333700e50c08746573743136333800e60c08746573743136333900e70c08" + "746573743136343000e80c08746573743136343100e90c08746573743136343200ea0c08746573743136343300eb0c" + "08746573743136343400ec0c08746573743136343500ed0c08746573743136343600ee0c08746573743136343700ef" + "0c08746573743136343800f00c08746573743136343900f10c08746573743136353000f20c08746573743136353100" + "f30c08746573743136353200f40c08746573743136353300f50c08746573743136353400f60c087465737431363535" + "00f70c08746573743136353600f80c08746573743136353700f90c08746573743136353800fa0c0874657374313635" + "3900fb0c08746573743136363000fc0c08746573743136363100fd0c08746573743136363200fe0c08746573743136" + "363300ff0c08746573743136363400800d08746573743136363500810d08746573743136363600820d087465737431" + "36363700830d08746573743136363800840d08746573743136363900850d08746573743136373000860d0874657374" + "3136373100870d08746573743136373200880d08746573743136373300890d087465737431363734008a0d08746573" + "7431363735008b0d087465737431363736008c0d087465737431363737008d0d087465737431363738008e0d087465" + "737431363739008f0d08746573743136383000900d08746573743136383100910d08746573743136383200920d0874" + "6573743136383300930d08746573743136383400940d08746573743136383500950d08746573743136383600960d08" + "746573743136383700970d08746573743136383800980d08746573743136383900990d087465737431363930009a0d" + "087465737431363931009b0d087465737431363932009c0d087465737431363933009d0d087465737431363934009e" + "0d087465737431363935009f0d08746573743136393600a00d08746573743136393700a10d08746573743136393800" + "a20d08746573743136393900a30d08746573743137303000a40d08746573743137303100a50d087465737431373032" + "00a60d08746573743137303300a70d08746573743137303400a80d08746573743137303500a90d0874657374313730" + "3600aa0d08746573743137303700ab0d08746573743137303800ac0d08746573743137303900ad0d08746573743137" + "313000ae0d08746573743137313100af0d08746573743137313200b00d08746573743137313300b10d087465737431" + "37313400b20d08746573743137313500b30d08746573743137313600b40d08746573743137313700b50d0874657374" + "3137313800b60d08746573743137313900b70d08746573743137323000b80d08746573743137323100b90d08746573" + "743137323200ba0d08746573743137323300bb0d08746573743137323400bc0d08746573743137323500bd0d087465" + "73743137323600be0d08746573743137323700bf0d08746573743137323800c00d08746573743137323900c10d0874" + "6573743137333000c20d08746573743137333100c30d08746573743137333200c40d08746573743137333300c50d08" + "746573743137333400c60d08746573743137333500c70d08746573743137333600c80d08746573743137333700c90d" + "08746573743137333800ca0d08746573743137333900cb0d08746573743137343000cc0d08746573743137343100cd" + "0d08746573743137343200ce0d08746573743137343300cf0d08746573743137343400d00d08746573743137343500" + "d10d08746573743137343600d20d08746573743137343700d30d08746573743137343800d40d087465737431373439" + "00d50d08746573743137353000d60d08746573743137353100d70d08746573743137353200d80d0874657374313735" + "3300d90d08746573743137353400da0d08746573743137353500db0d08746573743137353600dc0d08746573743137" + "353700dd0d08746573743137353800de0d08746573743137353900df0d08746573743137363000e00d087465737431" + "37363100e10d08746573743137363200e20d08746573743137363300e30d08746573743137363400e40d0874657374" + "3137363500e50d08746573743137363600e60d08746573743137363700e70d08746573743137363800e80d08746573" + "743137363900e90d08746573743137373000ea0d08746573743137373100eb0d08746573743137373200ec0d087465" + "73743137373300ed0d08746573743137373400ee0d08746573743137373500ef0d08746573743137373600f00d0874" + "6573743137373700f10d08746573743137373800f20d08746573743137373900f30d08746573743137383000f40d08" + "746573743137383100f50d08746573743137383200f60d08746573743137383300f70d08746573743137383400f80d" + "08746573743137383500f90d08746573743137383600fa0d08746573743137383700fb0d08746573743137383800fc" + "0d08746573743137383900fd0d08746573743137393000fe0d08746573743137393100ff0d08746573743137393200" + "800e08746573743137393300810e08746573743137393400820e08746573743137393500830e087465737431373936" + "00840e08746573743137393700850e08746573743137393800860e08746573743137393900870e0874657374313830" + "3000880e08746573743138303100890e087465737431383032008a0e087465737431383033008b0e08746573743138" + "3034008c0e087465737431383035008d0e087465737431383036008e0e087465737431383037008f0e087465737431" + "38303800900e08746573743138303900910e08746573743138313000920e08746573743138313100930e0874657374" + "3138313200940e08746573743138313300950e08746573743138313400960e08746573743138313500970e08746573" + "743138313600980e08746573743138313700990e087465737431383138009a0e087465737431383139009b0e087465" + "737431383230009c0e087465737431383231009d0e087465737431383232009e0e087465737431383233009f0e0874" + "6573743138323400a00e08746573743138323500a10e08746573743138323600a20e08746573743138323700a30e08" + "746573743138323800a40e08746573743138323900a50e08746573743138333000a60e08746573743138333100a70e" + "08746573743138333200a80e08746573743138333300a90e08746573743138333400aa0e08746573743138333500ab" + "0e08746573743138333600ac0e08746573743138333700ad0e08746573743138333800ae0e08746573743138333900" + "af0e08746573743138343000b00e08746573743138343100b10e08746573743138343200b20e087465737431383433" + "00b30e08746573743138343400b40e08746573743138343500b50e08746573743138343600b60e0874657374313834" + "3700b70e08746573743138343800b80e08746573743138343900b90e08746573743138353000ba0e08746573743138" + "353100bb0e08746573743138353200bc0e08746573743138353300bd0e08746573743138353400be0e087465737431" + "38353500bf0e08746573743138353600c00e08746573743138353700c10e08746573743138353800c20e0874657374" + "3138353900c30e08746573743138363000c40e08746573743138363100c50e08746573743138363200c60e08746573" + "743138363300c70e08746573743138363400c80e08746573743138363500c90e08746573743138363600ca0e087465" + "73743138363700cb0e08746573743138363800cc0e08746573743138363900cd0e08746573743138373000ce0e0874" + "6573743138373100cf0e08746573743138373200d00e08746573743138373300d10e08746573743138373400d20e08" + "746573743138373500d30e08746573743138373600d40e08746573743138373700d50e08746573743138373800d60e" + "08746573743138373900d70e08746573743138383000d80e08746573743138383100d90e08746573743138383200da" + "0e08746573743138383300db0e08746573743138383400dc0e08746573743138383500dd0e08746573743138383600" + "de0e08746573743138383700df0e08746573743138383800e00e08746573743138383900e10e087465737431383930" + "00e20e08746573743138393100e30e08746573743138393200e40e08746573743138393300e50e0874657374313839" + "3400e60e08746573743138393500e70e08746573743138393600e80e08746573743138393700e90e08746573743138" + "393800ea0e08746573743138393900eb0e08746573743139303000ec0e08746573743139303100ed0e087465737431" + "39303200ee0e08746573743139303300ef0e08746573743139303400f00e08746573743139303500f10e0874657374" + "3139303600f20e08746573743139303700f30e08746573743139303800f40e08746573743139303900f50e08746573" + "743139313000f60e08746573743139313100f70e08746573743139313200f80e08746573743139313300f90e087465" + "73743139313400fa0e08746573743139313500fb0e08746573743139313600fc0e08746573743139313700fd0e0874" + "6573743139313800fe0e08746573743139313900ff0e08746573743139323000800f08746573743139323100810f08" + "746573743139323200820f08746573743139323300830f08746573743139323400840f08746573743139323500850f" + "08746573743139323600860f08746573743139323700870f08746573743139323800880f0874657374313932390089" + "0f087465737431393330008a0f087465737431393331008b0f087465737431393332008c0f08746573743139333300" + "8d0f087465737431393334008e0f087465737431393335008f0f08746573743139333600900f087465737431393337" + "00910f08746573743139333800920f08746573743139333900930f08746573743139343000940f0874657374313934" + "3100950f08746573743139343200960f08746573743139343300970f08746573743139343400980f08746573743139" + "343500990f087465737431393436009a0f087465737431393437009b0f087465737431393438009c0f087465737431" + "393439009d0f087465737431393530009e0f087465737431393531009f0f08746573743139353200a00f0874657374" + "3139353300a10f08746573743139353400a20f08746573743139353500a30f08746573743139353600a40f08746573" + "743139353700a50f08746573743139353800a60f08746573743139353900a70f08746573743139363000a80f087465" + "73743139363100a90f08746573743139363200aa0f08746573743139363300ab0f08746573743139363400ac0f0874" + "6573743139363500ad0f08746573743139363600ae0f08746573743139363700af0f08746573743139363800b00f08" + "746573743139363900b10f08746573743139373000b20f08746573743139373100b30f08746573743139373200b40f" + "08746573743139373300b50f08746573743139373400b60f08746573743139373500b70f08746573743139373600b8" + "0f08746573743139373700b90f08746573743139373800ba0f08746573743139373900bb0f08746573743139383000" + "bc0f08746573743139383100bd0f08746573743139383200be0f08746573743139383300bf0f087465737431393834" + "00c00f08746573743139383500c10f08746573743139383600c20f08746573743139383700c30f0874657374313938" + "3800c40f08746573743139383900c50f08746573743139393000c60f08746573743139393100c70f08746573743139" + "393200c80f08746573743139393300c90f08746573743139393400ca0f08746573743139393500cb0f087465737431" + "39393600cc0f08746573743139393700cd0f08746573743139393800ce0f08746573743139393900cf0f0874657374" + "3230303000d00f08746573743230303100d10f08746573743230303200d20f08746573743230303300d30f08746573" + "743230303400d40f08746573743230303500d50f08746573743230303600d60f08746573743230303700d70f087465" + "73743230303800d80f08746573743230303900d90f08746573743230313000da0f08746573743230313100db0f0874" + "6573743230313200dc0f08746573743230313300dd0f08746573743230313400de0f08746573743230313500df0f08" + "746573743230313600e00f08746573743230313700e10f08746573743230313800e20f08746573743230313900e30f" + "08746573743230323000e40f08746573743230323100e50f08746573743230323200e60f08746573743230323300e7" + "0f08746573743230323400e80f08746573743230323500e90f08746573743230323600ea0f08746573743230323700" + "eb0f08746573743230323800ec0f08746573743230323900ed0f08746573743230333000ee0f087465737432303331" + "00ef0f08746573743230333200f00f08746573743230333300f10f08746573743230333400f20f0874657374323033" + "3500f30f08746573743230333600f40f08746573743230333700f50f08746573743230333800f60f08746573743230" + "333900f70f08746573743230343000f80f08746573743230343100f90f08746573743230343200fa0f087465737432" + "30343300fb0f08746573743230343400fc0f08746573743230343500fd0f08746573743230343600fe0f0874657374" + "3230343700ff0f08746573743230343800801008746573743230343900811008746573743230353000821008746573" + "7432303531008310087465737432303532008410087465737432303533008510087465737432303534008610087465" + "737432303535008710087465737432303536008810087465737432303537008910087465737432303538008a100874" + "65737432303539008b10087465737432303630008c10087465737432303631008d10087465737432303632008e1008" + "7465737432303633008f10087465737432303634009010087465737432303635009110087465737432303636009210" + "0874657374323036370093100874657374323036380094100874657374323036390095100874657374323037300096" + "1008746573743230373100971008746573743230373200981008746573743230373300991008746573743230373400" + "9a10087465737432303735009b10087465737432303736009c10087465737432303737009d10087465737432303738" + "009e10087465737432303739009f1008746573743230383000a01008746573743230383100a1100874657374323038" + "3200a21008746573743230383300a31008746573743230383400a41008746573743230383500a51008746573743230" + "383600a61008746573743230383700a71008746573743230383800a81008746573743230383900a910087465737432" + "30393000aa1008746573743230393100ab1008746573743230393200ac1008746573743230393300ad100874657374" + "3230393400ae1008746573743230393500af1008746573743230393600b01008746573743230393700b11008746573" + "743230393800b21008746573743230393900b31008746573743231303000b41008746573743231303100b510087465" + "73743231303200b61008746573743231303300b71008746573743231303400b81008746573743231303500b9100874" + "6573743231303600ba1008746573743231303700bb1008746573743231303800bc1008746573743231303900bd1008" + "746573743231313000be1008746573743231313100bf1008746573743231313200c01008746573743231313300c110" + "08746573743231313400c21008746573743231313500c31008746573743231313600c41008746573743231313700c5" + "1008746573743231313800c61008746573743231313900c71008746573743231323000c81008746573743231323100" + "c91008746573743231323200ca1008746573743231323300cb1008746573743231323400cc10087465737432313235" + "00cd1008746573743231323600ce1008746573743231323700cf1008746573743231323800d0100874657374323132" + "3900d11008746573743231333000d21008746573743231333100d31008746573743231333200d41008746573743231" + "333300d51008746573743231333400d61008746573743231333500d71008746573743231333600d810087465737432" + "31333700d91008746573743231333800da1008746573743231333900db1008746573743231343000dc100874657374" + "3231343100dd1008746573743231343200de1008746573743231343300df1008746573743231343400e01008746573" + "743231343500e11008746573743231343600e21008746573743231343700e31008746573743231343800e410087465" + "73743231343900e51008746573743231353000e61008746573743231353100e71008746573743231353200e8100874" + "6573743231353300e91008746573743231353400ea1008746573743231353500eb1008746573743231353600ec1008" + "746573743231353700ed1008746573743231353800ee1008746573743231353900ef1008746573743231363000f010" + "08746573743231363100f11008746573743231363200f21008746573743231363300f31008746573743231363400f4" + "1008746573743231363500f51008746573743231363600f61008746573743231363700f71008746573743231363800" + "f81008746573743231363900f91008746573743231373000fa1008746573743231373100fb10087465737432313732" + "00fc1008746573743231373300fd1008746573743231373400fe1008746573743231373500ff100874657374323137" + "3600801108746573743231373700811108746573743231373800821108746573743231373900831108746573743231" + "3830008411087465737432313831008511087465737432313832008611087465737432313833008711087465737432" + "313834008811087465737432313835008911087465737432313836008a11087465737432313837008b110874657374" + "32313838008c11087465737432313839008d11087465737432313930008e11087465737432313931008f1108746573" + "7432313932009011087465737432313933009111087465737432313934009211087465737432313935009311087465" + "7374323139360094110874657374323139370095110874657374323139380096110874657374323139390097110874" + "65737432323030009811087465737432323031009911087465737432323032009a11087465737432323033009b1108" + "7465737432323034009c11087465737432323035009d11087465737432323036009e11087465737432323037009f11" + "08746573743232303800a01108746573743232303900a11108746573743232313000a21108746573743232313100a3" + "1108746573743232313200a41108746573743232313300a51108746573743232313400a61108746573743232313500" + "a71108746573743232313600a81108746573743232313700a91108746573743232313800aa11087465737432323139" + "00ab1108746573743232323000ac1108746573743232323100ad1108746573743232323200ae110874657374323232" + "3300af1108746573743232323400b01108746573743232323500b11108746573743232323600b21108746573743232" + "323700b31108746573743232323800b41108746573743232323900b51108746573743232333000b611087465737432" + "32333100b71108746573743232333200b81108746573743232333300b91108746573743232333400ba110874657374" + "3232333500bb1108746573743232333600bc1108746573743232333700bd1108746573743232333800be1108746573" + "743232333900bf1108746573743232343000c01108746573743232343100c11108746573743232343200c211087465" + "73743232343300c31108746573743232343400c41108746573743232343500c51108746573743232343600c6110874" + "6573743232343700c71108746573743232343800c81108746573743232343900c91108746573743232353000ca1108" + "746573743232353100cb1108746573743232353200cc1108746573743232353300cd1108746573743232353400ce11" + "08746573743232353500cf1108746573743232353600d01108746573743232353700d11108746573743232353800d2" + "1108746573743232353900d31108746573743232363000d41108746573743232363100d51108746573743232363200" + "d61108746573743232363300d71108746573743232363400d81108746573743232363500d911087465737432323636" + "00da1108746573743232363700db1108746573743232363800dc1108746573743232363900dd110874657374323237" + "3000de1108746573743232373100df1108746573743232373200e01108746573743232373300e11108746573743232" + "373400e21108746573743232373500e31108746573743232373600e41108746573743232373700e511087465737432" + "32373800e61108746573743232373900e71108746573743232383000e81108746573743232383100e9110874657374" + "3232383200ea1108746573743232383300eb1108746573743232383400ec1108746573743232383500ed1108746573" + "743232383600ee1108746573743232383700ef1108746573743232383800f01108746573743232383900f111087465" + "73743232393000f21108746573743232393100f31108746573743232393200f41108746573743232393300f5110874" + "6573743232393400f61108746573743232393500f71108746573743232393600f81108746573743232393700f91108" + "746573743232393800fa1108746573743232393900fb1108746573743233303000fc1108746573743233303100fd11" + "08746573743233303200fe1108746573743233303300ff110874657374323330340080120874657374323330350081" + "1208746573743233303600821208746573743233303700831208746573743233303800841208746573743233303900" + "8512087465737432333130008612087465737432333131008712087465737432333132008812087465737432333133" + "008912087465737432333134008a12087465737432333135008b12087465737432333136008c120874657374323331" + "37008d12087465737432333138008e12087465737432333139008f1208746573743233323000901208746573743233" + "3231009112087465737432333232009212087465737432333233009312087465737432333234009412087465737432" + "3332350095120874657374323332360096120874657374323332370097120874657374323332380098120874657374" + "32333239009912087465737432333330009a12087465737432333331009b12087465737432333332009c1208746573" + "7432333333009d12087465737432333334009e12087465737432333335009f1208746573743233333600a012087465" + "73743233333700a11208746573743233333800a21208746573743233333900a31208746573743233343000a4120874" + "6573743233343100a51208746573743233343200a61208746573743233343300a71208746573743233343400a81208" + "746573743233343500a91208746573743233343600aa1208746573743233343700ab1208746573743233343800ac12" + "08746573743233343900ad1208746573743233353000ae1208746573743233353100af1208746573743233353200b0" + "1208746573743233353300b11208746573743233353400b21208746573743233353500b31208746573743233353600" + "b41208746573743233353700b51208746573743233353800b61208746573743233353900b712087465737432333630" + "00b81208746573743233363100b91208746573743233363200ba1208746573743233363300bb120874657374323336" + "3400bc1208746573743233363500bd1208746573743233363600be1208746573743233363700bf1208746573743233" + "363800c01208746573743233363900c11208746573743233373000c21208746573743233373100c312087465737432" + "33373200c41208746573743233373300c51208746573743233373400c61208746573743233373500c7120874657374" + "3233373600c81208746573743233373700c91208746573743233373800ca1208746573743233373900cb1208746573" + "743233383000cc1208746573743233383100cd1208746573743233383200ce1208746573743233383300cf12087465" + "73743233383400d01208746573743233383500d11208746573743233383600d21208746573743233383700d3120874" + "6573743233383800d41208746573743233383900d51208746573743233393000d61208746573743233393100d71208" + "746573743233393200d81208746573743233393300d91208746573743233393400da1208746573743233393500db12" + "08746573743233393600dc1208746573743233393700dd1208746573743233393800de1208746573743233393900df" + "1208746573743234303000e01208746573743234303100e11208746573743234303200e21208746573743234303300" + "e31208746573743234303400e41208746573743234303500e51208746573743234303600e612087465737432343037" + "00e71208746573743234303800e81208746573743234303900e91208746573743234313000ea120874657374323431" + "3100eb1208746573743234313200ec1208746573743234313300ed1208746573743234313400ee1208746573743234" + "313500ef1208746573743234313600f01208746573743234313700f11208746573743234313800f212087465737432" + "34313900f31208746573743234323000f41208746573743234323100f51208746573743234323200f6120874657374" + "3234323300f71208746573743234323400f81208746573743234323500f91208746573743234323600fa1208746573" + "743234323700fb1208746573743234323800fc1208746573743234323900fd1208746573743234333000fe12087465" + "73743234333100ff120874657374323433320080130874657374323433330081130874657374323433340082130874" + "6573743234333500831308746573743234333600841308746573743234333700851308746573743234333800861308" + "7465737432343339008713087465737432343430008813087465737432343431008913087465737432343432008a13" + "087465737432343433008b13087465737432343434008c13087465737432343435008d13087465737432343436008e" + "13087465737432343437008f1308746573743234343800901308746573743234343900911308746573743234353000" + "9213087465737432343531009313087465737432343532009413087465737432343533009513087465737432343534" + "0096130874657374323435350097130874657374323435360098130874657374323435370099130874657374323435" + "38009a13087465737432343539009b13087465737432343630009c13087465737432343631009d1308746573743234" + "3632009e13087465737432343633009f1308746573743234363400a01308746573743234363500a113087465737432" + "34363600a21308746573743234363700a31308746573743234363800a41308746573743234363900a5130874657374" + "3234373000a61308746573743234373100a71308746573743234373200a81308746573743234373300a91308746573" + "743234373400aa1308746573743234373500ab1308746573743234373600ac1308746573743234373700ad13087465" + "73743234373800ae1308746573743234373900af1308746573743234383000b01308746573743234383100b1130874" + "6573743234383200b21308746573743234383300b31308746573743234383400b41308746573743234383500b51308" + "746573743234383600b61308746573743234383700b71308746573743234383800b81308746573743234383900b913" + "08746573743234393000ba1308746573743234393100bb1308746573743234393200bc1308746573743234393300bd" + "1308746573743234393400be1308746573743234393500bf1308746573743234393600c01308746573743234393700" + "c11308746573743234393800c21308746573743234393900c31308746573743235303000c413087465737432353031" + "00c51308746573743235303200c61308746573743235303300c71308746573743235303400c8130874657374323530" + "3500c91308746573743235303600ca1308746573743235303700cb1308746573743235303800cc1308746573743235" + "303900cd1308746573743235313000ce1308746573743235313100cf1308746573743235313200d013087465737432" + "35313300d11308746573743235313400d21308746573743235313500d31308746573743235313600d4130874657374" + "3235313700d51308746573743235313800d61308746573743235313900d71308746573743235323000d81308746573" + "743235323100d91308746573743235323200da1308746573743235323300db1308746573743235323400dc13087465" + "73743235323500dd1308746573743235323600de1308746573743235323700df1308746573743235323800e0130874" + "6573743235323900e11308746573743235333000e21308746573743235333100e31308746573743235333200e41308" + "746573743235333300e51308746573743235333400e61308746573743235333500e71308746573743235333600e813" + "08746573743235333700e91308746573743235333800ea1308746573743235333900eb1308746573743235343000ec" + "1308746573743235343100ed1308746573743235343200ee1308746573743235343300ef1308746573743235343400" + "f01308746573743235343500f11308746573743235343600f21308746573743235343700f313087465737432353438" + "00f41308746573743235343900f51308746573743235353000f61308746573743235353100f7130874657374323535" + "3200f81308746573743235353300f91308746573743235353400fa1308746573743235353500fb1308746573743235" + "353600fc1308746573743235353700fd1308746573743235353800fe1308746573743235353900ff13087465737432" + "3536300080140874657374323536310081140874657374323536320082140874657374323536330083140874657374" + "3235363400841408746573743235363500851408746573743235363600861408746573743235363700871408746573" + "7432353638008814087465737432353639008914087465737432353730008a14087465737432353731008b14087465" + "737432353732008c14087465737432353733008d14087465737432353734008e14087465737432353735008f140874" + "6573743235373600901408746573743235373700911408746573743235373800921408746573743235373900931408" + "7465737432353830009414087465737432353831009514087465737432353832009614087465737432353833009714" + "087465737432353834009814087465737432353835009914087465737432353836009a14087465737432353837009b" + "14087465737432353838009c14087465737432353839009d14087465737432353930009e1408746573743235393100" + "9f1408746573743235393200a01408746573743235393300a11408746573743235393400a214087465737432353935" + "00a31408746573743235393600a41408746573743235393700a51408746573743235393800a6140874657374323539" + "3900a71408746573743236303000a81408746573743236303100a91408746573743236303200aa1408746573743236" + "303300ab1408746573743236303400ac1408746573743236303500ad1408746573743236303600ae14087465737432" + "36303700af1408746573743236303800b01408746573743236303900b11408746573743236313000b2140874657374" + "3236313100b31408746573743236313200b41408746573743236313300b51408746573743236313400b61408746573" + "743236313500b71408746573743236313600b81408746573743236313700b91408746573743236313800ba14087465" + "73743236313900bb1408746573743236323000bc1408746573743236323100bd1408746573743236323200be140874" + "6573743236323300bf1408746573743236323400c01408746573743236323500c11408746573743236323600c21408" + "746573743236323700c31408746573743236323800c41408746573743236323900c51408746573743236333000c614" + "08746573743236333100c71408746573743236333200c81408746573743236333300c91408746573743236333400ca" + "1408746573743236333500cb1408746573743236333600cc1408746573743236333700cd1408746573743236333800" + "ce1408746573743236333900cf1408746573743236343000d01408746573743236343100d114087465737432363432" + "00d21408746573743236343300d31408746573743236343400d41408746573743236343500d5140874657374323634" + "3600d61408746573743236343700d71408746573743236343800d81408746573743236343900d91408746573743236" + "353000da1408746573743236353100db1408746573743236353200dc1408746573743236353300dd14087465737432" + "36353400de1408746573743236353500df1408746573743236353600e01408746573743236353700e1140874657374" + "3236353800e21408746573743236353900e31408746573743236363000e41408746573743236363100e51408746573" + "743236363200e61408746573743236363300e71408746573743236363400e81408746573743236363500e914087465" + "73743236363600ea1408746573743236363700eb1408746573743236363800ec1408746573743236363900ed140874" + "6573743236373000ee1408746573743236373100ef1408746573743236373200f01408746573743236373300f11408" + "746573743236373400f21408746573743236373500f31408746573743236373600f41408746573743236373700f514" + "08746573743236373800f61408746573743236373900f71408746573743236383000f81408746573743236383100f9" + "1408746573743236383200fa1408746573743236383300fb1408746573743236383400fc1408746573743236383500" + "fd1408746573743236383600fe1408746573743236383700ff14087465737432363838008015087465737432363839" + "0081150874657374323639300082150874657374323639310083150874657374323639320084150874657374323639" + "3300851508746573743236393400861508746573743236393500871508746573743236393600881508746573743236" + "3937008915087465737432363938008a15087465737432363939008b15087465737432373030008c15087465737432" + "373031008d15087465737432373032008e15087465737432373033008f150874657374323730340090150874657374" + "3237303500911508746573743237303600921508746573743237303700931508746573743237303800941508746573" + "7432373039009515087465737432373130009615087465737432373131009715087465737432373132009815087465" + "737432373133009915087465737432373134009a15087465737432373135009b15087465737432373136009c150874" + "65737432373137009d15087465737432373138009e15087465737432373139009f1508746573743237323000a01508" + "746573743237323100a11508746573743237323200a21508746573743237323300a31508746573743237323400a415" + "08746573743237323500a51508746573743237323600a61508746573743237323700a71508746573743237323800a8" + "1508746573743237323900a91508746573743237333000aa1508746573743237333100ab1508746573743237333200" + "ac1508746573743237333300ad1508746573743237333400ae1508746573743237333500af15087465737432373336" + "00b01508746573743237333700b11508746573743237333800b21508746573743237333900b3150874657374323734" + "3000b41508746573743237343100b51508746573743237343200b61508746573743237343300b71508746573743237" + "343400b81508746573743237343500b91508746573743237343600ba1508746573743237343700bb15087465737432" + "37343800bc1508746573743237343900bd1508746573743237353000be1508746573743237353100bf150874657374" + "3237353200c01508746573743237353300c11508746573743237353400c21508746573743237353500c31508746573" + "743237353600c41508746573743237353700c51508746573743237353800c61508746573743237353900c715087465" + "73743237363000c81508746573743237363100c91508746573743237363200ca1508746573743237363300cb150874" + "6573743237363400cc1508746573743237363500cd1508746573743237363600ce1508746573743237363700cf1508" + "746573743237363800d01508746573743237363900d11508746573743237373000d21508746573743237373100d315" + "08746573743237373200d41508746573743237373300d51508746573743237373400d61508746573743237373500d7" + "1508746573743237373600d81508746573743237373700d91508746573743237373800da1508746573743237373900" + "db1508746573743237383000dc1508746573743237383100dd1508746573743237383200de15087465737432373833" + "00df1508746573743237383400e01508746573743237383500e11508746573743237383600e2150874657374323738" + "3700e31508746573743237383800e41508746573743237383900e51508746573743237393000e61508746573743237" + "393100e71508746573743237393200e81508746573743237393300e91508746573743237393400ea15087465737432" + "37393500eb1508746573743237393600ec1508746573743237393700ed1508746573743237393800ee150874657374" + "3237393900ef1508746573743238303000f01508746573743238303100f11508746573743238303200f21508746573" + "743238303300f31508746573743238303400f41508746573743238303500f51508746573743238303600f615087465" + "73743238303700f71508746573743238303800f81508746573743238303900f91508746573743238313000fa150874" + "6573743238313100fb1508746573743238313200fc1508746573743238313300fd1508746573743238313400fe1508" + "746573743238313500ff15087465737432383136008016087465737432383137008116087465737432383138008216" + "0874657374323831390083160874657374323832300084160874657374323832310085160874657374323832320086" + "1608746573743238323300871608746573743238323400881608746573743238323500891608746573743238323600" + "8a16087465737432383237008b16087465737432383238008c16087465737432383239008d16087465737432383330" + "008e16087465737432383331008f160874657374323833320090160874657374323833330091160874657374323833" + "3400921608746573743238333500931608746573743238333600941608746573743238333700951608746573743238" + "3338009616087465737432383339009716087465737432383430009816087465737432383431009916087465737432" + "383432009a16087465737432383433009b16087465737432383434009c16087465737432383435009d160874657374" + "32383436009e16087465737432383437009f1608746573743238343800a01608746573743238343900a11608746573" + "743238353000a21608746573743238353100a31608746573743238353200a41608746573743238353300a516087465" + "73743238353400a61608746573743238353500a71608746573743238353600a81608746573743238353700a9160874" + "6573743238353800aa1608746573743238353900ab1608746573743238363000ac1608746573743238363100ad1608" + "746573743238363200ae1608746573743238363300af1608746573743238363400b01608746573743238363500b116" + "08746573743238363600b21608746573743238363700b31608746573743238363800b41608746573743238363900b5" + "1608746573743238373000b61608746573743238373100b71608746573743238373200b81608746573743238373300" + "b91608746573743238373400ba1608746573743238373500bb1608746573743238373600bc16087465737432383737" + "00bd1608746573743238373800be1608746573743238373900bf1608746573743238383000c0160874657374323838" + "3100c11608746573743238383200c21608746573743238383300c31608746573743238383400c41608746573743238" + "383500c51608746573743238383600c61608746573743238383700c71608746573743238383800c816087465737432" + "38383900c91608746573743238393000ca1608746573743238393100cb1608746573743238393200cc160874657374" + "3238393300cd1608746573743238393400ce1608746573743238393500cf1608746573743238393600d01608746573" + "743238393700d11608746573743238393800d21608746573743238393900d31608746573743239303000d416087465" + "73743239303100d51608746573743239303200d61608746573743239303300d71608746573743239303400d8160874" + "6573743239303500d91608746573743239303600da1608746573743239303700db1608746573743239303800dc1608" + "746573743239303900dd1608746573743239313000de1608746573743239313100df1608746573743239313200e016" + "08746573743239313300e11608746573743239313400e21608746573743239313500e31608746573743239313600e4" + "1608746573743239313700e51608746573743239313800e61608746573743239313900e71608746573743239323000" + "e81608746573743239323100e91608746573743239323200ea1608746573743239323300eb16087465737432393234" + "00ec1608746573743239323500ed1608746573743239323600ee1608746573743239323700ef160874657374323932" + "3800f01608746573743239323900f11608746573743239333000f21608746573743239333100f31608746573743239" + "333200f41608746573743239333300f51608746573743239333400f61608746573743239333500f716087465737432" + "39333600f81608746573743239333700f91608746573743239333800fa1608746573743239333900fb160874657374" + "3239343000fc1608746573743239343100fd1608746573743239343200fe1608746573743239343300ff1608746573" + "7432393434008017087465737432393435008117087465737432393436008217087465737432393437008317087465" + "7374323934380084170874657374323934390085170874657374323935300086170874657374323935310087170874" + "65737432393532008817087465737432393533008917087465737432393534008a17087465737432393535008b1708" + "7465737432393536008c17087465737432393537008d17087465737432393538008e17087465737432393539008f17" + "0874657374323936300090170874657374323936310091170874657374323936320092170874657374323936330093" + "1708746573743239363400941708746573743239363500951708746573743239363600961708746573743239363700" + "9717087465737432393638009817087465737432393639009917087465737432393730009a17087465737432393731" + "009b17087465737432393732009c17087465737432393733009d17087465737432393734009e170874657374323937" + "35009f1708746573743239373600a01708746573743239373700a11708746573743239373800a21708746573743239" + "373900a31708746573743239383000a41708746573743239383100a51708746573743239383200a617087465737432" + "39383300a71708746573743239383400a81708746573743239383500a91708746573743239383600aa170874657374" + "3239383700ab1708746573743239383800ac1708746573743239383900ad1708746573743239393000ae1708746573" + "743239393100af1708746573743239393200b01708746573743239393300b11708746573743239393400b217087465" + "73743239393500b31708746573743239393600b41708746573743239393700b51708746573743239393800b6170874" + "6573743239393900b71708746573743330303000b81708746573743330303100b91708746573743330303200ba1708" + "746573743330303300bb1708746573743330303400bc1708746573743330303500bd1708746573743330303600be17" + "08746573743330303700bf1708746573743330303800c01708746573743330303900c11708746573743330313000c2" + "1708746573743330313100c31708746573743330313200c41708746573743330313300c51708746573743330313400" + "c61708746573743330313500c71708746573743330313600c81708746573743330313700c917087465737433303138" + "00ca1708746573743330313900cb1708746573743330323000cc1708746573743330323100cd170874657374333032" + "3200ce1708746573743330323300cf1708746573743330323400d01708746573743330323500d11708746573743330" + "323600d21708746573743330323700d31708746573743330323800d41708746573743330323900d517087465737433" + "30333000d61708746573743330333100d71708746573743330333200d81708746573743330333300d9170874657374" + "3330333400da1708746573743330333500db1708746573743330333600dc1708746573743330333700dd1708746573" + "743330333800de1708746573743330333900df1708746573743330343000e01708746573743330343100e117087465" + "73743330343200e21708746573743330343300e31708746573743330343400e41708746573743330343500e5170874" + "6573743330343600e61708746573743330343700e71708746573743330343800e81708746573743330343900e91708" + "746573743330353000ea1708746573743330353100eb1708746573743330353200ec1708746573743330353300ed17" + "08746573743330353400ee1708746573743330353500ef1708746573743330353600f01708746573743330353700f1" + "1708746573743330353800f21708746573743330353900f31708746573743330363000f41708746573743330363100" + "f51708746573743330363200f61708746573743330363300f71708746573743330363400f817087465737433303635" + "00f91708746573743330363600fa1708746573743330363700fb1708746573743330363800fc170874657374333036" + "3900fd1708746573743330373000fe1708746573743330373100ff1708746573743330373200801808746573743330" + "3733008118087465737433303734008218087465737433303735008318087465737433303736008418087465737433" + "3037370085180874657374333037380086180874657374333037390087180874657374333038300088180874657374" + "33303831008918087465737433303832008a18087465737433303833008b18087465737433303834008c1808746573" + "7433303835008d18087465737433303836008e18087465737433303837008f18087465737433303838009018087465" + "7374333038390091180874657374333039300092180874657374333039310093180874657374333039320094180874" + "6573743330393300951808746573743330393400961808746573743330393500971808746573743330393600981808" + "7465737433303937009918087465737433303938009a18087465737433303939009b18087465737433313030009c18" + "087465737433313031009d18087465737433313032009e18087465737433313033009f1808746573743331303400a0" + "1808746573743331303500a11808746573743331303600a21808746573743331303700a31808746573743331303800" + "a41808746573743331303900a51808746573743331313000a61808746573743331313100a718087465737433313132" + "00a81808746573743331313300a91808746573743331313400aa1808746573743331313500ab180874657374333131" + "3600ac1808746573743331313700ad1808746573743331313800ae1808746573743331313900af1808746573743331" + "323000b01808746573743331323100b11808746573743331323200b21808746573743331323300b318087465737433" + "31323400b41808746573743331323500b51808746573743331323600b61808746573743331323700b7180874657374" + "3331323800b81808746573743331323900b91808746573743331333000ba1808746573743331333100bb1808746573" + "743331333200bc1808746573743331333300bd1808746573743331333400be1808746573743331333500bf18087465" + "73743331333600c01808746573743331333700c11808746573743331333800c21808746573743331333900c3180874" + "6573743331343000c41808746573743331343100c51808746573743331343200c61808746573743331343300c71808" + "746573743331343400c81808746573743331343500c91808746573743331343600ca1808746573743331343700cb18" + "08746573743331343800cc1808746573743331343900cd1808746573743331353000ce1808746573743331353100cf" + "1808746573743331353200d01808746573743331353300d11808746573743331353400d21808746573743331353500" + "d31808746573743331353600d41808746573743331353700d51808746573743331353800d618087465737433313539" + "00d71808746573743331363000d81808746573743331363100d91808746573743331363200da180874657374333136" + "3300db1808746573743331363400dc1808746573743331363500dd1808746573743331363600de1808746573743331" + "363700df1808746573743331363800e01808746573743331363900e11808746573743331373000e218087465737433" + "31373100e31808746573743331373200e41808746573743331373300e51808746573743331373400e6180874657374" + "3331373500e71808746573743331373600e81808746573743331373700e91808746573743331373800ea1808746573" + "743331373900eb1808746573743331383000ec1808746573743331383100ed1808746573743331383200ee18087465" + "73743331383300ef1808746573743331383400f01808746573743331383500f11808746573743331383600f2180874" + "6573743331383700f31808746573743331383800f41808746573743331383900f51808746573743331393000f61808" + "746573743331393100f71808746573743331393200f81808746573743331393300f91808746573743331393400fa18" + "08746573743331393500fb1808746573743331393600fc1808746573743331393700fd1808746573743331393800fe" + "1808746573743331393900ff1808746573743332303000801908746573743332303100811908746573743332303200" + "8219087465737433323033008319087465737433323034008419087465737433323035008519087465737433323036" + "0086190874657374333230370087190874657374333230380088190874657374333230390089190874657374333231" + "30008a19087465737433323131008b19087465737433323132008c19087465737433323133008d1908746573743332" + "3134008e19087465737433323135008f19087465737433323136009019087465737433323137009119087465737433" + "3231380092190874657374333231390093190874657374333232300094190874657374333232310095190874657374" + "3332323200961908746573743332323300971908746573743332323400981908746573743332323500991908746573" + "7433323236009a19087465737433323237009b19087465737433323238009c19087465737433323239009d19087465" + "737433323330009e19087465737433323331009f1908746573743332333200a01908746573743332333300a1190874" + "6573743332333400a21908746573743332333500a31908746573743332333600a41908746573743332333700a51908" + "746573743332333800a61908746573743332333900a71908746573743332343000a81908746573743332343100a919" + "08746573743332343200aa1908746573743332343300ab1908746573743332343400ac1908746573743332343500ad" + "1908746573743332343600ae1908746573743332343700af1908746573743332343800b01908746573743332343900" + "b11908746573743332353000b21908746573743332353100b31908746573743332353200b419087465737433323533" + "00b51908746573743332353400b61908746573743332353500b71908746573743332353600b8190874657374333235" + "3700b91908746573743332353800ba1908746573743332353900bb1908746573743332363000bc1908746573743332" + "363100bd1908746573743332363200be1908746573743332363300bf1908746573743332363400c019087465737433" + "32363500c11908746573743332363600c21908746573743332363700c31908746573743332363800c4190874657374" + "3332363900c51908746573743332373000c61908746573743332373100c71908746573743332373200c81908746573" + "743332373300c91908746573743332373400ca1908746573743332373500cb1908746573743332373600cc19087465" + "73743332373700cd1908746573743332373800ce1908746573743332373900cf1908746573743332383000d0190874" + "6573743332383100d11908746573743332383200d21908746573743332383300d31908746573743332383400d41908" + "746573743332383500d51908746573743332383600d61908746573743332383700d71908746573743332383800d819" + "08746573743332383900d91908746573743332393000da1908746573743332393100db1908746573743332393200dc" + "1908746573743332393300dd1908746573743332393400de1908746573743332393500df1908746573743332393600" + "e01908746573743332393700e11908746573743332393800e21908746573743332393900e319087465737433333030" + "00e41908746573743333303100e51908746573743333303200e61908746573743333303300e7190874657374333330" + "3400e81908746573743333303500e91908746573743333303600ea1908746573743333303700eb1908746573743333" + "303800ec1908746573743333303900ed1908746573743333313000ee1908746573743333313100ef19087465737433" + "33313200f01908746573743333313300f11908746573743333313400f21908746573743333313500f3190874657374" + "3333313600f41908746573743333313700f51908746573743333313800f61908746573743333313900f71908746573" + "743333323000f81908746573743333323100f91908746573743333323200fa1908746573743333323300fb19087465" + "73743333323400fc1908746573743333323500fd1908746573743333323600fe1908746573743333323700ff190874" + "6573743333323800801a08746573743333323900811a08746573743333333000821a08746573743333333100831a08" + "746573743333333200841a08746573743333333300851a08746573743333333400861a08746573743333333500871a" + "08746573743333333600881a08746573743333333700891a087465737433333338008a1a087465737433333339008b" + "1a087465737433333430008c1a087465737433333431008d1a087465737433333432008e1a08746573743333343300" + "8f1a08746573743333343400901a08746573743333343500911a08746573743333343600921a087465737433333437" + "00931a08746573743333343800941a08746573743333343900951a08746573743333353000961a0874657374333335" + "3100971a08746573743333353200981a08746573743333353300991a087465737433333534009a1a08746573743333" + "3535009b1a087465737433333536009c1a087465737433333537009d1a087465737433333538009e1a087465737433" + "333539009f1a08746573743333363000a01a08746573743333363100a11a08746573743333363200a21a0874657374" + "3333363300a31a08746573743333363400a41a08746573743333363500a51a08746573743333363600a61a08746573" + "743333363700a71a08746573743333363800a81a08746573743333363900a91a08746573743333373000aa1a087465" + "73743333373100ab1a08746573743333373200ac1a08746573743333373300ad1a08746573743333373400ae1a0874" + "6573743333373500af1a08746573743333373600b01a08746573743333373700b11a08746573743333373800b21a08" + "746573743333373900b31a08746573743333383000b41a08746573743333383100b51a08746573743333383200b61a" + "08746573743333383300b71a08746573743333383400b81a08746573743333383500b91a08746573743333383600ba" + "1a08746573743333383700bb1a08746573743333383800bc1a08746573743333383900bd1a08746573743333393000" + "be1a08746573743333393100bf1a08746573743333393200c01a08746573743333393300c11a087465737433333934" + "00c21a08746573743333393500c31a08746573743333393600c41a08746573743333393700c51a0874657374333339" + "3800c61a08746573743333393900c71a08746573743334303000c81a08746573743334303100c91a08746573743334" + "303200ca1a08746573743334303300cb1a08746573743334303400cc1a08746573743334303500cd1a087465737433" + "34303600ce1a08746573743334303700cf1a08746573743334303800d01a08746573743334303900d11a0874657374" + "3334313000d21a08746573743334313100d31a08746573743334313200d41a08746573743334313300d51a08746573" + "743334313400d61a08746573743334313500d71a08746573743334313600d81a08746573743334313700d91a087465" + "73743334313800da1a08746573743334313900db1a08746573743334323000dc1a08746573743334323100dd1a0874" + "6573743334323200de1a08746573743334323300df1a08746573743334323400e01a08746573743334323500e11a08" + "746573743334323600e21a08746573743334323700e31a08746573743334323800e41a08746573743334323900e51a" + "08746573743334333000e61a08746573743334333100e71a08746573743334333200e81a08746573743334333300e9" + "1a08746573743334333400ea1a08746573743334333500eb1a08746573743334333600ec1a08746573743334333700" + "ed1a08746573743334333800ee1a08746573743334333900ef1a08746573743334343000f01a087465737433343431" + "00f11a08746573743334343200f21a08746573743334343300f31a08746573743334343400f41a0874657374333434" + "3500f51a08746573743334343600f61a08746573743334343700f71a08746573743334343800f81a08746573743334" + "343900f91a08746573743334353000fa1a08746573743334353100fb1a08746573743334353200fc1a087465737433" + "34353300fd1a08746573743334353400fe1a08746573743334353500ff1a08746573743334353600801b0874657374" + "3334353700811b08746573743334353800821b08746573743334353900831b08746573743334363000841b08746573" + "743334363100851b08746573743334363200861b08746573743334363300871b08746573743334363400881b087465" + "73743334363500891b087465737433343636008a1b087465737433343637008b1b087465737433343638008c1b0874" + "65737433343639008d1b087465737433343730008e1b087465737433343731008f1b08746573743334373200901b08" + "746573743334373300911b08746573743334373400921b08746573743334373500931b08746573743334373600941b" + "08746573743334373700951b08746573743334373800961b08746573743334373900971b0874657374333438300098" + "1b08746573743334383100991b087465737433343832009a1b087465737433343833009b1b08746573743334383400" + "9c1b087465737433343835009d1b087465737433343836009e1b087465737433343837009f1b087465737433343838" + "00a01b08746573743334383900a11b08746573743334393000a21b08746573743334393100a31b0874657374333439" + "3200a41b08746573743334393300a51b08746573743334393400a61b08746573743334393500a71b08746573743334" + "393600a81b08746573743334393700a91b08746573743334393800aa1b08746573743334393900ab1b087465737433" + "35303000ac1b08746573743335303100ad1b08746573743335303200ae1b08746573743335303300af1b0874657374" + "3335303400b01b08746573743335303500b11b08746573743335303600b21b08746573743335303700b31b08746573" + "743335303800b41b08746573743335303900b51b08746573743335313000b61b08746573743335313100b71b087465" + "73743335313200b81b08746573743335313300b91b08746573743335313400ba1b08746573743335313500bb1b0874" + "6573743335313600bc1b08746573743335313700bd1b08746573743335313800be1b08746573743335313900bf1b08" + "746573743335323000c01b08746573743335323100c11b08746573743335323200c21b08746573743335323300c31b" + "08746573743335323400c41b08746573743335323500c51b08746573743335323600c61b08746573743335323700c7" + "1b08746573743335323800c81b08746573743335323900c91b08746573743335333000ca1b08746573743335333100" + "cb1b08746573743335333200cc1b08746573743335333300cd1b08746573743335333400ce1b087465737433353335" + "00cf1b08746573743335333600d01b08746573743335333700d11b08746573743335333800d21b0874657374333533" + "3900d31b08746573743335343000d41b08746573743335343100d51b08746573743335343200d61b08746573743335" + "343300d71b08746573743335343400d81b08746573743335343500d91b08746573743335343600da1b087465737433" + "35343700db1b08746573743335343800dc1b08746573743335343900dd1b08746573743335353000de1b0874657374" + "3335353100df1b08746573743335353200e01b08746573743335353300e11b08746573743335353400e21b08746573" + "743335353500e31b08746573743335353600e41b08746573743335353700e51b08746573743335353800e61b087465" + "73743335353900e71b08746573743335363000e81b08746573743335363100e91b08746573743335363200ea1b0874" + "6573743335363300eb1b08746573743335363400ec1b08746573743335363500ed1b08746573743335363600ee1b08" + "746573743335363700ef1b08746573743335363800f01b08746573743335363900f11b08746573743335373000f21b" + "08746573743335373100f31b08746573743335373200f41b08746573743335373300f51b08746573743335373400f6" + "1b08746573743335373500f71b08746573743335373600f81b08746573743335373700f91b08746573743335373800" + "fa1b08746573743335373900fb1b08746573743335383000fc1b08746573743335383100fd1b087465737433353832" + "00fe1b08746573743335383300ff1b08746573743335383400801c08746573743335383500811c0874657374333538" + "3600821c08746573743335383700831c08746573743335383800841c08746573743335383900851c08746573743335" + "393000861c08746573743335393100871c08746573743335393200881c08746573743335393300891c087465737433" + "353934008a1c087465737433353935008b1c087465737433353936008c1c087465737433353937008d1c0874657374" + "33353938008e1c087465737433353939008f1c08746573743336303000901c08746573743336303100911c08746573" + "743336303200921c08746573743336303300931c08746573743336303400941c08746573743336303500951c087465" + "73743336303600961c08746573743336303700971c08746573743336303800981c08746573743336303900991c0874" + "65737433363130009a1c087465737433363131009b1c087465737433363132009c1c087465737433363133009d1c08" + "7465737433363134009e1c087465737433363135009f1c08746573743336313600a01c08746573743336313700a11c" + "08746573743336313800a21c08746573743336313900a31c08746573743336323000a41c08746573743336323100a5" + "1c08746573743336323200a61c08746573743336323300a71c08746573743336323400a81c08746573743336323500" + "a91c08746573743336323600aa1c08746573743336323700ab1c08746573743336323800ac1c087465737433363239" + "00ad1c08746573743336333000ae1c08746573743336333100af1c08746573743336333200b01c0874657374333633" + "3300b11c08746573743336333400b21c08746573743336333500b31c08746573743336333600b41c08746573743336" + "333700b51c08746573743336333800b61c08746573743336333900b71c08746573743336343000b81c087465737433" + "36343100b91c08746573743336343200ba1c08746573743336343300bb1c08746573743336343400bc1c0874657374" + "3336343500bd1c08746573743336343600be1c08746573743336343700bf1c08746573743336343800c01c08746573" + "743336343900c11c08746573743336353000c21c08746573743336353100c31c08746573743336353200c41c087465" + "73743336353300c51c08746573743336353400c61c08746573743336353500c71c08746573743336353600c81c0874" + "6573743336353700c91c08746573743336353800ca1c08746573743336353900cb1c08746573743336363000cc1c08" + "746573743336363100cd1c08746573743336363200ce1c08746573743336363300cf1c08746573743336363400d01c" + "08746573743336363500d11c08746573743336363600d21c08746573743336363700d31c08746573743336363800d4" + "1c08746573743336363900d51c08746573743336373000d61c08746573743336373100d71c08746573743336373200" + "d81c08746573743336373300d91c08746573743336373400da1c08746573743336373500db1c087465737433363736" + "00dc1c08746573743336373700dd1c08746573743336373800de1c08746573743336373900df1c0874657374333638" + "3000e01c08746573743336383100e11c08746573743336383200e21c08746573743336383300e31c08746573743336" + "383400e41c08746573743336383500e51c08746573743336383600e61c08746573743336383700e71c087465737433" + "36383800e81c08746573743336383900e91c08746573743336393000ea1c08746573743336393100eb1c0874657374" + "3336393200ec1c08746573743336393300ed1c08746573743336393400ee1c08746573743336393500ef1c08746573" + "743336393600f01c08746573743336393700f11c08746573743336393800f21c08746573743336393900f31c087465" + "73743337303000f41c08746573743337303100f51c08746573743337303200f61c08746573743337303300f71c0874" + "6573743337303400f81c08746573743337303500f91c08746573743337303600fa1c08746573743337303700fb1c08" + "746573743337303800fc1c08746573743337303900fd1c08746573743337313000fe1c08746573743337313100ff1c" + "08746573743337313200801d08746573743337313300811d08746573743337313400821d0874657374333731350083" + "1d08746573743337313600841d08746573743337313700851d08746573743337313800861d08746573743337313900" + "871d08746573743337323000881d08746573743337323100891d087465737433373232008a1d087465737433373233" + "008b1d087465737433373234008c1d087465737433373235008d1d087465737433373236008e1d0874657374333732" + "37008f1d08746573743337323800901d08746573743337323900911d08746573743337333000921d08746573743337" + "333100931d08746573743337333200941d08746573743337333300951d08746573743337333400961d087465737433" + "37333500971d08746573743337333600981d08746573743337333700991d087465737433373338009a1d0874657374" + "33373339009b1d087465737433373430009c1d087465737433373431009d1d087465737433373432009e1d08746573" + "7433373433009f1d08746573743337343400a01d08746573743337343500a11d08746573743337343600a21d087465" + "73743337343700a31d08746573743337343800a41d08746573743337343900a51d08746573743337353000a61d0874" + "6573743337353100a71d08746573743337353200a81d08746573743337353300a91d08746573743337353400aa1d08" + "746573743337353500ab1d08746573743337353600ac1d08746573743337353700ad1d08746573743337353800ae1d" + "08746573743337353900af1d08746573743337363000b01d08746573743337363100b11d08746573743337363200b2" + "1d08746573743337363300b31d08746573743337363400b41d08746573743337363500b51d08746573743337363600" + "b61d08746573743337363700b71d08746573743337363800b81d08746573743337363900b91d087465737433373730" + "00ba1d08746573743337373100bb1d08746573743337373200bc1d08746573743337373300bd1d0874657374333737" + "3400be1d08746573743337373500bf1d08746573743337373600c01d08746573743337373700c11d08746573743337" + "373800c21d08746573743337373900c31d08746573743337383000c41d08746573743337383100c51d087465737433" + "37383200c61d08746573743337383300c71d08746573743337383400c81d08746573743337383500c91d0874657374" + "3337383600ca1d08746573743337383700cb1d08746573743337383800cc1d08746573743337383900cd1d08746573" + "743337393000ce1d08746573743337393100cf1d08746573743337393200d01d08746573743337393300d11d087465" + "73743337393400d21d08746573743337393500d31d08746573743337393600d41d08746573743337393700d51d0874" + "6573743337393800d61d08746573743337393900d71d08746573743338303000d81d08746573743338303100d91d08" + "746573743338303200da1d08746573743338303300db1d08746573743338303400dc1d08746573743338303500dd1d" + "08746573743338303600de1d08746573743338303700df1d08746573743338303800e01d08746573743338303900e1" + "1d08746573743338313000e21d08746573743338313100e31d08746573743338313200e41d08746573743338313300" + "e51d08746573743338313400e61d08746573743338313500e71d08746573743338313600e81d087465737433383137" + "00e91d08746573743338313800ea1d08746573743338313900eb1d08746573743338323000ec1d0874657374333832" + "3100ed1d08746573743338323200ee1d08746573743338323300ef1d08746573743338323400f01d08746573743338" + "323500f11d08746573743338323600f21d08746573743338323700f31d08746573743338323800f41d087465737433" + "38323900f51d08746573743338333000f61d08746573743338333100f71d08746573743338333200f81d0874657374" + "3338333300f91d08746573743338333400fa1d08746573743338333500fb1d08746573743338333600fc1d08746573" + "743338333700fd1d08746573743338333800fe1d08746573743338333900ff1d08746573743338343000801e087465" + "73743338343100811e08746573743338343200821e08746573743338343300831e08746573743338343400841e0874" + "6573743338343500851e08746573743338343600861e08746573743338343700871e08746573743338343800881e08" + "746573743338343900891e087465737433383530008a1e087465737433383531008b1e087465737433383532008c1e" + "087465737433383533008d1e087465737433383534008e1e087465737433383535008f1e0874657374333835360090" + "1e08746573743338353700911e08746573743338353800921e08746573743338353900931e08746573743338363000" + "941e08746573743338363100951e08746573743338363200961e08746573743338363300971e087465737433383634" + "00981e08746573743338363500991e087465737433383636009a1e087465737433383637009b1e0874657374333836" + "38009c1e087465737433383639009d1e087465737433383730009e1e087465737433383731009f1e08746573743338" + "373200a01e08746573743338373300a11e08746573743338373400a21e08746573743338373500a31e087465737433" + "38373600a41e08746573743338373700a51e08746573743338373800a61e08746573743338373900a71e0874657374" + "3338383000a81e08746573743338383100a91e08746573743338383200aa1e08746573743338383300ab1e08746573" + "743338383400ac1e08746573743338383500ad1e08746573743338383600ae1e08746573743338383700af1e087465" + "73743338383800b01e08746573743338383900b11e08746573743338393000b21e08746573743338393100b31e0874" + "6573743338393200b41e08746573743338393300b51e08746573743338393400b61e08746573743338393500b71e08" + "746573743338393600b81e08746573743338393700b91e08746573743338393800ba1e08746573743338393900bb1e" + "08746573743339303000bc1e08746573743339303100bd1e08746573743339303200be1e08746573743339303300bf" + "1e08746573743339303400c01e08746573743339303500c11e08746573743339303600c21e08746573743339303700" + "c31e08746573743339303800c41e08746573743339303900c51e08746573743339313000c61e087465737433393131" + "00c71e08746573743339313200c81e08746573743339313300c91e08746573743339313400ca1e0874657374333931" + "3500cb1e08746573743339313600cc1e08746573743339313700cd1e08746573743339313800ce1e08746573743339" + "313900cf1e08746573743339323000d01e08746573743339323100d11e08746573743339323200d21e087465737433" + "39323300d31e08746573743339323400d41e08746573743339323500d51e08746573743339323600d61e0874657374" + "3339323700d71e08746573743339323800d81e08746573743339323900d91e08746573743339333000da1e08746573" + "743339333100db1e08746573743339333200dc1e08746573743339333300dd1e08746573743339333400de1e087465" + "73743339333500df1e08746573743339333600e01e08746573743339333700e11e08746573743339333800e21e0874" + "6573743339333900e31e08746573743339343000e41e08746573743339343100e51e08746573743339343200e61e08" + "746573743339343300e71e08746573743339343400e81e08746573743339343500e91e08746573743339343600ea1e" + "08746573743339343700eb1e08746573743339343800ec1e08746573743339343900ed1e08746573743339353000ee" + "1e08746573743339353100ef1e08746573743339353200f01e08746573743339353300f11e08746573743339353400" + "f21e08746573743339353500f31e08746573743339353600f41e08746573743339353700f51e087465737433393538" + "00f61e08746573743339353900f71e08746573743339363000f81e08746573743339363100f91e0874657374333936" + "3200fa1e08746573743339363300fb1e08746573743339363400fc1e08746573743339363500fd1e08746573743339" + "363600fe1e08746573743339363700ff1e08746573743339363800801f08746573743339363900811f087465737433" + "39373000821f08746573743339373100831f08746573743339373200841f08746573743339373300851f0874657374" + "3339373400861f08746573743339373500871f08746573743339373600881f08746573743339373700891f08746573" + "7433393738008a1f087465737433393739008b1f087465737433393830008c1f087465737433393831008d1f087465" + "737433393832008e1f087465737433393833008f1f08746573743339383400901f08746573743339383500911f0874" + "6573743339383600921f08746573743339383700931f08746573743339383800941f08746573743339383900951f08" + "746573743339393000961f08746573743339393100971f08746573743339393200981f08746573743339393300991f" + "087465737433393934009a1f087465737433393935009b1f087465737433393936009c1f087465737433393937009d" + "1f087465737433393938009e1f087465737433393939009f1f08746573743430303000a01f08746573743430303100" + "a11f08746573743430303200a21f08746573743430303300a31f08746573743430303400a41f087465737434303035" + "00a51f08746573743430303600a61f08746573743430303700a71f08746573743430303800a81f0874657374343030" + "3900a91f08746573743430313000aa1f08746573743430313100ab1f08746573743430313200ac1f08746573743430" + "313300ad1f08746573743430313400ae1f08746573743430313500af1f08746573743430313600b01f087465737434" + "30313700b11f08746573743430313800b21f08746573743430313900b31f08746573743430323000b41f0874657374" + "3430323100b51f08746573743430323200b61f08746573743430323300b71f08746573743430323400b81f08746573" + "743430323500b91f08746573743430323600ba1f08746573743430323700bb1f08746573743430323800bc1f087465" + "73743430323900bd1f08746573743430333000be1f08746573743430333100bf1f08746573743430333200c01f0874" + "6573743430333300c11f08746573743430333400c21f08746573743430333500c31f08746573743430333600c41f08" + "746573743430333700c51f08746573743430333800c61f08746573743430333900c71f08746573743430343000c81f" + "08746573743430343100c91f08746573743430343200ca1f08746573743430343300cb1f08746573743430343400cc" + "1f08746573743430343500cd1f08746573743430343600ce1f08746573743430343700cf1f08746573743430343800" + "d01f08746573743430343900d11f08746573743430353000d21f08746573743430353100d31f087465737434303532" + "00d41f08746573743430353300d51f08746573743430353400d61f08746573743430353500d71f0874657374343035" + "3600d81f08746573743430353700d91f08746573743430353800da1f08746573743430353900db1f08746573743430" + "363000dc1f08746573743430363100dd1f08746573743430363200de1f08746573743430363300df1f087465737434" + "30363400e01f08746573743430363500e11f08746573743430363600e21f08746573743430363700e31f0874657374" + "3430363800e41f08746573743430363900e51f08746573743430373000e61f08746573743430373100e71f08746573" + "743430373200e81f08746573743430373300e91f08746573743430373400ea1f08746573743430373500eb1f087465" + "73743430373600ec1f08746573743430373700ed1f08746573743430373800ee1f08746573743430373900ef1f0874" + "6573743430383000f01f08746573743430383100f11f08746573743430383200f21f08746573743430383300f31f08" + "746573743430383400f41f08746573743430383500f51f08746573743430383600f61f08746573743430383700f71f" + "08746573743430383800f81f08746573743430383900f91f08746573743430393000fa1f08746573743430393100fb" + "1f08746573743430393200fc1f08746573743430393300fd1f08746573743430393400fe1f08746573743430393500" + "ff1f087465737434303936008020087465737434303937008120087465737434303938008220087465737434303939" + "0083200874657374343130300084200874657374343130310085200874657374343130320086200874657374343130" + "33008720087465737434313034008820087465737434313035008920087465737434313036008a2008746573743431" + "3037008b20087465737434313038008c20087465737434313039008d20087465737434313130008e20087465737434" + "313131008f200874657374343131320090200874657374343131330091200874657374343131340092200874657374" + "3431313500932008746573743431313600942008746573743431313700952008746573743431313800962008746573" + "7434313139009720087465737434313230009820087465737434313231009920087465737434313232009a20087465" + "737434313233009b20087465737434313234009c20087465737434313235009d20087465737434313236009e200874" + "65737434313237009f2008746573743431323800a02008746573743431323900a12008746573743431333000a22008" + "746573743431333100a32008746573743431333200a42008746573743431333300a52008746573743431333400a620" + "08746573743431333500a72008746573743431333600a82008746573743431333700a92008746573743431333800aa" + "2008746573743431333900ab2008746573743431343000ac2008746573743431343100ad2008746573743431343200" + "ae2008746573743431343300af2008746573743431343400b02008746573743431343500b120087465737434313436" + "00b22008746573743431343700b32008746573743431343800b42008746573743431343900b5200874657374343135" + "3000b62008746573743431353100b72008746573743431353200b82008746573743431353300b92008746573743431" + "353400ba2008746573743431353500bb2008746573743431353600bc2008746573743431353700bd20087465737434" + "31353800be2008746573743431353900bf2008746573743431363000c02008746573743431363100c1200874657374" + "3431363200c22008746573743431363300c32008746573743431363400c42008746573743431363500c52008746573" + "743431363600c62008746573743431363700c72008746573743431363800c82008746573743431363900c920087465" + "73743431373000ca2008746573743431373100cb2008746573743431373200cc2008746573743431373300cd200874" + "6573743431373400ce2008746573743431373500cf2008746573743431373600d02008746573743431373700d12008" + "746573743431373800d22008746573743431373900d32008746573743431383000d42008746573743431383100d520" + "08746573743431383200d62008746573743431383300d72008746573743431383400d82008746573743431383500d9" + "2008746573743431383600da2008746573743431383700db2008746573743431383800dc2008746573743431383900" + "dd2008746573743431393000de2008746573743431393100df2008746573743431393200e020087465737434313933" + "00e12008746573743431393400e22008746573743431393500e32008746573743431393600e4200874657374343139" + "3700e52008746573743431393800e62008746573743431393900e72008746573743432303000e82008746573743432" + "303100e92008746573743432303200ea2008746573743432303300eb2008746573743432303400ec20087465737434" + "32303500ed2008746573743432303600ee2008746573743432303700ef2008746573743432303800f0200874657374" + "3432303900f12008746573743432313000f22008746573743432313100f32008746573743432313200f42008746573" + "743432313300f52008746573743432313400f62008746573743432313500f72008746573743432313600f820087465" + "73743432313700f92008746573743432313800fa2008746573743432313900fb2008746573743432323000fc200874" + "6573743432323100fd2008746573743432323200fe2008746573743432323300ff2008746573743432323400802108" + "7465737434323235008121087465737434323236008221087465737434323237008321087465737434323238008421" + "0874657374343232390085210874657374343233300086210874657374343233310087210874657374343233320088" + "21087465737434323333008921087465737434323334008a21087465737434323335008b2108746573743432333600" + "8c21087465737434323337008d21087465737434323338008e21087465737434323339008f21087465737434323430" + "0090210874657374343234310091210874657374343234320092210874657374343234330093210874657374343234" + "3400942108746573743432343500952108746573743432343600962108746573743432343700972108746573743432" + "3438009821087465737434323439009921087465737434323530009a21087465737434323531009b21087465737434" + "323532009c21087465737434323533009d21087465737434323534009e21087465737434323535009f210874657374" + "3432353600a02108746573743432353700a12108746573743432353800a22108746573743432353900a32108746573" + "743432363000a42108746573743432363100a52108746573743432363200a62108746573743432363300a721087465" + "73743432363400a82108746573743432363500a92108746573743432363600aa2108746573743432363700ab210874" + "6573743432363800ac2108746573743432363900ad2108746573743432373000ae2108746573743432373100af2108" + "746573743432373200b02108746573743432373300b12108746573743432373400b22108746573743432373500b321" + "08746573743432373600b42108746573743432373700b52108746573743432373800b62108746573743432373900b7" + "2108746573743432383000b82108746573743432383100b92108746573743432383200ba2108746573743432383300" + "bb2108746573743432383400bc2108746573743432383500bd2108746573743432383600be21087465737434323837" + "00bf2108746573743432383800c02108746573743432383900c12108746573743432393000c2210874657374343239" + "3100c32108746573743432393200c42108746573743432393300c52108746573743432393400c62108746573743432" + "393500c72108746573743432393600c82108746573743432393700c92108746573743432393800ca21087465737434" + "32393900cb2108746573743433303000cc2108746573743433303100cd2108746573743433303200ce210874657374" + "3433303300cf2108746573743433303400d02108746573743433303500d12108746573743433303600d22108746573" + "743433303700d32108746573743433303800d42108746573743433303900d52108746573743433313000d621087465" + "73743433313100d72108746573743433313200d82108746573743433313300d92108746573743433313400da210874" + "6573743433313500db2108746573743433313600dc2108746573743433313700dd2108746573743433313800de2108" + "746573743433313900df2108746573743433323000e02108746573743433323100e12108746573743433323200e221" + "08746573743433323300e32108746573743433323400e42108746573743433323500e52108746573743433323600e6" + "2108746573743433323700e72108746573743433323800e82108746573743433323900e92108746573743433333000" + "ea2108746573743433333100eb2108746573743433333200ec2108746573743433333300ed21087465737434333334" + "00ee2108746573743433333500ef2108746573743433333600f02108746573743433333700f1210874657374343333" + "3800f22108746573743433333900f32108746573743433343000f42108746573743433343100f52108746573743433" + "343200f62108746573743433343300f72108746573743433343400f82108746573743433343500f921087465737434" + "33343600fa2108746573743433343700fb2108746573743433343800fc2108746573743433343900fd210874657374" + "3433353000fe2108746573743433353100ff2108746573743433353200802208746573743433353300812208746573" + "7434333534008222087465737434333535008322087465737434333536008422087465737434333537008522087465" + "7374343335380086220874657374343335390087220874657374343336300088220874657374343336310089220874" + "65737434333632008a22087465737434333633008b22087465737434333634008c22087465737434333635008d2208" + "7465737434333636008e22087465737434333637008f22087465737434333638009022087465737434333639009122" + "0874657374343337300092220874657374343337310093220874657374343337320094220874657374343337330095" + "2208746573743433373400962208746573743433373500972208746573743433373600982208746573743433373700" + "9922087465737434333738009a22087465737434333739009b22087465737434333830009c22087465737434333831" + "009d22087465737434333832009e22087465737434333833009f2208746573743433383400a0220874657374343338" + "3500a12208746573743433383600a22208746573743433383700a32208746573743433383800a42208746573743433" + "383900a52208746573743433393000a62208746573743433393100a72208746573743433393200a822087465737434" + "33393300a92208746573743433393400aa2208746573743433393500ab2208746573743433393600ac220874657374" + "3433393700ad2208746573743433393800ae2208746573743433393900af2208746573743434303000b02208746573" + "743434303100b12208746573743434303200b22208746573743434303300b32208746573743434303400b422087465" + "73743434303500b52208746573743434303600b62208746573743434303700b72208746573743434303800b8220874" + "6573743434303900b92208746573743434313000ba2208746573743434313100bb2208746573743434313200bc2208" + "746573743434313300bd2208746573743434313400be2208746573743434313500bf2208746573743434313600c022" + "08746573743434313700c12208746573743434313800c22208746573743434313900c32208746573743434323000c4" + "2208746573743434323100c52208746573743434323200c62208746573743434323300c72208746573743434323400" + "c82208746573743434323500c92208746573743434323600ca2208746573743434323700cb22087465737434343238" + "00cc2208746573743434323900cd2208746573743434333000ce2208746573743434333100cf220874657374343433" + "3200d02208746573743434333300d12208746573743434333400d22208746573743434333500d32208746573743434" + "333600d42208746573743434333700d52208746573743434333800d62208746573743434333900d722087465737434" + "34343000d82208746573743434343100d92208746573743434343200da2208746573743434343300db220874657374" + "3434343400dc2208746573743434343500dd2208746573743434343600de2208746573743434343700df2208746573" + "743434343800e02208746573743434343900e12208746573743434353000e22208746573743434353100e322087465" + "73743434353200e42208746573743434353300e52208746573743434353400e62208746573743434353500e7220874" + "6573743434353600e82208746573743434353700e92208746573743434353800ea2208746573743434353900eb2208" + "746573743434363000ec2208746573743434363100ed2208746573743434363200ee2208746573743434363300ef22" + "08746573743434363400f02208746573743434363500f12208746573743434363600f22208746573743434363700f3" + "2208746573743434363800f42208746573743434363900f52208746573743434373000f62208746573743434373100" + "f72208746573743434373200f82208746573743434373300f92208746573743434373400fa22087465737434343735" + "00fb2208746573743434373600fc2208746573743434373700fd2208746573743434373800fe220874657374343437" + "3900ff2208746573743434383000802308746573743434383100812308746573743434383200822308746573743434" + "3833008323087465737434343834008423087465737434343835008523087465737434343836008623087465737434" + "343837008723087465737434343838008823087465737434343839008923087465737434343930008a230874657374" + "34343931008b23087465737434343932008c23087465737434343933008d23087465737434343934008e2308746573" + "7434343935008f23087465737434343936009023087465737434343937009123087465737434343938009223087465" + "7374343439390093230874657374343530300094230874657374343530310095230874657374343530320096230874" + "65737434353033009723087465737434353034009823087465737434353035009923087465737434353036009a2308" + "7465737434353037009b23087465737434353038009c23087465737434353039009d23087465737434353130009e23" + "087465737434353131009f2308746573743435313200a02308746573743435313300a12308746573743435313400a2" + "2308746573743435313500a32308746573743435313600a42308746573743435313700a52308746573743435313800" + "a62308746573743435313900a72308746573743435323000a82308746573743435323100a923087465737434353232" + "00aa2308746573743435323300ab2308746573743435323400ac2308746573743435323500ad230874657374343532" + "3600ae2308746573743435323700af2308746573743435323800b02308746573743435323900b12308746573743435" + "333000b22308746573743435333100b32308746573743435333200b42308746573743435333300b523087465737434" + "35333400b62308746573743435333500b72308746573743435333600b82308746573743435333700b9230874657374" + "3435333800ba2308746573743435333900bb2308746573743435343000bc2308746573743435343100bd2308746573" + "743435343200be2308746573743435343300bf2308746573743435343400c02308746573743435343500c123087465" + "73743435343600c22308746573743435343700c32308746573743435343800c42308746573743435343900c5230874" + "6573743435353000c62308746573743435353100c72308746573743435353200c82308746573743435353300c92308" + "746573743435353400ca2308746573743435353500cb2308746573743435353600cc2308746573743435353700cd23" + "08746573743435353800ce2308746573743435353900cf2308746573743435363000d02308746573743435363100d1" + "2308746573743435363200d22308746573743435363300d32308746573743435363400d42308746573743435363500" + "d52308746573743435363600d62308746573743435363700d72308746573743435363800d823087465737434353639" + "00d92308746573743435373000da2308746573743435373100db2308746573743435373200dc230874657374343537" + "3300dd2308746573743435373400de2308746573743435373500df2308746573743435373600e02308746573743435" + "373700e12308746573743435373800e22308746573743435373900e32308746573743435383000e423087465737434" + "35383100e52308746573743435383200e62308746573743435383300e72308746573743435383400e8230874657374" + "3435383500e92308746573743435383600ea2308746573743435383700eb2308746573743435383800ec2308746573" + "743435383900ed2308746573743435393000ee2308746573743435393100ef2308746573743435393200f023087465" + "73743435393300f12308746573743435393400f22308746573743435393500f32308746573743435393600f4230874" + "6573743435393700f52308746573743435393800f62308746573743435393900f72308746573743436303000f82308" + "746573743436303100f92308746573743436303200fa2308746573743436303300fb2308746573743436303400fc23" + "08746573743436303500fd2308746573743436303600fe2308746573743436303700ff230874657374343630380080" + "2408746573743436303900812408746573743436313000822408746573743436313100832408746573743436313200" + "8424087465737434363133008524087465737434363134008624087465737434363135008724087465737434363136" + "008824087465737434363137008924087465737434363138008a24087465737434363139008b240874657374343632" + "30008c24087465737434363231008d24087465737434363232008e24087465737434363233008f2408746573743436" + "3234009024087465737434363235009124087465737434363236009224087465737434363237009324087465737434" + "3632380094240874657374343632390095240874657374343633300096240874657374343633310097240874657374" + "34363332009824087465737434363333009924087465737434363334009a24087465737434363335009b2408746573" + "7434363336009c24087465737434363337009d24087465737434363338009e24087465737434363339009f24087465" + "73743436343000a02408746573743436343100a12408746573743436343200a22408746573743436343300a3240874" + "6573743436343400a42408746573743436343500a52408746573743436343600a62408746573743436343700a72408" + "746573743436343800a82408746573743436343900a92408746573743436353000aa2408746573743436353100ab24" + "08746573743436353200ac2408746573743436353300ad2408746573743436353400ae2408746573743436353500af" + "2408746573743436353600b02408746573743436353700b12408746573743436353800b22408746573743436353900" + "b32408746573743436363000b42408746573743436363100b52408746573743436363200b624087465737434363633" + "00b72408746573743436363400b82408746573743436363500b92408746573743436363600ba240874657374343636" + "3700bb2408746573743436363800bc2408746573743436363900bd2408746573743436373000be2408746573743436" + "373100bf2408746573743436373200c02408746573743436373300c12408746573743436373400c224087465737434" + "36373500c32408746573743436373600c42408746573743436373700c52408746573743436373800c6240874657374" + "3436373900c72408746573743436383000c82408746573743436383100c92408746573743436383200ca2408746573" + "743436383300cb2408746573743436383400cc2408746573743436383500cd2408746573743436383600ce24087465" + "73743436383700cf2408746573743436383800d02408746573743436383900d12408746573743436393000d2240874" + "6573743436393100d32408746573743436393200d42408746573743436393300d52408746573743436393400d62408" + "746573743436393500d72408746573743436393600d82408746573743436393700d92408746573743436393800da24" + "08746573743436393900db2408746573743437303000dc2408746573743437303100dd2408746573743437303200de" + "2408746573743437303300df2408746573743437303400e02408746573743437303500e12408746573743437303600" + "e22408746573743437303700e32408746573743437303800e42408746573743437303900e524087465737434373130" + "00e62408746573743437313100e72408746573743437313200e82408746573743437313300e9240874657374343731" + "3400ea2408746573743437313500eb2408746573743437313600ec2408746573743437313700ed2408746573743437" + "313800ee2408746573743437313900ef2408746573743437323000f02408746573743437323100f124087465737434" + "37323200f22408746573743437323300f32408746573743437323400f42408746573743437323500f5240874657374" + "3437323600f62408746573743437323700f72408746573743437323800f82408746573743437323900f92408746573" + "743437333000fa2408746573743437333100fb2408746573743437333200fc2408746573743437333300fd24087465" + "73743437333400fe2408746573743437333500ff240874657374343733360080250874657374343733370081250874" + "6573743437333800822508746573743437333900832508746573743437343000842508746573743437343100852508" + "7465737434373432008625087465737434373433008725087465737434373434008825087465737434373435008925" + "087465737434373436008a25087465737434373437008b25087465737434373438008c25087465737434373439008d" + "25087465737434373530008e25087465737434373531008f2508746573743437353200902508746573743437353300" + "9125087465737434373534009225087465737434373535009325087465737434373536009425087465737434373537" + "0095250874657374343735380096250874657374343735390097250874657374343736300098250874657374343736" + "31009925087465737434373632009a25087465737434373633009b25087465737434373634009c2508746573743437" + "3635009d25087465737434373636009e25087465737434373637009f2508746573743437363800a025087465737434" + "37363900a12508746573743437373000a22508746573743437373100a32508746573743437373200a4250874657374" + "3437373300a52508746573743437373400a62508746573743437373500a72508746573743437373600a82508746573" + "743437373700a92508746573743437373800aa2508746573743437373900ab2508746573743437383000ac25087465" + "73743437383100ad2508746573743437383200ae2508746573743437383300af2508746573743437383400b0250874" + "6573743437383500b12508746573743437383600b22508746573743437383700b32508746573743437383800b42508" + "746573743437383900b52508746573743437393000b62508746573743437393100b72508746573743437393200b825" + "08746573743437393300b92508746573743437393400ba2508746573743437393500bb2508746573743437393600bc" + "2508746573743437393700bd2508746573743437393800be2508746573743437393900bf2508746573743438303000" + "c02508746573743438303100c12508746573743438303200c22508746573743438303300c325087465737434383034" + "00c42508746573743438303500c52508746573743438303600c62508746573743438303700c7250874657374343830" + "3800c82508746573743438303900c92508746573743438313000ca2508746573743438313100cb2508746573743438" + "313200cc2508746573743438313300cd2508746573743438313400ce2508746573743438313500cf25087465737434" + "38313600d02508746573743438313700d12508746573743438313800d22508746573743438313900d3250874657374" + "3438323000d42508746573743438323100d52508746573743438323200d62508746573743438323300d72508746573" + "743438323400d82508746573743438323500d92508746573743438323600da2508746573743438323700db25087465" + "73743438323800dc2508746573743438323900dd2508746573743438333000de2508746573743438333100df250874" + "6573743438333200e02508746573743438333300e12508746573743438333400e22508746573743438333500e32508" + "746573743438333600e42508746573743438333700e52508746573743438333800e62508746573743438333900e725" + "08746573743438343000e82508746573743438343100e92508746573743438343200ea2508746573743438343300eb" + "2508746573743438343400ec2508746573743438343500ed2508746573743438343600ee2508746573743438343700" + "ef2508746573743438343800f02508746573743438343900f12508746573743438353000f225087465737434383531" + "00f32508746573743438353200f42508746573743438353300f52508746573743438353400f6250874657374343835" + "3500f72508746573743438353600f82508746573743438353700f92508746573743438353800fa2508746573743438" + "353900fb2508746573743438363000fc2508746573743438363100fd2508746573743438363200fe25087465737434" + "38363300ff250874657374343836340080260874657374343836350081260874657374343836360082260874657374" + "3438363700832608746573743438363800842608746573743438363900852608746573743438373000862608746573" + "7434383731008726087465737434383732008826087465737434383733008926087465737434383734008a26087465" + "737434383735008b26087465737434383736008c26087465737434383737008d26087465737434383738008e260874" + "65737434383739008f2608746573743438383000902608746573743438383100912608746573743438383200922608" + "7465737434383833009326087465737434383834009426087465737434383835009526087465737434383836009626" + "087465737434383837009726087465737434383838009826087465737434383839009926087465737434383930009a" + "26087465737434383931009b26087465737434383932009c26087465737434383933009d2608746573743438393400" + "9e26087465737434383935009f2608746573743438393600a02608746573743438393700a126087465737434383938" + "00a22608746573743438393900a32608746573743439303000a42608746573743439303100a5260874657374343930" + "3200a62608746573743439303300a72608746573743439303400a82608746573743439303500a92608746573743439" + "303600aa2608746573743439303700ab2608746573743439303800ac2608746573743439303900ad26087465737434" + "39313000ae2608746573743439313100af2608746573743439313200b02608746573743439313300b1260874657374" + "3439313400b22608746573743439313500b32608746573743439313600b42608746573743439313700b52608746573" + "743439313800b62608746573743439313900b72608746573743439323000b82608746573743439323100b926087465" + "73743439323200ba2608746573743439323300bb2608746573743439323400bc2608746573743439323500bd260874" + "6573743439323600be2608746573743439323700bf2608746573743439323800c02608746573743439323900c12608" + "746573743439333000c22608746573743439333100c32608746573743439333200c42608746573743439333300c526" + "08746573743439333400c62608746573743439333500c72608746573743439333600c82608746573743439333700c9" + "2608746573743439333800ca2608746573743439333900cb2608746573743439343000cc2608746573743439343100" + "cd2608746573743439343200ce2608746573743439343300cf2608746573743439343400d026087465737434393435" + "00d12608746573743439343600d22608746573743439343700d32608746573743439343800d4260874657374343934" + "3900d52608746573743439353000d62608746573743439353100d72608746573743439353200d82608746573743439" + "353300d92608746573743439353400da2608746573743439353500db2608746573743439353600dc26087465737434" + "39353700dd2608746573743439353800de2608746573743439353900df2608746573743439363000e0260874657374" + "3439363100e12608746573743439363200e22608746573743439363300e32608746573743439363400e42608746573" + "743439363500e52608746573743439363600e62608746573743439363700e72608746573743439363800e826087465" + "73743439363900e92608746573743439373000ea2608746573743439373100eb2608746573743439373200ec260874" + "6573743439373300ed2608746573743439373400ee2608746573743439373500ef2608746573743439373600f02608" + "746573743439373700f12608746573743439373800f22608746573743439373900f32608746573743439383000f426" + "08746573743439383100f52608746573743439383200f62608746573743439383300f72608746573743439383400f8" + "2608746573743439383500f92608746573743439383600fa2608746573743439383700fb2608746573743439383800" + "fc2608746573743439383900fd2608746573743439393000fe2608746573743439393100ff26087465737434393932" + "0080270874657374343939330081270874657374343939340082270874657374343939350083270874657374343939" + "360084270874657374343939370085270874657374343939380086270874657374343939390087270ac2b802882707" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" + "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" + "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" + "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" + "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" + "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" + "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" + "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" + "6a0b"; diff --git a/src/test/app/wasm_fixtures/fixture_locals_10k.cpp b/src/test/app/wasm_fixtures/fixture_locals_10k.cpp new file mode 100644 index 0000000000..75a799243d --- /dev/null +++ b/src/test/app/wasm_fixtures/fixture_locals_10k.cpp @@ -0,0 +1,2128 @@ +// TODO: consider moving these to separate files (and figure out the build) + +#include + +#include + +extern std::string const kLocals10kHex = + "0061736d0100000001070160027f7f017f03020100070801047465737400000a9b8a0601978a06018e4e7f20002001" + "6a2102200120026a2103200220036a2104200320046a2105200420056a2106200520066a2107200620076a21082007" + "20086a2109200820096a210a2009200a6a210b200a200b6a210c200b200c6a210d200c200d6a210e200d200e6a210f" + "200e200f6a2110200f20106a2111201020116a2112201120126a2113201220136a2114201320146a2115201420156a" + "2116201520166a2117201620176a2118201720186a2119201820196a211a2019201a6a211b201a201b6a211c201b20" + "1c6a211d201c201d6a211e201d201e6a211f201e201f6a2120201f20206a2121202020216a2122202120226a212320" + "2220236a2124202320246a2125202420256a2126202520266a2127202620276a2128202720286a2129202820296a21" + "2a2029202a6a212b202a202b6a212c202b202c6a212d202c202d6a212e202d202e6a212f202e202f6a2130202f2030" + "6a2131203020316a2132203120326a2133203220336a2134203320346a2135203420356a2136203520366a21372036" + "20376a2138203720386a2139203820396a213a2039203a6a213b203a203b6a213c203b203c6a213d203c203d6a213e" + "203d203e6a213f203e203f6a2140203f20406a2141204020416a2142204120426a2143204220436a2144204320446a" + "2145204420456a2146204520466a2147204620476a2148204720486a2149204820496a214a2049204a6a214b204a20" + "4b6a214c204b204c6a214d204c204d6a214e204d204e6a214f204e204f6a2150204f20506a2151205020516a215220" + "5120526a2153205220536a2154205320546a2155205420556a2156205520566a2157205620576a2158205720586a21" + "59205820596a215a2059205a6a215b205a205b6a215c205b205c6a215d205c205d6a215e205d205e6a215f205e205f" + "6a2160205f20606a2161206020616a2162206120626a2163206220636a2164206320646a2165206420656a21662065" + "20666a2167206620676a2168206720686a2169206820696a216a2069206a6a216b206a206b6a216c206b206c6a216d" + "206c206d6a216e206d206e6a216f206e206f6a2170206f20706a2171207020716a2172207120726a2173207220736a" + "2174207320746a2175207420756a2176207520766a2177207620776a2178207720786a2179207820796a217a207920" + "7a6a217b207a207b6a217c207b207c6a217d207c207d6a217e207d207e6a217f207e207f6a218001207f2080016a21" + "81012080012081016a2182012081012082016a2183012082012083016a2184012083012084016a2185012084012085" + "016a2186012085012086016a2187012086012087016a2188012087012088016a2189012088012089016a218a012089" + "01208a016a218b01208a01208b016a218c01208b01208c016a218d01208c01208d016a218e01208d01208e016a218f" + "01208e01208f016a219001208f012090016a2191012090012091016a2192012091012092016a219301209201209301" + "6a2194012093012094016a2195012094012095016a2196012095012096016a2197012096012097016a219801209701" + "2098016a2199012098012099016a219a01209901209a016a219b01209a01209b016a219c01209b01209c016a219d01" + "209c01209d016a219e01209d01209e016a219f01209e01209f016a21a001209f0120a0016a21a10120a00120a1016a" + "21a20120a10120a2016a21a30120a20120a3016a21a40120a30120a4016a21a50120a40120a5016a21a60120a50120" + "a6016a21a70120a60120a7016a21a80120a70120a8016a21a90120a80120a9016a21aa0120a90120aa016a21ab0120" + "aa0120ab016a21ac0120ab0120ac016a21ad0120ac0120ad016a21ae0120ad0120ae016a21af0120ae0120af016a21" + "b00120af0120b0016a21b10120b00120b1016a21b20120b10120b2016a21b30120b20120b3016a21b40120b30120b4" + "016a21b50120b40120b5016a21b60120b50120b6016a21b70120b60120b7016a21b80120b70120b8016a21b90120b8" + "0120b9016a21ba0120b90120ba016a21bb0120ba0120bb016a21bc0120bb0120bc016a21bd0120bc0120bd016a21be" + "0120bd0120be016a21bf0120be0120bf016a21c00120bf0120c0016a21c10120c00120c1016a21c20120c10120c201" + "6a21c30120c20120c3016a21c40120c30120c4016a21c50120c40120c5016a21c60120c50120c6016a21c70120c601" + "20c7016a21c80120c70120c8016a21c90120c80120c9016a21ca0120c90120ca016a21cb0120ca0120cb016a21cc01" + "20cb0120cc016a21cd0120cc0120cd016a21ce0120cd0120ce016a21cf0120ce0120cf016a21d00120cf0120d0016a" + "21d10120d00120d1016a21d20120d10120d2016a21d30120d20120d3016a21d40120d30120d4016a21d50120d40120" + "d5016a21d60120d50120d6016a21d70120d60120d7016a21d80120d70120d8016a21d90120d80120d9016a21da0120" + "d90120da016a21db0120da0120db016a21dc0120db0120dc016a21dd0120dc0120dd016a21de0120dd0120de016a21" + "df0120de0120df016a21e00120df0120e0016a21e10120e00120e1016a21e20120e10120e2016a21e30120e20120e3" + "016a21e40120e30120e4016a21e50120e40120e5016a21e60120e50120e6016a21e70120e60120e7016a21e80120e7" + "0120e8016a21e90120e80120e9016a21ea0120e90120ea016a21eb0120ea0120eb016a21ec0120eb0120ec016a21ed" + "0120ec0120ed016a21ee0120ed0120ee016a21ef0120ee0120ef016a21f00120ef0120f0016a21f10120f00120f101" + "6a21f20120f10120f2016a21f30120f20120f3016a21f40120f30120f4016a21f50120f40120f5016a21f60120f501" + "20f6016a21f70120f60120f7016a21f80120f70120f8016a21f90120f80120f9016a21fa0120f90120fa016a21fb01" + "20fa0120fb016a21fc0120fb0120fc016a21fd0120fc0120fd016a21fe0120fd0120fe016a21ff0120fe0120ff016a" + "21800220ff012080026a2181022080022081026a2182022081022082026a2183022082022083026a21840220830220" + "84026a2185022084022085026a2186022085022086026a2187022086022087026a2188022087022088026a21890220" + "88022089026a218a02208902208a026a218b02208a02208b026a218c02208b02208c026a218d02208c02208d026a21" + "8e02208d02208e026a218f02208e02208f026a219002208f022090026a2191022090022091026a2192022091022092" + "026a2193022092022093026a2194022093022094026a2195022094022095026a2196022095022096026a2197022096" + "022097026a2198022097022098026a2199022098022099026a219a02209902209a026a219b02209a02209b026a219c" + "02209b02209c026a219d02209c02209d026a219e02209d02209e026a219f02209e02209f026a21a002209f0220a002" + "6a21a10220a00220a1026a21a20220a10220a2026a21a30220a20220a3026a21a40220a30220a4026a21a50220a402" + "20a5026a21a60220a50220a6026a21a70220a60220a7026a21a80220a70220a8026a21a90220a80220a9026a21aa02" + "20a90220aa026a21ab0220aa0220ab026a21ac0220ab0220ac026a21ad0220ac0220ad026a21ae0220ad0220ae026a" + "21af0220ae0220af026a21b00220af0220b0026a21b10220b00220b1026a21b20220b10220b2026a21b30220b20220" + "b3026a21b40220b30220b4026a21b50220b40220b5026a21b60220b50220b6026a21b70220b60220b7026a21b80220" + "b70220b8026a21b90220b80220b9026a21ba0220b90220ba026a21bb0220ba0220bb026a21bc0220bb0220bc026a21" + "bd0220bc0220bd026a21be0220bd0220be026a21bf0220be0220bf026a21c00220bf0220c0026a21c10220c00220c1" + "026a21c20220c10220c2026a21c30220c20220c3026a21c40220c30220c4026a21c50220c40220c5026a21c60220c5" + "0220c6026a21c70220c60220c7026a21c80220c70220c8026a21c90220c80220c9026a21ca0220c90220ca026a21cb" + "0220ca0220cb026a21cc0220cb0220cc026a21cd0220cc0220cd026a21ce0220cd0220ce026a21cf0220ce0220cf02" + "6a21d00220cf0220d0026a21d10220d00220d1026a21d20220d10220d2026a21d30220d20220d3026a21d40220d302" + "20d4026a21d50220d40220d5026a21d60220d50220d6026a21d70220d60220d7026a21d80220d70220d8026a21d902" + "20d80220d9026a21da0220d90220da026a21db0220da0220db026a21dc0220db0220dc026a21dd0220dc0220dd026a" + "21de0220dd0220de026a21df0220de0220df026a21e00220df0220e0026a21e10220e00220e1026a21e20220e10220" + "e2026a21e30220e20220e3026a21e40220e30220e4026a21e50220e40220e5026a21e60220e50220e6026a21e70220" + "e60220e7026a21e80220e70220e8026a21e90220e80220e9026a21ea0220e90220ea026a21eb0220ea0220eb026a21" + "ec0220eb0220ec026a21ed0220ec0220ed026a21ee0220ed0220ee026a21ef0220ee0220ef026a21f00220ef0220f0" + "026a21f10220f00220f1026a21f20220f10220f2026a21f30220f20220f3026a21f40220f30220f4026a21f50220f4" + "0220f5026a21f60220f50220f6026a21f70220f60220f7026a21f80220f70220f8026a21f90220f80220f9026a21fa" + "0220f90220fa026a21fb0220fa0220fb026a21fc0220fb0220fc026a21fd0220fc0220fd026a21fe0220fd0220fe02" + "6a21ff0220fe0220ff026a21800320ff022080036a2181032080032081036a2182032081032082036a218303208203" + "2083036a2184032083032084036a2185032084032085036a2186032085032086036a2187032086032087036a218803" + "2087032088036a2189032088032089036a218a03208903208a036a218b03208a03208b036a218c03208b03208c036a" + "218d03208c03208d036a218e03208d03208e036a218f03208e03208f036a219003208f032090036a21910320900320" + "91036a2192032091032092036a2193032092032093036a2194032093032094036a2195032094032095036a21960320" + "95032096036a2197032096032097036a2198032097032098036a2199032098032099036a219a03209903209a036a21" + "9b03209a03209b036a219c03209b03209c036a219d03209c03209d036a219e03209d03209e036a219f03209e03209f" + "036a21a003209f0320a0036a21a10320a00320a1036a21a20320a10320a2036a21a30320a20320a3036a21a40320a3" + "0320a4036a21a50320a40320a5036a21a60320a50320a6036a21a70320a60320a7036a21a80320a70320a8036a21a9" + "0320a80320a9036a21aa0320a90320aa036a21ab0320aa0320ab036a21ac0320ab0320ac036a21ad0320ac0320ad03" + "6a21ae0320ad0320ae036a21af0320ae0320af036a21b00320af0320b0036a21b10320b00320b1036a21b20320b103" + "20b2036a21b30320b20320b3036a21b40320b30320b4036a21b50320b40320b5036a21b60320b50320b6036a21b703" + "20b60320b7036a21b80320b70320b8036a21b90320b80320b9036a21ba0320b90320ba036a21bb0320ba0320bb036a" + "21bc0320bb0320bc036a21bd0320bc0320bd036a21be0320bd0320be036a21bf0320be0320bf036a21c00320bf0320" + "c0036a21c10320c00320c1036a21c20320c10320c2036a21c30320c20320c3036a21c40320c30320c4036a21c50320" + "c40320c5036a21c60320c50320c6036a21c70320c60320c7036a21c80320c70320c8036a21c90320c80320c9036a21" + "ca0320c90320ca036a21cb0320ca0320cb036a21cc0320cb0320cc036a21cd0320cc0320cd036a21ce0320cd0320ce" + "036a21cf0320ce0320cf036a21d00320cf0320d0036a21d10320d00320d1036a21d20320d10320d2036a21d30320d2" + "0320d3036a21d40320d30320d4036a21d50320d40320d5036a21d60320d50320d6036a21d70320d60320d7036a21d8" + "0320d70320d8036a21d90320d80320d9036a21da0320d90320da036a21db0320da0320db036a21dc0320db0320dc03" + "6a21dd0320dc0320dd036a21de0320dd0320de036a21df0320de0320df036a21e00320df0320e0036a21e10320e003" + "20e1036a21e20320e10320e2036a21e30320e20320e3036a21e40320e30320e4036a21e50320e40320e5036a21e603" + "20e50320e6036a21e70320e60320e7036a21e80320e70320e8036a21e90320e80320e9036a21ea0320e90320ea036a" + "21eb0320ea0320eb036a21ec0320eb0320ec036a21ed0320ec0320ed036a21ee0320ed0320ee036a21ef0320ee0320" + "ef036a21f00320ef0320f0036a21f10320f00320f1036a21f20320f10320f2036a21f30320f20320f3036a21f40320" + "f30320f4036a21f50320f40320f5036a21f60320f50320f6036a21f70320f60320f7036a21f80320f70320f8036a21" + "f90320f80320f9036a21fa0320f90320fa036a21fb0320fa0320fb036a21fc0320fb0320fc036a21fd0320fc0320fd" + "036a21fe0320fd0320fe036a21ff0320fe0320ff036a21800420ff032080046a2181042080042081046a2182042081" + "042082046a2183042082042083046a2184042083042084046a2185042084042085046a2186042085042086046a2187" + "042086042087046a2188042087042088046a2189042088042089046a218a04208904208a046a218b04208a04208b04" + "6a218c04208b04208c046a218d04208c04208d046a218e04208d04208e046a218f04208e04208f046a219004208f04" + "2090046a2191042090042091046a2192042091042092046a2193042092042093046a2194042093042094046a219504" + "2094042095046a2196042095042096046a2197042096042097046a2198042097042098046a2199042098042099046a" + "219a04209904209a046a219b04209a04209b046a219c04209b04209c046a219d04209c04209d046a219e04209d0420" + "9e046a219f04209e04209f046a21a004209f0420a0046a21a10420a00420a1046a21a20420a10420a2046a21a30420" + "a20420a3046a21a40420a30420a4046a21a50420a40420a5046a21a60420a50420a6046a21a70420a60420a7046a21" + "a80420a70420a8046a21a90420a80420a9046a21aa0420a90420aa046a21ab0420aa0420ab046a21ac0420ab0420ac" + "046a21ad0420ac0420ad046a21ae0420ad0420ae046a21af0420ae0420af046a21b00420af0420b0046a21b10420b0" + "0420b1046a21b20420b10420b2046a21b30420b20420b3046a21b40420b30420b4046a21b50420b40420b5046a21b6" + "0420b50420b6046a21b70420b60420b7046a21b80420b70420b8046a21b90420b80420b9046a21ba0420b90420ba04" + "6a21bb0420ba0420bb046a21bc0420bb0420bc046a21bd0420bc0420bd046a21be0420bd0420be046a21bf0420be04" + "20bf046a21c00420bf0420c0046a21c10420c00420c1046a21c20420c10420c2046a21c30420c20420c3046a21c404" + "20c30420c4046a21c50420c40420c5046a21c60420c50420c6046a21c70420c60420c7046a21c80420c70420c8046a" + "21c90420c80420c9046a21ca0420c90420ca046a21cb0420ca0420cb046a21cc0420cb0420cc046a21cd0420cc0420" + "cd046a21ce0420cd0420ce046a21cf0420ce0420cf046a21d00420cf0420d0046a21d10420d00420d1046a21d20420" + "d10420d2046a21d30420d20420d3046a21d40420d30420d4046a21d50420d40420d5046a21d60420d50420d6046a21" + "d70420d60420d7046a21d80420d70420d8046a21d90420d80420d9046a21da0420d90420da046a21db0420da0420db" + "046a21dc0420db0420dc046a21dd0420dc0420dd046a21de0420dd0420de046a21df0420de0420df046a21e00420df" + "0420e0046a21e10420e00420e1046a21e20420e10420e2046a21e30420e20420e3046a21e40420e30420e4046a21e5" + "0420e40420e5046a21e60420e50420e6046a21e70420e60420e7046a21e80420e70420e8046a21e90420e80420e904" + "6a21ea0420e90420ea046a21eb0420ea0420eb046a21ec0420eb0420ec046a21ed0420ec0420ed046a21ee0420ed04" + "20ee046a21ef0420ee0420ef046a21f00420ef0420f0046a21f10420f00420f1046a21f20420f10420f2046a21f304" + "20f20420f3046a21f40420f30420f4046a21f50420f40420f5046a21f60420f50420f6046a21f70420f60420f7046a" + "21f80420f70420f8046a21f90420f80420f9046a21fa0420f90420fa046a21fb0420fa0420fb046a21fc0420fb0420" + "fc046a21fd0420fc0420fd046a21fe0420fd0420fe046a21ff0420fe0420ff046a21800520ff042080056a21810520" + "80052081056a2182052081052082056a2183052082052083056a2184052083052084056a2185052084052085056a21" + "86052085052086056a2187052086052087056a2188052087052088056a2189052088052089056a218a05208905208a" + "056a218b05208a05208b056a218c05208b05208c056a218d05208c05208d056a218e05208d05208e056a218f05208e" + "05208f056a219005208f052090056a2191052090052091056a2192052091052092056a2193052092052093056a2194" + "052093052094056a2195052094052095056a2196052095052096056a2197052096052097056a219805209705209805" + "6a2199052098052099056a219a05209905209a056a219b05209a05209b056a219c05209b05209c056a219d05209c05" + "209d056a219e05209d05209e056a219f05209e05209f056a21a005209f0520a0056a21a10520a00520a1056a21a205" + "20a10520a2056a21a30520a20520a3056a21a40520a30520a4056a21a50520a40520a5056a21a60520a50520a6056a" + "21a70520a60520a7056a21a80520a70520a8056a21a90520a80520a9056a21aa0520a90520aa056a21ab0520aa0520" + "ab056a21ac0520ab0520ac056a21ad0520ac0520ad056a21ae0520ad0520ae056a21af0520ae0520af056a21b00520" + "af0520b0056a21b10520b00520b1056a21b20520b10520b2056a21b30520b20520b3056a21b40520b30520b4056a21" + "b50520b40520b5056a21b60520b50520b6056a21b70520b60520b7056a21b80520b70520b8056a21b90520b80520b9" + "056a21ba0520b90520ba056a21bb0520ba0520bb056a21bc0520bb0520bc056a21bd0520bc0520bd056a21be0520bd" + "0520be056a21bf0520be0520bf056a21c00520bf0520c0056a21c10520c00520c1056a21c20520c10520c2056a21c3" + "0520c20520c3056a21c40520c30520c4056a21c50520c40520c5056a21c60520c50520c6056a21c70520c60520c705" + "6a21c80520c70520c8056a21c90520c80520c9056a21ca0520c90520ca056a21cb0520ca0520cb056a21cc0520cb05" + "20cc056a21cd0520cc0520cd056a21ce0520cd0520ce056a21cf0520ce0520cf056a21d00520cf0520d0056a21d105" + "20d00520d1056a21d20520d10520d2056a21d30520d20520d3056a21d40520d30520d4056a21d50520d40520d5056a" + "21d60520d50520d6056a21d70520d60520d7056a21d80520d70520d8056a21d90520d80520d9056a21da0520d90520" + "da056a21db0520da0520db056a21dc0520db0520dc056a21dd0520dc0520dd056a21de0520dd0520de056a21df0520" + "de0520df056a21e00520df0520e0056a21e10520e00520e1056a21e20520e10520e2056a21e30520e20520e3056a21" + "e40520e30520e4056a21e50520e40520e5056a21e60520e50520e6056a21e70520e60520e7056a21e80520e70520e8" + "056a21e90520e80520e9056a21ea0520e90520ea056a21eb0520ea0520eb056a21ec0520eb0520ec056a21ed0520ec" + "0520ed056a21ee0520ed0520ee056a21ef0520ee0520ef056a21f00520ef0520f0056a21f10520f00520f1056a21f2" + "0520f10520f2056a21f30520f20520f3056a21f40520f30520f4056a21f50520f40520f5056a21f60520f50520f605" + "6a21f70520f60520f7056a21f80520f70520f8056a21f90520f80520f9056a21fa0520f90520fa056a21fb0520fa05" + "20fb056a21fc0520fb0520fc056a21fd0520fc0520fd056a21fe0520fd0520fe056a21ff0520fe0520ff056a218006" + "20ff052080066a2181062080062081066a2182062081062082066a2183062082062083066a2184062083062084066a" + "2185062084062085066a2186062085062086066a2187062086062087066a2188062087062088066a21890620880620" + "89066a218a06208906208a066a218b06208a06208b066a218c06208b06208c066a218d06208c06208d066a218e0620" + "8d06208e066a218f06208e06208f066a219006208f062090066a2191062090062091066a2192062091062092066a21" + "93062092062093066a2194062093062094066a2195062094062095066a2196062095062096066a2197062096062097" + "066a2198062097062098066a2199062098062099066a219a06209906209a066a219b06209a06209b066a219c06209b" + "06209c066a219d06209c06209d066a219e06209d06209e066a219f06209e06209f066a21a006209f0620a0066a21a1" + "0620a00620a1066a21a20620a10620a2066a21a30620a20620a3066a21a40620a30620a4066a21a50620a40620a506" + "6a21a60620a50620a6066a21a70620a60620a7066a21a80620a70620a8066a21a90620a80620a9066a21aa0620a906" + "20aa066a21ab0620aa0620ab066a21ac0620ab0620ac066a21ad0620ac0620ad066a21ae0620ad0620ae066a21af06" + "20ae0620af066a21b00620af0620b0066a21b10620b00620b1066a21b20620b10620b2066a21b30620b20620b3066a" + "21b40620b30620b4066a21b50620b40620b5066a21b60620b50620b6066a21b70620b60620b7066a21b80620b70620" + "b8066a21b90620b80620b9066a21ba0620b90620ba066a21bb0620ba0620bb066a21bc0620bb0620bc066a21bd0620" + "bc0620bd066a21be0620bd0620be066a21bf0620be0620bf066a21c00620bf0620c0066a21c10620c00620c1066a21" + "c20620c10620c2066a21c30620c20620c3066a21c40620c30620c4066a21c50620c40620c5066a21c60620c50620c6" + "066a21c70620c60620c7066a21c80620c70620c8066a21c90620c80620c9066a21ca0620c90620ca066a21cb0620ca" + "0620cb066a21cc0620cb0620cc066a21cd0620cc0620cd066a21ce0620cd0620ce066a21cf0620ce0620cf066a21d0" + "0620cf0620d0066a21d10620d00620d1066a21d20620d10620d2066a21d30620d20620d3066a21d40620d30620d406" + "6a21d50620d40620d5066a21d60620d50620d6066a21d70620d60620d7066a21d80620d70620d8066a21d90620d806" + "20d9066a21da0620d90620da066a21db0620da0620db066a21dc0620db0620dc066a21dd0620dc0620dd066a21de06" + "20dd0620de066a21df0620de0620df066a21e00620df0620e0066a21e10620e00620e1066a21e20620e10620e2066a" + "21e30620e20620e3066a21e40620e30620e4066a21e50620e40620e5066a21e60620e50620e6066a21e70620e60620" + "e7066a21e80620e70620e8066a21e90620e80620e9066a21ea0620e90620ea066a21eb0620ea0620eb066a21ec0620" + "eb0620ec066a21ed0620ec0620ed066a21ee0620ed0620ee066a21ef0620ee0620ef066a21f00620ef0620f0066a21" + "f10620f00620f1066a21f20620f10620f2066a21f30620f20620f3066a21f40620f30620f4066a21f50620f40620f5" + "066a21f60620f50620f6066a21f70620f60620f7066a21f80620f70620f8066a21f90620f80620f9066a21fa0620f9" + "0620fa066a21fb0620fa0620fb066a21fc0620fb0620fc066a21fd0620fc0620fd066a21fe0620fd0620fe066a21ff" + "0620fe0620ff066a21800720ff062080076a2181072080072081076a2182072081072082076a218307208207208307" + "6a2184072083072084076a2185072084072085076a2186072085072086076a2187072086072087076a218807208707" + "2088076a2189072088072089076a218a07208907208a076a218b07208a07208b076a218c07208b07208c076a218d07" + "208c07208d076a218e07208d07208e076a218f07208e07208f076a219007208f072090076a2191072090072091076a" + "2192072091072092076a2193072092072093076a2194072093072094076a2195072094072095076a21960720950720" + "96076a2197072096072097076a2198072097072098076a2199072098072099076a219a07209907209a076a219b0720" + "9a07209b076a219c07209b07209c076a219d07209c07209d076a219e07209d07209e076a219f07209e07209f076a21" + "a007209f0720a0076a21a10720a00720a1076a21a20720a10720a2076a21a30720a20720a3076a21a40720a30720a4" + "076a21a50720a40720a5076a21a60720a50720a6076a21a70720a60720a7076a21a80720a70720a8076a21a90720a8" + "0720a9076a21aa0720a90720aa076a21ab0720aa0720ab076a21ac0720ab0720ac076a21ad0720ac0720ad076a21ae" + "0720ad0720ae076a21af0720ae0720af076a21b00720af0720b0076a21b10720b00720b1076a21b20720b10720b207" + "6a21b30720b20720b3076a21b40720b30720b4076a21b50720b40720b5076a21b60720b50720b6076a21b70720b607" + "20b7076a21b80720b70720b8076a21b90720b80720b9076a21ba0720b90720ba076a21bb0720ba0720bb076a21bc07" + "20bb0720bc076a21bd0720bc0720bd076a21be0720bd0720be076a21bf0720be0720bf076a21c00720bf0720c0076a" + "21c10720c00720c1076a21c20720c10720c2076a21c30720c20720c3076a21c40720c30720c4076a21c50720c40720" + "c5076a21c60720c50720c6076a21c70720c60720c7076a21c80720c70720c8076a21c90720c80720c9076a21ca0720" + "c90720ca076a21cb0720ca0720cb076a21cc0720cb0720cc076a21cd0720cc0720cd076a21ce0720cd0720ce076a21" + "cf0720ce0720cf076a21d00720cf0720d0076a21d10720d00720d1076a21d20720d10720d2076a21d30720d20720d3" + "076a21d40720d30720d4076a21d50720d40720d5076a21d60720d50720d6076a21d70720d60720d7076a21d80720d7" + "0720d8076a21d90720d80720d9076a21da0720d90720da076a21db0720da0720db076a21dc0720db0720dc076a21dd" + "0720dc0720dd076a21de0720dd0720de076a21df0720de0720df076a21e00720df0720e0076a21e10720e00720e107" + "6a21e20720e10720e2076a21e30720e20720e3076a21e40720e30720e4076a21e50720e40720e5076a21e60720e507" + "20e6076a21e70720e60720e7076a21e80720e70720e8076a21e90720e80720e9076a21ea0720e90720ea076a21eb07" + "20ea0720eb076a21ec0720eb0720ec076a21ed0720ec0720ed076a21ee0720ed0720ee076a21ef0720ee0720ef076a" + "21f00720ef0720f0076a21f10720f00720f1076a21f20720f10720f2076a21f30720f20720f3076a21f40720f30720" + "f4076a21f50720f40720f5076a21f60720f50720f6076a21f70720f60720f7076a21f80720f70720f8076a21f90720" + "f80720f9076a21fa0720f90720fa076a21fb0720fa0720fb076a21fc0720fb0720fc076a21fd0720fc0720fd076a21" + "fe0720fd0720fe076a21ff0720fe0720ff076a21800820ff072080086a2181082080082081086a2182082081082082" + "086a2183082082082083086a2184082083082084086a2185082084082085086a2186082085082086086a2187082086" + "082087086a2188082087082088086a2189082088082089086a218a08208908208a086a218b08208a08208b086a218c" + "08208b08208c086a218d08208c08208d086a218e08208d08208e086a218f08208e08208f086a219008208f08209008" + "6a2191082090082091086a2192082091082092086a2193082092082093086a2194082093082094086a219508209408" + "2095086a2196082095082096086a2197082096082097086a2198082097082098086a2199082098082099086a219a08" + "209908209a086a219b08209a08209b086a219c08209b08209c086a219d08209c08209d086a219e08209d08209e086a" + "219f08209e08209f086a21a008209f0820a0086a21a10820a00820a1086a21a20820a10820a2086a21a30820a20820" + "a3086a21a40820a30820a4086a21a50820a40820a5086a21a60820a50820a6086a21a70820a60820a7086a21a80820" + "a70820a8086a21a90820a80820a9086a21aa0820a90820aa086a21ab0820aa0820ab086a21ac0820ab0820ac086a21" + "ad0820ac0820ad086a21ae0820ad0820ae086a21af0820ae0820af086a21b00820af0820b0086a21b10820b00820b1" + "086a21b20820b10820b2086a21b30820b20820b3086a21b40820b30820b4086a21b50820b40820b5086a21b60820b5" + "0820b6086a21b70820b60820b7086a21b80820b70820b8086a21b90820b80820b9086a21ba0820b90820ba086a21bb" + "0820ba0820bb086a21bc0820bb0820bc086a21bd0820bc0820bd086a21be0820bd0820be086a21bf0820be0820bf08" + "6a21c00820bf0820c0086a21c10820c00820c1086a21c20820c10820c2086a21c30820c20820c3086a21c40820c308" + "20c4086a21c50820c40820c5086a21c60820c50820c6086a21c70820c60820c7086a21c80820c70820c8086a21c908" + "20c80820c9086a21ca0820c90820ca086a21cb0820ca0820cb086a21cc0820cb0820cc086a21cd0820cc0820cd086a" + "21ce0820cd0820ce086a21cf0820ce0820cf086a21d00820cf0820d0086a21d10820d00820d1086a21d20820d10820" + "d2086a21d30820d20820d3086a21d40820d30820d4086a21d50820d40820d5086a21d60820d50820d6086a21d70820" + "d60820d7086a21d80820d70820d8086a21d90820d80820d9086a21da0820d90820da086a21db0820da0820db086a21" + "dc0820db0820dc086a21dd0820dc0820dd086a21de0820dd0820de086a21df0820de0820df086a21e00820df0820e0" + "086a21e10820e00820e1086a21e20820e10820e2086a21e30820e20820e3086a21e40820e30820e4086a21e50820e4" + "0820e5086a21e60820e50820e6086a21e70820e60820e7086a21e80820e70820e8086a21e90820e80820e9086a21ea" + "0820e90820ea086a21eb0820ea0820eb086a21ec0820eb0820ec086a21ed0820ec0820ed086a21ee0820ed0820ee08" + "6a21ef0820ee0820ef086a21f00820ef0820f0086a21f10820f00820f1086a21f20820f10820f2086a21f30820f208" + "20f3086a21f40820f30820f4086a21f50820f40820f5086a21f60820f50820f6086a21f70820f60820f7086a21f808" + "20f70820f8086a21f90820f80820f9086a21fa0820f90820fa086a21fb0820fa0820fb086a21fc0820fb0820fc086a" + "21fd0820fc0820fd086a21fe0820fd0820fe086a21ff0820fe0820ff086a21800920ff082080096a21810920800920" + "81096a2182092081092082096a2183092082092083096a2184092083092084096a2185092084092085096a21860920" + "85092086096a2187092086092087096a2188092087092088096a2189092088092089096a218a09208909208a096a21" + "8b09208a09208b096a218c09208b09208c096a218d09208c09208d096a218e09208d09208e096a218f09208e09208f" + "096a219009208f092090096a2191092090092091096a2192092091092092096a2193092092092093096a2194092093" + "092094096a2195092094092095096a2196092095092096096a2197092096092097096a2198092097092098096a2199" + "092098092099096a219a09209909209a096a219b09209a09209b096a219c09209b09209c096a219d09209c09209d09" + "6a219e09209d09209e096a219f09209e09209f096a21a009209f0920a0096a21a10920a00920a1096a21a20920a109" + "20a2096a21a30920a20920a3096a21a40920a30920a4096a21a50920a40920a5096a21a60920a50920a6096a21a709" + "20a60920a7096a21a80920a70920a8096a21a90920a80920a9096a21aa0920a90920aa096a21ab0920aa0920ab096a" + "21ac0920ab0920ac096a21ad0920ac0920ad096a21ae0920ad0920ae096a21af0920ae0920af096a21b00920af0920" + "b0096a21b10920b00920b1096a21b20920b10920b2096a21b30920b20920b3096a21b40920b30920b4096a21b50920" + "b40920b5096a21b60920b50920b6096a21b70920b60920b7096a21b80920b70920b8096a21b90920b80920b9096a21" + "ba0920b90920ba096a21bb0920ba0920bb096a21bc0920bb0920bc096a21bd0920bc0920bd096a21be0920bd0920be" + "096a21bf0920be0920bf096a21c00920bf0920c0096a21c10920c00920c1096a21c20920c10920c2096a21c30920c2" + "0920c3096a21c40920c30920c4096a21c50920c40920c5096a21c60920c50920c6096a21c70920c60920c7096a21c8" + "0920c70920c8096a21c90920c80920c9096a21ca0920c90920ca096a21cb0920ca0920cb096a21cc0920cb0920cc09" + "6a21cd0920cc0920cd096a21ce0920cd0920ce096a21cf0920ce0920cf096a21d00920cf0920d0096a21d10920d009" + "20d1096a21d20920d10920d2096a21d30920d20920d3096a21d40920d30920d4096a21d50920d40920d5096a21d609" + "20d50920d6096a21d70920d60920d7096a21d80920d70920d8096a21d90920d80920d9096a21da0920d90920da096a" + "21db0920da0920db096a21dc0920db0920dc096a21dd0920dc0920dd096a21de0920dd0920de096a21df0920de0920" + "df096a21e00920df0920e0096a21e10920e00920e1096a21e20920e10920e2096a21e30920e20920e3096a21e40920" + "e30920e4096a21e50920e40920e5096a21e60920e50920e6096a21e70920e60920e7096a21e80920e70920e8096a21" + "e90920e80920e9096a21ea0920e90920ea096a21eb0920ea0920eb096a21ec0920eb0920ec096a21ed0920ec0920ed" + "096a21ee0920ed0920ee096a21ef0920ee0920ef096a21f00920ef0920f0096a21f10920f00920f1096a21f20920f1" + "0920f2096a21f30920f20920f3096a21f40920f30920f4096a21f50920f40920f5096a21f60920f50920f6096a21f7" + "0920f60920f7096a21f80920f70920f8096a21f90920f80920f9096a21fa0920f90920fa096a21fb0920fa0920fb09" + "6a21fc0920fb0920fc096a21fd0920fc0920fd096a21fe0920fd0920fe096a21ff0920fe0920ff096a21800a20ff09" + "20800a6a21810a20800a20810a6a21820a20810a20820a6a21830a20820a20830a6a21840a20830a20840a6a21850a" + "20840a20850a6a21860a20850a20860a6a21870a20860a20870a6a21880a20870a20880a6a21890a20880a20890a6a" + "218a0a20890a208a0a6a218b0a208a0a208b0a6a218c0a208b0a208c0a6a218d0a208c0a208d0a6a218e0a208d0a20" + "8e0a6a218f0a208e0a208f0a6a21900a208f0a20900a6a21910a20900a20910a6a21920a20910a20920a6a21930a20" + "920a20930a6a21940a20930a20940a6a21950a20940a20950a6a21960a20950a20960a6a21970a20960a20970a6a21" + "980a20970a20980a6a21990a20980a20990a6a219a0a20990a209a0a6a219b0a209a0a209b0a6a219c0a209b0a209c" + "0a6a219d0a209c0a209d0a6a219e0a209d0a209e0a6a219f0a209e0a209f0a6a21a00a209f0a20a00a6a21a10a20a0" + "0a20a10a6a21a20a20a10a20a20a6a21a30a20a20a20a30a6a21a40a20a30a20a40a6a21a50a20a40a20a50a6a21a6" + "0a20a50a20a60a6a21a70a20a60a20a70a6a21a80a20a70a20a80a6a21a90a20a80a20a90a6a21aa0a20a90a20aa0a" + "6a21ab0a20aa0a20ab0a6a21ac0a20ab0a20ac0a6a21ad0a20ac0a20ad0a6a21ae0a20ad0a20ae0a6a21af0a20ae0a" + "20af0a6a21b00a20af0a20b00a6a21b10a20b00a20b10a6a21b20a20b10a20b20a6a21b30a20b20a20b30a6a21b40a" + "20b30a20b40a6a21b50a20b40a20b50a6a21b60a20b50a20b60a6a21b70a20b60a20b70a6a21b80a20b70a20b80a6a" + "21b90a20b80a20b90a6a21ba0a20b90a20ba0a6a21bb0a20ba0a20bb0a6a21bc0a20bb0a20bc0a6a21bd0a20bc0a20" + "bd0a6a21be0a20bd0a20be0a6a21bf0a20be0a20bf0a6a21c00a20bf0a20c00a6a21c10a20c00a20c10a6a21c20a20" + "c10a20c20a6a21c30a20c20a20c30a6a21c40a20c30a20c40a6a21c50a20c40a20c50a6a21c60a20c50a20c60a6a21" + "c70a20c60a20c70a6a21c80a20c70a20c80a6a21c90a20c80a20c90a6a21ca0a20c90a20ca0a6a21cb0a20ca0a20cb" + "0a6a21cc0a20cb0a20cc0a6a21cd0a20cc0a20cd0a6a21ce0a20cd0a20ce0a6a21cf0a20ce0a20cf0a6a21d00a20cf" + "0a20d00a6a21d10a20d00a20d10a6a21d20a20d10a20d20a6a21d30a20d20a20d30a6a21d40a20d30a20d40a6a21d5" + "0a20d40a20d50a6a21d60a20d50a20d60a6a21d70a20d60a20d70a6a21d80a20d70a20d80a6a21d90a20d80a20d90a" + "6a21da0a20d90a20da0a6a21db0a20da0a20db0a6a21dc0a20db0a20dc0a6a21dd0a20dc0a20dd0a6a21de0a20dd0a" + "20de0a6a21df0a20de0a20df0a6a21e00a20df0a20e00a6a21e10a20e00a20e10a6a21e20a20e10a20e20a6a21e30a" + "20e20a20e30a6a21e40a20e30a20e40a6a21e50a20e40a20e50a6a21e60a20e50a20e60a6a21e70a20e60a20e70a6a" + "21e80a20e70a20e80a6a21e90a20e80a20e90a6a21ea0a20e90a20ea0a6a21eb0a20ea0a20eb0a6a21ec0a20eb0a20" + "ec0a6a21ed0a20ec0a20ed0a6a21ee0a20ed0a20ee0a6a21ef0a20ee0a20ef0a6a21f00a20ef0a20f00a6a21f10a20" + "f00a20f10a6a21f20a20f10a20f20a6a21f30a20f20a20f30a6a21f40a20f30a20f40a6a21f50a20f40a20f50a6a21" + "f60a20f50a20f60a6a21f70a20f60a20f70a6a21f80a20f70a20f80a6a21f90a20f80a20f90a6a21fa0a20f90a20fa" + "0a6a21fb0a20fa0a20fb0a6a21fc0a20fb0a20fc0a6a21fd0a20fc0a20fd0a6a21fe0a20fd0a20fe0a6a21ff0a20fe" + "0a20ff0a6a21800b20ff0a20800b6a21810b20800b20810b6a21820b20810b20820b6a21830b20820b20830b6a2184" + "0b20830b20840b6a21850b20840b20850b6a21860b20850b20860b6a21870b20860b20870b6a21880b20870b20880b" + "6a21890b20880b20890b6a218a0b20890b208a0b6a218b0b208a0b208b0b6a218c0b208b0b208c0b6a218d0b208c0b" + "208d0b6a218e0b208d0b208e0b6a218f0b208e0b208f0b6a21900b208f0b20900b6a21910b20900b20910b6a21920b" + "20910b20920b6a21930b20920b20930b6a21940b20930b20940b6a21950b20940b20950b6a21960b20950b20960b6a" + "21970b20960b20970b6a21980b20970b20980b6a21990b20980b20990b6a219a0b20990b209a0b6a219b0b209a0b20" + "9b0b6a219c0b209b0b209c0b6a219d0b209c0b209d0b6a219e0b209d0b209e0b6a219f0b209e0b209f0b6a21a00b20" + "9f0b20a00b6a21a10b20a00b20a10b6a21a20b20a10b20a20b6a21a30b20a20b20a30b6a21a40b20a30b20a40b6a21" + "a50b20a40b20a50b6a21a60b20a50b20a60b6a21a70b20a60b20a70b6a21a80b20a70b20a80b6a21a90b20a80b20a9" + "0b6a21aa0b20a90b20aa0b6a21ab0b20aa0b20ab0b6a21ac0b20ab0b20ac0b6a21ad0b20ac0b20ad0b6a21ae0b20ad" + "0b20ae0b6a21af0b20ae0b20af0b6a21b00b20af0b20b00b6a21b10b20b00b20b10b6a21b20b20b10b20b20b6a21b3" + "0b20b20b20b30b6a21b40b20b30b20b40b6a21b50b20b40b20b50b6a21b60b20b50b20b60b6a21b70b20b60b20b70b" + "6a21b80b20b70b20b80b6a21b90b20b80b20b90b6a21ba0b20b90b20ba0b6a21bb0b20ba0b20bb0b6a21bc0b20bb0b" + "20bc0b6a21bd0b20bc0b20bd0b6a21be0b20bd0b20be0b6a21bf0b20be0b20bf0b6a21c00b20bf0b20c00b6a21c10b" + "20c00b20c10b6a21c20b20c10b20c20b6a21c30b20c20b20c30b6a21c40b20c30b20c40b6a21c50b20c40b20c50b6a" + "21c60b20c50b20c60b6a21c70b20c60b20c70b6a21c80b20c70b20c80b6a21c90b20c80b20c90b6a21ca0b20c90b20" + "ca0b6a21cb0b20ca0b20cb0b6a21cc0b20cb0b20cc0b6a21cd0b20cc0b20cd0b6a21ce0b20cd0b20ce0b6a21cf0b20" + "ce0b20cf0b6a21d00b20cf0b20d00b6a21d10b20d00b20d10b6a21d20b20d10b20d20b6a21d30b20d20b20d30b6a21" + "d40b20d30b20d40b6a21d50b20d40b20d50b6a21d60b20d50b20d60b6a21d70b20d60b20d70b6a21d80b20d70b20d8" + "0b6a21d90b20d80b20d90b6a21da0b20d90b20da0b6a21db0b20da0b20db0b6a21dc0b20db0b20dc0b6a21dd0b20dc" + "0b20dd0b6a21de0b20dd0b20de0b6a21df0b20de0b20df0b6a21e00b20df0b20e00b6a21e10b20e00b20e10b6a21e2" + "0b20e10b20e20b6a21e30b20e20b20e30b6a21e40b20e30b20e40b6a21e50b20e40b20e50b6a21e60b20e50b20e60b" + "6a21e70b20e60b20e70b6a21e80b20e70b20e80b6a21e90b20e80b20e90b6a21ea0b20e90b20ea0b6a21eb0b20ea0b" + "20eb0b6a21ec0b20eb0b20ec0b6a21ed0b20ec0b20ed0b6a21ee0b20ed0b20ee0b6a21ef0b20ee0b20ef0b6a21f00b" + "20ef0b20f00b6a21f10b20f00b20f10b6a21f20b20f10b20f20b6a21f30b20f20b20f30b6a21f40b20f30b20f40b6a" + "21f50b20f40b20f50b6a21f60b20f50b20f60b6a21f70b20f60b20f70b6a21f80b20f70b20f80b6a21f90b20f80b20" + "f90b6a21fa0b20f90b20fa0b6a21fb0b20fa0b20fb0b6a21fc0b20fb0b20fc0b6a21fd0b20fc0b20fd0b6a21fe0b20" + "fd0b20fe0b6a21ff0b20fe0b20ff0b6a21800c20ff0b20800c6a21810c20800c20810c6a21820c20810c20820c6a21" + "830c20820c20830c6a21840c20830c20840c6a21850c20840c20850c6a21860c20850c20860c6a21870c20860c2087" + "0c6a21880c20870c20880c6a21890c20880c20890c6a218a0c20890c208a0c6a218b0c208a0c208b0c6a218c0c208b" + "0c208c0c6a218d0c208c0c208d0c6a218e0c208d0c208e0c6a218f0c208e0c208f0c6a21900c208f0c20900c6a2191" + "0c20900c20910c6a21920c20910c20920c6a21930c20920c20930c6a21940c20930c20940c6a21950c20940c20950c" + "6a21960c20950c20960c6a21970c20960c20970c6a21980c20970c20980c6a21990c20980c20990c6a219a0c20990c" + "209a0c6a219b0c209a0c209b0c6a219c0c209b0c209c0c6a219d0c209c0c209d0c6a219e0c209d0c209e0c6a219f0c" + "209e0c209f0c6a21a00c209f0c20a00c6a21a10c20a00c20a10c6a21a20c20a10c20a20c6a21a30c20a20c20a30c6a" + "21a40c20a30c20a40c6a21a50c20a40c20a50c6a21a60c20a50c20a60c6a21a70c20a60c20a70c6a21a80c20a70c20" + "a80c6a21a90c20a80c20a90c6a21aa0c20a90c20aa0c6a21ab0c20aa0c20ab0c6a21ac0c20ab0c20ac0c6a21ad0c20" + "ac0c20ad0c6a21ae0c20ad0c20ae0c6a21af0c20ae0c20af0c6a21b00c20af0c20b00c6a21b10c20b00c20b10c6a21" + "b20c20b10c20b20c6a21b30c20b20c20b30c6a21b40c20b30c20b40c6a21b50c20b40c20b50c6a21b60c20b50c20b6" + "0c6a21b70c20b60c20b70c6a21b80c20b70c20b80c6a21b90c20b80c20b90c6a21ba0c20b90c20ba0c6a21bb0c20ba" + "0c20bb0c6a21bc0c20bb0c20bc0c6a21bd0c20bc0c20bd0c6a21be0c20bd0c20be0c6a21bf0c20be0c20bf0c6a21c0" + "0c20bf0c20c00c6a21c10c20c00c20c10c6a21c20c20c10c20c20c6a21c30c20c20c20c30c6a21c40c20c30c20c40c" + "6a21c50c20c40c20c50c6a21c60c20c50c20c60c6a21c70c20c60c20c70c6a21c80c20c70c20c80c6a21c90c20c80c" + "20c90c6a21ca0c20c90c20ca0c6a21cb0c20ca0c20cb0c6a21cc0c20cb0c20cc0c6a21cd0c20cc0c20cd0c6a21ce0c" + "20cd0c20ce0c6a21cf0c20ce0c20cf0c6a21d00c20cf0c20d00c6a21d10c20d00c20d10c6a21d20c20d10c20d20c6a" + "21d30c20d20c20d30c6a21d40c20d30c20d40c6a21d50c20d40c20d50c6a21d60c20d50c20d60c6a21d70c20d60c20" + "d70c6a21d80c20d70c20d80c6a21d90c20d80c20d90c6a21da0c20d90c20da0c6a21db0c20da0c20db0c6a21dc0c20" + "db0c20dc0c6a21dd0c20dc0c20dd0c6a21de0c20dd0c20de0c6a21df0c20de0c20df0c6a21e00c20df0c20e00c6a21" + "e10c20e00c20e10c6a21e20c20e10c20e20c6a21e30c20e20c20e30c6a21e40c20e30c20e40c6a21e50c20e40c20e5" + "0c6a21e60c20e50c20e60c6a21e70c20e60c20e70c6a21e80c20e70c20e80c6a21e90c20e80c20e90c6a21ea0c20e9" + "0c20ea0c6a21eb0c20ea0c20eb0c6a21ec0c20eb0c20ec0c6a21ed0c20ec0c20ed0c6a21ee0c20ed0c20ee0c6a21ef" + "0c20ee0c20ef0c6a21f00c20ef0c20f00c6a21f10c20f00c20f10c6a21f20c20f10c20f20c6a21f30c20f20c20f30c" + "6a21f40c20f30c20f40c6a21f50c20f40c20f50c6a21f60c20f50c20f60c6a21f70c20f60c20f70c6a21f80c20f70c" + "20f80c6a21f90c20f80c20f90c6a21fa0c20f90c20fa0c6a21fb0c20fa0c20fb0c6a21fc0c20fb0c20fc0c6a21fd0c" + "20fc0c20fd0c6a21fe0c20fd0c20fe0c6a21ff0c20fe0c20ff0c6a21800d20ff0c20800d6a21810d20800d20810d6a" + "21820d20810d20820d6a21830d20820d20830d6a21840d20830d20840d6a21850d20840d20850d6a21860d20850d20" + "860d6a21870d20860d20870d6a21880d20870d20880d6a21890d20880d20890d6a218a0d20890d208a0d6a218b0d20" + "8a0d208b0d6a218c0d208b0d208c0d6a218d0d208c0d208d0d6a218e0d208d0d208e0d6a218f0d208e0d208f0d6a21" + "900d208f0d20900d6a21910d20900d20910d6a21920d20910d20920d6a21930d20920d20930d6a21940d20930d2094" + "0d6a21950d20940d20950d6a21960d20950d20960d6a21970d20960d20970d6a21980d20970d20980d6a21990d2098" + "0d20990d6a219a0d20990d209a0d6a219b0d209a0d209b0d6a219c0d209b0d209c0d6a219d0d209c0d209d0d6a219e" + "0d209d0d209e0d6a219f0d209e0d209f0d6a21a00d209f0d20a00d6a21a10d20a00d20a10d6a21a20d20a10d20a20d" + "6a21a30d20a20d20a30d6a21a40d20a30d20a40d6a21a50d20a40d20a50d6a21a60d20a50d20a60d6a21a70d20a60d" + "20a70d6a21a80d20a70d20a80d6a21a90d20a80d20a90d6a21aa0d20a90d20aa0d6a21ab0d20aa0d20ab0d6a21ac0d" + "20ab0d20ac0d6a21ad0d20ac0d20ad0d6a21ae0d20ad0d20ae0d6a21af0d20ae0d20af0d6a21b00d20af0d20b00d6a" + "21b10d20b00d20b10d6a21b20d20b10d20b20d6a21b30d20b20d20b30d6a21b40d20b30d20b40d6a21b50d20b40d20" + "b50d6a21b60d20b50d20b60d6a21b70d20b60d20b70d6a21b80d20b70d20b80d6a21b90d20b80d20b90d6a21ba0d20" + "b90d20ba0d6a21bb0d20ba0d20bb0d6a21bc0d20bb0d20bc0d6a21bd0d20bc0d20bd0d6a21be0d20bd0d20be0d6a21" + "bf0d20be0d20bf0d6a21c00d20bf0d20c00d6a21c10d20c00d20c10d6a21c20d20c10d20c20d6a21c30d20c20d20c3" + "0d6a21c40d20c30d20c40d6a21c50d20c40d20c50d6a21c60d20c50d20c60d6a21c70d20c60d20c70d6a21c80d20c7" + "0d20c80d6a21c90d20c80d20c90d6a21ca0d20c90d20ca0d6a21cb0d20ca0d20cb0d6a21cc0d20cb0d20cc0d6a21cd" + "0d20cc0d20cd0d6a21ce0d20cd0d20ce0d6a21cf0d20ce0d20cf0d6a21d00d20cf0d20d00d6a21d10d20d00d20d10d" + "6a21d20d20d10d20d20d6a21d30d20d20d20d30d6a21d40d20d30d20d40d6a21d50d20d40d20d50d6a21d60d20d50d" + "20d60d6a21d70d20d60d20d70d6a21d80d20d70d20d80d6a21d90d20d80d20d90d6a21da0d20d90d20da0d6a21db0d" + "20da0d20db0d6a21dc0d20db0d20dc0d6a21dd0d20dc0d20dd0d6a21de0d20dd0d20de0d6a21df0d20de0d20df0d6a" + "21e00d20df0d20e00d6a21e10d20e00d20e10d6a21e20d20e10d20e20d6a21e30d20e20d20e30d6a21e40d20e30d20" + "e40d6a21e50d20e40d20e50d6a21e60d20e50d20e60d6a21e70d20e60d20e70d6a21e80d20e70d20e80d6a21e90d20" + "e80d20e90d6a21ea0d20e90d20ea0d6a21eb0d20ea0d20eb0d6a21ec0d20eb0d20ec0d6a21ed0d20ec0d20ed0d6a21" + "ee0d20ed0d20ee0d6a21ef0d20ee0d20ef0d6a21f00d20ef0d20f00d6a21f10d20f00d20f10d6a21f20d20f10d20f2" + "0d6a21f30d20f20d20f30d6a21f40d20f30d20f40d6a21f50d20f40d20f50d6a21f60d20f50d20f60d6a21f70d20f6" + "0d20f70d6a21f80d20f70d20f80d6a21f90d20f80d20f90d6a21fa0d20f90d20fa0d6a21fb0d20fa0d20fb0d6a21fc" + "0d20fb0d20fc0d6a21fd0d20fc0d20fd0d6a21fe0d20fd0d20fe0d6a21ff0d20fe0d20ff0d6a21800e20ff0d20800e" + "6a21810e20800e20810e6a21820e20810e20820e6a21830e20820e20830e6a21840e20830e20840e6a21850e20840e" + "20850e6a21860e20850e20860e6a21870e20860e20870e6a21880e20870e20880e6a21890e20880e20890e6a218a0e" + "20890e208a0e6a218b0e208a0e208b0e6a218c0e208b0e208c0e6a218d0e208c0e208d0e6a218e0e208d0e208e0e6a" + "218f0e208e0e208f0e6a21900e208f0e20900e6a21910e20900e20910e6a21920e20910e20920e6a21930e20920e20" + "930e6a21940e20930e20940e6a21950e20940e20950e6a21960e20950e20960e6a21970e20960e20970e6a21980e20" + "970e20980e6a21990e20980e20990e6a219a0e20990e209a0e6a219b0e209a0e209b0e6a219c0e209b0e209c0e6a21" + "9d0e209c0e209d0e6a219e0e209d0e209e0e6a219f0e209e0e209f0e6a21a00e209f0e20a00e6a21a10e20a00e20a1" + "0e6a21a20e20a10e20a20e6a21a30e20a20e20a30e6a21a40e20a30e20a40e6a21a50e20a40e20a50e6a21a60e20a5" + "0e20a60e6a21a70e20a60e20a70e6a21a80e20a70e20a80e6a21a90e20a80e20a90e6a21aa0e20a90e20aa0e6a21ab" + "0e20aa0e20ab0e6a21ac0e20ab0e20ac0e6a21ad0e20ac0e20ad0e6a21ae0e20ad0e20ae0e6a21af0e20ae0e20af0e" + "6a21b00e20af0e20b00e6a21b10e20b00e20b10e6a21b20e20b10e20b20e6a21b30e20b20e20b30e6a21b40e20b30e" + "20b40e6a21b50e20b40e20b50e6a21b60e20b50e20b60e6a21b70e20b60e20b70e6a21b80e20b70e20b80e6a21b90e" + "20b80e20b90e6a21ba0e20b90e20ba0e6a21bb0e20ba0e20bb0e6a21bc0e20bb0e20bc0e6a21bd0e20bc0e20bd0e6a" + "21be0e20bd0e20be0e6a21bf0e20be0e20bf0e6a21c00e20bf0e20c00e6a21c10e20c00e20c10e6a21c20e20c10e20" + "c20e6a21c30e20c20e20c30e6a21c40e20c30e20c40e6a21c50e20c40e20c50e6a21c60e20c50e20c60e6a21c70e20" + "c60e20c70e6a21c80e20c70e20c80e6a21c90e20c80e20c90e6a21ca0e20c90e20ca0e6a21cb0e20ca0e20cb0e6a21" + "cc0e20cb0e20cc0e6a21cd0e20cc0e20cd0e6a21ce0e20cd0e20ce0e6a21cf0e20ce0e20cf0e6a21d00e20cf0e20d0" + "0e6a21d10e20d00e20d10e6a21d20e20d10e20d20e6a21d30e20d20e20d30e6a21d40e20d30e20d40e6a21d50e20d4" + "0e20d50e6a21d60e20d50e20d60e6a21d70e20d60e20d70e6a21d80e20d70e20d80e6a21d90e20d80e20d90e6a21da" + "0e20d90e20da0e6a21db0e20da0e20db0e6a21dc0e20db0e20dc0e6a21dd0e20dc0e20dd0e6a21de0e20dd0e20de0e" + "6a21df0e20de0e20df0e6a21e00e20df0e20e00e6a21e10e20e00e20e10e6a21e20e20e10e20e20e6a21e30e20e20e" + "20e30e6a21e40e20e30e20e40e6a21e50e20e40e20e50e6a21e60e20e50e20e60e6a21e70e20e60e20e70e6a21e80e" + "20e70e20e80e6a21e90e20e80e20e90e6a21ea0e20e90e20ea0e6a21eb0e20ea0e20eb0e6a21ec0e20eb0e20ec0e6a" + "21ed0e20ec0e20ed0e6a21ee0e20ed0e20ee0e6a21ef0e20ee0e20ef0e6a21f00e20ef0e20f00e6a21f10e20f00e20" + "f10e6a21f20e20f10e20f20e6a21f30e20f20e20f30e6a21f40e20f30e20f40e6a21f50e20f40e20f50e6a21f60e20" + "f50e20f60e6a21f70e20f60e20f70e6a21f80e20f70e20f80e6a21f90e20f80e20f90e6a21fa0e20f90e20fa0e6a21" + "fb0e20fa0e20fb0e6a21fc0e20fb0e20fc0e6a21fd0e20fc0e20fd0e6a21fe0e20fd0e20fe0e6a21ff0e20fe0e20ff" + "0e6a21800f20ff0e20800f6a21810f20800f20810f6a21820f20810f20820f6a21830f20820f20830f6a21840f2083" + "0f20840f6a21850f20840f20850f6a21860f20850f20860f6a21870f20860f20870f6a21880f20870f20880f6a2189" + "0f20880f20890f6a218a0f20890f208a0f6a218b0f208a0f208b0f6a218c0f208b0f208c0f6a218d0f208c0f208d0f" + "6a218e0f208d0f208e0f6a218f0f208e0f208f0f6a21900f208f0f20900f6a21910f20900f20910f6a21920f20910f" + "20920f6a21930f20920f20930f6a21940f20930f20940f6a21950f20940f20950f6a21960f20950f20960f6a21970f" + "20960f20970f6a21980f20970f20980f6a21990f20980f20990f6a219a0f20990f209a0f6a219b0f209a0f209b0f6a" + "219c0f209b0f209c0f6a219d0f209c0f209d0f6a219e0f209d0f209e0f6a219f0f209e0f209f0f6a21a00f209f0f20" + "a00f6a21a10f20a00f20a10f6a21a20f20a10f20a20f6a21a30f20a20f20a30f6a21a40f20a30f20a40f6a21a50f20" + "a40f20a50f6a21a60f20a50f20a60f6a21a70f20a60f20a70f6a21a80f20a70f20a80f6a21a90f20a80f20a90f6a21" + "aa0f20a90f20aa0f6a21ab0f20aa0f20ab0f6a21ac0f20ab0f20ac0f6a21ad0f20ac0f20ad0f6a21ae0f20ad0f20ae" + "0f6a21af0f20ae0f20af0f6a21b00f20af0f20b00f6a21b10f20b00f20b10f6a21b20f20b10f20b20f6a21b30f20b2" + "0f20b30f6a21b40f20b30f20b40f6a21b50f20b40f20b50f6a21b60f20b50f20b60f6a21b70f20b60f20b70f6a21b8" + "0f20b70f20b80f6a21b90f20b80f20b90f6a21ba0f20b90f20ba0f6a21bb0f20ba0f20bb0f6a21bc0f20bb0f20bc0f" + "6a21bd0f20bc0f20bd0f6a21be0f20bd0f20be0f6a21bf0f20be0f20bf0f6a21c00f20bf0f20c00f6a21c10f20c00f" + "20c10f6a21c20f20c10f20c20f6a21c30f20c20f20c30f6a21c40f20c30f20c40f6a21c50f20c40f20c50f6a21c60f" + "20c50f20c60f6a21c70f20c60f20c70f6a21c80f20c70f20c80f6a21c90f20c80f20c90f6a21ca0f20c90f20ca0f6a" + "21cb0f20ca0f20cb0f6a21cc0f20cb0f20cc0f6a21cd0f20cc0f20cd0f6a21ce0f20cd0f20ce0f6a21cf0f20ce0f20" + "cf0f6a21d00f20cf0f20d00f6a21d10f20d00f20d10f6a21d20f20d10f20d20f6a21d30f20d20f20d30f6a21d40f20" + "d30f20d40f6a21d50f20d40f20d50f6a21d60f20d50f20d60f6a21d70f20d60f20d70f6a21d80f20d70f20d80f6a21" + "d90f20d80f20d90f6a21da0f20d90f20da0f6a21db0f20da0f20db0f6a21dc0f20db0f20dc0f6a21dd0f20dc0f20dd" + "0f6a21de0f20dd0f20de0f6a21df0f20de0f20df0f6a21e00f20df0f20e00f6a21e10f20e00f20e10f6a21e20f20e1" + "0f20e20f6a21e30f20e20f20e30f6a21e40f20e30f20e40f6a21e50f20e40f20e50f6a21e60f20e50f20e60f6a21e7" + "0f20e60f20e70f6a21e80f20e70f20e80f6a21e90f20e80f20e90f6a21ea0f20e90f20ea0f6a21eb0f20ea0f20eb0f" + "6a21ec0f20eb0f20ec0f6a21ed0f20ec0f20ed0f6a21ee0f20ed0f20ee0f6a21ef0f20ee0f20ef0f6a21f00f20ef0f" + "20f00f6a21f10f20f00f20f10f6a21f20f20f10f20f20f6a21f30f20f20f20f30f6a21f40f20f30f20f40f6a21f50f" + "20f40f20f50f6a21f60f20f50f20f60f6a21f70f20f60f20f70f6a21f80f20f70f20f80f6a21f90f20f80f20f90f6a" + "21fa0f20f90f20fa0f6a21fb0f20fa0f20fb0f6a21fc0f20fb0f20fc0f6a21fd0f20fc0f20fd0f6a21fe0f20fd0f20" + "fe0f6a21ff0f20fe0f20ff0f6a21801020ff0f2080106a2181102080102081106a2182102081102082106a21831020" + "82102083106a2184102083102084106a2185102084102085106a2186102085102086106a2187102086102087106a21" + "88102087102088106a2189102088102089106a218a10208910208a106a218b10208a10208b106a218c10208b10208c" + "106a218d10208c10208d106a218e10208d10208e106a218f10208e10208f106a219010208f102090106a2191102090" + "102091106a2192102091102092106a2193102092102093106a2194102093102094106a2195102094102095106a2196" + "102095102096106a2197102096102097106a2198102097102098106a2199102098102099106a219a10209910209a10" + "6a219b10209a10209b106a219c10209b10209c106a219d10209c10209d106a219e10209d10209e106a219f10209e10" + "209f106a21a010209f1020a0106a21a11020a01020a1106a21a21020a11020a2106a21a31020a21020a3106a21a410" + "20a31020a4106a21a51020a41020a5106a21a61020a51020a6106a21a71020a61020a7106a21a81020a71020a8106a" + "21a91020a81020a9106a21aa1020a91020aa106a21ab1020aa1020ab106a21ac1020ab1020ac106a21ad1020ac1020" + "ad106a21ae1020ad1020ae106a21af1020ae1020af106a21b01020af1020b0106a21b11020b01020b1106a21b21020" + "b11020b2106a21b31020b21020b3106a21b41020b31020b4106a21b51020b41020b5106a21b61020b51020b6106a21" + "b71020b61020b7106a21b81020b71020b8106a21b91020b81020b9106a21ba1020b91020ba106a21bb1020ba1020bb" + "106a21bc1020bb1020bc106a21bd1020bc1020bd106a21be1020bd1020be106a21bf1020be1020bf106a21c01020bf" + "1020c0106a21c11020c01020c1106a21c21020c11020c2106a21c31020c21020c3106a21c41020c31020c4106a21c5" + "1020c41020c5106a21c61020c51020c6106a21c71020c61020c7106a21c81020c71020c8106a21c91020c81020c910" + "6a21ca1020c91020ca106a21cb1020ca1020cb106a21cc1020cb1020cc106a21cd1020cc1020cd106a21ce1020cd10" + "20ce106a21cf1020ce1020cf106a21d01020cf1020d0106a21d11020d01020d1106a21d21020d11020d2106a21d310" + "20d21020d3106a21d41020d31020d4106a21d51020d41020d5106a21d61020d51020d6106a21d71020d61020d7106a" + "21d81020d71020d8106a21d91020d81020d9106a21da1020d91020da106a21db1020da1020db106a21dc1020db1020" + "dc106a21dd1020dc1020dd106a21de1020dd1020de106a21df1020de1020df106a21e01020df1020e0106a21e11020" + "e01020e1106a21e21020e11020e2106a21e31020e21020e3106a21e41020e31020e4106a21e51020e41020e5106a21" + "e61020e51020e6106a21e71020e61020e7106a21e81020e71020e8106a21e91020e81020e9106a21ea1020e91020ea" + "106a21eb1020ea1020eb106a21ec1020eb1020ec106a21ed1020ec1020ed106a21ee1020ed1020ee106a21ef1020ee" + "1020ef106a21f01020ef1020f0106a21f11020f01020f1106a21f21020f11020f2106a21f31020f21020f3106a21f4" + "1020f31020f4106a21f51020f41020f5106a21f61020f51020f6106a21f71020f61020f7106a21f81020f71020f810" + "6a21f91020f81020f9106a21fa1020f91020fa106a21fb1020fa1020fb106a21fc1020fb1020fc106a21fd1020fc10" + "20fd106a21fe1020fd1020fe106a21ff1020fe1020ff106a21801120ff102080116a2181112080112081116a218211" + "2081112082116a2183112082112083116a2184112083112084116a2185112084112085116a2186112085112086116a" + "2187112086112087116a2188112087112088116a2189112088112089116a218a11208911208a116a218b11208a1120" + "8b116a218c11208b11208c116a218d11208c11208d116a218e11208d11208e116a218f11208e11208f116a21901120" + "8f112090116a2191112090112091116a2192112091112092116a2193112092112093116a2194112093112094116a21" + "95112094112095116a2196112095112096116a2197112096112097116a2198112097112098116a2199112098112099" + "116a219a11209911209a116a219b11209a11209b116a219c11209b11209c116a219d11209c11209d116a219e11209d" + "11209e116a219f11209e11209f116a21a011209f1120a0116a21a11120a01120a1116a21a21120a11120a2116a21a3" + "1120a21120a3116a21a41120a31120a4116a21a51120a41120a5116a21a61120a51120a6116a21a71120a61120a711" + "6a21a81120a71120a8116a21a91120a81120a9116a21aa1120a91120aa116a21ab1120aa1120ab116a21ac1120ab11" + "20ac116a21ad1120ac1120ad116a21ae1120ad1120ae116a21af1120ae1120af116a21b01120af1120b0116a21b111" + "20b01120b1116a21b21120b11120b2116a21b31120b21120b3116a21b41120b31120b4116a21b51120b41120b5116a" + "21b61120b51120b6116a21b71120b61120b7116a21b81120b71120b8116a21b91120b81120b9116a21ba1120b91120" + "ba116a21bb1120ba1120bb116a21bc1120bb1120bc116a21bd1120bc1120bd116a21be1120bd1120be116a21bf1120" + "be1120bf116a21c01120bf1120c0116a21c11120c01120c1116a21c21120c11120c2116a21c31120c21120c3116a21" + "c41120c31120c4116a21c51120c41120c5116a21c61120c51120c6116a21c71120c61120c7116a21c81120c71120c8" + "116a21c91120c81120c9116a21ca1120c91120ca116a21cb1120ca1120cb116a21cc1120cb1120cc116a21cd1120cc" + "1120cd116a21ce1120cd1120ce116a21cf1120ce1120cf116a21d01120cf1120d0116a21d11120d01120d1116a21d2" + "1120d11120d2116a21d31120d21120d3116a21d41120d31120d4116a21d51120d41120d5116a21d61120d51120d611" + "6a21d71120d61120d7116a21d81120d71120d8116a21d91120d81120d9116a21da1120d91120da116a21db1120da11" + "20db116a21dc1120db1120dc116a21dd1120dc1120dd116a21de1120dd1120de116a21df1120de1120df116a21e011" + "20df1120e0116a21e11120e01120e1116a21e21120e11120e2116a21e31120e21120e3116a21e41120e31120e4116a" + "21e51120e41120e5116a21e61120e51120e6116a21e71120e61120e7116a21e81120e71120e8116a21e91120e81120" + "e9116a21ea1120e91120ea116a21eb1120ea1120eb116a21ec1120eb1120ec116a21ed1120ec1120ed116a21ee1120" + "ed1120ee116a21ef1120ee1120ef116a21f01120ef1120f0116a21f11120f01120f1116a21f21120f11120f2116a21" + "f31120f21120f3116a21f41120f31120f4116a21f51120f41120f5116a21f61120f51120f6116a21f71120f61120f7" + "116a21f81120f71120f8116a21f91120f81120f9116a21fa1120f91120fa116a21fb1120fa1120fb116a21fc1120fb" + "1120fc116a21fd1120fc1120fd116a21fe1120fd1120fe116a21ff1120fe1120ff116a21801220ff112080126a2181" + "122080122081126a2182122081122082126a2183122082122083126a2184122083122084126a218512208412208512" + "6a2186122085122086126a2187122086122087126a2188122087122088126a2189122088122089126a218a12208912" + "208a126a218b12208a12208b126a218c12208b12208c126a218d12208c12208d126a218e12208d12208e126a218f12" + "208e12208f126a219012208f122090126a2191122090122091126a2192122091122092126a2193122092122093126a" + "2194122093122094126a2195122094122095126a2196122095122096126a2197122096122097126a21981220971220" + "98126a2199122098122099126a219a12209912209a126a219b12209a12209b126a219c12209b12209c126a219d1220" + "9c12209d126a219e12209d12209e126a219f12209e12209f126a21a012209f1220a0126a21a11220a01220a1126a21" + "a21220a11220a2126a21a31220a21220a3126a21a41220a31220a4126a21a51220a41220a5126a21a61220a51220a6" + "126a21a71220a61220a7126a21a81220a71220a8126a21a91220a81220a9126a21aa1220a91220aa126a21ab1220aa" + "1220ab126a21ac1220ab1220ac126a21ad1220ac1220ad126a21ae1220ad1220ae126a21af1220ae1220af126a21b0" + "1220af1220b0126a21b11220b01220b1126a21b21220b11220b2126a21b31220b21220b3126a21b41220b31220b412" + "6a21b51220b41220b5126a21b61220b51220b6126a21b71220b61220b7126a21b81220b71220b8126a21b91220b812" + "20b9126a21ba1220b91220ba126a21bb1220ba1220bb126a21bc1220bb1220bc126a21bd1220bc1220bd126a21be12" + "20bd1220be126a21bf1220be1220bf126a21c01220bf1220c0126a21c11220c01220c1126a21c21220c11220c2126a" + "21c31220c21220c3126a21c41220c31220c4126a21c51220c41220c5126a21c61220c51220c6126a21c71220c61220" + "c7126a21c81220c71220c8126a21c91220c81220c9126a21ca1220c91220ca126a21cb1220ca1220cb126a21cc1220" + "cb1220cc126a21cd1220cc1220cd126a21ce1220cd1220ce126a21cf1220ce1220cf126a21d01220cf1220d0126a21" + "d11220d01220d1126a21d21220d11220d2126a21d31220d21220d3126a21d41220d31220d4126a21d51220d41220d5" + "126a21d61220d51220d6126a21d71220d61220d7126a21d81220d71220d8126a21d91220d81220d9126a21da1220d9" + "1220da126a21db1220da1220db126a21dc1220db1220dc126a21dd1220dc1220dd126a21de1220dd1220de126a21df" + "1220de1220df126a21e01220df1220e0126a21e11220e01220e1126a21e21220e11220e2126a21e31220e21220e312" + "6a21e41220e31220e4126a21e51220e41220e5126a21e61220e51220e6126a21e71220e61220e7126a21e81220e712" + "20e8126a21e91220e81220e9126a21ea1220e91220ea126a21eb1220ea1220eb126a21ec1220eb1220ec126a21ed12" + "20ec1220ed126a21ee1220ed1220ee126a21ef1220ee1220ef126a21f01220ef1220f0126a21f11220f01220f1126a" + "21f21220f11220f2126a21f31220f21220f3126a21f41220f31220f4126a21f51220f41220f5126a21f61220f51220" + "f6126a21f71220f61220f7126a21f81220f71220f8126a21f91220f81220f9126a21fa1220f91220fa126a21fb1220" + "fa1220fb126a21fc1220fb1220fc126a21fd1220fc1220fd126a21fe1220fd1220fe126a21ff1220fe1220ff126a21" + "801320ff122080136a2181132080132081136a2182132081132082136a2183132082132083136a2184132083132084" + "136a2185132084132085136a2186132085132086136a2187132086132087136a2188132087132088136a2189132088" + "132089136a218a13208913208a136a218b13208a13208b136a218c13208b13208c136a218d13208c13208d136a218e" + "13208d13208e136a218f13208e13208f136a219013208f132090136a2191132090132091136a219213209113209213" + "6a2193132092132093136a2194132093132094136a2195132094132095136a2196132095132096136a219713209613" + "2097136a2198132097132098136a2199132098132099136a219a13209913209a136a219b13209a13209b136a219c13" + "209b13209c136a219d13209c13209d136a219e13209d13209e136a219f13209e13209f136a21a013209f1320a0136a" + "21a11320a01320a1136a21a21320a11320a2136a21a31320a21320a3136a21a41320a31320a4136a21a51320a41320" + "a5136a21a61320a51320a6136a21a71320a61320a7136a21a81320a71320a8136a21a91320a81320a9136a21aa1320" + "a91320aa136a21ab1320aa1320ab136a21ac1320ab1320ac136a21ad1320ac1320ad136a21ae1320ad1320ae136a21" + "af1320ae1320af136a21b01320af1320b0136a21b11320b01320b1136a21b21320b11320b2136a21b31320b21320b3" + "136a21b41320b31320b4136a21b51320b41320b5136a21b61320b51320b6136a21b71320b61320b7136a21b81320b7" + "1320b8136a21b91320b81320b9136a21ba1320b91320ba136a21bb1320ba1320bb136a21bc1320bb1320bc136a21bd" + "1320bc1320bd136a21be1320bd1320be136a21bf1320be1320bf136a21c01320bf1320c0136a21c11320c01320c113" + "6a21c21320c11320c2136a21c31320c21320c3136a21c41320c31320c4136a21c51320c41320c5136a21c61320c513" + "20c6136a21c71320c61320c7136a21c81320c71320c8136a21c91320c81320c9136a21ca1320c91320ca136a21cb13" + "20ca1320cb136a21cc1320cb1320cc136a21cd1320cc1320cd136a21ce1320cd1320ce136a21cf1320ce1320cf136a" + "21d01320cf1320d0136a21d11320d01320d1136a21d21320d11320d2136a21d31320d21320d3136a21d41320d31320" + "d4136a21d51320d41320d5136a21d61320d51320d6136a21d71320d61320d7136a21d81320d71320d8136a21d91320" + "d81320d9136a21da1320d91320da136a21db1320da1320db136a21dc1320db1320dc136a21dd1320dc1320dd136a21" + "de1320dd1320de136a21df1320de1320df136a21e01320df1320e0136a21e11320e01320e1136a21e21320e11320e2" + "136a21e31320e21320e3136a21e41320e31320e4136a21e51320e41320e5136a21e61320e51320e6136a21e71320e6" + "1320e7136a21e81320e71320e8136a21e91320e81320e9136a21ea1320e91320ea136a21eb1320ea1320eb136a21ec" + "1320eb1320ec136a21ed1320ec1320ed136a21ee1320ed1320ee136a21ef1320ee1320ef136a21f01320ef1320f013" + "6a21f11320f01320f1136a21f21320f11320f2136a21f31320f21320f3136a21f41320f31320f4136a21f51320f413" + "20f5136a21f61320f51320f6136a21f71320f61320f7136a21f81320f71320f8136a21f91320f81320f9136a21fa13" + "20f91320fa136a21fb1320fa1320fb136a21fc1320fb1320fc136a21fd1320fc1320fd136a21fe1320fd1320fe136a" + "21ff1320fe1320ff136a21801420ff132080146a2181142080142081146a2182142081142082146a21831420821420" + "83146a2184142083142084146a2185142084142085146a2186142085142086146a2187142086142087146a21881420" + "87142088146a2189142088142089146a218a14208914208a146a218b14208a14208b146a218c14208b14208c146a21" + "8d14208c14208d146a218e14208d14208e146a218f14208e14208f146a219014208f142090146a2191142090142091" + "146a2192142091142092146a2193142092142093146a2194142093142094146a2195142094142095146a2196142095" + "142096146a2197142096142097146a2198142097142098146a2199142098142099146a219a14209914209a146a219b" + "14209a14209b146a219c14209b14209c146a219d14209c14209d146a219e14209d14209e146a219f14209e14209f14" + "6a21a014209f1420a0146a21a11420a01420a1146a21a21420a11420a2146a21a31420a21420a3146a21a41420a314" + "20a4146a21a51420a41420a5146a21a61420a51420a6146a21a71420a61420a7146a21a81420a71420a8146a21a914" + "20a81420a9146a21aa1420a91420aa146a21ab1420aa1420ab146a21ac1420ab1420ac146a21ad1420ac1420ad146a" + "21ae1420ad1420ae146a21af1420ae1420af146a21b01420af1420b0146a21b11420b01420b1146a21b21420b11420" + "b2146a21b31420b21420b3146a21b41420b31420b4146a21b51420b41420b5146a21b61420b51420b6146a21b71420" + "b61420b7146a21b81420b71420b8146a21b91420b81420b9146a21ba1420b91420ba146a21bb1420ba1420bb146a21" + "bc1420bb1420bc146a21bd1420bc1420bd146a21be1420bd1420be146a21bf1420be1420bf146a21c01420bf1420c0" + "146a21c11420c01420c1146a21c21420c11420c2146a21c31420c21420c3146a21c41420c31420c4146a21c51420c4" + "1420c5146a21c61420c51420c6146a21c71420c61420c7146a21c81420c71420c8146a21c91420c81420c9146a21ca" + "1420c91420ca146a21cb1420ca1420cb146a21cc1420cb1420cc146a21cd1420cc1420cd146a21ce1420cd1420ce14" + "6a21cf1420ce1420cf146a21d01420cf1420d0146a21d11420d01420d1146a21d21420d11420d2146a21d31420d214" + "20d3146a21d41420d31420d4146a21d51420d41420d5146a21d61420d51420d6146a21d71420d61420d7146a21d814" + "20d71420d8146a21d91420d81420d9146a21da1420d91420da146a21db1420da1420db146a21dc1420db1420dc146a" + "21dd1420dc1420dd146a21de1420dd1420de146a21df1420de1420df146a21e01420df1420e0146a21e11420e01420" + "e1146a21e21420e11420e2146a21e31420e21420e3146a21e41420e31420e4146a21e51420e41420e5146a21e61420" + "e51420e6146a21e71420e61420e7146a21e81420e71420e8146a21e91420e81420e9146a21ea1420e91420ea146a21" + "eb1420ea1420eb146a21ec1420eb1420ec146a21ed1420ec1420ed146a21ee1420ed1420ee146a21ef1420ee1420ef" + "146a21f01420ef1420f0146a21f11420f01420f1146a21f21420f11420f2146a21f31420f21420f3146a21f41420f3" + "1420f4146a21f51420f41420f5146a21f61420f51420f6146a21f71420f61420f7146a21f81420f71420f8146a21f9" + "1420f81420f9146a21fa1420f91420fa146a21fb1420fa1420fb146a21fc1420fb1420fc146a21fd1420fc1420fd14" + "6a21fe1420fd1420fe146a21ff1420fe1420ff146a21801520ff142080156a2181152080152081156a218215208115" + "2082156a2183152082152083156a2184152083152084156a2185152084152085156a2186152085152086156a218715" + "2086152087156a2188152087152088156a2189152088152089156a218a15208915208a156a218b15208a15208b156a" + "218c15208b15208c156a218d15208c15208d156a218e15208d15208e156a218f15208e15208f156a219015208f1520" + "90156a2191152090152091156a2192152091152092156a2193152092152093156a2194152093152094156a21951520" + "94152095156a2196152095152096156a2197152096152097156a2198152097152098156a2199152098152099156a21" + "9a15209915209a156a219b15209a15209b156a219c15209b15209c156a219d15209c15209d156a219e15209d15209e" + "156a219f15209e15209f156a21a015209f1520a0156a21a11520a01520a1156a21a21520a11520a2156a21a31520a2" + "1520a3156a21a41520a31520a4156a21a51520a41520a5156a21a61520a51520a6156a21a71520a61520a7156a21a8" + "1520a71520a8156a21a91520a81520a9156a21aa1520a91520aa156a21ab1520aa1520ab156a21ac1520ab1520ac15" + "6a21ad1520ac1520ad156a21ae1520ad1520ae156a21af1520ae1520af156a21b01520af1520b0156a21b11520b015" + "20b1156a21b21520b11520b2156a21b31520b21520b3156a21b41520b31520b4156a21b51520b41520b5156a21b615" + "20b51520b6156a21b71520b61520b7156a21b81520b71520b8156a21b91520b81520b9156a21ba1520b91520ba156a" + "21bb1520ba1520bb156a21bc1520bb1520bc156a21bd1520bc1520bd156a21be1520bd1520be156a21bf1520be1520" + "bf156a21c01520bf1520c0156a21c11520c01520c1156a21c21520c11520c2156a21c31520c21520c3156a21c41520" + "c31520c4156a21c51520c41520c5156a21c61520c51520c6156a21c71520c61520c7156a21c81520c71520c8156a21" + "c91520c81520c9156a21ca1520c91520ca156a21cb1520ca1520cb156a21cc1520cb1520cc156a21cd1520cc1520cd" + "156a21ce1520cd1520ce156a21cf1520ce1520cf156a21d01520cf1520d0156a21d11520d01520d1156a21d21520d1" + "1520d2156a21d31520d21520d3156a21d41520d31520d4156a21d51520d41520d5156a21d61520d51520d6156a21d7" + "1520d61520d7156a21d81520d71520d8156a21d91520d81520d9156a21da1520d91520da156a21db1520da1520db15" + "6a21dc1520db1520dc156a21dd1520dc1520dd156a21de1520dd1520de156a21df1520de1520df156a21e01520df15" + "20e0156a21e11520e01520e1156a21e21520e11520e2156a21e31520e21520e3156a21e41520e31520e4156a21e515" + "20e41520e5156a21e61520e51520e6156a21e71520e61520e7156a21e81520e71520e8156a21e91520e81520e9156a" + "21ea1520e91520ea156a21eb1520ea1520eb156a21ec1520eb1520ec156a21ed1520ec1520ed156a21ee1520ed1520" + "ee156a21ef1520ee1520ef156a21f01520ef1520f0156a21f11520f01520f1156a21f21520f11520f2156a21f31520" + "f21520f3156a21f41520f31520f4156a21f51520f41520f5156a21f61520f51520f6156a21f71520f61520f7156a21" + "f81520f71520f8156a21f91520f81520f9156a21fa1520f91520fa156a21fb1520fa1520fb156a21fc1520fb1520fc" + "156a21fd1520fc1520fd156a21fe1520fd1520fe156a21ff1520fe1520ff156a21801620ff152080166a2181162080" + "162081166a2182162081162082166a2183162082162083166a2184162083162084166a2185162084162085166a2186" + "162085162086166a2187162086162087166a2188162087162088166a2189162088162089166a218a16208916208a16" + "6a218b16208a16208b166a218c16208b16208c166a218d16208c16208d166a218e16208d16208e166a218f16208e16" + "208f166a219016208f162090166a2191162090162091166a2192162091162092166a2193162092162093166a219416" + "2093162094166a2195162094162095166a2196162095162096166a2197162096162097166a2198162097162098166a" + "2199162098162099166a219a16209916209a166a219b16209a16209b166a219c16209b16209c166a219d16209c1620" + "9d166a219e16209d16209e166a219f16209e16209f166a21a016209f1620a0166a21a11620a01620a1166a21a21620" + "a11620a2166a21a31620a21620a3166a21a41620a31620a4166a21a51620a41620a5166a21a61620a51620a6166a21" + "a71620a61620a7166a21a81620a71620a8166a21a91620a81620a9166a21aa1620a91620aa166a21ab1620aa1620ab" + "166a21ac1620ab1620ac166a21ad1620ac1620ad166a21ae1620ad1620ae166a21af1620ae1620af166a21b01620af" + "1620b0166a21b11620b01620b1166a21b21620b11620b2166a21b31620b21620b3166a21b41620b31620b4166a21b5" + "1620b41620b5166a21b61620b51620b6166a21b71620b61620b7166a21b81620b71620b8166a21b91620b81620b916" + "6a21ba1620b91620ba166a21bb1620ba1620bb166a21bc1620bb1620bc166a21bd1620bc1620bd166a21be1620bd16" + "20be166a21bf1620be1620bf166a21c01620bf1620c0166a21c11620c01620c1166a21c21620c11620c2166a21c316" + "20c21620c3166a21c41620c31620c4166a21c51620c41620c5166a21c61620c51620c6166a21c71620c61620c7166a" + "21c81620c71620c8166a21c91620c81620c9166a21ca1620c91620ca166a21cb1620ca1620cb166a21cc1620cb1620" + "cc166a21cd1620cc1620cd166a21ce1620cd1620ce166a21cf1620ce1620cf166a21d01620cf1620d0166a21d11620" + "d01620d1166a21d21620d11620d2166a21d31620d21620d3166a21d41620d31620d4166a21d51620d41620d5166a21" + "d61620d51620d6166a21d71620d61620d7166a21d81620d71620d8166a21d91620d81620d9166a21da1620d91620da" + "166a21db1620da1620db166a21dc1620db1620dc166a21dd1620dc1620dd166a21de1620dd1620de166a21df1620de" + "1620df166a21e01620df1620e0166a21e11620e01620e1166a21e21620e11620e2166a21e31620e21620e3166a21e4" + "1620e31620e4166a21e51620e41620e5166a21e61620e51620e6166a21e71620e61620e7166a21e81620e71620e816" + "6a21e91620e81620e9166a21ea1620e91620ea166a21eb1620ea1620eb166a21ec1620eb1620ec166a21ed1620ec16" + "20ed166a21ee1620ed1620ee166a21ef1620ee1620ef166a21f01620ef1620f0166a21f11620f01620f1166a21f216" + "20f11620f2166a21f31620f21620f3166a21f41620f31620f4166a21f51620f41620f5166a21f61620f51620f6166a" + "21f71620f61620f7166a21f81620f71620f8166a21f91620f81620f9166a21fa1620f91620fa166a21fb1620fa1620" + "fb166a21fc1620fb1620fc166a21fd1620fc1620fd166a21fe1620fd1620fe166a21ff1620fe1620ff166a21801720" + "ff162080176a2181172080172081176a2182172081172082176a2183172082172083176a2184172083172084176a21" + "85172084172085176a2186172085172086176a2187172086172087176a2188172087172088176a2189172088172089" + "176a218a17208917208a176a218b17208a17208b176a218c17208b17208c176a218d17208c17208d176a218e17208d" + "17208e176a218f17208e17208f176a219017208f172090176a2191172090172091176a2192172091172092176a2193" + "172092172093176a2194172093172094176a2195172094172095176a2196172095172096176a219717209617209717" + "6a2198172097172098176a2199172098172099176a219a17209917209a176a219b17209a17209b176a219c17209b17" + "209c176a219d17209c17209d176a219e17209d17209e176a219f17209e17209f176a21a017209f1720a0176a21a117" + "20a01720a1176a21a21720a11720a2176a21a31720a21720a3176a21a41720a31720a4176a21a51720a41720a5176a" + "21a61720a51720a6176a21a71720a61720a7176a21a81720a71720a8176a21a91720a81720a9176a21aa1720a91720" + "aa176a21ab1720aa1720ab176a21ac1720ab1720ac176a21ad1720ac1720ad176a21ae1720ad1720ae176a21af1720" + "ae1720af176a21b01720af1720b0176a21b11720b01720b1176a21b21720b11720b2176a21b31720b21720b3176a21" + "b41720b31720b4176a21b51720b41720b5176a21b61720b51720b6176a21b71720b61720b7176a21b81720b71720b8" + "176a21b91720b81720b9176a21ba1720b91720ba176a21bb1720ba1720bb176a21bc1720bb1720bc176a21bd1720bc" + "1720bd176a21be1720bd1720be176a21bf1720be1720bf176a21c01720bf1720c0176a21c11720c01720c1176a21c2" + "1720c11720c2176a21c31720c21720c3176a21c41720c31720c4176a21c51720c41720c5176a21c61720c51720c617" + "6a21c71720c61720c7176a21c81720c71720c8176a21c91720c81720c9176a21ca1720c91720ca176a21cb1720ca17" + "20cb176a21cc1720cb1720cc176a21cd1720cc1720cd176a21ce1720cd1720ce176a21cf1720ce1720cf176a21d017" + "20cf1720d0176a21d11720d01720d1176a21d21720d11720d2176a21d31720d21720d3176a21d41720d31720d4176a" + "21d51720d41720d5176a21d61720d51720d6176a21d71720d61720d7176a21d81720d71720d8176a21d91720d81720" + "d9176a21da1720d91720da176a21db1720da1720db176a21dc1720db1720dc176a21dd1720dc1720dd176a21de1720" + "dd1720de176a21df1720de1720df176a21e01720df1720e0176a21e11720e01720e1176a21e21720e11720e2176a21" + "e31720e21720e3176a21e41720e31720e4176a21e51720e41720e5176a21e61720e51720e6176a21e71720e61720e7" + "176a21e81720e71720e8176a21e91720e81720e9176a21ea1720e91720ea176a21eb1720ea1720eb176a21ec1720eb" + "1720ec176a21ed1720ec1720ed176a21ee1720ed1720ee176a21ef1720ee1720ef176a21f01720ef1720f0176a21f1" + "1720f01720f1176a21f21720f11720f2176a21f31720f21720f3176a21f41720f31720f4176a21f51720f41720f517" + "6a21f61720f51720f6176a21f71720f61720f7176a21f81720f71720f8176a21f91720f81720f9176a21fa1720f917" + "20fa176a21fb1720fa1720fb176a21fc1720fb1720fc176a21fd1720fc1720fd176a21fe1720fd1720fe176a21ff17" + "20fe1720ff176a21801820ff172080186a2181182080182081186a2182182081182082186a2183182082182083186a" + "2184182083182084186a2185182084182085186a2186182085182086186a2187182086182087186a21881820871820" + "88186a2189182088182089186a218a18208918208a186a218b18208a18208b186a218c18208b18208c186a218d1820" + "8c18208d186a218e18208d18208e186a218f18208e18208f186a219018208f182090186a2191182090182091186a21" + "92182091182092186a2193182092182093186a2194182093182094186a2195182094182095186a2196182095182096" + "186a2197182096182097186a2198182097182098186a2199182098182099186a219a18209918209a186a219b18209a" + "18209b186a219c18209b18209c186a219d18209c18209d186a219e18209d18209e186a219f18209e18209f186a21a0" + "18209f1820a0186a21a11820a01820a1186a21a21820a11820a2186a21a31820a21820a3186a21a41820a31820a418" + "6a21a51820a41820a5186a21a61820a51820a6186a21a71820a61820a7186a21a81820a71820a8186a21a91820a818" + "20a9186a21aa1820a91820aa186a21ab1820aa1820ab186a21ac1820ab1820ac186a21ad1820ac1820ad186a21ae18" + "20ad1820ae186a21af1820ae1820af186a21b01820af1820b0186a21b11820b01820b1186a21b21820b11820b2186a" + "21b31820b21820b3186a21b41820b31820b4186a21b51820b41820b5186a21b61820b51820b6186a21b71820b61820" + "b7186a21b81820b71820b8186a21b91820b81820b9186a21ba1820b91820ba186a21bb1820ba1820bb186a21bc1820" + "bb1820bc186a21bd1820bc1820bd186a21be1820bd1820be186a21bf1820be1820bf186a21c01820bf1820c0186a21" + "c11820c01820c1186a21c21820c11820c2186a21c31820c21820c3186a21c41820c31820c4186a21c51820c41820c5" + "186a21c61820c51820c6186a21c71820c61820c7186a21c81820c71820c8186a21c91820c81820c9186a21ca1820c9" + "1820ca186a21cb1820ca1820cb186a21cc1820cb1820cc186a21cd1820cc1820cd186a21ce1820cd1820ce186a21cf" + "1820ce1820cf186a21d01820cf1820d0186a21d11820d01820d1186a21d21820d11820d2186a21d31820d21820d318" + "6a21d41820d31820d4186a21d51820d41820d5186a21d61820d51820d6186a21d71820d61820d7186a21d81820d718" + "20d8186a21d91820d81820d9186a21da1820d91820da186a21db1820da1820db186a21dc1820db1820dc186a21dd18" + "20dc1820dd186a21de1820dd1820de186a21df1820de1820df186a21e01820df1820e0186a21e11820e01820e1186a" + "21e21820e11820e2186a21e31820e21820e3186a21e41820e31820e4186a21e51820e41820e5186a21e61820e51820" + "e6186a21e71820e61820e7186a21e81820e71820e8186a21e91820e81820e9186a21ea1820e91820ea186a21eb1820" + "ea1820eb186a21ec1820eb1820ec186a21ed1820ec1820ed186a21ee1820ed1820ee186a21ef1820ee1820ef186a21" + "f01820ef1820f0186a21f11820f01820f1186a21f21820f11820f2186a21f31820f21820f3186a21f41820f31820f4" + "186a21f51820f41820f5186a21f61820f51820f6186a21f71820f61820f7186a21f81820f71820f8186a21f91820f8" + "1820f9186a21fa1820f91820fa186a21fb1820fa1820fb186a21fc1820fb1820fc186a21fd1820fc1820fd186a21fe" + "1820fd1820fe186a21ff1820fe1820ff186a21801920ff182080196a2181192080192081196a218219208119208219" + "6a2183192082192083196a2184192083192084196a2185192084192085196a2186192085192086196a218719208619" + "2087196a2188192087192088196a2189192088192089196a218a19208919208a196a218b19208a19208b196a218c19" + "208b19208c196a218d19208c19208d196a218e19208d19208e196a218f19208e19208f196a219019208f192090196a" + "2191192090192091196a2192192091192092196a2193192092192093196a2194192093192094196a21951920941920" + "95196a2196192095192096196a2197192096192097196a2198192097192098196a2199192098192099196a219a1920" + "9919209a196a219b19209a19209b196a219c19209b19209c196a219d19209c19209d196a219e19209d19209e196a21" + "9f19209e19209f196a21a019209f1920a0196a21a11920a01920a1196a21a21920a11920a2196a21a31920a21920a3" + "196a21a41920a31920a4196a21a51920a41920a5196a21a61920a51920a6196a21a71920a61920a7196a21a81920a7" + "1920a8196a21a91920a81920a9196a21aa1920a91920aa196a21ab1920aa1920ab196a21ac1920ab1920ac196a21ad" + "1920ac1920ad196a21ae1920ad1920ae196a21af1920ae1920af196a21b01920af1920b0196a21b11920b01920b119" + "6a21b21920b11920b2196a21b31920b21920b3196a21b41920b31920b4196a21b51920b41920b5196a21b61920b519" + "20b6196a21b71920b61920b7196a21b81920b71920b8196a21b91920b81920b9196a21ba1920b91920ba196a21bb19" + "20ba1920bb196a21bc1920bb1920bc196a21bd1920bc1920bd196a21be1920bd1920be196a21bf1920be1920bf196a" + "21c01920bf1920c0196a21c11920c01920c1196a21c21920c11920c2196a21c31920c21920c3196a21c41920c31920" + "c4196a21c51920c41920c5196a21c61920c51920c6196a21c71920c61920c7196a21c81920c71920c8196a21c91920" + "c81920c9196a21ca1920c91920ca196a21cb1920ca1920cb196a21cc1920cb1920cc196a21cd1920cc1920cd196a21" + "ce1920cd1920ce196a21cf1920ce1920cf196a21d01920cf1920d0196a21d11920d01920d1196a21d21920d11920d2" + "196a21d31920d21920d3196a21d41920d31920d4196a21d51920d41920d5196a21d61920d51920d6196a21d71920d6" + "1920d7196a21d81920d71920d8196a21d91920d81920d9196a21da1920d91920da196a21db1920da1920db196a21dc" + "1920db1920dc196a21dd1920dc1920dd196a21de1920dd1920de196a21df1920de1920df196a21e01920df1920e019" + "6a21e11920e01920e1196a21e21920e11920e2196a21e31920e21920e3196a21e41920e31920e4196a21e51920e419" + "20e5196a21e61920e51920e6196a21e71920e61920e7196a21e81920e71920e8196a21e91920e81920e9196a21ea19" + "20e91920ea196a21eb1920ea1920eb196a21ec1920eb1920ec196a21ed1920ec1920ed196a21ee1920ed1920ee196a" + "21ef1920ee1920ef196a21f01920ef1920f0196a21f11920f01920f1196a21f21920f11920f2196a21f31920f21920" + "f3196a21f41920f31920f4196a21f51920f41920f5196a21f61920f51920f6196a21f71920f61920f7196a21f81920" + "f71920f8196a21f91920f81920f9196a21fa1920f91920fa196a21fb1920fa1920fb196a21fc1920fb1920fc196a21" + "fd1920fc1920fd196a21fe1920fd1920fe196a21ff1920fe1920ff196a21801a20ff1920801a6a21811a20801a2081" + "1a6a21821a20811a20821a6a21831a20821a20831a6a21841a20831a20841a6a21851a20841a20851a6a21861a2085" + "1a20861a6a21871a20861a20871a6a21881a20871a20881a6a21891a20881a20891a6a218a1a20891a208a1a6a218b" + "1a208a1a208b1a6a218c1a208b1a208c1a6a218d1a208c1a208d1a6a218e1a208d1a208e1a6a218f1a208e1a208f1a" + "6a21901a208f1a20901a6a21911a20901a20911a6a21921a20911a20921a6a21931a20921a20931a6a21941a20931a" + "20941a6a21951a20941a20951a6a21961a20951a20961a6a21971a20961a20971a6a21981a20971a20981a6a21991a" + "20981a20991a6a219a1a20991a209a1a6a219b1a209a1a209b1a6a219c1a209b1a209c1a6a219d1a209c1a209d1a6a" + "219e1a209d1a209e1a6a219f1a209e1a209f1a6a21a01a209f1a20a01a6a21a11a20a01a20a11a6a21a21a20a11a20" + "a21a6a21a31a20a21a20a31a6a21a41a20a31a20a41a6a21a51a20a41a20a51a6a21a61a20a51a20a61a6a21a71a20" + "a61a20a71a6a21a81a20a71a20a81a6a21a91a20a81a20a91a6a21aa1a20a91a20aa1a6a21ab1a20aa1a20ab1a6a21" + "ac1a20ab1a20ac1a6a21ad1a20ac1a20ad1a6a21ae1a20ad1a20ae1a6a21af1a20ae1a20af1a6a21b01a20af1a20b0" + "1a6a21b11a20b01a20b11a6a21b21a20b11a20b21a6a21b31a20b21a20b31a6a21b41a20b31a20b41a6a21b51a20b4" + "1a20b51a6a21b61a20b51a20b61a6a21b71a20b61a20b71a6a21b81a20b71a20b81a6a21b91a20b81a20b91a6a21ba" + "1a20b91a20ba1a6a21bb1a20ba1a20bb1a6a21bc1a20bb1a20bc1a6a21bd1a20bc1a20bd1a6a21be1a20bd1a20be1a" + "6a21bf1a20be1a20bf1a6a21c01a20bf1a20c01a6a21c11a20c01a20c11a6a21c21a20c11a20c21a6a21c31a20c21a" + "20c31a6a21c41a20c31a20c41a6a21c51a20c41a20c51a6a21c61a20c51a20c61a6a21c71a20c61a20c71a6a21c81a" + "20c71a20c81a6a21c91a20c81a20c91a6a21ca1a20c91a20ca1a6a21cb1a20ca1a20cb1a6a21cc1a20cb1a20cc1a6a" + "21cd1a20cc1a20cd1a6a21ce1a20cd1a20ce1a6a21cf1a20ce1a20cf1a6a21d01a20cf1a20d01a6a21d11a20d01a20" + "d11a6a21d21a20d11a20d21a6a21d31a20d21a20d31a6a21d41a20d31a20d41a6a21d51a20d41a20d51a6a21d61a20" + "d51a20d61a6a21d71a20d61a20d71a6a21d81a20d71a20d81a6a21d91a20d81a20d91a6a21da1a20d91a20da1a6a21" + "db1a20da1a20db1a6a21dc1a20db1a20dc1a6a21dd1a20dc1a20dd1a6a21de1a20dd1a20de1a6a21df1a20de1a20df" + "1a6a21e01a20df1a20e01a6a21e11a20e01a20e11a6a21e21a20e11a20e21a6a21e31a20e21a20e31a6a21e41a20e3" + "1a20e41a6a21e51a20e41a20e51a6a21e61a20e51a20e61a6a21e71a20e61a20e71a6a21e81a20e71a20e81a6a21e9" + "1a20e81a20e91a6a21ea1a20e91a20ea1a6a21eb1a20ea1a20eb1a6a21ec1a20eb1a20ec1a6a21ed1a20ec1a20ed1a" + "6a21ee1a20ed1a20ee1a6a21ef1a20ee1a20ef1a6a21f01a20ef1a20f01a6a21f11a20f01a20f11a6a21f21a20f11a" + "20f21a6a21f31a20f21a20f31a6a21f41a20f31a20f41a6a21f51a20f41a20f51a6a21f61a20f51a20f61a6a21f71a" + "20f61a20f71a6a21f81a20f71a20f81a6a21f91a20f81a20f91a6a21fa1a20f91a20fa1a6a21fb1a20fa1a20fb1a6a" + "21fc1a20fb1a20fc1a6a21fd1a20fc1a20fd1a6a21fe1a20fd1a20fe1a6a21ff1a20fe1a20ff1a6a21801b20ff1a20" + "801b6a21811b20801b20811b6a21821b20811b20821b6a21831b20821b20831b6a21841b20831b20841b6a21851b20" + "841b20851b6a21861b20851b20861b6a21871b20861b20871b6a21881b20871b20881b6a21891b20881b20891b6a21" + "8a1b20891b208a1b6a218b1b208a1b208b1b6a218c1b208b1b208c1b6a218d1b208c1b208d1b6a218e1b208d1b208e" + "1b6a218f1b208e1b208f1b6a21901b208f1b20901b6a21911b20901b20911b6a21921b20911b20921b6a21931b2092" + "1b20931b6a21941b20931b20941b6a21951b20941b20951b6a21961b20951b20961b6a21971b20961b20971b6a2198" + "1b20971b20981b6a21991b20981b20991b6a219a1b20991b209a1b6a219b1b209a1b209b1b6a219c1b209b1b209c1b" + "6a219d1b209c1b209d1b6a219e1b209d1b209e1b6a219f1b209e1b209f1b6a21a01b209f1b20a01b6a21a11b20a01b" + "20a11b6a21a21b20a11b20a21b6a21a31b20a21b20a31b6a21a41b20a31b20a41b6a21a51b20a41b20a51b6a21a61b" + "20a51b20a61b6a21a71b20a61b20a71b6a21a81b20a71b20a81b6a21a91b20a81b20a91b6a21aa1b20a91b20aa1b6a" + "21ab1b20aa1b20ab1b6a21ac1b20ab1b20ac1b6a21ad1b20ac1b20ad1b6a21ae1b20ad1b20ae1b6a21af1b20ae1b20" + "af1b6a21b01b20af1b20b01b6a21b11b20b01b20b11b6a21b21b20b11b20b21b6a21b31b20b21b20b31b6a21b41b20" + "b31b20b41b6a21b51b20b41b20b51b6a21b61b20b51b20b61b6a21b71b20b61b20b71b6a21b81b20b71b20b81b6a21" + "b91b20b81b20b91b6a21ba1b20b91b20ba1b6a21bb1b20ba1b20bb1b6a21bc1b20bb1b20bc1b6a21bd1b20bc1b20bd" + "1b6a21be1b20bd1b20be1b6a21bf1b20be1b20bf1b6a21c01b20bf1b20c01b6a21c11b20c01b20c11b6a21c21b20c1" + "1b20c21b6a21c31b20c21b20c31b6a21c41b20c31b20c41b6a21c51b20c41b20c51b6a21c61b20c51b20c61b6a21c7" + "1b20c61b20c71b6a21c81b20c71b20c81b6a21c91b20c81b20c91b6a21ca1b20c91b20ca1b6a21cb1b20ca1b20cb1b" + "6a21cc1b20cb1b20cc1b6a21cd1b20cc1b20cd1b6a21ce1b20cd1b20ce1b6a21cf1b20ce1b20cf1b6a21d01b20cf1b" + "20d01b6a21d11b20d01b20d11b6a21d21b20d11b20d21b6a21d31b20d21b20d31b6a21d41b20d31b20d41b6a21d51b" + "20d41b20d51b6a21d61b20d51b20d61b6a21d71b20d61b20d71b6a21d81b20d71b20d81b6a21d91b20d81b20d91b6a" + "21da1b20d91b20da1b6a21db1b20da1b20db1b6a21dc1b20db1b20dc1b6a21dd1b20dc1b20dd1b6a21de1b20dd1b20" + "de1b6a21df1b20de1b20df1b6a21e01b20df1b20e01b6a21e11b20e01b20e11b6a21e21b20e11b20e21b6a21e31b20" + "e21b20e31b6a21e41b20e31b20e41b6a21e51b20e41b20e51b6a21e61b20e51b20e61b6a21e71b20e61b20e71b6a21" + "e81b20e71b20e81b6a21e91b20e81b20e91b6a21ea1b20e91b20ea1b6a21eb1b20ea1b20eb1b6a21ec1b20eb1b20ec" + "1b6a21ed1b20ec1b20ed1b6a21ee1b20ed1b20ee1b6a21ef1b20ee1b20ef1b6a21f01b20ef1b20f01b6a21f11b20f0" + "1b20f11b6a21f21b20f11b20f21b6a21f31b20f21b20f31b6a21f41b20f31b20f41b6a21f51b20f41b20f51b6a21f6" + "1b20f51b20f61b6a21f71b20f61b20f71b6a21f81b20f71b20f81b6a21f91b20f81b20f91b6a21fa1b20f91b20fa1b" + "6a21fb1b20fa1b20fb1b6a21fc1b20fb1b20fc1b6a21fd1b20fc1b20fd1b6a21fe1b20fd1b20fe1b6a21ff1b20fe1b" + "20ff1b6a21801c20ff1b20801c6a21811c20801c20811c6a21821c20811c20821c6a21831c20821c20831c6a21841c" + "20831c20841c6a21851c20841c20851c6a21861c20851c20861c6a21871c20861c20871c6a21881c20871c20881c6a" + "21891c20881c20891c6a218a1c20891c208a1c6a218b1c208a1c208b1c6a218c1c208b1c208c1c6a218d1c208c1c20" + "8d1c6a218e1c208d1c208e1c6a218f1c208e1c208f1c6a21901c208f1c20901c6a21911c20901c20911c6a21921c20" + "911c20921c6a21931c20921c20931c6a21941c20931c20941c6a21951c20941c20951c6a21961c20951c20961c6a21" + "971c20961c20971c6a21981c20971c20981c6a21991c20981c20991c6a219a1c20991c209a1c6a219b1c209a1c209b" + "1c6a219c1c209b1c209c1c6a219d1c209c1c209d1c6a219e1c209d1c209e1c6a219f1c209e1c209f1c6a21a01c209f" + "1c20a01c6a21a11c20a01c20a11c6a21a21c20a11c20a21c6a21a31c20a21c20a31c6a21a41c20a31c20a41c6a21a5" + "1c20a41c20a51c6a21a61c20a51c20a61c6a21a71c20a61c20a71c6a21a81c20a71c20a81c6a21a91c20a81c20a91c" + "6a21aa1c20a91c20aa1c6a21ab1c20aa1c20ab1c6a21ac1c20ab1c20ac1c6a21ad1c20ac1c20ad1c6a21ae1c20ad1c" + "20ae1c6a21af1c20ae1c20af1c6a21b01c20af1c20b01c6a21b11c20b01c20b11c6a21b21c20b11c20b21c6a21b31c" + "20b21c20b31c6a21b41c20b31c20b41c6a21b51c20b41c20b51c6a21b61c20b51c20b61c6a21b71c20b61c20b71c6a" + "21b81c20b71c20b81c6a21b91c20b81c20b91c6a21ba1c20b91c20ba1c6a21bb1c20ba1c20bb1c6a21bc1c20bb1c20" + "bc1c6a21bd1c20bc1c20bd1c6a21be1c20bd1c20be1c6a21bf1c20be1c20bf1c6a21c01c20bf1c20c01c6a21c11c20" + "c01c20c11c6a21c21c20c11c20c21c6a21c31c20c21c20c31c6a21c41c20c31c20c41c6a21c51c20c41c20c51c6a21" + "c61c20c51c20c61c6a21c71c20c61c20c71c6a21c81c20c71c20c81c6a21c91c20c81c20c91c6a21ca1c20c91c20ca" + "1c6a21cb1c20ca1c20cb1c6a21cc1c20cb1c20cc1c6a21cd1c20cc1c20cd1c6a21ce1c20cd1c20ce1c6a21cf1c20ce" + "1c20cf1c6a21d01c20cf1c20d01c6a21d11c20d01c20d11c6a21d21c20d11c20d21c6a21d31c20d21c20d31c6a21d4" + "1c20d31c20d41c6a21d51c20d41c20d51c6a21d61c20d51c20d61c6a21d71c20d61c20d71c6a21d81c20d71c20d81c" + "6a21d91c20d81c20d91c6a21da1c20d91c20da1c6a21db1c20da1c20db1c6a21dc1c20db1c20dc1c6a21dd1c20dc1c" + "20dd1c6a21de1c20dd1c20de1c6a21df1c20de1c20df1c6a21e01c20df1c20e01c6a21e11c20e01c20e11c6a21e21c" + "20e11c20e21c6a21e31c20e21c20e31c6a21e41c20e31c20e41c6a21e51c20e41c20e51c6a21e61c20e51c20e61c6a" + "21e71c20e61c20e71c6a21e81c20e71c20e81c6a21e91c20e81c20e91c6a21ea1c20e91c20ea1c6a21eb1c20ea1c20" + "eb1c6a21ec1c20eb1c20ec1c6a21ed1c20ec1c20ed1c6a21ee1c20ed1c20ee1c6a21ef1c20ee1c20ef1c6a21f01c20" + "ef1c20f01c6a21f11c20f01c20f11c6a21f21c20f11c20f21c6a21f31c20f21c20f31c6a21f41c20f31c20f41c6a21" + "f51c20f41c20f51c6a21f61c20f51c20f61c6a21f71c20f61c20f71c6a21f81c20f71c20f81c6a21f91c20f81c20f9" + "1c6a21fa1c20f91c20fa1c6a21fb1c20fa1c20fb1c6a21fc1c20fb1c20fc1c6a21fd1c20fc1c20fd1c6a21fe1c20fd" + "1c20fe1c6a21ff1c20fe1c20ff1c6a21801d20ff1c20801d6a21811d20801d20811d6a21821d20811d20821d6a2183" + "1d20821d20831d6a21841d20831d20841d6a21851d20841d20851d6a21861d20851d20861d6a21871d20861d20871d" + "6a21881d20871d20881d6a21891d20881d20891d6a218a1d20891d208a1d6a218b1d208a1d208b1d6a218c1d208b1d" + "208c1d6a218d1d208c1d208d1d6a218e1d208d1d208e1d6a218f1d208e1d208f1d6a21901d208f1d20901d6a21911d" + "20901d20911d6a21921d20911d20921d6a21931d20921d20931d6a21941d20931d20941d6a21951d20941d20951d6a" + "21961d20951d20961d6a21971d20961d20971d6a21981d20971d20981d6a21991d20981d20991d6a219a1d20991d20" + "9a1d6a219b1d209a1d209b1d6a219c1d209b1d209c1d6a219d1d209c1d209d1d6a219e1d209d1d209e1d6a219f1d20" + "9e1d209f1d6a21a01d209f1d20a01d6a21a11d20a01d20a11d6a21a21d20a11d20a21d6a21a31d20a21d20a31d6a21" + "a41d20a31d20a41d6a21a51d20a41d20a51d6a21a61d20a51d20a61d6a21a71d20a61d20a71d6a21a81d20a71d20a8" + "1d6a21a91d20a81d20a91d6a21aa1d20a91d20aa1d6a21ab1d20aa1d20ab1d6a21ac1d20ab1d20ac1d6a21ad1d20ac" + "1d20ad1d6a21ae1d20ad1d20ae1d6a21af1d20ae1d20af1d6a21b01d20af1d20b01d6a21b11d20b01d20b11d6a21b2" + "1d20b11d20b21d6a21b31d20b21d20b31d6a21b41d20b31d20b41d6a21b51d20b41d20b51d6a21b61d20b51d20b61d" + "6a21b71d20b61d20b71d6a21b81d20b71d20b81d6a21b91d20b81d20b91d6a21ba1d20b91d20ba1d6a21bb1d20ba1d" + "20bb1d6a21bc1d20bb1d20bc1d6a21bd1d20bc1d20bd1d6a21be1d20bd1d20be1d6a21bf1d20be1d20bf1d6a21c01d" + "20bf1d20c01d6a21c11d20c01d20c11d6a21c21d20c11d20c21d6a21c31d20c21d20c31d6a21c41d20c31d20c41d6a" + "21c51d20c41d20c51d6a21c61d20c51d20c61d6a21c71d20c61d20c71d6a21c81d20c71d20c81d6a21c91d20c81d20" + "c91d6a21ca1d20c91d20ca1d6a21cb1d20ca1d20cb1d6a21cc1d20cb1d20cc1d6a21cd1d20cc1d20cd1d6a21ce1d20" + "cd1d20ce1d6a21cf1d20ce1d20cf1d6a21d01d20cf1d20d01d6a21d11d20d01d20d11d6a21d21d20d11d20d21d6a21" + "d31d20d21d20d31d6a21d41d20d31d20d41d6a21d51d20d41d20d51d6a21d61d20d51d20d61d6a21d71d20d61d20d7" + "1d6a21d81d20d71d20d81d6a21d91d20d81d20d91d6a21da1d20d91d20da1d6a21db1d20da1d20db1d6a21dc1d20db" + "1d20dc1d6a21dd1d20dc1d20dd1d6a21de1d20dd1d20de1d6a21df1d20de1d20df1d6a21e01d20df1d20e01d6a21e1" + "1d20e01d20e11d6a21e21d20e11d20e21d6a21e31d20e21d20e31d6a21e41d20e31d20e41d6a21e51d20e41d20e51d" + "6a21e61d20e51d20e61d6a21e71d20e61d20e71d6a21e81d20e71d20e81d6a21e91d20e81d20e91d6a21ea1d20e91d" + "20ea1d6a21eb1d20ea1d20eb1d6a21ec1d20eb1d20ec1d6a21ed1d20ec1d20ed1d6a21ee1d20ed1d20ee1d6a21ef1d" + "20ee1d20ef1d6a21f01d20ef1d20f01d6a21f11d20f01d20f11d6a21f21d20f11d20f21d6a21f31d20f21d20f31d6a" + "21f41d20f31d20f41d6a21f51d20f41d20f51d6a21f61d20f51d20f61d6a21f71d20f61d20f71d6a21f81d20f71d20" + "f81d6a21f91d20f81d20f91d6a21fa1d20f91d20fa1d6a21fb1d20fa1d20fb1d6a21fc1d20fb1d20fc1d6a21fd1d20" + "fc1d20fd1d6a21fe1d20fd1d20fe1d6a21ff1d20fe1d20ff1d6a21801e20ff1d20801e6a21811e20801e20811e6a21" + "821e20811e20821e6a21831e20821e20831e6a21841e20831e20841e6a21851e20841e20851e6a21861e20851e2086" + "1e6a21871e20861e20871e6a21881e20871e20881e6a21891e20881e20891e6a218a1e20891e208a1e6a218b1e208a" + "1e208b1e6a218c1e208b1e208c1e6a218d1e208c1e208d1e6a218e1e208d1e208e1e6a218f1e208e1e208f1e6a2190" + "1e208f1e20901e6a21911e20901e20911e6a21921e20911e20921e6a21931e20921e20931e6a21941e20931e20941e" + "6a21951e20941e20951e6a21961e20951e20961e6a21971e20961e20971e6a21981e20971e20981e6a21991e20981e" + "20991e6a219a1e20991e209a1e6a219b1e209a1e209b1e6a219c1e209b1e209c1e6a219d1e209c1e209d1e6a219e1e" + "209d1e209e1e6a219f1e209e1e209f1e6a21a01e209f1e20a01e6a21a11e20a01e20a11e6a21a21e20a11e20a21e6a" + "21a31e20a21e20a31e6a21a41e20a31e20a41e6a21a51e20a41e20a51e6a21a61e20a51e20a61e6a21a71e20a61e20" + "a71e6a21a81e20a71e20a81e6a21a91e20a81e20a91e6a21aa1e20a91e20aa1e6a21ab1e20aa1e20ab1e6a21ac1e20" + "ab1e20ac1e6a21ad1e20ac1e20ad1e6a21ae1e20ad1e20ae1e6a21af1e20ae1e20af1e6a21b01e20af1e20b01e6a21" + "b11e20b01e20b11e6a21b21e20b11e20b21e6a21b31e20b21e20b31e6a21b41e20b31e20b41e6a21b51e20b41e20b5" + "1e6a21b61e20b51e20b61e6a21b71e20b61e20b71e6a21b81e20b71e20b81e6a21b91e20b81e20b91e6a21ba1e20b9" + "1e20ba1e6a21bb1e20ba1e20bb1e6a21bc1e20bb1e20bc1e6a21bd1e20bc1e20bd1e6a21be1e20bd1e20be1e6a21bf" + "1e20be1e20bf1e6a21c01e20bf1e20c01e6a21c11e20c01e20c11e6a21c21e20c11e20c21e6a21c31e20c21e20c31e" + "6a21c41e20c31e20c41e6a21c51e20c41e20c51e6a21c61e20c51e20c61e6a21c71e20c61e20c71e6a21c81e20c71e" + "20c81e6a21c91e20c81e20c91e6a21ca1e20c91e20ca1e6a21cb1e20ca1e20cb1e6a21cc1e20cb1e20cc1e6a21cd1e" + "20cc1e20cd1e6a21ce1e20cd1e20ce1e6a21cf1e20ce1e20cf1e6a21d01e20cf1e20d01e6a21d11e20d01e20d11e6a" + "21d21e20d11e20d21e6a21d31e20d21e20d31e6a21d41e20d31e20d41e6a21d51e20d41e20d51e6a21d61e20d51e20" + "d61e6a21d71e20d61e20d71e6a21d81e20d71e20d81e6a21d91e20d81e20d91e6a21da1e20d91e20da1e6a21db1e20" + "da1e20db1e6a21dc1e20db1e20dc1e6a21dd1e20dc1e20dd1e6a21de1e20dd1e20de1e6a21df1e20de1e20df1e6a21" + "e01e20df1e20e01e6a21e11e20e01e20e11e6a21e21e20e11e20e21e6a21e31e20e21e20e31e6a21e41e20e31e20e4" + "1e6a21e51e20e41e20e51e6a21e61e20e51e20e61e6a21e71e20e61e20e71e6a21e81e20e71e20e81e6a21e91e20e8" + "1e20e91e6a21ea1e20e91e20ea1e6a21eb1e20ea1e20eb1e6a21ec1e20eb1e20ec1e6a21ed1e20ec1e20ed1e6a21ee" + "1e20ed1e20ee1e6a21ef1e20ee1e20ef1e6a21f01e20ef1e20f01e6a21f11e20f01e20f11e6a21f21e20f11e20f21e" + "6a21f31e20f21e20f31e6a21f41e20f31e20f41e6a21f51e20f41e20f51e6a21f61e20f51e20f61e6a21f71e20f61e" + "20f71e6a21f81e20f71e20f81e6a21f91e20f81e20f91e6a21fa1e20f91e20fa1e6a21fb1e20fa1e20fb1e6a21fc1e" + "20fb1e20fc1e6a21fd1e20fc1e20fd1e6a21fe1e20fd1e20fe1e6a21ff1e20fe1e20ff1e6a21801f20ff1e20801f6a" + "21811f20801f20811f6a21821f20811f20821f6a21831f20821f20831f6a21841f20831f20841f6a21851f20841f20" + "851f6a21861f20851f20861f6a21871f20861f20871f6a21881f20871f20881f6a21891f20881f20891f6a218a1f20" + "891f208a1f6a218b1f208a1f208b1f6a218c1f208b1f208c1f6a218d1f208c1f208d1f6a218e1f208d1f208e1f6a21" + "8f1f208e1f208f1f6a21901f208f1f20901f6a21911f20901f20911f6a21921f20911f20921f6a21931f20921f2093" + "1f6a21941f20931f20941f6a21951f20941f20951f6a21961f20951f20961f6a21971f20961f20971f6a21981f2097" + "1f20981f6a21991f20981f20991f6a219a1f20991f209a1f6a219b1f209a1f209b1f6a219c1f209b1f209c1f6a219d" + "1f209c1f209d1f6a219e1f209d1f209e1f6a219f1f209e1f209f1f6a21a01f209f1f20a01f6a21a11f20a01f20a11f" + "6a21a21f20a11f20a21f6a21a31f20a21f20a31f6a21a41f20a31f20a41f6a21a51f20a41f20a51f6a21a61f20a51f" + "20a61f6a21a71f20a61f20a71f6a21a81f20a71f20a81f6a21a91f20a81f20a91f6a21aa1f20a91f20aa1f6a21ab1f" + "20aa1f20ab1f6a21ac1f20ab1f20ac1f6a21ad1f20ac1f20ad1f6a21ae1f20ad1f20ae1f6a21af1f20ae1f20af1f6a" + "21b01f20af1f20b01f6a21b11f20b01f20b11f6a21b21f20b11f20b21f6a21b31f20b21f20b31f6a21b41f20b31f20" + "b41f6a21b51f20b41f20b51f6a21b61f20b51f20b61f6a21b71f20b61f20b71f6a21b81f20b71f20b81f6a21b91f20" + "b81f20b91f6a21ba1f20b91f20ba1f6a21bb1f20ba1f20bb1f6a21bc1f20bb1f20bc1f6a21bd1f20bc1f20bd1f6a21" + "be1f20bd1f20be1f6a21bf1f20be1f20bf1f6a21c01f20bf1f20c01f6a21c11f20c01f20c11f6a21c21f20c11f20c2" + "1f6a21c31f20c21f20c31f6a21c41f20c31f20c41f6a21c51f20c41f20c51f6a21c61f20c51f20c61f6a21c71f20c6" + "1f20c71f6a21c81f20c71f20c81f6a21c91f20c81f20c91f6a21ca1f20c91f20ca1f6a21cb1f20ca1f20cb1f6a21cc" + "1f20cb1f20cc1f6a21cd1f20cc1f20cd1f6a21ce1f20cd1f20ce1f6a21cf1f20ce1f20cf1f6a21d01f20cf1f20d01f" + "6a21d11f20d01f20d11f6a21d21f20d11f20d21f6a21d31f20d21f20d31f6a21d41f20d31f20d41f6a21d51f20d41f" + "20d51f6a21d61f20d51f20d61f6a21d71f20d61f20d71f6a21d81f20d71f20d81f6a21d91f20d81f20d91f6a21da1f" + "20d91f20da1f6a21db1f20da1f20db1f6a21dc1f20db1f20dc1f6a21dd1f20dc1f20dd1f6a21de1f20dd1f20de1f6a" + "21df1f20de1f20df1f6a21e01f20df1f20e01f6a21e11f20e01f20e11f6a21e21f20e11f20e21f6a21e31f20e21f20" + "e31f6a21e41f20e31f20e41f6a21e51f20e41f20e51f6a21e61f20e51f20e61f6a21e71f20e61f20e71f6a21e81f20" + "e71f20e81f6a21e91f20e81f20e91f6a21ea1f20e91f20ea1f6a21eb1f20ea1f20eb1f6a21ec1f20eb1f20ec1f6a21" + "ed1f20ec1f20ed1f6a21ee1f20ed1f20ee1f6a21ef1f20ee1f20ef1f6a21f01f20ef1f20f01f6a21f11f20f01f20f1" + "1f6a21f21f20f11f20f21f6a21f31f20f21f20f31f6a21f41f20f31f20f41f6a21f51f20f41f20f51f6a21f61f20f5" + "1f20f61f6a21f71f20f61f20f71f6a21f81f20f71f20f81f6a21f91f20f81f20f91f6a21fa1f20f91f20fa1f6a21fb" + "1f20fa1f20fb1f6a21fc1f20fb1f20fc1f6a21fd1f20fc1f20fd1f6a21fe1f20fd1f20fe1f6a21ff1f20fe1f20ff1f" + "6a21802020ff1f2080206a2181202080202081206a2182202081202082206a2183202082202083206a218420208320" + "2084206a2185202084202085206a2186202085202086206a2187202086202087206a2188202087202088206a218920" + "2088202089206a218a20208920208a206a218b20208a20208b206a218c20208b20208c206a218d20208c20208d206a" + "218e20208d20208e206a218f20208e20208f206a219020208f202090206a2191202090202091206a21922020912020" + "92206a2193202092202093206a2194202093202094206a2195202094202095206a2196202095202096206a21972020" + "96202097206a2198202097202098206a2199202098202099206a219a20209920209a206a219b20209a20209b206a21" + "9c20209b20209c206a219d20209c20209d206a219e20209d20209e206a219f20209e20209f206a21a020209f2020a0" + "206a21a12020a02020a1206a21a22020a12020a2206a21a32020a22020a3206a21a42020a32020a4206a21a52020a4" + "2020a5206a21a62020a52020a6206a21a72020a62020a7206a21a82020a72020a8206a21a92020a82020a9206a21aa" + "2020a92020aa206a21ab2020aa2020ab206a21ac2020ab2020ac206a21ad2020ac2020ad206a21ae2020ad2020ae20" + "6a21af2020ae2020af206a21b02020af2020b0206a21b12020b02020b1206a21b22020b12020b2206a21b32020b220" + "20b3206a21b42020b32020b4206a21b52020b42020b5206a21b62020b52020b6206a21b72020b62020b7206a21b820" + "20b72020b8206a21b92020b82020b9206a21ba2020b92020ba206a21bb2020ba2020bb206a21bc2020bb2020bc206a" + "21bd2020bc2020bd206a21be2020bd2020be206a21bf2020be2020bf206a21c02020bf2020c0206a21c12020c02020" + "c1206a21c22020c12020c2206a21c32020c22020c3206a21c42020c32020c4206a21c52020c42020c5206a21c62020" + "c52020c6206a21c72020c62020c7206a21c82020c72020c8206a21c92020c82020c9206a21ca2020c92020ca206a21" + "cb2020ca2020cb206a21cc2020cb2020cc206a21cd2020cc2020cd206a21ce2020cd2020ce206a21cf2020ce2020cf" + "206a21d02020cf2020d0206a21d12020d02020d1206a21d22020d12020d2206a21d32020d22020d3206a21d42020d3" + "2020d4206a21d52020d42020d5206a21d62020d52020d6206a21d72020d62020d7206a21d82020d72020d8206a21d9" + "2020d82020d9206a21da2020d92020da206a21db2020da2020db206a21dc2020db2020dc206a21dd2020dc2020dd20" + "6a21de2020dd2020de206a21df2020de2020df206a21e02020df2020e0206a21e12020e02020e1206a21e22020e120" + "20e2206a21e32020e22020e3206a21e42020e32020e4206a21e52020e42020e5206a21e62020e52020e6206a21e720" + "20e62020e7206a21e82020e72020e8206a21e92020e82020e9206a21ea2020e92020ea206a21eb2020ea2020eb206a" + "21ec2020eb2020ec206a21ed2020ec2020ed206a21ee2020ed2020ee206a21ef2020ee2020ef206a21f02020ef2020" + "f0206a21f12020f02020f1206a21f22020f12020f2206a21f32020f22020f3206a21f42020f32020f4206a21f52020" + "f42020f5206a21f62020f52020f6206a21f72020f62020f7206a21f82020f72020f8206a21f92020f82020f9206a21" + "fa2020f92020fa206a21fb2020fa2020fb206a21fc2020fb2020fc206a21fd2020fc2020fd206a21fe2020fd2020fe" + "206a21ff2020fe2020ff206a21802120ff202080216a2181212080212081216a2182212081212082216a2183212082" + "212083216a2184212083212084216a2185212084212085216a2186212085212086216a2187212086212087216a2188" + "212087212088216a2189212088212089216a218a21208921208a216a218b21208a21208b216a218c21208b21208c21" + "6a218d21208c21208d216a218e21208d21208e216a218f21208e21208f216a219021208f212090216a219121209021" + "2091216a2192212091212092216a2193212092212093216a2194212093212094216a2195212094212095216a219621" + "2095212096216a2197212096212097216a2198212097212098216a2199212098212099216a219a21209921209a216a" + "219b21209a21209b216a219c21209b21209c216a219d21209c21209d216a219e21209d21209e216a219f21209e2120" + "9f216a21a021209f2120a0216a21a12120a02120a1216a21a22120a12120a2216a21a32120a22120a3216a21a42120" + "a32120a4216a21a52120a42120a5216a21a62120a52120a6216a21a72120a62120a7216a21a82120a72120a8216a21" + "a92120a82120a9216a21aa2120a92120aa216a21ab2120aa2120ab216a21ac2120ab2120ac216a21ad2120ac2120ad" + "216a21ae2120ad2120ae216a21af2120ae2120af216a21b02120af2120b0216a21b12120b02120b1216a21b22120b1" + "2120b2216a21b32120b22120b3216a21b42120b32120b4216a21b52120b42120b5216a21b62120b52120b6216a21b7" + "2120b62120b7216a21b82120b72120b8216a21b92120b82120b9216a21ba2120b92120ba216a21bb2120ba2120bb21" + "6a21bc2120bb2120bc216a21bd2120bc2120bd216a21be2120bd2120be216a21bf2120be2120bf216a21c02120bf21" + "20c0216a21c12120c02120c1216a21c22120c12120c2216a21c32120c22120c3216a21c42120c32120c4216a21c521" + "20c42120c5216a21c62120c52120c6216a21c72120c62120c7216a21c82120c72120c8216a21c92120c82120c9216a" + "21ca2120c92120ca216a21cb2120ca2120cb216a21cc2120cb2120cc216a21cd2120cc2120cd216a21ce2120cd2120" + "ce216a21cf2120ce2120cf216a21d02120cf2120d0216a21d12120d02120d1216a21d22120d12120d2216a21d32120" + "d22120d3216a21d42120d32120d4216a21d52120d42120d5216a21d62120d52120d6216a21d72120d62120d7216a21" + "d82120d72120d8216a21d92120d82120d9216a21da2120d92120da216a21db2120da2120db216a21dc2120db2120dc" + "216a21dd2120dc2120dd216a21de2120dd2120de216a21df2120de2120df216a21e02120df2120e0216a21e12120e0" + "2120e1216a21e22120e12120e2216a21e32120e22120e3216a21e42120e32120e4216a21e52120e42120e5216a21e6" + "2120e52120e6216a21e72120e62120e7216a21e82120e72120e8216a21e92120e82120e9216a21ea2120e92120ea21" + "6a21eb2120ea2120eb216a21ec2120eb2120ec216a21ed2120ec2120ed216a21ee2120ed2120ee216a21ef2120ee21" + "20ef216a21f02120ef2120f0216a21f12120f02120f1216a21f22120f12120f2216a21f32120f22120f3216a21f421" + "20f32120f4216a21f52120f42120f5216a21f62120f52120f6216a21f72120f62120f7216a21f82120f72120f8216a" + "21f92120f82120f9216a21fa2120f92120fa216a21fb2120fa2120fb216a21fc2120fb2120fc216a21fd2120fc2120" + "fd216a21fe2120fd2120fe216a21ff2120fe2120ff216a21802220ff212080226a2181222080222081226a21822220" + "81222082226a2183222082222083226a2184222083222084226a2185222084222085226a2186222085222086226a21" + "87222086222087226a2188222087222088226a2189222088222089226a218a22208922208a226a218b22208a22208b" + "226a218c22208b22208c226a218d22208c22208d226a218e22208d22208e226a218f22208e22208f226a219022208f" + "222090226a2191222090222091226a2192222091222092226a2193222092222093226a2194222093222094226a2195" + "222094222095226a2196222095222096226a2197222096222097226a2198222097222098226a219922209822209922" + "6a219a22209922209a226a219b22209a22209b226a219c22209b22209c226a219d22209c22209d226a219e22209d22" + "209e226a219f22209e22209f226a21a022209f2220a0226a21a12220a02220a1226a21a22220a12220a2226a21a322" + "20a22220a3226a21a42220a32220a4226a21a52220a42220a5226a21a62220a52220a6226a21a72220a62220a7226a" + "21a82220a72220a8226a21a92220a82220a9226a21aa2220a92220aa226a21ab2220aa2220ab226a21ac2220ab2220" + "ac226a21ad2220ac2220ad226a21ae2220ad2220ae226a21af2220ae2220af226a21b02220af2220b0226a21b12220" + "b02220b1226a21b22220b12220b2226a21b32220b22220b3226a21b42220b32220b4226a21b52220b42220b5226a21" + "b62220b52220b6226a21b72220b62220b7226a21b82220b72220b8226a21b92220b82220b9226a21ba2220b92220ba" + "226a21bb2220ba2220bb226a21bc2220bb2220bc226a21bd2220bc2220bd226a21be2220bd2220be226a21bf2220be" + "2220bf226a21c02220bf2220c0226a21c12220c02220c1226a21c22220c12220c2226a21c32220c22220c3226a21c4" + "2220c32220c4226a21c52220c42220c5226a21c62220c52220c6226a21c72220c62220c7226a21c82220c72220c822" + "6a21c92220c82220c9226a21ca2220c92220ca226a21cb2220ca2220cb226a21cc2220cb2220cc226a21cd2220cc22" + "20cd226a21ce2220cd2220ce226a21cf2220ce2220cf226a21d02220cf2220d0226a21d12220d02220d1226a21d222" + "20d12220d2226a21d32220d22220d3226a21d42220d32220d4226a21d52220d42220d5226a21d62220d52220d6226a" + "21d72220d62220d7226a21d82220d72220d8226a21d92220d82220d9226a21da2220d92220da226a21db2220da2220" + "db226a21dc2220db2220dc226a21dd2220dc2220dd226a21de2220dd2220de226a21df2220de2220df226a21e02220" + "df2220e0226a21e12220e02220e1226a21e22220e12220e2226a21e32220e22220e3226a21e42220e32220e4226a21" + "e52220e42220e5226a21e62220e52220e6226a21e72220e62220e7226a21e82220e72220e8226a21e92220e82220e9" + "226a21ea2220e92220ea226a21eb2220ea2220eb226a21ec2220eb2220ec226a21ed2220ec2220ed226a21ee2220ed" + "2220ee226a21ef2220ee2220ef226a21f02220ef2220f0226a21f12220f02220f1226a21f22220f12220f2226a21f3" + "2220f22220f3226a21f42220f32220f4226a21f52220f42220f5226a21f62220f52220f6226a21f72220f62220f722" + "6a21f82220f72220f8226a21f92220f82220f9226a21fa2220f92220fa226a21fb2220fa2220fb226a21fc2220fb22" + "20fc226a21fd2220fc2220fd226a21fe2220fd2220fe226a21ff2220fe2220ff226a21802320ff222080236a218123" + "2080232081236a2182232081232082236a2183232082232083236a2184232083232084236a2185232084232085236a" + "2186232085232086236a2187232086232087236a2188232087232088236a2189232088232089236a218a2320892320" + "8a236a218b23208a23208b236a218c23208b23208c236a218d23208c23208d236a218e23208d23208e236a218f2320" + "8e23208f236a219023208f232090236a2191232090232091236a2192232091232092236a2193232092232093236a21" + "94232093232094236a2195232094232095236a2196232095232096236a2197232096232097236a2198232097232098" + "236a2199232098232099236a219a23209923209a236a219b23209a23209b236a219c23209b23209c236a219d23209c" + "23209d236a219e23209d23209e236a219f23209e23209f236a21a023209f2320a0236a21a12320a02320a1236a21a2" + "2320a12320a2236a21a32320a22320a3236a21a42320a32320a4236a21a52320a42320a5236a21a62320a52320a623" + "6a21a72320a62320a7236a21a82320a72320a8236a21a92320a82320a9236a21aa2320a92320aa236a21ab2320aa23" + "20ab236a21ac2320ab2320ac236a21ad2320ac2320ad236a21ae2320ad2320ae236a21af2320ae2320af236a21b023" + "20af2320b0236a21b12320b02320b1236a21b22320b12320b2236a21b32320b22320b3236a21b42320b32320b4236a" + "21b52320b42320b5236a21b62320b52320b6236a21b72320b62320b7236a21b82320b72320b8236a21b92320b82320" + "b9236a21ba2320b92320ba236a21bb2320ba2320bb236a21bc2320bb2320bc236a21bd2320bc2320bd236a21be2320" + "bd2320be236a21bf2320be2320bf236a21c02320bf2320c0236a21c12320c02320c1236a21c22320c12320c2236a21" + "c32320c22320c3236a21c42320c32320c4236a21c52320c42320c5236a21c62320c52320c6236a21c72320c62320c7" + "236a21c82320c72320c8236a21c92320c82320c9236a21ca2320c92320ca236a21cb2320ca2320cb236a21cc2320cb" + "2320cc236a21cd2320cc2320cd236a21ce2320cd2320ce236a21cf2320ce2320cf236a21d02320cf2320d0236a21d1" + "2320d02320d1236a21d22320d12320d2236a21d32320d22320d3236a21d42320d32320d4236a21d52320d42320d523" + "6a21d62320d52320d6236a21d72320d62320d7236a21d82320d72320d8236a21d92320d82320d9236a21da2320d923" + "20da236a21db2320da2320db236a21dc2320db2320dc236a21dd2320dc2320dd236a21de2320dd2320de236a21df23" + "20de2320df236a21e02320df2320e0236a21e12320e02320e1236a21e22320e12320e2236a21e32320e22320e3236a" + "21e42320e32320e4236a21e52320e42320e5236a21e62320e52320e6236a21e72320e62320e7236a21e82320e72320" + "e8236a21e92320e82320e9236a21ea2320e92320ea236a21eb2320ea2320eb236a21ec2320eb2320ec236a21ed2320" + "ec2320ed236a21ee2320ed2320ee236a21ef2320ee2320ef236a21f02320ef2320f0236a21f12320f02320f1236a21" + "f22320f12320f2236a21f32320f22320f3236a21f42320f32320f4236a21f52320f42320f5236a21f62320f52320f6" + "236a21f72320f62320f7236a21f82320f72320f8236a21f92320f82320f9236a21fa2320f92320fa236a21fb2320fa" + "2320fb236a21fc2320fb2320fc236a21fd2320fc2320fd236a21fe2320fd2320fe236a21ff2320fe2320ff236a2180" + "2420ff232080246a2181242080242081246a2182242081242082246a2183242082242083246a218424208324208424" + "6a2185242084242085246a2186242085242086246a2187242086242087246a2188242087242088246a218924208824" + "2089246a218a24208924208a246a218b24208a24208b246a218c24208b24208c246a218d24208c24208d246a218e24" + "208d24208e246a218f24208e24208f246a219024208f242090246a2191242090242091246a2192242091242092246a" + "2193242092242093246a2194242093242094246a2195242094242095246a2196242095242096246a21972420962420" + "97246a2198242097242098246a2199242098242099246a219a24209924209a246a219b24209a24209b246a219c2420" + "9b24209c246a219d24209c24209d246a219e24209d24209e246a219f24209e24209f246a21a024209f2420a0246a21" + "a12420a02420a1246a21a22420a12420a2246a21a32420a22420a3246a21a42420a32420a4246a21a52420a42420a5" + "246a21a62420a52420a6246a21a72420a62420a7246a21a82420a72420a8246a21a92420a82420a9246a21aa2420a9" + "2420aa246a21ab2420aa2420ab246a21ac2420ab2420ac246a21ad2420ac2420ad246a21ae2420ad2420ae246a21af" + "2420ae2420af246a21b02420af2420b0246a21b12420b02420b1246a21b22420b12420b2246a21b32420b22420b324" + "6a21b42420b32420b4246a21b52420b42420b5246a21b62420b52420b6246a21b72420b62420b7246a21b82420b724" + "20b8246a21b92420b82420b9246a21ba2420b92420ba246a21bb2420ba2420bb246a21bc2420bb2420bc246a21bd24" + "20bc2420bd246a21be2420bd2420be246a21bf2420be2420bf246a21c02420bf2420c0246a21c12420c02420c1246a" + "21c22420c12420c2246a21c32420c22420c3246a21c42420c32420c4246a21c52420c42420c5246a21c62420c52420" + "c6246a21c72420c62420c7246a21c82420c72420c8246a21c92420c82420c9246a21ca2420c92420ca246a21cb2420" + "ca2420cb246a21cc2420cb2420cc246a21cd2420cc2420cd246a21ce2420cd2420ce246a21cf2420ce2420cf246a21" + "d02420cf2420d0246a21d12420d02420d1246a21d22420d12420d2246a21d32420d22420d3246a21d42420d32420d4" + "246a21d52420d42420d5246a21d62420d52420d6246a21d72420d62420d7246a21d82420d72420d8246a21d92420d8" + "2420d9246a21da2420d92420da246a21db2420da2420db246a21dc2420db2420dc246a21dd2420dc2420dd246a21de" + "2420dd2420de246a21df2420de2420df246a21e02420df2420e0246a21e12420e02420e1246a21e22420e12420e224" + "6a21e32420e22420e3246a21e42420e32420e4246a21e52420e42420e5246a21e62420e52420e6246a21e72420e624" + "20e7246a21e82420e72420e8246a21e92420e82420e9246a21ea2420e92420ea246a21eb2420ea2420eb246a21ec24" + "20eb2420ec246a21ed2420ec2420ed246a21ee2420ed2420ee246a21ef2420ee2420ef246a21f02420ef2420f0246a" + "21f12420f02420f1246a21f22420f12420f2246a21f32420f22420f3246a21f42420f32420f4246a21f52420f42420" + "f5246a21f62420f52420f6246a21f72420f62420f7246a21f82420f72420f8246a21f92420f82420f9246a21fa2420" + "f92420fa246a21fb2420fa2420fb246a21fc2420fb2420fc246a21fd2420fc2420fd246a21fe2420fd2420fe246a21" + "ff2420fe2420ff246a21802520ff242080256a2181252080252081256a2182252081252082256a2183252082252083" + "256a2184252083252084256a2185252084252085256a2186252085252086256a2187252086252087256a2188252087" + "252088256a2189252088252089256a218a25208925208a256a218b25208a25208b256a218c25208b25208c256a218d" + "25208c25208d256a218e25208d25208e256a218f25208e25208f256a219025208f252090256a219125209025209125" + "6a2192252091252092256a2193252092252093256a2194252093252094256a2195252094252095256a219625209525" + "2096256a2197252096252097256a2198252097252098256a2199252098252099256a219a25209925209a256a219b25" + "209a25209b256a219c25209b25209c256a219d25209c25209d256a219e25209d25209e256a219f25209e25209f256a" + "21a025209f2520a0256a21a12520a02520a1256a21a22520a12520a2256a21a32520a22520a3256a21a42520a32520" + "a4256a21a52520a42520a5256a21a62520a52520a6256a21a72520a62520a7256a21a82520a72520a8256a21a92520" + "a82520a9256a21aa2520a92520aa256a21ab2520aa2520ab256a21ac2520ab2520ac256a21ad2520ac2520ad256a21" + "ae2520ad2520ae256a21af2520ae2520af256a21b02520af2520b0256a21b12520b02520b1256a21b22520b12520b2" + "256a21b32520b22520b3256a21b42520b32520b4256a21b52520b42520b5256a21b62520b52520b6256a21b72520b6" + "2520b7256a21b82520b72520b8256a21b92520b82520b9256a21ba2520b92520ba256a21bb2520ba2520bb256a21bc" + "2520bb2520bc256a21bd2520bc2520bd256a21be2520bd2520be256a21bf2520be2520bf256a21c02520bf2520c025" + "6a21c12520c02520c1256a21c22520c12520c2256a21c32520c22520c3256a21c42520c32520c4256a21c52520c425" + "20c5256a21c62520c52520c6256a21c72520c62520c7256a21c82520c72520c8256a21c92520c82520c9256a21ca25" + "20c92520ca256a21cb2520ca2520cb256a21cc2520cb2520cc256a21cd2520cc2520cd256a21ce2520cd2520ce256a" + "21cf2520ce2520cf256a21d02520cf2520d0256a21d12520d02520d1256a21d22520d12520d2256a21d32520d22520" + "d3256a21d42520d32520d4256a21d52520d42520d5256a21d62520d52520d6256a21d72520d62520d7256a21d82520" + "d72520d8256a21d92520d82520d9256a21da2520d92520da256a21db2520da2520db256a21dc2520db2520dc256a21" + "dd2520dc2520dd256a21de2520dd2520de256a21df2520de2520df256a21e02520df2520e0256a21e12520e02520e1" + "256a21e22520e12520e2256a21e32520e22520e3256a21e42520e32520e4256a21e52520e42520e5256a21e62520e5" + "2520e6256a21e72520e62520e7256a21e82520e72520e8256a21e92520e82520e9256a21ea2520e92520ea256a21eb" + "2520ea2520eb256a21ec2520eb2520ec256a21ed2520ec2520ed256a21ee2520ed2520ee256a21ef2520ee2520ef25" + "6a21f02520ef2520f0256a21f12520f02520f1256a21f22520f12520f2256a21f32520f22520f3256a21f42520f325" + "20f4256a21f52520f42520f5256a21f62520f52520f6256a21f72520f62520f7256a21f82520f72520f8256a21f925" + "20f82520f9256a21fa2520f92520fa256a21fb2520fa2520fb256a21fc2520fb2520fc256a21fd2520fc2520fd256a" + "21fe2520fd2520fe256a21ff2520fe2520ff256a21802620ff252080266a2181262080262081266a21822620812620" + "82266a2183262082262083266a2184262083262084266a2185262084262085266a2186262085262086266a21872620" + "86262087266a2188262087262088266a2189262088262089266a218a26208926208a266a218b26208a26208b266a21" + "8c26208b26208c266a218d26208c26208d266a218e26208d26208e266a218f26208e26208f266a219026208f262090" + "266a2191262090262091266a2192262091262092266a2193262092262093266a2194262093262094266a2195262094" + "262095266a2196262095262096266a2197262096262097266a2198262097262098266a2199262098262099266a219a" + "26209926209a266a219b26209a26209b266a219c26209b26209c266a219d26209c26209d266a219e26209d26209e26" + "6a219f26209e26209f266a21a026209f2620a0266a21a12620a02620a1266a21a22620a12620a2266a21a32620a226" + "20a3266a21a42620a32620a4266a21a52620a42620a5266a21a62620a52620a6266a21a72620a62620a7266a21a826" + "20a72620a8266a21a92620a82620a9266a21aa2620a92620aa266a21ab2620aa2620ab266a21ac2620ab2620ac266a" + "21ad2620ac2620ad266a21ae2620ad2620ae266a21af2620ae2620af266a21b02620af2620b0266a21b12620b02620" + "b1266a21b22620b12620b2266a21b32620b22620b3266a21b42620b32620b4266a21b52620b42620b5266a21b62620" + "b52620b6266a21b72620b62620b7266a21b82620b72620b8266a21b92620b82620b9266a21ba2620b92620ba266a21" + "bb2620ba2620bb266a21bc2620bb2620bc266a21bd2620bc2620bd266a21be2620bd2620be266a21bf2620be2620bf" + "266a21c02620bf2620c0266a21c12620c02620c1266a21c22620c12620c2266a21c32620c22620c3266a21c42620c3" + "2620c4266a21c52620c42620c5266a21c62620c52620c6266a21c72620c62620c7266a21c82620c72620c8266a21c9" + "2620c82620c9266a21ca2620c92620ca266a21cb2620ca2620cb266a21cc2620cb2620cc266a21cd2620cc2620cd26" + "6a21ce2620cd2620ce266a21cf2620ce2620cf266a21d02620cf2620d0266a21d12620d02620d1266a21d22620d126" + "20d2266a21d32620d22620d3266a21d42620d32620d4266a21d52620d42620d5266a21d62620d52620d6266a21d726" + "20d62620d7266a21d82620d72620d8266a21d92620d82620d9266a21da2620d92620da266a21db2620da2620db266a" + "21dc2620db2620dc266a21dd2620dc2620dd266a21de2620dd2620de266a21df2620de2620df266a21e02620df2620" + "e0266a21e12620e02620e1266a21e22620e12620e2266a21e32620e22620e3266a21e42620e32620e4266a21e52620" + "e42620e5266a21e62620e52620e6266a21e72620e62620e7266a21e82620e72620e8266a21e92620e82620e9266a21" + "ea2620e92620ea266a21eb2620ea2620eb266a21ec2620eb2620ec266a21ed2620ec2620ed266a21ee2620ed2620ee" + "266a21ef2620ee2620ef266a21f02620ef2620f0266a21f12620f02620f1266a21f22620f12620f2266a21f32620f2" + "2620f3266a21f42620f32620f4266a21f52620f42620f5266a21f62620f52620f6266a21f72620f62620f7266a21f8" + "2620f72620f8266a21f92620f82620f9266a21fa2620f92620fa266a21fb2620fa2620fb266a21fc2620fb2620fc26" + "6a21fd2620fc2620fd266a21fe2620fd2620fe266a21ff2620fe2620ff266a21802720ff262080276a218127208027" + "2081276a2182272081272082276a2183272082272083276a2184272083272084276a2185272084272085276a218627" + "2085272086276a2187272086272087276a2188272087272088276a2189272088272089276a218a27208927208a276a" + "218b27208a27208b276a218c27208b27208c276a218d27208c27208d276a218e27208d27208e276a218f27208e2720" + "8f276a219027208f272090276a2191272090272091276a2192272091272092276a2193272092272093276a21942720" + "93272094276a2195272094272095276a2196272095272096276a2197272096272097276a2198272097272098276a21" + "99272098272099276a219a27209927209a276a219b27209a27209b276a219c27209b27209c276a219d27209c27209d" + "276a219e27209d27209e276a219f27209e27209f276a21a027209f2720a0276a21a12720a02720a1276a21a22720a1" + "2720a2276a21a32720a22720a3276a21a42720a32720a4276a21a52720a42720a5276a21a62720a52720a6276a21a7" + "2720a62720a7276a21a82720a72720a8276a21a92720a82720a9276a21aa2720a92720aa276a21ab2720aa2720ab27" + "6a21ac2720ab2720ac276a21ad2720ac2720ad276a21ae2720ad2720ae276a21af2720ae2720af276a21b02720af27" + "20b0276a21b12720b02720b1276a21b22720b12720b2276a21b32720b22720b3276a21b42720b32720b4276a21b527" + "20b42720b5276a21b62720b52720b6276a21b72720b62720b7276a21b82720b72720b8276a21b92720b82720b9276a" + "21ba2720b92720ba276a21bb2720ba2720bb276a21bc2720bb2720bc276a21bd2720bc2720bd276a21be2720bd2720" + "be276a21bf2720be2720bf276a21c02720bf2720c0276a21c12720c02720c1276a21c22720c12720c2276a21c32720" + "c22720c3276a21c42720c32720c4276a21c52720c42720c5276a21c62720c52720c6276a21c72720c62720c7276a21" + "c82720c72720c8276a21c92720c82720c9276a21ca2720c92720ca276a21cb2720ca2720cb276a21cc2720cb2720cc" + "276a21cd2720cc2720cd276a21ce2720cd2720ce276a21cf2720ce2720cf276a21d02720cf2720d0276a21d12720d0" + "2720d1276a21d22720d12720d2276a21d32720d22720d3276a21d42720d32720d4276a21d52720d42720d5276a21d6" + "2720d52720d6276a21d72720d62720d7276a21d82720d72720d8276a21d92720d82720d9276a21da2720d92720da27" + "6a21db2720da2720db276a21dc2720db2720dc276a21dd2720dc2720dd276a21de2720dd2720de276a21df2720de27" + "20df276a21e02720df2720e0276a21e12720e02720e1276a21e22720e12720e2276a21e32720e22720e3276a21e427" + "20e32720e4276a21e52720e42720e5276a21e62720e52720e6276a21e72720e62720e7276a21e82720e72720e8276a" + "21e92720e82720e9276a21ea2720e92720ea276a21eb2720ea2720eb276a21ec2720eb2720ec276a21ed2720ec2720" + "ed276a21ee2720ed2720ee276a21ef2720ee2720ef276a21f02720ef2720f0276a21f12720f02720f1276a21f22720" + "f12720f2276a21f32720f22720f3276a21f42720f32720f4276a21f52720f42720f5276a21f62720f52720f6276a21" + "f72720f62720f7276a21f82720f72720f8276a21f92720f82720f9276a21fa2720f92720fa276a21fb2720fa2720fb" + "276a21fc2720fb2720fc276a21fd2720fc2720fd276a21fe2720fd2720fe276a21ff2720fe2720ff276a21802820ff" + "272080286a2181282080282081286a2182282081282082286a2183282082282083286a2184282083282084286a2185" + "282084282085286a2186282085282086286a2187282086282087286a2188282087282088286a218928208828208928" + "6a218a28208928208a286a218b28208a28208b286a218c28208b28208c286a218d28208c28208d286a218e28208d28" + "208e286a218f28208e28208f286a219028208f282090286a2191282090282091286a2192282091282092286a219328" + "2092282093286a2194282093282094286a2195282094282095286a2196282095282096286a2197282096282097286a" + "2198282097282098286a2199282098282099286a219a28209928209a286a219b28209a28209b286a219c28209b2820" + "9c286a219d28209c28209d286a219e28209d28209e286a219f28209e28209f286a21a028209f2820a0286a21a12820" + "a02820a1286a21a22820a12820a2286a21a32820a22820a3286a21a42820a32820a4286a21a52820a42820a5286a21" + "a62820a52820a6286a21a72820a62820a7286a21a82820a72820a8286a21a92820a82820a9286a21aa2820a92820aa" + "286a21ab2820aa2820ab286a21ac2820ab2820ac286a21ad2820ac2820ad286a21ae2820ad2820ae286a21af2820ae" + "2820af286a21b02820af2820b0286a21b12820b02820b1286a21b22820b12820b2286a21b32820b22820b3286a21b4" + "2820b32820b4286a21b52820b42820b5286a21b62820b52820b6286a21b72820b62820b7286a21b82820b72820b828" + "6a21b92820b82820b9286a21ba2820b92820ba286a21bb2820ba2820bb286a21bc2820bb2820bc286a21bd2820bc28" + "20bd286a21be2820bd2820be286a21bf2820be2820bf286a21c02820bf2820c0286a21c12820c02820c1286a21c228" + "20c12820c2286a21c32820c22820c3286a21c42820c32820c4286a21c52820c42820c5286a21c62820c52820c6286a" + "21c72820c62820c7286a21c82820c72820c8286a21c92820c82820c9286a21ca2820c92820ca286a21cb2820ca2820" + "cb286a21cc2820cb2820cc286a21cd2820cc2820cd286a21ce2820cd2820ce286a21cf2820ce2820cf286a21d02820" + "cf2820d0286a21d12820d02820d1286a21d22820d12820d2286a21d32820d22820d3286a21d42820d32820d4286a21" + "d52820d42820d5286a21d62820d52820d6286a21d72820d62820d7286a21d82820d72820d8286a21d92820d82820d9" + "286a21da2820d92820da286a21db2820da2820db286a21dc2820db2820dc286a21dd2820dc2820dd286a21de2820dd" + "2820de286a21df2820de2820df286a21e02820df2820e0286a21e12820e02820e1286a21e22820e12820e2286a21e3" + "2820e22820e3286a21e42820e32820e4286a21e52820e42820e5286a21e62820e52820e6286a21e72820e62820e728" + "6a21e82820e72820e8286a21e92820e82820e9286a21ea2820e92820ea286a21eb2820ea2820eb286a21ec2820eb28" + "20ec286a21ed2820ec2820ed286a21ee2820ed2820ee286a21ef2820ee2820ef286a21f02820ef2820f0286a21f128" + "20f02820f1286a21f22820f12820f2286a21f32820f22820f3286a21f42820f32820f4286a21f52820f42820f5286a" + "21f62820f52820f6286a21f72820f62820f7286a21f82820f72820f8286a21f92820f82820f9286a21fa2820f92820" + "fa286a21fb2820fa2820fb286a21fc2820fb2820fc286a21fd2820fc2820fd286a21fe2820fd2820fe286a21ff2820" + "fe2820ff286a21802920ff282080296a2181292080292081296a2182292081292082296a2183292082292083296a21" + "84292083292084296a2185292084292085296a2186292085292086296a2187292086292087296a2188292087292088" + "296a2189292088292089296a218a29208929208a296a218b29208a29208b296a218c29208b29208c296a218d29208c" + "29208d296a218e29208d29208e296a218f29208e29208f296a219029208f292090296a2191292090292091296a2192" + "292091292092296a2193292092292093296a2194292093292094296a2195292094292095296a219629209529209629" + "6a2197292096292097296a2198292097292098296a2199292098292099296a219a29209929209a296a219b29209a29" + "209b296a219c29209b29209c296a219d29209c29209d296a219e29209d29209e296a219f29209e29209f296a21a029" + "209f2920a0296a21a12920a02920a1296a21a22920a12920a2296a21a32920a22920a3296a21a42920a32920a4296a" + "21a52920a42920a5296a21a62920a52920a6296a21a72920a62920a7296a21a82920a72920a8296a21a92920a82920" + "a9296a21aa2920a92920aa296a21ab2920aa2920ab296a21ac2920ab2920ac296a21ad2920ac2920ad296a21ae2920" + "ad2920ae296a21af2920ae2920af296a21b02920af2920b0296a21b12920b02920b1296a21b22920b12920b2296a21" + "b32920b22920b3296a21b42920b32920b4296a21b52920b42920b5296a21b62920b52920b6296a21b72920b62920b7" + "296a21b82920b72920b8296a21b92920b82920b9296a21ba2920b92920ba296a21bb2920ba2920bb296a21bc2920bb" + "2920bc296a21bd2920bc2920bd296a21be2920bd2920be296a21bf2920be2920bf296a21c02920bf2920c0296a21c1" + "2920c02920c1296a21c22920c12920c2296a21c32920c22920c3296a21c42920c32920c4296a21c52920c42920c529" + "6a21c62920c52920c6296a21c72920c62920c7296a21c82920c72920c8296a21c92920c82920c9296a21ca2920c929" + "20ca296a21cb2920ca2920cb296a21cc2920cb2920cc296a21cd2920cc2920cd296a21ce2920cd2920ce296a21cf29" + "20ce2920cf296a21d02920cf2920d0296a21d12920d02920d1296a21d22920d12920d2296a21d32920d22920d3296a" + "21d42920d32920d4296a21d52920d42920d5296a21d62920d52920d6296a21d72920d62920d7296a21d82920d72920" + "d8296a21d92920d82920d9296a21da2920d92920da296a21db2920da2920db296a21dc2920db2920dc296a21dd2920" + "dc2920dd296a21de2920dd2920de296a21df2920de2920df296a21e02920df2920e0296a21e12920e02920e1296a21" + "e22920e12920e2296a21e32920e22920e3296a21e42920e32920e4296a21e52920e42920e5296a21e62920e52920e6" + "296a21e72920e62920e7296a21e82920e72920e8296a21e92920e82920e9296a21ea2920e92920ea296a21eb2920ea" + "2920eb296a21ec2920eb2920ec296a21ed2920ec2920ed296a21ee2920ed2920ee296a21ef2920ee2920ef296a21f0" + "2920ef2920f0296a21f12920f02920f1296a21f22920f12920f2296a21f32920f22920f3296a21f42920f32920f429" + "6a21f52920f42920f5296a21f62920f52920f6296a21f72920f62920f7296a21f82920f72920f8296a21f92920f829" + "20f9296a21fa2920f92920fa296a21fb2920fa2920fb296a21fc2920fb2920fc296a21fd2920fc2920fd296a21fe29" + "20fd2920fe296a21ff2920fe2920ff296a21802a20ff2920802a6a21812a20802a20812a6a21822a20812a20822a6a" + "21832a20822a20832a6a21842a20832a20842a6a21852a20842a20852a6a21862a20852a20862a6a21872a20862a20" + "872a6a21882a20872a20882a6a21892a20882a20892a6a218a2a20892a208a2a6a218b2a208a2a208b2a6a218c2a20" + "8b2a208c2a6a218d2a208c2a208d2a6a218e2a208d2a208e2a6a218f2a208e2a208f2a6a21902a208f2a20902a6a21" + "912a20902a20912a6a21922a20912a20922a6a21932a20922a20932a6a21942a20932a20942a6a21952a20942a2095" + "2a6a21962a20952a20962a6a21972a20962a20972a6a21982a20972a20982a6a21992a20982a20992a6a219a2a2099" + "2a209a2a6a219b2a209a2a209b2a6a219c2a209b2a209c2a6a219d2a209c2a209d2a6a219e2a209d2a209e2a6a219f" + "2a209e2a209f2a6a21a02a209f2a20a02a6a21a12a20a02a20a12a6a21a22a20a12a20a22a6a21a32a20a22a20a32a" + "6a21a42a20a32a20a42a6a21a52a20a42a20a52a6a21a62a20a52a20a62a6a21a72a20a62a20a72a6a21a82a20a72a" + "20a82a6a21a92a20a82a20a92a6a21aa2a20a92a20aa2a6a21ab2a20aa2a20ab2a6a21ac2a20ab2a20ac2a6a21ad2a" + "20ac2a20ad2a6a21ae2a20ad2a20ae2a6a21af2a20ae2a20af2a6a21b02a20af2a20b02a6a21b12a20b02a20b12a6a" + "21b22a20b12a20b22a6a21b32a20b22a20b32a6a21b42a20b32a20b42a6a21b52a20b42a20b52a6a21b62a20b52a20" + "b62a6a21b72a20b62a20b72a6a21b82a20b72a20b82a6a21b92a20b82a20b92a6a21ba2a20b92a20ba2a6a21bb2a20" + "ba2a20bb2a6a21bc2a20bb2a20bc2a6a21bd2a20bc2a20bd2a6a21be2a20bd2a20be2a6a21bf2a20be2a20bf2a6a21" + "c02a20bf2a20c02a6a21c12a20c02a20c12a6a21c22a20c12a20c22a6a21c32a20c22a20c32a6a21c42a20c32a20c4" + "2a6a21c52a20c42a20c52a6a21c62a20c52a20c62a6a21c72a20c62a20c72a6a21c82a20c72a20c82a6a21c92a20c8" + "2a20c92a6a21ca2a20c92a20ca2a6a21cb2a20ca2a20cb2a6a21cc2a20cb2a20cc2a6a21cd2a20cc2a20cd2a6a21ce" + "2a20cd2a20ce2a6a21cf2a20ce2a20cf2a6a21d02a20cf2a20d02a6a21d12a20d02a20d12a6a21d22a20d12a20d22a" + "6a21d32a20d22a20d32a6a21d42a20d32a20d42a6a21d52a20d42a20d52a6a21d62a20d52a20d62a6a21d72a20d62a" + "20d72a6a21d82a20d72a20d82a6a21d92a20d82a20d92a6a21da2a20d92a20da2a6a21db2a20da2a20db2a6a21dc2a" + "20db2a20dc2a6a21dd2a20dc2a20dd2a6a21de2a20dd2a20de2a6a21df2a20de2a20df2a6a21e02a20df2a20e02a6a" + "21e12a20e02a20e12a6a21e22a20e12a20e22a6a21e32a20e22a20e32a6a21e42a20e32a20e42a6a21e52a20e42a20" + "e52a6a21e62a20e52a20e62a6a21e72a20e62a20e72a6a21e82a20e72a20e82a6a21e92a20e82a20e92a6a21ea2a20" + "e92a20ea2a6a21eb2a20ea2a20eb2a6a21ec2a20eb2a20ec2a6a21ed2a20ec2a20ed2a6a21ee2a20ed2a20ee2a6a21" + "ef2a20ee2a20ef2a6a21f02a20ef2a20f02a6a21f12a20f02a20f12a6a21f22a20f12a20f22a6a21f32a20f22a20f3" + "2a6a21f42a20f32a20f42a6a21f52a20f42a20f52a6a21f62a20f52a20f62a6a21f72a20f62a20f72a6a21f82a20f7" + "2a20f82a6a21f92a20f82a20f92a6a21fa2a20f92a20fa2a6a21fb2a20fa2a20fb2a6a21fc2a20fb2a20fc2a6a21fd" + "2a20fc2a20fd2a6a21fe2a20fd2a20fe2a6a21ff2a20fe2a20ff2a6a21802b20ff2a20802b6a21812b20802b20812b" + "6a21822b20812b20822b6a21832b20822b20832b6a21842b20832b20842b6a21852b20842b20852b6a21862b20852b" + "20862b6a21872b20862b20872b6a21882b20872b20882b6a21892b20882b20892b6a218a2b20892b208a2b6a218b2b" + "208a2b208b2b6a218c2b208b2b208c2b6a218d2b208c2b208d2b6a218e2b208d2b208e2b6a218f2b208e2b208f2b6a" + "21902b208f2b20902b6a21912b20902b20912b6a21922b20912b20922b6a21932b20922b20932b6a21942b20932b20" + "942b6a21952b20942b20952b6a21962b20952b20962b6a21972b20962b20972b6a21982b20972b20982b6a21992b20" + "982b20992b6a219a2b20992b209a2b6a219b2b209a2b209b2b6a219c2b209b2b209c2b6a219d2b209c2b209d2b6a21" + "9e2b209d2b209e2b6a219f2b209e2b209f2b6a21a02b209f2b20a02b6a21a12b20a02b20a12b6a21a22b20a12b20a2" + "2b6a21a32b20a22b20a32b6a21a42b20a32b20a42b6a21a52b20a42b20a52b6a21a62b20a52b20a62b6a21a72b20a6" + "2b20a72b6a21a82b20a72b20a82b6a21a92b20a82b20a92b6a21aa2b20a92b20aa2b6a21ab2b20aa2b20ab2b6a21ac" + "2b20ab2b20ac2b6a21ad2b20ac2b20ad2b6a21ae2b20ad2b20ae2b6a21af2b20ae2b20af2b6a21b02b20af2b20b02b" + "6a21b12b20b02b20b12b6a21b22b20b12b20b22b6a21b32b20b22b20b32b6a21b42b20b32b20b42b6a21b52b20b42b" + "20b52b6a21b62b20b52b20b62b6a21b72b20b62b20b72b6a21b82b20b72b20b82b6a21b92b20b82b20b92b6a21ba2b" + "20b92b20ba2b6a21bb2b20ba2b20bb2b6a21bc2b20bb2b20bc2b6a21bd2b20bc2b20bd2b6a21be2b20bd2b20be2b6a" + "21bf2b20be2b20bf2b6a21c02b20bf2b20c02b6a21c12b20c02b20c12b6a21c22b20c12b20c22b6a21c32b20c22b20" + "c32b6a21c42b20c32b20c42b6a21c52b20c42b20c52b6a21c62b20c52b20c62b6a21c72b20c62b20c72b6a21c82b20" + "c72b20c82b6a21c92b20c82b20c92b6a21ca2b20c92b20ca2b6a21cb2b20ca2b20cb2b6a21cc2b20cb2b20cc2b6a21" + "cd2b20cc2b20cd2b6a21ce2b20cd2b20ce2b6a21cf2b20ce2b20cf2b6a21d02b20cf2b20d02b6a21d12b20d02b20d1" + "2b6a21d22b20d12b20d22b6a21d32b20d22b20d32b6a21d42b20d32b20d42b6a21d52b20d42b20d52b6a21d62b20d5" + "2b20d62b6a21d72b20d62b20d72b6a21d82b20d72b20d82b6a21d92b20d82b20d92b6a21da2b20d92b20da2b6a21db" + "2b20da2b20db2b6a21dc2b20db2b20dc2b6a21dd2b20dc2b20dd2b6a21de2b20dd2b20de2b6a21df2b20de2b20df2b" + "6a21e02b20df2b20e02b6a21e12b20e02b20e12b6a21e22b20e12b20e22b6a21e32b20e22b20e32b6a21e42b20e32b" + "20e42b6a21e52b20e42b20e52b6a21e62b20e52b20e62b6a21e72b20e62b20e72b6a21e82b20e72b20e82b6a21e92b" + "20e82b20e92b6a21ea2b20e92b20ea2b6a21eb2b20ea2b20eb2b6a21ec2b20eb2b20ec2b6a21ed2b20ec2b20ed2b6a" + "21ee2b20ed2b20ee2b6a21ef2b20ee2b20ef2b6a21f02b20ef2b20f02b6a21f12b20f02b20f12b6a21f22b20f12b20" + "f22b6a21f32b20f22b20f32b6a21f42b20f32b20f42b6a21f52b20f42b20f52b6a21f62b20f52b20f62b6a21f72b20" + "f62b20f72b6a21f82b20f72b20f82b6a21f92b20f82b20f92b6a21fa2b20f92b20fa2b6a21fb2b20fa2b20fb2b6a21" + "fc2b20fb2b20fc2b6a21fd2b20fc2b20fd2b6a21fe2b20fd2b20fe2b6a21ff2b20fe2b20ff2b6a21802c20ff2b2080" + "2c6a21812c20802c20812c6a21822c20812c20822c6a21832c20822c20832c6a21842c20832c20842c6a21852c2084" + "2c20852c6a21862c20852c20862c6a21872c20862c20872c6a21882c20872c20882c6a21892c20882c20892c6a218a" + "2c20892c208a2c6a218b2c208a2c208b2c6a218c2c208b2c208c2c6a218d2c208c2c208d2c6a218e2c208d2c208e2c" + "6a218f2c208e2c208f2c6a21902c208f2c20902c6a21912c20902c20912c6a21922c20912c20922c6a21932c20922c" + "20932c6a21942c20932c20942c6a21952c20942c20952c6a21962c20952c20962c6a21972c20962c20972c6a21982c" + "20972c20982c6a21992c20982c20992c6a219a2c20992c209a2c6a219b2c209a2c209b2c6a219c2c209b2c209c2c6a" + "219d2c209c2c209d2c6a219e2c209d2c209e2c6a219f2c209e2c209f2c6a21a02c209f2c20a02c6a21a12c20a02c20" + "a12c6a21a22c20a12c20a22c6a21a32c20a22c20a32c6a21a42c20a32c20a42c6a21a52c20a42c20a52c6a21a62c20" + "a52c20a62c6a21a72c20a62c20a72c6a21a82c20a72c20a82c6a21a92c20a82c20a92c6a21aa2c20a92c20aa2c6a21" + "ab2c20aa2c20ab2c6a21ac2c20ab2c20ac2c6a21ad2c20ac2c20ad2c6a21ae2c20ad2c20ae2c6a21af2c20ae2c20af" + "2c6a21b02c20af2c20b02c6a21b12c20b02c20b12c6a21b22c20b12c20b22c6a21b32c20b22c20b32c6a21b42c20b3" + "2c20b42c6a21b52c20b42c20b52c6a21b62c20b52c20b62c6a21b72c20b62c20b72c6a21b82c20b72c20b82c6a21b9" + "2c20b82c20b92c6a21ba2c20b92c20ba2c6a21bb2c20ba2c20bb2c6a21bc2c20bb2c20bc2c6a21bd2c20bc2c20bd2c" + "6a21be2c20bd2c20be2c6a21bf2c20be2c20bf2c6a21c02c20bf2c20c02c6a21c12c20c02c20c12c6a21c22c20c12c" + "20c22c6a21c32c20c22c20c32c6a21c42c20c32c20c42c6a21c52c20c42c20c52c6a21c62c20c52c20c62c6a21c72c" + "20c62c20c72c6a21c82c20c72c20c82c6a21c92c20c82c20c92c6a21ca2c20c92c20ca2c6a21cb2c20ca2c20cb2c6a" + "21cc2c20cb2c20cc2c6a21cd2c20cc2c20cd2c6a21ce2c20cd2c20ce2c6a21cf2c20ce2c20cf2c6a21d02c20cf2c20" + "d02c6a21d12c20d02c20d12c6a21d22c20d12c20d22c6a21d32c20d22c20d32c6a21d42c20d32c20d42c6a21d52c20" + "d42c20d52c6a21d62c20d52c20d62c6a21d72c20d62c20d72c6a21d82c20d72c20d82c6a21d92c20d82c20d92c6a21" + "da2c20d92c20da2c6a21db2c20da2c20db2c6a21dc2c20db2c20dc2c6a21dd2c20dc2c20dd2c6a21de2c20dd2c20de" + "2c6a21df2c20de2c20df2c6a21e02c20df2c20e02c6a21e12c20e02c20e12c6a21e22c20e12c20e22c6a21e32c20e2" + "2c20e32c6a21e42c20e32c20e42c6a21e52c20e42c20e52c6a21e62c20e52c20e62c6a21e72c20e62c20e72c6a21e8" + "2c20e72c20e82c6a21e92c20e82c20e92c6a21ea2c20e92c20ea2c6a21eb2c20ea2c20eb2c6a21ec2c20eb2c20ec2c" + "6a21ed2c20ec2c20ed2c6a21ee2c20ed2c20ee2c6a21ef2c20ee2c20ef2c6a21f02c20ef2c20f02c6a21f12c20f02c" + "20f12c6a21f22c20f12c20f22c6a21f32c20f22c20f32c6a21f42c20f32c20f42c6a21f52c20f42c20f52c6a21f62c" + "20f52c20f62c6a21f72c20f62c20f72c6a21f82c20f72c20f82c6a21f92c20f82c20f92c6a21fa2c20f92c20fa2c6a" + "21fb2c20fa2c20fb2c6a21fc2c20fb2c20fc2c6a21fd2c20fc2c20fd2c6a21fe2c20fd2c20fe2c6a21ff2c20fe2c20" + "ff2c6a21802d20ff2c20802d6a21812d20802d20812d6a21822d20812d20822d6a21832d20822d20832d6a21842d20" + "832d20842d6a21852d20842d20852d6a21862d20852d20862d6a21872d20862d20872d6a21882d20872d20882d6a21" + "892d20882d20892d6a218a2d20892d208a2d6a218b2d208a2d208b2d6a218c2d208b2d208c2d6a218d2d208c2d208d" + "2d6a218e2d208d2d208e2d6a218f2d208e2d208f2d6a21902d208f2d20902d6a21912d20902d20912d6a21922d2091" + "2d20922d6a21932d20922d20932d6a21942d20932d20942d6a21952d20942d20952d6a21962d20952d20962d6a2197" + "2d20962d20972d6a21982d20972d20982d6a21992d20982d20992d6a219a2d20992d209a2d6a219b2d209a2d209b2d" + "6a219c2d209b2d209c2d6a219d2d209c2d209d2d6a219e2d209d2d209e2d6a219f2d209e2d209f2d6a21a02d209f2d" + "20a02d6a21a12d20a02d20a12d6a21a22d20a12d20a22d6a21a32d20a22d20a32d6a21a42d20a32d20a42d6a21a52d" + "20a42d20a52d6a21a62d20a52d20a62d6a21a72d20a62d20a72d6a21a82d20a72d20a82d6a21a92d20a82d20a92d6a" + "21aa2d20a92d20aa2d6a21ab2d20aa2d20ab2d6a21ac2d20ab2d20ac2d6a21ad2d20ac2d20ad2d6a21ae2d20ad2d20" + "ae2d6a21af2d20ae2d20af2d6a21b02d20af2d20b02d6a21b12d20b02d20b12d6a21b22d20b12d20b22d6a21b32d20" + "b22d20b32d6a21b42d20b32d20b42d6a21b52d20b42d20b52d6a21b62d20b52d20b62d6a21b72d20b62d20b72d6a21" + "b82d20b72d20b82d6a21b92d20b82d20b92d6a21ba2d20b92d20ba2d6a21bb2d20ba2d20bb2d6a21bc2d20bb2d20bc" + "2d6a21bd2d20bc2d20bd2d6a21be2d20bd2d20be2d6a21bf2d20be2d20bf2d6a21c02d20bf2d20c02d6a21c12d20c0" + "2d20c12d6a21c22d20c12d20c22d6a21c32d20c22d20c32d6a21c42d20c32d20c42d6a21c52d20c42d20c52d6a21c6" + "2d20c52d20c62d6a21c72d20c62d20c72d6a21c82d20c72d20c82d6a21c92d20c82d20c92d6a21ca2d20c92d20ca2d" + "6a21cb2d20ca2d20cb2d6a21cc2d20cb2d20cc2d6a21cd2d20cc2d20cd2d6a21ce2d20cd2d20ce2d6a21cf2d20ce2d" + "20cf2d6a21d02d20cf2d20d02d6a21d12d20d02d20d12d6a21d22d20d12d20d22d6a21d32d20d22d20d32d6a21d42d" + "20d32d20d42d6a21d52d20d42d20d52d6a21d62d20d52d20d62d6a21d72d20d62d20d72d6a21d82d20d72d20d82d6a" + "21d92d20d82d20d92d6a21da2d20d92d20da2d6a21db2d20da2d20db2d6a21dc2d20db2d20dc2d6a21dd2d20dc2d20" + "dd2d6a21de2d20dd2d20de2d6a21df2d20de2d20df2d6a21e02d20df2d20e02d6a21e12d20e02d20e12d6a21e22d20" + "e12d20e22d6a21e32d20e22d20e32d6a21e42d20e32d20e42d6a21e52d20e42d20e52d6a21e62d20e52d20e62d6a21" + "e72d20e62d20e72d6a21e82d20e72d20e82d6a21e92d20e82d20e92d6a21ea2d20e92d20ea2d6a21eb2d20ea2d20eb" + "2d6a21ec2d20eb2d20ec2d6a21ed2d20ec2d20ed2d6a21ee2d20ed2d20ee2d6a21ef2d20ee2d20ef2d6a21f02d20ef" + "2d20f02d6a21f12d20f02d20f12d6a21f22d20f12d20f22d6a21f32d20f22d20f32d6a21f42d20f32d20f42d6a21f5" + "2d20f42d20f52d6a21f62d20f52d20f62d6a21f72d20f62d20f72d6a21f82d20f72d20f82d6a21f92d20f82d20f92d" + "6a21fa2d20f92d20fa2d6a21fb2d20fa2d20fb2d6a21fc2d20fb2d20fc2d6a21fd2d20fc2d20fd2d6a21fe2d20fd2d" + "20fe2d6a21ff2d20fe2d20ff2d6a21802e20ff2d20802e6a21812e20802e20812e6a21822e20812e20822e6a21832e" + "20822e20832e6a21842e20832e20842e6a21852e20842e20852e6a21862e20852e20862e6a21872e20862e20872e6a" + "21882e20872e20882e6a21892e20882e20892e6a218a2e20892e208a2e6a218b2e208a2e208b2e6a218c2e208b2e20" + "8c2e6a218d2e208c2e208d2e6a218e2e208d2e208e2e6a218f2e208e2e208f2e6a21902e208f2e20902e6a21912e20" + "902e20912e6a21922e20912e20922e6a21932e20922e20932e6a21942e20932e20942e6a21952e20942e20952e6a21" + "962e20952e20962e6a21972e20962e20972e6a21982e20972e20982e6a21992e20982e20992e6a219a2e20992e209a" + "2e6a219b2e209a2e209b2e6a219c2e209b2e209c2e6a219d2e209c2e209d2e6a219e2e209d2e209e2e6a219f2e209e" + "2e209f2e6a21a02e209f2e20a02e6a21a12e20a02e20a12e6a21a22e20a12e20a22e6a21a32e20a22e20a32e6a21a4" + "2e20a32e20a42e6a21a52e20a42e20a52e6a21a62e20a52e20a62e6a21a72e20a62e20a72e6a21a82e20a72e20a82e" + "6a21a92e20a82e20a92e6a21aa2e20a92e20aa2e6a21ab2e20aa2e20ab2e6a21ac2e20ab2e20ac2e6a21ad2e20ac2e" + "20ad2e6a21ae2e20ad2e20ae2e6a21af2e20ae2e20af2e6a21b02e20af2e20b02e6a21b12e20b02e20b12e6a21b22e" + "20b12e20b22e6a21b32e20b22e20b32e6a21b42e20b32e20b42e6a21b52e20b42e20b52e6a21b62e20b52e20b62e6a" + "21b72e20b62e20b72e6a21b82e20b72e20b82e6a21b92e20b82e20b92e6a21ba2e20b92e20ba2e6a21bb2e20ba2e20" + "bb2e6a21bc2e20bb2e20bc2e6a21bd2e20bc2e20bd2e6a21be2e20bd2e20be2e6a21bf2e20be2e20bf2e6a21c02e20" + "bf2e20c02e6a21c12e20c02e20c12e6a21c22e20c12e20c22e6a21c32e20c22e20c32e6a21c42e20c32e20c42e6a21" + "c52e20c42e20c52e6a21c62e20c52e20c62e6a21c72e20c62e20c72e6a21c82e20c72e20c82e6a21c92e20c82e20c9" + "2e6a21ca2e20c92e20ca2e6a21cb2e20ca2e20cb2e6a21cc2e20cb2e20cc2e6a21cd2e20cc2e20cd2e6a21ce2e20cd" + "2e20ce2e6a21cf2e20ce2e20cf2e6a21d02e20cf2e20d02e6a21d12e20d02e20d12e6a21d22e20d12e20d22e6a21d3" + "2e20d22e20d32e6a21d42e20d32e20d42e6a21d52e20d42e20d52e6a21d62e20d52e20d62e6a21d72e20d62e20d72e" + "6a21d82e20d72e20d82e6a21d92e20d82e20d92e6a21da2e20d92e20da2e6a21db2e20da2e20db2e6a21dc2e20db2e" + "20dc2e6a21dd2e20dc2e20dd2e6a21de2e20dd2e20de2e6a21df2e20de2e20df2e6a21e02e20df2e20e02e6a21e12e" + "20e02e20e12e6a21e22e20e12e20e22e6a21e32e20e22e20e32e6a21e42e20e32e20e42e6a21e52e20e42e20e52e6a" + "21e62e20e52e20e62e6a21e72e20e62e20e72e6a21e82e20e72e20e82e6a21e92e20e82e20e92e6a21ea2e20e92e20" + "ea2e6a21eb2e20ea2e20eb2e6a21ec2e20eb2e20ec2e6a21ed2e20ec2e20ed2e6a21ee2e20ed2e20ee2e6a21ef2e20" + "ee2e20ef2e6a21f02e20ef2e20f02e6a21f12e20f02e20f12e6a21f22e20f12e20f22e6a21f32e20f22e20f32e6a21" + "f42e20f32e20f42e6a21f52e20f42e20f52e6a21f62e20f52e20f62e6a21f72e20f62e20f72e6a21f82e20f72e20f8" + "2e6a21f92e20f82e20f92e6a21fa2e20f92e20fa2e6a21fb2e20fa2e20fb2e6a21fc2e20fb2e20fc2e6a21fd2e20fc" + "2e20fd2e6a21fe2e20fd2e20fe2e6a21ff2e20fe2e20ff2e6a21802f20ff2e20802f6a21812f20802f20812f6a2182" + "2f20812f20822f6a21832f20822f20832f6a21842f20832f20842f6a21852f20842f20852f6a21862f20852f20862f" + "6a21872f20862f20872f6a21882f20872f20882f6a21892f20882f20892f6a218a2f20892f208a2f6a218b2f208a2f" + "208b2f6a218c2f208b2f208c2f6a218d2f208c2f208d2f6a218e2f208d2f208e2f6a218f2f208e2f208f2f6a21902f" + "208f2f20902f6a21912f20902f20912f6a21922f20912f20922f6a21932f20922f20932f6a21942f20932f20942f6a" + "21952f20942f20952f6a21962f20952f20962f6a21972f20962f20972f6a21982f20972f20982f6a21992f20982f20" + "992f6a219a2f20992f209a2f6a219b2f209a2f209b2f6a219c2f209b2f209c2f6a219d2f209c2f209d2f6a219e2f20" + "9d2f209e2f6a219f2f209e2f209f2f6a21a02f209f2f20a02f6a21a12f20a02f20a12f6a21a22f20a12f20a22f6a21" + "a32f20a22f20a32f6a21a42f20a32f20a42f6a21a52f20a42f20a52f6a21a62f20a52f20a62f6a21a72f20a62f20a7" + "2f6a21a82f20a72f20a82f6a21a92f20a82f20a92f6a21aa2f20a92f20aa2f6a21ab2f20aa2f20ab2f6a21ac2f20ab" + "2f20ac2f6a21ad2f20ac2f20ad2f6a21ae2f20ad2f20ae2f6a21af2f20ae2f20af2f6a21b02f20af2f20b02f6a21b1" + "2f20b02f20b12f6a21b22f20b12f20b22f6a21b32f20b22f20b32f6a21b42f20b32f20b42f6a21b52f20b42f20b52f" + "6a21b62f20b52f20b62f6a21b72f20b62f20b72f6a21b82f20b72f20b82f6a21b92f20b82f20b92f6a21ba2f20b92f" + "20ba2f6a21bb2f20ba2f20bb2f6a21bc2f20bb2f20bc2f6a21bd2f20bc2f20bd2f6a21be2f20bd2f20be2f6a21bf2f" + "20be2f20bf2f6a21c02f20bf2f20c02f6a21c12f20c02f20c12f6a21c22f20c12f20c22f6a21c32f20c22f20c32f6a" + "21c42f20c32f20c42f6a21c52f20c42f20c52f6a21c62f20c52f20c62f6a21c72f20c62f20c72f6a21c82f20c72f20" + "c82f6a21c92f20c82f20c92f6a21ca2f20c92f20ca2f6a21cb2f20ca2f20cb2f6a21cc2f20cb2f20cc2f6a21cd2f20" + "cc2f20cd2f6a21ce2f20cd2f20ce2f6a21cf2f20ce2f20cf2f6a21d02f20cf2f20d02f6a21d12f20d02f20d12f6a21" + "d22f20d12f20d22f6a21d32f20d22f20d32f6a21d42f20d32f20d42f6a21d52f20d42f20d52f6a21d62f20d52f20d6" + "2f6a21d72f20d62f20d72f6a21d82f20d72f20d82f6a21d92f20d82f20d92f6a21da2f20d92f20da2f6a21db2f20da" + "2f20db2f6a21dc2f20db2f20dc2f6a21dd2f20dc2f20dd2f6a21de2f20dd2f20de2f6a21df2f20de2f20df2f6a21e0" + "2f20df2f20e02f6a21e12f20e02f20e12f6a21e22f20e12f20e22f6a21e32f20e22f20e32f6a21e42f20e32f20e42f" + "6a21e52f20e42f20e52f6a21e62f20e52f20e62f6a21e72f20e62f20e72f6a21e82f20e72f20e82f6a21e92f20e82f" + "20e92f6a21ea2f20e92f20ea2f6a21eb2f20ea2f20eb2f6a21ec2f20eb2f20ec2f6a21ed2f20ec2f20ed2f6a21ee2f" + "20ed2f20ee2f6a21ef2f20ee2f20ef2f6a21f02f20ef2f20f02f6a21f12f20f02f20f12f6a21f22f20f12f20f22f6a" + "21f32f20f22f20f32f6a21f42f20f32f20f42f6a21f52f20f42f20f52f6a21f62f20f52f20f62f6a21f72f20f62f20" + "f72f6a21f82f20f72f20f82f6a21f92f20f82f20f92f6a21fa2f20f92f20fa2f6a21fb2f20fa2f20fb2f6a21fc2f20" + "fb2f20fc2f6a21fd2f20fc2f20fd2f6a21fe2f20fd2f20fe2f6a21ff2f20fe2f20ff2f6a21803020ff2f2080306a21" + "81302080302081306a2182302081302082306a2183302082302083306a2184302083302084306a2185302084302085" + "306a2186302085302086306a2187302086302087306a2188302087302088306a2189302088302089306a218a302089" + "30208a306a218b30208a30208b306a218c30208b30208c306a218d30208c30208d306a218e30208d30208e306a218f" + "30208e30208f306a219030208f302090306a2191302090302091306a2192302091302092306a219330209230209330" + "6a2194302093302094306a2195302094302095306a2196302095302096306a2197302096302097306a219830209730" + "2098306a2199302098302099306a219a30209930209a306a219b30209a30209b306a219c30209b30209c306a219d30" + "209c30209d306a219e30209d30209e306a219f30209e30209f306a21a030209f3020a0306a21a13020a03020a1306a" + "21a23020a13020a2306a21a33020a23020a3306a21a43020a33020a4306a21a53020a43020a5306a21a63020a53020" + "a6306a21a73020a63020a7306a21a83020a73020a8306a21a93020a83020a9306a21aa3020a93020aa306a21ab3020" + "aa3020ab306a21ac3020ab3020ac306a21ad3020ac3020ad306a21ae3020ad3020ae306a21af3020ae3020af306a21" + "b03020af3020b0306a21b13020b03020b1306a21b23020b13020b2306a21b33020b23020b3306a21b43020b33020b4" + "306a21b53020b43020b5306a21b63020b53020b6306a21b73020b63020b7306a21b83020b73020b8306a21b93020b8" + "3020b9306a21ba3020b93020ba306a21bb3020ba3020bb306a21bc3020bb3020bc306a21bd3020bc3020bd306a21be" + "3020bd3020be306a21bf3020be3020bf306a21c03020bf3020c0306a21c13020c03020c1306a21c23020c13020c230" + "6a21c33020c23020c3306a21c43020c33020c4306a21c53020c43020c5306a21c63020c53020c6306a21c73020c630" + "20c7306a21c83020c73020c8306a21c93020c83020c9306a21ca3020c93020ca306a21cb3020ca3020cb306a21cc30" + "20cb3020cc306a21cd3020cc3020cd306a21ce3020cd3020ce306a21cf3020ce3020cf306a21d03020cf3020d0306a" + "21d13020d03020d1306a21d23020d13020d2306a21d33020d23020d3306a21d43020d33020d4306a21d53020d43020" + "d5306a21d63020d53020d6306a21d73020d63020d7306a21d83020d73020d8306a21d93020d83020d9306a21da3020" + "d93020da306a21db3020da3020db306a21dc3020db3020dc306a21dd3020dc3020dd306a21de3020dd3020de306a21" + "df3020de3020df306a21e03020df3020e0306a21e13020e03020e1306a21e23020e13020e2306a21e33020e23020e3" + "306a21e43020e33020e4306a21e53020e43020e5306a21e63020e53020e6306a21e73020e63020e7306a21e83020e7" + "3020e8306a21e93020e83020e9306a21ea3020e93020ea306a21eb3020ea3020eb306a21ec3020eb3020ec306a21ed" + "3020ec3020ed306a21ee3020ed3020ee306a21ef3020ee3020ef306a21f03020ef3020f0306a21f13020f03020f130" + "6a21f23020f13020f2306a21f33020f23020f3306a21f43020f33020f4306a21f53020f43020f5306a21f63020f530" + "20f6306a21f73020f63020f7306a21f83020f73020f8306a21f93020f83020f9306a21fa3020f93020fa306a21fb30" + "20fa3020fb306a21fc3020fb3020fc306a21fd3020fc3020fd306a21fe3020fd3020fe306a21ff3020fe3020ff306a" + "21803120ff302080316a2181312080312081316a2182312081312082316a2183312082312083316a21843120833120" + "84316a2185312084312085316a2186312085312086316a2187312086312087316a2188312087312088316a21893120" + "88312089316a218a31208931208a316a218b31208a31208b316a218c31208b31208c316a218d31208c31208d316a21" + "8e31208d31208e316a218f31208e31208f316a219031208f312090316a2191312090312091316a2192312091312092" + "316a2193312092312093316a2194312093312094316a2195312094312095316a2196312095312096316a2197312096" + "312097316a2198312097312098316a2199312098312099316a219a31209931209a316a219b31209a31209b316a219c" + "31209b31209c316a219d31209c31209d316a219e31209d31209e316a219f31209e31209f316a21a031209f3120a031" + "6a21a13120a03120a1316a21a23120a13120a2316a21a33120a23120a3316a21a43120a33120a4316a21a53120a431" + "20a5316a21a63120a53120a6316a21a73120a63120a7316a21a83120a73120a8316a21a93120a83120a9316a21aa31" + "20a93120aa316a21ab3120aa3120ab316a21ac3120ab3120ac316a21ad3120ac3120ad316a21ae3120ad3120ae316a" + "21af3120ae3120af316a21b03120af3120b0316a21b13120b03120b1316a21b23120b13120b2316a21b33120b23120" + "b3316a21b43120b33120b4316a21b53120b43120b5316a21b63120b53120b6316a21b73120b63120b7316a21b83120" + "b73120b8316a21b93120b83120b9316a21ba3120b93120ba316a21bb3120ba3120bb316a21bc3120bb3120bc316a21" + "bd3120bc3120bd316a21be3120bd3120be316a21bf3120be3120bf316a21c03120bf3120c0316a21c13120c03120c1" + "316a21c23120c13120c2316a21c33120c23120c3316a21c43120c33120c4316a21c53120c43120c5316a21c63120c5" + "3120c6316a21c73120c63120c7316a21c83120c73120c8316a21c93120c83120c9316a21ca3120c93120ca316a21cb" + "3120ca3120cb316a21cc3120cb3120cc316a21cd3120cc3120cd316a21ce3120cd3120ce316a21cf3120ce3120cf31" + "6a21d03120cf3120d0316a21d13120d03120d1316a21d23120d13120d2316a21d33120d23120d3316a21d43120d331" + "20d4316a21d53120d43120d5316a21d63120d53120d6316a21d73120d63120d7316a21d83120d73120d8316a21d931" + "20d83120d9316a21da3120d93120da316a21db3120da3120db316a21dc3120db3120dc316a21dd3120dc3120dd316a" + "21de3120dd3120de316a21df3120de3120df316a21e03120df3120e0316a21e13120e03120e1316a21e23120e13120" + "e2316a21e33120e23120e3316a21e43120e33120e4316a21e53120e43120e5316a21e63120e53120e6316a21e73120" + "e63120e7316a21e83120e73120e8316a21e93120e83120e9316a21ea3120e93120ea316a21eb3120ea3120eb316a21" + "ec3120eb3120ec316a21ed3120ec3120ed316a21ee3120ed3120ee316a21ef3120ee3120ef316a21f03120ef3120f0" + "316a21f13120f03120f1316a21f23120f13120f2316a21f33120f23120f3316a21f43120f33120f4316a21f53120f4" + "3120f5316a21f63120f53120f6316a21f73120f63120f7316a21f83120f73120f8316a21f93120f83120f9316a21fa" + "3120f93120fa316a21fb3120fa3120fb316a21fc3120fb3120fc316a21fd3120fc3120fd316a21fe3120fd3120fe31" + "6a21ff3120fe3120ff316a21803220ff312080326a2181322080322081326a2182322081322082326a218332208232" + "2083326a2184322083322084326a2185322084322085326a2186322085322086326a2187322086322087326a218832" + "2087322088326a2189322088322089326a218a32208932208a326a218b32208a32208b326a218c32208b32208c326a" + "218d32208c32208d326a218e32208d32208e326a218f32208e32208f326a219032208f322090326a21913220903220" + "91326a2192322091322092326a2193322092322093326a2194322093322094326a2195322094322095326a21963220" + "95322096326a2197322096322097326a2198322097322098326a2199322098322099326a219a32209932209a326a21" + "9b32209a32209b326a219c32209b32209c326a219d32209c32209d326a219e32209d32209e326a219f32209e32209f" + "326a21a032209f3220a0326a21a13220a03220a1326a21a23220a13220a2326a21a33220a23220a3326a21a43220a3" + "3220a4326a21a53220a43220a5326a21a63220a53220a6326a21a73220a63220a7326a21a83220a73220a8326a21a9" + "3220a83220a9326a21aa3220a93220aa326a21ab3220aa3220ab326a21ac3220ab3220ac326a21ad3220ac3220ad32" + "6a21ae3220ad3220ae326a21af3220ae3220af326a21b03220af3220b0326a21b13220b03220b1326a21b23220b132" + "20b2326a21b33220b23220b3326a21b43220b33220b4326a21b53220b43220b5326a21b63220b53220b6326a21b732" + "20b63220b7326a21b83220b73220b8326a21b93220b83220b9326a21ba3220b93220ba326a21bb3220ba3220bb326a" + "21bc3220bb3220bc326a21bd3220bc3220bd326a21be3220bd3220be326a21bf3220be3220bf326a21c03220bf3220" + "c0326a21c13220c03220c1326a21c23220c13220c2326a21c33220c23220c3326a21c43220c33220c4326a21c53220" + "c43220c5326a21c63220c53220c6326a21c73220c63220c7326a21c83220c73220c8326a21c93220c83220c9326a21" + "ca3220c93220ca326a21cb3220ca3220cb326a21cc3220cb3220cc326a21cd3220cc3220cd326a21ce3220cd3220ce" + "326a21cf3220ce3220cf326a21d03220cf3220d0326a21d13220d03220d1326a21d23220d13220d2326a21d33220d2" + "3220d3326a21d43220d33220d4326a21d53220d43220d5326a21d63220d53220d6326a21d73220d63220d7326a21d8" + "3220d73220d8326a21d93220d83220d9326a21da3220d93220da326a21db3220da3220db326a21dc3220db3220dc32" + "6a21dd3220dc3220dd326a21de3220dd3220de326a21df3220de3220df326a21e03220df3220e0326a21e13220e032" + "20e1326a21e23220e13220e2326a21e33220e23220e3326a21e43220e33220e4326a21e53220e43220e5326a21e632" + "20e53220e6326a21e73220e63220e7326a21e83220e73220e8326a21e93220e83220e9326a21ea3220e93220ea326a" + "21eb3220ea3220eb326a21ec3220eb3220ec326a21ed3220ec3220ed326a21ee3220ed3220ee326a21ef3220ee3220" + "ef326a21f03220ef3220f0326a21f13220f03220f1326a21f23220f13220f2326a21f33220f23220f3326a21f43220" + "f33220f4326a21f53220f43220f5326a21f63220f53220f6326a21f73220f63220f7326a21f83220f73220f8326a21" + "f93220f83220f9326a21fa3220f93220fa326a21fb3220fa3220fb326a21fc3220fb3220fc326a21fd3220fc3220fd" + "326a21fe3220fd3220fe326a21ff3220fe3220ff326a21803320ff322080336a2181332080332081336a2182332081" + "332082336a2183332082332083336a2184332083332084336a2185332084332085336a2186332085332086336a2187" + "332086332087336a2188332087332088336a2189332088332089336a218a33208933208a336a218b33208a33208b33" + "6a218c33208b33208c336a218d33208c33208d336a218e33208d33208e336a218f33208e33208f336a219033208f33" + "2090336a2191332090332091336a2192332091332092336a2193332092332093336a2194332093332094336a219533" + "2094332095336a2196332095332096336a2197332096332097336a2198332097332098336a2199332098332099336a" + "219a33209933209a336a219b33209a33209b336a219c33209b33209c336a219d33209c33209d336a219e33209d3320" + "9e336a219f33209e33209f336a21a033209f3320a0336a21a13320a03320a1336a21a23320a13320a2336a21a33320" + "a23320a3336a21a43320a33320a4336a21a53320a43320a5336a21a63320a53320a6336a21a73320a63320a7336a21" + "a83320a73320a8336a21a93320a83320a9336a21aa3320a93320aa336a21ab3320aa3320ab336a21ac3320ab3320ac" + "336a21ad3320ac3320ad336a21ae3320ad3320ae336a21af3320ae3320af336a21b03320af3320b0336a21b13320b0" + "3320b1336a21b23320b13320b2336a21b33320b23320b3336a21b43320b33320b4336a21b53320b43320b5336a21b6" + "3320b53320b6336a21b73320b63320b7336a21b83320b73320b8336a21b93320b83320b9336a21ba3320b93320ba33" + "6a21bb3320ba3320bb336a21bc3320bb3320bc336a21bd3320bc3320bd336a21be3320bd3320be336a21bf3320be33" + "20bf336a21c03320bf3320c0336a21c13320c03320c1336a21c23320c13320c2336a21c33320c23320c3336a21c433" + "20c33320c4336a21c53320c43320c5336a21c63320c53320c6336a21c73320c63320c7336a21c83320c73320c8336a" + "21c93320c83320c9336a21ca3320c93320ca336a21cb3320ca3320cb336a21cc3320cb3320cc336a21cd3320cc3320" + "cd336a21ce3320cd3320ce336a21cf3320ce3320cf336a21d03320cf3320d0336a21d13320d03320d1336a21d23320" + "d13320d2336a21d33320d23320d3336a21d43320d33320d4336a21d53320d43320d5336a21d63320d53320d6336a21" + "d73320d63320d7336a21d83320d73320d8336a21d93320d83320d9336a21da3320d93320da336a21db3320da3320db" + "336a21dc3320db3320dc336a21dd3320dc3320dd336a21de3320dd3320de336a21df3320de3320df336a21e03320df" + "3320e0336a21e13320e03320e1336a21e23320e13320e2336a21e33320e23320e3336a21e43320e33320e4336a21e5" + "3320e43320e5336a21e63320e53320e6336a21e73320e63320e7336a21e83320e73320e8336a21e93320e83320e933" + "6a21ea3320e93320ea336a21eb3320ea3320eb336a21ec3320eb3320ec336a21ed3320ec3320ed336a21ee3320ed33" + "20ee336a21ef3320ee3320ef336a21f03320ef3320f0336a21f13320f03320f1336a21f23320f13320f2336a21f333" + "20f23320f3336a21f43320f33320f4336a21f53320f43320f5336a21f63320f53320f6336a21f73320f63320f7336a" + "21f83320f73320f8336a21f93320f83320f9336a21fa3320f93320fa336a21fb3320fa3320fb336a21fc3320fb3320" + "fc336a21fd3320fc3320fd336a21fe3320fd3320fe336a21ff3320fe3320ff336a21803420ff332080346a21813420" + "80342081346a2182342081342082346a2183342082342083346a2184342083342084346a2185342084342085346a21" + "86342085342086346a2187342086342087346a2188342087342088346a2189342088342089346a218a34208934208a" + "346a218b34208a34208b346a218c34208b34208c346a218d34208c34208d346a218e34208d34208e346a218f34208e" + "34208f346a219034208f342090346a2191342090342091346a2192342091342092346a2193342092342093346a2194" + "342093342094346a2195342094342095346a2196342095342096346a2197342096342097346a219834209734209834" + "6a2199342098342099346a219a34209934209a346a219b34209a34209b346a219c34209b34209c346a219d34209c34" + "209d346a219e34209d34209e346a219f34209e34209f346a21a034209f3420a0346a21a13420a03420a1346a21a234" + "20a13420a2346a21a33420a23420a3346a21a43420a33420a4346a21a53420a43420a5346a21a63420a53420a6346a" + "21a73420a63420a7346a21a83420a73420a8346a21a93420a83420a9346a21aa3420a93420aa346a21ab3420aa3420" + "ab346a21ac3420ab3420ac346a21ad3420ac3420ad346a21ae3420ad3420ae346a21af3420ae3420af346a21b03420" + "af3420b0346a21b13420b03420b1346a21b23420b13420b2346a21b33420b23420b3346a21b43420b33420b4346a21" + "b53420b43420b5346a21b63420b53420b6346a21b73420b63420b7346a21b83420b73420b8346a21b93420b83420b9" + "346a21ba3420b93420ba346a21bb3420ba3420bb346a21bc3420bb3420bc346a21bd3420bc3420bd346a21be3420bd" + "3420be346a21bf3420be3420bf346a21c03420bf3420c0346a21c13420c03420c1346a21c23420c13420c2346a21c3" + "3420c23420c3346a21c43420c33420c4346a21c53420c43420c5346a21c63420c53420c6346a21c73420c63420c734" + "6a21c83420c73420c8346a21c93420c83420c9346a21ca3420c93420ca346a21cb3420ca3420cb346a21cc3420cb34" + "20cc346a21cd3420cc3420cd346a21ce3420cd3420ce346a21cf3420ce3420cf346a21d03420cf3420d0346a21d134" + "20d03420d1346a21d23420d13420d2346a21d33420d23420d3346a21d43420d33420d4346a21d53420d43420d5346a" + "21d63420d53420d6346a21d73420d63420d7346a21d83420d73420d8346a21d93420d83420d9346a21da3420d93420" + "da346a21db3420da3420db346a21dc3420db3420dc346a21dd3420dc3420dd346a21de3420dd3420de346a21df3420" + "de3420df346a21e03420df3420e0346a21e13420e03420e1346a21e23420e13420e2346a21e33420e23420e3346a21" + "e43420e33420e4346a21e53420e43420e5346a21e63420e53420e6346a21e73420e63420e7346a21e83420e73420e8" + "346a21e93420e83420e9346a21ea3420e93420ea346a21eb3420ea3420eb346a21ec3420eb3420ec346a21ed3420ec" + "3420ed346a21ee3420ed3420ee346a21ef3420ee3420ef346a21f03420ef3420f0346a21f13420f03420f1346a21f2" + "3420f13420f2346a21f33420f23420f3346a21f43420f33420f4346a21f53420f43420f5346a21f63420f53420f634" + "6a21f73420f63420f7346a21f83420f73420f8346a21f93420f83420f9346a21fa3420f93420fa346a21fb3420fa34" + "20fb346a21fc3420fb3420fc346a21fd3420fc3420fd346a21fe3420fd3420fe346a21ff3420fe3420ff346a218035" + "20ff342080356a2181352080352081356a2182352081352082356a2183352082352083356a2184352083352084356a" + "2185352084352085356a2186352085352086356a2187352086352087356a2188352087352088356a21893520883520" + "89356a218a35208935208a356a218b35208a35208b356a218c35208b35208c356a218d35208c35208d356a218e3520" + "8d35208e356a218f35208e35208f356a219035208f352090356a2191352090352091356a2192352091352092356a21" + "93352092352093356a2194352093352094356a2195352094352095356a2196352095352096356a2197352096352097" + "356a2198352097352098356a2199352098352099356a219a35209935209a356a219b35209a35209b356a219c35209b" + "35209c356a219d35209c35209d356a219e35209d35209e356a219f35209e35209f356a21a035209f3520a0356a21a1" + "3520a03520a1356a21a23520a13520a2356a21a33520a23520a3356a21a43520a33520a4356a21a53520a43520a535" + "6a21a63520a53520a6356a21a73520a63520a7356a21a83520a73520a8356a21a93520a83520a9356a21aa3520a935" + "20aa356a21ab3520aa3520ab356a21ac3520ab3520ac356a21ad3520ac3520ad356a21ae3520ad3520ae356a21af35" + "20ae3520af356a21b03520af3520b0356a21b13520b03520b1356a21b23520b13520b2356a21b33520b23520b3356a" + "21b43520b33520b4356a21b53520b43520b5356a21b63520b53520b6356a21b73520b63520b7356a21b83520b73520" + "b8356a21b93520b83520b9356a21ba3520b93520ba356a21bb3520ba3520bb356a21bc3520bb3520bc356a21bd3520" + "bc3520bd356a21be3520bd3520be356a21bf3520be3520bf356a21c03520bf3520c0356a21c13520c03520c1356a21" + "c23520c13520c2356a21c33520c23520c3356a21c43520c33520c4356a21c53520c43520c5356a21c63520c53520c6" + "356a21c73520c63520c7356a21c83520c73520c8356a21c93520c83520c9356a21ca3520c93520ca356a21cb3520ca" + "3520cb356a21cc3520cb3520cc356a21cd3520cc3520cd356a21ce3520cd3520ce356a21cf3520ce3520cf356a21d0" + "3520cf3520d0356a21d13520d03520d1356a21d23520d13520d2356a21d33520d23520d3356a21d43520d33520d435" + "6a21d53520d43520d5356a21d63520d53520d6356a21d73520d63520d7356a21d83520d73520d8356a21d93520d835" + "20d9356a21da3520d93520da356a21db3520da3520db356a21dc3520db3520dc356a21dd3520dc3520dd356a21de35" + "20dd3520de356a21df3520de3520df356a21e03520df3520e0356a21e13520e03520e1356a21e23520e13520e2356a" + "21e33520e23520e3356a21e43520e33520e4356a21e53520e43520e5356a21e63520e53520e6356a21e73520e63520" + "e7356a21e83520e73520e8356a21e93520e83520e9356a21ea3520e93520ea356a21eb3520ea3520eb356a21ec3520" + "eb3520ec356a21ed3520ec3520ed356a21ee3520ed3520ee356a21ef3520ee3520ef356a21f03520ef3520f0356a21" + "f13520f03520f1356a21f23520f13520f2356a21f33520f23520f3356a21f43520f33520f4356a21f53520f43520f5" + "356a21f63520f53520f6356a21f73520f63520f7356a21f83520f73520f8356a21f93520f83520f9356a21fa3520f9" + "3520fa356a21fb3520fa3520fb356a21fc3520fb3520fc356a21fd3520fc3520fd356a21fe3520fd3520fe356a21ff" + "3520fe3520ff356a21803620ff352080366a2181362080362081366a2182362081362082366a218336208236208336" + "6a2184362083362084366a2185362084362085366a2186362085362086366a2187362086362087366a218836208736" + "2088366a2189362088362089366a218a36208936208a366a218b36208a36208b366a218c36208b36208c366a218d36" + "208c36208d366a218e36208d36208e366a218f36208e36208f366a219036208f362090366a2191362090362091366a" + "2192362091362092366a2193362092362093366a2194362093362094366a2195362094362095366a21963620953620" + "96366a2197362096362097366a2198362097362098366a2199362098362099366a219a36209936209a366a219b3620" + "9a36209b366a219c36209b36209c366a219d36209c36209d366a219e36209d36209e366a219f36209e36209f366a21" + "a036209f3620a0366a21a13620a03620a1366a21a23620a13620a2366a21a33620a23620a3366a21a43620a33620a4" + "366a21a53620a43620a5366a21a63620a53620a6366a21a73620a63620a7366a21a83620a73620a8366a21a93620a8" + "3620a9366a21aa3620a93620aa366a21ab3620aa3620ab366a21ac3620ab3620ac366a21ad3620ac3620ad366a21ae" + "3620ad3620ae366a21af3620ae3620af366a21b03620af3620b0366a21b13620b03620b1366a21b23620b13620b236" + "6a21b33620b23620b3366a21b43620b33620b4366a21b53620b43620b5366a21b63620b53620b6366a21b73620b636" + "20b7366a21b83620b73620b8366a21b93620b83620b9366a21ba3620b93620ba366a21bb3620ba3620bb366a21bc36" + "20bb3620bc366a21bd3620bc3620bd366a21be3620bd3620be366a21bf3620be3620bf366a21c03620bf3620c0366a" + "21c13620c03620c1366a21c23620c13620c2366a21c33620c23620c3366a21c43620c33620c4366a21c53620c43620" + "c5366a21c63620c53620c6366a21c73620c63620c7366a21c83620c73620c8366a21c93620c83620c9366a21ca3620" + "c93620ca366a21cb3620ca3620cb366a21cc3620cb3620cc366a21cd3620cc3620cd366a21ce3620cd3620ce366a21" + "cf3620ce3620cf366a21d03620cf3620d0366a21d13620d03620d1366a21d23620d13620d2366a21d33620d23620d3" + "366a21d43620d33620d4366a21d53620d43620d5366a21d63620d53620d6366a21d73620d63620d7366a21d83620d7" + "3620d8366a21d93620d83620d9366a21da3620d93620da366a21db3620da3620db366a21dc3620db3620dc366a21dd" + "3620dc3620dd366a21de3620dd3620de366a21df3620de3620df366a21e03620df3620e0366a21e13620e03620e136" + "6a21e23620e13620e2366a21e33620e23620e3366a21e43620e33620e4366a21e53620e43620e5366a21e63620e536" + "20e6366a21e73620e63620e7366a21e83620e73620e8366a21e93620e83620e9366a21ea3620e93620ea366a21eb36" + "20ea3620eb366a21ec3620eb3620ec366a21ed3620ec3620ed366a21ee3620ed3620ee366a21ef3620ee3620ef366a" + "21f03620ef3620f0366a21f13620f03620f1366a21f23620f13620f2366a21f33620f23620f3366a21f43620f33620" + "f4366a21f53620f43620f5366a21f63620f53620f6366a21f73620f63620f7366a21f83620f73620f8366a21f93620" + "f83620f9366a21fa3620f93620fa366a21fb3620fa3620fb366a21fc3620fb3620fc366a21fd3620fc3620fd366a21" + "fe3620fd3620fe366a21ff3620fe3620ff366a21803720ff362080376a2181372080372081376a2182372081372082" + "376a2183372082372083376a2184372083372084376a2185372084372085376a2186372085372086376a2187372086" + "372087376a2188372087372088376a2189372088372089376a218a37208937208a376a218b37208a37208b376a218c" + "37208b37208c376a218d37208c37208d376a218e37208d37208e376a218f37208e37208f376a219037208f37209037" + "6a2191372090372091376a2192372091372092376a2193372092372093376a2194372093372094376a219537209437" + "2095376a2196372095372096376a2197372096372097376a2198372097372098376a2199372098372099376a219a37" + "209937209a376a219b37209a37209b376a219c37209b37209c376a219d37209c37209d376a219e37209d37209e376a" + "219f37209e37209f376a21a037209f3720a0376a21a13720a03720a1376a21a23720a13720a2376a21a33720a23720" + "a3376a21a43720a33720a4376a21a53720a43720a5376a21a63720a53720a6376a21a73720a63720a7376a21a83720" + "a73720a8376a21a93720a83720a9376a21aa3720a93720aa376a21ab3720aa3720ab376a21ac3720ab3720ac376a21" + "ad3720ac3720ad376a21ae3720ad3720ae376a21af3720ae3720af376a21b03720af3720b0376a21b13720b03720b1" + "376a21b23720b13720b2376a21b33720b23720b3376a21b43720b33720b4376a21b53720b43720b5376a21b63720b5" + "3720b6376a21b73720b63720b7376a21b83720b73720b8376a21b93720b83720b9376a21ba3720b93720ba376a21bb" + "3720ba3720bb376a21bc3720bb3720bc376a21bd3720bc3720bd376a21be3720bd3720be376a21bf3720be3720bf37" + "6a21c03720bf3720c0376a21c13720c03720c1376a21c23720c13720c2376a21c33720c23720c3376a21c43720c337" + "20c4376a21c53720c43720c5376a21c63720c53720c6376a21c73720c63720c7376a21c83720c73720c8376a21c937" + "20c83720c9376a21ca3720c93720ca376a21cb3720ca3720cb376a21cc3720cb3720cc376a21cd3720cc3720cd376a" + "21ce3720cd3720ce376a21cf3720ce3720cf376a21d03720cf3720d0376a21d13720d03720d1376a21d23720d13720" + "d2376a21d33720d23720d3376a21d43720d33720d4376a21d53720d43720d5376a21d63720d53720d6376a21d73720" + "d63720d7376a21d83720d73720d8376a21d93720d83720d9376a21da3720d93720da376a21db3720da3720db376a21" + "dc3720db3720dc376a21dd3720dc3720dd376a21de3720dd3720de376a21df3720de3720df376a21e03720df3720e0" + "376a21e13720e03720e1376a21e23720e13720e2376a21e33720e23720e3376a21e43720e33720e4376a21e53720e4" + "3720e5376a21e63720e53720e6376a21e73720e63720e7376a21e83720e73720e8376a21e93720e83720e9376a21ea" + "3720e93720ea376a21eb3720ea3720eb376a21ec3720eb3720ec376a21ed3720ec3720ed376a21ee3720ed3720ee37" + "6a21ef3720ee3720ef376a21f03720ef3720f0376a21f13720f03720f1376a21f23720f13720f2376a21f33720f237" + "20f3376a21f43720f33720f4376a21f53720f43720f5376a21f63720f53720f6376a21f73720f63720f7376a21f837" + "20f73720f8376a21f93720f83720f9376a21fa3720f93720fa376a21fb3720fa3720fb376a21fc3720fb3720fc376a" + "21fd3720fc3720fd376a21fe3720fd3720fe376a21ff3720fe3720ff376a21803820ff372080386a21813820803820" + "81386a2182382081382082386a2183382082382083386a2184382083382084386a2185382084382085386a21863820" + "85382086386a2187382086382087386a2188382087382088386a2189382088382089386a218a38208938208a386a21" + "8b38208a38208b386a218c38208b38208c386a218d38208c38208d386a218e38208d38208e386a218f38208e38208f" + "386a219038208f382090386a2191382090382091386a2192382091382092386a2193382092382093386a2194382093" + "382094386a2195382094382095386a2196382095382096386a2197382096382097386a2198382097382098386a2199" + "382098382099386a219a38209938209a386a219b38209a38209b386a219c38209b38209c386a219d38209c38209d38" + "6a219e38209d38209e386a219f38209e38209f386a21a038209f3820a0386a21a13820a03820a1386a21a23820a138" + "20a2386a21a33820a23820a3386a21a43820a33820a4386a21a53820a43820a5386a21a63820a53820a6386a21a738" + "20a63820a7386a21a83820a73820a8386a21a93820a83820a9386a21aa3820a93820aa386a21ab3820aa3820ab386a" + "21ac3820ab3820ac386a21ad3820ac3820ad386a21ae3820ad3820ae386a21af3820ae3820af386a21b03820af3820" + "b0386a21b13820b03820b1386a21b23820b13820b2386a21b33820b23820b3386a21b43820b33820b4386a21b53820" + "b43820b5386a21b63820b53820b6386a21b73820b63820b7386a21b83820b73820b8386a21b93820b83820b9386a21" + "ba3820b93820ba386a21bb3820ba3820bb386a21bc3820bb3820bc386a21bd3820bc3820bd386a21be3820bd3820be" + "386a21bf3820be3820bf386a21c03820bf3820c0386a21c13820c03820c1386a21c23820c13820c2386a21c33820c2" + "3820c3386a21c43820c33820c4386a21c53820c43820c5386a21c63820c53820c6386a21c73820c63820c7386a21c8" + "3820c73820c8386a21c93820c83820c9386a21ca3820c93820ca386a21cb3820ca3820cb386a21cc3820cb3820cc38" + "6a21cd3820cc3820cd386a21ce3820cd3820ce386a21cf3820ce3820cf386a21d03820cf3820d0386a21d13820d038" + "20d1386a21d23820d13820d2386a21d33820d23820d3386a21d43820d33820d4386a21d53820d43820d5386a21d638" + "20d53820d6386a21d73820d63820d7386a21d83820d73820d8386a21d93820d83820d9386a21da3820d93820da386a" + "21db3820da3820db386a21dc3820db3820dc386a21dd3820dc3820dd386a21de3820dd3820de386a21df3820de3820" + "df386a21e03820df3820e0386a21e13820e03820e1386a21e23820e13820e2386a21e33820e23820e3386a21e43820" + "e33820e4386a21e53820e43820e5386a21e63820e53820e6386a21e73820e63820e7386a21e83820e73820e8386a21" + "e93820e83820e9386a21ea3820e93820ea386a21eb3820ea3820eb386a21ec3820eb3820ec386a21ed3820ec3820ed" + "386a21ee3820ed3820ee386a21ef3820ee3820ef386a21f03820ef3820f0386a21f13820f03820f1386a21f23820f1" + "3820f2386a21f33820f23820f3386a21f43820f33820f4386a21f53820f43820f5386a21f63820f53820f6386a21f7" + "3820f63820f7386a21f83820f73820f8386a21f93820f83820f9386a21fa3820f93820fa386a21fb3820fa3820fb38" + "6a21fc3820fb3820fc386a21fd3820fc3820fd386a21fe3820fd3820fe386a21ff3820fe3820ff386a21803920ff38" + "2080396a2181392080392081396a2182392081392082396a2183392082392083396a2184392083392084396a218539" + "2084392085396a2186392085392086396a2187392086392087396a2188392087392088396a2189392088392089396a" + "218a39208939208a396a218b39208a39208b396a218c39208b39208c396a218d39208c39208d396a218e39208d3920" + "8e396a218f39208e39208f396a219039208f392090396a2191392090392091396a2192392091392092396a21933920" + "92392093396a2194392093392094396a2195392094392095396a2196392095392096396a2197392096392097396a21" + "98392097392098396a2199392098392099396a219a39209939209a396a219b39209a39209b396a219c39209b39209c" + "396a219d39209c39209d396a219e39209d39209e396a219f39209e39209f396a21a039209f3920a0396a21a13920a0" + "3920a1396a21a23920a13920a2396a21a33920a23920a3396a21a43920a33920a4396a21a53920a43920a5396a21a6" + "3920a53920a6396a21a73920a63920a7396a21a83920a73920a8396a21a93920a83920a9396a21aa3920a93920aa39" + "6a21ab3920aa3920ab396a21ac3920ab3920ac396a21ad3920ac3920ad396a21ae3920ad3920ae396a21af3920ae39" + "20af396a21b03920af3920b0396a21b13920b03920b1396a21b23920b13920b2396a21b33920b23920b3396a21b439" + "20b33920b4396a21b53920b43920b5396a21b63920b53920b6396a21b73920b63920b7396a21b83920b73920b8396a" + "21b93920b83920b9396a21ba3920b93920ba396a21bb3920ba3920bb396a21bc3920bb3920bc396a21bd3920bc3920" + "bd396a21be3920bd3920be396a21bf3920be3920bf396a21c03920bf3920c0396a21c13920c03920c1396a21c23920" + "c13920c2396a21c33920c23920c3396a21c43920c33920c4396a21c53920c43920c5396a21c63920c53920c6396a21" + "c73920c63920c7396a21c83920c73920c8396a21c93920c83920c9396a21ca3920c93920ca396a21cb3920ca3920cb" + "396a21cc3920cb3920cc396a21cd3920cc3920cd396a21ce3920cd3920ce396a21cf3920ce3920cf396a21d03920cf" + "3920d0396a21d13920d03920d1396a21d23920d13920d2396a21d33920d23920d3396a21d43920d33920d4396a21d5" + "3920d43920d5396a21d63920d53920d6396a21d73920d63920d7396a21d83920d73920d8396a21d93920d83920d939" + "6a21da3920d93920da396a21db3920da3920db396a21dc3920db3920dc396a21dd3920dc3920dd396a21de3920dd39" + "20de396a21df3920de3920df396a21e03920df3920e0396a21e13920e03920e1396a21e23920e13920e2396a21e339" + "20e23920e3396a21e43920e33920e4396a21e53920e43920e5396a21e63920e53920e6396a21e73920e63920e7396a" + "21e83920e73920e8396a21e93920e83920e9396a21ea3920e93920ea396a21eb3920ea3920eb396a21ec3920eb3920" + "ec396a21ed3920ec3920ed396a21ee3920ed3920ee396a21ef3920ee3920ef396a21f03920ef3920f0396a21f13920" + "f03920f1396a21f23920f13920f2396a21f33920f23920f3396a21f43920f33920f4396a21f53920f43920f5396a21" + "f63920f53920f6396a21f73920f63920f7396a21f83920f73920f8396a21f93920f83920f9396a21fa3920f93920fa" + "396a21fb3920fa3920fb396a21fc3920fb3920fc396a21fd3920fc3920fd396a21fe3920fd3920fe396a21ff3920fe" + "3920ff396a21803a20ff3920803a6a21813a20803a20813a6a21823a20813a20823a6a21833a20823a20833a6a2184" + "3a20833a20843a6a21853a20843a20853a6a21863a20853a20863a6a21873a20863a20873a6a21883a20873a20883a" + "6a21893a20883a20893a6a218a3a20893a208a3a6a218b3a208a3a208b3a6a218c3a208b3a208c3a6a218d3a208c3a" + "208d3a6a218e3a208d3a208e3a6a218f3a208e3a208f3a6a21903a208f3a20903a6a21913a20903a20913a6a21923a" + "20913a20923a6a21933a20923a20933a6a21943a20933a20943a6a21953a20943a20953a6a21963a20953a20963a6a" + "21973a20963a20973a6a21983a20973a20983a6a21993a20983a20993a6a219a3a20993a209a3a6a219b3a209a3a20" + "9b3a6a219c3a209b3a209c3a6a219d3a209c3a209d3a6a219e3a209d3a209e3a6a219f3a209e3a209f3a6a21a03a20" + "9f3a20a03a6a21a13a20a03a20a13a6a21a23a20a13a20a23a6a21a33a20a23a20a33a6a21a43a20a33a20a43a6a21" + "a53a20a43a20a53a6a21a63a20a53a20a63a6a21a73a20a63a20a73a6a21a83a20a73a20a83a6a21a93a20a83a20a9" + "3a6a21aa3a20a93a20aa3a6a21ab3a20aa3a20ab3a6a21ac3a20ab3a20ac3a6a21ad3a20ac3a20ad3a6a21ae3a20ad" + "3a20ae3a6a21af3a20ae3a20af3a6a21b03a20af3a20b03a6a21b13a20b03a20b13a6a21b23a20b13a20b23a6a21b3" + "3a20b23a20b33a6a21b43a20b33a20b43a6a21b53a20b43a20b53a6a21b63a20b53a20b63a6a21b73a20b63a20b73a" + "6a21b83a20b73a20b83a6a21b93a20b83a20b93a6a21ba3a20b93a20ba3a6a21bb3a20ba3a20bb3a6a21bc3a20bb3a" + "20bc3a6a21bd3a20bc3a20bd3a6a21be3a20bd3a20be3a6a21bf3a20be3a20bf3a6a21c03a20bf3a20c03a6a21c13a" + "20c03a20c13a6a21c23a20c13a20c23a6a21c33a20c23a20c33a6a21c43a20c33a20c43a6a21c53a20c43a20c53a6a" + "21c63a20c53a20c63a6a21c73a20c63a20c73a6a21c83a20c73a20c83a6a21c93a20c83a20c93a6a21ca3a20c93a20" + "ca3a6a21cb3a20ca3a20cb3a6a21cc3a20cb3a20cc3a6a21cd3a20cc3a20cd3a6a21ce3a20cd3a20ce3a6a21cf3a20" + "ce3a20cf3a6a21d03a20cf3a20d03a6a21d13a20d03a20d13a6a21d23a20d13a20d23a6a21d33a20d23a20d33a6a21" + "d43a20d33a20d43a6a21d53a20d43a20d53a6a21d63a20d53a20d63a6a21d73a20d63a20d73a6a21d83a20d73a20d8" + "3a6a21d93a20d83a20d93a6a21da3a20d93a20da3a6a21db3a20da3a20db3a6a21dc3a20db3a20dc3a6a21dd3a20dc" + "3a20dd3a6a21de3a20dd3a20de3a6a21df3a20de3a20df3a6a21e03a20df3a20e03a6a21e13a20e03a20e13a6a21e2" + "3a20e13a20e23a6a21e33a20e23a20e33a6a21e43a20e33a20e43a6a21e53a20e43a20e53a6a21e63a20e53a20e63a" + "6a21e73a20e63a20e73a6a21e83a20e73a20e83a6a21e93a20e83a20e93a6a21ea3a20e93a20ea3a6a21eb3a20ea3a" + "20eb3a6a21ec3a20eb3a20ec3a6a21ed3a20ec3a20ed3a6a21ee3a20ed3a20ee3a6a21ef3a20ee3a20ef3a6a21f03a" + "20ef3a20f03a6a21f13a20f03a20f13a6a21f23a20f13a20f23a6a21f33a20f23a20f33a6a21f43a20f33a20f43a6a" + "21f53a20f43a20f53a6a21f63a20f53a20f63a6a21f73a20f63a20f73a6a21f83a20f73a20f83a6a21f93a20f83a20" + "f93a6a21fa3a20f93a20fa3a6a21fb3a20fa3a20fb3a6a21fc3a20fb3a20fc3a6a21fd3a20fc3a20fd3a6a21fe3a20" + "fd3a20fe3a6a21ff3a20fe3a20ff3a6a21803b20ff3a20803b6a21813b20803b20813b6a21823b20813b20823b6a21" + "833b20823b20833b6a21843b20833b20843b6a21853b20843b20853b6a21863b20853b20863b6a21873b20863b2087" + "3b6a21883b20873b20883b6a21893b20883b20893b6a218a3b20893b208a3b6a218b3b208a3b208b3b6a218c3b208b" + "3b208c3b6a218d3b208c3b208d3b6a218e3b208d3b208e3b6a218f3b208e3b208f3b6a21903b208f3b20903b6a2191" + "3b20903b20913b6a21923b20913b20923b6a21933b20923b20933b6a21943b20933b20943b6a21953b20943b20953b" + "6a21963b20953b20963b6a21973b20963b20973b6a21983b20973b20983b6a21993b20983b20993b6a219a3b20993b" + "209a3b6a219b3b209a3b209b3b6a219c3b209b3b209c3b6a219d3b209c3b209d3b6a219e3b209d3b209e3b6a219f3b" + "209e3b209f3b6a21a03b209f3b20a03b6a21a13b20a03b20a13b6a21a23b20a13b20a23b6a21a33b20a23b20a33b6a" + "21a43b20a33b20a43b6a21a53b20a43b20a53b6a21a63b20a53b20a63b6a21a73b20a63b20a73b6a21a83b20a73b20" + "a83b6a21a93b20a83b20a93b6a21aa3b20a93b20aa3b6a21ab3b20aa3b20ab3b6a21ac3b20ab3b20ac3b6a21ad3b20" + "ac3b20ad3b6a21ae3b20ad3b20ae3b6a21af3b20ae3b20af3b6a21b03b20af3b20b03b6a21b13b20b03b20b13b6a21" + "b23b20b13b20b23b6a21b33b20b23b20b33b6a21b43b20b33b20b43b6a21b53b20b43b20b53b6a21b63b20b53b20b6" + "3b6a21b73b20b63b20b73b6a21b83b20b73b20b83b6a21b93b20b83b20b93b6a21ba3b20b93b20ba3b6a21bb3b20ba" + "3b20bb3b6a21bc3b20bb3b20bc3b6a21bd3b20bc3b20bd3b6a21be3b20bd3b20be3b6a21bf3b20be3b20bf3b6a21c0" + "3b20bf3b20c03b6a21c13b20c03b20c13b6a21c23b20c13b20c23b6a21c33b20c23b20c33b6a21c43b20c33b20c43b" + "6a21c53b20c43b20c53b6a21c63b20c53b20c63b6a21c73b20c63b20c73b6a21c83b20c73b20c83b6a21c93b20c83b" + "20c93b6a21ca3b20c93b20ca3b6a21cb3b20ca3b20cb3b6a21cc3b20cb3b20cc3b6a21cd3b20cc3b20cd3b6a21ce3b" + "20cd3b20ce3b6a21cf3b20ce3b20cf3b6a21d03b20cf3b20d03b6a21d13b20d03b20d13b6a21d23b20d13b20d23b6a" + "21d33b20d23b20d33b6a21d43b20d33b20d43b6a21d53b20d43b20d53b6a21d63b20d53b20d63b6a21d73b20d63b20" + "d73b6a21d83b20d73b20d83b6a21d93b20d83b20d93b6a21da3b20d93b20da3b6a21db3b20da3b20db3b6a21dc3b20" + "db3b20dc3b6a21dd3b20dc3b20dd3b6a21de3b20dd3b20de3b6a21df3b20de3b20df3b6a21e03b20df3b20e03b6a21" + "e13b20e03b20e13b6a21e23b20e13b20e23b6a21e33b20e23b20e33b6a21e43b20e33b20e43b6a21e53b20e43b20e5" + "3b6a21e63b20e53b20e63b6a21e73b20e63b20e73b6a21e83b20e73b20e83b6a21e93b20e83b20e93b6a21ea3b20e9" + "3b20ea3b6a21eb3b20ea3b20eb3b6a21ec3b20eb3b20ec3b6a21ed3b20ec3b20ed3b6a21ee3b20ed3b20ee3b6a21ef" + "3b20ee3b20ef3b6a21f03b20ef3b20f03b6a21f13b20f03b20f13b6a21f23b20f13b20f23b6a21f33b20f23b20f33b" + "6a21f43b20f33b20f43b6a21f53b20f43b20f53b6a21f63b20f53b20f63b6a21f73b20f63b20f73b6a21f83b20f73b" + "20f83b6a21f93b20f83b20f93b6a21fa3b20f93b20fa3b6a21fb3b20fa3b20fb3b6a21fc3b20fb3b20fc3b6a21fd3b" + "20fc3b20fd3b6a21fe3b20fd3b20fe3b6a21ff3b20fe3b20ff3b6a21803c20ff3b20803c6a21813c20803c20813c6a" + "21823c20813c20823c6a21833c20823c20833c6a21843c20833c20843c6a21853c20843c20853c6a21863c20853c20" + "863c6a21873c20863c20873c6a21883c20873c20883c6a21893c20883c20893c6a218a3c20893c208a3c6a218b3c20" + "8a3c208b3c6a218c3c208b3c208c3c6a218d3c208c3c208d3c6a218e3c208d3c208e3c6a218f3c208e3c208f3c6a21" + "903c208f3c20903c6a21913c20903c20913c6a21923c20913c20923c6a21933c20923c20933c6a21943c20933c2094" + "3c6a21953c20943c20953c6a21963c20953c20963c6a21973c20963c20973c6a21983c20973c20983c6a21993c2098" + "3c20993c6a219a3c20993c209a3c6a219b3c209a3c209b3c6a219c3c209b3c209c3c6a219d3c209c3c209d3c6a219e" + "3c209d3c209e3c6a219f3c209e3c209f3c6a21a03c209f3c20a03c6a21a13c20a03c20a13c6a21a23c20a13c20a23c" + "6a21a33c20a23c20a33c6a21a43c20a33c20a43c6a21a53c20a43c20a53c6a21a63c20a53c20a63c6a21a73c20a63c" + "20a73c6a21a83c20a73c20a83c6a21a93c20a83c20a93c6a21aa3c20a93c20aa3c6a21ab3c20aa3c20ab3c6a21ac3c" + "20ab3c20ac3c6a21ad3c20ac3c20ad3c6a21ae3c20ad3c20ae3c6a21af3c20ae3c20af3c6a21b03c20af3c20b03c6a" + "21b13c20b03c20b13c6a21b23c20b13c20b23c6a21b33c20b23c20b33c6a21b43c20b33c20b43c6a21b53c20b43c20" + "b53c6a21b63c20b53c20b63c6a21b73c20b63c20b73c6a21b83c20b73c20b83c6a21b93c20b83c20b93c6a21ba3c20" + "b93c20ba3c6a21bb3c20ba3c20bb3c6a21bc3c20bb3c20bc3c6a21bd3c20bc3c20bd3c6a21be3c20bd3c20be3c6a21" + "bf3c20be3c20bf3c6a21c03c20bf3c20c03c6a21c13c20c03c20c13c6a21c23c20c13c20c23c6a21c33c20c23c20c3" + "3c6a21c43c20c33c20c43c6a21c53c20c43c20c53c6a21c63c20c53c20c63c6a21c73c20c63c20c73c6a21c83c20c7" + "3c20c83c6a21c93c20c83c20c93c6a21ca3c20c93c20ca3c6a21cb3c20ca3c20cb3c6a21cc3c20cb3c20cc3c6a21cd" + "3c20cc3c20cd3c6a21ce3c20cd3c20ce3c6a21cf3c20ce3c20cf3c6a21d03c20cf3c20d03c6a21d13c20d03c20d13c" + "6a21d23c20d13c20d23c6a21d33c20d23c20d33c6a21d43c20d33c20d43c6a21d53c20d43c20d53c6a21d63c20d53c" + "20d63c6a21d73c20d63c20d73c6a21d83c20d73c20d83c6a21d93c20d83c20d93c6a21da3c20d93c20da3c6a21db3c" + "20da3c20db3c6a21dc3c20db3c20dc3c6a21dd3c20dc3c20dd3c6a21de3c20dd3c20de3c6a21df3c20de3c20df3c6a" + "21e03c20df3c20e03c6a21e13c20e03c20e13c6a21e23c20e13c20e23c6a21e33c20e23c20e33c6a21e43c20e33c20" + "e43c6a21e53c20e43c20e53c6a21e63c20e53c20e63c6a21e73c20e63c20e73c6a21e83c20e73c20e83c6a21e93c20" + "e83c20e93c6a21ea3c20e93c20ea3c6a21eb3c20ea3c20eb3c6a21ec3c20eb3c20ec3c6a21ed3c20ec3c20ed3c6a21" + "ee3c20ed3c20ee3c6a21ef3c20ee3c20ef3c6a21f03c20ef3c20f03c6a21f13c20f03c20f13c6a21f23c20f13c20f2" + "3c6a21f33c20f23c20f33c6a21f43c20f33c20f43c6a21f53c20f43c20f53c6a21f63c20f53c20f63c6a21f73c20f6" + "3c20f73c6a21f83c20f73c20f83c6a21f93c20f83c20f93c6a21fa3c20f93c20fa3c6a21fb3c20fa3c20fb3c6a21fc" + "3c20fb3c20fc3c6a21fd3c20fc3c20fd3c6a21fe3c20fd3c20fe3c6a21ff3c20fe3c20ff3c6a21803d20ff3c20803d" + "6a21813d20803d20813d6a21823d20813d20823d6a21833d20823d20833d6a21843d20833d20843d6a21853d20843d" + "20853d6a21863d20853d20863d6a21873d20863d20873d6a21883d20873d20883d6a21893d20883d20893d6a218a3d" + "20893d208a3d6a218b3d208a3d208b3d6a218c3d208b3d208c3d6a218d3d208c3d208d3d6a218e3d208d3d208e3d6a" + "218f3d208e3d208f3d6a21903d208f3d20903d6a21913d20903d20913d6a21923d20913d20923d6a21933d20923d20" + "933d6a21943d20933d20943d6a21953d20943d20953d6a21963d20953d20963d6a21973d20963d20973d6a21983d20" + "973d20983d6a21993d20983d20993d6a219a3d20993d209a3d6a219b3d209a3d209b3d6a219c3d209b3d209c3d6a21" + "9d3d209c3d209d3d6a219e3d209d3d209e3d6a219f3d209e3d209f3d6a21a03d209f3d20a03d6a21a13d20a03d20a1" + "3d6a21a23d20a13d20a23d6a21a33d20a23d20a33d6a21a43d20a33d20a43d6a21a53d20a43d20a53d6a21a63d20a5" + "3d20a63d6a21a73d20a63d20a73d6a21a83d20a73d20a83d6a21a93d20a83d20a93d6a21aa3d20a93d20aa3d6a21ab" + "3d20aa3d20ab3d6a21ac3d20ab3d20ac3d6a21ad3d20ac3d20ad3d6a21ae3d20ad3d20ae3d6a21af3d20ae3d20af3d" + "6a21b03d20af3d20b03d6a21b13d20b03d20b13d6a21b23d20b13d20b23d6a21b33d20b23d20b33d6a21b43d20b33d" + "20b43d6a21b53d20b43d20b53d6a21b63d20b53d20b63d6a21b73d20b63d20b73d6a21b83d20b73d20b83d6a21b93d" + "20b83d20b93d6a21ba3d20b93d20ba3d6a21bb3d20ba3d20bb3d6a21bc3d20bb3d20bc3d6a21bd3d20bc3d20bd3d6a" + "21be3d20bd3d20be3d6a21bf3d20be3d20bf3d6a21c03d20bf3d20c03d6a21c13d20c03d20c13d6a21c23d20c13d20" + "c23d6a21c33d20c23d20c33d6a21c43d20c33d20c43d6a21c53d20c43d20c53d6a21c63d20c53d20c63d6a21c73d20" + "c63d20c73d6a21c83d20c73d20c83d6a21c93d20c83d20c93d6a21ca3d20c93d20ca3d6a21cb3d20ca3d20cb3d6a21" + "cc3d20cb3d20cc3d6a21cd3d20cc3d20cd3d6a21ce3d20cd3d20ce3d6a21cf3d20ce3d20cf3d6a21d03d20cf3d20d0" + "3d6a21d13d20d03d20d13d6a21d23d20d13d20d23d6a21d33d20d23d20d33d6a21d43d20d33d20d43d6a21d53d20d4" + "3d20d53d6a21d63d20d53d20d63d6a21d73d20d63d20d73d6a21d83d20d73d20d83d6a21d93d20d83d20d93d6a21da" + "3d20d93d20da3d6a21db3d20da3d20db3d6a21dc3d20db3d20dc3d6a21dd3d20dc3d20dd3d6a21de3d20dd3d20de3d" + "6a21df3d20de3d20df3d6a21e03d20df3d20e03d6a21e13d20e03d20e13d6a21e23d20e13d20e23d6a21e33d20e23d" + "20e33d6a21e43d20e33d20e43d6a21e53d20e43d20e53d6a21e63d20e53d20e63d6a21e73d20e63d20e73d6a21e83d" + "20e73d20e83d6a21e93d20e83d20e93d6a21ea3d20e93d20ea3d6a21eb3d20ea3d20eb3d6a21ec3d20eb3d20ec3d6a" + "21ed3d20ec3d20ed3d6a21ee3d20ed3d20ee3d6a21ef3d20ee3d20ef3d6a21f03d20ef3d20f03d6a21f13d20f03d20" + "f13d6a21f23d20f13d20f23d6a21f33d20f23d20f33d6a21f43d20f33d20f43d6a21f53d20f43d20f53d6a21f63d20" + "f53d20f63d6a21f73d20f63d20f73d6a21f83d20f73d20f83d6a21f93d20f83d20f93d6a21fa3d20f93d20fa3d6a21" + "fb3d20fa3d20fb3d6a21fc3d20fb3d20fc3d6a21fd3d20fc3d20fd3d6a21fe3d20fd3d20fe3d6a21ff3d20fe3d20ff" + "3d6a21803e20ff3d20803e6a21813e20803e20813e6a21823e20813e20823e6a21833e20823e20833e6a21843e2083" + "3e20843e6a21853e20843e20853e6a21863e20853e20863e6a21873e20863e20873e6a21883e20873e20883e6a2189" + "3e20883e20893e6a218a3e20893e208a3e6a218b3e208a3e208b3e6a218c3e208b3e208c3e6a218d3e208c3e208d3e" + "6a218e3e208d3e208e3e6a218f3e208e3e208f3e6a21903e208f3e20903e6a21913e20903e20913e6a21923e20913e" + "20923e6a21933e20923e20933e6a21943e20933e20943e6a21953e20943e20953e6a21963e20953e20963e6a21973e" + "20963e20973e6a21983e20973e20983e6a21993e20983e20993e6a219a3e20993e209a3e6a219b3e209a3e209b3e6a" + "219c3e209b3e209c3e6a219d3e209c3e209d3e6a219e3e209d3e209e3e6a219f3e209e3e209f3e6a21a03e209f3e20" + "a03e6a21a13e20a03e20a13e6a21a23e20a13e20a23e6a21a33e20a23e20a33e6a21a43e20a33e20a43e6a21a53e20" + "a43e20a53e6a21a63e20a53e20a63e6a21a73e20a63e20a73e6a21a83e20a73e20a83e6a21a93e20a83e20a93e6a21" + "aa3e20a93e20aa3e6a21ab3e20aa3e20ab3e6a21ac3e20ab3e20ac3e6a21ad3e20ac3e20ad3e6a21ae3e20ad3e20ae" + "3e6a21af3e20ae3e20af3e6a21b03e20af3e20b03e6a21b13e20b03e20b13e6a21b23e20b13e20b23e6a21b33e20b2" + "3e20b33e6a21b43e20b33e20b43e6a21b53e20b43e20b53e6a21b63e20b53e20b63e6a21b73e20b63e20b73e6a21b8" + "3e20b73e20b83e6a21b93e20b83e20b93e6a21ba3e20b93e20ba3e6a21bb3e20ba3e20bb3e6a21bc3e20bb3e20bc3e" + "6a21bd3e20bc3e20bd3e6a21be3e20bd3e20be3e6a21bf3e20be3e20bf3e6a21c03e20bf3e20c03e6a21c13e20c03e" + "20c13e6a21c23e20c13e20c23e6a21c33e20c23e20c33e6a21c43e20c33e20c43e6a21c53e20c43e20c53e6a21c63e" + "20c53e20c63e6a21c73e20c63e20c73e6a21c83e20c73e20c83e6a21c93e20c83e20c93e6a21ca3e20c93e20ca3e6a" + "21cb3e20ca3e20cb3e6a21cc3e20cb3e20cc3e6a21cd3e20cc3e20cd3e6a21ce3e20cd3e20ce3e6a21cf3e20ce3e20" + "cf3e6a21d03e20cf3e20d03e6a21d13e20d03e20d13e6a21d23e20d13e20d23e6a21d33e20d23e20d33e6a21d43e20" + "d33e20d43e6a21d53e20d43e20d53e6a21d63e20d53e20d63e6a21d73e20d63e20d73e6a21d83e20d73e20d83e6a21" + "d93e20d83e20d93e6a21da3e20d93e20da3e6a21db3e20da3e20db3e6a21dc3e20db3e20dc3e6a21dd3e20dc3e20dd" + "3e6a21de3e20dd3e20de3e6a21df3e20de3e20df3e6a21e03e20df3e20e03e6a21e13e20e03e20e13e6a21e23e20e1" + "3e20e23e6a21e33e20e23e20e33e6a21e43e20e33e20e43e6a21e53e20e43e20e53e6a21e63e20e53e20e63e6a21e7" + "3e20e63e20e73e6a21e83e20e73e20e83e6a21e93e20e83e20e93e6a21ea3e20e93e20ea3e6a21eb3e20ea3e20eb3e" + "6a21ec3e20eb3e20ec3e6a21ed3e20ec3e20ed3e6a21ee3e20ed3e20ee3e6a21ef3e20ee3e20ef3e6a21f03e20ef3e" + "20f03e6a21f13e20f03e20f13e6a21f23e20f13e20f23e6a21f33e20f23e20f33e6a21f43e20f33e20f43e6a21f53e" + "20f43e20f53e6a21f63e20f53e20f63e6a21f73e20f63e20f73e6a21f83e20f73e20f83e6a21f93e20f83e20f93e6a" + "21fa3e20f93e20fa3e6a21fb3e20fa3e20fb3e6a21fc3e20fb3e20fc3e6a21fd3e20fc3e20fd3e6a21fe3e20fd3e20" + "fe3e6a21ff3e20fe3e20ff3e6a21803f20ff3e20803f6a21813f20803f20813f6a21823f20813f20823f6a21833f20" + "823f20833f6a21843f20833f20843f6a21853f20843f20853f6a21863f20853f20863f6a21873f20863f20873f6a21" + "883f20873f20883f6a21893f20883f20893f6a218a3f20893f208a3f6a218b3f208a3f208b3f6a218c3f208b3f208c" + "3f6a218d3f208c3f208d3f6a218e3f208d3f208e3f6a218f3f208e3f208f3f6a21903f208f3f20903f6a21913f2090" + "3f20913f6a21923f20913f20923f6a21933f20923f20933f6a21943f20933f20943f6a21953f20943f20953f6a2196" + "3f20953f20963f6a21973f20963f20973f6a21983f20973f20983f6a21993f20983f20993f6a219a3f20993f209a3f" + "6a219b3f209a3f209b3f6a219c3f209b3f209c3f6a219d3f209c3f209d3f6a219e3f209d3f209e3f6a219f3f209e3f" + "209f3f6a21a03f209f3f20a03f6a21a13f20a03f20a13f6a21a23f20a13f20a23f6a21a33f20a23f20a33f6a21a43f" + "20a33f20a43f6a21a53f20a43f20a53f6a21a63f20a53f20a63f6a21a73f20a63f20a73f6a21a83f20a73f20a83f6a" + "21a93f20a83f20a93f6a21aa3f20a93f20aa3f6a21ab3f20aa3f20ab3f6a21ac3f20ab3f20ac3f6a21ad3f20ac3f20" + "ad3f6a21ae3f20ad3f20ae3f6a21af3f20ae3f20af3f6a21b03f20af3f20b03f6a21b13f20b03f20b13f6a21b23f20" + "b13f20b23f6a21b33f20b23f20b33f6a21b43f20b33f20b43f6a21b53f20b43f20b53f6a21b63f20b53f20b63f6a21" + "b73f20b63f20b73f6a21b83f20b73f20b83f6a21b93f20b83f20b93f6a21ba3f20b93f20ba3f6a21bb3f20ba3f20bb" + "3f6a21bc3f20bb3f20bc3f6a21bd3f20bc3f20bd3f6a21be3f20bd3f20be3f6a21bf3f20be3f20bf3f6a21c03f20bf" + "3f20c03f6a21c13f20c03f20c13f6a21c23f20c13f20c23f6a21c33f20c23f20c33f6a21c43f20c33f20c43f6a21c5" + "3f20c43f20c53f6a21c63f20c53f20c63f6a21c73f20c63f20c73f6a21c83f20c73f20c83f6a21c93f20c83f20c93f" + "6a21ca3f20c93f20ca3f6a21cb3f20ca3f20cb3f6a21cc3f20cb3f20cc3f6a21cd3f20cc3f20cd3f6a21ce3f20cd3f" + "20ce3f6a21cf3f20ce3f20cf3f6a21d03f20cf3f20d03f6a21d13f20d03f20d13f6a21d23f20d13f20d23f6a21d33f" + "20d23f20d33f6a21d43f20d33f20d43f6a21d53f20d43f20d53f6a21d63f20d53f20d63f6a21d73f20d63f20d73f6a" + "21d83f20d73f20d83f6a21d93f20d83f20d93f6a21da3f20d93f20da3f6a21db3f20da3f20db3f6a21dc3f20db3f20" + "dc3f6a21dd3f20dc3f20dd3f6a21de3f20dd3f20de3f6a21df3f20de3f20df3f6a21e03f20df3f20e03f6a21e13f20" + "e03f20e13f6a21e23f20e13f20e23f6a21e33f20e23f20e33f6a21e43f20e33f20e43f6a21e53f20e43f20e53f6a21" + "e63f20e53f20e63f6a21e73f20e63f20e73f6a21e83f20e73f20e83f6a21e93f20e83f20e93f6a21ea3f20e93f20ea" + "3f6a21eb3f20ea3f20eb3f6a21ec3f20eb3f20ec3f6a21ed3f20ec3f20ed3f6a21ee3f20ed3f20ee3f6a21ef3f20ee" + "3f20ef3f6a21f03f20ef3f20f03f6a21f13f20f03f20f13f6a21f23f20f13f20f23f6a21f33f20f23f20f33f6a21f4" + "3f20f33f20f43f6a21f53f20f43f20f53f6a21f63f20f53f20f63f6a21f73f20f63f20f73f6a21f83f20f73f20f83f" + "6a21f93f20f83f20f93f6a21fa3f20f93f20fa3f6a21fb3f20fa3f20fb3f6a21fc3f20fb3f20fc3f6a21fd3f20fc3f" + "20fd3f6a21fe3f20fd3f20fe3f6a21ff3f20fe3f20ff3f6a21804020ff3f2080406a2181402080402081406a218240" + "2081402082406a2183402082402083406a2184402083402084406a2185402084402085406a2186402085402086406a" + "2187402086402087406a2188402087402088406a2189402088402089406a218a40208940208a406a218b40208a4020" + "8b406a218c40208b40208c406a218d40208c40208d406a218e40208d40208e406a218f40208e40208f406a21904020" + "8f402090406a2191402090402091406a2192402091402092406a2193402092402093406a2194402093402094406a21" + "95402094402095406a2196402095402096406a2197402096402097406a2198402097402098406a2199402098402099" + "406a219a40209940209a406a219b40209a40209b406a219c40209b40209c406a219d40209c40209d406a219e40209d" + "40209e406a219f40209e40209f406a21a040209f4020a0406a21a14020a04020a1406a21a24020a14020a2406a21a3" + "4020a24020a3406a21a44020a34020a4406a21a54020a44020a5406a21a64020a54020a6406a21a74020a64020a740" + "6a21a84020a74020a8406a21a94020a84020a9406a21aa4020a94020aa406a21ab4020aa4020ab406a21ac4020ab40" + "20ac406a21ad4020ac4020ad406a21ae4020ad4020ae406a21af4020ae4020af406a21b04020af4020b0406a21b140" + "20b04020b1406a21b24020b14020b2406a21b34020b24020b3406a21b44020b34020b4406a21b54020b44020b5406a" + "21b64020b54020b6406a21b74020b64020b7406a21b84020b74020b8406a21b94020b84020b9406a21ba4020b94020" + "ba406a21bb4020ba4020bb406a21bc4020bb4020bc406a21bd4020bc4020bd406a21be4020bd4020be406a21bf4020" + "be4020bf406a21c04020bf4020c0406a21c14020c04020c1406a21c24020c14020c2406a21c34020c24020c3406a21" + "c44020c34020c4406a21c54020c44020c5406a21c64020c54020c6406a21c74020c64020c7406a21c84020c74020c8" + "406a21c94020c84020c9406a21ca4020c94020ca406a21cb4020ca4020cb406a21cc4020cb4020cc406a21cd4020cc" + "4020cd406a21ce4020cd4020ce406a21cf4020ce4020cf406a21d04020cf4020d0406a21d14020d04020d1406a21d2" + "4020d14020d2406a21d34020d24020d3406a21d44020d34020d4406a21d54020d44020d5406a21d64020d54020d640" + "6a21d74020d64020d7406a21d84020d74020d8406a21d94020d84020d9406a21da4020d94020da406a21db4020da40" + "20db406a21dc4020db4020dc406a21dd4020dc4020dd406a21de4020dd4020de406a21df4020de4020df406a21e040" + "20df4020e0406a21e14020e04020e1406a21e24020e14020e2406a21e34020e24020e3406a21e44020e34020e4406a" + "21e54020e44020e5406a21e64020e54020e6406a21e74020e64020e7406a21e84020e74020e8406a21e94020e84020" + "e9406a21ea4020e94020ea406a21eb4020ea4020eb406a21ec4020eb4020ec406a21ed4020ec4020ed406a21ee4020" + "ed4020ee406a21ef4020ee4020ef406a21f04020ef4020f0406a21f14020f04020f1406a21f24020f14020f2406a21" + "f34020f24020f3406a21f44020f34020f4406a21f54020f44020f5406a21f64020f54020f6406a21f74020f64020f7" + "406a21f84020f74020f8406a21f94020f84020f9406a21fa4020f94020fa406a21fb4020fa4020fb406a21fc4020fb" + "4020fc406a21fd4020fc4020fd406a21fe4020fd4020fe406a21ff4020fe4020ff406a21804120ff402080416a2181" + "412080412081416a2182412081412082416a2183412082412083416a2184412083412084416a218541208441208541" + "6a2186412085412086416a2187412086412087416a2188412087412088416a2189412088412089416a218a41208941" + "208a416a218b41208a41208b416a218c41208b41208c416a218d41208c41208d416a218e41208d41208e416a218f41" + "208e41208f416a219041208f412090416a2191412090412091416a2192412091412092416a2193412092412093416a" + "2194412093412094416a2195412094412095416a2196412095412096416a2197412096412097416a21984120974120" + "98416a2199412098412099416a219a41209941209a416a219b41209a41209b416a219c41209b41209c416a219d4120" + "9c41209d416a219e41209d41209e416a219f41209e41209f416a21a041209f4120a0416a21a14120a04120a1416a21" + "a24120a14120a2416a21a34120a24120a3416a21a44120a34120a4416a21a54120a44120a5416a21a64120a54120a6" + "416a21a74120a64120a7416a21a84120a74120a8416a21a94120a84120a9416a21aa4120a94120aa416a21ab4120aa" + "4120ab416a21ac4120ab4120ac416a21ad4120ac4120ad416a21ae4120ad4120ae416a21af4120ae4120af416a21b0" + "4120af4120b0416a21b14120b04120b1416a21b24120b14120b2416a21b34120b24120b3416a21b44120b34120b441" + "6a21b54120b44120b5416a21b64120b54120b6416a21b74120b64120b7416a21b84120b74120b8416a21b94120b841" + "20b9416a21ba4120b94120ba416a21bb4120ba4120bb416a21bc4120bb4120bc416a21bd4120bc4120bd416a21be41" + "20bd4120be416a21bf4120be4120bf416a21c04120bf4120c0416a21c14120c04120c1416a21c24120c14120c2416a" + "21c34120c24120c3416a21c44120c34120c4416a21c54120c44120c5416a21c64120c54120c6416a21c74120c64120" + "c7416a21c84120c74120c8416a21c94120c84120c9416a21ca4120c94120ca416a21cb4120ca4120cb416a21cc4120" + "cb4120cc416a21cd4120cc4120cd416a21ce4120cd4120ce416a21cf4120ce4120cf416a21d04120cf4120d0416a21" + "d14120d04120d1416a21d24120d14120d2416a21d34120d24120d3416a21d44120d34120d4416a21d54120d44120d5" + "416a21d64120d54120d6416a21d74120d64120d7416a21d84120d74120d8416a21d94120d84120d9416a21da4120d9" + "4120da416a21db4120da4120db416a21dc4120db4120dc416a21dd4120dc4120dd416a21de4120dd4120de416a21df" + "4120de4120df416a21e04120df4120e0416a21e14120e04120e1416a21e24120e14120e2416a21e34120e24120e341" + "6a21e44120e34120e4416a21e54120e44120e5416a21e64120e54120e6416a21e74120e64120e7416a21e84120e741" + "20e8416a21e94120e84120e9416a21ea4120e94120ea416a21eb4120ea4120eb416a21ec4120eb4120ec416a21ed41" + "20ec4120ed416a21ee4120ed4120ee416a21ef4120ee4120ef416a21f04120ef4120f0416a21f14120f04120f1416a" + "21f24120f14120f2416a21f34120f24120f3416a21f44120f34120f4416a21f54120f44120f5416a21f64120f54120" + "f6416a21f74120f64120f7416a21f84120f74120f8416a21f94120f84120f9416a21fa4120f94120fa416a21fb4120" + "fa4120fb416a21fc4120fb4120fc416a21fd4120fc4120fd416a21fe4120fd4120fe416a21ff4120fe4120ff416a21" + "804220ff412080426a2181422080422081426a2182422081422082426a2183422082422083426a2184422083422084" + "426a2185422084422085426a2186422085422086426a2187422086422087426a2188422087422088426a2189422088" + "422089426a218a42208942208a426a218b42208a42208b426a218c42208b42208c426a218d42208c42208d426a218e" + "42208d42208e426a218f42208e42208f426a219042208f422090426a2191422090422091426a219242209142209242" + "6a2193422092422093426a2194422093422094426a2195422094422095426a2196422095422096426a219742209642" + "2097426a2198422097422098426a2199422098422099426a219a42209942209a426a219b42209a42209b426a219c42" + "209b42209c426a219d42209c42209d426a219e42209d42209e426a219f42209e42209f426a21a042209f4220a0426a" + "21a14220a04220a1426a21a24220a14220a2426a21a34220a24220a3426a21a44220a34220a4426a21a54220a44220" + "a5426a21a64220a54220a6426a21a74220a64220a7426a21a84220a74220a8426a21a94220a84220a9426a21aa4220" + "a94220aa426a21ab4220aa4220ab426a21ac4220ab4220ac426a21ad4220ac4220ad426a21ae4220ad4220ae426a21" + "af4220ae4220af426a21b04220af4220b0426a21b14220b04220b1426a21b24220b14220b2426a21b34220b24220b3" + "426a21b44220b34220b4426a21b54220b44220b5426a21b64220b54220b6426a21b74220b64220b7426a21b84220b7" + "4220b8426a21b94220b84220b9426a21ba4220b94220ba426a21bb4220ba4220bb426a21bc4220bb4220bc426a21bd" + "4220bc4220bd426a21be4220bd4220be426a21bf4220be4220bf426a21c04220bf4220c0426a21c14220c04220c142" + "6a21c24220c14220c2426a21c34220c24220c3426a21c44220c34220c4426a21c54220c44220c5426a21c64220c542" + "20c6426a21c74220c64220c7426a21c84220c74220c8426a21c94220c84220c9426a21ca4220c94220ca426a21cb42" + "20ca4220cb426a21cc4220cb4220cc426a21cd4220cc4220cd426a21ce4220cd4220ce426a21cf4220ce4220cf426a" + "21d04220cf4220d0426a21d14220d04220d1426a21d24220d14220d2426a21d34220d24220d3426a21d44220d34220" + "d4426a21d54220d44220d5426a21d64220d54220d6426a21d74220d64220d7426a21d84220d74220d8426a21d94220" + "d84220d9426a21da4220d94220da426a21db4220da4220db426a21dc4220db4220dc426a21dd4220dc4220dd426a21" + "de4220dd4220de426a21df4220de4220df426a21e04220df4220e0426a21e14220e04220e1426a21e24220e14220e2" + "426a21e34220e24220e3426a21e44220e34220e4426a21e54220e44220e5426a21e64220e54220e6426a21e74220e6" + "4220e7426a21e84220e74220e8426a21e94220e84220e9426a21ea4220e94220ea426a21eb4220ea4220eb426a21ec" + "4220eb4220ec426a21ed4220ec4220ed426a21ee4220ed4220ee426a21ef4220ee4220ef426a21f04220ef4220f042" + "6a21f14220f04220f1426a21f24220f14220f2426a21f34220f24220f3426a21f44220f34220f4426a21f54220f442" + "20f5426a21f64220f54220f6426a21f74220f64220f7426a21f84220f74220f8426a21f94220f84220f9426a21fa42" + "20f94220fa426a21fb4220fa4220fb426a21fc4220fb4220fc426a21fd4220fc4220fd426a21fe4220fd4220fe426a" + "21ff4220fe4220ff426a21804320ff422080436a2181432080432081436a2182432081432082436a21834320824320" + "83436a2184432083432084436a2185432084432085436a2186432085432086436a2187432086432087436a21884320" + "87432088436a2189432088432089436a218a43208943208a436a218b43208a43208b436a218c43208b43208c436a21" + "8d43208c43208d436a218e43208d43208e436a218f43208e43208f436a219043208f432090436a2191432090432091" + "436a2192432091432092436a2193432092432093436a2194432093432094436a2195432094432095436a2196432095" + "432096436a2197432096432097436a2198432097432098436a2199432098432099436a219a43209943209a436a219b" + "43209a43209b436a219c43209b43209c436a219d43209c43209d436a219e43209d43209e436a219f43209e43209f43" + "6a21a043209f4320a0436a21a14320a04320a1436a21a24320a14320a2436a21a34320a24320a3436a21a44320a343" + "20a4436a21a54320a44320a5436a21a64320a54320a6436a21a74320a64320a7436a21a84320a74320a8436a21a943" + "20a84320a9436a21aa4320a94320aa436a21ab4320aa4320ab436a21ac4320ab4320ac436a21ad4320ac4320ad436a" + "21ae4320ad4320ae436a21af4320ae4320af436a21b04320af4320b0436a21b14320b04320b1436a21b24320b14320" + "b2436a21b34320b24320b3436a21b44320b34320b4436a21b54320b44320b5436a21b64320b54320b6436a21b74320" + "b64320b7436a21b84320b74320b8436a21b94320b84320b9436a21ba4320b94320ba436a21bb4320ba4320bb436a21" + "bc4320bb4320bc436a21bd4320bc4320bd436a21be4320bd4320be436a21bf4320be4320bf436a21c04320bf4320c0" + "436a21c14320c04320c1436a21c24320c14320c2436a21c34320c24320c3436a21c44320c34320c4436a21c54320c4" + "4320c5436a21c64320c54320c6436a21c74320c64320c7436a21c84320c74320c8436a21c94320c84320c9436a21ca" + "4320c94320ca436a21cb4320ca4320cb436a21cc4320cb4320cc436a21cd4320cc4320cd436a21ce4320cd4320ce43" + "6a21cf4320ce4320cf436a21d04320cf4320d0436a21d14320d04320d1436a21d24320d14320d2436a21d34320d243" + "20d3436a21d44320d34320d4436a21d54320d44320d5436a21d64320d54320d6436a21d74320d64320d7436a21d843" + "20d74320d8436a21d94320d84320d9436a21da4320d94320da436a21db4320da4320db436a21dc4320db4320dc436a" + "21dd4320dc4320dd436a21de4320dd4320de436a21df4320de4320df436a21e04320df4320e0436a21e14320e04320" + "e1436a21e24320e14320e2436a21e34320e24320e3436a21e44320e34320e4436a21e54320e44320e5436a21e64320" + "e54320e6436a21e74320e64320e7436a21e84320e74320e8436a21e94320e84320e9436a21ea4320e94320ea436a21" + "eb4320ea4320eb436a21ec4320eb4320ec436a21ed4320ec4320ed436a21ee4320ed4320ee436a21ef4320ee4320ef" + "436a21f04320ef4320f0436a21f14320f04320f1436a21f24320f14320f2436a21f34320f24320f3436a21f44320f3" + "4320f4436a21f54320f44320f5436a21f64320f54320f6436a21f74320f64320f7436a21f84320f74320f8436a21f9" + "4320f84320f9436a21fa4320f94320fa436a21fb4320fa4320fb436a21fc4320fb4320fc436a21fd4320fc4320fd43" + "6a21fe4320fd4320fe436a21ff4320fe4320ff436a21804420ff432080446a2181442080442081446a218244208144" + "2082446a2183442082442083446a2184442083442084446a2185442084442085446a2186442085442086446a218744" + "2086442087446a2188442087442088446a2189442088442089446a218a44208944208a446a218b44208a44208b446a" + "218c44208b44208c446a218d44208c44208d446a218e44208d44208e446a218f44208e44208f446a219044208f4420" + "90446a2191442090442091446a2192442091442092446a2193442092442093446a2194442093442094446a21954420" + "94442095446a2196442095442096446a2197442096442097446a2198442097442098446a2199442098442099446a21" + "9a44209944209a446a219b44209a44209b446a219c44209b44209c446a219d44209c44209d446a219e44209d44209e" + "446a219f44209e44209f446a21a044209f4420a0446a21a14420a04420a1446a21a24420a14420a2446a21a34420a2" + "4420a3446a21a44420a34420a4446a21a54420a44420a5446a21a64420a54420a6446a21a74420a64420a7446a21a8" + "4420a74420a8446a21a94420a84420a9446a21aa4420a94420aa446a21ab4420aa4420ab446a21ac4420ab4420ac44" + "6a21ad4420ac4420ad446a21ae4420ad4420ae446a21af4420ae4420af446a21b04420af4420b0446a21b14420b044" + "20b1446a21b24420b14420b2446a21b34420b24420b3446a21b44420b34420b4446a21b54420b44420b5446a21b644" + "20b54420b6446a21b74420b64420b7446a21b84420b74420b8446a21b94420b84420b9446a21ba4420b94420ba446a" + "21bb4420ba4420bb446a21bc4420bb4420bc446a21bd4420bc4420bd446a21be4420bd4420be446a21bf4420be4420" + "bf446a21c04420bf4420c0446a21c14420c04420c1446a21c24420c14420c2446a21c34420c24420c3446a21c44420" + "c34420c4446a21c54420c44420c5446a21c64420c54420c6446a21c74420c64420c7446a21c84420c74420c8446a21" + "c94420c84420c9446a21ca4420c94420ca446a21cb4420ca4420cb446a21cc4420cb4420cc446a21cd4420cc4420cd" + "446a21ce4420cd4420ce446a21cf4420ce4420cf446a21d04420cf4420d0446a21d14420d04420d1446a21d24420d1" + "4420d2446a21d34420d24420d3446a21d44420d34420d4446a21d54420d44420d5446a21d64420d54420d6446a21d7" + "4420d64420d7446a21d84420d74420d8446a21d94420d84420d9446a21da4420d94420da446a21db4420da4420db44" + "6a21dc4420db4420dc446a21dd4420dc4420dd446a21de4420dd4420de446a21df4420de4420df446a21e04420df44" + "20e0446a21e14420e04420e1446a21e24420e14420e2446a21e34420e24420e3446a21e44420e34420e4446a21e544" + "20e44420e5446a21e64420e54420e6446a21e74420e64420e7446a21e84420e74420e8446a21e94420e84420e9446a" + "21ea4420e94420ea446a21eb4420ea4420eb446a21ec4420eb4420ec446a21ed4420ec4420ed446a21ee4420ed4420" + "ee446a21ef4420ee4420ef446a21f04420ef4420f0446a21f14420f04420f1446a21f24420f14420f2446a21f34420" + "f24420f3446a21f44420f34420f4446a21f54420f44420f5446a21f64420f54420f6446a21f74420f64420f7446a21" + "f84420f74420f8446a21f94420f84420f9446a21fa4420f94420fa446a21fb4420fa4420fb446a21fc4420fb4420fc" + "446a21fd4420fc4420fd446a21fe4420fd4420fe446a21ff4420fe4420ff446a21804520ff442080456a2181452080" + "452081456a2182452081452082456a2183452082452083456a2184452083452084456a2185452084452085456a2186" + "452085452086456a2187452086452087456a2188452087452088456a2189452088452089456a218a45208945208a45" + "6a218b45208a45208b456a218c45208b45208c456a218d45208c45208d456a218e45208d45208e456a218f45208e45" + "208f456a219045208f452090456a2191452090452091456a2192452091452092456a2193452092452093456a219445" + "2093452094456a2195452094452095456a2196452095452096456a2197452096452097456a2198452097452098456a" + "2199452098452099456a219a45209945209a456a219b45209a45209b456a219c45209b45209c456a219d45209c4520" + "9d456a219e45209d45209e456a219f45209e45209f456a21a045209f4520a0456a21a14520a04520a1456a21a24520" + "a14520a2456a21a34520a24520a3456a21a44520a34520a4456a21a54520a44520a5456a21a64520a54520a6456a21" + "a74520a64520a7456a21a84520a74520a8456a21a94520a84520a9456a21aa4520a94520aa456a21ab4520aa4520ab" + "456a21ac4520ab4520ac456a21ad4520ac4520ad456a21ae4520ad4520ae456a21af4520ae4520af456a21b04520af" + "4520b0456a21b14520b04520b1456a21b24520b14520b2456a21b34520b24520b3456a21b44520b34520b4456a21b5" + "4520b44520b5456a21b64520b54520b6456a21b74520b64520b7456a21b84520b74520b8456a21b94520b84520b945" + "6a21ba4520b94520ba456a21bb4520ba4520bb456a21bc4520bb4520bc456a21bd4520bc4520bd456a21be4520bd45" + "20be456a21bf4520be4520bf456a21c04520bf4520c0456a21c14520c04520c1456a21c24520c14520c2456a21c345" + "20c24520c3456a21c44520c34520c4456a21c54520c44520c5456a21c64520c54520c6456a21c74520c64520c7456a" + "21c84520c74520c8456a21c94520c84520c9456a21ca4520c94520ca456a21cb4520ca4520cb456a21cc4520cb4520" + "cc456a21cd4520cc4520cd456a21ce4520cd4520ce456a21cf4520ce4520cf456a21d04520cf4520d0456a21d14520" + "d04520d1456a21d24520d14520d2456a21d34520d24520d3456a21d44520d34520d4456a21d54520d44520d5456a21" + "d64520d54520d6456a21d74520d64520d7456a21d84520d74520d8456a21d94520d84520d9456a21da4520d94520da" + "456a21db4520da4520db456a21dc4520db4520dc456a21dd4520dc4520dd456a21de4520dd4520de456a21df4520de" + "4520df456a21e04520df4520e0456a21e14520e04520e1456a21e24520e14520e2456a21e34520e24520e3456a21e4" + "4520e34520e4456a21e54520e44520e5456a21e64520e54520e6456a21e74520e64520e7456a21e84520e74520e845" + "6a21e94520e84520e9456a21ea4520e94520ea456a21eb4520ea4520eb456a21ec4520eb4520ec456a21ed4520ec45" + "20ed456a21ee4520ed4520ee456a21ef4520ee4520ef456a21f04520ef4520f0456a21f14520f04520f1456a21f245" + "20f14520f2456a21f34520f24520f3456a21f44520f34520f4456a21f54520f44520f5456a21f64520f54520f6456a" + "21f74520f64520f7456a21f84520f74520f8456a21f94520f84520f9456a21fa4520f94520fa456a21fb4520fa4520" + "fb456a21fc4520fb4520fc456a21fd4520fc4520fd456a21fe4520fd4520fe456a21ff4520fe4520ff456a21804620" + "ff452080466a2181462080462081466a2182462081462082466a2183462082462083466a2184462083462084466a21" + "85462084462085466a2186462085462086466a2187462086462087466a2188462087462088466a2189462088462089" + "466a218a46208946208a466a218b46208a46208b466a218c46208b46208c466a218d46208c46208d466a218e46208d" + "46208e466a218f46208e46208f466a219046208f462090466a2191462090462091466a2192462091462092466a2193" + "462092462093466a2194462093462094466a2195462094462095466a2196462095462096466a219746209646209746" + "6a2198462097462098466a2199462098462099466a219a46209946209a466a219b46209a46209b466a219c46209b46" + "209c466a219d46209c46209d466a219e46209d46209e466a219f46209e46209f466a21a046209f4620a0466a21a146" + "20a04620a1466a21a24620a14620a2466a21a34620a24620a3466a21a44620a34620a4466a21a54620a44620a5466a" + "21a64620a54620a6466a21a74620a64620a7466a21a84620a74620a8466a21a94620a84620a9466a21aa4620a94620" + "aa466a21ab4620aa4620ab466a21ac4620ab4620ac466a21ad4620ac4620ad466a21ae4620ad4620ae466a21af4620" + "ae4620af466a21b04620af4620b0466a21b14620b04620b1466a21b24620b14620b2466a21b34620b24620b3466a21" + "b44620b34620b4466a21b54620b44620b5466a21b64620b54620b6466a21b74620b64620b7466a21b84620b74620b8" + "466a21b94620b84620b9466a21ba4620b94620ba466a21bb4620ba4620bb466a21bc4620bb4620bc466a21bd4620bc" + "4620bd466a21be4620bd4620be466a21bf4620be4620bf466a21c04620bf4620c0466a21c14620c04620c1466a21c2" + "4620c14620c2466a21c34620c24620c3466a21c44620c34620c4466a21c54620c44620c5466a21c64620c54620c646" + "6a21c74620c64620c7466a21c84620c74620c8466a21c94620c84620c9466a21ca4620c94620ca466a21cb4620ca46" + "20cb466a21cc4620cb4620cc466a21cd4620cc4620cd466a21ce4620cd4620ce466a21cf4620ce4620cf466a21d046" + "20cf4620d0466a21d14620d04620d1466a21d24620d14620d2466a21d34620d24620d3466a21d44620d34620d4466a" + "21d54620d44620d5466a21d64620d54620d6466a21d74620d64620d7466a21d84620d74620d8466a21d94620d84620" + "d9466a21da4620d94620da466a21db4620da4620db466a21dc4620db4620dc466a21dd4620dc4620dd466a21de4620" + "dd4620de466a21df4620de4620df466a21e04620df4620e0466a21e14620e04620e1466a21e24620e14620e2466a21" + "e34620e24620e3466a21e44620e34620e4466a21e54620e44620e5466a21e64620e54620e6466a21e74620e64620e7" + "466a21e84620e74620e8466a21e94620e84620e9466a21ea4620e94620ea466a21eb4620ea4620eb466a21ec4620eb" + "4620ec466a21ed4620ec4620ed466a21ee4620ed4620ee466a21ef4620ee4620ef466a21f04620ef4620f0466a21f1" + "4620f04620f1466a21f24620f14620f2466a21f34620f24620f3466a21f44620f34620f4466a21f54620f44620f546" + "6a21f64620f54620f6466a21f74620f64620f7466a21f84620f74620f8466a21f94620f84620f9466a21fa4620f946" + "20fa466a21fb4620fa4620fb466a21fc4620fb4620fc466a21fd4620fc4620fd466a21fe4620fd4620fe466a21ff46" + "20fe4620ff466a21804720ff462080476a2181472080472081476a2182472081472082476a2183472082472083476a" + "2184472083472084476a2185472084472085476a2186472085472086476a2187472086472087476a21884720874720" + "88476a2189472088472089476a218a47208947208a476a218b47208a47208b476a218c47208b47208c476a218d4720" + "8c47208d476a218e47208d47208e476a218f47208e47208f476a219047208f472090476a2191472090472091476a21" + "92472091472092476a2193472092472093476a2194472093472094476a2195472094472095476a2196472095472096" + "476a2197472096472097476a2198472097472098476a2199472098472099476a219a47209947209a476a219b47209a" + "47209b476a219c47209b47209c476a219d47209c47209d476a219e47209d47209e476a219f47209e47209f476a21a0" + "47209f4720a0476a21a14720a04720a1476a21a24720a14720a2476a21a34720a24720a3476a21a44720a34720a447" + "6a21a54720a44720a5476a21a64720a54720a6476a21a74720a64720a7476a21a84720a74720a8476a21a94720a847" + "20a9476a21aa4720a94720aa476a21ab4720aa4720ab476a21ac4720ab4720ac476a21ad4720ac4720ad476a21ae47" + "20ad4720ae476a21af4720ae4720af476a21b04720af4720b0476a21b14720b04720b1476a21b24720b14720b2476a" + "21b34720b24720b3476a21b44720b34720b4476a21b54720b44720b5476a21b64720b54720b6476a21b74720b64720" + "b7476a21b84720b74720b8476a21b94720b84720b9476a21ba4720b94720ba476a21bb4720ba4720bb476a21bc4720" + "bb4720bc476a21bd4720bc4720bd476a21be4720bd4720be476a21bf4720be4720bf476a21c04720bf4720c0476a21" + "c14720c04720c1476a21c24720c14720c2476a21c34720c24720c3476a21c44720c34720c4476a21c54720c44720c5" + "476a21c64720c54720c6476a21c74720c64720c7476a21c84720c74720c8476a21c94720c84720c9476a21ca4720c9" + "4720ca476a21cb4720ca4720cb476a21cc4720cb4720cc476a21cd4720cc4720cd476a21ce4720cd4720ce476a21cf" + "4720ce4720cf476a21d04720cf4720d0476a21d14720d04720d1476a21d24720d14720d2476a21d34720d24720d347" + "6a21d44720d34720d4476a21d54720d44720d5476a21d64720d54720d6476a21d74720d64720d7476a21d84720d747" + "20d8476a21d94720d84720d9476a21da4720d94720da476a21db4720da4720db476a21dc4720db4720dc476a21dd47" + "20dc4720dd476a21de4720dd4720de476a21df4720de4720df476a21e04720df4720e0476a21e14720e04720e1476a" + "21e24720e14720e2476a21e34720e24720e3476a21e44720e34720e4476a21e54720e44720e5476a21e64720e54720" + "e6476a21e74720e64720e7476a21e84720e74720e8476a21e94720e84720e9476a21ea4720e94720ea476a21eb4720" + "ea4720eb476a21ec4720eb4720ec476a21ed4720ec4720ed476a21ee4720ed4720ee476a21ef4720ee4720ef476a21" + "f04720ef4720f0476a21f14720f04720f1476a21f24720f14720f2476a21f34720f24720f3476a21f44720f34720f4" + "476a21f54720f44720f5476a21f64720f54720f6476a21f74720f64720f7476a21f84720f74720f8476a21f94720f8" + "4720f9476a21fa4720f94720fa476a21fb4720fa4720fb476a21fc4720fb4720fc476a21fd4720fc4720fd476a21fe" + "4720fd4720fe476a21ff4720fe4720ff476a21804820ff472080486a2181482080482081486a218248208148208248" + "6a2183482082482083486a2184482083482084486a2185482084482085486a2186482085482086486a218748208648" + "2087486a2188482087482088486a2189482088482089486a218a48208948208a486a218b48208a48208b486a218c48" + "208b48208c486a218d48208c48208d486a218e48208d48208e486a218f48208e48208f486a219048208f482090486a" + "2191482090482091486a2192482091482092486a2193482092482093486a2194482093482094486a21954820944820" + "95486a2196482095482096486a2197482096482097486a2198482097482098486a2199482098482099486a219a4820" + "9948209a486a219b48209a48209b486a219c48209b48209c486a219d48209c48209d486a219e48209d48209e486a21" + "9f48209e48209f486a21a048209f4820a0486a21a14820a04820a1486a21a24820a14820a2486a21a34820a24820a3" + "486a21a44820a34820a4486a21a54820a44820a5486a21a64820a54820a6486a21a74820a64820a7486a21a84820a7" + "4820a8486a21a94820a84820a9486a21aa4820a94820aa486a21ab4820aa4820ab486a21ac4820ab4820ac486a21ad" + "4820ac4820ad486a21ae4820ad4820ae486a21af4820ae4820af486a21b04820af4820b0486a21b14820b04820b148" + "6a21b24820b14820b2486a21b34820b24820b3486a21b44820b34820b4486a21b54820b44820b5486a21b64820b548" + "20b6486a21b74820b64820b7486a21b84820b74820b8486a21b94820b84820b9486a21ba4820b94820ba486a21bb48" + "20ba4820bb486a21bc4820bb4820bc486a21bd4820bc4820bd486a21be4820bd4820be486a21bf4820be4820bf486a" + "21c04820bf4820c0486a21c14820c04820c1486a21c24820c14820c2486a21c34820c24820c3486a21c44820c34820" + "c4486a21c54820c44820c5486a21c64820c54820c6486a21c74820c64820c7486a21c84820c74820c8486a21c94820" + "c84820c9486a21ca4820c94820ca486a21cb4820ca4820cb486a21cc4820cb4820cc486a21cd4820cc4820cd486a21" + "ce4820cd4820ce486a21cf4820ce4820cf486a21d04820cf4820d0486a21d14820d04820d1486a21d24820d14820d2" + "486a21d34820d24820d3486a21d44820d34820d4486a21d54820d44820d5486a21d64820d54820d6486a21d74820d6" + "4820d7486a21d84820d74820d8486a21d94820d84820d9486a21da4820d94820da486a21db4820da4820db486a21dc" + "4820db4820dc486a21dd4820dc4820dd486a21de4820dd4820de486a21df4820de4820df486a21e04820df4820e048" + "6a21e14820e04820e1486a21e24820e14820e2486a21e34820e24820e3486a21e44820e34820e4486a21e54820e448" + "20e5486a21e64820e54820e6486a21e74820e64820e7486a21e84820e74820e8486a21e94820e84820e9486a21ea48" + "20e94820ea486a21eb4820ea4820eb486a21ec4820eb4820ec486a21ed4820ec4820ed486a21ee4820ed4820ee486a" + "21ef4820ee4820ef486a21f04820ef4820f0486a21f14820f04820f1486a21f24820f14820f2486a21f34820f24820" + "f3486a21f44820f34820f4486a21f54820f44820f5486a21f64820f54820f6486a21f74820f64820f7486a21f84820" + "f74820f8486a21f94820f84820f9486a21fa4820f94820fa486a21fb4820fa4820fb486a21fc4820fb4820fc486a21" + "fd4820fc4820fd486a21fe4820fd4820fe486a21ff4820fe4820ff486a21804920ff482080496a2181492080492081" + "496a2182492081492082496a2183492082492083496a2184492083492084496a2185492084492085496a2186492085" + "492086496a2187492086492087496a2188492087492088496a2189492088492089496a218a49208949208a496a218b" + "49208a49208b496a218c49208b49208c496a218d49208c49208d496a218e49208d49208e496a218f49208e49208f49" + "6a219049208f492090496a2191492090492091496a2192492091492092496a2193492092492093496a219449209349" + "2094496a2195492094492095496a2196492095492096496a2197492096492097496a2198492097492098496a219949" + "2098492099496a219a49209949209a496a219b49209a49209b496a219c49209b49209c496a219d49209c49209d496a" + "219e49209d49209e496a219f49209e49209f496a21a049209f4920a0496a21a14920a04920a1496a21a24920a14920" + "a2496a21a34920a24920a3496a21a44920a34920a4496a21a54920a44920a5496a21a64920a54920a6496a21a74920" + "a64920a7496a21a84920a74920a8496a21a94920a84920a9496a21aa4920a94920aa496a21ab4920aa4920ab496a21" + "ac4920ab4920ac496a21ad4920ac4920ad496a21ae4920ad4920ae496a21af4920ae4920af496a21b04920af4920b0" + "496a21b14920b04920b1496a21b24920b14920b2496a21b34920b24920b3496a21b44920b34920b4496a21b54920b4" + "4920b5496a21b64920b54920b6496a21b74920b64920b7496a21b84920b74920b8496a21b94920b84920b9496a21ba" + "4920b94920ba496a21bb4920ba4920bb496a21bc4920bb4920bc496a21bd4920bc4920bd496a21be4920bd4920be49" + "6a21bf4920be4920bf496a21c04920bf4920c0496a21c14920c04920c1496a21c24920c14920c2496a21c34920c249" + "20c3496a21c44920c34920c4496a21c54920c44920c5496a21c64920c54920c6496a21c74920c64920c7496a21c849" + "20c74920c8496a21c94920c84920c9496a21ca4920c94920ca496a21cb4920ca4920cb496a21cc4920cb4920cc496a" + "21cd4920cc4920cd496a21ce4920cd4920ce496a21cf4920ce4920cf496a21d04920cf4920d0496a21d14920d04920" + "d1496a21d24920d14920d2496a21d34920d24920d3496a21d44920d34920d4496a21d54920d44920d5496a21d64920" + "d54920d6496a21d74920d64920d7496a21d84920d74920d8496a21d94920d84920d9496a21da4920d94920da496a21" + "db4920da4920db496a21dc4920db4920dc496a21dd4920dc4920dd496a21de4920dd4920de496a21df4920de4920df" + "496a21e04920df4920e0496a21e14920e04920e1496a21e24920e14920e2496a21e34920e24920e3496a21e44920e3" + "4920e4496a21e54920e44920e5496a21e64920e54920e6496a21e74920e64920e7496a21e84920e74920e8496a21e9" + "4920e84920e9496a21ea4920e94920ea496a21eb4920ea4920eb496a21ec4920eb4920ec496a21ed4920ec4920ed49" + "6a21ee4920ed4920ee496a21ef4920ee4920ef496a21f04920ef4920f0496a21f14920f04920f1496a21f24920f149" + "20f2496a21f34920f24920f3496a21f44920f34920f4496a21f54920f44920f5496a21f64920f54920f6496a21f749" + "20f64920f7496a21f84920f74920f8496a21f94920f84920f9496a21fa4920f94920fa496a21fb4920fa4920fb496a" + "21fc4920fb4920fc496a21fd4920fc4920fd496a21fe4920fd4920fe496a21ff4920fe4920ff496a21804a20ff4920" + "804a6a21814a20804a20814a6a21824a20814a20824a6a21834a20824a20834a6a21844a20834a20844a6a21854a20" + "844a20854a6a21864a20854a20864a6a21874a20864a20874a6a21884a20874a20884a6a21894a20884a20894a6a21" + "8a4a20894a208a4a6a218b4a208a4a208b4a6a218c4a208b4a208c4a6a218d4a208c4a208d4a6a218e4a208d4a208e" + "4a6a218f4a208e4a208f4a6a21904a208f4a20904a6a21914a20904a20914a6a21924a20914a20924a6a21934a2092" + "4a20934a6a21944a20934a20944a6a21954a20944a20954a6a21964a20954a20964a6a21974a20964a20974a6a2198" + "4a20974a20984a6a21994a20984a20994a6a219a4a20994a209a4a6a219b4a209a4a209b4a6a219c4a209b4a209c4a" + "6a219d4a209c4a209d4a6a219e4a209d4a209e4a6a219f4a209e4a209f4a6a21a04a209f4a20a04a6a21a14a20a04a" + "20a14a6a21a24a20a14a20a24a6a21a34a20a24a20a34a6a21a44a20a34a20a44a6a21a54a20a44a20a54a6a21a64a" + "20a54a20a64a6a21a74a20a64a20a74a6a21a84a20a74a20a84a6a21a94a20a84a20a94a6a21aa4a20a94a20aa4a6a" + "21ab4a20aa4a20ab4a6a21ac4a20ab4a20ac4a6a21ad4a20ac4a20ad4a6a21ae4a20ad4a20ae4a6a21af4a20ae4a20" + "af4a6a21b04a20af4a20b04a6a21b14a20b04a20b14a6a21b24a20b14a20b24a6a21b34a20b24a20b34a6a21b44a20" + "b34a20b44a6a21b54a20b44a20b54a6a21b64a20b54a20b64a6a21b74a20b64a20b74a6a21b84a20b74a20b84a6a21" + "b94a20b84a20b94a6a21ba4a20b94a20ba4a6a21bb4a20ba4a20bb4a6a21bc4a20bb4a20bc4a6a21bd4a20bc4a20bd" + "4a6a21be4a20bd4a20be4a6a21bf4a20be4a20bf4a6a21c04a20bf4a20c04a6a21c14a20c04a20c14a6a21c24a20c1" + "4a20c24a6a21c34a20c24a20c34a6a21c44a20c34a20c44a6a21c54a20c44a20c54a6a21c64a20c54a20c64a6a21c7" + "4a20c64a20c74a6a21c84a20c74a20c84a6a21c94a20c84a20c94a6a21ca4a20c94a20ca4a6a21cb4a20ca4a20cb4a" + "6a21cc4a20cb4a20cc4a6a21cd4a20cc4a20cd4a6a21ce4a20cd4a20ce4a6a21cf4a20ce4a20cf4a6a21d04a20cf4a" + "20d04a6a21d14a20d04a20d14a6a21d24a20d14a20d24a6a21d34a20d24a20d34a6a21d44a20d34a20d44a6a21d54a" + "20d44a20d54a6a21d64a20d54a20d64a6a21d74a20d64a20d74a6a21d84a20d74a20d84a6a21d94a20d84a20d94a6a" + "21da4a20d94a20da4a6a21db4a20da4a20db4a6a21dc4a20db4a20dc4a6a21dd4a20dc4a20dd4a6a21de4a20dd4a20" + "de4a6a21df4a20de4a20df4a6a21e04a20df4a20e04a6a21e14a20e04a20e14a6a21e24a20e14a20e24a6a21e34a20" + "e24a20e34a6a21e44a20e34a20e44a6a21e54a20e44a20e54a6a21e64a20e54a20e64a6a21e74a20e64a20e74a6a21" + "e84a20e74a20e84a6a21e94a20e84a20e94a6a21ea4a20e94a20ea4a6a21eb4a20ea4a20eb4a6a21ec4a20eb4a20ec" + "4a6a21ed4a20ec4a20ed4a6a21ee4a20ed4a20ee4a6a21ef4a20ee4a20ef4a6a21f04a20ef4a20f04a6a21f14a20f0" + "4a20f14a6a21f24a20f14a20f24a6a21f34a20f24a20f34a6a21f44a20f34a20f44a6a21f54a20f44a20f54a6a21f6" + "4a20f54a20f64a6a21f74a20f64a20f74a6a21f84a20f74a20f84a6a21f94a20f84a20f94a6a21fa4a20f94a20fa4a" + "6a21fb4a20fa4a20fb4a6a21fc4a20fb4a20fc4a6a21fd4a20fc4a20fd4a6a21fe4a20fd4a20fe4a6a21ff4a20fe4a" + "20ff4a6a21804b20ff4a20804b6a21814b20804b20814b6a21824b20814b20824b6a21834b20824b20834b6a21844b" + "20834b20844b6a21854b20844b20854b6a21864b20854b20864b6a21874b20864b20874b6a21884b20874b20884b6a" + "21894b20884b20894b6a218a4b20894b208a4b6a218b4b208a4b208b4b6a218c4b208b4b208c4b6a218d4b208c4b20" + "8d4b6a218e4b208d4b208e4b6a218f4b208e4b208f4b6a21904b208f4b20904b6a21914b20904b20914b6a21924b20" + "914b20924b6a21934b20924b20934b6a21944b20934b20944b6a21954b20944b20954b6a21964b20954b20964b6a21" + "974b20964b20974b6a21984b20974b20984b6a21994b20984b20994b6a219a4b20994b209a4b6a219b4b209a4b209b" + "4b6a219c4b209b4b209c4b6a219d4b209c4b209d4b6a219e4b209d4b209e4b6a219f4b209e4b209f4b6a21a04b209f" + "4b20a04b6a21a14b20a04b20a14b6a21a24b20a14b20a24b6a21a34b20a24b20a34b6a21a44b20a34b20a44b6a21a5" + "4b20a44b20a54b6a21a64b20a54b20a64b6a21a74b20a64b20a74b6a21a84b20a74b20a84b6a21a94b20a84b20a94b" + "6a21aa4b20a94b20aa4b6a21ab4b20aa4b20ab4b6a21ac4b20ab4b20ac4b6a21ad4b20ac4b20ad4b6a21ae4b20ad4b" + "20ae4b6a21af4b20ae4b20af4b6a21b04b20af4b20b04b6a21b14b20b04b20b14b6a21b24b20b14b20b24b6a21b34b" + "20b24b20b34b6a21b44b20b34b20b44b6a21b54b20b44b20b54b6a21b64b20b54b20b64b6a21b74b20b64b20b74b6a" + "21b84b20b74b20b84b6a21b94b20b84b20b94b6a21ba4b20b94b20ba4b6a21bb4b20ba4b20bb4b6a21bc4b20bb4b20" + "bc4b6a21bd4b20bc4b20bd4b6a21be4b20bd4b20be4b6a21bf4b20be4b20bf4b6a21c04b20bf4b20c04b6a21c14b20" + "c04b20c14b6a21c24b20c14b20c24b6a21c34b20c24b20c34b6a21c44b20c34b20c44b6a21c54b20c44b20c54b6a21" + "c64b20c54b20c64b6a21c74b20c64b20c74b6a21c84b20c74b20c84b6a21c94b20c84b20c94b6a21ca4b20c94b20ca" + "4b6a21cb4b20ca4b20cb4b6a21cc4b20cb4b20cc4b6a21cd4b20cc4b20cd4b6a21ce4b20cd4b20ce4b6a21cf4b20ce" + "4b20cf4b6a21d04b20cf4b20d04b6a21d14b20d04b20d14b6a21d24b20d14b20d24b6a21d34b20d24b20d34b6a21d4" + "4b20d34b20d44b6a21d54b20d44b20d54b6a21d64b20d54b20d64b6a21d74b20d64b20d74b6a21d84b20d74b20d84b" + "6a21d94b20d84b20d94b6a21da4b20d94b20da4b6a21db4b20da4b20db4b6a21dc4b20db4b20dc4b6a21dd4b20dc4b" + "20dd4b6a21de4b20dd4b20de4b6a21df4b20de4b20df4b6a21e04b20df4b20e04b6a21e14b20e04b20e14b6a21e24b" + "20e14b20e24b6a21e34b20e24b20e34b6a21e44b20e34b20e44b6a21e54b20e44b20e54b6a21e64b20e54b20e64b6a" + "21e74b20e64b20e74b6a21e84b20e74b20e84b6a21e94b20e84b20e94b6a21ea4b20e94b20ea4b6a21eb4b20ea4b20" + "eb4b6a21ec4b20eb4b20ec4b6a21ed4b20ec4b20ed4b6a21ee4b20ed4b20ee4b6a21ef4b20ee4b20ef4b6a21f04b20" + "ef4b20f04b6a21f14b20f04b20f14b6a21f24b20f14b20f24b6a21f34b20f24b20f34b6a21f44b20f34b20f44b6a21" + "f54b20f44b20f54b6a21f64b20f54b20f64b6a21f74b20f64b20f74b6a21f84b20f74b20f84b6a21f94b20f84b20f9" + "4b6a21fa4b20f94b20fa4b6a21fb4b20fa4b20fb4b6a21fc4b20fb4b20fc4b6a21fd4b20fc4b20fd4b6a21fe4b20fd" + "4b20fe4b6a21ff4b20fe4b20ff4b6a21804c20ff4b20804c6a21814c20804c20814c6a21824c20814c20824c6a2183" + "4c20824c20834c6a21844c20834c20844c6a21854c20844c20854c6a21864c20854c20864c6a21874c20864c20874c" + "6a21884c20874c20884c6a21894c20884c20894c6a218a4c20894c208a4c6a218b4c208a4c208b4c6a218c4c208b4c" + "208c4c6a218d4c208c4c208d4c6a218e4c208d4c208e4c6a218f4c208e4c208f4c6a21904c208f4c20904c6a21914c" + "20904c20914c6a21924c20914c20924c6a21934c20924c20934c6a21944c20934c20944c6a21954c20944c20954c6a" + "21964c20954c20964c6a21974c20964c20974c6a21984c20974c20984c6a21994c20984c20994c6a219a4c20994c20" + "9a4c6a219b4c209a4c209b4c6a219c4c209b4c209c4c6a219d4c209c4c209d4c6a219e4c209d4c209e4c6a219f4c20" + "9e4c209f4c6a21a04c209f4c20a04c6a21a14c20a04c20a14c6a21a24c20a14c20a24c6a21a34c20a24c20a34c6a21" + "a44c20a34c20a44c6a21a54c20a44c20a54c6a21a64c20a54c20a64c6a21a74c20a64c20a74c6a21a84c20a74c20a8" + "4c6a21a94c20a84c20a94c6a21aa4c20a94c20aa4c6a21ab4c20aa4c20ab4c6a21ac4c20ab4c20ac4c6a21ad4c20ac" + "4c20ad4c6a21ae4c20ad4c20ae4c6a21af4c20ae4c20af4c6a21b04c20af4c20b04c6a21b14c20b04c20b14c6a21b2" + "4c20b14c20b24c6a21b34c20b24c20b34c6a21b44c20b34c20b44c6a21b54c20b44c20b54c6a21b64c20b54c20b64c" + "6a21b74c20b64c20b74c6a21b84c20b74c20b84c6a21b94c20b84c20b94c6a21ba4c20b94c20ba4c6a21bb4c20ba4c" + "20bb4c6a21bc4c20bb4c20bc4c6a21bd4c20bc4c20bd4c6a21be4c20bd4c20be4c6a21bf4c20be4c20bf4c6a21c04c" + "20bf4c20c04c6a21c14c20c04c20c14c6a21c24c20c14c20c24c6a21c34c20c24c20c34c6a21c44c20c34c20c44c6a" + "21c54c20c44c20c54c6a21c64c20c54c20c64c6a21c74c20c64c20c74c6a21c84c20c74c20c84c6a21c94c20c84c20" + "c94c6a21ca4c20c94c20ca4c6a21cb4c20ca4c20cb4c6a21cc4c20cb4c20cc4c6a21cd4c20cc4c20cd4c6a21ce4c20" + "cd4c20ce4c6a21cf4c20ce4c20cf4c6a21d04c20cf4c20d04c6a21d14c20d04c20d14c6a21d24c20d14c20d24c6a21" + "d34c20d24c20d34c6a21d44c20d34c20d44c6a21d54c20d44c20d54c6a21d64c20d54c20d64c6a21d74c20d64c20d7" + "4c6a21d84c20d74c20d84c6a21d94c20d84c20d94c6a21da4c20d94c20da4c6a21db4c20da4c20db4c6a21dc4c20db" + "4c20dc4c6a21dd4c20dc4c20dd4c6a21de4c20dd4c20de4c6a21df4c20de4c20df4c6a21e04c20df4c20e04c6a21e1" + "4c20e04c20e14c6a21e24c20e14c20e24c6a21e34c20e24c20e34c6a21e44c20e34c20e44c6a21e54c20e44c20e54c" + "6a21e64c20e54c20e64c6a21e74c20e64c20e74c6a21e84c20e74c20e84c6a21e94c20e84c20e94c6a21ea4c20e94c" + "20ea4c6a21eb4c20ea4c20eb4c6a21ec4c20eb4c20ec4c6a21ed4c20ec4c20ed4c6a21ee4c20ed4c20ee4c6a21ef4c" + "20ee4c20ef4c6a21f04c20ef4c20f04c6a21f14c20f04c20f14c6a21f24c20f14c20f24c6a21f34c20f24c20f34c6a" + "21f44c20f34c20f44c6a21f54c20f44c20f54c6a21f64c20f54c20f64c6a21f74c20f64c20f74c6a21f84c20f74c20" + "f84c6a21f94c20f84c20f94c6a21fa4c20f94c20fa4c6a21fb4c20fa4c20fb4c6a21fc4c20fb4c20fc4c6a21fd4c20" + "fc4c20fd4c6a21fe4c20fd4c20fe4c6a21ff4c20fe4c20ff4c6a21804d20ff4c20804d6a21814d20804d20814d6a21" + "824d20814d20824d6a21834d20824d20834d6a21844d20834d20844d6a21854d20844d20854d6a21864d20854d2086" + "4d6a21874d20864d20874d6a21884d20874d20884d6a21894d20884d20894d6a218a4d20894d208a4d6a218b4d208a" + "4d208b4d6a218c4d208b4d208c4d6a218d4d208c4d208d4d6a218e4d208d4d208e4d6a218f4d208e4d208f4d6a2190" + "4d208f4d20904d6a21914d20904d20914d6a21924d20914d20924d6a21934d20924d20934d6a21944d20934d20944d" + "6a21954d20944d20954d6a21964d20954d20964d6a21974d20964d20974d6a21984d20974d20984d6a21994d20984d" + "20994d6a219a4d20994d209a4d6a219b4d209a4d209b4d6a219c4d209b4d209c4d6a219d4d209c4d209d4d6a219e4d" + "209d4d209e4d6a219f4d209e4d209f4d6a21a04d209f4d20a04d6a21a14d20a04d20a14d6a21a24d20a14d20a24d6a" + "21a34d20a24d20a34d6a21a44d20a34d20a44d6a21a54d20a44d20a54d6a21a64d20a54d20a64d6a21a74d20a64d20" + "a74d6a21a84d20a74d20a84d6a21a94d20a84d20a94d6a21aa4d20a94d20aa4d6a21ab4d20aa4d20ab4d6a21ac4d20" + "ab4d20ac4d6a21ad4d20ac4d20ad4d6a21ae4d20ad4d20ae4d6a21af4d20ae4d20af4d6a21b04d20af4d20b04d6a21" + "b14d20b04d20b14d6a21b24d20b14d20b24d6a21b34d20b24d20b34d6a21b44d20b34d20b44d6a21b54d20b44d20b5" + "4d6a21b64d20b54d20b64d6a21b74d20b64d20b74d6a21b84d20b74d20b84d6a21b94d20b84d20b94d6a21ba4d20b9" + "4d20ba4d6a21bb4d20ba4d20bb4d6a21bc4d20bb4d20bc4d6a21bd4d20bc4d20bd4d6a21be4d20bd4d20be4d6a21bf" + "4d20be4d20bf4d6a21c04d20bf4d20c04d6a21c14d20c04d20c14d6a21c24d20c14d20c24d6a21c34d20c24d20c34d" + "6a21c44d20c34d20c44d6a21c54d20c44d20c54d6a21c64d20c54d20c64d6a21c74d20c64d20c74d6a21c84d20c74d" + "20c84d6a21c94d20c84d20c94d6a21ca4d20c94d20ca4d6a21cb4d20ca4d20cb4d6a21cc4d20cb4d20cc4d6a21cd4d" + "20cc4d20cd4d6a21ce4d20cd4d20ce4d6a21cf4d20ce4d20cf4d6a21d04d20cf4d20d04d6a21d14d20d04d20d14d6a" + "21d24d20d14d20d24d6a21d34d20d24d20d34d6a21d44d20d34d20d44d6a21d54d20d44d20d54d6a21d64d20d54d20" + "d64d6a21d74d20d64d20d74d6a21d84d20d74d20d84d6a21d94d20d84d20d94d6a21da4d20d94d20da4d6a21db4d20" + "da4d20db4d6a21dc4d20db4d20dc4d6a21dd4d20dc4d20dd4d6a21de4d20dd4d20de4d6a21df4d20de4d20df4d6a21" + "e04d20df4d20e04d6a21e14d20e04d20e14d6a21e24d20e14d20e24d6a21e34d20e24d20e34d6a21e44d20e34d20e4" + "4d6a21e54d20e44d20e54d6a21e64d20e54d20e64d6a21e74d20e64d20e74d6a21e84d20e74d20e84d6a21e94d20e8" + "4d20e94d6a21ea4d20e94d20ea4d6a21eb4d20ea4d20eb4d6a21ec4d20eb4d20ec4d6a21ed4d20ec4d20ed4d6a21ee" + "4d20ed4d20ee4d6a21ef4d20ee4d20ef4d6a21f04d20ef4d20f04d6a21f14d20f04d20f14d6a21f24d20f14d20f24d" + "6a21f34d20f24d20f34d6a21f44d20f34d20f44d6a21f54d20f44d20f54d6a21f64d20f54d20f64d6a21f74d20f64d" + "20f74d6a21f84d20f74d20f84d6a21f94d20f84d20f94d6a21fa4d20f94d20fa4d6a21fb4d20fa4d20fb4d6a21fc4d" + "20fb4d20fc4d6a21fd4d20fc4d20fd4d6a21fe4d20fd4d20fe4d6a21ff4d20fe4d20ff4d6a21804e20ff4d20804e6a" + "21814e20804e20814e6a21824e20814e20824e6a21834e20824e20834e6a21844e20834e20844e6a21854e20844e20" + "854e6a21864e20854e20864e6a21874e20864e20874e6a21884e20874e20884e6a21894e20884e20894e6a218a4e20" + "894e208a4e6a218b4e208a4e208b4e6a218c4e208b4e208c4e6a218d4e208c4e208d4e6a218e4e208d4e208e4e6a21" + "8f4e208f4e0b"; diff --git a/src/test/app/wasm_fixtures/fixtures.cpp b/src/test/app/wasm_fixtures/fixtures.cpp index 1087e30954..81d9f04047 100644 --- a/src/test/app/wasm_fixtures/fixtures.cpp +++ b/src/test/app/wasm_fixtures/fixtures.cpp @@ -1,7 +1,23 @@ +// TODO: consider moving these to separate files (and figure out the build) + #include #include +extern std::string const kFibWasmHex = + "0061736d0100000001090260000060017f017f030302000105030100020638097f004180080b7f004180080b7f0041" + "80080b7f00418088040b7f004180080b7f00418088040b7f00418080080b7f0041000b7f0041010b07a7010c066d65" + "6d6f72790200115f5f7761736d5f63616c6c5f63746f727300000366696200010c5f5f64736f5f68616e646c650300" + "0a5f5f646174615f656e6403010b5f5f737461636b5f6c6f7703020c5f5f737461636b5f6869676803030d5f5f676c" + "6f62616c5f6261736503040b5f5f686561705f6261736503050a5f5f686561705f656e6403060d5f5f6d656d6f7279" + "5f6261736503070c5f5f7461626c655f6261736503080a440202000b3f01017f200045044041000f0b200041034804" + "4041010f0b200041026a21000340200041036b100120016a2101200041026b220041044a0d000b200141016a0b007f" + "0970726f647563657273010c70726f6365737365642d62790105636c616e675f31392e312e352d776173692d73646b" + "202868747470733a2f2f6769746875622e636f6d2f6c6c766d2f6c6c766d2d70726f6a656374206162346235613264" + "62353832393538616631656533303861373930636664623432626432343732302900490f7461726765745f66656174" + "75726573042b0f6d757461626c652d676c6f62616c732b087369676e2d6578742b0f7265666572656e63652d747970" + "65732b0a6d756c746976616c7565"; + extern std::string const kLedgerSqnWasmHex = "0061736d01000000010e0360027f7f017f6000006000017f02120103656e760a6c6467725f696e6465780000030302" "01020503010002063f0a7f01418088040b7f004180080b7f004180080b7f004180080b7f00418088040b7f00418008" @@ -197,6 +213,10 @@ extern std::string const kAllHostFunctionsWasmHex = "39352e30202835393830373631366520323032362d30342d313429002c0f7461726765745f6665617475726573022b" "0f6d757461626c652d676c6f62616c732b087369676e2d657874"; +extern std::string const kDeepRecursionHex = + "0061736d010000000105016000017f030201000608017f0141c0843d0b0711010d657363726f775f66696e69736800" + "000a16011400230045044041010f0b230041016b240010000b"; + extern std::string const kAllKeyletsWasmHex = "0061736d0100000001500a60067f7f7f7f7f7f017f60047f7f7f7f017f60087f7f7f7f7f7f7f7f017f60047f7f7f7f" "0060037f7f7f017f60037f7f7e017f60057f7f7f7f7f017f6000017f60037f7f7f0060067f7f7f7f7f7e00029f0418" @@ -627,6 +647,487 @@ extern std::string const kCodecovTestsWasmHex = "6365737365642d6279010572757374631d312e39352e30202835393830373631366520323032362d30342d31342900" "2c0f7461726765745f6665617475726573022b0f6d757461626c652d676c6f62616c732b087369676e2d657874"; +extern std::string const kFloatTestsWasmHex = + "0061736d0100000001490960057f7f7f7f7f017f60077f7f7f7f7f7f7f017f60067f7f7f7f7f7f017f60047e7f7f7f" + "017f60057e7f7f7f7f017f60047f7f7f7f017f60037f7f7e017f60037f7f7f006000017f02ea021008686f73745f6c" + "6962057472616365000008686f73745f6c69620e666c6f61745f66726f6d5f696e74000308686f73745f6c69620f66" + "6c6f61745f66726f6d5f75696e74000003656e7613666c6f61745f66726f6d5f6d616e745f657870000408686f7374" + "5f6c696209666c6f61745f636d70000508686f73745f6c696209666c6f61745f616464000108686f73745f6c696209" + "666c6f61745f737562000108686f73745f6c69620a666c6f61745f6d756c74000108686f73745f6c696209666c6f61" + "745f646976000108686f73745f6c696209666c6f61745f706f77000208686f73745f6c69620974726163655f6e756d" + "000608686f73745f6c69620a666c6f61745f726f6f74000203656e760c666c6f61745f746f5f696e74000003656e76" + "11666c6f61745f746f5f6d616e745f657870000203656e7613666c6f61745f66726f6d5f7374616d6f756e74000003" + "656e7613666c6f61745f66726f6d5f73746e756d6265720000030302070805030100110619037f01418080c0000b7f" + "00418599c0000b7f00419099c0000b073504066d656d6f727902000d657363726f775f66696e69736800110a5f5f64" + "6174615f656e6403010b5f5f686561705f6261736503020aec20021f002000200141014100410010001a418080c000" + "41022002410c410110001a0bc920020c7f017e230041f0006b2200240041ee8ac000411d41014100410010001a2000" + "4100360268200042003703600240428ce000200041e0006a2202410c410010012201410c460440418b8bc000411720" + "02101041a28bc000411e2002410c410110001a0c010b41c08bc000411e41014100410010001a0b2000428ce0003703" + "500240200041d0006a4108200041e0006a2202410c41001002410c4604402001410c46210741de8bc0004117200210" + "100c010b41f58bc000411e41014100410010001a0b024042fb004102200041e0006a2201410c41001003410c460440" + "41938cc0004121200110100c010b41b48cc000412841014100410010001a410021070b41dc8cc000411541be80c000" + "101041f18cc0004116418881c0001010418280c000411741014100410010001a200041003602682000420037036002" + "404201200041e0006a2202410c410010012201410c460440419980c000410f200210100c010b41a880c00041164101" + "4100410010001a0b027f200041e0006a410c41be80c000410c100445044041ca80c000411b41014100410010001a20" + "01410c460c010b41e580c000412341014100410010001a41000b21080240200041e0006a410c418881c000410c1004" + "4101460440419481c000412341014100410010001a0c010b4100210841b781c000412c41014100410010001a0b0240" + "418881c000410c200041e0006a410c1004410246044041e381c000412341014100410010001a0c010b410021084186" + "82c000412c41014100410010001a0b419c93c000412041014100410010001a200041c680c000280000360258200041" + "be80c000290000370350410921030340200041d0006a2201410c41be80c000410c2001410c410010051a200341016b" + "22030d000b2000410036026820004200370360420a200041e0006a410c41001001410c46220945044041bc93c00041" + "1741014100410010001a0b0240200041e0006a410c200041d0006a410c100445044041d393c0004114410141004100" + "10001a0c010b4100210941e793c000411641014100410010001a0b410b21030340200041d0006a2201410c41be80c0" + "00410c2001410c410010061a200341016b22030d000b02402001410c418881c000410c100445044041fd93c0004119" + "41014100410010001a0c010b41002109419694c000411b41014100410010001a0b41878dc000411f41014100410010" + "001a2000410036021020004200370308420a200041086a410c410010011a200041c680c000280000360220200041be" + "80c000290000370318410621030340200041186a2201410c200041086a410c2001410c410010071a200341016b2203" + "0d000b200041003602582000420037035042c0843d200041d0006a2202410c410010011a02402002410c2001410c10" + "04220145044041a68dc000411941014100410010001a0c010b41bf8dc000411b41014100410010001a0b200145210a" + "410721030340200041186a2201410c200041086a410c2001410c410010081a200341016b22030d000b200041003602" + "68200042003703604201417f200041e0006a2202410c410010031a02402001410c2002410c100445044041da8dc000" + "411741014100410010001a0c010b41f18dc000411941014100410010001a4100210a0b41b282c00041174101410041" + "0010001a200041003602202000420037031841be80c000410c4103200041186a2202410c410010091a41c982c00041" + "1220021010418881c000410c41062002410c410010091a41db82c00041182002101020004100360258200042003703" + "504209200041d0006a2201410c410010011a2001410c41022002410c410010091a41f382c000411420021010200141" + "0c41002002410c410010091a418783c00041172002101020004100360268200042003703604200200041e0006a2203" + "410c410010011a2003410c41022002410c410010091a419e83c00041142002101041b283c00041382003410c410020" + "02410c41001009ac100a1a41ea83c000411841014100410010001a200041003602202000420037031842092002410c" + "410010011a20004100360258200042003703502002410c41022001410c4100100b1a418284c0004112200110102002" + "410c41032001410c4100100b1a419484c000411220011010200041003602682000420037036042c0843d2003410c41" + "0010011a2003410c41032001410c4100100b1a41a684c0004118200110102003410c41062001410c4100100b1a41be" + "84c000411c2001101041da84c000411a41014100410010001a20004100360258200042003703502000410036026820" + "004200370360420a2003410c410010011a41be80c000410c2003410c2001410c410010081a41f484c0004119200110" + "1041be80c000410c2001410c2001410c410010081a418d85c000410f2001101002402003410c2001410c1004220b45" + "0440419c85c000411441014100410010001a0c010b41b085c000411641014100410010001a0b4100210141c685c000" + "411a41014100410010001a20004200370308024041be80c000410c200041086a41084100100c220241084604402000" + "290308220c42015104404101210141e085c000411741014100410010001a0c020b41f785c000411941014100410010" + "001a419086c0004108200c100a1a0c010b419886c000412441014100410010001a41bc86c000410f2002ac100a1a0b" + "410021030240418881c000410c200041086a41084100100c220241084604402000290308220c427f51044041cb86c0" + "00411841014100410010001a200121030c020b41e386c000411a41014100410010001a419086c0004108200c100a1a" + "0c010b41fd86c000412541014100410010001a41bc86c000410f2002ac100a1a0b4100210120004100360220200042" + "0037031842ffffffffffffffffff00200041186a2202410c410010011a02402002410c200041086a41084100100c22" + "0241084604402000290308220c42ffffffffffffffffff0051044041a287c000411e41014100410010001a20032101" + "0c020b41c087c000412041014100410010001a41e087c000410d42ffffffffffffffffff00100a1a419086c0004108" + "200c100a1a0c010b41ed87c000412b41014100410010001a41bc86c000410f2002ac100a1a0b410021022000410036" + "0258200042003703504200200041d0006a2203410c410010011a02402003410c200041086a41084100100c22034108" + "4604402000290308220c500440419888c000411741014100410010001a200121020c020b41af88c000411941014100" + "410010001a419086c0004108200c100a1a0c010b41c888c000412441014100410010001a41bc86c000410f2003ac10" + "0a1a0b4100210320004100360268200042003703604201417f200041e0006a2201410c410010031a02402001410c20" + "0041086a41084100100c220141084604402000290308220c50044041ec88c000412541014100410010001a20022103" + "0c020b419189c000412741014100410010001a419086c0004108200c100a1a0c010b41b889c0004132410141004100" + "10001a41bc86c000410f2001ac100a1a0b0240200041e0006a410c200041086a41084101100c220141084604402000" + "290308220c50044041ea89c000412741014100410010001a0c020b4100210341918ac000412941014100410010001a" + "419086c0004108200c100a1a0c010b4100210341ba8ac000413441014100410010001a41bc86c000410f2001ac100a" + "1a0b41002101418a8ec000411f41014100410010001a2000420037032820004100360234024041be80c000410c2000" + "41286a4108200041346a4104100d2202410c46044020002802342202416e462000290328220c42808090bbbad6adf0" + "0d517145044041c58ec000411e41014100410010001a41e38ec000412f200c100a1a41928fc000411f2002ac100a1a" + "0c020b4101210141a98ec000411c41014100410010001a0c010b41b18fc000412941014100410010001a41bc86c000" + "410f2002ac100a1a0b2000420037033841002102200041003602440240418881c000410c200041386a4108200041c4" + "006a4104100d2204410c46044020002802442204416e462000290338220c428080f0c4c5a9d28f72517145044041f7" + "8fc000411f41014100410010001a419690c0004130200c100a1a41928fc000411f2004ac100a1a0c020b41da8fc000" + "411d41014100410010001a200121020c010b41c690c000412a41014100410010001a41bc86c000410f2004ac100a1a" + "0b410021012000410036025820004200370350420a200041d0006a2204410c410010011a2000420037030820004100" + "36024802402004410c200041086a4108200041c8006a4104100d2204410c46044020002802482204416f4620002903" + "08220c42808090bbbad6adf00d5171450440418d91c000411f41014100410010001a41e38ec000412f200c100a1a41" + "ac91c000411f2004ac100a1a0c020b41f090c000411d41014100410010001a200221010c010b41cb91c000412a4101" + "4100410010001a41bc86c000410f2004ac100a1a0b4100210220004100360268200042003703604200200041e0006a" + "2204410c410010011a200042003703182000410036024c02402004410c200041186a4108200041cc006a4104100d22" + "04410c4604402000290318220c50200028024c22044180808080784671450440419192c000411e4101410041001000" + "1a41af92c000411d200c100a1a41cc92c00041272004ac100a1a0c020b41f591c000411c41014100410010001a2001" + "21020c010b41f392c000412941014100410010001a41bc86c000410f2004ac100a1a0b4100210141b194c000412141" + "014100410010001a200042c0808080d0a0fdf000370018200041003602682000420037036002400240200041186a41" + "08200041e0006a2205410c4100100e2204410c46044041d294c000412220051010200042003703502005410c200041" + "d0006a41084100100c22044108470d012000290350220c4280c2d72f5104404101210141f494c000411d4101410041" + "0010001a0c030b419195c000411f41014100410010001a41b095c000411c200c100a1a0c020b418096c000411f4101" + "4100410010001a419f96c00041102004ac100a1a0c010b41cc95c000413441014100410010001a41bc86c000410f20" + "04ac100a1a0b4100210441af96c000412141014100410010001a200041ffffff8f7f36005820004281eceedce494cc" + "f9c000370050200041003602682000420037036002400240200041d0006a410c200041e0006a2206410c4100100f22" + "05410c46044041d096c000411c20061010200042003703182006410c200041186a41084100100c22054108470d0120" + "00290318220c42fb005104404101210441ec96c000411b41014100410010001a0c030b418797c000411d4101410041" + "0010001a41a497c0004116200c100a1a0c020b41ec97c000411d41014100410010001a419f96c00041102005ac100a" + "1a0c010b41ba97c000413241014100410010001a41bc86c000410f2005ac100a1a0b41002105024041be80c000410c" + "200041e0006a2206410c4100100f410c460440418998c000411a200610102006410c41be80c000410c100445044041" + "a398c000412041014100410010001a200421050c020b41c398c000412241014100410010001a0c010b41e598c00041" + "2041014100410010001a0b200041f0006a2400200b452007200871200971200a71200371200271200171200571710b" + "0b8f190100418080c0000b851920200a24242420746573745f666c6f61745f636d70202424242020666c6f61742066" + "726f6d20313a2020666c6f61742066726f6d20313a206661696c65640de0b6b3a7640000ffffffee2020666c6f6174" + "2066726f6d2031203d3d20464c4f41545f4f4e452020666c6f61742066726f6d203120213d20464c4f41545f4f4e45" + "2c206661696c6564f21f494c589c0000ffffffee2020666c6f61742066726f6d2031203e20464c4f41545f4e454741" + "544956455f4f4e452020666c6f61742066726f6d203120213e20464c4f41545f4e454741544956455f4f4e452c2066" + "61696c65642020464c4f41545f4e454741544956455f4f4e45203c20666c6f61742066726f6d20312020464c4f4154" + "5f4e454741544956455f4f4e4520213c20666c6f61742066726f6d20312c206661696c65640a24242420746573745f" + "666c6f61745f706f77202424242020666c6f61742063756265206f6620313a2020666c6f61742036746820706f7765" + "72206f66202d313a2020666c6f617420737175617265206f6620393a2020666c6f61742030746820706f776572206f" + "6620393a2020666c6f617420737175617265206f6620303a2020666c6f61742030746820706f776572206f66203020" + "28657870656374696e6720494e56414c49445f504152414d53206572726f72293a0a24242420746573745f666c6f61" + "745f726f6f74202424242020666c6f61742073717274206f6620393a2020666c6f61742063627274206f6620393a20" + "20666c6f61742063627274206f6620313030303030303a2020666c6f61742036746820726f6f74206f662031303030" + "3030303a0a24242420746573745f666c6f61745f696e76657274202424242020696e76657274206120666c6f617420" + "66726f6d2031303a2020696e7665727420616761696e3a2020696e766572742074776963653a20676f6f642020696e" + "766572742074776963653a206661696c65640a24242420746573745f666c6f61745f746f5f696e7420242424202066" + "6c6f61745f746f5f696e742831293a20676f6f642020666c6f61745f746f5f696e742831293a206661696c65642020" + "2020676f743a2020666c6f61745f746f5f696e742831293a206661696c65642077697468206572726f722020202065" + "72726f7220636f64653a2020666c6f61745f746f5f696e74282d31293a20676f6f642020666c6f61745f746f5f696e" + "74282d31293a206661696c65642020666c6f61745f746f5f696e74282d31293a206661696c65642077697468206572" + "726f722020666c6f61745f746f5f696e74286936343a3a4d4158293a20676f6f642020666c6f61745f746f5f696e74" + "286936343a3a4d4158293a206661696c65642020202065787065637465643a2020666c6f61745f746f5f696e742869" + "36343a3a4d4158293a206661696c65642077697468206572726f722020666c6f61745f746f5f696e742830293a2067" + "6f6f642020666c6f61745f746f5f696e742830293a206661696c65642020666c6f61745f746f5f696e742830293a20" + "6661696c65642077697468206572726f722020666c6f61745f746f5f696e7428302e312c20746f5f6e656172657374" + "293a20676f6f642020666c6f61745f746f5f696e7428302e312c20746f5f6e656172657374293a206661696c656420" + "20666c6f61745f746f5f696e7428302e312c20746f5f6e656172657374293a206661696c6564207769746820657272" + "6f722020666c6f61745f746f5f696e7428302e312c20746f77617264735f7a65726f293a20676f6f642020666c6f61" + "745f746f5f696e7428302e312c20746f77617264735f7a65726f293a206661696c65642020666c6f61745f746f5f69" + "6e7428302e312c20746f77617264735f7a65726f293a206661696c65642077697468206572726f720a242424207465" + "73745f666c6f61745f66726f6d5f7761736d202424242020666c6f61742066726f6d206936342031323330303a2020" + "666c6f61742066726f6d20693634203132333030206173204845583a2020666c6f61742066726f6d20693634203132" + "3330303a206661696c65642020666c6f61742066726f6d207536342031323330303a2020666c6f61742066726f6d20" + "7536342031323330303a206661696c65642020666c6f61742066726f6d2065787020322c206d616e74697373612031" + "32333a2020666c6f61742066726f6d2065787020322c206d616e7469737361203132333a206661696c65642020666c" + "6f61742066726f6d20636f6e737420313a2020666c6f61742066726f6d20636f6e7374202d313a0a24242420746573" + "745f666c6f61745f6d756c745f6469766964652024242420207265706561746564206d756c7469706c793a20676f6f" + "6420207265706561746564206d756c7469706c793a206661696c656420207265706561746564206469766964653a20" + "676f6f6420207265706561746564206469766964653a206661696c65640a24242420746573745f666c6f61745f746f" + "5f6d616e745f657870202424242020666c6f61745f746f5f6d616e745f6578702831293a20676f6f642020666c6f61" + "745f746f5f6d616e745f6578702831293a206661696c6564202020206578706563746564206d616e74697373612031" + "3030303030303030303030303030303030302c20676f743a202020206578706563746564206578706f6e656e74202d" + "31382c20676f743a2020666c6f61745f746f5f6d616e745f6578702831293a206661696c6564207769746820657272" + "6f722020666c6f61745f746f5f6d616e745f657870282d31293a20676f6f642020666c6f61745f746f5f6d616e745f" + "657870282d31293a206661696c6564202020206578706563746564206d616e7469737361202d313030303030303030" + "303030303030303030302c20676f743a2020666c6f61745f746f5f6d616e745f657870282d31293a206661696c6564" + "2077697468206572726f722020666c6f61745f746f5f6d616e745f657870283130293a20676f6f642020666c6f6174" + "5f746f5f6d616e745f657870283130293a206661696c6564202020206578706563746564206578706f6e656e74202d" + "31372c20676f743a2020666c6f61745f746f5f6d616e745f657870283130293a206661696c65642077697468206572" + "726f722020666c6f61745f746f5f6d616e745f6578702830293a20676f6f642020666c6f61745f746f5f6d616e745f" + "6578702830293a206661696c6564202020206578706563746564206d616e746973736120302c20676f743a20202020" + "6578706563746564206578706f6e656e74202d323134373438333634382c20676f743a2020666c6f61745f746f5f6d" + "616e745f6578702830293a206661696c65642077697468206572726f720a24242420746573745f666c6f61745f6164" + "645f7375627472616374202424242020666c6f61742066726f6d2031303a206661696c656420207265706561746564" + "206164643a20676f6f6420207265706561746564206164643a206661696c6564202072657065617465642073756274" + "726163743a20676f6f64202072657065617465642073756274726163743a206661696c65640a24242420746573745f" + "666c6f61745f66726f6d5f7374616d6f756e74202424242020666c6f61742066726f6d2058525020616d6f756e7420" + "2831303020585250293a202058525020616d6f756e7420636f6e76657273696f6e3a20676f6f64202058525020616d" + "6f756e7420636f6e76657273696f6e3a206661696c6564202020206578706563746564203130303030303030302c20" + "676f743a202058525020616d6f756e7420636f6e76657273696f6e3a206661696c6564202d20666c6f61745f746f5f" + "696e74206572726f722020666c6f61742066726f6d2058525020616d6f756e743a206661696c656420202020726573" + "756c745f73697a653a0a24242420746573745f666c6f61745f66726f6d5f73746e756d626572202424242020666c6f" + "61742066726f6d2053544e756d6265722028313233293a202053544e756d62657220636f6e76657273696f6e3a2067" + "6f6f64202053544e756d62657220636f6e76657273696f6e3a206661696c6564202020206578706563746564203132" + "332c20676f743a202053544e756d62657220636f6e76657273696f6e3a206661696c6564202d20666c6f61745f746f" + "5f696e74206572726f722020666c6f61742066726f6d2053544e756d6265723a206661696c65642020666c6f617420" + "66726f6d2053544e756d626572202831293a202053544e756d626572283129203d3d20464c4f41545f4f4e453a2067" + "6f6f64202053544e756d626572283129203d3d20464c4f41545f4f4e453a206661696c65642020666c6f6174206672" + "6f6d2053544e756d6265722831293a206661696c6564004d0970726f64756365727302086c616e6775616765010452" + "757374000c70726f6365737365642d6279010572757374631d312e39352e3020283539383037363136652032303236" + "2d30342d313429002c0f7461726765745f6665617475726573022b0f6d757461626c652d676c6f62616c732b087369" + "676e2d657874"; + +extern std::string const kFloat0Hex = + "0061736d0100000001290560057f7f7f7f7f017f60047e7f7f7f017f60077f7f7f7f7f7f7f017f60047f7f7f7f017f" + "6000017f02560408686f73745f6c6962057472616365000008686f73745f6c69620e666c6f61745f66726f6d5f696e" + "74000108686f73745f6c696209666c6f61745f737562000208686f73745f6c696209666c6f61745f636d7000030302" + "010405030100110619037f01418080c0000b7f0041e980c0000b7f0041f080c0000b073504066d656d6f727902000d" + "657363726f775f66696e69736800040a5f5f646174615f656e6403010b5f5f686561705f6261736503020acc0101c9" + "0101027f230041206b22002400418080c000411541014100410010001a200041003602082000420037030020004100" + "3602182000420037031002400240420a2000410c41001001410c4604402000410c2000410c200041106a2201410c41" + "001002410c470d012001410c419580c000410c100345044041a180c000411a41014100410010001a0c030b41bb80c0" + "00411941014100410010001a0c020b41d480c000411541014100410010001a0c010b41d480c0004115410141004100" + "10001a0b200041206a240041010b0b720100418080c0000b690a24242420746573745f666c6f61745f302024242400" + "00000000000000800000002020464c4f41545f5a45524f20636f6d706172653a20676f6f642020464c4f41545f5a45" + "524f20636f6d706172653a206261642020666c6f61742031302d31303a206661696c6564004d0970726f6475636572" + "7302086c616e6775616765010452757374000c70726f6365737365642d6279010572757374631d312e39352e302028" + "35393830373631366520323032362d30342d313429002c0f7461726765745f6665617475726573022b0f6d75746162" + "6c652d676c6f62616c732b087369676e2d657874"; + +extern std::string const kDisabledFloatHex = + "0061736d010000000108026000006000017f03030200010503010002063e0a7f004180080b7f004180080b7f004180" + "100b7f004180100b7f00418090040b7f004180080b7f00418090040b7f00418080080b7f0041000b7f0041010b07b7" + "010d066d656d6f72790200115f5f7761736d5f63616c6c5f63746f727300000d657363726f775f66696e6973680001" + "0362756603000c5f5f64736f5f68616e646c6503010a5f5f646174615f656e6403020b5f5f737461636b5f6c6f7703" + "030c5f5f737461636b5f6869676803040d5f5f676c6f62616c5f6261736503050b5f5f686561705f6261736503060a" + "5f5f686561705f656e6403070d5f5f6d656d6f72795f6261736503080c5f5f7461626c655f6261736503090a150202" + "000b100043000000c54300200045931a41010b"; + +extern std::string const kMemoryPointerAtLimitHex = + "0061736d010000000105016000017f0302010005030100010711010d657363726f775f66696e69736800000a0e010c" + "0041ffff032d00001a41010b"; + +extern std::string const kMemoryPointerOverLimitHex = + "0061736d010000000105016000017f0302010005030100010711010d657363726f775f66696e69736800000a0e010c" + "00418080042d00001a41010b"; + +extern std::string const kMemoryOffsetOverLimitHex = + "0061736d010000000105016000017f030201000503010001071a02066d656d6f727902000d657363726f775f66696e" + "69736800000a0e010c00410028028080041a41010b"; + +extern std::string const kMemoryEndOfWordOverLimitHex = + "0061736d010000000105016000017f030201000503010001071a02066d656d6f727902000d657363726f775f66696e" + "69736800000a0e010c0041feff032802001a41010b"; + +extern std::string const kMemoryGrow0To1PageHex = + "0061736d010000000105016000017f030201000503010000071a02066d656d6f727902000d657363726f775f66696e" + "69736800000a0b010900410140001a41010b"; + +extern std::string const kMemoryGrow1To0PageHex = + "0061736d010000000105016000017f030201000503010001071a02066d656d6f727902000d657363726f775f66696e" + "69736800000a13011100417f4000417f460440417f0f0b41010b"; + +extern std::string const kMemoryLastByteOf8MbHex = + "0061736d010000000105016000017f030201000506010180018001071a02066d656d6f727902000d657363726f775f" + "66696e69736800000a0f010d0041ffffff032d00001a41010b"; + +extern std::string const kMemoryGrow1MoreThan8MbHex = + "0061736d010000000105016000017f03020100050401008001071a02066d656d6f727902000d657363726f775f6669" + "6e69736800000a1301110041014000417f460440417f0f0b41010b"; + +extern std::string const kMemoryGrow0MoreThan8MbHex = + "0061736d010000000105016000017f03020100050401008001071a02066d656d6f727902000d657363726f775f6669" + "6e69736800000a1301110041004000417f460440417f0f0b41010b"; + +extern std::string const kMemoryInit1MoreThan8MbHex = + "0061736d010000000105016000017f030201000506010181018101071a02066d656d6f727902000d657363726f775f" + "66696e69736800000a0f010d0041ffffff032d00001a41010b"; + +extern std::string const kMemoryNegativeAddressHex = + "0061736d010000000105016000017f030201000506010180018001071a02066d656d6f727902000d657363726f775f" + "66696e69736800000a0c010a00417f2d00001a41010b"; + +extern std::string const kTable64ElementsHex = + "0061736d010000000108026000006000017f03030200010404017000400711010d657363726f775f66696e69736800" + "010946010041000b400000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000a090202000b040041010b"; + +extern std::string const kTable65ElementsHex = + "0061736d010000000108026000006000017f03030200010404017000410711010d657363726f775f66696e69736800" + "010947010041000b410000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000a090202000b040041010b"; + +extern std::string const kTable2TablesHex = + "0061736d010000000108026000006000017f030302000104090270010101700101010711010d657363726f775f6669" + "6e6973680001090f020041000b0100020141000b0001000a090202000b040041010b"; + +extern std::string const kTable0ElementsHex = + "0061736d010000000105016000017f030201000404017000000711010d657363726f775f66696e69736800000a0601" + "040041010b"; + +extern std::string const kTableUintMaxHex = + "0061736d010000000105016000017f030201000408017000ffffffff0f0711010d657363726f775f66696e69736800" + "000a0601040041010b"; + +extern std::string const kProposalMutableGlobalHex = + "0061736d010000000105016000017f030201000606017f0141000b071b0207636f756e74657203000d657363726f77" + "5f66696e69736800000a0d010b00230041016a240041010b"; + +extern std::string const kProposalGcStructNewHex = + "0061736d01000000010b026000017f5f027f017f01030201000711010d657363726f775f66696e69736800000a0a01" + "0800fb01011a41010b"; + +extern std::string const kProposalMultiValueHex = + "0061736d010000000110036000027f7f6000017f60027f7f017f03030200010711010d657363726f775f66696e6973" + "6800010a14020600410a41140b0b00100002026a411e460b0b"; + +extern std::string const kProposalSignExtHex = + "0061736d010000000105016000017f030201000711010d657363726f775f66696e69736800000a0b01090041ff01c0" + "417f460b"; + +extern std::string const kProposalFloatToIntHex = + "0061736d010000000105016000017f030201000711010d657363726f775f66696e69736800000a1201100043f90215" + "50fc0041ffffffff07460b"; + +extern std::string const kProposalBulkMemoryHex = + "0061736d010000000105016000017f030201000503010001071a02066d656d6f727902000d657363726f775f66696e" + "69736800000a1f011d004100412a3a000041e40041004101fc0a000041e4002d0000412a460b"; + +extern std::string const kProposalRefTypesHex = + "0061736d010000000105016000017f020f0103656e76057461626c65016f0001030201000711010d657363726f775f" + "66696e69736800000a0c010a004100d06f260041010b"; + +extern std::string const kProposalTailCallHex = + "0061736d010000000105016000017f03030200000711010d657363726f775f66696e69736800010a0b02040041010b" + "040012000b"; + +extern std::string const kProposalExtendedConstHex = + "0061736d010000000105016000017f030201000609017f00410a41206a0b0711010d657363726f775f66696e697368" + "00000a090107002300412a460b"; + +extern std::string const kProposalMultiMemoryHex = + "0061736d010000000105016000017f03020100050502000000010711010d657363726f775f66696e69736800000a06" + "0104003f010b"; + +extern std::string const kProposalCustomPageSizesHex = + "0061736d010000000105016000017f030201000504010801000711010d657363726f775f66696e69736800000a0601" + "040041010b"; + +extern std::string const kProposalMemory64Hex = + "0061736d010000000105016000017f0302010005030104010711010d657363726f775f66696e69736800000a10010e" + "004200412a3a00003f004201510b"; + +extern std::string const kProposalWideArithmeticHex = + "0061736d010000000105016000017f030201000711010d657363726f775f66696e69736800000a0e010c0042014202" + "fc161a1a41010b"; + +extern std::string const kTrapDivideBy0Hex = + "0061736d010000000105016000017f030201000711010d657363726f775f66696e69736800000a0c010a00412a4100" + "6d1a41010b"; + +extern std::string const kTrapIntOverflowHex = + "0061736d010000000105016000017f030201000711010d657363726f775f66696e69736800000a0d010b0041808080" + "8078417f6d0b"; + +extern std::string const kTrapUnreachableHex = + "0061736d010000000105016000017f030201000711010d657363726f775f66696e69736800000a070105000041010" + "b"; + +extern std::string const kTrapNullCallHex = + "0061736d010000000105016000017f030201000404017000010711010d657363726f775f66696e69736800000a0901" + "070041001100000b"; + +extern std::string const kTrapFuncSigMismatchHex = + "0061736d010000000108026000006000017f03030200010404017000010711010d657363726f775f66696e69736800" + "010907010041000b01000a0d020300010b070041001101000b"; + +extern std::string const kWasiGetTimeHex = + "0061736d01000000010c0260037f7e7f017f6000017f02290116776173695f736e617073686f745f70726576696577" + "310e636c6f636b5f74696d655f6765740000030201010503010001071a02066d656d6f727902000d657363726f775f" + "66696e69736800010a16011400410042e8074100100045047f410105417f0b0b"; + +extern std::string const kWasiPrintHex = + "0061736d01000000010d0260047f7f7f7f017f6000017f02230116776173695f736e617073686f745f707265766965" + "77310866645f77726974650000030201010503010001071a02066d656d6f727902000d657363726f775f66696e6973" + "6800010a1d011b01017f411821004101410041012000100045047f410105417f0b0b0b1e030041100b0648656c6c6f" + "0a0041000b04100000000041040b0406000000"; + +// The following several wasm hex strings are for testing wasm section +// corruption cases. They are illegal hence do not have corresponding +// rust or wat sources. +// Wasm code magic number is "0061736d", and the only valid version is 1. + +extern std::string const kBadMagicNumberHex = "1061736d01000000"; +extern std::string const kBadVersionNumberHex = "0061736d02000000"; + +// Corruption Test: lyingHeader +// Scenario: A section declares it is 2GB long, but the file ends immediately. +// Attack: Buffer pre-allocation DoS (OOM). +// # Magic (00 61 73 6d) + Version (01 00 00 00) +// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' +// # Type Section (ID 1) +// # Size: LEB128 encoded 2GB (0x80 0x80 0x80 0x80 0x08) +// data += b'\x01\x80\x80\x80\x80\x08' +extern std::string const kLyingHeaderHex = "0061736d01000000018080808008"; + +// Corruption Test: neverEndingNumber +// Scenario: An LEB128 integer that never has a stop bit (byte < 0x80). +// Attack: Infinite loop in parser or read out of bounds. +// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' +// # Type Section (ID 1), Size 5 +// data += b'\x01\x05' +// # Vector count: Infinite stream of 0x80 (100 bytes) +// data += b'\x80' * 100 +extern std::string const kNeverEndingNumberHex = + "0061736d01000000010580808080808080808080808080808080808080808080808080808080808080808080808080" + "8080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080" + "80808080808080808080808080808080"; + +// Corruption Test: vectorLie +// Scenario: A vector declares it has 4 billion items, but provides none. +// Attack: Vector pre-allocation DoS (OOM). +// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' +// # Type Section (ID 1) +// # Size 5 (just enough for the count bytes) +// data += b'\x01\x05' +// # Vector Count: 0xFF 0xFF 0xFF 0xFF 0x0F (4,294,967,295 items) +// data += b'\xff\xff\xff\xff\x0f' +// # No actual items follow... +extern std::string const kVectorLieHex = "0061736d010000000105ffffffff0f"; + +// Corruption Test: sectionOrdering +// Scenario: Sections appear out of order +// (Code section before Function section). +// Attack: Parser state confusion / potential null pointer deref. +// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' +// # Code Section (ID 10) - usually last +// # Size 2, Count 0 +// data += b'\x0a\x02\x00\x0b' +// # Function Section (ID 3) - usually 3rd +// data += b'\x03\x02\x00\x00' +extern std::string const kSectionOrderingHex = "0061736d010000000a02000b03020000"; + +// Corruption Test: ghostPayload +// Scenario: Valid headers, but file is truncated in the middle of a payload. +// Attack: Read out of bounds panic. +// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' +// # Type Section (ID 1), Size 10 +// data += b'\x01\x0a' +// # Content: Count 1 +// data += b'\x01' +// # Start of a type definition (0x60 = func) +// data += b'\x60' +// # File ends abruptly here (missing params/results) +extern std::string const kGhostPayloadHex = "0061736d01000000010a0160"; + +// Corruption Test: junkAfterSection +// Scenario: Section declares size X, but logical content finishes at X-5. +// Attack: Validation bypass if parser stops early, +// or panic if strict check missing. +// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' +// # Type Section (ID 1), Size 10 bytes +// data += b'\x01\x0a' +// # Real content: Count 1, (func -> void) = 4 bytes +// # \x01 (count) \x60 (func) \x00 (0 params) \x00 (0 results) +// data += b'\x01\x60\x00\x00' +// # Remaining 6 bytes are junk padding within the section size +// data += b'\x00' * 6 +extern std::string const kJunkAfterSectionHex = "0061736d01000000010a01600000000000000000"; + +// Corruption Test: invalidSectionId +// Scenario: A section ID that doesn't exist (0xFF). +// Attack: Default case handling / unhandled enum variant. +// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' +// # Section ID 0xFF, Size 1 +// data += b'\xff\x01\x00' +extern std::string const kInvalidSectionIdHex = "0061736d01000000ff0100"; + +// Corruption Test: localVariableBomb +// Scenario: A function declares 4 billion local variables. +// Attack: Stack Overflow / OOM during function init (memset). +// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' +// # 1. Type Section: (func) -> () +// data += b'\x01\x04\x01\x60\x00\x00' +// # 3. Function Section: 1 function of type 0 +// data += b'\x03\x02\x01\x00' +// # 10. Code Section +// # ID 10, Size 15 (estimated), Count 1 +// data += b'\x0a\x0f\x01' +// # Function Body Size: 13 bytes +// data += b'\x0d' +// # Local Declarations Count: 1 entry +// data += b'\x01' +// # The Bomb: 4,294,967,295 locals of type i32 +// # Count: 0xFF 0xFF 0xFF 0xFF 0x0F +// # Type: 0x7F (i32) +// data += b'\xff\xff\xff\xff\x0f\x7f' +// # Instruction: end (0x0b) +// data += b'\x0b' +extern std::string const kLocalVariableBombHex = + "0061736d01000000010401600000030201000a0f010d01ffffffff0f7f0b"; + +extern std::string const kInfiniteLoopWasmHex = + "0061736d010000000108026000006000017f030302000105030100020638097f004180080b7f004180080b7f004180" + "080b7f00418088040b7f004180080b7f00418088040b7f00418080080b7f0041000b7f0041010b07a8010c066d656d" + "6f72790200115f5f7761736d5f63616c6c5f63746f72730000046c6f6f7000010c5f5f64736f5f68616e646c650300" + "0a5f5f646174615f656e6403010b5f5f737461636b5f6c6f7703020c5f5f737461636b5f6869676803030d5f5f676c" + "6f62616c5f6261736503040b5f5f686561705f6261736503050a5f5f686561705f656e6403060d5f5f6d656d6f7279" + "5f6261736503070c5f5f7461626c655f6261736503080a270202000b220041fc87044100360200034041fc870441fc" + "870428020041016a3602000c000b000b007f0970726f647563657273010c70726f6365737365642d62790105636c61" + "6e675f31392e312e352d776173692d73646b202868747470733a2f2f6769746875622e636f6d2f6c6c766d2f6c6c76" + "6d2d70726f6a6563742061623462356132646235383239353861663165653330386137393063666462343262643234" + "3732302900490f7461726765745f6665617475726573042b0f6d757461626c652d676c6f62616c732b087369676e2d" + "6578742b0f7265666572656e63652d74797065732b0a6d756c746976616c7565"; + +extern std::string const kStartLoopHex = + "0061736d010000000108026000006000017f030302000107190205737461727400000d657363726f775f66696e6973" + "6800010801000a0e02070003400c000b0b040041010b"; + extern std::string const kBadAlignWasmHex = "0061736d01000000011b046000017f60057f7f7f7f7f017f60067f7f7f7f7f7f017f60000002260203656e760f666c" "6f61745f66726f6d5f75696e74000103656e7608636865636b5f6964000203050403000000050301000306470b7f00" @@ -647,3 +1148,247 @@ extern std::string const kBadAlignWasmHex = "32393538616631656533303861373930636664623432626432343732302900490f7461726765745f66656174757265" "73042b0f6d757461626c652d676c6f62616c732b087369676e2d6578742b0f7265666572656e63652d74797065732b" "0a6d756c746976616c7565"; + +extern std::string const kThousandParamsHex = + "0061736d0100000001f1070260000060e8077f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f017f030302000105030100020638097f" + "004180080b7f004180080b7f004180080b7f00418088040b7f004180080b7f00418088040b7f00418080080b7f0041" + "000b7f0041010b07a8010c066d656d6f72790200115f5f7761736d5f63616c6c5f63746f7273000004746573740001" + "0c5f5f64736f5f68616e646c6503000a5f5f646174615f656e6403010b5f5f737461636b5f6c6f7703020c5f5f7374" + "61636b5f6869676803030d5f5f676c6f62616c5f6261736503040b5f5f686561705f6261736503050a5f5f68656170" + "5f656e6403060d5f5f6d656d6f72795f6261736503070c5f5f7461626c655f6261736503080aa71e0202000ba11e00" + "200020016a20026a20036a20046a20056a20066a20076a20086a20096a200a6a200b6a200c6a200d6a200e6a200f6a" + "20106a20116a20126a20136a20146a20156a20166a20176a20186a20196a201a6a201b6a201c6a201d6a201e6a201f" + "6a20206a20216a20226a20236a20246a20256a20266a20276a20286a20296a202a6a202b6a202c6a202d6a202e6a20" + "2f6a20306a20316a20326a20336a20346a20356a20366a20376a20386a20396a203a6a203b6a203c6a203d6a203e6a" + "203f6a20406a20416a20426a20436a20446a20456a20466a20476a20486a20496a204a6a204b6a204c6a204d6a204e" + "6a204f6a20506a20516a20526a20536a20546a20556a20566a20576a20586a20596a205a6a205b6a205c6a205d6a20" + "5e6a205f6a20606a20616a20626a20636a20646a20656a20666a20676a20686a20696a206a6a206b6a206c6a206d6a" + "206e6a206f6a20706a20716a20726a20736a20746a20756a20766a20776a20786a20796a207a6a207b6a207c6a207d" + "6a207e6a207f6a2080016a2081016a2082016a2083016a2084016a2085016a2086016a2087016a2088016a2089016a" + "208a016a208b016a208c016a208d016a208e016a208f016a2090016a2091016a2092016a2093016a2094016a209501" + "6a2096016a2097016a2098016a2099016a209a016a209b016a209c016a209d016a209e016a209f016a20a0016a20a1" + "016a20a2016a20a3016a20a4016a20a5016a20a6016a20a7016a20a8016a20a9016a20aa016a20ab016a20ac016a20" + "ad016a20ae016a20af016a20b0016a20b1016a20b2016a20b3016a20b4016a20b5016a20b6016a20b7016a20b8016a" + "20b9016a20ba016a20bb016a20bc016a20bd016a20be016a20bf016a20c0016a20c1016a20c2016a20c3016a20c401" + "6a20c5016a20c6016a20c7016a20c8016a20c9016a20ca016a20cb016a20cc016a20cd016a20ce016a20cf016a20d0" + "016a20d1016a20d2016a20d3016a20d4016a20d5016a20d6016a20d7016a20d8016a20d9016a20da016a20db016a20" + "dc016a20dd016a20de016a20df016a20e0016a20e1016a20e2016a20e3016a20e4016a20e5016a20e6016a20e7016a" + "20e8016a20e9016a20ea016a20eb016a20ec016a20ed016a20ee016a20ef016a20f0016a20f1016a20f2016a20f301" + "6a20f4016a20f5016a20f6016a20f7016a20f8016a20f9016a20fa016a20fb016a20fc016a20fd016a20fe016a20ff" + "016a2080026a2081026a2082026a2083026a2084026a2085026a2086026a2087026a2088026a2089026a208a026a20" + "8b026a208c026a208d026a208e026a208f026a2090026a2091026a2092026a2093026a2094026a2095026a2096026a" + "2097026a2098026a2099026a209a026a209b026a209c026a209d026a209e026a209f026a20a0026a20a1026a20a202" + "6a20a3026a20a4026a20a5026a20a6026a20a7026a20a8026a20a9026a20aa026a20ab026a20ac026a20ad026a20ae" + "026a20af026a20b0026a20b1026a20b2026a20b3026a20b4026a20b5026a20b6026a20b7026a20b8026a20b9026a20" + "ba026a20bb026a20bc026a20bd026a20be026a20bf026a20c0026a20c1026a20c2026a20c3026a20c4026a20c5026a" + "20c6026a20c7026a20c8026a20c9026a20ca026a20cb026a20cc026a20cd026a20ce026a20cf026a20d0026a20d102" + "6a20d2026a20d3026a20d4026a20d5026a20d6026a20d7026a20d8026a20d9026a20da026a20db026a20dc026a20dd" + "026a20de026a20df026a20e0026a20e1026a20e2026a20e3026a20e4026a20e5026a20e6026a20e7026a20e8026a20" + "e9026a20ea026a20eb026a20ec026a20ed026a20ee026a20ef026a20f0026a20f1026a20f2026a20f3026a20f4026a" + "20f5026a20f6026a20f7026a20f8026a20f9026a20fa026a20fb026a20fc026a20fd026a20fe026a20ff026a208003" + "6a2081036a2082036a2083036a2084036a2085036a2086036a2087036a2088036a2089036a208a036a208b036a208c" + "036a208d036a208e036a208f036a2090036a2091036a2092036a2093036a2094036a2095036a2096036a2097036a20" + "98036a2099036a209a036a209b036a209c036a209d036a209e036a209f036a20a0036a20a1036a20a2036a20a3036a" + "20a4036a20a5036a20a6036a20a7036a20a8036a20a9036a20aa036a20ab036a20ac036a20ad036a20ae036a20af03" + "6a20b0036a20b1036a20b2036a20b3036a20b4036a20b5036a20b6036a20b7036a20b8036a20b9036a20ba036a20bb" + "036a20bc036a20bd036a20be036a20bf036a20c0036a20c1036a20c2036a20c3036a20c4036a20c5036a20c6036a20" + "c7036a20c8036a20c9036a20ca036a20cb036a20cc036a20cd036a20ce036a20cf036a20d0036a20d1036a20d2036a" + "20d3036a20d4036a20d5036a20d6036a20d7036a20d8036a20d9036a20da036a20db036a20dc036a20dd036a20de03" + "6a20df036a20e0036a20e1036a20e2036a20e3036a20e4036a20e5036a20e6036a20e7036a20e8036a20e9036a20ea" + "036a20eb036a20ec036a20ed036a20ee036a20ef036a20f0036a20f1036a20f2036a20f3036a20f4036a20f5036a20" + "f6036a20f7036a20f8036a20f9036a20fa036a20fb036a20fc036a20fd036a20fe036a20ff036a2080046a2081046a" + "2082046a2083046a2084046a2085046a2086046a2087046a2088046a2089046a208a046a208b046a208c046a208d04" + "6a208e046a208f046a2090046a2091046a2092046a2093046a2094046a2095046a2096046a2097046a2098046a2099" + "046a209a046a209b046a209c046a209d046a209e046a209f046a20a0046a20a1046a20a2046a20a3046a20a4046a20" + "a5046a20a6046a20a7046a20a8046a20a9046a20aa046a20ab046a20ac046a20ad046a20ae046a20af046a20b0046a" + "20b1046a20b2046a20b3046a20b4046a20b5046a20b6046a20b7046a20b8046a20b9046a20ba046a20bb046a20bc04" + "6a20bd046a20be046a20bf046a20c0046a20c1046a20c2046a20c3046a20c4046a20c5046a20c6046a20c7046a20c8" + "046a20c9046a20ca046a20cb046a20cc046a20cd046a20ce046a20cf046a20d0046a20d1046a20d2046a20d3046a20" + "d4046a20d5046a20d6046a20d7046a20d8046a20d9046a20da046a20db046a20dc046a20dd046a20de046a20df046a" + "20e0046a20e1046a20e2046a20e3046a20e4046a20e5046a20e6046a20e7046a20e8046a20e9046a20ea046a20eb04" + "6a20ec046a20ed046a20ee046a20ef046a20f0046a20f1046a20f2046a20f3046a20f4046a20f5046a20f6046a20f7" + "046a20f8046a20f9046a20fa046a20fb046a20fc046a20fd046a20fe046a20ff046a2080056a2081056a2082056a20" + "83056a2084056a2085056a2086056a2087056a2088056a2089056a208a056a208b056a208c056a208d056a208e056a" + "208f056a2090056a2091056a2092056a2093056a2094056a2095056a2096056a2097056a2098056a2099056a209a05" + "6a209b056a209c056a209d056a209e056a209f056a20a0056a20a1056a20a2056a20a3056a20a4056a20a5056a20a6" + "056a20a7056a20a8056a20a9056a20aa056a20ab056a20ac056a20ad056a20ae056a20af056a20b0056a20b1056a20" + "b2056a20b3056a20b4056a20b5056a20b6056a20b7056a20b8056a20b9056a20ba056a20bb056a20bc056a20bd056a" + "20be056a20bf056a20c0056a20c1056a20c2056a20c3056a20c4056a20c5056a20c6056a20c7056a20c8056a20c905" + "6a20ca056a20cb056a20cc056a20cd056a20ce056a20cf056a20d0056a20d1056a20d2056a20d3056a20d4056a20d5" + "056a20d6056a20d7056a20d8056a20d9056a20da056a20db056a20dc056a20dd056a20de056a20df056a20e0056a20" + "e1056a20e2056a20e3056a20e4056a20e5056a20e6056a20e7056a20e8056a20e9056a20ea056a20eb056a20ec056a" + "20ed056a20ee056a20ef056a20f0056a20f1056a20f2056a20f3056a20f4056a20f5056a20f6056a20f7056a20f805" + "6a20f9056a20fa056a20fb056a20fc056a20fd056a20fe056a20ff056a2080066a2081066a2082066a2083066a2084" + "066a2085066a2086066a2087066a2088066a2089066a208a066a208b066a208c066a208d066a208e066a208f066a20" + "90066a2091066a2092066a2093066a2094066a2095066a2096066a2097066a2098066a2099066a209a066a209b066a" + "209c066a209d066a209e066a209f066a20a0066a20a1066a20a2066a20a3066a20a4066a20a5066a20a6066a20a706" + "6a20a8066a20a9066a20aa066a20ab066a20ac066a20ad066a20ae066a20af066a20b0066a20b1066a20b2066a20b3" + "066a20b4066a20b5066a20b6066a20b7066a20b8066a20b9066a20ba066a20bb066a20bc066a20bd066a20be066a20" + "bf066a20c0066a20c1066a20c2066a20c3066a20c4066a20c5066a20c6066a20c7066a20c8066a20c9066a20ca066a" + "20cb066a20cc066a20cd066a20ce066a20cf066a20d0066a20d1066a20d2066a20d3066a20d4066a20d5066a20d606" + "6a20d7066a20d8066a20d9066a20da066a20db066a20dc066a20dd066a20de066a20df066a20e0066a20e1066a20e2" + "066a20e3066a20e4066a20e5066a20e6066a20e7066a20e8066a20e9066a20ea066a20eb066a20ec066a20ed066a20" + "ee066a20ef066a20f0066a20f1066a20f2066a20f3066a20f4066a20f5066a20f6066a20f7066a20f8066a20f9066a" + "20fa066a20fb066a20fc066a20fd066a20fe066a20ff066a2080076a2081076a2082076a2083076a2084076a208507" + "6a2086076a2087076a2088076a2089076a208a076a208b076a208c076a208d076a208e076a208f076a2090076a2091" + "076a2092076a2093076a2094076a2095076a2096076a2097076a2098076a2099076a209a076a209b076a209c076a20" + "9d076a209e076a209f076a20a0076a20a1076a20a2076a20a3076a20a4076a20a5076a20a6076a20a7076a20a8076a" + "20a9076a20aa076a20ab076a20ac076a20ad076a20ae076a20af076a20b0076a20b1076a20b2076a20b3076a20b407" + "6a20b5076a20b6076a20b7076a20b8076a20b9076a20ba076a20bb076a20bc076a20bd076a20be076a20bf076a20c0" + "076a20c1076a20c2076a20c3076a20c4076a20c5076a20c6076a20c7076a20c8076a20c9076a20ca076a20cb076a20" + "cc076a20cd076a20ce076a20cf076a20d0076a20d1076a20d2076a20d3076a20d4076a20d5076a20d6076a20d7076a" + "20d8076a20d9076a20da076a20db076a20dc076a20dd076a20de076a20df076a20e0076a20e1076a20e2076a20e307" + "6a20e4076a20e5076a20e6076a20e7076a0b007f0970726f647563657273010c70726f6365737365642d6279010563" + "6c616e675f31392e312e352d776173692d73646b202868747470733a2f2f6769746875622e636f6d2f6c6c766d2f6c" + "6c766d2d70726f6a656374206162346235613264623538323935386166316565333038613739306366646234326264" + "32343732302900490f7461726765745f6665617475726573042b0f6d757461626c652d676c6f62616c732b08736967" + "6e2d6578742b0f7265666572656e63652d74797065732b0a6d756c746976616c7565"; + +extern std::string const kThousand1ParamsHex = + "0061736d0100000001f2070260000060e9077f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f017f03030200010503010002063809" + "7f004180080b7f004180080b7f004180080b7f00418088040b7f004180080b7f00418088040b7f00418080080b7f00" + "41000b7f0041010b07a8010c066d656d6f72790200115f5f7761736d5f63616c6c5f63746f72730000047465737400" + "010c5f5f64736f5f68616e646c6503000a5f5f646174615f656e6403010b5f5f737461636b5f6c6f7703020c5f5f73" + "7461636b5f6869676803030d5f5f676c6f62616c5f6261736503040b5f5f686561705f6261736503050a5f5f686561" + "705f656e6403060d5f5f6d656d6f72795f6261736503070c5f5f7461626c655f6261736503080aab1e0202000ba51e" + "00200020016a20026a20036a20046a20056a20066a20076a20086a20096a200a6a200b6a200c6a200d6a200e6a200f" + "6a20106a20116a20126a20136a20146a20156a20166a20176a20186a20196a201a6a201b6a201c6a201d6a201e6a20" + "1f6a20206a20216a20226a20236a20246a20256a20266a20276a20286a20296a202a6a202b6a202c6a202d6a202e6a" + "202f6a20306a20316a20326a20336a20346a20356a20366a20376a20386a20396a203a6a203b6a203c6a203d6a203e" + "6a203f6a20406a20416a20426a20436a20446a20456a20466a20476a20486a20496a204a6a204b6a204c6a204d6a20" + "4e6a204f6a20506a20516a20526a20536a20546a20556a20566a20576a20586a20596a205a6a205b6a205c6a205d6a" + "205e6a205f6a20606a20616a20626a20636a20646a20656a20666a20676a20686a20696a206a6a206b6a206c6a206d" + "6a206e6a206f6a20706a20716a20726a20736a20746a20756a20766a20776a20786a20796a207a6a207b6a207c6a20" + "7d6a207e6a207f6a2080016a2081016a2082016a2083016a2084016a2085016a2086016a2087016a2088016a208901" + "6a208a016a208b016a208c016a208d016a208e016a208f016a2090016a2091016a2092016a2093016a2094016a2095" + "016a2096016a2097016a2098016a2099016a209a016a209b016a209c016a209d016a209e016a209f016a20a0016a20" + "a1016a20a2016a20a3016a20a4016a20a5016a20a6016a20a7016a20a8016a20a9016a20aa016a20ab016a20ac016a" + "20ad016a20ae016a20af016a20b0016a20b1016a20b2016a20b3016a20b4016a20b5016a20b6016a20b7016a20b801" + "6a20b9016a20ba016a20bb016a20bc016a20bd016a20be016a20bf016a20c0016a20c1016a20c2016a20c3016a20c4" + "016a20c5016a20c6016a20c7016a20c8016a20c9016a20ca016a20cb016a20cc016a20cd016a20ce016a20cf016a20" + "d0016a20d1016a20d2016a20d3016a20d4016a20d5016a20d6016a20d7016a20d8016a20d9016a20da016a20db016a" + "20dc016a20dd016a20de016a20df016a20e0016a20e1016a20e2016a20e3016a20e4016a20e5016a20e6016a20e701" + "6a20e8016a20e9016a20ea016a20eb016a20ec016a20ed016a20ee016a20ef016a20f0016a20f1016a20f2016a20f3" + "016a20f4016a20f5016a20f6016a20f7016a20f8016a20f9016a20fa016a20fb016a20fc016a20fd016a20fe016a20" + "ff016a2080026a2081026a2082026a2083026a2084026a2085026a2086026a2087026a2088026a2089026a208a026a" + "208b026a208c026a208d026a208e026a208f026a2090026a2091026a2092026a2093026a2094026a2095026a209602" + "6a2097026a2098026a2099026a209a026a209b026a209c026a209d026a209e026a209f026a20a0026a20a1026a20a2" + "026a20a3026a20a4026a20a5026a20a6026a20a7026a20a8026a20a9026a20aa026a20ab026a20ac026a20ad026a20" + "ae026a20af026a20b0026a20b1026a20b2026a20b3026a20b4026a20b5026a20b6026a20b7026a20b8026a20b9026a" + "20ba026a20bb026a20bc026a20bd026a20be026a20bf026a20c0026a20c1026a20c2026a20c3026a20c4026a20c502" + "6a20c6026a20c7026a20c8026a20c9026a20ca026a20cb026a20cc026a20cd026a20ce026a20cf026a20d0026a20d1" + "026a20d2026a20d3026a20d4026a20d5026a20d6026a20d7026a20d8026a20d9026a20da026a20db026a20dc026a20" + "dd026a20de026a20df026a20e0026a20e1026a20e2026a20e3026a20e4026a20e5026a20e6026a20e7026a20e8026a" + "20e9026a20ea026a20eb026a20ec026a20ed026a20ee026a20ef026a20f0026a20f1026a20f2026a20f3026a20f402" + "6a20f5026a20f6026a20f7026a20f8026a20f9026a20fa026a20fb026a20fc026a20fd026a20fe026a20ff026a2080" + "036a2081036a2082036a2083036a2084036a2085036a2086036a2087036a2088036a2089036a208a036a208b036a20" + "8c036a208d036a208e036a208f036a2090036a2091036a2092036a2093036a2094036a2095036a2096036a2097036a" + "2098036a2099036a209a036a209b036a209c036a209d036a209e036a209f036a20a0036a20a1036a20a2036a20a303" + "6a20a4036a20a5036a20a6036a20a7036a20a8036a20a9036a20aa036a20ab036a20ac036a20ad036a20ae036a20af" + "036a20b0036a20b1036a20b2036a20b3036a20b4036a20b5036a20b6036a20b7036a20b8036a20b9036a20ba036a20" + "bb036a20bc036a20bd036a20be036a20bf036a20c0036a20c1036a20c2036a20c3036a20c4036a20c5036a20c6036a" + "20c7036a20c8036a20c9036a20ca036a20cb036a20cc036a20cd036a20ce036a20cf036a20d0036a20d1036a20d203" + "6a20d3036a20d4036a20d5036a20d6036a20d7036a20d8036a20d9036a20da036a20db036a20dc036a20dd036a20de" + "036a20df036a20e0036a20e1036a20e2036a20e3036a20e4036a20e5036a20e6036a20e7036a20e8036a20e9036a20" + "ea036a20eb036a20ec036a20ed036a20ee036a20ef036a20f0036a20f1036a20f2036a20f3036a20f4036a20f5036a" + "20f6036a20f7036a20f8036a20f9036a20fa036a20fb036a20fc036a20fd036a20fe036a20ff036a2080046a208104" + "6a2082046a2083046a2084046a2085046a2086046a2087046a2088046a2089046a208a046a208b046a208c046a208d" + "046a208e046a208f046a2090046a2091046a2092046a2093046a2094046a2095046a2096046a2097046a2098046a20" + "99046a209a046a209b046a209c046a209d046a209e046a209f046a20a0046a20a1046a20a2046a20a3046a20a4046a" + "20a5046a20a6046a20a7046a20a8046a20a9046a20aa046a20ab046a20ac046a20ad046a20ae046a20af046a20b004" + "6a20b1046a20b2046a20b3046a20b4046a20b5046a20b6046a20b7046a20b8046a20b9046a20ba046a20bb046a20bc" + "046a20bd046a20be046a20bf046a20c0046a20c1046a20c2046a20c3046a20c4046a20c5046a20c6046a20c7046a20" + "c8046a20c9046a20ca046a20cb046a20cc046a20cd046a20ce046a20cf046a20d0046a20d1046a20d2046a20d3046a" + "20d4046a20d5046a20d6046a20d7046a20d8046a20d9046a20da046a20db046a20dc046a20dd046a20de046a20df04" + "6a20e0046a20e1046a20e2046a20e3046a20e4046a20e5046a20e6046a20e7046a20e8046a20e9046a20ea046a20eb" + "046a20ec046a20ed046a20ee046a20ef046a20f0046a20f1046a20f2046a20f3046a20f4046a20f5046a20f6046a20" + "f7046a20f8046a20f9046a20fa046a20fb046a20fc046a20fd046a20fe046a20ff046a2080056a2081056a2082056a" + "2083056a2084056a2085056a2086056a2087056a2088056a2089056a208a056a208b056a208c056a208d056a208e05" + "6a208f056a2090056a2091056a2092056a2093056a2094056a2095056a2096056a2097056a2098056a2099056a209a" + "056a209b056a209c056a209d056a209e056a209f056a20a0056a20a1056a20a2056a20a3056a20a4056a20a5056a20" + "a6056a20a7056a20a8056a20a9056a20aa056a20ab056a20ac056a20ad056a20ae056a20af056a20b0056a20b1056a" + "20b2056a20b3056a20b4056a20b5056a20b6056a20b7056a20b8056a20b9056a20ba056a20bb056a20bc056a20bd05" + "6a20be056a20bf056a20c0056a20c1056a20c2056a20c3056a20c4056a20c5056a20c6056a20c7056a20c8056a20c9" + "056a20ca056a20cb056a20cc056a20cd056a20ce056a20cf056a20d0056a20d1056a20d2056a20d3056a20d4056a20" + "d5056a20d6056a20d7056a20d8056a20d9056a20da056a20db056a20dc056a20dd056a20de056a20df056a20e0056a" + "20e1056a20e2056a20e3056a20e4056a20e5056a20e6056a20e7056a20e8056a20e9056a20ea056a20eb056a20ec05" + "6a20ed056a20ee056a20ef056a20f0056a20f1056a20f2056a20f3056a20f4056a20f5056a20f6056a20f7056a20f8" + "056a20f9056a20fa056a20fb056a20fc056a20fd056a20fe056a20ff056a2080066a2081066a2082066a2083066a20" + "84066a2085066a2086066a2087066a2088066a2089066a208a066a208b066a208c066a208d066a208e066a208f066a" + "2090066a2091066a2092066a2093066a2094066a2095066a2096066a2097066a2098066a2099066a209a066a209b06" + "6a209c066a209d066a209e066a209f066a20a0066a20a1066a20a2066a20a3066a20a4066a20a5066a20a6066a20a7" + "066a20a8066a20a9066a20aa066a20ab066a20ac066a20ad066a20ae066a20af066a20b0066a20b1066a20b2066a20" + "b3066a20b4066a20b5066a20b6066a20b7066a20b8066a20b9066a20ba066a20bb066a20bc066a20bd066a20be066a" + "20bf066a20c0066a20c1066a20c2066a20c3066a20c4066a20c5066a20c6066a20c7066a20c8066a20c9066a20ca06" + "6a20cb066a20cc066a20cd066a20ce066a20cf066a20d0066a20d1066a20d2066a20d3066a20d4066a20d5066a20d6" + "066a20d7066a20d8066a20d9066a20da066a20db066a20dc066a20dd066a20de066a20df066a20e0066a20e1066a20" + "e2066a20e3066a20e4066a20e5066a20e6066a20e7066a20e8066a20e9066a20ea066a20eb066a20ec066a20ed066a" + "20ee066a20ef066a20f0066a20f1066a20f2066a20f3066a20f4066a20f5066a20f6066a20f7066a20f8066a20f906" + "6a20fa066a20fb066a20fc066a20fd066a20fe066a20ff066a2080076a2081076a2082076a2083076a2084076a2085" + "076a2086076a2087076a2088076a2089076a208a076a208b076a208c076a208d076a208e076a208f076a2090076a20" + "91076a2092076a2093076a2094076a2095076a2096076a2097076a2098076a2099076a209a076a209b076a209c076a" + "209d076a209e076a209f076a20a0076a20a1076a20a2076a20a3076a20a4076a20a5076a20a6076a20a7076a20a807" + "6a20a9076a20aa076a20ab076a20ac076a20ad076a20ae076a20af076a20b0076a20b1076a20b2076a20b3076a20b4" + "076a20b5076a20b6076a20b7076a20b8076a20b9076a20ba076a20bb076a20bc076a20bd076a20be076a20bf076a20" + "c0076a20c1076a20c2076a20c3076a20c4076a20c5076a20c6076a20c7076a20c8076a20c9076a20ca076a20cb076a" + "20cc076a20cd076a20ce076a20cf076a20d0076a20d1076a20d2076a20d3076a20d4076a20d5076a20d6076a20d707" + "6a20d8076a20d9076a20da076a20db076a20dc076a20dd076a20de076a20df076a20e0076a20e1076a20e2076a20e3" + "076a20e4076a20e5076a20e6076a20e7076a20e8076a0b007f0970726f647563657273010c70726f6365737365642d" + "62790105636c616e675f31392e312e352d776173692d73646b202868747470733a2f2f6769746875622e636f6d2f6c" + "6c766d2f6c6c766d2d70726f6a65637420616234623561326462353832393538616631656533303861373930636664" + "623432626432343732302900490f7461726765745f6665617475726573042b0f6d757461626c652d676c6f62616c73" + "2b087369676e2d6578742b0f7265666572656e63652d74797065732b0a6d756c746976616c7565"; + +extern std::string const kOpcReservedHex = + "0061736d010000000105016000017f03030200000404017000010503010001060b027f0141000b7e0142000b071401" + "10616c6c5f696e737472756374696f6e7300010907010041000b01000a53020400412a0b4c02017f017e0101010101" + "0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "01010101010101010101010101010101410b0b0b0a010041000b0474657374"; + +extern std::string const kImpExpHex = + "0061736d0100000001100360027f7f017f6000017f60017f017f02330203656e760e6765745f6c65646765725f7371" + "6e000003656e76166765745f706172656e745f6c65646765725f686173680000030403010201050301000107310406" + "6d656d6f72790200096578705f66756e63310002096578705f66756e633200030c746573745f696d706f7274730004" + "0a2b03040041010b0700200041026c0b1c01027f4120410410001a41202802002100410041201001210120000b"; diff --git a/src/test/app/wasm_fixtures/fixtures.h b/src/test/app/wasm_fixtures/fixtures.h index ecb25b73da..2f0a1072f6 100644 --- a/src/test/app/wasm_fixtures/fixtures.h +++ b/src/test/app/wasm_fixtures/fixtures.h @@ -1,5 +1,7 @@ #pragma once +// TODO: consider moving these to separate files (and figure out the build) + #include extern std::string const kLedgerSqnWasmHex; @@ -7,4 +9,75 @@ extern std::string const kAllHostFunctionsWasmHex; extern std::string const kAllKeyletsWasmHex; extern std::string const kCodecovTestsWasmHex; +extern std::string const kFibWasmHex; + +extern std::string const kFloatTestsWasmHex; +extern std::string const kFloat0Hex; +extern std::string const kDisabledFloatHex; + +extern std::string const kMemoryPointerAtLimitHex; +extern std::string const kMemoryPointerOverLimitHex; +extern std::string const kMemoryOffsetOverLimitHex; +extern std::string const kMemoryEndOfWordOverLimitHex; +extern std::string const kMemoryGrow0To1PageHex; +extern std::string const kMemoryGrow1To0PageHex; +extern std::string const kMemoryLastByteOf8MbHex; +extern std::string const kMemoryGrow1MoreThan8MbHex; +extern std::string const kMemoryGrow0MoreThan8MbHex; +extern std::string const kMemoryInit1MoreThan8MbHex; +extern std::string const kMemoryNegativeAddressHex; + +extern std::string const kTable64ElementsHex; +extern std::string const kTable65ElementsHex; +extern std::string const kTable2TablesHex; +extern std::string const kTable0ElementsHex; +extern std::string const kTableUintMaxHex; + +extern std::string const kProposalMutableGlobalHex; +extern std::string const kProposalGcStructNewHex; +extern std::string const kProposalMultiValueHex; +extern std::string const kProposalSignExtHex; +extern std::string const kProposalFloatToIntHex; +extern std::string const kProposalBulkMemoryHex; +extern std::string const kProposalRefTypesHex; +extern std::string const kProposalTailCallHex; +extern std::string const kProposalExtendedConstHex; +extern std::string const kProposalMultiMemoryHex; +extern std::string const kProposalCustomPageSizesHex; +extern std::string const kProposalMemory64Hex; +extern std::string const kProposalWideArithmeticHex; + +extern std::string const kTrapDivideBy0Hex; +extern std::string const kTrapIntOverflowHex; +extern std::string const kTrapUnreachableHex; +extern std::string const kTrapNullCallHex; +extern std::string const kTrapFuncSigMismatchHex; + +extern std::string const kWasiGetTimeHex; +extern std::string const kWasiPrintHex; + +extern std::string const kBadMagicNumberHex; +extern std::string const kBadVersionNumberHex; +extern std::string const kLyingHeaderHex; +extern std::string const kNeverEndingNumberHex; +extern std::string const kVectorLieHex; +extern std::string const kSectionOrderingHex; +extern std::string const kGhostPayloadHex; +extern std::string const kJunkAfterSectionHex; +extern std::string const kInvalidSectionIdHex; +extern std::string const kLocalVariableBombHex; + +extern std::string const kDeepRecursionHex; +extern std::string const kInfiniteLoopWasmHex; +extern std::string const kStartLoopHex; + extern std::string const kBadAlignWasmHex; + +extern std::string const kThousandParamsHex; +extern std::string const kThousand1ParamsHex; +extern std::string const kLocals10kHex; +extern std::string const kFunctions5kHex; + +extern std::string const kOpcReservedHex; + +extern std::string const kImpExpHex; diff --git a/src/test/app/wasm_fixtures/float_0/Cargo.lock b/src/test/app/wasm_fixtures/float_0/Cargo.lock new file mode 100644 index 0000000000..690b1b51f3 --- /dev/null +++ b/src/test/app/wasm_fixtures/float_0/Cargo.lock @@ -0,0 +1,171 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", +] + +[[package]] +name = "float_0" +version = "0.0.1" +dependencies = [ + "xrpl-wasm-stdlib", +] + +[[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "typenum", +] + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "xrpl-macros" +version = "0.1.0" +source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#6b35fe45ac70bad38914e7f319d31d7947e05e25" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "sha2", + "syn", +] + +[[package]] +name = "xrpl-wasm-stdlib" +version = "0.8.0" +source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#6b35fe45ac70bad38914e7f319d31d7947e05e25" +dependencies = [ + "xrpl-macros", +] diff --git a/src/test/app/wasm_fixtures/float_0/Cargo.toml b/src/test/app/wasm_fixtures/float_0/Cargo.toml new file mode 100644 index 0000000000..95254f2e2b --- /dev/null +++ b/src/test/app/wasm_fixtures/float_0/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "float_0" +version = "0.0.1" +edition = "2024" + +# This empty workspace definition keeps this project independent of the parent workspace +[workspace] + +[lib] +crate-type = ["cdylib"] + +[profile.release] +lto = true +opt-level = 's' +panic = "abort" + +[dependencies] +xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" } + +[profile.dev] +panic = "abort" diff --git a/src/test/app/wasm_fixtures/float_0/src/lib.rs b/src/test/app/wasm_fixtures/float_0/src/lib.rs new file mode 100644 index 0000000000..5f6c8f0770 --- /dev/null +++ b/src/test/app/wasm_fixtures/float_0/src/lib.rs @@ -0,0 +1,70 @@ +#![cfg_attr(target_arch = "wasm32", no_std)] + +use xrpl_std::host::trace::trace; +use xrpl_std::host::{float_cmp, float_from_int, float_sub, FLOAT_ROUNDING_MODES_TO_NEAREST}; + +// Float size constant (8 bytes mantissa + 4 bytes exponent) +const FLOAT_SIZE: usize = 12; + +// FLOAT_ZERO constant +const FLOAT_ZERO: [u8; FLOAT_SIZE] = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, +]; + +#[unsafe(no_mangle)] +pub extern "C" fn escrow_finish() -> i32 { + let _ = trace("\n$$$ test_float_0 $$$"); + + // Test: 10 - 10 should equal 0 + let mut f10: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + let mut f_result: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + + // Create float from 10 + if FLOAT_SIZE as i32 + != unsafe { + float_from_int( + 10, + f10.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + } + { + let _ = trace(" float 10-10: failed"); + return 1; + } + + // Subtract: 10 - 10 = 0 + if FLOAT_SIZE as i32 + != unsafe { + float_sub( + f10.as_ptr(), + FLOAT_SIZE, + f10.as_ptr(), + FLOAT_SIZE, + f_result.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + } + { + let _ = trace(" float 10-10: failed"); + return 1; + } + + // Compare result with FLOAT_ZERO constant + if 0 == unsafe { + float_cmp( + f_result.as_ptr(), + FLOAT_SIZE, + FLOAT_ZERO.as_ptr(), + FLOAT_SIZE, + ) + } { + let _ = trace(" FLOAT_ZERO compare: good"); + } else { + let _ = trace(" FLOAT_ZERO compare: bad"); + } + + 1 +} diff --git a/src/test/app/wasm_fixtures/float_tests/Cargo.lock b/src/test/app/wasm_fixtures/float_tests/Cargo.lock new file mode 100644 index 0000000000..92158d3262 --- /dev/null +++ b/src/test/app/wasm_fixtures/float_tests/Cargo.lock @@ -0,0 +1,171 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", +] + +[[package]] +name = "float_tests" +version = "0.0.1" +dependencies = [ + "xrpl-wasm-stdlib", +] + +[[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "typenum", +] + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "syn" +version = "2.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "xrpl-macros" +version = "0.1.0" +source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#6b35fe45ac70bad38914e7f319d31d7947e05e25" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "sha2", + "syn", +] + +[[package]] +name = "xrpl-wasm-stdlib" +version = "0.8.0" +source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#6b35fe45ac70bad38914e7f319d31d7947e05e25" +dependencies = [ + "xrpl-macros", +] diff --git a/src/test/app/wasm_fixtures/float_tests/Cargo.toml b/src/test/app/wasm_fixtures/float_tests/Cargo.toml new file mode 100644 index 0000000000..d4f70f1afc --- /dev/null +++ b/src/test/app/wasm_fixtures/float_tests/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "float_tests" +version = "0.0.1" +edition = "2024" + +# This empty workspace definition keeps this project independent of the parent workspace +[workspace] + +[lib] +crate-type = ["cdylib"] + +[profile.release] +lto = true +opt-level = 's' +panic = "abort" + +[dependencies] +xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" } + +[profile.dev] +panic = "abort" diff --git a/src/test/app/wasm_fixtures/float_tests/src/lib.rs b/src/test/app/wasm_fixtures/float_tests/src/lib.rs new file mode 100644 index 0000000000..b5e6aa6185 --- /dev/null +++ b/src/test/app/wasm_fixtures/float_tests/src/lib.rs @@ -0,0 +1,1112 @@ +#![allow(unused_imports)] +#![allow(unused_variables)] +#![cfg_attr(target_arch = "wasm32", no_std)] + +#[cfg(not(target_arch = "wasm32"))] +extern crate std; + +use xrpl_std::core::locator::Locator; +use xrpl_std::decode_hex_32; +use xrpl_std::host::trace::DataRepr::AsHex; +use xrpl_std::host::trace::{trace, trace_data, trace_num, DataRepr}; +use xrpl_std::host::{ + cache_le, float_add, float_cmp, float_div, float_from_int, float_from_uint, float_mult, + float_pow, float_root, float_sub, le_field, le_inner, le_inner_arr_len, + FLOAT_ROUNDING_MODES_TO_NEAREST, +}; +use xrpl_std::sfield; +use xrpl_std::sfield::{ + Account, AccountTxnID, Balance, Domain, EmailHash, Flags, LedgerEntryType, MessageKey, + OwnerCount, PreviousTxnID, PreviousTxnLgrSeq, RegularKey, Sequence, TicketCount, TransferRate, +}; + +// External host functions not yet in xrpl_std +unsafe extern "C" { + #[link_name = "float_from_stamount"] + fn float_from_stamount( + amount_ptr: *const u8, + amount_len: i32, + out_ptr: *mut u8, + out_len: i32, + rounding: i32, + ) -> i32; + + #[link_name = "float_from_stnumber"] + fn float_from_stnumber( + number_ptr: *const u8, + number_len: i32, + out_ptr: *mut u8, + out_len: i32, + rounding: i32, + ) -> i32; + + #[link_name = "float_to_int"] + fn float_to_int( + float_ptr: *const u8, + float_len: i32, + out_ptr: *mut u8, + out_len: i32, + rounding: i32, + ) -> i32; + + #[link_name = "float_to_mant_exp"] + fn float_to_mant_exp( + float_ptr: *const u8, + float_len: i32, + mantissa_ptr: *mut u8, + mantissa_len: i32, + exponent_ptr: *mut u8, + exponent_len: i32, + ) -> i32; + + #[link_name = "float_from_mant_exp"] + fn float_from_mant_exp( + mantissa: i64, + exponent: i32, + out_ptr: *mut u8, + out_len: i32, + rounding: i32, + ) -> i32; +} + +// Float size constant (8 bytes mantissa + 4 bytes exponent) +const FLOAT_SIZE: usize = 12; + +// Float constants (8 bytes mantissa + 4 bytes exponent, big-endian) +// FLOAT_ONE: mantissa=0x0DE0B6B3A7640000 (10^18), exponent=0xFFFFFFEE (-18) +const FLOAT_ONE: [u8; FLOAT_SIZE] = [ + 0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE, +]; +// FLOAT_NEGATIVE_ONE: mantissa=0xF21F494C589C0000 (-10^18), exponent=0xFFFFFFEE (-18) +const FLOAT_NEGATIVE_ONE: [u8; FLOAT_SIZE] = [ + 0xF2, 0x1F, 0x49, 0x4C, 0x58, 0x9C, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE, +]; + +// Helper function to trace floats +fn trace_float(msg: &str, f: &[u8; FLOAT_SIZE]) { + let _ = trace(msg); + let _ = trace_data(" ", f, AsHex); +} + +fn test_float_from_wasm() -> bool { + let _ = trace("\n$$$ test_float_from_wasm $$$"); + let mut all_pass = true; + + let mut f: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + if FLOAT_SIZE as i32 + == unsafe { + float_from_int( + 12300, + f.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + } + { + let _ = trace_float(" float from i64 12300:", &f); + let _ = trace_data(" float from i64 12300 as HEX:", &f, AsHex); + } else { + let _ = trace(" float from i64 12300: failed"); + all_pass = false; + } + + let u64_value: u64 = 12300; + if FLOAT_SIZE as i32 + == unsafe { + float_from_uint( + &u64_value as *const u64 as *const u8, + 8, + f.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + } + { + let _ = trace_float(" float from u64 12300:", &f); + } else { + let _ = trace(" float from u64 12300: failed"); + all_pass = false; + } + + if FLOAT_SIZE as i32 + == unsafe { + float_from_mant_exp( + 123, + 2, + f.as_mut_ptr(), + FLOAT_SIZE as i32, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + } + { + let _ = trace_float(" float from exp 2, mantissa 123:", &f); + } else { + let _ = trace(" float from exp 2, mantissa 123: failed"); + all_pass = false; + } + + let _ = trace_float(" float from const 1:", &FLOAT_ONE); + let _ = trace_float(" float from const -1:", &FLOAT_NEGATIVE_ONE); + + all_pass +} + +fn test_float_cmp() -> bool { + let _ = trace("\n$$$ test_float_cmp $$$"); + let mut all_pass = true; + + let mut f1: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + if FLOAT_SIZE as i32 + != unsafe { + float_from_int( + 1, + f1.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + } + { + let _ = trace(" float from 1: failed"); + all_pass = false; + } else { + let _ = trace_float(" float from 1:", &f1); + } + + if 0 == unsafe { float_cmp(f1.as_ptr(), FLOAT_SIZE, FLOAT_ONE.as_ptr(), FLOAT_SIZE) } { + let _ = trace(" float from 1 == FLOAT_ONE"); + } else { + let _ = trace(" float from 1 != FLOAT_ONE, failed"); + all_pass = false; + } + + if 1 == unsafe { + float_cmp( + f1.as_ptr(), + FLOAT_SIZE, + FLOAT_NEGATIVE_ONE.as_ptr(), + FLOAT_SIZE, + ) + } { + let _ = trace(" float from 1 > FLOAT_NEGATIVE_ONE"); + } else { + let _ = trace(" float from 1 !> FLOAT_NEGATIVE_ONE, failed"); + all_pass = false; + } + + if 2 == unsafe { + float_cmp( + FLOAT_NEGATIVE_ONE.as_ptr(), + FLOAT_SIZE, + f1.as_ptr(), + FLOAT_SIZE, + ) + } { + let _ = trace(" FLOAT_NEGATIVE_ONE < float from 1"); + } else { + let _ = trace(" FLOAT_NEGATIVE_ONE !< float from 1, failed"); + all_pass = false; + } + + all_pass +} + +fn test_float_add_subtract() -> bool { + let _ = trace("\n$$$ test_float_add_subtract $$$"); + let mut all_pass = true; + + let mut f_compute: [u8; FLOAT_SIZE] = FLOAT_ONE; + for i in 0..9 { + unsafe { + float_add( + f_compute.as_ptr(), + FLOAT_SIZE, + FLOAT_ONE.as_ptr(), + FLOAT_SIZE, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + // let _ = trace_float(" float:", &f_compute); + } + let mut f10: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + if FLOAT_SIZE as i32 + != unsafe { + float_from_int( + 10, + f10.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + } + { + let _ = trace(" float from 10: failed"); + all_pass = false; + } + + if 0 == unsafe { float_cmp(f10.as_ptr(), FLOAT_SIZE, f_compute.as_ptr(), FLOAT_SIZE) } { + let _ = trace(" repeated add: good"); + } else { + let _ = trace(" repeated add: failed"); + all_pass = false; + } + + for i in 0..11 { + unsafe { + float_sub( + f_compute.as_ptr(), + FLOAT_SIZE, + FLOAT_ONE.as_ptr(), + FLOAT_SIZE, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + } + if 0 == unsafe { + float_cmp( + f_compute.as_ptr(), + FLOAT_SIZE, + FLOAT_NEGATIVE_ONE.as_ptr(), + FLOAT_SIZE, + ) + } { + let _ = trace(" repeated subtract: good"); + } else { + let _ = trace(" repeated subtract: failed"); + all_pass = false; + } + + all_pass +} + +fn test_float_mult_divide() -> bool { + let _ = trace("\n$$$ test_float_mult_divide $$$"); + let mut all_pass = true; + + let mut f10: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_from_int( + 10, + f10.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let mut f_compute: [u8; FLOAT_SIZE] = FLOAT_ONE; + for i in 0..6 { + unsafe { + float_mult( + f_compute.as_ptr(), + FLOAT_SIZE, + f10.as_ptr(), + FLOAT_SIZE, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + // let _ = trace_float(" float:", &f_compute); + } + let mut f1000000: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_from_int( + 1000000, + f1000000.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + + if 0 == unsafe { + float_cmp( + f1000000.as_ptr(), + FLOAT_SIZE, + f_compute.as_ptr(), + FLOAT_SIZE, + ) + } { + let _ = trace(" repeated multiply: good"); + } else { + let _ = trace(" repeated multiply: failed"); + all_pass = false; + } + + for i in 0..7 { + unsafe { + float_div( + f_compute.as_ptr(), + FLOAT_SIZE, + f10.as_ptr(), + FLOAT_SIZE, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + } + let mut f01: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_from_mant_exp( + 1, + -1, + f01.as_mut_ptr(), + FLOAT_SIZE as i32, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + + if 0 == unsafe { float_cmp(f_compute.as_ptr(), FLOAT_SIZE, f01.as_ptr(), FLOAT_SIZE) } { + let _ = trace(" repeated divide: good"); + } else { + let _ = trace(" repeated divide: failed"); + all_pass = false; + } + + all_pass +} + +fn test_float_pow() -> bool { + let _ = trace("\n$$$ test_float_pow $$$"); + let mut all_pass = true; + + let mut f_compute: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_pow( + FLOAT_ONE.as_ptr(), + FLOAT_SIZE, + 3, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let _ = trace_float(" float cube of 1:", &f_compute); + + unsafe { + float_pow( + FLOAT_NEGATIVE_ONE.as_ptr(), + FLOAT_SIZE, + 6, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let _ = trace_float(" float 6th power of -1:", &f_compute); + + let mut f9: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_from_int( + 9, + f9.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + unsafe { + float_pow( + f9.as_ptr(), + FLOAT_SIZE, + 2, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let _ = trace_float(" float square of 9:", &f_compute); + + unsafe { + float_pow( + f9.as_ptr(), + FLOAT_SIZE, + 0, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let _ = trace_float(" float 0th power of 9:", &f_compute); + + let mut f0: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_from_int( + 0, + f0.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + unsafe { + float_pow( + f0.as_ptr(), + FLOAT_SIZE, + 2, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let _ = trace_float(" float square of 0:", &f_compute); + + let r = unsafe { + float_pow( + f0.as_ptr(), + FLOAT_SIZE, + 0, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let _ = trace_num( + " float 0th power of 0 (expecting INVALID_PARAMS error):", + r as i64, + ); + + all_pass +} + +fn test_float_root() -> bool { + let _ = trace("\n$$$ test_float_root $$$"); + let mut all_pass = true; + + let mut f9: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_from_int( + 9, + f9.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let mut f_compute: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_root( + f9.as_ptr(), + FLOAT_SIZE, + 2, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let _ = trace_float(" float sqrt of 9:", &f_compute); + unsafe { + float_root( + f9.as_ptr(), + FLOAT_SIZE, + 3, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let _ = trace_float(" float cbrt of 9:", &f_compute); + + let mut f1000000: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_from_int( + 1000000, + f1000000.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + unsafe { + float_root( + f1000000.as_ptr(), + FLOAT_SIZE, + 3, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let _ = trace_float(" float cbrt of 1000000:", &f_compute); + unsafe { + float_root( + f1000000.as_ptr(), + FLOAT_SIZE, + 6, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let _ = trace_float(" float 6th root of 1000000:", &f_compute); + + all_pass +} + +fn test_float_invert() -> bool { + let _ = trace("\n$$$ test_float_invert $$$"); + let mut all_pass = true; + + let mut f_compute: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + let mut f10: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_from_int( + 10, + f10.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + unsafe { + float_div( + FLOAT_ONE.as_ptr(), + FLOAT_SIZE, + f10.as_ptr(), + FLOAT_SIZE, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let _ = trace_float(" invert a float from 10:", &f_compute); + unsafe { + float_div( + FLOAT_ONE.as_ptr(), + FLOAT_SIZE, + f_compute.as_ptr(), + FLOAT_SIZE, + f_compute.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let _ = trace_float(" invert again:", &f_compute); + + // if f10's value is 7, then invert twice won't match the original value + if 0 == unsafe { float_cmp(f10.as_ptr(), FLOAT_SIZE, f_compute.as_ptr(), FLOAT_SIZE) } { + let _ = trace(" invert twice: good"); + } else { + let _ = trace(" invert twice: failed"); + all_pass = false; + } + + all_pass +} + +fn test_float_to_int() -> bool { + let _ = trace("\n$$$ test_float_to_int $$$"); + let mut all_pass = true; + let mut result: [u8; 8] = [0u8; 8]; + + // Test converting FLOAT_ONE (value 1) to int + let ret = unsafe { + float_to_int( + FLOAT_ONE.as_ptr(), + FLOAT_SIZE as i32, + result.as_mut_ptr(), + 8, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + if ret == 8 { + let number = i64::from_le_bytes(result); + if number == 1 { + let _ = trace(" float_to_int(1): good"); + } else { + let _ = trace(" float_to_int(1): failed"); + let _ = trace_num(" got:", number); + all_pass = false; + } + } else { + let _ = trace(" float_to_int(1): failed with error"); + let _ = trace_num(" error code:", ret as i64); + all_pass = false; + } + + // Test converting FLOAT_NEGATIVE_ONE (value -1) to int + let ret = unsafe { + float_to_int( + FLOAT_NEGATIVE_ONE.as_ptr(), + FLOAT_SIZE as i32, + result.as_mut_ptr(), + 8, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + if ret == 8 { + let number = i64::from_le_bytes(result); + if number == -1 { + let _ = trace(" float_to_int(-1): good"); + } else { + let _ = trace(" float_to_int(-1): failed"); + let _ = trace_num(" got:", number); + all_pass = false; + } + } else { + let _ = trace(" float_to_int(-1): failed with error"); + let _ = trace_num(" error code:", ret as i64); + all_pass = false; + } + + // Test converting a larger number (i64::MAX) + let test_val: i64 = i64::MAX; + let mut f_max: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_from_int( + test_val, + f_max.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let ret = unsafe { + float_to_int( + f_max.as_ptr(), + FLOAT_SIZE as i32, + result.as_mut_ptr(), + 8, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + if ret == 8 { + let number = i64::from_le_bytes(result); + if number == test_val { + let _ = trace(" float_to_int(i64::MAX): good"); + } else { + let _ = trace(" float_to_int(i64::MAX): failed"); + let _ = trace_num(" expected:", test_val); + let _ = trace_num(" got:", number); + all_pass = false; + } + } else { + let _ = trace(" float_to_int(i64::MAX): failed with error"); + let _ = trace_num(" error code:", ret as i64); + all_pass = false; + } + + // Test converting zero + let mut f0: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_from_int( + 0, + f0.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let ret = unsafe { + float_to_int( + f0.as_ptr(), + FLOAT_SIZE as i32, + result.as_mut_ptr(), + 8, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + if ret == 8 { + let number = i64::from_le_bytes(result); + if number == 0 { + let _ = trace(" float_to_int(0): good"); + } else { + let _ = trace(" float_to_int(0): failed"); + let _ = trace_num(" got:", number); + all_pass = false; + } + } else { + let _ = trace(" float_to_int(0): failed with error"); + let _ = trace_num(" error code:", ret as i64); + all_pass = false; + } + + // Test rounding with fractional value (0.1) + let mut f01: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_from_mant_exp( + 1, + -1, + f01.as_mut_ptr(), + FLOAT_SIZE as i32, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + let ret = unsafe { + float_to_int( + f01.as_ptr(), + FLOAT_SIZE as i32, + result.as_mut_ptr(), + 8 as i32, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + if ret == 8 as i32 { + let number = i64::from_le_bytes(result); + if number == 0 { + let _ = trace(" float_to_int(0.1, to_nearest): good"); + } else { + let _ = trace(" float_to_int(0.1, to_nearest): failed"); + let _ = trace_num(" got:", number); + all_pass = false; + } + } else { + let _ = trace(" float_to_int(0.1, to_nearest): failed with error"); + let _ = trace_num(" error code:", ret as i64); + all_pass = false; + } + + // Test rounding mode 1 (towards_zero) + let ret = unsafe { + float_to_int( + f01.as_ptr(), + FLOAT_SIZE as i32, + result.as_mut_ptr(), + 8 as i32, + 1, + ) + }; + if ret == 8 as i32 { + let number = i64::from_le_bytes(result); + if number == 0 { + let _ = trace(" float_to_int(0.1, towards_zero): good"); + } else { + let _ = trace(" float_to_int(0.1, towards_zero): failed"); + let _ = trace_num(" got:", number); + all_pass = false; + } + } else { + let _ = trace(" float_to_int(0.1, towards_zero): failed with error"); + let _ = trace_num(" error code:", ret as i64); + all_pass = false; + } + + all_pass +} + +fn test_float_to_mant_exp() -> bool { + let _ = trace("\n$$$ test_float_to_mant_exp $$$"); + let mut all_pass = true; + + // Test with FLOAT_ONE (value 1) + let mut mantissa_bytes: [u8; 8] = [0u8; 8]; + let mut exponent_bytes: [u8; 4] = [0u8; 4]; + let result = unsafe { + float_to_mant_exp( + FLOAT_ONE.as_ptr(), + FLOAT_SIZE as i32, + mantissa_bytes.as_mut_ptr(), + 8, + exponent_bytes.as_mut_ptr(), + 4, + ) + }; + + if result == FLOAT_SIZE as i32 { + let mantissa = i64::from_le_bytes(mantissa_bytes); + let exponent = i32::from_le_bytes(exponent_bytes); + if mantissa == 1000000000000000000 && exponent == -18 { + let _ = trace(" float_to_mant_exp(1): good"); + } else { + let _ = trace(" float_to_mant_exp(1): failed"); + let _ = trace_num(" expected mantissa 1000000000000000000, got:", mantissa); + let _ = trace_num(" expected exponent -18, got:", exponent as i64); + all_pass = false; + } + } else { + let _ = trace(" float_to_mant_exp(1): failed with error"); + let _ = trace_num(" error code:", result as i64); + all_pass = false; + } + + // Test with FLOAT_NEGATIVE_ONE (value -1) + let mut mantissa_bytes: [u8; 8] = [0u8; 8]; + let mut exponent_bytes: [u8; 4] = [0u8; 4]; + let result = unsafe { + float_to_mant_exp( + FLOAT_NEGATIVE_ONE.as_ptr(), + FLOAT_SIZE as i32, + mantissa_bytes.as_mut_ptr(), + 8, + exponent_bytes.as_mut_ptr(), + 4, + ) + }; + + if result == FLOAT_SIZE as i32 { + let mantissa = i64::from_le_bytes(mantissa_bytes); + let exponent = i32::from_le_bytes(exponent_bytes); + if mantissa == -1000000000000000000 && exponent == -18 { + let _ = trace(" float_to_mant_exp(-1): good"); + } else { + let _ = trace(" float_to_mant_exp(-1): failed"); + let _ = trace_num(" expected mantissa -1000000000000000000, got:", mantissa); + let _ = trace_num(" expected exponent -18, got:", exponent as i64); + all_pass = false; + } + } else { + let _ = trace(" float_to_mant_exp(-1): failed with error"); + let _ = trace_num(" error code:", result as i64); + all_pass = false; + } + + // Test with a float created from int (10) + let mut f10: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_from_int( + 10, + f10.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + + let mut mantissa_bytes: [u8; 8] = [0u8; 8]; + let mut exponent_bytes: [u8; 4] = [0u8; 4]; + let result = unsafe { + float_to_mant_exp( + f10.as_ptr(), + FLOAT_SIZE as i32, + mantissa_bytes.as_mut_ptr(), + 8, + exponent_bytes.as_mut_ptr(), + 4, + ) + }; + + if result == FLOAT_SIZE as i32 { + let mantissa = i64::from_le_bytes(mantissa_bytes); + let exponent = i32::from_le_bytes(exponent_bytes); + if mantissa == 1000000000000000000 && exponent == -17 { + let _ = trace(" float_to_mant_exp(10): good"); + } else { + let _ = trace(" float_to_mant_exp(10): failed"); + let _ = trace_num(" expected mantissa 1000000000000000000, got:", mantissa); + let _ = trace_num(" expected exponent -17, got:", exponent as i64); + all_pass = false; + } + } else { + let _ = trace(" float_to_mant_exp(10): failed with error"); + let _ = trace_num(" error code:", result as i64); + all_pass = false; + } + + // Test with zero + let mut f0: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + unsafe { + float_from_int( + 0, + f0.as_mut_ptr(), + FLOAT_SIZE, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + + let mut mantissa_bytes: [u8; 8] = [0u8; 8]; + let mut exponent_bytes: [u8; 4] = [0u8; 4]; + let result = unsafe { + float_to_mant_exp( + f0.as_ptr(), + FLOAT_SIZE as i32, + mantissa_bytes.as_mut_ptr(), + 8, + exponent_bytes.as_mut_ptr(), + 4, + ) + }; + + if result == FLOAT_SIZE as i32 { + let mantissa = i64::from_le_bytes(mantissa_bytes); + let exponent = i32::from_le_bytes(exponent_bytes); + if mantissa == 0 && exponent == -2147483648 { + let _ = trace(" float_to_mant_exp(0): good"); + } else { + let _ = trace(" float_to_mant_exp(0): failed"); + let _ = trace_num(" expected mantissa 0, got:", mantissa); + let _ = trace_num(" expected exponent -2147483648, got:", exponent as i64); + all_pass = false; + } + } else { + let _ = trace(" float_to_mant_exp(0): failed with error"); + let _ = trace_num(" error code:", result as i64); + all_pass = false; + } + + all_pass +} + +fn test_float_from_stamount() -> bool { + let _ = trace("\n$$$ test_float_from_stamount $$$"); + let mut all_pass = true; + + // STAmount is serialized as: + // - 1 byte: type/flags + // - 8 bytes: amount (for XRP) or mantissa (for IOU) + // - For IOU: additional currency and issuer fields + + // Create an XRP amount: 100 XRP = 100,000,000 drops + // XRP format: bit 62 clear (not IOU), bit 63 clear (not negative) + // Amount in drops: 100,000,000 = 0x05F5E100 + let xrp_amount: [u8; 8] = [0x40, 0x00, 0x00, 0x00, 0x05, 0xF5, 0xE1, 0x00]; + + let mut f_result: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + let result_size = unsafe { + float_from_stamount( + xrp_amount.as_ptr(), + 8, + f_result.as_mut_ptr(), + FLOAT_SIZE as i32, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + + if result_size == FLOAT_SIZE as i32 { + let _ = trace_float(" float from XRP amount (100 XRP):", &f_result); + + // Convert back to int to verify + let mut int_bytes: [u8; 8] = [0u8; 8]; + let ret = unsafe { + float_to_int( + f_result.as_ptr(), + FLOAT_SIZE as i32, + int_bytes.as_mut_ptr(), + 8, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + if ret == 8 { + let int_val = i64::from_le_bytes(int_bytes); + if int_val == 100000000 { + let _ = trace(" XRP amount conversion: good"); + } else { + let _ = trace(" XRP amount conversion: failed"); + let _ = trace_num(" expected 100000000, got:", int_val); + all_pass = false; + } + } else { + let _ = trace(" XRP amount conversion: failed - float_to_int error"); + let _ = trace_num(" error code:", ret as i64); + all_pass = false; + } + } else { + let _ = trace(" float from XRP amount: failed"); + let _ = trace_num(" result_size:", result_size as i64); + all_pass = false; + } + + all_pass +} + +fn test_float_from_stnumber() -> bool { + let _ = trace("\n$$$ test_float_from_stnumber $$$"); + let mut all_pass = true; + + // STNumber is serialized as: + // - 8 bytes: mantissa (big-endian signed int64) + // - 4 bytes: exponent (big-endian signed int32) + + // Create STNumber for value 123 (mantissa=123*10^18, exponent=-18) + // mantissa = 123000000000000000000 = 0x6ADF37F675EF6B28000 + // But we need to fit in int64, so use mantissa=123*10^15, exponent=-15 + // 123*10^15 = 123000000000000000 = 0x01B69B4BA630F34000 + let stnumber_123: [u8; 12] = [ + 0x01, 0xB6, 0x9B, 0x4B, 0xA6, 0x30, 0xF3, 0x40, // mantissa + 0xFF, 0xFF, 0xFF, 0xF1, // exponent = -15 + ]; + + let mut f_result: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; + let result_size = unsafe { + float_from_stnumber( + stnumber_123.as_ptr(), + 12, + f_result.as_mut_ptr(), + FLOAT_SIZE as i32, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + + if result_size == FLOAT_SIZE as i32 { + let _ = trace_float(" float from STNumber (123):", &f_result); + + // Convert back to int to verify + let mut int_bytes: [u8; 8] = [0u8; 8]; + let ret = unsafe { + float_to_int( + f_result.as_ptr(), + FLOAT_SIZE as i32, + int_bytes.as_mut_ptr(), + 8, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + if ret == 8 { + let int_val = i64::from_le_bytes(int_bytes); + if int_val == 123 { + let _ = trace(" STNumber conversion: good"); + } else { + let _ = trace(" STNumber conversion: failed"); + let _ = trace_num(" expected 123, got:", int_val); + all_pass = false; + } + } else { + let _ = trace(" STNumber conversion: failed - float_to_int error"); + let _ = trace_num(" error code:", ret as i64); + all_pass = false; + } + } else { + let _ = trace(" float from STNumber: failed"); + let _ = trace_num(" result_size:", result_size as i64); + all_pass = false; + } + + // Test with FLOAT_ONE constant (which is already in STNumber format) + let result_size = unsafe { + float_from_stnumber( + FLOAT_ONE.as_ptr(), + FLOAT_SIZE as i32, + f_result.as_mut_ptr(), + FLOAT_SIZE as i32, + FLOAT_ROUNDING_MODES_TO_NEAREST, + ) + }; + + if result_size == FLOAT_SIZE as i32 { + let _ = trace_float(" float from STNumber (1):", &f_result); + + // Should match FLOAT_ONE + if 0 == unsafe { + float_cmp( + f_result.as_ptr(), + FLOAT_SIZE, + FLOAT_ONE.as_ptr(), + FLOAT_SIZE, + ) + } { + let _ = trace(" STNumber(1) == FLOAT_ONE: good"); + } else { + let _ = trace(" STNumber(1) == FLOAT_ONE: failed"); + all_pass = false; + } + } else { + let _ = trace(" float from STNumber(1): failed"); + all_pass = false; + } + + all_pass +} + +#[unsafe(no_mangle)] +pub extern "C" fn escrow_finish() -> i32 { + let mut all_pass = true; + all_pass &= test_float_from_wasm(); + all_pass &= test_float_cmp(); + all_pass &= test_float_add_subtract(); + all_pass &= test_float_mult_divide(); + all_pass &= test_float_pow(); + all_pass &= test_float_root(); + all_pass &= test_float_invert(); + all_pass &= test_float_to_int(); + all_pass &= test_float_to_mant_exp(); + all_pass &= test_float_from_stamount(); + all_pass &= test_float_from_stnumber(); + + if all_pass { + 1 + } else { + 0 + } +} diff --git a/src/test/app/wasm_fixtures/infiniteLoop.c b/src/test/app/wasm_fixtures/infiniteLoop.c new file mode 100644 index 0000000000..ba84a92ac1 --- /dev/null +++ b/src/test/app/wasm_fixtures/infiniteLoop.c @@ -0,0 +1,7 @@ +int loop() +{ + int volatile x = 0; + while (1) + x++; + return x; +} diff --git a/src/test/app/wasm_fixtures/thousand1_params.c b/src/test/app/wasm_fixtures/thousand1_params.c new file mode 100644 index 0000000000..1a281461c4 --- /dev/null +++ b/src/test/app/wasm_fixtures/thousand1_params.c @@ -0,0 +1,264 @@ +// clang-format off + +#include + +int32_t test( + int32_t p0, int32_t p1, int32_t p2, int32_t p3, int32_t p4, int32_t p5, int32_t p6, int32_t p7 +, int32_t p8, int32_t p9, int32_t p10, int32_t p11, int32_t p12, int32_t p13, int32_t p14, int32_t p15 +, int32_t p16, int32_t p17, int32_t p18, int32_t p19, int32_t p20, int32_t p21, int32_t p22, int32_t p23 +, int32_t p24, int32_t p25, int32_t p26, int32_t p27, int32_t p28, int32_t p29, int32_t p30, int32_t p31 +, int32_t p32, int32_t p33, int32_t p34, int32_t p35, int32_t p36, int32_t p37, int32_t p38, int32_t p39 +, int32_t p40, int32_t p41, int32_t p42, int32_t p43, int32_t p44, int32_t p45, int32_t p46, int32_t p47 +, int32_t p48, int32_t p49, int32_t p50, int32_t p51, int32_t p52, int32_t p53, int32_t p54, int32_t p55 +, int32_t p56, int32_t p57, int32_t p58, int32_t p59, int32_t p60, int32_t p61, int32_t p62, int32_t p63 +, int32_t p64, int32_t p65, int32_t p66, int32_t p67, int32_t p68, int32_t p69, int32_t p70, int32_t p71 +, int32_t p72, int32_t p73, int32_t p74, int32_t p75, int32_t p76, int32_t p77, int32_t p78, int32_t p79 +, int32_t p80, int32_t p81, int32_t p82, int32_t p83, int32_t p84, int32_t p85, int32_t p86, int32_t p87 +, int32_t p88, int32_t p89, int32_t p90, int32_t p91, int32_t p92, int32_t p93, int32_t p94, int32_t p95 +, int32_t p96, int32_t p97, int32_t p98, int32_t p99, int32_t p100, int32_t p101, int32_t p102, int32_t p103 +, int32_t p104, int32_t p105, int32_t p106, int32_t p107, int32_t p108, int32_t p109, int32_t p110, int32_t p111 +, int32_t p112, int32_t p113, int32_t p114, int32_t p115, int32_t p116, int32_t p117, int32_t p118, int32_t p119 +, int32_t p120, int32_t p121, int32_t p122, int32_t p123, int32_t p124, int32_t p125, int32_t p126, int32_t p127 +, int32_t p128, int32_t p129, int32_t p130, int32_t p131, int32_t p132, int32_t p133, int32_t p134, int32_t p135 +, int32_t p136, int32_t p137, int32_t p138, int32_t p139, int32_t p140, int32_t p141, int32_t p142, int32_t p143 +, int32_t p144, int32_t p145, int32_t p146, int32_t p147, int32_t p148, int32_t p149, int32_t p150, int32_t p151 +, int32_t p152, int32_t p153, int32_t p154, int32_t p155, int32_t p156, int32_t p157, int32_t p158, int32_t p159 +, int32_t p160, int32_t p161, int32_t p162, int32_t p163, int32_t p164, int32_t p165, int32_t p166, int32_t p167 +, int32_t p168, int32_t p169, int32_t p170, int32_t p171, int32_t p172, int32_t p173, int32_t p174, int32_t p175 +, int32_t p176, int32_t p177, int32_t p178, int32_t p179, int32_t p180, int32_t p181, int32_t p182, int32_t p183 +, int32_t p184, int32_t p185, int32_t p186, int32_t p187, int32_t p188, int32_t p189, int32_t p190, int32_t p191 +, int32_t p192, int32_t p193, int32_t p194, int32_t p195, int32_t p196, int32_t p197, int32_t p198, int32_t p199 +, int32_t p200, int32_t p201, int32_t p202, int32_t p203, int32_t p204, int32_t p205, int32_t p206, int32_t p207 +, int32_t p208, int32_t p209, int32_t p210, int32_t p211, int32_t p212, int32_t p213, int32_t p214, int32_t p215 +, int32_t p216, int32_t p217, int32_t p218, int32_t p219, int32_t p220, int32_t p221, int32_t p222, int32_t p223 +, int32_t p224, int32_t p225, int32_t p226, int32_t p227, int32_t p228, int32_t p229, int32_t p230, int32_t p231 +, int32_t p232, int32_t p233, int32_t p234, int32_t p235, int32_t p236, int32_t p237, int32_t p238, int32_t p239 +, int32_t p240, int32_t p241, int32_t p242, int32_t p243, int32_t p244, int32_t p245, int32_t p246, int32_t p247 +, int32_t p248, int32_t p249, int32_t p250, int32_t p251, int32_t p252, int32_t p253, int32_t p254, int32_t p255 +, int32_t p256, int32_t p257, int32_t p258, int32_t p259, int32_t p260, int32_t p261, int32_t p262, int32_t p263 +, int32_t p264, int32_t p265, int32_t p266, int32_t p267, int32_t p268, int32_t p269, int32_t p270, int32_t p271 +, int32_t p272, int32_t p273, int32_t p274, int32_t p275, int32_t p276, int32_t p277, int32_t p278, int32_t p279 +, int32_t p280, int32_t p281, int32_t p282, int32_t p283, int32_t p284, int32_t p285, int32_t p286, int32_t p287 +, int32_t p288, int32_t p289, int32_t p290, int32_t p291, int32_t p292, int32_t p293, int32_t p294, int32_t p295 +, int32_t p296, int32_t p297, int32_t p298, int32_t p299, int32_t p300, int32_t p301, int32_t p302, int32_t p303 +, int32_t p304, int32_t p305, int32_t p306, int32_t p307, int32_t p308, int32_t p309, int32_t p310, int32_t p311 +, int32_t p312, int32_t p313, int32_t p314, int32_t p315, int32_t p316, int32_t p317, int32_t p318, int32_t p319 +, int32_t p320, int32_t p321, int32_t p322, int32_t p323, int32_t p324, int32_t p325, int32_t p326, int32_t p327 +, int32_t p328, int32_t p329, int32_t p330, int32_t p331, int32_t p332, int32_t p333, int32_t p334, int32_t p335 +, int32_t p336, int32_t p337, int32_t p338, int32_t p339, int32_t p340, int32_t p341, int32_t p342, int32_t p343 +, int32_t p344, int32_t p345, int32_t p346, int32_t p347, int32_t p348, int32_t p349, int32_t p350, int32_t p351 +, int32_t p352, int32_t p353, int32_t p354, int32_t p355, int32_t p356, int32_t p357, int32_t p358, int32_t p359 +, int32_t p360, int32_t p361, int32_t p362, int32_t p363, int32_t p364, int32_t p365, int32_t p366, int32_t p367 +, int32_t p368, int32_t p369, int32_t p370, int32_t p371, int32_t p372, int32_t p373, int32_t p374, int32_t p375 +, int32_t p376, int32_t p377, int32_t p378, int32_t p379, int32_t p380, int32_t p381, int32_t p382, int32_t p383 +, int32_t p384, int32_t p385, int32_t p386, int32_t p387, int32_t p388, int32_t p389, int32_t p390, int32_t p391 +, int32_t p392, int32_t p393, int32_t p394, int32_t p395, int32_t p396, int32_t p397, int32_t p398, int32_t p399 +, int32_t p400, int32_t p401, int32_t p402, int32_t p403, int32_t p404, int32_t p405, int32_t p406, int32_t p407 +, int32_t p408, int32_t p409, int32_t p410, int32_t p411, int32_t p412, int32_t p413, int32_t p414, int32_t p415 +, int32_t p416, int32_t p417, int32_t p418, int32_t p419, int32_t p420, int32_t p421, int32_t p422, int32_t p423 +, int32_t p424, int32_t p425, int32_t p426, int32_t p427, int32_t p428, int32_t p429, int32_t p430, int32_t p431 +, int32_t p432, int32_t p433, int32_t p434, int32_t p435, int32_t p436, int32_t p437, int32_t p438, int32_t p439 +, int32_t p440, int32_t p441, int32_t p442, int32_t p443, int32_t p444, int32_t p445, int32_t p446, int32_t p447 +, int32_t p448, int32_t p449, int32_t p450, int32_t p451, int32_t p452, int32_t p453, int32_t p454, int32_t p455 +, int32_t p456, int32_t p457, int32_t p458, int32_t p459, int32_t p460, int32_t p461, int32_t p462, int32_t p463 +, int32_t p464, int32_t p465, int32_t p466, int32_t p467, int32_t p468, int32_t p469, int32_t p470, int32_t p471 +, int32_t p472, int32_t p473, int32_t p474, int32_t p475, int32_t p476, int32_t p477, int32_t p478, int32_t p479 +, int32_t p480, int32_t p481, int32_t p482, int32_t p483, int32_t p484, int32_t p485, int32_t p486, int32_t p487 +, int32_t p488, int32_t p489, int32_t p490, int32_t p491, int32_t p492, int32_t p493, int32_t p494, int32_t p495 +, int32_t p496, int32_t p497, int32_t p498, int32_t p499, int32_t p500, int32_t p501, int32_t p502, int32_t p503 +, int32_t p504, int32_t p505, int32_t p506, int32_t p507, int32_t p508, int32_t p509, int32_t p510, int32_t p511 +, int32_t p512, int32_t p513, int32_t p514, int32_t p515, int32_t p516, int32_t p517, int32_t p518, int32_t p519 +, int32_t p520, int32_t p521, int32_t p522, int32_t p523, int32_t p524, int32_t p525, int32_t p526, int32_t p527 +, int32_t p528, int32_t p529, int32_t p530, int32_t p531, int32_t p532, int32_t p533, int32_t p534, int32_t p535 +, int32_t p536, int32_t p537, int32_t p538, int32_t p539, int32_t p540, int32_t p541, int32_t p542, int32_t p543 +, int32_t p544, int32_t p545, int32_t p546, int32_t p547, int32_t p548, int32_t p549, int32_t p550, int32_t p551 +, int32_t p552, int32_t p553, int32_t p554, int32_t p555, int32_t p556, int32_t p557, int32_t p558, int32_t p559 +, int32_t p560, int32_t p561, int32_t p562, int32_t p563, int32_t p564, int32_t p565, int32_t p566, int32_t p567 +, int32_t p568, int32_t p569, int32_t p570, int32_t p571, int32_t p572, int32_t p573, int32_t p574, int32_t p575 +, int32_t p576, int32_t p577, int32_t p578, int32_t p579, int32_t p580, int32_t p581, int32_t p582, int32_t p583 +, int32_t p584, int32_t p585, int32_t p586, int32_t p587, int32_t p588, int32_t p589, int32_t p590, int32_t p591 +, int32_t p592, int32_t p593, int32_t p594, int32_t p595, int32_t p596, int32_t p597, int32_t p598, int32_t p599 +, int32_t p600, int32_t p601, int32_t p602, int32_t p603, int32_t p604, int32_t p605, int32_t p606, int32_t p607 +, int32_t p608, int32_t p609, int32_t p610, int32_t p611, int32_t p612, int32_t p613, int32_t p614, int32_t p615 +, int32_t p616, int32_t p617, int32_t p618, int32_t p619, int32_t p620, int32_t p621, int32_t p622, int32_t p623 +, int32_t p624, int32_t p625, int32_t p626, int32_t p627, int32_t p628, int32_t p629, int32_t p630, int32_t p631 +, int32_t p632, int32_t p633, int32_t p634, int32_t p635, int32_t p636, int32_t p637, int32_t p638, int32_t p639 +, int32_t p640, int32_t p641, int32_t p642, int32_t p643, int32_t p644, int32_t p645, int32_t p646, int32_t p647 +, int32_t p648, int32_t p649, int32_t p650, int32_t p651, int32_t p652, int32_t p653, int32_t p654, int32_t p655 +, int32_t p656, int32_t p657, int32_t p658, int32_t p659, int32_t p660, int32_t p661, int32_t p662, int32_t p663 +, int32_t p664, int32_t p665, int32_t p666, int32_t p667, int32_t p668, int32_t p669, int32_t p670, int32_t p671 +, int32_t p672, int32_t p673, int32_t p674, int32_t p675, int32_t p676, int32_t p677, int32_t p678, int32_t p679 +, int32_t p680, int32_t p681, int32_t p682, int32_t p683, int32_t p684, int32_t p685, int32_t p686, int32_t p687 +, int32_t p688, int32_t p689, int32_t p690, int32_t p691, int32_t p692, int32_t p693, int32_t p694, int32_t p695 +, int32_t p696, int32_t p697, int32_t p698, int32_t p699, int32_t p700, int32_t p701, int32_t p702, int32_t p703 +, int32_t p704, int32_t p705, int32_t p706, int32_t p707, int32_t p708, int32_t p709, int32_t p710, int32_t p711 +, int32_t p712, int32_t p713, int32_t p714, int32_t p715, int32_t p716, int32_t p717, int32_t p718, int32_t p719 +, int32_t p720, int32_t p721, int32_t p722, int32_t p723, int32_t p724, int32_t p725, int32_t p726, int32_t p727 +, int32_t p728, int32_t p729, int32_t p730, int32_t p731, int32_t p732, int32_t p733, int32_t p734, int32_t p735 +, int32_t p736, int32_t p737, int32_t p738, int32_t p739, int32_t p740, int32_t p741, int32_t p742, int32_t p743 +, int32_t p744, int32_t p745, int32_t p746, int32_t p747, int32_t p748, int32_t p749, int32_t p750, int32_t p751 +, int32_t p752, int32_t p753, int32_t p754, int32_t p755, int32_t p756, int32_t p757, int32_t p758, int32_t p759 +, int32_t p760, int32_t p761, int32_t p762, int32_t p763, int32_t p764, int32_t p765, int32_t p766, int32_t p767 +, int32_t p768, int32_t p769, int32_t p770, int32_t p771, int32_t p772, int32_t p773, int32_t p774, int32_t p775 +, int32_t p776, int32_t p777, int32_t p778, int32_t p779, int32_t p780, int32_t p781, int32_t p782, int32_t p783 +, int32_t p784, int32_t p785, int32_t p786, int32_t p787, int32_t p788, int32_t p789, int32_t p790, int32_t p791 +, int32_t p792, int32_t p793, int32_t p794, int32_t p795, int32_t p796, int32_t p797, int32_t p798, int32_t p799 +, int32_t p800, int32_t p801, int32_t p802, int32_t p803, int32_t p804, int32_t p805, int32_t p806, int32_t p807 +, int32_t p808, int32_t p809, int32_t p810, int32_t p811, int32_t p812, int32_t p813, int32_t p814, int32_t p815 +, int32_t p816, int32_t p817, int32_t p818, int32_t p819, int32_t p820, int32_t p821, int32_t p822, int32_t p823 +, int32_t p824, int32_t p825, int32_t p826, int32_t p827, int32_t p828, int32_t p829, int32_t p830, int32_t p831 +, int32_t p832, int32_t p833, int32_t p834, int32_t p835, int32_t p836, int32_t p837, int32_t p838, int32_t p839 +, int32_t p840, int32_t p841, int32_t p842, int32_t p843, int32_t p844, int32_t p845, int32_t p846, int32_t p847 +, int32_t p848, int32_t p849, int32_t p850, int32_t p851, int32_t p852, int32_t p853, int32_t p854, int32_t p855 +, int32_t p856, int32_t p857, int32_t p858, int32_t p859, int32_t p860, int32_t p861, int32_t p862, int32_t p863 +, int32_t p864, int32_t p865, int32_t p866, int32_t p867, int32_t p868, int32_t p869, int32_t p870, int32_t p871 +, int32_t p872, int32_t p873, int32_t p874, int32_t p875, int32_t p876, int32_t p877, int32_t p878, int32_t p879 +, int32_t p880, int32_t p881, int32_t p882, int32_t p883, int32_t p884, int32_t p885, int32_t p886, int32_t p887 +, int32_t p888, int32_t p889, int32_t p890, int32_t p891, int32_t p892, int32_t p893, int32_t p894, int32_t p895 +, int32_t p896, int32_t p897, int32_t p898, int32_t p899, int32_t p900, int32_t p901, int32_t p902, int32_t p903 +, int32_t p904, int32_t p905, int32_t p906, int32_t p907, int32_t p908, int32_t p909, int32_t p910, int32_t p911 +, int32_t p912, int32_t p913, int32_t p914, int32_t p915, int32_t p916, int32_t p917, int32_t p918, int32_t p919 +, int32_t p920, int32_t p921, int32_t p922, int32_t p923, int32_t p924, int32_t p925, int32_t p926, int32_t p927 +, int32_t p928, int32_t p929, int32_t p930, int32_t p931, int32_t p932, int32_t p933, int32_t p934, int32_t p935 +, int32_t p936, int32_t p937, int32_t p938, int32_t p939, int32_t p940, int32_t p941, int32_t p942, int32_t p943 +, int32_t p944, int32_t p945, int32_t p946, int32_t p947, int32_t p948, int32_t p949, int32_t p950, int32_t p951 +, int32_t p952, int32_t p953, int32_t p954, int32_t p955, int32_t p956, int32_t p957, int32_t p958, int32_t p959 +, int32_t p960, int32_t p961, int32_t p962, int32_t p963, int32_t p964, int32_t p965, int32_t p966, int32_t p967 +, int32_t p968, int32_t p969, int32_t p970, int32_t p971, int32_t p972, int32_t p973, int32_t p974, int32_t p975 +, int32_t p976, int32_t p977, int32_t p978, int32_t p979, int32_t p980, int32_t p981, int32_t p982, int32_t p983 +, int32_t p984, int32_t p985, int32_t p986, int32_t p987, int32_t p988, int32_t p989, int32_t p990, int32_t p991 +, int32_t p992, int32_t p993, int32_t p994, int32_t p995, int32_t p996, int32_t p997, int32_t p998, int32_t p999 +, int32_t p1000 +) +{ + int32_t x; + x = p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + + p8 + p9 + p10 + p11 + p12 + p13 + p14 + p15 + + p16 + p17 + p18 + p19 + p20 + p21 + p22 + p23 + + p24 + p25 + p26 + p27 + p28 + p29 + p30 + p31 + + p32 + p33 + p34 + p35 + p36 + p37 + p38 + p39 + + p40 + p41 + p42 + p43 + p44 + p45 + p46 + p47 + + p48 + p49 + p50 + p51 + p52 + p53 + p54 + p55 + + p56 + p57 + p58 + p59 + p60 + p61 + p62 + p63 + + p64 + p65 + p66 + p67 + p68 + p69 + p70 + p71 + + p72 + p73 + p74 + p75 + p76 + p77 + p78 + p79 + + p80 + p81 + p82 + p83 + p84 + p85 + p86 + p87 + + p88 + p89 + p90 + p91 + p92 + p93 + p94 + p95 + + p96 + p97 + p98 + p99 + p100 + p101 + p102 + p103 + + p104 + p105 + p106 + p107 + p108 + p109 + p110 + p111 + + p112 + p113 + p114 + p115 + p116 + p117 + p118 + p119 + + p120 + p121 + p122 + p123 + p124 + p125 + p126 + p127 + + p128 + p129 + p130 + p131 + p132 + p133 + p134 + p135 + + p136 + p137 + p138 + p139 + p140 + p141 + p142 + p143 + + p144 + p145 + p146 + p147 + p148 + p149 + p150 + p151 + + p152 + p153 + p154 + p155 + p156 + p157 + p158 + p159 + + p160 + p161 + p162 + p163 + p164 + p165 + p166 + p167 + + p168 + p169 + p170 + p171 + p172 + p173 + p174 + p175 + + p176 + p177 + p178 + p179 + p180 + p181 + p182 + p183 + + p184 + p185 + p186 + p187 + p188 + p189 + p190 + p191 + + p192 + p193 + p194 + p195 + p196 + p197 + p198 + p199 + + p200 + p201 + p202 + p203 + p204 + p205 + p206 + p207 + + p208 + p209 + p210 + p211 + p212 + p213 + p214 + p215 + + p216 + p217 + p218 + p219 + p220 + p221 + p222 + p223 + + p224 + p225 + p226 + p227 + p228 + p229 + p230 + p231 + + p232 + p233 + p234 + p235 + p236 + p237 + p238 + p239 + + p240 + p241 + p242 + p243 + p244 + p245 + p246 + p247 + + p248 + p249 + p250 + p251 + p252 + p253 + p254 + p255 + + p256 + p257 + p258 + p259 + p260 + p261 + p262 + p263 + + p264 + p265 + p266 + p267 + p268 + p269 + p270 + p271 + + p272 + p273 + p274 + p275 + p276 + p277 + p278 + p279 + + p280 + p281 + p282 + p283 + p284 + p285 + p286 + p287 + + p288 + p289 + p290 + p291 + p292 + p293 + p294 + p295 + + p296 + p297 + p298 + p299 + p300 + p301 + p302 + p303 + + p304 + p305 + p306 + p307 + p308 + p309 + p310 + p311 + + p312 + p313 + p314 + p315 + p316 + p317 + p318 + p319 + + p320 + p321 + p322 + p323 + p324 + p325 + p326 + p327 + + p328 + p329 + p330 + p331 + p332 + p333 + p334 + p335 + + p336 + p337 + p338 + p339 + p340 + p341 + p342 + p343 + + p344 + p345 + p346 + p347 + p348 + p349 + p350 + p351 + + p352 + p353 + p354 + p355 + p356 + p357 + p358 + p359 + + p360 + p361 + p362 + p363 + p364 + p365 + p366 + p367 + + p368 + p369 + p370 + p371 + p372 + p373 + p374 + p375 + + p376 + p377 + p378 + p379 + p380 + p381 + p382 + p383 + + p384 + p385 + p386 + p387 + p388 + p389 + p390 + p391 + + p392 + p393 + p394 + p395 + p396 + p397 + p398 + p399 + + p400 + p401 + p402 + p403 + p404 + p405 + p406 + p407 + + p408 + p409 + p410 + p411 + p412 + p413 + p414 + p415 + + p416 + p417 + p418 + p419 + p420 + p421 + p422 + p423 + + p424 + p425 + p426 + p427 + p428 + p429 + p430 + p431 + + p432 + p433 + p434 + p435 + p436 + p437 + p438 + p439 + + p440 + p441 + p442 + p443 + p444 + p445 + p446 + p447 + + p448 + p449 + p450 + p451 + p452 + p453 + p454 + p455 + + p456 + p457 + p458 + p459 + p460 + p461 + p462 + p463 + + p464 + p465 + p466 + p467 + p468 + p469 + p470 + p471 + + p472 + p473 + p474 + p475 + p476 + p477 + p478 + p479 + + p480 + p481 + p482 + p483 + p484 + p485 + p486 + p487 + + p488 + p489 + p490 + p491 + p492 + p493 + p494 + p495 + + p496 + p497 + p498 + p499 + p500 + p501 + p502 + p503 + + p504 + p505 + p506 + p507 + p508 + p509 + p510 + p511 + + p512 + p513 + p514 + p515 + p516 + p517 + p518 + p519 + + p520 + p521 + p522 + p523 + p524 + p525 + p526 + p527 + + p528 + p529 + p530 + p531 + p532 + p533 + p534 + p535 + + p536 + p537 + p538 + p539 + p540 + p541 + p542 + p543 + + p544 + p545 + p546 + p547 + p548 + p549 + p550 + p551 + + p552 + p553 + p554 + p555 + p556 + p557 + p558 + p559 + + p560 + p561 + p562 + p563 + p564 + p565 + p566 + p567 + + p568 + p569 + p570 + p571 + p572 + p573 + p574 + p575 + + p576 + p577 + p578 + p579 + p580 + p581 + p582 + p583 + + p584 + p585 + p586 + p587 + p588 + p589 + p590 + p591 + + p592 + p593 + p594 + p595 + p596 + p597 + p598 + p599 + + p600 + p601 + p602 + p603 + p604 + p605 + p606 + p607 + + p608 + p609 + p610 + p611 + p612 + p613 + p614 + p615 + + p616 + p617 + p618 + p619 + p620 + p621 + p622 + p623 + + p624 + p625 + p626 + p627 + p628 + p629 + p630 + p631 + + p632 + p633 + p634 + p635 + p636 + p637 + p638 + p639 + + p640 + p641 + p642 + p643 + p644 + p645 + p646 + p647 + + p648 + p649 + p650 + p651 + p652 + p653 + p654 + p655 + + p656 + p657 + p658 + p659 + p660 + p661 + p662 + p663 + + p664 + p665 + p666 + p667 + p668 + p669 + p670 + p671 + + p672 + p673 + p674 + p675 + p676 + p677 + p678 + p679 + + p680 + p681 + p682 + p683 + p684 + p685 + p686 + p687 + + p688 + p689 + p690 + p691 + p692 + p693 + p694 + p695 + + p696 + p697 + p698 + p699 + p700 + p701 + p702 + p703 + + p704 + p705 + p706 + p707 + p708 + p709 + p710 + p711 + + p712 + p713 + p714 + p715 + p716 + p717 + p718 + p719 + + p720 + p721 + p722 + p723 + p724 + p725 + p726 + p727 + + p728 + p729 + p730 + p731 + p732 + p733 + p734 + p735 + + p736 + p737 + p738 + p739 + p740 + p741 + p742 + p743 + + p744 + p745 + p746 + p747 + p748 + p749 + p750 + p751 + + p752 + p753 + p754 + p755 + p756 + p757 + p758 + p759 + + p760 + p761 + p762 + p763 + p764 + p765 + p766 + p767 + + p768 + p769 + p770 + p771 + p772 + p773 + p774 + p775 + + p776 + p777 + p778 + p779 + p780 + p781 + p782 + p783 + + p784 + p785 + p786 + p787 + p788 + p789 + p790 + p791 + + p792 + p793 + p794 + p795 + p796 + p797 + p798 + p799 + + p800 + p801 + p802 + p803 + p804 + p805 + p806 + p807 + + p808 + p809 + p810 + p811 + p812 + p813 + p814 + p815 + + p816 + p817 + p818 + p819 + p820 + p821 + p822 + p823 + + p824 + p825 + p826 + p827 + p828 + p829 + p830 + p831 + + p832 + p833 + p834 + p835 + p836 + p837 + p838 + p839 + + p840 + p841 + p842 + p843 + p844 + p845 + p846 + p847 + + p848 + p849 + p850 + p851 + p852 + p853 + p854 + p855 + + p856 + p857 + p858 + p859 + p860 + p861 + p862 + p863 + + p864 + p865 + p866 + p867 + p868 + p869 + p870 + p871 + + p872 + p873 + p874 + p875 + p876 + p877 + p878 + p879 + + p880 + p881 + p882 + p883 + p884 + p885 + p886 + p887 + + p888 + p889 + p890 + p891 + p892 + p893 + p894 + p895 + + p896 + p897 + p898 + p899 + p900 + p901 + p902 + p903 + + p904 + p905 + p906 + p907 + p908 + p909 + p910 + p911 + + p912 + p913 + p914 + p915 + p916 + p917 + p918 + p919 + + p920 + p921 + p922 + p923 + p924 + p925 + p926 + p927 + + p928 + p929 + p930 + p931 + p932 + p933 + p934 + p935 + + p936 + p937 + p938 + p939 + p940 + p941 + p942 + p943 + + p944 + p945 + p946 + p947 + p948 + p949 + p950 + p951 + + p952 + p953 + p954 + p955 + p956 + p957 + p958 + p959 + + p960 + p961 + p962 + p963 + p964 + p965 + p966 + p967 + + p968 + p969 + p970 + p971 + p972 + p973 + p974 + p975 + + p976 + p977 + p978 + p979 + p980 + p981 + p982 + p983 + + p984 + p985 + p986 + p987 + p988 + p989 + p990 + p991 + + p992 + p993 + p994 + p995 + p996 + p997 + p998 + p999 + + p1000; + return x; +} + +// clang-format on diff --git a/src/test/app/wasm_fixtures/thousand_params.c b/src/test/app/wasm_fixtures/thousand_params.c new file mode 100644 index 0000000000..d934ca38c8 --- /dev/null +++ b/src/test/app/wasm_fixtures/thousand_params.c @@ -0,0 +1,262 @@ +// clang-format off + +#include + +int32_t test( + int32_t p0, int32_t p1, int32_t p2, int32_t p3, int32_t p4, int32_t p5, int32_t p6, int32_t p7 +, int32_t p8, int32_t p9, int32_t p10, int32_t p11, int32_t p12, int32_t p13, int32_t p14, int32_t p15 +, int32_t p16, int32_t p17, int32_t p18, int32_t p19, int32_t p20, int32_t p21, int32_t p22, int32_t p23 +, int32_t p24, int32_t p25, int32_t p26, int32_t p27, int32_t p28, int32_t p29, int32_t p30, int32_t p31 +, int32_t p32, int32_t p33, int32_t p34, int32_t p35, int32_t p36, int32_t p37, int32_t p38, int32_t p39 +, int32_t p40, int32_t p41, int32_t p42, int32_t p43, int32_t p44, int32_t p45, int32_t p46, int32_t p47 +, int32_t p48, int32_t p49, int32_t p50, int32_t p51, int32_t p52, int32_t p53, int32_t p54, int32_t p55 +, int32_t p56, int32_t p57, int32_t p58, int32_t p59, int32_t p60, int32_t p61, int32_t p62, int32_t p63 +, int32_t p64, int32_t p65, int32_t p66, int32_t p67, int32_t p68, int32_t p69, int32_t p70, int32_t p71 +, int32_t p72, int32_t p73, int32_t p74, int32_t p75, int32_t p76, int32_t p77, int32_t p78, int32_t p79 +, int32_t p80, int32_t p81, int32_t p82, int32_t p83, int32_t p84, int32_t p85, int32_t p86, int32_t p87 +, int32_t p88, int32_t p89, int32_t p90, int32_t p91, int32_t p92, int32_t p93, int32_t p94, int32_t p95 +, int32_t p96, int32_t p97, int32_t p98, int32_t p99, int32_t p100, int32_t p101, int32_t p102, int32_t p103 +, int32_t p104, int32_t p105, int32_t p106, int32_t p107, int32_t p108, int32_t p109, int32_t p110, int32_t p111 +, int32_t p112, int32_t p113, int32_t p114, int32_t p115, int32_t p116, int32_t p117, int32_t p118, int32_t p119 +, int32_t p120, int32_t p121, int32_t p122, int32_t p123, int32_t p124, int32_t p125, int32_t p126, int32_t p127 +, int32_t p128, int32_t p129, int32_t p130, int32_t p131, int32_t p132, int32_t p133, int32_t p134, int32_t p135 +, int32_t p136, int32_t p137, int32_t p138, int32_t p139, int32_t p140, int32_t p141, int32_t p142, int32_t p143 +, int32_t p144, int32_t p145, int32_t p146, int32_t p147, int32_t p148, int32_t p149, int32_t p150, int32_t p151 +, int32_t p152, int32_t p153, int32_t p154, int32_t p155, int32_t p156, int32_t p157, int32_t p158, int32_t p159 +, int32_t p160, int32_t p161, int32_t p162, int32_t p163, int32_t p164, int32_t p165, int32_t p166, int32_t p167 +, int32_t p168, int32_t p169, int32_t p170, int32_t p171, int32_t p172, int32_t p173, int32_t p174, int32_t p175 +, int32_t p176, int32_t p177, int32_t p178, int32_t p179, int32_t p180, int32_t p181, int32_t p182, int32_t p183 +, int32_t p184, int32_t p185, int32_t p186, int32_t p187, int32_t p188, int32_t p189, int32_t p190, int32_t p191 +, int32_t p192, int32_t p193, int32_t p194, int32_t p195, int32_t p196, int32_t p197, int32_t p198, int32_t p199 +, int32_t p200, int32_t p201, int32_t p202, int32_t p203, int32_t p204, int32_t p205, int32_t p206, int32_t p207 +, int32_t p208, int32_t p209, int32_t p210, int32_t p211, int32_t p212, int32_t p213, int32_t p214, int32_t p215 +, int32_t p216, int32_t p217, int32_t p218, int32_t p219, int32_t p220, int32_t p221, int32_t p222, int32_t p223 +, int32_t p224, int32_t p225, int32_t p226, int32_t p227, int32_t p228, int32_t p229, int32_t p230, int32_t p231 +, int32_t p232, int32_t p233, int32_t p234, int32_t p235, int32_t p236, int32_t p237, int32_t p238, int32_t p239 +, int32_t p240, int32_t p241, int32_t p242, int32_t p243, int32_t p244, int32_t p245, int32_t p246, int32_t p247 +, int32_t p248, int32_t p249, int32_t p250, int32_t p251, int32_t p252, int32_t p253, int32_t p254, int32_t p255 +, int32_t p256, int32_t p257, int32_t p258, int32_t p259, int32_t p260, int32_t p261, int32_t p262, int32_t p263 +, int32_t p264, int32_t p265, int32_t p266, int32_t p267, int32_t p268, int32_t p269, int32_t p270, int32_t p271 +, int32_t p272, int32_t p273, int32_t p274, int32_t p275, int32_t p276, int32_t p277, int32_t p278, int32_t p279 +, int32_t p280, int32_t p281, int32_t p282, int32_t p283, int32_t p284, int32_t p285, int32_t p286, int32_t p287 +, int32_t p288, int32_t p289, int32_t p290, int32_t p291, int32_t p292, int32_t p293, int32_t p294, int32_t p295 +, int32_t p296, int32_t p297, int32_t p298, int32_t p299, int32_t p300, int32_t p301, int32_t p302, int32_t p303 +, int32_t p304, int32_t p305, int32_t p306, int32_t p307, int32_t p308, int32_t p309, int32_t p310, int32_t p311 +, int32_t p312, int32_t p313, int32_t p314, int32_t p315, int32_t p316, int32_t p317, int32_t p318, int32_t p319 +, int32_t p320, int32_t p321, int32_t p322, int32_t p323, int32_t p324, int32_t p325, int32_t p326, int32_t p327 +, int32_t p328, int32_t p329, int32_t p330, int32_t p331, int32_t p332, int32_t p333, int32_t p334, int32_t p335 +, int32_t p336, int32_t p337, int32_t p338, int32_t p339, int32_t p340, int32_t p341, int32_t p342, int32_t p343 +, int32_t p344, int32_t p345, int32_t p346, int32_t p347, int32_t p348, int32_t p349, int32_t p350, int32_t p351 +, int32_t p352, int32_t p353, int32_t p354, int32_t p355, int32_t p356, int32_t p357, int32_t p358, int32_t p359 +, int32_t p360, int32_t p361, int32_t p362, int32_t p363, int32_t p364, int32_t p365, int32_t p366, int32_t p367 +, int32_t p368, int32_t p369, int32_t p370, int32_t p371, int32_t p372, int32_t p373, int32_t p374, int32_t p375 +, int32_t p376, int32_t p377, int32_t p378, int32_t p379, int32_t p380, int32_t p381, int32_t p382, int32_t p383 +, int32_t p384, int32_t p385, int32_t p386, int32_t p387, int32_t p388, int32_t p389, int32_t p390, int32_t p391 +, int32_t p392, int32_t p393, int32_t p394, int32_t p395, int32_t p396, int32_t p397, int32_t p398, int32_t p399 +, int32_t p400, int32_t p401, int32_t p402, int32_t p403, int32_t p404, int32_t p405, int32_t p406, int32_t p407 +, int32_t p408, int32_t p409, int32_t p410, int32_t p411, int32_t p412, int32_t p413, int32_t p414, int32_t p415 +, int32_t p416, int32_t p417, int32_t p418, int32_t p419, int32_t p420, int32_t p421, int32_t p422, int32_t p423 +, int32_t p424, int32_t p425, int32_t p426, int32_t p427, int32_t p428, int32_t p429, int32_t p430, int32_t p431 +, int32_t p432, int32_t p433, int32_t p434, int32_t p435, int32_t p436, int32_t p437, int32_t p438, int32_t p439 +, int32_t p440, int32_t p441, int32_t p442, int32_t p443, int32_t p444, int32_t p445, int32_t p446, int32_t p447 +, int32_t p448, int32_t p449, int32_t p450, int32_t p451, int32_t p452, int32_t p453, int32_t p454, int32_t p455 +, int32_t p456, int32_t p457, int32_t p458, int32_t p459, int32_t p460, int32_t p461, int32_t p462, int32_t p463 +, int32_t p464, int32_t p465, int32_t p466, int32_t p467, int32_t p468, int32_t p469, int32_t p470, int32_t p471 +, int32_t p472, int32_t p473, int32_t p474, int32_t p475, int32_t p476, int32_t p477, int32_t p478, int32_t p479 +, int32_t p480, int32_t p481, int32_t p482, int32_t p483, int32_t p484, int32_t p485, int32_t p486, int32_t p487 +, int32_t p488, int32_t p489, int32_t p490, int32_t p491, int32_t p492, int32_t p493, int32_t p494, int32_t p495 +, int32_t p496, int32_t p497, int32_t p498, int32_t p499, int32_t p500, int32_t p501, int32_t p502, int32_t p503 +, int32_t p504, int32_t p505, int32_t p506, int32_t p507, int32_t p508, int32_t p509, int32_t p510, int32_t p511 +, int32_t p512, int32_t p513, int32_t p514, int32_t p515, int32_t p516, int32_t p517, int32_t p518, int32_t p519 +, int32_t p520, int32_t p521, int32_t p522, int32_t p523, int32_t p524, int32_t p525, int32_t p526, int32_t p527 +, int32_t p528, int32_t p529, int32_t p530, int32_t p531, int32_t p532, int32_t p533, int32_t p534, int32_t p535 +, int32_t p536, int32_t p537, int32_t p538, int32_t p539, int32_t p540, int32_t p541, int32_t p542, int32_t p543 +, int32_t p544, int32_t p545, int32_t p546, int32_t p547, int32_t p548, int32_t p549, int32_t p550, int32_t p551 +, int32_t p552, int32_t p553, int32_t p554, int32_t p555, int32_t p556, int32_t p557, int32_t p558, int32_t p559 +, int32_t p560, int32_t p561, int32_t p562, int32_t p563, int32_t p564, int32_t p565, int32_t p566, int32_t p567 +, int32_t p568, int32_t p569, int32_t p570, int32_t p571, int32_t p572, int32_t p573, int32_t p574, int32_t p575 +, int32_t p576, int32_t p577, int32_t p578, int32_t p579, int32_t p580, int32_t p581, int32_t p582, int32_t p583 +, int32_t p584, int32_t p585, int32_t p586, int32_t p587, int32_t p588, int32_t p589, int32_t p590, int32_t p591 +, int32_t p592, int32_t p593, int32_t p594, int32_t p595, int32_t p596, int32_t p597, int32_t p598, int32_t p599 +, int32_t p600, int32_t p601, int32_t p602, int32_t p603, int32_t p604, int32_t p605, int32_t p606, int32_t p607 +, int32_t p608, int32_t p609, int32_t p610, int32_t p611, int32_t p612, int32_t p613, int32_t p614, int32_t p615 +, int32_t p616, int32_t p617, int32_t p618, int32_t p619, int32_t p620, int32_t p621, int32_t p622, int32_t p623 +, int32_t p624, int32_t p625, int32_t p626, int32_t p627, int32_t p628, int32_t p629, int32_t p630, int32_t p631 +, int32_t p632, int32_t p633, int32_t p634, int32_t p635, int32_t p636, int32_t p637, int32_t p638, int32_t p639 +, int32_t p640, int32_t p641, int32_t p642, int32_t p643, int32_t p644, int32_t p645, int32_t p646, int32_t p647 +, int32_t p648, int32_t p649, int32_t p650, int32_t p651, int32_t p652, int32_t p653, int32_t p654, int32_t p655 +, int32_t p656, int32_t p657, int32_t p658, int32_t p659, int32_t p660, int32_t p661, int32_t p662, int32_t p663 +, int32_t p664, int32_t p665, int32_t p666, int32_t p667, int32_t p668, int32_t p669, int32_t p670, int32_t p671 +, int32_t p672, int32_t p673, int32_t p674, int32_t p675, int32_t p676, int32_t p677, int32_t p678, int32_t p679 +, int32_t p680, int32_t p681, int32_t p682, int32_t p683, int32_t p684, int32_t p685, int32_t p686, int32_t p687 +, int32_t p688, int32_t p689, int32_t p690, int32_t p691, int32_t p692, int32_t p693, int32_t p694, int32_t p695 +, int32_t p696, int32_t p697, int32_t p698, int32_t p699, int32_t p700, int32_t p701, int32_t p702, int32_t p703 +, int32_t p704, int32_t p705, int32_t p706, int32_t p707, int32_t p708, int32_t p709, int32_t p710, int32_t p711 +, int32_t p712, int32_t p713, int32_t p714, int32_t p715, int32_t p716, int32_t p717, int32_t p718, int32_t p719 +, int32_t p720, int32_t p721, int32_t p722, int32_t p723, int32_t p724, int32_t p725, int32_t p726, int32_t p727 +, int32_t p728, int32_t p729, int32_t p730, int32_t p731, int32_t p732, int32_t p733, int32_t p734, int32_t p735 +, int32_t p736, int32_t p737, int32_t p738, int32_t p739, int32_t p740, int32_t p741, int32_t p742, int32_t p743 +, int32_t p744, int32_t p745, int32_t p746, int32_t p747, int32_t p748, int32_t p749, int32_t p750, int32_t p751 +, int32_t p752, int32_t p753, int32_t p754, int32_t p755, int32_t p756, int32_t p757, int32_t p758, int32_t p759 +, int32_t p760, int32_t p761, int32_t p762, int32_t p763, int32_t p764, int32_t p765, int32_t p766, int32_t p767 +, int32_t p768, int32_t p769, int32_t p770, int32_t p771, int32_t p772, int32_t p773, int32_t p774, int32_t p775 +, int32_t p776, int32_t p777, int32_t p778, int32_t p779, int32_t p780, int32_t p781, int32_t p782, int32_t p783 +, int32_t p784, int32_t p785, int32_t p786, int32_t p787, int32_t p788, int32_t p789, int32_t p790, int32_t p791 +, int32_t p792, int32_t p793, int32_t p794, int32_t p795, int32_t p796, int32_t p797, int32_t p798, int32_t p799 +, int32_t p800, int32_t p801, int32_t p802, int32_t p803, int32_t p804, int32_t p805, int32_t p806, int32_t p807 +, int32_t p808, int32_t p809, int32_t p810, int32_t p811, int32_t p812, int32_t p813, int32_t p814, int32_t p815 +, int32_t p816, int32_t p817, int32_t p818, int32_t p819, int32_t p820, int32_t p821, int32_t p822, int32_t p823 +, int32_t p824, int32_t p825, int32_t p826, int32_t p827, int32_t p828, int32_t p829, int32_t p830, int32_t p831 +, int32_t p832, int32_t p833, int32_t p834, int32_t p835, int32_t p836, int32_t p837, int32_t p838, int32_t p839 +, int32_t p840, int32_t p841, int32_t p842, int32_t p843, int32_t p844, int32_t p845, int32_t p846, int32_t p847 +, int32_t p848, int32_t p849, int32_t p850, int32_t p851, int32_t p852, int32_t p853, int32_t p854, int32_t p855 +, int32_t p856, int32_t p857, int32_t p858, int32_t p859, int32_t p860, int32_t p861, int32_t p862, int32_t p863 +, int32_t p864, int32_t p865, int32_t p866, int32_t p867, int32_t p868, int32_t p869, int32_t p870, int32_t p871 +, int32_t p872, int32_t p873, int32_t p874, int32_t p875, int32_t p876, int32_t p877, int32_t p878, int32_t p879 +, int32_t p880, int32_t p881, int32_t p882, int32_t p883, int32_t p884, int32_t p885, int32_t p886, int32_t p887 +, int32_t p888, int32_t p889, int32_t p890, int32_t p891, int32_t p892, int32_t p893, int32_t p894, int32_t p895 +, int32_t p896, int32_t p897, int32_t p898, int32_t p899, int32_t p900, int32_t p901, int32_t p902, int32_t p903 +, int32_t p904, int32_t p905, int32_t p906, int32_t p907, int32_t p908, int32_t p909, int32_t p910, int32_t p911 +, int32_t p912, int32_t p913, int32_t p914, int32_t p915, int32_t p916, int32_t p917, int32_t p918, int32_t p919 +, int32_t p920, int32_t p921, int32_t p922, int32_t p923, int32_t p924, int32_t p925, int32_t p926, int32_t p927 +, int32_t p928, int32_t p929, int32_t p930, int32_t p931, int32_t p932, int32_t p933, int32_t p934, int32_t p935 +, int32_t p936, int32_t p937, int32_t p938, int32_t p939, int32_t p940, int32_t p941, int32_t p942, int32_t p943 +, int32_t p944, int32_t p945, int32_t p946, int32_t p947, int32_t p948, int32_t p949, int32_t p950, int32_t p951 +, int32_t p952, int32_t p953, int32_t p954, int32_t p955, int32_t p956, int32_t p957, int32_t p958, int32_t p959 +, int32_t p960, int32_t p961, int32_t p962, int32_t p963, int32_t p964, int32_t p965, int32_t p966, int32_t p967 +, int32_t p968, int32_t p969, int32_t p970, int32_t p971, int32_t p972, int32_t p973, int32_t p974, int32_t p975 +, int32_t p976, int32_t p977, int32_t p978, int32_t p979, int32_t p980, int32_t p981, int32_t p982, int32_t p983 +, int32_t p984, int32_t p985, int32_t p986, int32_t p987, int32_t p988, int32_t p989, int32_t p990, int32_t p991 +, int32_t p992, int32_t p993, int32_t p994, int32_t p995, int32_t p996, int32_t p997, int32_t p998, int32_t p999 +) +{ + int32_t x; + x = p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + + p8 + p9 + p10 + p11 + p12 + p13 + p14 + p15 + + p16 + p17 + p18 + p19 + p20 + p21 + p22 + p23 + + p24 + p25 + p26 + p27 + p28 + p29 + p30 + p31 + + p32 + p33 + p34 + p35 + p36 + p37 + p38 + p39 + + p40 + p41 + p42 + p43 + p44 + p45 + p46 + p47 + + p48 + p49 + p50 + p51 + p52 + p53 + p54 + p55 + + p56 + p57 + p58 + p59 + p60 + p61 + p62 + p63 + + p64 + p65 + p66 + p67 + p68 + p69 + p70 + p71 + + p72 + p73 + p74 + p75 + p76 + p77 + p78 + p79 + + p80 + p81 + p82 + p83 + p84 + p85 + p86 + p87 + + p88 + p89 + p90 + p91 + p92 + p93 + p94 + p95 + + p96 + p97 + p98 + p99 + p100 + p101 + p102 + p103 + + p104 + p105 + p106 + p107 + p108 + p109 + p110 + p111 + + p112 + p113 + p114 + p115 + p116 + p117 + p118 + p119 + + p120 + p121 + p122 + p123 + p124 + p125 + p126 + p127 + + p128 + p129 + p130 + p131 + p132 + p133 + p134 + p135 + + p136 + p137 + p138 + p139 + p140 + p141 + p142 + p143 + + p144 + p145 + p146 + p147 + p148 + p149 + p150 + p151 + + p152 + p153 + p154 + p155 + p156 + p157 + p158 + p159 + + p160 + p161 + p162 + p163 + p164 + p165 + p166 + p167 + + p168 + p169 + p170 + p171 + p172 + p173 + p174 + p175 + + p176 + p177 + p178 + p179 + p180 + p181 + p182 + p183 + + p184 + p185 + p186 + p187 + p188 + p189 + p190 + p191 + + p192 + p193 + p194 + p195 + p196 + p197 + p198 + p199 + + p200 + p201 + p202 + p203 + p204 + p205 + p206 + p207 + + p208 + p209 + p210 + p211 + p212 + p213 + p214 + p215 + + p216 + p217 + p218 + p219 + p220 + p221 + p222 + p223 + + p224 + p225 + p226 + p227 + p228 + p229 + p230 + p231 + + p232 + p233 + p234 + p235 + p236 + p237 + p238 + p239 + + p240 + p241 + p242 + p243 + p244 + p245 + p246 + p247 + + p248 + p249 + p250 + p251 + p252 + p253 + p254 + p255 + + p256 + p257 + p258 + p259 + p260 + p261 + p262 + p263 + + p264 + p265 + p266 + p267 + p268 + p269 + p270 + p271 + + p272 + p273 + p274 + p275 + p276 + p277 + p278 + p279 + + p280 + p281 + p282 + p283 + p284 + p285 + p286 + p287 + + p288 + p289 + p290 + p291 + p292 + p293 + p294 + p295 + + p296 + p297 + p298 + p299 + p300 + p301 + p302 + p303 + + p304 + p305 + p306 + p307 + p308 + p309 + p310 + p311 + + p312 + p313 + p314 + p315 + p316 + p317 + p318 + p319 + + p320 + p321 + p322 + p323 + p324 + p325 + p326 + p327 + + p328 + p329 + p330 + p331 + p332 + p333 + p334 + p335 + + p336 + p337 + p338 + p339 + p340 + p341 + p342 + p343 + + p344 + p345 + p346 + p347 + p348 + p349 + p350 + p351 + + p352 + p353 + p354 + p355 + p356 + p357 + p358 + p359 + + p360 + p361 + p362 + p363 + p364 + p365 + p366 + p367 + + p368 + p369 + p370 + p371 + p372 + p373 + p374 + p375 + + p376 + p377 + p378 + p379 + p380 + p381 + p382 + p383 + + p384 + p385 + p386 + p387 + p388 + p389 + p390 + p391 + + p392 + p393 + p394 + p395 + p396 + p397 + p398 + p399 + + p400 + p401 + p402 + p403 + p404 + p405 + p406 + p407 + + p408 + p409 + p410 + p411 + p412 + p413 + p414 + p415 + + p416 + p417 + p418 + p419 + p420 + p421 + p422 + p423 + + p424 + p425 + p426 + p427 + p428 + p429 + p430 + p431 + + p432 + p433 + p434 + p435 + p436 + p437 + p438 + p439 + + p440 + p441 + p442 + p443 + p444 + p445 + p446 + p447 + + p448 + p449 + p450 + p451 + p452 + p453 + p454 + p455 + + p456 + p457 + p458 + p459 + p460 + p461 + p462 + p463 + + p464 + p465 + p466 + p467 + p468 + p469 + p470 + p471 + + p472 + p473 + p474 + p475 + p476 + p477 + p478 + p479 + + p480 + p481 + p482 + p483 + p484 + p485 + p486 + p487 + + p488 + p489 + p490 + p491 + p492 + p493 + p494 + p495 + + p496 + p497 + p498 + p499 + p500 + p501 + p502 + p503 + + p504 + p505 + p506 + p507 + p508 + p509 + p510 + p511 + + p512 + p513 + p514 + p515 + p516 + p517 + p518 + p519 + + p520 + p521 + p522 + p523 + p524 + p525 + p526 + p527 + + p528 + p529 + p530 + p531 + p532 + p533 + p534 + p535 + + p536 + p537 + p538 + p539 + p540 + p541 + p542 + p543 + + p544 + p545 + p546 + p547 + p548 + p549 + p550 + p551 + + p552 + p553 + p554 + p555 + p556 + p557 + p558 + p559 + + p560 + p561 + p562 + p563 + p564 + p565 + p566 + p567 + + p568 + p569 + p570 + p571 + p572 + p573 + p574 + p575 + + p576 + p577 + p578 + p579 + p580 + p581 + p582 + p583 + + p584 + p585 + p586 + p587 + p588 + p589 + p590 + p591 + + p592 + p593 + p594 + p595 + p596 + p597 + p598 + p599 + + p600 + p601 + p602 + p603 + p604 + p605 + p606 + p607 + + p608 + p609 + p610 + p611 + p612 + p613 + p614 + p615 + + p616 + p617 + p618 + p619 + p620 + p621 + p622 + p623 + + p624 + p625 + p626 + p627 + p628 + p629 + p630 + p631 + + p632 + p633 + p634 + p635 + p636 + p637 + p638 + p639 + + p640 + p641 + p642 + p643 + p644 + p645 + p646 + p647 + + p648 + p649 + p650 + p651 + p652 + p653 + p654 + p655 + + p656 + p657 + p658 + p659 + p660 + p661 + p662 + p663 + + p664 + p665 + p666 + p667 + p668 + p669 + p670 + p671 + + p672 + p673 + p674 + p675 + p676 + p677 + p678 + p679 + + p680 + p681 + p682 + p683 + p684 + p685 + p686 + p687 + + p688 + p689 + p690 + p691 + p692 + p693 + p694 + p695 + + p696 + p697 + p698 + p699 + p700 + p701 + p702 + p703 + + p704 + p705 + p706 + p707 + p708 + p709 + p710 + p711 + + p712 + p713 + p714 + p715 + p716 + p717 + p718 + p719 + + p720 + p721 + p722 + p723 + p724 + p725 + p726 + p727 + + p728 + p729 + p730 + p731 + p732 + p733 + p734 + p735 + + p736 + p737 + p738 + p739 + p740 + p741 + p742 + p743 + + p744 + p745 + p746 + p747 + p748 + p749 + p750 + p751 + + p752 + p753 + p754 + p755 + p756 + p757 + p758 + p759 + + p760 + p761 + p762 + p763 + p764 + p765 + p766 + p767 + + p768 + p769 + p770 + p771 + p772 + p773 + p774 + p775 + + p776 + p777 + p778 + p779 + p780 + p781 + p782 + p783 + + p784 + p785 + p786 + p787 + p788 + p789 + p790 + p791 + + p792 + p793 + p794 + p795 + p796 + p797 + p798 + p799 + + p800 + p801 + p802 + p803 + p804 + p805 + p806 + p807 + + p808 + p809 + p810 + p811 + p812 + p813 + p814 + p815 + + p816 + p817 + p818 + p819 + p820 + p821 + p822 + p823 + + p824 + p825 + p826 + p827 + p828 + p829 + p830 + p831 + + p832 + p833 + p834 + p835 + p836 + p837 + p838 + p839 + + p840 + p841 + p842 + p843 + p844 + p845 + p846 + p847 + + p848 + p849 + p850 + p851 + p852 + p853 + p854 + p855 + + p856 + p857 + p858 + p859 + p860 + p861 + p862 + p863 + + p864 + p865 + p866 + p867 + p868 + p869 + p870 + p871 + + p872 + p873 + p874 + p875 + p876 + p877 + p878 + p879 + + p880 + p881 + p882 + p883 + p884 + p885 + p886 + p887 + + p888 + p889 + p890 + p891 + p892 + p893 + p894 + p895 + + p896 + p897 + p898 + p899 + p900 + p901 + p902 + p903 + + p904 + p905 + p906 + p907 + p908 + p909 + p910 + p911 + + p912 + p913 + p914 + p915 + p916 + p917 + p918 + p919 + + p920 + p921 + p922 + p923 + p924 + p925 + p926 + p927 + + p928 + p929 + p930 + p931 + p932 + p933 + p934 + p935 + + p936 + p937 + p938 + p939 + p940 + p941 + p942 + p943 + + p944 + p945 + p946 + p947 + p948 + p949 + p950 + p951 + + p952 + p953 + p954 + p955 + p956 + p957 + p958 + p959 + + p960 + p961 + p962 + p963 + p964 + p965 + p966 + p967 + + p968 + p969 + p970 + p971 + p972 + p973 + p974 + p975 + + p976 + p977 + p978 + p979 + p980 + p981 + p982 + p983 + + p984 + p985 + p986 + p987 + p988 + p989 + p990 + p991 + + p992 + p993 + p994 + p995 + p996 + p997 + p998 + p999; + return x; +} + +// clang-format on diff --git a/src/test/app/wasm_fixtures/wat/custom_page_sizes.wat b/src/test/app/wasm_fixtures/wat/custom_page_sizes.wat new file mode 100644 index 0000000000..c0bf1c3a11 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/custom_page_sizes.wat @@ -0,0 +1,13 @@ +(module + ;; Define a memory with 1 initial page. + ;; CRITICAL: We explicitly set the page size to 1 byte. + ;; Standard Wasm implies (pagesize 65536). + (memory 1 (pagesize 1)) + + (func $escrow_finish (result i32) + ;; If this module instantiates, the runtime accepted the custom page size. + i32.const 1 + ) + + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/deep_recursion.wat b/src/test/app/wasm_fixtures/wat/deep_recursion.wat new file mode 100644 index 0000000000..efe20cf53d --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/deep_recursion.wat @@ -0,0 +1,29 @@ +(module + ;; Define a Mutable Global Variable to act as our counter. + ;; We initialize it to 1,000,000. + (global $counter (mut i32) (i32.const 1000000)) + + (func $escrow_finish (result i32) + ;; 1. Check if counter == 0 (Base Case) + global.get $counter + i32.eqz + if + ;; If counter is 0, we are done. Return 1. + i32.const 1 + return + end + + ;; 2. Decrement the Global Counter + global.get $counter + i32.const 1 + i32.sub + global.set $counter + + ;; 3. Recursive Step: Call SELF + ;; This puts an i32 (1) on the stack when it returns. + call $escrow_finish + ) + + ;; Export the only function we have + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/functions_5k.zip b/src/test/app/wasm_fixtures/wat/functions_5k.zip new file mode 100644 index 0000000000000000000000000000000000000000..e261760545516dd244df3d31cc5a3acd4fb5685c GIT binary patch literal 29665 zcmeI5eQXnT7{@z?8!z&bi7dPav(pd)mmn`9LW2abUWj8V1h#P?bA}Oiy1@vH-Z^nG zfRp4RUNFL<6xj=7IvvH1^@IW11mwlxa0R-_0@AJR+O4nGyYttZiNVO~uKjP%wmeOq z`{maA_Q~bx=Xrk5r4xxm$7wXfhH2Kn{chG*3#Kn13pJYk+eT@|YBZYM9r>HLZ=v!F z$$496@7%Qg^6gbs^Rjp5J}_mv*_@^OrZ4QFuGIg$;Y{)~$LA)^zznao-Cs0y(&oYy z$(Lqt%N=?yds2O;OA3-wyHnTD6kEgnzY3d=n#3j7Z4=W8^Q`!plEt zWiKw@t96Z(J4tz>>~CU1oGkg#8D&2cww8~%=aJ9$=pXWus0}yyWqu>Ik*e@N>-%~) zwTY_q&-b0)?b_(7@K5bpY;Qc!SbewnTYr^*Ntgb9V~M%cL=DL7Gaolm12U!NLndlK zrp#P#q6TF4n#)YofK0M}k=;C{*HIx9T{9kYT9?{BF;P*Rr~kB82?H`k*NxRq>vG#E z6P2oOu$!}c9aTa!=NNsl-MqNhQ7QPY8BaK^%WOwYRKL!{!gwt&jL+lK+PDu}@!Vk?`(z5ZL6fKf5f0ulz9C@4`Lvs~?mVumC)sWy!@;G6S#X0UQ3Im+s>^(+ z6`v8nj{Araw60QQKOi&mctacaDY!wCr~$#y{u*@aX~MVElQ+7F^$u=sm|Y`aqj&?j zL6fKf(bLmF9rF=Mv;}27CFGnuKBtZQxD}rez`zZfL=A|AD1$C)rY$980a#EVjtWR& zr?pCCOUXKPPip5*w&LpoShbHBPg}qZnnVo&b$4E(hD_z{4&T9+4BRw_C`a7Tt zhkb;U)m(f%`r7|Edy1A9S@g~~{O^DG$Vo0-rTC7k%NtV%_^$sxiMt0by}u9l5v~6T zhh`dm>ds8S-6_EORkD81gPk_O-N5?Q);}^3K3D^|8(6>E`iF!HaDcmk^{cIaTt<|j z3~)EFewD1h17*aa2G+l{vuO!1~qJKYoZ*=5ErKQnCOnC=f>l1e9~1 z@DWqPELcz=UJAV9BRmftthGfTbfUt%F@<^0RG4?mt(i`%F~5&|pHuL7ANiiGEGoW* z8ir$H$idhcvJ?|OXJf0 zb2ZTP4J81TC4i2|27)&QES0u^1qI@$fD7f^M_ch--2_-rAZ`l$j#rkKlX?O5aF0@$ zH>WV~QwsCW-mG+c_mS^p1&_~C$ajOX$hoQ3M8(vC-5eW3_QrLQG#`+Tro z`YH!^0VP?bF!}^a0BTDBX#T(~7<~eBU(^o0@gjTxV?Lse`G9dSj~S8k5EbCI!srty z0jMkiSR(zqF!}`MzNj5~^9#zLr=ZQ{ZQNwApg{Z-s6&;x(=hr3=Dw&MdK1||u-3t4 z1u(FnKpYh~i*oMbJig-`z6&fU5HAICc>_b!UI&^3vY?N7_f0rCuXKBtDRWMe6!JYq z!Q;k0^4+)Sqei<~jAeq!jo27+Z*2Hnj18a5G2!z;d+GIL3QDpD=>TwxeDm^=r(R)) zCX8)9XvxcV=XO6=6nY_H<)+W|cD|#D^i<017{+o!B9?@)@(>>E=JvpWxJZ&lGy0KU zG9^H~EOJ97HeJR___St5*M<)VH)s+yAS5aDnVnB_bA}ME3uBcMk;3SzWcC8df*Ul6 z8W17TTZ3*l?f48YnGqmf6}fQ|n;~PRyaC*xNz{N4h0e@snY~2bu=55t_k9T862@vI zVj`mhH)s+yAnyBHjH_jAFQ3!QSlaLjUUE)=SRryxN-VfRlc)jF<*KEsC1N~dK}pX= zvd+%uxVe)dd|em=H)s+yAa?P*d9j!DbaO9(1qI@#KmiJ@BO!cY7(?7-G-E*wrHL#+ z*rc2L0^FcU{{d0Qci0#?F`Y;lGA{A)kK;s7DDMBB2|%x%1cCfs8m59BztFOgP|BC`R?_*T<;oxCt)&Y zXXebAbI$(v%;ZClUcF!J(W7tQ9$vnIANPx!)zEWt&mI-!{2u%sJ$kGNScI<#_Ic~g z<)c5tKmGJ_&a*3uKi`oTd7ymZg%86T^tnfbWh0;8YPTqRYc_HIZG86K_^trOun2(@?1tDvZF%8ohy@a_Z zVOo8dzXD{<@e;$mlthVPZY6UcGi0aBbTu00WQn2PXJ~8PZKgF|qp#ni8NTDC9bZF4(@ILQtpMX zX4%#O$_KB_1K1ajnQ?Asp7C{YXWOe%6YO;my*~A7_iEiUf8#Xp+A&~)LzvgSgE##0 z&hOkag$S^Ne_q^~G9W^ExyJe!#qApGel8jBJY4-*M2DEpMdn z*D4%~Y)cM`j`>S2H`<8~<@79DA2|8YFk!y~eV6ujeRWX(%-FuayhjaR|5m@`=!MgI zhrc@L#mt?3U!OwRubqv+plbYV7*de#x5`uIe3bH%ORS-uHDk%6WZWzvL|oLwl?3 z1`W;ptM4yv)P(i*{gR1=k-c?xgI>ve%I5W{)I00@^-tcqP~O}1wL!0D_P6emW~XN`6bbx-q%^^UELT^#?~ql#K| za!Fuo)9;xp4can7XgFP#D>R%fvmMeUr)AfF?6o#{&#aC8B>qM9&jrIzjJ6MTPxY|A zsM2R)>kFG?QO)&s|Hx=wI*8#{h(2lc*d*J4|2MDvZ+EFP#&nPE-hbA{E{Pwb{<&~? z&S<|-_y4(~#D4X|`X%YJ5mVOA{$uHswe!Awd`&*O`~OfcE*MUaemOLY z@{oJ~vo;owfBZ#jH(We9FJjBZKAsV=4JT*JS#=kmlenZIXwGBrMVd#PcUo<%Z#<@6 zTsS;?v}b76|5{PQ1cA@N`VRy?%6e~skE%JSSYEugL_2U*!T(gpgz9Sr!%vQO4$VsS z*y6pqHg-{bw<|g;UKjCF!Ds6tUM|R37cr#Z{yN#meXo!6u~}kuUl+xX56${NPv#HT zzMs5}d?R)4C)6LGL}$f{me^#ZdJI)xGf$4y#yYC6Wsh!7^Z5VsF=g!7VE@Jo|Jdg_ z`|YG9vvT%s|41oHF0!4QLlxP2*7e!nNYBx&`&EDLV&olv$y%l8`1Y@qM6{CFtR!NT z#5N`IosvjU5!ENt{p;SxO>DN#rSsi%OzUNnBA9 zWlEw_N!(NtbxNXMNi-;lW+kCl5G}J zMMS8Gbt>X36%nl>Hmisj6|qf4e5WE3RK!mzVz-J&QW5)AM5>BVs))lX;;4$qR1qgs zM3#!kQ4x76;-ZQuR1sHHM45`HR1r5-L~&K0QMz}x=`&9o0)1u2(hUv%NlRoS(rG05{<62B^wq0(nbBE$Ily%`^jz`l&mQdO{}y1u~G4%E^4nHzhIc;FB_?p zkVT?tb+&sO6|;3w`}Ful!*PGvGNt5Dk!V4kE!C))r;AF~6PSRo@)kvV;puxo>WYQ2(+u{qLrkY7oLIN8HZh!XBAVQ3#0*b^-A(6Po04` zjl)XhH;btVfi{3{SxIVmx(vLB7%P?AT&C6uq=EFatH?~A>mj_a7%P+8U#7kiXaniN zt4Nv`eh7bFjFrpXFH_M1X%IbX6?uZEK77IY z`zgJB6?vW)egywej8)6suTV(>X$ZY<6?u`TK7!8^V>NQWE7X30HiSO1ioC?r9l;lh zv08cb6)IIA4W&=7A`5x0YJ8a(tCJ^Pp_Bq`C|$IQEaru)@jx+lOP+OwIxLWWMpv&Q zukh4re2o~pEx&n%Ix5h9Mz^dYOL#gp{)HI3Be%IqWeTKg=w}1SGM?*i_}5~rUT%Mt zIw8=mp$7+$6}<4@@U3F(FS+|wDoY^!oE{ZGR`S%p;iMS5EBCuftjJ3$!OQ@RyX#~A5fNbEYkKqMkOegm%q3Q(M2>M6>d7q~{ zhL?)5R(W&@RWFc6(x(H+W}d4Czahr-@}v@~L7j7$P6i=vKN4o@)efYZL z_$y9WZ$)$|)lVp0Prn~X+VEX7@sUp0(~6{0>LsCeJ?#}pKF1Hw#NTwno>63#QZEao zQM7*`$>XataVICNkK$%2HAJY5qQe47TfQz6pX7w~RoIkK!-Uc==?#HoKfdel_*5s% zMqyt@4Hs&^q_+o>FYv>E$3Jw!o>jP)QT9UVSM@+H3dcYK}`_MF16jB*fazoL%> zk^}j=-|>Y`*gq7}Wz<_jshmC?NWRQ>rSWA>7*CN@MvWC}<#bUXDd30Gc%T!;S7en@ z&O)hzt_~!J@YOWF#tE}k+$^Ie2(=2jC6E;Hbu|8k6ZX8qrkr|5DE*p#Hi#U?cl`tZ z+6n8YurH^k2(@3+gM&yre)u2wRwt~#!o8ew7fPe)Q9Iy*j%I538h=PpdhlxUU4Hl}{CQ{WRfYRCDq1Lwp+~JIr|{LM@IlU)ox<-L zwOOc*pHHAVC_Dn=-crQcsoy7OJL@R82ga7EHJYMW3SOM9&*J^0~S z_?yny>x!&v)OSMZH?;q1@&mp)3wLtHMksDxqY{MLZ|Jbq$&Kn)KwmX5-78F$YCbC8ZQ<CIPX<7=ETN5#!b>Zni~Pq(ZlefYX;{0nF7O@+;M zDpM#W>1TsUobP%D|JoUQOJRSVIw91O^x$A}5kLG4zSSA~r^5X@l_ivZM~@07efjD$ zIO&YNt?;`}@CE#m(!~6`}TfIxLtB;Olbm$azD~8+PsueJ>rZ zb&2<`N~`%eG$H#yaAC-3^;xcv69}ga+(O_i17{UEkHC3D&Kq*xurqJC^3vftmkjSJ zRn6tlgyI9i#UZQIXSqU7Ae=IA3xTr?oK@sJ0_P1mZ^(JW&b;BGOP|-e5Z+a(HRD4Q zP9C^h5HeJKmMi20!YKo{5ID=gSw+qxaNdyfhMYI-%o{Gh^m(02ig%T==C{y2 zg)C5? z`_D;$lK>|HP6C_+I0&q;uj04D)X0-OXm32+kNB*004lR$Tt03%bM zWoYJ(BU8aNCNecLgDsOSGsq0*HLb-t8bh|M>5{DZ5_4Ckk7xdp=(8DvtaT4lBVpp1 zyFN^%#!$jkmfT|M$~8m6mUH?ZVxl%S!jexua$uLM9AaRCd3M8qU06F@v+L23qrp{mNHbyu3%0FG# zN=qTBfaE$PHzBEoHK zNKS03T^8i?^^(PITXd7fZ-d5NAer#CI#TnGvoS*^?)vGwArtL(0kZ37_~{q;X-~|M z-M5}|-(353h|gYs*n{P;2audvzT{HMzkYX4qnExnE}dTbDI`Bba$#KBu8N3Zhhm1< z-+nG92Q*#?NhKupkmz%2TO1ZTxrH`udUh!w&qFf6Ep+xV$7@b$cK0HFIt6=h8ulO? ze#(KL&caXUzVp@;@T*So6Ju_k;U~_hKDFhUrmyC?g)Tnsc+Uki{+cTwvmyBsl7o<3 zgXG2W={24_=MkY34h*ZhcU(F?b)9@f<7f9W1ICO`uQ<$uG!N06i1y^el9v&E3sHAS z>7`@Fr|q(h+*KAcB;t;MmkY-8NaAUG6iD~(VKG$`?J}|Dnb3)|`@sG;FH9&XOW(21 z&UJ16qCha~Vg11bdfL*UcFpHbK&%t|frOIx)cvt#V$){1TPWMr8s`~Ea&joN&WW)) z+f^vOvhTc!i8P!p<0#NjI*`sr7Pei4bfk>E61v<2!U}?@y%ANiYzBw4cVF?MXRo2a#Y z2RihJ{Zk#6dhLgTv0H{$jUisr&0DtS6Uk27iRbQ|*|H4-Vp}xwIdIK_)04qKuBXA` z6R3C$D$aq$V32TVy?C%$+ee7{VabDbPJyYO)J{rfI|&qK@#}?U>2uybabUtU-qH=; z-~4d-?2GC-&SgSi4dR_o@Ds=GbO*XKANa)%nYjFeZ-8>Wn*j8zsQSf+JGgw= zfX*ivi5AZCI;4et2JZmPv=L>(KcG54Jb$o^9SuKY zc2$Oda%s7~6e^cb-3Xvp8F!$Onz9yJt$`xIwcsu^RbqWKP?A1K^(B9s)=S@yLb_>o zz>gl>(X}s`)l8_5=9)62P;Dbbs`Z#9@w|XE4p9HVt^LJ4<1^O zawE!d%=lEFygoi)naCQOzmhKnT4Tu{(CNd4JrF4f~c4vt4Z09P>PQ z+tuvrICMjw@3lS5?Tmg^Z!zOHGoaHI?t8epM8+%#h#;_Ela$TztZR9UtT zR_QYuRC)Cf;M)lcZ>)!fJXq-B)RZ@rZBJz6`)3)v^jEOT09a)K4bmHvkT-zTu}Mhq-;hlQh@oASo9?M*Q9 z{ROLx{1#T339C$ld^0OS;ofbqa2_mN;@mXjJ+{3mM!s@bU+152eXfUoX3ZFlS2e5(OQL*Kzk(|i z9sn2cRhuu|(|mEJ=7LL3N?Z$Ur?YAuFX$Jkyx^#ucK6rak+74GY@!|Sb{{yz^R4U% zE$AN0%MGnNyIybz$A_Lm0C0G#9k!+xYD8Awe^Sp6~o1r$4+i1}zD zU{$LoVh++V*p5{?b`j|q?4&h128IZAtV=a+*BNeTZR^o>{+?!B7qx#@tDEwI!fQk` z;h$uyJez4-EJFGrx!}@AvO=~Osn3Ts!d6QE6H=mg_Xpph8x_VW2CFY(FVYzJtu?c! z@Pg(AHfD{6agDW;7c{hwUyR5HF%29?uK-) z>RHHQ>_Pf59hsO!*2G*yCT1TpF|(10Nn)oMS_V)D8W;GjHM5rloS^aoY|I)B;~Hxx zFX$v6zZh2}TvyaNs;1TZT%76SpKwjHZ}&0Q=dh9OOr#KOeCvTUh>da`kp=+{v^-&7 zccUq{Hn0U(fcj-^gvvE$T90sCS?gQDc%kZ`+-SOdsWXz3c<#+0Z1WAkV(<7 zCWVb{=O7I-MwPIypbngJYXippNWZKNYPrTbn3TsaMr2YHAfyF>%HEJz*}mOFk#4Y| zi5t=xHdvW~R0D-Ck;v#s+SwB}p0ze?;JDgQ1!$AIsWgy=!~+eP@6fOhXvnX-7a$Eu zLBYvfq#?heaP}jlAt*M9L`Fr^PDA#gJ05F86OOCBhICVD01c6;^g7Xsgi=OV+2?|f zAd9)5ZM#=94j{C}0HG}c2<=LM&@Qhi2NeNAyBQ#~jR3;!q{0{DVtrJ*KoooMLP@W} zsqEV_0QKb`22h_Dg!-02sBc%uXmf=e-~Um$AXDSBBB5ON5yW0!V}519*G_R-Ghcwa zT^P4;7_8CuqR{h6gqK;IKOJB!AjX{!FqYf?Ng#lPIKO$E*31`e7z>BNwu21N@_EAG zW%h<>A-Ex$;n46CxFOo*Rc%6L6?GQCxJJVwVsD774RwD)H$-g^uq7}VoCdD34mU)P zUyR5HNq`SxW_tjD@-=3USM?)tT1A}%S)F#su2EGu47Q^WdeY!!pii(z`8>2S*Vvq9=ob*GB{jg9kB8Lh#1*Nha16N^jzhI zc<|^DBqf+oS&<5atMJj`qhMTPtOC$i7QnS`%HvT~>|?EdagF_bnwnAjV2`nO?ip6Q_dzcSesbDHP&uDvWPicrjJpKtVzK^NITnO0(ck% z9x-l1;AtnAvUBa~@ zmCplo*Qg4S>aamackO;{lWFH$_aCY9N+&xDAW9G8TQ=MF8jIk<6gV~!fem)qFqdKT z6gqyPSuxj`ZfgW^`@j-mYnnHB#*`fj%#vd%ePFw}pNh_T|w{ zn0Srpw!pdpjM}2^Azn6U|9vufI1x-kIcv9Q^;u`GfMb0pcs1U4msVZ&ZF;C<)| zpcQZ;KzIu$0#>y^PaaGJ8?M53%&C*vLa1Zx^LW^oPF1l3uQA;g>KGh|H9E!(4avFC zB?lzf0zgi(Z}-FtE?KhKFntzgXq!*5eHhGbGc4~Sjj^?I_CT9(>S1HnXc*U+NnUUf zJbp2US@cz;lCb%39aC%{26N#Q zL(4E5MJ*8OwPyA}n{ZWF>w&n&Oe+%l|Hm)Jr8Q#!G7I;U?Tc%HNeN(E*`rcy&49Va zSj7=d`7vva3cCr-+6a|vtlfHq%k=S!5t$S*FexAtApn?^5|lm*5)wK|v3(fKZ8Irs zK7zFYBWM$tlw;PK6t1zqo0P{dMr2apGiHR@e#7S8f`~Q}g(kqS1D!DewTilqxUSKj zu)A)o4I4PFHdF!nkN=)D?lQyAEZFZo|M@|Ee;LzgC~O`vPD)(<)9=8=smW5!)zLLV zeV95q_+Cw2+S$C6jBFP-bA?wNJ@ltsSZcPy-wO{;yI)b~}~b}}V@5f?N8iy2L&C`ndws70pHi<|Cm{*}33EQ_+dpj1$p zl0gGa!WzWq1ckO9dfq+h{hB)J>_u2US96tL^RYh6H95G!T;V->rmWY|7(I2NWKzJV zT~sz*fotx6QJ6rBfZf;`vX2?%5s~FmDBHIC*kWi=WLe0f#3G9_99Wb!IuB%m;*kk* zL?+0`X!C$!1I#QnnUb!I4#(BrZ**g6Aa@i1+|li{3mL#2edbv`AL&8{(uDw|3nj=M zX^=aT0UHX`Dh?@+gUKCbAa?}09_=noIs^?c$JG{QbYp2CLlSw;<)Y;DOk2+pIycYi zVaRG&N&Jqi9t_)=uxnI?M!I)sASYVQgcKXYxQ(4WlD#j8!bsU=Uwf zqru#;T=$;`LFflHvzgHzM|~4&OMH{q_`^~PW)@C$0GevZWX)91M^kN#Wh`Qat2z!% zb^ANYu2`W4BV%>dN)6_Q#oo(+5JYx*rU--}(><&0PzYivHHIK=XsRKTHLE%XPIZfw zAxH!=Ruiq9Y7x?4!b%P1hJ`{9*|LOcpdga8X^j%!BoVrIksuc%LpQz*m_l&x5`*qt zSj}-mH#1|(6Rf&M*EJ5?7O1{~ z!c`*}+m+dW5C?KxZ5TTApWRd%z>qMyx=YNmgd0pot6jrwK_L^+>{eYOK42&bV0eaz zifTsRSW;?vL6fu*!hm@!=-P;&)V$8IRug=RP+1`hx-OO=7J9cfO_^a1Y3$2Z9Ys}dQSu5nmnL<^XKJA!ve*4*-NTISk$?~+G3|mI2tj5cC=}pmESlCOZ3{s-6x9@hJW=2<3PD65hXg1H0dhzH zIB$YgE9xx3VT~q)KxqQjg5Mlh`y7&PDh>7l&Tf#5=HQ_}?NZ3Z?T$2`-r5-sYYbEY zGYH`UwdxTo$MxWWC@Z~gDMMgLm`I&o;x(d$abTwEb<##=z9FW?`gGT}4B1}CVi3^E z<*%B_?|nkEbCEl81nwv$?Ls_oM{_-^&8N3^io+V+Q9N=-@IL9m;_1TZzD(J#OqjrNGh2D#DkyN{VqZ|w|+HM%3f3`{AYU1&x-9b)TqTIfZ(MA+>%mQrIN@+85HPbiA|?+pt!1c3AA(_1^kVcSfI9m*lGHZz*zYM(>WO{IanjLZ+@ zMrY5|fMhg{Z;}Pa47A5#je#m)1|hu0XlpIG<7Mk}Tqf(&O=SoTiKfKRO5{fyWZ9CL z3;<4V792Cs9)~r$Bft#YQHhoA zh~omN0)nGi>2*sPvT^M@09qRf_wv_@*lqb0br3nUgc?=kNrD^O%^Ei>7FzogoJj%G zHAm={dRD`2`D=8RQX{m+?dWfpwe}>Pzks}q4}jLdQ(zAOt$h?1hK@aow2-z1BHWIC zqkjbt>OlT5IBMewIe!5`YhnPcf!#N8;OSocZn!O<$bj*LCDaJ5JyCFDyQ%(ve^3D% zg1iet5PJ`hu30PbO@f(;6?K+UV+isj!Hw-g5N=p(4#`g-hr}M909pvZ`N*!18EB8g z8cm2b$A_9$D8~gB*n=FB?kWxBWw_&B*&EJ|o0ws`9CwWERbWWKaj!CiTg`jMV_r`g zG1#C6kPjPh=eA%jsK7kK9J93GxH!!xKmpD8qA(u%YLNv&dcqzL3-?cMHE(B3+SE?(*yCXVJOO~>&P`NDR&+cp#J+92v~DI= z_IOzKEZhIT!`c&aL=+$a4{#D;!s|Ee$pi4$3BE-Kt94C*2Z2*SkPu*+Mwg zX#W>Tx3y}jcc4c_)2*E9JxGIRS>^*#hq+U)fK^SlzFblfYqElbta~lf|dSww-gTQ|E#%p_V$&$tU3GPExi)m(ia&|&W9>E z9jYKG*yXbv-lqJ$R)<1pL`|X5gKKrD)$w|N4~-t#Ks(mIM|@rPjb#Osv%?hebu}z# zZIboihjP%l^wS#A6JzI=)J7N%SVDmapiE3Lgf%iT#SqrW#1unVA(I8B(5Ne!7`22O z7F-d)+A#W}6v=s)Jf`BW?=M^$o5q~16ep!D|5$(flEJy@i1s2AS(g}Pc|qym!W1R@ zdtAXkj)efN^SQxSV9{JnKKv;zFIVtWT+7k#bD1fG`JBRKn`;%jBl!oV_dBh3vBMR? zIS7(IUJ%$#?6p6yi$+Y$FsU|oUH&NmCs$2c{;4HBM9lDn0d9DvDFx}V^K_d*+`AuZ zcpaq2&WQ{A23Xr<{p%oiX`b!_WN*F)fZU=wF)+v{ivnOWg0ciYR$Q)uKP!GnYGvZnxWSXppKgl&u2a(#;MwlzRsLmECj|eG`1Q`+;II^wHkPJhH1aetp zNI0&x6$K4RH=S`lM;Q?9;U~K9zCCWvDb?|di3qv!^=1D<9>0o8hTFd y*`uPI--F-7^zY|&@bij*Mfi$fpSRvzKKe8K(+@qKeg>BI1h4Vn-2w3R=<#2Od%rLM literal 0 HcmV?d00001 diff --git a/src/test/app/wasm_fixtures/wat/memory64.wat b/src/test/app/wasm_fixtures/wat/memory64.wat new file mode 100644 index 0000000000..3273af1e40 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/memory64.wat @@ -0,0 +1,21 @@ +(module + ;; Define a 64-bit memory (index type i64) + ;; Start with 1 page. + (memory i64 1) + + (func $escrow_finish (result i32) + ;; 1. Perform a store using a 64-bit address. + ;; Even if the value is small (0), the type MUST be i64. + i64.const 0 ;; Address (64-bit) + i32.const 42 ;; Value (32-bit) + i32.store8 ;; Opcode doesn't change, but validation rules do. + + ;; 2. check memory size + ;; memory.size now returns an i64. + memory.size + i64.const 1 + i64.eq ;; Returns i32 (1 if true) + ) + + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/memory_end_of_word_over_limit.wat b/src/test/app/wasm_fixtures/wat/memory_end_of_word_over_limit.wat new file mode 100644 index 0000000000..855307ddf4 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/memory_end_of_word_over_limit.wat @@ -0,0 +1,28 @@ +(module + ;; 1. Define Memory: 1 Page = 64KB = 65,536 bytes + (memory 1) + + ;; Export memory so the host can inspect it if needed + (export "memory" (memory 0)) + + (func $test_straddle (result i32) + ;; Push the address onto the stack. + ;; 65534 is valid, but it is only 2 bytes away from the end. + i32.const 65534 + + ;; Attempt to load an i32 (4 bytes) from that address. + ;; This requires bytes 65534, 65535, 65536, and 65537. + ;; Since 65536 is the first invalid byte, this MUST trap. + i32.load + + ;; Clean up the stack. + ;; The load pushed a value, but we don't care what it is. + drop + + ;; Return 1 to signal "I survived the memory access" + i32.const 1 + ) + + ;; Export the function so you can call it from your host (JS, Python, etc.) + (export "escrow_finish" (func $test_straddle)) +) diff --git a/src/test/app/wasm_fixtures/wat/memory_grow_0_page_more_than_8MB.wat b/src/test/app/wasm_fixtures/wat/memory_grow_0_page_more_than_8MB.wat new file mode 100644 index 0000000000..777f3062bf --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/memory_grow_0_page_more_than_8MB.wat @@ -0,0 +1,29 @@ +(module + ;; Start at your limit: 128 pages (8MB) + (memory 128) + (export "memory" (memory 0)) + + (func $try_grow_beyond_limit (result i32) + ;; Attempt to grow by 0 page + i32.const 0 + memory.grow + + ;; memory.grow returns: + ;; -1 if the growth failed (Correct behavior for your limit) + ;; 128 (old size) if growth succeeded (Means limit was bypassed) + + ;; Check if result == -1 + i32.const -1 + i32.eq + if + ;; Growth FAILED (Host blocked it). Return -1. + i32.const -1 + return + end + + ;; Growth SUCCEEDED (Host allowed it). Return 1. + i32.const 1 + ) + + (export "escrow_finish" (func $try_grow_beyond_limit)) +) diff --git a/src/test/app/wasm_fixtures/wat/memory_grow_0_to_1.wat b/src/test/app/wasm_fixtures/wat/memory_grow_0_to_1.wat new file mode 100644 index 0000000000..54a4193927 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/memory_grow_0_to_1.wat @@ -0,0 +1,26 @@ +(module + ;; 1. Define Memory: Start with 0 pages + (memory 0) + + ;; Export memory to host + (export "memory" (memory 0)) + + (func $grow_from_zero (result i32) + ;; We have 0 pages. We want to add 1 page. + ;; Push delta (1) onto stack. + i32.const 1 + + ;; Grow the memory. + ;; If successful: memory becomes 64KB, returns old size (0). + ;; If failed: memory stays 0, returns -1. + memory.grow + + ;; Drop the return value of memory.grow + drop + + ;; Return 1 (as requested) + i32.const 1 + ) + + (export "escrow_finish" (func $grow_from_zero)) +) diff --git a/src/test/app/wasm_fixtures/wat/memory_grow_1_page_more_than_8MB.wat b/src/test/app/wasm_fixtures/wat/memory_grow_1_page_more_than_8MB.wat new file mode 100644 index 0000000000..540b112178 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/memory_grow_1_page_more_than_8MB.wat @@ -0,0 +1,29 @@ +(module + ;; Start at your limit: 128 pages (8MB) + (memory 128) + (export "memory" (memory 0)) + + (func $try_grow_beyond_limit (result i32) + ;; Attempt to grow by 1 page + i32.const 1 + memory.grow + + ;; memory.grow returns: + ;; -1 if the growth failed (Correct behavior for your limit) + ;; 128 (old size) if growth succeeded (Means limit was bypassed) + + ;; Check if result == -1 + i32.const -1 + i32.eq + if + ;; Growth FAILED (Host blocked it). Return -1. + i32.const -1 + return + end + + ;; Growth SUCCEEDED (Host allowed it). Return 1. + i32.const 1 + ) + + (export "escrow_finish" (func $try_grow_beyond_limit)) +) diff --git a/src/test/app/wasm_fixtures/wat/memory_grow_1_to_0.wat b/src/test/app/wasm_fixtures/wat/memory_grow_1_to_0.wat new file mode 100644 index 0000000000..cc4d161153 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/memory_grow_1_to_0.wat @@ -0,0 +1,33 @@ +(module + ;; 1. Define Memory: Start with 1 page (64KB) + (memory 1) + + ;; Export memory to host + (export "memory" (memory 0)) + + (func $grow_negative (result i32) + ;; The user pushed -1. In Wasm, this is interpreted as unsigned MAX_UINT32. + ;; This is requesting to add 4,294,967,295 pages (approx 256 TB). + ;; A secure runtime MUST fail this request (return -1) without crashing. + i32.const -1 + + ;; Grow the memory. + ;; Returns: old_size if success, -1 if failure. + memory.grow + + ;; Check if result == -1 (Failure) + i32.const -1 + i32.eq + if + ;; If memory.grow returned -1, we return -1 to signal "Correctly failed". + i32.const -1 + return + end + + ;; If we are here, memory.grow somehow SUCCEEDED (Vulnerability). + ;; We return 1 to signal "Unexpected Success". + i32.const 1 + ) + + (export "escrow_finish" (func $grow_negative)) +) diff --git a/src/test/app/wasm_fixtures/wat/memory_init_1_page_more_than_8MB.wat b/src/test/app/wasm_fixtures/wat/memory_init_1_page_more_than_8MB.wat new file mode 100644 index 0000000000..f1bbee6c61 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/memory_init_1_page_more_than_8MB.wat @@ -0,0 +1,27 @@ +(module + ;; Define memory: 129 pages (> 8MB limit) min, 129 pages max + (memory 129 129) + + ;; Export memory so host can verify size + (export "memory" (memory 0)) + + ;; access last byte of 8MB limit + (func $access_last_byte (result i32) + ;; Math: 128 pages * 64,536 bytes/page = 8,388,608 bytes + ;; Valid indices: 0 to 8,388,607 + + ;; Push the address of the LAST valid byte + i32.const 8388607 + + ;; Load byte from that address + i32.load8_u + + ;; Drop the value (we don't care what it is, just that we could read it) + drop + + ;; Return 1 to indicate success + i32.const 1 + ) + + (export "escrow_finish" (func $access_last_byte)) +) diff --git a/src/test/app/wasm_fixtures/wat/memory_last_byte_of_8MB.wat b/src/test/app/wasm_fixtures/wat/memory_last_byte_of_8MB.wat new file mode 100644 index 0000000000..e00f5e1239 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/memory_last_byte_of_8MB.wat @@ -0,0 +1,26 @@ +(module + ;; Define memory: 128 pages (8MB) min, 128 pages max + (memory 128 128) + + ;; Export memory so host can verify size + (export "memory" (memory 0)) + + (func $access_last_byte (result i32) + ;; Math: 128 pages * 64,536 bytes/page = 8,388,608 bytes + ;; Valid indices: 0 to 8,388,607 + + ;; Push the address of the LAST valid byte + i32.const 8388607 + + ;; Load byte from that address + i32.load8_u + + ;; Drop the value (we don't care what it is, just that we could read it) + drop + + ;; Return 1 to indicate success + i32.const 1 + ) + + (export "escrow_finish" (func $access_last_byte)) +) diff --git a/src/test/app/wasm_fixtures/wat/memory_negative_address.wat b/src/test/app/wasm_fixtures/wat/memory_negative_address.wat new file mode 100644 index 0000000000..6e26a07108 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/memory_negative_address.wat @@ -0,0 +1,23 @@ +(module + ;; Define memory: 128 pages (8MB) min, 128 pages max + (memory 128 128) + + ;; Export memory so host can verify size + (export "memory" (memory 0)) + + (func $access_last_byte (result i32) + ;; Push a negative address + i32.const -1 + + ;; Load byte from that address + i32.load8_u + + ;; Drop the value + drop + + ;; Return 1 to indicate success + i32.const 1 + ) + + (export "escrow_finish" (func $access_last_byte)) +) diff --git a/src/test/app/wasm_fixtures/wat/memory_offset_over_limit.wat b/src/test/app/wasm_fixtures/wat/memory_offset_over_limit.wat new file mode 100644 index 0000000000..20a401e3d2 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/memory_offset_over_limit.wat @@ -0,0 +1,27 @@ +(module + ;; 1. Define Memory: 1 Page = 64KB + (memory 1) + + (export "memory" (memory 0)) + + (func $test_offset_overflow (result i32) + ;; 1. Push the base address onto the stack. + ;; We use '0', which is the safest, most valid address possible. + i32.const 0 + + ;; 2. Attempt to load using a static offset. + ;; syntax: i32.load offset=N align=N + ;; We set the offset to 65536 (the size of the memory). + ;; The effective address becomes 0 + 65536 = 65536. + i32.load offset=65536 + + ;; Clean up the stack. + ;; The load pushed a value, but we don't care what it is. + drop + + ;; Return 1 to signal "I survived the memory access" + i32.const 1 + ) + + (export "escrow_finish" (func $test_offset_overflow)) +) diff --git a/src/test/app/wasm_fixtures/wat/memory_pointer_at_limit.wat b/src/test/app/wasm_fixtures/wat/memory_pointer_at_limit.wat new file mode 100644 index 0000000000..e4432e6fdd --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/memory_pointer_at_limit.wat @@ -0,0 +1,22 @@ +(module + ;; Define 1 page of memory (64KB = 65,536 bytes) + (memory 1) + + (func $read_edge (result i32) + ;; Push the index of the LAST valid byte + i32.const 65535 + + ;; Load 1 byte (unsigned) + i32.load8_u + + ;; Clean up the stack. + ;; The load pushed a value, but we don't care what it is. + drop + + ;; Return 1 to signal "I survived the memory access" + i32.const 1 + ) + + ;; Export as "escrow_finish" as requested + (export "escrow_finish" (func $read_edge)) +) diff --git a/src/test/app/wasm_fixtures/wat/memory_pointer_over_limit.wat b/src/test/app/wasm_fixtures/wat/memory_pointer_over_limit.wat new file mode 100644 index 0000000000..906468f308 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/memory_pointer_over_limit.wat @@ -0,0 +1,23 @@ +(module + ;; Define 1 page of memory (64KB = 65,536 bytes) + (memory 1) + + (func $read_overflow (result i32) + ;; Push the index of the FIRST invalid byte + ;; Memory is 0..65535, so 65536 is out of bounds. + i32.const 65536 + + ;; Load 1 byte (unsigned) + i32.load8_u + + ;; Clean up the stack. + ;; The load pushed a value, but we don't care what it is. + drop + + ;; Return 1 to signal "I survived the memory access" + i32.const 1 + ) + + ;; Export as "escrow_finish" as requested + (export "escrow_finish" (func $read_overflow)) + ) diff --git a/src/test/app/wasm_fixtures/wat/multi_memory.wat b/src/test/app/wasm_fixtures/wat/multi_memory.wat new file mode 100644 index 0000000000..67fc5e76aa --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/multi_memory.wat @@ -0,0 +1,16 @@ +(module + ;; Memory 0: Index 0 (Empty) + (memory 0) + + ;; Memory 1: Index 1 (Size 1 page) + ;; If multi-memory is disabled, this line causes a validation error (max 1 memory). + (memory 1) + + (func $escrow_finish (result i32) + ;; Query size of Memory Index 1. + ;; Should return 1 (success). + memory.size 1 + ) + + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/opc_reserved.wat b/src/test/app/wasm_fixtures/wat/opc_reserved.wat new file mode 100644 index 0000000000..0bc61b52c3 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/opc_reserved.wat @@ -0,0 +1,98 @@ +(module + + ;; Type for call_indirect + (type (func (result i32))) + + ;; Memory and table declarations + (memory 1) + (table 1 funcref) + (data (i32.const 0) "test") + (elem (i32.const 0) $test_func) + + ;; Global declarations + (global $g0 (mut i32) (i32.const 0)) + (global $g1 (mut i64) (i64.const 0)) + + ;; Test function for call/call_indirect + (func $test_func (result i32) + i32.const 42 + ) + + + ;; Main function with all instructions in hex order + (func $all_instructions (export "all_instructions") (result i32) + (local $l0 i32) + (local $l1 i64) + + ;; 0x01: nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + i32.const 11 + ) +) diff --git a/src/test/app/wasm_fixtures/wat/proposal_bulk_memory.wat b/src/test/app/wasm_fixtures/wat/proposal_bulk_memory.wat new file mode 100644 index 0000000000..ce59868ce6 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/proposal_bulk_memory.wat @@ -0,0 +1,25 @@ +(module + ;; Define 1 page of memory + (memory 1) + (export "memory" (memory 0)) + + (func $test_bulk_ops (result i32) + ;; Setup: Write value 42 at index 0 so we have something to copy + (i32.store8 (i32.const 0) (i32.const 42)) + + ;; Test memory.copy (Opcode 0xFC 0x0A) + ;; Copy 1 byte from offset 0 to offset 100 + (memory.copy + (i32.const 100) ;; Destination Offset + (i32.const 0) ;; Source Offset + (i32.const 1) ;; Size (bytes) + ) + + ;; Verify: Read byte at offset 100. Should be 42. + (i32.load8_u (i32.const 100)) + (i32.const 42) + i32.eq + ) + + (export "escrow_finish" (func $test_bulk_ops)) +) diff --git a/src/test/app/wasm_fixtures/wat/proposal_extended_const.wat b/src/test/app/wasm_fixtures/wat/proposal_extended_const.wat new file mode 100644 index 0000000000..e296a468f0 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/proposal_extended_const.wat @@ -0,0 +1,15 @@ +(module + ;; 1. Define a global using an EXTENDED constant expression. + ;; MVP only allows (i32.const X). + ;; This proposal allows (i32.add (i32.const X) (i32.const Y)). + (global $g i32 (i32.add (i32.const 10) (i32.const 32))) + + (func $escrow_finish (result i32) + ;; 2. verify the global equals 42 + global.get $g + i32.const 42 + i32.eq + ) + + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/proposal_float_to_int.wat b/src/test/app/wasm_fixtures/wat/proposal_float_to_int.wat new file mode 100644 index 0000000000..367735f5e7 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/proposal_float_to_int.wat @@ -0,0 +1,18 @@ +(module + (func $test_saturation (result i32) + ;; 1. Push a float that is too big for a 32-bit integer + ;; 1e10 (10 billion) > 2.14 billion (Max i32) + f32.const 1.0e10 + + ;; 2. Attempt saturating conversion (Opcode 0xFC 0x00) + ;; If supported: Clamps to MAX_I32. + ;; If disabled: Validation error (unknown instruction). + i32.trunc_sat_f32_s + + ;; 3. Check if result is MAX_I32 (2147483647) + i32.const 2147483647 + i32.eq + ) + + (export "escrow_finish" (func $test_saturation)) +) diff --git a/src/test/app/wasm_fixtures/wat/proposal_gc_struct_new.wat b/src/test/app/wasm_fixtures/wat/proposal_gc_struct_new.wat new file mode 100644 index 0000000000..bc33b7fada --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/proposal_gc_struct_new.wat @@ -0,0 +1,12 @@ +;; generated by wasm-tools print gc_test.wasm that has the following hex +;; 0061736d01000000010b026000017f5f027f017f0103020100070a010666696e69736800000a0a010800fb01011a41010b +(module + (type (;0;) (func (result i32))) + (type (;1;) (struct (field (mut i32)) (field (mut i32)))) + (export "escrow_finish" (func 0)) + (func (;0;) (type 0) (result i32) + struct.new_default 1 + drop + i32.const 1 + ) +) diff --git a/src/test/app/wasm_fixtures/wat/proposal_multi_value.wat b/src/test/app/wasm_fixtures/wat/proposal_multi_value.wat new file mode 100644 index 0000000000..23f1691872 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/proposal_multi_value.wat @@ -0,0 +1,22 @@ +(module + ;; 1. Function returning TWO values (Multi-Value feature) + (func $get_numbers (result i32 i32) + i32.const 10 + i32.const 20 + ) + + (func $escrow_finish (result i32) + ;; Call pushes [10, 20] onto the stack + call $get_numbers + + ;; 2. Block taking TWO parameters (Multi-Value feature) + ;; It consumes the [10, 20] from the stack. + block (param i32 i32) (result i32) + i32.add ;; 10 + 20 = 30 + i32.const 30 ;; Expected result + i32.eq ;; Compare: returns 1 if equal + end + ) + + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/proposal_mutable_global.wat b/src/test/app/wasm_fixtures/wat/proposal_mutable_global.wat new file mode 100644 index 0000000000..82a5d35203 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/proposal_mutable_global.wat @@ -0,0 +1,25 @@ +(module + ;; Define a mutable global initialized to 0 + (global $counter (mut i32) (i32.const 0)) + + ;; EXPORTING a mutable global is the key feature of this proposal. + ;; In strict MVP, exported globals had to be immutable (const). + (export "counter" (global $counter)) + + (func $escrow_finish (result i32) + ;; 1. Get current value + global.get $counter + + ;; 2. Add 1 + i32.const 1 + i32.add + + ;; 3. Set new value (Mutation) + global.set $counter + + ;; 4. Return 1 for success + i32.const 1 + ) + + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/proposal_ref_types.wat b/src/test/app/wasm_fixtures/wat/proposal_ref_types.wat new file mode 100644 index 0000000000..8cba4edf29 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/proposal_ref_types.wat @@ -0,0 +1,18 @@ +(module + ;; Import a table from the host that holds externrefs + (import "env" "table" (table 1 externref)) + + (func $test_ref_types (result i32) + ;; Store a null externref into the table at index 0 + ;; If reference_types is disabled, 'externref' and 'ref.null' will fail parsing. + (table.set + (i32.const 0) ;; Index + (ref.null extern) ;; Value (Null External Reference) + ) + + ;; Return 1 (Success) + i32.const 1 + ) + + (export "escrow_finish" (func $test_ref_types)) +) diff --git a/src/test/app/wasm_fixtures/wat/proposal_sign_ext.wat b/src/test/app/wasm_fixtures/wat/proposal_sign_ext.wat new file mode 100644 index 0000000000..9c8fdd1980 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/proposal_sign_ext.wat @@ -0,0 +1,18 @@ +(module + (func $test_sign_ext (result i32) + ;; Push 255 (0x000000FF) onto the stack + i32.const 255 + + ;; Sign-extend from 8-bit to 32-bit + ;; If 255 is treated as an i8, it is -1. + ;; Result should be -1 (0xFFFFFFFF). + ;; Without this proposal, this opcode (0xC0) causes a validation error. + i32.extend8_s + + ;; Check if result is -1 + i32.const -1 + i32.eq + ) + + (export "escrow_finish" (func $test_sign_ext)) +) diff --git a/src/test/app/wasm_fixtures/wat/proposal_stringref.wat b/src/test/app/wasm_fixtures/wat/proposal_stringref.wat new file mode 100644 index 0000000000..c9f8030faf --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/proposal_stringref.wat @@ -0,0 +1 @@ +;;hard to generate diff --git a/src/test/app/wasm_fixtures/wat/proposal_tail_call.wat b/src/test/app/wasm_fixtures/wat/proposal_tail_call.wat new file mode 100644 index 0000000000..193fb0aeb2 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/proposal_tail_call.wat @@ -0,0 +1,15 @@ +(module + ;; Define a simple function we can tail-call + (func $target (result i32) + i32.const 1 + ) + + (func $escrow_finish (result i32) + ;; Try to use the 'return_call' instruction (Opcode 0x12) + ;; If Tail Call proposal is disabled, this fails to Compile/Validate. + ;; If enabled, it jumps to $target, which returns 1. + return_call $target + ) + + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/start_loop.wat b/src/test/app/wasm_fixtures/wat/start_loop.wat new file mode 100644 index 0000000000..241774e53e --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/start_loop.wat @@ -0,0 +1,22 @@ +(module + ;; Function 1: The Infinite Loop + (func $run_forever + (loop $infinite + br $infinite + ) + ) + + ;; Function 2: Finish + (func $escrow_finish (result i32) + i32.const 1 + ) + + ;; 1. EXPORT the functions (optional, if you want to call them later) + (export "start" (func $run_forever)) + (export "escrow_finish" (func $escrow_finish)) + + ;; 2. The special start section + ;; This tells the VM: "Run function $run_forever immediately + ;; when this module is instantiated." + (start $run_forever) +) diff --git a/src/test/app/wasm_fixtures/wat/table_0_elements.wat b/src/test/app/wasm_fixtures/wat/table_0_elements.wat new file mode 100644 index 0000000000..9b8a5408d2 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/table_0_elements.wat @@ -0,0 +1,10 @@ +(module + ;; Define a table with exactly 0 entries + (table 0 funcref) + + ;; Standard finish function + (func $escrow_finish (result i32) + i32.const 1 + ) + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/table_2_tables.wat b/src/test/app/wasm_fixtures/wat/table_2_tables.wat new file mode 100644 index 0000000000..4e4e013ce3 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/table_2_tables.wat @@ -0,0 +1,24 @@ +(module + ;; Define a dummy function to put in the tables + (func $dummy) + + ;; TABLE 0: The default table (allowed in MVP) + ;; Size: 1 initial, 1 max + (table $t0 1 1 funcref) + + ;; Initialize Table 0 at index 0 + (elem (table $t0) (i32.const 0) $dummy) + + ;; TABLE 1: The second table (Requires Reference Types proposal) + ;; If strict MVP is enforced, the parser should error here. + (table $t1 1 1 funcref) + + ;; Initialize Table 1 at index 0 + (elem (table $t1) (i32.const 0) $dummy) + + (func $escrow_finish (result i32) + ;; If we successfully loaded a module with 2 tables, return 1. + i32.const 1 + ) + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/table_64_elements.wat b/src/test/app/wasm_fixtures/wat/table_64_elements.wat new file mode 100644 index 0000000000..3221571fe9 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/table_64_elements.wat @@ -0,0 +1,25 @@ +(module + ;; Define a table with exactly 64 entries + (table 64 funcref) + + ;; A dummy function to reference + (func $dummy) + + ;; Initialize the table at offset 0 with 64 references to $dummy + (elem (i32.const 0) + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 8 + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 16 + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 24 + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 32 + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 40 + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 48 + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 56 + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 64 + ) + + ;; Standard finish function + (func $escrow_finish (result i32) + i32.const 1 + ) + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/table_65_elements.wat b/src/test/app/wasm_fixtures/wat/table_65_elements.wat new file mode 100644 index 0000000000..aa0688c56f --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/table_65_elements.wat @@ -0,0 +1,25 @@ +(module + ;; Define a table with exactly 65 entries + (table 65 funcref) + + ;; A dummy function to reference + (func $dummy) + + ;; Initialize the table at offset 0 with 65 references to $dummy + (elem (i32.const 0) + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 8 + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 16 + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 24 + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 32 + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 40 + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 48 + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 56 + $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 64 + $dummy ;; 65 (The one that breaks the camel's back) + ) + + (func $escrow_finish (result i32) + i32.const 1 + ) + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/table_uint_max.wat b/src/test/app/wasm_fixtures/wat/table_uint_max.wat new file mode 100644 index 0000000000..23908611c8 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/table_uint_max.wat @@ -0,0 +1,15 @@ +(module + ;; Definition: (table ) + ;; We use 0xFFFFFFFF (4,294,967,295), which is the unsigned equivalent of -1. + ;; This tests if the runtime handles the maximum possible u32 value + ;; without integer overflows or attempting a massive allocation. + ;; + ;; Note that using -1 as the table size cannot be parsed by wasm-tools or wat2wasm + (table 0xFFFFFFFF funcref) + + (func $escrow_finish (result i32) + ;; If the module loads despite the massive table, return 1. + i32.const 1 + ) + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/trap_divide_by_0.wat b/src/test/app/wasm_fixtures/wat/trap_divide_by_0.wat new file mode 100644 index 0000000000..6f8754ec8f --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/trap_divide_by_0.wat @@ -0,0 +1,15 @@ +(module + (func $escrow_finish (export "escrow_finish") (result i32) + ;; Setup for Requirement 2: Divide an i32 by 0 + i32.const 42 ;; Push numerator + i32.const 0 ;; Push denominator (0) + i32.div_s ;; Perform signed division (42 / 0) + + ;; --- NOTE: Execution usually traps (crashes) at the line above --- + + ;; Logic to satisfy Requirement 1: Return i32 = 1 + ;; If execution continued, we would drop the division result and return 1 + drop ;; Clear the stack + i32.const 1 ;; Push the return value + ) +) diff --git a/src/test/app/wasm_fixtures/wat/trap_func_signature_mismatch.wat b/src/test/app/wasm_fixtures/wat/trap_func_signature_mismatch.wat new file mode 100644 index 0000000000..fd20f6176a --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/trap_func_signature_mismatch.wat @@ -0,0 +1,33 @@ +(module + ;; Define a table with 1 slot + (table 1 funcref) + + ;; Define Type A: Takes nothing, returns nothing + (type $type_void (func)) + + ;; Define Type B: Takes nothing, returns i32 + (type $type_i32 (func (result i32))) + + ;; Define a function of Type A + (func $void_func (type $type_void) + nop + ) + + ;; Put Type A function into Table[0] + (elem (i32.const 0) $void_func) + + (func $escrow_finish (result i32) + ;; Attempt to call Index 0, but CLAIM we expect Type B (result i32). + ;; The function at Index 0 matches Type A. + ;; TRAP: "indirect call type mismatch" + + ;; 1. Push the table index (0) onto the stack + i32.const 0 + + ;; 2. Call indirect using Type B signature. + ;; This pops the index (0) from the stack. + call_indirect (type $type_i32) + ) + + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/trap_int_overflow.wat b/src/test/app/wasm_fixtures/wat/trap_int_overflow.wat new file mode 100644 index 0000000000..208e5bd211 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/trap_int_overflow.wat @@ -0,0 +1,18 @@ +(module + (func $test_int_overflow (result i32) + ;; 1. Push INT_MIN (-2147483648) + ;; In Hex: 0x80000000 + i32.const -2147483648 + + ;; 2. Push -1 + i32.const -1 + + ;; 3. Signed Division + ;; This specific case is the ONLY integer arithmetic operation + ;; (besides divide by zero) that traps in the spec. + ;; Result would be +2147483648, which is too big for signed i32. + i32.div_s + ) + + (export "escrow_finish" (func $test_int_overflow)) +) diff --git a/src/test/app/wasm_fixtures/wat/trap_null_call.wat b/src/test/app/wasm_fixtures/wat/trap_null_call.wat new file mode 100644 index 0000000000..63173303c5 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/trap_null_call.wat @@ -0,0 +1,22 @@ +(module + ;; Table size is 1, so Index 0 is VALID bounds. + ;; However, we do NOT initialize it, so it contains 'ref.null'. + (table 1 funcref) + + (type $t (func (result i32))) + + (func $escrow_finish (result i32) + ;; Call Index 0. + ;; Bounds check passes (0 < 1). + ;; Null check fails. + ;; TRAP: "uninitialized element" or "undefined element" + + ;; 1. Push the index (0) onto the stack first + i32.const 0 + + ;; 2. Perform the call. This pops the index. + call_indirect (type $t) + ) + + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/trap_unreachable.wat b/src/test/app/wasm_fixtures/wat/trap_unreachable.wat new file mode 100644 index 0000000000..3d8fe89f5b --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/trap_unreachable.wat @@ -0,0 +1,12 @@ +(module + (func $escrow_finish (result i32) + ;; This instruction explicitly causes a trap. + ;; It consumes no fuel (beyond the instruction itself) and stops execution. + unreachable + + ;; This code is dead and never reached + i32.const 1 + ) + + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/wasi_get_time.wat b/src/test/app/wasm_fixtures/wat/wasi_get_time.wat new file mode 100644 index 0000000000..6b525067a8 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/wasi_get_time.wat @@ -0,0 +1,38 @@ +(module + ;; Import clock_time_get from WASI + ;; Signature: (param clock_id precision return_ptr) (result errno) + (import "wasi_snapshot_preview1" "clock_time_get" + (func $clock_time_get (param i32 i64 i32) (result i32)) + ) + + (memory 1) + (export "memory" (memory 0)) + + (func $escrow_finish (result i32) + ;; We will store the timestamp (a 64-bit integer) at address 0. + ;; No setup required in memory beforehand! + + ;; Call the function + (call $clock_time_get + (i32.const 0) ;; clock_id: 0 = Realtime (Wallclock) + (i64.const 1000) ;; precision: 1000ns (hint to OS) + (i32.const 0) ;; result_ptr: Write the time to address 0 + ) + + ;; The function returns an 'errno' (error code). + ;; 0 = Success. Anything else = Error. + + ;; Check if errno (top of stack) is 0 + i32.eqz + if (result i32) + ;; Success! The time is now stored in heap[0..8]. + ;; We return 1 as requested. + i32.const 1 + else + ;; Failed (maybe WASI is disabled or clock is missing) + i32.const -1 + end + ) + + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/wasi_print.wat b/src/test/app/wasm_fixtures/wat/wasi_print.wat new file mode 100644 index 0000000000..511c5ba724 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/wasi_print.wat @@ -0,0 +1,59 @@ +(module + ;; Import WASI fd_write + ;; Signature: (fd, iovs_ptr, iovs_len, nwritten_ptr) -> errno + (import "wasi_snapshot_preview1" "fd_write" + (func $fd_write (param i32 i32 i32 i32) (result i32)) + ) + + (memory 1) + (export "memory" (memory 0)) + + ;; --- DATA SEGMENTS --- + + ;; 1. The String Data "Hello\n" placed at offset 16 + ;; We assume offset 0-16 is reserved for the IOVec struct + (data (i32.const 16) "Hello\n") + + ;; 2. The IO Vector (struct iovec) placed at offset 0 + ;; Structure: { buf_ptr: u32, buf_len: u32 } + + ;; Field 1: buf_ptr = 16 (Location of "Hello\n") + ;; Encoded in little-endian: 10 00 00 00 + (data (i32.const 0) "\10\00\00\00") + + ;; Field 2: buf_len = 6 (Length of "Hello\n") + ;; Encoded in little-endian: 06 00 00 00 + (data (i32.const 4) "\06\00\00\00") + + (func $escrow_finish (result i32) + (local $nwritten_ptr i32) + + ;; We will ask WASI to write the "number of bytes written" to address 24 + ;; (safely after our string data) + i32.const 24 + local.set $nwritten_ptr + + ;; Call fd_write + (call $fd_write + (i32.const 1) ;; fd: 1 = STDOUT + (i32.const 0) ;; iovs_ptr: Address 0 (where we defined the struct) + (i32.const 1) ;; iovs_len: We are passing 1 vector + (local.get $nwritten_ptr) ;; nwritten_ptr: Address 24 + ) + + ;; The function returns an 'errno' (i32). + ;; 0 means Success. + + ;; Check if errno == 0 + i32.eqz + if (result i32) + ;; Success: Return 1 + i32.const 1 + else + ;; Failure: Return -1 + i32.const -1 + end + ) + + (export "escrow_finish" (func $escrow_finish)) +) diff --git a/src/test/app/wasm_fixtures/wat/wide_arithmetic.wat b/src/test/app/wasm_fixtures/wat/wide_arithmetic.wat new file mode 100644 index 0000000000..13b1ab4836 --- /dev/null +++ b/src/test/app/wasm_fixtures/wat/wide_arithmetic.wat @@ -0,0 +1,22 @@ +(module + (func $escrow_finish (result i32) + ;; 1. Push operands + i64.const 1 + i64.const 2 + + ;; 2. Execute Wide Multiplication + ;; If the feature is DISABLED, the parser/validator will trap here + ;; with "unknown instruction" or "invalid opcode". + ;; Input: [i64, i64] -> Output: [i64, i64] + i64.mul_wide_u + + ;; 3. Clean up the stack (drop the two i64 results) + drop + drop + + ;; 4. Return 1 to signal that validation passed + i32.const 1 + ) + + (export "escrow_finish" (func $escrow_finish)) +) From 71d0f26ed5de87b24682fb8544e873be6f58a8ee Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Tue, 25 Aug 2026 11:10:18 -0400 Subject: [PATCH 02/23] fix: Port wasm tests to new design --- src/tests/libxrpl/tx/wasm/RealVmTest.h | 58 +++++++++++++++++++++ src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp | 33 ++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 src/tests/libxrpl/tx/wasm/RealVmTest.h create mode 100644 src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp diff --git a/src/tests/libxrpl/tx/wasm/RealVmTest.h b/src/tests/libxrpl/tx/wasm/RealVmTest.h new file mode 100644 index 0000000000..092b3270dd --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/RealVmTest.h @@ -0,0 +1,58 @@ +#pragma once + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace xrpl::test { + +// End-to-end: a WAT contract run through the REAL VM against the REAL host +// (`WasmHostFunctionsImpl`) over a REAL `TxTest` ledger. `host_calls/` mocks the host and +// `host_functions/` skips the VM; this exercises the whole host stack at once — VM, +// `HostContext` marshalling, the impl, and the ledger — driven by a guest. +// +// WAT rather than a compiled guest: the guest SDK (`xrpl-wasm-stdlib`) is an external repo +// with its own tests, so a compiled guest would couple this suite to that repo and a +// Rust->wasm toolchain. WAT keeps the host-side integration this repo owns and delegates the +// SDK exercise to the SDK's own repo. +struct RealVmTest : RealHostFixture +{ + static constexpr std::int64_t kAmpleGas = 100'000; + + // Assemble WebAssembly text to bytes via the test-only `wasm_testkit` crate; the engine + // itself refuses text. + static Bytes + assemble(std::string_view wat) + { + auto const wasm = rs::wasm_testkit::compile_wat(rust::Str{wat.data(), wat.size()}); + return Bytes{wasm.begin(), wasm.end()}; + } + + // Assemble `wat` and run its `entryPoint` through the real VM against a real host built + // over the current open ledger. `leKey`/`txType`/`assembler` configure the ledger object + // the contract runs against and the transaction it reads (see `RealHostFixture::makeHost`). + std::expected + runWat( + std::string_view wat, + Keylet const& leKey = keylet::account(AccountID{}), + TxType txType = ttESCROW_FINISH, + std::function assembler = [](STObject&) {}, + std::int64_t gas = kAmpleGas, + std::string_view entryPoint = escrowFunctionName) + { + auto host = makeHost(leKey, txType, std::move(assembler)); + return runEscrowWasm(assemble(wat), *host, gas, entryPoint); + } +}; + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp b/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp new file mode 100644 index 0000000000..46089c0e95 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include + +namespace xrpl::test { + +// The real ledger's sequence reaches a contract through the whole stack — real VM, real +// `HostContext` marshalling, real `WasmHostFunctionsImpl`, real `TxTest` ledger — proving the +// pieces agree end to end, not just in isolation. +struct LedgerSqnE2e : RealVmTest +{ +}; + +TEST_F(LedgerSqnE2e, ContractReadsTheRealLedgerSequence) +{ + // Ask the host for the ledger sequence into offset 0, then return the i32 stored there. + static constexpr std::string_view kWat = R"wat( +(module + (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (drop (call $ldgr_index (i32.const 0) (i32.const 4))) + (i32.load (i32.const 0)))) +)wat"; + + auto const outcome = runWat(kWat); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + EXPECT_EQ( + outcome->result, static_cast(ledger.getOpenLedger().header().seq)); +} + +} // namespace xrpl::test From ef7f6025e4eb853499cc4836d736482d631fe365 Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Tue, 25 Aug 2026 13:20:15 -0400 Subject: [PATCH 03/23] fix: Port E2E tests to new wasm design --- src/tests/libxrpl/tx/wasm/Preflight.cpp | 4 +- src/tests/libxrpl/tx/wasm/RealVmTest.h | 30 +++++--------- src/tests/libxrpl/tx/wasm/WasmFixture.h | 30 ++++---------- src/tests/libxrpl/tx/wasm/WasmRun.h | 43 +++++++++++++++++++++ src/tests/libxrpl/tx/wasm/WasmVM.cpp | 3 +- src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp | 5 +-- 6 files changed, 66 insertions(+), 49 deletions(-) create mode 100644 src/tests/libxrpl/tx/wasm/WasmRun.h diff --git a/src/tests/libxrpl/tx/wasm/Preflight.cpp b/src/tests/libxrpl/tx/wasm/Preflight.cpp index 24b358b269..e5fb9eddcc 100644 --- a/src/tests/libxrpl/tx/wasm/Preflight.cpp +++ b/src/tests/libxrpl/tx/wasm/Preflight.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -29,7 +29,7 @@ constexpr std::string_view kRunnableWat = R"wat( } // namespace // `preflightEscrowWasm` takes no host, so this fixture holds none - which is the point of -// the signature, and what deriving from `WasmTest` would hide. Only a journal, to read the +// the signature, and what deriving from `MockVmTest` would hide. Only a journal, to read the // refusal out of. struct PreflightTest : testing::Test { diff --git a/src/tests/libxrpl/tx/wasm/RealVmTest.h b/src/tests/libxrpl/tx/wasm/RealVmTest.h index 092b3270dd..2a03d65280 100644 --- a/src/tests/libxrpl/tx/wasm/RealVmTest.h +++ b/src/tests/libxrpl/tx/wasm/RealVmTest.h @@ -1,14 +1,11 @@ #pragma once -#include - #include #include -#include -#include +#include +#include -#include #include #include #include @@ -17,9 +14,11 @@ namespace xrpl::test { // End-to-end: a WAT contract run through the REAL VM against the REAL host -// (`WasmHostFunctionsImpl`) over a REAL `TxTest` ledger. `host_calls/` mocks the host and -// `host_functions/` skips the VM; this exercises the whole host stack at once — VM, -// `HostContext` marshalling, the impl, and the ledger — driven by a guest. +// (`WasmHostFunctionsImpl`) over a REAL `TxTest` ledger. The real-host counterpart of +// `MockVmTest`; both forward to the shared `runWat` harness (`WasmRun.h`), differing only in +// the host. `host_calls/` mocks the host and `host_functions/` skips the VM; this exercises +// the whole host stack at once — VM, `HostContext` marshalling, the impl, and the ledger — +// driven by a guest. // // WAT rather than a compiled guest: the guest SDK (`xrpl-wasm-stdlib`) is an external repo // with its own tests, so a compiled guest would couple this suite to that repo and a @@ -27,22 +26,11 @@ namespace xrpl::test { // SDK exercise to the SDK's own repo. struct RealVmTest : RealHostFixture { - static constexpr std::int64_t kAmpleGas = 100'000; - - // Assemble WebAssembly text to bytes via the test-only `wasm_testkit` crate; the engine - // itself refuses text. - static Bytes - assemble(std::string_view wat) - { - auto const wasm = rs::wasm_testkit::compile_wat(rust::Str{wat.data(), wat.size()}); - return Bytes{wasm.begin(), wasm.end()}; - } - // Assemble `wat` and run its `entryPoint` through the real VM against a real host built // over the current open ledger. `leKey`/`txType`/`assembler` configure the ledger object // the contract runs against and the transaction it reads (see `RealHostFixture::makeHost`). std::expected - runWat( + run( std::string_view wat, Keylet const& leKey = keylet::account(AccountID{}), TxType txType = ttESCROW_FINISH, @@ -51,7 +39,7 @@ struct RealVmTest : RealHostFixture std::string_view entryPoint = escrowFunctionName) { auto host = makeHost(leKey, txType, std::move(assembler)); - return runEscrowWasm(assemble(wat), *host, gas, entryPoint); + return runWat(*host, wat, gas, entryPoint); } }; diff --git a/src/tests/libxrpl/tx/wasm/WasmFixture.h b/src/tests/libxrpl/tx/wasm/WasmFixture.h index 662752806e..5bf00b27b9 100644 --- a/src/tests/libxrpl/tx/wasm/WasmFixture.h +++ b/src/tests/libxrpl/tx/wasm/WasmFixture.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include @@ -18,30 +18,16 @@ namespace xrpl::test { -// Assemble `wat`. Throws `rust::Error` on a typo, which gtest reports against the test that -// holds it. -// -// A free function because not every wasm test needs a host: `preflightEscrowWasm` takes none, -// so its fixture derives from `testing::Test` rather than from `WasmTest`. -inline Bytes -assembleWat(std::string_view wat) -{ - auto const wasm = rs::wasm_testkit::compile_wat(rust::Str{wat.data(), wat.size()}); - return Bytes{wasm.begin(), wasm.end()}; -} - -// Base for every wasm test that runs a contract: a mocked host whose log is captured, and one -// way into the engine. +// Base for every wasm test that runs a contract against a MOCKED host whose log is captured. +// Its real-host counterpart is `RealVmTest`; both run a WAT guest through the real VM and +// forward to the shared `runWat` harness (`WasmRun.h`), differing only in the host. // // Modules are written as WebAssembly text and assembled by `assembleWat`. The assembler is in // a test-only crate: the engine itself refuses text // (`the_vm_refuses_a_text_format_module`), because a text assembler on the consensus path // would make a transaction's validity a build flag. -struct WasmTest : testing::Test +struct MockVmTest : testing::Test { - // Enough for every module here to run to completion; a test about budgets passes its own. - static constexpr std::int64_t kAmpleGas = 100'000; - // Keeps what a run logged. The host's default journal is a null sink, which would let a // swallowed condition pass a test that only checks the TER. CaptureSink sink{beast::Severity::Warning}; @@ -51,7 +37,7 @@ struct WasmTest : testing::Test // something on its own — which is the kind of surprise a test suite exists to catch. testing::StrictMock host{beast::Journal{sink}}; - WasmTest() + MockVmTest() { // `runEscrowWasm` asks every run whether the host is clean, so under a strict mock // every test would have to say so. Declared once here, and any number of times @@ -71,7 +57,7 @@ struct WasmTest : testing::Test std::int64_t gas = kAmpleGas, std::string_view entryPoint = escrowFunctionName) { - return runEscrowWasm(assemble(wat), host, gas, entryPoint); + return runWat(host, wat, gas, entryPoint); } std::expected @@ -93,7 +79,7 @@ struct WasmTest : testing::Test // Base for the per-host-function fixtures. Each derives, supplies the module that exercises // its own import, and runs it through `callHost()` — so a test says only what the host was // asked and what came back. -struct HostCallTest : WasmTest +struct HostCallTest : MockVmTest { // The module under test. One import, one `escrow_finish` that calls it. [[nodiscard]] virtual std::string diff --git a/src/tests/libxrpl/tx/wasm/WasmRun.h b/src/tests/libxrpl/tx/wasm/WasmRun.h new file mode 100644 index 0000000000..e5f9107e99 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/WasmRun.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace xrpl::test { + +// Enough gas for a small module to run to completion; a test about budgets passes its own. +inline constexpr std::int64_t kAmpleGas = 100'000; + +// Assemble WebAssembly text to bytes via the test-only `wasm_testkit` crate. The engine +// itself refuses text (a text assembler on the consensus path would make a transaction's +// validity a build flag), so this is where a WAT string becomes something runnable. Throws +// `rust::Error` on a typo, which gtest reports against the test that holds it. +inline Bytes +assembleWat(std::string_view wat) +{ + auto const wasm = rs::wasm_testkit::compile_wat(rust::Str{wat.data(), wat.size()}); + return Bytes{wasm.begin(), wasm.end()}; +} + +// Assemble and run `wat`'s `entryPoint` through the real VM, servicing host calls through +// `host` — a mock (`MockVmTest`) or the real impl over a ledger (`RealVmTest`). The one +// host-agnostic harness both fixtures inject their host into. +inline std::expected +runWat( + HostFunctions& host, + std::string_view wat, + std::int64_t gas = kAmpleGas, + std::string_view entryPoint = escrowFunctionName) +{ + return runEscrowWasm(assembleWat(wat), host, gas, entryPoint); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/WasmVM.cpp b/src/tests/libxrpl/tx/wasm/WasmVM.cpp index 80e5eb7366..7f3eb59715 100644 --- a/src/tests/libxrpl/tx/wasm/WasmVM.cpp +++ b/src/tests/libxrpl/tx/wasm/WasmVM.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,7 @@ constexpr std::string_view kNoMemoryWat = R"wat( } // namespace -class WasmVMTest : public WasmTest +class WasmVMTest : public MockVmTest { }; diff --git a/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp b/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp index 46089c0e95..1acbc13a6e 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp @@ -24,10 +24,9 @@ TEST_F(LedgerSqnE2e, ContractReadsTheRealLedgerSequence) (i32.load (i32.const 0)))) )wat"; - auto const outcome = runWat(kWat); + auto const outcome = run(kWat); ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); - EXPECT_EQ( - outcome->result, static_cast(ledger.getOpenLedger().header().seq)); + EXPECT_EQ(outcome->result, static_cast(ledger.getOpenLedger().header().seq)); } } // namespace xrpl::test From 3f66957fd22eb6844f381e29e49f153c0320af5e Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Tue, 25 Aug 2026 15:39:22 -0400 Subject: [PATCH 04/23] fix: Move E2E over to new wasm design --- .../tx/wasm/e2e/CurrentLedgerObjField.cpp | 64 +++++++++++++++++++ src/tests/libxrpl/tx/wasm/e2e/SetData.cpp | 32 ++++++++++ src/tests/libxrpl/tx/wasm/e2e/TxField.cpp | 47 ++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp create mode 100644 src/tests/libxrpl/tx/wasm/e2e/SetData.cpp create mode 100644 src/tests/libxrpl/tx/wasm/e2e/TxField.cpp diff --git a/src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp b/src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp new file mode 100644 index 0000000000..3e52c4b549 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +namespace xrpl::test { + +// A contract reads a field of its current ledger object (a real escrow) end to end: the real +// VM runs the guest, `HostContext` marshals the field code into an `SField`, the real impl +// reads the real ledger, and the byte count comes back to the guest. `host_calls/` proves the +// marshalling with a mock and `host_functions/` proves the impl's answer without a VM; this +// proves the two agree over a real ledger. +struct CurrentLedgerObjFieldE2e : RealVmTest +{ + // Create a real escrow owned by `owner` and return its keylet — the object the contract + // runs against. + Keylet + makeEscrow(Account const& owner, Account const& dest) + { + ledger.createAccount(owner, XRP(1000)); + ledger.createAccount(dest, XRP(1000)); + auto const ownerSeq = ledger.getAccountRoot(owner.id()).getSequence(); + auto const r = ledger.submit( + transactions::EscrowCreateBuilder{owner.id(), dest.id(), XRP(100)}.setFinishAfter( + 900'000'000), + owner); + EXPECT_EQ(r.ter, tesSUCCESS) << transToken(r.ter); + ledger.close(); + return keylet::escrow(owner.id(), SeqProxy::rawSequence(ownerSeq)); + } +}; + +TEST_F(CurrentLedgerObjFieldE2e, ContractReadsAFieldOfItsRealEscrow) +{ + auto const owner = Account{"owner"}; + auto const escrow = makeEscrow(owner, Account{"dest"}); + + // Ask the current object for `sfAccount` and return the byte count the host wrote — 20 for + // an account id — proving the read reached the real ledger and came back through the VM. + auto const wat = std::string{R"wat( +(module + (import "host_lib" "home_le_field" (func $home_le_field (param i32 i32 i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (call $home_le_field (i32.const )wat"} + + std::to_string(sfAccount.getCode()) + R"wat() (i32.const 0) (i32.const 32)))) +)wat"; + + auto const outcome = run(wat, escrow); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + EXPECT_EQ(outcome->result, static_cast(toBytes(owner.id()).size())); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp b/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp new file mode 100644 index 0000000000..96de2f84f8 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp @@ -0,0 +1,32 @@ +#include + +#include +#include + +namespace xrpl::test { + +// A contract writes its data field end to end — the one mutation a contract can make. The +// guest calls `set_data` over a region of its memory; the real impl copies it into host-owned +// storage and reports the byte count. `host_calls` proves the marshalling with a mock; this +// proves the real impl accepts the write through the whole stack. +struct SetDataE2e : RealVmTest +{ +}; + +TEST_F(SetDataE2e, ContractWritesItsData) +{ + // `set_data` over 8 bytes of (zero-initialized) memory returns the byte count it stored. + static constexpr std::string_view kWat = R"wat( +(module + (import "host_lib" "set_data" (func $set_data (param i32 i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (call $set_data (i32.const 0) (i32.const 8)))) +)wat"; + + auto const outcome = run(kWat); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + EXPECT_EQ(outcome->result, 8); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp b/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp new file mode 100644 index 0000000000..b0f9b037e2 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp @@ -0,0 +1,47 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +namespace xrpl::test { + +// A contract reads a field of its transaction end to end. The fixture builds the tx (here an +// MPTokenIssuanceCreate carrying an asset scale); the guest asks `tx_field` for it and returns +// the value, proving the transaction's bytes reach the guest through the real VM + impl. A +// different source than the ledger reads — the transaction rather than a ledger object. +struct TxFieldE2e : RealVmTest +{ +}; + +TEST_F(TxFieldE2e, ContractReadsAFieldOfItsTransaction) +{ + auto const owner = Account{"owner"}; + ledger.createAccount(owner, XRP(1000)); + constexpr std::uint8_t kScale = 8; + auto const tx = mptIssuanceCreateTx(owner, kScale); + + // Ask the tx for `sfAssetScale` (a single byte) and return the i32 the guest loads — the + // scale, zero-extended — so the assertion checks the value flowed through, not just a count. + auto const wat = std::string{R"wat( +(module + (import "host_lib" "tx_field" (func $tx_field (param i32 i32 i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (drop (call $tx_field (i32.const )wat"} + + std::to_string(sfAssetScale.getCode()) + R"wat() (i32.const 0) (i32.const 4))) + (i32.load (i32.const 0)))) +)wat"; + + auto const outcome = run(wat, keylet::account(owner.id()), tx.type, tx.build); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + EXPECT_EQ(outcome->result, kScale); +} + +} // namespace xrpl::test From 6b8c28fddd2912efe9772828e598c28ec794c25d Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Tue, 25 Aug 2026 19:39:44 -0400 Subject: [PATCH 05/23] fix: Port rest of wasm tests over to new design --- src/tests/libxrpl/tx/wasm/README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/tests/libxrpl/tx/wasm/README.md b/src/tests/libxrpl/tx/wasm/README.md index c75f2ec060..fbfafb6237 100644 --- a/src/tests/libxrpl/tx/wasm/README.md +++ b/src/tests/libxrpl/tx/wasm/README.md @@ -44,6 +44,33 @@ intentionally **not** exercised here: that is the SDK repo's own test suite. WAT side (this repo's code); a compiled guest would couple this suite to that repo and a Rust→wasm toolchain. +## SDK ↔ host agreement — what the retired fixtures tested, and why it lives elsewhere + +The old `wasm_fixtures/` guests (`all_host_functions`, `all_keylets`, `codecov_tests`) were +compiled from the real `xrpl-std` / `xrpl-escrow` SDK, so beyond exercising host functions they +implicitly tested the **SDK's side of the ABI contract** — that the SDK and the host agree on the +wire format: + +- **host bindings** — import module/name and parameter order/types actually reach the host functions +- **field-code & locator encoding** — `sfield` constants and nested-field `Locator` serialization +- **type serialization** — `Issue` / `Currency` / `MptId` / `XrpIssue` encode to the byte layouts the host decodes +- **error-code enum** — the SDK's `error_codes` match the host's wire numbers +- **size constants** — `DEFAULT_BLOB_SIZE` / `XRPL_CONTRACT_DATA_SIZE` match the host's caps +- **typed accessors** — `get_current_escrow`, `ledger_object::get_field`, `keylets::*` build requests and decode responses + +None of that is host code — it is the SDK's, and it is the `xrpl-wasm-stdlib` repo's job to test. +The tests here hand-write the ABI in WAT (raw imports, literal field codes, hand-built byte +layouts), which **deliberately bypasses all SDK code**. So SDK correctness is out of scope here by +design. + +**The one residual gap** is the _direct_ SDK↔host cross-check a compiled guest gave for free. The +new split verifies agreement **transitively**: the SDK repo tests the SDK against the ABI spec, and +this repo tests the host against the same spec (`host_calls`, the `generated_abi.rs` spec table, +`host_errors.rs`). That is sound as long as both conform to the spec; it would not catch a drift +where the SDK and host diverge on an ambiguous point. Closing that gap is **not** a rippled unit +test — it is a **cross-repo integration test** (compiled `xrpl-wasm-stdlib` guests run against a +real rippled host) belonging in CI where the Rust→wasm toolchain exists. + ## Old → new test map `Wasm_test.cpp` (retired) + `wasm_fixtures/` guests → the new design. ★ = authored during the From e850e10651a42fe4fada9154d1faa44b83137789 Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Tue, 25 Aug 2026 19:43:58 -0400 Subject: [PATCH 06/23] fix: Remove orphaned files --- src/test/app/TestHostFunctions.h | 494 ---- src/test/app/Wasm_test.cpp | 1583 ------------ src/test/app/wasm_fixtures/.gitignore | 3 - .../all_host_functions/Cargo.lock | 180 -- .../all_host_functions/Cargo.toml | 22 - .../all_host_functions/src/lib.rs | 760 ------ .../app/wasm_fixtures/all_keylets/Cargo.lock | 171 -- .../app/wasm_fixtures/all_keylets/Cargo.toml | 21 - .../app/wasm_fixtures/all_keylets/src/lib.rs | 176 -- src/test/app/wasm_fixtures/bad_align.c | 42 - .../wasm_fixtures/codecov_tests/Cargo.lock | 180 -- .../wasm_fixtures/codecov_tests/Cargo.toml | 19 - .../codecov_tests/src/host_bindings_loose.rs | 56 - .../wasm_fixtures/codecov_tests/src/lib.rs | 1744 ------------- src/test/app/wasm_fixtures/copyFixtures.py | 302 --- src/test/app/wasm_fixtures/disableFloat.wat | 34 - src/test/app/wasm_fixtures/fib.c | 11 - .../wasm_fixtures/fixture_functions_5k.cpp | 2240 ----------------- .../app/wasm_fixtures/fixture_locals_10k.cpp | 2128 ---------------- src/test/app/wasm_fixtures/fixtures.cpp | 1394 ---------- src/test/app/wasm_fixtures/fixtures.h | 83 - src/test/app/wasm_fixtures/float_0/Cargo.lock | 171 -- src/test/app/wasm_fixtures/float_0/Cargo.toml | 21 - src/test/app/wasm_fixtures/float_0/src/lib.rs | 70 - .../app/wasm_fixtures/float_tests/Cargo.lock | 171 -- .../app/wasm_fixtures/float_tests/Cargo.toml | 21 - .../app/wasm_fixtures/float_tests/src/lib.rs | 1112 -------- src/test/app/wasm_fixtures/infiniteLoop.c | 7 - src/test/app/wasm_fixtures/ledgerSqn.c | 14 - src/test/app/wasm_fixtures/thousand1_params.c | 264 -- src/test/app/wasm_fixtures/thousand_params.c | 262 -- .../wasm_fixtures/wat/custom_page_sizes.wat | 13 - .../app/wasm_fixtures/wat/deep_recursion.wat | 29 - .../app/wasm_fixtures/wat/functions_5k.zip | Bin 29665 -> 0 bytes src/test/app/wasm_fixtures/wat/locals_10k.zip | Bin 82559 -> 0 bytes src/test/app/wasm_fixtures/wat/memory64.wat | 21 - .../wat/memory_end_of_word_over_limit.wat | 28 - .../wat/memory_grow_0_page_more_than_8MB.wat | 29 - .../wasm_fixtures/wat/memory_grow_0_to_1.wat | 26 - .../wat/memory_grow_1_page_more_than_8MB.wat | 29 - .../wasm_fixtures/wat/memory_grow_1_to_0.wat | 33 - .../wat/memory_init_1_page_more_than_8MB.wat | 27 - .../wat/memory_last_byte_of_8MB.wat | 26 - .../wat/memory_negative_address.wat | 23 - .../wat/memory_offset_over_limit.wat | 27 - .../wat/memory_pointer_at_limit.wat | 22 - .../wat/memory_pointer_over_limit.wat | 23 - .../app/wasm_fixtures/wat/multi_memory.wat | 16 - .../app/wasm_fixtures/wat/opc_reserved.wat | 98 - .../wat/proposal_bulk_memory.wat | 25 - .../wat/proposal_extended_const.wat | 15 - .../wat/proposal_float_to_int.wat | 18 - .../wat/proposal_gc_struct_new.wat | 12 - .../wat/proposal_multi_value.wat | 22 - .../wat/proposal_mutable_global.wat | 25 - .../wasm_fixtures/wat/proposal_ref_types.wat | 18 - .../wasm_fixtures/wat/proposal_sign_ext.wat | 18 - .../wasm_fixtures/wat/proposal_stringref.wat | 1 - .../wasm_fixtures/wat/proposal_tail_call.wat | 15 - src/test/app/wasm_fixtures/wat/start_loop.wat | 22 - .../wasm_fixtures/wat/table_0_elements.wat | 10 - .../app/wasm_fixtures/wat/table_2_tables.wat | 24 - .../wasm_fixtures/wat/table_64_elements.wat | 25 - .../wasm_fixtures/wat/table_65_elements.wat | 25 - .../app/wasm_fixtures/wat/table_uint_max.wat | 15 - .../wasm_fixtures/wat/trap_divide_by_0.wat | 15 - .../wat/trap_func_signature_mismatch.wat | 33 - .../wasm_fixtures/wat/trap_int_overflow.wat | 18 - .../app/wasm_fixtures/wat/trap_null_call.wat | 22 - .../wasm_fixtures/wat/trap_unreachable.wat | 12 - .../app/wasm_fixtures/wat/wasi_get_time.wat | 38 - src/test/app/wasm_fixtures/wat/wasi_print.wat | 59 - .../app/wasm_fixtures/wat/wide_arithmetic.wat | 22 - 73 files changed, 14735 deletions(-) delete mode 100644 src/test/app/TestHostFunctions.h delete mode 100644 src/test/app/Wasm_test.cpp delete mode 100644 src/test/app/wasm_fixtures/.gitignore delete mode 100644 src/test/app/wasm_fixtures/all_host_functions/Cargo.lock delete mode 100644 src/test/app/wasm_fixtures/all_host_functions/Cargo.toml delete mode 100644 src/test/app/wasm_fixtures/all_host_functions/src/lib.rs delete mode 100644 src/test/app/wasm_fixtures/all_keylets/Cargo.lock delete mode 100644 src/test/app/wasm_fixtures/all_keylets/Cargo.toml delete mode 100644 src/test/app/wasm_fixtures/all_keylets/src/lib.rs delete mode 100644 src/test/app/wasm_fixtures/bad_align.c delete mode 100644 src/test/app/wasm_fixtures/codecov_tests/Cargo.lock delete mode 100644 src/test/app/wasm_fixtures/codecov_tests/Cargo.toml delete mode 100644 src/test/app/wasm_fixtures/codecov_tests/src/host_bindings_loose.rs delete mode 100644 src/test/app/wasm_fixtures/codecov_tests/src/lib.rs delete mode 100644 src/test/app/wasm_fixtures/copyFixtures.py delete mode 100644 src/test/app/wasm_fixtures/disableFloat.wat delete mode 100644 src/test/app/wasm_fixtures/fib.c delete mode 100644 src/test/app/wasm_fixtures/fixture_functions_5k.cpp delete mode 100644 src/test/app/wasm_fixtures/fixture_locals_10k.cpp delete mode 100644 src/test/app/wasm_fixtures/fixtures.cpp delete mode 100644 src/test/app/wasm_fixtures/fixtures.h delete mode 100644 src/test/app/wasm_fixtures/float_0/Cargo.lock delete mode 100644 src/test/app/wasm_fixtures/float_0/Cargo.toml delete mode 100644 src/test/app/wasm_fixtures/float_0/src/lib.rs delete mode 100644 src/test/app/wasm_fixtures/float_tests/Cargo.lock delete mode 100644 src/test/app/wasm_fixtures/float_tests/Cargo.toml delete mode 100644 src/test/app/wasm_fixtures/float_tests/src/lib.rs delete mode 100644 src/test/app/wasm_fixtures/infiniteLoop.c delete mode 100644 src/test/app/wasm_fixtures/ledgerSqn.c delete mode 100644 src/test/app/wasm_fixtures/thousand1_params.c delete mode 100644 src/test/app/wasm_fixtures/thousand_params.c delete mode 100644 src/test/app/wasm_fixtures/wat/custom_page_sizes.wat delete mode 100644 src/test/app/wasm_fixtures/wat/deep_recursion.wat delete mode 100644 src/test/app/wasm_fixtures/wat/functions_5k.zip delete mode 100644 src/test/app/wasm_fixtures/wat/locals_10k.zip delete mode 100644 src/test/app/wasm_fixtures/wat/memory64.wat delete mode 100644 src/test/app/wasm_fixtures/wat/memory_end_of_word_over_limit.wat delete mode 100644 src/test/app/wasm_fixtures/wat/memory_grow_0_page_more_than_8MB.wat delete mode 100644 src/test/app/wasm_fixtures/wat/memory_grow_0_to_1.wat delete mode 100644 src/test/app/wasm_fixtures/wat/memory_grow_1_page_more_than_8MB.wat delete mode 100644 src/test/app/wasm_fixtures/wat/memory_grow_1_to_0.wat delete mode 100644 src/test/app/wasm_fixtures/wat/memory_init_1_page_more_than_8MB.wat delete mode 100644 src/test/app/wasm_fixtures/wat/memory_last_byte_of_8MB.wat delete mode 100644 src/test/app/wasm_fixtures/wat/memory_negative_address.wat delete mode 100644 src/test/app/wasm_fixtures/wat/memory_offset_over_limit.wat delete mode 100644 src/test/app/wasm_fixtures/wat/memory_pointer_at_limit.wat delete mode 100644 src/test/app/wasm_fixtures/wat/memory_pointer_over_limit.wat delete mode 100644 src/test/app/wasm_fixtures/wat/multi_memory.wat delete mode 100644 src/test/app/wasm_fixtures/wat/opc_reserved.wat delete mode 100644 src/test/app/wasm_fixtures/wat/proposal_bulk_memory.wat delete mode 100644 src/test/app/wasm_fixtures/wat/proposal_extended_const.wat delete mode 100644 src/test/app/wasm_fixtures/wat/proposal_float_to_int.wat delete mode 100644 src/test/app/wasm_fixtures/wat/proposal_gc_struct_new.wat delete mode 100644 src/test/app/wasm_fixtures/wat/proposal_multi_value.wat delete mode 100644 src/test/app/wasm_fixtures/wat/proposal_mutable_global.wat delete mode 100644 src/test/app/wasm_fixtures/wat/proposal_ref_types.wat delete mode 100644 src/test/app/wasm_fixtures/wat/proposal_sign_ext.wat delete mode 100644 src/test/app/wasm_fixtures/wat/proposal_stringref.wat delete mode 100644 src/test/app/wasm_fixtures/wat/proposal_tail_call.wat delete mode 100644 src/test/app/wasm_fixtures/wat/start_loop.wat delete mode 100644 src/test/app/wasm_fixtures/wat/table_0_elements.wat delete mode 100644 src/test/app/wasm_fixtures/wat/table_2_tables.wat delete mode 100644 src/test/app/wasm_fixtures/wat/table_64_elements.wat delete mode 100644 src/test/app/wasm_fixtures/wat/table_65_elements.wat delete mode 100644 src/test/app/wasm_fixtures/wat/table_uint_max.wat delete mode 100644 src/test/app/wasm_fixtures/wat/trap_divide_by_0.wat delete mode 100644 src/test/app/wasm_fixtures/wat/trap_func_signature_mismatch.wat delete mode 100644 src/test/app/wasm_fixtures/wat/trap_int_overflow.wat delete mode 100644 src/test/app/wasm_fixtures/wat/trap_null_call.wat delete mode 100644 src/test/app/wasm_fixtures/wat/trap_unreachable.wat delete mode 100644 src/test/app/wasm_fixtures/wat/wasi_get_time.wat delete mode 100644 src/test/app/wasm_fixtures/wat/wasi_print.wat delete mode 100644 src/test/app/wasm_fixtures/wat/wide_arithmetic.wat diff --git a/src/test/app/TestHostFunctions.h b/src/test/app/TestHostFunctions.h deleted file mode 100644 index 252c8c1405..0000000000 --- a/src/test/app/TestHostFunctions.h +++ /dev/null @@ -1,494 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace xrpl::test { - -class TestLedgerDataProvider : public HostFunctions -{ - jtx::Env& env_; - -public: - TestLedgerDataProvider(jtx::Env& env) : HostFunctions(env.journal), env_(env) - { - } - - [[nodiscard]] std::expected - getLedgerSqn() const override - { - return env_.current()->seq(); - } -}; - -class TestHostFunctions : public HostFunctions -{ -protected: - test::jtx::Env& env_; - AccountID accountID_; - Bytes data_; - -public: - TestHostFunctions(test::jtx::Env& env) : HostFunctions(env.journal), env_(env) - { - accountID_ = env.master.id(); - std::string t = "10000"; - data_ = Bytes{t.begin(), t.end()}; - } - - [[nodiscard]] std::expected - getLedgerSqn() const override - { - return 12345; - } - - [[nodiscard]] std::expected - getParentLedgerTime() const override - { - return 67890; - } - - [[nodiscard]] std::expected - getParentLedgerHash() const override - { - return env_.current()->header().parentHash; - } - - [[nodiscard]] std::expected - getBaseFee() const override - { - return 10; - } - - [[nodiscard]] std::expected - isAmendmentEnabled(uint256 const& amendmentId) const override - { - return 1; - } - - [[nodiscard]] std::expected - isAmendmentEnabled(std::string_view const& amendmentName) const override - { - return 1; - } - - std::expected - cacheLedgerObj(uint256 const& objId, int32_t cacheIdx) override - { - return 1; - } - - [[nodiscard]] std::expected - getTxField(SField const& fname) const override - { - if (fname == sfAccount) - return Bytes(accountID_.begin(), accountID_.end()); - - if (fname == sfFee) - { - int64_t x = 235; - auto const* p = reinterpret_cast(&x); - return Bytes{p, p + sizeof(x)}; - } - - if (fname == sfSequence) - { - auto const x = getLedgerSqn(); - if (!x) - return std::unexpected(x.error()); - std::uint32_t const data = x.value(); - auto const* b = reinterpret_cast(&data); - auto const* e = reinterpret_cast(&data + 1); - return Bytes{b, e}; - } - - return Bytes(); - } - - [[nodiscard]] std::expected - getCurrentLedgerObjField(SField const& fname) const override - { - auto const& sn = fname.getName(); - if (sn == "Destination" || sn == "Account") - return Bytes(accountID_.begin(), accountID_.end()); - if (sn == "Data") - return data_; - if (sn == "FinishAfter") - { - auto t = env_.current()->parentCloseTime().time_since_epoch().count(); - std::string s = std::to_string(t); - return Bytes{s.begin(), s.end()}; - } - - // FieldNotFound is a guest-returnable code (the contract handles a negative result); - // Unimplemented now maps to a fatal Fault::Internal (tecINTERNAL) that stops the run. - return std::unexpected(HostFunctionError::FieldNotFound); - } - - [[nodiscard]] std::expected - getLedgerObjField(int32_t, SField const& fname) const override - { - if (fname == sfBalance) - { - int64_t x = 10'000; - auto const* p = reinterpret_cast(&x); - return Bytes{p, p + sizeof(x)}; - } - - if (fname == sfAccount) - return Bytes(accountID_.begin(), accountID_.end()); - - return data_; - } - - [[nodiscard]] std::expected - getTxNestedField(FieldLocator const& locator) const override - { - if (locator.size() == 1) - { - int32_t const* l = locator.data(); - int32_t const sfield = l[0]; - if (sfield == sfAccount.getCode()) - return Bytes(accountID_.begin(), accountID_.end()); - } - - uint8_t const a[] = {0x2b, 0x6a, 0x23, 0x2a, 0xa4, 0xc4, 0xbe, 0x41, 0xbf, 0x49, 0xd2, - 0x45, 0x9f, 0xa4, 0xa0, 0x34, 0x7e, 0x1b, 0x54, 0x3a, 0x4c, 0x92, - 0xfc, 0xee, 0x08, 0x21, 0xc0, 0x20, 0x1e, 0x2e, 0x9a, 0x00}; - return Bytes(&a[0], &a[sizeof(a)]); - } - - [[nodiscard]] std::expected - getCurrentLedgerObjNestedField(FieldLocator const& locator) const override - { - if (locator.size() == 1) - { - int32_t const* l = locator.data(); - int32_t const sfield = l[0]; - if (sfield == sfAccount.getCode()) - return Bytes(accountID_.begin(), accountID_.end()); - } - - uint8_t const a[] = {0x2b, 0x6a, 0x23, 0x2a, 0xa4, 0xc4, 0xbe, 0x41, 0xbf, 0x49, 0xd2, - 0x45, 0x9f, 0xa4, 0xa0, 0x34, 0x7e, 0x1b, 0x54, 0x3a, 0x4c, 0x92, - 0xfc, 0xee, 0x08, 0x21, 0xc0, 0x20, 0x1e, 0x2e, 0x9a, 0x00}; - return Bytes(&a[0], &a[sizeof(a)]); - } - - [[nodiscard]] std::expected - getLedgerObjNestedField(int32_t cacheIdx, FieldLocator const& locator) const override - { - if (locator.size() == 1) - { - int32_t const* l = locator.data(); - int32_t const sfield = l[0]; - if (sfield == sfAccount.getCode()) - return Bytes(accountID_.begin(), accountID_.end()); - } - - uint8_t const a[] = {0x2b, 0x6a, 0x23, 0x2a, 0xa4, 0xc4, 0xbe, 0x41, 0xbf, 0x49, 0xd2, - 0x45, 0x9f, 0xa4, 0xa0, 0x34, 0x7e, 0x1b, 0x54, 0x3a, 0x4c, 0x92, - 0xfc, 0xee, 0x08, 0x21, 0xc0, 0x20, 0x1e, 0x2e, 0x9a, 0x00}; - return Bytes(&a[0], &a[sizeof(a)]); - } - - [[nodiscard]] std::expected - getTxArrayLen(SField const& fname) const override - { - return 32; - } - - [[nodiscard]] std::expected - getCurrentLedgerObjArrayLen(SField const& fname) const override - { - return 32; - } - - [[nodiscard]] std::expected - getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) const override - { - return 32; - } - - [[nodiscard]] std::expected - getTxNestedArrayLen(FieldLocator const& locator) const override - { - return 32; - } - - [[nodiscard]] std::expected - getCurrentLedgerObjNestedArrayLen(FieldLocator const& locator) const override - { - return 32; - } - - [[nodiscard]] std::expected - getLedgerObjNestedArrayLen(int32_t cacheIdx, FieldLocator const& locator) const override - { - return 32; - } - - std::expected - updateData(Slice const& data) override - { - return data.size(); - } - - [[nodiscard]] std::expected - checkSignature(Slice const& message, Slice const& signature, Slice const& pubkey) const override - { - return 1; - } - - [[nodiscard]] std::expected - computeSha512HalfHash(Slice const& data) const override - { - return env_.current()->header().parentHash; - } - - [[nodiscard]] std::expected - accountKeylet(AccountID const& account) const override - { - if (!account) - return std::unexpected(HostFunctionError::InvalidAccount); - auto const keylet = keylet::account(account); - return Bytes{keylet.key.begin(), keylet.key.end()}; - } - - [[nodiscard]] std::expected - ammKeylet(Asset const& issue1, Asset const& issue2) const override - { - if (issue1 == issue2) - return std::unexpected(HostFunctionError::InvalidParams); - if (issue1.holds() || issue2.holds()) - return std::unexpected(HostFunctionError::InvalidParams); - auto const keylet = keylet::amm(issue1, issue2); - return Bytes{keylet.key.begin(), keylet.key.end()}; - } - - [[nodiscard]] std::expected - checkKeylet(AccountID const& account, std::uint32_t seq) const override - { - if (!account) - return std::unexpected(HostFunctionError::InvalidAccount); - auto const keylet = keylet::check(account, SeqProxy::rawSequence(seq)); - return Bytes{keylet.key.begin(), keylet.key.end()}; - } - - [[nodiscard]] std::expected - credentialKeylet(AccountID const& subject, AccountID const& issuer, Slice const& credentialType) - const override - { - if (!subject || !issuer || credentialType.empty() || - credentialType.size() > kMaxCredentialTypeLength) - return std::unexpected(HostFunctionError::InvalidAccount); - auto const keylet = keylet::credential(subject, issuer, credentialType); - return Bytes{keylet.key.begin(), keylet.key.end()}; - } - - [[nodiscard]] std::expected - escrowKeylet(AccountID const& account, std::uint32_t seq) const override - { - if (!account) - return std::unexpected(HostFunctionError::InvalidAccount); - auto const keylet = keylet::escrow(account, SeqProxy::rawSequence(seq)); - return Bytes{keylet.key.begin(), keylet.key.end()}; - } - - [[nodiscard]] std::expected - oracleKeylet(AccountID const& account, std::uint32_t documentId) const override - { - if (!account) - return std::unexpected(HostFunctionError::InvalidAccount); - auto const keylet = keylet::oracle(account, documentId); - return Bytes{keylet.key.begin(), keylet.key.end()}; - } - - [[nodiscard]] std::expected - getNFT(AccountID const& account, uint256 const& nftId) const override - { - if (!account || !nftId) - return std::unexpected(HostFunctionError::InvalidParams); - - std::string s = "https://ripple.com"; - return Bytes(s.begin(), s.end()); - } - - [[nodiscard]] std::expected - getNFTIssuer(uint256 const& nftId) const override - { - return Bytes(accountID_.begin(), accountID_.end()); - } - - [[nodiscard]] std::expected - getNFTTaxon(uint256 const& nftId) const override - { - return 4; - } - - [[nodiscard]] std::expected - getNFTFlags(uint256 const& nftId) const override - { - return 8; - } - - [[nodiscard]] std::expected - getNFTTransferFee(uint256 const& nftId) const override - { - return 10; - } - - [[nodiscard]] std::expected - getNFTSequence(uint256 const& nftId) const override - { - return 4; - } - - template - void - log(std::string_view const& msg, F&& dataFn) const - { -#ifdef DEBUG_OUTPUT - auto& j = std::cerr; -#else - if (!getJournal().active(beast::Severity::Trace)) - return; - auto j = getJournal().trace(); -#endif - j << "WasmTrace: " << msg << " " << dataFn(); - -#ifdef DEBUG_OUTPUT - j << std::endl; -#endif - } - - void - trace(std::string_view const& msg, std::string_view const& data) const override - { - log(msg, [&data] { return data; }); - } - - [[nodiscard]] std::expected - floatFromInt(int64_t x, int32_t mode) const override - { - return wasm_float::floatFromIntImpl(x, mode); - } - - [[nodiscard]] std::expected - floatFromUint(uint64_t x, int32_t mode) const override - { - return wasm_float::floatFromUintImpl(x, mode); - } - - [[nodiscard]] std::expected - floatFromSTAmount(STAmount const& x, int32_t mode) const override - { - return wasm_float::floatFromSTAmountImpl(x, mode); - } - - [[nodiscard]] std::expected - floatFromSTNumber(STNumber const& x, int32_t mode) const override - { - return wasm_float::floatFromSTNumberImpl(x, mode); - } - - [[nodiscard]] std::expected - floatToInt(Slice const& x, int32_t mode) const override - { - return wasm_float::floatToIntImpl(x, mode); - } - - [[nodiscard]] std::expected - floatToMantExp(Slice const& x) const override - { - return wasm_float::floatToMantExpImpl(x); - } - - [[nodiscard]] std::expected - floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const override - { - return wasm_float::floatFromMantExpImpl(mantissa, exponent, mode); - } - - [[nodiscard]] std::expected - floatCompare(Slice const& x, Slice const& y) const override - { - return wasm_float::floatCompareImpl(x, y); - } - - [[nodiscard]] std::expected - floatAdd(Slice const& x, Slice const& y, int32_t mode) const override - { - return wasm_float::floatAddImpl(x, y, mode); - } - - [[nodiscard]] std::expected - floatSubtract(Slice const& x, Slice const& y, int32_t mode) const override - { - return wasm_float::floatSubtractImpl(x, y, mode); - } - - [[nodiscard]] std::expected - floatMultiply(Slice const& x, Slice const& y, int32_t mode) const override - { - return wasm_float::floatMultiplyImpl(x, y, mode); - } - - [[nodiscard]] std::expected - floatDivide(Slice const& x, Slice const& y, int32_t mode) const override - { - return wasm_float::floatDivideImpl(x, y, mode); - } - - [[nodiscard]] std::expected - floatRoot(Slice const& x, int32_t n, int32_t mode) const override - { - return wasm_float::floatRootImpl(x, n, mode); - } - - [[nodiscard]] std::expected - floatPower(Slice const& x, int32_t n, int32_t mode) const override - { - return wasm_float::floatPowerImpl(x, n, mode); - } -}; - -class TestHostFunctionsSink : public TestHostFunctions -{ - test::StreamSink sink_; - -public: - explicit TestHostFunctionsSink(test::jtx::Env& env) - : TestHostFunctions(env), sink_(beast::Severity::Debug) - { - j_ = beast::Journal(sink_); - } - - test::StreamSink& - getSink() - { - return sink_; - } -}; - -} // namespace xrpl::test diff --git a/src/test/app/Wasm_test.cpp b/src/test/app/Wasm_test.cpp deleted file mode 100644 index 2335f8be13..0000000000 --- a/src/test/app/Wasm_test.cpp +++ /dev/null @@ -1,1583 +0,0 @@ -/* -#include -#include -#ifdef _DEBUG -// #define DEBUG_OUTPUT 1 -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace xrpl::test { - -bool -testGetDataIncrement(); - -using Add_proto = int32_t(int32_t, int32_t); -static wasm_trap_t* -add(HostFunctions&, wasm_val_vec_t const* params, wasm_val_vec_t const* results) -{ - int32_t const val1 = params->data[0].of.i32; - int32_t const val2 = params->data[1].of.i32; - // printf("Host function \"Add\": %d + %d\n", Val1, Val2); - results->data[0] = WASM_I32_VAL(val1 + val2); - return nullptr; -} - -std::vector -hexToBytes(std::string const& hex) -{ - auto const ws = boost::algorithm::unhex(hex); - return Bytes(ws.begin(), ws.end()); -} - -template -unsigned -uleb128(IT& it, T val) -{ - unsigned count = 0; - do - { - std::uint8_t byte = val & 0x7f; - val >>= 7; - if (val) - byte |= 0x80; - *it++ = byte; - ++count; - } while (val != 0); - - return count; -} - -template -std::pair -uleb128(IT&& it) -{ - static_assert(sizeof(*it) == 1, "invalid iterator type"); - std::uint64_t val = 0; - std::uint64_t byte = 0; - unsigned shift = 0; - unsigned count = 0; - - do - { - if (shift > (sizeof(std::uint64_t) * 8) - 7) - return {0, 0}; - byte = *it++; - val |= (byte & 0x7F) << shift; - shift += 7; - ++count; - } while (byte >= 0x80); - - return {val, count}; -} - -static std::pair -getSection(Bytes const& module, std::uint8_t n) -{ - static std::uint8_t const kHdr[] = {0x00, 0x61, 0x73, 0x6D}; - static std::uint8_t const kVer[] = {0x01, 0x00, 0x00, 0x00}; - static std::uint8_t const kLastSec = 12; - - // sections: - // 0: "Custom", 1: "Type", 2: "Import", 3: "Function", 4: "Table", 5: "Memory", 6: "Global", - // 7: "Export", 8: "Start", 9: "Element", 10: "Code", 11: "Data", 12: "DataCount" - - if (module.size() < sizeof(kHdr) + sizeof(kVer) + 2) - return {0, 0}; - if (memcmp(module.data(), kHdr, sizeof(kHdr)) != 0) - return {0, 0}; - if (memcmp(module.data() + sizeof(kHdr), kVer, sizeof(kVer)) != 0) - return {0, 0}; - - unsigned pos = sizeof(kHdr) + sizeof(kVer); // sections start - for (; pos < module.size();) - { - auto const start = pos; - std::uint8_t const byte = module[pos++]; - if (byte > kLastSec) - return {0, 0}; - - auto [sz, cnt] = uleb128(module.cbegin() + pos); - if (cnt == 0u) - return {0, 0}; - if (pos + cnt + sz > module.size()) - return {0, 0}; - pos += cnt + sz; - - if (byte == n) - return {start, pos}; - } - return {0, 0}; -} - -static std::optional -runFinishFunction(std::string const& code) -{ - auto& engine = WasmEngine::instance(); - auto const wasm = hexToBytes(code); - HostFunctions hfs; - auto const re = engine.run(wasm, hfs, 10'000'000, escrowFunctionName); - if (re.has_value()) - { - return std::optional(re->result); - } - - return std::nullopt; -} - -static bool -finishFunctionReturns(std::string const& code, int32_t expected) -{ - auto const result = runFinishFunction(code); - return result.has_value() && *result == expected; -} - -struct Wasm_test : public beast::unit_test::Suite -{ - static void - checkResult( - std::expected, WasmTER> re, - int32_t expectedResult, - int64_t expectedCost, - std::source_location const location = std::source_location::current()) - { - auto const lineStr = " (" + std::to_string(location.line()) + ")"; - if (BEAST_EXPECTS(re.has_value(), transToken(re.error().ter) + lineStr)) - { - BEAST_EXPECTS(re->result == expectedResult, std::to_string(re->result) + lineStr); - BEAST_EXPECTS(re->cost == expectedCost, std::to_string(re->cost) + lineStr); - } - } - - void - testGetDataHelperFunctions() - { - testcase("getData helper functions"); - BEAST_EXPECT(testGetDataIncrement()); - } - - void - testWasmLib() - { - testcase("wasm lib test"); - // clang-format off - // The WASM module buffer - Bytes const wasm = {// WASM header - 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, - // Type section - 0x01, 0x07, 0x01, - // function type {i32, i32} -> {i32} - 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, - // Import section - 0x02, 0x13, 0x01, - // module name: "extern" - 0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E, - // extern name: "func-add" - 0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64, - // import desc: func 0 - 0x00, 0x00, - // Function section - 0x03, 0x02, 0x01, 0x00, - // Export section - 0x07, 0x0A, 0x01, - // export name: "addTwo" - 0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F, - // export desc: func 0 - 0x00, 0x01, - // Code section - 0x0A, 0x0A, 0x01, - // code body - 0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B}; - // clang-format on - auto& vm = WasmEngine::instance(); - - HostFunctions hfs; - ImportVec imports; - WasmImpFunc(imports, "func-add", add, hfs); - - auto re = vm.run(wasm, hfs, 10'000'000, "addTwo", wasmParams(1234, 5678), imports); - - // if (res) printf("invokeAdd get the result: %d\n", res.value()); - - checkResult(re, 6'912, 59); - } - - void - testBadWasm() - { - testcase("bad wasm test"); - - using namespace test::jtx; - - Env const env{*this}; - HostFunctions const hfs(env.journal); - - { - auto wasm = hexToBytes("00000000"); - std::string const funcName("mock_escrow"); - - auto re = runEscrowWasm(wasm, hfs, 15, funcName, {}); - BEAST_EXPECT(!re); - } - - { - auto wasm = hexToBytes("00112233445566778899AA"); - std::string const funcName("mock_escrow"); - - auto const re = preflightEscrowWasm(wasm, hfs, funcName); - BEAST_EXPECT(!isTesSuccess(re)); - } - - { - // FinishFunction wrong function name - // pub fn bad() -> bool { - // unsafe { host_lib::getLedgerSqn() >= 5 } - // } - auto const badWasm = hexToBytes( - "0061736d010000000105016000017f02190108686f73745f6c69620c6765" - "744c656467657253716e00000302010005030100100611027f00418080c0" - "000b7f00418080c0000b072b04066d656d6f727902000362616400010a5f" - "5f646174615f656e6403000b5f5f686561705f6261736503010a09010700" - "100041044a0b004d0970726f64756365727302086c616e67756167650104" - "52757374000c70726f6365737365642d6279010572757374631d312e3835" - "2e31202834656231363132353020323032352d30332d31352900490f7461" - "726765745f6665617475726573042b0f6d757461626c652d676c6f62616c" - "732b087369676e2d6578742b0f7265666572656e63652d74797065732b0a" - "6d756c746976616c7565"); - - auto const re = preflightEscrowWasm(badWasm, hfs, escrowFunctionName); - BEAST_EXPECT(!isTesSuccess(re)); - } - } - - void - testWasmLedgerSqn() - { - testcase("Wasm get ledger sequence"); - - auto ledgerSqnWasm = hexToBytes(kLedgerSqnWasmHex); - - using namespace test::jtx; - - Env env{*this}; - TestLedgerDataProvider hfs(env); - ImportVec imports; - WASM_IMPORT_FUNC2(imports, getLedgerSqn, "ldgr_index", hfs, 33); - auto& engine = WasmEngine::instance(); - - auto re = - engine.run(ledgerSqnWasm, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal); - - checkResult(re, 0, 440); - - env.close(); - env.close(); - - // empty module, throwing exception - re = engine.run({}, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal); - BEAST_EXPECT(!re); - env.close(); - } - - void - testImpExp() - { - testcase("Wasm import/export functions"); - - auto impExpWasm = hexToBytes(kImpExpHex); - - using namespace test::jtx; - - Env env{*this}; - TestLedgerDataProvider hfs(env); - ImportVec imports; - WASM_IMPORT_FUNC2(imports, getLedgerSqn, "get_ledger_sqn", hfs, 33); - WASM_IMPORT_FUNC2(imports, getParentLedgerHash, "get_parent_ledger_hash", hfs, 60); - auto& engine = WasmEngine::instance(); - - // Test exp_func1() - should return 1 - auto re = engine.run(impExpWasm, hfs, 1'000'000, "exp_func1", {}, imports, env.journal); - checkResult(re, 1, 30); - - // Test exp_func2(5) - should return 2 * 5 = 10 - re = engine.run( - impExpWasm, hfs, 1'000'000, "exp_func2", wasmParams(5), imports, env.journal); - checkResult(re, 10, 52); - - // Test test_imports() - should call get_ledger_sqn and get_parent_ledger_hash - re = engine.run(impExpWasm, hfs, 1'000'000, "test_imports", {}, imports, env.journal); - // Should return the ledger sequence number (3 by default in test env) - checkResult(re, 3, 294); - - // Test corrupted import/export sections - invert each byte and expect failure - testcase("Wasm import/export section corruption"); - { - // Import section(#2): bytes [26, 79) - 53 bytes - // Export section(#7): bytes [90, 141) - 51 bytes - auto [importStart, importEnd] = getSection(impExpWasm, 2); - auto [exportStart, exportEnd] = getSection(impExpWasm, 7); - - BEAST_EXPECTS(importStart == 26, std::to_string(importStart)); - BEAST_EXPECTS(importEnd == 79, std::to_string(importEnd)); - BEAST_EXPECTS(exportStart == 90, std::to_string(exportStart)); - BEAST_EXPECTS(exportEnd == 141, std::to_string(exportEnd)); - - auto testInv = [&](unsigned i) { - auto corruptedWasm = impExpWasm; - corruptedWasm[i] = ~corruptedWasm[i]; // Invert byte - - // Try to run any function - should fail due to corruption - auto result = engine.run( - corruptedWasm, hfs, 1'000'000, "exp_func1", {}, imports, env.journal); - BEAST_EXPECT(!result); - }; - - // Test each byte in import section - for (unsigned i = importStart; i < importEnd; ++i) - testInv(i); - - // Test each byte in export section - for (unsigned i = exportStart; i < exportEnd; ++i) - testInv(i); - } - - env.close(); - } - - void - testWasmFib() - { - testcase("Wasm fibo"); - - auto const fibWasm = hexToBytes(kFibWasmHex); - auto& engine = WasmEngine::instance(); - HostFunctions hfs; - - auto const re = engine.run(fibWasm, hfs, 10'000'000, "fib", wasmParams(10)); - - checkResult(re, 55, 1'137); - } - - void - testHFCost() - { - testcase("wasm test host functions cost"); - - using namespace test::jtx; - - Env env(*this); - { - auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex); - - auto& engine = WasmEngine::instance(); - - TestHostFunctions hfs(env); - auto imp = createWasmImport(hfs); - for (auto& i : imp) - i.second.second.gas = 0; - - auto re = engine.run( - allHostFuncWasm, hfs, 1'000'000, escrowFunctionName, {}, imp, env.journal); - - checkResult(re, 1, 30'760); - - env.close(); - } - - env.close(); - env.close(); - env.close(); - env.close(); - env.close(); - - { - auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex); - - auto& engine = WasmEngine::instance(); - - TestHostFunctions hfs(env); - auto const imp = createWasmImport(hfs); - - auto re = engine.run( - allHostFuncWasm, hfs, 1'000'000, escrowFunctionName, {}, imp, env.journal); - - checkResult(re, 1, 48'580); - - env.close(); - } - - // not enough gas - { - auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex); - - auto& engine = WasmEngine::instance(); - - TestHostFunctions hfs(env); - auto const imp = createWasmImport(hfs); - - auto re = - engine.run(allHostFuncWasm, hfs, 200, escrowFunctionName, {}, imp, env.journal); - - if (BEAST_EXPECT(!re)) - { - // Running out of gas now terminates with tecOUT_OF_GAS (was - // previously collapsed into tecFAILED_PROCESSING). - BEAST_EXPECTS(re.error().ter == tecOUT_OF_GAS, transToken(re.error().ter)); - } - - env.close(); - } - } - - void - testEscrowWasmDN() - { - testcase("escrow wasm devnet test"); - - auto const allHFWasm = hexToBytes(kAllHostFunctionsWasmHex); - - using namespace test::jtx; - Env env{*this}; - { - TestHostFunctions hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName); - checkResult(re, 1, 50'207); - } - - { - // Invalid gas limit (0) should be rejected (boundary condition) - TestHostFunctions const hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, -1, escrowFunctionName, {}); - BEAST_EXPECT(!re.has_value()); - BEAST_EXPECT(re.error().ter == temBAD_AMOUNT); - } - - { - // Invalid gas limit (-1) should be rejected - TestHostFunctions const hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, 0, escrowFunctionName, {}); - BEAST_EXPECT(!re.has_value()); - BEAST_EXPECT(re.error().ter == temBAD_AMOUNT); - } - - { - // max() gas - TestHostFunctions const hfs(env); - auto re = runEscrowWasm( - allHFWasm, hfs, std::numeric_limits::max(), escrowFunctionName); - checkResult(re, 1, 50'207); - } - - { // fail because trying to access nonexistent field - struct FieldNotFoundHostFunctions : public TestHostFunctions - { - explicit FieldNotFoundHostFunctions(Env& env) : TestHostFunctions(env) - { - } - [[nodiscard]] std::expected - getTxField(SField const& fname) const override - { - return std::unexpected(HostFunctionError::FieldNotFound); - } - }; - - FieldNotFoundHostFunctions hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName); - checkResult(re, -201, 28'901); - } - - { // fail because trying to allocate more than MAX_PAGES memory - struct OversizedFieldHostFunctions : public TestHostFunctions - { - explicit OversizedFieldHostFunctions(Env& env) : TestHostFunctions(env) - { - } - [[nodiscard]] std::expected - getTxField(SField const& fname) const override - { - return Bytes((128 + 1) * 64 * 1024, 1); - } - }; - - OversizedFieldHostFunctions hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName); - checkResult(re, -201, 28'901); - } - -// This test use log output, so DEBUG_OUTPUT must be disabled. -#ifndef DEBUG_OUTPUT - { // fail because recursion too deep - - auto const deepWasm = hexToBytes(kDeepRecursionHex); - - TestHostFunctionsSink hfs(env); - std::string const funcName(escrowFunctionName); - auto re = runEscrowWasm(deepWasm, hfs, 1'000'000'000, funcName, {}); - BEAST_EXPECT(!re && re.error().ter); - // std::cout << "bad case (deep recursion) result " << re.error() - // << std::endl; - - auto const& sink = hfs.getSink(); - auto countSubstr = [](std::string const& str, std::string const& substr) { - std::size_t pos = 0; - int occurrences = 0; - while ((pos = str.find(substr, pos)) != std::string::npos) - { - occurrences++; - pos += substr.length(); - } - return occurrences; - }; - - auto const s = sink.messages().str(); - BEAST_EXPECT(countSubstr(s, "WASMI Error: failure to call func") == 1); - BEAST_EXPECT(countSubstr(s, "TrapCode(StackOverflow)") > 0); - } -#endif - - { // infinite loop - auto const infiniteLoopWasm = hexToBytes(kInfiniteLoopWasmHex); - std::string const funcName("loop"); - TestHostFunctions const hfs(env); - - // infinite loop should be caught and fail - auto const re = runEscrowWasm(infiniteLoopWasm, hfs, 1'000'000, funcName, {}); - if (BEAST_EXPECT(!re.has_value())) - { - BEAST_EXPECT(re.error().ter == tecOUT_OF_GAS); - } - } - - { - // expected import not provided - auto const lgrSqnWasm = hexToBytes(kLedgerSqnWasmHex); - TestLedgerDataProvider hfs(env); - ImportVec imports; - WASM_IMPORT_FUNC2(imports, getLedgerSqn, "get_ledger_sqn2", hfs); - - auto& engine = WasmEngine::instance(); - - auto re = engine.run( - lgrSqnWasm, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal); - - BEAST_EXPECT(!re); - } - - { - // HF unsync between import and VM - auto const lgrSqnWasm = hexToBytes(kLedgerSqnWasmHex); - TestLedgerDataProvider hfs(env); - TestLedgerDataProvider const hfs2(env); - ImportVec imports; - WASM_IMPORT_FUNC2(imports, getLedgerSqn, "get_ledger_sqn", hfs2); - - auto& engine = WasmEngine::instance(); - - auto re = engine.run( - lgrSqnWasm, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal); - - BEAST_EXPECT(!re); - } - - { - // bad function name - auto const lgrSqnWasm = hexToBytes(kLedgerSqnWasmHex); - TestLedgerDataProvider hfs(env); - ImportVec imports; - WASM_IMPORT_FUNC2(imports, getLedgerSqn, "get_ledger_sqn", hfs); - - auto& engine = WasmEngine::instance(); - auto re = engine.run(lgrSqnWasm, hfs, 1'000'000, "func1", {}, imports, env.journal); - - BEAST_EXPECT(!re); - } - } - - // TODO: testFloat is disabled until the float fixtures are regenerated. - // - // kFloatTestsWasmHex and kFloat0Hex were built against the old trace ABI, - // where the trace_* host functions returned i32. They now return void, so - // neither module instantiates and both blocks below fail with tecINTERNAL. - // - // Regenerating them is not just a rebuild: float_tests/ and float_0/ are - // still pinned to xrpl-wasm-stdlib @ "renames" and use APIs that no longer - // exist on xrpl-common-stdlib @ "error-and-trace" - // (FLOAT_ROUNDING_MODES_TO_NEAREST became RoundingMode, - // core::locator::Locator moved to fields::locator::Locator, and - // trace_data/DataRepr became trace_float/trace_hex). The fixture sources - // have to be ported first. The expected gas costs below are also stale and - // will need recomputing once the modules run again. - // - // void - // testFloat() - // { - // testcase("float point"); - // - // std::string const funcName(escrowFunctionName); - // - // using namespace test::jtx; - // - // Env env(*this); - // { - // auto const floatTestWasm = hexToBytes(kFloatTestsWasmHex); - // - // TestHostFunctions hfs(env); - // auto re = runEscrowWasm(floatTestWasm, hfs, 200'000, funcName, - // {}); checkResult(re, 1, 134'402); env.close(); - // } - // - // { - // auto const float0Wasm = hexToBytes(kFloat0Hex); - // - // TestHostFunctions hfs(env); - // auto re = runEscrowWasm(float0Wasm, hfs, 100'000, funcName, {}); - // checkResult(re, 1, 2'775); - // env.close(); - // } - // } - - void - testCodecovWasm() - { - testcase("Codecov wasm test"); - - using namespace test::jtx; - - Env env{*this}; - - auto const codecovWasm = hexToBytes(kCodecovTestsWasmHex); - TestHostFunctions const hfs(env); - - auto const allowance = 129'986; - auto re = runEscrowWasm(codecovWasm, hfs, allowance, escrowFunctionName); - - checkResult(re, 1, allowance); - } - - void - testDisabledFloat() - { - testcase("disabled float"); - - using namespace test::jtx; - Env env{*this}; - - auto disabledFloatWasm = hexToBytes(kDisabledFloatHex); - std::string const funcName(escrowFunctionName); - TestHostFunctions const hfs(env); - - { - // f32 set constant, opcode disabled exception - auto const re = runEscrowWasm(disabledFloatWasm, hfs, 1'000'000, funcName, {}); - if (BEAST_EXPECT(!re.has_value())) - { - BEAST_EXPECT(re.error().ter == tecFAILED_PROCESSING); - } - } - - { - // f32 add, can't create module exception - disabledFloatWasm[0x11e] = 0x92; - auto const re = runEscrowWasm(disabledFloatWasm, hfs, 1'000'000, funcName, {}); - if (BEAST_EXPECT(!re.has_value())) - { - BEAST_EXPECT(re.error().ter == tecFAILED_PROCESSING); - } - } - } - - void - testWasmMemory() - { - testcase("Wasm additional memory limit tests"); - BEAST_EXPECT(finishFunctionReturns(kMemoryPointerAtLimitHex, 1)); - BEAST_EXPECT(!runFinishFunction(kMemoryPointerOverLimitHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kMemoryOffsetOverLimitHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kMemoryEndOfWordOverLimitHex).has_value()); - BEAST_EXPECT(finishFunctionReturns(kMemoryGrow0To1PageHex, 1)); - BEAST_EXPECT(finishFunctionReturns(kMemoryGrow1To0PageHex, -1)); - BEAST_EXPECT(finishFunctionReturns(kMemoryLastByteOf8MbHex, 1)); - BEAST_EXPECT(finishFunctionReturns(kMemoryGrow1MoreThan8MbHex, -1)); - BEAST_EXPECT(finishFunctionReturns(kMemoryGrow0MoreThan8MbHex, 1)); - BEAST_EXPECT(!runFinishFunction(kMemoryInit1MoreThan8MbHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kMemoryNegativeAddressHex).has_value()); - } - - void - testWasmTable() - { - testcase("Wasm table limit tests"); - BEAST_EXPECT(finishFunctionReturns(kTable64ElementsHex, 1)); - BEAST_EXPECT(!runFinishFunction(kTable65ElementsHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kTable2TablesHex).has_value()); - BEAST_EXPECT(finishFunctionReturns(kTable0ElementsHex, 1)); - BEAST_EXPECT(!runFinishFunction(kTableUintMaxHex).has_value()); - } - - void - testWasmProposal() - { - testcase("Wasm disabled proposal tests"); - BEAST_EXPECT(!runFinishFunction(kProposalMutableGlobalHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kProposalGcStructNewHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kProposalMultiValueHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kProposalSignExtHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kProposalFloatToIntHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kProposalBulkMemoryHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kProposalRefTypesHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kProposalTailCallHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kProposalExtendedConstHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kProposalMultiMemoryHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kProposalCustomPageSizesHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kProposalMemory64Hex).has_value()); - BEAST_EXPECT(!runFinishFunction(kProposalWideArithmeticHex).has_value()); - } - - void - testWasmTrap() - { - testcase("Wasm trap tests"); - BEAST_EXPECT(!runFinishFunction(kTrapDivideBy0Hex).has_value()); - BEAST_EXPECT(!runFinishFunction(kTrapIntOverflowHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kTrapUnreachableHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kTrapNullCallHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kTrapFuncSigMismatchHex).has_value()); - } - - void - testWasmWasi() - { - testcase("Wasm Wasi tests"); - BEAST_EXPECT(!runFinishFunction(kWasiGetTimeHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kWasiPrintHex).has_value()); - } - - void - testWasmSectionCorruption() - { - testcase("Wasm Section Corruption tests"); - BEAST_EXPECT(!runFinishFunction(kBadMagicNumberHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kBadVersionNumberHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kLyingHeaderHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kNeverEndingNumberHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kVectorLieHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kSectionOrderingHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kGhostPayloadHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kJunkAfterSectionHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kInvalidSectionIdHex).has_value()); - BEAST_EXPECT(!runFinishFunction(kLocalVariableBombHex).has_value()); - } - - void - testStartFunctionLoop() - { - testcase("infinite loop in start function"); - - using namespace test::jtx; - Env env(*this); - - auto const startLoopWasm = hexToBytes(kStartLoopHex); - TestLedgerDataProvider hfs(env); - ImportVec const imports; - - auto& engine = WasmEngine::instance(); - auto checkRes = - engine.check(startLoopWasm, hfs, escrowFunctionName, {}, imports, env.journal); - BEAST_EXPECTS(checkRes == tesSUCCESS, transToken(checkRes)); - - auto result = - engine.run(startLoopWasm, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal); - auto resultTer = result.error().ter; - BEAST_EXPECTS(resultTer == tecFAILED_PROCESSING, transToken(resultTer)); - } - - void - testBadAlign() - { - testcase("Wasm Bad Align"); - - // bad_align.c - auto const badAlignWasm = hexToBytes(kBadAlignWasmHex); - - using namespace test::jtx; - - Env env{*this}; - TestHostFunctions hfs(env); - auto imports = createWasmImport(hfs); - - { // Calls float_from_uint with bad alignment. - // Can be checked through codecov - auto& engine = WasmEngine::instance(); - - auto re = engine.run(badAlignWasm, hfs, 1'000'000, "test", {}, imports, env.journal); - if (BEAST_EXPECTS(re, transToken(re.error().ter))) - { - BEAST_EXPECTS(re->result == 0x47308594, std::to_string(re->result)); - } - } - - env.close(); - } - - void - testReturnType() - { - using namespace test::jtx; - Env env(*this); - TestHostFunctions hfs(env); - - testcase("Wasm invalid return type"); - - // return int64. - { // (module - // (memory (export "memory") 1) - // (func (export "finish") (result i64) - // i64.const 0x100000000)) - auto const wasmHex = - "0061736d010000000105016000017e030201000503010001" - "071302066d656d6f727902000666696e69736800000a0a01" - "08004280808080100b"; - auto const wasm = hexToBytes(wasmHex); - auto const re = runEscrowWasm(wasm, hfs, 100'000, escrowFunctionName, {}); - BEAST_EXPECT(!re); - } - - // return void. wasmi return execution error - { //(module - // (type (;0;) (func)) - // (func (;0;) (type 0) - // return) - // (memory (;0;) 1) - // (export "memory" (memory 0)) - // (export "finish" (func 0))) - auto const wasmHex = - "0061736d01000000010401600000030201000503010001071302066d656d6f" - "727902000666696e69736800000a050103000f0b"; - auto const wasm = hexToBytes(wasmHex); - auto const re = runEscrowWasm(wasm, hfs, 100'000, escrowFunctionName, {}); - BEAST_EXPECT(!re); - } - - // return i32, i32. wasmi doesn't create module - { //(module - // (memory (export "memory") 1) - // (func (export "finish") (result i32 i32) - // i32.const 0x10000000 - // i32.const 0x100000FF)) - auto const wasmHex = - "0061736d010000000106016000027f7f030201000503010001071302066d65" - "6d6f727902000666696e69736800000a10010e0041808080800141ff818080" - "010b"; - auto const wasm = hexToBytes(wasmHex); - auto const re = runEscrowWasm(wasm, hfs, 100'000, escrowFunctionName, {}); - BEAST_EXPECT(!re); - } - } - - void - testParameterType() - { - using namespace test::jtx; - Env env(*this); - TestHostFunctions hfs(env); - - testcase("Wasm invalid params"); - - // (module - // (memory (export "memory") 1) - // (func $test1 (export "test1") (param i32) (result i32) - // i32.const 1000) - // (func $test2 (export "test2") (param i32 i32) (result i32) - // i32.const 1001)) - auto const wasmHex = - "0061736d01000000010c0260017f017f60027f7f017f03030200010503010001071a03066d656d6f727902" - "00057465737431000005746573743200010a0d02050041e8070b050041e9070b"; - auto const wasm = hexToBytes(wasmHex); - - // good params, module is working properly - { - auto const re = runEscrowWasm(wasm, hfs, 100'000, "test2", wasmParams(2, 10)); - BEAST_EXPECT(re && re->result == 1001 && re->cost == 37); - } - - // no params - { - auto const re = runEscrowWasm(wasm, hfs, 100'000, "test1", {}); - BEAST_EXPECT(!re); - } - - // more params - { - auto const re = runEscrowWasm(wasm, hfs, 100'000, "test1", wasmParams(0, 1)); - BEAST_EXPECT(!re); - } - - // less params - { - auto const re = runEscrowWasm(wasm, hfs, 100'000, "test2", wasmParams(1)); - BEAST_EXPECT(!re); - } - - // invalid type - { - auto const re = - runEscrowWasm(wasm, hfs, 100'000, "test1", wasmParams(std::int64_t(15))); - BEAST_EXPECT(!re); - } - } - - void - testSwapBytes() - { - testcase("Wasm swap bytes"); - - uint64_t const swapDataU64 = 0x123456789abcdeffull; - uint64_t const reverseSwapDataU64 = 0xffdebc9a78563412ull; - int64_t const swapDataI64 = 0x123456789abcdeffll; - int64_t const reverseSwapDataI64 = 0xffdebc9a78563412ll; - - uint32_t const swapDataU32 = 0x12789aff; - uint32_t const reverseSwapDataU32 = 0xff9a7812; - int32_t const swapDataI32 = 0x12789aff; - int32_t const reverseSwapDataI32 = 0xff9a7812; - - uint16_t const swapDataU16 = 0x12ff; - uint16_t const reverseSwapDataU16 = 0xff12; - int16_t const swapDataI16 = 0x12ff; - int16_t const reverseSwapDataI16 = 0xff12; - - uint64_t b1 = swapDataU64; - int64_t b2 = swapDataI64; - b1 = adjustWasmEndianessHlp(b1); - b2 = adjustWasmEndianessHlp(b2); - BEAST_EXPECT(b1 == reverseSwapDataU64); - BEAST_EXPECT(b2 == reverseSwapDataI64); - b1 = adjustWasmEndianessHlp(b1); - b2 = adjustWasmEndianessHlp(b2); - BEAST_EXPECT(b1 == swapDataU64); - BEAST_EXPECT(b2 == swapDataI64); - - uint32_t b3 = swapDataU32; - int32_t b4 = swapDataI32; - b3 = adjustWasmEndianessHlp(b3); - b4 = adjustWasmEndianessHlp(b4); - BEAST_EXPECT(b3 == reverseSwapDataU32); - BEAST_EXPECT(b4 == reverseSwapDataI32); - b3 = adjustWasmEndianessHlp(b3); - b4 = adjustWasmEndianessHlp(b4); - BEAST_EXPECT(b3 == swapDataU32); - BEAST_EXPECT(b4 == swapDataI32); - - uint16_t b5 = swapDataU16; - int16_t b6 = swapDataI16; - b5 = adjustWasmEndianessHlp(b5); - b6 = adjustWasmEndianessHlp(b6); - BEAST_EXPECT(b5 == reverseSwapDataU16); - BEAST_EXPECT(b6 == reverseSwapDataI16); - b5 = adjustWasmEndianessHlp(b5); - b6 = adjustWasmEndianessHlp(b6); - BEAST_EXPECT(b5 == swapDataU16); - BEAST_EXPECT(b6 == swapDataI16); - } - - void - testManyParams() - { - testcase("Wasm Many params"); - - auto const params1k = hexToBytes(kThousandParamsHex); - auto const params1k1 = hexToBytes(kThousand1ParamsHex); - - using namespace test::jtx; - - Env env{*this}; - TestHostFunctions hfs(env); - auto imports = createWasmImport(hfs); - - // add 1k parameter (max that wasmi support) - std::vector params; - params.reserve(1000); - for (int i = 0; i < 1000; ++i) - params.push_back({.type = WasmTypes::WtI32, .of = {.i32 = 2 * i}}); - - auto& engine = WasmEngine::instance(); - { - auto re = engine.run(params1k, hfs, 1'000'000, "test", params, imports, env.journal); - BEAST_EXPECT(re && re->result == 999000); - } - - // add 1 more parameter, module can't be created now - params.push_back({.type = WasmTypes::WtI32, .of = {.i32 = 2 * 1000}}); - { - auto re = engine.run(params1k1, hfs, 1'000'000, "test", params, imports, env.journal); - BEAST_EXPECT(!re); - } - - // function that create 10k local variables - auto const locals10k = hexToBytes(kLocals10kHex); - { - auto re = engine.run( - locals10k, hfs, 1'000'000, "test", wasmParams(0, 1), imports, env.journal); - BEAST_EXPECT(re && re->result == 890'489'442); - } - - // module has 5k functions - auto const functions5k = hexToBytes(kFunctions5kHex); - { - auto re = engine.run( - functions5k, hfs, 1'000'000, "test0001", wasmParams(2, 3), imports, env.journal); - BEAST_EXPECT(re && re->result == 5); - } - - env.close(); - } - - void - testOpcodes() - { - using namespace test::jtx; - - unsigned const reserved = 64; - std::uint8_t const nop = 0x01; - std::array const codeMarker = { - nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop}; - auto const opcReserved = hexToBytes(kOpcReservedHex); - - Env env{*this}; - auto& engine = WasmEngine::instance(); - - TestHostFunctions hfs(env); - auto imports = createWasmImport(hfs); - env.close(); - - { - auto run = [&](std::vector const& code, - bool good = false, - int64_t cost = -1, - std::source_location const location = std::source_location::current()) { - auto const lineStr = " (" + std::to_string(location.line()) + ")"; - auto re = - engine.run(code, hfs, 1'000'000, "all_instructions", {}, imports, env.journal); - if (BEAST_EXPECTS(re.has_value() == good, transToken(re.error().ter) + lineStr) && - good) - BEAST_EXPECTS(re->cost == cost, std::to_string(re->cost) + lineStr); - }; - - // 1 byte instruction - auto test = [&](std::uint8_t start, - std::uint8_t finish, - bool good = false, - int64_t cost = -1, - std::source_location const location = std::source_location::current()) { - auto const lineStr = " (" + std::to_string(location.line()) + ")"; - auto code = opcReserved; - auto codeRange = std::ranges::search(code, codeMarker); - if (!BEAST_EXPECTS(!codeRange.empty(), lineStr)) - return; - - auto it = codeRange.begin(); - for (std::uint16_t i = start; i <= finish; ++i) - { - *it = i; - run(code, good, cost, location); - } - }; - - // 2 bytes instruction - auto test2 = [&](std::uint8_t major, - std::uint16_t start, - std::uint16_t finish, - bool good = false, - int64_t cost = -1, - std::source_location const location = - std::source_location::current()) { - auto const lineStr = " (" + std::to_string(location.line()) + ")"; - auto code = opcReserved; - auto codeRange = std::ranges::search(code, codeMarker); - if (!BEAST_EXPECTS(!codeRange.empty(), lineStr)) - return; - - auto it = codeRange.begin(); - *it++ = major; - for (std::uint16_t i = start; i <= finish; ++i) - { - auto it2 = it; - uleb128(it2, i); - run(code, good, cost, location); - } - }; - - // multibytes instructions - auto testMB = [&](std::vector const& codeSnap, - bool good = false, - int64_t cost = -1, - std::source_location const location = - std::source_location::current()) { - auto const lineStr = " (" + std::to_string(location.line()) + ")"; - auto code = opcReserved; - auto codeRange = std::ranges::search(code, codeMarker); - if (!BEAST_EXPECTS(!codeRange.empty(), lineStr)) - return; - - if (!BEAST_EXPECTS(codeSnap.size() < reserved, lineStr)) - return; - auto it = codeRange.begin(); - for (auto x : codeSnap) - *it++ = x; - run(code, good, cost, location); - }; - - // normal run - testcase("Wasm reserved opcodes main"); - test(nop, nop, true, 534); - - // reserved main - test(0x06, 0x0A); - test(0x12, 0x19); - test(0x25, 0x27); - test(0xC0, 0xFA); - test(0xFF, 0xFF); - - // reserved gc, string - testcase("Wasm reserved opcodes gc"); - test2(0xFB, 0x00, 0xBF); // not supported by compiler - - // reserved FC - testcase("Wasm reserved opcodes FC"); - test2(0xFC, 0x00, 0x07); // floats, disabled - test2(0xFC, 0x12, 0x1F); - - // reserved SIMD - testcase("Wasm reserved opcodes SIMD"); - test2(0xFD, 0x9A, 0x9A); - test2(0xFD, 0xA2, 0xA2); - test2(0xFD, 0xA5, 0xA6); - test2(0xFD, 0xAF, 0xB0); - test2(0xFD, 0xB2, 0xB4); - test2(0xFD, 0xB8, 0xB8); - test2(0xFD, 0xC2, 0xC2); - test2(0xFD, 0xC5, 0xC6); - test2(0xFD, 0xCF, 0xD0); - test2(0xFD, 0xD2, 0xD4); - test2(0xFD, 0xE2, 0xE2); - test2(0xFD, 0xEE, 0xEE); - test2(0xFD, 0x115, 0x12F); - - testcase("Wasm opcodes THREADS"); - test2(0xFE, 0x00, 0x4F); // not supported by compiler - - // FC mem instructions - testMB({0x41, 0x00, 0x41, 0x00, 0x41, 0x04, 0xFC, 0x08, 0x00, 0x00}); // memory.init - testMB({0xFC, 0x09, 0x00}); // data.drop - testMB({0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0xFC, 0x0A, 0x00, 0x00}); // memory.copy - testMB({0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0xFC, 0x0B, 0x00}); // memory.fill - testMB({0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0xFC, 0x0C, 0x00, 0x00}); // table.init - testMB({0xFC, 0x0D, 0x00}); // elem.drop - testMB({0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0xFC, 0x0E, 0x00, 0x00}); // table.copy - testMB({0xD2, 0x00, 0x41, 0x00, 0xFC, 0x0F, 0x00, 0x1A}); // table.grow - testMB({0x1A, 0xFC, 0x10, 0x00, 0x1A}); // table.size - testMB({0x41, 0x00, 0xD2, 0x00, 0x41, 0x00, 0xFC, 0x11, 0x00}); // table.fill - - testcase("Wasm opcodes SIMD"); - // clang-format off - - // generated by auggie - // SIMD instructions - testMB({0x41, 0x00, 0xFD, 0x00, 0x04, 0x00, 0x1A}); // v128.load - testMB({0x41, 0x00, 0xFD, 0x01, 0x03, 0x00, 0x1A}); // v128.load8x8_s - testMB({0x41, 0x00, 0xFD, 0x02, 0x03, 0x00, 0x1A}); // v128.load8x8_u - testMB({0x41, 0x00, 0xFD, 0x03, 0x03, 0x00, 0x1A}); // v128.load16x4_s - testMB({0x41, 0x00, 0xFD, 0x04, 0x03, 0x00, 0x1A}); // v128.load16x4_u - testMB({0x41, 0x00, 0xFD, 0x05, 0x03, 0x00, 0x1A}); // v128.load32x2_s - testMB({0x41, 0x00, 0xFD, 0x06, 0x03, 0x00, 0x1A}); // v128.load32x2_u - testMB({0x41, 0x00, 0xFD, 0x07, 0x00, 0x00, 0x1A}); // v128.load8_splat - testMB({0x41, 0x00, 0xFD, 0x08, 0x01, 0x00, 0x1A}); // v128.load16_splat - testMB({0x41, 0x00, 0xFD, 0x09, 0x02, 0x00, 0x1A}); // v128.load32_splat - testMB({0x41, 0x00, 0xFD, 0x0A, 0x03, 0x00, 0x1A}); // v128.load64_splat - testMB({0x41, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0B, 0x04, 0x00}); // -v128.store testMB({0xFD, 0x0C, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, -0x00, 0x04, 0x00, 0x00, 0x00, 0x1A}); // v128.const testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0D, -0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -0x1A}); // i8x16.shuffle testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0E, 0x1A}); // i8x16.swizzle - testMB({0x41, 0x2A, 0xFD, 0x0F, 0x1A}); // i8x16.splat testMB({0x41, 0x2A, 0xFD, 0x10, -0x1A}); // i16x8.splat testMB({0x41, 0x2A, 0xFD, -0x11, 0x1A}); // i32x4.splat testMB({0x42, 0x2A, -0xFD, 0x12, 0x1A}); // i64x2.splat - - testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x15, 0x00, 0x1A}); // -i8x16.extract_lane_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x16, 0x00, 0x1A}); // i8x16.extract_lane_u testMB({0xFD, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x41, 0x2A, 0xFD, 0x17, 0x00, 0x1A}); // i8x16.replace_lane testMB({0xFD, 0x0C, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x18, -0x00, 0x1A}); // i16x8.extract_lane_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x19, 0x00, 0x1A}); // -i16x8.extract_lane_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x2A, 0xFD, 0x1A, 0x00, 0x1A}); // -i16x8.replace_lane testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x1B, 0x00, 0x1A}); // i32x4.extract_lane testMB({0xFD, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x41, 0x2A, 0xFD, 0x1C, 0x00, 0x1A}); // i32x4.replace_lane testMB({0xFD, 0x0C, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x1D, -0x00, 0x1A}); // i64x2.extract_lane testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x2A, 0xFD, 0x1E, 0x00, 0x1A}); // -i64x2.replace_lane testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x1F, 0x00, 0x1A}); // f32x4.extract_lane testMB( {0xFD, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x43, 0x00, 0x00, 0x80, 0x3F, 0xFD, 0x20, 0x00, 0x1A}); // f32x4.replace_lane testMB({0xFD, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xFD, 0x21, 0x00, 0x1A}); // f64x2.extract_lane testMB( {0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xF0, 0x3F, 0xFD, 0x22, 0x00, 0x1A}); // f64x2.replace_lane testMB({0xFD, 0x0C, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xFD, 0x23, 0x1A}); // i8x16.eq testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x24, 0x1A}); // -i8x16.ne testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x25, 0x1A}); // i8x16.lt_s testMB({0xFD, 0x0C, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xFD, 0x26, 0x1A}); // i8x16.lt_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x27, 0x1A}); // -i8x16.gt_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x28, 0x1A}); -// i8x16.gt_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x29, 0x1A}); -// i8x16.le_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x2A, 0x1A}); -// i8x16.le_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x2B, 0x1A}); -// i8x16.ge_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x2C, 0x1A}); -// i8x16.ge_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x2D, 0x1A}); -// i16x8.eq testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x2E, 0x1A}); -// i16x8.ne testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x2F, 0x1A}); -// i16x8.lt_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x30, 0x1A}); -// i16x8.lt_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x31, 0x1A}); -// i16x8.gt_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x32, 0x1A}); -// i16x8.gt_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x33, 0x1A}); -// i16x8.le_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x34, 0x1A}); -// i16x8.le_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x35, 0x1A}); -// i16x8.ge_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x36, 0x1A}); -// i16x8.ge_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x37, 0x1A}); -// i32x4.eq testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x38, 0x1A}); -// i32x4.ne testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x39, 0x1A}); -// i32x4.lt_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x3A, 0x1A}); -// i32x4.lt_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x3B, 0x1A}); -// i32x4.gt_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x3C, 0x1A}); -// i32x4.gt_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x3D, 0x1A}); -// i32x4.le_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x3E, 0x1A}); -// i32x4.le_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x3F, 0x1A}); -// i32x4.ge_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x40, 0x1A}); -// i32x4.ge_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x4D, 0x1A}); // v128.not testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, -0x4E, 0x1A}); // v128.and testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x4F, 0x1A}); // v128.andnot - testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x50, 0x1A}); -// v128.or testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x51, 0x1A}); -// v128.xor testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x52, 0x1A}); // -v128.bitselect testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x53, 0x1A}); // v128.any_true testMB({0xFD, 0x0C, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x60, -0x1A}); // i8x16.abs testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x61, 0x1A}); // i8x16.neg - testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x62, 0x1A}); // i8x16.popcnt - testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x63, 0x1A}); // i8x16.all_true - testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x64, 0x1A}); // i8x16.bitmask - testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0x6B, 0x1A}); // -i8x16.shl testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0x6C, 0x1A}); // i8x16.shr_s testMB({0xFD, 0x0C, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x41, 0x01, 0xFD, 0x6D, 0x1A}); // i8x16.shr_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x6E, 0x1A}); // -i8x16.add testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x6F, 0x1A}); -// i8x16.add_sat_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x70, 0x1A}); // i8x16.add_sat_u - testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x71, 0x1A}); -// i8x16.sub testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x72, 0x1A}); -// i8x16.sub_sat_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x73, 0x1A}); // i8x16.sub_sat_u - testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x76, 0x1A}); -// i8x16.min_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x77, 0x1A}); -// i8x16.min_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x78, 0x1A}); -// i8x16.max_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x79, 0x1A}); -// i8x16.max_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x7B, 0x1A}); -// i8x16.avgr_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x80, 0x01, 0x1A}); // i16x8.abs testMB({0xFD, 0x0C, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFD, 0x81, 0x01, 0x1A}); // i16x8.neg testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x83, 0x01, 0x1A}); // -i16x8.all_true testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x84, 0x01, 0x1A}); // i16x8.bitmask testMB({0xFD, 0x0C, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, -0x01, 0xFD, 0x8B, 0x01, 0x1A}); // i16x8.shl testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0x8C, 0x01, -0x1A}); // i16x8.shr_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0x8D, 0x01, 0x1A}); // i16x8.shr_u - testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x8E, 0x01, 0x1A}); // i16x8.add testMB({0xFD, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xFD, 0x8F, 0x01, 0x1A}); // i16x8.add_sat_s testMB({0xFD, 0x0C, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFD, 0x90, 0x01, 0x1A}); // i16x8.add_sat_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x91, 0x01, -0x1A}); // i16x8.sub testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x92, 0x01, 0x1A}); // i16x8.sub_sat_s - testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x93, 0x01, 0x1A}); // i16x8.sub_sat_u - testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x95, 0x01, 0x1A}); // i16x8.mul testMB({0xFD, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xFD, 0x96, 0x01, 0x1A}); // i16x8.min_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, -0x97, 0x01, 0x1A}); // i16x8.min_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x98, 0x01, 0x1A}); // -i16x8.max_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x99, 0x01, 0x1A}); // i16x8.max_u testMB({0xFD, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xFD, 0x9B, 0x01, 0x1A}); // i16x8.avgr_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xA0, 0x01, -0x1A}); // i32x4.abs testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xA1, 0x01, 0x1A}); // -i32x4.neg testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xA3, 0x01, 0x1A}); // i32x4.all_true testMB({0xFD, 0x0C, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, -0xA4, 0x01, 0x1A}); // i32x4.bitmask testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0xAB, 0x01, 0x1A}); // -i32x4.shl testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0xAC, 0x01, 0x1A}); // i32x4.shr_s testMB({0xFD, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x41, 0x01, 0xFD, 0xAD, 0x01, 0x1A}); // i32x4.shr_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, -0xAE, 0x01, 0x1A}); // i32x4.add testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xB1, 0x01, 0x1A}); // -i32x4.sub testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xB5, 0x01, 0x1A}); // i32x4.mul testMB({0xFD, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xFD, 0xB6, 0x01, 0x1A}); // i32x4.min_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, -0xB7, 0x01, 0x1A}); // i32x4.min_u testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xB8, 0x01, 0x1A}); // -i32x4.max_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xB9, 0x01, 0x1A}); // i32x4.max_u testMB({0xFD, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xFD, 0xBA, 0x01, 0x1A}); // i32x4.dot_i16x8_s testMB({0xFD, 0x0C, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xC0, -0x01, 0x1A}); // i64x2.abs testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xC1, 0x01, 0x1A}); // i64x2.neg - testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xC3, 0x01, 0x1A}); // -i64x2.all_true testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xC4, 0x01, 0x1A}); // i64x2.bitmask testMB({0xFD, 0x0C, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, -0x01, 0xFD, 0xCB, 0x01, 0x1A}); // i64x2.shl testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0xCC, 0x01, -0x1A}); // i64x2.shr_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0xFD, 0xCD, 0x01, 0x1A}); // i64x2.shr_u - testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xCE, 0x01, 0x1A}); // i64x2.add testMB({0xFD, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xFD, 0xD1, 0x01, 0x1A}); // i64x2.sub testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, -0xD5, 0x01, 0x1A}); // i64x2.mul testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xD6, 0x01, 0x1A}); // -i64x2.eq testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xD7, 0x01, 0x1A}); // i64x2.ne - testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xD8, 0x01, 0x1A}); // i64x2.lt_s testMB({0xFD, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xFD, 0xD9, 0x01, 0x1A}); // i64x2.gt_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, -0xDA, 0x01, 0x1A}); // i64x2.le_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xDB, 0x01, 0x1A}); // -i64x2.ge_s testMB({0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xF8, 0x01, 0x1A}); // i32x4.trunc_sat_f32x4_s testMB({0xFD, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xFD, 0xF9, 0x01, 0x1A}); // i32x4.trunc_sat_f32x4_u - - // clang-format on - } - } - - void - run() override - { - using namespace test::jtx; - - testGetDataHelperFunctions(); - testWasmLib(); - testBadWasm(); - testWasmLedgerSqn(); - testImpExp(); - - testWasmFib(); - - testHFCost(); - testEscrowWasmDN(); - // TODO: re-enable once the float fixtures are regenerated (see above) - // testFloat(); - - testCodecovWasm(); - // TODO: broken, fix after Rust re-arch - // testDisabledFloat(); - - testWasmMemory(); - testWasmTable(); - testWasmProposal(); - testWasmTrap(); - testWasmWasi(); - testWasmSectionCorruption(); - - // TODO: broken, fix after Rust re-arch - // testStartFunctionLoop(); - testBadAlign(); - testReturnType(); - testSwapBytes(); - testManyParams(); - testParameterType(); - - testOpcodes(); - } -}; - -BEAST_DEFINE_TESTSUITE(Wasm, app, xrpl); - -} // namespace xrpl::test -*/ diff --git a/src/test/app/wasm_fixtures/.gitignore b/src/test/app/wasm_fixtures/.gitignore deleted file mode 100644 index 08b2e8a256..0000000000 --- a/src/test/app/wasm_fixtures/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -**/target -**/debug -*.wasm diff --git a/src/test/app/wasm_fixtures/all_host_functions/Cargo.lock b/src/test/app/wasm_fixtures/all_host_functions/Cargo.lock deleted file mode 100644 index 5240e9b0f0..0000000000 --- a/src/test/app/wasm_fixtures/all_host_functions/Cargo.lock +++ /dev/null @@ -1,180 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "all_host_functions" -version = "0.1.0" -dependencies = [ - "xrpl-common-stdlib", - "xrpl-escrow-stdlib", -] - -[[package]] -name = "block-buffer" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "const-oid" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" - -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "digest" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", -] - -[[package]] -name = "hybrid-array" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" -dependencies = [ - "typenum", -] - -[[package]] -name = "libc" -version = "0.2.186" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "sha2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "syn" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tinyvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "typenum" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "xrpl-common-stdlib" -version = "0.8.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=error-and-trace#b008b097237ce0d1a2dffc72ba39dd9fc50020a9" -dependencies = [ - "xrpl-macros", -] - -[[package]] -name = "xrpl-escrow-stdlib" -version = "0.1.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=error-and-trace#b008b097237ce0d1a2dffc72ba39dd9fc50020a9" -dependencies = [ - "xrpl-common-stdlib", -] - -[[package]] -name = "xrpl-macros" -version = "0.1.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=error-and-trace#b008b097237ce0d1a2dffc72ba39dd9fc50020a9" -dependencies = [ - "bs58", - "proc-macro2", - "quote", - "sha2", - "syn", -] diff --git a/src/test/app/wasm_fixtures/all_host_functions/Cargo.toml b/src/test/app/wasm_fixtures/all_host_functions/Cargo.toml deleted file mode 100644 index 71ad3ba9c6..0000000000 --- a/src/test/app/wasm_fixtures/all_host_functions/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "all_host_functions" -version = "0.1.0" -edition = "2024" - -# This empty workspace definition keeps this project independent of the parent workspace -[workspace] - -[lib] -crate-type = ["cdylib"] - -[dependencies] -xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-common-stdlib", branch = "error-and-trace" } -xrpl-escrow = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-escrow-stdlib", branch = "error-and-trace" } - -[profile.dev] -panic = "abort" - -[profile.release] -panic = "abort" -opt-level = "z" -lto = true diff --git a/src/test/app/wasm_fixtures/all_host_functions/src/lib.rs b/src/test/app/wasm_fixtures/all_host_functions/src/lib.rs deleted file mode 100644 index a593f3cb83..0000000000 --- a/src/test/app/wasm_fixtures/all_host_functions/src/lib.rs +++ /dev/null @@ -1,760 +0,0 @@ -#![cfg_attr(target_arch = "wasm32", no_std)] - -#[cfg(not(target_arch = "wasm32"))] -extern crate std; - -// -// Host Functions Test -// Tests 26 host functions (across 7 categories) -// -// With craft you can run this test with: -// craft test --project host_functions_test --test-case host_functions_test -// -// Amount Format Update: -// - XRP amounts now return as 8-byte serialized rippled objects -// - IOU and MPT amounts return in variable-length serialized format -// - Format details: https://xrpl.org/docs/references/protocol/binary-format#amount-fields -// -// Error Code Ranges: -// -100 to -199: Ledger Header Functions (3 functions) -// -200 to -299: Transaction Data Functions (5 functions) -// -300 to -399: Current Ledger Object Functions (4 functions) -// -400 to -499: Any Ledger Object Functions (5 functions) -// -500 to -599: Keylet Generation Functions (4 functions) -// -600 to -699: Utility Functions (4 functions) -// -700 to -799: Data Update Functions (1 function) -// - -use xrpl_escrow::current_tx::escrow_finish::EscrowFinish; -use xrpl_std::current_tx::traits::TransactionCommonFields; -use xrpl_std::host; -use xrpl_std::host::trace::TraceDataType; -use xrpl_std::host::trace::{trace, trace_acct_buf, trace_hex, trace_num}; -use xrpl_std::sfield; - -#[unsafe(no_mangle)] -pub extern "C" fn escrow_finish() -> i32 { - let _ = trace("=== HOST FUNCTIONS TEST ==="); - let _ = trace("Testing 26 host functions"); - - // Category 1: Ledger Header Data Functions (3 functions) - // Error range: -100 to -199 - match test_ledger_header_functions() { - 0 => (), - err => return err, - } - - // Category 2: Transaction Data Functions (5 functions) - // Error range: -200 to -299 - match test_transaction_data_functions() { - 0 => (), - err => return err, - } - - // Category 3: Current Ledger Object Functions (4 functions) - // Error range: -300 to -399 - match test_current_ledger_object_functions() { - 0 => (), - err => return err, - } - - // Category 4: Any Ledger Object Functions (5 functions) - // Error range: -400 to -499 - match test_any_ledger_object_functions() { - 0 => (), - err => return err, - } - - // Category 5: Keylet Generation Functions (4 functions) - // Error range: -500 to -599 - match test_keylet_generation_functions() { - 0 => (), - err => return err, - } - - // Category 6: Utility Functions (4 functions) - // Error range: -600 to -699 - match test_utility_functions() { - 0 => (), - err => return err, - } - - // Category 7: Data Update Functions (1 function) - // Error range: -700 to -799 - match test_data_update_functions() { - 0 => (), - err => return err, - } - - let _ = trace("SUCCESS: All host function tests passed!"); - 1 // Success return code for WASM finish function -} - -/// Test Category 1: Ledger Header Data Functions (3 functions) -/// - get_ledger_sqn() - Get ledger sequence number -/// - get_parent_ledger_time() - Get parent ledger timestamp -/// - get_parent_ledger_hash() - Get parent ledger hash -fn test_ledger_header_functions() -> i32 { - let _ = trace("--- Category 1: Ledger Header Functions ---"); - - // Test 1.1: get_ledger_sqn() - should return current ledger sequence number - let mut sqn_buffer = [0u8; 4]; - let sqn_result = unsafe { host::ldgr_index(sqn_buffer.as_mut_ptr(), sqn_buffer.len()) }; - - if sqn_result <= 0 { - let _ = trace_num("ERROR: get_ledger_sqn failed:", sqn_result as i64); - return -101; // Ledger sequence number test failed - } - let ledger_sqn = u32::from_be_bytes(sqn_buffer); - let _ = trace_num("Ledger sequence number:", ledger_sqn as i64); - - // Test 1.2: get_parent_ledger_time() - should return parent ledger timestamp - let mut time_buffer = [0u8; 4]; - let time_result = - unsafe { host::parent_ldgr_time(time_buffer.as_mut_ptr(), time_buffer.len()) }; - - if time_result <= 0 { - let _ = trace_num("ERROR: get_parent_ledger_time failed:", time_result as i64); - return -102; // Parent ledger time test failed - } - let parent_ledger_time = u32::from_be_bytes(time_buffer); - let _ = trace_num("Parent ledger time:", parent_ledger_time as i64); - - // Test 1.3: get_parent_ledger_hash() - should return parent ledger hash (32 bytes) - let mut hash_buffer = [0u8; 32]; - let hash_result = - unsafe { host::parent_ldgr_hash(hash_buffer.as_mut_ptr(), hash_buffer.len()) }; - - if hash_result != 32 { - let _ = trace_num( - "ERROR: get_parent_ledger_hash wrong length:", - hash_result as i64, - ); - return -103; // Parent ledger hash test failed - should be exactly 32 bytes - } - let _ = trace_hex("Parent ledger hash:", &hash_buffer); - - let _ = trace("SUCCESS: Ledger header functions"); - 0 -} - -/// Test Category 2: Transaction Data Functions (5 functions) -/// Tests all functions for accessing current transaction data -fn test_transaction_data_functions() -> i32 { - let _ = trace("--- Category 2: Transaction Data Functions ---"); - - // Test 2.1: get_tx_field() - Basic transaction field access - // Test with Account field (required, 20 bytes) - let mut account_buffer = [0u8; 20]; - let account_len = unsafe { - host::tx_field( - sfield::Account.into(), - account_buffer.as_mut_ptr(), - account_buffer.len(), - ) - }; - - if account_len != 20 { - let _ = trace_num( - "ERROR: get_tx_field(Account) wrong length:", - account_len as i64, - ); - return -201; // Basic transaction field test failed - } - let _ = trace_acct_buf("Transaction Account:", &account_buffer); - - // Test with Fee field (XRP amount - 8 bytes in new serialized format) - // New format: XRP amounts are always 8 bytes (positive: value | cPositive flag, negative: just value) - let mut fee_buffer = [0u8; 8]; - let fee_len = unsafe { - host::tx_field( - sfield::Fee.into(), - fee_buffer.as_mut_ptr(), - fee_buffer.len(), - ) - }; - - if fee_len != 8 { - let _ = trace_num( - "ERROR: get_tx_field(Fee) wrong length (expected 8 bytes for XRP):", - fee_len as i64, - ); - return -202; // Fee field test failed - XRP amounts should be exactly 8 bytes - } - let _ = trace_num("Transaction Fee length:", fee_len as i64); - let _ = trace_hex("Transaction Fee (serialized XRP amount):", &fee_buffer); - - // Test with Sequence field (required, 4 bytes uint32) - let mut seq_buffer = [0u8; 4]; - let seq_len = unsafe { - host::tx_field( - sfield::Sequence.into(), - seq_buffer.as_mut_ptr(), - seq_buffer.len(), - ) - }; - - if seq_len != 4 { - let _ = trace_num( - "ERROR: get_tx_field(Sequence) wrong length:", - seq_len as i64, - ); - return -203; // Sequence field test failed - } - let _ = trace_hex("Transaction Sequence:", &seq_buffer); - - // NOTE: get_tx_field2() through get_tx_field6() have been deprecated. - // Use get_tx_field() with appropriate parameters for all transaction field access. - - // Test 2.2: get_tx_nested_field() - Nested field access with locator - let locator = [ - 0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, - ]; // Two int32s in little-endian: [1, 0] - let mut nested_buffer = [0u8; 32]; - let nested_result = unsafe { - host::tx_inner( - locator.as_ptr(), - locator.len(), - nested_buffer.as_mut_ptr(), - nested_buffer.len(), - ) - }; - - if nested_result < 0 { - let _ = trace_num( - "INFO: get_tx_nested_field not applicable:", - nested_result as i64, - ); - // Expected - locator may not match transaction structure - } else { - let _ = trace_num("Nested field length:", nested_result as i64); - let _ = trace_hex("Nested field:", &nested_buffer[..nested_result as usize]); - } - - // Test 2.3: get_tx_array_len() - Get array length - let signers_len = unsafe { host::tx_arr_len(sfield::Signers.into()) }; - let _ = trace_num("Signers array length:", signers_len as i64); - - let memos_len = unsafe { host::tx_arr_len(sfield::Memos.into()) }; - let _ = trace_num("Memos array length:", memos_len as i64); - - // Test 2.4: get_tx_nested_array_len() - Get nested array length with locator - let nested_array_len = unsafe { host::tx_inner_arr_len(locator.as_ptr(), locator.len()) }; - - if nested_array_len < 0 { - let _ = trace_num( - "INFO: get_tx_nested_array_len not applicable:", - nested_array_len as i64, - ); - } else { - let _ = trace_num("Nested array length:", nested_array_len as i64); - } - - let _ = trace("SUCCESS: Transaction data functions"); - 0 -} - -/// Test Category 3: Current Ledger Object Functions (4 functions) -/// Tests functions that access the current ledger object being processed -fn test_current_ledger_object_functions() -> i32 { - let _ = trace("--- Category 3: Current Ledger Object Functions ---"); - - // Test 3.1: get_current_ledger_obj_field() - Access field from current ledger object - // Test with Balance field (XRP amount - 8 bytes in new serialized format) - let mut balance_buffer = [0u8; 8]; - let balance_result = unsafe { - host::home_le_field( - sfield::Balance.into(), - balance_buffer.as_mut_ptr(), - balance_buffer.len(), - ) - }; - - if balance_result <= 0 { - let _ = trace_num( - "INFO: get_current_ledger_obj_field(Balance) failed (may be expected):", - balance_result as i64, - ); - // This might fail if current ledger object doesn't have balance field - } else if balance_result == 8 { - let _ = trace_num( - "Current object balance length (XRP amount):", - balance_result as i64, - ); - let _ = trace_hex( - "Current object balance (serialized XRP amount):", - &balance_buffer, - ); - } else { - let _ = trace_num( - "Current object balance length (non-XRP amount):", - balance_result as i64, - ); - let _ = trace_hex( - "Current object balance:", - &balance_buffer[..balance_result as usize], - ); - } - - // Test with Account field - let mut current_account_buffer = [0u8; 20]; - let current_account_result = unsafe { - host::home_le_field( - sfield::Account.into(), - current_account_buffer.as_mut_ptr(), - current_account_buffer.len(), - ) - }; - - if current_account_result <= 0 { - let _ = trace_num( - "INFO: get_current_ledger_obj_field(Account) failed:", - current_account_result as i64, - ); - } else { - let _ = trace_acct_buf("Current ledger object account:", ¤t_account_buffer); - } - - // Test 3.2: get_current_ledger_obj_nested_field() - Nested field access - let locator = [ - 0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, - ]; // Two int32s in little-endian: [1, 0] - let mut current_nested_buffer = [0u8; 32]; - let current_nested_result = unsafe { - host::home_le_inner( - locator.as_ptr(), - locator.len(), - current_nested_buffer.as_mut_ptr(), - current_nested_buffer.len(), - ) - }; - - if current_nested_result < 0 { - let _ = trace_num( - "INFO: get_current_ledger_obj_nested_field not applicable:", - current_nested_result as i64, - ); - } else { - let _ = trace_num("Current nested field length:", current_nested_result as i64); - let _ = trace_hex( - "Current nested field:", - ¤t_nested_buffer[..current_nested_result as usize], - ); - } - - // Test 3.3: get_current_ledger_obj_array_len() - Array length in current object - let current_array_len = unsafe { host::home_le_arr_len(sfield::Signers.into()) }; - let _ = trace_num( - "Current object Signers array length:", - current_array_len as i64, - ); - - // Test 3.4: get_current_ledger_obj_nested_array_len() - Nested array length - let current_nested_array_len = - unsafe { host::home_le_inner_arr_len(locator.as_ptr(), locator.len()) }; - - if current_nested_array_len < 0 { - let _ = trace_num( - "INFO: get_current_ledger_obj_nested_array_len not applicable:", - current_nested_array_len as i64, - ); - } else { - let _ = trace_num( - "Current nested array length:", - current_nested_array_len as i64, - ); - } - - let _ = trace("SUCCESS: Current ledger object functions"); - 0 -} - -/// Test Category 4: Any Ledger Object Functions (5 functions) -/// Tests functions that work with cached ledger objects -fn test_any_ledger_object_functions() -> i32 { - let _ = trace("--- Category 4: Any Ledger Object Functions ---"); - - // First we need to cache a ledger object to test the other functions - // Get the account from transaction and generate its keylet - let escrow_finish = EscrowFinish; - let account_id = escrow_finish.get_account().unwrap(); - - // Test 4.1: cache_le() - Cache a ledger object - let mut keylet_buffer = [0u8; 32]; - let keylet_result = unsafe { - host::accountroot_id( - account_id.0.as_ptr(), - account_id.0.len(), - keylet_buffer.as_mut_ptr(), - keylet_buffer.len(), - ) - }; - - if keylet_result != 32 { - let _ = trace_num( - "ERROR: accountroot_id failed for caching test:", - keylet_result as i64, - ); - return -401; // Keylet generation failed for caching test - } - - let cache_result = unsafe { host::cache_le(keylet_buffer.as_ptr(), keylet_result as usize, 0) }; - - if cache_result <= 0 { - let _ = trace_num( - "INFO: cache_le failed (expected with test fixtures):", - cache_result as i64, - ); - // Test fixtures may not contain the account object - this is expected - // We'll test the interface but expect failures - - // Test 4.2-4.5 with invalid slot (should fail gracefully) - let mut test_buffer = [0u8; 32]; - - // Test le_field with invalid slot - let field_result = unsafe { - host::le_field( - 1, - sfield::Balance.into(), - test_buffer.as_mut_ptr(), - test_buffer.len(), - ) - }; - if field_result < 0 { - let _ = trace_num( - "INFO: le_field failed as expected (no cached object):", - field_result as i64, - ); - } - - // Test le_inner_field with invalid slot - let locator = [ - 0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, - ]; // Two int32s in little-endian: [1, 0] - let nested_result = unsafe { - host::le_inner( - 1, - locator.as_ptr(), - locator.len(), - test_buffer.as_mut_ptr(), - test_buffer.len(), - ) - }; - if nested_result < 0 { - let _ = trace_num( - "INFO: le_inner_field failed as expected:", - nested_result as i64, - ); - } - - // Test le_inner_arr_len with invalid slot - let array_result = unsafe { host::le_arr_len(1, sfield::Signers.into()) }; - if array_result < 0 { - let _ = trace_num( - "INFO: le_inner_arr_len failed as expected:", - array_result as i64, - ); - } - - // Test get_ledger_obj_nested_array_len with invalid slot - let nested_array_result = - unsafe { host::le_inner_arr_len(1, locator.as_ptr(), locator.len()) }; - if nested_array_result < 0 { - let _ = trace_num( - "INFO: get_ledger_obj_nested_array_len failed as expected:", - nested_array_result as i64, - ); - } - - let _ = trace("SUCCESS: Any ledger object functions (interface tested)"); - return 0; - } - - // If we successfully cached an object, test the access functions - let slot = cache_result; - let _ = trace_num("Successfully cached object in slot:", slot as i64); - - // Test 4.2: le_field() - Access field from cached object - let mut cached_balance_buffer = [0u8; 8]; - let cached_balance_result = unsafe { - host::le_field( - slot, - sfield::Balance.into(), - cached_balance_buffer.as_mut_ptr(), - cached_balance_buffer.len(), - ) - }; - - if cached_balance_result <= 0 { - let _ = trace_num( - "INFO: le_field(Balance) failed:", - cached_balance_result as i64, - ); - } else if cached_balance_result == 8 { - let _ = trace_num( - "Cached object balance length (XRP amount):", - cached_balance_result as i64, - ); - let _ = trace_hex( - "Cached object balance (serialized XRP amount):", - &cached_balance_buffer, - ); - } else { - let _ = trace_num( - "Cached object balance length (non-XRP amount):", - cached_balance_result as i64, - ); - let _ = trace_hex( - "Cached object balance:", - &cached_balance_buffer[..cached_balance_result as usize], - ); - } - - // Test 4.3: le_inner_field() - Nested field from cached object - let locator = [ - 0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, - ]; // Two int32s in little-endian: [1, 0] - let mut cached_nested_buffer = [0u8; 32]; - let cached_nested_result = unsafe { - host::le_inner( - slot, - locator.as_ptr(), - locator.len(), - cached_nested_buffer.as_mut_ptr(), - cached_nested_buffer.len(), - ) - }; - - if cached_nested_result < 0 { - let _ = trace_num( - "INFO: le_inner_field not applicable:", - cached_nested_result as i64, - ); - } else { - let _ = trace_num("Cached nested field length:", cached_nested_result as i64); - let _ = trace_hex( - "Cached nested field:", - &cached_nested_buffer[..cached_nested_result as usize], - ); - } - - // Test 4.4: le_inner_arr_len() - Array length from cached object - let cached_array_len = unsafe { host::le_arr_len(slot, sfield::Signers.into()) }; - let _ = trace_num( - "Cached object Signers array length:", - cached_array_len as i64, - ); - - // Test 4.5: get_ledger_obj_nested_array_len() - Nested array length from cached object - let cached_nested_array_len = - unsafe { host::le_inner_arr_len(slot, locator.as_ptr(), locator.len()) }; - - if cached_nested_array_len < 0 { - let _ = trace_num( - "INFO: get_ledger_obj_nested_array_len not applicable:", - cached_nested_array_len as i64, - ); - } else { - let _ = trace_num( - "Cached nested array length:", - cached_nested_array_len as i64, - ); - } - - let _ = trace("SUCCESS: Any ledger object functions"); - 0 -} - -/// Test Category 5: Keylet Generation Functions (4 functions) -/// Tests keylet generation functions for different ledger entry types -fn test_keylet_generation_functions() -> i32 { - let _ = trace("--- Category 5: Keylet Generation Functions ---"); - - let escrow_finish = EscrowFinish; - let account_id = escrow_finish.get_account().unwrap(); - - // Test 5.1: accountroot_id() - Generate keylet for account - let mut accountroot_id_buffer = [0u8; 32]; - let accountroot_id_result = unsafe { - host::accountroot_id( - account_id.0.as_ptr(), - account_id.0.len(), - accountroot_id_buffer.as_mut_ptr(), - accountroot_id_buffer.len(), - ) - }; - - if accountroot_id_result != 32 { - let _ = trace_num( - "ERROR: accountroot_id failed:", - accountroot_id_result as i64, - ); - return -501; // Account keylet generation failed - } - let _ = trace_hex("Account keylet:", &accountroot_id_buffer); - - // Test 5.2: credential_keylet() - Generate keylet for credential - let mut credential_keylet_buffer = [0u8; 32]; - let credential_keylet_result = unsafe { - host::credential_id( - account_id.0.as_ptr(), // Subject - account_id.0.len(), - account_id.0.as_ptr(), // Issuer - same account for test - account_id.0.len(), - b"TestType".as_ptr(), // Credential type - 9usize, // Length of "TestType" - credential_keylet_buffer.as_mut_ptr(), - credential_keylet_buffer.len(), - ) - }; - - if credential_keylet_result <= 0 { - let _ = trace_num( - "INFO: credential_keylet failed (expected - interface issue):", - credential_keylet_result as i64, - ); - // This is expected to fail due to unusual parameter types - } else { - let _ = trace_hex( - "Credential keylet:", - &credential_keylet_buffer[..credential_keylet_result as usize], - ); - } - - // Test 5.3: escrow_keylet() - Generate keylet for escrow - let mut escrow_keylet_buffer = [0u8; 32]; - let sequence_number: i32 = 1000; - let sequence_number_bytes = sequence_number.to_be_bytes(); - let escrow_keylet_result = unsafe { - host::escrow_id( - account_id.0.as_ptr(), - account_id.0.len(), - sequence_number_bytes.as_ptr(), - sequence_number_bytes.len(), - escrow_keylet_buffer.as_mut_ptr(), - escrow_keylet_buffer.len(), - ) - }; - - if escrow_keylet_result != 32 { - let _ = trace_num("ERROR: escrow_keylet failed:", escrow_keylet_result as i64); - return -503; // Escrow keylet generation failed - } - let _ = trace_hex("Escrow keylet:", &escrow_keylet_buffer); - - // Test 5.4: oracle_keylet() - Generate keylet for oracle - let mut oracle_keylet_buffer = [0u8; 32]; - let document_id: i32 = 42; - let document_id_bytes = document_id.to_be_bytes(); - let oracle_keylet_result = unsafe { - host::oracle_id( - account_id.0.as_ptr(), - account_id.0.len(), - document_id_bytes.as_ptr(), - document_id_bytes.len(), - oracle_keylet_buffer.as_mut_ptr(), - oracle_keylet_buffer.len(), - ) - }; - - if oracle_keylet_result != 32 { - let _ = trace_num("ERROR: oracle_keylet failed:", oracle_keylet_result as i64); - return -504; // Oracle keylet generation failed - } - let _ = trace_hex("Oracle keylet:", &oracle_keylet_buffer); - - let _ = trace("SUCCESS: Keylet generation functions"); - 0 -} - -/// Test Category 6: Utility Functions (4 functions) -/// Tests utility functions for hashing, NFT access, and tracing -fn test_utility_functions() -> i32 { - let _ = trace("--- Category 6: Utility Functions ---"); - - // Test 6.1: compute_sha512_half() - SHA512 hash computation (first 32 bytes) - let test_data = b"Hello, XRPL WASM world!"; - let mut hash_output = [0u8; 32]; - let hash_result = unsafe { - host::sha512_half( - test_data.as_ptr(), - test_data.len(), - hash_output.as_mut_ptr(), - hash_output.len(), - ) - }; - - if hash_result != 32 { - let _ = trace_num("ERROR: compute_sha512_half failed:", hash_result as i64); - return -601; // SHA512 half computation failed - } - let _ = trace_hex("Input data:", test_data); - let _ = trace_hex("SHA512 half hash:", &hash_output); - - // Test 6.2: get_nft() - NFT data retrieval - let escrow_finish = EscrowFinish; - let account_id = escrow_finish.get_account().unwrap(); - let nft_id = [0u8; 32]; // Dummy NFT ID for testing - let mut nft_buffer = [0u8; 256]; - let nft_result = unsafe { - host::nft_uri( - account_id.0.as_ptr(), - account_id.0.len(), - nft_id.as_ptr(), - nft_id.len(), - nft_buffer.as_mut_ptr(), - nft_buffer.len(), - ) - }; - - if nft_result <= 0 { - let _ = trace_num( - "INFO: get_nft failed (expected - no such NFT):", - nft_result as i64, - ); - // This is expected - test account likely doesn't own the dummy NFT - } else { - let _ = trace_num("NFT data length:", nft_result as i64); - let _ = trace_hex("NFT data:", &nft_buffer[..nft_result as usize]); - } - - // Test 6.3: trace() - Debug logging with data - let trace_message = b"Test trace message"; - let trace_data_payload = b"payload"; - unsafe { - host::trace( - trace_message.as_ptr(), - trace_message.len(), - TraceDataType::AsHex as i32, - trace_data_payload.as_ptr(), - trace_data_payload.len(), - ) - }; - - // Test 6.4: trace_num() - Debug logging with number - let test_number = 42i64; - trace_num("Test number trace", test_number); - - let _ = trace("SUCCESS: Utility functions"); - 0 -} - -/// Test Category 7: Data Update Functions (1 function) -/// Tests the function for modifying the current ledger entry -fn test_data_update_functions() -> i32 { - let _ = trace("--- Category 7: Data Update Functions ---"); - - // Test 7.1: update_data() - Update current ledger entry data - let update_payload = b"Updated ledger entry data from WASM test"; - - let update_result = unsafe { host::set_data(update_payload.as_ptr(), update_payload.len()) }; - - if update_result != update_payload.len() as i32 { - let _ = trace_num("ERROR: update_data failed:", update_result as i64); - return -701; // Data update failed - } - - let _ = trace_hex("Successfully updated ledger entry with:", update_payload); - let _ = trace("SUCCESS: Data update functions"); - 0 -} diff --git a/src/test/app/wasm_fixtures/all_keylets/Cargo.lock b/src/test/app/wasm_fixtures/all_keylets/Cargo.lock deleted file mode 100644 index 5da5b26f66..0000000000 --- a/src/test/app/wasm_fixtures/all_keylets/Cargo.lock +++ /dev/null @@ -1,171 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "all_keylets" -version = "0.0.1" -dependencies = [ - "xrpl-wasm-stdlib", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "libc" -version = "0.2.186" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tinyvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "typenum" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "xrpl-macros" -version = "0.1.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#21c522f34a24b460297ebb6be1822680459bf37e" -dependencies = [ - "bs58", - "quote", - "sha2", - "syn", -] - -[[package]] -name = "xrpl-wasm-stdlib" -version = "0.8.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#21c522f34a24b460297ebb6be1822680459bf37e" -dependencies = [ - "xrpl-macros", -] diff --git a/src/test/app/wasm_fixtures/all_keylets/Cargo.toml b/src/test/app/wasm_fixtures/all_keylets/Cargo.toml deleted file mode 100644 index ad53fd62b1..0000000000 --- a/src/test/app/wasm_fixtures/all_keylets/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -edition = "2024" -name = "all_keylets" -version = "0.0.1" - -# This empty workspace definition keeps this project independent of the parent workspace -[workspace] - -[lib] -crate-type = ["cdylib"] - -[profile.release] -lto = true -opt-level = 's' -panic = "abort" - -[dependencies] -xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" } - -[profile.dev] -panic = "abort" diff --git a/src/test/app/wasm_fixtures/all_keylets/src/lib.rs b/src/test/app/wasm_fixtures/all_keylets/src/lib.rs deleted file mode 100644 index f0a4e5abb5..0000000000 --- a/src/test/app/wasm_fixtures/all_keylets/src/lib.rs +++ /dev/null @@ -1,176 +0,0 @@ -#![cfg_attr(target_arch = "wasm32", no_std)] - -#[cfg(not(target_arch = "wasm32"))] -extern crate std; - -use crate::host::{Error, Result, Result::Err, Result::Ok}; -use xrpl_std::core::keylets; -use xrpl_std::core::ledger_objects::current_escrow::get_current_escrow; -use xrpl_std::core::ledger_objects::current_escrow::CurrentEscrow; -use xrpl_std::core::ledger_objects::ledger_object; -use xrpl_std::core::ledger_objects::traits::CurrentEscrowFields; -use xrpl_std::core::ledger_objects::LedgerObjectFieldGetter; -use xrpl_std::core::types::currency::Currency; -use xrpl_std::core::types::issue::{IouIssue, Issue, XrpIssue}; -use xrpl_std::core::types::mpt_id::MptId; -use xrpl_std::host; -use xrpl_std::host::trace::{trace, trace_acct, trace_data, trace_num, DataRepr}; -use xrpl_std::sfield; - -pub fn object_exists( - keylet_result: Result, - keylet_type: &str, - sfield: sfield::SField, -) -> Result { - let field = CODE; - match keylet_result { - Ok(keylet) => { - let _ = trace_data(keylet_type, &keylet, DataRepr::AsHex); - - let slot = unsafe { host::cache_le(keylet.as_ptr(), keylet.len(), 0) }; - if slot <= 0 { - let _ = trace_num("Error: ", slot.into()); - return Err(Error::from_code(slot)); - } - if field == 0 { - let new_field = sfield::PreviousTxnID; - let _ = trace_num("Getting field: ", new_field.clone().into()); - match ledger_object::get_field(slot, new_field) { - Ok(data) => { - let _ = trace_data("Field data: ", &data.0, DataRepr::AsHex); - } - Err(result_code) => { - let _ = trace_num("Error getting field: ", result_code.into()); - return Err(result_code); - } - } - } else { - let _ = trace_num("Getting field: ", field.into()); - match ledger_object::get_field(slot, sfield) { - Ok(_data) => { - let _ = trace("Field data: retrieved"); - } - Err(result_code) => { - let _ = trace_num("Error getting field: ", result_code.into()); - return Err(result_code); - } - } - } - - Ok(true) - } - Err(error) => { - let _ = trace_num("Error getting keylet: ", error.into()); - Err(error) - } - } -} - -#[unsafe(no_mangle)] -pub extern "C" fn escrow_finish() -> i32 { - let _ = trace("$$$$$ STARTING WASM EXECUTION $$$$$"); - - let escrow: CurrentEscrow = get_current_escrow(); - - let account = escrow.get_account().unwrap_or_panic(); - let _ = trace_acct("Account:", &account); - - let destination = escrow.get_destination().unwrap_or_panic(); - let _ = trace_acct("Destination:", &destination); - - let mut seq = 5; - - macro_rules! check_object_exists { - ($keylet:expr, $type:expr, $field:expr) => { - match object_exists($keylet, $type, $field) { - Ok(_exists) => { - // false isn't returned - let _ = trace(concat!( - $type, - " object exists, proceeding with escrow finish." - )); - } - Err(error) => { - let _ = trace_num("Current seq value:", seq.try_into().unwrap()); - return error.code(); - } - } - }; - } - - let accountroot_id = keylets::accountroot_id(&account); - check_object_exists!(accountroot_id, "Account", sfield::Account); - - let currency_code: &[u8; 3] = b"USD"; - let currency: Currency = Currency::from(*currency_code); - let trustline_id = keylets::trustline_id(&account, &destination, ¤cy); - check_object_exists!(trustline_id, "Trustline", sfield::Generic); - seq += 1; - - let asset1 = Issue::XRP(XrpIssue {}); - let asset2 = Issue::IOU(IouIssue::new(destination, currency)); - check_object_exists!(keylets::amm_id(&asset1, &asset2), "AMM", sfield::Account); - - let check_id = keylets::check_id(&account, seq); - check_object_exists!(check_id, "Check", sfield::Account); - seq += 1; - - let cred_type: &[u8] = b"termsandconditions"; - let credential_id = keylets::credential_id(&account, &account, cred_type); - check_object_exists!(credential_id, "Credential", sfield::Subject); - seq += 1; - - let delegate_id = keylets::delegate_id(&account, &destination); - check_object_exists!(delegate_id, "Delegate", sfield::Account); - seq += 1; - - let deposit_preauth_id = keylets::deposit_preauth_id(&account, &destination); - check_object_exists!(deposit_preauth_id, "DepositPreauth", sfield::Account); - seq += 1; - - let did_id = keylets::did_id(&account); - check_object_exists!(did_id, "DID", sfield::Account); - seq += 1; - - let escrow_id = keylets::escrow_id(&account, seq); - check_object_exists!(escrow_id, "Escrow", sfield::Account); - seq += 1; - - let mpt_issuance_id = keylets::mpt_issuance_id(&account, seq); - let mpt_id = MptId::new(seq.try_into().unwrap(), account); - check_object_exists!(mpt_issuance_id, "MPTIssuance", sfield::Issuer); - seq += 1; - - let mptoken_id = keylets::mptoken_id(&mpt_id, &destination); - check_object_exists!(mptoken_id, "MPToken", sfield::Account); - - let nft_offer_id = keylets::nft_offer_id(&destination, 6); - check_object_exists!(nft_offer_id, "NFTokenOffer", sfield::Owner); - - let offer_id = keylets::offer_id(&account, seq); - check_object_exists!(offer_id, "Offer", sfield::Account); - seq += 1; - - let paychan_id = keylets::paychan_id(&account, &destination, seq); - check_object_exists!(paychan_id, "PayChannel", sfield::Account); - seq += 1; - - let pd_id = keylets::permissioned_domain_id(&account, seq); - check_object_exists!(pd_id, "PermissionedDomain", sfield::Owner); - seq += 1; - - let signers_id = keylets::signers_id(&account); - check_object_exists!(signers_id, "SignerList", sfield::Generic); - seq += 1; - - seq += 1; // ticket sequence number is one greater - let ticket_id = keylets::ticket_id(&account, seq); - check_object_exists!(ticket_id, "Ticket", sfield::Account); - seq += 1; - - let vault_id = keylets::vault_id(&account, seq); - check_object_exists!(vault_id, "Vault", sfield::Account); - // seq += 1; - - 1 // All keylets exist, finish the escrow. -} diff --git a/src/test/app/wasm_fixtures/bad_align.c b/src/test/app/wasm_fixtures/bad_align.c deleted file mode 100644 index 560245e762..0000000000 --- a/src/test/app/wasm_fixtures/bad_align.c +++ /dev/null @@ -1,42 +0,0 @@ -#include - -int32_t float_from_uint(uint8_t const *, int32_t, uint8_t *, int32_t, int32_t); -int32_t check_id(uint8_t const *, int32_t, uint8_t const *, int32_t, uint8_t *, - int32_t); - -uint8_t e_data1[32 * 1024]; -uint8_t e_data2[32 * 1024]; - -int32_t test1() -{ - e_data1[1] = 0xFF; - e_data1[2] = 0xFF; - e_data1[3] = 0xFF; - e_data1[4] = 0xFF; - e_data1[5] = 0xFF; - e_data1[6] = 0xFF; - e_data1[7] = 0xFF; - e_data1[8] = 0xFF; - int32_t result = float_from_uint(&e_data1[1], 8, &e_data1[35], 12, 0); - return result >= 0 ? *((int32_t *)(&e_data1[36])) : result; -} - -int32_t test2() -{ - // Set up misaligned uint32 (seq) at offset 1 - e_data2[1] = 0xFF; - e_data2[2] = 0xFF; - e_data2[3] = 0xFF; - e_data2[4] = 0xFF; - // Set up valid non-zero AccountID (20 bytes) at offset 10 - for (int i = 0; i < 20; i++) - e_data2[10 + i] = i + 1; - // Call check_id with misaligned uint32 at &e_data2[1] to hit line 72 in - // HostFuncWrapper.cpp - int32_t result = check_id(&e_data2[10], 20, &e_data2[1], 4, &e_data2[35], 32); - // Return the misaligned value directly to validate it was read correctly (-1 - // if all 0xFF) - return result >= 0 ? *((int32_t *)(&e_data2[36])) : result; -} - -int32_t test() { return test1() + test2(); } diff --git a/src/test/app/wasm_fixtures/codecov_tests/Cargo.lock b/src/test/app/wasm_fixtures/codecov_tests/Cargo.lock deleted file mode 100644 index 899f278196..0000000000 --- a/src/test/app/wasm_fixtures/codecov_tests/Cargo.lock +++ /dev/null @@ -1,180 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "block-buffer" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "codecov_tests" -version = "0.0.1" -dependencies = [ - "xrpl-common-stdlib", - "xrpl-escrow-stdlib", -] - -[[package]] -name = "const-oid" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" - -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "digest" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", -] - -[[package]] -name = "hybrid-array" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" -dependencies = [ - "typenum", -] - -[[package]] -name = "libc" -version = "0.2.186" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "sha2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "syn" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tinyvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "typenum" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "xrpl-common-stdlib" -version = "0.8.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=error-and-trace#b008b097237ce0d1a2dffc72ba39dd9fc50020a9" -dependencies = [ - "xrpl-macros", -] - -[[package]] -name = "xrpl-escrow-stdlib" -version = "0.1.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=error-and-trace#b008b097237ce0d1a2dffc72ba39dd9fc50020a9" -dependencies = [ - "xrpl-common-stdlib", -] - -[[package]] -name = "xrpl-macros" -version = "0.1.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=error-and-trace#b008b097237ce0d1a2dffc72ba39dd9fc50020a9" -dependencies = [ - "bs58", - "proc-macro2", - "quote", - "sha2", - "syn", -] diff --git a/src/test/app/wasm_fixtures/codecov_tests/Cargo.toml b/src/test/app/wasm_fixtures/codecov_tests/Cargo.toml deleted file mode 100644 index 1e388a5154..0000000000 --- a/src/test/app/wasm_fixtures/codecov_tests/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -edition = "2024" -name = "codecov_tests" -version = "0.0.1" - -# This empty workspace definition keeps this project independent of the parent workspace -[workspace] - -[lib] -crate-type = ["cdylib"] - -[profile.release] -lto = true -opt-level = 's' -panic = "abort" - -[dependencies] -xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-common-stdlib", branch = "error-and-trace" } -xrpl-escrow = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-escrow-stdlib", branch = "error-and-trace" } diff --git a/src/test/app/wasm_fixtures/codecov_tests/src/host_bindings_loose.rs b/src/test/app/wasm_fixtures/codecov_tests/src/host_bindings_loose.rs deleted file mode 100644 index 7b42f747a8..0000000000 --- a/src/test/app/wasm_fixtures/codecov_tests/src/host_bindings_loose.rs +++ /dev/null @@ -1,56 +0,0 @@ -//TODO add docs after discussing the interface -//Note that Craft currently does not honor the rounding modes -#[allow(unused)] -pub const FLOAT_ROUNDING_MODES_TO_NEAREST: i32 = 0; -#[allow(unused)] -pub const FLOAT_ROUNDING_MODES_TOWARDS_ZERO: i32 = 1; -#[allow(unused)] -pub const FLOAT_ROUNDING_MODES_DOWNWARD: i32 = 2; -#[allow(unused)] -pub const FLOAT_ROUNDING_MODES_UPWARD: i32 = 3; - -// pub enum RippledRoundingModes{ -// ToNearest = 0, -// TowardsZero = 1, -// DOWNWARD = 2, -// UPWARD = 3 -// } - -#[allow(unused)] -#[link(wasm_import_module = "host_lib")] -unsafe extern "C" { - pub fn parent_ldgr_hash(out_buff_ptr: i32, out_buff_len: i32) -> i32; - - pub fn cache_le(keylet_ptr: i32, keylet_len: i32, cache_num: i32) -> i32; - - pub fn tx_inner_arr_len(locator_ptr: i32, locator_len: i32) -> i32; - - pub fn accountroot_id( - account_ptr: i32, - account_len: i32, - out_buff_ptr: *mut u8, - out_buff_len: usize, - ) -> i32; - - pub fn trustline_id( - account1_ptr: *const u8, - account1_len: usize, - account2_ptr: *const u8, - account2_len: usize, - currency_ptr: i32, - currency_len: i32, - out_buff_ptr: *mut u8, - out_buff_len: usize, - ) -> i32; - - // Same wasm functype as the real binding, so this is not a second import of - // host_lib.trace. Loose i32 pointers exercise the out-of-bounds path. - #[link_name = "trace"] - pub fn trace_loose( - msg_read_ptr: i32, - msg_read_len: i32, - data_type: i32, - data_read_ptr: i32, - data_read_len: i32, - ); -} diff --git a/src/test/app/wasm_fixtures/codecov_tests/src/lib.rs b/src/test/app/wasm_fixtures/codecov_tests/src/lib.rs deleted file mode 100644 index 02b38f633e..0000000000 --- a/src/test/app/wasm_fixtures/codecov_tests/src/lib.rs +++ /dev/null @@ -1,1744 +0,0 @@ -#![cfg_attr(target_arch = "wasm32", no_std)] - -#[cfg(not(target_arch = "wasm32"))] -extern crate std; - -use core::panic; -use xrpl_escrow::current_tx::escrow_finish::{EscrowFinish, get_current_escrow_finish}; -use xrpl_std::current_tx::traits::TransactionCommonFields; -use xrpl_std::fields::locator::Locator; -use xrpl_std::host; -use xrpl_std::host::error_codes; -use xrpl_std::host::trace::TraceDataType; -use xrpl_std::host::trace::{trace, trace_num as trace_number}; -use xrpl_std::ledger_entry_ids; -use xrpl_std::sfield; -use xrpl_std::types::blob::DEFAULT_BLOB_SIZE; -use xrpl_std::types::contract_data::XRPL_CONTRACT_DATA_SIZE; -use xrpl_std::types::issue::Issue; -use xrpl_std::types::issue::XrpIssue; -use xrpl_std::types::mpt_id::MptId; - -mod host_bindings_loose; -include!("host_bindings_loose.rs"); - -fn check_result(result: i32, expected: i32, test_name: &'static str) { - match result { - code if code == expected => { - let _ = trace_number(test_name, code.into()); - } - code if code >= 0 => { - let _ = trace(test_name); - let _ = trace_number("TEST FAILED", code.into()); - panic!("Unexpected success code: {}", code); - } - code => { - let _ = trace(test_name); - let _ = trace_number("TEST FAILED", code.into()); - panic!("Error code: {}", code); - } - } -} - -fn with_buffer(mut f: F) -> R -where - F: FnMut(*mut u8, usize) -> R, -{ - let mut buf = [0u8; N]; - f(buf.as_mut_ptr(), buf.len()) -} - -#[unsafe(no_mangle)] -pub extern "C" fn escrow_finish() -> i32 { - let _ = trace("$$$$$ STARTING WASM EXECUTION $$$$$"); - - // ######################################## - // Step #1: Test all host function happy paths - // Note: not testing all the keylet functions, - // that's in a separate test file (all_keylets). - // The float tests are also in a separate file (float_tests). - // ######################################## - with_buffer::<4, _, _>(|ptr, len| { - check_result(unsafe { host::ldgr_index(ptr, len) }, 4, "ldgr_index"); - }); - with_buffer::<4, _, _>(|ptr, len| { - check_result( - unsafe { host::parent_ldgr_time(ptr, len) }, - 4, - "parent_ldgr_time", - ); - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { host::parent_ldgr_hash(ptr, len) }, - 32, - "parent_ldgr_hash", - ); - }); - with_buffer::<4, _, _>(|ptr, len| { - check_result(unsafe { host::base_fee(ptr, len) }, 4, "base_fee"); - }); - let amendment_name: &[u8] = b"test_amendment"; - let amendment_id: [u8; 32] = [1; 32]; - check_result( - unsafe { host::amendment_enabled(amendment_name.as_ptr(), amendment_name.len()) }, - 1, - "amendment_enabled", - ); - check_result( - unsafe { host::amendment_enabled(amendment_id.as_ptr(), amendment_id.len()) }, - 1, - "amendment_enabled", - ); - let tx: EscrowFinish = get_current_escrow_finish(); - let account = tx.get_account().unwrap_or_panic(); // get_tx_field under the hood - let keylet = ledger_entry_ids::accountroot_id(&account).unwrap_or_panic(); // accountroot_id under the hood - check_result( - unsafe { host::cache_le(keylet.as_ptr(), keylet.len(), 0) }, - 1, - "cache_le", - ); - with_buffer::<20, _, _>(|ptr, len| { - check_result( - unsafe { host::home_le_field(sfield::Account.into(), ptr, len) }, - 20, - "home_le_field", - ); - }); - with_buffer::<20, _, _>(|ptr, len| { - check_result( - unsafe { host::le_field(1, sfield::Account.into(), ptr, len) }, - 20, - "le_field", - ); - }); - let mut locator = Locator::new(); - locator.pack(sfield::Account); - with_buffer::<20, _, _>(|ptr, len| { - check_result( - unsafe { host::tx_inner(locator.as_ptr(), locator.len(), ptr, len) }, - 20, - "tx_inner", - ); - }); - with_buffer::<20, _, _>(|ptr, len| { - check_result( - unsafe { host::home_le_inner(locator.as_ptr(), locator.len(), ptr, len) }, - 20, - "home_le_inner", - ); - }); - with_buffer::<20, _, _>(|ptr, len| { - check_result( - unsafe { host::le_inner(1, locator.as_ptr(), locator.len(), ptr, len) }, - 20, - "le_inner", - ); - }); - check_result( - unsafe { host::tx_arr_len(sfield::Memos.into()) }, - 32, - "tx_arr_len", - ); - check_result( - unsafe { host::home_le_arr_len(sfield::Memos.into()) }, - 32, - "home_le_arr_len", - ); - check_result( - unsafe { host::le_arr_len(1, sfield::Memos.into()) }, - 32, - "le_arr_len", - ); - check_result( - unsafe { host::tx_inner_arr_len(locator.as_ptr(), locator.len()) }, - 32, - "tx_inner_arr_len", - ); - check_result( - unsafe { host::home_le_inner_arr_len(locator.as_ptr(), locator.len()) }, - 32, - "home_le_inner_arr_len", - ); - check_result( - unsafe { host::le_inner_arr_len(1, locator.as_ptr(), locator.len()) }, - 32, - "le_inner_arr_len", - ); - check_result( - unsafe { host::set_data(account.0.as_ptr(), account.0.len()) }, - 20, - "set_data", - ); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { host::sha512_half(locator.as_ptr(), locator.len(), ptr, len) }, - 32, - "sha512_half", - ); - }); - let message: &[u8] = b"test message"; - let pubkey: &[u8] = b"test pubkey"; //tx.get_public_key().unwrap_or_panic(); - let signature: &[u8] = b"test signature"; - check_result( - unsafe { - host::check_sig( - message.as_ptr(), - message.len(), - pubkey.as_ptr(), - pubkey.len(), - signature.as_ptr(), - signature.len(), - ) - }, - 1, - "check_sig", - ); - - let nft_id: [u8; 32] = amendment_id; - with_buffer::<18, _, _>(|ptr, len| { - check_result( - unsafe { - host::nft_uri( - account.0.as_ptr(), - account.0.len(), - nft_id.as_ptr(), - nft_id.len(), - ptr, - len, - ) - }, - 18, - "nft_uri", - ) - }); - with_buffer::<20, _, _>(|ptr, len| { - check_result( - unsafe { host::nft_issuer(nft_id.as_ptr(), nft_id.len(), ptr, len) }, - 20, - "nft_issuer", - ) - }); - with_buffer::<4, _, _>(|ptr, len| { - check_result( - unsafe { host::nft_taxon(nft_id.as_ptr(), nft_id.len(), ptr, len) }, - 4, - "nft_taxon", - ) - }); - check_result( - unsafe { host::nft_flags(nft_id.as_ptr(), nft_id.len()) }, - 8, - "nft_flags", - ); - check_result( - unsafe { host::nft_xfer_fee(nft_id.as_ptr(), nft_id.len()) }, - 10, - "nft_xfer_fee", - ); - with_buffer::<4, _, _>(|ptr, len| { - check_result( - unsafe { host::nft_serial(nft_id.as_ptr(), nft_id.len(), ptr, len) }, - 4, - "nft_serial", - ) - }); - let message = "testing trace"; - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::Account as i32, - account.0.as_ptr(), - account.0.len(), - ) - }; - let amount = &[0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F]; // 95 drops of XRP - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::Amount as i32, - amount.as_ptr(), - amount.len(), - ) - }; - let amount = &[0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; // 0 drops of XRP - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::Amount as i32, - amount.as_ptr(), - amount.len(), - ) - }; - - // ######################################## - // Step #2: Test set_data edge cases - // ######################################## - check_result( - unsafe { host_bindings_loose::parent_ldgr_hash(-1, 4) }, - error_codes::INVALID_PARAMS, - "parent_ldgr_hash_neg_ptr", - ); - with_buffer::<4, _, _>(|ptr, _len| { - check_result( - unsafe { host_bindings_loose::parent_ldgr_hash(ptr as i32, -1) }, - error_codes::INVALID_PARAMS, - "parent_ldgr_hash_neg_len", - ) - }); - with_buffer::<3, _, _>(|ptr, len| { - check_result( - unsafe { host_bindings_loose::parent_ldgr_hash(ptr as i32, len as i32) }, - error_codes::BUFFER_TOO_SMALL, - "parent_ldgr_hash_buf_too_small", - ) - }); - with_buffer::<4, _, _>(|ptr, _len| { - check_result( - unsafe { host_bindings_loose::parent_ldgr_hash(ptr as i32, 1_000_000_000) }, - error_codes::POINTER_OUT_OF_BOUNDS, - "parent_ldgr_hash_len_too_long", - ) - }); - - // ######################################## - // Step #3: Test getData[Type] edge cases - // ######################################## - - // SField - check_result( - unsafe { host::tx_arr_len(2) }, // not a valid SField value - error_codes::INVALID_FIELD, - "tx_arr_len_invalid_sfield", - ); - - // Slice - check_result( - unsafe { host_bindings_loose::tx_inner_arr_len(-1, locator.len() as i32) }, - error_codes::INVALID_PARAMS, - "tx_inner_arr_len_neg_ptr", - ); - check_result( - unsafe { host_bindings_loose::tx_inner_arr_len(locator.as_ptr() as i32, -1) }, - error_codes::INVALID_PARAMS, - "tx_inner_arr_len_neg_len", - ); - let long_len = DEFAULT_BLOB_SIZE + 1; - check_result( - unsafe { host_bindings_loose::tx_inner_arr_len(locator.as_ptr() as i32, long_len as i32) }, - error_codes::DATA_FIELD_TOO_LARGE, - "tx_inner_arr_len_too_long", - ); - check_result( - unsafe { - host_bindings_loose::tx_inner_arr_len( - locator.as_ptr() as i32 + 1_000_000_000, - locator.len() as i32, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "tx_inner_arr_len_ptr_oob", - ); - - // uint32 - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::check_id( - account.0.as_ptr(), - account.0.len(), - locator.as_ptr().wrapping_add(1_000_000_000), - 8, - ptr, - len, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "check_id_oob_len_u32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::check_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "check_id_wrong_len_u32", - ) - }); - - // uint64 - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_from_uint( - locator.as_ptr().wrapping_add(1_000_000_000), - 8, - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_from_uint_len_oob", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_from_uint( - locator.as_ptr(), - locator.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::INVALID_PARAMS, - "float_from_uint_wrong_len_uint64", - ) - }); - - // uint256 - check_result( - unsafe { - host_bindings_loose::cache_le( - locator.as_ptr() as i32 + 1_000_000_000, - locator.len() as i32, - 1, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "cache_le_ptr_oob", - ); - check_result( - unsafe { host_bindings_loose::cache_le(locator.as_ptr() as i32, locator.len() as i32, 1) }, - error_codes::INVALID_PARAMS, - "cache_le_wrong_len", - ); - - // AccountID - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host_bindings_loose::accountroot_id( - locator.as_ptr() as i32 + 1_000_000_000, - locator.len() as i32, - ptr, - len, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "accountroot_id_len_oob", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host_bindings_loose::accountroot_id( - locator.as_ptr() as i32, - locator.len() as i32, - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "accountroot_id_wrong_len", - ) - }); - - // Currency - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host_bindings_loose::trustline_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - locator.as_ptr() as i32 + 1_000_000_000, - locator.len() as i32, - ptr, - len, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "trustline_id_len_oob_currency", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host_bindings_loose::trustline_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - locator.as_ptr() as i32, - locator.len() as i32, - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "trustline_id_wrong_len_currency", - ) - }); - - // Issue - let asset1_bytes = Issue::XRP(XrpIssue {}).as_bytes(); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::amm_id( - asset1_bytes.as_ptr(), - asset1_bytes.len(), - locator.as_ptr().wrapping_add(1_000_000_000), - locator.len(), - ptr, - len, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "amm_id_len_oob_asset2", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::amm_id( - asset1_bytes.as_ptr(), - asset1_bytes.len(), - locator.as_ptr(), - locator.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "amm_id_len_wrong_len_asset2", - ) - }); - let currency: &[u8] = b"USD00000000000000000"; // 20 bytes - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::amm_id( - asset1_bytes.as_ptr(), - asset1_bytes.len(), - currency.as_ptr(), - currency.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "amm_id_len_wrong_non_xrp_currency_len", - ) - }); - let xrp_issue: &[u8] = &[0; 40]; // 40 bytes - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::amm_id( - xrp_issue.as_ptr(), - xrp_issue.len(), - asset1_bytes.as_ptr(), - asset1_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "amm_id_len_wrong_xrp_currency_len", - ) - }); - let mptid = MptId::new(1, account); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::amm_id( - mptid.as_ptr(), - mptid.len(), - asset1_bytes.as_ptr(), - asset1_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "amm_id_mpt", - ) - }); - - // Out-of-bounds message pointer; nothing to assert on now that trace is void. - let num_bytes = 42i64.to_le_bytes(); - unsafe { - host_bindings_loose::trace_loose( - locator.as_ptr() as i32 + 1_000_000_000, - locator.len() as i32, - TraceDataType::Int64 as i32, - num_bytes.as_ptr() as i32, - num_bytes.len() as i32, - ) - }; - - // ######################################## - // Step #4: Test other host function edge cases - // ######################################## - - // invalid SFields - - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::tx_field(2, ptr, len) }, - error_codes::INVALID_FIELD, - "tx_field_invalid_sfield", - ); - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::home_le_field(2, ptr, len) }, - error_codes::INVALID_FIELD, - "home_le_field_invalid_sfield", - ); - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::le_field(1, 2, ptr, len) }, - error_codes::INVALID_FIELD, - "le_field_invalid_sfield", - ); - }); - check_result( - unsafe { host::tx_arr_len(2) }, - error_codes::INVALID_FIELD, - "tx_arr_len_invalid_sfield", - ); - check_result( - unsafe { host::home_le_arr_len(2) }, - error_codes::INVALID_FIELD, - "home_le_arr_len_invalid_sfield", - ); - check_result( - unsafe { host::le_arr_len(1, 2) }, - error_codes::INVALID_FIELD, - "le_arr_len_invalid_sfield", - ); - - // invalid Slice - - check_result( - unsafe { host::amendment_enabled(amendment_name.as_ptr(), long_len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "amendment_enabled_too_big_slice", - ); - check_result( - unsafe { host::amendment_enabled(amendment_name.as_ptr(), 65) }, - error_codes::DATA_FIELD_TOO_LARGE, - "amendment_enabled_too_long", - ); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::tx_inner(locator.as_ptr(), long_len, ptr, len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "tx_inner_too_big_slice", - ); - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::home_le_inner(locator.as_ptr(), long_len, ptr, len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "home_le_inner_too_big_slice", - ); - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::le_inner(1, locator.as_ptr(), long_len, ptr, len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "le_inner_too_big_slice", - ); - }); - check_result( - unsafe { host::tx_inner_arr_len(locator.as_ptr(), long_len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "tx_inner_arr_len_too_big_slice", - ); - check_result( - unsafe { host::home_le_inner_arr_len(locator.as_ptr(), long_len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "home_le_inner_arr_len_too_big_slice", - ); - check_result( - unsafe { host::le_inner_arr_len(1, locator.as_ptr(), long_len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "le_inner_arr_len_too_big_slice", - ); - let too_big_data_len = XRPL_CONTRACT_DATA_SIZE + 1; - check_result( - unsafe { host::set_data(locator.as_ptr(), too_big_data_len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "set_data_too_big_slice", - ); - check_result( - unsafe { - host::check_sig( - message.as_ptr(), - long_len, - pubkey.as_ptr(), - pubkey.len(), - signature.as_ptr(), - signature.len(), - ) - }, - error_codes::DATA_FIELD_TOO_LARGE, - "check_sig", - ); - check_result( - unsafe { - host::check_sig( - message.as_ptr(), - message.len(), - pubkey.as_ptr(), - long_len, - signature.as_ptr(), - signature.len(), - ) - }, - error_codes::DATA_FIELD_TOO_LARGE, - "check_sig", - ); - check_result( - unsafe { - host::check_sig( - message.as_ptr(), - message.len(), - pubkey.as_ptr(), - pubkey.len(), - signature.as_ptr(), - long_len, - ) - }, - error_codes::DATA_FIELD_TOO_LARGE, - "check_sig", - ); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::sha512_half(locator.as_ptr(), long_len, ptr, len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "sha512_half_too_big_slice", - ); - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::amm_id( - asset1_bytes.as_ptr(), - long_len, - asset1_bytes.as_ptr(), - asset1_bytes.len(), - ptr, - len, - ) - }, - error_codes::DATA_FIELD_TOO_LARGE, - "amm_id_too_big_slice", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::credential_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), - long_len, - ptr, - len, - ) - }, - error_codes::DATA_FIELD_TOO_LARGE, - "credential_id_too_big_slice", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::mptoken_id( - mptid.as_ptr(), - long_len, - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::DATA_FIELD_TOO_LARGE, - "mptoken_id_too_big_slice_mptid", - ) - }); - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::AsText as i32, - locator.as_ptr().wrapping_add(1_000_000_000), - locator.len(), - ) - }; - let float: [u8; 8] = [0xD4, 0x83, 0x8D, 0x7E, 0xA4, 0xC6, 0x80, 0x00]; - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::Xfloat as i32, - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - ) - }; - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::Amount as i32, - locator.as_ptr().wrapping_add(1_000_000_000), - locator.len(), - ) - }; - check_result( - unsafe { - host::float_cmp( - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - float.as_ptr(), - float.len(), - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_cmp_oob_slice1", - ); - check_result( - unsafe { - host::float_cmp( - float.as_ptr(), - float.len(), - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_cmp_oob_slice2", - ); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_add( - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - float.as_ptr(), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_add_oob_slice1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_add( - float.as_ptr(), - float.len(), - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_add_oob_slice2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_sub( - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - float.as_ptr(), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_sub_oob_slice1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_sub( - float.as_ptr(), - float.len(), - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_sub_oob_slice2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_mult( - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - float.as_ptr(), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_mult_oob_slice1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_mult( - float.as_ptr(), - float.len(), - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_mult_oob_slice2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_div( - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - float.as_ptr(), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_div_oob_slice1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_div( - float.as_ptr(), - float.len(), - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_div_oob_slice2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_root( - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - 3, - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_root_oob_slice", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_pow( - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - 3, - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_pow_oob_slice", - ) - }); - - // invalid UInt32 - - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::escrow_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "escrow_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::mpt_issuance_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "mpt_issuance_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::nft_offer_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "nft_offer_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::offer_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "offer_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::oracle_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "oracle_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::paychan_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "paychan_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::permissioned_domain_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "permissioned_domain_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::ticket_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "ticket_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::vault_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "vault_id_wrong_size_uint32", - ) - }); - - // invalid UInt256 - - check_result( - unsafe { host::cache_le(locator.as_ptr(), locator.len(), 0) }, - error_codes::INVALID_PARAMS, - "cache_le_wrong_size_uint256", - ); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::nft_uri( - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), - locator.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "nft_uri_wrong_size_uint256", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::nft_issuer(locator.as_ptr(), locator.len(), ptr, len) }, - error_codes::INVALID_PARAMS, - "nft_issuer_wrong_size_uint256", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::nft_taxon(locator.as_ptr(), locator.len(), ptr, len) }, - error_codes::INVALID_PARAMS, - "nft_taxon_wrong_size_uint256", - ) - }); - check_result( - unsafe { host::nft_flags(locator.as_ptr(), locator.len()) }, - error_codes::INVALID_PARAMS, - "nft_flags_wrong_size_uint256", - ); - check_result( - unsafe { host::nft_xfer_fee(locator.as_ptr(), locator.len()) }, - error_codes::INVALID_PARAMS, - "nft_xfer_fee_wrong_size_uint256", - ); - with_buffer::<4, _, _>(|ptr, len| { - check_result( - unsafe { host::nft_serial(locator.as_ptr(), locator.len(), ptr, len) }, - error_codes::INVALID_PARAMS, - "nft_serial_wrong_size_uint256", - ) - }); - - // invalid AccountID - - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::accountroot_id(locator.as_ptr(), locator.len(), ptr, len) }, - error_codes::INVALID_PARAMS, - "accountroot_id_wrong_size_account_id", - ) - }); - let seq: i32 = 1; - let seq_bytes = seq.to_be_bytes(); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::check_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "check_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::credential_id( - locator.as_ptr(), // invalid AccountID size - locator.len(), - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), // valid slice size - locator.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "credential_id_wrong_size_account_id1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::credential_id( - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), // invalid AccountID size - locator.len(), - locator.as_ptr(), // valid slice size - locator.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "credential_id_wrong_size_account_id2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::delegate_id( - locator.as_ptr(), // invalid AccountID size - locator.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "delegate_id_wrong_size_account_id1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::delegate_id( - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), // invalid AccountID size - locator.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "delegate_id_wrong_size_account_id2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::deposit_preauth_id( - locator.as_ptr(), // invalid AccountID size - locator.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "deposit_preauth_id_wrong_size_account_id1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::deposit_preauth_id( - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), // invalid AccountID size - locator.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "deposit_preauth_id_wrong_size_account_id2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::did_id(locator.as_ptr(), locator.len(), ptr, len) }, - error_codes::INVALID_PARAMS, - "did_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::escrow_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "escrow_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::trustline_id( - locator.as_ptr(), // invalid AccountID size - locator.len(), - account.0.as_ptr(), - account.0.len(), - currency.as_ptr(), - currency.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "trustline_id_wrong_size_account_id1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::trustline_id( - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), // invalid AccountID size - locator.len(), - currency.as_ptr(), - currency.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "trustline_id_wrong_size_account_id2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::mpt_issuance_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "mpt_issuance_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::mptoken_id( - mptid.as_ptr(), - mptid.len(), - locator.as_ptr(), - locator.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "mptoken_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::nft_offer_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "nft_offer_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::offer_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "offer_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::oracle_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "oracle_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::paychan_id( - locator.as_ptr(), // invalid AccountID size - locator.len(), - account.0.as_ptr(), - account.0.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "paychan_id_wrong_size_account_id1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::paychan_id( - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), // invalid AccountID size - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "paychan_id_wrong_size_account_id2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::permissioned_domain_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "permissioned_domain_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::signers_id(locator.as_ptr(), locator.len(), ptr, len) }, - error_codes::INVALID_PARAMS, - "signers_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::ticket_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "ticket_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::vault_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "vault_id_wrong_size_account_id", - ) - }); - let uint256: &[u8] = b"00000000000000000000000000000001"; - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::nft_uri( - locator.as_ptr(), - locator.len(), - uint256.as_ptr(), - uint256.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "nft_uri_wrong_size_account_id", - ) - }); - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::Account as i32, - locator.as_ptr(), - locator.len(), - ) - }; - - // invalid Currency was already tested above - // invalid string - - unsafe { - host::trace( - message.as_ptr().wrapping_add(1_000_000_000), - message.len(), - TraceDataType::AsText as i32, - uint256.as_ptr(), - uint256.len(), - ) - }; - unsafe { - host::trace( - message.as_ptr().wrapping_add(1_000_000_000), - message.len(), - TraceDataType::Xfloat as i32, - float.as_ptr(), - float.len(), - ) - }; - unsafe { - host::trace( - message.as_ptr().wrapping_add(1_000_000_000), - message.len(), - TraceDataType::Account as i32, - account.0.as_ptr(), - account.0.len(), - ) - }; - unsafe { - host::trace( - message.as_ptr().wrapping_add(1_000_000_000), - message.len(), - TraceDataType::Amount as i32, - amount.as_ptr(), - amount.len(), - ) - }; - - // trace too large - - unsafe { - host::trace( - locator.as_ptr(), - locator.len(), - TraceDataType::AsText as i32, - locator.as_ptr(), - long_len, - ) - }; - let too_long_num = 1i64.to_le_bytes(); - unsafe { - host::trace( - locator.as_ptr(), - long_len, - TraceDataType::Int64 as i32, - too_long_num.as_ptr(), - too_long_num.len(), - ) - }; - unsafe { - host::trace( - message.as_ptr(), - long_len, - TraceDataType::Xfloat as i32, - float.as_ptr(), - float.len(), - ) - }; - unsafe { - host::trace( - message.as_ptr(), - long_len, - TraceDataType::Account as i32, - account.0.as_ptr(), - account.0.len(), - ) - }; - unsafe { - host::trace( - message.as_ptr(), - long_len, - TraceDataType::Amount as i32, - amount.as_ptr(), - amount.len(), - ) - }; - - // trace amount errors - - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::Amount as i32, - locator.as_ptr(), - locator.len(), - ) - }; - - // other misc errors - - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::mptoken_id( - locator.as_ptr(), - locator.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "mptoken_id_mptid_wrong_length", - ) - }); - // Unknown data_type: the host logs "invalid arguments" and returns. - unsafe { - host::trace( - message.as_ptr(), - message.len(), - 99, - locator.as_ptr(), - locator.len(), - ) - }; - - // ensure that the Slice index desync issue is fixed - let empty: &[u8] = b""; - unsafe { - host::trace( - empty.as_ptr(), - empty.len(), - TraceDataType::Account as i32, - account.0.as_ptr(), - account.0.len(), - ) - }; - - 1 // <-- If we get here, finish the escrow. -} diff --git a/src/test/app/wasm_fixtures/copyFixtures.py b/src/test/app/wasm_fixtures/copyFixtures.py deleted file mode 100644 index 23d116cbef..0000000000 --- a/src/test/app/wasm_fixtures/copyFixtures.py +++ /dev/null @@ -1,302 +0,0 @@ -# cspell: disable -import os -import re -import shlex -import subprocess -import sys -import tempfile -import zipfile -from difflib import get_close_matches - -OPT = "-Oz" -BASE_PATH = os.path.abspath(os.path.dirname(__file__)) - - -def pascal_case(name): - return "".join(word[:1].upper() + word[1:] for word in re.split(r"[_\W]+", name)) - - -def normalize_name(name): - name = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", name) - return re.sub(r"[^a-z0-9]", "", name.lower()) - - -def fixture_key(name): - name = normalize_name(name).removeprefix("k") - return name.removesuffix("wasmhex").removesuffix("hex") - - -def declared_fixtures(): - h_path = os.path.join(BASE_PATH, "fixtures.h") - with open(h_path, "r", encoding="utf8") as f: - return re.findall( - r"extern std::string const ([A-Za-z_][A-Za-z0-9_]*);", f.read() - ) - - -def find_fixture_name(project_name, suffix): - default = re.sub(r"_([a-z])", lambda m: m.group(1).upper(), project_name) + suffix - k_default = f"k{pascal_case(project_name)}{suffix}" - declarations = declared_fixtures() - normalized = {normalize_name(name): name for name in declarations} - fixture_keys = {fixture_key(name): name for name in declarations} - - for name in (default, k_default): - if normalize_name(name) in normalized: - return normalized[normalize_name(name)] - - project_key = normalize_name(project_name) - matches = [ - name - for key, name in fixture_keys.items() - if key.endswith(project_key) - or key.startswith(project_key) - or project_key.endswith(key) - or project_key.startswith(key) - ] - if len(matches) == 1: - return matches[0] - - close = get_close_matches(project_key, fixture_keys.keys(), n=1, cutoff=0.82) - if close: - return fixture_keys[close[0]] - - return k_default - - -def fixture_cpp_path(fixture_name): - pattern = rf"extern std::string const {fixture_name} =" - for file_name in os.listdir(BASE_PATH): - if not file_name.endswith(".cpp"): - continue - cpp_path = os.path.join(BASE_PATH, file_name) - with open(cpp_path, "r", encoding="utf8") as f: - if re.search(pattern, f.read()): - return cpp_path - return os.path.join(BASE_PATH, "fixtures.cpp") - - -def update_fixture(project_name, wasm, suffix="WasmHex"): - fixture_name = find_fixture_name(project_name, suffix) - print(f"Updating fixture: {fixture_name}") - - cpp_path = fixture_cpp_path(fixture_name) - h_path = os.path.join(BASE_PATH, "fixtures.h") - with open(cpp_path, "r", encoding="utf8") as f: - cpp_content = f.read() - - pattern = rf'extern std::string const {fixture_name} =[ \n]+"[^;]*;' - if re.search(pattern, cpp_content, flags=re.MULTILINE): - updated_cpp_content = re.sub( - pattern, - f'extern std::string const {fixture_name} = "{wasm}";', - cpp_content, - flags=re.MULTILINE, - ) - else: - with open(h_path, "r", encoding="utf8") as f: - h_content = f.read() - updated_h_content = ( - h_content.rstrip() + f"\n\nextern std::string const {fixture_name};\n" - ) - with open(h_path, "w", encoding="utf8") as f: - f.write(updated_h_content) - updated_cpp_content = ( - cpp_content.rstrip() - + f'\n\nextern std::string const {fixture_name} = "{wasm}";\n' - ) - - with open(cpp_path, "w", encoding="utf8") as f: - f.write(updated_cpp_content) - - -def read_wasm_hex(path): - with open(path, "rb") as f: - return f.read().hex() - - -def process_rust(project_name): - project_path = os.path.join(BASE_PATH, project_name) - wasm_location = os.path.join( - project_path, "target", "wasm32v1-none", "release", f"{project_name}.wasm" - ) - try: - subprocess.run( - ["cargo", "build", "--target", "wasm32v1-none", "--release"], - cwd=project_path, - check=True, - ) - subprocess.run( - ["wasm-opt", wasm_location, OPT, "-o", wasm_location], check=True - ) - print(f"WASM file for {project_name} has been built and optimized.") - except FileNotFoundError as e: - print(f"exec error: {e.filename} is required to build Rust fixtures") - sys.exit(1) - except subprocess.CalledProcessError as e: - print(f"exec error: {e}") - sys.exit(1) - - update_fixture(project_name, read_wasm_hex(wasm_location)) - - -def process_c(project_name): - project_path = os.path.join(BASE_PATH, f"{project_name}.c") - wasm_path = os.path.join(BASE_PATH, f"{project_name}.wasm") - cc = os.environ.get("CC") - sysroot = os.environ.get("SYSROOT") - if not cc or not sysroot: - print("exec error: CC and SYSROOT are required to build C fixtures") - sys.exit(1) - - build_cmd = [ - *shlex.split(cc), - f"--sysroot={sysroot}", - "-O3", - "-ffast-math", - "--target=wasm32", - "-fno-exceptions", - "-fno-threadsafe-statics", - "-fvisibility=default", - "-Wl,--export-all", - "-Wl,--no-entry", - "-Wl,--allow-undefined", - "-DNDEBUG", - "--no-standard-libraries", - "-fno-builtin-memset", - "-o", - wasm_path, - project_path, - ] - try: - subprocess.run(build_cmd, check=True) - subprocess.run(["wasm-opt", wasm_path, OPT, "-o", wasm_path], check=True) - print( - f"WASM file for {project_name} has been built with WASI support using clang." - ) - except FileNotFoundError as e: - print(f"exec error: {e.filename} is required to build C fixtures") - sys.exit(1) - except subprocess.CalledProcessError as e: - print(f"exec error: {e}") - sys.exit(1) - - update_fixture(project_name, read_wasm_hex(wasm_path)) - - -def wat_to_wasm(wat_path, wasm_path): - build_cmd = ["wat2wasm", "--enable-all", wat_path, "-o", wasm_path] - try: - subprocess.run(build_cmd, check=True) - print(f"WASM file for {os.path.basename(wat_path)} has been built.") - return - except FileNotFoundError: - print("exec error: wat2wasm is required to build WAT fixtures") - sys.exit(1) - except subprocess.CalledProcessError: - # wat2wasm (wabt) does not support some proposal text syntax such as - # the GC instructions, so fall back to wasm-tools which does. - pass - - fallback_cmd = ["wasm-tools", "parse", wat_path, "-o", wasm_path] - try: - subprocess.run(fallback_cmd, check=True) - print( - f"WASM file for {os.path.basename(wat_path)} has been built with wasm-tools." - ) - except FileNotFoundError: - print("exec error: wasm-tools is required to build this WAT fixture") - sys.exit(1) - except subprocess.CalledProcessError as e: - print(f"exec error: {e}") - sys.exit(1) - - -def process_wat_file(wat_path): - project_name = os.path.splitext(os.path.basename(wat_path))[0] - with open(wat_path, "r", encoding="utf8") as f: - if "(module" not in f.read(): - print(f"Skipping WAT fixture without a module: {project_name}") - return - - with tempfile.TemporaryDirectory() as tmpdir: - wasm_path = os.path.join(tmpdir, f"{project_name}.wasm") - wat_to_wasm(wat_path, wasm_path) - update_fixture(project_name, read_wasm_hex(wasm_path), "Hex") - - -def process_wat_zip(zip_path): - project_name = os.path.splitext(os.path.basename(zip_path))[0] - with tempfile.TemporaryDirectory() as tmpdir: - with zipfile.ZipFile(zip_path) as archive: - wat_names = [name for name in archive.namelist() if name.endswith(".wat")] - if len(wat_names) != 1: - print(f"exec error: expected one .wat file in {zip_path}") - sys.exit(1) - archive.extract(wat_names[0], tmpdir) - - wasm_path = os.path.join(tmpdir, f"{project_name}.wasm") - wat_to_wasm(os.path.join(tmpdir, wat_names[0]), wasm_path) - update_fixture(project_name, read_wasm_hex(wasm_path), "Hex") - - -def process_wat(project_name): - candidates = [ - os.path.join(BASE_PATH, f"{project_name}.wat"), - os.path.join(BASE_PATH, "wat", f"{project_name}.wat"), - os.path.join(BASE_PATH, "wat", f"{project_name}.zip"), - ] - for path in candidates: - if os.path.isfile(path): - if path.endswith(".zip"): - process_wat_zip(path) - else: - process_wat_file(path) - return - - print(f"exec error: fixture {project_name} not found") - sys.exit(1) - - -if __name__ == "__main__": - if len(sys.argv) > 2: - print("Usage: python copyFixtures.py []") - sys.exit(1) - - if len(sys.argv) == 2: - project_name = os.path.splitext(os.path.basename(sys.argv[1]))[0] - if os.path.isfile(os.path.join(BASE_PATH, project_name, "Cargo.toml")): - process_rust(project_name) - elif os.path.isfile(os.path.join(BASE_PATH, f"{project_name}.c")): - process_c(project_name) - else: - process_wat(project_name) - print("Fixture has been processed.") - else: - dirs = [ - d - for d in os.listdir(BASE_PATH) - if os.path.isfile(os.path.join(BASE_PATH, d, "Cargo.toml")) - ] - c_files = [f for f in os.listdir(BASE_PATH) if f.endswith(".c")] - wat_files = [f for f in os.listdir(BASE_PATH) if f.endswith(".wat")] - wat_path = os.path.join(BASE_PATH, "wat") - wat_fixture_files = [ - f - for f in (os.listdir(wat_path) if os.path.isdir(wat_path) else []) - if f.endswith((".wat", ".zip")) - ] - - for d in sorted(dirs): - process_rust(d) - for c in sorted(c_files): - process_c(c[:-2]) - for wat in sorted(wat_files): - process_wat_file(os.path.join(BASE_PATH, wat)) - for wat_fixture in sorted(wat_fixture_files): - path = os.path.join(wat_path, wat_fixture) - if wat_fixture.endswith(".zip"): - process_wat_zip(path) - else: - process_wat_file(path) - print("All fixtures have been processed.") diff --git a/src/test/app/wasm_fixtures/disableFloat.wat b/src/test/app/wasm_fixtures/disableFloat.wat deleted file mode 100644 index 5e09371ee9..0000000000 --- a/src/test/app/wasm_fixtures/disableFloat.wat +++ /dev/null @@ -1,34 +0,0 @@ -(module - (type (;0;) (func)) - (type (;1;) (func (result i32))) - (func (;0;) (type 0)) - (func (;1;) (type 1) (result i32) - f32.const -2048 - f32.const 2050 - f32.sub - drop - i32.const 1) - (memory (;0;) 2) - (global (;0;) i32 (i32.const 1024)) - (global (;1;) i32 (i32.const 1024)) - (global (;2;) i32 (i32.const 2048)) - (global (;3;) i32 (i32.const 2048)) - (global (;4;) i32 (i32.const 67584)) - (global (;5;) i32 (i32.const 1024)) - (global (;6;) i32 (i32.const 67584)) - (global (;7;) i32 (i32.const 131072)) - (global (;8;) i32 (i32.const 0)) - (global (;9;) i32 (i32.const 1)) - (export "memory" (memory 0)) - (export "__wasm_call_ctors" (func 0)) - (export "escrow_finish" (func 1)) - (export "buf" (global 0)) - (export "__dso_handle" (global 1)) - (export "__data_end" (global 2)) - (export "__stack_low" (global 3)) - (export "__stack_high" (global 4)) - (export "__global_base" (global 5)) - (export "__heap_base" (global 6)) - (export "__heap_end" (global 7)) - (export "__memory_base" (global 8)) - (export "__table_base" (global 9))) diff --git a/src/test/app/wasm_fixtures/fib.c b/src/test/app/wasm_fixtures/fib.c deleted file mode 100644 index e45cc4fe6c..0000000000 --- a/src/test/app/wasm_fixtures/fib.c +++ /dev/null @@ -1,11 +0,0 @@ -// typedef long long mint; -typedef int mint; - -mint fib(mint n) -{ - if (!n) - return 0; - if (n <= 2) - return 1; - return fib(n - 1) + fib(n - 2); -} diff --git a/src/test/app/wasm_fixtures/fixture_functions_5k.cpp b/src/test/app/wasm_fixtures/fixture_functions_5k.cpp deleted file mode 100644 index d65f602eec..0000000000 --- a/src/test/app/wasm_fixtures/fixture_functions_5k.cpp +++ /dev/null @@ -1,2240 +0,0 @@ -// TODO: consider moving these to separate files (and figure out the build) - -#include - -#include - -extern std::string const kFunctions5kHex = - "0061736d0100000001070160027f7f017f038a27882700000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000000000000000000007e2d303882708" - "7465737430303030000008746573743030303100010874657374303030320002087465737430303033000308746573" - "7430303034000408746573743030303500050874657374303030360006087465737430303037000708746573743030" - "303800080874657374303030390009087465737430303130000a087465737430303131000b08746573743030313200" - "0c087465737430303133000d087465737430303134000e087465737430303135000f08746573743030313600100874" - "6573743030313700110874657374303031380012087465737430303139001308746573743030323000140874657374" - "3030323100150874657374303032320016087465737430303233001708746573743030323400180874657374303032" - "350019087465737430303236001a087465737430303237001b087465737430303238001c087465737430303239001d" - "087465737430303330001e087465737430303331001f08746573743030333200200874657374303033330021087465" - "7374303033340022087465737430303335002308746573743030333600240874657374303033370025087465737430" - "3033380026087465737430303339002708746573743030343000280874657374303034310029087465737430303432" - "002a087465737430303433002b087465737430303434002c087465737430303435002d087465737430303436002e08" - "7465737430303437002f08746573743030343800300874657374303034390031087465737430303530003208746573" - "7430303531003308746573743030353200340874657374303035330035087465737430303534003608746573743030" - "3535003708746573743030353600380874657374303035370039087465737430303538003a08746573743030353900" - "3b087465737430303630003c087465737430303631003d087465737430303632003e087465737430303633003f0874" - "6573743030363400400874657374303036350041087465737430303636004208746573743030363700430874657374" - "3030363800440874657374303036390045087465737430303730004608746573743030373100470874657374303037" - "3200480874657374303037330049087465737430303734004a087465737430303735004b087465737430303736004c" - "087465737430303737004d087465737430303738004e087465737430303739004f0874657374303038300050087465" - "7374303038310051087465737430303832005208746573743030383300530874657374303038340054087465737430" - "3038350055087465737430303836005608746573743030383700570874657374303038380058087465737430303839" - "0059087465737430303930005a087465737430303931005b087465737430303932005c087465737430303933005d08" - "7465737430303934005e087465737430303935005f0874657374303039360060087465737430303937006108746573" - "7430303938006208746573743030393900630874657374303130300064087465737430313031006508746573743031" - "3032006608746573743031303300670874657374303130340068087465737430313035006908746573743031303600" - "6a087465737430313037006b087465737430313038006c087465737430313039006d087465737430313130006e0874" - "65737430313131006f0874657374303131320070087465737430313133007108746573743031313400720874657374" - "3031313500730874657374303131360074087465737430313137007508746573743031313800760874657374303131" - "39007708746573743031323000780874657374303132310079087465737430313232007a087465737430313233007b" - "087465737430313234007c087465737430313235007d087465737430313236007e087465737430313237007f087465" - "7374303132380080010874657374303132390081010874657374303133300082010874657374303133310083010874" - "6573743031333200840108746573743031333300850108746573743031333400860108746573743031333500870108" - "7465737430313336008801087465737430313337008901087465737430313338008a01087465737430313339008b01" - "087465737430313430008c01087465737430313431008d01087465737430313432008e01087465737430313433008f" - "0108746573743031343400900108746573743031343500910108746573743031343600920108746573743031343700" - "9301087465737430313438009401087465737430313439009501087465737430313530009601087465737430313531" - "009701087465737430313532009801087465737430313533009901087465737430313534009a010874657374303135" - "35009b01087465737430313536009c01087465737430313537009d01087465737430313538009e0108746573743031" - "3539009f0108746573743031363000a00108746573743031363100a10108746573743031363200a201087465737430" - "31363300a30108746573743031363400a40108746573743031363500a50108746573743031363600a6010874657374" - "3031363700a70108746573743031363800a80108746573743031363900a90108746573743031373000aa0108746573" - "743031373100ab0108746573743031373200ac0108746573743031373300ad0108746573743031373400ae01087465" - "73743031373500af0108746573743031373600b00108746573743031373700b10108746573743031373800b2010874" - "6573743031373900b30108746573743031383000b40108746573743031383100b50108746573743031383200b60108" - "746573743031383300b70108746573743031383400b80108746573743031383500b90108746573743031383600ba01" - "08746573743031383700bb0108746573743031383800bc0108746573743031383900bd0108746573743031393000be" - "0108746573743031393100bf0108746573743031393200c00108746573743031393300c10108746573743031393400" - "c20108746573743031393500c30108746573743031393600c40108746573743031393700c501087465737430313938" - "00c60108746573743031393900c70108746573743032303000c80108746573743032303100c9010874657374303230" - "3200ca0108746573743032303300cb0108746573743032303400cc0108746573743032303500cd0108746573743032" - "303600ce0108746573743032303700cf0108746573743032303800d00108746573743032303900d101087465737430" - "32313000d20108746573743032313100d30108746573743032313200d40108746573743032313300d5010874657374" - "3032313400d60108746573743032313500d70108746573743032313600d80108746573743032313700d90108746573" - "743032313800da0108746573743032313900db0108746573743032323000dc0108746573743032323100dd01087465" - "73743032323200de0108746573743032323300df0108746573743032323400e00108746573743032323500e1010874" - "6573743032323600e20108746573743032323700e30108746573743032323800e40108746573743032323900e50108" - "746573743032333000e60108746573743032333100e70108746573743032333200e80108746573743032333300e901" - "08746573743032333400ea0108746573743032333500eb0108746573743032333600ec0108746573743032333700ed" - "0108746573743032333800ee0108746573743032333900ef0108746573743032343000f00108746573743032343100" - "f10108746573743032343200f20108746573743032343300f30108746573743032343400f401087465737430323435" - "00f50108746573743032343600f60108746573743032343700f70108746573743032343800f8010874657374303234" - "3900f90108746573743032353000fa0108746573743032353100fb0108746573743032353200fc0108746573743032" - "353300fd0108746573743032353400fe0108746573743032353500ff01087465737430323536008002087465737430" - "3235370081020874657374303235380082020874657374303235390083020874657374303236300084020874657374" - "3032363100850208746573743032363200860208746573743032363300870208746573743032363400880208746573" - "7430323635008902087465737430323636008a02087465737430323637008b02087465737430323638008c02087465" - "737430323639008d02087465737430323730008e02087465737430323731008f020874657374303237320090020874" - "6573743032373300910208746573743032373400920208746573743032373500930208746573743032373600940208" - "7465737430323737009502087465737430323738009602087465737430323739009702087465737430323830009802" - "087465737430323831009902087465737430323832009a02087465737430323833009b02087465737430323834009c" - "02087465737430323835009d02087465737430323836009e02087465737430323837009f0208746573743032383800" - "a00208746573743032383900a10208746573743032393000a20208746573743032393100a302087465737430323932" - "00a40208746573743032393300a50208746573743032393400a60208746573743032393500a7020874657374303239" - "3600a80208746573743032393700a90208746573743032393800aa0208746573743032393900ab0208746573743033" - "303000ac0208746573743033303100ad0208746573743033303200ae0208746573743033303300af02087465737430" - "33303400b00208746573743033303500b10208746573743033303600b20208746573743033303700b3020874657374" - "3033303800b40208746573743033303900b50208746573743033313000b60208746573743033313100b70208746573" - "743033313200b80208746573743033313300b90208746573743033313400ba0208746573743033313500bb02087465" - "73743033313600bc0208746573743033313700bd0208746573743033313800be0208746573743033313900bf020874" - "6573743033323000c00208746573743033323100c10208746573743033323200c20208746573743033323300c30208" - "746573743033323400c40208746573743033323500c50208746573743033323600c60208746573743033323700c702" - "08746573743033323800c80208746573743033323900c90208746573743033333000ca0208746573743033333100cb" - "0208746573743033333200cc0208746573743033333300cd0208746573743033333400ce0208746573743033333500" - "cf0208746573743033333600d00208746573743033333700d10208746573743033333800d202087465737430333339" - "00d30208746573743033343000d40208746573743033343100d50208746573743033343200d6020874657374303334" - "3300d70208746573743033343400d80208746573743033343500d90208746573743033343600da0208746573743033" - "343700db0208746573743033343800dc0208746573743033343900dd0208746573743033353000de02087465737430" - "33353100df0208746573743033353200e00208746573743033353300e10208746573743033353400e2020874657374" - "3033353500e30208746573743033353600e40208746573743033353700e50208746573743033353800e60208746573" - "743033353900e70208746573743033363000e80208746573743033363100e90208746573743033363200ea02087465" - "73743033363300eb0208746573743033363400ec0208746573743033363500ed0208746573743033363600ee020874" - "6573743033363700ef0208746573743033363800f00208746573743033363900f10208746573743033373000f20208" - "746573743033373100f30208746573743033373200f40208746573743033373300f50208746573743033373400f602" - "08746573743033373500f70208746573743033373600f80208746573743033373700f90208746573743033373800fa" - "0208746573743033373900fb0208746573743033383000fc0208746573743033383100fd0208746573743033383200" - "fe0208746573743033383300ff02087465737430333834008003087465737430333835008103087465737430333836" - "0082030874657374303338370083030874657374303338380084030874657374303338390085030874657374303339" - "3000860308746573743033393100870308746573743033393200880308746573743033393300890308746573743033" - "3934008a03087465737430333935008b03087465737430333936008c03087465737430333937008d03087465737430" - "333938008e03087465737430333939008f030874657374303430300090030874657374303430310091030874657374" - "3034303200920308746573743034303300930308746573743034303400940308746573743034303500950308746573" - "7430343036009603087465737430343037009703087465737430343038009803087465737430343039009903087465" - "737430343130009a03087465737430343131009b03087465737430343132009c03087465737430343133009d030874" - "65737430343134009e03087465737430343135009f0308746573743034313600a00308746573743034313700a10308" - "746573743034313800a20308746573743034313900a30308746573743034323000a40308746573743034323100a503" - "08746573743034323200a60308746573743034323300a70308746573743034323400a80308746573743034323500a9" - "0308746573743034323600aa0308746573743034323700ab0308746573743034323800ac0308746573743034323900" - "ad0308746573743034333000ae0308746573743034333100af0308746573743034333200b003087465737430343333" - "00b10308746573743034333400b20308746573743034333500b30308746573743034333600b4030874657374303433" - "3700b50308746573743034333800b60308746573743034333900b70308746573743034343000b80308746573743034" - "343100b90308746573743034343200ba0308746573743034343300bb0308746573743034343400bc03087465737430" - "34343500bd0308746573743034343600be0308746573743034343700bf0308746573743034343800c0030874657374" - "3034343900c10308746573743034353000c20308746573743034353100c30308746573743034353200c40308746573" - "743034353300c50308746573743034353400c60308746573743034353500c70308746573743034353600c803087465" - "73743034353700c90308746573743034353800ca0308746573743034353900cb0308746573743034363000cc030874" - "6573743034363100cd0308746573743034363200ce0308746573743034363300cf0308746573743034363400d00308" - "746573743034363500d10308746573743034363600d20308746573743034363700d30308746573743034363800d403" - "08746573743034363900d50308746573743034373000d60308746573743034373100d70308746573743034373200d8" - "0308746573743034373300d90308746573743034373400da0308746573743034373500db0308746573743034373600" - "dc0308746573743034373700dd0308746573743034373800de0308746573743034373900df03087465737430343830" - "00e00308746573743034383100e10308746573743034383200e20308746573743034383300e3030874657374303438" - "3400e40308746573743034383500e50308746573743034383600e60308746573743034383700e70308746573743034" - "383800e80308746573743034383900e90308746573743034393000ea0308746573743034393100eb03087465737430" - "34393200ec0308746573743034393300ed0308746573743034393400ee0308746573743034393500ef030874657374" - "3034393600f00308746573743034393700f10308746573743034393800f20308746573743034393900f30308746573" - "743035303000f40308746573743035303100f50308746573743035303200f60308746573743035303300f703087465" - "73743035303400f80308746573743035303500f90308746573743035303600fa0308746573743035303700fb030874" - "6573743035303800fc0308746573743035303900fd0308746573743035313000fe0308746573743035313100ff0308" - "7465737430353132008004087465737430353133008104087465737430353134008204087465737430353135008304" - "0874657374303531360084040874657374303531370085040874657374303531380086040874657374303531390087" - "04087465737430353230008804087465737430353231008904087465737430353232008a0408746573743035323300" - "8b04087465737430353234008c04087465737430353235008d04087465737430353236008e04087465737430353237" - "008f040874657374303532380090040874657374303532390091040874657374303533300092040874657374303533" - "3100930408746573743035333200940408746573743035333300950408746573743035333400960408746573743035" - "3335009704087465737430353336009804087465737430353337009904087465737430353338009a04087465737430" - "353339009b04087465737430353430009c04087465737430353431009d04087465737430353432009e040874657374" - "30353433009f0408746573743035343400a00408746573743035343500a10408746573743035343600a20408746573" - "743035343700a30408746573743035343800a40408746573743035343900a50408746573743035353000a604087465" - "73743035353100a70408746573743035353200a80408746573743035353300a90408746573743035353400aa040874" - "6573743035353500ab0408746573743035353600ac0408746573743035353700ad0408746573743035353800ae0408" - "746573743035353900af0408746573743035363000b00408746573743035363100b10408746573743035363200b204" - "08746573743035363300b30408746573743035363400b40408746573743035363500b50408746573743035363600b6" - "0408746573743035363700b70408746573743035363800b80408746573743035363900b90408746573743035373000" - "ba0408746573743035373100bb0408746573743035373200bc0408746573743035373300bd04087465737430353734" - "00be0408746573743035373500bf0408746573743035373600c00408746573743035373700c1040874657374303537" - "3800c20408746573743035373900c30408746573743035383000c40408746573743035383100c50408746573743035" - "383200c60408746573743035383300c70408746573743035383400c80408746573743035383500c904087465737430" - "35383600ca0408746573743035383700cb0408746573743035383800cc0408746573743035383900cd040874657374" - "3035393000ce0408746573743035393100cf0408746573743035393200d00408746573743035393300d10408746573" - "743035393400d20408746573743035393500d30408746573743035393600d40408746573743035393700d504087465" - "73743035393800d60408746573743035393900d70408746573743036303000d80408746573743036303100d9040874" - "6573743036303200da0408746573743036303300db0408746573743036303400dc0408746573743036303500dd0408" - "746573743036303600de0408746573743036303700df0408746573743036303800e00408746573743036303900e104" - "08746573743036313000e20408746573743036313100e30408746573743036313200e40408746573743036313300e5" - "0408746573743036313400e60408746573743036313500e70408746573743036313600e80408746573743036313700" - "e90408746573743036313800ea0408746573743036313900eb0408746573743036323000ec04087465737430363231" - "00ed0408746573743036323200ee0408746573743036323300ef0408746573743036323400f0040874657374303632" - "3500f10408746573743036323600f20408746573743036323700f30408746573743036323800f40408746573743036" - "323900f50408746573743036333000f60408746573743036333100f70408746573743036333200f804087465737430" - "36333300f90408746573743036333400fa0408746573743036333500fb0408746573743036333600fc040874657374" - "3036333700fd0408746573743036333800fe0408746573743036333900ff0408746573743036343000800508746573" - "7430363431008105087465737430363432008205087465737430363433008305087465737430363434008405087465" - "7374303634350085050874657374303634360086050874657374303634370087050874657374303634380088050874" - "65737430363439008905087465737430363530008a05087465737430363531008b05087465737430363532008c0508" - "7465737430363533008d05087465737430363534008e05087465737430363535008f05087465737430363536009005" - "0874657374303635370091050874657374303635380092050874657374303635390093050874657374303636300094" - "0508746573743036363100950508746573743036363200960508746573743036363300970508746573743036363400" - "9805087465737430363635009905087465737430363636009a05087465737430363637009b05087465737430363638" - "009c05087465737430363639009d05087465737430363730009e05087465737430363731009f050874657374303637" - "3200a00508746573743036373300a10508746573743036373400a20508746573743036373500a30508746573743036" - "373600a40508746573743036373700a50508746573743036373800a60508746573743036373900a705087465737430" - "36383000a80508746573743036383100a90508746573743036383200aa0508746573743036383300ab050874657374" - "3036383400ac0508746573743036383500ad0508746573743036383600ae0508746573743036383700af0508746573" - "743036383800b00508746573743036383900b10508746573743036393000b20508746573743036393100b305087465" - "73743036393200b40508746573743036393300b50508746573743036393400b60508746573743036393500b7050874" - "6573743036393600b80508746573743036393700b90508746573743036393800ba0508746573743036393900bb0508" - "746573743037303000bc0508746573743037303100bd0508746573743037303200be0508746573743037303300bf05" - "08746573743037303400c00508746573743037303500c10508746573743037303600c20508746573743037303700c3" - "0508746573743037303800c40508746573743037303900c50508746573743037313000c60508746573743037313100" - "c70508746573743037313200c80508746573743037313300c90508746573743037313400ca05087465737430373135" - "00cb0508746573743037313600cc0508746573743037313700cd0508746573743037313800ce050874657374303731" - "3900cf0508746573743037323000d00508746573743037323100d10508746573743037323200d20508746573743037" - "323300d30508746573743037323400d40508746573743037323500d50508746573743037323600d605087465737430" - "37323700d70508746573743037323800d80508746573743037323900d90508746573743037333000da050874657374" - "3037333100db0508746573743037333200dc0508746573743037333300dd0508746573743037333400de0508746573" - "743037333500df0508746573743037333600e00508746573743037333700e10508746573743037333800e205087465" - "73743037333900e30508746573743037343000e40508746573743037343100e50508746573743037343200e6050874" - "6573743037343300e70508746573743037343400e80508746573743037343500e90508746573743037343600ea0508" - "746573743037343700eb0508746573743037343800ec0508746573743037343900ed0508746573743037353000ee05" - "08746573743037353100ef0508746573743037353200f00508746573743037353300f10508746573743037353400f2" - "0508746573743037353500f30508746573743037353600f40508746573743037353700f50508746573743037353800" - "f60508746573743037353900f70508746573743037363000f80508746573743037363100f905087465737430373632" - "00fa0508746573743037363300fb0508746573743037363400fc0508746573743037363500fd050874657374303736" - "3600fe0508746573743037363700ff0508746573743037363800800608746573743037363900810608746573743037" - "3730008206087465737430373731008306087465737430373732008406087465737430373733008506087465737430" - "3737340086060874657374303737350087060874657374303737360088060874657374303737370089060874657374" - "30373738008a06087465737430373739008b06087465737430373830008c06087465737430373831008d0608746573" - "7430373832008e06087465737430373833008f06087465737430373834009006087465737430373835009106087465" - "7374303738360092060874657374303738370093060874657374303738380094060874657374303738390095060874" - "6573743037393000960608746573743037393100970608746573743037393200980608746573743037393300990608" - "7465737430373934009a06087465737430373935009b06087465737430373936009c06087465737430373937009d06" - "087465737430373938009e06087465737430373939009f0608746573743038303000a00608746573743038303100a1" - "0608746573743038303200a20608746573743038303300a30608746573743038303400a40608746573743038303500" - "a50608746573743038303600a60608746573743038303700a70608746573743038303800a806087465737430383039" - "00a90608746573743038313000aa0608746573743038313100ab0608746573743038313200ac060874657374303831" - "3300ad0608746573743038313400ae0608746573743038313500af0608746573743038313600b00608746573743038" - "313700b10608746573743038313800b20608746573743038313900b30608746573743038323000b406087465737430" - "38323100b50608746573743038323200b60608746573743038323300b70608746573743038323400b8060874657374" - "3038323500b90608746573743038323600ba0608746573743038323700bb0608746573743038323800bc0608746573" - "743038323900bd0608746573743038333000be0608746573743038333100bf0608746573743038333200c006087465" - "73743038333300c10608746573743038333400c20608746573743038333500c30608746573743038333600c4060874" - "6573743038333700c50608746573743038333800c60608746573743038333900c70608746573743038343000c80608" - "746573743038343100c90608746573743038343200ca0608746573743038343300cb0608746573743038343400cc06" - "08746573743038343500cd0608746573743038343600ce0608746573743038343700cf0608746573743038343800d0" - "0608746573743038343900d10608746573743038353000d20608746573743038353100d30608746573743038353200" - "d40608746573743038353300d50608746573743038353400d60608746573743038353500d706087465737430383536" - "00d80608746573743038353700d90608746573743038353800da0608746573743038353900db060874657374303836" - "3000dc0608746573743038363100dd0608746573743038363200de0608746573743038363300df0608746573743038" - "363400e00608746573743038363500e10608746573743038363600e20608746573743038363700e306087465737430" - "38363800e40608746573743038363900e50608746573743038373000e60608746573743038373100e7060874657374" - "3038373200e80608746573743038373300e90608746573743038373400ea0608746573743038373500eb0608746573" - "743038373600ec0608746573743038373700ed0608746573743038373800ee0608746573743038373900ef06087465" - "73743038383000f00608746573743038383100f10608746573743038383200f20608746573743038383300f3060874" - "6573743038383400f40608746573743038383500f50608746573743038383600f60608746573743038383700f70608" - "746573743038383800f80608746573743038383900f90608746573743038393000fa0608746573743038393100fb06" - "08746573743038393200fc0608746573743038393300fd0608746573743038393400fe0608746573743038393500ff" - "0608746573743038393600800708746573743038393700810708746573743038393800820708746573743038393900" - "8307087465737430393030008407087465737430393031008507087465737430393032008607087465737430393033" - "008707087465737430393034008807087465737430393035008907087465737430393036008a070874657374303930" - "37008b07087465737430393038008c07087465737430393039008d07087465737430393130008e0708746573743039" - "3131008f07087465737430393132009007087465737430393133009107087465737430393134009207087465737430" - "3931350093070874657374303931360094070874657374303931370095070874657374303931380096070874657374" - "30393139009707087465737430393230009807087465737430393231009907087465737430393232009a0708746573" - "7430393233009b07087465737430393234009c07087465737430393235009d07087465737430393236009e07087465" - "737430393237009f0708746573743039323800a00708746573743039323900a10708746573743039333000a2070874" - "6573743039333100a30708746573743039333200a40708746573743039333300a50708746573743039333400a60708" - "746573743039333500a70708746573743039333600a80708746573743039333700a90708746573743039333800aa07" - "08746573743039333900ab0708746573743039343000ac0708746573743039343100ad0708746573743039343200ae" - "0708746573743039343300af0708746573743039343400b00708746573743039343500b10708746573743039343600" - "b20708746573743039343700b30708746573743039343800b40708746573743039343900b507087465737430393530" - "00b60708746573743039353100b70708746573743039353200b80708746573743039353300b9070874657374303935" - "3400ba0708746573743039353500bb0708746573743039353600bc0708746573743039353700bd0708746573743039" - "353800be0708746573743039353900bf0708746573743039363000c00708746573743039363100c107087465737430" - "39363200c20708746573743039363300c30708746573743039363400c40708746573743039363500c5070874657374" - "3039363600c60708746573743039363700c70708746573743039363800c80708746573743039363900c90708746573" - "743039373000ca0708746573743039373100cb0708746573743039373200cc0708746573743039373300cd07087465" - "73743039373400ce0708746573743039373500cf0708746573743039373600d00708746573743039373700d1070874" - "6573743039373800d20708746573743039373900d30708746573743039383000d40708746573743039383100d50708" - "746573743039383200d60708746573743039383300d70708746573743039383400d80708746573743039383500d907" - "08746573743039383600da0708746573743039383700db0708746573743039383800dc0708746573743039383900dd" - "0708746573743039393000de0708746573743039393100df0708746573743039393200e00708746573743039393300" - "e10708746573743039393400e20708746573743039393500e30708746573743039393600e407087465737430393937" - "00e50708746573743039393800e60708746573743039393900e70708746573743130303000e8070874657374313030" - "3100e90708746573743130303200ea0708746573743130303300eb0708746573743130303400ec0708746573743130" - "303500ed0708746573743130303600ee0708746573743130303700ef0708746573743130303800f007087465737431" - "30303900f10708746573743130313000f20708746573743130313100f30708746573743130313200f4070874657374" - "3130313300f50708746573743130313400f60708746573743130313500f70708746573743130313600f80708746573" - "743130313700f90708746573743130313800fa0708746573743130313900fb0708746573743130323000fc07087465" - "73743130323100fd0708746573743130323200fe0708746573743130323300ff070874657374313032340080080874" - "6573743130323500810808746573743130323600820808746573743130323700830808746573743130323800840808" - "7465737431303239008508087465737431303330008608087465737431303331008708087465737431303332008808" - "087465737431303333008908087465737431303334008a08087465737431303335008b08087465737431303336008c" - "08087465737431303337008d08087465737431303338008e08087465737431303339008f0808746573743130343000" - "9008087465737431303431009108087465737431303432009208087465737431303433009308087465737431303434" - "0094080874657374313034350095080874657374313034360096080874657374313034370097080874657374313034" - "38009808087465737431303439009908087465737431303530009a08087465737431303531009b0808746573743130" - "3532009c08087465737431303533009d08087465737431303534009e08087465737431303535009f08087465737431" - "30353600a00808746573743130353700a10808746573743130353800a20808746573743130353900a3080874657374" - "3130363000a40808746573743130363100a50808746573743130363200a60808746573743130363300a70808746573" - "743130363400a80808746573743130363500a90808746573743130363600aa0808746573743130363700ab08087465" - "73743130363800ac0808746573743130363900ad0808746573743130373000ae0808746573743130373100af080874" - "6573743130373200b00808746573743130373300b10808746573743130373400b20808746573743130373500b30808" - "746573743130373600b40808746573743130373700b50808746573743130373800b60808746573743130373900b708" - "08746573743130383000b80808746573743130383100b90808746573743130383200ba0808746573743130383300bb" - "0808746573743130383400bc0808746573743130383500bd0808746573743130383600be0808746573743130383700" - "bf0808746573743130383800c00808746573743130383900c10808746573743130393000c208087465737431303931" - "00c30808746573743130393200c40808746573743130393300c50808746573743130393400c6080874657374313039" - "3500c70808746573743130393600c80808746573743130393700c90808746573743130393800ca0808746573743130" - "393900cb0808746573743131303000cc0808746573743131303100cd0808746573743131303200ce08087465737431" - "31303300cf0808746573743131303400d00808746573743131303500d10808746573743131303600d2080874657374" - "3131303700d30808746573743131303800d40808746573743131303900d50808746573743131313000d60808746573" - "743131313100d70808746573743131313200d80808746573743131313300d90808746573743131313400da08087465" - "73743131313500db0808746573743131313600dc0808746573743131313700dd0808746573743131313800de080874" - "6573743131313900df0808746573743131323000e00808746573743131323100e10808746573743131323200e20808" - "746573743131323300e30808746573743131323400e40808746573743131323500e50808746573743131323600e608" - "08746573743131323700e70808746573743131323800e80808746573743131323900e90808746573743131333000ea" - "0808746573743131333100eb0808746573743131333200ec0808746573743131333300ed0808746573743131333400" - "ee0808746573743131333500ef0808746573743131333600f00808746573743131333700f108087465737431313338" - "00f20808746573743131333900f30808746573743131343000f40808746573743131343100f5080874657374313134" - "3200f60808746573743131343300f70808746573743131343400f80808746573743131343500f90808746573743131" - "343600fa0808746573743131343700fb0808746573743131343800fc0808746573743131343900fd08087465737431" - "31353000fe0808746573743131353100ff080874657374313135320080090874657374313135330081090874657374" - "3131353400820908746573743131353500830908746573743131353600840908746573743131353700850908746573" - "7431313538008609087465737431313539008709087465737431313630008809087465737431313631008909087465" - "737431313632008a09087465737431313633008b09087465737431313634008c09087465737431313635008d090874" - "65737431313636008e09087465737431313637008f0908746573743131363800900908746573743131363900910908" - "7465737431313730009209087465737431313731009309087465737431313732009409087465737431313733009509" - "0874657374313137340096090874657374313137350097090874657374313137360098090874657374313137370099" - "09087465737431313738009a09087465737431313739009b09087465737431313830009c0908746573743131383100" - "9d09087465737431313832009e09087465737431313833009f0908746573743131383400a009087465737431313835" - "00a10908746573743131383600a20908746573743131383700a30908746573743131383800a4090874657374313138" - "3900a50908746573743131393000a60908746573743131393100a70908746573743131393200a80908746573743131" - "393300a90908746573743131393400aa0908746573743131393500ab0908746573743131393600ac09087465737431" - "31393700ad0908746573743131393800ae0908746573743131393900af0908746573743132303000b0090874657374" - "3132303100b10908746573743132303200b20908746573743132303300b30908746573743132303400b40908746573" - "743132303500b50908746573743132303600b60908746573743132303700b70908746573743132303800b809087465" - "73743132303900b90908746573743132313000ba0908746573743132313100bb0908746573743132313200bc090874" - "6573743132313300bd0908746573743132313400be0908746573743132313500bf0908746573743132313600c00908" - "746573743132313700c10908746573743132313800c20908746573743132313900c30908746573743132323000c409" - "08746573743132323100c50908746573743132323200c60908746573743132323300c70908746573743132323400c8" - "0908746573743132323500c90908746573743132323600ca0908746573743132323700cb0908746573743132323800" - "cc0908746573743132323900cd0908746573743132333000ce0908746573743132333100cf09087465737431323332" - "00d00908746573743132333300d10908746573743132333400d20908746573743132333500d3090874657374313233" - "3600d40908746573743132333700d50908746573743132333800d60908746573743132333900d70908746573743132" - "343000d80908746573743132343100d90908746573743132343200da0908746573743132343300db09087465737431" - "32343400dc0908746573743132343500dd0908746573743132343600de0908746573743132343700df090874657374" - "3132343800e00908746573743132343900e10908746573743132353000e20908746573743132353100e30908746573" - "743132353200e40908746573743132353300e50908746573743132353400e60908746573743132353500e709087465" - "73743132353600e80908746573743132353700e90908746573743132353800ea0908746573743132353900eb090874" - "6573743132363000ec0908746573743132363100ed0908746573743132363200ee0908746573743132363300ef0908" - "746573743132363400f00908746573743132363500f10908746573743132363600f20908746573743132363700f309" - "08746573743132363800f40908746573743132363900f50908746573743132373000f60908746573743132373100f7" - "0908746573743132373200f80908746573743132373300f90908746573743132373400fa0908746573743132373500" - "fb0908746573743132373600fc0908746573743132373700fd0908746573743132373800fe09087465737431323739" - "00ff0908746573743132383000800a08746573743132383100810a08746573743132383200820a0874657374313238" - "3300830a08746573743132383400840a08746573743132383500850a08746573743132383600860a08746573743132" - "383700870a08746573743132383800880a08746573743132383900890a087465737431323930008a0a087465737431" - "323931008b0a087465737431323932008c0a087465737431323933008d0a087465737431323934008e0a0874657374" - "31323935008f0a08746573743132393600900a08746573743132393700910a08746573743132393800920a08746573" - "743132393900930a08746573743133303000940a08746573743133303100950a08746573743133303200960a087465" - "73743133303300970a08746573743133303400980a08746573743133303500990a087465737431333036009a0a0874" - "65737431333037009b0a087465737431333038009c0a087465737431333039009d0a087465737431333130009e0a08" - "7465737431333131009f0a08746573743133313200a00a08746573743133313300a10a08746573743133313400a20a" - "08746573743133313500a30a08746573743133313600a40a08746573743133313700a50a08746573743133313800a6" - "0a08746573743133313900a70a08746573743133323000a80a08746573743133323100a90a08746573743133323200" - "aa0a08746573743133323300ab0a08746573743133323400ac0a08746573743133323500ad0a087465737431333236" - "00ae0a08746573743133323700af0a08746573743133323800b00a08746573743133323900b10a0874657374313333" - "3000b20a08746573743133333100b30a08746573743133333200b40a08746573743133333300b50a08746573743133" - "333400b60a08746573743133333500b70a08746573743133333600b80a08746573743133333700b90a087465737431" - "33333800ba0a08746573743133333900bb0a08746573743133343000bc0a08746573743133343100bd0a0874657374" - "3133343200be0a08746573743133343300bf0a08746573743133343400c00a08746573743133343500c10a08746573" - "743133343600c20a08746573743133343700c30a08746573743133343800c40a08746573743133343900c50a087465" - "73743133353000c60a08746573743133353100c70a08746573743133353200c80a08746573743133353300c90a0874" - "6573743133353400ca0a08746573743133353500cb0a08746573743133353600cc0a08746573743133353700cd0a08" - "746573743133353800ce0a08746573743133353900cf0a08746573743133363000d00a08746573743133363100d10a" - "08746573743133363200d20a08746573743133363300d30a08746573743133363400d40a08746573743133363500d5" - "0a08746573743133363600d60a08746573743133363700d70a08746573743133363800d80a08746573743133363900" - "d90a08746573743133373000da0a08746573743133373100db0a08746573743133373200dc0a087465737431333733" - "00dd0a08746573743133373400de0a08746573743133373500df0a08746573743133373600e00a0874657374313337" - "3700e10a08746573743133373800e20a08746573743133373900e30a08746573743133383000e40a08746573743133" - "383100e50a08746573743133383200e60a08746573743133383300e70a08746573743133383400e80a087465737431" - "33383500e90a08746573743133383600ea0a08746573743133383700eb0a08746573743133383800ec0a0874657374" - "3133383900ed0a08746573743133393000ee0a08746573743133393100ef0a08746573743133393200f00a08746573" - "743133393300f10a08746573743133393400f20a08746573743133393500f30a08746573743133393600f40a087465" - "73743133393700f50a08746573743133393800f60a08746573743133393900f70a08746573743134303000f80a0874" - "6573743134303100f90a08746573743134303200fa0a08746573743134303300fb0a08746573743134303400fc0a08" - "746573743134303500fd0a08746573743134303600fe0a08746573743134303700ff0a08746573743134303800800b" - "08746573743134303900810b08746573743134313000820b08746573743134313100830b0874657374313431320084" - "0b08746573743134313300850b08746573743134313400860b08746573743134313500870b08746573743134313600" - "880b08746573743134313700890b087465737431343138008a0b087465737431343139008b0b087465737431343230" - "008c0b087465737431343231008d0b087465737431343232008e0b087465737431343233008f0b0874657374313432" - "3400900b08746573743134323500910b08746573743134323600920b08746573743134323700930b08746573743134" - "323800940b08746573743134323900950b08746573743134333000960b08746573743134333100970b087465737431" - "34333200980b08746573743134333300990b087465737431343334009a0b087465737431343335009b0b0874657374" - "31343336009c0b087465737431343337009d0b087465737431343338009e0b087465737431343339009f0b08746573" - "743134343000a00b08746573743134343100a10b08746573743134343200a20b08746573743134343300a30b087465" - "73743134343400a40b08746573743134343500a50b08746573743134343600a60b08746573743134343700a70b0874" - "6573743134343800a80b08746573743134343900a90b08746573743134353000aa0b08746573743134353100ab0b08" - "746573743134353200ac0b08746573743134353300ad0b08746573743134353400ae0b08746573743134353500af0b" - "08746573743134353600b00b08746573743134353700b10b08746573743134353800b20b08746573743134353900b3" - "0b08746573743134363000b40b08746573743134363100b50b08746573743134363200b60b08746573743134363300" - "b70b08746573743134363400b80b08746573743134363500b90b08746573743134363600ba0b087465737431343637" - "00bb0b08746573743134363800bc0b08746573743134363900bd0b08746573743134373000be0b0874657374313437" - "3100bf0b08746573743134373200c00b08746573743134373300c10b08746573743134373400c20b08746573743134" - "373500c30b08746573743134373600c40b08746573743134373700c50b08746573743134373800c60b087465737431" - "34373900c70b08746573743134383000c80b08746573743134383100c90b08746573743134383200ca0b0874657374" - "3134383300cb0b08746573743134383400cc0b08746573743134383500cd0b08746573743134383600ce0b08746573" - "743134383700cf0b08746573743134383800d00b08746573743134383900d10b08746573743134393000d20b087465" - "73743134393100d30b08746573743134393200d40b08746573743134393300d50b08746573743134393400d60b0874" - "6573743134393500d70b08746573743134393600d80b08746573743134393700d90b08746573743134393800da0b08" - "746573743134393900db0b08746573743135303000dc0b08746573743135303100dd0b08746573743135303200de0b" - "08746573743135303300df0b08746573743135303400e00b08746573743135303500e10b08746573743135303600e2" - "0b08746573743135303700e30b08746573743135303800e40b08746573743135303900e50b08746573743135313000" - "e60b08746573743135313100e70b08746573743135313200e80b08746573743135313300e90b087465737431353134" - "00ea0b08746573743135313500eb0b08746573743135313600ec0b08746573743135313700ed0b0874657374313531" - "3800ee0b08746573743135313900ef0b08746573743135323000f00b08746573743135323100f10b08746573743135" - "323200f20b08746573743135323300f30b08746573743135323400f40b08746573743135323500f50b087465737431" - "35323600f60b08746573743135323700f70b08746573743135323800f80b08746573743135323900f90b0874657374" - "3135333000fa0b08746573743135333100fb0b08746573743135333200fc0b08746573743135333300fd0b08746573" - "743135333400fe0b08746573743135333500ff0b08746573743135333600800c08746573743135333700810c087465" - "73743135333800820c08746573743135333900830c08746573743135343000840c08746573743135343100850c0874" - "6573743135343200860c08746573743135343300870c08746573743135343400880c08746573743135343500890c08" - "7465737431353436008a0c087465737431353437008b0c087465737431353438008c0c087465737431353439008d0c" - "087465737431353530008e0c087465737431353531008f0c08746573743135353200900c0874657374313535330091" - "0c08746573743135353400920c08746573743135353500930c08746573743135353600940c08746573743135353700" - "950c08746573743135353800960c08746573743135353900970c08746573743135363000980c087465737431353631" - "00990c087465737431353632009a0c087465737431353633009b0c087465737431353634009c0c0874657374313536" - "35009d0c087465737431353636009e0c087465737431353637009f0c08746573743135363800a00c08746573743135" - "363900a10c08746573743135373000a20c08746573743135373100a30c08746573743135373200a40c087465737431" - "35373300a50c08746573743135373400a60c08746573743135373500a70c08746573743135373600a80c0874657374" - "3135373700a90c08746573743135373800aa0c08746573743135373900ab0c08746573743135383000ac0c08746573" - "743135383100ad0c08746573743135383200ae0c08746573743135383300af0c08746573743135383400b00c087465" - "73743135383500b10c08746573743135383600b20c08746573743135383700b30c08746573743135383800b40c0874" - "6573743135383900b50c08746573743135393000b60c08746573743135393100b70c08746573743135393200b80c08" - "746573743135393300b90c08746573743135393400ba0c08746573743135393500bb0c08746573743135393600bc0c" - "08746573743135393700bd0c08746573743135393800be0c08746573743135393900bf0c08746573743136303000c0" - "0c08746573743136303100c10c08746573743136303200c20c08746573743136303300c30c08746573743136303400" - "c40c08746573743136303500c50c08746573743136303600c60c08746573743136303700c70c087465737431363038" - "00c80c08746573743136303900c90c08746573743136313000ca0c08746573743136313100cb0c0874657374313631" - "3200cc0c08746573743136313300cd0c08746573743136313400ce0c08746573743136313500cf0c08746573743136" - "313600d00c08746573743136313700d10c08746573743136313800d20c08746573743136313900d30c087465737431" - "36323000d40c08746573743136323100d50c08746573743136323200d60c08746573743136323300d70c0874657374" - "3136323400d80c08746573743136323500d90c08746573743136323600da0c08746573743136323700db0c08746573" - "743136323800dc0c08746573743136323900dd0c08746573743136333000de0c08746573743136333100df0c087465" - "73743136333200e00c08746573743136333300e10c08746573743136333400e20c08746573743136333500e30c0874" - "6573743136333600e40c08746573743136333700e50c08746573743136333800e60c08746573743136333900e70c08" - "746573743136343000e80c08746573743136343100e90c08746573743136343200ea0c08746573743136343300eb0c" - "08746573743136343400ec0c08746573743136343500ed0c08746573743136343600ee0c08746573743136343700ef" - "0c08746573743136343800f00c08746573743136343900f10c08746573743136353000f20c08746573743136353100" - "f30c08746573743136353200f40c08746573743136353300f50c08746573743136353400f60c087465737431363535" - "00f70c08746573743136353600f80c08746573743136353700f90c08746573743136353800fa0c0874657374313635" - "3900fb0c08746573743136363000fc0c08746573743136363100fd0c08746573743136363200fe0c08746573743136" - "363300ff0c08746573743136363400800d08746573743136363500810d08746573743136363600820d087465737431" - "36363700830d08746573743136363800840d08746573743136363900850d08746573743136373000860d0874657374" - "3136373100870d08746573743136373200880d08746573743136373300890d087465737431363734008a0d08746573" - "7431363735008b0d087465737431363736008c0d087465737431363737008d0d087465737431363738008e0d087465" - "737431363739008f0d08746573743136383000900d08746573743136383100910d08746573743136383200920d0874" - "6573743136383300930d08746573743136383400940d08746573743136383500950d08746573743136383600960d08" - "746573743136383700970d08746573743136383800980d08746573743136383900990d087465737431363930009a0d" - "087465737431363931009b0d087465737431363932009c0d087465737431363933009d0d087465737431363934009e" - "0d087465737431363935009f0d08746573743136393600a00d08746573743136393700a10d08746573743136393800" - "a20d08746573743136393900a30d08746573743137303000a40d08746573743137303100a50d087465737431373032" - "00a60d08746573743137303300a70d08746573743137303400a80d08746573743137303500a90d0874657374313730" - "3600aa0d08746573743137303700ab0d08746573743137303800ac0d08746573743137303900ad0d08746573743137" - "313000ae0d08746573743137313100af0d08746573743137313200b00d08746573743137313300b10d087465737431" - "37313400b20d08746573743137313500b30d08746573743137313600b40d08746573743137313700b50d0874657374" - "3137313800b60d08746573743137313900b70d08746573743137323000b80d08746573743137323100b90d08746573" - "743137323200ba0d08746573743137323300bb0d08746573743137323400bc0d08746573743137323500bd0d087465" - "73743137323600be0d08746573743137323700bf0d08746573743137323800c00d08746573743137323900c10d0874" - "6573743137333000c20d08746573743137333100c30d08746573743137333200c40d08746573743137333300c50d08" - "746573743137333400c60d08746573743137333500c70d08746573743137333600c80d08746573743137333700c90d" - "08746573743137333800ca0d08746573743137333900cb0d08746573743137343000cc0d08746573743137343100cd" - "0d08746573743137343200ce0d08746573743137343300cf0d08746573743137343400d00d08746573743137343500" - "d10d08746573743137343600d20d08746573743137343700d30d08746573743137343800d40d087465737431373439" - "00d50d08746573743137353000d60d08746573743137353100d70d08746573743137353200d80d0874657374313735" - "3300d90d08746573743137353400da0d08746573743137353500db0d08746573743137353600dc0d08746573743137" - "353700dd0d08746573743137353800de0d08746573743137353900df0d08746573743137363000e00d087465737431" - "37363100e10d08746573743137363200e20d08746573743137363300e30d08746573743137363400e40d0874657374" - "3137363500e50d08746573743137363600e60d08746573743137363700e70d08746573743137363800e80d08746573" - "743137363900e90d08746573743137373000ea0d08746573743137373100eb0d08746573743137373200ec0d087465" - "73743137373300ed0d08746573743137373400ee0d08746573743137373500ef0d08746573743137373600f00d0874" - "6573743137373700f10d08746573743137373800f20d08746573743137373900f30d08746573743137383000f40d08" - "746573743137383100f50d08746573743137383200f60d08746573743137383300f70d08746573743137383400f80d" - "08746573743137383500f90d08746573743137383600fa0d08746573743137383700fb0d08746573743137383800fc" - "0d08746573743137383900fd0d08746573743137393000fe0d08746573743137393100ff0d08746573743137393200" - "800e08746573743137393300810e08746573743137393400820e08746573743137393500830e087465737431373936" - "00840e08746573743137393700850e08746573743137393800860e08746573743137393900870e0874657374313830" - "3000880e08746573743138303100890e087465737431383032008a0e087465737431383033008b0e08746573743138" - "3034008c0e087465737431383035008d0e087465737431383036008e0e087465737431383037008f0e087465737431" - "38303800900e08746573743138303900910e08746573743138313000920e08746573743138313100930e0874657374" - "3138313200940e08746573743138313300950e08746573743138313400960e08746573743138313500970e08746573" - "743138313600980e08746573743138313700990e087465737431383138009a0e087465737431383139009b0e087465" - "737431383230009c0e087465737431383231009d0e087465737431383232009e0e087465737431383233009f0e0874" - "6573743138323400a00e08746573743138323500a10e08746573743138323600a20e08746573743138323700a30e08" - "746573743138323800a40e08746573743138323900a50e08746573743138333000a60e08746573743138333100a70e" - "08746573743138333200a80e08746573743138333300a90e08746573743138333400aa0e08746573743138333500ab" - "0e08746573743138333600ac0e08746573743138333700ad0e08746573743138333800ae0e08746573743138333900" - "af0e08746573743138343000b00e08746573743138343100b10e08746573743138343200b20e087465737431383433" - "00b30e08746573743138343400b40e08746573743138343500b50e08746573743138343600b60e0874657374313834" - "3700b70e08746573743138343800b80e08746573743138343900b90e08746573743138353000ba0e08746573743138" - "353100bb0e08746573743138353200bc0e08746573743138353300bd0e08746573743138353400be0e087465737431" - "38353500bf0e08746573743138353600c00e08746573743138353700c10e08746573743138353800c20e0874657374" - "3138353900c30e08746573743138363000c40e08746573743138363100c50e08746573743138363200c60e08746573" - "743138363300c70e08746573743138363400c80e08746573743138363500c90e08746573743138363600ca0e087465" - "73743138363700cb0e08746573743138363800cc0e08746573743138363900cd0e08746573743138373000ce0e0874" - "6573743138373100cf0e08746573743138373200d00e08746573743138373300d10e08746573743138373400d20e08" - "746573743138373500d30e08746573743138373600d40e08746573743138373700d50e08746573743138373800d60e" - "08746573743138373900d70e08746573743138383000d80e08746573743138383100d90e08746573743138383200da" - "0e08746573743138383300db0e08746573743138383400dc0e08746573743138383500dd0e08746573743138383600" - "de0e08746573743138383700df0e08746573743138383800e00e08746573743138383900e10e087465737431383930" - "00e20e08746573743138393100e30e08746573743138393200e40e08746573743138393300e50e0874657374313839" - "3400e60e08746573743138393500e70e08746573743138393600e80e08746573743138393700e90e08746573743138" - "393800ea0e08746573743138393900eb0e08746573743139303000ec0e08746573743139303100ed0e087465737431" - "39303200ee0e08746573743139303300ef0e08746573743139303400f00e08746573743139303500f10e0874657374" - "3139303600f20e08746573743139303700f30e08746573743139303800f40e08746573743139303900f50e08746573" - "743139313000f60e08746573743139313100f70e08746573743139313200f80e08746573743139313300f90e087465" - "73743139313400fa0e08746573743139313500fb0e08746573743139313600fc0e08746573743139313700fd0e0874" - "6573743139313800fe0e08746573743139313900ff0e08746573743139323000800f08746573743139323100810f08" - "746573743139323200820f08746573743139323300830f08746573743139323400840f08746573743139323500850f" - "08746573743139323600860f08746573743139323700870f08746573743139323800880f0874657374313932390089" - "0f087465737431393330008a0f087465737431393331008b0f087465737431393332008c0f08746573743139333300" - "8d0f087465737431393334008e0f087465737431393335008f0f08746573743139333600900f087465737431393337" - "00910f08746573743139333800920f08746573743139333900930f08746573743139343000940f0874657374313934" - "3100950f08746573743139343200960f08746573743139343300970f08746573743139343400980f08746573743139" - "343500990f087465737431393436009a0f087465737431393437009b0f087465737431393438009c0f087465737431" - "393439009d0f087465737431393530009e0f087465737431393531009f0f08746573743139353200a00f0874657374" - "3139353300a10f08746573743139353400a20f08746573743139353500a30f08746573743139353600a40f08746573" - "743139353700a50f08746573743139353800a60f08746573743139353900a70f08746573743139363000a80f087465" - "73743139363100a90f08746573743139363200aa0f08746573743139363300ab0f08746573743139363400ac0f0874" - "6573743139363500ad0f08746573743139363600ae0f08746573743139363700af0f08746573743139363800b00f08" - "746573743139363900b10f08746573743139373000b20f08746573743139373100b30f08746573743139373200b40f" - "08746573743139373300b50f08746573743139373400b60f08746573743139373500b70f08746573743139373600b8" - "0f08746573743139373700b90f08746573743139373800ba0f08746573743139373900bb0f08746573743139383000" - "bc0f08746573743139383100bd0f08746573743139383200be0f08746573743139383300bf0f087465737431393834" - "00c00f08746573743139383500c10f08746573743139383600c20f08746573743139383700c30f0874657374313938" - "3800c40f08746573743139383900c50f08746573743139393000c60f08746573743139393100c70f08746573743139" - "393200c80f08746573743139393300c90f08746573743139393400ca0f08746573743139393500cb0f087465737431" - "39393600cc0f08746573743139393700cd0f08746573743139393800ce0f08746573743139393900cf0f0874657374" - "3230303000d00f08746573743230303100d10f08746573743230303200d20f08746573743230303300d30f08746573" - "743230303400d40f08746573743230303500d50f08746573743230303600d60f08746573743230303700d70f087465" - "73743230303800d80f08746573743230303900d90f08746573743230313000da0f08746573743230313100db0f0874" - "6573743230313200dc0f08746573743230313300dd0f08746573743230313400de0f08746573743230313500df0f08" - "746573743230313600e00f08746573743230313700e10f08746573743230313800e20f08746573743230313900e30f" - "08746573743230323000e40f08746573743230323100e50f08746573743230323200e60f08746573743230323300e7" - "0f08746573743230323400e80f08746573743230323500e90f08746573743230323600ea0f08746573743230323700" - "eb0f08746573743230323800ec0f08746573743230323900ed0f08746573743230333000ee0f087465737432303331" - "00ef0f08746573743230333200f00f08746573743230333300f10f08746573743230333400f20f0874657374323033" - "3500f30f08746573743230333600f40f08746573743230333700f50f08746573743230333800f60f08746573743230" - "333900f70f08746573743230343000f80f08746573743230343100f90f08746573743230343200fa0f087465737432" - "30343300fb0f08746573743230343400fc0f08746573743230343500fd0f08746573743230343600fe0f0874657374" - "3230343700ff0f08746573743230343800801008746573743230343900811008746573743230353000821008746573" - "7432303531008310087465737432303532008410087465737432303533008510087465737432303534008610087465" - "737432303535008710087465737432303536008810087465737432303537008910087465737432303538008a100874" - "65737432303539008b10087465737432303630008c10087465737432303631008d10087465737432303632008e1008" - "7465737432303633008f10087465737432303634009010087465737432303635009110087465737432303636009210" - "0874657374323036370093100874657374323036380094100874657374323036390095100874657374323037300096" - "1008746573743230373100971008746573743230373200981008746573743230373300991008746573743230373400" - "9a10087465737432303735009b10087465737432303736009c10087465737432303737009d10087465737432303738" - "009e10087465737432303739009f1008746573743230383000a01008746573743230383100a1100874657374323038" - "3200a21008746573743230383300a31008746573743230383400a41008746573743230383500a51008746573743230" - "383600a61008746573743230383700a71008746573743230383800a81008746573743230383900a910087465737432" - "30393000aa1008746573743230393100ab1008746573743230393200ac1008746573743230393300ad100874657374" - "3230393400ae1008746573743230393500af1008746573743230393600b01008746573743230393700b11008746573" - "743230393800b21008746573743230393900b31008746573743231303000b41008746573743231303100b510087465" - "73743231303200b61008746573743231303300b71008746573743231303400b81008746573743231303500b9100874" - "6573743231303600ba1008746573743231303700bb1008746573743231303800bc1008746573743231303900bd1008" - "746573743231313000be1008746573743231313100bf1008746573743231313200c01008746573743231313300c110" - "08746573743231313400c21008746573743231313500c31008746573743231313600c41008746573743231313700c5" - "1008746573743231313800c61008746573743231313900c71008746573743231323000c81008746573743231323100" - "c91008746573743231323200ca1008746573743231323300cb1008746573743231323400cc10087465737432313235" - "00cd1008746573743231323600ce1008746573743231323700cf1008746573743231323800d0100874657374323132" - "3900d11008746573743231333000d21008746573743231333100d31008746573743231333200d41008746573743231" - "333300d51008746573743231333400d61008746573743231333500d71008746573743231333600d810087465737432" - "31333700d91008746573743231333800da1008746573743231333900db1008746573743231343000dc100874657374" - "3231343100dd1008746573743231343200de1008746573743231343300df1008746573743231343400e01008746573" - "743231343500e11008746573743231343600e21008746573743231343700e31008746573743231343800e410087465" - "73743231343900e51008746573743231353000e61008746573743231353100e71008746573743231353200e8100874" - "6573743231353300e91008746573743231353400ea1008746573743231353500eb1008746573743231353600ec1008" - "746573743231353700ed1008746573743231353800ee1008746573743231353900ef1008746573743231363000f010" - "08746573743231363100f11008746573743231363200f21008746573743231363300f31008746573743231363400f4" - "1008746573743231363500f51008746573743231363600f61008746573743231363700f71008746573743231363800" - "f81008746573743231363900f91008746573743231373000fa1008746573743231373100fb10087465737432313732" - "00fc1008746573743231373300fd1008746573743231373400fe1008746573743231373500ff100874657374323137" - "3600801108746573743231373700811108746573743231373800821108746573743231373900831108746573743231" - "3830008411087465737432313831008511087465737432313832008611087465737432313833008711087465737432" - "313834008811087465737432313835008911087465737432313836008a11087465737432313837008b110874657374" - "32313838008c11087465737432313839008d11087465737432313930008e11087465737432313931008f1108746573" - "7432313932009011087465737432313933009111087465737432313934009211087465737432313935009311087465" - "7374323139360094110874657374323139370095110874657374323139380096110874657374323139390097110874" - "65737432323030009811087465737432323031009911087465737432323032009a11087465737432323033009b1108" - "7465737432323034009c11087465737432323035009d11087465737432323036009e11087465737432323037009f11" - "08746573743232303800a01108746573743232303900a11108746573743232313000a21108746573743232313100a3" - "1108746573743232313200a41108746573743232313300a51108746573743232313400a61108746573743232313500" - "a71108746573743232313600a81108746573743232313700a91108746573743232313800aa11087465737432323139" - "00ab1108746573743232323000ac1108746573743232323100ad1108746573743232323200ae110874657374323232" - "3300af1108746573743232323400b01108746573743232323500b11108746573743232323600b21108746573743232" - "323700b31108746573743232323800b41108746573743232323900b51108746573743232333000b611087465737432" - "32333100b71108746573743232333200b81108746573743232333300b91108746573743232333400ba110874657374" - "3232333500bb1108746573743232333600bc1108746573743232333700bd1108746573743232333800be1108746573" - "743232333900bf1108746573743232343000c01108746573743232343100c11108746573743232343200c211087465" - "73743232343300c31108746573743232343400c41108746573743232343500c51108746573743232343600c6110874" - "6573743232343700c71108746573743232343800c81108746573743232343900c91108746573743232353000ca1108" - "746573743232353100cb1108746573743232353200cc1108746573743232353300cd1108746573743232353400ce11" - "08746573743232353500cf1108746573743232353600d01108746573743232353700d11108746573743232353800d2" - "1108746573743232353900d31108746573743232363000d41108746573743232363100d51108746573743232363200" - "d61108746573743232363300d71108746573743232363400d81108746573743232363500d911087465737432323636" - "00da1108746573743232363700db1108746573743232363800dc1108746573743232363900dd110874657374323237" - "3000de1108746573743232373100df1108746573743232373200e01108746573743232373300e11108746573743232" - "373400e21108746573743232373500e31108746573743232373600e41108746573743232373700e511087465737432" - "32373800e61108746573743232373900e71108746573743232383000e81108746573743232383100e9110874657374" - "3232383200ea1108746573743232383300eb1108746573743232383400ec1108746573743232383500ed1108746573" - "743232383600ee1108746573743232383700ef1108746573743232383800f01108746573743232383900f111087465" - "73743232393000f21108746573743232393100f31108746573743232393200f41108746573743232393300f5110874" - "6573743232393400f61108746573743232393500f71108746573743232393600f81108746573743232393700f91108" - "746573743232393800fa1108746573743232393900fb1108746573743233303000fc1108746573743233303100fd11" - "08746573743233303200fe1108746573743233303300ff110874657374323330340080120874657374323330350081" - "1208746573743233303600821208746573743233303700831208746573743233303800841208746573743233303900" - "8512087465737432333130008612087465737432333131008712087465737432333132008812087465737432333133" - "008912087465737432333134008a12087465737432333135008b12087465737432333136008c120874657374323331" - "37008d12087465737432333138008e12087465737432333139008f1208746573743233323000901208746573743233" - "3231009112087465737432333232009212087465737432333233009312087465737432333234009412087465737432" - "3332350095120874657374323332360096120874657374323332370097120874657374323332380098120874657374" - "32333239009912087465737432333330009a12087465737432333331009b12087465737432333332009c1208746573" - "7432333333009d12087465737432333334009e12087465737432333335009f1208746573743233333600a012087465" - "73743233333700a11208746573743233333800a21208746573743233333900a31208746573743233343000a4120874" - "6573743233343100a51208746573743233343200a61208746573743233343300a71208746573743233343400a81208" - "746573743233343500a91208746573743233343600aa1208746573743233343700ab1208746573743233343800ac12" - "08746573743233343900ad1208746573743233353000ae1208746573743233353100af1208746573743233353200b0" - "1208746573743233353300b11208746573743233353400b21208746573743233353500b31208746573743233353600" - "b41208746573743233353700b51208746573743233353800b61208746573743233353900b712087465737432333630" - "00b81208746573743233363100b91208746573743233363200ba1208746573743233363300bb120874657374323336" - "3400bc1208746573743233363500bd1208746573743233363600be1208746573743233363700bf1208746573743233" - "363800c01208746573743233363900c11208746573743233373000c21208746573743233373100c312087465737432" - "33373200c41208746573743233373300c51208746573743233373400c61208746573743233373500c7120874657374" - "3233373600c81208746573743233373700c91208746573743233373800ca1208746573743233373900cb1208746573" - "743233383000cc1208746573743233383100cd1208746573743233383200ce1208746573743233383300cf12087465" - "73743233383400d01208746573743233383500d11208746573743233383600d21208746573743233383700d3120874" - "6573743233383800d41208746573743233383900d51208746573743233393000d61208746573743233393100d71208" - "746573743233393200d81208746573743233393300d91208746573743233393400da1208746573743233393500db12" - "08746573743233393600dc1208746573743233393700dd1208746573743233393800de1208746573743233393900df" - "1208746573743234303000e01208746573743234303100e11208746573743234303200e21208746573743234303300" - "e31208746573743234303400e41208746573743234303500e51208746573743234303600e612087465737432343037" - "00e71208746573743234303800e81208746573743234303900e91208746573743234313000ea120874657374323431" - "3100eb1208746573743234313200ec1208746573743234313300ed1208746573743234313400ee1208746573743234" - "313500ef1208746573743234313600f01208746573743234313700f11208746573743234313800f212087465737432" - "34313900f31208746573743234323000f41208746573743234323100f51208746573743234323200f6120874657374" - "3234323300f71208746573743234323400f81208746573743234323500f91208746573743234323600fa1208746573" - "743234323700fb1208746573743234323800fc1208746573743234323900fd1208746573743234333000fe12087465" - "73743234333100ff120874657374323433320080130874657374323433330081130874657374323433340082130874" - "6573743234333500831308746573743234333600841308746573743234333700851308746573743234333800861308" - "7465737432343339008713087465737432343430008813087465737432343431008913087465737432343432008a13" - "087465737432343433008b13087465737432343434008c13087465737432343435008d13087465737432343436008e" - "13087465737432343437008f1308746573743234343800901308746573743234343900911308746573743234353000" - "9213087465737432343531009313087465737432343532009413087465737432343533009513087465737432343534" - "0096130874657374323435350097130874657374323435360098130874657374323435370099130874657374323435" - "38009a13087465737432343539009b13087465737432343630009c13087465737432343631009d1308746573743234" - "3632009e13087465737432343633009f1308746573743234363400a01308746573743234363500a113087465737432" - "34363600a21308746573743234363700a31308746573743234363800a41308746573743234363900a5130874657374" - "3234373000a61308746573743234373100a71308746573743234373200a81308746573743234373300a91308746573" - "743234373400aa1308746573743234373500ab1308746573743234373600ac1308746573743234373700ad13087465" - "73743234373800ae1308746573743234373900af1308746573743234383000b01308746573743234383100b1130874" - "6573743234383200b21308746573743234383300b31308746573743234383400b41308746573743234383500b51308" - "746573743234383600b61308746573743234383700b71308746573743234383800b81308746573743234383900b913" - "08746573743234393000ba1308746573743234393100bb1308746573743234393200bc1308746573743234393300bd" - "1308746573743234393400be1308746573743234393500bf1308746573743234393600c01308746573743234393700" - "c11308746573743234393800c21308746573743234393900c31308746573743235303000c413087465737432353031" - "00c51308746573743235303200c61308746573743235303300c71308746573743235303400c8130874657374323530" - "3500c91308746573743235303600ca1308746573743235303700cb1308746573743235303800cc1308746573743235" - "303900cd1308746573743235313000ce1308746573743235313100cf1308746573743235313200d013087465737432" - "35313300d11308746573743235313400d21308746573743235313500d31308746573743235313600d4130874657374" - "3235313700d51308746573743235313800d61308746573743235313900d71308746573743235323000d81308746573" - "743235323100d91308746573743235323200da1308746573743235323300db1308746573743235323400dc13087465" - "73743235323500dd1308746573743235323600de1308746573743235323700df1308746573743235323800e0130874" - "6573743235323900e11308746573743235333000e21308746573743235333100e31308746573743235333200e41308" - "746573743235333300e51308746573743235333400e61308746573743235333500e71308746573743235333600e813" - "08746573743235333700e91308746573743235333800ea1308746573743235333900eb1308746573743235343000ec" - "1308746573743235343100ed1308746573743235343200ee1308746573743235343300ef1308746573743235343400" - "f01308746573743235343500f11308746573743235343600f21308746573743235343700f313087465737432353438" - "00f41308746573743235343900f51308746573743235353000f61308746573743235353100f7130874657374323535" - "3200f81308746573743235353300f91308746573743235353400fa1308746573743235353500fb1308746573743235" - "353600fc1308746573743235353700fd1308746573743235353800fe1308746573743235353900ff13087465737432" - "3536300080140874657374323536310081140874657374323536320082140874657374323536330083140874657374" - "3235363400841408746573743235363500851408746573743235363600861408746573743235363700871408746573" - "7432353638008814087465737432353639008914087465737432353730008a14087465737432353731008b14087465" - "737432353732008c14087465737432353733008d14087465737432353734008e14087465737432353735008f140874" - "6573743235373600901408746573743235373700911408746573743235373800921408746573743235373900931408" - "7465737432353830009414087465737432353831009514087465737432353832009614087465737432353833009714" - "087465737432353834009814087465737432353835009914087465737432353836009a14087465737432353837009b" - "14087465737432353838009c14087465737432353839009d14087465737432353930009e1408746573743235393100" - "9f1408746573743235393200a01408746573743235393300a11408746573743235393400a214087465737432353935" - "00a31408746573743235393600a41408746573743235393700a51408746573743235393800a6140874657374323539" - "3900a71408746573743236303000a81408746573743236303100a91408746573743236303200aa1408746573743236" - "303300ab1408746573743236303400ac1408746573743236303500ad1408746573743236303600ae14087465737432" - "36303700af1408746573743236303800b01408746573743236303900b11408746573743236313000b2140874657374" - "3236313100b31408746573743236313200b41408746573743236313300b51408746573743236313400b61408746573" - "743236313500b71408746573743236313600b81408746573743236313700b91408746573743236313800ba14087465" - "73743236313900bb1408746573743236323000bc1408746573743236323100bd1408746573743236323200be140874" - "6573743236323300bf1408746573743236323400c01408746573743236323500c11408746573743236323600c21408" - "746573743236323700c31408746573743236323800c41408746573743236323900c51408746573743236333000c614" - "08746573743236333100c71408746573743236333200c81408746573743236333300c91408746573743236333400ca" - "1408746573743236333500cb1408746573743236333600cc1408746573743236333700cd1408746573743236333800" - "ce1408746573743236333900cf1408746573743236343000d01408746573743236343100d114087465737432363432" - "00d21408746573743236343300d31408746573743236343400d41408746573743236343500d5140874657374323634" - "3600d61408746573743236343700d71408746573743236343800d81408746573743236343900d91408746573743236" - "353000da1408746573743236353100db1408746573743236353200dc1408746573743236353300dd14087465737432" - "36353400de1408746573743236353500df1408746573743236353600e01408746573743236353700e1140874657374" - "3236353800e21408746573743236353900e31408746573743236363000e41408746573743236363100e51408746573" - "743236363200e61408746573743236363300e71408746573743236363400e81408746573743236363500e914087465" - "73743236363600ea1408746573743236363700eb1408746573743236363800ec1408746573743236363900ed140874" - "6573743236373000ee1408746573743236373100ef1408746573743236373200f01408746573743236373300f11408" - "746573743236373400f21408746573743236373500f31408746573743236373600f41408746573743236373700f514" - "08746573743236373800f61408746573743236373900f71408746573743236383000f81408746573743236383100f9" - "1408746573743236383200fa1408746573743236383300fb1408746573743236383400fc1408746573743236383500" - "fd1408746573743236383600fe1408746573743236383700ff14087465737432363838008015087465737432363839" - "0081150874657374323639300082150874657374323639310083150874657374323639320084150874657374323639" - "3300851508746573743236393400861508746573743236393500871508746573743236393600881508746573743236" - "3937008915087465737432363938008a15087465737432363939008b15087465737432373030008c15087465737432" - "373031008d15087465737432373032008e15087465737432373033008f150874657374323730340090150874657374" - "3237303500911508746573743237303600921508746573743237303700931508746573743237303800941508746573" - "7432373039009515087465737432373130009615087465737432373131009715087465737432373132009815087465" - "737432373133009915087465737432373134009a15087465737432373135009b15087465737432373136009c150874" - "65737432373137009d15087465737432373138009e15087465737432373139009f1508746573743237323000a01508" - "746573743237323100a11508746573743237323200a21508746573743237323300a31508746573743237323400a415" - "08746573743237323500a51508746573743237323600a61508746573743237323700a71508746573743237323800a8" - "1508746573743237323900a91508746573743237333000aa1508746573743237333100ab1508746573743237333200" - "ac1508746573743237333300ad1508746573743237333400ae1508746573743237333500af15087465737432373336" - "00b01508746573743237333700b11508746573743237333800b21508746573743237333900b3150874657374323734" - "3000b41508746573743237343100b51508746573743237343200b61508746573743237343300b71508746573743237" - "343400b81508746573743237343500b91508746573743237343600ba1508746573743237343700bb15087465737432" - "37343800bc1508746573743237343900bd1508746573743237353000be1508746573743237353100bf150874657374" - "3237353200c01508746573743237353300c11508746573743237353400c21508746573743237353500c31508746573" - "743237353600c41508746573743237353700c51508746573743237353800c61508746573743237353900c715087465" - "73743237363000c81508746573743237363100c91508746573743237363200ca1508746573743237363300cb150874" - "6573743237363400cc1508746573743237363500cd1508746573743237363600ce1508746573743237363700cf1508" - "746573743237363800d01508746573743237363900d11508746573743237373000d21508746573743237373100d315" - "08746573743237373200d41508746573743237373300d51508746573743237373400d61508746573743237373500d7" - "1508746573743237373600d81508746573743237373700d91508746573743237373800da1508746573743237373900" - "db1508746573743237383000dc1508746573743237383100dd1508746573743237383200de15087465737432373833" - "00df1508746573743237383400e01508746573743237383500e11508746573743237383600e2150874657374323738" - "3700e31508746573743237383800e41508746573743237383900e51508746573743237393000e61508746573743237" - "393100e71508746573743237393200e81508746573743237393300e91508746573743237393400ea15087465737432" - "37393500eb1508746573743237393600ec1508746573743237393700ed1508746573743237393800ee150874657374" - "3237393900ef1508746573743238303000f01508746573743238303100f11508746573743238303200f21508746573" - "743238303300f31508746573743238303400f41508746573743238303500f51508746573743238303600f615087465" - "73743238303700f71508746573743238303800f81508746573743238303900f91508746573743238313000fa150874" - "6573743238313100fb1508746573743238313200fc1508746573743238313300fd1508746573743238313400fe1508" - "746573743238313500ff15087465737432383136008016087465737432383137008116087465737432383138008216" - "0874657374323831390083160874657374323832300084160874657374323832310085160874657374323832320086" - "1608746573743238323300871608746573743238323400881608746573743238323500891608746573743238323600" - "8a16087465737432383237008b16087465737432383238008c16087465737432383239008d16087465737432383330" - "008e16087465737432383331008f160874657374323833320090160874657374323833330091160874657374323833" - "3400921608746573743238333500931608746573743238333600941608746573743238333700951608746573743238" - "3338009616087465737432383339009716087465737432383430009816087465737432383431009916087465737432" - "383432009a16087465737432383433009b16087465737432383434009c16087465737432383435009d160874657374" - "32383436009e16087465737432383437009f1608746573743238343800a01608746573743238343900a11608746573" - "743238353000a21608746573743238353100a31608746573743238353200a41608746573743238353300a516087465" - "73743238353400a61608746573743238353500a71608746573743238353600a81608746573743238353700a9160874" - "6573743238353800aa1608746573743238353900ab1608746573743238363000ac1608746573743238363100ad1608" - "746573743238363200ae1608746573743238363300af1608746573743238363400b01608746573743238363500b116" - "08746573743238363600b21608746573743238363700b31608746573743238363800b41608746573743238363900b5" - "1608746573743238373000b61608746573743238373100b71608746573743238373200b81608746573743238373300" - "b91608746573743238373400ba1608746573743238373500bb1608746573743238373600bc16087465737432383737" - "00bd1608746573743238373800be1608746573743238373900bf1608746573743238383000c0160874657374323838" - "3100c11608746573743238383200c21608746573743238383300c31608746573743238383400c41608746573743238" - "383500c51608746573743238383600c61608746573743238383700c71608746573743238383800c816087465737432" - "38383900c91608746573743238393000ca1608746573743238393100cb1608746573743238393200cc160874657374" - "3238393300cd1608746573743238393400ce1608746573743238393500cf1608746573743238393600d01608746573" - "743238393700d11608746573743238393800d21608746573743238393900d31608746573743239303000d416087465" - "73743239303100d51608746573743239303200d61608746573743239303300d71608746573743239303400d8160874" - "6573743239303500d91608746573743239303600da1608746573743239303700db1608746573743239303800dc1608" - "746573743239303900dd1608746573743239313000de1608746573743239313100df1608746573743239313200e016" - "08746573743239313300e11608746573743239313400e21608746573743239313500e31608746573743239313600e4" - "1608746573743239313700e51608746573743239313800e61608746573743239313900e71608746573743239323000" - "e81608746573743239323100e91608746573743239323200ea1608746573743239323300eb16087465737432393234" - "00ec1608746573743239323500ed1608746573743239323600ee1608746573743239323700ef160874657374323932" - "3800f01608746573743239323900f11608746573743239333000f21608746573743239333100f31608746573743239" - "333200f41608746573743239333300f51608746573743239333400f61608746573743239333500f716087465737432" - "39333600f81608746573743239333700f91608746573743239333800fa1608746573743239333900fb160874657374" - "3239343000fc1608746573743239343100fd1608746573743239343200fe1608746573743239343300ff1608746573" - "7432393434008017087465737432393435008117087465737432393436008217087465737432393437008317087465" - "7374323934380084170874657374323934390085170874657374323935300086170874657374323935310087170874" - "65737432393532008817087465737432393533008917087465737432393534008a17087465737432393535008b1708" - "7465737432393536008c17087465737432393537008d17087465737432393538008e17087465737432393539008f17" - "0874657374323936300090170874657374323936310091170874657374323936320092170874657374323936330093" - "1708746573743239363400941708746573743239363500951708746573743239363600961708746573743239363700" - "9717087465737432393638009817087465737432393639009917087465737432393730009a17087465737432393731" - "009b17087465737432393732009c17087465737432393733009d17087465737432393734009e170874657374323937" - "35009f1708746573743239373600a01708746573743239373700a11708746573743239373800a21708746573743239" - "373900a31708746573743239383000a41708746573743239383100a51708746573743239383200a617087465737432" - "39383300a71708746573743239383400a81708746573743239383500a91708746573743239383600aa170874657374" - "3239383700ab1708746573743239383800ac1708746573743239383900ad1708746573743239393000ae1708746573" - "743239393100af1708746573743239393200b01708746573743239393300b11708746573743239393400b217087465" - "73743239393500b31708746573743239393600b41708746573743239393700b51708746573743239393800b6170874" - "6573743239393900b71708746573743330303000b81708746573743330303100b91708746573743330303200ba1708" - "746573743330303300bb1708746573743330303400bc1708746573743330303500bd1708746573743330303600be17" - "08746573743330303700bf1708746573743330303800c01708746573743330303900c11708746573743330313000c2" - "1708746573743330313100c31708746573743330313200c41708746573743330313300c51708746573743330313400" - "c61708746573743330313500c71708746573743330313600c81708746573743330313700c917087465737433303138" - "00ca1708746573743330313900cb1708746573743330323000cc1708746573743330323100cd170874657374333032" - "3200ce1708746573743330323300cf1708746573743330323400d01708746573743330323500d11708746573743330" - "323600d21708746573743330323700d31708746573743330323800d41708746573743330323900d517087465737433" - "30333000d61708746573743330333100d71708746573743330333200d81708746573743330333300d9170874657374" - "3330333400da1708746573743330333500db1708746573743330333600dc1708746573743330333700dd1708746573" - "743330333800de1708746573743330333900df1708746573743330343000e01708746573743330343100e117087465" - "73743330343200e21708746573743330343300e31708746573743330343400e41708746573743330343500e5170874" - "6573743330343600e61708746573743330343700e71708746573743330343800e81708746573743330343900e91708" - "746573743330353000ea1708746573743330353100eb1708746573743330353200ec1708746573743330353300ed17" - "08746573743330353400ee1708746573743330353500ef1708746573743330353600f01708746573743330353700f1" - "1708746573743330353800f21708746573743330353900f31708746573743330363000f41708746573743330363100" - "f51708746573743330363200f61708746573743330363300f71708746573743330363400f817087465737433303635" - "00f91708746573743330363600fa1708746573743330363700fb1708746573743330363800fc170874657374333036" - "3900fd1708746573743330373000fe1708746573743330373100ff1708746573743330373200801808746573743330" - "3733008118087465737433303734008218087465737433303735008318087465737433303736008418087465737433" - "3037370085180874657374333037380086180874657374333037390087180874657374333038300088180874657374" - "33303831008918087465737433303832008a18087465737433303833008b18087465737433303834008c1808746573" - "7433303835008d18087465737433303836008e18087465737433303837008f18087465737433303838009018087465" - "7374333038390091180874657374333039300092180874657374333039310093180874657374333039320094180874" - "6573743330393300951808746573743330393400961808746573743330393500971808746573743330393600981808" - "7465737433303937009918087465737433303938009a18087465737433303939009b18087465737433313030009c18" - "087465737433313031009d18087465737433313032009e18087465737433313033009f1808746573743331303400a0" - "1808746573743331303500a11808746573743331303600a21808746573743331303700a31808746573743331303800" - "a41808746573743331303900a51808746573743331313000a61808746573743331313100a718087465737433313132" - "00a81808746573743331313300a91808746573743331313400aa1808746573743331313500ab180874657374333131" - "3600ac1808746573743331313700ad1808746573743331313800ae1808746573743331313900af1808746573743331" - "323000b01808746573743331323100b11808746573743331323200b21808746573743331323300b318087465737433" - "31323400b41808746573743331323500b51808746573743331323600b61808746573743331323700b7180874657374" - "3331323800b81808746573743331323900b91808746573743331333000ba1808746573743331333100bb1808746573" - "743331333200bc1808746573743331333300bd1808746573743331333400be1808746573743331333500bf18087465" - "73743331333600c01808746573743331333700c11808746573743331333800c21808746573743331333900c3180874" - "6573743331343000c41808746573743331343100c51808746573743331343200c61808746573743331343300c71808" - "746573743331343400c81808746573743331343500c91808746573743331343600ca1808746573743331343700cb18" - "08746573743331343800cc1808746573743331343900cd1808746573743331353000ce1808746573743331353100cf" - "1808746573743331353200d01808746573743331353300d11808746573743331353400d21808746573743331353500" - "d31808746573743331353600d41808746573743331353700d51808746573743331353800d618087465737433313539" - "00d71808746573743331363000d81808746573743331363100d91808746573743331363200da180874657374333136" - "3300db1808746573743331363400dc1808746573743331363500dd1808746573743331363600de1808746573743331" - "363700df1808746573743331363800e01808746573743331363900e11808746573743331373000e218087465737433" - "31373100e31808746573743331373200e41808746573743331373300e51808746573743331373400e6180874657374" - "3331373500e71808746573743331373600e81808746573743331373700e91808746573743331373800ea1808746573" - "743331373900eb1808746573743331383000ec1808746573743331383100ed1808746573743331383200ee18087465" - "73743331383300ef1808746573743331383400f01808746573743331383500f11808746573743331383600f2180874" - "6573743331383700f31808746573743331383800f41808746573743331383900f51808746573743331393000f61808" - "746573743331393100f71808746573743331393200f81808746573743331393300f91808746573743331393400fa18" - "08746573743331393500fb1808746573743331393600fc1808746573743331393700fd1808746573743331393800fe" - "1808746573743331393900ff1808746573743332303000801908746573743332303100811908746573743332303200" - "8219087465737433323033008319087465737433323034008419087465737433323035008519087465737433323036" - "0086190874657374333230370087190874657374333230380088190874657374333230390089190874657374333231" - "30008a19087465737433323131008b19087465737433323132008c19087465737433323133008d1908746573743332" - "3134008e19087465737433323135008f19087465737433323136009019087465737433323137009119087465737433" - "3231380092190874657374333231390093190874657374333232300094190874657374333232310095190874657374" - "3332323200961908746573743332323300971908746573743332323400981908746573743332323500991908746573" - "7433323236009a19087465737433323237009b19087465737433323238009c19087465737433323239009d19087465" - "737433323330009e19087465737433323331009f1908746573743332333200a01908746573743332333300a1190874" - "6573743332333400a21908746573743332333500a31908746573743332333600a41908746573743332333700a51908" - "746573743332333800a61908746573743332333900a71908746573743332343000a81908746573743332343100a919" - "08746573743332343200aa1908746573743332343300ab1908746573743332343400ac1908746573743332343500ad" - "1908746573743332343600ae1908746573743332343700af1908746573743332343800b01908746573743332343900" - "b11908746573743332353000b21908746573743332353100b31908746573743332353200b419087465737433323533" - "00b51908746573743332353400b61908746573743332353500b71908746573743332353600b8190874657374333235" - "3700b91908746573743332353800ba1908746573743332353900bb1908746573743332363000bc1908746573743332" - "363100bd1908746573743332363200be1908746573743332363300bf1908746573743332363400c019087465737433" - "32363500c11908746573743332363600c21908746573743332363700c31908746573743332363800c4190874657374" - "3332363900c51908746573743332373000c61908746573743332373100c71908746573743332373200c81908746573" - "743332373300c91908746573743332373400ca1908746573743332373500cb1908746573743332373600cc19087465" - "73743332373700cd1908746573743332373800ce1908746573743332373900cf1908746573743332383000d0190874" - "6573743332383100d11908746573743332383200d21908746573743332383300d31908746573743332383400d41908" - "746573743332383500d51908746573743332383600d61908746573743332383700d71908746573743332383800d819" - "08746573743332383900d91908746573743332393000da1908746573743332393100db1908746573743332393200dc" - "1908746573743332393300dd1908746573743332393400de1908746573743332393500df1908746573743332393600" - "e01908746573743332393700e11908746573743332393800e21908746573743332393900e319087465737433333030" - "00e41908746573743333303100e51908746573743333303200e61908746573743333303300e7190874657374333330" - "3400e81908746573743333303500e91908746573743333303600ea1908746573743333303700eb1908746573743333" - "303800ec1908746573743333303900ed1908746573743333313000ee1908746573743333313100ef19087465737433" - "33313200f01908746573743333313300f11908746573743333313400f21908746573743333313500f3190874657374" - "3333313600f41908746573743333313700f51908746573743333313800f61908746573743333313900f71908746573" - "743333323000f81908746573743333323100f91908746573743333323200fa1908746573743333323300fb19087465" - "73743333323400fc1908746573743333323500fd1908746573743333323600fe1908746573743333323700ff190874" - "6573743333323800801a08746573743333323900811a08746573743333333000821a08746573743333333100831a08" - "746573743333333200841a08746573743333333300851a08746573743333333400861a08746573743333333500871a" - "08746573743333333600881a08746573743333333700891a087465737433333338008a1a087465737433333339008b" - "1a087465737433333430008c1a087465737433333431008d1a087465737433333432008e1a08746573743333343300" - "8f1a08746573743333343400901a08746573743333343500911a08746573743333343600921a087465737433333437" - "00931a08746573743333343800941a08746573743333343900951a08746573743333353000961a0874657374333335" - "3100971a08746573743333353200981a08746573743333353300991a087465737433333534009a1a08746573743333" - "3535009b1a087465737433333536009c1a087465737433333537009d1a087465737433333538009e1a087465737433" - "333539009f1a08746573743333363000a01a08746573743333363100a11a08746573743333363200a21a0874657374" - "3333363300a31a08746573743333363400a41a08746573743333363500a51a08746573743333363600a61a08746573" - "743333363700a71a08746573743333363800a81a08746573743333363900a91a08746573743333373000aa1a087465" - "73743333373100ab1a08746573743333373200ac1a08746573743333373300ad1a08746573743333373400ae1a0874" - "6573743333373500af1a08746573743333373600b01a08746573743333373700b11a08746573743333373800b21a08" - "746573743333373900b31a08746573743333383000b41a08746573743333383100b51a08746573743333383200b61a" - "08746573743333383300b71a08746573743333383400b81a08746573743333383500b91a08746573743333383600ba" - "1a08746573743333383700bb1a08746573743333383800bc1a08746573743333383900bd1a08746573743333393000" - "be1a08746573743333393100bf1a08746573743333393200c01a08746573743333393300c11a087465737433333934" - "00c21a08746573743333393500c31a08746573743333393600c41a08746573743333393700c51a0874657374333339" - "3800c61a08746573743333393900c71a08746573743334303000c81a08746573743334303100c91a08746573743334" - "303200ca1a08746573743334303300cb1a08746573743334303400cc1a08746573743334303500cd1a087465737433" - "34303600ce1a08746573743334303700cf1a08746573743334303800d01a08746573743334303900d11a0874657374" - "3334313000d21a08746573743334313100d31a08746573743334313200d41a08746573743334313300d51a08746573" - "743334313400d61a08746573743334313500d71a08746573743334313600d81a08746573743334313700d91a087465" - "73743334313800da1a08746573743334313900db1a08746573743334323000dc1a08746573743334323100dd1a0874" - "6573743334323200de1a08746573743334323300df1a08746573743334323400e01a08746573743334323500e11a08" - "746573743334323600e21a08746573743334323700e31a08746573743334323800e41a08746573743334323900e51a" - "08746573743334333000e61a08746573743334333100e71a08746573743334333200e81a08746573743334333300e9" - "1a08746573743334333400ea1a08746573743334333500eb1a08746573743334333600ec1a08746573743334333700" - "ed1a08746573743334333800ee1a08746573743334333900ef1a08746573743334343000f01a087465737433343431" - "00f11a08746573743334343200f21a08746573743334343300f31a08746573743334343400f41a0874657374333434" - "3500f51a08746573743334343600f61a08746573743334343700f71a08746573743334343800f81a08746573743334" - "343900f91a08746573743334353000fa1a08746573743334353100fb1a08746573743334353200fc1a087465737433" - "34353300fd1a08746573743334353400fe1a08746573743334353500ff1a08746573743334353600801b0874657374" - "3334353700811b08746573743334353800821b08746573743334353900831b08746573743334363000841b08746573" - "743334363100851b08746573743334363200861b08746573743334363300871b08746573743334363400881b087465" - "73743334363500891b087465737433343636008a1b087465737433343637008b1b087465737433343638008c1b0874" - "65737433343639008d1b087465737433343730008e1b087465737433343731008f1b08746573743334373200901b08" - "746573743334373300911b08746573743334373400921b08746573743334373500931b08746573743334373600941b" - "08746573743334373700951b08746573743334373800961b08746573743334373900971b0874657374333438300098" - "1b08746573743334383100991b087465737433343832009a1b087465737433343833009b1b08746573743334383400" - "9c1b087465737433343835009d1b087465737433343836009e1b087465737433343837009f1b087465737433343838" - "00a01b08746573743334383900a11b08746573743334393000a21b08746573743334393100a31b0874657374333439" - "3200a41b08746573743334393300a51b08746573743334393400a61b08746573743334393500a71b08746573743334" - "393600a81b08746573743334393700a91b08746573743334393800aa1b08746573743334393900ab1b087465737433" - "35303000ac1b08746573743335303100ad1b08746573743335303200ae1b08746573743335303300af1b0874657374" - "3335303400b01b08746573743335303500b11b08746573743335303600b21b08746573743335303700b31b08746573" - "743335303800b41b08746573743335303900b51b08746573743335313000b61b08746573743335313100b71b087465" - "73743335313200b81b08746573743335313300b91b08746573743335313400ba1b08746573743335313500bb1b0874" - "6573743335313600bc1b08746573743335313700bd1b08746573743335313800be1b08746573743335313900bf1b08" - "746573743335323000c01b08746573743335323100c11b08746573743335323200c21b08746573743335323300c31b" - "08746573743335323400c41b08746573743335323500c51b08746573743335323600c61b08746573743335323700c7" - "1b08746573743335323800c81b08746573743335323900c91b08746573743335333000ca1b08746573743335333100" - "cb1b08746573743335333200cc1b08746573743335333300cd1b08746573743335333400ce1b087465737433353335" - "00cf1b08746573743335333600d01b08746573743335333700d11b08746573743335333800d21b0874657374333533" - "3900d31b08746573743335343000d41b08746573743335343100d51b08746573743335343200d61b08746573743335" - "343300d71b08746573743335343400d81b08746573743335343500d91b08746573743335343600da1b087465737433" - "35343700db1b08746573743335343800dc1b08746573743335343900dd1b08746573743335353000de1b0874657374" - "3335353100df1b08746573743335353200e01b08746573743335353300e11b08746573743335353400e21b08746573" - "743335353500e31b08746573743335353600e41b08746573743335353700e51b08746573743335353800e61b087465" - "73743335353900e71b08746573743335363000e81b08746573743335363100e91b08746573743335363200ea1b0874" - "6573743335363300eb1b08746573743335363400ec1b08746573743335363500ed1b08746573743335363600ee1b08" - "746573743335363700ef1b08746573743335363800f01b08746573743335363900f11b08746573743335373000f21b" - "08746573743335373100f31b08746573743335373200f41b08746573743335373300f51b08746573743335373400f6" - "1b08746573743335373500f71b08746573743335373600f81b08746573743335373700f91b08746573743335373800" - "fa1b08746573743335373900fb1b08746573743335383000fc1b08746573743335383100fd1b087465737433353832" - "00fe1b08746573743335383300ff1b08746573743335383400801c08746573743335383500811c0874657374333538" - "3600821c08746573743335383700831c08746573743335383800841c08746573743335383900851c08746573743335" - "393000861c08746573743335393100871c08746573743335393200881c08746573743335393300891c087465737433" - "353934008a1c087465737433353935008b1c087465737433353936008c1c087465737433353937008d1c0874657374" - "33353938008e1c087465737433353939008f1c08746573743336303000901c08746573743336303100911c08746573" - "743336303200921c08746573743336303300931c08746573743336303400941c08746573743336303500951c087465" - "73743336303600961c08746573743336303700971c08746573743336303800981c08746573743336303900991c0874" - "65737433363130009a1c087465737433363131009b1c087465737433363132009c1c087465737433363133009d1c08" - "7465737433363134009e1c087465737433363135009f1c08746573743336313600a01c08746573743336313700a11c" - "08746573743336313800a21c08746573743336313900a31c08746573743336323000a41c08746573743336323100a5" - "1c08746573743336323200a61c08746573743336323300a71c08746573743336323400a81c08746573743336323500" - "a91c08746573743336323600aa1c08746573743336323700ab1c08746573743336323800ac1c087465737433363239" - "00ad1c08746573743336333000ae1c08746573743336333100af1c08746573743336333200b01c0874657374333633" - "3300b11c08746573743336333400b21c08746573743336333500b31c08746573743336333600b41c08746573743336" - "333700b51c08746573743336333800b61c08746573743336333900b71c08746573743336343000b81c087465737433" - "36343100b91c08746573743336343200ba1c08746573743336343300bb1c08746573743336343400bc1c0874657374" - "3336343500bd1c08746573743336343600be1c08746573743336343700bf1c08746573743336343800c01c08746573" - "743336343900c11c08746573743336353000c21c08746573743336353100c31c08746573743336353200c41c087465" - "73743336353300c51c08746573743336353400c61c08746573743336353500c71c08746573743336353600c81c0874" - "6573743336353700c91c08746573743336353800ca1c08746573743336353900cb1c08746573743336363000cc1c08" - "746573743336363100cd1c08746573743336363200ce1c08746573743336363300cf1c08746573743336363400d01c" - "08746573743336363500d11c08746573743336363600d21c08746573743336363700d31c08746573743336363800d4" - "1c08746573743336363900d51c08746573743336373000d61c08746573743336373100d71c08746573743336373200" - "d81c08746573743336373300d91c08746573743336373400da1c08746573743336373500db1c087465737433363736" - "00dc1c08746573743336373700dd1c08746573743336373800de1c08746573743336373900df1c0874657374333638" - "3000e01c08746573743336383100e11c08746573743336383200e21c08746573743336383300e31c08746573743336" - "383400e41c08746573743336383500e51c08746573743336383600e61c08746573743336383700e71c087465737433" - "36383800e81c08746573743336383900e91c08746573743336393000ea1c08746573743336393100eb1c0874657374" - "3336393200ec1c08746573743336393300ed1c08746573743336393400ee1c08746573743336393500ef1c08746573" - "743336393600f01c08746573743336393700f11c08746573743336393800f21c08746573743336393900f31c087465" - "73743337303000f41c08746573743337303100f51c08746573743337303200f61c08746573743337303300f71c0874" - "6573743337303400f81c08746573743337303500f91c08746573743337303600fa1c08746573743337303700fb1c08" - "746573743337303800fc1c08746573743337303900fd1c08746573743337313000fe1c08746573743337313100ff1c" - "08746573743337313200801d08746573743337313300811d08746573743337313400821d0874657374333731350083" - "1d08746573743337313600841d08746573743337313700851d08746573743337313800861d08746573743337313900" - "871d08746573743337323000881d08746573743337323100891d087465737433373232008a1d087465737433373233" - "008b1d087465737433373234008c1d087465737433373235008d1d087465737433373236008e1d0874657374333732" - "37008f1d08746573743337323800901d08746573743337323900911d08746573743337333000921d08746573743337" - "333100931d08746573743337333200941d08746573743337333300951d08746573743337333400961d087465737433" - "37333500971d08746573743337333600981d08746573743337333700991d087465737433373338009a1d0874657374" - "33373339009b1d087465737433373430009c1d087465737433373431009d1d087465737433373432009e1d08746573" - "7433373433009f1d08746573743337343400a01d08746573743337343500a11d08746573743337343600a21d087465" - "73743337343700a31d08746573743337343800a41d08746573743337343900a51d08746573743337353000a61d0874" - "6573743337353100a71d08746573743337353200a81d08746573743337353300a91d08746573743337353400aa1d08" - "746573743337353500ab1d08746573743337353600ac1d08746573743337353700ad1d08746573743337353800ae1d" - "08746573743337353900af1d08746573743337363000b01d08746573743337363100b11d08746573743337363200b2" - "1d08746573743337363300b31d08746573743337363400b41d08746573743337363500b51d08746573743337363600" - "b61d08746573743337363700b71d08746573743337363800b81d08746573743337363900b91d087465737433373730" - "00ba1d08746573743337373100bb1d08746573743337373200bc1d08746573743337373300bd1d0874657374333737" - "3400be1d08746573743337373500bf1d08746573743337373600c01d08746573743337373700c11d08746573743337" - "373800c21d08746573743337373900c31d08746573743337383000c41d08746573743337383100c51d087465737433" - "37383200c61d08746573743337383300c71d08746573743337383400c81d08746573743337383500c91d0874657374" - "3337383600ca1d08746573743337383700cb1d08746573743337383800cc1d08746573743337383900cd1d08746573" - "743337393000ce1d08746573743337393100cf1d08746573743337393200d01d08746573743337393300d11d087465" - "73743337393400d21d08746573743337393500d31d08746573743337393600d41d08746573743337393700d51d0874" - "6573743337393800d61d08746573743337393900d71d08746573743338303000d81d08746573743338303100d91d08" - "746573743338303200da1d08746573743338303300db1d08746573743338303400dc1d08746573743338303500dd1d" - "08746573743338303600de1d08746573743338303700df1d08746573743338303800e01d08746573743338303900e1" - "1d08746573743338313000e21d08746573743338313100e31d08746573743338313200e41d08746573743338313300" - "e51d08746573743338313400e61d08746573743338313500e71d08746573743338313600e81d087465737433383137" - "00e91d08746573743338313800ea1d08746573743338313900eb1d08746573743338323000ec1d0874657374333832" - "3100ed1d08746573743338323200ee1d08746573743338323300ef1d08746573743338323400f01d08746573743338" - "323500f11d08746573743338323600f21d08746573743338323700f31d08746573743338323800f41d087465737433" - "38323900f51d08746573743338333000f61d08746573743338333100f71d08746573743338333200f81d0874657374" - "3338333300f91d08746573743338333400fa1d08746573743338333500fb1d08746573743338333600fc1d08746573" - "743338333700fd1d08746573743338333800fe1d08746573743338333900ff1d08746573743338343000801e087465" - "73743338343100811e08746573743338343200821e08746573743338343300831e08746573743338343400841e0874" - "6573743338343500851e08746573743338343600861e08746573743338343700871e08746573743338343800881e08" - "746573743338343900891e087465737433383530008a1e087465737433383531008b1e087465737433383532008c1e" - "087465737433383533008d1e087465737433383534008e1e087465737433383535008f1e0874657374333835360090" - "1e08746573743338353700911e08746573743338353800921e08746573743338353900931e08746573743338363000" - "941e08746573743338363100951e08746573743338363200961e08746573743338363300971e087465737433383634" - "00981e08746573743338363500991e087465737433383636009a1e087465737433383637009b1e0874657374333836" - "38009c1e087465737433383639009d1e087465737433383730009e1e087465737433383731009f1e08746573743338" - "373200a01e08746573743338373300a11e08746573743338373400a21e08746573743338373500a31e087465737433" - "38373600a41e08746573743338373700a51e08746573743338373800a61e08746573743338373900a71e0874657374" - "3338383000a81e08746573743338383100a91e08746573743338383200aa1e08746573743338383300ab1e08746573" - "743338383400ac1e08746573743338383500ad1e08746573743338383600ae1e08746573743338383700af1e087465" - "73743338383800b01e08746573743338383900b11e08746573743338393000b21e08746573743338393100b31e0874" - "6573743338393200b41e08746573743338393300b51e08746573743338393400b61e08746573743338393500b71e08" - "746573743338393600b81e08746573743338393700b91e08746573743338393800ba1e08746573743338393900bb1e" - "08746573743339303000bc1e08746573743339303100bd1e08746573743339303200be1e08746573743339303300bf" - "1e08746573743339303400c01e08746573743339303500c11e08746573743339303600c21e08746573743339303700" - "c31e08746573743339303800c41e08746573743339303900c51e08746573743339313000c61e087465737433393131" - "00c71e08746573743339313200c81e08746573743339313300c91e08746573743339313400ca1e0874657374333931" - "3500cb1e08746573743339313600cc1e08746573743339313700cd1e08746573743339313800ce1e08746573743339" - "313900cf1e08746573743339323000d01e08746573743339323100d11e08746573743339323200d21e087465737433" - "39323300d31e08746573743339323400d41e08746573743339323500d51e08746573743339323600d61e0874657374" - "3339323700d71e08746573743339323800d81e08746573743339323900d91e08746573743339333000da1e08746573" - "743339333100db1e08746573743339333200dc1e08746573743339333300dd1e08746573743339333400de1e087465" - "73743339333500df1e08746573743339333600e01e08746573743339333700e11e08746573743339333800e21e0874" - "6573743339333900e31e08746573743339343000e41e08746573743339343100e51e08746573743339343200e61e08" - "746573743339343300e71e08746573743339343400e81e08746573743339343500e91e08746573743339343600ea1e" - "08746573743339343700eb1e08746573743339343800ec1e08746573743339343900ed1e08746573743339353000ee" - "1e08746573743339353100ef1e08746573743339353200f01e08746573743339353300f11e08746573743339353400" - "f21e08746573743339353500f31e08746573743339353600f41e08746573743339353700f51e087465737433393538" - "00f61e08746573743339353900f71e08746573743339363000f81e08746573743339363100f91e0874657374333936" - "3200fa1e08746573743339363300fb1e08746573743339363400fc1e08746573743339363500fd1e08746573743339" - "363600fe1e08746573743339363700ff1e08746573743339363800801f08746573743339363900811f087465737433" - "39373000821f08746573743339373100831f08746573743339373200841f08746573743339373300851f0874657374" - "3339373400861f08746573743339373500871f08746573743339373600881f08746573743339373700891f08746573" - "7433393738008a1f087465737433393739008b1f087465737433393830008c1f087465737433393831008d1f087465" - "737433393832008e1f087465737433393833008f1f08746573743339383400901f08746573743339383500911f0874" - "6573743339383600921f08746573743339383700931f08746573743339383800941f08746573743339383900951f08" - "746573743339393000961f08746573743339393100971f08746573743339393200981f08746573743339393300991f" - "087465737433393934009a1f087465737433393935009b1f087465737433393936009c1f087465737433393937009d" - "1f087465737433393938009e1f087465737433393939009f1f08746573743430303000a01f08746573743430303100" - "a11f08746573743430303200a21f08746573743430303300a31f08746573743430303400a41f087465737434303035" - "00a51f08746573743430303600a61f08746573743430303700a71f08746573743430303800a81f0874657374343030" - "3900a91f08746573743430313000aa1f08746573743430313100ab1f08746573743430313200ac1f08746573743430" - "313300ad1f08746573743430313400ae1f08746573743430313500af1f08746573743430313600b01f087465737434" - "30313700b11f08746573743430313800b21f08746573743430313900b31f08746573743430323000b41f0874657374" - "3430323100b51f08746573743430323200b61f08746573743430323300b71f08746573743430323400b81f08746573" - "743430323500b91f08746573743430323600ba1f08746573743430323700bb1f08746573743430323800bc1f087465" - "73743430323900bd1f08746573743430333000be1f08746573743430333100bf1f08746573743430333200c01f0874" - "6573743430333300c11f08746573743430333400c21f08746573743430333500c31f08746573743430333600c41f08" - "746573743430333700c51f08746573743430333800c61f08746573743430333900c71f08746573743430343000c81f" - "08746573743430343100c91f08746573743430343200ca1f08746573743430343300cb1f08746573743430343400cc" - "1f08746573743430343500cd1f08746573743430343600ce1f08746573743430343700cf1f08746573743430343800" - "d01f08746573743430343900d11f08746573743430353000d21f08746573743430353100d31f087465737434303532" - "00d41f08746573743430353300d51f08746573743430353400d61f08746573743430353500d71f0874657374343035" - "3600d81f08746573743430353700d91f08746573743430353800da1f08746573743430353900db1f08746573743430" - "363000dc1f08746573743430363100dd1f08746573743430363200de1f08746573743430363300df1f087465737434" - "30363400e01f08746573743430363500e11f08746573743430363600e21f08746573743430363700e31f0874657374" - "3430363800e41f08746573743430363900e51f08746573743430373000e61f08746573743430373100e71f08746573" - "743430373200e81f08746573743430373300e91f08746573743430373400ea1f08746573743430373500eb1f087465" - "73743430373600ec1f08746573743430373700ed1f08746573743430373800ee1f08746573743430373900ef1f0874" - "6573743430383000f01f08746573743430383100f11f08746573743430383200f21f08746573743430383300f31f08" - "746573743430383400f41f08746573743430383500f51f08746573743430383600f61f08746573743430383700f71f" - "08746573743430383800f81f08746573743430383900f91f08746573743430393000fa1f08746573743430393100fb" - "1f08746573743430393200fc1f08746573743430393300fd1f08746573743430393400fe1f08746573743430393500" - "ff1f087465737434303936008020087465737434303937008120087465737434303938008220087465737434303939" - "0083200874657374343130300084200874657374343130310085200874657374343130320086200874657374343130" - "33008720087465737434313034008820087465737434313035008920087465737434313036008a2008746573743431" - "3037008b20087465737434313038008c20087465737434313039008d20087465737434313130008e20087465737434" - "313131008f200874657374343131320090200874657374343131330091200874657374343131340092200874657374" - "3431313500932008746573743431313600942008746573743431313700952008746573743431313800962008746573" - "7434313139009720087465737434313230009820087465737434313231009920087465737434313232009a20087465" - "737434313233009b20087465737434313234009c20087465737434313235009d20087465737434313236009e200874" - "65737434313237009f2008746573743431323800a02008746573743431323900a12008746573743431333000a22008" - "746573743431333100a32008746573743431333200a42008746573743431333300a52008746573743431333400a620" - "08746573743431333500a72008746573743431333600a82008746573743431333700a92008746573743431333800aa" - "2008746573743431333900ab2008746573743431343000ac2008746573743431343100ad2008746573743431343200" - "ae2008746573743431343300af2008746573743431343400b02008746573743431343500b120087465737434313436" - "00b22008746573743431343700b32008746573743431343800b42008746573743431343900b5200874657374343135" - "3000b62008746573743431353100b72008746573743431353200b82008746573743431353300b92008746573743431" - "353400ba2008746573743431353500bb2008746573743431353600bc2008746573743431353700bd20087465737434" - "31353800be2008746573743431353900bf2008746573743431363000c02008746573743431363100c1200874657374" - "3431363200c22008746573743431363300c32008746573743431363400c42008746573743431363500c52008746573" - "743431363600c62008746573743431363700c72008746573743431363800c82008746573743431363900c920087465" - "73743431373000ca2008746573743431373100cb2008746573743431373200cc2008746573743431373300cd200874" - "6573743431373400ce2008746573743431373500cf2008746573743431373600d02008746573743431373700d12008" - "746573743431373800d22008746573743431373900d32008746573743431383000d42008746573743431383100d520" - "08746573743431383200d62008746573743431383300d72008746573743431383400d82008746573743431383500d9" - "2008746573743431383600da2008746573743431383700db2008746573743431383800dc2008746573743431383900" - "dd2008746573743431393000de2008746573743431393100df2008746573743431393200e020087465737434313933" - "00e12008746573743431393400e22008746573743431393500e32008746573743431393600e4200874657374343139" - "3700e52008746573743431393800e62008746573743431393900e72008746573743432303000e82008746573743432" - "303100e92008746573743432303200ea2008746573743432303300eb2008746573743432303400ec20087465737434" - "32303500ed2008746573743432303600ee2008746573743432303700ef2008746573743432303800f0200874657374" - "3432303900f12008746573743432313000f22008746573743432313100f32008746573743432313200f42008746573" - "743432313300f52008746573743432313400f62008746573743432313500f72008746573743432313600f820087465" - "73743432313700f92008746573743432313800fa2008746573743432313900fb2008746573743432323000fc200874" - "6573743432323100fd2008746573743432323200fe2008746573743432323300ff2008746573743432323400802108" - "7465737434323235008121087465737434323236008221087465737434323237008321087465737434323238008421" - "0874657374343232390085210874657374343233300086210874657374343233310087210874657374343233320088" - "21087465737434323333008921087465737434323334008a21087465737434323335008b2108746573743432333600" - "8c21087465737434323337008d21087465737434323338008e21087465737434323339008f21087465737434323430" - "0090210874657374343234310091210874657374343234320092210874657374343234330093210874657374343234" - "3400942108746573743432343500952108746573743432343600962108746573743432343700972108746573743432" - "3438009821087465737434323439009921087465737434323530009a21087465737434323531009b21087465737434" - "323532009c21087465737434323533009d21087465737434323534009e21087465737434323535009f210874657374" - "3432353600a02108746573743432353700a12108746573743432353800a22108746573743432353900a32108746573" - "743432363000a42108746573743432363100a52108746573743432363200a62108746573743432363300a721087465" - "73743432363400a82108746573743432363500a92108746573743432363600aa2108746573743432363700ab210874" - "6573743432363800ac2108746573743432363900ad2108746573743432373000ae2108746573743432373100af2108" - "746573743432373200b02108746573743432373300b12108746573743432373400b22108746573743432373500b321" - "08746573743432373600b42108746573743432373700b52108746573743432373800b62108746573743432373900b7" - "2108746573743432383000b82108746573743432383100b92108746573743432383200ba2108746573743432383300" - "bb2108746573743432383400bc2108746573743432383500bd2108746573743432383600be21087465737434323837" - "00bf2108746573743432383800c02108746573743432383900c12108746573743432393000c2210874657374343239" - "3100c32108746573743432393200c42108746573743432393300c52108746573743432393400c62108746573743432" - "393500c72108746573743432393600c82108746573743432393700c92108746573743432393800ca21087465737434" - "32393900cb2108746573743433303000cc2108746573743433303100cd2108746573743433303200ce210874657374" - "3433303300cf2108746573743433303400d02108746573743433303500d12108746573743433303600d22108746573" - "743433303700d32108746573743433303800d42108746573743433303900d52108746573743433313000d621087465" - "73743433313100d72108746573743433313200d82108746573743433313300d92108746573743433313400da210874" - "6573743433313500db2108746573743433313600dc2108746573743433313700dd2108746573743433313800de2108" - "746573743433313900df2108746573743433323000e02108746573743433323100e12108746573743433323200e221" - "08746573743433323300e32108746573743433323400e42108746573743433323500e52108746573743433323600e6" - "2108746573743433323700e72108746573743433323800e82108746573743433323900e92108746573743433333000" - "ea2108746573743433333100eb2108746573743433333200ec2108746573743433333300ed21087465737434333334" - "00ee2108746573743433333500ef2108746573743433333600f02108746573743433333700f1210874657374343333" - "3800f22108746573743433333900f32108746573743433343000f42108746573743433343100f52108746573743433" - "343200f62108746573743433343300f72108746573743433343400f82108746573743433343500f921087465737434" - "33343600fa2108746573743433343700fb2108746573743433343800fc2108746573743433343900fd210874657374" - "3433353000fe2108746573743433353100ff2108746573743433353200802208746573743433353300812208746573" - "7434333534008222087465737434333535008322087465737434333536008422087465737434333537008522087465" - "7374343335380086220874657374343335390087220874657374343336300088220874657374343336310089220874" - "65737434333632008a22087465737434333633008b22087465737434333634008c22087465737434333635008d2208" - "7465737434333636008e22087465737434333637008f22087465737434333638009022087465737434333639009122" - "0874657374343337300092220874657374343337310093220874657374343337320094220874657374343337330095" - "2208746573743433373400962208746573743433373500972208746573743433373600982208746573743433373700" - "9922087465737434333738009a22087465737434333739009b22087465737434333830009c22087465737434333831" - "009d22087465737434333832009e22087465737434333833009f2208746573743433383400a0220874657374343338" - "3500a12208746573743433383600a22208746573743433383700a32208746573743433383800a42208746573743433" - "383900a52208746573743433393000a62208746573743433393100a72208746573743433393200a822087465737434" - "33393300a92208746573743433393400aa2208746573743433393500ab2208746573743433393600ac220874657374" - "3433393700ad2208746573743433393800ae2208746573743433393900af2208746573743434303000b02208746573" - "743434303100b12208746573743434303200b22208746573743434303300b32208746573743434303400b422087465" - "73743434303500b52208746573743434303600b62208746573743434303700b72208746573743434303800b8220874" - "6573743434303900b92208746573743434313000ba2208746573743434313100bb2208746573743434313200bc2208" - "746573743434313300bd2208746573743434313400be2208746573743434313500bf2208746573743434313600c022" - "08746573743434313700c12208746573743434313800c22208746573743434313900c32208746573743434323000c4" - "2208746573743434323100c52208746573743434323200c62208746573743434323300c72208746573743434323400" - "c82208746573743434323500c92208746573743434323600ca2208746573743434323700cb22087465737434343238" - "00cc2208746573743434323900cd2208746573743434333000ce2208746573743434333100cf220874657374343433" - "3200d02208746573743434333300d12208746573743434333400d22208746573743434333500d32208746573743434" - "333600d42208746573743434333700d52208746573743434333800d62208746573743434333900d722087465737434" - "34343000d82208746573743434343100d92208746573743434343200da2208746573743434343300db220874657374" - "3434343400dc2208746573743434343500dd2208746573743434343600de2208746573743434343700df2208746573" - "743434343800e02208746573743434343900e12208746573743434353000e22208746573743434353100e322087465" - "73743434353200e42208746573743434353300e52208746573743434353400e62208746573743434353500e7220874" - "6573743434353600e82208746573743434353700e92208746573743434353800ea2208746573743434353900eb2208" - "746573743434363000ec2208746573743434363100ed2208746573743434363200ee2208746573743434363300ef22" - "08746573743434363400f02208746573743434363500f12208746573743434363600f22208746573743434363700f3" - "2208746573743434363800f42208746573743434363900f52208746573743434373000f62208746573743434373100" - "f72208746573743434373200f82208746573743434373300f92208746573743434373400fa22087465737434343735" - "00fb2208746573743434373600fc2208746573743434373700fd2208746573743434373800fe220874657374343437" - "3900ff2208746573743434383000802308746573743434383100812308746573743434383200822308746573743434" - "3833008323087465737434343834008423087465737434343835008523087465737434343836008623087465737434" - "343837008723087465737434343838008823087465737434343839008923087465737434343930008a230874657374" - "34343931008b23087465737434343932008c23087465737434343933008d23087465737434343934008e2308746573" - "7434343935008f23087465737434343936009023087465737434343937009123087465737434343938009223087465" - "7374343439390093230874657374343530300094230874657374343530310095230874657374343530320096230874" - "65737434353033009723087465737434353034009823087465737434353035009923087465737434353036009a2308" - "7465737434353037009b23087465737434353038009c23087465737434353039009d23087465737434353130009e23" - "087465737434353131009f2308746573743435313200a02308746573743435313300a12308746573743435313400a2" - "2308746573743435313500a32308746573743435313600a42308746573743435313700a52308746573743435313800" - "a62308746573743435313900a72308746573743435323000a82308746573743435323100a923087465737434353232" - "00aa2308746573743435323300ab2308746573743435323400ac2308746573743435323500ad230874657374343532" - "3600ae2308746573743435323700af2308746573743435323800b02308746573743435323900b12308746573743435" - "333000b22308746573743435333100b32308746573743435333200b42308746573743435333300b523087465737434" - "35333400b62308746573743435333500b72308746573743435333600b82308746573743435333700b9230874657374" - "3435333800ba2308746573743435333900bb2308746573743435343000bc2308746573743435343100bd2308746573" - "743435343200be2308746573743435343300bf2308746573743435343400c02308746573743435343500c123087465" - "73743435343600c22308746573743435343700c32308746573743435343800c42308746573743435343900c5230874" - "6573743435353000c62308746573743435353100c72308746573743435353200c82308746573743435353300c92308" - "746573743435353400ca2308746573743435353500cb2308746573743435353600cc2308746573743435353700cd23" - "08746573743435353800ce2308746573743435353900cf2308746573743435363000d02308746573743435363100d1" - "2308746573743435363200d22308746573743435363300d32308746573743435363400d42308746573743435363500" - "d52308746573743435363600d62308746573743435363700d72308746573743435363800d823087465737434353639" - "00d92308746573743435373000da2308746573743435373100db2308746573743435373200dc230874657374343537" - "3300dd2308746573743435373400de2308746573743435373500df2308746573743435373600e02308746573743435" - "373700e12308746573743435373800e22308746573743435373900e32308746573743435383000e423087465737434" - "35383100e52308746573743435383200e62308746573743435383300e72308746573743435383400e8230874657374" - "3435383500e92308746573743435383600ea2308746573743435383700eb2308746573743435383800ec2308746573" - "743435383900ed2308746573743435393000ee2308746573743435393100ef2308746573743435393200f023087465" - "73743435393300f12308746573743435393400f22308746573743435393500f32308746573743435393600f4230874" - "6573743435393700f52308746573743435393800f62308746573743435393900f72308746573743436303000f82308" - "746573743436303100f92308746573743436303200fa2308746573743436303300fb2308746573743436303400fc23" - "08746573743436303500fd2308746573743436303600fe2308746573743436303700ff230874657374343630380080" - "2408746573743436303900812408746573743436313000822408746573743436313100832408746573743436313200" - "8424087465737434363133008524087465737434363134008624087465737434363135008724087465737434363136" - "008824087465737434363137008924087465737434363138008a24087465737434363139008b240874657374343632" - "30008c24087465737434363231008d24087465737434363232008e24087465737434363233008f2408746573743436" - "3234009024087465737434363235009124087465737434363236009224087465737434363237009324087465737434" - "3632380094240874657374343632390095240874657374343633300096240874657374343633310097240874657374" - "34363332009824087465737434363333009924087465737434363334009a24087465737434363335009b2408746573" - "7434363336009c24087465737434363337009d24087465737434363338009e24087465737434363339009f24087465" - "73743436343000a02408746573743436343100a12408746573743436343200a22408746573743436343300a3240874" - "6573743436343400a42408746573743436343500a52408746573743436343600a62408746573743436343700a72408" - "746573743436343800a82408746573743436343900a92408746573743436353000aa2408746573743436353100ab24" - "08746573743436353200ac2408746573743436353300ad2408746573743436353400ae2408746573743436353500af" - "2408746573743436353600b02408746573743436353700b12408746573743436353800b22408746573743436353900" - "b32408746573743436363000b42408746573743436363100b52408746573743436363200b624087465737434363633" - "00b72408746573743436363400b82408746573743436363500b92408746573743436363600ba240874657374343636" - "3700bb2408746573743436363800bc2408746573743436363900bd2408746573743436373000be2408746573743436" - "373100bf2408746573743436373200c02408746573743436373300c12408746573743436373400c224087465737434" - "36373500c32408746573743436373600c42408746573743436373700c52408746573743436373800c6240874657374" - "3436373900c72408746573743436383000c82408746573743436383100c92408746573743436383200ca2408746573" - "743436383300cb2408746573743436383400cc2408746573743436383500cd2408746573743436383600ce24087465" - "73743436383700cf2408746573743436383800d02408746573743436383900d12408746573743436393000d2240874" - "6573743436393100d32408746573743436393200d42408746573743436393300d52408746573743436393400d62408" - "746573743436393500d72408746573743436393600d82408746573743436393700d92408746573743436393800da24" - "08746573743436393900db2408746573743437303000dc2408746573743437303100dd2408746573743437303200de" - "2408746573743437303300df2408746573743437303400e02408746573743437303500e12408746573743437303600" - "e22408746573743437303700e32408746573743437303800e42408746573743437303900e524087465737434373130" - "00e62408746573743437313100e72408746573743437313200e82408746573743437313300e9240874657374343731" - "3400ea2408746573743437313500eb2408746573743437313600ec2408746573743437313700ed2408746573743437" - "313800ee2408746573743437313900ef2408746573743437323000f02408746573743437323100f124087465737434" - "37323200f22408746573743437323300f32408746573743437323400f42408746573743437323500f5240874657374" - "3437323600f62408746573743437323700f72408746573743437323800f82408746573743437323900f92408746573" - "743437333000fa2408746573743437333100fb2408746573743437333200fc2408746573743437333300fd24087465" - "73743437333400fe2408746573743437333500ff240874657374343733360080250874657374343733370081250874" - "6573743437333800822508746573743437333900832508746573743437343000842508746573743437343100852508" - "7465737434373432008625087465737434373433008725087465737434373434008825087465737434373435008925" - "087465737434373436008a25087465737434373437008b25087465737434373438008c25087465737434373439008d" - "25087465737434373530008e25087465737434373531008f2508746573743437353200902508746573743437353300" - "9125087465737434373534009225087465737434373535009325087465737434373536009425087465737434373537" - "0095250874657374343735380096250874657374343735390097250874657374343736300098250874657374343736" - "31009925087465737434373632009a25087465737434373633009b25087465737434373634009c2508746573743437" - "3635009d25087465737434373636009e25087465737434373637009f2508746573743437363800a025087465737434" - "37363900a12508746573743437373000a22508746573743437373100a32508746573743437373200a4250874657374" - "3437373300a52508746573743437373400a62508746573743437373500a72508746573743437373600a82508746573" - "743437373700a92508746573743437373800aa2508746573743437373900ab2508746573743437383000ac25087465" - "73743437383100ad2508746573743437383200ae2508746573743437383300af2508746573743437383400b0250874" - "6573743437383500b12508746573743437383600b22508746573743437383700b32508746573743437383800b42508" - "746573743437383900b52508746573743437393000b62508746573743437393100b72508746573743437393200b825" - "08746573743437393300b92508746573743437393400ba2508746573743437393500bb2508746573743437393600bc" - "2508746573743437393700bd2508746573743437393800be2508746573743437393900bf2508746573743438303000" - "c02508746573743438303100c12508746573743438303200c22508746573743438303300c325087465737434383034" - "00c42508746573743438303500c52508746573743438303600c62508746573743438303700c7250874657374343830" - "3800c82508746573743438303900c92508746573743438313000ca2508746573743438313100cb2508746573743438" - "313200cc2508746573743438313300cd2508746573743438313400ce2508746573743438313500cf25087465737434" - "38313600d02508746573743438313700d12508746573743438313800d22508746573743438313900d3250874657374" - "3438323000d42508746573743438323100d52508746573743438323200d62508746573743438323300d72508746573" - "743438323400d82508746573743438323500d92508746573743438323600da2508746573743438323700db25087465" - "73743438323800dc2508746573743438323900dd2508746573743438333000de2508746573743438333100df250874" - "6573743438333200e02508746573743438333300e12508746573743438333400e22508746573743438333500e32508" - "746573743438333600e42508746573743438333700e52508746573743438333800e62508746573743438333900e725" - "08746573743438343000e82508746573743438343100e92508746573743438343200ea2508746573743438343300eb" - "2508746573743438343400ec2508746573743438343500ed2508746573743438343600ee2508746573743438343700" - "ef2508746573743438343800f02508746573743438343900f12508746573743438353000f225087465737434383531" - "00f32508746573743438353200f42508746573743438353300f52508746573743438353400f6250874657374343835" - "3500f72508746573743438353600f82508746573743438353700f92508746573743438353800fa2508746573743438" - "353900fb2508746573743438363000fc2508746573743438363100fd2508746573743438363200fe25087465737434" - "38363300ff250874657374343836340080260874657374343836350081260874657374343836360082260874657374" - "3438363700832608746573743438363800842608746573743438363900852608746573743438373000862608746573" - "7434383731008726087465737434383732008826087465737434383733008926087465737434383734008a26087465" - "737434383735008b26087465737434383736008c26087465737434383737008d26087465737434383738008e260874" - "65737434383739008f2608746573743438383000902608746573743438383100912608746573743438383200922608" - "7465737434383833009326087465737434383834009426087465737434383835009526087465737434383836009626" - "087465737434383837009726087465737434383838009826087465737434383839009926087465737434383930009a" - "26087465737434383931009b26087465737434383932009c26087465737434383933009d2608746573743438393400" - "9e26087465737434383935009f2608746573743438393600a02608746573743438393700a126087465737434383938" - "00a22608746573743438393900a32608746573743439303000a42608746573743439303100a5260874657374343930" - "3200a62608746573743439303300a72608746573743439303400a82608746573743439303500a92608746573743439" - "303600aa2608746573743439303700ab2608746573743439303800ac2608746573743439303900ad26087465737434" - "39313000ae2608746573743439313100af2608746573743439313200b02608746573743439313300b1260874657374" - "3439313400b22608746573743439313500b32608746573743439313600b42608746573743439313700b52608746573" - "743439313800b62608746573743439313900b72608746573743439323000b82608746573743439323100b926087465" - "73743439323200ba2608746573743439323300bb2608746573743439323400bc2608746573743439323500bd260874" - "6573743439323600be2608746573743439323700bf2608746573743439323800c02608746573743439323900c12608" - "746573743439333000c22608746573743439333100c32608746573743439333200c42608746573743439333300c526" - "08746573743439333400c62608746573743439333500c72608746573743439333600c82608746573743439333700c9" - "2608746573743439333800ca2608746573743439333900cb2608746573743439343000cc2608746573743439343100" - "cd2608746573743439343200ce2608746573743439343300cf2608746573743439343400d026087465737434393435" - "00d12608746573743439343600d22608746573743439343700d32608746573743439343800d4260874657374343934" - "3900d52608746573743439353000d62608746573743439353100d72608746573743439353200d82608746573743439" - "353300d92608746573743439353400da2608746573743439353500db2608746573743439353600dc26087465737434" - "39353700dd2608746573743439353800de2608746573743439353900df2608746573743439363000e0260874657374" - "3439363100e12608746573743439363200e22608746573743439363300e32608746573743439363400e42608746573" - "743439363500e52608746573743439363600e62608746573743439363700e72608746573743439363800e826087465" - "73743439363900e92608746573743439373000ea2608746573743439373100eb2608746573743439373200ec260874" - "6573743439373300ed2608746573743439373400ee2608746573743439373500ef2608746573743439373600f02608" - "746573743439373700f12608746573743439373800f22608746573743439373900f32608746573743439383000f426" - "08746573743439383100f52608746573743439383200f62608746573743439383300f72608746573743439383400f8" - "2608746573743439383500f92608746573743439383600fa2608746573743439383700fb2608746573743439383800" - "fc2608746573743439383900fd2608746573743439393000fe2608746573743439393100ff26087465737434393932" - "0080270874657374343939330081270874657374343939340082270874657374343939350083270874657374343939" - "360084270874657374343939370085270874657374343939380086270874657374343939390087270ac2b802882707" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020" - "016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07002000" - "20016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020" - "0020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700" - "200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b07" - "00200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b" - "0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a" - "0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b0700200020016a0b070020002001" - "6a0b"; diff --git a/src/test/app/wasm_fixtures/fixture_locals_10k.cpp b/src/test/app/wasm_fixtures/fixture_locals_10k.cpp deleted file mode 100644 index 75a799243d..0000000000 --- a/src/test/app/wasm_fixtures/fixture_locals_10k.cpp +++ /dev/null @@ -1,2128 +0,0 @@ -// TODO: consider moving these to separate files (and figure out the build) - -#include - -#include - -extern std::string const kLocals10kHex = - "0061736d0100000001070160027f7f017f03020100070801047465737400000a9b8a0601978a06018e4e7f20002001" - "6a2102200120026a2103200220036a2104200320046a2105200420056a2106200520066a2107200620076a21082007" - "20086a2109200820096a210a2009200a6a210b200a200b6a210c200b200c6a210d200c200d6a210e200d200e6a210f" - "200e200f6a2110200f20106a2111201020116a2112201120126a2113201220136a2114201320146a2115201420156a" - "2116201520166a2117201620176a2118201720186a2119201820196a211a2019201a6a211b201a201b6a211c201b20" - "1c6a211d201c201d6a211e201d201e6a211f201e201f6a2120201f20206a2121202020216a2122202120226a212320" - "2220236a2124202320246a2125202420256a2126202520266a2127202620276a2128202720286a2129202820296a21" - "2a2029202a6a212b202a202b6a212c202b202c6a212d202c202d6a212e202d202e6a212f202e202f6a2130202f2030" - "6a2131203020316a2132203120326a2133203220336a2134203320346a2135203420356a2136203520366a21372036" - "20376a2138203720386a2139203820396a213a2039203a6a213b203a203b6a213c203b203c6a213d203c203d6a213e" - "203d203e6a213f203e203f6a2140203f20406a2141204020416a2142204120426a2143204220436a2144204320446a" - "2145204420456a2146204520466a2147204620476a2148204720486a2149204820496a214a2049204a6a214b204a20" - "4b6a214c204b204c6a214d204c204d6a214e204d204e6a214f204e204f6a2150204f20506a2151205020516a215220" - "5120526a2153205220536a2154205320546a2155205420556a2156205520566a2157205620576a2158205720586a21" - "59205820596a215a2059205a6a215b205a205b6a215c205b205c6a215d205c205d6a215e205d205e6a215f205e205f" - "6a2160205f20606a2161206020616a2162206120626a2163206220636a2164206320646a2165206420656a21662065" - "20666a2167206620676a2168206720686a2169206820696a216a2069206a6a216b206a206b6a216c206b206c6a216d" - "206c206d6a216e206d206e6a216f206e206f6a2170206f20706a2171207020716a2172207120726a2173207220736a" - "2174207320746a2175207420756a2176207520766a2177207620776a2178207720786a2179207820796a217a207920" - "7a6a217b207a207b6a217c207b207c6a217d207c207d6a217e207d207e6a217f207e207f6a218001207f2080016a21" - "81012080012081016a2182012081012082016a2183012082012083016a2184012083012084016a2185012084012085" - "016a2186012085012086016a2187012086012087016a2188012087012088016a2189012088012089016a218a012089" - "01208a016a218b01208a01208b016a218c01208b01208c016a218d01208c01208d016a218e01208d01208e016a218f" - "01208e01208f016a219001208f012090016a2191012090012091016a2192012091012092016a219301209201209301" - "6a2194012093012094016a2195012094012095016a2196012095012096016a2197012096012097016a219801209701" - "2098016a2199012098012099016a219a01209901209a016a219b01209a01209b016a219c01209b01209c016a219d01" - "209c01209d016a219e01209d01209e016a219f01209e01209f016a21a001209f0120a0016a21a10120a00120a1016a" - "21a20120a10120a2016a21a30120a20120a3016a21a40120a30120a4016a21a50120a40120a5016a21a60120a50120" - "a6016a21a70120a60120a7016a21a80120a70120a8016a21a90120a80120a9016a21aa0120a90120aa016a21ab0120" - "aa0120ab016a21ac0120ab0120ac016a21ad0120ac0120ad016a21ae0120ad0120ae016a21af0120ae0120af016a21" - "b00120af0120b0016a21b10120b00120b1016a21b20120b10120b2016a21b30120b20120b3016a21b40120b30120b4" - "016a21b50120b40120b5016a21b60120b50120b6016a21b70120b60120b7016a21b80120b70120b8016a21b90120b8" - "0120b9016a21ba0120b90120ba016a21bb0120ba0120bb016a21bc0120bb0120bc016a21bd0120bc0120bd016a21be" - "0120bd0120be016a21bf0120be0120bf016a21c00120bf0120c0016a21c10120c00120c1016a21c20120c10120c201" - "6a21c30120c20120c3016a21c40120c30120c4016a21c50120c40120c5016a21c60120c50120c6016a21c70120c601" - "20c7016a21c80120c70120c8016a21c90120c80120c9016a21ca0120c90120ca016a21cb0120ca0120cb016a21cc01" - "20cb0120cc016a21cd0120cc0120cd016a21ce0120cd0120ce016a21cf0120ce0120cf016a21d00120cf0120d0016a" - "21d10120d00120d1016a21d20120d10120d2016a21d30120d20120d3016a21d40120d30120d4016a21d50120d40120" - "d5016a21d60120d50120d6016a21d70120d60120d7016a21d80120d70120d8016a21d90120d80120d9016a21da0120" - "d90120da016a21db0120da0120db016a21dc0120db0120dc016a21dd0120dc0120dd016a21de0120dd0120de016a21" - "df0120de0120df016a21e00120df0120e0016a21e10120e00120e1016a21e20120e10120e2016a21e30120e20120e3" - "016a21e40120e30120e4016a21e50120e40120e5016a21e60120e50120e6016a21e70120e60120e7016a21e80120e7" - "0120e8016a21e90120e80120e9016a21ea0120e90120ea016a21eb0120ea0120eb016a21ec0120eb0120ec016a21ed" - "0120ec0120ed016a21ee0120ed0120ee016a21ef0120ee0120ef016a21f00120ef0120f0016a21f10120f00120f101" - "6a21f20120f10120f2016a21f30120f20120f3016a21f40120f30120f4016a21f50120f40120f5016a21f60120f501" - "20f6016a21f70120f60120f7016a21f80120f70120f8016a21f90120f80120f9016a21fa0120f90120fa016a21fb01" - "20fa0120fb016a21fc0120fb0120fc016a21fd0120fc0120fd016a21fe0120fd0120fe016a21ff0120fe0120ff016a" - "21800220ff012080026a2181022080022081026a2182022081022082026a2183022082022083026a21840220830220" - "84026a2185022084022085026a2186022085022086026a2187022086022087026a2188022087022088026a21890220" - "88022089026a218a02208902208a026a218b02208a02208b026a218c02208b02208c026a218d02208c02208d026a21" - "8e02208d02208e026a218f02208e02208f026a219002208f022090026a2191022090022091026a2192022091022092" - "026a2193022092022093026a2194022093022094026a2195022094022095026a2196022095022096026a2197022096" - "022097026a2198022097022098026a2199022098022099026a219a02209902209a026a219b02209a02209b026a219c" - "02209b02209c026a219d02209c02209d026a219e02209d02209e026a219f02209e02209f026a21a002209f0220a002" - "6a21a10220a00220a1026a21a20220a10220a2026a21a30220a20220a3026a21a40220a30220a4026a21a50220a402" - "20a5026a21a60220a50220a6026a21a70220a60220a7026a21a80220a70220a8026a21a90220a80220a9026a21aa02" - "20a90220aa026a21ab0220aa0220ab026a21ac0220ab0220ac026a21ad0220ac0220ad026a21ae0220ad0220ae026a" - "21af0220ae0220af026a21b00220af0220b0026a21b10220b00220b1026a21b20220b10220b2026a21b30220b20220" - "b3026a21b40220b30220b4026a21b50220b40220b5026a21b60220b50220b6026a21b70220b60220b7026a21b80220" - "b70220b8026a21b90220b80220b9026a21ba0220b90220ba026a21bb0220ba0220bb026a21bc0220bb0220bc026a21" - "bd0220bc0220bd026a21be0220bd0220be026a21bf0220be0220bf026a21c00220bf0220c0026a21c10220c00220c1" - "026a21c20220c10220c2026a21c30220c20220c3026a21c40220c30220c4026a21c50220c40220c5026a21c60220c5" - "0220c6026a21c70220c60220c7026a21c80220c70220c8026a21c90220c80220c9026a21ca0220c90220ca026a21cb" - "0220ca0220cb026a21cc0220cb0220cc026a21cd0220cc0220cd026a21ce0220cd0220ce026a21cf0220ce0220cf02" - "6a21d00220cf0220d0026a21d10220d00220d1026a21d20220d10220d2026a21d30220d20220d3026a21d40220d302" - "20d4026a21d50220d40220d5026a21d60220d50220d6026a21d70220d60220d7026a21d80220d70220d8026a21d902" - "20d80220d9026a21da0220d90220da026a21db0220da0220db026a21dc0220db0220dc026a21dd0220dc0220dd026a" - "21de0220dd0220de026a21df0220de0220df026a21e00220df0220e0026a21e10220e00220e1026a21e20220e10220" - "e2026a21e30220e20220e3026a21e40220e30220e4026a21e50220e40220e5026a21e60220e50220e6026a21e70220" - "e60220e7026a21e80220e70220e8026a21e90220e80220e9026a21ea0220e90220ea026a21eb0220ea0220eb026a21" - "ec0220eb0220ec026a21ed0220ec0220ed026a21ee0220ed0220ee026a21ef0220ee0220ef026a21f00220ef0220f0" - "026a21f10220f00220f1026a21f20220f10220f2026a21f30220f20220f3026a21f40220f30220f4026a21f50220f4" - "0220f5026a21f60220f50220f6026a21f70220f60220f7026a21f80220f70220f8026a21f90220f80220f9026a21fa" - "0220f90220fa026a21fb0220fa0220fb026a21fc0220fb0220fc026a21fd0220fc0220fd026a21fe0220fd0220fe02" - "6a21ff0220fe0220ff026a21800320ff022080036a2181032080032081036a2182032081032082036a218303208203" - "2083036a2184032083032084036a2185032084032085036a2186032085032086036a2187032086032087036a218803" - "2087032088036a2189032088032089036a218a03208903208a036a218b03208a03208b036a218c03208b03208c036a" - "218d03208c03208d036a218e03208d03208e036a218f03208e03208f036a219003208f032090036a21910320900320" - "91036a2192032091032092036a2193032092032093036a2194032093032094036a2195032094032095036a21960320" - "95032096036a2197032096032097036a2198032097032098036a2199032098032099036a219a03209903209a036a21" - "9b03209a03209b036a219c03209b03209c036a219d03209c03209d036a219e03209d03209e036a219f03209e03209f" - "036a21a003209f0320a0036a21a10320a00320a1036a21a20320a10320a2036a21a30320a20320a3036a21a40320a3" - "0320a4036a21a50320a40320a5036a21a60320a50320a6036a21a70320a60320a7036a21a80320a70320a8036a21a9" - "0320a80320a9036a21aa0320a90320aa036a21ab0320aa0320ab036a21ac0320ab0320ac036a21ad0320ac0320ad03" - "6a21ae0320ad0320ae036a21af0320ae0320af036a21b00320af0320b0036a21b10320b00320b1036a21b20320b103" - "20b2036a21b30320b20320b3036a21b40320b30320b4036a21b50320b40320b5036a21b60320b50320b6036a21b703" - "20b60320b7036a21b80320b70320b8036a21b90320b80320b9036a21ba0320b90320ba036a21bb0320ba0320bb036a" - "21bc0320bb0320bc036a21bd0320bc0320bd036a21be0320bd0320be036a21bf0320be0320bf036a21c00320bf0320" - "c0036a21c10320c00320c1036a21c20320c10320c2036a21c30320c20320c3036a21c40320c30320c4036a21c50320" - "c40320c5036a21c60320c50320c6036a21c70320c60320c7036a21c80320c70320c8036a21c90320c80320c9036a21" - "ca0320c90320ca036a21cb0320ca0320cb036a21cc0320cb0320cc036a21cd0320cc0320cd036a21ce0320cd0320ce" - "036a21cf0320ce0320cf036a21d00320cf0320d0036a21d10320d00320d1036a21d20320d10320d2036a21d30320d2" - "0320d3036a21d40320d30320d4036a21d50320d40320d5036a21d60320d50320d6036a21d70320d60320d7036a21d8" - "0320d70320d8036a21d90320d80320d9036a21da0320d90320da036a21db0320da0320db036a21dc0320db0320dc03" - "6a21dd0320dc0320dd036a21de0320dd0320de036a21df0320de0320df036a21e00320df0320e0036a21e10320e003" - "20e1036a21e20320e10320e2036a21e30320e20320e3036a21e40320e30320e4036a21e50320e40320e5036a21e603" - "20e50320e6036a21e70320e60320e7036a21e80320e70320e8036a21e90320e80320e9036a21ea0320e90320ea036a" - "21eb0320ea0320eb036a21ec0320eb0320ec036a21ed0320ec0320ed036a21ee0320ed0320ee036a21ef0320ee0320" - "ef036a21f00320ef0320f0036a21f10320f00320f1036a21f20320f10320f2036a21f30320f20320f3036a21f40320" - "f30320f4036a21f50320f40320f5036a21f60320f50320f6036a21f70320f60320f7036a21f80320f70320f8036a21" - "f90320f80320f9036a21fa0320f90320fa036a21fb0320fa0320fb036a21fc0320fb0320fc036a21fd0320fc0320fd" - "036a21fe0320fd0320fe036a21ff0320fe0320ff036a21800420ff032080046a2181042080042081046a2182042081" - "042082046a2183042082042083046a2184042083042084046a2185042084042085046a2186042085042086046a2187" - "042086042087046a2188042087042088046a2189042088042089046a218a04208904208a046a218b04208a04208b04" - "6a218c04208b04208c046a218d04208c04208d046a218e04208d04208e046a218f04208e04208f046a219004208f04" - "2090046a2191042090042091046a2192042091042092046a2193042092042093046a2194042093042094046a219504" - "2094042095046a2196042095042096046a2197042096042097046a2198042097042098046a2199042098042099046a" - "219a04209904209a046a219b04209a04209b046a219c04209b04209c046a219d04209c04209d046a219e04209d0420" - "9e046a219f04209e04209f046a21a004209f0420a0046a21a10420a00420a1046a21a20420a10420a2046a21a30420" - "a20420a3046a21a40420a30420a4046a21a50420a40420a5046a21a60420a50420a6046a21a70420a60420a7046a21" - "a80420a70420a8046a21a90420a80420a9046a21aa0420a90420aa046a21ab0420aa0420ab046a21ac0420ab0420ac" - "046a21ad0420ac0420ad046a21ae0420ad0420ae046a21af0420ae0420af046a21b00420af0420b0046a21b10420b0" - "0420b1046a21b20420b10420b2046a21b30420b20420b3046a21b40420b30420b4046a21b50420b40420b5046a21b6" - "0420b50420b6046a21b70420b60420b7046a21b80420b70420b8046a21b90420b80420b9046a21ba0420b90420ba04" - "6a21bb0420ba0420bb046a21bc0420bb0420bc046a21bd0420bc0420bd046a21be0420bd0420be046a21bf0420be04" - "20bf046a21c00420bf0420c0046a21c10420c00420c1046a21c20420c10420c2046a21c30420c20420c3046a21c404" - "20c30420c4046a21c50420c40420c5046a21c60420c50420c6046a21c70420c60420c7046a21c80420c70420c8046a" - "21c90420c80420c9046a21ca0420c90420ca046a21cb0420ca0420cb046a21cc0420cb0420cc046a21cd0420cc0420" - "cd046a21ce0420cd0420ce046a21cf0420ce0420cf046a21d00420cf0420d0046a21d10420d00420d1046a21d20420" - "d10420d2046a21d30420d20420d3046a21d40420d30420d4046a21d50420d40420d5046a21d60420d50420d6046a21" - "d70420d60420d7046a21d80420d70420d8046a21d90420d80420d9046a21da0420d90420da046a21db0420da0420db" - "046a21dc0420db0420dc046a21dd0420dc0420dd046a21de0420dd0420de046a21df0420de0420df046a21e00420df" - "0420e0046a21e10420e00420e1046a21e20420e10420e2046a21e30420e20420e3046a21e40420e30420e4046a21e5" - "0420e40420e5046a21e60420e50420e6046a21e70420e60420e7046a21e80420e70420e8046a21e90420e80420e904" - "6a21ea0420e90420ea046a21eb0420ea0420eb046a21ec0420eb0420ec046a21ed0420ec0420ed046a21ee0420ed04" - "20ee046a21ef0420ee0420ef046a21f00420ef0420f0046a21f10420f00420f1046a21f20420f10420f2046a21f304" - "20f20420f3046a21f40420f30420f4046a21f50420f40420f5046a21f60420f50420f6046a21f70420f60420f7046a" - "21f80420f70420f8046a21f90420f80420f9046a21fa0420f90420fa046a21fb0420fa0420fb046a21fc0420fb0420" - "fc046a21fd0420fc0420fd046a21fe0420fd0420fe046a21ff0420fe0420ff046a21800520ff042080056a21810520" - "80052081056a2182052081052082056a2183052082052083056a2184052083052084056a2185052084052085056a21" - "86052085052086056a2187052086052087056a2188052087052088056a2189052088052089056a218a05208905208a" - "056a218b05208a05208b056a218c05208b05208c056a218d05208c05208d056a218e05208d05208e056a218f05208e" - "05208f056a219005208f052090056a2191052090052091056a2192052091052092056a2193052092052093056a2194" - "052093052094056a2195052094052095056a2196052095052096056a2197052096052097056a219805209705209805" - "6a2199052098052099056a219a05209905209a056a219b05209a05209b056a219c05209b05209c056a219d05209c05" - "209d056a219e05209d05209e056a219f05209e05209f056a21a005209f0520a0056a21a10520a00520a1056a21a205" - "20a10520a2056a21a30520a20520a3056a21a40520a30520a4056a21a50520a40520a5056a21a60520a50520a6056a" - "21a70520a60520a7056a21a80520a70520a8056a21a90520a80520a9056a21aa0520a90520aa056a21ab0520aa0520" - "ab056a21ac0520ab0520ac056a21ad0520ac0520ad056a21ae0520ad0520ae056a21af0520ae0520af056a21b00520" - "af0520b0056a21b10520b00520b1056a21b20520b10520b2056a21b30520b20520b3056a21b40520b30520b4056a21" - "b50520b40520b5056a21b60520b50520b6056a21b70520b60520b7056a21b80520b70520b8056a21b90520b80520b9" - "056a21ba0520b90520ba056a21bb0520ba0520bb056a21bc0520bb0520bc056a21bd0520bc0520bd056a21be0520bd" - "0520be056a21bf0520be0520bf056a21c00520bf0520c0056a21c10520c00520c1056a21c20520c10520c2056a21c3" - "0520c20520c3056a21c40520c30520c4056a21c50520c40520c5056a21c60520c50520c6056a21c70520c60520c705" - "6a21c80520c70520c8056a21c90520c80520c9056a21ca0520c90520ca056a21cb0520ca0520cb056a21cc0520cb05" - "20cc056a21cd0520cc0520cd056a21ce0520cd0520ce056a21cf0520ce0520cf056a21d00520cf0520d0056a21d105" - "20d00520d1056a21d20520d10520d2056a21d30520d20520d3056a21d40520d30520d4056a21d50520d40520d5056a" - "21d60520d50520d6056a21d70520d60520d7056a21d80520d70520d8056a21d90520d80520d9056a21da0520d90520" - "da056a21db0520da0520db056a21dc0520db0520dc056a21dd0520dc0520dd056a21de0520dd0520de056a21df0520" - "de0520df056a21e00520df0520e0056a21e10520e00520e1056a21e20520e10520e2056a21e30520e20520e3056a21" - "e40520e30520e4056a21e50520e40520e5056a21e60520e50520e6056a21e70520e60520e7056a21e80520e70520e8" - "056a21e90520e80520e9056a21ea0520e90520ea056a21eb0520ea0520eb056a21ec0520eb0520ec056a21ed0520ec" - "0520ed056a21ee0520ed0520ee056a21ef0520ee0520ef056a21f00520ef0520f0056a21f10520f00520f1056a21f2" - "0520f10520f2056a21f30520f20520f3056a21f40520f30520f4056a21f50520f40520f5056a21f60520f50520f605" - "6a21f70520f60520f7056a21f80520f70520f8056a21f90520f80520f9056a21fa0520f90520fa056a21fb0520fa05" - "20fb056a21fc0520fb0520fc056a21fd0520fc0520fd056a21fe0520fd0520fe056a21ff0520fe0520ff056a218006" - "20ff052080066a2181062080062081066a2182062081062082066a2183062082062083066a2184062083062084066a" - "2185062084062085066a2186062085062086066a2187062086062087066a2188062087062088066a21890620880620" - "89066a218a06208906208a066a218b06208a06208b066a218c06208b06208c066a218d06208c06208d066a218e0620" - "8d06208e066a218f06208e06208f066a219006208f062090066a2191062090062091066a2192062091062092066a21" - "93062092062093066a2194062093062094066a2195062094062095066a2196062095062096066a2197062096062097" - "066a2198062097062098066a2199062098062099066a219a06209906209a066a219b06209a06209b066a219c06209b" - "06209c066a219d06209c06209d066a219e06209d06209e066a219f06209e06209f066a21a006209f0620a0066a21a1" - "0620a00620a1066a21a20620a10620a2066a21a30620a20620a3066a21a40620a30620a4066a21a50620a40620a506" - "6a21a60620a50620a6066a21a70620a60620a7066a21a80620a70620a8066a21a90620a80620a9066a21aa0620a906" - "20aa066a21ab0620aa0620ab066a21ac0620ab0620ac066a21ad0620ac0620ad066a21ae0620ad0620ae066a21af06" - "20ae0620af066a21b00620af0620b0066a21b10620b00620b1066a21b20620b10620b2066a21b30620b20620b3066a" - "21b40620b30620b4066a21b50620b40620b5066a21b60620b50620b6066a21b70620b60620b7066a21b80620b70620" - "b8066a21b90620b80620b9066a21ba0620b90620ba066a21bb0620ba0620bb066a21bc0620bb0620bc066a21bd0620" - "bc0620bd066a21be0620bd0620be066a21bf0620be0620bf066a21c00620bf0620c0066a21c10620c00620c1066a21" - "c20620c10620c2066a21c30620c20620c3066a21c40620c30620c4066a21c50620c40620c5066a21c60620c50620c6" - "066a21c70620c60620c7066a21c80620c70620c8066a21c90620c80620c9066a21ca0620c90620ca066a21cb0620ca" - "0620cb066a21cc0620cb0620cc066a21cd0620cc0620cd066a21ce0620cd0620ce066a21cf0620ce0620cf066a21d0" - "0620cf0620d0066a21d10620d00620d1066a21d20620d10620d2066a21d30620d20620d3066a21d40620d30620d406" - "6a21d50620d40620d5066a21d60620d50620d6066a21d70620d60620d7066a21d80620d70620d8066a21d90620d806" - "20d9066a21da0620d90620da066a21db0620da0620db066a21dc0620db0620dc066a21dd0620dc0620dd066a21de06" - "20dd0620de066a21df0620de0620df066a21e00620df0620e0066a21e10620e00620e1066a21e20620e10620e2066a" - "21e30620e20620e3066a21e40620e30620e4066a21e50620e40620e5066a21e60620e50620e6066a21e70620e60620" - "e7066a21e80620e70620e8066a21e90620e80620e9066a21ea0620e90620ea066a21eb0620ea0620eb066a21ec0620" - "eb0620ec066a21ed0620ec0620ed066a21ee0620ed0620ee066a21ef0620ee0620ef066a21f00620ef0620f0066a21" - "f10620f00620f1066a21f20620f10620f2066a21f30620f20620f3066a21f40620f30620f4066a21f50620f40620f5" - "066a21f60620f50620f6066a21f70620f60620f7066a21f80620f70620f8066a21f90620f80620f9066a21fa0620f9" - "0620fa066a21fb0620fa0620fb066a21fc0620fb0620fc066a21fd0620fc0620fd066a21fe0620fd0620fe066a21ff" - "0620fe0620ff066a21800720ff062080076a2181072080072081076a2182072081072082076a218307208207208307" - "6a2184072083072084076a2185072084072085076a2186072085072086076a2187072086072087076a218807208707" - "2088076a2189072088072089076a218a07208907208a076a218b07208a07208b076a218c07208b07208c076a218d07" - "208c07208d076a218e07208d07208e076a218f07208e07208f076a219007208f072090076a2191072090072091076a" - "2192072091072092076a2193072092072093076a2194072093072094076a2195072094072095076a21960720950720" - "96076a2197072096072097076a2198072097072098076a2199072098072099076a219a07209907209a076a219b0720" - "9a07209b076a219c07209b07209c076a219d07209c07209d076a219e07209d07209e076a219f07209e07209f076a21" - "a007209f0720a0076a21a10720a00720a1076a21a20720a10720a2076a21a30720a20720a3076a21a40720a30720a4" - "076a21a50720a40720a5076a21a60720a50720a6076a21a70720a60720a7076a21a80720a70720a8076a21a90720a8" - "0720a9076a21aa0720a90720aa076a21ab0720aa0720ab076a21ac0720ab0720ac076a21ad0720ac0720ad076a21ae" - "0720ad0720ae076a21af0720ae0720af076a21b00720af0720b0076a21b10720b00720b1076a21b20720b10720b207" - "6a21b30720b20720b3076a21b40720b30720b4076a21b50720b40720b5076a21b60720b50720b6076a21b70720b607" - "20b7076a21b80720b70720b8076a21b90720b80720b9076a21ba0720b90720ba076a21bb0720ba0720bb076a21bc07" - "20bb0720bc076a21bd0720bc0720bd076a21be0720bd0720be076a21bf0720be0720bf076a21c00720bf0720c0076a" - "21c10720c00720c1076a21c20720c10720c2076a21c30720c20720c3076a21c40720c30720c4076a21c50720c40720" - "c5076a21c60720c50720c6076a21c70720c60720c7076a21c80720c70720c8076a21c90720c80720c9076a21ca0720" - "c90720ca076a21cb0720ca0720cb076a21cc0720cb0720cc076a21cd0720cc0720cd076a21ce0720cd0720ce076a21" - "cf0720ce0720cf076a21d00720cf0720d0076a21d10720d00720d1076a21d20720d10720d2076a21d30720d20720d3" - "076a21d40720d30720d4076a21d50720d40720d5076a21d60720d50720d6076a21d70720d60720d7076a21d80720d7" - "0720d8076a21d90720d80720d9076a21da0720d90720da076a21db0720da0720db076a21dc0720db0720dc076a21dd" - "0720dc0720dd076a21de0720dd0720de076a21df0720de0720df076a21e00720df0720e0076a21e10720e00720e107" - "6a21e20720e10720e2076a21e30720e20720e3076a21e40720e30720e4076a21e50720e40720e5076a21e60720e507" - "20e6076a21e70720e60720e7076a21e80720e70720e8076a21e90720e80720e9076a21ea0720e90720ea076a21eb07" - "20ea0720eb076a21ec0720eb0720ec076a21ed0720ec0720ed076a21ee0720ed0720ee076a21ef0720ee0720ef076a" - "21f00720ef0720f0076a21f10720f00720f1076a21f20720f10720f2076a21f30720f20720f3076a21f40720f30720" - "f4076a21f50720f40720f5076a21f60720f50720f6076a21f70720f60720f7076a21f80720f70720f8076a21f90720" - "f80720f9076a21fa0720f90720fa076a21fb0720fa0720fb076a21fc0720fb0720fc076a21fd0720fc0720fd076a21" - "fe0720fd0720fe076a21ff0720fe0720ff076a21800820ff072080086a2181082080082081086a2182082081082082" - "086a2183082082082083086a2184082083082084086a2185082084082085086a2186082085082086086a2187082086" - "082087086a2188082087082088086a2189082088082089086a218a08208908208a086a218b08208a08208b086a218c" - "08208b08208c086a218d08208c08208d086a218e08208d08208e086a218f08208e08208f086a219008208f08209008" - "6a2191082090082091086a2192082091082092086a2193082092082093086a2194082093082094086a219508209408" - "2095086a2196082095082096086a2197082096082097086a2198082097082098086a2199082098082099086a219a08" - "209908209a086a219b08209a08209b086a219c08209b08209c086a219d08209c08209d086a219e08209d08209e086a" - "219f08209e08209f086a21a008209f0820a0086a21a10820a00820a1086a21a20820a10820a2086a21a30820a20820" - "a3086a21a40820a30820a4086a21a50820a40820a5086a21a60820a50820a6086a21a70820a60820a7086a21a80820" - "a70820a8086a21a90820a80820a9086a21aa0820a90820aa086a21ab0820aa0820ab086a21ac0820ab0820ac086a21" - "ad0820ac0820ad086a21ae0820ad0820ae086a21af0820ae0820af086a21b00820af0820b0086a21b10820b00820b1" - "086a21b20820b10820b2086a21b30820b20820b3086a21b40820b30820b4086a21b50820b40820b5086a21b60820b5" - "0820b6086a21b70820b60820b7086a21b80820b70820b8086a21b90820b80820b9086a21ba0820b90820ba086a21bb" - "0820ba0820bb086a21bc0820bb0820bc086a21bd0820bc0820bd086a21be0820bd0820be086a21bf0820be0820bf08" - "6a21c00820bf0820c0086a21c10820c00820c1086a21c20820c10820c2086a21c30820c20820c3086a21c40820c308" - "20c4086a21c50820c40820c5086a21c60820c50820c6086a21c70820c60820c7086a21c80820c70820c8086a21c908" - "20c80820c9086a21ca0820c90820ca086a21cb0820ca0820cb086a21cc0820cb0820cc086a21cd0820cc0820cd086a" - "21ce0820cd0820ce086a21cf0820ce0820cf086a21d00820cf0820d0086a21d10820d00820d1086a21d20820d10820" - "d2086a21d30820d20820d3086a21d40820d30820d4086a21d50820d40820d5086a21d60820d50820d6086a21d70820" - "d60820d7086a21d80820d70820d8086a21d90820d80820d9086a21da0820d90820da086a21db0820da0820db086a21" - "dc0820db0820dc086a21dd0820dc0820dd086a21de0820dd0820de086a21df0820de0820df086a21e00820df0820e0" - "086a21e10820e00820e1086a21e20820e10820e2086a21e30820e20820e3086a21e40820e30820e4086a21e50820e4" - "0820e5086a21e60820e50820e6086a21e70820e60820e7086a21e80820e70820e8086a21e90820e80820e9086a21ea" - "0820e90820ea086a21eb0820ea0820eb086a21ec0820eb0820ec086a21ed0820ec0820ed086a21ee0820ed0820ee08" - "6a21ef0820ee0820ef086a21f00820ef0820f0086a21f10820f00820f1086a21f20820f10820f2086a21f30820f208" - "20f3086a21f40820f30820f4086a21f50820f40820f5086a21f60820f50820f6086a21f70820f60820f7086a21f808" - "20f70820f8086a21f90820f80820f9086a21fa0820f90820fa086a21fb0820fa0820fb086a21fc0820fb0820fc086a" - "21fd0820fc0820fd086a21fe0820fd0820fe086a21ff0820fe0820ff086a21800920ff082080096a21810920800920" - "81096a2182092081092082096a2183092082092083096a2184092083092084096a2185092084092085096a21860920" - "85092086096a2187092086092087096a2188092087092088096a2189092088092089096a218a09208909208a096a21" - "8b09208a09208b096a218c09208b09208c096a218d09208c09208d096a218e09208d09208e096a218f09208e09208f" - "096a219009208f092090096a2191092090092091096a2192092091092092096a2193092092092093096a2194092093" - "092094096a2195092094092095096a2196092095092096096a2197092096092097096a2198092097092098096a2199" - "092098092099096a219a09209909209a096a219b09209a09209b096a219c09209b09209c096a219d09209c09209d09" - "6a219e09209d09209e096a219f09209e09209f096a21a009209f0920a0096a21a10920a00920a1096a21a20920a109" - "20a2096a21a30920a20920a3096a21a40920a30920a4096a21a50920a40920a5096a21a60920a50920a6096a21a709" - "20a60920a7096a21a80920a70920a8096a21a90920a80920a9096a21aa0920a90920aa096a21ab0920aa0920ab096a" - "21ac0920ab0920ac096a21ad0920ac0920ad096a21ae0920ad0920ae096a21af0920ae0920af096a21b00920af0920" - "b0096a21b10920b00920b1096a21b20920b10920b2096a21b30920b20920b3096a21b40920b30920b4096a21b50920" - "b40920b5096a21b60920b50920b6096a21b70920b60920b7096a21b80920b70920b8096a21b90920b80920b9096a21" - "ba0920b90920ba096a21bb0920ba0920bb096a21bc0920bb0920bc096a21bd0920bc0920bd096a21be0920bd0920be" - "096a21bf0920be0920bf096a21c00920bf0920c0096a21c10920c00920c1096a21c20920c10920c2096a21c30920c2" - "0920c3096a21c40920c30920c4096a21c50920c40920c5096a21c60920c50920c6096a21c70920c60920c7096a21c8" - "0920c70920c8096a21c90920c80920c9096a21ca0920c90920ca096a21cb0920ca0920cb096a21cc0920cb0920cc09" - "6a21cd0920cc0920cd096a21ce0920cd0920ce096a21cf0920ce0920cf096a21d00920cf0920d0096a21d10920d009" - "20d1096a21d20920d10920d2096a21d30920d20920d3096a21d40920d30920d4096a21d50920d40920d5096a21d609" - "20d50920d6096a21d70920d60920d7096a21d80920d70920d8096a21d90920d80920d9096a21da0920d90920da096a" - "21db0920da0920db096a21dc0920db0920dc096a21dd0920dc0920dd096a21de0920dd0920de096a21df0920de0920" - "df096a21e00920df0920e0096a21e10920e00920e1096a21e20920e10920e2096a21e30920e20920e3096a21e40920" - "e30920e4096a21e50920e40920e5096a21e60920e50920e6096a21e70920e60920e7096a21e80920e70920e8096a21" - "e90920e80920e9096a21ea0920e90920ea096a21eb0920ea0920eb096a21ec0920eb0920ec096a21ed0920ec0920ed" - "096a21ee0920ed0920ee096a21ef0920ee0920ef096a21f00920ef0920f0096a21f10920f00920f1096a21f20920f1" - "0920f2096a21f30920f20920f3096a21f40920f30920f4096a21f50920f40920f5096a21f60920f50920f6096a21f7" - "0920f60920f7096a21f80920f70920f8096a21f90920f80920f9096a21fa0920f90920fa096a21fb0920fa0920fb09" - "6a21fc0920fb0920fc096a21fd0920fc0920fd096a21fe0920fd0920fe096a21ff0920fe0920ff096a21800a20ff09" - "20800a6a21810a20800a20810a6a21820a20810a20820a6a21830a20820a20830a6a21840a20830a20840a6a21850a" - "20840a20850a6a21860a20850a20860a6a21870a20860a20870a6a21880a20870a20880a6a21890a20880a20890a6a" - "218a0a20890a208a0a6a218b0a208a0a208b0a6a218c0a208b0a208c0a6a218d0a208c0a208d0a6a218e0a208d0a20" - "8e0a6a218f0a208e0a208f0a6a21900a208f0a20900a6a21910a20900a20910a6a21920a20910a20920a6a21930a20" - "920a20930a6a21940a20930a20940a6a21950a20940a20950a6a21960a20950a20960a6a21970a20960a20970a6a21" - "980a20970a20980a6a21990a20980a20990a6a219a0a20990a209a0a6a219b0a209a0a209b0a6a219c0a209b0a209c" - "0a6a219d0a209c0a209d0a6a219e0a209d0a209e0a6a219f0a209e0a209f0a6a21a00a209f0a20a00a6a21a10a20a0" - "0a20a10a6a21a20a20a10a20a20a6a21a30a20a20a20a30a6a21a40a20a30a20a40a6a21a50a20a40a20a50a6a21a6" - "0a20a50a20a60a6a21a70a20a60a20a70a6a21a80a20a70a20a80a6a21a90a20a80a20a90a6a21aa0a20a90a20aa0a" - "6a21ab0a20aa0a20ab0a6a21ac0a20ab0a20ac0a6a21ad0a20ac0a20ad0a6a21ae0a20ad0a20ae0a6a21af0a20ae0a" - "20af0a6a21b00a20af0a20b00a6a21b10a20b00a20b10a6a21b20a20b10a20b20a6a21b30a20b20a20b30a6a21b40a" - "20b30a20b40a6a21b50a20b40a20b50a6a21b60a20b50a20b60a6a21b70a20b60a20b70a6a21b80a20b70a20b80a6a" - "21b90a20b80a20b90a6a21ba0a20b90a20ba0a6a21bb0a20ba0a20bb0a6a21bc0a20bb0a20bc0a6a21bd0a20bc0a20" - "bd0a6a21be0a20bd0a20be0a6a21bf0a20be0a20bf0a6a21c00a20bf0a20c00a6a21c10a20c00a20c10a6a21c20a20" - "c10a20c20a6a21c30a20c20a20c30a6a21c40a20c30a20c40a6a21c50a20c40a20c50a6a21c60a20c50a20c60a6a21" - "c70a20c60a20c70a6a21c80a20c70a20c80a6a21c90a20c80a20c90a6a21ca0a20c90a20ca0a6a21cb0a20ca0a20cb" - "0a6a21cc0a20cb0a20cc0a6a21cd0a20cc0a20cd0a6a21ce0a20cd0a20ce0a6a21cf0a20ce0a20cf0a6a21d00a20cf" - "0a20d00a6a21d10a20d00a20d10a6a21d20a20d10a20d20a6a21d30a20d20a20d30a6a21d40a20d30a20d40a6a21d5" - "0a20d40a20d50a6a21d60a20d50a20d60a6a21d70a20d60a20d70a6a21d80a20d70a20d80a6a21d90a20d80a20d90a" - "6a21da0a20d90a20da0a6a21db0a20da0a20db0a6a21dc0a20db0a20dc0a6a21dd0a20dc0a20dd0a6a21de0a20dd0a" - "20de0a6a21df0a20de0a20df0a6a21e00a20df0a20e00a6a21e10a20e00a20e10a6a21e20a20e10a20e20a6a21e30a" - "20e20a20e30a6a21e40a20e30a20e40a6a21e50a20e40a20e50a6a21e60a20e50a20e60a6a21e70a20e60a20e70a6a" - "21e80a20e70a20e80a6a21e90a20e80a20e90a6a21ea0a20e90a20ea0a6a21eb0a20ea0a20eb0a6a21ec0a20eb0a20" - "ec0a6a21ed0a20ec0a20ed0a6a21ee0a20ed0a20ee0a6a21ef0a20ee0a20ef0a6a21f00a20ef0a20f00a6a21f10a20" - "f00a20f10a6a21f20a20f10a20f20a6a21f30a20f20a20f30a6a21f40a20f30a20f40a6a21f50a20f40a20f50a6a21" - "f60a20f50a20f60a6a21f70a20f60a20f70a6a21f80a20f70a20f80a6a21f90a20f80a20f90a6a21fa0a20f90a20fa" - "0a6a21fb0a20fa0a20fb0a6a21fc0a20fb0a20fc0a6a21fd0a20fc0a20fd0a6a21fe0a20fd0a20fe0a6a21ff0a20fe" - "0a20ff0a6a21800b20ff0a20800b6a21810b20800b20810b6a21820b20810b20820b6a21830b20820b20830b6a2184" - "0b20830b20840b6a21850b20840b20850b6a21860b20850b20860b6a21870b20860b20870b6a21880b20870b20880b" - "6a21890b20880b20890b6a218a0b20890b208a0b6a218b0b208a0b208b0b6a218c0b208b0b208c0b6a218d0b208c0b" - "208d0b6a218e0b208d0b208e0b6a218f0b208e0b208f0b6a21900b208f0b20900b6a21910b20900b20910b6a21920b" - "20910b20920b6a21930b20920b20930b6a21940b20930b20940b6a21950b20940b20950b6a21960b20950b20960b6a" - "21970b20960b20970b6a21980b20970b20980b6a21990b20980b20990b6a219a0b20990b209a0b6a219b0b209a0b20" - "9b0b6a219c0b209b0b209c0b6a219d0b209c0b209d0b6a219e0b209d0b209e0b6a219f0b209e0b209f0b6a21a00b20" - "9f0b20a00b6a21a10b20a00b20a10b6a21a20b20a10b20a20b6a21a30b20a20b20a30b6a21a40b20a30b20a40b6a21" - "a50b20a40b20a50b6a21a60b20a50b20a60b6a21a70b20a60b20a70b6a21a80b20a70b20a80b6a21a90b20a80b20a9" - "0b6a21aa0b20a90b20aa0b6a21ab0b20aa0b20ab0b6a21ac0b20ab0b20ac0b6a21ad0b20ac0b20ad0b6a21ae0b20ad" - "0b20ae0b6a21af0b20ae0b20af0b6a21b00b20af0b20b00b6a21b10b20b00b20b10b6a21b20b20b10b20b20b6a21b3" - "0b20b20b20b30b6a21b40b20b30b20b40b6a21b50b20b40b20b50b6a21b60b20b50b20b60b6a21b70b20b60b20b70b" - "6a21b80b20b70b20b80b6a21b90b20b80b20b90b6a21ba0b20b90b20ba0b6a21bb0b20ba0b20bb0b6a21bc0b20bb0b" - "20bc0b6a21bd0b20bc0b20bd0b6a21be0b20bd0b20be0b6a21bf0b20be0b20bf0b6a21c00b20bf0b20c00b6a21c10b" - "20c00b20c10b6a21c20b20c10b20c20b6a21c30b20c20b20c30b6a21c40b20c30b20c40b6a21c50b20c40b20c50b6a" - "21c60b20c50b20c60b6a21c70b20c60b20c70b6a21c80b20c70b20c80b6a21c90b20c80b20c90b6a21ca0b20c90b20" - "ca0b6a21cb0b20ca0b20cb0b6a21cc0b20cb0b20cc0b6a21cd0b20cc0b20cd0b6a21ce0b20cd0b20ce0b6a21cf0b20" - "ce0b20cf0b6a21d00b20cf0b20d00b6a21d10b20d00b20d10b6a21d20b20d10b20d20b6a21d30b20d20b20d30b6a21" - "d40b20d30b20d40b6a21d50b20d40b20d50b6a21d60b20d50b20d60b6a21d70b20d60b20d70b6a21d80b20d70b20d8" - "0b6a21d90b20d80b20d90b6a21da0b20d90b20da0b6a21db0b20da0b20db0b6a21dc0b20db0b20dc0b6a21dd0b20dc" - "0b20dd0b6a21de0b20dd0b20de0b6a21df0b20de0b20df0b6a21e00b20df0b20e00b6a21e10b20e00b20e10b6a21e2" - "0b20e10b20e20b6a21e30b20e20b20e30b6a21e40b20e30b20e40b6a21e50b20e40b20e50b6a21e60b20e50b20e60b" - "6a21e70b20e60b20e70b6a21e80b20e70b20e80b6a21e90b20e80b20e90b6a21ea0b20e90b20ea0b6a21eb0b20ea0b" - "20eb0b6a21ec0b20eb0b20ec0b6a21ed0b20ec0b20ed0b6a21ee0b20ed0b20ee0b6a21ef0b20ee0b20ef0b6a21f00b" - "20ef0b20f00b6a21f10b20f00b20f10b6a21f20b20f10b20f20b6a21f30b20f20b20f30b6a21f40b20f30b20f40b6a" - "21f50b20f40b20f50b6a21f60b20f50b20f60b6a21f70b20f60b20f70b6a21f80b20f70b20f80b6a21f90b20f80b20" - "f90b6a21fa0b20f90b20fa0b6a21fb0b20fa0b20fb0b6a21fc0b20fb0b20fc0b6a21fd0b20fc0b20fd0b6a21fe0b20" - "fd0b20fe0b6a21ff0b20fe0b20ff0b6a21800c20ff0b20800c6a21810c20800c20810c6a21820c20810c20820c6a21" - "830c20820c20830c6a21840c20830c20840c6a21850c20840c20850c6a21860c20850c20860c6a21870c20860c2087" - "0c6a21880c20870c20880c6a21890c20880c20890c6a218a0c20890c208a0c6a218b0c208a0c208b0c6a218c0c208b" - "0c208c0c6a218d0c208c0c208d0c6a218e0c208d0c208e0c6a218f0c208e0c208f0c6a21900c208f0c20900c6a2191" - "0c20900c20910c6a21920c20910c20920c6a21930c20920c20930c6a21940c20930c20940c6a21950c20940c20950c" - "6a21960c20950c20960c6a21970c20960c20970c6a21980c20970c20980c6a21990c20980c20990c6a219a0c20990c" - "209a0c6a219b0c209a0c209b0c6a219c0c209b0c209c0c6a219d0c209c0c209d0c6a219e0c209d0c209e0c6a219f0c" - "209e0c209f0c6a21a00c209f0c20a00c6a21a10c20a00c20a10c6a21a20c20a10c20a20c6a21a30c20a20c20a30c6a" - "21a40c20a30c20a40c6a21a50c20a40c20a50c6a21a60c20a50c20a60c6a21a70c20a60c20a70c6a21a80c20a70c20" - "a80c6a21a90c20a80c20a90c6a21aa0c20a90c20aa0c6a21ab0c20aa0c20ab0c6a21ac0c20ab0c20ac0c6a21ad0c20" - "ac0c20ad0c6a21ae0c20ad0c20ae0c6a21af0c20ae0c20af0c6a21b00c20af0c20b00c6a21b10c20b00c20b10c6a21" - "b20c20b10c20b20c6a21b30c20b20c20b30c6a21b40c20b30c20b40c6a21b50c20b40c20b50c6a21b60c20b50c20b6" - "0c6a21b70c20b60c20b70c6a21b80c20b70c20b80c6a21b90c20b80c20b90c6a21ba0c20b90c20ba0c6a21bb0c20ba" - "0c20bb0c6a21bc0c20bb0c20bc0c6a21bd0c20bc0c20bd0c6a21be0c20bd0c20be0c6a21bf0c20be0c20bf0c6a21c0" - "0c20bf0c20c00c6a21c10c20c00c20c10c6a21c20c20c10c20c20c6a21c30c20c20c20c30c6a21c40c20c30c20c40c" - "6a21c50c20c40c20c50c6a21c60c20c50c20c60c6a21c70c20c60c20c70c6a21c80c20c70c20c80c6a21c90c20c80c" - "20c90c6a21ca0c20c90c20ca0c6a21cb0c20ca0c20cb0c6a21cc0c20cb0c20cc0c6a21cd0c20cc0c20cd0c6a21ce0c" - "20cd0c20ce0c6a21cf0c20ce0c20cf0c6a21d00c20cf0c20d00c6a21d10c20d00c20d10c6a21d20c20d10c20d20c6a" - "21d30c20d20c20d30c6a21d40c20d30c20d40c6a21d50c20d40c20d50c6a21d60c20d50c20d60c6a21d70c20d60c20" - "d70c6a21d80c20d70c20d80c6a21d90c20d80c20d90c6a21da0c20d90c20da0c6a21db0c20da0c20db0c6a21dc0c20" - "db0c20dc0c6a21dd0c20dc0c20dd0c6a21de0c20dd0c20de0c6a21df0c20de0c20df0c6a21e00c20df0c20e00c6a21" - "e10c20e00c20e10c6a21e20c20e10c20e20c6a21e30c20e20c20e30c6a21e40c20e30c20e40c6a21e50c20e40c20e5" - "0c6a21e60c20e50c20e60c6a21e70c20e60c20e70c6a21e80c20e70c20e80c6a21e90c20e80c20e90c6a21ea0c20e9" - "0c20ea0c6a21eb0c20ea0c20eb0c6a21ec0c20eb0c20ec0c6a21ed0c20ec0c20ed0c6a21ee0c20ed0c20ee0c6a21ef" - "0c20ee0c20ef0c6a21f00c20ef0c20f00c6a21f10c20f00c20f10c6a21f20c20f10c20f20c6a21f30c20f20c20f30c" - "6a21f40c20f30c20f40c6a21f50c20f40c20f50c6a21f60c20f50c20f60c6a21f70c20f60c20f70c6a21f80c20f70c" - "20f80c6a21f90c20f80c20f90c6a21fa0c20f90c20fa0c6a21fb0c20fa0c20fb0c6a21fc0c20fb0c20fc0c6a21fd0c" - "20fc0c20fd0c6a21fe0c20fd0c20fe0c6a21ff0c20fe0c20ff0c6a21800d20ff0c20800d6a21810d20800d20810d6a" - "21820d20810d20820d6a21830d20820d20830d6a21840d20830d20840d6a21850d20840d20850d6a21860d20850d20" - "860d6a21870d20860d20870d6a21880d20870d20880d6a21890d20880d20890d6a218a0d20890d208a0d6a218b0d20" - "8a0d208b0d6a218c0d208b0d208c0d6a218d0d208c0d208d0d6a218e0d208d0d208e0d6a218f0d208e0d208f0d6a21" - "900d208f0d20900d6a21910d20900d20910d6a21920d20910d20920d6a21930d20920d20930d6a21940d20930d2094" - "0d6a21950d20940d20950d6a21960d20950d20960d6a21970d20960d20970d6a21980d20970d20980d6a21990d2098" - "0d20990d6a219a0d20990d209a0d6a219b0d209a0d209b0d6a219c0d209b0d209c0d6a219d0d209c0d209d0d6a219e" - "0d209d0d209e0d6a219f0d209e0d209f0d6a21a00d209f0d20a00d6a21a10d20a00d20a10d6a21a20d20a10d20a20d" - "6a21a30d20a20d20a30d6a21a40d20a30d20a40d6a21a50d20a40d20a50d6a21a60d20a50d20a60d6a21a70d20a60d" - "20a70d6a21a80d20a70d20a80d6a21a90d20a80d20a90d6a21aa0d20a90d20aa0d6a21ab0d20aa0d20ab0d6a21ac0d" - "20ab0d20ac0d6a21ad0d20ac0d20ad0d6a21ae0d20ad0d20ae0d6a21af0d20ae0d20af0d6a21b00d20af0d20b00d6a" - "21b10d20b00d20b10d6a21b20d20b10d20b20d6a21b30d20b20d20b30d6a21b40d20b30d20b40d6a21b50d20b40d20" - "b50d6a21b60d20b50d20b60d6a21b70d20b60d20b70d6a21b80d20b70d20b80d6a21b90d20b80d20b90d6a21ba0d20" - "b90d20ba0d6a21bb0d20ba0d20bb0d6a21bc0d20bb0d20bc0d6a21bd0d20bc0d20bd0d6a21be0d20bd0d20be0d6a21" - "bf0d20be0d20bf0d6a21c00d20bf0d20c00d6a21c10d20c00d20c10d6a21c20d20c10d20c20d6a21c30d20c20d20c3" - "0d6a21c40d20c30d20c40d6a21c50d20c40d20c50d6a21c60d20c50d20c60d6a21c70d20c60d20c70d6a21c80d20c7" - "0d20c80d6a21c90d20c80d20c90d6a21ca0d20c90d20ca0d6a21cb0d20ca0d20cb0d6a21cc0d20cb0d20cc0d6a21cd" - "0d20cc0d20cd0d6a21ce0d20cd0d20ce0d6a21cf0d20ce0d20cf0d6a21d00d20cf0d20d00d6a21d10d20d00d20d10d" - "6a21d20d20d10d20d20d6a21d30d20d20d20d30d6a21d40d20d30d20d40d6a21d50d20d40d20d50d6a21d60d20d50d" - "20d60d6a21d70d20d60d20d70d6a21d80d20d70d20d80d6a21d90d20d80d20d90d6a21da0d20d90d20da0d6a21db0d" - "20da0d20db0d6a21dc0d20db0d20dc0d6a21dd0d20dc0d20dd0d6a21de0d20dd0d20de0d6a21df0d20de0d20df0d6a" - "21e00d20df0d20e00d6a21e10d20e00d20e10d6a21e20d20e10d20e20d6a21e30d20e20d20e30d6a21e40d20e30d20" - "e40d6a21e50d20e40d20e50d6a21e60d20e50d20e60d6a21e70d20e60d20e70d6a21e80d20e70d20e80d6a21e90d20" - "e80d20e90d6a21ea0d20e90d20ea0d6a21eb0d20ea0d20eb0d6a21ec0d20eb0d20ec0d6a21ed0d20ec0d20ed0d6a21" - "ee0d20ed0d20ee0d6a21ef0d20ee0d20ef0d6a21f00d20ef0d20f00d6a21f10d20f00d20f10d6a21f20d20f10d20f2" - "0d6a21f30d20f20d20f30d6a21f40d20f30d20f40d6a21f50d20f40d20f50d6a21f60d20f50d20f60d6a21f70d20f6" - "0d20f70d6a21f80d20f70d20f80d6a21f90d20f80d20f90d6a21fa0d20f90d20fa0d6a21fb0d20fa0d20fb0d6a21fc" - "0d20fb0d20fc0d6a21fd0d20fc0d20fd0d6a21fe0d20fd0d20fe0d6a21ff0d20fe0d20ff0d6a21800e20ff0d20800e" - "6a21810e20800e20810e6a21820e20810e20820e6a21830e20820e20830e6a21840e20830e20840e6a21850e20840e" - "20850e6a21860e20850e20860e6a21870e20860e20870e6a21880e20870e20880e6a21890e20880e20890e6a218a0e" - "20890e208a0e6a218b0e208a0e208b0e6a218c0e208b0e208c0e6a218d0e208c0e208d0e6a218e0e208d0e208e0e6a" - "218f0e208e0e208f0e6a21900e208f0e20900e6a21910e20900e20910e6a21920e20910e20920e6a21930e20920e20" - "930e6a21940e20930e20940e6a21950e20940e20950e6a21960e20950e20960e6a21970e20960e20970e6a21980e20" - "970e20980e6a21990e20980e20990e6a219a0e20990e209a0e6a219b0e209a0e209b0e6a219c0e209b0e209c0e6a21" - "9d0e209c0e209d0e6a219e0e209d0e209e0e6a219f0e209e0e209f0e6a21a00e209f0e20a00e6a21a10e20a00e20a1" - "0e6a21a20e20a10e20a20e6a21a30e20a20e20a30e6a21a40e20a30e20a40e6a21a50e20a40e20a50e6a21a60e20a5" - "0e20a60e6a21a70e20a60e20a70e6a21a80e20a70e20a80e6a21a90e20a80e20a90e6a21aa0e20a90e20aa0e6a21ab" - "0e20aa0e20ab0e6a21ac0e20ab0e20ac0e6a21ad0e20ac0e20ad0e6a21ae0e20ad0e20ae0e6a21af0e20ae0e20af0e" - "6a21b00e20af0e20b00e6a21b10e20b00e20b10e6a21b20e20b10e20b20e6a21b30e20b20e20b30e6a21b40e20b30e" - "20b40e6a21b50e20b40e20b50e6a21b60e20b50e20b60e6a21b70e20b60e20b70e6a21b80e20b70e20b80e6a21b90e" - "20b80e20b90e6a21ba0e20b90e20ba0e6a21bb0e20ba0e20bb0e6a21bc0e20bb0e20bc0e6a21bd0e20bc0e20bd0e6a" - "21be0e20bd0e20be0e6a21bf0e20be0e20bf0e6a21c00e20bf0e20c00e6a21c10e20c00e20c10e6a21c20e20c10e20" - "c20e6a21c30e20c20e20c30e6a21c40e20c30e20c40e6a21c50e20c40e20c50e6a21c60e20c50e20c60e6a21c70e20" - "c60e20c70e6a21c80e20c70e20c80e6a21c90e20c80e20c90e6a21ca0e20c90e20ca0e6a21cb0e20ca0e20cb0e6a21" - "cc0e20cb0e20cc0e6a21cd0e20cc0e20cd0e6a21ce0e20cd0e20ce0e6a21cf0e20ce0e20cf0e6a21d00e20cf0e20d0" - "0e6a21d10e20d00e20d10e6a21d20e20d10e20d20e6a21d30e20d20e20d30e6a21d40e20d30e20d40e6a21d50e20d4" - "0e20d50e6a21d60e20d50e20d60e6a21d70e20d60e20d70e6a21d80e20d70e20d80e6a21d90e20d80e20d90e6a21da" - "0e20d90e20da0e6a21db0e20da0e20db0e6a21dc0e20db0e20dc0e6a21dd0e20dc0e20dd0e6a21de0e20dd0e20de0e" - "6a21df0e20de0e20df0e6a21e00e20df0e20e00e6a21e10e20e00e20e10e6a21e20e20e10e20e20e6a21e30e20e20e" - "20e30e6a21e40e20e30e20e40e6a21e50e20e40e20e50e6a21e60e20e50e20e60e6a21e70e20e60e20e70e6a21e80e" - "20e70e20e80e6a21e90e20e80e20e90e6a21ea0e20e90e20ea0e6a21eb0e20ea0e20eb0e6a21ec0e20eb0e20ec0e6a" - "21ed0e20ec0e20ed0e6a21ee0e20ed0e20ee0e6a21ef0e20ee0e20ef0e6a21f00e20ef0e20f00e6a21f10e20f00e20" - "f10e6a21f20e20f10e20f20e6a21f30e20f20e20f30e6a21f40e20f30e20f40e6a21f50e20f40e20f50e6a21f60e20" - "f50e20f60e6a21f70e20f60e20f70e6a21f80e20f70e20f80e6a21f90e20f80e20f90e6a21fa0e20f90e20fa0e6a21" - "fb0e20fa0e20fb0e6a21fc0e20fb0e20fc0e6a21fd0e20fc0e20fd0e6a21fe0e20fd0e20fe0e6a21ff0e20fe0e20ff" - "0e6a21800f20ff0e20800f6a21810f20800f20810f6a21820f20810f20820f6a21830f20820f20830f6a21840f2083" - "0f20840f6a21850f20840f20850f6a21860f20850f20860f6a21870f20860f20870f6a21880f20870f20880f6a2189" - "0f20880f20890f6a218a0f20890f208a0f6a218b0f208a0f208b0f6a218c0f208b0f208c0f6a218d0f208c0f208d0f" - "6a218e0f208d0f208e0f6a218f0f208e0f208f0f6a21900f208f0f20900f6a21910f20900f20910f6a21920f20910f" - "20920f6a21930f20920f20930f6a21940f20930f20940f6a21950f20940f20950f6a21960f20950f20960f6a21970f" - "20960f20970f6a21980f20970f20980f6a21990f20980f20990f6a219a0f20990f209a0f6a219b0f209a0f209b0f6a" - "219c0f209b0f209c0f6a219d0f209c0f209d0f6a219e0f209d0f209e0f6a219f0f209e0f209f0f6a21a00f209f0f20" - "a00f6a21a10f20a00f20a10f6a21a20f20a10f20a20f6a21a30f20a20f20a30f6a21a40f20a30f20a40f6a21a50f20" - "a40f20a50f6a21a60f20a50f20a60f6a21a70f20a60f20a70f6a21a80f20a70f20a80f6a21a90f20a80f20a90f6a21" - "aa0f20a90f20aa0f6a21ab0f20aa0f20ab0f6a21ac0f20ab0f20ac0f6a21ad0f20ac0f20ad0f6a21ae0f20ad0f20ae" - "0f6a21af0f20ae0f20af0f6a21b00f20af0f20b00f6a21b10f20b00f20b10f6a21b20f20b10f20b20f6a21b30f20b2" - "0f20b30f6a21b40f20b30f20b40f6a21b50f20b40f20b50f6a21b60f20b50f20b60f6a21b70f20b60f20b70f6a21b8" - "0f20b70f20b80f6a21b90f20b80f20b90f6a21ba0f20b90f20ba0f6a21bb0f20ba0f20bb0f6a21bc0f20bb0f20bc0f" - "6a21bd0f20bc0f20bd0f6a21be0f20bd0f20be0f6a21bf0f20be0f20bf0f6a21c00f20bf0f20c00f6a21c10f20c00f" - "20c10f6a21c20f20c10f20c20f6a21c30f20c20f20c30f6a21c40f20c30f20c40f6a21c50f20c40f20c50f6a21c60f" - "20c50f20c60f6a21c70f20c60f20c70f6a21c80f20c70f20c80f6a21c90f20c80f20c90f6a21ca0f20c90f20ca0f6a" - "21cb0f20ca0f20cb0f6a21cc0f20cb0f20cc0f6a21cd0f20cc0f20cd0f6a21ce0f20cd0f20ce0f6a21cf0f20ce0f20" - "cf0f6a21d00f20cf0f20d00f6a21d10f20d00f20d10f6a21d20f20d10f20d20f6a21d30f20d20f20d30f6a21d40f20" - "d30f20d40f6a21d50f20d40f20d50f6a21d60f20d50f20d60f6a21d70f20d60f20d70f6a21d80f20d70f20d80f6a21" - "d90f20d80f20d90f6a21da0f20d90f20da0f6a21db0f20da0f20db0f6a21dc0f20db0f20dc0f6a21dd0f20dc0f20dd" - "0f6a21de0f20dd0f20de0f6a21df0f20de0f20df0f6a21e00f20df0f20e00f6a21e10f20e00f20e10f6a21e20f20e1" - "0f20e20f6a21e30f20e20f20e30f6a21e40f20e30f20e40f6a21e50f20e40f20e50f6a21e60f20e50f20e60f6a21e7" - "0f20e60f20e70f6a21e80f20e70f20e80f6a21e90f20e80f20e90f6a21ea0f20e90f20ea0f6a21eb0f20ea0f20eb0f" - "6a21ec0f20eb0f20ec0f6a21ed0f20ec0f20ed0f6a21ee0f20ed0f20ee0f6a21ef0f20ee0f20ef0f6a21f00f20ef0f" - "20f00f6a21f10f20f00f20f10f6a21f20f20f10f20f20f6a21f30f20f20f20f30f6a21f40f20f30f20f40f6a21f50f" - "20f40f20f50f6a21f60f20f50f20f60f6a21f70f20f60f20f70f6a21f80f20f70f20f80f6a21f90f20f80f20f90f6a" - "21fa0f20f90f20fa0f6a21fb0f20fa0f20fb0f6a21fc0f20fb0f20fc0f6a21fd0f20fc0f20fd0f6a21fe0f20fd0f20" - "fe0f6a21ff0f20fe0f20ff0f6a21801020ff0f2080106a2181102080102081106a2182102081102082106a21831020" - "82102083106a2184102083102084106a2185102084102085106a2186102085102086106a2187102086102087106a21" - "88102087102088106a2189102088102089106a218a10208910208a106a218b10208a10208b106a218c10208b10208c" - "106a218d10208c10208d106a218e10208d10208e106a218f10208e10208f106a219010208f102090106a2191102090" - "102091106a2192102091102092106a2193102092102093106a2194102093102094106a2195102094102095106a2196" - "102095102096106a2197102096102097106a2198102097102098106a2199102098102099106a219a10209910209a10" - "6a219b10209a10209b106a219c10209b10209c106a219d10209c10209d106a219e10209d10209e106a219f10209e10" - "209f106a21a010209f1020a0106a21a11020a01020a1106a21a21020a11020a2106a21a31020a21020a3106a21a410" - "20a31020a4106a21a51020a41020a5106a21a61020a51020a6106a21a71020a61020a7106a21a81020a71020a8106a" - "21a91020a81020a9106a21aa1020a91020aa106a21ab1020aa1020ab106a21ac1020ab1020ac106a21ad1020ac1020" - "ad106a21ae1020ad1020ae106a21af1020ae1020af106a21b01020af1020b0106a21b11020b01020b1106a21b21020" - "b11020b2106a21b31020b21020b3106a21b41020b31020b4106a21b51020b41020b5106a21b61020b51020b6106a21" - "b71020b61020b7106a21b81020b71020b8106a21b91020b81020b9106a21ba1020b91020ba106a21bb1020ba1020bb" - "106a21bc1020bb1020bc106a21bd1020bc1020bd106a21be1020bd1020be106a21bf1020be1020bf106a21c01020bf" - "1020c0106a21c11020c01020c1106a21c21020c11020c2106a21c31020c21020c3106a21c41020c31020c4106a21c5" - "1020c41020c5106a21c61020c51020c6106a21c71020c61020c7106a21c81020c71020c8106a21c91020c81020c910" - "6a21ca1020c91020ca106a21cb1020ca1020cb106a21cc1020cb1020cc106a21cd1020cc1020cd106a21ce1020cd10" - "20ce106a21cf1020ce1020cf106a21d01020cf1020d0106a21d11020d01020d1106a21d21020d11020d2106a21d310" - "20d21020d3106a21d41020d31020d4106a21d51020d41020d5106a21d61020d51020d6106a21d71020d61020d7106a" - "21d81020d71020d8106a21d91020d81020d9106a21da1020d91020da106a21db1020da1020db106a21dc1020db1020" - "dc106a21dd1020dc1020dd106a21de1020dd1020de106a21df1020de1020df106a21e01020df1020e0106a21e11020" - "e01020e1106a21e21020e11020e2106a21e31020e21020e3106a21e41020e31020e4106a21e51020e41020e5106a21" - "e61020e51020e6106a21e71020e61020e7106a21e81020e71020e8106a21e91020e81020e9106a21ea1020e91020ea" - "106a21eb1020ea1020eb106a21ec1020eb1020ec106a21ed1020ec1020ed106a21ee1020ed1020ee106a21ef1020ee" - "1020ef106a21f01020ef1020f0106a21f11020f01020f1106a21f21020f11020f2106a21f31020f21020f3106a21f4" - "1020f31020f4106a21f51020f41020f5106a21f61020f51020f6106a21f71020f61020f7106a21f81020f71020f810" - "6a21f91020f81020f9106a21fa1020f91020fa106a21fb1020fa1020fb106a21fc1020fb1020fc106a21fd1020fc10" - "20fd106a21fe1020fd1020fe106a21ff1020fe1020ff106a21801120ff102080116a2181112080112081116a218211" - "2081112082116a2183112082112083116a2184112083112084116a2185112084112085116a2186112085112086116a" - "2187112086112087116a2188112087112088116a2189112088112089116a218a11208911208a116a218b11208a1120" - "8b116a218c11208b11208c116a218d11208c11208d116a218e11208d11208e116a218f11208e11208f116a21901120" - "8f112090116a2191112090112091116a2192112091112092116a2193112092112093116a2194112093112094116a21" - "95112094112095116a2196112095112096116a2197112096112097116a2198112097112098116a2199112098112099" - "116a219a11209911209a116a219b11209a11209b116a219c11209b11209c116a219d11209c11209d116a219e11209d" - "11209e116a219f11209e11209f116a21a011209f1120a0116a21a11120a01120a1116a21a21120a11120a2116a21a3" - "1120a21120a3116a21a41120a31120a4116a21a51120a41120a5116a21a61120a51120a6116a21a71120a61120a711" - "6a21a81120a71120a8116a21a91120a81120a9116a21aa1120a91120aa116a21ab1120aa1120ab116a21ac1120ab11" - "20ac116a21ad1120ac1120ad116a21ae1120ad1120ae116a21af1120ae1120af116a21b01120af1120b0116a21b111" - "20b01120b1116a21b21120b11120b2116a21b31120b21120b3116a21b41120b31120b4116a21b51120b41120b5116a" - "21b61120b51120b6116a21b71120b61120b7116a21b81120b71120b8116a21b91120b81120b9116a21ba1120b91120" - "ba116a21bb1120ba1120bb116a21bc1120bb1120bc116a21bd1120bc1120bd116a21be1120bd1120be116a21bf1120" - "be1120bf116a21c01120bf1120c0116a21c11120c01120c1116a21c21120c11120c2116a21c31120c21120c3116a21" - "c41120c31120c4116a21c51120c41120c5116a21c61120c51120c6116a21c71120c61120c7116a21c81120c71120c8" - "116a21c91120c81120c9116a21ca1120c91120ca116a21cb1120ca1120cb116a21cc1120cb1120cc116a21cd1120cc" - "1120cd116a21ce1120cd1120ce116a21cf1120ce1120cf116a21d01120cf1120d0116a21d11120d01120d1116a21d2" - "1120d11120d2116a21d31120d21120d3116a21d41120d31120d4116a21d51120d41120d5116a21d61120d51120d611" - "6a21d71120d61120d7116a21d81120d71120d8116a21d91120d81120d9116a21da1120d91120da116a21db1120da11" - "20db116a21dc1120db1120dc116a21dd1120dc1120dd116a21de1120dd1120de116a21df1120de1120df116a21e011" - "20df1120e0116a21e11120e01120e1116a21e21120e11120e2116a21e31120e21120e3116a21e41120e31120e4116a" - "21e51120e41120e5116a21e61120e51120e6116a21e71120e61120e7116a21e81120e71120e8116a21e91120e81120" - "e9116a21ea1120e91120ea116a21eb1120ea1120eb116a21ec1120eb1120ec116a21ed1120ec1120ed116a21ee1120" - "ed1120ee116a21ef1120ee1120ef116a21f01120ef1120f0116a21f11120f01120f1116a21f21120f11120f2116a21" - "f31120f21120f3116a21f41120f31120f4116a21f51120f41120f5116a21f61120f51120f6116a21f71120f61120f7" - "116a21f81120f71120f8116a21f91120f81120f9116a21fa1120f91120fa116a21fb1120fa1120fb116a21fc1120fb" - "1120fc116a21fd1120fc1120fd116a21fe1120fd1120fe116a21ff1120fe1120ff116a21801220ff112080126a2181" - "122080122081126a2182122081122082126a2183122082122083126a2184122083122084126a218512208412208512" - "6a2186122085122086126a2187122086122087126a2188122087122088126a2189122088122089126a218a12208912" - "208a126a218b12208a12208b126a218c12208b12208c126a218d12208c12208d126a218e12208d12208e126a218f12" - "208e12208f126a219012208f122090126a2191122090122091126a2192122091122092126a2193122092122093126a" - "2194122093122094126a2195122094122095126a2196122095122096126a2197122096122097126a21981220971220" - "98126a2199122098122099126a219a12209912209a126a219b12209a12209b126a219c12209b12209c126a219d1220" - "9c12209d126a219e12209d12209e126a219f12209e12209f126a21a012209f1220a0126a21a11220a01220a1126a21" - "a21220a11220a2126a21a31220a21220a3126a21a41220a31220a4126a21a51220a41220a5126a21a61220a51220a6" - "126a21a71220a61220a7126a21a81220a71220a8126a21a91220a81220a9126a21aa1220a91220aa126a21ab1220aa" - "1220ab126a21ac1220ab1220ac126a21ad1220ac1220ad126a21ae1220ad1220ae126a21af1220ae1220af126a21b0" - "1220af1220b0126a21b11220b01220b1126a21b21220b11220b2126a21b31220b21220b3126a21b41220b31220b412" - "6a21b51220b41220b5126a21b61220b51220b6126a21b71220b61220b7126a21b81220b71220b8126a21b91220b812" - "20b9126a21ba1220b91220ba126a21bb1220ba1220bb126a21bc1220bb1220bc126a21bd1220bc1220bd126a21be12" - "20bd1220be126a21bf1220be1220bf126a21c01220bf1220c0126a21c11220c01220c1126a21c21220c11220c2126a" - "21c31220c21220c3126a21c41220c31220c4126a21c51220c41220c5126a21c61220c51220c6126a21c71220c61220" - "c7126a21c81220c71220c8126a21c91220c81220c9126a21ca1220c91220ca126a21cb1220ca1220cb126a21cc1220" - "cb1220cc126a21cd1220cc1220cd126a21ce1220cd1220ce126a21cf1220ce1220cf126a21d01220cf1220d0126a21" - "d11220d01220d1126a21d21220d11220d2126a21d31220d21220d3126a21d41220d31220d4126a21d51220d41220d5" - "126a21d61220d51220d6126a21d71220d61220d7126a21d81220d71220d8126a21d91220d81220d9126a21da1220d9" - "1220da126a21db1220da1220db126a21dc1220db1220dc126a21dd1220dc1220dd126a21de1220dd1220de126a21df" - "1220de1220df126a21e01220df1220e0126a21e11220e01220e1126a21e21220e11220e2126a21e31220e21220e312" - "6a21e41220e31220e4126a21e51220e41220e5126a21e61220e51220e6126a21e71220e61220e7126a21e81220e712" - "20e8126a21e91220e81220e9126a21ea1220e91220ea126a21eb1220ea1220eb126a21ec1220eb1220ec126a21ed12" - "20ec1220ed126a21ee1220ed1220ee126a21ef1220ee1220ef126a21f01220ef1220f0126a21f11220f01220f1126a" - "21f21220f11220f2126a21f31220f21220f3126a21f41220f31220f4126a21f51220f41220f5126a21f61220f51220" - "f6126a21f71220f61220f7126a21f81220f71220f8126a21f91220f81220f9126a21fa1220f91220fa126a21fb1220" - "fa1220fb126a21fc1220fb1220fc126a21fd1220fc1220fd126a21fe1220fd1220fe126a21ff1220fe1220ff126a21" - "801320ff122080136a2181132080132081136a2182132081132082136a2183132082132083136a2184132083132084" - "136a2185132084132085136a2186132085132086136a2187132086132087136a2188132087132088136a2189132088" - "132089136a218a13208913208a136a218b13208a13208b136a218c13208b13208c136a218d13208c13208d136a218e" - "13208d13208e136a218f13208e13208f136a219013208f132090136a2191132090132091136a219213209113209213" - "6a2193132092132093136a2194132093132094136a2195132094132095136a2196132095132096136a219713209613" - "2097136a2198132097132098136a2199132098132099136a219a13209913209a136a219b13209a13209b136a219c13" - "209b13209c136a219d13209c13209d136a219e13209d13209e136a219f13209e13209f136a21a013209f1320a0136a" - "21a11320a01320a1136a21a21320a11320a2136a21a31320a21320a3136a21a41320a31320a4136a21a51320a41320" - "a5136a21a61320a51320a6136a21a71320a61320a7136a21a81320a71320a8136a21a91320a81320a9136a21aa1320" - "a91320aa136a21ab1320aa1320ab136a21ac1320ab1320ac136a21ad1320ac1320ad136a21ae1320ad1320ae136a21" - "af1320ae1320af136a21b01320af1320b0136a21b11320b01320b1136a21b21320b11320b2136a21b31320b21320b3" - "136a21b41320b31320b4136a21b51320b41320b5136a21b61320b51320b6136a21b71320b61320b7136a21b81320b7" - "1320b8136a21b91320b81320b9136a21ba1320b91320ba136a21bb1320ba1320bb136a21bc1320bb1320bc136a21bd" - "1320bc1320bd136a21be1320bd1320be136a21bf1320be1320bf136a21c01320bf1320c0136a21c11320c01320c113" - "6a21c21320c11320c2136a21c31320c21320c3136a21c41320c31320c4136a21c51320c41320c5136a21c61320c513" - "20c6136a21c71320c61320c7136a21c81320c71320c8136a21c91320c81320c9136a21ca1320c91320ca136a21cb13" - "20ca1320cb136a21cc1320cb1320cc136a21cd1320cc1320cd136a21ce1320cd1320ce136a21cf1320ce1320cf136a" - "21d01320cf1320d0136a21d11320d01320d1136a21d21320d11320d2136a21d31320d21320d3136a21d41320d31320" - "d4136a21d51320d41320d5136a21d61320d51320d6136a21d71320d61320d7136a21d81320d71320d8136a21d91320" - "d81320d9136a21da1320d91320da136a21db1320da1320db136a21dc1320db1320dc136a21dd1320dc1320dd136a21" - "de1320dd1320de136a21df1320de1320df136a21e01320df1320e0136a21e11320e01320e1136a21e21320e11320e2" - "136a21e31320e21320e3136a21e41320e31320e4136a21e51320e41320e5136a21e61320e51320e6136a21e71320e6" - "1320e7136a21e81320e71320e8136a21e91320e81320e9136a21ea1320e91320ea136a21eb1320ea1320eb136a21ec" - "1320eb1320ec136a21ed1320ec1320ed136a21ee1320ed1320ee136a21ef1320ee1320ef136a21f01320ef1320f013" - "6a21f11320f01320f1136a21f21320f11320f2136a21f31320f21320f3136a21f41320f31320f4136a21f51320f413" - "20f5136a21f61320f51320f6136a21f71320f61320f7136a21f81320f71320f8136a21f91320f81320f9136a21fa13" - "20f91320fa136a21fb1320fa1320fb136a21fc1320fb1320fc136a21fd1320fc1320fd136a21fe1320fd1320fe136a" - "21ff1320fe1320ff136a21801420ff132080146a2181142080142081146a2182142081142082146a21831420821420" - "83146a2184142083142084146a2185142084142085146a2186142085142086146a2187142086142087146a21881420" - "87142088146a2189142088142089146a218a14208914208a146a218b14208a14208b146a218c14208b14208c146a21" - "8d14208c14208d146a218e14208d14208e146a218f14208e14208f146a219014208f142090146a2191142090142091" - "146a2192142091142092146a2193142092142093146a2194142093142094146a2195142094142095146a2196142095" - "142096146a2197142096142097146a2198142097142098146a2199142098142099146a219a14209914209a146a219b" - "14209a14209b146a219c14209b14209c146a219d14209c14209d146a219e14209d14209e146a219f14209e14209f14" - "6a21a014209f1420a0146a21a11420a01420a1146a21a21420a11420a2146a21a31420a21420a3146a21a41420a314" - "20a4146a21a51420a41420a5146a21a61420a51420a6146a21a71420a61420a7146a21a81420a71420a8146a21a914" - "20a81420a9146a21aa1420a91420aa146a21ab1420aa1420ab146a21ac1420ab1420ac146a21ad1420ac1420ad146a" - "21ae1420ad1420ae146a21af1420ae1420af146a21b01420af1420b0146a21b11420b01420b1146a21b21420b11420" - "b2146a21b31420b21420b3146a21b41420b31420b4146a21b51420b41420b5146a21b61420b51420b6146a21b71420" - "b61420b7146a21b81420b71420b8146a21b91420b81420b9146a21ba1420b91420ba146a21bb1420ba1420bb146a21" - "bc1420bb1420bc146a21bd1420bc1420bd146a21be1420bd1420be146a21bf1420be1420bf146a21c01420bf1420c0" - "146a21c11420c01420c1146a21c21420c11420c2146a21c31420c21420c3146a21c41420c31420c4146a21c51420c4" - "1420c5146a21c61420c51420c6146a21c71420c61420c7146a21c81420c71420c8146a21c91420c81420c9146a21ca" - "1420c91420ca146a21cb1420ca1420cb146a21cc1420cb1420cc146a21cd1420cc1420cd146a21ce1420cd1420ce14" - "6a21cf1420ce1420cf146a21d01420cf1420d0146a21d11420d01420d1146a21d21420d11420d2146a21d31420d214" - "20d3146a21d41420d31420d4146a21d51420d41420d5146a21d61420d51420d6146a21d71420d61420d7146a21d814" - "20d71420d8146a21d91420d81420d9146a21da1420d91420da146a21db1420da1420db146a21dc1420db1420dc146a" - "21dd1420dc1420dd146a21de1420dd1420de146a21df1420de1420df146a21e01420df1420e0146a21e11420e01420" - "e1146a21e21420e11420e2146a21e31420e21420e3146a21e41420e31420e4146a21e51420e41420e5146a21e61420" - "e51420e6146a21e71420e61420e7146a21e81420e71420e8146a21e91420e81420e9146a21ea1420e91420ea146a21" - "eb1420ea1420eb146a21ec1420eb1420ec146a21ed1420ec1420ed146a21ee1420ed1420ee146a21ef1420ee1420ef" - "146a21f01420ef1420f0146a21f11420f01420f1146a21f21420f11420f2146a21f31420f21420f3146a21f41420f3" - "1420f4146a21f51420f41420f5146a21f61420f51420f6146a21f71420f61420f7146a21f81420f71420f8146a21f9" - "1420f81420f9146a21fa1420f91420fa146a21fb1420fa1420fb146a21fc1420fb1420fc146a21fd1420fc1420fd14" - "6a21fe1420fd1420fe146a21ff1420fe1420ff146a21801520ff142080156a2181152080152081156a218215208115" - "2082156a2183152082152083156a2184152083152084156a2185152084152085156a2186152085152086156a218715" - "2086152087156a2188152087152088156a2189152088152089156a218a15208915208a156a218b15208a15208b156a" - "218c15208b15208c156a218d15208c15208d156a218e15208d15208e156a218f15208e15208f156a219015208f1520" - "90156a2191152090152091156a2192152091152092156a2193152092152093156a2194152093152094156a21951520" - "94152095156a2196152095152096156a2197152096152097156a2198152097152098156a2199152098152099156a21" - "9a15209915209a156a219b15209a15209b156a219c15209b15209c156a219d15209c15209d156a219e15209d15209e" - "156a219f15209e15209f156a21a015209f1520a0156a21a11520a01520a1156a21a21520a11520a2156a21a31520a2" - "1520a3156a21a41520a31520a4156a21a51520a41520a5156a21a61520a51520a6156a21a71520a61520a7156a21a8" - "1520a71520a8156a21a91520a81520a9156a21aa1520a91520aa156a21ab1520aa1520ab156a21ac1520ab1520ac15" - "6a21ad1520ac1520ad156a21ae1520ad1520ae156a21af1520ae1520af156a21b01520af1520b0156a21b11520b015" - "20b1156a21b21520b11520b2156a21b31520b21520b3156a21b41520b31520b4156a21b51520b41520b5156a21b615" - "20b51520b6156a21b71520b61520b7156a21b81520b71520b8156a21b91520b81520b9156a21ba1520b91520ba156a" - "21bb1520ba1520bb156a21bc1520bb1520bc156a21bd1520bc1520bd156a21be1520bd1520be156a21bf1520be1520" - "bf156a21c01520bf1520c0156a21c11520c01520c1156a21c21520c11520c2156a21c31520c21520c3156a21c41520" - "c31520c4156a21c51520c41520c5156a21c61520c51520c6156a21c71520c61520c7156a21c81520c71520c8156a21" - "c91520c81520c9156a21ca1520c91520ca156a21cb1520ca1520cb156a21cc1520cb1520cc156a21cd1520cc1520cd" - "156a21ce1520cd1520ce156a21cf1520ce1520cf156a21d01520cf1520d0156a21d11520d01520d1156a21d21520d1" - "1520d2156a21d31520d21520d3156a21d41520d31520d4156a21d51520d41520d5156a21d61520d51520d6156a21d7" - "1520d61520d7156a21d81520d71520d8156a21d91520d81520d9156a21da1520d91520da156a21db1520da1520db15" - "6a21dc1520db1520dc156a21dd1520dc1520dd156a21de1520dd1520de156a21df1520de1520df156a21e01520df15" - "20e0156a21e11520e01520e1156a21e21520e11520e2156a21e31520e21520e3156a21e41520e31520e4156a21e515" - "20e41520e5156a21e61520e51520e6156a21e71520e61520e7156a21e81520e71520e8156a21e91520e81520e9156a" - "21ea1520e91520ea156a21eb1520ea1520eb156a21ec1520eb1520ec156a21ed1520ec1520ed156a21ee1520ed1520" - "ee156a21ef1520ee1520ef156a21f01520ef1520f0156a21f11520f01520f1156a21f21520f11520f2156a21f31520" - "f21520f3156a21f41520f31520f4156a21f51520f41520f5156a21f61520f51520f6156a21f71520f61520f7156a21" - "f81520f71520f8156a21f91520f81520f9156a21fa1520f91520fa156a21fb1520fa1520fb156a21fc1520fb1520fc" - "156a21fd1520fc1520fd156a21fe1520fd1520fe156a21ff1520fe1520ff156a21801620ff152080166a2181162080" - "162081166a2182162081162082166a2183162082162083166a2184162083162084166a2185162084162085166a2186" - "162085162086166a2187162086162087166a2188162087162088166a2189162088162089166a218a16208916208a16" - "6a218b16208a16208b166a218c16208b16208c166a218d16208c16208d166a218e16208d16208e166a218f16208e16" - "208f166a219016208f162090166a2191162090162091166a2192162091162092166a2193162092162093166a219416" - "2093162094166a2195162094162095166a2196162095162096166a2197162096162097166a2198162097162098166a" - "2199162098162099166a219a16209916209a166a219b16209a16209b166a219c16209b16209c166a219d16209c1620" - "9d166a219e16209d16209e166a219f16209e16209f166a21a016209f1620a0166a21a11620a01620a1166a21a21620" - "a11620a2166a21a31620a21620a3166a21a41620a31620a4166a21a51620a41620a5166a21a61620a51620a6166a21" - "a71620a61620a7166a21a81620a71620a8166a21a91620a81620a9166a21aa1620a91620aa166a21ab1620aa1620ab" - "166a21ac1620ab1620ac166a21ad1620ac1620ad166a21ae1620ad1620ae166a21af1620ae1620af166a21b01620af" - "1620b0166a21b11620b01620b1166a21b21620b11620b2166a21b31620b21620b3166a21b41620b31620b4166a21b5" - "1620b41620b5166a21b61620b51620b6166a21b71620b61620b7166a21b81620b71620b8166a21b91620b81620b916" - "6a21ba1620b91620ba166a21bb1620ba1620bb166a21bc1620bb1620bc166a21bd1620bc1620bd166a21be1620bd16" - "20be166a21bf1620be1620bf166a21c01620bf1620c0166a21c11620c01620c1166a21c21620c11620c2166a21c316" - "20c21620c3166a21c41620c31620c4166a21c51620c41620c5166a21c61620c51620c6166a21c71620c61620c7166a" - "21c81620c71620c8166a21c91620c81620c9166a21ca1620c91620ca166a21cb1620ca1620cb166a21cc1620cb1620" - "cc166a21cd1620cc1620cd166a21ce1620cd1620ce166a21cf1620ce1620cf166a21d01620cf1620d0166a21d11620" - "d01620d1166a21d21620d11620d2166a21d31620d21620d3166a21d41620d31620d4166a21d51620d41620d5166a21" - "d61620d51620d6166a21d71620d61620d7166a21d81620d71620d8166a21d91620d81620d9166a21da1620d91620da" - "166a21db1620da1620db166a21dc1620db1620dc166a21dd1620dc1620dd166a21de1620dd1620de166a21df1620de" - "1620df166a21e01620df1620e0166a21e11620e01620e1166a21e21620e11620e2166a21e31620e21620e3166a21e4" - "1620e31620e4166a21e51620e41620e5166a21e61620e51620e6166a21e71620e61620e7166a21e81620e71620e816" - "6a21e91620e81620e9166a21ea1620e91620ea166a21eb1620ea1620eb166a21ec1620eb1620ec166a21ed1620ec16" - "20ed166a21ee1620ed1620ee166a21ef1620ee1620ef166a21f01620ef1620f0166a21f11620f01620f1166a21f216" - "20f11620f2166a21f31620f21620f3166a21f41620f31620f4166a21f51620f41620f5166a21f61620f51620f6166a" - "21f71620f61620f7166a21f81620f71620f8166a21f91620f81620f9166a21fa1620f91620fa166a21fb1620fa1620" - "fb166a21fc1620fb1620fc166a21fd1620fc1620fd166a21fe1620fd1620fe166a21ff1620fe1620ff166a21801720" - "ff162080176a2181172080172081176a2182172081172082176a2183172082172083176a2184172083172084176a21" - "85172084172085176a2186172085172086176a2187172086172087176a2188172087172088176a2189172088172089" - "176a218a17208917208a176a218b17208a17208b176a218c17208b17208c176a218d17208c17208d176a218e17208d" - "17208e176a218f17208e17208f176a219017208f172090176a2191172090172091176a2192172091172092176a2193" - "172092172093176a2194172093172094176a2195172094172095176a2196172095172096176a219717209617209717" - "6a2198172097172098176a2199172098172099176a219a17209917209a176a219b17209a17209b176a219c17209b17" - "209c176a219d17209c17209d176a219e17209d17209e176a219f17209e17209f176a21a017209f1720a0176a21a117" - "20a01720a1176a21a21720a11720a2176a21a31720a21720a3176a21a41720a31720a4176a21a51720a41720a5176a" - "21a61720a51720a6176a21a71720a61720a7176a21a81720a71720a8176a21a91720a81720a9176a21aa1720a91720" - "aa176a21ab1720aa1720ab176a21ac1720ab1720ac176a21ad1720ac1720ad176a21ae1720ad1720ae176a21af1720" - "ae1720af176a21b01720af1720b0176a21b11720b01720b1176a21b21720b11720b2176a21b31720b21720b3176a21" - "b41720b31720b4176a21b51720b41720b5176a21b61720b51720b6176a21b71720b61720b7176a21b81720b71720b8" - "176a21b91720b81720b9176a21ba1720b91720ba176a21bb1720ba1720bb176a21bc1720bb1720bc176a21bd1720bc" - "1720bd176a21be1720bd1720be176a21bf1720be1720bf176a21c01720bf1720c0176a21c11720c01720c1176a21c2" - "1720c11720c2176a21c31720c21720c3176a21c41720c31720c4176a21c51720c41720c5176a21c61720c51720c617" - "6a21c71720c61720c7176a21c81720c71720c8176a21c91720c81720c9176a21ca1720c91720ca176a21cb1720ca17" - "20cb176a21cc1720cb1720cc176a21cd1720cc1720cd176a21ce1720cd1720ce176a21cf1720ce1720cf176a21d017" - "20cf1720d0176a21d11720d01720d1176a21d21720d11720d2176a21d31720d21720d3176a21d41720d31720d4176a" - "21d51720d41720d5176a21d61720d51720d6176a21d71720d61720d7176a21d81720d71720d8176a21d91720d81720" - "d9176a21da1720d91720da176a21db1720da1720db176a21dc1720db1720dc176a21dd1720dc1720dd176a21de1720" - "dd1720de176a21df1720de1720df176a21e01720df1720e0176a21e11720e01720e1176a21e21720e11720e2176a21" - "e31720e21720e3176a21e41720e31720e4176a21e51720e41720e5176a21e61720e51720e6176a21e71720e61720e7" - "176a21e81720e71720e8176a21e91720e81720e9176a21ea1720e91720ea176a21eb1720ea1720eb176a21ec1720eb" - "1720ec176a21ed1720ec1720ed176a21ee1720ed1720ee176a21ef1720ee1720ef176a21f01720ef1720f0176a21f1" - "1720f01720f1176a21f21720f11720f2176a21f31720f21720f3176a21f41720f31720f4176a21f51720f41720f517" - "6a21f61720f51720f6176a21f71720f61720f7176a21f81720f71720f8176a21f91720f81720f9176a21fa1720f917" - "20fa176a21fb1720fa1720fb176a21fc1720fb1720fc176a21fd1720fc1720fd176a21fe1720fd1720fe176a21ff17" - "20fe1720ff176a21801820ff172080186a2181182080182081186a2182182081182082186a2183182082182083186a" - "2184182083182084186a2185182084182085186a2186182085182086186a2187182086182087186a21881820871820" - "88186a2189182088182089186a218a18208918208a186a218b18208a18208b186a218c18208b18208c186a218d1820" - "8c18208d186a218e18208d18208e186a218f18208e18208f186a219018208f182090186a2191182090182091186a21" - "92182091182092186a2193182092182093186a2194182093182094186a2195182094182095186a2196182095182096" - "186a2197182096182097186a2198182097182098186a2199182098182099186a219a18209918209a186a219b18209a" - "18209b186a219c18209b18209c186a219d18209c18209d186a219e18209d18209e186a219f18209e18209f186a21a0" - "18209f1820a0186a21a11820a01820a1186a21a21820a11820a2186a21a31820a21820a3186a21a41820a31820a418" - "6a21a51820a41820a5186a21a61820a51820a6186a21a71820a61820a7186a21a81820a71820a8186a21a91820a818" - "20a9186a21aa1820a91820aa186a21ab1820aa1820ab186a21ac1820ab1820ac186a21ad1820ac1820ad186a21ae18" - "20ad1820ae186a21af1820ae1820af186a21b01820af1820b0186a21b11820b01820b1186a21b21820b11820b2186a" - "21b31820b21820b3186a21b41820b31820b4186a21b51820b41820b5186a21b61820b51820b6186a21b71820b61820" - "b7186a21b81820b71820b8186a21b91820b81820b9186a21ba1820b91820ba186a21bb1820ba1820bb186a21bc1820" - "bb1820bc186a21bd1820bc1820bd186a21be1820bd1820be186a21bf1820be1820bf186a21c01820bf1820c0186a21" - "c11820c01820c1186a21c21820c11820c2186a21c31820c21820c3186a21c41820c31820c4186a21c51820c41820c5" - "186a21c61820c51820c6186a21c71820c61820c7186a21c81820c71820c8186a21c91820c81820c9186a21ca1820c9" - "1820ca186a21cb1820ca1820cb186a21cc1820cb1820cc186a21cd1820cc1820cd186a21ce1820cd1820ce186a21cf" - "1820ce1820cf186a21d01820cf1820d0186a21d11820d01820d1186a21d21820d11820d2186a21d31820d21820d318" - "6a21d41820d31820d4186a21d51820d41820d5186a21d61820d51820d6186a21d71820d61820d7186a21d81820d718" - "20d8186a21d91820d81820d9186a21da1820d91820da186a21db1820da1820db186a21dc1820db1820dc186a21dd18" - "20dc1820dd186a21de1820dd1820de186a21df1820de1820df186a21e01820df1820e0186a21e11820e01820e1186a" - "21e21820e11820e2186a21e31820e21820e3186a21e41820e31820e4186a21e51820e41820e5186a21e61820e51820" - "e6186a21e71820e61820e7186a21e81820e71820e8186a21e91820e81820e9186a21ea1820e91820ea186a21eb1820" - "ea1820eb186a21ec1820eb1820ec186a21ed1820ec1820ed186a21ee1820ed1820ee186a21ef1820ee1820ef186a21" - "f01820ef1820f0186a21f11820f01820f1186a21f21820f11820f2186a21f31820f21820f3186a21f41820f31820f4" - "186a21f51820f41820f5186a21f61820f51820f6186a21f71820f61820f7186a21f81820f71820f8186a21f91820f8" - "1820f9186a21fa1820f91820fa186a21fb1820fa1820fb186a21fc1820fb1820fc186a21fd1820fc1820fd186a21fe" - "1820fd1820fe186a21ff1820fe1820ff186a21801920ff182080196a2181192080192081196a218219208119208219" - "6a2183192082192083196a2184192083192084196a2185192084192085196a2186192085192086196a218719208619" - "2087196a2188192087192088196a2189192088192089196a218a19208919208a196a218b19208a19208b196a218c19" - "208b19208c196a218d19208c19208d196a218e19208d19208e196a218f19208e19208f196a219019208f192090196a" - "2191192090192091196a2192192091192092196a2193192092192093196a2194192093192094196a21951920941920" - "95196a2196192095192096196a2197192096192097196a2198192097192098196a2199192098192099196a219a1920" - "9919209a196a219b19209a19209b196a219c19209b19209c196a219d19209c19209d196a219e19209d19209e196a21" - "9f19209e19209f196a21a019209f1920a0196a21a11920a01920a1196a21a21920a11920a2196a21a31920a21920a3" - "196a21a41920a31920a4196a21a51920a41920a5196a21a61920a51920a6196a21a71920a61920a7196a21a81920a7" - "1920a8196a21a91920a81920a9196a21aa1920a91920aa196a21ab1920aa1920ab196a21ac1920ab1920ac196a21ad" - "1920ac1920ad196a21ae1920ad1920ae196a21af1920ae1920af196a21b01920af1920b0196a21b11920b01920b119" - "6a21b21920b11920b2196a21b31920b21920b3196a21b41920b31920b4196a21b51920b41920b5196a21b61920b519" - "20b6196a21b71920b61920b7196a21b81920b71920b8196a21b91920b81920b9196a21ba1920b91920ba196a21bb19" - "20ba1920bb196a21bc1920bb1920bc196a21bd1920bc1920bd196a21be1920bd1920be196a21bf1920be1920bf196a" - "21c01920bf1920c0196a21c11920c01920c1196a21c21920c11920c2196a21c31920c21920c3196a21c41920c31920" - "c4196a21c51920c41920c5196a21c61920c51920c6196a21c71920c61920c7196a21c81920c71920c8196a21c91920" - "c81920c9196a21ca1920c91920ca196a21cb1920ca1920cb196a21cc1920cb1920cc196a21cd1920cc1920cd196a21" - "ce1920cd1920ce196a21cf1920ce1920cf196a21d01920cf1920d0196a21d11920d01920d1196a21d21920d11920d2" - "196a21d31920d21920d3196a21d41920d31920d4196a21d51920d41920d5196a21d61920d51920d6196a21d71920d6" - "1920d7196a21d81920d71920d8196a21d91920d81920d9196a21da1920d91920da196a21db1920da1920db196a21dc" - "1920db1920dc196a21dd1920dc1920dd196a21de1920dd1920de196a21df1920de1920df196a21e01920df1920e019" - "6a21e11920e01920e1196a21e21920e11920e2196a21e31920e21920e3196a21e41920e31920e4196a21e51920e419" - "20e5196a21e61920e51920e6196a21e71920e61920e7196a21e81920e71920e8196a21e91920e81920e9196a21ea19" - "20e91920ea196a21eb1920ea1920eb196a21ec1920eb1920ec196a21ed1920ec1920ed196a21ee1920ed1920ee196a" - "21ef1920ee1920ef196a21f01920ef1920f0196a21f11920f01920f1196a21f21920f11920f2196a21f31920f21920" - "f3196a21f41920f31920f4196a21f51920f41920f5196a21f61920f51920f6196a21f71920f61920f7196a21f81920" - "f71920f8196a21f91920f81920f9196a21fa1920f91920fa196a21fb1920fa1920fb196a21fc1920fb1920fc196a21" - "fd1920fc1920fd196a21fe1920fd1920fe196a21ff1920fe1920ff196a21801a20ff1920801a6a21811a20801a2081" - "1a6a21821a20811a20821a6a21831a20821a20831a6a21841a20831a20841a6a21851a20841a20851a6a21861a2085" - "1a20861a6a21871a20861a20871a6a21881a20871a20881a6a21891a20881a20891a6a218a1a20891a208a1a6a218b" - "1a208a1a208b1a6a218c1a208b1a208c1a6a218d1a208c1a208d1a6a218e1a208d1a208e1a6a218f1a208e1a208f1a" - "6a21901a208f1a20901a6a21911a20901a20911a6a21921a20911a20921a6a21931a20921a20931a6a21941a20931a" - "20941a6a21951a20941a20951a6a21961a20951a20961a6a21971a20961a20971a6a21981a20971a20981a6a21991a" - "20981a20991a6a219a1a20991a209a1a6a219b1a209a1a209b1a6a219c1a209b1a209c1a6a219d1a209c1a209d1a6a" - "219e1a209d1a209e1a6a219f1a209e1a209f1a6a21a01a209f1a20a01a6a21a11a20a01a20a11a6a21a21a20a11a20" - "a21a6a21a31a20a21a20a31a6a21a41a20a31a20a41a6a21a51a20a41a20a51a6a21a61a20a51a20a61a6a21a71a20" - "a61a20a71a6a21a81a20a71a20a81a6a21a91a20a81a20a91a6a21aa1a20a91a20aa1a6a21ab1a20aa1a20ab1a6a21" - "ac1a20ab1a20ac1a6a21ad1a20ac1a20ad1a6a21ae1a20ad1a20ae1a6a21af1a20ae1a20af1a6a21b01a20af1a20b0" - "1a6a21b11a20b01a20b11a6a21b21a20b11a20b21a6a21b31a20b21a20b31a6a21b41a20b31a20b41a6a21b51a20b4" - "1a20b51a6a21b61a20b51a20b61a6a21b71a20b61a20b71a6a21b81a20b71a20b81a6a21b91a20b81a20b91a6a21ba" - "1a20b91a20ba1a6a21bb1a20ba1a20bb1a6a21bc1a20bb1a20bc1a6a21bd1a20bc1a20bd1a6a21be1a20bd1a20be1a" - "6a21bf1a20be1a20bf1a6a21c01a20bf1a20c01a6a21c11a20c01a20c11a6a21c21a20c11a20c21a6a21c31a20c21a" - "20c31a6a21c41a20c31a20c41a6a21c51a20c41a20c51a6a21c61a20c51a20c61a6a21c71a20c61a20c71a6a21c81a" - "20c71a20c81a6a21c91a20c81a20c91a6a21ca1a20c91a20ca1a6a21cb1a20ca1a20cb1a6a21cc1a20cb1a20cc1a6a" - "21cd1a20cc1a20cd1a6a21ce1a20cd1a20ce1a6a21cf1a20ce1a20cf1a6a21d01a20cf1a20d01a6a21d11a20d01a20" - "d11a6a21d21a20d11a20d21a6a21d31a20d21a20d31a6a21d41a20d31a20d41a6a21d51a20d41a20d51a6a21d61a20" - "d51a20d61a6a21d71a20d61a20d71a6a21d81a20d71a20d81a6a21d91a20d81a20d91a6a21da1a20d91a20da1a6a21" - "db1a20da1a20db1a6a21dc1a20db1a20dc1a6a21dd1a20dc1a20dd1a6a21de1a20dd1a20de1a6a21df1a20de1a20df" - "1a6a21e01a20df1a20e01a6a21e11a20e01a20e11a6a21e21a20e11a20e21a6a21e31a20e21a20e31a6a21e41a20e3" - "1a20e41a6a21e51a20e41a20e51a6a21e61a20e51a20e61a6a21e71a20e61a20e71a6a21e81a20e71a20e81a6a21e9" - "1a20e81a20e91a6a21ea1a20e91a20ea1a6a21eb1a20ea1a20eb1a6a21ec1a20eb1a20ec1a6a21ed1a20ec1a20ed1a" - "6a21ee1a20ed1a20ee1a6a21ef1a20ee1a20ef1a6a21f01a20ef1a20f01a6a21f11a20f01a20f11a6a21f21a20f11a" - "20f21a6a21f31a20f21a20f31a6a21f41a20f31a20f41a6a21f51a20f41a20f51a6a21f61a20f51a20f61a6a21f71a" - "20f61a20f71a6a21f81a20f71a20f81a6a21f91a20f81a20f91a6a21fa1a20f91a20fa1a6a21fb1a20fa1a20fb1a6a" - "21fc1a20fb1a20fc1a6a21fd1a20fc1a20fd1a6a21fe1a20fd1a20fe1a6a21ff1a20fe1a20ff1a6a21801b20ff1a20" - "801b6a21811b20801b20811b6a21821b20811b20821b6a21831b20821b20831b6a21841b20831b20841b6a21851b20" - "841b20851b6a21861b20851b20861b6a21871b20861b20871b6a21881b20871b20881b6a21891b20881b20891b6a21" - "8a1b20891b208a1b6a218b1b208a1b208b1b6a218c1b208b1b208c1b6a218d1b208c1b208d1b6a218e1b208d1b208e" - "1b6a218f1b208e1b208f1b6a21901b208f1b20901b6a21911b20901b20911b6a21921b20911b20921b6a21931b2092" - "1b20931b6a21941b20931b20941b6a21951b20941b20951b6a21961b20951b20961b6a21971b20961b20971b6a2198" - "1b20971b20981b6a21991b20981b20991b6a219a1b20991b209a1b6a219b1b209a1b209b1b6a219c1b209b1b209c1b" - "6a219d1b209c1b209d1b6a219e1b209d1b209e1b6a219f1b209e1b209f1b6a21a01b209f1b20a01b6a21a11b20a01b" - "20a11b6a21a21b20a11b20a21b6a21a31b20a21b20a31b6a21a41b20a31b20a41b6a21a51b20a41b20a51b6a21a61b" - "20a51b20a61b6a21a71b20a61b20a71b6a21a81b20a71b20a81b6a21a91b20a81b20a91b6a21aa1b20a91b20aa1b6a" - "21ab1b20aa1b20ab1b6a21ac1b20ab1b20ac1b6a21ad1b20ac1b20ad1b6a21ae1b20ad1b20ae1b6a21af1b20ae1b20" - "af1b6a21b01b20af1b20b01b6a21b11b20b01b20b11b6a21b21b20b11b20b21b6a21b31b20b21b20b31b6a21b41b20" - "b31b20b41b6a21b51b20b41b20b51b6a21b61b20b51b20b61b6a21b71b20b61b20b71b6a21b81b20b71b20b81b6a21" - "b91b20b81b20b91b6a21ba1b20b91b20ba1b6a21bb1b20ba1b20bb1b6a21bc1b20bb1b20bc1b6a21bd1b20bc1b20bd" - "1b6a21be1b20bd1b20be1b6a21bf1b20be1b20bf1b6a21c01b20bf1b20c01b6a21c11b20c01b20c11b6a21c21b20c1" - "1b20c21b6a21c31b20c21b20c31b6a21c41b20c31b20c41b6a21c51b20c41b20c51b6a21c61b20c51b20c61b6a21c7" - "1b20c61b20c71b6a21c81b20c71b20c81b6a21c91b20c81b20c91b6a21ca1b20c91b20ca1b6a21cb1b20ca1b20cb1b" - "6a21cc1b20cb1b20cc1b6a21cd1b20cc1b20cd1b6a21ce1b20cd1b20ce1b6a21cf1b20ce1b20cf1b6a21d01b20cf1b" - "20d01b6a21d11b20d01b20d11b6a21d21b20d11b20d21b6a21d31b20d21b20d31b6a21d41b20d31b20d41b6a21d51b" - "20d41b20d51b6a21d61b20d51b20d61b6a21d71b20d61b20d71b6a21d81b20d71b20d81b6a21d91b20d81b20d91b6a" - "21da1b20d91b20da1b6a21db1b20da1b20db1b6a21dc1b20db1b20dc1b6a21dd1b20dc1b20dd1b6a21de1b20dd1b20" - "de1b6a21df1b20de1b20df1b6a21e01b20df1b20e01b6a21e11b20e01b20e11b6a21e21b20e11b20e21b6a21e31b20" - "e21b20e31b6a21e41b20e31b20e41b6a21e51b20e41b20e51b6a21e61b20e51b20e61b6a21e71b20e61b20e71b6a21" - "e81b20e71b20e81b6a21e91b20e81b20e91b6a21ea1b20e91b20ea1b6a21eb1b20ea1b20eb1b6a21ec1b20eb1b20ec" - "1b6a21ed1b20ec1b20ed1b6a21ee1b20ed1b20ee1b6a21ef1b20ee1b20ef1b6a21f01b20ef1b20f01b6a21f11b20f0" - "1b20f11b6a21f21b20f11b20f21b6a21f31b20f21b20f31b6a21f41b20f31b20f41b6a21f51b20f41b20f51b6a21f6" - "1b20f51b20f61b6a21f71b20f61b20f71b6a21f81b20f71b20f81b6a21f91b20f81b20f91b6a21fa1b20f91b20fa1b" - "6a21fb1b20fa1b20fb1b6a21fc1b20fb1b20fc1b6a21fd1b20fc1b20fd1b6a21fe1b20fd1b20fe1b6a21ff1b20fe1b" - "20ff1b6a21801c20ff1b20801c6a21811c20801c20811c6a21821c20811c20821c6a21831c20821c20831c6a21841c" - "20831c20841c6a21851c20841c20851c6a21861c20851c20861c6a21871c20861c20871c6a21881c20871c20881c6a" - "21891c20881c20891c6a218a1c20891c208a1c6a218b1c208a1c208b1c6a218c1c208b1c208c1c6a218d1c208c1c20" - "8d1c6a218e1c208d1c208e1c6a218f1c208e1c208f1c6a21901c208f1c20901c6a21911c20901c20911c6a21921c20" - "911c20921c6a21931c20921c20931c6a21941c20931c20941c6a21951c20941c20951c6a21961c20951c20961c6a21" - "971c20961c20971c6a21981c20971c20981c6a21991c20981c20991c6a219a1c20991c209a1c6a219b1c209a1c209b" - "1c6a219c1c209b1c209c1c6a219d1c209c1c209d1c6a219e1c209d1c209e1c6a219f1c209e1c209f1c6a21a01c209f" - "1c20a01c6a21a11c20a01c20a11c6a21a21c20a11c20a21c6a21a31c20a21c20a31c6a21a41c20a31c20a41c6a21a5" - "1c20a41c20a51c6a21a61c20a51c20a61c6a21a71c20a61c20a71c6a21a81c20a71c20a81c6a21a91c20a81c20a91c" - "6a21aa1c20a91c20aa1c6a21ab1c20aa1c20ab1c6a21ac1c20ab1c20ac1c6a21ad1c20ac1c20ad1c6a21ae1c20ad1c" - "20ae1c6a21af1c20ae1c20af1c6a21b01c20af1c20b01c6a21b11c20b01c20b11c6a21b21c20b11c20b21c6a21b31c" - "20b21c20b31c6a21b41c20b31c20b41c6a21b51c20b41c20b51c6a21b61c20b51c20b61c6a21b71c20b61c20b71c6a" - "21b81c20b71c20b81c6a21b91c20b81c20b91c6a21ba1c20b91c20ba1c6a21bb1c20ba1c20bb1c6a21bc1c20bb1c20" - "bc1c6a21bd1c20bc1c20bd1c6a21be1c20bd1c20be1c6a21bf1c20be1c20bf1c6a21c01c20bf1c20c01c6a21c11c20" - "c01c20c11c6a21c21c20c11c20c21c6a21c31c20c21c20c31c6a21c41c20c31c20c41c6a21c51c20c41c20c51c6a21" - "c61c20c51c20c61c6a21c71c20c61c20c71c6a21c81c20c71c20c81c6a21c91c20c81c20c91c6a21ca1c20c91c20ca" - "1c6a21cb1c20ca1c20cb1c6a21cc1c20cb1c20cc1c6a21cd1c20cc1c20cd1c6a21ce1c20cd1c20ce1c6a21cf1c20ce" - "1c20cf1c6a21d01c20cf1c20d01c6a21d11c20d01c20d11c6a21d21c20d11c20d21c6a21d31c20d21c20d31c6a21d4" - "1c20d31c20d41c6a21d51c20d41c20d51c6a21d61c20d51c20d61c6a21d71c20d61c20d71c6a21d81c20d71c20d81c" - "6a21d91c20d81c20d91c6a21da1c20d91c20da1c6a21db1c20da1c20db1c6a21dc1c20db1c20dc1c6a21dd1c20dc1c" - "20dd1c6a21de1c20dd1c20de1c6a21df1c20de1c20df1c6a21e01c20df1c20e01c6a21e11c20e01c20e11c6a21e21c" - "20e11c20e21c6a21e31c20e21c20e31c6a21e41c20e31c20e41c6a21e51c20e41c20e51c6a21e61c20e51c20e61c6a" - "21e71c20e61c20e71c6a21e81c20e71c20e81c6a21e91c20e81c20e91c6a21ea1c20e91c20ea1c6a21eb1c20ea1c20" - "eb1c6a21ec1c20eb1c20ec1c6a21ed1c20ec1c20ed1c6a21ee1c20ed1c20ee1c6a21ef1c20ee1c20ef1c6a21f01c20" - "ef1c20f01c6a21f11c20f01c20f11c6a21f21c20f11c20f21c6a21f31c20f21c20f31c6a21f41c20f31c20f41c6a21" - "f51c20f41c20f51c6a21f61c20f51c20f61c6a21f71c20f61c20f71c6a21f81c20f71c20f81c6a21f91c20f81c20f9" - "1c6a21fa1c20f91c20fa1c6a21fb1c20fa1c20fb1c6a21fc1c20fb1c20fc1c6a21fd1c20fc1c20fd1c6a21fe1c20fd" - "1c20fe1c6a21ff1c20fe1c20ff1c6a21801d20ff1c20801d6a21811d20801d20811d6a21821d20811d20821d6a2183" - "1d20821d20831d6a21841d20831d20841d6a21851d20841d20851d6a21861d20851d20861d6a21871d20861d20871d" - "6a21881d20871d20881d6a21891d20881d20891d6a218a1d20891d208a1d6a218b1d208a1d208b1d6a218c1d208b1d" - "208c1d6a218d1d208c1d208d1d6a218e1d208d1d208e1d6a218f1d208e1d208f1d6a21901d208f1d20901d6a21911d" - "20901d20911d6a21921d20911d20921d6a21931d20921d20931d6a21941d20931d20941d6a21951d20941d20951d6a" - "21961d20951d20961d6a21971d20961d20971d6a21981d20971d20981d6a21991d20981d20991d6a219a1d20991d20" - "9a1d6a219b1d209a1d209b1d6a219c1d209b1d209c1d6a219d1d209c1d209d1d6a219e1d209d1d209e1d6a219f1d20" - "9e1d209f1d6a21a01d209f1d20a01d6a21a11d20a01d20a11d6a21a21d20a11d20a21d6a21a31d20a21d20a31d6a21" - "a41d20a31d20a41d6a21a51d20a41d20a51d6a21a61d20a51d20a61d6a21a71d20a61d20a71d6a21a81d20a71d20a8" - "1d6a21a91d20a81d20a91d6a21aa1d20a91d20aa1d6a21ab1d20aa1d20ab1d6a21ac1d20ab1d20ac1d6a21ad1d20ac" - "1d20ad1d6a21ae1d20ad1d20ae1d6a21af1d20ae1d20af1d6a21b01d20af1d20b01d6a21b11d20b01d20b11d6a21b2" - "1d20b11d20b21d6a21b31d20b21d20b31d6a21b41d20b31d20b41d6a21b51d20b41d20b51d6a21b61d20b51d20b61d" - "6a21b71d20b61d20b71d6a21b81d20b71d20b81d6a21b91d20b81d20b91d6a21ba1d20b91d20ba1d6a21bb1d20ba1d" - "20bb1d6a21bc1d20bb1d20bc1d6a21bd1d20bc1d20bd1d6a21be1d20bd1d20be1d6a21bf1d20be1d20bf1d6a21c01d" - "20bf1d20c01d6a21c11d20c01d20c11d6a21c21d20c11d20c21d6a21c31d20c21d20c31d6a21c41d20c31d20c41d6a" - "21c51d20c41d20c51d6a21c61d20c51d20c61d6a21c71d20c61d20c71d6a21c81d20c71d20c81d6a21c91d20c81d20" - "c91d6a21ca1d20c91d20ca1d6a21cb1d20ca1d20cb1d6a21cc1d20cb1d20cc1d6a21cd1d20cc1d20cd1d6a21ce1d20" - "cd1d20ce1d6a21cf1d20ce1d20cf1d6a21d01d20cf1d20d01d6a21d11d20d01d20d11d6a21d21d20d11d20d21d6a21" - "d31d20d21d20d31d6a21d41d20d31d20d41d6a21d51d20d41d20d51d6a21d61d20d51d20d61d6a21d71d20d61d20d7" - "1d6a21d81d20d71d20d81d6a21d91d20d81d20d91d6a21da1d20d91d20da1d6a21db1d20da1d20db1d6a21dc1d20db" - "1d20dc1d6a21dd1d20dc1d20dd1d6a21de1d20dd1d20de1d6a21df1d20de1d20df1d6a21e01d20df1d20e01d6a21e1" - "1d20e01d20e11d6a21e21d20e11d20e21d6a21e31d20e21d20e31d6a21e41d20e31d20e41d6a21e51d20e41d20e51d" - "6a21e61d20e51d20e61d6a21e71d20e61d20e71d6a21e81d20e71d20e81d6a21e91d20e81d20e91d6a21ea1d20e91d" - "20ea1d6a21eb1d20ea1d20eb1d6a21ec1d20eb1d20ec1d6a21ed1d20ec1d20ed1d6a21ee1d20ed1d20ee1d6a21ef1d" - "20ee1d20ef1d6a21f01d20ef1d20f01d6a21f11d20f01d20f11d6a21f21d20f11d20f21d6a21f31d20f21d20f31d6a" - "21f41d20f31d20f41d6a21f51d20f41d20f51d6a21f61d20f51d20f61d6a21f71d20f61d20f71d6a21f81d20f71d20" - "f81d6a21f91d20f81d20f91d6a21fa1d20f91d20fa1d6a21fb1d20fa1d20fb1d6a21fc1d20fb1d20fc1d6a21fd1d20" - "fc1d20fd1d6a21fe1d20fd1d20fe1d6a21ff1d20fe1d20ff1d6a21801e20ff1d20801e6a21811e20801e20811e6a21" - "821e20811e20821e6a21831e20821e20831e6a21841e20831e20841e6a21851e20841e20851e6a21861e20851e2086" - "1e6a21871e20861e20871e6a21881e20871e20881e6a21891e20881e20891e6a218a1e20891e208a1e6a218b1e208a" - "1e208b1e6a218c1e208b1e208c1e6a218d1e208c1e208d1e6a218e1e208d1e208e1e6a218f1e208e1e208f1e6a2190" - "1e208f1e20901e6a21911e20901e20911e6a21921e20911e20921e6a21931e20921e20931e6a21941e20931e20941e" - "6a21951e20941e20951e6a21961e20951e20961e6a21971e20961e20971e6a21981e20971e20981e6a21991e20981e" - "20991e6a219a1e20991e209a1e6a219b1e209a1e209b1e6a219c1e209b1e209c1e6a219d1e209c1e209d1e6a219e1e" - "209d1e209e1e6a219f1e209e1e209f1e6a21a01e209f1e20a01e6a21a11e20a01e20a11e6a21a21e20a11e20a21e6a" - "21a31e20a21e20a31e6a21a41e20a31e20a41e6a21a51e20a41e20a51e6a21a61e20a51e20a61e6a21a71e20a61e20" - "a71e6a21a81e20a71e20a81e6a21a91e20a81e20a91e6a21aa1e20a91e20aa1e6a21ab1e20aa1e20ab1e6a21ac1e20" - "ab1e20ac1e6a21ad1e20ac1e20ad1e6a21ae1e20ad1e20ae1e6a21af1e20ae1e20af1e6a21b01e20af1e20b01e6a21" - "b11e20b01e20b11e6a21b21e20b11e20b21e6a21b31e20b21e20b31e6a21b41e20b31e20b41e6a21b51e20b41e20b5" - "1e6a21b61e20b51e20b61e6a21b71e20b61e20b71e6a21b81e20b71e20b81e6a21b91e20b81e20b91e6a21ba1e20b9" - "1e20ba1e6a21bb1e20ba1e20bb1e6a21bc1e20bb1e20bc1e6a21bd1e20bc1e20bd1e6a21be1e20bd1e20be1e6a21bf" - "1e20be1e20bf1e6a21c01e20bf1e20c01e6a21c11e20c01e20c11e6a21c21e20c11e20c21e6a21c31e20c21e20c31e" - "6a21c41e20c31e20c41e6a21c51e20c41e20c51e6a21c61e20c51e20c61e6a21c71e20c61e20c71e6a21c81e20c71e" - "20c81e6a21c91e20c81e20c91e6a21ca1e20c91e20ca1e6a21cb1e20ca1e20cb1e6a21cc1e20cb1e20cc1e6a21cd1e" - "20cc1e20cd1e6a21ce1e20cd1e20ce1e6a21cf1e20ce1e20cf1e6a21d01e20cf1e20d01e6a21d11e20d01e20d11e6a" - "21d21e20d11e20d21e6a21d31e20d21e20d31e6a21d41e20d31e20d41e6a21d51e20d41e20d51e6a21d61e20d51e20" - "d61e6a21d71e20d61e20d71e6a21d81e20d71e20d81e6a21d91e20d81e20d91e6a21da1e20d91e20da1e6a21db1e20" - "da1e20db1e6a21dc1e20db1e20dc1e6a21dd1e20dc1e20dd1e6a21de1e20dd1e20de1e6a21df1e20de1e20df1e6a21" - "e01e20df1e20e01e6a21e11e20e01e20e11e6a21e21e20e11e20e21e6a21e31e20e21e20e31e6a21e41e20e31e20e4" - "1e6a21e51e20e41e20e51e6a21e61e20e51e20e61e6a21e71e20e61e20e71e6a21e81e20e71e20e81e6a21e91e20e8" - "1e20e91e6a21ea1e20e91e20ea1e6a21eb1e20ea1e20eb1e6a21ec1e20eb1e20ec1e6a21ed1e20ec1e20ed1e6a21ee" - "1e20ed1e20ee1e6a21ef1e20ee1e20ef1e6a21f01e20ef1e20f01e6a21f11e20f01e20f11e6a21f21e20f11e20f21e" - "6a21f31e20f21e20f31e6a21f41e20f31e20f41e6a21f51e20f41e20f51e6a21f61e20f51e20f61e6a21f71e20f61e" - "20f71e6a21f81e20f71e20f81e6a21f91e20f81e20f91e6a21fa1e20f91e20fa1e6a21fb1e20fa1e20fb1e6a21fc1e" - "20fb1e20fc1e6a21fd1e20fc1e20fd1e6a21fe1e20fd1e20fe1e6a21ff1e20fe1e20ff1e6a21801f20ff1e20801f6a" - "21811f20801f20811f6a21821f20811f20821f6a21831f20821f20831f6a21841f20831f20841f6a21851f20841f20" - "851f6a21861f20851f20861f6a21871f20861f20871f6a21881f20871f20881f6a21891f20881f20891f6a218a1f20" - "891f208a1f6a218b1f208a1f208b1f6a218c1f208b1f208c1f6a218d1f208c1f208d1f6a218e1f208d1f208e1f6a21" - "8f1f208e1f208f1f6a21901f208f1f20901f6a21911f20901f20911f6a21921f20911f20921f6a21931f20921f2093" - "1f6a21941f20931f20941f6a21951f20941f20951f6a21961f20951f20961f6a21971f20961f20971f6a21981f2097" - "1f20981f6a21991f20981f20991f6a219a1f20991f209a1f6a219b1f209a1f209b1f6a219c1f209b1f209c1f6a219d" - "1f209c1f209d1f6a219e1f209d1f209e1f6a219f1f209e1f209f1f6a21a01f209f1f20a01f6a21a11f20a01f20a11f" - "6a21a21f20a11f20a21f6a21a31f20a21f20a31f6a21a41f20a31f20a41f6a21a51f20a41f20a51f6a21a61f20a51f" - "20a61f6a21a71f20a61f20a71f6a21a81f20a71f20a81f6a21a91f20a81f20a91f6a21aa1f20a91f20aa1f6a21ab1f" - "20aa1f20ab1f6a21ac1f20ab1f20ac1f6a21ad1f20ac1f20ad1f6a21ae1f20ad1f20ae1f6a21af1f20ae1f20af1f6a" - "21b01f20af1f20b01f6a21b11f20b01f20b11f6a21b21f20b11f20b21f6a21b31f20b21f20b31f6a21b41f20b31f20" - "b41f6a21b51f20b41f20b51f6a21b61f20b51f20b61f6a21b71f20b61f20b71f6a21b81f20b71f20b81f6a21b91f20" - "b81f20b91f6a21ba1f20b91f20ba1f6a21bb1f20ba1f20bb1f6a21bc1f20bb1f20bc1f6a21bd1f20bc1f20bd1f6a21" - "be1f20bd1f20be1f6a21bf1f20be1f20bf1f6a21c01f20bf1f20c01f6a21c11f20c01f20c11f6a21c21f20c11f20c2" - "1f6a21c31f20c21f20c31f6a21c41f20c31f20c41f6a21c51f20c41f20c51f6a21c61f20c51f20c61f6a21c71f20c6" - "1f20c71f6a21c81f20c71f20c81f6a21c91f20c81f20c91f6a21ca1f20c91f20ca1f6a21cb1f20ca1f20cb1f6a21cc" - "1f20cb1f20cc1f6a21cd1f20cc1f20cd1f6a21ce1f20cd1f20ce1f6a21cf1f20ce1f20cf1f6a21d01f20cf1f20d01f" - "6a21d11f20d01f20d11f6a21d21f20d11f20d21f6a21d31f20d21f20d31f6a21d41f20d31f20d41f6a21d51f20d41f" - "20d51f6a21d61f20d51f20d61f6a21d71f20d61f20d71f6a21d81f20d71f20d81f6a21d91f20d81f20d91f6a21da1f" - "20d91f20da1f6a21db1f20da1f20db1f6a21dc1f20db1f20dc1f6a21dd1f20dc1f20dd1f6a21de1f20dd1f20de1f6a" - "21df1f20de1f20df1f6a21e01f20df1f20e01f6a21e11f20e01f20e11f6a21e21f20e11f20e21f6a21e31f20e21f20" - "e31f6a21e41f20e31f20e41f6a21e51f20e41f20e51f6a21e61f20e51f20e61f6a21e71f20e61f20e71f6a21e81f20" - "e71f20e81f6a21e91f20e81f20e91f6a21ea1f20e91f20ea1f6a21eb1f20ea1f20eb1f6a21ec1f20eb1f20ec1f6a21" - "ed1f20ec1f20ed1f6a21ee1f20ed1f20ee1f6a21ef1f20ee1f20ef1f6a21f01f20ef1f20f01f6a21f11f20f01f20f1" - "1f6a21f21f20f11f20f21f6a21f31f20f21f20f31f6a21f41f20f31f20f41f6a21f51f20f41f20f51f6a21f61f20f5" - "1f20f61f6a21f71f20f61f20f71f6a21f81f20f71f20f81f6a21f91f20f81f20f91f6a21fa1f20f91f20fa1f6a21fb" - "1f20fa1f20fb1f6a21fc1f20fb1f20fc1f6a21fd1f20fc1f20fd1f6a21fe1f20fd1f20fe1f6a21ff1f20fe1f20ff1f" - "6a21802020ff1f2080206a2181202080202081206a2182202081202082206a2183202082202083206a218420208320" - "2084206a2185202084202085206a2186202085202086206a2187202086202087206a2188202087202088206a218920" - "2088202089206a218a20208920208a206a218b20208a20208b206a218c20208b20208c206a218d20208c20208d206a" - "218e20208d20208e206a218f20208e20208f206a219020208f202090206a2191202090202091206a21922020912020" - "92206a2193202092202093206a2194202093202094206a2195202094202095206a2196202095202096206a21972020" - "96202097206a2198202097202098206a2199202098202099206a219a20209920209a206a219b20209a20209b206a21" - "9c20209b20209c206a219d20209c20209d206a219e20209d20209e206a219f20209e20209f206a21a020209f2020a0" - "206a21a12020a02020a1206a21a22020a12020a2206a21a32020a22020a3206a21a42020a32020a4206a21a52020a4" - "2020a5206a21a62020a52020a6206a21a72020a62020a7206a21a82020a72020a8206a21a92020a82020a9206a21aa" - "2020a92020aa206a21ab2020aa2020ab206a21ac2020ab2020ac206a21ad2020ac2020ad206a21ae2020ad2020ae20" - "6a21af2020ae2020af206a21b02020af2020b0206a21b12020b02020b1206a21b22020b12020b2206a21b32020b220" - "20b3206a21b42020b32020b4206a21b52020b42020b5206a21b62020b52020b6206a21b72020b62020b7206a21b820" - "20b72020b8206a21b92020b82020b9206a21ba2020b92020ba206a21bb2020ba2020bb206a21bc2020bb2020bc206a" - "21bd2020bc2020bd206a21be2020bd2020be206a21bf2020be2020bf206a21c02020bf2020c0206a21c12020c02020" - "c1206a21c22020c12020c2206a21c32020c22020c3206a21c42020c32020c4206a21c52020c42020c5206a21c62020" - "c52020c6206a21c72020c62020c7206a21c82020c72020c8206a21c92020c82020c9206a21ca2020c92020ca206a21" - "cb2020ca2020cb206a21cc2020cb2020cc206a21cd2020cc2020cd206a21ce2020cd2020ce206a21cf2020ce2020cf" - "206a21d02020cf2020d0206a21d12020d02020d1206a21d22020d12020d2206a21d32020d22020d3206a21d42020d3" - "2020d4206a21d52020d42020d5206a21d62020d52020d6206a21d72020d62020d7206a21d82020d72020d8206a21d9" - "2020d82020d9206a21da2020d92020da206a21db2020da2020db206a21dc2020db2020dc206a21dd2020dc2020dd20" - "6a21de2020dd2020de206a21df2020de2020df206a21e02020df2020e0206a21e12020e02020e1206a21e22020e120" - "20e2206a21e32020e22020e3206a21e42020e32020e4206a21e52020e42020e5206a21e62020e52020e6206a21e720" - "20e62020e7206a21e82020e72020e8206a21e92020e82020e9206a21ea2020e92020ea206a21eb2020ea2020eb206a" - "21ec2020eb2020ec206a21ed2020ec2020ed206a21ee2020ed2020ee206a21ef2020ee2020ef206a21f02020ef2020" - "f0206a21f12020f02020f1206a21f22020f12020f2206a21f32020f22020f3206a21f42020f32020f4206a21f52020" - "f42020f5206a21f62020f52020f6206a21f72020f62020f7206a21f82020f72020f8206a21f92020f82020f9206a21" - "fa2020f92020fa206a21fb2020fa2020fb206a21fc2020fb2020fc206a21fd2020fc2020fd206a21fe2020fd2020fe" - "206a21ff2020fe2020ff206a21802120ff202080216a2181212080212081216a2182212081212082216a2183212082" - "212083216a2184212083212084216a2185212084212085216a2186212085212086216a2187212086212087216a2188" - "212087212088216a2189212088212089216a218a21208921208a216a218b21208a21208b216a218c21208b21208c21" - "6a218d21208c21208d216a218e21208d21208e216a218f21208e21208f216a219021208f212090216a219121209021" - "2091216a2192212091212092216a2193212092212093216a2194212093212094216a2195212094212095216a219621" - "2095212096216a2197212096212097216a2198212097212098216a2199212098212099216a219a21209921209a216a" - "219b21209a21209b216a219c21209b21209c216a219d21209c21209d216a219e21209d21209e216a219f21209e2120" - "9f216a21a021209f2120a0216a21a12120a02120a1216a21a22120a12120a2216a21a32120a22120a3216a21a42120" - "a32120a4216a21a52120a42120a5216a21a62120a52120a6216a21a72120a62120a7216a21a82120a72120a8216a21" - "a92120a82120a9216a21aa2120a92120aa216a21ab2120aa2120ab216a21ac2120ab2120ac216a21ad2120ac2120ad" - "216a21ae2120ad2120ae216a21af2120ae2120af216a21b02120af2120b0216a21b12120b02120b1216a21b22120b1" - "2120b2216a21b32120b22120b3216a21b42120b32120b4216a21b52120b42120b5216a21b62120b52120b6216a21b7" - "2120b62120b7216a21b82120b72120b8216a21b92120b82120b9216a21ba2120b92120ba216a21bb2120ba2120bb21" - "6a21bc2120bb2120bc216a21bd2120bc2120bd216a21be2120bd2120be216a21bf2120be2120bf216a21c02120bf21" - "20c0216a21c12120c02120c1216a21c22120c12120c2216a21c32120c22120c3216a21c42120c32120c4216a21c521" - "20c42120c5216a21c62120c52120c6216a21c72120c62120c7216a21c82120c72120c8216a21c92120c82120c9216a" - "21ca2120c92120ca216a21cb2120ca2120cb216a21cc2120cb2120cc216a21cd2120cc2120cd216a21ce2120cd2120" - "ce216a21cf2120ce2120cf216a21d02120cf2120d0216a21d12120d02120d1216a21d22120d12120d2216a21d32120" - "d22120d3216a21d42120d32120d4216a21d52120d42120d5216a21d62120d52120d6216a21d72120d62120d7216a21" - "d82120d72120d8216a21d92120d82120d9216a21da2120d92120da216a21db2120da2120db216a21dc2120db2120dc" - "216a21dd2120dc2120dd216a21de2120dd2120de216a21df2120de2120df216a21e02120df2120e0216a21e12120e0" - "2120e1216a21e22120e12120e2216a21e32120e22120e3216a21e42120e32120e4216a21e52120e42120e5216a21e6" - "2120e52120e6216a21e72120e62120e7216a21e82120e72120e8216a21e92120e82120e9216a21ea2120e92120ea21" - "6a21eb2120ea2120eb216a21ec2120eb2120ec216a21ed2120ec2120ed216a21ee2120ed2120ee216a21ef2120ee21" - "20ef216a21f02120ef2120f0216a21f12120f02120f1216a21f22120f12120f2216a21f32120f22120f3216a21f421" - "20f32120f4216a21f52120f42120f5216a21f62120f52120f6216a21f72120f62120f7216a21f82120f72120f8216a" - "21f92120f82120f9216a21fa2120f92120fa216a21fb2120fa2120fb216a21fc2120fb2120fc216a21fd2120fc2120" - "fd216a21fe2120fd2120fe216a21ff2120fe2120ff216a21802220ff212080226a2181222080222081226a21822220" - "81222082226a2183222082222083226a2184222083222084226a2185222084222085226a2186222085222086226a21" - "87222086222087226a2188222087222088226a2189222088222089226a218a22208922208a226a218b22208a22208b" - "226a218c22208b22208c226a218d22208c22208d226a218e22208d22208e226a218f22208e22208f226a219022208f" - "222090226a2191222090222091226a2192222091222092226a2193222092222093226a2194222093222094226a2195" - "222094222095226a2196222095222096226a2197222096222097226a2198222097222098226a219922209822209922" - "6a219a22209922209a226a219b22209a22209b226a219c22209b22209c226a219d22209c22209d226a219e22209d22" - "209e226a219f22209e22209f226a21a022209f2220a0226a21a12220a02220a1226a21a22220a12220a2226a21a322" - "20a22220a3226a21a42220a32220a4226a21a52220a42220a5226a21a62220a52220a6226a21a72220a62220a7226a" - "21a82220a72220a8226a21a92220a82220a9226a21aa2220a92220aa226a21ab2220aa2220ab226a21ac2220ab2220" - "ac226a21ad2220ac2220ad226a21ae2220ad2220ae226a21af2220ae2220af226a21b02220af2220b0226a21b12220" - "b02220b1226a21b22220b12220b2226a21b32220b22220b3226a21b42220b32220b4226a21b52220b42220b5226a21" - "b62220b52220b6226a21b72220b62220b7226a21b82220b72220b8226a21b92220b82220b9226a21ba2220b92220ba" - "226a21bb2220ba2220bb226a21bc2220bb2220bc226a21bd2220bc2220bd226a21be2220bd2220be226a21bf2220be" - "2220bf226a21c02220bf2220c0226a21c12220c02220c1226a21c22220c12220c2226a21c32220c22220c3226a21c4" - "2220c32220c4226a21c52220c42220c5226a21c62220c52220c6226a21c72220c62220c7226a21c82220c72220c822" - "6a21c92220c82220c9226a21ca2220c92220ca226a21cb2220ca2220cb226a21cc2220cb2220cc226a21cd2220cc22" - "20cd226a21ce2220cd2220ce226a21cf2220ce2220cf226a21d02220cf2220d0226a21d12220d02220d1226a21d222" - "20d12220d2226a21d32220d22220d3226a21d42220d32220d4226a21d52220d42220d5226a21d62220d52220d6226a" - "21d72220d62220d7226a21d82220d72220d8226a21d92220d82220d9226a21da2220d92220da226a21db2220da2220" - "db226a21dc2220db2220dc226a21dd2220dc2220dd226a21de2220dd2220de226a21df2220de2220df226a21e02220" - "df2220e0226a21e12220e02220e1226a21e22220e12220e2226a21e32220e22220e3226a21e42220e32220e4226a21" - "e52220e42220e5226a21e62220e52220e6226a21e72220e62220e7226a21e82220e72220e8226a21e92220e82220e9" - "226a21ea2220e92220ea226a21eb2220ea2220eb226a21ec2220eb2220ec226a21ed2220ec2220ed226a21ee2220ed" - "2220ee226a21ef2220ee2220ef226a21f02220ef2220f0226a21f12220f02220f1226a21f22220f12220f2226a21f3" - "2220f22220f3226a21f42220f32220f4226a21f52220f42220f5226a21f62220f52220f6226a21f72220f62220f722" - "6a21f82220f72220f8226a21f92220f82220f9226a21fa2220f92220fa226a21fb2220fa2220fb226a21fc2220fb22" - "20fc226a21fd2220fc2220fd226a21fe2220fd2220fe226a21ff2220fe2220ff226a21802320ff222080236a218123" - "2080232081236a2182232081232082236a2183232082232083236a2184232083232084236a2185232084232085236a" - "2186232085232086236a2187232086232087236a2188232087232088236a2189232088232089236a218a2320892320" - "8a236a218b23208a23208b236a218c23208b23208c236a218d23208c23208d236a218e23208d23208e236a218f2320" - "8e23208f236a219023208f232090236a2191232090232091236a2192232091232092236a2193232092232093236a21" - "94232093232094236a2195232094232095236a2196232095232096236a2197232096232097236a2198232097232098" - "236a2199232098232099236a219a23209923209a236a219b23209a23209b236a219c23209b23209c236a219d23209c" - "23209d236a219e23209d23209e236a219f23209e23209f236a21a023209f2320a0236a21a12320a02320a1236a21a2" - "2320a12320a2236a21a32320a22320a3236a21a42320a32320a4236a21a52320a42320a5236a21a62320a52320a623" - "6a21a72320a62320a7236a21a82320a72320a8236a21a92320a82320a9236a21aa2320a92320aa236a21ab2320aa23" - "20ab236a21ac2320ab2320ac236a21ad2320ac2320ad236a21ae2320ad2320ae236a21af2320ae2320af236a21b023" - "20af2320b0236a21b12320b02320b1236a21b22320b12320b2236a21b32320b22320b3236a21b42320b32320b4236a" - "21b52320b42320b5236a21b62320b52320b6236a21b72320b62320b7236a21b82320b72320b8236a21b92320b82320" - "b9236a21ba2320b92320ba236a21bb2320ba2320bb236a21bc2320bb2320bc236a21bd2320bc2320bd236a21be2320" - "bd2320be236a21bf2320be2320bf236a21c02320bf2320c0236a21c12320c02320c1236a21c22320c12320c2236a21" - "c32320c22320c3236a21c42320c32320c4236a21c52320c42320c5236a21c62320c52320c6236a21c72320c62320c7" - "236a21c82320c72320c8236a21c92320c82320c9236a21ca2320c92320ca236a21cb2320ca2320cb236a21cc2320cb" - "2320cc236a21cd2320cc2320cd236a21ce2320cd2320ce236a21cf2320ce2320cf236a21d02320cf2320d0236a21d1" - "2320d02320d1236a21d22320d12320d2236a21d32320d22320d3236a21d42320d32320d4236a21d52320d42320d523" - "6a21d62320d52320d6236a21d72320d62320d7236a21d82320d72320d8236a21d92320d82320d9236a21da2320d923" - "20da236a21db2320da2320db236a21dc2320db2320dc236a21dd2320dc2320dd236a21de2320dd2320de236a21df23" - "20de2320df236a21e02320df2320e0236a21e12320e02320e1236a21e22320e12320e2236a21e32320e22320e3236a" - "21e42320e32320e4236a21e52320e42320e5236a21e62320e52320e6236a21e72320e62320e7236a21e82320e72320" - "e8236a21e92320e82320e9236a21ea2320e92320ea236a21eb2320ea2320eb236a21ec2320eb2320ec236a21ed2320" - "ec2320ed236a21ee2320ed2320ee236a21ef2320ee2320ef236a21f02320ef2320f0236a21f12320f02320f1236a21" - "f22320f12320f2236a21f32320f22320f3236a21f42320f32320f4236a21f52320f42320f5236a21f62320f52320f6" - "236a21f72320f62320f7236a21f82320f72320f8236a21f92320f82320f9236a21fa2320f92320fa236a21fb2320fa" - "2320fb236a21fc2320fb2320fc236a21fd2320fc2320fd236a21fe2320fd2320fe236a21ff2320fe2320ff236a2180" - "2420ff232080246a2181242080242081246a2182242081242082246a2183242082242083246a218424208324208424" - "6a2185242084242085246a2186242085242086246a2187242086242087246a2188242087242088246a218924208824" - "2089246a218a24208924208a246a218b24208a24208b246a218c24208b24208c246a218d24208c24208d246a218e24" - "208d24208e246a218f24208e24208f246a219024208f242090246a2191242090242091246a2192242091242092246a" - "2193242092242093246a2194242093242094246a2195242094242095246a2196242095242096246a21972420962420" - "97246a2198242097242098246a2199242098242099246a219a24209924209a246a219b24209a24209b246a219c2420" - "9b24209c246a219d24209c24209d246a219e24209d24209e246a219f24209e24209f246a21a024209f2420a0246a21" - "a12420a02420a1246a21a22420a12420a2246a21a32420a22420a3246a21a42420a32420a4246a21a52420a42420a5" - "246a21a62420a52420a6246a21a72420a62420a7246a21a82420a72420a8246a21a92420a82420a9246a21aa2420a9" - "2420aa246a21ab2420aa2420ab246a21ac2420ab2420ac246a21ad2420ac2420ad246a21ae2420ad2420ae246a21af" - "2420ae2420af246a21b02420af2420b0246a21b12420b02420b1246a21b22420b12420b2246a21b32420b22420b324" - "6a21b42420b32420b4246a21b52420b42420b5246a21b62420b52420b6246a21b72420b62420b7246a21b82420b724" - "20b8246a21b92420b82420b9246a21ba2420b92420ba246a21bb2420ba2420bb246a21bc2420bb2420bc246a21bd24" - "20bc2420bd246a21be2420bd2420be246a21bf2420be2420bf246a21c02420bf2420c0246a21c12420c02420c1246a" - "21c22420c12420c2246a21c32420c22420c3246a21c42420c32420c4246a21c52420c42420c5246a21c62420c52420" - "c6246a21c72420c62420c7246a21c82420c72420c8246a21c92420c82420c9246a21ca2420c92420ca246a21cb2420" - "ca2420cb246a21cc2420cb2420cc246a21cd2420cc2420cd246a21ce2420cd2420ce246a21cf2420ce2420cf246a21" - "d02420cf2420d0246a21d12420d02420d1246a21d22420d12420d2246a21d32420d22420d3246a21d42420d32420d4" - "246a21d52420d42420d5246a21d62420d52420d6246a21d72420d62420d7246a21d82420d72420d8246a21d92420d8" - "2420d9246a21da2420d92420da246a21db2420da2420db246a21dc2420db2420dc246a21dd2420dc2420dd246a21de" - "2420dd2420de246a21df2420de2420df246a21e02420df2420e0246a21e12420e02420e1246a21e22420e12420e224" - "6a21e32420e22420e3246a21e42420e32420e4246a21e52420e42420e5246a21e62420e52420e6246a21e72420e624" - "20e7246a21e82420e72420e8246a21e92420e82420e9246a21ea2420e92420ea246a21eb2420ea2420eb246a21ec24" - "20eb2420ec246a21ed2420ec2420ed246a21ee2420ed2420ee246a21ef2420ee2420ef246a21f02420ef2420f0246a" - "21f12420f02420f1246a21f22420f12420f2246a21f32420f22420f3246a21f42420f32420f4246a21f52420f42420" - "f5246a21f62420f52420f6246a21f72420f62420f7246a21f82420f72420f8246a21f92420f82420f9246a21fa2420" - "f92420fa246a21fb2420fa2420fb246a21fc2420fb2420fc246a21fd2420fc2420fd246a21fe2420fd2420fe246a21" - "ff2420fe2420ff246a21802520ff242080256a2181252080252081256a2182252081252082256a2183252082252083" - "256a2184252083252084256a2185252084252085256a2186252085252086256a2187252086252087256a2188252087" - "252088256a2189252088252089256a218a25208925208a256a218b25208a25208b256a218c25208b25208c256a218d" - "25208c25208d256a218e25208d25208e256a218f25208e25208f256a219025208f252090256a219125209025209125" - "6a2192252091252092256a2193252092252093256a2194252093252094256a2195252094252095256a219625209525" - "2096256a2197252096252097256a2198252097252098256a2199252098252099256a219a25209925209a256a219b25" - "209a25209b256a219c25209b25209c256a219d25209c25209d256a219e25209d25209e256a219f25209e25209f256a" - "21a025209f2520a0256a21a12520a02520a1256a21a22520a12520a2256a21a32520a22520a3256a21a42520a32520" - "a4256a21a52520a42520a5256a21a62520a52520a6256a21a72520a62520a7256a21a82520a72520a8256a21a92520" - "a82520a9256a21aa2520a92520aa256a21ab2520aa2520ab256a21ac2520ab2520ac256a21ad2520ac2520ad256a21" - "ae2520ad2520ae256a21af2520ae2520af256a21b02520af2520b0256a21b12520b02520b1256a21b22520b12520b2" - "256a21b32520b22520b3256a21b42520b32520b4256a21b52520b42520b5256a21b62520b52520b6256a21b72520b6" - "2520b7256a21b82520b72520b8256a21b92520b82520b9256a21ba2520b92520ba256a21bb2520ba2520bb256a21bc" - "2520bb2520bc256a21bd2520bc2520bd256a21be2520bd2520be256a21bf2520be2520bf256a21c02520bf2520c025" - "6a21c12520c02520c1256a21c22520c12520c2256a21c32520c22520c3256a21c42520c32520c4256a21c52520c425" - "20c5256a21c62520c52520c6256a21c72520c62520c7256a21c82520c72520c8256a21c92520c82520c9256a21ca25" - "20c92520ca256a21cb2520ca2520cb256a21cc2520cb2520cc256a21cd2520cc2520cd256a21ce2520cd2520ce256a" - "21cf2520ce2520cf256a21d02520cf2520d0256a21d12520d02520d1256a21d22520d12520d2256a21d32520d22520" - "d3256a21d42520d32520d4256a21d52520d42520d5256a21d62520d52520d6256a21d72520d62520d7256a21d82520" - "d72520d8256a21d92520d82520d9256a21da2520d92520da256a21db2520da2520db256a21dc2520db2520dc256a21" - "dd2520dc2520dd256a21de2520dd2520de256a21df2520de2520df256a21e02520df2520e0256a21e12520e02520e1" - "256a21e22520e12520e2256a21e32520e22520e3256a21e42520e32520e4256a21e52520e42520e5256a21e62520e5" - "2520e6256a21e72520e62520e7256a21e82520e72520e8256a21e92520e82520e9256a21ea2520e92520ea256a21eb" - "2520ea2520eb256a21ec2520eb2520ec256a21ed2520ec2520ed256a21ee2520ed2520ee256a21ef2520ee2520ef25" - "6a21f02520ef2520f0256a21f12520f02520f1256a21f22520f12520f2256a21f32520f22520f3256a21f42520f325" - "20f4256a21f52520f42520f5256a21f62520f52520f6256a21f72520f62520f7256a21f82520f72520f8256a21f925" - "20f82520f9256a21fa2520f92520fa256a21fb2520fa2520fb256a21fc2520fb2520fc256a21fd2520fc2520fd256a" - "21fe2520fd2520fe256a21ff2520fe2520ff256a21802620ff252080266a2181262080262081266a21822620812620" - "82266a2183262082262083266a2184262083262084266a2185262084262085266a2186262085262086266a21872620" - "86262087266a2188262087262088266a2189262088262089266a218a26208926208a266a218b26208a26208b266a21" - "8c26208b26208c266a218d26208c26208d266a218e26208d26208e266a218f26208e26208f266a219026208f262090" - "266a2191262090262091266a2192262091262092266a2193262092262093266a2194262093262094266a2195262094" - "262095266a2196262095262096266a2197262096262097266a2198262097262098266a2199262098262099266a219a" - "26209926209a266a219b26209a26209b266a219c26209b26209c266a219d26209c26209d266a219e26209d26209e26" - "6a219f26209e26209f266a21a026209f2620a0266a21a12620a02620a1266a21a22620a12620a2266a21a32620a226" - "20a3266a21a42620a32620a4266a21a52620a42620a5266a21a62620a52620a6266a21a72620a62620a7266a21a826" - "20a72620a8266a21a92620a82620a9266a21aa2620a92620aa266a21ab2620aa2620ab266a21ac2620ab2620ac266a" - "21ad2620ac2620ad266a21ae2620ad2620ae266a21af2620ae2620af266a21b02620af2620b0266a21b12620b02620" - "b1266a21b22620b12620b2266a21b32620b22620b3266a21b42620b32620b4266a21b52620b42620b5266a21b62620" - "b52620b6266a21b72620b62620b7266a21b82620b72620b8266a21b92620b82620b9266a21ba2620b92620ba266a21" - "bb2620ba2620bb266a21bc2620bb2620bc266a21bd2620bc2620bd266a21be2620bd2620be266a21bf2620be2620bf" - "266a21c02620bf2620c0266a21c12620c02620c1266a21c22620c12620c2266a21c32620c22620c3266a21c42620c3" - "2620c4266a21c52620c42620c5266a21c62620c52620c6266a21c72620c62620c7266a21c82620c72620c8266a21c9" - "2620c82620c9266a21ca2620c92620ca266a21cb2620ca2620cb266a21cc2620cb2620cc266a21cd2620cc2620cd26" - "6a21ce2620cd2620ce266a21cf2620ce2620cf266a21d02620cf2620d0266a21d12620d02620d1266a21d22620d126" - "20d2266a21d32620d22620d3266a21d42620d32620d4266a21d52620d42620d5266a21d62620d52620d6266a21d726" - "20d62620d7266a21d82620d72620d8266a21d92620d82620d9266a21da2620d92620da266a21db2620da2620db266a" - "21dc2620db2620dc266a21dd2620dc2620dd266a21de2620dd2620de266a21df2620de2620df266a21e02620df2620" - "e0266a21e12620e02620e1266a21e22620e12620e2266a21e32620e22620e3266a21e42620e32620e4266a21e52620" - "e42620e5266a21e62620e52620e6266a21e72620e62620e7266a21e82620e72620e8266a21e92620e82620e9266a21" - "ea2620e92620ea266a21eb2620ea2620eb266a21ec2620eb2620ec266a21ed2620ec2620ed266a21ee2620ed2620ee" - "266a21ef2620ee2620ef266a21f02620ef2620f0266a21f12620f02620f1266a21f22620f12620f2266a21f32620f2" - "2620f3266a21f42620f32620f4266a21f52620f42620f5266a21f62620f52620f6266a21f72620f62620f7266a21f8" - "2620f72620f8266a21f92620f82620f9266a21fa2620f92620fa266a21fb2620fa2620fb266a21fc2620fb2620fc26" - "6a21fd2620fc2620fd266a21fe2620fd2620fe266a21ff2620fe2620ff266a21802720ff262080276a218127208027" - "2081276a2182272081272082276a2183272082272083276a2184272083272084276a2185272084272085276a218627" - "2085272086276a2187272086272087276a2188272087272088276a2189272088272089276a218a27208927208a276a" - "218b27208a27208b276a218c27208b27208c276a218d27208c27208d276a218e27208d27208e276a218f27208e2720" - "8f276a219027208f272090276a2191272090272091276a2192272091272092276a2193272092272093276a21942720" - "93272094276a2195272094272095276a2196272095272096276a2197272096272097276a2198272097272098276a21" - "99272098272099276a219a27209927209a276a219b27209a27209b276a219c27209b27209c276a219d27209c27209d" - "276a219e27209d27209e276a219f27209e27209f276a21a027209f2720a0276a21a12720a02720a1276a21a22720a1" - "2720a2276a21a32720a22720a3276a21a42720a32720a4276a21a52720a42720a5276a21a62720a52720a6276a21a7" - "2720a62720a7276a21a82720a72720a8276a21a92720a82720a9276a21aa2720a92720aa276a21ab2720aa2720ab27" - "6a21ac2720ab2720ac276a21ad2720ac2720ad276a21ae2720ad2720ae276a21af2720ae2720af276a21b02720af27" - "20b0276a21b12720b02720b1276a21b22720b12720b2276a21b32720b22720b3276a21b42720b32720b4276a21b527" - "20b42720b5276a21b62720b52720b6276a21b72720b62720b7276a21b82720b72720b8276a21b92720b82720b9276a" - "21ba2720b92720ba276a21bb2720ba2720bb276a21bc2720bb2720bc276a21bd2720bc2720bd276a21be2720bd2720" - "be276a21bf2720be2720bf276a21c02720bf2720c0276a21c12720c02720c1276a21c22720c12720c2276a21c32720" - "c22720c3276a21c42720c32720c4276a21c52720c42720c5276a21c62720c52720c6276a21c72720c62720c7276a21" - "c82720c72720c8276a21c92720c82720c9276a21ca2720c92720ca276a21cb2720ca2720cb276a21cc2720cb2720cc" - "276a21cd2720cc2720cd276a21ce2720cd2720ce276a21cf2720ce2720cf276a21d02720cf2720d0276a21d12720d0" - "2720d1276a21d22720d12720d2276a21d32720d22720d3276a21d42720d32720d4276a21d52720d42720d5276a21d6" - "2720d52720d6276a21d72720d62720d7276a21d82720d72720d8276a21d92720d82720d9276a21da2720d92720da27" - "6a21db2720da2720db276a21dc2720db2720dc276a21dd2720dc2720dd276a21de2720dd2720de276a21df2720de27" - "20df276a21e02720df2720e0276a21e12720e02720e1276a21e22720e12720e2276a21e32720e22720e3276a21e427" - "20e32720e4276a21e52720e42720e5276a21e62720e52720e6276a21e72720e62720e7276a21e82720e72720e8276a" - "21e92720e82720e9276a21ea2720e92720ea276a21eb2720ea2720eb276a21ec2720eb2720ec276a21ed2720ec2720" - "ed276a21ee2720ed2720ee276a21ef2720ee2720ef276a21f02720ef2720f0276a21f12720f02720f1276a21f22720" - "f12720f2276a21f32720f22720f3276a21f42720f32720f4276a21f52720f42720f5276a21f62720f52720f6276a21" - "f72720f62720f7276a21f82720f72720f8276a21f92720f82720f9276a21fa2720f92720fa276a21fb2720fa2720fb" - "276a21fc2720fb2720fc276a21fd2720fc2720fd276a21fe2720fd2720fe276a21ff2720fe2720ff276a21802820ff" - "272080286a2181282080282081286a2182282081282082286a2183282082282083286a2184282083282084286a2185" - "282084282085286a2186282085282086286a2187282086282087286a2188282087282088286a218928208828208928" - "6a218a28208928208a286a218b28208a28208b286a218c28208b28208c286a218d28208c28208d286a218e28208d28" - "208e286a218f28208e28208f286a219028208f282090286a2191282090282091286a2192282091282092286a219328" - "2092282093286a2194282093282094286a2195282094282095286a2196282095282096286a2197282096282097286a" - "2198282097282098286a2199282098282099286a219a28209928209a286a219b28209a28209b286a219c28209b2820" - "9c286a219d28209c28209d286a219e28209d28209e286a219f28209e28209f286a21a028209f2820a0286a21a12820" - "a02820a1286a21a22820a12820a2286a21a32820a22820a3286a21a42820a32820a4286a21a52820a42820a5286a21" - "a62820a52820a6286a21a72820a62820a7286a21a82820a72820a8286a21a92820a82820a9286a21aa2820a92820aa" - "286a21ab2820aa2820ab286a21ac2820ab2820ac286a21ad2820ac2820ad286a21ae2820ad2820ae286a21af2820ae" - "2820af286a21b02820af2820b0286a21b12820b02820b1286a21b22820b12820b2286a21b32820b22820b3286a21b4" - "2820b32820b4286a21b52820b42820b5286a21b62820b52820b6286a21b72820b62820b7286a21b82820b72820b828" - "6a21b92820b82820b9286a21ba2820b92820ba286a21bb2820ba2820bb286a21bc2820bb2820bc286a21bd2820bc28" - "20bd286a21be2820bd2820be286a21bf2820be2820bf286a21c02820bf2820c0286a21c12820c02820c1286a21c228" - "20c12820c2286a21c32820c22820c3286a21c42820c32820c4286a21c52820c42820c5286a21c62820c52820c6286a" - "21c72820c62820c7286a21c82820c72820c8286a21c92820c82820c9286a21ca2820c92820ca286a21cb2820ca2820" - "cb286a21cc2820cb2820cc286a21cd2820cc2820cd286a21ce2820cd2820ce286a21cf2820ce2820cf286a21d02820" - "cf2820d0286a21d12820d02820d1286a21d22820d12820d2286a21d32820d22820d3286a21d42820d32820d4286a21" - "d52820d42820d5286a21d62820d52820d6286a21d72820d62820d7286a21d82820d72820d8286a21d92820d82820d9" - "286a21da2820d92820da286a21db2820da2820db286a21dc2820db2820dc286a21dd2820dc2820dd286a21de2820dd" - "2820de286a21df2820de2820df286a21e02820df2820e0286a21e12820e02820e1286a21e22820e12820e2286a21e3" - "2820e22820e3286a21e42820e32820e4286a21e52820e42820e5286a21e62820e52820e6286a21e72820e62820e728" - "6a21e82820e72820e8286a21e92820e82820e9286a21ea2820e92820ea286a21eb2820ea2820eb286a21ec2820eb28" - "20ec286a21ed2820ec2820ed286a21ee2820ed2820ee286a21ef2820ee2820ef286a21f02820ef2820f0286a21f128" - "20f02820f1286a21f22820f12820f2286a21f32820f22820f3286a21f42820f32820f4286a21f52820f42820f5286a" - "21f62820f52820f6286a21f72820f62820f7286a21f82820f72820f8286a21f92820f82820f9286a21fa2820f92820" - "fa286a21fb2820fa2820fb286a21fc2820fb2820fc286a21fd2820fc2820fd286a21fe2820fd2820fe286a21ff2820" - "fe2820ff286a21802920ff282080296a2181292080292081296a2182292081292082296a2183292082292083296a21" - "84292083292084296a2185292084292085296a2186292085292086296a2187292086292087296a2188292087292088" - "296a2189292088292089296a218a29208929208a296a218b29208a29208b296a218c29208b29208c296a218d29208c" - "29208d296a218e29208d29208e296a218f29208e29208f296a219029208f292090296a2191292090292091296a2192" - "292091292092296a2193292092292093296a2194292093292094296a2195292094292095296a219629209529209629" - "6a2197292096292097296a2198292097292098296a2199292098292099296a219a29209929209a296a219b29209a29" - "209b296a219c29209b29209c296a219d29209c29209d296a219e29209d29209e296a219f29209e29209f296a21a029" - "209f2920a0296a21a12920a02920a1296a21a22920a12920a2296a21a32920a22920a3296a21a42920a32920a4296a" - "21a52920a42920a5296a21a62920a52920a6296a21a72920a62920a7296a21a82920a72920a8296a21a92920a82920" - "a9296a21aa2920a92920aa296a21ab2920aa2920ab296a21ac2920ab2920ac296a21ad2920ac2920ad296a21ae2920" - "ad2920ae296a21af2920ae2920af296a21b02920af2920b0296a21b12920b02920b1296a21b22920b12920b2296a21" - "b32920b22920b3296a21b42920b32920b4296a21b52920b42920b5296a21b62920b52920b6296a21b72920b62920b7" - "296a21b82920b72920b8296a21b92920b82920b9296a21ba2920b92920ba296a21bb2920ba2920bb296a21bc2920bb" - "2920bc296a21bd2920bc2920bd296a21be2920bd2920be296a21bf2920be2920bf296a21c02920bf2920c0296a21c1" - "2920c02920c1296a21c22920c12920c2296a21c32920c22920c3296a21c42920c32920c4296a21c52920c42920c529" - "6a21c62920c52920c6296a21c72920c62920c7296a21c82920c72920c8296a21c92920c82920c9296a21ca2920c929" - "20ca296a21cb2920ca2920cb296a21cc2920cb2920cc296a21cd2920cc2920cd296a21ce2920cd2920ce296a21cf29" - "20ce2920cf296a21d02920cf2920d0296a21d12920d02920d1296a21d22920d12920d2296a21d32920d22920d3296a" - "21d42920d32920d4296a21d52920d42920d5296a21d62920d52920d6296a21d72920d62920d7296a21d82920d72920" - "d8296a21d92920d82920d9296a21da2920d92920da296a21db2920da2920db296a21dc2920db2920dc296a21dd2920" - "dc2920dd296a21de2920dd2920de296a21df2920de2920df296a21e02920df2920e0296a21e12920e02920e1296a21" - "e22920e12920e2296a21e32920e22920e3296a21e42920e32920e4296a21e52920e42920e5296a21e62920e52920e6" - "296a21e72920e62920e7296a21e82920e72920e8296a21e92920e82920e9296a21ea2920e92920ea296a21eb2920ea" - "2920eb296a21ec2920eb2920ec296a21ed2920ec2920ed296a21ee2920ed2920ee296a21ef2920ee2920ef296a21f0" - "2920ef2920f0296a21f12920f02920f1296a21f22920f12920f2296a21f32920f22920f3296a21f42920f32920f429" - "6a21f52920f42920f5296a21f62920f52920f6296a21f72920f62920f7296a21f82920f72920f8296a21f92920f829" - "20f9296a21fa2920f92920fa296a21fb2920fa2920fb296a21fc2920fb2920fc296a21fd2920fc2920fd296a21fe29" - "20fd2920fe296a21ff2920fe2920ff296a21802a20ff2920802a6a21812a20802a20812a6a21822a20812a20822a6a" - "21832a20822a20832a6a21842a20832a20842a6a21852a20842a20852a6a21862a20852a20862a6a21872a20862a20" - "872a6a21882a20872a20882a6a21892a20882a20892a6a218a2a20892a208a2a6a218b2a208a2a208b2a6a218c2a20" - "8b2a208c2a6a218d2a208c2a208d2a6a218e2a208d2a208e2a6a218f2a208e2a208f2a6a21902a208f2a20902a6a21" - "912a20902a20912a6a21922a20912a20922a6a21932a20922a20932a6a21942a20932a20942a6a21952a20942a2095" - "2a6a21962a20952a20962a6a21972a20962a20972a6a21982a20972a20982a6a21992a20982a20992a6a219a2a2099" - "2a209a2a6a219b2a209a2a209b2a6a219c2a209b2a209c2a6a219d2a209c2a209d2a6a219e2a209d2a209e2a6a219f" - "2a209e2a209f2a6a21a02a209f2a20a02a6a21a12a20a02a20a12a6a21a22a20a12a20a22a6a21a32a20a22a20a32a" - "6a21a42a20a32a20a42a6a21a52a20a42a20a52a6a21a62a20a52a20a62a6a21a72a20a62a20a72a6a21a82a20a72a" - "20a82a6a21a92a20a82a20a92a6a21aa2a20a92a20aa2a6a21ab2a20aa2a20ab2a6a21ac2a20ab2a20ac2a6a21ad2a" - "20ac2a20ad2a6a21ae2a20ad2a20ae2a6a21af2a20ae2a20af2a6a21b02a20af2a20b02a6a21b12a20b02a20b12a6a" - "21b22a20b12a20b22a6a21b32a20b22a20b32a6a21b42a20b32a20b42a6a21b52a20b42a20b52a6a21b62a20b52a20" - "b62a6a21b72a20b62a20b72a6a21b82a20b72a20b82a6a21b92a20b82a20b92a6a21ba2a20b92a20ba2a6a21bb2a20" - "ba2a20bb2a6a21bc2a20bb2a20bc2a6a21bd2a20bc2a20bd2a6a21be2a20bd2a20be2a6a21bf2a20be2a20bf2a6a21" - "c02a20bf2a20c02a6a21c12a20c02a20c12a6a21c22a20c12a20c22a6a21c32a20c22a20c32a6a21c42a20c32a20c4" - "2a6a21c52a20c42a20c52a6a21c62a20c52a20c62a6a21c72a20c62a20c72a6a21c82a20c72a20c82a6a21c92a20c8" - "2a20c92a6a21ca2a20c92a20ca2a6a21cb2a20ca2a20cb2a6a21cc2a20cb2a20cc2a6a21cd2a20cc2a20cd2a6a21ce" - "2a20cd2a20ce2a6a21cf2a20ce2a20cf2a6a21d02a20cf2a20d02a6a21d12a20d02a20d12a6a21d22a20d12a20d22a" - "6a21d32a20d22a20d32a6a21d42a20d32a20d42a6a21d52a20d42a20d52a6a21d62a20d52a20d62a6a21d72a20d62a" - "20d72a6a21d82a20d72a20d82a6a21d92a20d82a20d92a6a21da2a20d92a20da2a6a21db2a20da2a20db2a6a21dc2a" - "20db2a20dc2a6a21dd2a20dc2a20dd2a6a21de2a20dd2a20de2a6a21df2a20de2a20df2a6a21e02a20df2a20e02a6a" - "21e12a20e02a20e12a6a21e22a20e12a20e22a6a21e32a20e22a20e32a6a21e42a20e32a20e42a6a21e52a20e42a20" - "e52a6a21e62a20e52a20e62a6a21e72a20e62a20e72a6a21e82a20e72a20e82a6a21e92a20e82a20e92a6a21ea2a20" - "e92a20ea2a6a21eb2a20ea2a20eb2a6a21ec2a20eb2a20ec2a6a21ed2a20ec2a20ed2a6a21ee2a20ed2a20ee2a6a21" - "ef2a20ee2a20ef2a6a21f02a20ef2a20f02a6a21f12a20f02a20f12a6a21f22a20f12a20f22a6a21f32a20f22a20f3" - "2a6a21f42a20f32a20f42a6a21f52a20f42a20f52a6a21f62a20f52a20f62a6a21f72a20f62a20f72a6a21f82a20f7" - "2a20f82a6a21f92a20f82a20f92a6a21fa2a20f92a20fa2a6a21fb2a20fa2a20fb2a6a21fc2a20fb2a20fc2a6a21fd" - "2a20fc2a20fd2a6a21fe2a20fd2a20fe2a6a21ff2a20fe2a20ff2a6a21802b20ff2a20802b6a21812b20802b20812b" - "6a21822b20812b20822b6a21832b20822b20832b6a21842b20832b20842b6a21852b20842b20852b6a21862b20852b" - "20862b6a21872b20862b20872b6a21882b20872b20882b6a21892b20882b20892b6a218a2b20892b208a2b6a218b2b" - "208a2b208b2b6a218c2b208b2b208c2b6a218d2b208c2b208d2b6a218e2b208d2b208e2b6a218f2b208e2b208f2b6a" - "21902b208f2b20902b6a21912b20902b20912b6a21922b20912b20922b6a21932b20922b20932b6a21942b20932b20" - "942b6a21952b20942b20952b6a21962b20952b20962b6a21972b20962b20972b6a21982b20972b20982b6a21992b20" - "982b20992b6a219a2b20992b209a2b6a219b2b209a2b209b2b6a219c2b209b2b209c2b6a219d2b209c2b209d2b6a21" - "9e2b209d2b209e2b6a219f2b209e2b209f2b6a21a02b209f2b20a02b6a21a12b20a02b20a12b6a21a22b20a12b20a2" - "2b6a21a32b20a22b20a32b6a21a42b20a32b20a42b6a21a52b20a42b20a52b6a21a62b20a52b20a62b6a21a72b20a6" - "2b20a72b6a21a82b20a72b20a82b6a21a92b20a82b20a92b6a21aa2b20a92b20aa2b6a21ab2b20aa2b20ab2b6a21ac" - "2b20ab2b20ac2b6a21ad2b20ac2b20ad2b6a21ae2b20ad2b20ae2b6a21af2b20ae2b20af2b6a21b02b20af2b20b02b" - "6a21b12b20b02b20b12b6a21b22b20b12b20b22b6a21b32b20b22b20b32b6a21b42b20b32b20b42b6a21b52b20b42b" - "20b52b6a21b62b20b52b20b62b6a21b72b20b62b20b72b6a21b82b20b72b20b82b6a21b92b20b82b20b92b6a21ba2b" - "20b92b20ba2b6a21bb2b20ba2b20bb2b6a21bc2b20bb2b20bc2b6a21bd2b20bc2b20bd2b6a21be2b20bd2b20be2b6a" - "21bf2b20be2b20bf2b6a21c02b20bf2b20c02b6a21c12b20c02b20c12b6a21c22b20c12b20c22b6a21c32b20c22b20" - "c32b6a21c42b20c32b20c42b6a21c52b20c42b20c52b6a21c62b20c52b20c62b6a21c72b20c62b20c72b6a21c82b20" - "c72b20c82b6a21c92b20c82b20c92b6a21ca2b20c92b20ca2b6a21cb2b20ca2b20cb2b6a21cc2b20cb2b20cc2b6a21" - "cd2b20cc2b20cd2b6a21ce2b20cd2b20ce2b6a21cf2b20ce2b20cf2b6a21d02b20cf2b20d02b6a21d12b20d02b20d1" - "2b6a21d22b20d12b20d22b6a21d32b20d22b20d32b6a21d42b20d32b20d42b6a21d52b20d42b20d52b6a21d62b20d5" - "2b20d62b6a21d72b20d62b20d72b6a21d82b20d72b20d82b6a21d92b20d82b20d92b6a21da2b20d92b20da2b6a21db" - "2b20da2b20db2b6a21dc2b20db2b20dc2b6a21dd2b20dc2b20dd2b6a21de2b20dd2b20de2b6a21df2b20de2b20df2b" - "6a21e02b20df2b20e02b6a21e12b20e02b20e12b6a21e22b20e12b20e22b6a21e32b20e22b20e32b6a21e42b20e32b" - "20e42b6a21e52b20e42b20e52b6a21e62b20e52b20e62b6a21e72b20e62b20e72b6a21e82b20e72b20e82b6a21e92b" - "20e82b20e92b6a21ea2b20e92b20ea2b6a21eb2b20ea2b20eb2b6a21ec2b20eb2b20ec2b6a21ed2b20ec2b20ed2b6a" - "21ee2b20ed2b20ee2b6a21ef2b20ee2b20ef2b6a21f02b20ef2b20f02b6a21f12b20f02b20f12b6a21f22b20f12b20" - "f22b6a21f32b20f22b20f32b6a21f42b20f32b20f42b6a21f52b20f42b20f52b6a21f62b20f52b20f62b6a21f72b20" - "f62b20f72b6a21f82b20f72b20f82b6a21f92b20f82b20f92b6a21fa2b20f92b20fa2b6a21fb2b20fa2b20fb2b6a21" - "fc2b20fb2b20fc2b6a21fd2b20fc2b20fd2b6a21fe2b20fd2b20fe2b6a21ff2b20fe2b20ff2b6a21802c20ff2b2080" - "2c6a21812c20802c20812c6a21822c20812c20822c6a21832c20822c20832c6a21842c20832c20842c6a21852c2084" - "2c20852c6a21862c20852c20862c6a21872c20862c20872c6a21882c20872c20882c6a21892c20882c20892c6a218a" - "2c20892c208a2c6a218b2c208a2c208b2c6a218c2c208b2c208c2c6a218d2c208c2c208d2c6a218e2c208d2c208e2c" - "6a218f2c208e2c208f2c6a21902c208f2c20902c6a21912c20902c20912c6a21922c20912c20922c6a21932c20922c" - "20932c6a21942c20932c20942c6a21952c20942c20952c6a21962c20952c20962c6a21972c20962c20972c6a21982c" - "20972c20982c6a21992c20982c20992c6a219a2c20992c209a2c6a219b2c209a2c209b2c6a219c2c209b2c209c2c6a" - "219d2c209c2c209d2c6a219e2c209d2c209e2c6a219f2c209e2c209f2c6a21a02c209f2c20a02c6a21a12c20a02c20" - "a12c6a21a22c20a12c20a22c6a21a32c20a22c20a32c6a21a42c20a32c20a42c6a21a52c20a42c20a52c6a21a62c20" - "a52c20a62c6a21a72c20a62c20a72c6a21a82c20a72c20a82c6a21a92c20a82c20a92c6a21aa2c20a92c20aa2c6a21" - "ab2c20aa2c20ab2c6a21ac2c20ab2c20ac2c6a21ad2c20ac2c20ad2c6a21ae2c20ad2c20ae2c6a21af2c20ae2c20af" - "2c6a21b02c20af2c20b02c6a21b12c20b02c20b12c6a21b22c20b12c20b22c6a21b32c20b22c20b32c6a21b42c20b3" - "2c20b42c6a21b52c20b42c20b52c6a21b62c20b52c20b62c6a21b72c20b62c20b72c6a21b82c20b72c20b82c6a21b9" - "2c20b82c20b92c6a21ba2c20b92c20ba2c6a21bb2c20ba2c20bb2c6a21bc2c20bb2c20bc2c6a21bd2c20bc2c20bd2c" - "6a21be2c20bd2c20be2c6a21bf2c20be2c20bf2c6a21c02c20bf2c20c02c6a21c12c20c02c20c12c6a21c22c20c12c" - "20c22c6a21c32c20c22c20c32c6a21c42c20c32c20c42c6a21c52c20c42c20c52c6a21c62c20c52c20c62c6a21c72c" - "20c62c20c72c6a21c82c20c72c20c82c6a21c92c20c82c20c92c6a21ca2c20c92c20ca2c6a21cb2c20ca2c20cb2c6a" - "21cc2c20cb2c20cc2c6a21cd2c20cc2c20cd2c6a21ce2c20cd2c20ce2c6a21cf2c20ce2c20cf2c6a21d02c20cf2c20" - "d02c6a21d12c20d02c20d12c6a21d22c20d12c20d22c6a21d32c20d22c20d32c6a21d42c20d32c20d42c6a21d52c20" - "d42c20d52c6a21d62c20d52c20d62c6a21d72c20d62c20d72c6a21d82c20d72c20d82c6a21d92c20d82c20d92c6a21" - "da2c20d92c20da2c6a21db2c20da2c20db2c6a21dc2c20db2c20dc2c6a21dd2c20dc2c20dd2c6a21de2c20dd2c20de" - "2c6a21df2c20de2c20df2c6a21e02c20df2c20e02c6a21e12c20e02c20e12c6a21e22c20e12c20e22c6a21e32c20e2" - "2c20e32c6a21e42c20e32c20e42c6a21e52c20e42c20e52c6a21e62c20e52c20e62c6a21e72c20e62c20e72c6a21e8" - "2c20e72c20e82c6a21e92c20e82c20e92c6a21ea2c20e92c20ea2c6a21eb2c20ea2c20eb2c6a21ec2c20eb2c20ec2c" - "6a21ed2c20ec2c20ed2c6a21ee2c20ed2c20ee2c6a21ef2c20ee2c20ef2c6a21f02c20ef2c20f02c6a21f12c20f02c" - "20f12c6a21f22c20f12c20f22c6a21f32c20f22c20f32c6a21f42c20f32c20f42c6a21f52c20f42c20f52c6a21f62c" - "20f52c20f62c6a21f72c20f62c20f72c6a21f82c20f72c20f82c6a21f92c20f82c20f92c6a21fa2c20f92c20fa2c6a" - "21fb2c20fa2c20fb2c6a21fc2c20fb2c20fc2c6a21fd2c20fc2c20fd2c6a21fe2c20fd2c20fe2c6a21ff2c20fe2c20" - "ff2c6a21802d20ff2c20802d6a21812d20802d20812d6a21822d20812d20822d6a21832d20822d20832d6a21842d20" - "832d20842d6a21852d20842d20852d6a21862d20852d20862d6a21872d20862d20872d6a21882d20872d20882d6a21" - "892d20882d20892d6a218a2d20892d208a2d6a218b2d208a2d208b2d6a218c2d208b2d208c2d6a218d2d208c2d208d" - "2d6a218e2d208d2d208e2d6a218f2d208e2d208f2d6a21902d208f2d20902d6a21912d20902d20912d6a21922d2091" - "2d20922d6a21932d20922d20932d6a21942d20932d20942d6a21952d20942d20952d6a21962d20952d20962d6a2197" - "2d20962d20972d6a21982d20972d20982d6a21992d20982d20992d6a219a2d20992d209a2d6a219b2d209a2d209b2d" - "6a219c2d209b2d209c2d6a219d2d209c2d209d2d6a219e2d209d2d209e2d6a219f2d209e2d209f2d6a21a02d209f2d" - "20a02d6a21a12d20a02d20a12d6a21a22d20a12d20a22d6a21a32d20a22d20a32d6a21a42d20a32d20a42d6a21a52d" - "20a42d20a52d6a21a62d20a52d20a62d6a21a72d20a62d20a72d6a21a82d20a72d20a82d6a21a92d20a82d20a92d6a" - "21aa2d20a92d20aa2d6a21ab2d20aa2d20ab2d6a21ac2d20ab2d20ac2d6a21ad2d20ac2d20ad2d6a21ae2d20ad2d20" - "ae2d6a21af2d20ae2d20af2d6a21b02d20af2d20b02d6a21b12d20b02d20b12d6a21b22d20b12d20b22d6a21b32d20" - "b22d20b32d6a21b42d20b32d20b42d6a21b52d20b42d20b52d6a21b62d20b52d20b62d6a21b72d20b62d20b72d6a21" - "b82d20b72d20b82d6a21b92d20b82d20b92d6a21ba2d20b92d20ba2d6a21bb2d20ba2d20bb2d6a21bc2d20bb2d20bc" - "2d6a21bd2d20bc2d20bd2d6a21be2d20bd2d20be2d6a21bf2d20be2d20bf2d6a21c02d20bf2d20c02d6a21c12d20c0" - "2d20c12d6a21c22d20c12d20c22d6a21c32d20c22d20c32d6a21c42d20c32d20c42d6a21c52d20c42d20c52d6a21c6" - "2d20c52d20c62d6a21c72d20c62d20c72d6a21c82d20c72d20c82d6a21c92d20c82d20c92d6a21ca2d20c92d20ca2d" - "6a21cb2d20ca2d20cb2d6a21cc2d20cb2d20cc2d6a21cd2d20cc2d20cd2d6a21ce2d20cd2d20ce2d6a21cf2d20ce2d" - "20cf2d6a21d02d20cf2d20d02d6a21d12d20d02d20d12d6a21d22d20d12d20d22d6a21d32d20d22d20d32d6a21d42d" - "20d32d20d42d6a21d52d20d42d20d52d6a21d62d20d52d20d62d6a21d72d20d62d20d72d6a21d82d20d72d20d82d6a" - "21d92d20d82d20d92d6a21da2d20d92d20da2d6a21db2d20da2d20db2d6a21dc2d20db2d20dc2d6a21dd2d20dc2d20" - "dd2d6a21de2d20dd2d20de2d6a21df2d20de2d20df2d6a21e02d20df2d20e02d6a21e12d20e02d20e12d6a21e22d20" - "e12d20e22d6a21e32d20e22d20e32d6a21e42d20e32d20e42d6a21e52d20e42d20e52d6a21e62d20e52d20e62d6a21" - "e72d20e62d20e72d6a21e82d20e72d20e82d6a21e92d20e82d20e92d6a21ea2d20e92d20ea2d6a21eb2d20ea2d20eb" - "2d6a21ec2d20eb2d20ec2d6a21ed2d20ec2d20ed2d6a21ee2d20ed2d20ee2d6a21ef2d20ee2d20ef2d6a21f02d20ef" - "2d20f02d6a21f12d20f02d20f12d6a21f22d20f12d20f22d6a21f32d20f22d20f32d6a21f42d20f32d20f42d6a21f5" - "2d20f42d20f52d6a21f62d20f52d20f62d6a21f72d20f62d20f72d6a21f82d20f72d20f82d6a21f92d20f82d20f92d" - "6a21fa2d20f92d20fa2d6a21fb2d20fa2d20fb2d6a21fc2d20fb2d20fc2d6a21fd2d20fc2d20fd2d6a21fe2d20fd2d" - "20fe2d6a21ff2d20fe2d20ff2d6a21802e20ff2d20802e6a21812e20802e20812e6a21822e20812e20822e6a21832e" - "20822e20832e6a21842e20832e20842e6a21852e20842e20852e6a21862e20852e20862e6a21872e20862e20872e6a" - "21882e20872e20882e6a21892e20882e20892e6a218a2e20892e208a2e6a218b2e208a2e208b2e6a218c2e208b2e20" - "8c2e6a218d2e208c2e208d2e6a218e2e208d2e208e2e6a218f2e208e2e208f2e6a21902e208f2e20902e6a21912e20" - "902e20912e6a21922e20912e20922e6a21932e20922e20932e6a21942e20932e20942e6a21952e20942e20952e6a21" - "962e20952e20962e6a21972e20962e20972e6a21982e20972e20982e6a21992e20982e20992e6a219a2e20992e209a" - "2e6a219b2e209a2e209b2e6a219c2e209b2e209c2e6a219d2e209c2e209d2e6a219e2e209d2e209e2e6a219f2e209e" - "2e209f2e6a21a02e209f2e20a02e6a21a12e20a02e20a12e6a21a22e20a12e20a22e6a21a32e20a22e20a32e6a21a4" - "2e20a32e20a42e6a21a52e20a42e20a52e6a21a62e20a52e20a62e6a21a72e20a62e20a72e6a21a82e20a72e20a82e" - "6a21a92e20a82e20a92e6a21aa2e20a92e20aa2e6a21ab2e20aa2e20ab2e6a21ac2e20ab2e20ac2e6a21ad2e20ac2e" - "20ad2e6a21ae2e20ad2e20ae2e6a21af2e20ae2e20af2e6a21b02e20af2e20b02e6a21b12e20b02e20b12e6a21b22e" - "20b12e20b22e6a21b32e20b22e20b32e6a21b42e20b32e20b42e6a21b52e20b42e20b52e6a21b62e20b52e20b62e6a" - "21b72e20b62e20b72e6a21b82e20b72e20b82e6a21b92e20b82e20b92e6a21ba2e20b92e20ba2e6a21bb2e20ba2e20" - "bb2e6a21bc2e20bb2e20bc2e6a21bd2e20bc2e20bd2e6a21be2e20bd2e20be2e6a21bf2e20be2e20bf2e6a21c02e20" - "bf2e20c02e6a21c12e20c02e20c12e6a21c22e20c12e20c22e6a21c32e20c22e20c32e6a21c42e20c32e20c42e6a21" - "c52e20c42e20c52e6a21c62e20c52e20c62e6a21c72e20c62e20c72e6a21c82e20c72e20c82e6a21c92e20c82e20c9" - "2e6a21ca2e20c92e20ca2e6a21cb2e20ca2e20cb2e6a21cc2e20cb2e20cc2e6a21cd2e20cc2e20cd2e6a21ce2e20cd" - "2e20ce2e6a21cf2e20ce2e20cf2e6a21d02e20cf2e20d02e6a21d12e20d02e20d12e6a21d22e20d12e20d22e6a21d3" - "2e20d22e20d32e6a21d42e20d32e20d42e6a21d52e20d42e20d52e6a21d62e20d52e20d62e6a21d72e20d62e20d72e" - "6a21d82e20d72e20d82e6a21d92e20d82e20d92e6a21da2e20d92e20da2e6a21db2e20da2e20db2e6a21dc2e20db2e" - "20dc2e6a21dd2e20dc2e20dd2e6a21de2e20dd2e20de2e6a21df2e20de2e20df2e6a21e02e20df2e20e02e6a21e12e" - "20e02e20e12e6a21e22e20e12e20e22e6a21e32e20e22e20e32e6a21e42e20e32e20e42e6a21e52e20e42e20e52e6a" - "21e62e20e52e20e62e6a21e72e20e62e20e72e6a21e82e20e72e20e82e6a21e92e20e82e20e92e6a21ea2e20e92e20" - "ea2e6a21eb2e20ea2e20eb2e6a21ec2e20eb2e20ec2e6a21ed2e20ec2e20ed2e6a21ee2e20ed2e20ee2e6a21ef2e20" - "ee2e20ef2e6a21f02e20ef2e20f02e6a21f12e20f02e20f12e6a21f22e20f12e20f22e6a21f32e20f22e20f32e6a21" - "f42e20f32e20f42e6a21f52e20f42e20f52e6a21f62e20f52e20f62e6a21f72e20f62e20f72e6a21f82e20f72e20f8" - "2e6a21f92e20f82e20f92e6a21fa2e20f92e20fa2e6a21fb2e20fa2e20fb2e6a21fc2e20fb2e20fc2e6a21fd2e20fc" - "2e20fd2e6a21fe2e20fd2e20fe2e6a21ff2e20fe2e20ff2e6a21802f20ff2e20802f6a21812f20802f20812f6a2182" - "2f20812f20822f6a21832f20822f20832f6a21842f20832f20842f6a21852f20842f20852f6a21862f20852f20862f" - "6a21872f20862f20872f6a21882f20872f20882f6a21892f20882f20892f6a218a2f20892f208a2f6a218b2f208a2f" - "208b2f6a218c2f208b2f208c2f6a218d2f208c2f208d2f6a218e2f208d2f208e2f6a218f2f208e2f208f2f6a21902f" - "208f2f20902f6a21912f20902f20912f6a21922f20912f20922f6a21932f20922f20932f6a21942f20932f20942f6a" - "21952f20942f20952f6a21962f20952f20962f6a21972f20962f20972f6a21982f20972f20982f6a21992f20982f20" - "992f6a219a2f20992f209a2f6a219b2f209a2f209b2f6a219c2f209b2f209c2f6a219d2f209c2f209d2f6a219e2f20" - "9d2f209e2f6a219f2f209e2f209f2f6a21a02f209f2f20a02f6a21a12f20a02f20a12f6a21a22f20a12f20a22f6a21" - "a32f20a22f20a32f6a21a42f20a32f20a42f6a21a52f20a42f20a52f6a21a62f20a52f20a62f6a21a72f20a62f20a7" - "2f6a21a82f20a72f20a82f6a21a92f20a82f20a92f6a21aa2f20a92f20aa2f6a21ab2f20aa2f20ab2f6a21ac2f20ab" - "2f20ac2f6a21ad2f20ac2f20ad2f6a21ae2f20ad2f20ae2f6a21af2f20ae2f20af2f6a21b02f20af2f20b02f6a21b1" - "2f20b02f20b12f6a21b22f20b12f20b22f6a21b32f20b22f20b32f6a21b42f20b32f20b42f6a21b52f20b42f20b52f" - "6a21b62f20b52f20b62f6a21b72f20b62f20b72f6a21b82f20b72f20b82f6a21b92f20b82f20b92f6a21ba2f20b92f" - "20ba2f6a21bb2f20ba2f20bb2f6a21bc2f20bb2f20bc2f6a21bd2f20bc2f20bd2f6a21be2f20bd2f20be2f6a21bf2f" - "20be2f20bf2f6a21c02f20bf2f20c02f6a21c12f20c02f20c12f6a21c22f20c12f20c22f6a21c32f20c22f20c32f6a" - "21c42f20c32f20c42f6a21c52f20c42f20c52f6a21c62f20c52f20c62f6a21c72f20c62f20c72f6a21c82f20c72f20" - "c82f6a21c92f20c82f20c92f6a21ca2f20c92f20ca2f6a21cb2f20ca2f20cb2f6a21cc2f20cb2f20cc2f6a21cd2f20" - "cc2f20cd2f6a21ce2f20cd2f20ce2f6a21cf2f20ce2f20cf2f6a21d02f20cf2f20d02f6a21d12f20d02f20d12f6a21" - "d22f20d12f20d22f6a21d32f20d22f20d32f6a21d42f20d32f20d42f6a21d52f20d42f20d52f6a21d62f20d52f20d6" - "2f6a21d72f20d62f20d72f6a21d82f20d72f20d82f6a21d92f20d82f20d92f6a21da2f20d92f20da2f6a21db2f20da" - "2f20db2f6a21dc2f20db2f20dc2f6a21dd2f20dc2f20dd2f6a21de2f20dd2f20de2f6a21df2f20de2f20df2f6a21e0" - "2f20df2f20e02f6a21e12f20e02f20e12f6a21e22f20e12f20e22f6a21e32f20e22f20e32f6a21e42f20e32f20e42f" - "6a21e52f20e42f20e52f6a21e62f20e52f20e62f6a21e72f20e62f20e72f6a21e82f20e72f20e82f6a21e92f20e82f" - "20e92f6a21ea2f20e92f20ea2f6a21eb2f20ea2f20eb2f6a21ec2f20eb2f20ec2f6a21ed2f20ec2f20ed2f6a21ee2f" - "20ed2f20ee2f6a21ef2f20ee2f20ef2f6a21f02f20ef2f20f02f6a21f12f20f02f20f12f6a21f22f20f12f20f22f6a" - "21f32f20f22f20f32f6a21f42f20f32f20f42f6a21f52f20f42f20f52f6a21f62f20f52f20f62f6a21f72f20f62f20" - "f72f6a21f82f20f72f20f82f6a21f92f20f82f20f92f6a21fa2f20f92f20fa2f6a21fb2f20fa2f20fb2f6a21fc2f20" - "fb2f20fc2f6a21fd2f20fc2f20fd2f6a21fe2f20fd2f20fe2f6a21ff2f20fe2f20ff2f6a21803020ff2f2080306a21" - "81302080302081306a2182302081302082306a2183302082302083306a2184302083302084306a2185302084302085" - "306a2186302085302086306a2187302086302087306a2188302087302088306a2189302088302089306a218a302089" - "30208a306a218b30208a30208b306a218c30208b30208c306a218d30208c30208d306a218e30208d30208e306a218f" - "30208e30208f306a219030208f302090306a2191302090302091306a2192302091302092306a219330209230209330" - "6a2194302093302094306a2195302094302095306a2196302095302096306a2197302096302097306a219830209730" - "2098306a2199302098302099306a219a30209930209a306a219b30209a30209b306a219c30209b30209c306a219d30" - "209c30209d306a219e30209d30209e306a219f30209e30209f306a21a030209f3020a0306a21a13020a03020a1306a" - "21a23020a13020a2306a21a33020a23020a3306a21a43020a33020a4306a21a53020a43020a5306a21a63020a53020" - "a6306a21a73020a63020a7306a21a83020a73020a8306a21a93020a83020a9306a21aa3020a93020aa306a21ab3020" - "aa3020ab306a21ac3020ab3020ac306a21ad3020ac3020ad306a21ae3020ad3020ae306a21af3020ae3020af306a21" - "b03020af3020b0306a21b13020b03020b1306a21b23020b13020b2306a21b33020b23020b3306a21b43020b33020b4" - "306a21b53020b43020b5306a21b63020b53020b6306a21b73020b63020b7306a21b83020b73020b8306a21b93020b8" - "3020b9306a21ba3020b93020ba306a21bb3020ba3020bb306a21bc3020bb3020bc306a21bd3020bc3020bd306a21be" - "3020bd3020be306a21bf3020be3020bf306a21c03020bf3020c0306a21c13020c03020c1306a21c23020c13020c230" - "6a21c33020c23020c3306a21c43020c33020c4306a21c53020c43020c5306a21c63020c53020c6306a21c73020c630" - "20c7306a21c83020c73020c8306a21c93020c83020c9306a21ca3020c93020ca306a21cb3020ca3020cb306a21cc30" - "20cb3020cc306a21cd3020cc3020cd306a21ce3020cd3020ce306a21cf3020ce3020cf306a21d03020cf3020d0306a" - "21d13020d03020d1306a21d23020d13020d2306a21d33020d23020d3306a21d43020d33020d4306a21d53020d43020" - "d5306a21d63020d53020d6306a21d73020d63020d7306a21d83020d73020d8306a21d93020d83020d9306a21da3020" - "d93020da306a21db3020da3020db306a21dc3020db3020dc306a21dd3020dc3020dd306a21de3020dd3020de306a21" - "df3020de3020df306a21e03020df3020e0306a21e13020e03020e1306a21e23020e13020e2306a21e33020e23020e3" - "306a21e43020e33020e4306a21e53020e43020e5306a21e63020e53020e6306a21e73020e63020e7306a21e83020e7" - "3020e8306a21e93020e83020e9306a21ea3020e93020ea306a21eb3020ea3020eb306a21ec3020eb3020ec306a21ed" - "3020ec3020ed306a21ee3020ed3020ee306a21ef3020ee3020ef306a21f03020ef3020f0306a21f13020f03020f130" - "6a21f23020f13020f2306a21f33020f23020f3306a21f43020f33020f4306a21f53020f43020f5306a21f63020f530" - "20f6306a21f73020f63020f7306a21f83020f73020f8306a21f93020f83020f9306a21fa3020f93020fa306a21fb30" - "20fa3020fb306a21fc3020fb3020fc306a21fd3020fc3020fd306a21fe3020fd3020fe306a21ff3020fe3020ff306a" - "21803120ff302080316a2181312080312081316a2182312081312082316a2183312082312083316a21843120833120" - "84316a2185312084312085316a2186312085312086316a2187312086312087316a2188312087312088316a21893120" - "88312089316a218a31208931208a316a218b31208a31208b316a218c31208b31208c316a218d31208c31208d316a21" - "8e31208d31208e316a218f31208e31208f316a219031208f312090316a2191312090312091316a2192312091312092" - "316a2193312092312093316a2194312093312094316a2195312094312095316a2196312095312096316a2197312096" - "312097316a2198312097312098316a2199312098312099316a219a31209931209a316a219b31209a31209b316a219c" - "31209b31209c316a219d31209c31209d316a219e31209d31209e316a219f31209e31209f316a21a031209f3120a031" - "6a21a13120a03120a1316a21a23120a13120a2316a21a33120a23120a3316a21a43120a33120a4316a21a53120a431" - "20a5316a21a63120a53120a6316a21a73120a63120a7316a21a83120a73120a8316a21a93120a83120a9316a21aa31" - "20a93120aa316a21ab3120aa3120ab316a21ac3120ab3120ac316a21ad3120ac3120ad316a21ae3120ad3120ae316a" - "21af3120ae3120af316a21b03120af3120b0316a21b13120b03120b1316a21b23120b13120b2316a21b33120b23120" - "b3316a21b43120b33120b4316a21b53120b43120b5316a21b63120b53120b6316a21b73120b63120b7316a21b83120" - "b73120b8316a21b93120b83120b9316a21ba3120b93120ba316a21bb3120ba3120bb316a21bc3120bb3120bc316a21" - "bd3120bc3120bd316a21be3120bd3120be316a21bf3120be3120bf316a21c03120bf3120c0316a21c13120c03120c1" - "316a21c23120c13120c2316a21c33120c23120c3316a21c43120c33120c4316a21c53120c43120c5316a21c63120c5" - "3120c6316a21c73120c63120c7316a21c83120c73120c8316a21c93120c83120c9316a21ca3120c93120ca316a21cb" - "3120ca3120cb316a21cc3120cb3120cc316a21cd3120cc3120cd316a21ce3120cd3120ce316a21cf3120ce3120cf31" - "6a21d03120cf3120d0316a21d13120d03120d1316a21d23120d13120d2316a21d33120d23120d3316a21d43120d331" - "20d4316a21d53120d43120d5316a21d63120d53120d6316a21d73120d63120d7316a21d83120d73120d8316a21d931" - "20d83120d9316a21da3120d93120da316a21db3120da3120db316a21dc3120db3120dc316a21dd3120dc3120dd316a" - "21de3120dd3120de316a21df3120de3120df316a21e03120df3120e0316a21e13120e03120e1316a21e23120e13120" - "e2316a21e33120e23120e3316a21e43120e33120e4316a21e53120e43120e5316a21e63120e53120e6316a21e73120" - "e63120e7316a21e83120e73120e8316a21e93120e83120e9316a21ea3120e93120ea316a21eb3120ea3120eb316a21" - "ec3120eb3120ec316a21ed3120ec3120ed316a21ee3120ed3120ee316a21ef3120ee3120ef316a21f03120ef3120f0" - "316a21f13120f03120f1316a21f23120f13120f2316a21f33120f23120f3316a21f43120f33120f4316a21f53120f4" - "3120f5316a21f63120f53120f6316a21f73120f63120f7316a21f83120f73120f8316a21f93120f83120f9316a21fa" - "3120f93120fa316a21fb3120fa3120fb316a21fc3120fb3120fc316a21fd3120fc3120fd316a21fe3120fd3120fe31" - "6a21ff3120fe3120ff316a21803220ff312080326a2181322080322081326a2182322081322082326a218332208232" - "2083326a2184322083322084326a2185322084322085326a2186322085322086326a2187322086322087326a218832" - "2087322088326a2189322088322089326a218a32208932208a326a218b32208a32208b326a218c32208b32208c326a" - "218d32208c32208d326a218e32208d32208e326a218f32208e32208f326a219032208f322090326a21913220903220" - "91326a2192322091322092326a2193322092322093326a2194322093322094326a2195322094322095326a21963220" - "95322096326a2197322096322097326a2198322097322098326a2199322098322099326a219a32209932209a326a21" - "9b32209a32209b326a219c32209b32209c326a219d32209c32209d326a219e32209d32209e326a219f32209e32209f" - "326a21a032209f3220a0326a21a13220a03220a1326a21a23220a13220a2326a21a33220a23220a3326a21a43220a3" - "3220a4326a21a53220a43220a5326a21a63220a53220a6326a21a73220a63220a7326a21a83220a73220a8326a21a9" - "3220a83220a9326a21aa3220a93220aa326a21ab3220aa3220ab326a21ac3220ab3220ac326a21ad3220ac3220ad32" - "6a21ae3220ad3220ae326a21af3220ae3220af326a21b03220af3220b0326a21b13220b03220b1326a21b23220b132" - "20b2326a21b33220b23220b3326a21b43220b33220b4326a21b53220b43220b5326a21b63220b53220b6326a21b732" - "20b63220b7326a21b83220b73220b8326a21b93220b83220b9326a21ba3220b93220ba326a21bb3220ba3220bb326a" - "21bc3220bb3220bc326a21bd3220bc3220bd326a21be3220bd3220be326a21bf3220be3220bf326a21c03220bf3220" - "c0326a21c13220c03220c1326a21c23220c13220c2326a21c33220c23220c3326a21c43220c33220c4326a21c53220" - "c43220c5326a21c63220c53220c6326a21c73220c63220c7326a21c83220c73220c8326a21c93220c83220c9326a21" - "ca3220c93220ca326a21cb3220ca3220cb326a21cc3220cb3220cc326a21cd3220cc3220cd326a21ce3220cd3220ce" - "326a21cf3220ce3220cf326a21d03220cf3220d0326a21d13220d03220d1326a21d23220d13220d2326a21d33220d2" - "3220d3326a21d43220d33220d4326a21d53220d43220d5326a21d63220d53220d6326a21d73220d63220d7326a21d8" - "3220d73220d8326a21d93220d83220d9326a21da3220d93220da326a21db3220da3220db326a21dc3220db3220dc32" - "6a21dd3220dc3220dd326a21de3220dd3220de326a21df3220de3220df326a21e03220df3220e0326a21e13220e032" - "20e1326a21e23220e13220e2326a21e33220e23220e3326a21e43220e33220e4326a21e53220e43220e5326a21e632" - "20e53220e6326a21e73220e63220e7326a21e83220e73220e8326a21e93220e83220e9326a21ea3220e93220ea326a" - "21eb3220ea3220eb326a21ec3220eb3220ec326a21ed3220ec3220ed326a21ee3220ed3220ee326a21ef3220ee3220" - "ef326a21f03220ef3220f0326a21f13220f03220f1326a21f23220f13220f2326a21f33220f23220f3326a21f43220" - "f33220f4326a21f53220f43220f5326a21f63220f53220f6326a21f73220f63220f7326a21f83220f73220f8326a21" - "f93220f83220f9326a21fa3220f93220fa326a21fb3220fa3220fb326a21fc3220fb3220fc326a21fd3220fc3220fd" - "326a21fe3220fd3220fe326a21ff3220fe3220ff326a21803320ff322080336a2181332080332081336a2182332081" - "332082336a2183332082332083336a2184332083332084336a2185332084332085336a2186332085332086336a2187" - "332086332087336a2188332087332088336a2189332088332089336a218a33208933208a336a218b33208a33208b33" - "6a218c33208b33208c336a218d33208c33208d336a218e33208d33208e336a218f33208e33208f336a219033208f33" - "2090336a2191332090332091336a2192332091332092336a2193332092332093336a2194332093332094336a219533" - "2094332095336a2196332095332096336a2197332096332097336a2198332097332098336a2199332098332099336a" - "219a33209933209a336a219b33209a33209b336a219c33209b33209c336a219d33209c33209d336a219e33209d3320" - "9e336a219f33209e33209f336a21a033209f3320a0336a21a13320a03320a1336a21a23320a13320a2336a21a33320" - "a23320a3336a21a43320a33320a4336a21a53320a43320a5336a21a63320a53320a6336a21a73320a63320a7336a21" - "a83320a73320a8336a21a93320a83320a9336a21aa3320a93320aa336a21ab3320aa3320ab336a21ac3320ab3320ac" - "336a21ad3320ac3320ad336a21ae3320ad3320ae336a21af3320ae3320af336a21b03320af3320b0336a21b13320b0" - "3320b1336a21b23320b13320b2336a21b33320b23320b3336a21b43320b33320b4336a21b53320b43320b5336a21b6" - "3320b53320b6336a21b73320b63320b7336a21b83320b73320b8336a21b93320b83320b9336a21ba3320b93320ba33" - "6a21bb3320ba3320bb336a21bc3320bb3320bc336a21bd3320bc3320bd336a21be3320bd3320be336a21bf3320be33" - "20bf336a21c03320bf3320c0336a21c13320c03320c1336a21c23320c13320c2336a21c33320c23320c3336a21c433" - "20c33320c4336a21c53320c43320c5336a21c63320c53320c6336a21c73320c63320c7336a21c83320c73320c8336a" - "21c93320c83320c9336a21ca3320c93320ca336a21cb3320ca3320cb336a21cc3320cb3320cc336a21cd3320cc3320" - "cd336a21ce3320cd3320ce336a21cf3320ce3320cf336a21d03320cf3320d0336a21d13320d03320d1336a21d23320" - "d13320d2336a21d33320d23320d3336a21d43320d33320d4336a21d53320d43320d5336a21d63320d53320d6336a21" - "d73320d63320d7336a21d83320d73320d8336a21d93320d83320d9336a21da3320d93320da336a21db3320da3320db" - "336a21dc3320db3320dc336a21dd3320dc3320dd336a21de3320dd3320de336a21df3320de3320df336a21e03320df" - "3320e0336a21e13320e03320e1336a21e23320e13320e2336a21e33320e23320e3336a21e43320e33320e4336a21e5" - "3320e43320e5336a21e63320e53320e6336a21e73320e63320e7336a21e83320e73320e8336a21e93320e83320e933" - "6a21ea3320e93320ea336a21eb3320ea3320eb336a21ec3320eb3320ec336a21ed3320ec3320ed336a21ee3320ed33" - "20ee336a21ef3320ee3320ef336a21f03320ef3320f0336a21f13320f03320f1336a21f23320f13320f2336a21f333" - "20f23320f3336a21f43320f33320f4336a21f53320f43320f5336a21f63320f53320f6336a21f73320f63320f7336a" - "21f83320f73320f8336a21f93320f83320f9336a21fa3320f93320fa336a21fb3320fa3320fb336a21fc3320fb3320" - "fc336a21fd3320fc3320fd336a21fe3320fd3320fe336a21ff3320fe3320ff336a21803420ff332080346a21813420" - "80342081346a2182342081342082346a2183342082342083346a2184342083342084346a2185342084342085346a21" - "86342085342086346a2187342086342087346a2188342087342088346a2189342088342089346a218a34208934208a" - "346a218b34208a34208b346a218c34208b34208c346a218d34208c34208d346a218e34208d34208e346a218f34208e" - "34208f346a219034208f342090346a2191342090342091346a2192342091342092346a2193342092342093346a2194" - "342093342094346a2195342094342095346a2196342095342096346a2197342096342097346a219834209734209834" - "6a2199342098342099346a219a34209934209a346a219b34209a34209b346a219c34209b34209c346a219d34209c34" - "209d346a219e34209d34209e346a219f34209e34209f346a21a034209f3420a0346a21a13420a03420a1346a21a234" - "20a13420a2346a21a33420a23420a3346a21a43420a33420a4346a21a53420a43420a5346a21a63420a53420a6346a" - "21a73420a63420a7346a21a83420a73420a8346a21a93420a83420a9346a21aa3420a93420aa346a21ab3420aa3420" - "ab346a21ac3420ab3420ac346a21ad3420ac3420ad346a21ae3420ad3420ae346a21af3420ae3420af346a21b03420" - "af3420b0346a21b13420b03420b1346a21b23420b13420b2346a21b33420b23420b3346a21b43420b33420b4346a21" - "b53420b43420b5346a21b63420b53420b6346a21b73420b63420b7346a21b83420b73420b8346a21b93420b83420b9" - "346a21ba3420b93420ba346a21bb3420ba3420bb346a21bc3420bb3420bc346a21bd3420bc3420bd346a21be3420bd" - "3420be346a21bf3420be3420bf346a21c03420bf3420c0346a21c13420c03420c1346a21c23420c13420c2346a21c3" - "3420c23420c3346a21c43420c33420c4346a21c53420c43420c5346a21c63420c53420c6346a21c73420c63420c734" - "6a21c83420c73420c8346a21c93420c83420c9346a21ca3420c93420ca346a21cb3420ca3420cb346a21cc3420cb34" - "20cc346a21cd3420cc3420cd346a21ce3420cd3420ce346a21cf3420ce3420cf346a21d03420cf3420d0346a21d134" - "20d03420d1346a21d23420d13420d2346a21d33420d23420d3346a21d43420d33420d4346a21d53420d43420d5346a" - "21d63420d53420d6346a21d73420d63420d7346a21d83420d73420d8346a21d93420d83420d9346a21da3420d93420" - "da346a21db3420da3420db346a21dc3420db3420dc346a21dd3420dc3420dd346a21de3420dd3420de346a21df3420" - "de3420df346a21e03420df3420e0346a21e13420e03420e1346a21e23420e13420e2346a21e33420e23420e3346a21" - "e43420e33420e4346a21e53420e43420e5346a21e63420e53420e6346a21e73420e63420e7346a21e83420e73420e8" - "346a21e93420e83420e9346a21ea3420e93420ea346a21eb3420ea3420eb346a21ec3420eb3420ec346a21ed3420ec" - "3420ed346a21ee3420ed3420ee346a21ef3420ee3420ef346a21f03420ef3420f0346a21f13420f03420f1346a21f2" - "3420f13420f2346a21f33420f23420f3346a21f43420f33420f4346a21f53420f43420f5346a21f63420f53420f634" - "6a21f73420f63420f7346a21f83420f73420f8346a21f93420f83420f9346a21fa3420f93420fa346a21fb3420fa34" - "20fb346a21fc3420fb3420fc346a21fd3420fc3420fd346a21fe3420fd3420fe346a21ff3420fe3420ff346a218035" - "20ff342080356a2181352080352081356a2182352081352082356a2183352082352083356a2184352083352084356a" - "2185352084352085356a2186352085352086356a2187352086352087356a2188352087352088356a21893520883520" - "89356a218a35208935208a356a218b35208a35208b356a218c35208b35208c356a218d35208c35208d356a218e3520" - "8d35208e356a218f35208e35208f356a219035208f352090356a2191352090352091356a2192352091352092356a21" - "93352092352093356a2194352093352094356a2195352094352095356a2196352095352096356a2197352096352097" - "356a2198352097352098356a2199352098352099356a219a35209935209a356a219b35209a35209b356a219c35209b" - "35209c356a219d35209c35209d356a219e35209d35209e356a219f35209e35209f356a21a035209f3520a0356a21a1" - "3520a03520a1356a21a23520a13520a2356a21a33520a23520a3356a21a43520a33520a4356a21a53520a43520a535" - "6a21a63520a53520a6356a21a73520a63520a7356a21a83520a73520a8356a21a93520a83520a9356a21aa3520a935" - "20aa356a21ab3520aa3520ab356a21ac3520ab3520ac356a21ad3520ac3520ad356a21ae3520ad3520ae356a21af35" - "20ae3520af356a21b03520af3520b0356a21b13520b03520b1356a21b23520b13520b2356a21b33520b23520b3356a" - "21b43520b33520b4356a21b53520b43520b5356a21b63520b53520b6356a21b73520b63520b7356a21b83520b73520" - "b8356a21b93520b83520b9356a21ba3520b93520ba356a21bb3520ba3520bb356a21bc3520bb3520bc356a21bd3520" - "bc3520bd356a21be3520bd3520be356a21bf3520be3520bf356a21c03520bf3520c0356a21c13520c03520c1356a21" - "c23520c13520c2356a21c33520c23520c3356a21c43520c33520c4356a21c53520c43520c5356a21c63520c53520c6" - "356a21c73520c63520c7356a21c83520c73520c8356a21c93520c83520c9356a21ca3520c93520ca356a21cb3520ca" - "3520cb356a21cc3520cb3520cc356a21cd3520cc3520cd356a21ce3520cd3520ce356a21cf3520ce3520cf356a21d0" - "3520cf3520d0356a21d13520d03520d1356a21d23520d13520d2356a21d33520d23520d3356a21d43520d33520d435" - "6a21d53520d43520d5356a21d63520d53520d6356a21d73520d63520d7356a21d83520d73520d8356a21d93520d835" - "20d9356a21da3520d93520da356a21db3520da3520db356a21dc3520db3520dc356a21dd3520dc3520dd356a21de35" - "20dd3520de356a21df3520de3520df356a21e03520df3520e0356a21e13520e03520e1356a21e23520e13520e2356a" - "21e33520e23520e3356a21e43520e33520e4356a21e53520e43520e5356a21e63520e53520e6356a21e73520e63520" - "e7356a21e83520e73520e8356a21e93520e83520e9356a21ea3520e93520ea356a21eb3520ea3520eb356a21ec3520" - "eb3520ec356a21ed3520ec3520ed356a21ee3520ed3520ee356a21ef3520ee3520ef356a21f03520ef3520f0356a21" - "f13520f03520f1356a21f23520f13520f2356a21f33520f23520f3356a21f43520f33520f4356a21f53520f43520f5" - "356a21f63520f53520f6356a21f73520f63520f7356a21f83520f73520f8356a21f93520f83520f9356a21fa3520f9" - "3520fa356a21fb3520fa3520fb356a21fc3520fb3520fc356a21fd3520fc3520fd356a21fe3520fd3520fe356a21ff" - "3520fe3520ff356a21803620ff352080366a2181362080362081366a2182362081362082366a218336208236208336" - "6a2184362083362084366a2185362084362085366a2186362085362086366a2187362086362087366a218836208736" - "2088366a2189362088362089366a218a36208936208a366a218b36208a36208b366a218c36208b36208c366a218d36" - "208c36208d366a218e36208d36208e366a218f36208e36208f366a219036208f362090366a2191362090362091366a" - "2192362091362092366a2193362092362093366a2194362093362094366a2195362094362095366a21963620953620" - "96366a2197362096362097366a2198362097362098366a2199362098362099366a219a36209936209a366a219b3620" - "9a36209b366a219c36209b36209c366a219d36209c36209d366a219e36209d36209e366a219f36209e36209f366a21" - "a036209f3620a0366a21a13620a03620a1366a21a23620a13620a2366a21a33620a23620a3366a21a43620a33620a4" - "366a21a53620a43620a5366a21a63620a53620a6366a21a73620a63620a7366a21a83620a73620a8366a21a93620a8" - "3620a9366a21aa3620a93620aa366a21ab3620aa3620ab366a21ac3620ab3620ac366a21ad3620ac3620ad366a21ae" - "3620ad3620ae366a21af3620ae3620af366a21b03620af3620b0366a21b13620b03620b1366a21b23620b13620b236" - "6a21b33620b23620b3366a21b43620b33620b4366a21b53620b43620b5366a21b63620b53620b6366a21b73620b636" - "20b7366a21b83620b73620b8366a21b93620b83620b9366a21ba3620b93620ba366a21bb3620ba3620bb366a21bc36" - "20bb3620bc366a21bd3620bc3620bd366a21be3620bd3620be366a21bf3620be3620bf366a21c03620bf3620c0366a" - "21c13620c03620c1366a21c23620c13620c2366a21c33620c23620c3366a21c43620c33620c4366a21c53620c43620" - "c5366a21c63620c53620c6366a21c73620c63620c7366a21c83620c73620c8366a21c93620c83620c9366a21ca3620" - "c93620ca366a21cb3620ca3620cb366a21cc3620cb3620cc366a21cd3620cc3620cd366a21ce3620cd3620ce366a21" - "cf3620ce3620cf366a21d03620cf3620d0366a21d13620d03620d1366a21d23620d13620d2366a21d33620d23620d3" - "366a21d43620d33620d4366a21d53620d43620d5366a21d63620d53620d6366a21d73620d63620d7366a21d83620d7" - "3620d8366a21d93620d83620d9366a21da3620d93620da366a21db3620da3620db366a21dc3620db3620dc366a21dd" - "3620dc3620dd366a21de3620dd3620de366a21df3620de3620df366a21e03620df3620e0366a21e13620e03620e136" - "6a21e23620e13620e2366a21e33620e23620e3366a21e43620e33620e4366a21e53620e43620e5366a21e63620e536" - "20e6366a21e73620e63620e7366a21e83620e73620e8366a21e93620e83620e9366a21ea3620e93620ea366a21eb36" - "20ea3620eb366a21ec3620eb3620ec366a21ed3620ec3620ed366a21ee3620ed3620ee366a21ef3620ee3620ef366a" - "21f03620ef3620f0366a21f13620f03620f1366a21f23620f13620f2366a21f33620f23620f3366a21f43620f33620" - "f4366a21f53620f43620f5366a21f63620f53620f6366a21f73620f63620f7366a21f83620f73620f8366a21f93620" - "f83620f9366a21fa3620f93620fa366a21fb3620fa3620fb366a21fc3620fb3620fc366a21fd3620fc3620fd366a21" - "fe3620fd3620fe366a21ff3620fe3620ff366a21803720ff362080376a2181372080372081376a2182372081372082" - "376a2183372082372083376a2184372083372084376a2185372084372085376a2186372085372086376a2187372086" - "372087376a2188372087372088376a2189372088372089376a218a37208937208a376a218b37208a37208b376a218c" - "37208b37208c376a218d37208c37208d376a218e37208d37208e376a218f37208e37208f376a219037208f37209037" - "6a2191372090372091376a2192372091372092376a2193372092372093376a2194372093372094376a219537209437" - "2095376a2196372095372096376a2197372096372097376a2198372097372098376a2199372098372099376a219a37" - "209937209a376a219b37209a37209b376a219c37209b37209c376a219d37209c37209d376a219e37209d37209e376a" - "219f37209e37209f376a21a037209f3720a0376a21a13720a03720a1376a21a23720a13720a2376a21a33720a23720" - "a3376a21a43720a33720a4376a21a53720a43720a5376a21a63720a53720a6376a21a73720a63720a7376a21a83720" - "a73720a8376a21a93720a83720a9376a21aa3720a93720aa376a21ab3720aa3720ab376a21ac3720ab3720ac376a21" - "ad3720ac3720ad376a21ae3720ad3720ae376a21af3720ae3720af376a21b03720af3720b0376a21b13720b03720b1" - "376a21b23720b13720b2376a21b33720b23720b3376a21b43720b33720b4376a21b53720b43720b5376a21b63720b5" - "3720b6376a21b73720b63720b7376a21b83720b73720b8376a21b93720b83720b9376a21ba3720b93720ba376a21bb" - "3720ba3720bb376a21bc3720bb3720bc376a21bd3720bc3720bd376a21be3720bd3720be376a21bf3720be3720bf37" - "6a21c03720bf3720c0376a21c13720c03720c1376a21c23720c13720c2376a21c33720c23720c3376a21c43720c337" - "20c4376a21c53720c43720c5376a21c63720c53720c6376a21c73720c63720c7376a21c83720c73720c8376a21c937" - "20c83720c9376a21ca3720c93720ca376a21cb3720ca3720cb376a21cc3720cb3720cc376a21cd3720cc3720cd376a" - "21ce3720cd3720ce376a21cf3720ce3720cf376a21d03720cf3720d0376a21d13720d03720d1376a21d23720d13720" - "d2376a21d33720d23720d3376a21d43720d33720d4376a21d53720d43720d5376a21d63720d53720d6376a21d73720" - "d63720d7376a21d83720d73720d8376a21d93720d83720d9376a21da3720d93720da376a21db3720da3720db376a21" - "dc3720db3720dc376a21dd3720dc3720dd376a21de3720dd3720de376a21df3720de3720df376a21e03720df3720e0" - "376a21e13720e03720e1376a21e23720e13720e2376a21e33720e23720e3376a21e43720e33720e4376a21e53720e4" - "3720e5376a21e63720e53720e6376a21e73720e63720e7376a21e83720e73720e8376a21e93720e83720e9376a21ea" - "3720e93720ea376a21eb3720ea3720eb376a21ec3720eb3720ec376a21ed3720ec3720ed376a21ee3720ed3720ee37" - "6a21ef3720ee3720ef376a21f03720ef3720f0376a21f13720f03720f1376a21f23720f13720f2376a21f33720f237" - "20f3376a21f43720f33720f4376a21f53720f43720f5376a21f63720f53720f6376a21f73720f63720f7376a21f837" - "20f73720f8376a21f93720f83720f9376a21fa3720f93720fa376a21fb3720fa3720fb376a21fc3720fb3720fc376a" - "21fd3720fc3720fd376a21fe3720fd3720fe376a21ff3720fe3720ff376a21803820ff372080386a21813820803820" - "81386a2182382081382082386a2183382082382083386a2184382083382084386a2185382084382085386a21863820" - "85382086386a2187382086382087386a2188382087382088386a2189382088382089386a218a38208938208a386a21" - "8b38208a38208b386a218c38208b38208c386a218d38208c38208d386a218e38208d38208e386a218f38208e38208f" - "386a219038208f382090386a2191382090382091386a2192382091382092386a2193382092382093386a2194382093" - "382094386a2195382094382095386a2196382095382096386a2197382096382097386a2198382097382098386a2199" - "382098382099386a219a38209938209a386a219b38209a38209b386a219c38209b38209c386a219d38209c38209d38" - "6a219e38209d38209e386a219f38209e38209f386a21a038209f3820a0386a21a13820a03820a1386a21a23820a138" - "20a2386a21a33820a23820a3386a21a43820a33820a4386a21a53820a43820a5386a21a63820a53820a6386a21a738" - "20a63820a7386a21a83820a73820a8386a21a93820a83820a9386a21aa3820a93820aa386a21ab3820aa3820ab386a" - "21ac3820ab3820ac386a21ad3820ac3820ad386a21ae3820ad3820ae386a21af3820ae3820af386a21b03820af3820" - "b0386a21b13820b03820b1386a21b23820b13820b2386a21b33820b23820b3386a21b43820b33820b4386a21b53820" - "b43820b5386a21b63820b53820b6386a21b73820b63820b7386a21b83820b73820b8386a21b93820b83820b9386a21" - "ba3820b93820ba386a21bb3820ba3820bb386a21bc3820bb3820bc386a21bd3820bc3820bd386a21be3820bd3820be" - "386a21bf3820be3820bf386a21c03820bf3820c0386a21c13820c03820c1386a21c23820c13820c2386a21c33820c2" - "3820c3386a21c43820c33820c4386a21c53820c43820c5386a21c63820c53820c6386a21c73820c63820c7386a21c8" - "3820c73820c8386a21c93820c83820c9386a21ca3820c93820ca386a21cb3820ca3820cb386a21cc3820cb3820cc38" - "6a21cd3820cc3820cd386a21ce3820cd3820ce386a21cf3820ce3820cf386a21d03820cf3820d0386a21d13820d038" - "20d1386a21d23820d13820d2386a21d33820d23820d3386a21d43820d33820d4386a21d53820d43820d5386a21d638" - "20d53820d6386a21d73820d63820d7386a21d83820d73820d8386a21d93820d83820d9386a21da3820d93820da386a" - "21db3820da3820db386a21dc3820db3820dc386a21dd3820dc3820dd386a21de3820dd3820de386a21df3820de3820" - "df386a21e03820df3820e0386a21e13820e03820e1386a21e23820e13820e2386a21e33820e23820e3386a21e43820" - "e33820e4386a21e53820e43820e5386a21e63820e53820e6386a21e73820e63820e7386a21e83820e73820e8386a21" - "e93820e83820e9386a21ea3820e93820ea386a21eb3820ea3820eb386a21ec3820eb3820ec386a21ed3820ec3820ed" - "386a21ee3820ed3820ee386a21ef3820ee3820ef386a21f03820ef3820f0386a21f13820f03820f1386a21f23820f1" - "3820f2386a21f33820f23820f3386a21f43820f33820f4386a21f53820f43820f5386a21f63820f53820f6386a21f7" - "3820f63820f7386a21f83820f73820f8386a21f93820f83820f9386a21fa3820f93820fa386a21fb3820fa3820fb38" - "6a21fc3820fb3820fc386a21fd3820fc3820fd386a21fe3820fd3820fe386a21ff3820fe3820ff386a21803920ff38" - "2080396a2181392080392081396a2182392081392082396a2183392082392083396a2184392083392084396a218539" - "2084392085396a2186392085392086396a2187392086392087396a2188392087392088396a2189392088392089396a" - "218a39208939208a396a218b39208a39208b396a218c39208b39208c396a218d39208c39208d396a218e39208d3920" - "8e396a218f39208e39208f396a219039208f392090396a2191392090392091396a2192392091392092396a21933920" - "92392093396a2194392093392094396a2195392094392095396a2196392095392096396a2197392096392097396a21" - "98392097392098396a2199392098392099396a219a39209939209a396a219b39209a39209b396a219c39209b39209c" - "396a219d39209c39209d396a219e39209d39209e396a219f39209e39209f396a21a039209f3920a0396a21a13920a0" - "3920a1396a21a23920a13920a2396a21a33920a23920a3396a21a43920a33920a4396a21a53920a43920a5396a21a6" - "3920a53920a6396a21a73920a63920a7396a21a83920a73920a8396a21a93920a83920a9396a21aa3920a93920aa39" - "6a21ab3920aa3920ab396a21ac3920ab3920ac396a21ad3920ac3920ad396a21ae3920ad3920ae396a21af3920ae39" - "20af396a21b03920af3920b0396a21b13920b03920b1396a21b23920b13920b2396a21b33920b23920b3396a21b439" - "20b33920b4396a21b53920b43920b5396a21b63920b53920b6396a21b73920b63920b7396a21b83920b73920b8396a" - "21b93920b83920b9396a21ba3920b93920ba396a21bb3920ba3920bb396a21bc3920bb3920bc396a21bd3920bc3920" - "bd396a21be3920bd3920be396a21bf3920be3920bf396a21c03920bf3920c0396a21c13920c03920c1396a21c23920" - "c13920c2396a21c33920c23920c3396a21c43920c33920c4396a21c53920c43920c5396a21c63920c53920c6396a21" - "c73920c63920c7396a21c83920c73920c8396a21c93920c83920c9396a21ca3920c93920ca396a21cb3920ca3920cb" - "396a21cc3920cb3920cc396a21cd3920cc3920cd396a21ce3920cd3920ce396a21cf3920ce3920cf396a21d03920cf" - "3920d0396a21d13920d03920d1396a21d23920d13920d2396a21d33920d23920d3396a21d43920d33920d4396a21d5" - "3920d43920d5396a21d63920d53920d6396a21d73920d63920d7396a21d83920d73920d8396a21d93920d83920d939" - "6a21da3920d93920da396a21db3920da3920db396a21dc3920db3920dc396a21dd3920dc3920dd396a21de3920dd39" - "20de396a21df3920de3920df396a21e03920df3920e0396a21e13920e03920e1396a21e23920e13920e2396a21e339" - "20e23920e3396a21e43920e33920e4396a21e53920e43920e5396a21e63920e53920e6396a21e73920e63920e7396a" - "21e83920e73920e8396a21e93920e83920e9396a21ea3920e93920ea396a21eb3920ea3920eb396a21ec3920eb3920" - "ec396a21ed3920ec3920ed396a21ee3920ed3920ee396a21ef3920ee3920ef396a21f03920ef3920f0396a21f13920" - "f03920f1396a21f23920f13920f2396a21f33920f23920f3396a21f43920f33920f4396a21f53920f43920f5396a21" - "f63920f53920f6396a21f73920f63920f7396a21f83920f73920f8396a21f93920f83920f9396a21fa3920f93920fa" - "396a21fb3920fa3920fb396a21fc3920fb3920fc396a21fd3920fc3920fd396a21fe3920fd3920fe396a21ff3920fe" - "3920ff396a21803a20ff3920803a6a21813a20803a20813a6a21823a20813a20823a6a21833a20823a20833a6a2184" - "3a20833a20843a6a21853a20843a20853a6a21863a20853a20863a6a21873a20863a20873a6a21883a20873a20883a" - "6a21893a20883a20893a6a218a3a20893a208a3a6a218b3a208a3a208b3a6a218c3a208b3a208c3a6a218d3a208c3a" - "208d3a6a218e3a208d3a208e3a6a218f3a208e3a208f3a6a21903a208f3a20903a6a21913a20903a20913a6a21923a" - "20913a20923a6a21933a20923a20933a6a21943a20933a20943a6a21953a20943a20953a6a21963a20953a20963a6a" - "21973a20963a20973a6a21983a20973a20983a6a21993a20983a20993a6a219a3a20993a209a3a6a219b3a209a3a20" - "9b3a6a219c3a209b3a209c3a6a219d3a209c3a209d3a6a219e3a209d3a209e3a6a219f3a209e3a209f3a6a21a03a20" - "9f3a20a03a6a21a13a20a03a20a13a6a21a23a20a13a20a23a6a21a33a20a23a20a33a6a21a43a20a33a20a43a6a21" - "a53a20a43a20a53a6a21a63a20a53a20a63a6a21a73a20a63a20a73a6a21a83a20a73a20a83a6a21a93a20a83a20a9" - "3a6a21aa3a20a93a20aa3a6a21ab3a20aa3a20ab3a6a21ac3a20ab3a20ac3a6a21ad3a20ac3a20ad3a6a21ae3a20ad" - "3a20ae3a6a21af3a20ae3a20af3a6a21b03a20af3a20b03a6a21b13a20b03a20b13a6a21b23a20b13a20b23a6a21b3" - "3a20b23a20b33a6a21b43a20b33a20b43a6a21b53a20b43a20b53a6a21b63a20b53a20b63a6a21b73a20b63a20b73a" - "6a21b83a20b73a20b83a6a21b93a20b83a20b93a6a21ba3a20b93a20ba3a6a21bb3a20ba3a20bb3a6a21bc3a20bb3a" - "20bc3a6a21bd3a20bc3a20bd3a6a21be3a20bd3a20be3a6a21bf3a20be3a20bf3a6a21c03a20bf3a20c03a6a21c13a" - "20c03a20c13a6a21c23a20c13a20c23a6a21c33a20c23a20c33a6a21c43a20c33a20c43a6a21c53a20c43a20c53a6a" - "21c63a20c53a20c63a6a21c73a20c63a20c73a6a21c83a20c73a20c83a6a21c93a20c83a20c93a6a21ca3a20c93a20" - "ca3a6a21cb3a20ca3a20cb3a6a21cc3a20cb3a20cc3a6a21cd3a20cc3a20cd3a6a21ce3a20cd3a20ce3a6a21cf3a20" - "ce3a20cf3a6a21d03a20cf3a20d03a6a21d13a20d03a20d13a6a21d23a20d13a20d23a6a21d33a20d23a20d33a6a21" - "d43a20d33a20d43a6a21d53a20d43a20d53a6a21d63a20d53a20d63a6a21d73a20d63a20d73a6a21d83a20d73a20d8" - "3a6a21d93a20d83a20d93a6a21da3a20d93a20da3a6a21db3a20da3a20db3a6a21dc3a20db3a20dc3a6a21dd3a20dc" - "3a20dd3a6a21de3a20dd3a20de3a6a21df3a20de3a20df3a6a21e03a20df3a20e03a6a21e13a20e03a20e13a6a21e2" - "3a20e13a20e23a6a21e33a20e23a20e33a6a21e43a20e33a20e43a6a21e53a20e43a20e53a6a21e63a20e53a20e63a" - "6a21e73a20e63a20e73a6a21e83a20e73a20e83a6a21e93a20e83a20e93a6a21ea3a20e93a20ea3a6a21eb3a20ea3a" - "20eb3a6a21ec3a20eb3a20ec3a6a21ed3a20ec3a20ed3a6a21ee3a20ed3a20ee3a6a21ef3a20ee3a20ef3a6a21f03a" - "20ef3a20f03a6a21f13a20f03a20f13a6a21f23a20f13a20f23a6a21f33a20f23a20f33a6a21f43a20f33a20f43a6a" - "21f53a20f43a20f53a6a21f63a20f53a20f63a6a21f73a20f63a20f73a6a21f83a20f73a20f83a6a21f93a20f83a20" - "f93a6a21fa3a20f93a20fa3a6a21fb3a20fa3a20fb3a6a21fc3a20fb3a20fc3a6a21fd3a20fc3a20fd3a6a21fe3a20" - "fd3a20fe3a6a21ff3a20fe3a20ff3a6a21803b20ff3a20803b6a21813b20803b20813b6a21823b20813b20823b6a21" - "833b20823b20833b6a21843b20833b20843b6a21853b20843b20853b6a21863b20853b20863b6a21873b20863b2087" - "3b6a21883b20873b20883b6a21893b20883b20893b6a218a3b20893b208a3b6a218b3b208a3b208b3b6a218c3b208b" - "3b208c3b6a218d3b208c3b208d3b6a218e3b208d3b208e3b6a218f3b208e3b208f3b6a21903b208f3b20903b6a2191" - "3b20903b20913b6a21923b20913b20923b6a21933b20923b20933b6a21943b20933b20943b6a21953b20943b20953b" - "6a21963b20953b20963b6a21973b20963b20973b6a21983b20973b20983b6a21993b20983b20993b6a219a3b20993b" - "209a3b6a219b3b209a3b209b3b6a219c3b209b3b209c3b6a219d3b209c3b209d3b6a219e3b209d3b209e3b6a219f3b" - "209e3b209f3b6a21a03b209f3b20a03b6a21a13b20a03b20a13b6a21a23b20a13b20a23b6a21a33b20a23b20a33b6a" - "21a43b20a33b20a43b6a21a53b20a43b20a53b6a21a63b20a53b20a63b6a21a73b20a63b20a73b6a21a83b20a73b20" - "a83b6a21a93b20a83b20a93b6a21aa3b20a93b20aa3b6a21ab3b20aa3b20ab3b6a21ac3b20ab3b20ac3b6a21ad3b20" - "ac3b20ad3b6a21ae3b20ad3b20ae3b6a21af3b20ae3b20af3b6a21b03b20af3b20b03b6a21b13b20b03b20b13b6a21" - "b23b20b13b20b23b6a21b33b20b23b20b33b6a21b43b20b33b20b43b6a21b53b20b43b20b53b6a21b63b20b53b20b6" - "3b6a21b73b20b63b20b73b6a21b83b20b73b20b83b6a21b93b20b83b20b93b6a21ba3b20b93b20ba3b6a21bb3b20ba" - "3b20bb3b6a21bc3b20bb3b20bc3b6a21bd3b20bc3b20bd3b6a21be3b20bd3b20be3b6a21bf3b20be3b20bf3b6a21c0" - "3b20bf3b20c03b6a21c13b20c03b20c13b6a21c23b20c13b20c23b6a21c33b20c23b20c33b6a21c43b20c33b20c43b" - "6a21c53b20c43b20c53b6a21c63b20c53b20c63b6a21c73b20c63b20c73b6a21c83b20c73b20c83b6a21c93b20c83b" - "20c93b6a21ca3b20c93b20ca3b6a21cb3b20ca3b20cb3b6a21cc3b20cb3b20cc3b6a21cd3b20cc3b20cd3b6a21ce3b" - "20cd3b20ce3b6a21cf3b20ce3b20cf3b6a21d03b20cf3b20d03b6a21d13b20d03b20d13b6a21d23b20d13b20d23b6a" - "21d33b20d23b20d33b6a21d43b20d33b20d43b6a21d53b20d43b20d53b6a21d63b20d53b20d63b6a21d73b20d63b20" - "d73b6a21d83b20d73b20d83b6a21d93b20d83b20d93b6a21da3b20d93b20da3b6a21db3b20da3b20db3b6a21dc3b20" - "db3b20dc3b6a21dd3b20dc3b20dd3b6a21de3b20dd3b20de3b6a21df3b20de3b20df3b6a21e03b20df3b20e03b6a21" - "e13b20e03b20e13b6a21e23b20e13b20e23b6a21e33b20e23b20e33b6a21e43b20e33b20e43b6a21e53b20e43b20e5" - "3b6a21e63b20e53b20e63b6a21e73b20e63b20e73b6a21e83b20e73b20e83b6a21e93b20e83b20e93b6a21ea3b20e9" - "3b20ea3b6a21eb3b20ea3b20eb3b6a21ec3b20eb3b20ec3b6a21ed3b20ec3b20ed3b6a21ee3b20ed3b20ee3b6a21ef" - "3b20ee3b20ef3b6a21f03b20ef3b20f03b6a21f13b20f03b20f13b6a21f23b20f13b20f23b6a21f33b20f23b20f33b" - "6a21f43b20f33b20f43b6a21f53b20f43b20f53b6a21f63b20f53b20f63b6a21f73b20f63b20f73b6a21f83b20f73b" - "20f83b6a21f93b20f83b20f93b6a21fa3b20f93b20fa3b6a21fb3b20fa3b20fb3b6a21fc3b20fb3b20fc3b6a21fd3b" - "20fc3b20fd3b6a21fe3b20fd3b20fe3b6a21ff3b20fe3b20ff3b6a21803c20ff3b20803c6a21813c20803c20813c6a" - "21823c20813c20823c6a21833c20823c20833c6a21843c20833c20843c6a21853c20843c20853c6a21863c20853c20" - "863c6a21873c20863c20873c6a21883c20873c20883c6a21893c20883c20893c6a218a3c20893c208a3c6a218b3c20" - "8a3c208b3c6a218c3c208b3c208c3c6a218d3c208c3c208d3c6a218e3c208d3c208e3c6a218f3c208e3c208f3c6a21" - "903c208f3c20903c6a21913c20903c20913c6a21923c20913c20923c6a21933c20923c20933c6a21943c20933c2094" - "3c6a21953c20943c20953c6a21963c20953c20963c6a21973c20963c20973c6a21983c20973c20983c6a21993c2098" - "3c20993c6a219a3c20993c209a3c6a219b3c209a3c209b3c6a219c3c209b3c209c3c6a219d3c209c3c209d3c6a219e" - "3c209d3c209e3c6a219f3c209e3c209f3c6a21a03c209f3c20a03c6a21a13c20a03c20a13c6a21a23c20a13c20a23c" - "6a21a33c20a23c20a33c6a21a43c20a33c20a43c6a21a53c20a43c20a53c6a21a63c20a53c20a63c6a21a73c20a63c" - "20a73c6a21a83c20a73c20a83c6a21a93c20a83c20a93c6a21aa3c20a93c20aa3c6a21ab3c20aa3c20ab3c6a21ac3c" - "20ab3c20ac3c6a21ad3c20ac3c20ad3c6a21ae3c20ad3c20ae3c6a21af3c20ae3c20af3c6a21b03c20af3c20b03c6a" - "21b13c20b03c20b13c6a21b23c20b13c20b23c6a21b33c20b23c20b33c6a21b43c20b33c20b43c6a21b53c20b43c20" - "b53c6a21b63c20b53c20b63c6a21b73c20b63c20b73c6a21b83c20b73c20b83c6a21b93c20b83c20b93c6a21ba3c20" - "b93c20ba3c6a21bb3c20ba3c20bb3c6a21bc3c20bb3c20bc3c6a21bd3c20bc3c20bd3c6a21be3c20bd3c20be3c6a21" - "bf3c20be3c20bf3c6a21c03c20bf3c20c03c6a21c13c20c03c20c13c6a21c23c20c13c20c23c6a21c33c20c23c20c3" - "3c6a21c43c20c33c20c43c6a21c53c20c43c20c53c6a21c63c20c53c20c63c6a21c73c20c63c20c73c6a21c83c20c7" - "3c20c83c6a21c93c20c83c20c93c6a21ca3c20c93c20ca3c6a21cb3c20ca3c20cb3c6a21cc3c20cb3c20cc3c6a21cd" - "3c20cc3c20cd3c6a21ce3c20cd3c20ce3c6a21cf3c20ce3c20cf3c6a21d03c20cf3c20d03c6a21d13c20d03c20d13c" - "6a21d23c20d13c20d23c6a21d33c20d23c20d33c6a21d43c20d33c20d43c6a21d53c20d43c20d53c6a21d63c20d53c" - "20d63c6a21d73c20d63c20d73c6a21d83c20d73c20d83c6a21d93c20d83c20d93c6a21da3c20d93c20da3c6a21db3c" - "20da3c20db3c6a21dc3c20db3c20dc3c6a21dd3c20dc3c20dd3c6a21de3c20dd3c20de3c6a21df3c20de3c20df3c6a" - "21e03c20df3c20e03c6a21e13c20e03c20e13c6a21e23c20e13c20e23c6a21e33c20e23c20e33c6a21e43c20e33c20" - "e43c6a21e53c20e43c20e53c6a21e63c20e53c20e63c6a21e73c20e63c20e73c6a21e83c20e73c20e83c6a21e93c20" - "e83c20e93c6a21ea3c20e93c20ea3c6a21eb3c20ea3c20eb3c6a21ec3c20eb3c20ec3c6a21ed3c20ec3c20ed3c6a21" - "ee3c20ed3c20ee3c6a21ef3c20ee3c20ef3c6a21f03c20ef3c20f03c6a21f13c20f03c20f13c6a21f23c20f13c20f2" - "3c6a21f33c20f23c20f33c6a21f43c20f33c20f43c6a21f53c20f43c20f53c6a21f63c20f53c20f63c6a21f73c20f6" - "3c20f73c6a21f83c20f73c20f83c6a21f93c20f83c20f93c6a21fa3c20f93c20fa3c6a21fb3c20fa3c20fb3c6a21fc" - "3c20fb3c20fc3c6a21fd3c20fc3c20fd3c6a21fe3c20fd3c20fe3c6a21ff3c20fe3c20ff3c6a21803d20ff3c20803d" - "6a21813d20803d20813d6a21823d20813d20823d6a21833d20823d20833d6a21843d20833d20843d6a21853d20843d" - "20853d6a21863d20853d20863d6a21873d20863d20873d6a21883d20873d20883d6a21893d20883d20893d6a218a3d" - "20893d208a3d6a218b3d208a3d208b3d6a218c3d208b3d208c3d6a218d3d208c3d208d3d6a218e3d208d3d208e3d6a" - "218f3d208e3d208f3d6a21903d208f3d20903d6a21913d20903d20913d6a21923d20913d20923d6a21933d20923d20" - "933d6a21943d20933d20943d6a21953d20943d20953d6a21963d20953d20963d6a21973d20963d20973d6a21983d20" - "973d20983d6a21993d20983d20993d6a219a3d20993d209a3d6a219b3d209a3d209b3d6a219c3d209b3d209c3d6a21" - "9d3d209c3d209d3d6a219e3d209d3d209e3d6a219f3d209e3d209f3d6a21a03d209f3d20a03d6a21a13d20a03d20a1" - "3d6a21a23d20a13d20a23d6a21a33d20a23d20a33d6a21a43d20a33d20a43d6a21a53d20a43d20a53d6a21a63d20a5" - "3d20a63d6a21a73d20a63d20a73d6a21a83d20a73d20a83d6a21a93d20a83d20a93d6a21aa3d20a93d20aa3d6a21ab" - "3d20aa3d20ab3d6a21ac3d20ab3d20ac3d6a21ad3d20ac3d20ad3d6a21ae3d20ad3d20ae3d6a21af3d20ae3d20af3d" - "6a21b03d20af3d20b03d6a21b13d20b03d20b13d6a21b23d20b13d20b23d6a21b33d20b23d20b33d6a21b43d20b33d" - "20b43d6a21b53d20b43d20b53d6a21b63d20b53d20b63d6a21b73d20b63d20b73d6a21b83d20b73d20b83d6a21b93d" - "20b83d20b93d6a21ba3d20b93d20ba3d6a21bb3d20ba3d20bb3d6a21bc3d20bb3d20bc3d6a21bd3d20bc3d20bd3d6a" - "21be3d20bd3d20be3d6a21bf3d20be3d20bf3d6a21c03d20bf3d20c03d6a21c13d20c03d20c13d6a21c23d20c13d20" - "c23d6a21c33d20c23d20c33d6a21c43d20c33d20c43d6a21c53d20c43d20c53d6a21c63d20c53d20c63d6a21c73d20" - "c63d20c73d6a21c83d20c73d20c83d6a21c93d20c83d20c93d6a21ca3d20c93d20ca3d6a21cb3d20ca3d20cb3d6a21" - "cc3d20cb3d20cc3d6a21cd3d20cc3d20cd3d6a21ce3d20cd3d20ce3d6a21cf3d20ce3d20cf3d6a21d03d20cf3d20d0" - "3d6a21d13d20d03d20d13d6a21d23d20d13d20d23d6a21d33d20d23d20d33d6a21d43d20d33d20d43d6a21d53d20d4" - "3d20d53d6a21d63d20d53d20d63d6a21d73d20d63d20d73d6a21d83d20d73d20d83d6a21d93d20d83d20d93d6a21da" - "3d20d93d20da3d6a21db3d20da3d20db3d6a21dc3d20db3d20dc3d6a21dd3d20dc3d20dd3d6a21de3d20dd3d20de3d" - "6a21df3d20de3d20df3d6a21e03d20df3d20e03d6a21e13d20e03d20e13d6a21e23d20e13d20e23d6a21e33d20e23d" - "20e33d6a21e43d20e33d20e43d6a21e53d20e43d20e53d6a21e63d20e53d20e63d6a21e73d20e63d20e73d6a21e83d" - "20e73d20e83d6a21e93d20e83d20e93d6a21ea3d20e93d20ea3d6a21eb3d20ea3d20eb3d6a21ec3d20eb3d20ec3d6a" - "21ed3d20ec3d20ed3d6a21ee3d20ed3d20ee3d6a21ef3d20ee3d20ef3d6a21f03d20ef3d20f03d6a21f13d20f03d20" - "f13d6a21f23d20f13d20f23d6a21f33d20f23d20f33d6a21f43d20f33d20f43d6a21f53d20f43d20f53d6a21f63d20" - "f53d20f63d6a21f73d20f63d20f73d6a21f83d20f73d20f83d6a21f93d20f83d20f93d6a21fa3d20f93d20fa3d6a21" - "fb3d20fa3d20fb3d6a21fc3d20fb3d20fc3d6a21fd3d20fc3d20fd3d6a21fe3d20fd3d20fe3d6a21ff3d20fe3d20ff" - "3d6a21803e20ff3d20803e6a21813e20803e20813e6a21823e20813e20823e6a21833e20823e20833e6a21843e2083" - "3e20843e6a21853e20843e20853e6a21863e20853e20863e6a21873e20863e20873e6a21883e20873e20883e6a2189" - "3e20883e20893e6a218a3e20893e208a3e6a218b3e208a3e208b3e6a218c3e208b3e208c3e6a218d3e208c3e208d3e" - "6a218e3e208d3e208e3e6a218f3e208e3e208f3e6a21903e208f3e20903e6a21913e20903e20913e6a21923e20913e" - "20923e6a21933e20923e20933e6a21943e20933e20943e6a21953e20943e20953e6a21963e20953e20963e6a21973e" - "20963e20973e6a21983e20973e20983e6a21993e20983e20993e6a219a3e20993e209a3e6a219b3e209a3e209b3e6a" - "219c3e209b3e209c3e6a219d3e209c3e209d3e6a219e3e209d3e209e3e6a219f3e209e3e209f3e6a21a03e209f3e20" - "a03e6a21a13e20a03e20a13e6a21a23e20a13e20a23e6a21a33e20a23e20a33e6a21a43e20a33e20a43e6a21a53e20" - "a43e20a53e6a21a63e20a53e20a63e6a21a73e20a63e20a73e6a21a83e20a73e20a83e6a21a93e20a83e20a93e6a21" - "aa3e20a93e20aa3e6a21ab3e20aa3e20ab3e6a21ac3e20ab3e20ac3e6a21ad3e20ac3e20ad3e6a21ae3e20ad3e20ae" - "3e6a21af3e20ae3e20af3e6a21b03e20af3e20b03e6a21b13e20b03e20b13e6a21b23e20b13e20b23e6a21b33e20b2" - "3e20b33e6a21b43e20b33e20b43e6a21b53e20b43e20b53e6a21b63e20b53e20b63e6a21b73e20b63e20b73e6a21b8" - "3e20b73e20b83e6a21b93e20b83e20b93e6a21ba3e20b93e20ba3e6a21bb3e20ba3e20bb3e6a21bc3e20bb3e20bc3e" - "6a21bd3e20bc3e20bd3e6a21be3e20bd3e20be3e6a21bf3e20be3e20bf3e6a21c03e20bf3e20c03e6a21c13e20c03e" - "20c13e6a21c23e20c13e20c23e6a21c33e20c23e20c33e6a21c43e20c33e20c43e6a21c53e20c43e20c53e6a21c63e" - "20c53e20c63e6a21c73e20c63e20c73e6a21c83e20c73e20c83e6a21c93e20c83e20c93e6a21ca3e20c93e20ca3e6a" - "21cb3e20ca3e20cb3e6a21cc3e20cb3e20cc3e6a21cd3e20cc3e20cd3e6a21ce3e20cd3e20ce3e6a21cf3e20ce3e20" - "cf3e6a21d03e20cf3e20d03e6a21d13e20d03e20d13e6a21d23e20d13e20d23e6a21d33e20d23e20d33e6a21d43e20" - "d33e20d43e6a21d53e20d43e20d53e6a21d63e20d53e20d63e6a21d73e20d63e20d73e6a21d83e20d73e20d83e6a21" - "d93e20d83e20d93e6a21da3e20d93e20da3e6a21db3e20da3e20db3e6a21dc3e20db3e20dc3e6a21dd3e20dc3e20dd" - "3e6a21de3e20dd3e20de3e6a21df3e20de3e20df3e6a21e03e20df3e20e03e6a21e13e20e03e20e13e6a21e23e20e1" - "3e20e23e6a21e33e20e23e20e33e6a21e43e20e33e20e43e6a21e53e20e43e20e53e6a21e63e20e53e20e63e6a21e7" - "3e20e63e20e73e6a21e83e20e73e20e83e6a21e93e20e83e20e93e6a21ea3e20e93e20ea3e6a21eb3e20ea3e20eb3e" - "6a21ec3e20eb3e20ec3e6a21ed3e20ec3e20ed3e6a21ee3e20ed3e20ee3e6a21ef3e20ee3e20ef3e6a21f03e20ef3e" - "20f03e6a21f13e20f03e20f13e6a21f23e20f13e20f23e6a21f33e20f23e20f33e6a21f43e20f33e20f43e6a21f53e" - "20f43e20f53e6a21f63e20f53e20f63e6a21f73e20f63e20f73e6a21f83e20f73e20f83e6a21f93e20f83e20f93e6a" - "21fa3e20f93e20fa3e6a21fb3e20fa3e20fb3e6a21fc3e20fb3e20fc3e6a21fd3e20fc3e20fd3e6a21fe3e20fd3e20" - "fe3e6a21ff3e20fe3e20ff3e6a21803f20ff3e20803f6a21813f20803f20813f6a21823f20813f20823f6a21833f20" - "823f20833f6a21843f20833f20843f6a21853f20843f20853f6a21863f20853f20863f6a21873f20863f20873f6a21" - "883f20873f20883f6a21893f20883f20893f6a218a3f20893f208a3f6a218b3f208a3f208b3f6a218c3f208b3f208c" - "3f6a218d3f208c3f208d3f6a218e3f208d3f208e3f6a218f3f208e3f208f3f6a21903f208f3f20903f6a21913f2090" - "3f20913f6a21923f20913f20923f6a21933f20923f20933f6a21943f20933f20943f6a21953f20943f20953f6a2196" - "3f20953f20963f6a21973f20963f20973f6a21983f20973f20983f6a21993f20983f20993f6a219a3f20993f209a3f" - "6a219b3f209a3f209b3f6a219c3f209b3f209c3f6a219d3f209c3f209d3f6a219e3f209d3f209e3f6a219f3f209e3f" - "209f3f6a21a03f209f3f20a03f6a21a13f20a03f20a13f6a21a23f20a13f20a23f6a21a33f20a23f20a33f6a21a43f" - "20a33f20a43f6a21a53f20a43f20a53f6a21a63f20a53f20a63f6a21a73f20a63f20a73f6a21a83f20a73f20a83f6a" - "21a93f20a83f20a93f6a21aa3f20a93f20aa3f6a21ab3f20aa3f20ab3f6a21ac3f20ab3f20ac3f6a21ad3f20ac3f20" - "ad3f6a21ae3f20ad3f20ae3f6a21af3f20ae3f20af3f6a21b03f20af3f20b03f6a21b13f20b03f20b13f6a21b23f20" - "b13f20b23f6a21b33f20b23f20b33f6a21b43f20b33f20b43f6a21b53f20b43f20b53f6a21b63f20b53f20b63f6a21" - "b73f20b63f20b73f6a21b83f20b73f20b83f6a21b93f20b83f20b93f6a21ba3f20b93f20ba3f6a21bb3f20ba3f20bb" - "3f6a21bc3f20bb3f20bc3f6a21bd3f20bc3f20bd3f6a21be3f20bd3f20be3f6a21bf3f20be3f20bf3f6a21c03f20bf" - "3f20c03f6a21c13f20c03f20c13f6a21c23f20c13f20c23f6a21c33f20c23f20c33f6a21c43f20c33f20c43f6a21c5" - "3f20c43f20c53f6a21c63f20c53f20c63f6a21c73f20c63f20c73f6a21c83f20c73f20c83f6a21c93f20c83f20c93f" - "6a21ca3f20c93f20ca3f6a21cb3f20ca3f20cb3f6a21cc3f20cb3f20cc3f6a21cd3f20cc3f20cd3f6a21ce3f20cd3f" - "20ce3f6a21cf3f20ce3f20cf3f6a21d03f20cf3f20d03f6a21d13f20d03f20d13f6a21d23f20d13f20d23f6a21d33f" - "20d23f20d33f6a21d43f20d33f20d43f6a21d53f20d43f20d53f6a21d63f20d53f20d63f6a21d73f20d63f20d73f6a" - "21d83f20d73f20d83f6a21d93f20d83f20d93f6a21da3f20d93f20da3f6a21db3f20da3f20db3f6a21dc3f20db3f20" - "dc3f6a21dd3f20dc3f20dd3f6a21de3f20dd3f20de3f6a21df3f20de3f20df3f6a21e03f20df3f20e03f6a21e13f20" - "e03f20e13f6a21e23f20e13f20e23f6a21e33f20e23f20e33f6a21e43f20e33f20e43f6a21e53f20e43f20e53f6a21" - "e63f20e53f20e63f6a21e73f20e63f20e73f6a21e83f20e73f20e83f6a21e93f20e83f20e93f6a21ea3f20e93f20ea" - "3f6a21eb3f20ea3f20eb3f6a21ec3f20eb3f20ec3f6a21ed3f20ec3f20ed3f6a21ee3f20ed3f20ee3f6a21ef3f20ee" - "3f20ef3f6a21f03f20ef3f20f03f6a21f13f20f03f20f13f6a21f23f20f13f20f23f6a21f33f20f23f20f33f6a21f4" - "3f20f33f20f43f6a21f53f20f43f20f53f6a21f63f20f53f20f63f6a21f73f20f63f20f73f6a21f83f20f73f20f83f" - "6a21f93f20f83f20f93f6a21fa3f20f93f20fa3f6a21fb3f20fa3f20fb3f6a21fc3f20fb3f20fc3f6a21fd3f20fc3f" - "20fd3f6a21fe3f20fd3f20fe3f6a21ff3f20fe3f20ff3f6a21804020ff3f2080406a2181402080402081406a218240" - "2081402082406a2183402082402083406a2184402083402084406a2185402084402085406a2186402085402086406a" - "2187402086402087406a2188402087402088406a2189402088402089406a218a40208940208a406a218b40208a4020" - "8b406a218c40208b40208c406a218d40208c40208d406a218e40208d40208e406a218f40208e40208f406a21904020" - "8f402090406a2191402090402091406a2192402091402092406a2193402092402093406a2194402093402094406a21" - "95402094402095406a2196402095402096406a2197402096402097406a2198402097402098406a2199402098402099" - "406a219a40209940209a406a219b40209a40209b406a219c40209b40209c406a219d40209c40209d406a219e40209d" - "40209e406a219f40209e40209f406a21a040209f4020a0406a21a14020a04020a1406a21a24020a14020a2406a21a3" - "4020a24020a3406a21a44020a34020a4406a21a54020a44020a5406a21a64020a54020a6406a21a74020a64020a740" - "6a21a84020a74020a8406a21a94020a84020a9406a21aa4020a94020aa406a21ab4020aa4020ab406a21ac4020ab40" - "20ac406a21ad4020ac4020ad406a21ae4020ad4020ae406a21af4020ae4020af406a21b04020af4020b0406a21b140" - "20b04020b1406a21b24020b14020b2406a21b34020b24020b3406a21b44020b34020b4406a21b54020b44020b5406a" - "21b64020b54020b6406a21b74020b64020b7406a21b84020b74020b8406a21b94020b84020b9406a21ba4020b94020" - "ba406a21bb4020ba4020bb406a21bc4020bb4020bc406a21bd4020bc4020bd406a21be4020bd4020be406a21bf4020" - "be4020bf406a21c04020bf4020c0406a21c14020c04020c1406a21c24020c14020c2406a21c34020c24020c3406a21" - "c44020c34020c4406a21c54020c44020c5406a21c64020c54020c6406a21c74020c64020c7406a21c84020c74020c8" - "406a21c94020c84020c9406a21ca4020c94020ca406a21cb4020ca4020cb406a21cc4020cb4020cc406a21cd4020cc" - "4020cd406a21ce4020cd4020ce406a21cf4020ce4020cf406a21d04020cf4020d0406a21d14020d04020d1406a21d2" - "4020d14020d2406a21d34020d24020d3406a21d44020d34020d4406a21d54020d44020d5406a21d64020d54020d640" - "6a21d74020d64020d7406a21d84020d74020d8406a21d94020d84020d9406a21da4020d94020da406a21db4020da40" - "20db406a21dc4020db4020dc406a21dd4020dc4020dd406a21de4020dd4020de406a21df4020de4020df406a21e040" - "20df4020e0406a21e14020e04020e1406a21e24020e14020e2406a21e34020e24020e3406a21e44020e34020e4406a" - "21e54020e44020e5406a21e64020e54020e6406a21e74020e64020e7406a21e84020e74020e8406a21e94020e84020" - "e9406a21ea4020e94020ea406a21eb4020ea4020eb406a21ec4020eb4020ec406a21ed4020ec4020ed406a21ee4020" - "ed4020ee406a21ef4020ee4020ef406a21f04020ef4020f0406a21f14020f04020f1406a21f24020f14020f2406a21" - "f34020f24020f3406a21f44020f34020f4406a21f54020f44020f5406a21f64020f54020f6406a21f74020f64020f7" - "406a21f84020f74020f8406a21f94020f84020f9406a21fa4020f94020fa406a21fb4020fa4020fb406a21fc4020fb" - "4020fc406a21fd4020fc4020fd406a21fe4020fd4020fe406a21ff4020fe4020ff406a21804120ff402080416a2181" - "412080412081416a2182412081412082416a2183412082412083416a2184412083412084416a218541208441208541" - "6a2186412085412086416a2187412086412087416a2188412087412088416a2189412088412089416a218a41208941" - "208a416a218b41208a41208b416a218c41208b41208c416a218d41208c41208d416a218e41208d41208e416a218f41" - "208e41208f416a219041208f412090416a2191412090412091416a2192412091412092416a2193412092412093416a" - "2194412093412094416a2195412094412095416a2196412095412096416a2197412096412097416a21984120974120" - "98416a2199412098412099416a219a41209941209a416a219b41209a41209b416a219c41209b41209c416a219d4120" - "9c41209d416a219e41209d41209e416a219f41209e41209f416a21a041209f4120a0416a21a14120a04120a1416a21" - "a24120a14120a2416a21a34120a24120a3416a21a44120a34120a4416a21a54120a44120a5416a21a64120a54120a6" - "416a21a74120a64120a7416a21a84120a74120a8416a21a94120a84120a9416a21aa4120a94120aa416a21ab4120aa" - "4120ab416a21ac4120ab4120ac416a21ad4120ac4120ad416a21ae4120ad4120ae416a21af4120ae4120af416a21b0" - "4120af4120b0416a21b14120b04120b1416a21b24120b14120b2416a21b34120b24120b3416a21b44120b34120b441" - "6a21b54120b44120b5416a21b64120b54120b6416a21b74120b64120b7416a21b84120b74120b8416a21b94120b841" - "20b9416a21ba4120b94120ba416a21bb4120ba4120bb416a21bc4120bb4120bc416a21bd4120bc4120bd416a21be41" - "20bd4120be416a21bf4120be4120bf416a21c04120bf4120c0416a21c14120c04120c1416a21c24120c14120c2416a" - "21c34120c24120c3416a21c44120c34120c4416a21c54120c44120c5416a21c64120c54120c6416a21c74120c64120" - "c7416a21c84120c74120c8416a21c94120c84120c9416a21ca4120c94120ca416a21cb4120ca4120cb416a21cc4120" - "cb4120cc416a21cd4120cc4120cd416a21ce4120cd4120ce416a21cf4120ce4120cf416a21d04120cf4120d0416a21" - "d14120d04120d1416a21d24120d14120d2416a21d34120d24120d3416a21d44120d34120d4416a21d54120d44120d5" - "416a21d64120d54120d6416a21d74120d64120d7416a21d84120d74120d8416a21d94120d84120d9416a21da4120d9" - "4120da416a21db4120da4120db416a21dc4120db4120dc416a21dd4120dc4120dd416a21de4120dd4120de416a21df" - "4120de4120df416a21e04120df4120e0416a21e14120e04120e1416a21e24120e14120e2416a21e34120e24120e341" - "6a21e44120e34120e4416a21e54120e44120e5416a21e64120e54120e6416a21e74120e64120e7416a21e84120e741" - "20e8416a21e94120e84120e9416a21ea4120e94120ea416a21eb4120ea4120eb416a21ec4120eb4120ec416a21ed41" - "20ec4120ed416a21ee4120ed4120ee416a21ef4120ee4120ef416a21f04120ef4120f0416a21f14120f04120f1416a" - "21f24120f14120f2416a21f34120f24120f3416a21f44120f34120f4416a21f54120f44120f5416a21f64120f54120" - "f6416a21f74120f64120f7416a21f84120f74120f8416a21f94120f84120f9416a21fa4120f94120fa416a21fb4120" - "fa4120fb416a21fc4120fb4120fc416a21fd4120fc4120fd416a21fe4120fd4120fe416a21ff4120fe4120ff416a21" - "804220ff412080426a2181422080422081426a2182422081422082426a2183422082422083426a2184422083422084" - "426a2185422084422085426a2186422085422086426a2187422086422087426a2188422087422088426a2189422088" - "422089426a218a42208942208a426a218b42208a42208b426a218c42208b42208c426a218d42208c42208d426a218e" - "42208d42208e426a218f42208e42208f426a219042208f422090426a2191422090422091426a219242209142209242" - "6a2193422092422093426a2194422093422094426a2195422094422095426a2196422095422096426a219742209642" - "2097426a2198422097422098426a2199422098422099426a219a42209942209a426a219b42209a42209b426a219c42" - "209b42209c426a219d42209c42209d426a219e42209d42209e426a219f42209e42209f426a21a042209f4220a0426a" - "21a14220a04220a1426a21a24220a14220a2426a21a34220a24220a3426a21a44220a34220a4426a21a54220a44220" - "a5426a21a64220a54220a6426a21a74220a64220a7426a21a84220a74220a8426a21a94220a84220a9426a21aa4220" - "a94220aa426a21ab4220aa4220ab426a21ac4220ab4220ac426a21ad4220ac4220ad426a21ae4220ad4220ae426a21" - "af4220ae4220af426a21b04220af4220b0426a21b14220b04220b1426a21b24220b14220b2426a21b34220b24220b3" - "426a21b44220b34220b4426a21b54220b44220b5426a21b64220b54220b6426a21b74220b64220b7426a21b84220b7" - "4220b8426a21b94220b84220b9426a21ba4220b94220ba426a21bb4220ba4220bb426a21bc4220bb4220bc426a21bd" - "4220bc4220bd426a21be4220bd4220be426a21bf4220be4220bf426a21c04220bf4220c0426a21c14220c04220c142" - "6a21c24220c14220c2426a21c34220c24220c3426a21c44220c34220c4426a21c54220c44220c5426a21c64220c542" - "20c6426a21c74220c64220c7426a21c84220c74220c8426a21c94220c84220c9426a21ca4220c94220ca426a21cb42" - "20ca4220cb426a21cc4220cb4220cc426a21cd4220cc4220cd426a21ce4220cd4220ce426a21cf4220ce4220cf426a" - "21d04220cf4220d0426a21d14220d04220d1426a21d24220d14220d2426a21d34220d24220d3426a21d44220d34220" - "d4426a21d54220d44220d5426a21d64220d54220d6426a21d74220d64220d7426a21d84220d74220d8426a21d94220" - "d84220d9426a21da4220d94220da426a21db4220da4220db426a21dc4220db4220dc426a21dd4220dc4220dd426a21" - "de4220dd4220de426a21df4220de4220df426a21e04220df4220e0426a21e14220e04220e1426a21e24220e14220e2" - "426a21e34220e24220e3426a21e44220e34220e4426a21e54220e44220e5426a21e64220e54220e6426a21e74220e6" - "4220e7426a21e84220e74220e8426a21e94220e84220e9426a21ea4220e94220ea426a21eb4220ea4220eb426a21ec" - "4220eb4220ec426a21ed4220ec4220ed426a21ee4220ed4220ee426a21ef4220ee4220ef426a21f04220ef4220f042" - "6a21f14220f04220f1426a21f24220f14220f2426a21f34220f24220f3426a21f44220f34220f4426a21f54220f442" - "20f5426a21f64220f54220f6426a21f74220f64220f7426a21f84220f74220f8426a21f94220f84220f9426a21fa42" - "20f94220fa426a21fb4220fa4220fb426a21fc4220fb4220fc426a21fd4220fc4220fd426a21fe4220fd4220fe426a" - "21ff4220fe4220ff426a21804320ff422080436a2181432080432081436a2182432081432082436a21834320824320" - "83436a2184432083432084436a2185432084432085436a2186432085432086436a2187432086432087436a21884320" - "87432088436a2189432088432089436a218a43208943208a436a218b43208a43208b436a218c43208b43208c436a21" - "8d43208c43208d436a218e43208d43208e436a218f43208e43208f436a219043208f432090436a2191432090432091" - "436a2192432091432092436a2193432092432093436a2194432093432094436a2195432094432095436a2196432095" - "432096436a2197432096432097436a2198432097432098436a2199432098432099436a219a43209943209a436a219b" - "43209a43209b436a219c43209b43209c436a219d43209c43209d436a219e43209d43209e436a219f43209e43209f43" - "6a21a043209f4320a0436a21a14320a04320a1436a21a24320a14320a2436a21a34320a24320a3436a21a44320a343" - "20a4436a21a54320a44320a5436a21a64320a54320a6436a21a74320a64320a7436a21a84320a74320a8436a21a943" - "20a84320a9436a21aa4320a94320aa436a21ab4320aa4320ab436a21ac4320ab4320ac436a21ad4320ac4320ad436a" - "21ae4320ad4320ae436a21af4320ae4320af436a21b04320af4320b0436a21b14320b04320b1436a21b24320b14320" - "b2436a21b34320b24320b3436a21b44320b34320b4436a21b54320b44320b5436a21b64320b54320b6436a21b74320" - "b64320b7436a21b84320b74320b8436a21b94320b84320b9436a21ba4320b94320ba436a21bb4320ba4320bb436a21" - "bc4320bb4320bc436a21bd4320bc4320bd436a21be4320bd4320be436a21bf4320be4320bf436a21c04320bf4320c0" - "436a21c14320c04320c1436a21c24320c14320c2436a21c34320c24320c3436a21c44320c34320c4436a21c54320c4" - "4320c5436a21c64320c54320c6436a21c74320c64320c7436a21c84320c74320c8436a21c94320c84320c9436a21ca" - "4320c94320ca436a21cb4320ca4320cb436a21cc4320cb4320cc436a21cd4320cc4320cd436a21ce4320cd4320ce43" - "6a21cf4320ce4320cf436a21d04320cf4320d0436a21d14320d04320d1436a21d24320d14320d2436a21d34320d243" - "20d3436a21d44320d34320d4436a21d54320d44320d5436a21d64320d54320d6436a21d74320d64320d7436a21d843" - "20d74320d8436a21d94320d84320d9436a21da4320d94320da436a21db4320da4320db436a21dc4320db4320dc436a" - "21dd4320dc4320dd436a21de4320dd4320de436a21df4320de4320df436a21e04320df4320e0436a21e14320e04320" - "e1436a21e24320e14320e2436a21e34320e24320e3436a21e44320e34320e4436a21e54320e44320e5436a21e64320" - "e54320e6436a21e74320e64320e7436a21e84320e74320e8436a21e94320e84320e9436a21ea4320e94320ea436a21" - "eb4320ea4320eb436a21ec4320eb4320ec436a21ed4320ec4320ed436a21ee4320ed4320ee436a21ef4320ee4320ef" - "436a21f04320ef4320f0436a21f14320f04320f1436a21f24320f14320f2436a21f34320f24320f3436a21f44320f3" - "4320f4436a21f54320f44320f5436a21f64320f54320f6436a21f74320f64320f7436a21f84320f74320f8436a21f9" - "4320f84320f9436a21fa4320f94320fa436a21fb4320fa4320fb436a21fc4320fb4320fc436a21fd4320fc4320fd43" - "6a21fe4320fd4320fe436a21ff4320fe4320ff436a21804420ff432080446a2181442080442081446a218244208144" - "2082446a2183442082442083446a2184442083442084446a2185442084442085446a2186442085442086446a218744" - "2086442087446a2188442087442088446a2189442088442089446a218a44208944208a446a218b44208a44208b446a" - "218c44208b44208c446a218d44208c44208d446a218e44208d44208e446a218f44208e44208f446a219044208f4420" - "90446a2191442090442091446a2192442091442092446a2193442092442093446a2194442093442094446a21954420" - "94442095446a2196442095442096446a2197442096442097446a2198442097442098446a2199442098442099446a21" - "9a44209944209a446a219b44209a44209b446a219c44209b44209c446a219d44209c44209d446a219e44209d44209e" - "446a219f44209e44209f446a21a044209f4420a0446a21a14420a04420a1446a21a24420a14420a2446a21a34420a2" - "4420a3446a21a44420a34420a4446a21a54420a44420a5446a21a64420a54420a6446a21a74420a64420a7446a21a8" - "4420a74420a8446a21a94420a84420a9446a21aa4420a94420aa446a21ab4420aa4420ab446a21ac4420ab4420ac44" - "6a21ad4420ac4420ad446a21ae4420ad4420ae446a21af4420ae4420af446a21b04420af4420b0446a21b14420b044" - "20b1446a21b24420b14420b2446a21b34420b24420b3446a21b44420b34420b4446a21b54420b44420b5446a21b644" - "20b54420b6446a21b74420b64420b7446a21b84420b74420b8446a21b94420b84420b9446a21ba4420b94420ba446a" - "21bb4420ba4420bb446a21bc4420bb4420bc446a21bd4420bc4420bd446a21be4420bd4420be446a21bf4420be4420" - "bf446a21c04420bf4420c0446a21c14420c04420c1446a21c24420c14420c2446a21c34420c24420c3446a21c44420" - "c34420c4446a21c54420c44420c5446a21c64420c54420c6446a21c74420c64420c7446a21c84420c74420c8446a21" - "c94420c84420c9446a21ca4420c94420ca446a21cb4420ca4420cb446a21cc4420cb4420cc446a21cd4420cc4420cd" - "446a21ce4420cd4420ce446a21cf4420ce4420cf446a21d04420cf4420d0446a21d14420d04420d1446a21d24420d1" - "4420d2446a21d34420d24420d3446a21d44420d34420d4446a21d54420d44420d5446a21d64420d54420d6446a21d7" - "4420d64420d7446a21d84420d74420d8446a21d94420d84420d9446a21da4420d94420da446a21db4420da4420db44" - "6a21dc4420db4420dc446a21dd4420dc4420dd446a21de4420dd4420de446a21df4420de4420df446a21e04420df44" - "20e0446a21e14420e04420e1446a21e24420e14420e2446a21e34420e24420e3446a21e44420e34420e4446a21e544" - "20e44420e5446a21e64420e54420e6446a21e74420e64420e7446a21e84420e74420e8446a21e94420e84420e9446a" - "21ea4420e94420ea446a21eb4420ea4420eb446a21ec4420eb4420ec446a21ed4420ec4420ed446a21ee4420ed4420" - "ee446a21ef4420ee4420ef446a21f04420ef4420f0446a21f14420f04420f1446a21f24420f14420f2446a21f34420" - "f24420f3446a21f44420f34420f4446a21f54420f44420f5446a21f64420f54420f6446a21f74420f64420f7446a21" - "f84420f74420f8446a21f94420f84420f9446a21fa4420f94420fa446a21fb4420fa4420fb446a21fc4420fb4420fc" - "446a21fd4420fc4420fd446a21fe4420fd4420fe446a21ff4420fe4420ff446a21804520ff442080456a2181452080" - "452081456a2182452081452082456a2183452082452083456a2184452083452084456a2185452084452085456a2186" - "452085452086456a2187452086452087456a2188452087452088456a2189452088452089456a218a45208945208a45" - "6a218b45208a45208b456a218c45208b45208c456a218d45208c45208d456a218e45208d45208e456a218f45208e45" - "208f456a219045208f452090456a2191452090452091456a2192452091452092456a2193452092452093456a219445" - "2093452094456a2195452094452095456a2196452095452096456a2197452096452097456a2198452097452098456a" - "2199452098452099456a219a45209945209a456a219b45209a45209b456a219c45209b45209c456a219d45209c4520" - "9d456a219e45209d45209e456a219f45209e45209f456a21a045209f4520a0456a21a14520a04520a1456a21a24520" - "a14520a2456a21a34520a24520a3456a21a44520a34520a4456a21a54520a44520a5456a21a64520a54520a6456a21" - "a74520a64520a7456a21a84520a74520a8456a21a94520a84520a9456a21aa4520a94520aa456a21ab4520aa4520ab" - "456a21ac4520ab4520ac456a21ad4520ac4520ad456a21ae4520ad4520ae456a21af4520ae4520af456a21b04520af" - "4520b0456a21b14520b04520b1456a21b24520b14520b2456a21b34520b24520b3456a21b44520b34520b4456a21b5" - "4520b44520b5456a21b64520b54520b6456a21b74520b64520b7456a21b84520b74520b8456a21b94520b84520b945" - "6a21ba4520b94520ba456a21bb4520ba4520bb456a21bc4520bb4520bc456a21bd4520bc4520bd456a21be4520bd45" - "20be456a21bf4520be4520bf456a21c04520bf4520c0456a21c14520c04520c1456a21c24520c14520c2456a21c345" - "20c24520c3456a21c44520c34520c4456a21c54520c44520c5456a21c64520c54520c6456a21c74520c64520c7456a" - "21c84520c74520c8456a21c94520c84520c9456a21ca4520c94520ca456a21cb4520ca4520cb456a21cc4520cb4520" - "cc456a21cd4520cc4520cd456a21ce4520cd4520ce456a21cf4520ce4520cf456a21d04520cf4520d0456a21d14520" - "d04520d1456a21d24520d14520d2456a21d34520d24520d3456a21d44520d34520d4456a21d54520d44520d5456a21" - "d64520d54520d6456a21d74520d64520d7456a21d84520d74520d8456a21d94520d84520d9456a21da4520d94520da" - "456a21db4520da4520db456a21dc4520db4520dc456a21dd4520dc4520dd456a21de4520dd4520de456a21df4520de" - "4520df456a21e04520df4520e0456a21e14520e04520e1456a21e24520e14520e2456a21e34520e24520e3456a21e4" - "4520e34520e4456a21e54520e44520e5456a21e64520e54520e6456a21e74520e64520e7456a21e84520e74520e845" - "6a21e94520e84520e9456a21ea4520e94520ea456a21eb4520ea4520eb456a21ec4520eb4520ec456a21ed4520ec45" - "20ed456a21ee4520ed4520ee456a21ef4520ee4520ef456a21f04520ef4520f0456a21f14520f04520f1456a21f245" - "20f14520f2456a21f34520f24520f3456a21f44520f34520f4456a21f54520f44520f5456a21f64520f54520f6456a" - "21f74520f64520f7456a21f84520f74520f8456a21f94520f84520f9456a21fa4520f94520fa456a21fb4520fa4520" - "fb456a21fc4520fb4520fc456a21fd4520fc4520fd456a21fe4520fd4520fe456a21ff4520fe4520ff456a21804620" - "ff452080466a2181462080462081466a2182462081462082466a2183462082462083466a2184462083462084466a21" - "85462084462085466a2186462085462086466a2187462086462087466a2188462087462088466a2189462088462089" - "466a218a46208946208a466a218b46208a46208b466a218c46208b46208c466a218d46208c46208d466a218e46208d" - "46208e466a218f46208e46208f466a219046208f462090466a2191462090462091466a2192462091462092466a2193" - "462092462093466a2194462093462094466a2195462094462095466a2196462095462096466a219746209646209746" - "6a2198462097462098466a2199462098462099466a219a46209946209a466a219b46209a46209b466a219c46209b46" - "209c466a219d46209c46209d466a219e46209d46209e466a219f46209e46209f466a21a046209f4620a0466a21a146" - "20a04620a1466a21a24620a14620a2466a21a34620a24620a3466a21a44620a34620a4466a21a54620a44620a5466a" - "21a64620a54620a6466a21a74620a64620a7466a21a84620a74620a8466a21a94620a84620a9466a21aa4620a94620" - "aa466a21ab4620aa4620ab466a21ac4620ab4620ac466a21ad4620ac4620ad466a21ae4620ad4620ae466a21af4620" - "ae4620af466a21b04620af4620b0466a21b14620b04620b1466a21b24620b14620b2466a21b34620b24620b3466a21" - "b44620b34620b4466a21b54620b44620b5466a21b64620b54620b6466a21b74620b64620b7466a21b84620b74620b8" - "466a21b94620b84620b9466a21ba4620b94620ba466a21bb4620ba4620bb466a21bc4620bb4620bc466a21bd4620bc" - "4620bd466a21be4620bd4620be466a21bf4620be4620bf466a21c04620bf4620c0466a21c14620c04620c1466a21c2" - "4620c14620c2466a21c34620c24620c3466a21c44620c34620c4466a21c54620c44620c5466a21c64620c54620c646" - "6a21c74620c64620c7466a21c84620c74620c8466a21c94620c84620c9466a21ca4620c94620ca466a21cb4620ca46" - "20cb466a21cc4620cb4620cc466a21cd4620cc4620cd466a21ce4620cd4620ce466a21cf4620ce4620cf466a21d046" - "20cf4620d0466a21d14620d04620d1466a21d24620d14620d2466a21d34620d24620d3466a21d44620d34620d4466a" - "21d54620d44620d5466a21d64620d54620d6466a21d74620d64620d7466a21d84620d74620d8466a21d94620d84620" - "d9466a21da4620d94620da466a21db4620da4620db466a21dc4620db4620dc466a21dd4620dc4620dd466a21de4620" - "dd4620de466a21df4620de4620df466a21e04620df4620e0466a21e14620e04620e1466a21e24620e14620e2466a21" - "e34620e24620e3466a21e44620e34620e4466a21e54620e44620e5466a21e64620e54620e6466a21e74620e64620e7" - "466a21e84620e74620e8466a21e94620e84620e9466a21ea4620e94620ea466a21eb4620ea4620eb466a21ec4620eb" - "4620ec466a21ed4620ec4620ed466a21ee4620ed4620ee466a21ef4620ee4620ef466a21f04620ef4620f0466a21f1" - "4620f04620f1466a21f24620f14620f2466a21f34620f24620f3466a21f44620f34620f4466a21f54620f44620f546" - "6a21f64620f54620f6466a21f74620f64620f7466a21f84620f74620f8466a21f94620f84620f9466a21fa4620f946" - "20fa466a21fb4620fa4620fb466a21fc4620fb4620fc466a21fd4620fc4620fd466a21fe4620fd4620fe466a21ff46" - "20fe4620ff466a21804720ff462080476a2181472080472081476a2182472081472082476a2183472082472083476a" - "2184472083472084476a2185472084472085476a2186472085472086476a2187472086472087476a21884720874720" - "88476a2189472088472089476a218a47208947208a476a218b47208a47208b476a218c47208b47208c476a218d4720" - "8c47208d476a218e47208d47208e476a218f47208e47208f476a219047208f472090476a2191472090472091476a21" - "92472091472092476a2193472092472093476a2194472093472094476a2195472094472095476a2196472095472096" - "476a2197472096472097476a2198472097472098476a2199472098472099476a219a47209947209a476a219b47209a" - "47209b476a219c47209b47209c476a219d47209c47209d476a219e47209d47209e476a219f47209e47209f476a21a0" - "47209f4720a0476a21a14720a04720a1476a21a24720a14720a2476a21a34720a24720a3476a21a44720a34720a447" - "6a21a54720a44720a5476a21a64720a54720a6476a21a74720a64720a7476a21a84720a74720a8476a21a94720a847" - "20a9476a21aa4720a94720aa476a21ab4720aa4720ab476a21ac4720ab4720ac476a21ad4720ac4720ad476a21ae47" - "20ad4720ae476a21af4720ae4720af476a21b04720af4720b0476a21b14720b04720b1476a21b24720b14720b2476a" - "21b34720b24720b3476a21b44720b34720b4476a21b54720b44720b5476a21b64720b54720b6476a21b74720b64720" - "b7476a21b84720b74720b8476a21b94720b84720b9476a21ba4720b94720ba476a21bb4720ba4720bb476a21bc4720" - "bb4720bc476a21bd4720bc4720bd476a21be4720bd4720be476a21bf4720be4720bf476a21c04720bf4720c0476a21" - "c14720c04720c1476a21c24720c14720c2476a21c34720c24720c3476a21c44720c34720c4476a21c54720c44720c5" - "476a21c64720c54720c6476a21c74720c64720c7476a21c84720c74720c8476a21c94720c84720c9476a21ca4720c9" - "4720ca476a21cb4720ca4720cb476a21cc4720cb4720cc476a21cd4720cc4720cd476a21ce4720cd4720ce476a21cf" - "4720ce4720cf476a21d04720cf4720d0476a21d14720d04720d1476a21d24720d14720d2476a21d34720d24720d347" - "6a21d44720d34720d4476a21d54720d44720d5476a21d64720d54720d6476a21d74720d64720d7476a21d84720d747" - "20d8476a21d94720d84720d9476a21da4720d94720da476a21db4720da4720db476a21dc4720db4720dc476a21dd47" - "20dc4720dd476a21de4720dd4720de476a21df4720de4720df476a21e04720df4720e0476a21e14720e04720e1476a" - "21e24720e14720e2476a21e34720e24720e3476a21e44720e34720e4476a21e54720e44720e5476a21e64720e54720" - "e6476a21e74720e64720e7476a21e84720e74720e8476a21e94720e84720e9476a21ea4720e94720ea476a21eb4720" - "ea4720eb476a21ec4720eb4720ec476a21ed4720ec4720ed476a21ee4720ed4720ee476a21ef4720ee4720ef476a21" - "f04720ef4720f0476a21f14720f04720f1476a21f24720f14720f2476a21f34720f24720f3476a21f44720f34720f4" - "476a21f54720f44720f5476a21f64720f54720f6476a21f74720f64720f7476a21f84720f74720f8476a21f94720f8" - "4720f9476a21fa4720f94720fa476a21fb4720fa4720fb476a21fc4720fb4720fc476a21fd4720fc4720fd476a21fe" - "4720fd4720fe476a21ff4720fe4720ff476a21804820ff472080486a2181482080482081486a218248208148208248" - "6a2183482082482083486a2184482083482084486a2185482084482085486a2186482085482086486a218748208648" - "2087486a2188482087482088486a2189482088482089486a218a48208948208a486a218b48208a48208b486a218c48" - "208b48208c486a218d48208c48208d486a218e48208d48208e486a218f48208e48208f486a219048208f482090486a" - "2191482090482091486a2192482091482092486a2193482092482093486a2194482093482094486a21954820944820" - "95486a2196482095482096486a2197482096482097486a2198482097482098486a2199482098482099486a219a4820" - "9948209a486a219b48209a48209b486a219c48209b48209c486a219d48209c48209d486a219e48209d48209e486a21" - "9f48209e48209f486a21a048209f4820a0486a21a14820a04820a1486a21a24820a14820a2486a21a34820a24820a3" - "486a21a44820a34820a4486a21a54820a44820a5486a21a64820a54820a6486a21a74820a64820a7486a21a84820a7" - "4820a8486a21a94820a84820a9486a21aa4820a94820aa486a21ab4820aa4820ab486a21ac4820ab4820ac486a21ad" - "4820ac4820ad486a21ae4820ad4820ae486a21af4820ae4820af486a21b04820af4820b0486a21b14820b04820b148" - "6a21b24820b14820b2486a21b34820b24820b3486a21b44820b34820b4486a21b54820b44820b5486a21b64820b548" - "20b6486a21b74820b64820b7486a21b84820b74820b8486a21b94820b84820b9486a21ba4820b94820ba486a21bb48" - "20ba4820bb486a21bc4820bb4820bc486a21bd4820bc4820bd486a21be4820bd4820be486a21bf4820be4820bf486a" - "21c04820bf4820c0486a21c14820c04820c1486a21c24820c14820c2486a21c34820c24820c3486a21c44820c34820" - "c4486a21c54820c44820c5486a21c64820c54820c6486a21c74820c64820c7486a21c84820c74820c8486a21c94820" - "c84820c9486a21ca4820c94820ca486a21cb4820ca4820cb486a21cc4820cb4820cc486a21cd4820cc4820cd486a21" - "ce4820cd4820ce486a21cf4820ce4820cf486a21d04820cf4820d0486a21d14820d04820d1486a21d24820d14820d2" - "486a21d34820d24820d3486a21d44820d34820d4486a21d54820d44820d5486a21d64820d54820d6486a21d74820d6" - "4820d7486a21d84820d74820d8486a21d94820d84820d9486a21da4820d94820da486a21db4820da4820db486a21dc" - "4820db4820dc486a21dd4820dc4820dd486a21de4820dd4820de486a21df4820de4820df486a21e04820df4820e048" - "6a21e14820e04820e1486a21e24820e14820e2486a21e34820e24820e3486a21e44820e34820e4486a21e54820e448" - "20e5486a21e64820e54820e6486a21e74820e64820e7486a21e84820e74820e8486a21e94820e84820e9486a21ea48" - "20e94820ea486a21eb4820ea4820eb486a21ec4820eb4820ec486a21ed4820ec4820ed486a21ee4820ed4820ee486a" - "21ef4820ee4820ef486a21f04820ef4820f0486a21f14820f04820f1486a21f24820f14820f2486a21f34820f24820" - "f3486a21f44820f34820f4486a21f54820f44820f5486a21f64820f54820f6486a21f74820f64820f7486a21f84820" - "f74820f8486a21f94820f84820f9486a21fa4820f94820fa486a21fb4820fa4820fb486a21fc4820fb4820fc486a21" - "fd4820fc4820fd486a21fe4820fd4820fe486a21ff4820fe4820ff486a21804920ff482080496a2181492080492081" - "496a2182492081492082496a2183492082492083496a2184492083492084496a2185492084492085496a2186492085" - "492086496a2187492086492087496a2188492087492088496a2189492088492089496a218a49208949208a496a218b" - "49208a49208b496a218c49208b49208c496a218d49208c49208d496a218e49208d49208e496a218f49208e49208f49" - "6a219049208f492090496a2191492090492091496a2192492091492092496a2193492092492093496a219449209349" - "2094496a2195492094492095496a2196492095492096496a2197492096492097496a2198492097492098496a219949" - "2098492099496a219a49209949209a496a219b49209a49209b496a219c49209b49209c496a219d49209c49209d496a" - "219e49209d49209e496a219f49209e49209f496a21a049209f4920a0496a21a14920a04920a1496a21a24920a14920" - "a2496a21a34920a24920a3496a21a44920a34920a4496a21a54920a44920a5496a21a64920a54920a6496a21a74920" - "a64920a7496a21a84920a74920a8496a21a94920a84920a9496a21aa4920a94920aa496a21ab4920aa4920ab496a21" - "ac4920ab4920ac496a21ad4920ac4920ad496a21ae4920ad4920ae496a21af4920ae4920af496a21b04920af4920b0" - "496a21b14920b04920b1496a21b24920b14920b2496a21b34920b24920b3496a21b44920b34920b4496a21b54920b4" - "4920b5496a21b64920b54920b6496a21b74920b64920b7496a21b84920b74920b8496a21b94920b84920b9496a21ba" - "4920b94920ba496a21bb4920ba4920bb496a21bc4920bb4920bc496a21bd4920bc4920bd496a21be4920bd4920be49" - "6a21bf4920be4920bf496a21c04920bf4920c0496a21c14920c04920c1496a21c24920c14920c2496a21c34920c249" - "20c3496a21c44920c34920c4496a21c54920c44920c5496a21c64920c54920c6496a21c74920c64920c7496a21c849" - "20c74920c8496a21c94920c84920c9496a21ca4920c94920ca496a21cb4920ca4920cb496a21cc4920cb4920cc496a" - "21cd4920cc4920cd496a21ce4920cd4920ce496a21cf4920ce4920cf496a21d04920cf4920d0496a21d14920d04920" - "d1496a21d24920d14920d2496a21d34920d24920d3496a21d44920d34920d4496a21d54920d44920d5496a21d64920" - "d54920d6496a21d74920d64920d7496a21d84920d74920d8496a21d94920d84920d9496a21da4920d94920da496a21" - "db4920da4920db496a21dc4920db4920dc496a21dd4920dc4920dd496a21de4920dd4920de496a21df4920de4920df" - "496a21e04920df4920e0496a21e14920e04920e1496a21e24920e14920e2496a21e34920e24920e3496a21e44920e3" - "4920e4496a21e54920e44920e5496a21e64920e54920e6496a21e74920e64920e7496a21e84920e74920e8496a21e9" - "4920e84920e9496a21ea4920e94920ea496a21eb4920ea4920eb496a21ec4920eb4920ec496a21ed4920ec4920ed49" - "6a21ee4920ed4920ee496a21ef4920ee4920ef496a21f04920ef4920f0496a21f14920f04920f1496a21f24920f149" - "20f2496a21f34920f24920f3496a21f44920f34920f4496a21f54920f44920f5496a21f64920f54920f6496a21f749" - "20f64920f7496a21f84920f74920f8496a21f94920f84920f9496a21fa4920f94920fa496a21fb4920fa4920fb496a" - "21fc4920fb4920fc496a21fd4920fc4920fd496a21fe4920fd4920fe496a21ff4920fe4920ff496a21804a20ff4920" - "804a6a21814a20804a20814a6a21824a20814a20824a6a21834a20824a20834a6a21844a20834a20844a6a21854a20" - "844a20854a6a21864a20854a20864a6a21874a20864a20874a6a21884a20874a20884a6a21894a20884a20894a6a21" - "8a4a20894a208a4a6a218b4a208a4a208b4a6a218c4a208b4a208c4a6a218d4a208c4a208d4a6a218e4a208d4a208e" - "4a6a218f4a208e4a208f4a6a21904a208f4a20904a6a21914a20904a20914a6a21924a20914a20924a6a21934a2092" - "4a20934a6a21944a20934a20944a6a21954a20944a20954a6a21964a20954a20964a6a21974a20964a20974a6a2198" - "4a20974a20984a6a21994a20984a20994a6a219a4a20994a209a4a6a219b4a209a4a209b4a6a219c4a209b4a209c4a" - "6a219d4a209c4a209d4a6a219e4a209d4a209e4a6a219f4a209e4a209f4a6a21a04a209f4a20a04a6a21a14a20a04a" - "20a14a6a21a24a20a14a20a24a6a21a34a20a24a20a34a6a21a44a20a34a20a44a6a21a54a20a44a20a54a6a21a64a" - "20a54a20a64a6a21a74a20a64a20a74a6a21a84a20a74a20a84a6a21a94a20a84a20a94a6a21aa4a20a94a20aa4a6a" - "21ab4a20aa4a20ab4a6a21ac4a20ab4a20ac4a6a21ad4a20ac4a20ad4a6a21ae4a20ad4a20ae4a6a21af4a20ae4a20" - "af4a6a21b04a20af4a20b04a6a21b14a20b04a20b14a6a21b24a20b14a20b24a6a21b34a20b24a20b34a6a21b44a20" - "b34a20b44a6a21b54a20b44a20b54a6a21b64a20b54a20b64a6a21b74a20b64a20b74a6a21b84a20b74a20b84a6a21" - "b94a20b84a20b94a6a21ba4a20b94a20ba4a6a21bb4a20ba4a20bb4a6a21bc4a20bb4a20bc4a6a21bd4a20bc4a20bd" - "4a6a21be4a20bd4a20be4a6a21bf4a20be4a20bf4a6a21c04a20bf4a20c04a6a21c14a20c04a20c14a6a21c24a20c1" - "4a20c24a6a21c34a20c24a20c34a6a21c44a20c34a20c44a6a21c54a20c44a20c54a6a21c64a20c54a20c64a6a21c7" - "4a20c64a20c74a6a21c84a20c74a20c84a6a21c94a20c84a20c94a6a21ca4a20c94a20ca4a6a21cb4a20ca4a20cb4a" - "6a21cc4a20cb4a20cc4a6a21cd4a20cc4a20cd4a6a21ce4a20cd4a20ce4a6a21cf4a20ce4a20cf4a6a21d04a20cf4a" - "20d04a6a21d14a20d04a20d14a6a21d24a20d14a20d24a6a21d34a20d24a20d34a6a21d44a20d34a20d44a6a21d54a" - "20d44a20d54a6a21d64a20d54a20d64a6a21d74a20d64a20d74a6a21d84a20d74a20d84a6a21d94a20d84a20d94a6a" - "21da4a20d94a20da4a6a21db4a20da4a20db4a6a21dc4a20db4a20dc4a6a21dd4a20dc4a20dd4a6a21de4a20dd4a20" - "de4a6a21df4a20de4a20df4a6a21e04a20df4a20e04a6a21e14a20e04a20e14a6a21e24a20e14a20e24a6a21e34a20" - "e24a20e34a6a21e44a20e34a20e44a6a21e54a20e44a20e54a6a21e64a20e54a20e64a6a21e74a20e64a20e74a6a21" - "e84a20e74a20e84a6a21e94a20e84a20e94a6a21ea4a20e94a20ea4a6a21eb4a20ea4a20eb4a6a21ec4a20eb4a20ec" - "4a6a21ed4a20ec4a20ed4a6a21ee4a20ed4a20ee4a6a21ef4a20ee4a20ef4a6a21f04a20ef4a20f04a6a21f14a20f0" - "4a20f14a6a21f24a20f14a20f24a6a21f34a20f24a20f34a6a21f44a20f34a20f44a6a21f54a20f44a20f54a6a21f6" - "4a20f54a20f64a6a21f74a20f64a20f74a6a21f84a20f74a20f84a6a21f94a20f84a20f94a6a21fa4a20f94a20fa4a" - "6a21fb4a20fa4a20fb4a6a21fc4a20fb4a20fc4a6a21fd4a20fc4a20fd4a6a21fe4a20fd4a20fe4a6a21ff4a20fe4a" - "20ff4a6a21804b20ff4a20804b6a21814b20804b20814b6a21824b20814b20824b6a21834b20824b20834b6a21844b" - "20834b20844b6a21854b20844b20854b6a21864b20854b20864b6a21874b20864b20874b6a21884b20874b20884b6a" - "21894b20884b20894b6a218a4b20894b208a4b6a218b4b208a4b208b4b6a218c4b208b4b208c4b6a218d4b208c4b20" - "8d4b6a218e4b208d4b208e4b6a218f4b208e4b208f4b6a21904b208f4b20904b6a21914b20904b20914b6a21924b20" - "914b20924b6a21934b20924b20934b6a21944b20934b20944b6a21954b20944b20954b6a21964b20954b20964b6a21" - "974b20964b20974b6a21984b20974b20984b6a21994b20984b20994b6a219a4b20994b209a4b6a219b4b209a4b209b" - "4b6a219c4b209b4b209c4b6a219d4b209c4b209d4b6a219e4b209d4b209e4b6a219f4b209e4b209f4b6a21a04b209f" - "4b20a04b6a21a14b20a04b20a14b6a21a24b20a14b20a24b6a21a34b20a24b20a34b6a21a44b20a34b20a44b6a21a5" - "4b20a44b20a54b6a21a64b20a54b20a64b6a21a74b20a64b20a74b6a21a84b20a74b20a84b6a21a94b20a84b20a94b" - "6a21aa4b20a94b20aa4b6a21ab4b20aa4b20ab4b6a21ac4b20ab4b20ac4b6a21ad4b20ac4b20ad4b6a21ae4b20ad4b" - "20ae4b6a21af4b20ae4b20af4b6a21b04b20af4b20b04b6a21b14b20b04b20b14b6a21b24b20b14b20b24b6a21b34b" - "20b24b20b34b6a21b44b20b34b20b44b6a21b54b20b44b20b54b6a21b64b20b54b20b64b6a21b74b20b64b20b74b6a" - "21b84b20b74b20b84b6a21b94b20b84b20b94b6a21ba4b20b94b20ba4b6a21bb4b20ba4b20bb4b6a21bc4b20bb4b20" - "bc4b6a21bd4b20bc4b20bd4b6a21be4b20bd4b20be4b6a21bf4b20be4b20bf4b6a21c04b20bf4b20c04b6a21c14b20" - "c04b20c14b6a21c24b20c14b20c24b6a21c34b20c24b20c34b6a21c44b20c34b20c44b6a21c54b20c44b20c54b6a21" - "c64b20c54b20c64b6a21c74b20c64b20c74b6a21c84b20c74b20c84b6a21c94b20c84b20c94b6a21ca4b20c94b20ca" - "4b6a21cb4b20ca4b20cb4b6a21cc4b20cb4b20cc4b6a21cd4b20cc4b20cd4b6a21ce4b20cd4b20ce4b6a21cf4b20ce" - "4b20cf4b6a21d04b20cf4b20d04b6a21d14b20d04b20d14b6a21d24b20d14b20d24b6a21d34b20d24b20d34b6a21d4" - "4b20d34b20d44b6a21d54b20d44b20d54b6a21d64b20d54b20d64b6a21d74b20d64b20d74b6a21d84b20d74b20d84b" - "6a21d94b20d84b20d94b6a21da4b20d94b20da4b6a21db4b20da4b20db4b6a21dc4b20db4b20dc4b6a21dd4b20dc4b" - "20dd4b6a21de4b20dd4b20de4b6a21df4b20de4b20df4b6a21e04b20df4b20e04b6a21e14b20e04b20e14b6a21e24b" - "20e14b20e24b6a21e34b20e24b20e34b6a21e44b20e34b20e44b6a21e54b20e44b20e54b6a21e64b20e54b20e64b6a" - "21e74b20e64b20e74b6a21e84b20e74b20e84b6a21e94b20e84b20e94b6a21ea4b20e94b20ea4b6a21eb4b20ea4b20" - "eb4b6a21ec4b20eb4b20ec4b6a21ed4b20ec4b20ed4b6a21ee4b20ed4b20ee4b6a21ef4b20ee4b20ef4b6a21f04b20" - "ef4b20f04b6a21f14b20f04b20f14b6a21f24b20f14b20f24b6a21f34b20f24b20f34b6a21f44b20f34b20f44b6a21" - "f54b20f44b20f54b6a21f64b20f54b20f64b6a21f74b20f64b20f74b6a21f84b20f74b20f84b6a21f94b20f84b20f9" - "4b6a21fa4b20f94b20fa4b6a21fb4b20fa4b20fb4b6a21fc4b20fb4b20fc4b6a21fd4b20fc4b20fd4b6a21fe4b20fd" - "4b20fe4b6a21ff4b20fe4b20ff4b6a21804c20ff4b20804c6a21814c20804c20814c6a21824c20814c20824c6a2183" - "4c20824c20834c6a21844c20834c20844c6a21854c20844c20854c6a21864c20854c20864c6a21874c20864c20874c" - "6a21884c20874c20884c6a21894c20884c20894c6a218a4c20894c208a4c6a218b4c208a4c208b4c6a218c4c208b4c" - "208c4c6a218d4c208c4c208d4c6a218e4c208d4c208e4c6a218f4c208e4c208f4c6a21904c208f4c20904c6a21914c" - "20904c20914c6a21924c20914c20924c6a21934c20924c20934c6a21944c20934c20944c6a21954c20944c20954c6a" - "21964c20954c20964c6a21974c20964c20974c6a21984c20974c20984c6a21994c20984c20994c6a219a4c20994c20" - "9a4c6a219b4c209a4c209b4c6a219c4c209b4c209c4c6a219d4c209c4c209d4c6a219e4c209d4c209e4c6a219f4c20" - "9e4c209f4c6a21a04c209f4c20a04c6a21a14c20a04c20a14c6a21a24c20a14c20a24c6a21a34c20a24c20a34c6a21" - "a44c20a34c20a44c6a21a54c20a44c20a54c6a21a64c20a54c20a64c6a21a74c20a64c20a74c6a21a84c20a74c20a8" - "4c6a21a94c20a84c20a94c6a21aa4c20a94c20aa4c6a21ab4c20aa4c20ab4c6a21ac4c20ab4c20ac4c6a21ad4c20ac" - "4c20ad4c6a21ae4c20ad4c20ae4c6a21af4c20ae4c20af4c6a21b04c20af4c20b04c6a21b14c20b04c20b14c6a21b2" - "4c20b14c20b24c6a21b34c20b24c20b34c6a21b44c20b34c20b44c6a21b54c20b44c20b54c6a21b64c20b54c20b64c" - "6a21b74c20b64c20b74c6a21b84c20b74c20b84c6a21b94c20b84c20b94c6a21ba4c20b94c20ba4c6a21bb4c20ba4c" - "20bb4c6a21bc4c20bb4c20bc4c6a21bd4c20bc4c20bd4c6a21be4c20bd4c20be4c6a21bf4c20be4c20bf4c6a21c04c" - "20bf4c20c04c6a21c14c20c04c20c14c6a21c24c20c14c20c24c6a21c34c20c24c20c34c6a21c44c20c34c20c44c6a" - "21c54c20c44c20c54c6a21c64c20c54c20c64c6a21c74c20c64c20c74c6a21c84c20c74c20c84c6a21c94c20c84c20" - "c94c6a21ca4c20c94c20ca4c6a21cb4c20ca4c20cb4c6a21cc4c20cb4c20cc4c6a21cd4c20cc4c20cd4c6a21ce4c20" - "cd4c20ce4c6a21cf4c20ce4c20cf4c6a21d04c20cf4c20d04c6a21d14c20d04c20d14c6a21d24c20d14c20d24c6a21" - "d34c20d24c20d34c6a21d44c20d34c20d44c6a21d54c20d44c20d54c6a21d64c20d54c20d64c6a21d74c20d64c20d7" - "4c6a21d84c20d74c20d84c6a21d94c20d84c20d94c6a21da4c20d94c20da4c6a21db4c20da4c20db4c6a21dc4c20db" - "4c20dc4c6a21dd4c20dc4c20dd4c6a21de4c20dd4c20de4c6a21df4c20de4c20df4c6a21e04c20df4c20e04c6a21e1" - "4c20e04c20e14c6a21e24c20e14c20e24c6a21e34c20e24c20e34c6a21e44c20e34c20e44c6a21e54c20e44c20e54c" - "6a21e64c20e54c20e64c6a21e74c20e64c20e74c6a21e84c20e74c20e84c6a21e94c20e84c20e94c6a21ea4c20e94c" - "20ea4c6a21eb4c20ea4c20eb4c6a21ec4c20eb4c20ec4c6a21ed4c20ec4c20ed4c6a21ee4c20ed4c20ee4c6a21ef4c" - "20ee4c20ef4c6a21f04c20ef4c20f04c6a21f14c20f04c20f14c6a21f24c20f14c20f24c6a21f34c20f24c20f34c6a" - "21f44c20f34c20f44c6a21f54c20f44c20f54c6a21f64c20f54c20f64c6a21f74c20f64c20f74c6a21f84c20f74c20" - "f84c6a21f94c20f84c20f94c6a21fa4c20f94c20fa4c6a21fb4c20fa4c20fb4c6a21fc4c20fb4c20fc4c6a21fd4c20" - "fc4c20fd4c6a21fe4c20fd4c20fe4c6a21ff4c20fe4c20ff4c6a21804d20ff4c20804d6a21814d20804d20814d6a21" - "824d20814d20824d6a21834d20824d20834d6a21844d20834d20844d6a21854d20844d20854d6a21864d20854d2086" - "4d6a21874d20864d20874d6a21884d20874d20884d6a21894d20884d20894d6a218a4d20894d208a4d6a218b4d208a" - "4d208b4d6a218c4d208b4d208c4d6a218d4d208c4d208d4d6a218e4d208d4d208e4d6a218f4d208e4d208f4d6a2190" - "4d208f4d20904d6a21914d20904d20914d6a21924d20914d20924d6a21934d20924d20934d6a21944d20934d20944d" - "6a21954d20944d20954d6a21964d20954d20964d6a21974d20964d20974d6a21984d20974d20984d6a21994d20984d" - "20994d6a219a4d20994d209a4d6a219b4d209a4d209b4d6a219c4d209b4d209c4d6a219d4d209c4d209d4d6a219e4d" - "209d4d209e4d6a219f4d209e4d209f4d6a21a04d209f4d20a04d6a21a14d20a04d20a14d6a21a24d20a14d20a24d6a" - "21a34d20a24d20a34d6a21a44d20a34d20a44d6a21a54d20a44d20a54d6a21a64d20a54d20a64d6a21a74d20a64d20" - "a74d6a21a84d20a74d20a84d6a21a94d20a84d20a94d6a21aa4d20a94d20aa4d6a21ab4d20aa4d20ab4d6a21ac4d20" - "ab4d20ac4d6a21ad4d20ac4d20ad4d6a21ae4d20ad4d20ae4d6a21af4d20ae4d20af4d6a21b04d20af4d20b04d6a21" - "b14d20b04d20b14d6a21b24d20b14d20b24d6a21b34d20b24d20b34d6a21b44d20b34d20b44d6a21b54d20b44d20b5" - "4d6a21b64d20b54d20b64d6a21b74d20b64d20b74d6a21b84d20b74d20b84d6a21b94d20b84d20b94d6a21ba4d20b9" - "4d20ba4d6a21bb4d20ba4d20bb4d6a21bc4d20bb4d20bc4d6a21bd4d20bc4d20bd4d6a21be4d20bd4d20be4d6a21bf" - "4d20be4d20bf4d6a21c04d20bf4d20c04d6a21c14d20c04d20c14d6a21c24d20c14d20c24d6a21c34d20c24d20c34d" - "6a21c44d20c34d20c44d6a21c54d20c44d20c54d6a21c64d20c54d20c64d6a21c74d20c64d20c74d6a21c84d20c74d" - "20c84d6a21c94d20c84d20c94d6a21ca4d20c94d20ca4d6a21cb4d20ca4d20cb4d6a21cc4d20cb4d20cc4d6a21cd4d" - "20cc4d20cd4d6a21ce4d20cd4d20ce4d6a21cf4d20ce4d20cf4d6a21d04d20cf4d20d04d6a21d14d20d04d20d14d6a" - "21d24d20d14d20d24d6a21d34d20d24d20d34d6a21d44d20d34d20d44d6a21d54d20d44d20d54d6a21d64d20d54d20" - "d64d6a21d74d20d64d20d74d6a21d84d20d74d20d84d6a21d94d20d84d20d94d6a21da4d20d94d20da4d6a21db4d20" - "da4d20db4d6a21dc4d20db4d20dc4d6a21dd4d20dc4d20dd4d6a21de4d20dd4d20de4d6a21df4d20de4d20df4d6a21" - "e04d20df4d20e04d6a21e14d20e04d20e14d6a21e24d20e14d20e24d6a21e34d20e24d20e34d6a21e44d20e34d20e4" - "4d6a21e54d20e44d20e54d6a21e64d20e54d20e64d6a21e74d20e64d20e74d6a21e84d20e74d20e84d6a21e94d20e8" - "4d20e94d6a21ea4d20e94d20ea4d6a21eb4d20ea4d20eb4d6a21ec4d20eb4d20ec4d6a21ed4d20ec4d20ed4d6a21ee" - "4d20ed4d20ee4d6a21ef4d20ee4d20ef4d6a21f04d20ef4d20f04d6a21f14d20f04d20f14d6a21f24d20f14d20f24d" - "6a21f34d20f24d20f34d6a21f44d20f34d20f44d6a21f54d20f44d20f54d6a21f64d20f54d20f64d6a21f74d20f64d" - "20f74d6a21f84d20f74d20f84d6a21f94d20f84d20f94d6a21fa4d20f94d20fa4d6a21fb4d20fa4d20fb4d6a21fc4d" - "20fb4d20fc4d6a21fd4d20fc4d20fd4d6a21fe4d20fd4d20fe4d6a21ff4d20fe4d20ff4d6a21804e20ff4d20804e6a" - "21814e20804e20814e6a21824e20814e20824e6a21834e20824e20834e6a21844e20834e20844e6a21854e20844e20" - "854e6a21864e20854e20864e6a21874e20864e20874e6a21884e20874e20884e6a21894e20884e20894e6a218a4e20" - "894e208a4e6a218b4e208a4e208b4e6a218c4e208b4e208c4e6a218d4e208c4e208d4e6a218e4e208d4e208e4e6a21" - "8f4e208f4e0b"; diff --git a/src/test/app/wasm_fixtures/fixtures.cpp b/src/test/app/wasm_fixtures/fixtures.cpp deleted file mode 100644 index 81d9f04047..0000000000 --- a/src/test/app/wasm_fixtures/fixtures.cpp +++ /dev/null @@ -1,1394 +0,0 @@ -// TODO: consider moving these to separate files (and figure out the build) - -#include - -#include - -extern std::string const kFibWasmHex = - "0061736d0100000001090260000060017f017f030302000105030100020638097f004180080b7f004180080b7f0041" - "80080b7f00418088040b7f004180080b7f00418088040b7f00418080080b7f0041000b7f0041010b07a7010c066d65" - "6d6f72790200115f5f7761736d5f63616c6c5f63746f727300000366696200010c5f5f64736f5f68616e646c650300" - "0a5f5f646174615f656e6403010b5f5f737461636b5f6c6f7703020c5f5f737461636b5f6869676803030d5f5f676c" - "6f62616c5f6261736503040b5f5f686561705f6261736503050a5f5f686561705f656e6403060d5f5f6d656d6f7279" - "5f6261736503070c5f5f7461626c655f6261736503080a440202000b3f01017f200045044041000f0b200041034804" - "4041010f0b200041026a21000340200041036b100120016a2101200041026b220041044a0d000b200141016a0b007f" - "0970726f647563657273010c70726f6365737365642d62790105636c616e675f31392e312e352d776173692d73646b" - "202868747470733a2f2f6769746875622e636f6d2f6c6c766d2f6c6c766d2d70726f6a656374206162346235613264" - "62353832393538616631656533303861373930636664623432626432343732302900490f7461726765745f66656174" - "75726573042b0f6d757461626c652d676c6f62616c732b087369676e2d6578742b0f7265666572656e63652d747970" - "65732b0a6d756c746976616c7565"; - -extern std::string const kLedgerSqnWasmHex = - "0061736d01000000010e0360027f7f017f6000006000017f02120103656e760a6c6467725f696e6465780000030302" - "01020503010002063f0a7f01418088040b7f004180080b7f004180080b7f004180080b7f00418088040b7f00418008" - "0b7f00418088040b7f00418080080b7f0041000b7f0041010b07b1010c066d656d6f72790200115f5f7761736d5f63" - "616c6c5f63746f727300010d657363726f775f66696e69736800020c5f5f64736f5f68616e646c6503010a5f5f6461" - "74615f656e6403020b5f5f737461636b5f6c6f7703030c5f5f737461636b5f6869676803040d5f5f676c6f62616c5f" - "6261736503050b5f5f686561705f6261736503060a5f5f686561705f656e6403070d5f5f6d656d6f72795f62617365" - "03080c5f5f7461626c655f6261736503090a3d0202000b3801037f230041106b220024002000410c6a410410002101" - "200028020c2102200041106a2400200141054100200241054f1b20014100481b0b007f0970726f647563657273010c" - "70726f6365737365642d62790105636c616e675f31392e312e352d776173692d73646b202868747470733a2f2f6769" - "746875622e636f6d2f6c6c766d2f6c6c766d2d70726f6a656374206162346235613264623538323935386166316565" - "33303861373930636664623432626432343732302900490f7461726765745f6665617475726573042b0f6d75746162" - "6c652d676c6f62616c732b087369676e2d6578742b0f7265666572656e63652d74797065732b0a6d756c746976616c" - "7565"; - -extern std::string const kAllHostFunctionsWasmHex = - "0061736d0100000001550c60027f7f017f60037f7f7f017f60047f7f7f7f017f60017f017f60067f7f7f7f7f7f017f" - "60037f7f7f0060057f7f7f7f7f0060087f7f7f7f7f7f7f7f017f60057f7f7f7f7f017f60017f0060027f7f00600001" - "7f02b1041808686f73745f6c69620874785f6669656c64000108686f73745f6c6962057472616365000608686f7374" - "5f6c69620a6c6467725f696e646578000008686f73745f6c696210706172656e745f6c6467725f74696d6500000868" - "6f73745f6c696210706172656e745f6c6467725f68617368000008686f73745f6c69620874785f696e6e6572000208" - "686f73745f6c69620a74785f6172725f6c656e000308686f73745f6c69621074785f696e6e65725f6172725f6c656e" - "000008686f73745f6c69620d686f6d655f6c655f6669656c64000108686f73745f6c69620d686f6d655f6c655f696e" - "6e6572000208686f73745f6c69620f686f6d655f6c655f6172725f6c656e000308686f73745f6c696215686f6d655f" - "6c655f696e6e65725f6172725f6c656e000008686f73745f6c69620863616368655f6c65000108686f73745f6c6962" - "0d63726564656e7469616c5f6964000708686f73745f6c696209657363726f775f6964000408686f73745f6c696209" - "6f7261636c655f6964000408686f73745f6c69620b7368613531325f68616c66000208686f73745f6c6962076e6674" - "5f757269000408686f73745f6c6962087365745f64617461000008686f73745f6c69620a6c655f6172725f6c656e00" - "0008686f73745f6c69620e6163636f756e74726f6f745f6964000208686f73745f6c6962106c655f696e6e65725f61" - "72725f6c656e000108686f73745f6c6962086c655f6669656c64000208686f73745f6c6962086c655f696e6e657200" - "08030b0a090a05050b000101030005030100110619037f01418080c0000b7f0041c698c0000b7f0041d098c0000b07" - "3504066d656d6f727902000d657363726f775f66696e697368001c0a5f5f646174615f656e6403010b5f5f68656170" - "5f6261736503020acf210a9d0101027f230041206b2201240020014200370310200142003703082001410036021820" - "00027f024041818020200141086a41141000220241004e0440200241144b0d01200241144704402000418180808078" - "36020441010c030b20002001280218360011200020012903103700092000200129030837000141000c020b20002002" - "36020441010c010b2000417336020441010b3a0000200141206a24000b5a01017f230041106b2202240020012d0000" - "41014604402002200134020437030841df97c000410b4101200241086a41081001000b200020012800113600102000" - "200129000937000820002001290001370000200241106a24000b1900200241214f0440000b20002002360204200020" - "013602000b1900200241094f0440000b20002002360204200020013602000bdd1e01077f230041c0036b2200240041" - "ea97c000411b4107410141001001418598c0004119410741014100100141b583c000412b4107410141001001200041" - "003602500240024002400240024002400240200041d0006a41041002220141004a044020002000280250220141ff81" - "fc0771410878200141187841ff81fc077172ad3703c00141e083c00041174101200041c0016a220241081001200041" - "003602800120004180016a41041003220141004c0d012000200028028001220141ff81fc0771410878200141187841" - "ff81fc077172ad3703c00141f783c00041134101200241081001200042003703d801200042003703d0012000420037" - "03c801200042003703c0012002412010042201412047044020002001ac3703a00141bd84c000412b4101200041a001" - "6a4108100141997f21030c080b418a84c00041134106200041c0016a220441201001419d84c0004120410741014100" - "100141aa85c000412e4107410141001001200041003602b001200042003703a801200042003703a001418180202000" - "41a0016a22024114100022014114470d0241d885c00041144104200241141001200042003703384188801820004138" - "6a22024108100022014108470d03200042083703c00141ec85c00041174101200441081001418386c0004128410620" - "02410810012000410036027841848008200041f8006a22024104100022014104470d0441ab86c00041154106200241" - "04100120004100360051200041013a005020004100360054200042003703d801200042003703d001200042003703c8" - "01200042003703c0010240200041d0006a4108200441201005220141004e044020002001ad3703800141c086c00041" - "14410120004180016a41081001200041306a20042001101a41d486c000410d41062000280230200028023410010c01" - "0b20002001ac3703800141e186c0004129410120004180016a410810010b20004183803c1006ac37038001418a87c0" - "004115410120004180016a22024108100120004189803c1006ac37038001419f87c000411341012002410810010240" - "200041d0006a41081007220141004e044020002001ad3703800141b287c000411441012002410810010c010b200020" - "01ac3703800141c687c000412d410120004180016a410810010b41f387c0004123410741014100100141e792c00041" - "3341074101410010012000420037033841828018200041386a220141081008220241004c0d05200241084604402000" - "42083703c001419a93c000412b4101200041c0016a4108100141c593c000412f41062001410810010c070b20002002" - "ad3703c00141f493c000412f4101200041c0016a41081001200041286a200041386a2002101b41a394c00041174106" - "2000280228200028022c10010c060b20002001ac3703c001418d85c000411d4101200041c0016a41081001419b7f21" - "030c060b20002001ac3703c00141e884c00041254101200041c0016a41081001419a7f21030c050b20002001ac3703" - "c001418289c000412a4101200041c0016a4108100141b77e21030c040b20002001ac3703c00141c188c00041c10041" - "01200041c0016a4108100141b67e21030c030b20002001ac3703c001419688c000412b4101200041c0016a41081001" - "41b57e21030c020b20002002ac3703c00141ba94c00041c5004101200041c0016a410810010b200041003602b00120" - "0042003703a801200042003703a001024041818020200041a0016a220241141008220141004a044041ff94c000411e" - "41042002411410010c010b20002001ac3703c001419d95c00041334101200041c0016a410810010b20004100360051" - "200041013a005020004100360054200042003703d801200042003703d001200042003703c801200042003703c00102" - "40200041d0006a4108200041c0016a220141201009220241004e044020002002ad3703800141d095c000411c410120" - "004180016a41081001200041206a20012002101a41ec95c000411541062000280220200028022410010c010b200020" - "02ac37038001418196c0004139410120004180016a410810010b20004183803c100aac3703800141ba96c000412441" - "0120004180016a2201410810010240200041d0006a4108100b220241004e044020002002ad3703800141de96c00041" - "1c41012001410810010c010b20002002ac3703800141fa96c000413d410120004180016a410810010b41b797c00041" - "28410741014100100141ac89c000412f4107410141001001200041c0016a2204101820004180016a22012004101920" - "0042003703b801200042003703b001200042003703a801200042003703a001024002400240024002402001200041a0" - "016a2202101d22014120460440200241204100100c220541004a044020002005ad3703c00141db89c0004123410120" - "0441081001200042003703782005200041f8006a22014108101e220241004c0d0220024108460440200042083703c0" - "0141fe89c000412a410120044108100141a88ac000412e41062001410810010c060b20002002ad3703c00141d68ac0" - "00412e4101200041c0016a41081001200041186a200041f8006a2002101b41848bc000411641062000280218200028" - "021c10010c050b20002005ac3703c00141bc8dc000413c4101200041c0016a220141081001200042003703d8012000" - "42003703d001200042003703c801200042003703c001410120014120101e22014100480d020c030b20002001ac3703" - "c001419090c000412e4101200041c0016a4108100141ef7c21030c050b20002002ac3703c001419a8bc000412b4101" - "200041c0016a410810010c020b20002001ac37035041f88dc00041c1004101200041d0006a410810010b2000410036" - "0039200041013a00382000410036003c4101200041386a200041c0016a101f2201410048044020002001ac37035041" - "b98ec00041354101200041d0006a410810010b410110202201410048044020002001ac37035041ee8ec00041324101" - "200041d0006a410810010b4101200041386a10212201410048044020002001ac37035041a08fc00041394101200041" - "d0006a410810010b41d98fc000413741074101410010010c010b20004100360039200041013a00382000410036003c" - "200042003703d801200042003703d001200042003703c801200042003703c00102402005200041386a200041c0016a" - "2201101f220241004e044020002002ad37035041c58bc000411b4101200041d0006a41081001200041106a20012002" - "101a41e08bc000411441062000280210200028021410010c010b20002002ac37035041f48bc00041314101200041d0" - "006a410810010b200020051020ac37035041a58cc00041234101200041d0006a22014108100102402005200041386a" - "1021220241004e044020002002ad37035041c88cc000411b41012001410810010c010b20002002ac37035041e38cc0" - "0041354101200041d0006a410810010b41988dc000412441074101410010010b41be90c000412f4107410141001001" - "200041c0016a22011018200041386a2204200110192000420037036820004200370360200042003703582000420037" - "0350024002402004200041d0006a2202101d2201412046044041ed90c000410f410620024120100120004200370398" - "012000420037039001200042003703880120004200370380010240200441142004411441fc90c00041092000418001" - "6a22014120100d220241004a0440200041086a20012002101a418491c000411241062000280208200028020c10010c" - "010b20002002ac3703c001419691c000413c4101200041c0016a410810010b200042003703b801200042003703b001" - "200042003703a801200042003703a00120004180808cc07e360270200041386a22044114200041f0006a4104200041" - "a0016a22024120100e22014120470d0141d291c000410e4106200241201001200042003703d801200042003703d001" - "200042003703c801200042003703c001200041808080d00236027420044114200041f4006a4104200041c0016a4120" - "100f2201412047044020002001ac370378419292c000411c4101200041f8006a4108100141887c21030c040b41e091" - "c000410e4106200041c0016a22044120100141ee91c00041244107410141001001418080c000412541074101410010" - "0120004200370398012000420037039001200042003703880120004200370380010240024041a580c0004117200041" - "80016a2202412010102201412046044041bc80c000410b410641a580c0004117100141c780c0004111410620024120" - "100120041018200041d0006a220620041019200042003703b801200042003703b001200042003703a8012000420037" - "03a00102404100200422036b410371220220036a220520034d0d0020020440200221010340200341003a0000200341" - "016a2103200141016b22010d000b0b200241016b4107490d000340200341003a0000200341076a41003a0000200341" - "066a41003a0000200341056a41003a0000200341046a41003a0000200341036a41003a0000200341026a41003a0000" - "200341016a41003a0000200341086a22032005470d000b0b200541800220026b2201417c716a220320054b04400340" - "20054100360200200541046a22052003490d000b0b024020032001410371220120036a22024f0d0020012205044003" - "40200341003a0000200341016a2103200541016b22050d000b0b200141016b4107490d000340200341003a00002003" - "41076a41003a0000200341066a41003a0000200341056a41003a0000200341046a41003a0000200341036a41003a00" - "00200341026a41003a0000200341016a41003a0000200341086a22032002470d000b0b20064114200041a0016a4120" - "20044180021011220141004c0d0120002001ad37033841d880c00041104101200041386a4108100120014181024f0d" - "0541e880c000410941062004200110010c020b20002001ac3703c00141e381c00041224101200041c0016a41081001" - "41a77b21030c050b20002001ac37033841f180c000412e4101200041386a410810010b419f81c0004112410641b181" - "c000410710012000422a3703384101210341b881c00041114101200041386a4108100141c981c000411a4107410141" - "001001418582c0004129410741014100100141ae82c000412810122201412847044020002001ac3703c001419b83c0" - "00411a4101200041c0016a4108100141c37a21030c040b41d682c0004127410641ae82c0004128100141fd82c00041" - "1e4107410141001001419e98c000412841074101410010010c030b20002001ac3703c00141ca92c000411d41012000" - "41c0016a41081001418b7c21030c020b20002001ac3703c00141ae92c000411c4101200041c0016a4108100141897c" - "21030c010b000b200041c0036a240020030b0c00200041142001412010140b0e002000418280182001200210160b0e" - "002000200141082002412010170b0a0020004183803c10130b0a0020002001410810150b0bd0180100418080c0000b" - "c6182d2d2d2043617465676f727920363a205574696c6974792046756e6374696f6e73202d2d2d48656c6c6f2c2058" - "52504c205741534d20776f726c6421496e70757420646174613a5348413531322068616c6620686173683a4e465420" - "64617461206c656e6774683a4e465420646174613a494e464f3a206765745f6e6674206661696c6564202865787065" - "63746564202d206e6f2073756368204e4654293a54657374207472616365206d6573736167657061796c6f61645465" - "7374206e756d626572207472616365535543434553533a205574696c6974792066756e6374696f6e734552524f523a" - "20636f6d707574655f7368613531325f68616c66206661696c65643a2d2d2d2043617465676f727920373a20446174" - "61205570646174652046756e6374696f6e73202d2d2d55706461746564206c656467657220656e7472792064617461" - "2066726f6d205741534d20746573745375636365737366756c6c792075706461746564206c656467657220656e7472" - "7920776974683a535543434553533a2044617461207570646174652066756e6374696f6e734552524f523a20757064" - "6174655f64617461206661696c65643a2d2d2d2043617465676f727920313a204c6564676572204865616465722046" - "756e6374696f6e73202d2d2d4c65646765722073657175656e6365206e756d6265723a506172656e74206c65646765" - "722074696d653a506172656e74206c656467657220686173683a535543434553533a204c6564676572206865616465" - "722066756e6374696f6e734552524f523a206765745f706172656e745f6c65646765725f686173682077726f6e6720" - "6c656e6774683a4552524f523a206765745f706172656e745f6c65646765725f74696d65206661696c65643a455252" - "4f523a206765745f6c65646765725f73716e206661696c65643a2d2d2d2043617465676f727920323a205472616e73" - "616374696f6e20446174612046756e6374696f6e73202d2d2d5472616e73616374696f6e204163636f756e743a5472" - "616e73616374696f6e20466565206c656e6774683a5472616e73616374696f6e20466565202873657269616c697a65" - "642058525020616d6f756e74293a5472616e73616374696f6e2053657175656e63653a4e6573746564206669656c64" - "206c656e6774683a4e6573746564206669656c643a494e464f3a206765745f74785f6e65737465645f6669656c6420" - "6e6f74206170706c696361626c653a5369676e657273206172726179206c656e6774683a4d656d6f73206172726179" - "206c656e6774683a4e6573746564206172726179206c656e6774683a494e464f3a206765745f74785f6e6573746564" - "5f61727261795f6c656e206e6f74206170706c696361626c653a535543434553533a205472616e73616374696f6e20" - "646174612066756e6374696f6e734552524f523a206765745f74785f6669656c642853657175656e6365292077726f" - "6e67206c656e6774683a4552524f523a206765745f74785f6669656c6428466565292077726f6e67206c656e677468" - "20286578706563746564203820627974657320666f7220585250293a4552524f523a206765745f74785f6669656c64" - "284163636f756e74292077726f6e67206c656e6774683a2d2d2d2043617465676f727920343a20416e79204c656467" - "6572204f626a6563742046756e6374696f6e73202d2d2d5375636365737366756c6c7920636163686564206f626a65" - "637420696e20736c6f743a436163686564206f626a6563742062616c616e6365206c656e677468202858525020616d" - "6f756e74293a436163686564206f626a6563742062616c616e6365202873657269616c697a65642058525020616d6f" - "756e74293a436163686564206f626a6563742062616c616e6365206c656e67746820286e6f6e2d58525020616d6f75" - "6e74293a436163686564206f626a6563742062616c616e63653a494e464f3a206765745f6c65646765725f6f626a5f" - "6669656c642842616c616e636529206661696c65643a436163686564206e6573746564206669656c64206c656e6774" - "683a436163686564206e6573746564206669656c643a494e464f3a206765745f6c65646765725f6f626a5f6e657374" - "65645f6669656c64206e6f74206170706c696361626c653a436163686564206f626a656374205369676e6572732061" - "72726179206c656e6774683a436163686564206e6573746564206172726179206c656e6774683a494e464f3a206765" - "745f6c65646765725f6f626a5f6e65737465645f61727261795f6c656e206e6f74206170706c696361626c653a5355" - "43434553533a20416e79206c6564676572206f626a6563742066756e6374696f6e73494e464f3a2063616368655f6c" - "65646765725f6f626a206661696c65642028657870656374656420776974682074657374206669787475726573293a" - "494e464f3a206765745f6c65646765725f6f626a5f6669656c64206661696c65642061732065787065637465642028" - "6e6f20636163686564206f626a656374293a494e464f3a206765745f6c65646765725f6f626a5f6e65737465645f66" - "69656c64206661696c65642061732065787065637465643a494e464f3a206765745f6c65646765725f6f626a5f6172" - "7261795f6c656e206661696c65642061732065787065637465643a494e464f3a206765745f6c65646765725f6f626a" - "5f6e65737465645f61727261795f6c656e206661696c65642061732065787065637465643a535543434553533a2041" - "6e79206c6564676572206f626a6563742066756e6374696f6e732028696e7465726661636520746573746564294552" - "524f523a206163636f756e74726f6f745f6964206661696c656420666f722063616368696e6720746573743a2d2d2d" - "2043617465676f727920353a204b65796c65742047656e65726174696f6e2046756e6374696f6e73202d2d2d416363" - "6f756e74206b65796c65743a546573745479706543726564656e7469616c206b65796c65743a494e464f3a20637265" - "64656e7469616c5f6b65796c6574206661696c656420286578706563746564202d20696e7465726661636520697373" - "7565293a457363726f77206b65796c65743a4f7261636c65206b65796c65743a535543434553533a204b65796c6574" - "2067656e65726174696f6e2066756e6374696f6e734552524f523a206f7261636c655f6b65796c6574206661696c65" - "643a4552524f523a20657363726f775f6b65796c6574206661696c65643a4552524f523a206163636f756e74726f6f" - "745f6964206661696c65643a2d2d2d2043617465676f727920333a2043757272656e74204c6564676572204f626a65" - "63742046756e6374696f6e73202d2d2d43757272656e74206f626a6563742062616c616e6365206c656e6774682028" - "58525020616d6f756e74293a43757272656e74206f626a6563742062616c616e6365202873657269616c697a656420" - "58525020616d6f756e74293a43757272656e74206f626a6563742062616c616e6365206c656e67746820286e6f6e2d" - "58525020616d6f756e74293a43757272656e74206f626a6563742062616c616e63653a494e464f3a206765745f6375" - "7272656e745f6c65646765725f6f626a5f6669656c642842616c616e636529206661696c656420286d617920626520" - "6578706563746564293a43757272656e74206c6564676572206f626a656374206163636f756e743a494e464f3a2067" - "65745f63757272656e745f6c65646765725f6f626a5f6669656c64284163636f756e7429206661696c65643a437572" - "72656e74206e6573746564206669656c64206c656e6774683a43757272656e74206e6573746564206669656c643a49" - "4e464f3a206765745f63757272656e745f6c65646765725f6f626a5f6e65737465645f6669656c64206e6f74206170" - "706c696361626c653a43757272656e74206f626a656374205369676e657273206172726179206c656e6774683a4375" - "7272656e74206e6573746564206172726179206c656e6774683a494e464f3a206765745f63757272656e745f6c6564" - "6765725f6f626a5f6e65737465645f61727261795f6c656e206e6f74206170706c696361626c653a53554343455353" - "3a2043757272656e74206c6564676572206f626a6563742066756e6374696f6e736572726f725f636f64653d3d3d3d" - "20484f53542046554e4354494f4e532054455354203d3d3d54657374696e6720323620686f73742066756e6374696f" - "6e73535543434553533a20416c6c20686f73742066756e6374696f6e2074657374732070617373656421004d097072" - "6f64756365727302086c616e6775616765010452757374000c70726f6365737365642d6279010572757374631d312e" - "39352e30202835393830373631366520323032362d30342d313429002c0f7461726765745f6665617475726573022b" - "0f6d757461626c652d676c6f62616c732b087369676e2d657874"; - -extern std::string const kDeepRecursionHex = - "0061736d010000000105016000017f030201000608017f0141c0843d0b0711010d657363726f775f66696e69736800" - "000a16011400230045044041010f0b230041016b240010000b"; - -extern std::string const kAllKeyletsWasmHex = - "0061736d0100000001500a60067f7f7f7f7f7f017f60047f7f7f7f017f60087f7f7f7f7f7f7f7f017f60047f7f7f7f" - "0060037f7f7f017f60037f7f7e017f60057f7f7f7f7f017f6000017f60037f7f7f0060067f7f7f7f7f7e00029f0418" - "08686f73745f6c69620974726163655f6e756d000508686f73745f6c6962057472616365000608686f73745f6c6962" - "0863616368655f6c65000408686f73745f6c6962086c655f6669656c64000108686f73745f6c69620d686f6d655f6c" - "655f6669656c64000408686f73745f6c69620a74726163655f61636374000108686f73745f6c69620e6163636f756e" - "74726f6f745f6964000108686f73745f6c69620c74727573746c696e655f6964000208686f73745f6c696206616d6d" - "5f6964000008686f73745f6c696208636865636b5f6964000008686f73745f6c69620d63726564656e7469616c5f69" - "64000208686f73745f6c69620b64656c65676174655f6964000008686f73745f6c6962126465706f7369745f707265" - "617574685f6964000008686f73745f6c6962066469645f6964000108686f73745f6c696209657363726f775f696400" - "0008686f73745f6c69620f6d70745f69737375616e63655f6964000008686f73745f6c69620a6d70746f6b656e5f69" - "64000008686f73745f6c69620c6e66745f6f666665725f6964000008686f73745f6c6962086f666665725f69640000" - "08686f73745f6c69620a7061796368616e5f6964000208686f73745f6c6962167065726d697373696f6e65645f646f" - "6d61696e5f6964000008686f73745f6c69620a7369676e6572735f6964000108686f73745f6c6962097469636b6574" - "5f6964000008686f73745f6c6962087661756c745f6964000003070603030307080905030100110619037f01418080" - "c0000b7f0041c28ac0000b7f0041d08ac0000b073504066d656d6f727902000d657363726f775f66696e697368001b" - "0a5f5f646174615f656e6403010b5f5f686561705f6261736503020ae8370614002000200120022003418280204282" - "8020101d0b140020002001200220034181802042818020101d0bd10302017f017e230041a0016b2204240002402001" - "2d0000410146044041d780c000411620012802042201ac10001a200041013a0000200020013602040c010b20044118" - "6a200141196a290000370300200441106a200141116a290000370300200441086a200141096a290000370300200420" - "012900013703002002200320044120410110011a2004412041001002220141004c044041d080c00041072001ac1000" - "1a200041013a0000200020013602040c010b418b80c000410f4285801410001a20014185801420044180016a412010" - "032201412047044041af80c0004115417f20012001417f4e1b2201ac10001a200041013a0000200020013602040c01" - "0b200441c2006a20044182016a2d00003a0000200441f0006a20044197016a2900002205370300200441286a220120" - "04418f016a290000370300200441306a22022005370300200441386a22032004419f016a2d00003a0000200420042f" - "0080013b014020042004290087013703202004200428008301360043200441df006a20032d00003a0000200441d700" - "6a2002290300370000200441cf006a20012903003700002004200429032037004741c480c000410c200441406b4120" - "410110011a20004180023b01000b200441a0016a24000bd32c02097f027e23004180076b2200240041ed80c0004123" - "41014100410010011a02402000027f02404181802020004190016a220741141004220641144604402000410e6a2000" - "4192016a22032d00003a000020002000290097013703e80120002000419c016a22012900003700ed01200020002f00" - "90013b010c200020002903e8013703d806200020002900ed013700dd06200020002800930136000f200041186a2000" - "2900dd06370000200020002903d806370013419081c00041082000410c6a2204411410051a41838020200741141004" - "22064114470d03200041226a20032d00003a000020002000290097013703e801200020012900003700ed0120002000" - "2f0090013b0120200020002903e8013703d806200020002900ed013700dd0620002000280093013600232000412c6a" - "20002900dd06370000200020002903d806370027419881c000410c200041206a411410051a200041a8016a22034200" - "370300200041a0016a2201420037030020004198016a42003703002000420037039001200441142007412010062204" - "4120460d01024020044100480440200020043602380c010b2000417f3602380b41010c020b0c020b200041cd006a20" - "03290300370000200041c5006a20012903003700002000413d6a20004198016a290300370000200020002903900137" - "003541000b3a003420004190016a200041346a41a481c00041071019024020002d0090014101460440200028029401" - "2106419c8ac0004112420510001a0c010b4100210641ab81c000413541014100410010011a200041e6006a41c4003a" - "0000200041e0006a4100360200200041eb006a41003a0000200041d5a6013b01642000420037035820004100360067" - "200041a8016a22044200370300200041a0016a2203420037030020004198016a220142003703002000420037039001" - "02402000410c6a4114200041206a4114200041d8006a411420004190016a4120100722074120470440024020074100" - "480440200020073602700c010b2000417f3602700b410121060c010b20004185016a2004290300370000200041fd00" - "6a2003290300370000200041f5006a2001290300370000200020002903900137006d0b200020063a006c2000419001" - "6a200041ec006a41e081c0004109101a20002d00900141014604402000280294012106419c8ac0004112420510001a" - "0c010b4100210641e981c000413741014100410010011a200041f8016a200041306a2204280100360200200041f001" - "6a200041286a220329010037030020004184026a200041e0006a290300220a3702002000418c026a200041e8006a28" - "02002201360200200020002901203703e8012000200029035822093702fc01200041e8066a22052001360200200041" - "e0066a2207200a370300200020093703d806200041f4066a2003290100370200200041fc066a200428010036020020" - "0020002901203702ec0620004190026a200041d8066a22034128101c20004194016a200041e8016a41d000101c2000" - "410136029001200041f0066a220142003703002005420037030020074200370300200042003703d806024041ae8ac0" - "004114200041bc016a412820034120100822034120470440024020034100480440200020033602ec010c010b200041" - "7f3602ec010b410121060c010b20004181026a2001290300370000200041f9016a2005290300370000200041f1016a" - "2007290300370000200020002903d8063700e9010b200020063a00e801200041bc026a200041e8016a41a082c00041" - "03101920002d00bc02410146044020002802c0022106419c8ac0004112420610001a0c010b4100210641a382c00041" - "3141014100410010011a200041063602d80620004180026a22044200370300200041f8016a22034200370300200041" - "f0016a22014200370300200042003703e80102402000410c6a4114200041d8066a4104200041e8016a412010092207" - "4120470440024020074100480440200020073602c8020c010b2000417f3602c8020b410121060c010b200041dd026a" - "2004290300370000200041d5026a2003290300370000200041cd026a2001290300370000200020002903e8013700c5" - "020b200020063a00c402200041e8016a200041c4026a41d482c0004105101920002d00e801410146044020002802ec" - "012106419c8ac0004112420610001a0c010b41d982c000413341014100410010011a20004180026a42003703002000" - "41f8016a4200370300200041f0016a4200370300200042003703e801024002402000410c6a2201411420014114418c" - "83c0004112200041e8016a4120100a2201412047044041d780c0004116417f20012001417f4e1b2206ac10001a0c01" - "0b200041da066a20002d00ea013a0000200041f0026a200041f7016a290000220a370300200041f8026a200041ff01" - "6a290000220937030020004180036a20004187026a2d000022013a0000200041e7066a200a370000200041ef066a20" - "09370000200041f7066a20013a0000200020002f01e8013b01d806200020002900ef0122093703e802200020002800" - "eb013600db06200020093700df06419e83c000410a200041d8066a22014120410110011a2001412041001002220641" - "004c044041d080c00041072006ac10001a0c010b418b80c000410f4298802010001a200641988020200041e8016a41" - "14100322014114460d0141af80c0004115417f20012001417f4e1b2206ac10001a0b419c8ac0004112420710001a0c" - "010b419a80c000411541014100410010011a41a883c000413841014100410010011a230041206b2208240020084118" - "6a22074200370300200841106a22044200370300200841086a220342003703002008420037030020004184036a2201" - "027f2000410c6a22064114200041206a2202411420084120100b220541204704400240200541004804402001200536" - "02040c010b2001417f3602040b41010c010b20012008290300370001200141196a2007290300370000200141116a20" - "04290300370000200141096a200329030037000041000b3a0000200841206a2400200041e8016a2205200141e083c0" - "004108101920002d00e80145044041e883c000413641014100410010011a230041206b22082400200841186a220742" - "00370300200841106a22044200370300200841086a2203420037030020084200370300200041a8036a2201027f2006" - "41142002411420084120100c22024120470440024020024100480440200120023602040c010b2001417f3602040b41" - "010c010b20012008290300370001200141196a2007290300370000200141116a2004290300370000200141096a2003" - "29030037000041000b3a0000200841206a240020052001419e84c000410e101920002d00e801410146044020002802" - "ec012106419c8ac0004112420910001a0c020b41ac84c000413c41014100410010011a230041206b22022400200241" - "186a22074200370300200241106a22044200370300200241086a2203420037030020024200370300200041cc036a22" - "01027f2000410c6a411420024120100d22054120470440024020054100480440200120053602040c010b2001417f36" - "02040b41010c010b20012002290300370001200141196a2007290300370000200141116a2004290300370000200141" - "096a200329030037000041000b3a0000200241206a2400200041e8016a200141e884c0004103101920002d00e80141" - "0146044020002802ec012106419c8ac0004112420a10001a0c020b41eb84c000413141014100410010011a23004130" - "6b220224002002410b36020c200241286a22074200370300200241206a22044200370300200241186a220342003703" - "0020024200370310200041f0036a2201027f2000410c6a41142002410c6a4104200241106a4120100e220541204704" - "40024020054100480440200120053602040c010b2001417f3602040b41010c010b2001200229031037000120014119" - "6a2007290300370000200141116a2004290300370000200141096a200329030037000041000b3a0000200241306a24" - "00200041e8016a2001419c85c0004106101920002d00e801410146044020002802ec012106419c8ac0004112420b10" - "001a0c020b41a285c000413441014100410010011a230041306b220224002002410c36020c200241286a2207420037" - "0300200241206a22044200370300200241186a220342003703002002420037031020004194046a2201027f2000410c" - "6a41142002410c6a4104200241106a4120100f22054120470440024020054100480440200120053602040c010b2001" - "417f3602040b41010c010b20012002290310370001200141196a2007290300370000200141116a2004290300370000" - "200141096a200329030037000041000b3a0000200241306a2400200041fc016a2000411c6a280100360200200041f4" - "016a200041146a2901003702002000200029010c3702ec01200041808080e0003602e801200041d8066a2103230041" - "406a22042400024020012d0000410146044041d780c000411620012802042201ac10001a200341013a000020032001" - "3602040c010b200441206a200141196a290000370300200441186a200141116a290000370300200441106a20014109" - "6a2900003703002004200129000137030841d685c000410b200441086a22014120410110011a024002402001412041" - "001002220141004c044041d080c00041072001ac10001a0c010b418b80c000410f4284802010001a20014184802020" - "04412c6a4114100322014114460d0141af80c0004115417f20012001417f4e1b2201ac10001a0b200341013a000020" - "0320013602040c010b419a80c000411541014100410010011a20034180023b01000b200441406b240020002d00d806" - "410146044020002802dc062106419c8ac0004112420c10001a0c020b41e185c000413941014100410010011a230041" - "206b22022400200241186a22074200370300200241106a22044200370300200241086a220342003703002002420037" - "0300200041b8046a2201027f200041e8016a4118200041206a41142002412010102205412047044002402005410048" - "0440200120053602040c010b2001417f3602040b41010c010b20012002290300370001200141196a20072903003700" - "00200141116a2004290300370000200141096a200329030037000041000b3a0000200241206a2400200041d8066a20" - "01419a86c0004107101920002d00d806410146044020002802dc062106419c8ac0004112420d10001a0c020b41a186" - "c000413541014100410010011a230041306b220224002002410636020c200241286a22074200370300200241206a22" - "044200370300200241186a2203420037030020024200370310200041dc046a2201027f200041206a41142002410c6a" - "4104200241106a4120101122054120470440024020054100480440200120053602040c010b2001417f3602040b4101" - "0c010b20012002290310370001200141196a2007290300370000200141116a2004290300370000200141096a200329" - "030037000041000b3a0000200241306a2400200041d8066a200141d686c000410c101820002d00d806410146044020" - "002802dc062106419c8ac0004112420d10001a0c020b41e286c000413a41014100410010011a230041306b22022400" - "2002410d36020c200241286a22074200370300200241206a22044200370300200241186a2203420037030020024200" - "37031020004180056a2201027f2000410c6a41142002410c6a4104200241106a412010122205412047044002402005" - "4100480440200120053602040c010b2001417f3602040b41010c010b20012002290310370001200141196a20072903" - "00370000200141116a2004290300370000200141096a200329030037000041000b3a0000200241306a2400200041d8" - "066a2001419c87c0004105101920002d00d806410146044020002802dc062106419c8ac0004112420d10001a0c020b" - "41a187c000413341014100410010011a230041306b220224002002410e36020c200241286a22074200370300200241" - "206a22044200370300200241186a2203420037030020024200370310200041a4056a2201027f2000410c6a41142000" - "41206a41142002410c6a4104200241106a4120101322054120470440024020054100480440200120053602040c010b" - "2001417f3602040b41010c010b20012002290310370001200141196a2007290300370000200141116a200429030037" - "0000200141096a200329030037000041000b3a0000200241306a2400200041d8066a200141d487c000410a10192000" - "2d00d806410146044020002802dc062106419c8ac0004112420e10001a0c020b41de87c00041384101410041001001" - "1a230041306b220224002002410f36020c200241286a22074200370300200241206a22044200370300200241186a22" - "03420037030020024200370310200041c8056a2201027f2000410c6a41142002410c6a4104200241106a4120101422" - "054120470440024020054100480440200120053602040c010b2001417f3602040b41010c010b200120022903103700" - "01200141196a2007290300370000200141116a2004290300370000200141096a200329030037000041000b3a000020" - "0241306a2400200041d8066a2001419688c0004112101820002d00d806410146044020002802dc062106419c8ac000" - "4112420f10001a0c020b41a888c00041c00041014100410010011a230041206b22022400200241186a220742003703" - "00200241106a22044200370300200241086a2203420037030020024200370300200041ec056a2201027f2000410c6a" - "411420024120101522054120470440024020054100480440200120053602040c010b2001417f3602040b41010c010b" - "20012002290300370001200141196a2007290300370000200141116a2004290300370000200141096a200329030037" - "000041000b3a0000200241206a2400200041d8066a200141e888c000410a101a20002d00d806410146044020002802" - "dc062106419c8ac0004112421010001a0c020b41f288c000413841014100410010011a230041306b22022400200241" - "1236020c200241286a22074200370300200241206a22044200370300200241186a2203420037030020024200370310" - "20004190066a2201027f2000410c6a41142002410c6a4104200241106a412010162205412047044002402005410048" - "0440200120053602040c010b2001417f3602040b41010c010b20012002290310370001200141196a20072903003700" - "00200141116a2004290300370000200141096a200329030037000041000b3a0000200241306a2400200041d8066a20" - "0141aa89c0004106101920002d00d806410146044020002802dc062106419c8ac0004112421210001a0c020b410121" - "0641b089c000413441014100410010011a230041306b220224002002411336020c200241286a220742003703002002" - "41206a22044200370300200241186a2203420037030020024200370310200041b4066a2201027f2000410c6a411420" - "02410c6a4104200241106a4120101722054120470440024020054100480440200120053602040c010b2001417f3602" - "040b41010c010b20012002290310370001200141196a2007290300370000200141116a200429030037000020014109" - "6a200329030037000041000b3a0000200241306a2400200041d8066a200141e489c0004105101920002d00d8064101" - "46044020002802dc062106419c8ac0004112421310001a0c020b41e989c000413341014100410010011a0c010b2000" - "2802ec012106419c8ac0004112420810001a0b20004180076a240020060f0b418080c000410b417f20062006417f4e" - "1bac1000000bfd0401067f200241104f0440024020002000410020006b41037122056a22044f0d0020012103200504" - "40200521060340200020032d00003a0000200341016a2103200041016a2100200641016b22060d000b0b200541016b" - "4107490d000340200020032d00003a0000200041016a200341016a2d00003a0000200041026a200341026a2d00003a" - "0000200041036a200341036a2d00003a0000200041046a200341046a2d00003a0000200041056a200341056a2d0000" - "3a0000200041066a200341066a2d00003a0000200041076a200341076a2d00003a0000200341086a2103200041086a" - "22002004470d000b0b2004200220056b2207417c7122086a21000240200120056a2206410371450440200020044d0d" - "0120062101034020042001280200360200200141046a2101200441046a22042000490d000b0c010b200020044d0d00" - "2006410374220541187121032006417c71220241046a2101410020056b411871210520022802002102034020042002" - "2003762001280200220220057472360200200141046a2101200441046a22042000490d000b0b200741037121022006" - "20086a21010b02402000200020026a22064f0d002002410771220304400340200020012d00003a0000200141016a21" - "01200041016a2100200341016b22030d000b0b200241016b4107490d000340200020012d00003a0000200041016a20" - "0141016a2d00003a0000200041026a200141026a2d00003a0000200041036a200141036a2d00003a0000200041046a" - "200141046a2d00003a0000200041056a200141056a2d00003a0000200041066a200141066a2d00003a000020004107" - "6a200141076a2d00003a0000200141086a2101200041086a22002006470d000b0b0b940201017f230041406a220624" - "00024020012d0000410146044041d780c000411620012802042201ac10001a200041013a0000200020013602040c01" - "0b200641206a200141196a290000370300200641186a200141116a290000370300200641106a200141096a29000037" - "03002006200129000137030820022003200641086a22014120410110011a024002402001412041001002220141004c" - "044041d080c00041072001ac10001a0c010b418b80c000410f200510001a200120042006412c6a4114100322014114" - "460d0141af80c0004115417f20012001417f4e1b2201ac10001a0b200041013a0000200020013602040c010b419a80" - "c000411541014100410010011a20004180023b01000b200641406b24000b0bb80a0100418080c0000bae0a6572726f" - "725f636f64653d47657474696e67206669656c643a204669656c6420646174613a207265747269657665644572726f" - "722067657474696e67206669656c643a204669656c6420646174613a204572726f723a204572726f72206765747469" - "6e67206b65796c65743a202424242424205354415254494e47205741534d20455845435554494f4e20242424242441" - "63636f756e743a44657374696e6174696f6e3a4163636f756e744163636f756e74206f626a65637420657869737473" - "2c2070726f63656564696e67207769746820657363726f772066696e6973682e54727573746c696e6554727573746c" - "696e65206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973" - "682e414d4d414d4d206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f7720" - "66696e6973682e436865636b436865636b206f626a656374206578697374732c2070726f63656564696e6720776974" - "6820657363726f772066696e6973682e7465726d73616e64636f6e646974696f6e7343726564656e7469616c437265" - "64656e7469616c206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066" - "696e6973682e44656c656761746544656c6567617465206f626a656374206578697374732c2070726f63656564696e" - "67207769746820657363726f772066696e6973682e4465706f736974507265617574684465706f7369745072656175" - "7468206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e697368" - "2e444944444944206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066" - "696e6973682e457363726f77457363726f77206f626a656374206578697374732c2070726f63656564696e67207769" - "746820657363726f772066696e6973682e4d505449737375616e63654d505449737375616e6365206f626a65637420" - "6578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e4d50546f6b656e4d50" - "546f6b656e206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e" - "6973682e4e46546f6b656e4f666665724e46546f6b656e4f66666572206f626a656374206578697374732c2070726f" - "63656564696e67207769746820657363726f772066696e6973682e4f666665724f66666572206f626a656374206578" - "697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e5061794368616e6e656c50" - "61794368616e6e656c206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f77" - "2066696e6973682e5065726d697373696f6e6564446f6d61696e5065726d697373696f6e6564446f6d61696e206f62" - "6a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e5369676e" - "65724c6973745369676e65724c697374206f626a656374206578697374732c2070726f63656564696e672077697468" - "20657363726f772066696e6973682e5469636b65745469636b6574206f626a656374206578697374732c2070726f63" - "656564696e67207769746820657363726f772066696e6973682e5661756c745661756c74206f626a65637420657869" - "7374732c2070726f63656564696e67207769746820657363726f772066696e6973682e43757272656e742073657120" - "76616c75653a004d0970726f64756365727302086c616e6775616765010452757374000c70726f6365737365642d62" - "79010572757374631d312e38372e30202831373036376539616320323032352d30352d303929002c0f746172676574" - "5f6665617475726573022b0f6d757461626c652d676c6f62616c732b087369676e2d657874"; - -extern std::string const kCodecovTestsWasmHex = - "0061736d01000000015c0c60067f7f7f7f7f7f017f60027f7f017f60047f7f7f7f017f60037f7f7f017f60077f7f7f" - "7f7f7f7f017f60087f7f7f7f7f7f7f7f017f60057f7f7f7f7f017f60017f017f60057f7f7f7f7f0060047f7f7f7f00" - "60017f006000017f02ee093708686f73745f6c6962057472616365000808686f73745f6c69620a6c6467725f696e64" - "6578000108686f73745f6c696210706172656e745f6c6467725f74696d65000108686f73745f6c696210706172656e" - "745f6c6467725f68617368000108686f73745f6c696208626173655f666565000108686f73745f6c696211616d656e" - "646d656e745f656e61626c6564000108686f73745f6c69620874785f6669656c64000308686f73745f6c69620e6163" - "636f756e74726f6f745f6964000208686f73745f6c69620863616368655f6c65000308686f73745f6c69620d686f6d" - "655f6c655f6669656c64000308686f73745f6c6962086c655f6669656c64000208686f73745f6c69620874785f696e" - "6e6572000208686f73745f6c69620d686f6d655f6c655f696e6e6572000208686f73745f6c6962086c655f696e6e65" - "72000608686f73745f6c69620a74785f6172725f6c656e000708686f73745f6c69620f686f6d655f6c655f6172725f" - "6c656e000708686f73745f6c69620a6c655f6172725f6c656e000108686f73745f6c69621074785f696e6e65725f61" - "72725f6c656e000108686f73745f6c696215686f6d655f6c655f696e6e65725f6172725f6c656e000108686f73745f" - "6c6962106c655f696e6e65725f6172725f6c656e000308686f73745f6c6962087365745f64617461000108686f7374" - "5f6c69620b7368613531325f68616c66000208686f73745f6c696209636865636b5f736967000008686f73745f6c69" - "62076e66745f757269000008686f73745f6c69620a6e66745f697373756572000208686f73745f6c6962096e66745f" - "7461786f6e000208686f73745f6c6962096e66745f666c616773000108686f73745f6c69620c6e66745f786665725f" - "666565000108686f73745f6c69620a6e66745f73657269616c000208686f73745f6c696208636865636b5f69640000" - "08686f73745f6c69620f666c6f61745f66726f6d5f75696e74000608686f73745f6c69620c74727573746c696e655f" - "6964000508686f73745f6c696206616d6d5f6964000008686f73745f6c69620d63726564656e7469616c5f69640005" - "08686f73745f6c69620a6d70746f6b656e5f6964000008686f73745f6c696209666c6f61745f636d70000208686f73" - "745f6c696209666c6f61745f616464000408686f73745f6c696209666c6f61745f737562000408686f73745f6c6962" - "0a666c6f61745f6d756c74000408686f73745f6c696209666c6f61745f646976000408686f73745f6c69620a666c6f" - "61745f726f6f74000008686f73745f6c696209666c6f61745f706f77000008686f73745f6c696209657363726f775f" - "6964000008686f73745f6c69620f6d70745f69737375616e63655f6964000008686f73745f6c69620c6e66745f6f66" - "6665725f6964000008686f73745f6c6962086f666665725f6964000008686f73745f6c6962096f7261636c655f6964" - "000008686f73745f6c69620a7061796368616e5f6964000508686f73745f6c6962167065726d697373696f6e65645f" - "646f6d61696e5f6964000008686f73745f6c6962097469636b65745f6964000008686f73745f6c6962087661756c74" - "5f6964000008686f73745f6c69620b64656c65676174655f6964000008686f73745f6c6962126465706f7369745f70" - "7265617574685f6964000008686f73745f6c6962066469645f6964000208686f73745f6c69620a7369676e6572735f" - "69640002030403090a0b05030100110619037f01418080c0000b7f0041da98c0000b7f0041e098c0000b073504066d" - "656d6f727902000d657363726f775f66696e69736800390a5f5f646174615f656e6403010b5f5f686561705f626173" - "6503020ac32e037201017f230041106b22042400024002402000200147044020022003410741014100100020004100" - "480d0120042000ad3703080c020b20042000ac370308200220034101200441086a41081000200441106a24000f0b20" - "042000ac3703080b418080c000410b4101200441086a41081000000b2801017f230041106b2201240020012000ac37" - "030841be91c000410b4101200141086a41081000000ba42d02087f017e230041a0026b2200240041c991c000412341" - "0741014100100020004100360260200041e0006a220141041001410441a090c000410a103720004100360260200141" - "041002410441908bc00041101037200042003703782000420037037020004200370368200042003703602001412010" - "03412041f180c0004110103720004100360260200141041004410441ff83c000410810372000428182848890a0c080" - "013703202000428182848890a0c080013703182000428182848890a0c080013703102000428182848890a0c0800137" - "030841ec91c000410e1005410141fa91c00041111037200041086a41201005410141fa91c000411110372000410036" - "02702000420037036820004200370360024002404181802020014114100622014100480d00200141144b0440417321" - "010c010b20014114460d0141818080807821010b20011038000b2000200029006c3700fd01200020002900673703f8" - "01200020002d00623a002e200020002f01603b012c2000200028006336002f200020002903f8013700332000200029" - "00fd013700382000420037037820004200370370200042003703682000420037036002402000412c6a4114200041e0" - "006a4120100722014120470440200141004e0d0120011038000b200020002d00623a0042200020002f01603b014020" - "00200029006f22083703800220002000280063360043200020002900673700472000200837004f2000200029007737" - "0057200020002d007f3a005f200041406b4120410010084101418b92c0004108103720004100360270200042003703" - "682000420037036041818020200041e0006a220241141009411441d38dc000410d1037200041003602702000420037" - "03682000420037036041014181802020024114100a4114418784c0004108103702404100200041e4006a22046b4103" - "71220320046a220120044d0d0020030440200321050340200441003a0000200441016a2104200541016b22050d000b" - "0b200341016b4107490d000340200441003a0000200441076a41003a0000200441066a41003a0000200441056a4100" - "3a0000200441046a41003a0000200441036a41003a0000200441026a41003a0000200441016a41003a000020044108" - "6a22042001470d000b0b2001413c20036b2203417c716a220420014b0440034020014100360200200141046a220120" - "04490d000b0b024020042003410371220320046a22054f0d002003220104400340200441003a0000200441016a2104" - "200141016b22010d000b0b200341016b4107490d000340200441003a0000200441076a41003a0000200441066a4100" - "3a0000200441056a41003a0000200441046a41003a0000200441036a41003a0000200441026a41003a000020044101" - "6a41003a0000200441086a22042005470d000b0b200041043602a00120004181802036026020004100360288022000" - "420037038002200042003703f80120024104200041f8016a22014114100b411441a280c00041081037200041003602" - "88022000420037038002200042003703f801200220002802a00120014114100c411441d084c000410d103720004100" - "360288022000420037038002200042003703f8014101200220002802a00120014114100d411441b08dc00041081037" - "4189803c100e4120419392c000410a10374189803c100f4120419d92c000410f103741014189803c1010412041ac92" - "c000410a1037200220002802a0011011412041b692c00041101037200220002802a0011012412041c692c000411510" - "374101200220002802a0011013412041db92c000411010372000412c6a220341141014411441eb92c0004108103720" - "0042003703900220004200370388022000420037038002200042003703f801200220002802a0012001412010154120" - "418f84c000410b103741f392c000410c41ff92c000410b418a93c000410e10164101419893c0004109103720002000" - "2903203703c001200020002903183703b801200020002903103703b001200020002903083703a801200041003b0188" - "022000420037038002200042003703f80120034114200041a8016a22054120200141121017411241d18fc000410710" - "3720004100360288022000420037038002200042003703f80120054120200141141018411441ac8fc000410a103720" - "0041003602f801200541202001410410194104419790c0004109103720054120101a410841a193c000410910372005" - "4120101b410a41aa93c000410c1037200041003602f8012005412020014104101c410441ba83c000410a103741b693" - "c000410d410420034114100041b693c000410d410541c393c0004108100041b693c000410d410541cb93c000410810" - "00417f41041003417141d393c00041181037200041003602f8012001417f1003417141a888c0004118103720004100" - "3a00fa01200041003b01f801200141031003417d41e790c000411e1037200041003602f8012001418094ebdc031003" - "417341bd8ec000411d10374102100e416f41eb93c00041191037417f20002802a00110114171418494c00041181037" - "2002417f10114171419c94c0004118103720024181081011417441b494c00041191037200041e094ebdc036a220420" - "002802a0011011417341cd94c000411810372000420037039002200042003703880220004200370380022000420037" - "03f801200341142004410820014120101d417341cc8cc0004114103720004200370390022000420037038802200042" - "0037038002200042003703f801200341142003411420014120101d417141918ec00041161037200042003703900220" - "004200370388022000420037038002200042003703f80120044108200141204100101e4173418b80c0004117103720" - "0042003703900220004200370388022000420037038002200042003703f801200220002802a001200141204100101e" - "417141a485c00041201037200420002802a00141011008417341e594c00041101037200220002802a0014101100841" - "7141f594c00041121037200042003703900220004200370388022000420037038002200042003703f8012004200028" - "02a001200141201007417341a78ec00041161037200042003703900220004200370388022000420037038002200042" - "003703f801200220002802a0012001412010074171418e83c000411810372000420037039002200042003703880220" - "00420037038002200042003703f8012003411420034114200420002802a00120014120101f4173418591c000411d10" - "37200042003703900220004200370388022000420037038002200042003703f8012003411420034114200220002802" - "a00120014120101f4171419581c000411f103720004200370390022000420037038802200042003703800220004200" - "3703f80141c698c0004114200420002802a001200141201020417341dc8ac000411510372000420037039002200042" - "00370388022000420037038002200042003703f80141c698c0004114200220002802a0012001412010204171418e89" - "c000411b1037200042003703900220004200370388022000420037038002200042003703f80141c698c00041144187" - "95c0004114200141201020417141a38ac0004125103720004200370390022000420037038802200042003703800220" - "0042003703f801419b95c000412841c698c00041142001412010204171418887c000412110372000200028013c3602" - "dc01200020002901343702d4012000200029012c3702cc01200041808080083602c801200041003b01f801200041c8" - "016a2207411841c698c0004114200141021020417141be80c000410a10372000422a3703e001200420002802a00141" - "01200041e0016a41081000200041003b01f8014102200141021006416f41b481c00041171037200041003b01f80141" - "02200141021009416f41f68ec000411c1037200041003b01f8014101410220014102100a416f41b586c00041171037" - "4102100e416f41eb93c000411910374102100f416f41c395c000411e1037410141021010416f41e195c00041191037" - "41ec91c0004181081005417441fa95c000411f103741ec91c00041c10010054174419996c000411a1037200041003b" - "01f801200241810820014102100b417441a987c00041161037200041003b01f801200241810820014102100c417441" - "aa90c000411b1037200041003b01f8014101200241810820014102100d417441db88c0004116103720024181081011" - "417441b396c000411e103720024181081012417441d196c00041231037410120024181081013417441f496c000411e" - "1037200241810810144174419297c0004116103741b693c00041810841ff92c000410b418a93c000410e1016417441" - "9893c0004109103741b693c000410d41ff92c000418108418a93c000410e10164174419893c0004109103741b693c0" - "00410d41ff92c000410b418a93c00041810810164174419893c00041091037200041003b01f8012002418108200141" - "021015417441c483c00041191037200041003b01f80141c698c00041810841c698c0004114200141021020417441dd" - "82c00041141037200041003b01f80120034114200341142002418108200141021021417441cc86c000411b10372000" - "41003b01f801200741810820034114200141021022417441c389c000411e103741b693c000410d4107200420002802" - "a0011000200042d487b6f4c7d4b1c0003700ec0141b693c000410d4103200041ec95ebdc036a22054108100041b693" - "c000410d4105200420002802a001100020054108200041ec016a220441081023417341a897c0004114103720044108" - "200541081023417341bc97c00041141037200041003b01f80120054108200441082001410241001024417341e08dc0" - "0041141037200041003b01f801200441082005410820014102410010244173418181c00041141037200041003b01f8" - "0120054108200441082001410241001025417341aa80c00041141037200041003b01f8012004410820054108200141" - "0241001025417341e08cc00041141037200041003b01f80120054108200441082001410241001026417341bb84c000" - "41151037200041003b01f80120044108200541082001410241001026417341c98bc00041151037200041003b01f801" - "20054108200441082001410241001027417341a683c00041141037200041003b01f801200441082005410820014102" - "41001027417341c88ac00041141037200041003b01f80120054108410320014102410010284173419488c000411410" - "37200041003b01f8012005410841032001410241001029417341ff85c0004113103720004200370390022000420037" - "0388022000420037038002200042003703f801200341142003411420014120102a417141c088c000411b1037200042" - "003703900220004200370388022000420037038002200042003703f801200341142003411420014120102b417141bc" - "82c00041211037200042003703900220004200370388022000420037038002200042003703f8012003411420034114" - "20014120102c417141928dc000411e1037200042003703900220004200370388022000420037038002200042003703" - "f801200341142003411420014120102d417141928fc000411a10372000420037039002200042003703880220004200" - "37038002200042003703f801200341142003411420014120102e417141b88dc000411b103720004200370390022000" - "4200370388022000420037038002200042003703f80120034114200341142003411420014120102f417141a291c000" - "411c1037200042003703900220004200370388022000420037038002200042003703f8012003411420034114200141" - "201030417141ef81c00041281037200042003703900220004200370388022000420037038002200042003703f80120" - "03411420034114200141201031417141b68fc000411b10372000420037039002200042003703880220004200370380" - "02200042003703f8012003411420034114200141201032417141a989c000411a1037200220002802a0014100100841" - "7141d097c000411b1037200041003b01f80120034114200220002802a001200141021017417141de87c000411a1037" - "200041003b01f801200220002802a001200141021018417141e285c000411d1037200041003b01f801200220002802" - "a001200141021019417141da8ec000411c1037200220002802a001101a417141eb97c000411c1037200220002802a0" - "01101b4171418798c000411f1037200041003602f801200220002802a00120014104101c417141f48dc000411d1037" - "200041003b01f801200220002802a001200141021007417141ff89c00041241037200041808080083602f401200041" - "003b01f801200220002802a001200041f4016a2205410420014102101d417141f48cc000411e1037200041003b01f8" - "01200220002802a00122062003411420022006200141021021417141dd84c00041241037200041003b01f801200341" - "14200220002802a001220620022006200141021021417141cb81c00041241037200041003b01f801200220002802a0" - "0120034114200141021033417141dd83c00041221037200041003b01f80120034114200220002802a0012001410210" - "33417141de8bc00041221037200041003b01f801200220002802a00120034114200141021034417141c880c0004129" - "1037200041003b01f80120034114200220002802a001200141021034417141a08bc00041291037200041003b01f801" - "200220002802a001200141021035417141f887c000411c1037200041003b01f801200220002802a001200541042001" - "4102102a417141f18ac000411f1037200041003b01f801200220002802a00120034114418795c00041142001410210" - "1f4171419286c00041231037200041003b01f80120034114200220002802a001418795c000411420014102101f4171" - "418185c00041231037200041003b01f801200220002802a0012005410420014102102b4171419782c0004125103720" - "0041003b01f80120074118200220002802a001200141021022417141ac8cc00041201037200041003b01f801200220" - "002802a0012005410420014102102c417141c590c00041221037200041003b01f801200220002802a0012005410420" - "014102102d417141e189c000411e1037200041003b01f801200220002802a0012005410420014102102e417141bf87" - "c000411f1037200041003b01f801200220002802a001200341142005410420014102102f417141e786c00041211037" - "200041003b01f80120034114200220002802a0012005410420014102102f4171419a84c00041211037200041003b01" - "f801200220002802a00120054104200141021030417141808cc000412c1037200041003b01f801200220002802a001" - "200141021036417141f78fc00041201037200041003b01f801200220002802a00120054104200141021031417141d8" - "8fc000411f1037200041003b01f801200220002802a00120054104200141021032417141c485c000411e1037200041" - "003b01f801200220002802a00141a698c0004120200141021017417141f182c000411d103741b693c000410d410420" - "0220002802a001100041b6a7abdd03410d410741a698c0004120100041b6a7abdd03410d410320044108100041b6a7" - "abdd03410d410420034114100041b6a7abdd03410d410541cb93c00041081000200220002802a00141072002418108" - "1000200042013703f8012002418108410120014108100041b693c000418108410320044108100041b693c000418108" - "410420034114100041b693c000418108410541cb93c0004108100041b693c000410d4105200220002802a001100020" - "0041003b019e02200220002802a001200341142000419e026a41021022417141f188c000411d103741b693c000410d" - "41e300200220002802a0011000410141004104200341141000200041a0026a240041010f0b000b0bb1180200418080" - "c0000b9b1554455354204641494c4544666c6f61745f66726f6d5f75696e745f6c656e5f6f6f6274785f696e6e6572" - "666c6f61745f7375625f6f6f625f736c69636531616d6d5f69645f6d70746465706f7369745f707265617574685f69" - "645f77726f6e675f73697a655f6163636f756e745f696431706172656e745f6c6467725f68617368666c6f61745f61" - "64645f6f6f625f736c6963653274727573746c696e655f69645f77726f6e675f6c656e5f63757272656e637974785f" - "6669656c645f696e76616c69645f736669656c6463726564656e7469616c5f69645f77726f6e675f73697a655f6163" - "636f756e745f6964327065726d697373696f6e65645f646f6d61696e5f69645f77726f6e675f73697a655f75696e74" - "33326d70745f69737375616e63655f69645f77726f6e675f73697a655f6163636f756e745f69646d70745f69737375" - "616e63655f69645f77726f6e675f73697a655f75696e743332616d6d5f69645f746f6f5f6269675f736c6963656e66" - "745f7572695f77726f6e675f73697a655f6163636f756e745f69646163636f756e74726f6f745f69645f77726f6e67" - "5f6c656e666c6f61745f6469765f6f6f625f736c696365316e66745f73657269616c7368613531325f68616c665f74" - "6f6f5f6269675f736c69636564656c65676174655f69645f77726f6e675f73697a655f6163636f756e745f69643162" - "6173655f6665656c655f6669656c647368613531325f68616c667061796368616e5f69645f77726f6e675f73697a65" - "5f6163636f756e745f696432666c6f61745f6d756c745f6f6f625f736c69636531686f6d655f6c655f696e6e657263" - "726564656e7469616c5f69645f77726f6e675f73697a655f6163636f756e745f69643174727573746c696e655f6964" - "5f77726f6e675f73697a655f6163636f756e745f696432666c6f61745f66726f6d5f75696e745f77726f6e675f6c65" - "6e5f75696e7436347661756c745f69645f77726f6e675f73697a655f6163636f756e745f69646e66745f6973737565" - "725f77726f6e675f73697a655f75696e74323536666c6f61745f706f775f6f6f625f736c69636574727573746c696e" - "655f69645f77726f6e675f73697a655f6163636f756e745f6964316c655f6669656c645f696e76616c69645f736669" - "656c6463726564656e7469616c5f69645f746f6f5f6269675f736c6963657061796368616e5f69645f77726f6e675f" - "73697a655f6163636f756e745f696431616d6d5f69645f6c656e5f77726f6e675f7872705f63757272656e63795f6c" - "656e74785f696e6e65725f746f6f5f6269675f736c6963656f7261636c655f69645f77726f6e675f73697a655f6163" - "636f756e745f69646e66745f7572695f77726f6e675f73697a655f75696e743235366469645f69645f77726f6e675f" - "73697a655f6163636f756e745f6964666c6f61745f726f6f745f6f6f625f736c696365706172656e745f6c6467725f" - "686173685f6e65675f6c656e657363726f775f69645f77726f6e675f73697a655f75696e7433326c655f696e6e6572" - "5f746f6f5f6269675f736c6963656d70746f6b656e5f69645f6d707469645f77726f6e675f6c656e677468616d6d5f" - "69645f6c656e5f77726f6e675f6c656e5f6173736574327661756c745f69645f77726f6e675f73697a655f75696e74" - "33326d70746f6b656e5f69645f746f6f5f6269675f736c6963655f6d707469646f666665725f69645f77726f6e675f" - "73697a655f6163636f756e745f69646163636f756e74726f6f745f69645f77726f6e675f73697a655f6163636f756e" - "745f6964616d6d5f69645f6c656e5f77726f6e675f6e6f6e5f7872705f63757272656e63795f6c656e666c6f61745f" - "6469765f6f6f625f736c69636532616d6d5f69645f6c656e5f6f6f625f617373657432657363726f775f69645f7772" - "6f6e675f73697a655f6163636f756e745f6964706172656e745f6c6467725f74696d656465706f7369745f70726561" - "7574685f69645f77726f6e675f73697a655f6163636f756e745f696432666c6f61745f6d756c745f6f6f625f736c69" - "63653264656c65676174655f69645f77726f6e675f73697a655f6163636f756e745f6964327065726d697373696f6e" - "65645f646f6d61696e5f69645f77726f6e675f73697a655f6163636f756e745f69646d70746f6b656e5f69645f7772" - "6f6e675f73697a655f6163636f756e745f6964636865636b5f69645f6f6f625f6c656e5f753332666c6f61745f7375" - "625f6f6f625f736c69636532636865636b5f69645f77726f6e675f73697a655f6163636f756e745f69646e66745f6f" - "666665725f69645f77726f6e675f73697a655f75696e7433326c655f696e6e65726f7261636c655f69645f77726f6e" - "675f73697a655f75696e743332686f6d655f6c655f6669656c64666c6f61745f6164645f6f6f625f736c696365316e" - "66745f73657269616c5f77726f6e675f73697a655f75696e74323536636865636b5f69645f77726f6e675f6c656e5f" - "7533326163636f756e74726f6f745f69645f6c656e5f6f6f62706172656e745f6c6467725f686173685f6c656e5f74" - "6f6f5f6c6f6e676e66745f7461786f6e5f77726f6e675f73697a655f75696e74323536686f6d655f6c655f6669656c" - "645f696e76616c69645f736669656c646f666665725f69645f77726f6e675f73697a655f75696e7433326e66745f69" - "73737565727469636b65745f69645f77726f6e675f73697a655f75696e7433326e66745f7572697469636b65745f69" - "645f77726f6e675f73697a655f6163636f756e745f69647369676e6572735f69645f77726f6e675f73697a655f6163" - "636f756e745f69646e66745f7461786f6e6c6467725f696e646578686f6d655f6c655f696e6e65725f746f6f5f6269" - "675f736c6963656e66745f6f666665725f69645f77726f6e675f73697a655f6163636f756e745f6964706172656e74" - "5f6c6467725f686173685f6275665f746f6f5f736d616c6c74727573746c696e655f69645f6c656e5f6f6f625f6375" - "7272656e63797061796368616e5f69645f77726f6e675f73697a655f75696e7433326572726f725f636f64653d2424" - "242424205354415254494e47205741534d20455845435554494f4e202424242424746573745f616d656e646d656e74" - "616d656e646d656e745f656e61626c656463616368655f6c6574785f6172725f6c656e686f6d655f6c655f6172725f" - "6c656e6c655f6172725f6c656e74785f696e6e65725f6172725f6c656e686f6d655f6c655f696e6e65725f6172725f" - "6c656e6c655f696e6e65725f6172725f6c656e7365745f6461746174657374206d6573736167657465737420707562" - "6b657974657374207369676e6174757265636865636b5f7369676e66745f666c6167736e66745f786665725f666565" - "74657374696e67207472616365400000000000005f4000000000000000706172656e745f6c6467725f686173685f6e" - "65675f70747274785f6172725f6c656e5f696e76616c69645f736669656c6474785f696e6e65725f6172725f6c656e" - "5f6e65675f70747274785f696e6e65725f6172725f6c656e5f6e65675f6c656e74785f696e6e65725f6172725f6c65" - "6e5f746f6f5f6c6f6e6774785f696e6e65725f6172725f6c656e5f7074725f6f6f6263616368655f6c655f7074725f" - "6f6f6263616368655f6c655f77726f6e675f6c656e55534430303030303030303030303030303030300041c395c000" - "0b8303686f6d655f6c655f6172725f6c656e5f696e76616c69645f736669656c646c655f6172725f6c656e5f696e76" - "616c69645f736669656c64616d656e646d656e745f656e61626c65645f746f6f5f6269675f736c696365616d656e64" - "6d656e745f656e61626c65645f746f6f5f6c6f6e6774785f696e6e65725f6172725f6c656e5f746f6f5f6269675f73" - "6c696365686f6d655f6c655f696e6e65725f6172725f6c656e5f746f6f5f6269675f736c6963656c655f696e6e6572" - "5f6172725f6c656e5f746f6f5f6269675f736c6963657365745f646174615f746f6f5f6269675f736c696365666c6f" - "61745f636d705f6f6f625f736c69636531666c6f61745f636d705f6f6f625f736c6963653263616368655f6c655f77" - "726f6e675f73697a655f75696e743235366e66745f666c6167735f77726f6e675f73697a655f75696e743235366e66" - "745f786665725f6665655f77726f6e675f73697a655f75696e74323536303030303030303030303030303030303030" - "3030303030303030303030303031004d0970726f64756365727302086c616e6775616765010452757374000c70726f" - "6365737365642d6279010572757374631d312e39352e30202835393830373631366520323032362d30342d31342900" - "2c0f7461726765745f6665617475726573022b0f6d757461626c652d676c6f62616c732b087369676e2d657874"; - -extern std::string const kFloatTestsWasmHex = - "0061736d0100000001490960057f7f7f7f7f017f60077f7f7f7f7f7f7f017f60067f7f7f7f7f7f017f60047e7f7f7f" - "017f60057e7f7f7f7f017f60047f7f7f7f017f60037f7f7e017f60037f7f7f006000017f02ea021008686f73745f6c" - "6962057472616365000008686f73745f6c69620e666c6f61745f66726f6d5f696e74000308686f73745f6c69620f66" - "6c6f61745f66726f6d5f75696e74000003656e7613666c6f61745f66726f6d5f6d616e745f657870000408686f7374" - "5f6c696209666c6f61745f636d70000508686f73745f6c696209666c6f61745f616464000108686f73745f6c696209" - "666c6f61745f737562000108686f73745f6c69620a666c6f61745f6d756c74000108686f73745f6c696209666c6f61" - "745f646976000108686f73745f6c696209666c6f61745f706f77000208686f73745f6c69620974726163655f6e756d" - "000608686f73745f6c69620a666c6f61745f726f6f74000203656e760c666c6f61745f746f5f696e74000003656e76" - "11666c6f61745f746f5f6d616e745f657870000203656e7613666c6f61745f66726f6d5f7374616d6f756e74000003" - "656e7613666c6f61745f66726f6d5f73746e756d6265720000030302070805030100110619037f01418080c0000b7f" - "00418599c0000b7f00419099c0000b073504066d656d6f727902000d657363726f775f66696e69736800110a5f5f64" - "6174615f656e6403010b5f5f686561705f6261736503020aec20021f002000200141014100410010001a418080c000" - "41022002410c410110001a0bc920020c7f017e230041f0006b2200240041ee8ac000411d41014100410010001a2000" - "4100360268200042003703600240428ce000200041e0006a2202410c410010012201410c460440418b8bc000411720" - "02101041a28bc000411e2002410c410110001a0c010b41c08bc000411e41014100410010001a0b2000428ce0003703" - "500240200041d0006a4108200041e0006a2202410c41001002410c4604402001410c46210741de8bc0004117200210" - "100c010b41f58bc000411e41014100410010001a0b024042fb004102200041e0006a2201410c41001003410c460440" - "41938cc0004121200110100c010b41b48cc000412841014100410010001a410021070b41dc8cc000411541be80c000" - "101041f18cc0004116418881c0001010418280c000411741014100410010001a200041003602682000420037036002" - "404201200041e0006a2202410c410010012201410c460440419980c000410f200210100c010b41a880c00041164101" - "4100410010001a0b027f200041e0006a410c41be80c000410c100445044041ca80c000411b41014100410010001a20" - "01410c460c010b41e580c000412341014100410010001a41000b21080240200041e0006a410c418881c000410c1004" - "4101460440419481c000412341014100410010001a0c010b4100210841b781c000412c41014100410010001a0b0240" - "418881c000410c200041e0006a410c1004410246044041e381c000412341014100410010001a0c010b410021084186" - "82c000412c41014100410010001a0b419c93c000412041014100410010001a200041c680c000280000360258200041" - "be80c000290000370350410921030340200041d0006a2201410c41be80c000410c2001410c410010051a200341016b" - "22030d000b2000410036026820004200370360420a200041e0006a410c41001001410c46220945044041bc93c00041" - "1741014100410010001a0b0240200041e0006a410c200041d0006a410c100445044041d393c0004114410141004100" - "10001a0c010b4100210941e793c000411641014100410010001a0b410b21030340200041d0006a2201410c41be80c0" - "00410c2001410c410010061a200341016b22030d000b02402001410c418881c000410c100445044041fd93c0004119" - "41014100410010001a0c010b41002109419694c000411b41014100410010001a0b41878dc000411f41014100410010" - "001a2000410036021020004200370308420a200041086a410c410010011a200041c680c000280000360220200041be" - "80c000290000370318410621030340200041186a2201410c200041086a410c2001410c410010071a200341016b2203" - "0d000b200041003602582000420037035042c0843d200041d0006a2202410c410010011a02402002410c2001410c10" - "04220145044041a68dc000411941014100410010001a0c010b41bf8dc000411b41014100410010001a0b200145210a" - "410721030340200041186a2201410c200041086a410c2001410c410010081a200341016b22030d000b200041003602" - "68200042003703604201417f200041e0006a2202410c410010031a02402001410c2002410c100445044041da8dc000" - "411741014100410010001a0c010b41f18dc000411941014100410010001a4100210a0b41b282c00041174101410041" - "0010001a200041003602202000420037031841be80c000410c4103200041186a2202410c410010091a41c982c00041" - "1220021010418881c000410c41062002410c410010091a41db82c00041182002101020004100360258200042003703" - "504209200041d0006a2201410c410010011a2001410c41022002410c410010091a41f382c000411420021010200141" - "0c41002002410c410010091a418783c00041172002101020004100360268200042003703604200200041e0006a2203" - "410c410010011a2003410c41022002410c410010091a419e83c00041142002101041b283c00041382003410c410020" - "02410c41001009ac100a1a41ea83c000411841014100410010001a200041003602202000420037031842092002410c" - "410010011a20004100360258200042003703502002410c41022001410c4100100b1a418284c0004112200110102002" - "410c41032001410c4100100b1a419484c000411220011010200041003602682000420037036042c0843d2003410c41" - "0010011a2003410c41032001410c4100100b1a41a684c0004118200110102003410c41062001410c4100100b1a41be" - "84c000411c2001101041da84c000411a41014100410010001a20004100360258200042003703502000410036026820" - "004200370360420a2003410c410010011a41be80c000410c2003410c2001410c410010081a41f484c0004119200110" - "1041be80c000410c2001410c2001410c410010081a418d85c000410f2001101002402003410c2001410c1004220b45" - "0440419c85c000411441014100410010001a0c010b41b085c000411641014100410010001a0b4100210141c685c000" - "411a41014100410010001a20004200370308024041be80c000410c200041086a41084100100c220241084604402000" - "290308220c42015104404101210141e085c000411741014100410010001a0c020b41f785c000411941014100410010" - "001a419086c0004108200c100a1a0c010b419886c000412441014100410010001a41bc86c000410f2002ac100a1a0b" - "410021030240418881c000410c200041086a41084100100c220241084604402000290308220c427f51044041cb86c0" - "00411841014100410010001a200121030c020b41e386c000411a41014100410010001a419086c0004108200c100a1a" - "0c010b41fd86c000412541014100410010001a41bc86c000410f2002ac100a1a0b4100210120004100360220200042" - "0037031842ffffffffffffffffff00200041186a2202410c410010011a02402002410c200041086a41084100100c22" - "0241084604402000290308220c42ffffffffffffffffff0051044041a287c000411e41014100410010001a20032101" - "0c020b41c087c000412041014100410010001a41e087c000410d42ffffffffffffffffff00100a1a419086c0004108" - "200c100a1a0c010b41ed87c000412b41014100410010001a41bc86c000410f2002ac100a1a0b410021022000410036" - "0258200042003703504200200041d0006a2203410c410010011a02402003410c200041086a41084100100c22034108" - "4604402000290308220c500440419888c000411741014100410010001a200121020c020b41af88c000411941014100" - "410010001a419086c0004108200c100a1a0c010b41c888c000412441014100410010001a41bc86c000410f2003ac10" - "0a1a0b4100210320004100360268200042003703604201417f200041e0006a2201410c410010031a02402001410c20" - "0041086a41084100100c220141084604402000290308220c50044041ec88c000412541014100410010001a20022103" - "0c020b419189c000412741014100410010001a419086c0004108200c100a1a0c010b41b889c0004132410141004100" - "10001a41bc86c000410f2001ac100a1a0b0240200041e0006a410c200041086a41084101100c220141084604402000" - "290308220c50044041ea89c000412741014100410010001a0c020b4100210341918ac000412941014100410010001a" - "419086c0004108200c100a1a0c010b4100210341ba8ac000413441014100410010001a41bc86c000410f2001ac100a" - "1a0b41002101418a8ec000411f41014100410010001a2000420037032820004100360234024041be80c000410c2000" - "41286a4108200041346a4104100d2202410c46044020002802342202416e462000290328220c42808090bbbad6adf0" - "0d517145044041c58ec000411e41014100410010001a41e38ec000412f200c100a1a41928fc000411f2002ac100a1a" - "0c020b4101210141a98ec000411c41014100410010001a0c010b41b18fc000412941014100410010001a41bc86c000" - "410f2002ac100a1a0b2000420037033841002102200041003602440240418881c000410c200041386a4108200041c4" - "006a4104100d2204410c46044020002802442204416e462000290338220c428080f0c4c5a9d28f72517145044041f7" - "8fc000411f41014100410010001a419690c0004130200c100a1a41928fc000411f2004ac100a1a0c020b41da8fc000" - "411d41014100410010001a200121020c010b41c690c000412a41014100410010001a41bc86c000410f2004ac100a1a" - "0b410021012000410036025820004200370350420a200041d0006a2204410c410010011a2000420037030820004100" - "36024802402004410c200041086a4108200041c8006a4104100d2204410c46044020002802482204416f4620002903" - "08220c42808090bbbad6adf00d5171450440418d91c000411f41014100410010001a41e38ec000412f200c100a1a41" - "ac91c000411f2004ac100a1a0c020b41f090c000411d41014100410010001a200221010c010b41cb91c000412a4101" - "4100410010001a41bc86c000410f2004ac100a1a0b4100210220004100360268200042003703604200200041e0006a" - "2204410c410010011a200042003703182000410036024c02402004410c200041186a4108200041cc006a4104100d22" - "04410c4604402000290318220c50200028024c22044180808080784671450440419192c000411e4101410041001000" - "1a41af92c000411d200c100a1a41cc92c00041272004ac100a1a0c020b41f591c000411c41014100410010001a2001" - "21020c010b41f392c000412941014100410010001a41bc86c000410f2004ac100a1a0b4100210141b194c000412141" - "014100410010001a200042c0808080d0a0fdf000370018200041003602682000420037036002400240200041186a41" - "08200041e0006a2205410c4100100e2204410c46044041d294c000412220051010200042003703502005410c200041" - "d0006a41084100100c22044108470d012000290350220c4280c2d72f5104404101210141f494c000411d4101410041" - "0010001a0c030b419195c000411f41014100410010001a41b095c000411c200c100a1a0c020b418096c000411f4101" - "4100410010001a419f96c00041102004ac100a1a0c010b41cc95c000413441014100410010001a41bc86c000410f20" - "04ac100a1a0b4100210441af96c000412141014100410010001a200041ffffff8f7f36005820004281eceedce494cc" - "f9c000370050200041003602682000420037036002400240200041d0006a410c200041e0006a2206410c4100100f22" - "05410c46044041d096c000411c20061010200042003703182006410c200041186a41084100100c22054108470d0120" - "00290318220c42fb005104404101210441ec96c000411b41014100410010001a0c030b418797c000411d4101410041" - "0010001a41a497c0004116200c100a1a0c020b41ec97c000411d41014100410010001a419f96c00041102005ac100a" - "1a0c010b41ba97c000413241014100410010001a41bc86c000410f2005ac100a1a0b41002105024041be80c000410c" - "200041e0006a2206410c4100100f410c460440418998c000411a200610102006410c41be80c000410c100445044041" - "a398c000412041014100410010001a200421050c020b41c398c000412241014100410010001a0c010b41e598c00041" - "2041014100410010001a0b200041f0006a2400200b452007200871200971200a71200371200271200171200571710b" - "0b8f190100418080c0000b851920200a24242420746573745f666c6f61745f636d70202424242020666c6f61742066" - "726f6d20313a2020666c6f61742066726f6d20313a206661696c65640de0b6b3a7640000ffffffee2020666c6f6174" - "2066726f6d2031203d3d20464c4f41545f4f4e452020666c6f61742066726f6d203120213d20464c4f41545f4f4e45" - "2c206661696c6564f21f494c589c0000ffffffee2020666c6f61742066726f6d2031203e20464c4f41545f4e454741" - "544956455f4f4e452020666c6f61742066726f6d203120213e20464c4f41545f4e454741544956455f4f4e452c2066" - "61696c65642020464c4f41545f4e454741544956455f4f4e45203c20666c6f61742066726f6d20312020464c4f4154" - "5f4e454741544956455f4f4e4520213c20666c6f61742066726f6d20312c206661696c65640a24242420746573745f" - "666c6f61745f706f77202424242020666c6f61742063756265206f6620313a2020666c6f61742036746820706f7765" - "72206f66202d313a2020666c6f617420737175617265206f6620393a2020666c6f61742030746820706f776572206f" - "6620393a2020666c6f617420737175617265206f6620303a2020666c6f61742030746820706f776572206f66203020" - "28657870656374696e6720494e56414c49445f504152414d53206572726f72293a0a24242420746573745f666c6f61" - "745f726f6f74202424242020666c6f61742073717274206f6620393a2020666c6f61742063627274206f6620393a20" - "20666c6f61742063627274206f6620313030303030303a2020666c6f61742036746820726f6f74206f662031303030" - "3030303a0a24242420746573745f666c6f61745f696e76657274202424242020696e76657274206120666c6f617420" - "66726f6d2031303a2020696e7665727420616761696e3a2020696e766572742074776963653a20676f6f642020696e" - "766572742074776963653a206661696c65640a24242420746573745f666c6f61745f746f5f696e7420242424202066" - "6c6f61745f746f5f696e742831293a20676f6f642020666c6f61745f746f5f696e742831293a206661696c65642020" - "2020676f743a2020666c6f61745f746f5f696e742831293a206661696c65642077697468206572726f722020202065" - "72726f7220636f64653a2020666c6f61745f746f5f696e74282d31293a20676f6f642020666c6f61745f746f5f696e" - "74282d31293a206661696c65642020666c6f61745f746f5f696e74282d31293a206661696c65642077697468206572" - "726f722020666c6f61745f746f5f696e74286936343a3a4d4158293a20676f6f642020666c6f61745f746f5f696e74" - "286936343a3a4d4158293a206661696c65642020202065787065637465643a2020666c6f61745f746f5f696e742869" - "36343a3a4d4158293a206661696c65642077697468206572726f722020666c6f61745f746f5f696e742830293a2067" - "6f6f642020666c6f61745f746f5f696e742830293a206661696c65642020666c6f61745f746f5f696e742830293a20" - "6661696c65642077697468206572726f722020666c6f61745f746f5f696e7428302e312c20746f5f6e656172657374" - "293a20676f6f642020666c6f61745f746f5f696e7428302e312c20746f5f6e656172657374293a206661696c656420" - "20666c6f61745f746f5f696e7428302e312c20746f5f6e656172657374293a206661696c6564207769746820657272" - "6f722020666c6f61745f746f5f696e7428302e312c20746f77617264735f7a65726f293a20676f6f642020666c6f61" - "745f746f5f696e7428302e312c20746f77617264735f7a65726f293a206661696c65642020666c6f61745f746f5f69" - "6e7428302e312c20746f77617264735f7a65726f293a206661696c65642077697468206572726f720a242424207465" - "73745f666c6f61745f66726f6d5f7761736d202424242020666c6f61742066726f6d206936342031323330303a2020" - "666c6f61742066726f6d20693634203132333030206173204845583a2020666c6f61742066726f6d20693634203132" - "3330303a206661696c65642020666c6f61742066726f6d207536342031323330303a2020666c6f61742066726f6d20" - "7536342031323330303a206661696c65642020666c6f61742066726f6d2065787020322c206d616e74697373612031" - "32333a2020666c6f61742066726f6d2065787020322c206d616e7469737361203132333a206661696c65642020666c" - "6f61742066726f6d20636f6e737420313a2020666c6f61742066726f6d20636f6e7374202d313a0a24242420746573" - "745f666c6f61745f6d756c745f6469766964652024242420207265706561746564206d756c7469706c793a20676f6f" - "6420207265706561746564206d756c7469706c793a206661696c656420207265706561746564206469766964653a20" - "676f6f6420207265706561746564206469766964653a206661696c65640a24242420746573745f666c6f61745f746f" - "5f6d616e745f657870202424242020666c6f61745f746f5f6d616e745f6578702831293a20676f6f642020666c6f61" - "745f746f5f6d616e745f6578702831293a206661696c6564202020206578706563746564206d616e74697373612031" - "3030303030303030303030303030303030302c20676f743a202020206578706563746564206578706f6e656e74202d" - "31382c20676f743a2020666c6f61745f746f5f6d616e745f6578702831293a206661696c6564207769746820657272" - "6f722020666c6f61745f746f5f6d616e745f657870282d31293a20676f6f642020666c6f61745f746f5f6d616e745f" - "657870282d31293a206661696c6564202020206578706563746564206d616e7469737361202d313030303030303030" - "303030303030303030302c20676f743a2020666c6f61745f746f5f6d616e745f657870282d31293a206661696c6564" - "2077697468206572726f722020666c6f61745f746f5f6d616e745f657870283130293a20676f6f642020666c6f6174" - "5f746f5f6d616e745f657870283130293a206661696c6564202020206578706563746564206578706f6e656e74202d" - "31372c20676f743a2020666c6f61745f746f5f6d616e745f657870283130293a206661696c65642077697468206572" - "726f722020666c6f61745f746f5f6d616e745f6578702830293a20676f6f642020666c6f61745f746f5f6d616e745f" - "6578702830293a206661696c6564202020206578706563746564206d616e746973736120302c20676f743a20202020" - "6578706563746564206578706f6e656e74202d323134373438333634382c20676f743a2020666c6f61745f746f5f6d" - "616e745f6578702830293a206661696c65642077697468206572726f720a24242420746573745f666c6f61745f6164" - "645f7375627472616374202424242020666c6f61742066726f6d2031303a206661696c656420207265706561746564" - "206164643a20676f6f6420207265706561746564206164643a206661696c6564202072657065617465642073756274" - "726163743a20676f6f64202072657065617465642073756274726163743a206661696c65640a24242420746573745f" - "666c6f61745f66726f6d5f7374616d6f756e74202424242020666c6f61742066726f6d2058525020616d6f756e7420" - "2831303020585250293a202058525020616d6f756e7420636f6e76657273696f6e3a20676f6f64202058525020616d" - "6f756e7420636f6e76657273696f6e3a206661696c6564202020206578706563746564203130303030303030302c20" - "676f743a202058525020616d6f756e7420636f6e76657273696f6e3a206661696c6564202d20666c6f61745f746f5f" - "696e74206572726f722020666c6f61742066726f6d2058525020616d6f756e743a206661696c656420202020726573" - "756c745f73697a653a0a24242420746573745f666c6f61745f66726f6d5f73746e756d626572202424242020666c6f" - "61742066726f6d2053544e756d6265722028313233293a202053544e756d62657220636f6e76657273696f6e3a2067" - "6f6f64202053544e756d62657220636f6e76657273696f6e3a206661696c6564202020206578706563746564203132" - "332c20676f743a202053544e756d62657220636f6e76657273696f6e3a206661696c6564202d20666c6f61745f746f" - "5f696e74206572726f722020666c6f61742066726f6d2053544e756d6265723a206661696c65642020666c6f617420" - "66726f6d2053544e756d626572202831293a202053544e756d626572283129203d3d20464c4f41545f4f4e453a2067" - "6f6f64202053544e756d626572283129203d3d20464c4f41545f4f4e453a206661696c65642020666c6f6174206672" - "6f6d2053544e756d6265722831293a206661696c6564004d0970726f64756365727302086c616e6775616765010452" - "757374000c70726f6365737365642d6279010572757374631d312e39352e3020283539383037363136652032303236" - "2d30342d313429002c0f7461726765745f6665617475726573022b0f6d757461626c652d676c6f62616c732b087369" - "676e2d657874"; - -extern std::string const kFloat0Hex = - "0061736d0100000001290560057f7f7f7f7f017f60047e7f7f7f017f60077f7f7f7f7f7f7f017f60047f7f7f7f017f" - "6000017f02560408686f73745f6c6962057472616365000008686f73745f6c69620e666c6f61745f66726f6d5f696e" - "74000108686f73745f6c696209666c6f61745f737562000208686f73745f6c696209666c6f61745f636d7000030302" - "010405030100110619037f01418080c0000b7f0041e980c0000b7f0041f080c0000b073504066d656d6f727902000d" - "657363726f775f66696e69736800040a5f5f646174615f656e6403010b5f5f686561705f6261736503020acc0101c9" - "0101027f230041206b22002400418080c000411541014100410010001a200041003602082000420037030020004100" - "3602182000420037031002400240420a2000410c41001001410c4604402000410c2000410c200041106a2201410c41" - "001002410c470d012001410c419580c000410c100345044041a180c000411a41014100410010001a0c030b41bb80c0" - "00411941014100410010001a0c020b41d480c000411541014100410010001a0c010b41d480c0004115410141004100" - "10001a0b200041206a240041010b0b720100418080c0000b690a24242420746573745f666c6f61745f302024242400" - "00000000000000800000002020464c4f41545f5a45524f20636f6d706172653a20676f6f642020464c4f41545f5a45" - "524f20636f6d706172653a206261642020666c6f61742031302d31303a206661696c6564004d0970726f6475636572" - "7302086c616e6775616765010452757374000c70726f6365737365642d6279010572757374631d312e39352e302028" - "35393830373631366520323032362d30342d313429002c0f7461726765745f6665617475726573022b0f6d75746162" - "6c652d676c6f62616c732b087369676e2d657874"; - -extern std::string const kDisabledFloatHex = - "0061736d010000000108026000006000017f03030200010503010002063e0a7f004180080b7f004180080b7f004180" - "100b7f004180100b7f00418090040b7f004180080b7f00418090040b7f00418080080b7f0041000b7f0041010b07b7" - "010d066d656d6f72790200115f5f7761736d5f63616c6c5f63746f727300000d657363726f775f66696e6973680001" - "0362756603000c5f5f64736f5f68616e646c6503010a5f5f646174615f656e6403020b5f5f737461636b5f6c6f7703" - "030c5f5f737461636b5f6869676803040d5f5f676c6f62616c5f6261736503050b5f5f686561705f6261736503060a" - "5f5f686561705f656e6403070d5f5f6d656d6f72795f6261736503080c5f5f7461626c655f6261736503090a150202" - "000b100043000000c54300200045931a41010b"; - -extern std::string const kMemoryPointerAtLimitHex = - "0061736d010000000105016000017f0302010005030100010711010d657363726f775f66696e69736800000a0e010c" - "0041ffff032d00001a41010b"; - -extern std::string const kMemoryPointerOverLimitHex = - "0061736d010000000105016000017f0302010005030100010711010d657363726f775f66696e69736800000a0e010c" - "00418080042d00001a41010b"; - -extern std::string const kMemoryOffsetOverLimitHex = - "0061736d010000000105016000017f030201000503010001071a02066d656d6f727902000d657363726f775f66696e" - "69736800000a0e010c00410028028080041a41010b"; - -extern std::string const kMemoryEndOfWordOverLimitHex = - "0061736d010000000105016000017f030201000503010001071a02066d656d6f727902000d657363726f775f66696e" - "69736800000a0e010c0041feff032802001a41010b"; - -extern std::string const kMemoryGrow0To1PageHex = - "0061736d010000000105016000017f030201000503010000071a02066d656d6f727902000d657363726f775f66696e" - "69736800000a0b010900410140001a41010b"; - -extern std::string const kMemoryGrow1To0PageHex = - "0061736d010000000105016000017f030201000503010001071a02066d656d6f727902000d657363726f775f66696e" - "69736800000a13011100417f4000417f460440417f0f0b41010b"; - -extern std::string const kMemoryLastByteOf8MbHex = - "0061736d010000000105016000017f030201000506010180018001071a02066d656d6f727902000d657363726f775f" - "66696e69736800000a0f010d0041ffffff032d00001a41010b"; - -extern std::string const kMemoryGrow1MoreThan8MbHex = - "0061736d010000000105016000017f03020100050401008001071a02066d656d6f727902000d657363726f775f6669" - "6e69736800000a1301110041014000417f460440417f0f0b41010b"; - -extern std::string const kMemoryGrow0MoreThan8MbHex = - "0061736d010000000105016000017f03020100050401008001071a02066d656d6f727902000d657363726f775f6669" - "6e69736800000a1301110041004000417f460440417f0f0b41010b"; - -extern std::string const kMemoryInit1MoreThan8MbHex = - "0061736d010000000105016000017f030201000506010181018101071a02066d656d6f727902000d657363726f775f" - "66696e69736800000a0f010d0041ffffff032d00001a41010b"; - -extern std::string const kMemoryNegativeAddressHex = - "0061736d010000000105016000017f030201000506010180018001071a02066d656d6f727902000d657363726f775f" - "66696e69736800000a0c010a00417f2d00001a41010b"; - -extern std::string const kTable64ElementsHex = - "0061736d010000000108026000006000017f03030200010404017000400711010d657363726f775f66696e69736800" - "010946010041000b400000000000000000000000000000000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000000a090202000b040041010b"; - -extern std::string const kTable65ElementsHex = - "0061736d010000000108026000006000017f03030200010404017000410711010d657363726f775f66696e69736800" - "010947010041000b410000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000a090202000b040041010b"; - -extern std::string const kTable2TablesHex = - "0061736d010000000108026000006000017f030302000104090270010101700101010711010d657363726f775f6669" - "6e6973680001090f020041000b0100020141000b0001000a090202000b040041010b"; - -extern std::string const kTable0ElementsHex = - "0061736d010000000105016000017f030201000404017000000711010d657363726f775f66696e69736800000a0601" - "040041010b"; - -extern std::string const kTableUintMaxHex = - "0061736d010000000105016000017f030201000408017000ffffffff0f0711010d657363726f775f66696e69736800" - "000a0601040041010b"; - -extern std::string const kProposalMutableGlobalHex = - "0061736d010000000105016000017f030201000606017f0141000b071b0207636f756e74657203000d657363726f77" - "5f66696e69736800000a0d010b00230041016a240041010b"; - -extern std::string const kProposalGcStructNewHex = - "0061736d01000000010b026000017f5f027f017f01030201000711010d657363726f775f66696e69736800000a0a01" - "0800fb01011a41010b"; - -extern std::string const kProposalMultiValueHex = - "0061736d010000000110036000027f7f6000017f60027f7f017f03030200010711010d657363726f775f66696e6973" - "6800010a14020600410a41140b0b00100002026a411e460b0b"; - -extern std::string const kProposalSignExtHex = - "0061736d010000000105016000017f030201000711010d657363726f775f66696e69736800000a0b01090041ff01c0" - "417f460b"; - -extern std::string const kProposalFloatToIntHex = - "0061736d010000000105016000017f030201000711010d657363726f775f66696e69736800000a1201100043f90215" - "50fc0041ffffffff07460b"; - -extern std::string const kProposalBulkMemoryHex = - "0061736d010000000105016000017f030201000503010001071a02066d656d6f727902000d657363726f775f66696e" - "69736800000a1f011d004100412a3a000041e40041004101fc0a000041e4002d0000412a460b"; - -extern std::string const kProposalRefTypesHex = - "0061736d010000000105016000017f020f0103656e76057461626c65016f0001030201000711010d657363726f775f" - "66696e69736800000a0c010a004100d06f260041010b"; - -extern std::string const kProposalTailCallHex = - "0061736d010000000105016000017f03030200000711010d657363726f775f66696e69736800010a0b02040041010b" - "040012000b"; - -extern std::string const kProposalExtendedConstHex = - "0061736d010000000105016000017f030201000609017f00410a41206a0b0711010d657363726f775f66696e697368" - "00000a090107002300412a460b"; - -extern std::string const kProposalMultiMemoryHex = - "0061736d010000000105016000017f03020100050502000000010711010d657363726f775f66696e69736800000a06" - "0104003f010b"; - -extern std::string const kProposalCustomPageSizesHex = - "0061736d010000000105016000017f030201000504010801000711010d657363726f775f66696e69736800000a0601" - "040041010b"; - -extern std::string const kProposalMemory64Hex = - "0061736d010000000105016000017f0302010005030104010711010d657363726f775f66696e69736800000a10010e" - "004200412a3a00003f004201510b"; - -extern std::string const kProposalWideArithmeticHex = - "0061736d010000000105016000017f030201000711010d657363726f775f66696e69736800000a0e010c0042014202" - "fc161a1a41010b"; - -extern std::string const kTrapDivideBy0Hex = - "0061736d010000000105016000017f030201000711010d657363726f775f66696e69736800000a0c010a00412a4100" - "6d1a41010b"; - -extern std::string const kTrapIntOverflowHex = - "0061736d010000000105016000017f030201000711010d657363726f775f66696e69736800000a0d010b0041808080" - "8078417f6d0b"; - -extern std::string const kTrapUnreachableHex = - "0061736d010000000105016000017f030201000711010d657363726f775f66696e69736800000a070105000041010" - "b"; - -extern std::string const kTrapNullCallHex = - "0061736d010000000105016000017f030201000404017000010711010d657363726f775f66696e69736800000a0901" - "070041001100000b"; - -extern std::string const kTrapFuncSigMismatchHex = - "0061736d010000000108026000006000017f03030200010404017000010711010d657363726f775f66696e69736800" - "010907010041000b01000a0d020300010b070041001101000b"; - -extern std::string const kWasiGetTimeHex = - "0061736d01000000010c0260037f7e7f017f6000017f02290116776173695f736e617073686f745f70726576696577" - "310e636c6f636b5f74696d655f6765740000030201010503010001071a02066d656d6f727902000d657363726f775f" - "66696e69736800010a16011400410042e8074100100045047f410105417f0b0b"; - -extern std::string const kWasiPrintHex = - "0061736d01000000010d0260047f7f7f7f017f6000017f02230116776173695f736e617073686f745f707265766965" - "77310866645f77726974650000030201010503010001071a02066d656d6f727902000d657363726f775f66696e6973" - "6800010a1d011b01017f411821004101410041012000100045047f410105417f0b0b0b1e030041100b0648656c6c6f" - "0a0041000b04100000000041040b0406000000"; - -// The following several wasm hex strings are for testing wasm section -// corruption cases. They are illegal hence do not have corresponding -// rust or wat sources. -// Wasm code magic number is "0061736d", and the only valid version is 1. - -extern std::string const kBadMagicNumberHex = "1061736d01000000"; -extern std::string const kBadVersionNumberHex = "0061736d02000000"; - -// Corruption Test: lyingHeader -// Scenario: A section declares it is 2GB long, but the file ends immediately. -// Attack: Buffer pre-allocation DoS (OOM). -// # Magic (00 61 73 6d) + Version (01 00 00 00) -// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' -// # Type Section (ID 1) -// # Size: LEB128 encoded 2GB (0x80 0x80 0x80 0x80 0x08) -// data += b'\x01\x80\x80\x80\x80\x08' -extern std::string const kLyingHeaderHex = "0061736d01000000018080808008"; - -// Corruption Test: neverEndingNumber -// Scenario: An LEB128 integer that never has a stop bit (byte < 0x80). -// Attack: Infinite loop in parser or read out of bounds. -// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' -// # Type Section (ID 1), Size 5 -// data += b'\x01\x05' -// # Vector count: Infinite stream of 0x80 (100 bytes) -// data += b'\x80' * 100 -extern std::string const kNeverEndingNumberHex = - "0061736d01000000010580808080808080808080808080808080808080808080808080808080808080808080808080" - "8080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080" - "80808080808080808080808080808080"; - -// Corruption Test: vectorLie -// Scenario: A vector declares it has 4 billion items, but provides none. -// Attack: Vector pre-allocation DoS (OOM). -// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' -// # Type Section (ID 1) -// # Size 5 (just enough for the count bytes) -// data += b'\x01\x05' -// # Vector Count: 0xFF 0xFF 0xFF 0xFF 0x0F (4,294,967,295 items) -// data += b'\xff\xff\xff\xff\x0f' -// # No actual items follow... -extern std::string const kVectorLieHex = "0061736d010000000105ffffffff0f"; - -// Corruption Test: sectionOrdering -// Scenario: Sections appear out of order -// (Code section before Function section). -// Attack: Parser state confusion / potential null pointer deref. -// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' -// # Code Section (ID 10) - usually last -// # Size 2, Count 0 -// data += b'\x0a\x02\x00\x0b' -// # Function Section (ID 3) - usually 3rd -// data += b'\x03\x02\x00\x00' -extern std::string const kSectionOrderingHex = "0061736d010000000a02000b03020000"; - -// Corruption Test: ghostPayload -// Scenario: Valid headers, but file is truncated in the middle of a payload. -// Attack: Read out of bounds panic. -// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' -// # Type Section (ID 1), Size 10 -// data += b'\x01\x0a' -// # Content: Count 1 -// data += b'\x01' -// # Start of a type definition (0x60 = func) -// data += b'\x60' -// # File ends abruptly here (missing params/results) -extern std::string const kGhostPayloadHex = "0061736d01000000010a0160"; - -// Corruption Test: junkAfterSection -// Scenario: Section declares size X, but logical content finishes at X-5. -// Attack: Validation bypass if parser stops early, -// or panic if strict check missing. -// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' -// # Type Section (ID 1), Size 10 bytes -// data += b'\x01\x0a' -// # Real content: Count 1, (func -> void) = 4 bytes -// # \x01 (count) \x60 (func) \x00 (0 params) \x00 (0 results) -// data += b'\x01\x60\x00\x00' -// # Remaining 6 bytes are junk padding within the section size -// data += b'\x00' * 6 -extern std::string const kJunkAfterSectionHex = "0061736d01000000010a01600000000000000000"; - -// Corruption Test: invalidSectionId -// Scenario: A section ID that doesn't exist (0xFF). -// Attack: Default case handling / unhandled enum variant. -// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' -// # Section ID 0xFF, Size 1 -// data += b'\xff\x01\x00' -extern std::string const kInvalidSectionIdHex = "0061736d01000000ff0100"; - -// Corruption Test: localVariableBomb -// Scenario: A function declares 4 billion local variables. -// Attack: Stack Overflow / OOM during function init (memset). -// data = b'\x00\x61\x73\x6d\x01\x00\x00\x00' -// # 1. Type Section: (func) -> () -// data += b'\x01\x04\x01\x60\x00\x00' -// # 3. Function Section: 1 function of type 0 -// data += b'\x03\x02\x01\x00' -// # 10. Code Section -// # ID 10, Size 15 (estimated), Count 1 -// data += b'\x0a\x0f\x01' -// # Function Body Size: 13 bytes -// data += b'\x0d' -// # Local Declarations Count: 1 entry -// data += b'\x01' -// # The Bomb: 4,294,967,295 locals of type i32 -// # Count: 0xFF 0xFF 0xFF 0xFF 0x0F -// # Type: 0x7F (i32) -// data += b'\xff\xff\xff\xff\x0f\x7f' -// # Instruction: end (0x0b) -// data += b'\x0b' -extern std::string const kLocalVariableBombHex = - "0061736d01000000010401600000030201000a0f010d01ffffffff0f7f0b"; - -extern std::string const kInfiniteLoopWasmHex = - "0061736d010000000108026000006000017f030302000105030100020638097f004180080b7f004180080b7f004180" - "080b7f00418088040b7f004180080b7f00418088040b7f00418080080b7f0041000b7f0041010b07a8010c066d656d" - "6f72790200115f5f7761736d5f63616c6c5f63746f72730000046c6f6f7000010c5f5f64736f5f68616e646c650300" - "0a5f5f646174615f656e6403010b5f5f737461636b5f6c6f7703020c5f5f737461636b5f6869676803030d5f5f676c" - "6f62616c5f6261736503040b5f5f686561705f6261736503050a5f5f686561705f656e6403060d5f5f6d656d6f7279" - "5f6261736503070c5f5f7461626c655f6261736503080a270202000b220041fc87044100360200034041fc870441fc" - "870428020041016a3602000c000b000b007f0970726f647563657273010c70726f6365737365642d62790105636c61" - "6e675f31392e312e352d776173692d73646b202868747470733a2f2f6769746875622e636f6d2f6c6c766d2f6c6c76" - "6d2d70726f6a6563742061623462356132646235383239353861663165653330386137393063666462343262643234" - "3732302900490f7461726765745f6665617475726573042b0f6d757461626c652d676c6f62616c732b087369676e2d" - "6578742b0f7265666572656e63652d74797065732b0a6d756c746976616c7565"; - -extern std::string const kStartLoopHex = - "0061736d010000000108026000006000017f030302000107190205737461727400000d657363726f775f66696e6973" - "6800010801000a0e02070003400c000b0b040041010b"; - -extern std::string const kBadAlignWasmHex = - "0061736d01000000011b046000017f60057f7f7f7f7f017f60067f7f7f7f7f7f017f60000002260203656e760f666c" - "6f61745f66726f6d5f75696e74000103656e7608636865636b5f6964000203050403000000050301000306470b7f00" - "4180080b7f00418088020b7f004180080b7f00418088040b7f00418088040b7f00418088080b7f004180080b7f0041" - "8088080b7f004180800c0b7f0041000b7f0041010b07cc0110066d656d6f72790200115f5f7761736d5f63616c6c5f" - "63746f72730002057465737431000307655f64617461310300057465737432000407655f6461746132030104746573" - "7400050c5f5f64736f5f68616e646c6503020a5f5f646174615f656e6403030b5f5f737461636b5f6c6f7703040c5f" - "5f737461636b5f6869676803050d5f5f676c6f62616c5f6261736503060b5f5f686561705f6261736503070a5f5f68" - "6561705f656e6403080d5f5f6d656d6f72795f6261736503090c5f5f7461626c655f62617365030a0a99020402000b" - "2801017f418108427f370000418108410841a308410c41001000220041a40828020020004100481b0b5f01017f419a" - "88024191a4cca00136010041928802428994ace0d0c1c38710370100418a88024281848ca0d0c0c183083701004181" - "8802417f360000418a8802411441818802410441a3880241201001220041a4880228020020004100481b0b8a010103" - "7f418108427f370000418108410841a308410c410010002100419a88024191a4cca00136010041928802428994ace0" - "d0c1c38710370100418a88024281848ca0d0c0c1830837010041818802417f36000041a4082802002101418a880241" - "1441818802410441a3880241201001220241a4880228020020024100481b2000200120004100481b6a0b007f097072" - "6f647563657273010c70726f6365737365642d62790105636c616e675f31392e312e352d776173692d73646b202868" - "747470733a2f2f6769746875622e636f6d2f6c6c766d2f6c6c766d2d70726f6a656374206162346235613264623538" - "32393538616631656533303861373930636664623432626432343732302900490f7461726765745f66656174757265" - "73042b0f6d757461626c652d676c6f62616c732b087369676e2d6578742b0f7265666572656e63652d74797065732b" - "0a6d756c746976616c7565"; - -extern std::string const kThousandParamsHex = - "0061736d0100000001f1070260000060e8077f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f017f030302000105030100020638097f" - "004180080b7f004180080b7f004180080b7f00418088040b7f004180080b7f00418088040b7f00418080080b7f0041" - "000b7f0041010b07a8010c066d656d6f72790200115f5f7761736d5f63616c6c5f63746f7273000004746573740001" - "0c5f5f64736f5f68616e646c6503000a5f5f646174615f656e6403010b5f5f737461636b5f6c6f7703020c5f5f7374" - "61636b5f6869676803030d5f5f676c6f62616c5f6261736503040b5f5f686561705f6261736503050a5f5f68656170" - "5f656e6403060d5f5f6d656d6f72795f6261736503070c5f5f7461626c655f6261736503080aa71e0202000ba11e00" - "200020016a20026a20036a20046a20056a20066a20076a20086a20096a200a6a200b6a200c6a200d6a200e6a200f6a" - "20106a20116a20126a20136a20146a20156a20166a20176a20186a20196a201a6a201b6a201c6a201d6a201e6a201f" - "6a20206a20216a20226a20236a20246a20256a20266a20276a20286a20296a202a6a202b6a202c6a202d6a202e6a20" - "2f6a20306a20316a20326a20336a20346a20356a20366a20376a20386a20396a203a6a203b6a203c6a203d6a203e6a" - "203f6a20406a20416a20426a20436a20446a20456a20466a20476a20486a20496a204a6a204b6a204c6a204d6a204e" - "6a204f6a20506a20516a20526a20536a20546a20556a20566a20576a20586a20596a205a6a205b6a205c6a205d6a20" - "5e6a205f6a20606a20616a20626a20636a20646a20656a20666a20676a20686a20696a206a6a206b6a206c6a206d6a" - "206e6a206f6a20706a20716a20726a20736a20746a20756a20766a20776a20786a20796a207a6a207b6a207c6a207d" - "6a207e6a207f6a2080016a2081016a2082016a2083016a2084016a2085016a2086016a2087016a2088016a2089016a" - "208a016a208b016a208c016a208d016a208e016a208f016a2090016a2091016a2092016a2093016a2094016a209501" - "6a2096016a2097016a2098016a2099016a209a016a209b016a209c016a209d016a209e016a209f016a20a0016a20a1" - "016a20a2016a20a3016a20a4016a20a5016a20a6016a20a7016a20a8016a20a9016a20aa016a20ab016a20ac016a20" - "ad016a20ae016a20af016a20b0016a20b1016a20b2016a20b3016a20b4016a20b5016a20b6016a20b7016a20b8016a" - "20b9016a20ba016a20bb016a20bc016a20bd016a20be016a20bf016a20c0016a20c1016a20c2016a20c3016a20c401" - "6a20c5016a20c6016a20c7016a20c8016a20c9016a20ca016a20cb016a20cc016a20cd016a20ce016a20cf016a20d0" - "016a20d1016a20d2016a20d3016a20d4016a20d5016a20d6016a20d7016a20d8016a20d9016a20da016a20db016a20" - "dc016a20dd016a20de016a20df016a20e0016a20e1016a20e2016a20e3016a20e4016a20e5016a20e6016a20e7016a" - "20e8016a20e9016a20ea016a20eb016a20ec016a20ed016a20ee016a20ef016a20f0016a20f1016a20f2016a20f301" - "6a20f4016a20f5016a20f6016a20f7016a20f8016a20f9016a20fa016a20fb016a20fc016a20fd016a20fe016a20ff" - "016a2080026a2081026a2082026a2083026a2084026a2085026a2086026a2087026a2088026a2089026a208a026a20" - "8b026a208c026a208d026a208e026a208f026a2090026a2091026a2092026a2093026a2094026a2095026a2096026a" - "2097026a2098026a2099026a209a026a209b026a209c026a209d026a209e026a209f026a20a0026a20a1026a20a202" - "6a20a3026a20a4026a20a5026a20a6026a20a7026a20a8026a20a9026a20aa026a20ab026a20ac026a20ad026a20ae" - "026a20af026a20b0026a20b1026a20b2026a20b3026a20b4026a20b5026a20b6026a20b7026a20b8026a20b9026a20" - "ba026a20bb026a20bc026a20bd026a20be026a20bf026a20c0026a20c1026a20c2026a20c3026a20c4026a20c5026a" - "20c6026a20c7026a20c8026a20c9026a20ca026a20cb026a20cc026a20cd026a20ce026a20cf026a20d0026a20d102" - "6a20d2026a20d3026a20d4026a20d5026a20d6026a20d7026a20d8026a20d9026a20da026a20db026a20dc026a20dd" - "026a20de026a20df026a20e0026a20e1026a20e2026a20e3026a20e4026a20e5026a20e6026a20e7026a20e8026a20" - "e9026a20ea026a20eb026a20ec026a20ed026a20ee026a20ef026a20f0026a20f1026a20f2026a20f3026a20f4026a" - "20f5026a20f6026a20f7026a20f8026a20f9026a20fa026a20fb026a20fc026a20fd026a20fe026a20ff026a208003" - "6a2081036a2082036a2083036a2084036a2085036a2086036a2087036a2088036a2089036a208a036a208b036a208c" - "036a208d036a208e036a208f036a2090036a2091036a2092036a2093036a2094036a2095036a2096036a2097036a20" - "98036a2099036a209a036a209b036a209c036a209d036a209e036a209f036a20a0036a20a1036a20a2036a20a3036a" - "20a4036a20a5036a20a6036a20a7036a20a8036a20a9036a20aa036a20ab036a20ac036a20ad036a20ae036a20af03" - "6a20b0036a20b1036a20b2036a20b3036a20b4036a20b5036a20b6036a20b7036a20b8036a20b9036a20ba036a20bb" - "036a20bc036a20bd036a20be036a20bf036a20c0036a20c1036a20c2036a20c3036a20c4036a20c5036a20c6036a20" - "c7036a20c8036a20c9036a20ca036a20cb036a20cc036a20cd036a20ce036a20cf036a20d0036a20d1036a20d2036a" - "20d3036a20d4036a20d5036a20d6036a20d7036a20d8036a20d9036a20da036a20db036a20dc036a20dd036a20de03" - "6a20df036a20e0036a20e1036a20e2036a20e3036a20e4036a20e5036a20e6036a20e7036a20e8036a20e9036a20ea" - "036a20eb036a20ec036a20ed036a20ee036a20ef036a20f0036a20f1036a20f2036a20f3036a20f4036a20f5036a20" - "f6036a20f7036a20f8036a20f9036a20fa036a20fb036a20fc036a20fd036a20fe036a20ff036a2080046a2081046a" - "2082046a2083046a2084046a2085046a2086046a2087046a2088046a2089046a208a046a208b046a208c046a208d04" - "6a208e046a208f046a2090046a2091046a2092046a2093046a2094046a2095046a2096046a2097046a2098046a2099" - "046a209a046a209b046a209c046a209d046a209e046a209f046a20a0046a20a1046a20a2046a20a3046a20a4046a20" - "a5046a20a6046a20a7046a20a8046a20a9046a20aa046a20ab046a20ac046a20ad046a20ae046a20af046a20b0046a" - "20b1046a20b2046a20b3046a20b4046a20b5046a20b6046a20b7046a20b8046a20b9046a20ba046a20bb046a20bc04" - "6a20bd046a20be046a20bf046a20c0046a20c1046a20c2046a20c3046a20c4046a20c5046a20c6046a20c7046a20c8" - "046a20c9046a20ca046a20cb046a20cc046a20cd046a20ce046a20cf046a20d0046a20d1046a20d2046a20d3046a20" - "d4046a20d5046a20d6046a20d7046a20d8046a20d9046a20da046a20db046a20dc046a20dd046a20de046a20df046a" - "20e0046a20e1046a20e2046a20e3046a20e4046a20e5046a20e6046a20e7046a20e8046a20e9046a20ea046a20eb04" - "6a20ec046a20ed046a20ee046a20ef046a20f0046a20f1046a20f2046a20f3046a20f4046a20f5046a20f6046a20f7" - "046a20f8046a20f9046a20fa046a20fb046a20fc046a20fd046a20fe046a20ff046a2080056a2081056a2082056a20" - "83056a2084056a2085056a2086056a2087056a2088056a2089056a208a056a208b056a208c056a208d056a208e056a" - "208f056a2090056a2091056a2092056a2093056a2094056a2095056a2096056a2097056a2098056a2099056a209a05" - "6a209b056a209c056a209d056a209e056a209f056a20a0056a20a1056a20a2056a20a3056a20a4056a20a5056a20a6" - "056a20a7056a20a8056a20a9056a20aa056a20ab056a20ac056a20ad056a20ae056a20af056a20b0056a20b1056a20" - "b2056a20b3056a20b4056a20b5056a20b6056a20b7056a20b8056a20b9056a20ba056a20bb056a20bc056a20bd056a" - "20be056a20bf056a20c0056a20c1056a20c2056a20c3056a20c4056a20c5056a20c6056a20c7056a20c8056a20c905" - "6a20ca056a20cb056a20cc056a20cd056a20ce056a20cf056a20d0056a20d1056a20d2056a20d3056a20d4056a20d5" - "056a20d6056a20d7056a20d8056a20d9056a20da056a20db056a20dc056a20dd056a20de056a20df056a20e0056a20" - "e1056a20e2056a20e3056a20e4056a20e5056a20e6056a20e7056a20e8056a20e9056a20ea056a20eb056a20ec056a" - "20ed056a20ee056a20ef056a20f0056a20f1056a20f2056a20f3056a20f4056a20f5056a20f6056a20f7056a20f805" - "6a20f9056a20fa056a20fb056a20fc056a20fd056a20fe056a20ff056a2080066a2081066a2082066a2083066a2084" - "066a2085066a2086066a2087066a2088066a2089066a208a066a208b066a208c066a208d066a208e066a208f066a20" - "90066a2091066a2092066a2093066a2094066a2095066a2096066a2097066a2098066a2099066a209a066a209b066a" - "209c066a209d066a209e066a209f066a20a0066a20a1066a20a2066a20a3066a20a4066a20a5066a20a6066a20a706" - "6a20a8066a20a9066a20aa066a20ab066a20ac066a20ad066a20ae066a20af066a20b0066a20b1066a20b2066a20b3" - "066a20b4066a20b5066a20b6066a20b7066a20b8066a20b9066a20ba066a20bb066a20bc066a20bd066a20be066a20" - "bf066a20c0066a20c1066a20c2066a20c3066a20c4066a20c5066a20c6066a20c7066a20c8066a20c9066a20ca066a" - "20cb066a20cc066a20cd066a20ce066a20cf066a20d0066a20d1066a20d2066a20d3066a20d4066a20d5066a20d606" - "6a20d7066a20d8066a20d9066a20da066a20db066a20dc066a20dd066a20de066a20df066a20e0066a20e1066a20e2" - "066a20e3066a20e4066a20e5066a20e6066a20e7066a20e8066a20e9066a20ea066a20eb066a20ec066a20ed066a20" - "ee066a20ef066a20f0066a20f1066a20f2066a20f3066a20f4066a20f5066a20f6066a20f7066a20f8066a20f9066a" - "20fa066a20fb066a20fc066a20fd066a20fe066a20ff066a2080076a2081076a2082076a2083076a2084076a208507" - "6a2086076a2087076a2088076a2089076a208a076a208b076a208c076a208d076a208e076a208f076a2090076a2091" - "076a2092076a2093076a2094076a2095076a2096076a2097076a2098076a2099076a209a076a209b076a209c076a20" - "9d076a209e076a209f076a20a0076a20a1076a20a2076a20a3076a20a4076a20a5076a20a6076a20a7076a20a8076a" - "20a9076a20aa076a20ab076a20ac076a20ad076a20ae076a20af076a20b0076a20b1076a20b2076a20b3076a20b407" - "6a20b5076a20b6076a20b7076a20b8076a20b9076a20ba076a20bb076a20bc076a20bd076a20be076a20bf076a20c0" - "076a20c1076a20c2076a20c3076a20c4076a20c5076a20c6076a20c7076a20c8076a20c9076a20ca076a20cb076a20" - "cc076a20cd076a20ce076a20cf076a20d0076a20d1076a20d2076a20d3076a20d4076a20d5076a20d6076a20d7076a" - "20d8076a20d9076a20da076a20db076a20dc076a20dd076a20de076a20df076a20e0076a20e1076a20e2076a20e307" - "6a20e4076a20e5076a20e6076a20e7076a0b007f0970726f647563657273010c70726f6365737365642d6279010563" - "6c616e675f31392e312e352d776173692d73646b202868747470733a2f2f6769746875622e636f6d2f6c6c766d2f6c" - "6c766d2d70726f6a656374206162346235613264623538323935386166316565333038613739306366646234326264" - "32343732302900490f7461726765745f6665617475726573042b0f6d757461626c652d676c6f62616c732b08736967" - "6e2d6578742b0f7265666572656e63652d74797065732b0a6d756c746976616c7565"; - -extern std::string const kThousand1ParamsHex = - "0061736d0100000001f2070260000060e9077f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f" - "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f017f03030200010503010002063809" - "7f004180080b7f004180080b7f004180080b7f00418088040b7f004180080b7f00418088040b7f00418080080b7f00" - "41000b7f0041010b07a8010c066d656d6f72790200115f5f7761736d5f63616c6c5f63746f72730000047465737400" - "010c5f5f64736f5f68616e646c6503000a5f5f646174615f656e6403010b5f5f737461636b5f6c6f7703020c5f5f73" - "7461636b5f6869676803030d5f5f676c6f62616c5f6261736503040b5f5f686561705f6261736503050a5f5f686561" - "705f656e6403060d5f5f6d656d6f72795f6261736503070c5f5f7461626c655f6261736503080aab1e0202000ba51e" - "00200020016a20026a20036a20046a20056a20066a20076a20086a20096a200a6a200b6a200c6a200d6a200e6a200f" - "6a20106a20116a20126a20136a20146a20156a20166a20176a20186a20196a201a6a201b6a201c6a201d6a201e6a20" - "1f6a20206a20216a20226a20236a20246a20256a20266a20276a20286a20296a202a6a202b6a202c6a202d6a202e6a" - "202f6a20306a20316a20326a20336a20346a20356a20366a20376a20386a20396a203a6a203b6a203c6a203d6a203e" - "6a203f6a20406a20416a20426a20436a20446a20456a20466a20476a20486a20496a204a6a204b6a204c6a204d6a20" - "4e6a204f6a20506a20516a20526a20536a20546a20556a20566a20576a20586a20596a205a6a205b6a205c6a205d6a" - "205e6a205f6a20606a20616a20626a20636a20646a20656a20666a20676a20686a20696a206a6a206b6a206c6a206d" - "6a206e6a206f6a20706a20716a20726a20736a20746a20756a20766a20776a20786a20796a207a6a207b6a207c6a20" - "7d6a207e6a207f6a2080016a2081016a2082016a2083016a2084016a2085016a2086016a2087016a2088016a208901" - "6a208a016a208b016a208c016a208d016a208e016a208f016a2090016a2091016a2092016a2093016a2094016a2095" - "016a2096016a2097016a2098016a2099016a209a016a209b016a209c016a209d016a209e016a209f016a20a0016a20" - "a1016a20a2016a20a3016a20a4016a20a5016a20a6016a20a7016a20a8016a20a9016a20aa016a20ab016a20ac016a" - "20ad016a20ae016a20af016a20b0016a20b1016a20b2016a20b3016a20b4016a20b5016a20b6016a20b7016a20b801" - "6a20b9016a20ba016a20bb016a20bc016a20bd016a20be016a20bf016a20c0016a20c1016a20c2016a20c3016a20c4" - "016a20c5016a20c6016a20c7016a20c8016a20c9016a20ca016a20cb016a20cc016a20cd016a20ce016a20cf016a20" - "d0016a20d1016a20d2016a20d3016a20d4016a20d5016a20d6016a20d7016a20d8016a20d9016a20da016a20db016a" - "20dc016a20dd016a20de016a20df016a20e0016a20e1016a20e2016a20e3016a20e4016a20e5016a20e6016a20e701" - "6a20e8016a20e9016a20ea016a20eb016a20ec016a20ed016a20ee016a20ef016a20f0016a20f1016a20f2016a20f3" - "016a20f4016a20f5016a20f6016a20f7016a20f8016a20f9016a20fa016a20fb016a20fc016a20fd016a20fe016a20" - "ff016a2080026a2081026a2082026a2083026a2084026a2085026a2086026a2087026a2088026a2089026a208a026a" - "208b026a208c026a208d026a208e026a208f026a2090026a2091026a2092026a2093026a2094026a2095026a209602" - "6a2097026a2098026a2099026a209a026a209b026a209c026a209d026a209e026a209f026a20a0026a20a1026a20a2" - "026a20a3026a20a4026a20a5026a20a6026a20a7026a20a8026a20a9026a20aa026a20ab026a20ac026a20ad026a20" - "ae026a20af026a20b0026a20b1026a20b2026a20b3026a20b4026a20b5026a20b6026a20b7026a20b8026a20b9026a" - "20ba026a20bb026a20bc026a20bd026a20be026a20bf026a20c0026a20c1026a20c2026a20c3026a20c4026a20c502" - "6a20c6026a20c7026a20c8026a20c9026a20ca026a20cb026a20cc026a20cd026a20ce026a20cf026a20d0026a20d1" - "026a20d2026a20d3026a20d4026a20d5026a20d6026a20d7026a20d8026a20d9026a20da026a20db026a20dc026a20" - "dd026a20de026a20df026a20e0026a20e1026a20e2026a20e3026a20e4026a20e5026a20e6026a20e7026a20e8026a" - "20e9026a20ea026a20eb026a20ec026a20ed026a20ee026a20ef026a20f0026a20f1026a20f2026a20f3026a20f402" - "6a20f5026a20f6026a20f7026a20f8026a20f9026a20fa026a20fb026a20fc026a20fd026a20fe026a20ff026a2080" - "036a2081036a2082036a2083036a2084036a2085036a2086036a2087036a2088036a2089036a208a036a208b036a20" - "8c036a208d036a208e036a208f036a2090036a2091036a2092036a2093036a2094036a2095036a2096036a2097036a" - "2098036a2099036a209a036a209b036a209c036a209d036a209e036a209f036a20a0036a20a1036a20a2036a20a303" - "6a20a4036a20a5036a20a6036a20a7036a20a8036a20a9036a20aa036a20ab036a20ac036a20ad036a20ae036a20af" - "036a20b0036a20b1036a20b2036a20b3036a20b4036a20b5036a20b6036a20b7036a20b8036a20b9036a20ba036a20" - "bb036a20bc036a20bd036a20be036a20bf036a20c0036a20c1036a20c2036a20c3036a20c4036a20c5036a20c6036a" - "20c7036a20c8036a20c9036a20ca036a20cb036a20cc036a20cd036a20ce036a20cf036a20d0036a20d1036a20d203" - "6a20d3036a20d4036a20d5036a20d6036a20d7036a20d8036a20d9036a20da036a20db036a20dc036a20dd036a20de" - "036a20df036a20e0036a20e1036a20e2036a20e3036a20e4036a20e5036a20e6036a20e7036a20e8036a20e9036a20" - "ea036a20eb036a20ec036a20ed036a20ee036a20ef036a20f0036a20f1036a20f2036a20f3036a20f4036a20f5036a" - "20f6036a20f7036a20f8036a20f9036a20fa036a20fb036a20fc036a20fd036a20fe036a20ff036a2080046a208104" - "6a2082046a2083046a2084046a2085046a2086046a2087046a2088046a2089046a208a046a208b046a208c046a208d" - "046a208e046a208f046a2090046a2091046a2092046a2093046a2094046a2095046a2096046a2097046a2098046a20" - "99046a209a046a209b046a209c046a209d046a209e046a209f046a20a0046a20a1046a20a2046a20a3046a20a4046a" - "20a5046a20a6046a20a7046a20a8046a20a9046a20aa046a20ab046a20ac046a20ad046a20ae046a20af046a20b004" - "6a20b1046a20b2046a20b3046a20b4046a20b5046a20b6046a20b7046a20b8046a20b9046a20ba046a20bb046a20bc" - "046a20bd046a20be046a20bf046a20c0046a20c1046a20c2046a20c3046a20c4046a20c5046a20c6046a20c7046a20" - "c8046a20c9046a20ca046a20cb046a20cc046a20cd046a20ce046a20cf046a20d0046a20d1046a20d2046a20d3046a" - "20d4046a20d5046a20d6046a20d7046a20d8046a20d9046a20da046a20db046a20dc046a20dd046a20de046a20df04" - "6a20e0046a20e1046a20e2046a20e3046a20e4046a20e5046a20e6046a20e7046a20e8046a20e9046a20ea046a20eb" - "046a20ec046a20ed046a20ee046a20ef046a20f0046a20f1046a20f2046a20f3046a20f4046a20f5046a20f6046a20" - "f7046a20f8046a20f9046a20fa046a20fb046a20fc046a20fd046a20fe046a20ff046a2080056a2081056a2082056a" - "2083056a2084056a2085056a2086056a2087056a2088056a2089056a208a056a208b056a208c056a208d056a208e05" - "6a208f056a2090056a2091056a2092056a2093056a2094056a2095056a2096056a2097056a2098056a2099056a209a" - "056a209b056a209c056a209d056a209e056a209f056a20a0056a20a1056a20a2056a20a3056a20a4056a20a5056a20" - "a6056a20a7056a20a8056a20a9056a20aa056a20ab056a20ac056a20ad056a20ae056a20af056a20b0056a20b1056a" - "20b2056a20b3056a20b4056a20b5056a20b6056a20b7056a20b8056a20b9056a20ba056a20bb056a20bc056a20bd05" - "6a20be056a20bf056a20c0056a20c1056a20c2056a20c3056a20c4056a20c5056a20c6056a20c7056a20c8056a20c9" - "056a20ca056a20cb056a20cc056a20cd056a20ce056a20cf056a20d0056a20d1056a20d2056a20d3056a20d4056a20" - "d5056a20d6056a20d7056a20d8056a20d9056a20da056a20db056a20dc056a20dd056a20de056a20df056a20e0056a" - "20e1056a20e2056a20e3056a20e4056a20e5056a20e6056a20e7056a20e8056a20e9056a20ea056a20eb056a20ec05" - "6a20ed056a20ee056a20ef056a20f0056a20f1056a20f2056a20f3056a20f4056a20f5056a20f6056a20f7056a20f8" - "056a20f9056a20fa056a20fb056a20fc056a20fd056a20fe056a20ff056a2080066a2081066a2082066a2083066a20" - "84066a2085066a2086066a2087066a2088066a2089066a208a066a208b066a208c066a208d066a208e066a208f066a" - "2090066a2091066a2092066a2093066a2094066a2095066a2096066a2097066a2098066a2099066a209a066a209b06" - "6a209c066a209d066a209e066a209f066a20a0066a20a1066a20a2066a20a3066a20a4066a20a5066a20a6066a20a7" - "066a20a8066a20a9066a20aa066a20ab066a20ac066a20ad066a20ae066a20af066a20b0066a20b1066a20b2066a20" - "b3066a20b4066a20b5066a20b6066a20b7066a20b8066a20b9066a20ba066a20bb066a20bc066a20bd066a20be066a" - "20bf066a20c0066a20c1066a20c2066a20c3066a20c4066a20c5066a20c6066a20c7066a20c8066a20c9066a20ca06" - "6a20cb066a20cc066a20cd066a20ce066a20cf066a20d0066a20d1066a20d2066a20d3066a20d4066a20d5066a20d6" - "066a20d7066a20d8066a20d9066a20da066a20db066a20dc066a20dd066a20de066a20df066a20e0066a20e1066a20" - "e2066a20e3066a20e4066a20e5066a20e6066a20e7066a20e8066a20e9066a20ea066a20eb066a20ec066a20ed066a" - "20ee066a20ef066a20f0066a20f1066a20f2066a20f3066a20f4066a20f5066a20f6066a20f7066a20f8066a20f906" - "6a20fa066a20fb066a20fc066a20fd066a20fe066a20ff066a2080076a2081076a2082076a2083076a2084076a2085" - "076a2086076a2087076a2088076a2089076a208a076a208b076a208c076a208d076a208e076a208f076a2090076a20" - "91076a2092076a2093076a2094076a2095076a2096076a2097076a2098076a2099076a209a076a209b076a209c076a" - "209d076a209e076a209f076a20a0076a20a1076a20a2076a20a3076a20a4076a20a5076a20a6076a20a7076a20a807" - "6a20a9076a20aa076a20ab076a20ac076a20ad076a20ae076a20af076a20b0076a20b1076a20b2076a20b3076a20b4" - "076a20b5076a20b6076a20b7076a20b8076a20b9076a20ba076a20bb076a20bc076a20bd076a20be076a20bf076a20" - "c0076a20c1076a20c2076a20c3076a20c4076a20c5076a20c6076a20c7076a20c8076a20c9076a20ca076a20cb076a" - "20cc076a20cd076a20ce076a20cf076a20d0076a20d1076a20d2076a20d3076a20d4076a20d5076a20d6076a20d707" - "6a20d8076a20d9076a20da076a20db076a20dc076a20dd076a20de076a20df076a20e0076a20e1076a20e2076a20e3" - "076a20e4076a20e5076a20e6076a20e7076a20e8076a0b007f0970726f647563657273010c70726f6365737365642d" - "62790105636c616e675f31392e312e352d776173692d73646b202868747470733a2f2f6769746875622e636f6d2f6c" - "6c766d2f6c6c766d2d70726f6a65637420616234623561326462353832393538616631656533303861373930636664" - "623432626432343732302900490f7461726765745f6665617475726573042b0f6d757461626c652d676c6f62616c73" - "2b087369676e2d6578742b0f7265666572656e63652d74797065732b0a6d756c746976616c7565"; - -extern std::string const kOpcReservedHex = - "0061736d010000000105016000017f03030200000404017000010503010001060b027f0141000b7e0142000b071401" - "10616c6c5f696e737472756374696f6e7300010907010041000b01000a53020400412a0b4c02017f017e0101010101" - "0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" - "01010101010101010101010101010101410b0b0b0a010041000b0474657374"; - -extern std::string const kImpExpHex = - "0061736d0100000001100360027f7f017f6000017f60017f017f02330203656e760e6765745f6c65646765725f7371" - "6e000003656e76166765745f706172656e745f6c65646765725f686173680000030403010201050301000107310406" - "6d656d6f72790200096578705f66756e63310002096578705f66756e633200030c746573745f696d706f7274730004" - "0a2b03040041010b0700200041026c0b1c01027f4120410410001a41202802002100410041201001210120000b"; diff --git a/src/test/app/wasm_fixtures/fixtures.h b/src/test/app/wasm_fixtures/fixtures.h deleted file mode 100644 index 2f0a1072f6..0000000000 --- a/src/test/app/wasm_fixtures/fixtures.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once - -// TODO: consider moving these to separate files (and figure out the build) - -#include - -extern std::string const kLedgerSqnWasmHex; -extern std::string const kAllHostFunctionsWasmHex; -extern std::string const kAllKeyletsWasmHex; -extern std::string const kCodecovTestsWasmHex; - -extern std::string const kFibWasmHex; - -extern std::string const kFloatTestsWasmHex; -extern std::string const kFloat0Hex; -extern std::string const kDisabledFloatHex; - -extern std::string const kMemoryPointerAtLimitHex; -extern std::string const kMemoryPointerOverLimitHex; -extern std::string const kMemoryOffsetOverLimitHex; -extern std::string const kMemoryEndOfWordOverLimitHex; -extern std::string const kMemoryGrow0To1PageHex; -extern std::string const kMemoryGrow1To0PageHex; -extern std::string const kMemoryLastByteOf8MbHex; -extern std::string const kMemoryGrow1MoreThan8MbHex; -extern std::string const kMemoryGrow0MoreThan8MbHex; -extern std::string const kMemoryInit1MoreThan8MbHex; -extern std::string const kMemoryNegativeAddressHex; - -extern std::string const kTable64ElementsHex; -extern std::string const kTable65ElementsHex; -extern std::string const kTable2TablesHex; -extern std::string const kTable0ElementsHex; -extern std::string const kTableUintMaxHex; - -extern std::string const kProposalMutableGlobalHex; -extern std::string const kProposalGcStructNewHex; -extern std::string const kProposalMultiValueHex; -extern std::string const kProposalSignExtHex; -extern std::string const kProposalFloatToIntHex; -extern std::string const kProposalBulkMemoryHex; -extern std::string const kProposalRefTypesHex; -extern std::string const kProposalTailCallHex; -extern std::string const kProposalExtendedConstHex; -extern std::string const kProposalMultiMemoryHex; -extern std::string const kProposalCustomPageSizesHex; -extern std::string const kProposalMemory64Hex; -extern std::string const kProposalWideArithmeticHex; - -extern std::string const kTrapDivideBy0Hex; -extern std::string const kTrapIntOverflowHex; -extern std::string const kTrapUnreachableHex; -extern std::string const kTrapNullCallHex; -extern std::string const kTrapFuncSigMismatchHex; - -extern std::string const kWasiGetTimeHex; -extern std::string const kWasiPrintHex; - -extern std::string const kBadMagicNumberHex; -extern std::string const kBadVersionNumberHex; -extern std::string const kLyingHeaderHex; -extern std::string const kNeverEndingNumberHex; -extern std::string const kVectorLieHex; -extern std::string const kSectionOrderingHex; -extern std::string const kGhostPayloadHex; -extern std::string const kJunkAfterSectionHex; -extern std::string const kInvalidSectionIdHex; -extern std::string const kLocalVariableBombHex; - -extern std::string const kDeepRecursionHex; -extern std::string const kInfiniteLoopWasmHex; -extern std::string const kStartLoopHex; - -extern std::string const kBadAlignWasmHex; - -extern std::string const kThousandParamsHex; -extern std::string const kThousand1ParamsHex; -extern std::string const kLocals10kHex; -extern std::string const kFunctions5kHex; - -extern std::string const kOpcReservedHex; - -extern std::string const kImpExpHex; diff --git a/src/test/app/wasm_fixtures/float_0/Cargo.lock b/src/test/app/wasm_fixtures/float_0/Cargo.lock deleted file mode 100644 index 690b1b51f3..0000000000 --- a/src/test/app/wasm_fixtures/float_0/Cargo.lock +++ /dev/null @@ -1,171 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "block-buffer" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "const-oid" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" - -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "digest" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", -] - -[[package]] -name = "float_0" -version = "0.0.1" -dependencies = [ - "xrpl-wasm-stdlib", -] - -[[package]] -name = "hybrid-array" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" -dependencies = [ - "typenum", -] - -[[package]] -name = "libc" -version = "0.2.183" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "sha2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tinyvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "typenum" -version = "1.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "xrpl-macros" -version = "0.1.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#6b35fe45ac70bad38914e7f319d31d7947e05e25" -dependencies = [ - "bs58", - "proc-macro2", - "quote", - "sha2", - "syn", -] - -[[package]] -name = "xrpl-wasm-stdlib" -version = "0.8.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#6b35fe45ac70bad38914e7f319d31d7947e05e25" -dependencies = [ - "xrpl-macros", -] diff --git a/src/test/app/wasm_fixtures/float_0/Cargo.toml b/src/test/app/wasm_fixtures/float_0/Cargo.toml deleted file mode 100644 index 95254f2e2b..0000000000 --- a/src/test/app/wasm_fixtures/float_0/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "float_0" -version = "0.0.1" -edition = "2024" - -# This empty workspace definition keeps this project independent of the parent workspace -[workspace] - -[lib] -crate-type = ["cdylib"] - -[profile.release] -lto = true -opt-level = 's' -panic = "abort" - -[dependencies] -xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" } - -[profile.dev] -panic = "abort" diff --git a/src/test/app/wasm_fixtures/float_0/src/lib.rs b/src/test/app/wasm_fixtures/float_0/src/lib.rs deleted file mode 100644 index 5f6c8f0770..0000000000 --- a/src/test/app/wasm_fixtures/float_0/src/lib.rs +++ /dev/null @@ -1,70 +0,0 @@ -#![cfg_attr(target_arch = "wasm32", no_std)] - -use xrpl_std::host::trace::trace; -use xrpl_std::host::{float_cmp, float_from_int, float_sub, FLOAT_ROUNDING_MODES_TO_NEAREST}; - -// Float size constant (8 bytes mantissa + 4 bytes exponent) -const FLOAT_SIZE: usize = 12; - -// FLOAT_ZERO constant -const FLOAT_ZERO: [u8; FLOAT_SIZE] = [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, -]; - -#[unsafe(no_mangle)] -pub extern "C" fn escrow_finish() -> i32 { - let _ = trace("\n$$$ test_float_0 $$$"); - - // Test: 10 - 10 should equal 0 - let mut f10: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - let mut f_result: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - - // Create float from 10 - if FLOAT_SIZE as i32 - != unsafe { - float_from_int( - 10, - f10.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - } - { - let _ = trace(" float 10-10: failed"); - return 1; - } - - // Subtract: 10 - 10 = 0 - if FLOAT_SIZE as i32 - != unsafe { - float_sub( - f10.as_ptr(), - FLOAT_SIZE, - f10.as_ptr(), - FLOAT_SIZE, - f_result.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - } - { - let _ = trace(" float 10-10: failed"); - return 1; - } - - // Compare result with FLOAT_ZERO constant - if 0 == unsafe { - float_cmp( - f_result.as_ptr(), - FLOAT_SIZE, - FLOAT_ZERO.as_ptr(), - FLOAT_SIZE, - ) - } { - let _ = trace(" FLOAT_ZERO compare: good"); - } else { - let _ = trace(" FLOAT_ZERO compare: bad"); - } - - 1 -} diff --git a/src/test/app/wasm_fixtures/float_tests/Cargo.lock b/src/test/app/wasm_fixtures/float_tests/Cargo.lock deleted file mode 100644 index 92158d3262..0000000000 --- a/src/test/app/wasm_fixtures/float_tests/Cargo.lock +++ /dev/null @@ -1,171 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "block-buffer" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "const-oid" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" - -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "digest" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", -] - -[[package]] -name = "float_tests" -version = "0.0.1" -dependencies = [ - "xrpl-wasm-stdlib", -] - -[[package]] -name = "hybrid-array" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" -dependencies = [ - "typenum", -] - -[[package]] -name = "libc" -version = "0.2.177" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" - -[[package]] -name = "proc-macro2" -version = "1.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "sha2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "syn" -version = "2.0.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tinyvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "typenum" -version = "1.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" - -[[package]] -name = "unicode-ident" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" - -[[package]] -name = "xrpl-macros" -version = "0.1.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#6b35fe45ac70bad38914e7f319d31d7947e05e25" -dependencies = [ - "bs58", - "proc-macro2", - "quote", - "sha2", - "syn", -] - -[[package]] -name = "xrpl-wasm-stdlib" -version = "0.8.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#6b35fe45ac70bad38914e7f319d31d7947e05e25" -dependencies = [ - "xrpl-macros", -] diff --git a/src/test/app/wasm_fixtures/float_tests/Cargo.toml b/src/test/app/wasm_fixtures/float_tests/Cargo.toml deleted file mode 100644 index d4f70f1afc..0000000000 --- a/src/test/app/wasm_fixtures/float_tests/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "float_tests" -version = "0.0.1" -edition = "2024" - -# This empty workspace definition keeps this project independent of the parent workspace -[workspace] - -[lib] -crate-type = ["cdylib"] - -[profile.release] -lto = true -opt-level = 's' -panic = "abort" - -[dependencies] -xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" } - -[profile.dev] -panic = "abort" diff --git a/src/test/app/wasm_fixtures/float_tests/src/lib.rs b/src/test/app/wasm_fixtures/float_tests/src/lib.rs deleted file mode 100644 index b5e6aa6185..0000000000 --- a/src/test/app/wasm_fixtures/float_tests/src/lib.rs +++ /dev/null @@ -1,1112 +0,0 @@ -#![allow(unused_imports)] -#![allow(unused_variables)] -#![cfg_attr(target_arch = "wasm32", no_std)] - -#[cfg(not(target_arch = "wasm32"))] -extern crate std; - -use xrpl_std::core::locator::Locator; -use xrpl_std::decode_hex_32; -use xrpl_std::host::trace::DataRepr::AsHex; -use xrpl_std::host::trace::{trace, trace_data, trace_num, DataRepr}; -use xrpl_std::host::{ - cache_le, float_add, float_cmp, float_div, float_from_int, float_from_uint, float_mult, - float_pow, float_root, float_sub, le_field, le_inner, le_inner_arr_len, - FLOAT_ROUNDING_MODES_TO_NEAREST, -}; -use xrpl_std::sfield; -use xrpl_std::sfield::{ - Account, AccountTxnID, Balance, Domain, EmailHash, Flags, LedgerEntryType, MessageKey, - OwnerCount, PreviousTxnID, PreviousTxnLgrSeq, RegularKey, Sequence, TicketCount, TransferRate, -}; - -// External host functions not yet in xrpl_std -unsafe extern "C" { - #[link_name = "float_from_stamount"] - fn float_from_stamount( - amount_ptr: *const u8, - amount_len: i32, - out_ptr: *mut u8, - out_len: i32, - rounding: i32, - ) -> i32; - - #[link_name = "float_from_stnumber"] - fn float_from_stnumber( - number_ptr: *const u8, - number_len: i32, - out_ptr: *mut u8, - out_len: i32, - rounding: i32, - ) -> i32; - - #[link_name = "float_to_int"] - fn float_to_int( - float_ptr: *const u8, - float_len: i32, - out_ptr: *mut u8, - out_len: i32, - rounding: i32, - ) -> i32; - - #[link_name = "float_to_mant_exp"] - fn float_to_mant_exp( - float_ptr: *const u8, - float_len: i32, - mantissa_ptr: *mut u8, - mantissa_len: i32, - exponent_ptr: *mut u8, - exponent_len: i32, - ) -> i32; - - #[link_name = "float_from_mant_exp"] - fn float_from_mant_exp( - mantissa: i64, - exponent: i32, - out_ptr: *mut u8, - out_len: i32, - rounding: i32, - ) -> i32; -} - -// Float size constant (8 bytes mantissa + 4 bytes exponent) -const FLOAT_SIZE: usize = 12; - -// Float constants (8 bytes mantissa + 4 bytes exponent, big-endian) -// FLOAT_ONE: mantissa=0x0DE0B6B3A7640000 (10^18), exponent=0xFFFFFFEE (-18) -const FLOAT_ONE: [u8; FLOAT_SIZE] = [ - 0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE, -]; -// FLOAT_NEGATIVE_ONE: mantissa=0xF21F494C589C0000 (-10^18), exponent=0xFFFFFFEE (-18) -const FLOAT_NEGATIVE_ONE: [u8; FLOAT_SIZE] = [ - 0xF2, 0x1F, 0x49, 0x4C, 0x58, 0x9C, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE, -]; - -// Helper function to trace floats -fn trace_float(msg: &str, f: &[u8; FLOAT_SIZE]) { - let _ = trace(msg); - let _ = trace_data(" ", f, AsHex); -} - -fn test_float_from_wasm() -> bool { - let _ = trace("\n$$$ test_float_from_wasm $$$"); - let mut all_pass = true; - - let mut f: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - if FLOAT_SIZE as i32 - == unsafe { - float_from_int( - 12300, - f.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - } - { - let _ = trace_float(" float from i64 12300:", &f); - let _ = trace_data(" float from i64 12300 as HEX:", &f, AsHex); - } else { - let _ = trace(" float from i64 12300: failed"); - all_pass = false; - } - - let u64_value: u64 = 12300; - if FLOAT_SIZE as i32 - == unsafe { - float_from_uint( - &u64_value as *const u64 as *const u8, - 8, - f.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - } - { - let _ = trace_float(" float from u64 12300:", &f); - } else { - let _ = trace(" float from u64 12300: failed"); - all_pass = false; - } - - if FLOAT_SIZE as i32 - == unsafe { - float_from_mant_exp( - 123, - 2, - f.as_mut_ptr(), - FLOAT_SIZE as i32, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - } - { - let _ = trace_float(" float from exp 2, mantissa 123:", &f); - } else { - let _ = trace(" float from exp 2, mantissa 123: failed"); - all_pass = false; - } - - let _ = trace_float(" float from const 1:", &FLOAT_ONE); - let _ = trace_float(" float from const -1:", &FLOAT_NEGATIVE_ONE); - - all_pass -} - -fn test_float_cmp() -> bool { - let _ = trace("\n$$$ test_float_cmp $$$"); - let mut all_pass = true; - - let mut f1: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - if FLOAT_SIZE as i32 - != unsafe { - float_from_int( - 1, - f1.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - } - { - let _ = trace(" float from 1: failed"); - all_pass = false; - } else { - let _ = trace_float(" float from 1:", &f1); - } - - if 0 == unsafe { float_cmp(f1.as_ptr(), FLOAT_SIZE, FLOAT_ONE.as_ptr(), FLOAT_SIZE) } { - let _ = trace(" float from 1 == FLOAT_ONE"); - } else { - let _ = trace(" float from 1 != FLOAT_ONE, failed"); - all_pass = false; - } - - if 1 == unsafe { - float_cmp( - f1.as_ptr(), - FLOAT_SIZE, - FLOAT_NEGATIVE_ONE.as_ptr(), - FLOAT_SIZE, - ) - } { - let _ = trace(" float from 1 > FLOAT_NEGATIVE_ONE"); - } else { - let _ = trace(" float from 1 !> FLOAT_NEGATIVE_ONE, failed"); - all_pass = false; - } - - if 2 == unsafe { - float_cmp( - FLOAT_NEGATIVE_ONE.as_ptr(), - FLOAT_SIZE, - f1.as_ptr(), - FLOAT_SIZE, - ) - } { - let _ = trace(" FLOAT_NEGATIVE_ONE < float from 1"); - } else { - let _ = trace(" FLOAT_NEGATIVE_ONE !< float from 1, failed"); - all_pass = false; - } - - all_pass -} - -fn test_float_add_subtract() -> bool { - let _ = trace("\n$$$ test_float_add_subtract $$$"); - let mut all_pass = true; - - let mut f_compute: [u8; FLOAT_SIZE] = FLOAT_ONE; - for i in 0..9 { - unsafe { - float_add( - f_compute.as_ptr(), - FLOAT_SIZE, - FLOAT_ONE.as_ptr(), - FLOAT_SIZE, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - // let _ = trace_float(" float:", &f_compute); - } - let mut f10: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - if FLOAT_SIZE as i32 - != unsafe { - float_from_int( - 10, - f10.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - } - { - let _ = trace(" float from 10: failed"); - all_pass = false; - } - - if 0 == unsafe { float_cmp(f10.as_ptr(), FLOAT_SIZE, f_compute.as_ptr(), FLOAT_SIZE) } { - let _ = trace(" repeated add: good"); - } else { - let _ = trace(" repeated add: failed"); - all_pass = false; - } - - for i in 0..11 { - unsafe { - float_sub( - f_compute.as_ptr(), - FLOAT_SIZE, - FLOAT_ONE.as_ptr(), - FLOAT_SIZE, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - } - if 0 == unsafe { - float_cmp( - f_compute.as_ptr(), - FLOAT_SIZE, - FLOAT_NEGATIVE_ONE.as_ptr(), - FLOAT_SIZE, - ) - } { - let _ = trace(" repeated subtract: good"); - } else { - let _ = trace(" repeated subtract: failed"); - all_pass = false; - } - - all_pass -} - -fn test_float_mult_divide() -> bool { - let _ = trace("\n$$$ test_float_mult_divide $$$"); - let mut all_pass = true; - - let mut f10: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_from_int( - 10, - f10.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let mut f_compute: [u8; FLOAT_SIZE] = FLOAT_ONE; - for i in 0..6 { - unsafe { - float_mult( - f_compute.as_ptr(), - FLOAT_SIZE, - f10.as_ptr(), - FLOAT_SIZE, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - // let _ = trace_float(" float:", &f_compute); - } - let mut f1000000: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_from_int( - 1000000, - f1000000.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - - if 0 == unsafe { - float_cmp( - f1000000.as_ptr(), - FLOAT_SIZE, - f_compute.as_ptr(), - FLOAT_SIZE, - ) - } { - let _ = trace(" repeated multiply: good"); - } else { - let _ = trace(" repeated multiply: failed"); - all_pass = false; - } - - for i in 0..7 { - unsafe { - float_div( - f_compute.as_ptr(), - FLOAT_SIZE, - f10.as_ptr(), - FLOAT_SIZE, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - } - let mut f01: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_from_mant_exp( - 1, - -1, - f01.as_mut_ptr(), - FLOAT_SIZE as i32, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - - if 0 == unsafe { float_cmp(f_compute.as_ptr(), FLOAT_SIZE, f01.as_ptr(), FLOAT_SIZE) } { - let _ = trace(" repeated divide: good"); - } else { - let _ = trace(" repeated divide: failed"); - all_pass = false; - } - - all_pass -} - -fn test_float_pow() -> bool { - let _ = trace("\n$$$ test_float_pow $$$"); - let mut all_pass = true; - - let mut f_compute: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_pow( - FLOAT_ONE.as_ptr(), - FLOAT_SIZE, - 3, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let _ = trace_float(" float cube of 1:", &f_compute); - - unsafe { - float_pow( - FLOAT_NEGATIVE_ONE.as_ptr(), - FLOAT_SIZE, - 6, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let _ = trace_float(" float 6th power of -1:", &f_compute); - - let mut f9: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_from_int( - 9, - f9.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - unsafe { - float_pow( - f9.as_ptr(), - FLOAT_SIZE, - 2, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let _ = trace_float(" float square of 9:", &f_compute); - - unsafe { - float_pow( - f9.as_ptr(), - FLOAT_SIZE, - 0, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let _ = trace_float(" float 0th power of 9:", &f_compute); - - let mut f0: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_from_int( - 0, - f0.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - unsafe { - float_pow( - f0.as_ptr(), - FLOAT_SIZE, - 2, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let _ = trace_float(" float square of 0:", &f_compute); - - let r = unsafe { - float_pow( - f0.as_ptr(), - FLOAT_SIZE, - 0, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let _ = trace_num( - " float 0th power of 0 (expecting INVALID_PARAMS error):", - r as i64, - ); - - all_pass -} - -fn test_float_root() -> bool { - let _ = trace("\n$$$ test_float_root $$$"); - let mut all_pass = true; - - let mut f9: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_from_int( - 9, - f9.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let mut f_compute: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_root( - f9.as_ptr(), - FLOAT_SIZE, - 2, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let _ = trace_float(" float sqrt of 9:", &f_compute); - unsafe { - float_root( - f9.as_ptr(), - FLOAT_SIZE, - 3, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let _ = trace_float(" float cbrt of 9:", &f_compute); - - let mut f1000000: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_from_int( - 1000000, - f1000000.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - unsafe { - float_root( - f1000000.as_ptr(), - FLOAT_SIZE, - 3, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let _ = trace_float(" float cbrt of 1000000:", &f_compute); - unsafe { - float_root( - f1000000.as_ptr(), - FLOAT_SIZE, - 6, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let _ = trace_float(" float 6th root of 1000000:", &f_compute); - - all_pass -} - -fn test_float_invert() -> bool { - let _ = trace("\n$$$ test_float_invert $$$"); - let mut all_pass = true; - - let mut f_compute: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - let mut f10: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_from_int( - 10, - f10.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - unsafe { - float_div( - FLOAT_ONE.as_ptr(), - FLOAT_SIZE, - f10.as_ptr(), - FLOAT_SIZE, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let _ = trace_float(" invert a float from 10:", &f_compute); - unsafe { - float_div( - FLOAT_ONE.as_ptr(), - FLOAT_SIZE, - f_compute.as_ptr(), - FLOAT_SIZE, - f_compute.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let _ = trace_float(" invert again:", &f_compute); - - // if f10's value is 7, then invert twice won't match the original value - if 0 == unsafe { float_cmp(f10.as_ptr(), FLOAT_SIZE, f_compute.as_ptr(), FLOAT_SIZE) } { - let _ = trace(" invert twice: good"); - } else { - let _ = trace(" invert twice: failed"); - all_pass = false; - } - - all_pass -} - -fn test_float_to_int() -> bool { - let _ = trace("\n$$$ test_float_to_int $$$"); - let mut all_pass = true; - let mut result: [u8; 8] = [0u8; 8]; - - // Test converting FLOAT_ONE (value 1) to int - let ret = unsafe { - float_to_int( - FLOAT_ONE.as_ptr(), - FLOAT_SIZE as i32, - result.as_mut_ptr(), - 8, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - if ret == 8 { - let number = i64::from_le_bytes(result); - if number == 1 { - let _ = trace(" float_to_int(1): good"); - } else { - let _ = trace(" float_to_int(1): failed"); - let _ = trace_num(" got:", number); - all_pass = false; - } - } else { - let _ = trace(" float_to_int(1): failed with error"); - let _ = trace_num(" error code:", ret as i64); - all_pass = false; - } - - // Test converting FLOAT_NEGATIVE_ONE (value -1) to int - let ret = unsafe { - float_to_int( - FLOAT_NEGATIVE_ONE.as_ptr(), - FLOAT_SIZE as i32, - result.as_mut_ptr(), - 8, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - if ret == 8 { - let number = i64::from_le_bytes(result); - if number == -1 { - let _ = trace(" float_to_int(-1): good"); - } else { - let _ = trace(" float_to_int(-1): failed"); - let _ = trace_num(" got:", number); - all_pass = false; - } - } else { - let _ = trace(" float_to_int(-1): failed with error"); - let _ = trace_num(" error code:", ret as i64); - all_pass = false; - } - - // Test converting a larger number (i64::MAX) - let test_val: i64 = i64::MAX; - let mut f_max: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_from_int( - test_val, - f_max.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let ret = unsafe { - float_to_int( - f_max.as_ptr(), - FLOAT_SIZE as i32, - result.as_mut_ptr(), - 8, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - if ret == 8 { - let number = i64::from_le_bytes(result); - if number == test_val { - let _ = trace(" float_to_int(i64::MAX): good"); - } else { - let _ = trace(" float_to_int(i64::MAX): failed"); - let _ = trace_num(" expected:", test_val); - let _ = trace_num(" got:", number); - all_pass = false; - } - } else { - let _ = trace(" float_to_int(i64::MAX): failed with error"); - let _ = trace_num(" error code:", ret as i64); - all_pass = false; - } - - // Test converting zero - let mut f0: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_from_int( - 0, - f0.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let ret = unsafe { - float_to_int( - f0.as_ptr(), - FLOAT_SIZE as i32, - result.as_mut_ptr(), - 8, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - if ret == 8 { - let number = i64::from_le_bytes(result); - if number == 0 { - let _ = trace(" float_to_int(0): good"); - } else { - let _ = trace(" float_to_int(0): failed"); - let _ = trace_num(" got:", number); - all_pass = false; - } - } else { - let _ = trace(" float_to_int(0): failed with error"); - let _ = trace_num(" error code:", ret as i64); - all_pass = false; - } - - // Test rounding with fractional value (0.1) - let mut f01: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_from_mant_exp( - 1, - -1, - f01.as_mut_ptr(), - FLOAT_SIZE as i32, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - let ret = unsafe { - float_to_int( - f01.as_ptr(), - FLOAT_SIZE as i32, - result.as_mut_ptr(), - 8 as i32, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - if ret == 8 as i32 { - let number = i64::from_le_bytes(result); - if number == 0 { - let _ = trace(" float_to_int(0.1, to_nearest): good"); - } else { - let _ = trace(" float_to_int(0.1, to_nearest): failed"); - let _ = trace_num(" got:", number); - all_pass = false; - } - } else { - let _ = trace(" float_to_int(0.1, to_nearest): failed with error"); - let _ = trace_num(" error code:", ret as i64); - all_pass = false; - } - - // Test rounding mode 1 (towards_zero) - let ret = unsafe { - float_to_int( - f01.as_ptr(), - FLOAT_SIZE as i32, - result.as_mut_ptr(), - 8 as i32, - 1, - ) - }; - if ret == 8 as i32 { - let number = i64::from_le_bytes(result); - if number == 0 { - let _ = trace(" float_to_int(0.1, towards_zero): good"); - } else { - let _ = trace(" float_to_int(0.1, towards_zero): failed"); - let _ = trace_num(" got:", number); - all_pass = false; - } - } else { - let _ = trace(" float_to_int(0.1, towards_zero): failed with error"); - let _ = trace_num(" error code:", ret as i64); - all_pass = false; - } - - all_pass -} - -fn test_float_to_mant_exp() -> bool { - let _ = trace("\n$$$ test_float_to_mant_exp $$$"); - let mut all_pass = true; - - // Test with FLOAT_ONE (value 1) - let mut mantissa_bytes: [u8; 8] = [0u8; 8]; - let mut exponent_bytes: [u8; 4] = [0u8; 4]; - let result = unsafe { - float_to_mant_exp( - FLOAT_ONE.as_ptr(), - FLOAT_SIZE as i32, - mantissa_bytes.as_mut_ptr(), - 8, - exponent_bytes.as_mut_ptr(), - 4, - ) - }; - - if result == FLOAT_SIZE as i32 { - let mantissa = i64::from_le_bytes(mantissa_bytes); - let exponent = i32::from_le_bytes(exponent_bytes); - if mantissa == 1000000000000000000 && exponent == -18 { - let _ = trace(" float_to_mant_exp(1): good"); - } else { - let _ = trace(" float_to_mant_exp(1): failed"); - let _ = trace_num(" expected mantissa 1000000000000000000, got:", mantissa); - let _ = trace_num(" expected exponent -18, got:", exponent as i64); - all_pass = false; - } - } else { - let _ = trace(" float_to_mant_exp(1): failed with error"); - let _ = trace_num(" error code:", result as i64); - all_pass = false; - } - - // Test with FLOAT_NEGATIVE_ONE (value -1) - let mut mantissa_bytes: [u8; 8] = [0u8; 8]; - let mut exponent_bytes: [u8; 4] = [0u8; 4]; - let result = unsafe { - float_to_mant_exp( - FLOAT_NEGATIVE_ONE.as_ptr(), - FLOAT_SIZE as i32, - mantissa_bytes.as_mut_ptr(), - 8, - exponent_bytes.as_mut_ptr(), - 4, - ) - }; - - if result == FLOAT_SIZE as i32 { - let mantissa = i64::from_le_bytes(mantissa_bytes); - let exponent = i32::from_le_bytes(exponent_bytes); - if mantissa == -1000000000000000000 && exponent == -18 { - let _ = trace(" float_to_mant_exp(-1): good"); - } else { - let _ = trace(" float_to_mant_exp(-1): failed"); - let _ = trace_num(" expected mantissa -1000000000000000000, got:", mantissa); - let _ = trace_num(" expected exponent -18, got:", exponent as i64); - all_pass = false; - } - } else { - let _ = trace(" float_to_mant_exp(-1): failed with error"); - let _ = trace_num(" error code:", result as i64); - all_pass = false; - } - - // Test with a float created from int (10) - let mut f10: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_from_int( - 10, - f10.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - - let mut mantissa_bytes: [u8; 8] = [0u8; 8]; - let mut exponent_bytes: [u8; 4] = [0u8; 4]; - let result = unsafe { - float_to_mant_exp( - f10.as_ptr(), - FLOAT_SIZE as i32, - mantissa_bytes.as_mut_ptr(), - 8, - exponent_bytes.as_mut_ptr(), - 4, - ) - }; - - if result == FLOAT_SIZE as i32 { - let mantissa = i64::from_le_bytes(mantissa_bytes); - let exponent = i32::from_le_bytes(exponent_bytes); - if mantissa == 1000000000000000000 && exponent == -17 { - let _ = trace(" float_to_mant_exp(10): good"); - } else { - let _ = trace(" float_to_mant_exp(10): failed"); - let _ = trace_num(" expected mantissa 1000000000000000000, got:", mantissa); - let _ = trace_num(" expected exponent -17, got:", exponent as i64); - all_pass = false; - } - } else { - let _ = trace(" float_to_mant_exp(10): failed with error"); - let _ = trace_num(" error code:", result as i64); - all_pass = false; - } - - // Test with zero - let mut f0: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - unsafe { - float_from_int( - 0, - f0.as_mut_ptr(), - FLOAT_SIZE, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - - let mut mantissa_bytes: [u8; 8] = [0u8; 8]; - let mut exponent_bytes: [u8; 4] = [0u8; 4]; - let result = unsafe { - float_to_mant_exp( - f0.as_ptr(), - FLOAT_SIZE as i32, - mantissa_bytes.as_mut_ptr(), - 8, - exponent_bytes.as_mut_ptr(), - 4, - ) - }; - - if result == FLOAT_SIZE as i32 { - let mantissa = i64::from_le_bytes(mantissa_bytes); - let exponent = i32::from_le_bytes(exponent_bytes); - if mantissa == 0 && exponent == -2147483648 { - let _ = trace(" float_to_mant_exp(0): good"); - } else { - let _ = trace(" float_to_mant_exp(0): failed"); - let _ = trace_num(" expected mantissa 0, got:", mantissa); - let _ = trace_num(" expected exponent -2147483648, got:", exponent as i64); - all_pass = false; - } - } else { - let _ = trace(" float_to_mant_exp(0): failed with error"); - let _ = trace_num(" error code:", result as i64); - all_pass = false; - } - - all_pass -} - -fn test_float_from_stamount() -> bool { - let _ = trace("\n$$$ test_float_from_stamount $$$"); - let mut all_pass = true; - - // STAmount is serialized as: - // - 1 byte: type/flags - // - 8 bytes: amount (for XRP) or mantissa (for IOU) - // - For IOU: additional currency and issuer fields - - // Create an XRP amount: 100 XRP = 100,000,000 drops - // XRP format: bit 62 clear (not IOU), bit 63 clear (not negative) - // Amount in drops: 100,000,000 = 0x05F5E100 - let xrp_amount: [u8; 8] = [0x40, 0x00, 0x00, 0x00, 0x05, 0xF5, 0xE1, 0x00]; - - let mut f_result: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - let result_size = unsafe { - float_from_stamount( - xrp_amount.as_ptr(), - 8, - f_result.as_mut_ptr(), - FLOAT_SIZE as i32, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - - if result_size == FLOAT_SIZE as i32 { - let _ = trace_float(" float from XRP amount (100 XRP):", &f_result); - - // Convert back to int to verify - let mut int_bytes: [u8; 8] = [0u8; 8]; - let ret = unsafe { - float_to_int( - f_result.as_ptr(), - FLOAT_SIZE as i32, - int_bytes.as_mut_ptr(), - 8, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - if ret == 8 { - let int_val = i64::from_le_bytes(int_bytes); - if int_val == 100000000 { - let _ = trace(" XRP amount conversion: good"); - } else { - let _ = trace(" XRP amount conversion: failed"); - let _ = trace_num(" expected 100000000, got:", int_val); - all_pass = false; - } - } else { - let _ = trace(" XRP amount conversion: failed - float_to_int error"); - let _ = trace_num(" error code:", ret as i64); - all_pass = false; - } - } else { - let _ = trace(" float from XRP amount: failed"); - let _ = trace_num(" result_size:", result_size as i64); - all_pass = false; - } - - all_pass -} - -fn test_float_from_stnumber() -> bool { - let _ = trace("\n$$$ test_float_from_stnumber $$$"); - let mut all_pass = true; - - // STNumber is serialized as: - // - 8 bytes: mantissa (big-endian signed int64) - // - 4 bytes: exponent (big-endian signed int32) - - // Create STNumber for value 123 (mantissa=123*10^18, exponent=-18) - // mantissa = 123000000000000000000 = 0x6ADF37F675EF6B28000 - // But we need to fit in int64, so use mantissa=123*10^15, exponent=-15 - // 123*10^15 = 123000000000000000 = 0x01B69B4BA630F34000 - let stnumber_123: [u8; 12] = [ - 0x01, 0xB6, 0x9B, 0x4B, 0xA6, 0x30, 0xF3, 0x40, // mantissa - 0xFF, 0xFF, 0xFF, 0xF1, // exponent = -15 - ]; - - let mut f_result: [u8; FLOAT_SIZE] = [0u8; FLOAT_SIZE]; - let result_size = unsafe { - float_from_stnumber( - stnumber_123.as_ptr(), - 12, - f_result.as_mut_ptr(), - FLOAT_SIZE as i32, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - - if result_size == FLOAT_SIZE as i32 { - let _ = trace_float(" float from STNumber (123):", &f_result); - - // Convert back to int to verify - let mut int_bytes: [u8; 8] = [0u8; 8]; - let ret = unsafe { - float_to_int( - f_result.as_ptr(), - FLOAT_SIZE as i32, - int_bytes.as_mut_ptr(), - 8, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - if ret == 8 { - let int_val = i64::from_le_bytes(int_bytes); - if int_val == 123 { - let _ = trace(" STNumber conversion: good"); - } else { - let _ = trace(" STNumber conversion: failed"); - let _ = trace_num(" expected 123, got:", int_val); - all_pass = false; - } - } else { - let _ = trace(" STNumber conversion: failed - float_to_int error"); - let _ = trace_num(" error code:", ret as i64); - all_pass = false; - } - } else { - let _ = trace(" float from STNumber: failed"); - let _ = trace_num(" result_size:", result_size as i64); - all_pass = false; - } - - // Test with FLOAT_ONE constant (which is already in STNumber format) - let result_size = unsafe { - float_from_stnumber( - FLOAT_ONE.as_ptr(), - FLOAT_SIZE as i32, - f_result.as_mut_ptr(), - FLOAT_SIZE as i32, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }; - - if result_size == FLOAT_SIZE as i32 { - let _ = trace_float(" float from STNumber (1):", &f_result); - - // Should match FLOAT_ONE - if 0 == unsafe { - float_cmp( - f_result.as_ptr(), - FLOAT_SIZE, - FLOAT_ONE.as_ptr(), - FLOAT_SIZE, - ) - } { - let _ = trace(" STNumber(1) == FLOAT_ONE: good"); - } else { - let _ = trace(" STNumber(1) == FLOAT_ONE: failed"); - all_pass = false; - } - } else { - let _ = trace(" float from STNumber(1): failed"); - all_pass = false; - } - - all_pass -} - -#[unsafe(no_mangle)] -pub extern "C" fn escrow_finish() -> i32 { - let mut all_pass = true; - all_pass &= test_float_from_wasm(); - all_pass &= test_float_cmp(); - all_pass &= test_float_add_subtract(); - all_pass &= test_float_mult_divide(); - all_pass &= test_float_pow(); - all_pass &= test_float_root(); - all_pass &= test_float_invert(); - all_pass &= test_float_to_int(); - all_pass &= test_float_to_mant_exp(); - all_pass &= test_float_from_stamount(); - all_pass &= test_float_from_stnumber(); - - if all_pass { - 1 - } else { - 0 - } -} diff --git a/src/test/app/wasm_fixtures/infiniteLoop.c b/src/test/app/wasm_fixtures/infiniteLoop.c deleted file mode 100644 index ba84a92ac1..0000000000 --- a/src/test/app/wasm_fixtures/infiniteLoop.c +++ /dev/null @@ -1,7 +0,0 @@ -int loop() -{ - int volatile x = 0; - while (1) - x++; - return x; -} diff --git a/src/test/app/wasm_fixtures/ledgerSqn.c b/src/test/app/wasm_fixtures/ledgerSqn.c deleted file mode 100644 index 0f4c27af7d..0000000000 --- a/src/test/app/wasm_fixtures/ledgerSqn.c +++ /dev/null @@ -1,14 +0,0 @@ -#include - -int32_t ldgr_index(uint8_t *, int32_t); - -int escrow_finish() -{ - uint32_t sqn; - int32_t result = ldgr_index((uint8_t *)&sqn, sizeof(sqn)); - - if (result < 0) - return result; - - return sqn >= 5 ? 5 : 0; -} diff --git a/src/test/app/wasm_fixtures/thousand1_params.c b/src/test/app/wasm_fixtures/thousand1_params.c deleted file mode 100644 index 1a281461c4..0000000000 --- a/src/test/app/wasm_fixtures/thousand1_params.c +++ /dev/null @@ -1,264 +0,0 @@ -// clang-format off - -#include - -int32_t test( - int32_t p0, int32_t p1, int32_t p2, int32_t p3, int32_t p4, int32_t p5, int32_t p6, int32_t p7 -, int32_t p8, int32_t p9, int32_t p10, int32_t p11, int32_t p12, int32_t p13, int32_t p14, int32_t p15 -, int32_t p16, int32_t p17, int32_t p18, int32_t p19, int32_t p20, int32_t p21, int32_t p22, int32_t p23 -, int32_t p24, int32_t p25, int32_t p26, int32_t p27, int32_t p28, int32_t p29, int32_t p30, int32_t p31 -, int32_t p32, int32_t p33, int32_t p34, int32_t p35, int32_t p36, int32_t p37, int32_t p38, int32_t p39 -, int32_t p40, int32_t p41, int32_t p42, int32_t p43, int32_t p44, int32_t p45, int32_t p46, int32_t p47 -, int32_t p48, int32_t p49, int32_t p50, int32_t p51, int32_t p52, int32_t p53, int32_t p54, int32_t p55 -, int32_t p56, int32_t p57, int32_t p58, int32_t p59, int32_t p60, int32_t p61, int32_t p62, int32_t p63 -, int32_t p64, int32_t p65, int32_t p66, int32_t p67, int32_t p68, int32_t p69, int32_t p70, int32_t p71 -, int32_t p72, int32_t p73, int32_t p74, int32_t p75, int32_t p76, int32_t p77, int32_t p78, int32_t p79 -, int32_t p80, int32_t p81, int32_t p82, int32_t p83, int32_t p84, int32_t p85, int32_t p86, int32_t p87 -, int32_t p88, int32_t p89, int32_t p90, int32_t p91, int32_t p92, int32_t p93, int32_t p94, int32_t p95 -, int32_t p96, int32_t p97, int32_t p98, int32_t p99, int32_t p100, int32_t p101, int32_t p102, int32_t p103 -, int32_t p104, int32_t p105, int32_t p106, int32_t p107, int32_t p108, int32_t p109, int32_t p110, int32_t p111 -, int32_t p112, int32_t p113, int32_t p114, int32_t p115, int32_t p116, int32_t p117, int32_t p118, int32_t p119 -, int32_t p120, int32_t p121, int32_t p122, int32_t p123, int32_t p124, int32_t p125, int32_t p126, int32_t p127 -, int32_t p128, int32_t p129, int32_t p130, int32_t p131, int32_t p132, int32_t p133, int32_t p134, int32_t p135 -, int32_t p136, int32_t p137, int32_t p138, int32_t p139, int32_t p140, int32_t p141, int32_t p142, int32_t p143 -, int32_t p144, int32_t p145, int32_t p146, int32_t p147, int32_t p148, int32_t p149, int32_t p150, int32_t p151 -, int32_t p152, int32_t p153, int32_t p154, int32_t p155, int32_t p156, int32_t p157, int32_t p158, int32_t p159 -, int32_t p160, int32_t p161, int32_t p162, int32_t p163, int32_t p164, int32_t p165, int32_t p166, int32_t p167 -, int32_t p168, int32_t p169, int32_t p170, int32_t p171, int32_t p172, int32_t p173, int32_t p174, int32_t p175 -, int32_t p176, int32_t p177, int32_t p178, int32_t p179, int32_t p180, int32_t p181, int32_t p182, int32_t p183 -, int32_t p184, int32_t p185, int32_t p186, int32_t p187, int32_t p188, int32_t p189, int32_t p190, int32_t p191 -, int32_t p192, int32_t p193, int32_t p194, int32_t p195, int32_t p196, int32_t p197, int32_t p198, int32_t p199 -, int32_t p200, int32_t p201, int32_t p202, int32_t p203, int32_t p204, int32_t p205, int32_t p206, int32_t p207 -, int32_t p208, int32_t p209, int32_t p210, int32_t p211, int32_t p212, int32_t p213, int32_t p214, int32_t p215 -, int32_t p216, int32_t p217, int32_t p218, int32_t p219, int32_t p220, int32_t p221, int32_t p222, int32_t p223 -, int32_t p224, int32_t p225, int32_t p226, int32_t p227, int32_t p228, int32_t p229, int32_t p230, int32_t p231 -, int32_t p232, int32_t p233, int32_t p234, int32_t p235, int32_t p236, int32_t p237, int32_t p238, int32_t p239 -, int32_t p240, int32_t p241, int32_t p242, int32_t p243, int32_t p244, int32_t p245, int32_t p246, int32_t p247 -, int32_t p248, int32_t p249, int32_t p250, int32_t p251, int32_t p252, int32_t p253, int32_t p254, int32_t p255 -, int32_t p256, int32_t p257, int32_t p258, int32_t p259, int32_t p260, int32_t p261, int32_t p262, int32_t p263 -, int32_t p264, int32_t p265, int32_t p266, int32_t p267, int32_t p268, int32_t p269, int32_t p270, int32_t p271 -, int32_t p272, int32_t p273, int32_t p274, int32_t p275, int32_t p276, int32_t p277, int32_t p278, int32_t p279 -, int32_t p280, int32_t p281, int32_t p282, int32_t p283, int32_t p284, int32_t p285, int32_t p286, int32_t p287 -, int32_t p288, int32_t p289, int32_t p290, int32_t p291, int32_t p292, int32_t p293, int32_t p294, int32_t p295 -, int32_t p296, int32_t p297, int32_t p298, int32_t p299, int32_t p300, int32_t p301, int32_t p302, int32_t p303 -, int32_t p304, int32_t p305, int32_t p306, int32_t p307, int32_t p308, int32_t p309, int32_t p310, int32_t p311 -, int32_t p312, int32_t p313, int32_t p314, int32_t p315, int32_t p316, int32_t p317, int32_t p318, int32_t p319 -, int32_t p320, int32_t p321, int32_t p322, int32_t p323, int32_t p324, int32_t p325, int32_t p326, int32_t p327 -, int32_t p328, int32_t p329, int32_t p330, int32_t p331, int32_t p332, int32_t p333, int32_t p334, int32_t p335 -, int32_t p336, int32_t p337, int32_t p338, int32_t p339, int32_t p340, int32_t p341, int32_t p342, int32_t p343 -, int32_t p344, int32_t p345, int32_t p346, int32_t p347, int32_t p348, int32_t p349, int32_t p350, int32_t p351 -, int32_t p352, int32_t p353, int32_t p354, int32_t p355, int32_t p356, int32_t p357, int32_t p358, int32_t p359 -, int32_t p360, int32_t p361, int32_t p362, int32_t p363, int32_t p364, int32_t p365, int32_t p366, int32_t p367 -, int32_t p368, int32_t p369, int32_t p370, int32_t p371, int32_t p372, int32_t p373, int32_t p374, int32_t p375 -, int32_t p376, int32_t p377, int32_t p378, int32_t p379, int32_t p380, int32_t p381, int32_t p382, int32_t p383 -, int32_t p384, int32_t p385, int32_t p386, int32_t p387, int32_t p388, int32_t p389, int32_t p390, int32_t p391 -, int32_t p392, int32_t p393, int32_t p394, int32_t p395, int32_t p396, int32_t p397, int32_t p398, int32_t p399 -, int32_t p400, int32_t p401, int32_t p402, int32_t p403, int32_t p404, int32_t p405, int32_t p406, int32_t p407 -, int32_t p408, int32_t p409, int32_t p410, int32_t p411, int32_t p412, int32_t p413, int32_t p414, int32_t p415 -, int32_t p416, int32_t p417, int32_t p418, int32_t p419, int32_t p420, int32_t p421, int32_t p422, int32_t p423 -, int32_t p424, int32_t p425, int32_t p426, int32_t p427, int32_t p428, int32_t p429, int32_t p430, int32_t p431 -, int32_t p432, int32_t p433, int32_t p434, int32_t p435, int32_t p436, int32_t p437, int32_t p438, int32_t p439 -, int32_t p440, int32_t p441, int32_t p442, int32_t p443, int32_t p444, int32_t p445, int32_t p446, int32_t p447 -, int32_t p448, int32_t p449, int32_t p450, int32_t p451, int32_t p452, int32_t p453, int32_t p454, int32_t p455 -, int32_t p456, int32_t p457, int32_t p458, int32_t p459, int32_t p460, int32_t p461, int32_t p462, int32_t p463 -, int32_t p464, int32_t p465, int32_t p466, int32_t p467, int32_t p468, int32_t p469, int32_t p470, int32_t p471 -, int32_t p472, int32_t p473, int32_t p474, int32_t p475, int32_t p476, int32_t p477, int32_t p478, int32_t p479 -, int32_t p480, int32_t p481, int32_t p482, int32_t p483, int32_t p484, int32_t p485, int32_t p486, int32_t p487 -, int32_t p488, int32_t p489, int32_t p490, int32_t p491, int32_t p492, int32_t p493, int32_t p494, int32_t p495 -, int32_t p496, int32_t p497, int32_t p498, int32_t p499, int32_t p500, int32_t p501, int32_t p502, int32_t p503 -, int32_t p504, int32_t p505, int32_t p506, int32_t p507, int32_t p508, int32_t p509, int32_t p510, int32_t p511 -, int32_t p512, int32_t p513, int32_t p514, int32_t p515, int32_t p516, int32_t p517, int32_t p518, int32_t p519 -, int32_t p520, int32_t p521, int32_t p522, int32_t p523, int32_t p524, int32_t p525, int32_t p526, int32_t p527 -, int32_t p528, int32_t p529, int32_t p530, int32_t p531, int32_t p532, int32_t p533, int32_t p534, int32_t p535 -, int32_t p536, int32_t p537, int32_t p538, int32_t p539, int32_t p540, int32_t p541, int32_t p542, int32_t p543 -, int32_t p544, int32_t p545, int32_t p546, int32_t p547, int32_t p548, int32_t p549, int32_t p550, int32_t p551 -, int32_t p552, int32_t p553, int32_t p554, int32_t p555, int32_t p556, int32_t p557, int32_t p558, int32_t p559 -, int32_t p560, int32_t p561, int32_t p562, int32_t p563, int32_t p564, int32_t p565, int32_t p566, int32_t p567 -, int32_t p568, int32_t p569, int32_t p570, int32_t p571, int32_t p572, int32_t p573, int32_t p574, int32_t p575 -, int32_t p576, int32_t p577, int32_t p578, int32_t p579, int32_t p580, int32_t p581, int32_t p582, int32_t p583 -, int32_t p584, int32_t p585, int32_t p586, int32_t p587, int32_t p588, int32_t p589, int32_t p590, int32_t p591 -, int32_t p592, int32_t p593, int32_t p594, int32_t p595, int32_t p596, int32_t p597, int32_t p598, int32_t p599 -, int32_t p600, int32_t p601, int32_t p602, int32_t p603, int32_t p604, int32_t p605, int32_t p606, int32_t p607 -, int32_t p608, int32_t p609, int32_t p610, int32_t p611, int32_t p612, int32_t p613, int32_t p614, int32_t p615 -, int32_t p616, int32_t p617, int32_t p618, int32_t p619, int32_t p620, int32_t p621, int32_t p622, int32_t p623 -, int32_t p624, int32_t p625, int32_t p626, int32_t p627, int32_t p628, int32_t p629, int32_t p630, int32_t p631 -, int32_t p632, int32_t p633, int32_t p634, int32_t p635, int32_t p636, int32_t p637, int32_t p638, int32_t p639 -, int32_t p640, int32_t p641, int32_t p642, int32_t p643, int32_t p644, int32_t p645, int32_t p646, int32_t p647 -, int32_t p648, int32_t p649, int32_t p650, int32_t p651, int32_t p652, int32_t p653, int32_t p654, int32_t p655 -, int32_t p656, int32_t p657, int32_t p658, int32_t p659, int32_t p660, int32_t p661, int32_t p662, int32_t p663 -, int32_t p664, int32_t p665, int32_t p666, int32_t p667, int32_t p668, int32_t p669, int32_t p670, int32_t p671 -, int32_t p672, int32_t p673, int32_t p674, int32_t p675, int32_t p676, int32_t p677, int32_t p678, int32_t p679 -, int32_t p680, int32_t p681, int32_t p682, int32_t p683, int32_t p684, int32_t p685, int32_t p686, int32_t p687 -, int32_t p688, int32_t p689, int32_t p690, int32_t p691, int32_t p692, int32_t p693, int32_t p694, int32_t p695 -, int32_t p696, int32_t p697, int32_t p698, int32_t p699, int32_t p700, int32_t p701, int32_t p702, int32_t p703 -, int32_t p704, int32_t p705, int32_t p706, int32_t p707, int32_t p708, int32_t p709, int32_t p710, int32_t p711 -, int32_t p712, int32_t p713, int32_t p714, int32_t p715, int32_t p716, int32_t p717, int32_t p718, int32_t p719 -, int32_t p720, int32_t p721, int32_t p722, int32_t p723, int32_t p724, int32_t p725, int32_t p726, int32_t p727 -, int32_t p728, int32_t p729, int32_t p730, int32_t p731, int32_t p732, int32_t p733, int32_t p734, int32_t p735 -, int32_t p736, int32_t p737, int32_t p738, int32_t p739, int32_t p740, int32_t p741, int32_t p742, int32_t p743 -, int32_t p744, int32_t p745, int32_t p746, int32_t p747, int32_t p748, int32_t p749, int32_t p750, int32_t p751 -, int32_t p752, int32_t p753, int32_t p754, int32_t p755, int32_t p756, int32_t p757, int32_t p758, int32_t p759 -, int32_t p760, int32_t p761, int32_t p762, int32_t p763, int32_t p764, int32_t p765, int32_t p766, int32_t p767 -, int32_t p768, int32_t p769, int32_t p770, int32_t p771, int32_t p772, int32_t p773, int32_t p774, int32_t p775 -, int32_t p776, int32_t p777, int32_t p778, int32_t p779, int32_t p780, int32_t p781, int32_t p782, int32_t p783 -, int32_t p784, int32_t p785, int32_t p786, int32_t p787, int32_t p788, int32_t p789, int32_t p790, int32_t p791 -, int32_t p792, int32_t p793, int32_t p794, int32_t p795, int32_t p796, int32_t p797, int32_t p798, int32_t p799 -, int32_t p800, int32_t p801, int32_t p802, int32_t p803, int32_t p804, int32_t p805, int32_t p806, int32_t p807 -, int32_t p808, int32_t p809, int32_t p810, int32_t p811, int32_t p812, int32_t p813, int32_t p814, int32_t p815 -, int32_t p816, int32_t p817, int32_t p818, int32_t p819, int32_t p820, int32_t p821, int32_t p822, int32_t p823 -, int32_t p824, int32_t p825, int32_t p826, int32_t p827, int32_t p828, int32_t p829, int32_t p830, int32_t p831 -, int32_t p832, int32_t p833, int32_t p834, int32_t p835, int32_t p836, int32_t p837, int32_t p838, int32_t p839 -, int32_t p840, int32_t p841, int32_t p842, int32_t p843, int32_t p844, int32_t p845, int32_t p846, int32_t p847 -, int32_t p848, int32_t p849, int32_t p850, int32_t p851, int32_t p852, int32_t p853, int32_t p854, int32_t p855 -, int32_t p856, int32_t p857, int32_t p858, int32_t p859, int32_t p860, int32_t p861, int32_t p862, int32_t p863 -, int32_t p864, int32_t p865, int32_t p866, int32_t p867, int32_t p868, int32_t p869, int32_t p870, int32_t p871 -, int32_t p872, int32_t p873, int32_t p874, int32_t p875, int32_t p876, int32_t p877, int32_t p878, int32_t p879 -, int32_t p880, int32_t p881, int32_t p882, int32_t p883, int32_t p884, int32_t p885, int32_t p886, int32_t p887 -, int32_t p888, int32_t p889, int32_t p890, int32_t p891, int32_t p892, int32_t p893, int32_t p894, int32_t p895 -, int32_t p896, int32_t p897, int32_t p898, int32_t p899, int32_t p900, int32_t p901, int32_t p902, int32_t p903 -, int32_t p904, int32_t p905, int32_t p906, int32_t p907, int32_t p908, int32_t p909, int32_t p910, int32_t p911 -, int32_t p912, int32_t p913, int32_t p914, int32_t p915, int32_t p916, int32_t p917, int32_t p918, int32_t p919 -, int32_t p920, int32_t p921, int32_t p922, int32_t p923, int32_t p924, int32_t p925, int32_t p926, int32_t p927 -, int32_t p928, int32_t p929, int32_t p930, int32_t p931, int32_t p932, int32_t p933, int32_t p934, int32_t p935 -, int32_t p936, int32_t p937, int32_t p938, int32_t p939, int32_t p940, int32_t p941, int32_t p942, int32_t p943 -, int32_t p944, int32_t p945, int32_t p946, int32_t p947, int32_t p948, int32_t p949, int32_t p950, int32_t p951 -, int32_t p952, int32_t p953, int32_t p954, int32_t p955, int32_t p956, int32_t p957, int32_t p958, int32_t p959 -, int32_t p960, int32_t p961, int32_t p962, int32_t p963, int32_t p964, int32_t p965, int32_t p966, int32_t p967 -, int32_t p968, int32_t p969, int32_t p970, int32_t p971, int32_t p972, int32_t p973, int32_t p974, int32_t p975 -, int32_t p976, int32_t p977, int32_t p978, int32_t p979, int32_t p980, int32_t p981, int32_t p982, int32_t p983 -, int32_t p984, int32_t p985, int32_t p986, int32_t p987, int32_t p988, int32_t p989, int32_t p990, int32_t p991 -, int32_t p992, int32_t p993, int32_t p994, int32_t p995, int32_t p996, int32_t p997, int32_t p998, int32_t p999 -, int32_t p1000 -) -{ - int32_t x; - x = p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 - + p8 + p9 + p10 + p11 + p12 + p13 + p14 + p15 - + p16 + p17 + p18 + p19 + p20 + p21 + p22 + p23 - + p24 + p25 + p26 + p27 + p28 + p29 + p30 + p31 - + p32 + p33 + p34 + p35 + p36 + p37 + p38 + p39 - + p40 + p41 + p42 + p43 + p44 + p45 + p46 + p47 - + p48 + p49 + p50 + p51 + p52 + p53 + p54 + p55 - + p56 + p57 + p58 + p59 + p60 + p61 + p62 + p63 - + p64 + p65 + p66 + p67 + p68 + p69 + p70 + p71 - + p72 + p73 + p74 + p75 + p76 + p77 + p78 + p79 - + p80 + p81 + p82 + p83 + p84 + p85 + p86 + p87 - + p88 + p89 + p90 + p91 + p92 + p93 + p94 + p95 - + p96 + p97 + p98 + p99 + p100 + p101 + p102 + p103 - + p104 + p105 + p106 + p107 + p108 + p109 + p110 + p111 - + p112 + p113 + p114 + p115 + p116 + p117 + p118 + p119 - + p120 + p121 + p122 + p123 + p124 + p125 + p126 + p127 - + p128 + p129 + p130 + p131 + p132 + p133 + p134 + p135 - + p136 + p137 + p138 + p139 + p140 + p141 + p142 + p143 - + p144 + p145 + p146 + p147 + p148 + p149 + p150 + p151 - + p152 + p153 + p154 + p155 + p156 + p157 + p158 + p159 - + p160 + p161 + p162 + p163 + p164 + p165 + p166 + p167 - + p168 + p169 + p170 + p171 + p172 + p173 + p174 + p175 - + p176 + p177 + p178 + p179 + p180 + p181 + p182 + p183 - + p184 + p185 + p186 + p187 + p188 + p189 + p190 + p191 - + p192 + p193 + p194 + p195 + p196 + p197 + p198 + p199 - + p200 + p201 + p202 + p203 + p204 + p205 + p206 + p207 - + p208 + p209 + p210 + p211 + p212 + p213 + p214 + p215 - + p216 + p217 + p218 + p219 + p220 + p221 + p222 + p223 - + p224 + p225 + p226 + p227 + p228 + p229 + p230 + p231 - + p232 + p233 + p234 + p235 + p236 + p237 + p238 + p239 - + p240 + p241 + p242 + p243 + p244 + p245 + p246 + p247 - + p248 + p249 + p250 + p251 + p252 + p253 + p254 + p255 - + p256 + p257 + p258 + p259 + p260 + p261 + p262 + p263 - + p264 + p265 + p266 + p267 + p268 + p269 + p270 + p271 - + p272 + p273 + p274 + p275 + p276 + p277 + p278 + p279 - + p280 + p281 + p282 + p283 + p284 + p285 + p286 + p287 - + p288 + p289 + p290 + p291 + p292 + p293 + p294 + p295 - + p296 + p297 + p298 + p299 + p300 + p301 + p302 + p303 - + p304 + p305 + p306 + p307 + p308 + p309 + p310 + p311 - + p312 + p313 + p314 + p315 + p316 + p317 + p318 + p319 - + p320 + p321 + p322 + p323 + p324 + p325 + p326 + p327 - + p328 + p329 + p330 + p331 + p332 + p333 + p334 + p335 - + p336 + p337 + p338 + p339 + p340 + p341 + p342 + p343 - + p344 + p345 + p346 + p347 + p348 + p349 + p350 + p351 - + p352 + p353 + p354 + p355 + p356 + p357 + p358 + p359 - + p360 + p361 + p362 + p363 + p364 + p365 + p366 + p367 - + p368 + p369 + p370 + p371 + p372 + p373 + p374 + p375 - + p376 + p377 + p378 + p379 + p380 + p381 + p382 + p383 - + p384 + p385 + p386 + p387 + p388 + p389 + p390 + p391 - + p392 + p393 + p394 + p395 + p396 + p397 + p398 + p399 - + p400 + p401 + p402 + p403 + p404 + p405 + p406 + p407 - + p408 + p409 + p410 + p411 + p412 + p413 + p414 + p415 - + p416 + p417 + p418 + p419 + p420 + p421 + p422 + p423 - + p424 + p425 + p426 + p427 + p428 + p429 + p430 + p431 - + p432 + p433 + p434 + p435 + p436 + p437 + p438 + p439 - + p440 + p441 + p442 + p443 + p444 + p445 + p446 + p447 - + p448 + p449 + p450 + p451 + p452 + p453 + p454 + p455 - + p456 + p457 + p458 + p459 + p460 + p461 + p462 + p463 - + p464 + p465 + p466 + p467 + p468 + p469 + p470 + p471 - + p472 + p473 + p474 + p475 + p476 + p477 + p478 + p479 - + p480 + p481 + p482 + p483 + p484 + p485 + p486 + p487 - + p488 + p489 + p490 + p491 + p492 + p493 + p494 + p495 - + p496 + p497 + p498 + p499 + p500 + p501 + p502 + p503 - + p504 + p505 + p506 + p507 + p508 + p509 + p510 + p511 - + p512 + p513 + p514 + p515 + p516 + p517 + p518 + p519 - + p520 + p521 + p522 + p523 + p524 + p525 + p526 + p527 - + p528 + p529 + p530 + p531 + p532 + p533 + p534 + p535 - + p536 + p537 + p538 + p539 + p540 + p541 + p542 + p543 - + p544 + p545 + p546 + p547 + p548 + p549 + p550 + p551 - + p552 + p553 + p554 + p555 + p556 + p557 + p558 + p559 - + p560 + p561 + p562 + p563 + p564 + p565 + p566 + p567 - + p568 + p569 + p570 + p571 + p572 + p573 + p574 + p575 - + p576 + p577 + p578 + p579 + p580 + p581 + p582 + p583 - + p584 + p585 + p586 + p587 + p588 + p589 + p590 + p591 - + p592 + p593 + p594 + p595 + p596 + p597 + p598 + p599 - + p600 + p601 + p602 + p603 + p604 + p605 + p606 + p607 - + p608 + p609 + p610 + p611 + p612 + p613 + p614 + p615 - + p616 + p617 + p618 + p619 + p620 + p621 + p622 + p623 - + p624 + p625 + p626 + p627 + p628 + p629 + p630 + p631 - + p632 + p633 + p634 + p635 + p636 + p637 + p638 + p639 - + p640 + p641 + p642 + p643 + p644 + p645 + p646 + p647 - + p648 + p649 + p650 + p651 + p652 + p653 + p654 + p655 - + p656 + p657 + p658 + p659 + p660 + p661 + p662 + p663 - + p664 + p665 + p666 + p667 + p668 + p669 + p670 + p671 - + p672 + p673 + p674 + p675 + p676 + p677 + p678 + p679 - + p680 + p681 + p682 + p683 + p684 + p685 + p686 + p687 - + p688 + p689 + p690 + p691 + p692 + p693 + p694 + p695 - + p696 + p697 + p698 + p699 + p700 + p701 + p702 + p703 - + p704 + p705 + p706 + p707 + p708 + p709 + p710 + p711 - + p712 + p713 + p714 + p715 + p716 + p717 + p718 + p719 - + p720 + p721 + p722 + p723 + p724 + p725 + p726 + p727 - + p728 + p729 + p730 + p731 + p732 + p733 + p734 + p735 - + p736 + p737 + p738 + p739 + p740 + p741 + p742 + p743 - + p744 + p745 + p746 + p747 + p748 + p749 + p750 + p751 - + p752 + p753 + p754 + p755 + p756 + p757 + p758 + p759 - + p760 + p761 + p762 + p763 + p764 + p765 + p766 + p767 - + p768 + p769 + p770 + p771 + p772 + p773 + p774 + p775 - + p776 + p777 + p778 + p779 + p780 + p781 + p782 + p783 - + p784 + p785 + p786 + p787 + p788 + p789 + p790 + p791 - + p792 + p793 + p794 + p795 + p796 + p797 + p798 + p799 - + p800 + p801 + p802 + p803 + p804 + p805 + p806 + p807 - + p808 + p809 + p810 + p811 + p812 + p813 + p814 + p815 - + p816 + p817 + p818 + p819 + p820 + p821 + p822 + p823 - + p824 + p825 + p826 + p827 + p828 + p829 + p830 + p831 - + p832 + p833 + p834 + p835 + p836 + p837 + p838 + p839 - + p840 + p841 + p842 + p843 + p844 + p845 + p846 + p847 - + p848 + p849 + p850 + p851 + p852 + p853 + p854 + p855 - + p856 + p857 + p858 + p859 + p860 + p861 + p862 + p863 - + p864 + p865 + p866 + p867 + p868 + p869 + p870 + p871 - + p872 + p873 + p874 + p875 + p876 + p877 + p878 + p879 - + p880 + p881 + p882 + p883 + p884 + p885 + p886 + p887 - + p888 + p889 + p890 + p891 + p892 + p893 + p894 + p895 - + p896 + p897 + p898 + p899 + p900 + p901 + p902 + p903 - + p904 + p905 + p906 + p907 + p908 + p909 + p910 + p911 - + p912 + p913 + p914 + p915 + p916 + p917 + p918 + p919 - + p920 + p921 + p922 + p923 + p924 + p925 + p926 + p927 - + p928 + p929 + p930 + p931 + p932 + p933 + p934 + p935 - + p936 + p937 + p938 + p939 + p940 + p941 + p942 + p943 - + p944 + p945 + p946 + p947 + p948 + p949 + p950 + p951 - + p952 + p953 + p954 + p955 + p956 + p957 + p958 + p959 - + p960 + p961 + p962 + p963 + p964 + p965 + p966 + p967 - + p968 + p969 + p970 + p971 + p972 + p973 + p974 + p975 - + p976 + p977 + p978 + p979 + p980 + p981 + p982 + p983 - + p984 + p985 + p986 + p987 + p988 + p989 + p990 + p991 - + p992 + p993 + p994 + p995 + p996 + p997 + p998 + p999 - + p1000; - return x; -} - -// clang-format on diff --git a/src/test/app/wasm_fixtures/thousand_params.c b/src/test/app/wasm_fixtures/thousand_params.c deleted file mode 100644 index d934ca38c8..0000000000 --- a/src/test/app/wasm_fixtures/thousand_params.c +++ /dev/null @@ -1,262 +0,0 @@ -// clang-format off - -#include - -int32_t test( - int32_t p0, int32_t p1, int32_t p2, int32_t p3, int32_t p4, int32_t p5, int32_t p6, int32_t p7 -, int32_t p8, int32_t p9, int32_t p10, int32_t p11, int32_t p12, int32_t p13, int32_t p14, int32_t p15 -, int32_t p16, int32_t p17, int32_t p18, int32_t p19, int32_t p20, int32_t p21, int32_t p22, int32_t p23 -, int32_t p24, int32_t p25, int32_t p26, int32_t p27, int32_t p28, int32_t p29, int32_t p30, int32_t p31 -, int32_t p32, int32_t p33, int32_t p34, int32_t p35, int32_t p36, int32_t p37, int32_t p38, int32_t p39 -, int32_t p40, int32_t p41, int32_t p42, int32_t p43, int32_t p44, int32_t p45, int32_t p46, int32_t p47 -, int32_t p48, int32_t p49, int32_t p50, int32_t p51, int32_t p52, int32_t p53, int32_t p54, int32_t p55 -, int32_t p56, int32_t p57, int32_t p58, int32_t p59, int32_t p60, int32_t p61, int32_t p62, int32_t p63 -, int32_t p64, int32_t p65, int32_t p66, int32_t p67, int32_t p68, int32_t p69, int32_t p70, int32_t p71 -, int32_t p72, int32_t p73, int32_t p74, int32_t p75, int32_t p76, int32_t p77, int32_t p78, int32_t p79 -, int32_t p80, int32_t p81, int32_t p82, int32_t p83, int32_t p84, int32_t p85, int32_t p86, int32_t p87 -, int32_t p88, int32_t p89, int32_t p90, int32_t p91, int32_t p92, int32_t p93, int32_t p94, int32_t p95 -, int32_t p96, int32_t p97, int32_t p98, int32_t p99, int32_t p100, int32_t p101, int32_t p102, int32_t p103 -, int32_t p104, int32_t p105, int32_t p106, int32_t p107, int32_t p108, int32_t p109, int32_t p110, int32_t p111 -, int32_t p112, int32_t p113, int32_t p114, int32_t p115, int32_t p116, int32_t p117, int32_t p118, int32_t p119 -, int32_t p120, int32_t p121, int32_t p122, int32_t p123, int32_t p124, int32_t p125, int32_t p126, int32_t p127 -, int32_t p128, int32_t p129, int32_t p130, int32_t p131, int32_t p132, int32_t p133, int32_t p134, int32_t p135 -, int32_t p136, int32_t p137, int32_t p138, int32_t p139, int32_t p140, int32_t p141, int32_t p142, int32_t p143 -, int32_t p144, int32_t p145, int32_t p146, int32_t p147, int32_t p148, int32_t p149, int32_t p150, int32_t p151 -, int32_t p152, int32_t p153, int32_t p154, int32_t p155, int32_t p156, int32_t p157, int32_t p158, int32_t p159 -, int32_t p160, int32_t p161, int32_t p162, int32_t p163, int32_t p164, int32_t p165, int32_t p166, int32_t p167 -, int32_t p168, int32_t p169, int32_t p170, int32_t p171, int32_t p172, int32_t p173, int32_t p174, int32_t p175 -, int32_t p176, int32_t p177, int32_t p178, int32_t p179, int32_t p180, int32_t p181, int32_t p182, int32_t p183 -, int32_t p184, int32_t p185, int32_t p186, int32_t p187, int32_t p188, int32_t p189, int32_t p190, int32_t p191 -, int32_t p192, int32_t p193, int32_t p194, int32_t p195, int32_t p196, int32_t p197, int32_t p198, int32_t p199 -, int32_t p200, int32_t p201, int32_t p202, int32_t p203, int32_t p204, int32_t p205, int32_t p206, int32_t p207 -, int32_t p208, int32_t p209, int32_t p210, int32_t p211, int32_t p212, int32_t p213, int32_t p214, int32_t p215 -, int32_t p216, int32_t p217, int32_t p218, int32_t p219, int32_t p220, int32_t p221, int32_t p222, int32_t p223 -, int32_t p224, int32_t p225, int32_t p226, int32_t p227, int32_t p228, int32_t p229, int32_t p230, int32_t p231 -, int32_t p232, int32_t p233, int32_t p234, int32_t p235, int32_t p236, int32_t p237, int32_t p238, int32_t p239 -, int32_t p240, int32_t p241, int32_t p242, int32_t p243, int32_t p244, int32_t p245, int32_t p246, int32_t p247 -, int32_t p248, int32_t p249, int32_t p250, int32_t p251, int32_t p252, int32_t p253, int32_t p254, int32_t p255 -, int32_t p256, int32_t p257, int32_t p258, int32_t p259, int32_t p260, int32_t p261, int32_t p262, int32_t p263 -, int32_t p264, int32_t p265, int32_t p266, int32_t p267, int32_t p268, int32_t p269, int32_t p270, int32_t p271 -, int32_t p272, int32_t p273, int32_t p274, int32_t p275, int32_t p276, int32_t p277, int32_t p278, int32_t p279 -, int32_t p280, int32_t p281, int32_t p282, int32_t p283, int32_t p284, int32_t p285, int32_t p286, int32_t p287 -, int32_t p288, int32_t p289, int32_t p290, int32_t p291, int32_t p292, int32_t p293, int32_t p294, int32_t p295 -, int32_t p296, int32_t p297, int32_t p298, int32_t p299, int32_t p300, int32_t p301, int32_t p302, int32_t p303 -, int32_t p304, int32_t p305, int32_t p306, int32_t p307, int32_t p308, int32_t p309, int32_t p310, int32_t p311 -, int32_t p312, int32_t p313, int32_t p314, int32_t p315, int32_t p316, int32_t p317, int32_t p318, int32_t p319 -, int32_t p320, int32_t p321, int32_t p322, int32_t p323, int32_t p324, int32_t p325, int32_t p326, int32_t p327 -, int32_t p328, int32_t p329, int32_t p330, int32_t p331, int32_t p332, int32_t p333, int32_t p334, int32_t p335 -, int32_t p336, int32_t p337, int32_t p338, int32_t p339, int32_t p340, int32_t p341, int32_t p342, int32_t p343 -, int32_t p344, int32_t p345, int32_t p346, int32_t p347, int32_t p348, int32_t p349, int32_t p350, int32_t p351 -, int32_t p352, int32_t p353, int32_t p354, int32_t p355, int32_t p356, int32_t p357, int32_t p358, int32_t p359 -, int32_t p360, int32_t p361, int32_t p362, int32_t p363, int32_t p364, int32_t p365, int32_t p366, int32_t p367 -, int32_t p368, int32_t p369, int32_t p370, int32_t p371, int32_t p372, int32_t p373, int32_t p374, int32_t p375 -, int32_t p376, int32_t p377, int32_t p378, int32_t p379, int32_t p380, int32_t p381, int32_t p382, int32_t p383 -, int32_t p384, int32_t p385, int32_t p386, int32_t p387, int32_t p388, int32_t p389, int32_t p390, int32_t p391 -, int32_t p392, int32_t p393, int32_t p394, int32_t p395, int32_t p396, int32_t p397, int32_t p398, int32_t p399 -, int32_t p400, int32_t p401, int32_t p402, int32_t p403, int32_t p404, int32_t p405, int32_t p406, int32_t p407 -, int32_t p408, int32_t p409, int32_t p410, int32_t p411, int32_t p412, int32_t p413, int32_t p414, int32_t p415 -, int32_t p416, int32_t p417, int32_t p418, int32_t p419, int32_t p420, int32_t p421, int32_t p422, int32_t p423 -, int32_t p424, int32_t p425, int32_t p426, int32_t p427, int32_t p428, int32_t p429, int32_t p430, int32_t p431 -, int32_t p432, int32_t p433, int32_t p434, int32_t p435, int32_t p436, int32_t p437, int32_t p438, int32_t p439 -, int32_t p440, int32_t p441, int32_t p442, int32_t p443, int32_t p444, int32_t p445, int32_t p446, int32_t p447 -, int32_t p448, int32_t p449, int32_t p450, int32_t p451, int32_t p452, int32_t p453, int32_t p454, int32_t p455 -, int32_t p456, int32_t p457, int32_t p458, int32_t p459, int32_t p460, int32_t p461, int32_t p462, int32_t p463 -, int32_t p464, int32_t p465, int32_t p466, int32_t p467, int32_t p468, int32_t p469, int32_t p470, int32_t p471 -, int32_t p472, int32_t p473, int32_t p474, int32_t p475, int32_t p476, int32_t p477, int32_t p478, int32_t p479 -, int32_t p480, int32_t p481, int32_t p482, int32_t p483, int32_t p484, int32_t p485, int32_t p486, int32_t p487 -, int32_t p488, int32_t p489, int32_t p490, int32_t p491, int32_t p492, int32_t p493, int32_t p494, int32_t p495 -, int32_t p496, int32_t p497, int32_t p498, int32_t p499, int32_t p500, int32_t p501, int32_t p502, int32_t p503 -, int32_t p504, int32_t p505, int32_t p506, int32_t p507, int32_t p508, int32_t p509, int32_t p510, int32_t p511 -, int32_t p512, int32_t p513, int32_t p514, int32_t p515, int32_t p516, int32_t p517, int32_t p518, int32_t p519 -, int32_t p520, int32_t p521, int32_t p522, int32_t p523, int32_t p524, int32_t p525, int32_t p526, int32_t p527 -, int32_t p528, int32_t p529, int32_t p530, int32_t p531, int32_t p532, int32_t p533, int32_t p534, int32_t p535 -, int32_t p536, int32_t p537, int32_t p538, int32_t p539, int32_t p540, int32_t p541, int32_t p542, int32_t p543 -, int32_t p544, int32_t p545, int32_t p546, int32_t p547, int32_t p548, int32_t p549, int32_t p550, int32_t p551 -, int32_t p552, int32_t p553, int32_t p554, int32_t p555, int32_t p556, int32_t p557, int32_t p558, int32_t p559 -, int32_t p560, int32_t p561, int32_t p562, int32_t p563, int32_t p564, int32_t p565, int32_t p566, int32_t p567 -, int32_t p568, int32_t p569, int32_t p570, int32_t p571, int32_t p572, int32_t p573, int32_t p574, int32_t p575 -, int32_t p576, int32_t p577, int32_t p578, int32_t p579, int32_t p580, int32_t p581, int32_t p582, int32_t p583 -, int32_t p584, int32_t p585, int32_t p586, int32_t p587, int32_t p588, int32_t p589, int32_t p590, int32_t p591 -, int32_t p592, int32_t p593, int32_t p594, int32_t p595, int32_t p596, int32_t p597, int32_t p598, int32_t p599 -, int32_t p600, int32_t p601, int32_t p602, int32_t p603, int32_t p604, int32_t p605, int32_t p606, int32_t p607 -, int32_t p608, int32_t p609, int32_t p610, int32_t p611, int32_t p612, int32_t p613, int32_t p614, int32_t p615 -, int32_t p616, int32_t p617, int32_t p618, int32_t p619, int32_t p620, int32_t p621, int32_t p622, int32_t p623 -, int32_t p624, int32_t p625, int32_t p626, int32_t p627, int32_t p628, int32_t p629, int32_t p630, int32_t p631 -, int32_t p632, int32_t p633, int32_t p634, int32_t p635, int32_t p636, int32_t p637, int32_t p638, int32_t p639 -, int32_t p640, int32_t p641, int32_t p642, int32_t p643, int32_t p644, int32_t p645, int32_t p646, int32_t p647 -, int32_t p648, int32_t p649, int32_t p650, int32_t p651, int32_t p652, int32_t p653, int32_t p654, int32_t p655 -, int32_t p656, int32_t p657, int32_t p658, int32_t p659, int32_t p660, int32_t p661, int32_t p662, int32_t p663 -, int32_t p664, int32_t p665, int32_t p666, int32_t p667, int32_t p668, int32_t p669, int32_t p670, int32_t p671 -, int32_t p672, int32_t p673, int32_t p674, int32_t p675, int32_t p676, int32_t p677, int32_t p678, int32_t p679 -, int32_t p680, int32_t p681, int32_t p682, int32_t p683, int32_t p684, int32_t p685, int32_t p686, int32_t p687 -, int32_t p688, int32_t p689, int32_t p690, int32_t p691, int32_t p692, int32_t p693, int32_t p694, int32_t p695 -, int32_t p696, int32_t p697, int32_t p698, int32_t p699, int32_t p700, int32_t p701, int32_t p702, int32_t p703 -, int32_t p704, int32_t p705, int32_t p706, int32_t p707, int32_t p708, int32_t p709, int32_t p710, int32_t p711 -, int32_t p712, int32_t p713, int32_t p714, int32_t p715, int32_t p716, int32_t p717, int32_t p718, int32_t p719 -, int32_t p720, int32_t p721, int32_t p722, int32_t p723, int32_t p724, int32_t p725, int32_t p726, int32_t p727 -, int32_t p728, int32_t p729, int32_t p730, int32_t p731, int32_t p732, int32_t p733, int32_t p734, int32_t p735 -, int32_t p736, int32_t p737, int32_t p738, int32_t p739, int32_t p740, int32_t p741, int32_t p742, int32_t p743 -, int32_t p744, int32_t p745, int32_t p746, int32_t p747, int32_t p748, int32_t p749, int32_t p750, int32_t p751 -, int32_t p752, int32_t p753, int32_t p754, int32_t p755, int32_t p756, int32_t p757, int32_t p758, int32_t p759 -, int32_t p760, int32_t p761, int32_t p762, int32_t p763, int32_t p764, int32_t p765, int32_t p766, int32_t p767 -, int32_t p768, int32_t p769, int32_t p770, int32_t p771, int32_t p772, int32_t p773, int32_t p774, int32_t p775 -, int32_t p776, int32_t p777, int32_t p778, int32_t p779, int32_t p780, int32_t p781, int32_t p782, int32_t p783 -, int32_t p784, int32_t p785, int32_t p786, int32_t p787, int32_t p788, int32_t p789, int32_t p790, int32_t p791 -, int32_t p792, int32_t p793, int32_t p794, int32_t p795, int32_t p796, int32_t p797, int32_t p798, int32_t p799 -, int32_t p800, int32_t p801, int32_t p802, int32_t p803, int32_t p804, int32_t p805, int32_t p806, int32_t p807 -, int32_t p808, int32_t p809, int32_t p810, int32_t p811, int32_t p812, int32_t p813, int32_t p814, int32_t p815 -, int32_t p816, int32_t p817, int32_t p818, int32_t p819, int32_t p820, int32_t p821, int32_t p822, int32_t p823 -, int32_t p824, int32_t p825, int32_t p826, int32_t p827, int32_t p828, int32_t p829, int32_t p830, int32_t p831 -, int32_t p832, int32_t p833, int32_t p834, int32_t p835, int32_t p836, int32_t p837, int32_t p838, int32_t p839 -, int32_t p840, int32_t p841, int32_t p842, int32_t p843, int32_t p844, int32_t p845, int32_t p846, int32_t p847 -, int32_t p848, int32_t p849, int32_t p850, int32_t p851, int32_t p852, int32_t p853, int32_t p854, int32_t p855 -, int32_t p856, int32_t p857, int32_t p858, int32_t p859, int32_t p860, int32_t p861, int32_t p862, int32_t p863 -, int32_t p864, int32_t p865, int32_t p866, int32_t p867, int32_t p868, int32_t p869, int32_t p870, int32_t p871 -, int32_t p872, int32_t p873, int32_t p874, int32_t p875, int32_t p876, int32_t p877, int32_t p878, int32_t p879 -, int32_t p880, int32_t p881, int32_t p882, int32_t p883, int32_t p884, int32_t p885, int32_t p886, int32_t p887 -, int32_t p888, int32_t p889, int32_t p890, int32_t p891, int32_t p892, int32_t p893, int32_t p894, int32_t p895 -, int32_t p896, int32_t p897, int32_t p898, int32_t p899, int32_t p900, int32_t p901, int32_t p902, int32_t p903 -, int32_t p904, int32_t p905, int32_t p906, int32_t p907, int32_t p908, int32_t p909, int32_t p910, int32_t p911 -, int32_t p912, int32_t p913, int32_t p914, int32_t p915, int32_t p916, int32_t p917, int32_t p918, int32_t p919 -, int32_t p920, int32_t p921, int32_t p922, int32_t p923, int32_t p924, int32_t p925, int32_t p926, int32_t p927 -, int32_t p928, int32_t p929, int32_t p930, int32_t p931, int32_t p932, int32_t p933, int32_t p934, int32_t p935 -, int32_t p936, int32_t p937, int32_t p938, int32_t p939, int32_t p940, int32_t p941, int32_t p942, int32_t p943 -, int32_t p944, int32_t p945, int32_t p946, int32_t p947, int32_t p948, int32_t p949, int32_t p950, int32_t p951 -, int32_t p952, int32_t p953, int32_t p954, int32_t p955, int32_t p956, int32_t p957, int32_t p958, int32_t p959 -, int32_t p960, int32_t p961, int32_t p962, int32_t p963, int32_t p964, int32_t p965, int32_t p966, int32_t p967 -, int32_t p968, int32_t p969, int32_t p970, int32_t p971, int32_t p972, int32_t p973, int32_t p974, int32_t p975 -, int32_t p976, int32_t p977, int32_t p978, int32_t p979, int32_t p980, int32_t p981, int32_t p982, int32_t p983 -, int32_t p984, int32_t p985, int32_t p986, int32_t p987, int32_t p988, int32_t p989, int32_t p990, int32_t p991 -, int32_t p992, int32_t p993, int32_t p994, int32_t p995, int32_t p996, int32_t p997, int32_t p998, int32_t p999 -) -{ - int32_t x; - x = p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 - + p8 + p9 + p10 + p11 + p12 + p13 + p14 + p15 - + p16 + p17 + p18 + p19 + p20 + p21 + p22 + p23 - + p24 + p25 + p26 + p27 + p28 + p29 + p30 + p31 - + p32 + p33 + p34 + p35 + p36 + p37 + p38 + p39 - + p40 + p41 + p42 + p43 + p44 + p45 + p46 + p47 - + p48 + p49 + p50 + p51 + p52 + p53 + p54 + p55 - + p56 + p57 + p58 + p59 + p60 + p61 + p62 + p63 - + p64 + p65 + p66 + p67 + p68 + p69 + p70 + p71 - + p72 + p73 + p74 + p75 + p76 + p77 + p78 + p79 - + p80 + p81 + p82 + p83 + p84 + p85 + p86 + p87 - + p88 + p89 + p90 + p91 + p92 + p93 + p94 + p95 - + p96 + p97 + p98 + p99 + p100 + p101 + p102 + p103 - + p104 + p105 + p106 + p107 + p108 + p109 + p110 + p111 - + p112 + p113 + p114 + p115 + p116 + p117 + p118 + p119 - + p120 + p121 + p122 + p123 + p124 + p125 + p126 + p127 - + p128 + p129 + p130 + p131 + p132 + p133 + p134 + p135 - + p136 + p137 + p138 + p139 + p140 + p141 + p142 + p143 - + p144 + p145 + p146 + p147 + p148 + p149 + p150 + p151 - + p152 + p153 + p154 + p155 + p156 + p157 + p158 + p159 - + p160 + p161 + p162 + p163 + p164 + p165 + p166 + p167 - + p168 + p169 + p170 + p171 + p172 + p173 + p174 + p175 - + p176 + p177 + p178 + p179 + p180 + p181 + p182 + p183 - + p184 + p185 + p186 + p187 + p188 + p189 + p190 + p191 - + p192 + p193 + p194 + p195 + p196 + p197 + p198 + p199 - + p200 + p201 + p202 + p203 + p204 + p205 + p206 + p207 - + p208 + p209 + p210 + p211 + p212 + p213 + p214 + p215 - + p216 + p217 + p218 + p219 + p220 + p221 + p222 + p223 - + p224 + p225 + p226 + p227 + p228 + p229 + p230 + p231 - + p232 + p233 + p234 + p235 + p236 + p237 + p238 + p239 - + p240 + p241 + p242 + p243 + p244 + p245 + p246 + p247 - + p248 + p249 + p250 + p251 + p252 + p253 + p254 + p255 - + p256 + p257 + p258 + p259 + p260 + p261 + p262 + p263 - + p264 + p265 + p266 + p267 + p268 + p269 + p270 + p271 - + p272 + p273 + p274 + p275 + p276 + p277 + p278 + p279 - + p280 + p281 + p282 + p283 + p284 + p285 + p286 + p287 - + p288 + p289 + p290 + p291 + p292 + p293 + p294 + p295 - + p296 + p297 + p298 + p299 + p300 + p301 + p302 + p303 - + p304 + p305 + p306 + p307 + p308 + p309 + p310 + p311 - + p312 + p313 + p314 + p315 + p316 + p317 + p318 + p319 - + p320 + p321 + p322 + p323 + p324 + p325 + p326 + p327 - + p328 + p329 + p330 + p331 + p332 + p333 + p334 + p335 - + p336 + p337 + p338 + p339 + p340 + p341 + p342 + p343 - + p344 + p345 + p346 + p347 + p348 + p349 + p350 + p351 - + p352 + p353 + p354 + p355 + p356 + p357 + p358 + p359 - + p360 + p361 + p362 + p363 + p364 + p365 + p366 + p367 - + p368 + p369 + p370 + p371 + p372 + p373 + p374 + p375 - + p376 + p377 + p378 + p379 + p380 + p381 + p382 + p383 - + p384 + p385 + p386 + p387 + p388 + p389 + p390 + p391 - + p392 + p393 + p394 + p395 + p396 + p397 + p398 + p399 - + p400 + p401 + p402 + p403 + p404 + p405 + p406 + p407 - + p408 + p409 + p410 + p411 + p412 + p413 + p414 + p415 - + p416 + p417 + p418 + p419 + p420 + p421 + p422 + p423 - + p424 + p425 + p426 + p427 + p428 + p429 + p430 + p431 - + p432 + p433 + p434 + p435 + p436 + p437 + p438 + p439 - + p440 + p441 + p442 + p443 + p444 + p445 + p446 + p447 - + p448 + p449 + p450 + p451 + p452 + p453 + p454 + p455 - + p456 + p457 + p458 + p459 + p460 + p461 + p462 + p463 - + p464 + p465 + p466 + p467 + p468 + p469 + p470 + p471 - + p472 + p473 + p474 + p475 + p476 + p477 + p478 + p479 - + p480 + p481 + p482 + p483 + p484 + p485 + p486 + p487 - + p488 + p489 + p490 + p491 + p492 + p493 + p494 + p495 - + p496 + p497 + p498 + p499 + p500 + p501 + p502 + p503 - + p504 + p505 + p506 + p507 + p508 + p509 + p510 + p511 - + p512 + p513 + p514 + p515 + p516 + p517 + p518 + p519 - + p520 + p521 + p522 + p523 + p524 + p525 + p526 + p527 - + p528 + p529 + p530 + p531 + p532 + p533 + p534 + p535 - + p536 + p537 + p538 + p539 + p540 + p541 + p542 + p543 - + p544 + p545 + p546 + p547 + p548 + p549 + p550 + p551 - + p552 + p553 + p554 + p555 + p556 + p557 + p558 + p559 - + p560 + p561 + p562 + p563 + p564 + p565 + p566 + p567 - + p568 + p569 + p570 + p571 + p572 + p573 + p574 + p575 - + p576 + p577 + p578 + p579 + p580 + p581 + p582 + p583 - + p584 + p585 + p586 + p587 + p588 + p589 + p590 + p591 - + p592 + p593 + p594 + p595 + p596 + p597 + p598 + p599 - + p600 + p601 + p602 + p603 + p604 + p605 + p606 + p607 - + p608 + p609 + p610 + p611 + p612 + p613 + p614 + p615 - + p616 + p617 + p618 + p619 + p620 + p621 + p622 + p623 - + p624 + p625 + p626 + p627 + p628 + p629 + p630 + p631 - + p632 + p633 + p634 + p635 + p636 + p637 + p638 + p639 - + p640 + p641 + p642 + p643 + p644 + p645 + p646 + p647 - + p648 + p649 + p650 + p651 + p652 + p653 + p654 + p655 - + p656 + p657 + p658 + p659 + p660 + p661 + p662 + p663 - + p664 + p665 + p666 + p667 + p668 + p669 + p670 + p671 - + p672 + p673 + p674 + p675 + p676 + p677 + p678 + p679 - + p680 + p681 + p682 + p683 + p684 + p685 + p686 + p687 - + p688 + p689 + p690 + p691 + p692 + p693 + p694 + p695 - + p696 + p697 + p698 + p699 + p700 + p701 + p702 + p703 - + p704 + p705 + p706 + p707 + p708 + p709 + p710 + p711 - + p712 + p713 + p714 + p715 + p716 + p717 + p718 + p719 - + p720 + p721 + p722 + p723 + p724 + p725 + p726 + p727 - + p728 + p729 + p730 + p731 + p732 + p733 + p734 + p735 - + p736 + p737 + p738 + p739 + p740 + p741 + p742 + p743 - + p744 + p745 + p746 + p747 + p748 + p749 + p750 + p751 - + p752 + p753 + p754 + p755 + p756 + p757 + p758 + p759 - + p760 + p761 + p762 + p763 + p764 + p765 + p766 + p767 - + p768 + p769 + p770 + p771 + p772 + p773 + p774 + p775 - + p776 + p777 + p778 + p779 + p780 + p781 + p782 + p783 - + p784 + p785 + p786 + p787 + p788 + p789 + p790 + p791 - + p792 + p793 + p794 + p795 + p796 + p797 + p798 + p799 - + p800 + p801 + p802 + p803 + p804 + p805 + p806 + p807 - + p808 + p809 + p810 + p811 + p812 + p813 + p814 + p815 - + p816 + p817 + p818 + p819 + p820 + p821 + p822 + p823 - + p824 + p825 + p826 + p827 + p828 + p829 + p830 + p831 - + p832 + p833 + p834 + p835 + p836 + p837 + p838 + p839 - + p840 + p841 + p842 + p843 + p844 + p845 + p846 + p847 - + p848 + p849 + p850 + p851 + p852 + p853 + p854 + p855 - + p856 + p857 + p858 + p859 + p860 + p861 + p862 + p863 - + p864 + p865 + p866 + p867 + p868 + p869 + p870 + p871 - + p872 + p873 + p874 + p875 + p876 + p877 + p878 + p879 - + p880 + p881 + p882 + p883 + p884 + p885 + p886 + p887 - + p888 + p889 + p890 + p891 + p892 + p893 + p894 + p895 - + p896 + p897 + p898 + p899 + p900 + p901 + p902 + p903 - + p904 + p905 + p906 + p907 + p908 + p909 + p910 + p911 - + p912 + p913 + p914 + p915 + p916 + p917 + p918 + p919 - + p920 + p921 + p922 + p923 + p924 + p925 + p926 + p927 - + p928 + p929 + p930 + p931 + p932 + p933 + p934 + p935 - + p936 + p937 + p938 + p939 + p940 + p941 + p942 + p943 - + p944 + p945 + p946 + p947 + p948 + p949 + p950 + p951 - + p952 + p953 + p954 + p955 + p956 + p957 + p958 + p959 - + p960 + p961 + p962 + p963 + p964 + p965 + p966 + p967 - + p968 + p969 + p970 + p971 + p972 + p973 + p974 + p975 - + p976 + p977 + p978 + p979 + p980 + p981 + p982 + p983 - + p984 + p985 + p986 + p987 + p988 + p989 + p990 + p991 - + p992 + p993 + p994 + p995 + p996 + p997 + p998 + p999; - return x; -} - -// clang-format on diff --git a/src/test/app/wasm_fixtures/wat/custom_page_sizes.wat b/src/test/app/wasm_fixtures/wat/custom_page_sizes.wat deleted file mode 100644 index c0bf1c3a11..0000000000 --- a/src/test/app/wasm_fixtures/wat/custom_page_sizes.wat +++ /dev/null @@ -1,13 +0,0 @@ -(module - ;; Define a memory with 1 initial page. - ;; CRITICAL: We explicitly set the page size to 1 byte. - ;; Standard Wasm implies (pagesize 65536). - (memory 1 (pagesize 1)) - - (func $escrow_finish (result i32) - ;; If this module instantiates, the runtime accepted the custom page size. - i32.const 1 - ) - - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/deep_recursion.wat b/src/test/app/wasm_fixtures/wat/deep_recursion.wat deleted file mode 100644 index efe20cf53d..0000000000 --- a/src/test/app/wasm_fixtures/wat/deep_recursion.wat +++ /dev/null @@ -1,29 +0,0 @@ -(module - ;; Define a Mutable Global Variable to act as our counter. - ;; We initialize it to 1,000,000. - (global $counter (mut i32) (i32.const 1000000)) - - (func $escrow_finish (result i32) - ;; 1. Check if counter == 0 (Base Case) - global.get $counter - i32.eqz - if - ;; If counter is 0, we are done. Return 1. - i32.const 1 - return - end - - ;; 2. Decrement the Global Counter - global.get $counter - i32.const 1 - i32.sub - global.set $counter - - ;; 3. Recursive Step: Call SELF - ;; This puts an i32 (1) on the stack when it returns. - call $escrow_finish - ) - - ;; Export the only function we have - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/functions_5k.zip b/src/test/app/wasm_fixtures/wat/functions_5k.zip deleted file mode 100644 index e261760545516dd244df3d31cc5a3acd4fb5685c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29665 zcmeI5eQXnT7{@z?8!z&bi7dPav(pd)mmn`9LW2abUWj8V1h#P?bA}Oiy1@vH-Z^nG zfRp4RUNFL<6xj=7IvvH1^@IW11mwlxa0R-_0@AJR+O4nGyYttZiNVO~uKjP%wmeOq z`{maA_Q~bx=Xrk5r4xxm$7wXfhH2Kn{chG*3#Kn13pJYk+eT@|YBZYM9r>HLZ=v!F z$$496@7%Qg^6gbs^Rjp5J}_mv*_@^OrZ4QFuGIg$;Y{)~$LA)^zznao-Cs0y(&oYy z$(Lqt%N=?yds2O;OA3-wyHnTD6kEgnzY3d=n#3j7Z4=W8^Q`!plEt zWiKw@t96Z(J4tz>>~CU1oGkg#8D&2cww8~%=aJ9$=pXWus0}yyWqu>Ik*e@N>-%~) zwTY_q&-b0)?b_(7@K5bpY;Qc!SbewnTYr^*Ntgb9V~M%cL=DL7Gaolm12U!NLndlK zrp#P#q6TF4n#)YofK0M}k=;C{*HIx9T{9kYT9?{BF;P*Rr~kB82?H`k*NxRq>vG#E z6P2oOu$!}c9aTa!=NNsl-MqNhQ7QPY8BaK^%WOwYRKL!{!gwt&jL+lK+PDu}@!Vk?`(z5ZL6fKf5f0ulz9C@4`Lvs~?mVumC)sWy!@;G6S#X0UQ3Im+s>^(+ z6`v8nj{Araw60QQKOi&mctacaDY!wCr~$#y{u*@aX~MVElQ+7F^$u=sm|Y`aqj&?j zL6fKf(bLmF9rF=Mv;}27CFGnuKBtZQxD}rez`zZfL=A|AD1$C)rY$980a#EVjtWR& zr?pCCOUXKPPip5*w&LpoShbHBPg}qZnnVo&b$4E(hD_z{4&T9+4BRw_C`a7Tt zhkb;U)m(f%`r7|Edy1A9S@g~~{O^DG$Vo0-rTC7k%NtV%_^$sxiMt0by}u9l5v~6T zhh`dm>ds8S-6_EORkD81gPk_O-N5?Q);}^3K3D^|8(6>E`iF!HaDcmk^{cIaTt<|j z3~)EFewD1h17*aa2G+l{vuO!1~qJKYoZ*=5ErKQnCOnC=f>l1e9~1 z@DWqPELcz=UJAV9BRmftthGfTbfUt%F@<^0RG4?mt(i`%F~5&|pHuL7ANiiGEGoW* z8ir$H$idhcvJ?|OXJf0 zb2ZTP4J81TC4i2|27)&QES0u^1qI@$fD7f^M_ch--2_-rAZ`l$j#rkKlX?O5aF0@$ zH>WV~QwsCW-mG+c_mS^p1&_~C$ajOX$hoQ3M8(vC-5eW3_QrLQG#`+Tro z`YH!^0VP?bF!}^a0BTDBX#T(~7<~eBU(^o0@gjTxV?Lse`G9dSj~S8k5EbCI!srty z0jMkiSR(zqF!}`MzNj5~^9#zLr=ZQ{ZQNwApg{Z-s6&;x(=hr3=Dw&MdK1||u-3t4 z1u(FnKpYh~i*oMbJig-`z6&fU5HAICc>_b!UI&^3vY?N7_f0rCuXKBtDRWMe6!JYq z!Q;k0^4+)Sqei<~jAeq!jo27+Z*2Hnj18a5G2!z;d+GIL3QDpD=>TwxeDm^=r(R)) zCX8)9XvxcV=XO6=6nY_H<)+W|cD|#D^i<017{+o!B9?@)@(>>E=JvpWxJZ&lGy0KU zG9^H~EOJ97HeJR___St5*M<)VH)s+yAS5aDnVnB_bA}ME3uBcMk;3SzWcC8df*Ul6 z8W17TTZ3*l?f48YnGqmf6}fQ|n;~PRyaC*xNz{N4h0e@snY~2bu=55t_k9T862@vI zVj`mhH)s+yAnyBHjH_jAFQ3!QSlaLjUUE)=SRryxN-VfRlc)jF<*KEsC1N~dK}pX= zvd+%uxVe)dd|em=H)s+yAa?P*d9j!DbaO9(1qI@#KmiJ@BO!cY7(?7-G-E*wrHL#+ z*rc2L0^FcU{{d0Qci0#?F`Y;lGA{A)kK;s7DDMBB2|%x%1cCfs8m59BztFOgP|BC`R?_*T<;oxCt)&Y zXXebAbI$(v%;ZClUcF!J(W7tQ9$vnIANPx!)zEWt&mI-!{2u%sJ$kGNScI<#_Ic~g z<)c5tKmGJ_&a*3uKi`oTd7ymZg%86T^tnfbWh0;8YPTqRYc_HIZG86K_^trOun2(@?1tDvZF%8ohy@a_Z zVOo8dzXD{<@e;$mlthVPZY6UcGi0aBbTu00WQn2PXJ~8PZKgF|qp#ni8NTDC9bZF4(@ILQtpMX zX4%#O$_KB_1K1ajnQ?Asp7C{YXWOe%6YO;my*~A7_iEiUf8#Xp+A&~)LzvgSgE##0 z&hOkag$S^Ne_q^~G9W^ExyJe!#qApGel8jBJY4-*M2DEpMdn z*D4%~Y)cM`j`>S2H`<8~<@79DA2|8YFk!y~eV6ujeRWX(%-FuayhjaR|5m@`=!MgI zhrc@L#mt?3U!OwRubqv+plbYV7*de#x5`uIe3bH%ORS-uHDk%6WZWzvL|oLwl?3 z1`W;ptM4yv)P(i*{gR1=k-c?xgI>ve%I5W{)I00@^-tcqP~O}1wL!0D_P6emW~XN`6bbx-q%^^UELT^#?~ql#K| za!Fuo)9;xp4can7XgFP#D>R%fvmMeUr)AfF?6o#{&#aC8B>qM9&jrIzjJ6MTPxY|A zsM2R)>kFG?QO)&s|Hx=wI*8#{h(2lc*d*J4|2MDvZ+EFP#&nPE-hbA{E{Pwb{<&~? z&S<|-_y4(~#D4X|`X%YJ5mVOA{$uHswe!Awd`&*O`~OfcE*MUaemOLY z@{oJ~vo;owfBZ#jH(We9FJjBZKAsV=4JT*JS#=kmlenZIXwGBrMVd#PcUo<%Z#<@6 zTsS;?v}b76|5{PQ1cA@N`VRy?%6e~skE%JSSYEugL_2U*!T(gpgz9Sr!%vQO4$VsS z*y6pqHg-{bw<|g;UKjCF!Ds6tUM|R37cr#Z{yN#meXo!6u~}kuUl+xX56${NPv#HT zzMs5}d?R)4C)6LGL}$f{me^#ZdJI)xGf$4y#yYC6Wsh!7^Z5VsF=g!7VE@Jo|Jdg_ z`|YG9vvT%s|41oHF0!4QLlxP2*7e!nNYBx&`&EDLV&olv$y%l8`1Y@qM6{CFtR!NT z#5N`IosvjU5!ENt{p;SxO>DN#rSsi%OzUNnBA9 zWlEw_N!(NtbxNXMNi-;lW+kCl5G}J zMMS8Gbt>X36%nl>Hmisj6|qf4e5WE3RK!mzVz-J&QW5)AM5>BVs))lX;;4$qR1qgs zM3#!kQ4x76;-ZQuR1sHHM45`HR1r5-L~&K0QMz}x=`&9o0)1u2(hUv%NlRoS(rG05{<62B^wq0(nbBE$Ily%`^jz`l&mQdO{}y1u~G4%E^4nHzhIc;FB_?p zkVT?tb+&sO6|;3w`}Ful!*PGvGNt5Dk!V4kE!C))r;AF~6PSRo@)kvV;puxo>WYQ2(+u{qLrkY7oLIN8HZh!XBAVQ3#0*b^-A(6Po04` zjl)XhH;btVfi{3{SxIVmx(vLB7%P?AT&C6uq=EFatH?~A>mj_a7%P+8U#7kiXaniN zt4Nv`eh7bFjFrpXFH_M1X%IbX6?uZEK77IY z`zgJB6?vW)egywej8)6suTV(>X$ZY<6?u`TK7!8^V>NQWE7X30HiSO1ioC?r9l;lh zv08cb6)IIA4W&=7A`5x0YJ8a(tCJ^Pp_Bq`C|$IQEaru)@jx+lOP+OwIxLWWMpv&Q zukh4re2o~pEx&n%Ix5h9Mz^dYOL#gp{)HI3Be%IqWeTKg=w}1SGM?*i_}5~rUT%Mt zIw8=mp$7+$6}<4@@U3F(FS+|wDoY^!oE{ZGR`S%p;iMS5EBCuftjJ3$!OQ@RyX#~A5fNbEYkKqMkOegm%q3Q(M2>M6>d7q~{ zhL?)5R(W&@RWFc6(x(H+W}d4Czahr-@}v@~L7j7$P6i=vKN4o@)efYZL z_$y9WZ$)$|)lVp0Prn~X+VEX7@sUp0(~6{0>LsCeJ?#}pKF1Hw#NTwno>63#QZEao zQM7*`$>XataVICNkK$%2HAJY5qQe47TfQz6pX7w~RoIkK!-Uc==?#HoKfdel_*5s% zMqyt@4Hs&^q_+o>FYv>E$3Jw!o>jP)QT9UVSM@+H3dcYK}`_MF16jB*fazoL%> zk^}j=-|>Y`*gq7}Wz<_jshmC?NWRQ>rSWA>7*CN@MvWC}<#bUXDd30Gc%T!;S7en@ z&O)hzt_~!J@YOWF#tE}k+$^Ie2(=2jC6E;Hbu|8k6ZX8qrkr|5DE*p#Hi#U?cl`tZ z+6n8YurH^k2(@3+gM&yre)u2wRwt~#!o8ew7fPe)Q9Iy*j%I538h=PpdhlxUU4Hl}{CQ{WRfYRCDq1Lwp+~JIr|{LM@IlU)ox<-L zwOOc*pHHAVC_Dn=-crQcsoy7OJL@R82ga7EHJYMW3SOM9&*J^0~S z_?yny>x!&v)OSMZH?;q1@&mp)3wLtHMksDxqY{MLZ|Jbq$&Kn)KwmX5-78F$YCbC8ZQ<CIPX<7=ETN5#!b>Zni~Pq(ZlefYX;{0nF7O@+;M zDpM#W>1TsUobP%D|JoUQOJRSVIw91O^x$A}5kLG4zSSA~r^5X@l_ivZM~@07efjD$ zIO&YNt?;`}@CE#m(!~6`}TfIxLtB;Olbm$azD~8+PsueJ>rZ zb&2<`N~`%eG$H#yaAC-3^;xcv69}ga+(O_i17{UEkHC3D&Kq*xurqJC^3vftmkjSJ zRn6tlgyI9i#UZQIXSqU7Ae=IA3xTr?oK@sJ0_P1mZ^(JW&b;BGOP|-e5Z+a(HRD4Q zP9C^h5HeJKmMi20!YKo{5ID=gSw+qxaNdyfhMYI-%o{Gh^m(02ig%T==C{y2 zg)C5? z`_D;$lK>|HP6C_+I0&q;uj04D)X0-OXm32+kNB*004lR$Tt03%bM zWoYJ(BU8aNCNecLgDsOSGsq0*HLb-t8bh|M>5{DZ5_4Ckk7xdp=(8DvtaT4lBVpp1 zyFN^%#!$jkmfT|M$~8m6mUH?ZVxl%S!jexua$uLM9AaRCd3M8qU06F@v+L23qrp{mNHbyu3%0FG# zN=qTBfaE$PHzBEoHK zNKS03T^8i?^^(PITXd7fZ-d5NAer#CI#TnGvoS*^?)vGwArtL(0kZ37_~{q;X-~|M z-M5}|-(353h|gYs*n{P;2audvzT{HMzkYX4qnExnE}dTbDI`Bba$#KBu8N3Zhhm1< z-+nG92Q*#?NhKupkmz%2TO1ZTxrH`udUh!w&qFf6Ep+xV$7@b$cK0HFIt6=h8ulO? ze#(KL&caXUzVp@;@T*So6Ju_k;U~_hKDFhUrmyC?g)Tnsc+Uki{+cTwvmyBsl7o<3 zgXG2W={24_=MkY34h*ZhcU(F?b)9@f<7f9W1ICO`uQ<$uG!N06i1y^el9v&E3sHAS z>7`@Fr|q(h+*KAcB;t;MmkY-8NaAUG6iD~(VKG$`?J}|Dnb3)|`@sG;FH9&XOW(21 z&UJ16qCha~Vg11bdfL*UcFpHbK&%t|frOIx)cvt#V$){1TPWMr8s`~Ea&joN&WW)) z+f^vOvhTc!i8P!p<0#NjI*`sr7Pei4bfk>E61v<2!U}?@y%ANiYzBw4cVF?MXRo2a#Y z2RihJ{Zk#6dhLgTv0H{$jUisr&0DtS6Uk27iRbQ|*|H4-Vp}xwIdIK_)04qKuBXA` z6R3C$D$aq$V32TVy?C%$+ee7{VabDbPJyYO)J{rfI|&qK@#}?U>2uybabUtU-qH=; z-~4d-?2GC-&SgSi4dR_o@Ds=GbO*XKANa)%nYjFeZ-8>Wn*j8zsQSf+JGgw= zfX*ivi5AZCI;4et2JZmPv=L>(KcG54Jb$o^9SuKY zc2$Oda%s7~6e^cb-3Xvp8F!$Onz9yJt$`xIwcsu^RbqWKP?A1K^(B9s)=S@yLb_>o zz>gl>(X}s`)l8_5=9)62P;Dbbs`Z#9@w|XE4p9HVt^LJ4<1^O zawE!d%=lEFygoi)naCQOzmhKnT4Tu{(CNd4JrF4f~c4vt4Z09P>PQ z+tuvrICMjw@3lS5?Tmg^Z!zOHGoaHI?t8epM8+%#h#;_Ela$TztZR9UtT zR_QYuRC)Cf;M)lcZ>)!fJXq-B)RZ@rZBJz6`)3)v^jEOT09a)K4bmHvkT-zTu}Mhq-;hlQh@oASo9?M*Q9 z{ROLx{1#T339C$ld^0OS;ofbqa2_mN;@mXjJ+{3mM!s@bU+152eXfUoX3ZFlS2e5(OQL*Kzk(|i z9sn2cRhuu|(|mEJ=7LL3N?Z$Ur?YAuFX$Jkyx^#ucK6rak+74GY@!|Sb{{yz^R4U% zE$AN0%MGnNyIybz$A_Lm0C0G#9k!+xYD8Awe^Sp6~o1r$4+i1}zD zU{$LoVh++V*p5{?b`j|q?4&h128IZAtV=a+*BNeTZR^o>{+?!B7qx#@tDEwI!fQk` z;h$uyJez4-EJFGrx!}@AvO=~Osn3Ts!d6QE6H=mg_Xpph8x_VW2CFY(FVYzJtu?c! z@Pg(AHfD{6agDW;7c{hwUyR5HF%29?uK-) z>RHHQ>_Pf59hsO!*2G*yCT1TpF|(10Nn)oMS_V)D8W;GjHM5rloS^aoY|I)B;~Hxx zFX$v6zZh2}TvyaNs;1TZT%76SpKwjHZ}&0Q=dh9OOr#KOeCvTUh>da`kp=+{v^-&7 zccUq{Hn0U(fcj-^gvvE$T90sCS?gQDc%kZ`+-SOdsWXz3c<#+0Z1WAkV(<7 zCWVb{=O7I-MwPIypbngJYXippNWZKNYPrTbn3TsaMr2YHAfyF>%HEJz*}mOFk#4Y| zi5t=xHdvW~R0D-Ck;v#s+SwB}p0ze?;JDgQ1!$AIsWgy=!~+eP@6fOhXvnX-7a$Eu zLBYvfq#?heaP}jlAt*M9L`Fr^PDA#gJ05F86OOCBhICVD01c6;^g7Xsgi=OV+2?|f zAd9)5ZM#=94j{C}0HG}c2<=LM&@Qhi2NeNAyBQ#~jR3;!q{0{DVtrJ*KoooMLP@W} zsqEV_0QKb`22h_Dg!-02sBc%uXmf=e-~Um$AXDSBBB5ON5yW0!V}519*G_R-Ghcwa zT^P4;7_8CuqR{h6gqK;IKOJB!AjX{!FqYf?Ng#lPIKO$E*31`e7z>BNwu21N@_EAG zW%h<>A-Ex$;n46CxFOo*Rc%6L6?GQCxJJVwVsD774RwD)H$-g^uq7}VoCdD34mU)P zUyR5HNq`SxW_tjD@-=3USM?)tT1A}%S)F#su2EGu47Q^WdeY!!pii(z`8>2S*Vvq9=ob*GB{jg9kB8Lh#1*Nha16N^jzhI zc<|^DBqf+oS&<5atMJj`qhMTPtOC$i7QnS`%HvT~>|?EdagF_bnwnAjV2`nO?ip6Q_dzcSesbDHP&uDvWPicrjJpKtVzK^NITnO0(ck% z9x-l1;AtnAvUBa~@ zmCplo*Qg4S>aamackO;{lWFH$_aCY9N+&xDAW9G8TQ=MF8jIk<6gV~!fem)qFqdKT z6gqyPSuxj`ZfgW^`@j-mYnnHB#*`fj%#vd%ePFw}pNh_T|w{ zn0Srpw!pdpjM}2^Azn6U|9vufI1x-kIcv9Q^;u`GfMb0pcs1U4msVZ&ZF;C<)| zpcQZ;KzIu$0#>y^PaaGJ8?M53%&C*vLa1Zx^LW^oPF1l3uQA;g>KGh|H9E!(4avFC zB?lzf0zgi(Z}-FtE?KhKFntzgXq!*5eHhGbGc4~Sjj^?I_CT9(>S1HnXc*U+NnUUf zJbp2US@cz;lCb%39aC%{26N#Q zL(4E5MJ*8OwPyA}n{ZWF>w&n&Oe+%l|Hm)Jr8Q#!G7I;U?Tc%HNeN(E*`rcy&49Va zSj7=d`7vva3cCr-+6a|vtlfHq%k=S!5t$S*FexAtApn?^5|lm*5)wK|v3(fKZ8Irs zK7zFYBWM$tlw;PK6t1zqo0P{dMr2apGiHR@e#7S8f`~Q}g(kqS1D!DewTilqxUSKj zu)A)o4I4PFHdF!nkN=)D?lQyAEZFZo|M@|Ee;LzgC~O`vPD)(<)9=8=smW5!)zLLV zeV95q_+Cw2+S$C6jBFP-bA?wNJ@ltsSZcPy-wO{;yI)b~}~b}}V@5f?N8iy2L&C`ndws70pHi<|Cm{*}33EQ_+dpj1$p zl0gGa!WzWq1ckO9dfq+h{hB)J>_u2US96tL^RYh6H95G!T;V->rmWY|7(I2NWKzJV zT~sz*fotx6QJ6rBfZf;`vX2?%5s~FmDBHIC*kWi=WLe0f#3G9_99Wb!IuB%m;*kk* zL?+0`X!C$!1I#QnnUb!I4#(BrZ**g6Aa@i1+|li{3mL#2edbv`AL&8{(uDw|3nj=M zX^=aT0UHX`Dh?@+gUKCbAa?}09_=noIs^?c$JG{QbYp2CLlSw;<)Y;DOk2+pIycYi zVaRG&N&Jqi9t_)=uxnI?M!I)sASYVQgcKXYxQ(4WlD#j8!bsU=Uwf zqru#;T=$;`LFflHvzgHzM|~4&OMH{q_`^~PW)@C$0GevZWX)91M^kN#Wh`Qat2z!% zb^ANYu2`W4BV%>dN)6_Q#oo(+5JYx*rU--}(><&0PzYivHHIK=XsRKTHLE%XPIZfw zAxH!=Ruiq9Y7x?4!b%P1hJ`{9*|LOcpdga8X^j%!BoVrIksuc%LpQz*m_l&x5`*qt zSj}-mH#1|(6Rf&M*EJ5?7O1{~ z!c`*}+m+dW5C?KxZ5TTApWRd%z>qMyx=YNmgd0pot6jrwK_L^+>{eYOK42&bV0eaz zifTsRSW;?vL6fu*!hm@!=-P;&)V$8IRug=RP+1`hx-OO=7J9cfO_^a1Y3$2Z9Ys}dQSu5nmnL<^XKJA!ve*4*-NTISk$?~+G3|mI2tj5cC=}pmESlCOZ3{s-6x9@hJW=2<3PD65hXg1H0dhzH zIB$YgE9xx3VT~q)KxqQjg5Mlh`y7&PDh>7l&Tf#5=HQ_}?NZ3Z?T$2`-r5-sYYbEY zGYH`UwdxTo$MxWWC@Z~gDMMgLm`I&o;x(d$abTwEb<##=z9FW?`gGT}4B1}CVi3^E z<*%B_?|nkEbCEl81nwv$?Ls_oM{_-^&8N3^io+V+Q9N=-@IL9m;_1TZzD(J#OqjrNGh2D#DkyN{VqZ|w|+HM%3f3`{AYU1&x-9b)TqTIfZ(MA+>%mQrIN@+85HPbiA|?+pt!1c3AA(_1^kVcSfI9m*lGHZz*zYM(>WO{IanjLZ+@ zMrY5|fMhg{Z;}Pa47A5#je#m)1|hu0XlpIG<7Mk}Tqf(&O=SoTiKfKRO5{fyWZ9CL z3;<4V792Cs9)~r$Bft#YQHhoA zh~omN0)nGi>2*sPvT^M@09qRf_wv_@*lqb0br3nUgc?=kNrD^O%^Ei>7FzogoJj%G zHAm={dRD`2`D=8RQX{m+?dWfpwe}>Pzks}q4}jLdQ(zAOt$h?1hK@aow2-z1BHWIC zqkjbt>OlT5IBMewIe!5`YhnPcf!#N8;OSocZn!O<$bj*LCDaJ5JyCFDyQ%(ve^3D% zg1iet5PJ`hu30PbO@f(;6?K+UV+isj!Hw-g5N=p(4#`g-hr}M909pvZ`N*!18EB8g z8cm2b$A_9$D8~gB*n=FB?kWxBWw_&B*&EJ|o0ws`9CwWERbWWKaj!CiTg`jMV_r`g zG1#C6kPjPh=eA%jsK7kK9J93GxH!!xKmpD8qA(u%YLNv&dcqzL3-?cMHE(B3+SE?(*yCXVJOO~>&P`NDR&+cp#J+92v~DI= z_IOzKEZhIT!`c&aL=+$a4{#D;!s|Ee$pi4$3BE-Kt94C*2Z2*SkPu*+Mwg zX#W>Tx3y}jcc4c_)2*E9JxGIRS>^*#hq+U)fK^SlzFblfYqElbta~lf|dSww-gTQ|E#%p_V$&$tU3GPExi)m(ia&|&W9>E z9jYKG*yXbv-lqJ$R)<1pL`|X5gKKrD)$w|N4~-t#Ks(mIM|@rPjb#Osv%?hebu}z# zZIboihjP%l^wS#A6JzI=)J7N%SVDmapiE3Lgf%iT#SqrW#1unVA(I8B(5Ne!7`22O z7F-d)+A#W}6v=s)Jf`BW?=M^$o5q~16ep!D|5$(flEJy@i1s2AS(g}Pc|qym!W1R@ zdtAXkj)efN^SQxSV9{JnKKv;zFIVtWT+7k#bD1fG`JBRKn`;%jBl!oV_dBh3vBMR? zIS7(IUJ%$#?6p6yi$+Y$FsU|oUH&NmCs$2c{;4HBM9lDn0d9DvDFx}V^K_d*+`AuZ zcpaq2&WQ{A23Xr<{p%oiX`b!_WN*F)fZU=wF)+v{ivnOWg0ciYR$Q)uKP!GnYGvZnxWSXppKgl&u2a(#;MwlzRsLmECj|eG`1Q`+;II^wHkPJhH1aetp zNI0&x6$K4RH=S`lM;Q?9;U~K9zCCWvDb?|di3qv!^=1D<9>0o8hTFd y*`uPI--F-7^zY|&@bij*Mfi$fpSRvzKKe8K(+@qKeg>BI1h4Vn-2w3R=<#2Od%rLM diff --git a/src/test/app/wasm_fixtures/wat/memory64.wat b/src/test/app/wasm_fixtures/wat/memory64.wat deleted file mode 100644 index 3273af1e40..0000000000 --- a/src/test/app/wasm_fixtures/wat/memory64.wat +++ /dev/null @@ -1,21 +0,0 @@ -(module - ;; Define a 64-bit memory (index type i64) - ;; Start with 1 page. - (memory i64 1) - - (func $escrow_finish (result i32) - ;; 1. Perform a store using a 64-bit address. - ;; Even if the value is small (0), the type MUST be i64. - i64.const 0 ;; Address (64-bit) - i32.const 42 ;; Value (32-bit) - i32.store8 ;; Opcode doesn't change, but validation rules do. - - ;; 2. check memory size - ;; memory.size now returns an i64. - memory.size - i64.const 1 - i64.eq ;; Returns i32 (1 if true) - ) - - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/memory_end_of_word_over_limit.wat b/src/test/app/wasm_fixtures/wat/memory_end_of_word_over_limit.wat deleted file mode 100644 index 855307ddf4..0000000000 --- a/src/test/app/wasm_fixtures/wat/memory_end_of_word_over_limit.wat +++ /dev/null @@ -1,28 +0,0 @@ -(module - ;; 1. Define Memory: 1 Page = 64KB = 65,536 bytes - (memory 1) - - ;; Export memory so the host can inspect it if needed - (export "memory" (memory 0)) - - (func $test_straddle (result i32) - ;; Push the address onto the stack. - ;; 65534 is valid, but it is only 2 bytes away from the end. - i32.const 65534 - - ;; Attempt to load an i32 (4 bytes) from that address. - ;; This requires bytes 65534, 65535, 65536, and 65537. - ;; Since 65536 is the first invalid byte, this MUST trap. - i32.load - - ;; Clean up the stack. - ;; The load pushed a value, but we don't care what it is. - drop - - ;; Return 1 to signal "I survived the memory access" - i32.const 1 - ) - - ;; Export the function so you can call it from your host (JS, Python, etc.) - (export "escrow_finish" (func $test_straddle)) -) diff --git a/src/test/app/wasm_fixtures/wat/memory_grow_0_page_more_than_8MB.wat b/src/test/app/wasm_fixtures/wat/memory_grow_0_page_more_than_8MB.wat deleted file mode 100644 index 777f3062bf..0000000000 --- a/src/test/app/wasm_fixtures/wat/memory_grow_0_page_more_than_8MB.wat +++ /dev/null @@ -1,29 +0,0 @@ -(module - ;; Start at your limit: 128 pages (8MB) - (memory 128) - (export "memory" (memory 0)) - - (func $try_grow_beyond_limit (result i32) - ;; Attempt to grow by 0 page - i32.const 0 - memory.grow - - ;; memory.grow returns: - ;; -1 if the growth failed (Correct behavior for your limit) - ;; 128 (old size) if growth succeeded (Means limit was bypassed) - - ;; Check if result == -1 - i32.const -1 - i32.eq - if - ;; Growth FAILED (Host blocked it). Return -1. - i32.const -1 - return - end - - ;; Growth SUCCEEDED (Host allowed it). Return 1. - i32.const 1 - ) - - (export "escrow_finish" (func $try_grow_beyond_limit)) -) diff --git a/src/test/app/wasm_fixtures/wat/memory_grow_0_to_1.wat b/src/test/app/wasm_fixtures/wat/memory_grow_0_to_1.wat deleted file mode 100644 index 54a4193927..0000000000 --- a/src/test/app/wasm_fixtures/wat/memory_grow_0_to_1.wat +++ /dev/null @@ -1,26 +0,0 @@ -(module - ;; 1. Define Memory: Start with 0 pages - (memory 0) - - ;; Export memory to host - (export "memory" (memory 0)) - - (func $grow_from_zero (result i32) - ;; We have 0 pages. We want to add 1 page. - ;; Push delta (1) onto stack. - i32.const 1 - - ;; Grow the memory. - ;; If successful: memory becomes 64KB, returns old size (0). - ;; If failed: memory stays 0, returns -1. - memory.grow - - ;; Drop the return value of memory.grow - drop - - ;; Return 1 (as requested) - i32.const 1 - ) - - (export "escrow_finish" (func $grow_from_zero)) -) diff --git a/src/test/app/wasm_fixtures/wat/memory_grow_1_page_more_than_8MB.wat b/src/test/app/wasm_fixtures/wat/memory_grow_1_page_more_than_8MB.wat deleted file mode 100644 index 540b112178..0000000000 --- a/src/test/app/wasm_fixtures/wat/memory_grow_1_page_more_than_8MB.wat +++ /dev/null @@ -1,29 +0,0 @@ -(module - ;; Start at your limit: 128 pages (8MB) - (memory 128) - (export "memory" (memory 0)) - - (func $try_grow_beyond_limit (result i32) - ;; Attempt to grow by 1 page - i32.const 1 - memory.grow - - ;; memory.grow returns: - ;; -1 if the growth failed (Correct behavior for your limit) - ;; 128 (old size) if growth succeeded (Means limit was bypassed) - - ;; Check if result == -1 - i32.const -1 - i32.eq - if - ;; Growth FAILED (Host blocked it). Return -1. - i32.const -1 - return - end - - ;; Growth SUCCEEDED (Host allowed it). Return 1. - i32.const 1 - ) - - (export "escrow_finish" (func $try_grow_beyond_limit)) -) diff --git a/src/test/app/wasm_fixtures/wat/memory_grow_1_to_0.wat b/src/test/app/wasm_fixtures/wat/memory_grow_1_to_0.wat deleted file mode 100644 index cc4d161153..0000000000 --- a/src/test/app/wasm_fixtures/wat/memory_grow_1_to_0.wat +++ /dev/null @@ -1,33 +0,0 @@ -(module - ;; 1. Define Memory: Start with 1 page (64KB) - (memory 1) - - ;; Export memory to host - (export "memory" (memory 0)) - - (func $grow_negative (result i32) - ;; The user pushed -1. In Wasm, this is interpreted as unsigned MAX_UINT32. - ;; This is requesting to add 4,294,967,295 pages (approx 256 TB). - ;; A secure runtime MUST fail this request (return -1) without crashing. - i32.const -1 - - ;; Grow the memory. - ;; Returns: old_size if success, -1 if failure. - memory.grow - - ;; Check if result == -1 (Failure) - i32.const -1 - i32.eq - if - ;; If memory.grow returned -1, we return -1 to signal "Correctly failed". - i32.const -1 - return - end - - ;; If we are here, memory.grow somehow SUCCEEDED (Vulnerability). - ;; We return 1 to signal "Unexpected Success". - i32.const 1 - ) - - (export "escrow_finish" (func $grow_negative)) -) diff --git a/src/test/app/wasm_fixtures/wat/memory_init_1_page_more_than_8MB.wat b/src/test/app/wasm_fixtures/wat/memory_init_1_page_more_than_8MB.wat deleted file mode 100644 index f1bbee6c61..0000000000 --- a/src/test/app/wasm_fixtures/wat/memory_init_1_page_more_than_8MB.wat +++ /dev/null @@ -1,27 +0,0 @@ -(module - ;; Define memory: 129 pages (> 8MB limit) min, 129 pages max - (memory 129 129) - - ;; Export memory so host can verify size - (export "memory" (memory 0)) - - ;; access last byte of 8MB limit - (func $access_last_byte (result i32) - ;; Math: 128 pages * 64,536 bytes/page = 8,388,608 bytes - ;; Valid indices: 0 to 8,388,607 - - ;; Push the address of the LAST valid byte - i32.const 8388607 - - ;; Load byte from that address - i32.load8_u - - ;; Drop the value (we don't care what it is, just that we could read it) - drop - - ;; Return 1 to indicate success - i32.const 1 - ) - - (export "escrow_finish" (func $access_last_byte)) -) diff --git a/src/test/app/wasm_fixtures/wat/memory_last_byte_of_8MB.wat b/src/test/app/wasm_fixtures/wat/memory_last_byte_of_8MB.wat deleted file mode 100644 index e00f5e1239..0000000000 --- a/src/test/app/wasm_fixtures/wat/memory_last_byte_of_8MB.wat +++ /dev/null @@ -1,26 +0,0 @@ -(module - ;; Define memory: 128 pages (8MB) min, 128 pages max - (memory 128 128) - - ;; Export memory so host can verify size - (export "memory" (memory 0)) - - (func $access_last_byte (result i32) - ;; Math: 128 pages * 64,536 bytes/page = 8,388,608 bytes - ;; Valid indices: 0 to 8,388,607 - - ;; Push the address of the LAST valid byte - i32.const 8388607 - - ;; Load byte from that address - i32.load8_u - - ;; Drop the value (we don't care what it is, just that we could read it) - drop - - ;; Return 1 to indicate success - i32.const 1 - ) - - (export "escrow_finish" (func $access_last_byte)) -) diff --git a/src/test/app/wasm_fixtures/wat/memory_negative_address.wat b/src/test/app/wasm_fixtures/wat/memory_negative_address.wat deleted file mode 100644 index 6e26a07108..0000000000 --- a/src/test/app/wasm_fixtures/wat/memory_negative_address.wat +++ /dev/null @@ -1,23 +0,0 @@ -(module - ;; Define memory: 128 pages (8MB) min, 128 pages max - (memory 128 128) - - ;; Export memory so host can verify size - (export "memory" (memory 0)) - - (func $access_last_byte (result i32) - ;; Push a negative address - i32.const -1 - - ;; Load byte from that address - i32.load8_u - - ;; Drop the value - drop - - ;; Return 1 to indicate success - i32.const 1 - ) - - (export "escrow_finish" (func $access_last_byte)) -) diff --git a/src/test/app/wasm_fixtures/wat/memory_offset_over_limit.wat b/src/test/app/wasm_fixtures/wat/memory_offset_over_limit.wat deleted file mode 100644 index 20a401e3d2..0000000000 --- a/src/test/app/wasm_fixtures/wat/memory_offset_over_limit.wat +++ /dev/null @@ -1,27 +0,0 @@ -(module - ;; 1. Define Memory: 1 Page = 64KB - (memory 1) - - (export "memory" (memory 0)) - - (func $test_offset_overflow (result i32) - ;; 1. Push the base address onto the stack. - ;; We use '0', which is the safest, most valid address possible. - i32.const 0 - - ;; 2. Attempt to load using a static offset. - ;; syntax: i32.load offset=N align=N - ;; We set the offset to 65536 (the size of the memory). - ;; The effective address becomes 0 + 65536 = 65536. - i32.load offset=65536 - - ;; Clean up the stack. - ;; The load pushed a value, but we don't care what it is. - drop - - ;; Return 1 to signal "I survived the memory access" - i32.const 1 - ) - - (export "escrow_finish" (func $test_offset_overflow)) -) diff --git a/src/test/app/wasm_fixtures/wat/memory_pointer_at_limit.wat b/src/test/app/wasm_fixtures/wat/memory_pointer_at_limit.wat deleted file mode 100644 index e4432e6fdd..0000000000 --- a/src/test/app/wasm_fixtures/wat/memory_pointer_at_limit.wat +++ /dev/null @@ -1,22 +0,0 @@ -(module - ;; Define 1 page of memory (64KB = 65,536 bytes) - (memory 1) - - (func $read_edge (result i32) - ;; Push the index of the LAST valid byte - i32.const 65535 - - ;; Load 1 byte (unsigned) - i32.load8_u - - ;; Clean up the stack. - ;; The load pushed a value, but we don't care what it is. - drop - - ;; Return 1 to signal "I survived the memory access" - i32.const 1 - ) - - ;; Export as "escrow_finish" as requested - (export "escrow_finish" (func $read_edge)) -) diff --git a/src/test/app/wasm_fixtures/wat/memory_pointer_over_limit.wat b/src/test/app/wasm_fixtures/wat/memory_pointer_over_limit.wat deleted file mode 100644 index 906468f308..0000000000 --- a/src/test/app/wasm_fixtures/wat/memory_pointer_over_limit.wat +++ /dev/null @@ -1,23 +0,0 @@ -(module - ;; Define 1 page of memory (64KB = 65,536 bytes) - (memory 1) - - (func $read_overflow (result i32) - ;; Push the index of the FIRST invalid byte - ;; Memory is 0..65535, so 65536 is out of bounds. - i32.const 65536 - - ;; Load 1 byte (unsigned) - i32.load8_u - - ;; Clean up the stack. - ;; The load pushed a value, but we don't care what it is. - drop - - ;; Return 1 to signal "I survived the memory access" - i32.const 1 - ) - - ;; Export as "escrow_finish" as requested - (export "escrow_finish" (func $read_overflow)) - ) diff --git a/src/test/app/wasm_fixtures/wat/multi_memory.wat b/src/test/app/wasm_fixtures/wat/multi_memory.wat deleted file mode 100644 index 67fc5e76aa..0000000000 --- a/src/test/app/wasm_fixtures/wat/multi_memory.wat +++ /dev/null @@ -1,16 +0,0 @@ -(module - ;; Memory 0: Index 0 (Empty) - (memory 0) - - ;; Memory 1: Index 1 (Size 1 page) - ;; If multi-memory is disabled, this line causes a validation error (max 1 memory). - (memory 1) - - (func $escrow_finish (result i32) - ;; Query size of Memory Index 1. - ;; Should return 1 (success). - memory.size 1 - ) - - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/opc_reserved.wat b/src/test/app/wasm_fixtures/wat/opc_reserved.wat deleted file mode 100644 index 0bc61b52c3..0000000000 --- a/src/test/app/wasm_fixtures/wat/opc_reserved.wat +++ /dev/null @@ -1,98 +0,0 @@ -(module - - ;; Type for call_indirect - (type (func (result i32))) - - ;; Memory and table declarations - (memory 1) - (table 1 funcref) - (data (i32.const 0) "test") - (elem (i32.const 0) $test_func) - - ;; Global declarations - (global $g0 (mut i32) (i32.const 0)) - (global $g1 (mut i64) (i64.const 0)) - - ;; Test function for call/call_indirect - (func $test_func (result i32) - i32.const 42 - ) - - - ;; Main function with all instructions in hex order - (func $all_instructions (export "all_instructions") (result i32) - (local $l0 i32) - (local $l1 i64) - - ;; 0x01: nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - i32.const 11 - ) -) diff --git a/src/test/app/wasm_fixtures/wat/proposal_bulk_memory.wat b/src/test/app/wasm_fixtures/wat/proposal_bulk_memory.wat deleted file mode 100644 index ce59868ce6..0000000000 --- a/src/test/app/wasm_fixtures/wat/proposal_bulk_memory.wat +++ /dev/null @@ -1,25 +0,0 @@ -(module - ;; Define 1 page of memory - (memory 1) - (export "memory" (memory 0)) - - (func $test_bulk_ops (result i32) - ;; Setup: Write value 42 at index 0 so we have something to copy - (i32.store8 (i32.const 0) (i32.const 42)) - - ;; Test memory.copy (Opcode 0xFC 0x0A) - ;; Copy 1 byte from offset 0 to offset 100 - (memory.copy - (i32.const 100) ;; Destination Offset - (i32.const 0) ;; Source Offset - (i32.const 1) ;; Size (bytes) - ) - - ;; Verify: Read byte at offset 100. Should be 42. - (i32.load8_u (i32.const 100)) - (i32.const 42) - i32.eq - ) - - (export "escrow_finish" (func $test_bulk_ops)) -) diff --git a/src/test/app/wasm_fixtures/wat/proposal_extended_const.wat b/src/test/app/wasm_fixtures/wat/proposal_extended_const.wat deleted file mode 100644 index e296a468f0..0000000000 --- a/src/test/app/wasm_fixtures/wat/proposal_extended_const.wat +++ /dev/null @@ -1,15 +0,0 @@ -(module - ;; 1. Define a global using an EXTENDED constant expression. - ;; MVP only allows (i32.const X). - ;; This proposal allows (i32.add (i32.const X) (i32.const Y)). - (global $g i32 (i32.add (i32.const 10) (i32.const 32))) - - (func $escrow_finish (result i32) - ;; 2. verify the global equals 42 - global.get $g - i32.const 42 - i32.eq - ) - - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/proposal_float_to_int.wat b/src/test/app/wasm_fixtures/wat/proposal_float_to_int.wat deleted file mode 100644 index 367735f5e7..0000000000 --- a/src/test/app/wasm_fixtures/wat/proposal_float_to_int.wat +++ /dev/null @@ -1,18 +0,0 @@ -(module - (func $test_saturation (result i32) - ;; 1. Push a float that is too big for a 32-bit integer - ;; 1e10 (10 billion) > 2.14 billion (Max i32) - f32.const 1.0e10 - - ;; 2. Attempt saturating conversion (Opcode 0xFC 0x00) - ;; If supported: Clamps to MAX_I32. - ;; If disabled: Validation error (unknown instruction). - i32.trunc_sat_f32_s - - ;; 3. Check if result is MAX_I32 (2147483647) - i32.const 2147483647 - i32.eq - ) - - (export "escrow_finish" (func $test_saturation)) -) diff --git a/src/test/app/wasm_fixtures/wat/proposal_gc_struct_new.wat b/src/test/app/wasm_fixtures/wat/proposal_gc_struct_new.wat deleted file mode 100644 index bc33b7fada..0000000000 --- a/src/test/app/wasm_fixtures/wat/proposal_gc_struct_new.wat +++ /dev/null @@ -1,12 +0,0 @@ -;; generated by wasm-tools print gc_test.wasm that has the following hex -;; 0061736d01000000010b026000017f5f027f017f0103020100070a010666696e69736800000a0a010800fb01011a41010b -(module - (type (;0;) (func (result i32))) - (type (;1;) (struct (field (mut i32)) (field (mut i32)))) - (export "escrow_finish" (func 0)) - (func (;0;) (type 0) (result i32) - struct.new_default 1 - drop - i32.const 1 - ) -) diff --git a/src/test/app/wasm_fixtures/wat/proposal_multi_value.wat b/src/test/app/wasm_fixtures/wat/proposal_multi_value.wat deleted file mode 100644 index 23f1691872..0000000000 --- a/src/test/app/wasm_fixtures/wat/proposal_multi_value.wat +++ /dev/null @@ -1,22 +0,0 @@ -(module - ;; 1. Function returning TWO values (Multi-Value feature) - (func $get_numbers (result i32 i32) - i32.const 10 - i32.const 20 - ) - - (func $escrow_finish (result i32) - ;; Call pushes [10, 20] onto the stack - call $get_numbers - - ;; 2. Block taking TWO parameters (Multi-Value feature) - ;; It consumes the [10, 20] from the stack. - block (param i32 i32) (result i32) - i32.add ;; 10 + 20 = 30 - i32.const 30 ;; Expected result - i32.eq ;; Compare: returns 1 if equal - end - ) - - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/proposal_mutable_global.wat b/src/test/app/wasm_fixtures/wat/proposal_mutable_global.wat deleted file mode 100644 index 82a5d35203..0000000000 --- a/src/test/app/wasm_fixtures/wat/proposal_mutable_global.wat +++ /dev/null @@ -1,25 +0,0 @@ -(module - ;; Define a mutable global initialized to 0 - (global $counter (mut i32) (i32.const 0)) - - ;; EXPORTING a mutable global is the key feature of this proposal. - ;; In strict MVP, exported globals had to be immutable (const). - (export "counter" (global $counter)) - - (func $escrow_finish (result i32) - ;; 1. Get current value - global.get $counter - - ;; 2. Add 1 - i32.const 1 - i32.add - - ;; 3. Set new value (Mutation) - global.set $counter - - ;; 4. Return 1 for success - i32.const 1 - ) - - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/proposal_ref_types.wat b/src/test/app/wasm_fixtures/wat/proposal_ref_types.wat deleted file mode 100644 index 8cba4edf29..0000000000 --- a/src/test/app/wasm_fixtures/wat/proposal_ref_types.wat +++ /dev/null @@ -1,18 +0,0 @@ -(module - ;; Import a table from the host that holds externrefs - (import "env" "table" (table 1 externref)) - - (func $test_ref_types (result i32) - ;; Store a null externref into the table at index 0 - ;; If reference_types is disabled, 'externref' and 'ref.null' will fail parsing. - (table.set - (i32.const 0) ;; Index - (ref.null extern) ;; Value (Null External Reference) - ) - - ;; Return 1 (Success) - i32.const 1 - ) - - (export "escrow_finish" (func $test_ref_types)) -) diff --git a/src/test/app/wasm_fixtures/wat/proposal_sign_ext.wat b/src/test/app/wasm_fixtures/wat/proposal_sign_ext.wat deleted file mode 100644 index 9c8fdd1980..0000000000 --- a/src/test/app/wasm_fixtures/wat/proposal_sign_ext.wat +++ /dev/null @@ -1,18 +0,0 @@ -(module - (func $test_sign_ext (result i32) - ;; Push 255 (0x000000FF) onto the stack - i32.const 255 - - ;; Sign-extend from 8-bit to 32-bit - ;; If 255 is treated as an i8, it is -1. - ;; Result should be -1 (0xFFFFFFFF). - ;; Without this proposal, this opcode (0xC0) causes a validation error. - i32.extend8_s - - ;; Check if result is -1 - i32.const -1 - i32.eq - ) - - (export "escrow_finish" (func $test_sign_ext)) -) diff --git a/src/test/app/wasm_fixtures/wat/proposal_stringref.wat b/src/test/app/wasm_fixtures/wat/proposal_stringref.wat deleted file mode 100644 index c9f8030faf..0000000000 --- a/src/test/app/wasm_fixtures/wat/proposal_stringref.wat +++ /dev/null @@ -1 +0,0 @@ -;;hard to generate diff --git a/src/test/app/wasm_fixtures/wat/proposal_tail_call.wat b/src/test/app/wasm_fixtures/wat/proposal_tail_call.wat deleted file mode 100644 index 193fb0aeb2..0000000000 --- a/src/test/app/wasm_fixtures/wat/proposal_tail_call.wat +++ /dev/null @@ -1,15 +0,0 @@ -(module - ;; Define a simple function we can tail-call - (func $target (result i32) - i32.const 1 - ) - - (func $escrow_finish (result i32) - ;; Try to use the 'return_call' instruction (Opcode 0x12) - ;; If Tail Call proposal is disabled, this fails to Compile/Validate. - ;; If enabled, it jumps to $target, which returns 1. - return_call $target - ) - - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/start_loop.wat b/src/test/app/wasm_fixtures/wat/start_loop.wat deleted file mode 100644 index 241774e53e..0000000000 --- a/src/test/app/wasm_fixtures/wat/start_loop.wat +++ /dev/null @@ -1,22 +0,0 @@ -(module - ;; Function 1: The Infinite Loop - (func $run_forever - (loop $infinite - br $infinite - ) - ) - - ;; Function 2: Finish - (func $escrow_finish (result i32) - i32.const 1 - ) - - ;; 1. EXPORT the functions (optional, if you want to call them later) - (export "start" (func $run_forever)) - (export "escrow_finish" (func $escrow_finish)) - - ;; 2. The special start section - ;; This tells the VM: "Run function $run_forever immediately - ;; when this module is instantiated." - (start $run_forever) -) diff --git a/src/test/app/wasm_fixtures/wat/table_0_elements.wat b/src/test/app/wasm_fixtures/wat/table_0_elements.wat deleted file mode 100644 index 9b8a5408d2..0000000000 --- a/src/test/app/wasm_fixtures/wat/table_0_elements.wat +++ /dev/null @@ -1,10 +0,0 @@ -(module - ;; Define a table with exactly 0 entries - (table 0 funcref) - - ;; Standard finish function - (func $escrow_finish (result i32) - i32.const 1 - ) - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/table_2_tables.wat b/src/test/app/wasm_fixtures/wat/table_2_tables.wat deleted file mode 100644 index 4e4e013ce3..0000000000 --- a/src/test/app/wasm_fixtures/wat/table_2_tables.wat +++ /dev/null @@ -1,24 +0,0 @@ -(module - ;; Define a dummy function to put in the tables - (func $dummy) - - ;; TABLE 0: The default table (allowed in MVP) - ;; Size: 1 initial, 1 max - (table $t0 1 1 funcref) - - ;; Initialize Table 0 at index 0 - (elem (table $t0) (i32.const 0) $dummy) - - ;; TABLE 1: The second table (Requires Reference Types proposal) - ;; If strict MVP is enforced, the parser should error here. - (table $t1 1 1 funcref) - - ;; Initialize Table 1 at index 0 - (elem (table $t1) (i32.const 0) $dummy) - - (func $escrow_finish (result i32) - ;; If we successfully loaded a module with 2 tables, return 1. - i32.const 1 - ) - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/table_64_elements.wat b/src/test/app/wasm_fixtures/wat/table_64_elements.wat deleted file mode 100644 index 3221571fe9..0000000000 --- a/src/test/app/wasm_fixtures/wat/table_64_elements.wat +++ /dev/null @@ -1,25 +0,0 @@ -(module - ;; Define a table with exactly 64 entries - (table 64 funcref) - - ;; A dummy function to reference - (func $dummy) - - ;; Initialize the table at offset 0 with 64 references to $dummy - (elem (i32.const 0) - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 8 - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 16 - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 24 - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 32 - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 40 - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 48 - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 56 - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 64 - ) - - ;; Standard finish function - (func $escrow_finish (result i32) - i32.const 1 - ) - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/table_65_elements.wat b/src/test/app/wasm_fixtures/wat/table_65_elements.wat deleted file mode 100644 index aa0688c56f..0000000000 --- a/src/test/app/wasm_fixtures/wat/table_65_elements.wat +++ /dev/null @@ -1,25 +0,0 @@ -(module - ;; Define a table with exactly 65 entries - (table 65 funcref) - - ;; A dummy function to reference - (func $dummy) - - ;; Initialize the table at offset 0 with 65 references to $dummy - (elem (i32.const 0) - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 8 - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 16 - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 24 - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 32 - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 40 - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 48 - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 56 - $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 64 - $dummy ;; 65 (The one that breaks the camel's back) - ) - - (func $escrow_finish (result i32) - i32.const 1 - ) - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/table_uint_max.wat b/src/test/app/wasm_fixtures/wat/table_uint_max.wat deleted file mode 100644 index 23908611c8..0000000000 --- a/src/test/app/wasm_fixtures/wat/table_uint_max.wat +++ /dev/null @@ -1,15 +0,0 @@ -(module - ;; Definition: (table ) - ;; We use 0xFFFFFFFF (4,294,967,295), which is the unsigned equivalent of -1. - ;; This tests if the runtime handles the maximum possible u32 value - ;; without integer overflows or attempting a massive allocation. - ;; - ;; Note that using -1 as the table size cannot be parsed by wasm-tools or wat2wasm - (table 0xFFFFFFFF funcref) - - (func $escrow_finish (result i32) - ;; If the module loads despite the massive table, return 1. - i32.const 1 - ) - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/trap_divide_by_0.wat b/src/test/app/wasm_fixtures/wat/trap_divide_by_0.wat deleted file mode 100644 index 6f8754ec8f..0000000000 --- a/src/test/app/wasm_fixtures/wat/trap_divide_by_0.wat +++ /dev/null @@ -1,15 +0,0 @@ -(module - (func $escrow_finish (export "escrow_finish") (result i32) - ;; Setup for Requirement 2: Divide an i32 by 0 - i32.const 42 ;; Push numerator - i32.const 0 ;; Push denominator (0) - i32.div_s ;; Perform signed division (42 / 0) - - ;; --- NOTE: Execution usually traps (crashes) at the line above --- - - ;; Logic to satisfy Requirement 1: Return i32 = 1 - ;; If execution continued, we would drop the division result and return 1 - drop ;; Clear the stack - i32.const 1 ;; Push the return value - ) -) diff --git a/src/test/app/wasm_fixtures/wat/trap_func_signature_mismatch.wat b/src/test/app/wasm_fixtures/wat/trap_func_signature_mismatch.wat deleted file mode 100644 index fd20f6176a..0000000000 --- a/src/test/app/wasm_fixtures/wat/trap_func_signature_mismatch.wat +++ /dev/null @@ -1,33 +0,0 @@ -(module - ;; Define a table with 1 slot - (table 1 funcref) - - ;; Define Type A: Takes nothing, returns nothing - (type $type_void (func)) - - ;; Define Type B: Takes nothing, returns i32 - (type $type_i32 (func (result i32))) - - ;; Define a function of Type A - (func $void_func (type $type_void) - nop - ) - - ;; Put Type A function into Table[0] - (elem (i32.const 0) $void_func) - - (func $escrow_finish (result i32) - ;; Attempt to call Index 0, but CLAIM we expect Type B (result i32). - ;; The function at Index 0 matches Type A. - ;; TRAP: "indirect call type mismatch" - - ;; 1. Push the table index (0) onto the stack - i32.const 0 - - ;; 2. Call indirect using Type B signature. - ;; This pops the index (0) from the stack. - call_indirect (type $type_i32) - ) - - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/trap_int_overflow.wat b/src/test/app/wasm_fixtures/wat/trap_int_overflow.wat deleted file mode 100644 index 208e5bd211..0000000000 --- a/src/test/app/wasm_fixtures/wat/trap_int_overflow.wat +++ /dev/null @@ -1,18 +0,0 @@ -(module - (func $test_int_overflow (result i32) - ;; 1. Push INT_MIN (-2147483648) - ;; In Hex: 0x80000000 - i32.const -2147483648 - - ;; 2. Push -1 - i32.const -1 - - ;; 3. Signed Division - ;; This specific case is the ONLY integer arithmetic operation - ;; (besides divide by zero) that traps in the spec. - ;; Result would be +2147483648, which is too big for signed i32. - i32.div_s - ) - - (export "escrow_finish" (func $test_int_overflow)) -) diff --git a/src/test/app/wasm_fixtures/wat/trap_null_call.wat b/src/test/app/wasm_fixtures/wat/trap_null_call.wat deleted file mode 100644 index 63173303c5..0000000000 --- a/src/test/app/wasm_fixtures/wat/trap_null_call.wat +++ /dev/null @@ -1,22 +0,0 @@ -(module - ;; Table size is 1, so Index 0 is VALID bounds. - ;; However, we do NOT initialize it, so it contains 'ref.null'. - (table 1 funcref) - - (type $t (func (result i32))) - - (func $escrow_finish (result i32) - ;; Call Index 0. - ;; Bounds check passes (0 < 1). - ;; Null check fails. - ;; TRAP: "uninitialized element" or "undefined element" - - ;; 1. Push the index (0) onto the stack first - i32.const 0 - - ;; 2. Perform the call. This pops the index. - call_indirect (type $t) - ) - - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/trap_unreachable.wat b/src/test/app/wasm_fixtures/wat/trap_unreachable.wat deleted file mode 100644 index 3d8fe89f5b..0000000000 --- a/src/test/app/wasm_fixtures/wat/trap_unreachable.wat +++ /dev/null @@ -1,12 +0,0 @@ -(module - (func $escrow_finish (result i32) - ;; This instruction explicitly causes a trap. - ;; It consumes no fuel (beyond the instruction itself) and stops execution. - unreachable - - ;; This code is dead and never reached - i32.const 1 - ) - - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/wasi_get_time.wat b/src/test/app/wasm_fixtures/wat/wasi_get_time.wat deleted file mode 100644 index 6b525067a8..0000000000 --- a/src/test/app/wasm_fixtures/wat/wasi_get_time.wat +++ /dev/null @@ -1,38 +0,0 @@ -(module - ;; Import clock_time_get from WASI - ;; Signature: (param clock_id precision return_ptr) (result errno) - (import "wasi_snapshot_preview1" "clock_time_get" - (func $clock_time_get (param i32 i64 i32) (result i32)) - ) - - (memory 1) - (export "memory" (memory 0)) - - (func $escrow_finish (result i32) - ;; We will store the timestamp (a 64-bit integer) at address 0. - ;; No setup required in memory beforehand! - - ;; Call the function - (call $clock_time_get - (i32.const 0) ;; clock_id: 0 = Realtime (Wallclock) - (i64.const 1000) ;; precision: 1000ns (hint to OS) - (i32.const 0) ;; result_ptr: Write the time to address 0 - ) - - ;; The function returns an 'errno' (error code). - ;; 0 = Success. Anything else = Error. - - ;; Check if errno (top of stack) is 0 - i32.eqz - if (result i32) - ;; Success! The time is now stored in heap[0..8]. - ;; We return 1 as requested. - i32.const 1 - else - ;; Failed (maybe WASI is disabled or clock is missing) - i32.const -1 - end - ) - - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/wasi_print.wat b/src/test/app/wasm_fixtures/wat/wasi_print.wat deleted file mode 100644 index 511c5ba724..0000000000 --- a/src/test/app/wasm_fixtures/wat/wasi_print.wat +++ /dev/null @@ -1,59 +0,0 @@ -(module - ;; Import WASI fd_write - ;; Signature: (fd, iovs_ptr, iovs_len, nwritten_ptr) -> errno - (import "wasi_snapshot_preview1" "fd_write" - (func $fd_write (param i32 i32 i32 i32) (result i32)) - ) - - (memory 1) - (export "memory" (memory 0)) - - ;; --- DATA SEGMENTS --- - - ;; 1. The String Data "Hello\n" placed at offset 16 - ;; We assume offset 0-16 is reserved for the IOVec struct - (data (i32.const 16) "Hello\n") - - ;; 2. The IO Vector (struct iovec) placed at offset 0 - ;; Structure: { buf_ptr: u32, buf_len: u32 } - - ;; Field 1: buf_ptr = 16 (Location of "Hello\n") - ;; Encoded in little-endian: 10 00 00 00 - (data (i32.const 0) "\10\00\00\00") - - ;; Field 2: buf_len = 6 (Length of "Hello\n") - ;; Encoded in little-endian: 06 00 00 00 - (data (i32.const 4) "\06\00\00\00") - - (func $escrow_finish (result i32) - (local $nwritten_ptr i32) - - ;; We will ask WASI to write the "number of bytes written" to address 24 - ;; (safely after our string data) - i32.const 24 - local.set $nwritten_ptr - - ;; Call fd_write - (call $fd_write - (i32.const 1) ;; fd: 1 = STDOUT - (i32.const 0) ;; iovs_ptr: Address 0 (where we defined the struct) - (i32.const 1) ;; iovs_len: We are passing 1 vector - (local.get $nwritten_ptr) ;; nwritten_ptr: Address 24 - ) - - ;; The function returns an 'errno' (i32). - ;; 0 means Success. - - ;; Check if errno == 0 - i32.eqz - if (result i32) - ;; Success: Return 1 - i32.const 1 - else - ;; Failure: Return -1 - i32.const -1 - end - ) - - (export "escrow_finish" (func $escrow_finish)) -) diff --git a/src/test/app/wasm_fixtures/wat/wide_arithmetic.wat b/src/test/app/wasm_fixtures/wat/wide_arithmetic.wat deleted file mode 100644 index 13b1ab4836..0000000000 --- a/src/test/app/wasm_fixtures/wat/wide_arithmetic.wat +++ /dev/null @@ -1,22 +0,0 @@ -(module - (func $escrow_finish (result i32) - ;; 1. Push operands - i64.const 1 - i64.const 2 - - ;; 2. Execute Wide Multiplication - ;; If the feature is DISABLED, the parser/validator will trap here - ;; with "unknown instruction" or "invalid opcode". - ;; Input: [i64, i64] -> Output: [i64, i64] - i64.mul_wide_u - - ;; 3. Clean up the stack (drop the two i64 results) - drop - drop - - ;; 4. Return 1 to signal that validation passed - i32.const 1 - ) - - (export "escrow_finish" (func $escrow_finish)) -) From 7e3ac183453ae100c02ba096e151552af09a620a Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Tue, 25 Aug 2026 19:46:50 -0400 Subject: [PATCH 07/23] fix: Remove orphaned files --- crates/xrpl-wasm-vm/tests/host_calls.rs | 4 ---- crates/xrpl-wasm-vm/tests/vm_limits.rs | 8 -------- 2 files changed, 12 deletions(-) diff --git a/crates/xrpl-wasm-vm/tests/host_calls.rs b/crates/xrpl-wasm-vm/tests/host_calls.rs index f88d46e4b3..6d66c20e6b 100644 --- a/crates/xrpl-wasm-vm/tests/host_calls.rs +++ b/crates/xrpl-wasm-vm/tests/host_calls.rs @@ -1265,10 +1265,6 @@ fn the_outcome_carries_whatever_the_guest_returned() { } } -// --------------------------------------------------------------------------- -// Float operators without a dedicated marshalling test above (ported gaps) -// --------------------------------------------------------------------------- - /// The remaining binary operators marshal like `float_add`: both operands and the mode reach /// the host, tagged by operator. #[test] diff --git a/crates/xrpl-wasm-vm/tests/vm_limits.rs b/crates/xrpl-wasm-vm/tests/vm_limits.rs index 822787e81f..bcbfa7218d 100644 --- a/crates/xrpl-wasm-vm/tests/vm_limits.rs +++ b/crates/xrpl-wasm-vm/tests/vm_limits.rs @@ -599,10 +599,6 @@ fn a_memory64_module_is_rejected_at_compile() { ); } -// --------------------------------------------------------------------------- -// Resource-exhaustion limits (ported from the old Beast fixtures) -// --------------------------------------------------------------------------- - /// A function declaring more parameters than wasm allows (1000) is refused at compile, so a /// contract cannot smuggle an unbounded signature past screening. #[test] @@ -672,10 +668,6 @@ fn many_functions_currently_run_unbounded() { ); } -// --------------------------------------------------------------------------- -// Individual trap kinds (belt-and-suspenders alongside the unreachable representative) -// --------------------------------------------------------------------------- - /// The trap *kinds* wasmi distinguishes all reach the caller identically — a guest trap /// charged as the contract's fault — so the `unreachable` representative pins the mapping. /// These pin the individual kinds too, guarding against a wasmi upgrade reclassifying any of From 8320dd4982e6b4262f92a2f5a886ff1e53953b21 Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Tue, 25 Aug 2026 20:41:00 -0400 Subject: [PATCH 08/23] fix: Remove orphaned files --- src/tests/libxrpl/tx/wasm/README.md | 29 +++++++++++++++++-- src/tests/libxrpl/tx/wasm/RealVmTest.h | 6 ++++ .../libxrpl/tx/wasm/e2e/HostFunctionTour.cpp | 2 ++ src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp | 3 ++ src/tests/libxrpl/tx/wasm/e2e/SetData.cpp | 2 ++ src/tests/libxrpl/tx/wasm/e2e/TxField.cpp | 1 + 6 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/tests/libxrpl/tx/wasm/README.md b/src/tests/libxrpl/tx/wasm/README.md index fbfafb6237..4aee9bc398 100644 --- a/src/tests/libxrpl/tx/wasm/README.md +++ b/src/tests/libxrpl/tx/wasm/README.md @@ -67,9 +67,34 @@ design. new split verifies agreement **transitively**: the SDK repo tests the SDK against the ABI spec, and this repo tests the host against the same spec (`host_calls`, the `generated_abi.rs` spec table, `host_errors.rs`). That is sound as long as both conform to the spec; it would not catch a drift -where the SDK and host diverge on an ambiguous point. Closing that gap is **not** a rippled unit +where the SDK and host diverge on an ambiguous point. Closing that gap is **not** a xrpld unit test — it is a **cross-repo integration test** (compiled `xrpl-wasm-stdlib` guests run against a -real rippled host) belonging in CI where the Rust→wasm toolchain exists. +real xrpld host) belonging in CI where the Rust→wasm toolchain exists. + +## Out of scope — transactor-level (L5) tests deferred until the transactor is wired + +This migration ported `Wasm_test.cpp` + the `wasm_fixtures/` guests, which drive the VM directly +via `runEscrowWasm`. In the upstream `ripple/smart-escrow` branch the **same fixtures** are also +consumed by two **transactor-level** suites that are **not** part of this port and have **no +equivalent here yet**, because the redesign branch does not yet wire `runEscrowWasm` into the +`EscrowFinish` transactor (it has no caller under `src/xrpld`): + +- **`EscrowSmart_test.cpp`** — full `Env → EscrowFinish → ledger`. Its cases test things none of + the layers above cover, because they only exist once a transactor runs the contract: + - **`set_data` persistence** — "Update escrow data on failure" asserts the contract's data field + is written to the escrow ledger object **even on `tecBYTECODE_REJECTED`**. (Note: in _this_ + branch `set_data` is _not_ persisted — there is no transactor caller yet — so this is a real + gap, not a redundancy.) + - **gas → fee / meta** — `sfGasUsed` and `sfVMReturnCode` surfaced in transaction metadata. + - **owner reserve / owner count** accounting for the bytecode-bearing escrow. + - **transactor-driven tours** — "Test all host functions", "Test all keylet host functions", + "Test large wasm modules". +- **`PayChan_test.cpp`** — also consumes `wasm_fixtures` symbols at the transactor level. + +These belong to the **L5 transactor layer**. When `EscrowFinish` is wired to `runEscrowWasm` in the +redesign, those cases need a home (as C++ transactor tests over a real `Env`), and the persistence / +gas-in-meta / reserve behaviors should be pinned there — the WAT layers here deliberately stop at +the VM boundary and do not exercise the transactor. ## Old → new test map diff --git a/src/tests/libxrpl/tx/wasm/RealVmTest.h b/src/tests/libxrpl/tx/wasm/RealVmTest.h index 2a03d65280..6e716d3745 100644 --- a/src/tests/libxrpl/tx/wasm/RealVmTest.h +++ b/src/tests/libxrpl/tx/wasm/RealVmTest.h @@ -1,11 +1,17 @@ #pragma once +#include +#include +#include +#include #include #include #include #include +#include +#include #include #include #include diff --git a/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp b/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp index 5886ac4d07..3dba1521fb 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp @@ -3,6 +3,8 @@ #include #include +#include + namespace xrpl::test { // A single contract that tours several host functions end to end — a ledger-header read, the diff --git a/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp b/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp index 1acbc13a6e..9211dc3a86 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp @@ -1,7 +1,10 @@ +#include + #include #include #include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp b/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp index 96de2f84f8..01786ae777 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp @@ -3,6 +3,8 @@ #include #include +#include + namespace xrpl::test { // A contract writes its data field end to end — the one mutation a contract can make. The diff --git a/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp b/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp index b0f9b037e2..26aeaf6462 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include From 072c7cb5012bb8a225aaf52a7a7f29fc1767e6db Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Tue, 25 Aug 2026 20:49:12 -0400 Subject: [PATCH 09/23] fix: Remove orphaned files --- src/tests/libxrpl/tx/wasm/README.md | 2 +- src/tests/libxrpl/tx/wasm/RealVmTest.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tests/libxrpl/tx/wasm/README.md b/src/tests/libxrpl/tx/wasm/README.md index 4aee9bc398..c652b624b9 100644 --- a/src/tests/libxrpl/tx/wasm/README.md +++ b/src/tests/libxrpl/tx/wasm/README.md @@ -67,7 +67,7 @@ design. new split verifies agreement **transitively**: the SDK repo tests the SDK against the ABI spec, and this repo tests the host against the same spec (`host_calls`, the `generated_abi.rs` spec table, `host_errors.rs`). That is sound as long as both conform to the spec; it would not catch a drift -where the SDK and host diverge on an ambiguous point. Closing that gap is **not** a xrpld unit +where the SDK and host diverge on an ambiguous point. Closing that gap is **not** an xrpld unit test — it is a **cross-repo integration test** (compiled `xrpl-wasm-stdlib` guests run against a real xrpld host) belonging in CI where the Rust→wasm toolchain exists. diff --git a/src/tests/libxrpl/tx/wasm/RealVmTest.h b/src/tests/libxrpl/tx/wasm/RealVmTest.h index 6e716d3745..b437e45023 100644 --- a/src/tests/libxrpl/tx/wasm/RealVmTest.h +++ b/src/tests/libxrpl/tx/wasm/RealVmTest.h @@ -10,7 +10,6 @@ #include #include -#include #include #include #include From 37128fb8bdf04294797f526788cd67a126e84c6f Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Wed, 26 Aug 2026 15:25:10 -0400 Subject: [PATCH 10/23] fix: Add benchmark tests for host functions --- .cspell.config.yaml | 1 + cmake/XrplAddBenchmark.cmake | 8 + conanfile.py | 7 + crates/Cargo.lock | 1 + crates/xrpl-wasm-testkit/Cargo.toml | 1 + crates/xrpl-wasm-testkit/src/lib.rs | 58 ++ src/benchmarks/libxrpl/CMakeLists.txt | 80 +++ src/tests/libxrpl/CMakeLists.txt | 22 + src/tests/libxrpl/tx/wasm/BenchFixtures.h | 220 +++++++ src/tests/libxrpl/tx/wasm/Crossing.bench.cpp | 44 ++ src/tests/libxrpl/tx/wasm/README.md | 225 +++++++- src/tests/libxrpl/tx/wasm/WasmBench.h | 544 ++++++++++++++++++ src/tests/libxrpl/tx/wasm/WasmRun.h | 30 + .../libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp | 74 +++ .../libxrpl/tx/wasm/e2e/FloatToMantExp.cpp | 64 +++ src/tests/libxrpl/tx/wasm/e2e/HostError.cpp | 55 ++ .../libxrpl/tx/wasm/e2e/TxNestedField.cpp | 78 +++ .../host_functions/AccountKeylet.bench.cpp | 30 + .../wasm/host_functions/AmmKeylet.bench.cpp | 36 ++ .../tx/wasm/host_functions/BaseFee.bench.cpp | 25 + .../host_functions/CacheLedgerObj.bench.cpp | 40 ++ .../wasm/host_functions/CheckKeylet.bench.cpp | 30 + .../host_functions/CheckSignature.bench.cpp | 73 +++ .../host_functions/CredentialKeylet.bench.cpp | 36 ++ .../CurrentLedgerObjArrayLen.bench.cpp | 30 + .../CurrentLedgerObjField.bench.cpp | 57 ++ .../CurrentLedgerObjNestedArrayLen.bench.cpp | 33 ++ .../CurrentLedgerObjNestedField.bench.cpp | 34 ++ .../host_functions/DelegateKeylet.bench.cpp | 30 + .../DepositPreauthKeylet.bench.cpp | 30 + .../wasm/host_functions/DidKeylet.bench.cpp | 30 + .../host_functions/EscrowKeylet.bench.cpp | 63 ++ .../tx/wasm/host_functions/FloatAdd.bench.cpp | 56 ++ .../host_functions/FloatCompare.bench.cpp | 29 + .../wasm/host_functions/FloatDivide.bench.cpp | 28 + .../host_functions/FloatFromInt.bench.cpp | 28 + .../host_functions/FloatFromMantExp.bench.cpp | 28 + .../FloatFromStAmount.bench.cpp | 35 ++ .../FloatFromStNumber.bench.cpp | 35 ++ .../host_functions/FloatFromUint.bench.cpp | 28 + .../host_functions/FloatMultiply.bench.cpp | 29 + .../wasm/host_functions/FloatPower.bench.cpp | 49 ++ .../wasm/host_functions/FloatRoot.bench.cpp | 29 + .../host_functions/FloatSubtract.bench.cpp | 28 + .../wasm/host_functions/FloatToInt.bench.cpp | 28 + .../host_functions/FloatToMantExp.bench.cpp | 47 ++ .../tx/wasm/host_functions/GetNFT.bench.cpp | 40 ++ .../IsAmendmentEnabled.bench.cpp | 69 +++ .../LedgerObjArrayLen.bench.cpp | 29 + .../host_functions/LedgerObjField.bench.cpp | 32 ++ .../LedgerObjNestedArrayLen.bench.cpp | 32 ++ .../LedgerObjNestedField.bench.cpp | 33 ++ .../wasm/host_functions/LedgerSqn.bench.cpp | 45 ++ .../MptokenIssuanceKeylet.bench.cpp | 30 + .../host_functions/MptokenKeylet.bench.cpp | 33 ++ .../tx/wasm/host_functions/NFTFlags.bench.cpp | 27 + .../wasm/host_functions/NFTIssuer.bench.cpp | 29 + .../wasm/host_functions/NFTSequence.bench.cpp | 27 + .../tx/wasm/host_functions/NFTTaxon.bench.cpp | 27 + .../host_functions/NFTTransferFee.bench.cpp | 27 + .../NftokenOfferKeylet.bench.cpp | 30 + .../wasm/host_functions/OfferKeylet.bench.cpp | 30 + .../host_functions/OracleKeylet.bench.cpp | 30 + .../host_functions/ParentLedgerHash.bench.cpp | 29 + .../host_functions/ParentLedgerTime.bench.cpp | 29 + .../host_functions/PaychannelKeylet.bench.cpp | 32 ++ .../PermissionedDomainedKeylet.bench.cpp | 30 + .../wasm/host_functions/Sha512Half.bench.cpp | 82 +++ .../host_functions/SignerListKeylet.bench.cpp | 30 + .../host_functions/TicketKeylet.bench.cpp | 30 + .../tx/wasm/host_functions/Trace.bench.cpp | 54 ++ .../host_functions/TrustLineKeylet.bench.cpp | 35 ++ .../wasm/host_functions/TxArrayLen.bench.cpp | 31 + .../tx/wasm/host_functions/TxField.bench.cpp | 31 + .../host_functions/TxNestedArrayLen.bench.cpp | 32 ++ .../host_functions/TxNestedField.bench.cpp | 65 +++ .../wasm/host_functions/UpdateData.bench.cpp | 75 +++ .../wasm/host_functions/VaultKeylet.bench.cpp | 30 + 78 files changed, 3734 insertions(+), 17 deletions(-) create mode 100644 src/tests/libxrpl/tx/wasm/BenchFixtures.h create mode 100644 src/tests/libxrpl/tx/wasm/Crossing.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/WasmBench.h create mode 100644 src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp create mode 100644 src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp create mode 100644 src/tests/libxrpl/tx/wasm/e2e/HostError.cpp create mode 100644 src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp diff --git a/.cspell.config.yaml b/.cspell.config.yaml index b7b929dffe..1797a387f7 100644 --- a/.cspell.config.yaml +++ b/.cspell.config.yaml @@ -172,6 +172,7 @@ words: - levelization - levelized - libpb + - libpfm - libxrpl - llection - LOCALGOOD diff --git a/cmake/XrplAddBenchmark.cmake b/cmake/XrplAddBenchmark.cmake index 921deb0658..a09db01c46 100644 --- a/cmake/XrplAddBenchmark.cmake +++ b/cmake/XrplAddBenchmark.cmake @@ -29,6 +29,14 @@ function(xrpl_add_benchmark name) # XrplCore.cmake. Each file compiles fine on its own. set_target_properties(${target} PROPERTIES UNITY_BUILD OFF) + # Land next to `xrpl_tests` in the build root rather than buried under + # `src/benchmarks/libxrpl/`. A benchmark is something a person runs by hand, + # repeatedly, and comparing two of them should not mean typing two long paths. + set_target_properties( + ${target} + PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" + ) + isolate_headers( ${target} "${CMAKE_SOURCE_DIR}/src" diff --git a/conanfile.py b/conanfile.py index ae677b99aa..bf948fbfa8 100644 --- a/conanfile.py +++ b/conanfile.py @@ -131,6 +131,13 @@ class Xrpl(ConanFile): self.options["boost"].visibility = "global" if self.settings.compiler in ["clang", "gcc"]: self.options["boost"].without_cobalt = True + # Google Benchmark can read hardware performance counters (instructions, + # cycles, ...) through libpfm, which its recipe only offers on Linux. The + # wasm gas-calibration benchmarks want instruction counts as a + # machine-independent cross-check on wall time, so enable it where it + # exists; elsewhere those benchmarks fall back to timing alone. + if self.options.benchmark and self.settings.os == "Linux": + self.options["benchmark"].enable_libpfm = True def requirements(self): if self.options.benchmark: diff --git a/crates/Cargo.lock b/crates/Cargo.lock index ddfd05bc00..dc45bd9a24 100644 --- a/crates/Cargo.lock +++ b/crates/Cargo.lock @@ -476,6 +476,7 @@ version = "0.1.0" dependencies = [ "cxx", "wat", + "xrpl-host-functions", ] [[package]] diff --git a/crates/xrpl-wasm-testkit/Cargo.toml b/crates/xrpl-wasm-testkit/Cargo.toml index 06c1e7c366..21b929bae1 100644 --- a/crates/xrpl-wasm-testkit/Cargo.toml +++ b/crates/xrpl-wasm-testkit/Cargo.toml @@ -9,3 +9,4 @@ crate-type = ["staticlib", "rlib"] [dependencies] cxx.workspace = true wat = "1" +xrpl-host-functions = { path = "../xrpl-host-functions" } diff --git a/crates/xrpl-wasm-testkit/src/lib.rs b/crates/xrpl-wasm-testkit/src/lib.rs index f503294c59..9dbbaad7da 100644 --- a/crates/xrpl-wasm-testkit/src/lib.rs +++ b/crates/xrpl-wasm-testkit/src/lib.rs @@ -19,6 +19,18 @@ mod ffi { /// Throws `rust::Error` on invalid input, which is what a test wants: a typo in a /// fixture should fail the test that holds it, at the line that holds it. fn compile_wat(wat: &str) -> Result>; + + /// The gas a host function is charged before it runs, by its guest import name. + /// + /// For the C++ gas benchmarks, which measure what a host call actually costs and + /// report it against what the table says it costs. Reading the declaration through + /// here rather than copying the numbers into C++ is the point: 61 transcribed + /// constants would drift from `lib.rs` the first time a price changed, and drift + /// silently, because a benchmark has nothing to fail. + /// + /// Throws `rust::Error` on an unknown name — a typo should fail loudly rather than + /// quietly compare against zero. + fn declared_gas(wasm_name: &str) -> Result; } } @@ -26,6 +38,25 @@ fn compile_wat(wat: &str) -> Result, wat::Error> { wat::parse_str(wat) } +fn declared_gas(wasm_name: &str) -> Result { + xrpl_host_functions::HostFunctionSpec::ALL + .iter() + .find(|op| op.wasm_name() == wasm_name) + .map(|op| op.gas()) + .ok_or_else(|| UnknownHostFunction(wasm_name.to_owned())) +} + +#[derive(Debug)] +struct UnknownHostFunction(String); + +impl std::fmt::Display for UnknownHostFunction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "no host function is imported as `{}`", self.0) + } +} + +impl std::error::Error for UnknownHostFunction {} + #[cfg(test)] mod tests { use super::compile_wat; @@ -37,6 +68,33 @@ mod tests { assert_eq!(&wasm[..4], b"\0asm"); } + #[test] + fn a_host_function_reports_the_gas_its_declaration_gives_it() { + // `trace` is the cheapest declaration in the table; the point is not the number but + // that the lookup reaches the same constant the engine charges from. + assert_eq!( + super::declared_gas("trace").expect("trace is a host function"), + xrpl_host_functions::HostFunctionSpec::Trace.gas() + ); + } + + #[test] + fn every_host_function_is_reachable_by_its_import_name() { + for op in xrpl_host_functions::HostFunctionSpec::ALL { + assert_eq!( + super::declared_gas(op.wasm_name()).expect("declared"), + op.gas(), + "{} must be reachable by name", + op.wasm_name() + ); + } + } + + #[test] + fn an_unknown_name_is_an_error_rather_than_zero_gas() { + super::declared_gas("not_a_host_function").expect_err("must not resolve"); + } + #[test] fn a_typo_is_an_error_rather_than_a_module() { let error = compile_wat("(module (func (export").expect_err("must not assemble"); diff --git a/src/benchmarks/libxrpl/CMakeLists.txt b/src/benchmarks/libxrpl/CMakeLists.txt index ac751a0413..8e0f25d927 100644 --- a/src/benchmarks/libxrpl/CMakeLists.txt +++ b/src/benchmarks/libxrpl/CMakeLists.txt @@ -20,3 +20,83 @@ target_link_libraries( xrpl_add_benchmark(nodestore) target_link_libraries(xrpl.bench.nodestore PRIVATE xrpl.imports.bench) add_dependencies(xrpl.benchmarks xrpl.bench.nodestore) + +# --------------------------------------------------------------------------- +# xrpl.bench.wasm — gas calibration for the wasm host functions. +# +# Unlike `nodestore`, this module's sources do not live here: each `*.bench.cpp` +# sits beside the test that covers the same host function, under +# `src/tests/libxrpl/tx/wasm/`. Keeping the benchmark next to the test means the +# two move together and share one fixture; a separate executable means benchmark +# runtime never lands on the `ctest` path (the test binary filters `*.bench.cpp` +# back out). +# +# Reusing those fixtures means compiling a few test sources and linking GTest: +# `RealHostFixture` derives from `testing::Test`. Nothing here registers a test. +find_package(GTest QUIET) +if(TARGET GTest::gtest) + file( + GLOB_RECURSE wasm_bench_sources + CONFIGURE_DEPENDS + "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/*.bench.cpp" + ) + + add_executable( + xrpl.bench.wasm + ${wasm_bench_sources} + # The fixtures under measurement: a real ledger, a real host, real accounts. + "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/helpers/Account.cpp" + "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/helpers/TestSink.cpp" + "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/helpers/TxTest.cpp" + "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/RealHostFixture.cpp" + "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/NFTFixture.cpp" + ) + + # Google Benchmark registers cases through static registrars declared in + # anonymous namespaces; merging several such files into one unity translation + # unit collides them. Same reason as `xrpl_add_benchmark`. + # + # The output directory matches too: benchmarks land in the build root beside + # `xrpl_tests`, because they are run by hand and comparing two of them should + # not mean typing two long paths. + set_target_properties( + xrpl.bench.wasm + PROPERTIES + UNITY_BUILD OFF + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" + ) + + # The fixtures include their siblings as and , the + # same spelling the test binary gives them. + target_include_directories( + xrpl.bench.wasm + PRIVATE "${CMAKE_SOURCE_DIR}/src/tests/libxrpl" + ) + target_link_libraries( + xrpl.bench.wasm + PRIVATE + xrpl.imports.bench + GTest::gtest + GTest::gmock + xrpl_wasm_testkit_cxxbridge + ) + add_dependencies(xrpl.bench.wasm xrpl_crates) + + # Hardware performance counters (INSTRUCTIONS, CYCLES, ...) come from libpfm, + # which Google Benchmark only builds on Linux (see the `enable_libpfm` option + # set in conanfile.py). Where it is available the benchmarks advertise the + # `--benchmark_perf_counters=...` flag; elsewhere they report wall time only. + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + target_compile_definitions( + xrpl.bench.wasm + PRIVATE XRPL_BENCH_PERF_COUNTERS=1 + ) + endif() + + add_dependencies(xrpl.benchmarks xrpl.bench.wasm) +else() + message( + STATUS + "GTest not found; skipping xrpl.bench.wasm (it reuses the test fixtures)." + ) +endif() diff --git a/src/tests/libxrpl/CMakeLists.txt b/src/tests/libxrpl/CMakeLists.txt index 44f7b4bdc4..34fc7c66e6 100644 --- a/src/tests/libxrpl/CMakeLists.txt +++ b/src/tests/libxrpl/CMakeLists.txt @@ -55,6 +55,11 @@ foreach(module IN LISTS test_modules) "${CMAKE_CURRENT_SOURCE_DIR}/${module}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/${module}.cpp" ) + # `*.bench.cpp` files live beside the tests they measure, but belong to the + # benchmark executables (src/benchmarks/libxrpl), not to this one: they define + # Google Benchmark registrars, and running them under ctest would make a test + # run take minutes. Keep them out of the test binary. + list(FILTER sources EXCLUDE REGEX "\\.bench\\.cpp$") target_sources(xrpl_tests PRIVATE ${sources}) # Expose the module's private headers under their canonical include path. @@ -76,6 +81,23 @@ file( ) target_sources(xrpl_tests PRIVATE ${csf_sources}) +# `tx/wasm/WasmBench.h` and `tx/wasm/BenchFixtures.h` sit beside the tests they +# measure but belong to `xrpl.bench.wasm`, so they include +# while nothing in this binary does. `verify_target_headers` below compiles *every* +# header under this directory with this target's flags, so without the benchmark +# headers on the path those two fail to parse — which also makes clang-tidy's +# include-cleaner report nonsense for everything after the failed include. +# +# Carrying the include directory (not the library) is enough: the test binary +# compiles nothing that uses Google Benchmark, and links nothing from it. +if(benchmark AND TARGET benchmark::benchmark) + target_include_directories( + xrpl_tests + PRIVATE + $ + ) +endif() + # The test helpers and per-module test headers are not built with add_module, # so verify them against the test binary's own compile environment. if(verify_headers) diff --git a/src/tests/libxrpl/tx/wasm/BenchFixtures.h b/src/tests/libxrpl/tx/wasm/BenchFixtures.h new file mode 100644 index 0000000000..7c73591596 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/BenchFixtures.h @@ -0,0 +1,220 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// Shared ledger state for the `*.bench.cpp` files. +// +// Each host function gets its own `.bench.cpp`, mirroring its test one-for-one, which +// means ~61 translation units that would otherwise each build their own ledger, fund their own +// accounts and mint their own tokens. Everything here is `inline`, so a function-local static +// inside it is one object shared by the whole binary: the ledger is built once, each account is +// funded once, and a benchmark file is left holding only the call it measures. +// +// That sharing is safe because every helper does its setup inside its own `static`, so it +// happens exactly once no matter how many files ask for it. It is also why the accounts have +// bench-specific names — two files funding "owner" against one ledger would be a duplicate +// account, not a fresh one. +// +// Nothing here is timed. Benchmarks call these to get a host, then measure only the host call. + +namespace xrpl::test::bench { + +// The one ledger every benchmark runs against. +inline BenchFixture& +benchLedger() +{ + static BenchFixture value; + return value; +} + +// Two funded accounts, enough for every keylet shape and every object below. +inline Account const& +benchAlice() +{ + static auto const kValue = benchLedger().fund("benchAlice"); + return kValue; +} + +inline Account const& +benchBob() +{ + static auto const kValue = benchLedger().fund("benchBob"); + return kValue; +} + +// A sequence number for the keylets that take one. Arbitrary — a keylet hashes whatever it is +// given, so the value cannot change the cost. +inline constexpr std::uint32_t kBenchSeq = 42; + +// --------------------------------------------------------------------------- +// Transactions +// --------------------------------------------------------------------------- + +// An EscrowFinish carrying a two-element memo array: something for the nested-field getters to +// walk to and the array-length getters to count. +inline TxAssembler +benchMemoTx() +{ + auto assembler = escrowFinishTx(benchLedger().ledger, benchAlice()); + assembler.build = [inner = std::move(assembler.build)](STObject& obj) { + inner(obj); + auto memos = STArray{}; + memos.push_back(makeMemo(RealHostFixture::toBytes("hello"))); + memos.push_back(makeMemo(RealHostFixture::toBytes("world"))); + obj.setFieldArray(sfMemos, memos); + }; + return assembler; +} + +// `sfMemos[0].sfMemoData` — a two-step locator path, the shape the nested getters are priced for. +inline FieldLocator +benchMemoLocator() +{ + return FieldLocator{{sfMemos.getCode(), 0, sfMemoData.getCode()}}; +} + +// --------------------------------------------------------------------------- +// Hosts +// --------------------------------------------------------------------------- + +// The default: transaction carries the memo array, current object is Alice's account root. +inline WasmHost +benchHost() +{ + auto assembler = benchMemoTx(); + return benchLedger().makeHost( + keylet::account(benchAlice().id()), assembler.type, std::move(assembler.build)); +} + +// The same, with Alice's account root pinned to slot 1, for the `le_*` getters that read +// through a cache slot rather than the current object. +inline WasmHost +benchCachedHost() +{ + auto host = benchHost(); + (void)host->cacheLedgerObj(keylet::account(benchAlice().id()).key, 1); + return host; +} + +// An account root has no arrays, so the array-length getters that read a *ledger object* need a +// different one. A signer list has `sfSignerEntries`; without it those calls would answer +// `FieldNotFound` and the benchmark would time the rejection instead of the work. +inline Account const& +benchSignerListOwner() +{ + static auto const kValue = [] { + auto const acct = benchLedger().fund("benchSigners"); + benchLedger().makeSignerList(acct, 2, {{benchAlice(), 1}, {benchBob(), 1}}); + return acct; + }(); + return kValue; +} + +// Current object is the signer list. +inline WasmHost +benchSignerListHost() +{ + auto assembler = bareTx(); + return benchLedger().makeHost( + keylet::signerList(benchSignerListOwner().id()), + assembler.type, + std::move(assembler.build)); +} + +// Signer list pinned to slot 1. +inline WasmHost +benchCachedSignerListHost() +{ + auto assembler = bareTx(); + auto host = benchLedger().makeHost( + keylet::account(AccountID{}), assembler.type, std::move(assembler.build)); + (void)host->cacheLedgerObj(keylet::signerList(benchSignerListOwner().id()).key, 1); + return host; +} + +// A real escrow, created through the real transactor — the current object for `home_le_field`, +// which is the one getter whose cost depends on the object it reads rather than its arguments. +inline Keylet const& +benchEscrow() +{ + static auto const kValue = [] { + auto const ownerSeq = benchLedger().ledger.getAccountRoot(benchAlice().id()).getSequence(); + benchLedger().ledger.submit( + transactions::EscrowCreateBuilder{benchAlice().id(), benchBob().id(), XRP(100)} + .setFinishAfter(900'000'000), + benchAlice()); + benchLedger().ledger.close(); + return keylet::escrow(benchAlice().id(), SeqProxy::rawSequence(ownerSeq)); + }(); + return kValue; +} + +inline WasmHost +benchEscrowHost() +{ + return benchLedger().makeHost(benchEscrow()); +} + +// --------------------------------------------------------------------------- +// Inputs that need building +// --------------------------------------------------------------------------- + +// Canonical float operands. Zeroed bytes decode as a non-canonical float and would be refused +// before any arithmetic ran, so the whole family shares these two known-good values. +inline Slice +benchFloatX() +{ + return FloatTest::slice(FloatTest::kPi); +} + +inline Slice +benchFloatY() +{ + return FloatTest::slice(FloatTest::kTwo); +} + +// Rounding mode 0 throughout the float family: modes select a tie-breaking rule, not a different +// algorithm, so they do not move the cost, and pinning one keeps the fourteen comparable. +inline constexpr std::int32_t kBenchMode = 0; + +// A signed message for `check_sig`, produced once: signing is far more expensive than the +// verification being measured, so it must not happen inside the timed loop. +inline SignedMessage const& +benchSignedMessage() +{ + static auto const kValue = signMessage("the quick brown fox jumps over the lazy dog"); + return kValue; +} + +// A well-formed NFToken id with the fixture's known taxon, flags, fee and sequence baked in, so +// the id-extractor getters have real fields to pull out rather than zeros. +inline uint256 const& +benchNftId() +{ + // `makeNftId` is a static member, so no fixture instance is needed to reach it. + static auto const kValue = NFTTest::makeNftId(benchAlice().id()); + return kValue; +} + +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/Crossing.bench.cpp b/src/tests/libxrpl/tx/wasm/Crossing.bench.cpp new file mode 100644 index 0000000000..338c1d47fe --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/Crossing.bench.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The harness checking itself. +// +// This file holds no host function — it belongs to the wasm directory rather than +// `host_functions/` because it measures the two reference points every per-function number is read +// against, and neither is a host call. +// +// `GuestInstruction` runs a contract whose "host call" is a couple of guest instructions. Its +// `implied_gas` and `charged_gas` are then two independent measurements of the same quantity — one +// from wall time via `secondsPerGas`, one from the engine's own fuel meter — and they should agree +// closely. When they diverge, `secondsPerGas` has measured something other than a guest +// instruction and no other number in the run is trustworthy. Read this first. +// +// The crossing floor is the other reference point, and it lives in `host_functions/LedgerSqn`: +// `ldgr_index` takes no input and answers from a header already in hand, so its impl is as close +// to nothing as a host function gets, and whatever its `ThroughVm` case costs above its `Impl` +// case is the price of leaving the guest — paid by every one of the 61 functions before any of +// them does any work. +// +// So the reading order across the suite is: this file, then `LedgerSqn`'s pair for the floor, then +// a function's own `Impl` number. Those three should account for its `ThroughVm` number; where +// they do not, the gap is size-dependent copying, which the swept cases (`Sha512Half`, +// `UpdateData`) expose. + +void +guestInstruction(benchmark::State& state) +{ + static constexpr std::string_view kBody = "(i32.add (local.get $r) (i32.const 1))"; + // Empty import name: this case prices no host function, so there is nothing to look a + // declaration up for and it reports no `suggested_gas`. + benchmarkThroughVm(state, "", "", "", kBody, [] { return benchHost(); }); +} +BENCHMARK(guestInstruction)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/README.md b/src/tests/libxrpl/tx/wasm/README.md index c652b624b9..7be25e539d 100644 --- a/src/tests/libxrpl/tx/wasm/README.md +++ b/src/tests/libxrpl/tx/wasm/README.md @@ -18,26 +18,217 @@ the breadth it might seem to be missing lives in a sibling layer. This file is t both forward to the shared `runWat(HostFunctions&, ...)` in `WasmRun.h`, differing only in the host they inject. -## Why `e2e/` is a thin integration smoke (and not a per-function tour) +## `*.bench.cpp` — gas calibration -The old Beast suite (`src/test/app/Wasm_test.cpp`, now retired) had guest programs that toured -_many_ host functions in one run (`all_host_functions`, `codecov_tests`). The new design keeps -that breadth but **decomposes** it: +Interleaved with the tests are `*.bench.cpp` files. They are **not tests**: nothing asserts, +and a number moving is not a build failure. They answer the pricing question the tests cannot — +whether each `#[gas = N]` in `crates/xrpl-host-functions/src/lib.rs` matches what the function +actually costs. -- **Per-function breadth** — "does host fn X return the right value / marshal correctly?" — lives - in `host_functions/` (answers) and `host_calls/` (marshalling), one case per function. -- **Integration** — "do the layers _agree_ when wired together?" — is what `e2e/` uniquely adds. - That integration machinery (VM → `HostContext` → impl → ledger) is **shared** across host - functions; what varies per function (field code, byte layout) is already pinned by - `host_calls`/`host_functions`. So a few representative **shapes** exercise every integration - path: a scalar/header read, a ledger-object field read, a transaction read, a write, and one - multi-call **tour** (`HostFunctionTourE2e`) in the recognizable shape of the old - `all_host_functions` guest. +**One `.bench.cpp` per host function, named after its test** — `EscrowKeylet.cpp` and +`EscrowKeylet.bench.cpp` sit next to each other, 61 of each. That is a checklist rather than a +judgment call: adding a host function means adding two files, and nobody has to decide where a +benchmark belongs. Shared ledger setup lives in `BenchFixtures.h` (one ledger, funded once, for +the whole binary) so each file holds only the call it measures. -Testing all ~40 host functions e2e would re-drive the same shared machinery for little added -signal, at heavy per-test ledger-setup cost. The residual risk — a bug that manifests _only_ -through the full stack in a way unique to one function — is small because the machinery is -shared; add a targeted e2e for any function where that risk is real. +They build into a **separate executable** (`xrpl.bench.wasm`), and `xrpl_tests` filters +`*.bench.cpp` out of its source globs, so benchmark runtime never lands on the `ctest` path. + +### Running them + +The executable lands in the **build root**, beside `xrpl_tests`: + +```bash +# configure with -o benchmark=True (the conan default), then: +cmake --build build --target xrpl.bench.wasm +./build/xrpl.bench.wasm # everything (~2 min) +./build/xrpl.bench.wasm --benchmark_filter=sha512Half +./build/xrpl.bench.wasm --benchmark_format=json >gas.json +``` + +**Build Release first.** A Debug build inflates the crossing (templates and `std::expected`, +none of it inlined) far more than it inflates the impls, so Debug overstates what leaving the +guest costs. Google Benchmark prints a warning when it detects this. Ratios between `Impl` +cases survive Debug reasonably; absolute `implied_gas` does not. + +On Linux, Google Benchmark is built against libpfm (`enable_libpfm` in `conanfile.py`), so +hardware counters are available as a cross-check on the timing: + +```bash +./xrpl.bench.wasm --benchmark_perf_counters=INSTRUCTIONS,CYCLES +``` + +### Reading the output + +Gas _is_ wasmi fuel — `set_fuel(gas)` meters guest instructions and host charges from one pool — +so a host call's price is answerable as a **ratio**: how many guest instructions' worth of work +is it? That is machine-independent, which matters because a consensus rule cannot be derived +from one laptop's nanoseconds. + +| Counter | Meaning | +| --------------- | -------------------------------------------------------------------------------------------- | +| `suggested_gas` | **the answer** — what this function should be priced at | +| `declared_gas` | what `lib.rs` says today | +| `price_ratio` | `declared / suggested`. **1.0 is correct; below 1 is underpriced** | +| `implied_gas` | the raw measurement, before the crossing is added back | +| `charged_gas` | what the engine actually billed (`EscrowResult::cost`); confirms the right call was measured | +| `ns_per_call` | raw wall time, for debugging a suspicious ratio | +| `perf_counters` | 1 when libpfm is available | + +`declared_gas` is read from the declaration through the `wasm_testkit` bridge +(`declared_gas(wasm_name)`), not transcribed into C++ — 61 copied constants would drift from +`lib.rs` the first time a price changed, and drift _silently_, because a benchmark has nothing +to fail. + +`price_ratio` is what you sort by. **Below 1 is the direction that matters**: an underpriced call +is one a contract can buy too cheaply, which is a denial-of-service vector rather than a rounding +error. Above 1 the table merely overcharges. + +### How `suggested_gas` is measured + +Gas is not a unit of time, so a wall-clock number cannot be a gas number. The bridge between them +is that **gas is wasmi fuel** — `set_fuel(gas)` meters guest instructions and host charges from +one pool — so one unit of gas is, by construction, about one guest instruction. That turns the +question into a ratio: _how many guest instructions' worth of work is this host call?_ Everything +below exists to answer that without any hard-coded constant. + +Four steps, each a subtraction, all in `WasmBench.h`. + +**1. `secondsPerGas()` — what one unit of gas costs on this machine.** +Assemble two modules that differ only in a loop bound: one runs a trivial `i32.add` body +`kCallsPerRun` times, the other zero times. Run both, and take + +``` +secondsPerGas = (time_busy − time_idle) / (fuel_busy − fuel_idle) +``` + +Both numerator terms include module compilation, instantiation and process noise; both +denominator terms include the engine's fixed overhead. Subtracting cancels all of it, leaving +seconds per unit of fuel. Taken as the **minimum over 32 pairs** (after 8 warm-up pairs), because +the fastest run is the one least disturbed by the scheduler. Cached — it describes the machine, +not the case. + +**2. `secondsPerCall` — the isolated cost of one host call.** +The same subtraction, one level up. A `ThroughVm` case runs a contract making N host calls and a +**byte-identical** one making none, then reports `(t_loaded − t_baseline) / N` _per iteration_, so +Google Benchmark's variance statistics describe the host call rather than the run containing it. +An `Impl` case times `kCallsPerRun` direct calls and divides, spreading the clock read over +enough work that it does not distort a cheap call. + +**3. `implied_gas` — the measurement, in gas.** + +``` +implied_gas = secondsPerCall / secondsPerGas +``` + +Machine-independent: both terms scale with the box, so the ratio does not. + +**4. `crossingFloorGas()` — the toll every call pays.** +Measured once, from `ldgr_index` — the cheapest host function there is, taking no input and +answering from a header already in hand, so almost nothing remains after subtracting it away: + +``` +crossing_floor = (secondsPerCall_ThroughVm − secondsPerCall_Impl) / secondsPerGas +``` + +That is region decode, bounds checks and the cxx hop, and nothing else. + +**Putting it together:** + +``` +suggested_gas = implied_gas # ThroughVm — the guest already paid the crossing +suggested_gas = implied_gas + crossing_floor # Impl — a guest cannot call without paying it +price_ratio = declared_gas / suggested_gas +``` + +**Why you can trust it measured the right thing.** `charged_gas` comes from the engine's own fuel +meter (`EscrowResult::cost`), independently of every timing above. On a `ThroughVm` case it should +equal the declared gas plus the fuel the guest itself burns — the loop body (13, which +`GuestInstruction` reports on its own) plus the `i32.const`s pushing the call's arguments. So +`escrow_id` reports `charged_gas ≈ 367` against a declared 350: 13 for the loop, 4 for its six +argument constants. When that arithmetic does not line up, the case is measuring something other +than the call it names. `GuestInstruction` in +`Crossing.bench.cpp` is the same check applied to step 1: its `implied_gas` and `charged_gas` are +two independent measurements of the same quantity and should agree closely. + +**Two limitations, both real.** + +- `suggested_gas` for an `Impl`-only case is a **lower bound**. The crossing floor is measured on a + call with no input, so a function that moves bytes pays more than the floor. The swept cases + (`Sha512Half`, `UpdateData`) measure that per-byte term where it matters. +- A Debug build inflates the crossing far more than the impls, so absolute values are not usable + there. **Ratios between `Impl` cases survive Debug; `suggested_gas` does not.** + +### The two case kinds, and why the subtraction is the point + +Every function has an `Impl` case; the distinct crossing shapes also have a `ThroughVm` case. + +- **`Impl`** — the host method called directly. No guest, no VM, no marshalling: the computation alone. +- **`ThroughVm`** — the same call made by a real WAT contract through the real VM, against a real + ledger. Measured as the difference between a contract making N host calls and a **byte-identical** + one making none, so compilation, instantiation and the guest's own loop cancel out. + +`ThroughVm − Impl` is the **crossing**: region decode, bounds checks, memory copies, the cxx hop. +`Crossing.bench.cpp` brackets its floor with the cheapest possible host call, and the size-swept +cases (`Sha512Half`, `UpdateData`) expose its per-byte term. + +`ThroughVm` cases are deliberately **one per crossing shape, not one per function** — the same +argument as the e2e rule above. What the crossing costs depends on a call's shape, not on which +function makes it, so a `float_sub` ThroughVm would only re-measure `float_add`'s. + +### Gotchas, all of which have already cost someone an afternoon + +- **The wasm ABI is not the trait's argument order.** `float_add(x, y, mode, out)` in Rust is + `(x_ptr, x_len, y_ptr, y_len, out_ptr, out_len, mode)` on the wire — scalars move _after_ the + output region. Check `register.rs`, not `lib.rs`, when writing WAT. +- **A soft host error still "succeeds".** The run completes and gas is charged _before_ the body, + so a wrong-argument case reports a plausible, confidently wrong number — it measures the + rejection path. The harness guards this by requiring the contract's result to be `>= 0`. The + tell is a `ThroughVm` case coming out _faster_ than its `Impl` pair. +- **A host serves exactly one run** (`checkSelf` assert in `WasmVM.cpp`), so a benchmark builds a + fresh host per run and cannot pre-cache a slot. +- **`MAX_FIELD_BYTES` is 1024** — no value crosses the boundary in either direction above 1 KiB, + so size sweeps stop there. +- Cases pin `->Iterations(...)`: with `UseManualTime`, Google Benchmark's automatic sizing reads + only the tiny reported residue and would ask for millions of iterations. + +## What `e2e/` covers — the rule + +**`e2e/` covers every marshalling shape and every cross-call convention exactly once. It does +not cover every function.** That is a completeness claim on the axis e2e can uniquely test, not +a sample. + +The reasoning: `host_calls` pins what the bridge _asks_ a host and what it does with a _canned_ +answer; `host_functions` pins what the real impl _answers_. The C++ type system guarantees the +two agree on signatures — the real impl implements the same interface the mock does. What +nothing guarantees is that they agree on **conventions**: units, endianness, buffer layout, the +meaning of a wire format. A mocked bridge test and a direct impl test can both pass while +meaning different things by "a four-byte sequence number", because in neither test does a real +guest write bytes that a real host reads. That is precisely the `seq`-as-little-endian-region +bug: every internal test passed, and it was caught by cross-checking the guest SDK. + +Convention mismatch is a property of the **shape** of a call, not of the function making it. All +19 keylet functions share one shape; a 19th keylet e2e proves nothing the 1st did not. So the +inventory below is indexed by shape, and it is meant to be exhaustive: + +| Shape / convention | Covered by | Why it is its own row | +| ----------------------------------------- | -------------------------- | -------------------------------------------------------- | +| no-input scalar getter | `LedgerSqnE2e` | header read; the minimal call | +| field code in, bytes out (ledger object) | `CurrentLedgerObjFieldE2e` | `SField` translation over a real object | +| field code in, bytes out (transaction) | `TxFieldE2e` | a different source than a ledger object | +| region in, bytes out + `u32` region | `CacheLedgerObjE2e` | the 4-byte little-endian region convention | +| slot in, bytes out — **cross-call state** | `CacheLedgerObjE2e` | the slot table is the only host state outliving one call | +| locator (path of i32 steps) | `TxNestedFieldE2e` | a wire format the guest writes and the host walks | +| **two** output regions | `FloatToMantExpE2e` | two bounds checks, two writes, an ordering between them | +| write / mutation | `SetDataE2e` | the one thing a contract changes | +| **error** path from a real impl | `HostErrorE2e` | soft code produced by a real failure, not a staged one | +| realistic multi-call contract | `HostFunctionTourE2e` | the old `all_host_functions` tour shape, as one test | + +Adding a function does not require a new e2e case — unless it introduces a shape or a convention +not in that table, in which case it does. Per-function breadth (does fn X return the right +value, does it marshal correctly) lives in `host_functions/` and `host_calls/`, one case each, +and re-driving that shared machinery 61 times e2e would cost heavy per-test ledger setup for no +added signal. The **guest SDK** (`xrpl-std` / `xrpl-escrow`, from the external `xrpl-wasm-stdlib` repo) is intentionally **not** exercised here: that is the SDK repo's own test suite. WAT tests the host diff --git a/src/tests/libxrpl/tx/wasm/WasmBench.h b/src/tests/libxrpl/tx/wasm/WasmBench.h new file mode 100644 index 0000000000..7c2d0f64fd --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/WasmBench.h @@ -0,0 +1,544 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// Gas calibration for the wasm host functions. +// +// Every `#[gas = N]` in `crates/xrpl-host-functions/src/lib.rs` is a promise about how +// much work a host call does relative to a guest instruction: the engine meters both from +// one pool (`set_fuel(gas)` in `crates/xrpl-wasm-vm/src/vm.rs`), so one unit of gas *is* +// roughly one wasm instruction. That makes the calibration question answerable and, more +// importantly, machine-independent: not "how many nanoseconds does `sha512_half` take" +// (a property of the box) but "how many guest instructions' worth of work is it" (a +// property of the code). Only the second can be written into a consensus rule. +// +// Two costs hide inside one host call, and pricing needs them apart: +// +// * the *impl* — what `WasmHostFunctionsImpl` computes. Measured by calling the host +// method directly, with no VM in the picture (`benchmarkImpl`). +// * the *crossing* — region decode, bounds checks, memory copies, the cxx bridge hop. +// Paid on every call regardless of what the call does (`benchmarkThroughVm`). +// +// So the whole design here is a subtraction, and it appears twice: +// +// 1. Inside a VM benchmark, between a contract that makes N host calls and an otherwise +// byte-identical contract that makes none. That removes module compilation, +// instantiation and the guest's own loop from the number. The subtraction happens +// per iteration, so Google Benchmark's variance statistics describe the isolated +// host call rather than the run that contains it. +// 2. Between the `ThroughVm` and `Impl` cases for the same function, read off the +// report afterwards. That difference is the crossing, which should come out roughly +// constant across functions plus a term in the byte count. Functions whose cost +// grows with input size are registered over a `Range` so that term is visible. +// +// The reported counters are the point; wall time is only the raw material: +// +// `suggested_gas` **the answer** — what this function should be priced at. For a +// `ThroughVm` case that is what was measured; for an `Impl` case the +// crossing is added back, since a guest cannot call without paying it. +// `declared_gas` what `lib.rs` currently says, read through the `wasm_testkit` bridge so +// it can never drift from the declaration. +// `price_ratio` `declared / suggested`. 1.0 is correct. Above 1 the table overcharges; +// **below 1 it undercharges**, which is the direction that matters — an +// underpriced call is one a contract can buy too cheaply. +// `implied_gas` the raw measurement, before the crossing is added back. +// `charged_gas` what the engine actually charged (from `EscrowResult::cost`), on VM +// cases. Should track the declaration, and is how the harness shows it is +// measuring the call it thinks it is. +// `ns_per_call` the underlying wall time, for debugging a suspicious ratio. +// +// Sort a report by `price_ratio` and the mispriced functions come to the top: +// ./xrpl.bench.wasm --benchmark_format=csv | sort -t, -k + +// +// One caveat on `suggested_gas` for `Impl`-only cases: the crossing added back is the *floor*, +// measured on a call with no input. A function that moves bytes pays more than the floor, so +// its suggestion is a lower bound. The swept cases (`Sha512Half`, `UpdateData`) measure that +// per-byte term where it matters. +// +// Run it: +// ./xrpl.bench.wasm --benchmark_filter='Sha512Half' +// ./xrpl.bench.wasm --benchmark_format=json > gas.json +// and on Linux, where Google Benchmark is built against libpfm (see `enable_libpfm` in +// conanfile.py), hardware counters are available as a cross-check on the timing: +// ./xrpl.bench.wasm --benchmark_perf_counters=INSTRUCTIONS,CYCLES +// +// Build Release before believing anything. A Debug build inflates the crossing far more +// than it inflates the impls — the marshalling is templates and `std::expected`, none of it +// inlined — so Debug numbers overstate what leaving the guest costs and understate every +// function's own work relative to it. Google Benchmark prints a warning when it detects +// this; do not read past it. +// +// These are *calibration* runs, not tests: nothing here asserts, and a number moving is +// not a build failure. They live beside the tests for the same functions because the two +// share a fixture and should move together, but they build into their own executable +// (`xrpl.bench.wasm`) so they never run under ctest. + +namespace xrpl::test::bench { + +// Enough gas that a thousand-call benchmark loop never ends early; a benchmark measures +// work, so running out of budget would silently measure something shorter instead. +inline constexpr std::int64_t kBenchGas = 2'000'000'000; + +// How many host calls a benchmarked contract makes per run. Large enough that the +// per-call cost dominates the residue left by the baseline subtraction, small enough that +// one run stays in the microsecond range. +inline constexpr int kCallsPerRun = 1000; + +// How many timed iterations each case runs. Pinned rather than left to Google Benchmark's +// automatic sizing, which cannot work here: a case reports the subtraction's residue — tens +// of nanoseconds — while the iteration that produced it ran two whole contracts, module +// compilation included, and cost milliseconds. Automatic sizing sees only the reported time, +// so it would ask for millions of iterations to accumulate its default `min_time` and the +// case would never finish. Every registration therefore ends +// `->UseManualTime()->Iterations(kBenchIterations)`. +inline constexpr int kBenchIterations = 50; + +// Every run gets this much guest<->host copying before `charge_transfer` starts refusing +// calls (`TRANSFER_LIMIT_BYTES` in `crates/xrpl-wasm-vm/src/vm.rs`). It is a per-run budget, +// so it resets between the runs a benchmark makes — but a single run of `kCallsPerRun` calls +// moving a kilobyte each would exhaust it partway through and spend the rest of the loop +// measuring the refusal path instead of the host function. +inline constexpr std::int64_t kTransferLimitBytes = 1 << 20; + +// How many calls a run can afford at `bytesPerCall`, staying clear of the transfer budget. +// +// Halved because most functions move bytes in *both* directions — an input region read plus +// an output region written — and the budget counts both. A size-swept case passes this as +// its call count so the large end of the range does not silently turn into an error +// benchmark; per-call numbers stay comparable across counts, which is what the report shows. +inline int +callsWithinTransferBudget(std::int64_t bytesPerCall) +{ + if (bytesPerCall <= 0) + return kCallsPerRun; + auto const affordable = (kTransferLimitBytes / 2) / bytesPerCall; + return static_cast(std::clamp(affordable, 16, kCallsPerRun)); +} + +// True when Google Benchmark was built with libpfm and `--benchmark_perf_counters` will +// work. Reported as a counter so a JSON report records which mode produced it. +inline constexpr bool kPerfCountersAvailable = +#ifdef XRPL_BENCH_PERF_COUNTERS + true; +#else + false; +#endif + +// The test fixtures these benchmarks measure against derive from `testing::Test`, whose pure +// virtual `TestBody` makes them abstract. A benchmark wants a fixture's ledger, host and +// setup helpers, not GTest's lifecycle, so supply the one missing member and nothing else. +// Nothing here registers or runs a test. +// +// Templated so a case can reuse whichever fixture its test uses — `Bench` for the +// NFT benchmarks, `Bench` for the float ones — instead of duplicating that setup. +template +struct Bench : Fixture +{ + void + TestBody() override + { + } +}; + +using BenchFixture = Bench; + +// One run of a contract: how long it took, and what the engine charged it. +struct Timing +{ + double seconds; + std::int64_t gas; +}; + +// A `(data ...)` segment placing `bytes` at `offset` in the guest's memory, so a case's +// input is in place before the timed loop starts and the loop measures the host call rather +// than the guest arranging its arguments. See `watEscaped` in WasmRun.h for why zeroed +// memory will not do. +inline std::string +dataSegment(int offset, std::span bytes) +{ + return std::string{" (data (i32.const "} + std::to_string(offset) + ") \"" + + watEscaped(bytes) + "\")\n"; +} + +inline std::string +dataSegment(int offset, Bytes const& bytes) +{ + return dataSegment(offset, std::span{bytes.data(), bytes.size()}); +} + +// A contract that runs `body` `count` times and returns the last result. +// +// `count` is the *only* thing that varies between a loaded module and its baseline: the +// imports, the data segments, the function bodies and the module's size are identical, so +// compiling and instantiating them costs the same and cancels out of the subtraction. At +// `count == 0` the loop is entered and immediately exited, so even the branch is paid by +// both. +// +// `data` holds any `dataSegment` calls the case needs; it goes after the memory +// declaration that gives those segments something to write into. +inline std::string +makeLoopWat(std::string_view imports, std::string_view data, std::string_view body, int count) +{ + return std::string{"(module\n"} + std::string{imports} + + R"wat( + (memory (export "memory") 1) +)wat" + std::string{data} + + R"wat( + (func (export "escrow_finish") (result i32) + (local $i i32) + (local $r i32) + (local.set $i (i32.const )wat" + + std::to_string(count) + R"wat()) + (block $done + (loop $again + (br_if $done (i32.eqz (local.get $i))) + (local.set $r )wat" + + std::string{body} + R"wat() + (local.set $i (i32.sub (local.get $i) (i32.const 1))) + (br $again))) + (local.get $r))) +)wat"; +} + +// Run pre-assembled `wasm` once through the real VM, reporting wall time and gas. +// +// Assembly (WAT text -> bytes) is deliberately outside the timed region: it is a +// test-only convenience from the `wasm_testkit` crate, not something a validator ever +// does. Compilation *is* inside, because a validator does pay it — but it is identical +// between a module and its baseline, so the subtraction removes it. +inline Timing +timeRun(HostFunctions& host, Bytes const& wasm) +{ + auto const start = std::chrono::steady_clock::now(); + auto outcome = runEscrowWasm(wasm, host, kBenchGas); + auto const elapsed = std::chrono::steady_clock::now() - start; + + benchmark::DoNotOptimize(outcome); + return { + .seconds = std::chrono::duration(elapsed).count(), + .gas = outcome.has_value() ? outcome->cost : std::int64_t{0}}; +} + +// Seconds of wall time one unit of gas buys on this machine. +// +// This is the conversion that makes every other number here machine-independent. It is +// measured, not assumed: a pure-wasm loop (no host calls, no ledger) run at two different +// iteration counts, with the difference in time divided by the difference in fuel. Taking +// a difference rather than a single measurement removes compilation and startup, which +// would otherwise inflate the apparent cost of a guest instruction and make every host +// function look cheap by comparison. +// +// Computed once per process and cached: it describes the machine, not the case. +inline double +secondsPerGas() +{ + static double const kValue = [] { + // A couple of guest instructions per iteration, no memory traffic, nothing the + // engine can fold away. + static constexpr std::string_view kBody = "(i32.add (local.get $r) (i32.const 1))"; + auto const busy = assembleWat(makeLoopWat("", "", kBody, kCallsPerRun)); + auto const idle = assembleWat(makeLoopWat("", "", kBody, 0)); + + BenchFixture fixture; + + // Warm the instruction cache and the allocator before the pairs that count, so + // the first-run penalty does not land on one side of the subtraction. + for (int i = 0; i < 8; ++i) + { + timeRun(*fixture.makeHost(), busy); + timeRun(*fixture.makeHost(), idle); + } + + // Best-of over several pairs: the minimum is the run least disturbed by the + // scheduler, which is the honest floor for what this machine can do. + auto best = std::numeric_limits::max(); + auto gasDelta = std::int64_t{1}; + for (int i = 0; i < 32; ++i) + { + auto hotHost = fixture.makeHost(); + auto const hot = timeRun(*hotHost, busy); + auto coldHost = fixture.makeHost(); + auto const cold = timeRun(*coldHost, idle); + auto const delta = hot.seconds - cold.seconds; + if (delta > 0.0 && delta < best) + { + best = delta; + gasDelta = std::max(std::int64_t{1}, hot.gas - cold.gas); + } + } + return best == std::numeric_limits::max() ? 0.0 + : best / static_cast(gasDelta); + }(); + return kValue; +} + +// What the gas table says a host function costs, by its guest import name. +// +// Read from the declaration through the `wasm_testkit` bridge rather than transcribed into +// C++: 61 copied constants would drift from `crates/xrpl-host-functions/src/lib.rs` the first +// time a price changed, and drift *silently*, because a benchmark has nothing to fail. +inline double +declaredGas(std::string_view wasmName) +{ + return static_cast( + rs::wasm_testkit::declared_gas(rust::Str{wasmName.data(), wasmName.size()})); +} + +// The gas a host call costs before it does anything: region decode, bounds checks, the cxx hop. +// +// Measured once per process the same way `secondsPerGas` is, and from the same pair the suite +// uses as its floor — `ldgr_index` through the VM minus `ldgr_index` called directly. It takes +// no input and answers from a header already in hand, so what remains after the subtraction is +// the crossing and nothing else. +// +// This is what makes a *suggested* price possible for a function that has only an `Impl` case: +// the impl measures the work, and this measures the toll every call pays on top of it. +inline double +crossingFloorGas() +{ + static double const kValue = [] { + static constexpr std::string_view kImport = + R"( (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) +)"; + static constexpr std::string_view kBody = "(call $ldgr_index (i32.const 0) (i32.const 4))"; + + auto const loaded = assembleWat(makeLoopWat(kImport, "", kBody, kCallsPerRun)); + auto const baseline = assembleWat(makeLoopWat(kImport, "", kBody, 0)); + + BenchFixture fixture; + + auto best = std::numeric_limits::max(); + for (int i = 0; i < 16; ++i) + { + auto hotHost = fixture.makeHost(); + auto const hot = timeRun(*hotHost, loaded); + auto coldHost = fixture.makeHost(); + auto const cold = timeRun(*coldHost, baseline); + + auto const perCall = (hot.seconds - cold.seconds) / kCallsPerRun; + if (perCall > 0.0 && perCall < best) + best = perCall; + } + if (best == std::numeric_limits::max()) + return 0.0; + + // The impl side is the same call without the VM. Subtracting it leaves the crossing. + auto implSeconds = std::numeric_limits::max(); + auto host = fixture.makeHost(); + for (int i = 0; i < 16; ++i) + { + auto const start = std::chrono::steady_clock::now(); + for (int c = 0; c < kCallsPerRun; ++c) + { + auto result = host->getLedgerSqn(); + benchmark::DoNotOptimize(result); + } + auto const elapsed = std::chrono::steady_clock::now() - start; + implSeconds = std::min( + implSeconds, std::chrono::duration(elapsed).count() / kCallsPerRun); + } + + auto const perGas = secondsPerGas(); + return perGas > 0.0 ? std::max(0.0, best - implSeconds) / perGas : 0.0; + }(); + return kValue; +} + +// Attach the calibration counters to a finished case. +// +// `secondsPerCall` is the isolated per-call cost. `chargedGas` is what the engine billed per +// call, or 0 for a direct-impl case where no VM was involved. `wasmName` names the host +// function so its declared price can be looked up; empty for the harness's own reference cases, +// which price nothing. +// +// `suggested_gas` is the headline: what the function *should* cost, in the same units as the +// declaration. For a `ThroughVm` case that is simply what was measured, since the guest already +// paid the crossing. For an `Impl` case the crossing has to be added back, because a guest +// cannot make the call without it. +inline void +report( + benchmark::State& state, + double secondsPerCall, + double chargedGas, + std::string_view wasmName, + bool throughVm) +{ + auto const perGas = secondsPerGas(); + auto const implied = perGas > 0.0 ? secondsPerCall / perGas : 0.0; + auto const suggested = throughVm ? implied : implied + crossingFloorGas(); + + state.counters["implied_gas"] = implied; + state.counters["ns_per_call"] = secondsPerCall * 1e9; + state.counters["charged_gas"] = chargedGas; + state.counters["perf_counters"] = kPerfCountersAvailable ? 1 : 0; + + if (wasmName.empty()) + return; + + auto const declared = declaredGas(wasmName); + state.counters["declared_gas"] = declared; + state.counters["suggested_gas"] = suggested; + // Above 1: the table charges more than the work costs. Below 1: underpriced, which is the + // direction that matters — an underpriced call is one a contract can buy too cheaply. + state.counters["price_ratio"] = suggested > 0.0 ? declared / suggested : 0.0; +} + +// Measure a host function *through the whole stack* — guest, VM, marshalling, real impl, +// real ledger — with everything but the host calls subtracted away. +// +// `wasmName` is the guest import name, used to look up the declared price. `imports` declares +// the host function and `data` seeds any input bytes it reads; +// `body` is the call expression, which must leave one i32 on the stack. `setUp` prepares +// the ledger and returns the host to run against, so a case can fund accounts or create +// the object it reads. +// +// `calls` is how many host calls one run makes; a size-swept case should pass +// `callsWithinTransferBudget(bytesPerCall)` so the large end of its range stays inside the +// engine's copying budget. The reported numbers are per call either way. +// +// Register with `->UseManualTime()`: the reported time is the subtraction's result, not +// the wall time of the runs that produced it. +template +void +benchmarkThroughVm( + benchmark::State& state, + std::string_view wasmName, + std::string_view imports, + std::string_view data, + std::string_view body, + SetUp&& setUp, + int calls = kCallsPerRun) +{ + auto const loaded = assembleWat(makeLoopWat(imports, data, body, calls)); + auto const baseline = assembleWat(makeLoopWat(imports, data, body, 0)); + + // A host serves exactly one run: it caches the current ledger object, the slot table and + // the contract's data for that run's length, and `runEscrowWasm` asserts it was handed a + // clean one (see `checkSelf` in WasmVM.cpp). So every run below builds its own. That + // costs the measurement nothing — `timeRun` starts its clock after the host exists — + // and it is why `setUp` is a factory rather than a host. + auto probe = setUp(); + + // Confirm the contract actually succeeds before measuring it — and note that "the run + // succeeded" is not enough to establish that. + // + // A soft host error is an *answer*, not a fault: the engine hands the guest a negative + // code and the run completes normally, `EscrowResult` and all. Gas is charged before the + // body too (`charged` in crates/xrpl-wasm-vm/src/abi.rs), so `charged_gas` looks correct + // for a call that did nothing. A case whose arguments are subtly wrong would therefore + // report a plausible, confidently wrong number — measuring the rejection path, which is + // much cheaper than the work. The tell is a `ThroughVm` case coming out faster than its + // `Impl` pair, which is impossible when one contains the other. + // + // So require both: the run completed, and the contract's last host call returned a + // non-negative result. Every body here leaves that result in `$r`, which the module + // returns. + auto const check = runEscrowWasm(loaded, *probe, kBenchGas); + if (!check.has_value()) + { + state.SkipWithError("the benchmarked contract did not run to completion"); + return; + } + if (check->result < 0) + { + state.SkipWithError( + "the benchmarked host call returned error code " + std::to_string(check->result) + + "; the case would be measuring the rejection path, not the work"); + return; + } + + auto totalSeconds = 0.0; + auto totalGas = 0.0; + auto rounds = std::int64_t{0}; + for (auto _ : state) + { + auto hotHost = setUp(); + auto const hot = timeRun(*hotHost, loaded); + auto coldHost = setUp(); + auto const cold = timeRun(*coldHost, baseline); + + // Clamped at zero: on a noisy machine a single pair can invert, and a negative + // iteration time would make Google Benchmark's statistics meaningless. + auto const perCall = std::max(0.0, hot.seconds - cold.seconds) / calls; + state.SetIterationTime(perCall); + + totalSeconds += perCall; + totalGas += static_cast(hot.gas - cold.gas) / calls; + ++rounds; + } + + if (rounds > 0) + report(state, totalSeconds / rounds, totalGas / rounds, wasmName, true); +} + +// Measure a host function's *impl alone* — the computation, with no guest, no VM and no +// marshalling. Paired with the `ThroughVm` case for the same function, the difference is +// what crossing the guest/host boundary costs. +// +// `wasmName` is the guest import name, used to look up the declared price. `call` invokes the +// host method and returns its result; `setUp` builds the ledger and +// host once, outside the timed region, so fixture setup is not measured. The inner loop +// runs `kCallsPerRun` calls per timed iteration, matching the VM case's shape and +// amortizing the clock read over enough work that it does not dominate a cheap impl. +// +// Register with `->UseManualTime()`. +template +void +benchmarkImpl(benchmark::State& state, std::string_view wasmName, SetUp&& setUp, Call&& call) +{ + auto host = setUp(); + + auto totalSeconds = 0.0; + auto rounds = std::int64_t{0}; + for (auto _ : state) + { + auto const start = std::chrono::steady_clock::now(); + for (int i = 0; i < kCallsPerRun; ++i) + { + // `trace` is the one host function that answers nothing, so there is no result + // to hold onto; `ClobberMemory` stands in for `DoNotOptimize` to keep the call + // from being elided. + if constexpr (std::is_void_v) + { + call(*host); + benchmark::ClobberMemory(); + } + else + { + auto result = call(*host); + benchmark::DoNotOptimize(result); + } + } + auto const elapsed = std::chrono::steady_clock::now() - start; + + auto const perCall = std::chrono::duration(elapsed).count() / kCallsPerRun; + state.SetIterationTime(perCall); + + totalSeconds += perCall; + ++rounds; + } + + // No VM ran, so nothing was charged — and the crossing this case leaves out is added back + // into `suggested_gas`, because a guest cannot make the call without paying it. + if (rounds > 0) + report(state, totalSeconds / rounds, 0.0, wasmName, false); +} + +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/WasmRun.h b/src/tests/libxrpl/tx/wasm/WasmRun.h index e5f9107e99..ac016afe55 100644 --- a/src/tests/libxrpl/tx/wasm/WasmRun.h +++ b/src/tests/libxrpl/tx/wasm/WasmRun.h @@ -9,6 +9,8 @@ #include #include +#include +#include #include namespace xrpl::test { @@ -27,6 +29,34 @@ assembleWat(std::string_view wat) return Bytes{wasm.begin(), wasm.end()}; } +// `bytes` as the escape sequence a WAT string literal wants (`\aa\bb...`), for seeding a +// contract's memory through a `(data ...)` segment. +// +// Guest memory starts zeroed, and zeros are not a usable input to most host functions: an +// all-zero account id is `InvalidAccount`, an all-zero float is non-canonical. A contract +// that needs real bytes to work on gets them here, once at instantiation, rather than +// building them out of `i32.store` instructions. +inline std::string +watEscaped(std::span bytes) +{ + static constexpr char kHex[] = "0123456789abcdef"; + auto out = std::string{}; + out.reserve(bytes.size() * 3); + for (auto const byte : bytes) + { + out += '\\'; + out += kHex[byte >> 4]; + out += kHex[byte & 0x0F]; + } + return out; +} + +inline std::string +watEscaped(Bytes const& bytes) +{ + return watEscaped(std::span{bytes.data(), bytes.size()}); +} + // Assemble and run `wat`'s `entryPoint` through the real VM, servicing host calls through // `host` — a mock (`MockVmTest`) or the real impl over a ledger (`RealVmTest`). The one // host-agnostic harness both fixtures inject their host into. diff --git a/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp b/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp new file mode 100644 index 0000000000..f876a8d25a --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp @@ -0,0 +1,74 @@ +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::test { + +// The keylet -> cache -> read round trip: the only place a contract's host calls depend on +// each other. +// +// Every other e2e case here is one call in isolation. This one is three, and each consumes +// what the last produced: `accountroot_id` computes a key into guest memory, `cache_le` +// hands those same bytes back to the host and answers with a slot number, and `le_field` +// uses that slot to read the object. The slot table is the one piece of host state that +// outlives a single call, so this is the only test at any layer that can catch the two ends +// of that state disagreeing — `host_calls` mocks the host, so its slot numbers are whatever +// the mock was told to return, and `host_functions` calls the impl directly, so its slots +// never cross the guest boundary at all. +// +// It is also the shape that would have caught the `seq`-as-region bug class described in +// ../README.md: a key computed by one call and consumed by another only works if both ends +// agree byte for byte, and here the ledger itself is the judge — a wrong key simply fails +// to find the account. +struct CacheLedgerObjE2e : RealVmTest +{ +}; + +TEST_F(CacheLedgerObjE2e, ContractComputesAKeyCachesTheObjectAndReadsItsField) +{ + auto const owner = fund("owner"); + + // Memory: the 20-byte account at 0, the computed 32-byte keylet at 64, the field bytes + // read back at 128. Regions are disjoint so no call overwrites another's input. + // + // The contract returns a negative host error code the moment any step fails, so a + // failure names the step that broke rather than surfacing as a wrong byte count. + auto const wat = std::string{R"wat( +(module + (import "host_lib" "accountroot_id" (func $accountroot_id (param i32 i32 i32 i32) (result i32))) + (import "host_lib" "cache_le" (func $cache_le (param i32 i32 i32) (result i32))) + (import "host_lib" "le_field" (func $le_field (param i32 i32 i32 i32) (result i32))) + (memory (export "memory") 1) + (data (i32.const 0) ")wat"} + + watEscaped(RealHostFixture::toBytes(owner.id())) + R"wat(") + (func (export "escrow_finish") (result i32) + (local $slot i32) + (local $r i32) + ;; The account's AccountRoot keylet, computed by the host into offset 64. + (local.set $r (call $accountroot_id (i32.const 0) (i32.const 20) (i32.const 64) (i32.const 32))) + (if (i32.lt_s (local.get $r) (i32.const 0)) (then (return (local.get $r)))) + ;; Those same 32 bytes handed straight back: cache the object they name. + (local.set $slot (call $cache_le (i32.const 64) (i32.const 32) (i32.const 0))) + (if (i32.lt_s (local.get $slot) (i32.const 0)) (then (return (local.get $slot)))) + ;; And read a field of it through the slot the host just assigned. + (call $le_field (local.get $slot) (i32.const )wat" + + std::to_string(sfAccount.getCode()) + R"wat() (i32.const 128) (i32.const 32)))) +)wat"; + + auto const outcome = run(wat); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + // 20 bytes: the `sfAccount` the contract read back is the account it started from, so + // the key it computed found the right object. + EXPECT_EQ( + outcome->result, static_cast(RealHostFixture::toBytes(owner.id()).size())); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp b/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp new file mode 100644 index 0000000000..2aebbb93ad --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp @@ -0,0 +1,64 @@ +#include + +#include +#include +#include +#include + +#include +#include + +namespace xrpl::test { + +// The only host function that writes to *two* output regions, and so the only place the +// "one call, one answer" assumption in every other marshalling path is not what happens. +// +// `float_to_mant_exp` splits a float into an eight-byte mantissa and a four-byte exponent, +// each into its own guest buffer, and answers with a status rather than a byte count. Two +// regions means two independent bounds checks, two writes, and an ordering between them — +// none of which the single-output shapes exercise. `host_calls` pins that wiring against a +// mock; this proves the real impl drives it the same way, with the guest reading both +// halves back out of its own memory. +struct FloatToMantExpE2e : RealVmTest +{ +}; + +TEST_F(FloatToMantExpE2e, ContractReadsBothHalvesOfASplitFloat) +{ + // Pi's canonical encoding in, mantissa to offset 64, exponent to offset 128. The + // contract returns the low half of the mantissa so the assertion checks that real bytes + // landed in the guest's buffer, not merely that the call reported success. + auto const wat = std::string{R"wat( +(module + (import "host_lib" "float_to_mant_exp" (func $split (param i32 i32 i32 i32 i32 i32) (result i32))) + (memory (export "memory") 1) + (data (i32.const 0) ")wat"} + + watEscaped(FloatTest::kPi) + R"wat(") + (func (export "escrow_finish") (result i32) + (local $r i32) + (local.set $r (call $split + (i32.const 0) (i32.const 12) + (i32.const 64) (i32.const 8) + (i32.const 128) (i32.const 4))) + (if (i32.lt_s (local.get $r) (i32.const 0)) (then (return (local.get $r)))) + (i32.load (i32.const 64)))) +)wat"; + + auto const outcome = run(wat); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + + // The expected value is derived from the input rather than written out as a literal, + // because the derivation is the interesting part: a float stores its mantissa in the + // first eight bytes **big-endian**, while `float_to_mant_exp` writes it to the guest + // **little-endian**. So the guest's `i32.load` at the start of the mantissa buffer sees + // the *low* 32 bits of a number whose bytes arrived in the opposite order. Getting that + // flip wrong is exactly the convention mismatch this layer exists to catch, and a + // hard-coded constant would hide it. + auto mantissa = std::int64_t{0}; + for (auto i = 0; i < 8; ++i) + mantissa = (mantissa << 8) | FloatTest::kPi[i]; + + EXPECT_EQ(outcome->result, static_cast(mantissa & 0xFFFFFFFF)); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp b/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp new file mode 100644 index 0000000000..6df9842d3c --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp @@ -0,0 +1,55 @@ +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace xrpl::test { + +// The error channel, driven by a real failure rather than a mock's canned one. +// +// Every other e2e case here proves a success path. But a contract spends most of its life +// reacting to codes, and the path a *real* error takes is different from the one a mock +// error takes: the impl returns a `HostFunctionError`, `HostContext` turns it into a wire +// code, and the engine hands that back to the guest as a negative i32 without disturbing the +// run. `host_calls` proves the middle step against a mock that was *told* to fail; nothing +// until now has proved that a real impl's real failure comes out the far end intact. +// +// The distinction matters because the two halves are separately enumerated: a code the impl +// can return but the bridge does not map, or maps to a different number, is invisible to +// both of the other layers. +struct HostErrorE2e : RealVmTest +{ +}; + +TEST_F(HostErrorE2e, ARealHostErrorReachesTheGuestAsItsWireCode) +{ + // The contract runs against an account root, then asks it for `sfMemoData` — a field + // that object does not carry. The impl genuinely fails to find it, so the code the + // guest reads was produced by the real lookup rather than staged. + auto const owner = fund("owner"); + + auto const wat = std::string{R"wat( +(module + (import "host_lib" "home_le_field" (func $home_le_field (param i32 i32 i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (call $home_le_field (i32.const )wat"} + + std::to_string(sfMemoData.getCode()) + R"wat() (i32.const 0) (i32.const 32)))) +)wat"; + + auto const outcome = run(wat, keylet::account(owner.id())); + + // The run itself succeeds: a soft host error is an answer to the contract, not a fault + // in it. Reporting it as a failed run would be the interesting bug here. + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + EXPECT_EQ(outcome->result, static_cast(HostFunctionError::FieldNotFound)); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp b/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp new file mode 100644 index 0000000000..75b1da1b37 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +namespace xrpl::test { + +// The locator convention, end to end. +// +// A nested-field getter reaches its leaf through a *locator*: a path of little-endian i32 +// steps that the guest lays out in its own memory and the host walks. That is a wire format +// the two sides have to agree on byte for byte, and it is exactly the shape of convention +// that hid the `seq`-as-region bug (see ../README.md) — the kind that a mocked bridge test +// and a direct impl test can both pass while disagreeing with each other, because neither +// one ever has a real guest write the bytes that a real host reads. +// +// Here a real guest writes a two-step locator (`sfMemos`, index 0, `sfMemoData`) and the +// real impl walks it over a real transaction. `host_calls` covers the marshalling and +// `host_functions/TxNestedField.cpp` covers the traversal; this is the one that would catch +// them meaning different things by "a path of i32 steps". +struct TxNestedFieldE2e : RealVmTest +{ + // An EscrowFinish carrying a memo, so the locator has a real leaf to reach. + TxAssembler + withMemo(Account const& acct) + { + auto assembler = escrowFinishTx(ledger, acct); + assembler.build = [inner = std::move(assembler.build)](STObject& obj) { + inner(obj); + auto memos = STArray{}; + auto memo = STObject::makeInnerObject(sfMemo); + memo.setFieldVL(sfMemoData, Slice{"hello", 5}); + memos.push_back(std::move(memo)); + obj.setFieldArray(sfMemos, memos); + }; + return assembler; + } +}; + +TEST_F(TxNestedFieldE2e, ContractWalksALocatorToANestedTransactionField) +{ + auto const owner = fund("owner"); + auto assembler = withMemo(owner); + + // The locator is three i32 steps the guest stores itself: the array field, the index + // within it, then the field inside that element. Writing them with `i32.store` rather + // than a data segment is the point — the guest's own little-endian layout is what the + // host has to agree with. + auto const wat = std::string{R"wat( +(module + (import "host_lib" "tx_inner" (func $tx_inner (param i32 i32 i32 i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (i32.store (i32.const 0) (i32.const )wat"} + + std::to_string(sfMemos.getCode()) + R"wat()) + (i32.store (i32.const 4) (i32.const 0)) + (i32.store (i32.const 8) (i32.const )wat" + + std::to_string(sfMemoData.getCode()) + R"wat()) + (call $tx_inner (i32.const 0) (i32.const 12) (i32.const 64) (i32.const 32)))) +)wat"; + + auto const outcome = run(wat, keylet::account(owner.id()), assembler.type, assembler.build); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + // Five bytes: "hello", the memo's data, reached through the locator. + EXPECT_EQ(outcome->result, 5); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp new file mode 100644 index 0000000000..a79062db51 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "accountroot_id"; + +// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type +// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its +// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing +// cost follows a call's shape, not which keylet it computes (see ../README.md). +void +accountKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.accountKeylet(benchAlice().id()); }); +} +BENCHMARK(accountKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp new file mode 100644 index 0000000000..a6cf930b3d --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "amm_id"; + +// Declared 450 — a hundred above the keylet family's flat 350, and the only keylet whose input +// *length* selects between interpretations: 20 bytes is XRP, 24 an MPT, 40 an issue. That +// dispatch is the work the surcharge is paying for, so this case is whether it costs 100. +void +ammKeyletImpl(benchmark::State& state) +{ + auto const usd = Asset{Issue{toCurrency("USD"), benchAlice().id()}}; + auto const xrp = Asset{xrpIssue()}; + + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [&usd, &xrp](auto& host) { return host.ammKeylet(usd, xrp); }); +} +BENCHMARK(ammKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp new file mode 100644 index 0000000000..e6c220fb8c --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp @@ -0,0 +1,25 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "base_fee"; + +// Declared 60. A field of the current fee schedule; like the other header getters it should be +// far cheaper than its price, with the crossing accounting for nearly all of what a guest pays. +void +baseFeeImpl(benchmark::State& state) +{ + benchmarkImpl( + state, kWasmName, [] { return benchHost(); }, [](auto& host) { return host.getBaseFee(); }); +} +BENCHMARK(baseFeeImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp new file mode 100644 index 0000000000..894cd29c91 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp @@ -0,0 +1,40 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "cache_le"; + +// Declared 5000 — seventy times a field read, and the second-most expensive price in the table. +// +// The number is presumably set for a *cold* lookup: find an object in the ledger and pin it to a +// slot. But it is charged per call, and after the first call the view has the object cached, so +// a contract can arrange never to pay the cold cost again. This case measures the warm path. If +// the gap is large, 5000 is wrong in the common case; if it is small, it is wrong in the cold +// one. One number cannot be right for both. +// +// Re-caching the same key into the same slot is idempotent, which is what makes repeating it a +// measurement rather than a slot-table exhaustion test. +void +cacheLedgerObjImpl(benchmark::State& state) +{ + auto const key = keylet::account(benchAlice().id()).key; + + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [&key](auto& host) { return host.cacheLedgerObj(key, 1); }); +} +BENCHMARK(cacheLedgerObjImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp new file mode 100644 index 0000000000..7f4d00e7f9 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "check_id"; + +// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type +// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its +// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing +// cost follows a call's shape, not which keylet it computes (see ../README.md). +void +checkKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.checkKeylet(benchAlice().id(), kBenchSeq); }); +} +BENCHMARK(checkKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp new file mode 100644 index 0000000000..a63a515800 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp @@ -0,0 +1,73 @@ +#include + +#include +#include +#include + +#include +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "check_sig"; + +// Declared 300 — and the one host function with a documented pricing disagreement, which makes it +// the first one worth measuring. +// +// A prior C++ integration priced the same operation at 35000, a factor of over a hundred apart. +// One of those is wrong, and a signature verification underpriced by 100x is the cheapest +// denial-of-service a contract could buy: a secp256k1 verify, among the most expensive things the +// host can be asked to do, for the price of three hundred guest instructions. +// +// The pair settles it. `Impl` is the verification; `ThroughVm` adds the crossing for three input +// regions. If the two come out nearly equal, the cost is all verification and the crossing is +// noise beside it — which is itself the answer. + +constexpr std::string_view kImport = + R"( (import "host_lib" "check_sig" (func $check_sig (param i32 i32 i32 i32 i32 i32) (result i32))) +)"; + +// Message, signature and public key are all variable-length, so each gets a fixed offset with room +// to spare and the lengths come from the data itself. +constexpr int kMessageOffset = 0; +constexpr int kSignatureOffset = 256; +constexpr int kPubkeyOffset = 512; + +void +checkSignatureThroughVm(benchmark::State& state) +{ + auto const& m = benchSignedMessage(); + static auto const kData = dataSegment(kMessageOffset, m.message) + + dataSegment(kSignatureOffset, m.signature) + dataSegment(kPubkeyOffset, m.publicKey); + static auto const kBody = std::string{"(call $check_sig (i32.const "} + + std::to_string(kMessageOffset) + ") (i32.const " + std::to_string(m.message.size()) + + ") (i32.const " + std::to_string(kSignatureOffset) + ") (i32.const " + + std::to_string(m.signature.size()) + ") (i32.const " + std::to_string(kPubkeyOffset) + + ") (i32.const " + std::to_string(m.publicKey.size()) + "))"; + + benchmarkThroughVm(state, kWasmName, kImport, kData, kBody, [] { return benchHost(); }); +} +BENCHMARK(checkSignatureThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +checkSignatureImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { + auto const& m = benchSignedMessage(); + return host.checkSignature( + Slice{m.message.data(), m.message.size()}, + Slice{m.signature.data(), m.signature.size()}, + Slice{m.publicKey.data(), m.publicKey.size()}); + }); +} +BENCHMARK(checkSignatureImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp new file mode 100644 index 0000000000..d0e86ea5c0 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp @@ -0,0 +1,36 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "credential_id"; + +// Declared 350. Subject, issuer, and a variable-length credential type — the only keylet with an +// input whose size the guest chooses, so the only one where a flat price could be wrong for a +// reason other than the hash. Measured here at a typical length. +void +credentialKeyletImpl(benchmark::State& state) +{ + static constexpr auto kType = std::string_view{"termsandconditions"}; + + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { + return host.credentialKeylet( + benchAlice().id(), benchBob().id(), Slice{kType.data(), kType.size()}); + }); +} +BENCHMARK(credentialKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp new file mode 100644 index 0000000000..ad6b05c234 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp @@ -0,0 +1,30 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "home_le_arr_len"; + +// Declared 40. Runs against a signer list rather than an account root, which has no arrays at +// all — a `FieldNotFound` answer would time the rejection instead of the count. +void +currentLedgerObjArrayLenImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchSignerListHost(); }, + [](auto& host) { return host.getCurrentLedgerObjArrayLen(sfSignerEntries); }); +} +BENCHMARK(currentLedgerObjArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp new file mode 100644 index 0000000000..03fa05f0fd --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp @@ -0,0 +1,57 @@ +#include + +#include +#include +#include + +#include +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "home_le_field"; + +// Declared 70, barely above the 60 charged for reading the ledger sequence out of a header already +// in hand. But this one deserializes a field out of an `STObject`, and what that costs depends on +// the object's shape and on whether the read is served from the view's cache. A price set from a +// warm cache is a price an attacker can miss on purpose. +// +// The fixture runs against a real escrow created through the real transactor, so the object read +// is a real one. Note what that means for the number: after the first call the view has the object +// cached, so the thousand calls in a run measure the *warm* path. That is the honest floor, not +// the worst case; a cold-cache figure needs a fixture that evicts between calls, and is worth +// building before this particular 70 is trusted. +// +// This file carries the `ThroughVm` case for the field-code-in, bytes-out shape, shared with +// `tx_field` and `le_field`. + +constexpr std::string_view kImport = + R"( (import "host_lib" "home_le_field" (func $home_le_field (param i32 i32 i32) (result i32))) +)"; + +void +currentLedgerObjFieldThroughVm(benchmark::State& state) +{ + static auto const kBody = std::string{"(call $home_le_field (i32.const "} + + std::to_string(sfAccount.getCode()) + ") (i32.const 0) (i32.const 32))"; + + benchmarkThroughVm(state, kWasmName, kImport, "", kBody, [] { return benchEscrowHost(); }); +} +BENCHMARK(currentLedgerObjFieldThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +currentLedgerObjFieldImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchEscrowHost(); }, + [](auto& host) { return host.getCurrentLedgerObjField(sfAccount); }); +} +BENCHMARK(currentLedgerObjFieldImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp new file mode 100644 index 0000000000..d2ab63f73f --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "home_le_inner_arr_len"; + +// Declared 70. A locator walk to the signer list's entries, then a count. +void +currentLedgerObjNestedArrayLenImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchSignerListHost(); }, + [](auto& host) { + return host.getCurrentLedgerObjNestedArrayLen( + FieldLocator{{sfSignerEntries.getCode()}}); + }); +} +BENCHMARK(currentLedgerObjNestedArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp new file mode 100644 index 0000000000..6f6f702dde --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp @@ -0,0 +1,34 @@ +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "home_le_inner"; + +// Declared 110 against a direct read's 70 — the table's claim that walking a locator costs +// about half a field read again. A one-step locator like this one is the cheapest such walk, +// so it is the best case for that claim. +void +currentLedgerObjNestedFieldImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { + return host.getCurrentLedgerObjNestedField(FieldLocator{{sfAccount.getCode()}}); + }); +} +BENCHMARK(currentLedgerObjNestedFieldImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp new file mode 100644 index 0000000000..19887b789f --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "delegate_id"; + +// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type +// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its +// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing +// cost follows a call's shape, not which keylet it computes (see ../README.md). +void +delegateKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.delegateKeylet(benchAlice().id(), benchBob().id()); }); +} +BENCHMARK(delegateKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp new file mode 100644 index 0000000000..9b73044d6a --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "deposit_preauth_id"; + +// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type +// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its +// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing +// cost follows a call's shape, not which keylet it computes (see ../README.md). +void +depositPreauthKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.depositPreauthKeylet(benchAlice().id(), benchBob().id()); }); +} +BENCHMARK(depositPreauthKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp new file mode 100644 index 0000000000..854a9603ac --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "did_id"; + +// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type +// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its +// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing +// cost follows a call's shape, not which keylet it computes (see ../README.md). +void +didKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.didKeylet(benchAlice().id()); }); +} +BENCHMARK(didKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp new file mode 100644 index 0000000000..0989b7cb29 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp @@ -0,0 +1,63 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "escrow_id"; + +// Declared 350, and the one keylet carrying a `ThroughVm` pair on behalf of all nineteen. +// +// It is the right representative because it is the shape with the extra wrinkle: its sequence +// number arrives as a four-byte little-endian *region*, not a scalar, so the crossing decodes two +// inputs rather than one (`read_u32_arg` in crates/xrpl-wasm-vm/src/register.rs). The gap between +// this pair and the floor in `Crossing.bench.cpp` therefore prices region decoding as well as the +// hash. The other eighteen are `Impl`-only — crossing cost follows a call's shape, not which +// keylet it computes. + +constexpr std::string_view kImport = + R"( (import "host_lib" "escrow_id" (func $escrow_id (param i32 i32 i32 i32 i32 i32) (result i32))) +)"; +constexpr std::string_view kBody = + "(call $escrow_id (i32.const 0) (i32.const 20) (i32.const 32) (i32.const 4) " + "(i32.const 64) (i32.const 32))"; + +void +escrowKeyletThroughVm(benchmark::State& state) +{ + // Account at 0, sequence at 32, answer at 64. An all-zero account would be `InvalidAccount` + // and the benchmark would measure the rejection instead of the keylet. + static auto const kData = [] { + auto seq = Bytes(4); + for (auto i = 0; i < 4; ++i) + seq[i] = static_cast((kBenchSeq >> (8 * i)) & 0xFF); + return dataSegment(0, RealHostFixture::toBytes(benchAlice().id())) + dataSegment(32, seq); + }(); + + benchmarkThroughVm(state, kWasmName, kImport, kData, kBody, [] { return benchHost(); }); +} +BENCHMARK(escrowKeyletThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +escrowKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.escrowKeylet(benchAlice().id(), kBenchSeq); }); +} +BENCHMARK(escrowKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp new file mode 100644 index 0000000000..141f081ca8 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "float_add"; + +// Declared 160. The float family's reference arithmetic: every other operation in the family is +// priced as a multiple of this one, so if this number is wrong the whole block shifts with it. +// +// It also carries the family's `ThroughVm` case for the ordinary two-operands-in, one-out shape. +// `FloatPower` covers the expensive end and `FloatToMantExp` the two-output shape; the other +// eleven are `Impl`-only, because crossing cost follows a call's shape rather than its arithmetic. + +constexpr std::string_view kImport = + R"( (import "host_lib" "float_add" (func $float_add (param i32 i32 i32 i32 i32 i32 i32) (result i32))) +)"; + +// x, y, out, then the rounding mode LAST: the wasm signature is not the trait's argument order. +// `float_add(x, y, mode, out)` in Rust becomes `(x_ptr, x_len, y_ptr, y_len, out_ptr, out_len, +// mode)` on the wire, because the macro expands each slice to its pointer/length pair in place and +// moves the scalars after the output region (`HostFunctionSpec::FloatAdd` in +// crates/xrpl-wasm-vm/src/register.rs). Getting this wrong passes a byte count as the mode and the +// host answers `FloatInputMalformed` — a fast rejection that looks like a plausible measurement. +constexpr std::string_view kBody = + "(call $float_add (i32.const 0) (i32.const 12) (i32.const 16) (i32.const 12) " + "(i32.const 64) (i32.const 12) (i32.const 0))"; + +void +floatAddThroughVm(benchmark::State& state) +{ + static auto const kData = dataSegment(0, FloatTest::kPi) + dataSegment(16, FloatTest::kTwo); + benchmarkThroughVm(state, kWasmName, kImport, kData, kBody, [] { return benchHost(); }); +} +BENCHMARK(floatAddThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +floatAddImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.floatAdd(benchFloatX(), benchFloatY(), kBenchMode); }); +} +BENCHMARK(floatAddImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp new file mode 100644 index 0000000000..9b52b5f002 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp @@ -0,0 +1,29 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "float_cmp"; + +// Declared 80 — cheaper than any arithmetic, and the only float call answering a scalar rather +// than 12 bytes. It still decodes two operands, which is what makes it a useful floor for what +// operand decoding alone costs. +void +floatCompareImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.floatCompare(benchFloatX(), benchFloatY()); }); +} +BENCHMARK(floatCompareImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp new file mode 100644 index 0000000000..9c24814694 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "float_div"; + +// Declared 300, the same as `float_mult`. Division is usually the more expensive of the two, +// so pricing them identically is a claim worth checking. +void +floatDivideImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.floatDivide(benchFloatX(), benchFloatY(), kBenchMode); }); +} +BENCHMARK(floatDivideImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp new file mode 100644 index 0000000000..8fa7533bf9 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "float_from_int"; + +// Declared 100, the float family's floor. An integer becomes a normalized mantissa/exponent +// pair — no operand to decode first, which is what makes it the cheapest of the fourteen. +void +floatFromIntImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.floatFromInt(3141592653589793, kBenchMode); }); +} +BENCHMARK(floatFromIntImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp new file mode 100644 index 0000000000..66214577d6 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "float_from_mant_exp"; + +// Declared 100. Builds a float from parts the guest already split, so it is the inverse of +// `FloatToMantExp` and priced 30 below it. +void +floatFromMantExpImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.floatFromMantExp(3141592653589793, -15, kBenchMode); }); +} +BENCHMARK(floatFromMantExpImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp new file mode 100644 index 0000000000..55bf5847e4 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp @@ -0,0 +1,35 @@ +#include +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "float_from_stamount"; + +// Declared 150, the joint-highest of the float conversions. Unlike `float_from_int` it starts +// from a serialized ledger type, so it pays a parse before the conversion — which is what the +// 50% premium over `float_from_int`'s 100 is for. +void +floatFromStAmountImpl(benchmark::State& state) +{ + auto const amount = STAmount{Issue{toCurrency("USD"), benchAlice().id()}, 1234567, -3}; + + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [&amount](auto& host) { return host.floatFromSTAmount(amount, kBenchMode); }); +} +BENCHMARK(floatFromStAmountImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp new file mode 100644 index 0000000000..1e25a9964b --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp @@ -0,0 +1,35 @@ +#include +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "float_from_stnumber"; + +// Declared 150, the same as `float_from_stamount`. An `STNumber` is already a mantissa and an +// exponent, so this conversion has strictly less to do than one from an `STAmount` — pricing +// them identically is the claim under test. +void +floatFromStNumberImpl(benchmark::State& state) +{ + auto const number = STNumber{sfNumber, Number(3141592653589793, -15)}; + + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [&number](auto& host) { return host.floatFromSTNumber(number, kBenchMode); }); +} +BENCHMARK(floatFromStNumberImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp new file mode 100644 index 0000000000..6b70677dcb --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "float_from_uint"; + +// Declared 130 against `float_from_int`'s 100. The same conversion from an unsigned value, so +// the 30% surcharge is a claim about the wider range needing more normalization work. +void +floatFromUintImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.floatFromUint(3141592653589793u, kBenchMode); }); +} +BENCHMARK(floatFromUintImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp new file mode 100644 index 0000000000..bef3a8a247 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp @@ -0,0 +1,29 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "float_mult"; + +// Declared 300, 1.875x `float_add`'s 160. A multiplication really is more work than an +// addition on a mantissa/exponent pair, so this ratio is one of the table's more defensible +// claims — and one of the easier ones to confirm. +void +floatMultiplyImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.floatMultiply(benchFloatX(), benchFloatY(), kBenchMode); }); +} +BENCHMARK(floatMultiplyImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp new file mode 100644 index 0000000000..7232a73e5a --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "float_pow"; + +// Declared 5500 — 34x `float_add`'s 160, and tied with `float_root` for the most expensive host +// function that is not a signature check. Since both take the same 12-byte operand over the same +// crossing, the entire 34x has to appear in the `Impl` number; the `ThroughVm` case is here to +// confirm the crossing is the same one `FloatAdd` pays, and so cannot be what the 34x is for. + +constexpr std::string_view kImport = + R"( (import "host_lib" "float_pow" (func $float_pow (param i32 i32 i32 i32 i32 i32) (result i32))) +)"; + +// As with `float_add`, the mode goes last: (x_ptr, x_len, n, out_ptr, out_len, mode). +constexpr std::string_view kBody = + "(call $float_pow (i32.const 0) (i32.const 12) (i32.const 7) " + "(i32.const 64) (i32.const 12) (i32.const 0))"; + +void +floatPowerThroughVm(benchmark::State& state) +{ + static auto const kData = dataSegment(0, FloatTest::kPi); + benchmarkThroughVm(state, kWasmName, kImport, kData, kBody, [] { return benchHost(); }); +} +BENCHMARK(floatPowerThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +floatPowerImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.floatPower(benchFloatX(), 7, kBenchMode); }); +} +BENCHMARK(floatPowerImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp new file mode 100644 index 0000000000..cecd1360ef --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp @@ -0,0 +1,29 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "float_root"; + +// Declared 5500, tied with `float_pow` for the most expensive host function that is not a +// signature check. Tied is the thing to question: a root and a power are different algorithms, +// and one price for both is only right if they happen to cost the same. +void +floatRootImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.floatRoot(benchFloatX(), 2, kBenchMode); }); +} +BENCHMARK(floatRootImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp new file mode 100644 index 0000000000..38ff054958 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "float_sub"; + +// Declared 160, identical to `float_add` — the same operation up to a sign. These two should +// measure the same, and if they do not, something other than the arithmetic is being counted. +void +floatSubtractImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.floatSubtract(benchFloatX(), benchFloatY(), kBenchMode); }); +} +BENCHMARK(floatSubtractImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp new file mode 100644 index 0000000000..d7e3b57c6a --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "float_to_int"; + +// Declared 130. Decode a float, then round it to an integer under the given mode. Compare with +// `FloatFromInt` at 100 — the table says decoding an operand costs about 30. +void +floatToIntImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.floatToInt(benchFloatX(), kBenchMode); }); +} +BENCHMARK(floatToIntImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp new file mode 100644 index 0000000000..46c80369b5 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "float_to_mant_exp"; + +// Declared 130. The one call in the whole ABI that writes *two* output regions, so the one place +// the crossing does two bounds checks and two writes — which is why it carries a `ThroughVm` case +// despite being unremarkable arithmetic. Its gap over `floatToMantExpImpl` is the only measurement +// of what a second output region costs, and nothing else in the suite can supply it. + +constexpr std::string_view kImport = + R"( (import "host_lib" "float_to_mant_exp" (func $split (param i32 i32 i32 i32 i32 i32) (result i32))) +)"; +constexpr std::string_view kBody = + "(call $split (i32.const 0) (i32.const 12) (i32.const 64) (i32.const 8) " + "(i32.const 128) (i32.const 4))"; + +void +floatToMantExpThroughVm(benchmark::State& state) +{ + static auto const kData = dataSegment(0, FloatTest::kPi); + benchmarkThroughVm(state, kWasmName, kImport, kData, kBody, [] { return benchHost(); }); +} +BENCHMARK(floatToMantExpThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +floatToMantExpImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.floatToMantExp(benchFloatX()); }); +} +BENCHMARK(floatToMantExpImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp new file mode 100644 index 0000000000..729c0eccae --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp @@ -0,0 +1,40 @@ + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "nft_uri"; + +// Declared 5000 against the five id-extractor getters' 60-70 — a 14x ratio that is at least the +// right sign, since this is the only NFT call that touches the ledger. It has to find the token's +// `NFTokenPage`, walk it, and copy out a variable-length URI, where its siblings just mask bits +// out of an id the guest already supplied. Whether 14x is the right *size* is what the gap between +// this case and `NFTIssuer.bench.cpp` answers. + +void +getNFTImpl(benchmark::State& state) +{ + // A really minted token, so the lookup walks a real page rather than failing fast — a + // not-found answer would measure the rejection instead of the work. + static constexpr auto kUri = std::string_view{"ipfs://benchmark"}; + static Bench nft; + static auto const kOwner = nft.fund("benchNftOwner"); + static auto const kMinted = nft.mintNFT(kOwner, kUri); + + benchmarkImpl( + state, + kWasmName, + [] { return nft.makeHost(); }, + [](auto& host) { return host.getNFT(kOwner.id(), kMinted); }); +} +BENCHMARK(getNFTImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp new file mode 100644 index 0000000000..487187c526 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp @@ -0,0 +1,69 @@ +#include + +#include +#include +#include + +#include +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. Both cases below +// share it — one price covers both forms, which is the thing being questioned. +constexpr std::string_view kWasmName = "amendment_enabled"; + +// A real registered amendment, so both forms resolve and measure a lookup that succeeds rather +// than one that fails fast. The same one `IsAmendmentEnabled.cpp` uses. +// +// A `std::string` because `getRegisteredFeature` takes one; the name form of the host call takes +// a `string_view`, so both spellings are needed and this is the one that converts to the other. +std::string const& +benchAmendment() +{ + static std::string const kValue = "TokenEscrow"; + return kValue; +} + +// Declared 100 for *either* form, but the two forms do different work: by id is a set membership +// test against the ledger's rules, while by name has to resolve the name through +// `ServiceRegistry::getAmendmentTable().find()` first. One flat price for a lookup and a compare +// is exactly the kind of claim this suite exists to question, so both are measured. + +void +isAmendmentEnabledByIdImpl(benchmark::State& state) +{ + // `getRegisteredFeature` answers an optional; a missing amendment would make this case + // measure a lookup that fails rather than one that succeeds, so fail loudly instead. + auto const feature = getRegisteredFeature(benchAmendment()); + if (!feature.has_value()) + { + state.SkipWithError("the benchmarked amendment is not registered"); + return; + } + auto const id = *feature; + + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [&id](auto& host) { return host.isAmendmentEnabled(id); }); +} +BENCHMARK(isAmendmentEnabledByIdImpl)->UseManualTime()->Iterations(kBenchIterations); + +void +isAmendmentEnabledByNameImpl(benchmark::State& state) +{ + // The gap over the id form is precisely what the shared price of 100 asserts does not exist. + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.isAmendmentEnabled(std::string_view{benchAmendment()}); }); +} +BENCHMARK(isAmendmentEnabledByNameImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp new file mode 100644 index 0000000000..e5e365f189 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp @@ -0,0 +1,29 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "le_arr_len"; + +// Declared 40. The signer list's entries counted through a cache slot. +void +ledgerObjArrayLenImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchCachedSignerListHost(); }, + [](auto& host) { return host.getLedgerObjArrayLen(1, sfSignerEntries); }); +} +BENCHMARK(ledgerObjArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp new file mode 100644 index 0000000000..f5c8286e27 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp @@ -0,0 +1,32 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "le_field"; + +// Declared 70. The same read as `home_le_field`, but through a cache slot rather than the +// current object — one extra scalar and a slot-table lookup. There is deliberately no +// `ThroughVm` pair: `runEscrowWasm` asserts a clean host, so a benchmark cannot pre-cache a +// slot. `e2e/CacheLedgerObj.cpp` covers the cross-call behaviour instead. +void +ledgerObjFieldImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchCachedHost(); }, + [](auto& host) { return host.getLedgerObjField(1, sfAccount); }); +} +BENCHMARK(ledgerObjFieldImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp new file mode 100644 index 0000000000..a823254080 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp @@ -0,0 +1,32 @@ +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "le_inner_arr_len"; + +// Declared 70. The deepest read in the family: slot lookup, locator walk, then a count. +void +ledgerObjNestedArrayLenImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchCachedSignerListHost(); }, + [](auto& host) { + return host.getLedgerObjNestedArrayLen(1, FieldLocator{{sfSignerEntries.getCode()}}); + }); +} +BENCHMARK(ledgerObjNestedArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp new file mode 100644 index 0000000000..af8674d611 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "le_inner"; + +// Declared 110. A locator walk over a cached object: the nested read plus the slot lookup that +// `LedgerObjField` measures on its own. +void +ledgerObjNestedFieldImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchCachedHost(); }, + [](auto& host) { + return host.getLedgerObjNestedField(1, FieldLocator{{sfAccount.getCode()}}); + }); +} +BENCHMARK(ledgerObjNestedFieldImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp new file mode 100644 index 0000000000..996e3be67c --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp @@ -0,0 +1,45 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "ldgr_index"; + +// Declared 60, and the cheapest host call there is: no input, and the answer is a field of a +// header already in hand. That makes it the crossing's reference point — whatever the `ThroughVm` +// case costs above the `Impl` case is the floor price of leaving the guest, paid by all 61 +// functions before any of them does any work. `Crossing.bench.cpp` reads against these two. + +constexpr std::string_view kImport = + R"( (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) +)"; + +void +ledgerSqnThroughVm(benchmark::State& state) +{ + benchmarkThroughVm( + state, kWasmName, kImport, "", "(call $ldgr_index (i32.const 0) (i32.const 4))", [] { + return benchHost(); + }); +} +BENCHMARK(ledgerSqnThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +ledgerSqnImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.getLedgerSqn(); }); +} +BENCHMARK(ledgerSqnImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp new file mode 100644 index 0000000000..57babcd929 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "mpt_issuance_id"; + +// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type +// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its +// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing +// cost follows a call's shape, not which keylet it computes (see ../README.md). +void +mptokenIssuanceKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.mptokenIssuanceKeylet(benchAlice().id(), kBenchSeq); }); +} +BENCHMARK(mptokenIssuanceKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp new file mode 100644 index 0000000000..cfa88f71c4 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp @@ -0,0 +1,33 @@ + +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "mptoken_id"; + +// Declared 500, the highest in the keylet family. A 24-byte issuance id plus a 20-byte holder — +// more input bytes than its siblings, but not obviously 43% more work than the 350 ones. +void +mptokenKeyletImpl(benchmark::State& state) +{ + auto const mptid = makeMptID(1, benchAlice().id()); + + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [&mptid](auto& host) { return host.mptokenKeylet(mptid, benchBob().id()); }); +} +BENCHMARK(mptokenKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp new file mode 100644 index 0000000000..9f6eb9bf6b --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "nft_flags"; + +// Declared 60. Pure extraction from the id — no ledger access. See `NFTIssuer.bench.cpp`. +void +nftFlagsImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.getNFTFlags(benchNftId()); }); +} +BENCHMARK(nftFlagsImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp new file mode 100644 index 0000000000..56a4d82340 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp @@ -0,0 +1,29 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "nft_issuer"; + +// Declared 70. An NFToken id encodes its issuer in its own 32 bytes, so this touches no ledger +// state: it is shifts and masks over a value the guest already handed over. Compare against +// `GetNFT`, declared 5000, which actually goes and finds the token. +void +nftIssuerImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.getNFTIssuer(benchNftId()); }); +} +BENCHMARK(nftIssuerImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp new file mode 100644 index 0000000000..e1f67c3b05 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "nft_serial"; + +// Declared 60. Pure extraction from the id — no ledger access. See `NFTIssuer.bench.cpp`. +void +nftSequenceImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.getNFTSequence(benchNftId()); }); +} +BENCHMARK(nftSequenceImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp new file mode 100644 index 0000000000..026d4f32a1 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "nft_taxon"; + +// Declared 60. Pure extraction from the id — no ledger access. See `NFTIssuer.bench.cpp`. +void +nftTaxonImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.getNFTTaxon(benchNftId()); }); +} +BENCHMARK(nftTaxonImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp new file mode 100644 index 0000000000..7fc52ca64f --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "nft_xfer_fee"; + +// Declared 60. Pure extraction from the id — no ledger access. See `NFTIssuer.bench.cpp`. +void +nftTransferFeeImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.getNFTTransferFee(benchNftId()); }); +} +BENCHMARK(nftTransferFeeImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp new file mode 100644 index 0000000000..e8a59b7121 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "nft_offer_id"; + +// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type +// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its +// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing +// cost follows a call's shape, not which keylet it computes (see ../README.md). +void +nftokenOfferKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.nftokenOfferKeylet(benchAlice().id(), kBenchSeq); }); +} +BENCHMARK(nftokenOfferKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp new file mode 100644 index 0000000000..1e1dabc088 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "offer_id"; + +// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type +// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its +// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing +// cost follows a call's shape, not which keylet it computes (see ../README.md). +void +offerKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.offerKeylet(benchAlice().id(), kBenchSeq); }); +} +BENCHMARK(offerKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp new file mode 100644 index 0000000000..25caf96cff --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "oracle_id"; + +// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type +// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its +// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing +// cost follows a call's shape, not which keylet it computes (see ../README.md). +void +oracleKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.oracleKeylet(benchAlice().id(), kBenchSeq); }); +} +BENCHMARK(oracleKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp new file mode 100644 index 0000000000..906d9a5a93 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp @@ -0,0 +1,29 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "parent_ldgr_hash"; + +// Declared 60, the same as the other header getters, but this one returns 32 bytes rather than +// 4 — and on some paths a parent hash is a lookup rather than a field read. If any of the four +// is secretly doing work, it is this one. +void +parentLedgerHashImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.getParentLedgerHash(); }); +} +BENCHMARK(parentLedgerHashImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp new file mode 100644 index 0000000000..d7a4397832 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp @@ -0,0 +1,29 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "parent_ldgr_time"; + +// Declared 60. No input, and the answer is a field of a header already in hand, so this should +// measure at essentially nothing and the crossing should dominate it entirely. Read against +// `Crossing.bench.cpp`, which uses `ldgr_index` — the same shape — as the crossing floor. +void +parentLedgerTimeImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.getParentLedgerTime(); }); +} +BENCHMARK(parentLedgerTimeImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp new file mode 100644 index 0000000000..341e5b4bb4 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp @@ -0,0 +1,32 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "paychan_id"; + +// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type +// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its +// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing +// cost follows a call's shape, not which keylet it computes (see ../README.md). +void +paychannelKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { + return host.paychannelKeylet(benchAlice().id(), benchBob().id(), kBenchSeq); + }); +} +BENCHMARK(paychannelKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp new file mode 100644 index 0000000000..3ec1699682 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "permissioned_domain_id"; + +// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type +// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its +// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing +// cost follows a call's shape, not which keylet it computes (see ../README.md). +void +permissionedDomainKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.permissionedDomainKeylet(benchAlice().id(), kBenchSeq); }); +} +BENCHMARK(permissionedDomainKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp new file mode 100644 index 0000000000..ab73e82ad4 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp @@ -0,0 +1,82 @@ +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "sha512_half"; + +// Declared 2000 — a single flat price, no matter how many bytes it is asked to hash. Hashing is +// linear in its input, so the declaration can only be exactly right at one length; the `Range` +// here shows where that length is, and how far the flat price misses at the ends. +// +// What bounds the damage is `MAX_FIELD_BYTES` (crates/xrpl-wasm-vm/src/region.rs): no single value +// may cross the boundary in either direction above 1 KiB, `DataFieldTooLarge` otherwise. So the +// flat price is wrong over a 128x span, not an unbounded one — the worst a contract can extract is +// the ratio between hashing 1 KiB and hashing 8 bytes, both for 2000 gas. That is what this sweep +// puts a figure on, and why the range stops at 1024: past that the `ThroughVm` case cannot run at +// all, and comparing it against an `Impl` case that can would be measuring two different things. + +constexpr int kMaxBytes = 1024; + +constexpr std::string_view kImport = + R"( (import "host_lib" "sha512_half" (func $sha512_half (param i32 i32 i32 i32) (result i32))) +)"; + +void +sha512HalfThroughVm(benchmark::State& state) +{ + // Zeroed guest memory is a perfectly good hash input: `sha512_half` validates nothing about + // its bytes, so there is no data segment to seed. + auto const body = std::string{"(call $sha512_half (i32.const 0) (i32.const "} + + std::to_string(state.range(0)) + ") (i32.const 8192) (i32.const 32))"; + + // The call count shrinks as the input grows: at 1 KiB a thousand calls would approach the + // engine's per-run transfer budget and the tail of the loop would be measuring refusals. + benchmarkThroughVm( + state, + kWasmName, + kImport, + "", + body, + [] { return benchHost(); }, + callsWithinTransferBudget(state.range(0) + 32)); + state.SetBytesProcessed(state.iterations() * state.range(0)); +} +BENCHMARK(sha512HalfThroughVm) + ->RangeMultiplier(8) + ->Range(8, kMaxBytes) + ->UseManualTime() + ->Iterations(kBenchIterations); + +void +sha512HalfImpl(benchmark::State& state) +{ + auto const data = Bytes(static_cast(state.range(0)), 0x42); + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [&data](auto& host) { + return host.computeSha512HalfHash(Slice{data.data(), data.size()}); + }); + state.SetBytesProcessed(state.iterations() * state.range(0)); +} +BENCHMARK(sha512HalfImpl) + ->RangeMultiplier(8) + ->Range(8, kMaxBytes) + ->UseManualTime() + ->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp new file mode 100644 index 0000000000..59dec0ae8f --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "signers_id"; + +// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type +// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its +// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing +// cost follows a call's shape, not which keylet it computes (see ../README.md). +void +signerListKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.signerListKeylet(benchAlice().id()); }); +} +BENCHMARK(signerListKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp new file mode 100644 index 0000000000..f3a4ba15a5 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "ticket_id"; + +// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type +// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its +// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing +// cost follows a call's shape, not which keylet it computes (see ../README.md). +void +ticketKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.ticketKeylet(benchAlice().id(), kBenchSeq); }); +} +BENCHMARK(ticketKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp new file mode 100644 index 0000000000..87889da421 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp @@ -0,0 +1,54 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "trace"; + +// Declared 30, the cheapest price in the table, and the only host function that answers nothing. +// +// 30 is right for the case that matters: a validator with tracing off, where the call renders +// nothing and returns. But the same 30 is charged when the sink *is* enabled and the host formats +// a message and writes it. A contract cannot choose which node it runs on, so the price has to be +// set for the cheap case and the expensive one has to be a node's own problem. These two cases +// measure how far apart they are, which is how you decide whether that reasoning still holds. +// +// No `ThroughVm` case: `trace` has no result for the harness's `result >= 0` guard to check, and +// its input shape (two regions in, nothing out) is already priced by `Sha512Half.bench.cpp`. + +constexpr auto kMessage = std::string_view{"benchmark trace message"}; +constexpr auto kData = std::string_view{"0123456789abcdef"}; + +// The path a validator actually runs: journal pointed at a null sink. +void +traceDisabledImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchLedger().makeHost(); }, + [](auto& host) { return host.trace(kMessage, kData); }); +} +BENCHMARK(traceDisabledImpl)->UseManualTime()->Iterations(kBenchIterations); + +// The same call against a host whose sink records what it is given. The gap over the case above +// is the cost the flat 30 does not cover. +void +traceEnabledImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchLedger().makeTracingHost(); }, + [](auto& host) { return host.trace(kMessage, kData); }); +} +BENCHMARK(traceEnabledImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp new file mode 100644 index 0000000000..da4dc1f729 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp @@ -0,0 +1,35 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "trustline_id"; + +// Declared 400 against the family's 350. Three inputs rather than two — two accounts and a +// currency — so the surcharge prices one extra 20-byte value going into the hash. That is the +// most concrete per-input claim in the whole table, and the easiest to check. +void +trustLineKeyletImpl(benchmark::State& state) +{ + auto const currency = toCurrency("USD"); + + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [¤cy](auto& host) { + return host.trustLineKeylet(benchAlice().id(), benchBob().id(), currency); + }); +} +BENCHMARK(trustLineKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp new file mode 100644 index 0000000000..251b6c42d4 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp @@ -0,0 +1,31 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "tx_arr_len"; + +// Declared 40, the cheapest non-`trace` price in the table. Counting an array's elements does +// not serialize them, which is what justifies pricing it below a field read's 70 — this case +// and `TxField` together are whether that 40/70 split is the right size. +void +txArrayLenImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.getTxArrayLen(sfMemos); }); +} +BENCHMARK(txArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp new file mode 100644 index 0000000000..23792b57d4 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp @@ -0,0 +1,31 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "tx_field"; + +// Declared 70. One `getFieldByCode` on the transaction being executed, then serialize the +// result. Its pair with `CurrentLedgerObjField` (same price, an object instead of a tx) shows +// whether the source matters to the cost; the declared table says it does not. +void +txFieldImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.getTxField(sfAccount); }); +} +BENCHMARK(txFieldImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp new file mode 100644 index 0000000000..5d581492de --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp @@ -0,0 +1,32 @@ +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "tx_inner_arr_len"; + +// Declared 70 against a direct count's 40 — the same locator surcharge the nested field getters +// pay, expressed as a different ratio (1.75x here, 1.57x there). Both cannot be right unless a +// locator walk costs a fixed amount, which is what these two pairs check. +void +txNestedArrayLenImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.getTxNestedArrayLen(FieldLocator{{sfMemos.getCode()}}); }); +} +BENCHMARK(txNestedArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp new file mode 100644 index 0000000000..d9ea9ff054 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp @@ -0,0 +1,65 @@ +#include +#include + +#include +#include +#include + +#include +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "tx_inner"; + +// Declared 110 against a direct read's 70 — the table's claim that walking a locator costs about +// half a field read again. +// +// This file carries the locator `ThroughVm` case for the whole nested family. A locator is a +// variable-length path of little-endian i32 steps that the *guest* lays out and the host walks; +// every other input shape in the ABI is a fixed-size value, so this is the only place the crossing +// reads a length the guest chose. The other five nested getters are `Impl`-only. + +constexpr std::string_view kImport = + R"( (import "host_lib" "tx_inner" (func $tx_inner (param i32 i32 i32 i32) (result i32))) +)"; +constexpr std::string_view kBody = + "(call $tx_inner (i32.const 0) (i32.const 12) (i32.const 64) (i32.const 64))"; + +void +txNestedFieldThroughVm(benchmark::State& state) +{ + // The locator bytes are seeded rather than stored by the guest, so the loop measures the host + // call and not three `i32.store`s. + static auto const kData = dataSegment(0, [] { + auto bytes = Bytes{}; + for (auto const step : {sfMemos.getCode(), 0, sfMemoData.getCode()}) + { + for (auto i = 0; i < 4; ++i) + { + bytes.push_back(static_cast((step >> (8 * i)) & 0xFF)); + } + } + return bytes; + }()); + + benchmarkThroughVm(state, kWasmName, kImport, kData, kBody, [] { return benchHost(); }); +} +BENCHMARK(txNestedFieldThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +txNestedFieldImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.getTxNestedField(benchMemoLocator()); }); +} +BENCHMARK(txNestedFieldImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp new file mode 100644 index 0000000000..b172f24e42 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp @@ -0,0 +1,75 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "set_data"; + +// Declared 1000, and the suite's purest measurement of what *moving bytes* costs. +// +// The impl does almost nothing but copy the guest's region into host-owned storage, so unlike +// `sha512_half` there is no computation competing with the transfer. Swept over the input length +// up to `kMaxWasmDataLength`, the `ThroughVm` case is close to a direct readout of the per-byte +// term in the crossing — the number that, added to the fixed floor in `Crossing.bench.cpp`, should +// predict every other function's `ThroughVm` minus `Impl` gap. +// +// It is also a flat price over a range spanning two orders of magnitude, the same +// flat-price-for-linear-work question `Sha512Half.bench.cpp` asks. + +constexpr std::string_view kImport = + R"( (import "host_lib" "set_data" (func $set_data (param i32 i32) (result i32))) +)"; + +void +updateDataThroughVm(benchmark::State& state) +{ + auto const body = std::string{"(call $set_data (i32.const 0) (i32.const "} + + std::to_string(state.range(0)) + "))"; + + benchmarkThroughVm( + state, + kWasmName, + kImport, + "", + body, + [] { return benchHost(); }, + callsWithinTransferBudget(state.range(0))); + state.SetBytesProcessed(state.iterations() * state.range(0)); +} +BENCHMARK(updateDataThroughVm) + ->RangeMultiplier(4) + ->Range(8, kMaxWasmDataLength) + ->UseManualTime() + ->Iterations(kBenchIterations); + +void +updateDataImpl(benchmark::State& state) +{ + auto const data = Bytes(static_cast(state.range(0)), 0x42); + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [&data](auto& host) { return host.updateData(Slice{data.data(), data.size()}); }); + state.SetBytesProcessed(state.iterations() * state.range(0)); +} +BENCHMARK(updateDataImpl) + ->RangeMultiplier(4) + ->Range(8, kMaxWasmDataLength) + ->UseManualTime() + ->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp new file mode 100644 index 0000000000..c004de1f2d --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the +// declaration rather than copying the number keeps the two from drifting apart. +constexpr std::string_view kWasmName = "vault_id"; + +// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type +// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its +// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing +// cost follows a call's shape, not which keylet it computes (see ../README.md). +void +vaultKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return benchHost(); }, + [](auto& host) { return host.vaultKeylet(benchAlice().id(), kBenchSeq); }); +} +BENCHMARK(vaultKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench From e29e24dd5035335e9aabeaf148302cbe7cf54b9d Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Wed, 26 Aug 2026 18:09:56 -0400 Subject: [PATCH 11/23] chore: Self code review --- src/benchmarks/libxrpl/CMakeLists.txt | 13 +- src/tests/libxrpl/CMakeLists.txt | 20 +- src/tests/libxrpl/tx/wasm/BenchFixtures.cpp | 182 +++++++++++++++ src/tests/libxrpl/tx/wasm/BenchFixtures.h | 185 +++++---------- src/tests/libxrpl/tx/wasm/WasmBench.cpp | 210 ++++++++++++++++++ src/tests/libxrpl/tx/wasm/WasmBench.h | 194 ++-------------- src/tests/libxrpl/tx/wasm/WasmRun.cpp | 52 +++++ src/tests/libxrpl/tx/wasm/WasmRun.h | 41 +--- .../libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp | 17 +- .../libxrpl/tx/wasm/e2e/FloatToMantExp.cpp | 6 +- src/tests/libxrpl/tx/wasm/e2e/HostError.cpp | 5 - .../libxrpl/tx/wasm/e2e/HostFunctionTour.cpp | 12 +- src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp | 8 +- src/tests/libxrpl/tx/wasm/e2e/SetData.cpp | 9 +- src/tests/libxrpl/tx/wasm/e2e/TxField.cpp | 7 +- .../libxrpl/tx/wasm/e2e/TxNestedField.cpp | 16 -- .../host_functions/AccountKeylet.bench.cpp | 10 +- .../wasm/host_functions/AmmKeylet.bench.cpp | 9 +- .../tx/wasm/host_functions/BaseFee.bench.cpp | 8 +- .../host_functions/CacheLedgerObj.bench.cpp | 16 +- .../wasm/host_functions/CheckKeylet.bench.cpp | 10 +- .../host_functions/CheckSignature.bench.cpp | 23 +- .../host_functions/CredentialKeylet.bench.cpp | 8 +- .../CurrentLedgerObjArrayLen.bench.cpp | 8 +- .../CurrentLedgerObjField.bench.cpp | 17 -- .../CurrentLedgerObjNestedArrayLen.bench.cpp | 7 +- .../CurrentLedgerObjNestedField.bench.cpp | 9 +- .../host_functions/DelegateKeylet.bench.cpp | 10 +- .../DepositPreauthKeylet.bench.cpp | 10 +- .../wasm/host_functions/DidKeylet.bench.cpp | 10 +- .../host_functions/EscrowKeylet.bench.cpp | 17 +- .../tx/wasm/host_functions/FloatAdd.bench.cpp | 15 -- .../host_functions/FloatCompare.bench.cpp | 9 +- .../wasm/host_functions/FloatDivide.bench.cpp | 8 +- .../host_functions/FloatFromInt.bench.cpp | 8 +- .../host_functions/FloatFromMantExp.bench.cpp | 8 +- .../FloatFromStAmount.bench.cpp | 9 +- .../FloatFromStNumber.bench.cpp | 9 +- .../host_functions/FloatFromUint.bench.cpp | 8 +- .../host_functions/FloatMultiply.bench.cpp | 9 +- .../wasm/host_functions/FloatPower.bench.cpp | 8 - .../wasm/host_functions/FloatRoot.bench.cpp | 9 +- .../host_functions/FloatSubtract.bench.cpp | 8 +- .../wasm/host_functions/FloatToInt.bench.cpp | 8 +- .../host_functions/FloatToMantExp.bench.cpp | 7 - .../tx/wasm/host_functions/GetNFT.bench.cpp | 14 +- .../IsAmendmentEnabled.bench.cpp | 17 +- .../LedgerObjArrayLen.bench.cpp | 7 +- .../host_functions/LedgerObjField.bench.cpp | 10 +- .../LedgerObjNestedArrayLen.bench.cpp | 7 +- .../LedgerObjNestedField.bench.cpp | 8 +- .../wasm/host_functions/LedgerSqn.bench.cpp | 7 - .../MptokenIssuanceKeylet.bench.cpp | 10 +- .../host_functions/MptokenKeylet.bench.cpp | 8 +- .../tx/wasm/host_functions/NFTFlags.bench.cpp | 7 +- .../wasm/host_functions/NFTIssuer.bench.cpp | 9 +- .../wasm/host_functions/NFTSequence.bench.cpp | 7 +- .../tx/wasm/host_functions/NFTTaxon.bench.cpp | 7 +- .../host_functions/NFTTransferFee.bench.cpp | 7 +- .../NftokenOfferKeylet.bench.cpp | 10 +- .../wasm/host_functions/OfferKeylet.bench.cpp | 10 +- .../host_functions/OracleKeylet.bench.cpp | 10 +- .../host_functions/ParentLedgerHash.bench.cpp | 9 +- .../host_functions/ParentLedgerTime.bench.cpp | 9 +- .../host_functions/PaychannelKeylet.bench.cpp | 10 +- .../PermissionedDomainedKeylet.bench.cpp | 10 +- .../wasm/host_functions/Sha512Half.bench.cpp | 16 +- .../host_functions/SignerListKeylet.bench.cpp | 10 +- .../host_functions/TicketKeylet.bench.cpp | 10 +- .../tx/wasm/host_functions/Trace.bench.cpp | 18 +- .../host_functions/TrustLineKeylet.bench.cpp | 9 +- .../wasm/host_functions/TxArrayLen.bench.cpp | 9 +- .../tx/wasm/host_functions/TxField.bench.cpp | 9 +- .../host_functions/TxNestedArrayLen.bench.cpp | 9 +- .../host_functions/TxNestedField.bench.cpp | 13 +- .../wasm/host_functions/UpdateData.bench.cpp | 14 -- .../wasm/host_functions/VaultKeylet.bench.cpp | 10 +- 77 files changed, 663 insertions(+), 929 deletions(-) create mode 100644 src/tests/libxrpl/tx/wasm/BenchFixtures.cpp create mode 100644 src/tests/libxrpl/tx/wasm/WasmBench.cpp create mode 100644 src/tests/libxrpl/tx/wasm/WasmRun.cpp diff --git a/src/benchmarks/libxrpl/CMakeLists.txt b/src/benchmarks/libxrpl/CMakeLists.txt index 8e0f25d927..d5a6e6d07e 100644 --- a/src/benchmarks/libxrpl/CMakeLists.txt +++ b/src/benchmarks/libxrpl/CMakeLists.txt @@ -21,11 +21,9 @@ xrpl_add_benchmark(nodestore) target_link_libraries(xrpl.bench.nodestore PRIVATE xrpl.imports.bench) add_dependencies(xrpl.benchmarks xrpl.bench.nodestore) -# --------------------------------------------------------------------------- # xrpl.bench.wasm — gas calibration for the wasm host functions. # -# Unlike `nodestore`, this module's sources do not live here: each `*.bench.cpp` -# sits beside the test that covers the same host function, under +# Each `*.bench.cpp` sits beside the test that covers the same host function, under # `src/tests/libxrpl/tx/wasm/`. Keeping the benchmark next to the test means the # two move together and share one fixture; a separate executable means benchmark # runtime never lands on the `ctest` path (the test binary filters `*.bench.cpp` @@ -44,12 +42,19 @@ if(TARGET GTest::gtest) add_executable( xrpl.bench.wasm ${wasm_bench_sources} - # The fixtures under measurement: a real ledger, a real host, real accounts. "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/helpers/Account.cpp" "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/helpers/TestSink.cpp" "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/helpers/TxTest.cpp" "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/RealHostFixture.cpp" "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/NFTFixture.cpp" + # The benchmark harness and its shared ledger setup. Named without the + # `.bench.cpp` suffix because they are infrastructure rather than a benchmark, + # so the glob above does not find them and `xrpl_tests` excludes them by name. + "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/BenchFixtures.cpp" + "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/WasmBench.cpp" + # The WAT assembler, shared with the test binary rather than benchmark-only: + # both binaries compile their own copy. + "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/WasmRun.cpp" ) # Google Benchmark registers cases through static registrars declared in diff --git a/src/tests/libxrpl/CMakeLists.txt b/src/tests/libxrpl/CMakeLists.txt index 34fc7c66e6..34380240c6 100644 --- a/src/tests/libxrpl/CMakeLists.txt +++ b/src/tests/libxrpl/CMakeLists.txt @@ -55,11 +55,12 @@ foreach(module IN LISTS test_modules) "${CMAKE_CURRENT_SOURCE_DIR}/${module}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/${module}.cpp" ) - # `*.bench.cpp` files live beside the tests they measure, but belong to the - # benchmark executables (src/benchmarks/libxrpl), not to this one: they define - # Google Benchmark registrars, and running them under ctest would make a test - # run take minutes. Keep them out of the test binary. - list(FILTER sources EXCLUDE REGEX "\\.bench\\.cpp$") + # Remove Benchmark tests from this target. + list( + FILTER sources + EXCLUDE + REGEX "\\.bench\\.cpp$|/(WasmBench|BenchFixtures)\\.cpp$" + ) target_sources(xrpl_tests PRIVATE ${sources}) # Expose the module's private headers under their canonical include path. @@ -81,15 +82,6 @@ file( ) target_sources(xrpl_tests PRIVATE ${csf_sources}) -# `tx/wasm/WasmBench.h` and `tx/wasm/BenchFixtures.h` sit beside the tests they -# measure but belong to `xrpl.bench.wasm`, so they include -# while nothing in this binary does. `verify_target_headers` below compiles *every* -# header under this directory with this target's flags, so without the benchmark -# headers on the path those two fail to parse — which also makes clang-tidy's -# include-cleaner report nonsense for everything after the failed include. -# -# Carrying the include directory (not the library) is enough: the test binary -# compiles nothing that uses Google Benchmark, and links nothing from it. if(benchmark AND TARGET benchmark::benchmark) target_include_directories( xrpl_tests diff --git a/src/tests/libxrpl/tx/wasm/BenchFixtures.cpp b/src/tests/libxrpl/tx/wasm/BenchFixtures.cpp new file mode 100644 index 0000000000..52cbf6349b --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/BenchFixtures.cpp @@ -0,0 +1,182 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace xrpl::test::bench { + +[[noreturn]] void +benchSetupFailed(std::string_view what) +{ + throw std::runtime_error("benchmark fixture setup failed: " + std::string{what}); +} + +BenchFixture& +benchLedger() +{ + static BenchFixture value; + return value; +} + +Account const& +benchAlice() +{ + static auto const kValue = benchLedger().fund("benchAlice"); + return kValue; +} + +Account const& +benchBob() +{ + static auto const kValue = benchLedger().fund("benchBob"); + return kValue; +} + +TxAssembler +benchMemoTx() +{ + auto assembler = escrowFinishTx(benchLedger().ledger, benchAlice()); + assembler.build = [inner = std::move(assembler.build)](STObject& obj) { + inner(obj); + auto memos = STArray{}; + memos.push_back(makeMemo(RealHostFixture::toBytes("hello"))); + memos.push_back(makeMemo(RealHostFixture::toBytes("world"))); + obj.setFieldArray(sfMemos, memos); + }; + return assembler; +} + +FieldLocator +benchMemoLocator() +{ + return FieldLocator{{sfMemos.getCode(), 0, sfMemoData.getCode()}}; +} + +WasmHost +benchHost() +{ + auto assembler = benchMemoTx(); + return benchLedger().makeHost( + keylet::account(benchAlice().id()), assembler.type, std::move(assembler.build)); +} + +WasmHost +benchCachedHost() +{ + auto host = benchHost(); + if (!host->cacheLedgerObj(keylet::account(benchAlice().id()).key, 1).has_value()) + { + benchSetupFailed("caching the account root into slot 1"); + } + return host; +} + +Account const& +benchSignerListOwner() +{ + static auto const kValue = [] { + auto const acct = benchLedger().fund("benchSigners"); + benchLedger().makeSignerList(acct, 2, {{benchAlice(), 1}, {benchBob(), 1}}); + return acct; + }(); + return kValue; +} + +WasmHost +benchSignerListHost() +{ + auto assembler = bareTx(); + return benchLedger().makeHost( + keylet::signerList(benchSignerListOwner().id()), + assembler.type, + std::move(assembler.build)); +} + +WasmHost +benchCachedSignerListHost() +{ + auto assembler = bareTx(); + auto host = benchLedger().makeHost( + keylet::account(AccountID{}), assembler.type, std::move(assembler.build)); + if (!host->cacheLedgerObj(keylet::signerList(benchSignerListOwner().id()).key, 1).has_value()) + { + benchSetupFailed("caching the signer list into slot 1"); + } + return host; +} + +Keylet const& +benchEscrow() +{ + static auto const kValue = [] { + auto const ownerSeq = benchLedger().ledger.getAccountRoot(benchAlice().id()).getSequence(); + auto const created = benchLedger().ledger.submit( + transactions::EscrowCreateBuilder{benchAlice().id(), benchBob().id(), XRP(100)} + .setFinishAfter(900'000'000), + benchAlice()); + if (created.ter != tesSUCCESS) + { + benchSetupFailed(std::string{"creating the escrow: "} + transToken(created.ter)); + } + benchLedger().ledger.close(); + return keylet::escrow(benchAlice().id(), SeqProxy::rawSequence(ownerSeq)); + }(); + return kValue; +} + +WasmHost +benchEscrowHost() +{ + return benchLedger().makeHost(benchEscrow()); +} + +Slice +benchFloatX() +{ + return FloatTest::slice(FloatTest::kPi); +} + +Slice +benchFloatY() +{ + return FloatTest::slice(FloatTest::kTwo); +} + +SignedMessage const& +benchSignedMessage() +{ + static auto const kValue = signMessage("the quick brown fox jumps over the lazy dog"); + return kValue; +} + +uint256 const& +benchNftId() +{ + // `makeNftId` is a static member, so no fixture instance is needed to reach it. + static auto const kValue = NFTTest::makeNftId(benchAlice().id()); + return kValue; +} + +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/BenchFixtures.h b/src/tests/libxrpl/tx/wasm/BenchFixtures.h index 7c73591596..33d5de8661 100644 --- a/src/tests/libxrpl/tx/wasm/BenchFixtures.h +++ b/src/tests/libxrpl/tx/wasm/BenchFixtures.h @@ -2,34 +2,24 @@ #include #include -#include -#include #include -#include -#include -#include -#include -#include #include #include -#include -#include -#include #include #include #include #include -#include // Shared ledger state for the `*.bench.cpp` files. // // Each host function gets its own `.bench.cpp`, mirroring its test one-for-one, which // means ~61 translation units that would otherwise each build their own ledger, fund their own -// accounts and mint their own tokens. Everything here is `inline`, so a function-local static -// inside it is one object shared by the whole binary: the ledger is built once, each account is -// funded once, and a benchmark file is left holding only the call it measures. +// accounts and mint their own tokens. Declared here and defined once in `BenchFixtures.cpp`, so +// the function-local statics behind these accessors are single objects shared by the whole +// binary: the ledger is built once, each account is funded once, and a benchmark file is left +// holding only the call it measures. // // That sharing is safe because every helper does its setup inside its own `static`, so it // happens exactly once no matter how many files ask for it. It is also why the accounts have @@ -40,28 +30,31 @@ namespace xrpl::test::bench { +// Fail a fixture step loudly. +// +// A benchmark has no assertions — nothing here can `EXPECT_EQ` — and that makes a quietly +// failed setup step the most dangerous thing in this file. If the escrow is never created or +// the slot never cached, the host call still runs; it just takes the not-found path, which is +// cheap, plausible-looking, and completely wrong as a price. The `result >= 0` guard in +// `benchmarkThroughVm` catches that for VM cases, but an `Impl` case calls the host directly +// and has no such check. +// +// So every setup step whose failure would change what is being measured is checked here, and +// throws rather than returning. Google Benchmark reports the message and stops, which is the +// outcome you want: no number at all beats a confident wrong one. +[[noreturn]] void +benchSetupFailed(std::string_view what); + // The one ledger every benchmark runs against. -inline BenchFixture& -benchLedger() -{ - static BenchFixture value; - return value; -} +BenchFixture& +benchLedger(); // Two funded accounts, enough for every keylet shape and every object below. -inline Account const& -benchAlice() -{ - static auto const kValue = benchLedger().fund("benchAlice"); - return kValue; -} +Account const& +benchAlice(); -inline Account const& -benchBob() -{ - static auto const kValue = benchLedger().fund("benchBob"); - return kValue; -} +Account const& +benchBob(); // A sequence number for the keylets that take one. Arbitrary — a keylet hashes whatever it is // given, so the value cannot change the cost. @@ -73,108 +66,47 @@ inline constexpr std::uint32_t kBenchSeq = 42; // An EscrowFinish carrying a two-element memo array: something for the nested-field getters to // walk to and the array-length getters to count. -inline TxAssembler -benchMemoTx() -{ - auto assembler = escrowFinishTx(benchLedger().ledger, benchAlice()); - assembler.build = [inner = std::move(assembler.build)](STObject& obj) { - inner(obj); - auto memos = STArray{}; - memos.push_back(makeMemo(RealHostFixture::toBytes("hello"))); - memos.push_back(makeMemo(RealHostFixture::toBytes("world"))); - obj.setFieldArray(sfMemos, memos); - }; - return assembler; -} +TxAssembler +benchMemoTx(); // `sfMemos[0].sfMemoData` — a two-step locator path, the shape the nested getters are priced for. -inline FieldLocator -benchMemoLocator() -{ - return FieldLocator{{sfMemos.getCode(), 0, sfMemoData.getCode()}}; -} +FieldLocator +benchMemoLocator(); // --------------------------------------------------------------------------- // Hosts // --------------------------------------------------------------------------- // The default: transaction carries the memo array, current object is Alice's account root. -inline WasmHost -benchHost() -{ - auto assembler = benchMemoTx(); - return benchLedger().makeHost( - keylet::account(benchAlice().id()), assembler.type, std::move(assembler.build)); -} +WasmHost +benchHost(); // The same, with Alice's account root pinned to slot 1, for the `le_*` getters that read // through a cache slot rather than the current object. -inline WasmHost -benchCachedHost() -{ - auto host = benchHost(); - (void)host->cacheLedgerObj(keylet::account(benchAlice().id()).key, 1); - return host; -} +WasmHost +benchCachedHost(); // An account root has no arrays, so the array-length getters that read a *ledger object* need a // different one. A signer list has `sfSignerEntries`; without it those calls would answer // `FieldNotFound` and the benchmark would time the rejection instead of the work. -inline Account const& -benchSignerListOwner() -{ - static auto const kValue = [] { - auto const acct = benchLedger().fund("benchSigners"); - benchLedger().makeSignerList(acct, 2, {{benchAlice(), 1}, {benchBob(), 1}}); - return acct; - }(); - return kValue; -} +Account const& +benchSignerListOwner(); // Current object is the signer list. -inline WasmHost -benchSignerListHost() -{ - auto assembler = bareTx(); - return benchLedger().makeHost( - keylet::signerList(benchSignerListOwner().id()), - assembler.type, - std::move(assembler.build)); -} +WasmHost +benchSignerListHost(); // Signer list pinned to slot 1. -inline WasmHost -benchCachedSignerListHost() -{ - auto assembler = bareTx(); - auto host = benchLedger().makeHost( - keylet::account(AccountID{}), assembler.type, std::move(assembler.build)); - (void)host->cacheLedgerObj(keylet::signerList(benchSignerListOwner().id()).key, 1); - return host; -} +WasmHost +benchCachedSignerListHost(); // A real escrow, created through the real transactor — the current object for `home_le_field`, // which is the one getter whose cost depends on the object it reads rather than its arguments. -inline Keylet const& -benchEscrow() -{ - static auto const kValue = [] { - auto const ownerSeq = benchLedger().ledger.getAccountRoot(benchAlice().id()).getSequence(); - benchLedger().ledger.submit( - transactions::EscrowCreateBuilder{benchAlice().id(), benchBob().id(), XRP(100)} - .setFinishAfter(900'000'000), - benchAlice()); - benchLedger().ledger.close(); - return keylet::escrow(benchAlice().id(), SeqProxy::rawSequence(ownerSeq)); - }(); - return kValue; -} +Keylet const& +benchEscrow(); -inline WasmHost -benchEscrowHost() -{ - return benchLedger().makeHost(benchEscrow()); -} +WasmHost +benchEscrowHost(); // --------------------------------------------------------------------------- // Inputs that need building @@ -182,17 +114,11 @@ benchEscrowHost() // Canonical float operands. Zeroed bytes decode as a non-canonical float and would be refused // before any arithmetic ran, so the whole family shares these two known-good values. -inline Slice -benchFloatX() -{ - return FloatTest::slice(FloatTest::kPi); -} +Slice +benchFloatX(); -inline Slice -benchFloatY() -{ - return FloatTest::slice(FloatTest::kTwo); -} +Slice +benchFloatY(); // Rounding mode 0 throughout the float family: modes select a tie-breaking rule, not a different // algorithm, so they do not move the cost, and pinning one keeps the fourteen comparable. @@ -200,21 +126,12 @@ inline constexpr std::int32_t kBenchMode = 0; // A signed message for `check_sig`, produced once: signing is far more expensive than the // verification being measured, so it must not happen inside the timed loop. -inline SignedMessage const& -benchSignedMessage() -{ - static auto const kValue = signMessage("the quick brown fox jumps over the lazy dog"); - return kValue; -} +SignedMessage const& +benchSignedMessage(); // A well-formed NFToken id with the fixture's known taxon, flags, fee and sequence baked in, so // the id-extractor getters have real fields to pull out rather than zeros. -inline uint256 const& -benchNftId() -{ - // `makeNftId` is a static member, so no fixture instance is needed to reach it. - static auto const kValue = NFTTest::makeNftId(benchAlice().id()); - return kValue; -} +uint256 const& +benchNftId(); } // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/WasmBench.cpp b/src/tests/libxrpl/tx/wasm/WasmBench.cpp new file mode 100644 index 0000000000..cbf2f93529 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/WasmBench.cpp @@ -0,0 +1,210 @@ +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace xrpl::test::bench { + +int +callsWithinTransferBudget(std::int64_t bytesPerCall) +{ + if (bytesPerCall <= 0) + return kCallsPerRun; + auto const affordable = (kTransferLimitBytes / 2) / bytesPerCall; + return static_cast(std::clamp(affordable, 16, kCallsPerRun)); +} + +std::string +dataSegment(int offset, std::span bytes) +{ + return std::string{" (data (i32.const "} + std::to_string(offset) + ") \"" + + watEscaped(bytes) + "\")\n"; +} + +std::string +dataSegment(int offset, Bytes const& bytes) +{ + return dataSegment(offset, std::span{bytes.data(), bytes.size()}); +} + +std::string +makeLoopWat(std::string_view imports, std::string_view data, std::string_view body, int count) +{ + return std::string{"(module\n"} + std::string{imports} + + R"wat( + (memory (export "memory") 1) +)wat" + std::string{data} + + R"wat( + (func (export "escrow_finish") (result i32) + (local $i i32) + (local $r i32) + (local.set $i (i32.const )wat" + + std::to_string(count) + R"wat()) + (block $done + (loop $again + (br_if $done (i32.eqz (local.get $i))) + (local.set $r )wat" + + std::string{body} + R"wat() + (local.set $i (i32.sub (local.get $i) (i32.const 1))) + (br $again))) + (local.get $r))) +)wat"; +} + +Timing +timeRun(HostFunctions& host, Bytes const& wasm) +{ + auto const start = std::chrono::steady_clock::now(); + auto outcome = runEscrowWasm(wasm, host, kBenchGas); + auto const elapsed = std::chrono::steady_clock::now() - start; + + benchmark::DoNotOptimize(outcome); + return { + .seconds = std::chrono::duration(elapsed).count(), + .gas = outcome.has_value() ? outcome->cost : std::int64_t{0}}; +} + +double +secondsPerGas() +{ + static double const kValue = [] { + // A couple of guest instructions per iteration, no memory traffic, nothing the + // engine can fold away. + static constexpr std::string_view kBody = "(i32.add (local.get $r) (i32.const 1))"; + auto const busy = assembleWat(makeLoopWat("", "", kBody, kCallsPerRun)); + auto const idle = assembleWat(makeLoopWat("", "", kBody, 0)); + + BenchFixture fixture; + + // Warm the instruction cache and the allocator before the pairs that count, so + // the first-run penalty does not land on one side of the subtraction. + for (int i = 0; i < 8; ++i) + { + timeRun(*fixture.makeHost(), busy); + timeRun(*fixture.makeHost(), idle); + } + + // Best-of over several pairs: the minimum is the run least disturbed by the + // scheduler, which is the honest floor for what this machine can do. + auto best = std::numeric_limits::max(); + auto gasDelta = std::int64_t{1}; + for (int i = 0; i < 32; ++i) + { + auto hotHost = fixture.makeHost(); + auto const hot = timeRun(*hotHost, busy); + auto coldHost = fixture.makeHost(); + auto const cold = timeRun(*coldHost, idle); + auto const delta = hot.seconds - cold.seconds; + if (delta > 0.0 && delta < best) + { + best = delta; + gasDelta = std::max(std::int64_t{1}, hot.gas - cold.gas); + } + } + return best == std::numeric_limits::max() ? 0.0 + : best / static_cast(gasDelta); + }(); + return kValue; +} + +double +declaredGas(std::string_view wasmName) +{ + return static_cast( + rs::wasm_testkit::declared_gas(rust::Str{wasmName.data(), wasmName.size()})); +} + +double +crossingFloorGas() +{ + static double const kValue = [] { + static constexpr std::string_view kImport = + R"( (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) +)"; + static constexpr std::string_view kBody = "(call $ldgr_index (i32.const 0) (i32.const 4))"; + + auto const loaded = assembleWat(makeLoopWat(kImport, "", kBody, kCallsPerRun)); + auto const baseline = assembleWat(makeLoopWat(kImport, "", kBody, 0)); + + BenchFixture fixture; + + auto best = std::numeric_limits::max(); + for (int i = 0; i < 16; ++i) + { + auto hotHost = fixture.makeHost(); + auto const hot = timeRun(*hotHost, loaded); + auto coldHost = fixture.makeHost(); + auto const cold = timeRun(*coldHost, baseline); + + auto const perCall = (hot.seconds - cold.seconds) / kCallsPerRun; + if (perCall > 0.0 && perCall < best) + best = perCall; + } + if (best == std::numeric_limits::max()) + return 0.0; + + // The impl side is the same call without the VM. Subtracting it leaves the crossing. + auto implSeconds = std::numeric_limits::max(); + auto host = fixture.makeHost(); + for (int i = 0; i < 16; ++i) + { + auto const start = std::chrono::steady_clock::now(); + for (int c = 0; c < kCallsPerRun; ++c) + { + auto result = host->getLedgerSqn(); + benchmark::DoNotOptimize(result); + } + auto const elapsed = std::chrono::steady_clock::now() - start; + implSeconds = std::min( + implSeconds, std::chrono::duration(elapsed).count() / kCallsPerRun); + } + + auto const perGas = secondsPerGas(); + return perGas > 0.0 ? std::max(0.0, best - implSeconds) / perGas : 0.0; + }(); + return kValue; +} + +void +report( + benchmark::State& state, + double secondsPerCall, + double chargedGas, + std::string_view wasmName, + bool throughVm) +{ + auto const perGas = secondsPerGas(); + auto const implied = perGas > 0.0 ? secondsPerCall / perGas : 0.0; + auto const suggested = throughVm ? implied : implied + crossingFloorGas(); + + state.counters["implied_gas"] = implied; + state.counters["ns_per_call"] = secondsPerCall * 1e9; + state.counters["charged_gas"] = chargedGas; + state.counters["perf_counters"] = kPerfCountersAvailable ? 1 : 0; + + if (wasmName.empty()) + return; + + auto const declared = declaredGas(wasmName); + state.counters["declared_gas"] = declared; + state.counters["suggested_gas"] = suggested; + // Above 1: the table charges more than the work costs. Below 1: underpriced, which is the + // direction that matters — an underpriced call is one a contract can buy too cheaply. + state.counters["price_ratio"] = suggested > 0.0 ? declared / suggested : 0.0; +} + +} // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/WasmBench.h b/src/tests/libxrpl/tx/wasm/WasmBench.h index 7c2d0f64fd..88c8693c34 100644 --- a/src/tests/libxrpl/tx/wasm/WasmBench.h +++ b/src/tests/libxrpl/tx/wasm/WasmBench.h @@ -7,12 +7,10 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -123,14 +121,8 @@ inline constexpr std::int64_t kTransferLimitBytes = 1 << 20; // an output region written — and the budget counts both. A size-swept case passes this as // its call count so the large end of the range does not silently turn into an error // benchmark; per-call numbers stay comparable across counts, which is what the report shows. -inline int -callsWithinTransferBudget(std::int64_t bytesPerCall) -{ - if (bytesPerCall <= 0) - return kCallsPerRun; - auto const affordable = (kTransferLimitBytes / 2) / bytesPerCall; - return static_cast(std::clamp(affordable, 16, kCallsPerRun)); -} +int +callsWithinTransferBudget(std::int64_t bytesPerCall); // True when Google Benchmark was built with libpfm and `--benchmark_perf_counters` will // work. Reported as a counter so a JSON report records which mode produced it. @@ -170,18 +162,11 @@ struct Timing // input is in place before the timed loop starts and the loop measures the host call rather // than the guest arranging its arguments. See `watEscaped` in WasmRun.h for why zeroed // memory will not do. -inline std::string -dataSegment(int offset, std::span bytes) -{ - return std::string{" (data (i32.const "} + std::to_string(offset) + ") \"" + - watEscaped(bytes) + "\")\n"; -} +std::string +dataSegment(int offset, std::span bytes); -inline std::string -dataSegment(int offset, Bytes const& bytes) -{ - return dataSegment(offset, std::span{bytes.data(), bytes.size()}); -} +std::string +dataSegment(int offset, Bytes const& bytes); // A contract that runs `body` `count` times and returns the last result. // @@ -193,29 +178,8 @@ dataSegment(int offset, Bytes const& bytes) // // `data` holds any `dataSegment` calls the case needs; it goes after the memory // declaration that gives those segments something to write into. -inline std::string -makeLoopWat(std::string_view imports, std::string_view data, std::string_view body, int count) -{ - return std::string{"(module\n"} + std::string{imports} + - R"wat( - (memory (export "memory") 1) -)wat" + std::string{data} + - R"wat( - (func (export "escrow_finish") (result i32) - (local $i i32) - (local $r i32) - (local.set $i (i32.const )wat" + - std::to_string(count) + R"wat()) - (block $done - (loop $again - (br_if $done (i32.eqz (local.get $i))) - (local.set $r )wat" + - std::string{body} + R"wat() - (local.set $i (i32.sub (local.get $i) (i32.const 1))) - (br $again))) - (local.get $r))) -)wat"; -} +std::string +makeLoopWat(std::string_view imports, std::string_view data, std::string_view body, int count); // Run pre-assembled `wasm` once through the real VM, reporting wall time and gas. // @@ -223,18 +187,8 @@ makeLoopWat(std::string_view imports, std::string_view data, std::string_view bo // test-only convenience from the `wasm_testkit` crate, not something a validator ever // does. Compilation *is* inside, because a validator does pay it — but it is identical // between a module and its baseline, so the subtraction removes it. -inline Timing -timeRun(HostFunctions& host, Bytes const& wasm) -{ - auto const start = std::chrono::steady_clock::now(); - auto outcome = runEscrowWasm(wasm, host, kBenchGas); - auto const elapsed = std::chrono::steady_clock::now() - start; - - benchmark::DoNotOptimize(outcome); - return { - .seconds = std::chrono::duration(elapsed).count(), - .gas = outcome.has_value() ? outcome->cost : std::int64_t{0}}; -} +Timing +timeRun(HostFunctions& host, Bytes const& wasm); // Seconds of wall time one unit of gas buys on this machine. // @@ -246,60 +200,16 @@ timeRun(HostFunctions& host, Bytes const& wasm) // function look cheap by comparison. // // Computed once per process and cached: it describes the machine, not the case. -inline double -secondsPerGas() -{ - static double const kValue = [] { - // A couple of guest instructions per iteration, no memory traffic, nothing the - // engine can fold away. - static constexpr std::string_view kBody = "(i32.add (local.get $r) (i32.const 1))"; - auto const busy = assembleWat(makeLoopWat("", "", kBody, kCallsPerRun)); - auto const idle = assembleWat(makeLoopWat("", "", kBody, 0)); - - BenchFixture fixture; - - // Warm the instruction cache and the allocator before the pairs that count, so - // the first-run penalty does not land on one side of the subtraction. - for (int i = 0; i < 8; ++i) - { - timeRun(*fixture.makeHost(), busy); - timeRun(*fixture.makeHost(), idle); - } - - // Best-of over several pairs: the minimum is the run least disturbed by the - // scheduler, which is the honest floor for what this machine can do. - auto best = std::numeric_limits::max(); - auto gasDelta = std::int64_t{1}; - for (int i = 0; i < 32; ++i) - { - auto hotHost = fixture.makeHost(); - auto const hot = timeRun(*hotHost, busy); - auto coldHost = fixture.makeHost(); - auto const cold = timeRun(*coldHost, idle); - auto const delta = hot.seconds - cold.seconds; - if (delta > 0.0 && delta < best) - { - best = delta; - gasDelta = std::max(std::int64_t{1}, hot.gas - cold.gas); - } - } - return best == std::numeric_limits::max() ? 0.0 - : best / static_cast(gasDelta); - }(); - return kValue; -} +double +secondsPerGas(); // What the gas table says a host function costs, by its guest import name. // // Read from the declaration through the `wasm_testkit` bridge rather than transcribed into // C++: 61 copied constants would drift from `crates/xrpl-host-functions/src/lib.rs` the first // time a price changed, and drift *silently*, because a benchmark has nothing to fail. -inline double -declaredGas(std::string_view wasmName) -{ - return static_cast( - rs::wasm_testkit::declared_gas(rust::Str{wasmName.data(), wasmName.size()})); -} +double +declaredGas(std::string_view wasmName); // The gas a host call costs before it does anything: region decode, bounds checks, the cxx hop. // @@ -310,56 +220,8 @@ declaredGas(std::string_view wasmName) // // This is what makes a *suggested* price possible for a function that has only an `Impl` case: // the impl measures the work, and this measures the toll every call pays on top of it. -inline double -crossingFloorGas() -{ - static double const kValue = [] { - static constexpr std::string_view kImport = - R"( (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) -)"; - static constexpr std::string_view kBody = "(call $ldgr_index (i32.const 0) (i32.const 4))"; - - auto const loaded = assembleWat(makeLoopWat(kImport, "", kBody, kCallsPerRun)); - auto const baseline = assembleWat(makeLoopWat(kImport, "", kBody, 0)); - - BenchFixture fixture; - - auto best = std::numeric_limits::max(); - for (int i = 0; i < 16; ++i) - { - auto hotHost = fixture.makeHost(); - auto const hot = timeRun(*hotHost, loaded); - auto coldHost = fixture.makeHost(); - auto const cold = timeRun(*coldHost, baseline); - - auto const perCall = (hot.seconds - cold.seconds) / kCallsPerRun; - if (perCall > 0.0 && perCall < best) - best = perCall; - } - if (best == std::numeric_limits::max()) - return 0.0; - - // The impl side is the same call without the VM. Subtracting it leaves the crossing. - auto implSeconds = std::numeric_limits::max(); - auto host = fixture.makeHost(); - for (int i = 0; i < 16; ++i) - { - auto const start = std::chrono::steady_clock::now(); - for (int c = 0; c < kCallsPerRun; ++c) - { - auto result = host->getLedgerSqn(); - benchmark::DoNotOptimize(result); - } - auto const elapsed = std::chrono::steady_clock::now() - start; - implSeconds = std::min( - implSeconds, std::chrono::duration(elapsed).count() / kCallsPerRun); - } - - auto const perGas = secondsPerGas(); - return perGas > 0.0 ? std::max(0.0, best - implSeconds) / perGas : 0.0; - }(); - return kValue; -} +double +crossingFloorGas(); // Attach the calibration counters to a finished case. // @@ -372,33 +234,13 @@ crossingFloorGas() // declaration. For a `ThroughVm` case that is simply what was measured, since the guest already // paid the crossing. For an `Impl` case the crossing has to be added back, because a guest // cannot make the call without it. -inline void +void report( benchmark::State& state, double secondsPerCall, double chargedGas, std::string_view wasmName, - bool throughVm) -{ - auto const perGas = secondsPerGas(); - auto const implied = perGas > 0.0 ? secondsPerCall / perGas : 0.0; - auto const suggested = throughVm ? implied : implied + crossingFloorGas(); - - state.counters["implied_gas"] = implied; - state.counters["ns_per_call"] = secondsPerCall * 1e9; - state.counters["charged_gas"] = chargedGas; - state.counters["perf_counters"] = kPerfCountersAvailable ? 1 : 0; - - if (wasmName.empty()) - return; - - auto const declared = declaredGas(wasmName); - state.counters["declared_gas"] = declared; - state.counters["suggested_gas"] = suggested; - // Above 1: the table charges more than the work costs. Below 1: underpriced, which is the - // direction that matters — an underpriced call is one a contract can buy too cheaply. - state.counters["price_ratio"] = suggested > 0.0 ? declared / suggested : 0.0; -} + bool throughVm); // Measure a host function *through the whole stack* — guest, VM, marshalling, real impl, // real ledger — with everything but the host calls subtracted away. diff --git a/src/tests/libxrpl/tx/wasm/WasmRun.cpp b/src/tests/libxrpl/tx/wasm/WasmRun.cpp new file mode 100644 index 0000000000..b22bf9ea0f --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/WasmRun.cpp @@ -0,0 +1,52 @@ +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace xrpl::test { + +Bytes +assembleWat(std::string_view wat) +{ + auto const wasm = rs::wasm_testkit::compile_wat(rust::Str{wat.data(), wat.size()}); + return Bytes{wasm.begin(), wasm.end()}; +} + +std::string +watEscaped(std::span bytes) +{ + static constexpr char kHex[] = "0123456789abcdef"; + auto out = std::string{}; + out.reserve(bytes.size() * 3); + for (auto const byte : bytes) + { + out += '\\'; + out += kHex[byte >> 4]; + out += kHex[byte & 0x0F]; + } + return out; +} + +std::string +watEscaped(Bytes const& bytes) +{ + return watEscaped(std::span{bytes.data(), bytes.size()}); +} + +std::expected +runWat(HostFunctions& host, std::string_view wat, std::int64_t gas, std::string_view entryPoint) +{ + return runEscrowWasm(assembleWat(wat), host, gas, entryPoint); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/WasmRun.h b/src/tests/libxrpl/tx/wasm/WasmRun.h index ac016afe55..a67d784bb6 100644 --- a/src/tests/libxrpl/tx/wasm/WasmRun.h +++ b/src/tests/libxrpl/tx/wasm/WasmRun.h @@ -4,9 +4,6 @@ #include #include -#include -#include - #include #include #include @@ -22,12 +19,8 @@ inline constexpr std::int64_t kAmpleGas = 100'000; // itself refuses text (a text assembler on the consensus path would make a transaction's // validity a build flag), so this is where a WAT string becomes something runnable. Throws // `rust::Error` on a typo, which gtest reports against the test that holds it. -inline Bytes -assembleWat(std::string_view wat) -{ - auto const wasm = rs::wasm_testkit::compile_wat(rust::Str{wat.data(), wat.size()}); - return Bytes{wasm.begin(), wasm.end()}; -} +Bytes +assembleWat(std::string_view wat); // `bytes` as the escape sequence a WAT string literal wants (`\aa\bb...`), for seeding a // contract's memory through a `(data ...)` segment. @@ -36,38 +29,20 @@ assembleWat(std::string_view wat) // all-zero account id is `InvalidAccount`, an all-zero float is non-canonical. A contract // that needs real bytes to work on gets them here, once at instantiation, rather than // building them out of `i32.store` instructions. -inline std::string -watEscaped(std::span bytes) -{ - static constexpr char kHex[] = "0123456789abcdef"; - auto out = std::string{}; - out.reserve(bytes.size() * 3); - for (auto const byte : bytes) - { - out += '\\'; - out += kHex[byte >> 4]; - out += kHex[byte & 0x0F]; - } - return out; -} +std::string +watEscaped(std::span bytes); -inline std::string -watEscaped(Bytes const& bytes) -{ - return watEscaped(std::span{bytes.data(), bytes.size()}); -} +std::string +watEscaped(Bytes const& bytes); // Assemble and run `wat`'s `entryPoint` through the real VM, servicing host calls through // `host` — a mock (`MockVmTest`) or the real impl over a ledger (`RealVmTest`). The one // host-agnostic harness both fixtures inject their host into. -inline std::expected +std::expected runWat( HostFunctions& host, std::string_view wat, std::int64_t gas = kAmpleGas, - std::string_view entryPoint = escrowFunctionName) -{ - return runEscrowWasm(assembleWat(wat), host, gas, entryPoint); -} + std::string_view entryPoint = escrowFunctionName); } // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp b/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp index f876a8d25a..44a6013d78 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp @@ -13,21 +13,14 @@ namespace xrpl::test { // The keylet -> cache -> read round trip: the only place a contract's host calls depend on -// each other. -// -// Every other e2e case here is one call in isolation. This one is three, and each consumes -// what the last produced: `accountroot_id` computes a key into guest memory, `cache_le` +// each other. Every other e2e case here is one call in isolation. This one is three, and each +// consumes what the last produced: `accountroot_id` computes a key into guest memory, `cache_le` // hands those same bytes back to the host and answers with a slot number, and `le_field` // uses that slot to read the object. The slot table is the one piece of host state that // outlives a single call, so this is the only test at any layer that can catch the two ends // of that state disagreeing — `host_calls` mocks the host, so its slot numbers are whatever // the mock was told to return, and `host_functions` calls the impl directly, so its slots // never cross the guest boundary at all. -// -// It is also the shape that would have caught the `seq`-as-region bug class described in -// ../README.md: a key computed by one call and consumed by another only works if both ends -// agree byte for byte, and here the ledger itself is the judge — a wrong key simply fails -// to find the account. struct CacheLedgerObjE2e : RealVmTest { }; @@ -35,12 +28,6 @@ struct CacheLedgerObjE2e : RealVmTest TEST_F(CacheLedgerObjE2e, ContractComputesAKeyCachesTheObjectAndReadsItsField) { auto const owner = fund("owner"); - - // Memory: the 20-byte account at 0, the computed 32-byte keylet at 64, the field bytes - // read back at 128. Regions are disjoint so no call overwrites another's input. - // - // The contract returns a negative host error code the moment any step fails, so a - // failure names the step that broke rather than surfacing as a wrong byte count. auto const wat = std::string{R"wat( (module (import "host_lib" "accountroot_id" (func $accountroot_id (param i32 i32 i32 i32) (result i32))) diff --git a/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp b/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp index 2aebbb93ad..097118a521 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp @@ -12,7 +12,6 @@ namespace xrpl::test { // The only host function that writes to *two* output regions, and so the only place the // "one call, one answer" assumption in every other marshalling path is not what happens. -// // `float_to_mant_exp` splits a float into an eight-byte mantissa and a four-byte exponent, // each into its own guest buffer, and answers with a status rather than a byte count. Two // regions means two independent bounds checks, two writes, and an ordering between them — @@ -55,9 +54,10 @@ TEST_F(FloatToMantExpE2e, ContractReadsBothHalvesOfASplitFloat) // flip wrong is exactly the convention mismatch this layer exists to catch, and a // hard-coded constant would hide it. auto mantissa = std::int64_t{0}; - for (auto i = 0; i < 8; ++i) + for (auto i = 0U; i < 8; ++i) + { mantissa = (mantissa << 8) | FloatTest::kPi[i]; - + } EXPECT_EQ(outcome->result, static_cast(mantissa & 0xFFFFFFFF)); } diff --git a/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp b/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp index 6df9842d3c..aaa9f6547e 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp @@ -13,17 +13,12 @@ namespace xrpl::test { // The error channel, driven by a real failure rather than a mock's canned one. -// // Every other e2e case here proves a success path. But a contract spends most of its life // reacting to codes, and the path a *real* error takes is different from the one a mock // error takes: the impl returns a `HostFunctionError`, `HostContext` turns it into a wire // code, and the engine hands that back to the guest as a negative i32 without disturbing the // run. `host_calls` proves the middle step against a mock that was *told* to fail; nothing // until now has proved that a real impl's real failure comes out the far end intact. -// -// The distinction matters because the two halves are separately enumerated: a code the impl -// can return but the bridge does not map, or maps to a different number, is invisible to -// both of the other layers. struct HostErrorE2e : RealVmTest { }; diff --git a/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp b/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp index 3dba1521fb..d998b8a826 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp @@ -8,13 +8,7 @@ namespace xrpl::test { // A single contract that tours several host functions end to end — a ledger-header read, the -// base fee, a hash, a keylet, and a data write — returning 1 only if every call succeeds. This -// is the recognizable shape of the old `all_host_functions` guest tour, kept as one test. -// -// The per-function detail lives in `host_functions/` (each function's answer vs. a real ledger) -// and `host_calls/` (each function's wire marshalling); this proves that a realistic multi-call -// contract runs through the whole real stack — VM + HostContext + real impl + real ledger — -// with the pieces agreeing. See ../README.md for the layering rationale. +// base fee, a hash, a keylet, and a data write — returning 1 only if every call succeeds. struct HostFunctionTourE2e : RealVmTest { }; @@ -24,7 +18,7 @@ TEST_F(HostFunctionTourE2e, AContractTouringManyHostFunctionsSucceeds) // Each call must return >= 0 (a byte count, i.e. success); the guest returns the first // negative error code, or 1 if the whole tour succeeds. Output regions are disjoint so no // call clobbers another, and buffers are generous so exact value sizes don't matter. - static constexpr std::string_view kWat = R"wat( + static constexpr auto kWat = std::string_view{R"wat( (module (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) (import "host_lib" "base_fee" (func $base_fee (param i32 i32) (result i32))) @@ -45,7 +39,7 @@ TEST_F(HostFunctionTourE2e, AContractTouringManyHostFunctionsSucceeds) (local.set $r (call $set_data (i32.const 0) (i32.const 8))) (if (i32.lt_s (local.get $r) (i32.const 0)) (then (return (local.get $r)))) (i32.const 1))) -)wat"; +)wat"}; auto const outcome = run(kWat); ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); diff --git a/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp b/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp index 9211dc3a86..b0a565d030 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp @@ -8,9 +8,7 @@ namespace xrpl::test { -// The real ledger's sequence reaches a contract through the whole stack — real VM, real -// `HostContext` marshalling, real `WasmHostFunctionsImpl`, real `TxTest` ledger — proving the -// pieces agree end to end, not just in isolation. +// The real ledger's sequence. struct LedgerSqnE2e : RealVmTest { }; @@ -18,14 +16,14 @@ struct LedgerSqnE2e : RealVmTest TEST_F(LedgerSqnE2e, ContractReadsTheRealLedgerSequence) { // Ask the host for the ledger sequence into offset 0, then return the i32 stored there. - static constexpr std::string_view kWat = R"wat( + static constexpr auto kWat = std::string_view{R"wat( (module (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) (memory (export "memory") 1) (func (export "escrow_finish") (result i32) (drop (call $ldgr_index (i32.const 0) (i32.const 4))) (i32.load (i32.const 0)))) -)wat"; +)wat"}; auto const outcome = run(kWat); ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); diff --git a/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp b/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp index 01786ae777..2989eadb26 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp @@ -7,10 +7,7 @@ namespace xrpl::test { -// A contract writes its data field end to end — the one mutation a contract can make. The -// guest calls `set_data` over a region of its memory; the real impl copies it into host-owned -// storage and reports the byte count. `host_calls` proves the marshalling with a mock; this -// proves the real impl accepts the write through the whole stack. +// A contract writes its data field end to end. struct SetDataE2e : RealVmTest { }; @@ -18,13 +15,13 @@ struct SetDataE2e : RealVmTest TEST_F(SetDataE2e, ContractWritesItsData) { // `set_data` over 8 bytes of (zero-initialized) memory returns the byte count it stored. - static constexpr std::string_view kWat = R"wat( + static constexpr auto kWat = std::string_view{R"wat( (module (import "host_lib" "set_data" (func $set_data (param i32 i32) (result i32))) (memory (export "memory") 1) (func (export "escrow_finish") (result i32) (call $set_data (i32.const 0) (i32.const 8)))) -)wat"; +)wat"}; auto const outcome = run(kWat); ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); diff --git a/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp b/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp index 26aeaf6462..0d882927b7 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp @@ -13,10 +13,7 @@ namespace xrpl::test { -// A contract reads a field of its transaction end to end. The fixture builds the tx (here an -// MPTokenIssuanceCreate carrying an asset scale); the guest asks `tx_field` for it and returns -// the value, proving the transaction's bytes reach the guest through the real VM + impl. A -// different source than the ledger reads — the transaction rather than a ledger object. +// A contract reads a field of its transaction end to end. struct TxFieldE2e : RealVmTest { }; @@ -25,7 +22,7 @@ TEST_F(TxFieldE2e, ContractReadsAFieldOfItsTransaction) { auto const owner = Account{"owner"}; ledger.createAccount(owner, XRP(1000)); - constexpr std::uint8_t kScale = 8; + static constexpr auto kScale = std::uint8_t{8}; auto const tx = mptIssuanceCreateTx(owner, kScale); // Ask the tx for `sfAssetScale` (a single byte) and return the i32 the guest loads — the diff --git a/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp b/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp index 75b1da1b37..c30346b009 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp @@ -16,18 +16,6 @@ namespace xrpl::test { // The locator convention, end to end. -// -// A nested-field getter reaches its leaf through a *locator*: a path of little-endian i32 -// steps that the guest lays out in its own memory and the host walks. That is a wire format -// the two sides have to agree on byte for byte, and it is exactly the shape of convention -// that hid the `seq`-as-region bug (see ../README.md) — the kind that a mocked bridge test -// and a direct impl test can both pass while disagreeing with each other, because neither -// one ever has a real guest write the bytes that a real host reads. -// -// Here a real guest writes a two-step locator (`sfMemos`, index 0, `sfMemoData`) and the -// real impl walks it over a real transaction. `host_calls` covers the marshalling and -// `host_functions/TxNestedField.cpp` covers the traversal; this is the one that would catch -// them meaning different things by "a path of i32 steps". struct TxNestedFieldE2e : RealVmTest { // An EscrowFinish carrying a memo, so the locator has a real leaf to reach. @@ -52,10 +40,6 @@ TEST_F(TxNestedFieldE2e, ContractWalksALocatorToANestedTransactionField) auto const owner = fund("owner"); auto assembler = withMemo(owner); - // The locator is three i32 steps the guest stores itself: the array field, the index - // within it, then the field inside that element. Writing them with `i32.store` rather - // than a data segment is the point — the guest's own little-endian layout is what the - // host has to agree with. auto const wat = std::string{R"wat( (module (import "host_lib" "tx_inner" (func $tx_inner (param i32 i32 i32 i32) (result i32))) diff --git a/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp index a79062db51..e8d71b1e30 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp @@ -7,17 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "accountroot_id"; - -// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type -// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its -// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing -// cost follows a call's shape, not which keylet it computes (see ../README.md). void accountKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"accountroot_id"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp index a6cf930b3d..dcd568b7c9 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp @@ -11,16 +11,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "amm_id"; - -// Declared 450 — a hundred above the keylet family's flat 350, and the only keylet whose input -// *length* selects between interpretations: 20 bytes is XRP, 24 an MPT, 40 an issue. That -// dispatch is the work the surcharge is paying for, so this case is whether it costs 100. void ammKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"amm_id"}; + auto const usd = Asset{Issue{toCurrency("USD"), benchAlice().id()}}; auto const xrp = Asset{xrpIssue()}; diff --git a/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp index e6c220fb8c..99a3e3f918 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp @@ -7,15 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "base_fee"; - -// Declared 60. A field of the current fee schedule; like the other header getters it should be -// far cheaper than its price, with the crossing accounting for nearly all of what a guest pays. void baseFeeImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"base_fee"}; + benchmarkImpl( state, kWasmName, [] { return benchHost(); }, [](auto& host) { return host.getBaseFee(); }); } diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp index 894cd29c91..065b521443 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp @@ -9,23 +9,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "cache_le"; - -// Declared 5000 — seventy times a field read, and the second-most expensive price in the table. -// -// The number is presumably set for a *cold* lookup: find an object in the ledger and pin it to a -// slot. But it is charged per call, and after the first call the view has the object cached, so -// a contract can arrange never to pay the cold cost again. This case measures the warm path. If -// the gap is large, 5000 is wrong in the common case; if it is small, it is wrong in the cold -// one. One number cannot be right for both. -// -// Re-caching the same key into the same slot is idempotent, which is what makes repeating it a -// measurement rather than a slot-table exhaustion test. void cacheLedgerObjImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"cache_le"}; + auto const key = keylet::account(benchAlice().id()).key; benchmarkImpl( diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp index 7f4d00e7f9..71e57b183d 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp @@ -7,17 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "check_id"; - -// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type -// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its -// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing -// cost follows a call's shape, not which keylet it computes (see ../README.md). void checkKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"check_id"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp index a63a515800..2d99b625b7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp @@ -4,37 +4,22 @@ #include #include +#include #include #include namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. constexpr std::string_view kWasmName = "check_sig"; -// Declared 300 — and the one host function with a documented pricing disagreement, which makes it -// the first one worth measuring. -// -// A prior C++ integration priced the same operation at 35000, a factor of over a hundred apart. -// One of those is wrong, and a signature verification underpriced by 100x is the cheapest -// denial-of-service a contract could buy: a secp256k1 verify, among the most expensive things the -// host can be asked to do, for the price of three hundred guest instructions. -// -// The pair settles it. `Impl` is the verification; `ThroughVm` adds the crossing for three input -// regions. If the two come out nearly equal, the cost is all verification and the crossing is -// noise beside it — which is itself the answer. - constexpr std::string_view kImport = R"( (import "host_lib" "check_sig" (func $check_sig (param i32 i32 i32 i32 i32 i32) (result i32))) )"; -// Message, signature and public key are all variable-length, so each gets a fixed offset with room -// to spare and the lengths come from the data itself. -constexpr int kMessageOffset = 0; -constexpr int kSignatureOffset = 256; -constexpr int kPubkeyOffset = 512; +constexpr std::int32_t kMessageOffset = 0; +constexpr std::int32_t kSignatureOffset = 256; +constexpr std::int32_t kPubkeyOffset = 512; void checkSignatureThroughVm(benchmark::State& state) diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp index d0e86ea5c0..ddfd84654d 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp @@ -9,16 +9,10 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "credential_id"; - -// Declared 350. Subject, issuer, and a variable-length credential type — the only keylet with an -// input whose size the guest chooses, so the only one where a flat price could be wrong for a -// reason other than the hash. Measured here at a typical length. void credentialKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"credential_id"}; static constexpr auto kType = std::string_view{"termsandconditions"}; benchmarkImpl( diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp index ad6b05c234..340ed964b6 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp @@ -9,15 +9,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "home_le_arr_len"; - -// Declared 40. Runs against a signer list rather than an account root, which has no arrays at -// all — a `FieldNotFound` answer would time the rejection instead of the count. void currentLedgerObjArrayLenImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"home_le_arr_len"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp index 03fa05f0fd..f163cdcf16 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp @@ -10,24 +10,7 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. constexpr std::string_view kWasmName = "home_le_field"; - -// Declared 70, barely above the 60 charged for reading the ledger sequence out of a header already -// in hand. But this one deserializes a field out of an `STObject`, and what that costs depends on -// the object's shape and on whether the read is served from the view's cache. A price set from a -// warm cache is a price an attacker can miss on purpose. -// -// The fixture runs against a real escrow created through the real transactor, so the object read -// is a real one. Note what that means for the number: after the first call the view has the object -// cached, so the thousand calls in a run measure the *warm* path. That is the honest floor, not -// the worst case; a cold-cache figure needs a fixture that evicts between calls, and is worth -// building before this particular 70 is trusted. -// -// This file carries the `ThroughVm` case for the field-code-in, bytes-out shape, shared with -// `tx_field` and `le_field`. - constexpr std::string_view kImport = R"( (import "host_lib" "home_le_field" (func $home_le_field (param i32 i32 i32) (result i32))) )"; diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp index d2ab63f73f..bc3857d55f 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp @@ -10,14 +10,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "home_le_inner_arr_len"; - -// Declared 70. A locator walk to the signer list's entries, then a count. void currentLedgerObjNestedArrayLenImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"home_le_inner_arr_len"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp index 6f6f702dde..f88a939c9c 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp @@ -10,16 +10,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "home_le_inner"; - -// Declared 110 against a direct read's 70 — the table's claim that walking a locator costs -// about half a field read again. A one-step locator like this one is the cheapest such walk, -// so it is the best case for that claim. void currentLedgerObjNestedFieldImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"home_le_inner"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp index 19887b789f..066efdedf4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp @@ -7,17 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "delegate_id"; - -// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type -// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its -// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing -// cost follows a call's shape, not which keylet it computes (see ../README.md). void delegateKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"delegate_id"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp index 9b73044d6a..0cb8f9a284 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp @@ -7,17 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "deposit_preauth_id"; - -// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type -// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its -// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing -// cost follows a call's shape, not which keylet it computes (see ../README.md). void depositPreauthKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"deposit_preauth_id"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp index 854a9603ac..26456e5293 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp @@ -7,17 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "did_id"; - -// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type -// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its -// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing -// cost follows a call's shape, not which keylet it computes (see ../README.md). void didKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"did_id"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp index 0989b7cb29..1d727f74cf 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp @@ -12,19 +12,8 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. constexpr std::string_view kWasmName = "escrow_id"; -// Declared 350, and the one keylet carrying a `ThroughVm` pair on behalf of all nineteen. -// -// It is the right representative because it is the shape with the extra wrinkle: its sequence -// number arrives as a four-byte little-endian *region*, not a scalar, so the crossing decodes two -// inputs rather than one (`read_u32_arg` in crates/xrpl-wasm-vm/src/register.rs). The gap between -// this pair and the floor in `Crossing.bench.cpp` therefore prices region decoding as well as the -// hash. The other eighteen are `Impl`-only — crossing cost follows a call's shape, not which -// keylet it computes. - constexpr std::string_view kImport = R"( (import "host_lib" "escrow_id" (func $escrow_id (param i32 i32 i32 i32 i32 i32) (result i32))) )"; @@ -35,12 +24,12 @@ constexpr std::string_view kBody = void escrowKeyletThroughVm(benchmark::State& state) { - // Account at 0, sequence at 32, answer at 64. An all-zero account would be `InvalidAccount` - // and the benchmark would measure the rejection instead of the keylet. static auto const kData = [] { auto seq = Bytes(4); - for (auto i = 0; i < 4; ++i) + for (auto i = 0U; i < 4; ++i) + { seq[i] = static_cast((kBenchSeq >> (8 * i)) & 0xFF); + } return dataSegment(0, RealHostFixture::toBytes(benchAlice().id())) + dataSegment(32, seq); }(); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp index 141f081ca8..e416c24c08 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp @@ -8,27 +8,12 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. constexpr std::string_view kWasmName = "float_add"; -// Declared 160. The float family's reference arithmetic: every other operation in the family is -// priced as a multiple of this one, so if this number is wrong the whole block shifts with it. -// -// It also carries the family's `ThroughVm` case for the ordinary two-operands-in, one-out shape. -// `FloatPower` covers the expensive end and `FloatToMantExp` the two-output shape; the other -// eleven are `Impl`-only, because crossing cost follows a call's shape rather than its arithmetic. - constexpr std::string_view kImport = R"( (import "host_lib" "float_add" (func $float_add (param i32 i32 i32 i32 i32 i32 i32) (result i32))) )"; -// x, y, out, then the rounding mode LAST: the wasm signature is not the trait's argument order. -// `float_add(x, y, mode, out)` in Rust becomes `(x_ptr, x_len, y_ptr, y_len, out_ptr, out_len, -// mode)` on the wire, because the macro expands each slice to its pointer/length pair in place and -// moves the scalars after the output region (`HostFunctionSpec::FloatAdd` in -// crates/xrpl-wasm-vm/src/register.rs). Getting this wrong passes a byte count as the mode and the -// host answers `FloatInputMalformed` — a fast rejection that looks like a plausible measurement. constexpr std::string_view kBody = "(call $float_add (i32.const 0) (i32.const 12) (i32.const 16) (i32.const 12) " "(i32.const 64) (i32.const 12) (i32.const 0))"; diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp index 9b52b5f002..3026159b9c 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp @@ -7,16 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "float_cmp"; - -// Declared 80 — cheaper than any arithmetic, and the only float call answering a scalar rather -// than 12 bytes. It still decodes two operands, which is what makes it a useful floor for what -// operand decoding alone costs. void floatCompareImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"float_cmp"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp index 9c24814694..a1f8387813 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp @@ -7,15 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "float_div"; - -// Declared 300, the same as `float_mult`. Division is usually the more expensive of the two, -// so pricing them identically is a claim worth checking. void floatDivideImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"float_div"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp index 8fa7533bf9..abad146607 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp @@ -7,15 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "float_from_int"; - -// Declared 100, the float family's floor. An integer becomes a normalized mantissa/exponent -// pair — no operand to decode first, which is what makes it the cheapest of the fourteen. void floatFromIntImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"float_from_int"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp index 66214577d6..5dc04e290e 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp @@ -7,15 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "float_from_mant_exp"; - -// Declared 100. Builds a float from parts the guest already split, so it is the inverse of -// `FloatToMantExp` and priced 30 below it. void floatFromMantExpImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"float_from_mant_exp"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp index 55bf5847e4..c3b24ee2ef 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp @@ -11,16 +11,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "float_from_stamount"; - -// Declared 150, the joint-highest of the float conversions. Unlike `float_from_int` it starts -// from a serialized ledger type, so it pays a parse before the conversion — which is what the -// 50% premium over `float_from_int`'s 100 is for. void floatFromStAmountImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"float_from_stamount"}; + auto const amount = STAmount{Issue{toCurrency("USD"), benchAlice().id()}, 1234567, -3}; benchmarkImpl( diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp index 1e25a9964b..e99507872d 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp @@ -11,16 +11,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "float_from_stnumber"; - -// Declared 150, the same as `float_from_stamount`. An `STNumber` is already a mantissa and an -// exponent, so this conversion has strictly less to do than one from an `STAmount` — pricing -// them identically is the claim under test. void floatFromStNumberImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"float_from_stnumber"}; + auto const number = STNumber{sfNumber, Number(3141592653589793, -15)}; benchmarkImpl( diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp index 6b70677dcb..861dadbb1f 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp @@ -7,15 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "float_from_uint"; - -// Declared 130 against `float_from_int`'s 100. The same conversion from an unsigned value, so -// the 30% surcharge is a claim about the wider range needing more normalization work. void floatFromUintImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"float_from_uint"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp index bef3a8a247..17688b44bc 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp @@ -7,16 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "float_mult"; - -// Declared 300, 1.875x `float_add`'s 160. A multiplication really is more work than an -// addition on a mantissa/exponent pair, so this ratio is one of the table's more defensible -// claims — and one of the easier ones to confirm. void floatMultiplyImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"float_mult"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp index 7232a73e5a..bd94fdc8b4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp @@ -8,20 +8,12 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. constexpr std::string_view kWasmName = "float_pow"; -// Declared 5500 — 34x `float_add`'s 160, and tied with `float_root` for the most expensive host -// function that is not a signature check. Since both take the same 12-byte operand over the same -// crossing, the entire 34x has to appear in the `Impl` number; the `ThroughVm` case is here to -// confirm the crossing is the same one `FloatAdd` pays, and so cannot be what the 34x is for. - constexpr std::string_view kImport = R"( (import "host_lib" "float_pow" (func $float_pow (param i32 i32 i32 i32 i32 i32) (result i32))) )"; -// As with `float_add`, the mode goes last: (x_ptr, x_len, n, out_ptr, out_len, mode). constexpr std::string_view kBody = "(call $float_pow (i32.const 0) (i32.const 12) (i32.const 7) " "(i32.const 64) (i32.const 12) (i32.const 0))"; diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp index cecd1360ef..6307ca2648 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp @@ -7,16 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "float_root"; - -// Declared 5500, tied with `float_pow` for the most expensive host function that is not a -// signature check. Tied is the thing to question: a root and a power are different algorithms, -// and one price for both is only right if they happen to cost the same. void floatRootImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"float_root"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp index 38ff054958..e5e8a9a05f 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp @@ -7,15 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "float_sub"; - -// Declared 160, identical to `float_add` — the same operation up to a sign. These two should -// measure the same, and if they do not, something other than the arithmetic is being counted. void floatSubtractImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"float_sub"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp index d7e3b57c6a..41fb345268 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp @@ -7,15 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "float_to_int"; - -// Declared 130. Decode a float, then round it to an integer under the given mode. Compare with -// `FloatFromInt` at 100 — the table says decoding an operand costs about 30. void floatToIntImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"float_to_int"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp index 46c80369b5..2deeb88ce2 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp @@ -8,15 +8,8 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. constexpr std::string_view kWasmName = "float_to_mant_exp"; -// Declared 130. The one call in the whole ABI that writes *two* output regions, so the one place -// the crossing does two bounds checks and two writes — which is why it carries a `ThroughVm` case -// despite being unremarkable arithmetic. Its gap over `floatToMantExpImpl` is the only measurement -// of what a second output region costs, and nothing else in the suite can supply it. - constexpr std::string_view kImport = R"( (import "host_lib" "float_to_mant_exp" (func $split (param i32 i32 i32 i32 i32 i32) (result i32))) )"; diff --git a/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp index 729c0eccae..f95101e5aa 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp @@ -8,23 +8,15 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "nft_uri"; - -// Declared 5000 against the five id-extractor getters' 60-70 — a 14x ratio that is at least the -// right sign, since this is the only NFT call that touches the ledger. It has to find the token's -// `NFTokenPage`, walk it, and copy out a variable-length URI, where its siblings just mask bits -// out of an id the guest already supplied. Whether 14x is the right *size* is what the gap between -// this case and `NFTIssuer.bench.cpp` answers. - void getNFTImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"nft_uri"}; + // A really minted token, so the lookup walks a real page rather than failing fast — a // not-found answer would measure the rejection instead of the work. static constexpr auto kUri = std::string_view{"ipfs://benchmark"}; - static Bench nft; + static auto nft = Bench{}; static auto const kOwner = nft.fund("benchNftOwner"); static auto const kMinted = nft.mintNFT(kOwner, kUri); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp index 487187c526..a10a911e40 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp @@ -10,33 +10,18 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. Both cases below -// share it — one price covers both forms, which is the thing being questioned. constexpr std::string_view kWasmName = "amendment_enabled"; -// A real registered amendment, so both forms resolve and measure a lookup that succeeds rather -// than one that fails fast. The same one `IsAmendmentEnabled.cpp` uses. -// -// A `std::string` because `getRegisteredFeature` takes one; the name form of the host call takes -// a `string_view`, so both spellings are needed and this is the one that converts to the other. std::string const& benchAmendment() { - static std::string const kValue = "TokenEscrow"; + static auto const kValue = std::string{"TokenEscrow"}; return kValue; } -// Declared 100 for *either* form, but the two forms do different work: by id is a set membership -// test against the ledger's rules, while by name has to resolve the name through -// `ServiceRegistry::getAmendmentTable().find()` first. One flat price for a lookup and a compare -// is exactly the kind of claim this suite exists to question, so both are measured. - void isAmendmentEnabledByIdImpl(benchmark::State& state) { - // `getRegisteredFeature` answers an optional; a missing amendment would make this case - // measure a lookup that fails rather than one that succeeds, so fail loudly instead. auto const feature = getRegisteredFeature(benchAmendment()); if (!feature.has_value()) { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp index e5e365f189..a3373c8d55 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp @@ -9,14 +9,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "le_arr_len"; - -// Declared 40. The signer list's entries counted through a cache slot. void ledgerObjArrayLenImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"le_arr_len"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp index f5c8286e27..b791ffa469 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp @@ -9,17 +9,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "le_field"; - -// Declared 70. The same read as `home_le_field`, but through a cache slot rather than the -// current object — one extra scalar and a slot-table lookup. There is deliberately no -// `ThroughVm` pair: `runEscrowWasm` asserts a clean host, so a benchmark cannot pre-cache a -// slot. `e2e/CacheLedgerObj.cpp` covers the cross-call behaviour instead. void ledgerObjFieldImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"le_field"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp index a823254080..3f2a732658 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp @@ -10,14 +10,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "le_inner_arr_len"; - -// Declared 70. The deepest read in the family: slot lookup, locator walk, then a count. void ledgerObjNestedArrayLenImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"le_inner_arr_len"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp index af8674d611..9c2367895f 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp @@ -10,15 +10,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "le_inner"; - -// Declared 110. A locator walk over a cached object: the nested read plus the slot lookup that -// `LedgerObjField` measures on its own. void ledgerObjNestedFieldImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"le_inner"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp index 996e3be67c..a95d0641be 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp @@ -7,15 +7,8 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. constexpr std::string_view kWasmName = "ldgr_index"; -// Declared 60, and the cheapest host call there is: no input, and the answer is a field of a -// header already in hand. That makes it the crossing's reference point — whatever the `ThroughVm` -// case costs above the `Impl` case is the floor price of leaving the guest, paid by all 61 -// functions before any of them does any work. `Crossing.bench.cpp` reads against these two. - constexpr std::string_view kImport = R"( (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) )"; diff --git a/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp index 57babcd929..55a371e08e 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp @@ -7,17 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "mpt_issuance_id"; - -// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type -// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its -// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing -// cost follows a call's shape, not which keylet it computes (see ../README.md). void mptokenIssuanceKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"mpt_issuance_id"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp index cfa88f71c4..618643e908 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp @@ -10,15 +10,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "mptoken_id"; - -// Declared 500, the highest in the keylet family. A 24-byte issuance id plus a 20-byte holder — -// more input bytes than its siblings, but not obviously 43% more work than the 350 ones. void mptokenKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"mptoken_id"}; + auto const mptid = makeMptID(1, benchAlice().id()); benchmarkImpl( diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp index 9f6eb9bf6b..5810f8439b 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp @@ -7,14 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "nft_flags"; - -// Declared 60. Pure extraction from the id — no ledger access. See `NFTIssuer.bench.cpp`. void nftFlagsImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"nft_flags"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp index 56a4d82340..a8880b3525 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp @@ -7,16 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "nft_issuer"; - -// Declared 70. An NFToken id encodes its issuer in its own 32 bytes, so this touches no ledger -// state: it is shifts and masks over a value the guest already handed over. Compare against -// `GetNFT`, declared 5000, which actually goes and finds the token. void nftIssuerImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"nft_issuer"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp index e1f67c3b05..bef68d7dbf 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp @@ -7,14 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "nft_serial"; - -// Declared 60. Pure extraction from the id — no ledger access. See `NFTIssuer.bench.cpp`. void nftSequenceImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"nft_serial"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp index 026d4f32a1..f27a5fbf0d 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp @@ -7,14 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "nft_taxon"; - -// Declared 60. Pure extraction from the id — no ledger access. See `NFTIssuer.bench.cpp`. void nftTaxonImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"nft_taxon"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp index 7fc52ca64f..0318557ce0 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp @@ -7,14 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "nft_xfer_fee"; - -// Declared 60. Pure extraction from the id — no ledger access. See `NFTIssuer.bench.cpp`. void nftTransferFeeImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"nft_xfer_fee"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp index e8a59b7121..1326979aab 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp @@ -7,17 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "nft_offer_id"; - -// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type -// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its -// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing -// cost follows a call's shape, not which keylet it computes (see ../README.md). void nftokenOfferKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"nft_offer_id"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp index 1e1dabc088..8884697a9d 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp @@ -7,17 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "offer_id"; - -// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type -// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its -// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing -// cost follows a call's shape, not which keylet it computes (see ../README.md). void offerKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"offer_id"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp index 25caf96cff..dd39bb06eb 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp @@ -7,17 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "oracle_id"; - -// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type -// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its -// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing -// cost follows a call's shape, not which keylet it computes (see ../README.md). void oracleKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"oracle_id"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp index 906d9a5a93..0b864f3971 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp @@ -7,16 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "parent_ldgr_hash"; - -// Declared 60, the same as the other header getters, but this one returns 32 bytes rather than -// 4 — and on some paths a parent hash is a lookup rather than a field read. If any of the four -// is secretly doing work, it is this one. void parentLedgerHashImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"parent_ldgr_hash"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp index d7a4397832..9b0b146ffb 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp @@ -7,16 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "parent_ldgr_time"; - -// Declared 60. No input, and the answer is a field of a header already in hand, so this should -// measure at essentially nothing and the crossing should dominate it entirely. Read against -// `Crossing.bench.cpp`, which uses `ldgr_index` — the same shape — as the crossing floor. void parentLedgerTimeImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"parent_ldgr_time"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp index 341e5b4bb4..1efd32715a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp @@ -7,17 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "paychan_id"; - -// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type -// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its -// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing -// cost follows a call's shape, not which keylet it computes (see ../README.md). void paychannelKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"paychan_id"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp index 3ec1699682..c268fc4be4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp @@ -7,17 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "permissioned_domain_id"; - -// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type -// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its -// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing -// cost follows a call's shape, not which keylet it computes (see ../README.md). void permissionedDomainKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"permissioned_domain_id"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp index ab73e82ad4..9c3f32115b 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp @@ -6,28 +6,16 @@ #include #include +#include #include #include namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. constexpr std::string_view kWasmName = "sha512_half"; -// Declared 2000 — a single flat price, no matter how many bytes it is asked to hash. Hashing is -// linear in its input, so the declaration can only be exactly right at one length; the `Range` -// here shows where that length is, and how far the flat price misses at the ends. -// -// What bounds the damage is `MAX_FIELD_BYTES` (crates/xrpl-wasm-vm/src/region.rs): no single value -// may cross the boundary in either direction above 1 KiB, `DataFieldTooLarge` otherwise. So the -// flat price is wrong over a 128x span, not an unbounded one — the worst a contract can extract is -// the ratio between hashing 1 KiB and hashing 8 bytes, both for 2000 gas. That is what this sweep -// puts a figure on, and why the range stops at 1024: past that the `ThroughVm` case cannot run at -// all, and comparing it against an `Impl` case that can would be measuring two different things. - -constexpr int kMaxBytes = 1024; +constexpr std::int16_t kMaxBytes = 1024; constexpr std::string_view kImport = R"( (import "host_lib" "sha512_half" (func $sha512_half (param i32 i32 i32 i32) (result i32))) diff --git a/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp index 59dec0ae8f..18776662e0 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp @@ -7,17 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "signers_id"; - -// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type -// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its -// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing -// cost follows a call's shape, not which keylet it computes (see ../README.md). void signerListKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"signers_id"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp index f3a4ba15a5..d4d79985ef 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp @@ -7,17 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "ticket_id"; - -// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type -// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its -// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing -// cost follows a call's shape, not which keylet it computes (see ../README.md). void ticketKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"ticket_id"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp index 87889da421..4858d54cd9 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp @@ -7,23 +7,9 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. constexpr std::string_view kWasmName = "trace"; - -// Declared 30, the cheapest price in the table, and the only host function that answers nothing. -// -// 30 is right for the case that matters: a validator with tracing off, where the call renders -// nothing and returns. But the same 30 is charged when the sink *is* enabled and the host formats -// a message and writes it. A contract cannot choose which node it runs on, so the price has to be -// set for the cheap case and the expensive one has to be a node's own problem. These two cases -// measure how far apart they are, which is how you decide whether that reasoning still holds. -// -// No `ThroughVm` case: `trace` has no result for the harness's `result >= 0` guard to check, and -// its input shape (two regions in, nothing out) is already priced by `Sha512Half.bench.cpp`. - -constexpr auto kMessage = std::string_view{"benchmark trace message"}; -constexpr auto kData = std::string_view{"0123456789abcdef"}; +constexpr std::string_view kMessage = "benchmark trace message"; +constexpr std::string_view kData = "0123456789abcdef"; // The path a validator actually runs: journal pointed at a null sink. void diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp index da4dc1f729..750d6956de 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp @@ -9,16 +9,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "trustline_id"; - -// Declared 400 against the family's 350. Three inputs rather than two — two accounts and a -// currency — so the surcharge prices one extra 20-byte value going into the hash. That is the -// most concrete per-input claim in the whole table, and the easiest to check. void trustLineKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"trustline_id"}; + auto const currency = toCurrency("USD"); benchmarkImpl( diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp index 251b6c42d4..63b2614f31 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp @@ -9,16 +9,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "tx_arr_len"; - -// Declared 40, the cheapest non-`trace` price in the table. Counting an array's elements does -// not serialize them, which is what justifies pricing it below a field read's 70 — this case -// and `TxField` together are whether that 40/70 split is the right size. void txArrayLenImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"tx_arr_len"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp index 23792b57d4..0001f59bcc 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp @@ -9,16 +9,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "tx_field"; - -// Declared 70. One `getFieldByCode` on the transaction being executed, then serialize the -// result. Its pair with `CurrentLedgerObjField` (same price, an object instead of a tx) shows -// whether the source matters to the cost; the declared table says it does not. void txFieldImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"tx_field"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp index 5d581492de..a562f8eee4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp @@ -10,16 +10,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "tx_inner_arr_len"; - -// Declared 70 against a direct count's 40 — the same locator surcharge the nested field getters -// pay, expressed as a different ratio (1.75x here, 1.57x there). Both cannot be right unless a -// locator walk costs a fixed amount, which is what these two pairs check. void txNestedArrayLenImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"tx_inner_arr_len"}; + benchmarkImpl( state, kWasmName, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp index d9ea9ff054..79d7b5a685 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp @@ -11,18 +11,7 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. constexpr std::string_view kWasmName = "tx_inner"; - -// Declared 110 against a direct read's 70 — the table's claim that walking a locator costs about -// half a field read again. -// -// This file carries the locator `ThroughVm` case for the whole nested family. A locator is a -// variable-length path of little-endian i32 steps that the *guest* lays out and the host walks; -// every other input shape in the ABI is a fixed-size value, so this is the only place the crossing -// reads a length the guest chose. The other five nested getters are `Impl`-only. - constexpr std::string_view kImport = R"( (import "host_lib" "tx_inner" (func $tx_inner (param i32 i32 i32 i32) (result i32))) )"; @@ -38,7 +27,7 @@ txNestedFieldThroughVm(benchmark::State& state) auto bytes = Bytes{}; for (auto const step : {sfMemos.getCode(), 0, sfMemoData.getCode()}) { - for (auto i = 0; i < 4; ++i) + for (auto i = 0U; i < 4; ++i) { bytes.push_back(static_cast((step >> (8 * i)) & 0xFF)); } diff --git a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp index b172f24e42..eee496bb76 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp @@ -13,21 +13,7 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. constexpr std::string_view kWasmName = "set_data"; - -// Declared 1000, and the suite's purest measurement of what *moving bytes* costs. -// -// The impl does almost nothing but copy the guest's region into host-owned storage, so unlike -// `sha512_half` there is no computation competing with the transfer. Swept over the input length -// up to `kMaxWasmDataLength`, the `ThroughVm` case is close to a direct readout of the per-byte -// term in the crossing — the number that, added to the fixed floor in `Crossing.bench.cpp`, should -// predict every other function's `ThroughVm` minus `Impl` gap. -// -// It is also a flat price over a range spanning two orders of magnitude, the same -// flat-price-for-linear-work question `Sha512Half.bench.cpp` asks. - constexpr std::string_view kImport = R"( (import "host_lib" "set_data" (func $set_data (param i32 i32) (result i32))) )"; diff --git a/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp index c004de1f2d..00f3acebb1 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp @@ -7,17 +7,11 @@ namespace xrpl::test::bench { namespace { -// The guest import name, used to look up what `lib.rs` declares this call costs. Reading the -// declaration rather than copying the number keeps the two from drifting apart. -constexpr std::string_view kWasmName = "vault_id"; - -// Declared 350. One of the nineteen keylets: gather fixed-size inputs, hash them with a type -// prefix, answer 32 bytes. The family is priced flat, so the useful reading is against its -// siblings rather than in isolation. Only `escrow_id` carries a `ThroughVm` pair — crossing -// cost follows a call's shape, not which keylet it computes (see ../README.md). void vaultKeyletImpl(benchmark::State& state) { + static constexpr auto kWasmName = std::string_view{"vault_id"}; + benchmarkImpl( state, kWasmName, From abc888707abe33bdd0cee584109d96e3114104d0 Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Wed, 26 Aug 2026 21:48:27 -0400 Subject: [PATCH 12/23] chore: Address self review comments --- .cspell.config.yaml | 1 - conanfile.py | 7 - src/benchmarks/libxrpl/CMakeLists.txt | 11 - src/tests/libxrpl/tx/wasm/BenchFixtures.cpp | 147 ++++++------ src/tests/libxrpl/tx/wasm/BenchFixtures.h | 185 +++++++------- src/tests/libxrpl/tx/wasm/Crossing.bench.cpp | 2 +- src/tests/libxrpl/tx/wasm/README.md | 31 ++- src/tests/libxrpl/tx/wasm/RealVmTest.h | 13 +- src/tests/libxrpl/tx/wasm/WasmBench.cpp | 209 ++++++++-------- src/tests/libxrpl/tx/wasm/WasmBench.h | 226 ++++-------------- .../libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp | 14 +- .../tx/wasm/e2e/CurrentLedgerObjField.cpp | 10 +- .../libxrpl/tx/wasm/e2e/FloatToMantExp.cpp | 10 +- src/tests/libxrpl/tx/wasm/e2e/HostError.cpp | 10 +- src/tests/libxrpl/tx/wasm/e2e/TxField.cpp | 10 +- .../libxrpl/tx/wasm/e2e/TxNestedField.cpp | 14 +- .../host_functions/AccountKeylet.bench.cpp | 4 +- .../wasm/host_functions/AmmKeylet.bench.cpp | 4 +- .../tx/wasm/host_functions/BaseFee.bench.cpp | 5 +- .../host_functions/CacheLedgerObj.bench.cpp | 4 +- .../wasm/host_functions/CheckKeylet.bench.cpp | 6 +- .../host_functions/CheckSignature.bench.cpp | 24 +- .../host_functions/CredentialKeylet.bench.cpp | 6 +- .../CurrentLedgerObjArrayLen.bench.cpp | 2 +- .../CurrentLedgerObjField.bench.cpp | 11 +- .../CurrentLedgerObjNestedArrayLen.bench.cpp | 2 +- .../CurrentLedgerObjNestedField.bench.cpp | 2 +- .../host_functions/DelegateKeylet.bench.cpp | 7 +- .../DepositPreauthKeylet.bench.cpp | 7 +- .../wasm/host_functions/DidKeylet.bench.cpp | 4 +- .../host_functions/EscrowKeylet.bench.cpp | 14 +- .../tx/wasm/host_functions/FloatAdd.bench.cpp | 9 +- .../host_functions/FloatCompare.bench.cpp | 4 +- .../wasm/host_functions/FloatDivide.bench.cpp | 7 +- .../host_functions/FloatFromInt.bench.cpp | 4 +- .../host_functions/FloatFromMantExp.bench.cpp | 6 +- .../FloatFromStAmount.bench.cpp | 7 +- .../FloatFromStNumber.bench.cpp | 4 +- .../host_functions/FloatFromUint.bench.cpp | 4 +- .../host_functions/FloatMultiply.bench.cpp | 7 +- .../wasm/host_functions/FloatPower.bench.cpp | 7 +- .../wasm/host_functions/FloatRoot.bench.cpp | 4 +- .../host_functions/FloatSubtract.bench.cpp | 7 +- .../wasm/host_functions/FloatToInt.bench.cpp | 4 +- .../host_functions/FloatToMantExp.bench.cpp | 7 +- .../IsAmendmentEnabled.bench.cpp | 4 +- .../LedgerObjArrayLen.bench.cpp | 2 +- .../host_functions/LedgerObjField.bench.cpp | 2 +- .../LedgerObjNestedArrayLen.bench.cpp | 2 +- .../LedgerObjNestedField.bench.cpp | 2 +- .../wasm/host_functions/LedgerSqn.bench.cpp | 4 +- .../MptokenIssuanceKeylet.bench.cpp | 6 +- .../host_functions/MptokenKeylet.bench.cpp | 8 +- .../tx/wasm/host_functions/NFTFlags.bench.cpp | 4 +- .../wasm/host_functions/NFTIssuer.bench.cpp | 4 +- .../wasm/host_functions/NFTSequence.bench.cpp | 4 +- .../tx/wasm/host_functions/NFTTaxon.bench.cpp | 4 +- .../host_functions/NFTTransferFee.bench.cpp | 4 +- .../NftokenOfferKeylet.bench.cpp | 6 +- .../wasm/host_functions/OfferKeylet.bench.cpp | 6 +- .../host_functions/OracleKeylet.bench.cpp | 6 +- .../host_functions/ParentLedgerHash.bench.cpp | 2 +- .../host_functions/ParentLedgerTime.bench.cpp | 2 +- .../host_functions/PaychannelKeylet.bench.cpp | 5 +- .../PermissionedDomainedKeylet.bench.cpp | 6 +- .../wasm/host_functions/Sha512Half.bench.cpp | 11 +- .../host_functions/SignerListKeylet.bench.cpp | 4 +- .../host_functions/TicketKeylet.bench.cpp | 6 +- .../tx/wasm/host_functions/Trace.bench.cpp | 4 +- .../host_functions/TrustLineKeylet.bench.cpp | 5 +- .../wasm/host_functions/TxArrayLen.bench.cpp | 2 +- .../tx/wasm/host_functions/TxField.bench.cpp | 2 +- .../host_functions/TxNestedArrayLen.bench.cpp | 2 +- .../host_functions/TxNestedField.bench.cpp | 7 +- .../wasm/host_functions/UpdateData.bench.cpp | 9 +- .../wasm/host_functions/VaultKeylet.bench.cpp | 6 +- 76 files changed, 569 insertions(+), 655 deletions(-) diff --git a/.cspell.config.yaml b/.cspell.config.yaml index 1797a387f7..b7b929dffe 100644 --- a/.cspell.config.yaml +++ b/.cspell.config.yaml @@ -172,7 +172,6 @@ words: - levelization - levelized - libpb - - libpfm - libxrpl - llection - LOCALGOOD diff --git a/conanfile.py b/conanfile.py index bf948fbfa8..ae677b99aa 100644 --- a/conanfile.py +++ b/conanfile.py @@ -131,13 +131,6 @@ class Xrpl(ConanFile): self.options["boost"].visibility = "global" if self.settings.compiler in ["clang", "gcc"]: self.options["boost"].without_cobalt = True - # Google Benchmark can read hardware performance counters (instructions, - # cycles, ...) through libpfm, which its recipe only offers on Linux. The - # wasm gas-calibration benchmarks want instruction counts as a - # machine-independent cross-check on wall time, so enable it where it - # exists; elsewhere those benchmarks fall back to timing alone. - if self.options.benchmark and self.settings.os == "Linux": - self.options["benchmark"].enable_libpfm = True def requirements(self): if self.options.benchmark: diff --git a/src/benchmarks/libxrpl/CMakeLists.txt b/src/benchmarks/libxrpl/CMakeLists.txt index d5a6e6d07e..2e701b56db 100644 --- a/src/benchmarks/libxrpl/CMakeLists.txt +++ b/src/benchmarks/libxrpl/CMakeLists.txt @@ -87,17 +87,6 @@ if(TARGET GTest::gtest) ) add_dependencies(xrpl.bench.wasm xrpl_crates) - # Hardware performance counters (INSTRUCTIONS, CYCLES, ...) come from libpfm, - # which Google Benchmark only builds on Linux (see the `enable_libpfm` option - # set in conanfile.py). Where it is available the benchmarks advertise the - # `--benchmark_perf_counters=...` flag; elsewhere they report wall time only. - if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - target_compile_definitions( - xrpl.bench.wasm - PRIVATE XRPL_BENCH_PERF_COUNTERS=1 - ) - endif() - add_dependencies(xrpl.benchmarks xrpl.bench.wasm) else() message( diff --git a/src/tests/libxrpl/tx/wasm/BenchFixtures.cpp b/src/tests/libxrpl/tx/wasm/BenchFixtures.cpp index 52cbf6349b..aa84a57d5b 100644 --- a/src/tests/libxrpl/tx/wasm/BenchFixtures.cpp +++ b/src/tests/libxrpl/tx/wasm/BenchFixtures.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -26,38 +25,58 @@ #include namespace xrpl::test::bench { +namespace { [[noreturn]] void -benchSetupFailed(std::string_view what) +setupFailed(std::string_view what) { - throw std::runtime_error("benchmark fixture setup failed: " + std::string{what}); + throw std::runtime_error{"benchmark fixture setup failed: " + std::string{what}}; } -BenchFixture& -benchLedger() +} // namespace + +Fixtures::Fixtures() + : alice_{ledger_.fund("benchAlice")} + , bob_{ledger_.fund("benchBob")} + , signerListOwner_{ledger_.fund("benchSigners")} + , escrow_{keylet::account(AccountID{})} + , signedMessage_{signMessage("the quick brown fox jumps over the lazy dog")} + , nftId_{NFTTest::makeNftId(alice_.id())} { - static BenchFixture value; - return value; + ledger_.makeSignerList(signerListOwner_, 2, {{alice_, 1}, {bob_, 1}}); + + // The escrow has to be submitted after the accounts exist, which is why it is built here + // rather than in the initializer list: its keylet depends on the owner's sequence number at + // submission time. + auto const ownerSeq = ledger_.ledger.getAccountRoot(alice_.id()).getSequence(); + auto const created = ledger_.ledger.submit( + transactions::EscrowCreateBuilder{alice_.id(), bob_.id(), XRP(100)}.setFinishAfter( + 900'000'000), + alice_); + if (created.ter != tesSUCCESS) + { + setupFailed(std::string{"creating the escrow: "} + transToken(created.ter)); + } + ledger_.ledger.close(); + escrow_ = keylet::escrow(alice_.id(), SeqProxy::rawSequence(ownerSeq)); } Account const& -benchAlice() +Fixtures::alice() const { - static auto const kValue = benchLedger().fund("benchAlice"); - return kValue; + return alice_; } Account const& -benchBob() +Fixtures::bob() const { - static auto const kValue = benchLedger().fund("benchBob"); - return kValue; + return bob_; } TxAssembler -benchMemoTx() +Fixtures::memoTx() { - auto assembler = escrowFinishTx(benchLedger().ledger, benchAlice()); + auto assembler = escrowFinishTx(ledger_.ledger, alice_); assembler.build = [inner = std::move(assembler.build)](STObject& obj) { inner(obj); auto memos = STArray{}; @@ -69,113 +88,97 @@ benchMemoTx() } FieldLocator -benchMemoLocator() +Fixtures::memoLocator() { return FieldLocator{{sfMemos.getCode(), 0, sfMemoData.getCode()}}; } WasmHost -benchHost() +Fixtures::host() { - auto assembler = benchMemoTx(); - return benchLedger().makeHost( - keylet::account(benchAlice().id()), assembler.type, std::move(assembler.build)); + auto assembler = memoTx(); + return ledger_.makeHost( + keylet::account(alice_.id()), assembler.type, std::move(assembler.build)); } WasmHost -benchCachedHost() +Fixtures::cachedHost() { - auto host = benchHost(); - if (!host->cacheLedgerObj(keylet::account(benchAlice().id()).key, 1).has_value()) + auto wasmHost = host(); + if (!wasmHost->cacheLedgerObj(keylet::account(alice_.id()).key, 1).has_value()) { - benchSetupFailed("caching the account root into slot 1"); + setupFailed("caching the account root into slot 1"); } - return host; -} - -Account const& -benchSignerListOwner() -{ - static auto const kValue = [] { - auto const acct = benchLedger().fund("benchSigners"); - benchLedger().makeSignerList(acct, 2, {{benchAlice(), 1}, {benchBob(), 1}}); - return acct; - }(); - return kValue; + return wasmHost; } WasmHost -benchSignerListHost() +Fixtures::signerListHost() { auto assembler = bareTx(); - return benchLedger().makeHost( - keylet::signerList(benchSignerListOwner().id()), - assembler.type, - std::move(assembler.build)); + return ledger_.makeHost( + keylet::signerList(signerListOwner_.id()), assembler.type, std::move(assembler.build)); } WasmHost -benchCachedSignerListHost() +Fixtures::cachedSignerListHost() { auto assembler = bareTx(); - auto host = benchLedger().makeHost( - keylet::account(AccountID{}), assembler.type, std::move(assembler.build)); - if (!host->cacheLedgerObj(keylet::signerList(benchSignerListOwner().id()).key, 1).has_value()) + auto wasmHost = + ledger_.makeHost(keylet::account(AccountID{}), assembler.type, std::move(assembler.build)); + if (!wasmHost->cacheLedgerObj(keylet::signerList(signerListOwner_.id()).key, 1).has_value()) { - benchSetupFailed("caching the signer list into slot 1"); + setupFailed("caching the signer list into slot 1"); } - return host; + return wasmHost; +} + +WasmHost +Fixtures::tracingHost() +{ + return ledger_.makeTracingHost(); } Keylet const& -benchEscrow() +Fixtures::escrow() const { - static auto const kValue = [] { - auto const ownerSeq = benchLedger().ledger.getAccountRoot(benchAlice().id()).getSequence(); - auto const created = benchLedger().ledger.submit( - transactions::EscrowCreateBuilder{benchAlice().id(), benchBob().id(), XRP(100)} - .setFinishAfter(900'000'000), - benchAlice()); - if (created.ter != tesSUCCESS) - { - benchSetupFailed(std::string{"creating the escrow: "} + transToken(created.ter)); - } - benchLedger().ledger.close(); - return keylet::escrow(benchAlice().id(), SeqProxy::rawSequence(ownerSeq)); - }(); - return kValue; + return escrow_; } WasmHost -benchEscrowHost() +Fixtures::escrowHost() { - return benchLedger().makeHost(benchEscrow()); + return ledger_.makeHost(escrow_); } Slice -benchFloatX() +Fixtures::floatX() { return FloatTest::slice(FloatTest::kPi); } Slice -benchFloatY() +Fixtures::floatY() { return FloatTest::slice(FloatTest::kTwo); } SignedMessage const& -benchSignedMessage() +Fixtures::signedMessage() const { - static auto const kValue = signMessage("the quick brown fox jumps over the lazy dog"); - return kValue; + return signedMessage_; } uint256 const& -benchNftId() +Fixtures::nftId() const { - // `makeNftId` is a static member, so no fixture instance is needed to reach it. - static auto const kValue = NFTTest::makeNftId(benchAlice().id()); + return nftId_; +} + +Fixtures& +Fixtures::instance() +{ + static Fixtures kValue; return kValue; } diff --git a/src/tests/libxrpl/tx/wasm/BenchFixtures.h b/src/tests/libxrpl/tx/wasm/BenchFixtures.h index 33d5de8661..ea0b49261a 100644 --- a/src/tests/libxrpl/tx/wasm/BenchFixtures.h +++ b/src/tests/libxrpl/tx/wasm/BenchFixtures.h @@ -10,128 +10,103 @@ #include #include -#include - -// Shared ledger state for the `*.bench.cpp` files. -// -// Each host function gets its own `.bench.cpp`, mirroring its test one-for-one, which -// means ~61 translation units that would otherwise each build their own ledger, fund their own -// accounts and mint their own tokens. Declared here and defined once in `BenchFixtures.cpp`, so -// the function-local statics behind these accessors are single objects shared by the whole -// binary: the ledger is built once, each account is funded once, and a benchmark file is left -// holding only the call it measures. -// -// That sharing is safe because every helper does its setup inside its own `static`, so it -// happens exactly once no matter how many files ask for it. It is also why the accounts have -// bench-specific names — two files funding "owner" against one ledger would be a duplicate -// account, not a fresh one. -// -// Nothing here is timed. Benchmarks call these to get a host, then measure only the host call. namespace xrpl::test::bench { -// Fail a fixture step loudly. -// -// A benchmark has no assertions — nothing here can `EXPECT_EQ` — and that makes a quietly -// failed setup step the most dangerous thing in this file. If the escrow is never created or -// the slot never cached, the host call still runs; it just takes the not-found path, which is -// cheap, plausible-looking, and completely wrong as a price. The `result >= 0` guard in -// `benchmarkThroughVm` catches that for VM cases, but an `Impl` case calls the host directly -// and has no such check. -// -// So every setup step whose failure would change what is being measured is checked here, and -// throws rather than returning. Google Benchmark reports the message and stops, which is the -// outcome you want: no number at all beats a confident wrong one. -[[noreturn]] void -benchSetupFailed(std::string_view what); +// The ledger and canned inputs every `*.bench.cpp` measures against. +class Fixtures +{ +public: + // The one set of fixtures every benchmark shares, built on first use. + static Fixtures& + instance(); -// The one ledger every benchmark runs against. -BenchFixture& -benchLedger(); + // A sequence number for the keylets that take one. Arbitrary — a keylet hashes whatever it + // is given, so the value cannot change the cost. + static constexpr std::uint32_t kSeq = 42; -// Two funded accounts, enough for every keylet shape and every object below. -Account const& -benchAlice(); + // Rounding mode 0 throughout the float family: modes select a tie-breaking rule, not a + // different algorithm, so they do not move the cost, and pinning one keeps the fourteen + // comparable. + static constexpr std::int32_t kRoundingMode = 0; -Account const& -benchBob(); + // Two funded accounts, enough for every keylet shape and every object below. + [[nodiscard]] Account const& + alice() const; + [[nodiscard]] Account const& + bob() const; -// A sequence number for the keylets that take one. Arbitrary — a keylet hashes whatever it is -// given, so the value cannot change the cost. -inline constexpr std::uint32_t kBenchSeq = 42; + // The default host: its transaction carries a two-element memo array (something for the + // nested getters to walk to and the array-length getters to count) and its current object is + // Alice's account root. + [[nodiscard]] WasmHost + host(); -// --------------------------------------------------------------------------- -// Transactions -// --------------------------------------------------------------------------- + // The same, with Alice's account root pinned to slot 1, for the `le_*` getters that read + // through a cache slot rather than the current object. + [[nodiscard]] WasmHost + cachedHost(); -// An EscrowFinish carrying a two-element memo array: something for the nested-field getters to -// walk to and the array-length getters to count. -TxAssembler -benchMemoTx(); + // An account root has no arrays, so the array-length getters that read a *ledger object* + // need a different one. A signer list has `sfSignerEntries`; without it those calls would + // answer `FieldNotFound` and the benchmark would time the rejection instead of the work. + [[nodiscard]] WasmHost + signerListHost(); + [[nodiscard]] WasmHost + cachedSignerListHost(); -// `sfMemos[0].sfMemoData` — a two-step locator path, the shape the nested getters are priced for. -FieldLocator -benchMemoLocator(); + // A host whose `trace` output is captured rather than dropped, so the log-enabled path can + // be measured against the log-disabled one that `host()` gives. + [[nodiscard]] WasmHost + tracingHost(); -// --------------------------------------------------------------------------- -// Hosts -// --------------------------------------------------------------------------- + // A real escrow, created through the real transactor — the current object for + // `home_le_field`, the one getter whose cost depends on the object it reads rather than on + // its arguments. + [[nodiscard]] Keylet const& + escrow() const; + [[nodiscard]] WasmHost + escrowHost(); -// The default: transaction carries the memo array, current object is Alice's account root. -WasmHost -benchHost(); + // `sfMemos[0].sfMemoData` — a two-step locator path, the shape the nested getters are priced + // for. + [[nodiscard]] static FieldLocator + memoLocator(); -// The same, with Alice's account root pinned to slot 1, for the `le_*` getters that read -// through a cache slot rather than the current object. -WasmHost -benchCachedHost(); + // Canonical float operands. Zeroed bytes decode as a non-canonical float and would be + // refused before any arithmetic ran, so the whole family shares these two known-good values. + [[nodiscard]] static Slice + floatX(); + [[nodiscard]] static Slice + floatY(); -// An account root has no arrays, so the array-length getters that read a *ledger object* need a -// different one. A signer list has `sfSignerEntries`; without it those calls would answer -// `FieldNotFound` and the benchmark would time the rejection instead of the work. -Account const& -benchSignerListOwner(); + // A signed message for `check_sig`. Signing is far more expensive than the verification + // being measured, so it happens once here rather than inside a timed loop. + [[nodiscard]] SignedMessage const& + signedMessage() const; -// Current object is the signer list. -WasmHost -benchSignerListHost(); + // A well-formed NFToken id with the fixture's known taxon, flags, fee and sequence baked in, + // so the id-extractor getters have real fields to pull out rather than zeros. + [[nodiscard]] uint256 const& + nftId() const; -// Signer list pinned to slot 1. -WasmHost -benchCachedSignerListHost(); +private: + // Order matters, and that is the reason this is a constructor rather than a pile of lazy + // statics: the accounts have to be funded before the signer list and the escrow can be built + // on them. + Fixtures(); -// A real escrow, created through the real transactor — the current object for `home_le_field`, -// which is the one getter whose cost depends on the object it reads rather than its arguments. -Keylet const& -benchEscrow(); + // The transaction the default host runs, carrying the memo array. + [[nodiscard]] TxAssembler + memoTx(); -WasmHost -benchEscrowHost(); - -// --------------------------------------------------------------------------- -// Inputs that need building -// --------------------------------------------------------------------------- - -// Canonical float operands. Zeroed bytes decode as a non-canonical float and would be refused -// before any arithmetic ran, so the whole family shares these two known-good values. -Slice -benchFloatX(); - -Slice -benchFloatY(); - -// Rounding mode 0 throughout the float family: modes select a tie-breaking rule, not a different -// algorithm, so they do not move the cost, and pinning one keeps the fourteen comparable. -inline constexpr std::int32_t kBenchMode = 0; - -// A signed message for `check_sig`, produced once: signing is far more expensive than the -// verification being measured, so it must not happen inside the timed loop. -SignedMessage const& -benchSignedMessage(); - -// A well-formed NFToken id with the fixture's known taxon, flags, fee and sequence baked in, so -// the id-extractor getters have real fields to pull out rather than zeros. -uint256 const& -benchNftId(); + BenchFixture ledger_; + Account alice_; + Account bob_; + Account signerListOwner_; + Keylet escrow_; + SignedMessage signedMessage_; + uint256 nftId_; +}; } // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/Crossing.bench.cpp b/src/tests/libxrpl/tx/wasm/Crossing.bench.cpp index 338c1d47fe..29bb50af6a 100644 --- a/src/tests/libxrpl/tx/wasm/Crossing.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/Crossing.bench.cpp @@ -36,7 +36,7 @@ guestInstruction(benchmark::State& state) static constexpr std::string_view kBody = "(i32.add (local.get $r) (i32.const 1))"; // Empty import name: this case prices no host function, so there is nothing to look a // declaration up for and it reports no `suggested_gas`. - benchmarkThroughVm(state, "", "", "", kBody, [] { return benchHost(); }); + benchmarkThroughVm(state, "", "", "", kBody, [] { return Fixtures::instance().host(); }); } BENCHMARK(guestInstruction)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/README.md b/src/tests/libxrpl/tx/wasm/README.md index 7be25e539d..382362d910 100644 --- a/src/tests/libxrpl/tx/wasm/README.md +++ b/src/tests/libxrpl/tx/wasm/README.md @@ -28,8 +28,8 @@ actually costs. **One `.bench.cpp` per host function, named after its test** — `EscrowKeylet.cpp` and `EscrowKeylet.bench.cpp` sit next to each other, 61 of each. That is a checklist rather than a judgment call: adding a host function means adding two files, and nobody has to decide where a -benchmark belongs. Shared ledger setup lives in `BenchFixtures.h` (one ledger, funded once, for -the whole binary) so each file holds only the call it measures. +benchmark belongs. Shared ledger setup lives in the `Fixtures` type (`BenchFixtures.h`) — one +ledger, funded once, for the whole binary — so each file holds only the call it measures. They build into a **separate executable** (`xrpl.bench.wasm`), and `xrpl_tests` filters `*.bench.cpp` out of its source globs, so benchmark runtime never lands on the `ctest` path. @@ -51,12 +51,13 @@ none of it inlined) far more than it inflates the impls, so Debug overstates wha guest costs. Google Benchmark prints a warning when it detects this. Ratios between `Impl` cases survive Debug reasonably; absolute `implied_gas` does not. -On Linux, Google Benchmark is built against libpfm (`enable_libpfm` in `conanfile.py`), so -hardware counters are available as a cross-check on the timing: - -```bash -./xrpl.bench.wasm --benchmark_perf_counters=INSTRUCTIONS,CYCLES -``` +> **On hardware performance counters.** Google Benchmark can read instruction and cycle counts +> through libpfm on Linux, and that was wired up here at one point, but it has been removed: its +> counters start and stop around the whole `for (auto _ : state)` body, which for these cases +> covers the loaded run _and_ the baseline run _and_ two module compilations. They would not +> reflect the subtraction that makes these numbers mean anything. Getting useful instruction +> counts needs a custom `perf_event_open` around the same regions `timeRun` brackets — worth +> doing, but the dependency buys nothing until then. ### Reading the output @@ -73,7 +74,6 @@ from one laptop's nanoseconds. | `implied_gas` | the raw measurement, before the crossing is added back | | `charged_gas` | what the engine actually billed (`EscrowResult::cost`); confirms the right call was measured | | `ns_per_call` | raw wall time, for debugging a suspicious ratio | -| `perf_counters` | 1 when libpfm is available | `declared_gas` is read from the declaration through the `wasm_testkit` bridge (`declared_gas(wasm_name)`), not transcribed into C++ — 61 copied constants would drift from @@ -82,7 +82,12 @@ to fail. `price_ratio` is what you sort by. **Below 1 is the direction that matters**: an underpriced call is one a contract can buy too cheaply, which is a denial-of-service vector rather than a rounding -error. Above 1 the table merely overcharges. +error. Above 1 the table merely overcharges. The mispriced functions come to the top with: + +```bash +./build/xrpl.bench.wasm --benchmark_format=json | + jq -r '.benchmarks[] | select(.price_ratio) | [.price_ratio, .name] | @tsv' | sort -n +``` ### How `suggested_gas` is measured @@ -92,9 +97,9 @@ one pool — so one unit of gas is, by construction, about one guest instruction question into a ratio: _how many guest instructions' worth of work is this host call?_ Everything below exists to answer that without any hard-coded constant. -Four steps, each a subtraction, all in `WasmBench.h`. +Four steps, each a subtraction, all in `WasmBench.h` / `WasmBench.cpp`. -**1. `secondsPerGas()` — what one unit of gas costs on this machine.** +**1. `Calibration::secondsPerGas()` — what one unit of gas costs on this machine.** Assemble two modules that differ only in a loop bound: one runs a trivial `i32.add` body `kCallsPerRun` times, the other zero times. Run both, and take @@ -123,7 +128,7 @@ implied_gas = secondsPerCall / secondsPerGas Machine-independent: both terms scale with the box, so the ratio does not. -**4. `crossingFloorGas()` — the toll every call pays.** +**4. `Calibration::crossingFloorGas()` — the toll every call pays.** Measured once, from `ldgr_index` — the cheapest host function there is, taking no input and answering from a header already in hand, so almost nothing remains after subtracting it away: diff --git a/src/tests/libxrpl/tx/wasm/RealVmTest.h b/src/tests/libxrpl/tx/wasm/RealVmTest.h index b437e45023..a5c05293e4 100644 --- a/src/tests/libxrpl/tx/wasm/RealVmTest.h +++ b/src/tests/libxrpl/tx/wasm/RealVmTest.h @@ -19,21 +19,12 @@ namespace xrpl::test { // End-to-end: a WAT contract run through the REAL VM against the REAL host -// (`WasmHostFunctionsImpl`) over a REAL `TxTest` ledger. The real-host counterpart of -// `MockVmTest`; both forward to the shared `runWat` harness (`WasmRun.h`), differing only in -// the host. `host_calls/` mocks the host and `host_functions/` skips the VM; this exercises -// the whole host stack at once — VM, `HostContext` marshalling, the impl, and the ledger — -// driven by a guest. -// -// WAT rather than a compiled guest: the guest SDK (`xrpl-wasm-stdlib`) is an external repo -// with its own tests, so a compiled guest would couple this suite to that repo and a -// Rust->wasm toolchain. WAT keeps the host-side integration this repo owns and delegates the -// SDK exercise to the SDK's own repo. +// over a REAL `TxTest` ledger. struct RealVmTest : RealHostFixture { // Assemble `wat` and run its `entryPoint` through the real VM against a real host built // over the current open ledger. `leKey`/`txType`/`assembler` configure the ledger object - // the contract runs against and the transaction it reads (see `RealHostFixture::makeHost`). + // the contract runs against and the transaction it reads. std::expected run( std::string_view wat, diff --git a/src/tests/libxrpl/tx/wasm/WasmBench.cpp b/src/tests/libxrpl/tx/wasm/WasmBench.cpp index cbf2f93529..6f0efe2fc0 100644 --- a/src/tests/libxrpl/tx/wasm/WasmBench.cpp +++ b/src/tests/libxrpl/tx/wasm/WasmBench.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -23,7 +24,9 @@ int callsWithinTransferBudget(std::int64_t bytesPerCall) { if (bytesPerCall <= 0) + { return kCallsPerRun; + } auto const affordable = (kTransferLimitBytes / 2) / bytesPerCall; return static_cast(std::clamp(affordable, 16, kCallsPerRun)); } @@ -31,8 +34,7 @@ callsWithinTransferBudget(std::int64_t bytesPerCall) std::string dataSegment(int offset, std::span bytes) { - return std::string{" (data (i32.const "} + std::to_string(offset) + ") \"" + - watEscaped(bytes) + "\")\n"; + return std::format(" (data (i32.const {}) \"{}\")\n", offset, watEscaped(bytes)); } std::string @@ -44,25 +46,24 @@ dataSegment(int offset, Bytes const& bytes) std::string makeLoopWat(std::string_view imports, std::string_view data, std::string_view body, int count) { - return std::string{"(module\n"} + std::string{imports} + - R"wat( + static constexpr auto kTemplate = R"wat((module +{} (memory (export "memory") 1) -)wat" + std::string{data} + - R"wat( +{} (func (export "escrow_finish") (result i32) (local $i i32) (local $r i32) - (local.set $i (i32.const )wat" + - std::to_string(count) + R"wat()) + (local.set $i (i32.const {})) (block $done (loop $again (br_if $done (i32.eqz (local.get $i))) - (local.set $r )wat" + - std::string{body} + R"wat() + (local.set $r {}) (local.set $i (i32.sub (local.get $i) (i32.const 1))) (br $again))) (local.get $r))) )wat"; + + return std::format(kTemplate, imports, data, count, body); } Timing @@ -78,46 +79,115 @@ timeRun(HostFunctions& host, Bytes const& wasm) .gas = outcome.has_value() ? outcome->cost : std::int64_t{0}}; } +namespace { + +// Seconds of wall time one unit of gas buys on this machine. See `Calibration` for why this is +// a difference rather than a single measurement. double -secondsPerGas() +measureSecondsPerGas() { - static double const kValue = [] { - // A couple of guest instructions per iteration, no memory traffic, nothing the - // engine can fold away. - static constexpr std::string_view kBody = "(i32.add (local.get $r) (i32.const 1))"; - auto const busy = assembleWat(makeLoopWat("", "", kBody, kCallsPerRun)); - auto const idle = assembleWat(makeLoopWat("", "", kBody, 0)); + // A couple of guest instructions per iteration, no memory traffic, nothing the engine can + // fold away. + static constexpr auto kBody = std::string_view{"(i32.add (local.get $r) (i32.const 1))"}; + auto const busy = assembleWat(makeLoopWat("", "", kBody, kCallsPerRun)); + auto const idle = assembleWat(makeLoopWat("", "", kBody, 0)); - BenchFixture fixture; + auto fixture = BenchFixture{}; - // Warm the instruction cache and the allocator before the pairs that count, so - // the first-run penalty does not land on one side of the subtraction. - for (int i = 0; i < 8; ++i) + // Warm the instruction cache and the allocator before the pairs that count, so the first-run + // penalty does not land on one side of the subtraction. + for (auto i = 0U; i < 8; ++i) + { + timeRun(*fixture.makeHost(), busy); + timeRun(*fixture.makeHost(), idle); + } + + // Best-of over several pairs: the minimum is the run least disturbed by the scheduler, which + // is the honest floor for what this machine can do. + auto best = std::numeric_limits::max(); + auto gasDelta = std::int64_t{1}; + for (auto i = 0U; i < 32; ++i) + { + auto hotHost = fixture.makeHost(); + auto const hot = timeRun(*hotHost, busy); + auto coldHost = fixture.makeHost(); + auto const cold = timeRun(*coldHost, idle); + auto const delta = hot.seconds - cold.seconds; + if (delta > 0.0 && delta < best) { - timeRun(*fixture.makeHost(), busy); - timeRun(*fixture.makeHost(), idle); + best = delta; + gasDelta = std::max(std::int64_t{1}, hot.gas - cold.gas); } + } + return best == std::numeric_limits::max() ? 0.0 : best / static_cast(gasDelta); +} - // Best-of over several pairs: the minimum is the run least disturbed by the - // scheduler, which is the honest floor for what this machine can do. - auto best = std::numeric_limits::max(); - auto gasDelta = std::int64_t{1}; - for (int i = 0; i < 32; ++i) +// The crossing, in gas: `ldgr_index` through the VM minus `ldgr_index` called directly. +// `secondsPerGas` has to be the value from the same snapshot, so it is passed in rather than +// re-measured. +double +measureCrossingFloorGas(double secondsPerGas) +{ + static constexpr std::string_view kImport = + R"( (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) +)"; + static constexpr std::string_view kBody = "(call $ldgr_index (i32.const 0) (i32.const 4))"; + + auto const loaded = assembleWat(makeLoopWat(kImport, "", kBody, kCallsPerRun)); + auto const baseline = assembleWat(makeLoopWat(kImport, "", kBody, 0)); + + auto fixture = BenchFixture{}; + + auto best = std::numeric_limits::max(); + for (auto i = 0U; i < 16; ++i) + { + auto hotHost = fixture.makeHost(); + auto const hot = timeRun(*hotHost, loaded); + auto coldHost = fixture.makeHost(); + auto const cold = timeRun(*coldHost, baseline); + + auto const perCall = (hot.seconds - cold.seconds) / kCallsPerRun; + if (perCall > 0.0 && perCall < best) { - auto hotHost = fixture.makeHost(); - auto const hot = timeRun(*hotHost, busy); - auto coldHost = fixture.makeHost(); - auto const cold = timeRun(*coldHost, idle); - auto const delta = hot.seconds - cold.seconds; - if (delta > 0.0 && delta < best) - { - best = delta; - gasDelta = std::max(std::int64_t{1}, hot.gas - cold.gas); - } + best = perCall; } - return best == std::numeric_limits::max() ? 0.0 - : best / static_cast(gasDelta); - }(); + } + if (best == std::numeric_limits::max()) + { + return 0.0; + } + + // The impl side is the same call without the VM. Subtracting it leaves the crossing. + auto implSeconds = std::numeric_limits::max(); + auto host = fixture.makeHost(); + for (auto i = 0U; i < 16; ++i) + { + auto const start = std::chrono::steady_clock::now(); + for (auto c = 0U; c < kCallsPerRun; ++c) + { + auto result = host->getLedgerSqn(); + benchmark::DoNotOptimize(result); + } + auto const elapsed = std::chrono::steady_clock::now() - start; + implSeconds = + std::min(implSeconds, std::chrono::duration(elapsed).count() / kCallsPerRun); + } + + return secondsPerGas > 0.0 ? std::max(0.0, best - implSeconds) / secondsPerGas : 0.0; +} + +} // namespace + +Calibration::Calibration() + : secondsPerGas_{measureSecondsPerGas()} + , crossingFloorGas_{measureCrossingFloorGas(secondsPerGas_)} +{ +} + +Calibration const& +Calibration::instance() +{ + static Calibration const kValue; return kValue; } @@ -128,57 +198,6 @@ declaredGas(std::string_view wasmName) rs::wasm_testkit::declared_gas(rust::Str{wasmName.data(), wasmName.size()})); } -double -crossingFloorGas() -{ - static double const kValue = [] { - static constexpr std::string_view kImport = - R"( (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) -)"; - static constexpr std::string_view kBody = "(call $ldgr_index (i32.const 0) (i32.const 4))"; - - auto const loaded = assembleWat(makeLoopWat(kImport, "", kBody, kCallsPerRun)); - auto const baseline = assembleWat(makeLoopWat(kImport, "", kBody, 0)); - - BenchFixture fixture; - - auto best = std::numeric_limits::max(); - for (int i = 0; i < 16; ++i) - { - auto hotHost = fixture.makeHost(); - auto const hot = timeRun(*hotHost, loaded); - auto coldHost = fixture.makeHost(); - auto const cold = timeRun(*coldHost, baseline); - - auto const perCall = (hot.seconds - cold.seconds) / kCallsPerRun; - if (perCall > 0.0 && perCall < best) - best = perCall; - } - if (best == std::numeric_limits::max()) - return 0.0; - - // The impl side is the same call without the VM. Subtracting it leaves the crossing. - auto implSeconds = std::numeric_limits::max(); - auto host = fixture.makeHost(); - for (int i = 0; i < 16; ++i) - { - auto const start = std::chrono::steady_clock::now(); - for (int c = 0; c < kCallsPerRun; ++c) - { - auto result = host->getLedgerSqn(); - benchmark::DoNotOptimize(result); - } - auto const elapsed = std::chrono::steady_clock::now() - start; - implSeconds = std::min( - implSeconds, std::chrono::duration(elapsed).count() / kCallsPerRun); - } - - auto const perGas = secondsPerGas(); - return perGas > 0.0 ? std::max(0.0, best - implSeconds) / perGas : 0.0; - }(); - return kValue; -} - void report( benchmark::State& state, @@ -187,14 +206,14 @@ report( std::string_view wasmName, bool throughVm) { - auto const perGas = secondsPerGas(); + auto const perGas = Calibration::instance().secondsPerGas(); auto const implied = perGas > 0.0 ? secondsPerCall / perGas : 0.0; - auto const suggested = throughVm ? implied : implied + crossingFloorGas(); + auto const suggested = + throughVm ? implied : implied + Calibration::instance().crossingFloorGas(); state.counters["implied_gas"] = implied; state.counters["ns_per_call"] = secondsPerCall * 1e9; state.counters["charged_gas"] = chargedGas; - state.counters["perf_counters"] = kPerfCountersAvailable ? 1 : 0; if (wasmName.empty()) return; diff --git a/src/tests/libxrpl/tx/wasm/WasmBench.h b/src/tests/libxrpl/tx/wasm/WasmBench.h index 88c8693c34..059d6bf7f1 100644 --- a/src/tests/libxrpl/tx/wasm/WasmBench.h +++ b/src/tests/libxrpl/tx/wasm/WasmBench.h @@ -16,77 +16,9 @@ #include #include -// Gas calibration for the wasm host functions. -// -// Every `#[gas = N]` in `crates/xrpl-host-functions/src/lib.rs` is a promise about how -// much work a host call does relative to a guest instruction: the engine meters both from -// one pool (`set_fuel(gas)` in `crates/xrpl-wasm-vm/src/vm.rs`), so one unit of gas *is* -// roughly one wasm instruction. That makes the calibration question answerable and, more -// importantly, machine-independent: not "how many nanoseconds does `sha512_half` take" -// (a property of the box) but "how many guest instructions' worth of work is it" (a -// property of the code). Only the second can be written into a consensus rule. -// -// Two costs hide inside one host call, and pricing needs them apart: -// -// * the *impl* — what `WasmHostFunctionsImpl` computes. Measured by calling the host -// method directly, with no VM in the picture (`benchmarkImpl`). -// * the *crossing* — region decode, bounds checks, memory copies, the cxx bridge hop. -// Paid on every call regardless of what the call does (`benchmarkThroughVm`). -// -// So the whole design here is a subtraction, and it appears twice: -// -// 1. Inside a VM benchmark, between a contract that makes N host calls and an otherwise -// byte-identical contract that makes none. That removes module compilation, -// instantiation and the guest's own loop from the number. The subtraction happens -// per iteration, so Google Benchmark's variance statistics describe the isolated -// host call rather than the run that contains it. -// 2. Between the `ThroughVm` and `Impl` cases for the same function, read off the -// report afterwards. That difference is the crossing, which should come out roughly -// constant across functions plus a term in the byte count. Functions whose cost -// grows with input size are registered over a `Range` so that term is visible. -// -// The reported counters are the point; wall time is only the raw material: -// -// `suggested_gas` **the answer** — what this function should be priced at. For a -// `ThroughVm` case that is what was measured; for an `Impl` case the -// crossing is added back, since a guest cannot call without paying it. -// `declared_gas` what `lib.rs` currently says, read through the `wasm_testkit` bridge so -// it can never drift from the declaration. -// `price_ratio` `declared / suggested`. 1.0 is correct. Above 1 the table overcharges; -// **below 1 it undercharges**, which is the direction that matters — an -// underpriced call is one a contract can buy too cheaply. -// `implied_gas` the raw measurement, before the crossing is added back. -// `charged_gas` what the engine actually charged (from `EscrowResult::cost`), on VM -// cases. Should track the declaration, and is how the harness shows it is -// measuring the call it thinks it is. -// `ns_per_call` the underlying wall time, for debugging a suspicious ratio. -// -// Sort a report by `price_ratio` and the mispriced functions come to the top: -// ./xrpl.bench.wasm --benchmark_format=csv | sort -t, -k - -// -// One caveat on `suggested_gas` for `Impl`-only cases: the crossing added back is the *floor*, -// measured on a call with no input. A function that moves bytes pays more than the floor, so -// its suggestion is a lower bound. The swept cases (`Sha512Half`, `UpdateData`) measure that -// per-byte term where it matters. -// -// Run it: -// ./xrpl.bench.wasm --benchmark_filter='Sha512Half' -// ./xrpl.bench.wasm --benchmark_format=json > gas.json -// and on Linux, where Google Benchmark is built against libpfm (see `enable_libpfm` in -// conanfile.py), hardware counters are available as a cross-check on the timing: -// ./xrpl.bench.wasm --benchmark_perf_counters=INSTRUCTIONS,CYCLES -// -// Build Release before believing anything. A Debug build inflates the crossing far more -// than it inflates the impls — the marshalling is templates and `std::expected`, none of it -// inlined — so Debug numbers overstate what leaving the guest costs and understate every -// function's own work relative to it. Google Benchmark prints a warning when it detects -// this; do not read past it. -// -// These are *calibration* runs, not tests: nothing here asserts, and a number moving is -// not a build failure. They live beside the tests for the same functions because the two -// share a fixture and should move together, but they build into their own executable -// (`xrpl.bench.wasm`) so they never run under ctest. +// The gas-calibration harness: how a `*.bench.cpp` measures a host call, and how that +// measurement becomes a suggested price. What the numbers mean and how to read a report are in +// ../README.md. namespace xrpl::test::bench { @@ -97,7 +29,7 @@ inline constexpr std::int64_t kBenchGas = 2'000'000'000; // How many host calls a benchmarked contract makes per run. Large enough that the // per-call cost dominates the residue left by the baseline subtraction, small enough that // one run stays in the microsecond range. -inline constexpr int kCallsPerRun = 1000; +inline constexpr std::int32_t kCallsPerRun = 1000; // How many timed iterations each case runs. Pinned rather than left to Google Benchmark's // automatic sizing, which cannot work here: a case reports the subtraction's residue — tens @@ -106,38 +38,20 @@ inline constexpr int kCallsPerRun = 1000; // so it would ask for millions of iterations to accumulate its default `min_time` and the // case would never finish. Every registration therefore ends // `->UseManualTime()->Iterations(kBenchIterations)`. -inline constexpr int kBenchIterations = 50; +inline constexpr std::int32_t kBenchIterations = 50; // Every run gets this much guest<->host copying before `charge_transfer` starts refusing -// calls (`TRANSFER_LIMIT_BYTES` in `crates/xrpl-wasm-vm/src/vm.rs`). It is a per-run budget, -// so it resets between the runs a benchmark makes — but a single run of `kCallsPerRun` calls -// moving a kilobyte each would exhaust it partway through and spend the rest of the loop -// measuring the refusal path instead of the host function. +// calls. It is a per-run budget, so it resets between the runs a benchmark makes — +// but a single run of `kCallsPerRun` calls moving a kilobyte each would exhaust it partway +// through and spend the rest of the loop measuring the refusal path instead of the host function. inline constexpr std::int64_t kTransferLimitBytes = 1 << 20; // How many calls a run can afford at `bytesPerCall`, staying clear of the transfer budget. -// -// Halved because most functions move bytes in *both* directions — an input region read plus -// an output region written — and the budget counts both. A size-swept case passes this as -// its call count so the large end of the range does not silently turn into an error -// benchmark; per-call numbers stay comparable across counts, which is what the report shows. +// Halved because most functions move bytes in *both* directions. int callsWithinTransferBudget(std::int64_t bytesPerCall); -// True when Google Benchmark was built with libpfm and `--benchmark_perf_counters` will -// work. Reported as a counter so a JSON report records which mode produced it. -inline constexpr bool kPerfCountersAvailable = -#ifdef XRPL_BENCH_PERF_COUNTERS - true; -#else - false; -#endif - -// The test fixtures these benchmarks measure against derive from `testing::Test`, whose pure -// virtual `TestBody` makes them abstract. A benchmark wants a fixture's ledger, host and -// setup helpers, not GTest's lifecycle, so supply the one missing member and nothing else. -// Nothing here registers or runs a test. -// +// A benchmark wants a fixture's ledger, host and setup helpers. // Templated so a case can reuse whichever fixture its test uses — `Bench` for the // NFT benchmarks, `Bench` for the float ones — instead of duplicating that setup. template @@ -154,8 +68,8 @@ using BenchFixture = Bench; // One run of a contract: how long it took, and what the engine charged it. struct Timing { - double seconds; - std::int64_t gas; + double seconds{}; + std::int64_t gas{}; }; // A `(data ...)` segment placing `bytes` at `offset` in the guest's memory, so a case's @@ -169,71 +83,50 @@ std::string dataSegment(int offset, Bytes const& bytes); // A contract that runs `body` `count` times and returns the last result. -// -// `count` is the *only* thing that varies between a loaded module and its baseline: the -// imports, the data segments, the function bodies and the module's size are identical, so -// compiling and instantiating them costs the same and cancels out of the subtraction. At -// `count == 0` the loop is entered and immediately exited, so even the branch is paid by -// both. -// -// `data` holds any `dataSegment` calls the case needs; it goes after the memory -// declaration that gives those segments something to write into. std::string makeLoopWat(std::string_view imports, std::string_view data, std::string_view body, int count); // Run pre-assembled `wasm` once through the real VM, reporting wall time and gas. -// -// Assembly (WAT text -> bytes) is deliberately outside the timed region: it is a -// test-only convenience from the `wasm_testkit` crate, not something a validator ever -// does. Compilation *is* inside, because a validator does pay it — but it is identical -// between a module and its baseline, so the subtraction removes it. Timing timeRun(HostFunctions& host, Bytes const& wasm); -// Seconds of wall time one unit of gas buys on this machine. -// -// This is the conversion that makes every other number here machine-independent. It is -// measured, not assumed: a pure-wasm loop (no host calls, no ledger) run at two different -// iteration counts, with the difference in time divided by the difference in fuel. Taking -// a difference rather than a single measurement removes compilation and startup, which -// would otherwise inflate the apparent cost of a guest instruction and make every host -// function look cheap by comparison. -// -// Computed once per process and cached: it describes the machine, not the case. -double -secondsPerGas(); +// What this machine costs, measured once and shared by every case. +class Calibration +{ +public: + // The machine's calibration, measured on first use. Measuring runs a few hundred short + // contracts, so the first case to ask pays for it and every later case reads this answer. + static Calibration const& + instance(); + + Calibration(); + + // Seconds of wall time one unit of gas buys here. + [[nodiscard]] double + secondsPerGas() const + { + return secondsPerGas_; + } + + // The gas a host call costs before it does anything: region decode, bounds checks, the cxx + // hop. + [[nodiscard]] double + crossingFloorGas() const + { + return crossingFloorGas_; + } + +private: + double secondsPerGas_{}; + double crossingFloorGas_{}; +}; // What the gas table says a host function costs, by its guest import name. -// -// Read from the declaration through the `wasm_testkit` bridge rather than transcribed into -// C++: 61 copied constants would drift from `crates/xrpl-host-functions/src/lib.rs` the first -// time a price changed, and drift *silently*, because a benchmark has nothing to fail. +// Read from the declaration through the `wasm_testkit` bridge. double declaredGas(std::string_view wasmName); -// The gas a host call costs before it does anything: region decode, bounds checks, the cxx hop. -// -// Measured once per process the same way `secondsPerGas` is, and from the same pair the suite -// uses as its floor — `ldgr_index` through the VM minus `ldgr_index` called directly. It takes -// no input and answers from a header already in hand, so what remains after the subtraction is -// the crossing and nothing else. -// -// This is what makes a *suggested* price possible for a function that has only an `Impl` case: -// the impl measures the work, and this measures the toll every call pays on top of it. -double -crossingFloorGas(); - // Attach the calibration counters to a finished case. -// -// `secondsPerCall` is the isolated per-call cost. `chargedGas` is what the engine billed per -// call, or 0 for a direct-impl case where no VM was involved. `wasmName` names the host -// function so its declared price can be looked up; empty for the harness's own reference cases, -// which price nothing. -// -// `suggested_gas` is the headline: what the function *should* cost, in the same units as the -// declaration. For a `ThroughVm` case that is simply what was measured, since the guest already -// paid the crossing. For an `Impl` case the crossing has to be added back, because a guest -// cannot make the call without it. void report( benchmark::State& state, @@ -244,19 +137,6 @@ report( // Measure a host function *through the whole stack* — guest, VM, marshalling, real impl, // real ledger — with everything but the host calls subtracted away. -// -// `wasmName` is the guest import name, used to look up the declared price. `imports` declares -// the host function and `data` seeds any input bytes it reads; -// `body` is the call expression, which must leave one i32 on the stack. `setUp` prepares -// the ledger and returns the host to run against, so a case can fund accounts or create -// the object it reads. -// -// `calls` is how many host calls one run makes; a size-swept case should pass -// `callsWithinTransferBudget(bytesPerCall)` so the large end of its range stays inside the -// engine's copying budget. The reported numbers are per call either way. -// -// Register with `->UseManualTime()`: the reported time is the subtraction's result, not -// the wall time of the runs that produced it. template void benchmarkThroughVm( @@ -280,15 +160,6 @@ benchmarkThroughVm( // Confirm the contract actually succeeds before measuring it — and note that "the run // succeeded" is not enough to establish that. - // - // A soft host error is an *answer*, not a fault: the engine hands the guest a negative - // code and the run completes normally, `EscrowResult` and all. Gas is charged before the - // body too (`charged` in crates/xrpl-wasm-vm/src/abi.rs), so `charged_gas` looks correct - // for a call that did nothing. A case whose arguments are subtly wrong would therefore - // report a plausible, confidently wrong number — measuring the rejection path, which is - // much cheaper than the work. The tell is a `ThroughVm` case coming out faster than its - // `Impl` pair, which is impossible when one contains the other. - // // So require both: the run completed, and the contract's last host call returned a // non-negative result. Every body here leaves that result in `$r`, which the module // returns. @@ -327,19 +198,14 @@ benchmarkThroughVm( } if (rounds > 0) + { report(state, totalSeconds / rounds, totalGas / rounds, wasmName, true); + } } // Measure a host function's *impl alone* — the computation, with no guest, no VM and no // marshalling. Paired with the `ThroughVm` case for the same function, the difference is // what crossing the guest/host boundary costs. -// -// `wasmName` is the guest import name, used to look up the declared price. `call` invokes the -// host method and returns its result; `setUp` builds the ledger and -// host once, outside the timed region, so fixture setup is not measured. The inner loop -// runs `kCallsPerRun` calls per timed iteration, matching the VM case's shape and -// amortizing the clock read over enough work that it does not dominate a cheap impl. -// // Register with `->UseManualTime()`. template void @@ -380,7 +246,9 @@ benchmarkImpl(benchmark::State& state, std::string_view wasmName, SetUp&& setUp, // No VM ran, so nothing was charged — and the crossing this case leaves out is added back // into `suggested_gas`, because a guest cannot make the call without paying it. if (rounds > 0) + { report(state, totalSeconds / rounds, 0.0, wasmName, false); + } } } // namespace xrpl::test::bench diff --git a/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp b/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp index 44a6013d78..0fbcfd81df 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp @@ -8,6 +8,7 @@ #include #include +#include #include namespace xrpl::test { @@ -28,14 +29,14 @@ struct CacheLedgerObjE2e : RealVmTest TEST_F(CacheLedgerObjE2e, ContractComputesAKeyCachesTheObjectAndReadsItsField) { auto const owner = fund("owner"); - auto const wat = std::string{R"wat( + auto const wat = std::format( + R"wat( (module (import "host_lib" "accountroot_id" (func $accountroot_id (param i32 i32 i32 i32) (result i32))) (import "host_lib" "cache_le" (func $cache_le (param i32 i32 i32) (result i32))) (import "host_lib" "le_field" (func $le_field (param i32 i32 i32 i32) (result i32))) (memory (export "memory") 1) - (data (i32.const 0) ")wat"} + - watEscaped(RealHostFixture::toBytes(owner.id())) + R"wat(") + (data (i32.const 0) "{}") (func (export "escrow_finish") (result i32) (local $slot i32) (local $r i32) @@ -46,9 +47,10 @@ TEST_F(CacheLedgerObjE2e, ContractComputesAKeyCachesTheObjectAndReadsItsField) (local.set $slot (call $cache_le (i32.const 64) (i32.const 32) (i32.const 0))) (if (i32.lt_s (local.get $slot) (i32.const 0)) (then (return (local.get $slot)))) ;; And read a field of it through the slot the host just assigned. - (call $le_field (local.get $slot) (i32.const )wat" + - std::to_string(sfAccount.getCode()) + R"wat() (i32.const 128) (i32.const 32)))) -)wat"; + (call $le_field (local.get $slot) (i32.const {}) (i32.const 128) (i32.const 32)))) +)wat", + watEscaped(RealHostFixture::toBytes(owner.id())), + sfAccount.getCode()); auto const outcome = run(wat); ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); diff --git a/src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp b/src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp index 3e52c4b549..0f4d0392d8 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp @@ -11,6 +11,7 @@ #include #include +#include #include namespace xrpl::test { @@ -47,14 +48,15 @@ TEST_F(CurrentLedgerObjFieldE2e, ContractReadsAFieldOfItsRealEscrow) // Ask the current object for `sfAccount` and return the byte count the host wrote — 20 for // an account id — proving the read reached the real ledger and came back through the VM. - auto const wat = std::string{R"wat( + auto const wat = std::format( + R"wat( (module (import "host_lib" "home_le_field" (func $home_le_field (param i32 i32 i32) (result i32))) (memory (export "memory") 1) (func (export "escrow_finish") (result i32) - (call $home_le_field (i32.const )wat"} + - std::to_string(sfAccount.getCode()) + R"wat() (i32.const 0) (i32.const 32)))) -)wat"; + (call $home_le_field (i32.const {}) (i32.const 0) (i32.const 32)))) +)wat", + sfAccount.getCode()); auto const outcome = run(wat, escrow); ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); diff --git a/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp b/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp index 097118a521..454eaed7c0 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp @@ -6,6 +6,7 @@ #include #include +#include #include namespace xrpl::test { @@ -27,12 +28,12 @@ TEST_F(FloatToMantExpE2e, ContractReadsBothHalvesOfASplitFloat) // Pi's canonical encoding in, mantissa to offset 64, exponent to offset 128. The // contract returns the low half of the mantissa so the assertion checks that real bytes // landed in the guest's buffer, not merely that the call reported success. - auto const wat = std::string{R"wat( + auto const wat = std::format( + R"wat( (module (import "host_lib" "float_to_mant_exp" (func $split (param i32 i32 i32 i32 i32 i32) (result i32))) (memory (export "memory") 1) - (data (i32.const 0) ")wat"} + - watEscaped(FloatTest::kPi) + R"wat(") + (data (i32.const 0) "{}") (func (export "escrow_finish") (result i32) (local $r i32) (local.set $r (call $split @@ -41,7 +42,8 @@ TEST_F(FloatToMantExpE2e, ContractReadsBothHalvesOfASplitFloat) (i32.const 128) (i32.const 4))) (if (i32.lt_s (local.get $r) (i32.const 0)) (then (return (local.get $r)))) (i32.load (i32.const 64)))) -)wat"; +)wat", + watEscaped(FloatTest::kPi)); auto const outcome = run(wat); ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); diff --git a/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp b/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp index aaa9f6547e..2404fdd25a 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp @@ -8,6 +8,7 @@ #include #include +#include #include namespace xrpl::test { @@ -30,14 +31,15 @@ TEST_F(HostErrorE2e, ARealHostErrorReachesTheGuestAsItsWireCode) // guest reads was produced by the real lookup rather than staged. auto const owner = fund("owner"); - auto const wat = std::string{R"wat( + auto const wat = std::format( + R"wat( (module (import "host_lib" "home_le_field" (func $home_le_field (param i32 i32 i32) (result i32))) (memory (export "memory") 1) (func (export "escrow_finish") (result i32) - (call $home_le_field (i32.const )wat"} + - std::to_string(sfMemoData.getCode()) + R"wat() (i32.const 0) (i32.const 32)))) -)wat"; + (call $home_le_field (i32.const {}) (i32.const 0) (i32.const 32)))) +)wat", + sfMemoData.getCode()); auto const outcome = run(wat, keylet::account(owner.id())); diff --git a/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp b/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp index 0d882927b7..406c736d6c 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp @@ -9,6 +9,7 @@ #include #include +#include #include namespace xrpl::test { @@ -27,15 +28,16 @@ TEST_F(TxFieldE2e, ContractReadsAFieldOfItsTransaction) // Ask the tx for `sfAssetScale` (a single byte) and return the i32 the guest loads — the // scale, zero-extended — so the assertion checks the value flowed through, not just a count. - auto const wat = std::string{R"wat( + auto const wat = std::format( + R"wat( (module (import "host_lib" "tx_field" (func $tx_field (param i32 i32 i32) (result i32))) (memory (export "memory") 1) (func (export "escrow_finish") (result i32) - (drop (call $tx_field (i32.const )wat"} + - std::to_string(sfAssetScale.getCode()) + R"wat() (i32.const 0) (i32.const 4))) + (drop (call $tx_field (i32.const {}) (i32.const 0) (i32.const 4))) (i32.load (i32.const 0)))) -)wat"; +)wat", + sfAssetScale.getCode()); auto const outcome = run(wat, keylet::account(owner.id()), tx.type, tx.build); ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); diff --git a/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp b/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp index c30346b009..bce5a4060a 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -40,18 +41,19 @@ TEST_F(TxNestedFieldE2e, ContractWalksALocatorToANestedTransactionField) auto const owner = fund("owner"); auto assembler = withMemo(owner); - auto const wat = std::string{R"wat( + auto const wat = std::format( + R"wat( (module (import "host_lib" "tx_inner" (func $tx_inner (param i32 i32 i32 i32) (result i32))) (memory (export "memory") 1) (func (export "escrow_finish") (result i32) - (i32.store (i32.const 0) (i32.const )wat"} + - std::to_string(sfMemos.getCode()) + R"wat()) + (i32.store (i32.const 0) (i32.const {})) (i32.store (i32.const 4) (i32.const 0)) - (i32.store (i32.const 8) (i32.const )wat" + - std::to_string(sfMemoData.getCode()) + R"wat()) + (i32.store (i32.const 8) (i32.const {})) (call $tx_inner (i32.const 0) (i32.const 12) (i32.const 64) (i32.const 32)))) -)wat"; +)wat", + sfMemos.getCode(), + sfMemoData.getCode()); auto const outcome = run(wat, keylet::account(owner.id()), assembler.type, assembler.build); ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp index e8d71b1e30..cccdb5d12b 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp @@ -15,8 +15,8 @@ accountKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.accountKeylet(benchAlice().id()); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.accountKeylet(Fixtures::instance().alice().id()); }); } BENCHMARK(accountKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp index dcd568b7c9..fcc85eb6c4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp @@ -16,13 +16,13 @@ ammKeyletImpl(benchmark::State& state) { static constexpr auto kWasmName = std::string_view{"amm_id"}; - auto const usd = Asset{Issue{toCurrency("USD"), benchAlice().id()}}; + auto const usd = Asset{Issue{toCurrency("USD"), Fixtures::instance().alice().id()}}; auto const xrp = Asset{xrpIssue()}; benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [&usd, &xrp](auto& host) { return host.ammKeylet(usd, xrp); }); } BENCHMARK(ammKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp index 99a3e3f918..052b0b4186 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp @@ -13,7 +13,10 @@ baseFeeImpl(benchmark::State& state) static constexpr auto kWasmName = std::string_view{"base_fee"}; benchmarkImpl( - state, kWasmName, [] { return benchHost(); }, [](auto& host) { return host.getBaseFee(); }); + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getBaseFee(); }); } BENCHMARK(baseFeeImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp index 065b521443..df54cfa899 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp @@ -14,12 +14,12 @@ cacheLedgerObjImpl(benchmark::State& state) { static constexpr auto kWasmName = std::string_view{"cache_le"}; - auto const key = keylet::account(benchAlice().id()).key; + auto const key = keylet::account(Fixtures::instance().alice().id()).key; benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [&key](auto& host) { return host.cacheLedgerObj(key, 1); }); } BENCHMARK(cacheLedgerObjImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp index 71e57b183d..2390de6f31 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp @@ -15,8 +15,10 @@ checkKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.checkKeylet(benchAlice().id(), kBenchSeq); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.checkKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); } BENCHMARK(checkKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp index 2d99b625b7..c958ac3332 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -24,16 +25,21 @@ constexpr std::int32_t kPubkeyOffset = 512; void checkSignatureThroughVm(benchmark::State& state) { - auto const& m = benchSignedMessage(); + auto const& m = Fixtures::instance().signedMessage(); static auto const kData = dataSegment(kMessageOffset, m.message) + dataSegment(kSignatureOffset, m.signature) + dataSegment(kPubkeyOffset, m.publicKey); - static auto const kBody = std::string{"(call $check_sig (i32.const "} + - std::to_string(kMessageOffset) + ") (i32.const " + std::to_string(m.message.size()) + - ") (i32.const " + std::to_string(kSignatureOffset) + ") (i32.const " + - std::to_string(m.signature.size()) + ") (i32.const " + std::to_string(kPubkeyOffset) + - ") (i32.const " + std::to_string(m.publicKey.size()) + "))"; + static auto const kBody = std::format( + "(call $check_sig (i32.const {}) (i32.const {}) (i32.const {}) (i32.const {}) " + "(i32.const {}) (i32.const {}))", + kMessageOffset, + m.message.size(), + kSignatureOffset, + m.signature.size(), + kPubkeyOffset, + m.publicKey.size()); - benchmarkThroughVm(state, kWasmName, kImport, kData, kBody, [] { return benchHost(); }); + benchmarkThroughVm( + state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); } BENCHMARK(checkSignatureThroughVm)->UseManualTime()->Iterations(kBenchIterations); @@ -43,9 +49,9 @@ checkSignatureImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [](auto& host) { - auto const& m = benchSignedMessage(); + auto const& m = Fixtures::instance().signedMessage(); return host.checkSignature( Slice{m.message.data(), m.message.size()}, Slice{m.signature.data(), m.signature.size()}, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp index ddfd84654d..d8ed3844e6 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp @@ -18,10 +18,12 @@ credentialKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [](auto& host) { return host.credentialKeylet( - benchAlice().id(), benchBob().id(), Slice{kType.data(), kType.size()}); + Fixtures::instance().alice().id(), + Fixtures::instance().bob().id(), + Slice{kType.data(), kType.size()}); }); } BENCHMARK(credentialKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp index 340ed964b6..9f59f186e9 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp @@ -17,7 +17,7 @@ currentLedgerObjArrayLenImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchSignerListHost(); }, + [] { return Fixtures::instance().signerListHost(); }, [](auto& host) { return host.getCurrentLedgerObjArrayLen(sfSignerEntries); }); } BENCHMARK(currentLedgerObjArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp index f163cdcf16..a5cc479484 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include namespace xrpl::test::bench { @@ -18,10 +18,11 @@ constexpr std::string_view kImport = void currentLedgerObjFieldThroughVm(benchmark::State& state) { - static auto const kBody = std::string{"(call $home_le_field (i32.const "} + - std::to_string(sfAccount.getCode()) + ") (i32.const 0) (i32.const 32))"; + static auto const kBody = std::format( + "(call $home_le_field (i32.const {}) (i32.const 0) (i32.const 32))", sfAccount.getCode()); - benchmarkThroughVm(state, kWasmName, kImport, "", kBody, [] { return benchEscrowHost(); }); + benchmarkThroughVm( + state, kWasmName, kImport, "", kBody, [] { return Fixtures::instance().escrowHost(); }); } BENCHMARK(currentLedgerObjFieldThroughVm)->UseManualTime()->Iterations(kBenchIterations); @@ -31,7 +32,7 @@ currentLedgerObjFieldImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchEscrowHost(); }, + [] { return Fixtures::instance().escrowHost(); }, [](auto& host) { return host.getCurrentLedgerObjField(sfAccount); }); } BENCHMARK(currentLedgerObjFieldImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp index bc3857d55f..0086e13d72 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp @@ -18,7 +18,7 @@ currentLedgerObjNestedArrayLenImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchSignerListHost(); }, + [] { return Fixtures::instance().signerListHost(); }, [](auto& host) { return host.getCurrentLedgerObjNestedArrayLen( FieldLocator{{sfSignerEntries.getCode()}}); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp index f88a939c9c..423107409a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp @@ -18,7 +18,7 @@ currentLedgerObjNestedFieldImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [](auto& host) { return host.getCurrentLedgerObjNestedField(FieldLocator{{sfAccount.getCode()}}); }); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp index 066efdedf4..4cbc3f7921 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp @@ -15,8 +15,11 @@ delegateKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.delegateKeylet(benchAlice().id(), benchBob().id()); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.delegateKeylet( + Fixtures::instance().alice().id(), Fixtures::instance().bob().id()); + }); } BENCHMARK(delegateKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp index 0cb8f9a284..5064652ba5 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp @@ -15,8 +15,11 @@ depositPreauthKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.depositPreauthKeylet(benchAlice().id(), benchBob().id()); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.depositPreauthKeylet( + Fixtures::instance().alice().id(), Fixtures::instance().bob().id()); + }); } BENCHMARK(depositPreauthKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp index 26456e5293..1f0b280894 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp @@ -15,8 +15,8 @@ didKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.didKeylet(benchAlice().id()); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.didKeylet(Fixtures::instance().alice().id()); }); } BENCHMARK(didKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp index 1d727f74cf..f234bb56ca 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp @@ -28,12 +28,14 @@ escrowKeyletThroughVm(benchmark::State& state) auto seq = Bytes(4); for (auto i = 0U; i < 4; ++i) { - seq[i] = static_cast((kBenchSeq >> (8 * i)) & 0xFF); + seq[i] = static_cast((Fixtures::kSeq >> (8 * i)) & 0xFF); } - return dataSegment(0, RealHostFixture::toBytes(benchAlice().id())) + dataSegment(32, seq); + return dataSegment(0, RealHostFixture::toBytes(Fixtures::instance().alice().id())) + + dataSegment(32, seq); }(); - benchmarkThroughVm(state, kWasmName, kImport, kData, kBody, [] { return benchHost(); }); + benchmarkThroughVm( + state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); } BENCHMARK(escrowKeyletThroughVm)->UseManualTime()->Iterations(kBenchIterations); @@ -43,8 +45,10 @@ escrowKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.escrowKeylet(benchAlice().id(), kBenchSeq); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.escrowKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); } BENCHMARK(escrowKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp index e416c24c08..4978c35300 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp @@ -22,7 +22,8 @@ void floatAddThroughVm(benchmark::State& state) { static auto const kData = dataSegment(0, FloatTest::kPi) + dataSegment(16, FloatTest::kTwo); - benchmarkThroughVm(state, kWasmName, kImport, kData, kBody, [] { return benchHost(); }); + benchmarkThroughVm( + state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); } BENCHMARK(floatAddThroughVm)->UseManualTime()->Iterations(kBenchIterations); @@ -32,8 +33,10 @@ floatAddImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.floatAdd(benchFloatX(), benchFloatY(), kBenchMode); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.floatAdd(Fixtures::floatX(), Fixtures::floatY(), Fixtures::kRoundingMode); + }); } BENCHMARK(floatAddImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp index 3026159b9c..a03dce32fa 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp @@ -15,8 +15,8 @@ floatCompareImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.floatCompare(benchFloatX(), benchFloatY()); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.floatCompare(Fixtures::floatX(), Fixtures::floatY()); }); } BENCHMARK(floatCompareImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp index a1f8387813..ed8fe9f154 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp @@ -15,8 +15,11 @@ floatDivideImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.floatDivide(benchFloatX(), benchFloatY(), kBenchMode); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.floatDivide( + Fixtures::floatX(), Fixtures::floatY(), Fixtures::kRoundingMode); + }); } BENCHMARK(floatDivideImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp index abad146607..90d3913e15 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp @@ -15,8 +15,8 @@ floatFromIntImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.floatFromInt(3141592653589793, kBenchMode); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.floatFromInt(3141592653589793, Fixtures::kRoundingMode); }); } BENCHMARK(floatFromIntImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp index 5dc04e290e..665eaa914f 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp @@ -15,8 +15,10 @@ floatFromMantExpImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.floatFromMantExp(3141592653589793, -15, kBenchMode); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.floatFromMantExp(3141592653589793, -15, Fixtures::kRoundingMode); + }); } BENCHMARK(floatFromMantExpImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp index c3b24ee2ef..23868feedc 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp @@ -16,13 +16,14 @@ floatFromStAmountImpl(benchmark::State& state) { static constexpr auto kWasmName = std::string_view{"float_from_stamount"}; - auto const amount = STAmount{Issue{toCurrency("USD"), benchAlice().id()}, 1234567, -3}; + auto const amount = + STAmount{Issue{toCurrency("USD"), Fixtures::instance().alice().id()}, 1234567, -3}; benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [&amount](auto& host) { return host.floatFromSTAmount(amount, kBenchMode); }); + [] { return Fixtures::instance().host(); }, + [&amount](auto& host) { return host.floatFromSTAmount(amount, Fixtures::kRoundingMode); }); } BENCHMARK(floatFromStAmountImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp index e99507872d..e97e626fbc 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp @@ -21,8 +21,8 @@ floatFromStNumberImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [&number](auto& host) { return host.floatFromSTNumber(number, kBenchMode); }); + [] { return Fixtures::instance().host(); }, + [&number](auto& host) { return host.floatFromSTNumber(number, Fixtures::kRoundingMode); }); } BENCHMARK(floatFromStNumberImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp index 861dadbb1f..a16a836ff9 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp @@ -15,8 +15,8 @@ floatFromUintImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.floatFromUint(3141592653589793u, kBenchMode); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.floatFromUint(3141592653589793u, Fixtures::kRoundingMode); }); } BENCHMARK(floatFromUintImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp index 17688b44bc..085a56ddc9 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp @@ -15,8 +15,11 @@ floatMultiplyImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.floatMultiply(benchFloatX(), benchFloatY(), kBenchMode); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.floatMultiply( + Fixtures::floatX(), Fixtures::floatY(), Fixtures::kRoundingMode); + }); } BENCHMARK(floatMultiplyImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp index bd94fdc8b4..cc4bd4c2cf 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp @@ -22,7 +22,8 @@ void floatPowerThroughVm(benchmark::State& state) { static auto const kData = dataSegment(0, FloatTest::kPi); - benchmarkThroughVm(state, kWasmName, kImport, kData, kBody, [] { return benchHost(); }); + benchmarkThroughVm( + state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); } BENCHMARK(floatPowerThroughVm)->UseManualTime()->Iterations(kBenchIterations); @@ -32,8 +33,8 @@ floatPowerImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.floatPower(benchFloatX(), 7, kBenchMode); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.floatPower(Fixtures::floatX(), 7, Fixtures::kRoundingMode); }); } BENCHMARK(floatPowerImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp index 6307ca2648..84e2e46b08 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp @@ -15,8 +15,8 @@ floatRootImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.floatRoot(benchFloatX(), 2, kBenchMode); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.floatRoot(Fixtures::floatX(), 2, Fixtures::kRoundingMode); }); } BENCHMARK(floatRootImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp index e5e8a9a05f..82c08f1040 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp @@ -15,8 +15,11 @@ floatSubtractImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.floatSubtract(benchFloatX(), benchFloatY(), kBenchMode); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.floatSubtract( + Fixtures::floatX(), Fixtures::floatY(), Fixtures::kRoundingMode); + }); } BENCHMARK(floatSubtractImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp index 41fb345268..937fb61238 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp @@ -15,8 +15,8 @@ floatToIntImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.floatToInt(benchFloatX(), kBenchMode); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.floatToInt(Fixtures::floatX(), Fixtures::kRoundingMode); }); } BENCHMARK(floatToIntImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp index 2deeb88ce2..8ff4610c88 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp @@ -21,7 +21,8 @@ void floatToMantExpThroughVm(benchmark::State& state) { static auto const kData = dataSegment(0, FloatTest::kPi); - benchmarkThroughVm(state, kWasmName, kImport, kData, kBody, [] { return benchHost(); }); + benchmarkThroughVm( + state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); } BENCHMARK(floatToMantExpThroughVm)->UseManualTime()->Iterations(kBenchIterations); @@ -31,8 +32,8 @@ floatToMantExpImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.floatToMantExp(benchFloatX()); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.floatToMantExp(Fixtures::floatX()); }); } BENCHMARK(floatToMantExpImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp index a10a911e40..c83be9a784 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp @@ -33,7 +33,7 @@ isAmendmentEnabledByIdImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [&id](auto& host) { return host.isAmendmentEnabled(id); }); } BENCHMARK(isAmendmentEnabledByIdImpl)->UseManualTime()->Iterations(kBenchIterations); @@ -45,7 +45,7 @@ isAmendmentEnabledByNameImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [](auto& host) { return host.isAmendmentEnabled(std::string_view{benchAmendment()}); }); } BENCHMARK(isAmendmentEnabledByNameImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp index a3373c8d55..20ce7eec81 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp @@ -17,7 +17,7 @@ ledgerObjArrayLenImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchCachedSignerListHost(); }, + [] { return Fixtures::instance().cachedSignerListHost(); }, [](auto& host) { return host.getLedgerObjArrayLen(1, sfSignerEntries); }); } BENCHMARK(ledgerObjArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp index b791ffa469..c177394202 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp @@ -17,7 +17,7 @@ ledgerObjFieldImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchCachedHost(); }, + [] { return Fixtures::instance().cachedHost(); }, [](auto& host) { return host.getLedgerObjField(1, sfAccount); }); } BENCHMARK(ledgerObjFieldImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp index 3f2a732658..93f3936c83 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp @@ -18,7 +18,7 @@ ledgerObjNestedArrayLenImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchCachedSignerListHost(); }, + [] { return Fixtures::instance().cachedSignerListHost(); }, [](auto& host) { return host.getLedgerObjNestedArrayLen(1, FieldLocator{{sfSignerEntries.getCode()}}); }); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp index 9c2367895f..0bcade3ffe 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp @@ -18,7 +18,7 @@ ledgerObjNestedFieldImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchCachedHost(); }, + [] { return Fixtures::instance().cachedHost(); }, [](auto& host) { return host.getLedgerObjNestedField(1, FieldLocator{{sfAccount.getCode()}}); }); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp index a95d0641be..5d8140f586 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp @@ -18,7 +18,7 @@ ledgerSqnThroughVm(benchmark::State& state) { benchmarkThroughVm( state, kWasmName, kImport, "", "(call $ldgr_index (i32.const 0) (i32.const 4))", [] { - return benchHost(); + return Fixtures::instance().host(); }); } BENCHMARK(ledgerSqnThroughVm)->UseManualTime()->Iterations(kBenchIterations); @@ -29,7 +29,7 @@ ledgerSqnImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [](auto& host) { return host.getLedgerSqn(); }); } BENCHMARK(ledgerSqnImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp index 55a371e08e..8bcfa8a344 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp @@ -15,8 +15,10 @@ mptokenIssuanceKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.mptokenIssuanceKeylet(benchAlice().id(), kBenchSeq); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.mptokenIssuanceKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); } BENCHMARK(mptokenIssuanceKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp index 618643e908..ca534e8939 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp @@ -15,13 +15,15 @@ mptokenKeyletImpl(benchmark::State& state) { static constexpr auto kWasmName = std::string_view{"mptoken_id"}; - auto const mptid = makeMptID(1, benchAlice().id()); + auto const mptid = makeMptID(1, Fixtures::instance().alice().id()); benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [&mptid](auto& host) { return host.mptokenKeylet(mptid, benchBob().id()); }); + [] { return Fixtures::instance().host(); }, + [&mptid](auto& host) { + return host.mptokenKeylet(mptid, Fixtures::instance().bob().id()); + }); } BENCHMARK(mptokenKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp index 5810f8439b..65a341415b 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp @@ -15,8 +15,8 @@ nftFlagsImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.getNFTFlags(benchNftId()); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getNFTFlags(Fixtures::instance().nftId()); }); } BENCHMARK(nftFlagsImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp index a8880b3525..5eb4327803 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp @@ -15,8 +15,8 @@ nftIssuerImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.getNFTIssuer(benchNftId()); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getNFTIssuer(Fixtures::instance().nftId()); }); } BENCHMARK(nftIssuerImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp index bef68d7dbf..fc456ab245 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp @@ -15,8 +15,8 @@ nftSequenceImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.getNFTSequence(benchNftId()); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getNFTSequence(Fixtures::instance().nftId()); }); } BENCHMARK(nftSequenceImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp index f27a5fbf0d..284b157bde 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp @@ -15,8 +15,8 @@ nftTaxonImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.getNFTTaxon(benchNftId()); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getNFTTaxon(Fixtures::instance().nftId()); }); } BENCHMARK(nftTaxonImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp index 0318557ce0..fe5d0eb7b1 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp @@ -15,8 +15,8 @@ nftTransferFeeImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.getNFTTransferFee(benchNftId()); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getNFTTransferFee(Fixtures::instance().nftId()); }); } BENCHMARK(nftTransferFeeImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp index 1326979aab..4882258566 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp @@ -15,8 +15,10 @@ nftokenOfferKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.nftokenOfferKeylet(benchAlice().id(), kBenchSeq); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.nftokenOfferKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); } BENCHMARK(nftokenOfferKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp index 8884697a9d..5bf1bb6510 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp @@ -15,8 +15,10 @@ offerKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.offerKeylet(benchAlice().id(), kBenchSeq); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.offerKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); } BENCHMARK(offerKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp index dd39bb06eb..069e83b8df 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp @@ -15,8 +15,10 @@ oracleKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.oracleKeylet(benchAlice().id(), kBenchSeq); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.oracleKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); } BENCHMARK(oracleKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp index 0b864f3971..52632e1b01 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp @@ -15,7 +15,7 @@ parentLedgerHashImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [](auto& host) { return host.getParentLedgerHash(); }); } BENCHMARK(parentLedgerHashImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp index 9b0b146ffb..c65a1b85b5 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp @@ -15,7 +15,7 @@ parentLedgerTimeImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [](auto& host) { return host.getParentLedgerTime(); }); } BENCHMARK(parentLedgerTimeImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp index 1efd32715a..5fb8aa800b 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp @@ -15,9 +15,10 @@ paychannelKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [](auto& host) { - return host.paychannelKeylet(benchAlice().id(), benchBob().id(), kBenchSeq); + return host.paychannelKeylet( + Fixtures::instance().alice().id(), Fixtures::instance().bob().id(), Fixtures::kSeq); }); } BENCHMARK(paychannelKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp index c268fc4be4..6ef99a02e6 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp @@ -15,8 +15,10 @@ permissionedDomainKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.permissionedDomainKeylet(benchAlice().id(), kBenchSeq); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.permissionedDomainKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); } BENCHMARK(permissionedDomainKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp index 9c3f32115b..55a38d59b8 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include namespace xrpl::test::bench { @@ -26,8 +26,9 @@ sha512HalfThroughVm(benchmark::State& state) { // Zeroed guest memory is a perfectly good hash input: `sha512_half` validates nothing about // its bytes, so there is no data segment to seed. - auto const body = std::string{"(call $sha512_half (i32.const 0) (i32.const "} + - std::to_string(state.range(0)) + ") (i32.const 8192) (i32.const 32))"; + auto const body = std::format( + "(call $sha512_half (i32.const 0) (i32.const {}) (i32.const 8192) (i32.const 32))", + state.range(0)); // The call count shrinks as the input grows: at 1 KiB a thousand calls would approach the // engine's per-run transfer budget and the tail of the loop would be measuring refusals. @@ -37,7 +38,7 @@ sha512HalfThroughVm(benchmark::State& state) kImport, "", body, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, callsWithinTransferBudget(state.range(0) + 32)); state.SetBytesProcessed(state.iterations() * state.range(0)); } @@ -54,7 +55,7 @@ sha512HalfImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [&data](auto& host) { return host.computeSha512HalfHash(Slice{data.data(), data.size()}); }); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp index 18776662e0..e66ead3f5e 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp @@ -15,8 +15,8 @@ signerListKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.signerListKeylet(benchAlice().id()); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.signerListKeylet(Fixtures::instance().alice().id()); }); } BENCHMARK(signerListKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp index d4d79985ef..a3276ce2c2 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp @@ -15,8 +15,10 @@ ticketKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.ticketKeylet(benchAlice().id(), kBenchSeq); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.ticketKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); } BENCHMARK(ticketKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp index 4858d54cd9..ac84a70bbd 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp @@ -18,7 +18,7 @@ traceDisabledImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchLedger().makeHost(); }, + [] { return Fixtures::instance().host(); }, [](auto& host) { return host.trace(kMessage, kData); }); } BENCHMARK(traceDisabledImpl)->UseManualTime()->Iterations(kBenchIterations); @@ -31,7 +31,7 @@ traceEnabledImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchLedger().makeTracingHost(); }, + [] { return Fixtures::instance().tracingHost(); }, [](auto& host) { return host.trace(kMessage, kData); }); } BENCHMARK(traceEnabledImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp index 750d6956de..4f187159bb 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp @@ -19,9 +19,10 @@ trustLineKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [¤cy](auto& host) { - return host.trustLineKeylet(benchAlice().id(), benchBob().id(), currency); + return host.trustLineKeylet( + Fixtures::instance().alice().id(), Fixtures::instance().bob().id(), currency); }); } BENCHMARK(trustLineKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp index 63b2614f31..b4fb17077a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp @@ -17,7 +17,7 @@ txArrayLenImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [](auto& host) { return host.getTxArrayLen(sfMemos); }); } BENCHMARK(txArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp index 0001f59bcc..6d858cd783 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp @@ -17,7 +17,7 @@ txFieldImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [](auto& host) { return host.getTxField(sfAccount); }); } BENCHMARK(txFieldImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp index a562f8eee4..4f6ecf0ba2 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp @@ -18,7 +18,7 @@ txNestedArrayLenImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [](auto& host) { return host.getTxNestedArrayLen(FieldLocator{{sfMemos.getCode()}}); }); } BENCHMARK(txNestedArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp index 79d7b5a685..f131d292c6 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp @@ -35,7 +35,8 @@ txNestedFieldThroughVm(benchmark::State& state) return bytes; }()); - benchmarkThroughVm(state, kWasmName, kImport, kData, kBody, [] { return benchHost(); }); + benchmarkThroughVm( + state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); } BENCHMARK(txNestedFieldThroughVm)->UseManualTime()->Iterations(kBenchIterations); @@ -45,8 +46,8 @@ txNestedFieldImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.getTxNestedField(benchMemoLocator()); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getTxNestedField(Fixtures::memoLocator()); }); } BENCHMARK(txNestedFieldImpl)->UseManualTime()->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp index eee496bb76..4df7fc5478 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include namespace xrpl::test::bench { @@ -21,8 +21,7 @@ constexpr std::string_view kImport = void updateDataThroughVm(benchmark::State& state) { - auto const body = std::string{"(call $set_data (i32.const 0) (i32.const "} + - std::to_string(state.range(0)) + "))"; + auto const body = std::format("(call $set_data (i32.const 0) (i32.const {}))", state.range(0)); benchmarkThroughVm( state, @@ -30,7 +29,7 @@ updateDataThroughVm(benchmark::State& state) kImport, "", body, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, callsWithinTransferBudget(state.range(0))); state.SetBytesProcessed(state.iterations() * state.range(0)); } @@ -47,7 +46,7 @@ updateDataImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, + [] { return Fixtures::instance().host(); }, [&data](auto& host) { return host.updateData(Slice{data.data(), data.size()}); }); state.SetBytesProcessed(state.iterations() * state.range(0)); } diff --git a/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp index 00f3acebb1..409b465be6 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp @@ -15,8 +15,10 @@ vaultKeyletImpl(benchmark::State& state) benchmarkImpl( state, kWasmName, - [] { return benchHost(); }, - [](auto& host) { return host.vaultKeylet(benchAlice().id(), kBenchSeq); }); + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.vaultKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); } BENCHMARK(vaultKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); From 2787af8cd06815e97ac3f47768d0590e680ed149 Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Wed, 26 Aug 2026 22:16:43 -0400 Subject: [PATCH 13/23] chore: Address self review comments --- .../libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp | 1 - src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp index c958ac3332..e883866627 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp @@ -6,7 +6,6 @@ #include #include -#include #include namespace xrpl::test::bench { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp index f234bb56ca..a1848ec200 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp @@ -6,7 +6,6 @@ #include #include -#include #include namespace xrpl::test::bench { From 5973d606650d16f9652848a210503a5a110db659 Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Thu, 27 Aug 2026 16:15:34 -0400 Subject: [PATCH 14/23] fix: Correct variance between charged and implied gas for guestInstruction test --- src/tests/libxrpl/tx/wasm/README.md | 22 +++++++-- src/tests/libxrpl/tx/wasm/WasmBench.cpp | 60 +++++++++++++------------ src/tests/libxrpl/tx/wasm/WasmBench.h | 8 ++++ 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/tests/libxrpl/tx/wasm/README.md b/src/tests/libxrpl/tx/wasm/README.md index 382362d910..7eb89488a4 100644 --- a/src/tests/libxrpl/tx/wasm/README.md +++ b/src/tests/libxrpl/tx/wasm/README.md @@ -152,9 +152,22 @@ equal the declared gas plus the fuel the guest itself burns — the loop body (1 `GuestInstruction` reports on its own) plus the `i32.const`s pushing the call's arguments. So `escrow_id` reports `charged_gas ≈ 367` against a declared 350: 13 for the loop, 4 for its six argument constants. When that arithmetic does not line up, the case is measuring something other -than the call it names. `GuestInstruction` in -`Crossing.bench.cpp` is the same check applied to step 1: its `implied_gas` and `charged_gas` are -two independent measurements of the same quantity and should agree closely. +than the call it names. + +**`guestInstruction` is the harness's self-test, and it has a number.** It runs the same loop body +`Calibration::secondsPerGas()` calibrates against, so its `implied_gas` (from wall time) and +`charged_gas` (from the engine's fuel meter) are two measurements of one quantity and must agree. +On a quiet machine, Release, that is currently **`implied_gas` ≈ 13.6 against `charged_gas` 13.007 +— about 4% high, with roughly 4% run-to-run spread.** Treat a persistent gap much beyond that as a +harness bug rather than a property of the machine, and do not trust any other number in the run +until it is closed. + +That check is worth running because it has already caught a real defect. Calibration originally +took a _best-of-N_ while the cases report a _mean_, and since `implied_gas = +secondsPerCall / secondsPerGas`, a minimum in the divisor against a mean in the dividend biased +every reported number one way — `guestInstruction` read 18.2 against 13.007, +40%, and every +`suggested_gas` in the report was inflated by that factor. Both estimators are now means. **If you +change how either side is estimated, change both.** **Two limitations, both real.** @@ -163,6 +176,9 @@ two independent measurements of the same quantity and should agree closely. (`Sha512Half`, `UpdateData`) measure that per-byte term where it matters. - A Debug build inflates the crossing far more than the impls, so absolute values are not usable there. **Ratios between `Impl` cases survive Debug; `suggested_gas` does not.** +- Run-to-run spread is a few percent, which is immaterial next to the pricing errors this suite finds + (6x-20x). If you need it tighter, `--benchmark_repetitions=N` averages the noise down; it will + not touch a systematic bias, which is what the `guestInstruction` check above is for. ### The two case kinds, and why the subtraction is the point diff --git a/src/tests/libxrpl/tx/wasm/WasmBench.cpp b/src/tests/libxrpl/tx/wasm/WasmBench.cpp index 6f0efe2fc0..397ef65f00 100644 --- a/src/tests/libxrpl/tx/wasm/WasmBench.cpp +++ b/src/tests/libxrpl/tx/wasm/WasmBench.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -83,6 +82,17 @@ namespace { // Seconds of wall time one unit of gas buys on this machine. See `Calibration` for why this is // a difference rather than a single measurement. +// +// The estimator has to be the *same* one the cases use — a mean over `kBenchIterations` pairs, +// with the same clamp at zero as `benchmarkThroughVm`. This is not a stylistic point. Since +// `implied_gas = secondsPerCall / secondsPerGas`, any systematic difference between how the +// divisor and the dividend are estimated lands directly in every reported number. A minimum +// sits below a mean, so calibrating with a best-of while measuring cases with a mean biases +// `secondsPerGas` low and every `implied_gas` and `suggested_gas` correspondingly high. +// +// `guestInstruction` in Crossing.bench.cpp is the check that this holds: it runs this exact loop +// body, so its `implied_gas` and `charged_gas` are two measurements of one quantity and must +// agree within a few percent. double measureSecondsPerGas() { @@ -102,29 +112,30 @@ measureSecondsPerGas() timeRun(*fixture.makeHost(), idle); } - // Best-of over several pairs: the minimum is the run least disturbed by the scheduler, which - // is the honest floor for what this machine can do. - auto best = std::numeric_limits::max(); + auto total = 0.0; + // Fuel is exact and deterministic, so any pair gives the same delta. auto gasDelta = std::int64_t{1}; - for (auto i = 0U; i < 32; ++i) + for (auto i = 0; i < kCalibrationPairs; ++i) { auto hotHost = fixture.makeHost(); auto const hot = timeRun(*hotHost, busy); auto coldHost = fixture.makeHost(); auto const cold = timeRun(*coldHost, idle); - auto const delta = hot.seconds - cold.seconds; - if (delta > 0.0 && delta < best) - { - best = delta; - gasDelta = std::max(std::int64_t{1}, hot.gas - cold.gas); - } + + total += std::max(0.0, hot.seconds - cold.seconds); + gasDelta = std::max(std::int64_t{1}, hot.gas - cold.gas); } - return best == std::numeric_limits::max() ? 0.0 : best / static_cast(gasDelta); + + return (total / kCalibrationPairs) / static_cast(gasDelta); } // The crossing, in gas: `ldgr_index` through the VM minus `ldgr_index` called directly. // `secondsPerGas` has to be the value from the same snapshot, so it is passed in rather than // re-measured. +// +// Both halves are means for the same reason `measureSecondsPerGas` is: the VM half has to match +// `benchmarkThroughVm`'s estimator and the impl half `benchmarkImpl`'s, or the crossing is the +// difference of two numbers computed differently. double measureCrossingFloorGas(double secondsPerGas) { @@ -138,29 +149,22 @@ measureCrossingFloorGas(double secondsPerGas) auto fixture = BenchFixture{}; - auto best = std::numeric_limits::max(); - for (auto i = 0U; i < 16; ++i) + auto vmTotal = 0.0; + for (auto i = 0; i < kBenchIterations; ++i) { auto hotHost = fixture.makeHost(); auto const hot = timeRun(*hotHost, loaded); auto coldHost = fixture.makeHost(); auto const cold = timeRun(*coldHost, baseline); - auto const perCall = (hot.seconds - cold.seconds) / kCallsPerRun; - if (perCall > 0.0 && perCall < best) - { - best = perCall; - } - } - if (best == std::numeric_limits::max()) - { - return 0.0; + vmTotal += std::max(0.0, hot.seconds - cold.seconds) / kCallsPerRun; } + auto const vmSeconds = vmTotal / kBenchIterations; // The impl side is the same call without the VM. Subtracting it leaves the crossing. - auto implSeconds = std::numeric_limits::max(); + auto implTotal = 0.0; auto host = fixture.makeHost(); - for (auto i = 0U; i < 16; ++i) + for (auto i = 0; i < kBenchIterations; ++i) { auto const start = std::chrono::steady_clock::now(); for (auto c = 0U; c < kCallsPerRun; ++c) @@ -169,11 +173,11 @@ measureCrossingFloorGas(double secondsPerGas) benchmark::DoNotOptimize(result); } auto const elapsed = std::chrono::steady_clock::now() - start; - implSeconds = - std::min(implSeconds, std::chrono::duration(elapsed).count() / kCallsPerRun); + implTotal += std::chrono::duration(elapsed).count() / kCallsPerRun; } + auto const implSeconds = implTotal / kBenchIterations; - return secondsPerGas > 0.0 ? std::max(0.0, best - implSeconds) / secondsPerGas : 0.0; + return secondsPerGas > 0.0 ? std::max(0.0, vmSeconds - implSeconds) / secondsPerGas : 0.0; } } // namespace diff --git a/src/tests/libxrpl/tx/wasm/WasmBench.h b/src/tests/libxrpl/tx/wasm/WasmBench.h index 059d6bf7f1..6da4071c0e 100644 --- a/src/tests/libxrpl/tx/wasm/WasmBench.h +++ b/src/tests/libxrpl/tx/wasm/WasmBench.h @@ -40,6 +40,14 @@ inline constexpr std::int32_t kCallsPerRun = 1000; // `->UseManualTime()->Iterations(kBenchIterations)`. inline constexpr std::int32_t kBenchIterations = 50; +// How many pairs the one-off calibration averages. Higher than `kBenchIterations` because +// `secondsPerGas` is the divisor for *every* reported number, so its noise is common-mode across +// the whole report, and because calibration runs a bare wasm loop with no ledger and no host +// calls — a few hundred extra pairs cost milliseconds. More samples of a mean is only more +// precision, not a different estimator, so this does not reintroduce the bias that mixing a +// best-of with a mean did. +inline constexpr std::int32_t kCalibrationPairs = 400; + // Every run gets this much guest<->host copying before `charge_transfer` starts refusing // calls. It is a per-run budget, so it resets between the runs a benchmark makes — // but a single run of `kCallsPerRun` calls moving a kilobyte each would exhaust it partway From fe38635dd02f4221a1a8190b0f94eaa971af918c Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Tue, 1 Sep 2026 12:31:03 -0400 Subject: [PATCH 15/23] chore: Addressing code review code comments --- crates/xrpl-wasm-testkit/src/lib.rs | 12 ++-- src/benchmarks/libxrpl/CMakeLists.txt | 57 +++++---------- src/tests/libxrpl/CMakeLists.txt | 50 ++++++++++--- src/tests/libxrpl/tx/wasm/Crossing.bench.cpp | 4 +- src/tests/libxrpl/tx/wasm/NFTFixture.h | 33 --------- src/tests/libxrpl/tx/wasm/Preflight.cpp | 4 +- src/tests/libxrpl/tx/wasm/README.md | 30 ++++++-- src/tests/libxrpl/tx/wasm/WasmVM.cpp | 4 +- .../libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp | 6 +- .../tx/wasm/e2e/CurrentLedgerObjField.cpp | 2 +- .../libxrpl/tx/wasm/e2e/FloatToMantExp.cpp | 6 +- src/tests/libxrpl/tx/wasm/e2e/HostError.cpp | 2 +- .../libxrpl/tx/wasm/e2e/HostFunctionTour.cpp | 2 +- src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp | 2 +- src/tests/libxrpl/tx/wasm/e2e/SetData.cpp | 2 +- src/tests/libxrpl/tx/wasm/e2e/TxField.cpp | 4 +- .../libxrpl/tx/wasm/e2e/TxNestedField.cpp | 4 +- .../tx/wasm/{ => fixtures}/BenchFixtures.cpp | 34 ++++----- .../tx/wasm/{ => fixtures}/BenchFixtures.h | 5 +- .../FloatConstants.h} | 8 ++- .../libxrpl/tx/wasm/fixtures/FloatFixture.h | 15 ++++ .../{ => fixtures}/HostContextFixture.cpp | 2 +- .../wasm/{ => fixtures}/HostContextFixture.h | 2 +- .../wasm/{ => fixtures}/MockHostFunctions.h | 0 .../libxrpl/tx/wasm/fixtures/NFTFixture.h | 26 +++++++ .../{NFTFixture.cpp => fixtures/NftSetup.cpp} | 36 ++++++---- src/tests/libxrpl/tx/wasm/fixtures/NftSetup.h | 46 ++++++++++++ .../tx/wasm/fixtures/RealHostFixture.cpp | 16 +++++ .../tx/wasm/fixtures/RealHostFixture.h | 54 ++++++++++++++ .../tx/wasm/{ => fixtures}/RealVmTest.h | 4 +- .../tx/wasm/{ => fixtures}/WasmBench.cpp | 13 ++-- .../tx/wasm/{ => fixtures}/WasmBench.h | 21 +----- .../tx/wasm/{ => fixtures}/WasmFixture.h | 4 +- .../WasmLedger.cpp} | 72 ++++++++++--------- .../WasmLedger.h} | 48 +++++-------- .../tx/wasm/{ => fixtures}/WasmRun.cpp | 2 +- .../libxrpl/tx/wasm/{ => fixtures}/WasmRun.h | 0 .../wasm/host_calls/CurrentLedgerObjField.cpp | 2 +- .../libxrpl/tx/wasm/host_calls/LedgerSqn.cpp | 2 +- .../libxrpl/tx/wasm/host_calls/Sha512Half.cpp | 4 +- .../libxrpl/tx/wasm/host_calls/Trace.cpp | 2 +- .../tx/wasm/host_context/AccountKeylet.cpp | 2 +- .../tx/wasm/host_context/AmmKeylet.cpp | 2 +- .../libxrpl/tx/wasm/host_context/BaseFee.cpp | 2 +- .../tx/wasm/host_context/CacheLedgerObj.cpp | 2 +- .../tx/wasm/host_context/CheckKeylet.cpp | 2 +- .../tx/wasm/host_context/CheckSignature.cpp | 4 +- .../tx/wasm/host_context/CredentialKeylet.cpp | 2 +- .../host_context/CurrentLedgerObjArrayLen.cpp | 2 +- .../host_context/CurrentLedgerObjField.cpp | 2 +- .../CurrentLedgerObjNestedArrayLen.cpp | 2 +- .../CurrentLedgerObjNestedField.cpp | 2 +- .../tx/wasm/host_context/DelegateKeylet.cpp | 2 +- .../host_context/DepositPreauthKeylet.cpp | 2 +- .../tx/wasm/host_context/DidKeylet.cpp | 2 +- .../tx/wasm/host_context/EscrowKeylet.cpp | 2 +- .../libxrpl/tx/wasm/host_context/FloatAdd.cpp | 4 +- .../tx/wasm/host_context/FloatCompare.cpp | 4 +- .../tx/wasm/host_context/FloatDivide.cpp | 4 +- .../tx/wasm/host_context/FloatFromInt.cpp | 2 +- .../tx/wasm/host_context/FloatFromMantExp.cpp | 2 +- .../wasm/host_context/FloatFromSTAmount.cpp | 2 +- .../wasm/host_context/FloatFromSTNumber.cpp | 2 +- .../tx/wasm/host_context/FloatFromUint.cpp | 2 +- .../tx/wasm/host_context/FloatMultiply.cpp | 4 +- .../tx/wasm/host_context/FloatPower.cpp | 4 +- .../tx/wasm/host_context/FloatRoot.cpp | 4 +- .../tx/wasm/host_context/FloatSubtract.cpp | 4 +- .../tx/wasm/host_context/FloatToInt.cpp | 4 +- .../tx/wasm/host_context/FloatToMantExp.cpp | 4 +- .../wasm/host_context/IsAmendmentEnabled.cpp | 2 +- .../wasm/host_context/LedgerObjArrayLen.cpp | 2 +- .../tx/wasm/host_context/LedgerObjField.cpp | 2 +- .../host_context/LedgerObjNestedArrayLen.cpp | 2 +- .../host_context/LedgerObjNestedField.cpp | 2 +- .../tx/wasm/host_context/LedgerSqn.cpp | 2 +- .../host_context/MptokenIssuanceKeylet.cpp | 2 +- .../tx/wasm/host_context/MptokenKeylet.cpp | 2 +- .../libxrpl/tx/wasm/host_context/NFT.cpp | 2 +- .../libxrpl/tx/wasm/host_context/NFTFlags.cpp | 2 +- .../tx/wasm/host_context/NFTIssuer.cpp | 2 +- .../tx/wasm/host_context/NFTSequence.cpp | 2 +- .../libxrpl/tx/wasm/host_context/NFTTaxon.cpp | 2 +- .../tx/wasm/host_context/NFTTransferFee.cpp | 2 +- .../wasm/host_context/NftokenOfferKeylet.cpp | 2 +- .../tx/wasm/host_context/OfferKeylet.cpp | 2 +- .../tx/wasm/host_context/OracleKeylet.cpp | 2 +- .../tx/wasm/host_context/ParentLedgerHash.cpp | 2 +- .../tx/wasm/host_context/ParentLedgerTime.cpp | 2 +- .../tx/wasm/host_context/PaychannelKeylet.cpp | 2 +- .../host_context/PermissionedDomainKeylet.cpp | 2 +- .../tx/wasm/host_context/Sha512Half.cpp | 4 +- .../tx/wasm/host_context/SignerListKeylet.cpp | 2 +- .../tx/wasm/host_context/TicketKeylet.cpp | 2 +- .../libxrpl/tx/wasm/host_context/Trace.cpp | 2 +- .../tx/wasm/host_context/TrustLineKeylet.cpp | 2 +- .../tx/wasm/host_context/TxArrayLen.cpp | 2 +- .../libxrpl/tx/wasm/host_context/TxField.cpp | 2 +- .../tx/wasm/host_context/TxNestedArrayLen.cpp | 2 +- .../tx/wasm/host_context/TxNestedField.cpp | 2 +- .../tx/wasm/host_context/UpdateData.cpp | 4 +- .../tx/wasm/host_context/VaultKeylet.cpp | 2 +- .../host_functions/AccountKeylet.bench.cpp | 4 +- .../tx/wasm/host_functions/AccountKeylet.cpp | 2 +- .../wasm/host_functions/AmmKeylet.bench.cpp | 4 +- .../tx/wasm/host_functions/AmmKeylet.cpp | 2 +- .../tx/wasm/host_functions/BaseFee.bench.cpp | 4 +- .../tx/wasm/host_functions/BaseFee.cpp | 2 +- .../host_functions/CacheLedgerObj.bench.cpp | 4 +- .../tx/wasm/host_functions/CacheLedgerObj.cpp | 2 +- .../wasm/host_functions/CheckKeylet.bench.cpp | 4 +- .../tx/wasm/host_functions/CheckKeylet.cpp | 2 +- .../host_functions/CheckSignature.bench.cpp | 4 +- .../tx/wasm/host_functions/CheckSignature.cpp | 2 +- .../host_functions/CredentialKeylet.bench.cpp | 4 +- .../wasm/host_functions/CredentialKeylet.cpp | 2 +- .../CurrentLedgerObjArrayLen.bench.cpp | 4 +- .../CurrentLedgerObjArrayLen.cpp | 3 +- .../CurrentLedgerObjField.bench.cpp | 4 +- .../host_functions/CurrentLedgerObjField.cpp | 2 +- .../CurrentLedgerObjNestedArrayLen.bench.cpp | 4 +- .../CurrentLedgerObjNestedArrayLen.cpp | 3 +- .../CurrentLedgerObjNestedField.bench.cpp | 4 +- .../CurrentLedgerObjNestedField.cpp | 3 +- .../host_functions/DelegateKeylet.bench.cpp | 4 +- .../tx/wasm/host_functions/DelegateKeylet.cpp | 2 +- .../DepositPreauthKeylet.bench.cpp | 4 +- .../host_functions/DepositPreauthKeylet.cpp | 2 +- .../wasm/host_functions/DidKeylet.bench.cpp | 4 +- .../tx/wasm/host_functions/DidKeylet.cpp | 2 +- .../host_functions/EscrowKeylet.bench.cpp | 8 +-- .../tx/wasm/host_functions/EscrowKeylet.cpp | 2 +- .../tx/wasm/host_functions/FloatAdd.bench.cpp | 9 +-- .../tx/wasm/host_functions/FloatAdd.cpp | 4 +- .../host_functions/FloatCompare.bench.cpp | 4 +- .../tx/wasm/host_functions/FloatCompare.cpp | 4 +- .../wasm/host_functions/FloatDivide.bench.cpp | 4 +- .../tx/wasm/host_functions/FloatDivide.cpp | 4 +- .../host_functions/FloatFromInt.bench.cpp | 4 +- .../tx/wasm/host_functions/FloatFromInt.cpp | 4 +- .../host_functions/FloatFromMantExp.bench.cpp | 4 +- .../wasm/host_functions/FloatFromMantExp.cpp | 4 +- .../FloatFromStAmount.bench.cpp | 4 +- .../wasm/host_functions/FloatFromStAmount.cpp | 4 +- .../FloatFromStNumber.bench.cpp | 4 +- .../wasm/host_functions/FloatFromStNumber.cpp | 4 +- .../host_functions/FloatFromUint.bench.cpp | 4 +- .../tx/wasm/host_functions/FloatFromUint.cpp | 4 +- .../host_functions/FloatMultiply.bench.cpp | 4 +- .../tx/wasm/host_functions/FloatMultiply.cpp | 4 +- .../wasm/host_functions/FloatPower.bench.cpp | 8 +-- .../tx/wasm/host_functions/FloatPower.cpp | 4 +- .../wasm/host_functions/FloatRoot.bench.cpp | 4 +- .../tx/wasm/host_functions/FloatRoot.cpp | 4 +- .../host_functions/FloatSubtract.bench.cpp | 4 +- .../tx/wasm/host_functions/FloatSubtract.cpp | 4 +- .../wasm/host_functions/FloatToInt.bench.cpp | 4 +- .../tx/wasm/host_functions/FloatToInt.cpp | 4 +- .../host_functions/FloatToMantExp.bench.cpp | 8 +-- .../tx/wasm/host_functions/FloatToMantExp.cpp | 4 +- .../tx/wasm/host_functions/GetNFT.bench.cpp | 10 +-- .../libxrpl/tx/wasm/host_functions/GetNFT.cpp | 4 +- .../IsAmendmentEnabled.bench.cpp | 4 +- .../host_functions/IsAmendmentEnabled.cpp | 2 +- .../LedgerObjArrayLen.bench.cpp | 4 +- .../wasm/host_functions/LedgerObjArrayLen.cpp | 3 +- .../host_functions/LedgerObjField.bench.cpp | 4 +- .../tx/wasm/host_functions/LedgerObjField.cpp | 3 +- .../LedgerObjNestedArrayLen.bench.cpp | 4 +- .../LedgerObjNestedArrayLen.cpp | 3 +- .../LedgerObjNestedField.bench.cpp | 4 +- .../host_functions/LedgerObjNestedField.cpp | 3 +- .../wasm/host_functions/LedgerSqn.bench.cpp | 4 +- .../tx/wasm/host_functions/LedgerSqn.cpp | 2 +- .../MptokenIssuanceKeylet.bench.cpp | 4 +- .../host_functions/MptokenIssuanceKeylet.cpp | 2 +- .../host_functions/MptokenKeylet.bench.cpp | 4 +- .../tx/wasm/host_functions/MptokenKeylet.cpp | 2 +- .../tx/wasm/host_functions/NFTFlags.bench.cpp | 4 +- .../tx/wasm/host_functions/NFTFlags.cpp | 4 +- .../wasm/host_functions/NFTIssuer.bench.cpp | 4 +- .../tx/wasm/host_functions/NFTIssuer.cpp | 4 +- .../wasm/host_functions/NFTSequence.bench.cpp | 4 +- .../tx/wasm/host_functions/NFTSequence.cpp | 4 +- .../tx/wasm/host_functions/NFTTaxon.bench.cpp | 4 +- .../tx/wasm/host_functions/NFTTaxon.cpp | 4 +- .../host_functions/NFTTransferFee.bench.cpp | 4 +- .../tx/wasm/host_functions/NFTTransferFee.cpp | 4 +- .../NftokenOfferKeylet.bench.cpp | 4 +- .../host_functions/NftokenOfferKeylet.cpp | 2 +- .../wasm/host_functions/OfferKeylet.bench.cpp | 4 +- .../tx/wasm/host_functions/OfferKeylet.cpp | 2 +- .../host_functions/OracleKeylet.bench.cpp | 4 +- .../tx/wasm/host_functions/OracleKeylet.cpp | 2 +- .../host_functions/ParentLedgerHash.bench.cpp | 4 +- .../wasm/host_functions/ParentLedgerHash.cpp | 2 +- .../host_functions/ParentLedgerTime.bench.cpp | 4 +- .../wasm/host_functions/ParentLedgerTime.cpp | 2 +- .../host_functions/PaychannelKeylet.bench.cpp | 4 +- .../wasm/host_functions/PaychannelKeylet.cpp | 2 +- .../PermissionedDomainedKeylet.bench.cpp | 4 +- .../PermissionedDomainedKeylet.cpp | 2 +- .../wasm/host_functions/Sha512Half.bench.cpp | 4 +- .../tx/wasm/host_functions/Sha512Half.cpp | 2 +- .../host_functions/SignerListKeylet.bench.cpp | 4 +- .../wasm/host_functions/SignerListKeylet.cpp | 2 +- .../host_functions/TicketKeylet.bench.cpp | 4 +- .../tx/wasm/host_functions/TicketKeylet.cpp | 2 +- .../tx/wasm/host_functions/Trace.bench.cpp | 4 +- .../libxrpl/tx/wasm/host_functions/Trace.cpp | 2 +- .../host_functions/TrustLineKeylet.bench.cpp | 4 +- .../wasm/host_functions/TrustLineKeylet.cpp | 2 +- .../wasm/host_functions/TxArrayLen.bench.cpp | 4 +- .../tx/wasm/host_functions/TxArrayLen.cpp | 3 +- .../tx/wasm/host_functions/TxField.bench.cpp | 4 +- .../tx/wasm/host_functions/TxField.cpp | 3 +- .../host_functions/TxNestedArrayLen.bench.cpp | 4 +- .../wasm/host_functions/TxNestedArrayLen.cpp | 3 +- .../host_functions/TxNestedField.bench.cpp | 4 +- .../tx/wasm/host_functions/TxNestedField.cpp | 3 +- .../wasm/host_functions/UpdateData.bench.cpp | 4 +- .../tx/wasm/host_functions/UpdateData.cpp | 2 +- .../wasm/host_functions/VaultKeylet.bench.cpp | 4 +- .../tx/wasm/host_functions/VaultKeylet.cpp | 2 +- 224 files changed, 686 insertions(+), 542 deletions(-) delete mode 100644 src/tests/libxrpl/tx/wasm/NFTFixture.h rename src/tests/libxrpl/tx/wasm/{ => fixtures}/BenchFixtures.cpp (81%) rename src/tests/libxrpl/tx/wasm/{ => fixtures}/BenchFixtures.h (97%) rename src/tests/libxrpl/tx/wasm/{FloatFixture.h => fixtures/FloatConstants.h} (91%) create mode 100644 src/tests/libxrpl/tx/wasm/fixtures/FloatFixture.h rename src/tests/libxrpl/tx/wasm/{ => fixtures}/HostContextFixture.cpp (96%) rename src/tests/libxrpl/tx/wasm/{ => fixtures}/HostContextFixture.h (98%) rename src/tests/libxrpl/tx/wasm/{ => fixtures}/MockHostFunctions.h (100%) create mode 100644 src/tests/libxrpl/tx/wasm/fixtures/NFTFixture.h rename src/tests/libxrpl/tx/wasm/{NFTFixture.cpp => fixtures/NftSetup.cpp} (59%) create mode 100644 src/tests/libxrpl/tx/wasm/fixtures/NftSetup.h create mode 100644 src/tests/libxrpl/tx/wasm/fixtures/RealHostFixture.cpp create mode 100644 src/tests/libxrpl/tx/wasm/fixtures/RealHostFixture.h rename src/tests/libxrpl/tx/wasm/{ => fixtures}/RealVmTest.h (93%) rename src/tests/libxrpl/tx/wasm/{ => fixtures}/WasmBench.cpp (95%) rename src/tests/libxrpl/tx/wasm/{ => fixtures}/WasmBench.h (95%) rename src/tests/libxrpl/tx/wasm/{ => fixtures}/WasmFixture.h (97%) rename src/tests/libxrpl/tx/wasm/{RealHostFixture.cpp => fixtures/WasmLedger.cpp} (82%) rename src/tests/libxrpl/tx/wasm/{RealHostFixture.h => fixtures/WasmLedger.h} (79%) rename src/tests/libxrpl/tx/wasm/{ => fixtures}/WasmRun.cpp (96%) rename src/tests/libxrpl/tx/wasm/{ => fixtures}/WasmRun.h (100%) diff --git a/crates/xrpl-wasm-testkit/src/lib.rs b/crates/xrpl-wasm-testkit/src/lib.rs index 9dbbaad7da..58c109dd61 100644 --- a/crates/xrpl-wasm-testkit/src/lib.rs +++ b/crates/xrpl-wasm-testkit/src/lib.rs @@ -30,7 +30,7 @@ mod ffi { /// /// Throws `rust::Error` on an unknown name — a typo should fail loudly rather than /// quietly compare against zero. - fn declared_gas(wasm_name: &str) -> Result; + fn host_function_gas(wasm_name: &str) -> Result; } } @@ -38,7 +38,7 @@ fn compile_wat(wat: &str) -> Result, wat::Error> { wat::parse_str(wat) } -fn declared_gas(wasm_name: &str) -> Result { +fn host_function_gas(wasm_name: &str) -> Result { xrpl_host_functions::HostFunctionSpec::ALL .iter() .find(|op| op.wasm_name() == wasm_name) @@ -59,7 +59,7 @@ impl std::error::Error for UnknownHostFunction {} #[cfg(test)] mod tests { - use super::compile_wat; + use super::*; #[test] fn a_module_assembles_to_something_beginning_with_the_wasm_magic() { @@ -73,7 +73,7 @@ mod tests { // `trace` is the cheapest declaration in the table; the point is not the number but // that the lookup reaches the same constant the engine charges from. assert_eq!( - super::declared_gas("trace").expect("trace is a host function"), + host_function_gas("trace").expect("trace is a host function"), xrpl_host_functions::HostFunctionSpec::Trace.gas() ); } @@ -82,7 +82,7 @@ mod tests { fn every_host_function_is_reachable_by_its_import_name() { for op in xrpl_host_functions::HostFunctionSpec::ALL { assert_eq!( - super::declared_gas(op.wasm_name()).expect("declared"), + host_function_gas(op.wasm_name()).expect("declared"), op.gas(), "{} must be reachable by name", op.wasm_name() @@ -92,7 +92,7 @@ mod tests { #[test] fn an_unknown_name_is_an_error_rather_than_zero_gas() { - super::declared_gas("not_a_host_function").expect_err("must not resolve"); + host_function_gas("not_a_host_function").expect_err("must not resolve"); } #[test] diff --git a/src/benchmarks/libxrpl/CMakeLists.txt b/src/benchmarks/libxrpl/CMakeLists.txt index 2e701b56db..960f55c257 100644 --- a/src/benchmarks/libxrpl/CMakeLists.txt +++ b/src/benchmarks/libxrpl/CMakeLists.txt @@ -24,15 +24,13 @@ add_dependencies(xrpl.benchmarks xrpl.bench.nodestore) # xrpl.bench.wasm — gas calibration for the wasm host functions. # # Each `*.bench.cpp` sits beside the test that covers the same host function, under -# `src/tests/libxrpl/tx/wasm/`. Keeping the benchmark next to the test means the -# two move together and share one fixture; a separate executable means benchmark -# runtime never lands on the `ctest` path (the test binary filters `*.bench.cpp` -# back out). +# `src/tests/libxrpl/tx/wasm/`, so the two move together. A separate executable keeps +# benchmark runtime off the `ctest` path (the test binary filters `*.bench.cpp` out). # -# Reusing those fixtures means compiling a few test sources and linking GTest: -# `RealHostFixture` derives from `testing::Test`. Nothing here registers a test. -find_package(GTest QUIET) -if(TARGET GTest::gtest) +# The ledger and host come from `xrpl.testkit.wasm`, which links no test framework — so +# this target links **no GTest and no GMock**, and compiles no test sources of its own +# beyond the benchmark harness. +if(TARGET xrpl.testkit.wasm) file( GLOB_RECURSE wasm_bench_sources CONFIGURE_DEPENDS @@ -42,28 +40,20 @@ if(TARGET GTest::gtest) add_executable( xrpl.bench.wasm ${wasm_bench_sources} - "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/helpers/Account.cpp" - "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/helpers/TestSink.cpp" - "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/helpers/TxTest.cpp" - "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/RealHostFixture.cpp" - "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/NFTFixture.cpp" - # The benchmark harness and its shared ledger setup. Named without the - # `.bench.cpp` suffix because they are infrastructure rather than a benchmark, - # so the glob above does not find them and `xrpl_tests` excludes them by name. - "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/BenchFixtures.cpp" - "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/WasmBench.cpp" - # The WAT assembler, shared with the test binary rather than benchmark-only: - # both binaries compile their own copy. - "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/WasmRun.cpp" + # The benchmark harness. Named without the `.bench.cpp` suffix because it is + # infrastructure rather than a benchmark, so the glob above does not find it and + # `xrpl_tests` excludes it by name. + "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/fixtures/BenchFixtures.cpp" + "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.cpp" ) - # Google Benchmark registers cases through static registrars declared in - # anonymous namespaces; merging several such files into one unity translation - # unit collides them. Same reason as `xrpl_add_benchmark`. + # Google Benchmark registers cases through static registrars declared in anonymous + # namespaces; merging several such files into one unity translation unit collides + # them. Same reason as `xrpl_add_benchmark`. # # The output directory matches too: benchmarks land in the build root beside - # `xrpl_tests`, because they are run by hand and comparing two of them should - # not mean typing two long paths. + # `xrpl_tests`, because they are run by hand and comparing two of them should not + # mean typing two long paths. set_target_properties( xrpl.bench.wasm PROPERTIES @@ -71,26 +61,15 @@ if(TARGET GTest::gtest) RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ) - # The fixtures include their siblings as and , the - # same spelling the test binary gives them. - target_include_directories( - xrpl.bench.wasm - PRIVATE "${CMAKE_SOURCE_DIR}/src/tests/libxrpl" - ) target_link_libraries( xrpl.bench.wasm - PRIVATE - xrpl.imports.bench - GTest::gtest - GTest::gmock - xrpl_wasm_testkit_cxxbridge + PRIVATE xrpl.imports.bench xrpl.testkit.wasm ) - add_dependencies(xrpl.bench.wasm xrpl_crates) add_dependencies(xrpl.benchmarks xrpl.bench.wasm) else() message( STATUS - "GTest not found; skipping xrpl.bench.wasm (it reuses the test fixtures)." + "xrpl.testkit.wasm not built (tests disabled); skipping xrpl.bench.wasm." ) endif() diff --git a/src/tests/libxrpl/CMakeLists.txt b/src/tests/libxrpl/CMakeLists.txt index 34380240c6..ba71939209 100644 --- a/src/tests/libxrpl/CMakeLists.txt +++ b/src/tests/libxrpl/CMakeLists.txt @@ -5,15 +5,37 @@ include(verify_headers) # Test requirements. find_package(GTest REQUIRED) -# Single combined gtest binary built from the shared test helpers and all test -# modules below. -add_executable( - xrpl_tests - main.cpp +# The wasm fixtures the test binary and the wasm benchmarks both need: a real genesis +# ledger, the real host built over it, and the WAT assembler. Its own library because +# it links **no test framework** — a benchmark wants a ledger and a host, not GTest's +# lifecycle, and before this existed `xrpl.bench.wasm` had to link GTest and subclass +# `testing::Test` just to reach them. +# +# Only the framework-free half of `tx/wasm/fixtures/` lives here. The GTest half +# (`RealHostFixture`, `FloatFixture`, `NFTFixture`, `MockHostFunctions`, `WasmFixture`, +# `RealVmTest`, `HostContextFixture`) compiles into `xrpl_tests` with the tests, and the +# benchmark harness (`WasmBench`, `BenchFixtures`) into `xrpl.bench.wasm`. +add_library( + xrpl.testkit.wasm + STATIC helpers/Account.cpp helpers/TestSink.cpp helpers/TxTest.cpp + tx/wasm/fixtures/NftSetup.cpp + tx/wasm/fixtures/WasmLedger.cpp + tx/wasm/fixtures/WasmRun.cpp ) +# Fixtures include their siblings as and . +target_include_directories(xrpl.testkit.wasm PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries( + xrpl.testkit.wasm + PUBLIC xrpl.libxrpl xrpl_wasm_testkit_cxxbridge +) +add_dependencies(xrpl.testkit.wasm xrpl_crates) + +# Single combined gtest binary built from the shared test helpers and all test +# modules below. +add_executable(xrpl_tests main.cpp) patch_nix_binary(xrpl_tests) set_target_properties( xrpl_tests @@ -21,10 +43,10 @@ set_target_properties( ) # Lets test sources include the shared helpers as . target_include_directories(xrpl_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(xrpl_tests PRIVATE GTest::gtest GTest::gmock xrpl.libxrpl) - -target_link_libraries(xrpl_tests PRIVATE xrpl_wasm_testkit_cxxbridge) -add_dependencies(xrpl_tests xrpl_crates) +target_link_libraries( + xrpl_tests + PRIVATE GTest::gtest GTest::gmock xrpl.libxrpl xrpl.testkit.wasm +) # One source subdirectory per module. Network unit tests are currently not # supported on Windows. @@ -55,11 +77,17 @@ foreach(module IN LISTS test_modules) "${CMAKE_CURRENT_SOURCE_DIR}/${module}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/${module}.cpp" ) - # Remove Benchmark tests from this target. + # Sources under this tree that belong to another target: + # * `*.bench.cpp` and the `WasmBench`/`BenchFixtures` harness -> xrpl.bench.wasm + # * `NftSetup`/`WasmLedger`/`WasmRun` -> xrpl.testkit.wasm, which this binary links + # + # The GTest half of `tx/wasm/fixtures/` (RealHostFixture, HostContextFixture) is not + # excluded: it shares the tests' framework and belongs here. list( FILTER sources EXCLUDE - REGEX "\\.bench\\.cpp$|/(WasmBench|BenchFixtures)\\.cpp$" + REGEX + "\\.bench\\.cpp$|/fixtures/(WasmBench|BenchFixtures|NftSetup|WasmLedger|WasmRun)\\.cpp$" ) target_sources(xrpl_tests PRIVATE ${sources}) diff --git a/src/tests/libxrpl/tx/wasm/Crossing.bench.cpp b/src/tests/libxrpl/tx/wasm/Crossing.bench.cpp index 29bb50af6a..04a93817f8 100644 --- a/src/tests/libxrpl/tx/wasm/Crossing.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/Crossing.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/NFTFixture.h b/src/tests/libxrpl/tx/wasm/NFTFixture.h deleted file mode 100644 index 559787ada4..0000000000 --- a/src/tests/libxrpl/tx/wasm/NFTFixture.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include - -#include -#include -#include - -namespace xrpl::test { - -struct NFTTest : RealHostFixture -{ - static constexpr std::uint16_t kFlags = nft::kFlagTransferable | nft::kFlagBurnable; - static constexpr std::uint16_t kFee = 314; - static constexpr std::uint32_t kTaxon = 12345; - static constexpr std::uint32_t kSequence = 7; - - static uint256 - makeNftId(AccountID const& issuer); - - // Mint a real NFToken owned by `issuer` (taxon 0) and return its id, read back from the - // owner's NFTokenPage. TxTest applies to the open ledger, which produces no metadata, so - // the id is recovered from ledger state rather than from the mint's metadata. - uint256 - mintNFT(Account const& issuer, std::optional uri = std::nullopt); -}; - -} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/Preflight.cpp b/src/tests/libxrpl/tx/wasm/Preflight.cpp index e5fb9eddcc..3e995d0cbf 100644 --- a/src/tests/libxrpl/tx/wasm/Preflight.cpp +++ b/src/tests/libxrpl/tx/wasm/Preflight.cpp @@ -6,8 +6,8 @@ #include #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/README.md b/src/tests/libxrpl/tx/wasm/README.md index 7eb89488a4..1add9daad0 100644 --- a/src/tests/libxrpl/tx/wasm/README.md +++ b/src/tests/libxrpl/tx/wasm/README.md @@ -15,8 +15,27 @@ the breadth it might seem to be missing lives in a sibling layer. This file is t | `e2e/` (`RealVmTest`) | `.../e2e` | real | ✓ | real | **full-stack integration** — VM + `HostContext` + real impl + real ledger, driven by a WAT contract | `MockVmTest` / `RealVmTest` are the mock-host and real-host counterparts of the same VM harness; -both forward to the shared `runWat(HostFunctions&, ...)` in `WasmRun.h`, differing only in the -host they inject. +both forward to the shared `runWat(HostFunctions&, ...)` in `fixtures/WasmRun.h`, differing only +in the host they inject. + +## `fixtures/` — and why it is split in two + +Everything shared sits in `fixtures/`, divided by whether it needs a test framework: + +| | | +| ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **No GTest** — the `xrpl.testkit.wasm` library | `WasmLedger` (a real genesis ledger + the real host over it), `WasmRun` (the WAT assembler), `NftSetup`, `FloatConstants` | +| **GTest** — compiled into `xrpl_tests` | `RealHostFixture` (`: testing::Test, WasmLedger` plus `expectValue`/`expectError`/`expectKeyletMatches`), `FloatFixture`, `NFTFixture`, `MockHostFunctions`, `WasmFixture`, `RealVmTest`, `HostContextFixture` | +| **Benchmark harness** — compiled into `xrpl.bench.wasm` | `WasmBench`, `BenchFixtures` | + +The split exists because **a benchmark wants a ledger and a host, not GTest's lifecycle.** Both +binaries link the library; `xrpl.bench.wasm` links no GTest and no GMock at all. + +One consequence worth knowing: setup steps in `WasmLedger` and `NftSetup` **throw** (via +`fixtureFailed`) rather than using `EXPECT_`. That is not stylistic. An `EXPECT_` outside a +running test is recorded and discarded, so a benchmark whose escrow was never created would still +run its host call, take the not-found path, and report a cheap, plausible, completely wrong price. +Throwing turns that into a stopped run. If you add a setup step that can fail, throw. ## `*.bench.cpp` — gas calibration @@ -28,11 +47,12 @@ actually costs. **One `.bench.cpp` per host function, named after its test** — `EscrowKeylet.cpp` and `EscrowKeylet.bench.cpp` sit next to each other, 61 of each. That is a checklist rather than a judgment call: adding a host function means adding two files, and nobody has to decide where a -benchmark belongs. Shared ledger setup lives in the `Fixtures` type (`BenchFixtures.h`) — one +benchmark belongs. Shared ledger setup lives in the `Fixtures` type (`fixtures/BenchFixtures.h`) — one ledger, funded once, for the whole binary — so each file holds only the call it measures. -They build into a **separate executable** (`xrpl.bench.wasm`), and `xrpl_tests` filters -`*.bench.cpp` out of its source globs, so benchmark runtime never lands on the `ctest` path. +They build into a **separate executable** (`xrpl.bench.wasm`) that links `xrpl.testkit.wasm` and +no test framework, and `xrpl_tests` filters `*.bench.cpp` out of its source globs, so benchmark +runtime never lands on the `ctest` path. ### Running them diff --git a/src/tests/libxrpl/tx/wasm/WasmVM.cpp b/src/tests/libxrpl/tx/wasm/WasmVM.cpp index 4e212e2f3f..5a762823ca 100644 --- a/src/tests/libxrpl/tx/wasm/WasmVM.cpp +++ b/src/tests/libxrpl/tx/wasm/WasmVM.cpp @@ -6,8 +6,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp b/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp index 0fbcfd81df..80635fee76 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp @@ -3,9 +3,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp b/src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp index 0f4d0392d8..839aaedd1d 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp b/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp index 454eaed7c0..a70fdb07ce 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp @@ -1,9 +1,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp b/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp index 2404fdd25a..3b7203b415 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp b/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp index d998b8a826..ed3570aab5 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp b/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp index b0a565d030..824cd19f45 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp b/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp index 2989eadb26..130c812dc8 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp b/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp index 406c736d6c..54c66c1e9e 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp @@ -5,8 +5,8 @@ #include #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp b/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp index bce5a4060a..224e3bb525 100644 --- a/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp @@ -7,8 +7,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/BenchFixtures.cpp b/src/tests/libxrpl/tx/wasm/fixtures/BenchFixtures.cpp similarity index 81% rename from src/tests/libxrpl/tx/wasm/BenchFixtures.cpp rename to src/tests/libxrpl/tx/wasm/fixtures/BenchFixtures.cpp index aa84a57d5b..9a6b2de4db 100644 --- a/src/tests/libxrpl/tx/wasm/BenchFixtures.cpp +++ b/src/tests/libxrpl/tx/wasm/fixtures/BenchFixtures.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -15,25 +15,15 @@ #include #include -#include -#include -#include +#include +#include +#include -#include #include #include #include namespace xrpl::test::bench { -namespace { - -[[noreturn]] void -setupFailed(std::string_view what) -{ - throw std::runtime_error{"benchmark fixture setup failed: " + std::string{what}}; -} - -} // namespace Fixtures::Fixtures() : alice_{ledger_.fund("benchAlice")} @@ -41,7 +31,7 @@ Fixtures::Fixtures() , signerListOwner_{ledger_.fund("benchSigners")} , escrow_{keylet::account(AccountID{})} , signedMessage_{signMessage("the quick brown fox jumps over the lazy dog")} - , nftId_{NFTTest::makeNftId(alice_.id())} + , nftId_{NftIds::makeNftId(alice_.id())} { ledger_.makeSignerList(signerListOwner_, 2, {{alice_, 1}, {bob_, 1}}); @@ -55,7 +45,7 @@ Fixtures::Fixtures() alice_); if (created.ter != tesSUCCESS) { - setupFailed(std::string{"creating the escrow: "} + transToken(created.ter)); + fixtureFailed(std::string{"creating the escrow: "} + transToken(created.ter)); } ledger_.ledger.close(); escrow_ = keylet::escrow(alice_.id(), SeqProxy::rawSequence(ownerSeq)); @@ -80,8 +70,8 @@ Fixtures::memoTx() assembler.build = [inner = std::move(assembler.build)](STObject& obj) { inner(obj); auto memos = STArray{}; - memos.push_back(makeMemo(RealHostFixture::toBytes("hello"))); - memos.push_back(makeMemo(RealHostFixture::toBytes("world"))); + memos.push_back(makeMemo(WasmLedger::toBytes("hello"))); + memos.push_back(makeMemo(WasmLedger::toBytes("world"))); obj.setFieldArray(sfMemos, memos); }; return assembler; @@ -107,7 +97,7 @@ Fixtures::cachedHost() auto wasmHost = host(); if (!wasmHost->cacheLedgerObj(keylet::account(alice_.id()).key, 1).has_value()) { - setupFailed("caching the account root into slot 1"); + fixtureFailed("caching the account root into slot 1"); } return wasmHost; } @@ -128,7 +118,7 @@ Fixtures::cachedSignerListHost() ledger_.makeHost(keylet::account(AccountID{}), assembler.type, std::move(assembler.build)); if (!wasmHost->cacheLedgerObj(keylet::signerList(signerListOwner_.id()).key, 1).has_value()) { - setupFailed("caching the signer list into slot 1"); + fixtureFailed("caching the signer list into slot 1"); } return wasmHost; } @@ -154,13 +144,13 @@ Fixtures::escrowHost() Slice Fixtures::floatX() { - return FloatTest::slice(FloatTest::kPi); + return FloatConstants::slice(FloatConstants::kPi); } Slice Fixtures::floatY() { - return FloatTest::slice(FloatTest::kTwo); + return FloatConstants::slice(FloatConstants::kTwo); } SignedMessage const& diff --git a/src/tests/libxrpl/tx/wasm/BenchFixtures.h b/src/tests/libxrpl/tx/wasm/fixtures/BenchFixtures.h similarity index 97% rename from src/tests/libxrpl/tx/wasm/BenchFixtures.h rename to src/tests/libxrpl/tx/wasm/fixtures/BenchFixtures.h index ea0b49261a..8693a13dfd 100644 --- a/src/tests/libxrpl/tx/wasm/BenchFixtures.h +++ b/src/tests/libxrpl/tx/wasm/fixtures/BenchFixtures.h @@ -6,8 +6,7 @@ #include #include -#include -#include +#include #include @@ -100,7 +99,7 @@ private: [[nodiscard]] TxAssembler memoTx(); - BenchFixture ledger_; + WasmLedger ledger_; Account alice_; Account bob_; Account signerListOwner_; diff --git a/src/tests/libxrpl/tx/wasm/FloatFixture.h b/src/tests/libxrpl/tx/wasm/fixtures/FloatConstants.h similarity index 91% rename from src/tests/libxrpl/tx/wasm/FloatFixture.h rename to src/tests/libxrpl/tx/wasm/fixtures/FloatConstants.h index d643f7f39a..fe7be63c8d 100644 --- a/src/tests/libxrpl/tx/wasm/FloatFixture.h +++ b/src/tests/libxrpl/tx/wasm/fixtures/FloatConstants.h @@ -3,15 +3,17 @@ #include #include -#include - #include #include #include +// Canonical float encodings, with no ledger and no test framework behind them — just the byte +// patterns the float host functions take and return. Benchmarks include this directly; +// `FloatFixture.h` mixes it into the GTest fixture the `host_functions/` tests use. + namespace xrpl::test { -struct FloatTest : RealHostFixture +struct FloatConstants { static constexpr std::int64_t kMin64 = std::numeric_limits::min(); static constexpr std::int64_t kMax64 = std::numeric_limits::max(); diff --git a/src/tests/libxrpl/tx/wasm/fixtures/FloatFixture.h b/src/tests/libxrpl/tx/wasm/fixtures/FloatFixture.h new file mode 100644 index 0000000000..926a6f5943 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/fixtures/FloatFixture.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +// The float constants with a real ledger and GTest attached, for the `host_functions/Float*` +// tests. The constants alone are in FloatConstants.h, which links no test framework. + +namespace xrpl::test { + +struct FloatTest : RealHostFixture, FloatConstants +{ +}; + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/HostContextFixture.cpp b/src/tests/libxrpl/tx/wasm/fixtures/HostContextFixture.cpp similarity index 96% rename from src/tests/libxrpl/tx/wasm/HostContextFixture.cpp rename to src/tests/libxrpl/tx/wasm/fixtures/HostContextFixture.cpp index cf5efc0453..fd0fd5d4bc 100644 --- a/src/tests/libxrpl/tx/wasm/HostContextFixture.cpp +++ b/src/tests/libxrpl/tx/wasm/fixtures/HostContextFixture.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/HostContextFixture.h b/src/tests/libxrpl/tx/wasm/fixtures/HostContextFixture.h similarity index 98% rename from src/tests/libxrpl/tx/wasm/HostContextFixture.h rename to src/tests/libxrpl/tx/wasm/fixtures/HostContextFixture.h index 1677014b8a..3789b3b7fa 100644 --- a/src/tests/libxrpl/tx/wasm/HostContextFixture.h +++ b/src/tests/libxrpl/tx/wasm/fixtures/HostContextFixture.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/MockHostFunctions.h b/src/tests/libxrpl/tx/wasm/fixtures/MockHostFunctions.h similarity index 100% rename from src/tests/libxrpl/tx/wasm/MockHostFunctions.h rename to src/tests/libxrpl/tx/wasm/fixtures/MockHostFunctions.h diff --git a/src/tests/libxrpl/tx/wasm/fixtures/NFTFixture.h b/src/tests/libxrpl/tx/wasm/fixtures/NFTFixture.h new file mode 100644 index 0000000000..9a163b2ca0 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/fixtures/NFTFixture.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include +#include +#include + +#include +#include + +// The NFToken helpers with a real ledger and GTest attached, for the `host_functions/NFT*` tests. +// The ledger-only versions are in NftSetup.h, which links no test framework. + +namespace xrpl::test { + +struct NFTTest : RealHostFixture, NftIds +{ + uint256 + mintNFT(Account const& issuer, std::optional uri = std::nullopt) + { + return mintNft(*this, issuer, uri); + } +}; + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/NFTFixture.cpp b/src/tests/libxrpl/tx/wasm/fixtures/NftSetup.cpp similarity index 59% rename from src/tests/libxrpl/tx/wasm/NFTFixture.cpp rename to src/tests/libxrpl/tx/wasm/fixtures/NftSetup.cpp index 0bf1ea023c..bdaf29c8f9 100644 --- a/src/tests/libxrpl/tx/wasm/NFTFixture.cpp +++ b/src/tests/libxrpl/tx/wasm/fixtures/NftSetup.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -10,28 +10,33 @@ #include // IWYU pragma: keep #include -#include #include +#include #include +#include #include namespace xrpl::test { uint256 -NFTTest::makeNftId(AccountID const& issuer) +NftIds::makeNftId(AccountID const& issuer) { return NFTokenMint::createNFTokenID(kFlags, kFee, issuer, nft::toTaxon(kTaxon), kSequence); } uint256 -NFTTest::mintNFT(Account const& issuer, std::optional uri) +mintNft(WasmLedger& fixture, Account const& issuer, std::optional uri) { + auto& ledger = fixture.ledger; auto builder = transactions::NFTokenMintBuilder{issuer.id(), 0u}; if (uri) builder.setURI(Slice{uri->data(), uri->size()}); auto const r = ledger.submit(builder, issuer); - EXPECT_EQ(r.ter, tesSUCCESS) << transToken(r.ter); + if (r.ter != tesSUCCESS) + { + fixtureFailed(std::string{"minting the NFToken: "} + transToken(r.ter)); + } ledger.close(); // The single minted token lives in the owner's first NFTokenPage. @@ -39,14 +44,21 @@ NFTTest::mintNFT(Account const& issuer, std::optional uri) auto const first = keylet::nftokenPageMin(issuer.id()).key; auto const last = keylet::nftokenPageMax(issuer.id()).key; auto const pageKey = view.succ(first, last.next()); - EXPECT_TRUE(pageKey.has_value()); - auto const page = pageKey ? view.read(Keylet{ltNFTOKEN_PAGE, *pageKey}) : nullptr; - EXPECT_NE(page, nullptr); - if (!page) - return uint256{}; + if (!pageKey.has_value()) + { + fixtureFailed("finding the minted token's NFTokenPage"); + } + auto const page = view.read(Keylet{ltNFTOKEN_PAGE, *pageKey}); + if (page == nullptr) + { + fixtureFailed("reading the minted token's NFTokenPage"); + } auto const& tokens = page->getFieldArray(sfNFTokens); - EXPECT_FALSE(tokens.empty()); - return tokens.empty() ? uint256{} : tokens[0].getFieldH256(sfNFTokenID); + if (tokens.empty()) + { + fixtureFailed("the NFTokenPage holds no tokens"); + } + return tokens[0].getFieldH256(sfNFTokenID); } } // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/fixtures/NftSetup.h b/src/tests/libxrpl/tx/wasm/fixtures/NftSetup.h new file mode 100644 index 0000000000..93e3f798f1 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/fixtures/NftSetup.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include +#include +#include + +// NFToken setup, built on `WasmLedger` rather than on a GTest fixture so a benchmark can mint a +// token without linking a test framework. Tests reach the same helpers through +// `RealHostFixture`, which derives from `WasmLedger`. + +namespace xrpl::test { + +// The fields baked into `makeNftId`, so a caller can assert an extractor returned the right one. +struct NftIds +{ + static constexpr std::uint16_t kFlags = nft::kFlagTransferable | nft::kFlagBurnable; + static constexpr std::uint16_t kFee = 314; + static constexpr std::uint32_t kTaxon = 12345; + static constexpr std::uint32_t kSequence = 7; + + // A well-formed id carrying the constants above. Computed, not minted: the id-extractor host + // functions read the id itself and never touch the ledger. + static uint256 + makeNftId(AccountID const& issuer); +}; + +// Mint a real NFToken owned by `issuer` (taxon 0) and return its id, read back from the owner's +// NFTokenPage. `TxTest` applies to the open ledger, which produces no metadata, so the id comes +// from ledger state rather than from the mint's metadata. +// +// Throws via `fixtureFailed` if the mint or the page lookup fails; see WasmLedger.h for why that +// is a throw and not an `EXPECT_`. +uint256 +mintNft( + WasmLedger& fixture, + Account const& issuer, + std::optional uri = std::nullopt); + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/fixtures/RealHostFixture.cpp b/src/tests/libxrpl/tx/wasm/fixtures/RealHostFixture.cpp new file mode 100644 index 0000000000..6380f301f6 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/fixtures/RealHostFixture.cpp @@ -0,0 +1,16 @@ +#include + +#include +#include + +#include + +namespace xrpl::test { + +void +expectKeyletMatches(std::expected const& result, Keylet const& expected) +{ + expectValue(result, RealHostFixture::toBytes(expected.key)); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/fixtures/RealHostFixture.h b/src/tests/libxrpl/tx/wasm/fixtures/RealHostFixture.h new file mode 100644 index 0000000000..f9bdb6b049 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/fixtures/RealHostFixture.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include + +#include +#include + +#include +#include + +// The GTest layer over `WasmLedger`: the assertion helpers, and the fixture base the +// `host_functions/` tests derive from. +// +// Everything that touches a ledger or builds a host lives in `WasmLedger.h`, which knows nothing +// about GTest so the benchmarks can share it. Only what genuinely needs the framework is here. + +namespace xrpl::test { + +template +void +expectValue( + std::expected const& result, + U const& expected, + std::source_location loc = std::source_location::current()) +{ + auto trace = testing::ScopedTrace{loc.file_name(), static_cast(loc.line()), ""}; + ASSERT_TRUE(result.has_value()) + << "expected a value, got error " << static_cast(result.error()); + EXPECT_EQ(*result, expected); +} + +template +void +expectError( + std::expected const& result, + HostFunctionError expected, + std::source_location loc = std::source_location::current()) +{ + auto trace = testing::ScopedTrace{loc.file_name(), static_cast(loc.line()), ""}; + ASSERT_FALSE(result.has_value()) << "expected error, got a value"; + EXPECT_EQ(result.error(), expected); +} + +void +expectKeyletMatches(std::expected const& result, Keylet const& expected); + +// A `WasmLedger` with GTest's lifecycle attached. Tests derive from this; benchmarks use +// `WasmLedger` directly. +struct RealHostFixture : testing::Test, WasmLedger +{ +}; + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/RealVmTest.h b/src/tests/libxrpl/tx/wasm/fixtures/RealVmTest.h similarity index 93% rename from src/tests/libxrpl/tx/wasm/RealVmTest.h rename to src/tests/libxrpl/tx/wasm/fixtures/RealVmTest.h index a5c05293e4..a2bed7bc4d 100644 --- a/src/tests/libxrpl/tx/wasm/RealVmTest.h +++ b/src/tests/libxrpl/tx/wasm/fixtures/RealVmTest.h @@ -7,8 +7,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/WasmBench.cpp b/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.cpp similarity index 95% rename from src/tests/libxrpl/tx/wasm/WasmBench.cpp rename to src/tests/libxrpl/tx/wasm/fixtures/WasmBench.cpp index 397ef65f00..9cdc921285 100644 --- a/src/tests/libxrpl/tx/wasm/WasmBench.cpp +++ b/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #include #include @@ -102,7 +103,7 @@ measureSecondsPerGas() auto const busy = assembleWat(makeLoopWat("", "", kBody, kCallsPerRun)); auto const idle = assembleWat(makeLoopWat("", "", kBody, 0)); - auto fixture = BenchFixture{}; + auto fixture = WasmLedger{}; // Warm the instruction cache and the allocator before the pairs that count, so the first-run // penalty does not land on one side of the subtraction. @@ -147,7 +148,7 @@ measureCrossingFloorGas(double secondsPerGas) auto const loaded = assembleWat(makeLoopWat(kImport, "", kBody, kCallsPerRun)); auto const baseline = assembleWat(makeLoopWat(kImport, "", kBody, 0)); - auto fixture = BenchFixture{}; + auto fixture = WasmLedger{}; auto vmTotal = 0.0; for (auto i = 0; i < kBenchIterations; ++i) @@ -199,7 +200,7 @@ double declaredGas(std::string_view wasmName) { return static_cast( - rs::wasm_testkit::declared_gas(rust::Str{wasmName.data(), wasmName.size()})); + rs::wasm_testkit::host_function_gas(rust::Str{wasmName.data(), wasmName.size()})); } void @@ -223,7 +224,7 @@ report( return; auto const declared = declaredGas(wasmName); - state.counters["declared_gas"] = declared; + state.counters["host_function_gas"] = declared; state.counters["suggested_gas"] = suggested; // Above 1: the table charges more than the work costs. Below 1: underpriced, which is the // direction that matters — an underpriced call is one a contract can buy too cheaply. diff --git a/src/tests/libxrpl/tx/wasm/WasmBench.h b/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.h similarity index 95% rename from src/tests/libxrpl/tx/wasm/WasmBench.h rename to src/tests/libxrpl/tx/wasm/fixtures/WasmBench.h index 6da4071c0e..5063d61f23 100644 --- a/src/tests/libxrpl/tx/wasm/WasmBench.h +++ b/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.h @@ -5,8 +5,7 @@ #include #include -#include -#include +#include #include #include @@ -59,20 +58,6 @@ inline constexpr std::int64_t kTransferLimitBytes = 1 << 20; int callsWithinTransferBudget(std::int64_t bytesPerCall); -// A benchmark wants a fixture's ledger, host and setup helpers. -// Templated so a case can reuse whichever fixture its test uses — `Bench` for the -// NFT benchmarks, `Bench` for the float ones — instead of duplicating that setup. -template -struct Bench : Fixture -{ - void - TestBody() override - { - } -}; - -using BenchFixture = Bench; - // One run of a contract: how long it took, and what the engine charged it. struct Timing { @@ -107,8 +92,6 @@ public: static Calibration const& instance(); - Calibration(); - // Seconds of wall time one unit of gas buys here. [[nodiscard]] double secondsPerGas() const @@ -125,6 +108,8 @@ public: } private: + Calibration(); + double secondsPerGas_{}; double crossingFloorGas_{}; }; diff --git a/src/tests/libxrpl/tx/wasm/WasmFixture.h b/src/tests/libxrpl/tx/wasm/fixtures/WasmFixture.h similarity index 97% rename from src/tests/libxrpl/tx/wasm/WasmFixture.h rename to src/tests/libxrpl/tx/wasm/fixtures/WasmFixture.h index 5bf00b27b9..28099f0a97 100644 --- a/src/tests/libxrpl/tx/wasm/WasmFixture.h +++ b/src/tests/libxrpl/tx/wasm/fixtures/WasmFixture.h @@ -8,8 +8,8 @@ #include #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/RealHostFixture.cpp b/src/tests/libxrpl/tx/wasm/fixtures/WasmLedger.cpp similarity index 82% rename from src/tests/libxrpl/tx/wasm/RealHostFixture.cpp rename to src/tests/libxrpl/tx/wasm/fixtures/WasmLedger.cpp index 4e97566845..887bf4fbab 100644 --- a/src/tests/libxrpl/tx/wasm/RealHostFixture.cpp +++ b/src/tests/libxrpl/tx/wasm/fixtures/WasmLedger.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -24,36 +24,42 @@ #include #include -#include #include #include #include -#include #include #include #include #include +#include +#include #include #include #include namespace xrpl::test { +void +fixtureFailed(std::string_view what) +{ + throw std::runtime_error("test fixture setup failed: " + std::string{what}); +} + Bytes -RealHostFixture::toBytes(std::uint8_t value) +WasmLedger::toBytes(std::uint8_t value) { return {value}; } Bytes -RealHostFixture::toBytes(std::uint16_t value) +WasmLedger::toBytes(std::uint16_t value) { return {static_cast(value), static_cast(value >> 8)}; } Bytes -RealHostFixture::toBytes(std::uint32_t value) +WasmLedger::toBytes(std::uint32_t value) { return { static_cast(value), @@ -63,31 +69,31 @@ RealHostFixture::toBytes(std::uint32_t value) } Bytes -RealHostFixture::toBytes(uint256 const& value) +WasmLedger::toBytes(uint256 const& value) { return Bytes{std::begin(value), std::end(value)}; } Bytes -RealHostFixture::toBytes(std::string_view value) +WasmLedger::toBytes(std::string_view value) { return Bytes{std::begin(value), std::end(value)}; } Bytes -RealHostFixture::toBytes(std::span value) +WasmLedger::toBytes(std::span value) { return Bytes{std::begin(value), std::end(value)}; } Bytes -RealHostFixture::toBytes(AccountID const& account) +WasmLedger::toBytes(AccountID const& account) { return Bytes{std::begin(account), std::end(account)}; } Bytes -RealHostFixture::toBytes(Issue const& issue) +WasmLedger::toBytes(Issue const& issue) { auto s = Serializer{}; s.addBitString(issue.currency); @@ -97,7 +103,7 @@ RealHostFixture::toBytes(Issue const& issue) } Bytes -RealHostFixture::toBytes(Asset const& asset) +WasmLedger::toBytes(Asset const& asset) { if (asset.holds()) return toBytes(asset.get()); @@ -108,7 +114,7 @@ RealHostFixture::toBytes(Asset const& asset) } Bytes -RealHostFixture::toBytes(STAmount const& amount) +WasmLedger::toBytes(STAmount const& amount) { auto msg = Serializer{}; amount.add(msg); @@ -116,19 +122,13 @@ RealHostFixture::toBytes(STAmount const& amount) } Bytes -RealHostFixture::toBytes(STNumber const& number) +WasmLedger::toBytes(STNumber const& number) { auto msg = Serializer{}; number.add(msg); return msg.getData(); } -void -expectKeyletMatches(std::expected const& result, Keylet const& expected) -{ - expectValue(result, RealHostFixture::toBytes(expected.key)); -} - SignedMessage signMessage(std::string_view message, KeyType keyType) { @@ -145,7 +145,10 @@ uint256 credentialId(std::string_view hex) { auto id = uint256{}; - EXPECT_TRUE(id.parseHex(std::string{hex})); + if (!id.parseHex(std::string{hex})) + { + fixtureFailed("parsing the credential id hex"); + } return id; } @@ -168,8 +171,11 @@ escrowFinishTx(TxTest& ledger, Account const& acct) { return {.type = ttESCROW_FINISH, .build = [&ledger, acct](STObject& obj) { auto credId = uint256{}; - EXPECT_TRUE(credId.parseHex( - "0011223344556677889900112233445566778899001122334455667788990011")); + if (!credId.parseHex( + "0011223344556677889900112233445566778899001122334455667788990011")) + { + fixtureFailed("parsing the credential id hex"); + } obj.setAccountID(sfAccount, acct.id()); obj.setAccountID(sfOwner, acct.id()); @@ -221,7 +227,7 @@ WasmHost::operator*() const } Account -RealHostFixture::fund(char const* name, XRPAmount amount) +WasmLedger::fund(char const* name, XRPAmount amount) { auto const account = Account{name}; ledger.createAccount(account, amount); @@ -229,7 +235,7 @@ RealHostFixture::fund(char const* name, XRPAmount amount) } WasmHost -RealHostFixture::makeHost( +WasmLedger::makeHost( beast::Journal journal, Keylet const& leKey, TxType txType, @@ -250,17 +256,14 @@ RealHostFixture::makeHost( } WasmHost -RealHostFixture::makeHost( - Keylet const& leKey, - TxType txType, - std::function assembler) +WasmLedger::makeHost(Keylet const& leKey, TxType txType, std::function assembler) { return makeHost( beast::Journal{beast::Journal::getNullSink()}, leKey, txType, std::move(assembler)); } WasmHost -RealHostFixture::makeTracingHost( +WasmLedger::makeTracingHost( Keylet const& leKey, TxType txType, std::function assembler) @@ -269,13 +272,13 @@ RealHostFixture::makeTracingHost( } std::string -RealHostFixture::logged() const +WasmLedger::logged() const { return traceSink_.messages(); } void -RealHostFixture::makeSignerList( +WasmLedger::makeSignerList( Account const& owner, std::uint32_t quorum, std::vector> const& signers) @@ -290,7 +293,10 @@ RealHostFixture::makeSignerList( } auto const r = ledger.submit( transactions::SignerListSetBuilder{owner.id(), quorum}.setSignerEntries(entries), owner); - EXPECT_EQ(r.ter, tesSUCCESS) << transToken(r.ter); + if (r.ter != tesSUCCESS) + { + fixtureFailed(std::string{"submitting the signer list: "} + transToken(r.ter)); + } ledger.close(); } diff --git a/src/tests/libxrpl/tx/wasm/RealHostFixture.h b/src/tests/libxrpl/tx/wasm/fixtures/WasmLedger.h similarity index 79% rename from src/tests/libxrpl/tx/wasm/RealHostFixture.h rename to src/tests/libxrpl/tx/wasm/fixtures/WasmLedger.h index 9e149c1f3b..abe6aa8e26 100644 --- a/src/tests/libxrpl/tx/wasm/RealHostFixture.h +++ b/src/tests/libxrpl/tx/wasm/fixtures/WasmLedger.h @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -19,51 +18,36 @@ #include #include -#include #include #include #include #include -#include #include #include -#include #include #include #include #include #include +// A real genesis ledger and the real host built over it, with **no test framework**. +// +// This is the piece both `xrpl_tests` and `xrpl.bench.wasm` need, and the reason it is its own +// type: a benchmark wants a ledger and a host, not GTest's lifecycle. `RealHostFixture` adds the +// framework on top (`: testing::Test, WasmLedger`) plus the assertion helpers; a benchmark uses +// `WasmLedger` directly and links no GTest at all. +// +// Setup steps here **throw** rather than `EXPECT_`. That is the point of the separation, not a +// detail: an `EXPECT_` outside a running test is recorded and discarded, so a benchmark whose +// escrow was never created would still run its host call, take the not-found path, and report a +// cheap, plausible, completely wrong price. Throwing turns that into a stopped run. + namespace xrpl::test { -template -void -expectValue( - std::expected const& result, - U const& expected, - std::source_location loc = std::source_location::current()) -{ - auto trace = testing::ScopedTrace{loc.file_name(), static_cast(loc.line()), ""}; - ASSERT_TRUE(result.has_value()) - << "expected a value, got error " << static_cast(result.error()); - EXPECT_EQ(*result, expected); -} - -template -void -expectError( - std::expected const& result, - HostFunctionError expected, - std::source_location loc = std::source_location::current()) -{ - auto trace = testing::ScopedTrace{loc.file_name(), static_cast(loc.line()), ""}; - ASSERT_FALSE(result.has_value()) << "expected error, got a value"; - EXPECT_EQ(result.error(), expected); -} - -void -expectKeyletMatches(std::expected const& result, Keylet const& expected); +// Fail a setup step loudly. See the note above on why this is not an `EXPECT_`. +[[noreturn]] void +fixtureFailed(std::string_view what); struct SignedMessage { @@ -116,7 +100,7 @@ private: std::unique_ptr host_; }; -class RealHostFixture : public testing::Test +class WasmLedger { public: TxTest ledger; diff --git a/src/tests/libxrpl/tx/wasm/WasmRun.cpp b/src/tests/libxrpl/tx/wasm/fixtures/WasmRun.cpp similarity index 96% rename from src/tests/libxrpl/tx/wasm/WasmRun.cpp rename to src/tests/libxrpl/tx/wasm/fixtures/WasmRun.cpp index b22bf9ea0f..278bd8fabe 100644 --- a/src/tests/libxrpl/tx/wasm/WasmRun.cpp +++ b/src/tests/libxrpl/tx/wasm/fixtures/WasmRun.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/WasmRun.h b/src/tests/libxrpl/tx/wasm/fixtures/WasmRun.h similarity index 100% rename from src/tests/libxrpl/tx/wasm/WasmRun.h rename to src/tests/libxrpl/tx/wasm/fixtures/WasmRun.h diff --git a/src/tests/libxrpl/tx/wasm/host_calls/CurrentLedgerObjField.cpp b/src/tests/libxrpl/tx/wasm/host_calls/CurrentLedgerObjField.cpp index 143c20fa96..e6030d7886 100644 --- a/src/tests/libxrpl/tx/wasm/host_calls/CurrentLedgerObjField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_calls/CurrentLedgerObjField.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_calls/LedgerSqn.cpp b/src/tests/libxrpl/tx/wasm/host_calls/LedgerSqn.cpp index d4cec43616..32f383f5c6 100644 --- a/src/tests/libxrpl/tx/wasm/host_calls/LedgerSqn.cpp +++ b/src/tests/libxrpl/tx/wasm/host_calls/LedgerSqn.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_calls/Sha512Half.cpp b/src/tests/libxrpl/tx/wasm/host_calls/Sha512Half.cpp index 3653a6e931..9aef5d5966 100644 --- a/src/tests/libxrpl/tx/wasm/host_calls/Sha512Half.cpp +++ b/src/tests/libxrpl/tx/wasm/host_calls/Sha512Half.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_calls/Trace.cpp b/src/tests/libxrpl/tx/wasm/host_calls/Trace.cpp index e7dd854d22..fd7b871749 100644 --- a/src/tests/libxrpl/tx/wasm/host_calls/Trace.cpp +++ b/src/tests/libxrpl/tx/wasm/host_calls/Trace.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include // For `TraceDataType`: declared in the cxx bridge, defined in the header it generates. #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/AccountKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/AccountKeylet.cpp index e64ef2c073..f53d625216 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/AccountKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/AccountKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/AmmKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/AmmKeylet.cpp index e734bdc464..5ef7108fda 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/AmmKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/AmmKeylet.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/BaseFee.cpp b/src/tests/libxrpl/tx/wasm/host_context/BaseFee.cpp index 373a47f483..ee8557ce3a 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/BaseFee.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/BaseFee.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CacheLedgerObj.cpp b/src/tests/libxrpl/tx/wasm/host_context/CacheLedgerObj.cpp index 8c3d015362..a9376fa890 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CacheLedgerObj.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CacheLedgerObj.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CheckKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/CheckKeylet.cpp index 60191ec484..f2af938101 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CheckKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CheckKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CheckSignature.cpp b/src/tests/libxrpl/tx/wasm/host_context/CheckSignature.cpp index 796c56665c..751e4f17aa 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CheckSignature.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CheckSignature.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CredentialKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/CredentialKeylet.cpp index 09d4c7b2fc..462babad6c 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CredentialKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CredentialKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjArrayLen.cpp index 5ef9dbe7c3..8c3aab2d8b 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjArrayLen.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjField.cpp b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjField.cpp index ad00450c35..43f139bfc4 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjField.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedArrayLen.cpp index 6a3f9f2263..5b68a4c510 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedArrayLen.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedField.cpp b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedField.cpp index f9b03f0623..7279438209 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedField.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/DelegateKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/DelegateKeylet.cpp index ecbbf2abab..d1ef893d00 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/DelegateKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/DelegateKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/DepositPreauthKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/DepositPreauthKeylet.cpp index a6f2cc151c..81e524baf2 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/DepositPreauthKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/DepositPreauthKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/DidKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/DidKeylet.cpp index 872c6e9120..220cce677f 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/DidKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/DidKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/EscrowKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/EscrowKeylet.cpp index fbb4d2dbce..8983cfae8b 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/EscrowKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/EscrowKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatAdd.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatAdd.cpp index a6dadf0219..5408e80738 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatAdd.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatAdd.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatCompare.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatCompare.cpp index dbd2fbcb65..381dc58e6f 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatCompare.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatCompare.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatDivide.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatDivide.cpp index 552d172e34..b224e353e8 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatDivide.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatDivide.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatFromInt.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatFromInt.cpp index 78e78d7aa1..51736589a8 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatFromInt.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatFromInt.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatFromMantExp.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatFromMantExp.cpp index 0f3b5d8acd..f825f43f49 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatFromMantExp.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatFromMantExp.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTAmount.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTAmount.cpp index 9a9c22e390..ce2b9f070e 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTAmount.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTAmount.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTNumber.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTNumber.cpp index c18e849026..58497bd914 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTNumber.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTNumber.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatFromUint.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatFromUint.cpp index 35370dfb9b..2c8c101863 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatFromUint.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatFromUint.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatMultiply.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatMultiply.cpp index 939ecb6885..74f20430e4 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatMultiply.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatMultiply.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatPower.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatPower.cpp index 6b2c8087f4..3ec0c3b8be 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatPower.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatPower.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatRoot.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatRoot.cpp index ae9d6057af..593f520ee4 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatRoot.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatRoot.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatSubtract.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatSubtract.cpp index 7f2a08ee1b..1821acc392 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatSubtract.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatSubtract.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatToInt.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatToInt.cpp index 05626d5c60..7f9f3f0ae2 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatToInt.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatToInt.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatToMantExp.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatToMantExp.cpp index 709c6198c0..fb6a82cdc4 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatToMantExp.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatToMantExp.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/IsAmendmentEnabled.cpp b/src/tests/libxrpl/tx/wasm/host_context/IsAmendmentEnabled.cpp index b0cbb6362c..f8fe9c7010 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/IsAmendmentEnabled.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/IsAmendmentEnabled.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjArrayLen.cpp index 80df1bd313..e7c9c62b0e 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjArrayLen.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjField.cpp b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjField.cpp index 8ee616b75a..bd33245258 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjField.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedArrayLen.cpp index 8f2d0d59a0..f4048f93fc 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedArrayLen.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedField.cpp b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedField.cpp index f0336cf39c..a4df4ec6da 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedField.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/LedgerSqn.cpp b/src/tests/libxrpl/tx/wasm/host_context/LedgerSqn.cpp index 442248b47a..4471a0e2b0 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/LedgerSqn.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/LedgerSqn.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/MptokenIssuanceKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/MptokenIssuanceKeylet.cpp index 5a53b05eb5..b8c4c7701b 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/MptokenIssuanceKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/MptokenIssuanceKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/MptokenKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/MptokenKeylet.cpp index 7f4fd2b8f3..c26f0cd5cf 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/MptokenKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/MptokenKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/NFT.cpp b/src/tests/libxrpl/tx/wasm/host_context/NFT.cpp index ba34fff6b0..67ee63ab7b 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/NFT.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/NFT.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/NFTFlags.cpp b/src/tests/libxrpl/tx/wasm/host_context/NFTFlags.cpp index 3c18d53f1f..7c785de074 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/NFTFlags.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/NFTFlags.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/NFTIssuer.cpp b/src/tests/libxrpl/tx/wasm/host_context/NFTIssuer.cpp index 7d0401bccb..cf0c222cf2 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/NFTIssuer.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/NFTIssuer.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/NFTSequence.cpp b/src/tests/libxrpl/tx/wasm/host_context/NFTSequence.cpp index 01bdf0e19a..d3fcc9be87 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/NFTSequence.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/NFTSequence.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/NFTTaxon.cpp b/src/tests/libxrpl/tx/wasm/host_context/NFTTaxon.cpp index 4ddff82c78..1e2909845e 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/NFTTaxon.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/NFTTaxon.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/NFTTransferFee.cpp b/src/tests/libxrpl/tx/wasm/host_context/NFTTransferFee.cpp index d67c5fc5db..2ccd30f517 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/NFTTransferFee.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/NFTTransferFee.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/NftokenOfferKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/NftokenOfferKeylet.cpp index c009321ad2..81e547039e 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/NftokenOfferKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/NftokenOfferKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/OfferKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/OfferKeylet.cpp index de1f36809d..7068ee846d 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/OfferKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/OfferKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/OracleKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/OracleKeylet.cpp index 0355d05b8c..85c58d2c1d 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/OracleKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/OracleKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerHash.cpp b/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerHash.cpp index 2c9d3f219b..9d11271ae6 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerHash.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerHash.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerTime.cpp b/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerTime.cpp index 71a02e995c..c31d20a690 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerTime.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerTime.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/PaychannelKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/PaychannelKeylet.cpp index a184882a1a..096a3996b9 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/PaychannelKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/PaychannelKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/PermissionedDomainKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/PermissionedDomainKeylet.cpp index 5b490954b5..b2484379d3 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/PermissionedDomainKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/PermissionedDomainKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/Sha512Half.cpp b/src/tests/libxrpl/tx/wasm/host_context/Sha512Half.cpp index 6745be70d3..a7bd781335 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/Sha512Half.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/Sha512Half.cpp @@ -4,8 +4,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/SignerListKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/SignerListKeylet.cpp index 29c179863c..fd48a2d18b 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/SignerListKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/SignerListKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/TicketKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/TicketKeylet.cpp index 03dadd4079..c18963993d 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/TicketKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/TicketKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/Trace.cpp b/src/tests/libxrpl/tx/wasm/host_context/Trace.cpp index 857b068cdd..2ac0ebacf3 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/Trace.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/Trace.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/TrustLineKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/TrustLineKeylet.cpp index c4e4bccb01..18a4d8d34a 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/TrustLineKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/TrustLineKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/TxArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_context/TxArrayLen.cpp index 120a8069d7..887842ef7a 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/TxArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/TxArrayLen.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/TxField.cpp b/src/tests/libxrpl/tx/wasm/host_context/TxField.cpp index 24b73bb63c..84a3d694a4 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/TxField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/TxField.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/TxNestedArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_context/TxNestedArrayLen.cpp index 0269f6fbbe..5d550cc623 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/TxNestedArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/TxNestedArrayLen.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/TxNestedField.cpp b/src/tests/libxrpl/tx/wasm/host_context/TxNestedField.cpp index 0cc1cb5a77..43351b6884 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/TxNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/TxNestedField.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/UpdateData.cpp b/src/tests/libxrpl/tx/wasm/host_context/UpdateData.cpp index 7d724205d5..11ee5760ed 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/UpdateData.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/UpdateData.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/VaultKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/VaultKeylet.cpp index a480b21ba2..febf81f0e0 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/VaultKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/VaultKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp index cccdb5d12b..7b2211c3aa 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.cpp index c36eea1d13..a846f8807e 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp index fcc85eb6c4..236a2cf8cf 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.cpp index 9414ecd6dc..cf393f7b89 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp index 052b0b4186..dd0767262a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.cpp b/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.cpp index b1f40233ca..0bba608633 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp index df54cfa899..9811769e86 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.cpp index 2625238e2e..649bd6e5ba 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp index 2390de6f31..2da4c29ec9 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.cpp index 0abcbdc3db..7e2571fac5 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp index e883866627..4587ad0ee8 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.cpp index c1bfd722e4..7bfd7be73a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp index d8ed3844e6..470505c8ef 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.cpp index 0eaeeb5d6a..d3521ad256 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp index 9f59f186e9..243ec2c3e4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.cpp index 6ef7b686c3..72c3491e85 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.cpp @@ -4,7 +4,8 @@ #include #include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp index a5cc479484..42a41e5705 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.cpp index 08816ee4fa..c3c249396f 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp index 0086e13d72..84a6f1f3fa 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp index b94d6f1329..40ce10c841 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp @@ -4,7 +4,8 @@ #include #include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp index 423107409a..d12aa6d935 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.cpp index c59ab5ed47..c1a9cab3da 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.cpp @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp index 4cbc3f7921..0b7e02d055 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.cpp index 8b936652d3..afe148ed53 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp index 5064652ba5..9f7cae8954 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.cpp index 8846c8d1f0..a7a3fec8c4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp index 1f0b280894..882d23c888 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.cpp index 933b3583e0..5ba5a9585c 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp index a1848ec200..8ba2f9a83f 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp @@ -1,9 +1,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -29,7 +29,7 @@ escrowKeyletThroughVm(benchmark::State& state) { seq[i] = static_cast((Fixtures::kSeq >> (8 * i)) & 0xFF); } - return dataSegment(0, RealHostFixture::toBytes(Fixtures::instance().alice().id())) + + return dataSegment(0, WasmLedger::toBytes(Fixtures::instance().alice().id())) + dataSegment(32, seq); }(); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.cpp index ce6bfa73a0..e8bbaa1145 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp index 4978c35300..5efc0635a4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp @@ -1,7 +1,7 @@ #include -#include -#include -#include +#include +#include +#include #include @@ -21,7 +21,8 @@ constexpr std::string_view kBody = void floatAddThroughVm(benchmark::State& state) { - static auto const kData = dataSegment(0, FloatTest::kPi) + dataSegment(16, FloatTest::kTwo); + static auto const kData = + dataSegment(0, FloatConstants::kPi) + dataSegment(16, FloatConstants::kTwo); benchmarkThroughVm( state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); } diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.cpp index 6864794411..c594950cad 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp index a03dce32fa..5c0191f8a1 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.cpp index e66a3beebe..21acd3f915 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp index ed8fe9f154..e070bacad6 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.cpp index 518ab79a82..8e48cfcafe 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp index 90d3913e15..50a13976c6 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.cpp index 9b5cc70b1f..cc972cbde3 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp index 665eaa914f..cde61b9e47 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.cpp index 518db9e411..705c6b3fa1 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp index 23868feedc..107205000e 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.cpp index 66136d78c4..36666ba2d3 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.cpp @@ -7,8 +7,8 @@ #include #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp index e97e626fbc..c89ae97042 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.cpp index 17b350fb9c..40c9f30fa5 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.cpp @@ -4,8 +4,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp index a16a836ff9..dd67a16ad1 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.cpp index bac8d19b6e..c407831448 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp index 085a56ddc9..2629123a69 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.cpp index d49693dc31..cb91211dd4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp index cc4bd4c2cf..a0318f478a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp @@ -1,7 +1,7 @@ #include -#include -#include -#include +#include +#include +#include #include @@ -21,7 +21,7 @@ constexpr std::string_view kBody = void floatPowerThroughVm(benchmark::State& state) { - static auto const kData = dataSegment(0, FloatTest::kPi); + static auto const kData = dataSegment(0, FloatConstants::kPi); benchmarkThroughVm( state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); } diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.cpp index dcb99ca9b3..44e01add62 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp index 84e2e46b08..c45dc36d6f 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.cpp index dd6a14dee0..e4e88bc8a3 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatRoot.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp index 82c08f1040..8536215b0a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.cpp index fc0d5eaa53..4e2a1d9d95 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp index 937fb61238..64e7b3e5af 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.cpp index 119ab42b00..c8fbe6c54b 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp index 8ff4610c88..f59e9346e4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp @@ -1,7 +1,7 @@ #include -#include -#include -#include +#include +#include +#include #include @@ -20,7 +20,7 @@ constexpr std::string_view kBody = void floatToMantExpThroughVm(benchmark::State& state) { - static auto const kData = dataSegment(0, FloatTest::kPi); + static auto const kData = dataSegment(0, FloatConstants::kPi); benchmarkThroughVm( state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); } diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.cpp index 877db427d5..5c8a89e5d0 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp index f95101e5aa..9cb6305b98 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp @@ -1,7 +1,7 @@ #include -#include -#include +#include +#include #include @@ -16,9 +16,11 @@ getNFTImpl(benchmark::State& state) // A really minted token, so the lookup walks a real page rather than failing fast — a // not-found answer would measure the rejection instead of the work. static constexpr auto kUri = std::string_view{"ipfs://benchmark"}; - static auto nft = Bench{}; + // Its own ledger rather than the shared `Fixtures`: minting mutates state, and the shared + // one is deliberately read-only after construction. + static auto nft = WasmLedger{}; static auto const kOwner = nft.fund("benchNftOwner"); - static auto const kMinted = nft.mintNFT(kOwner, kUri); + static auto const kMinted = mintNft(nft, kOwner, kUri); benchmarkImpl( state, diff --git a/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.cpp b/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.cpp index e51b65e1e6..e6d152a06b 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.cpp @@ -4,8 +4,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp index c83be9a784..425bc9e284 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.cpp b/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.cpp index f31954c54c..8c9c34a0df 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp index 20ce7eec81..29a32ae1c4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.cpp index c9969d9f86..b63dfa2657 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.cpp @@ -5,7 +5,8 @@ #include #include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp index c177394202..fe4b08ea0d 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.cpp index 91efc2738b..8deed246f5 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.cpp @@ -5,7 +5,8 @@ #include #include #include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp index 93f3936c83..0e264e1b75 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.cpp index bd340883e6..d7e2fa8939 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.cpp @@ -5,7 +5,8 @@ #include #include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp index 0bcade3ffe..9e4baf7fc1 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.cpp index 95c4da4e69..c8e5d844e7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.cpp @@ -7,7 +7,8 @@ #include #include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp index 5d8140f586..d62ae54989 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.cpp index cf21a259f1..a88c81a586 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp index 8bcfa8a344..9d1ec21ce4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.cpp index 91637c6e3e..d2960a0747 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp index ca534e8939..3cd4b8efd9 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.cpp index 1e9a67fe90..eb3544c2a5 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp index 65a341415b..f279a5b6fd 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.cpp index d06ad23a17..c69871dc0d 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp index 5eb4327803..38973a970f 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.cpp index 12fcf76c48..ef65a4fa4a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp index fc456ab245..7299c892cd 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.cpp index af8f2227a4..28cba45a68 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp index 284b157bde..b707ae19d5 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.cpp index da2942e6cd..3b7641d9e1 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp index fe5d0eb7b1..4e671ec093 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.cpp index c9181b872c..e69eee0192 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp index 4882258566..a3ebd2a3d1 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.cpp index 97d8b3f699..18e669e949 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp index 5bf1bb6510..5204efba4e 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.cpp index cf4eac49e6..82737c9a11 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp index 069e83b8df..c67936dce6 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.cpp index 0d6df50f13..69b0792fe4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp index 52632e1b01..ad87abebb9 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.cpp b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.cpp index 4f0142731a..d5b39bde46 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp index c65a1b85b5..e819d5f0e0 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.cpp b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.cpp index f76e47fda1..3abdef7916 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp index 5fb8aa800b..eca8bd6e77 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.cpp index 77b51254dd..8695f51605 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp index 6ef99a02e6..fdd4aa2bb7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.cpp index 1c9a2ae3ce..fd659f24a7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp index 55a38d59b8..2df5ad46ce 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.cpp b/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.cpp index b02c720503..7cf56f4550 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp index e66ead3f5e..8f42df0d8a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.cpp index b35afd493b..4d640a7a25 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp index a3276ce2c2..4901206ef7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.cpp index e7669bc354..93be84aff7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp index ac84a70bbd..9fc702f9fa 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Trace.cpp b/src/tests/libxrpl/tx/wasm/host_functions/Trace.cpp index 8bb94acd13..0db8539c1d 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/Trace.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/Trace.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp index 4f187159bb..660e242cb7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.cpp index 26017ade9e..c8c428eadf 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp index b4fb17077a..e8ff9724d1 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.cpp index 12aa3b6760..97e5d1d8b9 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.cpp @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp index 6d858cd783..5f61724156 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxField.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxField.cpp index 6d83977c09..c0dd8efdc7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxField.cpp @@ -9,7 +9,8 @@ #include #include #include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp index 4f6ecf0ba2..92d8a60562 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.cpp index c2d8354805..f697ceeed3 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.cpp @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp index f131d292c6..817522eeac 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.cpp index 4a229478db..d801d46f44 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.cpp @@ -7,7 +7,8 @@ #include #include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp index 4df7fc5478..1c3897cb78 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.cpp b/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.cpp index 46bbee69d8..295956d6fb 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp index 409b465be6..22ba8dc7aa 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.cpp index dfc968fa04..1026ed448e 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { From 549d0f57572e973a022712a7f1ab890696c6eeca Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Tue, 1 Sep 2026 12:45:07 -0400 Subject: [PATCH 16/23] chore: Addressing code review code comments --- src/tests/libxrpl/tx/wasm/README.md | 407 ++++++++-------------------- 1 file changed, 112 insertions(+), 295 deletions(-) diff --git a/src/tests/libxrpl/tx/wasm/README.md b/src/tests/libxrpl/tx/wasm/README.md index 1add9daad0..f5dd8336b2 100644 --- a/src/tests/libxrpl/tx/wasm/README.md +++ b/src/tests/libxrpl/tx/wasm/README.md @@ -1,108 +1,75 @@ # WASM host-function tests — layering These tests are deliberately **layered**: each layer isolates one thing, so a failure points at -one place instead of "somewhere in the stack." If a folder looks thin, that is usually because -the breadth it might seem to be missing lives in a sibling layer. This file is the map. +one place instead of "somewhere in the stack." If a folder looks thin, the breadth it seems to be +missing lives in a sibling layer. This file is the map. ## The layers -| Layer | Location | host | VM | ledger | Answers | -| ------------------------------------- | ------------------------------------------------------------------------------------------- | ---- | --- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------- | -| Engine / gas / limits / ABI | `crates/xrpl-wasm-vm/tests`, `crates/xrpl-host-functions/tests` (Rust, `.wat` + `FakeHost`) | mock | ✓ | ✗ | gas, transfer budget, memory/field limits, preflight screening, VM limits, the generated ABI + error codes | -| `host_context/` (`HostContextTest`) | `src/tests/libxrpl/tx/wasm/host_context` | mock | ✗ | ✗ | the `HostContext` marshalling shim in isolation (byte order, buffer sizing, `SField` translation) | -| `host_calls/` (`HostCallTest`) | `.../host_calls` | mock | ✓ | ✗ | per-host-function **wire contract** — what the host was asked, what came back — a real guest through the real VM + `HostContext`, mock host | -| `host_functions/` (`RealHostFixture`) | `.../host_functions` | real | ✗ | real | each host function's **actual answer** vs. real `TxTest` ledger state (impl called directly in C++) | -| `e2e/` (`RealVmTest`) | `.../e2e` | real | ✓ | real | **full-stack integration** — VM + `HostContext` + real impl + real ledger, driven by a WAT contract | +| Layer | Location | host | VM | ledger | Answers | +| ------------------------------------- | --------------------------------------------------- | ---- | --- | ------ | ----------------------------------------------------------------------------------- | +| Engine / gas / limits / ABI | `crates/xrpl-wasm-vm`, `crates/xrpl-host-functions` | mock | ✓ | ✗ | gas, transfer budget, memory/field limits, preflight, VM limits, generated ABI | +| `host_context/` (`HostContextTest`) | `.../host_context` | mock | ✗ | ✗ | the `HostContext` marshalling shim alone (byte order, buffer sizing, `SField` xlat) | +| `host_calls/` (`HostCallTest`) | `.../host_calls` | mock | ✓ | ✗ | per-function **wire contract** — what the host was asked, what came back | +| `host_functions/` (`RealHostFixture`) | `.../host_functions` | real | ✗ | real | each function's **actual answer** vs. a real `TxTest` ledger | +| `e2e/` (`RealVmTest`) | `.../e2e` | real | ✓ | real | **full-stack integration** — VM + `HostContext` + real impl + real ledger | -`MockVmTest` / `RealVmTest` are the mock-host and real-host counterparts of the same VM harness; -both forward to the shared `runWat(HostFunctions&, ...)` in `fixtures/WasmRun.h`, differing only -in the host they inject. +Run the C++ side with: -## `fixtures/` — and why it is split in two +```bash +./build/xrpl_tests --gtest_filter='*Impl.*:*Call.*:*E2e.*:WasmVMTest.*:WasmVMDeathTest.*:PreflightTest.*' +``` -Everything shared sits in `fixtures/`, divided by whether it needs a test framework: +(720 tests, 138 suites.) The engine-level coverage is Rust: `cd crates && cargo test`. -| | | -| ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **No GTest** — the `xrpl.testkit.wasm` library | `WasmLedger` (a real genesis ledger + the real host over it), `WasmRun` (the WAT assembler), `NftSetup`, `FloatConstants` | -| **GTest** — compiled into `xrpl_tests` | `RealHostFixture` (`: testing::Test, WasmLedger` plus `expectValue`/`expectError`/`expectKeyletMatches`), `FloatFixture`, `NFTFixture`, `MockHostFunctions`, `WasmFixture`, `RealVmTest`, `HostContextFixture` | -| **Benchmark harness** — compiled into `xrpl.bench.wasm` | `WasmBench`, `BenchFixtures` | +## `fixtures/` — split by whether it needs a test framework -The split exists because **a benchmark wants a ledger and a host, not GTest's lifecycle.** Both -binaries link the library; `xrpl.bench.wasm` links no GTest and no GMock at all. +| | | +| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **No GTest** — the `xrpl.testkit.wasm` library | `WasmLedger` (real genesis ledger + the real host over it), `WasmRun` (WAT assembler), `NftSetup`, `FloatConstants` | +| **GTest** → `xrpl_tests` | `RealHostFixture` (`: testing::Test, WasmLedger` + `expectValue`/`expectError`/`expectKeyletMatches`), `FloatFixture`, `NFTFixture`, `MockHostFunctions`, `WasmFixture`, `RealVmTest`, `HostContextFixture` | +| **Benchmark harness** → `xrpl.bench.wasm` | `WasmBench`, `BenchFixtures` | -One consequence worth knowing: setup steps in `WasmLedger` and `NftSetup` **throw** (via -`fixtureFailed`) rather than using `EXPECT_`. That is not stylistic. An `EXPECT_` outside a -running test is recorded and discarded, so a benchmark whose escrow was never created would still -run its host call, take the not-found path, and report a cheap, plausible, completely wrong price. -Throwing turns that into a stopped run. If you add a setup step that can fail, throw. +A benchmark wants a ledger and a host, not GTest's lifecycle. Both binaries link the library; +`xrpl.bench.wasm` links no GTest and no GMock at all. + +Setup steps in `WasmLedger` and `NftSetup` **throw** (`fixtureFailed`) rather than using `EXPECT_`. +Not stylistic: an `EXPECT_` outside a running test is recorded and discarded, so a benchmark whose +escrow was never created would still run its host call, take the not-found path, and report a +cheap, plausible, completely wrong price. **If you add a setup step that can fail, throw.** ## `*.bench.cpp` — gas calibration -Interleaved with the tests are `*.bench.cpp` files. They are **not tests**: nothing asserts, -and a number moving is not a build failure. They answer the pricing question the tests cannot — -whether each `#[gas = N]` in `crates/xrpl-host-functions/src/lib.rs` matches what the function -actually costs. +Not tests: nothing asserts, and a number moving is not a build failure. They answer the question +the tests cannot — whether each `#[gas = N]` in `crates/xrpl-host-functions/src/lib.rs` matches +what the function costs. -**One `.bench.cpp` per host function, named after its test** — `EscrowKeylet.cpp` and -`EscrowKeylet.bench.cpp` sit next to each other, 61 of each. That is a checklist rather than a -judgment call: adding a host function means adding two files, and nobody has to decide where a -benchmark belongs. Shared ledger setup lives in the `Fixtures` type (`fixtures/BenchFixtures.h`) — one -ledger, funded once, for the whole binary — so each file holds only the call it measures. - -They build into a **separate executable** (`xrpl.bench.wasm`) that links `xrpl.testkit.wasm` and -no test framework, and `xrpl_tests` filters `*.bench.cpp` out of its source globs, so benchmark -runtime never lands on the `ctest` path. - -### Running them - -The executable lands in the **build root**, beside `xrpl_tests`: +One `.bench.cpp` per host function, named after its test, so adding a function is a two-file +checklist rather than a judgement call. Shared ledger setup is the `Fixtures` type — one ledger, +funded once, for the whole binary. ```bash -# configure with -o benchmark=True (the conan default), then: cmake --build build --target xrpl.bench.wasm ./build/xrpl.bench.wasm # everything (~2 min) ./build/xrpl.bench.wasm --benchmark_filter=sha512Half -./build/xrpl.bench.wasm --benchmark_format=json >gas.json ``` -**Build Release first.** A Debug build inflates the crossing (templates and `std::expected`, -none of it inlined) far more than it inflates the impls, so Debug overstates what leaving the -guest costs. Google Benchmark prints a warning when it detects this. Ratios between `Impl` -cases survive Debug reasonably; absolute `implied_gas` does not. - -> **On hardware performance counters.** Google Benchmark can read instruction and cycle counts -> through libpfm on Linux, and that was wired up here at one point, but it has been removed: its -> counters start and stop around the whole `for (auto _ : state)` body, which for these cases -> covers the loaded run _and_ the baseline run _and_ two module compilations. They would not -> reflect the subtraction that makes these numbers mean anything. Getting useful instruction -> counts needs a custom `perf_event_open` around the same regions `timeRun` brackets — worth -> doing, but the dependency buys nothing until then. +**Build Release first.** Debug inflates the crossing far more than the impls. Ratios between +`Impl` cases survive Debug; `suggested_gas` does not. ### Reading the output -Gas _is_ wasmi fuel — `set_fuel(gas)` meters guest instructions and host charges from one pool — -so a host call's price is answerable as a **ratio**: how many guest instructions' worth of work -is it? That is machine-independent, which matters because a consensus rule cannot be derived -from one laptop's nanoseconds. +| Counter | Meaning | +| ------------------- | ---------------------------------------------------------------------------------- | +| `suggested_gas` | **the answer** — what this function should be priced at | +| `host_function_gas` | what `lib.rs` says today, read through the `wasm_testkit` bridge so it can't drift | +| `price_ratio` | `declared / suggested`. **1.0 is correct; below 1 is underpriced** | +| `implied_gas` | the raw measurement, before the crossing is added back | +| `charged_gas` | what the engine actually billed; confirms the right call was measured | +| `ns_per_call` | raw wall time, for debugging a suspicious ratio | -| Counter | Meaning | -| --------------- | -------------------------------------------------------------------------------------------- | -| `suggested_gas` | **the answer** — what this function should be priced at | -| `declared_gas` | what `lib.rs` says today | -| `price_ratio` | `declared / suggested`. **1.0 is correct; below 1 is underpriced** | -| `implied_gas` | the raw measurement, before the crossing is added back | -| `charged_gas` | what the engine actually billed (`EscrowResult::cost`); confirms the right call was measured | -| `ns_per_call` | raw wall time, for debugging a suspicious ratio | - -`declared_gas` is read from the declaration through the `wasm_testkit` bridge -(`declared_gas(wasm_name)`), not transcribed into C++ — 61 copied constants would drift from -`lib.rs` the first time a price changed, and drift _silently_, because a benchmark has nothing -to fail. - -`price_ratio` is what you sort by. **Below 1 is the direction that matters**: an underpriced call -is one a contract can buy too cheaply, which is a denial-of-service vector rather than a rounding -error. Above 1 the table merely overcharges. The mispriced functions come to the top with: +`price_ratio` is what you sort by. **Below 1 is the direction that matters** — an underpriced call +is one a contract can buy too cheaply, a denial-of-service vector rather than a rounding error: ```bash ./build/xrpl.bench.wasm --benchmark_format=json | @@ -111,146 +78,72 @@ error. Above 1 the table merely overcharges. The mispriced functions come to the ### How `suggested_gas` is measured -Gas is not a unit of time, so a wall-clock number cannot be a gas number. The bridge between them -is that **gas is wasmi fuel** — `set_fuel(gas)` meters guest instructions and host charges from -one pool — so one unit of gas is, by construction, about one guest instruction. That turns the -question into a ratio: _how many guest instructions' worth of work is this host call?_ Everything -below exists to answer that without any hard-coded constant. - -Four steps, each a subtraction, all in `WasmBench.h` / `WasmBench.cpp`. - -**1. `Calibration::secondsPerGas()` — what one unit of gas costs on this machine.** -Assemble two modules that differ only in a loop bound: one runs a trivial `i32.add` body -`kCallsPerRun` times, the other zero times. Run both, and take +A wall-clock number cannot be a gas number. The bridge is that **gas is wasmi fuel** — +`set_fuel(gas)` meters guest instructions and host charges from one pool — so one unit of gas is +about one guest instruction, and the question becomes a ratio: _how many guest instructions' worth +of work is this call?_ Every step is a subtraction, so fixed costs cancel: ``` -secondsPerGas = (time_busy − time_idle) / (fuel_busy − fuel_idle) +secondsPerGas = (time_busy − time_idle) / (fuel_busy − fuel_idle) # a pure-wasm loop, N vs 0 +implied_gas = secondsPerCall / secondsPerGas +crossing_floor = (ldgr_index ThroughVm − ldgr_index Impl) / secondsPerGas + +suggested_gas = implied_gas # ThroughVm — the guest already paid the crossing +suggested_gas = implied_gas + crossing_floor # Impl — a guest cannot call without paying it +price_ratio = host_function_gas / suggested_gas ``` -Both numerator terms include module compilation, instantiation and process noise; both -denominator terms include the engine's fixed overhead. Subtracting cancels all of it, leaving -seconds per unit of fuel. Taken as the **minimum over 32 pairs** (after 8 warm-up pairs), because -the fastest run is the one least disturbed by the scheduler. Cached — it describes the machine, -not the case. +`secondsPerCall` is itself a subtraction: a `ThroughVm` case runs a contract making N host calls +against a **byte-identical** one making none, so compilation, instantiation and the guest's own +loop cancel. It is reported per iteration, so Google Benchmark's variance statistics describe the +host call rather than the run containing it. An `Impl` case times `kCallsPerRun` direct calls and +divides. -**2. `secondsPerCall` — the isolated cost of one host call.** -The same subtraction, one level up. A `ThroughVm` case runs a contract making N host calls and a -**byte-identical** one making none, then reports `(t_loaded − t_baseline) / N` _per iteration_, so -Google Benchmark's variance statistics describe the host call rather than the run containing it. -An `Impl` case times `kCallsPerRun` direct calls and divides, spreading the clock read over -enough work that it does not distort a cheap call. +**`guestInstruction` is the self-test, and it has a number.** It runs the same loop body the +calibration uses, so its `implied_gas` (wall time) and `charged_gas` (the engine's fuel meter) are +two measurements of one quantity. Release, quiet machine: **≈13.6 against 13.007, ~4% high with +~4% spread.** A persistent gap much beyond that is a harness bug — do not trust any other number +in the run until it is closed. -**3. `implied_gas` — the measurement, in gas.** +That check has already caught a real defect: calibration took a _best-of-N_ while the cases report +a _mean_, which biased every number +40%. Both are means now. **If you change how either side is +estimated, change both.** -``` -implied_gas = secondsPerCall / secondsPerGas -``` +**Two limits.** `suggested_gas` for an `Impl`-only case is a **lower bound** — the crossing floor +is measured on a call with no input, so a function that moves bytes pays more (the swept cases, +`Sha512Half` and `UpdateData`, measure that per-byte term). And `--benchmark_repetitions=N` +averages down noise but will not touch a systematic bias. -Machine-independent: both terms scale with the box, so the ratio does not. +`ThroughVm` cases are deliberately **one per crossing shape, not one per function**: what the +crossing costs depends on a call's shape, not on which function makes it. -**4. `Calibration::crossingFloorGas()` — the toll every call pays.** -Measured once, from `ldgr_index` — the cheapest host function there is, taking no input and -answering from a header already in hand, so almost nothing remains after subtracting it away: - -``` -crossing_floor = (secondsPerCall_ThroughVm − secondsPerCall_Impl) / secondsPerGas -``` - -That is region decode, bounds checks and the cxx hop, and nothing else. - -**Putting it together:** - -``` -suggested_gas = implied_gas # ThroughVm — the guest already paid the crossing -suggested_gas = implied_gas + crossing_floor # Impl — a guest cannot call without paying it -price_ratio = declared_gas / suggested_gas -``` - -**Why you can trust it measured the right thing.** `charged_gas` comes from the engine's own fuel -meter (`EscrowResult::cost`), independently of every timing above. On a `ThroughVm` case it should -equal the declared gas plus the fuel the guest itself burns — the loop body (13, which -`GuestInstruction` reports on its own) plus the `i32.const`s pushing the call's arguments. So -`escrow_id` reports `charged_gas ≈ 367` against a declared 350: 13 for the loop, 4 for its six -argument constants. When that arithmetic does not line up, the case is measuring something other -than the call it names. - -**`guestInstruction` is the harness's self-test, and it has a number.** It runs the same loop body -`Calibration::secondsPerGas()` calibrates against, so its `implied_gas` (from wall time) and -`charged_gas` (from the engine's fuel meter) are two measurements of one quantity and must agree. -On a quiet machine, Release, that is currently **`implied_gas` ≈ 13.6 against `charged_gas` 13.007 -— about 4% high, with roughly 4% run-to-run spread.** Treat a persistent gap much beyond that as a -harness bug rather than a property of the machine, and do not trust any other number in the run -until it is closed. - -That check is worth running because it has already caught a real defect. Calibration originally -took a _best-of-N_ while the cases report a _mean_, and since `implied_gas = -secondsPerCall / secondsPerGas`, a minimum in the divisor against a mean in the dividend biased -every reported number one way — `guestInstruction` read 18.2 against 13.007, +40%, and every -`suggested_gas` in the report was inflated by that factor. Both estimators are now means. **If you -change how either side is estimated, change both.** - -**Two limitations, both real.** - -- `suggested_gas` for an `Impl`-only case is a **lower bound**. The crossing floor is measured on a - call with no input, so a function that moves bytes pays more than the floor. The swept cases - (`Sha512Half`, `UpdateData`) measure that per-byte term where it matters. -- A Debug build inflates the crossing far more than the impls, so absolute values are not usable - there. **Ratios between `Impl` cases survive Debug; `suggested_gas` does not.** -- Run-to-run spread is a few percent, which is immaterial next to the pricing errors this suite finds - (6x-20x). If you need it tighter, `--benchmark_repetitions=N` averages the noise down; it will - not touch a systematic bias, which is what the `guestInstruction` check above is for. - -### The two case kinds, and why the subtraction is the point - -Every function has an `Impl` case; the distinct crossing shapes also have a `ThroughVm` case. - -- **`Impl`** — the host method called directly. No guest, no VM, no marshalling: the computation alone. -- **`ThroughVm`** — the same call made by a real WAT contract through the real VM, against a real - ledger. Measured as the difference between a contract making N host calls and a **byte-identical** - one making none, so compilation, instantiation and the guest's own loop cancel out. - -`ThroughVm − Impl` is the **crossing**: region decode, bounds checks, memory copies, the cxx hop. -`Crossing.bench.cpp` brackets its floor with the cheapest possible host call, and the size-swept -cases (`Sha512Half`, `UpdateData`) expose its per-byte term. - -`ThroughVm` cases are deliberately **one per crossing shape, not one per function** — the same -argument as the e2e rule above. What the crossing costs depends on a call's shape, not on which -function makes it, so a `float_sub` ThroughVm would only re-measure `float_add`'s. - -### Gotchas, all of which have already cost someone an afternoon +### Gotchas, each of which has already cost someone an afternoon - **The wasm ABI is not the trait's argument order.** `float_add(x, y, mode, out)` in Rust is `(x_ptr, x_len, y_ptr, y_len, out_ptr, out_len, mode)` on the wire — scalars move _after_ the output region. Check `register.rs`, not `lib.rs`, when writing WAT. - **A soft host error still "succeeds".** The run completes and gas is charged _before_ the body, - so a wrong-argument case reports a plausible, confidently wrong number — it measures the - rejection path. The harness guards this by requiring the contract's result to be `>= 0`. The - tell is a `ThroughVm` case coming out _faster_ than its `Impl` pair. -- **A host serves exactly one run** (`checkSelf` assert in `WasmVM.cpp`), so a benchmark builds a - fresh host per run and cannot pre-cache a slot. -- **`MAX_FIELD_BYTES` is 1024** — no value crosses the boundary in either direction above 1 KiB, - so size sweeps stop there. -- Cases pin `->Iterations(...)`: with `UseManualTime`, Google Benchmark's automatic sizing reads - only the tiny reported residue and would ask for millions of iterations. + so a wrong-argument case reports a plausible, confidently wrong number. The harness requires the + contract's result to be `>= 0`; the tell is a `ThroughVm` case coming out _faster_ than its `Impl`. +- **A host serves exactly one run** (`checkSelf` in `WasmVM.cpp`), so a benchmark builds a fresh + host per run and cannot pre-cache a slot. +- **`MAX_FIELD_BYTES` is 1024** — nothing crosses the boundary above 1 KiB, so size sweeps stop there. +- Cases pin `->Iterations(...)`: with `UseManualTime`, automatic sizing reads only the tiny reported + residue and would ask for millions of iterations. ## What `e2e/` covers — the rule -**`e2e/` covers every marshalling shape and every cross-call convention exactly once. It does -not cover every function.** That is a completeness claim on the axis e2e can uniquely test, not -a sample. +**`e2e/` covers every marshalling shape and cross-call convention exactly once. It does not cover +every function.** That is a completeness claim on the axis e2e uniquely tests, not a sample. -The reasoning: `host_calls` pins what the bridge _asks_ a host and what it does with a _canned_ -answer; `host_functions` pins what the real impl _answers_. The C++ type system guarantees the -two agree on signatures — the real impl implements the same interface the mock does. What -nothing guarantees is that they agree on **conventions**: units, endianness, buffer layout, the -meaning of a wire format. A mocked bridge test and a direct impl test can both pass while -meaning different things by "a four-byte sequence number", because in neither test does a real -guest write bytes that a real host reads. That is precisely the `seq`-as-little-endian-region -bug: every internal test passed, and it was caught by cross-checking the guest SDK. +`host_calls` pins what the bridge _asks_ with a _canned_ answer; `host_functions` pins what the +real impl _answers_. The type system guarantees they agree on signatures. Nothing guarantees they +agree on **conventions** — units, endianness, buffer layout — because in neither test does a real +guest write bytes a real host reads. That is exactly the `seq`-as-little-endian-region bug: every +internal test passed, and it was caught by cross-checking the guest SDK. -Convention mismatch is a property of the **shape** of a call, not of the function making it. All -19 keylet functions share one shape; a 19th keylet e2e proves nothing the 1st did not. So the -inventory below is indexed by shape, and it is meant to be exhaustive: +Convention mismatch is a property of a call's **shape**, not of the function. All 19 keylets share +one shape, so a 19th keylet e2e proves nothing the 1st did. The inventory is meant to be exhaustive: | Shape / convention | Covered by | Why it is its own row | | ----------------------------------------- | -------------------------- | -------------------------------------------------------- | @@ -262,106 +155,30 @@ inventory below is indexed by shape, and it is meant to be exhaustive: | locator (path of i32 steps) | `TxNestedFieldE2e` | a wire format the guest writes and the host walks | | **two** output regions | `FloatToMantExpE2e` | two bounds checks, two writes, an ordering between them | | write / mutation | `SetDataE2e` | the one thing a contract changes | -| **error** path from a real impl | `HostErrorE2e` | soft code produced by a real failure, not a staged one | +| **error** path from a real impl | `HostErrorE2e` | a soft code from a real failure, not a staged one | | realistic multi-call contract | `HostFunctionTourE2e` | the old `all_host_functions` tour shape, as one test | -Adding a function does not require a new e2e case — unless it introduces a shape or a convention -not in that table, in which case it does. Per-function breadth (does fn X return the right -value, does it marshal correctly) lives in `host_functions/` and `host_calls/`, one case each, -and re-driving that shared machinery 61 times e2e would cost heavy per-test ledger setup for no -added signal. +Adding a function needs no new e2e case unless it introduces a shape not in that table. Per-function +breadth lives in `host_functions/` and `host_calls/`, one case each. -The **guest SDK** (`xrpl-std` / `xrpl-escrow`, from the external `xrpl-wasm-stdlib` repo) is -intentionally **not** exercised here: that is the SDK repo's own test suite. WAT tests the host -side (this repo's code); a compiled guest would couple this suite to that repo and a Rust→wasm -toolchain. +## Out of scope -## SDK ↔ host agreement — what the retired fixtures tested, and why it lives elsewhere +**The guest SDK** (`xrpl-std` / `xrpl-escrow`, external `xrpl-wasm-stdlib` repo) is not exercised +here — that is the SDK repo's own suite. These tests hand-write the ABI in WAT (raw imports, +literal field codes, hand-built byte layouts), deliberately bypassing all SDK code. Agreement is +verified _transitively_: the SDK repo tests the SDK against the ABI spec, this repo tests the host +against the same spec. That would not catch a drift where both diverge on an ambiguous point; +closing it needs a **cross-repo integration test** (compiled guests against a real host) in CI +where the Rust→wasm toolchain exists. -The old `wasm_fixtures/` guests (`all_host_functions`, `all_keylets`, `codecov_tests`) were -compiled from the real `xrpl-std` / `xrpl-escrow` SDK, so beyond exercising host functions they -implicitly tested the **SDK's side of the ABI contract** — that the SDK and the host agree on the -wire format: +**Transactor-level (L5) tests** are deferred: the redesign does not yet wire `runEscrowWasm` into +the `EscrowFinish` transactor, so there is no caller under `src/xrpld`. When it is wired, these +need a home as C++ transactor tests over a real `Env` — `set_data` persistence (including on +`tecBYTECODE_REJECTED`), `sfGasUsed` / `sfVMReturnCode` in transaction metadata, and owner-reserve +accounting for a bytecode-bearing escrow. The layers here deliberately stop at the VM boundary. -- **host bindings** — import module/name and parameter order/types actually reach the host functions -- **field-code & locator encoding** — `sfield` constants and nested-field `Locator` serialization -- **type serialization** — `Issue` / `Currency` / `MptId` / `XrpIssue` encode to the byte layouts the host decodes -- **error-code enum** — the SDK's `error_codes` match the host's wire numbers -- **size constants** — `DEFAULT_BLOB_SIZE` / `XRPL_CONTRACT_DATA_SIZE` match the host's caps -- **typed accessors** — `get_current_escrow`, `ledger_object::get_field`, `keylets::*` build requests and decode responses +--- -None of that is host code — it is the SDK's, and it is the `xrpl-wasm-stdlib` repo's job to test. -The tests here hand-write the ABI in WAT (raw imports, literal field codes, hand-built byte -layouts), which **deliberately bypasses all SDK code**. So SDK correctness is out of scope here by -design. - -**The one residual gap** is the _direct_ SDK↔host cross-check a compiled guest gave for free. The -new split verifies agreement **transitively**: the SDK repo tests the SDK against the ABI spec, and -this repo tests the host against the same spec (`host_calls`, the `generated_abi.rs` spec table, -`host_errors.rs`). That is sound as long as both conform to the spec; it would not catch a drift -where the SDK and host diverge on an ambiguous point. Closing that gap is **not** an xrpld unit -test — it is a **cross-repo integration test** (compiled `xrpl-wasm-stdlib` guests run against a -real xrpld host) belonging in CI where the Rust→wasm toolchain exists. - -## Out of scope — transactor-level (L5) tests deferred until the transactor is wired - -This migration ported `Wasm_test.cpp` + the `wasm_fixtures/` guests, which drive the VM directly -via `runEscrowWasm`. In the upstream `ripple/smart-escrow` branch the **same fixtures** are also -consumed by two **transactor-level** suites that are **not** part of this port and have **no -equivalent here yet**, because the redesign branch does not yet wire `runEscrowWasm` into the -`EscrowFinish` transactor (it has no caller under `src/xrpld`): - -- **`EscrowSmart_test.cpp`** — full `Env → EscrowFinish → ledger`. Its cases test things none of - the layers above cover, because they only exist once a transactor runs the contract: - - **`set_data` persistence** — "Update escrow data on failure" asserts the contract's data field - is written to the escrow ledger object **even on `tecBYTECODE_REJECTED`**. (Note: in _this_ - branch `set_data` is _not_ persisted — there is no transactor caller yet — so this is a real - gap, not a redundancy.) - - **gas → fee / meta** — `sfGasUsed` and `sfVMReturnCode` surfaced in transaction metadata. - - **owner reserve / owner count** accounting for the bytecode-bearing escrow. - - **transactor-driven tours** — "Test all host functions", "Test all keylet host functions", - "Test large wasm modules". -- **`PayChan_test.cpp`** — also consumes `wasm_fixtures` symbols at the transactor level. - -These belong to the **L5 transactor layer**. When `EscrowFinish` is wired to `runEscrowWasm` in the -redesign, those cases need a home (as C++ transactor tests over a real `Env`), and the persistence / -gas-in-meta / reserve behaviors should be pinned there — the WAT layers here deliberately stop at -the VM boundary and do not exercise the transactor. - -## Old → new test map - -`Wasm_test.cpp` (retired) + `wasm_fixtures/` guests → the new design. ★ = authored during the -migration. - -| Old test / fixture | New home | Status | -| --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | -| `wasm lib test` (inline addTwo) | Rust `vm_limits::WasmVMTest::ContractReturnValueReachesCaller` | superseded | -| `bad wasm test` | Rust `preflight::garbage_does_not_pass` | superseded | -| `Wasm get ledger sequence` | `host_calls/LedgerSqn` + ★`e2e/LedgerSqn` | superseded + e2e | -| `import/export functions` | Rust `preflight` (imports) / `vm_limits` (imports at instantiation) | superseded | -| `import/export section corruption` | Rust `preflight::garbage_does_not_pass` + ★`structurally_malformed_modules_are_refused` | superseded + ported | -| `Wasm fibo` | Rust `budgets` (gas baseline) | superseded | -| `wasm test host functions cost` | Rust `budgets` (`a_host_call_costs_its_gas...`) | superseded | -| `escrow wasm devnet` (26-fn tour) | `host_functions/*` + `host_calls/*` + ★`e2e/*` (incl. `HostFunctionTourE2e`) | decomposed | -| `Codecov wasm test` | Rust `memory_policy` + `host_calls` error paths | superseded | -| `float point` (was commented) | `host_functions/Float*` + Rust `host_calls` float (incl. ★8 gaps) | superseded + ported | -| `disabled float` | Rust `vm_limits::disabled_features` (floats) | superseded | -| `memory limit tests` (×11) | Rust `memory_policy` + `vm_limits` | superseded | -| `table limit tests` (×5) | Rust `vm_limits` | superseded | -| `disabled proposal tests` (×13) | Rust `vm_limits::disabled_features` | superseded | -| `trap tests` (×5) | Rust `vm_limits`: `unreachable` + ★div0 / overflow / null-indirect / sig-mismatch | all ported | -| `Wasm Wasi tests` (×2) | Rust `preflight`/`vm_limits` (unknown import) | superseded | -| `Section Corruption` (×10) | Rust ★`structurally_malformed_modules_are_refused` (6) + ★`parser_abuse_shapes_are_refused` (4 DoS) | all ported | -| `start function loop` | Rust `vm_limits` (start section) / `preflight` | superseded | -| `Wasm Bad Align` | Rust ★`host_calls::an_unaligned_input_is_read_intact` | ported | -| `invalid return type` / `invalid params` | Rust `preflight`/`vm_limits` | superseded | -| `Wasm swap bytes` | plain C++ endian util test (not a VM test) | keep as-is | -| `Many params` — params / locals / functions | Rust ★`vm_limits` (`too_many_params`, `too_many_locals`, `past_the_register_frame`, `many_functions_currently_run_unbounded` [`#[ignore]` marker]) | ported (functions enforcement deferred to preflight) | -| `deep recursion` | Rust ★`vm_limits::unbounded_recursion_is_stopped_by_the_call_stack_limit` | ported | -| `infinite loop` | Rust `budgets::an_endless_loop_is_stopped_by_gas` | superseded | -| `reserved opcodes` | Rust `vm_limits::disabled_features` (representative) | superseded | -| float sub/mult/div/pow, from_stamount/stnumber, to_int, from_mant_exp | Rust ★`host_calls` (8 tests) | ported | -| **Fixture** `all_host_functions` | ★`e2e` (incl. tour) + `host_functions/*` + `host_calls/*`; SDK → external repo | decomposed | -| **Fixture** `all_keylets` (was orphaned) | `host_functions/*Keylet`; SDK → external repo | decomposed | -| **Fixture** `codecov_tests` | Rust `memory_policy` + `host_calls` error paths + ★`e2e` | decomposed | -| `getData helper functions` | — (tested a deleted engine API) | removed | +The old→new coverage map for the retired `Wasm_test.cpp` and `wasm_fixtures/` guests lives in the +migration notes and this PR's history; it is a record of a completed port rather than something a +reader of these tests needs. From f9527b90da4f228a69c1da2ffdfe53b454f74498 Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Tue, 1 Sep 2026 15:25:00 -0400 Subject: [PATCH 17/23] chore: Addressing code review comments --- .../libxrpl/tx/wasm/fixtures/WasmBench.cpp | 14 +++++++++---- .../libxrpl/tx/wasm/fixtures/WasmBench.h | 21 ++++++++++++------- .../wasm/host_functions/Sha512Half.bench.cpp | 6 +++--- .../wasm/host_functions/UpdateData.bench.cpp | 4 +++- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.cpp b/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.cpp index 9cdc921285..c0f877ba17 100644 --- a/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.cpp +++ b/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.cpp @@ -21,14 +21,20 @@ namespace xrpl::test::bench { int -callsWithinTransferBudget(std::int64_t bytesPerCall) +callsWithinTransferBudget(std::int64_t bytesWrittenPerCall) { - if (bytesPerCall <= 0) + // Writes nothing back to the guest, so the budget does not apply at all. + if (bytesWrittenPerCall <= 0) { return kCallsPerRun; } - auto const affordable = (kTransferLimitBytes / 2) / bytesPerCall; - return static_cast(std::clamp(affordable, 16, kCallsPerRun)); + + auto const affordable = kTransferLimitBytes / bytesWrittenPerCall; + if (affordable < 1) + { + fixtureFailed("a single call would exceed the run's transfer budget"); + } + return static_cast(std::min(affordable, kCallsPerRun)); } std::string diff --git a/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.h b/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.h index 5063d61f23..281ac5c8a2 100644 --- a/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.h +++ b/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.h @@ -47,16 +47,23 @@ inline constexpr std::int32_t kBenchIterations = 50; // best-of with a mean did. inline constexpr std::int32_t kCalibrationPairs = 400; -// Every run gets this much guest<->host copying before `charge_transfer` starts refusing -// calls. It is a per-run budget, so it resets between the runs a benchmark makes — -// but a single run of `kCallsPerRun` calls moving a kilobyte each would exhaust it partway -// through and spend the rest of the loop measuring the refusal path instead of the host function. +// How much a run may write into guest memory before `charge_transfer` starts refusing calls +// (`TRANSFER_LIMIT_BYTES` in crates/xrpl-wasm-vm/src/vm.rs). Per run, so it resets between the +// runs a benchmark makes — but one run of `kCallsPerRun` calls could exhaust it partway through +// and spend the rest of the loop measuring the refusal path instead of the host function. inline constexpr std::int64_t kTransferLimitBytes = 1 << 20; -// How many calls a run can afford at `bytesPerCall`, staying clear of the transfer budget. -// Halved because most functions move bytes in *both* directions. +// How many calls a run can afford, given how many bytes each one has the host **write into guest +// memory**. +// +// One direction only: the budget is charged in `write_into` / `write_buffered` / `write_mant_exp` +// and nowhere else. What the guest passes *in* is borrowed rather than copied and costs nothing +// against it, so a caller passes the size of its output region, not of its input. +// +// Never raises the count to meet a floor — that would be the one thing this function exists to +// prevent. A case that cannot afford a single call cannot be measured, so that fails loudly. int -callsWithinTransferBudget(std::int64_t bytesPerCall); +callsWithinTransferBudget(std::int64_t bytesWrittenPerCall); // One run of a contract: how long it took, and what the engine charged it. struct Timing diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp index 2df5ad46ce..751b1ea8b7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp @@ -30,8 +30,8 @@ sha512HalfThroughVm(benchmark::State& state) "(call $sha512_half (i32.const 0) (i32.const {}) (i32.const 8192) (i32.const 32))", state.range(0)); - // The call count shrinks as the input grows: at 1 KiB a thousand calls would approach the - // engine's per-run transfer budget and the tail of the loop would be measuring refusals. + // A hash is 32 bytes back to the guest whatever the input length, and the transfer budget + // counts only what the host writes — so the input sweep does not shrink the call count. benchmarkThroughVm( state, kWasmName, @@ -39,7 +39,7 @@ sha512HalfThroughVm(benchmark::State& state) "", body, [] { return Fixtures::instance().host(); }, - callsWithinTransferBudget(state.range(0) + 32)); + callsWithinTransferBudget(32)); state.SetBytesProcessed(state.iterations() * state.range(0)); } BENCHMARK(sha512HalfThroughVm) diff --git a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp b/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp index 1c3897cb78..fca836bd3b 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp @@ -30,7 +30,9 @@ updateDataThroughVm(benchmark::State& state) "", body, [] { return Fixtures::instance().host(); }, - callsWithinTransferBudget(state.range(0))); + // `set_data` answers a scalar and writes nothing into guest memory, so the + // transfer budget does not constrain it however large the input gets. + callsWithinTransferBudget(0)); state.SetBytesProcessed(state.iterations() * state.range(0)); } BENCHMARK(updateDataThroughVm) From 279ef458c81bb43c9ff5bcccf44125b7fd73b650 Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Tue, 1 Sep 2026 16:06:13 -0400 Subject: [PATCH 18/23] chore: Addressing code review comments --- src/tests/libxrpl/CMakeLists.txt | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/tests/libxrpl/CMakeLists.txt b/src/tests/libxrpl/CMakeLists.txt index ba71939209..915b75251d 100644 --- a/src/tests/libxrpl/CMakeLists.txt +++ b/src/tests/libxrpl/CMakeLists.txt @@ -5,16 +5,6 @@ include(verify_headers) # Test requirements. find_package(GTest REQUIRED) -# The wasm fixtures the test binary and the wasm benchmarks both need: a real genesis -# ledger, the real host built over it, and the WAT assembler. Its own library because -# it links **no test framework** — a benchmark wants a ledger and a host, not GTest's -# lifecycle, and before this existed `xrpl.bench.wasm` had to link GTest and subclass -# `testing::Test` just to reach them. -# -# Only the framework-free half of `tx/wasm/fixtures/` lives here. The GTest half -# (`RealHostFixture`, `FloatFixture`, `NFTFixture`, `MockHostFunctions`, `WasmFixture`, -# `RealVmTest`, `HostContextFixture`) compiles into `xrpl_tests` with the tests, and the -# benchmark harness (`WasmBench`, `BenchFixtures`) into `xrpl.bench.wasm`. add_library( xrpl.testkit.wasm STATIC @@ -25,7 +15,6 @@ add_library( tx/wasm/fixtures/WasmLedger.cpp tx/wasm/fixtures/WasmRun.cpp ) -# Fixtures include their siblings as and . target_include_directories(xrpl.testkit.wasm PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries( xrpl.testkit.wasm @@ -33,8 +22,6 @@ target_link_libraries( ) add_dependencies(xrpl.testkit.wasm xrpl_crates) -# Single combined gtest binary built from the shared test helpers and all test -# modules below. add_executable(xrpl_tests main.cpp) patch_nix_binary(xrpl_tests) set_target_properties( @@ -77,12 +64,6 @@ foreach(module IN LISTS test_modules) "${CMAKE_CURRENT_SOURCE_DIR}/${module}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/${module}.cpp" ) - # Sources under this tree that belong to another target: - # * `*.bench.cpp` and the `WasmBench`/`BenchFixtures` harness -> xrpl.bench.wasm - # * `NftSetup`/`WasmLedger`/`WasmRun` -> xrpl.testkit.wasm, which this binary links - # - # The GTest half of `tx/wasm/fixtures/` (RealHostFixture, HostContextFixture) is not - # excluded: it shares the tests' framework and belongs here. list( FILTER sources EXCLUDE From a1ea8d3a6e96cf0e9e53c931a5d547bc6b997464 Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Wed, 2 Sep 2026 17:03:47 -0400 Subject: [PATCH 19/23] chore: Address review comments --- .cspell.config.yaml | 2 - crates/xrpl-wasm-vm/tests/preflight.rs | 22 ++-- src/benchmarks/libxrpl/CMakeLists.txt | 44 +------ .../libxrpl/wasm}/BenchFixtures.cpp | 2 +- .../libxrpl/wasm}/BenchFixtures.h | 0 .../libxrpl/wasm/Crossing.cpp} | 4 +- src/benchmarks/libxrpl/wasm/README.md | 107 ++++++++++++++++++ .../libxrpl/wasm}/WasmBench.cpp | 4 +- .../libxrpl/wasm}/WasmBench.h | 38 +++++++ .../wasm/host_functions/AccountKeylet.cpp} | 4 +- .../wasm/host_functions/AmmKeylet.cpp} | 4 +- .../libxrpl/wasm/host_functions/BaseFee.cpp} | 4 +- .../wasm/host_functions/CacheLedgerObj.cpp} | 4 +- .../wasm/host_functions/CheckKeylet.cpp} | 4 +- .../wasm/host_functions/CheckSignature.cpp} | 4 +- .../wasm/host_functions/CredentialKeylet.cpp} | 4 +- .../CurrentLedgerObjArrayLen.cpp} | 4 +- .../host_functions/CurrentLedgerObjField.cpp} | 4 +- .../CurrentLedgerObjNestedArrayLen.cpp} | 4 +- .../CurrentLedgerObjNestedField.cpp} | 4 +- .../wasm/host_functions/DelegateKeylet.cpp} | 4 +- .../host_functions/DepositPreauthKeylet.cpp} | 4 +- .../wasm/host_functions/DidKeylet.cpp} | 4 +- .../wasm/host_functions/EscrowKeylet.cpp} | 4 +- .../libxrpl/wasm/host_functions/FloatAdd.cpp} | 4 +- .../wasm/host_functions/FloatCompare.cpp} | 4 +- .../wasm/host_functions/FloatDivide.cpp} | 4 +- .../wasm/host_functions/FloatFromInt.cpp} | 4 +- .../wasm/host_functions/FloatFromMantExp.cpp} | 4 +- .../host_functions/FloatFromStAmount.cpp} | 4 +- .../host_functions/FloatFromStNumber.cpp} | 4 +- .../wasm/host_functions/FloatFromUint.cpp} | 4 +- .../wasm/host_functions/FloatMultiply.cpp} | 4 +- .../wasm/host_functions/FloatPower.cpp} | 4 +- .../wasm/host_functions/FloatSubtract.cpp} | 4 +- .../wasm/host_functions/FloatToInt.cpp} | 4 +- .../wasm/host_functions/FloatToMantExp.cpp} | 4 +- .../libxrpl/wasm/host_functions/GetNFT.cpp} | 2 +- .../host_functions/IsAmendmentEnabled.cpp} | 4 +- .../host_functions/LedgerObjArrayLen.cpp} | 4 +- .../wasm/host_functions/LedgerObjField.cpp} | 4 +- .../LedgerObjNestedArrayLen.cpp} | 4 +- .../host_functions/LedgerObjNestedField.cpp} | 4 +- .../wasm/host_functions/LedgerSqn.cpp} | 4 +- .../host_functions/MptokenIssuanceKeylet.cpp} | 4 +- .../wasm/host_functions/MptokenKeylet.cpp} | 4 +- .../libxrpl/wasm/host_functions/NFTFlags.cpp} | 4 +- .../wasm/host_functions/NFTIssuer.cpp} | 4 +- .../wasm/host_functions/NFTSequence.cpp} | 4 +- .../libxrpl/wasm/host_functions/NFTTaxon.cpp} | 4 +- .../wasm/host_functions/NFTTransferFee.cpp} | 4 +- .../host_functions/NftokenOfferKeylet.cpp} | 4 +- .../wasm/host_functions/OfferKeylet.cpp} | 4 +- .../wasm/host_functions/OracleKeylet.cpp} | 4 +- .../wasm/host_functions/ParentLedgerHash.cpp} | 4 +- .../wasm/host_functions/ParentLedgerTime.cpp} | 4 +- .../wasm/host_functions/PaychannelKeylet.cpp} | 4 +- .../PermissionedDomainedKeylet.cpp} | 4 +- .../wasm/host_functions/Sha512Half.cpp} | 12 +- .../wasm/host_functions/SignerListKeylet.cpp} | 4 +- .../wasm/host_functions/TicketKeylet.cpp} | 4 +- .../libxrpl/wasm/host_functions/Trace.cpp} | 4 +- .../wasm/host_functions/TrustLineKeylet.cpp} | 4 +- .../wasm/host_functions/TxArrayLen.cpp} | 4 +- .../libxrpl/wasm/host_functions/TxField.cpp} | 4 +- .../wasm/host_functions/TxNestedArrayLen.cpp} | 4 +- .../wasm/host_functions/TxNestedField.cpp} | 4 +- .../wasm/host_functions/UpdateData.cpp} | 4 +- .../wasm/host_functions/VaultKeylet.cpp} | 4 +- src/tests/libxrpl/CMakeLists.txt | 13 +-- src/tests/libxrpl/tx/wasm/README.md | 98 +--------------- 71 files changed, 294 insertions(+), 286 deletions(-) rename src/{tests/libxrpl/tx/wasm/fixtures => benchmarks/libxrpl/wasm}/BenchFixtures.cpp (98%) rename src/{tests/libxrpl/tx/wasm/fixtures => benchmarks/libxrpl/wasm}/BenchFixtures.h (100%) rename src/{tests/libxrpl/tx/wasm/Crossing.bench.cpp => benchmarks/libxrpl/wasm/Crossing.cpp} (95%) create mode 100644 src/benchmarks/libxrpl/wasm/README.md rename src/{tests/libxrpl/tx/wasm/fixtures => benchmarks/libxrpl/wasm}/WasmBench.cpp (98%) rename src/{tests/libxrpl/tx/wasm/fixtures => benchmarks/libxrpl/wasm}/WasmBench.h (85%) rename src/{tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/AccountKeylet.cpp} (84%) rename src/{tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/AmmKeylet.cpp} (88%) rename src/{tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp => benchmarks/libxrpl/wasm/host_functions/BaseFee.cpp} (83%) rename src/{tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp => benchmarks/libxrpl/wasm/host_functions/CacheLedgerObj.cpp} (86%) rename src/{tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/CheckKeylet.cpp} (85%) rename src/{tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp => benchmarks/libxrpl/wasm/host_functions/CheckSignature.cpp} (95%) rename src/{tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/CredentialKeylet.cpp} (89%) rename src/{tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp => benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjArrayLen.cpp} (86%) rename src/{tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp => benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjField.cpp} (92%) rename src/{tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp => benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp} (88%) rename src/{tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp => benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjNestedField.cpp} (87%) rename src/{tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/DelegateKeylet.cpp} (86%) rename src/{tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/DepositPreauthKeylet.cpp} (86%) rename src/{tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/DidKeylet.cpp} (84%) rename src/{tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/EscrowKeylet.cpp} (94%) rename src/{tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp => benchmarks/libxrpl/wasm/host_functions/FloatAdd.cpp} (92%) rename src/{tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp => benchmarks/libxrpl/wasm/host_functions/FloatCompare.cpp} (84%) rename src/{tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp => benchmarks/libxrpl/wasm/host_functions/FloatDivide.cpp} (86%) rename src/{tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp => benchmarks/libxrpl/wasm/host_functions/FloatFromInt.cpp} (85%) rename src/{tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp => benchmarks/libxrpl/wasm/host_functions/FloatFromMantExp.cpp} (85%) rename src/{tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp => benchmarks/libxrpl/wasm/host_functions/FloatFromStAmount.cpp} (89%) rename src/{tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp => benchmarks/libxrpl/wasm/host_functions/FloatFromStNumber.cpp} (88%) rename src/{tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp => benchmarks/libxrpl/wasm/host_functions/FloatFromUint.cpp} (85%) rename src/{tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp => benchmarks/libxrpl/wasm/host_functions/FloatMultiply.cpp} (86%) rename src/{tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp => benchmarks/libxrpl/wasm/host_functions/FloatPower.cpp} (92%) rename src/{tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp => benchmarks/libxrpl/wasm/host_functions/FloatSubtract.cpp} (86%) rename src/{tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp => benchmarks/libxrpl/wasm/host_functions/FloatToInt.cpp} (84%) rename src/{tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp => benchmarks/libxrpl/wasm/host_functions/FloatToMantExp.cpp} (92%) rename src/{tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp => benchmarks/libxrpl/wasm/host_functions/GetNFT.cpp} (95%) rename src/{tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp => benchmarks/libxrpl/wasm/host_functions/IsAmendmentEnabled.cpp} (93%) rename src/{tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp => benchmarks/libxrpl/wasm/host_functions/LedgerObjArrayLen.cpp} (85%) rename src/{tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp => benchmarks/libxrpl/wasm/host_functions/LedgerObjField.cpp} (85%) rename src/{tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp => benchmarks/libxrpl/wasm/host_functions/LedgerObjNestedArrayLen.cpp} (87%) rename src/{tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp => benchmarks/libxrpl/wasm/host_functions/LedgerObjNestedField.cpp} (87%) rename src/{tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp => benchmarks/libxrpl/wasm/host_functions/LedgerSqn.cpp} (90%) rename src/{tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/MptokenIssuanceKeylet.cpp} (86%) rename src/{tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/MptokenKeylet.cpp} (87%) rename src/{tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp => benchmarks/libxrpl/wasm/host_functions/NFTFlags.cpp} (84%) rename src/{tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp => benchmarks/libxrpl/wasm/host_functions/NFTIssuer.cpp} (84%) rename src/{tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp => benchmarks/libxrpl/wasm/host_functions/NFTSequence.cpp} (84%) rename src/{tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp => benchmarks/libxrpl/wasm/host_functions/NFTTaxon.cpp} (84%) rename src/{tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp => benchmarks/libxrpl/wasm/host_functions/NFTTransferFee.cpp} (84%) rename src/{tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/NftokenOfferKeylet.cpp} (85%) rename src/{tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/OfferKeylet.cpp} (85%) rename src/{tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/OracleKeylet.cpp} (85%) rename src/{tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp => benchmarks/libxrpl/wasm/host_functions/ParentLedgerHash.cpp} (84%) rename src/{tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp => benchmarks/libxrpl/wasm/host_functions/ParentLedgerTime.cpp} (84%) rename src/{tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/PaychannelKeylet.cpp} (86%) rename src/{tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/PermissionedDomainedKeylet.cpp} (86%) rename src/{tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp => benchmarks/libxrpl/wasm/host_functions/Sha512Half.cpp} (89%) rename src/{tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/SignerListKeylet.cpp} (85%) rename src/{tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/TicketKeylet.cpp} (85%) rename src/{tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp => benchmarks/libxrpl/wasm/host_functions/Trace.cpp} (92%) rename src/{tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/TrustLineKeylet.cpp} (88%) rename src/{tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp => benchmarks/libxrpl/wasm/host_functions/TxArrayLen.cpp} (84%) rename src/{tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp => benchmarks/libxrpl/wasm/host_functions/TxField.cpp} (84%) rename src/{tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp => benchmarks/libxrpl/wasm/host_functions/TxNestedArrayLen.cpp} (86%) rename src/{tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp => benchmarks/libxrpl/wasm/host_functions/TxNestedField.cpp} (94%) rename src/{tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp => benchmarks/libxrpl/wasm/host_functions/UpdateData.cpp} (94%) rename src/{tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp => benchmarks/libxrpl/wasm/host_functions/VaultKeylet.cpp} (85%) diff --git a/.cspell.config.yaml b/.cspell.config.yaml index 348d94da99..4e91dee24f 100644 --- a/.cspell.config.yaml +++ b/.cspell.config.yaml @@ -7,8 +7,6 @@ ignorePaths: - cmake/** - LICENSE.md - .clang-tidy - - src/test/app/wasm_fixtures/**/*.wat - - src/test/app/wasm_fixtures/*.c - nix/check-tools/*.txt # generated, and full of Nix store hashes language: en allowCompoundWords: true # TODO (#6334) diff --git a/crates/xrpl-wasm-vm/tests/preflight.rs b/crates/xrpl-wasm-vm/tests/preflight.rs index e9e65c45e7..46a9bd5450 100644 --- a/crates/xrpl-wasm-vm/tests/preflight.rs +++ b/crates/xrpl-wasm-vm/tests/preflight.rs @@ -594,6 +594,16 @@ fn a_memory64_memory_is_refused_by_screening() { ); } +/// The corruption fixtures below are written as hex strings, which is how the old Beast suite +/// carried them — the bytes are deliberately malformed, so there is nothing to assemble them +/// from. +fn hex(s: &str) -> Vec { + (0..s.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap()) + .collect() +} + /// Malformed modules crafted to abuse the parser rather than merely be invalid — a vector /// length that lies about its size, a section that overruns its payload, a locals-count bomb, /// and a non-terminating LEB128 — are refused at compile like any other garbage. These guard @@ -601,12 +611,6 @@ fn a_memory64_memory_is_refused_by_screening() { /// fixtures); the plainer "bad magic / wrong version" shapes are covered by `garbage_does_not_pass`. #[test] fn parser_abuse_shapes_are_refused() { - fn hex(s: &str) -> Vec { - (0..s.len()) - .step_by(2) - .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap()) - .collect() - } let cases = [ ("vector length lies", "0061736d010000000105ffffffff0f"), ("section overruns its payload", "0061736d01000000010a0160"), @@ -631,12 +635,6 @@ fn parser_abuse_shapes_are_refused() { /// alongside `garbage_does_not_pass`: guards against a wasmi upgrade loosening the validator. #[test] fn structurally_malformed_modules_are_refused() { - fn hex(s: &str) -> Vec { - (0..s.len()) - .step_by(2) - .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap()) - .collect() - } let cases = [ ("corrupt magic number", "0161736d01000000"), ("wrong version", "0061736d02000000"), diff --git a/src/benchmarks/libxrpl/CMakeLists.txt b/src/benchmarks/libxrpl/CMakeLists.txt index 960f55c257..ab3e68b87b 100644 --- a/src/benchmarks/libxrpl/CMakeLists.txt +++ b/src/benchmarks/libxrpl/CMakeLists.txt @@ -21,51 +21,15 @@ xrpl_add_benchmark(nodestore) target_link_libraries(xrpl.bench.nodestore PRIVATE xrpl.imports.bench) add_dependencies(xrpl.benchmarks xrpl.bench.nodestore) -# xrpl.bench.wasm — gas calibration for the wasm host functions. -# -# Each `*.bench.cpp` sits beside the test that covers the same host function, under -# `src/tests/libxrpl/tx/wasm/`, so the two move together. A separate executable keeps -# benchmark runtime off the `ctest` path (the test binary filters `*.bench.cpp` out). -# -# The ledger and host come from `xrpl.testkit.wasm`, which links no test framework — so -# this target links **no GTest and no GMock**, and compiles no test sources of its own -# beyond the benchmark harness. +# Gas calibration for the wasm host functions. The ledger and real host come from +# `xrpl.testkit.wasm` (built with the tests, but framework-free), so this target links +# no GTest and no GMock. if(TARGET xrpl.testkit.wasm) - file( - GLOB_RECURSE wasm_bench_sources - CONFIGURE_DEPENDS - "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/*.bench.cpp" - ) - - add_executable( - xrpl.bench.wasm - ${wasm_bench_sources} - # The benchmark harness. Named without the `.bench.cpp` suffix because it is - # infrastructure rather than a benchmark, so the glob above does not find it and - # `xrpl_tests` excludes it by name. - "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/fixtures/BenchFixtures.cpp" - "${CMAKE_SOURCE_DIR}/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.cpp" - ) - - # Google Benchmark registers cases through static registrars declared in anonymous - # namespaces; merging several such files into one unity translation unit collides - # them. Same reason as `xrpl_add_benchmark`. - # - # The output directory matches too: benchmarks land in the build root beside - # `xrpl_tests`, because they are run by hand and comparing two of them should not - # mean typing two long paths. - set_target_properties( - xrpl.bench.wasm - PROPERTIES - UNITY_BUILD OFF - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" - ) - + xrpl_add_benchmark(wasm) target_link_libraries( xrpl.bench.wasm PRIVATE xrpl.imports.bench xrpl.testkit.wasm ) - add_dependencies(xrpl.benchmarks xrpl.bench.wasm) else() message( diff --git a/src/tests/libxrpl/tx/wasm/fixtures/BenchFixtures.cpp b/src/benchmarks/libxrpl/wasm/BenchFixtures.cpp similarity index 98% rename from src/tests/libxrpl/tx/wasm/fixtures/BenchFixtures.cpp rename to src/benchmarks/libxrpl/wasm/BenchFixtures.cpp index 9a6b2de4db..3eb9c7e35b 100644 --- a/src/tests/libxrpl/tx/wasm/fixtures/BenchFixtures.cpp +++ b/src/benchmarks/libxrpl/wasm/BenchFixtures.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/fixtures/BenchFixtures.h b/src/benchmarks/libxrpl/wasm/BenchFixtures.h similarity index 100% rename from src/tests/libxrpl/tx/wasm/fixtures/BenchFixtures.h rename to src/benchmarks/libxrpl/wasm/BenchFixtures.h diff --git a/src/tests/libxrpl/tx/wasm/Crossing.bench.cpp b/src/benchmarks/libxrpl/wasm/Crossing.cpp similarity index 95% rename from src/tests/libxrpl/tx/wasm/Crossing.bench.cpp rename to src/benchmarks/libxrpl/wasm/Crossing.cpp index 04a93817f8..d764d051b7 100644 --- a/src/tests/libxrpl/tx/wasm/Crossing.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/Crossing.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/benchmarks/libxrpl/wasm/README.md b/src/benchmarks/libxrpl/wasm/README.md new file mode 100644 index 0000000000..e2ffbbf4a6 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/README.md @@ -0,0 +1,107 @@ +# WASM host functions — gas calibration + +These are **not tests**: nothing asserts, and a number moving is not a build failure. They answer +the question the tests cannot — whether each `#[gas = N]` in +`crates/xrpl-host-functions/src/lib.rs` matches what the function actually costs. + +Shared ledger setup is the `Fixtures` type: one ledger, funded once, for the whole binary. + +```bash +cmake --build build --target xrpl.bench.wasm +./build/xrpl.bench.wasm # everything (~2 min) +./build/xrpl.bench.wasm --benchmark_filter=sha512Half +``` + +**Build Release first.** Debug inflates the crossing far more than the impls. Ratios between +`Impl` cases survive Debug; `suggested_gas` does not. + +## Reading the output + +| Counter | Meaning | +| ------------------- | ---------------------------------------------------------------------------------- | +| `suggested_gas` | **the answer** — what this function should be priced at | +| `host_function_gas` | what `lib.rs` says today, read through the `wasm_testkit` bridge so it can't drift | +| `price_ratio` | `host_function_gas / suggested_gas`. **1.0 is correct; below 1 is underpriced** | +| `implied_gas` | the raw measurement, before the crossing is added back | +| `charged_gas` | what the engine actually billed; confirms the right call was measured | +| `ns_per_call` | raw wall time, for debugging a suspicious ratio | + +`price_ratio` is what you sort by. **Below 1 is the direction that matters** — an underpriced call +is one a contract can buy too cheaply, a denial-of-service vector rather than a rounding error: + +```bash +./build/xrpl.bench.wasm --benchmark_format=json | + jq -r '.benchmarks[] | select(.price_ratio) | [.price_ratio, .name] | @tsv' | sort -n +``` + +## How `suggested_gas` is measured + +A wall-clock number cannot be a gas number. The bridge is that **gas is wasmi fuel** — +`set_fuel(gas)` meters guest instructions and host charges from one pool — so one unit of gas is +about one guest instruction, and the question becomes a ratio: _how many guest instructions' worth +of work is this call?_ Every step is a subtraction, so fixed costs cancel: + +``` +secondsPerGas = (time_busy − time_idle) / (fuel_busy − fuel_idle) # a pure-wasm loop, N vs 0 +implied_gas = secondsPerCall / secondsPerGas +crossing_floor = (ldgr_index ThroughVm − ldgr_index Impl) / secondsPerGas + +suggested_gas = implied_gas # ThroughVm — the guest already paid the crossing +suggested_gas = implied_gas + crossing_floor # Impl — a guest cannot call without paying it +price_ratio = host_function_gas / suggested_gas +``` + +`secondsPerCall` is itself a subtraction: a `ThroughVm` case runs a contract making N host calls +against a **byte-identical** one making none, so compilation, instantiation and the guest's own +loop cancel. It is reported per iteration, so Google Benchmark's variance statistics describe the +host call rather than the run containing it. An `Impl` case times `kCallsPerRun` direct calls and +divides. + +**`guestInstruction` is the self-test, and it has a number.** It runs the same loop body the +calibration uses, so its `implied_gas` (wall time) and `charged_gas` (the engine's fuel meter) are +two measurements of one quantity. Release, quiet machine: **≈13.6 against 13.007, ~4% high with +~4% spread.** A persistent gap much beyond that is a harness bug — do not trust any other number +in the run until it is closed. + +That check has already caught a real defect: calibration took a _best-of-N_ while the cases report +a _mean_, which biased every number +40%. Both are means now. **If you change how either side is +estimated, change both.** + +**Two limits.** `suggested_gas` for an `Impl`-only case is a **lower bound** — the crossing floor +is measured on a call with no input, so a function that moves bytes pays more (the swept cases, +`Sha512Half` and `UpdateData`, measure that per-byte term). And `--benchmark_repetitions=N` +averages down noise but will not touch a systematic bias. + +`ThroughVm` cases are deliberately **one per crossing shape, not one per function**: what the +crossing costs depends on a call's shape, not on which function makes it. + +## Gotchas, each of which has already cost someone an afternoon + +- **The wasm ABI is not the trait's argument order.** `float_add(x, y, mode, out)` in Rust is + `(x_ptr, x_len, y_ptr, y_len, out_ptr, out_len, mode)` on the wire — scalars move _after_ the + output region. Check `register.rs`, not `lib.rs`, when writing WAT. +- **A soft host error still "succeeds".** The run completes and gas is charged _before_ the body, + so a wrong-argument case reports a plausible, confidently wrong number. The harness requires the + contract's result to be `>= 0`; the tell is a `ThroughVm` case coming out _faster_ than its `Impl`. +- **A host serves exactly one run** (`checkSelf` in `WasmVM.cpp`), so a benchmark builds a fresh + host per run and cannot pre-cache a slot. +- **`MAX_FIELD_BYTES` is 1024** — nothing crosses the boundary above 1 KiB, so size sweeps stop there. +- **Do not compare timings across builds at the cheap end.** Two builds whose timed regions were + byte-identical measured 2.18 ns and 2.52 ns for the same case — ~15% apart, from code layout + alone. At ~2 ns the cheapest calls are below the resolution of a cross-build comparison; use + `price_ratio` within one run, and reason from the code when deciding whether a change costs + anything. +- Cases pin `->Iterations(...)`: with `UseManualTime`, automatic sizing reads only the tiny reported + residue and would ask for millions of iterations. + +## Layout + +One `.cpp` per host function under `host_functions/`, mirroring +`src/tests/libxrpl/tx/wasm/host_functions/`, so adding a host function is a two-file checklist +rather than a judgement call. `Crossing.cpp` holds the harness's own reference points, +`WasmBench.*` the measurement machinery, `BenchFixtures.*` the shared ledger. + +The ledger and real host come from `xrpl.testkit.wasm` — a framework-free library built alongside +the tests — so this target links **no GTest and no GMock**. See +`src/tests/libxrpl/tx/wasm/README.md` for how that library is split, and why its setup steps throw +rather than using `EXPECT_`. diff --git a/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.cpp b/src/benchmarks/libxrpl/wasm/WasmBench.cpp similarity index 98% rename from src/tests/libxrpl/tx/wasm/fixtures/WasmBench.cpp rename to src/benchmarks/libxrpl/wasm/WasmBench.cpp index c0f877ba17..c0ca253e54 100644 --- a/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.cpp +++ b/src/benchmarks/libxrpl/wasm/WasmBench.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -90,7 +90,7 @@ namespace { // Seconds of wall time one unit of gas buys on this machine. See `Calibration` for why this is // a difference rather than a single measurement. // -// The estimator has to be the *same* one the cases use — a mean over `kBenchIterations` pairs, +// The estimator has to be the *same* one the cases use — a mean over `kCalibrationPairs` pairs, // with the same clamp at zero as `benchmarkThroughVm`. This is not a stylistic point. Since // `implied_gas = secondsPerCall / secondsPerGas`, any systematic difference between how the // divisor and the dividend are estimated lands directly in every reported number. A minimum diff --git a/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.h b/src/benchmarks/libxrpl/wasm/WasmBench.h similarity index 85% rename from src/tests/libxrpl/tx/wasm/fixtures/WasmBench.h rename to src/benchmarks/libxrpl/wasm/WasmBench.h index 281ac5c8a2..6c5762793f 100644 --- a/src/tests/libxrpl/tx/wasm/fixtures/WasmBench.h +++ b/src/benchmarks/libxrpl/wasm/WasmBench.h @@ -213,6 +213,39 @@ benchmarkImpl(benchmark::State& state, std::string_view wasmName, SetUp&& setUp, { auto host = setUp(); + // Confirm the call succeeds — one that errors returns early and is far cheaper than one that + // does the work, so a case with a subtly wrong argument reports a plausible, confidently + // wrong, and always *too low* price. `benchmarkThroughVm` gets this for free from the + // contract's return value; a direct call has no such signal. + // + // Checked on either side of the timed loop rather than inside it. Inside, the branch lands in + // the measurement — worth up to ~13% on the cheapest calls, which run about 2 ns. Outside it + // costs nothing and still catches both failure modes: the *before* probe catches wrong + // arguments, the *after* probe catches a call that stopped working partway through because + // the loop exhausted something. + // + // The `requires` skips host functions that answer nothing (`trace`) or answer a bare value + // rather than an `expected`. + auto const checkSucceeds = [&](char const* when) { + if constexpr (requires { call(*host).has_value(); }) + { + if (auto const probe = call(*host); !probe.has_value()) + { + state.SkipWithError( + std::string{"the benchmarked host call returned error code "} + + std::to_string(static_cast(probe.error())) + " " + when + + " the timed loop; the case would be measuring the rejection path"); + return false; + } + } + return true; + }; + + if (!checkSucceeds("before")) + { + return; + } + auto totalSeconds = 0.0; auto rounds = std::int64_t{0}; for (auto _ : state) @@ -243,6 +276,11 @@ benchmarkImpl(benchmark::State& state, std::string_view wasmName, SetUp&& setUp, ++rounds; } + if (!checkSucceeds("after")) + { + return; + } + // No VM ran, so nothing was charged — and the crossing this case leaves out is added back // into `suggested_gas`, because a guest cannot make the call without paying it. if (rounds > 0) diff --git a/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/AccountKeylet.cpp similarity index 84% rename from src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/AccountKeylet.cpp index 7b2211c3aa..5bd2c7c2e8 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/AccountKeylet.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/AmmKeylet.cpp similarity index 88% rename from src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/AmmKeylet.cpp index 236a2cf8cf..4cefc1c553 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/AmmKeylet.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/BaseFee.cpp similarity index 83% rename from src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/BaseFee.cpp index dd0767262a..b304beeb65 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/BaseFee.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CacheLedgerObj.cpp similarity index 86% rename from src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/CacheLedgerObj.cpp index 9811769e86..b027396d1e 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/CacheLedgerObj.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CheckKeylet.cpp similarity index 85% rename from src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/CheckKeylet.cpp index 2da4c29ec9..24af99a6ac 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/CheckKeylet.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CheckSignature.cpp similarity index 95% rename from src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/CheckSignature.cpp index 4587ad0ee8..af7e333bc7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/CheckSignature.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CredentialKeylet.cpp similarity index 89% rename from src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/CredentialKeylet.cpp index 470505c8ef..219cc9051c 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/CredentialKeylet.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjArrayLen.cpp similarity index 86% rename from src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjArrayLen.cpp index 243ec2c3e4..4678749e84 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjArrayLen.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjField.cpp similarity index 92% rename from src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjField.cpp index 42a41e5705..5a441ffa42 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjField.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp similarity index 88% rename from src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp index 84a6f1f3fa..e2c5d0ab73 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjNestedField.cpp similarity index 87% rename from src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjNestedField.cpp index d12aa6d935..fd0a7f96ed 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjNestedField.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/DelegateKeylet.cpp similarity index 86% rename from src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/DelegateKeylet.cpp index 0b7e02d055..6a66db420a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/DelegateKeylet.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/DepositPreauthKeylet.cpp similarity index 86% rename from src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/DepositPreauthKeylet.cpp index 9f7cae8954..2931669c34 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/DepositPreauthKeylet.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/DidKeylet.cpp similarity index 84% rename from src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/DidKeylet.cpp index 882d23c888..6402bf425a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/DidKeylet.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/EscrowKeylet.cpp similarity index 94% rename from src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/EscrowKeylet.cpp index 8ba2f9a83f..369388fb19 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/EscrowKeylet.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatAdd.cpp similarity index 92% rename from src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/FloatAdd.cpp index 5efc0635a4..e5fb2360f3 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatAdd.cpp @@ -1,7 +1,7 @@ #include -#include +#include +#include #include -#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatCompare.cpp similarity index 84% rename from src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/FloatCompare.cpp index 5c0191f8a1..ea6c68c44f 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatCompare.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatDivide.cpp similarity index 86% rename from src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/FloatDivide.cpp index e070bacad6..bdc802d4bc 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatDivide.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromInt.cpp similarity index 85% rename from src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/FloatFromInt.cpp index 50a13976c6..5edc05d000 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromInt.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromMantExp.cpp similarity index 85% rename from src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/FloatFromMantExp.cpp index cde61b9e47..6f60b16136 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromMantExp.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromStAmount.cpp similarity index 89% rename from src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/FloatFromStAmount.cpp index 107205000e..4cca4f48af 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromStAmount.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromStNumber.cpp similarity index 88% rename from src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/FloatFromStNumber.cpp index c89ae97042..b5081550c9 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromStNumber.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromUint.cpp similarity index 85% rename from src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/FloatFromUint.cpp index dd67a16ad1..ffe04d409f 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromUint.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatMultiply.cpp similarity index 86% rename from src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/FloatMultiply.cpp index 2629123a69..a2bcbbd06a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatMultiply.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatPower.cpp similarity index 92% rename from src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/FloatPower.cpp index a0318f478a..81b5134d2e 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatPower.cpp @@ -1,7 +1,7 @@ #include -#include +#include +#include #include -#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatSubtract.cpp similarity index 86% rename from src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/FloatSubtract.cpp index 8536215b0a..644aada775 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatSubtract.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatToInt.cpp similarity index 84% rename from src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/FloatToInt.cpp index 64e7b3e5af..e8e3179b36 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatToInt.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatToMantExp.cpp similarity index 92% rename from src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/FloatToMantExp.cpp index f59e9346e4..50522b5e5c 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatToMantExp.cpp @@ -1,7 +1,7 @@ #include -#include +#include +#include #include -#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/GetNFT.cpp similarity index 95% rename from src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/GetNFT.cpp index 9cb6305b98..e28addfed0 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/GetNFT.cpp @@ -1,7 +1,7 @@ #include +#include #include -#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/IsAmendmentEnabled.cpp similarity index 93% rename from src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/IsAmendmentEnabled.cpp index 425bc9e284..3fc49c706c 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/IsAmendmentEnabled.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjArrayLen.cpp similarity index 85% rename from src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/LedgerObjArrayLen.cpp index 29a32ae1c4..89b14997da 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjArrayLen.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjField.cpp similarity index 85% rename from src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/LedgerObjField.cpp index fe4b08ea0d..2f707b6cb8 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjField.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjNestedArrayLen.cpp similarity index 87% rename from src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/LedgerObjNestedArrayLen.cpp index 0e264e1b75..b51460e664 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjNestedArrayLen.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjNestedField.cpp similarity index 87% rename from src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/LedgerObjNestedField.cpp index 9e4baf7fc1..757b3118c5 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjNestedField.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/LedgerSqn.cpp similarity index 90% rename from src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/LedgerSqn.cpp index d62ae54989..130cea3cd2 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/LedgerSqn.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/MptokenIssuanceKeylet.cpp similarity index 86% rename from src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/MptokenIssuanceKeylet.cpp index 9d1ec21ce4..bda4c979be 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/MptokenIssuanceKeylet.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/MptokenKeylet.cpp similarity index 87% rename from src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/MptokenKeylet.cpp index 3cd4b8efd9..b1e289181d 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/MptokenKeylet.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/NFTFlags.cpp similarity index 84% rename from src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/NFTFlags.cpp index f279a5b6fd..270f8337fa 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/NFTFlags.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/NFTIssuer.cpp similarity index 84% rename from src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/NFTIssuer.cpp index 38973a970f..bcb960e6ee 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/NFTIssuer.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/NFTSequence.cpp similarity index 84% rename from src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/NFTSequence.cpp index 7299c892cd..f30a8d2348 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/NFTSequence.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/NFTTaxon.cpp similarity index 84% rename from src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/NFTTaxon.cpp index b707ae19d5..8a4bc91790 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/NFTTaxon.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/NFTTransferFee.cpp similarity index 84% rename from src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/NFTTransferFee.cpp index 4e671ec093..c574ccab9d 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/NFTTransferFee.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/NftokenOfferKeylet.cpp similarity index 85% rename from src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/NftokenOfferKeylet.cpp index a3ebd2a3d1..46a3b074a8 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/NftokenOfferKeylet.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/OfferKeylet.cpp similarity index 85% rename from src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/OfferKeylet.cpp index 5204efba4e..7cd61c2b69 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/OfferKeylet.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/OracleKeylet.cpp similarity index 85% rename from src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/OracleKeylet.cpp index c67936dce6..8a7679322c 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/OracleKeylet.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/ParentLedgerHash.cpp similarity index 84% rename from src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/ParentLedgerHash.cpp index ad87abebb9..8f3210d101 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/ParentLedgerHash.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/ParentLedgerTime.cpp similarity index 84% rename from src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/ParentLedgerTime.cpp index e819d5f0e0..fa800c7520 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/ParentLedgerTime.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/PaychannelKeylet.cpp similarity index 86% rename from src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/PaychannelKeylet.cpp index eca8bd6e77..0892fdfbde 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/PaychannelKeylet.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/PermissionedDomainedKeylet.cpp similarity index 86% rename from src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/PermissionedDomainedKeylet.cpp index fdd4aa2bb7..d97d35afba 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/PermissionedDomainedKeylet.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/Sha512Half.cpp similarity index 89% rename from src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/Sha512Half.cpp index 751b1ea8b7..0894956d8e 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/Sha512Half.cpp @@ -1,12 +1,12 @@ #include +#include #include #include -#include -#include +#include +#include #include -#include #include #include @@ -15,8 +15,6 @@ namespace { constexpr std::string_view kWasmName = "sha512_half"; -constexpr std::int16_t kMaxBytes = 1024; - constexpr std::string_view kImport = R"( (import "host_lib" "sha512_half" (func $sha512_half (param i32 i32 i32 i32) (result i32))) )"; @@ -44,7 +42,7 @@ sha512HalfThroughVm(benchmark::State& state) } BENCHMARK(sha512HalfThroughVm) ->RangeMultiplier(8) - ->Range(8, kMaxBytes) + ->Range(8, xrpl::kMaxWasmDataLength) ->UseManualTime() ->Iterations(kBenchIterations); @@ -63,7 +61,7 @@ sha512HalfImpl(benchmark::State& state) } BENCHMARK(sha512HalfImpl) ->RangeMultiplier(8) - ->Range(8, kMaxBytes) + ->Range(8, xrpl::kMaxWasmDataLength) ->UseManualTime() ->Iterations(kBenchIterations); diff --git a/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/SignerListKeylet.cpp similarity index 85% rename from src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/SignerListKeylet.cpp index 8f42df0d8a..0764bd140c 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/SignerListKeylet.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/TicketKeylet.cpp similarity index 85% rename from src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/TicketKeylet.cpp index 4901206ef7..78791a7d2c 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/TicketKeylet.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/Trace.cpp similarity index 92% rename from src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/Trace.cpp index 9fc702f9fa..c0eec7a2d6 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/Trace.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/Trace.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/TrustLineKeylet.cpp similarity index 88% rename from src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/TrustLineKeylet.cpp index 660e242cb7..ffb09dc65c 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/TrustLineKeylet.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/TxArrayLen.cpp similarity index 84% rename from src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/TxArrayLen.cpp index e8ff9724d1..a4b1b94811 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/TxArrayLen.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/TxField.cpp similarity index 84% rename from src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/TxField.cpp index 5f61724156..afe0dcaf8d 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxField.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/TxField.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/TxNestedArrayLen.cpp similarity index 86% rename from src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/TxNestedArrayLen.cpp index 92d8a60562..de7b4d4a4a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/TxNestedArrayLen.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/TxNestedField.cpp similarity index 94% rename from src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/TxNestedField.cpp index 817522eeac..3707a55ee7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/TxNestedField.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/UpdateData.cpp similarity index 94% rename from src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/UpdateData.cpp index fca836bd3b..0cc8a19249 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/UpdateData.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp b/src/benchmarks/libxrpl/wasm/host_functions/VaultKeylet.cpp similarity index 85% rename from src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp rename to src/benchmarks/libxrpl/wasm/host_functions/VaultKeylet.cpp index 22ba8dc7aa..32b7feabac 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.bench.cpp +++ b/src/benchmarks/libxrpl/wasm/host_functions/VaultKeylet.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/CMakeLists.txt b/src/tests/libxrpl/CMakeLists.txt index 915b75251d..f8c53e02bd 100644 --- a/src/tests/libxrpl/CMakeLists.txt +++ b/src/tests/libxrpl/CMakeLists.txt @@ -64,11 +64,12 @@ foreach(module IN LISTS test_modules) "${CMAKE_CURRENT_SOURCE_DIR}/${module}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/${module}.cpp" ) + # The framework-free half of tx/wasm/fixtures/ is compiled into xrpl.testkit.wasm, + # which this binary links; the rest of that folder belongs here. list( FILTER sources EXCLUDE - REGEX - "\\.bench\\.cpp$|/fixtures/(WasmBench|BenchFixtures|NftSetup|WasmLedger|WasmRun)\\.cpp$" + REGEX "/fixtures/(NftSetup|WasmLedger|WasmRun)\\.cpp$" ) target_sources(xrpl_tests PRIVATE ${sources}) @@ -91,14 +92,6 @@ file( ) target_sources(xrpl_tests PRIVATE ${csf_sources}) -if(benchmark AND TARGET benchmark::benchmark) - target_include_directories( - xrpl_tests - PRIVATE - $ - ) -endif() - # The test helpers and per-module test headers are not built with add_module, # so verify them against the test binary's own compile environment. if(verify_headers) diff --git a/src/tests/libxrpl/tx/wasm/README.md b/src/tests/libxrpl/tx/wasm/README.md index 31bcb11f23..ed1621c8aa 100644 --- a/src/tests/libxrpl/tx/wasm/README.md +++ b/src/tests/libxrpl/tx/wasm/README.md @@ -20,7 +20,7 @@ Run the C++ side with: ./build/xrpl_tests --gtest_filter='*Impl.*:*Call.*:*E2e.*:WasmVMTest.*:WasmVMDeathTest.*:PreflightTest.*' ``` -(720 tests, 138 suites.) The engine-level coverage is Rust: `cd crates && cargo test`. +(707 tests, 136 suites.) The engine-level coverage is Rust: `cd crates && cargo test`. ## `fixtures/` — split by whether it needs a test framework @@ -28,7 +28,6 @@ Run the C++ side with: | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **No GTest** — the `xrpl.testkit.wasm` library | `WasmLedger` (real genesis ledger + the real host over it), `WasmRun` (WAT assembler), `NftSetup`, `FloatConstants` | | **GTest** → `xrpl_tests` | `RealHostFixture` (`: testing::Test, WasmLedger` + `expectValue`/`expectError`/`expectKeyletMatches`), `FloatFixture`, `NFTFixture`, `MockHostFunctions`, `WasmFixture`, `RealVmTest`, `HostContextFixture` | -| **Benchmark harness** → `xrpl.bench.wasm` | `WasmBench`, `BenchFixtures` | A benchmark wants a ledger and a host, not GTest's lifecycle. Both binaries link the library; `xrpl.bench.wasm` links no GTest and no GMock at all. @@ -38,98 +37,11 @@ Not stylistic: an `EXPECT_` outside a running test is recorded and discarded, so escrow was never created would still run its host call, take the not-found path, and report a cheap, plausible, completely wrong price. **If you add a setup step that can fail, throw.** -## `*.bench.cpp` — gas calibration +## Gas calibration -Not tests: nothing asserts, and a number moving is not a build failure. They answer the question -the tests cannot — whether each `#[gas = N]` in `crates/xrpl-host-functions/src/lib.rs` matches -what the function costs. - -One `.bench.cpp` per host function, named after its test, so adding a function is a two-file -checklist rather than a judgement call. Shared ledger setup is the `Fixtures` type — one ledger, -funded once, for the whole binary. - -```bash -cmake --build build --target xrpl.bench.wasm -./build/xrpl.bench.wasm # everything (~2 min) -./build/xrpl.bench.wasm --benchmark_filter=sha512Half -``` - -**Build Release first.** Debug inflates the crossing far more than the impls. Ratios between -`Impl` cases survive Debug; `suggested_gas` does not. - -### Reading the output - -| Counter | Meaning | -| ------------------- | ---------------------------------------------------------------------------------- | -| `suggested_gas` | **the answer** — what this function should be priced at | -| `host_function_gas` | what `lib.rs` says today, read through the `wasm_testkit` bridge so it can't drift | -| `price_ratio` | `host_function_gas / suggested_gas`. **1.0 is correct; below 1 is underpriced** | -| `implied_gas` | the raw measurement, before the crossing is added back | -| `charged_gas` | what the engine actually billed; confirms the right call was measured | -| `ns_per_call` | raw wall time, for debugging a suspicious ratio | - -`price_ratio` is what you sort by. **Below 1 is the direction that matters** — an underpriced call -is one a contract can buy too cheaply, a denial-of-service vector rather than a rounding error: - -```bash -./build/xrpl.bench.wasm --benchmark_format=json | - jq -r '.benchmarks[] | select(.price_ratio) | [.price_ratio, .name] | @tsv' | sort -n -``` - -### How `suggested_gas` is measured - -A wall-clock number cannot be a gas number. The bridge is that **gas is wasmi fuel** — -`set_fuel(gas)` meters guest instructions and host charges from one pool — so one unit of gas is -about one guest instruction, and the question becomes a ratio: _how many guest instructions' worth -of work is this call?_ Every step is a subtraction, so fixed costs cancel: - -``` -secondsPerGas = (time_busy − time_idle) / (fuel_busy − fuel_idle) # a pure-wasm loop, N vs 0 -implied_gas = secondsPerCall / secondsPerGas -crossing_floor = (ldgr_index ThroughVm − ldgr_index Impl) / secondsPerGas - -suggested_gas = implied_gas # ThroughVm — the guest already paid the crossing -suggested_gas = implied_gas + crossing_floor # Impl — a guest cannot call without paying it -price_ratio = host_function_gas / suggested_gas -``` - -`secondsPerCall` is itself a subtraction: a `ThroughVm` case runs a contract making N host calls -against a **byte-identical** one making none, so compilation, instantiation and the guest's own -loop cancel. It is reported per iteration, so Google Benchmark's variance statistics describe the -host call rather than the run containing it. An `Impl` case times `kCallsPerRun` direct calls and -divides. - -**`guestInstruction` is the self-test, and it has a number.** It runs the same loop body the -calibration uses, so its `implied_gas` (wall time) and `charged_gas` (the engine's fuel meter) are -two measurements of one quantity. Release, quiet machine: **≈13.6 against 13.007, ~4% high with -~4% spread.** A persistent gap much beyond that is a harness bug — do not trust any other number -in the run until it is closed. - -That check has already caught a real defect: calibration took a _best-of-N_ while the cases report -a _mean_, which biased every number +40%. Both are means now. **If you change how either side is -estimated, change both.** - -**Two limits.** `suggested_gas` for an `Impl`-only case is a **lower bound** — the crossing floor -is measured on a call with no input, so a function that moves bytes pays more (the swept cases, -`Sha512Half` and `UpdateData`, measure that per-byte term). And `--benchmark_repetitions=N` -averages down noise but will not touch a systematic bias. - -`ThroughVm` cases are deliberately **one per crossing shape, not one per function**: what the -crossing costs depends on a call's shape, not on which function makes it. - -### Gotchas, each of which has already cost someone an afternoon - -- **The wasm ABI is not the trait's argument order.** `float_add(x, y, mode, out)` in Rust is - `(x_ptr, x_len, y_ptr, y_len, out_ptr, out_len, mode)` on the wire — scalars move _after_ the - output region. Check `register.rs`, not `lib.rs`, when writing WAT. -- **A soft host error still "succeeds".** The run completes and gas is charged _before_ the body, - so a wrong-argument case reports a plausible, confidently wrong number. The harness requires the - contract's result to be `>= 0`; the tell is a `ThroughVm` case coming out _faster_ than its `Impl`. -- **A host serves exactly one run** (`checkSelf` in `WasmVM.cpp`), so a benchmark builds a fresh - host per run and cannot pre-cache a slot. -- **`MAX_FIELD_BYTES` is 1024** — nothing crosses the boundary above 1 KiB, so size sweeps stop there. -- Cases pin `->Iterations(...)`: with `UseManualTime`, automatic sizing reads only the tiny reported - residue and would ask for millions of iterations. +The benchmarks that price these host functions live in `src/benchmarks/libxrpl/wasm/`, mirroring +this tree one file per function, and have their own README. They link `xrpl.testkit.wasm` (above) +for the ledger and host, and no test framework. ## What `e2e/` covers — the rule From 422b8d0a432b340e799374454c44da8841cf0be7 Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Wed, 2 Sep 2026 18:49:20 -0400 Subject: [PATCH 20/23] chore: Address review comments --- .github/scripts/levelization/results/ordering.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/scripts/levelization/results/ordering.txt b/.github/scripts/levelization/results/ordering.txt index 5577c363fd..e8ccb8a290 100644 --- a/.github/scripts/levelization/results/ordering.txt +++ b/.github/scripts/levelization/results/ordering.txt @@ -1,6 +1,9 @@ benchmarks.libxrpl > xrpl.basics benchmarks.libxrpl > xrpl.config benchmarks.libxrpl > xrpl.nodestore +benchmarks.libxrpl > xrpl.protocol +benchmarks.libxrpl > xrpl.protocol_autogen +benchmarks.libxrpl > xrpl.tx libxrpl.basics > xrpl.basics libxrpl.conditions > xrpl.basics libxrpl.conditions > xrpl.conditions From 491b930ebb1f2a70399cab6aec7f95ecfb2f5d31 Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Thu, 3 Sep 2026 12:08:40 -0400 Subject: [PATCH 21/23] chore: Make Calibration type a non singleton --- src/benchmarks/libxrpl/wasm/WasmBench.cpp | 13 +++---------- src/benchmarks/libxrpl/wasm/WasmBench.h | 7 +------ 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/benchmarks/libxrpl/wasm/WasmBench.cpp b/src/benchmarks/libxrpl/wasm/WasmBench.cpp index c0ca253e54..423e1291b9 100644 --- a/src/benchmarks/libxrpl/wasm/WasmBench.cpp +++ b/src/benchmarks/libxrpl/wasm/WasmBench.cpp @@ -195,13 +195,6 @@ Calibration::Calibration() { } -Calibration const& -Calibration::instance() -{ - static Calibration const kValue; - return kValue; -} - double declaredGas(std::string_view wasmName) { @@ -217,10 +210,10 @@ report( std::string_view wasmName, bool throughVm) { - auto const perGas = Calibration::instance().secondsPerGas(); + auto calibration = Calibration{}; + auto const perGas = calibration.secondsPerGas(); auto const implied = perGas > 0.0 ? secondsPerCall / perGas : 0.0; - auto const suggested = - throughVm ? implied : implied + Calibration::instance().crossingFloorGas(); + auto const suggested = throughVm ? implied : implied + calibration.crossingFloorGas(); state.counters["implied_gas"] = implied; state.counters["ns_per_call"] = secondsPerCall * 1e9; diff --git a/src/benchmarks/libxrpl/wasm/WasmBench.h b/src/benchmarks/libxrpl/wasm/WasmBench.h index 6c5762793f..3caa7a02f6 100644 --- a/src/benchmarks/libxrpl/wasm/WasmBench.h +++ b/src/benchmarks/libxrpl/wasm/WasmBench.h @@ -94,10 +94,7 @@ timeRun(HostFunctions& host, Bytes const& wasm); class Calibration { public: - // The machine's calibration, measured on first use. Measuring runs a few hundred short - // contracts, so the first case to ask pays for it and every later case reads this answer. - static Calibration const& - instance(); + Calibration(); // Seconds of wall time one unit of gas buys here. [[nodiscard]] double @@ -115,8 +112,6 @@ public: } private: - Calibration(); - double secondsPerGas_{}; double crossingFloorGas_{}; }; From 4208f14a91b1e87fe1bc396db321405c3e2299a8 Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Thu, 3 Sep 2026 20:47:09 -0400 Subject: [PATCH 22/23] fix: Add additional vm benchmarks --- src/benchmarks/libxrpl/wasm/README.md | 154 ++++++++++---- src/benchmarks/libxrpl/wasm/Vm.cpp | 149 +++++++++++++ src/benchmarks/libxrpl/wasm/WasmBench.cpp | 232 +++++++++++++++++--- src/benchmarks/libxrpl/wasm/WasmBench.h | 244 +++++++++++++++------- 4 files changed, 624 insertions(+), 155 deletions(-) create mode 100644 src/benchmarks/libxrpl/wasm/Vm.cpp diff --git a/src/benchmarks/libxrpl/wasm/README.md b/src/benchmarks/libxrpl/wasm/README.md index e2ffbbf4a6..e50afdec01 100644 --- a/src/benchmarks/libxrpl/wasm/README.md +++ b/src/benchmarks/libxrpl/wasm/README.md @@ -4,16 +4,15 @@ These are **not tests**: nothing asserts, and a number moving is not a build fai the question the tests cannot — whether each `#[gas = N]` in `crates/xrpl-host-functions/src/lib.rs` matches what the function actually costs. -Shared ledger setup is the `Fixtures` type: one ledger, funded once, for the whole binary. - ```bash cmake --build build --target xrpl.bench.wasm ./build/xrpl.bench.wasm # everything (~2 min) ./build/xrpl.bench.wasm --benchmark_filter=sha512Half +./build/xrpl.bench.wasm --benchmark_repetitions=25 --benchmark_report_aggregates_only=true ``` -**Build Release first.** Debug inflates the crossing far more than the impls. Ratios between -`Impl` cases survive Debug; `suggested_gas` does not. +**Build Release.** Debug inflates the crossing far more than the impls: `Impl`-to-`Impl` ratios +survive it, `suggested_gas` does not. ## Reading the output @@ -22,84 +21,159 @@ cmake --build build --target xrpl.bench.wasm | `suggested_gas` | **the answer** — what this function should be priced at | | `host_function_gas` | what `lib.rs` says today, read through the `wasm_testkit` bridge so it can't drift | | `price_ratio` | `host_function_gas / suggested_gas`. **1.0 is correct; below 1 is underpriced** | +| `rel_error` | relative uncertainty of `suggested_gas`. **Quote this one** — ~1.2% when quiet | +| `unreliable` | `1` means do not act on this row | | `implied_gas` | the raw measurement, before the crossing is added back | | `charged_gas` | what the engine actually billed; confirms the right call was measured | | `ns_per_call` | raw wall time, for debugging a suspicious ratio | -`price_ratio` is what you sort by. **Below 1 is the direction that matters** — an underpriced call -is one a contract can buy too cheaply, a denial-of-service vector rather than a rounding error: +Sort by `price_ratio`. **Below 1 is the direction that matters** — an underpriced call is one a +contract can buy too cheaply, a denial-of-service vector rather than a rounding error: ```bash ./build/xrpl.bench.wasm --benchmark_format=json | jq -r '.benchmarks[] | select(.price_ratio) | [.price_ratio, .name] | @tsv' | sort -n ``` +`unreliable=1` when `rel_error` exceeds 25%, or when `suggested_gas` falls below the crossing floor +— a call whose own cost is small next to the crossing is read off the difference of two nearly +equal numbers. + +### With `--benchmark_repetitions` + +Adds `_mean` / `_median` / `_stddev` / `_cv` rows. One trap worth knowing: + +**`cv` on `suggested_gas` for an `Impl` case is not an error bar.** The crossing floor is measured +once per process, so repetitions never resample it — and it is most of a cheap `Impl` case's value. +Over 25 repetitions on an idle machine, `Impl` `cv` reads **1.3%** against `ThroughVm`'s 2.3%, while +`rel_error` is 1.2% for both. The lowest number in the output is the least trustworthy one. + +Use repetitions to confirm the machine is quiet and to get a median; quote `rel_error`. Under load +the `Impl` cases inflate first (3.0% against 1.8% at load ~10), which makes the gap between the two +families a usable load detector. + ## How `suggested_gas` is measured -A wall-clock number cannot be a gas number. The bridge is that **gas is wasmi fuel** — -`set_fuel(gas)` meters guest instructions and host charges from one pool — so one unit of gas is -about one guest instruction, and the question becomes a ratio: _how many guest instructions' worth -of work is this call?_ Every step is a subtraction, so fixed costs cancel: +Gas is wasmi fuel — `set_fuel(gas)` meters guest instructions and host charges from one pool — so +one gas is about one guest instruction and the question becomes a ratio. Every step is a +subtraction, so fixed costs cancel: ``` -secondsPerGas = (time_busy − time_idle) / (fuel_busy − fuel_idle) # a pure-wasm loop, N vs 0 +secondsPerGas = (time_busy − time_idle) / (fuel_busy − fuel_idle) # pure-wasm loop, N vs 0 implied_gas = secondsPerCall / secondsPerGas crossing_floor = (ldgr_index ThroughVm − ldgr_index Impl) / secondsPerGas suggested_gas = implied_gas # ThroughVm — the guest already paid the crossing suggested_gas = implied_gas + crossing_floor # Impl — a guest cannot call without paying it price_ratio = host_function_gas / suggested_gas + +rel_error = sqrt( ( sqrt((implied·caseErr)² + (floor·floorErr)²) / suggested )² + perGasErr² ) ``` `secondsPerCall` is itself a subtraction: a `ThroughVm` case runs a contract making N host calls -against a **byte-identical** one making none, so compilation, instantiation and the guest's own -loop cancel. It is reported per iteration, so Google Benchmark's variance statistics describe the -host call rather than the run containing it. An `Impl` case times `kCallsPerRun` direct calls and -divides. +against a **byte-identical** one making none, so compilation, instantiation and the guest's own loop +cancel. An `Impl` case times `kCallsPerRun` direct calls and divides. -**`guestInstruction` is the self-test, and it has a number.** It runs the same loop body the -calibration uses, so its `implied_gas` (wall time) and `charged_gas` (the engine's fuel meter) are -two measurements of one quantity. Release, quiet machine: **≈13.6 against 13.007, ~4% high with -~4% spread.** A persistent gap much beyond that is a harness bug — do not trust any other number -in the run until it is closed. +`secondsPerGas` is measured **once** and shared by every case, deliberately — two routes to the same +price must divide by the same constant, and per-case calibration was tried and swung 6x between +runs. Its uncertainty is propagated arithmetically instead. See the comments in `WasmBench.cpp` for +why the three terms in `rel_error` do not all combine in quadrature. -That check has already caught a real defect: calibration took a _best-of-N_ while the cases report -a _mean_, which biased every number +40%. Both are means now. **If you change how either side is -estimated, change both.** +**`guestInstruction` is the self-test — read it first.** It runs the calibration's own loop body, so +its `implied_gas` (wall time) and `charged_gas` (the fuel meter) are two independent measurements of +one quantity. Quiet Release machine: **≈13.7 against 13.007, ~5% high.** A persistent gap much +beyond that means every other number in the run shares it. It has already caught an estimator +mismatch worth +40%, and the memory leak below. -**Two limits.** `suggested_gas` for an `Impl`-only case is a **lower bound** — the crossing floor -is measured on a call with no input, so a function that moves bytes pays more (the swept cases, -`Sha512Half` and `UpdateData`, measure that per-byte term). And `--benchmark_repetitions=N` -averages down noise but will not touch a systematic bias. +**`suggested_gas` for an `Impl`-only case is a lower bound** — the crossing floor is measured on a +call with no input, so a function that moves bytes pays more; `Sha512Half` and `UpdateData` sweep +that per-byte term. `ThroughVm` cases are deliberately one per crossing _shape_, not one per +function. -`ThroughVm` cases are deliberately **one per crossing shape, not one per function**: what the -crossing costs depends on a call's shape, not on which function makes it. +## VM overhead (`Vm.cpp`) + +Everything above prices what a contract _asks for_. `Vm.cpp` prices getting it running at all. Of +the seven stages `runEscrowWasm` performs — compile, store, linker, instantiate, entry-point lookup, +call, fuel read — **only the call is metered**; the rest is wall time no transaction pays for. + +These cases report `ns_per_op` and `gas_equivalent` (that time over the same `secondsPerGas`, so an +unpriced stage reads on the same axis as a priced one), plus `module_bytes` and `gas_per_byte` on +size sweeps. + +| case | measures | +| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | +| `preflightMinimal` | compile plus the import/export walk. The narrowest view of compilation reachable from C++: no host, no instance | +| `preflightRejects` | the same on a module refused at the import walk. Against `preflightMinimal`, what refusing costs versus accepting | +| `runMinimal` | a whole run of a do-nothing contract — every stage. Minus `preflightMinimal`, the stages that are not compilation | +| `compileScaling/N` | compilation against module size: `N` unreachable filler functions, preflight only | +| `runScaling/N` | the same modules through a whole run. Paired with `compileScaling` per size, separates size-dependent stages from fixed ones | +| `instantiateScaling/pages` | declared memory at constant module size, so what moves is the host allocating and zeroing pages | + +Two of those pairings are the point of the file. `runMinimal − preflightMinimal` gives the fixed +cost of everything that is not compilation; `runScaling` against `compileScaling` shows compilation +appearing a second time, because the transactor validates and executes with no module cache between +them. The size sweeps matter more than the floor: a fixed cost is only a griefing concern if it is +large, but a slope against attacker-chosen module size is one at any height. + +Two caveats when reading a sweep. `gas_per_byte` is an **average** carrying the case's fixed cost, +not a marginal rate — it overestimates, and falls toward the true slope as the module grows, so read +the convergence rather than any single row. And the `/4096` points get few iterations and go noisy +first; compare `rel_error` across the sweep before quoting the largest one. + +The sweep stops at 4096 functions for want of a real cap to stop at — no maximum contract size is +enforced anywhere yet, the transactor not being wired. + +The linker rebuild and the fuel-metering overhead are **not** separable from here — C++ sees only +`runEscrowWasm` and `preflightEscrowWasm`. Both need benchmarks inside `xrpl-wasm-vm`, where +`compile` and `wasm_engine` are `pub(crate)`. + +### Compiling leaks — pin your iteration counts + +`wasm_engine()` is a process-global `LazyLock`, and what `Module::new` adds to it is never +released. Repeatedly preflighting one **60-byte** module: + +| `--benchmark_repetitions` | peak RSS | +| ------------------------- | -------- | +| 1 | 0.41 GB | +| 5 | 1.46 GB | +| 15 | 4.20 GB | + +Linear, at roughly **800 bytes per compile**. Within the suite this is why every `Vm.cpp` case pins +`->Iterations(...)`: automatic sizing ran `preflightMinimal` ~348k times per repetition, reaching +7.9 GB at 25 repetitions, after which every later case in the binary failed to compile — 720 errored +rows, all blaming cases that were innocent. + +**Outside the suite it is worth a look.** A validator compiles twice per programmable-escrow +transaction against that same static engine. Whether that is unbounded growth in production depends +on wasmi internals not checked here — this is the C++-visible symptom, not a diagnosis. wasmi is +pinned at `2.0.0-beta.10`, a beta, so try a version bump first. ## Gotchas, each of which has already cost someone an afternoon - **The wasm ABI is not the trait's argument order.** `float_add(x, y, mode, out)` in Rust is `(x_ptr, x_len, y_ptr, y_len, out_ptr, out_len, mode)` on the wire — scalars move _after_ the output region. Check `register.rs`, not `lib.rs`, when writing WAT. -- **A soft host error still "succeeds".** The run completes and gas is charged _before_ the body, - so a wrong-argument case reports a plausible, confidently wrong number. The harness requires the +- **A soft host error still "succeeds".** The run completes and gas is charged _before_ the body, so + a wrong-argument case reports a plausible, confidently wrong number. The harness requires the contract's result to be `>= 0`; the tell is a `ThroughVm` case coming out _faster_ than its `Impl`. -- **A host serves exactly one run** (`checkSelf` in `WasmVM.cpp`), so a benchmark builds a fresh - host per run and cannot pre-cache a slot. +- **A host serves exactly one run** (`checkSelf` in `WasmVM.cpp`), so a benchmark builds a fresh host + per run and cannot pre-cache a slot. - **`MAX_FIELD_BYTES` is 1024** — nothing crosses the boundary above 1 KiB, so size sweeps stop there. - **Do not compare timings across builds at the cheap end.** Two builds whose timed regions were - byte-identical measured 2.18 ns and 2.52 ns for the same case — ~15% apart, from code layout - alone. At ~2 ns the cheapest calls are below the resolution of a cross-build comparison; use - `price_ratio` within one run, and reason from the code when deciding whether a change costs + byte-identical measured 2.18 ns and 2.52 ns for the same case — ~15% apart, from code layout alone. + Use `price_ratio` within one run, and reason from the code when judging whether a change costs anything. -- Cases pin `->Iterations(...)`: with `UseManualTime`, automatic sizing reads only the tiny reported - residue and would ask for millions of iterations. +- **Every case pins `->Iterations(...)`, for two different reasons.** Host-function cases must + because with `UseManualTime` automatic sizing reads only the tiny reported residue and would ask + for millions of iterations; `Vm.cpp` cases must because compiling leaks. ## Layout One `.cpp` per host function under `host_functions/`, mirroring `src/tests/libxrpl/tx/wasm/host_functions/`, so adding a host function is a two-file checklist -rather than a judgement call. `Crossing.cpp` holds the harness's own reference points, -`WasmBench.*` the measurement machinery, `BenchFixtures.*` the shared ledger. +rather than a judgement call. `Crossing.cpp` holds the harness's own reference points, `Vm.cpp` the +per-run overhead around them, `WasmBench.*` the measurement machinery, `BenchFixtures.*` the shared +ledger (one ledger, funded once, for the whole binary). The ledger and real host come from `xrpl.testkit.wasm` — a framework-free library built alongside the tests — so this target links **no GTest and no GMock**. See diff --git a/src/benchmarks/libxrpl/wasm/Vm.cpp b/src/benchmarks/libxrpl/wasm/Vm.cpp new file mode 100644 index 0000000000..dd5ec2e420 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/Vm.cpp @@ -0,0 +1,149 @@ +#include +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test::bench { +namespace { + +// What a run costs *around* the contract, rather than what its host calls cost. Only the guest's +// own execution is metered, so every stage measured here is wall time no transaction pays for. +// ../README.md has what each case measures and how to read `gas_equivalent`. +// +// **Every case must pin `->Iterations(...)`.** Compiling a module allocates against the +// process-global engine and is never reclaimed — roughly 800 bytes per compile — so Google +// Benchmark's automatic sizing, which targets a wall-clock budget rather than a compile count, +// reaches gigabytes resident and the whole binary stops being able to compile anything. + +// The smallest module the engine accepts. Everything a run does to it is overhead by construction. +std::string +minimalWat() +{ + return R"wat((module + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (i32.const 1))) +)wat"; +} + +// `count` unreachable functions on top of the minimal module: bigger without doing more. +// +// Each body is seeded with its own index so no two are identical and none folds to a constant the +// translator can drop — either would break the link between function count and byte count. +// Unreachable is fine: validation and translation visit every function a module declares, and that +// visit is exactly the cost being swept. +std::string +fillerWat(size_t count) +{ + auto out = std::string{"(module\n (memory (export \"memory\") 1)\n"}; + for (auto i = 0uz; i < count; ++i) + { + out += std::format( + " (func $f{0} (param i32) (result i32)\n" + " (i32.add (i32.mul (local.get 0) (i32.const {0})) (i32.const {0})))\n", + i); + } + out += " (func (export \"escrow_finish\") (result i32)\n (i32.const 1)))\n"; + return out; +} + +// The minimal module asking for `pages` of initial memory. `MAX_MEMORY_PAGES` is 128 (8 MiB), and a +// contract declares this for free — the host allocates and zeroes it before the first instruction. +std::string +pagesWat(size_t pages) +{ + return std::format( + "(module\n" + " (memory (export \"memory\") {})\n" + " (func (export \"escrow_finish\") (result i32)\n" + " (i32.const 1)))\n", + pages); +} + +// Compiles cleanly and is then refused: `env::malloc` is not a namespace the engine serves, so +// `check_imports` stops at it. +std::string +rejectedWat() +{ + return R"wat((module + (import "env" "malloc" (func $malloc (param i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (i32.const 1))) +)wat"; +} + +void +preflightMinimal(benchmark::State& state) +{ + static auto const kWasm = assembleWat(minimalWat()); + benchmarkPreflight(state, kWasm); +} +BENCHMARK(preflightMinimal)->UseManualTime()->Iterations(kBenchIterations); + +void +preflightRejects(benchmark::State& state) +{ + static auto const kWasm = assembleWat(rejectedWat()); + benchmarkPreflight(state, kWasm, /*expectAccepted*/ false); +} +BENCHMARK(preflightRejects)->UseManualTime()->Iterations(kBenchIterations); + +void +runMinimal(benchmark::State& state) +{ + static auto const kWasm = assembleWat(minimalWat()); + benchmarkRun(state, kWasm, [] { return Fixtures::instance().host(); }); +} +BENCHMARK(runMinimal)->UseManualTime()->Iterations(kBenchIterations); + +void +compileScaling(benchmark::State& state) +{ + auto const wasm = assembleWat(fillerWat(static_cast(state.range(0)))); + benchmarkPreflight(state, wasm, /*expectAccepted*/ true, /*sizeSweep*/ true); +} +BENCHMARK(compileScaling) + ->UseManualTime() + ->Iterations(kBenchIterations) + ->Arg(1) + ->Arg(8) + ->Arg(64) + ->Arg(512) + ->Arg(4096); + +void +runScaling(benchmark::State& state) +{ + auto const wasm = assembleWat(fillerWat(static_cast(state.range(0)))); + benchmarkRun(state, wasm, [] { return Fixtures::instance().host(); }, /*sizeSweep*/ true); +} +BENCHMARK(runScaling) + ->UseManualTime() + ->Iterations(kBenchIterations) + ->Arg(1) + ->Arg(8) + ->Arg(64) + ->Arg(512) + ->Arg(4096); + +void +instantiateScaling(benchmark::State& state) +{ + auto const wasm = assembleWat(pagesWat(static_cast(state.range(0)))); + benchmarkRun(state, wasm, [] { return Fixtures::instance().host(); }); +} +BENCHMARK(instantiateScaling) + ->UseManualTime() + ->Iterations(kBenchIterations) + ->Arg(1) + ->Arg(8) + ->Arg(32) + ->Arg(128); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/WasmBench.cpp b/src/benchmarks/libxrpl/wasm/WasmBench.cpp index 423e1291b9..e5975f2403 100644 --- a/src/benchmarks/libxrpl/wasm/WasmBench.cpp +++ b/src/benchmarks/libxrpl/wasm/WasmBench.cpp @@ -1,5 +1,7 @@ #include +#include +#include #include #include #include @@ -12,6 +14,7 @@ #include #include +#include #include #include #include @@ -23,7 +26,7 @@ namespace xrpl::test::bench { int callsWithinTransferBudget(std::int64_t bytesWrittenPerCall) { - // Writes nothing back to the guest, so the budget does not apply at all. + // Writes nothing back to the guest, so the budget does not apply. if (bytesWrittenPerCall <= 0) { return kCallsPerRun; @@ -85,34 +88,112 @@ timeRun(HostFunctions& host, Bytes const& wasm) .gas = outcome.has_value() ? outcome->cost : std::int64_t{0}}; } +StageTimer::StageTimer(benchmark::State& state, std::int64_t moduleBytes) + : state_{state}, moduleBytes_{moduleBytes} +{ +} + +void +StageTimer::add(double seconds) +{ + state_.SetIterationTime(seconds); + total_ += seconds; + sumSquares_ += seconds * seconds; + ++rounds_; +} + +void +StageTimer::report() +{ + if (rounds_ == 0) + { + return; + } + + auto const count = static_cast(rounds_); + auto const mean = total_ / count; + auto const variance = std::max(0.0, (sumSquares_ / count) - (mean * mean)); + auto const spread = mean > 0.0 ? std::sqrt(variance) / mean : 0.0; + + auto const& calibration = Calibration::instance(); + auto const perGas = calibration.secondsPerGas(); + auto const equivalent = perGas > 0.0 ? mean / perGas : 0.0; + + state_.counters["ns_per_op"] = mean * 1e9; + // What this stage would cost if it were charged at the rate the guest inside it is charged at. + // It is not charged, which is the point: this puts an unpriced stage in the host-function + // table's units. + state_.counters["gas_equivalent"] = equivalent; + + if (moduleBytes_ > 0) + { + state_.counters["module_bytes"] = static_cast(moduleBytes_); + // An average over the whole operation, not the marginal rate: it carries the case's fixed + // cost, so it overestimates and falls toward the true slope as the sweep grows. + state_.counters["gas_per_byte"] = equivalent / static_cast(moduleBytes_); + } + + // `gas_equivalent` divides by `secondsPerGas`, so the divisor's uncertainty is in every number + // here too. + auto const caseStdErr = spread / std::sqrt(count); + auto const perGasErr = calibration.secondsPerGasRelStdErr(); + auto const totalErr = std::sqrt((caseStdErr * caseStdErr) + (perGasErr * perGasErr)); + state_.counters["rel_error"] = totalErr; + state_.counters["unreliable"] = totalErr > kMaxRelativeSpread ? 1 : 0; +} + +void +benchmarkPreflight(benchmark::State& state, Bytes const& wasm, bool expectAccepted, bool sizeSweep) +{ + (void)Calibration::instance(); + + // Discarded: the reject case refuses on every iteration, and a real sink would put string + // formatting and I/O inside the measurement. + auto const journal = beast::Journal{beast::Journal::getNullSink()}; + + if (isTesSuccess(preflightEscrowWasm(wasm, journal)) != expectAccepted) + { + state.SkipWithError( + expectAccepted + ? "the module was refused; the case would be measuring the reject path" + : "the module was accepted; the case would be measuring the accept path"); + return; + } + + StageTimer timer{state, sizeSweep ? static_cast(wasm.size()) : 0}; + for (auto _ : state) + { + auto const start = std::chrono::steady_clock::now(); + auto verdict = preflightEscrowWasm(wasm, journal); + auto const elapsed = std::chrono::steady_clock::now() - start; + + benchmark::DoNotOptimize(verdict); + timer.add(std::chrono::duration(elapsed).count()); + } + timer.report(); +} + namespace { -// Seconds of wall time one unit of gas buys on this machine. See `Calibration` for why this is -// a difference rather than a single measurement. +// Seconds of wall time one unit of gas buys on this machine. // -// The estimator has to be the *same* one the cases use — a mean over `kCalibrationPairs` pairs, -// with the same clamp at zero as `benchmarkThroughVm`. This is not a stylistic point. Since -// `implied_gas = secondsPerCall / secondsPerGas`, any systematic difference between how the -// divisor and the dividend are estimated lands directly in every reported number. A minimum -// sits below a mean, so calibrating with a best-of while measuring cases with a mean biases -// `secondsPerGas` low and every `implied_gas` and `suggested_gas` correspondingly high. +// The estimator must be the *same* one the cases use — a mean, with the same clamp at zero. Since +// `implied_gas = secondsPerCall / secondsPerGas`, any difference between how divisor and dividend +// are estimated lands in every reported number: calibrating with a best-of while measuring with a +// mean once biased the whole report +40%. // -// `guestInstruction` in Crossing.bench.cpp is the check that this holds: it runs this exact loop -// body, so its `implied_gas` and `charged_gas` are two measurements of one quantity and must -// agree within a few percent. +// `guestInstruction` in Crossing.cpp is the check that this holds — it runs this exact loop body. double -measureSecondsPerGas() +measureSecondsPerGas(double& relativeStandardError) { - // A couple of guest instructions per iteration, no memory traffic, nothing the engine can - // fold away. + // A couple of guest instructions, no memory traffic, nothing the engine can fold away. static constexpr auto kBody = std::string_view{"(i32.add (local.get $r) (i32.const 1))"}; auto const busy = assembleWat(makeLoopWat("", "", kBody, kCallsPerRun)); auto const idle = assembleWat(makeLoopWat("", "", kBody, 0)); auto fixture = WasmLedger{}; - // Warm the instruction cache and the allocator before the pairs that count, so the first-run - // penalty does not land on one side of the subtraction. + // Warm up, so the first-run penalty does not land on one side of the subtraction. for (auto i = 0U; i < 8; ++i) { timeRun(*fixture.makeHost(), busy); @@ -120,6 +201,7 @@ measureSecondsPerGas() } auto total = 0.0; + auto sumSquares = 0.0; // Fuel is exact and deterministic, so any pair gives the same delta. auto gasDelta = std::int64_t{1}; for (auto i = 0; i < kCalibrationPairs; ++i) @@ -129,22 +211,26 @@ measureSecondsPerGas() auto coldHost = fixture.makeHost(); auto const cold = timeRun(*coldHost, idle); - total += std::max(0.0, hot.seconds - cold.seconds); + auto const delta = std::max(0.0, hot.seconds - cold.seconds); + total += delta; + sumSquares += delta * delta; gasDelta = std::max(std::int64_t{1}, hot.gas - cold.gas); } - return (total / kCalibrationPairs) / static_cast(gasDelta); + auto const mean = total / kCalibrationPairs; + auto const variance = std::max(0.0, (sumSquares / kCalibrationPairs) - (mean * mean)); + relativeStandardError = mean > 0.0 ? std::sqrt(variance / kCalibrationPairs) / mean : 0.0; + + return mean / static_cast(gasDelta); } // The crossing, in gas: `ldgr_index` through the VM minus `ldgr_index` called directly. -// `secondsPerGas` has to be the value from the same snapshot, so it is passed in rather than -// re-measured. // -// Both halves are means for the same reason `measureSecondsPerGas` is: the VM half has to match -// `benchmarkThroughVm`'s estimator and the impl half `benchmarkImpl`'s, or the crossing is the -// difference of two numbers computed differently. +// Both halves are means, for the reason above: the VM half has to match `benchmarkThroughVm`'s +// estimator and the impl half `benchmarkImpl`'s. `secondsPerGas` is passed in rather than +// re-measured so it comes from the same snapshot. double -measureCrossingFloorGas(double secondsPerGas) +measureCrossingFloorGas(double secondsPerGas, double& relativeStandardError) { static constexpr std::string_view kImport = R"( (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) @@ -157,6 +243,8 @@ measureCrossingFloorGas(double secondsPerGas) auto fixture = WasmLedger{}; auto vmTotal = 0.0; + auto vmSquares = 0.0; + auto guestOverheadGas = 0.0; for (auto i = 0; i < kBenchIterations; ++i) { auto hotHost = fixture.makeHost(); @@ -164,12 +252,18 @@ measureCrossingFloorGas(double secondsPerGas) auto coldHost = fixture.makeHost(); auto const cold = timeRun(*coldHost, baseline); - vmTotal += std::max(0.0, hot.seconds - cold.seconds) / kCallsPerRun; + auto const perCall = std::max(0.0, hot.seconds - cold.seconds) / kCallsPerRun; + vmTotal += perCall; + vmSquares += perCall * perCall; + // Exact, from the fuel meter: what the guest burned per call beyond the call itself. + guestOverheadGas = + (static_cast(hot.gas - cold.gas) / kCallsPerRun) - declaredGas("ldgr_index"); } auto const vmSeconds = vmTotal / kBenchIterations; // The impl side is the same call without the VM. Subtracting it leaves the crossing. auto implTotal = 0.0; + auto implSquares = 0.0; auto host = fixture.makeHost(); for (auto i = 0; i < kBenchIterations; ++i) { @@ -180,18 +274,50 @@ measureCrossingFloorGas(double secondsPerGas) benchmark::DoNotOptimize(result); } auto const elapsed = std::chrono::steady_clock::now() - start; - implTotal += std::chrono::duration(elapsed).count() / kCallsPerRun; + + auto const perCall = std::chrono::duration(elapsed).count() / kCallsPerRun; + implTotal += perCall; + implSquares += perCall * perCall; } auto const implSeconds = implTotal / kBenchIterations; - return secondsPerGas > 0.0 ? std::max(0.0, vmSeconds - implSeconds) / secondsPerGas : 0.0; + if (secondsPerGas <= 0.0) + { + return 0.0; + } + // Take the guest's loop bookkeeping off here too: `report` removes it from every `ThroughVm` + // number, so leaving it in would make the two routes to one price disagree by that amount. + auto const crossing = std::max(0.0, vmSeconds - implSeconds) / secondsPerGas; + auto const floor = std::max(0.0, crossing - std::max(0.0, guestOverheadGas)); + + // Relative to the *difference*, not to either half: both contribute their error, and the + // denominator is what survives the subtraction. Not divided by `secondsPerGas` — that error is + // common-mode with the rest of `suggested_gas` and is applied once, to the sum, in `report`. + auto const vmVariance = std::max(0.0, (vmSquares / kBenchIterations) - (vmSeconds * vmSeconds)); + auto const implVariance = + std::max(0.0, (implSquares / kBenchIterations) - (implSeconds * implSeconds)); + auto const vmStdErr = std::sqrt(vmVariance / kBenchIterations); + auto const implStdErr = std::sqrt(implVariance / kBenchIterations); + + auto const crossingSeconds = vmSeconds - implSeconds; + auto const crossingStdErr = std::sqrt((vmStdErr * vmStdErr) + (implStdErr * implStdErr)); + relativeStandardError = crossingSeconds > 0.0 ? crossingStdErr / crossingSeconds : 0.0; + + return floor; } } // namespace +Calibration const& +Calibration::instance() +{ + static Calibration const kValue; + return kValue; +} + Calibration::Calibration() - : secondsPerGas_{measureSecondsPerGas()} - , crossingFloorGas_{measureCrossingFloorGas(secondsPerGas_)} + : secondsPerGas_{measureSecondsPerGas(secondsPerGasRelStdErr_)} + , crossingFloorGas_{measureCrossingFloorGas(secondsPerGas_, crossingFloorRelStdErr_)} { } @@ -207,12 +333,19 @@ report( benchmark::State& state, double secondsPerCall, double chargedGas, + double guestOverheadGas, + double relativeSpread, + std::int64_t rounds, std::string_view wasmName, bool throughVm) { - auto calibration = Calibration{}; + auto const& calibration = Calibration::instance(); auto const perGas = calibration.secondsPerGas(); - auto const implied = perGas > 0.0 ? secondsPerCall / perGas : 0.0; + auto const measured = perGas > 0.0 ? secondsPerCall / perGas : 0.0; + + // The timed number covers the host call *and* whatever the guest ran around it. + // `guestOverheadGas` is exact, so taking it off removes a bias rather than trading estimates. + auto const implied = std::max(0.0, measured - guestOverheadGas); auto const suggested = throughVm ? implied : implied + calibration.crossingFloorGas(); state.counters["implied_gas"] = implied; @@ -220,14 +353,45 @@ report( state.counters["charged_gas"] = chargedGas; if (wasmName.empty()) + { return; + } auto const declared = declaredGas(wasmName); state.counters["host_function_gas"] = declared; state.counters["suggested_gas"] = suggested; - // Above 1: the table charges more than the work costs. Below 1: underpriced, which is the - // direction that matters — an underpriced call is one a contract can buy too cheaply. + // Below 1 is the direction that matters: an underpriced call is one a contract buys too + // cheaply. state.counters["price_ratio"] = suggested > 0.0 ? declared / suggested : 0.0; + + // Uncertainty **of `suggested_gas`**, not of `implied_gas` — different numbers once the floor + // is added. `implied` and the floor are independent timings, so their absolute errors add in + // quadrature over the sum; but both divide by `secondsPerGas`, so that error is common-mode and + // applies once to the total. Adding it per-term would count it twice. + // + // For `ThroughVm` the floor term is zero and `suggested == implied`, so this reduces exactly to + // the plain `sqrt(caseErr² + perGasErr²)`. Only `Impl` cases move — and for a cheap one the + // floor is most of `suggested_gas`, so an error bar describing `implied` alone described + // little. + auto const caseStdErr = + rounds > 0 ? relativeSpread / std::sqrt(static_cast(rounds)) : relativeSpread; + + auto const impliedErr = implied * caseStdErr; + auto const floorErr = + throughVm ? 0.0 : calibration.crossingFloorGas() * calibration.crossingFloorRelStdErr(); + auto const independentErr = suggested > 0.0 + ? std::sqrt((impliedErr * impliedErr) + (floorErr * floorErr)) / suggested + : caseStdErr; + + auto const perGasErr = calibration.secondsPerGasRelStdErr(); + auto const totalErr = std::sqrt((independentErr * independentErr) + (perGasErr * perGasErr)); + state.counters["rel_error"] = totalErr; + + // A call whose own cost is small next to the crossing is read off the difference of two nearly + // equal numbers, so its `suggested_gas` is scatter rather than signal. + auto const floor = calibration.crossingFloorGas(); + state.counters["unreliable"] = + (totalErr > kMaxRelativeSpread || (floor > 0.0 && suggested < floor)) ? 1 : 0; } } // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/WasmBench.h b/src/benchmarks/libxrpl/wasm/WasmBench.h index 3caa7a02f6..98f0921be7 100644 --- a/src/benchmarks/libxrpl/wasm/WasmBench.h +++ b/src/benchmarks/libxrpl/wasm/WasmBench.h @@ -9,59 +9,42 @@ #include #include +#include #include #include #include #include #include -// The gas-calibration harness: how a `*.bench.cpp` measures a host call, and how that -// measurement becomes a suggested price. What the numbers mean and how to read a report are in -// ../README.md. +// The gas-calibration harness. What the numbers mean and how to read a report are in ../README.md. namespace xrpl::test::bench { -// Enough gas that a thousand-call benchmark loop never ends early; a benchmark measures -// work, so running out of budget would silently measure something shorter instead. +// Enough that a benchmark loop never ends early; running out would measure something shorter. inline constexpr std::int64_t kBenchGas = 2'000'000'000; -// How many host calls a benchmarked contract makes per run. Large enough that the -// per-call cost dominates the residue left by the baseline subtraction, small enough that -// one run stays in the microsecond range. +// Host calls per run: enough that the per-call cost dominates the baseline subtraction's residue. inline constexpr std::int32_t kCallsPerRun = 1000; -// How many timed iterations each case runs. Pinned rather than left to Google Benchmark's -// automatic sizing, which cannot work here: a case reports the subtraction's residue — tens -// of nanoseconds — while the iteration that produced it ran two whole contracts, module -// compilation included, and cost milliseconds. Automatic sizing sees only the reported time, -// so it would ask for millions of iterations to accumulate its default `min_time` and the -// case would never finish. Every registration therefore ends -// `->UseManualTime()->Iterations(kBenchIterations)`. +// Timed iterations per case. Pinned because automatic sizing cannot work here: a case reports a +// residue of nanoseconds while the iteration producing it ran two contracts and cost milliseconds, +// so sizing would ask for millions. inline constexpr std::int32_t kBenchIterations = 50; -// How many pairs the one-off calibration averages. Higher than `kBenchIterations` because -// `secondsPerGas` is the divisor for *every* reported number, so its noise is common-mode across -// the whole report, and because calibration runs a bare wasm loop with no ledger and no host -// calls — a few hundred extra pairs cost milliseconds. More samples of a mean is only more -// precision, not a different estimator, so this does not reintroduce the bias that mixing a -// best-of with a mean did. +// Pairs the one-off calibration averages. Higher than `kBenchIterations` because `secondsPerGas` +// divides every reported number, and a bare wasm loop is cheap to repeat. inline constexpr std::int32_t kCalibrationPairs = 400; -// How much a run may write into guest memory before `charge_transfer` starts refusing calls -// (`TRANSFER_LIMIT_BYTES` in crates/xrpl-wasm-vm/src/vm.rs). Per run, so it resets between the -// runs a benchmark makes — but one run of `kCallsPerRun` calls could exhaust it partway through -// and spend the rest of the loop measuring the refusal path instead of the host function. +// Above this relative uncertainty, `suggested_gas` is reported as unreliable. +inline constexpr double kMaxRelativeSpread = 0.25; + +// `TRANSFER_LIMIT_BYTES` in crates/xrpl-wasm-vm/src/vm.rs: what a run may write into guest memory +// before `charge_transfer` starts refusing calls. inline constexpr std::int64_t kTransferLimitBytes = 1 << 20; -// How many calls a run can afford, given how many bytes each one has the host **write into guest -// memory**. -// -// One direction only: the budget is charged in `write_into` / `write_buffered` / `write_mant_exp` -// and nowhere else. What the guest passes *in* is borrowed rather than copied and costs nothing -// against it, so a caller passes the size of its output region, not of its input. -// -// Never raises the count to meet a floor — that would be the one thing this function exists to -// prevent. A case that cannot afford a single call cannot be measured, so that fails loudly. +// How many calls a run can afford, given the bytes each has the host **write into guest memory**. +// Output direction only — what the guest passes in is borrowed, and costs nothing against the +// budget. Never raises the count to meet a floor; a case that cannot afford one call fails loudly. int callsWithinTransferBudget(std::int64_t bytesWrittenPerCall); @@ -72,10 +55,9 @@ struct Timing std::int64_t gas{}; }; -// A `(data ...)` segment placing `bytes` at `offset` in the guest's memory, so a case's -// input is in place before the timed loop starts and the loop measures the host call rather -// than the guest arranging its arguments. See `watEscaped` in WasmRun.h for why zeroed -// memory will not do. +// A `(data ...)` segment placing `bytes` at `offset` in guest memory, so the timed loop measures +// the host call rather than the guest arranging its arguments. `watEscaped` in WasmRun.h says why +// zeroed memory will not do. std::string dataSegment(int offset, std::span bytes); @@ -90,11 +72,14 @@ makeLoopWat(std::string_view imports, std::string_view data, std::string_view bo Timing timeRun(HostFunctions& host, Bytes const& wasm); -// What this machine costs, measured once and shared by every case. +// What this machine costs, measured once and shared by every case: two cases pricing one function +// two ways (`Impl` + crossing floor, versus `ThroughVm`) must divide by the *same* `secondsPerGas` +// or they disagree for reasons unrelated to the function. class Calibration { public: - Calibration(); + static Calibration const& + instance(); // Seconds of wall time one unit of gas buys here. [[nodiscard]] double @@ -103,35 +88,123 @@ public: return secondsPerGas_; } - // The gas a host call costs before it does anything: region decode, bounds checks, the cxx - // hop. + // The gas a host call costs before it does anything: region decode, bounds checks, the cxx hop. [[nodiscard]] double crossingFloorGas() const { return crossingFloorGas_; } + // Propagated into every case's `rel_error`, which is what lets one snapshot stay shared: + // `--benchmark_repetitions` resamples per-case timings but never this divisor. + [[nodiscard]] double + secondsPerGasRelStdErr() const + { + return secondsPerGasRelStdErr_; + } + + // An additive term in every `Impl` case's `suggested_gas`, and most of the cheap ones. + [[nodiscard]] double + crossingFloorRelStdErr() const + { + return crossingFloorRelStdErr_; + } + private: + Calibration(); + + double secondsPerGasRelStdErr_{}; + double crossingFloorRelStdErr_{}; double secondsPerGas_{}; double crossingFloorGas_{}; }; -// What the gas table says a host function costs, by its guest import name. -// Read from the declaration through the `wasm_testkit` bridge. +// What the gas table declares for a host function, by guest import name, read through the +// `wasm_testkit` bridge so it cannot drift. double declaredGas(std::string_view wasmName); // Attach the calibration counters to a finished case. +// +// `guestOverheadGas` is fuel the guest burned around the call — loop bookkeeping and the +// `i32.const`s pushing arguments. From the fuel meter, so it is exact. Zero for `Impl` cases. void report( benchmark::State& state, double secondsPerCall, double chargedGas, + double guestOverheadGas, + double relativeSpread, + std::int64_t rounds, std::string_view wasmName, bool throughVm); -// Measure a host function *through the whole stack* — guest, VM, marshalling, real impl, -// real ledger — with everything but the host calls subtracted away. +// Accumulates one whole-operation case and turns it into counters. +// +// The two harnesses below subtract setup away, amortizing over `kCallsPerRun` calls against a +// baseline. Here that is inverted: setup is the subject, timed whole, nothing amortized. +class StageTimer +{ +public: + // Pass zero for `moduleBytes` unless the case belongs to a sweep that *varies* module size — + // the per-byte counter it enables is an average over the whole operation, meaningless where the + // module is constant. + StageTimer(benchmark::State& state, std::int64_t moduleBytes); + + void + add(double seconds); + + // Attach the counters. Call once, after the loop. + void + report(); + +private: + benchmark::State& state_; + std::int64_t moduleBytes_{}; + double total_{}; + double sumSquares_{}; + std::int64_t rounds_{}; +}; + +// Measure `preflightEscrowWasm`: compile, then the walk over the module's imports and exports. +// +// `expectAccepted` is what the module *should* do. A refused module stops at the first fault and is +// far cheaper, so a case that silently flipped verdict would report a confident number for an +// operation it never performed. +void +benchmarkPreflight( + benchmark::State& state, + Bytes const& wasm, + bool expectAccepted = true, + bool sizeSweep = false); + +// Measure a whole `runEscrowWasm` — every stage, unamortized. +template +void +benchmarkRun(benchmark::State& state, Bytes const& wasm, SetUp&& setUp, bool sizeSweep = false) +{ + // Force the calibration and the engine's lazy construction before the clock starts, so the + // first case does not absorb them into its own first iteration. + [[maybe_unused]] auto const& calibration = Calibration::instance(); + + auto probe = setUp(); + if (auto const check = runEscrowWasm(wasm, *probe, kBenchGas); !check.has_value()) + { + state.SkipWithError("the benchmarked contract did not run to completion"); + return; + } + + auto timer = StageTimer{state, sizeSweep ? static_cast(wasm.size()) : 0}; + for (auto _ : state) + { + auto host = setUp(); + timer.add(timeRun(*host, wasm).seconds); + } + timer.report(); +} + +// Measure a host function through the whole stack — guest, VM, marshalling, real impl, real ledger +// — with everything but the host calls subtracted away. template void benchmarkThroughVm( @@ -146,18 +219,12 @@ benchmarkThroughVm( auto const loaded = assembleWat(makeLoopWat(imports, data, body, calls)); auto const baseline = assembleWat(makeLoopWat(imports, data, body, 0)); - // A host serves exactly one run: it caches the current ledger object, the slot table and - // the contract's data for that run's length, and `runEscrowWasm` asserts it was handed a - // clean one (see `checkSelf` in WasmVM.cpp). So every run below builds its own. That - // costs the measurement nothing — `timeRun` starts its clock after the host exists — - // and it is why `setUp` is a factory rather than a host. + // A host serves exactly one run — `runEscrowWasm` asserts it was handed a clean one + // (`checkSelf` in WasmVM.cpp). Hence `setUp` being a factory rather than a host. auto probe = setUp(); - // Confirm the contract actually succeeds before measuring it — and note that "the run - // succeeded" is not enough to establish that. - // So require both: the run completed, and the contract's last host call returned a - // non-negative result. Every body here leaves that result in `$r`, which the module - // returns. + // A soft host error still completes the run, so require both that it completed and that the + // last host call returned a non-negative result, which every body leaves in `$r`. auto const check = runEscrowWasm(loaded, *probe, kBenchGas); if (!check.has_value()) { @@ -173,6 +240,7 @@ benchmarkThroughVm( } auto totalSeconds = 0.0; + auto sumSquares = 0.0; auto totalGas = 0.0; auto rounds = std::int64_t{0}; for (auto _ : state) @@ -182,45 +250,56 @@ benchmarkThroughVm( auto coldHost = setUp(); auto const cold = timeRun(*coldHost, baseline); - // Clamped at zero: on a noisy machine a single pair can invert, and a negative - // iteration time would make Google Benchmark's statistics meaningless. + // Clamped: on a noisy machine a pair can invert, and a negative iteration time would make + // Google Benchmark's statistics meaningless. auto const perCall = std::max(0.0, hot.seconds - cold.seconds) / calls; state.SetIterationTime(perCall); totalSeconds += perCall; + sumSquares += perCall * perCall; totalGas += static_cast(hot.gas - cold.gas) / calls; ++rounds; } if (rounds > 0) { - report(state, totalSeconds / rounds, totalGas / rounds, wasmName, true); + auto const meanSeconds = totalSeconds / rounds; + auto const variance = std::max(0.0, (sumSquares / rounds) - (meanSeconds * meanSeconds)); + auto const spread = meanSeconds > 0.0 ? std::sqrt(variance) / meanSeconds : 0.0; + + // Zero for the empty-name case — `guestInstruction`, which prices no host function. There + // is no host call to separate scaffolding *from*, and subtracting the full charge would + // leave `implied_gas = measured - charged`, ~0 by construction: it would turn the harness's + // one self-test into a tautology that cannot fail. + auto const chargedPerCall = totalGas / rounds; + auto const overhead = wasmName.empty() ? 0.0 : chargedPerCall - declaredGas(wasmName); + + report( + state, + meanSeconds, + chargedPerCall, + std::max(0.0, overhead), + spread, + rounds, + wasmName, + true); } } -// Measure a host function's *impl alone* — the computation, with no guest, no VM and no -// marshalling. Paired with the `ThroughVm` case for the same function, the difference is -// what crossing the guest/host boundary costs. -// Register with `->UseManualTime()`. +// Measure a host function's impl alone — no guest, no VM, no marshalling. Against the `ThroughVm` +// case for the same function, the difference is what crossing the boundary costs. template void benchmarkImpl(benchmark::State& state, std::string_view wasmName, SetUp&& setUp, Call&& call) { auto host = setUp(); - // Confirm the call succeeds — one that errors returns early and is far cheaper than one that - // does the work, so a case with a subtly wrong argument reports a plausible, confidently - // wrong, and always *too low* price. `benchmarkThroughVm` gets this for free from the - // contract's return value; a direct call has no such signal. + // A call that errors returns early and is far cheaper than one that works, so a subtly wrong + // argument yields a confident and always *too low* price. Probed either side of the loop rather + // than inside it, where the branch would land in the measurement: *before* catches wrong + // arguments, *after* catches a call that stopped working once the loop exhausted something. // - // Checked on either side of the timed loop rather than inside it. Inside, the branch lands in - // the measurement — worth up to ~13% on the cheapest calls, which run about 2 ns. Outside it - // costs nothing and still catches both failure modes: the *before* probe catches wrong - // arguments, the *after* probe catches a call that stopped working partway through because - // the loop exhausted something. - // - // The `requires` skips host functions that answer nothing (`trace`) or answer a bare value - // rather than an `expected`. + // The `requires` skips host functions that answer nothing (`trace`) or answer a bare value. auto const checkSucceeds = [&](char const* when) { if constexpr (requires { call(*host).has_value(); }) { @@ -242,15 +321,14 @@ benchmarkImpl(benchmark::State& state, std::string_view wasmName, SetUp&& setUp, } auto totalSeconds = 0.0; + auto sumSquares = 0.0; auto rounds = std::int64_t{0}; for (auto _ : state) { auto const start = std::chrono::steady_clock::now(); for (int i = 0; i < kCallsPerRun; ++i) { - // `trace` is the one host function that answers nothing, so there is no result - // to hold onto; `ClobberMemory` stands in for `DoNotOptimize` to keep the call - // from being elided. + // `trace` answers nothing, so `ClobberMemory` stands in for `DoNotOptimize`. if constexpr (std::is_void_v) { call(*host); @@ -268,6 +346,7 @@ benchmarkImpl(benchmark::State& state, std::string_view wasmName, SetUp&& setUp, state.SetIterationTime(perCall); totalSeconds += perCall; + sumSquares += perCall * perCall; ++rounds; } @@ -276,11 +355,14 @@ benchmarkImpl(benchmark::State& state, std::string_view wasmName, SetUp&& setUp, return; } - // No VM ran, so nothing was charged — and the crossing this case leaves out is added back - // into `suggested_gas`, because a guest cannot make the call without paying it. if (rounds > 0) { - report(state, totalSeconds / rounds, 0.0, wasmName, false); + auto const meanSeconds = totalSeconds / rounds; + auto const variance = std::max(0.0, (sumSquares / rounds) - (meanSeconds * meanSeconds)); + auto const spread = meanSeconds > 0.0 ? std::sqrt(variance) / meanSeconds : 0.0; + + // Nothing charged and no guest scaffolding; `report` adds the crossing back in. + report(state, meanSeconds, 0.0, 0.0, spread, rounds, wasmName, false); } } From daecad43c9c6b34a32aea341a49d555bc277f45b Mon Sep 17 00:00:00 2001 From: TimothyBanks Date: Tue, 8 Sep 2026 09:58:32 -0400 Subject: [PATCH 23/23] chore: Upgrade to Wasmi 2.0 --- crates/Cargo.lock | 16 ++++++++-------- crates/xrpl-wasm-vm/Cargo.toml | 2 +- src/benchmarks/libxrpl/wasm/README.md | 3 +-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/Cargo.lock b/crates/Cargo.lock index dc45bd9a24..cecf09688b 100644 --- a/crates/Cargo.lock +++ b/crates/Cargo.lock @@ -348,9 +348,9 @@ dependencies = [ [[package]] name = "wasmi" -version = "2.0.0-beta.10" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab57cbb8db5ee46c6667b642544d7664adfbc0ea6a1ab219c92d734b795f36b1" +checksum = "78693fcdd618e0fc34af59c6b8efa9ac5d58c68df940beff4bedddb6acfe7c27" dependencies = [ "spin", "wasmi_collections", @@ -361,27 +361,27 @@ dependencies = [ [[package]] name = "wasmi_collections" -version = "2.0.0-beta.10" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ea3ee266456966465c55a1f440e33116caf2b05a4fc30da36cb0c9813059d5" +checksum = "8a8be2aa467cf2d29e96ff759472c36eeb44a3c81c67fc9cb76c9a24c519c557" dependencies = [ "string-interner", ] [[package]] name = "wasmi_core" -version = "2.0.0-beta.10" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f8285efe48a9e1afbcdfcc19cd807b3eb20129b7e199c7a99efd30ba192926b" +checksum = "69372d5fda3ea3d1e0aa6603c7888110e0187e88ea17cd8fc2e2df0a0e1f37fa" dependencies = [ "libm", ] [[package]] name = "wasmi_ir" -version = "2.0.0-beta.10" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6227be1aebba39b4815ab6a312d0528590f0db2473621ec9285606410889b0a6" +checksum = "8f17b774caa13c618c7244f1ee51fe23c5e7b8538a471fa46d9949779758aed6" dependencies = [ "wasmi_core", ] diff --git a/crates/xrpl-wasm-vm/Cargo.toml b/crates/xrpl-wasm-vm/Cargo.toml index 02c4ec15bb..dc01cd86e9 100644 --- a/crates/xrpl-wasm-vm/Cargo.toml +++ b/crates/xrpl-wasm-vm/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition.workspace = true [dependencies] -wasmi = { version = "2.0.0-beta.10", default-features = false, features = ["std", "validate", "portable-dispatch"] } +wasmi = { version = "2.0.0", default-features = false, features = ["std", "validate", "portable-dispatch"] } xrpl-host-functions = { path = "../xrpl-host-functions" } [dev-dependencies] diff --git a/src/benchmarks/libxrpl/wasm/README.md b/src/benchmarks/libxrpl/wasm/README.md index e50afdec01..65b7677762 100644 --- a/src/benchmarks/libxrpl/wasm/README.md +++ b/src/benchmarks/libxrpl/wasm/README.md @@ -145,8 +145,7 @@ rows, all blaming cases that were innocent. **Outside the suite it is worth a look.** A validator compiles twice per programmable-escrow transaction against that same static engine. Whether that is unbounded growth in production depends -on wasmi internals not checked here — this is the C++-visible symptom, not a diagnosis. wasmi is -pinned at `2.0.0-beta.10`, a beta, so try a version bump first. +on wasmi internals not checked here — this is the C++-visible symptom, not a diagnosis. ## Gotchas, each of which has already cost someone an afternoon