From 7342e06f36f650da836798785ce869584221b93f Mon Sep 17 00:00:00 2001 From: vlbos <45447465+vlbos@users.noreply.github.com> Date: Fri, 1 Mar 2019 00:22:42 +0800 Subject: [PATCH] Release/2.0.x (#47) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove unnecessary conversion of contractPath to empty path * enhance cleos multisig review to show proposed transaction ID and optionally show requested approvals #6272 * add cleos multisig invalidate command to call eosio.msig::invalidate * state history plugin * fix GMP & secp256 linker order for EosioTesterBuild.cmake.in This is the same fix from pr #6268 but for EosioTesterBuild.cmake.in too * state history plugin * bump version to 1.5.0-rc1 * Update README to reflect new package names * Change from 1.5.0 to 1.5.0-rc1 * Fix requires in spec file to resolve dependency resolution issues with rpms * Fix requires in spec file to resolve dependency resolution issues with rpms * Remove unneeded req_trx vector * Remove needless copy of signed_block. Only create pending_notify if needed. * Remove unused blk_buffer * separate out version suffix so that RPM packages produce an acceptable specfile * address PR review feedback * Make signed_block copy constructor private to avoid accidental copies. * add release suffix to doxygen cmake module * move signed_block instead of making copy * Avoid copy constructor for push_block * add release suffix to EOSIO_VERSION in tester cmake modules * Add which comment * Update tests for private signed_block copy constructor * Avoid making copies of signed_block * export the new bash vars * Use rvalue for signed_block * Update buildkite pipeline to use new queues * Update buildkite pipeline to use new queues * Special case msg_handler visit of signed_block to avoid hidden move from net_message * pass along trigger_send * Use move for rvalue * Added Mongo History API link * Added ZMQ Light History API * Added Chintai ZMQ Watcher * Added State History API * Stop the unix_server from listening in shutdown stage as well. * bump version to rc2 * update rpm names to match the real files * Fix deb package names in README * Fix package naming scheme for debs * Update LICENSE path * add a test that reduces the size of the producer set to validate that it does not create protocol level issues * promote rc2 to release * add missing release to deb packages * remove x86_64 arch dep specification on AMI2 build script I can't find any reason we need to explcitly request the x86_64 versions of packages for AMI2. Removing this apparently extraneous specification makes the build script "just work" on new ARM8 instances * Use 64-bit float printing of 128-bit floats on non x86_64 For platforms other then x86_64, have the 128-bit float console print API (printqf()) convert to a 64-bit float before printing. While this loses precision it’s enough to get the unit tests for printqf() working on ARM8, which actually was the only unit_test unit test that failed on that platform. * prebump to 1.6.0 and add develop suffix * Do not broadcast block if peer lib is larger than block number * Provide more efficient sha256_less * Simply by removing unused large_msg_notify * Remove unused node_transaction_state.packed_txn * Store serialized transaction as shared_ptr to minimize copies * Not possible for serialized_txn to be empty * Remove find_plugin overhead * Minimize shared_ptr copies * Use sha256_less for all sets/maps with ids * Add explicit constructors * Add accept_transaction that takes a packed_transaction_ptr to avoid copy * Pass id and packed_transaction by const& since never moved * Remove copy assignment operator. Remove used std::move. * Minimize packed_transaction copies. Store packed_transaction_ptr in transaction_metadata. * Cache chain_plugin lookup * Update tester for transaction_metadata packed_transaction_ptr * Remove packed_tansaction to net_message copy * Remove unused constructor * Explicitly disable copy/move construction * Remove inflight update of node_transaction_state as it is not needed * Remove connections for unused signals that only logged * Fix sync check for lib * add a test that verifies proposing an empty producer schedule does not break things * Allow disablement of net_plugin's listen socket Disable net_plugin's listen socket when p2p-listen-endpoint is empty. This is useful for security and for an easier way of running multiple nodeos without it conflicting when you don't actually need to service incoming connections. * More descriptive memo to distinguish from other transfers * Revert "Fix sync check for lib" This reverts commit 52a6f193aa3a06833165fc36d3a52407769c732f. * Update the bios-boot-tutorial.py script and readme.md: 1. args.contracts_dir doesn't end in a forward slash, therefor when it is concatenated with a subpath, the subpath has to start with a forward slash; this pattern is present in other similar variables as well 2. system contract has to be initialized before it can be used (e.g. creating staked acconts) 3. commands list updated to include the new addition stepInitSystemContract 4. readme.md updated as well to reflect the current status of the script and requirements * README.md refactored - correcting spelling errors, and caps - better bash commands - simpler command line to launch the script - improved prerequisites - include steps to follow after prerequisites * Correct typos * Correct link format * Add eosio.cdt steps * merge v1.0.2 (#12) * boscore basic improvement (#2) * kafka_plugin code * Automatic installation librdkafka/cppkafka * Feature/ci * Feature/48 kafka plugin * add CMakeModules/FindCppkafka.cmake * Production of block in time zone sequence * P2p self discovery * P2p self discovery * add notify_plugin * add api "get_block_detail" * add free res limit and blklst code * update free res limit and blklst code * update res code * update unittest code * revert submodule version * code typo * update blklist code * update sync name list db object error code * update code * update index code * Feature/5 ramdom * Revert "Merge branch 'feature/5-ramdom' into 'develop'" This reverts merge request !8 * adjust for setup BOSCore * change description * adjust the kafka plugin dependency be more special * use boscore repository to improve security * change version tag * finish for docker/builder * pass to build docker and update readme * add actionseed, global action sequence (#5) * delete renamed old file * BOSCore v1.0.1-1.4.3 * restructure the version schema * fix __gmpn_set_str error when build bos.contract * prepare for the v1.0.1 * finish BOS basic functions * add README files * update info * Release/1.0.x (#11) * boscore basic improvement (#2) * kafka_plugin code * Automatic installation librdkafka/cppkafka * Feature/ci * Feature/48 kafka plugin * add CMakeModules/FindCppkafka.cmake * Production of block in time zone sequence * P2p self discovery * P2p self discovery * add notify_plugin * add api "get_block_detail" * add free res limit and blklst code * update free res limit and blklst code * update res code * update unittest code * revert submodule version * code typo * update blklist code * update sync name list db object error code * update code * update index code * Feature/5 ramdom * Revert "Merge branch 'feature/5-ramdom' into 'develop'" This reverts merge request !8 * adjust for setup BOSCore * change description * adjust the kafka plugin dependency be more special * use boscore repository to improve security * change version tag * finish for docker/builder * pass to build docker and update readme * add actionseed, global action sequence (#5) * delete renamed old file * BOSCore v1.0.1-1.4.3 * restructure the version schema * fix __gmpn_set_str error when build bos.contract * prepare for the v1.0.1 * add README files * update info * readme for kafka & add time for action (#5) * 重启 节点,黑名单 失效,fixes #7 (#8) * restart sync list db * recovery system account bos to eosio * recovery system account bos to eosio * recovery system account bos to eosio * Fix/#3 notify plugin (#10) * Add debug info * comment log * rm log for notify_plugin * prepare for v1.0.2 * Better name for eosio contracts directory * dummy checkin to trigger another build * Added scrit to support recursive search for files with FC_REFLECT or FC_REFLECT_ENUM to verify order and completeness. Supports comments with @swap to support different order from definition and @ignore to ignore a specific field for reflection. Still need to support FC_REFLECT_DERIVED. GH #3127 * Added @ignore comment for field that is left out of reflect definition. GH #3127 * Fixed pull request comments. * bump version to 1.5.1 * Consolidated Security Fixes for 1.5.1 - Only allow authorizations that are satisfiable by `eosio.code` for self-addressed deferred transactions - Only allow authorizations that are satisfiable by `eosio.code` OR on the parent action for self-addressed inline actions sent from direct actions - Only allow authorizations that are satisfiable by `eosio.code` for self-addressed inline actions sent from recipient handlers Co-authored-by: arhag Co-authored-by: Bart Wyatt * Peer review changes. Fix move. * Spelling correction * Spelling correction #2 * Remove unused max-implicit-request config * Switch interface from packed_transaction_ptr to transaction_metadata_ptr * Thread pool does not need to be optional * Add transaction_metadata create_signing_keys_future method * Start transaction signature earily in thread pool * Refactor packed_transaction for better encapsulation * Add transaction_metadata create_signing_keys_future method * Start transaction signature earily in thread pool * Update txn_test_gen_plugin to overlap transaction submit @taokayan * release v1.0.3 to master (#15) * boscore basic improvement (#2) * kafka_plugin code * Automatic installation librdkafka/cppkafka * Feature/ci * Feature/48 kafka plugin * add CMakeModules/FindCppkafka.cmake * Production of block in time zone sequence * P2p self discovery * P2p self discovery * add notify_plugin * add api "get_block_detail" * add free res limit and blklst code * update free res limit and blklst code * update res code * update unittest code * revert submodule version * code typo * update blklist code * update sync name list db object error code * update code * update index code * Feature/5 ramdom * Revert "Merge branch 'feature/5-ramdom' into 'develop'" This reverts merge request !8 * adjust for setup BOSCore * change description * adjust the kafka plugin dependency be more special * use boscore repository to improve security * change version tag * finish for docker/builder * pass to build docker and update readme * add actionseed, global action sequence (#5) * delete renamed old file * BOSCore v1.0.1-1.4.3 * restructure the version schema * fix __gmpn_set_str error when build bos.contract * prepare for the v1.0.1 * finish BOS basic functions * add README files * update info * Release/1.0.x (#11) * boscore basic improvement (#2) * kafka_plugin code * Automatic installation librdkafka/cppkafka * Feature/ci * Feature/48 kafka plugin * add CMakeModules/FindCppkafka.cmake * Production of block in time zone sequence * P2p self discovery * P2p self discovery * add notify_plugin * add api "get_block_detail" * add free res limit and blklst code * update free res limit and blklst code * update res code * update unittest code * revert submodule version * code typo * update blklist code * update sync name list db object error code * update code * update index code * Feature/5 ramdom * Revert "Merge branch 'feature/5-ramdom' into 'develop'" This reverts merge request !8 * adjust for setup BOSCore * change description * adjust the kafka plugin dependency be more special * use boscore repository to improve security * change version tag * finish for docker/builder * pass to build docker and update readme * add actionseed, global action sequence (#5) * delete renamed old file * BOSCore v1.0.1-1.4.3 * restructure the version schema * fix __gmpn_set_str error when build bos.contract * prepare for the v1.0.1 * add README files * update info * readme for kafka & add time for action (#5) * 重启 节点,黑名单 失效,fixes #7 (#8) * restart sync list db * recovery system account bos to eosio * recovery system account bos to eosio * recovery system account bos to eosio * Fix/#3 notify plugin (#10) * Add debug info * comment log * rm log for notify_plugin * prepare for v1.0.2 * merge v1.0.2 (#13) * boscore basic improvement (#2) * kafka_plugin code * Automatic installation librdkafka/cppkafka * Feature/ci * Feature/48 kafka plugin * add CMakeModules/FindCppkafka.cmake * Production of block in time zone sequence * P2p self discovery * P2p self discovery * add notify_plugin * add api "get_block_detail" * add free res limit and blklst code * update free res limit and blklst code * update res code * update unittest code * revert submodule version * code typo * update blklist code * update sync name list db object error code * update code * update index code * Feature/5 ramdom * Revert "Merge branch 'feature/5-ramdom' into 'develop'" This reverts merge request !8 * adjust for setup BOSCore * change description * adjust the kafka plugin dependency be more special * use boscore repository to improve security * change version tag * finish for docker/builder * pass to build docker and update readme * add actionseed, global action sequence (#5) * delete renamed old file * BOSCore v1.0.1-1.4.3 * restructure the version schema * fix __gmpn_set_str error when build bos.contract * prepare for the v1.0.1 * add README files * update info * prepare for v1.0.2 * patch the EOSIO 1.5.1 security bug fixes * prepare for v1.0.3 * adjust the slogon * Remove redundant signing_keys check * state history plugin: permission_object bug #6495 * Add deadline to key recovery * Modify producer_plugin to have its own thead_pool instead of using chain-threads * Move thread_pool join/stop to plugin shutdown so that they are joined before application quit * Fix signature future deadline from starting too early * Fix overflow of deadline and deadline check * initial setup of billing CPU for signatures recovered earlier * Return 400 on get_block with uonexist block number. For issue 6374 * fix issue 5488 * Add action_trace.block_num index. Remove action_trace.trx_id index. * Fix return codes of build scripts so that buildkite can fail properly * Make recovery cache non-thread local and guard by mutex * Calculate cpu usage of signature recovery * Add signature-cpu-billable-pct option to chain_plugin * Add missing include of mutex * Assert signature-cpu-billable-pct is 0-100 * Fix capture of cpu_usage. move flat_set into attribute * clear recovered_pub_keys to preserve previous behaviour * use `assign` instead of `resize`+`memcpy` to update `shared_blob` data Co-Authored-By: Kayan * Add move into tuple creation * bump version to 1.6.0-rc1 * add explicitly defaulted move semantics * Store unpacked_trx as signed_transaction * get_uncached_id no longer needed for thread safety * get_raw_transaction no longer needed for thread safety * Remove cached signed_transaction since now cached in packed_transaction * Test should honor existing compression * Cleanup of packed_transaction interface. Fixes for comments on PR #6471 * Update to fc with unpack verify * fc renamed reflector_verify to reflector_init * bump version to 1.5.2 * Update to latest fc with updated verify_init * Consolidated Security Fixes for 1.5.3 - Add missing implementation of dtor, copy ctor, etc for blob_types of fc::variant Co-Authored-By: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> * bump version to 1.5.3 * bump version to 1.6.0-rc2 * Consolidated Security Fixes for 1.6.0-rc2 - Add missing implementation of dtor, copy ctor, etc for blob_types of fc::variant Co-Authored-By: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> * update developer portal link update the getting started link to the latest version * prepare for 2.0.1 * adjust the location paramater * apply 1.5.3 patch * modify the location type * fix cmake error * Use https url for wabt submodule A user agent that doesn't respect hsts could potentially be coerced into downloading malicious sources for wabt via a mitm attack. Prevent this by using a https upstream like the other submodules already do * Add libtinfo5 dependency to deb package. Resolves #6590 Also clean up unused variables and force control directory permissions to comply with Debian specifications regardless of umask. * fix aragument name error * merge v2.0.1 version (#36) * Bump version to 1.6.0 * Consolidated Security Fixes for 1.6.0 - Force compilation support for c++ exceptions for the wabt submodule - Allow limiting the time a node will spend processing scheduled transactions Co-Authored-By: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Co-Authored-By: Bart Wyatt * Consolidated Security Fixes for 1.6.1 - net_plugin security fixes - Additional checktime calls to limit cpu usage - Limit memory usage in producer_plugin Co-Authored-By: Kevin Heifner Co-Authored-By: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Co-authored-by: Kayan * Bump version to 1.6.1 * Fix boost 1.67 brew install The latest homebrew code balks at something in the old 1.67 package file. Fix the package file and store it locally in our repo for now. We try and pin the boost version because boost upgrades invalidate nodeos data files. * Set proper directory for baked in macOS LLVM_DIR Some users (including myself) were seeing llvm@4 unpacked to 4.0.1_1 instead of 4.0.1. Stuff unpacked to the Cellar directory appears to be a kind of implementation detail — /usr/local/opt is the proper place to reference here. * Add bk step to gather brew files for automatic update * Update version to 1.6.2 * add noninteractive option for build scripts * Limit assert message to 1024 chars * Don't unlink what we install via brew unlinking eveything we install makes no sense -- it means things like cmake aren't in the path any longer like the script expects. So don't do that any more. Unfortuately this old script requires that gettext be force linked. So implement that behavior explictly for now * Make sure python-devel is installed for amazon linux builds * fc version 1.6.x * merge missed code * merge missed code * merge missed code * prepare v2.0.2 --- .buildkite/pipeline.yml | 23 +- .github/PULL_REQUEST_TEMPLATE.md | 8 +- .gitmodules | 2 +- CMakeLists.txt | 12 +- CMakeModules/EosioTester.cmake.in | 4 +- CMakeModules/EosioTesterBuild.cmake.in | 6 +- CMakeModules/doxygen.cmake | 2 +- Docker/Dockerfile | 3 +- Docker/README.md | 9 +- Docker/config.ini | 3 - README.md | 22 +- README_CN.md | 21 +- contracts/CMakeLists.txt | 4 - contracts/asserter/asserter.cpp | 2 +- contracts/asserter/asserter.hpp | 2 +- contracts/bancor/CMakeLists.txt | 8 - contracts/bancor/bancor.cpp | 18 - contracts/bancor/bancor.hpp | 22 - contracts/bancor/converter.hpp | 166 - contracts/bancor/eosio.system.abi | 37 - contracts/eosio.system/delegate_bandwidth.cpp | 4 +- contracts/eosio.system/eosio.system.hpp | 2 +- contracts/eosio.system/native.hpp | 2 +- contracts/eosio.system/voting.cpp | 2 +- contracts/eosio.token/eosio.token.cpp | 2 +- contracts/eosio.token/eosio.token.hpp | 2 +- contracts/eosiolib/action.h | 2 +- contracts/eosiolib/action.hpp | 2 +- contracts/eosiolib/chain.h | 2 +- contracts/eosiolib/compiler_builtins.h | 2 +- contracts/eosiolib/core_symbol.hpp.in | 2 +- contracts/eosiolib/crypto.h | 2 +- contracts/eosiolib/currency.hpp | 254 - contracts/eosiolib/datastream.hpp | 2 +- contracts/eosiolib/db.h | 2 +- contracts/eosiolib/eosio.hpp | 2 +- contracts/eosiolib/fixed_key.hpp | 2 +- contracts/eosiolib/memory.h | 2 +- contracts/eosiolib/memory.hpp | 2 +- contracts/eosiolib/multi_index.hpp | 2 +- contracts/eosiolib/permission.h | 2 +- contracts/eosiolib/permission.hpp | 2 +- contracts/eosiolib/print.h | 2 +- contracts/eosiolib/print.hpp | 2 +- contracts/eosiolib/system.h | 2 +- contracts/eosiolib/transaction.h | 2 +- contracts/eosiolib/transaction.hpp | 2 +- contracts/eosiolib/types.h | 2 +- contracts/eosiolib/types.hpp | 2 +- contracts/eosiolib/varint.hpp | 2 +- contracts/infinite/CMakeLists.txt | 5 - contracts/infinite/infinite.cpp | 16 - contracts/noop/noop.cpp | 2 +- contracts/proxy/proxy.cpp | 2 +- contracts/proxy/proxy.hpp | 2 +- contracts/simple.token/CMakeLists.txt | 9 - contracts/simple.token/simple.token.abi | 2 - contracts/simple.token/simple.token.cpp | 49 - contracts/skeleton/skeleton.hpp | 2 +- contracts/social/CMakeLists.txt | 5 - contracts/social/social.cpp | 107 - contracts/stltest/stltest.cpp | 2 +- contracts/test_api/test_action.cpp | 2 +- contracts/test_api/test_api.cpp | 2 +- contracts/test_api/test_api.hpp | 2 +- contracts/test_api/test_api_common.hpp | 2 +- contracts/test_api/test_chain.cpp | 2 +- contracts/test_api/test_checktime.cpp | 2 +- contracts/test_api/test_compiler_builtins.cpp | 2 +- contracts/test_api/test_crypto.cpp | 2 +- contracts/test_api/test_permission.cpp | 2 +- contracts/test_api/test_print.cpp | 2 +- contracts/test_api/test_transaction.cpp | 2 +- contracts/test_api/test_types.cpp | 2 +- contracts/test_api_db/test_api_db.cpp | 2 +- contracts/test_api_mem/test_api_mem.cpp | 2 +- contracts/test_api_mem/test_memory.cpp | 2 +- .../test_api_multi_index.cpp | 2 +- contracts/test_ram_limit/test_ram_limit.cpp | 2 +- contracts/tic_tac_toe/tic_tac_toe.cpp | 4 +- contracts/tic_tac_toe/tic_tac_toe.hpp | 2 +- eosio.version.in | 2 +- eosio_build.sh | 13 +- images/bos-workflow.png | Bin 0 -> 437365 bytes libraries/CMakeLists.txt | 5 +- libraries/abi_generator/CMakeLists.txt | 64 - libraries/abi_generator/abi_generator.cpp | 688 - .../eosio/abi_generator/abi_generator.hpp | 442 - libraries/appbase | 2 +- libraries/chain/CMakeLists.txt | 4 +- libraries/chain/abi_serializer.cpp | 2 +- libraries/chain/apply_context.cpp | 24 +- libraries/chain/asset.cpp | 2 +- libraries/chain/authorization_manager.cpp | 2 +- libraries/chain/block_header.cpp | 2 +- libraries/chain/block_header_state.cpp | 14 +- libraries/chain/block_log.cpp | 4 +- libraries/chain/block_state.cpp | 6 +- libraries/chain/chain_config.cpp | 2 +- libraries/chain/chain_id_type.cpp | 4 +- libraries/chain/controller.cpp | 394 +- libraries/chain/eosio_contract.cpp | 23 +- libraries/chain/fork_database.cpp | 17 +- libraries/chain/genesis_state.cpp | 2 +- libraries/chain/genesis_state_root_key.cpp.in | 2 +- .../chain/include/eosio/chain/abi_def.hpp | 2 +- .../include/eosio/chain/abi_serializer.hpp | 64 +- .../include/eosio/chain/account_object.hpp | 2 +- .../chain/include/eosio/chain/action.hpp | 2 +- .../include/eosio/chain/action_receipt.hpp | 2 +- .../include/eosio/chain/apply_context.hpp | 8 +- libraries/chain/include/eosio/chain/asset.hpp | 4 +- .../chain/include/eosio/chain/authority.hpp | 2 +- .../include/eosio/chain/authority_checker.hpp | 9 +- .../eosio/chain/authorization_manager.hpp | 2 +- libraries/chain/include/eosio/chain/block.hpp | 17 +- .../eosio/chain/block_header_state.hpp | 2 + .../chain/include/eosio/chain/block_log.hpp | 2 +- .../chain/include/eosio/chain/block_state.hpp | 6 +- .../eosio/chain/block_summary_object.hpp | 2 +- .../include/eosio/chain/chain_config.hpp | 48 +- .../include/eosio/chain/chain_id_type.hpp | 4 +- .../include/eosio/chain/chain_snapshot.hpp | 2 +- .../chain/include/eosio/chain/config.hpp | 4 +- .../eosio/chain/contract_table_objects.hpp | 72 +- .../chain/include/eosio/chain/controller.hpp | 41 +- .../include/eosio/chain/core_symbol.hpp.in | 2 +- .../include/eosio/chain/database_utils.hpp | 3 +- .../include/eosio/chain/eosio_contract.hpp | 2 +- .../chain/include/eosio/chain/exceptions.hpp | 6 +- .../chain/include/eosio/chain/fixed_key.hpp | 2 +- .../include/eosio/chain/fork_database.hpp | 6 +- .../chain/generated_transaction_object.hpp | 2 +- .../include/eosio/chain/genesis_state.hpp | 10 +- .../eosio/chain/global_property_object.hpp | 2 +- .../eosio/chain/multi_index_includes.hpp | 2 +- .../include/eosio/chain}/parallel_markers.hpp | 6 +- .../eosio/chain/permission_link_object.hpp | 2 +- .../include/eosio/chain/permission_object.hpp | 2 +- .../include/eosio/chain/producer_object.hpp | 2 +- .../chain/include/eosio/chain/protocol.hpp | 2 +- .../eosio/chain/resource_limits_private.hpp | 4 +- .../eosio/chain/reversible_block_object.hpp | 2 +- .../chain/include/eosio/chain/snapshot.hpp | 2 +- .../chain/include/eosio/chain/symbol.hpp | 4 +- .../include/eosio/chain/thread_utils.hpp | 24 + libraries/chain/include/eosio/chain/trace.hpp | 2 +- .../chain/include/eosio/chain/transaction.hpp | 83 +- .../eosio/chain/transaction_context.hpp | 5 +- .../eosio/chain/transaction_metadata.hpp | 48 +- .../eosio/chain/transaction_object.hpp | 2 +- libraries/chain/include/eosio/chain/types.hpp | 19 +- .../eosio/chain/wasm_eosio_injection.hpp | 11 +- .../include/eosio/chain/wast_to_wasm.hpp | 2 +- libraries/chain/transaction.cpp | 182 +- libraries/chain/transaction_context.cpp | 43 +- libraries/chain/transaction_metadata.cpp | 47 + libraries/chain/wasm_eosio_injection.cpp | 2 +- libraries/chain/wasm_interface.cpp | 78 +- libraries/chain/wast_to_wasm.cpp | 2 +- libraries/fc | 2 +- libraries/softfloat | 2 +- libraries/testing/CMakeLists.txt | 2 +- .../testing/include/eosio/testing/tester.hpp | 38 +- libraries/testing/tester.cpp | 78 +- libraries/utilities/CMakeLists.txt | 32 - libraries/utilities/git_revision.cpp.in | 14 - .../include/eosio/utilities/common.hpp | 22 - .../include/eosio/utilities/git_revision.hpp | 14 - .../eosio/utilities/key_conversion.hpp | 17 - .../eosio/utilities/padding_ostream.hpp | 39 - .../include/eosio/utilities/rand.hpp | 44 - .../include/eosio/utilities/string_escape.hpp | 13 - .../include/eosio/utilities/tempdir.hpp | 15 - .../include/eosio/utilities/words.hpp | 13 - libraries/utilities/key_conversion.cpp | 53 - libraries/utilities/string_escape.cpp | 55 - libraries/utilities/tempdir.cpp | 20 - libraries/utilities/words.cpp | 49764 ---------------- libraries/wabt | 2 +- plugins/CMakeLists.txt | 1 + plugins/COMMUNITY.md | 4 + plugins/bnet_plugin/bnet_plugin.cpp | 62 +- .../include/eosio/bnet_plugin/bnet_plugin.hpp | 2 +- plugins/chain_api_plugin/chain_api_plugin.cpp | 2 +- .../chain_api_plugin/chain_api_plugin.hpp | 2 +- .../include/eosio/chain/plugin_interface.hpp | 8 +- plugins/chain_plugin/chain_plugin.cpp | 205 +- .../eosio/chain_plugin/chain_plugin.hpp | 187 +- .../db_size_api_plugin/db_size_api_plugin.cpp | 2 +- .../db_size_api_plugin/db_size_api_plugin.hpp | 2 +- .../faucet_testnet_plugin.cpp | 3 +- .../faucet_testnet_plugin.hpp | 2 +- .../history_api_plugin/history_api_plugin.cpp | 5 +- .../history_api_plugin/history_api_plugin.hpp | 2 +- plugins/history_plugin/history_plugin.cpp | 13 +- .../account_control_history_object.hpp | 2 +- .../eosio/history_plugin/history_plugin.hpp | 2 +- .../public_key_history_object.hpp | 2 +- .../http_client_plugin/http_client_plugin.cpp | 2 +- .../http_client_plugin/http_client_plugin.hpp | 2 +- plugins/http_plugin/http_plugin.cpp | 7 +- .../include/eosio/http_plugin/http_plugin.hpp | 2 +- .../eosio/login_plugin/login_plugin.hpp | 2 +- plugins/login_plugin/login_plugin.cpp | 2 +- .../eosio/mongo_db_plugin/mongo_db_plugin.hpp | 2 +- plugins/mongo_db_plugin/mongo_db_plugin.cpp | 32 +- .../eosio/net_api_plugin/net_api_plugin.hpp | 2 +- plugins/net_api_plugin/net_api_plugin.cpp | 2 +- .../include/eosio/net_plugin/net_plugin.hpp | 2 +- .../include/eosio/net_plugin/protocol.hpp | 7 +- plugins/net_plugin/net_plugin.cpp | 1172 +- .../producer_api_plugin.hpp | 2 +- .../producer_api_plugin.cpp | 2 +- plugins/producer_plugin/CMakeLists.txt | 2 +- .../eosio/producer_plugin/producer_plugin.hpp | 3 +- plugins/producer_plugin/producer_plugin.cpp | 435 +- plugins/state_history_plugin/.clang-format | 8 + plugins/state_history_plugin/CMakeLists.txt | 8 + .../state_history_log.hpp | 279 + .../state_history_plugin.hpp | 101 + .../state_history_serialization.hpp | 557 + .../state_history_plugin.cpp | 571 + .../state_history_plugin_abi.cpp | 475 + .../eosio/template_plugin/template_plugin.hpp | 2 +- plugins/template_plugin/template_plugin.cpp | 2 +- .../test_control_api_plugin.hpp | 2 +- .../test_control_api_plugin.cpp | 2 +- plugins/test_control_plugin/CMakeLists.txt | 2 +- .../test_control_plugin.hpp | 2 +- .../test_control_plugin.cpp | 2 +- .../txn_test_gen_plugin.hpp | 2 +- .../txn_test_gen_plugin.cpp | 53 +- .../wallet_api_plugin/wallet_api_plugin.hpp | 2 +- .../wallet_api_plugin/wallet_api_plugin.cpp | 2 +- .../include/eosio/wallet_plugin/wallet.hpp | 2 +- .../eosio/wallet_plugin/wallet_api.hpp | 2 +- .../eosio/wallet_plugin/wallet_manager.hpp | 2 +- .../eosio/wallet_plugin/wallet_plugin.hpp | 2 +- plugins/wallet_plugin/se_wallet.cpp | 10 +- plugins/wallet_plugin/wallet.cpp | 2 +- plugins/wallet_plugin/wallet_manager.cpp | 2 +- plugins/wallet_plugin/wallet_plugin.cpp | 2 +- plugins/wallet_plugin/yubihsm_wallet.cpp | 2 +- programs/CMakeLists.txt | 1 - programs/cleos/config.hpp.in | 2 +- programs/cleos/eosc.pot | 8 +- programs/cleos/help_text.cpp | 2 +- programs/cleos/help_text.hpp | 2 +- programs/cleos/httpc.hpp | 2 +- programs/cleos/localize.hpp | 2 +- programs/cleos/main.cpp | 583 +- programs/eosio-abigen/CMakeLists.txt | 28 - programs/eosio-abigen/main.cpp | 106 - programs/eosio-launcher/config.hpp.in | 2 +- programs/eosio-launcher/main.cpp | 2 +- programs/keosd/config.hpp.in | 2 +- programs/keosd/main.cpp | 2 +- programs/nodeos/CMakeLists.txt | 1 + programs/nodeos/config.hpp.in | 2 +- programs/nodeos/main.cpp | 3 - scripts/abi_to_rc/README.md | 14 - scripts/abi_to_rc/abi_to_rc.py | 135 - scripts/abi_to_rc/rc-action-template.md | 14 - scripts/abi_to_rc/rc-overview-template.md | 14 - scripts/abigen.sh | 22 - scripts/boost.rb | 131 + scripts/eosio_build_amazon.sh | 11 +- scripts/eosio_build_centos.sh | 6 +- scripts/eosio_build_darwin.sh | 18 +- scripts/eosio_build_fedora.sh | 3 +- scripts/eosio_build_ubuntu.sh | 1 + scripts/generate_deb.sh | 31 +- scripts/generate_package.sh.in | 12 +- scripts/generate_rpm.sh | 18 +- scripts/ricardeos/README.md | 20 - scripts/ricardeos/ricardeos.py | 164 - tests/CMakeLists.txt | 5 +- tests/Cluster.py | 5 +- tests/Node.py | 87 +- tests/chain_plugin_tests.cpp | 9 - tests/chain_tests/proof_tests.cpp | 340 - tests/distributed-transactions-remote-test.py | 2 +- tests/get_table_tests.cpp | 345 +- tests/launcher_test.py | 3 +- tests/main.cpp | 2 +- tests/nodeos_forked_chain_test.py | 5 + tests/nodeos_run_remote_test.py | 2 +- tests/nodeos_run_test.py | 2 +- tests/p2p_tests/fuzz_test_generic.sh | 11 - tests/p2p_tests/pump/run_test.pl | 285 - tests/validate-dirty-db.py | 17 +- tests/wallet_tests.cpp | 8 +- tools/CMakeLists.txt | 14 - tools/eosiocpp.in | 204 - tools/print_floats.cpp | 102 - tools/validate_reflection.py | 698 + tutorials/bios-boot-tutorial/.gitignore | 1 + tutorials/bios-boot-tutorial/README.md | 39 +- .../bios-boot-tutorial/bios-boot-tutorial.py | 54 +- unittests/CMakeLists.txt | 4 +- unittests/abi_tests.cpp | 1297 +- unittests/actiondemo/actiondemo.cpp | 2 - unittests/api_tests.cpp | 148 +- unittests/block_tests.cpp | 14 +- unittests/block_timestamp_tests.cpp | 2 +- unittests/bootseq_tests.cpp | 2 - .../contracts/deferred_test/deferred_test.abi | 24 +- .../contracts/deferred_test/deferred_test.cpp | 10 +- unittests/database_tests.cpp | 5 +- unittests/delay_tests.cpp | 4 +- unittests/eosio.sudo_tests.cpp | 367 - unittests/eosio.system_tests.cpp | 2585 - unittests/eosio.token_tests.cpp | 268 - unittests/eosio_system_tester.hpp | 2 +- unittests/forked_tests.cpp | 99 +- unittests/include/config.hpp.in | 2 +- unittests/main.cpp | 2 +- unittests/message_buffer_tests.cpp | 2 +- unittests/misc_tests.cpp | 45 +- unittests/multisig_tests.cpp | 626 - unittests/producer_schedule_tests.cpp | 132 + unittests/ram_tests.cpp | 5 +- unittests/snapshot_tests.cpp | 6 +- unittests/special_accounts_tests.cpp | 4 +- unittests/tic_tac_toe_tests.cpp | 5 - unittests/wasm_tests.cpp | 73 - unittests/whitelist_blacklist_tests.cpp | 299 + 328 files changed, 6825 insertions(+), 60899 deletions(-) delete mode 100644 contracts/bancor/CMakeLists.txt delete mode 100644 contracts/bancor/bancor.cpp delete mode 100644 contracts/bancor/bancor.hpp delete mode 100644 contracts/bancor/converter.hpp delete mode 100644 contracts/bancor/eosio.system.abi delete mode 100644 contracts/eosiolib/currency.hpp delete mode 100644 contracts/infinite/CMakeLists.txt delete mode 100644 contracts/infinite/infinite.cpp delete mode 100644 contracts/simple.token/CMakeLists.txt delete mode 100644 contracts/simple.token/simple.token.abi delete mode 100644 contracts/simple.token/simple.token.cpp delete mode 100644 contracts/social/CMakeLists.txt delete mode 100644 contracts/social/social.cpp create mode 100644 images/bos-workflow.png delete mode 100644 libraries/abi_generator/CMakeLists.txt delete mode 100644 libraries/abi_generator/abi_generator.cpp delete mode 100644 libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp rename libraries/{utilities/include/eosio/utilities => chain/include/eosio/chain}/parallel_markers.hpp (92%) create mode 100644 libraries/chain/include/eosio/chain/thread_utils.hpp create mode 100644 libraries/chain/transaction_metadata.cpp delete mode 100644 libraries/utilities/CMakeLists.txt delete mode 100644 libraries/utilities/git_revision.cpp.in delete mode 100644 libraries/utilities/include/eosio/utilities/common.hpp delete mode 100644 libraries/utilities/include/eosio/utilities/git_revision.hpp delete mode 100644 libraries/utilities/include/eosio/utilities/key_conversion.hpp delete mode 100644 libraries/utilities/include/eosio/utilities/padding_ostream.hpp delete mode 100644 libraries/utilities/include/eosio/utilities/rand.hpp delete mode 100644 libraries/utilities/include/eosio/utilities/string_escape.hpp delete mode 100644 libraries/utilities/include/eosio/utilities/tempdir.hpp delete mode 100644 libraries/utilities/include/eosio/utilities/words.hpp delete mode 100644 libraries/utilities/key_conversion.cpp delete mode 100644 libraries/utilities/string_escape.cpp delete mode 100644 libraries/utilities/tempdir.cpp delete mode 100644 libraries/utilities/words.cpp create mode 100644 plugins/state_history_plugin/.clang-format create mode 100644 plugins/state_history_plugin/CMakeLists.txt create mode 100644 plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp create mode 100644 plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp create mode 100644 plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp create mode 100644 plugins/state_history_plugin/state_history_plugin.cpp create mode 100644 plugins/state_history_plugin/state_history_plugin_abi.cpp delete mode 100644 programs/eosio-abigen/CMakeLists.txt delete mode 100644 programs/eosio-abigen/main.cpp delete mode 100644 scripts/abi_to_rc/README.md delete mode 100644 scripts/abi_to_rc/abi_to_rc.py delete mode 100644 scripts/abi_to_rc/rc-action-template.md delete mode 100644 scripts/abi_to_rc/rc-overview-template.md delete mode 100755 scripts/abigen.sh create mode 100644 scripts/boost.rb delete mode 100644 scripts/ricardeos/README.md delete mode 100755 scripts/ricardeos/ricardeos.py delete mode 100644 tests/chain_tests/proof_tests.cpp delete mode 100644 tests/p2p_tests/fuzz_test_generic.sh delete mode 100755 tests/p2p_tests/pump/run_test.pl delete mode 100755 tools/eosiocpp.in delete mode 100644 tools/print_floats.cpp create mode 100755 tools/validate_reflection.py delete mode 100644 unittests/eosio.sudo_tests.cpp delete mode 100644 unittests/eosio.system_tests.cpp delete mode 100644 unittests/eosio.token_tests.cpp delete mode 100644 unittests/multisig_tests.cpp diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 1cd49460163..893a19f9ff9 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -398,6 +398,7 @@ steps: - "os=high-sierra" artifact_paths: - "build/packages/*.tar.gz" + - "build/packages/*.rb" timeout: 60 - command: | @@ -412,6 +413,7 @@ steps: - "os=mojave" artifact_paths: - "build/packages/*.tar.gz" + - "build/packages/*.rb" timeout: 60 - command: | @@ -442,7 +444,7 @@ steps: cd /data/job/build/packages && bash generate_package.sh deb label: ":ubuntu: 18.04 Package builder" agents: - - "role=linux-builder" + queue: "automation-large-builder-fleet" artifact_paths: - "build/packages/*.deb" plugins: @@ -469,7 +471,7 @@ steps: cd /data/job/build/packages && bash generate_package.sh rpm label: ":fedora: Package builder" agents: - - "role=linux-builder" + queue: "automation-large-builder-fleet" artifact_paths: - "build/packages/x86_64/*.rpm" plugins: @@ -496,7 +498,7 @@ steps: cd /data/job/build/packages && bash generate_package.sh rpm label: ":centos: Package builder" agents: - - "role=linux-builder" + queue: "automation-large-builder-fleet" artifact_paths: - "build/packages/x86_64/*.rpm" plugins: @@ -507,3 +509,18 @@ steps: OS: "el7" PKGTYPE: "rpm" timeout: 60 + + - wait + + - command: | + echo "--- :arrow_down: Downloading brew files" && \ + buildkite-agent artifact download "build/packages/eosio.rb" . --step ":darwin: High Sierra Package Builder" && \ + mv build/packages/eosio.rb build/packages/eosio_highsierra.rb && \ + buildkite-agent artifact download "build/packages/eosio.rb" . --step ":darwin: Mojave Package Builder" + label: ":darwin: Brew Updater" + agents: + queue: "automation-large-builder-fleet" + artifact_paths: + - "build/packages/eosio_highsierra.rb" + - "build/packages/eosio.rb" + timeout: 60 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9ffbb5ffb6b..7e186303e51 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,20 +1,20 @@ -**Change Description** +## Change Description -**Consensus Changes** +## Consensus Changes -**API Changes** +## API Changes -**Documentation Additions** +## Documentation Additions diff --git a/.gitmodules b/.gitmodules index 7d0f8a37f7b..205a731ffce 100644 --- a/.gitmodules +++ b/.gitmodules @@ -29,4 +29,4 @@ url = https://github.com/EOSIO/fc [submodule "libraries/wabt"] path = libraries/wabt - url = http://github.com/EOSIO/wabt + url = https://github.com/EOSIO/wabt diff --git a/CMakeLists.txt b/CMakeLists.txt index 0309bb0b5e4..daacda9a0c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules") if (UNIX) if (APPLE) if (LLVM_DIR STREQUAL "" OR NOT LLVM_DIR) - set(LLVM_DIR "/usr/local/Cellar/llvm@4/4.0.1/lib/cmake/llvm") + set(LLVM_DIR "/usr/local/opt/llvm@4/lib/cmake/llvm/") endif() endif() endif() @@ -33,9 +33,15 @@ set( CMAKE_CXX_STANDARD 14 ) set( CMAKE_CXX_EXTENSIONS ON ) set( CXX_STANDARD_REQUIRED ON) -set(VERSION_MAJOR 1) +set(VERSION_MAJOR 2) set(VERSION_MINOR 0) -set(VERSION_PATCH 3) +set(VERSION_PATCH 2) + +if(VERSION_SUFFIX) + set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") +else() + set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") +endif() set( CLI_CLIENT_EXECUTABLE_NAME cleos ) set( NODE_EXECUTABLE_NAME nodeos ) diff --git a/CMakeModules/EosioTester.cmake.in b/CMakeModules/EosioTester.cmake.in index ac2bc0221fa..d767251cf54 100644 --- a/CMakeModules/EosioTester.cmake.in +++ b/CMakeModules/EosioTester.cmake.in @@ -1,10 +1,10 @@ cmake_minimum_required( VERSION 3.5 ) -message(STATUS "Setting up Eosio Tester @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@ at @EOS_ROOT_DIR@") +message(STATUS "Setting up Eosio Tester @VERSION_FULL@ at @EOS_ROOT_DIR@") set(CMAKE_CXX_COMPILER @CMAKE_CXX_COMPILER@) set(CMAKE_C_COMPILER @CMAKE_C_COMPILER@) -set(EOSIO_VERSION "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@") +set(EOSIO_VERSION "@VERSION_FULL@") enable_testing() diff --git a/CMakeModules/EosioTesterBuild.cmake.in b/CMakeModules/EosioTesterBuild.cmake.in index 04ac7da6fe5..290cefa576c 100644 --- a/CMakeModules/EosioTesterBuild.cmake.in +++ b/CMakeModules/EosioTesterBuild.cmake.in @@ -1,10 +1,10 @@ cmake_minimum_required( VERSION 3.5 ) -message(STATUS "Setting up Eosio Tester @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@ at @EOS_ROOT_DIR@") +message(STATUS "Setting up Eosio Tester @VERSION_FULL@ at @EOS_ROOT_DIR@") set(CMAKE_CXX_COMPILER @CMAKE_CXX_COMPILER@) set(CMAKE_C_COMPILER @CMAKE_C_COMPILER@) -set(EOSIO_VERSION "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@") +set(EOSIO_VERSION "@VERSION_FULL@") enable_testing() @@ -98,8 +98,8 @@ macro(add_eosio_test test_name) ${liblogging} ${libchainbase} ${libbuiltins} - ${GMP_LIBRARIES} ${libsecp256k1} + ${GMP_LIBRARIES} LLVMX86Disassembler LLVMX86AsmParser diff --git a/CMakeModules/doxygen.cmake b/CMakeModules/doxygen.cmake index 2857f668364..d3014b4efce 100644 --- a/CMakeModules/doxygen.cmake +++ b/CMakeModules/doxygen.cmake @@ -5,7 +5,7 @@ include(FindDoxygen) if(NOT DOXYGEN_FOUND) message(STATUS "Doxygen not found. Contract documentation will not be generated.") else() - set(DOXY_EOS_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" CACHE INTERNAL "Version string used in PROJECT_NUMBER.") + set(DOXY_EOS_VERSION "${VERSION_FULL}" CACHE INTERNAL "Version string used in PROJECT_NUMBER.") # CMake strips trailing path separators off of variables it knows are paths, # so the trailing '/' Doxygen expects is embedded in the doxyfile. set(DOXY_DOC_DEST_DIR "${CMAKE_BINARY_DIR}/docs" CACHE PATH "Path to the doxygen output") diff --git a/Docker/Dockerfile b/Docker/Dockerfile index 67f7714c894..81b09c4171a 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -10,7 +10,8 @@ RUN git clone -b $branch https://github.com/boscore/bos.git --recursive \ && cmake -H. -B"/tmp/build" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/tmp/build -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \ -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" \ - && cmake --build /tmp/build --target install && rm /tmp/build/bin/eosiocpp + && cmake --build /tmp/build --target install + FROM ubuntu:18.04 diff --git a/Docker/README.md b/Docker/README.md index ffdfe07e2c5..5be2cbe6a1f 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -17,13 +17,14 @@ Simple and fast setup of BOSCore on Docker is also available. ```bash git clone https://github.com/boscore/bos.git --recursive --depth 1 cd bos/Docker -docker build . -t boscore/bos +docker build . -t boscore/bos -s BOS ``` -The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v1.0.3 tag, you could do the following: +The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v2.0.2 tag, you could do the following: ```bash -docker build -t boscore/bos:v1.0.3 --build-arg branch=v1.0.3 . +docker build -t boscore/bos:v2.0.2 --build-arg branch=v2.0.2 . + ``` By default, the symbol in eosio.system is set to SYS. You can override this using the symbol argument while building the docker image. @@ -197,4 +198,4 @@ The `blocks` data are stored under `--data-dir` by default, and the wallet files ### About MongoDB Plugin -Currently, the mongodb plugin is disabled in `config.ini` by default, you have to change it manually in `config.ini` or you can mount a `config.ini` file to `/opt/eosio/bin/data-dir/config.ini` in the docker-compose file. +Currently, the mongodb plugin is disabled in `config.ini` by default, you have to change it manually in `config.ini` or you can mount a `config.ini` file to `/opt/eosio/bin/data-dir/config.ini` in the docker-compose file. \ No newline at end of file diff --git a/Docker/config.ini b/Docker/config.ini index 71ae5c6c0ed..9014d16a888 100644 --- a/Docker/config.ini +++ b/Docker/config.ini @@ -113,9 +113,6 @@ network-version-match = 0 # number of blocks to retrieve in a chunk from any individual peer during synchronization (eosio::net_plugin) sync-fetch-span = 100 -# maximum sizes of transaction or block messages that are sent without first sending a notice (eosio::net_plugin) -max-implicit-request = 1500 - # Enable block production, even if the chain is stale. (eosio::producer_plugin) enable-stale-production = false diff --git a/README.md b/README.md index eecfaf7ec1c..eae2abca3f3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # BOSCore - Born for DApps. Born for Usability. -## BOSCore Version: v1.0.3 -### Basic EOSIO Version: v1.4.4 +## BOSCore Version: v2.0.2 +### Basic EOSIO Version: v1.6.2 # Background The emergence of EOS has brought new imagination to the blockchain. In just a few months since the main network was launched, the version has undergone dozens of upgrades, not only the stability has been greatly improved, but also the new functions have been gradually realized. The node team is also actively involved in building the EOSIO ecosystem. What is even more exciting is that EOS has attracted more and more development teams. There are already hundreds of DApp running on the EOS main network. The transaction volume and circulation market value far exceed Ethereum, and the space for development is growing broader. @@ -20,18 +20,28 @@ As BOS continues to develop, developer rewards will be appropriately adjusted to ## Links 1. [Website](https://boscore.io) -2. [Developer Telegram Group](https://t.me/BOSCoreDev) -3. [WhitePaper](https://github.com/boscore/Documentation/blob/master/BOSCoreTechnicalWhitePaper.md) -4. [白皮书](https://github.com/boscore/Documentation/blob/master/zh-CN/BOSCoreTechnicalWhitePaper.md) +2. [Developer Telegram Group](https://t.me/BOSDevelopers) +3. [Community Telegram Group](https://t.me/boscorecommunity) +4. [WhitePaper](https://github.com/boscore/Documentation/blob/master/BOSCoreTechnicalWhitePaper.md) +5. [白皮书](https://github.com/boscore/Documentation/blob/master/zh-CN/BOSCoreTechnicalWhitePaper.md) ## Start 1. Build from code : `bash ./eosio_build.sh -s BOS` 2. Docker Style,check [Docker](./Docker/README.md) +## BOSCore Workflow +BOSCore encourage community developer actively participate in contributing the code, members should follow the workflow below. +![BOSCore Workflow](./images/bos-workflow.png) + +Attention: +1. Only allow Feature Branch or bug fix to submit PR to Develop Branch. +2. Rebase is required before submitting PR to Develop Branch. +3. Treat update of eosio/eos code as new feature. +4. Emergent issues must repaired by adopting hotfixes mode. + BOSCore bases on EOSIO, so you can also referer: [Getting Started](https://developers.eos.io/eosio-nodeos/docs/overview-1) [EOSIO Developer Portal](https://developers.eos.io). - diff --git a/README_CN.md b/README_CN.md index a1f55247bcf..2c1b2434dc8 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,7 +1,7 @@ # BOSCore - 更可用的链,为DApp而生。 -## BOSCore Version: v1.0.3 -### Basic EOSIO Version: v1.4.4 +## BOSCore Version: v2.0.2 +### Basic EOSIO Version: v1.6.2 # 背景 EOS的出现给区块链带来了新的想象力,主网启动短短几个月以来,版本经历了几十次升级,不仅稳定性得到了很大提高,并且新功能也逐步实现,各个节点团队也积极参与建设EOSIO生态。让人更加兴奋的是,EOS已经吸引了越来越多的开发团队,当前已经有数百个DApp在EOS主网上面运行,其交易量和流通市值远超以太坊,可发展的空间愈来愈广阔。 @@ -20,14 +20,25 @@ BOS链的代码完全由社区贡献并维护,每个生态参与者都可以 ## 资源 1. [官网](https://boscore.io) -2. [开发者社群](https://t.me/BOSCoreDev) -3. [WhitePaper](https://github.com/boscore/Documentation/blob/master/BOSCoreTechnicalWhitePaper.md) -4. [白皮书](https://github.com/boscore/Documentation/blob/master/zh-CN/BOSCoreTechnicalWhitePaper.md) +2. [Developer Telegram Group](https://t.me/BOSDevelopers) +3. [Community Telegram Group](https://t.me/boscorecommunity) +4. [WhitePaper](https://github.com/boscore/Documentation/blob/master/BOSCoreTechnicalWhitePaper.md) +5. [白皮书](https://github.com/boscore/Documentation/blob/master/zh-CN/BOSCoreTechnicalWhitePaper.md) ## 开始 1. 源码直接编译: `bash ./eosio_build.sh -s BOS` 2. Docker方式部署,参看 [Docker](./Docker/README.md) +## BOSCore 开发流程 +BOSCore 鼓励社区开发者参与代码贡献,社区成员应当遵循以下工作流: +![BOSCore Workflow](./images/bos-workflow.png) + +注意: +1. 只有待发布的 Feature Branch 或者Bug修复才应该向 Develop Branch 提交 +2. 向 Develop Branch 提交 PR 之前需要现在本地执行 rebase 操作 +3. EOSIO 主网版本作为一个 Feature Branch 来对待 +4. 紧急问题修复采用 hotfixes 模式 + BOSCore是基于EOSIO技术的扩展,所以EOSIO的相关资料也可以参考: [EOSIO 开始](https://developers.eos.io/eosio-nodeos/docs/overview-1) diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt index bd84d155e85..443330c886a 100644 --- a/contracts/CMakeLists.txt +++ b/contracts/CMakeLists.txt @@ -7,7 +7,6 @@ set(STANDARD_INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts ${CMAKE_BINARY_DIR}/c add_subdirectory(eosiolib) add_subdirectory(musl) add_subdirectory(libc++) -add_subdirectory(simple.token) add_subdirectory(eosio.token) add_subdirectory(eosio.msig) add_subdirectory(eosio.sudo) @@ -18,17 +17,14 @@ add_subdirectory(identity) add_subdirectory(stltest) add_subdirectory(test.inline) -#add_subdirectory(bancor) add_subdirectory(hello) add_subdirectory(asserter) -add_subdirectory(infinite) add_subdirectory(proxy) add_subdirectory(test_api) add_subdirectory(test_api_mem) add_subdirectory(test_api_db) add_subdirectory(test_api_multi_index) add_subdirectory(test_ram_limit) -#add_subdirectory(social) add_subdirectory(eosio.bios) add_subdirectory(noop) add_subdirectory(tic_tac_toe) diff --git a/contracts/asserter/asserter.cpp b/contracts/asserter/asserter.cpp index f64ea509a1f..c89db1fc709 100644 --- a/contracts/asserter/asserter.cpp +++ b/contracts/asserter/asserter.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include /// defines assert_def struct (abi) diff --git a/contracts/asserter/asserter.hpp b/contracts/asserter/asserter.hpp index 99680870c04..01d4b343e3f 100644 --- a/contracts/asserter/asserter.hpp +++ b/contracts/asserter/asserter.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/contracts/bancor/CMakeLists.txt b/contracts/bancor/CMakeLists.txt deleted file mode 100644 index b845361e8f0..00000000000 --- a/contracts/bancor/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET bancor - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc libc++ eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/bancor/bancor.cpp b/contracts/bancor/bancor.cpp deleted file mode 100644 index 15bc9e802c8..00000000000 --- a/contracts/bancor/bancor.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ - -#include - -namespace bancor { - -extern "C" { - - /// The apply method implements the dispatch of events to this contract - void apply( uint64_t r, uint64_t c, uint64_t a ) { - bancor::example_converter::apply( c, a ); - } -} - -} diff --git a/contracts/bancor/bancor.hpp b/contracts/bancor/bancor.hpp deleted file mode 100644 index b6030908b81..00000000000 --- a/contracts/bancor/bancor.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -#include -#include -#include -#include - -#include -#include - -namespace bancor { - typedef eosio::generic_currency< eosio::token > other_currency; - typedef eosio::generic_currency< eosio::token > relay_currency; - typedef eosio::generic_currency< eosio::token > cur_currency; - - typedef converter example_converter; -} /// bancor - diff --git a/contracts/bancor/converter.hpp b/contracts/bancor/converter.hpp deleted file mode 100644 index 774fc910e32..00000000000 --- a/contracts/bancor/converter.hpp +++ /dev/null @@ -1,166 +0,0 @@ -#pragma once -namespace bancor { - template - class converter_contract { - public: - typedef ConverterCurrency converter_currency; - typedef FirstCurrency first_currency; - typedef SecondCurrency second_currency; - - - static const account_name converter_account = converter_currency::code; - - struct converter_state { - typename converter_currency::token_type supply; /// total supply held by all users - typename converter_currency::token_type balance; /// supply held by converter in its own balance - }; - - struct converter_args { - eosio::account_name to_currency_account; - eosio::symbol_name to_currency_symbol; - uint64_t min_return_currency; - }; - - - template - struct connector { - typedef CurrencyType currency_type; - typedef typename converter_currency::token_type converter_token_type; - typedef typename currency_type::token_type in_token_type; - - converter_token_type convert_to_converter( in_token_type in, converter_state& state ) { - in_token_type balance = currency_type::get_balance( converter_account ); - - /// balance already changed when transfer executed, get pre-transfer balance - in_token_type previous_balance = balance - in; - - auto init_price = (previous_balance * Base) / (Weight * state.supply); - auto init_out = init_price * in; - - auto out_price = (balance*Base) / (Weight * (state.supply+init_out) ); - auto final_out = out_price * in; - - state.balance += final_out; - state.supply += final_out; - - return final_out; - } - - - in_token_type convert_from_converter( converter_token_type converter_in, converter_state& state ) { - in_token_type to_balance = CurrencyType::get_balance( converter_account ); - - auto init_price = (to_balance * Base) / (Weight * state.supply); - in_token_type init_out = init_price * converter_in; - - state.supply -= converter_in; - state.balance -= converter_in; - - auto out_price = ((to_balance-init_out) * Base) / ( Weight * (state.supply) ); - - return out_price * converter_in; - } - - }; - - - - /** - * This is called when we receive RELAY tokens from user and wish to - * convert to one of the connector currencies. - */ - static void on_convert( const typename converter_currency::transfer& trans, - const converter_args& args, - converter_state& state ) { - - if( args.to_currency_type == first_currency ) { - auto output = first_connector::convert_from_converter( trans.quantity, state ); - save_and_send( trans.from, state, output, args.min_return ); - } - else if( args.to_currency_type == second_currency ) { - auto output = second_connector::convert_from_converter( trans.quantity, state ); - save_and_send( trans.from, state, output, args.min_return ); - } - else { - eosio_assert( false, "invalid to currency" ); - } - } - - - /** - * This is called when the converter receives one of the connector currencies and it - * will send either converter tokens or a different connector currency in response. - */ - template - static void on_convert( const typename ConnectorType::currency_type::transfer& trans, - const converter_args& args, - converter_state& state ) - { - /// convert to converter - auto converter_out = ConnectorType::convert_to_converter( trans.quantity, state ); - - if( args.to_currency_type == converter_currency ) - { - save_and_send( trans.from, state, converter_out, args.min_return ); - } - else - { - auto output = ConnectorType::convert_from_converter( converter_out, state ); - save_and_send( trans.from, state, output, args.min_return ); - } - } - - - /** - * This method factors out the boiler plate for parsing args and loading the - * initial state before dispatching to the proper on_convert case - */ - template - static void start_convert( const typename CurrencyType::transfer_memo& trans ) { - auto args = unpack( trans.memo ); - eosio_assert( args.to_currency_type != trans.quantity.token_type(), "cannot convert to self" ); - - auto state = read_converter_state(); - on_convert( trans, args, state ); - } - - - /** - * converter_account first needs to call the currency handler to perform - * user-to-user transfers of the converter token, then if a transfer is sending - * the token back to the converter contract, it should convert like everything else. - * - * This method should be called from apply( code, action ) for each of the - * transfer types that we support (for each currency) - */ - static void on( const typename converter_currency::transfer_memo& trans ) { - converter_currency::on( trans ); - if( trans.to == converter_account ) { - start_convert( trans ); - } - } - - /** - * All other currencies simply call start_convert if to == converter_account - */ - template - static void on( const typename Currency::transfer_memo& trans ) { - if( trans.to == converter_account ) { - start_convert( trans ); - } else { - eosio_assert( trans.from == converter_account, - "received unexpected notification of transfer" ); - } - } - - static void apply( account_name code, action_name action ) { - if( !dispatch( converter_contract, - converter_currency::transfer, - converter_currency::issue, - first_currency::transfer, - second_currency::transfer ) { - eosio_assert( false, "received unexpected action" ); - } - } - }; /// converter_contract -} /// namespace bancor diff --git a/contracts/bancor/eosio.system.abi b/contracts/bancor/eosio.system.abi deleted file mode 100644 index c8d8e4b16e9..00000000000 --- a/contracts/bancor/eosio.system.abi +++ /dev/null @@ -1,37 +0,0 @@ -{ - "types": [{ - "new_type_name": "account_name", - "type": "name" - } - ], - "structs": [{ - "name": "transfer", - "base": "", - "fields": [ - {"name":"from", "type":"account_name"}, - {"name":"to", "type":"account_name"}, - {"name":"quantity", "type":"uint64"} - ] - },{ - "name": "account", - "base": "", - "fields": [ - {"name":"key", "type":"name"}, - {"name":"balance", "type":"uint64"} - ] - } - ], - "actions": [{ - "name": "transfer", - "type": "transfer" - } - ], - "tables": [{ - "name": "account", - "type": "account", - "index_type": "i64", - "key_names" : ["key"], - "key_types" : ["name"] - } - ] -} \ No newline at end of file diff --git a/contracts/eosio.system/delegate_bandwidth.cpp b/contracts/eosio.system/delegate_bandwidth.cpp index 95a40781530..a2920d70295 100644 --- a/contracts/eosio.system/delegate_bandwidth.cpp +++ b/contracts/eosio.system/delegate_bandwidth.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include "eosio.system.hpp" @@ -205,7 +205,7 @@ namespace eosiosystem { const int64_t max_claimable = 100'000'000'0000ll; const int64_t claimable = int64_t(max_claimable * double(now()-base_time) / (10*seconds_per_year) ); - eosio_assert( max_claimable - claimable <= stake, "bosbosbosbos can only claim their tokens over 10 years" ); + eosio_assert( max_claimable - claimable <= stake, "bos can only claim their tokens over 10 years" ); } void system_contract::changebw( account_name from, account_name receiver, diff --git a/contracts/eosio.system/eosio.system.hpp b/contracts/eosio.system/eosio.system.hpp index 66964e39659..2b6d16d3d59 100644 --- a/contracts/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/eosio.system.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/eosio.system/native.hpp b/contracts/eosio.system/native.hpp index e6395807395..e2bcb319575 100644 --- a/contracts/eosio.system/native.hpp +++ b/contracts/eosio.system/native.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/eosio.system/voting.cpp b/contracts/eosio.system/voting.cpp index feeb53fc3d8..8076f79886d 100644 --- a/contracts/eosio.system/voting.cpp +++ b/contracts/eosio.system/voting.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include "eosio.system.hpp" diff --git a/contracts/eosio.token/eosio.token.cpp b/contracts/eosio.token/eosio.token.cpp index 351d81c47c5..4570b19b5c9 100644 --- a/contracts/eosio.token/eosio.token.cpp +++ b/contracts/eosio.token/eosio.token.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include "eosio.token.hpp" diff --git a/contracts/eosio.token/eosio.token.hpp b/contracts/eosio.token/eosio.token.hpp index 15875134777..48312c9edb4 100644 --- a/contracts/eosio.token/eosio.token.hpp +++ b/contracts/eosio.token/eosio.token.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/eosiolib/action.h b/contracts/eosiolib/action.h index 3e686fe469d..f8deba837b8 100644 --- a/contracts/eosiolib/action.h +++ b/contracts/eosiolib/action.h @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/contracts/eosiolib/action.hpp b/contracts/eosiolib/action.hpp index 11028f09e93..d4538c2972e 100644 --- a/contracts/eosiolib/action.hpp +++ b/contracts/eosiolib/action.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/contracts/eosiolib/chain.h b/contracts/eosiolib/chain.h index 8477968be9e..ec4f219b4b9 100644 --- a/contracts/eosiolib/chain.h +++ b/contracts/eosiolib/chain.h @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/eosiolib/compiler_builtins.h b/contracts/eosiolib/compiler_builtins.h index 3e0d9435357..c2dc09bb356 100644 --- a/contracts/eosiolib/compiler_builtins.h +++ b/contracts/eosiolib/compiler_builtins.h @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/eosiolib/core_symbol.hpp.in b/contracts/eosiolib/core_symbol.hpp.in index 4a60220b6a9..3262d2aad10 100644 --- a/contracts/eosiolib/core_symbol.hpp.in +++ b/contracts/eosiolib/core_symbol.hpp.in @@ -1,5 +1,5 @@ /** @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE * * \warning This file is machine generated. DO NOT EDIT. See core_symbol.hpp.in for changes. */ diff --git a/contracts/eosiolib/crypto.h b/contracts/eosiolib/crypto.h index 916c25954f7..0133762c43b 100644 --- a/contracts/eosiolib/crypto.h +++ b/contracts/eosiolib/crypto.h @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/contracts/eosiolib/currency.hpp b/contracts/eosiolib/currency.hpp deleted file mode 100644 index 1328c493876..00000000000 --- a/contracts/eosiolib/currency.hpp +++ /dev/null @@ -1,254 +0,0 @@ -#pragma once -#include -#include -#include - -namespace eosio { - using std::string; - using std::array; - - /** - * This contract enables the creation, issuance, and transfering of many different tokens. - * @deprecated This class is deprecated in favor of eosio.token in Dawn 3.0 - */ - class currency { - public: - currency( account_name contract ) - :_contract(contract) - { } - - struct create { - account_name issuer; - asset maximum_supply; - // array issuer_agreement_hash; - uint8_t issuer_can_freeze = true; - uint8_t issuer_can_recall = true; - uint8_t issuer_can_whitelist = true; - - /*(issuer_agreement_hash)*/ - EOSLIB_SERIALIZE( create, (issuer)(maximum_supply)(issuer_can_freeze)(issuer_can_recall)(issuer_can_whitelist) ) - }; - - struct transfer - { - account_name from; - account_name to; - asset quantity; - string memo; - - EOSLIB_SERIALIZE( transfer, (from)(to)(quantity)(memo) ) - }; - - struct issue { - account_name to; - asset quantity; - string memo; - - EOSLIB_SERIALIZE( issue, (to)(quantity)(memo) ) - }; - - struct fee_schedule { - uint64_t primary_key()const { return 0; } - - array fee_per_length; - EOSLIB_SERIALIZE( fee_schedule, (fee_per_length) ) - }; - - struct account { - asset balance; - bool frozen = false; - bool whitelist = true; - - uint64_t primary_key()const { return balance.symbol.name(); } - - EOSLIB_SERIALIZE( account, (balance)(frozen)(whitelist) ) - }; - - struct currency_stats { - asset supply; - asset max_supply; - account_name issuer; - bool can_freeze = true; - bool can_recall = true; - bool can_whitelist = true; - bool is_frozen = false; - bool enforce_whitelist = false; - - uint64_t primary_key()const { return supply.symbol.name(); } - - EOSLIB_SERIALIZE( currency_stats, (supply)(max_supply)(issuer)(can_freeze)(can_recall)(can_whitelist)(is_frozen)(enforce_whitelist) ) - }; - - typedef eosio::multi_index accounts; - typedef eosio::multi_index stats; - - - asset get_balance( account_name owner, symbol_name symbol )const { - accounts t( _contract, owner ); - return t.get(symbol).balance; - } - - asset get_supply( symbol_name symbol )const { - accounts t( _contract, symbol ); - return t.get(symbol).balance; - } - - static void inline_transfer( account_name from, account_name to, extended_asset amount, string memo = string(), permission_name perm = N(active) ) { - action act( permission_level( from, perm ), amount.contract, N(transfer), transfer{from,to,amount,memo} ); - act.send(); - } - - void inline_transfer( account_name from, account_name to, asset amount, string memo = string(), permission_name perm = N(active) ) { - action act( permission_level( from, perm ), _contract, N(transfer), transfer{from,to,amount,memo} ); - act.send(); - } - - - bool apply( account_name contract, action_name act ) { - if( contract != _contract ) - return false; - - switch( act ) { - case N(issue): - print( "issue\n"); - on( unpack_action_data() ); - return true; - case N(transfer): - print( "transfer\n"); - on( unpack_action_data() ); - return true; - case N(create): - print( "create\n"); - on( unpack_action_data() ); - return true; - } - return false; - } - - /** - * This is factored out so it can be used as a building block - */ - void create_currency( const create& c ) { - auto sym = c.maximum_supply.symbol; - eosio_assert( sym.is_valid(), "invalid symbol name" ); - - stats statstable( _contract, sym.name() ); - auto existing = statstable.find( sym.name() ); - eosio_assert( existing == statstable.end(), "token with symbol already exists" ); - - statstable.emplace( c.issuer, [&]( auto& s ) { - s.supply.symbol = c.maximum_supply.symbol; - s.max_supply = c.maximum_supply; - s.issuer = c.issuer; - s.can_freeze = c.issuer_can_freeze; - s.can_recall = c.issuer_can_recall; - s.can_whitelist = c.issuer_can_whitelist; - }); - } - - void issue_currency( const issue& i ) { - auto sym = i.quantity.symbol.name(); - stats statstable( _contract, sym ); - const auto& st = statstable.get( sym ); - - statstable.modify( st, 0, [&]( auto& s ) { - s.supply.amount += i.quantity.amount; - eosio_assert( s.supply.amount >= 0, "underflow" ); - }); - - add_balance( st.issuer, i.quantity, st, st.issuer ); - } - - - void on( const create& c ) { - require_auth( c.issuer ); - create_currency( c ); - - /* - auto fee = get_fee_schedule()[c.maximum_supply.name_length()]; - if( fee.amount > 0 ) { - inline_transfer( c.issuer, _contract, fee, "symbol registration fee" ); - } - */ - } - - void on( const issue& i ) { - auto sym = i.quantity.symbol.name(); - stats statstable( _contract, sym ); - const auto& st = statstable.get( sym ); - - require_auth( st.issuer ); - eosio_assert( i.quantity.is_valid(), "invalid quantity" ); - eosio_assert( i.quantity.amount > 0, "must issue positive quantity" ); - - statstable.modify( st, 0, [&]( auto& s ) { - s.supply.amount += i.quantity.amount; - }); - - add_balance( st.issuer, i.quantity, st, st.issuer ); - - if( i.to != st.issuer ) - { - inline_transfer( st.issuer, i.to, i.quantity, i.memo ); - } - } - - void on( const transfer& t ) { - require_auth(t.from); - auto sym = t.quantity.symbol.name(); - stats statstable( _contract, sym ); - const auto& st = statstable.get( sym ); - - require_recipient( t.to ); - - eosio_assert( t.quantity.is_valid(), "invalid quantity" ); - eosio_assert( t.quantity.amount > 0, "must transfer positive quantity" ); - sub_balance( t.from, t.quantity, st ); - add_balance( t.to, t.quantity, st, t.from ); - } - - - private: - void sub_balance( account_name owner, asset value, const currency_stats& st ) { - accounts from_acnts( _contract, owner ); - - const auto& from = from_acnts.get( value.symbol.name() ); - eosio_assert( from.balance.amount >= value.amount, "overdrawn balance" ); - - if( has_auth( owner ) ) { - eosio_assert( !st.can_freeze || !from.frozen, "account is frozen by issuer" ); - eosio_assert( !st.can_freeze || !st.is_frozen, "all transfers are frozen by issuer" ); - eosio_assert( !st.enforce_whitelist || from.whitelist, "account is not white listed" ); - } else if( has_auth( st.issuer ) ) { - eosio_assert( st.can_recall, "issuer may not recall token" ); - } else { - eosio_assert( false, "insufficient authority" ); - } - - from_acnts.modify( from, owner, [&]( auto& a ) { - a.balance.amount -= value.amount; - }); - } - - void add_balance( account_name owner, asset value, const currency_stats& st, account_name ram_payer ) - { - accounts to_acnts( _contract, owner ); - auto to = to_acnts.find( value.symbol.name() ); - if( to == to_acnts.end() ) { - eosio_assert( !st.enforce_whitelist, "can only transfer to white listed accounts" ); - to_acnts.emplace( ram_payer, [&]( auto& a ){ - a.balance = value; - }); - } else { - eosio_assert( !st.enforce_whitelist || to->whitelist, "receiver requires whitelist by issuer" ); - to_acnts.modify( to, 0, [&]( auto& a ) { - a.balance.amount += value.amount; - }); - } - } - - private: - account_name _contract; - }; - -} diff --git a/contracts/eosiolib/datastream.hpp b/contracts/eosiolib/datastream.hpp index 65666e78cc4..97aed9f4cf7 100644 --- a/contracts/eosiolib/datastream.hpp +++ b/contracts/eosiolib/datastream.hpp @@ -1,6 +1,6 @@ /** * @file datastream.hpp - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/contracts/eosiolib/db.h b/contracts/eosiolib/db.h index d2c01b6b15d..f112ef5bf6d 100644 --- a/contracts/eosiolib/db.h +++ b/contracts/eosiolib/db.h @@ -1,6 +1,6 @@ /** * @file db.h - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE * @brief Defines C API for interfacing with blockchain database */ #pragma once diff --git a/contracts/eosiolib/eosio.hpp b/contracts/eosiolib/eosio.hpp index 3e850a69dea..2126abb3203 100644 --- a/contracts/eosiolib/eosio.hpp +++ b/contracts/eosiolib/eosio.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/contracts/eosiolib/fixed_key.hpp b/contracts/eosiolib/fixed_key.hpp index eb04a45b46c..4e8cd8241da 100644 --- a/contracts/eosiolib/fixed_key.hpp +++ b/contracts/eosiolib/fixed_key.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/eosiolib/memory.h b/contracts/eosiolib/memory.h index 58e5a482b3d..474e7c7b598 100644 --- a/contracts/eosiolib/memory.h +++ b/contracts/eosiolib/memory.h @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/eosiolib/memory.hpp b/contracts/eosiolib/memory.hpp index 4a4f56a1c48..f2abbf898d2 100644 --- a/contracts/eosiolib/memory.hpp +++ b/contracts/eosiolib/memory.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/eosiolib/multi_index.hpp b/contracts/eosiolib/multi_index.hpp index d7082559059..cba34f103a0 100644 --- a/contracts/eosiolib/multi_index.hpp +++ b/contracts/eosiolib/multi_index.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/eosiolib/permission.h b/contracts/eosiolib/permission.h index 8acd07fd553..743b499bca8 100644 --- a/contracts/eosiolib/permission.h +++ b/contracts/eosiolib/permission.h @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/contracts/eosiolib/permission.hpp b/contracts/eosiolib/permission.hpp index a6956f5dd28..668fa79bff9 100644 --- a/contracts/eosiolib/permission.hpp +++ b/contracts/eosiolib/permission.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/eosiolib/print.h b/contracts/eosiolib/print.h index 63fd1da9d54..ab7dfcc8ade 100644 --- a/contracts/eosiolib/print.h +++ b/contracts/eosiolib/print.h @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/eosiolib/print.hpp b/contracts/eosiolib/print.hpp index a90a277cf47..84bdf263aa3 100644 --- a/contracts/eosiolib/print.hpp +++ b/contracts/eosiolib/print.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/contracts/eosiolib/system.h b/contracts/eosiolib/system.h index 62a5cfeef51..b7d3e614107 100644 --- a/contracts/eosiolib/system.h +++ b/contracts/eosiolib/system.h @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/contracts/eosiolib/transaction.h b/contracts/eosiolib/transaction.h index 95a41322acc..0cbe0f67a57 100644 --- a/contracts/eosiolib/transaction.h +++ b/contracts/eosiolib/transaction.h @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/contracts/eosiolib/transaction.hpp b/contracts/eosiolib/transaction.hpp index 1586b92b09b..2b5e1f1fb2a 100644 --- a/contracts/eosiolib/transaction.hpp +++ b/contracts/eosiolib/transaction.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/contracts/eosiolib/types.h b/contracts/eosiolib/types.h index 120c896cd87..1611df2aad2 100644 --- a/contracts/eosiolib/types.h +++ b/contracts/eosiolib/types.h @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/eosiolib/types.hpp b/contracts/eosiolib/types.hpp index d535f49e922..f1e7c10dcd1 100644 --- a/contracts/eosiolib/types.hpp +++ b/contracts/eosiolib/types.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/contracts/eosiolib/varint.hpp b/contracts/eosiolib/varint.hpp index b8240839aa0..dcc444f20d6 100644 --- a/contracts/eosiolib/varint.hpp +++ b/contracts/eosiolib/varint.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/infinite/CMakeLists.txt b/contracts/infinite/CMakeLists.txt deleted file mode 100644 index af3ec44f496..00000000000 --- a/contracts/infinite/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_wast_executable(TARGET infinite - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/infinite/infinite.cpp b/contracts/infinite/infinite.cpp deleted file mode 100644 index 21a542c1a28..00000000000 --- a/contracts/infinite/infinite.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#include /// defines transfer struct (abi) - -extern "C" { - - /// The apply method just prints forever - void apply( uint64_t, uint64_t, uint64_t ) { - int idx = 0; - while(true) { - eosio::print(idx++); - } - } -} diff --git a/contracts/noop/noop.cpp b/contracts/noop/noop.cpp index 67f3f101f14..6699eca57c9 100644 --- a/contracts/noop/noop.cpp +++ b/contracts/noop/noop.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/contracts/proxy/proxy.cpp b/contracts/proxy/proxy.cpp index ff27e5d5af2..3d243fd4e02 100644 --- a/contracts/proxy/proxy.cpp +++ b/contracts/proxy/proxy.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/contracts/proxy/proxy.hpp b/contracts/proxy/proxy.hpp index fd439e3c274..924edd24b10 100644 --- a/contracts/proxy/proxy.hpp +++ b/contracts/proxy/proxy.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/simple.token/CMakeLists.txt b/contracts/simple.token/CMakeLists.txt deleted file mode 100644 index 1e755eabe2f..00000000000 --- a/contracts/simple.token/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ - -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET simple.token - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/simple.token/simple.token.abi b/contracts/simple.token/simple.token.abi deleted file mode 100644 index 2c63c085104..00000000000 --- a/contracts/simple.token/simple.token.abi +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/contracts/simple.token/simple.token.cpp b/contracts/simple.token/simple.token.cpp deleted file mode 100644 index 1f2ab97feca..00000000000 --- a/contracts/simple.token/simple.token.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include - -class simpletoken : public eosio::contract { - public: - simpletoken( account_name self ) - :contract(self),_accounts( _self, _self){} - - void transfer( account_name from, account_name to, uint64_t quantity ) { - require_auth( from ); - - const auto& fromacnt = _accounts.get( from ); - eosio_assert( fromacnt.balance >= quantity, "overdrawn balance" ); - _accounts.modify( fromacnt, from, [&]( auto& a ){ a.balance -= quantity; } ); - - add_balance( from, to, quantity ); - } - - void issue( account_name to, uint64_t quantity ) { - require_auth( _self ); - add_balance( _self, to, quantity ); - } - - private: - struct account { - account_name owner; - uint64_t balance; - - uint64_t primary_key()const { return owner; } - }; - - eosio::multi_index _accounts; - - void add_balance( account_name payer, account_name to, uint64_t q ) { - auto toitr = _accounts.find( to ); - if( toitr == _accounts.end() ) { - _accounts.emplace( payer, [&]( auto& a ) { - a.owner = to; - a.balance = q; - }); - } else { - _accounts.modify( toitr, 0, [&]( auto& a ) { - a.balance += q; - eosio_assert( a.balance >= q, "overflow detected" ); - }); - } - } -}; - -EOSIO_ABI( simpletoken, (transfer)(issue) ) diff --git a/contracts/skeleton/skeleton.hpp b/contracts/skeleton/skeleton.hpp index ec28c3d168b..2b621b6f2ed 100644 --- a/contracts/skeleton/skeleton.hpp +++ b/contracts/skeleton/skeleton.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/contracts/social/CMakeLists.txt b/contracts/social/CMakeLists.txt deleted file mode 100644 index 72d5d9e059e..00000000000 --- a/contracts/social/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_wast_executable(TARGET social - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/social/social.cpp b/contracts/social/social.cpp deleted file mode 100644 index 7cee3dd1ddf..00000000000 --- a/contracts/social/social.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#include - -/** - * The purpose of this contract is to implement something like Steem on EOS, this - * means this contract defines its own currency, allows people to create posts, vote - * on posts, and stake their voting power. - * - * Unlike Steem, the goal is to enable maximum parallelism and enable the currency to - * be easily integrated with an exchange contract. - */ - -struct post_action { - account_name author; - post_name postid; - account_name reply_to_author; - int32_t reply_to_id; - uint8_t author; /// index in notify list - char[] data; /// ignored, title is embedded within - - account_name get_author()const { return get_notify(author); } -}; - -struct vote_action { - account_name voter; - account_name author; - post_name postid; - int32_t vote_power; -}; - -struct post_record { - uint64_t total_votes = 0; - uint64_t claimed_votes = 0; - uint32_t created; - - post_record( uint32_t c = now() ):created(c){} - static Name table_id() { return Name("post"); } -}; - -struct account { - uint64_t social = 0; - uint64_t social_power = 0; - int32_t vote_power = 0; - uint32_t last_vote = 0; - - static Name table_id() { return Name("account"); } -}; - - -/** - * When a user posts we create a record that tracks the total votes and the time it - * was created. A user can submit this action multiple times, but subsequent calls do - * nothing. - * - * This method only does something when called in the context of the author, if - * any other contexts are notified - */ -void apply_social_post() { - const auto& post = current_action(); - require_auth( post.author ); - - eosio_assert( current_context() == post.author, "cannot call from any other context" ); - - static post_record& existing; - if( !Db::get( post.postid, existing ) ) - Db::store( post.postid, post_record( now() ) ); -} - -/** - * This action is called when a user casts a vote, it requires that this code is executed - * in the context of both the voter and the author. When executed in the author's context it - * updates the vote total. When executed - */ -void apply_social_vote() { - const auto& vote = current_action(); - require_recipient( vote.voter, vote.author ); - disable_context_code( vote.author() ); /// prevent the author's code from rejecting the potentially negative vote - - auto context = current_context(); - auto voter = vote.getVoter(); - - if( context == vote.author ) { - static post_record post; - eosio_assert( Db::get( vote.postid, post ) > 0, "unable to find post" ); - eosio_assert( now() - post.created < days(7), "cannot vote after 7 days" ); - post.votes += vote.vote_power; - Db::store( vote.postid, post ); - } - else if( context == vote.voter ) { - static account vote_account; - Db::get( "account", vote_account ); - auto abs_vote = abs(vote.vote_power); - vote_account.vote_power = min( vote_account.social_power, - vote_account.vote_power + (vote_account.social_power * (now()-last_vote)) / days(7)); - eosio_assert( abs_vote <= vote_account.vote_power, "insufficient vote power" ); - post.votes += vote.vote_power; - vote_account.vote_power -= abs_vote; - vote_account.last_vote = now(); - Db::store( "account", vote_account ); - } else { - eosio_assert( false, "invalid context for execution of this vote" ); - } -} - diff --git a/contracts/stltest/stltest.cpp b/contracts/stltest/stltest.cpp index 79828877f98..baf975ff703 100644 --- a/contracts/stltest/stltest.cpp +++ b/contracts/stltest/stltest.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ // include entire libc #include diff --git a/contracts/test_api/test_action.cpp b/contracts/test_api/test_action.cpp index 496b30fcc37..20eacaa1bd8 100644 --- a/contracts/test_api/test_action.cpp +++ b/contracts/test_api/test_action.cpp @@ -1,6 +1,6 @@ /** * @file action_test.cpp - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/contracts/test_api/test_api.cpp b/contracts/test_api/test_api.cpp index 9ddcb712752..ce7b44d6c9f 100644 --- a/contracts/test_api/test_api.cpp +++ b/contracts/test_api/test_api.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/contracts/test_api/test_api.hpp b/contracts/test_api/test_api.hpp index 4dc5711e3a1..5406dff5520 100644 --- a/contracts/test_api/test_api.hpp +++ b/contracts/test_api/test_api.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include "test_api_common.hpp" diff --git a/contracts/test_api/test_api_common.hpp b/contracts/test_api/test_api_common.hpp index 8d63a535089..d78afa29bb3 100644 --- a/contracts/test_api/test_api_common.hpp +++ b/contracts/test_api/test_api_common.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/contracts/test_api/test_chain.cpp b/contracts/test_api/test_chain.cpp index 6c71eb78eda..22f4ca4f914 100644 --- a/contracts/test_api/test_chain.cpp +++ b/contracts/test_api/test_chain.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/contracts/test_api/test_checktime.cpp b/contracts/test_api/test_checktime.cpp index 4f6bef4659a..a227ee91b04 100644 --- a/contracts/test_api/test_checktime.cpp +++ b/contracts/test_api/test_checktime.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/contracts/test_api/test_compiler_builtins.cpp b/contracts/test_api/test_compiler_builtins.cpp index 1492110b82e..a7571b0a2ce 100644 --- a/contracts/test_api/test_compiler_builtins.cpp +++ b/contracts/test_api/test_compiler_builtins.cpp @@ -1,6 +1,6 @@ /** * @file test_compiler_builtins.cpp - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/contracts/test_api/test_crypto.cpp b/contracts/test_api/test_crypto.cpp index 526ec4170af..3b96e6e6fad 100644 --- a/contracts/test_api/test_crypto.cpp +++ b/contracts/test_api/test_crypto.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/contracts/test_api/test_permission.cpp b/contracts/test_api/test_permission.cpp index 824e8434b7d..f26c120a0a1 100644 --- a/contracts/test_api/test_permission.cpp +++ b/contracts/test_api/test_permission.cpp @@ -1,6 +1,6 @@ /** * @file action_test.cpp - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/contracts/test_api/test_print.cpp b/contracts/test_api/test_print.cpp index 310834037b2..a042ff6f57a 100644 --- a/contracts/test_api/test_print.cpp +++ b/contracts/test_api/test_print.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/contracts/test_api/test_transaction.cpp b/contracts/test_api/test_transaction.cpp index 95030419f58..cc1128ae5f6 100644 --- a/contracts/test_api/test_transaction.cpp +++ b/contracts/test_api/test_transaction.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/contracts/test_api/test_types.cpp b/contracts/test_api/test_types.cpp index d3cf87b9614..bc9dca52e2a 100644 --- a/contracts/test_api/test_types.cpp +++ b/contracts/test_api/test_types.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/contracts/test_api_db/test_api_db.cpp b/contracts/test_api_db/test_api_db.cpp index 706734ba967..d603477a631 100644 --- a/contracts/test_api_db/test_api_db.cpp +++ b/contracts/test_api_db/test_api_db.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include "../test_api/test_api.hpp" diff --git a/contracts/test_api_mem/test_api_mem.cpp b/contracts/test_api_mem/test_api_mem.cpp index e01bba16378..ce59249425d 100644 --- a/contracts/test_api_mem/test_api_mem.cpp +++ b/contracts/test_api_mem/test_api_mem.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include "../test_api/test_api.hpp" diff --git a/contracts/test_api_mem/test_memory.cpp b/contracts/test_api_mem/test_memory.cpp index d3f387fd8b1..3e1eb52243e 100644 --- a/contracts/test_api_mem/test_memory.cpp +++ b/contracts/test_api_mem/test_memory.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/contracts/test_api_multi_index/test_api_multi_index.cpp b/contracts/test_api_multi_index/test_api_multi_index.cpp index 9c5713385ad..828a1d75b88 100644 --- a/contracts/test_api_multi_index/test_api_multi_index.cpp +++ b/contracts/test_api_multi_index/test_api_multi_index.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include "../test_api/test_api.hpp" diff --git a/contracts/test_ram_limit/test_ram_limit.cpp b/contracts/test_ram_limit/test_ram_limit.cpp index 136c27aa72c..c162cea6585 100644 --- a/contracts/test_ram_limit/test_ram_limit.cpp +++ b/contracts/test_ram_limit/test_ram_limit.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/contracts/tic_tac_toe/tic_tac_toe.cpp b/contracts/tic_tac_toe/tic_tac_toe.cpp index cdbdc3d098d..a6eb62eccf6 100644 --- a/contracts/tic_tac_toe/tic_tac_toe.cpp +++ b/contracts/tic_tac_toe/tic_tac_toe.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include "tic_tac_toe.hpp" @@ -51,7 +51,7 @@ account_name get_winner(const tic_tac_toe::game& current_game) { uint32_t consecutive_diagonal_backslash = 3; uint32_t consecutive_diagonal_slash = 3; for (uint32_t i = 0; i < board.size(); i++) { - is_board_full &= is_empty_cell(board[i]); + is_board_full &= !is_empty_cell(board[i]); uint16_t row = uint16_t(i / tic_tac_toe::game::board_width); uint16_t column = uint16_t(i % tic_tac_toe::game::board_width); diff --git a/contracts/tic_tac_toe/tic_tac_toe.hpp b/contracts/tic_tac_toe/tic_tac_toe.hpp index 4339ab212e1..f4f32982ff6 100644 --- a/contracts/tic_tac_toe/tic_tac_toe.hpp +++ b/contracts/tic_tac_toe/tic_tac_toe.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/eosio.version.in b/eosio.version.in index 239b7599404..8d29e7ced19 100644 --- a/eosio.version.in +++ b/eosio.version.in @@ -1,6 +1,6 @@ #pragma once -/// VERSION @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@ +/// VERSION @VERSION_FULL@ namespace eosio { enum version { MAJOR @VERSION_MAJOR@, diff --git a/eosio_build.sh b/eosio_build.sh index fafdbbaeb8e..b600e0905ea 100755 --- a/eosio_build.sh +++ b/eosio_build.sh @@ -34,10 +34,14 @@ function usage() { - printf "\\tUsage: %s \\n\\t[Build Option -o ] \\n\\t[CodeCoverage -c] \\n\\t[Doxygen -d] \\n\\t[CoreSymbolName -s <1-7 characters>] \\n\\t[Avoid Compiling -a]\\n\\n" "$0" 1>&2 + printf "\\tUsage: %s \\n\\t[Build Option -o ] \\n\\t[CodeCoverage -c] \\n\\t[Doxygen -d] \\n\\t[CoreSymbolName -s <1-7 characters>] \\n\\t[Avoid Compiling -a]\\n\\t[Noninteractive -y]\\n\\n" "$0" 1>&2 exit 1 } + is_noninteractive() { + [[ -n "${EOSIO_BUILD_NONINTERACTIVE+1}" ]] + } + ARCH=$( uname ) if [ "${SOURCE_DIR}" == "${PWD}" ]; then BUILD_DIR="${PWD}/build" @@ -66,7 +70,7 @@ txtrst=$(tput sgr0) if [ $# -ne 0 ]; then - while getopts ":cdo:s:ah" opt; do + while getopts ":cdo:s:ahy" opt; do case "${opt}" in o ) options=( "Debug" "Release" "RelWithDebInfo" "MinSizeRel" ) @@ -100,6 +104,9 @@ usage exit 1 ;; + y) + EOSIO_BUILD_NONINTERACTIVE=1 + ;; \? ) printf "\\n\\tInvalid Option: %s\\n" "-${OPTARG}" 1>&2 usage @@ -238,7 +245,7 @@ . "$FILE" - printf "\\n\\n>>>>>>>> ALL dependencies sucessfully found or installed . Installing BOSCore\\n\\n" + printf "\\n\\n>>>>>>>> ALL dependencies successfully found or installed . Installing EOSIO\\n\\n" printf ">>>>>>>> CMAKE_BUILD_TYPE=%s\\n" "${CMAKE_BUILD_TYPE}" printf ">>>>>>>> ENABLE_COVERAGE_TESTING=%s\\n" "${ENABLE_COVERAGE_TESTING}" printf ">>>>>>>> DOXYGEN=%s\\n\\n" "${DOXYGEN}" diff --git a/images/bos-workflow.png b/images/bos-workflow.png new file mode 100644 index 0000000000000000000000000000000000000000..6c00b9cf715c0c449f11c037a42f21e354a67b28 GIT binary patch literal 437365 zcmeEuWmuGJ*ETWKkV-eG)Q|$wjkI)^grw34qI64l*C5>pN;i^{0s;a`2#6q^Qr|WE zefIP0?cVS4?(hHeLytj+nft!3b**)-^E}rbrlul?3#EV}AtB)^$lupMLc-KRLc*}Z zLSB>gaoa!m6ldhkd~%Xb8)n?wX;M*k`GHt#?VR_An98_|3Jx3fXtH1zwx0U zh$ftl`aZ)QWT`NE`r;Y28@i@4H*R#+yecC?lPO?_nRj;GGL@7uj+K!yCdGdBYR%hU zZr*#RcC3i$oOebW85th{P!`_orDDGZG|b z$(QjI66S%y%H+qCPXMCX-F4Cer#v8ea>)>K%FO zil5>!E53%ZO&;#}q8725L04uUF7wxu>qOLgFWv>y*AA@=P2O20dhPp_tybotbM27X zbBw`{g`7C)t9PWvdPPa&ogshTG!YC9Nh?kmbgBZRT)< zfx!D$Z+1I&?mpyhSEFJq6IA%dx_MXnFs04ofxefHVo-az+{cqo4X?=baj7cnV}?d! z5_>RfL@dwHHgan`9GY^5I0x}kDu$&v=1$(`)*L8Uq6Lj`FZ!Eyplq>i53<>IK75Z> z7S!@JkxdBo`CTKSgweWGx%$^N?kEyJudKv&gg+fN2iQ!vpVx^%Ixh3?-?F{jJ~)ST z3|#h8KRw^(kT8zJ*ca5kW#cM_1Hadrxv zA{EkMc1aSwgqBEtibb|SpOuJ?rTmJDCTXU|mWae4?In*>;m;=-tcIn9Oda$Xo}kA1 z6uAlgNb)4t%m(KLws(j+7r9QzJu~TBNx(U*mWG@v8wjYd zQ-a_3{ph6b&gwf_k#(lsyVJt=8GR=rru$%za?kSA;6l(#{EFNs94^5{CqO8LN!10D zy1T@c8|9S1rI>mPb~EZ_2VU}Ca<}51DyZbk+@WDf(NYnTY*M6P z^uEO!r#$fRt4B?0OO#jQykwiIk6f-A4hv19fFg+{WkHBb+tTxVUe*Z4-f;mA)? z9|zf%e-y|cueh6AQm|3PGB%(0T>T)4MESimt9F^zX6DCKKJ7W>j3VPw?}z7T#=#@- zqKWq#Dc@FvD1@$r%(DW8M1?e)WSioeDBUQZ(r(;1qB@E{R6G(o>OFdU6nHfKZF)nT zi;hfyBA;xF?;Ce2FE4i_-@N&Z-RZpi)JxmMM_Sg0W2xp_4w<$_mR@s^C(AbRRyCvf z(?oo4d6e%~@V45bXUt~o4IQT)4R;T@ruXIO-gE58v>V|X<*VYMt%K`B^zGi*)OpyK zIFeg8cGtY$&q&JBZkjSHlYGLkiL@E@(f*^O{R8_Mz9hbSdzQMkx=njSyDvlh8KYV4 zzE`5crN-3@B+V+#RmXV8Qs*zu?_zj|LPA^dP@@N9I$`H!P)2Xtf08o3$kS7I24&VO^jau9FCZQN|AoiCfu@%Z-KNhI1s z{smpFOKM z-rVgw#rV0iOKbX=dv=Io&BIT+`?PTHe^umqEwAD_s&xH*VZ9xb=8ILpDgIenziFUnKKKvT@p_v&>|;CM&V- zzOH)}xA9xIsamQpnK`<7y0yB`D#!I}&4zakdOrnj!rj6)g{C(vMh(T&H&YB-{Tt}* zyQ?TG_>%3s+F4#`8fIHPboktF)jsTY=5p3`;m^)thCiW>s9Vj=_GDrH=D+J9Tqb`{g#?3H201ID;U=ZQ;OYd`Taauob`T z7}RYV%wE)>HitF$G=~lb4jLYR+nH@!SCUce$x<903~8nCtl!R>@0*=&|MJN95_uRk z7(?v(-TB66$@V~H?GSCt(CW|{d{I#z-_+dnjtVG3)6)&2 zJ}nD1s2K6Pvt8-!IPa{mAFUl>P}<-IGj(9?g^@B5s(iM`vD*?^^(ei1)49=VU2F|a zhZkxquMD#cOS8Xb_pU&$$g=0KxAu8`x@yy`;<>7yRNJ%ua(#b9VPris=NrM(mZn%Q zvwTJEjD>Whf%MGMux4bJaw-tf;+C z33^l&MU=%K>PXD5k<@N1JTMZ;iz&iQA3vOcToI1ie6y{^fYYSqYrKrZmdL|E3c=JA zLW&)PW8x#teH!c)S5CBe!jljYSu8sw7xp!a5vhR>sSU~yU*dgpV7goW^$GH~{><@J zjqY1NTeF2uL*#y3Cud+^^;{uKzlIW8a%u1Z1dHV)ukVV4M8bghgRG!&XBP=c0!iV% zq?QNr)&g3p_S99wUcs{V4b=N=T9CV)T_mW7rDUXRY~`%(Ce5f@cy{U%c4}Mi99|O> zqN?8~IRA9@e0rySWWjn=P;*G2d$)3(d}RA{YcaF6?Y!CQ^ob%C2^x`_1oHp=mp>GR zM~7?~>HmJ`Zy)B*Y-$?J6o3L{hWq`Wf2qlKbcAzr;pzO73qeN1Dc_~~N7syuHi${4 zr;gs+`HwCG?&nXOjrz~tDnX8n$~xE~p!W}!4!nh{y36&S-5e3~ZBtVjaxx6of3R@i zE$BKPc>iRL!CNgMIOWW!E2jT!3p+ZXqyOyY)Zmd|ssGs9C(|XLV_eSpMRC6PUSD=swO>&@ zdn*$`vea@gQZ})$)^ZBIw41a2LSxkheDhNEm=w0QU>4zDQgp`~dbMUIsfpgU#-u;Q z2;zMcsT~KS;dL{vOxF?e7bn})bqnru z9anmf8FvR+tAcWTuLMW#OFS@6QqPkOzPdc`gNJ|TaQ)(ag4?{)=IO@tOz02$_CMQT z^A&{;?L$9)Y(~+a)1unjj%gELYKNwc!rdz0OV)YkK5FezF3WK6QNnhwdq|clo3~4O zi*K=S_0js`K=cl`W_emJ_TSq&&5niQ$ zVr@2(yYNPFY}u2Yc~aH-m`H2y#6IhZ#;1h~L|r(OBIxru|3OOQx%K*@SV~;- zrUiRHhJ36-uIu`US;gCrP}a%@bDOz3`(QV(gJJ%qSZO@0t%w3Mv=OoMtzEDT#P;_~ z4&n|bU;TNFz!od(b`(maZ@+dM{Zm-`+dlN$A^;2HHE?;l6iSPtPfz1}u_pnCAmb;3 zfD_I1+8q%v!)wh|~k52o zE(X39jL{mn+N^5t{qZU-=J|S7eb);;v4aBcFJ1>d_TN7gCE~Npl7eai;X*~fLNnPI8e_fQ2Ry?>8Bt4QYp5*!@gJ&8+PmJk|FXi&aEXbV z#i!quCq9Xv$o?5Uz{8+#Y{qZBc{0thRr8)>X*q%u4bO z-AV$jJ${GyvcEdfPHNnpxbGeYLers+-~G$8FWyVT{9o8` znADcRF?~7gN`#)gp=bYgs_X6aLqnnt=TXsvQA{S$VNeqg| zOe!B$wH`x3CSr*!6pYh2S4%ae_}-7sJlSJ)z1K(U_BvHDMY1>CF6~jYU`?yrXX9yE zw>EzcwLdSdg#U)#qHoo~gFejdraxbD#~V(G1gf(_${Nq3_nhtThDc`3nt#+8rh0BS z)&|0UIDqi|HdUsZn|6cSbj+g9ZQ58jHRi|y+n+=$eN^Dl>JA^5&wKWIobC`@)}gE8 zImgg~l!r}YCRx$WE4@8dN;MN#>*CieP)vmt8?j(J>XPy|9~8|3arxw1WpYlw`1*QW z9!+C+&s2g%Y8lJ<0e_zSTSmUVI^Wv?xi)-O#>Og`j_kPh`N7((et45@ujNqc-C#3F zR;;MS7+lidil6a8Dglr8)1A+vvC8?3tKdFx0x|F_W8YdJQo}6Hoi9G;_T%QZpH|Cj zM_?4Pbwu3RlZBHXzs*|b;Hrw9S(qhZb2ONKn*0T^3-^+U=2fdVz5ZKas`jg5TRT=)IA6ko= z{UXl8_om+!$}amUUgZkjyecdtFqLAAqV+k=ttJa#z)bHag>5*tovn45);K0&my-!N znbI}TB@wC!(7Ta{wS&cU>Ls^^1aR%I2I7lhUc}w|nr!HRb@}s%)zJC+9ieIvSn8(g zm(=bv^qDS$EU%v@^6r8ngAXc|%lC?pOb1)7C!hTn6SPQ-pN>0i6r}X7q`j42nP5^5 z{MvW2HCx;3PptXm{#xXg`w;hgw%lhspJkM1^6hEvn%`gKOq#XIsIV~Y`8tq*>Q4-T z7Syan3m2-0{|ehvx6xp}##T-1H-1UlrUnG?TVj-YuX`z;1bwV9B(;CxE^_83MV{XflV^7wiy5jqD^Z0o*2cYU>P<^gbFow!SI>C;jZz)ugme zm>s<|I`Q=xxAXG5SMYGF;q+jKg(hNU*|8pwKn=NzU)glAh(h=df6Uc0PssVC+ll+c zh#u>?t3@^UMN?Bwr{R|BxePEo>Ww~I&uQ;{Up9>6W;R)(S(I9FyCMgNrK;`c~66f4dSJr}|7%O4Z$yc)5LPoUZi#R1gvC zxabR7wTsa%jz2A(gug7K(@yIN`c!~|}Mds|+f!6WUE z&<^6*0}F|5+|5B&k%@SvfCcM0yRC_mM$7lfCXdWdjdw}wkl<7z;Reeoo#iW2J(%6J zu8DWj3+x<-nO4%?Et5SlyP0Z<#rrVcP!J9&kn~ykf=7MPW}xKb7iGVAockOafU6>Y zdB|lm2IpFdOk$eKCyxNfP{6KcfH4=Owbx-uAoUmYq+EJkU!HV>y`gLan4^mqQM3il zw`#jV-ZCKT<&F{h4uHliLybQ%wa`;$3X|08bZR%-AYZ=ffJe#rjDyy<&3N{F_IgNJ zc~817X5+=%W}V%CWeT`Np;}jy<}ZkxbACC1g$n-3?1mv?-amt6Nc8i+9AG^5hN>|=Iy2@h!SB(5%>U0)6gpW`P!>OA&uY{ z?v1nI&(eM58H7b}-|Mv0ZrLsNjEY}V@u=q8o{6j`YK8~EJ~X6RrL#~05R>bDer&5Y zv=uijuTB=XL8sJ%MruS*_xZ&pnN}w=w-sC6jCooK%srY$RA{SlJzGYS*uql)VDE?k z7;HqpUi$l|mk*d`JLtI8V>=lPYxJ3G`uK%2H?RbL?!V{6uC3X+I5Q@*4gGWd18BMg zkP{Od{?F?Fv>5({j9kz6zdChcF$K|xzW6Oac5RPOO4p4I$=knoY`@gued04~3zW~H zn{}TamvMRQE;^n6sP9`7P_&#d{rUP)UkGRq1ndCRT^eA@c@R;2WG%KS(IzE2rw%YE!OnI1(BpkjAgYc=e2!{3@w>W{7m22>dd@)iS?`IKxQvO=jN3Gye{Oa`44A=*hbtxFA^ZG-{>e>mnZGSdh zl;h`JIQP@kP99>POAs=8Ol;v;&Nn#kaUMT7V-luaMZw0PcsJ#Nw2v{^}62k-=0dG&jaW}>=G{$tLjZ?8HsE=s;;VCDui)-i}X zx}mVvY`!ALsJUUhtahOV3(IexTRqJ* z0wh1Ux1X(L_#@##D|z#zoMd3LTNvN~al2Y%Ae;U48tXv8W{V}!Jaz?j9-9|CUQyeh zSo_{tTylcgfNcCRC+;J0MwQIe7uO$0e{vZ-E-8=#*bVzU4%cshrj{r%UbM|t1ep&Y zd2=)JEFm`-#FPmA)2|rD52dpMs*3VUDrKaX2no=sFd#l&U3m5d7o=s*!}UPg($XQ$ zA-z|DYuq&j#?9`*57V&}d?E5$+MnLo61p$AO(Qa1?1F57G>y;cQmIwdQ?JHy^b+%| zG|gb)91Au$fu5uq^!)DQ$zp*>-{O4Gq0VAoKDEgB1aAjv(M!vqpF)y{r6g8A;F4X} zD$DJoOJ1qyMOjr_xV}_jAy(?+DmH#IZ*t2R&h-~UobRc>ywSJy;_C=;o?R`lz0~>z zL`e7}IA{MqCjf~F0ycwgJ@HJ(@NlRW`}W9?z2t1+7}E%?CTa zNU&3Vrf4X{HV=rsAe^aTd zDeiZ#f^CmEKLaO*bd6JcFB=zT*7bdh(;s~{@+MVAlf$dPgQX5se747Us}=R1p$K5M zHTq>r-9+|mrE_o9qu?L`=QeA_8;yD8^bmz!ixRq622Yw9oc=Fvd<`_eY?rNiM1~>BQ~IgRwiNW&Y*`01^MW<%4~sB3fI9959!*gk{GSxr=vP83A3*NHVZ_Tjiw@JRL#yL(cC`( zSd^XObFOsgtE-Y9X#i_=gJyt~wDzOHlVH)4`C6MeQWGy{kDnVw5g}97s@@d#)t%_U z%Dw<~g&(teili~$JC{1S9V4QFS)D8HnLXzC%l)cJ_+Mj@>FtSQH~#{d3f27)jRuwT zyBov-Hx26S^xw#}B(?ALQj&(;{Q}608zDI48e}@9fgLYFxQbJ`O{&Y}Jp-p1>Uak5 zz}N+3mar6NQ7EvHpAgQtIp652?rZ`bE_?>74>U zzvXqy(Ryo<>Euu!*(Qo|KvpBk?!KyKJzL4ZEpON;%zz^E@u6za)k^;gr{htE74h8Q ze?IAcC{YrNAa_7{71T>FK&Oge{Fb`$#c}Y(PEAv}%%sLGRzG)$?{=VeKZ+40@c{&% zfaokGN5f*kE0Na1du}SR-M}R9K;SgbomSGKqKzOseFUE{BD|AHP1HOrT(QVVLb7)s^|Sk5KnQTh ziUtJmAQLm?c)8?C+uSdGs{fE@!hj*w0K~sg%Yxy3WINI81f_Djpk1n9BPWV5A!T|EQ*;-q0!4!gk{ z%=JuHl^M$vW2ht=fag*A@&d^a_@s4->h0(qZCzvSH)pe3M7H-4blD<~zsRfx2PTVf z)WR=!2z@Y$a&$gv`Xbrw%P-mW${iWjH&8AyLCG`Bt2ujg5OReeUWMGgYq_Vp+}67S zzD1l%!aK#E6Dq>&Uo+5Hgr%(@Nnb2l5RDkObWvpj8&QS9TbO}-N%%8H=6fwd z#5>+U53w%KPw*jJ`TL+2^*n&`UdM3<Nrrl%Vk zkK>`;siBLw=}5Wyv2nNMLd35xYP+7=A|YehU4!FCd%}WS6)`$V)ekD3fu2zb5>z%` z#vHT{VZ-HP;+y5Qy{5!XWiZhfhc7$tK$2Qcmm^*aCS8cw&(+}~;8dXY+C z@Td)Dc%xN88JDhl*b43bUX~{oDUdQ(??~GpE|t4MSW}k>J6loN#qXQ@E8Dt?W|g{s z+;6ffC;SU3379kKML>-}0l8vz`g5~tg|-vZ;yInuqgl%oTprL6X-QUJ?5*^LB3O4o zmT)5=a<1FvM>CK;VtgT?)gy%(n77VA)%Y!6oFw_-29P4S_`;e9%~o0p<$Jlt8>@)v?L+#*6V|D1Q+a z{ujX*mjzsm^!H|mU&H!uKi*~%ai`zAS9)3gm(TmtEl5ZMt$IB6XQkoauk$b8@!w_t zUzX{=%l^Ma=YOO9mm~E1kN-_Fzt)W3+nxXaBr{CmvihG4miiF__{Zj5(66Q}Y^@Dv zgaSq|ncC#>JHVWi_X6VkGr+yOKkC1PL{kg*iYIF?a68O5>;joC7}UW&eG((5&aq14 z<_>G`q^0gq3=srdf`ELJ(~rMfG}3zQN_u=RDe7{0&rYgiU|S%hUx;lhf+>&8fItleM4#~C_o*_2GEjWmyWo<6U4RRv01SQe_WvC zA=q)?XYd3&MI`B9|rk2N#%qaL5^oi0m?T@85TkP;pa-c%KfoOISs&N;P z9u3_;<@o$$$pmb~Qf?>>RIAkLJr2(h!6$$wqD7Bqs(~DBEl2Fu4%GA|0GROs40r&K zzh|f?Tko*Y1=a_Uv)^K=wV4(GTJt^yy+ap?q22g5R92vrQggJOE?0vkrqsKeBzL`@ z*LbDg`l;s!SD+oh0urSi zP+vvO{dygme~?&ZzHT6{=l|lxvsF7PwglQ5EJQ1#2beGE&5sq2V$q4e+?I{Rye$`v z!`XVML5FFc8%$DKO^v4pXGE!L*;f?!8Y?X|nk~9wt-O|%T)6t8@!PA2F0l3I^=LW| zl*Am${uW70WFVN^xf{=X{{;T;J=fC7^9ZlC#uE-hhY_FiT26 zW@(}YmS671_+I2yvwiL;6aftKQo~9#cFMySwx@vgc|;&%_KJlXVimjbo8ElZ%QyE7 z1Z;@#cEjz;N8iSBXJ>!tz9J2l$Vt>L4eki{6 z5_?Z#d`~_Z=lp&D3DfjHdKeib<#oX?p#_I0x; z%CTNR(h43&P;b0_Y8<#?om6tvZd$1Tn3|*Gz#`ax`L;j)sK$fLqcb`5zT|g^<^LFa z2%zyL1SvJk_~8K%nGHO4J24&sUb>>Vlz`|p(C0!xuPlTE`Zt6i=$yRMe%)58zjB&p zoh@kBve)a6Ljl|^FZ3+pWJ>Ruq`%yvP!&DW@&KpMT=Ne2)faXy7SV!h@(GC-7r?5} zg=ncWWX`~Ol{!EE(XFAxP7Fw(tXC58ax~BH@a5DXxDPZEJ^0s}Y>(wIiNYXl9eoBi zz^w+`_C`^X)<+fU_Rn|j3%h+MDq?-0H5?6&jUZo!6d^kVJ|=>#T>EtMBl{4rR>&yj z4y2fMhXe!0646Uy9PfZw!bb2B!|C_15mJ@il_iLGHo-55WWqORS4+0F|1B>j1YwF8 z>ArH?o);WB07tX8(6ry6%f}s9KKR< zV&vM67{S7o?%!VyfSlCIkX zzlDX+z>PkFv_o0jU}0UgePyxEGNoKcS}8czwO2>-!=HLkT2?O9>k$9!tR<7mae|KrWryFRO;%LU?M15!_0| zw44u5!#0yjCK*Bx{pD^VD2Fiqgm zhzO`*VN9sCgW;s*t3i7sgpQ0%j7YCFy}Q4Px%pB~DZxJ_vYb z0)y65Grr>$;0B91m)eCSjX~lUr9*DQ*0BNvf4rG6FK|!4J1i%GKKI^dn5!Gd`KeGH zWJGOTnTH$X(w9kd2=xO;qj4#O(tLtrv$EO2z~bVoQC?#zc+EkfNw2bc0&+Dus;B@- ztLF*FP{INptl?zNvAy9^tEQHg=%X7r07NMGzd0L#2Gi$!(cRbyq!?g)c_`?vdyIdu zQU^G;UO2Q#b4f(rU-sTY&YMV$94f=(9kAWud4_d%B(`(%N1y6-G;*e+oNd0Q3oc?+Ba8Dvv%ri_>7 zS3XO^QG;EB{4#;`FLF#s6rd07GNqe!OU?Eq!h^8h2=XHj_9UM+1oh>S?@x?oz!34z z1MuNYz-RPDZ|P&1Zq=(NjKh6Q$i(yFnC})J_IN=O_MU zQ|ol8IR|BJItY-*Y<9pWGpjvQ@fR)y$~^WCR9zc$jLC(6(X##_q;#HLz-vfmQ~3x4 z4Cg1h&mW3nr{GP&P+8b+N$Q&N2A}<>chKiBb5((*AidcU!(|9jdE;6-G3-WJbN1HL zmIdDqWQ=#=im*h0DlW-zBvzS;w=t-ns;SG^rKjMKHgDA^l`j_UC)(fggAmq;sFe(P zz(lY(;2PN-P*_vRVxb1FVR1)6eBuLgEfmdSB8J64{>@Rr^~}^uzq4X_#*W2k;cZNW zS4IGk-Zc@h*{r&h`g3qrcdDm!412_FwStJJgrNBTgm9uiDn>63Bcvc7DJ;=HDBLGm2?_Q6JUI9$ z=s=p5!>Obj^K%WeB#=*pCi9}+PY%~q6}@N0L{H#{!(xXmiT0MgJYT6CQX`3{8P zMzypW+KL{(Kf!DlZz!#gM@w=8$3TY!Itd%IQ8z@Pyy<)Co)J^WOZznudd!yx{zysE zc!GDDXJ&?7UawHx8Vg+UNA6TKs<*(Q$7DzX`iYno2|XeD$-U#?ArV{Zd7l1?O%ek$P-{82{Qj{kYnSuy* zGHab)Zc3?ZX#ZA<3*8@AYed6L$+QDxGV1k`En1j2*3S+*kcyeL4mDm69p6Nf3<=ao z`mFWl!yzW|bjb!r4S^jHPwo~6LOo!$2f>O?BZNk_LO~tS8ntS%k20}nlDH*U_{jqT z#}SJ+V6K|~Ev@Y@ZhwDik?%0P#7a{A%`KSJ1* zW*t_qI@ZXM6#WWzu%G`MRS2V6!}f=2BD;>mEz~sr{>XR~rPQ24hhmHM8A6FzC^8Df zAohoU_!Y5^9(`rZ9+fb6z}N#dd+bgjqMH1CdnS08CuE(&pD&a4Oe%zUL~;Z_z^HmT z6ZnNBO)UaUpU=M+n4Xn`u48rU$$^GNI7?}smD!@1ZZT-h4YOvECJl;AaOfIY*{~e$ zVX{cI<|92p&ysu(on~lR%coJf~33rSo!ta&kw{d)nD@g=~qeu6~vGwcG4bE zdQ`E3!bH*8M2ki7BD*Iy$u5a#(i^QILW12<-zy#+`Tb*eWvH@w^$)E=P2`8AYUDYb z5CbrS?Eo8u(Lr`9AG5O&Kj zr_J_n_XjRQx!*XotzsjSYK^HX)7#`uHuk^1!@La2dRQ9O{wCcy&a_?|fmYYiP%A@* z{w-xW39M;4$(v{AR1;3h1rm|G_&FQd`@rK!j9zq(Jnc|&kXp{k7GssPk8BKaauV++ zjppp+vZExoWd>VHpeCt?d6H+RrfEQX(gjc(6S{bTnGftgXzbswct!oKlpRy%Z~snP z!LQJYBkx2=w8dWftuc5grPr6)k_6OuP8eSDq9Uk)o;UkXb?akaf5u`Gr&kA{NTQpGU~1#r*a%PsAxdqxRHRI zroO;kOEa$8OxbOHm}cPu@qphkP3;paQVRZ(aLxK{c@&4vR1jP zu@iONK=48M5IvPije%BuHC3f!G}?P+>uhdMr;)L&05hRy+eYr%EKY@6kfcbu&HI+` z83R%E>1U$1o*FTotx0}(OqPNItG)&IUyH*0Kwk^()*vC`HpxF=8y*#XrKPY=qP&qG z@1;@8YU^>#V_DIUmzQy_T;g}L*ExoPF2H`xNOjsvd7Bmz8haxUhkE{G@AlXegcTh) zkvxV@)e}4g=Pdss6$9QN^%x+Q)Z^$h!{3LrqV)U}y-}#-$wxCrczYzEKCo402(j9@ znETd@-iGdiv4Z0>>kJ-de$J#2i(88^i$R2{B6llu)?hX+uS(-T*Ql~wyjND0u`I>3 zrZ^6hs=afetv$npLR`GK1AG*AP5u%@8b38X-si-pBj*ZRlENF2u3)SK<@3BH8ZAcE zis_tawD}toPOu+JmQwO7nrJRQ!iuduIcrO`MhwpG>62MQ_yUW5yv1AAKEi`&3Droj z?<{9lq{|&87e(AVC9^pi89ncWHZtYI3p6$vPHlmq_;n+G0O4beLH7E|#$dvAZ+jG?2H!+hTVpC7Mf)Av))zC1(>`oP>C!i0*W zF<|8>ze#5(Z%Kadg9{c8v+h!6vi6jZM&kpJZ7p^0ne5Zg6t+Rqtr8FlfD;+_eU_dq@n~ z@Kg`9-AD4b@EJ(8dO8M^-CC;VGBDB>vn zWa4jw3)LD_Z(L~TcZ^O}GEs+qniuc?*-1Mq)Nt}aWGpX6i~_R`a5Tc^NYpETOLQn} z0y(Vd}1iFIxtyn=H z^l^`BaV?roL8IJ_;2(KVzoPPLm_j8{?itJZcmi81DMms4%)yGLFGWtFYIjL>kyNwM zB4n6REnX?TibGtVuP@9#ZzImOb#nD8mc?rMUDy)15PU>igGLc;GH9V@W|4*r(IU{2 zIG{%`YP0aHi>;}~LXE=Iieptm)jbKbG}gXYp34myWfJgH%b&_t|45Rzyizcec8z!I$8)^DBh`2(D~OFuy;5`6EY-fhI7kj%LX(jaguk$lnf{Te6N1x#C% zUtTg1Fc@kahxgHVvI#d7p97ywR8ls=O+}HtVSk${ z$t7F^z;>f)MuyriCLzP+c$AV}_4UD9GCk^;yl5fVi^RE)2IY01txDcs(zD_)P{t-M zIHeDi*e;1MNaOUSZ02dv&xH8FL6^ji4&_oFwAft?#7|CVz*{k>v|kd7PahfJyqy(c zu~E#{tnAYU8aPqBt}3kqUS8Bg(0s33mudS7Z6}e(UWU@umJGDSf7DDk$LO;|r0x`B zcl`nHIbZ}uNt389hPlcQpb7js;eps7({uu^YV&k~2M+oFqEa3xp=ec#0z1-gG-$>G zaBRIA{sP(>^VLQB`UT*`)O>DI%H>nP;2wdDGbBwQ0n>_&4-2TDj{$5aS#eyirTFu1 zVKlOGK#$C-TQ-+8%!4I2XIKJ+8fBn#4WVi(SFQ!aZRMouR>%u3+BDXh;44iPK?ZbH z0=>AZ@&ZAE!F$t2gvD=ufD@6sk?@8JR`y);0^xD1pLYSI&FP(pUKvtjqWUy9EuDVm z8qjU_{rGBsK|H#jhL(tMIMJ-kB%E0TC;MLJqEW%d4e0QST8U~k#<1*HY)L)feA4xCiuwtN>cRN+ zThpi~sp;7f7HjZ)q@=B0U`@1=*q?TCPfvg9>K%8s3W!`hgke2ce;`}Zj|>@a-ukiO zW7lgv+kzx>I$VDRUfp<3i#JQ3B`0K8Yo@=hzc%^P;rbt4$Mh3nHA}4RPHJP%zfkiS zCZxZ37n~$gdo1Gbz(1g0PWC_&&BAELER;IDaBTK=%J0ttcrsP0-2h;4_uW1!LYtof z^>bK>zfCHj33L)zl#&U%+j$YD4_*QgRc%AwBIpaa!BF7&em8{KqTL1z*TKMf&7~s} zuamQg3bSJY4huIU)p04<2ED{G;4oe$wQdn6?XzV>5_X5;$0)0+#ib_akjS91q)~Wy zW<&cBerbfC2v(B=nB3HX06&5{VG|qlfHgJ^8HYCVSl&y-^c7-+%V{mmIt0uW_8<`k zQ0Z~bGGV@?BPaj^ShmSEIStkJL+|S*hLFne0_D& zj@pR?dO>dyAB2iRm%7wLYJ$Tn96QXdVTSC+<>!Z$-bD8@^il6s^%tsZK;`hF6PvmM zzg40=<15CD@kZBmkLdWpKoNz}Jc(vU zzG=bFqOGq&2SL7h(Yim#Iv#xxZHimdGZu+2iR4vt&D$eoirts(S_BlE;EvKaRS2fh zh{<0ivmO}1TvCCev~u^BybUDU6{%s;W9OD$^`R_Dj_uA>y} zgyI3BGkn|Dkb4(E`9iqmqE0wb-U>{^-gB!j5W8>+g2h<5H+-+>`2#xW=8D);Fh3z28EGQTCaxJy?dO5AQi1b>w@c&b%wb4P6%FfUQaxB!zT zD1Pe<#OPC0fj!4M22)8)SY!x)vyWE6B?K3TN`Nc##rG2DbI?~00gA^tM@9I@8z&IL z+Ir}YjV6GDzMIzr;*x+zH$SYOz1Y%w;OiG>LjBQd>P$xl!TUzc)s`CM0YE6qyv`>RC>zYbzuqZ`@a zqEpF(pzg5!&C~ zZcMPhg+d!3a14es$7(F!zmjof#{+YeRA6S*xpCvgDi!_MOH=qKbe*vwj7}cJWG4<1 z9i4yIE-v2;T_%`5xcf5CCb0AyeKYE;6GzK#7s6wC+IQv5ar9%3AAO(TP+K?H6pA9z z|G4`oksZ{16`U5jezV6)_S>|8oHfC5SvieUc-gMipnEsFgE8W-Bs-YNBu+IOoV(|H zZ(+gp-vg)qw$gs#YM*_s0K$3H!;s{5kEKO@gz`I3pkjzGTkfjzKp-X$?9YG_jH1um z59y@*UJ~Y4ntYCsP3li<`TXoiA(?99hAFE+5)5+y;b~l+xLR@fiBGj-+MHV@*4fW~ zwQ90vrV1hSp!*UKNt-=Hv7gBB~M!FXT85 z^-BSM!TW>(l%<|mI@A77q6?oiSYhE5tGE(CR$`M1!Fbf(i**k`wLg?P#zFBy%>R^p zHc9X5jCq37-qcW}^|lI7sBR)LSQhjN%E~*T+U(*{RU4P6hTK@rLyalUIlyCPk0YS; z{_yYFGK8AU8&l@_yP6Ef2UJlCP*}g)YIErPO+No0lI;fOtycb&y&#xnY^U?qLlK;GNyJM<_FC{6+u) zEP)b}<^HUT{n`)$sO73%5ab_ijEB0<+$NOyr)DZ!Pw))Y%Fhpns_wDCTLig6rfNC)$*JuBC zsQ*7ZYr~6z5NHrM0$$@XS*$KIcLWk~(8Jaj!GITkYttYKO(dkFdz7Hehh?Q&%zWP} zEQdR&)q;7!lrErp?66tpAqcw@x>nL-a-3!0@X9p_Y5a#}~P8GhgRMyGmEo zCqIbt;X`GmxTJSM{aqCQ8Tg~DShyvBRwfNQmD?0Bn0|?NH znM{Sh|Ha=vqL9fSw8vZsjnE9}Z8(U5knzfdg2j@eY$#|l@qU}YKxpB>B}}BFZ<+LJ zqehgMat}bGp69?Q5-|om@d96jHp>aG_F{Z3m~dMfFA?*)3@Jw3Pk~GgrW1sh04T#m zDAP6*h01zXX_ivJhaz>bHXN~5<}eBb2(sTsS^yImjIjO>0k4Kx53w%JHIOn>_k<+lo%~$uZWneaqO0M1wmZZ#`tCrAG zW;KAB#8G(|l<9Z$Y;uFUD4vwx=zDa8cpwLR{XDmW@Jd>=r8+{i0Tz?G8Bx#_h5}gm zZhK4ox6ECLaFU!NEI|mV7cqag!99m|E)GU9xj+#N8RnZ~d$0Aaumor11Xz|i*j~T8 z8NBpVh%~mZTQZ;Sxq(W`> z`4Nz+`ZhDq8aQ;o<3v0-flMX%;Z@m@f>i=Q5UeWipDUZuwgH$iGwl6nT!u7iVS~2v z3`}p_eJE`wj&9uaH0&ghSJ_?+*!Wj>!K7cWCv+Np{S4uC>J(_Ut2+R*fsrSHU;wno zHRZ{3FlT{_cvy-1hpyH##uKD%`gx^>9F5Q5VIEya?~d95>Lg8$AbgnPwXe_;od!mF zQ*glw8D{ePR`mKe`ld21q#!)z9y@CfW4FC+_b)Ela7TUiuRBinR=PpzqTT7cCphv} zl(TlTsQGS|$(en|$8+mcm)f6C48CC1|6Moo?@XRb;SUm#s1BD#r_!o1Ov^pXxtIL) za?0QiGAjBz#Z%rZ;Pk*l3?h`<6lpxGo3+A5$ca?SV;z75Hl|k#P&}2!7v)7fKSk&B zFlf17b7#XSVQ9cov_&=_`%#jh2fQLg+?7O+$@SIcBQ(ZNB&}n0%prs(i9(!uk7dZU z8<+px;3dL{vMV=+6m0nra5iR$DZQj7kg%VX`&s?e0GsZBWu5)ps$5G11cdo6#+sZF5P7&LM^<(C=|k&&3*912Vwr-3_^Si@3eo+K30C09y=g z5U_{c(iyZWVk%w+Co?Ju4sj+Rif8`~uL&)A{HX56b0+e?*&q($bZ;gbxGjRizihQU zC44Ep3R}NH+yN~8Q1DCwJfLnzy@$`n0^1Jbh-~!$LK2QTcyBv+sh<%_^P>1`$|3}wbM@7AMed9Dk$7FHgJZ&hKAoD_Eq*E_%IVTtKb)345{>F|)q96)cB)P5B0rRr#tK*RjB zr%$F+C@IczvgHS8rlTp+8?U9EmRsI!3K!EYfguj_k!3I}H&6qE!vc+B2k2d%5DFLq zIHBSr=ghZJrQ4k?;ow1RlrzIFBsnfP5AHp2c9umGvr z&8}t3IN_$5e0W+bRTs@s8ev9=@mf~~w^gjf$ru~}pAIsgEm(#ud$D>Ba1>>drU-&8 z2I{YgnB#`$(hNz^`Y9IVTypX z9=Q(hw>$D!W6n}e14WxpO81=0c0CMVGJb3@+5G(Z=;M5~=CAe}Uf=PrO;j(N|It!| zc0UFq-)&=;ngRBNyja68bPY~kV#g%Ov1RZE^K;>m#JB(bZJ7lE=#Q4U1O3^!)ohu! z4v(-o{}k)9wYP&4oOEfj@L9AR6pbPUK%?%t0y(e%eI6irqgIerL;_tJ*;2eU9Ytc} zTkTG`V;h-e9IvIZ8GO9JTDk`zW5q`UJ(KD^?faRGLQqso;01>0obn~`LK?CPv2q7a zYM@={Hb_&C#SHd~^I{^vy;LpWb1btVpvcl+B+YC&ETJx3O(&#u-AZ{4+Sty%CyQD( z61qo(+zlYV<4b%}9}>lpHl$Z9Y=3f2*XyNhYS8m&`1#>um*^k8SjF@Z{5PD#cpp~o zoxKV!WG_bUfqEDHtg#z@4%j8}*)H*S5RhoVWvg&Jt!=u$1ZjjN zVExK<@^&&wunV$Q`S8@hR9qU^7-?)+#x-cWJY-hhY)Q48D?TDDQ{S|b#&f6#La^2Q z%6{Zqnr{8z@1Y6ggd{RY^goNZNBLR)BoxNFr%8@cJ+}W8;}PVM`NBYZRVH|_@D5?M zVVglHGo-m5sA$XStpP2!@M-wsiDVsS9mYRChVh{I>BXa$m*Pd{j?D1!$H10w+i*UwXK9 zdez;B2(FwK$Ree7QeHt}|1EWjl>9R7LEroX{XN|k(PtfDZF5^#;^ntEUmZFAC~~0K zd5q7e+W*YAdIpSIgfe-tU=L@{ACSW`3sF|-^Q+Fey*6@Q2x*{p1lM3@EK(G3J?albyZ#$F8){LL}2ICqk zZv->@OhdkWF2GPK&b{}zXHrHF!$FWncG^b3J(h|2VdmBr8^m99!d@2=4T}vZr8v`r z+-33$6rJonkrg3H-!RL#>-E|uhtnR1Rm&jIw-~}xV`_OPSHFfMkhZj1RjVGfaaa|+ zu?4~5zR_e`yfjJ(due)Q_v||cV#7VUvgMw2_9FDR%f9baX;z253O>rP&*Bz!GaS1P z`1QqzNdlKm^Xbd_9b}C3AF-2Ud`^||f>MeS>4o;Oi!tO5`=ZfP%gc4zI|<61!gaX$ z9v_Z+CHbwsmJI!#vE!WcO;^cd{kY@hHe)<@RKZitlqKlq?eo2}T6oe501pN+k#qlr zqVQ?rjZ_Od4#nN^0LJjL^4)D&{a}(?{}^=jF|az~WkK2)L@al;TEE~YumaN7WPCll zdiY2eCxARmJ%Q}pnq6&h*vryQh3#Qu(Vr{!RtVN3KGTQe0=)jDC=Akz3yA&qqk*P~ z8`rQSPa)*(;ac{6N`;J z_Gzu&qhJ!E3+GoZO5P@zU@BsRp(ep zDw{!NcHyaIP0if5yY;@z_sIE=bD6&Ty~@v6tY5wX=3*#sr+T9yt@^{p=9a4e-G|00 zk?iFGmll(ycTWAT>bZV>e(w2Pg0~E-io{kCrd6-~u)1+J@*_A^Gu$?|Nrz#7Y;zi8dP)zJGhcGD1uGch$I^&cKOK09)EvHA;neDC4eR3F?YpI*2eQ>c~= zF!(d&kyZlUMrcOw4^#lbcPUNl5pE2_+2ULj?58s52aV;cVzXK=er{@C&%kLW@p_Lg z1Cf7D%$W?vnO!+O{2emK`O2joTy*Nh`j$>VlL(xQ@Iv0*hXjO+`Q8r!YGWCP zijW;al={}l6N`fm=wp+3UHhg{Jh_%UwnV`P2XZ&>rV6b+s`(fL5r2~c{8NfD&$5i4 zSP#ny3$5yew)9@sox44pV!B`8Y3y^~ZNYTGo2P2AFWPXjswseTx^P{8{HS8$&xEUi zcb2K}LbRRT8%(akg7+KM|CH^>yeCJ|?iRC}3|gqjpL zCYKuHfcS@}h_#T!COF?l9sx0}YD({%$@VAVS;LK13P1swp_X~!_c7_E<1yD@^j_njiWn5D7N2N)wI`jw=iFFbH#PBc>aVhvnCy3 z@phuQU=gDpIGa~R5}5DrIzC}=>i9;g{c?!6+e*GhWE7u20OX__6>^h<#;nONO79*3Y9~-+pe89#! z=%&+i(Q>->GZBabShc!NXMPSP81pRga&cX4=5hltK1uVDJ6*Hn8Bags(h(5y-x$b# zLjfDu)Uj2o052g#`Cb6Sp?9SzS54?ssqrH39J@)q$eW|45qP&b{w&S{8uo*6o<=NI zbJE#$+x{&d&(V2x&MTf;Kq9t*af1>S@K|f)(`@kbu^)^oTG@(X;h|Na8O;^XW=tgO zRW&Oz>nPEpXJ67Mltf?N_s^+uog}MMnC{GZ&#{JeU_H+jrDdI^FDm>?ohN&DRdgK; zmnN^gO8n;;Z4bjd`Uktu0YtXn?GQ;_elIbxg#9G(jNPhQ<+PqOK`32Th)AytSsJ{S z9xXjS8cAF*@6mUiU#J;6ancxhTOjFXV(MHtDdT&w&5h|^q0+as|FZp#h+#u0|8iEL z`dwcq8^$5za%jzzZNfR2(BBdx%QD7JxEu#iF>C9ARGhy&JU3Aqd`#S1kw^1DvEd)u zfRaQYfG#~8b~cJKGIYZ*Id=?~0Mkduh<22FfEp4UvkP476$KxUx-5EZ1%s<9Qa%U= zy004`0U!do3mSA!wkqQ{yJP~Ij+-J~bnlww9eVZ#pzATM@mw?PJ|+Wa!zd$lh&^DfzRC9ISdvtKLB@k{8_BJ&s9$x z%UUDWP=1?xC0sXHciQLTTz!`{2ecT$=DmD_!4eWL@kApwlRVUgHVaHG30M;45QBR* z;t?|Gq+9guNB$*p7)pGS-2PJwCamr+>A!z2hlWOTw<37Sp6)Y%2?Ql-M-~82i`eBi z1Az6xywRKO0t*VB)W{l)?2 zGUfgk5C0e60!*k9o6OTPl#YF1LZ+bu1sRxMp7CpP8Z(@r(13$Hdg<9-g_d^1#Va!} zwS?YCcqYuuPsAIK69H5x7)MYCCjc#Wi%6nm^YKYn1M+BSNr!OO^?O_b;;07spq1-a z-{Vy(k!po*0Ol})>;hWGcThsvM}!PKW7hW^Pmz2nX2kg0ETTZAa|U~x8>Y)vfO7}Q zl<^@Uk^%G*jws51Reai=Vc^gy1uYx|XS}y{&KKL*Wx-%ZL`36K!8@LvV?8N%pzC4Q z&59qpC=_a*@u+xVV$(1#WS9LlQV4!ock%OM_lb`xeHKHTQ`v|qXO_?wnPaQd{J8}^ zodkn^4#;6)V-&ESvZ?vUD2tE0jz?PtA+e&?HnkwFihv6sX}Nd;gCr_hyp47~008aW zKj)C~&$Sfb*74V9x#y^0LvUS``AY5TPd8j&%!WV~7x<5&?3x~vQERS<%D52>zTtB$ zk+DdQ!{9um;j^VQdmkl&-}v1dWZiW2wE|M%;p?i0THX5$`2N!cKHYqoxd{LX)~_qw z!Ls}g!(=qvILlH@;5J-C(TLVsX6IK@A9osj-0Mm*{3tQBezJJVK2g@YW=#!gBfvOs zb1c59Y7XgWP<*p&CvVA4F?1#B(dDV2sMX?Fxd3%)Z@}g+T5sMO~Q9r1W zm~xOR_Oo9GHm!c%53|=CF3(C_LY8`WSkN`#j6GBsF}3W@i@U%%dp>G)2{7_4M7F>_ zfViHTiwlf;{T@~3cMA5T4EDqx#^_OrD{J0~#JY_#m^$mYr9bH%dRitiV`jt{ye0D3 z$XPL1(Pa^pwks95axTxA=>pQIBhwT;4p^U_4G#75Z>Y_t=yunMY+2PEuZKRaUIY*H z;oL~#MTT%emb2;K+y(f~zggW6mmNOO^o@Y`Sh%Rx+h>WTJlTPeoBifn`uX`@@8RpL!v?=4 z8lj9`L|3*W<1hlUOAS2+m6xI_1ssF4d9g&bLm|q4&K~PQ=T! zwSbed*pP0H8s8rR5zTIupK6_#+Onu5dY;LG@UPwoS`GQ?K8Mx}hr~wKmL`{LsDmHl zoLo7+CT4*KWX8jOT+^j!hw7BsL?`e3K{QQs$**@#j8>+#p|AEWjp2bX`@5&Y**TW` z_VDqRh#Oo;$THo#lE)RLe8lKBV4{6{2m)q}=8goKqjj&7KA}Jt-MLZy5E_F~{pkG5 z|5%~_I(mI0&}1$w(_EeuW7#H!QTc1c~OycwB(*$W-o7oyK@mGS)Ql73k1K(6RN`Z7|Uh7NMca zSXB9D=-euK{kLDh6_(BAIJpD;a2af^=GZmYW}3WKm`I6X9@Je;g)R7vh}1Zuj-H`@ z`JcLu^Oi-u?v>oL)tlz{#L^yQZ`Q7+Re_Tpz+d!KZ=i+b?> zgg%Ztu+I{O=Xiw{)`{x6PF%`axQOD>3Q4f%`JNIj_^q@G&i5w+21)pKXdRJTMGz5 zJj_Y3c#+@IWKz<1?4O_|tzH#c+(68FsnS!H8$<`cb-2i>gDIJnn(s4%fArVDD#ooNxg8c=$6cGFfsGEVeK|wPYAGXWy{r$>*8EBFA(zvZf?;) zWBv$g!V|XD_oZT_x4-n({2%7(F!#l=5;X*wbs68&&}eML3SK}gt*YQ-v$Q_BP=PE< zgJoK`&NNO(o?i!80SJt#L04ATo8|dY{>bToA@AKk7U&!Df`W7sDg*M3 zCjI1pd}5hVQZt?S*ZoG3r*=4p2Csy1T;)~bjgIaV*q8~Wv_8OEA`Boa{9LO*F_BPB zy8ny2qC(s67j2#nj|p{c3{;oZLq$V5vf5c>cg>dOtNFoXg;ZoU=b}saEL3;74o3Ap zDqJ+K;#n9+1&MypT0st)tfI4lY+3)iVr6GzQ^f~0@wy>F6l@zB#SF|ajDLQyWuq~p zKf5HY#}sV{118Xjny}(vLzdb>Ht##_pLi7t)Fq0<>tT{H9zTTx<1 z{RD9FD3$fdO0YjRRpvk{i@RVMPhf4pStf)y>~TbG0N-82X>KJ&4B55<`DlINh1R)2 zp@n9W^un7qe?p_RdjV_h!hCJ`;-vv2{w{A*G2(C!ys5YimMf0}JSSbP>@)sx{rn(_ z!WfNIENx1^b?D4x`e=FSWB&TF%r-mBTya}ER2+i@ivEu;e>Vjf?P`D%VGs^eChp4p zca=p>S#MXe6VNXmBBNEUH@Qt3r*TgL4VW?-^WS=whi%DI`>#Byg@vR*;CAK9$?>(7 zzp6%Kp!2ggry+!udnbJ8B{62XD?L*@p6&1Z2)#Ws7*I#dFgdfCevu~Ea?u7`F)6B z>kf~cI*dBk3$DH_%+wpU@D`WQ$hE5z8}R_fU>mQQE(8ew4(2<5UWuI4G+z$_Fq4=# zibOl+aTFg{RK@#{hDi_-F$0tuyMPH6sjhKcT3mxEk5jCBIthnw#ey(ec1rYp0NySr zMN-FA6$b=_X%jFuIxnYT%mJqOIzc*6m~Z zLXPO?2ie-dvV1bVde_7%{D0nVnYS$9uD+FE`w;uDhagPGj>!qcb=38s@8bXs!{A4e z6&7T2`Lj;^27qMDyC^Pp37aApr6)F1B<|~oFM8}7sYvie@k5gjLAC( z5gSJPE)X;xTLcMTyv|=WfL2j*8+aQi2jfp9%=vmQfw+jRkRTwOm6%%6^W-<2j^z>g zB4=Z+urJ8b+%*MJ9t>1fLB}fz$B>6W4&PkP`AZwF!);j60RT<@Ku4iMUiukCMT>nW zkTtz9o9Ts6gqo4>!g$J z{hwd^mEkAnU%D@tdmZtg0{B1YMB)<+1RrV!_D-f;q+tL#_Yxq|{0gBZwt{tDu@`R=9_?I z>Z4v!v@uYDczCp>0J+VAq|mbB8VK(^7-0qaEqrx)TIgtB6(=rG+u$NB3^bDvVlRbFo zE&As`Jzoc6PiCS)#C+zdfB7oF+}#~v%5=^OO;#{;?80 zb}Glj#OMPr+>aFhdcFQp=RANJx<@{b_rHH0E8!2eY0N8P0j*GlBuMV82A`5P@CG5+ za?}b?5l7To1J5!@fg`}HyOuA2lVNRzt?i8zO7?Xc=~qN>h$G(tUI$_c5bIeAmb{p| zEway{0%=Y&oxxwa=}}g!TM+I!Y^FqGS5XBNXZ2yr;4yS3!Ild*LrlxCw(w7Uc*s>c zbh$oF;tU76ooaxBZtcu4eap^o z5R#zL9*D6hSPoc;L9hg683Qc{qYlEkx^d*W(iY4R5X47=D1m9lq7E#kbYK=tse-FV?NIA5`cX#h4?z&kUkx&7b& z(*Irr*kg>DOaH+t%L1x@eu%%mzng-ELqxmY?G4`7lO*?+x}GO8?mE}I$+Kr^`u zEYciy5B0pk|7MZ|z0uAD*!4~Ts{HA_~15UqWD zQuQH}-SBhL=+J-Nqs*3ACVA986s|`xujD|X(5b*fK|Ckmowp?1HLQq{t0MD1R+h<= znFO&qhW|QBz(>N@Gy|a0Q8{B>2o1;YXgzYim-AxwbJd@AL2YQIoW!VE(A@uua( zzm%@W=(Rso7&Jfs&UsthwHT#t12rnaRkgpP8ps$saflflfcmQjz;KCY78k&^2sRYi z@n~$(#uwZvcbE~l1aVlp>|rlfvR4dahY;0HpPhL{pHK7vJ>AofAi1ob+x`XWJb2L+ zNz-*5<$SAdSU0O5eDvwn&WP)@xSxh3?&aWg_&oP}d)$~%b^!=HxrifZ#?}wd!TDea zu2HGy>0X^BSCyS|G~M>_89<%KX+>Wey^9HSxd!{#o`QsX2Qc^Xj=J3&PD&_$2hZ`Q zZ}_h>t%QB#oni#(Mpxz2nwMSweg(i|?*x=-sI$0|2Q`M)09`Df=^GsF%i~`*sA?HO z_YMzaBC%ZdoBnw=W#ke?{8F(-vAG%OqE3L^>&y({D!D}S6}}qAvI88IL+s^Z#}j%l zhBEJqc%3=TxsGeD8AhQ`fh4=ZyNu2<698_BpQJ7Ih((G3! zROrz5;(fKi@_?gjuveiQC|=TD@ik3kM>3b4fsW7|6Nj*;egf=%=>ePIGI*~+Xx=VR z8CQU4llmT}>|C(m#vPpChV{r~Ks8r@1xGDXAVcVVW3h9yKgLKPhMN3`S z5)YFNQZ>cU3in-{?mL1=Wc-hZQX~;54$~dL+jHPa&#aLer^-eLd4B%8;4tF(*^}7B z?a-}04473jA|PQuXv0^Khu0vQ)D0fI`YeUVrM6f1VDSI<&HqmcV8)^*9}vRKS_dAg zsP&8eDd4l20d8nZRDAFYFsJU>y#QyLAY6gZf_?=jFdxLAB@%n>p|ICJ1n_t601AK~ z-W?bHD%CC82G2T4Fzgguf7S%L$^-1PH-1AkB@O znF8v%bd;#oeN2_T;P?&6r!ycB-dS8n!GJ%WdsF%As^^0K$H&)F+z$lytgBa8_L4S$ z^?_04)bri*RP*+T02xH*x1MSsuO9_*e=krH04b)nj<;mHfD!x()XU%5DZ#R$&gWBQ zy8*=@eyg>1YY~`ZZcDhAN)w}E5WJ36p7<+g_+I}qJ=yoYncLq7JNr7ZMGfU&5F7C(Ae^K`I&g%<^NSp z{vWphcF!Lezgv;B$sboJmciCP*SvN>p6{8k#rMgOx0bGen>qrt+dijeBx5UwIfm;4 z*1n+RNjk_(Q%aG*VLoRd%wiW%9#yC97NszGEloQ-?3X5qF@m9Z}c1 zj*XchJhESrE=?|62gglzc@%_XBjPSV&5mXBpO9^=;FjtAe_W3LJd6M5N4fc=GC?Sj zA>tS%!p|pv80&}r0O#HpK(FLgTBfK1=DAVtchhBMC}vt>w~wERFNY8qfTA`fgtq7@{2nh`O0^By;cuG zE>_~UKqq1azkgBWh{v53>wo9z)xh`J9YDn@G+9k}3+yndZo&j^BLEpQe-(7DE)^{9P|A_)~Kk9*=H4!CJMq4RJR1IT*AZMS(@cX1nuyhHr*9tJ3wO} z-uQyS<8X^%SO7~NybShAN}~eD*UeamH|$WFe}Dr2)64n4()2SZcYOuCI`<8`?e9&s zxFY}gz_F#bfPrrJm<3Cw+P#mX=q#6WziZ&Ii<-LwP@zN;fTJ_=TIM4C!#5{+`@Po= zAed^@k~pmrI>*6Lwsr!_Pl4tQsMIrn+u8-r81=MUA_G1)PVudJ*6p|^z=~5&atMBn9k{)+)SxWoBecB0ZZ(6;% z(P6+03zC3&PvG35vxTTr_Z0X5h|R^3fsmQ>4O6d*IyJ?i01~yAf))e6gPl<1WP7|j z8h)rU+~+vSvIyhGe3x0v6kZ3M+1{`!o8j!H`zhWX{puHk_cyQjQiuHnyL*>KLvYDX zhL`R58c9*Yd3Uh2tlkEvnx#pmw!MY7%kO^R88}-BXZkwXpV8vcf+VM0ryJ;ThWg(%+S-y0-5zF*7UuMMw+Nwv%qd*+m$~f405|W5qEM5- ziZ)Mozu@xH&7T^A*?2jLl@~vNra>Tx7-Aeiu?`-#F6k29JUg)5==Ku%5ExBx5r%RO z6ol1qT(Q>>4d@Dt)qgmiP2GsE=jaHWiVXxxa#G&bcVaVk*j+r-nEtO>OQ#QS1W%(I zNTZ|F&f|(N{`sUan@NccFEa?1R0>-^w-B@$8t8BH;}mQs!Gcz=0c#GDriGA?azgH$ zaN63QuuRaP%gmCRTf48H+YN_WZ&24}c^^>0N3t4NxQJYtAO5&RjY2SPGd|wubX*t| z3KU=)lJH6EvNQt)HJ?@NZvgWj7+#Ee5zgv94kAFHGZ6=V1L-3PTXi6X!n@F`ClHF+ zL}+^pcV_rP{PZogh!s9h(7K5@&$a%cfeQAgmGE8=X8XkK4 z3VIUBAUXRjlW$G>Wu`ig=D|Qq-Mg~&je095%9T#Acx!E@@Ap15nkB`P2zFqDE=SQJ zG5^%48Nx31cs>TZ3P~p;2Bi`x;1Yx=KqvAA_K1E`mTe)#+tQsRxedx&_D`LpogHCM zT3CqYQ0o}0Dp0C2)D-5?jDE_oU8htRikJk_s|3`hs830uo^N*{>^ROSApUT7sN)K&&>*7}&_y)BD*k?b;g<&w|*Fnf-MnyvQ@w_Qg zF^DXP3)`bw=@<1i!_R)fFF?rtr?fo+XZZOL@f>ETtyGhX7U-HBPPJNHB#|o~Z7#uE zn2So5Gi0&d;X8&L1^+c8a4@x$1{)F9d~prW7f8I;E7Ul^k*M_l!P>I>Y<~Cohbvdt zmE?GXQdIaaC*YO_nLeP{_y=4P%+`{7zb(KuL?#uT-2sg7Qa?I(u8bBPJ@&gVF#;bUgk@4maP;xq zT638gC=94sEh(=+(c3k_dgVbyjOqK8_Z5G1XsiAq3t!mn7t}bXPN!OzEHA&ZfbRGu zmGC@pN7;LPV3Ayfv}y6#syw|zsI+F1?f(ca24jY3qB> z6TF>sL^>`K`F7*Mkg^7wN=jg3EM-#JGe50tQ5mLll@J z1*6dG@cB&gcMKMOUi8a~*90?g)S)s>>&v;YBQ_QD6XM@L`ju*O6F2xuMCj0<)oJ$g2 zSRu0zDdiB&TmUX?a*YD(Gcn;|JLxFa%DuMh`>)n}yiAm!w#Z0vV1zu%K27ZOSf=T4 z8xrJvS;xSemlZG-50(Me`!PSUh8ke6sLAGh8WniIghDcSA=}DN0(-Ox z&#YF%6QWb|weZEiPZQHW$a{aMNjiwcRRDzhOk-0V?A9jkR&{;a1^F9s+SAS;*ZK{e zhPC7JJCT=2NSw zX6%)@fyK<}G%FaF3T9};V*E(uOFUvci>}B6|0Y|8#=EePun;*W$rZd_vKQk{MqymG z@`_WThfpIZDbrpR1`}cBAkB#8^Je}qPtaV>fgWzZvi?5KtT~Y972R07BPNcz0YbLp z_6rm~6G{Av7@hqy_IE@bCxm`VpSNtq;i0G<@o(GkaWrX+v?_oJv`Z`|$ONV@Kjxv) z_c(r%>6v-2E8O8)JrJrYdQvPgp@e95T4nDaphf~%GW=4fdHXmZE zP;a(7Y6di8p%xMBvR;Zkv_l^8%MmtcQ?$b$poe!&x*jOgZ(yDv-0?6kSDtLqkWf4f zY77&AUM?Sm*x#Fv2^-_vW0Wga=v0GX1CPq;@TVV=;XmH?3ObMCnQ*5X1&BtmzW2gn z(0GaWXk=}}!|$=S0{QPMthMuwFD-sH*pEhR?C%O*sCtuR9+axPNt3zb#V{hu^KM|A z3h%iuk`dP3QESUHa>ZnnZ6Q4ZWU=MUf-D99VtUX??gnH1=rJpNAfm+nWa5XH?6&q= zqE;blShdkwxk%A^Xl*;n6sG<}T<@(h&39ns_N~@)_qQn(s2f_2dDn+N+iR{F+Z0E<($6jmhSXd8RSqzls9>u4zY}{LX zDdIKhmafiI*RkLk5?$x^&39M(?>9q@86D?$z~!a>al|cV{`a)%!pPJQgw_%Xq3+lL zKWay{eoT}k@CISGe8hZbt1w3>bEryqsS)^af;fg~higK(>2v;4P-BbkThY|f809d4 zncw4R@cd?hiJ4_y?FDCgK@}}XXeRhE%U=ost$-z=x=o%^$T{^DD>>u^bx>&cirjtT;G5sr$B2q zmUqfKR`g{aw?Uymhg4Ykfr-j(!8gDpj~1sI&+n&snN)32Hf5~q@ymj~@|1+YvH~Qq z7+I_=_9lutC@%*DUzvlI114s&KLXIuh}j_~ar`$Zuq;9{w=lm~t@1y6UMkM4S0)f7Mr~-u2*3($*5` zqr|Ps&ldkef&B$E{FLrtj$`vbdo9o&jwAl=?aA)k7FUQ?CqR}vB{b3sWJ9s(^;@BL zN6?jv80bG7Xx$SRN$u>4q=?{ zaS+epnSOb-p+==_Gt21qOeY+B>SyB(nYI5u0z2$YL)d->x;jpk^>B99t7Vbw(50|S z{=;q}(dz*jsg)qILys;3yTHd%Z5rkImF2vLFfmo(u-knweQe5;*4MMrgx0G~j3j44 zcw}%abO&T#3(yN0-SOsR5h6%_&X@GU{KktI$CQwmD2;LCvH3_9k7S?Qk`WtVxGToia2;8c!$_AJKA1Rlt{vR;~zwYg#Zx->lE+Y_y1I0ri0EgDm~g>>S= z$VC!yJl&*E$Ny~Bn03-2&}@u6^s@PcMjBRn0)|b#L!9WY#}hY z(=NgAf{`%JL!4l)T}ti=eD}*00E9&VO^{QiMNKiwIdKl!zT@4$-e|!c77ijNomC|% zh4m>D&)p|0xU1V|^b`XwQfY?TVal@(2<-f!u$R;tM3oc0k4I3|CD=;ydd$#Fp`p6b zpf;ubTh^d63#%MfQ1I2)n>wE~vr&*$l-PL%G9Icn`cvjWddH6yy0NNLj@x+{?~0cx zn5|mlh*k{RTv#i5C52%)KS7j&>+zGN_G<-|gkmwXPYQ925Cy(NX9pvj5;zBPU|IaV zG}Z$}KDZvVDGiTpeaM3%rY2hV_3UboO0`(NCz#j>`8z0bFB~UbIIPR*u-n zE#M8RHET`G$xkcu3{UEJ)AsebW*P|^sO(EmUiBvO!rA-AU0~%LKZ=4Vu-S^d{&k07 z7*_EufDGFH@*0>2*E_WO&SY}{x+^t~K}^-rNJvlXTKmkkBVUkq9gzrYRJrrMJ+4cF zUSP(xe$^x;+Jg47LsV<(i&`B>TX_5WqL4H|M_N1y8l{m9pOIj7Zr3o@9rR-&j&d`y z4oTCmJz!-#ju5?4jR`Jib@f@hm6Ter{$3EXRYgQ;>;AFjCV|Hfw7fmnfXZ7_?Mw{Z z-NOT9at$MI-+mkfV<0a-CC6n~=beqwyurFcFX|47$M25`EB&Ua=*tK8%qI!BNAg z_QClV9^Rvx1A@V9ARwN(Yj>^yhm~TiKl;E8b2dwg05CsNhw* zw$I`|*v5fJMKzKw!yVTPa7ptV^dUdrdFZ`m$(Yvzu7W%A4cH{;m@PBZizJBd^(+dd z5**C-((UpX#0+7_>Vp_;l0Faxu!r#qi;K4rDF;7)(k!onw&<-#v;V`{VmTeo_qNHm zdz|fhlUBw6{c#Y5s<}+h<5cgC)7wMFsn-lk3_iG%<|ERj!$O#nNG@$Am|e{njs-H? zo#{oBhLRX@$E~lXH8a+?wWHa?fYNww__eq>_FMU4!fed#ND(n_OhjGFC9Aoj0FAi} zSY4q=#lxx@olCDeN0leXNiapkz*gaXONVlb{c`IfG93TiYWz{RJjb=9v#c6oZ{yHG z^Wlv{4(7^zk}=SRPQuDm*fJqk7%6|%E`616s!#tLcFy%8k=Yo|6Sed$L;^Y%AFN@)*Sb&72i_HE%bzR%~11rD@;aAioJOXUbw~ z%ykiZSj0P*Dy#H^R4x)qmZX(~Vwe^(3qMFR$N=#kq5=4!8w0~=gb^66Y@Cbmc=1%H z;7G_i3igO*?x1ru8S~e;1{`1GWZuXFKQZhT)d?}ipjYOb1oYJaBs_8nQjP~3AZDSR zPD3PKI#de6wQPl$;TNm*X1Jm!iPV8dyc@vd=n^ zr3LSRx~4KM*8v~-A(mK&XaOCixNJFUy^iAoXupp>U_P~OZ6W>R)VA>(?CZ2fZ6JQ_ zy1{00#D+8zVRbfFmH)PlERquV8(_Tq5sSK3-mlM-dS5DyQ1rNQjUO3KEk?a+#67+& zZHFl8Oc#0aGpFPa-;W*%o<(xR(h%#w9{^fk(WkjX_A8xl^FIqZ7)sUB*UaXlPT!M+ z-XgqnXcEmItD35?=s51Y?tPm8a|-cBW@13XGk(-WX8sDWvDTU9QQZWQ0(vx<+0Ol& z2)wGEgC;O1*jw4;lJn!N(slHH4Hk1ekUehOvG_z^c1|)qDw20E*>d2}#w_uTLg!Te zhPW(Yw&mCRP!lI3S=;QyveHlTcVOn7v+&>Qe>do;$3K^j43b5KUs=<)Q)5%*GD~TM6BJhGA_t$|0vL z01D)!CkT>k)T{Qr`Ewpb)FIjVjXg`XmQgWGHjpu{8>Fn*Iw%*DY>gFZGoI=?1E)@X z5s}euJk?bHz{>_ueWyq*M;^#zJ_;g1WQN_|*~ZFS3w*<((<+ZiuQ0I&wwAm)!0m3A zW5?YhCuVT|($#!(?MQqr*G)mcl&D-6M)?C8A}F{k7fR-acl-|XmdUy~lk^mA)>vtG z>S)k%09%LN=5$*<$Uyb1Z%H;xa7ANb@FzLmN`<~|k?K8W--`JfCKGm}8A>aK5&5rRjs7*ESJE1PK6YvZ_{U+IB_Iv_ivnm<;`iVlbGs#Pp{#@z(xW!uZ*#SH6O>uL~x=iVm9`nJJCdW)W>P&IqLt<)83nh&q}{Uyha z)H|!u9 zt?2#NMxU9q@3MIP0lfLaFQJ4MeB%3Xy=nFUpF5EXQA-*+%QHPLeok!EWMn@lKmA&i z@L=d7`huB&Uz^irNj&Cc>_T*Bp}~PTAiS8JVs>l(>F8VTe4;7d({7+pFif(UNV#PB z6Up=AAS56Vm*tM(NX!=yO1gRE`UK3?)5^aSZ0>t=Wa3`XAheXCE;Ek5UXo0A$jdXO z=axA?z!@gXUU6DW6-%kuf!rlm`G0{rB)MzR=$jf{gkMKED8+XIJZCgK+D}G)5bseL z4wpi4KBeKcw@3u8aVHMuN@WR}-;uw|zQ8W1^<&4()D>c5FH~w5DG1dr!k~9>mY4C% z7(#SAt0;$}XVun*DiA^y*j+!s4s&Irr*1W}A!$}M$6IAFbB<)Xb@;@i&ZBIg&*;Ye z$*eJ)Gc$3k<9K%>)BZ_R6bKC6y2`94syAgFhnL!+|JF@*VT`iB?;6& zZdC6P(U2}~N^y-6mTUp&T{G9*vF!opaSvH#S3YsS?U8(zlp#Cou;2^qFSuFfvgGn_ ztgoGYCqlRhWwhDAO1-EzuYNAw+p(GRSRhts-a} z>SqBc*Wv!5%N@W=?Y^L2%=4fsFvb*ZY<}R2SZ2CMy=t~tV#mvuItak+N?v#%UnRg4 z8r!htvFLG3Nz|asFzWpZ1cTW~`WwL?nqjhyYX?n3O;818qUaQ(S8r=DsZ|OW+MGxK z$nX|6mshg59ex9GUl?tG%j~nT(v{ZbE3l4mWs0K> zful&{6n*O=^ePBv9r5P)=f+mpNN{-w+wP<4A_5YUK8}(cquXCCD*0zK^5_S=RWp+R zKfc~Op349KA4i9dee4yEJ(H2hCPJh%tR#DcP|C3#j=eKV*%TGBvXaaQWfURFNQgL! zGD^S4)%*Q=H9qg}@1NIA(aUwN>v=uK{c*qFAD64s*yG;caMU8>Cm$h7hA2FF(5i}& zU%s48UtLvaihlayfvaiXvDYcCF$YYYcV8?GSBrE$sQ-49ZSMM(7d_wP^g%)-bN0TM zv2)Dsnq`q-Z}&brIe&K5Eq{gY!(RRd)h%v{J-b7L6LONSk5{P}VB|bKF7+LLorbH= zJ^DJux%5D26Ir$loDDV0o|3uEmZqubRm>RpF+KSel7PW=61X?HIr?FvY?akP)sV#!e-)%Pe{OU-pce-}Gxma&1 zaD+?o}`-YrQhY z)q*pfJIf)X-$<9atJ_9BGmNPAEcd`l6OB=4I7_O*!;mk$VFN98mLt5o8fhY?{nVd2 zf5s*`ovSu>t`#)5`NFU-(KU2Nd!v;^{9}Q2broi_eU$LgG7{~nXhJ}>Tq1uZpSe1w zdt>lCPKUd zR>=XIxhTwLhkXQKp_=|KdOFLQ7Gh{yu9EwOu>k#u+^{d|bBbeM43G3EjXjEDC9dg> z7-@62SZhWx3X`_qXWLkn)Lu%gsR0T zUkbq0qamY?`-v{r5k`aF^0)Jzhsu~8H6!Qj?rrKC7Bme(oZ|Ak96+hF4Ui$A`wk zRa08JY*{wm%x#=O-UlwJETz!JpNg2I(4?4Bt;-H0uSwPH^b?=4I9$&7X*W-=S>7N0 z$_fgn-o}LrC83zkU$Go5Z!zGp;>US(vhUXpxp^ct`Dg~bE7xc?WKZ5~kcqnX9Jf-$ z-PY`Cxs)t*ZsbWtx%&0}E`#lf0@W#6Hwur9iAmc#?hh+oQqS_Tj1rop@IjHGEo5g6 zP7Cjfz#dgyPU`;jDpc`2JlLyDr16#EYP^UC?zzbcRcC>aoWZUzsGY8-`%SQl>_C zy*EggT(t``zddJpSJrpOi|&pOG#-_X=lW-ko=z-WCl9Oq{U~*7u zt7uYRo$atyW5sb^!oGp0;`-Zz4fbRUD^2fIEdJ#6Lve5`RHKahaEm`VcVPVp;7oH* z5AAsSa^yN`WQK1%r3sp;z~e7C`WMP_wxcEIMRQN?z4@HBJHIM)RNtFbcr~{zJfX(B zYK)A2{G(%KGnppI;W<4e>Z*@geuH1;2ilb5Ch^KPN~Dy5n!57&D94_{PwdIn_r0gd z2SqMx3#Ks*BRn59x#;JmpnKtN7wE;{>}4<(zh>7{@5EwJWkZj?A5} zK8dMua^1rgw!NCMH2OZV$d05IJBQ)ZJAsbJZH8~2P2JA@&K6kIcgsq8AG*Nui}8&Y zgGPr9+fQH$9_e%4s~a<~4l}QmA#hh8q*TthR~-7u29FC9Vmp)?@%4!%O`e`O{UV@21!pN2yJB;-Occo&O_&pMF8+%C|AA%s$l7}f zE1nweb+oiswu{F#n#~{A>DBml*3s$~lR$rREF0P}U8X07)bmrJ?1#uXw2Hl;ubEyq z+lRvwf&yQ}xuv`t3uTogGU_8@`wR`|RoYu=SZp8PmQ%Fj3)G8UJe>~ItvAF7{07Pc z6SbGUnTloO3NaH7o0a%z3du?o;R%)|8rrnn07kQ>fO>y< zOJ4WcPx_X+XD1M5`NZ?O1k+zl9Mb7xh49^J5)XAzmO|5KL(I}LXlgTY(r91(zLHWP zsMHrlAqxddC9EB5C-akWg()J(j3i2|G2AxfGWxuJ^Ld7+KOg7hd!xCVJ9VGxw!kS= z9^W7cen-cw zN*=Es$9sm3^5HV|E`Geh+@owEMo_K;UFgugYYfUU57 znfymlLlXKn6qkuP$bi9D9wO;uC8Vap_nGPOR2?TvjP%@Ue#aXCLS`lBNP6Dv`*G!=Ny2Ds)JzP+SGFlqGN$R57L1d9CaNd0=4f}~WAz^auMzWq^RH=c4Gwj~WWI~ep0*Y^nMh=MWV#q^+6 zs{xw5diE)P?&q}Q(gdkd_E#iYJX(dA7fMety_4bZ05M%RyQ}X~ZS?2!&2?iyPq|;D zojqP7I`0fmeBQO|ifx>;!!eE4|HUdfh}Ez>rOikvR$Q)|iNo&*ww>$%agZaf7VVqA zV5G9D-Nr?pCxG5evL^s|NtUNd3{AT8nYx7{PjI6VtUFZW(9;QZ09<%nf&IC!VV}we z{$zxDo82DtechDJ3DyMgm0qKf<##N$dei^{08uX@ZwvXJ`F85ENJ@^uhdv%{_gcX% z+@swuehdz0psFnjH#57dKM_H(wWc-0-fJ_>>z{y@T5wO*5M334cG9Z5R_9d$J~{FCFN~B=S=?M4x;OWDt}o~D z@D`A`Um7Vb2tGc%Qa3~AwC5Sgn z|3+-%X~^^a{Qe16ZGwa-)oi^5-qMbUnvLrneYmvpB&<e0qz@Eja&}cwXyH#B>VFH3Ir!IN04O?GE zVA+ecr70Lyd#$2dF)F?oGRH4VqstHY2^;7PeQNc_V($+xpMH3Cf5n!krY&W0cb`zy zQ8;+&VcZK4b_2iK!&+L+-@w>ENCNm)1|Xq(eoH;`*Be7%v>px;KgO^sE^s}HD?bEe za`m0jV1qphH!}NLp>0Qu6h;voc0U#uBy^wQ{c#ca=3G;%6g2FUQ_Ac~iJVs4uwR`0 z9Q*#hVGJk2Z$Y@U2#cP+T&^o&D$5$IM=Aj+?}T;SnE|1R<%!?|_Vlhv>5VxXexTY$ zi<0G0@LxqtqD$>@8FjEqRrQ;$_bwh~Opyxk(hwC#iIC#t2xVf6;oZ7i)Cv(vpA8!U5?Y0aK|ng`}_HkXrw`6EI$f%Iq%BG%90S(6n6C2TI`9ACqw zn)Q{pZxJaZo0fK4-6T2qzw=}(ESr;6&`-!Hb`sn*u}qHH$t&<|<+N@iR^`tRE-}?a z$<)T{I5pyuNE@|ZGX%~`l00=pux17Owkie=*Dt(W zrNdvN>b9BW>SG~9bv?)w+yZWM)t!??e&(~3{!zGIZ7B*m#YQmGbClpw53 zT3+01FA>AXOJj!K6&6XUEseIMvP-2lE!(HfQ@%H5@vijc6IQ=4{NIm_r~wEEMGc%z zcJlxIk<2m8J)}H>V2kEOZ+umURfyrQob&G=@fQss`d;+^aC!06S-O-uxh0I(<(v}U(&LIGJ&+l&`WMhSHZ*cK zB>1R;!oyZoApeY_ zSp3AF0pMrA{vX%*pTEy_L$oVynY!HJe?9Vfb08qMvHEDwI*+u1b{<-@; zZuGsR4B5;bRD@?FvVx*Ce6iBOI|1AC1&MC3h9QU^9E!#ou6(?)5`^XcO4~=0%>oqX zwYg@nXNp%r%*}Yp5XtC7z~`gePzlEc+;ppqo8QX!;|s9< zU&9Q@7EvIkNtkYFJvgSieroZ}!&-OP^X#kZ1+qWH(%%-y5T(>I2*>lr#vm$9>RTczt>o}m2oyCU+uy!`+eU^$ z5$kY)=lAC?q!tt;WzheRVxS7d7yXXC*KI&XmDxv8q#FJ;3K=4kGk_^OTwHg74vjA)&Y>h0Ise78coN`Rf1u48pjU02| zf|T+L$U^H)X&kTaMr5qi8rP|NNkn%&I(_$41z2fyV|-Lr+nI)8`sWY+k@1>utZ8`U za(fNGfO2x+b#!k+(FNQxn87}#1@AY(S4HSl7cxs^lU37O1K8nK_?AA3u`U=f7=U{A z8ZC!x`^qy>w8|-L*>twbyQD*w`@`AT-8y1euE1tFM8x_L_JmYqtNJ$-QPoU63U#8H z{k&%cM!M!%PEn$W!i3FgkI%SQ(6N)c%RLMNhewd&ueCS{AH@41s+Lp50*ju>Xj_4Y z(!aCW7d!^C37@am+jjDwc&(~Ta^P!uwo-6Le5_OTbXXQ9+{gLu*0ZQNDvF@6jV6e=YMwoYKJ9!2g`{W* ze9h}YAO|0#6v<5TQTOCUq(u=T)GE#WCJ9`vx653$!Y4IDr8QJ`Ar# zm>BF*?tN$CWDB3cgh;Dwwm_74IihhPx8Td9oCvVzKW>JgAnCcE{z5^Rsqqk8>uX~` z%I{~#rAZ!tL8)V2CFPcghNPY2CBy5|e1Wa9bu0{YoknwszfFN5Np|nT1BYhf0Bo!c zh>Y>s?RZ^|DYJZ!7nnJRQ*%r&ZXUf(|4CZ(hQ0DqdDwj;MyVy>wVQxfNx&%LF>>xJ zFrMe!Z_2x-2SOEH1ItkwtOYy{y`!Fv0eaLyW0m-#n7XNja#+0Bv;}J3SdU>32GJB0 zI{c7Xg5V4XUV(G02bUGixwx-s!*x57$DpfSUr9N*uUg_|3Y0HE`?8Af-S7*Vkq;#= zI2xfGL|DPyu^z^W?t5B*4UHGHt5M1peczXpQ_Hb0oW1I83dM!d8t9+5-MpK0<4G-0 z9Qv#TZoWdz6P%??_)2XO58A2hcwV-AgpgimYOp+0jK*)v<07NxUgKus-#kPuu4;#2 zLOpp@nC5FikEfcozk;;F)LVU^(wEg5{sMJ_oSJo`>BO5C=-b4*$@YlyaPWf){#y2~ zXk4|dE}W8gXv3#}Rc^zycnlTcdglI#g~l1>c=wwBp-kfDgzZs&#ejl zS?4S?ywe%We61cBsZ=M;wTZq|dJlS#k`v3-317R0PpIzhdOUFW2X{VQU+APU|H-o_ zKHf~y)xSNb!N^i7AxcUqL3PAv^RF^4CXHm8a(t+=zuyr+f*`iV=cnub2qaLmrSg+i zr=2iI--<%>UAUv7opfP?ICTX)KO1m)ruVIQVs<4{$W3!FXF;Y#tR7eSFYUxTX~orK zBf#4vYEX5zsQgeBHj4i07sDuetxJ=uHjwyhk$w-Oe(Ju}o19(mX!(M!esX#!rLtR= z`%ulSSQeUjH(YW|*xl~Gli7ZJaS~aw4#uLtE4?#jd=+|`Aw(a4Q`#m}9;^$_E-8EY35~7pkUb#^E4)wSBbW*_*Gc(MlP}J_< zA@3q?ciO5`LbgRH0Os)%`&8oSeilBBa?d`U+FM&e z07Z;}d)ddU22vHs+T(MwTjVjV5;Rll^ErB7_gK$?1ga-^q(mQpD%(TFt;4iIpy5qWBvsNE1FItip$e?PIN?RBBCYV_lQma5wGXqS&tlQ zBto}60#VBqkBHizu58unS*mSS+hT5Z>CE6Kjz9We7BNR82r13lKKwG90)6 z(y_#HA{(rJnc-0&-aLYl+4 zA>aI)^5uFcpT^z2z*|N2y#%)!RFkP^VSPdbi8dflzjX}`_+}9G+cdrv83oh)g?r!? zf3y0a*PGr9Ia)6{+xMWl&VXV*tG%(l%x$8vKK7PwJf{QFT_a}a=NQ}$O?tsXmburr z5x<-tLe1K!<+H;2?eY4|njtJ6mpWe@4o>7%p9sEvUR`&aCV%td_XM^~D9VSMwmwLB zv;k_Cuo#@pb8;qTjf{!o8E6l6I=j85TmQNiD4c%>>e_Goe=UHMn6rY^nLnSuij z-OL4T1iDmkP#6chs;Sl_&?*lqpUyZ4TdjE6j%t5i<(8q;VpQ@oQ`|ucu|=Q7(po=V zFO|fgKXRvri(m*b!)LMX5d`dIF**-cs1|$zE_J_c)U~4-l(K5Xm3mjVfd|t7Ka&YG zS#5~ymj0y1LjkG6AMnP~Xv*_1F28wr|1{fofEhM;Ntd(0gUX+M=trsiSEA=!md}=W ztKU1@DRUwSe&6*RfVSl!SS`m>GU?cWgZ~%X`8Kl#ZCN)y26ahb$;6vXr*Q8Hpu4%Rp{$FuNlh{ zOk#9Q*AyZqrF-5O_v6Pb&_vds8!6fQt<5LbW+WK3x?!%MDo|DLp~kCg{1~8#1)BsP zvsdyqdZ7=X&r>zqbE#Jbseeb2ElmeFF6c50S_Xe#_id#+z^FtZ_h8+#tCdp8uHdlR z7oA7awwgHrj{C}4Bk&}Y3vK!4YiIvx&5sC?ws*lH$Xj0;eF2oUIa}L_6!3j<2&QkE zj*<8@5nFXoLuhq9JTbqcOM!1!L58{P5P#xpY_!a7zDT?T|}(HMKJ}jj{xGnpT5(7O=E;tWvo9@ zgZ)IdZkDo-5sm)UQ`y7O8pfbq$}f(-tMXTb;^)JBHDjQ1P|Xt{#vHG()uEIiyUv_b z*B2Kft|i+};ax*8N~$XlrRxz$P~;apx0oW$3&NI~q0%!xrR!6jfR9a{%Xq_D3%2a{ zh3=wXdu={Fpkx@G6X$wD=~Tw$NDQjw@KuHnVM#*zRpyA%TKjXmgtQEK2ux>BBwL95 z5nLdMXOCW&-&uQc>@`@;KHB*voZ1Oh|JU|@k_@`587nyaAtJ`{9@FixFXVZ<7^K+J zjF;i1vB9OoKCV{*B=V{8y42clqYfk7s5_J|%g(+AJBr}V@2&PRli$Pr*I|vNw6N~G z4`<2tG4@>Br_gA@n6MkEWlF(mWtrO!0F8?_Iv*@%Yr@O(QlB+BFYYe*5qUt3?4GnQ zKjM#BA^~&#jMWEzXFnQl|Bbrg-6#N8ap%&@3ZnFspymK1)4a@B4;eEseq3 z*VTiYrXC>n)fbHe%VtF%p;Mj649#Hfes$>1$ zG|s#%F@KSmC)#1zVeXR#YrebebVgNcmHzCAMTb!Ax#ucu!}ocYkjIwoi!o|Fe!={^ z_WtB<2-WYadcmy8NqWM$;D;7r2Bq5# zYOO(ovqJ~|INqZ1D2(c)(qmCt`iqi_-MDkQ%`J$*ktjRqSR1ZfQoQXFjg7`|+N$K4 zSAE%+FT0H$TM!~XwyGNRr@34IXR)TiAxMOK#5I92%WtJ>lKUJQZcbgfhB7I$%#hVY z-wS<}ST}-w#y5n+z?&u6M4%`wlXWfgO}x=K#t$}Z@&zfoOcWLa(Ie1i@hJDAjZ${8?FXo zln{-_a=oCK`fCghvxtnpek($L|GGmH@a^f`yRv^}ekwzf3KS0&Y`*ocDzh>B#|wbh zP^8Qe@I%$5-C;|F8uaVc^LR{H5^JSB8Tu6B5fi}0z>nZ0JPl!M(F{x6sZM_f8;d3?EZ}@ONKXwVJ!4dsEVy?&~YabPC1$%;q z@1J{I(qnjyn0nHv0#;&mZ=6ITX6zIDNr*;7!$2nBZj(`X6qnd~o!SH2Hhe zQ^^O~>;tK(e>sQdj!;fso`!W+p8Hs$#EI1*K2!t}v;^@8rqK-Bq+u`PvuyeLV$a^Q zr}%7iK8bzk&kI8adKc?ag5e3P7keAhYxZ{sgDo<4QY-tJW%@#TL-blQAfexCo=8~qcWH&aJpPGg?i!MqqTNE-!{z$IvnygZnp z1I`Qb6zD2LvDU1P=)_{wLiZQWhN!iA+=WPmC3XGlCi9NFKV_!6FSKw ziaCv~!=~!~_suZ@X<5K_8N48{PRK|qeFMhCmS&p#-6E;zS&TR;kqz7(GyESSTn+^L zZ;QnUqw>NDESvr3|9=K#8f1WWFy=a^p-ZUAddK6QkGxY3qqB){*l5=|;1bOy^(&>} z2lYrQw6B(vk+wrFjZfkstc(Dzes&{7AqFN}b+s|#r|-T~wjXwXFl15#zQ2g|mw#^a zHuk|5<|7f;q#8q3&-{I! zaZp@xlngn$PaV9AV(7{s3ES=ctxDQ8Wm<1S7MAGp) zCvG*iP*AXGDPq2e80)w+UOnaX@3l|Z;MBF8V?O50_@z!IX)#dQ7 zG3qAYZSL)u&90nkG}S+6#d%+F=wH84Y@?|IqY1_+{;PzVualM=gLYBA=%2+zk}}M8 zy0S7ZMrq*D{l0ynJ&V8u7z5A3Svm0x2M(1Jg5jX|Dbm6-qw8h=eeF^)WN6X(Z@L?p zEPZ_ubt^HD-&jApsoO@%Rco%l<1~rrewzc?`WCtd0Wq%H>HXXH(67Wx-)md|f%2 z7dd|{wj?*@G0bbFDn$)16AdfC(16WMJDf%HI0K3mErBVk?E3Yp=TnP!)~HY+lnKLc->92#ScvLVl>LYzKhjOy-+|8vO7tthb*lW(GL0U*8jKx*u_#sYxY zts5A_LM9W8g*(DGl4tR-YDswo4qxLb!yr za^FVj9~|(+qNNbP!%70~mmTa-O{111zL)oyQ29AJ`TEAkmh#V&`ZLW&Y1Csi zqU33e$*BX6=p#igz>^=N_Cd#Dw|4Ydmh!6())G4|zEM%R)SIW$hyQ&i|5I3(`0i#y z0RT14r(w4a=ydJsOs9Vvi!r&>9Vnd7E3Y(GJvcwq4V&yP)t{B*`6hn)*IV)Hpu@mv zFR50b_tMA!RQ^r~RRJ>O;C3;Z_7miJj%<@f5Y1&v5JRADt$%dN`wxPRIXoYJgX2ep z$wnEm&u3xKeu0`zYK?;g(k@~ru)P$5%v5S)5KCe(Yt3*^KJq6R^83>unYwnniHAnrOxuur~Gl{z?D%I#-br*^s$h5vs2i&nbVAo&{HAhIp=m;9rCs7+J?U%*p@t zhX2oHI)sK0SRAJJf50ALBqgu_-us#21JwM^a18c4l1^Ung4|t!*sHkVA-fFe{O>!i zox8+<-M=@_nUXS8WC-StBfvCqixMN6$+!+no&kJnRN0d|`Hxe>EQ3rl*o$MBkkO*= zOe%#qe=I_?M2wb^vI{A}f<3B}^NI6E{zh#6DOJoAP-x0QD2vW*>_GS&3nixxn0okI zo<;5uR+Th<`Sx5vDU6umL$=?u--Ll=$;H`jHHi=o(q4?UNrH%g}- zpTA!+KX}Os|9cVb%$jESF55O*h5gg!CNNfbJZG6JTbDFlm||23Nvuq#09um8(`FUG zruqp*sv-#LgAccP|9iZel}V>sn5!&ah5mL^o415RzMg8lTS?6FIjt2^-XARVt4R8J zv3dxncP*g$H0q*oNOuk?GsTGwgjK<2f-Tdq=j+L82K?^qsg~ZDlST)Hjv3;qd)8f$ zjTZOH8oCitZA!UqU^eB)zX*~4;XPrwN!ytTBzJ(1;&1xKI*fJ+xI&+kuxN>$Z=a9Z zasOS0V%6aUe3BdBWPn<;of&cR3}1mmW5Nf)mgP<9{;j6|_`>W53S)Sx#7w5I>OA5gr;X1I zZIWbdH2E#v{=BrSl+LLN8L`7L8hFZn%vor3;B?55F;fZp7q)*5SnXi@EZciiq35^n-p2k7QAFlx2iYf)YPJWKgCJOZ|>LP5wP(QF@Zl)XJ|k_m85hl7KG|Fg3R!}HfLZArWK9vD_NR4n2n@QK~z9DBKQU@I8Rn?Hfh`2H+w)@&?s=GlD&P@pI$yrQM9&SeuNr=SeB`a;O?OA&^wxrP zyz+^dQDn9^)0wEy=#L4Cm;u<~!AF<_xZZj}|MOPie=wl?Ty~DRfwAjO@FaM!NTULy zHlM5i2=KYK=OXckGfYf(g5SgbC*uBZ!J~l3#Cx75uLxCp44AtE&|dC7%RKnv$1wzc z1#?|DnCm|TctNc~9GcHBKaPU`ZrSRO1df=O4r1b4w81q_<9*5pDDIH5cc;Ip6>FqgXPb9Do#*%uKI+JAXHV|F|Fc z3d(luRzhs*?|Va=R{~z^YSxF~sFX;m;-TRhBi+3xNp0Xp>HWq}N3!Rq;4-U#5Iu6+ zDC@)KJlcAgJfdp~?6s;821Ky#5A5{(i=sqWfFSH4Z*ykeviW+87tlE@`m$BOe+4jT zDa>R?pd$w$9Y3db;A`0(iljqask?qc@GtkY0qK3kVFGSfc7&bg{uAJ*kC1{?_wgJL zT?b*0C|AJ_0wdK<`1J%|Dlxn6PziTx43L(^&MB@n-Jjtbo2Y>^0(@`w01)rEq^&h3 z4m1&I=tC*9KO)@l*p-ndKQ6Uj8G%T60XSS$h_(NY^0y3_CPR_fgJVOS%3II>knH`u z&HG~`l6tw-RprM$%%x8^=`QUYv-Ij}MtUNGdDxXNm)Xzn53n7Da9CvXKcnCe1_)x$d3o8}CA6n>RT(R1%Y?5p`I;DB6 zN9sjs$TgSyC_kAcf4`%1+!LyzIR|82v8A*Z*fo~PQ`ef5T4YC<*TS4C6Umv&Hq&6h zUK2sf#mOIqSe7G1?S1rKWL1d;SDp%8t1Av=OP_e;f2PPNtMR1GXr;q)#x$U^)i9$w z17PXdJ#CYxi(do%@gorCy!$ZV(r#f@p(Fn=%v^vb&dU<9fPVmdq;t+t_I(dt%A#!K zd9m4fjGr$Zn|yrRsQA%&*V9Wn1No;)_nv=yWFUR)+SncWyUrg^-O0}@z4h{K8DZ=i zcK##=mC7jwplmI#`pg6EccFyF7 zgmOe9s4ZenJpDOzt_u!7TR8uoS9+=^>!pOSfH5H#8iHzIBi&*q*44n)#>08iR{K^r zqKorOcH)*VKN&v!^CtxRzf*pLNTWG%owoIieQgn{xBTezE&}7zIyxFp zK0R#VlQdH+j-ZV;-U#q%esLx>Zl*26+2 z?07SKh{5Z@RR>81AIva;RJk?!U3|;FFKyxY10T}kT3Ub+CW76t?vK;dR4H;sKBb_v z5NWHWv;qBnrYPFV!*y{;qK=`#j5(YW_RYoy2)K0t)sJE2Az@nYLVDGv{j0@C!86g( z*IeD;uqXCar|xS-);#P}dqJnRF-eS6|CYyJqEQ^#NxK9Yf{t3UT*GpXp05BM-s*-T z0Gv(3YT}_f)3TEczx=;A*`>?t;0{5d`yQEg7~yqq9i%k zY{^_s@k-028KX;5QsgS=3AoTLEr#*@26Bn#a8u#=Z?c+b`Sg;DLp3YGpS_axd0!v*`8n%+9? zD@JqSUVKn;^C`jH&X_ysxA{U?{1ZxKej&revw;@6YaU~e9>4ckL2hXT>9Vv8Me*&3 zDVKsSprQ=1vl1>@0n8qAwcWigz=>6kR)FH&V6(;0u5muNnp`$UGZ+!*F8s6ZDE00aHFT4O@!2LQ4EgImdb4f8Mx%jstQmvG^+t*IjOBSojLNztR*E z_5(tW?FF2}5PatYirM6p(+m$>+-?lA56y0G27Wsw=Ud_V_>^r)ikMG_3#I`6poawD z$$UJHTlv6~yL0T*J$AidQ*7ty1|k?q$pcvmG0y;$E|ordMPR{m^+KDdLC0m}TFzm* zBA#@~`2quL`Zi#=2friF}BF(>_yZI%* z#{5a)v$CYg$KMfNJ&{B4op2q6MwMy%95M4doW_Xz0kaZbwp5)%A6(}Y8*^nZwBU9H zO2Y#(&742+PW5KeJ7iVHE;6L`sV+aVK732MDm|XCldDdNP~xVq5*N(xzr9yddBhA( z|4h?bkySc~Z|Gpbw%rn!Kzk?n`*0F7W4@kNvA6#S9Vum|$6a1K`BA^A)9Do{Km%5b z@XrCAkgeH<8;?ttisCECOp!p@m32?B(<1o4g(#(POD&P?ows8Dq+e;Z zS~Tr?k@|O+n1)X(qd-t@JMh|#30bDXUP-v7X*IU#sY0fsb=)R?xN2$Q66gDFoHptioUv2ZMy zv+2k8mCnFX^(A$%PM%TJR+2hOu&Jb;(1Q|lnxVpYYdsDE)nJ^1vdXAtU+i!IT$Y%MpVMKr8+YSU}zJRX}-_in|q)&pc zZ#3e%5XX!HQNN~Ni(1E~1FA`$S~(lh@XNC_Cj52O*9)p&f+uEakGJMuSVojHBK^VL`UTvR{=te zl6M)h8$KFrr5drZp0D`{W2#v(@dlYZoi`KZ#*Wydm#3y#|z@qLL9!VVK zyL#;j2r1`y9~=B9hyVL#{fsDO!Wz7tAUouQ+3C~ytZA5qM)6P-?`AUnr(O}2s)He^ z1tmAeY7cG_Uy(!57bloGNb{1Sm`uP4w%W6mQluT~p+`QmFSB8juP40poh!H-NFZ&? zkCozlv>$ULttFr_Nw(z@sNwGHF?GE)(eSc6B`~h2a7RF~KZhWaP-2D}AQ?s*j97tg z!fPpfN1i|vC66&d=E%k`n+5rt70xb>CJDrHDa`k1Mw@gmFW4(3x=Fe1as2{Su_X3IU^OuY! zhl-jKie<1nU6Zr1hOw#5k0FsWlFeXmX1-bSHiJyj3dcO}i2$+~yOb^y_m zLmju@wgx39g5z*2%oYp2_On3wRgwLCn%3tT>XsW8r>~QQ5owlZy!gS%5D_&h9za-= z?Vh|eC3b6fik^zl5Iul8xllfzMsk1mojkpFo7-zD%8<%NDTyJoc~9bAGw+rRe%{;F;lLL25>8re zWoGB8Z_;SOn>W?m*drT3Q|zMLL4l1t2FL9a>ZA zKj^`;6(fGv_F^QGP4A)x4Y+Jo2yQwNBY1Q4xW^0XbH++F@N_OL*6Zvv_Rq!FrNQRE zV*#x1zusC|aJaGcg0vrM;_TmR;(y<#=9gHFd0G_)>$O+*IxKh83>90#$PO1r+P^v% z9JqEk1jA3eRut$G4T^Mb^lqY7a$E%!LdQ-!j&!%=>FNyqoCPPQKRlRcy8AxdSOHCR0AR`pE$;ft`OK;J`aMA%PO zdApO!5@%D)>Rb2T9fVl%H?P~o-Mn7{b1<1F7w*kIF2};CqGr(aAl-sKBk5x`= zD^yWP69}7gbnBD8A=ItVa+IAOFp#X!X5a6890&D9E2!1S&Y#-~^+dIOv}K$gI@6b0 zWbnTVB58RvB6jymx+#MP%|h9E7UH|;Ih1gfVBVomvhmkkx8B|x1($`qL=u_jFqmzc zzspU&0Gwp5-4Rh?>!7420F)z5$H)x?)Pc0q{Mseb32n6Ov?3IJQKyduJb+<1U&A#e zcpF+1gVqYbVNuAd`8~8X(jbVM=Ly1-v!bKKJYB+Nk{*CL=V1lgUi&AdEVgmhJSSo<)Pu&465MYhc#^lUwE_!QCicIQj2q6yhP6m#5L>7W)7^B{iX zv5AZx<|jhuC?@2HWU*P0p1c}GbA$tnj?o<=e#p%e(65N9=SmWo?Kt{~i;S;UdS7-39Nya&KE&aa$-s3c zN)bFyy=it?7VkB_jSws2c|VDKLsu*@T-k3MrI-#_kYenO2+ACL0)NZ1QBK#A&BKD|`cM+XW$TV|8Ok1kJpwxOG6&AGNYNA7~VqgxW`Easzwac1zl{xf6;(qsG*|Qb z0vFK=U%3W^-q=tIPOS$N4eT`A04{L1`Sv&4K9T9foKZ73z8+ug0S+N_h#+xGspIOC zAyA*PBHNw-|JaAp3Yi?@S1s|{>=1DkwQ)_$INGx%ey@b_0`NN&7dN0bjLw!;+}-H% z^5W_AzRnfoR{3#}I?@td68SO@8R}jaU7i!|r+kL5%?GYmlQgxq_k-oR_3_7E=c2p9 zq)(}=;JglPz;Qbu88e~ z12T|gbXQ(-izTYDZUv4}8MFjxv#e1I8SB(!-iIO?PtPNV5y4jG_C+-Dt3+7&E!;}O zu#e7EE;Et_A1eSHbmfXj2`j5b(T7ONe z)#oU57vE^1qdTfY!beKKwN~!Y_jG{BN5Pu&T(+HCqNH5Q$$|H?gJ)dJzW-nkN{J*> z>7Z4v*buvynlSNr^{S?`m>Rcyc1o1!c}lUnv!erkCOw@W|N3M<^J1quz%JJ>-MV@Em~tqALj zE{!-B#M>&al-7)i8>QC+w``{7x_+8EMC>E!+!N#I9*AcmG2+C*3b1ftOIHO$B*o1l zPbV&}7ljs$@u%ceB465lV`X>Z-$Tu0;Yuk%G<;rY(fVO9__q8$eA6@k^Vu0cgCpD# z2S#jMGa#}&>Ns1M19q&zO6uvruzq~=BeN|;@q@)P;<)j%u}@uD!gR=Vfi&4L`8&WPQe)#~?zo_i zvW5?L?=CQ$o=lrzd%U5uCV56aPx(eDR0_B2;<5?FFe((riL=Z#K?MtXklOJvnE#}uasBV|SL zeMRO=uvyP}Xx|ITxir;8*y3#ZydpzeX7tjM(W3hHXkWg@G`!f7G(%f}f0~S~fiV5- ztq-`GCl68CBCts4tr*I%`W9$Bx|&yU`!`zXgN`4(0<@&qMZz~x&iSI?w67Q4Ae$xj zSOjz4F(?gCZn$riP8jF_RIh^lfY2E!Et#@sU@grGO;p2DS@#yyORTCIhy>Gbvv_Ia zE!Bh;CJ1w0=todQafH8MYos5o4D;qp3&HPw{6&ylkJM$9e-=XpsAavq85xqNabwQH zPx!C*gNpKzwQCfev z&20!QI}95_lPt$shr-N_I`>>MyywSw)g_Yqis+H$1C-tdWRKR>UhLf$k#-ew%W)Ar zB5WT@-driYvZX`zD3ip7xv6C)@H2a#fpQ*~-O%N`mF>L_ZA z3%10DcSRl8rEX@vvuP5YLl$>xr5=1*ns4$m|CAlhmIwnWMPz7Y1M?}Hyl~c-Z`Pzt z+Tyt308l>_6|?e4po4=zE6};vye?2eot;(zS?z$;Op1|`*kniKaY?8d0vd%0d{asS zR5rn?hs}|_QX8}Tf;o&-*Iz2?hnEXS?JZVbKk_PNu~1$eN%6t)s)zolAak!VnSmU? zpfiSme@^xmSc@y>9CM6woaZ@|HgBQ~ z$h0{-J=!(8cMCSSu23*`C_ZuS5)oT`MBsmMN?~ThxXE{0mctz1@p7nUb zP}?A=4yFBh4}^_?q_XS-7_-v86Fee`DMK&?whp6HoKQOs3=NGG5~emB*?;U`Wd?_| z*Soj2|3W7IXFbyqnWf@!^8>6V07HQcoFGrF!2Oe<)P+0ur>BHDI@rkb=|uj4XF#7S zLJvyOGh)X(xLl&WiU{rm3G2joNtpGWJY~X`rB=|&B$xM=*dKuHQk%72yMY4)Ov*T< zcekyIGHf!-!Lbnz!Y@a|ULOZ&?3qN&vLfoVR7rxqqVPa~p0Y&Tv%Z(KVjgzs0BS-F z-t{{FuHS4#UdB}Trj~o-q$U+}=(NiEu>3wqxZ0qWLJpwHk`DzRvx^{9Qg7tF+~y>_ zO_x~$c|YMwUo7CGz7R2Sz}ksP6Ou4?^-GdG7?HQHu4n)y$E{80w_5sbZ-^3?!K06r zi@!!@KsSNQ7dzpD39t4Uu0B%x3#b`nawjk@8tB1!{k_>yG>uUn6O)6n)Do!~8d0~t zcdZBg`B0M;0ujjDU~b3V1RF*uC$g0ZL8caL(T;siY zSJSXMZi7v=13%>M@|ap!Y`*8rv#b*cs?5Sl|#G8Y7c#*~{GzEI;&@5g~2U}V3> zy=N1X&#M_W{R5QYVt%px09WR{0DCafS|=Qkin=QxToW!;@{&?;v6WapUc|2?`PGdE zxM)i(HFukrIUE1@NO{*frul@(w5v|qTOJ-{knbLmG%N-|ZIBOHGRiy7ilk1Zcc=^?)~%8(kXXO|~+f;0&KQ0dNH= zzWEUb%ob3!h@qno@zpXu6s#Q{-U8cKg{jze(m7xoSWbb-A4~vN!{r+Uaw)>}&+UyF z2wcF$a2UMhItzRupOAyon-eHBW}`O7)NWcV5vf+EK0Y{mma~SHnk@@+TkLQJ&04*v z#SeQ_{WlMpS-9Nn+=}}+*=zuOaCpTGU_Ftg0g({? zdG2-%jrBVi>N=3a#0)FigpPWttg$|P=SXoyd|_kOdWBxuV;9gu|5NJIZux3PG$HUBi$4K$4Is$e(rULsj#X<6%{> zmvWwD=;+Zmppkt;b_`Hwc2{-Y?h})K*nuLx8aYrluUvYkYZ12;znmJWbl|N9=k#RJ5y%-p_zDOr`sh~}_^bj}A z31{A{!DHc))1`rq7GOr9r_acAc~Au>TM5xgT~*_eP%O*mfi5m$^Hh2qa0YB?-4rPl z?u3mj%m?F_;RL?io?L;fH6Rm0cJ$}uGgA<-q7wPSKmZkuu=7PY%}tDoTaoS@Y-!*y zU2l^mS^V*HKlds|8S!YyOnou4zv!91RO}q+ObxMW4L5R`zERqt_Ly}GXar^(j$zzp zh*TeIe-_-}t`Oeao*)Id;dvxvG@Kkz&<`PZU4_iF5@@bJI$+FH^0VYJ(f~rpzpj7( zEd!jRV#ojZV}fkL*FYaWZWAxEaegsow~fsB4WpgI1+NzO7hFpjPe=HEby9K_J!C1(f!4 zm~fTsfCe^YCjn02^0#ZnKO^`902p5lc4PBNC(o@m{5bWsa7XjF!CD=1wkgmMSVU5P zeXIG2e=d2m@sxpegqqH!q}PUD(cx#u)pNB?*df4MN1kH|e6oF3NAL6t%cvoS@|CaM zi2-`W66AH#E6F;qkFuZP@iA@B0Z;)(O_mlB0KmDQeL_=irvh7?1vx2lcMN39&&F~u z1vJ!pZI!3D^_$OhNn*#kR3J+{wb7$DwbW|Ho1pI2Fa#}x1$;LPHS6{(z4hn$-y%gw ze?oN>V6#$ z^Vd;2b=V941*8E)`W=1CfNBTkz<`<(t3+k4;ohf+L|PuQ>X@{uc0BP?T`5!yJRIM| z-AA_#Ck^Wc(v=JnVq_W6(WAC@0Usn0(a^`kt{c}ppHUrV`jCUtOb+U`)!pi&s9S0XA8?Hn6pylZroB+u(jX+f8OR9jJs z1QmwnrQznH2}YiesH6)ju;a9>#Znl9mcbZFK6Vc6sVyc=!Voy;eaYTiHdMaTyp?=L zBrU}8dfsc$CCHk;fs8H>m@RTyn$hvRE=g&sJfaVouZ=#}Yp9^(oToSi-AyKJW`ZCx z(3`mDikBrWhgLQUVNacogO%j?)X>Cf$o}S*uCi6To9}!WwQCD8bZDHp`kOo>bnLFP zXkW|GO+QGEIaXC*jcBag$+U0&7j|l=KHqPWHZlG4&+JWxhYkT;Z!jcaOqS@&5OVb3 z1>}{q5Jz@AhSSH}lG~>LvTBkU72Qxjxz5-YDSGLYcUt_MKkB2~j5UiT5+g21A0lSWre$4u#L%W2xzYojwYj$+SjJ|qnu!V2cyzhaUGu3iPk`+ey8 zAgko2A6ajVy#tma9X|SYk{@X7#ypL1MNjk2Wb~S-= zMk-8LhPS1~XW{|xFh<#p{1!0Egl_gqr5nbDo27&Cro@ z=nql6z+KEU3Zt~aabcA(c4HlE@vT{^pV+nDW-P@WcAsLdV=3~TF=vdL7mZxOV6DS* zDv-}vyM!=@RZs`OIm_w@>A}?D=o1Dn-`b`%RQ*jaZ8-~$fw%vDO!4*|5wSB=gGECQT;HVy z;$dv+YX0w&qx^3Q*Y4Ygk19VM?Xo1uEw|2s%^(J3KfdB3Q~?WFu7J>!$xzVz+V+)I zm15-r8YR2*%H%}FmSfskHazzQEhm->mVDAw-FT$ut#g52$9jpnjJcw-)DMW%0*WpH zLF6_s-e*C4OB7G$=guZ-Z&fn6Nxv>02k11s4K2%`#vv_=uq<6myBX4I(|bM`EZ-kPQhlxb zmbr{1gETuPh-mRsaosj&E#NMQ1SWoZ*7Vk3Yq?czYx(f$PzY4i%oj2|F5>NJ3rqm} z%!4|J|A+Hik{)~&inVlVkypg*GJS%xW0B(Ue}9cKDIKj$yEUblIDPL;X-=p zTE0>lKJ`w!F?!4C0N5|DGT;BO7gxtBO ztt<J?WNz-qzst? zrU*TzSShY}!zI2s#r3{}h!5w^_u{1|scq~G2O42^!qXEP)Bj>TwWOh)`PYAk`YAy} z%q=mG#qjV!IXJ{s628nGPxI(SW<%z{L-j7TNeAlfx`m>oyqOOXDTTfK9VWZuARq#|`GGhjZO;;QrUH|Sk0t>7CfmGe9oI}?j zf{>sx221fulO$_#lTS5OFHwO81K^VZAbz?kA#sE>1L zR@T;8Pe!KOb<~O5MtI?S3O-70oB_q*)@?6p_2+*6FD=(V&0h|jZHnFnA#ZJ!zNxZI z(bZFVaLfR&GF;IGtko2F<^?R*Tc~u$mg5{IPc=EwkU^GXG@Zw zbN9r{2DYoz?Sg-y6QEqc0#8vZkNEjyrkCnkayE5_X8ZASC)$@O^0f>R0-{h^swvya zA-A@~XEp$vjO#ur7DV2GnIi0tz)}0=hcGBpY6;j1hLM77yji=KNKLAvVuaW&zF9@k z?UH43PWu;XqG-BLt_g0ySqeQRo$pP_ZdX@)pPb#Bx+4ronRke$#thx$t(E(+x0%t9 zK9|Ok=peY8e?R_nRM^s7Nx}dL6`Ujt^8XUnOYr-|yFl*^Kie z62*2ZH!6ONOkM)Jit3xU2Z{#0Bl6^*8aCOJar1nETbqer(bff9c_MWUsG1-WtxY>3 ziHBqqCn``wCbvsrB3%P$oSQ)m4@>sK&t6*It^k&nx+UIz;LHr^>} zoqhz8l6cfJK{%Q?n3ZdURdl!UE;V7dwXIswPx}o2V8bWNn1Tdti(JvJqP_(Ak8)cI zaA9Ui!llXa{XCf9)Z0sY)@Uj)?YG)r=>b|E>*{EI-(fwow1hHxjprjOg@aHxegp z10mgOx)_2N&)1)AMWh%G(*kx5HTwr$Bby*nEH?6c!`@pxG|AiPZ&Sk#oUt(0$GhA+ zp&aYl(@FlR%Gr!BtSQ6$Ow)X^$Dv2wW+jIW?YOQ_cqO?!1V|v}3L%CE?X#v5} zL^+C0kn2#9E|UHe{fx4<4@0DhN^V=V?i)_jhfYhYxDzs@FJ>v4B6)T-m$YVY=sgO5%*2QRFzeF59A zlGe>96EmgJU~!IJm2Nk9GpVlh)fat07z z+&s}>99WczF&VUzt(8iBwps;}UGqv4uixLc-#dSUyL|8ZyTrZT;ah`W7z^Fmk+G6B z^AdbiKh&;V+3p{Q`M%vhuRO*R`{=qoEF;EkQLk(xxiKG${H59#;pyJTUVIOCA(^Lk zzFk;soG@8)RX1AT&lOGIUcs)K4 zpPf(qA`<8P2LI*FFZ|Q3Rh@{E1c}_yIWXaR^V#<(w&zX7R@SMxdjmWm2UsX9NZoCc z&txj?X$qbY8}frtS#J(xNxg#!jvcRGFsjTu)@O&Wkz$+%_83G!QO7kU(Ydt<*vrjD zssm0eY)h3jfRYskFh#zmfltV?BG15(&Z?CD?yXYfIQ1WmI#M_a%MU1u{7$V$k#wYR z=k{SGW7px@Mm2>)X;lG1WXDH}shVk;@~plS4!Ae1$Lc|fB%nce6<`X0qFiN)V?3L8 zyR8U;R-|pf%e--o)ZSAZHXd+PnHxHHu`0ZcqHQBd(ew7p)Sejdm8p&^Ky?G#sVw5w zI?|lOo3|Fq!Z2Jc{6riVD)z10Q>mt&U56^xbb)lf_q>G=0}2G6OdR_im3{U%xHs0( zR%_3JxspPw_FG$~U}A&nH8T1?@F5Y!0FqL#E!j8@^qs z5VBX@HYLOX@@Uk&4~)6<6LvIHk85V@XST|2%f1!-~=cG&A4a>1S$2z zuS%WMBo+g{S1M}H&UI`g2_1_^-qu@8U1X+@T{7J_B?>9tf1N5TSY}-lY_0&GocsCX z$@`mdv>D5INh2?GCQeno3nQD;&qIv^j%i%MO%iC_pJ%U~WV6KEQ|Z4^&mR2piwNDA z0ve{X-Yb$WSRSY-0#gx`12L*%5gQ0&p!Ts;YxOFV?D12746ryZ!n zNG*?EFt8lK`NiI8QNhY(P!o3=kQSn@0MlcZNw)*ctB#;qldrc`JU zXz0iNV3LxpH$N}2VLeXE$HKlR2uQ9{mog`e8s2+CyIPwmh{gafzgPS4o^GfNP1;IK`NUAE`3x4 znIsgbln{yAqq`C0MCu7>3&^Q9ks1kkt+)|P5%1%k#4g2&b6;Lv9u!OC{vyUJj=pLJ z{0aR#^yotQ(Gbr)Y@5yDxw{7FR~m1j*^+UzVf){JIDr?j1QSI)iPsXPRYHR&lUXNRW6}cq9f_p55EITFq?W&e|z5Hr^d^*hCT-jm^mvJ zM+x!IdU)yW)Z7sr&(l{~7Zs(BX@hCUSA<{D7VqwfkQGjUkPiu>Jf@)LG)SB3=Ly;dpCK{@2`r{O$64RW&mZ}Xt2yy$ec)TgigtR z0Ewsz39S-;qoG5~YiuJvg3+)qH%@i0xF9i%xqI(ZutOH!kl=&?W0uD!mABuOXkMDL zY=Xv|!A7#WHBoK+(70usC`&2m!My6xQ#GN|%F~G#kio&9Is7DRBv63k+2B-|k+e}~ z{IH&R;`tI(vgxhxvJD&wthWt$#C1Hd5&8zPtU&X!Ua$MKP!!8`n~?qG9BT7t;E>Ob zC$T)7eih`v)8avp=c^g)AHhJtKuYnD+s!(63t05$F0RDg_{vmjX2yGNFah- zYl>sJ`|e==XIH2S8!H9u{uGg2VHI~XqGi#2wcqsVa0ZWI)swfSKA;N2o8p$px+6{AJFKj67En;dg);S)molBXc&)l5#6S`JPLOf4FHb}}5JaQSBXj^Sn$I9=PL ziF5FI6?{GJE*UbqM0nU^6p{Br<@CY5XPO`sUI9fBP5=O@^Gi-4*k?hoVxeu_SGl95 zx&Sw!q0wrXvZ%@paipa>k|kNxxGAxQh1~YB4d^HdLdU53&xaw!4>ZEy1h3Tx>*1^S zF8=$^we2)0BLteyKEJya%)M3IsA!D6OV^e;zM8Mz{gH@z4RC`U7hEXbqu2B>M0Y$1 zJn59q)@V6bD`u=gf}j~etmMzO<$#*np<+N1w#Ig*@@Ze(GzhdQswyIT$$BlXJ;iAY zWGaYf+E$%j*L?X?E&vI|BxY}lqm&Ii4Q^{rd(%QG)2a9HnYL)f*>%+yE)|(6lXzjL zcU8Ga6OqD%^!F~i4*|y0B&aCZ#~Bbca8>)FvWz;37)aN8+AJ!6>K_m%630;Jp*=H3t+%d^DojD+2Sq%_Z(x zH^|UaH}aZ5GupB}7q3V1cm@^)1AaHEnzMFU3^{qbeh@#NUpt8ymHGwdQ!E=9GF&ws zT68(MY(8gP0ZxOZYZEkMW{YkxwU;k~i=4@ZAoGCg324+QAYP)yO!=U;M-4>%C3aj$qx1z3i$< zztcmY{u!=h^&OVluRG=^$Pvyl#hKEttSB392|@)8rXsE=j3F6cqRG*RgE@ zZEf_gW3bwu>&i#zIUj~vP;m$d_)Y>xp4OmS+?Z;t(j>^^{J2%IdwSm^XG0QY;SjXx z38_Rwe+3!2;A6>Ip$EWVx>ym*c&r!(tCkiI{w@Em!^ z8-5_C5Hv3yS!&1XHso7;KjeFd_1d>64U;LthIh}nr!Q5lKWs^Wz%Lg6Rusw$?Rb7A zE-bd!kV6joG|*mf&+Kow$a^HjNOdl|;n7;LX$&jGZ>jKsziWzaGmXOr4nPPEUFl3^t}ZEl8pu{Ay(85OzK4XRM7O% zu(5Idq+Q?3^8DpDw_Z-qIA#{F*Oa(-Z0g2DAmTF0Yj-h$ByC!oto_86>xA6sN!l!^ z^&absD5;hk>jO6*zgUPljErh)vOZf#p^L~OIxaw!cDue!5@_UV2Iirpw`d+fZReBc z^64ErX>(jWri!TQhS&qox^&Q9xWl!T?ze0i*dX!t43?_e*u0FhwsGLM)3Uk%Bi_#1 zX)i|{gdZ=~-nW8hnvXm+c=@%Hi@SBBN9Lt$aVL~dH``v*#bm6YzNvU>Q_CkFbX5;1 zO`H!|0-E-()AV}^V>P&YDq+@B43p^x+BxBxsx z*GV}k)fNMWa;nZ$;112q(=dJhFj9+{{@UV=OP&f;s*8Y;xU~S$NXC66f*WJ#ML(bC zG)C}J3QA1wN-PEtz9Uvt5)Tq0y84L2g1~#qi;^~3wNyU@FHv#E-^<&UImrd-yOkiC4~Jo;jhx zK7O7(+BQH)4Rcx;Op>~j;uW`~80{~G(=-is_=gyVbpD_G_hb-#nTII8w ztaK&j_gSq*H7OCkrsey*nc-KR4P?Ecq&oa=&{pV0Tj#XWW8y*gvZTB5MB77wXcO<< zbuW1~EvDCW)Y*DCLL@vxs#EVAQfCo4W)Qp5xk2#&{`p2RJ51}d@1 zh2MDT?vyp?kl(Q5JY^#S>fKjBz&b^V!sNqwjG=JH<0+y!h83v|Z6%hUeEs#2bmk{mf5w&Ko+VOYPhBpb zPW5`zz2sSE)4Kg*(Ixkyn5)o=AI`C};wM+dWB4w*9#2P4yUjRq8RQ$3&YXM-*dF*B z7aR_(eIagI>J1#yQK%r_mYDMKlCO&jOer_?;@CVJQR+<6`F^j+GJDefl)}9#g%ErH zLS;C=^y7xpPx#P$XP!9a_S#nIki%m|0qw!{@-@TWEA$Hj(YC~f=`-p1t1OD*>KMFr zqsK3^ljk(MJ&d!*#Q}rh) zrq?Op4)^a}>_nt!562~c(KBkezC?Wk|33M4G81<%O*A?Af~z1$C3TjZ|NNjZ#caxc z(#0pKQ~)9j3V$>?s$P2VREU|@zgV$Z*MKVEV)v~?h1KTrhhGS>uZmfp_8`x3J(Qm3 z>0t6!ew@I0D4}mQkj%r6hVvPRS)}sZ0rx9Qn$4u)3cIw4XS%tmRR?!5aS}!Jq@@={ zo7PV~Sn}F{f@POwlY3fP0RthX7oRb1e`*?f!$zKJ*?~p=46Tik1zRg$pE`{gJj04N z+i#L0eZYcI-Cs|4pha3;HE`$%;1$w%U+KU0QogVzAb1Np=BE$dHtm0ur3y5om&R0( zyKFwWVj>fp<#eD3roW&`+BNQGRODKcAjfGx6f|*-iZP^tr^;^Ki+3{_(2}jXrykhh z+3@{YS%iGe{d78q7gB~d5HHQml1ErUC-prly`kNY^p8ohDY?? z;VS2y>g3AWzUCZg&WE&ip6}`dn%zBx`;VkBRnosI%vJxZI&&soALDPgel*>y_Dfyv zhEi9{h<2^ABuYa2C6N|yv8=vL(E@rbg%QAS?Y9tJ4;~t4zZ_U(RHDjZCtz*>5QrN( zC2TP184_}LBx??NwE8Km#23skD15E<-pVZF875mP#YyKmYUOo4n^k?vfoz6?RNU=_ zpopigbRHoLeJ!p#{iO;fLx~86A3Z-?-=Mc)nNaPz2D$YY2WJOSBp;IJR^sY< zaJ^TO0EMuhz==XC5tPhh7<8 z>XYC9(Q{?z^SyVA#D=&%#_)aJCmy0=tNpfMoLNU+x%V$KUh@WvAM&SUYcxj?9Ty7hs!zvP!Vf6KFYzO$nWddAbn1+HuKLR-^}Q`_s0 zH=H-HzV-iH232Xi+J>$91cg3D1M^AJr@E} zrL=zN#OTs}WzWpZTxk{6Ho;En_!+B07htirudscBfGaj6l4^f;SYuREPZKMxLaoXP=|ITEibpkjt zC3UN|fk9o@Zn@A*u)W-Xm#tX5`^Neyk+<_*k;dud>h@r90S}%)DX#*xp(dH)%4pAv zhXQT(w=0KARV^sMgn@5-c!IIX%h+-5C%u~fM3}YthZ-msN(A)dMB7#2IL(fi$0urB zODmz8wl|NN8q7SHX6>ubTATpB8h z;W9+kBh7sVXnuPkNgc$z7HJK(Ds4Vse%|0HBRw%AR%{NAc^A-V-Xqk@0;;>w>n@ob z!|A=i4|h@FPD9-P=+KSTKixT9Qp5;CrSatZp0;O>vH=L2H&_D-E5;JtNF?@(cvrHB ziPw20j(J7NG$Ui`Nepimn=g_RoA7nf11s~eb=8dK|M$2n9LH^#&D& z^q!kI86($SIE`u6!f!|ecE;sf**sZdpqdUOHf+8bvM+a4$#i4G zxp#}SAMclQ-euh5wVCP)PFu0e_kiJa|T0$m`)#~a-g zG@-@JjRgCr0dOxC-@_3_PHk~(xcH4wHH+id!GwfH0Y@-P<}eUOX+4}EPixu70FDkC zCP3OyP`(T(jL|f8qWE2$x0B?i=T(*v?fCJNTL8ftH5Q`@B@C7TRB^rw!5kU0N>Dyn zMT17(W5V^ifWi+^yL8awFePdk^t(&tUw_yyNHax_Dqg}WZc*3Pro~1E3Pk0C7o74d z=_H8)$*(E6E45-5S8uVizA1Ee^w~oined|1ss{*W{xl!RQv$9iCGRcA2lL^IjTd)_ zcMur-GPCi%1>S%u+reg|zm)BF<~6s!y#T1~bf5(MS^)+$7qa8KCO%pzxP%Vo^%yw; zNr#&nomWiHzO1WE#1BYcIXWh=Ab_|P`^28bgMq09p%7bauYhu}u~cmVemk0m=PPIc zG00m59!Ee^ZNhryMY=Q~E&53|)}09aimrNsJH7yC!~7*M4;T<7l(K=V-p1=9;%$4+ zIMoA9W+aky1uo6yK_h5E=n}jV`VdJVrJbDk12|s_($P{eWkdq{Ix6=dJlG%1mg(kY z-_i_Y#p}wv9q)=VoC7ayp(L>6gQNgznO(7;+_;&wctGlZn7A(jw){hsj?s_6p63ls zd^c9iS4(QX#i-rZRG_MBlh+o`f5|zPxG6ScstY42E>R;iw@S(V{OQY-h5_;TYj_46 z7=~acEry~Lt^+(xE3yFNInZSlYsqHv)8|ksS(c=pFc&@njknu*;zXc_zJe3%T^2u_ z;a%bt^DFiH>lSECL7FXm6N;_GBpV<_U%xRnOqm}H9CfN(X986+)xtVB+5tr`S6aaT z3IJcE*Dx`efQvY<;>|O!PvlCTtZkt{6D0ib&Vtm*(;Ju_G?=^y6m2U^Spr*LJlUxR zXP_tzooxhuy@$NORscS;K3c#LPQPa+@zh;ymhG1KRjr&IiJZ$~He;xrrioEg&Wq+}5~hl)+bL8%6J|;Om* zfqx%q?OT9iyBQvY@85TLRhTcs;HGe|t$yDRvkX#l=bx|oPOMdV02bKu?;XU^t&egFbScbz^Py|!6?`c}lkA{HTX4kMlf zqNPRtF_5fXr}aC~o^SOXQy1>U*nxDdqZtH)S-f{AC{zS^k_VJG14v_q0Ts9*PWgn_9K&YwkwCeqt^a27muMPjeAJmiyBMYep{y zTRCpxqSuCdk9L7*s*7oS7t)5Cu;;)RBgq+Zc-htXf36BQQ-tBu(vX?@?mA4?KR}^o z(favia-mcLx>}iYOi0@@8jSkl79#7HnGQ`4s>`V2jaYo?)I)L_c2{Xd5yC}}-B!2( zv5q647sM{cdheAz9)L`1mOOs~IZ@Q9Gzje}%L4aH^!KQ=Cr4Yb`z&WH!OSvis5lw@ zsVnsHo!_?OLS8UlltuKG=S^bx@VvoIi_@?60{n=uAT~t^C>ha#7WYNpX_kG~3(bIx;IprXk;n4^`s$G5e5V)Ovb?Fs2$=*29`f9XM!uRE@S5i zlZ%^|E`x5u>zfu#D@%7#w&_QTt&tu*@*&EEoZVz>31sYhQSlU)!Ld7O&O`e7dk6-O zTtImi2!91;1#j;E*w+dGCMhVfOfyEi=7Fy(W2R4lqK6E!09$9agmhf+(GqK_U>}|t z=TWVj01JunnnrqhudK9n0^Y|~1!WT^lNbq=p#J3O0zZ%vdFHEckcI!?# zI0L(^;1etY$Iy|$8cIeTZHp~ewB(k_Y|;{qh7U(C&b@*pc9^*3$yb`7brNX%iNW&e zt=Y$-mk^6q1%c!SMzeJi(5f+QM=;Ys^lV*CLa5IN5y(`2q*(ZVn z3nIrjWnOlo&D*q68-#Rpugyv=!A`dwBMB>K^vX!Lu%)IcCP-uD1}v}nCD`QHN*3lt^en0{f{fwA*us&_$(s!*pEZV^A~{_ z1RFLaVhN>eQHl4yDc!#A1fE-2Cb}k$^-XgnOwm1{((3$hV z)0pOQt?x7GUxQzeM4?~JxE)G}f`(5Xg2c|>L8i)8eQ)Lv2+2v9-JYX~DFBvmxN8QO zwECZ6>hIUuas!QkJPVi@@s%p3V!fz~7g>y`+W^`Q^OhtzWylvTrk7BZ&ZY-ap^zbN zx&eO_MS2BKQ^rj|PsbW36$hd;)P>u7(100bd}3hb8%;mEe=dIJ2Rbs5G;BYBpDSGI zbO~$Q4I~d;gP`GmjAGKxCl_HBazRJsI*VA{1=^C1!DyZ)xPR>&^N2Z07|I4OKmPyw z;z0-@$cHb2=#CF`Y*q%=DY|W-8AF4(>jqAuFd$zOE(JPCb08hs;e8F-n9| z4w)jd92_B zCa|xxgH(&ZM0U`r2@Mi%M?gGeP;ukd0@oA`rcLC8I zFM=Z#M9Fe6U|e@^7AS~Os7f{=0z4o;HU^T1BIwG^O~v9I^HlP*LF#dnd42acUZTu9 zrgE@Uly~reoLcYX+m64!IWLf}hERKcrH6*yzHpg~!yrrtv8WxGIM6^=&j=u2>elS@ z1+^p&fzcMlkNX1EgdIv)T>*j~1}u!5bdNB(AXT}{&p!UW1|Zze*IEX{j&LEz zOlC(Bh7xFR$v69(;yG9P195dI&_09!44B)ytb}U3g5RtqF!00zw41L3gOTAMkA9T^ zu=>vLVxNNlc7*lpwHe~1>BJG7L@Db%q2YqOgKFNyrYFQnY=(y)78-1 z%n?&z3hELNYyq}~3l!9*IMbsU)|x=J4xJgJ(-=5wK<=yeG%CLWP&jBeRZd71NPzuq zY!-pF9T8hJV7C0L;Qx<({LimIT{&;b-!>C3h?VL0!U6O(QCMuHY^#fU|DHPhm;3%B zw;&+VJ7N5-z3{K=)&+1^2};-CKVS4e{;zpx^Y7mQlUArq^R4OP@2gnEEFnPI2`hKf zdoJPiC|UI$FF ziYUT>of8f;xRT}LzqeduP#Pm;YDx6wU!iDsLY6JF9$X)`>yN<9n^%qD9>xfrdJE_v zgChS4*aXI(Uz#@in*%91K3JhH)!%rC0t1^V12A-w0-Kv(smxXMv&`?*JLRtm3u2x4 z#;3Z}&wybH}CJ35hc}O8&1&HUqXBH5KZp`lC za!xjyH#%_K2OL!_T3>|h8*F@FFgO5&c-S09+PkU@^E)gFuA+jNC+E*^j&oI3VxIW? z;H+2`2mj-f^Y8yNO@nfIIVIl<4ooP8nnd%Zc`RhUpC+?Lh`6fV|C;H(LkE=VPwv|e z-vy~(U@^7=Dd(7}Ig)jTT{srWnS4xU8oawwNqp7c)94tIcG*>um9ONRjt666jX z1%7XVHpW7)9$JFFprFTr{9NMeY5dL(u)v6hM<;92R}^WJQSMT}gws2oB-)img*;J` z^&hP_|A;>SC&LGCxG@O&`h$D%q)Dur+y`4gZvr-eImkjA7lcoUV+ z=88m#H5Gnydw`oyRs)B6ugsvv?|vj`l^*gdC@ZvO_`OF5@~>VXl~2YQ-}>FBO=L#{ z4yk{#_xSJM@V__mzi;F(d+Kj{R-S3^X~qM5Mg&Np!$9WK zVWbJ9+~zHT$dX$)rDcDIgZ@iSm$#3({yu;I>rq4&Bor?P-ZNdpz&qs|<98?Kzj&qm zUxM}nMQ|4AC)7~=_L=KV1pr{lABl$Mzx|O9Q6L{KV{jJzFZ=U9GtvVQa2R;cFjuzy z_D6s@awzEo#i>Vs?)v}y*1tW-bvMY)rB2l*^mm^Y(fTcLT_2*VR{r)?|NU=`EP)() z-7ReZ`w!2U|M%sM=z{C=AhqxRN2|wwdLVh-gzI0H9A=_#T>!(x#<5|~z2)9)ldx;Q zdzqlO5lZ^)q|Xmj-rwpx_5SqA|G%u9U)M2mfrfMK(=TJ@-^f*d-Flt|ig#%V@qK+N zA>azmdO8fbN{e&gK}m|V0u3FMXb@2HsHdoIL-X`KYpi0 zi%#;e&(P(!*RWVNSi>61PQUv%KriSXw1&T@RL=h9T>+J|72y6r9b5T`)hauTEk)%*Z=#@_*)vDS4_12MTg^I zV?TX47=jyadUf`NuM*_(@3Pbe6@N2T9bp20R-iYu^jHAGNg!s5H~ul`RsF*v`p>lu zyv2bBt&XXQ=I^J*N??22g_saiodYwX5MXA_06B@Ny9(tz{oOczAAnTsX|}KGfsUq` zL$LXDEmyh}Ku0MO(6QhOV7;y#!2b3i2a}4^f$1E_`QJ@oN63PDlUT#SOdg4-YF713 zk`vIRW!()1hUc|&csz{;9wU7CN`D2mPnlbNo4 zIsk?3+x&0;1(F1o5uglE<^7`H1CE&ob3wXsM!=qsqb&;98A;yg}D*4tu=g>T_KR)RVjfsRP&o7 z=3Cw7pymn$ib3A{ya0OXevCF3!SgQ*ga2Gw9vDz~Zr4r6ewGkxCrd1uzfFqb#EB(IAeV%Z_w(4F$X#o-`0Ckct|igiogurbQ&Hq zV5w!4Zk=kFKVlIl+C&tFM@^(i=JedHi^9^oQJ=&FUHG3%HV;DRTtfShW1$CpkG=8U zcn^S43nr7oz`8#Cvz{>*=|Xq7vGm8*C{aYxzLpF5fi-{~u>c-AE;Oa1 z4Pa?Bjduwa8ADN2R29hKH7%ItvlgQwTBZLvAn62w5cdkHu~8B7^V(K7(*FSL@FcN0BD}!pR>}@|*JJBt*}r^N zW{mg*prrY9D6-dR*boA{;AVj3Kcv#?YC3#)!lXvYa-1y`lB${81PdLp%^WEX=yzPJ z`YD$y<;Pes%o;!=b$&6%Yrj{#(5{jj+DmLKvEe7hcaVMIzkb6c)`SNUA}b1SkRg!* zLZ9`!@n-UkpirF>!;;3@K4r0}C{CWdVXr3rxMZVscO1 zPT-HCg`@17iP{d_!=zw5BxeI76e$qO;$Laj_qa4RJ;v{z7dVg^`^24{_doT8N8YJ z_T~8Q&|zB&GO2*8Q^cuwd}ust6Pc6~7SpvcF$=F(DXpntN>2pgjL-5fJ*L^P|#?C3JmfpU9+3e0xS$lK0 z-~%>7bC;;{x%Nel`}fXCUV=q)dmUzGhsl-0EjMT1wzg!0lX=pJ|ECu~QdcvP6wQ?e z{Hp!SA|Yr37_WbMX9{i5C8Bqv-eqio8!Uf$h<`rMpt}&%OKMx60nl^5LK_iiGl3FQyLaDvq}z-TnP+Y^6B#Y~3E;iZoLk>!@NP)= z)WZB(0}wjWD4VzT2ZOjDZXMq6=G{u*{$A^{QFFex_29^&F3ovWF&guoGDP0YpD zoMHPgl4}MTJdNQtFjT!*gkdH4&HcY+<1$<*AxNjdu{S>u*@YD1R{`N6eiMQ2fQXAK z<}<~10n{5YIk(OZvWxWeaJM&MgMmB^<~UTeEVap}UeRBoG`pLL2z(`uXZE$V-UAU@ z2p9qucKOq|E#hE%TFZ-u^RJKLe^#Lbc(eBy$8c*v%W0ds>{@mV#PX~I?V|Rc1V-bT zRSi5!r*c^lFx_$6Zi`p_FKsuO9mc?tMbN>!4m94l& zsLVl<7fUbq+Iq$FFRSa%s|H$cxfXWG*pbb!?!{~i&~wCv7*oHJDKPD)U044BX&l%y z4-Jgp{I&VwA&in_q(A}yZw(Tz@(b6C4#dW?y*xRuz(Mxu)ui}7-N#QAm(sPz8s4Uf zKRj4eZJ(?4JTo6fR=`kD2y$Z|tsvl19)Ei41;HdXT7sO%vNUJ+U2KwSE$tRrMT!>= zt~Ou&MKa87_&2sT1UC+vT#heicc#6jV8XR96`qahZ@H*D4QmayKErD>Gt+BX!(KT* z^$7BHUq*4rV-q~kDAId>Za!^J`)V<&d|1+a?p%)crqje7Co2zzquo!1s_*r3Dd>=p zF=dcY2m+DN{{6>tBQydIy=W&Ir(;DP?}VQVw3jam+n$?%IS6@>DXZ5A$A`auav2uX z+uO^gd)sIPUR2(}Z+)2h|MB(S@l^ls|9FEkvJS^6^EmeCMMgG&^g zLsUX$_TCEFBbk|*smxHwh<=Y#z2Bb~y}!Tz+`3hs&*$TMT-W`6zZQoxL7vFvqS8vy zJ>vG7HPXtf>sp7p4E)yaWoj$Q8Fsm8VbGd2w^HW+`2-yJjJgh+!^fZmWRjRplp^Nq z-L%8^7o-e{NlrYjKJQsY0$y&EX=xy%Zo+7Y4cSg2XI`bY#qv8FXz%neQE?jQr9*DQ z!(ucUm!%mZ&A4!BeH~d?E0e%|;eWrpz&WI{QB>6^c>vYRIow@v*(SmG&70@XpVu|I z;)Lcu^})Jiq%DIpq*29>skj1B8k!PjP8L~c`}!Q;PQMYHiA=5@ij_QDFI5Lkz)7=>Rh1^$kXKN+Ip~$I9S5_^ z7>T8_MBa%N57g%q6P)dji;LT9<~zJTYU%CZ@aFiF^Kpmdw0^sW87)4%+VI^7 z)GmV@E`Rw_4f-!<8~6L1i`zbpU%+83#W{!Jgex!ms1AC;HEr(OfOh zSh+ImUdn=kf{0#WVPPX{>+E-9W62rgHpW+{P>trNF4viWk7Uw?`t(gN%?=mZBXa&J zmRxFidiI1>`!`$SeERfh!Kh#9e8wFvcKn|uWi3OK>;l}?Gj=sEG}~XVK2}r2;9CaM zOXtUUXHI2u6?!mGP91}V%WH&Ydx5@S<5$(z))v5MaUOK57p3-O;_=Gf%Y5wwRUNl} z{^_U$4Ptx>y<+2VB*znqM+%Od5N?4YijspFEee8g zsCR(;Dmyw@lT=4fPhrr~M=M@XNIWp^p{u&2E{ZT6f~jv+gjcx^6~TWS!{T9iltWI zO5{dyn5Pc+;D8gnjI%wRoxv{i`EANIMZ*K$xa--u6!mEz@}yrT2F=g%pg9*cL)r+C zFT(Pq5r(m7G=cp@S*ugik%ySeod5cC!(lhzXKVfI&*X|9Wx$J!NFFV#brJ~%*9>AK z5D>Z=tA7xgO}8kU9cUiznEiD3Ih>kpw4Ab%CG~Hv!hr`Vh7Cy2BA=^gg%7__Qz%;i ze6fm42GfP3n9;0k`vgh>HMpaZ{wPG$U1z2z2v2C4Q7`MZY*u=m!IiWpWp1&2{H@Hl z=u&d1oG9>R4>j5deWl)wj&>|Tv+(M6Uk;o*ahB3^-r(em6>dj;#$r;g(TCW*R=dMe zN5fpz5<)m9{<4G0Iq!G_GAiH>K5GTAQ_Dr-ktvLRc`nje0!S%gY_7inzl_S#;j%8kfCOLU0hru@gidSYkuDscV+hXJWNkH?`AT`XK6|`Qy1*5QjI?5!=Rrd;oW(uR;Z|Ajk)pO3Eu(aG$K~{Dh%Q|)V0LH{zTZzoMD%1R zR7F*F0_^H7Dl6m5A=%nSiqxx+pZE+Q3L3Lu?;Zp0^kV(QYv;{b-xQVvb~$xSq~ zHeZG8PT`9PvVrqLCK0(yXWtvM20cl`xA^!%fm^52x^EG!;>{{9M@#IB?|e5@@}3k_ z5HTp2c#XYf7F*JbggAa~`gz!N7Y+USP3mU_qmE6T@XL9k{ES6X1>I#SjL3~=*U4&* zwWM~mc5{SZ*&=u0d`JY|c^pO;d%UI8D9s1#>z&wDPd`oUz4@~);HNtk!sPODAI$R= z5XZ4pJ2;nPR#r$;GR6tCTblG9B`B%jV#3#vOsXi`FdH(hz#whLyVr)9T-#%#a77%J zwmDYCj)PQ#mY_G8Si)dK?643keqZMmpGMI&+1bp$f~box2%=-3D{}5O?G!mrZy!Gr z)1vC>c?DK|_z8`o^|$iWe0!>$XZ?n!ZsMN!YUX#z23o6&jA}aED82EnlLuYszC;N= zSH07^dDd+n@&m?hX6ON&L;6U2aL@IE3D>JdmaAo0%eiw6!ZouM?P*-mjoluRUewq) zW4c?O#G_I&+J#*|q9m1JVdnMl=pmSFX19)BN1QoVAjc^G6Mv8spp~0hXzciWB`B3x zLm?xIh=s{DC=0zJTVvEpXlC=M!PCgr`VllyQZ0c|#JYXV!@D|tu!kZlBcBsR9V|qx z85U{w(k4?Tml_{*yex^S%%)rbR5-JsrS{Mt=4f1ODsRA>{hL&pkm}%>53$r{%d*eFS z_D1r9=Z(1liyw5I1oHskMvw!D@~p2uEwiThcv0;b9^x@FMf!7F?PukenDFx_A&qX5 zKcaPPWJKT5as9s1Yf?IdW^e{F$c3z+;oGXCgnXg8RNx%h0aF>mS6d@3N$kfSc)`0_ zxX2+O=gy{@jXSDz&|%JTB^YS&}#FEVR9GuxsolfjcVe}}K4q9PYC zKa!{AQC`%?TU|5dwO3f^|ea9ao`*RA*5dk$jvU(zu{0qCU9m9lzNbH!L`_3L)yD& zuIW~>B&Kh4v@?fuZOQulh7!=h{ zn0|XYR=DRk&iKo9Tp}Tv0-C9{_cC%2c1zYROnZ-*%h|3vZfad{{YD9{Y)d?l40#&skPhmaEZO2=7GLl{RMvKy(~+`)=ILK~*Ut zf{pRn*`_W{0ojv`5U+nKP=zTEF@%W3;S+Yu%ag3==8`F;CbGSb7(u_`xkSUTo9%n+ zR)-~n1E=wD5cqupl7qk)JJH#DbTuicGnEF1fB+#yH3^H>qY8nOi$Vw z)d(ACkn-r-4^-C(2?h%=7wOV{A+w#$W7I?KU8fuB%y+Ig%WA|xtg7Cgn+iU`5=O-W zGIspVZ2#QHXQwJ9N#ZpruO}tIoWkGIyytkix#bEUCs&Th#bkGga!X9y&g1FRReve? z(!keV{7B^%uM+eLqjpw@n5-EuZkZ(~0V91GVvtMM(rYWi%t0wHca@b0o2F9DH~`I7 z<*}H|($WFb@AYFvZC@y-J3v&Q<$dGR&Sh%x^LXQD<3B01BA#E~gB8B-!7}rQcMLzf zR2|lq-o)N~B>tN>Z^q~5o|`n@pMcxDf8QRrilyrD_)^(H)zo(Ri+9{3VF5##JyU}y z8|Vz5qtW3&{!$$=FR7unl-&3;fq+w<>+7RDrhgeS_D4o6 z^1xvTiePfiAwfZJ1YSOYO}dcMBp>bV?QaU;NtjO=np$cNe-NTtL~n1>C`0x1^Ibi? zrs`M=8^2ntrVYP{g~)2~f0E}7@=YU7XZ9|Fip`3H}9vI*0r)<3=1p;kTdTX7_e4y`kCPP%Ou8t0q?t4-} z%E0Coh&m1)GBCFCxi`0569*nl-yjT6n@+Pvx9UsPLeFN(CxumfmpWZrxFPfpST)@TIUMxf2_Wd=kVMqP3pl+G=mg< zOm2BOf1__{0C9}$N#d#d*dLB7@mNnF?9-=P_Lr80l$6mthw=;T9Dg=~D)5)KY)Sigj2p_4Kr0PbTtEyZ!UtxzE6F@!s(d1 z9_y3V*zsB)yoBOGAL?WySOqoJ*t`z9V!F#%o`RQs$H=JoIyjhJH)x{(v-wKrvZiZ- zwyuH3a!(dt{b1t@glKGrdgaCtqgU?L3Rzh~%iu4}z}DDR6Ca*%AVOC_Y!H|Hpa!xn zs^6Ui7Q5Dn_xYwKC)c>l_Iq0Tu20h*rOfW9B+t-uos^1_@Dhac=dSU z>Ka&va-YIr#0BJedDp&qGv9vu%z%`O!eWuiZ=R~yz!(u+j61yS_Ut?8K$xA`&Ji}L zpd|vtv4=c1>p43qhATs#Y{)-Bdn`!P5x3?aP2_Hz?d-Rs+_LV4*e}cZXEOX?x>m!M zCmn`=vpDus9mC)MqJRxGFF*2lEOx~~r|7Q$FaNJNDkK!ZV^lryd?~qDn+msBj!&BN7*~%L&1^w{esz_h6c@WK!)e$a?J`T;e8T8#m2-hd!u9RY zc{RgZO9@aF5`E;oGLEB8pj@xby?$8cY(3BP(e4t2U2?x$Z4&s>yF$P*Hyw)%_deN6 zda$1q{EkJ!=D-(l9>kPV)cs{;Gs9TU%D$`j=Ly50T)0W=(sTFl*aMe<3nsdBscj=Z zFgByAGDkGwDd`s5eY4_0#xlead);Kr@*vsj#zqW?2T?Z&8cv3uuc>D&kuzx-AKgp& zjVqhh9i2aPOnm*PTOh2krk`MYGQ_q>ab-f2}5n05 z;FS85&D}TT98HV4To6?Cn{9B@uVUH@iHeAHfI;Vb9a#y#^=K%YP`a$2WLxkdg# zh)&Z3n7)J4QdXaCm7$$-*h_WID>xDPb6O5nfeUDLJ)9C)(5rr{Kov4LdZKJjC$eu0 z!ryX0nMFXTiL}dLLtTETYy6MBQLpk^bqWvY_$zxnscz|?gXZ3x7N7^Y9Ed@ z%O*gxwA-}1*}+g!MYl6c2huzGTy0T$MJ@ zgmeXMh-Xu1RuV)}g=`Fetrz7gAhbkMn-!$12P%Z=GSvaN1lL0SP}h+9D-|(kh$XB1 z>9{Aq238+Y*A~w{YwO@35S5ge*ny%{;=8l|)f!y8nz%vwYmAB<)clvPaTy8@z za8@i7CE{x$S-YTl!1vogH43TIsJIZ75pUkS)Q@}m(gBxgM`TnJ~d;UzNKE?P+LW z(584TrfDr|!Vlk$C@w@@I~lHi>4reWvo0?--1d0f6HO=P(3{A!n!n*jdE!v?rEs>* z)yHVjrh@|m=1TaQ8X6Xl9z7~+bX&%#-ncQjz3q0%S4u)cs@S%QYvg4}%O+z95c+ez zv2$IGnBpQHGG%I`@&OMX_Kfg$z1UG$}gV@F}n=|(69|HFZw4ucN$zXHpzAHfAJe(ZX;dukNh zDZC4s_@>$;sMcG835A4&st5F530C`jcM@}3ialB>IktN_Socpn*$IY!<{X!FGj3>p zem=W2D(JfRb}kVy@nmzebfK^D@T*s^%79MQ9_oqqN?#&ZQXPE%o)$?ERWJhNQNs_D zjft}P`T_ABtl+*2GJ!xbdyliCq9QRhr7UmWBAK41dV%MoZmoP?)Tdh`G3nz}JKcvI zb*d0LARL`U=*G%t$`%Y+?@hR_jBxz&QxATAe?YaK_Vr4^eGt1UKu#$FJEnai8H}d( zI@`3Q^yU=kbBV`+i?O!^q2XbPiImBYAM3|*Vl0ERHm}`&JHE7JlK|hIE3U5>Re}~3 z74f|bjezDup|T|V+P}VP;q7x63V0Yc4dOE-V-u^*RF_d$JcAxvnuBYpgi7WzV7Mvr z5J%cfcI}r_C_GLI{EHF*4!o2?-byF^IHw5;3CYvE ztgXGCb1_bRUW3mmhk+aW7>u)cOW?6Rw_oLkW!?qPx4ntt#$Xc+{cq&+5U#-;uhI_u zq`RSdWRNuXqulK4anpOnjEC&)}$1i+8a+!q-v;CYS zIc|0v)+FOf1?}3kH-NhE3WWKJrXRgc0w39LojQzC434-?XtB<=3$M?0&o9r2LPI_4 zg$99a1BF8QaKnbeM&7-%E@=?}h7dp`Bh4XA5w2hxoj_@8$Z;J3aur1=fP;!cs709X zUsWiB$(0Ov)*R$!NdCWWGDesOOL*1pFOU-+-J9q&y|v*z)}Z3-zP|}-{yH>XF?oQ7 z_qL3XpWsFLk@-u&r>3Vf9b(gfSW{CgR=KEfGO_sQoOI&=2SR?#D=CT5oCwnls2wOx zB;yKH;UhofqZp0{UHAtR0|TUob!gN$_I3V6w*uUi{j;j>-CsFgiaBO)oXF;F{3KWs zo+p9PY~QIrj+fex-^D6ogw79AMBRHD!S+itXXq!HlPblZPg_WO7P%CsJKNVLL`Jtu=3WJChdLYRRo}nu*R(-Sxosf^ zEPj>veE06%UC`<(yz2yF9p6G*pN9^UJ9a7E)xzC(C4TM}&rZ9G-~Um-JLczMPza^C zCDPk>O_OpSo-aB}1bXsIbaZuj^UOe+iEAAcvE+n70WAqqRZ-EucW)n4 z-L7=%jedQ2^9u4VEB-{??NCNeuO}%fCe&&88cZX_KL057i_$FOX1nmbX8ym9-8M8Yj%+w}p(a;kZ3O zUTsA^revF4TwL`Bk^6gD1}&Tbgaeu(MRX3Rz+N2y_U0Ov5Hq0scJ$n>aF$`1e-EY0tRs#Lya zd;}N0u*Au$}wYICzy3gp*gW-!N_pjcrb^X}W zvZAcYQC@l$=tuv$Y=3@i7G))6zRoTvPYO>cmSstzoez}bhXi*(^AMK7${;6J`#4U8 zB*VJ0Fp*<3m%?I}=_OJHf9P=UXGa%w%5)FG#m!~3l?xRe&5Mm*>>=?p*Nc{NA~#8q z$)~Q#7)a{qkZ%C3*=yKctIN`(TO8S|r@oqQ${C=%Fq=*i8yXo=>Av*Z%6PSeylVKk zaU#xYJ0gU1A?~mD#J)+P=Q(qI1$FqYQ$@DBooe)-a7r7!H|?4rys= z(N93gB8T&#N9mQ70y)<2fVPZE;1VbiP~lqd+?H-4s!pl=$08UREOaF(bm*xe*JS-W zf`|wn=wfL0C8a|?D!J&1ExzQ-)RpOXZx?NJvpM7z@vPl#?rE)lbo^l;T{dUCOw993 zWjUk!Kc^y){7(ttz|cL>wIb+>FOA1 zj2~-WP=um2`Dlltwk4R-7qX(NYNp&Cq-8%u4Gj!g0?O_gsmt^l_{M{dzbxoae&Fd_ z4bE85%RB`t!`A^(Xp{hpkan4+zA_6>zW^l^QgTVOF{`gubV}-%cMSgbd9nsrwc%6I z8hf~OGbNp2+OqKW7R~v(X#-IVZ<*3&o02#RtzKRhDQCXH{xt}ux@dQmn2bRiuDb{d zGB{DCOC$?z(qW`b;j*3jIyz8hId@0p1C0{U@xwCpd>bW_&I4H9#TW z1s`SC6BHB#8VuP~#ceeQDWBa!Iw`;RqM~As;@nc+yODi3G&h$fZWm>^r#Wf} zginfc;UnY~!(26t%LGRr>8fkeW}zdqU%YU*v`$j-fm5kgelH#PZg>)rNb>y(l`m)s`sg#hLZNDK_VLb@Zv8K8;c5>l}KZ0 z(--2{;AFKgV-v32fB*R&j|c*Ws7B2XW7xGTBTeBN4H1NB!*pL|yRJl90iHY3kT%P2 za25Elrxy-^B86fcY@+yMmFoJnv45^#x8X$VryDMWX6RJnl*wqo67qFAxyxi+72LyA z((xz_{j%7)NFSaTl7K{C%Od3{C?c{%?&ttii42CCLb*P*c(CZSK{8BKNJwx2OzWy0 zxk(OKC+B89{?*Bm5ImZxYR8B;4HjMYqe4v#iqqm0P&^ZGh1p;K&dq0|4jjm$B?9Nm z;vn5#MuMFb_o02GQ*yWL^R_Mf;#+_N%xIh~;kVg8fA*RAM&AH1LVRE3sbKu;e-D5% z&1tZ~N#U7FDF01cDrU?u?+p}xEaQAeFd=omjzE8Bd@pKoz?Y<(ToJz|JIpFMf-GO+ zAjqz$U}2CIZeE)eR~Y}nP#)1{+3FHT3-)t|?|qGc>Dr_LMK>COl$Cw>?t%fLGyPc6 zYiVhzw7R-Fc!*&%&8EplOD2{Ye;Gx9KE4V?sa({IEms-8r-BQqj!)fjW4y+MZg=B; z{l2umlp&lJP})dqP_(m^iaB_wT{b?ENq6#wNILQA~<58FI+5rMU$;%^a6*#J86wt^qjVtBMd28J;2b zTNt@w<2p;Avz8H3@ygNH*JQFoIWe4W+?Pj4!YM&PM%k>=hx}u+dN+=8is3E~SJ>C6 z1ts&syIC?v9v6&SgfiJ7)$_}$09XAc#kJ1s3Xy-4+qqA8jJoe>O9Tz-;V)A*<6`c& z`Ryk?n83p1tKMe|lL_l>boD#U4y()}sQT=OEIbJQ2OOw}J*N_aUqD4~R?~ww{%2HfHKKM6)*x{V^{!ME-=ew{zDy1!zR@V=h36YOK_d- zogIVQw{J%xK-f@8xF8qDtPQ`hHy8Nu6IXuFmt|TBZ-E>V8axgO@$9e;9d93>n}dFp z#b2nx<2BI&!or<9g2k|a*3K$lo|>V~)y`8TjMC=UNI_Ow;kE(Qgc1>k7Mn_&;4|dT3MCRlee}#(e5!yO<$SN{p;Ji;bx#B&TSc_b>cDij6Cxznc_F${^ z54_SSJN4umWq&|v6|OS&u>#dhf|xTN4+kX}U|MVamu%qmud)Vw$0N%7ZXNi>7s&VmGciuk>u z$;ruu+UPqQGq3nEa)$y?skLCu0$pgdMoU=q^dD}$MNO31)FkC+oFFPUCFQoH{$Anc z%@5}k_IuCQOC2Y{4(Zt3EOmExZ#P)T8G$J= zWx(z|{0n^OhJq(vaj`D=Ur%hVh(qCy7-Tk%-CQE?7BxbHc=AyPu2<_d&o94QIa%?! zPCfnNE-wO=uxUd+@uAxqu2jo7&mn2tyeZl+{bJ0=3RjUL>8e?EbaXVk1iNqOI52|_ z8wj@i1c+8aQC8_hinL!LHsopK{vy0~-LT`ps=>$YobWqKS3IZW+sv%&DshF6dSqAGdjb_q z#!;WY?nfh+wJGuz-aNU+XBVst1qlFb3X-}GasMwJ*8B)Em+y3xD&~DMMfwZ%O4CDJ z@+`f*51zVR;gx}}I@lsygBA&(RJ<=6Q?r=T5$zxGyNTk%2eH= zB41!3liK1d;5GV$A|oTm!^zp!z|5rZJW+Vc+H`|(&KXbzVlZZVLujgQ(d*Qe;FdpA zX3582`9H#1X&yc*Ha3?rPX-x>uf5GU&2phi`FX7Vb2rkb9vp~3xoUy9NW}cISUC$} z(F;dURB`AU_}dd3nF4HG}3<&Uy(dD@dGHs9~~Yh zAC^G*ZNgs5kP*UlP+76!=^5_tK54Lup9`MEtWVg=xHV7SvbD8MV8#Rn#WXO^TLw+O zVqXY~pfa`h;We#|jkBM*6?wgEgygX#)%5hV$JRnS`#V%U+0?{ z{0Lj)^Ye2o^Z&9pvU3v}Y#7alge1V)fP2i{%_WDhP&|2_nc0f1A{Usq492-c1mO@r z2%@jIH{#`k+f!YJ-+)_Rbktt{U63hKDXj@lqMVfKg6B@T2KL*i;7i;hg%s&TPa1i zcd#g+QeDo<4o`+uf960K=MQ`_ncOtwM`}jvbK@#hv!{QA>(<)LS5+rb@Cl?o+ucV& zMIeEbP=FxJU%yO#Zi46J zpZ{{!!t%|TH)`K7-eGzo+1egzy#ADp3DKUZSc{s^KzcNMDnR8A2nl+%;YTSO4^+}W zRd!HcA;PD?Fc~|k7kMPHVl;ylQa9PjCD(iHj12Xr%)6w{LF~7mXc$rhawkfP6Ji#dX%z@Iu3pe>pVoRnmW#5tadbRfU&OSBVi2Z{8yw$ zit!E2U^pJ~*=86d;@t#?SY`AgK{(ZlGN@a=Us~*#kE)K(TulRE(6unXQzp`a4@GK^t> z%hZmpFEiua(sNeH(>1Us?Hg^va+)0FER0UuLJhH|9KYr z%NHkmXXl#Uq^k;p3S^wbwAV?8{k6d*!lS&h+9h)Nv>`|r&RzTWUHT1h{F{l$V#gWp zAmW(e(z#xh_za$WFp>3MRN+9YEfr6>^`$;#G>v32`&mGP@4=EN;vAF-AoRY7s!<(9 z0xDi>`08RUoCwKa?(dJcbj^3ZCHV2VteP5Oc?}IX1(MVDw`F$rvsIoxRr3$nDmbst z3CyRi5qL`DB!4;FM-F97MqXWlJb4H*IA%ePzbZ7w2ZtbuQ`_F>vN5KMMZ{|aux)%| z`Zxq6SPma~!Q~E&L#x&*{oYJ*=xl2JhkEnJ_yI^f6sP873^vaK)DlN?b4GauTRS_n zt+_TAQJCb^Uy5((7C`n6FYoq{{VjDH9Yc(b0NLd z-5(Qr&gWS^^n3p8N9ne6r6WyL*N>7Vlb&qT<3=jO~Q!tLzsi?Xv> zl%Pr%Gae}a59fewkoEHZ~G?tM`Lq_ul=PJZLAqQlch#LH36b0i6R92zUI65d*5FV48*2L z_z2~kp`oXb{yF3E<-IMoG6J+J#$8yf8-IMtXO^a8A8Tp2_w`>^7eyMYot_I&FEfp8 zOJ{r>>j*0!q6$6w2urCn+fda$ZTLw7Bf{N8XxjM&ptbPIdo|cGjPYYw0cZ=FuL4~5 zR_7F zZDCf0BQI7d=7Xc-)q$@9)TwJ@f)7DKuB=wP87$;EdzAbI6jSc*dSLU@fx*Yqqhn)J zsS-ZeeH9Uw!;`z1SEsLDa}nIXJ7|9FKeGVz?{L{xTs`&pq`;G4IJJRS^+usdBEliv z9ulZ`S5|mUYF(HtTBb0tkdAmHiHS+{CW@R_&MN`GEsM3KV%{n5RFe`P<;`VWUy%-M+X}2G`|- zO~|D0nHZzwpP`h9C)S@PG6M0H#W?j>QYKRq0N!H(l%dO=*TEOwVHhY_5Z}Zh!Tn?6 z;Sf$kRt_~(ZWoJAt^T|wD2}5Q#S0+1(cJVPBqU@F@Y6Ct4(0Y0H8?>o#UAtoZOwka zpzwPBmvuF>vd%Sy9!wcNU@kz3{^~7FO99oofS)k4WLFK(b{zEG9ICi)5 z2Esn>-}EelB1rQqUQ}e`_l;He$F(k3VZ7qI<~+=7m{g~RWnOD7tTt2PRGN_Xnwjf>-m zF9fw+P$ZmqNN>8ky{-S?!Oy!mc;O`Vaa;y1nTl{00_Sfi3RC-g(DnY=Ff9T6820%p zrt~Hcq7kBxtm3q?35`f zDY_;mbjXMt5VV+nL@Sl6Cm+8Z{VG>7Zj;6seG#kZe_{lTOXTe}1^hpN@lXBeTq4;( zlmR}mH;Q9I27}yvex-uys%fOKwMk;Ebh^7+ysofE1@jHB?eI0xx@Xt~34v_k#pjBO zFdsu<|9D431z~TnW<=o`s=6*~evnNdN;}Rsx52#bn)4Tl+bRt~N`{QVwO#&z;tn@9CJJ2yN7;8LRYd8O z0}w_wJD0LDtJMy~QqcTKYG@*Te0(V2<(|bCAG4{YMmmSAvKB8A@N5V>RsGDWjisPn zh?-=S0leHy7vwi`t(2h{b_^`IUoSZ^Nk4rZo4!nr@PE+1Y%ze%;;l_oY|UdDsXR7j z91p*5#ApWR{D+ob3HCpZP9jZjYKI0O;#jxE*vk+Z^UaTxbumxN7PLE*TGG0V5WDp) z2?iR9J?I|pu=a28A*Soo#@?(6q!LcvS>NwVVtIfwH0JpL{&2kr54Z|CbasBe-M4`GuwTL7T$UU}u}XTN1y^)3 zJb3>W#Onuy7cU$*dU=g2J=7j7cOSjnJFKf^rwf`tdD=Oq@-;Qh+x33Br4mEh_f$j^ zRJdD*X|6ouUrk{zE#`|j^jf(n6}Hd;CJc}Vw}TPH*W^obK_~fxPG_3|+TXf^12q=o ze$sYj{5N6(&s@yHsPTHXW7h`a9rjov)!tCp2r2{PxKWEr7h+KBq2$%I@wp6S3`?8& zwN%Aa^&aAB6;%RK2(36QI08bzwDy0wi>U<00C=40Gh5&q`OY2iVmoS=!?jlrRcE;X zzzTzkd8~zzIZ_&>dHgoYW^dSY`}0RBSJO+2iuzLh4s6Bze$={Gn^oq8YjE|bOjR># z3OII;r>>~v_T^{lTgc?s8X|6SheMh4gZpsGEV;c#KIrv!RZd8ga(Q=Lv)C7D5Rkkj zD|>TPgx}ovRZ{Do`b)~VFyGBN8G8qZ$Yt5RLthDB^b)p&HlR-tK)bgO};&WM?Tcb@8Z?^b|H6|NpAS~q=z>c1|4@p;q6qXSu6DSE%X z`Mtvz%M;y$v0rXZ8gdSKWW9E9u9~R+iYOq6<3!7H#%3^TQUps?5E3FdWB;Mgx6wtF zvg0pr=PM!F8q5uY=AatY>WgUEDjG4dgt8aKR)s$ICs{ibRN~UNeWu37sD93j?I7IU z1tA~g_gwD$iqb;Y&lVF1@8N&iJV9*(cGQ}2@u{dVgDmA!m~R5bS6%>_9ApdfH}CQ4 z+Ze7Yz4;Fv^Ipmoa{iu6ZU+*=Yl3VtmccD+T$h70Q~{Ng7~tmOiXh=5gBQP+2lT5n z5a-9Cmc_u1i{h-#0rALp4Io)u(kadrJxIOzCzgU5je`bLYZsS)?(C6oiT%U3Z*PD-S)FU$Y^kM4Xh;h;v^lw_A zerk|vJ#fHRi$PoJqqFIJ@95W*XEpC?KY5pUYpuE`Qo`@v+Z!Zr4Zc5~cvQN99l%kh z=4X;_kEa>P9VKl48w{;rnYnMr+Nnf`bOMFjwc+*)R5Zp8>gyl6@9`p0g)VU|?cr;- zRk!udy8}Q=X(7yt*@#6Fsa->xVj{My;~@ptlN!V5$Ns&F+y>L z5-Fko%?hz;+1iL2P{g$`gWwQH!DXC-8YO5gaIZA!rpfx$br{1&7X(DZSpUZ47cX8E zm6Y_~NRy;v)?I4QC2<7>T8?03p01V_dDBlPm-zn-&gn8bS06o46=p?%EV%Bo>p(%k zqEo32O6=cJ4!OTk$Y(buDp=s8L6(eHv&a?T9Zu=RmxWJMx<|f!@lllAFJ?#V<%6Go zSm)mKIt!T#vs_mIK7Kxs;oT$a7QfbG0)8P%n66t)jFG2W%sZ2p zHWKMGjlMn#mmLPEPM|!{>WtEiEu3?G7;#B5C4tV^X+XTHfSb}C zCe|ajTRA%1D2Ot5xyM9fyWnjrETD#w{t88ABEE-Q(uYpO<2p7T$#L3 z22+gro!joZ2ms5z3+2*Dxz42*4^YA6?)dolF}YNbH&x_7IHD!f4Uwy?){$9ZaSlMg zq`2nhkGVo2($Wr+4#tt29`7WJt$%c6C{vrVWvVVh1dZny7ut9Zy~@DgD04beY8sj{ zup(g+BoI~hKkfK70C@sPzo2UQ#;Vw(Ki?XVx}|!BI7T>+%}cl(I+rUs!d7IZm$0zB zvKg&6m5=ftY0PhtywWqAPGZ|2ZZRsXL4BB$dwJ!BU(A2d?>F{>T@CRiP#E1g6 zTW;!LY#BWI2q3SmmkcD7*y|k|@88(8Gg|EWCQZzfSH5V#4Y0lhP9W#q25K5#iO*Z2 zfj@v)KNM%%=yOY8@on@&F@3G4(aTbt$^^38XdPmmxONrd(A_*xlFDQ!uiCZ8C+-Lu z8WrMu45JkPxT&Yuc=1h3`r=8{kj%uGhd>4fWrb$#l|E(%364IwX=Ar#&@DlAO}hX- z^-8rWh@hJsLnodu=fMNurlL(_Vv_d!AS)J9Q`>#>ND_J}pI`e#4ZjyF71SpBHy$1y z925dgw_euo-pAyz@AX#bhZjk(C3J-u84Ht8+dtp5@aDOLBP|NNZYX_OMm_wd4hs{~ zBFwZ*SN2Xou;iQXvLAT;bJH&0{^JN2v8|Z*#hACT6!8xs1Z*bAUm-=^j+lxHE>^oa zSM|xd1|VZx9r5y@UUFVTs~R6|g6XVbA;Cq+Ww;Q#XpkIUpC?%h?nPC5Q_a-cRIB-+ zU~odW$`o(#g<|O@V+r2U_jJ(w1uCx@a0!z*4Gj&kT22L41?!h6c}t!0>-hs7F+SH0 z!QfxKa3MpyQ3oL#2GO8H2ZdB!u5{j!@#P@+a5Fva=;){nWNqFVSp04ha*+UcWh}E* z{FD~}Dnu+}dh)IR(;?z`jBB5#i_(CE|Gqdr9r`$yYo+ZQK7>~RRjjTkpX9RDGWBxT z;~m=L_3s3Wy{tLNB;80Ar|I3?bcqzL^xQDTmP>%jiCNsn7h|8^m+Jlct@;w@>M1XS zBp&iZyLBF;KrX7Vw#rr-qaeai2HR$qdpoeVwtZh}$EV2eKhw{?f}#~E6nZ8U#ul(pmw_kuEG~ND);K{elE<+WLEN>s&S6d zM1m$fFo>#?9hnRvz4$v&UU}+Y+-a;b=5;6CK-Kp3OMSAAF+24H0(^S3KA1i+_Gslr zo6mpSoc1E-s9hv*~a`Xxk_#%3PmUd9h$Z06gWb>~0j>OUsk>t9VklWVR3U2&+4EA?^R6~TuLyeIk?aii-V)cN{XGwCQ5am*ACgkr#Q(mi1vjLH zi{Yy5u0hJAiX1IS{1{N4*%;YI@Zh}C)Sa`for3+HCLIHna>UtNvEp$FjK=<`>U&xE z@348l7dx@=`4(icXoIQ-+wbBA^Sh+6BV(hZw}1{J@X-+nEnyte*oY21r$+vqr^Vg- zl-GZ0D&U!m>$b&S*uzXhIVk07aU!i%@8P`8l=dZb&t0fW|4Coa|3?80xDP5Xo_S*tLjxCrf4q>EsGW`nfp8gvikp^9Rru#R?R3MbfjLZ&)3|lS zC6MY8QPW@tv>Q$k4)GrU_4yCLS z#+DK#Sq5bZV;TDvm3^t~`!->$g$h|lh_UZmh_Y4I?7Jjewyary*BH9*=XqY=-ygS^ zUN`3Rxvq1a^FHtMKIeKx#*s>>+8=bCp$o%&Z9?LkMUlg0XdY*El2tdyaVu6iKiG-+ z@AohNn*r}VMIf8dp>(x{3b4itDFI(7`Q==yUVd|P>t{cI>6J^t>r{*rJ&awYd@a(T z>KtaUi9;R;FXSNf;{3DqO^*J2H*+l(UWvr^Hcdwv;+(!VIpMY^7>|dxkmNV2x%f?W zwoJxC5;rw~numSuZ*p{%AQ;NQ!BHSnAl`iXZQY}DvBEq&3OTX*f)}<0JxZ91X8(X7 z%xQ5!1^pCeHDf>}GSP%xp&rJ=|+19GwZU!RguQeRr5 zl&}A^o(f5t_CuwYT;4D<2o0~5>^J_Xa@?tM6y1MlPp+Aq*81cqrq)#X<% z6kERYIdh1$B@-z-)?ayTVu5hcF_rz<^H|CflSaP>1x^WTUZMI6ft%_Um0;ZD;`@BF z!>8AN11c)ttzREU0ZAsRuEqg@XxT%>vvC{k#p3Nab`3}lQ0-MeAZNCJSze%q>0?2m zQP*gvS2{&s&3}+x@{Hx24NC^~{gU&Di=z4hg8s!#*l_c4jnSy&~H#Rl~e+7Wy z9e07)CcK2<=Ov(#Xm~%as;_%-C<-fBOXh-9|I|{2x}=<;DMSTh3m=U@%+4DTC3{ zdLo_I>9sKsB z{36D}=x&m$jUpRr?#D@%;B)+DE+A8t349+e^U@`1MPdANPnS@;zeV z&ROFOTEM%JC!{mZ#kg>Z#tn3=ZP^Y3iB>Tf@jn2XQYM#vJlUwL#DgZ^b-3iF_}Ybx z9oFsJZy;q#cl^JyV5C$p^;$-1KmT>t)rI@cp0&Ao(4KylSAh}UYQca?(ByJS`qr@@ zu~L?_8=bE!v<+8G?g)DfO@nvD?^>!qH^$8R`ue&|>QlVp(43Jfc&SAj($>~?ZbL0a zR{h(CJx1JHT?%t$-CpMlC$nzepSo|p*Ey5hlhBIfhSTU96Cjes7rubK=n7DT@*}n! z3O5{>1_RkiJTD^^^${x>)cnL8vY;p})P9)SDyG|K!b?&r%^44zKh&bGA8d8v0g5(= zu}%@;;e#NcnRbr(ZdXTZyARov$qs1R)z3Nq%@od)%B2Glu!U4#$feonbrm}8vD5)= zxsQU^UKP~)MWYVJUPwt@{aL@Xt}S=BOXPW>Z;J-47*=|W9qA%rCvVnIhF_8K%Q#&& z5icERUp{mc2_R| zqzL=+SwZPfiSsY>0x*i@_Rs!N(BOJHBy-&*nHO?;|IarwuJclCdgu-Zwb121+a8t% zp2ENsV275T zw`B{+pm!t9-J5ylj^psOa{{~f5pGdQ=rfPE_I+fNcm((b%|*FyJtza%KifVS$O>F! zKt1eXaU#<%^T-e5zx{qNG50B5N_rK2Q7HG6_*@bR-?S_oHCo!!dN~6AoY57&GtM_0 z6n=0B4?bMJlsslD52bz#9FD2zjlD!zo(CXEd0$XHClwhu<^K_94*4x)GfaWG92{CR zA_c`BSxWa*h%xsY+s>xhSQQM|Ai1;7#;R%Q<&Y}NhQ8<&e^Kz%Kei)~F#ap8-t5c5 zei1N2DJ$3N|4K})pAfpSEhaRqZJ=Y>x_{A{687k0m{Zs$m_fG3 zg1*o$wi>!HRy(!`#*V75LDI-ob%~y>t4Kca7gtBKOmwmra*!r%3|`VOcfFnbc*4Z6 zD>kg&zpNtrIiGpZn;#@2AD*nRa>Lox9nHO-oNrZ6;yB1q84O1UoE|amGSd)=7fPVL zuHQ9&zjOOw_z4l-j|&lQkG!{^sIMQ3P*+!1Rqpm@-}71=uDFH{RvZ$=GoV0N%Sm7$ z0yBvs+5=9us{0#FSNg^?p^Mixwx*WV6q;LAsSFJ>A+nDeEL)(JT2W^YX5*Xt4-7x| zQ{-x&qY$_h9o^tLvLT|iDeE+9*gSlBB^y&x!;XzUx z9V5Hg%$rJHAp5%ea(Qs*HjoK(n3}s&pVPN)4(FZdR4U{+HB#Osh7wRp|7BmnR>e2K zUjTou;c!i!5b-2(?OS&@?Nri(Ta!orzxCdS15HFRM7{#;l-_K%J<_|Bo^l%`w|u)J z+DgUf)?KNIejMDgRwJxTMAFI_sLZ8N?-?pToBvT~d|m(a^Gl!6SDo}84t|yv>WJ&2 zJTKIpC3x>yMv6b{iq#%&Q1rqQ1&fm~1yFr}oI1sNT9;RnY=FbkFA!^Fe0lBRcY*q!+EDS6oC1UR!gW>7-i@bCqxeFhCskx}*4TDkT^-lV z+>*RJ8sh8)CjQ|@ta_-w8tYqkG@QlDhqHMJ_V}5=SSUl&`Lvf47=rlM*XPd)ycKhO zsH}rrkn?;VLznIsR9?8FS&W{@488qLrq}7 zb*q%0J?WDR1Q|;+<>*->#$2JD#m^O40uK(W}U z?*Pq>)vJr_5^@2{PI=eIra7iS2Nhjnmo$(gk#?27yt+JY#@(%r=XZp82-&c;g|U>Tt~IGMU}h$t-dR8=>j)JFR?XXx6s^kb+lY z3R(t=k%7(7sfI@l6H_tE2OMWuKL)i19E1ka8$3(@%75DI*Q|KaHGjHv>AA0kXv#2$ zyU{Grn;M>zQ!hC%kMJCSxhzhsMrH2w7xvl`x^?7+xQ>u|Dpc|L6tfx-goJ*{*<-dL7by!U~sYi9$mnd*Bqs0DzSUDOJPK@rfh5X z`G1_RHUR?>olTO&V7~mn>|(Srr%oy;c7b^iIP?JbdE!@AT>L3N!7Zbf=~RLl8DPDi z$WxBK%r=O#&t%gpx0jM$2Z9xL4ZtQxe}58?r1gsB{l=dbixw(S{nq~!$@@H7z(Z^x zcSUbKRwp9q)b{Bkpd?SYy;G;|!?pc-Ul^glmv+!!?e6ShUSxRiOjlmnn*1<@7ZxEf zcssX=*rYey|NW|I6Z=Q|rB{Yko3{m{nKScfr~`ziO#wh&BiA*O2pmvoLz{KI2hxWI~+umtg9R z_F+n_lIiGm>KYspct%QB#5!`h_Zv1CPDD0B`l6Vn zvrd+zhpAQix3rp%JvUs${8L*RBrl3uRxKM*g%ezOQcIa2#rLgg@k~fQFCi0^;_NU; zHZL4Fb(Qb)cbsHs$pjRaQAzFO%N|$FXL$TLY(iLBid3yUBRkVwQW+p~Mxk|3Pk0;XtVO@yN>uB3<( zz0c1ly8xLtV))Wu!CLgL-nO!lT_akz^JPx2n%)IrsXX-I!}C_Q{H3PO$o|f^deQ;GDbVMz!pC#>U6qtn z`|rv&bHqVdub4>}lcv3S9qg%^x$&W4URZ4HB}}gJ^k`f ziIvvrVD1WIzEii~BbaHW;D!D~q_0>C8-gBGHI{^jBcGtY&|^VS=e|qAo4j}lH@O$l zm-M~lK2wP=t~x9hhxaN0ej<0U$)H=Vlogph#To8-R8Y!Q`EbcZ{@!iR?PAbA8y`+9`he+Up5F!zxZ+z0iql{o#(BHZw;1jdC4U2mb(U$4*3 zN_|y6^T1kV{mpfo7Hy?W)C`n+h#|$Nk(y11_EZJi@a6nj7S+&G@o;X5M)>nc%({D{ zniQ5RUvUy8RY>|>7Tc}x8FaO-3Ilz`YsQ;T*wg1_xk#uUGO{v9!XoV34nflp##?4@6UTWtFiTugLv(n#XyuE83ot>L@)4#LS zrQpQ#jvZdK7E+$i->`HVSNQ)R^{)Ds_AIqI^7i64!>lF1FSd}iYXXen->pkysc*H=vV>k^gLfni4N{t0g%AjGxzipg!~Ih9b5Es7F9rKiwP!en|}VB zU5JH!zNqjm&7GH;hgJs*2C*-C+XUx3ALX@Spc|lEP??wb$nAW9&~!*URU2f4IJFSn zzC9v!<2C8?^XOk30-5>rD0667n8IeHZqKRjZv9M)mjW&;ye42VcYcgs9UF zSx=(QoN-+I;!(X*KQi-KN?2Qr=`no+bDl2h*<|ke4*7nt%%|GvS&LDx9lj|-W*w1q zb%|1zt>lnh=RaL}l>YU^Qm9i2yIQET3EA4Zy1(fOg+8hk@vOg@r$f>DMfxwE3h{&J zu4`NPOw8@gdue9Cq3nJLl&$|JSGD(b4NOwWZ9XYEcpY($RI*f=R8Mf%*z8I&8_JKi zFtllMzf{Qlu|WpBwl6r5g`Mi0eaH#i3!NZrS7*tnarE%`rRS4zCJ5#+djli`&3EqH z@#ujtO6TK#1oz_Wgxlea9uit5oFzn^n+_$NT{&&2nPJ~HR&yXx@kd6?zX_mIdc?KY zmbbJMW(zi*e}30T_YF(~qX5NnrEPZJB+lVI{6tcXs1tQ)%R#+R=;12*GEjHCvPZ%E z1m@P)9dqHb{UuXDx+>0Jb@kpZ!gs%Uw)DEs-gb90@j9(HbiVJ!r6m=%4D7SUOqw%g z1`hQ`S@on46(T7J5{oE@_lVLKBa)>!FRu+}g(zR;x&?@T^;Rp zo>*o5y}r73{0oQ~5g0U+!7Eo+S4+#wXChvKX0TmUJZJ{2KwIrpz z`QrsqS|0@E_ttok{r9NLelxo$&5=IrMw;$=nRZ@}3~2&0qK9jbuXoPv)!<;{}xH>(!qNcMNb>o@m0QB849DLqw_#P z)(^yQ-(J6uHrDF{n=r=hfT1}jC9hnqIdSTC?xw2o_jH8pautg)CTU&QAd>40KM}#R zaluwzvc-Afa%PPL1R_O960Bd}ZMpz~wW{P7#GDAf>MwlwM<*S=E7=rYC-{;uTl8m_ zAR3-O*O!Zhif$N7;nqmHD@%Z&kE_ldC2h}(8DX4pAxspWP11T?CTE%yo3gBFrDo-ZCJO@&%^1bfDO)QFEruHEeI zeJL@JH$7jJSs0M`Zptzl&I!xa^P8UCtjt?})`+o}U9Q~Bx1=O74QuA zqn46nGhe~j5O4Zh(zx-uh;1=mQ_3AO6?=B%Tvb?;O<}~kn;RRu1+VI}w{>zPYIYWH z#U~~@@lEL_nsB{8b#zLO{p>Xw7VVXa5?mln_JFMrlS#l|2eh zH>K-`hJqCC$t8444GI(Y+j#;3}k{&H&6D2T;b69JdqyJIEooq=4AFz*;ic3oVT#-{$44F->(T$7F#oAKsX7ALsS8^?vP&Sr{W9!e= zSu2J4D?rDnCpV9_3&BGuItq0BzX|#h5*TkuNNo1Nx=Cc9Jli`v20ca3bpMoloW;9@ z(;gP-Cit=t`6JFT4x&fFf-)DW~L^_o1*TXl7V)I zC*AQUk5`b+xG3247th_uDk$hAAtBic0s$isF{>K1K$(D0g3my#c9~&T7GK3Ng z%kV0_4{q$R&K*~do*s!SYHQ1Ix7lj!ljs$Irjrsf-E=nMoV~7`kiP_O`~x#Uw#zgn z;aQEj#wb4;h#C2B33%eM}Q_5+U(LwANx zeX8i<%^NrJD=KcP-x6jdpY68>ty`BbUj}lRk7e>%s)XWn$Hsy`Y?3Ha%Iu6t#=0x` zwRW*3w9LeS^J$eOA(hygE^zV;L?qg(Wr{X?>*6w^{}Mya=Hxwg>e_g+Os9*wYd6=b zKngy_Cc{c*aDwZM;!F+UIjk+lUWT%U>x>~$1aTSmo+?8!DNK_xo2#$(^eEmv5)dT< z4+R$$9vmGl1&Cp2czDgGAD}VoCr`QztKFs|J|?>9zi0l>hyAdMbF#Y|HEB}CWw zp|42^p_K^xb*~O_83J_I93A#0#);i6kEMGhXY#C!Z+?{ot**(^L+Z$O4LI zySzNM^dZo4X1N~}%J`q>Jz0T>R8ylR+~hUh(!1k);1Donqo(?fr)M>VI#CRp#`P5a z5I<;BQ?3b0&(Vl;{(4((ZmxvJBT-t2K`FG;OsnKb%rdDMSMyuR!O1!+6KJ!_z$s>d9+_Yzts_qCJd8MX=%NSG23en8KqP)Uo z*lH{rYzz-_7FOMlk5jT5vBs<-E0}?NJ3c9?Y-;MEw|=UnnW?F%u%O@sPtxOi8kz2q zkN?Ji!v`$k1Q2m!gFA^7zu#C&#A`T`1*}RlTMU0?&4BCtTw7(-j1J)ED|CYH(^tC0 z8KdCPmItF76osWVFH3S3-lvVc7Aj3PX;6O|*Zb=WuvTVKd3I_|UOG>5N)(UK<-aFB zS(BI+3vRY41KG?NM23JIbq|{TIx(>nT&`TTY?Y!ZA)ZA3Ut3NHLZ`;K@_jk{f{L9Y zAm$ky8uBcMbGDckTvkjpDz}$ydo z(C}v+81xCjGZJq?qX~+zb#60R?0TSPHCUd>Ny2=`zl-PxhI2>f^1RgHq9cL|NZ8#hvJv;b_3-~{vZilb{{Z@{6BtE z9ha8FEJjZqEvpx2a@2$<_h@J5#Lfc{{mOeU&^tLqI~CCg=*K*ZJQLAf<#dj9^CHrQ z^k8wFVqF>*Q+Bd%-_%RohFLt_+G4g|E6d!@4qRyY*nNF2hWRbb`k&}cDwZfIo+MI2 zpgJD`8m5g(;1csLs!b1pYF$r>@0<32tQ&YB7X<*xRWe)MkBss|Em_8yW+%qZOb zwYWIg((;@mN~cfdmg&LnbS#uyc5^4-x=;p3^T!RMPIo58sbAAc?Z4h_%J((hvYMW@ ztfN|w5gM&_Hv`2gf4ft^?M_brV@|%Opokz7GqWbfQ@I0;jn8f=-+B_$@ViCzu(^y$<6pbva~ZEXu} zwmBl6cZ4YazU6ogAra3aPt*L-T8~Q+byKH;@aj;%3%caiHV?og$AO406mqp6|hH~{D>jzw{PFp*yy{v zS5YAC^_?!U*2)~CBmD2Vumd}YAo}v?$eWHk5sKc-Me<4E0@at>OG`^T^vq05l^ZP6 zxs{(#9PJRz=6G`1A3zN`isGrK3qg6TqvcZDkR=^hn^-Fz6HR+Q8I1(CS3B=vi03V| z9x>?F*3j0rv<0Kwy+AlLQ=@r(4rsh&tCUn!hT=u+cD04l?`NJwK zufF`jKC~nU<((fxJ`b**pP!joK1{crfA!6U_tkH@pEUgY^T&w_GwrxS9W&97sUtgD zzCu`_{dKdQiJ5tG0*&iFI@qrUk6tOvGA&#iS>V}+o%|RW9Tw47MJdyrU>#8&^~;ii zy1+%u8W3Zr_-M1s%el(?rWStjF8Q6mN#ERDp~-yHIYr#`>C^K={a-61Wk-nxx^+`q zkl1sDWp-nOn`7Q~qON%eSs@0`*Az{f$Gby7R0B)aw2zOEFD)!I0p+{Jt%a|FTn=J4 zK!gb2YxG=4=h^xg9lgjg>|t4M1~$cX{&g!DPlYqh4+}&>Csp~RDyypYg4aNi+^7X! zMC0hUH$MI$!Cs=|?Z@JT%KT41H9v_C`Wwsk6Z5d~Yhxm1nj!o;m^s>(RC45&vF!fS z{O?z+hV*V~rLj$8HD>-WF76F_*4ic%YvseI(y!lATWbHuoh@$>wt&ktU%j$<{J2x2 z;9dwE>hJGgWAJ8CUG~??=Ege+J93A#B@(B`F&OweU;*q3L1j> zjW% z$mr-s5p%b*-Zgf$%usSg55x6`hMa`OGe4>x3Ez1uXk~7`Jfz5;vak5w3k+3Q_eCea zFCKlDo7j$4n+>=xUY%R(K+=w9&bj= z_lW#HOb!pfNt#J{%IlWx(CK=<#QF?fLdZaW|FZW-#|!r~J8#k@#FJevoOw_Fe{fpQ zh}VeqLzL64N>ltO?MB}hfP%EdNqAYEXKPUZ$jEw@g63Qa)&(<16F1f0*EemHx1$U6 zKzlihRy%G?7&OCv)2F+~X*rsg6|IbjAD6Bw^a|>1{hCpFm;<08BM~Ysi}Eyipvphn5T|}#Kdc4z&U?j zmxd3KY9bpto>S@0Y1=YvsJp<&RrVY2p3j0WPC;qc{R;SR_bUOBQc7hT)I< zH5$^I@hsV(M`A>n;ADNI6snLNq8ObNADX<5cdgNS;6W=kPb@_o8DAMS zX^qc3QI#K+7JW=+cZ=)#YIh2Ze#K?D-AUuZb1(ohOJKt6D42s&f0cBGFzits_U_Ky z9CqQ?udRV>EMjG@hsVg~UejZJ5AKg`6MTn3DY3+7e*;E|xe}nc7bY$)Uh^s#7EChK z>A9af7V@0_5Wr|eo+!!VF*mzH`}Y$L&mZnfaxZaPdpiy^lo1RJ4HboikTau^7br{Y zFEBA}T+_1}@omQ^nvxt4U;?y39VrUxAf1X9&vUp{dE^NtOUMxgDTA9VlYfb*e|$Su zMv`71XSNw|8_Ba26rN-2;Qo1V+hrj@u3N$^UoCT9Fn+#r_&S!#l2A$HA9e32e>$e^ z$TBj`8Q1L#xyZa8;bK0UC_K;NYe}DMB3rT~)p)$V{~#k$4PPJrW?Bd_C{7hdFiYSz zH6bxkm+g6eON;y%NoraeN^Js}FL3_Q$w@9ixQH+?HOOsjm&}ceHK!G$HB-5uq)ZfW z=ySPGr+A9b*n}9%X3}jQKHh&>;IV5t3``o&C57YHp)eqdw03mt0mKHq2}lTRJUoWW z2rO)Eb5m44A@D#V<2C_`jn=Ju3{bFnO}16QIMoq_AXC@E09Cl%j<^`b;RgA>qXTJg z_xJx!hjE{~e46-0ODdm$z>Y8rR`+@PG#^vM4)p|pG{QG-%$SvlOEZXH#rtvSB}%~g zm!NBE#1EV+F_?+o$!|}42vdt=f=XNPp$u#wU;{R8H*eve@NeRXi$M@NK(?c}l$DjO zy}U;AAex^{1ikAXft=H*7-Y%UTc12UX2O3%xJWy@yB*GFBbvXLf`k{`eB;$KPl_DY z44=juVWqfLJe7(hT~04%VY*6=Pp{a)7RfTt5_ zXy>cahbESBlYp3AqaXz&B#XKQ-^KH?Zc2(%;@(%Xm29|1P_xz30srs+*dzcFOvwRY zx+Nx743a&7|BLqaJP%&Z4dv3YV70-uJiGlLjdzah$^MjY9x@TZft{x#W>@4f$bdE* z5T5U|iE6@IcLok0#uSVEFF+?{L73uzLD>N!4T6Go)3Gx}=&7hgRD1mCYJWCWuNb!A zAb$4naeK(S`}%fjdmwULC(fS@+#9p^%+H!YC(lJEzNKSx3)8gmKQen=s${5K&M$fK z|DvFAZ-|g0tei=qY*<+-;N#`pqGRFY1j85`Jakr`Kc|{sT-;y{kqfAhfELf6gW#(wX8Y`W2{G(pLlg4=ft!V7RoJibjtRlTEe#CVF4(Ze>GS`wQ~1h-18%zj zq^UU*ghlf5^T%Peii?Z;!My-x-@bj@XH!b^KHG@*9v`04BA{pl*N>0Xz$C;^yQ&jI zQ2ey7yPrbyJFNT_=-N9Y+CvZD#2uhIOS`1s!T-3BCdPM>ewji4YK0{X!(*xdAV-38rae za?1z`2|d7NC6=hq0Yyi6SMnh_7ogH!lMcGiELFc8H`_~C0)%*bHMfuIK+?-je3H8C zNC4CH73!+>=J2G$woB*}0uz!6|hPR`C`CgV~F`};7VjDX< zaMxuVFf1KJ4&1Zv?qO*fixi9SCihS{{2O!hK{9OO7YD%1Y|GiS+KCDKt>6B$HTAfV z2(t3Mr|S$yLElmd#L}DvRdI^{{W!!O0%C4)uU&IyagTfeutESaOp-O|1F}(VGqZQz z*`d-ua*iC@_)9{p0u==1kqplf2Q!nrHl4*7!nUuV;Pk*u_A8_~LiB2gRq&828HOYD z8f;A>|NVCOECXyu2C*D)_4m=hLFs90=L1Xee*O@+L%_F!AV+VYU{P8713r6zm#?x{NT36$R9YQ*74?x?C5ivP~pz}AW70P3Rb!Bq>; z3jj*j=3l;i*`JnSyAL$ZUN#mMu7gr5w#TN(LTI@OxSi>bP%u3H)sRL$j>dV8U0eCW zX^$sbd>L?%`_io!5x%&yhJT~u@1oUN5|nYoK~8q|mL7`NZy*P_M37Fq=f8Ry`d;Md z7eM|=s+qwkXVCyD*|oH@+l2D0T|C|`97M}m)DfrupTEws96$&L2MFJ~Wp(Y^HK!*} zzDq;n2DX1sDN0l!dthwOn`y#>%Ha46+&7RKq5WGA3W~>K(ZWNA;UzKqaBgiQk-Dh2_ZEf2Cf%-T;ysoja(b~kMzTG5EY-_~El^FjbF>J}JT;RU5 z8c|s>rcDBcFr{hDwIW+Ggy!c_lZ%HB6u}Be89|MKBLx7d*lS5jZ2!>Es%K?HL`2@m z#_sO>G_}kxW888ew9Wd{1O^7~EACGTj4&pgM##?rKKP5h?Ces-Kd8q376A(AF-+Xu zhX56A4Ztn)t98(Qw6<1kL=*gJLAbH#$g?D~5ra7!9`^9M7C?)GsdB|81vBk=Tw)-k zD77C|{s7NOs@Xl4IQ10oGZ4~*+bOvq1tF*?E&a)(JyXyn%lZ5IwX52++5P?f`S&hQ z+WDVI5KPKj@Zc~=lGc`nKA%QHDKNQ zDh8LycxKLK)j<+E1aO%Qh}bpkB?_vRKLhAITl(4uLD$PthNfzx=NG+W|7Am(q1yo3 z@_tP=Mbtb&!D&yPJc+9ZW%*k?va;vZypZ%-1#kWzR-qj?8I;t>+UmF-V2p{6lDQIo zz&`hGUP(HFVK90GC7knn3HGbQ)z~%8U&!F^>9Xy}n2@ZHnqPo~dF|$VYUtse1|)~q zonr>6hA(-NoAGJpLfl|srU?p*%vfmZ?|&T@5wW8-G1v0X3b7^!^ICqv)~?{Vfu0|< zId1oCwANkh`DLfgfV9DrgB)4Z@rizKLF~xID!wZ{qRMPXll6P2bS~MP~I6 z46G~+cE>3-nZwA$0VRMd*|LUsdvin_hoLkGmj8%6rD0lWsL_Wn2$3v2>Q?={s&`d$M4T5!d(+o!k(FGP^v7w*5G%EhOXGN|p?$ zd1KW>@92rCZBH4XsdI8jLNs{Nx}G_9AI3FATOgKzBz<6UF*m6i``K8u*X_^mG;j>I z2eP#BhU|lL$_l7@TC7;wDj%43=7lu>4OkzE^d@LNq66N8^}|B3$^e=ENOE>?crZUd zFaBVlv-5tnfT6aQa~XvWmrLe`v77j`32bNV$HiE*A zZ~J@Rl%7$uVv<%RAzO_iSHkw8D_y%I2xxmh%Y#JeuB z7@xLSbI^-a)X*RcP{z9V7}6KMpxrZg$()#a7#4u}OsCt;a4&)<8e@#Ys&k2Tjt}~L zntVLZd@dgpC3X}vaVSCQwc%#Y)0=K*kL)&v9oX%Q4HDC1IGzW|5P0|Kc8z@zqYw?- z79mr><(ln!f!dDMlDQHv0X@y8@ShkktRzW~5K=@I=>Q4`mk}D>>-^dckX3DIS=mkq z%z5Z)`;mG3z5{Z>r^M{E83=)OUM25~l{Ims zvp`(=zA8s<+oo6(>1g%&Ni5BmwAQxOM@u?Ntbp*`tba^r=oQAeJRkm4u z!3JL%7-t2MSS)~T=qMxcy-SZEg%v-%J>?njCprXga&9z}UvtP@$d}7MJ4Kn|+T)y+H-LE9q6ME~PhE#~YCiu^!( zu@Apzk%3Et!1x(Y%9khRpB`w{PvbvCgP>#?)N)wSv9afIVuyu8QBtJ|ede_g+H1X& zezes}vKK7)D)ovqnX|9ZW48($znUA&`ZwvJv607{5qyA$p3?%eT6zJ;!lM-cH+sPk18FKhbVZ5Pz%!X0sGK-~cQ#mQ z7E&qm%hECe-~zIBnZL(!Cag_>SeavSpgST_lSFJjeEDHwd+?!gr50CzTx?5z&uMw z#k5~nKMkE>MNIv;A~4A6fa+`oI(f0C>M@6m#3^2rT&%fbwz=zO5s%@-M>?#&V2@!j zYBFW7P^-9gH8ibF#gkkR`3bSkgS>>i6$$Qh_~v@y2s zXRm5w1SUjd!TuR_09Uk!wI{)#hcZ?!9y{If1ETI{N;Z-jX(kpHEm}Dp?Un`Ug`>KT z_hsnikBd>sg+v;e@cGWp=M;DMcURj%g{G$R!8*pzQJB{HieYiEQ;|f4af5M68+Gp3 zUEXY>1}!>bzTrIaGU7jbtD^d!Q@)i@$(MgX33qx#7nKzGFgDuH1bF&co@i{$ zYgi2Iwfv1$o?bD0-sJ>L^5Gcq>Elzg$d>FA0MpFqUfbQ>%`wv57JVc&92drU#GIWV zd_@RR{q^hDYwR;{CHofnHHcn@5-y#XO_390s`U_eKE@_bh-k5L@4f*&oUQl4&e+1V z_uiKc18p@7y5?tg^%Gxo*~tCA{YyXeyoD;V?ot`O{O*;+I%gOkgtAU;$gZw2mkv(Z zD~>9wc>CVwa_gz<2P+ZYTY?tUVKC!a50KOCxURwuV@wlJU9N03zCU?%s>G6gY91JA zxu$4qn6-NwX~d=!ccFBBLEh)g$@JH8*KpW7IsN28at&j#P^kK>lPqR$-|pZ61v|$5k(86eV6xxcg^vQtR^D(HLxoGY6mU z{Cqa6T7IY%P0BZs>0F~`!?~}TFAYjg_ra~f#FfBnj`yC+vF~ri7ZKylf=SB9t}4Rk z^X21wWrb)BRrT&&6K!ONHAzfdue>Lp)<>vR6~*nlMa*jqIfEp}z6+2VBShVPN}m1R zKo6j9=fD_(E4|XOfDG&v$NQyHWFnq11%*RaFpRWz_jgDpaS-7P2(mly_eM(QjIMWp zO=VG=uKtPdtZ=B7L_}$(jd$NHzkJ1mhBntu<*PTJ9{edVzXvg!8wTs0<+h7A8E!(1 z!gU+p**AlNWElL?KMbgfCzSX%n=16 z`JSsQn^ob&n8bt3sQ+ZjH&}|jA6ne|2XfwjvD(z}CUftbr1(|STQ_bjoA$gu(kf;M z;aqR&-E+qYidJw03zOm9*1|NF?4L_7=^ zE_iCgeS@EoY%1;YgbaES0hQ-7FiAAo1+S6;aBvIl<3}4eB0Bvj3gkmOX51Qr;Ho-+ zhsBMlLKs}hahpCXic3IM>G5}K^WTW`5CfKHCEzp6^8KysuEaQsGg z5X}rQI+ETk*YICrK6`iHlzIQ$#9z2PUL{HVk0sPH2dG2tgV0jb6E~R6{r<0lAciwi z`JHD5978-3fkNk6%8ZswacP^GCUDG2(;>f41k+V(g}Ar#Z;mqfH>L<$SYt!e9>Y%8 zAMu=NWHK-t$)Dv*sm)8IxppzTQh+UQWJv8yh7%MNyiekx6UWN-<_i8S|p}AXTY;>jD z%imD2AL*w9N7Z9^MD=?@OWlg1LJdfGoSdD>G&R0STxrC?OtDMAHrvh3R#oxqn8D%O zWh@Iy`xI(Goks)|&W=WPXq@09J0mTj{TO=!O6G=yL>U-QucxnH41_k`&o7x50d=A+ z5GnQoPLthqLg~mE1Ent514uwURH^~ptKF%qPoEc*MXQ?2F^4uN@i-s2c#42BED8;s z8sxz%jy@<6c3Zrc4;(wj+6|D5AH|R4EE^x_>BV#FQ=P4{pf{o$(b|HiVL^WOFY*R_ zrmr12SH7E*(<4v}^13Z5`nyRNOC&5L^kXP{_QpM%zQ6JA3Gvm~(AlM}i3v<5Lkxvb zIgBdDwrB4NpPOA6rXh#Q*=SM>9Aut4^pgcBUQITB+4t)Hzqigtr^3S9(=RoPNE4fmweG-oE&=fm7cB%Z5+;C{@Vb5b zb_w8Dfa!VlJboG8aHD3sno;5?VYVOyrP};d&5?*o!;3lVNm?TUecw+qf>_NvZDfo(YAf%JlZ|CQ2=7x_FY zvecXh@?9YJ+3uS7<1u}mA#>oH|EJ%Rms}7B$~&NNyIt!qTL(dA%>dq@tI2=t>2a?K zDT{rzpxVNTw}8~n+gG|t9ZM-JDr$)zfc7FgWH#6}$Ep~D zV>019kpruAk*o?RemFVx0&pB*U?Y*9o^B0Bv4bIRpe}lUZ22WVtPN|in5Quua`-)d z2r1H>hX(o|E@@~@YdKFg(Lp?G9?1F>WxGEUIsD8m^a&_W4dKU+M==q>NQhO#=tN%I{z9MTnj8X=(C?{AL+rYF^1!Hp`i)~7yl{XaFzLB)rt5d&z?Q& z5%H8*tLF)B)HM+G3P@*9G4cFU1*HM{?*+AzpHFUnskrhnR`J@KM_(D(93PTvnP22I zYJAR9{uyf2n2CKW`s!%oCDQ;&pYfkY0?{<@p|?ZkAXM!6Aeu9&zBRAa;lGtr#g0o9 ziLsI$gfdO4Qu*Jvw)&YBGp7c@wT9I$EA`aDpRPqs9MygidxQ{f^Q&l>8&(vVYd-;p z$}(r0+i{Ief2mM_*4-#v^txhk$F%2I84OeMsa5_D;Gihk!>y6S7NhW|kLO?X5!lZU zt%NZ0-1FIh;scU6Ac%PiGC&}I5War>A@D54Cn{ni$MEZnC?K@N40d&W=S*gglJE2S zNX$@}Ybo2S-<;y{@oeMc?S~iZZa{yqYpd4m)!#ZaOAiAOUi)mej#(0oNXaWvYMgt3 z3f+xseWaAdgp<`q5chBkkxP5lAzR>9q6xyD@;C;mCRM#P#n0)A^f5RxAhVve|BUm$12baQi9ghZh7yRj8Q-|VaP_bV&_1;pE+Aw zM@O)=rXz*sRNQmS2UKF-)!w-EWOAZ8nq0sidEVkN*}QtxCPK;e)+aovn@|Rq6xqE^ z4`IOJ7!AxM7cuhqh$L?lIV`@dsv1h7=#+^fcOLxl6?GmcW_p6209%O;f7{7uW&Q^H zI_+Oxh=>Pf6LE#<$cL5FB4QvYZcr5W^f9rsYcIA1)r`72U+;T$5Mo}91b7h-vK5Zx z0pIOOuZtP5XoE7;LjhbbWZ5QaCuRRnDo#VabR9c=s)wKd)Cb0+KYXZ^K^u!E>S}8* z^GVWb_cVlp+ukoQGOqh}yNDTngm?(yf7DV>(!1|^iwuSs#j8y2=oEQ&z-y3qcF_L8 zsw{cn+}FKL_7L=gA0vMfQ?2e6CSi*{IwVlI6jv5-Yfy!*%9DJI$A=ui`TIegKYY(T zaxlvdgrc2!$h~U7G}-`XhD(`w5aya`y6!|dl74!qD;fiEMe(G~S}iVVz_^MbTv9NY z(M{5&C1xD!G?b;4w<~)xrlA{NUVm-*SbXS0LMUph#)X{d2K5l{uW6In0HE}PJkSU^ z74p}Hv?QmcX|+MWA8Uw1Zd+;lrCwJ}2MkHk>d%zx6+E(-HN=nHw45pB9l+g- z?0#8pm=4tFU8sP@oGwRRkAyxaqdAot>cHjPQ6-&pSYA>JxvpzuV6fh#FS^ks7|H)0 zcQ+*vw_Fz%9<_-7>x5v6lG8UFYCvO;5-iisx>Vz5Jvi8<_WJohGX@Zf2_?@)9z@+` zs{Ep{1v{VhPF7D0Rw)?3YY?jIsqW7lA1)=NsT6w5+jrs0QG-nP#qc{R_7s!_x@)A7 zFt6=d&artt&Rq%$ihF697cTtX`2FxxYiek@z>sR+=%w%Vl=rnzaH~%!wmJPY@~0D_ zejHJ*x1L)4=Cy0$yjeE#hFs&vaKp(FiF_lkKSthE6J=vwMZv*jI}?G-9_x@2@(H&3 zYX^bNP53Z5ex8)e7`r?NR23A(pfW+u@9F8;J2vKhvuOQ1Vwvg)w(1a|XhCrFxK6qk zHa0r=#75KE;6ixzUh(ARwDQr5k40S58gdjg#Wc&|)0U7$@16fg*H?f=we?>Mg213S zAOjdkcSuVpT~bm*Bi$`2ND9)aNJ&c#Eu9h~7<7Y#pwcBNq2C^vLErcNf6v3ckN3GU zXU;i$|6={tTDu_Y#JR!pcZ0=xvo`I>Y$wSLuY7E6+P0j+EGZjh9{}jlIj9S@+7bY||n4i>7c4`fjAQoc_ zY3p57%f=;~H`a9gh-pUp2dwAkuQbC8-{nKDqbAGhSs=d3eP)R`l{NcYFlH!A_01fW z`koYe0|ff_%ii>cFk)=LVKjG`;cHNq%HG|3rt8stiS^h5G&o%kFy!~?%66ritEz_W zvcFtizl3I(;10b8@G0OsbZbm)XF|wvmMp5Ifo856Fo@-8iK-M@EKXtn*>Svl=3&63 zJ~1U$v=$H$u2k=_9aNP5`RG<@31ZLN;_Y&~tHyrII4DN>>lh~-jsy$}jJdB?yR=q0 zN4`CN`@(%=`X_VNH5xSJ%?u!K)%}a}r-Q@UBwWjPuSUQu*q~r;A>DTmnb=^Y)*SoT zLbmPgm-Y@_vztzwE8ffu%r!5L1~*f=oM`*4uLn%#GV2GjeLW23>zuk68DF%vkvjJ7 zuwW+F(-X1!6&d)7&E1vj=B|G}M)L&_(#Ub?3zqZEpkD{vRTA|=;3`=S_!b6L0oE{h zh0s;T)1_Ji(DFSH>nU>8^SStM^4Ig1*R?k~U=WqC=m=_-X@CNi)0)KfndWETeI31E z!jJX8QyW6rJ4wwyGDsb{&e;Cy`rJzu&imGTg%ev4E}(8=^6+C*{v$%<$G2QTQt7EJ zr!Sy-pb}Dm`5Js59UWcU@crFza=iUU&nD_F1%m8G$k@t~^il6`g|P#z?5e8Z;yR|) ziGa`Bx=q&u9!ySLb2X!vD7k3a(urT%U()46bsXK84$Oi;dDI zCfTLRyYtZ^hey6glQXs^Y*s1vDqNZkah3uUYqJP_mk|}MlBslh4RCl_ZEu!x$9t(( zjr;fpm@wCBACl^Jmo9iA?zo|5!pXN=zMP3{06kRPCoPq8|nX zV0V+i+2!HG-_JlpRSO{z7+t6NYR(E8Oqk+c-bTvj-rdWpVXDRA%Tu55;fH6^n_b&6x5xq-TTMQ6#(?SuK{yY|c3ra`O z?ILl&LiMeRQj$z%DG7=GpsPS~qyKrj(aH@*PkosPQTst#Q`5rEj&T2`)2Mu9PyE}S z@hztbcwyHe00R$=OT#biTz!M+MCp1dmF+O={o)kpPn>!N2I5M|a${@&=gFpFZ$dq+ zAtxtiLYQP8-JS^H<}$UANeC^s< zDgCC7Yx?=dj$Oc1-)6@5cN1WF)NOOwmDK022%*uSASCN;ll<)_s&9m2bSHi?7r`M@ z57XhMhrg&VFSop9AUzd&a$)pWb}JkaqJ5BN#^7Kw+6R3|6_wb~6;pF>KMg3)3bkT+ zv4y`cEIiII2JC?$XFY=*E4+u-;b#z1JQ!H{HeaC@_0e2?>DGqc;Wo(xiwC(IAjeW?{{q)%lVG9+8wK0iwCZG}|OC-_>r z+1&ZAQ~Zlv%V@oh-SEqZ8flhtnK8p|-ELt`R{}1+7l6gx4OFz1v9H_ z&y|zdO{U6}m6YV4Ecnvu349b3a%O;zjP%$!JAd?kZ?Hv5>C!4z!RXTFkFEis`O+9c zS|Xt8)C`h+BD?|)$;dS!hZkmCbmv{ye)k7b22eJ(i;qO>1$deAtkD^%z5TAPJDkC- z2cP6<03x~lU*uVjiKf&}=qz`oKSHiUJkvq56U#ASEfV zi2=oY>E{C7RQ!8+gD-&0t3ze#Lg7tKI#o7=Tc%+y;xRxx4%T?5kRNqipS&FJ7 zdakmcbL=Dm%b`%($k|_A3jN7xYiD8We*3R&2deABWCKQ+^6{;&wZy*F@hOQS%ev7)J%*lz>h z5;szW{~Rh0dH^W!!@p>1OV?H&1v1|>%qz!3_Cx-!fl!qZU&sMHhyP=wLHs(TW4S2% zuI-dQq2^OTw2?-j{$2TEy!~nYDe%&`Z96-IJ{kro-LU-h?+q+!*_fEL0~Q<*>t#ap z$NGYzkrG_pZpJhE-~v-d*%M|3OE?tia1qP_%f}r7B(9k6AjI2bdw!Q75_}4dvflk8 zx*45w-Q-fpv@2kKiqNq{eMUwyQXsfJZL)g${ME~WCN!D1z%fW^ukezrjqaHDPXZCE zoUp<`PLThLha=mI`z?EdnRuj&u~>7l@@#75MlTjKrrb>fBON3y+pm4ncyHS&^5_I zOxOfHDm4rvxh{X1+Zl4$J3)6C>5{t5r%1PA@VO=R%EY||KJEwUZWRA9pjg}CIW?dF zp>x33=Hm6!l(N7a)4Sk(YX{J2K`pcmV^J>_Cza*NR&VOzeWp%&7mf3t!@$ET796L?GDUBrT1&wFn~<-nmidY5d(=byJiQBT0sN}T z5>vgm2nzb21S&vT*)TSXdD9-=MNO7x?!GL1HW*W8!-TvBg}!zU(xpHr@upg$F~IE} zyzyDHNYePYVDu8TInZM!+~@Kck2Tpo?1nxvK=tiN=psWM9}1}2q7q)ZLlgSQ9`+%d zSO>Dk(Tx$$obAl#qeN5T0gA64-tzNj-DP#wQ_@OlbI!x5WJScU1yC6|u8mzoe4FP` zLZbpmyb_7*eV_;L!FHz+RV?-DW@xb{>-Yhre!bI}N|T)nSL68x6p7LnS=zyG0WpOd z<3T2T-t=sYiI5V7)gT=iz!YVZt^vFSBn-DN299>w&uM^vPdQsGrvNCps6EN-Y95sE`ec3pEHEA zQMsoL`j0Qdk0CSy2Yz<|n>Y)p)CF)Az_^g^)dt@3aApwc*MZ$0}loc~ZpnU|n8geX9V7uPl5TyxNU1x^c4SRgcH{MPzMft6z#JE=7{>UJ3B+* zoqh$nt}8a+;AYTarX(hAVuS;En{R~LQu>oE)K~`1453tJ0+(eryU&60QbD{W8!M}=KM~Ky&hF%mhHda&+~$Vce!4J$n*xwG_{JG9?7P0< z=~M0rgVn|P$&6s%32>q(!UH+;8wEr9sZWMKGYm-+sH?LAELS930Klg}t_^6H-NbC_v;XQsz?(jvc+xtG?W0qW8}gk>DB(a2B(& z+%G>lZEG{!u!&Vc^S8%vFuZWIUo0ACb~Fo7yFtoMz|qzsK<>{z$dAS;&-u&2 zfP(>&m$S3<3@K0ntWq{nu#CN1#O=Dpsg$tc%fJ5Tvhge}HA^3+ZbzK9H~z^a%Cce= z^gyxQMeVHO!p-7b-B36^`{<)7#Qw#%L2TBY2ilsv5*tko3EL*`O~ZU_A#kkuqNUWf z;L|UD&L2SxpfF+C@}?#`V1M0AE=&K6vq}%S#@IxMMp$nU00UBexR3M&G=%{DBt!+k zHh!*_zJEGFp1lfK>X|J8z$ioe)qs>cA*Dm1jrQc^M;)%D8ol+U0NBsR{cje2iH(d* zkyTf3zi=}d7$ZjXX~F-oPs!&&vYM`6zutVQtEVRlKP>Gh6i}r*%>a{`Z?$NJH zF2`J8fDTUR$@L40YWhFFQtVMvgyz|%^i==@;TJDR3@&AXBhvtr4$zVA*5t1F{#qD% zSi&ZQl-;Y`+7#5RK8$Xf8GTT!jO2>Sy%YK6Wc~Y?X=x(Xl#R&BF*Ew6FQ+&uJx!&)p9c4ng8nI)3T{N+xI34=PB&8Cr(@ z5tC*YQFa;=&^|n$s&QO7^_2ioL2n}&nG&6jxgcJ?r?wuirjwJ!*9BDeoexxmJ^pXm z{q9MZt5|?`TC{ktG%5;$cL8)ZnqOF~!0-q#8s;3F>t2>t<`{My9MsYg;fce1`;z`X zXw<3_Eer5HkNUH+21eC{$I)J~RrNQ({Y-Is^pzcIYG=pxAENs^#|rXI3;ilRKEHl` z^6^XuvYw*U^kBW9i2Tx5TkBIoe~?U}nAg->-_c9Ag%=Z09IG1}K_!*{W3;0q=yC}d zZ5%0g0M`OwUSO~-ck{oq);a$MP>0rrlk}oHSR7JIFrhnn!#k-;dI88D((N8OI{p#d zyPgY`6ldR5cC5HXvpy#}mensfbMve46P3wm+v>%(>yIc9T3WK>Z+^wQ?Hs)5VMQ6sGMEVJKK6vgNVDgz2cBH$pkw@cs$w~q`Cnt-DPb2V(% z*4EY&nRYBq4AGOsvufrJDUwfMc7Iy{1x6}kq^>%ELmq&r^JuG+;^gGb$(jQQxYmU> zkA&{$*gA+e2$z|N&*AG&)s<2$&`_S;zM&c4-aBuE^C(wLB@b%#}AIUgQgFCSJGz`+H!g>T89=>fqB7HcvPoc_v z%iXx*hp*jSKP8FN8ozy3NTgG}j7#m7| zzlbT>6U4{GCzMd_Ten96fxl9vy4}wGC4hL1@9teYpxWIs=})94BuKDcF}RU_im&-E zlXjU`lz2~smj0*$+#b-umw|>Ez!(5!O6-_-qES~lIZD2N_6|;GG0Iml^_cP_PFfgG zW0l7q5Z|xbVc=Kcgw}@R z7|GL83tMIy0@`qE6Z?jo>4H87%>w3Cfzf3ei|f~~rlfpCqS!&KKiEAoN2nD`R6Amt zypKkjfB*6V@gp-h3BZjAk@Y5Q7}?9_X3M%;{Y8yR-s-w=(5IF5gZnRit46#XE^i261kwXnJ?3&Q~T8E zAP2QV^dlA*7afbGmw(SP%%QCd{94)}VBoA?Y>X5nTH|E-Sp#;FO%mT~J510gOQ)lK zqJsA{OIYiR+P$lMpr?0$$Bu|`oyywg&Uy3k+rwtMBt$gd?b{7}g(bb#?}7Fn^7z8S zBlRlO*wfz{DawiTisVEUZ|y)UQEd2x9lEo#GX^N>8`n#wzv$do+OspGTaYtY`0Tv= zIA-p*j{i^{hji+#ptT-sJu7TgM9gu@YBD$G$hEN|;bY{uf_E z^w1BXB}yvf0-9k6IVm#REbCb`4~&8-nic4(1DO#X6x=STPJs>@$UJ0>#N-u~1)AL$ zA@0trwY6w3fZV?llir;CoI-?UJUiqu^YQrbu$>p zKE#L##AVq-0#;$Kv!e&EtF2$;mwKj6jCHBHa39r_WauDajg>T$&!-{e4!8d-ezQ)X zhxb^-A4IMdhscgR8Q>94C7 zfVmM^1j+>nxFtyeyW8Tyci{70v9x40!&fXPaDGX>8xzR{fwH6_N?gJ2o7z(SPy=a#eZFDBp1^hwiE z|3-Z?Iz`9Na&2+3_K@hWa0ekSO3FigbJ!`0{bBy4WOE-kSJx!WS2V!5E6VGv;PV%u z&Tzg3kz~A>=?biSqN1ZWs_wywE>&kA1v0O9bcO#3^USh-6Qi(7ZnWkW6?XsR21mGP zagVu$1=2PtArn%?H)uNmW<)>-x|KOlSUP`Z2QXWLnFF{7)Rp;cNh1zyIlU}XQRrSx zc@0zj|D)T^pvQJ`0*ZScHFY-8N`!aWHw6>t|o#|n0} z0blHtK!-$~Hb%b&FG!%blQtGGsc=+-m8)BcuXP5LNm@yT4YXoM&mO%5Z{9Odsyi!Vwi;Gd!EpIop<2FawPze@xYXdMK9orywo5@mCOOgI0uxcM5$G*`bshL*4XUAXEwemedD_Msz80BE+6@#lP0ef%%rEMAL(|Jcmq=uprQrjZ1{fbRa8litDfqIP-Z+XD3b&hi4ON( zeEimY4e$!Ge+dANclPLocvi%EJGbHKBP#*wW2Z}y%V*v3-*0l6EhC%|B9B#Zcl+n@ zH(k>T?LkkV5vEYXl^~@Fz$ZG??$w+XFBa!vQOCH5da%H_h7&7bKIYv!X^J9c!@14P zKH&0I>MaBxS_U;~@30MV5jt`f$6V*K`!*QMLQsj{F&i|)*G2eI>d>L`T>+u zj)gN!wp&~CG8DOe^YzO80|Vk^S;SFjV~9;gl<42p$!V)_BQp#JF<7kgyo5rOs*n)a z$R1<*8O{6*6l7Kvg|Ps;Yi03$hYCiIOb97JU4AVgbetR=4XrN^0CCPyDo%xX(pAsv zDrd7pcS7ZyqJb7k=&y@ynXSDDt<3o=K%ao72aO=_ZQ|y)?Z0aq^(Rp&2v7wCu>kYo z){c;r3y+rkHzC!|xp{fFES?e-)!vIm)4W@}kv0HG*|cI3@b~WI zs4q1Pic-PV_$-q&`sd@-pMcS!^_YCbA2Xk`*o?ea!~;r8>@33$I~I*a38em`4ry=) zdTj4ue0b?1AZCNo3&{1G;j+UtTNtSDnURG>9UI~x2DtU>(E`LJ0CLTphq8gqMG*|d zj{tSt?WJ4QR%wW7{qqIx#E35XSGSv^e*HhbfjtyB9}!})@XT{F=6FxZmmYZwrdD@% zD}u2|4QQc#ooL3UT_?c;LdWiAOtAGc0x@AgsIQ!dnc7MeDeavoF4miISKEp=eD=|2 z6k&4>89u!)bNQfu_3Xm=5RC5CJ3!Vsph4+=wU%8KE2o;*2B6gK$tfw`IS})w(^7E@ zC{Ve@4*M@5+zw?75ELbktAWLQdZ{5K%SY#P;bZ#$y%N8F1}p@S_=7?zS)E+VM&XD) zXZ0vuQeL0qEt#W@-@hD?7#=B?oJG`wDH4%0M9Wt_BQvuVX@Bn|>+OB=?K@bERY>fYTh3L2W03yat1E@iAv$?jY7WiohL94L%7$8!+_Jr-h#;QpT8|O z6l$~i z7N!GniUVCj87AR>{x?sGUm&cz`MltpzkmPi7eiXADPv$7F--yD<`Bpnp4?+4isN)B zJf>i-FH>SKPvqo1ID_^j7o0;-J&8Hs`3q`F%+sGp+7=!Pd9$LJvaDEl(M}Q!LMR5I zB_9SJOR_hPix2X@kU#$SiSjiHr9mqX*k4THN+E|7P2iMy_Zg|q4#0LA{5%h&1#gb< zvRT~LKPL^Sb1~F?r~6HQ(;M~s7=&6fn4HBjW87mr@p5MGxdZdF8XAPm5VbB#svp#y zejPtDLukdNx&8h7_c7n9czSuMxj|lAQdMR^b-!@S2WBv%zIhoqbC#_JzEM;nk0mLJ z{HezEhr)q#`y^1s+qt;7w6a_$BP&~4T8f^bdgZY-Cq<+Ln2fXxzvmO0#W`ldS+L+3 zw&v)$u+@DX($l*{-smp1UzxGJJv*LMxh7PLvdHjAHHo=PRxCGcJlM@z;g^ zY#F=Ww7b%jqEhH9i(*~7=ck}!T9Ekir9$<+5M~k~i!l~3wYjHGn8e(ZDwOax(`b}+ z&&%%Lo22*i7B{Pp2Iu+`=Y6?>%L08IhxdE~e)=RO4GW24%8U!Awe=HFi_Ml0lmENR zO%Cj?Y?3$V3cLr!AX>|y8y2Nod-hB41Y z)ljmF)c9rt)+1AWkEH&*XudeG6RzLWT_8fgH7!mIK~kucGNC%hfU~VFYvkVXQ0rI% zLBwG|MepK$>9BWByjfXkal)rt32d7p2LCeoGDR(eqQI%asVTd3@4Y0c+^`CZ-fNT3 z3ye7*POzgk2zA*5ET}gZ8w(%)V1f!^sOtE;%0k<4Ey!Rh0G{~FUQ?!EpErO87}qFY z{hVb>vf}FQa^rN*n1iR7m9*n(kG?5?I=sN_W|K|=Q=Ty6N`Ngaok$}vACr)guNP@BY2dvZA6tN_f}Ki)-V9(f_gP|w zFo)C`)-?K@2!_&YQIL}>p4W$J+#LJQZy1sxr0agSl{8gmP|}r|Kaq`d<2QF-;3Z6*zf$POIt~F?=(V@1o!o2-*1Fr`tk`6YuP>1{0Pl1(H8nq& zXKE?XtY<|r{rPZk<3t)f$z@Tu(AO$s$9mls2BK4r$-9?dX#_P0;%qI3L_?{0oiDYFiNgQ^Or_;!rjC zGCK`LY|r@?(Q&}i34HC!gG;L0s2w7T^&OAn)T7Efr#wts(W#IdQ;55_V2PXax-O195zb0LD%i;2pF=$!%e2NtnV z|Hy!hfQ!VY$sPxrMnoE)o4iJ)pBiX;m6&$ubx+`%3vHVRz0}tA>X{HE4DG2w=r}t` zReg1x_~2}!k;a*VNQ@l$u{Q*c=)}$nPb66j!Dj>cRdo-dNH`E8RA>@*nxMkKwv41M zoIm|fSYb%M zALv@gfU&He=~fRgx+!Xxg2~i>sP>f^c5_d3ZOAaT;Iz;m+G~XATZ$!Z_kB_?Sgv}p zJf_z@-4M0Y?J}KqUq`UB8~6m{-L{`;wzKGYd5`b%I7=eC8rgV@U^cnz?YfuZ*W`Sj3@T0B8(9e=`zR2#_s?62C(4)) z7#bTYT5G#A-x)<-aqG=7mn%mMwQdr#hMeZn-#`_3PR+wGg)*zw_jmJDz3aykgE#iQ zPt(R$cLJ-1zpwh?GZCy6Y5O{KCzvA$+|O|LNhnam8RtU*$1;qpHsnB^W|9Uyex8T=)V5>UiwGw zE5cKqFUiN@Rq{ull=hOz$5hI0_NuGw6o^jf?e~2j^dzpZ_AVrDjKI^iT<-q&L7N%b5uzXLV#z;JH*1P=bcP{3(*4`}&Q^zfp4;uW!7C zQ7JH`)ZmShIAr9WcDLTVt=F&PIz^?!z%LJ=;*^J`2+rnqX`^~hK|H7u<%O~?3^0`b)Q9V+IW@C=<2)DHxmF0qD34O6`ES; zD?6F_w&wlr$}13Y^W0F;m6I>8CxM;ROszdy+2CAR$saFYPd@okZ+v-1b2TVMwcTeO zoJq`7h35rn2=#~zgcZ&g8=S5)o-|~LvMA#Id&4vsFIR)O?sK%cWVSK(+veiuV#byk zQ>jkSqqg?svvYh{ZNUWv1+*EIUH3uWiU*Z1yPbrVe@j5`s~-Ai*n8M*5H6!~k!+Er ze9CxU@o))y=biQG)Mkc3?4XUrU-RL&nq{-X@JZQ$zmyqbEUh=KLSkYkKklFUR%K+Gi{~nN8X~K`D!YkXV8zxM zqwxL}@dNV@3;0*l(#ja3@9I9a__^$!xm2RxARMMX>f=T(hPui~I=JzbUUeB_bYifi z#JFKE{fIiokmr21kO`J$Q*8jjWylf7q5q7sz`t+DP)M19o_-aSp3*YswT|{@WI?5351s zeq3obkZ^cbGlR-i)^An!w!^f7nja-ZO1(d}bgVU%H~lc%kaYihQ71NZg$j}X=3>%8eN}s}rZmL(*vm;3d+L6YTsk9WsPS#n->Rs%>aRgdX(Yum4Xe6`E{+XVF!?9= z$AN~YdQ!&!wUVH{ATJ5?m&A%&@k#_a@p>W8(V?wnkIIkn$|Qyu_Ep9%o~_LSNy2F<&ALsdga-R3KddU zVYX@p{|n>HWg=a+V)Wqv`({wV9%p%8Fn3;-?JU(_lRhWLh^c~gF+>(vTGTub#aHQw z)lVzV8huBB%RMJtao*sg>VvUO+o}wiKx~Avwuvd-L(r z8EN|PpuJJPv(#IBAH?86&zPLK1OuOPFhchNv!%!bK54+Z$)775^%jn+xUI?kPSLF{ z**I^Za{Y(Sv7cp+6sZ~<;ZEd1zQ4Ai@3xgYV1CP+y#IpsEjP~>Y*=ZyEVAw0d~Zq6 zSp{9Jb`|Y{1ALG+xd~}WHg0Yc!p`3oP zuH`G`Sn*2u-|rga&xQn-16sCtipuv)^>Bs@XtXI4%bV+ z>1nA{X{OD2Cb$zfzGR-vcPDAwHo5QF@l;ID-#b9D&BaWCg8InR>yB@|9O~&?Uhp3u zAE#xMs`M*!@wEOd2;rTq$u`gPbard2fV)&3QIgb{UDM{j(-x`k!`>sH!qxD*#Jqiw zE+y@Tyq(uK?RHC=t?PI!*B;$=u|2I)hN0j=@DA<#E!K0dw7mbdTG6X&R=H#x6afpl zHI^`we-;dF4L~IYHRbv@2eW%FzDy}^Ps^N(3uiiXh70vQ%`g@gl1d3@nrNf}+csOk zgc*uOBCKD#>tVeT7S7t}+hWu6&KfSHnNr~|H*Np3^g%tQ$;cb8!yT*Swg|q!`~W5~ zK_TzN{C`t`-?^mMP&lQIVbc`1)ap{vD=UG$^)6j^ndz`d4Y+AZxbyCT!2X(}myN~n zgQMrx4te+mcBaD_si406cr0Fs%G!O`kR?mxQHI9ZT@}TgBZq3YN-AuqY!hZZKlp?j zd>)73mG`h!xp>!vKKk|JVsOEg?>$k>4ZD8Zo>rx!0*tCQSBbqJM5}*vn~;Jf6xqro z{c7(ZTDw^2lKIv+XV!ptQ25P^N%SO*7Ylsy8zw&Ht%eW0Uh4}KTM=Zv(lUcRpzN;# zIG~W%o~=$?m3R`1Pp?Y)Sr8ae@{52`X^Cp7xSTh4m*G|X-9PnUa}^doDQF{d^o9cC z63zmxbH~lzD$^}a_y|H)FSaODl=Z_NxdiQpHGbi zyAkLb2>a9a=>^JTok!fkDWw_$6gbkEI$Ka`o^h54F7v9ZCU zr(svv^A}x@jPh`fCrO|RtfUu>!|gXJ7x&YiOtF{nFY|pU{T6oj6Kpk}!gQ?nWbnR7 z4xdpc68;d9Y76^DG~#nsMt!97ll5nXhOkhZNI7_QdrnMEZ>_?*nWgSyjBIC;7X_aS zbd%HSFKWozKJ6SHBO8hItn7`mC#Cb^9L*gsPtPL2Fmv0OwsVnFxPM)xwVk^4~Q;w`zVNLf^w(;4gsbsq=>doRZ_n0|D`umr~f8xDAtb|Pu2zhu49qlJXbtfKs4@~}CpK4I2E3zEX z??(X`!cwAbVfXv{-OoOTP2SIz7?%#J&M}O$?ZAckBxt4-4M3PjzpXpm_12AwQ6YSG zPw9)#VeLLWkZvAYZ^;(7CR3! zk~$xeZbp>etMz4V^V8L$goW>u0>Z*+6Lp{3EpMaZ)))uqV{OT-Q)SO`?p-{}xD4uK zLqs%4P< zTCq&xkplQKD|RsaSzUm$f_Ask&qsL(^WKjF5}TZxpp8|3Dd0>$&K)8VZ&tXQ&Q_(2 z`T~6T7+hXl*tqe#S@$)o8)!ss6>aXC!(OXXZc>_Hw}mCv+gV$Gc+lt(Yb+3Q9}Eiy z1qU1A*1|95pfgn8MI@x~q`v1AVE_rM%pS|J=w51Mt+Auy=DgF=b4uL~aNNza`I9aD z;ctS1Vhli)5!OjD?QUs6#H)%J(eQzo3S;L2}QF zDG&w`UIOJ2lL_|GKZ!sD^HVRljSvzorDw%$d2?gBg=6paI+VU5M!p3EKbA0qy@-mc z&HBi#al_rIBQX89Se3DZyfYuKhLW9$9QTAQA3GjP^-KkVcD>+n zy3+mQK1qG44_@vYzU_gO0U zW1?98l;cnk-EoO@&JYG$IZXck*mCMgyx49nDx;3v#wzPd)PgQbI>%H>c$!k4?0TnR zdcA?$mb%lscsYpo2f?nx`8A`{-P7-5Kg>|AzCGQ$Ridn5M^kuV?bY_b=;}!LxpDGD z^NU|Fu2RKlXH*?zfHQIji;ns21HM_M+~VxCWQhNC4FFhRg>!>cC`n?9oc|m$R#Fm3 zlHfC+w==$`@ zednnmhLKc%1Cg8N$Lh`?ScBedUwLb*yC4Do0z1~tw5qI{7ZqFLlQKpf0R9+Y>|S%v zbLlt>Fp<=L`2n@K@k@LNc0^*ahj~cYeQfc=FnZX8$`9Y~dX74-DYzEIj8k=1b5qAB8W%7Me1>6=B7G>o#*MERvEug=`htev)zo6pA*&bMU_1(fJ z!O4e;S2X*g$}g`mYA#e*_q_uyR}GJUzK)m6p-nTq29+e97tR5SiqFS8_UyHk*&W5Y zHF3C4$e`M9pn8B7&;F|Jyx5Swlcd6TjLH0wK<=^H-2JY zsq_a>)(rtkRd>;RSrrw24TY|>gwpF`TTwId&*8GDpGD>BTNu)2N(u_EK6v)K5;v)n z^73$-NcB71bFhD)rLtpIdBvY`1sy7pu@T_ogy1FmV;EyeUYw`v)luOh)h-&<*6?|0 z*?AD`CMiTH%Td)?Zqlh5xg-kx5H}Tmk;Jsn@SZu>DnnoaK!cYK(}cZ~1BpX;YR#j9 zW~pCm$BYL!LuJl7yLe_o=Voi9(d%|Reh0~&x70}L)e;*C zd*m-uo}D<+m2nk|5TMuh6lrcsO0mixy_fZu4d92yM;JT~KKCT7FW`jHG=G-gw9GIJ zx+mhXX?QIW3?NdQEhv~@hQMOKNT6|Q5)dgm#MRFl6v>QlxP9;av@mg!2q7VV5dJDa zp7?r01VH?eN*P=HZzH-|tjv91+P^fvv4gB}UH4+!KR>L|xr74b{9#u_O+)ot@;m(f z{Y@!0qtcU;tW>dyRdaW3s;hwLFuKe z+s*2mZ4g^gEYjHb0sP7#Y+4NVlAl6Mpx48S$V^|0I*NS?+5V9_Cn@$o{2K9-qCo3*c~okaqJdsoDb7gV+3)s>(o!R83zz-Gqf`}D_qW7| z?eO5W*f9UG=l0HaAnyw!+*-pC09U>ekb7Lr_WKHlF0>AL&U{?Y>0aIE@mhl zb%boXVkg$*l4GWG&@2XlhlPdAvZ=u1gAn~%$JU;-yEY8>(-g8{=V+Wday{-0$)3Is zJ0*Y(_&a^?la>W%I6TLk$7LS;{KfwK<}`zBlwC`ggzfn-U9#i(TPHi^R=@im`PV)% zH}s`U%ZLn-DATnRYW2n<0Y%js-_l$3gImHg)TF!?5&`4>_OdD2x}xa{FDY-LqU*42 z-ahd+6(4(1F?G&wSz)o-6{OFwz3#?yPXzi=acOYmtfb1_%=nG`NNbfrz@bZZ%UT>;U=YsOa}Jx-~- zfgwl?m8Hz5Jdd4(Kv`NE55h!XW6 zWhnz+H1^WSDsjAwAi(Onw{#3n?4$F?cDACarDVMCm+E&X-Y$Ym(on40CSCQj`IJ`T z57ZI6T$#*>sw)wu= z)>Q_pFb?i1=N1x9#t5;vDDq)+XJ)f4T}%|HErjWdKtC%IJWXQICt-{$p=J z#UW|<5@ZU-x6+~>q24Ww?PRWGS&->@T>AT|g7KKMNI){{J#F>Qd}PDs!#kQ4O82jR zF_%!28@G$+?0s@~eU0gnF78*FBFb7{FzP4%oHzgElg^CyzW!@9Pft&u+cO?&*GiuK zEmDD@&$%)hC~nO7m-uk(r@=D^JU8f$zExe8b4oEyU{Uf?PNhDu?Sl~&795H=;BRLD}>&B{*mvG6TtVPv<`moL~iNN_^iF%6c?GSx$)bmI7{9}X2r zZr~gd`BV}LJ^SE9sKxlK!+PVn4+FC5Oo?t;o>5BK&>1#93xXu{Eg_haF#d}DjhPzV z8vF6xmC>eo)2^EPhq8WQx$`EclFZ&pP2w2+`KOh9;&HOLX-{xAb&>2` zSm^6;uJ1vx-n954uhF8rzA8UfNh93IcU4Na$+=x>`RSn0k~-szMyjd8zA|Ya{#qRcsYjPsf%#JgRJ|y3gx01lH?NO>a}14&mRAM|!#E z+am8>_tbIAdqnLzG^_Va=LQbhLW)xIw@)htDQAPsGGQ!S4;p&P7)5i4Byk86uG@AR zK{>X#>>gc=_s*h9&6OzR1V_h$hid$$?6*&hl5a^G2e0}kVqLOl2+T0@)@k~YO_@tp z`pvd2p)&N`owZkMR6CCWrkXrQ8<;oqcsnvx#8()5i%|D(zZudZhigcoU-yvilC)Th z0H2`op#Ag4%~r#>B5! z^Kki~0gf-bO#Su46oXsD+rp%$?vejlEy*$fqWNA9?EU{xPC#+|@?0vly5Qw5b*K4v zk+cYpU&o>0*FKT221NI*R^pSojm4MN4|v{>7CI#VNq4|@1AFYvo8?a0!Jz1yn?EHQ z+-jy5T#D59a2EFaHzKT;!3#Rr`F z2+xtSP7~gS-4WZ_rk@LqRqpF@)tB2;R2N1Z}&SJ@Hm7CoZ&=2_& ztVHn%MHxlQk|}w_Apk+5rTp_|3~3M{MFa|4{vmTi1!_#2inGZXZjBY=w;&j{0h1vl zxEZ}339XXs8vz$CXXLFv8FMyCcF5|q(YY}c=>l1&Rr^4Io1hYip3%kF6 z?Z08j#J+?3ordxKgOzs={Cm*zN9wY1TaPC;bh%cZ&di`=4c%YEnt&Z5U z&$YI=WA&Ew=%HJskj0en6!TS94K*k{qFckxvhh$%Ikv*$3ikD+_g>XujpVLkZNUG| z#LLRMUzsoMR$!5(S1w3)>kYTNg>p zHW=R@g#;<}s+JEn*H#XSxEIMY%jH6rHe*Rm8y8n>wnYQnEf0vP;O++udAWCo=bu}Y zdAxjSC3stwv*&Y4L>T-p#C_L4dBIPb(mx|k#W&)Gq`H3yCMUL4eEOY7ajTfkCf4i$ zlUSK}%4%1|LdvM$!l)7rXM!MaEGXW>LRjDFed35?8PmP*c2|4b_Ns7PTysFq4?{MW z)nVJh!|2DJPALzKI)q3)BD7lNrgNcw9I982&QG3K!et=4bdNHf@L5EzsR6(0IK}lK zyMJ2XO(x7(Hvc8QuD(zx!^aj*cXTMh=m{$ioc-#gWzi{BcE*?(KV6F!GV=ijPsX z-tK_Hcm%2?HC@o1-shGBjQ|!2@dZpO^Nt4{d?un$`Bkpf(f7_nFt|l` z>Ts5RUH!+@RrX$v{%ZEDu)~jSR#Qz4-M!@>8#EsZQ&+A=ZAG}7K3Dw?$)#&8?_7#6 z%SuZ_)9hM);DI>oid#`T zTS!p>CP;3*Z;x?!O7T~9r>MpF%&RJ*p8XVhp-NKf5q zClMsI4tD+e=Ug#V2+Iyuy|)pDQb%1p{w<`sBq=bV2r`oMK>&bCqkM*4eQgf%Vyp_+ zBx<*vi#kDe9Tq#7Mj7ze`@8#XQ_vicjqra=yeLkP(oX0w?1)(+J ze||0HH~`Gy?RND1?|)N;g!6F~uP4908-tmotvF}~~733TviWX2lgHzHLvP^P_oN4=6QM#cGH#FnD!a*LI`!f!Z$?~{os={0{-Pf*``DqG zL9hSP8}TG68>0^Z9G=sBCCqXoKVmINoAT_Ny9CHZVn4Aw{{*3@kot-qVd zLk*U#MKzZW;;VJJcDn4~<_y?X!(RG{>izdZ)WslTW%%ap3Xo7zPr;Oy|F}nZ1XG28 zTF{zv4JovMlh;S7*8y*GmtP-(F|YT5i}v;!IY$qhDKq2%Wle#mlzqEfw9S9flI1O$ z9Q)*T9U{|+g*p;?v2lU5-2OxlMA$|G2-|kc;;X-N(KR~I7wb9mIfsm!^$kjkBVq9x zpESY(yeoqcjeFul#<%^3+;kiCXbppcoYWV0gL^cjE5fsk2c}Nz)N_dCD$mLL7*}?P z+(ono}cp^>r^_8cS%1wI!3u9AMG_>Zoq15|&GO#eR zE8Iy7A3t9o?PF}hvSNv3bQ#-t9|}^}T90fz|9qr1jrfZR%YRBy!=p9xOIz`E{DTJC z=}!5q9pJ&vAX0s=Y;y@vHtaLrzEh{Mw1lg5#L1#ktYg*Qz@FUW2g4W&5z=Z*$_(2n zh8&I${wI0wXMsCWH*o|Sm>0(ND^<84Ik2CNo2X;((q;Ah`7zkG*c5CV3wM9uu6iJ2 zah^Vv4RsUOyEN3!4G)djCX;byl2IqqT?WJ)AOW&4b+1Qh%pj$WojW~Wpu0Q4=?dHO z9aj@9`hNE(CV!z@93GMj_WFlc%Rjjw`5RBGhyOOe)R0;8x05WXcT7x1*!QU~?sKjZ zjsmT=Tmn4n^xAkC*5{oIHVM(&@8j-2TUZ&+KX>bnAJz+y+x$lkL`RANmjSNOMOU$- zZ>sl=Kaqg-(uKfTlPm9qM1R+Uo`<4<^-0MjWR&?>uvSlU@-Fh*X$1JA>W}LD$~JyE zt*br5=O(?iYkp=_KHui<(zGso@Z#pNe1`wf0sqbW{(*y)lp!DN@ssG5Z(6vKB_fcV z`tjS~eOr&(9?NsOg#nWR5yYzA;>aVl4UtVwG;9|M{yi^voU0gFd%C3$y*U2ADes8| zJSLaq34ufP!}h-2ubwadE(@iwcC193+0^Om%5+g+*jHo}W!FQ;tIfk<%Y4PZn`*=< zrWklR^uWrz+c%UmsfYT}u_R{2F7aPh04_@x9 z`uLl?nB~{|kk*w5;lZFX10?^QQ?EIKAQI5CV|jwMHc&26YfX9id-ZnrEGTWL%ed)Y zu);-Ehr~^D0I{bPI{JjYfZYijjYtva%Wr(wn9ax|v|b)gm975(R6hLfqE)`<)BX>d z{zk)z(>C}^*JH9sA{Xt<_tH&V%r{8OH=a?cHOu{^z8MlMXM3RT-eE-$=w0nVGf!b_Eeg*c!Ue+&#x%_89q} zsy7Tv(M4ZiN@NeXDSyh8yoS}7i9I!JXEQ?#9Cfa1nV9+lxMM5RsT$MI{ipZP1&57b z08X5rQi%H9dAL35@=Z`DcoHTLg&W)HS?5|tD9YY@h)u*}DZ-MSh2iGVS2nS_D$$_DyBlXH1(%MW(+LQa_f!N%n?iY*flt zy!iGrnX>q3KGw4)m|U9Z_{>Dh^k}ttrUJtbe(l;=FhZl+nQF=SG=8h&_%|6q;7K#> z;TqK6>YR>#RqBY0LljLfKKYCG0T+BwD5?-<>w+qdy#_j97Fq<_vP@kHr+e6I92(4> z;(7h}1H8`CQYCuccWCv}iwKMs7zUB;|CqxrhRiVXg=Mb*5?@@l>pP)V!pK51Dbk%% z4-nWfV4QO7R=n3H0zKMXiWOX%foHuJcFp-cdj6@N=YKk6QViI)-;GF>8WI#V-NSf8 zwib1HWI^pyLB8^@iomQ-d4*(E1PZ7IqG4n2-Tyh?(Pvmu`;5~cz)?uZ5KaS}0S@7= zGwstZTY>^^=rmX$IQVS*(2_c64G2q;u%)JS1+5LjSZnt{hZF_zud4JCi;GGY}7pf{Ij@?yAg>1mblg1%TTlbbfu z-SzB`Yb)#+X~m28o?zdk;up2?qsAM7jQ^Wd^0O%TH|OJ)c&-bmU~_9 z&KoY-_4UMl#K(bal;eNdC6oqC*G|t!zEfQNyw36Vl#iFzLhOQzfZi1>8GO4zpWgUw zdT;KVWH9!uQ*u=)cc;sU*#VcuS=58{yI$|Vjj`tE$%iT~+6KL7oO|erSGAFy?7Y-- z$3^?is_or?5L$!#`Qmn`OCa*+WGixihUiorc9;9}1nKou`GkIVln?*}LATq7d!4V@ z1lkzUmeLD84F2{y`}B-*bv+Eom2|Cpuhe^6{?4zVJf&(Ss)s#*SQ!IU^GW*?#sF(g zlyhI2b@siFM@!W2U;ZnH0dSQ#iqeZeO*QwuO?b_U8-%z?gp56b; z^P;3!Awtw-t?AD~SVKcSdwTUX*ogrr-CyAYZQ-`LS+sQ&g{=SecX^SAyBnt;q(;eh ze)6CVKt>IV>x^@|CXgu7^^=*x<|&uoa5H-!TtCic5D9FFDV^$JagnW9x|I%ozEqrv z?-GoY;Jj=t7C!YNGJ-tAyqLIMI(D<6P@{IL!HDmdu1Xjn8?S|j(w3>I9edN?NUep# z?s@LBgEl{jt?|y$uPCgYG6TzkKdFgLJpDiK31UnW1oV07GF>=v;t;+YcK%*A$WIAP zx8kSh7*mxO%#(+jOtlc$4tB4fRjGCJ|M?l6Cq38tuXaS*0w{)$xV@PF!(6XI2?+*K zy4J-!{0afDN=i*E(v(aS4GMJB?RQgkbqZBiS3`of^&Q>}C9}WGsw-{2|5A5zK+R}Z z?@{633x?08TYrko9Xz-*X2kX$Xf|GaD;xOJf(&$iUv94HDPcz&v_1jn$E5=apwTzU_vle)O>11#vY)9xqdkLv&UA!?I>S|>IC zsO{gW2Q|owORs^5EXgMfu@3#_TAsYRVnEA~Do`lnUQsen?U~B6EbaGeSF1C!fC!b6 z_pNWpd~=^#(1`mpJ8xRPKbfSb-h0>=2+q8=+}nK4^IrjbbT72Oy|01n3r-&@PQhbe z7mNgqne@^UAz-(G!zhQS)bM(FXqAy&bZ%)j!$kCps3@g(S@I%~2?LK)InFv*o2T5o zxNqebb1;3DrO;&2-4u)NGnEug&yWvhmCC>{KzoM$ZlXGRC(#^Tj?B}4A@EUutZ;e$ z$Ou(Y%TPi)(!Ool z@CV|gCQ`(T8I4jzJb+F$xw5)Rov&jSX@dOt=U@`Zbp3aaw3x&H681N&C^mGJ55SgA z0gd>t{!P8gd@2Q+l3jG#wlHUWN-D3UNDRHIw`%fP{A`(~Tc{GNL2zcPh251e$ATYC zTfRBy>-|f5O2K9eEucAG@-#X)@ge{%({9k3-dpL@$Y%;OWCLoLS4|r9y!-=MY&|$y z#VjF6W7UL0uVimfuEV_3%a9IST`j~R;%m{<{-qhV9%okWe&`c=U9iHqd)Kmus$g|@f^E|NTic(iuTwTAkrEC;>rnG@h#h~)f!E*=# zwH}9fX6hvdX_itNx4qf0jH5DS2lRekuVkmAA+%8HG0K^#seI#Rp<4L8(6>r<_g15a z81whE25$F4w6O1!zamZfOA~AHSooP_e7gQnl!XD5N7S7R0s75$Hyv*z!-Q@Q{TeHX zX^nP*@bgP|yq6@jf~s?TJ|cG21YY=CC6lWno$vM^mG?h>j%yb{uA%7Wt37q3ZP$0m z8bUij(z>Vi-0YDpM^y9*5(2++xj#iku3X7+Z_?%C!+IHVxr(`6|EclMe zu1x$ZDfmVQ#}Hh*LQ1KqJte)}AM~dhU*$cpL2ep?r|(|^DPi{+)GlERE~NeBXVuUaku zA{60L`1(0x8cYnHD%i)9n(B8E(7{GgJftT3OGbY-PNGrH2qGyeSkRzZutOvxoE7Y$ z{M)qIGY7X;NwlOh=5>^Uxu{L+y`taBHHP`u`c!7ZGCy{o`Sj9X?0Np1WS!$f|N71s z6Zd6Z&Vjgr68eMbyXL>+=81Hv9gMh3?I(qK3rrD}4!ouG7#$*DoC387YH$<-3R~&P z7o=up0Zmi16S$d=>fpXKhaHg<7Vlw3QkBkkEd5QA`D6xWC8fG{`_6>W;6*0mPWA45 za#~XxjrzYAnXn)fKV(h8>Us zOCxxB74#(anJ^Y%R0%SFI3B0Ms5`Vx`~2fuf1FwvZV-5bE^MAF7J_K02nY08{!Ud1mV3l#V?)VY@KJ={Jpy~w9l zP-i_n|Le{6d9Q`C5=uXVhI22I@#xF5(WEkmmEByBmb%D;56b^h#5rbgpgX1{vI5J# zEp5Z^32+HfciK&NKqToZevXI^QrbGoKk7M=vgu~;sFEYqzgN>2$nG$mj?}@N!N}I1 zhr-kD0G5P+W7rEseagyJ00{`8f1uLw%{%&UQ+xtFU7~~EA#e!C#mgh|2SAatK(=$7 z4-`ayNM$$)5N2fZ=a%~sR_1u^OzI6SMaNmBweVAiW&U?$psXrWoiu~pF6Vjw)Yv9r zN<#<)`lIL6#>>l)&PA@<57_NuqOez$0X2(A*n&#H(-L(PF5O4A!sC8;v{nvIatYO` zMz2SGE}&^%+)pz#ts!=w|C`1lS|gRWP#z-ci(e`cGB8RG?5UpT;!7guwZP(^IzQNl z*8=tg3pRVh-b5SDi+D>7FJ$)hzmPg$zlw6vGZKz=K&((q*Wo0Ah26Gs^v1OtBOX_# zH(T$AOl+=sxbtA?W7u0e=m_;`*zzaAefK9sSJc*!+l)h>djlA+N~Mqro)MTH>m03qFy_UF%z_YVMX=c4l2Q z1nd8&tSe!sgJ;2a&+2A<7oc%5-B@~4cADiBOjz&y3VjUcO46yQV6238u&1EfE#bCh z{cC!tteqnD38#&l&sr@=fuyUXGbA^N*U{c+WW^%2AN43xps3#VvyLNm>S48{wd2>0 z%bfpv_{M6$_*MKyLeCdwp!vSe9SG-^f?n+i+fz)CfjR?TdcCkZ;OHrfaKHJX~h-HCl^rfWs{gHP|ku?{Hvd;t7 zRJy;t&w2Usfkwh=b(zG+$t56Z@8AC~o)1Lghse~O!m~mGezuG5sx6f!_Mh)m#;{lM@oQZuQ>St21dX*ju=Co6E#HXl=%&_*A&$-Q}K|_Hu z{0t{ySwT+Z?tN0KY2!R3-I8u;p2tFb9h=y`Z)2@@lu zFfHBI9aY;;6sZ<*iGa)dQRA0@vGtILjO<$~jGl>>{MhZr8+R%e7OP0@zeRL{2KZkD za)z^g`u>s2mAW)>U?8zA{9?VQmD%>s3q52TnddT!_A#^NN0)v%{*~1{px~dy@xji= zETxb5P0x_{Nj&fI{K1Qe(vplvAm9PDoSsatrgzf4dYzRJCu}M}c^gx3;?bQ9(KHhp zcWsDR>#>f&d!M^kf_hAL6mR+W zUT&2>_&uc2JW}3ja;WF@QswV_2^dpIf?#QGi8z_g(7X{JA{zvrcXXFRY-VF*@$+a) z($1}9gvRY3b}WEE1YWf#aZtiNQRS~(M6oTr?WTzgTgXEXEEyI_V4R9nFs9?ke7X+3 zsK@_ztj2FaP|L2zHWEaJYEmMu8D&esT235)bs_H%s($|4IS!`)znxxdLG(^gPP9@yBo38rBX%9 z3xVG7&D(Y{wwI0Bq#-n=5+QYlflfFvec?{BeiRJLz*pk%>`KIIH9b>oKb2TQYF@T` z)zXg5vq?sF=fPWs?0&1s89miqZ|-dUxa!@#zMc%=?DO`r7oLP(>@<1X^ys@TkI2(? zr?s7$g+UY_?XRa(EdVc?vIvhyp$*?Jlafx_*2rME4UBcLEDe;CD2mI%=J&Cr7=8`w6l|x4|K26M(xLc2B->~5- z=wW#%t6(>myeqLX7R`Z`@F!lrdUSsS>km)MxKfS-h8A^4b zDq!$Xmu`M55&cE5G!be`Tm=4jsw)CQp`4O=EijYg7pl(XJ9Shu4g7V60Rivj8s_N7 ztE*nzm%8i#x$K(&kWXR<-img7T6a$0p02IX0xuw|A{U18vh;mDJjP9CM@VHR4MjZi zK4SY{GIt0%?}|@*F!g@_o~RKj!kIlpDr|YDtg5=aqeCtW3w>9x={{dFPr3Hr!Mz4@ zoTBDM#uOzV>D%dfB<7Yf*a&Z*(laHpfFII!NrH<^kYk5vBNJt)gS+#_xCjATsUmBcGNw3)wHPr_-J@+ zVhKnP(Ed{2=zB`MqG#Pn?vIFu7f@Q@Wc4XVSOnuq)iG_n;S;yDPvWhB#$e7i;MX7I zl29S4+XqI|g2Cy2h@35S!Y-e2qu>Zwowq&_yCtA} z`+Iw*TQ)EJ94S*fSkw`#wSTg=^Lfo$L8O0wgbtLnLmmvA?~VC=EBvhn%ee>uf%=$O zZTsWLhsS|?Kfitbb#PZYW#hVc?&^Mfxm|H59`%2-6sQ6BQiw z-akMyrUaXcgWBMWe)CQ3o#J0prFVR2;9f!~8NHcy8#DwY1B`0Iiua0U&#*7LBC{r( z8Q2$NuL~PcTQZHD@+vwjW*L8KO59nnP(jsLRUzR0z30(Up-AIa#PsZo#*`5xc31TZ zdD>!9YZM-xRr*AR%yj94$=N0~H?Zi-(^{t9>-5L2AJfiPFDyO=?7%)97E{kUEI+n| zDn*PW3bsh8-74=jw$`6|AAtGT@fsGq@5ttQp%0T$!teX~)*S!$-NofY1L7f63cd1M1 zw@n(OpRp>~Z9g=2w$GDhQU47%f$*Itvp#B8{oj-R1A;0*<`C9Xvq)U?Lb(tdL+QQL z+v?wu2ZrvsyIJyg$>ORsLRo+}EKYM7heSJtdGH==wm>gQdvZ&XKiD`eJ|8pS21 zEVBJYKTjHJKRfTPvF!5ioi0nLKCD}Zvy5Xe3Zi8OxI=3gUso9!QtTBb2!(fF@J32;P} zy+D+4Y%_3Emd-y2I?XMKu%$TYwR1Bcjt$0M1$4qS=D+ny(h11zq(n$$n2;9?hOw!rYv;n zgPQ>T$d4W_hH$1g#!@)RsF5?>kUn?$%!eQ`@FEz{Y)Uvw@t+3welPgGlggvbY8MYf za;p3QqQ$!u(7$AMnEJl&Z!H%&x`|V7(?;YsG;3ezE7W+`ZWW&dPn3mtZCZ*}(0Xld za{w7s3p+CRW7r!SE*!h`7^$##OxIrtoy^Pn%$>iP%}>vG9;0M^Uek_$+2j8cCfEakUL^J!9!8a5NrFcfj77+Z1Qe*#2qNBp85RLku$;@= zwIC{N+~tDX7X$V$#G{Wv(&zMAOY$^rgOz=$y7T<3#3E~Tm-S7oR zw=3$roglDL9Vj@%A(Th+LBbB1k=vd~0R<8WuGC&@2V zXAaB9Y1SG%=@GiG?_lHGS2IkOLnO3bD5RZ~5EXN=OOIjC4sq=<9k|>k9hyU5k?k7E zSJ(dD%NJ;?glnUy!c_mG4{Bp6$etKMj4*~*lI%8p9VY?Y??8G`0+^%DMgJFWSbr>i z7D*PBVcrBeqv&MX>NHl_TKgDB6_r|cW;D8GDkLG=E(tLv~%fa(m|ZNgj_Clvo+SpXLg4a+h5dAXx|~> z+A&)|ELT7w=a@{v$OUq5b#Uy13-u>;VmDZN6?->;qGH=8R#^C6-d+AOBDX@9yd8os z?T#9uU{ov;DiTSS_vUInF~IloqUp9D{p6?le4ZVdA1*%&8Ar2iN~6V1#_o%ZUJ2wq zuvVZ~fGB`DYc!v2O{rwo^=r-gWOZC*bW`^Nob$Ovn=Nih`Cr`Md4PI`Rgp62K}U*k ztwMNTOf;sXRvzq-BWvBoUk@VI_d5RBbP9do_HZnn+11lmH^!kZ7tr*m=#9b5GDPrvQ|ngX;!7*`BZ@y?f>4aVtLx1}cC!LJ6Sfi{7Q z_ZY|-{2uc8qkF*Zzlg_ex|k|-aIorCT6jgHwa{A3DPC$Pj?nuK^i7m?FM)k*@J*g3 z*@OO^;kT3R%cOjwd&uQ=zxB|5^k75mje!QDf6we_zkBDefZdCvVq*4W{9?L;0#y&* zB|&7)gdf15diJ3eo4@a91?>j^sw4)a@-@#iFf=6+g6ocoa4^>9c(Kw*dIkSObJ7NX zSH#v1W~Rf;W$*0?Q2ro&8yYQR0>6C3CDdxIkW;Nt$vsu-UmyY4%wdHex#U}~g>=Tf zz>dZ<3Dk!l?1&)6K|ZayNb%-xx;Hx+5}Bf)iqfLN{Sj92+DvStbiJHjllpo?fs!=* z*;`P1R8;*9AsebG-^O}0WV{+DEWce3N_6n#=4Y;DJ?!!A#eY-#Bsq%yB*q6xMjcsp z=ZZa2Wui7KV4(lB%iEJqNO)96BSdMelS(smDS>&XICQA3tWDM4&&ToSjAW4raOgU| ze}CCHvKT!5;wB$2Ujw>MOG}0CSxe|;zhQqi5Ub*a*%y9A_H%?YKwI)p-zET>+))aI zDKoQcky5*t}^I{c2#jiN=A)bp%Grh|k; zt%TLo8$B%ff(NWljQI>5(ITU=@2WR2e-VG6E7S&&8UrpVp=kBw$>B{`8T`0cK8q94 zOI0GW-HJ4iQD!JXqAtgrtRw;o?&=e|X=cQw_a(2pNqG9Km`Evyp+#vn~KI`{+2PBMpfBjT}M@`KR&^)y;pj zzxC<)%HWJRBdXpZl6h)xO7teP!QAUcR*hoiZrFjq`1<+C(MxN%h?eXVfk-y_=~D|Z z2OLUy1>2gO8@fIloqm>LON_sftBZ^FjoyH|-i&;SW93i8!Xw`24P{Ey;mm?+1;&zv zTA|x+)+rwA8TMY`piiER7mMz4h4lKv_^G5P1*RO%E1>7|I-}h9k-45C%Tck`$RdLx zL3P%u03O4XQK1af*`EH#oX)7z6BD%#cehfMJ$S<_zx2&4oKv!cE_uZ0x>rFq^dJ9B zIKDaSAOwEs|NVsgG}dOK=+(}?Em9DxFGEu|F^IP-# zzi8vKLDY_tGL&4dHwrg0S~8VS+qpopCOMJ}TSFl%h+xB66L@NgAX%(^UMuBu+0MKD zPlEhcZ-DVVfKj|{WWVEROYQ)O$$PhH=~1`Nu+G}C|KqWHP^?UIlhX2En-CntYZS%g zv0{a`B&H15#ePmK%$FfG5J6@5)M2xNL@xe1Rr)51Vzp_2S9n)<@nZu2;@GVNC~lD^ zKa-^3XTHzVHSMk|9?lJ+fc}Ix>9RpLFmu=ygAQ74c0V0MEx_|(ess~j0j`YeM?V@B z9@SXv0K(9Ij~*Xdd2=F?MsGD>dhm`t3N|&_t5DDMkv<*s@pHHC!Zac5IkzOBZkH!K zBuPi#{Fq>C^{6c2xMG$NQ-zSK#ibK8A0IL;LSoNMn4jCSPK_@CEhc(q)%-=&q(q_$ zV_mYtb>3B*qtbML&C>c&>uF;|rd3F4V4Aw?TxWY)5_Xix)liC`Bet+;dt{WHi7pSX zfJSj*WP;V%Sso3>{Ok_8?W+Ug%@BJZj;V$ZFCJ_Cedg1_!B_f1i-JOkCBci4HF!D1 z+&)eo8PZOz?=aPB-S%t`*=@+`4C!w@Pd@*zHy>aw#%E zN8?C)E_T|RVZ8*Uxe>eVz96R+M-kbC5@eY6T;t)BSx%Pbh0xTL(TRT5?Q;jAfnUR{ z-9{?ApOVQ6f_&d2yT5Uh$=nwstu%cuB@)mlZ+vocQxbs#83l{>&gDD;!c8;YLY3-6 zzkW9TQGTO%xv@LDtm)Yu!X5wc@xmS0rw~Dj#phBTgCG4@7a9zms+B!6Kb*}k9T&aP z`ok9bKCC==?Ri_H=XXApL3mxY?^`3E8(n)zW1Kd}SF-u~lKC?LtjeSLOnGl((mz z7S4XMQg}@W-Ges431Z&TS zTpBui>3Dn@_vhzuN}&j3iPnf=bFUzbRQTsn2n5=b9AKu#n4!>w6`SAM{G8FcO|T*4 z5=Y=0`}y+a$xC2-cYi(BqDNhO8n{sfMF$TbKKyDjYXxuG?G`+`XIPiQDDETk>J`sl zj7K&am%g4_+5Ld&+MJ9TofOCQ+kEkqasik94^{in9d80*4#^Y%^&_&OJ2&iJ0x!En ze3d}U!uj>()r8_Wi`SdHr3_)ufmkw;nWW$|=%5%f=>6+D#d&i-Acza4n!{J~kbxJ}b_jm|MtkI#Df?fzUoiP9GvI7g=^_S4K~rBcPP;}?T&)c~M(z5}>oXIad~|kmzNPDj8?A5rjAGOO z!pXHcK$0uj1LQ@raj%41_l3p>DN&wQ&k5n&c-l20GiAa-`P-@EX*_EutQ=L?1U=C8HW(Tns z04NUXbo$^qiBDd)+kuUCy+}`C9Sh{>MHO^9sh!jcQBf7$2%h_~o4AVwu8B14y02!8 z(Z<1t%aMn&PlH-^cEHRsMyRrrYW{`@0H`Dsh>I?uJ)?9hUN8c$5wuo5`Yj>x_Q+~u z_j9*xqoevQPRpsIQrcEcTWZ_r#=T#H-y_=(JF0cP?WK2{_bivIw-jMGPyD*Kzp_35 zbN>$v+g0i)U|0Q0Pl1$jUnSr(x{EDQ(o@0uaA|QNc^x4uuBTlcI-{E8cjS6c_1Zk9 z-IdRke=Faw4@qY~ixLr)B6UlWy|nORFx8Ag?Clk2 zjG!c?1_q81G1gY-p;d-vkHShArm8>O7+VcYyWKV@7PUI6#9t^^3kahlt>zF%qWza~ zY5IgcVDXn(DI!c)Yje=ER_hOWZ&>08q?OYf@7Url*yOO7xbF-K!~B@~_{tZ6%%FV@@h`$&|K+G}xTs$E14v)6FvEJM(AUP^qj06{Wr|~>VTl_C zOs2MY-ZPRlc8t%q&L_(*Iugd_rVV)&Uezyep=q^|I2RSh`8N64(o`p~@X7lw82D={LJ z*RdbKjTIX%yZqO$M@RfMEF;FmLBztPf(5P71MQWIn6KZma7J-Y2z9Cz zi9qnPE`WiR+a1c%Z;Q3_1WE*616nTz1~dcu*={JQ7ALi9&L}XG8Z0%c14xvda){6C z+y?ATn;;RHGQ@*Dt-b`3)=ZyTmzeOHz>Sfki0ZA?>6r#L!EiaCQ3P7A6vUHF9D#;) z)@aa-S7hN&$g;}H>iU#$jjDq-#`6~E%HwSvhsde3%Nsz<^8WG1TgOG0B3};6?)$Vb zXpI-^Ty2@!CcSx0cW`?x@xE+UEn zW+-jI)v0L6TI(PALPe+vM-UtAkzDk8-}b30^xe?ry0fp`cRV+cdNL~I=m9il_IlU! zDw$$KW0jz`;i#;4A$R>o+Zg6s^Crst|8-jc3@{;-+X?8THo#rZ75RxPY~a_ya&CjM zRalrsYvzD;^lW<2nNC%VlsBmjmNh*T_C65S&qA2cmF{ee49JB>^&Wrqp*fBfL5LXB zL>&L#2?RW&?xP68|C0Iuf15%{e6k%eFW86GvpnWS>Gad#n~NG~9I;xJ#!m{!7T>(= z^UWUic;Tg+H>$`jhW$j7hJ~P?;E=dBz@^(Rpe@kF5T?D)vHmSMr+PPVH(|xB(`P7W zS7Vk;tw(EH??#)sy1qH8(|n@p*h@UL_;7scYFfkCeju6bh)ZZn&{aA~1ZDi8UJ1ca zP=eaHr~&C3{$OWqYHVKUaaK)JN8p&{w~>!MhxY^9ecv##F*%MLH;-qGzI>RmEPpg{ zJ$&3tqc*F!;Q=q_yXO+TMZq_$Xo`j1;%q_#*4%~+>7P6=66^-ujh*EOQL9%e_(Ebb zdy_`Ijk(af)=M!J-48|~Z1zs_IaNXdIFTC(Tl*sXON~m#I`!rJ@1Ymno9jk?3&RIq zaXAob=cH196dzO`Jm)VKcKM6{LucEPWd=gI6|R%qUCq!Y84p3xvNLsZdS_P7g4x`4 z-3AW0U8z9~(-Wi%KxOU7-J9X3z^mjq5M zcR%LM5x7$UCm*%TbXS7D*P820?XxD7_!m1A31w|FAGV=3!a7wZbC~MyDK*8x0!ZR3 z;lYHZE}WZVhd}X{*Xqf14jv6wF`d2j?dX1+Z!5Li2@ccbxtES!arElfml}n9hqV^e z;P;*!Jl9gWMsule8%yePsflG5V;X#r?Kk0T2(kw3^cyKY4arMU-mw_vf3Z?G5V8G{%ebm)ju5b zYb+->Ut6CKW76a^E$k{!GAcY%ieOA31Cjtp5lkZs)dID^1z<%M<;WA)gPZo@b z@23=^qP`pN_Vcs;TwE;$V%#<5BO4VRl~ih;i>H&_h{?AgE@v*wtvQ-t;8;^rVPll;gIRqTTG+t;oM#8(pxy34G;SKioKqK0h7B z*`zc_FS#wEEV#`>o`x!CqyP(M97$DSy=xh{=-WF69UpnX>nc@{WQg^A3$aSmkPNvG zsAW`ocBJz-VmgY~!<%U6Tw?!enSjcA3Ph9%@dQ$~gVZ)gzOl`v;}oh|7nd~(@B1^Z zB0(t#XrPo|P|=1saXDdQp0;;$a5JsAf72?GA)9n`uE=ZU@;(hdWkXAiwn=diX_6|e zqqMSk%`A}nXxW}j9=O~vZUn3p0$#hxca0h6%&cb;B zUSgm-O)}>7Rg`}Kd2eeV4J&S#+GR3{nL!1|0$_uyaTsT5ayHkUPSe3H5yEDVQr%^4 z$?@jf>VHC!{^53A<=j-_a3DX~=$cwpj!@PX20f!=S{OCAB>qZhXsC`yT32e%+DRxP zUic}HWvh2h(H36b7ymMdeEH|`ZVQlve2Jxp)w~@b@ji0;W&9mSaJtuFv-~3(g3i>kw=Oo==0OSw9@Lf3L}}A1 z+7o}i&X)3e<#}ikHWYhq_nA{$hv&oVKy*BCF%pmdyBJGfD>pehDF?rAcr91m{&=|< z{MG$Sa-n!Z<5TBm2L7MdRR`bd7&&wvzq-}368vx`49gg5{nE|H%m?F*QGcFN!gGU& zay;h{y#Yhh6Hg^e3h!F*s4LpZzk-$tE85{Bxnvohb5K&Bv&Ak!G#vU&6Vj7_bm7IM zQ5Yue#>yyJoFRb^((4~SNhbAf%{jRDu+<5eVUvXFb)!1{c5iTbFu2@rdQKA^e6$<- zby9ETE^I_ISo5(ESfA43OGwGPxPboTk4Wmzz?7d!nMO6}U-B2pLEzN^wGVz$Uz0al zVWnSh)I3_NUwzw!!2v7op@JtG#zeN?e~ z;Fdr^7rG13$^-FTg7mKH%5o9VNTeVEjm{r(v0*PqM9n8O+U$qe zFZvRnufBeH=dj?w`(Raf?_OK=tK3rgf{$^pGXmc}Y_;oLC*W{d7t1pr0YoZauLXp^ z)IcM&H8wdSIs15YIxpD7&)xC(LbhE7^dm`68cpjaZ{A`R)G}I-*KwHt?s4B*k%vOk zBqmz;-o2RZ=S}3_`rtxYGkul|HLEmC7wsjalzw{H6O(pseln?n%6FxwW-`0Q?Yw!} zJSiod_;s-$ZGN7DNJuQl?eZkR26j}r^ODyKmr!31r!Ev^z7LieSbi7yTZrJ_*?@>m z+;36wPKQE4`nr%t4$vE$*kRmo{BK+h@3tb?WJL$UX}6*XX;zK4sX)b^&+Qxk&t7G>CmG%UXkU;T~0KR3Y zitm!ExKW_D+8atwjTqdn8Vysif*wJSYk+m*jQZ^S!3*!Ci|ySz&)+J9T=Z@j_V4|@ zsD{oz7;KxgIII0k({@V24rRUBDz6|CjEqhE41W?H8};Xxz@+H%rPVDW96=fx6td;? z1sAG}_3EQ)860yIxDS|0<>nPfuGrH*w2sEI2{T|+ddascN#inat^gmHf-*u0Y+pqp z9WIm>4wKVoM2k06Fn*YyfZLYl5f`=VFGjk*zl9bk`3eTHoj6Blgt zLiM*5Q;=KqYS{TIGSfwjZx(St1uWf$sDeJx>ob=na#DYRflge^n7Gqw zTo0a7o%eg~wzSfySWP;skvZ{b^)(VoC2tPN<2s)!Y#dLv9PRf*gocnrdgwl`4V#E9sf(|H$LH7{zKNdgD|&)Fob!BCpLy>6dGu9-bh#l5J? zav!20|e0YmDBQ{dDZIlf&8oB_FKzX+_bfpo~M zT>b&5%eu)wfo(9I(aEg;kFB>1i!$okhG7_F2w{jJq=ph0L_nl#=QLAs?u8j%u|kPr|=x*OgLyzl3Ij_-T_${}2Puf6JA=UOYRKk%ILpiz~%!0Dd? zKtX2-SeAT}YUlYAUlkJ=ZhP$;bP`ZzSCE|T(w|5jU1hDtrYOP@ri&|Vvoe$Y8rB*O z(`1VxP_A6}u4~o--W;Ex$GKl#kDpge%pn!%AQ}}3J9uF`cAu$S5u8hg^OqR>B9pm=N6uj#-@^E+qM~Pgtzfd0!s## z0NMfZ1J+03$ETM>_1O)sT`ohqBGN4-?c|UoOj@_db?f$-ZW`;n>q_Gj8ofRbhsHqY z{7Ji+b(h0{Q;&qg>6tFq(y_C@iFclsbar?jTWB-@MB_!dWprm4%KzuGQP2r`khU9w zj5Y6ep96Dbyq*s6HiIp7?Hw=LL6dHi$hZPs%q~tCL2rEQIJ3y+rlg$KVw@SuVvSMLp$JWDAsWs`eRLS;*ZY zM8A+nc1FKw=684vonQeGeHKnBbgcU@Rl+l~RZ|-c%V%8;ng6v!FhwyPW&T-E+QEd6 z46c=}v9rJW%}lMF+Oj@woXchlTJzMq&aVgkdeuEadp?q`&<^ zro~LEC65_=hX&ifXF%u?R&-^|-xrS=u;~WCk=M7FF^oYQ@j)TCYe0|(@-EABg-BjCJC<(zaO?+$ z)a*;G@%B=1Lu54vPa?JU<%!Ac;smYx0ScJFbt?&Xi%BI?yIJH-A_heo(Ev#?!%Z3L zO%`7-lGO&9Em(Zq%iOYd`&kJeV8eF%14UKrr34WAa4COa9_g@6DSGV$7!-!nC|R4Z z7CE=LrBi@K3j1FQddL!gZ(UKT4w#8Z2kbz-O>CkB)04DZ?_O@J4H}bq3Kz$-} z`fx0_lAWn~n=EdFmMl?E#8P{*OjqDf{Y=?^R^l-(wj(t16WHX@BykjIn$$1Uje44N z6n9Z@kiFYO#~+#dZa1qU3yV86=Av5q@o$Dz(XciR(s`l&pD17Cd2`^=j5jcdLFnsG z%pAW*q}2H@5;VoTxpj?^@xcF@eMAg0$q4C0q(Lo{0n&!DBDeB*&8|ioW&36V zdryg?tjxH6H<6k&VBk1;QLwDf=~CfWjlbCD7cM#Qa%GcFu2iNkSBpI*#DYq;#q8=u z!Vz>YC-eU!iO3KG{{uPL_q4y&gU>(Idm+EN_T`U$-^rm*TTl?Qvn-}Y=n>)3&5oej z%(Bh=%b%Jo9v!_fr+eL=rP6MsbHWBPQ-ibg?^Y(oMh^(e;Y8xV zhY`H8@K9Ku(q)!#;OBTc2{I*0e+5*?+29f4>4JyMFz(8FGO!K`h@K9CDJS7(L_ZXA zE--iDio?!Xcr7^gp@*{ha7>3}lY2?^Yy7)%M5B?szI40uUxCp*Avmc+^@9JS9x`St z5MD3KqY6YsMQZ=2FT%uW!4=e9RjDDA5xPW!3Qt1zpJ3>;KL`U$eW>T~7y4(XPXdOs zWU?Paw$sC`zPda>beSjfGe+(aEyD-Cxgx$XB0J4W3+CKvHlyRY{-Yvh9$@M^nh?uV z<6ao}MV?ej1r3PRQm|I|tbciyPBmak7_v>Yx4ziZ^5Vc@`-n_6GI06R*JnTPU(s$Y z&iTA!J+h@uugfrM|4G@H8tfE%m1e1Zhi#VpPSF)U`mP*c)$cYHHspU-KuN!nW(=WR ze6{mE;w%m=q_6ruyY5RLOz-n@pI2o=P%qBNk1|t|_Gd&<95|}wS-}K&#GaSkwoSVX z9U*IR;qnu{R979+R0&pX-_b29Z0%Im1rJ0pWT!-2r% ztCymu1a|@!jwB9`KslpomUG@GoAWR4Mg8@PZp(G)jJS7sy2RkkT$nzDLaM8DRsqM# z6aX4@qqF0{D`(~;<6`#UPlEfr>u!_mR#ZcOKD61&LkIJb6TWq$8|*mJ7lgKD$D}Iu zIc2;7h9@lB%zicU8&oEfFMCx}Iwmca+Mg=r`%1Z{UbH`a7w@Q{?ZW8m6Z7`C&Lnax z$FAkkJ;A9KQaUC(vMp>bRr6Lul`OG4rF3s$rAh?Jmn_C1WiR5$+kEDHHHU9mrkN29 zy{AAhi@tz?{@E8Tdhmiz+y=HA`83uvQ7-r5gH8epgw_X?9{OvzF4ZVlr$d{M-~q0j zx`{SsVaxrG-b&VLflRgz1nCpq$xinJYy;QX7Jcx5Y#Dz*HnomVaXw{ExYchtiP=c+ zuf`wY|C+H{1+4Tp{fHOqE;=mpjd6hj-5UjWs9nQzu7c5uUx@Lo(M=(usI0Ji5(aFFxHZ^VjG?vD-0lX&h7MYqkJ?Ujy0) zqvJxDmzPwcvCy~gDisq0vs|4aHfkCgQv+vd*?%!lx2ko+zIo;Q44mrVd{5r2*?e9{ zzde;H`G+;@o+#%lE?-psA8axQd(NL%lcTZf?`J1J#f5o@pZ_vfA_cAf8hxkgwf4OP zN@4!{PIAQ%=T3b)*2VPPCFN*PCk2DCr9bh4h|hbi5)@MA1v!y)7AIl||CYeIpPm5* z2oZ2-!0#nliL##1eg0o*z#xzY*cgWo;748a11I1G`eq5dg8ammJ$weTsi>DR54tc# zSru^}ule4zaV_!*vMts|15P~-jpZeD`0!A`1FKhiVhe*v{n8BVDBmY9j=!F7M(u7) z-uA1m^uHkh60%MLifz0X8UoDZV<7A#aCGyp-;I&i1EM8F2r{qR58-hj8VxOwy3T1^ z{cw_|H|wa4d4C>KOZZ&O1Pf;yP+NO2!$RMm8OKKoKLsV!#SqsqQf{Iq;=HCdzh&y`X!N^c}{wf0b{*for7 zDBAhUxrcj~jKi!=%$C#V*{SvgX}>ygXOAycf};F3x?AsY($Ib#0nP5eRUk>owqNxV z>c1xEANvTx^?i?(Q^te9i*2lk=s?OgR!!1i=HlSJf_ z2w*h+`{2DIuomxk;=kmCKYU{=0LA z{&MOGWQ-g%F*9-)?;*GB;;#^dwG)j+d~s_DVZvmN{J2mz6!?GN0Me5*vXfxly_ce5 zzOkbxdQL6BCou#NjoRc%P zd6S0;Me>hm4nIg;^Z^4&$TCt-x`I7R8OwFw@gG{BzPfFFe`@4#5v?VSzzAwykzSsx zwE`1wiX|3<)WwwFkJ$z)8n=HgDw+0o8!V+Ln;hzTeOR#FHd~r7`S-IsB)=Tt`QnA> zPs7bE6N6mo`1!1=+>NcED?hkCoQe2R@H4d}#6s1}^VqX~ehT*R-rKVKa336gsrUGa zGV)aypyv|*q*4ABf_#Hyi_Yd$fkC;LnO;4I$Nrx1op1na(M0eVe}WoRS~8mLEtq}w zO@F?=xgzk#82FEXU-`sLl71$2wI_v>^A}k0aJ%q4m8HpdulsWMb!+J50!h$u2(V*P zVm;*P|56)0D(v$z?FwdPhi=M*Xc)7B-Vwu}KP3^!*t~~+O&<<6i%UOglTHLYtkN#i z+n@w-2V~qVcB%?&uDN75btqNzd4gcwm}DNF*}M2c^>$f=2=>v~ctp5RJ|h)DpD_Db;r4 z3+QSY_*vP$|7fjmU)bK_teUEr_Su|V*qPQ&B>jE5nvn0$R+Cor?|V(B*N~<^4RW#c zu*BBrCB!&uh0mv)$<35@o~dcw(!pJo*ZMjC=2LCSOGJMHO+tqirkWAR8v%|Zbj&=Z zn6B=3r2bKWza)O!&RH05%_H-1k6oAZ7GFx&&*VOfm+XWWTC6?mOD8IUhSUEMj|X_+ z)8otAr*^#=Kr3!_Vq)U3?KeitWa&4NDKD`AiPbZ!5Lx1U1aOdHV@Rh61Ngka7+WN3 zPE1e&e6JTa;S2VL%UTwF)7)k_D z)gUmOb~v5U8CPQS*w3bvF`|90r3PoY2yAjJq5#mc8rXGTm-qBZnsyvZLiXOogprny zkLwj$T~i%Tr)%e&v+-qvjj45zrL5CR$q(Hiy6qsR!e%k<>5E2*G!t4C)AGw&S+54y z!OgO(x6St?4jwYO1n(aKtyff2o%#1l6=v`&K)VCS$3DG%=N%+c6Pi*N)g?OeC;U`z z@v~?KRiP_WHP4tfdIBZNemglF9ErchATXhd3=H+hUkN_43eQ^pN(($Yboyh7Nm#CX zdv6~*-!tmyKzGP+w{eQ{#%`fAS&&!{1AdM&O%i2yu)D zg0J+&T+J|K2Q!M4un>et5mNe0e?slWl(=6FcM7EhOm5v(SOqjh_kKW)q9$AA;lhTS?n!`ucg6KE0I)uwf}vD8_J2jf}cA zVj3KOd=uJm=(hIaXTSIRO0q6r*M3dOllm%S#X0l4b$#`RKigQRD)y7_Dd#5Fe*G}l z5nQUA1M6V!uohH4GAC1Hi-Y777_`i`21yk=Eb?c(OvimLC}yzB-y+K!8O%bJ6rth- zoj2)B`I?uPCvE=jJS$g6#_T?2BuxB=@RV;HYw4c?sesexuA|>cLCWjb$KIeE4!Mfm+tZj!8VlTf0?8h2Rg}KQlsovq1oDsvbUs@Mc3${v z=qMU2;!n&(cR+ATyX>{kr*}%SOcWsq$i;vyq_jlE~fLo@G%AODme9Id`>{ufMQ^l_6nz4_~stME6V+CI+K5Y2x z%c~pi8jB7k`^hD$u{G>~9r40dsz zYoP}T?UPJ|dIeaeYf9Qb_)iXOku7v;M*V>{ zag4f5u}mgAi&U%WL)KRO)OVohXEYM+{q)DrF$nLl#ej?vGKqUSvnFNS+Ru=>?rjWD zNu%rVVE$m(bK(>&h6!S|A5aK_CNIn|aFa?f?M~hJA#Cl>K;X-myplM?kA|5Vq5e5Y zAoLGP4gDCmJ;B#o$%{g4LvOYEshVkpN7g0IJA#)QAN55?GrjJ4etxB^>XqX&`6}ki z;d@@PNKzitCZf)8)z|mK+6aeKiGq8uh&A*KIuzU?8U~Ufj@k_Vb6*AIx^PA{v%|3} zg0V=XeN!%Eu|D|drAtePqUiIfHn+UO0v7*9Ed}l;H#aw%>syLDvxv+l|H!?;oRQq5 zk&C?jS{%1Xhx6y;a~VCEx-}gMyLBDocY~S7fdn6?9%O<0mtvw^ClaBkvIUeOP_deC z;LD(W_KC%&(V>CC!Elk=9-&GLcihLtmfuWl#+j}3&5rZm2jAdX2cgL7y`3VnHC-CZ zLjQ1*_@M>rn4s{7L9svd)`PkoA=G-^PKocM##=aXMk%>75pT0D7 zzmmbqOF=O?K#PxQ8Q+!{_Hp{PK6LUXyn+-W8@}O{u#c~OseP(b53;8h#G%%aAJIiM z@n}rWoJ*~n@3b^)YCiI_ePTx&?_t2Qpk;`8!4E!K;lC><%$zu4t-m@A%p$3+v|)D| zZc(}FZc&@7?I>gcG^)fljO+IVR7jX=Mg2+lE2qBh*FEbS$4|uePqnldP!m|@k;*i< zwuoe*QStNNJVE#>FkwUdzq})=Kv-nObMi>ISMX|)8XN_IHV0mag8h8F>U0JtmbFg5 z*}|b)^zm-nwxFS^Gfs;xgAcJiISH&jJv)mcwWsltRR8>eDNCDhtSpTEZ#kEIj+%5> ztgw&}m69vw7v|Qi<9U|}5HLs60~E1|P+{{$>Z`S?Rq`8*5?AaTa7H;pZFjGJMKH<` zASt-uhL(+00ej2pX9-uw31(u!PnxG+R0ND@q%;?Oc=``dbBIFj*Znf>u#IdU@~YmU z`LLaAzNWhXqLj3~N*$z{sTw+v zwhYB1YlGvekA6;0<2D91PSwZ#qN-25-n$MqtfLM9ppk!E9~Ns6!zK76wc^)j&BLbS zF@^P%5^IAEtvS@wrsq40f8~f=Ql^-YyrB>A`JR6659W$~DY{Y4jxF-G-fHE+N{QI` zqFlt^_sS@v_SQ`xOHZeHV7lcnM5yT~DrEmvNVIKNK0DxA3F-P!*nlD^oVyuzYRDe&@AIKBQzZLm;nENyt}9rRO7kGYs= z<&pcn0L2@Ntpedalo7SUeXK{4%hMf?Oar;&rexnelgSEeyS4h7udxYP4)oVJy4JqB zQomLbC@7t&?K}~FdksCzV1Qyn zp@(~|*GFsQO20DOfX_6es%MR4LwhGnJ%4WE@pSaNs?}@*x0OM9V4J&v7DK_3uV?WL z3(_pq43f-RTg9fyrtA7x{xp(C^aw)oR1QGof}KJAJu@-FfR-0vrkom?4u zOA;yv!TiR>OEf4+$;&+gqMmgywxe+5BPjR8U8BA0B3Vw5MPNt+%^vMCr1fkDSnQC- zk6zc`3eXq@6rwSiUHa@lVE`MnE%1ZIP#zM`e5Ws&y`3aHU?{bJ;!QDz*9aqr*84gK zw?-D5`G<>-ta^ZY$3EP`yWPb(iuFLM%|(4OCgHxn_7ypZI}$Kz+&*AIxFAm~$RlqCDqCZCTia;1kch-irb0&Duf*m1ZBJ0tlma?0Q!K{?rY z;A1#;_a;KyW5!|v1%nU82`DB`3fg6g&D1i}-jq8cRwNgbtod#5{Er8YPn&9s&r)Ve z*6!D8MQ^_1r0_5?yw@t}a-v`LJ9yHV({&B$C_$~ zEst+rd_i5#R?d^F10sg(e-5$_XF;nN#4@3W;A5W+1dKK`x^9&;UA?)kX8&WRr2ACh z)!7`a0}Nciq(4@~UzEZ?7tE&S48Q02pVD~qvI^|7%;4SEA$3{{u_Q2tL*)26DMsr_ zp9!((cV_$T-eE2TMX<&CA_m8g`@ME0$i)%iT&?UNd9`yrhY+lzxbdN-m8C%5oo;+& z)Kc{BS=M<*tMtoXf$l`{U3}MNKcMI|{{u1{)V(7_#;Ks704xU(l3t+7#f9N;KjV&oNcD<{e~g8wV93BAEnp$NWDHdJyM!` z(0G>LgAc=-l1SkhPl=kA+NSt1BT$vW^@2N0wAG|?QlP3YrTQ$FJ7Y12yd=#~Jn&pN zzf9q4svC`rpd`b!rKnXz?qqH3jF^T2W)*JH706Vw2SEoYpwO?PlWEfgf)kcn^V*Ps zt-|(S);5WF?myzwFPAsO6@Dyg-fR#0`{i9Ds!*CG>XdSysX~|_cW}lb0EA^vl175%Pjw^7+yrPe3`WfoH$!%)6zz<02aO1{Z|{Nw5bbIdefI(U zW$8p4H~QjU(d^iq;F)gz8ab#&8cPN@fV2#3T~1X&;;Z>q{=SdF%mc>mmK9j8l*sJl z>x;jIy|X1B8gpuIEae+2Y#pC@^3K|b&|`q_U+!b?xKvY8a_{jI`uCg_K_&V)9?h8TH%DpTQUWA_Ox0g9Tr?P300u=n8i3^KWg%mHAnJEOmDQw) zIzy?KKUvh=u~VOm^7V%2rmf}-pCu20=7#ZRFnwL}_t(29>xLf<-&!6^1q?Uv1>L`9r*bG``VoQNgu( z(TDw0p$;R2H>!O{$vXWxZ@_9`S&e=%>gPAS_KrSSHD_%yK4X0{{w}g|-h&{VEfk-E z&8UJhWK%f_+)h8c=wm&nRNdyQ%pJriwW6ONed=RksYU!jq$n4Eib=Xv*8*1>2@2B7 z!kPJT`l-wz4A9dWMJ(C`v&Hjse>hMR2+@D0of+K5`j;YqA0nr=C5x{HXx{f+QF*$c zMI+U>MS-=4M+V$bP)RVBpxB`#muba8#nI(qT`R5*b-(|G_I4d`f4>3(Jx9I;6i?5$=gtUQc(n|z8yR-Lcv_e{ zQy=NnvRV4|TaeXgDdg|;B@1>Ig2q5SUAQiLq^WQgQ(sH^6w*^0owm=I2*?s^sB``?b zA=1xK1LyD=C||XyboPb0r9a8^9FLYy=ZJqI)k*N!{F&Z`hXGjXR{18 z;#=#CF5DOMOTSZ5GpN6|x>2!+(<6gA11bb)Bhq&>!mTP7a3mC0ktJp0@TI2J11Q(6 z&k|+&s=l)?_^&i@LCINyWW&E;J)G@y2Hm@{ds%%{L!J-H$@?gF1l}K@be=iu^k7P!f-qaEw{+p);*>`|V-G!ys^Q$QSvwvj`*36$!@fK}*%Yq0gB#%nTpgdMoCAAI!I!%p}lHIu)xKQ>qMkcndUuU%-(pj~i29j0Pw? ze7&#%-#)UwlbnqT8FXYVrB-@-y9-q({L6LMDbd0tk*k$TlXw6u zX*D4_Dlhi)QS~=GRj{6 zklz=UJ93;=po$T!s&=-F@%V)r;M-oy`84p%IHk2~a=!v<=L;@>0^71b=|KXUq5&?4 z1EfWR8+=HPogpurX7-TG$0kKc$E9LW{VSeDr=A;gK8UG2Q`xtzVX5dOro}=kksyD* z5V>2}1RKTu;#(@AgI>z`+B941j1zGym?<`v7WP4Gg)N&~rz>!FCo_|<2hOFb9cY$* zHv5*QJkYSD_x;mvWeV@OrHk#jY9i)I1~u=ZYzH&&r9Cs^s1w0%KBZ|s(y8+S^`~;X z65X}}blC#IAK5g&NZgI=aaeuLW4cKlvUD`@uYypG0L6ZQ!alrzFOyA5hKqm|FWo(c znBNW~a0GX&QS?BNz}Qk;+)AZ@bnzo7tbS__SW1W? z4uy~Q_9|(WnkBXaLmJ7KixXojl56>Gqd)qBgFXtBDNU7Ji_7+Z#03V#1%FDpxEOMF zh`B=*@a;O^B~U;5KJ`(dVaI$3>Mt85af*f+TU za(%NgxH*-3Vw#O`FLA5o?EZjys^Pqp4Uv_&A>bFx{D8b|l7aC;AEHMHNa|x)F;Gc9k$dh#o!1n zG=N4c3X=@JcM!?=OSByRj5uCe#s9$5UVExNN>Fv>A1@j~tG;&X25V0JKY`C|Ew)>|VJ z6Jky&%q3e5Wq!1|VIj&$dN>ipL`s|JMk&B?svZfWx^E02fK4Rr=iLc<@*98DlK|Z< z4KH<%>*P7*Je4p>6jR(Fa>reQILex=P8<2RH3eU~R8`j2QjW4K;7Tli-VdY8yCZ+- zETA>c_b*OCxy3#Y0yv&^wwiCJde;mM?k%ks6sZ`m3pKh;tWV{rdD!qYR$0p)vp#CrJn^Vzv|5I=K|+yJA|wY&Q`Uw zIH+z?wFx2VIJ*7H-&Uklgj7gZM8N>z_+8Z0kZQ4htl4TUZNUZnI3Ark6b?}%%kKsR zlWF)Dz@c4h_h`sIx^*#!a1pa2Dhu@t_;iw|=@@POiR^0OW4GPUMF)E3@qBQJ1w1btoE@Ih9n>;{hT(nxQF^f(^pVP#tSw7Kzm)0 zdgeo4x5{?!0y^0nUfwVQ(n;43<-~lBkVC(qDU`H8Kr@OdPW4ZXKyesOt!U;0yjuEr z4FtA)Tx-eh{vXjWq$M+yzH=hry0kAV)or{`h?khUR#}cpY2Yx-9`m?3J-|4)a#`R8 zuyqohYS(Jle*zYcjYq;Ny=nLAb&GBUaS)HSdIijvvCGGjZYI`|kKiI>l+xNAW29*e z6t-^GK)DJTcMYGn%WUMeICNI*Y1pt?kK|%6mS3Ey;TF^I9SHBrySdMsmX|0ArBy< z_?|iJmVO(Z+3Ckz0Sdw@T!s_wNt|yCoG|G_kJ<<0B=x%d-fSq39O!`ni-bS})2zUE zsL_91qgN>w;L*DDmaou&1LzhE8)M)w{t4_!qW&bDSU}x4GXFaj0aVt>UjkyivrOpw zgya5%jD7nzG+lY|xQ%{L%gd^h&rNmKv+jldsY)XnS&DRT5hZb00YpRh`3KR>u;$)WV5yS!K+ksaVL0!UTyV7Ry{64Tm)#d5*I`h<=H zXwALNSyz4pksGzuq467c5nR*FTO$K~jYFw@(QZDg$CUrL5@i>b%5dZuF$ zcQ#R5TWi7IIN;34HCe*KDYh<4lOOHS;3-l&bZ=eDwr^-{dNql=-lFTtGEXUoXYUFR zhiZ;+*D<0-TcS}0NV&`uA4KpZ9L)>8<7sQGs53f0Z z#SQUXx_~on(!Z(oKO_WA#3youlYu)S%hD95%Iiv}ijH!Z-CT0~r!tq(Aw>4ZA zW2V-!j~+JLGjBA&$~Hnj?#lhq#AVRw^*OtX<|8v0iBcAP;Hh^P_X#YE@h;wakM}jH z6bkwpjFnFijKbW_6~(<^LQ7>N3ae7jx#g2R?0ghlyi)J6@>zxAB|?kSQh*v;PJ}1@ zci*t*^=H691AZ;X3o*lt59+cdfdqO#ZzxNGFyQXRU1|E${?%3cGk|I)dk3mSSuwnI zU0WMahi@;Sx}%=1GW*qyM*j7=NfN%xVd36Yg2lQx+CJr6(6VL9|1JD8r8bM0q|G2* zKM|F6g9bi_HQ$!^tFsVnPQrJR)erG{psD>|wuY7qghN!{#anLU=3mxXK)o+W)o7@x z%lrD2e?;|8{!dvxCF5;C`?T~sdT=)|IA5>`f(=Ewizuf?4mujR>Mr=D{s7G7oXVGn z5#*~uH(wVZ11IBzt7L1TtuB84GGFQxi}py;p8!^n zppDQDxYF_^;OP&v1>b;M(((Z3KJ7gZ*7xTyL~5~gDY6!h{1~kpeJ!Kqce-zHG(zR1 zc0X8>T88#w4QOYPxr#>I>M5~GY<{Br(DU96Otr?`cFsgbDWig}jhk%%Z>)f=2z=~iBtAcsuir5D$(~AtMv;D!q``zVW`tyg2y?0TO z9b#k%JHBagelUsrHCw2F5`dh`#lS#o`9Q}cB#JqS(?=7Ec?dsm*5U}&AB)|>a1<0b zz2~v25p>Y!&>K!r!FTXJLi$~+Djj4PFG=-HAXJR33x8LgyqD=nTm{BqlzoWP4x;5J z87b4^3FyncNSLw*E8(Rob8+e__#F;YLoj76t{y>S2Se%*coI7_LJVxyb2 zkl8}vDi&aBn#p;>^-zBjlI7-(Gn74~-G0bM|bB7?CNB>hP-lt7Rs82k0;0B{}fuq&xg6d$s~ z)we~ii@Ex*sd-|j0mjq!r^0r&IxEFO0G_+~@gui~+e~&6-(#QOD}m<8g>FxrOe^9C z9qnkBNTwdIHg)MYbI><^gv{H$Ux2cwDq$s>Spo!cj||vUqLKFat=0LPS2~1*t9k^?F{0rrX`;j%5S1LI!&9V_J37{wzdCcb6SmBw$o4v|8|yl8-P1s51qfGj%#_VV9#{{QX<{VDgY84*`a zcMrRxgM0rhkNWh?XDJy3W^-S9P5Gcf994E$Mph5{f7Dh*LRz@NU-0kz%C_p_=4#Um zMUr9bsrdvl8N%Zj35SG2a|(LNq<$3LeC8}P^1)t#X0}oys}4Z(ywztyfq)y&Td|rc zz9E57Tyv7MNkWwrP`pX^Es&+NrH21}!WbcFzZL9^Q2=)7xfSFaM(0N#tN5+zCWp0> zX2_V(Gyl8}V)+)ompp;77-EpLT4+ZF2u^^ycbQRDFKr~t-O#0)y zfs>8(cZHa;;;J!gTY{D1FT_ScHf^H1Pxb37#}}f%Qrb9v+D?|>k*p#0vwoJQFE%D* zM#b~A8t8M15X>zHa@&5=$atGkG%HL!mzi*=PN(-}9pc{cK=2mgAg{Ml_}g>!=gqTIkVQ$Rwj2RP zw8Qnus$o1?_Yk>?WEAlk^gJy+y$Yy}MF50f8h4&hR|-Caw$;`@+!Q$Sa08^1kGsVt zgKOf~)!M%K$M7bC>0P3+pgNa1Vsa|F7!Urv zT8l4&CO(!@#d9?l@9l&{olo+Msun)N3iJo4R@Qe;W&QM;Y{^%JYQNW7tU8Jo=mQho zdyEd`Y4t%aje>PesG8kU)a5hMmzGgehqF(D&l zaEtm~5lP?w0Ea{?x$P`;C9FyvizD(qa#SToFRM%@dD?swU@e&KDK z^N!6h6y=_YwX>*CpTo=xCNu^sl6UHIokrSkqA=iF*RcRw?1h!&^)E0L0~H5bTf?O3 zK;ldMte^OWu4YYMWj*?csjT%+FL`NDEH&=(w9xsPX3be=4>^1@2Xn|`*gxrRKe_Dq z-2@g`+tY;?Sh^zk`c1`p`yupU!;6ED*CX$%)zLc=SToF~Xr#0&U+Gf!j@qyK?wqeh zI=$7s9ob(fK%UW9gQ`~EG^RAqv?G~)BA9U(@3#vhbavMxI+9z~dJ|c4f>@A34 z3Z;~O$(z2`TP^&iYFKr163-~CXlV{m;)^H>2Fsv6UMD zAp}jK(VEG6v3Z!VrrmJi5U+nJI4!oqfQ{(I^Zmuse14lb`| zCqBhZI@piTuDsu{xQw3Z{aN`f&EtFWYEArD>o~So2t|JM$>)qX%AbiRXssPV35%-2 zquN&{HQy99rms1xvLy>+g}O{}I8J(`KwTcnK3hDcFbR%2|MZ#GRuEgIl$LZfNw9nVnXub}9NY*=nO7DQFdbN9 zy7Euxw4nX^{hn(QW$Fw3N?f+7xI{Bjpi`4H<~XZWH?3@7U|<4RZh^CNd(`Ef-jOgB z`tD>SX+Sf}Y}IRveF9Uy&xj?Uer?A$0U@_UH**6XIqM@WOOI*t0F?s&=$=W8g)@Op`Bvb(r8UIp9K{Fro6&`a5ay1lv^!5R_`YzO{La zenpmlJgzMVl8qFZ6O1*pyXy{DFOQ}n>jLPQCjKZ z>?Ba=(1hk-m&z;~z3TOom@j%hV_?-H%}6w9VQtN}KexZw$c^EG_e*DW5X<{+4d=+B zt1s*KXeJvQn`x&^|C#V42yX%^BLXpddfGtFWn6FHOc4pg$?TIj@)p}tfmP6p%-J;M zXO0cgiya-QJQw_D;sC^vqR=5ltYq!R@&igu7XxBmdyttz!0>XEXM1kMjfAoR-a$$b&82nyVRlsi6;EHQlFpdfN1G z5kc*;p?~_WSv79j|Hb#+$tKU|wocmv*)ss5vBakEmyZ2|)u6ZQVznv~1^X#pCEUp= z{zd%TKX~~<0ZXR~px%RggJB~qEG&o1UupfWE(0J9q&^|f+o=^>aT9~xNXT$i)ctSu zF^fvMA!NvO|0P-IemDvQ^XlD< zbW7GEvb>Gqo#_Y7GC3fR!Kd&fx{=`;Q(IGBU7Zm0Dm4aaVbojiAU~L4r7b3IAx0@# z%~G4}rVB85XQ(nC{k#8K1t4=Nskmu6hl02xu!y{Lf-#MmPITU2cOy4>6omcP(&tZK zO9mSpx^mSidP*2A!bB>V&w; z_Ta_SoGkJ@Z2&}CJlxgZccLGPl*6(Ws7EH2u-Ykq{q3H!OCwTpa!<7WQ5brcfUCW* zsHli3vd=?44&DDLNIb#hMp?wAh1HgXjv;Hx=;@ z8Lz7de<=Ve3h@^H@rY1i(9~+?@J)XpdWH$b4Z(gbnRY@F>Z}AEP%h`x-iRTfWWxG= z;k~|BCq}-A4fgD%xz4LYqf@)>*)JN_XEuia+dO4f29XQ9+b!B%a8BR=qXpW97YpSzL5waGb%69jD(ygBc?ZHkvi7X z*+CM@@;;iJ38v)taYh$qRa~;Pii~zzend)N6Q>8q)x=HGtPkOPT5jAQGM`1j`r4%K zpw^RC_#t#O0G_PMmfh+5NJN45CWcdjVc3)outy@=*rq)^JOrh-hVsSQ@huk4-*2B+ zGKUOJzJ>iNeqqKYJR~r^&SHPT+JEgl&4eIOEEbf4X{V8LbOJCN;bbw|_LTjURf!6N zfa{gJ(^wN2sPJz}+puO+jdN08d6D@~tBckA$C{nr!9IN)34{JDry0r=qgwA*iqDh! zV5;aD`BLNesx&nYM#V3&Vy?jxJ3W+mmMPjX3lg@Uh7S4 z^OyoVBM=;9)ZAqi9!14f0+HJj<>MnYxFTP=t5tms-M4)8)5CU!=x8+}VOX54pY9Yl zHVdi6=aQ4l;HtpDslo}t%G{^JPHvOJ1-_*i%ezPs0Rb3d2u^_TS70lMBF`8P)2<0# ziC;;*a1Ceai#_e{CfHfLbaWAh9mk^Xo(1(!Hp}xLQ~-zJ4#rx1LiC~{DNSWNR^Jpn z3u(*IYWKTT$O$sPXMMf|dw>h%jhFCLyh0g`4oY9t^R(;ei5@hdU$8$8b}tuOZMA%S zcbR>E2J_sqmBc(=ghVbzc#E@@_cGp{)Qf!)r>wZ8(RSAMzq0_WiSUP^V+ik@nVMyBh*gD_+T_`IwR+hbZr?lc#yM7L)jY{68zlE5ttfuZ zRV}S5y*Jbmta?KLPLOn=U37L_xvW;O{b!H>^ugoW?TZ*p>E8TWcSt9kpX(D)gT-p_ z-Lrw{khk46QnyZ5fk)lJnO6Jmszdfrh8unhlRI|5OfP;YkXgU_Crj-H?xNNEg-)BU zd0+wQ22i4wMl*|6TOu&W(fs0~pWM9mMDmHUbhCPHCuu4|T(d+4?5^?GkDOo;UrL}K zY_8Vr^qLdQ9ffs4*#1DtWM37-0oO$y2Ah$FIPXhfDDbUDTFVLEz`n$WfWK28!5>4- z@=SI9V^&X*SV_1S{ACm2&^D%>2R%8hj0_ByO4%LVod$7i_OcI5c-bwQ+5*GMFT1Er z&!dgBx&7)odZg3!>Nad;VSe5W^DrSlnzbVMAra6pMT7?0%2^|`$pGT~a;3^^%g*RGSRX0%U`$X_ z6qMAEP-a5f9++oAg*Ms&KvYp>i&3B{a;^7GjjivXmV$CX!N#TdN#f6*I9HWf!>5=v z(YL0qNx0bBLre{rUCRdYcAOkwA!=x@PkWVm8+j6m2HrbJl(!tfwDu&0^WIVhJ-`jX zUBW+Q(;)(i3Wr#|O@f$X$z(ocvjlmtbYnqa)02(5f$K?i zO!UtbKfJr}+i;>;+x{^YaiSZw=W`Z)5?n&L%aGsyXr!lj^gMX-PwM*2sbA+9^UV#a zL(PmW&n@m*W{r-FJ8`W&)3EEE)bx;F^C~?`n|*m;?O&ms@&v+8ni88BmUJQhWLGfX zsbo`j-KC4LNA{&j!9=fbz|oe*;0jf=>)YbI}DSK1Azc z+P(n|kTTGWF+vKR2&fhi@;fLUkiI)lrPFpZzH8`JbN6GzUw5!imQT3R?LZ){L4G$+ znI9N9gO08Lz2}3f{2I^bve)O;C>7BwWGjwQcJfg4>CYTr9{iij%?)!LSsS%zUtZn| z{MjUyx_7^C;Ly+ScspWyAPFZO76t4}BN)2p{#AVCI^L)j1jRam2fKTEa1w(9?Vms2 zxBQqut%k!EYy+N$ljUkj|CX?13JOt!C~I4N{vP-qsG0zoG9_Sg7Mdc)!l2!)=eu9b z6lF@y)KGSKq||<}QRhlt4J6ct=o1h{$9TAn@ z$wKls?M!G&VDuebsPwsetTnl0YucMP`w!_v8qWr)-chJ}4M)5(38%6((2Frfm%aaU zm2Sd0*?L#yu;b-P?V~5P{MFp=7oz`abNduM?*mQ)m^-Z%z~ySM2q}HNf!Kg1L1D^5 zaG0QFJh|&<(#YgQ8LX&2Xi-%GxCqE%4It$oNpx^E>CTRKN>i9r5dN(R-+h1d!Vn9L%B5E}dnl&l!~ z`80FG0eFXY+@R$foO%Y1W9mNqKJd?nG3dzBHK-udC(>elUe#O+65MXc{dCT1C93CG zmQTJc&>nuQY@{_hsb<+mudGNeLiR`9Z3Vb{US?^#9bh&so2l0XKE4|XP2iAB;G9}t zcbc55+OeFp7?n2kIi9ky$wHzZTE2XG=He*P-ux7$3>}X^>B&n4mUk^RaNApek+osb zvLE%Fk6tvS?x?7ZHyaVwee6z^{#Ad+dQwN;*7)%Y?{>RU+u_k&cDRzW=O^4y%KIjG zB~R^{@M!+T$EXx)3t)ER+&Zi%e)9MBV4$ZE^t+>}yjJ zyQ+@IxSoBqQ&|8{-|P9`rD9I!XIF9`nc5~9r2N{OD3>|=mn=V62) z8n4oSRXxkcBP&a0(99HZzX#z|FEXp=55@Zjgl_i=R7F;Dat+yqfs@ZL1@ScD)w2}7 zNp4tQ=+*#w=FTbW#gYoYGf*8iIeR>P;ZIBa= z{auU8o!Qp5boNkkScdk1?y>x~`x=6W-g4Ie5OMpVXqj4p3n;prh4HvM+Eo5jKC_$M zSwkihefyHOD^B%Orx2nblG0%BHk6$^^*R)O;I;(to-dFwbV)wx3y%D?M9e@D>a6@R zfeUfYjH>S(oakUk1NgNmIT%rm@C)8T1Lw?GV$44QU_LsvNbQ~oeA zZH@-fg(AsEKk_Rp=dJI3-8&g+whAcvbxe=1`cwZl})- zzc8ovgxENszTCw|xfY2{OPg|;tK(u1tjKO}ia!6o=$UFIyg;|w--8nH{33Vdmhb2MNbaQ!R>NE~ zbDFi%Xl0EGZwLc|!I#*faAl?rhbPmKpZ1u1J}(W~l4Ib4$Xy$mqoByGo6Vvej9L*~ zy644I>%vLPTbZkisG9>~6+HA9A8prcserw*i|i|$^E-N*0nB=>{%1nwd0W?7`$Wz@`N{=Dh&LK z0qFy%pukv6X^iXeNrP$O1SMQgXm5uj0oCVz=N$NeA)-jtw$^_0&C) z{m!wE`d>6qszP8BZ#1z5he!%%y4Xr)pT_6(PW>L=zHB#EBl0#9+HBRrQN0bi=cx!; z)9+O-0i#qWO)P7>_U`M#_1!vY{8`3n=ZEETG_A%%s(apRJu-cKeS$MBInj;ne>+tK zAgapZVR!Wnt2oejd>55qTeICz?RG;7r+%k#5B@fbm}jnC+e}J*i<0JB{D_82-pQY@ zQe&Rsu;4F_&a z005=nVw6Mx4E;3E0$DuX0Hv59g@x3G^+YJQ>A6`WTDwLWo=XuHG0u%$0 zHVJZPQSdIH<5$Y(1?AMYPv#=1qxyK4IF0W=W0gRGuw&5mxoR>- zXzsm2#K=feGWG24SyqVTz@BFq?kMZ8OUa+6f?@4tA3uH`bsKY!djEYq>)dR+lx*;M z9mop240g!2_vjwA$wFa*t$P>8_62qG7er6_F;Y;VVpd@oEf9lt1kv>{7pmk)%7 zfiXIFPB7WD&DK9{e&hXMO8AHHWCyTcVb%21oG|W#LGO_HmYo%iamojUM&bY58X!8{k5?wxiFRwOJy|*bnoIRT2R9tDsN|b_J#JYN!X*Rygk(<|?B;V5V z%AnxG9y7w)7GROH9N-KkXqReFd9EoxdoN8uwZ?T>zO=i>ShZBxzt83R!fT~3HsL7= zfOf?GL*ylf(z+fd*+RDXbNG$CGvQmoWQK2;iVwV9S+lr3Yv$jY*3b+c-t=bDB}t$%sm3FUmArv`vpgK8BIJGbzy?rW3)Q@{;sU||sr3|qPe0uX|% z-Qps6s9F}8o8K2!Ua%OjEiT)viHZa|)?ppqB%H^VPM?awQA}c!z2pwi!rKkW zS6yG|GpBRh7s}h`elinH@E$2g3+>x09Tn^PQQ??gG=kmK&-QdTHvblYj~P0q<&+YD z7mF?BVg&0q0w4J(+SWHNSw-rwDv|GIUE2#qLTzv|Z^w2|&87w;p+B!hJG-`nTV6Bh zwi?bT{;Iagnp$z^{&ctamhUGV8Q3#o6n%_pXaXa{JAw{W|+!_cO$=$!^$4M_pUUzE(ZWA*rlENjS7K-`V`P^ z6_^ucz0F2WfNoj5$19t`J|mCi`RC&`^qN6cdtutJLM#R-7$`nsu&4MPWmy%(X>f5CT3R6}c~l{smvBex@gu>GJ_U_(fKxIEUdLjYsc@Km)p*}Q{upRL$RE#Z z87D%f`7j6?2=T%Wl(gm_8Pi&VTwGuYx*eXP<)o6q-a?N zwZF{kX8ms5{yPNMj7a)8aVGCOjn9Q1h9=V^;eWdMl3{4c zu8L5%{Dtwv=V6E#9KpHW>2c)H;fL$O*5*Ql6^#hxy0|A7%`C5EwM%kx*b-Nuw}P14 zgJM*6D+M--R@ca(qM^axlu+dCIa^(|Qty?{3;rE`C+j5&<47a{h9ZY$k|_Eaga~w0 z+pn7X9io7I1?aGnuzm3QN@q6MEHSgm+|Kjbbl-L0GzKU8tjv{X#HXXby@HI@dB*wB zgZ{pK(a!v@W_-~OYw}K@13JVzf>8? zy(=VK?n_V69Vj6H@8uIt({&HP6a0l5aE6#+(9t#uyVuU7(BAnpJRlS{?L`1su{?CWXfEG0mR_(6<`!M`#2u?lfHKB{T61NbpQ z3oNBVI^e2ltLry}B@YR#;yO{wQ&4vaG!~ZZ?p@$ESy-|(aVnhH z`W=)FT6dD<8^<$oNV`%&K}ahr%HBlZ`XRxgW21DY|=eM~486^xgNaY}R7-<|F* zBNTjXR^RpemDD*;OS#%(VJ*)Zum zbng8$D8$Z_DP}vr|3SE?*^fb85EySLxl<=v1p%YH01n^wSj%>-TYuucIi|-xK=h(TW)A z>l6DFxlu*xSLb-itdn9;e9FGO!S2NE>Iq&CjSxp?-v-z&ek)d_XJ-qYbyrAdVAQaV zNKMo+0=V(Je!@7_rvFqi0csyDEl}Wl4?-at3 zkxo|F+rqBtqYj@@nSyM%IFUd+Lq4*;}w0Oq9y?;%Rd#;%job)REOA zEUNX(Y&KhEa#LL}+yVy!9;gm{PI zSiY(ofThWO-}`ECZH_cPo=5XfS$q5yRMbFgzhp-)(Dx-4}o*$K4mY zlxX-njtg`qp+5`J%ung&W}Id*3jlPPaxX$#9l5d1L}@1~{KgHTWnYAP0h6+UfkY1E z#kS`0@O-$5r;W|M1a_E_dSXGCV$g1|3>Gs&z;XeIY0JK2l8)C)CZL0MguUM z#aG5nHv>vG-h6HXbRb>@p<(XY43ZgQk>F}FXT%p`kW?>ICTzt5|6~pvc6R>|>hXJI zr0!b`j;v#merHolGr!4K`Z;MD%U?a#o1=i7b|C1lv{tii!*;%W(JU^ukuHR1EEnax zs;RE#dz+a_a4la0+LXk`#txnbMjyiPOsXvvFBuqniJk>|{wdIcgG!koyWcO~DA^)E zuP;oH_dScnTX*s59k3G1FQ=J%TJV0e4s{{ue@_p=fWiRgAbvY`%TW9KcmNi+u>i#He8JN>oD2-PvOn>_pUoJW| zH8s}>(|j2P0nD%f+L=!D5-%SVUUj&1(skPBE^e$Z($E5h7u5gD5dp7blA3LCIZ*I@ zNcAyQY?3FwM<%N7-S>@CZUFosr`GZxT4t1k269TS1+tsUg@ez_5=QaM5~r{9Cfi@a zQHbJ3e1{N7F(znsb{1Jw#EL}Q-QOoh$17}L&~wsFSh|}SPUGCQp)abz@UoGiUf4qr;~>ZM3wT-$cPT7N6IVYbAW%LN&@4iuLL+m zJ3P zH? zuEIYvPE}f#fSgUQFz7! z;CsziDo>t-J)noMs~4xIr&rC)%)n~`)f0!-y7rNy$L%>%0g?%9s5$E$LdosjUBXcO zSMdqr|4iKjZCU}0@wk{X7rva@`b!@})ASE#n8s-(iJgWAhn~)_cmRw|ujk-G`Fhb~ z=f7|K&)e-7L0xaitp_kYB}sweQL8+2G6s68cJscKoRkVK6QU7@-Ogy2OC`xPos;zK=So{(UN>fBs7AUjJKRH3Y}k`*&BWqSp7t-VXB}mN9iOGm14wF^q>w3wrJ3j!y zbl`6S6%W6vNnv>)0F-X7KKgj@qIhbQ?I=BN|=JUp2Lqq=L7 z(`tVTAfj#kACp_mgTc2zhD$a+niO+BhCxvWA=7LvYCe~J^vnWj z9>C=vIN-gr&!CyB&IeHHPH@1!OV5Ph*18|vWV-u;bw z56F@aEFI4tz3BLh#lYl~qxM0GXVKAE0WOH_mm#*+0lG-aXqNqLr61puwJyifPEV7H z*gv7>CTzFAGZ>dZE(9@7u1{_OjCNXX(k!Mmqau_|3tkhVO{o);-pIr~vYNSg1KtrG;%|?YcEdo$|&$Ki=pN7SDcdNh5X@1QlIW51NOVf?p|jpJ zWoqjJoY5vyv$yf7ZR_D&^NVype@ymZYWlgjb^i3<$@V`Kuj?c<5nC$6>vNuInUpi_ z|4YdE$Irr@A&Pyz2Lq5fY4ZnKjj3S5eBgtAVR{- z9&`DPpsA?xlz)#aesJr^EMaEEFc;S&=0KJMjQxeFh^z8{Fck0CT^wKk909kIvm86- zQc;PC_-*6hFxh_ls`IER|Mc##Fm4fdA!Z2$Fmi$A04=uiJD(5!wY`^A#5B-Us#KIL z8Ru_gKDzZXMHc|;aWbHl1P`1QDyPZjqQb1yNkYgv>?yp_Oe**h$Qq`Rt1cY|uv{>= z_{;NnhQ4}KegfKj`X>u4j|DuK*xrgQjOnUT^e}$Ed`a#EIhSt0n$^;2DEJ(!5J75r zwVLw8@3!s9VjGQS(2GWA--*W~!-rJe*82@-$E9U|+3HZj0$5-yL@rFDc9-U&uzUrR zoDOGDZUP7g5kyY$@xM7hPbtu`pXwu!W2zM#*10T-j280S5_cfMz;`zmAg-InR zsg+3b%#y6y*Z1{y2jV#;oAmJ=pqQBc3?7{TU|lvKeFvX&9-CGT42+ThChSd!3dtn9 z;`Jc_qP>l6B`A?H`S^Iy0?^q=aOW(c2uRetM##GE;YG4zosYwLFxbxWfDj#E4eh`3Vl5iclBK2SOZ%2@?X z#&p)K4u-WTIWijKXBfsuGw4qFc6BW8db?a`=4VCB2pM^f$pGtCOMxz5ea4YD$D zbY^3t`Pa5-v@S>5&Ax=ocfD6o`t{7L&vPL-(VpiENwKkO;=eRzDG6K(C7RvWkc zy&+pJdUetHes8`WFkUvCLsLI3MF!n!ybRB(C&K=l$#91PQYz3-)PAqXp$lZ2GQ^=g z9-~0sS#7&G?$7C~DA0tT`rjZfVvZl>p@i7tV0YR|R7 z)G?taTxY>`?OOZbF|T#w;LOFlo8rX@9O}%$DnT*;o8}GOOvEDkN4*_147rn)8&4Dw z_5}OJR|cJ%fU^;Cg^Hch+oIB!wR7{kXYDO*bB8hg-Dq!A$jLWZ^W`2d5i6>P_AoLq zxQ|#$@$%dZ%+f(-RC|O zy`OLJEvwkt+jlnoR#vLFKY#ACKkv0KvFNLc+~)jsp(9BGaJT>;eQu0+$9+{oqUkY0 zN~AA6yH08i5}(fDgOFirG?|uUGH2znvgXc~zHAHmt%Se( zW$%jLF$AnImc%~fz{)auU1RAYr;GrohqadqcFIjaj% z@0P8tM56D3K_#zQGJ%YK)~aU~*qPAPofg5h&F0L75ef73CNMDyAHP_>GjN$p%Z}ju zX+qhXb8Jk$TSeHwV&2==9R5@6sZG1P1mE1Rcdt$GhALZ+5FTD141FJs-248-?KT8S zd;{zhUEkh4_#wIv*1oQgWdHj5*iqh1N zZ+OA7gW9sDi)z^G=gG{|d+>RczH2!zFE5BX(9>ZBbL{!vcy$E;`hqRpdvfyPKr+Y+ zAsazt5FK&3^y(d5Jni#Y?C+ct$L=|pjv2{=JQ$2H)Q3}g$!&MuGXPtyDc!AOuH`H7 zmGkN<``nN0?{|pk8)g-9hL?U-zGIeydY4eSjUR=4BhfbcaCqjaOe|j2`q10!!rf?h z{$0Z4v;T_O%$YQD<;a_|w~uUBB9fab$2QY+Ma1#=d+9`(G9c&4weq&8jyDV)vMHVP zM&8G+y@JBHn0VOg)YRXGON_>Y84+ee{NKG}<?nUm$=topxGTV%vpFX)zxw5CBA2M9<5by35A(m3#_Rt#KF19)_(a;IA zix_TzT&1r`gn}2?Yi2THav8HmaPC9r=j~g390yI#59lK~?y)8>1lb*A_QhD~Rgv@eR7|3IJD+`=y^unyNGb-)|R30XY+Vnh^RPEWfhgD zZN9yBo zB%_aDQxE&&Xz`cvw%$fl-ftfNAVC#u_^fC*C}OM8)A>srZJ7s&Tz&M5(pF5kcLK-5 z-|vl(TF_7mFz5TC9b4|fC-e!P6|Eb?+#Xhovj z=k4Uh@rS;!xJkpUU-g|yf|EQQZ2FQC&KZZeqrVBf%&~(Bx}sHHc+BW;a|i4;oE#*) z<2RUF{V1}O%`vfHd~x~Z&0ifteOE1j&F0L9J-$f1Po&x&zZiKbHYA#@Nt#fVpYo#K znM5BG#GB2_nM$=iY{6p5Y}?@dnz-*^&~`j`grBFIPl&>n?vs^`r}BIww(1Q(;!}Mf z8zUZPqe6bysr_4d{UEB47!4j1J+vl#yhnuW@f`TZ2MsjzlGh6D1XyNz%LaZ;9nx-(|ae5H@GLnL&FM(RwDwE}<8^_ht zXq0VJTyi_3+cVhHaT4o2qq{fly3hYp_UG@l?9?_}EH#8seFd<0y}ClRh)4lMp%&Q3 zPpo$5BNb0UqIjQSzr1iC)fB^_NH{gY3YE#HP2-l( zSK5zb+Bafpsd8qL7!SUa2&unTuUvwz^~KWE`dF<7&9}Th%{VhKWhDtEe-?(p5Tn63 z+<3m_tjY%260_M|`OLV9*l}j~-VY2B#HyrYo(;hQ<)Ft|)cy@=;4uRm7y$!THakQM zvKL}2F?vIV7iziu=FwPaBnDq^X9!NWZ>tup0p>2nkM^GVADhlt<%gl>xKHFw?^p9H z`$-GjBE{Bq(l8G$BMg~sF^PfT_2gV$IuYO`x!tGOOla%eW?Z$Y_j(=BT!)3ay=h)h zesS>O5-{`?&bM?)lwI8+JeRf4*TZi!d`x&h>VzShY^DE1kYuMe?kcVKMI9Fgr!q>^ zPNLI3`STHvg_-+&scwI`_r*{hzizX&9*t^fXh(^3p2HkpLzu! zVJRtV))|r#!A)#H9_vlHBt2y7UAu%%(+j0yI^S8a6!Y8zGvZ73tA{jenBY>pcsezq z6v_DWSiG}d&~*6@?2#JfaA;bUg{0;c0S36XQTM<^x`^fnMb`7JyCx-N8+A+<`7UoV zPlUg;tNe5qg)ob54Odj2HBJ~kbE?cUS8$`PGzUS4zcbx{ucN*>Ob7lZ3lfw=t0Ws1 zHgk<$_w-9UZnYVUmag{9X+q=%UkCf5@nMZR?g@m-bJLxLbn>KKX8LMinmBGSs%yyq zi8iJPf_fXgzG@}c?#>_j%(Y08U6=z6wz*-da=>&5ybi(RKwTD8KCoJ%=K=+RCo`t9 z%n)1XZzNb5{I(+klc_^R&)?4 z*p7;7Rg|IEk%i7#{M_vzVKKpym9wHqk0f0gW+GPno&*m2>4Wl`OgThovHtu+tL^RW z36}k63{>A(Pt^&GyZJLNg4{B8Yw50|uQLrP+9-pRSUWsMk28pP={OElJNacEXYX5K zw>RF0XzrX-ZF?6B1C^u$$sRPybM*Xs{2mQ^5lT|q965iCe8*E(NKU=Oe#NOk$x(D5 zII`mk76=YL6zvP4e%Ov$>qE=yg^WL3v51FqoqJz!5Y&P%H`S87M*xmiiQAiF^EuM} z%6LclM;aoaMyUa{+H+U>zL;HBRTWE>oKb24i_BCvCMU_7bL|lk-Nzi!fuYb;4@vDi zBy7~^bP3|TJ{=Z;J=4KQROY>JpS9bEw1wzq9Y)wJ)J{(SlnW7LZg`q{`;Js6?L>-{ z_`A_P#~GQa=f7WbTRDBd=PWE@K|4uneouth{44~6w3`rHB}Py@#j?BE3a6B?5)WNe z-kUhG&pwTB)-Cq)YkhiI;|EqN9&p-{OU2FFCeTLc*AiCuU+P6;=JELm3v;Y+E1REM zw+CW2n|W0V+Ck_U)TD=ZR#P35w$;Ba8*RNb-2`p$G8LNfaw6_gby&dgE6Kr};Jj`w z#x3jC`h&ZDvRDE{;1#*XcyCi!%8D<`A4?7d(q~qB?}F0IM~2WFLd%%q~F`j{7qy2kMnk69s2gl!#t{ZRq z)?nWofl(IM>VUoPBHg}NeRpHTlpJ%=vS2aeRPPTN1FPeRzO95pi;WB-JPP;>X-nz@ zXpv_mJw%eHV2doaH%ra32L3>WO#NK_TO#B}{X7$3f(pG_x)W3CSn;^R+&H4lpQ8Tb z8Yx^m=o2sku#79?citH2IXj>ofJ1GaJAb=P7j^-w1T)C;HVV{I==~nADxqG6J`dumrmAL=!@;cvQLC{XmwcVUQfOgAEHKHgkHycB9Or2FhFMyGT#VXx~y8xngR>EjZx!l`dOCuujp< zoK=<}#TzhanT|``a8}`{+mkhJ(`N;RU5bT}AZKaNwmjDfVpy7a@SX9#|UkwuVKMKev%hRo!PT z@d(R-p z2i`9~>C(&-ySHpgJDZ!hGI-hRZto!$^6j?9p^o0~;o{QX#9ON<$fgEX7oK>%Iu28_ z`v2egi%4>bA1{*Ty(0M0`E1#H@$0M63s}Zt4UmXeMyVCN-S>MRstIElDf;d013@1h!XsZk{Ti<=#p|baqDeYFDDZo*8|{pVIW`xg&AXZ*yCw zB);`DAg{OLY*DE2PC1LuM1!t#EoM{q*~=^6si%#5<}%I5j~^FJe0S^B@7m85*rD0QjV zLt*)k+~g0Z=}pN4M!ZxiERhM$Rou9oQ(YN))SMZCI})jWp4ttua)2CSUo?0iX%HQ& ztA!pO9y0*v`flGT&D5(8^UpI{cextT@40o2Fz3{3l?XI&*7qC9wmJz7$bE4jtM4;S z7BtLqu2JE4#-j9Ap}2<(Kz`e+pU02gpzux`&^P=%#T@t})7ZhZaB#f3=V-6pTw zZtsXL!7Zt+R&51=pX0e-*(xeJR||yDf$xF$`6MOj+^l$E(EaNY&HlJM<#0+HuYV)BK3Y#0~-cK>wCa5Nl4IEn1@OqvsC<8 z-na0kk&}&dZo)y3W$W8%$(bk268#BLfj{~0=N$`tF`3V>@A?xLS#V9`liNblvF!DS z-s(NIj6+)ml2PgHWI;tJGrJj67Y;^ZqvLYwhSZ!fU|7QfqYqHiJP??7G+bNbZCQO* z!`z6jl&!6%Z8_ge9b-PCDI!9>VBmxQ`=8VTlmh2#dvl7O(_e&W#q}U*%%y4e`kdv) z7%vdKp5&Zk07oNz5A-gSmc57kMZS7tZH1`jzYQY<1GjV&zcvgr!)Tq*Hf1w^& zp5&wF;_RH|Oj9M(x<{f46j8A|oezltQarY|!nIGj5Ei09jr>0zANV2Y3u&ak(pCD2 zH13*ojz?Y>-aXKmDT{zj@hb=W(bo;_eBe(DwR|JBaWzM{iuxLt>xwMoLGmPKfo~Of zFuxCb_9_bSi{6n5+~K@i1(+7k>F$7~62??E10@N6pnAl615jhR_hyPh zRqbWiII5IpjT{bJab$C3eZMFb@G=;VTR__H}SaUSl>kR8B7Wc&1Ru>(1Z4_ z(>Pm-f8(LQVgjNf_}pC$Ida`GuXpnw6Ub$8m_9|4p-~)(l`~;59h-advjD4T}{( z^2Kc29kmz_20~$M=D@rR-p9kdaJkN%-(p^S!{JwE@1!nHMq}{`yVD|itq@x-YF$mv1lVLEeg2h4F zxzqmTdJgei8k<1wc)-7Uh5Dgt3s^3@2&`J~k_!x@$i495;*1Ieb7cV*NZGc?6ai-k z@)Hfb(%JXmlteUaYV48~v(wd$!bys)VWz!n3PvdbX*78kU1-_5f9t}LC6H}qOg=qDJ zjuTtLu;CtsjLJ;g%5!}y?8>4!O9fk2<74W@?e z@@9kz5VP56d|<50RqYjkSm0-8DFMw;3@`&kKH;#YtA4~|#N)QGr}_A^=gOV+r|Sz* zbJp~zu;YI}Wom)d;;pK~r{a8iinPiKb6IyKjCs+OSAr7bOyte%QU3YP!(U1uC6s5< zOq}$T&s72OjsSr{UB~k$orH5DuXUKur_WYZ9Tf!)JeIk;y-K17+VA-1h~bGj>v_hX zt{JN&zTsp1p%e0)RLaoanXIFOQbLzJ+6p0|Tg+77Fj}p2AGi+yh8muc8lS-UvS=xF zoo<1hm%}pDMj~dw`%L8dYGi%mL%c43SZN0)l-6!bXG`nzchm18W3%r7^FdsPnch1E z1f#7_#GmLNHYWA%j=fjs`q{7XW&M8-%UC4}+K6U6c?6TDhaL*}>whtFli#7KB69Y5 zCCfv{YLunvc%QMV9c405H2|AkvVO*JznV0+iHGI?DCMP zY&_FN#R);DN@&DTs$>!^$QR5*P#2isbEqO*TiQlQ3R88wfS8WGSd5RE2??VYeZgjC z;op$QjFGAmxGjRm)f8vH==SSA3qzL`jaAyp(vD`syT$+Gc7c~1k7nspJ&IVDOUr;A z2r~$73t)e0w(0{3N}Ktt!#`30djEnj5^hbBkXlwV5~0L|F?6pZByFaOz+n{3=}=xh zW)=H0o8zX^sATZ`3AKfYMM&UtC4G&G+M4Iry$90kxTm7DtTrYEMvt6=_-X5#W0*Mm z4Gn>#6^mmKa1jy_J+-y91s?{nq@ z8j%7I&~$v(4Orgfz^kj40S;&LcfujN_M^AUr-%<^@^6m!HF5ym_}??8yg_rmq-scV zg@wLnMlJ#wl1i%u?bJKdp=UW$^lYbmcGrwmQ@FrYPL1Xceq2D68x}^2<7~Uha?OW! zbYsLaRQkS~1`6JTJa7{1AzV|66um=c2$a(M$Njw)~MkfO@eSf z7tt;}8|yNr`sc`cz|006k##_Z%}6m6Y_=18_82MTRK{m#9Z-a7c}@Be&56=1Tm8;+ z4Pnynfv^C3pB#tiE_gpOXzfaTu>*rpUkRQ430nHPNbY;bTd9y>5!io$0 zk^w0_Mk(x<$p-mc0ub*B?@;RSbB`|B2h1N{@>KTY$s|2sIB<2tvPP^GGK|!Gxq`uQ z5C-3d2k)87$>{@c4N#ozFtl(B{w|y@KUgko0w)+xT!F!5btXI);|Gk64eSW_j<@WO zqn5$Lesi!#)&}$(`q0ZxyB_yfSA$&%_ou6wdQ5H5Jldy+G@M8VaQ^B4lO@PUVV&L_C~_}I-CFGAwYJXPb+_xy;eIxA!o*dxNpLRQ-~||AA;VvQ7wW2KwPQp4)Av*e8IO zG0Mw-Wbhz6x44&3vbKI8(_PenO8FC&#_DGa=S<&JO^^^r5L;ocWVZlTFkUFxuV25U zRf4K8h@lb^5<=qQcefNlWZ7;xg4Ffsw2jZf1fbR+cd6eI9(MuB#~oqfj_S@%zu0%Y~Lez2R@O6!jfc zub8W^Pa=CeuE*n2TN_iw7=D&qWx<_opV~x<>smRmpcQ4SU_Dz5L?YA0wkG{;F1T`u zGJa1C2DeD}xM2pik4<^>lvt8_q6hp^l{nMry*)C*k=ea(=Tyli*S>cqNMA{N(0`Q67-5!eO&-nhk++dH>oNzsm& zytbE`M1f#m1}AzSVhuy)CWm?FS2XavXgJ$lv;`Qv8i4E=B+Hy7kW>*>lzpchP)v13 zj7XN^T1Y&Kf^EXzyA-Y;6c}@ruwO#YhqmG$0ipLUhCO;F9@$IfWYHIgouc%jrfvqo z6bQ#K?*(EjnaIpAimHENtN%6L+C)LZamw_sCGV4gHw2g}V0=>%>A`LiR|9z0h9c{# zEC$!0Wi^YQ6^FH}(P^fGtGy>S41p!C+V<92SI5LQL-crV&`w2hnZ4{P|XBTFh>en)30g zgkh|+l2bKzRLW(lZHZi}@1qQjckUJLE``IY*4z)@)H*R(t_az850GpZ?}4*;2~u`& zLe_r&x(>Ob4Jnif<=W7;M`^4zX>NP>5D}&fxDTigt6W!9RG3lqDFex~Z*h^gi}?vl zCP}R;m5QkAQeb_f7aso*0kb{CK7&K=&leLI%RG!QuNup>??D8m1at*p=Y zI%xq_FaGxf_rdM)6a%&&?RY!&h&fkRF}^I0?Lr)->HAU!oyx+`vQOQ4JeapbfO^~Z ziue|roLL$g@l%2?RyOlC?gliU<7e&6C%S{2JjoiPIR_JXi{n=nTDh3g9$STsNAdG} z$IWV%)PP~7Kq>t-0-urxv|?dunnOrLfc@b@a8q>dwV0XMQ45lN+=*~Np-k;+$7%F* zfSYHzq*D!Hjb~3Y8b1eW;-wq8RW~2IB5j+p%rd8cz1Vm+lm;Lvtp`ZS<^am|;By4v z6|qu%trIoufl|{H4LXompTgnc5qPayRWXeid05owRHIy>D5yIDx{? zjC&frFI!|@h(|L7Mo`#P@l6j(kl0RC#WpSDVcR}NhExSFCd`EY+gtrBIQSY#?r3y` z=A+5V>>BFaKH==g zw!r{O0$sn>nbVNLc-h<%EG}-FoUv5Scqcy{9jQ$XI(XjY5fZr!^wI!q3$(@iFyCWg zyKb|(PRF{`sc5%)KCI32Qyfr;GojRV%7Ow_wPLkNLl1J@#t71f%Cmp#nlaPruR8V& zKR6FOt6qqrqsgYKiR)C|-uH*tAeg{iV?IZ#1G$0y>5nlr{}kxbl+n6*enh3~kV$C6 zayNh)72vXF#c%8>9pj2I=k+DW#Q=4nexRmF|*mk*@cQzk8qS zeg5lx)|%xSl?8g{obTTIQ`Dq^M{mbh1g8JMtfa1ONhN-GFk+ z1DZL^B2u6YpGF2BJ)T5>e7et3D$k1_Dmci2v;+K#Q(45+<{OsQc5>7sRyi+1v& z{WTWGe(KNXc5;+e=@SisSpbEuMRiAabGZx9f>_$=znl`@OzPTj;r|~9XZx!<5kQ}8 z6)|S>*}S{DSb65trhF#w46()_%%-&^A0l`5pMFCt~%EWB+QaLfjl~x0_b@HBkjN3#1BvxpB=Ubi@Jbx_#71 z@uzuF5QpSgoD_XjHkkWNw+#)K3M**cB{%BOdwf7F@8MH06J077OJXuoxAZSy%ixiw z^Y)KiSmBoa?$=qbbRM$#+otP+XGwy#BcF$7?tan$b6Bm-YTrRU<}Y=jwe4#MjM^tH z9W|S7v!r%kE!qtIHg`+x>K8(OpiVxYC!g%{hUI+x1B^yJ`OtO68%439)F^yxAufw9 zh&PxFHrBYI>}~{<|FH2kNK9MfGc|nEUULr7DILz#(~5_|#K-mI6s}83K0-(Koh)eL zY(XUFhf93T=H6BV=0Bx=_uxE~Bzf}W3C&5yNF+w=B*tUPU~ut6|JCV%F#29FZ{7KZ z!n}%_Zno~=3BeC*pzZw6OZ7PjD$`aw0B5_ko;`ZhtqmV3Vi?sLzEqc+!~h1E$sUh! zwPI>SiNscK!h25)=o_^zCMp(SfWhQMvlP{hKW-U1AdPY1x&|CZ zF6oKi&LUSHeB!REHTFK$YWRIc?>Tx83uAV(KA$=6wDm0AK(qV8Zx&5;)seo|kR0*N z;I64UH~5LxwG)MU^yE9im-IcN+gmzJE$n$BJ@5v6lQtuieF zf)?n~X$|QVW4CiDcGOBoN5=`3nVp>-_z=?a^TWZx0p1&&5F!4{uJAU$j!^uONs0RA zi0$Irb@&2g=hKjR%OaqfvIrtJkbw7KW~3YV1%^H}NRlQ%qhbytAK(c{3E&U2PDBrz zynB;Pr%Q?A%s^2!Q+rO83{8>pYI_T$3^?!Zxc=3GA-b?%grc%aEh)k-zg62Fp+DSUn(zm&9!dLC#}CqB%8wU&(&D3_^rU>5t~L$}Fb)H-WdbM;U#QA%3c z*V0n92B0rlsP*ZXJ*?4ZOZb)^yx{iqzkpoAyKnRF6(5!Gs@dJt4KM82Cs@9-WvNB> zuH-PiHE(h&+c(;JZ@Se9i}{X*n*XEwk*G{M`AE>0wmBqeS78=q=-{yp0Z}_vshz>- z$pa~a*S`qVAREZ${BQDp%reFec(l@x$-P=6P=uucrkSxZB0&vUDQqn@G)OF&KRAvW z2gP(A2q-I1+l;H@g~!OhsyZvfrEJ?F62;MDO$iGus#uIU{E~c(-cj#D-gvbs=Slou zU2Yd7i&7X*=&7Me4&7E0I(Hnr4q*4KDbWhcHK3Y{g;I4fiSbz2yh5iw6 zdD$V~&AVQk^}kIJnoQp+Z@WRAOJB14m~a|m>dB)H(fZlry@WcM@LB~Fe9fDlf`>i~ z94x5YMa~Qvjrcfmz>YRvald5}BsD3A;RV+@M*;oYv~;=j>TZj%h%n}jBv7_=g44C) z5VzIys^)obiaxxC8>?;!WJ__}*i9@~C&_ho9v2fTR26rX`Rm0i(E=u;;L{;Vy zG0^~Y0+XPfr*jaKFx_jhstGXj3ft>V}SL^E62ygc+3HJGgy z5268^Z0ANZQaC$YqRvPUtIfGq&&YoOdC@QxC~sth($$WYu{5tRKGSthJTSfw4~;L+ zY1~xs{1@x^&n5Nmf`o-EK12VcIuecP)+c$ zl*IM?n*v78;Rh}KaS&y$W1Uj$E)DPbkcz%f_;NonE zesgMXtiP$7OY+yPsoMgANO4<1uNQtdk&8S!Ave{zWIf9y&!oX&M6u%{GTsWMYlV%8 zWHnJw8Mpj=ZGlj70GHb%Z#D-pi3E`hWalqMh@uf@eeYj>x(G{&o*Q#ry1Kq{FuCzJ z?7ejYqp4@ko8g8_XV&cFzPM+R64#7Bhrm!TeH!9!jT_Q@7tr6`Y8&d1^oKZOmp#BK z7^~H0#z*Ftgwg?>a!FIuf`GITuh4S`PlpzvWUsaixr}f7;gn*UYK3;ebk=iVzG<>+ zr5F7S_VaHU_)8k{=V}(_NCojtaJob#@)d2@AYqh;Hqd<3k?QNGrd?~`u6e%aO;WAbfoL?Ma5(^~3#N(zxUTqSX0DBeq9A`(>{UQJB-WW;&QV>ZHRqOHqci67~ zAWznAR^@P&e3cvKD|XIT@{|L&A>Z$} zi@y{2EG6(8C5RN~jKed;E?DnKtuxdeOWbEUJD?npvOYUUT!35}(WVEx4naydNX{dq z*eta&wq??$QnvCrCI1WbV+}&Ob?hYmT}STJM)&A>OwTc5&i6iSYirXhBZ2x5XpL=H zqmbR6OfN32-TG55Qj1!&S)ZPswtWolHY0V>1}1XdlrWfQY$=GK;304XYYx|`%1N3? zVRE1z-CUluK_{lBtUChfc(;X--ntl`NnZu5Yj_Cgdk(+UaMb+WlBftTg7)FhP5icO zc-LZco?ysp$Yb00!2+raq&aWy12X5flUDfyow*l+$X2d&g;@!m08TE^_tQW-e%^d8 zL7;?Y!eSzP0(+wUf1~6(_?8`U%Fk0z3%_z=5@WNJ8n;lvMvobVN+gULjgH-PwF~W0 z(gfNuV8j;EI5ffs^L5<2=>h(fR(&vHb8Xxa5lP~ofUFlpfSbwb2h0T=8VE8!>o+JT z4%Zm~b>{Z)$l>eF7O%9-`t(?VGHA?mF|JDM?o8z@?ZEy7awRMQAd zM==<`TgN8QK(t3U^M;H!6YjS{4^J@h5V_w(`&;>AWH2EIR>tDb_rUakf_y*$V9T6g zqL&E9?anoeFicbqoJD9A!WL~DrTX1ZSdh!4B$y(pm%f-;-!dUsZtlY?zClbK>;^S~ z?G>@4ci`*z#~1di0Yx7idJi@ZrYCObm!^~`lyP1RCGBvyUI4oa+< zR_S#vbuh_5F%`+8+%T;wa?sG1PZcz4<)JKQyv_;^kr~7JVd{n#jw5 z9OdMBwufm-X$HoZmHgg0RxoPHc%mQWWv_tVl&_|Ldq|!V?kGb(PD59?eAmOFfRG(o z7vLX_cSeyls=_js=cU!q$_C%dh<0Sf00U?14q;e3*8Dx`QXtM(myy*9@%^?5A;#H{ zf1M3}U`Z4(Ekt(oup1REgTZm3o+O9_*pr@zd$#oLgJgG46t?!7njr6WxpV*Krq;wo zZKZ(!Z{D>bZ$o>#4i|KKm?S9~9_$aoAV5R&_mtP>Uo=l#u$ zqQU@(N)j%&^b!69pfM)3-IoDrry_+g;K)7IG=96CTYl5eQl>ivPd?SnS0c%?hn=*> zSgOpT3m9Om-sBh*27RB{f|wh>W1Yn z&m+MovGmZbf~BybJ{S_hnK10ebeDEmSXdZP9`HvB(C=%snS`W95^=^t}1iN z8E}}LAh25>wku7L_D7&%7AYBA6Zvb=0@O-WWB~$VTcbNZlx2#;=)SV26>=o<;8Uh| z**Nic01_&A7&r^2bhUE&+cR781g|G=lF?2)I+NZU64!}O0)J-3N-6F;KjN;h-^>GM zsVAi5H59O&IMu3Y@n}hZ?%JKkSXnH69AMl4!$pCpZrf&B*|RaBZaXQ_UK5B3@0)EoM|5Jp@-JTSC1`DDgHWt091kBe;U7s`zIg` z+v`tcaXVg>+O==79!oIS){>oLBU9g-F(^;U3uyVkgJv3BSFmb&2L1?W14lnNn|9UW z4=D-`ezK+Zbu*P3k!+h9nYj&j&Sc_rO#c*kmQ}{5_@URT$}|dpq+2mAtE|lD=Eukv zpSn8)L3B4#5%bCc5@+e^kj4nG07;6l2U&<_pp&GtGQ*asVJe~mvmv=|En5J6U;Ch* za`<8OLe10%LdSAN-WT4LizlQ-Dh`;Y;whKuXCXXhIKOH)zu$y4yrFo_4qb5Ln|av; z06KDbdNmAo)u%i)_se&X>s=sltUJmqDz&RLE7{BBY9#`aMMPw{U#0jgCGV&9$oi?S ze{DXde`q8NlLjl}0g9gXYzim`Ogrqy@LonnrY9hnWH7>N@+rAF)m-GkX9d$9%Q`xNM8ZMEiL79&PGagY% zP{ds)o;@RL<|h-^QmLDSO(+a8HtfufAZWa9W5CR#|p_EgINlTx+&u;%J1f_XlDBmCwm z?GYIHK|Yj5?XGeV#=9f^peRVI6;*V}22cUw)=folHe?=Flz>_0t^Eg>Z$^SiGB_RA z%FLv7IgfcwyW+4}t`eFi(`~+O*FUziu`gd3Y6xh!13*a(Q>oYc+I#3%@$EZ-T8yGl zG=qZ#y;5bk3`1~v&hxYrE%wn4N|z>{yhSWDLJ8F6k^sxxXayuX%5K-FT`7>P6S8@v_4-Y{l36~RFDP?N^jZ{PHFbdqWEmeZU|kGKK~ z0$c&q+ZwB^QARV{wXSkgPM^p>k+!u-Zo_DUD&~}DfAkrh()pqM_er<^g5?0k7*vC9 zt%+2H1mXV7i5NcPEmGQW@HAY+vwu8&Y*l4#pzEAPV~Sh)p+GJ>3$7?`vtm3HgywPm zcFw@EVxc4KY3*`=(m1|li8-rN;F|63Lkc_!Nv~)qMeIOhx87y!%tv8Te_X`4itCFB z7EMKz@(rS_g~-;I1frvUrV(O$0J#u6)A}^aoa%rYvpwwY<`#kl>TqL@cbRgcf;=*| z49`)8J;z6Tr)2RYc~Gz0e4ha8(b~(6*IKh5zVU>Ha5&EQA}G;o%e)*(lA<>?WX;r3 zX+dhOqkUYP-gbpEHT6>wA3k6IX3;48hvbsT$6vunbzyd}M}clZwD;z|v3K4ZFh#E} z0bE}_sMftN=o&WIgUE@0sMDx153J?H*@Jx*Rc+fN2R#kCY~_|xP*8wpzz8iS1xARQ zHwF8d8tOOIJc;~sAz8S+evi-jFyql2)c+q54IPA$jk989LdUpTp{&Ib|LQuhz|6_J zTe&uC^=9~e=>3tL2i28%m40ktfPO@7V#TcQoNB_?BLcbNjmQ zO>^$@H)Utj44!orbm5pq=|N{18GAaeZC=M3q2x?qqj#8>mO0|&U_NLbq>@(k&&O(y z9MD~J;<2h*yE`&B>+im8;HUD4_9 z+NsYgE9Go~Oi%+4-s9qk8~}|@J7!!Cs^VSFz6ooJ)wOr({h$B0n4vKpN!(gc5(v2-b2Mmi+&@2fA)H*1exS8F ztzA_$H>B*OFkLzX&+xo$)dXc`lgR z)Vwf_U?rzFjb&PpF*}iWy1Tn!eytprdsQPLsqMAqJtPmwCCCDoy`-Z&(Yr67;Oj&g zT0|LJ;28c~wXBKtk6P;Vb`+f_@$F5cc%bsM)2dM{1;Z;fRm(BlY%q6k|O zQC58h^Iavg2lDo-H4h94fm6jspP6GosM2U;W*vy2H`Hx0N5wjN`?=}g<|7t@!)qWR zFD)z{g+19CjXx@s42vbDR($^Uw+&>6fDI2yW)A&c1F@HEe5S9<#C+c`g^I_E} zUrA2LuQej*S+eKH5j_#S4BFmYA8T0Rn*v}Z>Hqjq|Gd!-L2@|xM^UKw7El!KQiZ!a zvB9@u->1)HluMI|Uc6d~V65q@S*lo2QZFsuN@tpu<+rP26hV7V z=64>lt1l_LT!^)f`t8jgRHzvcP=ECbX^Wgb1GHcEk=X!vHIHjmNIZPX7;HXv`^81SO}jz4#r#4UrCAIF zO}(P<)dbZ|ihs8C`#ld_eS~8OuYCrj7}_j%zk)q=GY`~3U5b2$Y-yB;CodQZ<*%wM zj^2=Q_{y=fBFd{DooKD?TN76iKOdHC*~t}dza^`tTq;AZH{kVMv-RMMd952~ziCu{ z$I$8ZGgGuTM7!mV#J*oLUR)COJzw@{+jEs9R#R-dwlP@uBwQu6${jPMo5wH{8YUQ_ zY+e(jDIA6M_h&LXr~z~o(B^ZYa>8>=U!BcX+lj?Rj^cjH;Ut#z%8juSO%6(C70y=% zI#%wC`udt0wsB-Yw_7!quQC@-#27Fg(f07&&VirUJ;0Rxhjwkv0gs;LEhybL0sz(9 zdDr>hzd!FUSh)GgePP@gXL=?2&C$d)TzaLqh)z&$>y#nHf)($Fi=C08egddxK z^sF;?K_}waLgiq~LKvi;q5S^1S#>_jn9o)VKQ>F5Z)rYmsSR4!+0%rlQ6vU%QV; zo2jW;P)><8=5$Q65Kf9}t2ynOK-cilXquy=G$pHmtx%VD>(x2-`MG9p4|kt{OaT_A zp!5@xy`$K6n2ae}OMHb7TXt?!4@du=t02{Jqo`n8@#_pS2ex8SWR;CZ)hSq1gz4vJ z)J)5tFg^oLfM9Fv&5)BK;J>As3aUM{Wrr1HE#{`f2dtB5is2_id?nv}N4eMrSRdI9 z3NpUaH^5zy$e&o;FaGlD+Ou09lJUjmvRH}i#zQ2%s@3^EW> zrdiM0k@CwZ=$;nDYXvcDY0opMNzBd;9Xt4?gBCqjuW0#mpaFEfhUeQIElJMn(G3i>x zg^%2sJ&!eIU; zsZ7KqxZW_Sz=5~O@vFs~Ci=pi+c%NePYho9f5R5{w(K6NTuVAP=#A1feLIS!(R4rt z&!h5Kiyp{Ut^?L(uHan&Sd}R$ZlGY{fPzO7;Qsv&9^`*2jTGw=#teBkV&Cr2ulWk(VEx`o;QulzPrk#) z2|wOeTNPQ8X$t~HCV~uGM_ZRB880V7e6j`TaY%oc*-OWLhnsXhM3g!a$P+OOc}_L`U#R$SnQ@k-zBgyu#@ zLaDz==l!%+S6YWmN1O1mLB&v$mHlZLHQl0Ami_w#9}LSsGEo4c^OvUsn2y|ZfPCoz2JACA)zCqE5p{y6^~SQJoO`NvbyprQCN z6_`*a)mep&JT^s>B+WFD@4g06JqB($95)Ca(jhU9pUFihHXdLKQ-3JnHV9FNm9}!@ zm7+a&s*fe}rTUFcz{CisH0F1MZsC{f$$%}%j{E%XeJHw|V@>-;VA8zX@Vn?9);e2v zh$e_Y>IWLx&meb!+ll*=z0=o~vrW3Sqa~w17g-vc2wY~-NIR08_#H0ewFmGGDt}w# zM|&)|0%X=Bx-1~b<7G6I@8Z98ziVogOHT>u)SXAT z-yEXV>5|m^Xto3Jvgksi zF5p~kCs?akjgNo2)T!Rscy*-2BFDVpX}H|B=EZsp?G#nyu$H)}q zyEsQS-&F52pE=Vus+Scx8tYFb%Cr16(U;eQAo62*GOW>j{cl0Iixy75qO!6L!o4-n z`_IDONo+*a@t{K8A$@bXLM@zGfOEpt8nC6eO#;n``5Bp7uez}@ z^?~suqQTYm1VOYoKH)m?lr>)!Hr-v(?;iR>BuVOqu35Ji=?mQ&O}=!~ac7GZ&U?mr ze$sup`b~~Z3!?m4wPDCbA5XvL-ZP1!*^zf;Kj6*>uu4sdrxsj)F}EQ@6p7WV^uJpI zX_%jT-!t2Q^_}`4><7JImW>3#GQ33cSP~<=%+NL$ULlR)?`rsJd+VCOzwD3tQJyYK z?Lc0DjyV?bjf!cJgGdI?dSKDVb$QL*4EYSjd{gG`ze=<-=gcsOLQ6PToPXSwz3&Ue z1+kM;)-^OA>Q5$bReafzD=I0%wCsQ@=y4{ogd>3NIhTG@}-ay{G`(M(mRsg0v zr%Pd|GDzo|d+{-iK>Na_j?jo10$;8G21{Z$Zs9gSWBN}k_Wu-=)hHjFA5ez3Zx8f+ zjazV|M9Q)2?s2n4cM|lAX;#?kINjdM8u%B`9@2=S|GIUfxo&ZLeqWFK=-N=sm?Ucb z`fMM&YLzp~X5*UK2xe!YGpN0B1(3){Fosemki>U7g&Tu1Cq}>o$BC9Lv@Fx?erNu*%7RT%)?h=mxmK9@|l1dLf^L(flEEw3B4hXkeU(j=KahU;pJRXhc5h?J~H)%u% zgNe1~GF;WV^v*fHf8_$aS8)afZ8b$7GAn{Yy@!<+&&lmOgrgn!;ibT^z@NCBNl*;c(b-laBhbckh=v8MO9p*u9xZyvYD?SPG)z zQ3*nWTn~ND8}@<7T!n?NK8$}o`KneZ@VrML@U3ssv3f-{+xE<-qr?gG;7I0|z1$hx zHVL#hFb(B@V;==i5%kzBxta%}h?$UJnlRCWz*WPs)FO^h)x7_UkNlzZ|IbIVcB_pVaNUgaRLm0praPciS@`%B#7PXD8+!* zPGpNlR9UxhMfONDUN*@wLZ4QPZw>d8={#2RNTX*-Z_KyQv;GqOlI*+e+W^t`SB3K# zE(IdKYkWQ(z|_~V%_#Uo9-9Tyc)L?}_p%^=ji<)I6s^5}=`ww(;{LkjKJp_@86a=O zE%UwG^mP=uTN81lzMk%BuUd9s*^d6}&=Bn+`Ui!vcCEfMPUl-6C@3nw>=z?9FNK#g zXZ`ug))1iBcZCS7^P3<}4fuN`^f6#ZQ)r9=LWqeUGyPdfSEY1dQP#NJi`mKAZp0(M z$g!&l(R@A&BW|Z&#{=S$d=d)+fMvdjGO!BFC7VaeHx>$FtPL`mnR!^L& z&J||0E`9szM+j#?4wj_OILSD{!h#U*c0jS@f=|`Hh)Li6=94Tc1TI4|xh*LXQ+wvB4)4Z$@-#-0INku{3P+*uZuAFMmTYR#u5PBUc9N5L@p zkJgDKmtn{oBR*$UPDEO)?j7(u(E|V4Gw1NN>u$bgg2v>V3FF(upwd{>+>!ruT3OJtoLN(1>P{|pdWKM?jVTWiU6#K7&(1!)!S zXMJr|w$ub6aeYtLAi{-|N7naz`I(qiD=8^eq5Fc6 zAC>MhAx#(1Sa7uGj%~kEarI507KB5BhzE zV7r{Rk%v`XSgC3Q_{LRx7Mam8N+Dc}04&<5?psn*9&q)W`fi0yi7Lk#d#BWUtEs;~EvORU#H` zbO+hLrZRwTw%O!l6PJGa(Os?Ub?Neqg#R*cj$*ir#ZAlW#YRQ8LN`t+R_oM=&kO&e z_gjeoyysX_@Jb!=eR$E4`E{X>QsVD^D6j{w>lk@-)ps`(_wYLua#*6KVz{w-{us_1 zp79?y1+}nL!{?oha%bhAO2=~1!kXBWsol#5I$agce zbfe@&VMK7fa%`SE=H7B`c-^nlT$%GRcTbSa?CM8yGhh=R@m$px0HW8MfI3hEY;7Dn z+jsI6@VYzqy+5aU1ReqX`}qFTa#V}?aq?W9SaeqFk#R@WeK39Mpskb0^szR;B}$N0 zhF4@wE0Bu|uU8jAVgG?V{=3MkqNBVn?}cis06Bs4C|uYHl5ju&3gM5k4ZHg{wd+LB zDXIwO^rp?D`xuI99u&#f?xc(ODtVlhT(U0|?E31RE620I^P@$4hjjUa?rJj+Yihjg zAlk3#`R(i7eiZH&+54XO2)J%U30?110j#9$r?(VfM$vnrM5G){E=s2$q|Qu6n&K>p z;cCP1_6R8V`%#K{>qq^u70gr`7q9&9gY_8M;zXG^f$h_hMCGEA{slQDB~Rc5%R(XQ zXZ|wyXP7MFUtq=0fOZ=|^Wq8f>hDS6C|^H-i|J6t>D0?- zx#X+yKA+__LcsiC;gwp$w*JVDHOFgH z%JZMG2rdW=*i<9Zf6#KEZuk*Apkv`CcCAa}Jh=z=|vugdRY@>eubM zJ#!s*n=`VLf2uE0`F$s0@mS8W;%Ynz!tf{v#`HN5iYnIqhq}ZiLtns_{8k=mu-jDK_VPXki56`Kuaktk9g9qTytW7Yi}`IK{3m$EovBBgT}B7U zx|9B;9z=3~5ql36r>mfzrD!?AZaL~@TfXFJJAfk^;Qv zw10We{ree2^^@;}6PUpS5n-lJ*Nj-^zdu+Famm$<`5w9+w*E-+OAyIAKg;aDf!R z-XrhLrI+KCV}olj_Y-o#EO6Q@R%UcIp5N%F1t=HHMo~?0&9m! z4W?MD@XP`x6px?P*Vpg00G(-I8x8>|@F60ZVwFKqPH>;9bvk^7hz1Rv%L?LJwpsxg zZ65Z5WdXPOTFSnepgB3-yxm|8LkCTSx^_b789e~$dVnBBYO!&8$`?rabp;!(UV?@Ng!hdf>8$uYn*m2!U0EA+dx586G}E!nSSwGV96MGPzE2=Tgk zrZ43m_w1ko5-LlGcB9T{YWA9x4HC}x##O2`yzRV2dVB&m*g5^YJbP zBr4QtBk$8eMX$xfnJOT&^hi_eg5WIBRHu8vLuDZ326BjJpi|2#BkFJCH^^fuGtTwz zEP!4dOJO>5O$nQ}y_Z%`TydQjoGGiQP=bbshnEwPkB2ja8g6GZ$TeFvP*G4P+1IOk zyv6bw!-PtWnjVPn&o_E-1AE`}@&xB821l8cp}2rT!rvso+$;~%EMjs}+gzH{3|Bn+ zm9O)jec+mutXM665D7RX$2w|t-|kN_p+#;dR$GeGtFef_pL_Xbb^~S;wp(&$*B+dP zKsxX~FSlduX!gtAlFv~^J{|*R|9uSKBa9~@hoZX2EG@rSV(nMwmhR5>tiNh4UJknt zH?vQmoL(K?E*=ICjrkyY5aONF#98W|<5Ksg-7g2l ziGr9zfU|qnH;e_M7qvme%aQmML&IwAAd4-5MVEPd>@#7JhDDmiPp?Mn`HpzO6vgRf zO)NN$-RQi0mvD*@7 z7V6RWyIF-EbP%q{HV~uOhTIh`Iyl%y0*N>V8Q05Ls**0>*_-lb3$q;%N zYimkKdHyrH_ONcAD1Wa|i2v^UU1#Z^8WbRL03P@T5JMPckApH--abm)dGOgFj0z&^ zwJESvfnY){gGk?VQ!$E%0V(St=CPLks6CM|R2smWF^vZ_n=!3{4z4%A?c*gDh7VF; z<>qKRcFr`-8XJt2VdL{g*efOd_(R`fijfV3zxT{@QA1me2#RFwPb8GXUkRGRA+z0} z#$qYh?R)R~7_*E-P1hgkaENaSXC$QdNd^r7alQ1iJM_K3R-obv=f5S&ypSxInmKm5 zKXbw`owujawncXC=@Gd*CU=fLOt9{8x}9_?`LS62x9AF?Hi65gJ(K$A$o#SVnnK_&d1e0j<}}Aa}ftfyoLdzxO0sNSnRecy!R9 z{TVdp6XsGLK5gw3HV_z!5ldz;2ZxJ#wPtn52ZLAOOsMBrJpoy(r&GrGJ)L))M(-ex z2r5BkMDTSJ4rESg3x63rNs?n>35zz~8Q}~Ih{aJq5@<#E#k_+c;P$sza|rR&{bRTz z6^BI-uiCYDc+;!Dp}F?Oo{_Yj3|}vp{mERL>Z016l3Y1Aiw&oI=96T#fSG zP|>x+&udG9I>I<{@67`YVdiQzNcf8EiM}f@MqD zSaNL+Z zYzBBpj)&ZV89|(6Do8;73>Nz0R)6d;0U-WNi#KiyEy*e2LM~-2rD@bOsC`8f_U0&v z>)A6CV2gXr7q-oIe`YcqO%Lma*|H91GKtRynxdsHYLe~I_8S2~jh-&OGbx+L6=}G! z7TyhdWSSNWbEpHTY%Xv*gQ}o)*rOr97uwDfDeJ%MMNgQ6)gPUVX(eO~kTqe95Us&s z^m9*ae^4e(Rx1VCIoJ$alC)g(y;$n;EC1|B<}zF$_s!i$-8s=kj7yh6&`Ea|?pD z3u_g}JhIR8SxHq{uy_`jWtOg|yJe;ABgC#l>;KkKI*xpxFD7X=Bdb)#;21I2W;cRa zgwHBsgDvmYycNG%!?oXY-2x4N_3d2Ct^RZu_lTf*%b8t^cK?DAMQ_ z2uFuM5Rmn0k7Cz7o-T+*q-*zG&en-YbYCzp)RWMzD{xWZv~Wa6B4FU{lO%C9G=h9 z&*13*2dEQ8W_;YaOU9Mxlm-qhug#FeQW=a>an<&%yMB-ZZLH zG?*hGwa2OPSo%owJCKKbMj%DvJoiw9{1}w+{AiK@NcH1_7?cb32kPL0h~Yjfi|uqc z0B3(re!eL0F(0-*R)lCBX+(uOL>ZosD+Q;myN)Hn^82@L^WwgV3sY9!lg&P=NE>)A zKz*}}0i*0ZFqZKUzdYT@wsn%-&Zh!?{{ zUqR)J$C>vxoBQd9Ue-6V2+i*QyzHWo_C32XZRTi*t@a%IdxS#_CSHvQ$&71}03xnM z-a5X~lIjEUabtz}y!oQ7I8QjQoQLPZ9nFmQ2~k+bR*LM>2@-1sekJI@2G8mfx%j=+B%OK-qh zdVyrLfWDA7S;;`H*P1n%>bNor-js^_hSKtLhEYt)UND&v*o;S9GX4na?~b+OxMM;% z$NokZuTc_&Pt)82G!cepvvy^{-Xpj8>U11;0k zH*M5|A(AWBf3WSU%v<|cU5%|nHa!1n69EGj>mc<=H*!V@kgA zPHP|Vaq~=^$V<_!uEYrV77@Q4VCWr(o55V)qrsc#?o^}2V`{L52#Ye3eEjKuzz}8x zg?&0$VDPUyq+ARvse&sZA<^~^Q3uX0+RdOC7!;U(eBP&@$ z(C`4{CvOu{ojk7;5&bWz0ulkTINJ`jq!~HcQpL%e^*wgjQ3v~fo+9845MT;CNCYX3ZBVo|d?6}Q z3!Ar{j<_4*;5f}36OEZhp1RElrGw&{S;n%97JB+vj#cmQ0Hq7bWYZ~@CCbOsi5ONT z5*vqxgNEO_n&J%;bxriwM8)(3xtj+nW73Y^Zkl9!;`Sy=|C>O6TE7SU$CpM* z_k4npJ=tmhkRTp-t(KrJD?LpiG<8`2+U71hi`F#V{4qtEeEqkG&y+`;vB1`c??>AH zt!A9&>_KX!Mj%=TcPs2iJDvVU@`mQG(n3U65yaEd@U|U_H;4r~s(D zj#uZOgJvnDp5^>0geoMpb}}46*XA)?}^x{-%*wBmrG4ffHLKjHhEpT zOb;I3-yMz&kK5YYf2F>Rr`8+ZSUS^hgx&&ehDyN{<^sW(%1x(AkpKF{opTxZy!klV zY0&2us8CjJjKLBcT&ve*Uh6E*r^_YVWp_Je0q&n?@T>o-TD0Yk zVBjPeo9vNbG$#p?pf^?Z=HRg+k^llZehNO!nz5-jY2e)~sbDajI5@8ArwrAu>(1%# z(Nb@ID5!Vw7M|DpcK8yd?BJ-~i->oxrA5T3T)=UuX|G}XfsCq}oz}-)hn8=!q$Ox{Q|Nec&JpFQ}&%n9rH!68c6p&81RtYcqNpcJd z4>uSmgTFI*zKTKQLOdthosk0Ve^kv@k$!KqST#bp`j+y$Uu^)E^F-EKc z*y3-QD(*x$p7*bWOdQh!xSP=9W5xH88;k@${^(Wy`FvGpKsJYT%2p^C=A>V**^L@) z(kb^Bg&&^8QQG3;o4L7`n>@h)&a^q&fFj{1>Ru>QwwT;+0*{fiBW5}$k}l%v#(0Eg zH-4l!23WKChh*!QMVfdT?HVNlEk~q+YEFFQB@w)ls_vOCJ~^U(bMPgno8nZ#RiG}e zqo_!sKI~KX!oud>=R;R7+D$4Ju8`$V)u-AJ&4)nLCiHM?YfSC2a_tNSu#7$9@sa9r zH-!^iH{LE=L%ng)ESY>>v{)=OR2i2tg{f6{ujXqrq623QK{~|^ED9qH$YSBM3b)NP zD=|b>G2(mV4kKrOpS(GlOKDn zRHZ=9ymvG*Bb+iXA~=3-`W$R#)W$Ub9TZStfD*;IjGN&0`k|9aF>3OCQ&Ur0>#P9p zj#=1aGWnk+Q$4m;K_pfm4ewPCJt767JR8c}y$s28;Z$!30Oi|aU+O6Jn6@?U0U91B zM)oGuTuc`cV8Rg|bQg+%Uw?r)ta@)1rB%grRl0ePC69qHNO)b!M<{lyC*4|tbHjt= zGzGasK3bs3;a%06;`~?EkSH3Y^%c+4r^NgKBfQThxpk)NmvCTK+V69O@ogF(C`jo7 zMNP*U7x#PVGjAz$+-k^>2tP~46Vt!@z+{)is*q#hejh$}`+BqQrxN5HlYC?J~(rS<_A zzKV$?q+}BQy4JR-8nx!vrnomvkfU*uJvWP%|3V3X6{pQX7bPp-Ld7nQKI-UJj<3e$ zZY;>Zww+hUP|>Y#?(>axlhy^s7J4$x&!p&$PdeC&b@3b`V@T#!vLG5hH;A)+mi+o> zf(ihpd+uNMutAEIlK>+TW2WOASI;|Efa!I5&dwS5_%2$$G~e>?9`#nj&+~RGCVbf+ z3i_gCo}T)!3fVm!s>k%=EMF5g=t)BYwiS~_3ou9fB8o*%J$QF$zJNCG( zE1+SsrKyA>&?F5$!OA(-$;ua(;mgXg1)Bs0rKeE^RQNu;tmo7!`DCe4o%U6`=Z&u# z-n726iN>mZ;}9-xv*lrcwW1nNqHAAdgt5MDdUa@u$GvpC;7?~Cd$qH0S;0{BBm3$! zTiUP`{Jh$4D+t?OxVl(aP_&jBHX;4TQK$qMe7luKWF6jV_nlTDr2kG0#DcEtUK-5@ z%kt*inNv-7GG>G%YoWID-^*5u8P#<_&SqZZyx8d=Lt za4>JRXgyv+Z9>0y)Ga0~T>A!3`olwVJ`yPiECze$?x=)$$}ZS~joiYPfBE9qNllB_ zPbNX7uHz4I@rzw)YmDAuTuEFSZpd@Ui*Qu<*ZMkkWKTP*5)i-~gN2ZU$Wu~L)oYMP z4>cLdI&b@25gOOH9mOS!koJ~7lMQ)UMyL~q_QZJ*H*dkndD&4O<6~OIO$TYGp67QY zP0<=>HGoLqvg7ioq0PZd3%v2Gr{mGM-{rt-y`l~F3fHaI1YO(ZMvKE;#0B!@AJJXy z(=9!hdzkHin(EJ83jZ4%5`f)Bf$j%XYuNOTa|puk1`&Q-CBgkXU_r7r)8L*#@H9fr z$zSOTHd3oBi%y$5Ew;7)3ZXUz)`CnuMpH2F2G+)%J(k8l{1%$NdiU*AmxFP|YDF`j zT(w-5|L^4KXQI^Sxp{5;rocck{9yx~^FYl#N_lc=+IO zF^_EX7`vqDJQB)XU1c<)Nq^g!AuKmeTir>2C0Z){4K0#i>GY>!lBW5XR;==Sqwbq* zs^T>XyG@mdClwqH9%I(;&F|4vM6%UfDLN)D{!k^6xp)1M{HL_r6GQ8Qe!HRGs3!{M z0^~KQWJwjwWq}ar@Zcag0_q#10L^cf)^-N@TWx=)j;YYh2w^eWn^OvMpLPn$f_axp z_?aax!4ZWl@$Rfol-v&kuvc`d5S&LlvbA+%{0~f}9fA^wY7B+wLG__{@>@$$o~^vX zo7x&L_Y6EM1?M(*_6$w433$0|EbZ^1MLuu4;LpE;%86Fp=j3dyqZFd2Gn&HWjdHGl z21v3JrIlO*U#f&qZ11g!3P`|G!*dtA9+y)Lw&Av# ze+aI?j5CLZfcSd+6iVs!Q2cRP_2&;y7v8<$duQ2gW$j9@AAp_T&>--Ym@!=9j35wO zLtC;pNU=RYRmt~B{~@)2q9?4Gs~N7d znA9`q!CL8pyn~^qxCsqV18)*th+gFCjiGh@!#?DVc`L!G={q{plBpR~jUNdl4zh{BC z>HZEIt2jzNxN%2EoabPcImieD?dD4X+q{1Ur$0Xk6sv?X2JEvR`Ri}Q7Zw)UY|Sw) z>@@@KYDIK8z>$o;bvG&c|0k1TOjIz_gevv4u~qDuL)eyyiV2+z*=HN#^Qah7gl-&J zzP_=;J>EJ({hYl=`$Nj#^QkewGCIf>4r4-Y#1MNeUcFqeY-XyR2@aBLMnTVIWN!2P z^^%*I!w}_uMUS^bS#}kp;as;TcSUD(a0PEQF>Oma z?r!!^d401)9DXxMH)EsbW0$BB$AMA(I~x_OtzVwUNhU4cpF!X?M-C42TAyTU|LbD> zrd>~7q14DMr)cOSZ4WG7i&xd`6J1<>6AKcQcJ7Nd*vPz4kccn7@S1lYM;;9_v%90+ znxNNgCk$M*=ilLX)zH^yp#-{Ur*azyMsk~(5Ylewubj;MmG+lelpn*HbLG+KWk{sC zMtf22Zru$br+d$?A^Z8h2A>4_ktnLn^L$|{FgfRQ{CygjY~1RFf9tZWb+ux%|R%g}xw2U07e51X}A zQyaOjH?^4jbzNT6JWFq5NpX^xk(0uI{gmcN?`Ej>UYZpEc_?U z3{mfo#M(0E7_s?VX0*T4=2dM#Bi`Ff~A+H+3qr zdH$TBEi8NmVpu)DJr~EJrq-x$F$}*conq%?F6$RLi^6Bnhpbig@&l_ozpw^YTbS$U zFFBGIB1LrvC0a#Mu$IHQdlp#v-W-!z*Mx-+STZWXH8wl@3`p3rx4}YH zel9LZ7g;{q2GE?FUY$+Sb6{7sz1Z)}67#dOOyo^*F_&?6p7NKem6X>|Y_uEx6hI_% z_xBp`FHEdh1x;DrERX^X=j>w_kMyt41P#WL7 zZxMf$GwrH`655h8x9sE_G}xzqxNwh$Vqz}nKHu~#6?GOD)0nk>;v?Kl)}rFZX>*5l zXU)n=y`fv@kQw>G@X11jbd;5qDZZ0nvldr9ZUJNbDJdy&Z~%ExAC;M2^uLIyV{VJY z<_rxBbFj5#K^QJt#Sc_)uDdku3C$Kgd3kn0z>A}c$=KWmOUFKFeOK$s(8Z5ZOjKWicYpB=`n1E|_gPj7~V1Wi`&vf4a z%1Z|+)(B^nkB}K<#I%J-$FbTvJ3FgrgT@3p4wkXjG&VLu(jA?J| z<*nsvzyEdpATR>3V1PMphN1>NIf9_Jwsy-A8>fYNsz<-x_1&f z*j&uL_D?V;t86{%W*{@KI4-D!5$Xb_snJMhT%tG_6KxbtE#|F z3%S+)Qs?D)f-0$?^4@u7Mq?+B#lyh+zf>QM$v}p@6yv~vNbpX)MQ|rSp|vrfU-QqP zFM=X5W}^e6zaFu9ZO_#I_5bj&GuhS)W{sCoKVfUFi6Xj zsuhIl+6KL>t$27dYa&Lf*nfd#HNhk_pBW&uY=tJq9XyjP4*4IguHR@eDcUcG^KIm}p(yn0JtJRRjp}|3AdA3fU!C-pRXBm7S zUjFYuSf7d#6R*%AlhGxSolTVeNeyrXx4_K;zY%tbguBGZTdo}v8RDS8#RjPxUVQ59 zEwulABy!5v^2Y6(Qn)U)u9iJHctOm4ol&}&_A$3bsV3s985D|+QVChOlpbbX=}3Mk z)k3c%{LK2!(tBohDfy`o@w?iV7E$A(&vvQE^Fy|BU?Wms7>M3e0t>#D;Oo6LOoXm~ zLhZNlk@0-9tO_8rVmE7bAu3%t10D^svww&C|D&Y3ZlEx11vWl?T30*TF<^S>5B5sn zu+@{d)$0aNMVfLN36f`uq zYR&W71CJ2~c?nvX2Boh{s3LZ%!tmVH6=Pr(?#PnuaxZZ_ zCV+)Z$KY*JB<$624aA;}V5~%c)3T+FlZP28_UmTFSL|*IR@`7*0X0`8Z|4O=l1##qK!W`~OyjRua{xs72kir>*`&{Y`ip^tw(1vkHuCW>|4DQkk zR#@a?FEK?cn)}R+*F@iMJ&|%Go%QcO>LP2j?Zsda(q-pNHV)USK8hiwrZ(E29y3rQ z{V;SfjLimA3nS$Az82k>XL|NF2s5R5rpk+N`t)qgqRzG@@!&{z>Eql=Pd?CHLM|)s z#C+Wqf|1COwq0H925DjF=D3u;AW(1N`2U9XKaspC4keK~qWey9j=vgv%B6qQ(x(ME zW!SgncGwMblmGqQAzr~dvAZBYfBx(c5=k9koH$!$*cu)h3VH3D3bS*ZQt#>6*$m}S zu<>WVQ!c?VgeNMnJH0KLZmRF$EIXeiYWh}sh*H?Iehlm2<98=b117PQZ!zo`YVNg9 zMzT1j7uDy5DX`&G(z6i%QC%VG>oicUhm$0%GY1AL!dcJG&H@uj@HN9(9p{@VWk>~e z_B;)1b&fVE^_qUihQAjgN4%&O-?e3k^UutFP$WVVK}6Sw5QKNaF9wx*Inj2J6Ef%6 z8-CXp0Os@)1Jkh*0AGzM^D9WyYm|HIsw;x{P0ySo=;LI{JWONZHjdvKZ-YcSS7I@^ zl>l&yA;XsiHbY@NoSh{yBqSlb2q0|L*!Kgz zF*hHDk|C=s#+)&jd(Ai5-;d#frZG*0K?tZ2eo;}A)|tYrUh0Q3RN;INY-(BT`5H8p zxrwdiM+OI9Y(_s#e{J|9iFe?oL;lX-G-gAoQj^{L`RuB~glR`eWF&^3U6sDtNP?($ z^S8{%)kR&P!>}XgG_FSa>3!zM|MPsvaTXyV6bS|_fL5pmg*HYJ9DHF|0=OALCoNmw zzo%$*KNjh*tNkAlzd1-Es<+oI+xhc1W@Xlpe~Cp^mTjHUUmWmXB`-LSmw;&yM`Ar*zU_aG5~wCMTYO%n5+c9lt_1$B;+@=^z@#siJ|v-?>*%&M!k zb6v>`e_Slz@HRJvEP8+2+;rjYZazFZdjG6D0S^!FbZ`^HXBnSJo@I0MBj*cdFj$t! z$M>|nRgCmwkUa*(R$NzCv9(PKqSO4M#>R7ZcsB8#QtL?I^Cp)3D+KU}rLfO;*wnWV zc_#++Tj~yIVC7 zqV+RmA8GHr%YmdaUU0`M!i=fc4dpZpkXn_Ls(Q}fH7bfZhR2eAsPoV6#hXF=Nr18S zB$00&_L<9Z&g&~0;^1(}UHe}F8tQd?p=yLB1J!Ol4| z^1{HaKb4X8i28IX^z(Tx;ZEow`$R(;ck6)z))Wt>VEcbhU;J;wU9 zwEiAV{`|XHI(8SrS4%5#X)w}<(b=bqtm_vk!4%WzjPejr3+Jw>)!?fmuSI<s_H#IC|&BEZ-i0R8;94F;Mo?uW@tyDOMbTeu|P?(oEP-T zF@#%ZV`CVesrvP&jk%;Iy}Y6(dr1%QUan-<*z?oQv2AWbcGRcIr08mMiy$4D4B4g? z*sLy%7EUD;G=tN%>q;JzpZtNhnz6DER_=5NiG#=CrcRUd$|IYb4he=$g`5JkQP|rz zk;NSF%frisUtV7BrH57%YIFl#NKo-|qM8_vf9#=vm#Oh>A^HCbM=-xf0heOQI8V9` z!I;?%Fn~O5&);Q5N<3vv9)jD9 znY6Z%o$#oeY);yecjN1G+1Q+l(y~1@WFfjFx*?>AZ2Tfgo~iI=PpJM?_-++Peqke! zTtaj+ggrSCrPcn|W$cs^x>KqCkBmood3i_6-8aGJp~p_86ciMD3q5ChMxLiXp8gq` zg=*}8Q0{M!x{U&}7|WDu;kPCnV^PYSsYAE_~u_`=poD5IAzc7t>`P8tY z0^UAP4>IrkLp{3^f ztc-0t6^i0;9l~HOj{;Esn3~c*Y5Daj`|=4GK<3Y2#fC3Z$d=|U{8|%O5>Qhm_1W1j zZTU};g#3%T0U7{avvV67Chrw1S2amnz?|!a*+vP>t5fuGSxgiz(%F^M0H`0el+`Ol zqd4(f5S5h=1No7N{ia zdTL-r%hZ8{yVDf(-<17MCyPNiP`Lhx7nGlbha4UskgEhE`i`x5pOVZ>ycoh+>V&~hu$cO>a12)i#ZJs_~=SpAw+x^xxBnvTL8B5Qe1;A-X6?vSm}*1^69m+CxekB zj_GHQl!UjxWCR!IrRYzg>k{b%8_g|Fy__L#F%%AS!gOa|&8&ElM~XFYdW+BFtynJQ znN2it_#}R*EjlFJi-P1U6EJFzb$+$3zn}$d+WGh<*OxwoO=?b7D>M3=8C#u~_g*fG zJ)^0>R|A7|J=l;x?%Dt{IM)A{B}fWhZlx01`(Ubp|5pkT&DgFSR#yj7L-o_gQCDlk&geiHkV5Fr%Qb+WDp;HO5^H379`F&I4R8lRxtU<>B;v($ zh0OHyn+vm`#YDoCfj2NJNqkLD@tN2dq6E34)5Lb^`=P^%BFXwvmeQ7KiylA5`{EQ2 zK*o4<_GGz)q+5MpBsgoA93B~|F@i{m@F{tVd) zu)mtPQ!v?&ZB82=2dOtEe1y5LnAHnuB5|x;28i%U{((d}u`ID0gSsxrQTN;!(&!~6_kt2$ zcgSe^xw*NOmsB<~HHNy=wnif6LC-w3gWjLXnwA`>C9A0o)52&Aaw(nKvDVu8M?Vb% z%bvN3mO1aKW!>VPk7#IC)34DeTk%NSlM;#B>GiWeplksJRP{qN-}@1;WlmSXcW_PL zy0_35(FYChU!&T2@@8NrGIQd!UG3UC;iJOz?VQQN1Nwo&w`-5d>oxnQeVymYiVM8b zIfkdS`!Zo#cle*&FsCEY#a;;k!Jw&^XGJJUfD0tN-|jOmY!@;{G-G&!@`01 z(0hbY1PX!W7oR?TGO|Ne&2<)LSJJLw1cqVQ&9VU`w*lLu0U>}sRZFv<5HK5XeOP8x z!W-K;Tk{d;ylZ&2<^YFWm*z1s@JF)ge_-H8qDx|;zjQ@*vc3$TPP)kkC+4>g@+f}s z$0M>(dvEjpvwK+f_D@89-G(GWNqI}sS7i9R&liMLyfr@{p^T-(GHK+g!4!$*J>F4_ z&lhuH4?_tuS*}~;--u|nJ8;Uw#KHGJd z%SyB8#vqTkZZnldO*{5IUwpP=F(iSwV^icp?qoeyya0Sd_ z)BM(C)ht-KEOkb3`Ta-3!%M$PF9{)Ffc_6yC6)}!(EmPCZ1POq_`o~lgyR! zJ(n-;oC@u7|DjkO7olsf)CtGUe&Eo$hCFK~E-o&!g_q|QUz&VIdU{1}FXqB6PZK@3 z4@ER4Fi zyIa=s5l2W2xrbR8J}qvFS$SD{nTgZ#_-}?1CMugVSF#MgWBLoM(-=Z_CJ^CRI-|I* zE6%^4^As-Xvft3q5dFN|VC-sR<3j*0Pmiz3;|yBME6F#jLYwuC3?d~70%Zubfh5OuyD?)J!|0f*uShbYQm z2pyRMLGiOrTp>-37qHGu_s{XAdkSM~zwslx7?9gAykeX|vLE~W`7lKb1E%!f56B9m zXu6ZqE5Xva19~Twn{3~T7LC)D8HpMiKl5+6GE^_%3=R%XfkE`Bq#S_fN@|a(+f?HV zTTO00pZPq<_e`P5b(KGywcnt2NO$4r^R_#$Koup&ty$%lGcNTsGg9ffO3`5M`{1B? z0z3cNPJr9>_B$w=upAVZ4QUa+`RyB57fDTZ6zRiF4;(fIfHM3p;@j7-x$Z7{Wu|@6IcUjoK5>QwqQd0FWZXp1)u-|EAWi5>xmss%0gWi35_{CZ5@cWgCILBYB znDrZ^^+RG)wQTE3nt^I2cFf@D}TYXYcbh8IL>|Bxu=_+?SI*L zjmZE&l|g^|`}7T+5C1{|J!oMRyLS#3!>|zzXN@LU5_m)~6NvyEaxE>bN35d&rEjY}$AkBxOg*-6h9j|GyQ_kMp}j89uloMcZ03<*aD%z6`7~x2W<^!iNN8xN zl#xI>KeMAzEJJlFQVN$koHBEb;5Q{nY;%D%e?q!XYNxqIrB%BLHUf4&e$cM{3qO#< z2AyX0nej-;GT43x@Mw-AIPJqbGyh=&ua9wC9Ifj|f9AdURk02qg`%6w!EmhaZCj7z znp@DF%Gz=oO!1%FDAK-FAtHs3C!@0y52La{FUG6&XgD0)S1IqeaT8s8n*HHnbV)S ze_p6?T2GaVMr0bpafYv+o_Y)q zIgCJk%bA>JCdBdSz}AWDh*q%8LGK#OQW<~A2BQ`X6B7sEnhx0e`CRp0msgU z1Xc6fUH<3NWera!tR{j4On0O_MhS@}dBmZVx(NZnf1Wf(6Y$A? zPh01$UAYU`3${NK?35Ndze_0;%2EUub!Yvo|Bt*o^%FgOl|D*>T~aYFCI)|C{U5R`3XXdqjT??x_Z-5+%FQIXF~mW@h5a0XyFGq0&1#E9<6Vzqf|%IisiT z*Hu?TGFWem`6AY|B^@=bLYB0hFV5USj~SZ5Du!Pt_Aid2S^-Ws%h zj6a#a*n0s=gL8An#q5(sB8;AA)sve-x^W5lq)2ZD8!h{L#GD4dSTODo`jlL)~rOs5=n`-K65d zW}6AjSxWVpdIc7%ynFIe6{9l^wZ^~aCJ?;*D+Oo=pa{s`LVF{^Xi5carW+g6U%kTV zgtxYerDtao`1Dp>FC`v6W1gsa(EB+shHRibvF{1%sNtWF2R;u07=UkcmYa54YqPSl z_%ynat>{_oH|>rEt^ZEmwn+IWAmM}J0%1$c#W|vYtP%vfkb+5t{Q}>$iOL4-;_tf$ z6A5ZSjACO*R!6*I59O<1qk$s~Hi8+pwI9A4#;fR!u)OD_FE3{MjKz)7Nx-_J{qN@j z{nLxu-bDg5cuh@>dRSQ42Nl{Xjm9x)8_7!9q!PE{YLxsB-9vPZi-1or2h(~;lDRjQ z7K~pWLEkRc6&4m&zkI7zuM(Csglwn4pY}@N6Rp)9Nq)a`K~W|w|5tm#wOuT5aN28d z(W4EZ`qzc5evZ8;7&+QhF@)tRx^us#RnX@)wsM-qGD)RR*NHxPm?0_Q6aji#xO_A| z@vcu4=V;eVL{aKZwuEKedFiRHV-7eePfATsQj>HMHOJ1tXVzERGgL3_ShWq;1UH$fwFDq%=NIuwmI7Vqi|{=7iKX~)7=*JCZS<=Drlc)D@2Qky+tP5bf2WO zc{rK@6krD798}a)($-sFOA?PZin6IrS11K@T_43GEC@^=*uDS#%sxo|@2)HyrBW zC;OJ^{|#Jh{xW6KS+|?k(Rsh+ULnznC}<|Nx|wpnVyc;A#?8CuZ0lV5UR1im(TC_Y zpm+*Aqdmqgz@BE)i=6r0Jysi_4Jt1^f9&ty7JnH8FAi+0LsxPtZ7+~gB~526J^WWq z$Ep$_smYp)bB$78FK7=ZD@60wx4<7@*El3{zNg_N(OS%>ykBx*CKz`12TEm-npkxF_Hf@RSi8g_W28^D@lmsualM7 zYlk1;fy(QqKrUqs)ZV|}fn5lSB*|R%ZIKsd;=lHSTD%Wg1%>EKkt`TQ+jqa4++zZR z%%!wAxwdlU@7)UoHUpJV3`BY?Ib-;}(x*V_sQ|j3JadR(Yo#0^fYx)10}(IWvcq%3 zPbj(x_v0rCDd>|HT~{56_q|BW_e8#9b)av!CL{|=_})&P?nRFGLxkHY@0kAK6ZJ(a zJV``F{wzn$%gtGq6qlIU8kd)TzAd32OAb$l{+B8gP2;~J2@FNiz!8m5Lj>R`Acfj^ zexIv>wW1nj4H$e;%yge}7S|98BOl7g1xO(No=WQ65jR*_= z)lT>_*fW?z%X<55dm<*JcI%g!oa#(0QbLA|L|N1&h7m*Appc%2417pKkS=Qk|J)rKGQW4*{IxHKx7+OP>Fp>`m z_3iJrGm~38WnkY!9OX&m8q;W83M~Kw?xsW%lWOBjsuJn6ILWAtqgBz?+vs@w#3^On zl)bofCF{*=Uupt9R(kqsTxnPt)XUJ_+$T3*eZJPiwPQgf8kI6%zs6N11xvJVf|^+G z#)P{4yL!#0OqW>r&5Z#M(N7LVAG7sc3#Vm?#XWN;W@!se54XO032WLn ze7bE`(>KrFR$np~jHgTxtio-SnvRqVgvcQwn3~(GGyWWpvzgm1Z+9NXyguM_^R{@C zCvA=M2H(zB=uuxMp7_I?IGEqg6cfhYf|Tb$2#S~d3AidLJ265MIizq3G@trlobnZf zeY(=`neac}BY3UVndsqpTnHu8P}p)>XX+I0h}U?)rU%hveF9inoz$dum-gPWizY;p zJzkquL!`sfGO084zlGnu*#UOs%+AhEc9HfS|DNrkQ-W@2?>Dqv3_bQ@ zg*?793dv*zhJsI#{SPcT_DilDSg* z{N0xsCJEoTzMIPLy;CI^;EWK(YEJI%LmBe@x*u|tmdm4E`4Nmg@8fL(4FOA*3JFU%NjBMh`{nFO;0oNl5d8e_3;3zSV(!FFPPML((V0={GXC<5@Y4D2K-1C+?2072s2@vy(a0>SUt}C z_L5~#W17EOBtZQmAGDabkN-V80fBu{4tRl^ENR`f+-1v*%|`Kyae~3T+fgj2smuYJ zQU0@}3Y#hZor|gJ^h$bH2-*ie2&t!YF%;rl6=-};Tc;J zZoT?z0*5r^rl9Ib(YMnn(9-aoU)@-Tf!O2NpwqMaDznLj4D*YY*jy(catHu_j{(rJ ze*szzj*-Q=&6(JIhJLepwUa}*R(T=j>3wSFJ5#07s1D0LDe2lcZ2cQMvFmPw8#1Fc zol;kTetYvlhqF99vrIlDW@2qMtOK z0bk_32GSzjIS=d;h|}F2EFD$SSxLj$eELv zGABqy{8(j9GGma|bc#1th4V~_<-#fS9x>NsaWTM|UVQbl7&Tte@a&p}6Cvy=X#CLlw90%hSeDQk!z{hKXodFgZ5l zTgs{(GeqN!WAPQhhS_iJ-8*)VWE0|2KwDR@7(n>|z+N4hXy#BUE*VmEI5z)}2IL;c zeAIZYZe5lw*MCLQ#aSznQt1=nj zpM5|ACGO^K%DkGtO|m;9<2|@Zy(KjpKK&yzOqBil)qmTp{LEXna;^SVfk;p)zYb30 zGJ^X}f5|7*baV$Q`m>+`}Q#WaIkGF5A z-}dKc_zmPSuw7!#G{gyz+f095PC6v_si<*lS0x{wLKU_N<8_!w6Hvv&&cw+87N#&RQBcr4#I+{*u?YCob4G+X)C zl1o%HTCVZ(qL;5sFf0fqq{H*ET$1EMI7|n#gW8WP4fZ|p z`_wVO0zzSvV7drHz)?}s-`nSlxiyB4 zERt)oBp6syB-(@i2-sr7lbW%5E zH#u}Gk5%%y8AP&6Y(fb@W>;j)mS zR9;9Y?()XD>VHF7c<2xrV9pUhgN2*HlqK$e8~97niP!hlm=6@{`hL{udrMgxWcyRQ zRg5Cb9SB{63CrX(4j$eQS%y!_4y;?Tw>_y>=St@+s94C0R!)*~Bg9(XpsuT{!w^6% zz%KcfEHQVBP?_Yx-EO@7y03S3KTWP?$YS9Rn~3=L$))50t7V9%^q@MY2lO)3N5+?S z>_+lr#HSWD^^Ws$xmDLXXwu0j??}x`0M73G{5-_dtn=%^VDMp5mSO4Q!hmlkM+(`F z(`GfTe4}ubnuW5DcU%R@$Cu?v##}lszuUNB?~PGIE3%y zWP$?yE%NPK-|Qv&;mWg;9z!LGqDZ2bT)!4$pz zG2xtJ6Xy3=vGyh_{)7*!Y3Yb|)s<~C|N5I(A<4Oun#H`02`XMEj&9rz&(}D%S2`}v zB@z2Tc^vA72}YJfeK1OHeBErwv_4FomC}}+6JT)!YdyNwHJED<2nw+veFmX~yWQkl z9K=PIW|;^hw;cKRDoOWiZ?9)f8Iu_Ag*!2viZs&DGQadns=LBvkz5Sn+9<1P#T{7i z{Tc1wJ3keNH>GLY$E4e{BX#-KWWdcxZ!M}xqv7OkPlXDrv^KX^TK%O|c9V8FE-U6I zz^(I{4{R`Q+3mgsYv(>Xl>y=26T#zm8vo-k+;S*Lq>^K(rl0%#1D{{+H~fvyzaf5P zt=0**%S_(fO^qSJb+_VEHz@qjTi5hTsyAw6)VB9^43aIjs?T#rmY@MSB>v*BhGaKm z!DwUX0bTR_(rJ)$DZ=Y#A@HoWrvFA?gloe4uQH}71m(s~7y31P^5DQ4fTflUesxs@Ak(CO|$U7<8+;*ZK%@WuER5LCq>ghXaZR@`>3jOvQuM5TJ8#a90e%~zeiws){U_CpE1*RU zAzcl`U3PB9v=;jyrai9~@GL=5IWg_Vx;4NXeB-7ryXJ~}N7o(R2tM!D?pT|{c%SDs zXZTS$XVB23ba-X^a)gfevEQ>x15e(4e=pA>=A<8Fm!~W6RjJL`rRAI!)+2QD?sV-o z4gq#UKdsD6JK?8D>k(oFpb%cBQYVC6NJ!|Ny%Zb}dUVaD0f>HfpXv3}?GD3FVJ*6o zHG%0Zy6Cq#D|1w8GUvY4mcJFp>B8s8dY!Lr3?&*fI^9%l!&jYk)7X|96n%K-w`uBGrFwRkhUv zMMuc`X~9Fa*wFt|s>mu=%RgLPO`9YRaCCDw29RL~w^Ie+ATAskP=fH_Y?tN%D# ze4$kTHK>;J9djj|!>JPSQTHwRCq^GG-M1Yf862F0p${;5d3nv%(3hXCu5nPPrWvkKXBG7>R;CzE#qdg&Q3|q`KcI&9`XS;Ev z{Q~+@f|;-zvdR#_oU`aR(G3pvet!u0zSob7OtMegUk`Ok{Pz7MQQW|ErBjyEpfTyA z#%JAgfrk~%2jjGt7n~wBylm?`X_U zlUa*IkK{L*-71h#Teg@Cry za8}TYlgW@0+!m>3-UBhqQ3Hr&8asALB$@vEbn(!`t28z~Eo#HgZv)I}vZ|ckM>=m=UXJd2MC0 z&3yG8##}4>fJsTh)YDt;d3&Y&7v9m4#(mdq?3+%{p(!%T5hQ*2QuMMo%Q0$Vr+4#X z7<&-Jow%6ww&dJ1%--R#tASWqKW{VObP??mYj^dz9ax^SKNWSp!Tt8c+xJOMhW@jU ze#<6+9J%wIY-C9;liBYi6CJ_%(7Fq%zb3NZvUJ86%^x$8S1Zlm@?f=+)Ro_u=IsaI zC7w6)l=KpKi9e2LThRmQ$?1)%ls-3rWNQw>@d_W$x~wGdH9VNDsUMCrJO%xsBv{0E zid1t?sUe9=HEW~ZYk|R2bc9!|z!tl!w7cLZtFSM14Cx+fZLG=fgR65Zwc92-a_&Hc z{pP9@Kf-7n1tFt^D^}ULs6SaV5wtTLw0xNC50AfI&DkrwjCp!}7ANXx3ZR_^Go8MV z!mk`Q!DJ$DdO|Ml#jr24NyWdwA20xVYw?r+8@iu64GS|ZO`Z=f6 z%|Bk85zyry)_e>S^VTM}XQ`hk^}e!q<#(_)8l0h0^myO+q(Kh%$hXui=%+Wvr zIp;eTp*y3orAd*f-0B%Tf|o!H8JtEW<)xXsCj_?V6%gJX#bg(WzBZKY`{Ts20fX82dZ;gh1Ho@;`7@bZc*96U)(!zuc^mt)Jnve0>yG1O zsS*)e*eVS)w!YMQ^IA?oSbaBm}eh0yOMS z^b!S1Vge*h+K!hcbBh~2t;-9k9$|6-)PB2tCC|oPlaBu7qAaSY2!ez ztPWQ}mWM%5(l!=!a&U4$YZzKS@votsDFrk^zR}n>ra#9+FsjbIEA;hi@I8|ePE*@6 z8ntS%`Q<;M&PlP)DPKo{IWU{O(Z|oE`>D2kJ(`Pf=xG`kPo;Xu*2}9Vzwn57cphy} zFP`+uP+7d3)qo_7TIY#}aiNZ(yvSqXYdsnh%#{+0r*tE|_8)3stcZfx0j4mJ=?8eVfvE{SeSph5O-w@UNE2 zTZEQ&bp29WdRZv@j>E+3$rKM0@e|kMo~1v_-U``bPc?e$WxDpT>gPpH*H-ve@C%mN zXQj_^76vGS7}tRGc0+C|wlcCm+jPhLm8l`)le z#KVU1(r>xT(fXcP^PJ>*>Knb?>3l-;Ujt-d14FkTLTcE*G9|>IvYH5)jSWetl5KT< z`Fa22(xZr>Q(0QtDpP!RSbg9+n1P_&*OLB;! zWVXYKV`-W}ZTDu03erXD_x71yTrSB}DIm5BZ(vnDNSs#Ou!8LVB zAw0}9OY;k6GqY3an|^X)OU!N?|Z#-;*SJNY*T4 z-{L4)$_z5bz9vhSs1PB$LL#yxvSs~$Ca3eB^Zw3z{kytc6Ib>9ewJsspZmF=f%l%J z|Ex4d>oE*k}xzKWh_Ma_-HW1adwuk;qMd-T%5E0E|_;SAG2OdW7)o zC}6np9a-fkNqfHeh&1VZ?^z&=wMF7dn{?FQ5E(Qd3!69Yd@9*^wxT}&q$6CCL*d<% za3jX@Nv4u>)%*C;G}!3swb4=zZvF0dHxDJ!#p=BQsp*>EZrL*XgV_ zZXYq=AG#DJNND5(7ObVr=;7k)NSBrpqV5jtqu}Jcyat$^^!K`Z#nPebGI)>%lrdrEk(93P~g(ip<`#)?hU#-SOu|hyCar2ijjWx{wDc z@(=Y}$K(ecD*usO^~q9D??gU|jftV!803x56FYr+B=WG`GubNxA0L-xJ(fV|szW>x z)}!A-tS+9o^1^c5vc~p@^AU;J$zYYGTb#>H7F%Yk#cbWX=x4fWu!zr*tb9Cozu6pZ zfoH2l5U9s;i&;OTMD@M39fgZtpB?4zirD0ZiVrYfZUKmTiNE4YfC683qh8iRN{DYI z(F&xIkfkw$z((N@___lU58<9G7y+Y=u=D=WP5gZ2W$&lf{8 zAEJieM<&LK6%9@9T(xK46(6~@^Todzy5+39qkPrg$7cjk&O^MZtmQ*qXEWKMSa54u z34C?vbtUQhd=wJYrFu5;t4Fg+CjG%&`-j=%Z0bj+<7xT4#e@SUq=zj%GKE<6)Knnx zn1SmPY1Kthpl>F^O@H!<*^OyjWV9dS=3@bR;i|~e6>=|ci3BKINZDoGAt#NQU+7$K zw|2tYv6%j!y*k0vw`piCiwv4dDW65j6yLp55V5FM*mcMNK!rpPXQGhf*UfH~7#n)7 zXw5C;&4f_0rsSFNioa#jqM=9GrT>2 zwB6_EN59C8g8qdY$pG9vCyiMJT5Xzs2`M}%+7^b=C(p*#6VELhv+`2&9aUSWWu2v& zJbT|G)#zPh@E{CRa$1cs;v@mhCmds>Bgv$GQa4nELqyzVm3UcoK0~Yi7ebg!#<8Z4 z-(n;`X~``**Q|IW3PIXXy1S;O&lB&+|FgQ;jn9lVO5~;dbpM!~Mg$6-{eC$y2`Gb% zbS*t>dJ8yWUSZG0g_dR7_raK&k|Jv5JA3js0YBD|_WNk*eSHXpT#NBR-^Y489aiqY zh-Q=&Efl&X_euz3u?!3s;Hq2kUqF+C2+|R&>&4aWTB4IK5?6iemGwI{`K0pm)({EJ z5i<)Lj)ZHBv&q3nqG%lFkiGOhg8IF4N@xMQ%I`inUrPLAh_e&7dwv998d zDI2LoQH4T}D4sU%YCZBe`0(G0lUmiBs|?iO3_Y%(h&eptVe9=w8|ut5x@g;!DZl+x zUoCRGkcE5kPO`F|QP5Go863mym7S8e=R-V|_>KVeyfyHj6kOz?o*lSNva&nYz#X`8 zC-4S{58O#cjF}eyXc+=YbS0Qyedaiwo4QAVedmJ$f%#yHJHb5a!a*ZK?Fy*tEitf_(OiI+9F1{)F1lpnn2O2xV4&|sLDdZ zkUrcPC}_FK2zO1Kr$Vq-o*p(3I}q=|JOMCUzY@&>ijIjr#Ccc^5pfJ=Ty2QcdivU_ z`IX}f$r~b%6Zw2u+BoP-nQ*)u)1H2KRqdRZ>~2I^HM~^N_cBeG!G)A2h2`PdNkMQ z?JvE3-eaL=b((3yh5A7;)lAB?$I_TW^j9VCrM^7rRzqXtQ|40BT^_1D{FIq}c=s^6JSWwCsL+)AnAQ(k1km zhig_o?YT2BLv#v-vLIUzWH8w7&@2JOH$sB2!=6+#dq84%1PmD-BnxKnkT$_MVCHlr zxw&u8&iTs{`ey*3(~=G4-+lu+od*joGvKOTcxu+ItZr0Vep5N|hykZa9p|_7CU?bW zBiiYL_JX_TxxN;ELNkdlAeOyTFqMyqld9J|bQ79pA|!S{EA3r_4KV-Ue+n1$te=;V z)h&r-{1})RO|D0R|IO<(nMl0!T({$wnVzJA8JrpAc7uex8-7|KCN4H~$@+~2i*G@m z>l^LdE~6`RC3hcY5*CGxg{y5>S$+J+-#JO1x4p6!J za%qN4e_|4ZQ<8f6c(xLljQ}&O19GSGi8g#S0^L1?_BNYyH)cN%Msi|PZgat&cMoer zML-D__EOe8f7AQR2q=Faqu4tI)B*O!W-*`vab~KxU){C3TCuja2Dw0Pz3;y9GACGb zA-7J=TJ7h&>D?}>$6yo`n3g@L`c`Lhs}S9HD> ze(06PYe$=a56-MF81s}xzU5@h6pG%7>%SBq*ugz2} zS*bhR!j+AJG&xFJ46b0J&z*TCaqazJe?LOj(PIQ~Pn!>ob|=(&Rc|R6$ley3x?yK` zWLwRQi7oV+Tt#FRCs5Nq^G8yv!Mm;jrHeEV=ULra^9_p!q*~TuX9Z--3hMC?kox%R z@IV(~*c}k(Szg+2T9SR2MD86BH>-w)`bPkbpT8YB@@K1Jrp$d+CBYiy2|c%JiN$_V zQ|xOfE7mqIzw0aq0QUVFE;R~=#_Wx8Ro*B1;1Iw zA6)v%%U1JQ`ju^}2P?K6b?Dq?8{$pO9w5+Ce`;J=Nz@Y8HV!NuJaL6)!Q)d5XGw?` z099i1+TZq>BWsBGGdGK&rx%QuBkQXyOuIyf?+-}Tx-JKs*LVn5xXDph&I&oTwgtzr zpG(Vff852vsV8HM*%x8PA&kzS;?yGW(+@tgW5w*t=Rx>NOle_k(b~VtGoTy)MEvK^ zpPPyRd!csvY98l*jMOh$*r*Cm)Zxi%ue5Hm?*ztvGtgBx#}y6&!mWseJaU=S%=T_e zvJ_MeW>aEj@pR@qI9Oe;L3IL!nU_ji6I zj6Rk!AgN)uG_+Zy4Ps(rA-Pa9QS{p%Z{~@!AWq6VSN?p_eT;Aog2Edm#vzUws3Ad< z$*vX;_0TUBHvsEU=|U*ZnS}@ZNE;7rkORe(@xiD#i+`9Mz}a*=eTw?}*+*DbYNa!S zr$bHpuXzMrOs)Evr9{P~?kMPAPQDv}pRc+TOQ+NFC8Dj9jJBVWkm=oB;VNE!bKByE z-0FUn9?YS|X)>7fyEpGXFv|BsxyXjcikq3|4v(Gys8nwiHLpRj%{r^1Fl2a;ALJTF#P!5zKfXZg-i_WaFZ z)irC^d5~6m0mgrKl_q1%`?e2n+JYZ-PPuR#KTa16mA&IJHQU{)ot7?I<;v^${vr%r zQB_5qAD~yxQ<3Rv{v-W${AJ#9ta0f`2c%aBlg_&oyAM%1TO+84n-@Zxh?NwA( z7VbXAlztugXNm-32R}H)mYl>FTxQ*@PslW?EkBpCNs6F}^D5ZfcXx*BiWb)BcWb8$ zUm6F(Heb7S_`hiE9DS%_<9^kZ5FdUoc<`E|xOjQMRsUn$S^4TeZ(D?4)(Zs#mK@^` zAVPpnM1b5q;v|`d!$Y~9a)?uuI_o%Q>$gJ7HJ2~r|5`-?4Lk+BYvpo{;S>M=I#TA# zP-3vuH;+hdmW2i&Tjnum|88>9hA3@tX8x|Xw=}Kzlx^wz8}^=oy6_OrlU=9Yp2}2> z8KR`2x3g`zZJfd4Pz;`~|5T$3rB_i;-sD)luZs+}r6Dllm#+hammmM>^7zy6SQRt# zJk{6_J3&P)ZkKZV{7c8Kg3>O1C(LED`x{=#A{c85H*N$r@=FJRFB z>OF11_xeg^LpBLwCjJ0oLuo1OmADUeV(^*56y#8Pr_sf))s@+%g=1v~4@u?U|19LR zB|fJfTluD~D|DA8JaDht=CSNc{lFuvG>h0$L0XZq>@BC~);)7+a|@W!JgXmfKvBM% zWdx)3EJ)g3huu}tiuxR`%hZERbCfZrl9bz1>S9WclbQ+dl7Lu4INgh!fG6Imun*@e z5ut6dVplmIkPqr=w`bzWVf9EvQ3>@~F*~il9Bh@1;Bm9N_(I{4XK=p&2T+(5F9?E$-T_ z6DV&Sa+s*BHFzs#G~Rwi=cB~Ucl0_7Z`<$6*$Eb$@3-sx%5qE7_qCw^o7A)6s8pEj zx#xP~5fU)lx4s#mHQwW9ulX73!V4d-@#pcTUDh#HOnVmgv>-#)za4NP5!BTw5;4SJ zNyggJmLNa2`_3qBmVTux9wjo|9udN39cJ&zax&Ww4+TbV`i2pIwSa%Z^t^x1+$$%+ zFDwgUu8AcEm70%RcW&%IR_A>F4~!$C@ii%s&?F- z#4e`n=5dy0WK%>oM==horejn^X?dv`SX;tuwivgaFT18i$0f%M*ihCy4jx`_o<4l~q0*+yTrh0m zOf&Shwfg2vGj#hhP<}<^H%H-kihy34FsngK&PB&FYaxv}LylGUbgloZGj-_g!Kft2;e?*8go{wl;g5vw_{FTx9SesYD(+5If}+xQlZ8v? zMi0#((nX0=L)l4Pp6ao$Sq8@!Hq_>UDCa@|<&FiKE{2!1x%`@Y5wseEvnHv%!@?ow zbrrbEeGCcrU#^n-@*zA$(nHws1TKk&2-8;5HON(9|D7*u76)r%{#3lrU?sn%za;8;MFP7roxD?A61Dbc{85x=5p|t5rdg(l6pFX&8 z-Kpt*G+kq2WJG(I0Q#ymrcb1&q|g@g7ARYR2Cb^kwoT{Nd}U|~E&x@u!-o&wGKhN} z&;8?;?|Gtf?r{mm`K7g6F1hdG*99qSW0lk0TCVa_VdrH){p2%f#?{!0CrjH=3|Jt3 zEK2P;#Q)bt{l>2x7@opTfT*#QxBj6en&afx<~a7=wE(X9;PSR)USC%QXHpC$L&)Pe zTR(~GNmufCzT2-=F@?u0eux}^(eTAx#KrzLW_8ivb}kXJHh#suPnaV@$g^m5DS4^N zeUE3`9ZCagwzn6k^4zS_80ZcU3>`fym-4QhWAU$Hw8pn)Wr{w2vkelmv$q$jPW%9b zNz#MKO4OkHZ2?Gl4ZB&ZyWd*{=wlGtlI*t=TpQalNU1M z;W_8zvOv>!DG)noyI$V(GbUCv8QRuO-y&XfuMd9EO>rLh&;oq-!8puDA1XH6 zr`J@kPdri)USZJCRo4TxQi(JAY|jqMI!jY`3pYDt{1VFLUn=GDRQdy~5r}4nrunU` zT#wzSEWX_(vr#QKVbSEND@;KdOiOi)JT=xeHB*aLgi9%4VQ`FSX{vtfdnDDGF_nmP zR(1es=)zY2R5^Fu*9RNMtkP~%Kgt8-IihD^8CpN36e1>ySR=%T7~@zuxbMm{{d8S) ze?g8k)~SPpS|)4Xj`NZGh(lMg-yA}`g8_U$KUfG@x3r|mJN_;lc$0t1f&lww%C8&~ z;!QIN7$8S!QXM6pEd+-ld?n01?iiQ97ZbjW=HP3u|gd(qWSb5Grr%c5gpm_Yx+{x^$y|ab82a{vo@1&>GjK%Pz7&SB``;} zBs<%>5wQ`KvS(XtcF`f1cHz$Ne)PS-^>3^Bv2t45n}r$b3v#d6E#6z$D4kOf%=q?I z=7vQlx5DXDUp=;_zCLcbRcCX=u5|bg)yU&#_?j8F5#kCi*%9&1To%5CP&;22e z*#u3i3{KK3>m8VCA%WE|Z^EJtQ~T-oPl}KbMcsGK=X?(=pTEBS(|nk#%c$Dr!PUW^ zLw#`uE!Tw`vo2RS!{6Iq2VWVZQaFTEc+}raWSW{#c-kQUe-`ncvKDmK_o%;A z?}mE~(e~!eHuq1p@wfyBwxh}XbBWjGMloeu=%W?qnZ*x5pY^A><4Ln9;>j(aJloS> z#2n=+4hahu);||8OYj^Pp?8QOl{AI^+Mz}_IFFGVM?CZz3M?v2dW{lV!l5BRpB#j_ z!csZjefd)5YxFb|ghNt2h~6Ah6vaZaa9bQXzx^z5`-007fh0iFzo9pZnP;rr-TYR& zRL2<^AkH#~awWiv&gzV2$i?zvbh(3Nzru*#+=NRx1Sy^+m(R-^2ob%!@6*cm%!CPb zd;$X&+iuZn<5tQ>a&Zh@oI<%?>mQ3jpdxHrH8eDKI&j0o#>Eu`#ub|9fw_BHM-NeA zVcp|G*sG)h48HyHmhV%MbkJ&k>z6D{jc2qb0{i_&^50J(T8`4;u=`9G=YG*e)=E*a zu2G*R$FpWJD^^d5MI^5*{+o|N#S3JIcA?xK9dBkiHgvJn>9tNdG`r`ZJEb12)0=)9 ztDm>_j=fI@mPz?g&}XD_$z(Ox@mDzVI=aq57_t)8@7#Iz(5SDU-k~0k#*y@AZLdq_ zMZH{EDWef#VP&mP#AzFm2(18t-U5NO_1zOes&KGSyC1v9Php3LE%H!e`KudWL29x$onF+g zx6N4OC)*Oz@)W$%ulFKG<5C_3Enlkn`&<(BpbB7YPJ zV2X%3k8+w@MLq>?r=r4{I>Pr&=~-(;ol{~(lNXl@hP#7tPd+~=>hQs-m^Ws%<4=sL znAepTQ~cl~uO0=J7ZZE>Oag>YIRkNH8*${s;s?}>KY+{>NK&FbAmXI87$OPD^1WDRR#NGfl}?FGJk1}iFlj1^-H+(e$B~hA`?X{hz_27L z>E4>yIj!j>1COm9K3*R5H03g%~lssoDJH_A+SD5*pk^wXSpf0+%}LzFb;ZK&i^scC5n()j!ak$fzM z!BFt*S~|(VexMB5RE!QC@djF$UE7|>m`uib-=oIF)(Gu5FqfPUQ{c@K%%1g0a}{O3 z!Nh1N+J{3Tj(YvjP~DWd&66Y4k37j-REKVjuBx)#80z%234{>>z z>b|Ih+x7b>O1DyO6={@@I1y2~;+eW~7%hiZ*)-GAN}QHyCu<=aNlVn_L18W4w)1OB z4yyH?tq@1*k>k;}n-&60-+Tq4OVW}0@Mg0kcRbjk7Dh%mv9Q4gQ?b$SgyF1`N0C?v z^6Udg`-*c;PV4=KmOp2tV%4wl9SMvYPhXG)mm19vR@7liS>o!SXZF};q9zMeiuf^H z+X%^nzv(MPSeX&>#zR?k9?LH?ej-WX8Cz=FCl-dw1CoO%d3+yLJSMX+H4%(;CZQ;V zr|0$g`76U2wZq?eYb7u#m$)twZMMBDEDH*Zyz{O(;$Vrr+$q{ zId_|Adms8K>N_^kDGb(Xa!H>!{n{Y~@uquzyyz8*$mhH?aE#ZMDVVi1CTCuiXfsjp z5s1-}C)|XDgm95~js$Kl9j=NXpULk(!3rvl#~2>O1FoWwb^SIJR*;2-MVxVfbFx@`j7mAH={q;SZb^>VY&3cLl${_&}(^M`51KbChs*FbN&uj$d@PGh{8WG`yG1gvFZl44U;Uo zs?Y@{LIa(y;l6fvTGc5OnqaH{$v1VQ30fY8K2jp_cG$zda!aM8xw(wjis{QVjDRk& zaoF{rk3X7U{uC{YwT}Dt&DljT->MZfwAHWVRlPg#zsh2?umU13tA&l}*QO2S-V0`! z)6L6gEE_J^D8PJIDcAhk;JeX9p30)MyP6am8@sE|p3ts|cyc0G+X2aePY6}?V`O9; zZP=S{@G-vZe+e|b?#y1PtV3~bb?*UFj~25zo6cj-XqYbea=v^$5LFpfRP;wUa{X*v zyt6GMqr*pJQP1$Bvhn>}`a(C3)2rN{o+!0TN^*G_zSDE2>KPY{?oCa_?@JWP>M&`m zpv7b)M$69DwnY`Ol~D&9S>GY6O{HCM@#*J4VmZE3Sb6^4^SVw_ts0Z+>pxGN?;kcxPgf&Ro*Q-=?bD;iAcfioNr4HZu0kPBk`Q!TS zZvtMNFaDd`Jrwj_0ESiUzd;1FfWm0^J}7pa^=mB*D}o(0GUvz|wIBGrRrmDrI7Qz1 zEXDAz+X98fiXR3y1h<|8!QI0M5;bX^zh?8|I3qUTqDRftuqk;lf=m!RpvCWEoZEq` z{SKkr`c87iH6Km&oYZ@7q15MWsXgB-yGr5f?%u29oeymVS=S=KLsniqf*N6*Rk@oH zqzFagjkBd_JRj4Ddv-ys2xl`}-gkUm4Iawf?XsWibTjSa$D7tc__ z>Vt+b-g}Lo=w_FqP$pZxE1*$h1jy$p5ixjlD|vwH=6K59Ucf%3jwQp{1E=*@z`LNu zvlW*sQ!$Um(m{CPW`nKgz$k?P_K$<_fYznr{PxLu1H@^#k74pVpnelr|LxWQM6t)e z(6Zy}`5vhaDb#~s;jHq6H@IHXT(5(4|Fl4}l)54e{z3!0r!xqyt?lia_BqP|2HrNF zo}T$WI7O>@67ZUtj1#(6DjhlRC2qM~F*3Z-o0`V_i4=x5T!H1P5pU!@7j~>I7dhUp zcM4VeN3TH%%96wW?N#6~{DX*kI1?6Oat)Nf7_&UrFS4%?gT#J#;XgVWc!Ysrs~;VT zBn3JSQU1f;$WuT#G1jQ^VAzeW^yMXYI5ENwSfINe9(@>f^!V{MC?Cg zNER_MZI*6M*F;oN@|+NCih>G#<3pi~zz^2$2@85t<;TcK>a$6-90P=%!6$0V zdCq}a3+h6o$}UnH#2)eSb9U}>!AfN133D|cX@eD@ExTUcqA2rksC0_Ox4yprY8wC!8k)7IKhg66PZyZDm z;jhx!@~f(-m|~rum4ST3W?;nBB%eKd<`PJ!^k;a>M@4Ip9`W*x_Q78+xkG_NdIaks z1TYdPgaACado{-pwy^3`*}Dm*d2%<9J^`pWU@fG5C*LFcRh9uyp;O*?Fyf*i*V*K# z@O%kWBmY~dvAyGo&mgxLAFq|X!gsH62I@!B!v!$*@2MK9?1K5&W$YK6(Rq`%-Hf^Z z5g7cnC+lL$B{t(8b+BJQ4jO@XBR)a(W~rVQA?=-=*Yg{*q_}7*4M*a%!!+ix$1h_G z(Fv;9vwb1@pBS(m-9~zOpw{*jg^m6rT$I6q<4Nsfq79B@Koq-_hgp?ySUB-a``gp^ zH@O?OLLHQZZvA}TE*jq$PT4a~zxEA#c^Ej7)jOK~!k}_6{R2nOy0i3fuL#(Te=PD} z%iYfc?3k1F00<<(9yCfYqa#$r#4ugDf=I-XZa9R8!J*n=3Gc;U)1M6sN6{e}^OEo+ zN_+_l{^C;ZXS|s$yg<4=3L#N!)YD6_$aHftKW47J4=yVEi4!XiP9a_L@@M4acv(-%FqB<)Fu7>BiMQtliXRT4@3kW z1G+UfydWgK(vlJ@kkY<*;S4pjZvgqAJjj_?OzZ&DwWg+~4i!NPB}U;)aIgyLMAf$% z@o42_WM9Cg26mD*$gp2BBC){E{9GCaidc&vo*lEfh==a}Z%c7e06;UusbTShht4%q z7QB*{mbN?R0bySG`N1GlJNf&>AdYqo)5ng2!sX5 zIft_mG?_>z+%QSa@aSl~je3fwWe`oQeiL2nxm3vj2(oWLm6xtk44p6uwpL1Be!+>M zZ%&yv3Wc9|_S~#X#Oy;u;P~JjU@3}i+`!zm`T6-D?JOf)%#?y!25r7*gjY}V%${!b*~Z#Rzt+`PD#x>iRHPJB9w0tW}cue}N{u0PqGIE$u5 za6zle^o|rtYT|oUMKP|@=}GxHdc#qzWiGxxPbaPoe-Jg**B?=Z^+;!_<}fz^ewyOE z!?sPSJycsr6yKTAmUQ1Hx#E?>EOMh*Nt598Lmh=|RYXEB zrH`7xK{krQ^HuJnbD-F)?xo0Jbx<03s;4f-W%VlNKWqJ;PmRI=K6BG#kgSb7I4N$- z=oA!|hY*FBf9_7p0WT~U;clk>iEiTMq@<37)kvpX;ZTVDeD$=9j?qn{v9TBWXu<*( z^cf)Juu0vQZ4`?A^@LD`NA{*I_gYPZh)3Vd&JqpF(CX1R9K_Vr^oJ`BX>#P~(Yu+b zCMZNy+@j8YrYqwIlEnc*@VvdY=jKau?r}Y>Ux6MjSY4MmIoF@R{#t3Tr^vFw8ABS1 z7V7vH^FsFHy5s;I>REO0B8Mm~a!|=!a5Z#tm`6>M!JrhXnqYO>;*03$A0^SOm{Jvd z@LX`R>dgJ=X&d|T`{k^s-KBn3Sa{SQCbtfIic^H zZcJ#%!_H2vK$ixewRWJ5_gy6ix*K3t>(wbjmWO@`v?zBrE-pEp`g@f7pL3=>QB4P4 z&G};J^1-XSYEr@V(C4WkG+;Q}!pGWYV=UL~PTknw*cUhDwJdw;$S0b#>c!I!H59_& z9T23%<@Y)r>pxEC^Y$e$I$gr}6GlN*sh$+pe6($9Z2xO^CQkd9h%G+p6_h+Vvh^?m zY9OSx3_#LiTYL$~ZK9N(y?F7hDH;&UjILaXen#^g$d}$U5TMUUFt~mMC!GS5E}{h2 zzO@rf3SE579av!*xZ7_!p_YtuJcp;&~Db!U(yyERp$<|hNMneLf)A>p3N0`m$vMRxAYc|y+ zMeY%|sfD)pYcQ{&?+yqjCowN@(-~EXy`d%#{k~;0xB6t*;Z90UyUQ>FD44J|mtAIZ z@2ZYYIO%u?p0kbgB;oO+N6Sf_q(8v5O6`{dgTM##ZwUQC=ng}%m?#-;1%B(X{^>vq zUTZbLAetRZ^4|Q8r-@wUibZ1mcGm{ENazms-N)bnz3Q>b_%}ZYf(taT8Vs6=YkwZ& z#urq5)KefzH(}CGB$<(nx3%e=iKh4mCQ%>)Q8c#I(QX3w8`D#+?uLO$i^B zrD)^$uMr*v)jA&t{ZDI({(_Fd#$lQ5?d`uq8AyGZ%0Vb9m+==zgM!cdvLG)BY2Ls3 zN_7GcN1i{anj99Iqvudw+K_-737GmZ4I2~kA!`7y!HkS5Z@hE2PHQdsrs1-WH-LaH z`L$9`TYDA3luE@;sH2+UWD}8 z-ZL*4CtvAYX(BVrquD=3Rj@fkC*+ZB{NAFOv1ePFgu%lSfREcHZ4kz?w)|`Sx22Mi zaUXl^l>dF_O40x}^fA=?cMe2CW@f7R``6P@kwxYj_Q`&FYKq9_I5&@x13bQG ze0+%)5?gALG*Ac(BRxU6Ww`uCeQ&Z2C}9-aNXW>1?I*`=J8qQ_UF;zU(xcae zA{x|`Q%ywdKLBGI>8f5C_o2LCtF@djv5i|nL14#;zSlZHSxFzl0F=|bOVBvx^TrJ2T1?C zx2StNyxYB}ijP`bs}?w>#hcLmMev>rNan8fq=GrQZN3PDlnzs zs?Y6<(`caaIW2ssa(6=o;E&felF99wh>uga^dXYq8{QsABd zxL<5mT2?kGraGW{oe_d02b|ZI78ff)NhK7@J>&l%7ilBZ(iGb0ObPwEvsN6qb}!z< zd$zuBaF8|Nb*iFw9tr{dAs@K+;o;zRF(?wC5P>_Nx$E_Cl&Dao;>2f~e|K3#CW>Ih zdG}1VQwNc=pt-W(j;DIv2-R!=#u}fKb3I@0<)(dX$i`V6Z1phmNy)fTyj!oC65jFC|; z){jnj^-6=$Sm-SQ$#NBtMjiI?32{ig{N0rn5nZBB6f#>4PYdzzu*5@gcY(gbmt-WF ztAZ6@-HZMO#mQAHKmW3LlQ4L3bdu%Y0&(y?A_6Q$rF%A;;Gao^nsN{|gx#apvWcRy zvAh3!PhEv1JLx>UneGG1NP{BOTU{ilBUQntV={K31c63Z(m#zfOx>Y0mAo*>*Jgo4hiIQ8@zMiyJp8p zAeO`-fgt}^_vrt`jeq}C2@2Q*gLsb58V8tRD0FtJaKwt}gKIwIV12*SuHHSw*|W^h zu-zprR88>-u<&c|l6`ajH)AqVdwe@w;oyD#3yhgKNe_atwu=w_$>b53a%LEWkhD$e%{&yUJv3J1 z*`c$7WP@dV@AvN{1I+m*Ar|@VWN$cek92N!t)|#mOoFhjdn@KM2WfN2x-W7OEEFXZ zNrQ~3)CQs8B*{$XaouhkC#OzeM$AE|{Buvl2tSy&+eXF^%|qlR)%UnZrQ$Q>L6RtW zT3p-*jdD`%qdb|qy1fo2r@eg1;=_0oP-(Dw@B#7`=Zx=uyR+VTVch#X8xpJL^MUVo zTK*45r(6i$jJU@CX7f)Zp@~xVc`80ta?X=uD=_w>4SZQ4d@_ z3IS?$V}ByaC*a!MX3nDAWGgS~<@3f7*E|@#*6G&VM9l1BViyyDF@AZdx z!Ofyb&E#PyA#7Xb@3+5!B%Uh(kPje_Rv&-zXQum~XY{{tZ8#lAF8D$rUHVb zXW08HqF@r9MWl-0-TpaMmBUzXbUuBjpqMBuqtSp3CHNe{rJJdSpoOQRBPKnG;+aWb zWL1hBsC={q-y(?KU|3>EA6X`JB-j^nGu-HhZvX>8FBb z)e0$@pc;-(`qpg#k>@aYmSh%;r-}+iCu!ETSMa!c6BFc$WM1< zmX8g6X&?shn(j!?-2&tO)9~Je9FzQ6wVGg-N|Udjvm0pE%L73UdUAPX`pOe*j~YU> zO2mb~P&oP5gWY(UOiel#kK8^el>+0nb1IXCD;3+M z8bpiDM4zX`9!LAa!NEMwSP9k5p{(>VGB;n##Bs5+v;UZ5fm#p~aU(IrNgO#1$C<i_t1HNzjaZ$(1W0P+5tjn)Vi)7m9eh&x)v?8IgfbT?E^3B_Kh8okZW7!II#Wy z{d|3?Afhypvx#B-?L0OqgNWu4!AuTc@lf~$m$B6)d2 zQAbN_I7v{aE(&Ln4`uNw`~m>G;s}*15lF7;(?*q)FsLqZt%ID$g8I6JCo2Dg*b)7o zbpu(KDbgBt7hU$oy5C`n5-9)4P5kTJrNe={7o5IS#{K)T8(C>jCS4{&0{L4lU%otj zVsDra!lAynSw+H`6MHgaL#KN){+qtzS^FvS#s}p+OONg#h7X%{|2)Ux6p@0v)jOaeogM zeyt$utD3Uh2*-QQ9wwm!@Pw_Y8g^Wt5>h&(f9-$mww44NZCMsW(VX6xk|{W zZ#lXamJu_kRz2y;P=P||vM1p2yh?Vm2C0N7cu#3WK%54PLeY~fG!7*N^h=~T--B#! zYa8|2r2jHJ^MBve|FgfD?Ub^4MKVckn*~WTvdb^P#iWP?#ZY}nG$=WMk|+`(Yh8TT z+PZ1%1t6B>Cr6m*5L0m^OE6W_yP6La0oL+OG^Q`_AeTn+O#J(*)G1N`ORe~fo+!(m z^W74W&2W--PjBxeFFWVUb}QW2VH53+bN`w=f_ovT4xs=m&y7#_-$*hX=)p>Iuzf@aPt}vUPCzZ1nAbwlcf9@(w+6>&& z@cGVxzx)%kK;}A6Dk$OAZGj+l1Bn1R^c=(iflpcn63!OSZLVK$1xT!dAAT@4K7N~g zQwx~aNMV`ai;b?OrAr>hVH^R|%t^d?6(rmuj>N=ZO3GZZYF?U764wft2<`iGCFiS= zqssnZEG^<4eG!p+}*)F!)%BrmmL?%(Eaf))Zd zLi3cU4lv$2@4PRC!<)0!kh;O2X~)?fo;R8Y#_KwS_gsJ(|ch9Sx6RO zK1iSdn|#)zp{S_qFb_01{pn>qR7Rw31vrl4lLRZ=Qz0{5D#xvL`0r&W)+mFUiaq7AqColsboDF+QCDuE5z*j0 zDYbFqxWKgb1pwJwG}(X}&Xf1oNC}zK043g4dqK%0`>A;1m4)`~jJu4B0>LVrk_&oR zXaUc1k`#tt<7mx36XJ-u3_4O?-he0(=1xGB>lg|#fc=nUhA`>bv)}g=xrQC@F4!Fs zo+_!SaRB{SW7M`l$NyG+&x?!mgEd)Dgsg$Avtg0hvX>YbQ$9{Ym$Gi#fBYZu@gd4e zaaYOllY=!UJ|EB{$eS~ibWgi+KD(ZzO{Bz89=+iFp@f`>=#c}z!&I`v#a1}vm01Z0 zJvo6CTvd%nWHqG5vK!>=+1`WPy!CcgoFs>UHb*75|I@8EuZu{*Cd^I_RaX- z`h{(PnOoNs=YgEvB6sbUIaE)`k3ixr8>~T8b^nmVUGU4<;r@Lg|MFf3uGN*2jQBK$ zw2S|Br(dfpH_>$JUWb5eG5Zj%nL_q{v8yr&>J3XHOhScVc!#4td;~QD{%vSe5vje*KRnxp2Z2OHj1E z<@sCVm<-kUn*%9p<;{X5J6#a;FwLa&{Cn)Npcj&qf!}yI04!PG{F5-n93{(U%!kMmaHNoE_vj` z!h)Gn;Z%{R<4^;8OTf{9hQ0Z|wKi|+1SY^mTd?9Vw!9Y=ShS#6P>_8MXf}2ZYxvA) zl8=3ctW+qHPuTe&U;F2~0rs^dIaBSt_{9IO_m8{8c)oec06#f z#m$)x45SHIr*0)Rx|HR?!R3{BLbE;EL50bg|o5dx9$FIYz|gn;v~5eM0fGN|6eQOV5ZDVld)>3 zj1t_Tp`lUW$pq{v?U*z$e^88qHR=+4knE5La*yMiqta z@m3)y+M43VSA&*;PC#&vOLXYPPC%dm5k&!u{qfK;VA+6UB>eeLnQ>>{=Qkt25d=&+ z9ymb7lulfGK#Vpm+uP+}w5AscN2}uB!c zxVxkmUGlY!RExxUuY-))%jk8fJbhVCMyK6y6!X$JLhMj{rLeOlqEj!v+mQw`O zj7Pbt3LrM(0DCLi5Y>oIxzzDCF7I5e=>=}93PAz8{tIfKGMBlrEUd!_dk_Ty4f!>^ zP%R&TTb(2NON0%ezARv$JV)-D9jrrytQf~O{HXFJC=ni2!FPbXivZFjzX4Pgdm7|D z3lhvEs0w9_nE26pbUxpDRgS8$AjEh6zNfz$!e)jpCfALL$abwz%pwn-* zByFz!V2-SP4B4-XB})tK%*?21kFBT5ae5r0UBhefDsRNM&JLe~gjZ}b4UVyW(kUqd zM`%7p^`%=+8*&(J-yz}XCFxSVS z_wSc8RfMBmytj}VCC zftybrXSOE4+%XWG+WO`$?^&CX*U!_rkm<0XI^!(+AOhAAj=uq#cz*Q&(Hu&oRQTgy zAaqCYiFm27IPfTkqSE&LnmjB=E3JYNSDwRVvo|?Erlum*(^#M~$jZK{ny%^FV9x1u z2Y`M)?N5;Ttb~${WVS#6Q~pN20 z+48O3X`x9Kxdu2fOaqr*TOTOES8z9BkMoern|=@icJsG_dW@x3+46dDcsFZh#z|K~2oC@WJ2{ zOPandr(Aim8dSzHR41TC)uP>dT~OkZ26sW_V|Xr+yd!Rn+Kwa!anx{7@MPtSFT}Z4 zHwz={BR=(av`&834rF_6nw_a!&GL?VZGn=ag@u;cytv2`oXY%$h7Xb)BV@};YHAvf z{#Kz8(^mos^v3h&5(g<+n~GQr4b^GPhzsaN(3gC30@;jFy1|&MLtcLL)albD_wF56 zV-L4$+#SRA`;dN%%^3Wp`Yj{W~8D`5hO_^&#Y0b8=3OojttLF30Su8WygCC z>N|9f_(a_4S7PMd^u;Ei<)W~=GH29tzTY2YtX)(Kc-_^ z_uH~j40lQvp%rJtCuC>kfD^B6vFj`JZDwQsQd2vQu@Uoa?9B-rxHmY6 z?l3;DT{wN>FBZkOsSRgE-v!AWEV`wvzL(egXQY-#&R@G`x8=r{7OJ#tsP1Rz;Lr!s z?n=Z>&OCkqI>8y$LGuOU#cUf)jt*8zoCkKL9!@4Asc#} zE$>!hZ$(+xq!t7f9%y-*#7$dId#$)0G$PmyNCfEz^*;Ka^Yk<4@k=6-2rxTrLM*k# zCXSVlodi2ECI&us3YCt@QBnVtL_ous$Q{?`#rwoJDCZ{Uxz)JFoz}hW#{E(6&1srK z`7|_h-_r$ZE$K9(_mM$$QhC+JArbd8v?a?!Uj(*37*IqZpYV^xR%F|7j3|gw-;*;^ z!_m$SV2A(sKkm}+JrP!;xRzYu;FZ&<`EfE8mz5cVM7AP2nmm_O#B;vr3E*?lCJd}e zq7Z;KH8%;ez1S|(%8?*sGgKj#7uZ>2tVXnTxF(BNmD`Ml&M4`qEoTsaV5*ebaA@vy zzJAb12H5(q?;I=q6U6=VPWl1WRGuswMMJ);$ft=2!0sf|!{$iU@$X0qZ#QU3@i?5@ zu1YEA)QBbpu}rJIkE3%x$cjAAXcRN5{Onl!m$L-lW~t!#h9V0~7k+PlK;D>xH%do0q0F0ooh($-)%QRe717yg36hPw!p~~5yrUrkD~$D zudQ8Y4F;iw%?YX`w;<`r>re4Su`A+f`fPu_Q-*?W%3of2SP|}@sSty z2X7=I#aGK0=zM7bLVGaHhnu0w<(QJnalst&IFWG!w9X|mSC9$uTMj;o|JTbq_|}C6 z^b`NXvNIJu@s)t;>go>m^%=wi3KJ<5Wsa_zz@9;Ma2818laTw55J!irf!q=b5x3`8?&_UQ zv{M`1;OA-eynZ@S0^TP`W{0%?TS$l1#hDh5rIT0w9J?ldatr~9Hk@0)2%Vsy;UHwY z*$T7O;0w~1k`<Gd2Zo!_}FnkY*XAN`@l6`F%msB)lu=KJV4zqsJY+)97BPn!N}8o&c0S#tr%+ z*&n>(duOHhH-zHx3H*i|SLxg0>ydw49X4G|gyEY2El}zK>T@RAT3WcUxTC9ZbY}E^ zYd^d8BA1qkQLL@J1`B0wySaQKvwE?5*(Fr&N#5ZZ;Zj#o1KwpEG0~*<_H?Mlfqufj zo*DOT(Pi-59*%}wze~R0CS2gkKz`%SCs&iu`FRU%jmMQ;$4hsvV;NRi>{@U4Y4Mpz z^s*QfAL#~(o|HGcdd|u2(e@7IY(wCzx}IiCSrk5X`1VP+7L-ydj|@A@X#9Dw!>1PK z=Jgf8Tc#$ub9mX$`vDJyqqh$XplCrm3y5O@*jGL<&93c3d7rHKK0BopcTkbkdD>E> zE|xPoT$87v@uAd}vRzJiJGwI-j&9e>Hgv`sR~O~KzTH_epI5nG1qP?+*1He1p>NU% zwEsb951;iPi(!Uaj7&rE!;3+!tPr)eaC_9~_VXfg%|8x?L*1Dijnd>e!?=>BY&Xzo;wVs&M&@GK5+g-%pxY*ara zLm|)|75v&IUsqvykQfB?f`fu>CU2r;S;Z#-T!X<9P~Qb1D_8u-lzm|avE+k|`p@?% z%F=W>mr;Cz`Oxw;AeoXBL9sm%h-(7M8a+L|3uvVCxUlzPP=YpU=VK->pSC%fYMHuE zvnoAEHXpImw&*ankQ*olU15-*p6(TY`jAiCfR&Krw!w+C@D|HgYaMA?QZKDPa!gJL zn6}2O)Z88cw!mehQ?nMx+P%kdok8_&E?PdL!8p$Kuf+~aT>W`OvM1ue^s6f{Ma#O< zMgbVBfA{*CsTdwm391_#A>2M!-lHT+m9l>wjqC}0qb8-PKkXq(?VH=x2#Y8_ZIwLupZCPh$Gb!e*E}xz54Xh(*8FTY>8c3YHAP08bIcCyZW(> zt*sV7xkkIb-e??{%24IJNuKE{Qno33hL?WC?ajb|rk7-Wc6qQr?eC^w^|TGv5k;P- z=l_og#WNl(4d0ikfkScF5&}j`A&j4y&K6uOC)Z|0aGA&zmz(LA^!W6PXr*Wq%3sT5AAQ;PMk)OZwZOr>7Q} zx5_P0cs&nb0%2GeR2_-pcX=;J@^1t8CyDWl1&i1-X=rfxsOm6T4y1_%`jd}lftFI7 z*8vEck38xu@M4vCDzwoX8ym}f6K040&p(#T4?(QVT_sC-$9UTJ`6b~AwJJN|#W z77z!H;p)UU+DH!NHQz=2e(=$Z0H$71RrS3O4rr>wpc`q>5vmGcV0U{%Z|@H!!%KsX zHT@vT1K>K~@pR|gw;m%|Ir7&yzX90TrNjuDL&h8kzf9jA&Q+=d93DWfsq+tF$bF3K z(*qToHmW?pAuR%}RgEYU=#65H&RjK8Qc?{Mk6LFZCnVp*Uv1sEFMw0%U~IYK2WCwF zGJg5IGN%Nu7{F+kSEt%C1sF#I;80a{bYAZ+=%Y)}3Is$h1yHHtBH~^z9lQhL=p59N z3*MiOkbfCb*ibOA(QhH<1Rpk>k6*l*?HUU2&=2m%^x z{o%qPf1@G(TV3aeCn~b@1G%zt&#hgJLAs>;i*4c2Y~Bmpn4l|&@sHWHpFXtJhE$lqCbhFG1T5kq zZ!K5s`5@DJ^kQ#Knd1MkJ|KyASjo&gq+{eqPekQEx3p9SC{St{AxM@9apE9$1h=Ys z0h>FJ8w9VG3~f%YMbjKA&->{h@H}+Bz`7jc07ag09?iom??Iu=nVy~fYGh=@bI|K* z#alps(*)JR^2$nW5YZGaI_fpPT`u|y2b9Uz_f#|V1JR*nqbm_pca|7Hfb&!rBcrSP zK3OKsWPrf9F(0{6$4vdV5Ff^*(d==spYi;jz?7@f)6xt8dprs#BoT3gK`mZ`i)Cm3 zzHkc=<>GXqg2S{aKV2fKC;%jaoM`)9D16)PeZdjKzZnZWKOa!#SXE*Z`4i5764eA~ z=UjWPIKYuk&7zV45ckc;VlO6^;M#|d-=P}^A$F|Tn(^`pkKavYU~$BjA;#xVEdpV7 zA~w)C&KnKpYig|1bH;TrF3D0=^`3{K=Po6bpZGtXjTk(edqv)G3!Y9$7U5naZavQ1+#;t&d<%Y zYJ*Ziby|#8V?md@p@ze`fihta|p%{I< z6xdo%Y8sM5XUcwsAf`DKMB})~9M=qx2QVvUaAbphFC8-ehxQO2K?)#ougaZHK746= zLfq@Sd>NO-g4dVO0uMnNT20jyu1EnKTzFmSBbK@+Gh#T|` z{7|G(d&H99bSnliGCE3(Msog@YZeSb>dC0oVbVk1vX&V8UIrArg1OJfcMeWMaWx(Q z_@hJ{%JB}@X$~zBI954lKyYqZmUk$5^y{I-_`@xascIHW*oXteRc9C!`}c(s6akwd z*sLq|@ODxW%NKLW)etW-l#%#r+2Mo^liRqJ@!>7aRK$mm$~L#KSY4n35HeL+@0;FU z{VmPPS8V%%V>D;^{^lMwxSA?Uwgab34sA)gGBFSYeKV>{m^>?@7`RZbi@nPF^55mAzvYadfsVda#gT7l%B}#ZyWr- zoYr?1d{mZlIp}9}z7;7!4MqP|j0Qr7+l0?9n}r=b70{Vjz6yAxa469zNRF?h^dy>I z6#xyNky19-1TJ5;0ooDVn%D%XvvH-MkPg*1S3L7Ty;N}eGndOhyL7)(;Co3A^! ztgQAn*Nql|dd2qm6|cLfaw#uUl(vGGUjF0t;qtV!=4-V%&?lz9tfwV_&wyyar9+|t z%KZdeCGrNuUYmf?KYdGVes6Lzofj|?e-62_E4k~iE7u<-roE&^5_CdJ}K&97Q z^%qj66+bKNso^2CUoZE6St?3K*#sMCuuUSFF4F1TUx|@Ab~7_rm?~ zYwp(_oiZXDqF%>Hj1Gg)Fug@Gt@ z>v~R4K2A9f9Rotyt(_X6Xk&->l$@Y>p3*QEehAv$ch8uPk}-`@vtbPeE|dC ze=K`bGzljpO*wD|sCeXa4dke%Slme{%M%T@O-YZ9-O{1Uk6YPyVfX&gr}rPYs@M(U zITFtD&%FbpjXP^$*)+?5jM3HA6W@@EV7tuQN8ey<$*Y~iRkmYJddqmAl~;4$J0iF! zC@3d4Lt+?Ooer0Hl>UfY+xt>y$Hbn*tI&RvTVp_Y?rPO47>hmvMBbM-mPhsKfkX#z z4OZ>|cX~dA-y2zY5elDlQ@CqO@0`|ZopX&4A=E|Nj1;AWue)AKd9LEN51}KfIdi?=4QFDJKGV-TRUn5!VvAnJ}(J)ZOEz!&N~4J z65RQ_NZ8b&JHG;&6aNnqUF8<2WLL8D#-nJXzVV6~rV+`Clo9mVd{^wqaz&_@$mXU? z4Y#){KWFI#dd?ZviL>$*qIxAUX|SS4#5OXwI|M*i51bzq*6Tm!$QMGfrl{Zy}HAKo!V*`}L?;XW-e&y$MfUBiN?ujVViTX3upm$<5QA zE(20SLZ_bWxh_1QxuK=V-oN;T01%D z7}CPWfX)CCYalB#eLL;bce{STRQneEHl~m<(dp6>prGc1((!)t^`c25d66HIb@r-6 z>ti=}?>GYU`I}-l-&hVsJr^QD-#KfW|5gH0%r}8TP&fm%CP%Cx2REvEMPJ&d{=EUm5AbKpDQ+&ECl2RjJoBNPjLC16{&l_1U> z^=G3X=BAb$etu30aJpi+5sYsgq2CrSU z9NDz<)1XN}ubE{_rU*34>7-Gfj{#Cgm9AeGV)6?Lyo;oE12j1-Koeme5EpfF=J}P} zW!(_NN1~kFS0{tAjTipP$m4q((mGZNkqfLd%HdKkfK&$6Z3RB$tyHNP2!hj|@>(`% z1MT)20*PN4DsS8{F!-MYrGl7~Dy=8n#>Pf;v7v$EgWjs^Xh(&&x|C79^cXp4tJ~UL z77x!4s{WY`i56V~8YNiG9!UxDcDpX!? zOjV59L*(EVkR4Yj50$6;ncF@-?FVWPxF#D=Jr-0+3%#9Vp6yaPqrlanr@k23TRMd& z0UuS7e9@;mTvbk*DbW#C1)mLz)h6EOC8MvuNL|hzQgE8(zgT;0uplO253fEdL^ITI z+7&j30({&KUv*fXO^c)Dr-gr00=&1DsCziQA0MpunknkVjZy-t9I>PL17?;aPPyqa1J!C5`A8<4<`X%JzKUxdyv zmL+_R9L0%{%9MQid?!aIa<7j*-=}eL>X(G=oBK`sMxQ$ypH$s1qc4{uSY8UlE0*l< z{hpZY=(*F_LnhibWzpj~=F5Mw6eCqDCb6wGO49@P%N-yfPE(c3_%^xN+1}n>w`q*H z!1~F974{=^0^JtYpo9kU)V%MLcD61M;Khv>`^Q(25;0R0m{R!p(dKe&(w=SY=v((+ztGDG zhJsuSt=r%x*!C5JaJ!0UdUuhmy_jhuakLJ$$;C}>1z$}D%%I;UfklW}i>ai)Wvwpe zi&TemBK?(=a#pj_SYdx`U&xy;vg>(>=c z30J<^hKsDSr`VB}g~`%9CD^3)`C@AG`uwk9SmtbCj?ihjTieurUShtol(a$c0m}ib zcFf3E%gQgj(R>vnSq(HlMh?OJc4hTVOxUIT#mbsIGsg*nfhmu;nU~S_1XVW6lUSIQ zKADnT#JBOP!LbdI&07{yL5>P=k=I!5>0Fm1{5j#{;NNj20$d~I!W%A0roIm!l2zq{ zU0HTo_>VUeaix=^S7;HV%D)Dm`@xP^y<>-SUOHp`ym7I}oeedO9kv4vU{xt4B`)X{c58U^fD@k<|wxrb=BI~l*KGkv&g zoken{{swcN>;7JSApF>drP{NfqdpIAF?Ek{ZL`kV#YO999qs9+L^FIlg)1*I@{w~k za5OK@{~oDnPK|rT9r14*Fij_jnfwL86i-z~N(%y%1BP9~q0XVdSY$9P&XlUtTA?NM z-t%?MA9tHNOw5$W1SOmdr7CXmlBwRvnHI{4wMb+^b@kw1UKds4==|vJ|@> z^mD)CvojgA;$L;Jtbi<0`(cEdJ3fKt&q`164^_AHGFi<&D5{27ze^VVb?qi`Hf2N% zz(JW&GZ!|);UlH!xtBGmX%4JT<}%4Ht|p=*SFT-4nIU7bD*w5>Vu#jD|1%_T?Bv*L zTp*mZNz${~eMkED2+D+ezLDB$V6zD>5yEaVg+dHkf!cWAL`hOhhZAS4n*rLja#^`w z=;v`h79&=zqv%ig+KcI_7`BO%E;&g-L4oTyWRXhedGG7^^4Oy!+%RW0KbcyYyqDEQ z>8f%zY+6#Sv;Q+f6x`mp0%6NOt$)bM{{6EF6e%GZ;yH8qEZUwHx3(02-TcM{a6~u0 z46BSH^~s1={5v~VfuM!8zP|pbN5L-r7u-ZQ+*fZWAxyOsNTdU`!FnLu(N$Si#-@Us zwn?Eit|QSK6$n3D@RIs8O)<-&g{+o{R_p1OP|r&tTrh9tXT*b@vkGlLW^Mnv+|P@y z*brIra@)6eSQD0_EW$~mc$%@1my{`s zP7@~ar=!ohTErF^Dk;Ug{JgZX8G*mN}AP(A;6>XRqWKq}o|gLF~8~{Wq>3DDsYn5_Z4PhUfC?aBAiYm*J;9@ z7tXVncYmvRh73jaB!3wKP!nS7Tq^dXFo)EPMx z9~S|1T2e=xiwY`t-EYnx-y@IP;|tSc&2p6=Pd;u1#tN>MKQC*5T;#%k*p`%(wEt8j z^8&F$t7#C8DdEYwb80GVGBRDJi&lS5vl#(|3nrIWP>?xCg-lOX1daT2bLJH2sI7oa z92ZJkTftu<*+(z}b`#d;Kg%_mjrR1gLUGev<&{;Kim21#&wW_OtG5e#;20*L`d^z^ zpPK-~h8=1kEf98FGd^vt%$>)i+FESXCQ8g*F_QVme+0;iF$@H_4!$uZ#~$(1n&zJu z1FrDPoMQ_#U9ITEVmdmOqWT1fR3dHyC7926fdIn{Q-Fm`0tL_%#1nfEfLnWeixP9l zlK6ioU?yU92Ge=Ne^=Zn|bgc~m9(V0n zoh21LMiV3kJ)-1v{I}f(f9B8E&gx(KBz|iXQ!&KS+7&UdNeDhwpKHGnLs&PCDhyhUmDNGG1UN<&6nz&>j3Zbbm3lQ>8d#}gC{8Pk#G<{f37%d4IBAyt9!fK zN_||i%gyc>#7VCJ%p~X+9~>J?NshsA1BmOstbwsHTfXG?{`J}tc5z9IzPuVYbpF+5 z)K@B|Rw){^YrgCA(2B@vJGp&!gVyB71k1>OAL0amvG4cfj!9gc;w&fUX3K*h5<-8( zFBe&XapFX#Tl!6V-gA>jqX`KJpHqs^kON6&enw^DKW zo0FrIn)_a2;1H3{c19wGvN!?NE7E`4R&qHM0NPw)j_#WhL}MNf*GZ@ddPXPA7k{_W+>U(a2<`0%wS&?_DVF|TS4 zSs*p!EEa>XhcG{8YL#h}$r=|D*J!?t@P`s!sn+>K$%cgPoVneO)_n;sptU*&zlT6} zaArMZ1CKc(G@>dzRb!`KTXyT<)ciU=egRT=Dd$>Shh3=DJxoo1WDhf*iW6m#o53S|IJln4^F^ z#!YaX**8sbJp^PPr|Bm#yc%e25bUb9x$;PA@Cykgd@{Ih^<>3<45Up8OGvfh~wd`(!DdKxBF1bI-Bar-%2F`yo?l>+x5jKX{p}QYcTLrVM(di) zyH_74L+d#)2zhQecUN_l;d!eV3viwj&1uu2&*5~nzo$bU#C%}B^KrkE8Zgn5OJ>%F zzt4iX3(jh8pBh{ZX}U>~`Yc+WgM#&r3LWL?q!XOb>h-xOW|XYcMX%|zWi>ee=n2RF zB!^+aW~g#GhxT7lMEdi=2k-S!mMP>un{KJ_e z21N5lAF8VSF+gQEcm7oHIUuSZ9sdYd1INhw75U4;F());t)Oq=-E7_p>RC_nmo0oU z$k??RvNb+ohWjp@)mvJz%I}V&?L%PHi$(Mlx6f8%St?^I(KM>aD)dPE1>N5P<3Wlb z1|&w2Y_iriOXi3plvp04afzX~J16!#-@H+$_{=)qCffD^=__tx-+>N*TYf8a`*m=J z3c;A_p+Yn1WeUHel#pqD`g0%w*lF=O6nI`30Rbs2$?)$=e?B@5k6MiGCbOzxtVDY_vU(#4|Z2f0CSSO{O%~?%U#V6RD)< za4sU*3`?sE@WkyW)?s|y=*O$F>Olg+(>7CfoJe-T%KsTo4T7=MSTUr(aZx+4GxyE? z-O^7R`Ao$bFdebD%*F2;G@TcDTM57O$^fL;hc^LE6>rew zLy`p8un>)6{)e>mGIcNojpASq$yy40a#{LG2usyBW&St(b9Yp$8e3f+#ep&z73~*V z=`N-y{dJPQhxU{9^i1g|0m0hO&+p?q0|tH~MOq{U@)nB_QOmJp1JEYD#g;dI;q72$ zC@G7{@t$t0w*~BGl&r4k%s3mHI>X`EP~N1o+Jl#9d6O9YGRj5UL)#O=5Hsx+7ianq zN4YBm3}Sg_^0qZ90rR>GC**(Y@puKP-@kR4Q6y6^y(p(d$X_k%6K%SsxMKz5S_sxz$$ANFd_rENiQ z#pVmfl;>sPS-h%vI<*Jp5aLF!&JQ=#dJGO8J}tjpo?lVrsZ`&jT^xq9wQf;TUtD_X z9V}bSFccE-lA21@sf14Z@tenx%~g)d>iT=jUfun6KqZiycvr4DQ zKK;CvdNU$?dPF20`Ju3Dsau^IrL?WWh03opL~CI)W#M5*;M%KRAf+Abn^fev_6ZDf z8o5V%S#=bqlylg&{`^d5O8{XhswP*5`4MPu11v>O1I(ZH8Cw4sSZ*AOeyQHocJz^1 zW!dAzg3Z|Q>Gyd~GztjYSgq>GBgBXfv{qv2{n0E1lhR?!!MpiU>3U2x`qz+kO^R)e z*VmyLkSp)rrbg)DBD52yabd~GDK!r%{YXgfrUtD<(j46Bb|14;7RZvaL%+=#n_mXL zF9a`X2Ba>s*>o@uhsYLUF_4YC*j5FTWl8!@&NB|h2EvKQ8g>|GPZSe&(-T5}JEoV5 zTEe%F7ULP7LLLwIWfmezA=g}a*JAKY2!asMagYp@5zehH88(jltC_KfN0d(4jsja8~aBwyK`8zB$jztwYMW4TOj zaYqg>`g*pyJUPS3S1p{>&nZ7T=EKqBA1C6e2#yk-$DD!Tv6zY}`#ByZ#|L9vhdLx` zu{uT|s!*C_T63ljh{b4bPb%dX!FVRu6paX#2j1T3 z<9cU+;`Pv?DimdUDIbQ?PRbct!;o-`s7hI!x7sYHUgRv({+z9cYm#|i?{T?2NPuhP zjh^1|k+^^7y-U{!o~|?%ylC*=+o`?^gku>*J$VelFO0 zlP65f-6;iUv++9oSHWCD%Qb65mw5C)5wS-!8)-U}6U-y!F zdd_V7I6GgGLbHvqiJEUFej6)Krv^jY!4cZQRa5rjgGIr&)=W(by!4M$=Bi#pKBuN- zgLGVv0zytWSpc%YOmjj2GLKTD|mO?fubFww(}ZshF@AsCPx`#5| z9~CSJ%#uFlJiQh+Fgtv2rq#vC>EaDd>ZHg{%DYM3@gwrH@R;Z#Y?#sRRYAgK2~Z(} zk&l0nAoPc!?F(5-nq8nrg|eBkPBn|7<@Ai4@)pX zI(wOpm)s&yR{p7@xU#sEzPJ;#d(k`OrC6c`8LQo+*;B8+L|3p8#5?``z(Q zwQ+T}B?X#lefNWgRfS>OC}Qxf zO1YKji%*4T^X42^eX?@TXz8r%5BvAFH0mgkto1C?JI1s+D6zht_a_nP6ICmj2nxNy zS1|mt#d?G-09G^=^8KW@iB!RN9vd&_pH)D8T(te2(EJ-quQ>tv*1ZUBA@}qL6syn2 z$MqLJN{G{Ci)kp%($GI}I-x?G)uV8Z{z~VQ^O=-#KZ4r@aXdf57O3h~P$01Opeb+c z=fv0;jedobqm+RZ}s~;~YyU%14+3E_>$YS95ss z+2=`05gq%pi%|qmCndse4+c?-@@}rF4&KhFqhGulOQ!-f!erCbx3{)ldk1t~X1MEp z_MZq0s94%J5sx3!)6|qZa@u=u)68Riu~1<82ptUd*oJS!nMVEHwfHaVjG~-PYCd$% z+ZR(>RF{^TNcKj%WAnb=adV#^%+a088wt2$;&DZ-qF747d-j(1CVP2^_{E{Z?^YmU zKV`Qo|D%2ZumQF_>@}lhal#FHe4#R!e6InVHSiSsbp{XV-V#zjB6=NAF_F7YMIwEt zpa1#!bWNsohyziQw3%W`F(ro*TQpIJ+o>}-LDE5=YZb(fQ}`XZfye4m`jYb9r~vo7 z04({uzd92I+FCkCv_nF+*)e!lPW^UuM0ohqmsEv%_3|tv$>Jh*m~}C!GMR@^LShUT z46RdT&m3YYyXgR9VPn4dab(IBlhe%444F99{?Lpsg7>@q()G8o^;-|81sgc&xLF=h z`xM;XWw_$bcGZa7_W2lLI+O(!Dy!=+mh1~p~b(q7ZgpQ4XRKF=}8yC3kEyV+l zv@^a>pQ5{ZNbXhBJ0eok`9`ONr@0X1n?6?J5Be649MkgJ(Y<5!Vq^`j?MO-Ut?T|Q zNxY6;QFA2&@3ZBRy}dnS)(cTbJv4tOR~xvh&&HIdN+L2ff-pTGtgk5?HY1fF;tr~p zrD2MX=Y~Su)`n$*+37_v=U}(qWD;0d*(mTe&UUAiYFFB3sFXVS_AyIGSEWaApc1M5 zB&G2J5+hs)DIisIRWqVeAs#5E5Dz6M+b=kbX_%JaF=aA0G947W^6OVGGO8yF^N`>( z_Rzf!V3J@uO-ukKB!D0U$3&C_$CzsbA?cx7Ee^aa5O7ii=Yaj^BIKrnw91<#hpq&k zp09!l+}^Rrs0((gd3bpAKXj|;ai>7NdHuHT-#!q7xA6_kC%Q+)^!*Mws?4;*Wy^d( z&FACN#%j28HJ;&RB%Icw^hU*Q+|&p5X>b2K3aCVF?)d$<5sAc;*L{`50FJc&3rEs# zgnOomLoqmy?!R zX4~2xU)(G0!F?4N`e7J5x7*HY$v!tKtirrQATg*IF!UR>lfIKC>idK*b`o$oq;n#xGUF#b{WA)d-&aSJ|1K{4Dc%AAZfKs=wdsUe6uk;- z@c=pM@#htD`1_f8p+Q#E$Az?^;GU(VCa9QM9IYTQFT$`jv-znYm3FZuc zx@RnwvNUR1P2fz2E9vx#;6k)y$81(|KR#UD0=9_Ec3l}4U&u3HTUrnP+SkHsW#dxt z&Wr<*l_%V9m88kInqX7;L~pc|e(=7<>iQ?qg{pp zt8o0MH121|;d?J6Dy6JvXm*N0{I;|6aCc4O#$I;Ld*SHfDVv#q#RbZImWZayc2_!v ziYszHznv{bX|H48MxtOCuIIamO}qeylu0li+%Ns!(JQ!;Cde>0NN@+eBVJh;2@0Re zZ2fYeybRbg8y{ai_}ZP&Os=h~QR>NW_u;*HR<7A{x^8j*a4B$V3&pl@btc z#M!(RAB7!9hgQ!QLGTzd0Ry8!mHCx(wo?MN7mc3vvkGk5A~HzR9^6xT6(|}R!Ne7@ z=+siKNiIl8I46?%n)#lFzdRd*w6-<++;d5dW;>_-;qcepvC%U}{0RHFFm*VuCdGV| z={yBF4W{m#h{)q^G6{m`c!ILBn#~Wtyxmt(2lx-b3FNLf*L3Mj3eC79>57Y)fX>vh zO*<}~Hpq?11erYS{}v0G2(-zY_`;GR%>Cxq?#tx9L@hs$&e5Ik9%7F~_W_!d#)8Pv zpsrfsHX+YjOO9#g8#|H%XX3&t>ICCPUN9XW!R$-7gywhW{lZse4D5&xi@+NIU)dGE3BO5Vocd#HLF8(FbdoNs*C($LQj$gDBaGq2MI zd6?gS`>t+z2b>sMh`#XyYCn07^;u}rpp$edL!-(tJpl%Rg&^!bnVvF95V3^vGw!yO z2G3DF4NjL4c=MRQB01wupDL1@8#dVhl4AZ z!?9OciWCSj>f-F3w9yD4!}SmeXSI{gD}QZTkLoe_%#SEAwHvzS_-)B^Bi(sMXt%ZI zYZ$Noj=cfp*R|qyVqrZ|3;IEmVax6a^oWg<^Gnk~&o^sJvLk1nM9pgeuBm&%YlqD4 zQohN-IIuLgn8ZRcTFuC(;;E%66e;uAYt9SmT5)68rEoET&MlG0vmjco1X2Z3N{#zB z`Pb#=1xIDn*I$)NV-g~oodEEn9EfZE-B@lS*Y75kUvC5zu|KBo&xh}H_$=r^eS8C{ zX8O9T`7saoo|LlB_Hhe1YOKbT=k`Gwmhb_^ET+;K+&!= z@F}}4(r*~ZhuFb;b5+RVJRh0NZbuUxX@-8bFc>=>NRz8107 z=s9ysGTN^43emoeSwY8E>CHS2pU$oJxTUw{`({T5sC=^pero}kC7&_A=v=b9*1?y3 zBV0D~$-NVb03=kUyZzdd-r z%Q*j1zva$ig`QO@E4s5lbAX7UV}LzT$JH#r?x@-^4ti^+D)QLI($X*5ck;&o)qzfx z0NKPmA`UnweVUO~{vNjg-2e#y?Pzbz_HizZ#!bV5d{+cmHxf(gRxB>NX{ zpxmI$X-$5e$yuJ0s7L-t#s{U-oTX5UuSk9^6JPF0-zU-kpj^no0*%^;k- zDUrBstDOzuZt!Y)uNY~3)i9{?nJ!Uh+~D9YjC3hA={KvQXbb{CtFdm(2rI#utnZ1l z58D8?gcdg&dfXUZfgV}XDeu9V3U;M^@u#6WFDMrVvdc_Im(*v%c}=L7<)>?SQL)x# zA`hj7$?E82{X;>?dHB@>4z<}V>FBrfNb^#b-sglYL4@hV>1_7b42&i7i~J$PIARWn zJ`Cx`Jk14pPm-4ag)}4<(CTi8$Z=gdcTOKiNCVD@TxFimB}(hKf0lY4=zM zOtq-sKObJq2m%{^K*gj!Lt>lxt<3ao5d8SX;Sg27rT~Crat(e*iDxg^tolE^hPCnF9YpH&a?@WG4@d17!IH#!#9%^4`7Cg|(cd@-G{eOO3;~ zO1~|;&LAmJOVZG&9&zJQ$Ynse>eA}2%k6#%b1_06evjHw>x2cJNn zgK%y)mZIWmzr^wAflm2+i@&q~_0ONt)*~s~!Aq^C z`6*NDF_us;bb!NvB$^A0ByXN)?t7P6Rj&MRj2RbhgyRWZ6E!-jeopCOXmUl~&C=Mr z(s}kOQY6k-ZyyD~8YAf=HxS_IGTa#W-^-j^!K3F8c|pCm5mmh>Tp zh?SD-m+`Y!kn=u`9{tiWsAW?+l}z~Y_NN5hcHN4N>sci9I!ATd{EPg3mg7&25|GGy)km&^e6IB$ z&yLjhfi)cy3$f@f^(ouh9}&@#I^ql$<@|hWlzi`pNd=?r9*kAx<}RjyVJ$o>H_jCu zNx6+I)z{JvN#*Km-K#n}0L8hS!$db3fkJl|+vEQmjw_wuzs%GSpRxA1QfdJ_l2 z%TDd{&&#nMhloNfpPsqLNnK9P3)4F%hMbo;eaF4r?8k#k;|eQNngjgwmIO|LK|kEA zR$kTuYejBbKI^DO{&4+`>gcadO!<1lcM2=hMn})vIi>`{>zMjYe?;{|T==9`LYw>v z!a_o?&5u?D;dhy3J}nf?3sO!HWOqHobN1}WPTg3Lt_V5T6M*8Tfgx|Y>v#L{n+a98 z>{ZXPBcuQ%QSCpJj(&byV|bzJr$zn+g8bw|={Hg~b+_?Jw8|(usI*#EFAS*p!35I9 zgIuU~eXQVL1l*R4Zr<#bPFEbCP0L4)hKDM#swNbj-DB_+e*;53zvzjCoD-!P@b|Ka zk_}L7aN)+)SdKkxnpidwOy#)VMeUalVNw-qRR|ugDM}xx$$39$!jRpve<|mq*H{_z z2sr_4gv&tcNp~nJA9dF|!LJ%3X`{~7KK?GwV#$WT)2{rh33sCBx|HJT2_ z_FTNKBQ886TJc0(GZI97tIIn;n^?)_j1*VjC9ACO=T|tUIxv{WPX+G%f1JH#RFrGq zHw;4!Jp&9OJtNX73et^)bT=X?DJ|V29ZEdS_k^-#;&4oU4Vc17i!>;bV@! z{A@Xj(UrKW=%7cEdO_+fOI>2CnC(=7l%X|uYSJv`Y&#T4h_K~c0in}^b550TU|dNi z=IZ4oh|A{8uxuYltSkbg&Aa`|8D2e@-3m}mL6hWDy4m$r_vminX4 z$S-xhv`QZl+A_kCVsUZsZpaNh3d#>0)5_q;5o&Rq5Se74k9UoL8-y-{+Q4Gu7qrk7 zx4fd@5tQUUlloIxs=>o~h_P=}T!D+*A6p+1^c-j}n>{?el?4ps?UY~ku+)3z>zy=_N*ay~ zjx)uSn0@GDkpMEvD;Nw@?(6MMJY)ngV5&3i-+_aDqY&2Qb?}%(8>nNIfKlZ$_|9qR z!(Gz9Z-d{7+z_tWGy*R1B!1kM!G`7e=g8a-{f`fqc6v0r$!aXFEQIam6?|Ugd^97z zfDtg@qGS2fYh>^>#Mcxc0sA3JRQdxI{}2d;PPfgtakrhAiL-yEA;%l<)>Q9d}YY={#~Ne|ElI+uHvt@x#*#U5@YETjdZ zA>`x=6`1Ey%83|yH)hQ&U>9eYBA zMlVi_PLN0?Q|J{9j!fYufQ9MAD*)R2DoYcwHUlYhIeUK#5q|^<;64;U??z7`38~3> zYniKECSS%tE1&o2c{g6JP8q%kUU`@*9OnZ5c?b`P4Gds*DK&LrOK$=W^TmC7#(su5 ztSjinx=g-=Jt+MKt`ymT(8!&N|~YdToCn#_W&SjZM=}YchK8$l|N!-Bv8Q;JeH&58Aq!^JEZIZ zlR<93(@2L0W$;W9J+TbiD zL|O=U;{7-lBoK7WHMy~t0Q?A&EYR-=k~lLszw6Nt^a>`U2hNxV7J^qVb|#qrHd5_& z$;|gs$@72PYiH2*QHx_>q*8DHDxKRK=9U z48{p1MDY)2i)UZR)`IY`bCxM)DaSzQ*#2Y}3cv+B#4v8w0#Ry@^7dsyy}FOb4R6F+ zT2V>>Y7X6aAanvz*XJhNXtAykjg&CP4SmR1@L)jSu-CQ6a-QS+VGP>`1d}&$`^rEQE!x(Cb4>X28t-V6P}Vv-*Q32z8~&EIV9uKzTAr@ z=DJ=(z5QJ!3_@P%-;&4gED{~hK*lt7+aK`b1leGP87N1|ghaXl(YbbF_WZei~z$gi&X!GiA|VTgCr<=4VE~Ae1q0=ME$` zYfY>oX4g+Q;59trr|Ee%`D`}&SAdTOI8oi>x<9uNJU*a)f#We)8o9k4$qlZ}DqM`~; zaV3sff8}{(!;GW87d!Y!()JB76l?{c?ChABU~E9#JOM5OOy1Wh5NTsrwJ>SHaeNoz zuT5a$7v@pw^HWo=36=o&wRu3VYX`8RU=5ZAQ*FDeu6o%}cShh4)7==-@5YH=J%rv9 zl#4zA;{NT>2EX%@wha1K>lOn>tjBm_7AVaJIkb45+5PWVjUyzoo&;1UrKHlAU%HAO4r;4qNATGnmJl8S1)@wd%_*S z-7GB>28LQ$eQ7#tdtC0ALTIn=n-0g9M9W2SMi?8KCeFK4Z(+gQlE%JVH7}jYCumF!IbmgJ`!-$ z{`(gZf+j|Efe9vupx4mZ)_<$jrr;+7=Au1w_*N8+d{euQ@z0xL7mpKipAZb`?j9>o z&d1lnRH*?h0cS0tImkh_y>g;6kjhu+^AP4OD3mNf7P&XCJ$oemz{@ZZ5<)ND*{(k;PCfHmLdVGo!x8RP65Cqt1uI(xMB2cWiHZRp&3! zdRfCc)Y*_b5@a}-xDylf<2Jzv2g|tj_){=}w?N&;!Zc4_%oVC)?=~DOqkJ>RuR050 zuKD2Up0Mhn;a9#*OcYu#?QM|1i0SUF*56)0U7jxO&ec8zWD;9$%e6zSzIHg0VUjMy zK_3CGxYw0S{^vsvFFRPkat~$9X`?;nWXbRdoRiJJz86CvkW)cHBhQgiMGHz)V?jKa zj973y8JHlP@<9-KoF1mSY)h_7H?Ixb|9p@Cei(RV8+g=P6-T@k;{uEHM|Nt4@1Ct- zwCA?f{=v-D z)4sY7uNF;*`l9ARAmVp#?Ri_8$A>p}<}XFW-`=vm+z;~6%B0T~Oh)+gLV z00%`S1ihUsEQ1}BGWvPDpf#;OMJJxj9ho2Pf!4G?4nAuZsxXDn^ntg;AV3$+?7`9i zkGM?$mfb(84>zlUesK%>Em4w5##ql~sV}N|bmDPfa=ixvf&M0hD$*s@S?iS1JtG-2yj&C`8{53&tDQ z4q767jOY7M{a~605^h7mk>|_-7L-y3(ijPXRlEy19e-be_m%VY z+jl@Mb^-`YI`Svq0s*;V1#-{50bRGZ_bq{CQx=6|n6AqUxslo~S z&-l}gU=(UEcew-fk1xv_M$N~t}eq-H2#3+1UoN_pWR3nMvCPV=GvP2akqrmWnNUC}$1d=E>yb=2$J@N4V< zA~-(W`ZFGPs>(tyOLkdCW zt?F+#eX>tI)NFA&@#Y@B9lB}YMWmo1(2KxC00`JIj!slD7x4C$q@YNZkL~|}%o%cA z6ncDmJ(acI)VMI}G~|fx;L6?pF$uPGCxPo(^6|x+U0Ni4Syv{aTR)*d#0`}Q;yPy{}aRh zbI}Ybp`|AT-2#IsQ9;HEXOU@>4}2aNtFTHuODidV$u_l{z#iL>{$@Eu_o9s!Hp25* z_IfFi*e&fCjmT-E+ zu-~8ST&A@5!Jb$?@9-y9msN)9=JzuUQx2ohDi6{g&m$VlsCPmRN#KzNE?9@C;RCEm zx%Xgm>;W57nVR_h+!GGl-{`?@X&`q!bDq?Z%`wOHs)C!+aho(7l>>+;DiJIkDEozJ z9^PZTxxmWY&Fk3bPOQ7P-_h*ekhBDwF?nwD@+r6<9FB-LRj%sB&GDqk!2C82J-(kn z&rbvPYD#ru^;F*#3Jbkz6dV?xc z8H%tW?d8Pg55M#XgHe8pmSgzY8*sG|aK{`g7Pv{=Vl4s#hG$~>VKN2CF(@#NQ9Eji z2a=pq6}h`+dh+v9p)OwUazk9d0v}GJVc7YJOS!!cWc71F)XH-jYHFnsWg7mB>p7|0 zq`9fxuI^3KPj~P0|K6~F`-r2>n3be2{3Y1WQL)S+Ws`rJOZ7ia!*uO>k=@rl1 zBffPoO-l9s`=DN-JRVbUj|yIHVX0tyz+w_ zc;8*Y8Ys$`favZ_@!ARh@tWzR0D{1k%YY4plZ?h~)I2(N5Z>Qup*`c~@kwkZpHs&# zzXqU0So*%KyPl6)T^lVo;+)rT=dCpt`i^im-T{PRUkL@|X8Meg?@9wm+W?ZBLoYx( z_Qnth%AV!@GD1>!H$`MoeoCIB#`|St-pRDE{N>#(&eluHhp_Q&1UJ%aY(Cu+ga4_l zDpbQIB*4XX_Rbw7<-vWbN+eaML~s11h9tlGy!q9^uvLfTF4@+I#ZDJdyyuB@+|UdIyd zG|2>nDO@@tK~zx73+LZ@O+hi3`v|oIcE}r2ajdO}tYB234!ON;FBW=F^||ZN`gDoM zwoOl?0iVu(&TDT^=8Z+}B+oX*;SJ5(_@;6FWK8cYv(2~Bxd#Qz-(Q`-=qYJAIlzqb z6Ud7Kvl(y()GQ7+wXFeaC?A(34Lhf+s)o*w@74*nQrYEi7df!s7xNHNXD2b-h;|N^ zBtM{PLtDk0>Y9rCQDNhiEqgO3GKLHR9h^i#G{H zHg9-6iFT+9b>??ptL*5R_73OoQ{}fS&8T)?91GCJiR}e|1gpHn?y`M5{yxo`t02Qy z>>wKZY7Pk-B>jacPcSVZ!@6Rye0SdBCGmXnWRbC8|^L^Ernfc>_q9D8z!*Gcj>VBwd0 zVEERTtBXl>;qS}4mK$02h~t~llah6;NaE zY|myg)wpYHEJO}0yc`M8d`md0b-H0qdhxDfMN*U`pO71x=vRAwbMY~zsyulXVcc(2 zU7;N3$vCC^*5KGt5vVm%md;vD=gtQk%E^+;Ys;BxV^Ta!P_K7;J`fdZr;`O0+-_&_ z6AIxadZBXwEDL|+b$>!hVKd9jP`X3bRo)OnyT*(8+2s#i2M2u$ml_mHQ1#-z9~ajv z(Z{m9RAm?#+(|jBKwAG1yzXCHHSyY_eU#}@7ch-UdWiW3T>L1vO9YeD)D`}VFq)^A zxBEk(lG?#N%+rm=3~3ptRt2$KVYkgo?%Gs$mlAspky8ai(k%FFsW6z8yz%wukJ`K*&GM_H%1&Qn3O%n( zPbgMrr02l*VsV|J3H^q}NcvQ_LX;i=lxy{UfQvR0aF={WLtLN;5`<+d@etamuGR5C z!nxxV%x;%wP)U%0?GL(;LzV1Pxm?|kWZQ3BySwb`6m17xjox?vxbZn!_f0IIY+zP@ zLu{LusTGCV@SvN7dg)7HDLK|39N?z=irdnY7w$;@3eaGSKe3N+w`v>&+FmW)fTtW= z7U-+A4EgGRvJne*a952{B6Ad;P0Z@MTRnd!;QXuzoI|Ytwe8v%<-?hX5?k?3yzo=8YM7u|3HB3TY|QSF8JvE*g-h4 z5}}kEZ^6ghd1ku0y7te#d&AkC%FCa3bG_uAg$mn=elU4DKvO)xTcMTgP$1&q^y%G> z?6)++Swq92@|h|};=7)^cF)raVw%6+psi_CKtq)k_>R67)W}2?bf=xWnPcJpp_Hfm8X7RN~PH^(Cof| z&JDm6{I(=ktKE3q=!bWb=-(Hl(1LDSZ|y`t#dHq71D6H2@~5AO*bYeXy@WpK_X#-zya*4N_beAM1i`7Zi&$eVePs}PgXpvTB^%HPz-UX_j5 z0WNG;`pa_Q`43UJZ9K-+4aLavhgud5Z4DSH0S|=67QqRQr>3Hp5YN6S7*%RAf0WjD zUMp|Sjhxd2^jtQIH93n3*GQlGUvn@sgJ_p(NJH-8VebIWd{(MiA_`+{l(QXtpEfXI z*@krUWtr7n;k>jzWRA>^`T?(8rm~_ix4@03VX&J^OP*x9PiGZ*Ba_nA{BP5CfC^bD zxn;&&f+>XrIB|FAaS|Z=?rLd;t4|BYgGQXTd#Z1KNOJmN(O5qPaQz=bP zGCy!V9jb9`Y$+#)m!z_f%sG3H=4qATv-MU>-%t8wRyqs&E<9!p#A?4t9Z3~$lZIoy z7MQjlH)!Y)T1e~-bP2){kDcGdyn*fOsEW|G&tF(gV1M4<iE_ropFSYf(cQ)FXa% z5Jy(N3K%8YK0sjF;md6~!U&$wkVpRne43{m9dzbxdC)U}x|)#$cNmujA}GtkSTW;8 zJIS>noWTxepZU#<`&&@?BgX7=Vpa-NsUr-ekasp;7T(R0ypu2cmNZ)`;sRi$#h|T1SKdG-!yr^rv{~6hX~;>gq26 zRD`Je)PAST%G<53P9H-9!x)_#&pNW}MSZ*Lt#s}C`f%Iu&{U^< z^;(fGGuMby|7>F-xBTsAdeT?CKAKbyJ0r&iE6eM+4Bv=4ZTO7L10L&|;0FNWdXqro zraE1~@R8qH|sb&JN?Xa0swMA#hIY;t8kGHdgRPee9IHb_-)*$$C54Xt&W z&MF7ga`F2{mL{34KXtvZx1uA)uzUDD6I((9(fEL?IzEvqU2R zwBpm*S2HUSrPyy}do&;$DeD^U_!>g=DE1&$b(^UUIL=KJ;_k0a+;#R$7$ zGA&3Ja^+uy)2c}OhODpkMc3|cM1d3bIVJG<{qF<1h7>{Jq{}^FDb$}kqeH*FWiF14 z5V7m&Oe7>X_1TWK_0jjYN{Q6nsmZMU5$(DEq^V4F{zq-soGUHsBQUr6)5+S~y%O5#ZIkOAb0~^;KL@+#+bO%i7h^FEbLbHK;SKUs6~^q}jn7 zYZ`}D!cOx=_kH3!(As~;($s^O5oT&Q!8jKOs8;}d6{R2%6d#NvM|~TYP>z$(U~f00 zdc{&+rnCeK#>b`$+hg-J-U*SEJQ5wHkkoo~LXrK8h@MimHEL0)Yc3YJx)4B}HU{3F zD+KQ_qLY=n%|Y-uK9?3rt0$05WyL$}ZS*;K^h_3CIpy*>ih|h(!(dz4`0P7*m7RIo zW%%sLi4E{j*j=u&)WO#GRfF;6b>({2x`mlPL|;iInf@jyfpPiI9A3I+GWqDCoOXVuV-=~Znn_L;Yx-wrBQ7RXEWN*8xb}Km zP;Hz7iZQH_Jch(=cQzp4_mxO!IN+H zvyo|!6|po1D`pM+hn~kB7kowl93>t*Q&ZD9?h@^}93ba(_5$z2>9@oHtvQWYxdKWD zWQ&wdhmz>`x|%1K{?N`yIk~d_d?ajf@hfPk-~@h=ler)djW$;f)r&c23zw&)p`@>s zisDg2JsO-=Nn6@+-L2-~vh3zxS|Xk%>Wl;?6tnH^?RCVJC!T*GFaCKuwtL`)W=8@U zawerrs1wMPF7tpFXb;r}N6mS+_F0FI2CI0(TUQaKyBU2>&@JVIa&@3eJ(T%iwv5}# z^Q*Pa2V20DxQ%^-NRj~K=>y%tyL!>C-F)LH=PxW7g~*o!o~R=DF8<}i!L{?Rw{CQ2 zc#0iwJgtRg7+dAGSTq5<^q z=C*$W{!qVfh_|-^l&S9?WIGvkwG*{j1@(~#pNs%t^AkHh6sqD10s)U3DGV@T^XX{5) z!Y!E5+J0p+Q}WKx?(@`MUc;M6!g)ky_69gNO3NfD-Y9bP^65vFbJo<+Y7z zNkyC2jCo*a;s~))TazsUEM<#)W4-HCU*h?bo{Q9sx-Y{=zhbU_%k+^)GN=Chc?Gok z-Bee4#4srqjf*zi$9~v0k8WPiqFSG|}w4IJ^#fkF>?O80}neWp@Rt8^=zEPERgLdL4uic1V zInu7F)P)oUgK5d;LgES%EEnSp9{CC0SP28dN;3fQAt^3d(g|#`Y-0F;o{?xpZ}r02 zQIH$SJZCUH^6|sr#*GggtKx&LFI(4dx{t^DEv8##bD%fGA58aMP0U-$ff01v99ndt z(KLl!NjTP88ex#3;NdX?EW`j{QkN)1;r-@Kcxo^!x8B&tndPp}KY$d)BTb^Y=&-sa zv!5(9PI`B+k@D7?z;&_COE>|%b;OxI6>dYe$svAP2 z1{JsGK;a#jGL+?*GIo=pFc6(sOR_Ri2I|;jq^LnN_KRS9@iS^EHK=CtT9O5=T{#OP z*KnEpP0Q!!FZZKJ-h}iwgJCxGyPc{bORn7b3ubZ7VOP}fM}X!nA3&Z4dUxsm0uEuh zQMcJl%6np;2$h9=-n*fa`K+G0nyXP;{IPv&yYRS#Kh*f;QGU=O=o z%@A)yx85Gc@i(3kFwm<`8LZ`o1_GpvMk1Nzcv55vLWsco7ehX&cMbBP$C;`|F`C?i_lTIxB@hg-m?!RGSv zQep9t7XA-JQJzvy$;KIi+2W%tK|ZY=LGR@wl-Lfq z=nKfdN^HCM#?8tm*s6j_emr+-WsN(G)J19>EO%f4=8+E*LJGx|nZy4#=`4;X>o26U z-Ggg4tsa^>=)$5#pte21aSrYuP;x@KAr;Av)mCL%Jqx3 z%rei7E)h?r18phTUMes`^py&&NpS9{cRy19Wo+|8PG>$3Uoyp8|2;BoAiCSAfZnvP zV_h1;HAjC947f-4GB2WcMi%AcuJ{L=ceh5qjch}uv?MP;*8D%Gsy#=tN-YP?V3>p1 zc94~08P>+~lPsVEnsq0vD$G|2*o-y{Gh7+CjAhFLBEU@WKlrr2JpgBNUrEMoXXqqu zgm?uLqt;F{RK^WInUpZd9r8r&1-9f8<`op%0-DK)9Y)eYiY||2Pc4-Dij0ABZXV|N zDcgQmxn!xqH6_d?hD$+;Q|iV&x*1TyQ2*tP{Bq&N5i5eHDbPiX0+e<(Ff0VR0abva z++6=MvYZQ$0Z$d6kG1%}B%xJ$D*cs&hWkX2nMSyH{Xm`3rg-{bimqv0)=d0{wke*0 zRV(=?X!`^jq-GZI^a-9+m%4X{oJ0^$Q0#J1bD+i1K5ef?Rl`q((ZGf`>Tk8A^s2b_ zC3e(VY6?8ykPaRVC;-x2-U~*mYspdjRxE=h{w8txx5WfT)$HiLwn)N#>t&2?T_g_! zCYel4J2xei6KNNebJJ6xIRJHrKVryf5fk^~wTxO$l6bCzd?e(;8#)#|9MCFn1l{fEBRND}x02ZgU&_rxLLlY{ zxXY;HTrhD&U6z=i&~A#P!4AS#h&t}_sn}ZA+s=@Ous?>_2?B^I1KamswsD33K~yv5 zKlo-e(2dXasP+JUW#Su17QQ(`mssIbp3NP#CyaRPGuNXZlYPe=E|qG zItitlfgP|H1F|S;{~)*ns&guVDK4K^idq18uGr*@7ccS~*JWuj&@Iq0A|jz3QGDU( z+#{hM=GpjUDeq7dgS*0P$n9|u7RIBMbgaQe&=|HF3y-P!l~>+E?`)YLP}>$pfhAr0=UW_M^jP$_gYf{F(i)(aMcuX#3#BM)(tjh$cw#1o zcgX0GBPtUwVdH$bKBPrO)5SY==DAvLdbcNTpemv9^8XjtZRGQw>3i-ePLz|dtMOEJ z%VW`B7E`*dPueOj#i@(L4*41L6fh45xZCpYyL^ERInyzfp$x_iu5)f;Y)&R`?SE8E zTN5Q@3YKNFDV#$|-josLgxW8P0ur;A;A6!~rg!z)r9`(lTc5W!X-F`q_YP+<@ ztW?bT^r^P^m*m?e0N}2(q6Qa=q5xf#Lz5HRIHP^9l2O8zU$L1w*?Twfr(RW^aZ}d* zYYbjSgGx9Dj)W-oUGxU$pk?0?Q^q8%&BY5P;*g$^kio~Ks?8tF($&N5Ob{sHOQ)Tkp-kD#V0-CeI1t+lF?sf(ie~KygH@-H zP2LL!4Tzxmvc)FCc`jy*NZ6s&pZV|2`v3IqeI(HWaK&VN;izx>h}HTsnA-9{cN-Oy zNy@i_Yz6C{Z&p5`Br4GK<*r=Mbg*hTfLy3Ty1}7iAbK|cTLnAmBwL0SS#@wUZvaM5 z637FH0he6vIt3_cUWo2kFo&)AT%cSO(WR&%+BM0ByZM=Q!eMQ*y9>16KY8p$7Cp8& zhuFED*E!W+Ob+&4H*>4b7}-u;aNMTLXX=O>tWwacO2`rupa$A-uXm%jz5cjbh&Y4F z;hOv7#_WLK^1WU(?lwx2W2ExI2hz?f%1l)pzRVs@PI(6x+sS#oY6@=Mvb?+2Dd+Re z(rM1#+4G-%aGXZtJEC6h?#{z>{ol>ZczqPEF-}{YOP&iKlQY~}(7Cza+EE2R1s;|V zcZ&$#$P$|`L;$RW-O>C1oc7+l6d;NK4!{kmE~3WA_=G%B2t^u5$_}m>0+ftY5WS5S zTp#i+ILL+#ziGx+RX(N*LJTxYcXbSM8$zv~Ebn za(G6=YOF%5VqU}YquhYB!YJSVGX`9?3gf2a3w@Moy--EW{IoSxkmY7P!eXts`zK>H zh!boNOAF2jaU0JajkN`$MHt-ynyu&!telOu$?a<*A}-~!sF?=QjhZ4s?9URvS-o>- z3SpzHQZW;7ecJrW$a`@%!PNq>$Gzqz6!4u+;94{nFIOAFw3cGJz8gT#(YT^{WMS_* z*7v-TbjD0?x7Wq#3mzvd$Q=~jy1a)jeSV|8Te*K4jP~NG%U$`-LfAb(mheAY^{)>R zp=h1><4+-+=xwyENq~2QFNq+7TRTN0aFS$YYJVfWg0ji3Sr3tL_-ic9ZbIKakJNWD zI+D~ZwFCPTs{yoBR0_GVfOT_|+g9R@>owrLknUTF3aldm+^@Rn3F4`5-TH}cy9UTa z*;(&4Uvi#1olNie31>Y>kbyNNfWEq>5YEdr0HYqKsb_UhqVBiyuVQ@e-I-agBE!NA zAm5N^Egebt{4+#ldEQ5sNC>^w^v`%eL>c7tLRoTygS)P|0rA>Q5qUqC7ZOWkE~_Qv z%&W*lx2?`YV}rl#L^c#!W2mq1ZeiYI(q`h$C_lw@T>qT9x>cn^d|KYUrP;_Mufzre zgZ<>OKAt5%08yB%V=^lxVp<6#Ms%v#bnIf6dKV&pnr94Y17oFIW zirDGBv$Jg-3cGkZ;x^M`)W$i}+`=MWTfFLH_}Wm#0iliO@WeSQ6xI}JNpvAcnyEy+Ci7T~DbJGmrFO=t4{ z`f>@YRHx+1uh8>O63G+KE*&$1p~06T;w!81L-Gu*r9#TOwh3De?vO*Kc+wg<2;9A}M z!Qhv4C`)Ohsxein?6q@)I>bJ+=V!8IR-M8q zG{4@_{H;B3aIX|8@%{$Ep+8aoBTxh;c%~n=1DIOMu~EN&CAOx z{`vD$lsGneW@T*x>tLMQtP9>#)?jp zYHK=45UZ?M_VHRpLqdWl%yT%7IM2o!jz8{C7Nxyp`rri+sSN5&1B`2|M|3hwXX_WU zW)_;g?@|fWJffX7%#`(OGsHyA1Gp78yz!C!dZm@U&=KWViB|PCPyfV+{dZ;mcmUS7 z1Jp`phtju;qoU_%oknt~vzN5*o%L$gu7)tJVz$m^zSJmwsSym&Ma=Y3&J^S#Cn4uH z_pVm|qXpotFci&=+=QXr6r7|wMyP|a=JYDbzZXB3nJ6jb9QH7HTIbF@G<)Dwokf&C z$$tLh_`aKu;d%^9H+yj=4K<)!5M=c~($+VV!1f^KoBJE!!6&f6`LLwW32+PCzTU6S zBcBv>=mDTcTOlY< zavkO({xPHc-IwL3M!(?5Uu{1Pjw7MBlc|=_`|XLf*LM9Qq&f>w$ky>si&>J#j7o)9 zGu-P3=pvd&kpR-0Qk@;SIlw=Dw=2y9f(3Hv`TrtcHc{N1QT$K;eG%UvH15gcXyqU? z^dPhn>u8Knvh!jFgPidfzL#gmWIDu_f>?;P%X6kUt}44I{H*j!d#*?ppY9kP0gq>n zNAcp&NpGz>%P&xe;hOFF5`*Fz6R1{Mxwgj3$f~M)J_pZw{Ev_5k!;B+?<+9(+*DdT zfJ&{&=hV>--@z__^NDySbFHNl*vwZGdbBSvP=tloD=H@zz)nqg)MA_VFJj8S@0cNl zKrmG6g0~h+oB--UwbOY~pA6{K{|b)WOX_ct>1r2O#*6|K_ijNWgoTBZQiJ#O-sy3? z?z>xCK@g06s()V%(9OtWpGcaM5>B2X*C2~Ub{_!VeLm2?DDeL7o(b|}p1}EJ!EEs8 z1^-Z`LSEXBH`K{hyw9`5^kQz`PSg|w`1b9F3PiN~CJF~yRZ626@UnVu@6itD<9zga z9hyN+bH%nNg&ztC5W}vGX9*Ll@$V{f^|SoK_y0IiP&PY|^7Outj$7W_olbm>D4OGk zFp5OJi{VUR1=`r6$89gvPS(6N)3>DoMbfq)Fz?4D>;S}nWC;Fo;rd7ik_{oTionz? zjIlGe_^YP`8LTOy2JZ^}=xAt^iys21$t!H1ML;u^@Cts05#k6jf^6l+ACOhg(!Gm` z(UVk6bi}0Ns>peiupL^*_YMvkx@jz1iM|)&x+!)6tQoSbeE`bsu4Tef%z^mSPCfD< zA~HERG9}ix^W~e9M=PI13_!HuT5$B8!m(-Sz2LgOe&==1QcQ7^esk!jCnj0mTNxP{ z%D>LQyz)$L21UMG%MnyG2o7TaZnNzr+u?h%Gy77}LR`LJCK55N7&>o}wf607*(;=H zW~O;a`Q1!&6jN{Sp+}iOC@gFK9byk)8j$FhHdF)Zi&0TrCBU@yXJh5#MjO&KrZ^4t zXIEtbgI(vxcVMX6r_+g*t3SUDaLouNpR{SGAGd&aUP>$wi+PGOc`~2QAXPg2LVP$* z14Ep}7g;GT|6{iCzxyN@=)M9dtNlK;gP|Rd4*EwuZDIlfDZbsP7z@)uM2T4>I4|Bs zQX0q;oJjb0Jbdb!M7zn1KL8C4XM!522{4iQU%`J{A}|GRvJF8W9UH=DIs^y=TRm}> zU=TS4#l#mV294-*es_&S+RW=v9t$#$(7V#@m8Q8Y&i0|&c|1ZH!vl*P`)l7wR&X;5 z7;_jF00w{{yl$C^zn}&;Rz{VfjlL6?jpJAJW)2`8Qwvk?lte05!89>pVCshZ4JtPd z-2e$HdwXHwWod&F-JN$|zduQgUmek6prWvVR0SWg)dBddY3^YBT>U4PH1tY%`_$Lj zEy4kIYl`#N0iI7K85kkw$%0>)le&|9*CVX$uFi{Jzb^4!KUbzwd6thKPKMwGME1--2*f#ZL`wT55K=EoNEu25XQPH64$1G(*#Sr z(z>Q2D;OW)mJXOx5l)T)>=Xa)A`Pz5l-M9w#bHlOU#c1YdMDMR%yc8veOONtzg%;J zH3=}XiUSdL6(2&X|dwE^F{mPYGYF2M9`IRn#; zAwTN8q$CIb8V}9J#MJZ@$MY=B3X8+7vd~QGSxPMky>ay2G`n(TbMsCJTBD8Fy$6;S zYZhWp5<)SK&OGQ+vzW%}Y^Tsm>&#tUC*o`iCBi>az#KGmqj*OvYGq?$W~ zIV7Y_`zrPI>z_e*+9jj=2)qm5{wx1WoqbJAf9`#;%i`dt*5{g+O={vkb>f*B8Ap=r zmxP`r;+L0GKS^&)-TrPZy!;Gr^CEZnF5BlE*T&}+heAS2sS7Mc8z0MDBZUf!`@UL# zT$^3Wyu3O(R~fd<%FvwlW@yn#nkr}g*7_`{)ausy;AG^9`1kGr4M`inwmJkXvqsuM zd0nOEg*)6C3V7vlNu{~pe6bWQh6j*w^sfLEba!i_@MLog5ztrjBX7U$Kh$?=k&oR5FDz)tI)PZLr-SL3%u1IxyMeK z_W<`~bMH~Hm!Y-_v+X@Cruhgd z5|In``rnE1bif+xM3)?}d}D)?uMD4JAl96o?XzX~%H2n+trjW~u9J+N)tr{ezTeP| zZ-0KSbs$B7?cQNX@xfi97^B}q8Bc5z^meKk{{S!g;#JDH3ybB8WobC9-UXOi|M@gPMe=$PM(~a)vLwwx#D?ZlK zv7@iOn0|I1myafHaq5=8bvH}!Q8J3*w0X;6Um!e{-Rk%K7w1310)z7dEH{7N4=YNq z++k&EGmORLuQBf&y`K(aO>CF>*(46w)NgdD;*h#wqz$`lw_F*y?F`S$_Z7UeUk>L} z8KySoaUp9u{GLz>-?1{rP)koT>&FrZn`Cr;bF-^oroXzeiA|A~kVJo#uKOwyzza^9 zmg%6Gds{`51IAy!3WF?~>oA8V4tG(;j zo$y;tD!5O=5Lz+P==ej8@$W+BrXLBVPJVZH32<;2()~I5?8r!)r$!_UEwMd}&ayPb z)_4Z+hp10WqZ0qV+SaN{H0a)5wmV%mUC;jHXXEbnRQ48{F%jQb&~uX4@x>=wK#6v_ zlz8QFkC2GytnDp;Ry=zn_SNSMV;)rB{j1v zPo?sg%gl`hp8J=~uA80Y6~eVeTWmX@jU7LY(n<}!4nZ4%4vSWT>Nn0LOm?Hk$NhfVN8dVOI6?S2GQxF^r8-EwI(7Z`m!GmY zce&=Ldh3Ycn`r6^MueB~M&N1muinay?Zu;^Qp6>lZ+Ifuw2Lxc6UDl_m?UMrtEe~& z3=PLnpN#BYcT>jE2M}uK8@I1cnuT@3*1KRspA;%{s~n~_ z=Z@&T78X~tZ!eh2CAkJ9$TWbwT{1#q(W(Lq9j6QlIE zP5@>wDnj)6QGdXah`oM=nAzO}<`YY=5izC3nuEc7Vl5k%_!{b~u7D4HOW`0FPt(E$ zr>+dx8l&r}eiI(KV_oB`JijK=%a2*|hbNWC?K^;j2o=UR)fGv`Y1a;1KUn2*_nly{!!Wbj+N@rgU2pmyq!de*RgSz1x^r8Z1Zc zp|r!)-aY0He0_~HIP@DdsFZoX;HqZa`AwwQw0Lx%P6L&}by?G4&e!Lo!Qto+s6e-! zr2|8`7T)!Jl?&rpW7B`4J=Qsi@oe#xm1)l^Pu*Ezf_4f*IKvY?ic=t3b2q2_a%*xv z-JbVfLfrvKsI4sh$Su}L;McvyU+(lamDK_M2b@Csd2BkUzzBSAe&e3V{LB&t<;q-5 zpRi+KY}XMPrDjEYW4@V!&mx$kFKtky5hjI$r_FI)ZSSW(tay+*)OZUf&?S6gxt%o> zo;_z~HyU>5i;11GY}-O@`_d!CSZYjNZ@HN){@P1I8E?Y}{^mZ%w1!_yPu}Uu;?RaJ z0=Kq!iDJjOPK8>k)co7Z5Gg2N@aErC`?iG=<3C%|fpF<7e> z3k&<|_+7wk$R6Fy$y6P&w(@=J9i4sVbET7aC;DfNu*Fe&j34Z@7yc~ap2n8FEuK8u zH6xwW_cQ3KK1|&^ueb`hPcQD#6bQ&YaLa4)ayi=^gr%)-9pnJWMuRTmvOY=)cO8VOQyx3&?u+M8&)mMi@E5$k}P z+jYx$x59bSPZy!lCuJWzFQ2ZsgN?X?-d}EcF8OVo^M|noR~38{BXmGH_F@+-re;(q z%CZ%*!QLt4w5(Z`ehMSD8q6>IKfHZ;Jd|x4c0{&BWhjz0*|nkUk&?268QWMxmKi(Q z##ShWN|s2BvW*%0zDtsXk=@u!_AUGVU3bs>zR&Yi&-;GgKi@z7lzub!eO>2zoX2^d ztw9ok+9D*s{+ucECUeP~4{%d2ula3;H;??rbnhb{=S_MN*m7w)_4q)Cu1jYU12TP7 z0VdS1o5mL;&~boLh;`1cCZSwc+AT7uS!Lvc0SH|&$(LsqcwnktGkNLk%W672nunRRbzY1woP^3CoRP^rDYk6c%2 z*wt@yeet%TPp)ZLx|vxc92ZL`?8j5EUHE+L>V>X`hIopRMn*1yyXO_&yFJBvqa-e< ztDp+M^n|Y-LYpndFwAMlR|N@^{XH!IV>Pc51(O!h^G*=6t8rf^E@!}zNDL#r!93k~gn703HgtqodS9@`zATVc$-X!7PW1(sZgNS( zX@vb;d0p;pzqG>OQ*BQ;amd9iun=9a0HB?+`Fq>r@^YHFRaJ9!hc^c%1!0#LrlOiH zte?E;3nGWbftV!#|Mtjrf5j+))YR1N%REs6Epz%+*M@CrU(Ra4a1YLlG(C=mIauKx zjg5KfoAek6zjxbj zP$okU%XawZB#@ng>7*w7fRUrNcu1n(Ztq9?l1Ekicg`=q95^`NBQCiO{5AhZUsi_L zr`{`PETe`$*k36ofL4u^mAAStWBnxN_rr?q2fjBV;eH+iPdLHa_wA$+DW+sSJ-r-= zLjt0!Sy18Jy^FJOlG0hcMvA;ItaJ8Dq=wugRgTmXcnqGi5&2DIN@&FK%`XwWbyYRlJh(Emuy6fF6oox;Y$8L6a`Aqv>N}Gh zgnL6gK%IULtqM#OYH1U^yDr(#Dg!NmG5e zFyZiZE?K_Qr*|&*^*Z%E+xKpFw<=?K7i@X?D&z>w!2`-?rv$qr1m}I6=9hI(fquye zw1{ja?rm^@;kspea*3^5TyoE=I`RAab#R#4$Tw&iZhwU}+U+WNBR3@{9T8b8M9ERT z5qIksX5FNezTWs<1L``0(ll!Yn*rlhcRd%bM}$y9shqEq#Uf$HW{tM}+^ z{HoG&!t8y+=*E}>&o%>q-C`Bt2j}u7OZ?IVv9!z=we7ZL5k?v`T4b! z`U1}~CFIh`2zGBkta^KNKa3V(eeB8X>}(9}ymkh+XQU!CE*#6HVn0-c1`7>ROysFT z9x_Hyb3UO4s>zT^#cXlA=^$m7Je$E@!K243<*%~nmHc_p3la7k20>jZZbgEkI=RER zqqE{ONm{j2A;_UOhm;hV+M@WuFSa6nd| z0oVMEO|3nuDA5a?4@ufH_*Z4*B&w0K9{4()UA;P9CMhY2_A5rgb(cH|h2}%u)rI`9 zUKY$6UMy-!^31C{Bsd}Y#4IUdg=5Cdb*QTjCatb3@+r8=pk8vw=QfltMy0m8R0`7t z*fRmVAj~^R0`jLUyh+md$eKV=TB}cCA6BQ17wGtRUjel6?u!n%NR}8fS;pKp7Qx_kn!JGeupu zw##>yxk>NJe!--GF&{KBH8rgPTMD-?O#yhs&-WTUeXU6v#7MbGV=ZLj?TD~Ui4zA6 z{hq8z-VC<)c*5}F!pt=ud%aUxJyo;4iqoY#$7CI+y==E?vn=V3w=ZzqogXX&?IY_& zHXl$xfPm3b&Ym|bVt^dSBY#l}9PRzLu+z1nazgKw5Epba-eTNro!8vABzR|4MD=h9 z*NK332;F>%seB7FupfQ1|Eg+S0`s>^plR5O*Ssq86VWE z4Gjo{)ulQrfe=k9R8&8+D4jiO6U(5^ua}#bH=4M&{v~2{VMJ+bcWWMV<_$Z#Glw%S z^2nYlnH|2Qwzk$CA8yI*UvrB2A}KN0Gv9UOjX{vmyY}4cwV?%caBKV0@s-zQ^GbK! z`>D)WvTj2_*3XweVNVvse8EoT3789MnAw>(JBuE&hPw@3>USL{M&OUI>oXP15a9tQ zBhv84rVf0>rwq_=?~R?*ws*hbG9M=5Y@(){kPMS-1_@wr=MIr$x(&B;qq4W*sj_lzG1@(8l0iorg5^XBUk; zLp^!JSlo5z<@%p1;<3}dM(a|$a&kD?w(7# zHWmo8U#+FpC5-aw-SRx8mpdK^GaLyf91xqisGDCqnxq!ZhcY*RYd=snb`Mszp&6A> z=nLfH8Hk@V3yOOYKvahx`zw;u(oJMp%65}=I^rzqvTT(lKE3i>smH|2!SE^#$Nd&H z&^jfGSQ_?=f|}T*dJw`e1WkB{jiuh7@uU)R^-mw0-WNqNSHHua!$%<+S<}0#6L5e7 z?>G{AroA*2hGh%pofbrNfDbD_5+QmM%lN=5&^%^R>~RtIuTpZFT*`!CdQVV~endVa}Kf8LTMpq5BPK5>I>9X3MlB;>$wC5?oT+uV24 z-6*h6dHRfF?hB|mrh3}jw`A*%f24sgbbG)ksS(Kf$`%PIfUKtFW$Ap@@H|DB<*P8u zw|;C?Icqmo0CvA?%}!dY&0$uvlR8SOo$MtarO4{)>UMoCuijIgtc$IwLh0BsTtVDh zwwsV*=?A>wP&;WPX_bMWzCM5-PlyXVrPZ~$(yH!DD{n$GT8gJDitYJ2JRL;D z5(PGi_p1{BESN~iXSs}xV{U&55m*qV5H$wTYkhqFRq(w@b`-Ar-rPIQ{ve^h5|y>D zr;$>UPU_OvAiJ1y@^t+*PcX6CV-(C~Ssj<(>t&nTr%81$u7F;Oy2Evl%H80V)hT~B z(~lr4q<#rg+01w&Uud%RIdb2slGP@|I3HztowR?`f28e2tiTzINq4WPoX z4CONy>3Z`vDo&>R>r#A+nV-+K$II>-g^QKklY;o|<1=bb&Q zu)8$_<8nS$Qjt23472F3Wr@IaBhuZpQXcFUkaoSS8GbRroC}NOv^OTUOM{n*YU0B6*iXK%RE&p= zGTjkkZPfc~+RpISc&8)Q{9EHJ9gl|yS7Aargi&I%t@da2Q`R(y?eIq&06S!%=H1cx zoLKfW$|niy`BhN)f^>IH4?WpuM>G-tMESG&W_!!*(XPk8dbl4&K@A|IW28F;$AI`; zlq8F~*R5xhqBY5@XGSmm*eI!%p7OJ6tF*Xye;)%<`a&jq8DqMHEh7Gh_pm<-TjMOc#8N{%ELD?@32$AJjT9XxU6PRaM(X7|#QX@-iX6yp!vz7n zaiVkzmJrtw9?kLW3K_#|`Pq(e)5@Qn`5)ixm;ss8sex->4ufNkI111_ENzgG>#dx* zD)%}xDOW@~lz}i3{ME7ki@g1*`9*uejcNS5YgP2+BjJzW9T*Z5PNi?-Q7I$cx{ z^K9x(wAQ}+|EP43mvb!#Ue|s|sQ?PktzU!iJX-Y>hu*Q1CyP*WcAYotB?860Pd1Yt zb%|wpy~CDn;YmHAk;-=LIPm6j5wChv?UY0e3#$~nIwXSRJGyT2wXYWCkb|cj#!!N% z+>i03i#Xrae>PL}8p6nKW9l#qF=5jdhSRxagx+wIyu1HK=lSSX*o4N=-G=X8ziQWy zv#X(bbL)r6D=8zV6<~U#?6>xPdAZ;xOu+2YADDnXqrq@h-&p~j!=<(`>9%MLX**(v z5pzd+B-+y1W~c}h<~Z>DOtjJJOVwHKGy9`~`Qkob*C6r;N%?SD z!Fsa7ORGDkC{20=OACLWKCg_}&9J=I+Ru2y8@qDHSz<(RkC^D&@B3}wA0$znvP8;F zd`;RA;!}78oH>ZmUw``aaJk!bbX1e2v|LuNy<2NEn3`O_vwD3xZiVDepQaj3w@KpG zeS|CO?khAgkSDcIMEa|OIgv%P%w^$g7&%Dd4ruEd~Rpn_x9jIq}!{J zcuZEr4SmO!UfS*;!!JZQ&SNmA?v98ZDulVKJ(@m$ISt)Q5@!0%bAxxu3WXxcytG~j ziX9dq-@kvqgrwx1YuBz7<>Z(a8Z^_>Je#$2W}dQXZ1OrLG4@~Ja_rM zqNL1+kejTluMbP&kLaR?R#DiMe&5F@OWb4&cTBtUf*y0$)4{ zeUT#NU`OIf_L7=Dx)>j7?i*?SL{3rEQ&Ea<-))&w2ZlLELQ;f5?%eU106%Yc@_m(7 zeVdPkcyZPQXO3c#f}a=Gj|_kC_pju23xZ+h;6*gx_Z}K#Q91J{k`0Q~{EdB!+pYDRRyPXNKdNdv3-EezX1K_owxSR^pO6*L3U++_Ef# z;Cq=x?4 z6M2s0fwF2lY~C8wh9IWp5lgkzpfi# zcS#t=6}HOn^+ObuA?8AXgl~SjvwK3O^uYU{glG|nkJqvUiMfTir=hxfI%k{0)4h~k zwMx0iLJi)K)A?a;2Gczpu*0~8Mth@5FF)@;A&!g+eccmY%#$fvZW@%S)7DQbV$^ED z6TNW03orOD4fvV>3!gsITzv;B;pITGJs+aE{}i_skfjxb|Te| zaG^s&MLiyK!E-%@cL)vc1gAPabYF1bkNh*lQ<6nEQE=T%ar9!57jn()AmzF6ejh+_ zkRNn|pFyCxUKWR$Hh&y>C7!P~-E;@N8mYgvIh{TGNUSOc3Ida^@kMSB0%Ra`Li8bY z)htb7_|af88+_O7a83ULr%2PM3nJ%jqmR4RiPD#p4h8Y_zjSh$Py|E+H?Gj0xCYUS zw_Nh+EH6ZG+np$}g^BL()}tA?ZAwsDtGZ|hEdQ3p>e0>i8{dl+&x1?;jbtZnK}Kdz zE;;Cjo27Z9B_MzB0|@XYJxxp!vn|eExM0D?##WS{e>Ps0?q_2Ymje7DfEd_ zXgh`u(Ubk}RC948l=r_Tn_?7TRL#KEt5>%-#ZX`L4}-IJ3@4xeoOp7Ey=QSGR~)By z1Kl8}_q35J`eP|A^Ny(X$hR}IfiN6uBzSuPOUr_{E-hWO%SkR|GiajUd1~_&<&iT{ z=d_$QUc#f#^lMlPd05V2;P)5q{P=M}nv7DA2}NY@E>kE5E2VzUBP{|SvytQDkbEn?NcBP-OJLGac)KD6%BoU_!_k+o!?% z9wLd!u(G5eZ&X>Lq|y!Xb_p$3tbFBTKhA>VzqvE$^Minay^$Ml%?ll2E_qqI7r+p8 zvyZW{ou{YK;%7oRIuhlxva<~dh?BZvRyMDWV_ckJ()^LnFCD0S;818G;0e_ zOw-2L*m-4+IO3YNwzixmRu#tTdu5uYAAY47%3~G8s4M*ZrZzuM#c#EvJ|`Yp-l~Gv z(r>mKuir3Z`v=z*4@uS1AQlaMKnUeCf2CZ#Wio0?E=c!DBvSssfYDy8O!r!Re7vum zoZRXNHM~M|<>APPS^TS4tCwkIyODxX+pk~QZFsR`Ll4b6A|imRI+`SpW)q>i`a4Mm z|JEm}kdr+74iEjhq@TR(Sh{qwxDdrz05Nvju2`mzy5^WWIkkNoAD>-VAcpX|vaAq^ zPZ;3+pwot7QEfNmnu-ls15x$X@hux%!o-xe+%s2 zlYe*ZNSsPAMJZ%L#KcG~E#W5R!G}sg(FW{*O5QWZ20S$81;;N4E$m1g@5r}Rf|qT}B;9pl>2hWdvu|NDtsSMP%f^*MZE z{r&a-b>CsK}Seh;X#;>6-2xTgRMYy8A435rZ7=;JQ(PeDLZ<+L^idWT z@1Tt<#S0H=qL@J{mU35~4M_5Tc^&YcF>nPXSAHg}nH)5?8<6iWfa;%w9+tCyG8E=j zRa9if%FUagZYUV_oq`rI;Vm*B?@)y`sJGmyOBxslN-)}gU7z!Rd3=PeCkf@^BPw*KNlDS^(Fcp(N}8Fk?XIY8ta;2lwF?uz=g2v-97d9Q?M%l1X#o zvWuTzb@QiBJs?N$+r^Tcy)J z+(OJh%GG~OGf8~V*X&JrM12R-%$X7Q8VI)#ePR>_`5un zyd$T*{5UME_uaeu8K19!%ezbybV^mH)tcdZ zbf#Os_uPMe_^=ioKhxQZ7p+sY8e6@x5-X>lH(KEJg!?{xctFpH|!;5Riiwy-kJrTx;Ri9%K|t~KO{=QwOpkwP>B@<3%@ ztR?=}9fBGwKl1FEGYjYRuutmC)oBqo)zmih=iBpQLCh`*)Vx}M;UA*zzu1?O0&-fF zbo2U8pB`5_)Q2*74y6Pok5E^nf#+DG_%imFXaBveP>`gp$ol?{gwx?oHtZ*`1_6ibQHfRRs zeEIwzpJ!U1dD183e@Q$wQk4vjrLH4}oB}))l#kCg0mjc%MzmWtpcGyneDkb6g(9hq zy5Ksh5X=?B`+4=Q0V0xRXIbs+kJd|P*JM&tYPmn zhIUt7@7x)W8WN9J1Lde3P$_E~UqWPd`g-Sjr|y@CV%FwH2hEr z{uTQM%pKN@9d$M3K0e43etYP{SMP+x#Msz{Y>eT)*WN{sqdAGkfjlNS-624hEaixb zBFxax5K3CNwzjg-d)wO;@XXGbYV9ZHZf>1ar`_+~C1~;PJE!&VqR_T@`ny|$FCr&ewe zK(6O{SqdniSj3i$-7#bHUH+X`l#NZJZjQ<`!u7iD?rx0oqp#kSLI?x`Z=Ah#jXlZc zb8Q?>`%`msFHrul@Nhndk;Bjjc!FT&)lfa^H(r706yPd_2DV-`o(?m|!MjzbU|kmM1#yX`G_1ewF!ugPi zlAF*?EKwP_6$bc(EC@^&yueLm-yKQ&A#-UIu4hs-?^{s{hKGmak)m6wOliieJ}Noki@k3V<4lzTUSpY1wc0yJVr{C3)k92R&8t8Rc^sd9E2c-(f;>-+cV?WKJFi z5iaNjstW0q1BWntf>Ot36qUmre!G49TKi;of^qmC)mmM(VORNBA4k~%jjHA^%hT#& zA-l_H+wDWY#z-Y`;M-mo!|^ID8b)edMXUjLkE&FYnmk~C*qCok0cybZFZMj+lKJ{w zw3fC~R3IRGZHiO9DfwNj1!M?tH0krNi!9V~7vLAD!(ERwzI4F$c2XeShhdwOCsEMm2?{$;3d9m%>Vjc=GtoW3ii z&>j#MjkP?CpBO%5*$IT=ERe|XwtVwnWnx$r(4fYaHY$LEkR~S5tM#?a=n`Ik_T0@M zU&&@-WP4O24LF@1*Z7TpuwG2%Acs5=NnrI>Yh_?yAhcOm9F2IE>(vU>Qr^GahJ`%JU`;7OXj2gn;{3tphq^xyq;0{ZM*+0TzPNSW9|;MIfHLVx=k+iK`Y1H z%IZDHoG+WH8}vDA?6U;KQvVA zTsm_P23XqeuC8BolWk$Z2<{=XyD$0C8)f2{!J>@aQsYR~6uF996-NV3Li_+F=}0x` zoysA2Hs1yJMAc09|(aMfHbyPmC^u1IAZ=cbvO z+Y9UgI7?CJEceKJe1Ex8h2b3vrU%4Q4@yCu0L3W2SF+yU?!n}DmLq5FXADxofX1is zB6d5MYiTck{5&TFdn4j%634yPX)8g{w=k8aLqrZbiZOq?n`GS7f3ZES9uHrz-1!S{f}hOUga0Ya$SDk&_I|xR5Qqg*Zc_2 zZnIlCSs9}<9W-|i0c?Pgpn_jtigd8mZ@^b0!K9@H)+!|z&iC8@o&^9GtlC*Mj89A~ z24!#3KyRUQDXQ12#mc}%f?2IcQ!}qN$9m(8!+!gg5XzWLHCa@$_mVUR0X{1PGG2d!a*;C`>5V7f^FSZi^`1u1xgyr-ZcDg`20 z$cjKPg4^($ocmU%Zbunl2Ht3`UC&XR2kGSW^Y!E4jg^5_%q;2dwff!pQ(m|q0t&RZ zWIVsWJ1OU54NWc{s|QsTykXf>iM!sf)!w(SW(?#sI`&Zt1)CfYV#0k$`yPEg5cZS~ zQIZ{6g)AB6bgT`vZs89F^INqf(K6>J_rq9ed1r(77EIh3)X|q3|1qK?$3hSnf~6R%5jca(W1+go zHd3houD3j_ZW#$_=A$DQFJ-{t|`5YtPKS@av+SQ@U|Wx86c&A?A$1B zvOe>R8RT^2BBzCS*oqq(8yETQOq;9@ms1s07S1ZcBAbtw!?qiDpY3E~qO0tcC6^og zw^XTKFxVUZmu8Y4fB@})TFff?vs-|V+8#HF>-_qHMbF)R9p1tZwl4GdOE6->}bBkLBY;E=k98{d9+q`L_gvfij zV#tFxoFPBiSz>M&!dA52lw6Jdp5H2WK4Gu>%rIDH$5C!O7@?pG6=$Xfl)gYGJ;$sm zPD^=;DIIvP+qZ8QK`jU{TTi~oMKjtUQLtcb$4)~xe`1dC+6|JHdK%z_Uy9rPhE66L zsQ}0kU;$U{1&RkaWqzHu?x}pI_yVzWez~pMCVFR2NX2N@>$6ab2lwa6xBA+An@j6Q z5e!R99o(c>(YNAV>z-sCX2f62Y*?%0V_fY!kSqJc!?BzOoqjsjib|Nr5fNKwls}VG z3h88+TUgvTRSta11MYu;6$nFj(gM$K>9%vOYCVL z4mWbC^Sk*b4KMboP))U|OR7K={()GQFWQ5xY1q#9G`W8J&Ygy0INC}vNf(mOsaKXi z;vG6BkgHa8#Jq)JFc`6JylD^){y03m>ibfR*zk|w{lDmyqa`J4STN*&-@gy81oPPb zVEE4*7(bRC?T)v~*&__NP83uv6q}W{-fhk{F_;M6Kk1U+W#o)L z=8V3SlgEHbPXI*+3L#^S1`Y2k{+USGJf7ZzkQt67zs$Hkd_^v?7+^4L!2Ded$Mh(| zgtY`D-^Y9ZUtJFnF$Mkt$0PWOd~+EKWtS*H&;yoQU|8Juq=1LUKRrPQKha@qR>=Zl zic#+8`c&X_iC@S8(?`D!^ITOl#mjNHSPw3o*NYFrvV93NRgTz$<#>W{?IbvaaqNe4 zKZmuzIy8xCW_P231Ax$oHtX0-26VkbK(Lv1306B&k-grur&xJ5y@LS_)TEU{NUBg* zZ(bRImL=4dT|Z))!+%8nwuMv0dR%mrLQvcVD6ks9bM91li2o`9L_6|ktM)?-3_B1% zmcEhwPvTsV1)Y2zNxDGhNUflPg>o0*xJ zyLYa;(Vns`E-uELqJ!rzjD0+Jyq!|1dD1n`mKoinA$$ZPZ~N~SY^@y@foM#B9zoVK z|CSA#u8k_yl+o6;O8YH0-Le)+zQ`7uDRW#4nQg3T!k)COWq)Z6n5pI`stHGnpXY+8 z=LH5Ldk(65S<5m4KN>UZWR*3cr7OnPh*tw5jBYKPnmPOPFkz*u+FXeFCDoyIyAil@gzR0eKm# z=`n_86Y|8hW>?OnFz~zKh+thaC>#;1ruIRUw?6&VI|!^h%e!bwp(av=_PPsbyU!OZPD=V z?f%Kg6^2-HDS^aIU-UIWDVvbK*iQ+zEYr$K1E4_GC-Uh#ZA#!Xv*l9P^D)OviHx}sd+i00?&%t%{C ztEUMR$AmprhQ5`Ht;iTp25JMfy5#uiMqkD$7yCUKAN{MvP!nmFtkMr(2e1xKH8Pri zB|^`2baO_b-8%zeMokxxD%{TbmIQfzJuVgfK1@nr!HuR@kE158S`|dI-O2qm6*5^- z#L^M2*?1To6OK}?@}g9_@4CR?59jf(DW%!IC!iD z5{Y!?P+OVQiDY|qE;O#ox)VPrmGhzURMvau0xf2V_T{wGs@p7o6?p&{?5A`+tHa_T zE;+CvGoX`#^>YhfKt~#9E_vNavv^>N5mk?FqU_FB^@#wUk;y|#;d;Kk)noI!gK|<5 z7|Z>-?0lCTmRIXvZaKWZn0Hm@F4{>_zf5e0q~7N_Cv-c2+Vv>}SoR&iKncDW0G1fj z&kO9TX?|O?#i_YRp%x@C!@@7=W0#9Wdt835_1pijJJ=juyBr^9DT6fTh^pfu`XzNZS5`{%`9X^lfTw z+6haV4B5HG=2F_Yd#NB_B;?xv1isNAQjhJ9*aNZ83DZCn!Yq4$tb9>DqCz400wh;{n&9w~ z&0OOA|MLWg0{|=Cyp4qb{y)JPg&1o7^(2M+ZyDnxCDi3id{vfQ1H|>iUmeA*Gb#_d zbW-Zfo=Utcd7;elSqn*Wik`#DaV3#p!NdN==`e$|PEB3&?unSpbga8AVhm73LErrU zzljb|o>_g*+uNIT+AzwQ9ZU$l-p$Z+VlWWApX*H^el{s1iZF~@(?1Sou;*u#EpsvO zr9GeZOc??MZUL3d!n>l+c|=G{;aeP zns7!o>H!MK_y=(rjrIhSwSWUcTjTT9@0L761Oa@sf{l;QGFSfGQd@gD5H_y#Nvli; zRHtI*j>QE*xBteUBe5Bt*+U{NMG2mi@fcQuHB}26nmo_flCjFqx?1175RQ3Kb|-%% zO(K@n75lI_hSjB;(r6`g$e~f?g4Jt+laOB9+l!X_Zw(^CO?r$m4bf{cJ8Ymf4|?Xo zj;o#5ID}^D=vwqPsJE2efOPilXECeZ4{yy;rPuR!OBZ0pf!IWqA5zvRT}{JhNYv+tt-;>lu0gL2EozFIivVbV{@poXzOnjzp4vrpdZ##_#U zs-)Is@vm3!HR)H2zb&g59ljMNROD7-_NZET^ImAvJXUA2{zW#yhVLZ zsB7LKMLFwqJChCC`4CL>XRtV|N)6Z{E{=@@<6gcV9@b&+%LmxArMp*N0ba9TTIH)m zdUGU=io}rs7sfw`_smRrj)j6K$^IgCQr_#HopM(t=QrfKG@TfucTD;ge;cZhJlBU< z#)1JVEN#qP0Sc$VX}KyUxIt*45uc`L%xnmU?-_cskyRCD~Wh zXx(?3q}7Xk z{5Da$$9HUscSeX1-}z60NTQ=;x=++R+1}osY8s@-JTEnwj2n!sh|sJr|F|dxrsaX* zDYyne!;q0d_4;(-UWB44>{eysidhII$dw05j|OzhPZN~j=L%ZJ+s>0*(dm|%UAiAO ziv+f@ML1iK`&I(#NV4vlFbT5975DsA*Z(Uv@~!D%LIWeGgYC0u!ZXW%1V^UJquG7h z%ho{`F()8l46UVQ+Vh9wQXW|aNe9pm(un9S4UDO3AY_$$(a+71I{vR?$4UKrhI*?;B) zX%#&!4@MR2<+JOSa)-Yz3I^cxgMLO%(6C^bW|(bQ9L&@B^>Y<^>NFFc_+$_#*9_&e z3*7^m-qEuVwl;WKp;J(YMiEOXi(o*$z0mT4t*|*O&Azv=!>x(x9-8B|TFmj4C$50VCn_cFZO>gqy;T0C^$0RoGb6Waor(7%guKC&DU6wzq%LDqC{7b@%_q)>fII( zcG-*#7Ts?UabPt(vl%L8>4(* zwj7WK6vb>;s;4Yt`Ff;;J~deQC=xj-O30k(y7a9}cBD_!w)EcFZoWb_ zxOj)UQH8~Sy4Y}8=lQQjvxW&v&*0!+2N*dg-O~hpwcE-H)Ctn!M>dMm)t1w$k1zhj z85(XTFUz$7ZLLgCK8!C#tETukDvrI&yf01v9pJUvP2hh{tTulh5-cnJHB5 zZrVZFmru}xGi(Opv$)8

ji5moMJWVXMv95Qj)NP`=c6cY3|n*Sf!W#k4;BJY1U% zlzlMqU?%rCK+F=+qlMJSt7L)*02Gn9V}l*CNHprVYF+jNg|Q@{)>*FpNbU*%B7UzzS3q#3R$eC;!3 zKJ>mzDs)mq%=vTWoxLiKh&dbq2p-Z=}3YsNMQ!kK2Jce(9(P5%>c&kmPT;Ga(K8Pn5b76Wwh! za*Y4}!p=15z||fuO9DM}WAis1B;p+oA}r1w-(#&r%(r<*sxrseHQ9)e51dZ&(_rQH zc6aaE1v4GC#-ZsK=rQYhI6<$-0GXfgzGwh7m@B5Wh7xsahQAgqi$5km^Zt5};70<+ z&{m|c&Sd|ulLnSL1+A>CwsYhuGRo%XgP9Ym6{s|pUhTclxdJ_Az}ivGw?6*?{{pSs#-KVv`aV=(y$DXi)ewDhK8yRQzb;{MP(A2n=)0V$^8hqZIlqs)H>Zd(|B= zwVcLIV#7oIgMVIpi3~ZdvUOKIGU(KW=@X-1G=ZI@A{gJGx35xteuR74?!`J6IR`H| zf;c$+H_*}BWm|{>xq{e@J<+>|BnK`n^JHGR#!M+9?Fvs4@4tJtgZ{bxjq;;ccAI2V z`)8uR4YC=2t%}Q%QWmn0+jEYf&)mYwcfE#hor+tl4UIBw4Bx`p_w*JtM_bK;X&J@Y zRhu7+mC;)DtiMhgcz#Y^MrJwx)t$h{^g(rC3T8bm`wYFn@W@*j)M|-wYmi`w$jkffZij{G)`QVa%LbJpAfRqB;f!zI z9PzXtteC8WfjRT;d%GAz-w_<*1Ok=2*iS!@Yu9QJF>CN8Sgo%>y44t}w|d@X(UcR` z8;la~ytH;PoN%%mb4)4VF^?q26-!dYT_f0IxFPj8nny3+x#UhWs(tgje*BI_*AKfg z`bcc%eHfeE1lDg0uxDWaa@V!g$WH*~y2g&;ISK?PaV!5pALUEDnhiz2UX#iZO7&%< zkfss`IA%~rFMp@+Ri=TH^>kYt zy^!9BEg13?hId(YW2CD_Z!E+-dIrv0wPBAN?V`uks+WVf(o&;w}_holJ|kzWZ(6QD@Hc_Nc4Y*|_}kbB~nc?H*{JKkH& zY3A#Jv9ZXrWGj~d+D>^Iu;fqxy9S4a^7QNlOd3olZNiz)jVbLTV%=f-g414FlGC1P zshkIqZ0g_Mu=k0=_Zc9O%U`|->YWAc!9scy6tQz&#P!&+{fhZT8u@Z(v>U;+#b-aM zWWr(1s5wc zy-n@hrewN{j29Bjqn7OKn0E8KZCPoY&$EUcnzo96BUrFYm>MbxULuxq{1|%RqOfT^ z{*WnMGliC3K6!;-#Z5}Dvx;ER2oh9){>_n27f=J6S#pMqec$Bpbt?1IEELVKebO{% z^c=NX=HIe{81OFNpc=1!S@kpF-r<4RW~;N(H(?hlUR(m@-Hq|-m#^Zo=GG2`1}5tr z97I1}8!*tC-+g=Eu!R2DZ9@`^&U1@PQO7r$>W@oSt$%%`m`8kgmtoOe8_ zEnQt^AOY4$CU}pxJmwzcIi`<99^6tIf3Z_n3D(uR<~+FMI%cs5|7h^bt}51Og~v^8 zCKgsQ_eu`-ac3nF)2`e+Ou6}v6;^H6(|%bRahqba@Vz+j&s@-Y610ttz&ngb*!;u& znDqrN9lrhrqbs*cG#q!1P>pU?q^+)&<*ziX;S*nFS;s#{Q&orD7h)#vGhm8X1Hv8A2SV7S(pHjYx!Dxo?$YxL=&RtjGfI& zl2(zFYN2x@DQ6Dd>nNZ6IsC@qHSPOHKbh7Ls7J2gg@lAg=E=4`RgHFWoqqIMj#MD` z^CG`=dGh6Z$9eXPGu9pMuI|{|5ye z6`$L_?y6jS=6x!F+jwhpQ&C~^W0Vkf|HqsAs*cX5r6iB%AjJ&Zf?(HmSG0sqiQ@Uo z(#g$~wfY<5A2uCu5C7WmRaW%GExp=ZZtmJbC3R+cw~uyre%f(xWw@OBiWz0(!DEhL zL6`M5W0xcKuPTEj;h-7*vgX6vaO1RG<#$=JI!eM10*{6EFbXK7BO9Q%O+3wMRzKc5 zAqjrwCN5BTl$dv&`v@1F`9ExZ2T)U6v^InQp$MUbA}xY~bP&bRLldO;uJj^`fK;WK z01`loB2DQcMUmcnM>>eoYY^#8djC)K-uvFY@1Hqjk{QS3?6dbO-}kMx!WW{@L_3V# z=k+Fp9i)>y!?ko%MeOA?gr9?8-^F>x^C36s@D*V0S6yx3Z5>NX4$23z`JGD|R2$*- z%*onzGw_T`U}zbj`ySx*bR z!<1WU{GkdGoq%0jS69^K#HPh3G`H)BZG$2&;~Arf-Y(0`x? zS}3j&^>xplWtI~v0ve3Cxw$o+M^C=~k)Xhg@*!LV9b8tRhEzi}g*b?{6=@ADA~4|; zi&VjzS4uGlLwmEdC{u+oT^GHfA`mLXc=>%J$F!#Fw8e$@heix3Q$Ayo#19*)fu#W4 zL;3fm@%;SineuU6kBgFn?3ME7{#r*lJ!Hm3=%3Lv*MW&{mv>k2yq+11|*a6U6BAq{4P29 zQm!?%L zi_o>y6KbPQrE^hVh1a5dSyQOSHr6ULLx$7Hb;(!l4ji`>pGS&s&^S-m3KO+bnQj@| zTE37Xm@fh*BDMQTr&1OqZN5pckCwG&Cc?fvJCv#$zK!2U)<+pBk%5vsg=&0-6ZO?N_#1SpQ0yb{O!OaeK`C- zL*p9{sMGqDuT2r>!&)C)hwx%}zncF%z@7QuM?D8Ha}M7)KAlkmqjOLM(6pfzJX80) zQ4OcDN6*@`bZN>HdM1v3WF%`;m>vh+0R`r;8y`3cj;cND`q{PVBvHnqw@D8AYOvra z*@$u~R9s3BaZrC71vKs(17=3Zn}pOglLpboM#5@=N$4bji{!LQUMPfj&oQgiGuq*^ zs-|B=@?*3$G>WjwH__A9Ha1s*A&$O40VuTsC`mAhU=pBYwtSYir!@jifq(Z-7jzM6qEmQaj4No4M`%RK?=M%!X4u2M-mFMeBt`MfW3clQ+1^d^Rovxm_w@df<6@Ip* zKdj|5#!^u8XAcd3?MvQ0Y=vDRRMsg!)v@9Yc=PB?-75G)X>wQjm{`LI+xN4Z_eFrE z8x~RQ{_ojCI?(`2r)H1{n8XZ{X+c4t;N-R|Bj=6i8?ULk3b(|%X`GkW*2s%$-4^?T z5BO-36(0I*ei#2MusM{(kI?W-iSXyZoz+X4@GPUH)zy-Bx1C?~4esy9@jn(AQ@G*i zw4m!*<^Ek`?7?d1u8C<^wi%oJn2M-VZm9#uhl+jirw`^u9VZg`S64U6m~K0d0!iyj z(XS-B4}ifX*c;DP7n4+!k}1wCNlUn}&%D`)F_a|&ev39FLJx^h;1YA7!dMO(vV%v} z_Txt;Ac7B>rP!p>g_g=*m8~}fcAzHoTh+6@mHa|FgtD}<<-x(hvsYWT=Mh#cs$p~>ue=az+5*iuE`BnsOsgO> z7taWPtaZ2W@Galsk@RxTfBVY;Z}3uwFey%1iEv;$W~JlEmIk{cFjs=VBYii zY-X!=hsVu`^7h0&TJUI6+2|W`YpF<-hq~yQP8n0i%Ukv)^Gw4Yt*dvE?mSTSA&oW@ z_p&+|^5%cy)b!TcW%=s|mq~;tcaGg6q^Y1 znHHrGN)`g7;#kk9xSZktEIu3*p$XrwNK8Y@ob0WRq|4k1i0~KnD@`E1TF>5$glk?= zX-N|-?I^y#Tn8)syyw|xt1Dh_Nb`$SJqyp@32eP_l4ZN4^mQJEJ+{8 zklJp##NH!xRuwgQX5YZ2>1SHtBv$5775S*}Qv=Y22T)5%ltzqo^7N`d$9Ey>WYmh_ zmV{F)(wM)O4@vIwGA3TNO6DoM3n%h~47)go#mYXlYXGeB9x;kl0S0zOq%fNk%_Wkw zG@hpsyS$KGCl-K_f1zoVRd#)26{dnttx3%nCXpvVZ+y3Z}=xLKM2=YXa82zhuxE_c84OM5yu0nw7X{z)`n(^GO3RRzb8(+EzsLf$0Lj>Ght82&~h| zm7PWb+k6xItZozC5T-YG^on#$%0s^<)ab22c(R7(%iow3uJ6X(TWPStbIF(y<#~wv44FwFAgzo_tIbCtUH$VGf&?>}0T%bD4ZdxJHWkV9 z$+{3XjePl{oCD!LBo7JfN)(yof_B5Ht%=AtXir~$L0dYVr#-~47MyULFmZ?8v(BH7G_&NrN82aKMRE0ohf)3q?|mnI@^ca^U?QXI?2Ps$DVvV9g@FePHo{7IJ_WUT(YbVoJ(dFY{_kMO+kW66zpc;ENeJxdO%Ti>$NRe#9 zdw;@NwsQMqvmwO2wQ}gIS9ZUKjP~Er$_fgIR`y)pe7l1?ColSB#K+!Av zdTcn|`O(9sUsv`zPHe{Syq<&SC8(&6dahpxek>_3Yk6g01p6gfrc%WT-90cdhk9YEsF6zBYZ&0bL=qljEf0X25Gx7Pr z%vpU(^L=ILL$RzaOy5U>wUn;!UZ!6(ERr4%{T;h&b%Sr}=yxkAInm(U z5e+Aj>jnNQ(2oi1N=OhZ!NTkH*=VA$s98dDs>s1vMR475t~$9Qd^q_R{)T&eS@uMo zr;$$Ss8a4W+%kAhE~VH0=))nx6Z5m_NlqPMJhm#^{u3>zL#DQW5s{M|+x z7)7xLAl{Z1FPmIoRL_yjJP#`?Y-2Mik-=SjokW$Z`MN=$H1UAESLbD= z1fdl!3hV15!oS3RnFmBp)KO*lYI+{PKtyler0pXn8e(*?A4u8Bd>eTcFp`m)krOY7 z6G(@i(vv4-6LTATra6p>u)bMwm-s$(U$Y9){BZc;xFVguga?)4SlEO>(&(?1jF;GF zR>AsSpIk1PS@NtGaPxjXI_MIUm>Pc^Pb@gn21IIs%!23#kQ5gdS)}YW8NsIdM8=Em zx#mzKF++s?p`V)h9&jh{%uo=|292JAsM*1(dN?|=a%v^@$Px8l94?6uKt3SDcTcv5 zG-Vk5xcvnle|}mWRePy=>mtOzC5cmAAVmPme2H) zc%MvbZgxF=t8y{c%ZnZbErv%xB-c0i%T0GIS#6 zuN{Zvrvb2yxTwhS->#NR?RlRX^CVU(@O4hx@}y8@XU`nvCz0~nvLE@dhx^irMXW)v zp9G0>sbsus?+cr!cszq(OsNpwI5Q*R_>{8cZ0z4-$lr344qZ-@PLn zPJ{45_2Ef#hwVsJ_serB3gYx&m>!s}QrE@oVcXnK_`%Tk5Bd}LC(4`c25;;v!1KP8 zXYa|kSILog!@uF3|M7uv5VSED9foAd4g&yhBJH*xhnTV~8i}E}(GQWuQ){~CF*J$nT*ee?awzEa742JXmimdW&-?N#4SKV}u>B7i>Ur17D^n^u%N7b%z+1b7 zt^*6Vs*(PlKF7g-Z3MknfXUSlDp1G8{m9SM$N^-eJncOBfNX1s#y5T1l8#f zJ@}a3u!J&WD)%~p_1*BQ(7MfW4W8)N*&yz$FawqNyxA(oyM#I}dp`Booa_AR(&ybz z_SY@WI{0kMyI)#`@;L6T<@nb?m0OLM02w#&W37dQn`GF=(MaE>gk${Mph;q=R&;;t z2{}l>u5(tcY4h#{(gFZ&&RLX+sEN_clF$eii*@J3L`h-koggBWYTETlLzz`xQb}*m!e)5+^I_ zOMX7sTV7ZzzC!d z1$tPd&+3Gp#(h5V@y`mpqZA>hgpt+$`gB0p%5QxvAO3dMo=AmCU#R5mF2|#grcy+j zC%7g<|0W#ey|LzzV$tZ|K;56aYy6QgbAC&y5j{yzENbJ&a&#R9)vqLq#oC~@9Z25nboGINW(ThLvCYl z4LTg?M)C*9=YU7AZ~I~;n~PpFC;`pOYPjVPAueLFZ(3$Jz~UH>!Xpq#T z5_H)mrEP~IMQ`-UspA>5L?W-T>3^Wn952vr)RIh{|JnHcI^PHL*6#&o1xJm&Vk-x& z_XD$YYA520-BL2BUtJu~-DLbM?V9$TpTF8vcX$}PQO`v%7spCm8kh@P#roGsDg z369%<8Mf|lQ#{^b;aSxJrmiv5v{FxU03uhX)*)Xl#&17Geto>5+y_T2%R(E;$;rX^ zglJwcjM;eu#=MC*yhoW4rqaA^_U)|nbyr106tfs5RN+e}c7k!`zt|5jmiqhvDCCeM zh3dGne{}E&8QaP3PC4eVKIqHL>n4OMUHLewn&45q5g;)yufxifFm-)GrQYG(+$A5* zPh#b51)?@s`;eXb2c&ci25dsvldIn-exn}RAaW~Vh`OysjI0LjhPIwIcOI^@osNjb zeE&hhc6hK%M%d~|0aLEDky4&}90T)*kC;YTl7Ydj7?w7%T6+strJysFwS1=#qd=|xya-m z{Ne|A6s}3#s?=sk`sD+)R&cMsOfbjDtys4g>|Ei`8pOZ(|AjaJkt6Ox&9ftAl1V6c zTUJuVgluG|rciCa1vs~Cv)!2gx_bD>H0QewN#{o|$&M;2 zZm(mxOF|aA_S0l+?R^CZGDt5rM@d)rZNi5~4EEQLPu$0br;4n`b;UILdyG;w1roLm zu^_d`R})J`ETo@}ekTgE(Eyr&xQg&o$9;VJ3Xj0h^?4NjVBG=`Sj*aK)ZZaxffLi^QS{Ob3*&&iL~ac6jeyueL0MPFnSL!D0SnB!9s|deKh#1wrM)cLPPK8(tO4 zE$07TYvgAfUo#wu8UJm~aofZN4stKPDZKtX^?H0ixUx$}o}dovGyk97hah5OcP^=67j>w`WBTp@8=bfHvlsZCM~@*s~D#TRk~)w6wZ0 zt?Mfc|HS)$hhb$TtGx9y2m`jaK- z;}#@%LO7tow3%j2iR{BiM@K>o5y{s<^kBNoA`3C15=IBRMn*5v$QFQmhZ?{?&Pw%> zGk@}~r5F(hoTaqpb2n8Dy41z@Gyl1To1*y4ycrhwmWsod*nLc5qR-!p!~=|sb@|89 zK>AC>6RlMl{r5zkne-a`D(B5Zo@%_)2etu)2K+Ad`zPx{O`){N6Bx54Pe4Z|wb}E~ zO{$i8R&C>iLIW`>m6&v%O(F7Gu5+kSJ=nCaygzN=B$gbmZj> zGMPk3#4)mS^#uvsE znF-K~gWW+!29y`XGF$Fnv_20tH7A4Sz{^ySc0E$w3<<(VRBCXmbecOM;cv(wyvo2t zHE?8LD?hOek;yM_5_o=eOxyO2;qm{lVIMW|lHmC>JVY2dNq!U?} zNeK4*LvY(keIU?C8jY=>HYw zjh5>PGGZ%|`kIct^9dmJX9Ehrvj4N9E3c5gjY?W58W6#eI|bBGtMH?|8cH5i@^zWK z)p%vEvVm*L4u}A?8g~I@ZBsJZovnv?ZpUaj^NK}!;H@8hv^k@>gUO&*glIA_j4zuV zRHg=>=J;Ww-K})@cOv`81^s>n%zjaTrcBDgSos^W%Q+BU4be-=wl!YNytOQ>JhOhn z4KyJZ773oXsDwEQ&s9@_3X`q;{p9p$$Ax7bW&qE`6zLB4og^kE!X2!Bkp9@U?? zzCJ?J^+06HBIOC=P(9R%Nl7;!fjZjT(c{T@#L0X?)P?H+nqPp>A@>6`7dlOwP@Pta zvCy?3QFf3L5>7-3fx}5NpqR8LPSIYpO;jRch25D?KD#)%oVCIUOPZjpMXU<<%{cVp zxNcD$sfD-+yxk{9)EzckA$2qs~jGgA{P@5dHT z3T8zZ!1K~B6qrKQx9$TV(d;Z3a|NoJMm^8rkJ{mjyk*YArz&afd?ibXFVN?XSpk;T zhkJR^?kc<^%uaG;-2ShSzyS^-SGZvmS_yPOu<`1L8VEUr#>kZxO`Lt0_LX~%Z;hrW zr_)qZ1BZ~_XT-B}NigOoXV7K5dgms-n~pC$gMpcuJg}8qPS=$xo#2HD@KY|MkmRgi zIy0yuv-bbj&I0c5Z8)Bvzg;qb>iC%PJRARdzxRp0N1lteVr2Dv5-I^LYsRy#2Ut%8 z0@YR7*4T)|EW1wO=$|Tn=!Jz;>jh?~=q~~&94P|DS)Rz^eeJ(3PXdzGAo>|dSdou> z?O=bOhzhSeXAKHR$bPVfwNXR3fFrmpT}a-Vi%vY^Qz8!QBKJvXe#;yV;l=qAyP0{j zbd9*a;yav;M-hd}8gvo9Z_1qi#5aGv0z^ZG@|AkKN#=s@7b8C(!}P!DkNU4;gu_RN z+a)fKb5J3qL9P5y1^A1!*M0O#<1KF(oNc9Q<8!b=w0p^St^y8$gH?b1@A%^;6>8M7 zu_)tfV#e1Zx#qBd6eyTWD^HN0pOGEt?malWD{Df~3L6Epmo`3&83Ve;&MCX@t>`oT z(qqf{j)P0z#sXRl38NL8vzU_UTf`{uzV6NpvB--3e_P3wS9oW1%-4!`C?7-XX&B_R zKAD)!zRGesUlFvN6%{vcuQ$-2$c_j{vQT4Ob-+}D=Jn)0&|nqwntYx=Bn9yJJb{EP zUF4rfnwC!jPs2%*G)RFKEV7Bc6mx}*{k1n*YK_SZ-a@V_@5%Zr{^Dd$L6$`pqIbCw zdH_ooYzwi1Cp5-_=t=Lpe!w)7g84A~Jc@k1T?QxoAShhu3Kv;2*}oPY4k}Z5?(e@= z0_9LP(<-{h_%q?2ZxHUC^-w+ z54yn;iXvqC(qtwLP!uU>JB5QQob>uL-hcB|T0oaM-la|5WDVU?`BOIX(!v+l?wjX^^w9 zj-N`cUsIO5OgS7XPgq5JcUxFY>;d2w0ZPyg=qV=q2!%xVQBAs}BNNd2v(aR{8S;ui zv-LSrkP=RH6-YBH9$E4k>aShdmuvQJXJZ;^mJBANotla61I>Xw*T-+wJXug-$Xh63_%a(y5i71$=1-UF zw%(MRWxD_4iE;j5b_p_2pp@AQrd626Fc^?+n9R-RVSv_@RuTp>Wq$W#-^WG?2I|$!f3u;|&p> zAPiAL84C-ei*1@N!2A=j9q~!8iI4>{&bjW32EKCtN@bz7oXKX;=t3)@YRbs>!EFa{ zy#pJg`+zEUpk2_3tIyZ|g5)JU4vCb$$*Bjf@XFcdoCZ*9O5m-Ru)6pq?>=Da+^#+|B>m)VFjCnpZvcT z0x(~Gc$}_KVmQBpD@{chO9$y!SG`Yb2!mOZB95&u<#zH+tF{?xWt9(V*tc$hb`L@c z0im3$?4&TI4(2_3dm6Q>*4ixmTdA4|E)PkJEZ_f4FanFbk^rzct<>&dpix4g1NtDd z8kzRI5Pg%LTuleUER^$Qkx$beZA^){0q2{Q>el0M<_gRyeaEspVu-J9Pf-uSW*v!nu_XOp#@x1jgWE~XVPH&B$ zNhIx%d&;_r3-YC}0U3L?#~6+eASSKEqZ;nV%ra?;G6 zyXk4rVRBu5$ePjF=fH2s+n_4ZKIkOAj{!a3LI1)s5G0^hCa6A?9!^yFHuI4suhWjH z-D=8<_gXxroXIyXHWf%Y8Lve}<@t!eKI(nL|M&yC@%_ZaiyZdy9fiy9BQVH7Y9wt@ z>JGT5^NduO#L>MP?g^}nf99@n2@ZxI>&IJf_zN!hb{(H}Hx~kdlGpm5i6bP15ST)| zZKN6@wKNxTv+@~0Oc)nY`{eZwx1M%n!B1Syxd>;{s{`7JLbya;R+v@ z+Hg$#7uvym4Ig`@6_R1yW*}_4dD~>I$7D?Lk{#2!t;G5q%KfL!8yJR1)J(6a(n+)~ zrD!bT%^)Y17Q^H4iO4T)C2m%)}J+-AL{Yrp#l8qa`h2X=&E+NWiUWsIALN z>)7SS{35VyTj-8&sV`zK8O5E9l@L7q$oDSAv#iZ$`Wke5ZfoCl{=Mf&L9GZ34cy4$ zhSF-T=R}WlO%CAo$WA}Um#4mO1Y`_eYAH-y3ND; zBO@y1wK}_dboaEhOSfI81uGx6{>3>@^uD{j-V{hI`|>#w#fVkX2H?gG zaSeC$673bb^gvqJlIy!?Fd+ZZ1Z|td#VGo*%9NS>%fM^A#$zXB<_l$k3VLsDhgMZl z0!P>)%HB^WZ1LyPRwwU08&VJ3HrG&I%=fG34M)AjXPYO*XQKA!(|OlM=*C5bgrH`( zFt*SZEnNN}iH{|MaA3%=MxA?_N!xDCq#HDREycbeo9&}5bEfIeVaR!^0rTv3i7X&y z|KkyJR6&`Yvvbnb;*tU9lRy~^wmHQ0!gtD^_syeOt9Aj3(y?A9F(w9!cExTb%in+P z!9>fm=h6K>^%@E=4DWDZ>kO5Fng(57iS9{O>RYHW?!Nr>S`8p-CuV(I*=PgD@Fw^* z&+;U*iOc7y0ymph1!-NquR+)AFuX!W%lJ>A-GTUEmmK~W>($_+Y`Tfh9sV>5s~s(Z}E{h7WzJ=C{{vx?eQES zvUPC>Vyxawl$s*?+zo22OaYX=@R0oZpi$Qy@fB z{>zJ;^gY@(Edk%$uET(ibu>Z0A1=gW#BIsDe6#<=+y4r}dv7HcXd`hG!;_WOZf0hY zAJU`9ul7FGbxq8F9~sZ~aJqLINs7`^f)sTNbBb zi+Ja9C*KxOpB+5nEG9F?mQS#6@9QfG)D2C;KahYzyB^v!u*_bTe~GFLL^l#Jso6Pg zg)tFs&;r$Yo@d8GTffzb_K$Q9V10n~{^!zS0(*PfXAmtbCLYQrMV5Y0o#5TKE27nT zZlhy6!NWPc-UrK;?1|p%g;zl+F!vwl=Nw)Og`|3P<|M^Gob z*Ty7CUwUbTbTF>kW{_(3?MDEyt$(&~Rj~YyZ%P73_lmfr__>MhJT8>nj?CTveY7Hz z0B{kP;YQMz&z-=CB6)|H24t=AUJ#2U5i`){^Yzr)5BmiKT;x|~{5p6x!wg0=APki~ zwt-sInnJ80{d^ChcH4(0x*DI&H)o3hp5qa#*?HNwt=F?f1lSQa1=Fv7O>J!C)ktOD z%ZqkH$-O(93COEXupXMw`X%|^tw|UyO686$MTTJ0n%RPA%s3Fvrw0KSUO+sOV=?er zRz+N(h^FKK(xGvwj~2o^DxG{8Obg+L>REJmz_~_rADPlxuH8%Zr^8`$kX9cGEb+#b zH7r9RE`lxUkXM8Sr>yv9wYS;j!tpOpx{gE%a2ExCZhc(+pf&1@yXISBv4&NB zWc#(ty{pknDrXBotjokqV^73h@nn9tzd!3eI5B}m1(m{nRTjT-^0OWyrf_}9aA|Qh zI-HRKZj&WS@XDMA!|CD?3d)@EKk4-c=6l2MU@s&2iVoh6Is3UX+WF#OtL;GmYVfjm zwg~Usq~O^db!IwN1FX&wWUJ!9O@r=qz1_pn(^C|}3vqm6{?q@(^_PrJr|OITehge> z8>qk4Lw}!*@7I6`L&Xd~L<37(*`t#Hz16TF;Hmo5RPasSkH<8hj*62dl8p=nY>jV! zf8;tpKo`|r>TPyyelsv8STICHaqwa1%+|^a`k$W)Z7)cy7trfC`de)Lu8!WQj*|rZH_^HGLK;J}s4{I-(DXg2?beR>4%{xX^ zwj67HD0wVZsOZ>x&;_6R!|D=kL-k9`V(;}tmxV-$*Tzh3Q0|X*u}LxYwWXxc&D;rD zq*gyVGI6g6q}xeeJUGb@}jZAqemauLDlELx6#X0VOyWoJz_5F^%QT^^ddm z<(;#f_%CX_Hi=M#se>t%r-L+umjP)0Z78xfUMP_8;QEH!q}SnzdRq~CvU_ILrpZrw zdgg6t!9R&5E>A;(9be%spD@_exz68VFtcr@;a20~YOiA}{K+lxD}}XnZO>}#MYXEu zocq`_-+aAnGQROC!kckw07&h(P|AQqG>Cj+r%UPjY0Gk{AOo9R8yadzz>Rgk0WliX}%xher*~)$(B&?b#zyruU-Bf(=EYufo|-RqKX03 zJc>U{!lLe(#e{0^b^s?K1bexawo<>=??g07Fk2&5YC&;$WAeeyF53_Mo}(%+@{eIr zn2GVP0@yD{Pwy2^)c5X1yp}MaZ5ET3Jmn<6ISpu#Mkj{GMtMP2Y)daKQlk{5*{OJP z)hme@)FgYJv(KQYMu@^(#SzsSmoKUZSi>6c(#+PQEqKGeKnis#i50oRuje81Vh95^ z=N~0>orR~C@K4R~bS~BXJK15w$GQls!#C%HxU4AE7)Ty_KKvx`V)RM6f>jA?_865x zLUP|*GTt8XC(`hf(86Y4V|pX+dmdDPz+Pte)HehZFI>yPp zQmS5R_^o2vQ<8y^tS7x4yUAwrvCX9Uer6xu7iK(t@StCDb`@ZM55+n7ui)I2x+a{$ zbIYYIjg;UEIVaojxI}))E@_VKJi+~;z{fZ6lH^rYRnv!n`EnbNsfJQitcP@4OGg7v zl|s(gygng(M41#|+su*_3V9Rrko?iU@qlxs>yitEA^y!i#2W>)vK**cdV+Sa*+uKay-zl=xEZ`TVJohlylc&iX>qWZUtpRbhu)DQhDvu zx4JV#kCOmx&9u5(mnSfz;o@5Rlda*0cL7|{`3mwP#Yl3y7hnme3T}kH^yc!rs1xp= z3f{c~ReL){xL90tOhN1l?Q+_qJ^0-qw8r?vQk&i4r2Xna9yau33V^< zULV&1z(vb`Tv=J!J>km}v#hEMW6yn(b=cOgW&Ncf`C}Gv&|d4JUrN(mN~q%ZOvu%9 zq$KFdP4p517!suoXGz^o1UHvR5R^)Ghb%q|&^!%F6$A>Uz%Yb z@KumGM`M{XA1f7X#F1~eZh4c#(~1#?qX+`%1-9FF*Yx+31Hfqaml=gvAk&?@?K*q- zFgd+zfoG(}C-&!6hj6LjyP2td&C+aQIL8fd0zi3)|SKop3^uO z7}+1oYj`y;CnysqXy?*+-f#dmwHnxiYtVro9jFq@@m#lSac$rj?Ghnc4d2fMyK$TQ zv?E+0<7xjo$~U2?!&>$6`)1d?MH>Px{4uUTE87=_SeDxC8%Kd%LD2f{M!pT2o@a}R zDVsYfUC*6-`;UzyH(Q-Vp?B89Am47H7^1QpShykvXH_~#Nq8NPp&wmu$pL=ovKZ9y z1@6nf5#X~{FEMZ9(dl{*Yy?u!bwtw4*s|n(`X!ss%8(PGr1YG^o0bn={AEFBc;sDC z$r=Cf_t?{Za_5r6;_>k_mjc|BY%a|dur?vL zL`Dua=WUONqV1jAbbjPkI-Neacpnb>eidq8&ho7jeZqw;sSDOqah|EabnuPgdD|YB z^h1}1n3%Tvj>mr!?SJ+Wpg|XwuyWT6f&vZMH?UPzytsPsXo}bb$Tn$xhXr5%hUAbr zFw0c8_Wn3bw@@Hu*|jVUhaBkv-Rwy7bz3#mtS~VwRnkX^hDr7~_@-VBY1kQmwDebQ z0|PIa30tQo?nwIT_aP&&VRd0UUHwNaln#8Vpn#K!8MG-O0ou2|sA#*>asNJX>gg}0 z0JxScK>POt>X?S@2@^Bi@z!{OB+uDcwAluRDM(Fj9+U?)^6WPOrQ%KLAq^x5qphSy zHPPYVFLD}mKAp>dQ<{G)6~M$vPSEUd>?<(~hH+Y{Ksghm>0;mH(&~i#T@H{=`4h%_j*Gt@Cp18x&sDih~WL&LY(>|@ck2(q#-@=tFCwM_(r6*jhsm@ z*7&lap|UN{ ztIEEx-X*6PsKqR~B}ME(CTMxN*Pqrvub=hCJM|iq2}0KURK^3M;!FVAybn}RY#jr# zbNELjb8&@>#?X~?YO@^Qh07S3otiVp)5m6_6gt!ijSGsvPXjQzP`m>L1+2AqG@B zZB2*=+<)w36qtd*GVL}gZ$c3pEZ;n^73r#1z|lAA9KG;xbzqYz1euiH!)H5fUm~`; z-g!*mH_W#5DLXnc5>{ytO?UOKr=1QkCnuyydc2#@QJnomOhf4TmzR-sps+eLNj+N| zjkZP6j2HGso^B*8!tMN_rb1dGWb44cq2Z{lbQzMqndj535jIpVk z2aGdElZ`fRsfy!1fFF9s*?2~gep$l+!;>H^-&TZe38B10$_bP+?@$>`{73A9JM*u9 z^D$~cNq?#;hx*%Luch}#M~xD`AZsuWzX~q8#c}=AJbrA(?~?dKsvG(arx_56DU`GS zBjInnO=AIlDzivJ)N#P;ibROt6MD{$gY@67mU!2<8m9CEk?DPr^TPX59i-)cD|+p` z?3iTFfjdNa%UYB5em;f@R4kl4ZLq;#(mW0CR&yMkaX%AKSX65Ml6<~*J+}GG)7rX) zj*bp6@lT2o2wi^e|Fy~fY`6h4@RAZoR+?bMa}d2UPYi6ybcYd!0ss(Tj#CX#mI&pr z>wf~oeWGGw%QSt}EkBCM76pwi#?Aq1xnzHTf7UKN!QL&|e0)Na1ZaK0O?mcPi_7kU z2kPmuf6j;kQ|eteNF3A*4gBGHYg;zl)?0aALT@m(R)J406<5nvYIa#W)GsiXbf z!g|Ir)A2S-f>`ZEZYKX$&5FMH`xF3MZy4r{o0V>12qp5!YDkOtl z;=+CsUahKP^6p>Bh))gNa}Tn;NL*OA@H7@qx#_x6Rtp$-auFYG9d)i>eH;Z$gf`g{ zZS%Yl__j&26Cb;kx!L#u*Ya2tXsXF3?OWIutQhq< z-$-D_j^KmpaB5P?hF*b3R!yGN)Z^^B@@xsd_^!kgBGdGwianbt(VPVjQ+0z!xwQ^# zIwhjkF_ujI{yua;Obr+3J}$rfwq|8r3M_sx(hTb1Oc|irS5q?mW3ZGIo;O|Mq13=! z%eii?{dvPs`2?W)d_z!PTOUWoX;cemz9jHN)Sd0hqJC!gz3j?BTWv$d7 z(BS#aR013DqdZcB?)zN+=l{MNdpmmrqnUha||v{G{D1h}e<;jPM6tWI*fOtG_{W8z5YO$k30d49Ceh5iE4? zTOXq?*#aHz){fvgaF}v<_66kPbT2g**%jA&=se^!tiK_u3C2>;-RF1a?JSGaijJx}PEjPIR$ld+hd={^$j0{_nAC*3IqHWnw5&RZcc-ZUmrY!2W<4^;8TL5^d zP^Bz)ycbd1d_Te_JZDt9mCHJJwN)<1i09@q0H1kK10%(kD%kEC&>unSXV*SF!)xQq6a-Z*)0xDyzK1 ziMzofraQ)ROvJt~=&nP><0;aDN`o&|Selo|>G*(w9ehr#U-R3-aw(<(m5buUK>+KS zk%so%Vzq2L+F87ohsY(+<(iPqM20c2Hj60%YD@_Ys>(Zhp9UfqY@I_4r`=M9`hdaS z1AUHVsuKX=1w?5;s+=NI8L)FZ>;3x{pdSd(L`Fm}PnBx7E@1O#*3gjXty{4BM@eHc zJ@s?3GuEHGL@1Wij0|bt6icT#9iB8EbI10}5Ci2pxSI6;TtJS8)GI10vyF*~*#}_c zi6QgU@zY6PsD6?l#c1!hdndXZGfp`RZ#{73IOhe|6hAJs#O4K5hz!}vFRu;{eYKBQ zF6mKyrJAs(0uH0sWO%{G?_oOVl~&)Q_yc_!)9Zws)tbZs9}?T zS#R7#_j7y0zI@TcUK-r9+3_2u_Qa(1u7D>4smR?K0F5 zqKA5!?hue~mQ0S5D0y5&u_;kGjj=vwqu?*7vSafV@9=?6})`uY+&db zGBokxQ8q>=!J-Dl0NUEWrm=9++xV0x`tW2Z?Xiaqus) z^4@ea7AzjTX%|9=y)kn7QzSoGQ0$d;;N@vK<$dq>bBV4q$!Q71tFOBOQiMxIJKLvp zQ~m8grk4PnB!s7O;oiRMFz~25Z>g!!P0sxNIb)T8&l&qftwHI^WB&O|a~B(;2lO82 zwzg2Q!1l4QdfJ5#i;Yi3?E+OUTh22A>}<8qWp!OCxZpB5?K0w)B-+}WCJi&i)S{+GW^_DR`LRXd zlGxWKs)nwpNI9OD%z)HYIoLGoSMH<;YwyzbK$ZI0m3yFo+trFY9NWd?UXLVUGM=ks z0a~xipr>pmrUJ9w@*ggK2F{?eQ_g?p@DIb-&|~Y^=2@z$3L|%4+r;Og7FMk~L`C25 zBn{(!Z3fz|bAYmD$lklL-KJ^IUzY}yiU4c%1h1)Y`J&W}d|MHjh&w~4q;_p6`&>m4QrW%DxQzx}_N6+JbkJi%)?v}%@AzuwrO zX`y*Ahx^R5LFK7)mT0%9JSKQM<*ykFX?(zcW@B4B{-P*e&&CKPbPd9siJqF8s_p~x zxHV-<64Lt$dbA%d)Yd0Yx5^E_V~!Tt?6kkS5)S((UlqIDWN{Vq0D_j- z1V6?X517JBpb+~lT(_jqQ~#=FBUS^P5T0T&&i}2jiDjXABfh-u{m4Wr0vz{1 zyRRxRyKfoRlmOvG0?@ev;)Nwk+qyWQs6@FRQEX%)gXMma(Fo#xY zF~NY#iR6XomjWY=V3#VF;lYKsL z_Wu5S{MGGz#XS?lR;aoOrZs7GaA)-Pc6XaWZ9_v6p-418n)9T~f9%DJABXGefZitI z2O+MeZy}S+CGX2tYNh>-MgxvM;{fR%xP@h=v09!mIWR6AH(_uvE_e>(+cD8o}8y$-IaBBbVjUHZ+!a0$rq zwt%q7kiX~1`-_Q_#ee0dy z^Xr(nlpGjMM)Y05*_=X-&jGje)4uJ0MZMke13`QRofj*uoxCCb@%)b{p zK{Uq$#Twngc(JN^%OLTKYkx;(W*6P7d{URSf$_ht&Q1yh^yVe}08J`jtXiVz(yY@6 z7#1r_^x_DK$W?oJ@Y-I1|Gsp|W*ULHg6b{0Zi+3eRA4d*UU)SDrxlMn{57^7hr}R3 zAi0!#f`UM)ys42=^w>u+(e0pooZ}A#_BanIH1cE^(pab$S68iEn9N4cI*$pb0~>E6 zd0kk|1hdu(7kWr`JE9{qw=CNYDLe#Y9eXq#$z z4X@BXwdKBOg=w?-gC8QiK3KfaCMqJel0&P&W7}Mj2Beige#Y#6S9u1>t(e6P{8@T7 zB!@yT$)Cqogpw<$|ECbK^8$4XJXv{`l|Q1imHk?Rd=OBA%$1?{Z{aM*Q0cvFC|+cc zcyIGC(6ln?PI2XdrKE7bhUDf_uW_X(z}9wIyc&~r>NNgEvYiwPK7z_?UII?-WB$&S z3Y8aA=$R0uvY)k!B(X!G=9)V$k(W4YX}niKWrHKf?$L74`?tPguW=Is@=HoMMzu%V z;_g0Uaqy8Mp%F)5bOc?IDY}~EH$vRGJtdAZ-yBSGZhiEVtM2lq#LM-%YYpdVwLRzU zJ6sWscM+@S{@W~$crh<_pnmYhNH2&M4v2ueQ}3b*(897H#HR2Y-lJkBd~hsXrGdS8 zE3bSJ3u2Pn!O>hQ#k2J{yc_vEF_2^Cv)JZ2?%34y1pPGEj1w zW9iOlKni~u6s#H8cde7Rh5<9QxcoEG$Eptgs^>4VY0lNyF*GMPuHZ6UfU~U-%4oQq zc2yhrkzg{8gC|)^&DyX3zricxGgJ1dl}B?qk)_>Cdnz&&wXgN+#~<}auZ2`*kx&#F zI510+;({Res~H$+yfv-bvt%)Gds3NKed8=F{nGJV$K5nZ5iW6pvlI%HK%;wnbd>a? z--<7hu8@6ta4|689;wTurPjfNr788TFY=-n`r_?hwQ8vt2+;U^#q#3tzah8%6)E(? zuvIk;VSI8oLr$CT$2uyM6~Qe5Hh zd_ao@rBbCU12QQzwnv26kFlxND;7yR3?EwFo^(Aux-Xt7vg47B8b3d8#9U&NU)Hr0 zexpFQ;bxt;)0u~~m!CZ)w;QD2eNuG~sTkgFl+KaS(R+ zH0L}L;_~U|QXmNzEwIYVY-aIohzD%e07$!8+p#1>DVeR@e*k1UxLHGBBwoe0bEmqs=?E0^8a|CBVZnb8yG@(qT>%V zPAfwu=heub4u=b^N1Z}HKXsk=2O6!&he>2bhTJ|e{!{t`6}iOS;neFZ(cBd5npG+K zh&OEs^LGsHET%>|J>xYB$0|_Ir2zuB22q3PFJPnLF2)p3=p>S}I%Pedk4QgWeg4q+ zgE0Z0=d@JdljDN>HD5ht`~d+K>6T6cdCKif&jCgAa31}c^CjHNd-rOdxtS}h-0F6m zmq;ScdY@6V7R#1pm|fpAcWmZ3gvCtqtSA79_0f%@^xS=e)ff#WPu;^b@BR=10h@SC zzNfgyUoG87oD*%R^iRzG5)R~JU)Ge%a{h`$|NH&hT~N^sdvEM1c52EzfJ(?J3rR>^ zXBW~?QwtkG_Kl@=5RuoHbqB@=7CHRit8Zd6 zK6v^$r=IP#rp}u2_Yrs5-RoCq?CEAL+&9Q1D=vi_Pa^u zz7KpJO&s4@Fn%w{$V*G3R5oA+;x@R4ui5-ZRsjd53z8M;@-XKE{~d~gjoE`rL!vW6 z_UBU(1neS7(|`)DU{k{DpH1!?0Jl0an#Z6jtiBh?n;{rc0eB>fRaD*P_XDV1b?UcP zV_p|jdydbL{TKsJ26ki%E^+7I&?1K{kd`DrM>!(l*T}%fuNQNm>j#~RZMEOmzt^k{XnE^JK0SME57&u~(l* zy@IY(DEy-Zu;?7RqvgutzYs7eRo$^q`E}5v*=}V(-;#D|drKyh>Le*ZQb)p`VcPn$ zTdxMkwrGR2lj<=}*1cS!>gv{Y*cPyt@}u5{j$@wOBVa`6uf(gp9|BB8_q$B%|ECQh zzYIL3gb>%{O^uEW0%pKk0ZHJb~R2b?`{e(8$<(w1<;G9Dy|gDH7NahX$Zq9 zU}rI}Lmmq|x>jz5;NHdQJbjcJ;_N@QAY053LpY|$oy_*{`o$F14won(;4MAEYJ2nM ztY1u1{YT_=h1Kcl>7CspITLV3IV!Zg842kE`l+|`}_N0OF00T6;siD zE>{F^cIc*5vw80(wy8(0hgvcGcv-Fo(HX@Jqr|y~_UL=lCui`!+4o)uy_?Nh> z>S+PcO|_ugC#4*BPT{%y7u9>TIAb^~1Yy)bxX?|%A~KL*rM4&vrpr20q|WMok9<%Z z0ET9KG~Wd@BM-l<@z60bywZl%)UEA#N6Xulzn z-vJrWxFIz=3ww8jAA;X&pzJ6uDG9Kwu6p60IMj^U)`wr?ljDu#{j8tQWykuC`B?_( zz4Y3(>q@RzM(IY4=|}fo<0D39!k^{UJ^OF?X0t2PXQU21J9OM_2j6!6JUvMaOf$47 zcIy{?_cj08)6Y2RdaG|8@5}0vE_kofO%o_QR|J|RS}b^oA)tf99s~}#{mxMLd*206 zhQQX8DD-{NykRSI+^}_yBKf7R!36&vr+rrVP6e{5+%Tc zbo!3*uB+s)?%&@Jt^+{iSIn~OQ~r5^|5QNqVHlq{VltN%NfjvGtenO2h$9HuQNkLC zKq3x60($19DGB8(f^loeM(cR5FNg#xk(Vxhw6evV|@ z^fQU0KELas>#;zby1tEk6!;%Eq!Eqr-JLyOF_NHH6Qa3%p~jmdAuLSRt7aH?K^+nW z$o|qkoNz6oaeETYiGs6!zbT}!)+)3U0twxPjiVbj9Ng`@Y*a-K`Dq&uwIlCq+`sm@ zCBE}vv)h92Qj39-OMeDu>`CL&Y~*B&qqSIN10VH##8GG?S(^cAu;NuVSjcF!oeuU3 zhf_!=)Dfn#Myue?wy~p*79V}`QJx8^!}uD%aJ2Yj-}?aHWw3uQLT~Qq=ye{RNaNck zM{38>ivvn`o*OF3a&C`u=*MtKHcowKQf3AWMy!Z#hUcOSBBpu#9Q0;}wP=_UR8;IRrAM*zoP^}u$!i!^du6S|Vf((PvDq){ ze67y2%Bw?$mH!2LFuW0VmY*}5TlPP%3^eVfF>^21tX%i+HT=>#{a@EB_yh`J$aUR* ziXh0&y;J=53s*gFMSei!adVhNRK2c{cEqmMQ=k;N*&yR+juSHvaR{?%H&`pp4GYAtgX> z;2Gju>UAb&!}LY$R>exsfOty(^^l)A?~+F%i)()s4^f$zs~71Hu@t*uW3s z2oHX|3%QnVYE+(5n`ZIUF-@$JW6H8bd)vIzYJMV={zbxJp(g*VqIXxCW51&6?iR3x zXvb8G-sE&iq)S~3@`*tJnZ9YipOM{dJsiJr889PZG?4lx*YEBPMawt1n3R+X36g_@ zPXY;Ed5Q;Nf!uuw26jGwuBr+se_?N$JAdH&Ic@1{aO_4e%F)2y81w^ZLDmE8{uj-% z;|64)*tj4hW$cGe9~sy;d~B#J1arAP80!vadqT9JEP-2(8w~23y=!(~xLOC-I?C`n z{;2(?eVAea9A0I}tY2^P3(aNGJ2Gw1e!7$;Auk<*fsj@}mFib)wj$tQFeVI&9R{ys z4jO!^Of@ur;^TDng&+t7^w)PsUxUNmdwY4!0!3f~m{PvN>-^*~vvD;mm{wci?%jBt zL}1Vn!q9ru$-%iZpDHXdp`XAF&vS!4cDW2Z`^5C{a=yX-(BVsF?5s`}-^hGc_>AYH z@2LBn_i78n$r)pt2RMYB99CG1qN7$`U!%s8R_P(jU-1q=e^~!8doN%*Zb$MF09W2D z(4)WQ#`^hb7HMXotM9X1lokY1Q=nz6Jp#iPMPd|z5jrr6gt^GfJLn1(G7!#8buabD z(pgiD?$RRq932L1V0+eW6uDB?ZvFk~)X>rDKB$;3kL;ICHyggk`HT~L$%jA$O!+@2 zBf|0=IG4o}AJ2cEi{>R*(A>k-RY+Zs^#@h}#9>&zh=ztnSv3$|Z8k@;wGLr391iU- zI?_Pux^B%1U1@7D>(R^jiTk%PTtJiwt^5QR^ZIKNZY#^rd5IjqbKGoIyYuj!N>hQl z55?yBn%s1%Eyy~nVbyqXcqg!x&+Bmf>|Jf@ne$ko4h0~6e&N?*w)gOJJazGgsHRT} zl5)hYOLS%jJ9(Ju>-OgcU_r$K03qqzFC`CPXM>FrflEuo7^|AQlFS^VI5TQ@Ny&QU=3xVO% zh2_q?R*$|6Y2FWYy*qr@#a?>Q#dTTmiPpS{x`Q+cvwNqP;YZ;;bsA$n6bo)qKL z3B-F-5cP3hq93d)Ixt^OQ!P+czO5Vbi9eVJ_~6@};e^vmOL<5}wN^bc&`=2Q+J?r* zeKcUzxFDhnFh~{^^cjiOk`(qWC`dLUyXJj}Jlo^RTNNxAb*XG{G;mDWqnbg6W65C^ zQ!f|iouN7&lrsD{+T5wy3{mjn4!JT+2a*rU z!yDs_h=?GoSph~{qO633gc2P-9Vs(&i-qB&otX8LFw0jj;uH~_!KTzUO^?hEcbA;E z>Ubp+c>%9C;kG2d>~-MO-D|t#GZ}rySL=F>G=xV=v0;MyY$S>@x2BE!rA3sXP!5_> z7UlJ|J9_L))i;-}wkghN;eEpb@gcpkYKNR~u%YXZ)qaYedjp*Ybz++zrr_}I=ts}1 zdOJ~JOq$osYg9z)f+bS$n0L;gAn<*{^-(IB6(kZFDRBEp!!3U=Fhk8f|f z?iB~A>Ts^Ky_MifD{msRwnF7T?v$k@DWt|ia%}o-82lOw2A4%Kn!MsxjZm5m%Y6v0 zYIpQ?r)9lzs%^T35K0uwj5)(GF?A(D#l41uNW!K!4Q(%#^6PcuArYiLQRN|msu@BV zP1SCxe>htx_9Hw@h1$}bMosm9eK`zX$P%=jL8Qf8paUP502ppLtulj9OQ6q3TOnCBPOJyk-;Lk&Q-9d`843Ek+ep6uL8dG0@(~a3==X0 zpTQ6s@<4#YAimEyymH z+k=k6gm}kiS~=W``%Y5GY0_#-MI{XNA+(l-#Bcg;vW4~ZWGJuv$EE;Fx*-ZW5*($@ zNT6mVXw28CCPJ^SuHxn44fyOI9I!Df1O^6w-ST#8gda!`5z$A(OCWm zZ|s1Yy`iS2rasnRrqDeR_S}Wf({rCYS2``)HjhZL=I(KJ-%ZyM<37a$a*#G~4ZTUM^xs`xo=x22ZH?v$hv{0nx27v_C355ii5BaKx z3)n<*E#WwB4}JCGGolRh9{_OyjtJ^V???#xP^BIdo=ljbbQkp$9}swQhM2Az&+mi)@7&x zuH9|Bl&Rc{FlQ`m`nSjRhXpa_D^ndz*_2oQ+vk?DgA&-F_vimAMsS<_x+#( zV9bUq(npX|36u;gk>{H`oEZKx$Pm7Y!@MF(-yX5Jp&Im!K|;Ck_-5xwmwTlZOQag2 z8_w))H31B}CYvHFugf?9U$rq_)o+AwjyBnV`(u$g7e3hoBF@uxpZI z)*4RYhS3lDTTILfdC8n{Ot*8b0^*dy2$U(4&h0B=_2^)lB!DB-BB?BrAP9Dp$LL~< z=*7Y#F8XG$cpVeV)^ls`mTLR*)#rzT2?afb)CA^3)YEcCmsNwSO)Kk{p9F3kKy^rv zWMTG}{^CR{5Lt1m2#=U`DZ+uw>i9(ZPB3gS+1054p3mgQvHyx^Hg+qKOG%RmLNXql5MSZ56!3x`EQ^-C3Ft@>*L*$5zULN(W z?GYQAViMD$C**S5;|KA9l;@VAF&>HeGcXk(GjPYg)7n?TQov$p`fq|`6q78*AkQeE`E!3h(QHKJq8KuAT{olrLO=H6xr zS?;UC0}qlvK8ynsXe!zY5SAK^ZQOnMxWopIaUQWrKG@zJ9Q1%Zk>%5I)T|Oy40cUO z=Ce&%hp}DdO~mG%&AX`N*x?dZ?B6yPY^;EhiRa5-du>2ZF58Tm;l~g#hGTq!bqprs z9&4#SNV4pN$`d&B0@N%GlLA)}A>CiWsCw?oFy@fuQZUU8a2O^#njFGm*d`tmDZXUx z8{raC6Jek7g*@191PN?n$ZAMGCIzz0#+q?^Nka(-$-SJk5l505=0t84oq%02(WF3| z!Zm8q^ek0e1h(}Fqdz&~ig!Gb1f4twlm|Tleq*;`z}b;2Sv$TG;-T7RVm59JYpF7Q$ok{#HRk{o}^D!L9nYym7O6#Y)pgi`IQ^94MYw zeQ#_X9x~hy)6f!*czXBj1If0YQ@4$YE$VF{pMr8QT=xFw(8;U-Kk%(!6-sZY*P9;FdO)0qBwCGC^&r1SmhuVL(z=LDS^UnA~BI#^yJax2er42 zbUk?!+R&Wi`;C$_YZJLr68%((JW#z9Kl}u-Vy%{%qq_I}=Z~C!6i&~NC4Ipq%)9`9 zr6E&bMN0$f#r@BR-03Ae&{d{wx!BG$LkWClH$$4KlPm|uqxF1EoYKq<@HHT|#t#6uS9i)tzj_Qs2yRa@h!1LymquoZoyU1$>ELyUx zeZKzZbEN{I2Y`GdvG&bg`)RR^;bG|7ZDek&H1#dyUiC3qPQk8pBFIGWhnSmq@@9f> zwJXoB0N;oe9RHzg`*qe13^=U!(4dc`RGbKc-Y#V@*Wej-4Kt){*O4atp*^AmHaa{s zG(S6NLdP#%6ZeByQeVnk(xC*X#SE34`qHGnIXvwBK-K5){AiXjWhc`;*|AE{-nYef zYx1*>=lWpgBvYM#V)Q5zOC%&#mJXyD7A*(naOX1#bH;X-5%E?1cMkfU6u#5dp{Cde zQ$U*&y++50*SS8joD9DgC!0$&Zlgf$OK%>49%WJthtmyZ*-0y zN1tbi#${y)#(AhrXq9>ZP|>*YqTEiNMSgywMSS|j*S@n@;CB`i%qI_J)`bcvc@V5V zvSLuC zgav(PW7fB#&6`6~f(2D#gE8bo0U(#-lQ3fIXf|wUwmz03Z_as745iCC7k;QZ{lKMg zkzJ`0YTP6La4{gS&GCtf*tWt&=1{|+VJlx=fnGKHw_??FGFpq9^+NiVlQO=C4i?;U zxllKp&RZbKuRqLb0#EkK{4dXcMwNCPf9a}#m4Euvu>7zE=OaFZey7sz85~r5H<%*F zPuz)PMTn$^a3ERRy?MKWv@$-SbAWxL>ZFs%f(V_gAIL)`5Ak;#{T=U*&cC?l3aX-B zKiPf2T|UmqIk#84ro3^SO*Pi=`(J6_U=E7uw0Z?Jr~;u{@E7n1#dVt|lC4JcbV5E% z7nnnm@1UByju1)Y0S++`k-R4JO3&jh5OnDj00$P!T=F#x9?H@l!);@1juAs^ASImV zs?0KIm2PF{B7XhiyWJ-j(T&6!EmTcgAuj;Xz?w`jUZ2Zh|+@25%C&r5s!>Cq6+ze5b2SqX{SX~JQ< zz1r6jcoW1D^I$&^%XT8;Nb86%of`{VVVGxlky6wiAhQe!jZRT)=8+DV7|@r$t)cpUp-;g5IiO^l2E4P z(8yL!zMYsA^#=7Tx|WIprl;G2;}HncECd4!rO-%HTo&jU55xoFBsk8Q;utHsh+7eE z79E_fOmcbDcYFK-=$^oc z;p6ff5-L)7`5y&CEak%(uDOQL=VyN&*>^+?){uCI+FN<3saIY8PO&gyqx)bKRX=Es zf|jf)(SM(1)!ItKW}}Afgs#_0nJW8fOf;%YnM!@BQU)KxheQMWgfi1Vn?zozjI}4` zF2Zi&cGH76q)NiXt^d7jMN&9!T=5U&7u?S@$217x0TB`}k1IAED;QS@0#5=G%Qrwy!Uzo zj@PK^7#P&^vzwU4c*IQ+zMl^4r4xUbG*E0&EX-AT4;XTTw=O6b`%Zd{9DNfdhq!7G zWQ=(_cK!4~z820N&dMA5!=~QYKb5o@TqhQa6p@m;CsY%n%(Jg9EF#4v@D3%ws{6kh z;rWBV>cTm(Uv**s&IusuTOYS^n~US{$Z>!5pyxYi7~QTxb1E5 zdj?Dp7oindd9ysxVrd~p@~Ufy&Wa~2qB5t`0Ng$QbR4-IY-p~5QV!HWRsZZJh}W-? zM`dWNMnm=AJhteuyC{|(xi)vN54F8B?}+D1TvY80o`UdbD4SRW)J!Tgm>b=+Sf}GC~F? zQLK}}fUF-BDgH4bv5kv-E;}ai)_&#a&~>Kmbw9*BwLdG8a&uLjjr-0%d0IAX!gXyt6Y)}@1hydC3es%}6d0yABvVOTKc18@fKlZKk zO^TNf-U_2BNSI{Q#<&tfKg*$C!e-zqiqpVS1G{L=j#?(PWOTJ&o4@Q$YS0k!3ag*} z;$s6#ki{^k-4N~+h}#pKhv&8*$G`+_3|x%{n>#f_YvN$yJmCpIB4PB5)~h$E}Qw@%o9)Fr@&qrG1Yr*eO)KS=EedzFv| zGD4pYwx)T1om)swI~DgmL?x15kU3oVCFc$~40APKt!3M1Q1)091*N5hqHp6rz_aH{*i*I6CqYzR{QDkt$#NoakNW zx0sq+ZYVK6W?##n9J$0H*xMSW7VEafT)uzwVx~jk3Eb6qx4nO`_6zacADIoyCdX&S z5w&#i7N3ifN>HEug)YzuJO%!6zJ)*l(AQuA___147nE!_t;#9ExZaeb-U+IzafsRh_7@oGX?F1E(#Ce z7vl+oKmv}#X{{mS*j$mVLbq?*>$Hy8#uXwHHB*>*g+qkb9yfZju|%ZGG)?_{hd8x!m4w?P!Z;@ z!sG&J+VZ=I4MZP-g+g&6Z$eW#InR-rE|Eg*>~LD;@LPm|F{5{gOoKK70|5gu0@puW z_%|AZqQ>mK&c19e(&ZW#>wJ6^dM`AF9AEN!<4p%ghnluTn!M_=9(nGq0F{Gq49C0j zWb-sknBDkRCiC8AW>8Z2XO1H(agt*!BTA#NL&d{z-O%^x0qsJolx$bF0DsF2)Io0> zv%m0N^)ovmw6INJ$($N$96+Yn^@Tb~5#vdPe*Ln;G9TX}f)q0pHADOo?-LXizGb~;G&=O@yIdfFo77A~R~hBTL!Q5#(XtNM?9$>4j@#knw=tZv z%4;ffXm)!*5oH!=WyN}HF|)cmL*620MP$t%P!TM1n46WEB52r?-qwha53Nk$WS8d& zR>o|?HF1$I4bla6naD>2lUJ;CyyS<~m&}Bg>8XC&lG_!}03TH?bQK6`oSId@lMEml zbF*tKThM(eKps>mUTFOMdmoeNq1&J_^*pL!b#C6l*6G#u@V1cYY)876-S=>YwCUDR zL#=y;^*yx$+slDZ*Ko3gNnEq?sy|M%4+$;8*o98N(-Pj zw?s%mIRVAp$NM#-4VxSb#g>)2Obq0|D)?Xktfhn264GYTSl;!F+MLRbc26`&<8XMW z=FrK{u!akBIc_?+=Z_tt99&6pDzkmJ1+mX?{klpw0dpq2Am4PE1AY-C6^sfwPhXQc zIXTe|BVeC(y=N8u7k_bll3P?CRIb(g^vi=ytBB~=WaA@b?QCr{E*hS zrMFWYJ3HYKztHwxqdRsf@KT!ZJFwQ9jl~D2uEIs1XG#E+Z#EW3vupSxyp&{LAj}DS z8*pqK<2V}@gL1AGX^gNXNVQgZ$a4G7Db3PSEJc+97wB@=i;K@CdD`!_=#O&Xj2%Je zfRbDZm^b_7g-M&g0T6e7TRglH8gy0x^mE6rHyFi_7Q5&#r@#RMTf_Al(0R1Gc)ERg zvF#N5v+~rx(iYul`0QqNpgB($f5cnohVL6XYl^pKiD~mVZ|{6Bvp+aLWWlHbkr5T) zvk(7jc=p@X_=zWf-XzH;%qM5YN&bx9r`;-R80q_zJDv8RQ zNJ=&i{iCHDff`j_>FyQ^{WC<38;uq90}nLfXOH$x=ooz;6$+S^fH7!-46lPYJjJJP z`r3r|mWRsaV~hpR?51%TZi1)53v<|IxGYQy#>xrOnmb;&Vg5)e`SN8E6)dg$VCOz( zJT?qAGB?P%SXD*%h9<)w=`j@h3pwVh7Cn&_(J1SxopLLBJj|dsGdTFVGRjV24~%cTHq zkEjrO^9&)6IuuJ0q42;D^Ud{BB(%>hp5|>oBrDOitE__xPiob|%KVo2qm~gX1`}~H zebr5l1OYqKDy@GyDc^2^t@`qOf9@0)xU?tBut{2t45Sr)=jt%fxg66!BCcM*iwfZr zW*=Zj#UvbC7MyKmW8Fo!i2J^?!`01R8kPaj1ZvnSP;VX5)sd- zAW&@_S~?*INhqyE|Jcnt9`ZSy!H8LLYKXh8ZnzGVmnSHtJ*pJ%;oC< zpCa@G8evT|!ihoiLP#ws^j>gM#}m>3Y8EjStUj4yO{ecHrCxs=BRCirVb-8bmB0fX zltZ<9Yfuoze4yzR^5aQTzJW*=0j9yIr>CY_s z`Y!re@1&i#GrrRvN#F*^4j_RIXdCx0c<>nxP!>NcEimU)0?vWh!7AYpc_a7}eWVl@nsTnj z?%1`p>*MgO0&NPLg+j>7^2@OZbUZpXffK1AyDlQkHpT`0Iv#+|MpGFvE67WKk`#92 zT?o+2(iH=|!*hbGHXhFCV^vr+0~pHMA<9Oyb?*DqakD>xl3Jy)&2RL?-FD0GqQKus z+!>D`a`0An-u+^~;dEVe16|Jr`b~~UV=8p zq+IYjU|l*)iU`f?nkSlvniO)fz_u{8F;nC{%!g5e1Acc+*~wICZgI)|1FOR8pzRsT zHoX)3`ySVs417Gn(J?uRNDKu-BXl&)D)fU5xmKZtRNSWa+-`#a_A^pU`s?DNXh_f< zbm3XRQ7l)Ig5@E>KB-Og;r@P+=f-Gj4PQc~Ms6k`5=~~)haC928`mXQaXbW874`+t>-ew&2P8%98EKCWghE&4_D`nTX-{6Jg3X6 z8d4ph1@17u1D+%Uae_Gs27&z(_^u&K;{abh84Ii^_HGqmSZ`IlY^`-}JD-kYkW4$N zPw6&(bZ1K8FKDardN5QEYA*wnMzmk_n>iFE>4Osmw`#&LkOg9iZ%Ii037K~D7s3F-lO7{R$C#&3TRUA&+}LFZ9gW-R(f$bG0*GBn{)`0x z_yt8r9(USWXl_^wp(}Y?HIwN;x1WAGmBU}5aEN>Fvj&U=}_+_9e1zUt{Iwv>iTjh+xIJ;3o z2OANe349=bdA}oU&|pR%XCF;e4W&_v>hTs&s1h(Y$lur0=2m zc~veM(g7`NL%KYlOHq0nagkB6Q7xoq5}Q6;@ly_MceGES&6Me1SMvx9vlmML1&Fcp z^lpJ{Txqo-38ciwDpeD=@**)v0mX1+c6(7ZAeGBbhGRu=hK;3x3bG1zQluLb-F&cl zzg~pAuX+Y(tlc^Nt6dV-ZVGU;R$h8-CPPYnv0e6=Z;%pD<$pfjBhAXntm~S#4;;9B z-}=t9QNZn#tjt0r4a4Y~;Jb*|9dBPde;^Qb)DaavpUjPydi6Hc*AXZ;Xd^T3lj9yt zy_;}_X`tl9VbYk(CR2L`qgJ)5%Qe6RD@=PM7v zUv@2&#nxs};c{FTf$?9v!kHR~7)W-&a@6Vn<#~#0^<6WfD(g$&d#% zaK~Rr08{(&a!A(_R?QBA!NY5O*5Ai8q)ToQngSf`kM%j6+4aMVP8<@eGrSw_ZDEET zrnXM$3Y&pieEioaw-`SY(d2k=1JHEA;gqJyv7k`RES z@l|))kJf3H$Sp{iaeLK=uPKe`PpVr3%^Bbk1wjDFT-=%VD>^2a<_is7lzfeTbVB{W z2tG55NM*sjoqPaSZ$BYj77O!JQ50p9_36xrBgQ3VQj!+t6QRxwf7iTl76-fS%BZ@O zZ}3C18y%;UXV1KsS&L7~@Drh-_$rjOcxm@!!Lfm-opLc#Iy!(X>L>fx=j1gZ?!T*i z2X;^lpZIdRQm&y!QJk;vVKU1&PHjkU3EbBGRXwH;r7+zOx^Db5BY96cz@HzgFcUD3 zr zk(PRj9R0-GR;H^z7j_V@8rEg5TQpwh-kDnaxoGgg8IOu&t|BR!i=eQ~iDs{q<7)#K zez373lqjwGwH*F2P^64&ONNbDrt#z2#f$^>&)b|^?(DSULV|xkg&>HXE_Ua`cV3Y~ zajuZsk0nUTijSmg%TnFns3Yd4hG$%XW1o)1Xyf|-=z7bzrr$Sg7{-v%8;#T`X(^?< zTR^2HC#ayLbTfLSq;v@wv~=ePDV6RJ6p-$EzNo+dbKfuSm%QP#UAy8ukMoEXqx79v zMu+%xU@ibqk~vepghh8(xLsuSD##-nAFSK^&X=#SjKATq6{{$as63I>x&#jwu5=BRtxX72D>R4MFJJAD%Cw5BW*oC zPIb}Z)uhL>f4dam%e4C6CX!C~Mdye-6ON~n=Lj0`rLqy$O)9ymUY~;HN><%~UXaV` zQKa&Syn`<^BXFIuiUGIhF>>>cTG)T2w16)P{^i)>RLjIpSmz4L22mei^y zQQx$$Oi+$iIsxpL7(dC|x%z$0-*}(wSiH4U1RHI8Zw8#St=YV2^@{UN#b7$-OX2+h=7q?%(Pc*ui`^NYS;CKJx zuvGkPq&%w!(6^pIlcB^z)$lbBk!AH{K3lPwM1O&4l6?6R|< zeJrBp?k87mF2s*aeb8ht-9WkNAX)!m5q%M!L%4q#|DWW0~S)B4N#1^Gsw?6V20Seo~V@YgP@CjR^N+A%** zds$8xFTxFUKIx74j7MVNF;a&}DQOZ6ADEFT3*_HHlV1>>-c8VK&&z9c(6}{pm|L>{ zcaLX}!CLu3cgflrZ+)ZM2)wsjeC8~bYReH+!Tt~^>jJjqWq`#X-iVsvn0uqJ-)7j( z{g|W^&xJs=L@4n6&CUT<0_akq%f$IM2p0jNHLB1gvls$~PP`HeZ(Sp4(7F!7E?S`o z!(PC(2Qw!99Iy&b0B)B~wG|Nvsdbzl{0v!GT*3QAcBsIPFaruJQV@F*d+0}H6$Bm`Wy<^w zIV*w?nPcXA${M`lb$RyrNv%U0;G&W|xF%X>`oDTL5AGiq%^wG?q|)Y};4$;^IGv!( z$B%x)Y{&Oh8<_h=jfx-89-=T>G}DiOMo}~05_PaPl=WcawV)u0l@ttOI7H*bPaQ9< zg>fJec9p)r&=%w(*@@^2lp*iGDpO1fspWQRE%d_QR!V37n5q?skfr$_>k$}X#qL^d z-Z5%_5w5C?#s@f+YBcfyKSR}cg3|B@)&S!}xUH<6MIEu-^}0#y-I1(7l{ShD&fJG^ zKSt@Wm5TD};m3cLe-+p(<+Lz>&hk1M14ORzSm6AVDBC?UxZVMaocw2cVgW_{#bsSM zk~c59>=mvtMWr3zd*)5Xu%4uCzF}TrwEl*niy0$S3!Xq~JwB?hkh&%Y@ejKaHl_(~6Oc0lY)^Nq>x_wo;V(%K9)2vCaHF+L#@+9_bznx6z4=4A2 zXNTCRrPKl;?B;mWPNlMcqu0t;J>)`cTBbODb**4QI1zINi0AITF&91I+u3@-35 z3{3D8Uws*Ij>UtVo+I~f5!K#@))iHVKk@(;FcY7pT>}sn@^&_+l}_n(`ViF*W}u{& zEg}*#C)Ily`tF%`vujJMb z(SLhxZDt6Pkvx>0NROZxp#71Pa>ZggevDU?`WUD5_&yR4!|bG$jssvdGn_qJP+m=@ zXQk;OmkvV_!y(fWPCmH`>E^OYTQ3Lz=7hBH4sO z`vtPJF)(B>R25_&{e3aaHNh2~5wYXt;-U1dU7PYBW!_PiTWX42Z}gYN2_{)76EIcF zys67%n3?2aNH`^pWkDdkyoc_*HFQCYN@j;x4McX4||V!iS=ykGqd$@^g`p>wcGed06m*DZiy zSj!KpL5jg~an}Z8gX2HI^fzhHL>+w3qL5V=WJT4^XWYQt4}-B7dZ>d-rF3|>nBr}ZH+f|N~*B_8`ovD+nQhzAH-OTGXmk^SNpP{W(_z!8HlCYAjjo$PK za?Dnnjb6vEEK^APwt;xc8@Uldt*+3A@0RtYe_vIg=%l)!I(N{ugnqpDwA2c?lp!~$ zJRPwp)g{3tVFj7atV1K%0;7qz5EDj$j>UxIE{OOe337ld6X&OAUp6-_q|um3{#kc` zKS7fz4v2^Vv3v8JL!9A0z_|S!pw&bTPp)TAr@|k{j)bRX^i}2w`V$I1Eat662(r9n zGL9WSJtfk;Wf15$ns@mmB6?%c>~Ji8d;mvZ$8`)T=uV<)O^yd~?ii2t?vQULsD=o;XaZY3lK|+e|<^ z68ktdw4FlBD_eR*>h^S6G0smz;Q9dw`2b^v)MwThVuuNWl*nqgPUvz{zHDBxtvoX` zE}7+FH+J}n7r~vVUakH1xV{#KzJ?wZv4NQ6+y+M5R1~Z!fS*A#lX)<5QdqXg|5=+< zyBFk5x;l~Nt@D8JFiP@!Nm`S9po2Ozd;EbUK?b|%M{&)TZi7Dl=0ZRD&IRGtx?fo| zA*Pgn8xk2pc&mFT^J|Y4+?B>eT`G*YMLy_~1bMk7YrcyHp6_lk#~*`x;1h>=EMyUbJ0#vs@VP! zVbQ_MxGy839Kv%t#sN}D$iWi`Ilp|OSPs|4%>?QfOL)Zw&MA6}K43KK)8_*7Es4C1 z%X|SbX|a9F5$niEp)dOA8iOX_dLwsqM-i>7AWUBnfN(5(q z*Iu9|8C&CB(&|`a4Uo|5PWaKR+dOLyEI>k_n-ygzlFJWf^mZaxB$YRou(E@(GtZbL zxnKq*qa22golNv|cGGr}4%7*fY=$y5D}QPS`kwtPtkPn-Or3njuFkFrG(A3VWxG$= zv;N1|{Y8$6@*gnon27jFREN*ZbklawW~B$w_S{GGX#=lsb~$w6INBR!+TD=z78n7y zg{SaKNTj={L+AjLI1MCmIt`GMcx`o))IoB({E#JT=sBwj`Fis@w(zSN6&>GU=lR;f zNFo#0Tr^Qu;*?`6u1yJB)$7;B8+X~{-Crq|zI?eqo&0Him0Lq=vQfGxaP4##H;vBA zs!}S_-PN6acDZJ{=Bpr(C${~(dIMk(0>t+z`Lmw2s@#%4=-E965R^IyN=OYSd4nq3 zwS1E(!BFHqV>xa;qdW$$VCc7$7YH^9_(bD@bf!vft0^tzoy3a)a4$5udE}F{?ci-? zlg~gk4xFf4Hzx|~H2_E0F@mTH`SmQayA3M&T4K=zQqodZHI*YbYEPj=CaiD<{yQyDWbE=ppvZSfqCDdINibozB}6x}E7&i9h4+ zn`!Z32!@tQx8w>Rg7=7@L}2h!f=HHQjB|%U(d0`m#sVw3>?;`Ll!`iaUi`T@v!R3E z?@&|KdjtaKaUS|PW=xfDPH5Gm;r;ew4dLrljiih^(6e)(N)4ajUqQrBOPk8+zYgt- z?ohU?8Pa&#pzv|sNw=%ycqQTqM|`mKFiCm)#_g4e({RVM*H1jBGVZ@=aGM;cToXDP z>%DDy_2GC#HpM?+{}zeJP;Kf^a_iUsuD&t|xEyr;c+9oSfTY@B@c9p9W1B&w25b-8 zRR$3Q5U|K{K!I%ecnHt|;~j9WI4lPwfGs4~{al5DmNGRr)hi+M32?m|$pZvSBU>0i z7x%scf_#QTplIkEMgKM~p-|kBbma*lpk2nxeXQYWdJsmg^Way6Kbk-h>@bGHuK>5R z%CUFfwcY{}521vk*v9SMBvMh%qA@&c0{FN&QUY?4ft<&I&tUDoo1s|#&U|mfP0APF zjRjMK*VWmj4{XnvE-!$0RAqXdPIwXR!6Q@;COgr8qpC9wIn{QrlE5OamCTWW>F zI)AyWqbSU~T33#Kg?2EJpqfNZ><;)gO~4ikf!US`5nD&27Z(RG7U3oekXK1ur@(`= z1$2-%j~!zFixbJNltSUt$ruLT6Gk58_BF%Y^OFYWWaZ+MCHv%0(`*cz67J|J6JGX{ z27w2z0=Gq#kKA}*Tq1Kz{m3dWg~%$Fum=+CcTbSuB>mlWnq^{!iH)?DsezqX&AMiS zI&l|U^qqC~b^5eJ@2FX;LzlnL6ch$zD7=*~2^Hx@)L7F$jOD0s!d?b?$+CycW_&+z z;z-YhU3ZtIj;!zz#W4mITwxUExYSSnbvVF;uqn~DkmnI8V;Kj;oJuw}n7x%dMbWsd zw}SMxHwX0SLn6h+@9jo<#IJx>x|Lfflepw@-mz@?^#Kyj31uo)U`Qm>{gK8ADhM|M z{{-bw$R?b3`UC+kI4K}88a9F0>9gRkIL`5NH^D4wMqtdrGiY7L z*yA|Sk;@6Wcmmn^{&k-lpA5r7#6t8UlASDPfa%gQgR*0G%REfO~8-W>6> z%}Ji;zwdH+|MJBy{esu_o8ow@hA3C3w&PAR?}V|L9Ae6*SF7IS0yvp0>1GnkKs_O~ zUgt^7_Us_*Z}syr5W|&h^YMh9)pIK1aW0r$}(GI6bv;>CMx(xb`!j*`}9-=Q+^b}O!gadeh^MYZ<2!T)PX&+LPH%T6aARUgFq$Lzqt4iI1JqzLhIzbS z=TlFWq~B%1&W?e|iExaAjnbBPzN+($4vT?L8r}I7YZs=hAIQF!;aBA7nrPCsq`>Ij zQE8+}@j%i3+qF|Uv`3BY(#JE3Mn)g~Y07An;no$fdJ485FK~kxSMUdyZ~wVN zF(B~k+`=5coUGkU5x*<%`2AR{INa33-pvOHNdYAGfkZk5^rh(9-x5)Vh$WABk4_7U z7^r11j+Wi*;SUr9(>b*!@1FnqP^ya%O)ASbrHLD=qpaX~eFYRATl#EzsQMY=;@rHN z@uPHc8=U6z!TQZuuK;UidIFOw;^eesVg4e2|1?xTL|ya&Q( zcoF0w#;CSfZtb1*7;k0ig84hOCZ$R zUo%THePw>oea>BC_EJ5ghzk+pMPF_?yn3yeY%}dxbaMNb7ce!RyRI|OxT+f!&~KpZ zF$5~Stkjv`^>#T{p*)_K{k}u|$;pLJUimH&!5w}&k7DP)G3fF6T}Z7xN>De5o*!~ z`cy9mqH0OI0Pc)Hi4Fsre7rkn=KJ_F)uhC;>VJ2E(2Y|HO^=p7Ucg%g3=7ocIK-Mt z^@mgCk$|-2kaLHSp65#(_0X3#&0qKGwixwTbQPcXZC`dP?G4#gU9@l9Oa67MII!L~ znvrgi(t;|8rdt^7fqX>!)sO`HmXI}@Y<(-V#=GB5wsAo`jEZWhRWOY|+rni@${eM` zLo*q;?9FSbsCgyvB3Jjo5LG`=AL*;Gg4d3j=icTJ1MQ?jwd|+bLNT&?&nMHUV) z#$1=0`o+b?qsxaH=$P|>CN`)+4F(v+U~Ch*2)gj4lQoKSMj--BsP>qn$#su1sxF+- zsq5i4GLlZhTule*73HMg%TFlxo^m=wU9+zN@;U~DuL`+ni*HX(NA)()F1F`=|J-o5 zu2IXD%y3u#r_aV=>VI*kIrO@`xSz(C!42D?&i`^kri_ojcoyY)@IWNqsxY2U%@FB8ItZ-IHo&e$gH z%YfE&|5Dhcp(i4v>xnD3TYJ5e*Gy5xJuin3GLA&{5%K&cF0z#e!=|fBcGa)Dr^J(T z<>3Ag$A_K>6Je6cLp=(R!}z_RTl_khNpCozAFYH)@GuAUkSl0dMbr@0Ak^CtrF_Z1 zsd&q|xnsD;d4xW$GK)hwa9{1yciJ9p8J%|%qtfd%WozNxP{ECLdn!NC(5uL0+^)#x zuXZdLzFZQ*)Ea^8*h;pngR5>W5&<3q1}LXPFO%qasXychp=b;N>TSan2?R5O4Z+*CngBI%7>UEfif+LI(O0g|Qt2FxvfVQ6-^7Dvu%^Fdhdod9rjqK{%?Mz_4L; zaZa&AjB2HdWv%6bzN(U8dI9^`r}wsDEUxs@Nq|=ALV2xCKIzzI`u(>h7NT4WZY|BJ z&SbMGCLONy;V7*29P!j)L4#jlI_z16?Uhe2a1;MrJ4M7`DlF=bvJZSj@zg_T+8~wI z^0ET+EQ|D~8Z3go0-5GtnerI;syk1ogXO+ug{z}FVp;u8SCjMe(htLQCR|5Uhc)%o z%>9WvDnodHD_B(`mXnDYNbp)UXO0ek)YLpf*%=`fL)4Ye;ga`ap=`ABXUacNgdiZX zDVByyT_31ew6P%YD$De4xZFy}|3e0-=snECtS|GP{gec5ua@U(wQJMx?!qs!cSd-1CQ3}3 z-nL^a%@@xXn)-c_-~BP^;g;RHKfUT!8%MV4FWjQv7vp7@FYzDk-cQlrjnj!}+aT%8 ze@ESY#^G6rNr(l1_x+~O>xdkwo3AYjYLsq|E0>7J7NgzHlD<0WxZ1wH;_aOjk*X+; zKPDDqUV$LAS6pa0fK=^IHv_<*H8XAi&+{8*C{h2lq+6ZuSpP4FwZ5wsKil)>t8UlL z=`0oU#BWvwUXPqm6^ySON-u$!TqDkv;Gv=n4>3FDyT-)zzas`=Iem_S|KN6+eI|?? zj5K_NOgGEk?7BWdZ5oErVFtNq@`BClM2G2CK&dCKQyllRFQST3nQ~Q z4`~e8dQiQPs6EF2r)2QCF;npQocw|dEESFcx~&8S%Uh?zHwQh!hRRcGgiJgw=~n4n zKf1Sj`=b7-9ohP4(72Ta)LzE4l>tjuUfT6G@<*LN@G7fo8hW%cq!J0Vzd7D-d(C`o zvhg-0vH5KPM3&kK8{`R3oi4AO#rWN3*U zqKwFc>wP;H{BQ+af{!QzzB3uZd2_vTN*Rw|-pk?b9*s-rlByTp{``jR!JR_b_WhO9 zk9Og6=yT#iqG=9k>FvYyonyxTnGJAgP^ucPxr(&MMWZTE< z*e%WDaP&@-);B^Bp7C72MCiYH8kBlLNw3B$zNGCd1cw8iz(#io1Rq>7dDvM7}wMG&u>zoJ22}MLQ^gx z?Cv%n$}lM=L;}EEu7@Ddv}#<1HeDoXAt=Q&R{p778D>^rmx@((GcARk-r2wfeAZs zEODx1B)xLCq1;)*4Ar55FZ~|N(`;s@RsbVB0zT0Z5W+1kN$fhUB0&mcFTy!onk>c_dJ@JgA&ew&q3ZU8+<|2T zR*YBxq!9XLTTU_#lWwnH7xe#sLCs zP9U~SYQL#-+PoSeYHMg$p1OzH>h+-dkzN_>+?@2Dm$)LXvw{KtsSQ?g#&m;BWWT%3xCv-?c=XxQtA{6k);I=@h2O|=PA1fH#mN8V83)KJL)QHa-Jr(k) z&oJ?*UPg`fQLsigcW0;ujSz37OF@uHd?D3_*sLpKkm)sWbd7SWO4jEI9?h4 z02a;oqssyePf&(XE~?TBEAk2rv;^*@V>YA&mu37kgtkNx=IzUflw$Y?V* z`or}pL;Fl;yl(Fofv(ZOHEQGZtg(aHNlcAvs)Lp2l6Wwhb9xy~?1`-cgI z`kTX>P+mKQ!-h~B@n=Ab_uC5kc~f*WL~=NK$qv;dJUmc3seX#Y5& ztGoonU?d-!hj1wlLakLUlu~3vNoZOWQ5gAfeefjH4w`lj*fvJc0aiaE0#dJ}esk&oT|o>a+iQ_e*4H{KA(2=*^Ymv^tYGDM-nA^U8#f3m z6it48u_hgbi@ol$9)aGCr2vr6!-eWsW@AIE$KK?z=pSQ3uk)9C-yFZ(= z1^-;NQGpl;(B>P3;#y!PYxElwKRYpzhM2c=(^a%z%iWsSsgQgnFt>$_$oM3>!QzEj z8asYB>mmF_gZBhk73|bUy8qN`L!wDv(4$7txW4Blo2ZPtxhhev1oTVFI(fOog0(pw z;N>FzYQFhp%f+60gc@dBJlV4FxrX<$N%u1d3oI(d5n31En6b?mWPTou5%?+kEEA9k zPgYyu!Zs_{B`0?OyRLQtMo{kVw84Xke8@sJt5sEqXyiVOF)ktf>P@Mgr*Gdo^@nHc2;42YIZd$w3STw%Gh@;clM`Gttg1V4-SPSFP;rX*}v$vUs zzz*1w^FO}3OuD_vC*rgXkF9v3Su#~3_Dc$=8SdQyty?2#nFdr?ndR+W@qCEr(vX=w z;xX*O(EbXf7ha&&5i^%7L5>Fzl-I3h(BRaOH^?Y|w%9@%nrW~+fg^5LN!+wpCXcmDWde?^_1^h=mfZ%-JZ=9QW%G*X z-**HG+K~5m)`UrUmGT?BBE%`=9GFYkQ$GB3-z+`^i3FY1(SY2c&RE&h@X^u&ANt!yGwn=~4+zv?Q#>@c>S1Xh6xLc|Cb1L# z3Lb%;c?>9EiNu%;Q{a{i*b_}95;Yn6tj%pR4~)#S6fI_gP(UsiHfE;Fv)f8tE0WqD z%5}1};{|L5@rBz?=8t+`i~R#ig+gRdij978`b$1hv=OvSdu!be-)~q@-nRo%!XvMO zxuclDx}IaHdp~uhd~O}f(#JTBV22xF#s#rcH(n2K4PzGL>u^qa9U1gw(sR|`)%!#S zC0mtgU?T;OL*5B`|GXpnK5$P9YyJSA3?)Yn=Hpfq_>u!ptRMbG@V@<2V0# zUpTq4+nQZX<((-!K6X7-D9;5Knq155q+iu5sq07xo4SzDeftM& zJzwi4%FCX^98-D3Ky~q*6J3>M7dS)hNS37giw3N?G+b6f^|(SJcJJ4LOaefONKziy z8!_=cj*V*VzfV?o^H9`Hn?0CUfWR*pX_?qbno)*xkm3JR2rh?=kSkfpnfDfr)s2ko zf>f!i2ax%2#CFZ(lJ6@T?|eQoz(cf64*c^9#cfAAGFM*F9xI9z5PiwiCg3Y!3|pps z#{*qrwn8%r=Ha$uQ-hQMh=F05_LfA-_w*R&)aozRzp;M9nwS!>s@ZvHduq}5MWhm5 zkYY~VlIPpFzZ{mkrA?+orE>*w4%&C!@|$acecpu=YS<9^65}#j2n&9?ow?GS9qRod>OZauPg;pF^xoL` zs+f$|Wc1eE>8NByuaoL$LxtRvpKn~4ejzgw_!IaWNG!3J$&YlI1g`-y7l#q{Q1F*~ z;z^&ZX(F9ZGSB6*{bwA1&xmepZE04EY&v@PoS3R+aJDJ@XE)#jSQ0Aw)MUNj1#>FF zX-@}6tvxVN(^Os#A1hfUI0Nq!`J&_n1=TBGO!PpI3!1sK$li}wEr8`Io&3(zJ0eIt zrpNGDCkF7h@5qS=hHP0aFb*F}s3Y(BGmGK&lUog9XmThU{INo}OeiL?l|`(;Gp_WF zNugzWg%bF3XSQUZc^e>)&4OFGo5Ikb5rmFgM0$axfV1Z zN**PPSc!{O&6M`bj1HDSrv%$|G^C&iZtvkN8=&bOeV=|FHU!S|O;NaWC37nTmC)*HvHJj{-c`|y}|R{vkq zMS-~)HIyk?i9<|30cfM_p6!GuM&MV^=c%PnS-CFaS2}w+yPC6A&kU8~r=whnACLT& zH+AzG6f=^zU6GdJgD!t=#*1*V9=(<2UPUmDc_twT7JAWbw`ur+wVTr}cS0kT53O6r zy$0*|>r82wI^?3Wxd>5c1Jj3*b7KW+1!`*kk8BD=pmJ3_du9f?hY7OCRx;>pMOxiN zo-m}Ji0t=@yxqAV{WNyWq=|J6pMoW=wQO zpl8yLbT|MDWSC5{oR-42Y@uw{R0ML9dW4;wVe*YvD8U(U_$F@HWpVnIE5QZ#=WB9J zv+j~gO4^IE`J9-(w_hjFIew6w^S6+f%btVE2(|c}ABD0P#d1zbGVQiyJT*JZGhb`j zDJs_T-&wT#O8Qjy=-PYnE(e3OnO5>kOW%Vj5KTq%{DBJjq(<5(@w0Kb)xtX5M*5)^ z`yH+)R{-8(%Ip+_&_qkMYMVFjNG^7p;w zOQI)y-EW0O0!=iS`5*@FU|%(79@I=CratpP46OwF{`${_(XA+R`{8o+r%VmVBP0fh zX>e>6MiQnHz!%9#iz5LNSzAhw04D7b1_Ayw-JD1A3yH&qumc(?T<^BGDx_63mEu7n z0Zjg1K{n!Q*wL<2&>lsh<#o8TlmdPUZjVyzoj`9=4aamk!#zc)?Szo!BP5~lu#kz$ z`Ldm5)3Y+0ciTV+Spu0At%={&sSVTjg`#?=RW&2#`1yMXl#Mtuo0`-a-3^zi>PS!D6*b+)5aI`NvwTG#fH^2d7HFV!<*Hd^5(h~RYN_!5j`XspzY8HMfajk~k_Uq*{ znx10y8fz)EjZ#d!lE}NI_?^zS&-=!RjX%hqH7m3ts+8A%KNvwB-x%2)?UA}%PS!s z(9q1UR|HFJ3Zt)LD@SmP0DSv8lL?r!;haH`VV@zSiMhyGl*T;*2!)1u;7ksGxi0v1 z=FMa)+XK*NUeeEK)}QWl3uqi%zR1CjyVSAPrb&WSDh;Zo8DRfEFPcK9iXP zVJ9lZk=*!q5awMbeLm92^W~iw4QhV%&*5(^`Wfy+C;&5O&8@&uHz1j#!SCAFNiE0a z>SQ_Qc@~8A1`lp-ZYJBZ?B}W>6b^ev$KE)QV#*`S65!qDVUqX9st$1blgAJRi3Yg+ zzM0i>^Cv}lEel{(vTFe6m$D9bOx-o8ZuT1F(;9!C(J+(p-M@^`_mhlLn!4 z6mGLj(dHj9>5Sc(D==}QD>f>wT38YCvj_B*(!W%{sfotD|IYch>@?qinhOvKF{$8h z)_CNHHPLldaraP)?^QRUT4PNmpg@Wu%m zlJ&z)s`exhMNP6B&}&I+#_>t1%77)kR-wJMJ6x00tMGpsEpC7{i5MCFBYDb} zg~}L)6;VJLlGs#;2E>9V=@js)VIxe@vW+r}fsbJM1S%xuC>3tf4#_YRScnJ{7zt{p z=t6qwN-2pq551b~@yF4TDRu(4MiTsH_lkY;jB6)fQ~Rxs%5(9Zf-UsT+t)ptc&4=K zR(h5COT;{(2oR9xF<<3%`yUG&25cuF9b@(M0WX5$?Y*7mliuNB0;S zrX`qOSwzY|<_;ny!Z~Jf>N1UaTi&C8k>Wre0D#W|ar))bB&^$j@2+O&tK3ybqWZQq zmQ6*AhaILALXS3;C-}yhUU?7ty#A+o1ylimw%m{A7w#X7azhCoMmccOxri#?M#nMt z{*0~&-p}Bve4i2!AqPW5ZYFKRZL+^Pqz~n!XQwE1{~Yo`58UfA?@21)p0K&455*e0 zRWd9oEgnSdDo;Yl9KmbS%|Dukup^!V0lxy!yU_6 zG1Ms)!9OCQ@Uf^zPcP$!y^akiZ=t<-@;?CR!~BM9kyU8z^E~!Ki)&lL`m`yTd;WFb zo;cARIYlO&l?(^j!MdrR#@9oYErt7^=)2m(vsPclm@X=fB&>askbYJ0+gb0eJEB0i z#?JRgv8Lw%cT$a9w>d$_diYo3Nm)dl(K_Ax8;fsS#@6!))}O;(v8wY=aR~uINT)6w z|H?EYYv;IRJm{F?P$4V(zkGyY1Bm%DGaeX;ZRZXUVqb9?Cp-T%@@_FI{{B6v50FxyE4tpQNXh-fA;Y4T(J(QNJETH8O>Nk!!Knr#t@RS*cxx2@Wk_7|eje)jZj)=w4gpf{-Gh-(ch@rppJ=i{;oNr%{>vr~|13)a z`k<}PR70|r^YK(XV>vV3^CNVdJNmZHy#rR3_12|;EDG%Tp_<>-CW~LS>Joo+CW;>! zmRPl2npXu>_60+OZR@u`K7k&{CXf&@Oi)2lkKCvsfRW|1yObhkuGZ@W}n<=HfIUXn*?!^cKG(ZpXePt;0Ct31FGD&#st zTgqx~K(Tn!w|!E;I42g6tY);6%YfcCL2MrpA5{DFi>Qhz|?-{)_zYMGAPh z1CLMjwDRXaknSTw%mgwr!t@b#3M#NpCmJ>a+EY;YEVJuzw3$jsNXW_>wv3>ig>t|1 z>E;;ELBqOv(Io7g>;f}EUXEG7_>-bgG<9D)x+rb558_X#0HW1m4>AvvJGto+f*I%m zh4f1h$1TM}z+1WU#wixNYR;jc`2gpPXef+7g_`O>lmt)6C!(1Y@y64uJJHxs`48oB zItU{luiLYGi^1<=M1E(kVnoNSU9>p2c0X)YvRwXCy4(EBBFR9uB?sUy6lU6fvKe#xvqh~H{Es>ERjtE-pz`@!IH7hq22P_v zyvHN2yYn8IRLKo_aBYfo`tO`VSJNeaj@;GljI5^5s;=%JENWIzncS`udHGO~_sJNQ zhLt{GP8v@`#2}U4T{_fKrv|)pKy@GmTIX07hz0Q9ap|Et-+Rk@C$+q#-1uh zw+%q{c%v zi;ad#&i~1Qd~U{$KGkV2c>X{#xL}7zc`4c7vQxn2n0d5X=WyNDqaPAvBDC|9PZcL( zo>3_1EYPN3%O-{KfHAD!S*8$-D%y2GApG!zytf!deTf*(WZFBSRiIP<)aH-ss^ZYW zj3Oo|4?rV&ad~-34ukUbjaIYtl?cTJuXUDp?-LRb1>+(djlXojl^S;N7Br2u+FXLcUS| zU9b0hIMr5kRjPj8(bD{N^|e6gx?FPD}#Qqi=cd)JfV`xEt}l~>ZoQ{(EEY>r17 zM?P7-E@Dr`UYuj$eNU*?mXY}$sIADV@EjJFq(~O5H4tR&pt#uX-B3pp&ZK*YCQpjy_hNdrMeTH46v0-CcaY=|=^~S~THkla zfvU7^=X52dCZ+BSsUeMdjq^6m>htQ4_-lOUr)X}H2UD~_o zNCT%Ovg3X+H$hh{2tSJwONYU!*s>o?#i}_f+Su4YIH8a8?=chLo(XCY``QJ`h$bE~ z7O6y2phykcQvLhn^*krkIt~`@o2BEs*RHIxpMT+BupsLu_!*$liZVs>g;2}Wn=Inn zMsMx3^RLz}sI@y+yw}y~p1kPpE8VM**DV%Wr^<+OiMnw#(>wvsY8;TQ6lzuRrnaOnjuc zDhB+dF%eUL{&og1ipT>2*dms!FFgt}7VFDI==f14Heez!VkdWWGFR8V%|(iIf-Njw zfwU2|gcwlwWM zA2u3vl~A=QJY8H&Qp=87g&FKHxh{7{jbN1;NrrgTYDJS@(Cb>Xobotauzpl|bdL-Z z1`Qa&b@2I7ukmVmY)o&+)_cpj4L9L9D{Z96yuK;cyN{ZAAE_{x{jS#hlz7EUB5yvYvfapME(4UU+iF6*&$67GD>RzBZC8GPN9%6v3~4rRgC)R==h z7m|*=QR4G2DGkUjOzV5LTS}Ww0u#N@`jlsI(OAl=`BH`rXrc32>YcNG-s!_2UZd@T z$h+^?%Z(^~hDlFGlo_I0oTrNZoiAbB{9|Vbg+q{x^6y*gXHVngr!dMDHNb=$epFrB)Cd>fE z_u$2^BE-+%T*^7W;F$N@>geLxx?H&BSOfe zsyJuA&%xw3EkumZrj_g2!O!gW$c1nSSMxyu?_|qGe+w#d^BhPr!Nupw^ttkBXTg_Wt!SD`LTR_4qa=CX7lP^SAQ&Cu7Q?doym%W?w|Bx5qRae3sl5 z-n@8WdvP&lb*OIiacuj8?FGH?@(?R2$5Xp+mzmAOUteCl!yojqo(W-MRQGnr4e%O7Oq>7aSQ#S2*_7xd9 z3XmN5*ulhP0z64pzHZWf>$aib^DxEC5{TK^R>sB5nI{zBtb=tPEJRp+T8?_k^0oJn z`W}TYNT+t(`+I_=8EcB3klkph)q*TTmavEPLyuxJiXMklk*gg+&i%9Dr1-_}?K>kv z%~TN_9SluW4ZIN&xTHn90W`<0{QHFG%zBO@-*d1vsWsHGoO^2VFy-Z&EQi1^gTgx| zQ}1%)vWf-sl5C4^Z`m@|QO-^B7wpuq+s=wBNI2Ykt2;fneYbuSez=`2!?w#$JxZ0F zmh}#=xe*?$x^0vfHcF(nr(OW0o?9Ul+dkyx+fO1XjRLf-9-#^(}$< zjXU3BG}`wDG-Pb^S5}6GhaQR?`&6H{JJ*z$XA8PohCO6__(k~M<1!y%iD+C7C@xe& zXr^-7cb-jXa>0c(9h)SQ_ig^?+++k#iW?_b2P)upk`~VQdylSD4AK1FU_x+&3WV|M zld8ltr^dXrp{cGrDu%KWtK+sxY1bA!Zb?)LZ3z7dB)}nH2G&479Hr6nB-q!4omQFn z)br=HxwJ^U6ff#|4$joE0)f|1^up%g5|ag=zk$3aE9WY1Y(rG(p~Vd@sh>w_81&0q z&PC1Tf`3>V6tZ`t(WlE?hY$)_jzIgJgA<>jF5NC@$(_lWx45v-vf(Eo z2lrUy%=5Exd=_8u+EJWgnWQ7qMGK}|7`eRlSVDK8O??a)iw46+Lov3>I7k5erL(D` zcbJ5(K#7`BiG}qAh6NTY1M|d}4p>&ss%piP@2>kM24_~!lJOUQ$^JZGR7t&G;d@w- zv!0lz&6|gy>;SqH0ft4YyThPz@^r}lcql3dx3nuUxk2R#v;ed3s!i>+i!8spe{79; zI2j4-wB2bF_PJb;KRfaAJ0o^q9WfEa1)8k)_8cj6qDosg99Wt!qGAl5uc^*AZY)14GscDaHm11x$jjPD5)`4Kky0NtL^I37;N-BsJjYE&Q*-E8p|KI50wMQJE^< zlK;6=gI9;=vbl3;yn5(nnQ5c*Ga{@UV6y;khOq~EI97|Wcys;w<0X0MI_LAa<3-{y zlnga4msTx}R#QWWA-0>LHZKDhAQ+%YByt9%2sYzWqzmTFfl|9Q>G4)8cQdHT$2U2a zT-Vd6F;!ig6scRh9lhzF`Z=0Q37Cp+j(mye5kKobUGwmBB0h3`2AEglve=&qt45$r zjn*INv-gq_-L5F)JXRBPsl0<|PQ&Dhs{c8vvs{hW;f&B$kbg5dqxN8xIoO%`6`%32 zbvfIL-pooR{jkrda{kl889)KQw!(2T&0##C)*2d2%aM^`!oRe)pd@2$@7BV?{=j+H zkfBc@GkBI@=@qFp_nzJ(d-pDbRV5L+xVB@-${0@_#n}frm%+HWarm=fAlqxij)biu|HA#koA)2SlDNZ)QF;ap zPrCU-CdFOU{?F#`Pqv`srA2yqQhM?8NVA1cH8z1$<(zgox+*IRwPO*3>XTh6z;L2B z=_{drP+(d3c%)wdeD}?pwcpf|VXVt$ApWT;3&E0s;a1Ge6d(mO zjvZ{u)GnV%?a-cz_rl1SLa5zJ{Xfcc5FdX8I`?B;dRlQzI8|z*R@gGB?QPBgU`E^- zk$&$+FcPwbS8o#K)z_9aBpwDN=1=ipnlsc(c{atnuWcRjtmry~*kmG*1EUkF30BK2 zkZH;W;s~DD*^~&n4gt0|*L+8LC>04lq@E6c)G7Ab=20-X`1UHp^rFlU*fsQJqWLlQ z#~rDS<|e5&%9@?~4T*tE-|SDm+usb$fA76wLp?|z@H!WN=K7tv*QfihgLH3O<5aa2 z4`%Atyx)5tFWs*ofTGJG7TkHtPp;8pH|SD3F3nS%l%JbVdExmGWE9-$X17?oY!*CL z@i?`l%foPF+)r<00CzT&4|eyO{%0do#lD{5V7~O~v9?Aw#;C)pnzfG>OFsuW&iP8; z1EyFB)=LEp0>GHUv<;Z2++r26^6vM(_D|lR+BYg|Rh7d6+cUbC7XU~eVI3>mL2k%@ z2Eq=^%Z9?fXl30~QW%5(y0J{*fYsj6^zZ)m%U4r~up8UYpEEv{6nM^GsVynn2m+;_aJ|!{#!f*j!p&!d~q0tbUhCV5?hp-!P@j zI+hyn*q9tMeUBQ#3s*}f!ktOssAQb0FU`;Ytez}-8Et=1XKTL%S#rfHWcS46dtZku zXOMJ0d?vA}44Ij4&_-sGbk>Bmq0o0($Fv(N=A~ahkwtgwJdU%3hwxqSIV#N{+@?=A zK!)~}@4tCNf!*!Cw*7Mz$xvoYc#f{Dp4Qihn+-i#uWIl1JHNfBr1-~@l^j5LTvbw< z3i)*%KaqoiNpiM#RGWjQDV5IpRpN*wXF^p)!ng}e#AV%+g`w7(G?wcLb9-v|rzlA? za4QLv#!XCLpT-bY$}`g3Vq=l%y?AvcbK;ATWS*|>PNWI*Cs;f}?wn9o&SR&UCw+p? z912jMQ1+rj`>BT=F8VU*Okn!bpio7rj&Lh9NNX|v!f@!efr)g4;L2>gL!Rz?<2mXd z{=)F*u&4VRrFF4}*MtaOza$VvTi|e#;W#;88#X{4p}8uycKTB9w)ZV4^V_of3C~Cw zjL@>;QNNWNJqvNs@eJW$Dgd4+AwP08!$ ztjx*mP8Wb?9qKf;q!*%W4Ee@wxT86TTvxy&F0gdKG72!)}*7K#; zZnFH2vM{Uz3;?#Qh1cE@{@38f<@1eQ^6czn>08awq^ic~thiXP1xynL>_F7GZ0mEaS5MjQcU}5dT2U)cvYQp!)CSl66Te}UX$Iybz8yB!` z>pe$TOg3i1gm12&UlAD?sC^chT`0)MN!=fV7!?H;pNMK=lHI;OThAaTOZH96*mpOO98DHPjGZhX<{@yU+;>Cnjr$LZw)ODj*6vm2fbyPoaWAJ+z^ z+VX9i%-7Eu2d1oi^5>_|bo}Zm_+}A!Aaky$RSB94vlp>2Ghjfy!~O6N;fFSSv*_iq zT*;t9f!&Iua7T_X36`#_>T_SY!b^O`g74BAVcBjQIWg4-ht1I7IVui zj4T+h$Nv-%7z0JpTi9eN>0@)!I~3s+l1cYHUBiu5Iu(*0893%CuYLLs@?G)&ZNqUS z!nAE%?BysO0Z75HT2NR39vLpKjr0qsgQ%cU!5zMzHq?J-nh& z-Rf$aXNGy>HPC|)-cMxf0MWu100(M*TX9{($#*+{NR`LE>#8IQNbyLh`Qmxi();}6 zA-1~k z_blwaW?6#zT@iVEW%m!uhV#GM+&>)cy%yka@3WN@B(1Rn?cjvB3a)uh9TGP4TJ`rv z%?8Cs)3b8`3(HoreSTy=t!L?ic8I|XzPyS3=*}0%W-I0m)PgRF6R!e8Zpe3g#$z1s zrzpUIgR@!&42x#leJ`NY8{%oN02lp=z^R&%KMl@uJCpwQPgK1Rs-4A4(a(?63k3}_VxrtI4vr#}kuqN^u3!#@k{or!*Bg`cnMI zy7BE_Nhko0{%0P80>8cK#~4wmk9dUIMnwvPZslIMO99#dAMryNRot3NxocB*g=J|x zV(*ai^oQx-=p}n~LxrBh{E^MixC`P{FM=&cl)z_uqz@l|i^~2Cb{rx7_^zoenxkl+ zotT7J9OncK*o|bY;ywStZB)YmA94#K%Vo?ykOEB4Xg^?K2`x93&(FViXKC5-I$q)4SKzTNxU%vqJ_E+?b8{p1k3U=SyUcGN z1Rr>z`vFf#k#9PLi?t}VnFli{J9o_!sdMni;@ zZKD@pjf53Cl4A1RR;%XCXoqFNUcn?f(}^dauJ&X^?sU7>J3UI0r{i(R=r6*}$|ElU zo4C4j#{Ds$fOTqgQx2bx2zhRi8$CQs2N(SmvVSdnOkwo)XTI&`Q zxI-@N87S>}t>c?2UFW1`4G7t{g2@Fse4?Kx z%`jQ3+g+jiJD#UDDNniVg{vpa@l|4pwOb!KKP?`W^?b1RVfUhTzpJx(YPbDzC6M33 z^J@uyV&VF`e4F5MsqJ2Q`NbkPjz5S60lFIQSD=1%B{)awH`Kbr)flG4M{Umq`9day zWJi2>?h&z}eYHyRQbZwWmjnz)8~a_bq+n&+`y_sG`%=y8LL6geDGBmS^Vz48XL+K} z%+>;)Ju?LN<~EcQ+8=emB_>uV>?JaU8vsAUV+%nJWEF>U;`&VA8nd%=s2&*cZ59 zuBqp+VK$kVbg-iBIT<-i*`q%-ZClU4NgF}gLBaoh+w4Ggf71T-&sPL*rbdeWw$QjA z-Y7YI3A6`Y5FO@x&=Tn9WTKkTwjaNQ9L8#Y?O9W-c$Gc$Z290C+o9>)^HV1t%J!O5vTjQ-F<~qqKMPKc2gPGH0XhjFD8K z++_6KV05UPJqW9uA)s_V#=14pUG7|r@8x^B$=Qxy`(6$Z@GX$Zxrcu|=Gi@Hp_sQ> z9TPUHroX>Y5wcDuD++fg{7nS=LC^9uItSXE8732t#Rx8LS^AF^SXbh^X(-Dq45kc= zZ@Q8gX|F{nODBi+&ljXuOsH&+zk2?v)}r24gIK$uEHjLu28A)mu+9vx-PQgZu@jV0 z&7lcy=)nuW-TOHe1O&4n_EDZa9XhxTe)Zf9XPUVVasbKsb61<_@zx>=+elU{)&v{7 zbl9K7xPeST>EQAfe~Y)B)0}gvKD~`Hwprn#^6SMfZ_t#=E}$%qj3F0VC=P=zfu^C< z%lvl>&SF12THy{R74G-(+De)#1qz+*^JYaIip=L-b8|{aNExbg();eS4!f`0Ybr!{ zWnM%0w>);~E#i#ZiX%z609Fc7#e-5m&Ffy#!8`w z(3@tWGeH~oOe^WV1~RILEX3Wj!58|)7=p;V%WQ3Jk;QoNMlp|;r0-TJJJ~m(8E8;jT8UYWxYsa8NnfGuuYoyZaSj_O=W?Td7R{eT2#cKPY zHL#^6vggflkXzJ}fQ5iu$VYcQ-M?=5*InPC!5{Yn8!=|2sBx1LY!!LKhbN_;mM`K8 z7+YT3trg#U_g;2Er0THaU8cmbg@of9m^yrA;`-2CN7u~J>V=Wbg*TB;!!FvQ|7B-Y zf}K4c3<~|Rvyva`Oe}&54j?MI^-v->v4;nkE`uj3FqJceKVIDrH(3-+mJ@t+?~|j~ z1)`hOhKBsmRi4X`na~&Z&x3Az%5!27G?_SL)UtPOP!h>S9)!oylk*!*lk) zh&%b9sQs+!qiv1TQmqc{$=&*0eOld1G96Fyn#mO+a}mL;`9R84wfv}S(eu}P{*}wZ zunF>hyLwAQ`C;=!<4c%(nQwYlP9$7@=w8V z)cJPYz`nN7-)HY~qW+a?>XL-_*pbuF59Y)fZ<^gn(V+et&UOhfYr#L|p4)_4!G+$@ zXTMR~5h5ypu~YRGk$0vWsE-)SjMHahW0S{)ao3uBc*2Lx|7O?p#DjtB1wc_rJ_ej= zVN@#vRQNg6ADRAiThl|>0WuSL*Vz3$?$Ki>HeA+V{# z#{qE3Pju^Ck;k`$*)}cS2j!SejNTh7tLbC+t^HbVXH|M$@On8$HvDQlUZ+kZ-hxrM zyXy0UAtTg}#{*es4o`N)jXw1)*)8PLXjk7$wH;J9B^u&PK`6bfnng);ELi)qRtb?8DRr7N5p+p2+&w+<8HBw^B!; zOtmUG^2UpavSz~vO+TY-C^%b5X>=ubM$C~yNI1hB%hcXYj5{zLQC^_)8tdg0j~~1@ zE!Do3S`FBY;tFT-?Y)<5vL=>D%o5R0vpG}-_=94%&_V`ck$~*?S1|td_2CWTNt<G(Gn?9cmT%LoSCVbe)?~&B(Q12j^1RIDh#cr)jW+bq5ySG){j4g?|BJCew<~&B3a>_RXnR8G?+$I{t?!uZT%Wj#ROXkG9|KA zv14cn3YOB2S~13vjdr`Lh(_;NWSAxf9lyDIZH3E3sW5_cZ@NiXFN%lR=75eT!V|xS z%SQ0JRY&IS>OI25g+j{h*FdL+zyfWnu-T-WZ=*cc+_AHYw{GQE@Y?JX_ouwbugM-R zFkEzq?%X%I*&Dj^Uccl5$aQw?`FEfp0ft>X-}n=f#ytO|fD6hEyA!oTl1*M9yjYFR z0lE4E@`#$=$2J+nvdT?WDRTqP+@K$ZPRb2H?bbCk=N?%H`KSXAE59RU6^za?-@M_% zy-K?VLIT!sSkn-8C+cLjh2x~~P8RWW+f}uP+Oo^CV-7y)2y0fGTzaMTn#%jkH1*~w zXui1H1HY<|zpo~M4fny7t{Iy?XM(y1d7r*?YH)q?zRSaoTF*7*iQmIlBo+o$sSm<_ zTzTo#(Q{9PD*xy1m9i7#%=V6!&gS`+gmiq_0@vAz^=2>l&~(@RMWL~;R3&%Eb7!$Nv(`#W5rM1d5e_OMjPzb7Lb69!*>)N8ekgda#z-NNl z0Z!tWnOM=W3>Dw#Z%b=@N$oXRJW?5j!PY>q*Kqe^(?hsdQ+b4`b2>XYLoW44HJeph)ta6~5b`fDW6r2UlcjMYu(NFNDy2hGsRDf%!9^bMG2hbG}Qxtd*b*T+ose2VdHo`laXv;pd+;co@5u4g2r zg1>eeSd5icK6=Oa!d9iO%2TnOp_<|m+O_yYRb{iiscoYoy;MOKVos^zF8G{)ZIaM07x-efXP%{?3XWl=t(K z!sbl}BFO3@7B4@G;tb(^UIQV%q5$||XfRBxi z8|9B!B>1eE4Y^K07>smXu<{pXjfSoaJdqZNJ4)2rww=}Rn#eoNs<3JtE5E1!mtXPn z^DhQk=Eo}R??aFEK64!RakTx6bqL_G_Z%BzdiBB)*y?b&>e|2}TWg{w%8*4& z`u_2cyXK?5$HTr~NoDq$kbSeg&s>$HcdL3RZ<~FU^4vM={V-tmH1@sM`2usO{EXh@ zE0UsFiK%_{!)C^Mn9j+;`_oaMZ%RJgtBkANv?Qw{(pw2VXK$OGdwJ&%YWj6(;_JW* z=$6Bat8dQDpS-pNt!^zKTBPt_3e*|pD_M-|AKX2b`kY$W{205$!Qf%L*%2^I&i`rN z85=mP&ZvdRs~nYxKX^06ocDDt*PXP?aqeT~yrN!_`_^|%pr>Z^_OcYMb=B{v{g?~j zS{_T7S^stijmbPHOaO`z6fhX(=f}hu%AI1O{1&FbfNljc@aO=hV0xI5CJ+VaE4}s| z!6R;u&iA$-=-;Ka&YJ`&2{CVWtY$*iI8bTdTa$%1Ca5#pG1n526@*~Z5}j@nresqbBjkG%dq>fyRBmHM=TR2yIwBZm1s{x;n;uIaKL{^Am~b2ZRhKe@Pb2*y++`w`dL+~ zA9cPyQaKQRDryGsS-VuP4+gWBsZa3KPgxW9D2u!czT_4@`vZ$ zrD~%m!y)ga&cCZkA`kEp&Hy0=p}8nb9s;ghWH`%<`WP)2fJRj6 zoqbVq!=!9zW=wg;4m?>qYgRMf@Pn;ud{59y_*Vi@Phe8(S*=#Ge;CoNpk~_qNk?JjJxIx9>L1?v; z`b~N);+e6D-qG^|^UsObqer1lZO7!p?5&JY2G|S1$4_V`QIT*XL#=A3(JNIKx~|!m zsvXnb|2&xT#$6}u*3F`=TKmHn2^Gk@t7T6i&V4s_V#*`RHFn3Qw%I_TGQg?s~LoF2+}E*Evo%v~MU z>3@Ma(wQDPSzSA^J78)#J)SycqrGzp+cVDJ$RGPk!gUm2?u-w2eNT7eTP1_9``}4^ z5Cw}pQoDwtk23dtH+g*fCo){JBAI`e7XOfNj-bjrQ3o$v*;MpCOR#9CUHN7N?O|U$ zrfESZbeE7pDkv1j#$&jk552>syASE4x2T}9kk!YMNf?d9N$<~&0oL`ujVwvH|B@2; zQKLW6O2aQmgB&XiGL{5yX(qDU(P$v5Q7C{znT9k~Ovf&w*#l@4(V<-ZH)!*>#X@-c zqt*sotvY(02_AFH?d%%pBNtXk;1GefGQ|nsFS1$n>s_&fXD&@S1>T=5 zcD}8HjPrO`effaAWkQHC=&kr?+|OG4smdi_KX8 zsJHj#vD|nJeJM}Jj(On5Oc|kJFp4CA+!E*|NPkiE}GKp95IE0E%2MZ@vRbjjDA)1#g-;LN;lu&ciC+mL_E z=>uByrrM1fzwa1X?R$FS)~?Lv>NaVT>;d5XoLWz_uYp}i(F+Qv3^p!NTqP)J@5KeM1BANiEDgC~ z^%JX$x1lpZA@mCLi&)XJciM(cqO0_h0p|JYM9+-L&+-Stot@7ajB1+>@4zC#( zOE2#Wz0EQ~;)bOVxF<0CIy?PESY3+8x0f|{l8dxE9QY5*ZEks&yJ>~lZl&0bknt?d zbdE}|(#JN3c0PHR8s4ydtAW0obLwz%cl^9nm^V=L^e`H5zkHm~<8?tB=e1MvIvg$B zV%hw5|E|y6-DN;%;JOWCJvoj%S%_qgpu2yv88_>32)OTe@9FLro*iBx=)_;ERs|R| z%g$ZWetjI!2 zk_czp`2`1L$}K_EN|;qZwLz0t)AM8I9d{~|G>2^b$2BGm;wJi3VYPQUZR_5-PV=GX!|K?KovP%5c^`4zX%3w(-3D3|P58(#Ckosh z6l&wVuJs!1$>v_u5U#j4LJd7wL0DT&SZyvx9vV9 zc}Y1Io|2=6)7{hM{rT6g*ZEHOB2PzhfV!il?6sz@#lx~!HhVf6QWhCJ)1#eTHcwf{ zKBr7V&g}9FoDy8@4okxZ3o>uo81FO3=rhguEYxkj7wLLtqq&G<)ytv5c|qczbV!w~ zpR4$jZz^jqoGQTAO4Kpt z0kIqx_OQVyAyT1~KoAgqT~dOs<5kbcH@B>>%Qc3h^lfZxK3zRJ-0)Eck&p9UT$D`? za>$}#eGnWEqVUAs8lJe9;)kUE{`s>$d8>8wkoH2&d+pp%@`Ye=3Lh8q{l$(|Hc)% zXh;MqW@F}gipBN~u6%l-bHRAnob%4q6Vebm-A%@Vwr4Wh3?70y4Xv;E$A?6cwkR6G zp6RhtD@wff7L4{U4yDRe=Joj}JUTzJ@d!#_x)Pb4+D|r`8N$p)Zy1Y2IB-1Uy@&Tn z5B+%Cku7_k!42^a$j%u*;ZD2J?Or)LjZYL-oddPd-`n0n+> zMq{_88}5iGhdeGCqbTwRDz{b(3e9k`RU0=P1NNP&@^-gfut9ef7)rx$Jl76%`0a*N zLCL-`QN*4`+CB(BE(mm& z0yg%Qr`+(xjym;yY?J2So+#{}VSCwD)jZ(;V2MFLE6YbNNeQjByjG|^9Eg++bgsBJ z6v(QtL0s&$FYY-L!qc3O^S+6eW%+xhe>>-Yel>YZ5J`UtDD(MqI^)y83pBS=BgEnA zXEUECwR+wTG^W}%L%?ogVDsd-pt`!c=?BqWU-Y}4CzFyoA&Zr}Ztq?a)5YJDy%(jO z%Y;=MRnf2o#p&HE=GgwOj;-q?f1tj5V(keW)Gs`KNz^#9?vM;K{E_lUYQEe=SW{-H zI+PqHjvw`_1ihQE=z3Xqv+;($XTT$DXbp&yYP9pZKQ88`>(q6Yg@tmn`ms+vu{SUs zA1QPVvh0egnwxF%lkU2;eQ6Flc|BZw%J1$$^SZ%sU5hbKku7+TBQwQ?e?rW5E=gEF zEBo`0k97bUmw%sS=w@}y@!_tL!J~mki-M1`{|Rh=X*B*74%N;8dFuuL^daP*Q&kd0 zBrCaD#>JrA9GXi{T4>h_52js+zP%oW;1q&+6};=JHhMs-i+)dfrJ0>`&5QZ>AjiTP-stX(*s^t9vd;9fsCW6tmie|hk^`r4|TW2!rwQ1I>d8D^?RvsA-pTl>VT(D z^M;wHCcll0WFIs4MA?em7;>{{AO&j94tsvH&`aV{5X_`Y* zWK9EWj9zT{H;1ZC-Rbi95$Un@geNTNc)Yq_x4`h+VR)h0*7wiR?-TyYz5aEA{{2nk z6M~-+x3V$#>$rg-#cvmum(OB}W^>V@e9(JHDwFtj758ZAY~)tPqE)S9)yI8pqDv6^ z9`~N*_rAwVG%vzlAS+u2V#KVizid+*?M@TRzl~g9D`4WzRBxK*f}p6`#2<+2nshZd z%(g=hXowUa5i|aIT}1N$GRIBSs-3d zKG+r-kwM%UMVs-W;#rtrv9ZnL#)>}LMQNAi5z|5ErJ*(#l{N*IzfSj`Ug-DtCe;LA zG|^fn_16~>gJD--$)km)@|8*m59L+5?Wn9xDLA&Vu9cQ6gpV)#j?jIBTbj1L#2_&E zLyG5W)d)j+pjqxRuZpVH(h^yHo%q@lPN!>=I^$#0W#4SmKbNxIq+k#THXf_=La3+R z6$2C+kIiR&fx<-L8V_Ds^M$usS7WK;X|~hrQbB+%`$3COzSWjVIt{iHNfrV6omqIF z-ZL;**|Bx?#F(BFf(2iMJ)YJE@)1+wdAjblF9NaivI-U%U?iL@Lh7uFaGSKFde8ip zG%M@;)d6{hc?r$gAJ>7jk&%U&Wu`XK$u;cB=SDIh8=_*nWFnC)<4l$Ry>GbupCtPq zJO;cZ6CVO3^WpGasr!>Iar^n<@LvEXbA^x&aKV)`$G}*j?t3VrKh#|S8#hX?uIiGAJ^H=Z~(Hhq1~){Ns3SCcx<3oJqQbjA={ znVy}^(+UTxE;@I6fmt022<3+0yLwL-Lk#Y?sIdSV#T;fVz&+MFERS54aQ^XvFiX0d z3o0l|>X?FD>8STUoH1+>17jhaf?yjc%|lfcP>^C6Lm&|d*?Mw(D9?&(JR1#-b>PcY z&jGsE09pNgn$SY~<*R_4r!DrkoX68D>1rT$^sn#z-yY~v1N2jJh0|78&5rILjQaK_ zf{eM)spB^GIhg8f%tf=eEXq+)?A@hE4-rOHA)q&-(Clk*vi;=B>^n`E4mXz6jCwQy z&VTZQs2D;GSnT+L<4GQB zTr*$$A|j88-tC*wG7!a;Sc=kl_LO>l0HueZM6^5vGdH`!-8|9q0-es+-x!K%8d{$35CsYu{m03X-dzFDOiB z;uU@SrQn-h-}DT5yQu;T8PNXWtQN%ZqeKS&sYP}N-g&89YIB&yv14Km-(s=vVPVMdCEb@BT zN<`+_#Bdz0uYf;!9+rezeJ7ACA;x&+Z{_)aT8>~ZY=Ro07VY(9@Wx+P*8+yo^xitx z1OldKK`8yzX)14`-}OdBP}v9FZKsj!RmY{qN`0`BX+jAsk)2%~s}K&L&mcnjh0e*u zqRi4XgOPQEWToulPc9BAA)I3*^kC>rSCP8fm@wtCo%;kKYCIEh015Q%9!tloX<+by z0~PAAGtke2$wjP?cGCmYa|J;EP-Qlnh~vV(UVIzRBq(_PA4vMI34Xu%k}yD=T(abr zTlUuymQaK?3RvZfuc`UC`dt&V8;WxVV1``%x0joG?Uq>?WsvA>bVv|OCVj- zZrCtVD;ND4LbufaGE`8ixrb~wk zoNxdHoU)S~a}+RYJ0J#vy$dP?nzRibOydgyA61U?$XRU*DRG z^O6v#vKJ8{r{=J?K8<->35+*73ZK<(62orG9^D4k$V;3Qh$-RK2L=Z-8de>8m4HByK6Xgv(>M6@5J6({amCt}S1qr4OmU+a#O0&xc<-im*+Tv8#OVNCa}dURc8q1#k^IXA=f5F6jVN0)J6v|0?Y8AvS&Cc6xhHfxt(ota$%lq5J1VBd)`kT zlI!i^>Ddx;hLrgvi$)2VhhK9uF=?D|u?Cn`dYOzvm0TH2KI(DP?w{6=|M)>mg8U{I zKBt&xzWhT@HYRiWDHDsF2_OM;0K+<1r5fJfUn`kUSt^yQfAIPCb!iRT43Y#s2S_^k zI3K3dZRe}H=X9GLmi4&9~W!^!Ix=^8!inh2ty%?^(yR)M4e!UikjF$9FaiX zxI;1G(%6?T@F|+YInRD*?>ja|3Q!5!qmF9?aVacV9-t0QJji}wJfM1T!*ee7uAF9* zXaR6qUmOQCyW1Wg{M`A#6*=-!(BP~oJe@Bq1{AV|`|s%ppeW`97}8~NW9$4sx$38L zATT4@6l(qdK0}?dvZdDYu(omilbPMa42J7|gF15vq)n`#}`I5UipnEJxN#x9!Da66W6q zH0E+@hPi>V&$0^Sh#K_HzOn*a(byu2O^(TjB6b%Z`Oq-EB9bFZw%n^x6m6P9G-m^; zOh93JS=sdyV|rDUShw>V``b?c2FU+2^#XqW2@M?EPlH@< zTz)HhgBvB0DCQ`jiB&?8#_qk{2aV`&@8nZ?fXx9{L;#ht0G&2qXs)5AxC%9?S;8$ncTkC6FD{z)EY~OFANI{K49xqoa8g?5eASnoB~I*I#x;KQuSvr0Dngwgr$U z^zvwj?`rQU7^+wHHl(K>_6^rv@VYgQ&UxB|SYzn++t^NqbhQN{8zfD@*}d0;YAbnKGP#xoRa%)r%YI z_h99U_O7gw%E#DX9GXN_zqF!4$*%%HyIFM0Qr-topnTBf=1BZ1P$EvB$RJNsHoVM# zDloXfM}tCRZ$WV6C#&kO#4P|xHp@ZM(vKg-a%nKo#elnL?Q;$VjcMt*xhhsNZ=Woe z>i>!D{};f;s{$Wg?YvR`Z(S<^*`q;FiX2g)$5ZuEtgJA&Cgwq?`JdPX6c0caT`;gk4b)>WG)#Mi$gKDqS#~gaoWcA*9Vz7?XXl z9F={FLidd&l_e%Vq>d;b0b1p40U>=K!zkK7qO9T;l*8KEy4ea;LB^7qK>HNP_l$vb8P~9#$^#o;>Sl-X zEf_^20-k`uUO+r!f~SC=(m3P*=et&w2uUY*zV%ixZv?xP^^rFcEvJda;~JDsQZU(# znIKb$uVp2A{gndz{pMi&AK(3dFUBWD!mVg~^VXa8HweM%EBpD$@X8X@BTc8@3Q_ng zV%JM6Jnc6PyoVOeLUy{!%1h6a@mm|}X)OU7JX(Ez_f&e<&{aFeJAm&My_i=STfrYk zv8t_wL4vk~f3B1T@PmnUv@ucYBtg*f`}uNF3|gdRfICj?o0{T~H3riK3t}=FKZAnE zTj44uvX|oLU?!JR05sNMBBmW6U|4xcfgxBQQ>00Q-M^WtCvYHUhESjroyG5ICmi@U z@RQGTE6`^g;90TnsA3yrj*mZ8+z;Qm``5Jp09*w3XCh5NUD6!hD>Z*38VUquhTVXb zDu|+lHvw(**)I~Vc5e2YI8r$ZX=+fw@&q7=T|^asRm5QoZv<;F25WcTKs5*Rs6{Zg0OvtT!A5jWO^-pi&~D~ z@G;Y-NWd+~qVt}F+Uk|9@K^u!GZI*PfJgj3t2HbQ6psmJZ#;X!&j~Vguuabsr9w^t zN)Q#fRO>hw`t#>cMf)u;>9rXwmWfC6<2G$5xv=PE80+V`AI-0@Kd+0-%U#396U~!? z;oEXbj~ZPb7Qd1)%n6ppY$!{ul2Ntr7FpZdNBUiEGVNzU)Lx_~pEhX{#Zllof(4+g zbQf>B5j$1lUDEtE&YqBH4O~$0+XDHL28ZvB;n(~cVu7a3(JtWzR*+CP$5HrnV#`!J z;0b4rfOM~e{N(1|q2|AW)PHbnzJ#>Yx5Lo$cM~ztLWV<;ug>=S{mJ@UGKo!z>?qOg zxqv(>EYyIctN#sa6Hznq_&L242R`1*{cft^mtz#+Tx^#DxH{`VvS7IoC3bgirl>RE zY;tWD?leUW4UJ%am>D3|5#M=@zueWw@)~ia$=pqo_B6UY-wNn$0a!KEqt>Z*pvQQ| zJ{5o;hCq-Imy2rK2hAq}s#(gaYD6(=Fz^yZU*P`_YaMX|SnEh~b=2l>ng$0$S7&=s zK=KatW1m++Yw_lxl>JOn-@W5kAP%O)xS-HQ0EZ2Yzi=5M@9~;TJ+-?X!~&`Vd*x=3 z^2T)`BlOCw?`&6FGUuW(Z&6-yCg-q_S*VZ@Ab7{lv52sIILZAx3&2i++UI-AKFAWr z_soQvi%jt0?E42NS}j*Jnj0dH?#qwjYs5-0G;5Kqfz8M zAuqo3-&(2o`(*zI(FQjz0W9Z+$A!e-{j$H(YNw|}W@NawU?fZz=!xeV=PNL*GRx3F zo(HKj0QaN>7|4mKXl%o+8M{pfLQ(I5q5!BjX}lAJJtK8ML-15;$S7@JL=Ngfpgcq! zp3!W|OeGjB1S7K@D;EUF-dyEXA!xMnAyTVNO)T9y=)XSRCjmnE$(v0Z`gdq*%%DXC zlEO);!8D?pFcV|IR+{g<$ALj~gy^gsgNpPGU{K?_6kY>)4J1Uc@L344wZ}=!72;@! z`Z;n{jUQTww1&mxPZ-pcEkdSC?*pj1p^XB2=Yd=w<48* zxnI8ie>}LqVg@@QX0UU3tyKU0D2+#4QT>64X9)Z=k~V;R#nK2WMdRq%HoH{tKFq!&=I z1l7ibPy^uI0M}PdGvR58qNk^4rQSLl@p6)gefu>9MnEt^RRmFI$bjn?nFU6xBdhfA zQE90^NjQY^O_;D|MUO~GNH#p{oaWV!sCs~SL`CQfq|j2#MUw|HfZ;$z>&>7*!fpeGr4PP{DJ0ZkG9W6v zj6jmkr3e)wuGA|OpkffX)dnY0ItwYBUx>_7tqIJ*O`UJ(02Bd1I*PRWh*H!i|4WYm zXY^Da(x9Rscf?L}!ri11oB00oKgC1;K4`x#%O`EZ3G64ye)uO)5@O{8+MN9S@Ih#X zQlmGH=teHRGF&b-(W+A4u+HNP)MN|L^^Y?O8=oaUGn;WX?LzcT$D&7%AD0>mF=E#` zA6E=ruOP!qYh9#2i=<9x@AtxI$o+_nyYD0B<0<+UxHXbZYcH-{2fFSkO(6wv70t^P zDpr4nCH(u%{L5Jq=D+~&O-JSK(!Yoz7*<~uK_&?JMdczOz(60z?2uFt@d2g;EiNsE z`H3{G0n`tWrPjiTSApXgW7T6cd52Sa#|!6mgQc}KY9w_7o1r#r6OkwCx@zck6VtTzd{?mI$c-%`tWU!0b^D@oQRt9j%?%EVbI)Fq) z@8C`P0HGlcz+h_fdJe#la~mtGA_C#m2yoTo0?LeXnB*&cs3X>!((ha-Wx=a7FA@_I z$vAqr-=cuq`+YE1XIi_-{%jEWxK?~n=`|ouoaKS{`>cDm0*Q>exA$?LS$6yX?`(Pz z&gPMM2E)Jq5ujM-W(47e&;hjI0Z$JPIfU#F$T$hqjSk#lMdSea32e)C+25RtSLdT) z6~dG>9s~6U3uJ+^5JMhI#aS}Jw>}>_2K~NW>H~PBj`$wYn}~R1_}LD}(&j6`ZI^F= z`$+sd>VU<8HyXa~Iqh0*+Hz*B&a(pfcBIn5JeY4g>0EeeJuvp^pT6jy-^X7hRI*jo zyZ%rqgnK2)gF>(%!Di&3#Y)X5E-p`jZtpfRjWJYP)eJB*7@31Wb-TW=-Bbm)I24Tl z9E9yAJrx=>FKUMONWHQ}hG)lK#0?4qgV;;ww%mWI4C80)n%8E1AX<>vsgA{g?3Of8 zHhHoJ>>FYP$bv-3lhywpUsnPSb=$ooQ)5)dGE#O$8hcSH%NS%SWtp*zosw*kC0WWg z)*=-NVXR~9yRvT;63Q-nvX^}g|7S{XeQ)3Qf3Np-&3j!l%L0yRP7Dn3gXNO z0Y!)-c1%^}d(P5mTu4HlJIQ9pV|a!OU#8+-A!@VAT0X3i%AiVDbx1jqt$jQmgjg|CY(y11e74fq39^8u# zA|vELh7+c5#UjSfdgeFu7FzksBS3CfIrkp_2&{4zKD8L(U57f$`6i>k-0A&a}2J->7q1g;&%&w{oEJm zsWmCqbGPesB9=sw0*6<y*bdCO5!wWpOFgzo{D#RpA;5gbU0+ulI)wx5P_#{G?0 z3@kFPfF61VF3%Z)DiMvSI-dniVwdff1(Oiq87Cmrw#*r+M*Tj#RY-fG6O4`l#G*9-F;*00{kJ zC7cVMIftF1I?M3ko?QlAZ_Ih8MskL(ouwbRbrDs2izhjNYj*#%?6t6vO`js8rr%-b z$0PlR+p2P*#*C{jxag&=|5>3m=b@mS0usW4QIu?zJAezrmr-`*An%}@Px2l*P2rZp zB_IJnZ(%_}-6^Pm4*OY}5BNt&-&0YKJTVM6-p2$EN%h6EmGBG|q4vmR-gq?(`q3;N zeUj`pdQBI_DTylZT%+QmgwR0}=s%>-0sUKVh}!kB#&FRPJ`<8=3@0gmL~LOuzva+5 zY^yUBmtDORH=ADXoB0F-=ykgk3HLQSRt75J%VxTrfh_ePovR^un>F7SXc3jeRDVx8plVTO@p{CW43&j@>FuR(rJR#E z3eS1dYzh!mF1U50p`KEm!fW+-ffD5&@0IaSvJ~1>oh_%RCg~`K4#~1aUhGSG)yiAP zICFs#wi4c0!6jmRH2los^R4=3Zx6JNSM9#V+A(l@3zs~~!b=Bo&rUvO55t$M0=!n0 z7BV)9RF7kj@XA)L6@G*-e*wc;SP0Fg+^|k8ND*0u;4e9k5*|Y3?RaD*p8%8`Z(<~& z_5aloxYcZcpT}%MEjE9jdl6b{&TA;BC(T}pWgs2$f3$}Va)=>-O9|oSwwH1*<%YX| zAH~Q4DmsAWia_Fn4~9_ssJ!tzZi*s$?%n6*{^15E#$|hbT#mKs&gRPO=?|)x3v;-s zrQi=@q})1{UU+r;c%Y3@eHzF|V)7ZD`49+~68&|~3}YirB;1!v*O zx)#W!A<#hm65$*dCH# zPm20<6n-53`OOh8W2tI4)c?d_H5({pT^=hqxiELP`c+oO?v~n))_4D;aND z)5t<7>0)^8ZliR(rfUnMwKH|1&!!9NrgVNxS?j->GGHKWDY>Pn`da3bP2n`Z3eTM$ zzLg$S?njjhrI*Fl&rKg*rzy;h3%J^SCzVw*w-0f=? z(Z@1rUQ75^y)dhvACstlZsw~={f61(U96NF`hZ4ryTGwopOoM6@Na`hfoh8aH-Ydg z%K+~{bwD|9b9O)|sq6NDK{eD~dlI0mC&-)<8STkRdKz=Tlo{$qJ&IkTqngrXI!i^l zAz>sk2&9=DCVRQ5Uej4iF1$T994VqJL~G5U4)LbaM;f}%*DK+xr9YK9oi5TNvgJgD zE2Qgc6zS)ue%Fc2jq=OrICH2oBUtd=LrxWZ9%3U%%T81ww*}AHZ+OAuyK_TOS7WX; zD>vMh)3pjeN*41}Q`)lUys(gU@#gbg8O6wM(5@XTQW8RBT(CDg>P_#D3lErZY9F!T%9LzK8M zl<~+H3WYq@FB6r$Aslhe z=gD=D13fa#p{bm)p34BA_{SiJ4t`Vty<|>#JAmzE0R{1n{RxMGqabz9r0K)4lF;$t zzK$FJJD`K;4FeA2G6b8c`3K24g^nk0Hjj*sR7IhsGeO7XkXg& z%)yIsh_KQ`JF<3V=$gqa$;n(JcW|01>%m*+wsbn5guL+k?H>PiNWlN99V9zZpI1dE z|4-L>YKgXqG!;}r zYe=gaK2PxxgzFTfA#qK;qXk8aNW`KhaYlg=wL@p z1CPo{*jLgIzM899X39QUufWrEE^3DIuwKa#1*1e7!K@X%H!mnkKX%eB)=-~#MCP3y zZ4m~tIaRz)jD(YWzFE%>Jy1&4h`e3tgt_PM1APM@rwcif0Q=v99NKuiUR4wXd3ws@_VPzlCJ!jzwO^jK%Q!%>CEA>y5#)Dx;iS#E{%Az zDtTl(A!yU)@UvjJxg^GHS*UkH*PtL|^zL-|(B|w-w9*|iLbw=h>=#cl{MLees+5_% zbGVZ+%J05*rPMvU8yRQj>4GGt)ZD=PlKQJ6=p~+X%Yp$ z_$mGP4Lsxb8<845fRyf4^7mqR{p70jO_1c!sG|*D@E`uFX=jdlfP%q4al^4s9Tb`b z#q|orZ>UBqZw=p+;FZOQmK`}_bR+AeRdDfV$?Hm;LB&CxUDzB7MUFIA3SK=J@3V9%{-^RDNr)0)FQ~{W-I>SL7~=KPZcT zz5Xw#4n@U_2bvI!!%KbWKDhRy$7bC40)#-Y$lfpt&{enR@*vP*N(gdhF~=VDy$-+5 zX^cX7Uf63&*%U5N`~gVKmpGQcV&*y1WG?olT6^#osZWVd8;qx^Z8U0?oR16|ZJ*Sv z-XHcB$Z-!CHi&u`jTXtm7<{?NfFCBcY8Kt}oeU<~y3ojR4Gw=|~D;Y3*)+gMDPd;3OH|ro_i>@_1R-&t^If-u| z4>|?&3u)}3Us;~k@kl?IGun{0XEli+D6=Mlwq?8yq#Bl{{J(XvU>A*3$b4rC2Up?M zKX#Q|G~Nq8JrrOEcvv_r$#aKD6DlHiJAPtfBIoPZuUzA>x}#)>@&@8dQ6jCT#Nyoq zNt0uCUUtT%WLdwgKVqdnJ*m=pEie z2k2;eISt~FPMAF6B%b=FTI3CGh&^QTB2mJvDm70?uSh^1VSPsc{UESFw&_1Irhi#g z)iv^ii{y!ctme-L+b#z z+QXjAcw`z?4loHDvIdXZR!c(ZnOjN*xbunE#G6iO6(@Dxrm+&xyU;-j(q8qo$!&hc zBb29u%XycXr>m%1a8UbT?@RZWeK%cz`Z*skm3_deGF(AO+`>fE<=)1Pxs0tskxWAR z%vTsCOu?h&HH%wyGKU-qW)dXnKm3o`7yq&-dE?h)b@yxbqvDtU+#@l{01jeOCSb>6 zUdY@ZaCQBZV)9spUYqk%{Nsha`}fr`1qgL!8L)6u0{mr6VS?|75G*BH7k<@IFBLHp zcj{5LZ0pu~(vYV*xZ?e|xLTl3zsU5?x_AxDmy7YkeR5?I47a2kc{Hqtl8{vp3;T4! zE>S6t|HVnWYJjaRyn{->{Gt+X`!6Qv{{QfGkQ}}aDk|Ij8NQgq_SEeE-~gJq?S|1M z!Uqm(Va_9S9uLPU>d)r{TKkVFoxTlf^R*pbvz$dB`&LY%tcHM*ff8D42F}ejc^zWw zx3OiT=6&L-K82r0mG^j;?z5@yA0=DFo1ozD_xAhD%InxqwWnDKr=dVW(VI4e0jSAE{6sRdvuVSqMjP;yZvsDG42$7= zT;hG5CyF>Q-x={cZ~n_2r}&Y15> zS?TKxUtyc!7qE-asc?VEmE_4qNyiMX0G9Sef^tX5H|3pb$Cz`+qawrZ@3VaR?|3dL z;`Mpx?dfAJ{%MKTbBMvRyNlw3JQOlQApr|_g|Y;oi+5AxGg=&yKcKZfw3Yn$c$GC- zVrP9GXZf>v^`{G~3ZR0njp}=uQQqW#%$#srLXr&{=O4`TAvj6w#bNof%L%;m5aB?V z2H!`N{y}0Pqk9+g4XF-tW!Tv(oY9tg6O@t4mFDm!2+(td*6R_$Y1kjf`;6m$MLJe9+N#zd2SVR zpskro_!<1lBXBv)xe`p0;W?-P^VLI41)@*H)6<$RUN6J(JZW}e*=KeA0$lBp^pAEC z+Z@fmwE&TWR1C!=$o(bVkbIa8+JY9P5K7Sl= zt;ag9;V#PU8gAr6vJZNwsA}`OvI2lL6J;5c`}#iN$MCB|`qjY+k>-7J0Qwl@U@&b|+GOb%-wfSqWR6D|VN;EgVGe7E(zF0TBCZ~keI z#sl#9M9KtctQ+WGv?8n7#)pQ1cV%>xRKm}LJ}t!)RI#V;4kRUw-|SokQ^guHxhX#G zj<4w?`}|J!^Wyq{{9e$!I=5h9Y|Qz=!_m>vm(9}3Djm=fbwELKy8YOGb;!D@Ch{R% z^Qq+QYgA9r-K#VjXTvkgc3w4Q&GRA31Pv#zJvFor8weKp?V9c3r@H{q_zbzga)wQ?5c}s>#6bb^ z$|pNTE6+%V-((zum;#xQzw5a1%~yaob#E%$0r8<<7j zn^q7D0;~KDs?N9~`|RuF`wf2VhWRP-IbCQ|@B1^nriAa2vdIyhotipD#YnF6fhD}2 z_Bl%7X^wTzDLvp9Y?d=wPRcRZIVpecCY{WPlpx=A|4f802dJ;P;pk)6B;hgSEfz$6M_QO+IO4aP6v7p zq`Xf`BozG#b}-?45@4=lLmIM;p2b^AcAz^36bPwwSQ zmx2Wi%OqwrXcTB<hn;1T?NAyJ|~*)qCGLlS@@A$A~L`e)4kUo|_kP#Ahcbsm}(1 zL4@5v>^chstj^&2*wTAjujWkyo}tpUGEZsTC-)rsB0xOIO}_LDcP3g~{_q1ZGAN*p z4fG}`Je7hdinH;Ul_OV;fvP~p917~#HaEE9HjVx zY0`1oA(PJ5cKGb^hk=IH*lD6g>7PK9{943;dM@Mb=}~aaL*f%zRn>=xU?18dWqr|4 zFB5K`9}IJ)H-SvIE{?yG>a=|RGhnO%If|&X;qI8yUAMx-P(|=oX{7aK07^j@)u~X> zbBNQ{)?Uhz<&%}}25Rb~H)ZTd@x=#)pS$E@bR&zbd-C9doOyhM&a!ffuVIG4oxAzri5i!1%Z(m znf`T67Tt)I`9uRw-)Vn;ti~ zsE<5SW_E^p&D^nwKCH29Bk6+q!oufs!iHrz;DWtqoF@nm_#zIHy#4%$LaE!TEfGV= zONOahoKm8I6>hJ&s4K~OL1t4uj*dlk9NtQceHn?>lKj-FS$s`T(wAR)dq(|xhMGbl zrg)0v52STkMhnLHP-QbsBHFCkJYUh?G9+*hC6p6L&vt*&3$iUf? zYy;2auPllN->G}|T}JUG5r;=&8E;q)f5OsYk2fket$mJooigYDnv@!#^ZT#=e6^;7 zl7-^A!7nCBO_}(X3&6Da9uTm@2ha#Nbu$j~_x5_iiOLx{uFvy2;Gaj%5vIT++iA4C zf^u_3HSw@a*Ix6RHyc!vHHavJNIh^#a!sKi#`#O<;L%){kI(XW#(OYU1@!vAd-tyU z)AyKgEmF}+hPhKVXP9-U-l_3f)YA-!1Uoz$@$l7t<%sE`jRJEPGpBTcH<^Org%sHs zQ86(_Zv?54umI52AB#`k2KOr{3TgSRzK9 z_*;bI*Eobd&%IPqYoYyw* zX*%eIJ7r_$UztvuiKh$H34RqseVBKIKKc$M^DCpFGJfA)etR+}`|~jWI!Ruqx#Ioz z@7uTUGDV=i(2YQOZj5jHvmFV2y28y?X-lqz7K<${z2?&t4bS9(4ZtPDDXI9cG$(%! z{%1dKXvZ6_P8}G_v$3}JwWPDGCp0ozZq5TLE;=rbR!~N)I#D{iwzk$8G(Ezzn2#Kx z4(G)nUk#JUG`2tJ?d;&Kg3ayuWzH4R;C+VJYCa$h@Q14nM^Oo_<($Wi5ONE(k2K{dLZQHhAo#@=Vzs-l{Rg1aok2en$K*6R7 zYCrzw^=q?ZOej=m1cZhCMQQ;(Ah**sIXMX@s)fU(coHje$YMMo6Y2pWF(W%$7?Y(I z9#jj(1{l3j52nLbtu+~K(--Zm6j%0qY4;QV(yTH-O02*Yj@UJy&swh-ABkwZYxQVp z+ZzGHV$PJ!`WLh4-Y;Y$^0m}|XWicU@@%y8PHxLKnCKKu!cJ`RW2);qk8E?mjM#oX z+K-3qPV{7#Y~32l1*xD93 ztjc<`CXAF4Ke`0&^!%hm-EESQd%MjDzdtL8g~lC;~4`L);VOsV6_Hb%uQ z4}X~RkaG%(s_Z;!lBr#$Qh%|wi0P9_qYuI`E#W*z@wIa{Y-ur0w2uDp1~9y^Mn{ZS zO1ADVlPjiT%xER~?`Mo?C2iuQ%I01w(2DW76SkI)^t0suJePJ+RFS$;s@hM!{qyk{ zIxjv9K?INUAddOt?!SBgzPGVaWn#6rr{^Ysj|HW7zD4zVSlmu6Ev0cG-J;dVZ&&NkC^t`YfA@H{qUf$fP1n?m2`%kD;xbh{wQZH_d(oUaycX7<%laZO0-fD~ZhtAlBo_dmUrQ?sCSo;L`+Kj(nfyAc)ZnPvXg~et^UqO5d-J*edl+|L5+K4881*y^+KskwUG2gl2n!}xmVyQ%$Vik3Q3w|i3rk9M zDqw@0gWB(1OP=OZL*_i>GE;zK!is zFWgiEvFpi`C&T3$X^coUzRUKYgx-VV&oa~N=F+~}FaEX(- zUy(1A@lJ26eE$iiav0v9uju>E1#SLEItjxa$TEX~7H#}XBsNox=FzMDf|mBQxHYQ| zVMlS>K+6xVuiR?xRM?OD-DG2DKQ!JvcH0+uWq5~uP31o#T9rNZ%pt9b0h}zXKT**O z_E4_x)eg2#)f@4~>AD0hc>${IX~4GG+Q0YzwQHO?Hz=?~KBnNJSFeszGQxNtJbZ}9 z@+e`;xk(2INCe20dv4w*EF^+y#ctAF>N7-3M3l=1W^w64sbw{Xz>VbrixXW(eV2q6)=5B|F-x0K-HZ?3h|KLnc5*bp>X15W^%+csPmQ4Rz|{gpOUD=NMqagew5-qMC8pP|9WSV~=ul==6-cY`)l!u>NtF;t?)wLg!4kInq%W3)~-WM1x>=QMTJY6Bxa}cKo4NPce)4wHeb&SXj8ZhX> z^d=fOGf#}U-Jhvy`Hus>hw_9R3d`j*NV3C!?MYNvO@eJr-^0?<=j^&(90aNr)5+ho z`g4iN=gAXQZb<8)i+yS0%0CZn|#`VDIq9HVRnAqJ!WmX7H`-WUNaw(SA zc4_lTf&A6)d~kv?G4wD*p&h2c^`t*Ic8^B#q4Kp@UW)WqdCuV4F}M9qUSWvvTxf+FqNSXmmu zb$4k@N(o3jEPM#YUa`Jyn=mY2Ow~V2{?DIQJP{uhtX>Z=-$`ff3=mKqw^@&n_cMN- ze5CFlWTx14cJ2x&#K8iRLfw}yDOhB9%h${kn|F4yaG6m!MF9Z;9ieCW8fi<_D*}Ro_~`EwcU(KJRRO7R zEyve1*Bres7R3mXngv=m5(Luj#qkyZ1qCn}txm{iO(|!Nkip;PiVX`J+rcj7Lh*Z!&juM6SQ+66cD`e1AXO0CtoB^KG+*!DNK-QpB5+C#YekiQ(HN{cI;>h z^5}#ZqPk?O4}&bt6Wul6@Z>}a>H!HuWD7tufT1H?Ghi4kq7>-qEw%_6iLM)X$S*tn z$4y2Zi(hBVv|J^S5K*aZ3C0TNUmS7}1pDq_BfRo`zfR63qZ$-VfEKR1 zY;6=uxi0ZxB-bQ#2%Pm_gAl#3&!1C=(=Ey4V`EwqqTRPLMz;WJAMP%o=ozo?8GYlJ z$>@57gM)UM8G_{HAdJ3heCTwX5;4zfn>iZ>HPS1%wX{_Cb;~h- z5P+mYoXvQNqWKij1he?;z?aea(Ko~5B+i7YU|wxZ_y{23oTobl!GI$T z3yOr+U=l`Ta$)O>JLSLj-pdCDVC1>O{iV|th6HMx?2HWG{RU#fi9t_Y=M*k2?Fk;} z+K#%_Fuq72)q`&8?oMfSo;IJ5(3YQPy;T4}n&!vjWxI<2B0q$KF`%{irB*+2+V7rB zaBOTqNTLlIv8n!j>2%vi0n2ql5cjK#;B>Dnj9t>44xI>OQcWV?$)~>;zYJD(}g>2Sj#a@1N)Z{EC_YKbRlPE?22 z*DL558WyFco#bbP5$MP6R(5@x22y^S@>EiIZ`{ks#Ih(>7V=^Y5y5;F)^LG03P0nn zmmH#-EyHDHMpvT9_IsiGw4eLxz0%M`n}}LEwR38PTWXObZHbC!&YUp^C;*^>!`@7< zF1ng3grEF6P;O1~bz>LB1bndZ7+Uf0k5w1V+ClJv~uV%iC$zj;} z=`>I@061F^f~(bb|ISbo1rfm@0 z53A-(1R|s|6He%gQ7>+OtMt!{cf~0%2wHw?>*^~0xG@U&9_RUy`Z?(?W6&Q1`|I#P zK}hrTr9`|+)lR0CIu71SJsCfMA9JFk_C$uODp)h(5w2@816^HKDY`SPQtl^$?g z`lU?6`9h111rqj>d9-+b_{C4Wf`~6L##gO(#qP%!#rOC36I>yJ=tH+5>jFRg&%ZI| zCVeZ%(DIwR%j1}2>cR)D$2}wX^ylY49x5H|`u4ct8dPh7`8?D8_Q9^?ZqY8P2aP@? z@3+8}%k_oc`8I%Gh~IdT)z;ejsK3Ia4untK%SZYP(r1#2WDc3mj7i+M%K^cP&C@UI zcQ6P79%fjXNvb2kX6s6_G!`L042C~sb%Xgg=;=^!1=d_?zV+KX|A{q0w0}-X5=e7% z!}BdY^6kAV?J`%D!u#4Ly~MWRV$VKFCHsnU6K&YR`{Mk*#`wF$kx+3PE*-+YOa!f# z^;-M8FC5dj9_t1l#OdgRgO%p_(Jb40Ui+zL3ii}|+ME;d>kYKEvFQP{Mn+|&OaU!H z%Hs46*3On}BVOeo!gL4IZ|+7;)JHOr2`B>ECCf3P>fqrT2AI}{dtot18MCM4S4*?5=5^lo1-edlC2Qeyyid=i0tJg|L?ZZ#;r zVpiA??RddBY$YiC#iU=y_Zz~7bTv#Q{du`NwT78uGsEt+DQBCsKI!Kd-x~A_Vy2;? zA$&;g^&;l+IP7cQJX`(zM|!fti^?&*b!FzK1@EC01nN;=oRWMstlxK=BZ|8`|e#?S@Amu zk%}R_gfw%gy&R$GEPF_H*R75qGN@Kk9r)>1DX1zGe=wt&tJH}0@5nIYp0&WQ%am?qky`;iQGDj^CUO#h|@mANJT zW2@|zK%@>Ch&;Xf_p7*I?r96YI4qz{lYM_vrbUAv<%3;cfN_p~A7Wrw;#d%XWZ$OV zy}Jz6OVUVF+mhotj7Kgx1|qR2r7&)O+F<8s=ltyx4F5wr?JsF z?aHz=_Il7y{)t!~)Og2oL9WX`_0pAXP zM&GSg@BZ-_ty}NTOYN~|CIp2pJ6>knbk5#UZhV6Hc9x|Gmld^h0x*+$^o5jdpAJ@o zcdY%)RQ8Y!y?qVa#(Ec#Zd z`^g&A6#KC0F3VHlliNmwAR0Eq%mm|sEVEJ#g%Lgt#CD(-?3m_lo zd?8T0$=IP8+WZL~?P}PAdk+7a1wh3Z)Y=OmZw)={GC46z6_j4ZIv!((@Gl*Sb?LT! zo>1kByT>P)3y7Cq56S!6lDC_Vt@D27XjZ)LJyRLjHF8I6V}t zCXqfFP2(zP>slBjU%SzJ^o&M8&-HAruuGeA0s~p2e23WvQXMjCTaq2JwBN-FpRumc z$sKuZ$sCQeuzV0z$)#ieRNKew#{dV6rCm!QQwwN(D)LENitQ>q(aVaue^ta#@naBB z$AV({3gTxAw1XxZI?;L|14Sicr|mDXIgw1CJ$~OYIX+{RzR5hbQejb~cG)*KEh^=8 z+J4F1UuGc=+;FC|0`m{94p`reGV1=PLAJ<%UN=68c%BX2s}cu*wR^PO=0weE1l5}o zH3;*P3g>=>Xxn=|?;Qv0Y5g}zLp2%-jge!VsT>t5lzJ=~a+nY7I zAJEb(h0MKe@EGs;WxgC<{nbGr#K4o(h}MD|Nho+2}249 zKO;#^Jb-Abz}27gzCiawy0(~=a((lg9H~P#iWKmNn!n0;1yO*3(JJMBK$hT=5!%Y} zN0)h3?=NXL!3v3LCFo%YucJeNs5h+2dLe0 znXnxVqXCQ}Pq+$R1dj$Zxy_BNhoJJAo}PY2RMez$XS=lAef?Cy4#;Jz$=ESXNq zO6&J0xh}1&;H2Yd2|@Xc^3D7 zHHos@enshHv-Xzn(WARh8s9Cgr*nws%zBK~&f36(( zT0c3&{d+%57C7Cx;}3Y5)D9+9dU*zj`trkXY@m#3n1-BunU_aT!jQuqXit!v4sB>? zXg!*on0O4ctX9fcxLpE>BO=BgG|8(akGQooZSQW)Z}eq%iYnoy|AhE(zs#v^Bi(GR zwmN;hhb`+-vx3+I1{Z$_6zn3v&c-CCH{bc0We+jJh={jCL&nfUGg+5&OHCEh_wgsh z5*n_ZDiB|fZAuK>C)G><%8AQAQcAMdynHzlczEKJLpuo-EWq`%ou~~;W28S zXR(GSE0^$GSF+oBJKG9q>sOJdrf)j?ma7X?U$Y1~H@>x&cp&Be67h(z5nkT^}=z^Z4ENRyqs zgO$71>&0+9eu|N#MF={CW6V>_Nx(+%af00SCb+_62NWI2c@6^$ExRO?0$wOIIWzO! z_-)jZ8uKX7sI1Hl%ek#DB%jn5m654r;BFfSOt=N$D#%0To+GuEmY4BnC+!vrk<1)1 z4>)#ny5Gsd5Qch!;!v~r1O=m10Rdi%t54U$ypv;U-Xyh2bZ#>%id`vG;n8U;o38np zfK~_qFxGVD`@Y>B#3^x-*5dQRL4nF76N5~_eoK?`8we$7@;%A{hzlvpr>}+#M~g!t zA_Y^tTM{H)i%&SLvYeSam_>U9#SPQr6Cecow6&>E1L+-)u=sXIN5>r7(z)40An3u$ zW6v!ef$%XVfl5?$5Lu2>#If=Iulg{jT@hrdHL%xbih{9_K9dQXX<7=@BlcoeJy|+{ zp6;Uv#qc6tcU#gniZ%H!a+BRqK`aQzou#}Fpu3MEeGHC=gA!`;emrkMIdE{4P#6br zasH{oOZKX)6M+ZHv$qh^YH(SsAP|ex6s??_s(1k^BWncF?_Kw|v@LcBfd@P|wyv1K zvGJ|lsVONn$GsaJNGkPUFv3iI@Zl9OvH+A>2C=gA5cCpT`;?r?0iZEpfqNK*zq3wO zVT*hDwCq=E|I0Y{P`)`He~z+{v%@`rU96{9L~m8Zhw>olXj_Itbx{AP#o~T>u`5!j z1TbOfhkI?cB(uV^K_cwCc%_?8Z4MRA0!T+WPxP#C!Fy2k2U&{CRg=9C0mcFy9IiJF zN1%TUJ!{BLo&3sE-oy@e@kcqfFw74#Lt^+{Qb=t59i4bJmg9O@rMKojqsP+ z-h0nOI^;i-I`G|9nbeeI2{1epW1dd>8|z%gV*KMCzv5wH`_YJiH}7^F1cHOEwTl^z z%qlSjiRvNi(N&2c#}Ebo?OyQ-U#`mzFX1t@-KBwl)(vxx+JGnxmb!Hk?Xb zmo52%({A0-8TPgK4)gy0eX(U_sCuv4;ulq77GZvBwJpH`xo3gw8CO7wbgrl(&YOE9 zYr_zUPjluVPxm#e06ijLy=fq#hpaxeMY{a$2A>GWufris2|$=-`Of_8lg`qCIW?ai z^DL9u?Pm!tBQB4DG{)MMXnM2B+Vz;px3gv`q9^yzV>9B*CmVL|ygB=$W}OJm^hX!$ z`jwxjC&rip!p(S`Y&?`$D`plJ8bMLU^E!sHi;v{{Pu# zvVFn8@qXhfAw;mi_`k1>h7w%yXc`h_ZX6GQ;iEf?aXSaXk%r~22sC2DHjV~6QO>89 z;4pOqo1hjP3ivkQ1u|vGPDI|Ph6#pMOE#6!4ruvLatiPq&Qy#Vk1IsYQYs$S_QB#`K!v>YZ3d7&ABjIbD71cq0uX>a$f ztQ@||-)?OoV&WsG%TgY((&`mkqO?ty@#8<29By`R>ao1lX$%oP9JEaGKUL&|(9}dU z-LdW|oea{h)XBN?O{*-gE+!L{ho+c7h#>S|Z2!3E#*ZfA0kX9;NKipo8ZB&Zx$!dv z#~sAV9~OscPuzg;iiN@PQeQv4WI!{)+(cf&1LuSOau$R1tz~|_))QRx&8IW6vTzOK z(h*V}B45Lg>*VDT4^=Kc0U*lvP>)aV|hpu{NN;yL57$#RoH?3#3Pw!sr z0N*V>+9#<&O*Dv(7Em zsP96mPTVy(_0%)OnhJDP4`KzWiKnL95_9AWX<9_l)uie^IgDJKWfTC7p*2JPR7ra~^h zyu2TP=2}TSyHJ}P=jj2aYj>?WUPo9GAWGbwIU0qwkZk?7h*Ou=Yx%e1JOl?!>X6$; z(cAG&jS)S49ez?c5x1At+YX;T^n|FrSOgasLc`_6i@tf3TsPV~D)-Z+&S(PmMtXRS zc^8Ybh5+C4>UmsLR9@xI);IQywGKUpcYr~j!zcBZb(r7Z&>YBmSfHzYr{?x7?C8v5 z)_{LT3lr?5@aZF~D)5`7w|T5~zJC+Xex$x6+FsT&QMLu*i^=6E$G2m*hhJ~&kqL|T z6(9)#Gh2>Uw7i*>snAM8N2z0j0bAhBdp`Dc{0SAYLw{#7C}SDQs4g|}cjWnM%5haYH%x(3( zVVTP?fu^bzZ$vx)XEmsm4=F#N+uB!kGDl(hHLe)b{C5 zvEqp)EYZNM`j=o#x3*S~&>HCHg4-TgSXm3)rFVM1r84o7R76EZ>5y1S_cak;B#`rI#_0}>3e@LEg<44d;e=lY|lPz}qBGE&1|k!mM66LIZ9PJ{y6 z=qBkm>S?;o>8cq3F0~pKzju76A&m%Isv#)1=p6SjLBX}SC)05VQ>b8B5N{&uETdZsY zm&CsCh@=zfgRu1907xe~DkjI& zzF*JzX*swFJ2=_T;AH!ZyIbw6Q(rpxO(PbO@g~bEOeblz#Uz!~SK#$2sVCbP%xbkE zrrQ*9p(=}7#ySwA>*;s%OngAt<+%Hc81X+;1!V#U~nrGc2oc z#oqKQ?K6IH4rcjZ5d6rLsyE;+W5h8~s?Dsd9PA57s`Gm|3~ooBtf=!G$Rz6`8XA8tr{86sAz-{szSg%lLywm5Z6Dzf(rxEn0O@gSuO?#q-Z z60ll-{~rFORqj}nnR?SlAR%!L?qvURZpDFa{RcUW(gaXe4FBTEE|m53rY5uNDF!xT z=H@9jR_PYCwaS~t_os7q#ygN3o0?phdEg!W2}HB>(u+n$joVAN?h4;HvKYi*#ctkR zFgbaovVmhYx7pX&M@92uwI3gbEK%Pam)SXjd!CWu;?ZPqN$l$_h+x8&vxnmi%?@D< zo!r$&6M>Jf#69?LhIEKKe*GYXWeM(2N$W}+1v&GD>8TH8s&_jASEHRS?Xr}(ejxnOnt(q0KJ~aowMU=rJ*cmZGD|wTqI)7K5LqNm&^Lu zZBF-R0uyoxxLkW>hhO>38p_zps%eSQ7clbJmkriuzMNe=QaNn9c>9s=^n}ueCWE4O zCVKCJzJdkyWpXGYubMLJ5&r(;FI$1dd!~WB#GsxJgT7pKjJ#^(|ScD;{Z#9Jhfl|S<_{;06 z>ur8WXIhQ%59jvp`(Se5bpG||=yZGoC7xI8imDhUy+iHA2oU+awsvDSU3tH%h(#VcT%-UgPiLc;jjT^YB5=#>e^+-n?Q|&HV(?$sFj%x~0GOMF zMR-O|)S%+MGPyc8+%Xg59o+ zGenNOrF;&Dc2m?fdDPh`h+2SRK)P{R-VJo zcIvao$Jtr}9Q~ga=&*mw=*MV7-2H&3#__vT-9t`;Nv82CL%?5K6=DUt4tDrnOjjQp zGg5Hw#btN~JZn_Po2hO%UN0`z09g+@yaTZRHZ4w%Kk&O1-GC-gDe(i40MI+bW-M>e4Z`i&1kY8nP_3?@Yz-6l$S)7kjUq7U? z)V+mrGsziS^o67#`9OBNZJd2pa-8kt)dUINZ>g!ZfSF@52S3y@ZZ8n2>F3w+Y5^*XSQZcWI%Fh6 zIn9=0_uXQa^oW(YMb3z_O%V-uIxHtGAQo#~{`n>2!`8$teODZb%e(gz7qIA8r|1n38x7?*^OP~I{gQZ>8OXW!SGA5lk&Al58nl0Wpdhsx1C%SM(JxLep zGM~S3HCeVCvRcCslf*VA&-(ucN&Yzx$ijSLF=_9KN$Lo-`cZ?YPmkVrOoNk2i;A1F zMw|aqc9CoEjg#{Ny*ya0;@O*vkIf@%wWu}N$K*RleS6cKg@Mk!NW*3*@E@y!o@x>0%bP1hxj8)j{(V^#Ni|ch9Is&#j8^YGXNDe`EjK z%jv~+-UvgNu_2x4&!ZkMpXk5 zAC0@(H}2?(5E{?)@mPO|r1x55NpO{#2m6;{vF@e9;D`YjIS06N==74EXzvUw(i7-% znh1m0S5A-xATpz4E#Xq~L^|94f0Sn-kmt*TPUDu#T4wSGnKu&{)%3i)M$vFTmnNF{ z+T5$CGub)aLZ`6xb^zV#85$g!0&y%vew7LwfFPGLnr?bK7q*m`rV>B5 zZ8X+hmL@7HDwgf9&d!+X*RLHCaE|(?Cj;ElwCh{1eK^8UtWwuKcE8+^({(Y+RV`Vz z9;MFH)Bmt>$jz;J)NVK8H1A`MS=OxB*jTzWAY2-qns$rYRu$Fr5Avo)F+Es%Dqqcy zaan@T^3nyQB9B)%IXPKezy1!;K1CB1p+b9|3AjdGKzrm>X^J+qb4$uFV$^>jxG4z_Gn8{`jvC{o7R`N`Jp z+nw(lK7%@hK@9=L1N-;)XzV^P9IhFNzK0C=bMB12($;pWs+S>Dv0T@?eEg*@J*J zQQRx2|2^#!jEo88f}4K3t}@EGU*(+8`dsNugT-U5+!=5D!l>K}*Mf(StHK^*_~Q%x zD;M#aPzjWyHWtds#xBbkW$U|_I}`V_|@~;%WjL~50&asfbJ_)JJBG=J{DZ| zLgMdFV42Q9h!ELD`F*|@wt9>(qD_va>Uf?jacwgrJn&&>E;|N26AC3O6E(w{a{MO> z>dpINZ#~$$&G_iKpseeMIq;ghgGDmUVl|$NS_v3prkIgr`N| zw?c6;HE#)>9H-@{iwv6LlFuXI3E`Y$sfZKd37#)G-C-}^{JS6dV?#aO@|5b+C^t@g zXk8Y1YeP!7P|utFNQ8SiZ)h~RkP3^77mb_`o*xU8ufD-z zCRF!11SQ-8EWE=&Qhq>Gl);k&&ZxhfM6JII)=yLOW2hkT66~b>O;4rj_uqB8lS2)3 zF4?D%k*NWCYO9GL>JY*2MUis!x7#@`RfmQt68j8%KZVCnTtE2~=e1ejE=L+#0eQt% z1q0<66*qlQvRQG&ooQM?6?&#VRb9PE(R*?vdvWo~4p!Ez+S*#Wv_G9D@S6`fmCbCQ z4w;tt2jd<|4&zJeM1Dam4^TphoJO6WRL@9r^o+7{3jnn3!GWgS!I|0Ow|RHnCoL+q zd3}Mv`#vIu?KJUS=`ur)FkH6Vb@{Dh&6uxd-l=75ad{8Cdb!)+YGS2o-CSC(niwNpps9=ceh5Sii)3to|2d84sdFm4mk11 z;P&m?obz~Sd6!G}Gw4|BaW21mw21s&@uHr{+uk}G(&vVd+m@wh$1IeS);wBwN)tih1UT` zGw+Qrbq;uS9+ zpByD^QJ!;nRMb|4P}~$#n#0uRD8SQ>;$Jf97-nlFqeYG$wSZ!V27sQpcxkRSRUR&& zdQE)noNKrYmMvLl47pitEZVCDTj;vb!XfE&$!vV=YL@IVTpL0lS91UUi)Qq9&+rNb zDR{*~%=OT=@S*FhuNh)Q55{MHcu z;sd*fpAdGZn!3Z3X50j~8-B(MB}svuSr?FMhheRyQ}3C>X5e?yNhXQV$9y&yT=I>fu3l zHUZ8fdQS$L(?b~w*>k&V=TwuC;b(4M@P_x&r!}RQA6RvKWVw;lAg^crRcFV!%hJza z+es8*c*~-^Mu0JDU%s3)@%5_~unWK`88zbfbN7CY`;8j8 zYCSbvjevbkKbq4#6#YEerJnp!N&4|gEYfbdI_HOBcpU?w#D0g`nV0MBLONfJHINI< zDQC%Y1I-Z)hSaAbZ8q{w`5IlfmH=Vc_B`m(y0*?5ZvJM3m@*lMqIiPM}j;UuB7(+_X@8GI}+X=xWVI=g#R z@DM<7)|uUA1_j>W&~Gdz-{ARnsF2xi5kiS9qD9mEA~U@Cr7JiFz$)gmb*_UxVYw$YuWM~O{4@1uEcw+TtbS!$%Q0+aBZtC0KEn5Ux# zt0lsZ^roJr4b!vhjV7Hh>xfn@lxH*In|5ZsA$lS}$9HMfI)w$&ue4K8jSS0;6Xw-l z&!Gb3ED$n)pOpLg^A+e4E9x!4;QQC>u(!lA7GQS3@H3VDf6P(c9|@RE86Y+R$eZ@z zsP;p~s1Oe7RhcRSwS*tza<$i(a+$E!i7Fj-q1T*sb$BYPSm)K8a-c!ST3 ziT8F}tF06zKsvs+jS4?q&GH-42^LwxlssEYkb>`8ex$9ftu_Qh;%xqO#L7#ep$fat z%&iU8*`r{2A3g4^Tz`2LWMZkI3ca?i%@T@nx*YI^LCQ%&9081J5`p_TSLerzg}}#b zJu&o?)o7)8kvU5V#k2J&sAgdG0ptnhw}BLq26C`(%en)>YRC*r4onniq-wN+*KMAl zCX()C1?bp97QzC5SQUx-1Ern(fK+g%jxwUTV4}nutp0c!FHy4kfS81W7sCE7q z@3t|B3ea^~AeM!0OHy9nkcx(YyXOX;J*g|uRl92*kEsPRTd2SW!vSVePUAM|#y8ys z)GWv^?8bLT{=0x(211Q;?SdBU8n^44E_j5}1H{*R&o}6xp{r~AFYMq`8cIR+sGr5t z&@0+!Av7$^(#-57go<#MHsz1^rN#NBuvTH%q(xcaFyDK;%Gr!#)2`m`|EfR6I=*XwTSkiLuu73FTGWHfyA0SQ0% z6bCi_ErmY2**NarI%&>pK6a^2?S+@oyf|}!Pw>H`7gRGbF6n@-AXF=s4{%hNq-8+q zjyIl#=KRN_cn3hlQw~D#RWD#dpR+XhoNr~Wqtk-qV?;DYS$!*o{N-MJdwN4bBCP9^ zgObOYUKSGQmsC0z=OYNovGgtkUyJbhoT1V~RZeusHtj6+ldtQF6AKySks*_+2h;kV zr=(eFHK*#TV}&x)bWBZa728k5iyfkWJvR5uhnrMZd=aQA2*4yRqMnI<5=bNxd9lvQ zt9K>x3@jGkc!7x7N?rec29jXR%p3rRJw7%+W8?hwV-P9B!CPo3U)zzHq!!A-o=ben zU8VnoSugJfB8mh5aeCLeT6&bW!}g$IlIQB?CGav;0Q04^qVI`4F?uAc`-!Qp&Sch2 zPPZ!tPcaxw+5kcr#x(@pdK#b~bBoVkOUdq6J^BAYtumt4LnH$j70I|-(3dwjQk=Ak zvw$%oRq(ceJeAe(SZy^N9&YH;Kshb-79$FCj?d+fhYB+l9+rREty4sKtD#9*An=5P z^e0PMQN3DZF2xvzi=fynpqbWGG2BWNoh)PKm^YKp)XVM?ItJOg9VkOVhe{;G9BBEc zH9-?Jf2?(V^}+QWv*mRCR%)|mquoo3DWT+c@XMEL$?9XvHMi66j@))m<{l2&#f0ad zw|+aj*sCw-Hj`uYB`UP?QnBl6ucgBipM>j+U90eH@|Tm!yQy_2nUN7aJ;cu*IPpxq z*aS$i-{q(ywRv#RsHZ_`V$EKxCQ6Wj_#1h*6Y)beR{Ay`a?FqoQ%5!5^I=J5B%*Vbe$)iUmwD>zEx9B0I-kTs7qS zi1S~4EoWHaGIID^sjS(QP4BgQG{F-p;>u^(SMFmZB?#N)F4XwWl{)gniGF}Y3o;M4 zJ+Yr8kq1o9=liRi(W-yO91cduy65JELkKRq)n2e)`nh5D#sHDNdcM1Q!?NayPg)t8 z52QNnxCH`=^V%8G+tT1FI1*HQ6 zcuDN^o9{55TaE-Aar{Pu{ZjEn`;*JzvR!Cd1gD!erMT$%^9}YRC(mAbB)0!zZ!aR% zB80^8Mxapbg)^CRaO_)+z|W75x`8k+)_4l7qj5mlEqUmU%mp+P7U!0?ZXOnxz`C-659M)VaSximQs2rLtKqT>68auUAI6GNX zJh%J&{?Oo;0cJD$vNgfZXspcqGtQZH{dZUfR8}uHuDraQPUp?wiEI=9>n%BYf5cfY z6xiN5M^G=`MX|GRd*v~esot8oY(%1h?RBlLfm;aBZ{rwgKclwi@!4?CaZ}Sje2v4} zc@|{w;e*j_D+TkX%dnY&KSYsRJ@yTB?9ih|wl!XEetOJ&+*&>no#mC+E|DP*kc`&N zo6?5oV-lR5g+3qK?ysaFE~ZSPK@(r5LHn`Mkzyp%I*b$1TW^s=;qsB2MiAH&d|2z+ z?RNDD9jcpAK5d+%cM5scqGMOzu*}_N3kmy*jT~%MfLnO~p8YBA;uE&WAGHnNWL23| zfEa97&br>Mr%V+s9H1yV8cq0$rk?^!0ai$Bo>f2tyCuQKD&SGo^Pp`8H2$gr2mz^v z?#ru2c|q45cwrebheLw+mKCMru(9>Ic|A zNms;P6&4o08FHcgxz7CR5ZeNRl1_c{b+^Dr5S@;(1Z;m=i?W05EueTgqSe(}tphOn zaB0-#<2~neb@%^vd5T4W({Yxuecfv@$Y2n3gmO2i?x3?wRg_PBQk8SQjU&gzwH)V{ z$5SgYFyX|Sgx4^M_&>^ui5MHHT3yEENRYCwu1bKB^U-fZWuS3@Mg)Y7suSR7G0nfh z|ES~mc`W?fa8(t!o&3ugLthy`V>`Wj+x4LvSgn3#0>Ne9Hh&SF?bj@%Rv$Bw7?8CU zd{@6Vi}dt>m+p4CAV+|1*^MnN2U>UPnHU@0x*x!IMT9fL$~)UMQiu5bj{`G%S4qGI zkMpE}*dS}Q!|+{IN)4#^)1cP%8NO8ZQJ>I3MIQaUvPpx;i~7&eg8|o?2Z|41buZqo z$j|H<<6iaN&VSBP6avHs=qa;eXYY-hz@r{(QY zwcWZlC7=RU4Qp1m`Uw1?jqD0C+}=P1J3Krbi#*=8aVxkr=TuYGw|`q(16)pkfiru^ zz61VeQ&F00qlACkt`zl`q1Bbp$s1=|2VY3=df(=mhGA*N7yb)J>=7> zO}kz89ZIykK~U9wD>iSQN7P)5%|OU`qzZDg`?~Mkxr0_zbJ<5&7k!a?$GycJddFzn z+vkD1sI4s|0rmEF0)f1kG<5G4!fw^9vQ$k_d=azy`)e8bq~Hc{Eag;H(W49U^$*RU zPACV6-@V5mtFL8cW#w=e?%b=+i*EWoR=s=<)^Blfai3f8i%S-k_A#;H2!W$#RH>ih z5Sd!4*%k+OQ~)C8G8^C8Tt*W4<-=OpPZ)qF&N!Kd)YZ6dX5dCM%EKG-DZ1y*<@)+k zJ1@@X*ALpJPWz8|(}te%_1>_7OYGF~W9lqvkh%X_`tB{|`Y;5UaY`n&H*z90n*31P zf{O3;rWA0Tz~QVKQAW4eVk`3Vk*VKZ<@yJXfDfuLqFcJKsp;KE|m(~NI+e{g7NB{x<5g^sN3%o%` z3i0}UPV{P|Bj4waCFLnS35HZz0**{OF54RXW|*ZnDqbZ=eH z&Osd-I$Ji@yQ|B91a-B&ex3c3M6s>4ziN*vr?USD)Fc}eI;mJ5`zlE)Jh^b8^vmLP zvNe14O<82jsQ`o2*0z(J7D{&-`lPKK%inds@=N#g*RJcoc6hITwu9zCWojbc%-qPO z8q-ls=*?y^*n$z%dE$eDkxPqVG>)&m7@Ah^JOh=z=<*LA;=j?vrJ_s0e^M`s`*<+) zkegvlGlZY~#tWawG~NRLslTe_vFrQOM$qG5{C|{O|8NwS4J0Gg1h`NgRuS@-wY z933AYkKOuw$ZhGFnN(izq>ocwae(8Iz(;1McIb4?va4Oa(r&yowq19+H*DWcKTWgY zDHK!?;V*diJ=IBYGB-be>cmgF*>B5!Kk5bWRZ89~^7#N{J4F-m#rR|VSuqhOiv}t* z5dx5fN-HW_XnH$a(4}D_D?~zru(A}6^d?Hz$H@1*Yr1ZevEkNBv5J5cPQIl_>zz!~ zME5?kcgByBlAZ&g*%C-3iSyhK93KYgOyT2SSVZ*hJx`3Uku-YZEcnSr@?^I90$JQ$ z>9ogRmRg^@9YNu*Z!g`!P)4V~S{5Ti#dU+9=xQ@FH8(?asb@x`xygd|aBt-1jvdUi zVrf*~yqPM6>8NwM4j*5CWJ^TSogDmh{apK>dWj`-8Ly+v5WAGTanP(U6uLRoizk-d zJm$WEjGTgsj!TC0Fi2Y%{1g|8B)d(qCx=kasg{kb=XNzw6ixIjhxR8gKYlcs3sQ1? zrK6UPv=_Ow6Kdr6;kI&bpK@|H5M0?>=J#+9p2d$*25|m(<ZWS;1o_Y#k5H3Y7Wzkb`N)3}gXB0N+E>V z8GnzD)+meGg7*hflRJ=)m#luwXNXh z=5G?LyS7V1@JqB8Gs7i?kXzMwnp)z9d_ek#nfOJ4T>|W2??4(lYji$8H#ou4|`FqAZuA26KHiE4{iAhh?J+Q{MAz{6)KT6jA@m= z#yg6e((c|$QNEgfsJZA`ucG6-$WdPPpd(wCAf6wYJl@n>AHePezuq1DLDs* z_wh#b=Ffb=+9n8!HzwbV7?hS%LezWglrwU+c~m{wH>*OlY*u>_mrvI3Xj8;rzXuax zu5D|cA&@S(HzeUxxTssdUASpW6|YwIKF3rGT?e(B5qQ?k54g$!siP&VUwp3du6RB% zSG?pPM*f$El{PRqBrR!3dHAZkD8zI@&jp??+&!anIy(51rgnBj%pHY5NM5x~DkD#pEO--a!u&79H9gxPDIN0MMg&plb}~^90&O7!lic&zJhMaxO=9r#@`QL zSgGgBt7_o_DN>J?O}mBk#>ZbL)}PE6{-Ew~O{#XjDs zjn!CFpSh=-Ip1B7$LDbzb;x>MGEtuvxYBCs%5_Fk9?RZO5EK8Jg4RaT%^~P>sfJ8e0;UknD_++yk_n$ZX6h#7UFKcG9WK`DMpmw zpk6ymNd|=&@Oz~|p`yJu-Ii--K|%FZg{#r|nx!f9w=uG?NYgWKX;qI?plvz| z@RzA_@s!+K=XJ1ZnJT?(^;ny9REWxcwPB=?xp~6dz6TnUd5@Y;$};BP40)MEt?_|3 zHkb2-czW)=dJNI6;|~GeUz!l(O!gGl$NItR0AHk~J2xLb1zk(*cBs3jeCBpwz2y3ou=XXDP{MkHTFN@CC<8wM=2#B=IyEB+j`a-Y8~R?I_k z%Tn$}R|ar?U0>V9 zq+n_nBNzHzWDyJV(OTjw6hv1}CJQP_4rQMyleXU!-+MwCZPWeWg1oEpv;o+Jc9B5L zPHL^lLpF)grNysLnUb@oCp zssb0E0s^*fDK~=-0lS6Ph>k+Ymi5NRR5_7wZu`rLlyg=uw;o729<;-zj^P8e7U+eH zvH10%Dc*fSQ%U6~bzF8|2+ER2#TZu&W;#_53^Pq8A%AVWdub{yX`C67V@I97nkdck zeGC)|5r~#{)8l;GFUt2Pv;|9hv6Q?0#dwJ*Lv*DpG(|wW&VEYLNk_)|Qydm`bqFtZ`xN|N-aYx`$ww3>oYt)#6LZIQQ z5)bYx@zo2n&zlsQ%e}b29PRS?N+<+M0wt1-__TMkKnuxDzO)r{MoFoDfOS|+Eee@_ z0^om|z-MBXjI`%kt(_|-`g4y<`)H^zX+2Rm`aKUNq^0%i9*PD~pN$t+C_^~9LJL(k zhswFS$6spH?^RxQo13|3b%xRpcv1>*UVNhViW16a&fEj@!!mrLK|4{O{`Xn0`Hhtp zTyX8|ym$W0-l~n8x7`Dx!iIf+NiWURuxRkK;25dZ-xoSQzKN>K=n1H3!Lf9>EiK$e z%S%O|$ z0?T$ti_UH`|3c}fxS@+niwgwV3Miv9rwt4nem?S>5nm-Du$3Ow^mJ*{JNvzMs`+-m ziIp=lG>pS!C`ceR1RyMZSy!i)t`jr`yiuvdFIs!Gf;tk)3!W`W({gcvzF72FhL$WYKC zQ62X}(+hF-ppNvNru5ffUbErqg$hRkb16-qS5_+I1I2VY=IUtYQ#QN;g7$w{S_~|$ z%JlZFTSG`9Gu7^#8IM1X!n}vRxA6!CU4JBaLs^wXyWQBJshU@>-qEn6=mm*LNNA;M zuuD4Sk{sR7&JGTLT67e<3=1FSTTc&G&H6AMtSsZl6pkRen9`LX8{{aykLX_Z=f zdKt046v!{*EkPa7WGM+4=rf5Frur(hfk21VXvRuy2`Tl^ok#3)_d5UXT&>Xtio?vL z4{hdpinB=Jz1sbkZ_b~8YN^G-eQWV19)?J8OhMOlo*E7dk1rC96gU`570}-#MNz)R zFCJL|oOKPZ?`(c^Tvr?p%SVnJY*~r>!+pog5GU`jr=%aLo9uylK!T3EUGRo-r(NmN z46hWDk?C^a=g%DiV}1x&J<_$Zq3Pj-)PVh3*<1U5cNrgYPlOwpbOUbsU{s5Zl?9ox|bKP zU(bzi`3q=EKo!KrHEuAQPGsBVmQ?jKyfjJGCMHD7pNTJ0g_ZW`wL^;_Ii!F@zuY}&$FGokSn7Pb@{#_Jx6+rgIw~;p5te$kw zA$sVLHUMs`pw)#Nr9fTZMQiIU;sR`4E1Y&!Z{EByfA#qhMSGe|@ncin$95m=9jm#r zqTNTTolvfM+T_J<5j>XB)pVmS?OTj&EJEE!#*I%!T;5NCeRxo=nSC$g=z?>&Uk4)y zYN;{J^qk3lLbd#biKZTfmD5djneUjk}LTcZyh+Gjd%Y&W9~%-tkHWuf8G+uQpEjPjSE=EqA~ zhKt>8V2s8V7Pd31EDCix_oTi_a39eRo9$~iA?xV(XC{;gQ(_-Jd3SK?1nsnxRc`Xa z0)nigq$IAlh$Ne%i4^lLUlT74hm}UKjCPDf96a!>Rj89V-Y8LQ$%FIat?S-3ECacS zrHe16PxMbf!us=jZ2{fLqmDTw69GC~T#+WFc)^B(A(Ae-iG487l({1!?~}>oNKN-# zW64G1^1UphF0T3hnzMYJbMIIFqP@_4qyxUVktDhE+3qC)i%peBV3K4@3s>rQT|Dms zhPugpSICp808VK=s8M(cFnx2x?f0J^Vz`|rhxPzNW-lqiR0EFXP42CfYgJ(FVbio5 z)OoA>6-K?0qA9(t=%KbJc_e4bjylCS=mK!-9{*#O@p1Re#~u*UyEQ3t_!vgj1iIe%UV+Qz0jv$L}c z0^qo#w5S#FZ&TvRY6g|u!5`htX-O8So`4QF+<0{ux5_N9893>c*SVlnkE~$Nzn_+_ zR39~J19~on{JSmN3?tbY6LI(7K2G=12lC+3cY-w-)*ANThPsoA3Ul54isHYUYEJn2 zf`l^W)Y@JD?Hm7>$x~sz_DE>+{OdNn@qj69{+RghXV)w@Ed75A`fnTh--7;+>iM69 z{-^T)Y;pgyq5mC9|12RC{~b#Io$~)8BH%NQ?lqD0pE9}oGI|62IVG=rJVW+^=l=t; C2d%#V literal 0 HcmV?d00001 diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 78593706c7d..eeaf5afa771 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -3,14 +3,13 @@ add_subdirectory( builtins ) add_subdirectory( softfloat ) add_subdirectory( chainbase ) add_subdirectory( wasm-jit ) -add_subdirectory( utilities ) add_subdirectory( appbase ) add_subdirectory( chain ) add_subdirectory( testing ) -add_subdirectory( abi_generator ) -#turn these off for now +#turn tools&tests off; not needed for library build set(BUILD_TESTS OFF CACHE BOOL "Build GTest-based tests") set(BUILD_TOOLS OFF CACHE BOOL "Build wabt tools") set(RUN_RE2C OFF CACHE BOOL "Run re2c") +set(WITH_EXCEPTIONS ON CACHE BOOL "Build with exceptions enabled" FORCE) add_subdirectory( wabt ) diff --git a/libraries/abi_generator/CMakeLists.txt b/libraries/abi_generator/CMakeLists.txt deleted file mode 100644 index 88e32a84048..00000000000 --- a/libraries/abi_generator/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -# Find an installed build of LLVM -find_package(LLVM 4.0 REQUIRED CONFIG) -set( CMAKE_CXX_STANDARD 14 ) - -file(GLOB HEADERS "include/eosio/abi_generator/*.hpp") - -set(SOURCES ${HEADERS}) - -add_library( abi_generator - abi_generator.cpp - ${HEADERS} ) - -target_include_directories(abi_generator - PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" - "${LLVM_INCLUDE_DIRS}") - -target_link_libraries(abi_generator eosio_chain - clangRewrite - clangTooling - clangToolingCore - clangFrontend - clangDriver - clangSerialization - clangParse - clangSema - clangAnalysis - clangAST - clangBasic - clangEdit - clangLex -) - -target_link_libraries(abi_generator - LLVMX86AsmParser # MC, MCParser, Support, X86CodeGen, X86Desc, X86Info - LLVMX86CodeGen # Analysis, AsmPrinter, CodeGen, Core, MC, Support, Target, - # X86AsmPrinter, X86Desc, X86Info, X86Utils - LLVMX86Desc # MC, MCDisassembler, Object, Support, X86AsmPrinter, X86Info - LLVMX86AsmPrinter # MC, Support, X86Utils - LLVMX86Info # Support - LLVMX86Utils # Core, Support - LLVMCodeGen # Analysis, Core, MC, Scalar, Support, Target, TransformUtils - LLVMipo - LLVMScalarOpts - LLVMInstCombine - LLVMTransformUtils - LLVMTarget # Analysis, MC, Core, Support - LLVMAnalysis # Core, Support - LLVMOption # Support - LLVMMCDisassembler # MC, Support - LLVMMCParser # MC, Support - LLVMMC # Object, Support - LLVMProfileData # Core, Support, Object - LLVMObject # BitReader, Core, Support - LLVMBitReader # Core, Support - LLVMCore # BinaryFormat, Support - #LLVMBinaryFormat # Support - LLVMSupport # Demangle - LLVMDemangle -) - -if (USE_PCH) - set_target_properties(abi_generator PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE) - cotire(eos_utilities) -endif(USE_PCH) diff --git a/libraries/abi_generator/abi_generator.cpp b/libraries/abi_generator/abi_generator.cpp deleted file mode 100644 index fc021c0a3fd..00000000000 --- a/libraries/abi_generator/abi_generator.cpp +++ /dev/null @@ -1,688 +0,0 @@ -#include -#include - -namespace eosio { - -void abi_generator::set_target_contract(const string& contract, const vector& actions) { - target_contract = contract; - target_actions = actions; -} - -void abi_generator::enable_optimizaton(abi_generator::optimization o) { - optimizations |= o; -} - -bool abi_generator::is_opt_enabled(abi_generator::optimization o) { - return (optimizations & o) != 0; -} - -void abi_generator::set_output(abi_def& output) { - this->output = &output; -} - -void abi_generator::set_verbose(bool verbose) { - this->verbose = verbose; -} - -void abi_generator::set_ricardian_contracts(const ricardian_contracts& contracts) { - this->rc = contracts; -} - -void abi_generator::set_abi_context(const string& abi_context) { - this->abi_context = abi_context; -} - -void abi_generator::set_compiler_instance(CompilerInstance& compiler_instance) { - this->compiler_instance = &compiler_instance; -} - -void abi_generator::handle_tagdecl_definition(TagDecl* tag_decl) { - ast_context = &tag_decl->getASTContext(); - auto decl_location = tag_decl->getLocation().printToString(ast_context->getSourceManager()); - try { - handle_decl(tag_decl); -} FC_CAPTURE_AND_RETHROW((decl_location)) } - -string abi_generator::remove_namespace(const string& full_name) { - int i = full_name.size(); - int on_spec = 0; - int colons = 0; - while( --i >= 0 ) { - if( full_name[i] == '>' ) { - ++on_spec; colons=0; - } else if( full_name[i] == '<' ) { - --on_spec; colons=0; - } else if( full_name[i] == ':' && !on_spec) { - if (++colons == 2) - return full_name.substr(i+2); - } else { - colons = 0; - } - } - return full_name; -} - -bool abi_generator::is_builtin_type(const string& type_name) { - abi_serializer serializer; - auto rtype = resolve_type(type_name); - return serializer.is_builtin_type(translate_type(rtype)); -} - -string abi_generator::translate_type(const string& type_name) { - string built_in_type = type_name; - - if (type_name == "unsigned __int128" || type_name == "uint128_t") built_in_type = "uint128"; - else if (type_name == "__int128" || type_name == "int128_t") built_in_type = "int128"; - - else if (type_name == "unsigned long long" || type_name == "uint64_t") built_in_type = "uint64"; - else if (type_name == "unsigned long" || type_name == "uint32_t") built_in_type = "uint32"; - else if (type_name == "unsigned short" || type_name == "uint16_t") built_in_type = "uint16"; - else if (type_name == "unsigned char" || type_name == "uint8_t") built_in_type = "uint8"; - - else if (type_name == "long long" || type_name == "int64_t") built_in_type = "int64"; - else if (type_name == "long" || type_name == "int32_t") built_in_type = "int32"; - else if (type_name == "short" || type_name == "int16_t") built_in_type = "int16"; - else if (type_name == "char" || type_name == "int8_t") built_in_type = "int8"; - else if (type_name == "double") built_in_type = "float64"; - else { - static auto types = eosio::chain::common_type_defs(); - auto itr = std::find_if( types.begin(), types.end(), - [&type_name]( const eosio::chain::type_def& t ) { return t.new_type_name == type_name; } ); - if( itr != types.end()) { - built_in_type = itr->type; - } - } - - return built_in_type; -} - -bool abi_generator::inspect_type_methods_for_actions(const Decl* decl) { try { - - const auto* rec_decl = dyn_cast(decl); - if(rec_decl == nullptr) return false; - - const auto* type = rec_decl->getTypeForDecl(); - ABI_ASSERT(type != nullptr); - - bool at_least_one_action = false; - - auto export_method = [&](const CXXMethodDecl* method) { - - auto method_name = method->getNameAsString(); - - // Try to get "action" annotation from method comment - bool raw_comment_is_action = false; - string action_name_from_comment; - const RawComment* raw_comment = ast_context->getRawCommentForDeclNoCache(method); - if(raw_comment != nullptr) { - SourceManager& source_manager = ast_context->getSourceManager(); - string raw_text = raw_comment->getRawText(source_manager); - regex r(R"(@abi (action) ?((?:[a-z0-9]+)*))"); - smatch smatch; - regex_search(raw_text, smatch, r); - raw_comment_is_action = smatch.size() == 3; - - if (raw_comment_is_action) { - action_name_from_comment = smatch[2]; - } - } - - // Check if current method is listed the EOSIO_ABI macro - bool is_action_from_macro = rec_decl->getName().str() == target_contract && std::find(target_actions.begin(), target_actions.end(), method_name) != target_actions.end(); - - if(!raw_comment_is_action && !is_action_from_macro) { - return; - } - - ABI_ASSERT(find_struct(method_name) == nullptr, "action already exists ${method_name}", ("method_name",method_name)); - - struct_def abi_struct; - for(const auto* p : method->parameters() ) { - clang::QualType qt = p->getOriginalType().getNonReferenceType(); - qt.setLocalFastQualifiers(0); - - string field_name = p->getNameAsString(); - string field_type_name = add_type(qt, 0); - - field_def struct_field{field_name, field_type_name}; - ABI_ASSERT(is_builtin_type(get_vector_element_type(struct_field.type)) - || find_struct(get_vector_element_type(struct_field.type)) - || find_type(get_vector_element_type(struct_field.type)) - , "Unknown type ${type} [${abi}]",("type",struct_field.type)("abi",*output)); - - type_size[string(struct_field.type)] = is_vector(struct_field.type) ? 0 : ast_context->getTypeSize(qt); - abi_struct.fields.push_back(struct_field); - } - - abi_struct.name = method_name; - abi_struct.base = ""; - - output->structs.push_back(abi_struct); - - full_types[method_name] = method_name; - - string action_name = action_name_from_comment.empty() ? method_name : action_name_from_comment; - output->actions.push_back({action_name, method_name, rc[method_name]}); - at_least_one_action = true; - }; - - const auto export_methods = [&export_method](const CXXRecordDecl* rec_decl) { - - - auto export_methods_impl = [&export_method](const CXXRecordDecl* rec_decl, auto& ref) -> void { - - - auto tmp = rec_decl->bases(); - auto rec_name = rec_decl->getName().str(); - - rec_decl->forallBases([&ref](const CXXRecordDecl* base) -> bool { - ref(base, ref); - return true; - }); - - for(const auto* method : rec_decl->methods()) { - export_method(method); - } - - }; - - export_methods_impl(rec_decl, export_methods_impl); - }; - - export_methods(rec_decl); - - return at_least_one_action; - -} FC_CAPTURE_AND_RETHROW() } - -void abi_generator::handle_decl(const Decl* decl) { try { - - ABI_ASSERT(decl != nullptr); - ABI_ASSERT(output != nullptr); - ABI_ASSERT(ast_context != nullptr); - - // Only process declarations that has the `abi_context` folder as parent. - SourceManager& source_manager = ast_context->getSourceManager(); - auto file_name = source_manager.getFilename(decl->getLocStart()); - if ( !abi_context.empty() && !file_name.startswith(abi_context) ) { - return; - } - - // Check if the current declaration has actions (EOSIO_ABI, or explicit) - bool type_has_actions = inspect_type_methods_for_actions(decl); - if( type_has_actions ) return; - - // The current Decl doesn't have actions - const RawComment* raw_comment = ast_context->getRawCommentForDeclNoCache(decl); - if(raw_comment == nullptr) { - return; - } - - string raw_text = raw_comment->getRawText(source_manager); - regex r; - - // If EOSIO_ABI macro was found, we will only check if the current Decl - // is intented to be an ABI table record, otherwise we check for both (action or table) - if( target_contract.size() ) - r = regex(R"(@abi (table)((?: [a-z0-9]+)*))"); - else - r = regex(R"(@abi (action|table)((?: [a-z0-9]+)*))"); - - smatch smatch; - while(regex_search(raw_text, smatch, r)) - { - if(smatch.size() == 3) { - - auto type = smatch[1].str(); - - vector params; - auto string_params = smatch[2].str(); - boost::trim(string_params); - if(!string_params.empty()) - boost::split(params, string_params, boost::is_any_of(" ")); - - if(type == "action") { - - const auto* action_decl = dyn_cast(decl); - ABI_ASSERT(action_decl != nullptr); - - auto qt = action_decl->getTypeForDecl()->getCanonicalTypeInternal(); - - auto type_name = add_struct(qt, "", 0); - ABI_ASSERT(!is_builtin_type(type_name), - "A built-in type with the same name exists, try using another name: ${type_name}", ("type_name",type_name)); - - if(params.size()==0) { - params.push_back( boost::algorithm::to_lower_copy(boost::erase_all_copy(type_name, "_")) ); - } - - for(const auto& action : params) { - const auto* ac = find_action(action); - if( ac ) { - ABI_ASSERT(ac->type == type_name, "Same action name with different type ${action}",("action",action)); - continue; - } - output->actions.push_back({action, type_name, rc[action]}); - } - - } else if (type == "table") { - - const auto* table_decl = dyn_cast(decl); - ABI_ASSERT(table_decl != nullptr); - - auto qt = table_decl->getTypeForDecl()->getCanonicalTypeInternal(); - auto type_name = add_struct(qt, "", 0); - - ABI_ASSERT(!is_builtin_type(type_name), - "A built-in type with the same name exists, try using another name: ${type_name}", ("type_name",type_name)); - - const auto* s = find_struct(type_name); - ABI_ASSERT(s, "Unable to find type ${type}", ("type",type_name)); - - table_def table; - table.name = boost::algorithm::to_lower_copy(boost::erase_all_copy(type_name, "_")); - table.type = type_name; - - if(params.size() >= 1) { - table.name = params[0]; - } - - if(params.size() >= 2) { - table.index_type = params[1]; - ABI_ASSERT(table.index_type == "i64", "Only i64 index is supported. ${index_type}",("index_type",table.index_type)); - } else { try { - guess_index_type(table, *s); - } FC_CAPTURE_AND_RETHROW( (type_name) ) } - - try { - guess_key_names(table, *s); - } FC_CAPTURE_AND_RETHROW( (type_name) ) - - //TODO: assert that we are adding the same table - const auto* ta = find_table(table.name); - if(!ta) { - output->tables.push_back(table); - } - } - } - - raw_text = smatch.suffix(); - } - -} FC_CAPTURE_AND_RETHROW() } - -bool abi_generator::is_64bit(const string& type) { - return type_size[type] == 64; -} - -bool abi_generator::is_128bit(const string& type) { - return type_size[type] == 128; -} - -bool abi_generator::is_string(const string& type) { - return type == "String" || type == "string"; -} - -void abi_generator::get_all_fields(const struct_def& s, vector& fields) { - abi_serializer abis(*output, fc::seconds(1)); // No risk to client side serialization taking a long time - - for(const auto& field : s.fields) { - fields.push_back(field); - } - - if(s.base.size()) { - const auto* base = find_struct(s.base); - ABI_ASSERT(base, "Unable to find base type ${type}",("type",s.base)); - get_all_fields(*base, fields); - } -} - -bool abi_generator::is_i64_index(const vector& fields) { - return fields.size() >= 1 && is_64bit(fields[0].type); -} - -void abi_generator::guess_index_type(table_def& table, const struct_def s) { - vector fields; - get_all_fields(s, fields); - if( is_i64_index(fields) ) { - table.index_type = "i64"; - } else { - ABI_ASSERT(false, "Unable to guess index type"); - } -} - -void abi_generator::guess_key_names(table_def& table, const struct_def s) { - - vector fields; - get_all_fields(s, fields); - - if( table.index_type == "i64") { - - table.key_names.clear(); - table.key_types.clear(); - - unsigned int key_size = 0; - bool valid_key = false; - for(auto& f : fields) { - table.key_names.emplace_back(f.name); - table.key_types.emplace_back(f.type); - key_size += type_size[f.type]/8; - - if(table.index_type == "i64" && key_size >= sizeof(uint64_t)) { - valid_key = true; - break; - } - } - - ABI_ASSERT(valid_key, "Unable to guess key names"); - } else { - ABI_ASSERT(false, "Unable to guess key names"); - } -} - -const table_def* abi_generator::find_table(const table_name& name) { - for( const auto& ta : output->tables ) { - if(ta.name == name) { - return &ta; - } - } - return nullptr; -} - -const type_def* abi_generator::find_type(const type_name& new_type_name) { - for( const auto& td : output->types ) { - if(td.new_type_name == new_type_name) { - return &td; - } - } - return nullptr; -} - -const action_def* abi_generator::find_action(const action_name& name) { - for( const auto& ac : output->actions ) { - if(ac.name == name) { - return ∾ - } - } - return nullptr; -} - -const struct_def* abi_generator::find_struct(const type_name& name) { - auto rname = resolve_type(name); - for( const auto& st : output->structs ) { - if(st.name == rname) { - return &st; - } - } - return nullptr; -} - -type_name abi_generator::resolve_type(const type_name& type){ - const auto* td = find_type(type); - if( td ) { - for( auto i = output->types.size(); i > 0; --i ) { // avoid infinite recursion - const type_name& t = td->type; - td = find_type(t); - if( td == nullptr ) return t; - } - } - return type; -} - -bool abi_generator::is_one_filed_no_base(const string& type_name) { - const auto* s = find_struct(type_name); - return s && s->base.size() == 0 && s->fields.size() == 1; -} - -string abi_generator::decl_to_string(clang::Decl* d) { - //ASTContext& ctx = d->getASTContext(); - const auto& sm = ast_context->getSourceManager(); - clang::SourceLocation b(d->getLocStart()), _e(d->getLocEnd()); - clang::SourceLocation e(clang::Lexer::getLocForEndOfToken(_e, 0, sm, compiler_instance->getLangOpts())); - return string(sm.getCharacterData(b), - sm.getCharacterData(e)-sm.getCharacterData(b)); -} - -bool abi_generator::is_typedef(const clang::QualType& qt) { - return isa(qt.getTypePtr()); -} - -bool abi_generator::is_elaborated(const clang::QualType& qt) { - return isa(qt.getTypePtr()); -} - -bool abi_generator::is_vector(const clang::QualType& vqt) { - - QualType qt(vqt); - - if ( is_elaborated(qt) ) - qt = qt->getAs()->getNamedType(); - - return isa(qt.getTypePtr()) \ - && boost::starts_with( get_type_name(qt, false), "vector"); -} - -bool abi_generator::is_vector(const string& type_name) { - return boost::ends_with(type_name, "[]"); -} - -bool abi_generator::is_struct_specialization(const clang::QualType& qt) { - return is_struct(qt) && isa(qt.getTypePtr()); -} - -bool abi_generator::is_struct(const clang::QualType& sqt) { - clang::QualType qt(sqt); - const auto* type = qt.getTypePtr(); - return !is_vector(qt) && (type->isStructureType() || type->isClassType()); -} - -clang::QualType abi_generator::get_vector_element_type(const clang::QualType& qt) { - const auto* tst = clang::dyn_cast(qt.getTypePtr()); - ABI_ASSERT(tst != nullptr); - const clang::TemplateArgument& arg0 = tst->getArg(0); - return arg0.getAsType(); -} - -string abi_generator::get_vector_element_type(const string& type_name) { - if( is_vector(type_name) ) - return type_name.substr(0, type_name.size()-2); - return type_name; -} - -string abi_generator::get_type_name(const clang::QualType& qt, bool with_namespace=false) { - auto name = clang::TypeName::getFullyQualifiedName(qt, *ast_context); - if(!with_namespace) - name = remove_namespace(name); - return name; -} - -clang::QualType abi_generator::add_typedef(const clang::QualType& tqt, size_t recursion_depth) { - - ABI_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); - - clang::QualType qt(get_named_type_if_elaborated(tqt)); - - const auto* td_decl = qt->getAs()->getDecl(); - auto underlying_type = td_decl->getUnderlyingType().getUnqualifiedType(); - - auto new_type_name = td_decl->getName().str(); - auto underlying_type_name = get_type_name(underlying_type); - - if ( is_vector(underlying_type) ) { - underlying_type_name = add_vector(underlying_type, recursion_depth); - } - - type_def abi_typedef; - abi_typedef.new_type_name = new_type_name; - abi_typedef.type = translate_type(underlying_type_name); - const auto* td = find_type(abi_typedef.new_type_name); - - if(!td && !is_struct_specialization(underlying_type) ) { - output->types.push_back(abi_typedef); - } else { - if(td) ABI_ASSERT(abi_typedef.type == td->type); - } - - if( is_typedef(underlying_type) && !is_builtin_type(get_type_name(underlying_type)) ) - return add_typedef(underlying_type, recursion_depth); - - return underlying_type; -} - -clang::CXXRecordDecl::base_class_range abi_generator::get_struct_bases(const clang::QualType& sqt) { - - clang::QualType qt(sqt); - if(is_typedef(qt)) { - const auto* td_decl = qt->getAs()->getDecl(); - qt = td_decl->getUnderlyingType().getUnqualifiedType(); - } - - const auto* record_type = qt->getAs(); - ABI_ASSERT(record_type != nullptr); - auto cxxrecord_decl = clang::dyn_cast(record_type->getDecl()); - ABI_ASSERT(cxxrecord_decl != nullptr); - //record_type->getCanonicalTypeInternal().dump(); - ABI_ASSERT(cxxrecord_decl->hasDefinition(), "No definition for ${t}", ("t", qt.getAsString())); - - auto bases = cxxrecord_decl->bases(); - - return bases; -} - -const clang::RecordDecl::field_range abi_generator::get_struct_fields(const clang::QualType& sqt) { - clang::QualType qt(sqt); - - if(is_typedef(qt)) { - const auto* td_decl = qt->getAs()->getDecl(); - qt = td_decl->getUnderlyingType().getUnqualifiedType(); - } - - const auto* record_type = qt->getAs(); - ABI_ASSERT(record_type != nullptr); - return record_type->getDecl()->fields(); -} - -string abi_generator::add_vector(const clang::QualType& vqt, size_t recursion_depth) { - - ABI_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); - - clang::QualType qt(get_named_type_if_elaborated(vqt)); - - auto vector_element_type = get_vector_element_type(qt); - ABI_ASSERT(!is_vector(vector_element_type), "Only one-dimensional arrays are supported"); - - add_type(vector_element_type, recursion_depth); - - auto vector_element_type_str = translate_type(get_type_name(vector_element_type)); - vector_element_type_str += "[]"; - - return vector_element_type_str; -} - -string abi_generator::add_type(const clang::QualType& tqt, size_t recursion_depth) { - - ABI_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); - - clang::QualType qt(get_named_type_if_elaborated(tqt)); - - string full_type_name = translate_type(get_type_name(qt, true)); - string type_name = translate_type(get_type_name(qt)); - bool is_type_def = false; - - if( is_builtin_type(type_name) ) { - return type_name; - } - - if( is_typedef(qt) ) { - qt = add_typedef(qt, recursion_depth); - if( is_builtin_type(translate_type(get_type_name(qt))) ) { - return type_name; - } - is_type_def = true; - } - - if( is_vector(qt) ) { - auto vector_type_name = add_vector(qt, recursion_depth); - return is_type_def ? type_name : vector_type_name; - } - - if( is_struct(qt) ) { - return add_struct(qt, full_type_name, recursion_depth); - } - - ABI_ASSERT(false, "types can only be: vector, struct, class or a built-in type. (${type}) ", ("type",get_type_name(qt))); - return type_name; -} - -clang::QualType abi_generator::get_named_type_if_elaborated(const clang::QualType& qt) { - if( is_elaborated(qt) ) { - return qt->getAs()->getNamedType(); - } - return qt; -} - -string abi_generator::add_struct(const clang::QualType& sqt, string full_name, size_t recursion_depth) { - - ABI_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); - - clang::QualType qt(get_named_type_if_elaborated(sqt)); - - if( full_name.empty() ) { - full_name = get_type_name(qt, true); - } - - auto name = remove_namespace(full_name); - - ABI_ASSERT(is_struct(qt), "Only struct and class are supported. ${full_name}",("full_name",full_name)); - - if( find_struct(name) ) { - auto itr = full_types.find(resolve_type(name)); - if(itr != full_types.end()) { - ABI_ASSERT(itr->second == full_name, "Unable to add type '${full_name}' because '${conflict}' is already in.\n${t}", ("full_name",full_name)("conflict",itr->second)("t",output->types)); - } - return name; - } - - auto bases = get_struct_bases(qt); - auto bitr = bases.begin(); - int total_bases = 0; - - string base_name; - while( bitr != bases.end() ) { - auto base_qt = bitr->getType(); - const auto* record_type = base_qt->getAs(); - if( record_type && is_struct(base_qt) && !record_type->getDecl()->field_empty() ) { - ABI_ASSERT(total_bases == 0, "Multiple inheritance not supported - ${type}", ("type",full_name)); - base_name = add_type(base_qt, recursion_depth); - ++total_bases; - } - ++bitr; - } - - struct_def abi_struct; - for (const clang::FieldDecl* field : get_struct_fields(qt) ) { - clang::QualType qt = field->getType(); - - string field_name = field->getNameAsString(); - string field_type_name = add_type(qt, recursion_depth); - - field_def struct_field{field_name, field_type_name}; - ABI_ASSERT(is_builtin_type(get_vector_element_type(struct_field.type)) - || find_struct(get_vector_element_type(struct_field.type)) - || find_type(get_vector_element_type(struct_field.type)) - , "Unknown type ${type} [${abi}]",("type",struct_field.type)("abi",*output)); - - type_size[string(struct_field.type)] = is_vector(struct_field.type) ? 0 : ast_context->getTypeSize(qt); - abi_struct.fields.push_back(struct_field); - } - - abi_struct.name = resolve_type(name); - abi_struct.base = base_name; - - output->structs.push_back(abi_struct); - - full_types[name] = full_name; - return name; -} - -} diff --git a/libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp b/libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp deleted file mode 100644 index 9248846cd88..00000000000 --- a/libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp +++ /dev/null @@ -1,442 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -//clashes with something deep in the AST includes in clang 6 and possibly other versions of clang -#pragma push_macro("N") -#undef N - -#include "clang/Driver/Options.h" -#include "clang/AST/AST.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/ASTConsumer.h" - -#include "clang/Frontend/FrontendPluginRegistry.h" -#include "clang/AST/AST.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Sema/Sema.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/MacroArgs.h" -#include "clang/Tooling/Tooling.h" -#include "clang/Tooling/CommonOptionsParser.h" -#include "clang/Tooling/Core/QualTypeNames.h" -#include "llvm/Support/raw_ostream.h" -#include -#include - -using namespace clang; -using namespace std; -using namespace clang::tooling; -namespace cl = llvm::cl; - -namespace eosio { - using namespace eosio::chain; - - FC_DECLARE_EXCEPTION( abi_generation_exception, 999999, "Unable to generate abi" ); - - #define ABI_ASSERT( TEST, ... ) \ - FC_EXPAND_MACRO( \ - FC_MULTILINE_MACRO_BEGIN \ - if( UNLIKELY(!(TEST)) ) \ - { \ - if( fc::enable_record_assert_trip ) \ - fc::record_assert_trip( __FILE__, __LINE__, #TEST ); \ - FC_THROW_EXCEPTION( eosio::abi_generation_exception, #TEST ": " __VA_ARGS__ ); \ - } \ - FC_MULTILINE_MACRO_END \ - ) - - class ricardian_contracts { - public: - ricardian_contracts() = default; - ricardian_contracts( const string& context, const string& contract, const vector& actions ) { - ifstream clauses_file( context+"/"+contract+"_rc.md"); - if ( !clauses_file.good() ) - wlog("Warning, no ricardian clauses found for ${con}\n", ("con", contract)); - else - parse_clauses( clauses_file ); - - for ( auto act : actions ) { - ifstream contract_file( context+"/"+contract+"."+act+"_rc.md" ); - if ( !contract_file.good() ) - wlog("Warning, no ricardian contract found for ${act}\n", ("act", act)); - else { - parse_contract( contract_file ); - } - } - } - - vector get_clauses() { - return _clauses; - } - string operator[]( string key ) { - return _contracts[key]; - } - private: - inline string is_clause_decl( string line ) { - smatch match; - if ( regex_match( line, match, regex("(###[ ]+CLAUSE[ ]+NAME[ ]*:[ ]*)(.*)", regex_constants::ECMAScript) ) ) { - EOS_ASSERT( match.size() == 3, invalid_ricardian_clause_exception, "Error, malformed clause declaration" ); - return match[2].str(); - } - return {}; - } - - inline string is_action_decl( string line ) { - smatch match; - if ( regex_match( line, match, regex("(##[ ]+ACTION[ ]+NAME[ ]*:[ ]*)(.*)", regex_constants::ECMAScript) ) ) { - EOS_ASSERT( match.size() == 3, invalid_ricardian_action_exception, "Error, malformed action declaration" ); - return match[2].str(); - } - return {}; - } - - void parse_contract( ifstream& contract_file ) { - string line; - string name; - string _name; - stringstream body; - bool first_time = true; - while ( contract_file.peek() != EOF ) { - getline( contract_file, line ); - body << line; - if ( !(_name = is_action_decl( line )).empty() ) { - name = _name; - first_time = false; - } - else - if ( !first_time ) - body << line << '\n'; - } - - _contracts.emplace(name, body.str()); - } - - void parse_clauses( ifstream& clause_file ) { - string line; - string name; - string _name; - stringstream body; - bool first_time = true; - while ( clause_file.peek() != EOF ) { - getline( clause_file, line ); - - if ( !(_name = is_clause_decl( line )).empty() ) { - if ( !first_time ) { - if (body.str().empty() ) { - EOS_ASSERT( false, invalid_ricardian_clause_exception, "Error, invalid input in ricardian clauses, no body found" ); - } - _clauses.emplace_back( name, body.str() ); - body.str(""); - } - name = _name; - first_time = false; - } - else - if ( !first_time ) - body << line << '\n'; - } - - } - vector _clauses; - map _contracts; - }; - - /** - * @brief Generates eosio::abi_def struct handling events from ASTConsumer - */ - class abi_generator { - private: - static constexpr size_t max_recursion_depth = 25; // arbitrary depth to prevent infinite recursion - bool verbose; - int optimizations; - abi_def* output; - CompilerInstance* compiler_instance; - map type_size; - map full_types; - string abi_context; - clang::ASTContext* ast_context; - string target_contract; - vector target_actions; - ricardian_contracts rc; - - public: - - enum optimization { - OPT_SINGLE_FIELD_STRUCT - }; - - abi_generator() - : verbose(false) - , optimizations(0) - , output(nullptr) - , compiler_instance(nullptr) - , ast_context(nullptr) - {} - - ~abi_generator() {} - - /** - * @brief Enable optimization when generating ABI - * @param o optimization to enable - */ - void enable_optimizaton(optimization o); - - /** - * @brief Check if an optimization is enabled - * @param o optimization to check - */ - bool is_opt_enabled(optimization o); - - /** - * @brief Set the destination ABI struct to write - * @param output ABI destination - */ - void set_output(abi_def& output); - - /** - * @brief Enable/Disable verbose status messages - * @param verbose enable/disable flag - */ - void set_verbose(bool verbose); - - /** - * @brief Set the root folder that limits where types will be imported. Types declared in header files located in child sub-folders will also be exported - * @param abi_context folder - */ - void set_abi_context(const string& abi_context); - - /** - * @brief Set the ricardian_contracts object with parsed contracts and clauses - * @param ricardian_contracts contracts - */ - void set_ricardian_contracts(const ricardian_contracts& contracts); - - - /** - * @brief Set the single instance of the Clang compiler - * @param compiler_instance compiler instance - */ - void set_compiler_instance(CompilerInstance& compiler_instance); - - /** - * @brief Handle declaration of struct/union/enum - * @param tag_decl declaration to handle - */ - void handle_tagdecl_definition(TagDecl* tag_decl); - - void set_target_contract(const string& contract, const vector& actions); - - private: - bool inspect_type_methods_for_actions(const Decl* decl); - - string remove_namespace(const string& full_name); - - bool is_builtin_type(const string& type_name); - - string translate_type(const string& type_name); - - void handle_decl(const Decl* decl); - - bool is_64bit(const string& type); - - bool is_128bit(const string& type); - - bool is_string(const string& type); - - void get_all_fields(const struct_def& s, vector& fields); - - bool is_i64i64i64_index(const vector& fields); - - bool is_i64_index(const vector& fields); - - bool is_i128i128_index(const vector& fields); - - bool is_str_index(const vector& fields); - - void guess_index_type(table_def& table, const struct_def s); - - void guess_key_names(table_def& table, const struct_def s); - - const table_def* find_table(const table_name& name); - - const type_def* find_type(const type_name& new_type_name); - - const action_def* find_action(const action_name& name); - - const struct_def* find_struct(const type_name& name); - - type_name resolve_type(const type_name& type); - - bool is_one_filed_no_base(const string& type_name); - - string decl_to_string(clang::Decl* d); - - bool is_typedef(const clang::QualType& qt); - QualType add_typedef(const clang::QualType& qt, size_t recursion_depth); - - bool is_vector(const clang::QualType& qt); - bool is_vector(const string& type_name); - string add_vector(const clang::QualType& qt, size_t recursion_depth); - - bool is_struct(const clang::QualType& qt); - string add_struct(const clang::QualType& qt, string full_type_name, size_t recursion_depth); - - string get_type_name(const clang::QualType& qt, bool no_namespace); - string add_type(const clang::QualType& tqt, size_t recursion_depth); - - bool is_elaborated(const clang::QualType& qt); - bool is_struct_specialization(const clang::QualType& qt); - - QualType get_vector_element_type(const clang::QualType& qt); - string get_vector_element_type(const string& type_name); - - clang::QualType get_named_type_if_elaborated(const clang::QualType& qt); - - const clang::RecordDecl::field_range get_struct_fields(const clang::QualType& qt); - clang::CXXRecordDecl::base_class_range get_struct_bases(const clang::QualType& qt); - }; - - struct abi_generator_astconsumer : public ASTConsumer { - abi_generator& abi_gen; - - abi_generator_astconsumer(CompilerInstance& compiler_instance, abi_generator& abi_gen) - :abi_gen(abi_gen) - { - abi_gen.set_compiler_instance(compiler_instance); - } - - void HandleTagDeclDefinition(TagDecl* tag_decl) override { - abi_gen.handle_tagdecl_definition(tag_decl); - } - }; - - struct find_eosio_abi_macro_action : public PreprocessOnlyAction { - - string& contract; - vector& actions; - const string& abi_context; - - find_eosio_abi_macro_action(string& contract, vector& actions, const string& abi_context - ): contract(contract), - actions(actions), abi_context(abi_context) { - } - - struct callback_handler : public PPCallbacks { - - CompilerInstance& compiler_instance; - find_eosio_abi_macro_action& act; - - callback_handler(CompilerInstance& compiler_instance, find_eosio_abi_macro_action& act) - : compiler_instance(compiler_instance), act(act) {} - - string remove_namespace(const string& full_name) { - int i = full_name.size(); - int on_spec = 0; - int colons = 0; - while( --i >= 0 ) { - if( full_name[i] == '>' ) { - ++on_spec; colons=0; - } else if( full_name[i] == '<' ) { - --on_spec; colons=0; - } else if( full_name[i] == ':' && !on_spec) { - if (++colons == 2) - return full_name.substr(i+2); - } else { - colons = 0; - } - } - return full_name; - } - - void MacroExpands (const Token &token, const MacroDefinition &md, SourceRange range, const MacroArgs *args) override { - - auto* id = token.getIdentifierInfo(); - if( id == nullptr ) return; - if( id->getName() != "EOSIO_ABI" ) return; - - const auto& sm = compiler_instance.getSourceManager(); - auto file_name = sm.getFilename(range.getBegin()); - if ( !act.abi_context.empty() && !file_name.startswith(act.abi_context) ) { - return; - } - - ABI_ASSERT( md.getMacroInfo()->getNumArgs() == 2 ); - - clang::SourceLocation b(range.getBegin()), _e(range.getEnd()); - clang::SourceLocation e(clang::Lexer::getLocForEndOfToken(_e, 0, sm, compiler_instance.getLangOpts())); - auto macrostr = string(sm.getCharacterData(b), sm.getCharacterData(e)-sm.getCharacterData(b)); - - regex r(R"(EOSIO_ABI\s*\(\s*(.+?)\s*,((?:.+?)*)\s*\))"); - smatch smatch; - auto res = regex_search(macrostr, smatch, r); - ABI_ASSERT( res ); - - act.contract = remove_namespace(smatch[1].str()); - - auto actions_str = smatch[2].str(); - boost::trim(actions_str); - actions_str = actions_str.substr(1); - actions_str.pop_back(); - boost::remove_erase_if(actions_str, boost::is_any_of(" (")); - - boost::split(act.actions, actions_str, boost::is_any_of(")")); - } - }; - - void ExecuteAction() override { - getCompilerInstance().getPreprocessor().addPPCallbacks( - llvm::make_unique(getCompilerInstance(), *this) - ); - PreprocessOnlyAction::ExecuteAction(); - }; - - }; - - - class generate_abi_action : public ASTFrontendAction { - - private: - set parsed_templates; - abi_generator abi_gen; - - public: - - generate_abi_action(bool verbose, bool opt_sfs, string abi_context, - abi_def& output, const string& contract, const vector& actions) { - - ricardian_contracts rc( abi_context, contract, actions ); - abi_gen.set_output(output); - abi_gen.set_verbose(verbose); - abi_gen.set_abi_context(abi_context); - abi_gen.set_target_contract(contract, actions); - abi_gen.set_ricardian_contracts( rc ); - output.ricardian_clauses = rc.get_clauses(); - - if(opt_sfs) - abi_gen.enable_optimizaton(abi_generator::OPT_SINGLE_FIELD_STRUCT); - } - - protected: - std::unique_ptr CreateASTConsumer(CompilerInstance& compiler_instance, - llvm::StringRef) override { - return llvm::make_unique(compiler_instance, abi_gen); - } - }; - -} //ns eosio - -#pragma pop_macro("N") diff --git a/libraries/appbase b/libraries/appbase index f3a63c1c04d..1d6e6e4a0b3 160000 --- a/libraries/appbase +++ b/libraries/appbase @@ -1 +1 @@ -Subproject commit f3a63c1c04df957c0675b51d298851c71d6ccbe7 +Subproject commit 1d6e6e4a0b334553658fe05cfa1e86081b6d0b4a diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index a8eeadaa94a..2c430fecea0 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -46,11 +46,11 @@ add_library( eosio_chain # contracts/chain_initializer.cpp -# transaction_metadata.cpp + transaction_metadata.cpp ${HEADERS} ) -target_link_libraries( eosio_chain eos_utilities fc chainbase Logging IR WAST WASM Runtime +target_link_libraries( eosio_chain fc chainbase Logging IR WAST WASM Runtime softfloat builtins wabt ) target_include_directories( eosio_chain diff --git a/libraries/chain/abi_serializer.cpp b/libraries/chain/abi_serializer.cpp index b5f67e51059..2f453e0cf93 100644 --- a/libraries/chain/abi_serializer.cpp +++ b/libraries/chain/abi_serializer.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 4e9807ed85c..44a3970f230 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -54,7 +54,7 @@ void apply_context::exec_one( action_trace& trace ) privileged = a.privileged; auto native = control.find_apply_handler( receiver, act.account, act.name ); if( native ) { - if( trx_context.can_subjectively_fail && control.is_producing_block() ) { + if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) { control.check_contract_list( receiver ); control.check_action_list( act.account, act.name ); } @@ -64,7 +64,7 @@ void apply_context::exec_one( action_trace& trace ) if( a.code.size() > 0 && !(act.account == config::system_account_name && act.name == N( setcode ) && receiver == config::system_account_name) ) { - if( trx_context.can_subjectively_fail && control.is_producing_block() ) { + if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) { control.check_contract_list( receiver ); control.check_action_list( act.account, act.name ); } @@ -209,6 +209,9 @@ void apply_context::execute_inline( action&& a ) { EOS_ASSERT( code != nullptr, action_validate_exception, "inline action's code account ${account} does not exist", ("account", a.account) ); + bool enforce_actor_whitelist_blacklist = trx_context.enforce_whiteblacklist && control.is_producing_block(); + flat_set actors; + bool disallow_send_to_self_bypass = false; // eventually set to whether the appropriate protocol feature has been activated bool send_to_self = (a.account == receiver); bool inherit_parent_authorizations = (!disallow_send_to_self_bypass && send_to_self && (receiver == act.account) && control.is_producing_block()); @@ -225,12 +228,18 @@ void apply_context::execute_inline( action&& a ) { EOS_ASSERT( control.get_authorization_manager().find_permission(auth) != nullptr, action_validate_exception, "inline action's authorizations include a non-existent permission: ${permission}", ("permission", auth) ); + if( enforce_actor_whitelist_blacklist ) + actors.insert( auth.actor ); if( inherit_parent_authorizations && std::find(act.authorization.begin(), act.authorization.end(), auth) != act.authorization.end() ) { inherited_authorizations.insert( auth ); } } + if( enforce_actor_whitelist_blacklist ) { + control.check_actor_list( actors ); + } + // No need to check authorization if replaying irreversible blocks or contract is privileged if( !control.skip_auth_check() && !privileged ) { try { @@ -285,7 +294,10 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a EOS_ASSERT( trx.context_free_actions.size() == 0, cfa_inside_generated_tx, "context free actions are not currently allowed in generated transactions" ); trx.expiration = control.pending_block_time() + fc::microseconds(999'999); // Rounds up to nearest second (makes expiration check unnecessary) trx.set_reference_block(control.head_block_id()); // No TaPoS check necessary - control.validate_referenced_accounts( trx ); + + bool enforce_actor_whitelist_blacklist = trx_context.enforce_whiteblacklist && control.is_producing_block() + && !control.sender_avoids_whitelist_blacklist_enforcement( receiver ); + trx_context.validate_referenced_accounts( trx, enforce_actor_whitelist_blacklist ); // Charge ahead of time for the additional net usage needed to retire the deferred transaction // whether that be by successfully executing, soft failure, hard failure, or expiration. @@ -513,9 +525,8 @@ int apply_context::db_store_i64( uint64_t code, uint64_t scope, uint64_t table, const auto& obj = db.create( [&]( auto& o ) { o.t_id = tableid; o.primary_key = id; - o.value.resize( buffer_size ); + o.value.assign( buffer, buffer_size ); o.payer = payer; - memcpy( o.value.data(), buffer, buffer_size ); }); db.modify( tab, [&]( auto& t ) { @@ -554,8 +565,7 @@ void apply_context::db_update_i64( int iterator, account_name payer, const char* } db.modify( obj, [&]( auto& o ) { - o.value.resize( buffer_size ); - memcpy( o.value.data(), buffer, buffer_size ); + o.value.assign( buffer, buffer_size ); o.payer = payer; }); } diff --git a/libraries/chain/asset.cpp b/libraries/chain/asset.cpp index 142e04cffa3..580156f6d21 100644 --- a/libraries/chain/asset.cpp +++ b/libraries/chain/asset.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/libraries/chain/authorization_manager.cpp b/libraries/chain/authorization_manager.cpp index 6725468cf97..e69f7129121 100644 --- a/libraries/chain/authorization_manager.cpp +++ b/libraries/chain/authorization_manager.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/libraries/chain/block_header.cpp b/libraries/chain/block_header.cpp index b73338b3ca2..bbc9de7b06b 100644 --- a/libraries/chain/block_header.cpp +++ b/libraries/chain/block_header.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 2ae15af7341..70bcfa3a236 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -58,8 +58,6 @@ namespace eosio { namespace chain { result.blockroot_merkle = blockroot_merkle; result.blockroot_merkle.append( id ); - auto block_mroot = result.blockroot_merkle.get_root(); - result.active_schedule = active_schedule; result.pending_schedule = pending_schedule; result.dpos_proposed_irreversible_blocknum = dpos_proposed_irreversible_blocknum; @@ -143,7 +141,7 @@ namespace eosio { namespace chain { * * If the header specifies new_producers then apply them accordingly. */ - block_header_state block_header_state::next( const signed_block_header& h, bool trust )const { + block_header_state block_header_state::next( const signed_block_header& h, bool skip_validate_signee )const { EOS_ASSERT( h.timestamp != block_timestamp_type(), block_validate_exception, "", ("h",h) ); //EOS_ASSERT( h.header_extensions.size() == 0, block_validate_exception, "no supported extensions" ); @@ -180,9 +178,8 @@ namespace eosio { namespace chain { // ASSUMPTION FROM controller_impl::apply_block = all untrusted blocks will have their signatures pre-validated here - if( !trust ) { - EOS_ASSERT( result.block_signing_key == result.signee(), wrong_signing_key, "block not signed by expected key", - ("result.block_signing_key", result.block_signing_key)("signee", result.signee() ) ); + if( !skip_validate_signee ) { + result.verify_signee( result.signee() ); } return result; @@ -238,6 +235,11 @@ namespace eosio { namespace chain { return fc::crypto::public_key( header.producer_signature, sig_digest(), true ); } + void block_header_state::verify_signee( const public_key_type& signee )const { + EOS_ASSERT( block_signing_key == signee, wrong_signing_key, "block not signed by expected key", + ("block_signing_key", block_signing_key)( "signee", signee ) ); + } + void block_header_state::add_confirmation( const header_confirmation& conf ) { for( const auto& c : confirmations ) EOS_ASSERT( c.producer != conf.producer, producer_double_confirm, "block already confirmed by this producer" ); diff --git a/libraries/chain/block_log.cpp b/libraries/chain/block_log.cpp index dc769cc9612..41e9756483e 100644 --- a/libraries/chain/block_log.cpp +++ b/libraries/chain/block_log.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include @@ -473,7 +473,7 @@ namespace eosio { namespace chain { old_block_stream.read( reinterpret_cast(&tmp_pos), sizeof(tmp_pos) ); } if( pos != tmp_pos ) { - bad_block = tmp; + bad_block.emplace(std::move(tmp)); break; } diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index f62da8655df..b4834775951 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -10,9 +10,9 @@ namespace eosio { namespace chain { static_cast(*block) = header; } - block_state::block_state( const block_header_state& prev, signed_block_ptr b, bool trust ) - :block_header_state( prev.next( *b, trust )), block( move(b) ) - { } + block_state::block_state( const block_header_state& prev, signed_block_ptr b, bool skip_validate_signee ) + :block_header_state( prev.next( *b, skip_validate_signee )), block( move(b) ) + { } diff --git a/libraries/chain/chain_config.cpp b/libraries/chain/chain_config.cpp index efb66bba95f..c39d89cee46 100644 --- a/libraries/chain/chain_config.cpp +++ b/libraries/chain/chain_config.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/libraries/chain/chain_id_type.cpp b/libraries/chain/chain_id_type.cpp index efddb213c6f..634d4623c98 100644 --- a/libraries/chain/chain_id_type.cpp +++ b/libraries/chain/chain_id_type.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include @@ -8,7 +8,7 @@ namespace eosio { namespace chain { - void chain_id_type::reflector_verify()const { + void chain_id_type::reflector_init()const { EOS_ASSERT( *reinterpret_cast(this) != fc::sha256(), chain_id_type_exception, "chain_id_type cannot be zero" ); } diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index dd5a85ba2df..5853f1ff1ec 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -16,14 +17,13 @@ #include #include #include +#include #include #include #include - #include -#include namespace eosio { namespace chain { @@ -136,6 +136,7 @@ struct controller_impl { optional subjective_cpu_leeway; bool trusted_producer_light_validation = false; uint32_t snapshot_head_block = 0; + boost::asio::thread_pool thread_pool; typedef pair handler_key; map< account_name, map > apply_handlers; @@ -145,7 +146,7 @@ struct controller_impl { * are removed from this list if they are re-applied in other blocks. Producers * can query this list when scheduling new transactions into blocks. */ - map unapplied_transactions; + unapplied_transactions_type unapplied_transactions; void pop_block() { auto prev = fork_db.get_block( head->header.previous ); @@ -186,7 +187,8 @@ struct controller_impl { authorization( s, db ), conf( cfg ), chain_id( cfg.genesis.compute_chain_id() ), - read_mode( cfg.read_mode ) + read_mode( cfg.read_mode ), + thread_pool( cfg.thread_pool_size ) { #define SET_APP_HANDLER( receiver, contract, action) \ @@ -299,22 +301,25 @@ struct controller_impl { } } - void replay() { + void replay(std::function shutdown) { auto blog_head = blog.read_head(); auto blog_head_time = blog_head->timestamp.to_time_point(); replaying = true; replay_head_time = blog_head_time; - ilog( "existing block log, attempting to replay ${n} blocks", ("n",blog_head->block_num()) ); + auto start_block_num = head->block_num + 1; + ilog( "existing block log, attempting to replay from ${s} to ${n} blocks", + ("s", start_block_num)("n", blog_head->block_num()) ); auto start = fc::time_point::now(); while( auto next = blog.read_block_by_num( head->block_num + 1 ) ) { - self.push_block( next, controller::block_status::irreversible ); + replay_push_block( next, controller::block_status::irreversible ); if( next->block_num() % 100 == 0 ) { std::cerr << std::setw(10) << next->block_num() << " of " << blog_head->block_num() <<"\r"; + if( shutdown() ) break; } } std::cerr<< "\n"; - ilog( "${n} blocks replayed", ("n", head->block_num) ); + ilog( "${n} blocks replayed", ("n", head->block_num - start_block_num) ); // if the irreverible log is played without undo sessions enabled, we need to sync the // revision ordinal to the appropriate expected value here. @@ -324,46 +329,52 @@ struct controller_impl { int rev = 0; while( auto obj = reversible_blocks.find(head->block_num+1) ) { ++rev; - self.push_block( obj->get_block(), controller::block_status::validated ); + replay_push_block( obj->get_block(), controller::block_status::validated ); } ilog( "${n} reversible blocks replayed", ("n",rev) ); auto end = fc::time_point::now(); ilog( "replayed ${n} blocks in ${duration} seconds, ${mspb} ms/block", - ("n", head->block_num)("duration", (end-start).count()/1000000) - ("mspb", ((end-start).count()/1000.0)/head->block_num) ); + ("n", head->block_num - start_block_num)("duration", (end-start).count()/1000000) + ("mspb", ((end-start).count()/1000.0)/(head->block_num-start_block_num)) ); replaying = false; replay_head_time.reset(); } - void init(const snapshot_reader_ptr& snapshot) { + void init(std::function shutdown, const snapshot_reader_ptr& snapshot) { + bool report_integrity_hash = !!snapshot; if (snapshot) { - EOS_ASSERT(!head, fork_database_exception, ""); + EOS_ASSERT( !head, fork_database_exception, "" ); snapshot->validate(); - read_from_snapshot(snapshot); + read_from_snapshot( snapshot ); auto end = blog.read_head(); if( !end ) { - blog.reset(conf.genesis, signed_block_ptr(), head->block_num + 1); - } else if ( end->block_num() > head->block_num) { - replay(); + blog.reset( conf.genesis, signed_block_ptr(), head->block_num + 1 ); + } else if( end->block_num() > head->block_num ) { + replay( shutdown ); } else { - EOS_ASSERT(end->block_num() == head->block_num, fork_database_exception, - "Block log is provided with snapshot but does not contain the head block from the snapshot"); + EOS_ASSERT( end->block_num() == head->block_num, fork_database_exception, + "Block log is provided with snapshot but does not contain the head block from the snapshot" ); + } + } else { + if( !head ) { + initialize_fork_db(); // set head to genesis state } - } else if( !head ) { - initialize_fork_db(); // set head to genesis state auto end = blog.read_head(); - if( end && end->block_num() > 1 ) { - replay(); - } else if( !end ) { + if( !end ) { blog.reset( conf.genesis, head->block ); + } else if( end->block_num() > head->block_num ) { + replay( shutdown ); + report_integrity_hash = true; } } + if( shutdown() ) return; + const auto& ubi = reversible_blocks.get_index(); auto objitr = ubi.rbegin(); if( objitr != ubi.rend() ) { @@ -389,7 +400,7 @@ struct controller_impl { db.undo(); } - if( snapshot ) { + if( report_integrity_hash ) { const auto hash = calculate_integrity_hash(); ilog( "database initialized with hash: ${hash}", ("hash", hash) ); } @@ -767,7 +778,7 @@ struct controller_impl { try { if (add_to_fork_db) { pending->_pending_block_state->validated = true; - auto new_bsp = fork_db.add(pending->_pending_block_state); + auto new_bsp = fork_db.add(pending->_pending_block_state, true); emit(self.accepted_block_header, pending->_pending_block_state); head = fork_db.head(); EOS_ASSERT(new_bsp == head, fork_database_exception, "committed block did not become the new head in fork database"); @@ -816,7 +827,10 @@ struct controller_impl { fc::time_point start, uint32_t& cpu_time_to_bill_us, // only set on failure uint32_t billed_cpu_time_us, - bool explicit_billed_cpu_time = false ) { + bool explicit_billed_cpu_time = false, + bool enforce_whiteblacklist = true + ) + { signed_transaction etrx; // Deliver onerror action containing the failed deferred transaction directly back to the sender. etrx.actions.emplace_back( vector{{gtrx.sender, config::active_name}}, @@ -828,6 +842,7 @@ struct controller_impl { trx_context.deadline = deadline; trx_context.explicit_billed_cpu_time = explicit_billed_cpu_time; trx_context.billed_cpu_time_us = billed_cpu_time_us; + trx_context.enforce_whiteblacklist = enforce_whiteblacklist; transaction_trace_ptr trace = trx_context.trace; try { trx_context.init_for_implicit_trx(); @@ -946,9 +961,15 @@ struct controller_impl { trx_context.deadline = deadline; trx_context.explicit_billed_cpu_time = explicit_billed_cpu_time; trx_context.billed_cpu_time_us = billed_cpu_time_us; + trx_context.enforce_whiteblacklist = gtrx.sender.empty() ? true : !sender_avoids_whitelist_blacklist_enforcement( gtrx.sender ); trace = trx_context.trace; try { trx_context.init_for_deferred_trx( gtrx.published ); + + if( trx_context.enforce_whiteblacklist && pending->_block_status == controller::block_status::incomplete ) { + check_actor_list( trx_context.bill_to_accounts ); // Assumes bill_to_accounts is the set of actors authorizing the transaction + } + trx_context.exec(); trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful @@ -982,8 +1003,10 @@ struct controller_impl { if( gtrx.sender != account_name() && !failure_is_subjective(*trace->except)) { // Attempt error handling for the generated transaction. - dlog("${detail}", ("detail", trace->except->to_detail_string())); - auto error_trace = apply_onerror( gtrx, deadline, trx_context.pseudo_start, cpu_time_to_bill_us, billed_cpu_time_us, explicit_billed_cpu_time ); + + auto error_trace = apply_onerror( gtrx, deadline, trx_context.pseudo_start, + cpu_time_to_bill_us, billed_cpu_time_us, explicit_billed_cpu_time, + trx_context.enforce_whiteblacklist ); error_trace->failed_dtrx_trace = trace; trace = error_trace; if( !trace->except_ptr ) { @@ -1067,7 +1090,19 @@ struct controller_impl { transaction_trace_ptr trace; try { - transaction_context trx_context(self, trx->trx, trx->id); + auto start = fc::time_point::now(); + if( !explicit_billed_cpu_time ) { + fc::microseconds already_consumed_time( EOS_PERCENT(trx->sig_cpu_usage.count(), conf.sig_cpu_bill_pct) ); + + if( start.time_since_epoch() < already_consumed_time ) { + start = fc::time_point(); + } else { + start -= already_consumed_time; + } + } + + const signed_transaction& trn = trx->packed_trx->get_signed_transaction(); + transaction_context trx_context(self, trn, trx->id, start); if ((bool)subjective_cpu_leeway && pending->_block_status == controller::block_status::incomplete) { trx_context.leeway = *subjective_cpu_leeway; } @@ -1078,25 +1113,18 @@ struct controller_impl { try { if( trx->implicit ) { trx_context.init_for_implicit_trx(); - trx_context.can_subjectively_fail = false; + trx_context.enforce_whiteblacklist = false; } else { - bool skip_recording = replay_head_time && (time_point(trx->trx.expiration) <= *replay_head_time); - trx_context.init_for_input_trx( trx->packed_trx.get_unprunable_size(), - trx->packed_trx.get_prunable_size(), - trx->trx.signatures.size(), + bool skip_recording = replay_head_time && (time_point(trn.expiration) <= *replay_head_time); + trx_context.init_for_input_trx( trx->packed_trx->get_unprunable_size(), + trx->packed_trx->get_prunable_size(), skip_recording); } - - if( trx_context.can_subjectively_fail && pending->_block_status == controller::block_status::incomplete ) { - check_actor_list( trx_context.bill_to_accounts ); // Assumes bill_to_accounts is the set of actors authorizing the transaction - } - - - trx_context.delay = fc::seconds(trx->trx.delay_sec); + trx_context.delay = fc::seconds(trn.delay_sec); if( !self.skip_auth_check() && !trx->implicit ) { authorization.check_authorization( - trx->trx.actions, + trn.actions, trx->recover_keys( chain_id ), {}, trx_context.delay, @@ -1115,7 +1143,7 @@ struct controller_impl { transaction_receipt::status_enum s = (trx_context.delay == fc::seconds(0)) ? transaction_receipt::executed : transaction_receipt::delayed; - trace->receipt = push_receipt(trx->packed_trx, s, trx_context.billed_cpu_time_us, trace->net_usage); + trace->receipt = push_receipt(*trx->packed_trx, s, trx_context.billed_cpu_time_us, trace->net_usage); pending->_pending_block_state->trxs.emplace_back(trx); } else { transaction_receipt_header r; @@ -1257,17 +1285,29 @@ struct controller_impl { auto producer_block_id = b->id(); start_block( b->timestamp, b->confirmed, s , producer_block_id); + std::vector packed_transactions; + packed_transactions.reserve( b->transactions.size() ); + for( const auto& receipt : b->transactions ) { + if( receipt.trx.contains()) { + auto& pt = receipt.trx.get(); + auto mtrx = std::make_shared( std::make_shared( pt ) ); + if( !self.skip_auth_check() ) { + transaction_metadata::create_signing_keys_future( mtrx, thread_pool, chain_id, microseconds::maximum() ); + } + packed_transactions.emplace_back( std::move( mtrx ) ); + } + } + pending->_pending_block_state->block->header_extensions = b->header_extensions; pending->_pending_block_state->block->block_extensions = b->block_extensions; transaction_trace_ptr trace; + size_t packed_idx = 0; for( const auto& receipt : b->transactions ) { auto num_pending_receipts = pending->_pending_block_state->block->transactions.size(); if( receipt.trx.contains() ) { - auto& pt = receipt.trx.get(); - auto mtrx = std::make_shared(pt); - trace = push_transaction( mtrx, fc::time_point::maximum(), receipt.cpu_usage_us, true ); + trace = push_transaction( packed_transactions.at(packed_idx++), fc::time_point::maximum(), receipt.cpu_usage_us, true ); } else if( receipt.trx.contains() ) { trace = push_scheduled_transaction( receipt.trx.get(), fc::time_point::maximum(), receipt.cpu_usage_us, true ); } else { @@ -1321,18 +1361,37 @@ struct controller_impl { } } FC_CAPTURE_AND_RETHROW() } /// apply_block + std::future create_block_state_future( const signed_block_ptr& b ) { + EOS_ASSERT( b, block_validate_exception, "null block" ); + + auto id = b->id(); - void push_block( const signed_block_ptr& b, controller::block_status s ) { + // no reason for a block_state if fork_db already knows about block + auto existing = fork_db.get_block( id ); + EOS_ASSERT( !existing, fork_database_exception, "we already know about this block: ${id}", ("id", id) ); + + auto prev = fork_db.get_block( b->previous ); + EOS_ASSERT( prev, unlinkable_block_exception, "unlinkable block ${id}", ("id", id)("previous", b->previous) ); + + return async_thread_pool( thread_pool, [b, prev]() { + const bool skip_validate_signee = false; + return std::make_shared( *prev, move( b ), skip_validate_signee ); + } ); + } + + void push_block( std::future& block_state_future ) { + controller::block_status s = controller::block_status::complete; EOS_ASSERT(!pending, block_validate_exception, "it is not valid to push a block when there is a pending block"); auto reset_prod_light_validation = fc::make_scoped_exit([old_value=trusted_producer_light_validation, this]() { trusted_producer_light_validation = old_value; }); try { - EOS_ASSERT( b, block_validate_exception, "trying to push empty block" ); - EOS_ASSERT( s != controller::block_status::incomplete, block_validate_exception, "invalid block status for a completed block" ); + block_state_ptr new_header_state = block_state_future.get(); + auto& b = new_header_state->block; emit( self.pre_accepted_block, b ); - bool trust = !conf.force_all_checks && (s == controller::block_status::irreversible || s == controller::block_status::validated); - auto new_header_state = fork_db.add( b, trust ); + + fork_db.add( new_header_state, false ); + if (conf.trusted_producers.count(b->producer)) { trusted_producer_light_validation = true; }; @@ -1342,6 +1401,29 @@ struct controller_impl { maybe_switch_forks( s ); } + } FC_LOG_AND_RETHROW( ) + } + + void replay_push_block( const signed_block_ptr& b, controller::block_status s ) { + self.validate_db_available_size(); + self.validate_reversible_available_size(); + + EOS_ASSERT(!pending, block_validate_exception, "it is not valid to push a block when there is a pending block"); + + try { + EOS_ASSERT( b, block_validate_exception, "trying to push empty block" ); + EOS_ASSERT( (s == controller::block_status::irreversible || s == controller::block_status::validated), + block_validate_exception, "invalid block status for replay" ); + emit( self.pre_accepted_block, b ); + const bool skip_validate_signee = !conf.force_all_checks; + auto new_header_state = fork_db.add( b, skip_validate_signee ); + + emit( self.accepted_block_header, new_header_state ); + + if ( read_mode != db_read_mode::IRREVERSIBLE ) { + maybe_switch_forks( s ); + } + // on replay irreversible is not emitted by fork database, so emit it explicitly here if( s == controller::block_status::irreversible ) emit( self.irreversible_block, new_header_state ); @@ -1349,16 +1431,7 @@ struct controller_impl { } FC_LOG_AND_RETHROW( ) } - void push_confirmation( const header_confirmation& c ) { - EOS_ASSERT(!pending, block_validate_exception, "it is not valid to push a confirmation when there is a pending block"); - fork_db.add( c ); - emit( self.accepted_confirmation, c ); - if ( read_mode != db_read_mode::IRREVERSIBLE ) { - maybe_switch_forks(); - } - } - - void maybe_switch_forks( controller::block_status s = controller::block_status::complete ) { + void maybe_switch_forks( controller::block_status s ) { auto new_head = fork_db.head(); if( new_head->header.previous == head->id ) { @@ -1377,13 +1450,13 @@ struct controller_impl { auto branches = fork_db.fetch_branch_from( new_head->id, head->id ); for( auto itr = branches.second.begin(); itr != branches.second.end(); ++itr ) { - fork_db.mark_in_current_chain( *itr , false ); + fork_db.mark_in_current_chain( *itr, false ); pop_block(); } EOS_ASSERT( self.head_block_id() == branches.second.back()->header.previous, fork_database_exception, - "loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail + "loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail - for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr) { + for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr ) { optional except; try { apply_block( (*ritr)->block, (*ritr)->validated ? controller::block_status::validated : controller::block_status::complete ); @@ -1393,7 +1466,7 @@ struct controller_impl { } catch (const fc::exception& e) { except = e; } if (except) { - elog("exception thrown while switching forks ${e}", ("e",except->to_detail_string())); + elog("exception thrown while switching forks ${e}", ("e", except->to_detail_string())); // ritr currently points to the block that threw // if we mark it invalid it will automatically remove all forks built off it. @@ -1403,11 +1476,11 @@ struct controller_impl { // ritr base is a forward itr to the last block successfully applied auto applied_itr = ritr.base(); for( auto itr = applied_itr; itr != branches.first.end(); ++itr ) { - fork_db.mark_in_current_chain( *itr , false ); + fork_db.mark_in_current_chain( *itr, false ); pop_block(); } EOS_ASSERT( self.head_block_id() == branches.second.back()->header.previous, fork_database_exception, - "loss of sync between fork_db and chainbase during fork switch reversal" ); // _should_ never fail + "loss of sync between fork_db and chainbase during fork switch reversal" ); // _should_ never fail // re-apply good blocks for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) { @@ -1418,7 +1491,7 @@ struct controller_impl { throw *except; } // end if exception } /// end for each block in branch - ilog("successfully switched fork to new head ${new_head_id}", ("new_head_id", new_head->id)); + ilog("successfully switched fork to new head ${new_head_id}", ("new_head_id", new_head->id) ); } } /// push_block @@ -1572,28 +1645,97 @@ struct controller_impl { } } + bool sender_avoids_whitelist_blacklist_enforcement( account_name sender )const { + if( conf.sender_bypass_whiteblacklist.size() > 0 && + ( conf.sender_bypass_whiteblacklist.find( sender ) != conf.sender_bypass_whiteblacklist.end() ) ) + { + return true; + } + + return false; + } void check_actor_list( const flat_set& actors )const { + if( actors.size() == 0 ) return; + if( conf.actor_whitelist.size() > 0 ) { - vector excluded; - excluded.reserve( actors.size() ); - set_difference( actors.begin(), actors.end(), - conf.actor_whitelist.begin(), conf.actor_whitelist.end(), - std::back_inserter(excluded) ); - EOS_ASSERT( excluded.size() == 0, actor_whitelist_exception, + // throw if actors is not a subset of whitelist + const auto& whitelist = conf.actor_whitelist; + bool is_subset = true; + + // quick extents check, then brute force the check actors + if (*actors.cbegin() >= *whitelist.cbegin() && *actors.crbegin() <= *whitelist.crbegin() ) { + auto lower_bound = whitelist.cbegin(); + for (const auto& actor: actors) { + lower_bound = std::lower_bound(lower_bound, whitelist.cend(), actor); + + // if the actor is not found, this is not a subset + if (lower_bound == whitelist.cend() || *lower_bound != actor ) { + is_subset = false; + break; + } + + // if the actor was found, we are guaranteed that other actors are either not present in the whitelist + // or will be present in the range defined as [next actor,end) + lower_bound = std::next(lower_bound); + } + } else { + is_subset = false; + } + + // helper lambda to lazily calculate the actors for error messaging + static auto generate_missing_actors = [](const flat_set& actors, const flat_set& whitelist) -> vector { + vector excluded; + excluded.reserve( actors.size() ); + set_difference( actors.begin(), actors.end(), + whitelist.begin(), whitelist.end(), + std::back_inserter(excluded) ); + return excluded; + }; + + EOS_ASSERT( is_subset, actor_whitelist_exception, "authorizing actor(s) in transaction are not on the actor whitelist: ${actors}", - ("actors", excluded) + ("actors", generate_missing_actors(actors, whitelist)) ); } else if( conf.actor_blacklist.size() > 0 ) { - vector blacklisted; - blacklisted.reserve( actors.size() ); - set_intersection( actors.begin(), actors.end(), - conf.actor_blacklist.begin(), conf.actor_blacklist.end(), - std::back_inserter(blacklisted) - ); - EOS_ASSERT( blacklisted.size() == 0, actor_blacklist_exception, + // throw if actors intersects blacklist + const auto& blacklist = conf.actor_blacklist; + bool intersects = false; + + // quick extents check then brute force check actors + if( *actors.cbegin() <= *blacklist.crbegin() && *actors.crbegin() >= *blacklist.cbegin() ) { + auto lower_bound = blacklist.cbegin(); + for (const auto& actor: actors) { + lower_bound = std::lower_bound(lower_bound, blacklist.cend(), actor); + + // if the lower bound in the blacklist is at the end, all other actors are guaranteed to + // not exist in the blacklist + if (lower_bound == blacklist.cend()) { + break; + } + + // if the lower bound of an actor IS the actor, then we have an intersection + if (*lower_bound == actor) { + intersects = true; + break; + } + } + } + + // helper lambda to lazily calculate the actors for error messaging + static auto generate_blacklisted_actors = [](const flat_set& actors, const flat_set& blacklist) -> vector { + vector blacklisted; + blacklisted.reserve( actors.size() ); + set_intersection( actors.begin(), actors.end(), + blacklist.begin(), blacklist.end(), + std::back_inserter(blacklisted) + ); + return blacklisted; + }; + + EOS_ASSERT( !intersects, actor_blacklist_exception, "authorizing actor(s) in transaction are on the actor blacklist: ${actors}", - ("actors", blacklisted) + ("actors", generate_blacklisted_actors(actors, blacklist)) ); } } @@ -1704,12 +1846,12 @@ void controller::add_indices() { my->add_indices(); } -void controller::startup( const snapshot_reader_ptr& snapshot ) { +void controller::startup( std::function shutdown, const snapshot_reader_ptr& snapshot ) { my->head = my->fork_db.head(); if( !my->head ) { elog( "No head block in fork db, perhaps we need to replay" ); } - my->init(snapshot); + my->init(shutdown, snapshot); } const chainbase::database& controller::db()const { return my->db; } @@ -1743,15 +1885,18 @@ void controller::abort_block() { my->abort_block(); } -void controller::push_block( const signed_block_ptr& b, block_status s ) { - validate_db_available_size(); - validate_reversible_available_size(); - my->push_block( b, s ); +boost::asio::thread_pool& controller::get_thread_pool() { + return my->thread_pool; +} + +std::future controller::create_block_state_future( const signed_block_ptr& b ) { + return my->create_block_state_future( b ); } -void controller::push_confirmation( const header_confirmation& c ) { +void controller::push_block( std::future& block_state_future ) { validate_db_available_size(); - my->push_confirmation( c ); + validate_reversible_available_size(); + my->push_block( block_state_future ); } transaction_trace_ptr controller::push_transaction( const transaction_metadata_ptr& trx, fc::time_point deadline, uint32_t billed_cpu_time_us ) { @@ -2088,41 +2233,20 @@ const account_object& controller::get_account( account_name name )const return my->db.get(name); } FC_CAPTURE_AND_RETHROW( (name) ) } -vector controller::get_unapplied_transactions() const { - vector result; - if ( my->read_mode == db_read_mode::SPECULATIVE ) { - result.reserve(my->unapplied_transactions.size()); - for ( const auto& entry: my->unapplied_transactions ) { - result.emplace_back(entry.second); - } - } else { - EOS_ASSERT( my->unapplied_transactions.empty(), transaction_exception, "not empty unapplied_transactions in non-speculative mode" ); //should never happen +unapplied_transactions_type& controller::get_unapplied_transactions() { + if ( my->read_mode != db_read_mode::SPECULATIVE ) { + EOS_ASSERT( my->unapplied_transactions.empty(), transaction_exception, + "not empty unapplied_transactions in non-speculative mode" ); //should never happen } - return result; -} - -void controller::drop_unapplied_transaction(const transaction_metadata_ptr& trx) { - my->unapplied_transactions.erase(trx->signed_id); + return my->unapplied_transactions; } -void controller::drop_all_unapplied_transactions() { - my->unapplied_transactions.clear(); +bool controller::sender_avoids_whitelist_blacklist_enforcement( account_name sender )const { + return my->sender_avoids_whitelist_blacklist_enforcement( sender ); } -vector controller::get_scheduled_transactions() const { - const auto& idx = db().get_index(); - - vector result; - - static const size_t max_reserve = 64; - result.reserve(std::min(idx.size(), max_reserve)); - - auto itr = idx.begin(); - while( itr != idx.end() && itr->delay_until <= pending_block_time() ) { - result.emplace_back(itr->trx_id); - ++itr; - } - return result; +void controller::check_actor_list( const flat_set& actors )const { + my->check_actor_list( actors ); } void controller::check_contract_list( account_name code )const { @@ -2147,32 +2271,6 @@ bool controller::is_ram_billing_in_notify_allowed()const { return !is_producing_block() || my->conf.allow_ram_billing_in_notify; } -void controller::validate_referenced_accounts( const transaction& trx )const { - for( const auto& a : trx.context_free_actions ) { - auto* code = my->db.find(a.account); - EOS_ASSERT( code != nullptr, transaction_exception, - "action's code account '${account}' does not exist", ("account", a.account) ); - EOS_ASSERT( a.authorization.size() == 0, transaction_exception, - "context-free actions cannot have authorizations" ); - } - bool one_auth = false; - for( const auto& a : trx.actions ) { - auto* code = my->db.find(a.account); - EOS_ASSERT( code != nullptr, transaction_exception, - "action's code account '${account}' does not exist", ("account", a.account) ); - for( const auto& auth : a.authorization ) { - one_auth = true; - auto* actor = my->db.find(auth.actor); - EOS_ASSERT( actor != nullptr, transaction_exception, - "action's authorizing actor '${account}' does not exist", ("account", auth.actor) ); - EOS_ASSERT( my->authorization.find_permission(auth) != nullptr, transaction_exception, - "action's authorizations include a non-existent permission: {permission}", - ("permission", auth) ); - } - } - EOS_ASSERT( one_auth, tx_no_auths, "transaction must have at least one authorization" ); -} - void controller::validate_expiration( const transaction& trx )const { try { const auto& chain_configuration = get_global_properties().configuration; diff --git a/libraries/chain/eosio_contract.cpp b/libraries/chain/eosio_contract.cpp index 33a123981a1..03e0fed7f7f 100644 --- a/libraries/chain/eosio_contract.cpp +++ b/libraries/chain/eosio_contract.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include @@ -57,7 +57,7 @@ void validate_authority_precondition( const apply_context& context, const author } } - if( context.control.is_producing_block() ) { + if( context.trx_context.enforce_whiteblacklist && context.control.is_producing_block() ) { for( const auto& p : auth.keys ) { context.control.check_key_list( p.key ); } @@ -155,10 +155,11 @@ void apply_eosio_setcode(apply_context& context) { // TODO: update setcode message to include the hash, then validate it in validate a.last_code_update = context.control.pending_block_time(); a.code_version = code_id; - a.code.resize( code_size ); - if( code_size > 0 ) - memcpy( a.code.data(), act.code.data(), code_size ); - + if ( code_size > 0 ) { + a.code.assign(act.code.data(), code_size); + } else { + a.code.resize(0); + } }); const auto& account_sequence = db.get(act.account); @@ -185,9 +186,11 @@ void apply_eosio_setabi(apply_context& context) { int64_t new_size = abi_size; db.modify( account, [&]( auto& a ) { - a.abi.resize( abi_size ); - if( abi_size > 0 ) - memcpy( a.abi.data(), act.abi.data(), abi_size ); + if (abi_size > 0) { + a.abi.assign(act.abi.data(), abi_size); + } else { + a.abi.resize(0); + } }); const auto& account_sequence = db.get(act.account); @@ -282,7 +285,7 @@ void apply_eosio_deleteauth(apply_context& context) { const auto& index = db.get_index(); auto range = index.equal_range(boost::make_tuple(remove.account, remove.permission)); EOS_ASSERT(range.first == range.second, action_validate_exception, - "Cannot delete a linked authority. Unlink the authority first. This authority is linked to ${code}::${type}.", + "Cannot delete a linked authority. Unlink the authority first. This authority is linked to ${code}::${type}.", ("code", string(range.first->code))("type", string(range.first->message_type))); } diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 317453f19b8..441677bb8a8 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -123,7 +123,16 @@ namespace eosio { namespace chain { } } - block_state_ptr fork_database::add( block_state_ptr n ) { + block_state_ptr fork_database::add( const block_state_ptr& n, bool skip_validate_previous ) { + EOS_ASSERT( n, fork_database_exception, "attempt to add null block state" ); + EOS_ASSERT( my->head, fork_db_block_not_found, "no head block set" ); + + if( !skip_validate_previous ) { + auto prior = my->index.find( n->block->previous ); + EOS_ASSERT( prior != my->index.end(), unlinkable_block_exception, + "unlinkable block", ("id", n->block->id())("previous", n->block->previous) ); + } + auto inserted = my->index.insert(n); EOS_ASSERT( inserted.second, fork_database_exception, "duplicate block added?" ); @@ -139,7 +148,7 @@ namespace eosio { namespace chain { return n; } - block_state_ptr fork_database::add( signed_block_ptr b, bool trust ) { + block_state_ptr fork_database::add( signed_block_ptr b, bool skip_validate_signee ) { EOS_ASSERT( b, fork_database_exception, "attempt to add null block" ); EOS_ASSERT( my->head, fork_db_block_not_found, "no head block set" ); const auto& by_id_idx = my->index.get(); @@ -149,9 +158,9 @@ namespace eosio { namespace chain { auto prior = by_id_idx.find( b->previous ); EOS_ASSERT( prior != by_id_idx.end(), unlinkable_block_exception, "unlinkable block", ("id", string(b->id()))("previous", string(b->previous)) ); - auto result = std::make_shared( **prior, move(b), trust ); + auto result = std::make_shared( **prior, move(b), skip_validate_signee ); EOS_ASSERT( result, fork_database_exception , "fail to add new block state" ); - return add(result); + return add(result, true); } const block_state_ptr& fork_database::head()const { return my->head; } diff --git a/libraries/chain/genesis_state.cpp b/libraries/chain/genesis_state.cpp index 40257a6168b..23d8986e5bd 100644 --- a/libraries/chain/genesis_state.cpp +++ b/libraries/chain/genesis_state.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/libraries/chain/genesis_state_root_key.cpp.in b/libraries/chain/genesis_state_root_key.cpp.in index 6530698e33a..11bbde26397 100644 --- a/libraries/chain/genesis_state_root_key.cpp.in +++ b/libraries/chain/genesis_state_root_key.cpp.in @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/libraries/chain/include/eosio/chain/abi_def.hpp b/libraries/chain/include/eosio/chain/abi_def.hpp index f00dd19884d..9b1d211d623 100644 --- a/libraries/chain/include/eosio/chain/abi_def.hpp +++ b/libraries/chain/include/eosio/chain/abi_def.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index 221424e041e..8f8fca4cdeb 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include @@ -418,11 +418,11 @@ namespace impl { mutable_variant_object mvo; auto trx = ptrx.get_transaction(); mvo("id", trx.id()); - mvo("signatures", ptrx.signatures); - mvo("compression", ptrx.compression); - mvo("packed_context_free_data", ptrx.packed_context_free_data); + mvo("signatures", ptrx.get_signatures()); + mvo("compression", ptrx.get_compression()); + mvo("packed_context_free_data", ptrx.get_packed_context_free_data()); mvo("context_free_data", ptrx.get_context_free_data()); - mvo("packed_trx", ptrx.packed_trx); + mvo("packed_trx", ptrx.get_packed_transaction()); add(mvo, "transaction", trx, resolver, ctx); out(name, std::move(mvo)); @@ -577,32 +577,42 @@ namespace impl { const variant_object& vo = v.get_object(); EOS_ASSERT(vo.contains("signatures"), packed_transaction_type_exception, "Missing signatures"); EOS_ASSERT(vo.contains("compression"), packed_transaction_type_exception, "Missing compression"); - from_variant(vo["signatures"], ptrx.signatures); - from_variant(vo["compression"], ptrx.compression); + std::vector signatures; + packed_transaction::compression_type compression; + from_variant(vo["signatures"], signatures); + from_variant(vo["compression"], compression); + + bytes packed_cfd; + std::vector cfd; + bool use_packed_cfd = false; + if( vo.contains("packed_context_free_data") && vo["packed_context_free_data"].is_string() && !vo["packed_context_free_data"].as_string().empty() ) { + from_variant(vo["packed_context_free_data"], packed_cfd ); + use_packed_cfd = true; + } else if( vo.contains("context_free_data") ) { + from_variant(vo["context_free_data"], cfd); + } - // TODO: Make this nicer eventually. But for now, if it works... good enough. if( vo.contains("packed_trx") && vo["packed_trx"].is_string() && !vo["packed_trx"].as_string().empty() ) { - from_variant(vo["packed_trx"], ptrx.packed_trx); - auto trx = ptrx.get_transaction(); // Validates transaction data provided. - if( vo.contains("packed_context_free_data") && vo["packed_context_free_data"].is_string() && !vo["packed_context_free_data"].as_string().empty() ) { - from_variant(vo["packed_context_free_data"], ptrx.packed_context_free_data ); - } else if( vo.contains("context_free_data") ) { - vector context_free_data; - from_variant(vo["context_free_data"], context_free_data); - ptrx.set_transaction(trx, context_free_data, ptrx.compression); + bytes packed_trx; + from_variant(vo["packed_trx"], packed_trx); + if( use_packed_cfd ) { + ptrx = packed_transaction( std::move( packed_trx ), std::move( signatures ), std::move( packed_cfd ), compression ); + } else { + ptrx = packed_transaction( std::move( packed_trx ), std::move( signatures ), std::move( cfd ), compression ); } } else { EOS_ASSERT(vo.contains("transaction"), packed_transaction_type_exception, "Missing transaction"); - transaction trx; - vector context_free_data; - extract(vo["transaction"], trx, resolver, ctx); - if( vo.contains("packed_context_free_data") && vo["packed_context_free_data"].is_string() && !vo["packed_context_free_data"].as_string().empty() ) { - from_variant(vo["packed_context_free_data"], ptrx.packed_context_free_data ); - context_free_data = ptrx.get_context_free_data(); - } else if( vo.contains("context_free_data") ) { - from_variant(vo["context_free_data"], context_free_data); + if( use_packed_cfd ) { + transaction trx; + extract( vo["transaction"], trx, resolver, ctx ); + ptrx = packed_transaction( std::move(trx), std::move(signatures), std::move(packed_cfd), compression ); + } else { + signed_transaction trx; + extract( vo["transaction"], trx, resolver, ctx ); + trx.signatures = std::move( signatures ); + trx.context_free_data = std::move(cfd); + ptrx = packed_transaction( std::move( trx ), compression ); } - ptrx.set_transaction(trx, context_free_data, ptrx.compression); } } }; @@ -615,11 +625,11 @@ namespace impl { * @tparam Reslover - callable with the signature (const name& code_account) -> optional */ template - class abi_from_variant_visitor : reflector_verifier_visitor + class abi_from_variant_visitor : reflector_init_visitor { public: abi_from_variant_visitor( const variant_object& _vo, T& v, Resolver _resolver, abi_traverse_context& _ctx ) - : reflector_verifier_visitor(v) + : reflector_init_visitor(v) ,_vo(_vo) ,_resolver(_resolver) ,_ctx(_ctx) diff --git a/libraries/chain/include/eosio/chain/account_object.hpp b/libraries/chain/include/eosio/chain/account_object.hpp index 8a945512b3c..b995a8508a1 100644 --- a/libraries/chain/include/eosio/chain/account_object.hpp +++ b/libraries/chain/include/eosio/chain/account_object.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/libraries/chain/include/eosio/chain/action.hpp b/libraries/chain/include/eosio/chain/action.hpp index 9eb989bda91..9912e2f31b7 100644 --- a/libraries/chain/include/eosio/chain/action.hpp +++ b/libraries/chain/include/eosio/chain/action.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/libraries/chain/include/eosio/chain/action_receipt.hpp b/libraries/chain/include/eosio/chain/action_receipt.hpp index 9b5d138117f..17fe4f46713 100644 --- a/libraries/chain/include/eosio/chain/action_receipt.hpp +++ b/libraries/chain/include/eosio/chain/action_receipt.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index 2b68d015442..3909906dbd5 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include @@ -575,12 +575,6 @@ class apply_context { void add_ram_usage( account_name account, int64_t ram_delta ); void finalize_trace( action_trace& trace, const fc::time_point& start ); - private: - - void validate_referenced_accounts( const transaction& t )const; - void validate_expiration( const transaction& t )const; - - /// Fields: public: diff --git a/libraries/chain/include/eosio/chain/asset.hpp b/libraries/chain/include/eosio/chain/asset.hpp index 2c1f2bb4fc3..5c9bb9669bc 100644 --- a/libraries/chain/include/eosio/chain/asset.hpp +++ b/libraries/chain/include/eosio/chain/asset.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include @@ -84,7 +84,7 @@ struct asset friend struct fc::reflector; - void reflector_verify()const { + void reflector_init()const { EOS_ASSERT( is_amount_within_range(), asset_type_exception, "magnitude of asset amount must be less than 2^62" ); EOS_ASSERT( sym.valid(), asset_type_exception, "invalid symbol" ); } diff --git a/libraries/chain/include/eosio/chain/authority.hpp b/libraries/chain/include/eosio/chain/authority.hpp index d59382de2c9..373deb56120 100644 --- a/libraries/chain/include/eosio/chain/authority.hpp +++ b/libraries/chain/include/eosio/chain/authority.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/libraries/chain/include/eosio/chain/authority_checker.hpp b/libraries/chain/include/eosio/chain/authority_checker.hpp index 5f1fdfbfb76..f17eeac10bf 100644 --- a/libraries/chain/include/eosio/chain/authority_checker.hpp +++ b/libraries/chain/include/eosio/chain/authority_checker.hpp @@ -1,14 +1,13 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include #include #include - -#include +#include #include @@ -148,11 +147,11 @@ namespace detail { bool all_keys_used() const { return boost::algorithm::all_of_equal(_used_keys, true); } flat_set used_keys() const { - auto range = utilities::filter_data_by_marker(provided_keys, _used_keys, true); + auto range = filter_data_by_marker(provided_keys, _used_keys, true); return {range.begin(), range.end()}; } flat_set unused_keys() const { - auto range = utilities::filter_data_by_marker(provided_keys, _used_keys, false); + auto range = filter_data_by_marker(provided_keys, _used_keys, false); return {range.begin(), range.end()}; } diff --git a/libraries/chain/include/eosio/chain/authorization_manager.hpp b/libraries/chain/include/eosio/chain/authorization_manager.hpp index a6df7ad2568..3e9ffd0bb42 100644 --- a/libraries/chain/include/eosio/chain/authorization_manager.hpp +++ b/libraries/chain/include/eosio/chain/authorization_manager.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/libraries/chain/include/eosio/chain/block.hpp b/libraries/chain/include/eosio/chain/block.hpp index 28c49f9772e..9cd942026cf 100644 --- a/libraries/chain/include/eosio/chain/block.hpp +++ b/libraries/chain/include/eosio/chain/block.hpp @@ -19,22 +19,22 @@ namespace eosio { namespace chain { }; transaction_receipt_header():status(hard_fail){} - transaction_receipt_header( status_enum s ):status(s){} + explicit transaction_receipt_header( status_enum s ):status(s){} friend inline bool operator ==( const transaction_receipt_header& lhs, const transaction_receipt_header& rhs ) { return std::tie(lhs.status, lhs.cpu_usage_us, lhs.net_usage_words) == std::tie(rhs.status, rhs.cpu_usage_us, rhs.net_usage_words); } fc::enum_type status; - uint32_t cpu_usage_us; ///< total billed CPU usage (microseconds) + uint32_t cpu_usage_us = 0; ///< total billed CPU usage (microseconds) fc::unsigned_int net_usage_words; ///< total billed NET usage, so we can reconstruct resource state when skipping context free data... hard failures... }; struct transaction_receipt : public transaction_receipt_header { transaction_receipt():transaction_receipt_header(){} - transaction_receipt( transaction_id_type tid ):transaction_receipt_header(executed),trx(tid){} - transaction_receipt( packed_transaction ptrx ):transaction_receipt_header(executed),trx(ptrx){} + explicit transaction_receipt( const transaction_id_type& tid ):transaction_receipt_header(executed),trx(tid){} + explicit transaction_receipt( const packed_transaction& ptrx ):transaction_receipt_header(executed),trx(ptrx){} fc::static_variant trx; @@ -58,9 +58,14 @@ namespace eosio { namespace chain { /** */ struct signed_block : public signed_block_header { - using signed_block_header::signed_block_header; + private: + signed_block( const signed_block& ) = default; + public: signed_block() = default; - signed_block( const signed_block_header& h ):signed_block_header(h){} + explicit signed_block( const signed_block_header& h ):signed_block_header(h){} + signed_block( signed_block&& ) = default; + signed_block& operator=(const signed_block&) = delete; + signed_block clone() const { return *this; } vector transactions; /// new or generated transactions extensions_type block_extensions; diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index ecd272353d4..c318843d5df 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include namespace eosio { namespace chain { @@ -51,6 +52,7 @@ struct block_header_state { digest_type sig_digest()const; void sign( const std::function& signer ); public_key_type signee()const; + void verify_signee(const public_key_type& signee)const; }; diff --git a/libraries/chain/include/eosio/chain/block_log.hpp b/libraries/chain/include/eosio/chain/block_log.hpp index 24ff0ad2835..26e1dcb41fa 100644 --- a/libraries/chain/include/eosio/chain/block_log.hpp +++ b/libraries/chain/include/eosio/chain/block_log.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/libraries/chain/include/eosio/chain/block_state.hpp b/libraries/chain/include/eosio/chain/block_state.hpp index 73602023a42..2292392ade4 100644 --- a/libraries/chain/include/eosio/chain/block_state.hpp +++ b/libraries/chain/include/eosio/chain/block_state.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once @@ -12,8 +12,8 @@ namespace eosio { namespace chain { struct block_state : public block_header_state { - block_state( const block_header_state& cur ):block_header_state(cur){} - block_state( const block_header_state& prev, signed_block_ptr b, bool trust = false ); + explicit block_state( const block_header_state& cur ):block_header_state(cur){} + block_state( const block_header_state& prev, signed_block_ptr b, bool skip_validate_signee ); block_state( const block_header_state& prev, block_timestamp_type when ); block_state() = default; diff --git a/libraries/chain/include/eosio/chain/block_summary_object.hpp b/libraries/chain/include/eosio/chain/block_summary_object.hpp index d0224c9a9d5..0bb24ee7976 100644 --- a/libraries/chain/include/eosio/chain/block_summary_object.hpp +++ b/libraries/chain/include/eosio/chain/block_summary_object.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/libraries/chain/include/eosio/chain/chain_config.hpp b/libraries/chain/include/eosio/chain/chain_config.hpp index 907846d1a55..da258010fbb 100644 --- a/libraries/chain/include/eosio/chain/chain_config.hpp +++ b/libraries/chain/include/eosio/chain/chain_config.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once @@ -60,10 +60,50 @@ struct chain_config { << "Max Inline Action Depth: " << c.max_inline_action_depth << ", " << "Max Authority Depth: " << c.max_authority_depth << "\n"; } -}; - bool operator==(const chain_config& a, const chain_config& b); -inline bool operator!=(const chain_config& a, const chain_config& b) { return !(a == b); } + friend inline bool operator ==( const chain_config& lhs, const chain_config& rhs ) { + return std::tie( lhs.max_block_net_usage, + lhs.target_block_net_usage_pct, + lhs.max_transaction_net_usage, + lhs.base_per_transaction_net_usage, + lhs.net_usage_leeway, + lhs.context_free_discount_net_usage_num, + lhs.context_free_discount_net_usage_den, + lhs.max_block_cpu_usage, + lhs.target_block_cpu_usage_pct, + lhs.max_transaction_cpu_usage, + lhs.max_transaction_cpu_usage, + lhs.max_transaction_lifetime, + lhs.deferred_trx_expiration_window, + lhs.max_transaction_delay, + lhs.max_inline_action_size, + lhs.max_inline_action_depth, + lhs.max_authority_depth + ) + == + std::tie( rhs.max_block_net_usage, + rhs.target_block_net_usage_pct, + rhs.max_transaction_net_usage, + rhs.base_per_transaction_net_usage, + rhs.net_usage_leeway, + rhs.context_free_discount_net_usage_num, + rhs.context_free_discount_net_usage_den, + rhs.max_block_cpu_usage, + rhs.target_block_cpu_usage_pct, + rhs.max_transaction_cpu_usage, + rhs.max_transaction_cpu_usage, + rhs.max_transaction_lifetime, + rhs.deferred_trx_expiration_window, + rhs.max_transaction_delay, + rhs.max_inline_action_size, + rhs.max_inline_action_depth, + rhs.max_authority_depth + ); + }; + + friend inline bool operator !=( const chain_config& lhs, const chain_config& rhs ) { return !(lhs == rhs); } + +}; // *bos* struct chain_config2 { diff --git a/libraries/chain/include/eosio/chain/chain_id_type.hpp b/libraries/chain/include/eosio/chain/chain_id_type.hpp index 3b583a65997..a16fc143ae6 100644 --- a/libraries/chain/include/eosio/chain/chain_id_type.hpp +++ b/libraries/chain/include/eosio/chain/chain_id_type.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once @@ -34,7 +34,7 @@ namespace chain { return ds; } - void reflector_verify()const; + void reflector_init()const; private: chain_id_type() = default; diff --git a/libraries/chain/include/eosio/chain/chain_snapshot.hpp b/libraries/chain/include/eosio/chain/chain_snapshot.hpp index 7174e69c5b9..3b3e64f264f 100644 --- a/libraries/chain/include/eosio/chain/chain_snapshot.hpp +++ b/libraries/chain/include/eosio/chain/chain_snapshot.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 6aea7c3e3bd..f34b7702095 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include @@ -80,6 +80,8 @@ const static uint32_t default_max_trx_delay = 45*24*3600; // const static uint32_t default_max_inline_action_size = 4 * 1024; // 4 KB const static uint16_t default_max_inline_action_depth = 4; const static uint16_t default_max_auth_depth = 6; +const static uint32_t default_sig_cpu_bill_pct = 50 * percent_1; // billable percentage of signature recovery +const static uint16_t default_controller_thread_pool_size = 2; const static uint32_t min_net_usage_delta_between_base_and_max_for_trx = 10*1024; // Should be large enough to allow recovery from badly set blockchain parameters without a hard fork diff --git a/libraries/chain/include/eosio/chain/contract_table_objects.hpp b/libraries/chain/include/eosio/chain/contract_table_objects.hpp index b3428340823..dc6b25b0501 100644 --- a/libraries/chain/include/eosio/chain/contract_table_objects.hpp +++ b/libraries/chain/include/eosio/chain/contract_table_objects.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once @@ -131,14 +131,14 @@ namespace eosio { namespace chain { typedef secondary_index::index_index index256_index; struct soft_double_less { - bool operator()( const float64_t& lhs, const float64_t& rhs )const { - return f64_lt(lhs, rhs); + bool operator()( const float64_t& lhs, const float64_t& rhs ) const { + return f64_lt( lhs, rhs ); } }; struct soft_long_double_less { - bool operator()( const float128_t lhs, const float128_t& rhs )const { - return f128_lt(lhs, rhs); + bool operator()( const float128_t& lhs, const float128_t& rhs ) const { + return f128_lt( lhs, rhs ); } }; @@ -147,6 +147,7 @@ namespace eosio { namespace chain { * * The software double implementation is using the Berkeley softfloat library (release 3). */ + typedef secondary_index::index_object index_double_object; typedef secondary_index::index_index index_double_index; @@ -158,6 +159,65 @@ namespace eosio { namespace chain { typedef secondary_index::index_object index_long_double_object; typedef secondary_index::index_index index_long_double_index; + template + struct secondary_key_traits { + using value_type = std::enable_if_t::value, T>; + + static_assert( std::numeric_limits::is_specialized, "value_type does not have specialized numeric_limits" ); + + static constexpr value_type true_lowest() { return std::numeric_limits::lowest(); } + static constexpr value_type true_highest() { return std::numeric_limits::max(); } + }; + + template + struct secondary_key_traits> { + private: + static constexpr uint128_t max_uint128 = (static_cast(std::numeric_limits::max()) << 64) | std::numeric_limits::max(); + static_assert( std::numeric_limits::max() == max_uint128, "numeric_limits for uint128_t is not properly defined" ); + + public: + using value_type = std::array; + + static value_type true_lowest() { + value_type arr; + return arr; + } + + static value_type true_highest() { + value_type arr; + for( auto& v : arr ) { + v = std::numeric_limits::max(); + } + return arr; + } + }; + + template<> + struct secondary_key_traits { + using value_type = float64_t; + + static value_type true_lowest() { + return f64_negative_infinity(); + } + + static value_type true_highest() { + return f64_positive_infinity(); + } + }; + + template<> + struct secondary_key_traits { + using value_type = float128_t; + + static value_type true_lowest() { + return f128_negative_infinity(); + } + + static value_type true_highest() { + return f128_positive_infinity(); + } + }; + /** * helper template to map from an index type to the best tag * to use when traversing by table_id @@ -185,7 +245,7 @@ namespace config { template<> struct billable_size { static const uint64_t overhead = overhead_per_row_per_index_ram_bytes * 2; ///< overhead for 2x indices internal-key and code,scope,table - static const uint64_t value = 44 + overhead; ///< 36 bytes for constant size fields + overhead + static const uint64_t value = 44 + overhead; ///< 44 bytes for constant size fields + overhead }; template<> diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 17ca27b3235..ac3581f580f 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -11,7 +11,9 @@ namespace chainbase { class database; } - +namespace boost { namespace asio { + class thread_pool; +}} namespace eosio { namespace chain { @@ -32,6 +34,7 @@ namespace eosio { namespace chain { class account_object; using resource_limits::resource_limits_manager; using apply_handler = std::function; + using unapplied_transactions_type = map; class fork_database; @@ -66,6 +69,7 @@ namespace eosio { namespace chain { public: struct config { + flat_set sender_bypass_whiteblacklist; flat_set actor_whitelist; flat_set actor_blacklist; flat_set contract_whitelist; @@ -78,6 +82,8 @@ namespace eosio { namespace chain { uint64_t state_guard_size = chain::config::default_state_guard_size; uint64_t reversible_cache_size = chain::config::default_reversible_cache_size; uint64_t reversible_guard_size = chain::config::default_reversible_guard_size; + uint32_t sig_cpu_bill_pct = chain::config::default_sig_cpu_bill_pct; + uint16_t thread_pool_size = chain::config::default_controller_thread_pool_size; bool read_only = false; bool force_all_checks = false; bool disable_replay_opts = false; @@ -101,11 +107,11 @@ namespace eosio { namespace chain { incomplete = 3, ///< this is an incomplete block (either being produced by a producer or speculatively produced by a node) }; - controller( const config& cfg ); + explicit controller( const config& cfg ); ~controller(); void add_indices(); - void startup( const snapshot_reader_ptr& snapshot = nullptr ); + void startup( std::function shutdown, const snapshot_reader_ptr& snapshot = nullptr ); /** * Starts a new pending block session upon which new transactions can @@ -122,22 +128,9 @@ namespace eosio { namespace chain { * The caller is responsible for calling drop_unapplied_transaction on a failing transaction that * they never intend to retry * - * @return vector of transactions which have been unapplied - */ - vector get_unapplied_transactions() const; - void drop_unapplied_transaction(const transaction_metadata_ptr& trx); - void drop_all_unapplied_transactions(); - - /** - * These transaction IDs represent transactions available in the head chain state as scheduled - * or otherwise generated transactions. - * - * calling push_scheduled_transaction with these IDs will remove the associated transaction from - * the chain state IFF it succeeds or objectively fails - * - * @return + * @return map of transactions which have been unapplied */ - vector get_scheduled_transactions() const; + unapplied_transactions_type& get_unapplied_transactions(); /** * @@ -155,13 +148,10 @@ namespace eosio { namespace chain { void commit_block(); void pop_block(); - void push_block( const signed_block_ptr& b, block_status s = block_status::complete ); + std::future create_block_state_future( const signed_block_ptr& b ); + void push_block( std::future& block_state_future ); - /** - * Call this method when a producer confirmation is received, this might update - * the last bft irreversible block and/or cause a switch of forks - */ - void push_confirmation( const header_confirmation& c ); + boost::asio::thread_pool& get_thread_pool(); const chainbase::database& db()const; @@ -224,6 +214,8 @@ namespace eosio { namespace chain { sha256 calculate_integrity_hash()const; void write_snapshot( const snapshot_writer_ptr& snapshot )const; + bool sender_avoids_whitelist_blacklist_enforcement( account_name sender )const; + void check_actor_list( const flat_set& actors )const; void check_contract_list( account_name code )const; void check_action_list( account_name code, action_name action )const; void check_key_list( const public_key_type& key )const; @@ -245,7 +237,6 @@ namespace eosio { namespace chain { bool is_resource_greylisted(const account_name &name) const; const flat_set &get_resource_greylist() const; - void validate_referenced_accounts( const transaction& t )const; void validate_expiration( const transaction& t )const; void validate_tapos( const transaction& t )const; void validate_db_available_size() const; diff --git a/libraries/chain/include/eosio/chain/core_symbol.hpp.in b/libraries/chain/include/eosio/chain/core_symbol.hpp.in index ee8e368296d..c07f1ae267d 100644 --- a/libraries/chain/include/eosio/chain/core_symbol.hpp.in +++ b/libraries/chain/include/eosio/chain/core_symbol.hpp.in @@ -1,5 +1,5 @@ /** @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE * * \warning This file is machine generated. DO NOT EDIT. See core_symbol.hpp.in for changes. */ diff --git a/libraries/chain/include/eosio/chain/database_utils.hpp b/libraries/chain/include/eosio/chain/database_utils.hpp index e2b0c0d487f..19de97bd3da 100644 --- a/libraries/chain/include/eosio/chain/database_utils.hpp +++ b/libraries/chain/include/eosio/chain/database_utils.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once @@ -216,4 +216,3 @@ DataStream& operator >> ( DataStream& ds, float128_t& v ) { fc::raw::unpack(ds, *reinterpret_cast(&v)); return ds; } - diff --git a/libraries/chain/include/eosio/chain/eosio_contract.hpp b/libraries/chain/include/eosio/chain/eosio_contract.hpp index 88566b30982..1bf9163827e 100644 --- a/libraries/chain/include/eosio/chain/eosio_contract.hpp +++ b/libraries/chain/include/eosio/chain/eosio_contract.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index 2dc5e114d03..6c3e504d349 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once @@ -439,8 +439,8 @@ namespace eosio { namespace chain { 3160007, "Invalid contract vm version" ) FC_DECLARE_DERIVED_EXCEPTION( set_exact_code, contract_exception, 3160008, "Contract is already running this version of code" ) - FC_DECLARE_DERIVED_EXCEPTION( wast_file_not_found, contract_exception, - 3160009, "No wast file found" ) + FC_DECLARE_DERIVED_EXCEPTION( wasm_file_not_found, contract_exception, + 3160009, "No wasm file found" ) FC_DECLARE_DERIVED_EXCEPTION( abi_file_not_found, contract_exception, 3160010, "No abi file found" ) diff --git a/libraries/chain/include/eosio/chain/fixed_key.hpp b/libraries/chain/include/eosio/chain/fixed_key.hpp index 1839225a4f9..5dd90f901ad 100644 --- a/libraries/chain/include/eosio/chain/fixed_key.hpp +++ b/libraries/chain/include/eosio/chain/fixed_key.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 529a43a0a05..998157ab41a 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -36,12 +36,12 @@ namespace eosio { namespace chain { */ void set( block_state_ptr s ); - /** this method will attempt to append the block to an exsting + /** this method will attempt to append the block to an existing * block_state and will return a pointer to the new block state or * throw on error. */ - block_state_ptr add( signed_block_ptr b, bool trust = false ); - block_state_ptr add( block_state_ptr next_block ); + block_state_ptr add( signed_block_ptr b, bool skip_validate_signee ); + block_state_ptr add( const block_state_ptr& next_block, bool skip_validate_previous ); void remove( const block_id_type& id ); void add( const header_confirmation& c ); diff --git a/libraries/chain/include/eosio/chain/generated_transaction_object.hpp b/libraries/chain/include/eosio/chain/generated_transaction_object.hpp index 6d3e74dd558..24db926b4a8 100644 --- a/libraries/chain/include/eosio/chain/generated_transaction_object.hpp +++ b/libraries/chain/include/eosio/chain/generated_transaction_object.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/libraries/chain/include/eosio/chain/genesis_state.hpp b/libraries/chain/include/eosio/chain/genesis_state.hpp index 9fd05a82dc6..364f505629e 100644 --- a/libraries/chain/include/eosio/chain/genesis_state.hpp +++ b/libraries/chain/include/eosio/chain/genesis_state.hpp @@ -1,7 +1,7 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once @@ -51,6 +51,14 @@ struct genesis_state { * This is the SHA256 serialization of the genesis_state. */ chain_id_type compute_chain_id() const; + + friend inline bool operator==( const genesis_state& lhs, const genesis_state& rhs ) { + return std::tie( lhs.initial_configuration, lhs.initial_timestamp, lhs.initial_key ) + == std::tie( rhs.initial_configuration, rhs.initial_timestamp, rhs.initial_key ); + }; + + friend inline bool operator!=( const genesis_state& lhs, const genesis_state& rhs ) { return !(lhs == rhs); } + }; } } // namespace eosio::chain diff --git a/libraries/chain/include/eosio/chain/global_property_object.hpp b/libraries/chain/include/eosio/chain/global_property_object.hpp index 6f4f35ffd80..bdb49d3ce06 100644 --- a/libraries/chain/include/eosio/chain/global_property_object.hpp +++ b/libraries/chain/include/eosio/chain/global_property_object.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/libraries/chain/include/eosio/chain/multi_index_includes.hpp b/libraries/chain/include/eosio/chain/multi_index_includes.hpp index 5d2deaf04d0..2bb5485194c 100644 --- a/libraries/chain/include/eosio/chain/multi_index_includes.hpp +++ b/libraries/chain/include/eosio/chain/multi_index_includes.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/libraries/utilities/include/eosio/utilities/parallel_markers.hpp b/libraries/chain/include/eosio/chain/parallel_markers.hpp similarity index 92% rename from libraries/utilities/include/eosio/utilities/parallel_markers.hpp rename to libraries/chain/include/eosio/chain/parallel_markers.hpp index 0d6aa5a9821..7436f970630 100644 --- a/libraries/utilities/include/eosio/utilities/parallel_markers.hpp +++ b/libraries/chain/include/eosio/chain/parallel_markers.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once @@ -8,7 +8,7 @@ #include #include -namespace eosio { namespace utilities { +namespace eosio { namespace chain { /** * @brief Return values in DataRange corresponding to matching Markers @@ -39,5 +39,5 @@ DataRange filter_data_by_marker(DataRange data, MarkerRange markers, const Marke return {range.begin(), range.end()}; } -}} // namespace eosio::utilities +}} // namespace eosio::chain diff --git a/libraries/chain/include/eosio/chain/permission_link_object.hpp b/libraries/chain/include/eosio/chain/permission_link_object.hpp index 9930b647ad8..b7b4ea76f57 100644 --- a/libraries/chain/include/eosio/chain/permission_link_object.hpp +++ b/libraries/chain/include/eosio/chain/permission_link_object.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/libraries/chain/include/eosio/chain/permission_object.hpp b/libraries/chain/include/eosio/chain/permission_object.hpp index ee43f0e52a7..7db580b74d8 100644 --- a/libraries/chain/include/eosio/chain/permission_object.hpp +++ b/libraries/chain/include/eosio/chain/permission_object.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/libraries/chain/include/eosio/chain/producer_object.hpp b/libraries/chain/include/eosio/chain/producer_object.hpp index a2bb729dcc2..61d23870280 100644 --- a/libraries/chain/include/eosio/chain/producer_object.hpp +++ b/libraries/chain/include/eosio/chain/producer_object.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/libraries/chain/include/eosio/chain/protocol.hpp b/libraries/chain/include/eosio/chain/protocol.hpp index 134f953fb85..389e9c08723 100644 --- a/libraries/chain/include/eosio/chain/protocol.hpp +++ b/libraries/chain/include/eosio/chain/protocol.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/libraries/chain/include/eosio/chain/resource_limits_private.hpp b/libraries/chain/include/eosio/chain/resource_limits_private.hpp index 877c77e5acb..0bbe7e0e3e1 100644 --- a/libraries/chain/include/eosio/chain/resource_limits_private.hpp +++ b/libraries/chain/include/eosio/chain/resource_limits_private.hpp @@ -287,10 +287,10 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::resource_limits::gmr_config_object, eosio FC_REFLECT(eosio::chain::resource_limits::usage_accumulator, (last_ordinal)(value_ex)(consumed)) +// @ignore pending FC_REFLECT(eosio::chain::resource_limits::resource_limits_object, (owner)(net_weight)(cpu_weight)(ram_bytes)) FC_REFLECT(eosio::chain::resource_limits::resource_usage_object, (owner)(net_usage)(cpu_usage)(ram_usage)) FC_REFLECT(eosio::chain::resource_limits::resource_limits_config_object, (cpu_limit_parameters)(net_limit_parameters)(account_cpu_usage_average_window)(account_net_usage_average_window)) FC_REFLECT(eosio::chain::resource_limits::resource_limits_state_object, (average_block_net_usage)(average_block_cpu_usage)(pending_net_usage)(pending_cpu_usage)(total_net_weight)(total_cpu_weight)(total_ram_bytes)(virtual_net_limit)(virtual_cpu_limit)) - - FC_REFLECT(eosio::chain::resource_limits::gmr_config_object, (res_parameters)) + diff --git a/libraries/chain/include/eosio/chain/reversible_block_object.hpp b/libraries/chain/include/eosio/chain/reversible_block_object.hpp index e0502b7e72f..ea9a4c9e122 100644 --- a/libraries/chain/include/eosio/chain/reversible_block_object.hpp +++ b/libraries/chain/include/eosio/chain/reversible_block_object.hpp @@ -1,7 +1,7 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/libraries/chain/include/eosio/chain/snapshot.hpp b/libraries/chain/include/eosio/chain/snapshot.hpp index 47f69dd07e2..499fbe29960 100644 --- a/libraries/chain/include/eosio/chain/snapshot.hpp +++ b/libraries/chain/include/eosio/chain/snapshot.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/libraries/chain/include/eosio/chain/symbol.hpp b/libraries/chain/include/eosio/chain/symbol.hpp index 3d6a4f72b35..437b1d36ab7 100644 --- a/libraries/chain/include/eosio/chain/symbol.hpp +++ b/libraries/chain/include/eosio/chain/symbol.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include @@ -137,7 +137,7 @@ namespace eosio { return ds << s.to_string(); } - void reflector_verify()const { + void reflector_init()const { EOS_ASSERT( decimals() <= max_precision, symbol_type_exception, "precision ${p} should be <= 18", ("p", decimals()) ); EOS_ASSERT( valid_name(name()), symbol_type_exception, "invalid symbol: ${name}", ("name",name())); } diff --git a/libraries/chain/include/eosio/chain/thread_utils.hpp b/libraries/chain/include/eosio/chain/thread_utils.hpp new file mode 100644 index 00000000000..31b32cbd91f --- /dev/null +++ b/libraries/chain/include/eosio/chain/thread_utils.hpp @@ -0,0 +1,24 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#pragma once + +#include +#include +#include +#include + +namespace eosio { namespace chain { + + // async on thread_pool and return future + template + auto async_thread_pool( boost::asio::thread_pool& thread_pool, F&& f ) { + auto task = std::make_shared>( std::forward( f ) ); + boost::asio::post( thread_pool, [task]() { (*task)(); } ); + return task->get_future(); + } + +} } // eosio::chain + + diff --git a/libraries/chain/include/eosio/chain/trace.hpp b/libraries/chain/include/eosio/chain/trace.hpp index 03750bd512e..58de120bdd8 100644 --- a/libraries/chain/include/eosio/chain/trace.hpp +++ b/libraries/chain/include/eosio/chain/trace.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/libraries/chain/include/eosio/chain/transaction.hpp b/libraries/chain/include/eosio/chain/transaction.hpp index 895d3ee4fb8..a8b53b98e0d 100644 --- a/libraries/chain/include/eosio/chain/transaction.hpp +++ b/libraries/chain/include/eosio/chain/transaction.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once @@ -58,11 +58,12 @@ namespace eosio { namespace chain { transaction_id_type id()const; digest_type sig_digest( const chain_id_type& chain_id, const vector& cfd = vector() )const; - flat_set get_signature_keys( const vector& signatures, + fc::microseconds get_signature_keys( const vector& signatures, const chain_id_type& chain_id, - const vector& cfd = vector(), - bool allow_duplicate_keys = false, - bool use_cache = true )const; + fc::time_point deadline, + const vector& cfd, + flat_set& recovered_pub_keys, + bool allow_duplicate_keys = false) const; uint32_t total_actions()const { return context_free_actions.size() + actions.size(); } account_name first_authorizor()const { @@ -84,15 +85,21 @@ namespace eosio { namespace chain { : transaction(std::move(trx)) , signatures(signatures) , context_free_data(context_free_data) - { - } + {} + signed_transaction( transaction&& trx, const vector& signatures, vector&& context_free_data) + : transaction(std::move(trx)) + , signatures(signatures) + , context_free_data(std::move(context_free_data)) + {} vector signatures; vector context_free_data; ///< for each context-free action, there is an entry here const signature_type& sign(const private_key_type& key, const chain_id_type& chain_id); signature_type sign(const private_key_type& key, const chain_id_type& chain_id)const; - flat_set get_signature_keys( const chain_id_type& chain_id, bool allow_duplicate_keys = false, bool use_cache = true )const; + fc::microseconds get_signature_keys( const chain_id_type& chain_id, fc::time_point deadline, + flat_set& recovered_pub_keys, + bool allow_duplicate_keys = false )const; }; struct packed_transaction { @@ -102,47 +109,65 @@ namespace eosio { namespace chain { }; packed_transaction() = default; - - explicit packed_transaction(const transaction& t, compression_type _compression = none) - { - set_transaction(t, _compression); - } + packed_transaction(packed_transaction&&) = default; + explicit packed_transaction(const packed_transaction&) = default; + packed_transaction& operator=(const packed_transaction&) = delete; + packed_transaction& operator=(packed_transaction&&) = default; explicit packed_transaction(const signed_transaction& t, compression_type _compression = none) - :signatures(t.signatures) + :signatures(t.signatures), compression(_compression), unpacked_trx(t) { - set_transaction(t, t.context_free_data, _compression); + local_pack_transaction(); + local_pack_context_free_data(); } explicit packed_transaction(signed_transaction&& t, compression_type _compression = none) - :signatures(std::move(t.signatures)) + :signatures(t.signatures), compression(_compression), unpacked_trx(std::move(t)) { - set_transaction(t, std::move(t.context_free_data), _compression); + local_pack_transaction(); + local_pack_context_free_data(); } + // used by abi_serializer + packed_transaction( bytes&& packed_txn, vector&& sigs, bytes&& packed_cfd, compression_type _compression ); + packed_transaction( bytes&& packed_txn, vector&& sigs, vector&& cfd, compression_type _compression ); + packed_transaction( transaction&& t, vector&& sigs, bytes&& packed_cfd, compression_type _compression ); + uint32_t get_unprunable_size()const; uint32_t get_prunable_size()const; digest_type packed_digest()const; + transaction_id_type id()const { return unpacked_trx.id(); } + bytes get_raw_transaction()const; + + time_point_sec expiration()const { return unpacked_trx.expiration; } + const vector& get_context_free_data()const { return unpacked_trx.context_free_data; } + const transaction& get_transaction()const { return unpacked_trx; } + const signed_transaction& get_signed_transaction()const { return unpacked_trx; } + const vector& get_signatures()const { return signatures; } + const fc::enum_type& get_compression()const { return compression; } + const bytes& get_packed_context_free_data()const { return packed_context_free_data; } + const bytes& get_packed_transaction()const { return packed_trx; } + + private: + void local_unpack_transaction(vector&& context_free_data); + void local_unpack_context_free_data(); + void local_pack_transaction(); + void local_pack_context_free_data(); + + friend struct fc::reflector; + friend struct fc::reflector_init_visitor; + void reflector_init(); + private: vector signatures; fc::enum_type compression; bytes packed_context_free_data; bytes packed_trx; - time_point_sec expiration()const; - transaction_id_type id()const; - transaction_id_type get_uncached_id()const; // thread safe - bytes get_raw_transaction()const; // thread safe - vector get_context_free_data()const; - transaction get_transaction()const; - signed_transaction get_signed_transaction()const; - void set_transaction(const transaction& t, compression_type _compression = none); - void set_transaction(const transaction& t, const vector& cfd, compression_type _compression = none); - private: - mutable optional unpacked_trx; // <-- intermediate buffer used to retrieve values - void local_unpack()const; + // cache unpacked trx, for thread safety do not modify after construction + signed_transaction unpacked_trx; }; using packed_transaction_ptr = std::shared_ptr; diff --git a/libraries/chain/include/eosio/chain/transaction_context.hpp b/libraries/chain/include/eosio/chain/transaction_context.hpp index b69a00143e9..b0327dafb18 100644 --- a/libraries/chain/include/eosio/chain/transaction_context.hpp +++ b/libraries/chain/include/eosio/chain/transaction_context.hpp @@ -33,7 +33,6 @@ namespace eosio { namespace chain { void init_for_input_trx( uint64_t packed_trx_unprunable_size, uint64_t packed_trx_prunable_size, - uint32_t num_signatures, bool skip_recording); void init_for_deferred_trx( fc::time_point published ); @@ -56,6 +55,8 @@ namespace eosio { namespace chain { std::tuple max_bandwidth_billed_accounts_can_pay( bool force_elastic_limits = false )const; + void validate_referenced_accounts( const transaction& trx, bool enforce_actor_whitelist_blacklist )const; + private: friend struct controller_impl; @@ -95,7 +96,7 @@ namespace eosio { namespace chain { fc::microseconds delay; bool is_input = false; bool apply_context_free = true; - bool can_subjectively_fail = true; + bool enforce_whiteblacklist = true; fc::time_point deadline = fc::time_point::maximum(); fc::microseconds leeway = fc::microseconds(3000); diff --git a/libraries/chain/include/eosio/chain/transaction_metadata.hpp b/libraries/chain/include/eosio/chain/transaction_metadata.hpp index 44d5d008a79..6136580fa44 100644 --- a/libraries/chain/include/eosio/chain/transaction_metadata.hpp +++ b/libraries/chain/include/eosio/chain/transaction_metadata.hpp @@ -1,14 +1,20 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include -#include -#include +#include +#include + +namespace boost { namespace asio { + class thread_pool; +}} namespace eosio { namespace chain { +class transaction_metadata; +using transaction_metadata_ptr = std::shared_ptr; /** * This data structure should store context-free cached data about a transaction such as * packed/unpacked/compressed and recovered keys @@ -17,36 +23,38 @@ class transaction_metadata { public: transaction_id_type id; transaction_id_type signed_id; - signed_transaction trx; - packed_transaction packed_trx; + packed_transaction_ptr packed_trx; + fc::microseconds sig_cpu_usage; optional>> signing_keys; + std::future>> + signing_keys_future; bool accepted = false; bool implicit = false; bool scheduled = false; + transaction_metadata() = delete; + transaction_metadata(const transaction_metadata&) = delete; + transaction_metadata(transaction_metadata&&) = delete; + transaction_metadata operator=(transaction_metadata&) = delete; + transaction_metadata operator=(transaction_metadata&&) = delete; + explicit transaction_metadata( const signed_transaction& t, packed_transaction::compression_type c = packed_transaction::none ) - :trx(t),packed_trx(t, c) { - id = trx.id(); + :id(t.id()), packed_trx(std::make_shared(t, c)) { //raw_packed = fc::raw::pack( static_cast(trx) ); - signed_id = digest_type::hash(packed_trx); + signed_id = digest_type::hash(*packed_trx); } - explicit transaction_metadata( const packed_transaction& ptrx ) - :trx( ptrx.get_signed_transaction() ), packed_trx(ptrx) { - id = trx.id(); + explicit transaction_metadata( const packed_transaction_ptr& ptrx ) + :id(ptrx->id()), packed_trx(ptrx) { //raw_packed = fc::raw::pack( static_cast(trx) ); - signed_id = digest_type::hash(packed_trx); + signed_id = digest_type::hash(*packed_trx); } - const flat_set& recover_keys( const chain_id_type& chain_id ) { - if( !signing_keys || signing_keys->first != chain_id ) // Unlikely for more than one chain_id to be used in one nodeos instance - signing_keys = std::make_pair( chain_id, trx.get_signature_keys( chain_id ) ); - return signing_keys->second; - } + const flat_set& recover_keys( const chain_id_type& chain_id ); - uint32_t total_actions()const { return trx.context_free_actions.size() + trx.actions.size(); } -}; + static void create_signing_keys_future( const transaction_metadata_ptr& mtrx, boost::asio::thread_pool& thread_pool, + const chain_id_type& chain_id, fc::microseconds time_limit ); -using transaction_metadata_ptr = std::shared_ptr; +}; } } // eosio::chain diff --git a/libraries/chain/include/eosio/chain/transaction_object.hpp b/libraries/chain/include/eosio/chain/transaction_object.hpp index 0d049267e8e..50a7eb62cdd 100644 --- a/libraries/chain/include/eosio/chain/transaction_object.hpp +++ b/libraries/chain/include/eosio/chain/transaction_object.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index 028b050a595..bddeb1dd553 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include @@ -103,7 +103,22 @@ namespace eosio { namespace chain { */ class shared_blob : public shared_string { public: - shared_blob() = default; + shared_blob() = delete; + shared_blob(shared_blob&&) = default; + + shared_blob(const shared_blob& s) + :shared_string(s.get_allocator()) + { + assign(s.c_str(), s.size()); + } + + + shared_blob& operator=(const shared_blob& s) { + assign(s.c_str(), s.size()); + return *this; + } + + shared_blob& operator=(shared_blob&& ) = default; template shared_blob(InputIterator f, InputIterator l, const allocator_type& a) diff --git a/libraries/chain/include/eosio/chain/wasm_eosio_injection.hpp b/libraries/chain/include/eosio/chain/wasm_eosio_injection.hpp index f5ebf01c1f7..a67ca9ef696 100644 --- a/libraries/chain/include/eosio/chain/wasm_eosio_injection.hpp +++ b/libraries/chain/include/eosio/chain/wasm_eosio_injection.hpp @@ -272,7 +272,7 @@ namespace eosio { namespace chain { namespace wasm_injections { }; - struct call_depth_check { + struct call_depth_check_and_insert_checktime { static constexpr bool kills = true; static constexpr bool post = false; static int32_t global_idx; @@ -290,6 +290,7 @@ namespace eosio { namespace chain { namespace wasm_injections { injector_utils::add_import(*(arg.module), "call_depth_assert", assert_idx); wasm_ops::op_types<>::call_t call_assert; + wasm_ops::op_types<>::call_t call_checktime; wasm_ops::op_types<>::get_global_t get_global_inst; wasm_ops::op_types<>::set_global_t set_global_inst; @@ -301,6 +302,7 @@ namespace eosio { namespace chain { namespace wasm_injections { wasm_ops::op_types<>::else__t else_inst; call_assert.field = assert_idx; + call_checktime.field = checktime_injection::chktm_idx; get_global_inst.field = global_idx; set_global_inst.field = global_idx; const_inst.field = -1; @@ -334,6 +336,7 @@ namespace eosio { namespace chain { namespace wasm_injections { INSERT_INJECTED(const_inst); INSERT_INJECTED(add_inst); INSERT_INJECTED(set_global_inst); + INSERT_INJECTED(call_checktime); #undef INSERT_INJECTED } @@ -679,8 +682,8 @@ namespace eosio { namespace chain { namespace wasm_injections { }; struct pre_op_injectors : wasm_ops::op_types { - using call_t = wasm_ops::call ; - using call_indirect_t = wasm_ops::call_indirect ; + using call_t = wasm_ops::call ; + using call_indirect_t = wasm_ops::call_indirect ; // float binops using f32_add_t = wasm_ops::f32_add >; @@ -785,7 +788,7 @@ namespace eosio { namespace chain { namespace wasm_injections { // initialize static fields of injectors injector_utils::init( mod ); checktime_injection::init(); - call_depth_check::init(); + call_depth_check_and_insert_checktime::init(); } void inject() { diff --git a/libraries/chain/include/eosio/chain/wast_to_wasm.hpp b/libraries/chain/include/eosio/chain/wast_to_wasm.hpp index e77d23b1360..1493f2f99f7 100644 --- a/libraries/chain/include/eosio/chain/wast_to_wasm.hpp +++ b/libraries/chain/include/eosio/chain/wast_to_wasm.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/libraries/chain/transaction.cpp b/libraries/chain/transaction.cpp index c49f76ce771..2724a31b28d 100644 --- a/libraries/chain/transaction.cpp +++ b/libraries/chain/transaction.cpp @@ -1,11 +1,12 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include #include #include +#include #include #include @@ -28,6 +29,7 @@ struct cached_pub_key { transaction_id_type trx_id; public_key_type pub_key; signature_type sig; + fc::microseconds cpu_usage; cached_pub_key(const cached_pub_key&) = delete; cached_pub_key() = delete; cached_pub_key& operator=(const cached_pub_key&) = delete; @@ -81,43 +83,55 @@ digest_type transaction::sig_digest( const chain_id_type& chain_id, const vector return enc.result(); } -flat_set transaction::get_signature_keys( const vector& signatures, - const chain_id_type& chain_id, const vector& cfd, bool allow_duplicate_keys, bool use_cache )const +fc::microseconds transaction::get_signature_keys( const vector& signatures, + const chain_id_type& chain_id, fc::time_point deadline, const vector& cfd, + flat_set& recovered_pub_keys, bool allow_duplicate_keys)const { try { using boost::adaptors::transformed; - constexpr size_t recovery_cache_size = 1000; + constexpr size_t recovery_cache_size = 10000; static recovery_cache_type recovery_cache; + static std::mutex cache_mtx; + + auto start = fc::time_point::now(); + recovered_pub_keys.clear(); const digest_type digest = sig_digest(chain_id, cfd); - flat_set recovered_pub_keys; + std::unique_lock lock(cache_mtx, std::defer_lock); + fc::microseconds sig_cpu_usage; for(const signature_type& sig : signatures) { + auto now = fc::time_point::now(); + EOS_ASSERT( now < deadline, tx_cpu_usage_exceeded, "transaction signature verification executed for too long", + ("now", now)("deadline", deadline)("start", start) ); public_key_type recov; - if( use_cache ) { - recovery_cache_type::index::type::iterator it = recovery_cache.get().find( sig ); - if( it == recovery_cache.get().end() || it->trx_id != id()) { - recov = public_key_type( sig, digest ); - recovery_cache.emplace_back(cached_pub_key{id(), recov, sig} ); //could fail on dup signatures; not a problem - } else { - recov = it->pub_key; - } - } else { + const auto& tid = id(); + lock.lock(); + recovery_cache_type::index::type::iterator it = recovery_cache.get().find( sig ); + if( it == recovery_cache.get().end() || it->trx_id != tid ) { + lock.unlock(); recov = public_key_type( sig, digest ); + fc::microseconds cpu_usage = fc::time_point::now() - start; + lock.lock(); + recovery_cache.emplace_back( cached_pub_key{tid, recov, sig, cpu_usage} ); //could fail on dup signatures; not a problem + sig_cpu_usage += cpu_usage; + } else { + recov = it->pub_key; + sig_cpu_usage += it->cpu_usage; } + lock.unlock(); bool successful_insertion = false; std::tie(std::ignore, successful_insertion) = recovered_pub_keys.insert(recov); EOS_ASSERT( allow_duplicate_keys || successful_insertion, tx_duplicate_sig, "transaction includes more than one signature signed using the same key associated with public key: ${key}", - ("key", recov) - ); + ("key", recov) ); } - if( use_cache ) { - while ( recovery_cache.size() > recovery_cache_size ) - recovery_cache.erase( recovery_cache.begin() ); - } + lock.lock(); + while ( recovery_cache.size() > recovery_cache_size ) + recovery_cache.erase( recovery_cache.begin()); + lock.unlock(); - return recovered_pub_keys; + return sig_cpu_usage; } FC_CAPTURE_AND_RETHROW() } @@ -130,9 +144,12 @@ signature_type signed_transaction::sign(const private_key_type& key, const chain return key.sign(sig_digest(chain_id, context_free_data)); } -flat_set signed_transaction::get_signature_keys( const chain_id_type& chain_id, bool allow_duplicate_keys, bool use_cache )const +fc::microseconds +signed_transaction::get_signature_keys( const chain_id_type& chain_id, fc::time_point deadline, + flat_set& recovered_pub_keys, + bool allow_duplicate_keys)const { - return transaction::get_signature_keys(signatures, chain_id, context_free_data, allow_duplicate_keys, use_cache); + return transaction::get_signature_keys(signatures, chain_id, deadline, context_free_data, recovered_pub_keys, allow_duplicate_keys); } uint32_t packed_transaction::get_unprunable_size()const { @@ -272,112 +289,115 @@ bytes packed_transaction::get_raw_transaction() const } FC_CAPTURE_AND_RETHROW((compression)(packed_trx)) } -vector packed_transaction::get_context_free_data()const +packed_transaction::packed_transaction( bytes&& packed_txn, vector&& sigs, bytes&& packed_cfd, compression_type _compression ) +:signatures(std::move(sigs)) +,compression(_compression) +,packed_context_free_data(std::move(packed_cfd)) +,packed_trx(std::move(packed_txn)) { - try { - switch(compression) { - case none: - return unpack_context_free_data(packed_context_free_data); - case zlib: - return zlib_decompress_context_free_data(packed_context_free_data); - default: - EOS_THROW(unknown_transaction_compression, "Unknown transaction compression algorithm"); - } - } FC_CAPTURE_AND_RETHROW((compression)(packed_context_free_data)) + local_unpack_transaction({}); + if( !packed_context_free_data.empty() ) { + local_unpack_context_free_data(); + } } -time_point_sec packed_transaction::expiration()const +packed_transaction::packed_transaction( bytes&& packed_txn, vector&& sigs, vector&& cfd, compression_type _compression ) +:signatures(std::move(sigs)) +,compression(_compression) +,packed_trx(std::move(packed_txn)) { - local_unpack(); - return unpacked_trx->expiration; + local_unpack_transaction( std::move( cfd ) ); + if( !unpacked_trx.context_free_data.empty() ) { + local_pack_context_free_data(); + } } -transaction_id_type packed_transaction::id()const +packed_transaction::packed_transaction( transaction&& t, vector&& sigs, bytes&& packed_cfd, compression_type _compression ) +:signatures(std::move(sigs)) +,compression(_compression) +,packed_context_free_data(std::move(packed_cfd)) +,unpacked_trx(std::move(t), signatures, {}) { - local_unpack(); - return get_transaction().id(); + local_pack_transaction(); + if( !packed_context_free_data.empty() ) { + local_unpack_context_free_data(); + } } -transaction_id_type packed_transaction::get_uncached_id()const +void packed_transaction::reflector_init() { - const auto raw = get_raw_transaction(); - return fc::raw::unpack( raw ).id(); + // called after construction, but always on the same thread and before packed_transaction passed to any other threads + static_assert(&fc::reflector_init_visitor::reflector_init, "FC with reflector_init required"); + static_assert(fc::raw::has_feature_reflector_init_on_unpacked_reflected_types, + "FC unpack needs to call reflector_init otherwise unpacked_trx will not be initialized"); + EOS_ASSERT( unpacked_trx.expiration == time_point_sec(), tx_decompression_error, "packed_transaction already unpacked" ); + local_unpack_transaction({}); + local_unpack_context_free_data(); } -void packed_transaction::local_unpack()const +void packed_transaction::local_unpack_transaction(vector&& context_free_data) { - if (!unpacked_trx) { - try { - switch(compression) { + try { + switch( compression ) { case none: - unpacked_trx = unpack_transaction(packed_trx); + unpacked_trx = signed_transaction( unpack_transaction( packed_trx ), signatures, std::move(context_free_data) ); break; case zlib: - unpacked_trx = zlib_decompress_transaction(packed_trx); + unpacked_trx = signed_transaction( zlib_decompress_transaction( packed_trx ), signatures, std::move(context_free_data) ); break; default: - EOS_THROW(unknown_transaction_compression, "Unknown transaction compression algorithm"); - } - } FC_CAPTURE_AND_RETHROW((compression)(packed_trx)) - } -} - -transaction packed_transaction::get_transaction()const -{ - local_unpack(); - return transaction(*unpacked_trx); + EOS_THROW( unknown_transaction_compression, "Unknown transaction compression algorithm" ); + } + } FC_CAPTURE_AND_RETHROW( (compression) ) } -signed_transaction packed_transaction::get_signed_transaction() const +void packed_transaction::local_unpack_context_free_data() { try { - switch(compression) { + EOS_ASSERT(unpacked_trx.context_free_data.empty(), tx_decompression_error, "packed_transaction.context_free_data not empty"); + switch( compression ) { case none: - return signed_transaction(get_transaction(), signatures, unpack_context_free_data(packed_context_free_data)); + unpacked_trx.context_free_data = unpack_context_free_data( packed_context_free_data ); + break; case zlib: - return signed_transaction(get_transaction(), signatures, zlib_decompress_context_free_data(packed_context_free_data)); + unpacked_trx.context_free_data = zlib_decompress_context_free_data( packed_context_free_data ); + break; default: - EOS_THROW(unknown_transaction_compression, "Unknown transaction compression algorithm"); + EOS_THROW( unknown_transaction_compression, "Unknown transaction compression algorithm" ); } - } FC_CAPTURE_AND_RETHROW((compression)(packed_trx)(packed_context_free_data)) - + } FC_CAPTURE_AND_RETHROW( (compression) ) } -void packed_transaction::set_transaction(const transaction& t, packed_transaction::compression_type _compression) +void packed_transaction::local_pack_transaction() { try { - switch(_compression) { + switch(compression) { case none: - packed_trx = pack_transaction(t); + packed_trx = pack_transaction(unpacked_trx); break; case zlib: - packed_trx = zlib_compress_transaction(t); + packed_trx = zlib_compress_transaction(unpacked_trx); break; default: EOS_THROW(unknown_transaction_compression, "Unknown transaction compression algorithm"); } - } FC_CAPTURE_AND_RETHROW((_compression)(t)) - packed_context_free_data.clear(); - compression = _compression; + } FC_CAPTURE_AND_RETHROW((compression)) } -void packed_transaction::set_transaction(const transaction& t, const vector& cfd, packed_transaction::compression_type _compression) +void packed_transaction::local_pack_context_free_data() { try { - switch(_compression) { + switch(compression) { case none: - packed_trx = pack_transaction(t); - packed_context_free_data = pack_context_free_data(cfd); + packed_context_free_data = pack_context_free_data(unpacked_trx.context_free_data); break; case zlib: - packed_trx = zlib_compress_transaction(t); - packed_context_free_data = zlib_compress_context_free_data(cfd); + packed_context_free_data = zlib_compress_context_free_data(unpacked_trx.context_free_data); break; default: EOS_THROW(unknown_transaction_compression, "Unknown transaction compression algorithm"); } - } FC_CAPTURE_AND_RETHROW((_compression)(t)) - compression = _compression; + } FC_CAPTURE_AND_RETHROW((compression)) } diff --git a/libraries/chain/transaction_context.cpp b/libraries/chain/transaction_context.cpp index 476a78d982b..d5da8ca279b 100644 --- a/libraries/chain/transaction_context.cpp +++ b/libraries/chain/transaction_context.cpp @@ -26,7 +26,7 @@ namespace bacc = boost::accumulators; struct deadline_timer_verify { deadline_timer_verify() { //keep longest first in list. You're effectively going to take test_intervals[0]*sizeof(test_intervals[0]) - //time to do the the "calibration" + //time to do the the "calibration" int test_intervals[] = {50000, 10000, 5000, 1000, 500, 100, 50, 10}; struct sigaction act; @@ -284,7 +284,6 @@ namespace bacc = boost::accumulators; void transaction_context::init_for_input_trx( uint64_t packed_trx_unprunable_size, uint64_t packed_trx_prunable_size, - uint32_t num_signatures, bool skip_recording ) { const auto& cfg = control.get_global_properties().configuration; @@ -314,7 +313,7 @@ namespace bacc = boost::accumulators; if (!control.skip_trx_checks()) { control.validate_expiration(trx); control.validate_tapos(trx); - control.validate_referenced_accounts(trx); + validate_referenced_accounts( trx, enforce_whiteblacklist && control.is_producing_block() ); } init( initial_net_usage); if (!skip_recording) @@ -615,5 +614,43 @@ namespace bacc = boost::accumulators; } } /// record_transaction + void transaction_context::validate_referenced_accounts( const transaction& trx, bool enforce_actor_whitelist_blacklist )const { + const auto& db = control.db(); + const auto& auth_manager = control.get_authorization_manager(); + + for( const auto& a : trx.context_free_actions ) { + auto* code = db.find(a.account); + EOS_ASSERT( code != nullptr, transaction_exception, + "action's code account '${account}' does not exist", ("account", a.account) ); + EOS_ASSERT( a.authorization.size() == 0, transaction_exception, + "context-free actions cannot have authorizations" ); + } + + flat_set actors; + + bool one_auth = false; + for( const auto& a : trx.actions ) { + auto* code = db.find(a.account); + EOS_ASSERT( code != nullptr, transaction_exception, + "action's code account '${account}' does not exist", ("account", a.account) ); + for( const auto& auth : a.authorization ) { + one_auth = true; + auto* actor = db.find(auth.actor); + EOS_ASSERT( actor != nullptr, transaction_exception, + "action's authorizing actor '${account}' does not exist", ("account", auth.actor) ); + EOS_ASSERT( auth_manager.find_permission(auth) != nullptr, transaction_exception, + "action's authorizations include a non-existent permission: {permission}", + ("permission", auth) ); + if( enforce_actor_whitelist_blacklist ) + actors.insert( auth.actor ); + } + } + EOS_ASSERT( one_auth, tx_no_auths, "transaction must have at least one authorization" ); + + if( enforce_actor_whitelist_blacklist ) { + control.check_actor_list( actors ); + } + } + } } /// eosio::chain diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp new file mode 100644 index 00000000000..2053669c0d7 --- /dev/null +++ b/libraries/chain/transaction_metadata.cpp @@ -0,0 +1,47 @@ +#include +#include +#include + +namespace eosio { namespace chain { + + +const flat_set& transaction_metadata::recover_keys( const chain_id_type& chain_id ) { + // Unlikely for more than one chain_id to be used in one nodeos instance + if( !signing_keys || signing_keys->first != chain_id ) { + if( signing_keys_future.valid() ) { + std::tuple> sig_keys = signing_keys_future.get(); + if( std::get<0>( sig_keys ) == chain_id ) { + sig_cpu_usage = std::get<1>( sig_keys ); + signing_keys.emplace( std::get<0>( sig_keys ), std::move( std::get<2>( sig_keys ))); + return signing_keys->second; + } + } + flat_set recovered_pub_keys; + sig_cpu_usage = packed_trx->get_signed_transaction().get_signature_keys( chain_id, fc::time_point::maximum(), recovered_pub_keys ); + signing_keys.emplace( chain_id, std::move( recovered_pub_keys )); + } + return signing_keys->second; +} + +void transaction_metadata::create_signing_keys_future( const transaction_metadata_ptr& mtrx, + boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id, fc::microseconds time_limit ) { + if( mtrx->signing_keys.valid() ) // already created + return; + + std::weak_ptr mtrx_wp = mtrx; + mtrx->signing_keys_future = async_thread_pool( thread_pool, [time_limit, chain_id, mtrx_wp]() { + fc::time_point deadline = time_limit == fc::microseconds::maximum() ? + fc::time_point::maximum() : fc::time_point::now() + time_limit; + auto mtrx = mtrx_wp.lock(); + fc::microseconds cpu_usage; + flat_set recovered_pub_keys; + if( mtrx ) { + const signed_transaction& trn = mtrx->packed_trx->get_signed_transaction(); + cpu_usage = trn.get_signature_keys( chain_id, deadline, recovered_pub_keys ); + } + return std::make_tuple( chain_id, cpu_usage, std::move( recovered_pub_keys )); + } ); +} + + +} } // eosio::chain diff --git a/libraries/chain/wasm_eosio_injection.cpp b/libraries/chain/wasm_eosio_injection.cpp index a4afa44d46d..2c627e13ea7 100644 --- a/libraries/chain/wasm_eosio_injection.cpp +++ b/libraries/chain/wasm_eosio_injection.cpp @@ -35,7 +35,7 @@ void max_memory_injection_visitor::inject( Module& m ) { } void max_memory_injection_visitor::initializer() {} -int32_t call_depth_check::global_idx = -1; +int32_t call_depth_check_and_insert_checktime::global_idx = -1; uint32_t instruction_counter::icnt = 0; uint32_t instruction_counter::tcnt = 0; uint32_t instruction_counter::bcnt = 0; diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index 12ff329bd29..7d3553e379b 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace eosio { namespace chain { using namespace webassembly; @@ -273,8 +274,8 @@ class softfloat_api : public context_aware_api { if (is_nan(b)) { return bf; } - if ( sign_bit(a) != sign_bit(b) ) { - return sign_bit(a) ? af : bf; + if ( f32_sign_bit(a) != f32_sign_bit(b) ) { + return f32_sign_bit(a) ? af : bf; } return f32_lt(a,b) ? af : bf; } @@ -287,8 +288,8 @@ class softfloat_api : public context_aware_api { if (is_nan(b)) { return bf; } - if ( sign_bit(a) != sign_bit(b) ) { - return sign_bit(a) ? bf : af; + if ( f32_sign_bit(a) != f32_sign_bit(b) ) { + return f32_sign_bit(a) ? bf : af; } return f32_lt( a, b ) ? bf : af; } @@ -440,8 +441,8 @@ class softfloat_api : public context_aware_api { return af; if (is_nan(b)) return bf; - if (sign_bit(a) != sign_bit(b)) - return sign_bit(a) ? af : bf; + if (f64_sign_bit(a) != f64_sign_bit(b)) + return f64_sign_bit(a) ? af : bf; return f64_lt( a, b ) ? af : bf; } double _eosio_f64_max( double af, double bf ) { @@ -451,8 +452,8 @@ class softfloat_api : public context_aware_api { return af; if (is_nan(b)) return bf; - if (sign_bit(a) != sign_bit(b)) - return sign_bit(a) ? bf : af; + if (f64_sign_bit(a) != f64_sign_bit(b)) + return f64_sign_bit(a) ? bf : af; return f64_lt( a, b ) ? bf : af; } double _eosio_f64_copysign( double af, double bf ) { @@ -686,32 +687,17 @@ class softfloat_api : public context_aware_api { } static bool is_nan( const float32_t f ) { - return ((f.v & 0x7FFFFFFF) > 0x7F800000); + return f32_is_nan( f ); } static bool is_nan( const float64_t f ) { - return ((f.v & 0x7FFFFFFFFFFFFFFF) > 0x7FF0000000000000); + return f64_is_nan( f ); } static bool is_nan( const float128_t& f ) { - return (((~(f.v[1]) & uint64_t( 0x7FFF000000000000 )) == 0) && (f.v[0] || ((f.v[1]) & uint64_t( 0x0000FFFFFFFFFFFF )))); - } - static float32_t to_softfloat32( float f ) { - return *reinterpret_cast(&f); - } - static float64_t to_softfloat64( double d ) { - return *reinterpret_cast(&d); - } - static float from_softfloat32( float32_t f ) { - return *reinterpret_cast(&f); - } - static double from_softfloat64( float64_t d ) { - return *reinterpret_cast(&d); + return f128_is_nan( f ); } + static constexpr uint32_t inv_float_eps = 0x4B000000; static constexpr uint64_t inv_double_eps = 0x4330000000000000; - - static bool sign_bit( float32_t f ) { return f.v >> 31; } - static bool sign_bit( float64_t f ) { return f.v >> 63; } - }; class producer_api : public context_aware_api { @@ -952,36 +938,36 @@ class system_api : public context_aware_api { }; +constexpr size_t max_assert_message = 1024; + class context_free_system_api : public context_aware_api { public: explicit context_free_system_api( apply_context& ctx ) :context_aware_api(ctx,true){} void abort() { - edump(("abort() called")); EOS_ASSERT( false, abort_called, "abort() called"); } // Kept as intrinsic rather than implementing on WASM side (using eosio_assert_message and strlen) because strlen is faster on native side. void eosio_assert( bool condition, null_terminated_ptr msg ) { if( BOOST_UNLIKELY( !condition ) ) { - std::string message( msg ); - edump((message)); + const size_t sz = strnlen( msg, max_assert_message ); + std::string message( msg, sz ); EOS_THROW( eosio_assert_message_exception, "assertion failure with message: ${s}", ("s",message) ); } } void eosio_assert_message( bool condition, array_ptr msg, size_t msg_len ) { if( BOOST_UNLIKELY( !condition ) ) { - std::string message( msg, msg_len ); - edump((message)); + const size_t sz = msg_len > max_assert_message ? max_assert_message : msg_len; + std::string message( msg, sz ); EOS_THROW( eosio_assert_message_exception, "assertion failure with message: ${s}", ("s",message) ); } } void eosio_assert_code( bool condition, uint64_t error_code ) { if( BOOST_UNLIKELY( !condition ) ) { - edump((error_code)); EOS_THROW( eosio_assert_code_exception, "assertion failure with error code: ${error_code}", ("error_code", error_code) ); } @@ -1118,12 +1104,16 @@ class console_api : public context_aware_api { auto& console = context.get_console_stream(); auto orig_prec = console.precision(); +#ifdef __x86_64__ console.precision( std::numeric_limits::digits10 ); - extFloat80_t val_approx; f128M_to_extF80M(&val, &val_approx); context.console_append( *(long double*)(&val_approx) ); - +#else + console.precision( std::numeric_limits::digits10 ); + double val_approx = from_softfloat64( f128M_to_f64(&val) ); + context.console_append(val_approx); +#endif console.precision( orig_prec ); } } @@ -1576,18 +1566,18 @@ class compiler_builtins : public context_aware_api { // conversion long double void __extendsftf2( float128_t& ret, float f ) { - ret = f32_to_f128( softfloat_api::to_softfloat32(f) ); + ret = f32_to_f128( to_softfloat32(f) ); } void __extenddftf2( float128_t& ret, double d ) { - ret = f64_to_f128( softfloat_api::to_softfloat64(d) ); + ret = f64_to_f128( to_softfloat64(d) ); } double __trunctfdf2( uint64_t l, uint64_t h ) { float128_t f = {{ l, h }}; - return softfloat_api::from_softfloat64(f128_to_f64( f )); + return from_softfloat64(f128_to_f64( f )); } float __trunctfsf2( uint64_t l, uint64_t h ) { float128_t f = {{ l, h }}; - return softfloat_api::from_softfloat32(f128_to_f32( f )); + return from_softfloat32(f128_to_f32( f )); } int32_t __fixtfsi( uint64_t l, uint64_t h ) { float128_t f = {{ l, h }}; @@ -1614,19 +1604,19 @@ class compiler_builtins : public context_aware_api { ret = ___fixunstfti( f ); } void __fixsfti( __int128& ret, float a ) { - ret = ___fixsfti( softfloat_api::to_softfloat32(a).v ); + ret = ___fixsfti( to_softfloat32(a).v ); } void __fixdfti( __int128& ret, double a ) { - ret = ___fixdfti( softfloat_api::to_softfloat64(a).v ); + ret = ___fixdfti( to_softfloat64(a).v ); } void __fixunssfti( unsigned __int128& ret, float a ) { - ret = ___fixunssfti( softfloat_api::to_softfloat32(a).v ); + ret = ___fixunssfti( to_softfloat32(a).v ); } void __fixunsdfti( unsigned __int128& ret, double a ) { - ret = ___fixunsdfti( softfloat_api::to_softfloat64(a).v ); + ret = ___fixunsdfti( to_softfloat64(a).v ); } double __floatsidf( int32_t i ) { - return softfloat_api::from_softfloat64(i32_to_f64(i)); + return from_softfloat64(i32_to_f64(i)); } void __floatsitf( float128_t& ret, int32_t i ) { ret = i32_to_f128(i); diff --git a/libraries/chain/wast_to_wasm.cpp b/libraries/chain/wast_to_wasm.cpp index 6a2ca2e1bbc..09add7a0b6e 100644 --- a/libraries/chain/wast_to_wasm.cpp +++ b/libraries/chain/wast_to_wasm.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/libraries/fc b/libraries/fc index 9adee183df3..b2fa419ddf6 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 9adee183df3ce4170d1f362c96d960132bd77ed9 +Subproject commit b2fa419ddf68c6b5fc902de53cf8e691206cc8f3 diff --git a/libraries/softfloat b/libraries/softfloat index 9942875eb70..203b6df7ded 160000 --- a/libraries/softfloat +++ b/libraries/softfloat @@ -1 +1 @@ -Subproject commit 9942875eb704369db297eb289aa4e9912bddcfb8 +Subproject commit 203b6df7dedc5bae1b2a7b1b23562335a6344578 diff --git a/libraries/testing/CMakeLists.txt b/libraries/testing/CMakeLists.txt index 620c7fb4003..eaf9bf87502 100644 --- a/libraries/testing/CMakeLists.txt +++ b/libraries/testing/CMakeLists.txt @@ -7,7 +7,7 @@ add_library( eosio_testing ${HEADERS} ) -target_link_libraries( eosio_testing eosio_chain eos_utilities fc chainbase Logging IR WAST WASM Runtime ) +target_link_libraries( eosio_testing eosio_chain fc chainbase Logging IR WAST WASM Runtime ) target_include_directories( eosio_testing PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../wasm-jit/Include" diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 22e52407953..5f0a5206fdc 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -91,6 +91,7 @@ namespace eosio { namespace testing { virtual signed_block_ptr produce_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms), uint32_t skip_flag = 0/*skip_missed_block_penalty*/ ) = 0; virtual signed_block_ptr produce_empty_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms), uint32_t skip_flag = 0/*skip_missed_block_penalty*/ ) = 0; + virtual signed_block_ptr finish_block() = 0; void produce_blocks( uint32_t n = 1, bool empty = false ); void produce_blocks_until_end_of_round(); void produce_blocks_for_n_rounds(const uint32_t num_of_rounds = 1); @@ -98,6 +99,17 @@ namespace eosio { namespace testing { void produce_min_num_of_blocks_to_spend_time_wo_inactive_prod(const fc::microseconds target_elapsed_time = fc::microseconds()); signed_block_ptr push_block(signed_block_ptr b); + /** + * These transaction IDs represent transactions available in the head chain state as scheduled + * or otherwise generated transactions. + * + * calling push_scheduled_transaction with these IDs will remove the associated transaction from + * the chain state IFF it succeeds or objectively fails + * + * @return + */ + vector get_scheduled_transactions() const; + transaction_trace_ptr push_transaction( packed_transaction& trx, fc::time_point deadline = fc::time_point::maximum(), uint32_t billed_cpu_time_us = DEFAULT_BILLED_CPU_TIME_US ); transaction_trace_ptr push_transaction( signed_transaction& trx, fc::time_point deadline = fc::time_point::maximum(), uint32_t billed_cpu_time_us = DEFAULT_BILLED_CPU_TIME_US ); action_result push_action(action&& cert_act, uint64_t authorizer); // TODO/QUESTION: Is this needed? @@ -271,6 +283,7 @@ namespace eosio { namespace testing { protected: signed_block_ptr _produce_block( fc::microseconds skip_time, bool skip_pending_trxs = false, uint32_t skip_flag = 0 ); void _start_block(fc::time_point block_time); + signed_block_ptr _finish_block(); // Fields: protected: @@ -304,6 +317,10 @@ namespace eosio { namespace testing { return _produce_block(skip_time, true, skip_flag); } + signed_block_ptr finish_block()override { + return _finish_block(); + } + bool validate() { return true; } }; @@ -351,7 +368,7 @@ namespace eosio { namespace testing { validating_node = std::make_unique(vcfg); validating_node->add_indices(); - validating_node->startup(); + validating_node->startup( []() { return false; } ); init(true); } @@ -366,14 +383,15 @@ namespace eosio { namespace testing { validating_node = std::make_unique(vcfg); validating_node->add_indices(); - validating_node->startup(); + validating_node->startup( []() { return false; } ); init(config); } signed_block_ptr produce_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms), uint32_t skip_flag = 0 /*skip_missed_block_penalty*/ )override { auto sb = _produce_block(skip_time, false, skip_flag | 2); - validating_node->push_block( sb ); + auto bs = validating_node->create_block_state_future( sb ); + validating_node->push_block( bs ); return sb; } @@ -383,19 +401,23 @@ namespace eosio { namespace testing { } void validate_push_block(const signed_block_ptr& sb) { - validating_node->push_block( sb ); + auto bs = validating_node->create_block_state_future( sb ); + validating_node->push_block( bs ); } signed_block_ptr produce_empty_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms), uint32_t skip_flag = 0 /*skip_missed_block_penalty*/ )override { control->abort_block(); auto sb = _produce_block(skip_time, true, skip_flag | 2); - validating_node->push_block( sb ); - - + auto bs = validating_node->create_block_state_future( sb ); + validating_node->push_block( bs ); return sb; } + signed_block_ptr finish_block()override { + return _finish_block(); + } + bool validate() { @@ -411,7 +433,7 @@ namespace eosio { namespace testing { validating_node.reset(); validating_node = std::make_unique(vcfg); validating_node->add_indices(); - validating_node->startup(); + validating_node->startup( []() { return false; } ); return ok; } diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index b116d1a4969..a632cb40643 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -124,7 +125,7 @@ namespace eosio { namespace testing { void base_tester::open( const snapshot_reader_ptr& snapshot) { control.reset( new controller(cfg) ); control->add_indices(); - control->startup(snapshot); + control->startup( []() { return false; }, snapshot); chain_transactions.clear(); control->accepted_block.connect([this]( const block_state_ptr& block_state ){ FC_ASSERT( block_state->block ); @@ -141,8 +142,9 @@ namespace eosio { namespace testing { } signed_block_ptr base_tester::push_block(signed_block_ptr b) { + auto bs = control->create_block_state_future(b); control->abort_block(); - control->push_block(b); + control->push_block(bs); auto itr = last_produced_block.find(b->producer); if (itr == last_produced_block.end() || block_header::num_from_id(b->id()) > block_header::num_from_id(itr->second)) { @@ -161,28 +163,17 @@ namespace eosio { namespace testing { _start_block( next_time ); } - auto producer = control->head_block_state()->get_scheduled_producer(next_time); - private_key_type priv_key; - // Check if signing private key exist in the list - auto private_key_itr = block_signing_private_keys.find( producer.block_signing_key ); - if( private_key_itr == block_signing_private_keys.end() ) { - // If it's not found, default to active k1 key - priv_key = get_private_key( producer.producer_name, "active" ); - } else { - priv_key = private_key_itr->second; - } - if( !skip_pending_trxs ) { - auto unapplied_trxs = control->get_unapplied_transactions(); - for (const auto& trx : unapplied_trxs ) { - auto trace = control->push_transaction(trx, fc::time_point::maximum()); + unapplied_transactions_type unapplied_trxs = control->get_unapplied_transactions(); // make copy of map + for (const auto& entry : unapplied_trxs ) { + auto trace = control->push_transaction(entry.second, fc::time_point::maximum()); if(trace->except) { trace->except->dynamic_rethrow_exception(); } } vector scheduled_trxs; - while( (scheduled_trxs = control->get_scheduled_transactions() ).size() > 0 ) { + while( (scheduled_trxs = get_scheduled_transactions() ).size() > 0 ) { for (const auto& trx : scheduled_trxs ) { auto trace = control->push_scheduled_transaction(trx, fc::time_point::maximum()); if(trace->except) { @@ -192,18 +183,10 @@ namespace eosio { namespace testing { } } - - - control->finalize_block(); - control->sign_block( [&]( digest_type d ) { - return priv_key.sign(d); - }); - - control->commit_block(); - last_produced_block[control->head_block_state()->header.producer] = control->head_block_state()->id; + auto head_block = _finish_block(); _start_block( next_time + fc::microseconds(config::block_interval_us)); - return control->head_block_state()->block; + return head_block; } void base_tester::_start_block(fc::time_point block_time) { @@ -220,6 +203,30 @@ namespace eosio { namespace testing { control->start_block( block_time, head_block_number - last_produced_block_num ); } + signed_block_ptr base_tester::_finish_block() { + FC_ASSERT( control->pending_block_state(), "must first start a block before it can be finished" ); + + auto producer = control->head_block_state()->get_scheduled_producer( control->pending_block_time() ); + private_key_type priv_key; + // Check if signing private key exist in the list + auto private_key_itr = block_signing_private_keys.find( producer.block_signing_key ); + if( private_key_itr == block_signing_private_keys.end() ) { + // If it's not found, default to active k1 key + priv_key = get_private_key( producer.producer_name, "active" ); + } else { + priv_key = private_key_itr->second; + } + + control->finalize_block(); + control->sign_block( [&]( digest_type d ) { + return priv_key.sign(d); + }); + + control->commit_block(); + last_produced_block[control->head_block_state()->header.producer] = control->head_block_state()->id; + + return control->head_block_state()->block; + } void base_tester::produce_blocks( uint32_t n, bool empty ) { if( empty ) { @@ -231,6 +238,18 @@ namespace eosio { namespace testing { } } + vector base_tester::get_scheduled_transactions() const { + const auto& idx = control->db().get_index(); + + vector result; + + auto itr = idx.begin(); + while( itr != idx.end() && itr->delay_until <= control->pending_block_time() ) { + result.emplace_back(itr->trx_id); + ++itr; + } + return result; + } void base_tester::produce_blocks_until_end_of_round() { uint64_t blocks_per_round; @@ -327,7 +346,7 @@ namespace eosio { namespace testing { { try { if( !control->pending_block_state() ) _start_block(control->head_block_time() + fc::microseconds(config::block_interval_us)); - auto r = control->push_transaction( std::make_shared(trx), deadline, billed_cpu_time_us ); + auto r = control->push_transaction( std::make_shared(std::make_shared(trx)), deadline, billed_cpu_time_us ); if( r->except_ptr ) std::rethrow_exception( r->except_ptr ); if( r->except ) throw *r->except; return r; @@ -795,8 +814,9 @@ namespace eosio { namespace testing { for( int i = 1; i <= a.control->head_block_num(); ++i ) { auto block = a.control->fetch_block_by_number(i); if( block ) { //&& !b.control->is_known_block(block->id()) ) { + auto bs = b.control->create_block_state_future( block ); b.control->abort_block(); - b.control->push_block(block); //, eosio::chain::validation_steps::created_block); + b.control->push_block(bs); //, eosio::chain::validation_steps::created_block); } } }; diff --git a/libraries/utilities/CMakeLists.txt b/libraries/utilities/CMakeLists.txt deleted file mode 100644 index 4aed508d14f..00000000000 --- a/libraries/utilities/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -#list( APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/libraries/fc/GitVersionGen" ) -#include( GetGitRevisionDescription ) -#get_git_head_revision(GIT_REFSPEC EOS_GIT_REVISION_SHA) -#get_git_unix_timestamp(EOS_GIT_REVISION_UNIX_TIMESTAMP) -#git_describe(EOS_GIT_REVISION_DESCRIPTION --tags) -if(NOT EOS_GIT_REVISION_DESCRIPTION) - set(EOS_GIT_REVISION_DESCRIPTION "unknown") -endif(NOT EOS_GIT_REVISION_DESCRIPTION) - -file(GLOB HEADERS "include/eosio/utilities/*.hpp") - -set(sources - key_conversion.cpp - string_escape.cpp - tempdir.cpp - words.cpp - ${HEADERS}) - -#configure_file("${CMAKE_CURRENT_SOURCE_DIR}/git_revision.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/git_revision.cpp" @ONLY) -#list(APPEND sources "${CMAKE_CURRENT_BINARY_DIR}/git_revision.cpp") - -add_library( eos_utilities - ${sources} - ${HEADERS} ) -target_link_libraries( eos_utilities fc WAST WASM ) -target_include_directories( eos_utilities - PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" - "${CMAKE_CURRENT_SOURCE_DIR}/../wasm-jit/Include" ) -if (USE_PCH) - set_target_properties(eos_utilities PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE) - cotire(eos_utilities) -endif(USE_PCH) diff --git a/libraries/utilities/git_revision.cpp.in b/libraries/utilities/git_revision.cpp.in deleted file mode 100644 index 9c52da41307..00000000000 --- a/libraries/utilities/git_revision.cpp.in +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -#define EOS_GIT_REVISION_SHA "@EOS_GIT_REVISION_SHA@" -#define EOS_GIT_REVISION_UNIX_TIMESTAMP @EOS_GIT_REVISION_UNIX_TIMESTAMP@ -#define EOS_GIT_REVISION_DESCRIPTION "@EOS_GIT_REVISION_DESCRIPTION@" - -namespace eosio { namespace utilities { - -const char* const git_revision_sha = EOS_GIT_REVISION_SHA; -const uint32_t git_revision_unix_timestamp = EOS_GIT_REVISION_UNIX_TIMESTAMP; -const char* const git_revision_description = EOS_GIT_REVISION_DESCRIPTION; - -} } // end namespace eosio::utilities diff --git a/libraries/utilities/include/eosio/utilities/common.hpp b/libraries/utilities/include/eosio/utilities/common.hpp deleted file mode 100644 index 793a3d58e7a..00000000000 --- a/libraries/utilities/include/eosio/utilities/common.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - * - */ -#pragma once - -#ifndef COMMON_HPP -#define COMMON_HPP - -namespace eosio { namespace utilities { namespace common { - template - std::string itoh(I n, size_t hlen = sizeof(I)<<1) { - static const char* digits = "0123456789abcdef"; - std::string r(hlen, '0'); - for(size_t i = 0, j = (hlen - 1) * 4 ; i < hlen; ++i, j -= 4) - r[i] = digits[(n>>j) & 0x0f]; - return r; - } -}}} - -#endif // COMMON_HPP diff --git a/libraries/utilities/include/eosio/utilities/git_revision.hpp b/libraries/utilities/include/eosio/utilities/git_revision.hpp deleted file mode 100644 index 85697d645eb..00000000000 --- a/libraries/utilities/include/eosio/utilities/git_revision.hpp +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once -#include - -namespace eosio { namespace utilities { - -extern const char* const git_revision_sha; -extern const uint32_t git_revision_unix_timestamp; -extern const char* const git_revision_description; - -} } // end namespace eosio::utilities diff --git a/libraries/utilities/include/eosio/utilities/key_conversion.hpp b/libraries/utilities/include/eosio/utilities/key_conversion.hpp deleted file mode 100644 index 0d6daaf903a..00000000000 --- a/libraries/utilities/include/eosio/utilities/key_conversion.hpp +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -#include -#include -#include - -namespace eosio { namespace utilities { - -std::string key_to_wif(const fc::sha256& private_secret ); -std::string key_to_wif(const fc::ecc::private_key& key); -fc::optional wif_to_key( const std::string& wif_key ); - -} } // end namespace eosio::utilities diff --git a/libraries/utilities/include/eosio/utilities/padding_ostream.hpp b/libraries/utilities/include/eosio/utilities/padding_ostream.hpp deleted file mode 100644 index fbf7a34396a..00000000000 --- a/libraries/utilities/include/eosio/utilities/padding_ostream.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -namespace eosio { namespace utilities { - -template -class padding_ostream : public fc::buffered_ostream { -public: - padding_ostream( fc::ostream_ptr o, size_t bufsize = 4096 ) : buffered_ostream(o, bufsize) {} - virtual ~padding_ostream() {} - - virtual size_t writesome( const char* buffer, size_t len ) { - auto out = buffered_ostream::writesome(buffer, len); - bytes_out += out; - bytes_out %= BlockSize; - return out; - } - virtual size_t writesome( const std::shared_ptr& buf, size_t len, size_t offset ) { - auto out = buffered_ostream::writesome(buf, len, offset); - bytes_out += out; - bytes_out %= BlockSize; - return out; - } - virtual void flush() { - static const char pad = PaddingChar; - while( bytes_out % BlockSize ) - writesome(&pad, 1); - buffered_ostream::flush(); - } - -private: - size_t bytes_out = 0; -}; - -} } //eosio::utilities - diff --git a/libraries/utilities/include/eosio/utilities/rand.hpp b/libraries/utilities/include/eosio/utilities/rand.hpp deleted file mode 100644 index 556f706d1b3..00000000000 --- a/libraries/utilities/include/eosio/utilities/rand.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#ifndef RAND_HPP -#define RAND_HPP 1 - -#include - -namespace eosio { namespace utilities { namespace rand { - -/// High performance random generator -/// http://xorshift.di.unimi.it/ - -class random { -private: - - uint64_t seed; - -public: - - random(uint64_t seed) { - this->seed = seed; - } - - uint64_t next() { - uint64_t z = (seed += UINT64_C(0x9E3779B97F4A7C15)); - z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9); - z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB); - return z ^ (z >> 31); - } - - template - void shuffle(Range&& range) { - int idx_count = range.size(); - for (auto idx = range.rbegin(); idx != range.rend() - 1; ++idx , --idx_count) { - std::swap(range.at(next() % idx_count), *idx); - } - } -}; - -} } } //eosio::utilities::rand - -#endif // RAND_HPP diff --git a/libraries/utilities/include/eosio/utilities/string_escape.hpp b/libraries/utilities/include/eosio/utilities/string_escape.hpp deleted file mode 100644 index 03870b73e2d..00000000000 --- a/libraries/utilities/include/eosio/utilities/string_escape.hpp +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -#include - -namespace eosio { namespace utilities { - - std::string escape_string_for_c_source_code(const std::string& input); - -} } // end namespace eosio::utilities diff --git a/libraries/utilities/include/eosio/utilities/tempdir.hpp b/libraries/utilities/include/eosio/utilities/tempdir.hpp deleted file mode 100644 index 0151a7d88a7..00000000000 --- a/libraries/utilities/include/eosio/utilities/tempdir.hpp +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -#include - -#include - -namespace eosio { namespace utilities { - -fc::path temp_directory_path(); - -} } // eosio::utilities diff --git a/libraries/utilities/include/eosio/utilities/words.hpp b/libraries/utilities/include/eosio/utilities/words.hpp deleted file mode 100644 index cc1ead427a7..00000000000 --- a/libraries/utilities/include/eosio/utilities/words.hpp +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -namespace eosio { namespace words { - -typedef const char* const_char_ptr; -extern const const_char_ptr word_list[]; -extern const uint32_t word_list_size; - -} } diff --git a/libraries/utilities/key_conversion.cpp b/libraries/utilities/key_conversion.cpp deleted file mode 100644 index 693514f6c99..00000000000 --- a/libraries/utilities/key_conversion.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#include -#include -#include - -namespace eosio { namespace utilities { - -std::string key_to_wif(const fc::sha256& secret ) -{ - const size_t size_of_data_to_hash = sizeof(secret) + 1; - const size_t size_of_hash_bytes = 4; - char data[size_of_data_to_hash + size_of_hash_bytes]; - data[0] = (char)0x80; - memcpy(&data[1], (char*)&secret, sizeof(secret)); - fc::sha256 digest = fc::sha256::hash(data, size_of_data_to_hash); - digest = fc::sha256::hash(digest); - memcpy(data + size_of_data_to_hash, (char*)&digest, size_of_hash_bytes); - return fc::to_base58(data, sizeof(data)); -} -std::string key_to_wif(const fc::ecc::private_key& key) -{ - return key_to_wif( key.get_secret() ); -} - -fc::optional wif_to_key( const std::string& wif_key ) -{ - std::vector wif_bytes; - try - { - wif_bytes = fc::from_base58(wif_key); - } - catch (const fc::parse_error_exception&) - { - return fc::optional(); - } - if (wif_bytes.size() < 5) - return fc::optional(); - std::vector key_bytes(wif_bytes.begin() + 1, wif_bytes.end() - 4); - fc::ecc::private_key key = fc::variant(key_bytes).as(); - fc::sha256 check = fc::sha256::hash(wif_bytes.data(), wif_bytes.size() - 4); - fc::sha256 check2 = fc::sha256::hash(check); - - if( memcmp( (char*)&check, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 || - memcmp( (char*)&check2, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 ) - return key; - - return fc::optional(); -} - -} } // end namespace eosio::utilities diff --git a/libraries/utilities/string_escape.cpp b/libraries/utilities/string_escape.cpp deleted file mode 100644 index 05421b327c3..00000000000 --- a/libraries/utilities/string_escape.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ - -#include -#include - -namespace eosio { namespace utilities { - - std::string escape_string_for_c_source_code(const std::string& input) - { - std::ostringstream escaped_string; - escaped_string << "\""; - for (unsigned i = 0; i < input.size(); ++i) - { - switch (input[i]) - { - case '\a': - escaped_string << "\\a"; - break; - case '\b': - escaped_string << "\\b"; - break; - case '\t': - escaped_string << "\\t"; - break; - case '\n': - escaped_string << "\\n"; - break; - case '\v': - escaped_string << "\\v"; - break; - case '\f': - escaped_string << "\\f"; - break; - case '\r': - escaped_string << "\\r"; - break; - case '\\': - escaped_string << "\\\\"; - break; - case '\"': - escaped_string << "\\\""; - break; - default: - escaped_string << input[i]; - } - } - escaped_string << "\""; - return escaped_string.str(); - } - -} } // end namespace eosio::utilities - diff --git a/libraries/utilities/tempdir.cpp b/libraries/utilities/tempdir.cpp deleted file mode 100644 index 5aae9cbbede..00000000000 --- a/libraries/utilities/tempdir.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ - -#include - -#include - -namespace eosio { namespace utilities { - -fc::path temp_directory_path() -{ - const char* eos_tempdir = getenv("EOS_TEMPDIR"); - if( eos_tempdir != nullptr ) - return fc::path( eos_tempdir ); - return fc::temp_directory_path() / "eos-tmp"; -} - -} } // eosio::utilities diff --git a/libraries/utilities/words.cpp b/libraries/utilities/words.cpp deleted file mode 100644 index 0da88e78af5..00000000000 --- a/libraries/utilities/words.cpp +++ /dev/null @@ -1,49764 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#include -#include - -namespace eosio { namespace words { - -const const_char_ptr word_list[] = { -"a", -"aa", -"aal", -"aalii", -"aam", -"aba", -"abac", -"abaca", -"abacate", -"abacay", -"abacist", -"aback", -"abactor", -"abacus", -"abaff", -"abaft", -"abaiser", -"abalone", -"abandon", -"abas", -"abase", -"abased", -"abaser", -"abash", -"abashed", -"abasia", -"abasic", -"abask", -"abate", -"abater", -"abatis", -"abaton", -"abator", -"abature", -"abave", -"abaxial", -"abaxile", -"abaze", -"abb", -"abbacy", -"abbas", -"abbasi", -"abbassi", -"abbess", -"abbey", -"abbot", -"abbotcy", -"abdal", -"abdat", -"abdest", -"abdomen", -"abduce", -"abduct", -"abeam", -"abear", -"abed", -"abeigh", -"abele", -"abelite", -"abet", -"abettal", -"abettor", -"abey", -"abeyant", -"abfarad", -"abhenry", -"abhor", -"abidal", -"abide", -"abider", -"abidi", -"abiding", -"abietic", -"abietin", -"abigail", -"abigeat", -"abigeus", -"abilao", -"ability", -"abilla", -"abilo", -"abiosis", -"abiotic", -"abir", -"abiston", -"abiuret", -"abject", -"abjoint", -"abjudge", -"abjure", -"abjurer", -"abkar", -"abkari", -"ablach", -"ablare", -"ablate", -"ablator", -"ablaut", -"ablaze", -"able", -"ableeze", -"abler", -"ablest", -"ablins", -"abloom", -"ablow", -"ablude", -"abluent", -"ablush", -"ably", -"abmho", -"abnet", -"aboard", -"abode", -"abody", -"abohm", -"aboil", -"abolish", -"abolla", -"aboma", -"abomine", -"aboon", -"aborad", -"aboral", -"abord", -"abort", -"aborted", -"abortin", -"abortus", -"abound", -"about", -"abouts", -"above", -"abox", -"abrade", -"abrader", -"abraid", -"abrasax", -"abrase", -"abrash", -"abraum", -"abraxas", -"abreact", -"abreast", -"abret", -"abrico", -"abridge", -"abrim", -"abrin", -"abroach", -"abroad", -"abrook", -"abrupt", -"abscess", -"abscind", -"abscise", -"absciss", -"abscond", -"absence", -"absent", -"absit", -"absmho", -"absohm", -"absolve", -"absorb", -"absorpt", -"abstain", -"absume", -"absurd", -"absvolt", -"abthain", -"abu", -"abucco", -"abulia", -"abulic", -"abuna", -"abura", -"aburban", -"aburst", -"aburton", -"abuse", -"abusee", -"abuser", -"abusion", -"abusive", -"abut", -"abuttal", -"abutter", -"abuzz", -"abvolt", -"abwab", -"aby", -"abysm", -"abysmal", -"abyss", -"abyssal", -"acaciin", -"acacin", -"academe", -"academy", -"acajou", -"acaleph", -"acana", -"acanth", -"acantha", -"acapnia", -"acapu", -"acara", -"acardia", -"acari", -"acarian", -"acarid", -"acarine", -"acaroid", -"acarol", -"acate", -"acatery", -"acaudal", -"acca", -"accede", -"acceder", -"accend", -"accent", -"accept", -"accerse", -"access", -"accidia", -"accidie", -"accinge", -"accite", -"acclaim", -"accloy", -"accoast", -"accoil", -"accolle", -"accompt", -"accord", -"accost", -"account", -"accoy", -"accrete", -"accrual", -"accrue", -"accruer", -"accurse", -"accusal", -"accuse", -"accused", -"accuser", -"ace", -"acedia", -"acedy", -"acephal", -"acerate", -"acerb", -"acerbic", -"acerdol", -"acerin", -"acerose", -"acerous", -"acerra", -"aceship", -"acetal", -"acetate", -"acetic", -"acetify", -"acetin", -"acetize", -"acetoin", -"acetol", -"acetone", -"acetose", -"acetous", -"acetum", -"acetyl", -"ach", -"achage", -"achar", -"achate", -"ache", -"achene", -"acher", -"achete", -"achieve", -"achigan", -"achill", -"achime", -"aching", -"achira", -"acholia", -"acholic", -"achor", -"achree", -"achroma", -"achtel", -"achy", -"achylia", -"achymia", -"acicula", -"acid", -"acider", -"acidic", -"acidify", -"acidite", -"acidity", -"acidize", -"acidly", -"acidoid", -"acidyl", -"acier", -"aciform", -"acinar", -"acinary", -"acinic", -"acinose", -"acinous", -"acinus", -"aciurgy", -"acker", -"ackey", -"ackman", -"acknow", -"acle", -"aclinal", -"aclinic", -"acloud", -"aclys", -"acmatic", -"acme", -"acmic", -"acmite", -"acne", -"acnemia", -"acnodal", -"acnode", -"acock", -"acocotl", -"acoin", -"acoine", -"acold", -"acology", -"acolous", -"acolyte", -"acoma", -"acomia", -"acomous", -"acone", -"aconic", -"aconin", -"aconine", -"aconite", -"acopic", -"acopon", -"acor", -"acorea", -"acoria", -"acorn", -"acorned", -"acosmic", -"acouasm", -"acouchi", -"acouchy", -"acoupa", -"acquest", -"acquire", -"acquist", -"acquit", -"acracy", -"acraein", -"acrasia", -"acratia", -"acrawl", -"acraze", -"acre", -"acreage", -"acreak", -"acream", -"acred", -"acreman", -"acrid", -"acridan", -"acridic", -"acridly", -"acridyl", -"acrinyl", -"acrisia", -"acritan", -"acrite", -"acritol", -"acroama", -"acrobat", -"acrogen", -"acron", -"acronyc", -"acronym", -"acronyx", -"acrook", -"acrose", -"across", -"acrotic", -"acryl", -"acrylic", -"acrylyl", -"act", -"acta", -"actable", -"actify", -"actin", -"actinal", -"actine", -"acting", -"actinic", -"actinon", -"action", -"active", -"activin", -"actless", -"acton", -"actor", -"actress", -"actu", -"actual", -"actuary", -"acture", -"acuate", -"acuity", -"aculea", -"aculeus", -"acumen", -"acushla", -"acutate", -"acute", -"acutely", -"acutish", -"acyclic", -"acyesis", -"acyetic", -"acyl", -"acylate", -"acyloin", -"acyloxy", -"acystia", -"ad", -"adactyl", -"adad", -"adage", -"adagial", -"adagio", -"adamant", -"adamas", -"adamine", -"adamite", -"adance", -"adangle", -"adapid", -"adapt", -"adapter", -"adaptor", -"adarme", -"adat", -"adati", -"adatom", -"adaunt", -"adaw", -"adawe", -"adawlut", -"adawn", -"adaxial", -"aday", -"adays", -"adazzle", -"adcraft", -"add", -"adda", -"addable", -"addax", -"added", -"addedly", -"addend", -"addenda", -"adder", -"addible", -"addict", -"addle", -"addlins", -"address", -"addrest", -"adduce", -"adducer", -"adduct", -"ade", -"adead", -"adeem", -"adeep", -"adeling", -"adelite", -"adenase", -"adenia", -"adenine", -"adenoid", -"adenoma", -"adenose", -"adenyl", -"adept", -"adermia", -"adermin", -"adet", -"adevism", -"adfix", -"adhaka", -"adharma", -"adhere", -"adherer", -"adhibit", -"adiate", -"adicity", -"adieu", -"adieux", -"adinole", -"adion", -"adipate", -"adipic", -"adipoid", -"adipoma", -"adipose", -"adipous", -"adipsia", -"adipsic", -"adipsy", -"adipyl", -"adit", -"adital", -"aditus", -"adjag", -"adject", -"adjiger", -"adjoin", -"adjoint", -"adjourn", -"adjudge", -"adjunct", -"adjure", -"adjurer", -"adjust", -"adlay", -"adless", -"adlet", -"adman", -"admi", -"admiral", -"admire", -"admired", -"admirer", -"admit", -"admix", -"adnate", -"adnex", -"adnexal", -"adnexed", -"adnoun", -"ado", -"adobe", -"adonin", -"adonite", -"adonize", -"adopt", -"adopted", -"adoptee", -"adopter", -"adoral", -"adorant", -"adore", -"adorer", -"adorn", -"adorner", -"adossed", -"adoulie", -"adown", -"adoxy", -"adoze", -"adpao", -"adpress", -"adread", -"adream", -"adreamt", -"adrenal", -"adrenin", -"adrift", -"adrip", -"adroit", -"adroop", -"adrop", -"adrowse", -"adrue", -"adry", -"adsbud", -"adsmith", -"adsorb", -"adtevac", -"adular", -"adulate", -"adult", -"adulter", -"adunc", -"adusk", -"adust", -"advance", -"advene", -"adverb", -"adverse", -"advert", -"advice", -"advisal", -"advise", -"advised", -"advisee", -"adviser", -"advisor", -"advowee", -"ady", -"adynamy", -"adyta", -"adyton", -"adytum", -"adz", -"adze", -"adzer", -"adzooks", -"ae", -"aecial", -"aecium", -"aedile", -"aedilic", -"aefald", -"aefaldy", -"aefauld", -"aegis", -"aenach", -"aenean", -"aeneous", -"aeolid", -"aeolina", -"aeoline", -"aeon", -"aeonial", -"aeonian", -"aeonist", -"aer", -"aerage", -"aerate", -"aerator", -"aerial", -"aeric", -"aerical", -"aerie", -"aeried", -"aerify", -"aero", -"aerobe", -"aerobic", -"aerobus", -"aerogel", -"aerogen", -"aerogun", -"aeronat", -"aeronef", -"aerose", -"aerosol", -"aerugo", -"aery", -"aes", -"aevia", -"aface", -"afaint", -"afar", -"afara", -"afear", -"afeard", -"afeared", -"afernan", -"afetal", -"affa", -"affable", -"affably", -"affair", -"affaite", -"affect", -"affeer", -"affeir", -"affiant", -"affinal", -"affine", -"affined", -"affirm", -"affix", -"affixal", -"affixer", -"afflict", -"afflux", -"afforce", -"afford", -"affray", -"affront", -"affuse", -"affy", -"afghani", -"afield", -"afire", -"aflame", -"aflare", -"aflat", -"aflaunt", -"aflight", -"afloat", -"aflow", -"aflower", -"aflush", -"afoam", -"afoot", -"afore", -"afoul", -"afraid", -"afreet", -"afresh", -"afret", -"afront", -"afrown", -"aft", -"aftaba", -"after", -"aftergo", -"aftmost", -"aftosa", -"aftward", -"aga", -"again", -"against", -"agal", -"agalaxy", -"agalite", -"agallop", -"agalma", -"agama", -"agamete", -"agami", -"agamian", -"agamic", -"agamid", -"agamoid", -"agamont", -"agamous", -"agamy", -"agape", -"agapeti", -"agar", -"agaric", -"agarita", -"agarwal", -"agasp", -"agate", -"agathin", -"agatine", -"agatize", -"agatoid", -"agaty", -"agavose", -"agaze", -"agazed", -"age", -"aged", -"agedly", -"agee", -"ageless", -"agelong", -"agen", -"agency", -"agenda", -"agendum", -"agent", -"agentry", -"ager", -"ageusia", -"ageusic", -"agger", -"aggrade", -"aggrate", -"aggress", -"aggroup", -"aggry", -"aggur", -"agha", -"aghanee", -"aghast", -"agile", -"agilely", -"agility", -"aging", -"agio", -"agist", -"agistor", -"agitant", -"agitate", -"agla", -"aglance", -"aglare", -"agleaf", -"agleam", -"aglet", -"agley", -"aglint", -"aglow", -"aglucon", -"agnail", -"agname", -"agnamed", -"agnate", -"agnatic", -"agnel", -"agnize", -"agnomen", -"agnosia", -"agnosis", -"agnosy", -"agnus", -"ago", -"agog", -"agoge", -"agogic", -"agogics", -"agoho", -"agoing", -"agon", -"agonal", -"agone", -"agonic", -"agonied", -"agonist", -"agonium", -"agonize", -"agony", -"agora", -"agouara", -"agouta", -"agouti", -"agpaite", -"agrah", -"agral", -"agre", -"agree", -"agreed", -"agreer", -"agrege", -"agria", -"agrin", -"agrise", -"agrito", -"agroan", -"agrom", -"agroof", -"agrope", -"aground", -"agrufe", -"agruif", -"agsam", -"agua", -"ague", -"aguey", -"aguish", -"agunah", -"agush", -"agust", -"agy", -"agynary", -"agynous", -"agyrate", -"agyria", -"ah", -"aha", -"ahaaina", -"ahaunch", -"ahead", -"aheap", -"ahem", -"ahey", -"ahimsa", -"ahind", -"ahint", -"ahmadi", -"aho", -"ahong", -"ahorse", -"ahoy", -"ahsan", -"ahu", -"ahuatle", -"ahull", -"ahum", -"ahungry", -"ahunt", -"ahura", -"ahush", -"ahwal", -"ahypnia", -"ai", -"aid", -"aidable", -"aidance", -"aidant", -"aide", -"aider", -"aidful", -"aidless", -"aiel", -"aiglet", -"ail", -"ailanto", -"aile", -"aileron", -"ailette", -"ailing", -"aillt", -"ailment", -"ailsyte", -"ailuro", -"ailweed", -"aim", -"aimara", -"aimer", -"aimful", -"aiming", -"aimless", -"ainaleh", -"ainhum", -"ainoi", -"ainsell", -"aint", -"aion", -"aionial", -"air", -"airable", -"airampo", -"airan", -"aircrew", -"airdock", -"airdrop", -"aire", -"airer", -"airfoil", -"airhead", -"airily", -"airing", -"airish", -"airless", -"airlift", -"airlike", -"airmail", -"airman", -"airmark", -"airpark", -"airport", -"airship", -"airsick", -"airt", -"airward", -"airway", -"airy", -"aisle", -"aisled", -"aisling", -"ait", -"aitch", -"aitesis", -"aition", -"aiwan", -"aizle", -"ajaja", -"ajangle", -"ajar", -"ajari", -"ajava", -"ajhar", -"ajivika", -"ajog", -"ajoint", -"ajowan", -"ak", -"aka", -"akala", -"akaroa", -"akasa", -"akazga", -"akcheh", -"ake", -"akeake", -"akebi", -"akee", -"akeki", -"akeley", -"akepiro", -"akerite", -"akey", -"akhoond", -"akhrot", -"akhyana", -"akia", -"akimbo", -"akin", -"akindle", -"akinete", -"akmudar", -"aknee", -"ako", -"akoasm", -"akoasma", -"akonge", -"akov", -"akpek", -"akra", -"aku", -"akule", -"akund", -"al", -"ala", -"alacha", -"alack", -"alada", -"alaihi", -"alaite", -"alala", -"alalite", -"alalus", -"alameda", -"alamo", -"alamoth", -"alan", -"aland", -"alangin", -"alani", -"alanine", -"alannah", -"alantic", -"alantin", -"alantol", -"alanyl", -"alar", -"alares", -"alarm", -"alarmed", -"alarum", -"alary", -"alas", -"alate", -"alated", -"alatern", -"alation", -"alb", -"alba", -"alban", -"albarco", -"albata", -"albe", -"albedo", -"albee", -"albeit", -"albetad", -"albify", -"albinal", -"albinic", -"albino", -"albite", -"albitic", -"albugo", -"album", -"albumen", -"albumin", -"alburn", -"albus", -"alcaide", -"alcalde", -"alcanna", -"alcazar", -"alchemy", -"alchera", -"alchimy", -"alchymy", -"alcine", -"alclad", -"alco", -"alcoate", -"alcogel", -"alcohol", -"alcosol", -"alcove", -"alcyon", -"aldane", -"aldazin", -"aldehol", -"alder", -"aldern", -"aldim", -"aldime", -"aldine", -"aldol", -"aldose", -"ale", -"aleak", -"alec", -"alecize", -"alecost", -"alecup", -"alee", -"alef", -"aleft", -"alegar", -"alehoof", -"alem", -"alemana", -"alembic", -"alemite", -"alemmal", -"alen", -"aleph", -"alephs", -"alepole", -"alepot", -"alerce", -"alerse", -"alert", -"alertly", -"alesan", -"aletap", -"alette", -"alevin", -"alewife", -"alexia", -"alexic", -"alexin", -"aleyard", -"alf", -"alfa", -"alfaje", -"alfalfa", -"alfaqui", -"alfet", -"alfiona", -"alfonso", -"alforja", -"alga", -"algae", -"algal", -"algalia", -"algate", -"algebra", -"algedo", -"algesia", -"algesic", -"algesis", -"algetic", -"algic", -"algid", -"algific", -"algin", -"algine", -"alginic", -"algist", -"algoid", -"algor", -"algosis", -"algous", -"algum", -"alhenna", -"alias", -"alibi", -"alible", -"alichel", -"alidade", -"alien", -"aliency", -"alienee", -"aliener", -"alienor", -"alif", -"aliform", -"alight", -"align", -"aligner", -"aliipoe", -"alike", -"alima", -"aliment", -"alimony", -"alin", -"aliofar", -"alipata", -"aliped", -"aliptes", -"aliptic", -"aliquot", -"alish", -"alisier", -"alismad", -"alismal", -"aliso", -"alison", -"alisp", -"alist", -"alit", -"alite", -"aliunde", -"alive", -"aliyah", -"alizari", -"aljoba", -"alk", -"alkali", -"alkalic", -"alkamin", -"alkane", -"alkanet", -"alkene", -"alkenna", -"alkenyl", -"alkide", -"alkine", -"alkool", -"alkoxy", -"alkoxyl", -"alky", -"alkyd", -"alkyl", -"alkylic", -"alkyne", -"all", -"allan", -"allay", -"allayer", -"allbone", -"allege", -"alleger", -"allegro", -"allele", -"allelic", -"allene", -"aller", -"allergy", -"alley", -"alleyed", -"allgood", -"allheal", -"allice", -"allied", -"allies", -"allness", -"allonym", -"alloquy", -"allose", -"allot", -"allotee", -"allover", -"allow", -"allower", -"alloxan", -"alloy", -"allseed", -"alltud", -"allude", -"allure", -"allurer", -"alluvia", -"allwork", -"ally", -"allyl", -"allylic", -"alma", -"almadia", -"almadie", -"almagra", -"almanac", -"alme", -"almemar", -"almique", -"almirah", -"almoign", -"almon", -"almond", -"almondy", -"almoner", -"almonry", -"almost", -"almous", -"alms", -"almsful", -"almsman", -"almuce", -"almud", -"almude", -"almug", -"almuten", -"aln", -"alnage", -"alnager", -"alnein", -"alnico", -"alnoite", -"alnuin", -"alo", -"alochia", -"alod", -"alodial", -"alodian", -"alodium", -"alody", -"aloe", -"aloed", -"aloesol", -"aloetic", -"aloft", -"alogia", -"alogism", -"alogy", -"aloid", -"aloin", -"aloma", -"alone", -"along", -"alongst", -"aloof", -"aloofly", -"aloose", -"alop", -"alopeke", -"alose", -"aloud", -"alow", -"alowe", -"alp", -"alpaca", -"alpeen", -"alpha", -"alphol", -"alphorn", -"alphos", -"alphyl", -"alpieu", -"alpine", -"alpist", -"alquier", -"alraun", -"already", -"alright", -"alroot", -"alruna", -"also", -"alsoon", -"alt", -"altaite", -"altar", -"altared", -"alter", -"alterer", -"altern", -"alterne", -"althea", -"althein", -"altho", -"althorn", -"altilik", -"altin", -"alto", -"altoun", -"altrose", -"altun", -"aludel", -"alula", -"alular", -"alulet", -"alum", -"alumic", -"alumina", -"alumine", -"alumish", -"alumite", -"alumium", -"alumna", -"alumnae", -"alumnal", -"alumni", -"alumnus", -"alunite", -"alupag", -"alure", -"aluta", -"alvar", -"alveary", -"alveloz", -"alveola", -"alveole", -"alveoli", -"alveus", -"alvine", -"alvite", -"alvus", -"alway", -"always", -"aly", -"alypin", -"alysson", -"am", -"ama", -"amaas", -"amadou", -"amaga", -"amah", -"amain", -"amakebe", -"amala", -"amalaka", -"amalgam", -"amaltas", -"amamau", -"amandin", -"amang", -"amani", -"amania", -"amanori", -"amanous", -"amapa", -"amar", -"amarin", -"amarine", -"amarity", -"amaroid", -"amass", -"amasser", -"amastia", -"amasty", -"amateur", -"amative", -"amatol", -"amatory", -"amaze", -"amazed", -"amazia", -"amazing", -"amba", -"ambage", -"ambalam", -"amban", -"ambar", -"ambaree", -"ambary", -"ambash", -"ambassy", -"ambatch", -"ambay", -"ambeer", -"amber", -"ambery", -"ambiens", -"ambient", -"ambier", -"ambit", -"ambital", -"ambitty", -"ambitus", -"amble", -"ambler", -"ambling", -"ambo", -"ambon", -"ambos", -"ambrain", -"ambrein", -"ambrite", -"ambroid", -"ambrose", -"ambry", -"ambsace", -"ambury", -"ambush", -"amchoor", -"ame", -"ameed", -"ameen", -"amelia", -"amellus", -"amelu", -"amelus", -"amen", -"amend", -"amende", -"amender", -"amends", -"amene", -"amenia", -"amenity", -"ament", -"amental", -"amentia", -"amentum", -"amerce", -"amercer", -"amerism", -"amesite", -"ametria", -"amgarn", -"amhar", -"amhran", -"ami", -"amiable", -"amiably", -"amianth", -"amic", -"amical", -"amice", -"amiced", -"amicron", -"amid", -"amidase", -"amidate", -"amide", -"amidic", -"amidid", -"amidide", -"amidin", -"amidine", -"amido", -"amidol", -"amidon", -"amidoxy", -"amidst", -"amil", -"amimia", -"amimide", -"amin", -"aminate", -"amine", -"amini", -"aminic", -"aminity", -"aminize", -"amino", -"aminoid", -"amir", -"amiray", -"amiss", -"amity", -"amixia", -"amla", -"amli", -"amlikar", -"amlong", -"amma", -"amman", -"ammelin", -"ammer", -"ammeter", -"ammine", -"ammo", -"ammonal", -"ammonia", -"ammonic", -"ammono", -"ammu", -"amnesia", -"amnesic", -"amnesty", -"amnia", -"amniac", -"amnic", -"amnion", -"amniote", -"amober", -"amobyr", -"amoeba", -"amoebae", -"amoeban", -"amoebic", -"amoebid", -"amok", -"amoke", -"amole", -"amomal", -"amomum", -"among", -"amongst", -"amor", -"amorado", -"amoraic", -"amoraim", -"amoral", -"amoret", -"amorism", -"amorist", -"amoroso", -"amorous", -"amorphy", -"amort", -"amotion", -"amotus", -"amount", -"amour", -"amove", -"ampalea", -"amper", -"ampere", -"ampery", -"amphid", -"amphide", -"amphora", -"amphore", -"ample", -"amplify", -"amply", -"ampoule", -"ampul", -"ampulla", -"amputee", -"ampyx", -"amra", -"amreeta", -"amrita", -"amsath", -"amsel", -"amt", -"amtman", -"amuck", -"amuguis", -"amula", -"amulet", -"amulla", -"amunam", -"amurca", -"amuse", -"amused", -"amusee", -"amuser", -"amusia", -"amusing", -"amusive", -"amutter", -"amuyon", -"amuyong", -"amuze", -"amvis", -"amy", -"amyelia", -"amyelic", -"amygdal", -"amyl", -"amylan", -"amylase", -"amylate", -"amylene", -"amylic", -"amylin", -"amylo", -"amyloid", -"amylom", -"amylon", -"amylose", -"amylum", -"amyous", -"amyrin", -"amyrol", -"amyroot", -"an", -"ana", -"anabata", -"anabo", -"anabong", -"anacara", -"anacard", -"anacid", -"anadem", -"anadrom", -"anaemia", -"anaemic", -"anagap", -"anagep", -"anagoge", -"anagogy", -"anagram", -"anagua", -"anahau", -"anal", -"analav", -"analgen", -"analgia", -"analgic", -"anally", -"analogy", -"analyse", -"analyst", -"analyze", -"anam", -"anama", -"anamite", -"anan", -"anana", -"ananas", -"ananda", -"ananym", -"anaphia", -"anapnea", -"anapsid", -"anaqua", -"anarch", -"anarchy", -"anareta", -"anarya", -"anatase", -"anatifa", -"anatine", -"anatomy", -"anatox", -"anatron", -"anaudia", -"anaxial", -"anaxon", -"anaxone", -"anay", -"anba", -"anbury", -"anchor", -"anchovy", -"ancient", -"ancile", -"ancilla", -"ancon", -"anconad", -"anconal", -"ancone", -"ancony", -"ancora", -"ancoral", -"and", -"anda", -"andante", -"andirin", -"andiron", -"andric", -"android", -"androl", -"andron", -"anear", -"aneath", -"anele", -"anemia", -"anemic", -"anemone", -"anemony", -"anend", -"anenst", -"anent", -"anepia", -"anergia", -"anergic", -"anergy", -"anerly", -"aneroid", -"anes", -"anesis", -"aneuria", -"aneuric", -"aneurin", -"anew", -"angaria", -"angary", -"angekok", -"angel", -"angelet", -"angelic", -"angelin", -"angelot", -"anger", -"angerly", -"angeyok", -"angico", -"angild", -"angili", -"angina", -"anginal", -"angioid", -"angioma", -"angle", -"angled", -"angler", -"angling", -"angloid", -"ango", -"angolar", -"angor", -"angrily", -"angrite", -"angry", -"angst", -"angster", -"anguid", -"anguine", -"anguis", -"anguish", -"angula", -"angular", -"anguria", -"anhang", -"anhima", -"anhinga", -"ani", -"anicut", -"anidian", -"aniente", -"anigh", -"anight", -"anights", -"anil", -"anilao", -"anilau", -"anile", -"anilic", -"anilid", -"anilide", -"aniline", -"anility", -"anilla", -"anima", -"animal", -"animate", -"anime", -"animi", -"animism", -"animist", -"animize", -"animous", -"animus", -"anion", -"anionic", -"anis", -"anisal", -"anisate", -"anise", -"aniseed", -"anisic", -"anisil", -"anisoin", -"anisole", -"anisoyl", -"anisum", -"anisyl", -"anither", -"anjan", -"ankee", -"anker", -"ankh", -"ankle", -"anklet", -"anklong", -"ankus", -"ankusha", -"anlace", -"anlaut", -"ann", -"anna", -"annal", -"annale", -"annals", -"annat", -"annates", -"annatto", -"anneal", -"annelid", -"annet", -"annex", -"annexa", -"annexal", -"annexer", -"annite", -"annona", -"annoy", -"annoyer", -"annual", -"annuary", -"annuent", -"annuity", -"annul", -"annular", -"annulet", -"annulus", -"anoa", -"anodal", -"anode", -"anodic", -"anodize", -"anodos", -"anodyne", -"anoesia", -"anoesis", -"anoetic", -"anoil", -"anoine", -"anoint", -"anole", -"anoli", -"anolian", -"anolyte", -"anomaly", -"anomite", -"anomy", -"anon", -"anonang", -"anonol", -"anonym", -"anonyma", -"anopia", -"anopsia", -"anorak", -"anorexy", -"anormal", -"anorth", -"anosmia", -"anosmic", -"another", -"anotia", -"anotta", -"anotto", -"anotus", -"anounou", -"anoxia", -"anoxic", -"ansa", -"ansar", -"ansate", -"ansu", -"answer", -"ant", -"anta", -"antacid", -"antal", -"antapex", -"antdom", -"ante", -"anteact", -"anteal", -"antefix", -"antenna", -"antes", -"antewar", -"anthela", -"anthem", -"anthema", -"anthemy", -"anther", -"anthill", -"anthine", -"anthoid", -"anthood", -"anthrax", -"anthrol", -"anthryl", -"anti", -"antiae", -"antiar", -"antic", -"antical", -"anticly", -"anticor", -"anticum", -"antifat", -"antigen", -"antigod", -"antihum", -"antiqua", -"antique", -"antired", -"antirun", -"antisun", -"antitax", -"antiwar", -"antiwit", -"antler", -"antlia", -"antling", -"antoeci", -"antonym", -"antra", -"antral", -"antre", -"antrin", -"antrum", -"antship", -"antu", -"antwise", -"anubing", -"anuloma", -"anuran", -"anuria", -"anuric", -"anurous", -"anury", -"anus", -"anusim", -"anvil", -"anxiety", -"anxious", -"any", -"anybody", -"anyhow", -"anyone", -"anyway", -"anyways", -"anywhen", -"anywhy", -"anywise", -"aogiri", -"aonach", -"aorist", -"aorta", -"aortal", -"aortic", -"aortism", -"aosmic", -"aoudad", -"apa", -"apace", -"apache", -"apadana", -"apagoge", -"apaid", -"apalit", -"apandry", -"apar", -"aparejo", -"apart", -"apasote", -"apatan", -"apathic", -"apathy", -"apatite", -"ape", -"apeak", -"apedom", -"apehood", -"apeiron", -"apelet", -"apelike", -"apeling", -"apepsia", -"apepsy", -"apeptic", -"aper", -"aperch", -"aperea", -"apert", -"apertly", -"apery", -"apetaly", -"apex", -"apexed", -"aphagia", -"aphakia", -"aphakic", -"aphasia", -"aphasic", -"aphemia", -"aphemic", -"aphesis", -"apheta", -"aphetic", -"aphid", -"aphides", -"aphidid", -"aphodal", -"aphodus", -"aphonia", -"aphonic", -"aphony", -"aphoria", -"aphotic", -"aphrite", -"aphtha", -"aphthic", -"aphylly", -"aphyric", -"apian", -"apiary", -"apiator", -"apicad", -"apical", -"apices", -"apicula", -"apiece", -"apieces", -"apii", -"apiin", -"apilary", -"apinch", -"aping", -"apinoid", -"apio", -"apioid", -"apiole", -"apiolin", -"apionol", -"apiose", -"apish", -"apishly", -"apism", -"apitong", -"apitpat", -"aplanat", -"aplasia", -"aplenty", -"aplite", -"aplitic", -"aplomb", -"aplome", -"apnea", -"apneal", -"apneic", -"apocarp", -"apocha", -"apocope", -"apod", -"apodal", -"apodan", -"apodema", -"apodeme", -"apodia", -"apodous", -"apogamy", -"apogeal", -"apogean", -"apogee", -"apogeic", -"apogeny", -"apohyal", -"apoise", -"apojove", -"apokrea", -"apolar", -"apology", -"aponia", -"aponic", -"apoop", -"apoplex", -"apopyle", -"aporia", -"aporose", -"aport", -"aposia", -"aposoro", -"apostil", -"apostle", -"apothem", -"apotome", -"apotype", -"apout", -"apozem", -"apozema", -"appall", -"apparel", -"appay", -"appeal", -"appear", -"appease", -"append", -"appet", -"appete", -"applaud", -"apple", -"applied", -"applier", -"applot", -"apply", -"appoint", -"apport", -"appose", -"apposer", -"apprend", -"apprise", -"apprize", -"approof", -"approve", -"appulse", -"apraxia", -"apraxic", -"apricot", -"apriori", -"apron", -"apropos", -"apse", -"apsidal", -"apsides", -"apsis", -"apt", -"apteral", -"apteran", -"aptly", -"aptness", -"aptote", -"aptotic", -"apulse", -"apyonin", -"apyrene", -"apyrexy", -"apyrous", -"aqua", -"aquabib", -"aquage", -"aquaria", -"aquatic", -"aquavit", -"aqueous", -"aquifer", -"aquiver", -"aquo", -"aquose", -"ar", -"ara", -"araba", -"araban", -"arabana", -"arabin", -"arabit", -"arable", -"araca", -"aracari", -"arachic", -"arachin", -"arad", -"arado", -"arain", -"arake", -"araliad", -"aralie", -"aralkyl", -"aramina", -"araneid", -"aranein", -"aranga", -"arango", -"arar", -"arara", -"ararao", -"arariba", -"araroba", -"arati", -"aration", -"aratory", -"arba", -"arbacin", -"arbalo", -"arbiter", -"arbor", -"arboral", -"arbored", -"arboret", -"arbute", -"arbutin", -"arbutus", -"arc", -"arca", -"arcade", -"arcana", -"arcanal", -"arcane", -"arcanum", -"arcate", -"arch", -"archae", -"archaic", -"arche", -"archeal", -"arched", -"archer", -"archery", -"arches", -"archeus", -"archfoe", -"archgod", -"archil", -"arching", -"archive", -"archly", -"archon", -"archont", -"archsee", -"archsin", -"archspy", -"archwag", -"archway", -"archy", -"arcing", -"arcked", -"arcking", -"arctian", -"arctic", -"arctiid", -"arctoid", -"arcual", -"arcuale", -"arcuate", -"arcula", -"ardeb", -"ardella", -"ardency", -"ardent", -"ardish", -"ardoise", -"ardor", -"ardri", -"ardu", -"arduous", -"are", -"area", -"areach", -"aread", -"areal", -"arear", -"areaway", -"arecain", -"ared", -"areek", -"areel", -"arefact", -"areito", -"arena", -"arenae", -"arend", -"areng", -"arenoid", -"arenose", -"arent", -"areola", -"areolar", -"areole", -"areolet", -"arete", -"argal", -"argala", -"argali", -"argans", -"argasid", -"argeers", -"argel", -"argenol", -"argent", -"arghan", -"arghel", -"arghool", -"argil", -"argo", -"argol", -"argolet", -"argon", -"argosy", -"argot", -"argotic", -"argue", -"arguer", -"argufy", -"argute", -"argyria", -"argyric", -"arhar", -"arhat", -"aria", -"aribine", -"aricine", -"arid", -"aridge", -"aridian", -"aridity", -"aridly", -"ariel", -"arienzo", -"arietta", -"aright", -"arigue", -"aril", -"ariled", -"arillus", -"ariose", -"arioso", -"ariot", -"aripple", -"arisard", -"arise", -"arisen", -"arist", -"arista", -"arite", -"arjun", -"ark", -"arkite", -"arkose", -"arkosic", -"arles", -"arm", -"armada", -"armbone", -"armed", -"armer", -"armet", -"armful", -"armhole", -"armhoop", -"armied", -"armiger", -"armil", -"armilla", -"arming", -"armless", -"armlet", -"armload", -"armoire", -"armor", -"armored", -"armorer", -"armory", -"armpit", -"armrack", -"armrest", -"arms", -"armscye", -"armure", -"army", -"arn", -"arna", -"arnee", -"arni", -"arnica", -"arnotta", -"arnotto", -"arnut", -"aroar", -"aroast", -"arock", -"aroeira", -"aroid", -"aroint", -"arolium", -"arolla", -"aroma", -"aroon", -"arose", -"around", -"arousal", -"arouse", -"arouser", -"arow", -"aroxyl", -"arpen", -"arpent", -"arrack", -"arrah", -"arraign", -"arrame", -"arrange", -"arrant", -"arras", -"arrased", -"arratel", -"arrau", -"array", -"arrayal", -"arrayer", -"arrear", -"arrect", -"arrent", -"arrest", -"arriage", -"arriba", -"arride", -"arridge", -"arrie", -"arriere", -"arrimby", -"arris", -"arrish", -"arrival", -"arrive", -"arriver", -"arroba", -"arrope", -"arrow", -"arrowed", -"arrowy", -"arroyo", -"arse", -"arsenal", -"arsenic", -"arseno", -"arsenyl", -"arses", -"arsheen", -"arshin", -"arshine", -"arsine", -"arsinic", -"arsino", -"arsis", -"arsle", -"arsoite", -"arson", -"arsonic", -"arsono", -"arsyl", -"art", -"artaba", -"artabe", -"artal", -"artar", -"artel", -"arterin", -"artery", -"artful", -"artha", -"arthel", -"arthral", -"artiad", -"article", -"artisan", -"artist", -"artiste", -"artless", -"artlet", -"artlike", -"artware", -"arty", -"aru", -"arui", -"aruke", -"arumin", -"arupa", -"arusa", -"arusha", -"arustle", -"arval", -"arvel", -"arx", -"ary", -"aryl", -"arylate", -"arzan", -"arzun", -"as", -"asaddle", -"asak", -"asale", -"asana", -"asaphia", -"asaphid", -"asaprol", -"asarite", -"asaron", -"asarone", -"asbest", -"asbolin", -"ascan", -"ascare", -"ascarid", -"ascaron", -"ascend", -"ascent", -"ascetic", -"ascham", -"asci", -"ascian", -"ascii", -"ascites", -"ascitic", -"asclent", -"ascoma", -"ascon", -"ascot", -"ascribe", -"ascript", -"ascry", -"ascula", -"ascus", -"asdic", -"ase", -"asearch", -"aseethe", -"aseity", -"asem", -"asemia", -"asepsis", -"aseptic", -"aseptol", -"asexual", -"ash", -"ashake", -"ashame", -"ashamed", -"ashamnu", -"ashcake", -"ashen", -"asherah", -"ashery", -"ashes", -"ashet", -"ashily", -"ashine", -"ashiver", -"ashkoko", -"ashlar", -"ashless", -"ashling", -"ashman", -"ashore", -"ashpan", -"ashpit", -"ashraf", -"ashrafi", -"ashur", -"ashweed", -"ashwort", -"ashy", -"asialia", -"aside", -"asideu", -"asiento", -"asilid", -"asimen", -"asimmer", -"asinego", -"asinine", -"asitia", -"ask", -"askable", -"askance", -"askant", -"askar", -"askari", -"asker", -"askew", -"askip", -"asklent", -"askos", -"aslant", -"aslaver", -"asleep", -"aslop", -"aslope", -"asmack", -"asmalte", -"asmear", -"asmile", -"asmoke", -"asnort", -"asoak", -"asocial", -"asok", -"asoka", -"asonant", -"asonia", -"asop", -"asor", -"asouth", -"asp", -"aspace", -"aspect", -"aspen", -"asper", -"asperge", -"asperse", -"asphalt", -"asphyxy", -"aspic", -"aspire", -"aspirer", -"aspirin", -"aspish", -"asport", -"aspout", -"asprawl", -"aspread", -"aspring", -"asprout", -"asquare", -"asquat", -"asqueal", -"asquint", -"asquirm", -"ass", -"assacu", -"assagai", -"assai", -"assail", -"assapan", -"assart", -"assary", -"assate", -"assault", -"assaut", -"assay", -"assayer", -"assbaa", -"asse", -"assegai", -"asself", -"assent", -"assert", -"assess", -"asset", -"assets", -"assever", -"asshead", -"assi", -"assify", -"assign", -"assilag", -"assis", -"assise", -"assish", -"assist", -"assize", -"assizer", -"assizes", -"asslike", -"assman", -"assoil", -"assort", -"assuade", -"assuage", -"assume", -"assumed", -"assumer", -"assure", -"assured", -"assurer", -"assurge", -"ast", -"asta", -"astalk", -"astare", -"astart", -"astasia", -"astatic", -"astay", -"asteam", -"asteep", -"asteer", -"asteism", -"astelic", -"astely", -"aster", -"asteria", -"asterin", -"astern", -"astheny", -"asthma", -"asthore", -"astilbe", -"astint", -"astir", -"astite", -"astomia", -"astony", -"astoop", -"astor", -"astound", -"astrain", -"astral", -"astrand", -"astray", -"astream", -"astrer", -"astrict", -"astride", -"astrier", -"astrild", -"astroid", -"astrut", -"astute", -"astylar", -"asudden", -"asunder", -"aswail", -"aswarm", -"asway", -"asweat", -"aswell", -"aswim", -"aswing", -"aswirl", -"aswoon", -"asyla", -"asylum", -"at", -"atabal", -"atabeg", -"atabek", -"atactic", -"atafter", -"ataman", -"atangle", -"atap", -"ataraxy", -"ataunt", -"atavi", -"atavic", -"atavism", -"atavist", -"atavus", -"ataxia", -"ataxic", -"ataxite", -"ataxy", -"atazir", -"atbash", -"ate", -"atebrin", -"atechny", -"ateeter", -"atef", -"atelets", -"atelier", -"atelo", -"ates", -"ateuchi", -"athanor", -"athar", -"atheism", -"atheist", -"atheize", -"athelia", -"athenee", -"athenor", -"atheous", -"athing", -"athirst", -"athlete", -"athodyd", -"athort", -"athrill", -"athrive", -"athrob", -"athrong", -"athwart", -"athymia", -"athymic", -"athymy", -"athyria", -"athyrid", -"atilt", -"atimon", -"atinga", -"atingle", -"atinkle", -"atip", -"atis", -"atlas", -"atlatl", -"atle", -"atlee", -"atloid", -"atma", -"atman", -"atmid", -"atmo", -"atmos", -"atocha", -"atocia", -"atokal", -"atoke", -"atokous", -"atoll", -"atom", -"atomerg", -"atomic", -"atomics", -"atomism", -"atomist", -"atomity", -"atomize", -"atomy", -"atonal", -"atone", -"atoner", -"atonia", -"atonic", -"atony", -"atop", -"atophan", -"atopic", -"atopite", -"atopy", -"atour", -"atoxic", -"atoxyl", -"atrail", -"atrepsy", -"atresia", -"atresic", -"atresy", -"atretic", -"atria", -"atrial", -"atrip", -"atrium", -"atrocha", -"atropal", -"atrophy", -"atropia", -"atropic", -"atrous", -"atry", -"atta", -"attacco", -"attach", -"attache", -"attack", -"attacus", -"attagen", -"attain", -"attaint", -"attaleh", -"attar", -"attask", -"attempt", -"attend", -"attent", -"atter", -"attern", -"attery", -"attest", -"attic", -"attid", -"attinge", -"attire", -"attired", -"attirer", -"attorn", -"attract", -"attrap", -"attrist", -"attrite", -"attune", -"atule", -"atumble", -"atune", -"atwain", -"atweel", -"atween", -"atwin", -"atwirl", -"atwist", -"atwitch", -"atwixt", -"atwo", -"atypic", -"atypy", -"auantic", -"aube", -"aubrite", -"auburn", -"auca", -"auchlet", -"auction", -"aucuba", -"audible", -"audibly", -"audient", -"audile", -"audio", -"audion", -"audit", -"auditor", -"auge", -"augen", -"augend", -"auger", -"augerer", -"augh", -"aught", -"augite", -"augitic", -"augment", -"augur", -"augural", -"augury", -"august", -"auh", -"auhuhu", -"auk", -"auklet", -"aula", -"aulae", -"auld", -"auletai", -"aulete", -"auletes", -"auletic", -"aulic", -"auloi", -"aulos", -"aulu", -"aum", -"aumaga", -"aumail", -"aumbry", -"aumery", -"aumil", -"aumous", -"aumrie", -"auncel", -"aune", -"aunt", -"auntie", -"auntish", -"auntly", -"aupaka", -"aura", -"aurae", -"aural", -"aurally", -"aurar", -"aurate", -"aurated", -"aureate", -"aureity", -"aurelia", -"aureola", -"aureole", -"aureous", -"auresca", -"aureus", -"auric", -"auricle", -"auride", -"aurific", -"aurify", -"aurigal", -"aurin", -"aurir", -"aurist", -"aurite", -"aurochs", -"auronal", -"aurora", -"aurorae", -"auroral", -"aurore", -"aurous", -"aurum", -"aurure", -"auryl", -"auscult", -"auslaut", -"auspex", -"auspice", -"auspicy", -"austere", -"austral", -"ausu", -"ausubo", -"autarch", -"autarky", -"aute", -"autecy", -"autem", -"author", -"autism", -"autist", -"auto", -"autobus", -"autocab", -"autocar", -"autoecy", -"autoist", -"automa", -"automat", -"autonym", -"autopsy", -"autumn", -"auxesis", -"auxetic", -"auxin", -"auxinic", -"auxotox", -"ava", -"avadana", -"avahi", -"avail", -"aval", -"avalent", -"avania", -"avarice", -"avast", -"avaunt", -"ave", -"avellan", -"aveloz", -"avenage", -"avener", -"avenge", -"avenger", -"avenin", -"avenous", -"avens", -"avenue", -"aver", -"avera", -"average", -"averah", -"averil", -"averin", -"averral", -"averse", -"avert", -"averted", -"averter", -"avian", -"aviary", -"aviate", -"aviatic", -"aviator", -"avichi", -"avicide", -"avick", -"avid", -"avidity", -"avidly", -"avidous", -"avidya", -"avigate", -"avijja", -"avine", -"aviso", -"avital", -"avitic", -"avives", -"avo", -"avocado", -"avocate", -"avocet", -"avodire", -"avoid", -"avoider", -"avolate", -"avouch", -"avow", -"avowal", -"avowant", -"avowed", -"avower", -"avowry", -"avoyer", -"avulse", -"aw", -"awa", -"awabi", -"awaft", -"awag", -"await", -"awaiter", -"awake", -"awaken", -"awald", -"awalim", -"awalt", -"awane", -"awapuhi", -"award", -"awarder", -"aware", -"awash", -"awaste", -"awat", -"awatch", -"awater", -"awave", -"away", -"awber", -"awd", -"awe", -"aweary", -"aweband", -"awee", -"aweek", -"aweel", -"aweigh", -"awesome", -"awest", -"aweto", -"awfu", -"awful", -"awfully", -"awheel", -"awheft", -"awhet", -"awhile", -"awhir", -"awhirl", -"awide", -"awiggle", -"awin", -"awing", -"awink", -"awiwi", -"awkward", -"awl", -"awless", -"awlwort", -"awmous", -"awn", -"awned", -"awner", -"awning", -"awnless", -"awnlike", -"awny", -"awoke", -"awork", -"awreck", -"awrist", -"awrong", -"awry", -"ax", -"axal", -"axe", -"axed", -"axenic", -"axes", -"axfetch", -"axhead", -"axial", -"axially", -"axiate", -"axiform", -"axil", -"axile", -"axilla", -"axillae", -"axillar", -"axine", -"axinite", -"axiom", -"axion", -"axis", -"axised", -"axite", -"axle", -"axled", -"axmaker", -"axman", -"axogamy", -"axoid", -"axolotl", -"axon", -"axonal", -"axonost", -"axseed", -"axstone", -"axtree", -"axunge", -"axweed", -"axwise", -"axwort", -"ay", -"ayah", -"aye", -"ayelp", -"ayin", -"ayless", -"aylet", -"ayllu", -"ayond", -"ayont", -"ayous", -"ayu", -"azafrin", -"azalea", -"azarole", -"azelaic", -"azelate", -"azide", -"azilut", -"azimene", -"azimide", -"azimine", -"azimino", -"azimuth", -"azine", -"aziola", -"azo", -"azoch", -"azofier", -"azofy", -"azoic", -"azole", -"azon", -"azonal", -"azonic", -"azonium", -"azophen", -"azorite", -"azotate", -"azote", -"azoted", -"azoth", -"azotic", -"azotine", -"azotite", -"azotize", -"azotous", -"azox", -"azoxime", -"azoxine", -"azoxy", -"azteca", -"azulene", -"azulite", -"azulmic", -"azumbre", -"azure", -"azurean", -"azured", -"azurine", -"azurite", -"azurous", -"azury", -"azygos", -"azygous", -"azyme", -"azymite", -"azymous", -"b", -"ba", -"baa", -"baal", -"baar", -"baba", -"babai", -"babasco", -"babassu", -"babbitt", -"babble", -"babbler", -"babbly", -"babby", -"babe", -"babelet", -"babery", -"babiche", -"babied", -"babish", -"bablah", -"babloh", -"baboen", -"baboo", -"baboon", -"baboot", -"babroot", -"babu", -"babudom", -"babuina", -"babuism", -"babul", -"baby", -"babydom", -"babyish", -"babyism", -"bac", -"bacaba", -"bacach", -"bacalao", -"bacao", -"bacca", -"baccae", -"baccara", -"baccate", -"bacchar", -"bacchic", -"bacchii", -"bach", -"bache", -"bachel", -"bacilli", -"back", -"backage", -"backcap", -"backed", -"backen", -"backer", -"backet", -"backie", -"backing", -"backjaw", -"backlet", -"backlog", -"backrun", -"backsaw", -"backset", -"backup", -"backway", -"baclin", -"bacon", -"baconer", -"bacony", -"bacula", -"bacule", -"baculi", -"baculum", -"baculus", -"bacury", -"bad", -"badan", -"baddish", -"baddock", -"bade", -"badge", -"badger", -"badiaga", -"badian", -"badious", -"badland", -"badly", -"badness", -"bae", -"baetuli", -"baetyl", -"bafaro", -"baff", -"baffeta", -"baffle", -"baffler", -"baffy", -"baft", -"bafta", -"bag", -"baga", -"bagani", -"bagasse", -"bagel", -"bagful", -"baggage", -"baggala", -"bagged", -"bagger", -"baggie", -"baggily", -"bagging", -"baggit", -"baggy", -"baglike", -"bagman", -"bagnio", -"bagnut", -"bago", -"bagonet", -"bagpipe", -"bagre", -"bagreef", -"bagroom", -"bagwig", -"bagworm", -"bagwyn", -"bah", -"bahan", -"bahar", -"bahay", -"bahera", -"bahisti", -"bahnung", -"baho", -"bahoe", -"bahoo", -"baht", -"bahur", -"bahut", -"baignet", -"baikie", -"bail", -"bailage", -"bailee", -"bailer", -"bailey", -"bailie", -"bailiff", -"bailor", -"bain", -"bainie", -"baioc", -"baiocco", -"bairagi", -"bairn", -"bairnie", -"bairnly", -"baister", -"bait", -"baiter", -"baith", -"baittle", -"baize", -"bajada", -"bajan", -"bajra", -"bajree", -"bajri", -"bajury", -"baka", -"bakal", -"bake", -"baked", -"baken", -"bakepan", -"baker", -"bakerly", -"bakery", -"bakie", -"baking", -"bakli", -"baktun", -"baku", -"bakula", -"bal", -"balafo", -"balagan", -"balai", -"balance", -"balanic", -"balanid", -"balao", -"balas", -"balata", -"balboa", -"balcony", -"bald", -"balden", -"balder", -"baldish", -"baldly", -"baldrib", -"baldric", -"baldy", -"bale", -"baleen", -"baleful", -"balei", -"baleise", -"baler", -"balete", -"bali", -"baline", -"balita", -"balk", -"balker", -"balky", -"ball", -"ballad", -"ballade", -"ballam", -"ballan", -"ballant", -"ballast", -"ballata", -"ballate", -"balldom", -"balled", -"baller", -"ballet", -"balli", -"ballist", -"ballium", -"balloon", -"ballot", -"ballow", -"ballup", -"bally", -"balm", -"balmily", -"balmony", -"balmy", -"balneal", -"balonea", -"baloney", -"baloo", -"balow", -"balsa", -"balsam", -"balsamo", -"balsamy", -"baltei", -"balter", -"balteus", -"balu", -"balut", -"balza", -"bam", -"bamban", -"bambini", -"bambino", -"bamboo", -"bamoth", -"ban", -"banaba", -"banago", -"banak", -"banal", -"banally", -"banana", -"banat", -"banc", -"banca", -"bancal", -"banchi", -"banco", -"bancus", -"band", -"banda", -"bandage", -"bandaka", -"bandala", -"bandar", -"bandbox", -"bande", -"bandeau", -"banded", -"bander", -"bandhu", -"bandi", -"bandie", -"banding", -"bandit", -"bandle", -"bandlet", -"bandman", -"bando", -"bandog", -"bandore", -"bandrol", -"bandy", -"bane", -"baneful", -"bang", -"banga", -"bange", -"banger", -"banghy", -"banging", -"bangkok", -"bangle", -"bangled", -"bani", -"banian", -"banig", -"banilad", -"banish", -"baniwa", -"baniya", -"banjo", -"banjore", -"banjuke", -"bank", -"banked", -"banker", -"bankera", -"banket", -"banking", -"bankman", -"banky", -"banner", -"bannet", -"banning", -"bannock", -"banns", -"bannut", -"banquet", -"banshee", -"bant", -"bantam", -"bantay", -"banteng", -"banter", -"bantery", -"banty", -"banuyo", -"banya", -"banyan", -"banzai", -"baobab", -"bap", -"baptism", -"baptize", -"bar", -"bara", -"barad", -"barauna", -"barb", -"barbal", -"barbary", -"barbas", -"barbate", -"barbe", -"barbed", -"barbel", -"barber", -"barbet", -"barbion", -"barblet", -"barbone", -"barbudo", -"barbule", -"bard", -"bardane", -"bardash", -"bardel", -"bardess", -"bardic", -"bardie", -"bardily", -"barding", -"bardish", -"bardism", -"bardlet", -"bardo", -"bardy", -"bare", -"bareca", -"barefit", -"barely", -"barer", -"baresma", -"baretta", -"barff", -"barfish", -"barfly", -"barful", -"bargain", -"barge", -"bargee", -"bargeer", -"barger", -"bargh", -"bargham", -"bari", -"baria", -"baric", -"barid", -"barie", -"barile", -"barilla", -"baring", -"baris", -"barish", -"barit", -"barite", -"barium", -"bark", -"barken", -"barker", -"barkery", -"barkey", -"barkhan", -"barking", -"barkle", -"barky", -"barless", -"barley", -"barling", -"barlock", -"barlow", -"barm", -"barmaid", -"barman", -"barmkin", -"barmote", -"barmy", -"barn", -"barnard", -"barney", -"barnful", -"barnman", -"barny", -"baroi", -"barolo", -"baron", -"baronet", -"barong", -"baronry", -"barony", -"baroque", -"baroto", -"barpost", -"barra", -"barrack", -"barrad", -"barrage", -"barras", -"barred", -"barrel", -"barren", -"barrer", -"barret", -"barrico", -"barrier", -"barring", -"barrio", -"barroom", -"barrow", -"barruly", -"barry", -"barse", -"barsom", -"barter", -"barth", -"barton", -"baru", -"baruria", -"barvel", -"barwal", -"barway", -"barways", -"barwise", -"barwood", -"barye", -"baryta", -"barytes", -"barytic", -"baryton", -"bas", -"basal", -"basale", -"basalia", -"basally", -"basalt", -"basaree", -"bascule", -"base", -"based", -"basely", -"baseman", -"basenji", -"bases", -"bash", -"bashaw", -"bashful", -"bashlyk", -"basial", -"basiate", -"basic", -"basidia", -"basify", -"basil", -"basilar", -"basilic", -"basin", -"basined", -"basinet", -"basion", -"basis", -"bask", -"basker", -"basket", -"basoid", -"bason", -"basos", -"basote", -"basque", -"basqued", -"bass", -"bassan", -"bassara", -"basset", -"bassie", -"bassine", -"bassist", -"basso", -"bassoon", -"bassus", -"bast", -"basta", -"bastard", -"baste", -"basten", -"baster", -"bastide", -"basting", -"bastion", -"bastite", -"basto", -"baston", -"bat", -"bataan", -"batad", -"batakan", -"batara", -"batata", -"batch", -"batcher", -"bate", -"batea", -"bateau", -"bateaux", -"bated", -"batel", -"bateman", -"bater", -"batfish", -"batfowl", -"bath", -"bathe", -"bather", -"bathic", -"bathing", -"bathman", -"bathmic", -"bathos", -"bathtub", -"bathyal", -"batik", -"batiker", -"bating", -"batino", -"batiste", -"batlan", -"batlike", -"batling", -"batlon", -"batman", -"batoid", -"baton", -"batonne", -"bats", -"batsman", -"batster", -"batt", -"batta", -"battel", -"batten", -"batter", -"battery", -"battik", -"batting", -"battish", -"battle", -"battled", -"battler", -"battue", -"batty", -"batule", -"batwing", -"batz", -"batzen", -"bauble", -"bauch", -"bauchle", -"bauckie", -"baud", -"baul", -"bauleah", -"baun", -"bauno", -"bauson", -"bausond", -"bauta", -"bauxite", -"bavaroy", -"bavary", -"bavian", -"baviere", -"bavin", -"bavoso", -"baw", -"bawbee", -"bawcock", -"bawd", -"bawdily", -"bawdry", -"bawl", -"bawler", -"bawley", -"bawn", -"bawtie", -"baxter", -"baxtone", -"bay", -"baya", -"bayal", -"bayamo", -"bayard", -"baybolt", -"baybush", -"baycuru", -"bayed", -"bayeta", -"baygall", -"bayhead", -"bayish", -"baylet", -"baylike", -"bayman", -"bayness", -"bayok", -"bayonet", -"bayou", -"baywood", -"bazaar", -"baze", -"bazoo", -"bazooka", -"bazzite", -"bdellid", -"be", -"beach", -"beached", -"beachy", -"beacon", -"bead", -"beaded", -"beader", -"beadily", -"beading", -"beadle", -"beadlet", -"beadman", -"beadrow", -"beady", -"beagle", -"beak", -"beaked", -"beaker", -"beakful", -"beaky", -"beal", -"beala", -"bealing", -"beam", -"beamage", -"beamed", -"beamer", -"beamful", -"beamily", -"beaming", -"beamish", -"beamlet", -"beamman", -"beamy", -"bean", -"beanbag", -"beancod", -"beanery", -"beanie", -"beano", -"beant", -"beany", -"bear", -"beard", -"bearded", -"bearder", -"beardie", -"beardom", -"beardy", -"bearer", -"bearess", -"bearing", -"bearish", -"bearlet", -"bearm", -"beast", -"beastie", -"beastly", -"beat", -"beata", -"beatae", -"beatee", -"beaten", -"beater", -"beath", -"beatify", -"beating", -"beatus", -"beau", -"beaufin", -"beauish", -"beauism", -"beauti", -"beauty", -"beaux", -"beaver", -"beavery", -"beback", -"bebait", -"bebang", -"bebar", -"bebaron", -"bebaste", -"bebat", -"bebathe", -"bebay", -"bebeast", -"bebed", -"bebeeru", -"bebilya", -"bebite", -"beblain", -"beblear", -"bebled", -"bebless", -"beblood", -"bebloom", -"bebog", -"bebop", -"beboss", -"bebotch", -"bebrave", -"bebrine", -"bebrush", -"bebump", -"bebusy", -"becall", -"becalm", -"becap", -"becard", -"becarve", -"becater", -"because", -"becense", -"bechalk", -"becharm", -"bechase", -"becheck", -"becher", -"bechern", -"bechirp", -"becivet", -"beck", -"becker", -"becket", -"beckon", -"beclad", -"beclang", -"beclart", -"beclasp", -"beclaw", -"becloak", -"beclog", -"becloud", -"beclout", -"beclown", -"becolme", -"becolor", -"become", -"becomes", -"becomma", -"becoom", -"becost", -"becovet", -"becram", -"becramp", -"becrawl", -"becreep", -"becrime", -"becroak", -"becross", -"becrowd", -"becrown", -"becrush", -"becrust", -"becry", -"becuiba", -"becuna", -"becurl", -"becurry", -"becurse", -"becut", -"bed", -"bedad", -"bedamn", -"bedamp", -"bedare", -"bedark", -"bedash", -"bedaub", -"bedawn", -"beday", -"bedaze", -"bedbug", -"bedcap", -"bedcase", -"bedcord", -"bedded", -"bedder", -"bedding", -"bedead", -"bedeaf", -"bedebt", -"bedeck", -"bedel", -"beden", -"bedene", -"bedevil", -"bedew", -"bedewer", -"bedfast", -"bedfoot", -"bedgery", -"bedgoer", -"bedgown", -"bedight", -"bedikah", -"bedim", -"bedin", -"bedip", -"bedirt", -"bedirty", -"bedizen", -"bedkey", -"bedlam", -"bedlar", -"bedless", -"bedlids", -"bedman", -"bedmate", -"bedog", -"bedolt", -"bedot", -"bedote", -"bedouse", -"bedown", -"bedoyo", -"bedpan", -"bedpost", -"bedrail", -"bedral", -"bedrape", -"bedress", -"bedrid", -"bedrift", -"bedrip", -"bedrock", -"bedroll", -"bedroom", -"bedrop", -"bedrown", -"bedrug", -"bedsick", -"bedside", -"bedsite", -"bedsock", -"bedsore", -"bedtick", -"bedtime", -"bedub", -"beduck", -"beduke", -"bedull", -"bedumb", -"bedunce", -"bedunch", -"bedung", -"bedur", -"bedusk", -"bedust", -"bedwarf", -"bedway", -"bedways", -"bedwell", -"bedye", -"bee", -"beearn", -"beech", -"beechen", -"beechy", -"beedged", -"beedom", -"beef", -"beefer", -"beefily", -"beefin", -"beefish", -"beefy", -"beehead", -"beeherd", -"beehive", -"beeish", -"beek", -"beekite", -"beelbow", -"beelike", -"beeline", -"beelol", -"beeman", -"been", -"beennut", -"beer", -"beerage", -"beerily", -"beerish", -"beery", -"bees", -"beest", -"beeswax", -"beet", -"beeth", -"beetle", -"beetled", -"beetler", -"beety", -"beeve", -"beevish", -"beeware", -"beeway", -"beeweed", -"beewise", -"beewort", -"befall", -"befame", -"befan", -"befancy", -"befavor", -"befilch", -"befile", -"befilth", -"befire", -"befist", -"befit", -"beflag", -"beflap", -"beflea", -"befleck", -"beflour", -"beflout", -"beflum", -"befoam", -"befog", -"befool", -"befop", -"before", -"befoul", -"befret", -"befrill", -"befriz", -"befume", -"beg", -"begad", -"begall", -"begani", -"begar", -"begari", -"begash", -"begat", -"begaud", -"begaudy", -"begay", -"begaze", -"begeck", -"begem", -"beget", -"beggar", -"beggary", -"begging", -"begift", -"begild", -"begin", -"begird", -"beglad", -"beglare", -"beglic", -"beglide", -"begloom", -"begloze", -"begluc", -"beglue", -"begnaw", -"bego", -"begob", -"begobs", -"begohm", -"begone", -"begonia", -"begorra", -"begorry", -"begoud", -"begowk", -"begrace", -"begrain", -"begrave", -"begray", -"begreen", -"begrett", -"begrim", -"begrime", -"begroan", -"begrown", -"beguard", -"beguess", -"beguile", -"beguine", -"begulf", -"begum", -"begun", -"begunk", -"begut", -"behale", -"behalf", -"behap", -"behave", -"behead", -"behear", -"behears", -"behedge", -"beheld", -"behelp", -"behen", -"behenic", -"behest", -"behind", -"behint", -"behn", -"behold", -"behoney", -"behoof", -"behoot", -"behoove", -"behorn", -"behowl", -"behung", -"behymn", -"beice", -"beige", -"being", -"beinked", -"beira", -"beisa", -"bejade", -"bejan", -"bejant", -"bejazz", -"bejel", -"bejewel", -"bejig", -"bekah", -"bekick", -"beking", -"bekiss", -"bekko", -"beknave", -"beknit", -"beknow", -"beknown", -"bel", -"bela", -"belabor", -"belaced", -"beladle", -"belady", -"belage", -"belah", -"belam", -"belanda", -"belar", -"belard", -"belash", -"belate", -"belated", -"belaud", -"belay", -"belayer", -"belch", -"belcher", -"beld", -"beldam", -"beleaf", -"beleap", -"beleave", -"belee", -"belfry", -"belga", -"belibel", -"belick", -"belie", -"belief", -"belier", -"believe", -"belight", -"beliked", -"belion", -"belite", -"belive", -"bell", -"bellboy", -"belle", -"belled", -"bellhop", -"bellied", -"belling", -"bellite", -"bellman", -"bellote", -"bellow", -"bellows", -"belly", -"bellyer", -"beloam", -"beloid", -"belong", -"belonid", -"belord", -"belout", -"belove", -"beloved", -"below", -"belsire", -"belt", -"belted", -"belter", -"beltie", -"beltine", -"belting", -"beltman", -"belton", -"beluga", -"belute", -"belve", -"bely", -"belying", -"bema", -"bemad", -"bemadam", -"bemail", -"bemaim", -"beman", -"bemar", -"bemask", -"bemat", -"bemata", -"bemaul", -"bemazed", -"bemeal", -"bemean", -"bemercy", -"bemire", -"bemist", -"bemix", -"bemoan", -"bemoat", -"bemock", -"bemoil", -"bemole", -"bemolt", -"bemoon", -"bemotto", -"bemoult", -"bemouth", -"bemuck", -"bemud", -"bemuddy", -"bemuse", -"bemused", -"bemusk", -"ben", -"bena", -"benab", -"bename", -"benami", -"benasty", -"benben", -"bench", -"bencher", -"benchy", -"bencite", -"bend", -"benda", -"bended", -"bender", -"bending", -"bendlet", -"bendy", -"bene", -"beneath", -"benefic", -"benefit", -"benempt", -"benet", -"beng", -"beni", -"benight", -"benign", -"benison", -"benj", -"benjy", -"benmost", -"benn", -"benne", -"bennel", -"bennet", -"benny", -"beno", -"benorth", -"benote", -"bensel", -"bensh", -"benshea", -"benshee", -"benshi", -"bent", -"bentang", -"benthal", -"benthic", -"benthon", -"benthos", -"benting", -"benty", -"benumb", -"benward", -"benweed", -"benzal", -"benzein", -"benzene", -"benzil", -"benzine", -"benzo", -"benzoic", -"benzoid", -"benzoin", -"benzol", -"benzole", -"benzoxy", -"benzoyl", -"benzyl", -"beode", -"bepaid", -"bepale", -"bepaper", -"beparch", -"beparse", -"bepart", -"bepaste", -"bepat", -"bepaw", -"bepearl", -"bepelt", -"bepen", -"bepewed", -"bepiece", -"bepile", -"bepill", -"bepinch", -"bepity", -"beprank", -"bepray", -"bepress", -"bepride", -"beprose", -"bepuff", -"bepun", -"bequalm", -"bequest", -"bequote", -"ber", -"berain", -"berakah", -"berake", -"berapt", -"berat", -"berate", -"beray", -"bere", -"bereave", -"bereft", -"berend", -"beret", -"berg", -"berger", -"berglet", -"bergut", -"bergy", -"bergylt", -"berhyme", -"beride", -"berinse", -"berith", -"berley", -"berlin", -"berline", -"berm", -"berne", -"berobed", -"beroll", -"beround", -"berret", -"berri", -"berried", -"berrier", -"berry", -"berseem", -"berserk", -"berth", -"berthed", -"berther", -"bertram", -"bertrum", -"berust", -"bervie", -"berycid", -"beryl", -"bes", -"besa", -"besagne", -"besaiel", -"besaint", -"besan", -"besauce", -"bescab", -"bescarf", -"bescent", -"bescorn", -"bescour", -"bescurf", -"beseam", -"besee", -"beseech", -"beseem", -"beseen", -"beset", -"beshade", -"beshag", -"beshake", -"beshame", -"beshear", -"beshell", -"beshine", -"beshlik", -"beshod", -"beshout", -"beshow", -"beshrew", -"beside", -"besides", -"besiege", -"besigh", -"besin", -"besing", -"besiren", -"besit", -"beslab", -"beslap", -"beslash", -"beslave", -"beslime", -"beslow", -"beslur", -"besmear", -"besmell", -"besmile", -"besmoke", -"besmut", -"besnare", -"besneer", -"besnow", -"besnuff", -"besogne", -"besoil", -"besom", -"besomer", -"besoot", -"besot", -"besoul", -"besour", -"bespate", -"bespawl", -"bespeak", -"besped", -"bespeed", -"bespell", -"bespend", -"bespete", -"bespew", -"bespice", -"bespill", -"bespin", -"bespit", -"besplit", -"bespoke", -"bespot", -"bespout", -"bespray", -"bespy", -"besquib", -"besra", -"best", -"bestab", -"bestain", -"bestamp", -"bestar", -"bestare", -"bestay", -"bestead", -"besteer", -"bester", -"bestial", -"bestick", -"bestill", -"bestink", -"bestir", -"bestock", -"bestore", -"bestorm", -"bestove", -"bestow", -"bestraw", -"bestrew", -"bestuck", -"bestud", -"besugar", -"besuit", -"besully", -"beswarm", -"beswim", -"bet", -"beta", -"betag", -"betail", -"betaine", -"betalk", -"betask", -"betaxed", -"betear", -"beteela", -"beteem", -"betel", -"beth", -"bethel", -"bethink", -"bethumb", -"bethump", -"betide", -"betimes", -"betinge", -"betire", -"betis", -"betitle", -"betoil", -"betoken", -"betone", -"betony", -"betoss", -"betowel", -"betrace", -"betrail", -"betrap", -"betray", -"betread", -"betrend", -"betrim", -"betroth", -"betrunk", -"betso", -"betted", -"better", -"betters", -"betting", -"bettong", -"bettor", -"betty", -"betulin", -"betutor", -"between", -"betwine", -"betwit", -"betwixt", -"beveil", -"bevel", -"beveled", -"beveler", -"bevenom", -"bever", -"beverse", -"beveto", -"bevined", -"bevomit", -"bevue", -"bevy", -"bewail", -"bewall", -"beware", -"bewash", -"bewaste", -"bewater", -"beweary", -"beweep", -"bewept", -"bewest", -"bewet", -"bewhig", -"bewhite", -"bewidow", -"bewig", -"bewired", -"bewitch", -"bewith", -"bework", -"beworm", -"beworn", -"beworry", -"bewrap", -"bewray", -"bewreck", -"bewrite", -"bey", -"beydom", -"beylic", -"beyond", -"beyship", -"bezant", -"bezanty", -"bezel", -"bezetta", -"bezique", -"bezoar", -"bezzi", -"bezzle", -"bezzo", -"bhabar", -"bhakta", -"bhakti", -"bhalu", -"bhandar", -"bhang", -"bhangi", -"bhara", -"bharal", -"bhat", -"bhava", -"bheesty", -"bhikku", -"bhikshu", -"bhoosa", -"bhoy", -"bhungi", -"bhut", -"biabo", -"biacid", -"biacuru", -"bialate", -"biallyl", -"bianco", -"biarchy", -"bias", -"biaxal", -"biaxial", -"bib", -"bibasic", -"bibb", -"bibber", -"bibble", -"bibbler", -"bibbons", -"bibcock", -"bibi", -"bibiri", -"bibless", -"biblus", -"bice", -"biceps", -"bicetyl", -"bichir", -"bichord", -"bichy", -"bick", -"bicker", -"bickern", -"bicolor", -"bicone", -"biconic", -"bicorn", -"bicorne", -"bicron", -"bicycle", -"bicyclo", -"bid", -"bidar", -"bidarka", -"bidcock", -"bidder", -"bidding", -"biddy", -"bide", -"bident", -"bider", -"bidet", -"biding", -"bidri", -"biduous", -"bield", -"bieldy", -"bien", -"bienly", -"biennia", -"bier", -"bietle", -"bifara", -"bifer", -"biff", -"biffin", -"bifid", -"bifidly", -"bifilar", -"biflex", -"bifocal", -"bifoil", -"bifold", -"bifolia", -"biform", -"bifront", -"big", -"biga", -"bigamic", -"bigamy", -"bigener", -"bigeye", -"bigg", -"biggah", -"biggen", -"bigger", -"biggest", -"biggin", -"biggish", -"bigha", -"bighead", -"bighorn", -"bight", -"biglot", -"bigness", -"bignou", -"bigot", -"bigoted", -"bigotry", -"bigotty", -"bigroot", -"bigwig", -"bija", -"bijasal", -"bijou", -"bijoux", -"bike", -"bikh", -"bikini", -"bilabe", -"bilalo", -"bilbie", -"bilbo", -"bilby", -"bilch", -"bilcock", -"bildar", -"bilders", -"bile", -"bilge", -"bilgy", -"biliary", -"biliate", -"bilic", -"bilify", -"bilimbi", -"bilio", -"bilious", -"bilith", -"bilk", -"bilker", -"bill", -"billa", -"billbug", -"billed", -"biller", -"billet", -"billety", -"billian", -"billing", -"billion", -"billman", -"billon", -"billot", -"billow", -"billowy", -"billy", -"billyer", -"bilo", -"bilobe", -"bilobed", -"bilsh", -"bilsted", -"biltong", -"bimalar", -"bimanal", -"bimane", -"bimasty", -"bimbil", -"bimeby", -"bimodal", -"bin", -"binal", -"binary", -"binate", -"bind", -"binder", -"bindery", -"binding", -"bindle", -"bindlet", -"bindweb", -"bine", -"bing", -"binge", -"bingey", -"binghi", -"bingle", -"bingo", -"bingy", -"binh", -"bink", -"binman", -"binna", -"binning", -"binnite", -"bino", -"binocle", -"binodal", -"binode", -"binotic", -"binous", -"bint", -"binukau", -"biod", -"biodyne", -"biogen", -"biogeny", -"bioherm", -"biolith", -"biology", -"biome", -"bion", -"bionomy", -"biopsic", -"biopsy", -"bioral", -"biorgan", -"bios", -"biose", -"biosis", -"biota", -"biotaxy", -"biotic", -"biotics", -"biotin", -"biotite", -"biotome", -"biotomy", -"biotope", -"biotype", -"bioxide", -"bipack", -"biparty", -"biped", -"bipedal", -"biphase", -"biplane", -"bipod", -"bipolar", -"biprism", -"biprong", -"birch", -"birchen", -"bird", -"birddom", -"birdeen", -"birder", -"birdie", -"birding", -"birdlet", -"birdman", -"birdy", -"bireme", -"biretta", -"biri", -"biriba", -"birk", -"birken", -"birkie", -"birl", -"birle", -"birler", -"birlie", -"birlinn", -"birma", -"birn", -"birny", -"birr", -"birse", -"birsle", -"birsy", -"birth", -"birthy", -"bis", -"bisabol", -"bisalt", -"biscuit", -"bisect", -"bisexed", -"bisext", -"bishop", -"bismar", -"bismite", -"bismuth", -"bisnaga", -"bison", -"bispore", -"bisque", -"bissext", -"bisson", -"bistate", -"bister", -"bisti", -"bistort", -"bistro", -"bit", -"bitable", -"bitch", -"bite", -"biter", -"biti", -"biting", -"bitless", -"bito", -"bitolyl", -"bitt", -"bitted", -"bitten", -"bitter", -"bittern", -"bitters", -"bittie", -"bittock", -"bitty", -"bitume", -"bitumed", -"bitumen", -"bitwise", -"bityite", -"bitypic", -"biune", -"biunial", -"biunity", -"biurate", -"biurea", -"biuret", -"bivalve", -"bivinyl", -"bivious", -"bivocal", -"bivouac", -"biwa", -"bixin", -"biz", -"bizarre", -"bizet", -"bizonal", -"bizone", -"bizz", -"blab", -"blabber", -"black", -"blacken", -"blacker", -"blackey", -"blackie", -"blackit", -"blackly", -"blacky", -"blad", -"bladder", -"blade", -"bladed", -"blader", -"blading", -"bladish", -"blady", -"blae", -"blaff", -"blaflum", -"blah", -"blain", -"blair", -"blake", -"blame", -"blamed", -"blamer", -"blaming", -"blan", -"blanc", -"blanca", -"blanch", -"blanco", -"bland", -"blanda", -"blandly", -"blank", -"blanked", -"blanket", -"blankly", -"blanky", -"blanque", -"blare", -"blarney", -"blarnid", -"blarny", -"blart", -"blas", -"blase", -"blash", -"blashy", -"blast", -"blasted", -"blaster", -"blastid", -"blastie", -"blasty", -"blat", -"blatant", -"blate", -"blately", -"blather", -"blatta", -"blatter", -"blatti", -"blattid", -"blaubok", -"blaver", -"blaw", -"blawort", -"blay", -"blaze", -"blazer", -"blazing", -"blazon", -"blazy", -"bleach", -"bleak", -"bleakly", -"bleaky", -"blear", -"bleared", -"bleary", -"bleat", -"bleater", -"bleaty", -"bleb", -"blebby", -"bleck", -"blee", -"bleed", -"bleeder", -"bleery", -"bleeze", -"bleezy", -"blellum", -"blemish", -"blench", -"blend", -"blende", -"blended", -"blender", -"blendor", -"blenny", -"blent", -"bleo", -"blesbok", -"bless", -"blessed", -"blesser", -"blest", -"blet", -"blewits", -"blibe", -"blick", -"blickey", -"blight", -"blighty", -"blimp", -"blimy", -"blind", -"blinded", -"blinder", -"blindly", -"blink", -"blinked", -"blinker", -"blinks", -"blinky", -"blinter", -"blintze", -"blip", -"bliss", -"blissom", -"blister", -"blite", -"blithe", -"blithen", -"blither", -"blitter", -"blitz", -"blizz", -"blo", -"bloat", -"bloated", -"bloater", -"blob", -"blobbed", -"blobber", -"blobby", -"bloc", -"block", -"blocked", -"blocker", -"blocky", -"blodite", -"bloke", -"blolly", -"blonde", -"blood", -"blooded", -"bloody", -"blooey", -"bloom", -"bloomer", -"bloomy", -"bloop", -"blooper", -"blore", -"blosmy", -"blossom", -"blot", -"blotch", -"blotchy", -"blotter", -"blotto", -"blotty", -"blouse", -"bloused", -"blout", -"blow", -"blowen", -"blower", -"blowfly", -"blowgun", -"blowing", -"blown", -"blowoff", -"blowout", -"blowth", -"blowup", -"blowy", -"blowze", -"blowzed", -"blowzy", -"blub", -"blubber", -"blucher", -"blue", -"bluecap", -"bluecup", -"blueing", -"blueleg", -"bluely", -"bluer", -"blues", -"bluet", -"bluetop", -"bluey", -"bluff", -"bluffer", -"bluffly", -"bluffy", -"bluggy", -"bluing", -"bluish", -"bluism", -"blunder", -"blunge", -"blunger", -"blunk", -"blunker", -"blunks", -"blunnen", -"blunt", -"blunter", -"bluntie", -"bluntly", -"blup", -"blur", -"blurb", -"blurred", -"blurrer", -"blurry", -"blurt", -"blush", -"blusher", -"blushy", -"bluster", -"blype", -"bo", -"boa", -"boagane", -"boar", -"board", -"boarder", -"boardly", -"boardy", -"boarish", -"boast", -"boaster", -"boat", -"boatage", -"boater", -"boatful", -"boatie", -"boating", -"boatlip", -"boatly", -"boatman", -"bob", -"boba", -"bobac", -"bobbed", -"bobber", -"bobbery", -"bobbin", -"bobbing", -"bobbish", -"bobble", -"bobby", -"bobcat", -"bobcoat", -"bobeche", -"bobfly", -"bobo", -"bobotie", -"bobsled", -"bobstay", -"bobtail", -"bobwood", -"bocal", -"bocardo", -"bocca", -"boccale", -"boccaro", -"bocce", -"boce", -"bocher", -"bock", -"bocking", -"bocoy", -"bod", -"bodach", -"bode", -"bodeful", -"bodega", -"boden", -"boder", -"bodge", -"bodger", -"bodgery", -"bodhi", -"bodice", -"bodiced", -"bodied", -"bodier", -"bodikin", -"bodily", -"boding", -"bodkin", -"bodle", -"bodock", -"body", -"bog", -"boga", -"bogan", -"bogard", -"bogart", -"bogey", -"boggart", -"boggin", -"boggish", -"boggle", -"boggler", -"boggy", -"boghole", -"bogie", -"bogier", -"bogland", -"bogle", -"boglet", -"bogman", -"bogmire", -"bogo", -"bogong", -"bogtrot", -"bogue", -"bogum", -"bogus", -"bogway", -"bogwood", -"bogwort", -"bogy", -"bogydom", -"bogyism", -"bohawn", -"bohea", -"boho", -"bohor", -"bohunk", -"boid", -"boil", -"boiled", -"boiler", -"boilery", -"boiling", -"boily", -"boist", -"bojite", -"bojo", -"bokadam", -"bokard", -"bokark", -"boke", -"bokom", -"bola", -"bolar", -"bold", -"bolden", -"boldine", -"boldly", -"boldo", -"bole", -"boled", -"boleite", -"bolero", -"bolete", -"bolide", -"bolimba", -"bolis", -"bolivar", -"bolivia", -"bolk", -"boll", -"bollard", -"bolled", -"boller", -"bolling", -"bollock", -"bolly", -"bolo", -"boloman", -"boloney", -"bolson", -"bolster", -"bolt", -"boltage", -"boltant", -"boltel", -"bolter", -"bolti", -"bolting", -"bolus", -"bom", -"boma", -"bomb", -"bombard", -"bombast", -"bombed", -"bomber", -"bombo", -"bombola", -"bombous", -"bon", -"bonaci", -"bonagh", -"bonaght", -"bonair", -"bonally", -"bonang", -"bonanza", -"bonasus", -"bonbon", -"bonce", -"bond", -"bondage", -"bondar", -"bonded", -"bonder", -"bonding", -"bondman", -"bonduc", -"bone", -"boned", -"bonedog", -"bonelet", -"boner", -"boneset", -"bonfire", -"bong", -"bongo", -"boniata", -"bonify", -"bonito", -"bonk", -"bonnaz", -"bonnet", -"bonnily", -"bonny", -"bonsai", -"bonus", -"bonxie", -"bony", -"bonze", -"bonzer", -"bonzery", -"bonzian", -"boo", -"boob", -"boobery", -"boobily", -"boobook", -"booby", -"bood", -"boodie", -"boodle", -"boodler", -"boody", -"boof", -"booger", -"boohoo", -"boojum", -"book", -"bookdom", -"booked", -"booker", -"bookery", -"bookful", -"bookie", -"booking", -"bookish", -"bookism", -"booklet", -"bookman", -"booky", -"bool", -"booly", -"boolya", -"boom", -"boomage", -"boomah", -"boomdas", -"boomer", -"booming", -"boomlet", -"boomy", -"boon", -"boonk", -"boopis", -"boor", -"boorish", -"boort", -"boose", -"boost", -"booster", -"boosy", -"boot", -"bootboy", -"booted", -"bootee", -"booter", -"bootery", -"bootful", -"booth", -"boother", -"bootied", -"booting", -"bootleg", -"boots", -"booty", -"booze", -"boozed", -"boozer", -"boozily", -"boozy", -"bop", -"bopeep", -"boppist", -"bopyrid", -"bor", -"bora", -"borable", -"boracic", -"borage", -"borak", -"boral", -"borasca", -"borate", -"borax", -"bord", -"bordage", -"bordar", -"bordel", -"border", -"bordure", -"bore", -"boread", -"boreal", -"borean", -"boredom", -"boree", -"boreen", -"boregat", -"boreism", -"borele", -"borer", -"borg", -"borgh", -"borh", -"boric", -"boride", -"borine", -"boring", -"borish", -"borism", -"bority", -"borize", -"borlase", -"born", -"borne", -"borneol", -"borning", -"bornite", -"bornyl", -"boro", -"boron", -"boronic", -"borough", -"borrel", -"borrow", -"borsch", -"borscht", -"borsht", -"bort", -"bortsch", -"borty", -"bortz", -"borwort", -"boryl", -"borzoi", -"boscage", -"bosch", -"bose", -"boser", -"bosh", -"bosher", -"bosk", -"bosker", -"bosket", -"bosky", -"bosn", -"bosom", -"bosomed", -"bosomer", -"bosomy", -"boss", -"bossage", -"bossdom", -"bossed", -"bosser", -"bosset", -"bossing", -"bossism", -"bosslet", -"bossy", -"boston", -"bostryx", -"bosun", -"bot", -"bota", -"botanic", -"botany", -"botargo", -"botch", -"botched", -"botcher", -"botchka", -"botchy", -"bote", -"botella", -"boterol", -"botfly", -"both", -"bother", -"bothros", -"bothway", -"bothy", -"botonee", -"botong", -"bott", -"bottine", -"bottle", -"bottled", -"bottler", -"bottom", -"botulin", -"bouchal", -"bouche", -"boucher", -"boud", -"boudoir", -"bougar", -"bouge", -"bouget", -"bough", -"boughed", -"bought", -"boughy", -"bougie", -"bouk", -"boukit", -"boulder", -"boule", -"boultel", -"boulter", -"boun", -"bounce", -"bouncer", -"bound", -"bounded", -"bounden", -"bounder", -"boundly", -"bounty", -"bouquet", -"bourbon", -"bourd", -"bourder", -"bourdon", -"bourg", -"bourn", -"bourock", -"bourse", -"bouse", -"bouser", -"bousy", -"bout", -"boutade", -"bouto", -"bouw", -"bovate", -"bovid", -"bovine", -"bovoid", -"bow", -"bowable", -"bowback", -"bowbent", -"bowboy", -"bowed", -"bowel", -"boweled", -"bowels", -"bower", -"bowery", -"bowet", -"bowfin", -"bowhead", -"bowie", -"bowing", -"bowk", -"bowkail", -"bowker", -"bowknot", -"bowl", -"bowla", -"bowleg", -"bowler", -"bowless", -"bowlful", -"bowlike", -"bowline", -"bowling", -"bowls", -"bowly", -"bowman", -"bowpin", -"bowshot", -"bowwood", -"bowwort", -"bowwow", -"bowyer", -"boxbush", -"boxcar", -"boxen", -"boxer", -"boxfish", -"boxful", -"boxhaul", -"boxhead", -"boxing", -"boxlike", -"boxman", -"boxty", -"boxwood", -"boxwork", -"boxy", -"boy", -"boyang", -"boyar", -"boyard", -"boycott", -"boydom", -"boyer", -"boyhood", -"boyish", -"boyism", -"boyla", -"boylike", -"boyship", -"boza", -"bozal", -"bozo", -"bozze", -"bra", -"brab", -"brabant", -"brabble", -"braca", -"braccia", -"braccio", -"brace", -"braced", -"bracer", -"bracero", -"braces", -"brach", -"brachet", -"bracing", -"brack", -"bracken", -"bracker", -"bracket", -"bracky", -"bract", -"bractea", -"bracted", -"brad", -"bradawl", -"bradsot", -"brae", -"braeman", -"brag", -"braggat", -"bragger", -"bragget", -"bragite", -"braid", -"braided", -"braider", -"brail", -"brain", -"brainer", -"brainge", -"brains", -"brainy", -"braird", -"brairo", -"braise", -"brake", -"braker", -"brakie", -"braky", -"bramble", -"brambly", -"bran", -"branch", -"branchi", -"branchy", -"brand", -"branded", -"brander", -"brandy", -"brangle", -"branial", -"brank", -"brankie", -"branle", -"branner", -"branny", -"bransle", -"brant", -"brash", -"brashy", -"brasque", -"brass", -"brasse", -"brasser", -"brasset", -"brassic", -"brassie", -"brassy", -"brat", -"brattie", -"brattle", -"brauna", -"bravade", -"bravado", -"brave", -"bravely", -"braver", -"bravery", -"braving", -"bravish", -"bravo", -"bravura", -"braw", -"brawl", -"brawler", -"brawly", -"brawlys", -"brawn", -"brawned", -"brawner", -"brawny", -"braws", -"braxy", -"bray", -"brayer", -"brayera", -"braza", -"braze", -"brazen", -"brazer", -"brazera", -"brazier", -"brazil", -"breach", -"breachy", -"bread", -"breaden", -"breadth", -"breaghe", -"break", -"breakax", -"breaker", -"breakup", -"bream", -"breards", -"breast", -"breath", -"breathe", -"breathy", -"breba", -"breccia", -"brecham", -"breck", -"brecken", -"bred", -"brede", -"bredi", -"bree", -"breech", -"breed", -"breeder", -"breedy", -"breek", -"breeze", -"breezy", -"bregma", -"brehon", -"brei", -"brekkle", -"brelaw", -"breme", -"bremely", -"brent", -"brephic", -"bret", -"breth", -"brett", -"breva", -"breve", -"brevet", -"brevier", -"brevit", -"brevity", -"brew", -"brewage", -"brewer", -"brewery", -"brewing", -"brewis", -"brewst", -"brey", -"briar", -"bribe", -"bribee", -"briber", -"bribery", -"brichen", -"brick", -"brickel", -"bricken", -"brickle", -"brickly", -"bricky", -"bricole", -"bridal", -"bridale", -"bride", -"bridely", -"bridge", -"bridged", -"bridger", -"bridle", -"bridled", -"bridler", -"bridoon", -"brief", -"briefly", -"briefs", -"brier", -"briered", -"briery", -"brieve", -"brig", -"brigade", -"brigand", -"bright", -"brill", -"brills", -"brim", -"brimful", -"briming", -"brimmed", -"brimmer", -"brin", -"brine", -"briner", -"bring", -"bringal", -"bringer", -"brinish", -"brinjal", -"brink", -"briny", -"brioche", -"brique", -"brisk", -"brisken", -"brisket", -"briskly", -"brisque", -"briss", -"bristle", -"bristly", -"brisure", -"brit", -"brith", -"brither", -"britska", -"britten", -"brittle", -"brizz", -"broach", -"broad", -"broadax", -"broaden", -"broadly", -"brob", -"brocade", -"brocard", -"broch", -"brochan", -"broche", -"brocho", -"brock", -"brocked", -"brocket", -"brockle", -"brod", -"brodder", -"brog", -"brogan", -"brogger", -"broggle", -"brogue", -"broguer", -"broider", -"broigne", -"broil", -"broiler", -"brokage", -"broke", -"broken", -"broker", -"broking", -"brolga", -"broll", -"brolly", -"broma", -"bromal", -"bromate", -"brome", -"bromic", -"bromide", -"bromine", -"bromism", -"bromite", -"bromize", -"bromoil", -"bromol", -"bromous", -"bronc", -"bronchi", -"bronco", -"bronk", -"bronze", -"bronzed", -"bronzen", -"bronzer", -"bronzy", -"broo", -"brooch", -"brood", -"brooder", -"broody", -"brook", -"brooked", -"brookie", -"brooky", -"brool", -"broom", -"broomer", -"broomy", -"broon", -"broose", -"brose", -"brosot", -"brosy", -"brot", -"brotan", -"brotany", -"broth", -"brothel", -"brother", -"brothy", -"brough", -"brought", -"brow", -"browden", -"browed", -"browis", -"browman", -"brown", -"browner", -"brownie", -"brownly", -"browny", -"browse", -"browser", -"browst", -"bruang", -"brucia", -"brucina", -"brucine", -"brucite", -"bruckle", -"brugh", -"bruin", -"bruise", -"bruiser", -"bruit", -"bruiter", -"bruke", -"brulee", -"brulyie", -"brumal", -"brumby", -"brume", -"brumous", -"brunch", -"brunet", -"brunt", -"bruscus", -"brush", -"brushed", -"brusher", -"brushes", -"brushet", -"brushy", -"brusque", -"brustle", -"brut", -"brutage", -"brutal", -"brute", -"brutely", -"brutify", -"bruting", -"brutish", -"brutism", -"brutter", -"bruzz", -"bryonin", -"bryony", -"bu", -"bual", -"buaze", -"bub", -"buba", -"bubal", -"bubalis", -"bubble", -"bubbler", -"bubbly", -"bubby", -"bubinga", -"bubo", -"buboed", -"bubonic", -"bubukle", -"bucare", -"bucca", -"buccal", -"buccan", -"buccate", -"buccina", -"buccula", -"buchite", -"buchu", -"buck", -"bucked", -"buckeen", -"bucker", -"bucket", -"buckety", -"buckeye", -"buckie", -"bucking", -"buckish", -"buckle", -"buckled", -"buckler", -"bucklum", -"bucko", -"buckpot", -"buckra", -"buckram", -"bucksaw", -"bucky", -"bucolic", -"bucrane", -"bud", -"buda", -"buddage", -"budder", -"buddhi", -"budding", -"buddle", -"buddler", -"buddy", -"budge", -"budger", -"budget", -"budless", -"budlet", -"budlike", -"budmash", -"budtime", -"budwood", -"budworm", -"budzat", -"bufagin", -"buff", -"buffalo", -"buffed", -"buffer", -"buffet", -"buffing", -"buffle", -"buffont", -"buffoon", -"buffy", -"bufidin", -"bufo", -"bug", -"bugaboo", -"bugan", -"bugbane", -"bugbear", -"bugbite", -"bugdom", -"bugfish", -"bugger", -"buggery", -"buggy", -"bughead", -"bugle", -"bugled", -"bugler", -"buglet", -"bugloss", -"bugre", -"bugseed", -"bugweed", -"bugwort", -"buhl", -"buhr", -"build", -"builder", -"buildup", -"built", -"buirdly", -"buisson", -"buist", -"bukh", -"bukshi", -"bulak", -"bulb", -"bulbar", -"bulbed", -"bulbil", -"bulblet", -"bulbose", -"bulbous", -"bulbul", -"bulbule", -"bulby", -"bulchin", -"bulge", -"bulger", -"bulgy", -"bulimia", -"bulimic", -"bulimy", -"bulk", -"bulked", -"bulker", -"bulkily", -"bulkish", -"bulky", -"bull", -"bulla", -"bullace", -"bullan", -"bullary", -"bullate", -"bullbat", -"bulldog", -"buller", -"bullet", -"bullety", -"bulling", -"bullion", -"bullish", -"bullism", -"bullit", -"bullnut", -"bullock", -"bullous", -"bullule", -"bully", -"bulrush", -"bulse", -"bult", -"bulter", -"bultey", -"bultong", -"bultow", -"bulwand", -"bulwark", -"bum", -"bumbaze", -"bumbee", -"bumble", -"bumbler", -"bumbo", -"bumboat", -"bumicky", -"bummalo", -"bummed", -"bummer", -"bummie", -"bumming", -"bummler", -"bummock", -"bump", -"bumpee", -"bumper", -"bumpily", -"bumping", -"bumpkin", -"bumpy", -"bumtrap", -"bumwood", -"bun", -"buna", -"buncal", -"bunce", -"bunch", -"buncher", -"bunchy", -"bund", -"bunder", -"bundle", -"bundler", -"bundlet", -"bundook", -"bundy", -"bung", -"bungee", -"bungey", -"bungfu", -"bungle", -"bungler", -"bungo", -"bungy", -"bunion", -"bunk", -"bunker", -"bunkery", -"bunkie", -"bunko", -"bunkum", -"bunnell", -"bunny", -"bunt", -"buntal", -"bunted", -"bunter", -"bunting", -"bunton", -"bunty", -"bunya", -"bunyah", -"bunyip", -"buoy", -"buoyage", -"buoyant", -"bur", -"buran", -"burao", -"burbank", -"burbark", -"burble", -"burbler", -"burbly", -"burbot", -"burbush", -"burd", -"burden", -"burdie", -"burdock", -"burdon", -"bure", -"bureau", -"bureaux", -"burel", -"burele", -"buret", -"burette", -"burfish", -"burg", -"burgage", -"burgall", -"burgee", -"burgeon", -"burgess", -"burgh", -"burghal", -"burgher", -"burglar", -"burgle", -"burgoo", -"burgul", -"burgus", -"burhead", -"buri", -"burial", -"burian", -"buried", -"burier", -"burin", -"burion", -"buriti", -"burka", -"burke", -"burker", -"burl", -"burlap", -"burled", -"burler", -"burlet", -"burlily", -"burly", -"burmite", -"burn", -"burned", -"burner", -"burnet", -"burnie", -"burning", -"burnish", -"burnous", -"burnout", -"burnt", -"burnut", -"burny", -"buro", -"burp", -"burr", -"burrah", -"burred", -"burrel", -"burrer", -"burring", -"burrish", -"burrito", -"burro", -"burrow", -"burry", -"bursa", -"bursal", -"bursar", -"bursary", -"bursate", -"burse", -"burseed", -"burst", -"burster", -"burt", -"burton", -"burucha", -"burweed", -"bury", -"burying", -"bus", -"busby", -"buscarl", -"bush", -"bushed", -"bushel", -"busher", -"bushful", -"bushi", -"bushily", -"bushing", -"bushlet", -"bushwa", -"bushy", -"busied", -"busily", -"busine", -"busk", -"busked", -"busker", -"busket", -"buskin", -"buskle", -"busky", -"busman", -"buss", -"busser", -"bussock", -"bussu", -"bust", -"bustard", -"busted", -"bustee", -"buster", -"bustic", -"bustle", -"bustled", -"bustler", -"busy", -"busying", -"busyish", -"but", -"butanal", -"butane", -"butanol", -"butch", -"butcher", -"butein", -"butene", -"butenyl", -"butic", -"butine", -"butler", -"butlery", -"butment", -"butoxy", -"butoxyl", -"butt", -"butte", -"butter", -"buttery", -"butting", -"buttle", -"buttock", -"button", -"buttons", -"buttony", -"butty", -"butyl", -"butylic", -"butyne", -"butyr", -"butyral", -"butyric", -"butyrin", -"butyryl", -"buxerry", -"buxom", -"buxomly", -"buy", -"buyable", -"buyer", -"buzane", -"buzz", -"buzzard", -"buzzer", -"buzzies", -"buzzing", -"buzzle", -"buzzwig", -"buzzy", -"by", -"bycoket", -"bye", -"byee", -"byeman", -"byepath", -"byerite", -"bygane", -"bygo", -"bygoing", -"bygone", -"byhand", -"bylaw", -"byname", -"byon", -"byous", -"byously", -"bypass", -"bypast", -"bypath", -"byplay", -"byre", -"byreman", -"byrlaw", -"byrnie", -"byroad", -"byrrus", -"bysen", -"byspell", -"byssal", -"byssin", -"byssine", -"byssoid", -"byssus", -"byth", -"bytime", -"bywalk", -"byway", -"bywoner", -"byword", -"bywork", -"c", -"ca", -"caam", -"caama", -"caaming", -"caapeba", -"cab", -"caba", -"cabaan", -"caback", -"cabaho", -"cabal", -"cabala", -"cabalic", -"caban", -"cabana", -"cabaret", -"cabas", -"cabbage", -"cabbagy", -"cabber", -"cabble", -"cabbler", -"cabby", -"cabda", -"caber", -"cabezon", -"cabin", -"cabinet", -"cabio", -"cable", -"cabled", -"cabler", -"cablet", -"cabling", -"cabman", -"cabob", -"cabocle", -"cabook", -"caboose", -"cabot", -"cabree", -"cabrit", -"cabuya", -"cacam", -"cacao", -"cachaza", -"cache", -"cachet", -"cachexy", -"cachou", -"cachrys", -"cacique", -"cack", -"cackle", -"cackler", -"cacodyl", -"cacoepy", -"caconym", -"cacoon", -"cacti", -"cactoid", -"cacur", -"cad", -"cadamba", -"cadaver", -"cadbait", -"cadbit", -"cadbote", -"caddice", -"caddie", -"caddis", -"caddish", -"caddle", -"caddow", -"caddy", -"cade", -"cadelle", -"cadence", -"cadency", -"cadent", -"cadenza", -"cader", -"caderas", -"cadet", -"cadetcy", -"cadette", -"cadew", -"cadge", -"cadger", -"cadgily", -"cadgy", -"cadi", -"cadism", -"cadjan", -"cadlock", -"cadmia", -"cadmic", -"cadmide", -"cadmium", -"cados", -"cadrans", -"cadre", -"cadua", -"caduac", -"caduca", -"cadus", -"cadweed", -"caeca", -"caecal", -"caecum", -"caeoma", -"caesura", -"cafeneh", -"cafenet", -"caffa", -"caffeic", -"caffeol", -"caffiso", -"caffle", -"caffoy", -"cafh", -"cafiz", -"caftan", -"cag", -"cage", -"caged", -"cageful", -"cageman", -"cager", -"cagey", -"caggy", -"cagily", -"cagit", -"cagmag", -"cahiz", -"cahoot", -"cahot", -"cahow", -"caickle", -"caid", -"caiman", -"caimito", -"cain", -"caique", -"caird", -"cairn", -"cairned", -"cairny", -"caisson", -"caitiff", -"cajeput", -"cajole", -"cajoler", -"cajuela", -"cajun", -"cajuput", -"cake", -"cakebox", -"caker", -"cakette", -"cakey", -"caky", -"cal", -"calaba", -"calaber", -"calade", -"calais", -"calalu", -"calamus", -"calash", -"calcar", -"calced", -"calcic", -"calcify", -"calcine", -"calcite", -"calcium", -"calculi", -"calden", -"caldron", -"calean", -"calends", -"calepin", -"calf", -"calfish", -"caliber", -"calibre", -"calices", -"calicle", -"calico", -"calid", -"caliga", -"caligo", -"calinda", -"calinut", -"calipee", -"caliper", -"caliph", -"caliver", -"calix", -"calk", -"calkage", -"calker", -"calkin", -"calking", -"call", -"callant", -"callboy", -"caller", -"callet", -"calli", -"callid", -"calling", -"callo", -"callose", -"callous", -"callow", -"callus", -"calm", -"calmant", -"calmer", -"calmly", -"calmy", -"calomba", -"calomel", -"calool", -"calor", -"caloric", -"calorie", -"caloris", -"calotte", -"caloyer", -"calp", -"calpac", -"calpack", -"caltrap", -"caltrop", -"calumba", -"calumet", -"calumny", -"calve", -"calved", -"calver", -"calves", -"calvish", -"calvity", -"calvous", -"calx", -"calyces", -"calycle", -"calymma", -"calypso", -"calyx", -"cam", -"camaca", -"camagon", -"camail", -"caman", -"camansi", -"camara", -"camass", -"camata", -"camb", -"cambaye", -"camber", -"cambial", -"cambism", -"cambist", -"cambium", -"cambrel", -"cambuca", -"came", -"cameist", -"camel", -"camelry", -"cameo", -"camera", -"cameral", -"camilla", -"camion", -"camise", -"camisia", -"camlet", -"cammed", -"cammock", -"camoodi", -"camp", -"campana", -"campane", -"camper", -"campho", -"camphol", -"camphor", -"campion", -"cample", -"campo", -"campody", -"campoo", -"campus", -"camus", -"camused", -"camwood", -"can", -"canaba", -"canada", -"canadol", -"canal", -"canamo", -"canape", -"canard", -"canari", -"canarin", -"canary", -"canasta", -"canaut", -"cancan", -"cancel", -"cancer", -"canch", -"cancrum", -"cand", -"candela", -"candent", -"candid", -"candied", -"candier", -"candify", -"candiru", -"candle", -"candler", -"candock", -"candor", -"candroy", -"candy", -"candys", -"cane", -"canel", -"canella", -"canelo", -"caner", -"canette", -"canful", -"cangan", -"cangia", -"cangle", -"cangler", -"cangue", -"canhoop", -"canid", -"canille", -"caninal", -"canine", -"caninus", -"canions", -"canjac", -"cank", -"canker", -"cankery", -"canman", -"canna", -"cannach", -"canned", -"cannel", -"canner", -"cannery", -"cannet", -"cannily", -"canning", -"cannon", -"cannot", -"cannula", -"canny", -"canoe", -"canon", -"canonic", -"canonry", -"canopic", -"canopy", -"canroy", -"canso", -"cant", -"cantala", -"cantar", -"cantara", -"cantaro", -"cantata", -"canted", -"canteen", -"canter", -"canthal", -"canthus", -"cantic", -"cantico", -"cantily", -"cantina", -"canting", -"cantion", -"cantish", -"cantle", -"cantlet", -"canto", -"canton", -"cantoon", -"cantor", -"cantred", -"cantref", -"cantrip", -"cantus", -"canty", -"canun", -"canvas", -"canvass", -"cany", -"canyon", -"canzon", -"caoba", -"cap", -"capable", -"capably", -"capanna", -"capanne", -"capax", -"capcase", -"cape", -"caped", -"capel", -"capelet", -"capelin", -"caper", -"caperer", -"capes", -"capful", -"caph", -"caphar", -"caphite", -"capias", -"capicha", -"capital", -"capitan", -"capivi", -"capkin", -"capless", -"caplin", -"capman", -"capmint", -"capomo", -"capon", -"caporal", -"capot", -"capote", -"capped", -"capper", -"cappie", -"capping", -"capple", -"cappy", -"caprate", -"capreol", -"capric", -"caprice", -"caprid", -"caprin", -"caprine", -"caproic", -"caproin", -"caprone", -"caproyl", -"capryl", -"capsa", -"capsid", -"capsize", -"capstan", -"capsula", -"capsule", -"captain", -"caption", -"captive", -"captor", -"capture", -"capuche", -"capulet", -"capulin", -"car", -"carabao", -"carabid", -"carabin", -"carabus", -"caracal", -"caracol", -"caract", -"carafe", -"caraibe", -"caraipi", -"caramba", -"caramel", -"caranda", -"carane", -"caranna", -"carapax", -"carapo", -"carat", -"caratch", -"caravan", -"caravel", -"caraway", -"carbarn", -"carbeen", -"carbene", -"carbide", -"carbine", -"carbo", -"carbon", -"carbona", -"carbora", -"carboxy", -"carboy", -"carbro", -"carbure", -"carbyl", -"carcake", -"carcass", -"carceag", -"carcel", -"carcoon", -"card", -"cardecu", -"carded", -"cardel", -"carder", -"cardia", -"cardiac", -"cardial", -"cardin", -"carding", -"cardo", -"cardol", -"cardon", -"cardona", -"cardoon", -"care", -"careen", -"career", -"careful", -"carene", -"carer", -"caress", -"carest", -"caret", -"carfare", -"carfax", -"carful", -"carga", -"cargo", -"carhop", -"cariama", -"caribou", -"carid", -"caries", -"carina", -"carinal", -"cariole", -"carious", -"cark", -"carking", -"carkled", -"carl", -"carless", -"carlet", -"carlie", -"carlin", -"carline", -"carling", -"carlish", -"carload", -"carlot", -"carls", -"carman", -"carmele", -"carmine", -"carmot", -"carnage", -"carnal", -"carnate", -"carneol", -"carney", -"carnic", -"carnify", -"carnose", -"carnous", -"caroa", -"carob", -"caroba", -"caroche", -"carol", -"caroler", -"caroli", -"carolin", -"carolus", -"carom", -"carone", -"caronic", -"caroome", -"caroon", -"carotic", -"carotid", -"carotin", -"carouse", -"carp", -"carpal", -"carpale", -"carpel", -"carpent", -"carper", -"carpet", -"carpid", -"carping", -"carpium", -"carport", -"carpos", -"carpus", -"carr", -"carrack", -"carrel", -"carrick", -"carried", -"carrier", -"carrion", -"carrizo", -"carroch", -"carrot", -"carroty", -"carrow", -"carry", -"carse", -"carshop", -"carsick", -"cart", -"cartage", -"carte", -"cartel", -"carter", -"cartful", -"cartman", -"carton", -"cartoon", -"cartway", -"carty", -"carua", -"carucal", -"carval", -"carve", -"carvel", -"carven", -"carvene", -"carver", -"carving", -"carvol", -"carvone", -"carvyl", -"caryl", -"casaba", -"casabe", -"casal", -"casalty", -"casate", -"casaun", -"casava", -"casave", -"casavi", -"casbah", -"cascade", -"cascado", -"cascara", -"casco", -"cascol", -"case", -"casease", -"caseate", -"casebox", -"cased", -"caseful", -"casefy", -"caseic", -"casein", -"caseose", -"caseous", -"caser", -"casern", -"caseum", -"cash", -"casha", -"cashaw", -"cashbox", -"cashboy", -"cashel", -"cashew", -"cashier", -"casing", -"casino", -"casiri", -"cask", -"casket", -"casking", -"casque", -"casqued", -"casquet", -"cass", -"cassady", -"casse", -"cassena", -"cassia", -"cassie", -"cassina", -"cassine", -"cassino", -"cassis", -"cassock", -"casson", -"cassoon", -"cast", -"caste", -"caster", -"castice", -"casting", -"castle", -"castled", -"castlet", -"castock", -"castoff", -"castor", -"castory", -"castra", -"castral", -"castrum", -"castuli", -"casual", -"casuary", -"casuist", -"casula", -"cat", -"catalpa", -"catan", -"catapan", -"cataria", -"catarrh", -"catasta", -"catbird", -"catboat", -"catcall", -"catch", -"catcher", -"catchup", -"catchy", -"catclaw", -"catdom", -"cate", -"catechu", -"catella", -"catena", -"catenae", -"cater", -"cateran", -"caterer", -"caterva", -"cateye", -"catface", -"catfall", -"catfish", -"catfoot", -"catgut", -"cathead", -"cathect", -"catheti", -"cathin", -"cathine", -"cathion", -"cathode", -"cathole", -"cathood", -"cathop", -"cathro", -"cation", -"cativo", -"catjang", -"catkin", -"catlap", -"catlike", -"catlin", -"catling", -"catmint", -"catnip", -"catpipe", -"catskin", -"catstep", -"catsup", -"cattabu", -"cattail", -"cattalo", -"cattery", -"cattily", -"catting", -"cattish", -"cattle", -"catty", -"catvine", -"catwalk", -"catwise", -"catwood", -"catwort", -"caubeen", -"cauboge", -"cauch", -"caucho", -"caucus", -"cauda", -"caudad", -"caudae", -"caudal", -"caudata", -"caudate", -"caudex", -"caudle", -"caught", -"cauk", -"caul", -"cauld", -"caules", -"cauline", -"caulis", -"caulome", -"caulote", -"caum", -"cauma", -"caunch", -"caup", -"caupo", -"caurale", -"causal", -"causate", -"cause", -"causer", -"causey", -"causing", -"causse", -"causson", -"caustic", -"cautel", -"cauter", -"cautery", -"caution", -"cautivo", -"cava", -"cavae", -"caval", -"cavalla", -"cavalry", -"cavate", -"cave", -"caveat", -"cavel", -"cavelet", -"cavern", -"cavetto", -"caviar", -"cavie", -"cavil", -"caviler", -"caving", -"cavings", -"cavish", -"cavity", -"caviya", -"cavort", -"cavus", -"cavy", -"caw", -"cawk", -"cawky", -"cawney", -"cawquaw", -"caxiri", -"caxon", -"cay", -"cayenne", -"cayman", -"caza", -"cazimi", -"ce", -"cearin", -"cease", -"ceasmic", -"cebell", -"cebian", -"cebid", -"cebil", -"cebine", -"ceboid", -"cebur", -"cecils", -"cecity", -"cedar", -"cedared", -"cedarn", -"cedary", -"cede", -"cedent", -"ceder", -"cedilla", -"cedrat", -"cedrate", -"cedre", -"cedrene", -"cedrin", -"cedrine", -"cedrium", -"cedrol", -"cedron", -"cedry", -"cedula", -"cee", -"ceibo", -"ceil", -"ceile", -"ceiler", -"ceilidh", -"ceiling", -"celadon", -"celemin", -"celery", -"celesta", -"celeste", -"celiac", -"celite", -"cell", -"cella", -"cellae", -"cellar", -"celled", -"cellist", -"cello", -"celloid", -"cellose", -"cellule", -"celsian", -"celt", -"celtium", -"celtuce", -"cembalo", -"cement", -"cenacle", -"cendre", -"cenoby", -"cense", -"censer", -"censive", -"censor", -"censual", -"censure", -"census", -"cent", -"centage", -"cental", -"centare", -"centaur", -"centavo", -"centena", -"center", -"centiar", -"centile", -"centime", -"centimo", -"centner", -"cento", -"centrad", -"central", -"centric", -"centrum", -"centry", -"centum", -"century", -"ceorl", -"cep", -"cepa", -"cepe", -"cephid", -"ceps", -"ceptor", -"cequi", -"cerago", -"ceral", -"ceramal", -"ceramic", -"ceras", -"cerasin", -"cerata", -"cerate", -"cerated", -"cercal", -"cerci", -"cercus", -"cere", -"cereal", -"cerebra", -"cered", -"cereous", -"cerer", -"ceresin", -"cerevis", -"ceria", -"ceric", -"ceride", -"cerillo", -"ceriman", -"cerin", -"cerine", -"ceriops", -"cerise", -"cerite", -"cerium", -"cermet", -"cern", -"cero", -"ceroma", -"cerote", -"cerotic", -"cerotin", -"cerous", -"cerrero", -"cerrial", -"cerris", -"certain", -"certie", -"certify", -"certis", -"certy", -"cerule", -"cerumen", -"ceruse", -"cervid", -"cervine", -"cervix", -"cervoid", -"ceryl", -"cesious", -"cesium", -"cess", -"cesser", -"cession", -"cessor", -"cesspit", -"cest", -"cestode", -"cestoid", -"cestrum", -"cestus", -"cetane", -"cetene", -"ceti", -"cetic", -"cetin", -"cetyl", -"cetylic", -"cevine", -"cha", -"chaa", -"chab", -"chabot", -"chabouk", -"chabuk", -"chacate", -"chack", -"chacker", -"chackle", -"chacma", -"chacona", -"chacte", -"chad", -"chaeta", -"chafe", -"chafer", -"chafery", -"chaff", -"chaffer", -"chaffy", -"chaft", -"chafted", -"chagan", -"chagrin", -"chaguar", -"chagul", -"chahar", -"chai", -"chain", -"chained", -"chainer", -"chainon", -"chair", -"chairer", -"chais", -"chaise", -"chaitya", -"chaja", -"chaka", -"chakar", -"chakari", -"chakazi", -"chakdar", -"chakobu", -"chakra", -"chakram", -"chaksi", -"chal", -"chalaco", -"chalana", -"chalaza", -"chalaze", -"chalcid", -"chalcon", -"chalcus", -"chalder", -"chalet", -"chalice", -"chalk", -"chalker", -"chalky", -"challah", -"challie", -"challis", -"chalmer", -"chalon", -"chalone", -"chalque", -"chalta", -"chalutz", -"cham", -"chamal", -"chamar", -"chamber", -"chambul", -"chamfer", -"chamiso", -"chamite", -"chamma", -"chamois", -"champ", -"champac", -"champer", -"champy", -"chance", -"chancel", -"chancer", -"chanche", -"chanco", -"chancre", -"chancy", -"chandam", -"chandi", -"chandoo", -"chandu", -"chandul", -"chang", -"changa", -"changar", -"change", -"changer", -"chank", -"channel", -"channer", -"chanson", -"chanst", -"chant", -"chanter", -"chantey", -"chantry", -"chao", -"chaos", -"chaotic", -"chap", -"chapah", -"chape", -"chapeau", -"chaped", -"chapel", -"chapin", -"chaplet", -"chapman", -"chapped", -"chapper", -"chappie", -"chappin", -"chappow", -"chappy", -"chaps", -"chapt", -"chapter", -"char", -"charac", -"charade", -"charas", -"charbon", -"chard", -"chare", -"charer", -"charet", -"charge", -"chargee", -"charger", -"charier", -"charily", -"chariot", -"charism", -"charity", -"chark", -"charka", -"charkha", -"charm", -"charmel", -"charmer", -"charnel", -"charpit", -"charpoy", -"charqui", -"charr", -"charry", -"chart", -"charter", -"charuk", -"chary", -"chase", -"chaser", -"chasing", -"chasm", -"chasma", -"chasmal", -"chasmed", -"chasmic", -"chasmy", -"chasse", -"chassis", -"chaste", -"chasten", -"chat", -"chataka", -"chateau", -"chati", -"chatta", -"chattel", -"chatter", -"chatty", -"chauk", -"chaus", -"chaute", -"chauth", -"chavish", -"chaw", -"chawan", -"chawer", -"chawk", -"chawl", -"chay", -"chaya", -"chayote", -"chazan", -"che", -"cheap", -"cheapen", -"cheaply", -"cheat", -"cheatee", -"cheater", -"chebec", -"chebel", -"chebog", -"chebule", -"check", -"checked", -"checker", -"checkup", -"checky", -"cheder", -"chee", -"cheecha", -"cheek", -"cheeker", -"cheeky", -"cheep", -"cheeper", -"cheepy", -"cheer", -"cheered", -"cheerer", -"cheerio", -"cheerly", -"cheery", -"cheese", -"cheeser", -"cheesy", -"cheet", -"cheetah", -"cheeter", -"cheetie", -"chef", -"chegoe", -"chegre", -"cheir", -"chekan", -"cheke", -"cheki", -"chekmak", -"chela", -"chelate", -"chelem", -"chelide", -"chello", -"chelone", -"chelp", -"chelys", -"chemic", -"chemis", -"chemise", -"chemism", -"chemist", -"chena", -"chende", -"cheng", -"chenica", -"cheque", -"cherem", -"cherish", -"cheroot", -"cherry", -"chert", -"cherte", -"cherty", -"cherub", -"chervil", -"cheson", -"chess", -"chessel", -"chesser", -"chest", -"chester", -"chesty", -"cheth", -"chettik", -"chetty", -"chevage", -"cheval", -"cheve", -"cheven", -"chevin", -"chevise", -"chevon", -"chevron", -"chevy", -"chew", -"chewer", -"chewink", -"chewy", -"cheyney", -"chhatri", -"chi", -"chia", -"chiasm", -"chiasma", -"chiaus", -"chibouk", -"chibrit", -"chic", -"chicane", -"chichi", -"chick", -"chicken", -"chicker", -"chicky", -"chicle", -"chico", -"chicory", -"chicot", -"chicote", -"chid", -"chidden", -"chide", -"chider", -"chiding", -"chidra", -"chief", -"chiefly", -"chield", -"chien", -"chiffer", -"chiffon", -"chiggak", -"chigger", -"chignon", -"chigoe", -"chih", -"chihfu", -"chikara", -"chil", -"child", -"childe", -"childed", -"childly", -"chile", -"chili", -"chiliad", -"chill", -"chilla", -"chilled", -"chiller", -"chillo", -"chillum", -"chilly", -"chiloma", -"chilver", -"chimble", -"chime", -"chimer", -"chimera", -"chimney", -"chin", -"china", -"chinar", -"chinch", -"chincha", -"chinche", -"chine", -"chined", -"ching", -"chingma", -"chinik", -"chinin", -"chink", -"chinker", -"chinkle", -"chinks", -"chinky", -"chinnam", -"chinned", -"chinny", -"chino", -"chinoa", -"chinol", -"chinse", -"chint", -"chintz", -"chip", -"chiplet", -"chipped", -"chipper", -"chippy", -"chips", -"chiral", -"chirata", -"chiripa", -"chirk", -"chirm", -"chiro", -"chirp", -"chirper", -"chirpy", -"chirr", -"chirrup", -"chisel", -"chit", -"chitak", -"chital", -"chitin", -"chiton", -"chitose", -"chitra", -"chitter", -"chitty", -"chive", -"chivey", -"chkalik", -"chlamyd", -"chlamys", -"chlor", -"chloral", -"chlore", -"chloric", -"chloryl", -"cho", -"choana", -"choate", -"choaty", -"chob", -"choca", -"chocard", -"chocho", -"chock", -"chocker", -"choel", -"choenix", -"choffer", -"choga", -"chogak", -"chogset", -"choice", -"choicy", -"choil", -"choiler", -"choir", -"chokage", -"choke", -"choker", -"choking", -"chokra", -"choky", -"chol", -"chola", -"cholane", -"cholate", -"chold", -"choleic", -"choler", -"cholera", -"choli", -"cholic", -"choline", -"cholla", -"choller", -"cholum", -"chomp", -"chondre", -"chonta", -"choop", -"choose", -"chooser", -"choosy", -"chop", -"chopa", -"chopin", -"chopine", -"chopped", -"chopper", -"choppy", -"choragy", -"choral", -"chord", -"chorda", -"chordal", -"chorded", -"chore", -"chorea", -"choreal", -"choree", -"choregy", -"choreic", -"choreus", -"chorial", -"choric", -"chorine", -"chorion", -"chorism", -"chorist", -"chorogi", -"choroid", -"chorook", -"chort", -"chorten", -"chortle", -"chorus", -"choryos", -"chose", -"chosen", -"chott", -"chough", -"chouka", -"choup", -"chous", -"chouse", -"chouser", -"chow", -"chowder", -"chowk", -"chowry", -"choya", -"chria", -"chrism", -"chrisma", -"chrisom", -"chroma", -"chrome", -"chromic", -"chromid", -"chromo", -"chromy", -"chromyl", -"chronal", -"chronic", -"chrotta", -"chrysal", -"chrysid", -"chrysin", -"chub", -"chubbed", -"chubby", -"chuck", -"chucker", -"chuckle", -"chucky", -"chuddar", -"chufa", -"chuff", -"chuffy", -"chug", -"chugger", -"chuhra", -"chukar", -"chukker", -"chukor", -"chulan", -"chullpa", -"chum", -"chummer", -"chummy", -"chump", -"chumpy", -"chun", -"chunari", -"chunga", -"chunk", -"chunky", -"chunner", -"chunnia", -"chunter", -"chupak", -"chupon", -"church", -"churchy", -"churel", -"churl", -"churled", -"churly", -"churm", -"churn", -"churr", -"churrus", -"chut", -"chute", -"chuter", -"chutney", -"chyack", -"chyak", -"chyle", -"chylify", -"chyloid", -"chylous", -"chymase", -"chyme", -"chymia", -"chymic", -"chymify", -"chymous", -"chypre", -"chytra", -"chytrid", -"cibol", -"cibory", -"ciboule", -"cicad", -"cicada", -"cicadid", -"cicala", -"cicely", -"cicer", -"cichlid", -"cidarid", -"cidaris", -"cider", -"cig", -"cigala", -"cigar", -"cigua", -"cilia", -"ciliary", -"ciliate", -"cilice", -"cilium", -"cimbia", -"cimelia", -"cimex", -"cimicid", -"cimline", -"cinch", -"cincher", -"cinclis", -"cinct", -"cinder", -"cindery", -"cine", -"cinel", -"cinema", -"cinene", -"cineole", -"cinerea", -"cingle", -"cinnyl", -"cinque", -"cinter", -"cinuran", -"cion", -"cipher", -"cipo", -"cipolin", -"cippus", -"circa", -"circle", -"circled", -"circler", -"circlet", -"circuit", -"circus", -"circusy", -"cirque", -"cirrate", -"cirri", -"cirrose", -"cirrous", -"cirrus", -"cirsoid", -"ciruela", -"cisco", -"cise", -"cisele", -"cissing", -"cissoid", -"cist", -"cista", -"cistae", -"cisted", -"cistern", -"cistic", -"cit", -"citable", -"citadel", -"citator", -"cite", -"citee", -"citer", -"citess", -"cithara", -"cither", -"citied", -"citify", -"citizen", -"citole", -"citral", -"citrate", -"citrean", -"citrene", -"citric", -"citril", -"citrin", -"citrine", -"citron", -"citrous", -"citrus", -"cittern", -"citua", -"city", -"citydom", -"cityful", -"cityish", -"cive", -"civet", -"civic", -"civics", -"civil", -"civilly", -"civism", -"civvy", -"cixiid", -"clabber", -"clachan", -"clack", -"clacker", -"clacket", -"clad", -"cladine", -"cladode", -"cladose", -"cladus", -"clag", -"claggum", -"claggy", -"claim", -"claimer", -"clairce", -"claith", -"claiver", -"clam", -"clamant", -"clamb", -"clamber", -"clame", -"clamer", -"clammed", -"clammer", -"clammy", -"clamor", -"clamp", -"clamper", -"clan", -"clang", -"clangor", -"clank", -"clanned", -"clap", -"clapnet", -"clapped", -"clapper", -"clapt", -"claque", -"claquer", -"clarain", -"claret", -"clarify", -"clarin", -"clarion", -"clarity", -"clark", -"claro", -"clart", -"clarty", -"clary", -"clash", -"clasher", -"clashy", -"clasp", -"clasper", -"claspt", -"class", -"classed", -"classer", -"classes", -"classic", -"classis", -"classy", -"clastic", -"clat", -"clatch", -"clatter", -"clatty", -"claught", -"clausal", -"clause", -"claut", -"clava", -"claval", -"clavate", -"clave", -"clavel", -"claver", -"clavial", -"clavier", -"claviol", -"clavis", -"clavola", -"clavus", -"clavy", -"claw", -"clawed", -"clawer", -"clawk", -"clawker", -"clay", -"clayen", -"clayer", -"clayey", -"clayish", -"clayman", -"claypan", -"cleach", -"clead", -"cleaded", -"cleam", -"cleamer", -"clean", -"cleaner", -"cleanly", -"cleanse", -"cleanup", -"clear", -"clearer", -"clearly", -"cleat", -"cleave", -"cleaver", -"cleche", -"cleck", -"cled", -"cledge", -"cledgy", -"clee", -"cleek", -"cleeked", -"cleeky", -"clef", -"cleft", -"clefted", -"cleg", -"clem", -"clement", -"clench", -"cleoid", -"clep", -"clergy", -"cleric", -"clerid", -"clerisy", -"clerk", -"clerkly", -"cleruch", -"cletch", -"cleuch", -"cleve", -"clever", -"clevis", -"clew", -"cliack", -"cliche", -"click", -"clicker", -"clicket", -"clicky", -"cliency", -"client", -"cliff", -"cliffed", -"cliffy", -"clift", -"clifty", -"clima", -"climata", -"climate", -"climath", -"climax", -"climb", -"climber", -"clime", -"clinal", -"clinch", -"cline", -"cling", -"clinger", -"clingy", -"clinia", -"clinic", -"clinium", -"clink", -"clinker", -"clinkum", -"clinoid", -"clint", -"clinty", -"clip", -"clipei", -"clipeus", -"clipped", -"clipper", -"clips", -"clipse", -"clipt", -"clique", -"cliquy", -"clisere", -"clit", -"clitch", -"clite", -"clites", -"clithe", -"clitia", -"clition", -"clitter", -"clival", -"clive", -"clivers", -"clivis", -"clivus", -"cloaca", -"cloacal", -"cloak", -"cloaked", -"cloam", -"cloamen", -"cloamer", -"clobber", -"clochan", -"cloche", -"clocher", -"clock", -"clocked", -"clocker", -"clod", -"clodder", -"cloddy", -"clodlet", -"cloff", -"clog", -"clogger", -"cloggy", -"cloghad", -"clogwyn", -"cloit", -"clomb", -"clomben", -"clonal", -"clone", -"clonic", -"clonism", -"clonus", -"cloof", -"cloop", -"cloot", -"clootie", -"clop", -"close", -"closed", -"closely", -"closen", -"closer", -"closet", -"closh", -"closish", -"closter", -"closure", -"clot", -"clotbur", -"clote", -"cloth", -"clothe", -"clothes", -"clothy", -"clotter", -"clotty", -"cloture", -"cloud", -"clouded", -"cloudy", -"clough", -"clour", -"clout", -"clouted", -"clouter", -"clouty", -"clove", -"cloven", -"clovene", -"clover", -"clovery", -"clow", -"clown", -"cloy", -"cloyer", -"cloying", -"club", -"clubbed", -"clubber", -"clubby", -"clubdom", -"clubman", -"cluck", -"clue", -"cluff", -"clump", -"clumpy", -"clumse", -"clumsy", -"clunch", -"clung", -"clunk", -"clupeid", -"cluster", -"clutch", -"cluther", -"clutter", -"cly", -"clyer", -"clype", -"clypeal", -"clypeus", -"clysis", -"clysma", -"clysmic", -"clyster", -"cnemial", -"cnemis", -"cnicin", -"cnida", -"coabode", -"coach", -"coachee", -"coacher", -"coachy", -"coact", -"coactor", -"coadapt", -"coadmit", -"coadore", -"coaged", -"coagent", -"coagula", -"coaid", -"coaita", -"coak", -"coakum", -"coal", -"coalbag", -"coalbin", -"coalbox", -"coaler", -"coalify", -"coalize", -"coalpit", -"coaly", -"coaming", -"coannex", -"coapt", -"coarb", -"coarse", -"coarsen", -"coast", -"coastal", -"coaster", -"coat", -"coated", -"coatee", -"coater", -"coati", -"coatie", -"coating", -"coax", -"coaxal", -"coaxer", -"coaxial", -"coaxing", -"coaxy", -"cob", -"cobaea", -"cobalt", -"cobang", -"cobbed", -"cobber", -"cobbing", -"cobble", -"cobbler", -"cobbly", -"cobbra", -"cobby", -"cobcab", -"cobego", -"cobhead", -"cobia", -"cobiron", -"coble", -"cobless", -"cobloaf", -"cobnut", -"cobola", -"cobourg", -"cobra", -"coburg", -"cobweb", -"cobwork", -"coca", -"cocaine", -"cocash", -"cocause", -"coccal", -"cocci", -"coccid", -"cocco", -"coccoid", -"coccous", -"coccule", -"coccus", -"coccyx", -"cochal", -"cochief", -"cochlea", -"cock", -"cockade", -"cockal", -"cocked", -"cocker", -"cocket", -"cockeye", -"cockily", -"cocking", -"cockish", -"cockle", -"cockled", -"cockler", -"cocklet", -"cockly", -"cockney", -"cockpit", -"cockshy", -"cockup", -"cocky", -"coco", -"cocoa", -"cocoach", -"coconut", -"cocoon", -"cocotte", -"coctile", -"coction", -"cocuisa", -"cocullo", -"cocuyo", -"cod", -"coda", -"codbank", -"codder", -"codding", -"coddle", -"coddler", -"code", -"codeine", -"coder", -"codex", -"codfish", -"codger", -"codhead", -"codical", -"codices", -"codicil", -"codify", -"codilla", -"codille", -"codist", -"codling", -"codman", -"codo", -"codol", -"codon", -"codworm", -"coe", -"coecal", -"coecum", -"coed", -"coelar", -"coelder", -"coelect", -"coelho", -"coelia", -"coeliac", -"coelian", -"coelin", -"coeline", -"coelom", -"coeloma", -"coempt", -"coenact", -"coenjoy", -"coenobe", -"coequal", -"coerce", -"coercer", -"coetus", -"coeval", -"coexert", -"coexist", -"coff", -"coffee", -"coffer", -"coffin", -"coffle", -"coffret", -"coft", -"cog", -"cogence", -"cogency", -"cogener", -"cogent", -"cogged", -"cogger", -"coggie", -"cogging", -"coggle", -"coggly", -"coghle", -"cogman", -"cognac", -"cognate", -"cognize", -"cogon", -"cogonal", -"cograil", -"cogroad", -"cogue", -"cogway", -"cogwood", -"cohabit", -"coheir", -"cohere", -"coherer", -"cohibit", -"coho", -"cohoba", -"cohol", -"cohort", -"cohosh", -"cohune", -"coif", -"coifed", -"coign", -"coigue", -"coil", -"coiled", -"coiler", -"coiling", -"coin", -"coinage", -"coiner", -"coinfer", -"coining", -"cointer", -"coiny", -"coir", -"coital", -"coition", -"coiture", -"coitus", -"cojudge", -"cojuror", -"coke", -"cokeman", -"coker", -"cokery", -"coking", -"coky", -"col", -"cola", -"colane", -"colarin", -"colate", -"colauxe", -"colback", -"cold", -"colder", -"coldish", -"coldly", -"cole", -"coletit", -"coleur", -"coli", -"colibri", -"colic", -"colical", -"colicky", -"colima", -"colin", -"coling", -"colitic", -"colitis", -"colk", -"coll", -"collage", -"collar", -"collard", -"collare", -"collate", -"collaud", -"collect", -"colleen", -"college", -"collery", -"collet", -"colley", -"collide", -"collie", -"collied", -"collier", -"collin", -"colline", -"colling", -"collins", -"collock", -"colloid", -"collop", -"collude", -"collum", -"colly", -"collyba", -"colmar", -"colobin", -"colon", -"colonel", -"colonic", -"colony", -"color", -"colored", -"colorer", -"colorin", -"colors", -"colory", -"coloss", -"colossi", -"colove", -"colp", -"colpeo", -"colport", -"colpus", -"colt", -"colter", -"coltish", -"colugo", -"columbo", -"column", -"colunar", -"colure", -"coly", -"colyone", -"colytic", -"colyum", -"colza", -"coma", -"comaker", -"comal", -"comamie", -"comanic", -"comart", -"comate", -"comb", -"combat", -"combed", -"comber", -"combine", -"combing", -"comble", -"comboy", -"combure", -"combust", -"comby", -"come", -"comedic", -"comedo", -"comedy", -"comely", -"comenic", -"comer", -"comes", -"comet", -"cometic", -"comfit", -"comfort", -"comfrey", -"comfy", -"comic", -"comical", -"comicry", -"coming", -"comino", -"comism", -"comital", -"comitia", -"comity", -"comma", -"command", -"commend", -"comment", -"commie", -"commit", -"commix", -"commixt", -"commode", -"common", -"commons", -"commot", -"commove", -"communa", -"commune", -"commute", -"comoid", -"comose", -"comourn", -"comous", -"compact", -"company", -"compare", -"compart", -"compass", -"compear", -"compeer", -"compel", -"compend", -"compete", -"compile", -"complex", -"complin", -"complot", -"comply", -"compo", -"compoer", -"compole", -"compone", -"compony", -"comport", -"compos", -"compose", -"compost", -"compote", -"compreg", -"compter", -"compute", -"comrade", -"con", -"conacre", -"conal", -"conamed", -"conatus", -"concave", -"conceal", -"concede", -"conceit", -"concent", -"concept", -"concern", -"concert", -"conch", -"concha", -"conchal", -"conche", -"conched", -"concher", -"conchy", -"concile", -"concise", -"concoct", -"concord", -"concupy", -"concur", -"concuss", -"cond", -"condemn", -"condign", -"condite", -"condole", -"condone", -"condor", -"conduce", -"conduct", -"conduit", -"condyle", -"cone", -"coned", -"coneen", -"coneine", -"conelet", -"coner", -"cones", -"confab", -"confact", -"confect", -"confess", -"confide", -"confine", -"confirm", -"confix", -"conflow", -"conflux", -"conform", -"confuse", -"confute", -"conga", -"congeal", -"congee", -"conger", -"congest", -"congius", -"congou", -"conic", -"conical", -"conicle", -"conics", -"conidia", -"conifer", -"conima", -"conin", -"conine", -"conject", -"conjoin", -"conjure", -"conjury", -"conk", -"conker", -"conkers", -"conky", -"conn", -"connach", -"connate", -"connect", -"conner", -"connex", -"conning", -"connive", -"connote", -"conoid", -"conopid", -"conquer", -"conred", -"consent", -"consign", -"consist", -"consol", -"console", -"consort", -"conspue", -"constat", -"consul", -"consult", -"consume", -"consute", -"contact", -"contain", -"conte", -"contect", -"contemn", -"content", -"conter", -"contest", -"context", -"contise", -"conto", -"contort", -"contour", -"contra", -"control", -"contund", -"contuse", -"conure", -"conus", -"conusee", -"conusor", -"conuzee", -"conuzor", -"convect", -"convene", -"convent", -"convert", -"conveth", -"convex", -"convey", -"convict", -"convive", -"convoke", -"convoy", -"cony", -"coo", -"cooba", -"coodle", -"cooee", -"cooer", -"coof", -"cooing", -"cooja", -"cook", -"cookdom", -"cookee", -"cooker", -"cookery", -"cooking", -"cookish", -"cookout", -"cooky", -"cool", -"coolant", -"coolen", -"cooler", -"coolie", -"cooling", -"coolish", -"coolly", -"coolth", -"coolung", -"cooly", -"coom", -"coomb", -"coomy", -"coon", -"cooncan", -"coonily", -"coontie", -"coony", -"coop", -"cooper", -"coopery", -"cooree", -"coorie", -"cooser", -"coost", -"coot", -"cooter", -"coothay", -"cootie", -"cop", -"copa", -"copable", -"copaene", -"copaiba", -"copaiye", -"copal", -"copalm", -"copart", -"coparty", -"cope", -"copei", -"copeman", -"copen", -"copepod", -"coper", -"coperta", -"copied", -"copier", -"copilot", -"coping", -"copious", -"copis", -"copist", -"copita", -"copolar", -"copped", -"copper", -"coppery", -"coppet", -"coppice", -"coppin", -"copping", -"copple", -"coppled", -"coppy", -"copr", -"copra", -"coprose", -"copse", -"copsing", -"copsy", -"copter", -"copula", -"copular", -"copus", -"copy", -"copycat", -"copyism", -"copyist", -"copyman", -"coque", -"coquet", -"coquina", -"coquita", -"coquito", -"cor", -"cora", -"corach", -"coracle", -"corah", -"coraise", -"coral", -"coraled", -"coram", -"coranto", -"corban", -"corbeau", -"corbeil", -"corbel", -"corbie", -"corbula", -"corcass", -"corcir", -"cord", -"cordage", -"cordant", -"cordate", -"cordax", -"corded", -"cordel", -"corder", -"cordial", -"cordies", -"cording", -"cordite", -"cordoba", -"cordon", -"cordy", -"cordyl", -"core", -"corebel", -"cored", -"coreid", -"coreign", -"corella", -"corer", -"corf", -"corge", -"corgi", -"corial", -"coriin", -"coring", -"corinne", -"corium", -"cork", -"corkage", -"corke", -"corked", -"corker", -"corking", -"corkish", -"corkite", -"corky", -"corm", -"cormel", -"cormoid", -"cormous", -"cormus", -"corn", -"cornage", -"cornbin", -"corncob", -"cornea", -"corneal", -"cornein", -"cornel", -"corner", -"cornet", -"corneum", -"cornic", -"cornice", -"cornin", -"corning", -"cornu", -"cornual", -"cornule", -"cornute", -"cornuto", -"corny", -"coroa", -"corody", -"corol", -"corolla", -"corona", -"coronad", -"coronae", -"coronal", -"coroner", -"coronet", -"corozo", -"corp", -"corpora", -"corps", -"corpse", -"corpus", -"corrade", -"corral", -"correal", -"correct", -"corrie", -"corrige", -"corrode", -"corrupt", -"corsac", -"corsage", -"corsair", -"corse", -"corset", -"corsie", -"corsite", -"corta", -"cortege", -"cortex", -"cortez", -"cortin", -"cortina", -"coruco", -"coruler", -"corupay", -"corver", -"corvina", -"corvine", -"corvoid", -"coryl", -"corylin", -"corymb", -"coryza", -"cos", -"cosaque", -"coscet", -"coseat", -"cosec", -"cosech", -"coseism", -"coset", -"cosh", -"cosher", -"coshery", -"cosily", -"cosine", -"cosmic", -"cosmism", -"cosmist", -"cosmos", -"coss", -"cossas", -"cosse", -"cosset", -"cossid", -"cost", -"costa", -"costal", -"costar", -"costard", -"costate", -"costean", -"coster", -"costing", -"costive", -"costly", -"costrel", -"costula", -"costume", -"cosy", -"cot", -"cotch", -"cote", -"coteful", -"coterie", -"coth", -"cothe", -"cothish", -"cothon", -"cothurn", -"cothy", -"cotidal", -"cotise", -"cotland", -"cotman", -"coto", -"cotoin", -"cotoro", -"cotrine", -"cotset", -"cotta", -"cottage", -"cotte", -"cotted", -"cotter", -"cottid", -"cottier", -"cottoid", -"cotton", -"cottony", -"cotty", -"cotuit", -"cotula", -"cotutor", -"cotwin", -"cotwist", -"cotyla", -"cotylar", -"cotype", -"couac", -"coucal", -"couch", -"couched", -"couchee", -"coucher", -"couchy", -"coude", -"coudee", -"coue", -"cougar", -"cough", -"cougher", -"cougnar", -"coul", -"could", -"coulee", -"coulomb", -"coulure", -"couma", -"coumara", -"council", -"counite", -"counsel", -"count", -"counter", -"countor", -"country", -"county", -"coup", -"coupage", -"coupe", -"couped", -"coupee", -"couper", -"couple", -"coupled", -"coupler", -"couplet", -"coupon", -"coupure", -"courage", -"courant", -"courap", -"courb", -"courge", -"courida", -"courier", -"couril", -"courlan", -"course", -"coursed", -"courser", -"court", -"courter", -"courtin", -"courtly", -"cousin", -"cousiny", -"coutel", -"couter", -"couth", -"couthie", -"coutil", -"couvade", -"couxia", -"covado", -"cove", -"coved", -"covent", -"cover", -"covered", -"coverer", -"covert", -"covet", -"coveter", -"covey", -"covid", -"covin", -"coving", -"covisit", -"covite", -"cow", -"cowal", -"coward", -"cowardy", -"cowbane", -"cowbell", -"cowbind", -"cowbird", -"cowboy", -"cowdie", -"coween", -"cower", -"cowfish", -"cowgate", -"cowgram", -"cowhage", -"cowheel", -"cowherb", -"cowherd", -"cowhide", -"cowhorn", -"cowish", -"cowitch", -"cowl", -"cowle", -"cowled", -"cowlick", -"cowlike", -"cowling", -"cowman", -"cowpath", -"cowpea", -"cowpen", -"cowpock", -"cowpox", -"cowrie", -"cowroid", -"cowshed", -"cowskin", -"cowslip", -"cowtail", -"cowweed", -"cowy", -"cowyard", -"cox", -"coxa", -"coxal", -"coxcomb", -"coxite", -"coxitis", -"coxy", -"coy", -"coyan", -"coydog", -"coyish", -"coyly", -"coyness", -"coynye", -"coyo", -"coyol", -"coyote", -"coypu", -"coyure", -"coz", -"coze", -"cozen", -"cozener", -"cozier", -"cozily", -"cozy", -"crab", -"crabbed", -"crabber", -"crabby", -"craber", -"crablet", -"crabman", -"crack", -"cracked", -"cracker", -"crackle", -"crackly", -"cracky", -"craddy", -"cradge", -"cradle", -"cradler", -"craft", -"crafty", -"crag", -"craggan", -"cragged", -"craggy", -"craichy", -"crain", -"craisey", -"craizey", -"crajuru", -"crake", -"crakow", -"cram", -"crambe", -"crambid", -"cramble", -"crambly", -"crambo", -"crammer", -"cramp", -"cramped", -"cramper", -"crampet", -"crampon", -"crampy", -"cran", -"cranage", -"crance", -"crane", -"craner", -"craney", -"crania", -"craniad", -"cranial", -"cranian", -"cranic", -"cranium", -"crank", -"cranked", -"cranker", -"crankle", -"crankly", -"crankum", -"cranky", -"crannog", -"cranny", -"crants", -"crap", -"crapaud", -"crape", -"crappie", -"crappin", -"crapple", -"crappo", -"craps", -"crapy", -"crare", -"crash", -"crasher", -"crasis", -"crass", -"crassly", -"cratch", -"crate", -"crater", -"craunch", -"cravat", -"crave", -"craven", -"craver", -"craving", -"cravo", -"craw", -"crawdad", -"crawful", -"crawl", -"crawler", -"crawley", -"crawly", -"crawm", -"crawtae", -"crayer", -"crayon", -"craze", -"crazed", -"crazily", -"crazy", -"crea", -"creagh", -"creaght", -"creak", -"creaker", -"creaky", -"cream", -"creamer", -"creamy", -"creance", -"creant", -"crease", -"creaser", -"creasy", -"creat", -"create", -"creatic", -"creator", -"creche", -"credent", -"credit", -"cree", -"creed", -"creedal", -"creeded", -"creek", -"creeker", -"creeky", -"creel", -"creeler", -"creem", -"creen", -"creep", -"creeper", -"creepie", -"creepy", -"creese", -"creesh", -"creeshy", -"cremate", -"cremone", -"cremor", -"cremule", -"crena", -"crenate", -"crenel", -"crenele", -"crenic", -"crenula", -"creole", -"creosol", -"crepe", -"crepine", -"crepon", -"crept", -"crepy", -"cresol", -"cresoxy", -"cress", -"cressed", -"cresset", -"cresson", -"cressy", -"crest", -"crested", -"cresyl", -"creta", -"cretic", -"cretify", -"cretin", -"cretion", -"crevice", -"crew", -"crewel", -"crewer", -"crewman", -"crib", -"cribber", -"cribble", -"cribo", -"cribral", -"cric", -"crick", -"cricket", -"crickey", -"crickle", -"cricoid", -"cried", -"crier", -"criey", -"crig", -"crile", -"crime", -"crimine", -"crimp", -"crimper", -"crimple", -"crimpy", -"crimson", -"crin", -"crinal", -"crine", -"crined", -"crinet", -"cringe", -"cringer", -"cringle", -"crinite", -"crink", -"crinkle", -"crinkly", -"crinoid", -"crinose", -"crinula", -"cripes", -"cripple", -"cripply", -"crises", -"crisic", -"crisis", -"crisp", -"crisped", -"crisper", -"crisply", -"crispy", -"criss", -"crissal", -"crissum", -"crista", -"critch", -"crith", -"critic", -"crizzle", -"cro", -"croak", -"croaker", -"croaky", -"croc", -"crocard", -"croceic", -"crocein", -"croche", -"crochet", -"croci", -"crocin", -"crock", -"crocker", -"crocket", -"crocky", -"crocus", -"croft", -"crofter", -"crome", -"crone", -"cronet", -"cronish", -"cronk", -"crony", -"crood", -"croodle", -"crook", -"crooked", -"crooken", -"crookle", -"crool", -"croon", -"crooner", -"crop", -"cropman", -"croppa", -"cropper", -"croppie", -"croppy", -"croquet", -"crore", -"crosa", -"crosier", -"crosnes", -"cross", -"crosse", -"crossed", -"crosser", -"crossly", -"crotal", -"crotalo", -"crotch", -"crotchy", -"crotin", -"crottle", -"crotyl", -"crouch", -"croup", -"croupal", -"croupe", -"croupy", -"crouse", -"crout", -"croute", -"crouton", -"crow", -"crowbar", -"crowd", -"crowded", -"crowder", -"crowdy", -"crower", -"crowhop", -"crowing", -"crowl", -"crown", -"crowned", -"crowner", -"crowtoe", -"croy", -"croyden", -"croydon", -"croze", -"crozer", -"crozzle", -"crozzly", -"crubeen", -"cruce", -"cruces", -"cruche", -"crucial", -"crucian", -"crucify", -"crucily", -"cruck", -"crude", -"crudely", -"crudity", -"cruel", -"cruelly", -"cruels", -"cruelty", -"cruent", -"cruet", -"cruety", -"cruise", -"cruiser", -"cruive", -"cruller", -"crum", -"crumb", -"crumber", -"crumble", -"crumbly", -"crumby", -"crumen", -"crumlet", -"crummie", -"crummy", -"crump", -"crumper", -"crumpet", -"crumple", -"crumply", -"crumpy", -"crunch", -"crunchy", -"crunk", -"crunkle", -"crunode", -"crunt", -"cruor", -"crupper", -"crural", -"crureus", -"crus", -"crusade", -"crusado", -"cruse", -"crush", -"crushed", -"crusher", -"crusie", -"crusily", -"crust", -"crusta", -"crustal", -"crusted", -"cruster", -"crusty", -"crutch", -"cruth", -"crutter", -"crux", -"cry", -"cryable", -"crybaby", -"crying", -"cryogen", -"cryosel", -"crypt", -"crypta", -"cryptal", -"crypted", -"cryptic", -"crystal", -"crystic", -"csardas", -"ctene", -"ctenoid", -"cuadra", -"cuarta", -"cub", -"cubage", -"cubbing", -"cubbish", -"cubby", -"cubdom", -"cube", -"cubeb", -"cubelet", -"cuber", -"cubhood", -"cubi", -"cubic", -"cubica", -"cubical", -"cubicle", -"cubicly", -"cubism", -"cubist", -"cubit", -"cubital", -"cubited", -"cubito", -"cubitus", -"cuboid", -"cuck", -"cuckold", -"cuckoo", -"cuculla", -"cud", -"cudava", -"cudbear", -"cudden", -"cuddle", -"cuddly", -"cuddy", -"cudgel", -"cudweed", -"cue", -"cueball", -"cueca", -"cueist", -"cueman", -"cuerda", -"cuesta", -"cuff", -"cuffer", -"cuffin", -"cuffy", -"cuinage", -"cuir", -"cuirass", -"cuisine", -"cuisse", -"cuissen", -"cuisten", -"cuke", -"culbut", -"culebra", -"culet", -"culeus", -"culgee", -"culicid", -"cull", -"culla", -"cullage", -"culler", -"cullet", -"culling", -"cullion", -"cullis", -"cully", -"culm", -"culmen", -"culmy", -"culotte", -"culpa", -"culpose", -"culprit", -"cult", -"cultch", -"cultic", -"cultish", -"cultism", -"cultist", -"cultual", -"culture", -"cultus", -"culver", -"culvert", -"cum", -"cumal", -"cumay", -"cumbent", -"cumber", -"cumbha", -"cumbly", -"cumbre", -"cumbu", -"cumene", -"cumenyl", -"cumhal", -"cumic", -"cumidin", -"cumin", -"cuminal", -"cuminic", -"cuminol", -"cuminyl", -"cummer", -"cummin", -"cumol", -"cump", -"cumshaw", -"cumular", -"cumuli", -"cumulus", -"cumyl", -"cuneal", -"cuneate", -"cunette", -"cuneus", -"cunila", -"cunjah", -"cunjer", -"cunner", -"cunning", -"cunye", -"cuorin", -"cup", -"cupay", -"cupcake", -"cupel", -"cupeler", -"cupful", -"cuphead", -"cupidon", -"cupless", -"cupman", -"cupmate", -"cupola", -"cupolar", -"cupped", -"cupper", -"cupping", -"cuppy", -"cuprene", -"cupric", -"cupride", -"cuprite", -"cuproid", -"cuprose", -"cuprous", -"cuprum", -"cupseed", -"cupula", -"cupule", -"cur", -"curable", -"curably", -"curacao", -"curacy", -"curare", -"curate", -"curatel", -"curatic", -"curator", -"curb", -"curber", -"curbing", -"curby", -"curcas", -"curch", -"curd", -"curdle", -"curdler", -"curdly", -"curdy", -"cure", -"curer", -"curette", -"curfew", -"curial", -"curiate", -"curie", -"curin", -"curine", -"curing", -"curio", -"curiosa", -"curioso", -"curious", -"curite", -"curium", -"curl", -"curled", -"curler", -"curlew", -"curlike", -"curlily", -"curling", -"curly", -"curn", -"curney", -"curnock", -"curple", -"curr", -"currach", -"currack", -"curragh", -"currant", -"current", -"curried", -"currier", -"currish", -"curry", -"cursal", -"curse", -"cursed", -"curser", -"curship", -"cursive", -"cursor", -"cursory", -"curst", -"curstly", -"cursus", -"curt", -"curtail", -"curtain", -"curtal", -"curtate", -"curtesy", -"curtly", -"curtsy", -"curua", -"curuba", -"curule", -"cururo", -"curvant", -"curvate", -"curve", -"curved", -"curver", -"curvet", -"curvity", -"curvous", -"curvy", -"cuscus", -"cusec", -"cush", -"cushag", -"cushat", -"cushaw", -"cushion", -"cushy", -"cusie", -"cusk", -"cusp", -"cuspal", -"cuspate", -"cusped", -"cuspid", -"cuspule", -"cuss", -"cussed", -"cusser", -"cusso", -"custard", -"custody", -"custom", -"customs", -"cut", -"cutaway", -"cutback", -"cutch", -"cutcher", -"cute", -"cutely", -"cutheal", -"cuticle", -"cutie", -"cutin", -"cutis", -"cutitis", -"cutlass", -"cutler", -"cutlery", -"cutlet", -"cutling", -"cutlips", -"cutoff", -"cutout", -"cutover", -"cuttage", -"cuttail", -"cutted", -"cutter", -"cutting", -"cuttle", -"cuttler", -"cuttoo", -"cutty", -"cutup", -"cutweed", -"cutwork", -"cutworm", -"cuvette", -"cuvy", -"cuya", -"cwierc", -"cwm", -"cyan", -"cyanate", -"cyanean", -"cyanic", -"cyanide", -"cyanin", -"cyanine", -"cyanite", -"cyanize", -"cyanol", -"cyanole", -"cyanose", -"cyanus", -"cyath", -"cyathos", -"cyathus", -"cycad", -"cyclane", -"cyclar", -"cyclas", -"cycle", -"cyclene", -"cycler", -"cyclian", -"cyclic", -"cyclide", -"cycling", -"cyclism", -"cyclist", -"cyclize", -"cycloid", -"cyclone", -"cyclope", -"cyclopy", -"cyclose", -"cyclus", -"cyesis", -"cygnet", -"cygnine", -"cyke", -"cylix", -"cyma", -"cymar", -"cymba", -"cymbal", -"cymbalo", -"cymbate", -"cyme", -"cymelet", -"cymene", -"cymling", -"cymoid", -"cymose", -"cymous", -"cymule", -"cynebot", -"cynic", -"cynical", -"cynipid", -"cynism", -"cynoid", -"cyp", -"cypre", -"cypres", -"cypress", -"cyprine", -"cypsela", -"cyrus", -"cyst", -"cystal", -"cysted", -"cystic", -"cystid", -"cystine", -"cystis", -"cystoid", -"cystoma", -"cystose", -"cystous", -"cytase", -"cytasic", -"cytitis", -"cytode", -"cytoid", -"cytoma", -"cyton", -"cytost", -"cytula", -"czar", -"czardas", -"czardom", -"czarian", -"czaric", -"czarina", -"czarish", -"czarism", -"czarist", -"d", -"da", -"daalder", -"dab", -"dabb", -"dabba", -"dabber", -"dabble", -"dabbler", -"dabby", -"dablet", -"daboia", -"daboya", -"dabster", -"dace", -"dacite", -"dacitic", -"dacker", -"dacoit", -"dacoity", -"dacryon", -"dactyl", -"dad", -"dada", -"dadap", -"dadder", -"daddle", -"daddock", -"daddy", -"dade", -"dado", -"dae", -"daedal", -"daemon", -"daemony", -"daer", -"daff", -"daffery", -"daffing", -"daffish", -"daffle", -"daffy", -"daft", -"daftly", -"dag", -"dagaba", -"dagame", -"dagassa", -"dagesh", -"dagga", -"dagger", -"daggers", -"daggle", -"daggly", -"daggy", -"daghesh", -"daglock", -"dagoba", -"dags", -"dah", -"dahoon", -"daidle", -"daidly", -"daiker", -"daikon", -"daily", -"daimen", -"daimio", -"daimon", -"dain", -"daincha", -"dainty", -"daira", -"dairi", -"dairy", -"dais", -"daisied", -"daisy", -"daitya", -"daiva", -"dak", -"daker", -"dakir", -"dal", -"dalar", -"dale", -"daleman", -"daler", -"daleth", -"dali", -"dalk", -"dallack", -"dalle", -"dalles", -"dallier", -"dally", -"dalt", -"dalteen", -"dalton", -"dam", -"dama", -"damage", -"damager", -"damages", -"daman", -"damask", -"damasse", -"dambose", -"dambrod", -"dame", -"damiana", -"damie", -"damier", -"damine", -"damlike", -"dammar", -"damme", -"dammer", -"dammish", -"damn", -"damned", -"damner", -"damnify", -"damning", -"damnous", -"damp", -"dampang", -"damped", -"dampen", -"damper", -"damping", -"dampish", -"damply", -"dampy", -"damsel", -"damson", -"dan", -"danaid", -"danaide", -"danaine", -"danaite", -"dance", -"dancer", -"dancery", -"dancing", -"dand", -"danda", -"dander", -"dandify", -"dandily", -"dandle", -"dandler", -"dandy", -"dang", -"danger", -"dangle", -"dangler", -"danglin", -"danio", -"dank", -"dankish", -"dankly", -"danli", -"danner", -"dannock", -"dansant", -"danta", -"danton", -"dao", -"daoine", -"dap", -"daphnin", -"dapicho", -"dapico", -"dapifer", -"dapper", -"dapple", -"dappled", -"dar", -"darac", -"daraf", -"darat", -"darbha", -"darby", -"dardaol", -"dare", -"dareall", -"dareful", -"darer", -"daresay", -"darg", -"dargah", -"darger", -"dargue", -"dari", -"daribah", -"daric", -"daring", -"dariole", -"dark", -"darken", -"darkful", -"darkish", -"darkle", -"darkly", -"darky", -"darling", -"darn", -"darned", -"darnel", -"darner", -"darnex", -"darning", -"daroga", -"daroo", -"darr", -"darrein", -"darst", -"dart", -"dartars", -"darter", -"darting", -"dartle", -"dartman", -"dartoic", -"dartoid", -"dartos", -"dartre", -"darts", -"darzee", -"das", -"dash", -"dashed", -"dashee", -"dasheen", -"dasher", -"dashing", -"dashpot", -"dashy", -"dasi", -"dasnt", -"dassie", -"dassy", -"dastard", -"dastur", -"dasturi", -"dasyure", -"data", -"datable", -"datably", -"dataria", -"datary", -"datch", -"datcha", -"date", -"dater", -"datil", -"dating", -"dation", -"datival", -"dative", -"dattock", -"datum", -"daturic", -"daub", -"daube", -"dauber", -"daubery", -"daubing", -"dauby", -"daud", -"daunch", -"dauncy", -"daunt", -"daunter", -"daunton", -"dauphin", -"daut", -"dautie", -"dauw", -"davach", -"daven", -"daver", -"daverdy", -"davit", -"davoch", -"davy", -"davyne", -"daw", -"dawdle", -"dawdler", -"dawdy", -"dawish", -"dawkin", -"dawn", -"dawning", -"dawny", -"dawtet", -"dawtit", -"dawut", -"day", -"dayal", -"daybeam", -"daybook", -"daydawn", -"dayfly", -"dayless", -"daylit", -"daylong", -"dayman", -"daymare", -"daymark", -"dayroom", -"days", -"daysman", -"daystar", -"daytale", -"daytide", -"daytime", -"dayward", -"daywork", -"daywrit", -"daze", -"dazed", -"dazedly", -"dazy", -"dazzle", -"dazzler", -"de", -"deacon", -"dead", -"deaden", -"deader", -"deadeye", -"deading", -"deadish", -"deadly", -"deadman", -"deadpan", -"deadpay", -"deaf", -"deafen", -"deafish", -"deafly", -"deair", -"deal", -"dealate", -"dealer", -"dealing", -"dealt", -"dean", -"deaner", -"deanery", -"deaness", -"dear", -"dearie", -"dearly", -"dearth", -"deary", -"deash", -"deasil", -"death", -"deathin", -"deathly", -"deathy", -"deave", -"deavely", -"deb", -"debacle", -"debadge", -"debar", -"debark", -"debase", -"debaser", -"debate", -"debater", -"debauch", -"debby", -"debeige", -"deben", -"debile", -"debind", -"debit", -"debord", -"debosh", -"debouch", -"debride", -"debrief", -"debris", -"debt", -"debtee", -"debtful", -"debtor", -"debunk", -"debus", -"debut", -"decad", -"decadal", -"decade", -"decadic", -"decafid", -"decagon", -"decal", -"decamp", -"decan", -"decanal", -"decane", -"decani", -"decant", -"decap", -"decapod", -"decarch", -"decare", -"decart", -"decast", -"decate", -"decator", -"decatyl", -"decay", -"decayed", -"decayer", -"decease", -"deceit", -"deceive", -"decence", -"decency", -"decene", -"decent", -"decenyl", -"decern", -"decess", -"deciare", -"decibel", -"decide", -"decided", -"decider", -"decidua", -"decil", -"decile", -"decima", -"decimal", -"deck", -"decke", -"decked", -"deckel", -"decker", -"deckie", -"decking", -"deckle", -"declaim", -"declare", -"declass", -"decline", -"declive", -"decoat", -"decoct", -"decode", -"decoic", -"decoke", -"decolor", -"decorum", -"decoy", -"decoyer", -"decream", -"decree", -"decreer", -"decreet", -"decrete", -"decrew", -"decrial", -"decried", -"decrier", -"decrown", -"decry", -"decuman", -"decuple", -"decuria", -"decurve", -"decury", -"decus", -"decyl", -"decylic", -"decyne", -"dedimus", -"dedo", -"deduce", -"deduct", -"dee", -"deed", -"deedbox", -"deedeed", -"deedful", -"deedily", -"deedy", -"deem", -"deemer", -"deemie", -"deep", -"deepen", -"deeping", -"deepish", -"deeply", -"deer", -"deerdog", -"deerlet", -"deevey", -"deface", -"defacer", -"defalk", -"defame", -"defamed", -"defamer", -"defassa", -"defat", -"default", -"defease", -"defeat", -"defect", -"defence", -"defend", -"defense", -"defer", -"defial", -"defiant", -"defiber", -"deficit", -"defier", -"defile", -"defiled", -"defiler", -"define", -"defined", -"definer", -"deflate", -"deflect", -"deflesh", -"deflex", -"defog", -"deforce", -"deform", -"defoul", -"defraud", -"defray", -"defrock", -"defrost", -"deft", -"deftly", -"defunct", -"defuse", -"defy", -"deg", -"degas", -"degauss", -"degerm", -"degged", -"degger", -"deglaze", -"degorge", -"degrade", -"degrain", -"degree", -"degu", -"degum", -"degust", -"dehair", -"dehisce", -"dehorn", -"dehors", -"dehort", -"dehull", -"dehusk", -"deice", -"deicer", -"deicide", -"deictic", -"deific", -"deifier", -"deiform", -"deify", -"deign", -"deink", -"deinos", -"deiseal", -"deism", -"deist", -"deistic", -"deity", -"deject", -"dejecta", -"dejeune", -"dekko", -"dekle", -"delaine", -"delapse", -"delate", -"delater", -"delator", -"delawn", -"delay", -"delayer", -"dele", -"delead", -"delenda", -"delete", -"delf", -"delft", -"delible", -"delict", -"delight", -"delime", -"delimit", -"delint", -"deliver", -"dell", -"deloul", -"delouse", -"delta", -"deltaic", -"deltal", -"deltic", -"deltoid", -"delude", -"deluder", -"deluge", -"deluxe", -"delve", -"delver", -"demagog", -"demal", -"demand", -"demarch", -"demark", -"demast", -"deme", -"demean", -"demency", -"dement", -"demerit", -"demesne", -"demi", -"demibob", -"demidog", -"demigod", -"demihag", -"demiman", -"demiowl", -"demiox", -"demiram", -"demirep", -"demise", -"demiss", -"demit", -"demivol", -"demob", -"demoded", -"demoid", -"demon", -"demonic", -"demonry", -"demos", -"demote", -"demotic", -"demount", -"demulce", -"demure", -"demy", -"den", -"denaro", -"denary", -"denat", -"denda", -"dendral", -"dendric", -"dendron", -"dene", -"dengue", -"denial", -"denier", -"denim", -"denizen", -"dennet", -"denote", -"dense", -"densely", -"densen", -"densher", -"densify", -"density", -"dent", -"dental", -"dentale", -"dentary", -"dentata", -"dentate", -"dentel", -"denter", -"dentex", -"dentil", -"dentile", -"dentin", -"dentine", -"dentist", -"dentoid", -"denture", -"denty", -"denude", -"denuder", -"deny", -"deodand", -"deodara", -"deota", -"depa", -"depaint", -"depark", -"depart", -"depas", -"depass", -"depend", -"depeter", -"dephase", -"depict", -"deplane", -"deplete", -"deplore", -"deploy", -"deplume", -"deplump", -"depoh", -"depone", -"deport", -"deposal", -"depose", -"deposer", -"deposit", -"depot", -"deprave", -"depress", -"deprint", -"deprive", -"depside", -"depth", -"depthen", -"depute", -"deputy", -"dequeen", -"derah", -"deraign", -"derail", -"derange", -"derat", -"derate", -"derater", -"deray", -"derby", -"dere", -"dereism", -"deric", -"deride", -"derider", -"derival", -"derive", -"derived", -"deriver", -"derm", -"derma", -"dermad", -"dermal", -"dermic", -"dermis", -"dermoid", -"dermol", -"dern", -"dernier", -"derout", -"derrick", -"derride", -"derries", -"derry", -"dertrum", -"derust", -"dervish", -"desalt", -"desand", -"descale", -"descant", -"descend", -"descent", -"descort", -"descry", -"deseed", -"deseret", -"desert", -"deserve", -"desex", -"desi", -"desight", -"design", -"desire", -"desired", -"desirer", -"desist", -"desize", -"desk", -"deslime", -"desma", -"desman", -"desmic", -"desmid", -"desmine", -"desmoid", -"desmoma", -"desmon", -"despair", -"despect", -"despise", -"despite", -"despoil", -"despond", -"despot", -"dess", -"dessa", -"dessert", -"dessil", -"destain", -"destine", -"destiny", -"destour", -"destroy", -"desuete", -"desugar", -"desyl", -"detach", -"detail", -"detain", -"detar", -"detax", -"detect", -"detent", -"deter", -"deterge", -"detest", -"detin", -"detinet", -"detinue", -"detour", -"detract", -"detrain", -"detrude", -"detune", -"detur", -"deuce", -"deuced", -"deul", -"deuton", -"dev", -"deva", -"devall", -"devalue", -"devance", -"devast", -"devata", -"develin", -"develop", -"devest", -"deviant", -"deviate", -"device", -"devil", -"deviled", -"deviler", -"devilet", -"devilry", -"devily", -"devious", -"devisal", -"devise", -"devisee", -"deviser", -"devisor", -"devoice", -"devoid", -"devoir", -"devolve", -"devote", -"devoted", -"devotee", -"devoter", -"devour", -"devout", -"devow", -"devvel", -"dew", -"dewan", -"dewanee", -"dewater", -"dewax", -"dewbeam", -"dewclaw", -"dewcup", -"dewdamp", -"dewdrop", -"dewer", -"dewfall", -"dewily", -"dewlap", -"dewless", -"dewlike", -"dewool", -"deworm", -"dewret", -"dewtry", -"dewworm", -"dewy", -"dexter", -"dextrad", -"dextral", -"dextran", -"dextrin", -"dextro", -"dey", -"deyship", -"dezinc", -"dha", -"dhabb", -"dhai", -"dhak", -"dhamnoo", -"dhan", -"dhangar", -"dhanuk", -"dhanush", -"dharana", -"dharani", -"dharma", -"dharna", -"dhaura", -"dhauri", -"dhava", -"dhaw", -"dheri", -"dhobi", -"dhole", -"dhoni", -"dhoon", -"dhoti", -"dhoul", -"dhow", -"dhu", -"dhunchi", -"dhurra", -"dhyal", -"dhyana", -"di", -"diabase", -"diacid", -"diacle", -"diacope", -"diact", -"diactin", -"diadem", -"diaderm", -"diaene", -"diagram", -"dial", -"dialect", -"dialer", -"dialin", -"dialing", -"dialist", -"dialkyl", -"diallel", -"diallyl", -"dialyze", -"diamb", -"diambic", -"diamide", -"diamine", -"diamond", -"dian", -"diander", -"dianite", -"diapase", -"diapasm", -"diaper", -"diaplex", -"diapsid", -"diarch", -"diarchy", -"diarial", -"diarian", -"diarist", -"diarize", -"diary", -"diastem", -"diaster", -"diasyrm", -"diatom", -"diaulic", -"diaulos", -"diaxial", -"diaxon", -"diazide", -"diazine", -"diazoic", -"diazole", -"diazoma", -"dib", -"dibase", -"dibasic", -"dibatag", -"dibber", -"dibble", -"dibbler", -"dibbuk", -"dibhole", -"dibrach", -"dibrom", -"dibs", -"dicast", -"dice", -"dicebox", -"dicecup", -"diceman", -"dicer", -"dicetyl", -"dich", -"dichas", -"dichord", -"dicing", -"dick", -"dickens", -"dicker", -"dickey", -"dicky", -"dicolic", -"dicolon", -"dicot", -"dicotyl", -"dicta", -"dictate", -"dictic", -"diction", -"dictum", -"dicycle", -"did", -"didder", -"diddle", -"diddler", -"diddy", -"didelph", -"didie", -"didine", -"didle", -"didna", -"didnt", -"didromy", -"didst", -"didym", -"didymia", -"didymus", -"die", -"dieb", -"dieback", -"diedral", -"diedric", -"diehard", -"dielike", -"diem", -"diene", -"dier", -"diesel", -"diesis", -"diet", -"dietal", -"dietary", -"dieter", -"diethyl", -"dietic", -"dietics", -"dietine", -"dietist", -"diewise", -"diffame", -"differ", -"diffide", -"difform", -"diffuse", -"dig", -"digamma", -"digamy", -"digenic", -"digeny", -"digest", -"digger", -"digging", -"dight", -"dighter", -"digit", -"digital", -"digitus", -"diglot", -"diglyph", -"digmeat", -"dignify", -"dignity", -"digram", -"digraph", -"digress", -"digs", -"dihalo", -"diiamb", -"diiodo", -"dika", -"dikage", -"dike", -"diker", -"diketo", -"dikkop", -"dilate", -"dilated", -"dilater", -"dilator", -"dildo", -"dilemma", -"dilker", -"dill", -"dilli", -"dillier", -"dilling", -"dillue", -"dilluer", -"dilly", -"dilo", -"dilogy", -"diluent", -"dilute", -"diluted", -"dilutee", -"diluter", -"dilutor", -"diluvia", -"dim", -"dimber", -"dimble", -"dime", -"dimer", -"dimeran", -"dimeric", -"dimeter", -"dimiss", -"dimit", -"dimity", -"dimly", -"dimmed", -"dimmer", -"dimmest", -"dimmet", -"dimmish", -"dimness", -"dimoric", -"dimorph", -"dimple", -"dimply", -"dimps", -"dimpsy", -"din", -"dinar", -"dinder", -"dindle", -"dine", -"diner", -"dineric", -"dinero", -"dinette", -"ding", -"dingar", -"dingbat", -"dinge", -"dingee", -"dinghee", -"dinghy", -"dingily", -"dingle", -"dingly", -"dingo", -"dingus", -"dingy", -"dinic", -"dinical", -"dining", -"dinitro", -"dink", -"dinkey", -"dinkum", -"dinky", -"dinmont", -"dinner", -"dinnery", -"dinomic", -"dinsome", -"dint", -"dinus", -"diobely", -"diobol", -"diocese", -"diode", -"diodont", -"dioecy", -"diol", -"dionise", -"dionym", -"diopter", -"dioptra", -"dioptry", -"diorama", -"diorite", -"diose", -"diosmin", -"diota", -"diotic", -"dioxane", -"dioxide", -"dioxime", -"dioxy", -"dip", -"dipetto", -"diphase", -"diphead", -"diplex", -"diploe", -"diploic", -"diploid", -"diplois", -"diploma", -"diplont", -"diplopy", -"dipnoan", -"dipnoid", -"dipode", -"dipodic", -"dipody", -"dipolar", -"dipole", -"diporpa", -"dipped", -"dipper", -"dipping", -"dipsas", -"dipsey", -"dipter", -"diptote", -"diptych", -"dipware", -"dipygus", -"dipylon", -"dipyre", -"dird", -"dirdum", -"dire", -"direct", -"direful", -"direly", -"dirempt", -"dirge", -"dirgler", -"dirhem", -"dirk", -"dirl", -"dirndl", -"dirt", -"dirten", -"dirtily", -"dirty", -"dis", -"disable", -"disagio", -"disally", -"disarm", -"disavow", -"disawa", -"disazo", -"disband", -"disbar", -"disbark", -"disbody", -"disbud", -"disbury", -"disc", -"discage", -"discal", -"discard", -"discase", -"discept", -"discern", -"discerp", -"discoid", -"discord", -"discous", -"discus", -"discuss", -"disdain", -"disdub", -"disease", -"disedge", -"diseme", -"disemic", -"disfame", -"disfen", -"disgig", -"disglut", -"disgood", -"disgown", -"disgulf", -"disgust", -"dish", -"dished", -"dishelm", -"disher", -"dishful", -"dishome", -"dishorn", -"dishpan", -"dishrag", -"disject", -"disjoin", -"disjune", -"disk", -"disleaf", -"dislike", -"dislimn", -"dislink", -"dislip", -"disload", -"dislove", -"dismain", -"dismal", -"disman", -"dismark", -"dismask", -"dismast", -"dismay", -"disme", -"dismiss", -"disna", -"disnest", -"disnew", -"disobey", -"disodic", -"disomic", -"disomus", -"disorb", -"disown", -"dispark", -"dispart", -"dispel", -"dispend", -"display", -"dispone", -"dispope", -"disport", -"dispose", -"dispost", -"dispulp", -"dispute", -"disrank", -"disrate", -"disring", -"disrobe", -"disroof", -"disroot", -"disrump", -"disrupt", -"diss", -"disseat", -"dissect", -"dissent", -"dissert", -"dissoul", -"dissuit", -"distad", -"distaff", -"distain", -"distal", -"distale", -"distant", -"distend", -"distent", -"distich", -"distill", -"distome", -"distort", -"distune", -"disturb", -"disturn", -"disuse", -"diswood", -"disyoke", -"dit", -"dita", -"dital", -"ditch", -"ditcher", -"dite", -"diter", -"dither", -"dithery", -"dithion", -"ditolyl", -"ditone", -"dittamy", -"dittany", -"dittay", -"dittied", -"ditto", -"ditty", -"diurnal", -"diurne", -"div", -"diva", -"divan", -"divata", -"dive", -"divel", -"diver", -"diverge", -"divers", -"diverse", -"divert", -"divest", -"divide", -"divided", -"divider", -"divine", -"diviner", -"diving", -"divinyl", -"divisor", -"divorce", -"divot", -"divoto", -"divulge", -"divulse", -"divus", -"divvy", -"diwata", -"dixie", -"dixit", -"dixy", -"dizain", -"dizen", -"dizoic", -"dizzard", -"dizzily", -"dizzy", -"djave", -"djehad", -"djerib", -"djersa", -"do", -"doab", -"doable", -"doarium", -"doat", -"doated", -"doater", -"doating", -"doatish", -"dob", -"dobbed", -"dobber", -"dobbin", -"dobbing", -"dobby", -"dobe", -"dobla", -"doblon", -"dobra", -"dobrao", -"dobson", -"doby", -"doc", -"docent", -"docible", -"docile", -"docity", -"dock", -"dockage", -"docken", -"docker", -"docket", -"dockize", -"dockman", -"docmac", -"doctor", -"doctrix", -"dod", -"dodd", -"doddart", -"dodded", -"dodder", -"doddery", -"doddie", -"dodding", -"doddle", -"doddy", -"dodecyl", -"dodge", -"dodger", -"dodgery", -"dodgily", -"dodgy", -"dodkin", -"dodlet", -"dodman", -"dodo", -"dodoism", -"dodrans", -"doe", -"doebird", -"doeglic", -"doer", -"does", -"doeskin", -"doesnt", -"doest", -"doff", -"doffer", -"dog", -"dogal", -"dogate", -"dogbane", -"dogbite", -"dogblow", -"dogboat", -"dogbolt", -"dogbush", -"dogcart", -"dogdom", -"doge", -"dogedom", -"dogface", -"dogfall", -"dogfish", -"dogfoot", -"dogged", -"dogger", -"doggery", -"doggess", -"doggish", -"doggo", -"doggone", -"doggrel", -"doggy", -"doghead", -"doghole", -"doghood", -"dogie", -"dogless", -"doglike", -"dogly", -"dogma", -"dogman", -"dogmata", -"dogs", -"dogship", -"dogskin", -"dogtail", -"dogtie", -"dogtrot", -"dogvane", -"dogwood", -"dogy", -"doigt", -"doiled", -"doily", -"doina", -"doing", -"doings", -"doit", -"doited", -"doitkin", -"doke", -"dokhma", -"dola", -"dolabra", -"dolcan", -"dolcian", -"dolcino", -"doldrum", -"dole", -"doleful", -"dolent", -"doless", -"doli", -"dolia", -"dolina", -"doline", -"dolium", -"doll", -"dollar", -"dolldom", -"dollier", -"dollish", -"dollop", -"dolly", -"dolman", -"dolmen", -"dolor", -"dolose", -"dolous", -"dolphin", -"dolt", -"doltish", -"dom", -"domain", -"domal", -"domba", -"dome", -"doment", -"domer", -"domett", -"domic", -"domical", -"domine", -"dominie", -"domino", -"dominus", -"domite", -"domitic", -"domn", -"domnei", -"domoid", -"dompt", -"domy", -"don", -"donable", -"donary", -"donate", -"donated", -"donatee", -"donator", -"donax", -"done", -"donee", -"doney", -"dong", -"donga", -"dongon", -"donjon", -"donkey", -"donna", -"donnert", -"donnish", -"donnism", -"donnot", -"donor", -"donship", -"donsie", -"dont", -"donum", -"doob", -"doocot", -"doodab", -"doodad", -"doodle", -"doodler", -"dooja", -"dook", -"dooket", -"dookit", -"dool", -"doolee", -"dooley", -"dooli", -"doolie", -"dooly", -"doom", -"doomage", -"doomer", -"doomful", -"dooms", -"doon", -"door", -"doorba", -"doorboy", -"doored", -"doorman", -"doorway", -"dop", -"dopa", -"dopatta", -"dope", -"doper", -"dopey", -"dopper", -"doppia", -"dor", -"dorab", -"dorad", -"dorado", -"doree", -"dorhawk", -"doria", -"dorje", -"dorlach", -"dorlot", -"dorm", -"dormant", -"dormer", -"dormie", -"dormy", -"dorn", -"dorneck", -"dornic", -"dornick", -"dornock", -"dorp", -"dorsad", -"dorsal", -"dorsale", -"dorsel", -"dorser", -"dorsum", -"dorter", -"dorts", -"dorty", -"doruck", -"dory", -"dos", -"dosa", -"dosadh", -"dosage", -"dose", -"doser", -"dosis", -"doss", -"dossal", -"dossel", -"dosser", -"dossier", -"dossil", -"dossman", -"dot", -"dotage", -"dotal", -"dotard", -"dotardy", -"dotate", -"dotchin", -"dote", -"doted", -"doter", -"doting", -"dotish", -"dotkin", -"dotless", -"dotlike", -"dotted", -"dotter", -"dottily", -"dotting", -"dottle", -"dottler", -"dotty", -"doty", -"douar", -"double", -"doubled", -"doubler", -"doublet", -"doubly", -"doubt", -"doubter", -"douc", -"douce", -"doucely", -"doucet", -"douche", -"doucin", -"doucine", -"doudle", -"dough", -"dought", -"doughty", -"doughy", -"doum", -"doup", -"douping", -"dour", -"dourine", -"dourly", -"douse", -"douser", -"dout", -"douter", -"doutous", -"dove", -"dovecot", -"dovekey", -"dovekie", -"dovelet", -"dover", -"dovish", -"dow", -"dowable", -"dowager", -"dowcet", -"dowd", -"dowdily", -"dowdy", -"dowed", -"dowel", -"dower", -"doweral", -"dowery", -"dowf", -"dowie", -"dowily", -"dowitch", -"dowl", -"dowlas", -"dowless", -"down", -"downby", -"downcry", -"downcut", -"downer", -"downily", -"downlie", -"downset", -"downway", -"downy", -"dowp", -"dowry", -"dowse", -"dowser", -"dowset", -"doxa", -"doxy", -"doze", -"dozed", -"dozen", -"dozener", -"dozenth", -"dozer", -"dozily", -"dozy", -"dozzled", -"drab", -"drabbet", -"drabble", -"drabby", -"drably", -"drachm", -"drachma", -"dracma", -"draff", -"draffy", -"draft", -"draftee", -"drafter", -"drafty", -"drag", -"dragade", -"dragbar", -"dragged", -"dragger", -"draggle", -"draggly", -"draggy", -"dragman", -"dragnet", -"drago", -"dragon", -"dragoon", -"dragsaw", -"drail", -"drain", -"draine", -"drained", -"drainer", -"drake", -"dram", -"drama", -"dramm", -"dramme", -"drammed", -"drammer", -"drang", -"drank", -"drant", -"drape", -"draper", -"drapery", -"drassid", -"drastic", -"drat", -"drate", -"dratted", -"draught", -"dravya", -"draw", -"drawarm", -"drawbar", -"drawboy", -"drawcut", -"drawee", -"drawer", -"drawers", -"drawing", -"drawk", -"drawl", -"drawler", -"drawly", -"drawn", -"drawnet", -"drawoff", -"drawout", -"drawrod", -"dray", -"drayage", -"drayman", -"drazel", -"dread", -"dreader", -"dreadly", -"dream", -"dreamer", -"dreamsy", -"dreamt", -"dreamy", -"drear", -"drearly", -"dreary", -"dredge", -"dredger", -"dree", -"dreep", -"dreepy", -"dreg", -"dreggy", -"dregs", -"drench", -"dreng", -"dress", -"dressed", -"dresser", -"dressy", -"drest", -"drew", -"drewite", -"drias", -"drib", -"dribble", -"driblet", -"driddle", -"dried", -"drier", -"driest", -"drift", -"drifter", -"drifty", -"drill", -"driller", -"drillet", -"dringle", -"drink", -"drinker", -"drinn", -"drip", -"dripper", -"dripple", -"drippy", -"drisk", -"drivage", -"drive", -"drivel", -"driven", -"driver", -"driving", -"drizzle", -"drizzly", -"droddum", -"drogh", -"drogher", -"drogue", -"droit", -"droll", -"drolly", -"drome", -"dromic", -"dromond", -"dromos", -"drona", -"dronage", -"drone", -"droner", -"drongo", -"dronish", -"drony", -"drool", -"droop", -"drooper", -"droopt", -"droopy", -"drop", -"droplet", -"dropman", -"dropout", -"dropper", -"droppy", -"dropsy", -"dropt", -"droshky", -"drosky", -"dross", -"drossel", -"drosser", -"drossy", -"drostdy", -"droud", -"drought", -"drouk", -"drove", -"drover", -"drovy", -"drow", -"drown", -"drowner", -"drowse", -"drowsy", -"drub", -"drubber", -"drubbly", -"drucken", -"drudge", -"drudger", -"druery", -"drug", -"drugger", -"drugget", -"druggy", -"drugman", -"druid", -"druidic", -"druidry", -"druith", -"drum", -"drumble", -"drumlin", -"drumly", -"drummer", -"drummy", -"drung", -"drungar", -"drunk", -"drunken", -"drupal", -"drupe", -"drupel", -"druse", -"drusy", -"druxy", -"dry", -"dryad", -"dryadic", -"dryas", -"drycoal", -"dryfoot", -"drying", -"dryish", -"dryly", -"dryness", -"dryster", -"dryth", -"duad", -"duadic", -"dual", -"duali", -"dualin", -"dualism", -"dualist", -"duality", -"dualize", -"dually", -"duarch", -"duarchy", -"dub", -"dubash", -"dubb", -"dubba", -"dubbah", -"dubber", -"dubbing", -"dubby", -"dubiety", -"dubious", -"dubs", -"ducal", -"ducally", -"ducape", -"ducat", -"ducato", -"ducdame", -"duces", -"duchess", -"duchy", -"duck", -"ducker", -"duckery", -"duckie", -"ducking", -"duckpin", -"duct", -"ducted", -"ductile", -"duction", -"ductor", -"ductule", -"dud", -"dudaim", -"dudder", -"duddery", -"duddies", -"dude", -"dudeen", -"dudgeon", -"dudine", -"dudish", -"dudism", -"dudler", -"dudley", -"dudman", -"due", -"duel", -"dueler", -"dueling", -"duelist", -"duello", -"dueness", -"duenna", -"duer", -"duet", -"duff", -"duffel", -"duffer", -"duffing", -"dufoil", -"dufter", -"duftery", -"dug", -"dugal", -"dugdug", -"duggler", -"dugong", -"dugout", -"dugway", -"duhat", -"duiker", -"duim", -"duit", -"dujan", -"duke", -"dukedom", -"dukely", -"dukery", -"dukhn", -"dukker", -"dulbert", -"dulcet", -"dulcian", -"dulcify", -"dulcose", -"duledge", -"duler", -"dulia", -"dull", -"dullard", -"duller", -"dullery", -"dullify", -"dullish", -"dullity", -"dully", -"dulosis", -"dulotic", -"dulse", -"dult", -"dultie", -"duly", -"dum", -"duma", -"dumaist", -"dumb", -"dumba", -"dumbcow", -"dumbly", -"dumdum", -"dummel", -"dummy", -"dumose", -"dump", -"dumpage", -"dumper", -"dumpily", -"dumping", -"dumpish", -"dumple", -"dumpoke", -"dumpy", -"dumsola", -"dun", -"dunair", -"dunal", -"dunbird", -"dunce", -"duncery", -"dunch", -"duncify", -"duncish", -"dunder", -"dune", -"dunfish", -"dung", -"dungeon", -"dunger", -"dungol", -"dungon", -"dungy", -"dunite", -"dunk", -"dunker", -"dunlin", -"dunnage", -"dunne", -"dunner", -"dunness", -"dunnish", -"dunnite", -"dunnock", -"dunny", -"dunst", -"dunt", -"duntle", -"duny", -"duo", -"duodena", -"duodene", -"duole", -"duopod", -"duopoly", -"duotone", -"duotype", -"dup", -"dupable", -"dupe", -"dupedom", -"duper", -"dupery", -"dupion", -"dupla", -"duple", -"duplet", -"duplex", -"duplify", -"duplone", -"duppy", -"dura", -"durable", -"durably", -"durain", -"dural", -"duramen", -"durance", -"durant", -"durax", -"durbar", -"dure", -"durene", -"durenol", -"duress", -"durgan", -"durian", -"during", -"durity", -"durmast", -"durn", -"duro", -"durra", -"durrie", -"durrin", -"durry", -"durst", -"durwaun", -"duryl", -"dusack", -"duscle", -"dush", -"dusio", -"dusk", -"dusken", -"duskily", -"duskish", -"duskly", -"dusky", -"dust", -"dustbin", -"dustbox", -"dustee", -"duster", -"dustily", -"dusting", -"dustman", -"dustpan", -"dustuck", -"dusty", -"dutch", -"duteous", -"dutied", -"dutiful", -"dutra", -"duty", -"duumvir", -"duvet", -"duvetyn", -"dux", -"duyker", -"dvaita", -"dvandva", -"dwale", -"dwalm", -"dwang", -"dwarf", -"dwarfy", -"dwell", -"dwelled", -"dweller", -"dwelt", -"dwindle", -"dwine", -"dyad", -"dyadic", -"dyarchy", -"dyaster", -"dyce", -"dye", -"dyeable", -"dyeing", -"dyer", -"dyester", -"dyeware", -"dyeweed", -"dyewood", -"dying", -"dyingly", -"dyke", -"dyker", -"dynamic", -"dynamis", -"dynamo", -"dynast", -"dynasty", -"dyne", -"dyphone", -"dyslogy", -"dysnomy", -"dyspnea", -"dystome", -"dysuria", -"dysuric", -"dzeren", -"e", -"ea", -"each", -"eager", -"eagerly", -"eagle", -"eagless", -"eaglet", -"eagre", -"ean", -"ear", -"earache", -"earbob", -"earcap", -"eardrop", -"eardrum", -"eared", -"earful", -"earhole", -"earing", -"earl", -"earlap", -"earldom", -"earless", -"earlet", -"earlike", -"earlish", -"earlock", -"early", -"earmark", -"earn", -"earner", -"earnest", -"earnful", -"earning", -"earpick", -"earplug", -"earring", -"earshot", -"earsore", -"eartab", -"earth", -"earthed", -"earthen", -"earthly", -"earthy", -"earwax", -"earwig", -"earworm", -"earwort", -"ease", -"easeful", -"easel", -"easer", -"easier", -"easiest", -"easily", -"easing", -"east", -"easter", -"eastern", -"easting", -"easy", -"eat", -"eatable", -"eatage", -"eaten", -"eater", -"eatery", -"eating", -"eats", -"eave", -"eaved", -"eaver", -"eaves", -"ebb", -"ebbman", -"eboe", -"ebon", -"ebonist", -"ebonite", -"ebonize", -"ebony", -"ebriate", -"ebriety", -"ebrious", -"ebulus", -"eburine", -"ecad", -"ecanda", -"ecarte", -"ecbatic", -"ecbole", -"ecbolic", -"ecdemic", -"ecderon", -"ecdysis", -"ecesic", -"ecesis", -"eche", -"echea", -"echelon", -"echidna", -"echinal", -"echinid", -"echinus", -"echo", -"echoer", -"echoic", -"echoism", -"echoist", -"echoize", -"ecize", -"ecklein", -"eclair", -"eclat", -"eclegm", -"eclegma", -"eclipse", -"eclogue", -"ecoid", -"ecole", -"ecology", -"economy", -"ecotone", -"ecotype", -"ecphore", -"ecru", -"ecstasy", -"ectad", -"ectal", -"ectally", -"ectasia", -"ectasis", -"ectatic", -"ectene", -"ecthyma", -"ectiris", -"ectopia", -"ectopic", -"ectopy", -"ectozoa", -"ectypal", -"ectype", -"eczema", -"edacity", -"edaphic", -"edaphon", -"edder", -"eddish", -"eddo", -"eddy", -"edea", -"edeagra", -"edeitis", -"edema", -"edemic", -"edenite", -"edental", -"edestan", -"edestin", -"edge", -"edged", -"edgeman", -"edger", -"edging", -"edgrew", -"edgy", -"edh", -"edible", -"edict", -"edictal", -"edicule", -"edifice", -"edifier", -"edify", -"edit", -"edital", -"edition", -"editor", -"educand", -"educate", -"educe", -"educive", -"educt", -"eductor", -"eegrass", -"eel", -"eelboat", -"eelbob", -"eelcake", -"eeler", -"eelery", -"eelfare", -"eelfish", -"eellike", -"eelpot", -"eelpout", -"eelshop", -"eelskin", -"eelware", -"eelworm", -"eely", -"eer", -"eerie", -"eerily", -"effable", -"efface", -"effacer", -"effect", -"effects", -"effendi", -"effete", -"effigy", -"efflate", -"efflux", -"efform", -"effort", -"effulge", -"effund", -"effuse", -"eft", -"eftest", -"egad", -"egality", -"egence", -"egeran", -"egest", -"egesta", -"egg", -"eggcup", -"egger", -"eggfish", -"egghead", -"egghot", -"egging", -"eggler", -"eggless", -"egglike", -"eggnog", -"eggy", -"egilops", -"egipto", -"egma", -"ego", -"egohood", -"egoism", -"egoist", -"egoity", -"egoize", -"egoizer", -"egol", -"egomism", -"egotism", -"egotist", -"egotize", -"egress", -"egret", -"eh", -"eheu", -"ehlite", -"ehuawa", -"eident", -"eider", -"eidetic", -"eidolic", -"eidolon", -"eight", -"eighth", -"eighty", -"eigne", -"eimer", -"einkorn", -"eisodic", -"either", -"eject", -"ejecta", -"ejector", -"ejoo", -"ekaha", -"eke", -"eker", -"ekerite", -"eking", -"ekka", -"ekphore", -"ektene", -"ektenes", -"el", -"elaidic", -"elaidin", -"elain", -"elaine", -"elance", -"eland", -"elanet", -"elapid", -"elapine", -"elapoid", -"elapse", -"elastic", -"elastin", -"elatcha", -"elate", -"elated", -"elater", -"elation", -"elative", -"elator", -"elb", -"elbow", -"elbowed", -"elbower", -"elbowy", -"elcaja", -"elchee", -"eld", -"elder", -"elderly", -"eldest", -"eldin", -"elding", -"eldress", -"elect", -"electee", -"electly", -"elector", -"electro", -"elegant", -"elegiac", -"elegist", -"elegit", -"elegize", -"elegy", -"eleidin", -"element", -"elemi", -"elemin", -"elench", -"elenchi", -"elenge", -"elevate", -"eleven", -"elevon", -"elf", -"elfhood", -"elfic", -"elfin", -"elfish", -"elfkin", -"elfland", -"elflike", -"elflock", -"elfship", -"elfwife", -"elfwort", -"elicit", -"elide", -"elision", -"elisor", -"elite", -"elixir", -"elk", -"elkhorn", -"elkslip", -"elkwood", -"ell", -"ellagic", -"elle", -"elleck", -"ellfish", -"ellipse", -"ellops", -"ellwand", -"elm", -"elmy", -"elocute", -"elod", -"eloge", -"elogium", -"eloign", -"elope", -"eloper", -"elops", -"els", -"else", -"elsehow", -"elsin", -"elt", -"eluate", -"elude", -"eluder", -"elusion", -"elusive", -"elusory", -"elute", -"elution", -"elutor", -"eluvial", -"eluvium", -"elvan", -"elver", -"elves", -"elvet", -"elvish", -"elysia", -"elytral", -"elytrin", -"elytron", -"elytrum", -"em", -"emanant", -"emanate", -"emanium", -"emarcid", -"emball", -"embalm", -"embank", -"embar", -"embargo", -"embark", -"embassy", -"embathe", -"embay", -"embed", -"embelic", -"ember", -"embind", -"embira", -"emblaze", -"emblem", -"emblema", -"emblic", -"embody", -"embog", -"embole", -"embolic", -"embolo", -"embolum", -"embolus", -"emboly", -"embosom", -"emboss", -"embound", -"embow", -"embowed", -"embowel", -"embower", -"embox", -"embrace", -"embrail", -"embroil", -"embrown", -"embryo", -"embryon", -"embuia", -"embus", -"embusk", -"emcee", -"eme", -"emeer", -"emend", -"emender", -"emerald", -"emerge", -"emerize", -"emerse", -"emersed", -"emery", -"emesis", -"emetic", -"emetine", -"emgalla", -"emigree", -"eminent", -"emir", -"emirate", -"emit", -"emitter", -"emma", -"emmenic", -"emmer", -"emmet", -"emodin", -"emoloa", -"emote", -"emotion", -"emotive", -"empall", -"empanel", -"empaper", -"empark", -"empasm", -"empathy", -"emperor", -"empery", -"empire", -"empiric", -"emplace", -"emplane", -"employ", -"emplume", -"emporia", -"empower", -"empress", -"emprise", -"empt", -"emptier", -"emptily", -"emptins", -"emption", -"emptor", -"empty", -"empyema", -"emu", -"emulant", -"emulate", -"emulous", -"emulsin", -"emulsor", -"emyd", -"emydian", -"en", -"enable", -"enabler", -"enact", -"enactor", -"enaena", -"enage", -"enalid", -"enam", -"enamber", -"enamdar", -"enamel", -"enamor", -"enapt", -"enarbor", -"enarch", -"enarm", -"enarme", -"enate", -"enatic", -"enation", -"enbrave", -"encage", -"encake", -"encamp", -"encase", -"encash", -"encauma", -"encave", -"encell", -"enchain", -"enchair", -"enchant", -"enchase", -"enchest", -"encina", -"encinal", -"encist", -"enclasp", -"enclave", -"encloak", -"enclose", -"encloud", -"encoach", -"encode", -"encoil", -"encolor", -"encomia", -"encomic", -"encoop", -"encore", -"encowl", -"encraal", -"encraty", -"encreel", -"encrisp", -"encrown", -"encrust", -"encrypt", -"encup", -"encurl", -"encyst", -"end", -"endable", -"endarch", -"endaze", -"endear", -"ended", -"endemic", -"ender", -"endere", -"enderon", -"endevil", -"endew", -"endgate", -"ending", -"endite", -"endive", -"endless", -"endlong", -"endmost", -"endogen", -"endome", -"endopod", -"endoral", -"endore", -"endorse", -"endoss", -"endotys", -"endow", -"endower", -"endozoa", -"endue", -"endura", -"endure", -"endurer", -"endways", -"endwise", -"endyma", -"endymal", -"endysis", -"enema", -"enemy", -"energic", -"energid", -"energy", -"eneuch", -"eneugh", -"enface", -"enfelon", -"enfeoff", -"enfever", -"enfile", -"enfiled", -"enflesh", -"enfoil", -"enfold", -"enforce", -"enfork", -"enfoul", -"enframe", -"enfree", -"engage", -"engaged", -"engager", -"engaol", -"engarb", -"engaud", -"engaze", -"engem", -"engild", -"engine", -"engird", -"engirt", -"englad", -"englobe", -"engloom", -"englory", -"englut", -"englyn", -"engobe", -"engold", -"engore", -"engorge", -"engrace", -"engraff", -"engraft", -"engrail", -"engrain", -"engram", -"engrasp", -"engrave", -"engreen", -"engross", -"enguard", -"engulf", -"enhalo", -"enhance", -"enhat", -"enhaunt", -"enheart", -"enhedge", -"enhelm", -"enherit", -"enhusk", -"eniac", -"enigma", -"enisle", -"enjail", -"enjamb", -"enjelly", -"enjewel", -"enjoin", -"enjoy", -"enjoyer", -"enkraal", -"enlace", -"enlard", -"enlarge", -"enleaf", -"enlief", -"enlife", -"enlight", -"enlink", -"enlist", -"enliven", -"enlock", -"enlodge", -"enmask", -"enmass", -"enmesh", -"enmist", -"enmity", -"enmoss", -"ennead", -"ennerve", -"enniche", -"ennoble", -"ennoic", -"ennomic", -"ennui", -"enocyte", -"enodal", -"enoil", -"enol", -"enolate", -"enolic", -"enolize", -"enomoty", -"enoplan", -"enorm", -"enough", -"enounce", -"enow", -"enplane", -"enquire", -"enquiry", -"enrace", -"enrage", -"enraged", -"enrange", -"enrank", -"enrapt", -"enray", -"enrib", -"enrich", -"enring", -"enrive", -"enrobe", -"enrober", -"enrol", -"enroll", -"enroot", -"enrough", -"enruin", -"enrut", -"ens", -"ensaint", -"ensand", -"ensate", -"enscene", -"ense", -"enseam", -"enseat", -"enseem", -"enserf", -"ensete", -"enshade", -"enshawl", -"enshell", -"ensign", -"ensile", -"ensky", -"enslave", -"ensmall", -"ensnare", -"ensnarl", -"ensnow", -"ensoul", -"enspell", -"enstamp", -"enstar", -"enstate", -"ensteel", -"enstool", -"enstore", -"ensuant", -"ensue", -"ensuer", -"ensure", -"ensurer", -"ensweep", -"entach", -"entad", -"entail", -"ental", -"entame", -"entasia", -"entasis", -"entelam", -"entente", -"enter", -"enteral", -"enterer", -"enteria", -"enteric", -"enteron", -"entheal", -"enthral", -"enthuse", -"entia", -"entice", -"enticer", -"entify", -"entire", -"entiris", -"entitle", -"entity", -"entoil", -"entomb", -"entomic", -"entone", -"entopic", -"entotic", -"entozoa", -"entrail", -"entrain", -"entrant", -"entrap", -"entreat", -"entree", -"entropy", -"entrust", -"entry", -"entwine", -"entwist", -"enure", -"enurny", -"envapor", -"envault", -"enveil", -"envelop", -"envenom", -"envied", -"envier", -"envious", -"environ", -"envoy", -"envy", -"envying", -"enwiden", -"enwind", -"enwisen", -"enwoman", -"enwomb", -"enwood", -"enwound", -"enwrap", -"enwrite", -"enzone", -"enzooty", -"enzym", -"enzyme", -"enzymic", -"eoan", -"eolith", -"eon", -"eonism", -"eophyte", -"eosate", -"eoside", -"eosin", -"eosinic", -"eozoon", -"epacme", -"epacrid", -"epact", -"epactal", -"epagoge", -"epanody", -"eparch", -"eparchy", -"epaule", -"epaulet", -"epaxial", -"epee", -"epeeist", -"epeiric", -"epeirid", -"epergne", -"epha", -"ephah", -"ephebe", -"ephebic", -"ephebos", -"ephebus", -"ephelis", -"ephetae", -"ephete", -"ephetic", -"ephod", -"ephor", -"ephoral", -"ephoric", -"ephorus", -"ephyra", -"epibole", -"epiboly", -"epic", -"epical", -"epicarp", -"epicede", -"epicele", -"epicene", -"epichil", -"epicism", -"epicist", -"epicly", -"epicure", -"epicyte", -"epidemy", -"epiderm", -"epidote", -"epigeal", -"epigean", -"epigeic", -"epigene", -"epigone", -"epigram", -"epigyne", -"epigyny", -"epihyal", -"epikeia", -"epilate", -"epilobe", -"epimer", -"epimere", -"epimyth", -"epinaos", -"epinine", -"epiotic", -"epipial", -"episode", -"epistle", -"epitaph", -"epitela", -"epithem", -"epithet", -"epitoke", -"epitome", -"epiural", -"epizoa", -"epizoal", -"epizoan", -"epizoic", -"epizoon", -"epoch", -"epocha", -"epochal", -"epode", -"epodic", -"eponym", -"eponymy", -"epopee", -"epopt", -"epoptes", -"epoptic", -"epos", -"epsilon", -"epulary", -"epulis", -"epulo", -"epuloid", -"epural", -"epurate", -"equable", -"equably", -"equal", -"equally", -"equant", -"equate", -"equator", -"equerry", -"equid", -"equine", -"equinia", -"equinox", -"equinus", -"equip", -"equiped", -"equison", -"equites", -"equity", -"equoid", -"er", -"era", -"erade", -"eral", -"eranist", -"erase", -"erased", -"eraser", -"erasion", -"erasure", -"erbia", -"erbium", -"erd", -"erdvark", -"ere", -"erect", -"erecter", -"erectly", -"erector", -"erelong", -"eremic", -"eremite", -"erenach", -"erenow", -"erepsin", -"erept", -"ereptic", -"erethic", -"erg", -"ergal", -"ergasia", -"ergates", -"ergodic", -"ergoism", -"ergon", -"ergot", -"ergoted", -"ergotic", -"ergotin", -"ergusia", -"eria", -"eric", -"ericad", -"erical", -"ericius", -"ericoid", -"erika", -"erikite", -"erineum", -"erinite", -"erinose", -"eristic", -"erizo", -"erlking", -"ermelin", -"ermine", -"ermined", -"erminee", -"ermines", -"erne", -"erode", -"eroded", -"erodent", -"erogeny", -"eros", -"erose", -"erosely", -"erosion", -"erosive", -"eroteme", -"erotic", -"erotica", -"erotism", -"err", -"errable", -"errancy", -"errand", -"errant", -"errata", -"erratic", -"erratum", -"errhine", -"erring", -"errite", -"error", -"ers", -"ersatz", -"erth", -"erthen", -"erthly", -"eruc", -"eruca", -"erucic", -"erucin", -"eruct", -"erudit", -"erudite", -"erugate", -"erupt", -"eryngo", -"es", -"esca", -"escalan", -"escalin", -"escalop", -"escape", -"escapee", -"escaper", -"escarp", -"eschar", -"eschara", -"escheat", -"eschew", -"escoba", -"escolar", -"escort", -"escribe", -"escrol", -"escrow", -"escudo", -"esculin", -"esere", -"eserine", -"esexual", -"eshin", -"esker", -"esne", -"esodic", -"esotery", -"espadon", -"esparto", -"espave", -"espial", -"espier", -"espinal", -"espino", -"esplees", -"espouse", -"espy", -"esquire", -"ess", -"essang", -"essay", -"essayer", -"essed", -"essence", -"essency", -"essling", -"essoin", -"estadal", -"estadio", -"estado", -"estamp", -"estate", -"esteem", -"ester", -"estevin", -"estival", -"estmark", -"estoc", -"estoile", -"estop", -"estrade", -"estray", -"estre", -"estreat", -"estrepe", -"estrin", -"estriol", -"estrone", -"estrous", -"estrual", -"estuary", -"estufa", -"estuous", -"estus", -"eta", -"etacism", -"etacist", -"etalon", -"etamine", -"etch", -"etcher", -"etching", -"eternal", -"etesian", -"ethal", -"ethanal", -"ethane", -"ethanol", -"ethel", -"ethene", -"ethenic", -"ethenol", -"ethenyl", -"ether", -"ethered", -"etheric", -"etherin", -"ethic", -"ethical", -"ethics", -"ethid", -"ethide", -"ethine", -"ethiops", -"ethmoid", -"ethnal", -"ethnic", -"ethnize", -"ethnos", -"ethos", -"ethoxyl", -"ethrog", -"ethyl", -"ethylic", -"ethylin", -"ethyne", -"ethynyl", -"etiolin", -"etna", -"ettle", -"etua", -"etude", -"etui", -"etym", -"etymic", -"etymon", -"etypic", -"eu", -"euaster", -"eucaine", -"euchre", -"euchred", -"euclase", -"eucone", -"euconic", -"eucrasy", -"eucrite", -"euge", -"eugenic", -"eugenol", -"eugeny", -"eulalia", -"eulogia", -"eulogic", -"eulogy", -"eumenid", -"eunicid", -"eunomy", -"eunuch", -"euonym", -"euonymy", -"euouae", -"eupad", -"eupathy", -"eupepsy", -"euphemy", -"euphon", -"euphone", -"euphony", -"euphory", -"euphroe", -"eupione", -"euploid", -"eupnea", -"eureka", -"euripus", -"eurite", -"eurobin", -"euryon", -"eusol", -"eustyle", -"eutaxic", -"eutaxy", -"eutexia", -"eutony", -"evacue", -"evacuee", -"evade", -"evader", -"evalue", -"evangel", -"evanish", -"evase", -"evasion", -"evasive", -"eve", -"evejar", -"evelong", -"even", -"evener", -"evening", -"evenly", -"evens", -"event", -"eveque", -"ever", -"evert", -"evertor", -"everwho", -"every", -"evestar", -"evetide", -"eveweed", -"evict", -"evictor", -"evident", -"evil", -"evilly", -"evince", -"evirate", -"evisite", -"evitate", -"evocate", -"evoe", -"evoke", -"evoker", -"evolute", -"evolve", -"evolver", -"evovae", -"evulse", -"evzone", -"ewder", -"ewe", -"ewer", -"ewerer", -"ewery", -"ewry", -"ex", -"exact", -"exacter", -"exactly", -"exactor", -"exalate", -"exalt", -"exalted", -"exalter", -"exam", -"examen", -"examine", -"example", -"exarate", -"exarch", -"exarchy", -"excamb", -"excave", -"exceed", -"excel", -"except", -"excerpt", -"excess", -"excide", -"exciple", -"excise", -"excisor", -"excite", -"excited", -"exciter", -"excitor", -"exclaim", -"exclave", -"exclude", -"excreta", -"excrete", -"excurse", -"excusal", -"excuse", -"excuser", -"excuss", -"excyst", -"exdie", -"exeat", -"execute", -"exedent", -"exedra", -"exegete", -"exempt", -"exequy", -"exergue", -"exert", -"exes", -"exeunt", -"exflect", -"exhale", -"exhaust", -"exhibit", -"exhort", -"exhume", -"exhumer", -"exigent", -"exile", -"exiler", -"exilian", -"exilic", -"exility", -"exist", -"exister", -"exit", -"exite", -"exition", -"exitus", -"exlex", -"exocarp", -"exocone", -"exode", -"exoderm", -"exodic", -"exodist", -"exodos", -"exodus", -"exody", -"exogamy", -"exogen", -"exogeny", -"exomion", -"exomis", -"exon", -"exoner", -"exopod", -"exordia", -"exormia", -"exosmic", -"exostra", -"exotic", -"exotism", -"expand", -"expanse", -"expect", -"expede", -"expel", -"expend", -"expense", -"expert", -"expiate", -"expire", -"expiree", -"expirer", -"expiry", -"explain", -"explant", -"explode", -"exploit", -"explore", -"expone", -"export", -"exposal", -"expose", -"exposed", -"exposer", -"exposit", -"expound", -"express", -"expugn", -"expulse", -"expunge", -"expurge", -"exradio", -"exscind", -"exsect", -"exsert", -"exship", -"exsurge", -"extant", -"extend", -"extense", -"extent", -"exter", -"extern", -"externe", -"extima", -"extinct", -"extine", -"extol", -"extoll", -"extort", -"extra", -"extract", -"extrait", -"extreme", -"extrude", -"extund", -"exudate", -"exude", -"exult", -"exultet", -"exuviae", -"exuvial", -"ey", -"eyah", -"eyalet", -"eyas", -"eye", -"eyeball", -"eyebalm", -"eyebar", -"eyebeam", -"eyebolt", -"eyebree", -"eyebrow", -"eyecup", -"eyed", -"eyedot", -"eyedrop", -"eyeflap", -"eyeful", -"eyehole", -"eyelash", -"eyeless", -"eyelet", -"eyelid", -"eyelike", -"eyeline", -"eyemark", -"eyen", -"eyepit", -"eyer", -"eyeroot", -"eyeseed", -"eyeshot", -"eyesome", -"eyesore", -"eyespot", -"eyewash", -"eyewear", -"eyewink", -"eyewort", -"eyey", -"eying", -"eyn", -"eyne", -"eyot", -"eyoty", -"eyra", -"eyre", -"eyrie", -"eyrir", -"ezba", -"f", -"fa", -"fabella", -"fabes", -"fable", -"fabled", -"fabler", -"fabliau", -"fabling", -"fabric", -"fabular", -"facadal", -"facade", -"face", -"faced", -"faceman", -"facer", -"facet", -"facete", -"faceted", -"facia", -"facial", -"faciend", -"facient", -"facies", -"facile", -"facing", -"fack", -"fackins", -"facks", -"fact", -"factful", -"faction", -"factish", -"factive", -"factor", -"factory", -"factrix", -"factual", -"factum", -"facture", -"facty", -"facula", -"facular", -"faculty", -"facund", -"facy", -"fad", -"fadable", -"faddish", -"faddism", -"faddist", -"faddle", -"faddy", -"fade", -"faded", -"fadedly", -"faden", -"fader", -"fadge", -"fading", -"fady", -"fae", -"faerie", -"faery", -"faff", -"faffle", -"faffy", -"fag", -"fagald", -"fage", -"fager", -"fagger", -"faggery", -"fagging", -"fagine", -"fagot", -"fagoter", -"fagoty", -"faham", -"fahlerz", -"fahlore", -"faience", -"fail", -"failing", -"faille", -"failure", -"fain", -"fainly", -"fains", -"faint", -"fainter", -"faintly", -"faints", -"fainty", -"faipule", -"fair", -"fairer", -"fairily", -"fairing", -"fairish", -"fairly", -"fairm", -"fairway", -"fairy", -"faith", -"faitour", -"fake", -"faker", -"fakery", -"fakir", -"faky", -"falbala", -"falcade", -"falcate", -"falcer", -"falces", -"falcial", -"falcon", -"falcula", -"faldage", -"faldfee", -"fall", -"fallace", -"fallacy", -"fallage", -"fallen", -"faller", -"falling", -"fallow", -"fallway", -"fally", -"falsary", -"false", -"falsely", -"falsen", -"falser", -"falsie", -"falsify", -"falsism", -"faltche", -"falter", -"falutin", -"falx", -"fam", -"famble", -"fame", -"fameful", -"familia", -"family", -"famine", -"famish", -"famous", -"famulus", -"fan", -"fana", -"fanal", -"fanam", -"fanatic", -"fanback", -"fancied", -"fancier", -"fancify", -"fancy", -"fand", -"fandom", -"fanega", -"fanfare", -"fanfoot", -"fang", -"fanged", -"fangle", -"fangled", -"fanglet", -"fangot", -"fangy", -"fanion", -"fanlike", -"fanman", -"fannel", -"fanner", -"fannier", -"fanning", -"fanon", -"fant", -"fantail", -"fantast", -"fantasy", -"fantod", -"fanweed", -"fanwise", -"fanwork", -"fanwort", -"faon", -"far", -"farad", -"faraday", -"faradic", -"faraway", -"farce", -"farcer", -"farcial", -"farcied", -"farcify", -"farcing", -"farcist", -"farcy", -"farde", -"fardel", -"fardh", -"fardo", -"fare", -"farer", -"farfara", -"farfel", -"fargood", -"farina", -"faring", -"farish", -"farl", -"farleu", -"farm", -"farmage", -"farmer", -"farmery", -"farming", -"farmost", -"farmy", -"farness", -"faro", -"farrago", -"farrand", -"farrier", -"farrow", -"farruca", -"farse", -"farseer", -"farset", -"farther", -"fasces", -"fascet", -"fascia", -"fascial", -"fascine", -"fascis", -"fascism", -"fascist", -"fash", -"fasher", -"fashery", -"fashion", -"fass", -"fast", -"fasten", -"faster", -"fasting", -"fastish", -"fastus", -"fat", -"fatal", -"fatally", -"fatbird", -"fate", -"fated", -"fateful", -"fathead", -"father", -"fathmur", -"fathom", -"fatidic", -"fatigue", -"fatiha", -"fatil", -"fatless", -"fatling", -"fatly", -"fatness", -"fatsia", -"fatten", -"fatter", -"fattily", -"fattish", -"fatty", -"fatuism", -"fatuity", -"fatuoid", -"fatuous", -"fatwood", -"faucal", -"fauces", -"faucet", -"faucial", -"faucre", -"faugh", -"fauld", -"fault", -"faulter", -"faulty", -"faun", -"faunal", -"faunish", -"faunist", -"faunule", -"fause", -"faust", -"fautor", -"fauve", -"favella", -"favilla", -"favism", -"favissa", -"favn", -"favor", -"favored", -"favorer", -"favose", -"favous", -"favus", -"fawn", -"fawner", -"fawnery", -"fawning", -"fawny", -"fay", -"fayles", -"faze", -"fazenda", -"fe", -"feague", -"feak", -"feal", -"fealty", -"fear", -"feared", -"fearer", -"fearful", -"feasor", -"feast", -"feasten", -"feaster", -"feat", -"feather", -"featly", -"featous", -"feature", -"featy", -"feaze", -"febrile", -"fecal", -"feces", -"feck", -"feckful", -"feckly", -"fecula", -"fecund", -"fed", -"feddan", -"federal", -"fee", -"feeable", -"feeble", -"feebly", -"feed", -"feedbin", -"feedbox", -"feeder", -"feeding", -"feedman", -"feedway", -"feedy", -"feel", -"feeler", -"feeless", -"feeling", -"feer", -"feere", -"feering", -"feetage", -"feeze", -"fegary", -"fei", -"feif", -"feigher", -"feign", -"feigned", -"feigner", -"feil", -"feint", -"feis", -"feist", -"feisty", -"felid", -"feline", -"fell", -"fellage", -"fellah", -"fellen", -"feller", -"fellic", -"felling", -"felloe", -"fellow", -"felly", -"feloid", -"felon", -"felonry", -"felony", -"fels", -"felsite", -"felt", -"felted", -"felter", -"felting", -"felty", -"felucca", -"felwort", -"female", -"feme", -"femic", -"feminal", -"feminie", -"feminin", -"femora", -"femoral", -"femur", -"fen", -"fenbank", -"fence", -"fencer", -"fenchyl", -"fencing", -"fend", -"fender", -"fendy", -"fenite", -"fenks", -"fenland", -"fenman", -"fennec", -"fennel", -"fennig", -"fennish", -"fenny", -"fensive", -"fent", -"fenter", -"feod", -"feodal", -"feodary", -"feoff", -"feoffee", -"feoffor", -"feower", -"feral", -"feralin", -"ferash", -"ferdwit", -"ferfet", -"feria", -"ferial", -"feridgi", -"ferie", -"ferine", -"ferity", -"ferk", -"ferling", -"ferly", -"fermail", -"ferme", -"ferment", -"fermery", -"fermila", -"fern", -"ferned", -"fernery", -"ferny", -"feroher", -"ferrado", -"ferrate", -"ferrean", -"ferret", -"ferrety", -"ferri", -"ferric", -"ferrier", -"ferrite", -"ferrous", -"ferrule", -"ferrum", -"ferry", -"fertile", -"feru", -"ferula", -"ferule", -"ferulic", -"fervent", -"fervid", -"fervor", -"fescue", -"fess", -"fessely", -"fest", -"festal", -"fester", -"festine", -"festive", -"festoon", -"festuca", -"fet", -"fetal", -"fetch", -"fetched", -"fetcher", -"fetial", -"fetid", -"fetidly", -"fetish", -"fetlock", -"fetlow", -"fetor", -"fetter", -"fettle", -"fettler", -"fetus", -"feu", -"feuage", -"feuar", -"feucht", -"feud", -"feudal", -"feudee", -"feudist", -"feued", -"feuille", -"fever", -"feveret", -"few", -"fewness", -"fewsome", -"fewter", -"fey", -"feyness", -"fez", -"fezzed", -"fezzy", -"fi", -"fiacre", -"fiance", -"fiancee", -"fiar", -"fiard", -"fiasco", -"fiat", -"fib", -"fibber", -"fibbery", -"fibdom", -"fiber", -"fibered", -"fibril", -"fibrin", -"fibrine", -"fibroid", -"fibroin", -"fibroma", -"fibrose", -"fibrous", -"fibry", -"fibster", -"fibula", -"fibulae", -"fibular", -"ficary", -"fice", -"ficelle", -"fiche", -"fichu", -"fickle", -"fickly", -"fico", -"ficoid", -"fictile", -"fiction", -"fictive", -"fid", -"fidalgo", -"fidate", -"fiddle", -"fiddler", -"fiddley", -"fide", -"fideism", -"fideist", -"fidfad", -"fidge", -"fidget", -"fidgety", -"fiducia", -"fie", -"fiefdom", -"field", -"fielded", -"fielder", -"fieldy", -"fiend", -"fiendly", -"fient", -"fierce", -"fiercen", -"fierily", -"fiery", -"fiesta", -"fife", -"fifer", -"fifie", -"fifish", -"fifo", -"fifteen", -"fifth", -"fifthly", -"fifty", -"fig", -"figaro", -"figbird", -"figent", -"figged", -"figgery", -"figging", -"figgle", -"figgy", -"fight", -"fighter", -"figless", -"figlike", -"figment", -"figural", -"figure", -"figured", -"figurer", -"figury", -"figworm", -"figwort", -"fike", -"fikie", -"filace", -"filacer", -"filao", -"filar", -"filaria", -"filasse", -"filate", -"filator", -"filbert", -"filch", -"filcher", -"file", -"filemot", -"filer", -"filet", -"filial", -"filiate", -"filibeg", -"filical", -"filicic", -"filicin", -"filiety", -"filing", -"filings", -"filippo", -"filite", -"fill", -"filled", -"filler", -"fillet", -"filleul", -"filling", -"fillip", -"fillock", -"filly", -"film", -"filmdom", -"filmet", -"filmic", -"filmily", -"filmish", -"filmist", -"filmize", -"filmy", -"filo", -"filose", -"fils", -"filter", -"filth", -"filthy", -"fimble", -"fimbria", -"fin", -"finable", -"finagle", -"final", -"finale", -"finally", -"finance", -"finback", -"finch", -"finched", -"find", -"findal", -"finder", -"finding", -"findjan", -"fine", -"fineish", -"finely", -"finer", -"finery", -"finesse", -"finetop", -"finfish", -"finfoot", -"fingent", -"finger", -"fingery", -"finial", -"finical", -"finick", -"finific", -"finify", -"finikin", -"fining", -"finis", -"finish", -"finite", -"finity", -"finjan", -"fink", -"finkel", -"finland", -"finless", -"finlet", -"finlike", -"finnac", -"finned", -"finner", -"finnip", -"finny", -"fiord", -"fiorded", -"fiorin", -"fiorite", -"fip", -"fipenny", -"fipple", -"fique", -"fir", -"firca", -"fire", -"firearm", -"firebox", -"fireboy", -"firebug", -"fired", -"firedog", -"firefly", -"firelit", -"fireman", -"firer", -"firetop", -"firing", -"firk", -"firker", -"firkin", -"firlot", -"firm", -"firman", -"firmer", -"firmly", -"firn", -"firring", -"firry", -"first", -"firstly", -"firth", -"fisc", -"fiscal", -"fise", -"fisetin", -"fish", -"fishbed", -"fished", -"fisher", -"fishery", -"fishet", -"fisheye", -"fishful", -"fishgig", -"fishify", -"fishily", -"fishing", -"fishlet", -"fishman", -"fishpot", -"fishway", -"fishy", -"fisnoga", -"fissate", -"fissile", -"fission", -"fissive", -"fissure", -"fissury", -"fist", -"fisted", -"fister", -"fistful", -"fistic", -"fistify", -"fisting", -"fistuca", -"fistula", -"fistule", -"fisty", -"fit", -"fitch", -"fitched", -"fitchee", -"fitcher", -"fitchet", -"fitchew", -"fitful", -"fitly", -"fitment", -"fitness", -"fitout", -"fitroot", -"fittage", -"fitted", -"fitten", -"fitter", -"fitters", -"fittily", -"fitting", -"fitty", -"fitweed", -"five", -"fivebar", -"fiver", -"fives", -"fix", -"fixable", -"fixage", -"fixate", -"fixatif", -"fixator", -"fixed", -"fixedly", -"fixer", -"fixing", -"fixity", -"fixture", -"fixure", -"fizgig", -"fizz", -"fizzer", -"fizzle", -"fizzy", -"fjeld", -"flabby", -"flabrum", -"flaccid", -"flack", -"flacked", -"flacker", -"flacket", -"flaff", -"flaffer", -"flag", -"flagger", -"flaggy", -"flaglet", -"flagman", -"flagon", -"flail", -"flair", -"flaith", -"flak", -"flakage", -"flake", -"flaker", -"flakily", -"flaky", -"flam", -"flamant", -"flamb", -"flame", -"flamed", -"flamen", -"flamer", -"flamfew", -"flaming", -"flamy", -"flan", -"flanch", -"flandan", -"flane", -"flange", -"flanger", -"flank", -"flanked", -"flanker", -"flanky", -"flannel", -"flanque", -"flap", -"flapper", -"flare", -"flaring", -"flary", -"flaser", -"flash", -"flasher", -"flashet", -"flashly", -"flashy", -"flask", -"flasker", -"flasket", -"flasque", -"flat", -"flatcap", -"flatcar", -"flatdom", -"flated", -"flathat", -"flatlet", -"flatly", -"flatman", -"flatten", -"flatter", -"flattie", -"flattop", -"flatus", -"flatway", -"flaught", -"flaunt", -"flaunty", -"flavedo", -"flavic", -"flavid", -"flavin", -"flavine", -"flavo", -"flavone", -"flavor", -"flavory", -"flavour", -"flaw", -"flawed", -"flawful", -"flawn", -"flawy", -"flax", -"flaxen", -"flaxman", -"flaxy", -"flay", -"flayer", -"flea", -"fleam", -"fleay", -"flebile", -"fleche", -"fleck", -"flecken", -"flecker", -"flecky", -"flector", -"fled", -"fledge", -"fledgy", -"flee", -"fleece", -"fleeced", -"fleecer", -"fleech", -"fleecy", -"fleer", -"fleerer", -"fleet", -"fleeter", -"fleetly", -"flemish", -"flench", -"flense", -"flenser", -"flerry", -"flesh", -"fleshed", -"fleshen", -"flesher", -"fleshly", -"fleshy", -"flet", -"fletch", -"flether", -"fleuret", -"fleury", -"flew", -"flewed", -"flewit", -"flews", -"flex", -"flexed", -"flexile", -"flexion", -"flexor", -"flexure", -"fley", -"flick", -"flicker", -"flicky", -"flidder", -"flier", -"fligger", -"flight", -"flighty", -"flimmer", -"flimp", -"flimsy", -"flinch", -"flinder", -"fling", -"flinger", -"flingy", -"flint", -"flinter", -"flinty", -"flioma", -"flip", -"flipe", -"flipper", -"flirt", -"flirter", -"flirty", -"flisk", -"flisky", -"flit", -"flitch", -"flite", -"fliting", -"flitter", -"flivver", -"flix", -"float", -"floater", -"floaty", -"flob", -"flobby", -"floc", -"floccus", -"flock", -"flocker", -"flocky", -"flocoon", -"flodge", -"floe", -"floey", -"flog", -"flogger", -"flokite", -"flong", -"flood", -"flooded", -"flooder", -"floody", -"floor", -"floorer", -"floozy", -"flop", -"flopper", -"floppy", -"flora", -"floral", -"floran", -"florate", -"floreal", -"florent", -"flores", -"floret", -"florid", -"florin", -"florist", -"floroon", -"florula", -"flory", -"flosh", -"floss", -"flosser", -"flossy", -"flot", -"flota", -"flotage", -"flotant", -"flotsam", -"flounce", -"flour", -"floury", -"flouse", -"flout", -"flouter", -"flow", -"flowage", -"flower", -"flowery", -"flowing", -"flown", -"flowoff", -"flu", -"fluate", -"fluavil", -"flub", -"flubdub", -"flucan", -"flue", -"flued", -"flueman", -"fluency", -"fluent", -"fluer", -"fluey", -"fluff", -"fluffer", -"fluffy", -"fluible", -"fluid", -"fluidal", -"fluidic", -"fluidly", -"fluke", -"fluked", -"flukily", -"fluking", -"fluky", -"flume", -"flummer", -"flummox", -"flump", -"flung", -"flunk", -"flunker", -"flunky", -"fluor", -"fluoran", -"fluoric", -"fluoryl", -"flurn", -"flurr", -"flurry", -"flush", -"flusher", -"flushy", -"flusk", -"flusker", -"fluster", -"flute", -"fluted", -"fluter", -"flutina", -"fluting", -"flutist", -"flutter", -"fluty", -"fluvial", -"flux", -"fluxer", -"fluxile", -"fluxion", -"fly", -"flyable", -"flyaway", -"flyback", -"flyball", -"flybane", -"flybelt", -"flyblow", -"flyboat", -"flyboy", -"flyer", -"flyflap", -"flying", -"flyleaf", -"flyless", -"flyman", -"flyness", -"flype", -"flytail", -"flytier", -"flytrap", -"flyway", -"flywort", -"foal", -"foaly", -"foam", -"foambow", -"foamer", -"foamily", -"foaming", -"foamy", -"fob", -"focal", -"focally", -"foci", -"focoids", -"focsle", -"focus", -"focuser", -"fod", -"fodda", -"fodder", -"foder", -"fodge", -"fodgel", -"fodient", -"foe", -"foehn", -"foeish", -"foeless", -"foelike", -"foeman", -"foeship", -"fog", -"fogbow", -"fogdog", -"fogdom", -"fogey", -"foggage", -"fogged", -"fogger", -"foggily", -"foggish", -"foggy", -"foghorn", -"fogle", -"fogless", -"fogman", -"fogo", -"fogon", -"fogou", -"fogram", -"fogus", -"fogy", -"fogydom", -"fogyish", -"fogyism", -"fohat", -"foible", -"foil", -"foiler", -"foiling", -"foining", -"foison", -"foist", -"foister", -"foisty", -"foiter", -"fold", -"foldage", -"folded", -"folden", -"folder", -"folding", -"foldure", -"foldy", -"fole", -"folia", -"foliage", -"folial", -"foliar", -"foliary", -"foliate", -"folie", -"folio", -"foliole", -"foliose", -"foliot", -"folious", -"folium", -"folk", -"folkmot", -"folksy", -"folkway", -"folky", -"folles", -"follis", -"follow", -"folly", -"foment", -"fomes", -"fomites", -"fondak", -"fondant", -"fondish", -"fondle", -"fondler", -"fondly", -"fondu", -"fondue", -"fonduk", -"fonly", -"fonnish", -"fono", -"fons", -"font", -"fontal", -"fonted", -"fontful", -"fontlet", -"foo", -"food", -"fooder", -"foodful", -"foody", -"fool", -"fooldom", -"foolery", -"fooless", -"fooling", -"foolish", -"fooner", -"fooster", -"foot", -"footage", -"footboy", -"footed", -"footer", -"footful", -"foothot", -"footing", -"footle", -"footler", -"footman", -"footpad", -"foots", -"footway", -"footy", -"foozle", -"foozler", -"fop", -"fopling", -"foppery", -"foppish", -"foppy", -"fopship", -"for", -"fora", -"forage", -"forager", -"foramen", -"forane", -"foray", -"forayer", -"forb", -"forbade", -"forbar", -"forbear", -"forbid", -"forbit", -"forbled", -"forblow", -"forbore", -"forbow", -"forby", -"force", -"forced", -"forceps", -"forcer", -"forche", -"forcing", -"ford", -"fordays", -"fording", -"fordo", -"fordone", -"fordy", -"fore", -"foreact", -"forearm", -"forebay", -"forecar", -"foreday", -"forefin", -"forefit", -"forego", -"foreign", -"forel", -"forelay", -"foreleg", -"foreman", -"forepad", -"forepaw", -"foreran", -"forerib", -"forerun", -"foresay", -"foresee", -"foreset", -"foresin", -"forest", -"foresty", -"foretop", -"foreuse", -"forever", -"forevow", -"forfar", -"forfare", -"forfars", -"forfeit", -"forfend", -"forge", -"forged", -"forger", -"forgery", -"forget", -"forgie", -"forging", -"forgive", -"forgo", -"forgoer", -"forgot", -"forgrow", -"forhoo", -"forhooy", -"forhow", -"forint", -"fork", -"forked", -"forker", -"forkful", -"forkman", -"forky", -"forleft", -"forlet", -"forlorn", -"form", -"formal", -"formant", -"format", -"formate", -"forme", -"formed", -"formee", -"formel", -"formene", -"former", -"formful", -"formic", -"formin", -"forming", -"formose", -"formula", -"formule", -"formy", -"formyl", -"fornent", -"fornix", -"forpet", -"forpine", -"forpit", -"forrad", -"forrard", -"forride", -"forrit", -"forrue", -"forsake", -"forset", -"forslow", -"fort", -"forte", -"forth", -"forthgo", -"forthy", -"forties", -"fortify", -"fortin", -"fortis", -"fortlet", -"fortune", -"forty", -"forum", -"forward", -"forwean", -"forwent", -"fosh", -"fosie", -"fossa", -"fossage", -"fossane", -"fosse", -"fossed", -"fossick", -"fossil", -"fossor", -"fossula", -"fossule", -"fostell", -"foster", -"fot", -"fotch", -"fother", -"fotmal", -"fotui", -"fou", -"foud", -"fouette", -"fougade", -"fought", -"foughty", -"foujdar", -"foul", -"foulage", -"foulard", -"fouler", -"fouling", -"foulish", -"foully", -"foumart", -"foun", -"found", -"founder", -"foundry", -"fount", -"four", -"fourble", -"fourche", -"fourer", -"fourre", -"fourth", -"foussa", -"foute", -"fouter", -"fouth", -"fovea", -"foveal", -"foveate", -"foveola", -"foveole", -"fow", -"fowk", -"fowl", -"fowler", -"fowlery", -"fowling", -"fox", -"foxbane", -"foxchop", -"foxer", -"foxery", -"foxfeet", -"foxfish", -"foxhole", -"foxily", -"foxing", -"foxish", -"foxlike", -"foxship", -"foxskin", -"foxtail", -"foxwood", -"foxy", -"foy", -"foyaite", -"foyboat", -"foyer", -"fozy", -"fra", -"frab", -"frabbit", -"frabous", -"fracas", -"frache", -"frack", -"fracted", -"frae", -"fraghan", -"fragile", -"fraid", -"fraik", -"frail", -"frailly", -"frailty", -"fraise", -"fraiser", -"frame", -"framea", -"framed", -"framer", -"framing", -"frammit", -"franc", -"franco", -"frank", -"franker", -"frankly", -"frantic", -"franzy", -"frap", -"frappe", -"frasco", -"frase", -"frasier", -"frass", -"frat", -"fratch", -"fratchy", -"frater", -"fratery", -"fratry", -"fraud", -"fraught", -"frawn", -"fraxin", -"fray", -"frayed", -"fraying", -"frayn", -"fraze", -"frazer", -"frazil", -"frazzle", -"freak", -"freaky", -"fream", -"freath", -"freck", -"frecken", -"frecket", -"freckle", -"freckly", -"free", -"freed", -"freedom", -"freeing", -"freeish", -"freely", -"freeman", -"freer", -"freet", -"freety", -"freeway", -"freeze", -"freezer", -"freight", -"freir", -"freit", -"freity", -"fremd", -"fremdly", -"frenal", -"frenate", -"frenum", -"frenzy", -"fresco", -"fresh", -"freshen", -"freshet", -"freshly", -"fresnel", -"fresno", -"fret", -"fretful", -"frett", -"frette", -"fretted", -"fretter", -"fretty", -"fretum", -"friable", -"friand", -"friar", -"friarly", -"friary", -"frib", -"fribble", -"fribby", -"fried", -"friend", -"frier", -"frieze", -"friezer", -"friezy", -"frig", -"frigate", -"friggle", -"fright", -"frighty", -"frigid", -"frijol", -"frike", -"frill", -"frilled", -"friller", -"frilly", -"frim", -"fringe", -"fringed", -"fringy", -"frisca", -"frisk", -"frisker", -"frisket", -"frisky", -"frison", -"frist", -"frisure", -"frit", -"frith", -"fritt", -"fritter", -"frivol", -"frixion", -"friz", -"frize", -"frizer", -"frizz", -"frizzer", -"frizzle", -"frizzly", -"frizzy", -"fro", -"frock", -"froe", -"frog", -"frogbit", -"frogeye", -"frogged", -"froggy", -"frogleg", -"froglet", -"frogman", -"froise", -"frolic", -"from", -"frond", -"fronded", -"front", -"frontad", -"frontal", -"fronted", -"fronter", -"froom", -"frore", -"frory", -"frosh", -"frost", -"frosted", -"froster", -"frosty", -"frot", -"froth", -"frother", -"frothy", -"frotton", -"frough", -"froughy", -"frounce", -"frow", -"froward", -"frower", -"frowl", -"frown", -"frowner", -"frowny", -"frowst", -"frowsty", -"frowy", -"frowze", -"frowzly", -"frowzy", -"froze", -"frozen", -"fructed", -"frugal", -"fruggan", -"fruit", -"fruited", -"fruiter", -"fruity", -"frump", -"frumple", -"frumpy", -"frush", -"frustum", -"frutify", -"fry", -"fryer", -"fu", -"fub", -"fubby", -"fubsy", -"fucate", -"fuchsin", -"fuci", -"fucoid", -"fucosan", -"fucose", -"fucous", -"fucus", -"fud", -"fuddle", -"fuddler", -"fuder", -"fudge", -"fudger", -"fudgy", -"fuel", -"fueler", -"fuerte", -"fuff", -"fuffy", -"fugal", -"fugally", -"fuggy", -"fugient", -"fugle", -"fugler", -"fugu", -"fugue", -"fuguist", -"fuidhir", -"fuji", -"fulcral", -"fulcrum", -"fulfill", -"fulgent", -"fulgid", -"fulgide", -"fulgor", -"fulham", -"fulk", -"full", -"fullam", -"fuller", -"fullery", -"fulling", -"fullish", -"fullom", -"fully", -"fulmar", -"fulmine", -"fulsome", -"fulth", -"fulvene", -"fulvid", -"fulvous", -"fulwa", -"fulyie", -"fulzie", -"fum", -"fumado", -"fumage", -"fumaric", -"fumaryl", -"fumble", -"fumbler", -"fume", -"fumer", -"fumet", -"fumette", -"fumily", -"fuming", -"fumose", -"fumous", -"fumy", -"fun", -"fund", -"fundal", -"funded", -"funder", -"fundi", -"fundic", -"funds", -"fundus", -"funeral", -"funest", -"fungal", -"fungate", -"fungi", -"fungian", -"fungic", -"fungin", -"fungo", -"fungoid", -"fungose", -"fungous", -"fungus", -"fungusy", -"funicle", -"funis", -"funk", -"funker", -"funky", -"funnel", -"funnily", -"funny", -"funori", -"funt", -"fur", -"fural", -"furan", -"furazan", -"furbish", -"furca", -"furcal", -"furcate", -"furcula", -"furdel", -"furfur", -"furiant", -"furied", -"furify", -"furil", -"furilic", -"furiosa", -"furioso", -"furious", -"furison", -"furl", -"furler", -"furless", -"furlong", -"furnace", -"furnage", -"furner", -"furnish", -"furoic", -"furoid", -"furoin", -"furole", -"furor", -"furore", -"furphy", -"furred", -"furrier", -"furrily", -"furring", -"furrow", -"furrowy", -"furry", -"further", -"furtive", -"fury", -"furyl", -"furze", -"furzed", -"furzery", -"furzy", -"fusain", -"fusate", -"fusc", -"fuscin", -"fuscous", -"fuse", -"fused", -"fusee", -"fusht", -"fusible", -"fusibly", -"fusil", -"fusilly", -"fusion", -"fusoid", -"fuss", -"fusser", -"fussify", -"fussily", -"fussock", -"fussy", -"fust", -"fustee", -"fustet", -"fustian", -"fustic", -"fustily", -"fustin", -"fustle", -"fusty", -"fusuma", -"fusure", -"fut", -"futchel", -"fute", -"futhorc", -"futile", -"futtock", -"futural", -"future", -"futuric", -"futwa", -"fuye", -"fuze", -"fuzz", -"fuzzily", -"fuzzy", -"fyke", -"fylfot", -"fyrd", -"g", -"ga", -"gab", -"gabbard", -"gabber", -"gabble", -"gabbler", -"gabbro", -"gabby", -"gabelle", -"gabgab", -"gabi", -"gabion", -"gable", -"gablet", -"gablock", -"gaby", -"gad", -"gadbee", -"gadbush", -"gadded", -"gadder", -"gaddi", -"gadding", -"gaddish", -"gade", -"gadfly", -"gadge", -"gadger", -"gadget", -"gadid", -"gadling", -"gadman", -"gadoid", -"gadroon", -"gadsman", -"gaduin", -"gadwall", -"gaen", -"gaet", -"gaff", -"gaffe", -"gaffer", -"gaffle", -"gag", -"gagate", -"gage", -"gagee", -"gageite", -"gager", -"gagger", -"gaggery", -"gaggle", -"gaggler", -"gagman", -"gagor", -"gagroot", -"gahnite", -"gaiassa", -"gaiety", -"gaily", -"gain", -"gainage", -"gaine", -"gainer", -"gainful", -"gaining", -"gainly", -"gains", -"gainsay", -"gainset", -"gainst", -"gair", -"gait", -"gaited", -"gaiter", -"gaiting", -"gaize", -"gaj", -"gal", -"gala", -"galah", -"galanas", -"galanga", -"galant", -"galany", -"galatea", -"galaxy", -"galban", -"gale", -"galea", -"galeage", -"galeate", -"galee", -"galeeny", -"galeid", -"galena", -"galenic", -"galeoid", -"galera", -"galerum", -"galerus", -"galet", -"galey", -"galgal", -"gali", -"galilee", -"galiot", -"galipot", -"gall", -"galla", -"gallah", -"gallant", -"gallate", -"galled", -"gallein", -"galleon", -"galler", -"gallery", -"gallet", -"galley", -"gallfly", -"gallic", -"galline", -"galling", -"gallium", -"gallnut", -"gallon", -"galloon", -"gallop", -"gallous", -"gallows", -"gally", -"galoot", -"galop", -"galore", -"galosh", -"galp", -"galt", -"galumph", -"galuth", -"galyac", -"galyak", -"gam", -"gamahe", -"gamasid", -"gamb", -"gamba", -"gambade", -"gambado", -"gambang", -"gambeer", -"gambet", -"gambia", -"gambier", -"gambist", -"gambit", -"gamble", -"gambler", -"gamboge", -"gambol", -"gambrel", -"game", -"gamebag", -"gameful", -"gamely", -"gamene", -"gametal", -"gamete", -"gametic", -"gamic", -"gamily", -"gamin", -"gaming", -"gamma", -"gammer", -"gammick", -"gammock", -"gammon", -"gammy", -"gamont", -"gamori", -"gamp", -"gamut", -"gamy", -"gan", -"ganam", -"ganch", -"gander", -"gandul", -"gandum", -"gane", -"ganef", -"gang", -"ganga", -"gangan", -"gangava", -"gangdom", -"gange", -"ganger", -"ganging", -"gangism", -"ganglia", -"gangly", -"gangman", -"gangrel", -"gangue", -"gangway", -"ganja", -"ganner", -"gannet", -"ganoid", -"ganoin", -"ganosis", -"gansel", -"gansey", -"gansy", -"gant", -"ganta", -"gantang", -"gantlet", -"ganton", -"gantry", -"gantsl", -"ganza", -"ganzie", -"gaol", -"gaoler", -"gap", -"gapa", -"gape", -"gaper", -"gapes", -"gaping", -"gapo", -"gappy", -"gapy", -"gar", -"gara", -"garad", -"garage", -"garance", -"garava", -"garawi", -"garb", -"garbage", -"garbel", -"garbell", -"garbill", -"garble", -"garbler", -"garboil", -"garbure", -"garce", -"gardant", -"gardeen", -"garden", -"gardeny", -"gardy", -"gare", -"gareh", -"garetta", -"garfish", -"garget", -"gargety", -"gargle", -"gargol", -"garial", -"gariba", -"garish", -"garland", -"garle", -"garlic", -"garment", -"garn", -"garnel", -"garner", -"garnet", -"garnets", -"garnett", -"garnetz", -"garnice", -"garniec", -"garnish", -"garoo", -"garrafa", -"garran", -"garret", -"garrot", -"garrote", -"garrupa", -"garse", -"garsil", -"garston", -"garten", -"garter", -"garth", -"garum", -"garvey", -"garvock", -"gas", -"gasbag", -"gaseity", -"gaseous", -"gash", -"gashes", -"gashful", -"gashly", -"gashy", -"gasify", -"gasket", -"gaskin", -"gasking", -"gaskins", -"gasless", -"gaslit", -"gaslock", -"gasman", -"gasp", -"gasper", -"gasping", -"gaspy", -"gasser", -"gassing", -"gassy", -"gast", -"gaster", -"gastral", -"gastric", -"gastrin", -"gat", -"gata", -"gatch", -"gate", -"gateado", -"gateage", -"gated", -"gateman", -"gater", -"gateway", -"gather", -"gating", -"gator", -"gatter", -"gau", -"gaub", -"gauby", -"gauche", -"gaud", -"gaudery", -"gaudful", -"gaudily", -"gaudy", -"gaufer", -"gauffer", -"gauffre", -"gaufre", -"gauge", -"gauger", -"gauging", -"gaulin", -"gault", -"gaulter", -"gaum", -"gaumish", -"gaumy", -"gaun", -"gaunt", -"gaunted", -"gauntly", -"gauntry", -"gaunty", -"gaup", -"gaupus", -"gaur", -"gaus", -"gauss", -"gauster", -"gaut", -"gauze", -"gauzily", -"gauzy", -"gavall", -"gave", -"gavel", -"gaveler", -"gavial", -"gavotte", -"gavyuti", -"gaw", -"gawby", -"gawcie", -"gawk", -"gawkily", -"gawkish", -"gawky", -"gawm", -"gawn", -"gawney", -"gawsie", -"gay", -"gayal", -"gayatri", -"gaybine", -"gaycat", -"gayish", -"gayment", -"gayness", -"gaysome", -"gayyou", -"gaz", -"gazabo", -"gaze", -"gazebo", -"gazee", -"gazel", -"gazelle", -"gazer", -"gazette", -"gazi", -"gazing", -"gazon", -"gazy", -"ge", -"geal", -"gean", -"gear", -"gearbox", -"geared", -"gearing", -"gearman", -"gearset", -"gease", -"geason", -"geat", -"gebang", -"gebanga", -"gebbie", -"gebur", -"geck", -"gecko", -"geckoid", -"ged", -"gedackt", -"gedder", -"gedeckt", -"gedrite", -"gee", -"geebong", -"geebung", -"geejee", -"geek", -"geelbec", -"geerah", -"geest", -"geet", -"geezer", -"gegg", -"geggee", -"gegger", -"geggery", -"gein", -"geira", -"geisha", -"geison", -"geitjie", -"gel", -"gelable", -"gelada", -"gelatin", -"geld", -"geldant", -"gelder", -"gelding", -"gelid", -"gelidly", -"gelilah", -"gell", -"gelly", -"gelong", -"gelose", -"gelosin", -"gelt", -"gem", -"gemauve", -"gemel", -"gemeled", -"gemless", -"gemlike", -"gemma", -"gemmae", -"gemmate", -"gemmer", -"gemmily", -"gemmoid", -"gemmula", -"gemmule", -"gemmy", -"gemot", -"gemsbok", -"gemul", -"gemuti", -"gemwork", -"gen", -"gena", -"genal", -"genapp", -"genarch", -"gender", -"gene", -"genear", -"geneat", -"geneki", -"genep", -"genera", -"general", -"generic", -"genesic", -"genesis", -"genet", -"genetic", -"geneva", -"genial", -"genian", -"genic", -"genie", -"genii", -"genin", -"genion", -"genip", -"genipa", -"genipap", -"genista", -"genital", -"genitor", -"genius", -"genizah", -"genoese", -"genom", -"genome", -"genomic", -"genos", -"genre", -"genro", -"gens", -"genson", -"gent", -"genteel", -"gentes", -"gentian", -"gentile", -"gentle", -"gently", -"gentman", -"gentry", -"genty", -"genu", -"genua", -"genual", -"genuine", -"genus", -"genys", -"geo", -"geobios", -"geodal", -"geode", -"geodesy", -"geodete", -"geodic", -"geodist", -"geoduck", -"geoform", -"geogeny", -"geogony", -"geoid", -"geoidal", -"geology", -"geomaly", -"geomant", -"geomyid", -"geonoma", -"geopony", -"georama", -"georgic", -"geosid", -"geoside", -"geotaxy", -"geotic", -"geoty", -"ger", -"gerah", -"geranic", -"geranyl", -"gerate", -"gerated", -"geratic", -"geraty", -"gerb", -"gerbe", -"gerbil", -"gercrow", -"gerefa", -"gerenda", -"gerent", -"gerenuk", -"gerim", -"gerip", -"germ", -"germal", -"german", -"germane", -"germen", -"germin", -"germina", -"germing", -"germon", -"germule", -"germy", -"gernitz", -"geront", -"geronto", -"gers", -"gersum", -"gerund", -"gerusia", -"gervao", -"gesith", -"gesning", -"gesso", -"gest", -"gestant", -"gestate", -"geste", -"gested", -"gesten", -"gestic", -"gestion", -"gesture", -"get", -"geta", -"getah", -"getaway", -"gether", -"getling", -"getter", -"getting", -"getup", -"geum", -"gewgaw", -"gewgawy", -"gey", -"geyan", -"geyser", -"gez", -"ghafir", -"ghaist", -"ghalva", -"gharial", -"gharnao", -"gharry", -"ghastly", -"ghat", -"ghatti", -"ghatwal", -"ghazi", -"ghazism", -"ghebeta", -"ghee", -"gheleem", -"gherkin", -"ghetti", -"ghetto", -"ghizite", -"ghoom", -"ghost", -"ghoster", -"ghostly", -"ghosty", -"ghoul", -"ghrush", -"ghurry", -"giant", -"giantly", -"giantry", -"giardia", -"giarra", -"giarre", -"gib", -"gibaro", -"gibbals", -"gibbed", -"gibber", -"gibbet", -"gibbles", -"gibbon", -"gibbose", -"gibbous", -"gibbus", -"gibby", -"gibe", -"gibel", -"giber", -"gibing", -"gibleh", -"giblet", -"giblets", -"gibus", -"gid", -"giddap", -"giddea", -"giddify", -"giddily", -"giddy", -"gidgee", -"gie", -"gied", -"gien", -"gif", -"gift", -"gifted", -"giftie", -"gig", -"gigback", -"gigeria", -"gigful", -"gigger", -"giggish", -"giggit", -"giggle", -"giggler", -"giggly", -"giglet", -"giglot", -"gigman", -"gignate", -"gigolo", -"gigot", -"gigsman", -"gigster", -"gigtree", -"gigunu", -"gilbert", -"gild", -"gilded", -"gilden", -"gilder", -"gilding", -"gilguy", -"gilia", -"gilim", -"gill", -"gilled", -"giller", -"gillie", -"gilling", -"gilly", -"gilo", -"gilpy", -"gilse", -"gilt", -"giltcup", -"gim", -"gimbal", -"gimble", -"gimel", -"gimlet", -"gimlety", -"gimmal", -"gimmer", -"gimmick", -"gimp", -"gimped", -"gimper", -"gimping", -"gin", -"ging", -"ginger", -"gingery", -"gingham", -"gingili", -"gingiva", -"gink", -"ginkgo", -"ginned", -"ginner", -"ginners", -"ginnery", -"ginney", -"ginning", -"ginnle", -"ginny", -"ginseng", -"ginward", -"gio", -"gip", -"gipon", -"gipper", -"gipser", -"gipsire", -"giraffe", -"girasol", -"girba", -"gird", -"girder", -"girding", -"girdle", -"girdler", -"girl", -"girleen", -"girlery", -"girlie", -"girling", -"girlish", -"girlism", -"girly", -"girn", -"girny", -"giro", -"girr", -"girse", -"girsh", -"girsle", -"girt", -"girth", -"gisarme", -"gish", -"gisla", -"gisler", -"gist", -"git", -"gitalin", -"gith", -"gitonin", -"gitoxin", -"gittern", -"gittith", -"give", -"given", -"giver", -"givey", -"giving", -"gizz", -"gizzard", -"gizzen", -"gizzern", -"glace", -"glaceed", -"glacial", -"glacier", -"glacis", -"glack", -"glad", -"gladden", -"gladdon", -"gladdy", -"glade", -"gladeye", -"gladful", -"gladify", -"gladii", -"gladius", -"gladly", -"glady", -"glaga", -"glaieul", -"glaik", -"glaiket", -"glair", -"glairy", -"glaive", -"glaived", -"glaked", -"glaky", -"glam", -"glamour", -"glance", -"glancer", -"gland", -"glandes", -"glans", -"glar", -"glare", -"glarily", -"glaring", -"glarry", -"glary", -"glashan", -"glass", -"glassen", -"glasser", -"glasses", -"glassie", -"glassy", -"glaucin", -"glaum", -"glaur", -"glaury", -"glaver", -"glaze", -"glazed", -"glazen", -"glazer", -"glazier", -"glazily", -"glazing", -"glazy", -"gleam", -"gleamy", -"glean", -"gleaner", -"gleary", -"gleba", -"glebal", -"glebe", -"glebous", -"glede", -"gledy", -"glee", -"gleed", -"gleeful", -"gleek", -"gleeman", -"gleet", -"gleety", -"gleg", -"glegly", -"glen", -"glenoid", -"glent", -"gleyde", -"glia", -"gliadin", -"glial", -"glib", -"glibly", -"glidder", -"glide", -"glider", -"gliding", -"gliff", -"glime", -"glimmer", -"glimpse", -"glink", -"glint", -"glioma", -"gliosa", -"gliosis", -"glirine", -"glisk", -"glisky", -"glisten", -"glister", -"glitter", -"gloam", -"gloat", -"gloater", -"global", -"globate", -"globe", -"globed", -"globin", -"globoid", -"globose", -"globous", -"globule", -"globy", -"glochid", -"glochis", -"gloea", -"gloeal", -"glom", -"glome", -"glommox", -"glomus", -"glonoin", -"gloom", -"gloomth", -"gloomy", -"glop", -"gloppen", -"glor", -"glore", -"glorify", -"glory", -"gloss", -"glossa", -"glossal", -"glossed", -"glosser", -"glossic", -"glossy", -"glost", -"glottal", -"glottic", -"glottid", -"glottis", -"glout", -"glove", -"glover", -"glovey", -"gloving", -"glow", -"glower", -"glowfly", -"glowing", -"gloy", -"gloze", -"glozing", -"glub", -"glucase", -"glucid", -"glucide", -"glucina", -"glucine", -"gluck", -"glucose", -"glue", -"glued", -"gluepot", -"gluer", -"gluey", -"glug", -"gluish", -"glum", -"gluma", -"glumal", -"glume", -"glumly", -"glummy", -"glumose", -"glump", -"glumpy", -"glunch", -"glusid", -"gluside", -"glut", -"glutch", -"gluteal", -"gluten", -"gluteus", -"glutin", -"glutoid", -"glutose", -"glutter", -"glutton", -"glycid", -"glycide", -"glycine", -"glycol", -"glycose", -"glycyl", -"glyoxal", -"glyoxim", -"glyoxyl", -"glyph", -"glyphic", -"glyptic", -"glyster", -"gnabble", -"gnar", -"gnarl", -"gnarled", -"gnarly", -"gnash", -"gnat", -"gnathal", -"gnathic", -"gnatter", -"gnatty", -"gnaw", -"gnawer", -"gnawing", -"gnawn", -"gneiss", -"gneissy", -"gnome", -"gnomed", -"gnomic", -"gnomide", -"gnomish", -"gnomist", -"gnomon", -"gnosis", -"gnostic", -"gnu", -"go", -"goa", -"goad", -"goaf", -"goal", -"goalage", -"goalee", -"goalie", -"goanna", -"goat", -"goatee", -"goateed", -"goatish", -"goatly", -"goaty", -"goave", -"gob", -"goback", -"goban", -"gobang", -"gobbe", -"gobber", -"gobbet", -"gobbin", -"gobbing", -"gobble", -"gobbler", -"gobby", -"gobelin", -"gobi", -"gobiid", -"gobioid", -"goblet", -"goblin", -"gobline", -"gobo", -"gobony", -"goburra", -"goby", -"gocart", -"god", -"goddard", -"godded", -"goddess", -"goddize", -"gode", -"godet", -"godhead", -"godhood", -"godkin", -"godless", -"godlet", -"godlike", -"godlily", -"godling", -"godly", -"godown", -"godpapa", -"godsend", -"godship", -"godson", -"godwit", -"goeduck", -"goel", -"goelism", -"goer", -"goes", -"goetia", -"goetic", -"goety", -"goff", -"goffer", -"goffle", -"gog", -"gogga", -"goggan", -"goggle", -"goggled", -"goggler", -"goggly", -"goglet", -"gogo", -"goi", -"going", -"goitcho", -"goiter", -"goitral", -"gol", -"gola", -"golach", -"goladar", -"gold", -"goldbug", -"goldcup", -"golden", -"golder", -"goldie", -"goldin", -"goldish", -"goldtit", -"goldy", -"golee", -"golem", -"golf", -"golfdom", -"golfer", -"goli", -"goliard", -"goliath", -"golland", -"gollar", -"golly", -"goloe", -"golpe", -"gomari", -"gomart", -"gomavel", -"gombay", -"gombeen", -"gomer", -"gomeral", -"gomlah", -"gomuti", -"gon", -"gonad", -"gonadal", -"gonadic", -"gonagra", -"gonakie", -"gonal", -"gonapod", -"gondang", -"gondite", -"gondola", -"gone", -"goner", -"gong", -"gongman", -"gonia", -"goniac", -"gonial", -"goniale", -"gonid", -"gonidia", -"gonidic", -"gonimic", -"gonion", -"gonitis", -"gonium", -"gonne", -"gony", -"gonys", -"goo", -"goober", -"good", -"gooding", -"goodish", -"goodly", -"goodman", -"goods", -"goody", -"goof", -"goofer", -"goofily", -"goofy", -"googly", -"googol", -"googul", -"gook", -"gool", -"goolah", -"gools", -"gooma", -"goon", -"goondie", -"goonie", -"goose", -"goosery", -"goosish", -"goosy", -"gopher", -"gopura", -"gor", -"gora", -"goracco", -"goral", -"goran", -"gorb", -"gorbal", -"gorbet", -"gorble", -"gorce", -"gorcock", -"gorcrow", -"gore", -"gorer", -"gorevan", -"gorfly", -"gorge", -"gorged", -"gorger", -"gorget", -"gorglin", -"gorhen", -"goric", -"gorilla", -"gorily", -"goring", -"gorlin", -"gorlois", -"gormaw", -"gormed", -"gorra", -"gorraf", -"gorry", -"gorse", -"gorsedd", -"gorsy", -"gory", -"gos", -"gosain", -"goschen", -"gosh", -"goshawk", -"goslet", -"gosling", -"gosmore", -"gospel", -"gosport", -"gossan", -"gossard", -"gossip", -"gossipy", -"gossoon", -"gossy", -"got", -"gotch", -"gote", -"gothite", -"gotra", -"gotraja", -"gotten", -"gouaree", -"gouge", -"gouger", -"goujon", -"goulash", -"goumi", -"goup", -"gourami", -"gourd", -"gourde", -"gourdy", -"gourmet", -"gousty", -"gout", -"goutify", -"goutily", -"goutish", -"goutte", -"gouty", -"gove", -"govern", -"gowan", -"gowdnie", -"gowf", -"gowfer", -"gowk", -"gowked", -"gowkit", -"gowl", -"gown", -"gownlet", -"gowpen", -"goy", -"goyim", -"goyin", -"goyle", -"gozell", -"gozzard", -"gra", -"grab", -"grabber", -"grabble", -"graben", -"grace", -"gracer", -"gracile", -"grackle", -"grad", -"gradal", -"gradate", -"graddan", -"grade", -"graded", -"gradely", -"grader", -"gradin", -"gradine", -"grading", -"gradual", -"gradus", -"graff", -"graffer", -"graft", -"grafted", -"grafter", -"graham", -"grail", -"grailer", -"grain", -"grained", -"grainer", -"grainy", -"graip", -"graisse", -"graith", -"grallic", -"gram", -"grama", -"grame", -"grammar", -"gramme", -"gramp", -"grampa", -"grampus", -"granada", -"granage", -"granary", -"granate", -"granch", -"grand", -"grandam", -"grandee", -"grandly", -"grandma", -"grandpa", -"grane", -"grange", -"granger", -"granite", -"grank", -"grannom", -"granny", -"grano", -"granose", -"grant", -"grantee", -"granter", -"grantor", -"granula", -"granule", -"granza", -"grape", -"graped", -"grapery", -"graph", -"graphic", -"graphy", -"graping", -"grapnel", -"grappa", -"grapple", -"grapy", -"grasp", -"grasper", -"grass", -"grassed", -"grasser", -"grasset", -"grassy", -"grat", -"grate", -"grater", -"grather", -"gratify", -"grating", -"gratis", -"gratten", -"graupel", -"grave", -"graved", -"gravel", -"gravely", -"graven", -"graver", -"gravic", -"gravid", -"graving", -"gravity", -"gravure", -"gravy", -"grawls", -"gray", -"grayfly", -"grayish", -"graylag", -"grayly", -"graze", -"grazer", -"grazier", -"grazing", -"grease", -"greaser", -"greasy", -"great", -"greaten", -"greater", -"greatly", -"greave", -"greaved", -"greaves", -"grebe", -"grece", -"gree", -"greed", -"greedy", -"green", -"greener", -"greeney", -"greenly", -"greenth", -"greenuk", -"greeny", -"greet", -"greeter", -"gregal", -"gregale", -"grege", -"greggle", -"grego", -"greige", -"grein", -"greisen", -"gremial", -"gremlin", -"grenade", -"greund", -"grew", -"grey", -"greyly", -"gribble", -"grice", -"grid", -"griddle", -"gride", -"griece", -"grieced", -"grief", -"grieve", -"grieved", -"griever", -"griff", -"griffe", -"griffin", -"griffon", -"grift", -"grifter", -"grig", -"grignet", -"grigri", -"grike", -"grill", -"grille", -"grilled", -"griller", -"grilse", -"grim", -"grimace", -"grime", -"grimful", -"grimily", -"grimly", -"grimme", -"grimp", -"grimy", -"grin", -"grinch", -"grind", -"grinder", -"grindle", -"gringo", -"grinner", -"grinny", -"grip", -"gripe", -"griper", -"griping", -"gripman", -"grippal", -"grippe", -"gripper", -"gripple", -"grippy", -"gripy", -"gris", -"grisard", -"griskin", -"grisly", -"grison", -"grist", -"grister", -"gristle", -"gristly", -"gristy", -"grit", -"grith", -"grits", -"gritten", -"gritter", -"grittle", -"gritty", -"grivet", -"grivna", -"grizzle", -"grizzly", -"groan", -"groaner", -"groat", -"groats", -"grobian", -"grocer", -"grocery", -"groff", -"grog", -"groggy", -"grogram", -"groin", -"groined", -"grommet", -"groom", -"groomer", -"groomy", -"groop", -"groose", -"groot", -"grooty", -"groove", -"groover", -"groovy", -"grope", -"groper", -"groping", -"gropple", -"gros", -"groser", -"groset", -"gross", -"grossen", -"grosser", -"grossly", -"grosso", -"grosz", -"groszy", -"grot", -"grotto", -"grouch", -"grouchy", -"grouf", -"grough", -"ground", -"grounds", -"groundy", -"group", -"grouped", -"grouper", -"grouse", -"grouser", -"grousy", -"grout", -"grouter", -"grouts", -"grouty", -"grouze", -"grove", -"groved", -"grovel", -"grovy", -"grow", -"growan", -"growed", -"grower", -"growing", -"growl", -"growler", -"growly", -"grown", -"grownup", -"growse", -"growth", -"growthy", -"grozart", -"grozet", -"grr", -"grub", -"grubbed", -"grubber", -"grubby", -"grubs", -"grudge", -"grudger", -"grue", -"gruel", -"grueler", -"gruelly", -"gruff", -"gruffly", -"gruffs", -"gruffy", -"grufted", -"grugru", -"gruine", -"grum", -"grumble", -"grumbly", -"grume", -"grumly", -"grummel", -"grummet", -"grumose", -"grumous", -"grump", -"grumph", -"grumphy", -"grumpy", -"grun", -"grundy", -"grunion", -"grunt", -"grunter", -"gruntle", -"grush", -"grushie", -"gruss", -"grutch", -"grutten", -"gryde", -"grylli", -"gryllid", -"gryllos", -"gryllus", -"grysbok", -"guaba", -"guacimo", -"guacin", -"guaco", -"guaiac", -"guaiol", -"guaka", -"guama", -"guan", -"guana", -"guanaco", -"guanase", -"guanay", -"guango", -"guanine", -"guanize", -"guano", -"guanyl", -"guao", -"guapena", -"guar", -"guara", -"guarabu", -"guarana", -"guarani", -"guard", -"guarded", -"guarder", -"guardo", -"guariba", -"guarri", -"guasa", -"guava", -"guavina", -"guayaba", -"guayabi", -"guayabo", -"guayule", -"guaza", -"gubbo", -"gucki", -"gud", -"gudame", -"guddle", -"gude", -"gudge", -"gudgeon", -"gudget", -"gudok", -"gue", -"guebucu", -"guemal", -"guenepe", -"guenon", -"guepard", -"guerdon", -"guereza", -"guess", -"guesser", -"guest", -"guesten", -"guester", -"gufa", -"guff", -"guffaw", -"guffer", -"guffin", -"guffy", -"gugal", -"guggle", -"gugglet", -"guglet", -"guglia", -"guglio", -"gugu", -"guhr", -"guib", -"guiba", -"guidage", -"guide", -"guider", -"guidman", -"guidon", -"guige", -"guignol", -"guijo", -"guild", -"guilder", -"guildic", -"guildry", -"guile", -"guilery", -"guilt", -"guilty", -"guily", -"guimpe", -"guinea", -"guipure", -"guisard", -"guise", -"guiser", -"guising", -"guitar", -"gul", -"gula", -"gulae", -"gulaman", -"gular", -"gularis", -"gulch", -"gulden", -"gule", -"gules", -"gulf", -"gulfy", -"gulgul", -"gulix", -"gull", -"gullery", -"gullet", -"gullion", -"gullish", -"gully", -"gulonic", -"gulose", -"gulp", -"gulper", -"gulpin", -"gulping", -"gulpy", -"gulsach", -"gum", -"gumbo", -"gumboil", -"gumby", -"gumdrop", -"gumihan", -"gumless", -"gumlike", -"gumly", -"gumma", -"gummage", -"gummata", -"gummed", -"gummer", -"gumming", -"gummite", -"gummose", -"gummous", -"gummy", -"gump", -"gumpus", -"gumshoe", -"gumweed", -"gumwood", -"gun", -"guna", -"gunate", -"gunboat", -"gundi", -"gundy", -"gunebo", -"gunfire", -"gunge", -"gunite", -"gunj", -"gunk", -"gunl", -"gunless", -"gunlock", -"gunman", -"gunnage", -"gunne", -"gunnel", -"gunner", -"gunnery", -"gunnies", -"gunning", -"gunnung", -"gunny", -"gunong", -"gunplay", -"gunrack", -"gunsel", -"gunshop", -"gunshot", -"gunsman", -"gunster", -"gunter", -"gunwale", -"gunyah", -"gunyang", -"gunyeh", -"gup", -"guppy", -"gur", -"gurdle", -"gurge", -"gurgeon", -"gurges", -"gurgle", -"gurglet", -"gurgly", -"gurjun", -"gurk", -"gurl", -"gurly", -"gurnard", -"gurnet", -"gurniad", -"gurr", -"gurrah", -"gurry", -"gurt", -"guru", -"gush", -"gusher", -"gushet", -"gushily", -"gushing", -"gushy", -"gusla", -"gusle", -"guss", -"gusset", -"gussie", -"gust", -"gustful", -"gustily", -"gusto", -"gusty", -"gut", -"gutless", -"gutlike", -"gutling", -"gutt", -"gutta", -"guttate", -"gutte", -"gutter", -"guttery", -"gutti", -"guttide", -"guttie", -"guttle", -"guttler", -"guttula", -"guttule", -"guttus", -"gutty", -"gutweed", -"gutwise", -"gutwort", -"guy", -"guydom", -"guyer", -"guz", -"guze", -"guzzle", -"guzzler", -"gwag", -"gweduc", -"gweed", -"gweeon", -"gwely", -"gwine", -"gwyniad", -"gyle", -"gym", -"gymel", -"gymnast", -"gymnic", -"gymnics", -"gymnite", -"gymnure", -"gympie", -"gyn", -"gyne", -"gynecic", -"gynic", -"gynics", -"gyp", -"gype", -"gypper", -"gyps", -"gypsine", -"gypsite", -"gypsous", -"gypster", -"gypsum", -"gypsy", -"gypsyfy", -"gypsyry", -"gyral", -"gyrally", -"gyrant", -"gyrate", -"gyrator", -"gyre", -"gyrene", -"gyri", -"gyric", -"gyrinid", -"gyro", -"gyrocar", -"gyroma", -"gyron", -"gyronny", -"gyrose", -"gyrous", -"gyrus", -"gyte", -"gytling", -"gyve", -"h", -"ha", -"haab", -"haaf", -"habble", -"habeas", -"habena", -"habenal", -"habenar", -"habile", -"habille", -"habit", -"habitan", -"habitat", -"habited", -"habitue", -"habitus", -"habnab", -"haboob", -"habu", -"habutai", -"hache", -"hachure", -"hack", -"hackbut", -"hacked", -"hackee", -"hacker", -"hackery", -"hackin", -"hacking", -"hackle", -"hackler", -"hacklog", -"hackly", -"hackman", -"hackney", -"hacksaw", -"hacky", -"had", -"hadbot", -"hadden", -"haddie", -"haddo", -"haddock", -"hade", -"hading", -"hadj", -"hadji", -"hadland", -"hadrome", -"haec", -"haem", -"haemony", -"haet", -"haff", -"haffet", -"haffle", -"hafiz", -"hafnium", -"hafnyl", -"haft", -"hafter", -"hag", -"hagboat", -"hagborn", -"hagbush", -"hagdon", -"hageen", -"hagfish", -"haggada", -"haggard", -"hagged", -"hagger", -"haggis", -"haggish", -"haggle", -"haggler", -"haggly", -"haggy", -"hagi", -"hagia", -"haglet", -"haglike", -"haglin", -"hagride", -"hagrope", -"hagseed", -"hagship", -"hagweed", -"hagworm", -"hah", -"haik", -"haikai", -"haikal", -"haikwan", -"hail", -"hailer", -"hailse", -"haily", -"hain", -"haine", -"hair", -"haircut", -"hairdo", -"haire", -"haired", -"hairen", -"hairif", -"hairlet", -"hairpin", -"hairup", -"hairy", -"haje", -"hajib", -"hajilij", -"hak", -"hakam", -"hakdar", -"hake", -"hakeem", -"hakim", -"hako", -"haku", -"hala", -"halakah", -"halakic", -"halal", -"halberd", -"halbert", -"halch", -"halcyon", -"hale", -"halebi", -"haler", -"halerz", -"half", -"halfer", -"halfman", -"halfway", -"halibiu", -"halibut", -"halide", -"halidom", -"halite", -"halitus", -"hall", -"hallage", -"hallah", -"hallan", -"hallel", -"hallex", -"halling", -"hallman", -"halloo", -"hallow", -"hallux", -"hallway", -"halma", -"halo", -"halogen", -"haloid", -"hals", -"halse", -"halsen", -"halt", -"halter", -"halting", -"halurgy", -"halutz", -"halvans", -"halve", -"halved", -"halver", -"halves", -"halyard", -"ham", -"hamal", -"hamald", -"hamate", -"hamated", -"hamatum", -"hamble", -"hame", -"hameil", -"hamel", -"hamfat", -"hami", -"hamlah", -"hamlet", -"hammada", -"hammam", -"hammer", -"hammock", -"hammy", -"hamose", -"hamous", -"hamper", -"hamsa", -"hamster", -"hamular", -"hamule", -"hamulus", -"hamus", -"hamza", -"han", -"hanaper", -"hanbury", -"hance", -"hanced", -"hanch", -"hand", -"handbag", -"handbow", -"handcar", -"handed", -"hander", -"handful", -"handgun", -"handily", -"handle", -"handled", -"handler", -"handout", -"handsaw", -"handsel", -"handset", -"handy", -"hangar", -"hangby", -"hangdog", -"hange", -"hangee", -"hanger", -"hangie", -"hanging", -"hangle", -"hangman", -"hangout", -"hangul", -"hanif", -"hank", -"hanker", -"hankie", -"hankle", -"hanky", -"hanna", -"hansa", -"hanse", -"hansel", -"hansom", -"hant", -"hantle", -"hao", -"haole", -"haoma", -"haori", -"hap", -"hapless", -"haplite", -"haploid", -"haploma", -"haplont", -"haply", -"happen", -"happier", -"happify", -"happily", -"happing", -"happy", -"hapten", -"haptene", -"haptere", -"haptic", -"haptics", -"hapu", -"hapuku", -"harass", -"haratch", -"harbi", -"harbor", -"hard", -"harden", -"harder", -"hardily", -"hardim", -"hardish", -"hardly", -"hardock", -"hardpan", -"hardy", -"hare", -"harebur", -"harelip", -"harem", -"harfang", -"haricot", -"harish", -"hark", -"harka", -"harl", -"harling", -"harlock", -"harlot", -"harm", -"harmal", -"harmala", -"harman", -"harmel", -"harmer", -"harmful", -"harmine", -"harmony", -"harmost", -"harn", -"harness", -"harnpan", -"harp", -"harpago", -"harper", -"harpier", -"harpist", -"harpoon", -"harpula", -"harr", -"harrier", -"harrow", -"harry", -"harsh", -"harshen", -"harshly", -"hart", -"hartal", -"hartin", -"hartite", -"harvest", -"hasan", -"hash", -"hashab", -"hasher", -"hashish", -"hashy", -"hask", -"hasky", -"haslet", -"haslock", -"hasp", -"hassar", -"hassel", -"hassle", -"hassock", -"hasta", -"hastate", -"hastati", -"haste", -"hasten", -"haster", -"hastily", -"hastish", -"hastler", -"hasty", -"hat", -"hatable", -"hatband", -"hatbox", -"hatbrim", -"hatch", -"hatchel", -"hatcher", -"hatchet", -"hate", -"hateful", -"hater", -"hatful", -"hath", -"hathi", -"hatless", -"hatlike", -"hatpin", -"hatrack", -"hatrail", -"hatred", -"hatress", -"hatt", -"hatted", -"hatter", -"hattery", -"hatting", -"hattock", -"hatty", -"hau", -"hauberk", -"haugh", -"haught", -"haughty", -"haul", -"haulage", -"hauld", -"hauler", -"haulier", -"haulm", -"haulmy", -"haunch", -"haunchy", -"haunt", -"haunter", -"haunty", -"hause", -"hausen", -"hausse", -"hautboy", -"hauteur", -"havage", -"have", -"haveage", -"havel", -"haven", -"havener", -"havenet", -"havent", -"haver", -"haverel", -"haverer", -"havers", -"havier", -"havoc", -"haw", -"hawbuck", -"hawer", -"hawk", -"hawkbit", -"hawked", -"hawker", -"hawkery", -"hawkie", -"hawking", -"hawkish", -"hawknut", -"hawky", -"hawm", -"hawok", -"hawse", -"hawser", -"hay", -"haya", -"hayband", -"haybird", -"haybote", -"haycap", -"haycart", -"haycock", -"hayey", -"hayfork", -"haylift", -"hayloft", -"haymow", -"hayrack", -"hayrake", -"hayrick", -"hayseed", -"haysel", -"haysuck", -"haytime", -"hayward", -"hayweed", -"haywire", -"hayz", -"hazard", -"haze", -"hazel", -"hazeled", -"hazelly", -"hazen", -"hazer", -"hazily", -"hazing", -"hazle", -"hazy", -"hazzan", -"he", -"head", -"headcap", -"headed", -"header", -"headful", -"headily", -"heading", -"headman", -"headset", -"headway", -"heady", -"heaf", -"heal", -"heald", -"healder", -"healer", -"healful", -"healing", -"health", -"healthy", -"heap", -"heaper", -"heaps", -"heapy", -"hear", -"hearer", -"hearing", -"hearken", -"hearsay", -"hearse", -"hearst", -"heart", -"hearted", -"hearten", -"hearth", -"heartly", -"hearts", -"hearty", -"heat", -"heater", -"heatful", -"heath", -"heathen", -"heather", -"heathy", -"heating", -"heaume", -"heaumer", -"heave", -"heaven", -"heavens", -"heaver", -"heavies", -"heavily", -"heaving", -"heavity", -"heavy", -"hebamic", -"hebenon", -"hebete", -"hebetic", -"hech", -"heck", -"heckle", -"heckler", -"hectare", -"hecte", -"hectic", -"hector", -"heddle", -"heddler", -"hedebo", -"heder", -"hederic", -"hederin", -"hedge", -"hedger", -"hedging", -"hedgy", -"hedonic", -"heed", -"heeder", -"heedful", -"heedily", -"heedy", -"heehaw", -"heel", -"heelcap", -"heeled", -"heeler", -"heeltap", -"heer", -"heeze", -"heezie", -"heezy", -"heft", -"hefter", -"heftily", -"hefty", -"hegari", -"hegemon", -"hegira", -"hegumen", -"hei", -"heiau", -"heifer", -"heigh", -"height", -"heii", -"heimin", -"heinous", -"heir", -"heirdom", -"heiress", -"heitiki", -"hekteus", -"helbeh", -"helcoid", -"helder", -"hele", -"helenin", -"heliast", -"helical", -"heliced", -"helices", -"helicin", -"helicon", -"helide", -"heling", -"helio", -"helioid", -"helium", -"helix", -"hell", -"hellbox", -"hellcat", -"helldog", -"heller", -"helleri", -"hellhag", -"hellier", -"hellion", -"hellish", -"hello", -"helluo", -"helly", -"helm", -"helmage", -"helmed", -"helmet", -"helodes", -"heloe", -"heloma", -"helonin", -"helosis", -"helotry", -"help", -"helper", -"helpful", -"helping", -"helply", -"helve", -"helvell", -"helver", -"helvite", -"hem", -"hemad", -"hemal", -"hemapod", -"hemase", -"hematal", -"hematic", -"hematid", -"hematin", -"heme", -"hemen", -"hemera", -"hemiamb", -"hemic", -"hemin", -"hemina", -"hemine", -"heminee", -"hemiope", -"hemipic", -"heml", -"hemlock", -"hemmel", -"hemmer", -"hemocry", -"hemoid", -"hemol", -"hemopod", -"hemp", -"hempen", -"hempy", -"hen", -"henad", -"henbane", -"henbill", -"henbit", -"hence", -"hencoop", -"hencote", -"hend", -"hendly", -"henfish", -"henism", -"henlike", -"henna", -"hennery", -"hennin", -"hennish", -"henny", -"henotic", -"henpeck", -"henpen", -"henry", -"hent", -"henter", -"henware", -"henwife", -"henwise", -"henyard", -"hep", -"hepar", -"heparin", -"hepatic", -"hepcat", -"heppen", -"hepper", -"heptace", -"heptad", -"heptal", -"heptane", -"heptene", -"heptine", -"heptite", -"heptoic", -"heptose", -"heptyl", -"heptyne", -"her", -"herald", -"herb", -"herbage", -"herbal", -"herbane", -"herbary", -"herbish", -"herbist", -"herblet", -"herbman", -"herbose", -"herbous", -"herby", -"herd", -"herdboy", -"herder", -"herdic", -"herding", -"here", -"hereat", -"hereby", -"herein", -"herem", -"hereof", -"hereon", -"heresy", -"heretic", -"hereto", -"herile", -"heriot", -"heritor", -"herl", -"herling", -"herma", -"hermaic", -"hermit", -"hern", -"hernani", -"hernant", -"herne", -"hernia", -"hernial", -"hero", -"heroess", -"heroic", -"heroid", -"heroify", -"heroin", -"heroine", -"heroism", -"heroize", -"heron", -"heroner", -"heronry", -"herpes", -"herring", -"hers", -"herse", -"hersed", -"herself", -"hership", -"hersir", -"hertz", -"hessite", -"hest", -"hestern", -"het", -"hetaera", -"hetaery", -"heteric", -"hetero", -"hething", -"hetman", -"hetter", -"heuau", -"heugh", -"heumite", -"hevi", -"hew", -"hewable", -"hewel", -"hewer", -"hewhall", -"hewn", -"hewt", -"hex", -"hexa", -"hexace", -"hexacid", -"hexact", -"hexad", -"hexadic", -"hexagon", -"hexagyn", -"hexane", -"hexaped", -"hexapla", -"hexapod", -"hexarch", -"hexene", -"hexer", -"hexerei", -"hexeris", -"hexine", -"hexis", -"hexitol", -"hexode", -"hexogen", -"hexoic", -"hexone", -"hexonic", -"hexosan", -"hexose", -"hexyl", -"hexylic", -"hexyne", -"hey", -"heyday", -"hi", -"hia", -"hiant", -"hiatal", -"hiate", -"hiation", -"hiatus", -"hibbin", -"hic", -"hicatee", -"hiccup", -"hick", -"hickey", -"hickory", -"hidable", -"hidage", -"hidalgo", -"hidated", -"hidden", -"hide", -"hided", -"hideous", -"hider", -"hidling", -"hie", -"hieder", -"hield", -"hiemal", -"hieron", -"hieros", -"higdon", -"higgle", -"higgler", -"high", -"highboy", -"higher", -"highest", -"highish", -"highly", -"highman", -"hight", -"hightop", -"highway", -"higuero", -"hijack", -"hike", -"hiker", -"hilch", -"hilding", -"hill", -"hiller", -"hillet", -"hillman", -"hillock", -"hilltop", -"hilly", -"hilsa", -"hilt", -"hilum", -"hilus", -"him", -"himp", -"himself", -"himward", -"hin", -"hinau", -"hinch", -"hind", -"hinder", -"hing", -"hinge", -"hinger", -"hingle", -"hinney", -"hinny", -"hinoid", -"hinoki", -"hint", -"hinter", -"hiodont", -"hip", -"hipbone", -"hipe", -"hiper", -"hiphalt", -"hipless", -"hipmold", -"hipped", -"hippen", -"hippian", -"hippic", -"hipping", -"hippish", -"hipple", -"hippo", -"hippoid", -"hippus", -"hippy", -"hipshot", -"hipwort", -"hirable", -"hircine", -"hire", -"hired", -"hireman", -"hirer", -"hirmos", -"hiro", -"hirple", -"hirse", -"hirsel", -"hirsle", -"hirsute", -"his", -"hish", -"hisn", -"hispid", -"hiss", -"hisser", -"hissing", -"hist", -"histie", -"histoid", -"histon", -"histone", -"history", -"histrio", -"hit", -"hitch", -"hitcher", -"hitchy", -"hithe", -"hither", -"hitless", -"hitter", -"hive", -"hiver", -"hives", -"hizz", -"ho", -"hoar", -"hoard", -"hoarder", -"hoarily", -"hoarish", -"hoarse", -"hoarsen", -"hoary", -"hoast", -"hoatzin", -"hoax", -"hoaxee", -"hoaxer", -"hob", -"hobber", -"hobbet", -"hobbil", -"hobble", -"hobbler", -"hobbly", -"hobby", -"hoblike", -"hobnail", -"hobnob", -"hobo", -"hoboism", -"hocco", -"hock", -"hocker", -"hocket", -"hockey", -"hocky", -"hocus", -"hod", -"hodden", -"hodder", -"hoddle", -"hoddy", -"hodful", -"hodman", -"hoe", -"hoecake", -"hoedown", -"hoeful", -"hoer", -"hog", -"hoga", -"hogan", -"hogback", -"hogbush", -"hogfish", -"hogged", -"hogger", -"hoggery", -"hogget", -"hoggie", -"hoggin", -"hoggish", -"hoggism", -"hoggy", -"hogherd", -"hoghide", -"hoghood", -"hoglike", -"hogling", -"hogmace", -"hognose", -"hognut", -"hogpen", -"hogship", -"hogskin", -"hogsty", -"hogward", -"hogwash", -"hogweed", -"hogwort", -"hogyard", -"hoi", -"hoick", -"hoin", -"hoise", -"hoist", -"hoister", -"hoit", -"hoju", -"hokey", -"hokum", -"holard", -"holcad", -"hold", -"holdall", -"holden", -"holder", -"holding", -"holdout", -"holdup", -"hole", -"holeman", -"holer", -"holey", -"holia", -"holiday", -"holily", -"holing", -"holism", -"holl", -"holla", -"holler", -"hollin", -"hollo", -"hollock", -"hollong", -"hollow", -"holly", -"holm", -"holmia", -"holmic", -"holmium", -"holmos", -"holour", -"holster", -"holt", -"holy", -"holyday", -"homage", -"homager", -"home", -"homelet", -"homely", -"homelyn", -"homeoid", -"homer", -"homey", -"homily", -"hominal", -"hominid", -"hominy", -"homish", -"homo", -"homodox", -"homogen", -"homonym", -"homrai", -"homy", -"honda", -"hondo", -"hone", -"honest", -"honesty", -"honey", -"honeyed", -"hong", -"honied", -"honily", -"honk", -"honker", -"honor", -"honoree", -"honorer", -"hontish", -"hontous", -"hooch", -"hood", -"hoodcap", -"hooded", -"hoodful", -"hoodie", -"hoodlum", -"hoodman", -"hoodoo", -"hoodshy", -"hooey", -"hoof", -"hoofed", -"hoofer", -"hoofish", -"hooflet", -"hoofrot", -"hoofs", -"hoofy", -"hook", -"hookah", -"hooked", -"hooker", -"hookers", -"hookish", -"hooklet", -"hookman", -"hooktip", -"hookum", -"hookup", -"hooky", -"hoolock", -"hooly", -"hoon", -"hoop", -"hooped", -"hooper", -"hooping", -"hoopla", -"hoople", -"hoopman", -"hoopoe", -"hoose", -"hoosh", -"hoot", -"hootay", -"hooter", -"hoove", -"hooven", -"hoovey", -"hop", -"hopbine", -"hopbush", -"hope", -"hoped", -"hopeful", -"hopeite", -"hoper", -"hopi", -"hoplite", -"hopoff", -"hopped", -"hopper", -"hoppers", -"hoppet", -"hoppity", -"hopple", -"hoppy", -"hoptoad", -"hopvine", -"hopyard", -"hora", -"horal", -"horary", -"hordary", -"horde", -"hordein", -"horizon", -"horme", -"hormic", -"hormigo", -"hormion", -"hormist", -"hormone", -"hormos", -"horn", -"horned", -"horner", -"hornet", -"hornety", -"hornful", -"hornify", -"hornily", -"horning", -"hornish", -"hornist", -"hornito", -"hornlet", -"horntip", -"horny", -"horrent", -"horreum", -"horrid", -"horrify", -"horror", -"horse", -"horser", -"horsify", -"horsily", -"horsing", -"horst", -"horsy", -"hortite", -"hory", -"hosanna", -"hose", -"hosed", -"hosel", -"hoseman", -"hosier", -"hosiery", -"hospice", -"host", -"hostage", -"hostel", -"hoster", -"hostess", -"hostie", -"hostile", -"hosting", -"hostler", -"hostly", -"hostry", -"hot", -"hotbed", -"hotbox", -"hotch", -"hotel", -"hotfoot", -"hothead", -"hoti", -"hotly", -"hotness", -"hotspur", -"hotter", -"hottery", -"hottish", -"houbara", -"hough", -"hougher", -"hounce", -"hound", -"hounder", -"houndy", -"hour", -"hourful", -"houri", -"hourly", -"housage", -"housal", -"house", -"housel", -"houser", -"housing", -"housty", -"housy", -"houtou", -"houvari", -"hove", -"hovel", -"hoveler", -"hoven", -"hover", -"hoverer", -"hoverly", -"how", -"howadji", -"howbeit", -"howdah", -"howder", -"howdie", -"howdy", -"howe", -"howel", -"however", -"howff", -"howish", -"howk", -"howkit", -"howl", -"howler", -"howlet", -"howling", -"howlite", -"howso", -"hox", -"hoy", -"hoyden", -"hoyle", -"hoyman", -"huaca", -"huaco", -"huarizo", -"hub", -"hubb", -"hubba", -"hubber", -"hubble", -"hubbly", -"hubbub", -"hubby", -"hubshi", -"huchen", -"hucho", -"huck", -"huckle", -"hud", -"huddle", -"huddler", -"huddock", -"huddup", -"hue", -"hued", -"hueful", -"hueless", -"huer", -"huff", -"huffier", -"huffily", -"huffish", -"huffle", -"huffler", -"huffy", -"hug", -"huge", -"hugely", -"hugeous", -"hugger", -"hugging", -"huggle", -"hugsome", -"huh", -"huia", -"huipil", -"huitain", -"huke", -"hula", -"huldee", -"hulk", -"hulkage", -"hulking", -"hulky", -"hull", -"huller", -"hullock", -"hulloo", -"hulsite", -"hulster", -"hulu", -"hulver", -"hum", -"human", -"humane", -"humanly", -"humate", -"humble", -"humbler", -"humblie", -"humbly", -"humbo", -"humbug", -"humbuzz", -"humdrum", -"humect", -"humeral", -"humeri", -"humerus", -"humet", -"humetty", -"humhum", -"humic", -"humid", -"humidly", -"humidor", -"humific", -"humify", -"humin", -"humite", -"humlie", -"hummel", -"hummer", -"hummie", -"humming", -"hummock", -"humor", -"humoral", -"humous", -"hump", -"humped", -"humph", -"humpty", -"humpy", -"humus", -"hunch", -"hunchet", -"hunchy", -"hundi", -"hundred", -"hung", -"hunger", -"hungry", -"hunh", -"hunk", -"hunker", -"hunkers", -"hunkies", -"hunks", -"hunky", -"hunt", -"hunting", -"hup", -"hura", -"hurdies", -"hurdis", -"hurdle", -"hurdler", -"hurds", -"hure", -"hureek", -"hurgila", -"hurkle", -"hurl", -"hurled", -"hurler", -"hurley", -"hurling", -"hurlock", -"hurly", -"huron", -"hurr", -"hurrah", -"hurried", -"hurrier", -"hurrock", -"hurroo", -"hurry", -"hurst", -"hurt", -"hurted", -"hurter", -"hurtful", -"hurting", -"hurtle", -"hurty", -"husband", -"huse", -"hush", -"hushaby", -"husheen", -"hushel", -"husher", -"hushful", -"hushing", -"hushion", -"husho", -"husk", -"husked", -"husker", -"huskily", -"husking", -"husky", -"huso", -"huspil", -"huss", -"hussar", -"hussy", -"husting", -"hustle", -"hustler", -"hut", -"hutch", -"hutcher", -"hutchet", -"huthold", -"hutia", -"hutlet", -"hutment", -"huvelyk", -"huzoor", -"huzz", -"huzza", -"huzzard", -"hyaena", -"hyaline", -"hyalite", -"hyaloid", -"hybosis", -"hybrid", -"hydatid", -"hydnoid", -"hydrant", -"hydrate", -"hydrazo", -"hydria", -"hydric", -"hydride", -"hydro", -"hydroa", -"hydroid", -"hydrol", -"hydrome", -"hydrone", -"hydrops", -"hydrous", -"hydroxy", -"hydrula", -"hyena", -"hyenic", -"hyenine", -"hyenoid", -"hyetal", -"hygeist", -"hygiene", -"hygric", -"hygrine", -"hygroma", -"hying", -"hyke", -"hyle", -"hyleg", -"hylic", -"hylism", -"hylist", -"hyloid", -"hymen", -"hymenal", -"hymenic", -"hymn", -"hymnal", -"hymnary", -"hymner", -"hymnic", -"hymnist", -"hymnode", -"hymnody", -"hynde", -"hyne", -"hyoid", -"hyoidal", -"hyoidan", -"hyoides", -"hyp", -"hypate", -"hypaton", -"hyper", -"hypha", -"hyphal", -"hyphema", -"hyphen", -"hypho", -"hypnody", -"hypnoid", -"hypnone", -"hypo", -"hypogee", -"hypoid", -"hyponym", -"hypopus", -"hyporit", -"hyppish", -"hypural", -"hyraces", -"hyracid", -"hyrax", -"hyson", -"hyssop", -"i", -"iamb", -"iambi", -"iambic", -"iambist", -"iambize", -"iambus", -"iao", -"iatric", -"iba", -"iberite", -"ibex", -"ibices", -"ibid", -"ibidine", -"ibis", -"ibolium", -"ibota", -"icaco", -"ice", -"iceberg", -"iceboat", -"icebone", -"icebox", -"icecap", -"iced", -"icefall", -"icefish", -"iceland", -"iceleaf", -"iceless", -"icelike", -"iceman", -"iceroot", -"icework", -"ich", -"ichnite", -"icho", -"ichor", -"ichthus", -"ichu", -"icica", -"icicle", -"icicled", -"icily", -"iciness", -"icing", -"icon", -"iconic", -"iconism", -"icosian", -"icotype", -"icteric", -"icterus", -"ictic", -"ictuate", -"ictus", -"icy", -"id", -"idalia", -"idant", -"iddat", -"ide", -"idea", -"ideaed", -"ideaful", -"ideal", -"ideally", -"ideate", -"ideist", -"identic", -"ides", -"idgah", -"idiasm", -"idic", -"idiocy", -"idiom", -"idiot", -"idiotcy", -"idiotic", -"idiotry", -"idite", -"iditol", -"idle", -"idleful", -"idleman", -"idler", -"idleset", -"idlety", -"idlish", -"idly", -"idol", -"idola", -"idolify", -"idolism", -"idolist", -"idolize", -"idolous", -"idolum", -"idoneal", -"idorgan", -"idose", -"idryl", -"idyl", -"idyler", -"idylism", -"idylist", -"idylize", -"idyllic", -"ie", -"if", -"ife", -"iffy", -"igloo", -"ignatia", -"ignavia", -"igneous", -"ignify", -"ignite", -"igniter", -"ignitor", -"ignoble", -"ignobly", -"ignore", -"ignorer", -"ignote", -"iguana", -"iguanid", -"ihi", -"ihleite", -"ihram", -"iiwi", -"ijma", -"ijolite", -"ikat", -"ikey", -"ikona", -"ikra", -"ileac", -"ileitis", -"ileon", -"ilesite", -"ileum", -"ileus", -"ilex", -"ilia", -"iliac", -"iliacus", -"iliahi", -"ilial", -"iliau", -"ilicic", -"ilicin", -"ilima", -"ilium", -"ilk", -"ilka", -"ilkane", -"ill", -"illapse", -"illeck", -"illegal", -"illeism", -"illeist", -"illess", -"illfare", -"illicit", -"illish", -"illium", -"illness", -"illocal", -"illogic", -"illoyal", -"illth", -"illude", -"illuder", -"illume", -"illumer", -"illupi", -"illure", -"illusor", -"illy", -"ilot", -"ilvaite", -"image", -"imager", -"imagery", -"imagine", -"imagism", -"imagist", -"imago", -"imam", -"imamah", -"imamate", -"imamic", -"imaret", -"imban", -"imband", -"imbarge", -"imbark", -"imbarn", -"imbased", -"imbat", -"imbauba", -"imbe", -"imbed", -"imber", -"imbibe", -"imbiber", -"imbondo", -"imbosom", -"imbower", -"imbrex", -"imbrue", -"imbrute", -"imbue", -"imburse", -"imi", -"imide", -"imidic", -"imine", -"imino", -"imitant", -"imitate", -"immane", -"immask", -"immense", -"immerd", -"immerge", -"immerit", -"immerse", -"immew", -"immi", -"immit", -"immix", -"immoral", -"immound", -"immund", -"immune", -"immure", -"immute", -"imonium", -"imp", -"impack", -"impact", -"impages", -"impaint", -"impair", -"impala", -"impale", -"impaler", -"impall", -"impalm", -"impalsy", -"impane", -"impanel", -"impar", -"impark", -"imparl", -"impart", -"impasse", -"impaste", -"impasto", -"impave", -"impavid", -"impawn", -"impeach", -"impearl", -"impede", -"impeder", -"impel", -"impen", -"impend", -"impent", -"imperia", -"imperil", -"impest", -"impetre", -"impetus", -"imphee", -"impi", -"impiety", -"impinge", -"impious", -"impish", -"implant", -"implate", -"implead", -"implete", -"implex", -"implial", -"impling", -"implode", -"implore", -"implume", -"imply", -"impofo", -"impone", -"impoor", -"import", -"imposal", -"impose", -"imposer", -"impost", -"impot", -"impound", -"impreg", -"impregn", -"impresa", -"imprese", -"impress", -"imprest", -"imprime", -"imprint", -"improof", -"improve", -"impship", -"impubic", -"impugn", -"impulse", -"impure", -"impute", -"imputer", -"impy", -"imshi", -"imsonic", -"imu", -"in", -"inachid", -"inadept", -"inagile", -"inaja", -"inane", -"inanely", -"inanga", -"inanity", -"inapt", -"inaptly", -"inarch", -"inarm", -"inaugur", -"inaxon", -"inbe", -"inbeing", -"inbent", -"inbirth", -"inblow", -"inblown", -"inboard", -"inbond", -"inborn", -"inbound", -"inbread", -"inbreak", -"inbred", -"inbreed", -"inbring", -"inbuilt", -"inburnt", -"inburst", -"inby", -"incarn", -"incase", -"incast", -"incense", -"incept", -"incest", -"inch", -"inched", -"inchpin", -"incide", -"incisal", -"incise", -"incisor", -"incite", -"inciter", -"incivic", -"incline", -"inclip", -"inclose", -"include", -"inclusa", -"incluse", -"incog", -"income", -"incomer", -"inconnu", -"incrash", -"increep", -"increst", -"incross", -"incrust", -"incubi", -"incubus", -"incudal", -"incudes", -"incult", -"incur", -"incurse", -"incurve", -"incus", -"incuse", -"incut", -"indaba", -"indan", -"indane", -"indart", -"indazin", -"indazol", -"inde", -"indebt", -"indeed", -"indeedy", -"indene", -"indent", -"index", -"indexed", -"indexer", -"indic", -"indican", -"indices", -"indicia", -"indict", -"indign", -"indigo", -"indite", -"inditer", -"indium", -"indogen", -"indole", -"indoles", -"indolyl", -"indoor", -"indoors", -"indorse", -"indoxyl", -"indraft", -"indrawn", -"indri", -"induce", -"induced", -"inducer", -"induct", -"indue", -"indulge", -"indult", -"indulto", -"induna", -"indwell", -"indy", -"indyl", -"indylic", -"inearth", -"inept", -"ineptly", -"inequal", -"inerm", -"inert", -"inertia", -"inertly", -"inesite", -"ineunt", -"inexact", -"inexist", -"inface", -"infall", -"infame", -"infamy", -"infancy", -"infand", -"infang", -"infant", -"infanta", -"infante", -"infarct", -"infare", -"infaust", -"infect", -"infeed", -"infeft", -"infelt", -"infer", -"infern", -"inferno", -"infest", -"infidel", -"infield", -"infill", -"infilm", -"infirm", -"infit", -"infix", -"inflame", -"inflate", -"inflect", -"inflex", -"inflict", -"inflood", -"inflow", -"influx", -"infold", -"inform", -"infra", -"infract", -"infula", -"infuse", -"infuser", -"ing", -"ingate", -"ingenit", -"ingenue", -"ingest", -"ingesta", -"ingiver", -"ingle", -"inglobe", -"ingoing", -"ingot", -"ingraft", -"ingrain", -"ingrate", -"ingress", -"ingross", -"ingrow", -"ingrown", -"inguen", -"ingulf", -"inhabit", -"inhale", -"inhaler", -"inhaul", -"inhaust", -"inhere", -"inherit", -"inhiate", -"inhibit", -"inhuman", -"inhume", -"inhumer", -"inial", -"iniome", -"inion", -"initial", -"initis", -"initive", -"inject", -"injelly", -"injunct", -"injure", -"injured", -"injurer", -"injury", -"ink", -"inkbush", -"inken", -"inker", -"inket", -"inkfish", -"inkhorn", -"inkish", -"inkle", -"inkless", -"inklike", -"inkling", -"inknot", -"inkosi", -"inkpot", -"inkroot", -"inks", -"inkshed", -"inkweed", -"inkwell", -"inkwood", -"inky", -"inlaid", -"inlaik", -"inlake", -"inland", -"inlaut", -"inlaw", -"inlawry", -"inlay", -"inlayer", -"inleak", -"inlet", -"inlier", -"inlook", -"inly", -"inlying", -"inmate", -"inmeats", -"inmost", -"inn", -"innate", -"inneity", -"inner", -"innerly", -"innerve", -"inness", -"innest", -"innet", -"inning", -"innless", -"innyard", -"inocyte", -"inogen", -"inoglia", -"inolith", -"inoma", -"inone", -"inopine", -"inorb", -"inosic", -"inosin", -"inosite", -"inower", -"inphase", -"inport", -"inpour", -"inpush", -"input", -"inquest", -"inquiet", -"inquire", -"inquiry", -"inring", -"inro", -"inroad", -"inroll", -"inrub", -"inrun", -"inrush", -"insack", -"insane", -"insculp", -"insea", -"inseam", -"insect", -"insee", -"inseer", -"insense", -"insert", -"inset", -"inshave", -"inshell", -"inship", -"inshoe", -"inshoot", -"inshore", -"inside", -"insider", -"insight", -"insigne", -"insipid", -"insist", -"insnare", -"insofar", -"insole", -"insolid", -"insooth", -"insorb", -"insoul", -"inspan", -"inspeak", -"inspect", -"inspire", -"inspoke", -"install", -"instant", -"instar", -"instate", -"instead", -"insteam", -"insteep", -"instep", -"instill", -"insula", -"insular", -"insulin", -"insulse", -"insult", -"insunk", -"insure", -"insured", -"insurer", -"insurge", -"inswamp", -"inswell", -"inswept", -"inswing", -"intact", -"intake", -"intaker", -"integer", -"inteind", -"intend", -"intense", -"intent", -"inter", -"interim", -"intern", -"intext", -"inthrow", -"intil", -"intima", -"intimal", -"intine", -"into", -"intoed", -"intone", -"intoner", -"intort", -"intown", -"intrada", -"intrait", -"intrant", -"intreat", -"intrine", -"introit", -"intrude", -"intruse", -"intrust", -"intube", -"intue", -"intuent", -"intuit", -"inturn", -"intwist", -"inula", -"inulase", -"inulin", -"inuloid", -"inunct", -"inure", -"inured", -"inurn", -"inutile", -"invade", -"invader", -"invalid", -"inveigh", -"inveil", -"invein", -"invent", -"inverse", -"invert", -"invest", -"invigor", -"invised", -"invital", -"invite", -"invitee", -"inviter", -"invivid", -"invoice", -"invoke", -"invoker", -"involve", -"inwale", -"inwall", -"inward", -"inwards", -"inweave", -"inweed", -"inwick", -"inwind", -"inwit", -"inwith", -"inwood", -"inwork", -"inworn", -"inwound", -"inwoven", -"inwrap", -"inwrit", -"inyoite", -"inyoke", -"io", -"iodate", -"iodic", -"iodide", -"iodine", -"iodism", -"iodite", -"iodize", -"iodizer", -"iodo", -"iodol", -"iodoso", -"iodous", -"iodoxy", -"iolite", -"ion", -"ionic", -"ionium", -"ionize", -"ionizer", -"ionogen", -"ionone", -"iota", -"iotize", -"ipecac", -"ipid", -"ipil", -"ipomea", -"ipseand", -"ipseity", -"iracund", -"irade", -"irate", -"irately", -"ire", -"ireful", -"ireless", -"irene", -"irenic", -"irenics", -"irian", -"irid", -"iridal", -"iridate", -"irides", -"iridial", -"iridian", -"iridic", -"iridin", -"iridine", -"iridite", -"iridium", -"iridize", -"iris", -"irised", -"irisin", -"iritic", -"iritis", -"irk", -"irksome", -"irok", -"iroko", -"iron", -"irone", -"ironer", -"ironice", -"ironish", -"ironism", -"ironist", -"ironize", -"ironly", -"ironman", -"irony", -"irrisor", -"irrupt", -"is", -"isagoge", -"isagon", -"isamine", -"isatate", -"isatic", -"isatide", -"isatin", -"isazoxy", -"isba", -"ischiac", -"ischial", -"ischium", -"ischury", -"iserine", -"iserite", -"isidium", -"isidoid", -"island", -"islandy", -"islay", -"isle", -"islet", -"isleted", -"islot", -"ism", -"ismal", -"ismatic", -"ismdom", -"ismy", -"iso", -"isoamyl", -"isobar", -"isobare", -"isobase", -"isobath", -"isochor", -"isocola", -"isocrat", -"isodont", -"isoflor", -"isogamy", -"isogen", -"isogeny", -"isogon", -"isogram", -"isohel", -"isohyet", -"isolate", -"isology", -"isomer", -"isomere", -"isomery", -"isoneph", -"isonomy", -"isonym", -"isonymy", -"isopag", -"isopod", -"isopoly", -"isoptic", -"isopyre", -"isotac", -"isotely", -"isotome", -"isotony", -"isotope", -"isotopy", -"isotron", -"isotype", -"isoxime", -"issei", -"issite", -"issuant", -"issue", -"issuer", -"issuing", -"ist", -"isthmi", -"isthmic", -"isthmus", -"istle", -"istoke", -"isuret", -"isuroid", -"it", -"itacism", -"itacist", -"italics", -"italite", -"itch", -"itching", -"itchy", -"itcze", -"item", -"iteming", -"itemize", -"itemy", -"iter", -"iterant", -"iterate", -"ither", -"itmo", -"itoubou", -"its", -"itself", -"iturite", -"itzebu", -"iva", -"ivied", -"ivin", -"ivoried", -"ivorine", -"ivorist", -"ivory", -"ivy", -"ivylike", -"ivyweed", -"ivywood", -"ivywort", -"iwa", -"iwaiwa", -"iwis", -"ixodian", -"ixodic", -"ixodid", -"iyo", -"izar", -"izard", -"izle", -"izote", -"iztle", -"izzard", -"j", -"jab", -"jabbed", -"jabber", -"jabbing", -"jabble", -"jabers", -"jabia", -"jabiru", -"jabot", -"jabul", -"jacal", -"jacamar", -"jacami", -"jacamin", -"jacana", -"jacare", -"jacate", -"jacchus", -"jacent", -"jacinth", -"jack", -"jackal", -"jackass", -"jackbox", -"jackboy", -"jackdaw", -"jackeen", -"jacker", -"jacket", -"jackety", -"jackleg", -"jackman", -"jacko", -"jackrod", -"jacksaw", -"jacktan", -"jacobus", -"jacoby", -"jaconet", -"jactant", -"jacu", -"jacuaru", -"jadder", -"jade", -"jaded", -"jadedly", -"jadeite", -"jadery", -"jadish", -"jady", -"jaeger", -"jag", -"jagat", -"jager", -"jagged", -"jagger", -"jaggery", -"jaggy", -"jagir", -"jagla", -"jagless", -"jagong", -"jagrata", -"jagua", -"jaguar", -"jail", -"jailage", -"jaildom", -"jailer", -"jailish", -"jajman", -"jake", -"jakes", -"jako", -"jalap", -"jalapa", -"jalapin", -"jalkar", -"jalopy", -"jalouse", -"jam", -"jama", -"jaman", -"jamb", -"jambeau", -"jambo", -"jambone", -"jambool", -"jambosa", -"jamdani", -"jami", -"jamlike", -"jammer", -"jammy", -"jampan", -"jampani", -"jamwood", -"janapa", -"janapan", -"jane", -"jangada", -"jangkar", -"jangle", -"jangler", -"jangly", -"janitor", -"jank", -"janker", -"jann", -"jannock", -"jantu", -"janua", -"jaob", -"jap", -"japan", -"jape", -"japer", -"japery", -"japing", -"japish", -"jaquima", -"jar", -"jara", -"jaragua", -"jarbird", -"jarble", -"jarbot", -"jarfly", -"jarful", -"jarg", -"jargon", -"jarkman", -"jarl", -"jarldom", -"jarless", -"jarnut", -"jarool", -"jarra", -"jarrah", -"jarring", -"jarry", -"jarvey", -"jasey", -"jaseyed", -"jasmine", -"jasmone", -"jasper", -"jaspery", -"jaspis", -"jaspoid", -"jass", -"jassid", -"jassoid", -"jatha", -"jati", -"jato", -"jaudie", -"jauk", -"jaun", -"jaunce", -"jaunder", -"jaunt", -"jauntie", -"jaunty", -"jaup", -"javali", -"javelin", -"javer", -"jaw", -"jawab", -"jawbone", -"jawed", -"jawfall", -"jawfish", -"jawfoot", -"jawless", -"jawy", -"jay", -"jayhawk", -"jaypie", -"jaywalk", -"jazz", -"jazzer", -"jazzily", -"jazzy", -"jealous", -"jean", -"jeans", -"jecoral", -"jecorin", -"jed", -"jedcock", -"jedding", -"jeddock", -"jeel", -"jeep", -"jeer", -"jeerer", -"jeering", -"jeery", -"jeff", -"jehu", -"jehup", -"jejunal", -"jejune", -"jejunum", -"jelab", -"jelick", -"jell", -"jellica", -"jellico", -"jellied", -"jellify", -"jellily", -"jelloid", -"jelly", -"jemadar", -"jemmily", -"jemmy", -"jenkin", -"jenna", -"jennet", -"jennier", -"jenny", -"jeofail", -"jeopard", -"jerboa", -"jereed", -"jerez", -"jerib", -"jerk", -"jerker", -"jerkily", -"jerkin", -"jerkish", -"jerky", -"jerl", -"jerm", -"jerque", -"jerquer", -"jerry", -"jersey", -"jert", -"jervia", -"jervina", -"jervine", -"jess", -"jessamy", -"jessant", -"jessed", -"jessur", -"jest", -"jestee", -"jester", -"jestful", -"jesting", -"jet", -"jetbead", -"jete", -"jetsam", -"jettage", -"jetted", -"jetter", -"jettied", -"jetton", -"jetty", -"jetware", -"jewbird", -"jewbush", -"jewel", -"jeweler", -"jewelry", -"jewely", -"jewfish", -"jezail", -"jeziah", -"jharal", -"jheel", -"jhool", -"jhow", -"jib", -"jibbah", -"jibber", -"jibby", -"jibe", -"jibhead", -"jibi", -"jibman", -"jiboa", -"jibstay", -"jicama", -"jicara", -"jiff", -"jiffle", -"jiffy", -"jig", -"jigger", -"jiggers", -"jigget", -"jiggety", -"jiggish", -"jiggle", -"jiggly", -"jiggy", -"jiglike", -"jigman", -"jihad", -"jikungu", -"jillet", -"jilt", -"jiltee", -"jilter", -"jiltish", -"jimbang", -"jimjam", -"jimmy", -"jimp", -"jimply", -"jina", -"jing", -"jingal", -"jingle", -"jingled", -"jingler", -"jinglet", -"jingly", -"jingo", -"jinja", -"jinjili", -"jink", -"jinker", -"jinket", -"jinkle", -"jinks", -"jinn", -"jinni", -"jinny", -"jinriki", -"jinx", -"jipper", -"jiqui", -"jirble", -"jirga", -"jiti", -"jitneur", -"jitney", -"jitro", -"jitter", -"jitters", -"jittery", -"jiva", -"jive", -"jixie", -"jo", -"job", -"jobade", -"jobarbe", -"jobber", -"jobbery", -"jobbet", -"jobbing", -"jobbish", -"jobble", -"jobless", -"jobman", -"jobo", -"joch", -"jock", -"jocker", -"jockey", -"jocko", -"jocoque", -"jocose", -"jocote", -"jocu", -"jocular", -"jocum", -"jocuma", -"jocund", -"jodel", -"jodelr", -"joe", -"joebush", -"joewood", -"joey", -"jog", -"jogger", -"joggle", -"joggler", -"joggly", -"johnin", -"join", -"joinant", -"joinder", -"joiner", -"joinery", -"joining", -"joint", -"jointed", -"jointer", -"jointly", -"jointy", -"joist", -"jojoba", -"joke", -"jokelet", -"joker", -"jokish", -"jokist", -"jokul", -"joky", -"joll", -"jollier", -"jollify", -"jollily", -"jollity", -"jollop", -"jolly", -"jolt", -"jolter", -"jolting", -"jolty", -"jonque", -"jonquil", -"joola", -"joom", -"jordan", -"joree", -"jorum", -"joseite", -"josh", -"josher", -"joshi", -"josie", -"joskin", -"joss", -"josser", -"jostle", -"jostler", -"jot", -"jota", -"jotisi", -"jotter", -"jotting", -"jotty", -"joubarb", -"joug", -"jough", -"jouk", -"joule", -"joulean", -"jounce", -"journal", -"journey", -"jours", -"joust", -"jouster", -"jovial", -"jow", -"jowar", -"jowari", -"jowel", -"jower", -"jowery", -"jowl", -"jowler", -"jowlish", -"jowlop", -"jowly", -"jowpy", -"jowser", -"jowter", -"joy", -"joyance", -"joyancy", -"joyant", -"joyful", -"joyhop", -"joyleaf", -"joyless", -"joylet", -"joyous", -"joysome", -"joyweed", -"juba", -"jubate", -"jubbah", -"jubbe", -"jube", -"jubilee", -"jubilus", -"juck", -"juckies", -"jud", -"judcock", -"judex", -"judge", -"judger", -"judices", -"judo", -"jufti", -"jug", -"jugal", -"jugale", -"jugate", -"jugated", -"juger", -"jugerum", -"jugful", -"jugger", -"juggins", -"juggle", -"juggler", -"juglone", -"jugular", -"jugulum", -"jugum", -"juice", -"juicily", -"juicy", -"jujitsu", -"juju", -"jujube", -"jujuism", -"jujuist", -"juke", -"jukebox", -"julep", -"julid", -"julidan", -"julio", -"juloid", -"julole", -"julolin", -"jumart", -"jumba", -"jumble", -"jumbler", -"jumbly", -"jumbo", -"jumbuck", -"jumby", -"jumelle", -"jument", -"jumfru", -"jumma", -"jump", -"jumper", -"jumpy", -"juncite", -"juncous", -"june", -"jungle", -"jungled", -"jungli", -"jungly", -"juniata", -"junior", -"juniper", -"junk", -"junker", -"junket", -"junking", -"junkman", -"junt", -"junta", -"junto", -"jupati", -"jupe", -"jupon", -"jural", -"jurally", -"jurant", -"jurara", -"jurat", -"jurator", -"jure", -"jurel", -"juridic", -"juring", -"jurist", -"juror", -"jury", -"juryman", -"jussel", -"jussion", -"jussive", -"jussory", -"just", -"justen", -"justice", -"justify", -"justly", -"justo", -"jut", -"jute", -"jutka", -"jutting", -"jutty", -"juvenal", -"juvia", -"juvite", -"jyngine", -"jynx", -"k", -"ka", -"kabaya", -"kabel", -"kaberu", -"kabiet", -"kabuki", -"kachin", -"kadaya", -"kadein", -"kados", -"kaffir", -"kafir", -"kafirin", -"kafiz", -"kafta", -"kago", -"kagu", -"kaha", -"kahar", -"kahau", -"kahili", -"kahu", -"kahuna", -"kai", -"kaid", -"kaik", -"kaikara", -"kail", -"kainga", -"kainite", -"kainsi", -"kainyn", -"kairine", -"kaiser", -"kaitaka", -"kaiwi", -"kajawah", -"kaka", -"kakapo", -"kakar", -"kaki", -"kakkak", -"kakke", -"kala", -"kalasie", -"kale", -"kalema", -"kalends", -"kali", -"kalian", -"kalium", -"kallah", -"kallege", -"kalo", -"kalon", -"kalong", -"kalpis", -"kamahi", -"kamala", -"kamansi", -"kamao", -"kamas", -"kamassi", -"kambal", -"kamboh", -"kame", -"kamerad", -"kamias", -"kamichi", -"kamik", -"kampong", -"kan", -"kana", -"kanae", -"kanagi", -"kanap", -"kanara", -"kanari", -"kanat", -"kanchil", -"kande", -"kandol", -"kaneh", -"kang", -"kanga", -"kangani", -"kankie", -"kannume", -"kanoon", -"kans", -"kantele", -"kanten", -"kaolin", -"kapa", -"kapai", -"kapeika", -"kapok", -"kapp", -"kappa", -"kappe", -"kapur", -"kaput", -"karagan", -"karaka", -"karakul", -"karamu", -"karaoke", -"karate", -"karaya", -"karbi", -"karch", -"kareao", -"kareeta", -"karela", -"karite", -"karma", -"karmic", -"karo", -"kaross", -"karou", -"karree", -"karri", -"karroo", -"karsha", -"karst", -"karstic", -"kartel", -"kartos", -"karwar", -"karyon", -"kasa", -"kasbah", -"kasbeke", -"kasher", -"kashga", -"kashi", -"kashima", -"kasida", -"kasm", -"kassu", -"kastura", -"kat", -"katar", -"katcina", -"kath", -"katha", -"kathal", -"katipo", -"katmon", -"katogle", -"katsup", -"katuka", -"katun", -"katurai", -"katydid", -"kauri", -"kava", -"kavaic", -"kavass", -"kawaka", -"kawika", -"kay", -"kayak", -"kayaker", -"kayles", -"kayo", -"kazi", -"kazoo", -"kea", -"keach", -"keacorn", -"keawe", -"keb", -"kebab", -"kebbie", -"kebbuck", -"kechel", -"keck", -"keckle", -"kecksy", -"kecky", -"ked", -"keddah", -"kedge", -"kedger", -"kedlock", -"keech", -"keek", -"keeker", -"keel", -"keelage", -"keeled", -"keeler", -"keelfat", -"keelie", -"keeling", -"keelman", -"keelson", -"keen", -"keena", -"keened", -"keener", -"keenly", -"keep", -"keeper", -"keeping", -"keest", -"keet", -"keeve", -"kef", -"keffel", -"kefir", -"kefiric", -"keg", -"kegler", -"kehaya", -"keita", -"keitloa", -"kekuna", -"kelchin", -"keld", -"kele", -"kelebe", -"keleh", -"kelek", -"kelep", -"kelk", -"kell", -"kella", -"kellion", -"kelly", -"keloid", -"kelp", -"kelper", -"kelpie", -"kelpy", -"kelt", -"kelter", -"kelty", -"kelvin", -"kemb", -"kemp", -"kempite", -"kemple", -"kempt", -"kempy", -"ken", -"kenaf", -"kenareh", -"kench", -"kend", -"kendir", -"kendyr", -"kenlore", -"kenmark", -"kennel", -"kenner", -"kenning", -"kenno", -"keno", -"kenosis", -"kenotic", -"kenspac", -"kent", -"kenyte", -"kep", -"kepi", -"kept", -"kerana", -"kerasin", -"kerat", -"keratin", -"keratto", -"kerchoo", -"kerchug", -"kerel", -"kerf", -"kerflap", -"kerflop", -"kermes", -"kermis", -"kern", -"kernel", -"kerner", -"kernish", -"kernite", -"kernos", -"kerogen", -"kerrie", -"kerril", -"kerrite", -"kerry", -"kersey", -"kerslam", -"kerugma", -"kerwham", -"kerygma", -"kestrel", -"ket", -"keta", -"ketal", -"ketch", -"ketchup", -"keten", -"ketene", -"ketipic", -"keto", -"ketogen", -"ketol", -"ketole", -"ketone", -"ketonic", -"ketose", -"ketosis", -"kette", -"ketting", -"kettle", -"kettler", -"ketty", -"ketuba", -"ketupa", -"ketyl", -"keup", -"kevalin", -"kevel", -"kewpie", -"kex", -"kexy", -"key", -"keyage", -"keyed", -"keyhole", -"keyless", -"keylet", -"keylock", -"keynote", -"keyway", -"khaddar", -"khadi", -"khahoon", -"khaiki", -"khair", -"khaja", -"khajur", -"khaki", -"khakied", -"khalifa", -"khalsa", -"khamsin", -"khan", -"khanate", -"khanda", -"khanjar", -"khanjee", -"khankah", -"khanum", -"khar", -"kharaj", -"kharua", -"khass", -"khat", -"khatib", -"khatri", -"khediva", -"khedive", -"khepesh", -"khet", -"khilat", -"khir", -"khirka", -"khoja", -"khoka", -"khot", -"khu", -"khubber", -"khula", -"khutbah", -"khvat", -"kiack", -"kiaki", -"kialee", -"kiang", -"kiaugh", -"kibber", -"kibble", -"kibbler", -"kibe", -"kibei", -"kibitka", -"kibitz", -"kiblah", -"kibosh", -"kiby", -"kick", -"kickee", -"kicker", -"kicking", -"kickish", -"kickoff", -"kickout", -"kickup", -"kidder", -"kiddier", -"kiddish", -"kiddush", -"kiddy", -"kidhood", -"kidlet", -"kidling", -"kidnap", -"kidney", -"kidskin", -"kidsman", -"kiekie", -"kiel", -"kier", -"kieye", -"kikar", -"kike", -"kiki", -"kiku", -"kikuel", -"kikumon", -"kil", -"kiladja", -"kilah", -"kilan", -"kildee", -"kileh", -"kilerg", -"kiley", -"kilhig", -"kiliare", -"kilim", -"kill", -"killas", -"killcu", -"killeen", -"killer", -"killick", -"killing", -"killy", -"kiln", -"kilneye", -"kilnman", -"kilnrib", -"kilo", -"kilobar", -"kiloton", -"kilovar", -"kilp", -"kilt", -"kilter", -"kiltie", -"kilting", -"kim", -"kimbang", -"kimnel", -"kimono", -"kin", -"kina", -"kinah", -"kinase", -"kinbote", -"kinch", -"kinchin", -"kincob", -"kind", -"kindle", -"kindler", -"kindly", -"kindred", -"kinepox", -"kinesic", -"kinesis", -"kinetic", -"king", -"kingcob", -"kingcup", -"kingdom", -"kinglet", -"kingly", -"kingpin", -"kingrow", -"kink", -"kinkhab", -"kinkily", -"kinkle", -"kinkled", -"kinkly", -"kinky", -"kinless", -"kino", -"kinship", -"kinsman", -"kintar", -"kioea", -"kiosk", -"kiotome", -"kip", -"kipage", -"kipe", -"kippeen", -"kipper", -"kippy", -"kipsey", -"kipskin", -"kiri", -"kirimon", -"kirk", -"kirker", -"kirkify", -"kirking", -"kirkman", -"kirmew", -"kirn", -"kirombo", -"kirsch", -"kirtle", -"kirtled", -"kirve", -"kirver", -"kischen", -"kish", -"kishen", -"kishon", -"kishy", -"kismet", -"kisra", -"kiss", -"kissage", -"kissar", -"kisser", -"kissing", -"kissy", -"kist", -"kistful", -"kiswa", -"kit", -"kitab", -"kitabis", -"kitar", -"kitcat", -"kitchen", -"kite", -"kith", -"kithe", -"kitish", -"kitling", -"kittel", -"kitten", -"kitter", -"kittle", -"kittles", -"kittly", -"kittock", -"kittul", -"kitty", -"kiva", -"kiver", -"kivu", -"kiwi", -"kiyas", -"kiyi", -"klafter", -"klam", -"klavern", -"klaxon", -"klepht", -"kleptic", -"klicket", -"klip", -"klipbok", -"klipdas", -"klippe", -"klippen", -"klister", -"klom", -"klop", -"klops", -"klosh", -"kmet", -"knab", -"knabble", -"knack", -"knacker", -"knacky", -"knag", -"knagged", -"knaggy", -"knap", -"knape", -"knappan", -"knapper", -"knar", -"knark", -"knarred", -"knarry", -"knave", -"knavery", -"knavess", -"knavish", -"knawel", -"knead", -"kneader", -"knee", -"kneecap", -"kneed", -"kneel", -"kneeler", -"kneelet", -"kneepad", -"kneepan", -"knell", -"knelt", -"knet", -"knew", -"knez", -"knezi", -"kniaz", -"kniazi", -"knick", -"knicker", -"knife", -"knifer", -"knight", -"knit", -"knitch", -"knitted", -"knitter", -"knittle", -"knived", -"knivey", -"knob", -"knobbed", -"knobber", -"knobble", -"knobbly", -"knobby", -"knock", -"knocker", -"knockup", -"knoll", -"knoller", -"knolly", -"knop", -"knopite", -"knopped", -"knopper", -"knoppy", -"knosp", -"knosped", -"knot", -"knotted", -"knotter", -"knotty", -"knout", -"know", -"knowe", -"knower", -"knowing", -"known", -"knub", -"knubbly", -"knubby", -"knublet", -"knuckle", -"knuckly", -"knur", -"knurl", -"knurled", -"knurly", -"knut", -"knutty", -"knyaz", -"knyazi", -"ko", -"koa", -"koae", -"koala", -"koali", -"kob", -"koban", -"kobi", -"kobird", -"kobold", -"kobong", -"kobu", -"koda", -"kodak", -"kodaker", -"kodakry", -"kodro", -"koel", -"koff", -"koft", -"koftgar", -"kohemp", -"kohl", -"kohua", -"koi", -"koil", -"koila", -"koilon", -"koine", -"koinon", -"kojang", -"kokako", -"kokam", -"kokan", -"kokil", -"kokio", -"koklas", -"koklass", -"koko", -"kokoon", -"kokowai", -"kokra", -"koku", -"kokum", -"kokumin", -"kola", -"kolach", -"kolea", -"kolhoz", -"kolkhos", -"kolkhoz", -"kollast", -"koller", -"kolo", -"kolobus", -"kolsun", -"komatik", -"kombu", -"kommos", -"kompeni", -"kon", -"kona", -"konak", -"kongoni", -"kongu", -"konini", -"konjak", -"kooka", -"kookery", -"kookri", -"koolah", -"koombar", -"koomkie", -"kootcha", -"kop", -"kopeck", -"koph", -"kopi", -"koppa", -"koppen", -"koppite", -"kor", -"kora", -"koradji", -"korait", -"korakan", -"korari", -"kore", -"korec", -"koreci", -"korero", -"kori", -"korin", -"korona", -"korova", -"korrel", -"koruna", -"korzec", -"kos", -"kosher", -"kosin", -"kosong", -"koswite", -"kotal", -"koto", -"kotuku", -"kotwal", -"kotyle", -"kotylos", -"kou", -"koulan", -"kouza", -"kovil", -"kowhai", -"kowtow", -"koyan", -"kozo", -"kra", -"kraal", -"kraft", -"krait", -"kraken", -"kral", -"krama", -"kran", -"kras", -"krasis", -"krausen", -"kraut", -"kreis", -"krelos", -"kremlin", -"krems", -"kreng", -"krieker", -"krimmer", -"krina", -"krocket", -"krome", -"krona", -"krone", -"kronen", -"kroner", -"kronor", -"kronur", -"kroon", -"krosa", -"krypsis", -"kryptic", -"kryptol", -"krypton", -"kuan", -"kuba", -"kubba", -"kuchen", -"kudize", -"kudos", -"kudu", -"kudzu", -"kuei", -"kuge", -"kugel", -"kuichua", -"kukri", -"kuku", -"kukui", -"kukupa", -"kula", -"kulack", -"kulah", -"kulaite", -"kulak", -"kulang", -"kulimit", -"kulm", -"kulmet", -"kumbi", -"kumhar", -"kumiss", -"kummel", -"kumquat", -"kumrah", -"kunai", -"kung", -"kunk", -"kunkur", -"kunzite", -"kuphar", -"kupper", -"kurbash", -"kurgan", -"kuruma", -"kurung", -"kurus", -"kurvey", -"kusa", -"kusam", -"kusha", -"kuskite", -"kuskos", -"kuskus", -"kusti", -"kusum", -"kutcha", -"kuttab", -"kuttar", -"kuttaur", -"kuvasz", -"kvass", -"kvint", -"kvinter", -"kwamme", -"kwan", -"kwarta", -"kwazoku", -"kyack", -"kyah", -"kyar", -"kyat", -"kyaung", -"kyl", -"kyle", -"kylite", -"kylix", -"kyrine", -"kyte", -"l", -"la", -"laager", -"laang", -"lab", -"labara", -"labarum", -"labba", -"labber", -"labefy", -"label", -"labeler", -"labella", -"labia", -"labial", -"labiate", -"labile", -"labiose", -"labis", -"labium", -"lablab", -"labor", -"labored", -"laborer", -"labour", -"labra", -"labral", -"labret", -"labroid", -"labrose", -"labrum", -"labrys", -"lac", -"lacca", -"laccaic", -"laccase", -"laccol", -"lace", -"laced", -"laceman", -"lacepod", -"lacer", -"lacery", -"lacet", -"lache", -"laches", -"lachsa", -"lacily", -"lacing", -"lacinia", -"lacis", -"lack", -"lacker", -"lackey", -"lackwit", -"lacmoid", -"lacmus", -"laconic", -"lacquer", -"lacrym", -"lactam", -"lactant", -"lactary", -"lactase", -"lactate", -"lacteal", -"lactean", -"lactic", -"lactid", -"lactide", -"lactify", -"lactim", -"lacto", -"lactoid", -"lactol", -"lactone", -"lactose", -"lactyl", -"lacuna", -"lacunae", -"lacunal", -"lacunar", -"lacune", -"lacwork", -"lacy", -"lad", -"ladakin", -"ladanum", -"ladder", -"laddery", -"laddess", -"laddie", -"laddish", -"laddock", -"lade", -"lademan", -"laden", -"lader", -"ladhood", -"ladies", -"ladify", -"lading", -"ladkin", -"ladle", -"ladler", -"ladrone", -"lady", -"ladybug", -"ladydom", -"ladyfly", -"ladyfy", -"ladyish", -"ladyism", -"ladykin", -"ladyly", -"laet", -"laeti", -"laetic", -"lag", -"lagan", -"lagarto", -"lagen", -"lagena", -"lagend", -"lager", -"lagetto", -"laggar", -"laggard", -"lagged", -"laggen", -"lagger", -"laggin", -"lagging", -"laglast", -"lagna", -"lagoon", -"lagwort", -"lai", -"laic", -"laical", -"laich", -"laicism", -"laicity", -"laicize", -"laid", -"laigh", -"lain", -"laine", -"laiose", -"lair", -"lairage", -"laird", -"lairdie", -"lairdly", -"lairman", -"lairy", -"laity", -"lak", -"lakatoi", -"lake", -"lakelet", -"laker", -"lakie", -"laking", -"lakish", -"lakism", -"lakist", -"laky", -"lalang", -"lall", -"lalling", -"lalo", -"lam", -"lama", -"lamaic", -"lamany", -"lamb", -"lamba", -"lambale", -"lambda", -"lambeau", -"lambent", -"lamber", -"lambert", -"lambie", -"lambish", -"lambkin", -"lambly", -"lamboys", -"lamby", -"lame", -"lamedh", -"lamel", -"lamella", -"lamely", -"lament", -"lameter", -"lametta", -"lamia", -"lamiger", -"lamiid", -"lamin", -"lamina", -"laminae", -"laminar", -"lamish", -"lamiter", -"lammas", -"lammer", -"lammock", -"lammy", -"lamnid", -"lamnoid", -"lamp", -"lampad", -"lampas", -"lamper", -"lampern", -"lampers", -"lampfly", -"lampful", -"lamping", -"lampion", -"lampist", -"lamplet", -"lamplit", -"lampman", -"lampoon", -"lamprey", -"lan", -"lanas", -"lanate", -"lanated", -"lanaz", -"lance", -"lanced", -"lancely", -"lancer", -"lances", -"lancet", -"lancha", -"land", -"landau", -"landed", -"lander", -"landing", -"landman", -"landmil", -"lane", -"lanete", -"laneway", -"laney", -"langaha", -"langca", -"langi", -"langite", -"langle", -"langoon", -"langsat", -"langued", -"languet", -"languid", -"languor", -"langur", -"laniary", -"laniate", -"lanific", -"lanioid", -"lanista", -"lank", -"lanket", -"lankily", -"lankish", -"lankly", -"lanky", -"lanner", -"lanolin", -"lanose", -"lansat", -"lanseh", -"lanson", -"lant", -"lantaca", -"lantern", -"lantum", -"lanugo", -"lanum", -"lanx", -"lanyard", -"lap", -"lapacho", -"lapcock", -"lapel", -"lapeler", -"lapful", -"lapillo", -"lapon", -"lappage", -"lapped", -"lapper", -"lappet", -"lapping", -"lapse", -"lapsed", -"lapser", -"lapsi", -"lapsing", -"lapwing", -"lapwork", -"laquear", -"laqueus", -"lar", -"larceny", -"larch", -"larchen", -"lard", -"larder", -"lardite", -"lardon", -"lardy", -"large", -"largely", -"largen", -"largess", -"largish", -"largo", -"lari", -"lariat", -"larick", -"larid", -"larigo", -"larigot", -"lariid", -"larin", -"larine", -"larixin", -"lark", -"larker", -"larking", -"larkish", -"larky", -"larmier", -"larnax", -"laroid", -"larrup", -"larry", -"larva", -"larvae", -"larval", -"larvate", -"larve", -"larvule", -"larynx", -"las", -"lasa", -"lascar", -"laser", -"lash", -"lasher", -"lask", -"lasket", -"lasque", -"lass", -"lasset", -"lassie", -"lasso", -"lassock", -"lassoer", -"last", -"lastage", -"laster", -"lasting", -"lastly", -"lastre", -"lasty", -"lat", -"lata", -"latah", -"latch", -"latcher", -"latchet", -"late", -"latebra", -"lated", -"lateen", -"lately", -"laten", -"latence", -"latency", -"latent", -"later", -"latera", -"laterad", -"lateral", -"latest", -"latex", -"lath", -"lathe", -"lathee", -"lathen", -"lather", -"lathery", -"lathing", -"lathy", -"latices", -"latigo", -"lation", -"latish", -"latitat", -"latite", -"latomy", -"latrant", -"latria", -"latrine", -"latro", -"latrobe", -"latron", -"latten", -"latter", -"lattice", -"latus", -"lauan", -"laud", -"lauder", -"laudist", -"laugh", -"laughee", -"laugher", -"laughy", -"lauia", -"laun", -"launce", -"launch", -"laund", -"launder", -"laundry", -"laur", -"laura", -"laurate", -"laurel", -"lauric", -"laurin", -"laurite", -"laurone", -"lauryl", -"lava", -"lavable", -"lavabo", -"lavacre", -"lavage", -"lavanga", -"lavant", -"lavaret", -"lavatic", -"lave", -"laveer", -"laver", -"lavic", -"lavish", -"lavolta", -"law", -"lawbook", -"lawful", -"lawing", -"lawish", -"lawk", -"lawless", -"lawlike", -"lawman", -"lawn", -"lawned", -"lawner", -"lawnlet", -"lawny", -"lawsuit", -"lawter", -"lawyer", -"lawyery", -"lawzy", -"lax", -"laxate", -"laxism", -"laxist", -"laxity", -"laxly", -"laxness", -"lay", -"layaway", -"layback", -"layboy", -"layer", -"layered", -"layery", -"layette", -"laying", -"layland", -"layman", -"layne", -"layoff", -"layout", -"layover", -"layship", -"laystow", -"lazar", -"lazaret", -"lazarly", -"laze", -"lazily", -"lazule", -"lazuli", -"lazy", -"lazyish", -"lea", -"leach", -"leacher", -"leachy", -"lead", -"leadage", -"leaded", -"leaden", -"leader", -"leadin", -"leading", -"leadman", -"leadoff", -"leadout", -"leadway", -"leady", -"leaf", -"leafage", -"leafboy", -"leafcup", -"leafdom", -"leafed", -"leafen", -"leafer", -"leafery", -"leafit", -"leaflet", -"leafy", -"league", -"leaguer", -"leak", -"leakage", -"leaker", -"leaky", -"leal", -"lealand", -"leally", -"lealty", -"leam", -"leamer", -"lean", -"leaner", -"leaning", -"leanish", -"leanly", -"leant", -"leap", -"leaper", -"leaping", -"leapt", -"lear", -"learn", -"learned", -"learner", -"learnt", -"lease", -"leaser", -"leash", -"leasing", -"leasow", -"least", -"leat", -"leath", -"leather", -"leatman", -"leave", -"leaved", -"leaven", -"leaver", -"leaves", -"leaving", -"leavy", -"leawill", -"leban", -"lebbek", -"lecama", -"lech", -"lecher", -"lechery", -"lechwe", -"leck", -"lecker", -"lectern", -"lection", -"lector", -"lectual", -"lecture", -"lecyth", -"led", -"lede", -"leden", -"ledge", -"ledged", -"ledger", -"ledging", -"ledgy", -"ledol", -"lee", -"leech", -"leecher", -"leeches", -"leed", -"leefang", -"leek", -"leekish", -"leeky", -"leep", -"leepit", -"leer", -"leerily", -"leerish", -"leery", -"lees", -"leet", -"leetman", -"leewan", -"leeward", -"leeway", -"leewill", -"left", -"leftish", -"leftism", -"leftist", -"leg", -"legacy", -"legal", -"legally", -"legate", -"legatee", -"legato", -"legator", -"legend", -"legenda", -"leger", -"leges", -"legged", -"legger", -"legging", -"leggy", -"leghorn", -"legible", -"legibly", -"legific", -"legion", -"legist", -"legit", -"legitim", -"leglen", -"legless", -"leglet", -"leglike", -"legman", -"legoa", -"legpull", -"legrope", -"legua", -"leguan", -"legume", -"legumen", -"legumin", -"lehr", -"lehrman", -"lehua", -"lei", -"leister", -"leisure", -"lek", -"lekach", -"lekane", -"lekha", -"leman", -"lemel", -"lemma", -"lemmata", -"lemming", -"lemnad", -"lemon", -"lemony", -"lempira", -"lemur", -"lemures", -"lemurid", -"lenad", -"lenard", -"lench", -"lend", -"lendee", -"lender", -"lene", -"length", -"lengthy", -"lenient", -"lenify", -"lenis", -"lenitic", -"lenity", -"lennow", -"leno", -"lens", -"lensed", -"lent", -"lenth", -"lentigo", -"lentil", -"lentisc", -"lentisk", -"lento", -"lentoid", -"lentor", -"lentous", -"lenvoi", -"lenvoy", -"leonine", -"leonite", -"leopard", -"leotard", -"lepa", -"leper", -"lepered", -"leporid", -"lepra", -"lepric", -"leproid", -"leproma", -"leprose", -"leprosy", -"leprous", -"leptid", -"leptite", -"leptome", -"lepton", -"leptus", -"lerot", -"lerp", -"lerret", -"lesche", -"lesion", -"lesiy", -"less", -"lessee", -"lessen", -"lesser", -"lessive", -"lessn", -"lesson", -"lessor", -"lest", -"lestrad", -"let", -"letch", -"letchy", -"letdown", -"lete", -"lethal", -"letoff", -"letten", -"letter", -"lettrin", -"lettuce", -"letup", -"leu", -"leuch", -"leucine", -"leucism", -"leucite", -"leuco", -"leucoid", -"leucoma", -"leucon", -"leucous", -"leucyl", -"leud", -"leuk", -"leuma", -"lev", -"levance", -"levant", -"levator", -"levee", -"level", -"leveler", -"levelly", -"lever", -"leverer", -"leveret", -"levers", -"levier", -"levin", -"levir", -"levity", -"levo", -"levulic", -"levulin", -"levy", -"levyist", -"lew", -"lewd", -"lewdly", -"lewis", -"lewth", -"lexia", -"lexical", -"lexicon", -"ley", -"leyland", -"leysing", -"li", -"liable", -"liaison", -"liana", -"liang", -"liar", -"liard", -"libant", -"libate", -"libber", -"libbet", -"libbra", -"libel", -"libelee", -"libeler", -"liber", -"liberal", -"liberty", -"libido", -"libken", -"libra", -"libral", -"library", -"librate", -"licca", -"license", -"lich", -"licham", -"lichen", -"licheny", -"lichi", -"licit", -"licitly", -"lick", -"licker", -"licking", -"licorn", -"licorne", -"lictor", -"lid", -"lidded", -"lidder", -"lidgate", -"lidless", -"lie", -"lied", -"lief", -"liege", -"liegely", -"lieger", -"lien", -"lienal", -"lienee", -"lienic", -"lienor", -"lier", -"lierne", -"lierre", -"liesh", -"lieu", -"lieue", -"lieve", -"life", -"lifeday", -"lifeful", -"lifelet", -"lifer", -"lifey", -"lifo", -"lift", -"lifter", -"lifting", -"liftman", -"ligable", -"ligas", -"ligate", -"ligator", -"ligger", -"light", -"lighten", -"lighter", -"lightly", -"ligne", -"lignify", -"lignin", -"lignite", -"lignone", -"lignose", -"lignum", -"ligula", -"ligular", -"ligule", -"ligulin", -"ligure", -"liin", -"lija", -"likable", -"like", -"likely", -"liken", -"liker", -"likin", -"liking", -"liknon", -"lilac", -"lilacin", -"lilacky", -"lile", -"lilied", -"lill", -"lilt", -"lily", -"lilyfy", -"lim", -"limacel", -"limacon", -"liman", -"limb", -"limbal", -"limbat", -"limbate", -"limbeck", -"limbed", -"limber", -"limbers", -"limbic", -"limbie", -"limbo", -"limbous", -"limbus", -"limby", -"lime", -"limeade", -"limeman", -"limen", -"limer", -"limes", -"limetta", -"limey", -"liminal", -"liming", -"limit", -"limital", -"limited", -"limiter", -"limma", -"limmer", -"limmock", -"limmu", -"limn", -"limner", -"limnery", -"limniad", -"limnite", -"limoid", -"limonin", -"limose", -"limous", -"limp", -"limper", -"limpet", -"limpid", -"limpily", -"limpin", -"limping", -"limpish", -"limpkin", -"limply", -"limpsy", -"limpy", -"limsy", -"limu", -"limulid", -"limy", -"lin", -"lina", -"linable", -"linaga", -"linage", -"linaloa", -"linalol", -"linch", -"linchet", -"linctus", -"lindane", -"linden", -"linder", -"lindo", -"line", -"linea", -"lineage", -"lineal", -"linear", -"lineate", -"linecut", -"lined", -"linelet", -"lineman", -"linen", -"liner", -"ling", -"linga", -"linge", -"lingel", -"linger", -"lingo", -"lingtow", -"lingua", -"lingual", -"linguet", -"lingula", -"lingy", -"linha", -"linhay", -"linie", -"linin", -"lining", -"linitis", -"liniya", -"linja", -"linje", -"link", -"linkage", -"linkboy", -"linked", -"linker", -"linking", -"linkman", -"links", -"linky", -"linn", -"linnet", -"lino", -"linolic", -"linolin", -"linon", -"linous", -"linoxin", -"linoxyn", -"linpin", -"linseed", -"linsey", -"lint", -"lintel", -"linten", -"linter", -"lintern", -"lintie", -"linty", -"linwood", -"liny", -"lion", -"lioncel", -"lionel", -"lioness", -"lionet", -"lionism", -"lionize", -"lionly", -"lip", -"lipa", -"liparid", -"lipase", -"lipemia", -"lipide", -"lipin", -"lipless", -"liplet", -"liplike", -"lipoid", -"lipoma", -"lipopod", -"liposis", -"lipped", -"lippen", -"lipper", -"lipping", -"lippy", -"lipuria", -"lipwork", -"liquate", -"liquefy", -"liqueur", -"liquid", -"liquidy", -"liquor", -"lira", -"lirate", -"lire", -"lirella", -"lis", -"lisere", -"lish", -"lisk", -"lisle", -"lisp", -"lisper", -"lispund", -"liss", -"lissom", -"lissome", -"list", -"listed", -"listel", -"listen", -"lister", -"listing", -"listred", -"lit", -"litany", -"litas", -"litch", -"litchi", -"lite", -"liter", -"literal", -"lith", -"lithe", -"lithely", -"lithi", -"lithia", -"lithic", -"lithify", -"lithite", -"lithium", -"litho", -"lithoid", -"lithous", -"lithy", -"litmus", -"litotes", -"litra", -"litster", -"litten", -"litter", -"littery", -"little", -"lituite", -"liturgy", -"litus", -"lituus", -"litz", -"livable", -"live", -"lived", -"livedo", -"lively", -"liven", -"liver", -"livered", -"livery", -"livid", -"lividly", -"livier", -"living", -"livor", -"livre", -"liwan", -"lixive", -"lizard", -"llama", -"llano", -"llautu", -"llyn", -"lo", -"loa", -"loach", -"load", -"loadage", -"loaded", -"loaden", -"loader", -"loading", -"loaf", -"loafer", -"loafing", -"loaflet", -"loam", -"loamily", -"loaming", -"loamy", -"loan", -"loaner", -"loanin", -"loath", -"loathe", -"loather", -"loathly", -"loave", -"lob", -"lobal", -"lobar", -"lobate", -"lobated", -"lobber", -"lobbish", -"lobby", -"lobbyer", -"lobcock", -"lobe", -"lobed", -"lobelet", -"lobelin", -"lobfig", -"lobing", -"lobiped", -"lobo", -"lobola", -"lobose", -"lobster", -"lobtail", -"lobular", -"lobule", -"lobworm", -"loca", -"locable", -"local", -"locale", -"locally", -"locanda", -"locate", -"locator", -"loch", -"lochage", -"lochan", -"lochia", -"lochial", -"lochus", -"lochy", -"loci", -"lock", -"lockage", -"lockbox", -"locked", -"locker", -"locket", -"lockful", -"locking", -"lockjaw", -"locklet", -"lockman", -"lockout", -"lockpin", -"lockram", -"lockup", -"locky", -"loco", -"locoism", -"locular", -"locule", -"loculus", -"locum", -"locus", -"locust", -"locusta", -"locutor", -"lod", -"lode", -"lodge", -"lodged", -"lodger", -"lodging", -"loess", -"loessal", -"loessic", -"lof", -"loft", -"lofter", -"loftily", -"lofting", -"loftman", -"lofty", -"log", -"loganin", -"logbook", -"logcock", -"loge", -"logeion", -"logeum", -"loggat", -"logged", -"logger", -"loggia", -"loggin", -"logging", -"loggish", -"loghead", -"logia", -"logic", -"logical", -"logie", -"login", -"logion", -"logium", -"loglet", -"loglike", -"logman", -"logoi", -"logos", -"logroll", -"logway", -"logwise", -"logwood", -"logwork", -"logy", -"lohan", -"lohoch", -"loimic", -"loin", -"loined", -"loir", -"loiter", -"loka", -"lokao", -"lokaose", -"loke", -"loket", -"lokiec", -"loll", -"loller", -"lollop", -"lollopy", -"lolly", -"loma", -"lombard", -"lomboy", -"loment", -"lomita", -"lommock", -"lone", -"lonely", -"long", -"longa", -"longan", -"longbow", -"longe", -"longear", -"longer", -"longfin", -"longful", -"longing", -"longish", -"longjaw", -"longly", -"longs", -"longue", -"longway", -"lontar", -"loo", -"looby", -"lood", -"loof", -"loofah", -"loofie", -"look", -"looker", -"looking", -"lookout", -"lookum", -"loom", -"loomer", -"loomery", -"looming", -"loon", -"loonery", -"looney", -"loony", -"loop", -"looper", -"loopful", -"looping", -"loopist", -"looplet", -"loopy", -"loose", -"loosely", -"loosen", -"looser", -"loosing", -"loosish", -"loot", -"looten", -"looter", -"lootie", -"lop", -"lope", -"loper", -"lophiid", -"lophine", -"loppard", -"lopper", -"loppet", -"lopping", -"loppy", -"lopseed", -"loquat", -"loquent", -"lora", -"loral", -"loran", -"lorate", -"lorcha", -"lord", -"lording", -"lordkin", -"lordlet", -"lordly", -"lordy", -"lore", -"loreal", -"lored", -"lori", -"loric", -"lorica", -"lorilet", -"lorimer", -"loriot", -"loris", -"lormery", -"lorn", -"loro", -"lorry", -"lors", -"lorum", -"lory", -"losable", -"lose", -"losel", -"loser", -"losh", -"losing", -"loss", -"lost", -"lot", -"lota", -"lotase", -"lote", -"lotic", -"lotion", -"lotment", -"lotrite", -"lots", -"lotter", -"lottery", -"lotto", -"lotus", -"lotusin", -"louch", -"loud", -"louden", -"loudish", -"loudly", -"louey", -"lough", -"louk", -"loukoum", -"loulu", -"lounder", -"lounge", -"lounger", -"loungy", -"loup", -"loupe", -"lour", -"lourdy", -"louse", -"lousily", -"louster", -"lousy", -"lout", -"louter", -"louther", -"loutish", -"louty", -"louvar", -"louver", -"lovable", -"lovably", -"lovage", -"love", -"loveful", -"lovely", -"loveman", -"lover", -"lovered", -"loverly", -"loving", -"low", -"lowa", -"lowan", -"lowbell", -"lowborn", -"lowboy", -"lowbred", -"lowdah", -"lowder", -"loweite", -"lower", -"lowerer", -"lowery", -"lowish", -"lowland", -"lowlily", -"lowly", -"lowmen", -"lowmost", -"lown", -"lowness", -"lownly", -"lowth", -"lowwood", -"lowy", -"lox", -"loxia", -"loxic", -"loxotic", -"loy", -"loyal", -"loyally", -"loyalty", -"lozenge", -"lozengy", -"lubber", -"lube", -"lubra", -"lubric", -"lubrify", -"lucanid", -"lucarne", -"lucban", -"luce", -"lucence", -"lucency", -"lucent", -"lucern", -"lucerne", -"lucet", -"lucible", -"lucid", -"lucida", -"lucidly", -"lucifee", -"lucific", -"lucigen", -"lucivee", -"luck", -"lucken", -"luckful", -"luckie", -"luckily", -"lucky", -"lucre", -"lucrify", -"lucule", -"lucumia", -"lucy", -"ludden", -"ludibry", -"ludo", -"lue", -"lues", -"luetic", -"lufbery", -"luff", -"lug", -"luge", -"luger", -"luggage", -"luggar", -"lugged", -"lugger", -"luggie", -"lugmark", -"lugsail", -"lugsome", -"lugworm", -"luhinga", -"luigino", -"luke", -"lukely", -"lulab", -"lull", -"lullaby", -"luller", -"lulu", -"lum", -"lumbago", -"lumbang", -"lumbar", -"lumber", -"lumen", -"luminal", -"lumine", -"lummox", -"lummy", -"lump", -"lumper", -"lumpet", -"lumpily", -"lumping", -"lumpish", -"lumpkin", -"lumpman", -"lumpy", -"luna", -"lunacy", -"lunar", -"lunare", -"lunary", -"lunate", -"lunatic", -"lunatum", -"lunch", -"luncher", -"lune", -"lunes", -"lunette", -"lung", -"lunge", -"lunged", -"lunger", -"lungful", -"lungi", -"lungie", -"lungis", -"lungy", -"lunn", -"lunoid", -"lunt", -"lunula", -"lunular", -"lunule", -"lunulet", -"lupe", -"lupeol", -"lupeose", -"lupine", -"lupinin", -"lupis", -"lupoid", -"lupous", -"lupulic", -"lupulin", -"lupulus", -"lupus", -"lura", -"lural", -"lurch", -"lurcher", -"lurdan", -"lure", -"lureful", -"lurer", -"lurg", -"lurid", -"luridly", -"lurk", -"lurker", -"lurky", -"lurrier", -"lurry", -"lush", -"lusher", -"lushly", -"lushy", -"lusk", -"lusky", -"lusory", -"lust", -"luster", -"lustful", -"lustily", -"lustra", -"lustral", -"lustrum", -"lusty", -"lut", -"lutany", -"lute", -"luteal", -"lutecia", -"lutein", -"lutelet", -"luteo", -"luteoma", -"luteous", -"luter", -"luteway", -"lutfisk", -"luthern", -"luthier", -"luting", -"lutist", -"lutose", -"lutrin", -"lutrine", -"lux", -"luxate", -"luxe", -"luxury", -"luxus", -"ly", -"lyam", -"lyard", -"lyceal", -"lyceum", -"lycid", -"lycopin", -"lycopod", -"lycosid", -"lyctid", -"lyddite", -"lydite", -"lye", -"lyery", -"lygaeid", -"lying", -"lyingly", -"lymph", -"lymphad", -"lymphy", -"lyncean", -"lynch", -"lyncher", -"lyncine", -"lynx", -"lyra", -"lyrate", -"lyrated", -"lyraway", -"lyre", -"lyreman", -"lyric", -"lyrical", -"lyrism", -"lyrist", -"lys", -"lysate", -"lyse", -"lysin", -"lysine", -"lysis", -"lysogen", -"lyssa", -"lyssic", -"lytic", -"lytta", -"lyxose", -"m", -"ma", -"maam", -"mabi", -"mabolo", -"mac", -"macabre", -"macaco", -"macadam", -"macan", -"macana", -"macao", -"macaque", -"macaw", -"macco", -"mace", -"maceman", -"macer", -"machan", -"machar", -"machete", -"machi", -"machila", -"machin", -"machine", -"machree", -"macies", -"mack", -"mackins", -"mackle", -"macle", -"macled", -"maco", -"macrame", -"macro", -"macron", -"macuca", -"macula", -"macular", -"macule", -"macuta", -"mad", -"madam", -"madame", -"madcap", -"madden", -"madder", -"madding", -"maddish", -"maddle", -"made", -"madefy", -"madhuca", -"madid", -"madling", -"madly", -"madman", -"madnep", -"madness", -"mado", -"madoqua", -"madrier", -"madrona", -"madship", -"maduro", -"madweed", -"madwort", -"mae", -"maenad", -"maestri", -"maestro", -"maffia", -"maffick", -"maffle", -"mafflin", -"mafic", -"mafoo", -"mafura", -"mag", -"magadis", -"magani", -"magas", -"mage", -"magenta", -"magged", -"maggle", -"maggot", -"maggoty", -"magi", -"magic", -"magical", -"magiric", -"magma", -"magnate", -"magnes", -"magnet", -"magneta", -"magneto", -"magnify", -"magnum", -"magot", -"magpie", -"magpied", -"magsman", -"maguari", -"maguey", -"maha", -"mahaleb", -"mahalla", -"mahant", -"mahar", -"maharao", -"mahatma", -"mahmal", -"mahmudi", -"mahoe", -"maholi", -"mahone", -"mahout", -"mahseer", -"mahua", -"mahuang", -"maid", -"maidan", -"maiden", -"maidish", -"maidism", -"maidkin", -"maidy", -"maiefic", -"maigre", -"maiid", -"mail", -"mailbag", -"mailbox", -"mailed", -"mailer", -"mailie", -"mailman", -"maim", -"maimed", -"maimer", -"maimon", -"main", -"mainly", -"mainour", -"mainpin", -"mains", -"maint", -"maintop", -"maioid", -"maire", -"maize", -"maizer", -"majagua", -"majesty", -"majo", -"majoon", -"major", -"makable", -"make", -"makedom", -"maker", -"makhzan", -"maki", -"making", -"makluk", -"mako", -"makuk", -"mal", -"mala", -"malacia", -"malacon", -"malady", -"malagma", -"malaise", -"malakin", -"malambo", -"malanga", -"malapi", -"malar", -"malaria", -"malarin", -"malate", -"malati", -"malax", -"malduck", -"male", -"malease", -"maleate", -"maleic", -"malella", -"maleo", -"malfed", -"mali", -"malic", -"malice", -"malicho", -"malign", -"malik", -"maline", -"malines", -"malism", -"malison", -"malist", -"malkin", -"mall", -"mallard", -"malleal", -"mallear", -"mallee", -"mallein", -"mallet", -"malleus", -"mallow", -"mallum", -"mallus", -"malm", -"malmsey", -"malmy", -"malo", -"malodor", -"malonic", -"malonyl", -"malouah", -"malpais", -"malt", -"maltase", -"malter", -"maltha", -"malting", -"maltman", -"maltose", -"malty", -"mamba", -"mambo", -"mamma", -"mammal", -"mammary", -"mammate", -"mammee", -"mammer", -"mammock", -"mammon", -"mammoth", -"mammula", -"mammy", -"mamo", -"man", -"mana", -"manacle", -"manage", -"managee", -"manager", -"manaism", -"manakin", -"manal", -"manas", -"manatee", -"manavel", -"manbird", -"manbot", -"manche", -"manchet", -"mancono", -"mancus", -"mand", -"mandala", -"mandant", -"mandate", -"mandil", -"mandola", -"mandom", -"mandora", -"mandore", -"mandra", -"mandrel", -"mandrin", -"mandua", -"mandyas", -"mane", -"maned", -"manege", -"manei", -"manent", -"manes", -"maness", -"maney", -"manful", -"mang", -"manga", -"mangal", -"mange", -"mangeao", -"mangel", -"manger", -"mangi", -"mangily", -"mangle", -"mangler", -"mango", -"mangona", -"mangue", -"mangy", -"manhead", -"manhole", -"manhood", -"mani", -"mania", -"maniac", -"manic", -"manid", -"manify", -"manikin", -"manila", -"manilla", -"manille", -"manioc", -"maniple", -"manism", -"manist", -"manito", -"maniu", -"manjak", -"mank", -"mankin", -"mankind", -"manless", -"manlet", -"manlike", -"manlily", -"manling", -"manly", -"manna", -"mannan", -"manner", -"manners", -"manness", -"mannide", -"mannie", -"mannify", -"manning", -"mannish", -"mannite", -"mannose", -"manny", -"mano", -"manoc", -"manomin", -"manor", -"manque", -"manred", -"manrent", -"manroot", -"manrope", -"mansard", -"manse", -"manship", -"mansion", -"manso", -"mant", -"manta", -"mantal", -"manteau", -"mantel", -"manter", -"mantes", -"mantic", -"mantid", -"mantis", -"mantle", -"mantled", -"mantlet", -"manto", -"mantoid", -"mantra", -"mantrap", -"mantua", -"manual", -"manuao", -"manuka", -"manul", -"manuma", -"manumea", -"manumit", -"manure", -"manurer", -"manus", -"manward", -"manway", -"manweed", -"manwise", -"many", -"manzana", -"manzil", -"mao", -"maomao", -"map", -"mapach", -"mapau", -"mapland", -"maple", -"mapo", -"mapper", -"mappist", -"mappy", -"mapwise", -"maqui", -"maquis", -"mar", -"marabou", -"maraca", -"maracan", -"marae", -"maral", -"marang", -"marara", -"mararie", -"marasca", -"maraud", -"marble", -"marbled", -"marbler", -"marbles", -"marbly", -"marc", -"marcel", -"march", -"marcher", -"marcid", -"marco", -"marconi", -"marcor", -"mardy", -"mare", -"maremma", -"marengo", -"marfire", -"margay", -"marge", -"margent", -"margin", -"margosa", -"marhala", -"maria", -"marid", -"marimba", -"marina", -"marine", -"mariner", -"mariola", -"maris", -"marish", -"marital", -"mark", -"marka", -"marked", -"marker", -"market", -"markhor", -"marking", -"markka", -"markman", -"markup", -"marl", -"marled", -"marler", -"marli", -"marlin", -"marline", -"marlite", -"marlock", -"marlpit", -"marly", -"marm", -"marmit", -"marmite", -"marmose", -"marmot", -"maro", -"marok", -"maroon", -"marplot", -"marque", -"marquee", -"marquis", -"marrano", -"marree", -"marrer", -"married", -"marrier", -"marron", -"marrot", -"marrow", -"marrowy", -"marry", -"marryer", -"marsh", -"marshal", -"marshy", -"marsoon", -"mart", -"martel", -"marten", -"martext", -"martial", -"martin", -"martite", -"martlet", -"martyr", -"martyry", -"maru", -"marvel", -"marver", -"mary", -"marybud", -"mas", -"masa", -"mascara", -"mascled", -"mascot", -"masculy", -"masdeu", -"mash", -"masha", -"mashal", -"masher", -"mashie", -"mashing", -"mashman", -"mashru", -"mashy", -"masjid", -"mask", -"masked", -"masker", -"maskoid", -"maslin", -"mason", -"masoned", -"masoner", -"masonic", -"masonry", -"masooka", -"masoola", -"masque", -"masquer", -"mass", -"massa", -"massage", -"masse", -"massel", -"masser", -"masseur", -"massier", -"massif", -"massily", -"massive", -"massoy", -"massula", -"massy", -"mast", -"mastaba", -"mastage", -"mastax", -"masted", -"master", -"mastery", -"mastful", -"mastic", -"mastiff", -"masting", -"mastman", -"mastoid", -"masty", -"masu", -"mat", -"mataco", -"matador", -"matai", -"matalan", -"matanza", -"matapan", -"matapi", -"matara", -"matax", -"match", -"matcher", -"matchy", -"mate", -"mately", -"mater", -"matey", -"math", -"mathes", -"matico", -"matin", -"matinal", -"matinee", -"mating", -"matins", -"matipo", -"matka", -"matless", -"matlow", -"matra", -"matral", -"matrass", -"matreed", -"matric", -"matris", -"matrix", -"matron", -"matross", -"matsu", -"matsuri", -"matta", -"mattaro", -"matte", -"matted", -"matter", -"mattery", -"matti", -"matting", -"mattock", -"mattoid", -"mattoir", -"mature", -"maturer", -"matweed", -"maty", -"matzo", -"matzoon", -"matzos", -"matzoth", -"mau", -"maud", -"maudle", -"maudlin", -"mauger", -"maugh", -"maul", -"mauler", -"mauley", -"mauling", -"maumet", -"maun", -"maund", -"maunder", -"maundy", -"maunge", -"mauther", -"mauve", -"mauvine", -"maux", -"mavis", -"maw", -"mawk", -"mawkish", -"mawky", -"mawp", -"maxilla", -"maxim", -"maxima", -"maximal", -"maximed", -"maximum", -"maximus", -"maxixe", -"maxwell", -"may", -"maya", -"maybe", -"maybush", -"maycock", -"mayday", -"mayfish", -"mayhap", -"mayhem", -"maynt", -"mayor", -"mayoral", -"maypop", -"maysin", -"mayten", -"mayweed", -"maza", -"mazame", -"mazard", -"maze", -"mazed", -"mazedly", -"mazeful", -"mazer", -"mazic", -"mazily", -"mazuca", -"mazuma", -"mazurka", -"mazut", -"mazy", -"mazzard", -"mbalolo", -"mbori", -"me", -"meable", -"mead", -"meader", -"meadow", -"meadowy", -"meager", -"meagre", -"meak", -"meal", -"mealer", -"mealies", -"mealily", -"mealman", -"mealy", -"mean", -"meander", -"meaned", -"meaner", -"meaning", -"meanish", -"meanly", -"meant", -"mease", -"measle", -"measled", -"measles", -"measly", -"measure", -"meat", -"meatal", -"meated", -"meatily", -"meatman", -"meatus", -"meaty", -"mecate", -"mecon", -"meconic", -"meconin", -"medal", -"medaled", -"medalet", -"meddle", -"meddler", -"media", -"mediacy", -"mediad", -"medial", -"median", -"mediant", -"mediate", -"medic", -"medical", -"medico", -"mediety", -"medimn", -"medimno", -"medino", -"medio", -"medium", -"medius", -"medlar", -"medley", -"medrick", -"medulla", -"medusal", -"medusan", -"meebos", -"meece", -"meed", -"meek", -"meeken", -"meekly", -"meered", -"meerkat", -"meese", -"meet", -"meeten", -"meeter", -"meeting", -"meetly", -"megabar", -"megaerg", -"megafog", -"megapod", -"megaron", -"megaton", -"megerg", -"megilp", -"megmho", -"megohm", -"megrim", -"mehalla", -"mehari", -"mehtar", -"meile", -"mein", -"meinie", -"meio", -"meiobar", -"meiosis", -"meiotic", -"meith", -"mel", -"mela", -"melada", -"melagra", -"melam", -"melamed", -"melange", -"melanic", -"melanin", -"melano", -"melasma", -"melch", -"meld", -"melder", -"meldrop", -"mele", -"melee", -"melena", -"melene", -"melenic", -"melic", -"melilot", -"meline", -"melisma", -"melitis", -"mell", -"mellate", -"mellay", -"meller", -"mellit", -"mellite", -"mellon", -"mellow", -"mellowy", -"melodia", -"melodic", -"melody", -"meloe", -"meloid", -"melon", -"melonry", -"melos", -"melosa", -"melt", -"meltage", -"melted", -"melter", -"melters", -"melting", -"melton", -"mem", -"member", -"membral", -"memento", -"meminna", -"memo", -"memoir", -"memoria", -"memory", -"men", -"menace", -"menacer", -"menacme", -"menage", -"menald", -"mend", -"mendee", -"mender", -"mending", -"mendole", -"mends", -"menfolk", -"meng", -"menhir", -"menial", -"meninx", -"menkind", -"mennom", -"mensa", -"mensal", -"mense", -"menses", -"mensk", -"mensual", -"mental", -"mentary", -"menthol", -"menthyl", -"mention", -"mentor", -"mentum", -"menu", -"meny", -"menyie", -"menzie", -"merbaby", -"mercal", -"mercer", -"mercery", -"merch", -"merchet", -"mercy", -"mere", -"merel", -"merely", -"merfold", -"merfolk", -"merge", -"merger", -"mergh", -"meriah", -"merice", -"meril", -"merism", -"merist", -"merit", -"merited", -"meriter", -"merk", -"merkhet", -"merkin", -"merl", -"merle", -"merlin", -"merlon", -"mermaid", -"merman", -"mero", -"merop", -"meropia", -"meros", -"merrily", -"merrow", -"merry", -"merse", -"mesa", -"mesad", -"mesail", -"mesal", -"mesally", -"mesange", -"mesarch", -"mescal", -"mese", -"mesem", -"mesenna", -"mesh", -"meshed", -"meshy", -"mesiad", -"mesial", -"mesian", -"mesic", -"mesilla", -"mesion", -"mesityl", -"mesne", -"meso", -"mesobar", -"mesode", -"mesodic", -"mesole", -"meson", -"mesonic", -"mesopic", -"mespil", -"mess", -"message", -"messan", -"messe", -"messer", -"messet", -"messily", -"messin", -"messing", -"messman", -"messor", -"messrs", -"messtin", -"messy", -"mestee", -"mester", -"mestiza", -"mestizo", -"mestome", -"met", -"meta", -"metad", -"metage", -"metal", -"metaler", -"metamer", -"metanym", -"metate", -"metayer", -"mete", -"metel", -"meteor", -"meter", -"methane", -"methene", -"mether", -"methid", -"methide", -"methine", -"method", -"methyl", -"metic", -"metier", -"metis", -"metochy", -"metonym", -"metope", -"metopic", -"metopon", -"metra", -"metreta", -"metrete", -"metria", -"metric", -"metrics", -"metrify", -"metrist", -"mettar", -"mettle", -"mettled", -"metusia", -"metze", -"meuse", -"meute", -"mew", -"meward", -"mewer", -"mewl", -"mewler", -"mezcal", -"mezuzah", -"mezzo", -"mho", -"mi", -"miamia", -"mian", -"miaow", -"miaower", -"mias", -"miasm", -"miasma", -"miasmal", -"miasmic", -"miaul", -"miauler", -"mib", -"mica", -"micate", -"mice", -"micelle", -"miche", -"micher", -"miching", -"micht", -"mick", -"mickle", -"mico", -"micrify", -"micro", -"microbe", -"microhm", -"micron", -"miction", -"mid", -"midday", -"midden", -"middle", -"middler", -"middy", -"mide", -"midge", -"midget", -"midgety", -"midgy", -"midiron", -"midland", -"midleg", -"midmain", -"midmorn", -"midmost", -"midnoon", -"midpit", -"midrash", -"midrib", -"midriff", -"mids", -"midship", -"midst", -"midtap", -"midvein", -"midward", -"midway", -"midweek", -"midwife", -"midwise", -"midyear", -"mien", -"miff", -"miffy", -"mig", -"might", -"mightnt", -"mighty", -"miglio", -"mignon", -"migrant", -"migrate", -"mihrab", -"mijl", -"mikado", -"mike", -"mikie", -"mil", -"mila", -"milady", -"milch", -"milcher", -"milchy", -"mild", -"milden", -"milder", -"mildew", -"mildewy", -"mildish", -"mildly", -"mile", -"mileage", -"miler", -"mileway", -"milfoil", -"milha", -"miliary", -"milieu", -"militia", -"milium", -"milk", -"milken", -"milker", -"milkily", -"milking", -"milkman", -"milksop", -"milky", -"mill", -"milla", -"millage", -"milldam", -"mille", -"milled", -"miller", -"millet", -"millful", -"milliad", -"millile", -"milline", -"milling", -"million", -"millman", -"milner", -"milo", -"milord", -"milpa", -"milreis", -"milsey", -"milsie", -"milt", -"milter", -"milty", -"milvine", -"mim", -"mima", -"mimbar", -"mimble", -"mime", -"mimeo", -"mimer", -"mimesis", -"mimetic", -"mimic", -"mimical", -"mimicry", -"mimine", -"mimly", -"mimmest", -"mimmock", -"mimmood", -"mimmoud", -"mimosis", -"mimp", -"mimsey", -"min", -"mina", -"minable", -"minar", -"minaret", -"minaway", -"mince", -"mincer", -"mincing", -"mind", -"minded", -"minder", -"mindful", -"minding", -"mine", -"miner", -"mineral", -"minery", -"mines", -"minette", -"ming", -"minge", -"mingle", -"mingler", -"mingy", -"minhag", -"minhah", -"miniate", -"minibus", -"minicam", -"minify", -"minikin", -"minim", -"minima", -"minimal", -"minimum", -"minimus", -"mining", -"minion", -"minish", -"minium", -"miniver", -"minivet", -"mink", -"minkery", -"minkish", -"minnie", -"minning", -"minnow", -"minny", -"mino", -"minoize", -"minor", -"minot", -"minster", -"mint", -"mintage", -"minter", -"mintman", -"minty", -"minuend", -"minuet", -"minus", -"minute", -"minuter", -"minutia", -"minx", -"minxish", -"miny", -"minyan", -"miqra", -"mir", -"mirach", -"miracle", -"mirador", -"mirage", -"miragy", -"mirate", -"mirbane", -"mird", -"mirdaha", -"mire", -"mirid", -"mirific", -"mirish", -"mirk", -"miro", -"mirror", -"mirrory", -"mirth", -"miry", -"mirza", -"misact", -"misadd", -"misaim", -"misally", -"misbias", -"misbill", -"misbind", -"misbode", -"misborn", -"misbusy", -"miscall", -"miscast", -"mischio", -"miscoin", -"miscook", -"miscrop", -"miscue", -"miscut", -"misdate", -"misdaub", -"misdeal", -"misdeed", -"misdeem", -"misdiet", -"misdo", -"misdoer", -"misdraw", -"mise", -"misease", -"misedit", -"miser", -"miserly", -"misery", -"misfare", -"misfile", -"misfire", -"misfit", -"misfond", -"misform", -"misgive", -"misgo", -"misgrow", -"mishap", -"mishmee", -"misjoin", -"miskeep", -"misken", -"miskill", -"misknow", -"misky", -"mislay", -"mislead", -"mislear", -"misled", -"mislest", -"mislike", -"mislive", -"mismade", -"mismake", -"mismate", -"mismove", -"misname", -"misobey", -"mispage", -"mispart", -"mispay", -"mispick", -"misplay", -"misput", -"misrate", -"misread", -"misrule", -"miss", -"missal", -"missay", -"misseem", -"missel", -"misset", -"missile", -"missing", -"mission", -"missis", -"missish", -"missive", -"misstay", -"misstep", -"missy", -"mist", -"mistake", -"mistbow", -"misted", -"mistell", -"mistend", -"mister", -"misterm", -"mistful", -"mistic", -"mistide", -"mistify", -"mistily", -"mistime", -"mistle", -"mistone", -"mistook", -"mistral", -"mistry", -"misturn", -"misty", -"misura", -"misuse", -"misuser", -"miswed", -"miswish", -"misword", -"misyoke", -"mite", -"miter", -"mitered", -"miterer", -"mitis", -"mitome", -"mitosis", -"mitotic", -"mitra", -"mitral", -"mitrate", -"mitre", -"mitrer", -"mitt", -"mitten", -"mitty", -"mity", -"miurus", -"mix", -"mixable", -"mixed", -"mixedly", -"mixen", -"mixer", -"mixhill", -"mixible", -"mixite", -"mixtion", -"mixture", -"mixy", -"mizmaze", -"mizzen", -"mizzle", -"mizzler", -"mizzly", -"mizzy", -"mneme", -"mnemic", -"mnesic", -"mnestic", -"mnioid", -"mo", -"moan", -"moanful", -"moaning", -"moat", -"mob", -"mobable", -"mobber", -"mobbish", -"mobbism", -"mobbist", -"mobby", -"mobcap", -"mobed", -"mobile", -"moble", -"moblike", -"mobship", -"mobsman", -"mobster", -"mocha", -"mochras", -"mock", -"mockado", -"mocker", -"mockery", -"mockful", -"mocmain", -"mocuck", -"modal", -"modally", -"mode", -"model", -"modeler", -"modena", -"modern", -"modest", -"modesty", -"modicum", -"modify", -"modish", -"modist", -"modiste", -"modius", -"modular", -"module", -"modulo", -"modulus", -"moellon", -"mofette", -"moff", -"mog", -"mogador", -"mogdad", -"moggan", -"moggy", -"mogo", -"moguey", -"moha", -"mohabat", -"mohair", -"mohar", -"mohel", -"moho", -"mohr", -"mohur", -"moider", -"moidore", -"moieter", -"moiety", -"moil", -"moiler", -"moiles", -"moiley", -"moiling", -"moineau", -"moio", -"moire", -"moise", -"moist", -"moisten", -"moistly", -"moisty", -"moit", -"moity", -"mojarra", -"mojo", -"moke", -"moki", -"moko", -"moksha", -"mokum", -"moky", -"mola", -"molal", -"molar", -"molary", -"molassy", -"molave", -"mold", -"molder", -"moldery", -"molding", -"moldy", -"mole", -"moleism", -"moler", -"molest", -"molimen", -"moline", -"molka", -"molland", -"molle", -"mollie", -"mollify", -"mollusk", -"molly", -"molman", -"moloid", -"moloker", -"molompi", -"molosse", -"molpe", -"molt", -"molten", -"molter", -"moly", -"mombin", -"momble", -"mome", -"moment", -"momenta", -"momism", -"momme", -"mommet", -"mommy", -"momo", -"mon", -"mona", -"monad", -"monadic", -"monaene", -"monal", -"monarch", -"monas", -"monase", -"monaxon", -"mone", -"monel", -"monepic", -"moner", -"moneral", -"moneran", -"moneric", -"moneron", -"monesia", -"money", -"moneyed", -"moneyer", -"mong", -"monger", -"mongery", -"mongler", -"mongrel", -"mongst", -"monial", -"moniker", -"monism", -"monist", -"monitor", -"monk", -"monkdom", -"monkery", -"monkess", -"monkey", -"monkish", -"monkism", -"monkly", -"monny", -"mono", -"monoazo", -"monocle", -"monocot", -"monodic", -"monody", -"monoid", -"monomer", -"mononch", -"monont", -"mononym", -"monose", -"monotic", -"monsoon", -"monster", -"montage", -"montana", -"montane", -"montant", -"monte", -"montem", -"month", -"monthly", -"monthon", -"montjoy", -"monton", -"monture", -"moo", -"mooch", -"moocha", -"moocher", -"mood", -"mooder", -"moodily", -"moodish", -"moodle", -"moody", -"mooing", -"mool", -"moolet", -"mools", -"moolum", -"moon", -"moonack", -"mooned", -"mooner", -"moonery", -"mooneye", -"moonily", -"mooning", -"moonish", -"moonite", -"moonja", -"moonjah", -"moonlet", -"moonlit", -"moonman", -"moonset", -"moonway", -"moony", -"moop", -"moor", -"moorage", -"mooring", -"moorish", -"moorman", -"moorn", -"moorpan", -"moors", -"moorup", -"moory", -"moosa", -"moose", -"moosey", -"moost", -"moot", -"mooter", -"mooth", -"mooting", -"mootman", -"mop", -"mopane", -"mope", -"moper", -"moph", -"mophead", -"moping", -"mopish", -"mopla", -"mopper", -"moppet", -"moppy", -"mopsy", -"mopus", -"mor", -"mora", -"moraine", -"moral", -"morale", -"morally", -"morals", -"morass", -"morassy", -"morat", -"morate", -"moray", -"morbid", -"morbify", -"mordant", -"mordent", -"mordore", -"more", -"moreen", -"moreish", -"morel", -"morella", -"morello", -"mores", -"morfrey", -"morg", -"morga", -"morgan", -"morgay", -"morgen", -"morglay", -"morgue", -"moric", -"moriche", -"morin", -"morinel", -"morion", -"morkin", -"morlop", -"mormaor", -"mormo", -"mormon", -"mormyr", -"mormyre", -"morn", -"morne", -"morned", -"morning", -"moro", -"moroc", -"morocco", -"moron", -"moroncy", -"morong", -"moronic", -"moronry", -"morose", -"morosis", -"morph", -"morphea", -"morphew", -"morphia", -"morphic", -"morphon", -"morris", -"morrow", -"morsal", -"morse", -"morsel", -"morsing", -"morsure", -"mort", -"mortal", -"mortar", -"mortary", -"morth", -"mortier", -"mortify", -"mortise", -"morula", -"morular", -"morule", -"morvin", -"morwong", -"mosaic", -"mosaist", -"mosette", -"mosey", -"mosker", -"mosque", -"moss", -"mossed", -"mosser", -"mossery", -"mossful", -"mossy", -"most", -"moste", -"mostly", -"mot", -"mote", -"moted", -"motel", -"moter", -"motet", -"motey", -"moth", -"mothed", -"mother", -"mothery", -"mothy", -"motif", -"motific", -"motile", -"motion", -"motive", -"motley", -"motmot", -"motor", -"motored", -"motoric", -"motory", -"mott", -"motte", -"mottle", -"mottled", -"mottler", -"motto", -"mottoed", -"motyka", -"mou", -"mouche", -"moud", -"moudie", -"moudy", -"mouflon", -"mouille", -"moujik", -"moul", -"mould", -"moulded", -"moule", -"moulin", -"mouls", -"moulter", -"mouly", -"mound", -"moundy", -"mount", -"mounted", -"mounter", -"moup", -"mourn", -"mourner", -"mouse", -"mouser", -"mousery", -"mousey", -"mousily", -"mousing", -"mousle", -"mousmee", -"mousse", -"moustoc", -"mousy", -"mout", -"moutan", -"mouth", -"mouthed", -"mouther", -"mouthy", -"mouton", -"mouzah", -"movable", -"movably", -"movant", -"move", -"mover", -"movie", -"moving", -"mow", -"mowable", -"mowana", -"mowburn", -"mowch", -"mowcht", -"mower", -"mowha", -"mowie", -"mowing", -"mowland", -"mown", -"mowra", -"mowrah", -"mowse", -"mowt", -"mowth", -"moxa", -"moy", -"moyen", -"moyenne", -"moyite", -"moyle", -"moyo", -"mozing", -"mpret", -"mu", -"muang", -"mubarat", -"mucago", -"mucaro", -"mucedin", -"much", -"muchly", -"mucic", -"mucid", -"mucific", -"mucigen", -"mucin", -"muck", -"mucker", -"mucket", -"muckite", -"muckle", -"muckman", -"muckna", -"mucksy", -"mucky", -"mucluc", -"mucoid", -"muconic", -"mucopus", -"mucor", -"mucosa", -"mucosal", -"mucose", -"mucous", -"mucro", -"mucus", -"mucusin", -"mud", -"mudar", -"mudbank", -"mudcap", -"mudd", -"mudde", -"mudden", -"muddify", -"muddily", -"mudding", -"muddish", -"muddle", -"muddler", -"muddy", -"mudee", -"mudfish", -"mudflow", -"mudhead", -"mudhole", -"mudir", -"mudiria", -"mudland", -"mudlark", -"mudless", -"mudra", -"mudsill", -"mudweed", -"mudwort", -"muermo", -"muezzin", -"muff", -"muffed", -"muffet", -"muffin", -"muffish", -"muffle", -"muffled", -"muffler", -"mufflin", -"muffy", -"mufti", -"mufty", -"mug", -"muga", -"mugful", -"mugg", -"mugger", -"mugget", -"muggily", -"muggins", -"muggish", -"muggles", -"muggy", -"mugient", -"mugweed", -"mugwort", -"mugwump", -"muid", -"muir", -"muist", -"mukluk", -"muktar", -"mukti", -"mulatta", -"mulatto", -"mulch", -"mulcher", -"mulct", -"mulder", -"mule", -"muleman", -"muleta", -"muletta", -"muley", -"mulga", -"mulier", -"mulish", -"mulism", -"mulita", -"mulk", -"mull", -"mulla", -"mullah", -"mullar", -"mullein", -"muller", -"mullet", -"mullets", -"mulley", -"mullid", -"mullion", -"mullite", -"mullock", -"mulloid", -"mulmul", -"mulse", -"mulsify", -"mult", -"multum", -"multure", -"mum", -"mumble", -"mumbler", -"mummer", -"mummery", -"mummick", -"mummied", -"mummify", -"mumming", -"mummy", -"mumness", -"mump", -"mumper", -"mumpish", -"mumps", -"mun", -"munch", -"muncher", -"munchet", -"mund", -"mundane", -"mundic", -"mundify", -"mundil", -"mundle", -"mung", -"munga", -"munge", -"mungey", -"mungo", -"mungofa", -"munguba", -"mungy", -"munific", -"munity", -"munj", -"munjeet", -"munnion", -"munshi", -"munt", -"muntin", -"muntjac", -"mura", -"murage", -"mural", -"muraled", -"murally", -"murchy", -"murder", -"murdrum", -"mure", -"murex", -"murexan", -"murga", -"murgavi", -"murgeon", -"muriate", -"muricid", -"murid", -"murine", -"murinus", -"muriti", -"murium", -"murk", -"murkily", -"murkish", -"murkly", -"murky", -"murlin", -"murly", -"murmur", -"murphy", -"murra", -"murrain", -"murre", -"murrey", -"murrina", -"murshid", -"muruxi", -"murva", -"murza", -"musal", -"musang", -"musar", -"muscade", -"muscat", -"muscid", -"muscle", -"muscled", -"muscly", -"muscoid", -"muscone", -"muscose", -"muscot", -"muscovy", -"muscule", -"muse", -"mused", -"museful", -"museist", -"muser", -"musery", -"musette", -"museum", -"mush", -"musha", -"mushaa", -"mushed", -"musher", -"mushily", -"mushla", -"mushru", -"mushy", -"music", -"musical", -"musico", -"musie", -"musily", -"musimon", -"musing", -"musk", -"muskat", -"muskeg", -"musket", -"muskie", -"muskish", -"muskrat", -"musky", -"muslin", -"musnud", -"musquaw", -"musrol", -"muss", -"mussal", -"mussel", -"mussily", -"mussuk", -"mussy", -"must", -"mustang", -"mustard", -"mustee", -"muster", -"mustify", -"mustily", -"mustnt", -"musty", -"muta", -"mutable", -"mutably", -"mutage", -"mutant", -"mutase", -"mutate", -"mutch", -"mute", -"mutedly", -"mutely", -"muth", -"mutic", -"mutiny", -"mutism", -"mutist", -"mutive", -"mutsje", -"mutt", -"mutter", -"mutton", -"muttony", -"mutual", -"mutuary", -"mutule", -"mutuum", -"mux", -"muyusa", -"muzhik", -"muzz", -"muzzily", -"muzzle", -"muzzler", -"muzzy", -"my", -"myal", -"myalgia", -"myalgic", -"myalism", -"myall", -"myarian", -"myatony", -"mycele", -"mycelia", -"mycoid", -"mycose", -"mycosin", -"mycosis", -"mycotic", -"mydine", -"myelic", -"myelin", -"myeloic", -"myeloid", -"myeloma", -"myelon", -"mygale", -"mygalid", -"myiasis", -"myiosis", -"myitis", -"mykiss", -"mymarid", -"myna", -"myocele", -"myocyte", -"myogen", -"myogram", -"myoid", -"myology", -"myoma", -"myomere", -"myoneme", -"myope", -"myophan", -"myopia", -"myopic", -"myops", -"myopy", -"myosin", -"myosis", -"myosote", -"myotic", -"myotome", -"myotomy", -"myotony", -"myowun", -"myoxine", -"myrcene", -"myrcia", -"myriad", -"myriare", -"myrica", -"myricin", -"myricyl", -"myringa", -"myron", -"myronic", -"myrosin", -"myrrh", -"myrrhed", -"myrrhic", -"myrrhol", -"myrrhy", -"myrtal", -"myrtle", -"myrtol", -"mysel", -"myself", -"mysell", -"mysid", -"mysoid", -"mysost", -"myst", -"mystax", -"mystery", -"mystes", -"mystic", -"mystify", -"myth", -"mythify", -"mythism", -"mythist", -"mythize", -"mythos", -"mythus", -"mytilid", -"myxa", -"myxemia", -"myxo", -"myxoid", -"myxoma", -"myxopod", -"myzont", -"n", -"na", -"naa", -"naam", -"nab", -"nabak", -"nabber", -"nabk", -"nabla", -"nable", -"nabob", -"nabobry", -"nabs", -"nacarat", -"nace", -"nacelle", -"nach", -"nachani", -"nacket", -"nacre", -"nacred", -"nacrine", -"nacrite", -"nacrous", -"nacry", -"nadder", -"nadir", -"nadiral", -"nae", -"naebody", -"naegate", -"nael", -"naether", -"nag", -"naga", -"nagaika", -"nagana", -"nagara", -"nagger", -"naggin", -"nagging", -"naggish", -"naggle", -"naggly", -"naggy", -"naght", -"nagmaal", -"nagman", -"nagnag", -"nagnail", -"nagor", -"nagsman", -"nagster", -"nagual", -"naiad", -"naiant", -"naid", -"naif", -"naifly", -"naig", -"naigie", -"naik", -"nail", -"nailbin", -"nailer", -"nailery", -"nailing", -"nailrod", -"naily", -"nain", -"nainsel", -"naio", -"naipkin", -"nairy", -"nais", -"naish", -"naither", -"naive", -"naively", -"naivete", -"naivety", -"nak", -"nake", -"naked", -"nakedly", -"naker", -"nakhod", -"nakhoda", -"nako", -"nakong", -"nakoo", -"nallah", -"nam", -"namable", -"namaqua", -"namaz", -"namda", -"name", -"namely", -"namer", -"naming", -"nammad", -"nan", -"nana", -"nancy", -"nandi", -"nandine", -"nandow", -"nandu", -"nane", -"nanes", -"nanga", -"nanism", -"nankeen", -"nankin", -"nanny", -"nanoid", -"nanpie", -"nant", -"nantle", -"naology", -"naos", -"nap", -"napa", -"napal", -"napalm", -"nape", -"napead", -"naperer", -"napery", -"naphtha", -"naphtho", -"naphtol", -"napkin", -"napless", -"napoo", -"nappe", -"napped", -"napper", -"napping", -"nappy", -"napron", -"napu", -"nar", -"narcism", -"narcist", -"narcoma", -"narcose", -"narcous", -"nard", -"nardine", -"nardoo", -"nares", -"nargil", -"narial", -"naric", -"narica", -"narine", -"nark", -"narky", -"narr", -"narra", -"narras", -"narrate", -"narrow", -"narrowy", -"narthex", -"narwhal", -"nary", -"nasab", -"nasal", -"nasalis", -"nasally", -"nasard", -"nascent", -"nasch", -"nash", -"nashgab", -"nashgob", -"nasi", -"nasial", -"nasion", -"nasitis", -"nasrol", -"nast", -"nastic", -"nastika", -"nastily", -"nasty", -"nasus", -"nasute", -"nasutus", -"nat", -"nataka", -"natal", -"natals", -"natant", -"natator", -"natch", -"nates", -"nathe", -"nather", -"nation", -"native", -"natr", -"natrium", -"natron", -"natter", -"nattily", -"nattle", -"natty", -"natuary", -"natural", -"nature", -"naucrar", -"nauger", -"naught", -"naughty", -"naumk", -"naunt", -"nauntle", -"nausea", -"naut", -"nautch", -"nauther", -"nautic", -"nautics", -"naval", -"navally", -"navar", -"navarch", -"nave", -"navel", -"naveled", -"navet", -"navette", -"navew", -"navite", -"navvy", -"navy", -"naw", -"nawab", -"nawt", -"nay", -"nayaur", -"naysay", -"nayward", -"nayword", -"naze", -"nazim", -"nazir", -"ne", -"nea", -"neal", -"neanic", -"neap", -"neaped", -"nearby", -"nearest", -"nearish", -"nearly", -"neat", -"neaten", -"neath", -"neatify", -"neatly", -"neb", -"neback", -"nebbed", -"nebbuck", -"nebbuk", -"nebby", -"nebel", -"nebris", -"nebula", -"nebulae", -"nebular", -"nebule", -"neck", -"neckar", -"necked", -"necker", -"neckful", -"necking", -"necklet", -"necktie", -"necrose", -"nectar", -"nectary", -"nedder", -"neddy", -"nee", -"neebor", -"neebour", -"need", -"needer", -"needful", -"needham", -"needily", -"needing", -"needle", -"needled", -"needler", -"needles", -"needly", -"needs", -"needy", -"neeger", -"neeld", -"neele", -"neem", -"neep", -"neepour", -"neer", -"neese", -"neet", -"neetup", -"neeze", -"nef", -"nefast", -"neffy", -"neftgil", -"negate", -"negator", -"neger", -"neglect", -"negrine", -"negro", -"negus", -"nei", -"neif", -"neigh", -"neigher", -"neiper", -"neist", -"neither", -"nekton", -"nelson", -"nema", -"nematic", -"nemeses", -"nemesic", -"nemoral", -"nenta", -"neo", -"neocyte", -"neogamy", -"neolith", -"neology", -"neon", -"neonate", -"neorama", -"neossin", -"neoteny", -"neotype", -"neoza", -"nep", -"neper", -"nephele", -"nephesh", -"nephew", -"nephria", -"nephric", -"nephron", -"nephros", -"nepman", -"nepotal", -"nepote", -"nepotic", -"nereite", -"nerine", -"neritic", -"nerval", -"nervate", -"nerve", -"nerver", -"nervid", -"nervily", -"nervine", -"nerving", -"nervish", -"nervism", -"nervose", -"nervous", -"nervule", -"nervure", -"nervy", -"nese", -"nesh", -"neshly", -"nesiote", -"ness", -"nest", -"nestage", -"nester", -"nestful", -"nestle", -"nestler", -"nesty", -"net", -"netball", -"netbush", -"netcha", -"nete", -"neter", -"netful", -"neth", -"nether", -"neti", -"netleaf", -"netlike", -"netman", -"netop", -"netsman", -"netsuke", -"netted", -"netter", -"netting", -"nettle", -"nettler", -"nettly", -"netty", -"netwise", -"network", -"neuma", -"neume", -"neumic", -"neurad", -"neural", -"neurale", -"neuric", -"neurin", -"neurine", -"neurism", -"neurite", -"neuroid", -"neuroma", -"neuron", -"neurone", -"neurula", -"neuter", -"neutral", -"neutron", -"neve", -"nevel", -"never", -"nevo", -"nevoid", -"nevoy", -"nevus", -"new", -"newcal", -"newcome", -"newel", -"newelty", -"newing", -"newings", -"newish", -"newly", -"newness", -"news", -"newsboy", -"newsful", -"newsman", -"newsy", -"newt", -"newtake", -"newton", -"nexal", -"next", -"nextly", -"nexum", -"nexus", -"neyanda", -"ngai", -"ngaio", -"ngapi", -"ni", -"niacin", -"niata", -"nib", -"nibbana", -"nibbed", -"nibber", -"nibble", -"nibbler", -"nibby", -"niblick", -"niblike", -"nibong", -"nibs", -"nibsome", -"nice", -"niceish", -"nicely", -"nicety", -"niche", -"nicher", -"nick", -"nickel", -"nicker", -"nickey", -"nicking", -"nickle", -"nicky", -"nicolo", -"nicotia", -"nicotic", -"nictate", -"nid", -"nidal", -"nidana", -"niddick", -"niddle", -"nide", -"nidge", -"nidget", -"nidgety", -"nidi", -"nidify", -"niding", -"nidor", -"nidulus", -"nidus", -"niece", -"nielled", -"niello", -"niepa", -"nieve", -"nieveta", -"nife", -"niffer", -"nific", -"nifle", -"nifling", -"nifty", -"nig", -"niggard", -"nigger", -"niggery", -"niggle", -"niggler", -"niggly", -"nigh", -"nighly", -"night", -"nighted", -"nightie", -"nightly", -"nights", -"nignay", -"nignye", -"nigori", -"nigre", -"nigrify", -"nigrine", -"nigrous", -"nigua", -"nikau", -"nil", -"nilgai", -"nim", -"nimb", -"nimbed", -"nimbi", -"nimble", -"nimbly", -"nimbose", -"nimbus", -"nimiety", -"niminy", -"nimious", -"nimmer", -"nimshi", -"nincom", -"nine", -"ninepin", -"nineted", -"ninety", -"ninny", -"ninon", -"ninth", -"ninthly", -"nintu", -"ninut", -"niobate", -"niobic", -"niobite", -"niobium", -"niobous", -"niog", -"niota", -"nip", -"nipa", -"nipper", -"nippers", -"nippily", -"nipping", -"nipple", -"nippy", -"nipter", -"nirles", -"nirvana", -"nisei", -"nishiki", -"nisnas", -"nispero", -"nisse", -"nisus", -"nit", -"nitch", -"nitency", -"niter", -"nitered", -"nither", -"nithing", -"nitid", -"nito", -"niton", -"nitrate", -"nitric", -"nitride", -"nitrify", -"nitrile", -"nitrite", -"nitro", -"nitrous", -"nitryl", -"nitter", -"nitty", -"nitwit", -"nival", -"niveous", -"nix", -"nixie", -"niyoga", -"nizam", -"nizamut", -"nizy", -"njave", -"no", -"noa", -"nob", -"nobber", -"nobbily", -"nobble", -"nobbler", -"nobbut", -"nobby", -"noble", -"nobley", -"nobly", -"nobody", -"nobs", -"nocake", -"nocent", -"nock", -"nocket", -"nocktat", -"noctuid", -"noctule", -"nocturn", -"nocuity", -"nocuous", -"nod", -"nodal", -"nodated", -"nodder", -"nodding", -"noddle", -"noddy", -"node", -"noded", -"nodi", -"nodiak", -"nodical", -"nodose", -"nodous", -"nodular", -"nodule", -"noduled", -"nodulus", -"nodus", -"noel", -"noetic", -"noetics", -"nog", -"nogada", -"nogal", -"noggen", -"noggin", -"nogging", -"noghead", -"nohow", -"noil", -"noilage", -"noiler", -"noily", -"noint", -"noir", -"noise", -"noisily", -"noisome", -"noisy", -"nokta", -"noll", -"nolle", -"nolo", -"noma", -"nomad", -"nomadic", -"nomancy", -"nomarch", -"nombril", -"nome", -"nomial", -"nomic", -"nomina", -"nominal", -"nominee", -"nominy", -"nomism", -"nomisma", -"nomos", -"non", -"nonacid", -"nonact", -"nonage", -"nonagon", -"nonaid", -"nonair", -"nonane", -"nonary", -"nonbase", -"nonce", -"noncock", -"noncom", -"noncome", -"noncon", -"nonda", -"nondo", -"none", -"nonego", -"nonene", -"nonent", -"nonepic", -"nones", -"nonet", -"nonevil", -"nonfact", -"nonfarm", -"nonfat", -"nonfood", -"nonform", -"nonfrat", -"nongas", -"nongod", -"nongold", -"nongray", -"nongrey", -"nonhero", -"nonic", -"nonion", -"nonius", -"nonjury", -"nonlife", -"nonly", -"nonnant", -"nonnat", -"nonoic", -"nonoily", -"nonomad", -"nonpaid", -"nonpar", -"nonpeak", -"nonplus", -"nonpoet", -"nonport", -"nonrun", -"nonsale", -"nonsane", -"nonself", -"nonsine", -"nonskid", -"nonslip", -"nonstop", -"nonsuit", -"nontan", -"nontax", -"nonterm", -"nonuple", -"nonuse", -"nonuser", -"nonwar", -"nonya", -"nonyl", -"nonylic", -"nonzero", -"noodle", -"nook", -"nooked", -"nookery", -"nooking", -"nooklet", -"nooky", -"noology", -"noon", -"noonday", -"nooning", -"noonlit", -"noop", -"noose", -"nooser", -"nopal", -"nopalry", -"nope", -"nor", -"norard", -"norate", -"noreast", -"norelin", -"norgine", -"nori", -"noria", -"norie", -"norimon", -"norite", -"norland", -"norm", -"norma", -"normal", -"norsel", -"north", -"norther", -"norward", -"norwest", -"nose", -"nosean", -"nosed", -"nosegay", -"noser", -"nosey", -"nosine", -"nosing", -"nosism", -"nostic", -"nostril", -"nostrum", -"nosy", -"not", -"notable", -"notably", -"notaeal", -"notaeum", -"notal", -"notan", -"notary", -"notate", -"notator", -"notch", -"notched", -"notchel", -"notcher", -"notchy", -"note", -"noted", -"notedly", -"notekin", -"notelet", -"noter", -"nother", -"nothing", -"nothous", -"notice", -"noticer", -"notify", -"notion", -"notitia", -"notour", -"notself", -"notum", -"nougat", -"nought", -"noun", -"nounal", -"nounize", -"noup", -"nourice", -"nourish", -"nous", -"nouther", -"nova", -"novalia", -"novate", -"novator", -"novcic", -"novel", -"novelet", -"novella", -"novelly", -"novelry", -"novelty", -"novem", -"novena", -"novene", -"novice", -"novity", -"now", -"nowaday", -"noway", -"noways", -"nowed", -"nowel", -"nowhat", -"nowhen", -"nowhere", -"nowhit", -"nowise", -"nowness", -"nowt", -"nowy", -"noxa", -"noxal", -"noxally", -"noxious", -"noy", -"noyade", -"noyau", -"nozzle", -"nozzler", -"nth", -"nu", -"nuance", -"nub", -"nubbin", -"nubble", -"nubbly", -"nubby", -"nubia", -"nubile", -"nucal", -"nucha", -"nuchal", -"nucin", -"nucleal", -"nuclear", -"nuclei", -"nuclein", -"nucleon", -"nucleus", -"nuclide", -"nucule", -"nuculid", -"nudate", -"nuddle", -"nude", -"nudely", -"nudge", -"nudger", -"nudiped", -"nudish", -"nudism", -"nudist", -"nudity", -"nugator", -"nuggar", -"nugget", -"nuggety", -"nugify", -"nuke", -"nul", -"null", -"nullah", -"nullify", -"nullism", -"nullity", -"nullo", -"numb", -"number", -"numbing", -"numble", -"numbles", -"numbly", -"numda", -"numdah", -"numen", -"numeral", -"numero", -"nummary", -"nummi", -"nummus", -"numud", -"nun", -"nunatak", -"nunbird", -"nunch", -"nuncio", -"nuncle", -"nundine", -"nunhood", -"nunky", -"nunlet", -"nunlike", -"nunnari", -"nunnery", -"nunni", -"nunnify", -"nunnish", -"nunship", -"nuptial", -"nuque", -"nuraghe", -"nurhag", -"nurly", -"nurse", -"nurser", -"nursery", -"nursing", -"nursle", -"nursy", -"nurture", -"nusfiah", -"nut", -"nutant", -"nutate", -"nutcake", -"nutgall", -"nuthook", -"nutlet", -"nutlike", -"nutmeg", -"nutpick", -"nutria", -"nutrice", -"nutrify", -"nutseed", -"nutted", -"nutter", -"nuttery", -"nuttily", -"nutting", -"nuttish", -"nutty", -"nuzzer", -"nuzzle", -"nyanza", -"nye", -"nylast", -"nylon", -"nymil", -"nymph", -"nympha", -"nymphae", -"nymphal", -"nymphet", -"nymphic", -"nymphid", -"nymphly", -"nyxis", -"o", -"oadal", -"oaf", -"oafdom", -"oafish", -"oak", -"oaken", -"oaklet", -"oaklike", -"oakling", -"oakum", -"oakweb", -"oakwood", -"oaky", -"oam", -"oar", -"oarage", -"oarcock", -"oared", -"oarfish", -"oarhole", -"oarial", -"oaric", -"oaritic", -"oaritis", -"oarium", -"oarless", -"oarlike", -"oarlock", -"oarlop", -"oarman", -"oarsman", -"oarweed", -"oary", -"oasal", -"oasean", -"oases", -"oasis", -"oasitic", -"oast", -"oat", -"oatbin", -"oatcake", -"oatear", -"oaten", -"oatfowl", -"oath", -"oathay", -"oathed", -"oathful", -"oathlet", -"oatland", -"oatlike", -"oatmeal", -"oatseed", -"oaty", -"oban", -"obclude", -"obe", -"obeah", -"obeche", -"obeism", -"obelia", -"obeliac", -"obelial", -"obelion", -"obelisk", -"obelism", -"obelize", -"obelus", -"obese", -"obesely", -"obesity", -"obex", -"obey", -"obeyer", -"obi", -"obispo", -"obit", -"obitual", -"object", -"objure", -"oblate", -"obley", -"oblige", -"obliged", -"obligee", -"obliger", -"obligor", -"oblique", -"oblong", -"obloquy", -"oboe", -"oboist", -"obol", -"obolary", -"obole", -"obolet", -"obolus", -"oboval", -"obovate", -"obovoid", -"obscene", -"obscure", -"obsede", -"obsequy", -"observe", -"obsess", -"obtain", -"obtect", -"obtest", -"obtrude", -"obtund", -"obtuse", -"obverse", -"obvert", -"obviate", -"obvious", -"obvolve", -"ocarina", -"occamy", -"occiput", -"occlude", -"occluse", -"occult", -"occupy", -"occur", -"ocean", -"oceaned", -"oceanet", -"oceanic", -"ocellar", -"ocelli", -"ocellus", -"oceloid", -"ocelot", -"och", -"ochava", -"ochavo", -"ocher", -"ochery", -"ochone", -"ochrea", -"ochro", -"ochroid", -"ochrous", -"ocht", -"ock", -"oclock", -"ocote", -"ocque", -"ocracy", -"ocrea", -"ocreate", -"octad", -"octadic", -"octagon", -"octan", -"octane", -"octant", -"octapla", -"octarch", -"octary", -"octaval", -"octave", -"octavic", -"octavo", -"octene", -"octet", -"octic", -"octine", -"octoad", -"octoate", -"octofid", -"octoic", -"octoid", -"octonal", -"octoon", -"octoped", -"octopi", -"octopod", -"octopus", -"octose", -"octoyl", -"octroi", -"octroy", -"octuor", -"octuple", -"octuply", -"octyl", -"octyne", -"ocuby", -"ocular", -"oculary", -"oculate", -"oculist", -"oculus", -"od", -"oda", -"odacoid", -"odal", -"odalisk", -"odaller", -"odalman", -"odd", -"oddish", -"oddity", -"oddlegs", -"oddly", -"oddman", -"oddment", -"oddness", -"odds", -"oddsman", -"ode", -"odel", -"odelet", -"odeon", -"odeum", -"odic", -"odinite", -"odious", -"odist", -"odium", -"odology", -"odontic", -"odoom", -"odor", -"odorant", -"odorate", -"odored", -"odorful", -"odorize", -"odorous", -"odso", -"odum", -"odyl", -"odylic", -"odylism", -"odylist", -"odylize", -"oe", -"oecist", -"oecus", -"oenin", -"oenolin", -"oenomel", -"oer", -"oersted", -"oes", -"oestrid", -"oestrin", -"oestrum", -"oestrus", -"of", -"off", -"offal", -"offbeat", -"offcast", -"offcome", -"offcut", -"offend", -"offense", -"offer", -"offeree", -"offerer", -"offeror", -"offhand", -"office", -"officer", -"offing", -"offish", -"offlet", -"offlook", -"offscum", -"offset", -"offtake", -"offtype", -"offward", -"oflete", -"oft", -"often", -"oftens", -"ofter", -"oftest", -"oftly", -"oftness", -"ofttime", -"ogaire", -"ogam", -"ogamic", -"ogdoad", -"ogdoas", -"ogee", -"ogeed", -"ogham", -"oghamic", -"ogival", -"ogive", -"ogived", -"ogle", -"ogler", -"ogmic", -"ogre", -"ogreish", -"ogreism", -"ogress", -"ogrish", -"ogrism", -"ogtiern", -"ogum", -"oh", -"ohelo", -"ohia", -"ohm", -"ohmage", -"ohmic", -"oho", -"ohoy", -"oidioid", -"oii", -"oil", -"oilbird", -"oilcan", -"oilcoat", -"oilcup", -"oildom", -"oiled", -"oiler", -"oilery", -"oilfish", -"oilhole", -"oilily", -"oilless", -"oillet", -"oillike", -"oilman", -"oilseed", -"oilskin", -"oilway", -"oily", -"oilyish", -"oime", -"oinomel", -"oint", -"oisin", -"oitava", -"oka", -"okapi", -"okee", -"okenite", -"oket", -"oki", -"okia", -"okonite", -"okra", -"okrug", -"olam", -"olamic", -"old", -"olden", -"older", -"oldish", -"oldland", -"oldness", -"oldster", -"oldwife", -"oleana", -"olease", -"oleate", -"olefin", -"olefine", -"oleic", -"olein", -"olena", -"olenid", -"olent", -"oleo", -"oleose", -"oleous", -"olfact", -"olfacty", -"oliban", -"olid", -"oligist", -"olio", -"olitory", -"oliva", -"olivary", -"olive", -"olived", -"olivet", -"olivil", -"olivile", -"olivine", -"olla", -"ollamh", -"ollapod", -"ollock", -"olm", -"ologist", -"ology", -"olomao", -"olona", -"oloroso", -"olpe", -"oltonde", -"oltunna", -"olycook", -"olykoek", -"om", -"omagra", -"omalgia", -"omao", -"omasum", -"omber", -"omega", -"omegoid", -"omelet", -"omen", -"omened", -"omental", -"omentum", -"omer", -"omicron", -"omina", -"ominous", -"omit", -"omitis", -"omitter", -"omlah", -"omneity", -"omniana", -"omnibus", -"omnific", -"omnify", -"omnist", -"omnium", -"on", -"ona", -"onager", -"onagra", -"onanism", -"onanist", -"onca", -"once", -"oncetta", -"oncia", -"oncin", -"oncome", -"oncosis", -"oncost", -"ondatra", -"ondine", -"ondy", -"one", -"onefold", -"onegite", -"onehow", -"oneiric", -"oneism", -"onement", -"oneness", -"oner", -"onerary", -"onerous", -"onery", -"oneself", -"onetime", -"oneyer", -"onfall", -"onflow", -"ongaro", -"ongoing", -"onicolo", -"onion", -"onionet", -"oniony", -"onium", -"onkos", -"onlay", -"onlepy", -"onliest", -"onlook", -"only", -"onmarch", -"onrush", -"ons", -"onset", -"onshore", -"onside", -"onsight", -"onstand", -"onstead", -"onsweep", -"ontal", -"onto", -"onus", -"onward", -"onwards", -"onycha", -"onychia", -"onychin", -"onym", -"onymal", -"onymity", -"onymize", -"onymous", -"onymy", -"onyx", -"onyxis", -"onza", -"ooblast", -"oocyst", -"oocyte", -"oodles", -"ooecial", -"ooecium", -"oofbird", -"ooftish", -"oofy", -"oogamy", -"oogeny", -"ooglea", -"oogone", -"oograph", -"ooid", -"ooidal", -"oolak", -"oolemma", -"oolite", -"oolitic", -"oolly", -"oologic", -"oology", -"oolong", -"oomancy", -"oometer", -"oometry", -"oons", -"oont", -"oopak", -"oophore", -"oophyte", -"ooplasm", -"ooplast", -"oopod", -"oopodal", -"oorali", -"oord", -"ooscope", -"ooscopy", -"oosperm", -"oospore", -"ootheca", -"ootid", -"ootype", -"ooze", -"oozily", -"oozooid", -"oozy", -"opacate", -"opacify", -"opacite", -"opacity", -"opacous", -"opah", -"opal", -"opaled", -"opaline", -"opalish", -"opalize", -"opaloid", -"opaque", -"ope", -"opelet", -"open", -"opener", -"opening", -"openly", -"opera", -"operae", -"operand", -"operant", -"operate", -"opercle", -"operose", -"ophic", -"ophioid", -"ophite", -"ophitic", -"ophryon", -"opianic", -"opianyl", -"opiate", -"opiatic", -"opiism", -"opinant", -"opine", -"opiner", -"opinion", -"opium", -"opossum", -"oppidan", -"oppose", -"opposed", -"opposer", -"opposit", -"oppress", -"oppugn", -"opsonic", -"opsonin", -"opsy", -"opt", -"optable", -"optably", -"optant", -"optate", -"optic", -"optical", -"opticon", -"optics", -"optimal", -"optime", -"optimum", -"option", -"optive", -"opulent", -"opulus", -"opus", -"oquassa", -"or", -"ora", -"orach", -"oracle", -"orad", -"orage", -"oral", -"oraler", -"oralism", -"oralist", -"orality", -"oralize", -"orally", -"oralogy", -"orang", -"orange", -"oranger", -"orangey", -"orant", -"orarian", -"orarion", -"orarium", -"orary", -"orate", -"oration", -"orator", -"oratory", -"oratrix", -"orb", -"orbed", -"orbic", -"orbical", -"orbicle", -"orbific", -"orbit", -"orbital", -"orbitar", -"orbite", -"orbless", -"orblet", -"orby", -"orc", -"orcanet", -"orcein", -"orchard", -"orchat", -"orchel", -"orchic", -"orchid", -"orchil", -"orcin", -"orcinol", -"ordain", -"ordeal", -"order", -"ordered", -"orderer", -"orderly", -"ordinal", -"ordinar", -"ordinee", -"ordines", -"ordu", -"ordure", -"ore", -"oread", -"orectic", -"orellin", -"oreman", -"orenda", -"oreweed", -"orewood", -"orexis", -"orf", -"orfgild", -"organ", -"organal", -"organdy", -"organer", -"organic", -"organon", -"organry", -"organum", -"orgasm", -"orgeat", -"orgia", -"orgiac", -"orgiacs", -"orgiasm", -"orgiast", -"orgic", -"orgue", -"orgy", -"orgyia", -"oribi", -"oriel", -"oriency", -"orient", -"orifice", -"oriform", -"origan", -"origin", -"orignal", -"orihon", -"orillon", -"oriole", -"orison", -"oristic", -"orle", -"orlean", -"orlet", -"orlo", -"orlop", -"ormer", -"ormolu", -"orna", -"ornate", -"ornery", -"ornis", -"ornoite", -"oroanal", -"orogen", -"orogeny", -"oroide", -"orology", -"oronoco", -"orotund", -"orphan", -"orpheon", -"orpheum", -"orphrey", -"orpine", -"orrery", -"orrhoid", -"orris", -"orsel", -"orselle", -"ort", -"ortalid", -"ortet", -"orthal", -"orthian", -"orthic", -"orthid", -"orthite", -"ortho", -"orthose", -"orthron", -"ortiga", -"ortive", -"ortolan", -"ortygan", -"ory", -"oryssid", -"os", -"osamin", -"osamine", -"osazone", -"oscella", -"oscheal", -"oscin", -"oscine", -"oscnode", -"oscular", -"oscule", -"osculum", -"ose", -"osela", -"oshac", -"oside", -"osier", -"osiered", -"osiery", -"osmate", -"osmatic", -"osmesis", -"osmetic", -"osmic", -"osmin", -"osmina", -"osmious", -"osmium", -"osmose", -"osmosis", -"osmotic", -"osmous", -"osmund", -"osone", -"osophy", -"osprey", -"ossal", -"osse", -"ossein", -"osselet", -"osseous", -"ossicle", -"ossific", -"ossify", -"ossuary", -"osteal", -"ostein", -"ostemia", -"ostent", -"osteoid", -"osteoma", -"ostial", -"ostiary", -"ostiate", -"ostiole", -"ostitis", -"ostium", -"ostmark", -"ostosis", -"ostrich", -"otalgia", -"otalgic", -"otalgy", -"otarian", -"otarine", -"otary", -"otate", -"other", -"othmany", -"otiant", -"otiatry", -"otic", -"otidine", -"otidium", -"otiose", -"otitic", -"otitis", -"otkon", -"otocyst", -"otolite", -"otolith", -"otology", -"otosis", -"ototomy", -"ottar", -"otter", -"otterer", -"otto", -"oturia", -"ouabain", -"ouabaio", -"ouabe", -"ouakari", -"ouch", -"ouenite", -"ouf", -"ough", -"ought", -"oughtnt", -"oukia", -"oulap", -"ounce", -"ounds", -"ouphe", -"ouphish", -"our", -"ourie", -"ouroub", -"ours", -"ourself", -"oust", -"ouster", -"out", -"outact", -"outage", -"outarde", -"outask", -"outawe", -"outback", -"outbake", -"outban", -"outbar", -"outbark", -"outbawl", -"outbeam", -"outbear", -"outbeg", -"outbent", -"outbid", -"outblot", -"outblow", -"outbond", -"outbook", -"outborn", -"outbow", -"outbowl", -"outbox", -"outbrag", -"outbray", -"outbred", -"outbud", -"outbulk", -"outburn", -"outbuy", -"outbuzz", -"outby", -"outcant", -"outcase", -"outcast", -"outcity", -"outcome", -"outcrop", -"outcrow", -"outcry", -"outcull", -"outcure", -"outcut", -"outdare", -"outdate", -"outdo", -"outdoer", -"outdoor", -"outdraw", -"outdure", -"outeat", -"outecho", -"outed", -"outedge", -"outen", -"outer", -"outerly", -"outeye", -"outeyed", -"outface", -"outfall", -"outfame", -"outfast", -"outfawn", -"outfeat", -"outfish", -"outfit", -"outflow", -"outflue", -"outflux", -"outfly", -"outfold", -"outfool", -"outfoot", -"outform", -"outfort", -"outgain", -"outgame", -"outgang", -"outgas", -"outgate", -"outgaze", -"outgive", -"outglad", -"outglow", -"outgnaw", -"outgo", -"outgoer", -"outgone", -"outgrin", -"outgrow", -"outgun", -"outgush", -"outhaul", -"outhear", -"outheel", -"outher", -"outhire", -"outhiss", -"outhit", -"outhold", -"outhowl", -"outhue", -"outhunt", -"outhurl", -"outhut", -"outhymn", -"outing", -"outish", -"outjazz", -"outjest", -"outjet", -"outjinx", -"outjump", -"outjut", -"outkick", -"outkill", -"outking", -"outkiss", -"outknee", -"outlaid", -"outland", -"outlash", -"outlast", -"outlaw", -"outlay", -"outlean", -"outleap", -"outler", -"outlet", -"outlie", -"outlier", -"outlimb", -"outlimn", -"outline", -"outlip", -"outlive", -"outlook", -"outlord", -"outlove", -"outlung", -"outly", -"outman", -"outmate", -"outmode", -"outmost", -"outmove", -"outname", -"outness", -"outnook", -"outoven", -"outpace", -"outpage", -"outpart", -"outpass", -"outpath", -"outpay", -"outpeal", -"outpeep", -"outpeer", -"outpick", -"outpipe", -"outpity", -"outplan", -"outplay", -"outplod", -"outplot", -"outpoll", -"outpomp", -"outpop", -"outport", -"outpost", -"outpour", -"outpray", -"outpry", -"outpull", -"outpurl", -"outpush", -"output", -"outrace", -"outrage", -"outrail", -"outrank", -"outrant", -"outrap", -"outrate", -"outrave", -"outray", -"outre", -"outread", -"outrede", -"outrick", -"outride", -"outrig", -"outring", -"outroar", -"outroll", -"outroot", -"outrove", -"outrow", -"outrun", -"outrush", -"outsail", -"outsay", -"outsea", -"outseam", -"outsee", -"outseek", -"outsell", -"outsert", -"outset", -"outshot", -"outshow", -"outshut", -"outside", -"outsift", -"outsigh", -"outsin", -"outsing", -"outsit", -"outsize", -"outskip", -"outsoar", -"outsole", -"outspan", -"outspin", -"outspit", -"outspue", -"outstay", -"outstep", -"outsuck", -"outsulk", -"outsum", -"outswim", -"outtalk", -"outtask", -"outtear", -"outtell", -"outtire", -"outtoil", -"outtop", -"outtrot", -"outturn", -"outvie", -"outvier", -"outvote", -"outwait", -"outwake", -"outwale", -"outwalk", -"outwall", -"outwar", -"outward", -"outwash", -"outwave", -"outwear", -"outweed", -"outweep", -"outwell", -"outwent", -"outwick", -"outwile", -"outwill", -"outwind", -"outwing", -"outwish", -"outwit", -"outwith", -"outwoe", -"outwood", -"outword", -"outwore", -"outwork", -"outworn", -"outyard", -"outyell", -"outyelp", -"outzany", -"ouzel", -"ova", -"oval", -"ovalish", -"ovalize", -"ovally", -"ovaloid", -"ovant", -"ovarial", -"ovarian", -"ovarin", -"ovarium", -"ovary", -"ovate", -"ovated", -"ovately", -"ovation", -"oven", -"ovenful", -"ovenly", -"ovenman", -"over", -"overact", -"overage", -"overall", -"overapt", -"overarm", -"overawe", -"overawn", -"overbet", -"overbid", -"overbig", -"overbit", -"overbow", -"overbuy", -"overby", -"overcap", -"overcow", -"overcoy", -"overcry", -"overcup", -"overcut", -"overdo", -"overdry", -"overdue", -"overdye", -"overeat", -"overegg", -"overeye", -"overfag", -"overfar", -"overfat", -"overfed", -"overfee", -"overfew", -"overfit", -"overfix", -"overfly", -"overget", -"overgo", -"overgod", -"overgun", -"overhit", -"overhot", -"overink", -"overjob", -"overjoy", -"overlap", -"overlax", -"overlay", -"overleg", -"overlie", -"overlip", -"overlow", -"overly", -"overman", -"overmix", -"overnet", -"overnew", -"overpay", -"overpet", -"overply", -"overpot", -"overrim", -"overrun", -"oversad", -"oversea", -"oversee", -"overset", -"oversew", -"oversot", -"oversow", -"overt", -"overtax", -"overtip", -"overtly", -"overtoe", -"overtop", -"overuse", -"overway", -"overweb", -"overwet", -"overwin", -"ovest", -"ovey", -"ovicell", -"ovicide", -"ovicyst", -"oviduct", -"oviform", -"ovigerm", -"ovile", -"ovine", -"ovinia", -"ovipara", -"ovisac", -"ovism", -"ovist", -"ovistic", -"ovocyte", -"ovoid", -"ovoidal", -"ovolo", -"ovology", -"ovular", -"ovulary", -"ovulate", -"ovule", -"ovulist", -"ovum", -"ow", -"owd", -"owe", -"owelty", -"ower", -"owerby", -"owght", -"owing", -"owk", -"owl", -"owldom", -"owler", -"owlery", -"owlet", -"owlhead", -"owling", -"owlish", -"owlism", -"owllike", -"owly", -"own", -"owner", -"ownhood", -"ownness", -"ownself", -"owrehip", -"owrelay", -"owse", -"owsen", -"owser", -"owtchah", -"ox", -"oxacid", -"oxalan", -"oxalate", -"oxalic", -"oxalite", -"oxalyl", -"oxamate", -"oxamic", -"oxamid", -"oxamide", -"oxan", -"oxanate", -"oxane", -"oxanic", -"oxazine", -"oxazole", -"oxbane", -"oxberry", -"oxbird", -"oxbiter", -"oxblood", -"oxbow", -"oxboy", -"oxbrake", -"oxcart", -"oxcheek", -"oxea", -"oxeate", -"oxen", -"oxeote", -"oxer", -"oxetone", -"oxeye", -"oxfly", -"oxgang", -"oxgoad", -"oxhead", -"oxheal", -"oxheart", -"oxhide", -"oxhoft", -"oxhorn", -"oxhouse", -"oxhuvud", -"oxidant", -"oxidase", -"oxidate", -"oxide", -"oxidic", -"oxidize", -"oximate", -"oxime", -"oxland", -"oxlike", -"oxlip", -"oxman", -"oxonic", -"oxonium", -"oxozone", -"oxphony", -"oxreim", -"oxshoe", -"oxskin", -"oxtail", -"oxter", -"oxwort", -"oxy", -"oxyacid", -"oxygas", -"oxygen", -"oxyl", -"oxymel", -"oxyntic", -"oxyopia", -"oxysalt", -"oxytone", -"oyapock", -"oyer", -"oyster", -"ozena", -"ozonate", -"ozone", -"ozoned", -"ozonic", -"ozonide", -"ozonify", -"ozonize", -"ozonous", -"ozophen", -"ozotype", -"p", -"pa", -"paal", -"paar", -"paauw", -"pabble", -"pablo", -"pabouch", -"pabular", -"pabulum", -"pac", -"paca", -"pacable", -"pacate", -"pacay", -"pacaya", -"pace", -"paced", -"pacer", -"pachak", -"pachisi", -"pacific", -"pacify", -"pack", -"package", -"packer", -"packery", -"packet", -"packly", -"packman", -"packway", -"paco", -"pact", -"paction", -"pad", -"padder", -"padding", -"paddle", -"paddled", -"paddler", -"paddock", -"paddy", -"padella", -"padfoot", -"padge", -"padle", -"padlike", -"padlock", -"padnag", -"padre", -"padtree", -"paean", -"paegel", -"paegle", -"paenula", -"paeon", -"paeonic", -"paga", -"pagan", -"paganic", -"paganly", -"paganry", -"page", -"pageant", -"pagedom", -"pageful", -"pager", -"pagina", -"paginal", -"pagoda", -"pagrus", -"pagurid", -"pagus", -"pah", -"paha", -"pahi", -"pahlavi", -"pahmi", -"paho", -"pahutan", -"paigle", -"paik", -"pail", -"pailful", -"pailou", -"pain", -"pained", -"painful", -"paining", -"paint", -"painted", -"painter", -"painty", -"paip", -"pair", -"paired", -"pairer", -"pais", -"paisa", -"paiwari", -"pajama", -"pajock", -"pakchoi", -"pakeha", -"paktong", -"pal", -"palace", -"palaced", -"paladin", -"palaite", -"palama", -"palame", -"palanka", -"palar", -"palas", -"palatal", -"palate", -"palated", -"palatic", -"palaver", -"palay", -"palazzi", -"palch", -"pale", -"palea", -"paleate", -"paled", -"palely", -"paleola", -"paler", -"palet", -"paletot", -"palette", -"paletz", -"palfrey", -"palgat", -"pali", -"palikar", -"palila", -"palinal", -"paling", -"palisfy", -"palish", -"palkee", -"pall", -"palla", -"pallae", -"pallah", -"pallall", -"palled", -"pallet", -"palli", -"pallial", -"pallid", -"pallion", -"pallium", -"pallone", -"pallor", -"pally", -"palm", -"palma", -"palmad", -"palmar", -"palmary", -"palmate", -"palmed", -"palmer", -"palmery", -"palmful", -"palmist", -"palmite", -"palmito", -"palmo", -"palmula", -"palmus", -"palmy", -"palmyra", -"palolo", -"palp", -"palpal", -"palpate", -"palped", -"palpi", -"palpon", -"palpus", -"palsied", -"palster", -"palsy", -"palt", -"palter", -"paltry", -"paludal", -"paludic", -"palule", -"palulus", -"palus", -"paly", -"pam", -"pament", -"pamment", -"pampas", -"pampean", -"pamper", -"pampero", -"pampre", -"pan", -"panace", -"panacea", -"panache", -"panada", -"panade", -"panama", -"panaris", -"panary", -"panax", -"pancake", -"pand", -"panda", -"pandal", -"pandan", -"pandect", -"pandemy", -"pander", -"pandita", -"pandle", -"pandora", -"pandour", -"pandrop", -"pandura", -"pandy", -"pane", -"paned", -"paneity", -"panel", -"panela", -"paneler", -"panfil", -"panfish", -"panful", -"pang", -"pangamy", -"pangane", -"pangen", -"pangene", -"pangful", -"pangi", -"panhead", -"panic", -"panical", -"panicky", -"panicle", -"panisc", -"panisca", -"panisic", -"pank", -"pankin", -"panman", -"panmixy", -"panmug", -"pannade", -"pannage", -"pannam", -"panne", -"pannel", -"panner", -"pannery", -"pannier", -"panning", -"pannose", -"pannum", -"pannus", -"panocha", -"panoche", -"panoply", -"panoram", -"panse", -"panside", -"pansied", -"pansy", -"pant", -"pantas", -"panter", -"panther", -"pantie", -"panties", -"pantile", -"panting", -"pantle", -"pantler", -"panto", -"pantod", -"panton", -"pantoon", -"pantoum", -"pantry", -"pants", -"pantun", -"panty", -"panung", -"panurgy", -"panyar", -"paolo", -"paon", -"pap", -"papa", -"papable", -"papabot", -"papacy", -"papain", -"papal", -"papally", -"papalty", -"papane", -"papaw", -"papaya", -"papboat", -"pape", -"paper", -"papered", -"paperer", -"papern", -"papery", -"papess", -"papey", -"papilla", -"papion", -"papish", -"papism", -"papist", -"papize", -"papless", -"papmeat", -"papoose", -"pappi", -"pappose", -"pappox", -"pappus", -"pappy", -"papreg", -"paprica", -"paprika", -"papula", -"papular", -"papule", -"papyr", -"papyral", -"papyri", -"papyrin", -"papyrus", -"paquet", -"par", -"para", -"parable", -"paracme", -"parade", -"parader", -"parado", -"parados", -"paradox", -"parafle", -"parage", -"paragon", -"parah", -"paraiba", -"parale", -"param", -"paramo", -"parang", -"parao", -"parapet", -"paraph", -"parapod", -"pararek", -"parasol", -"paraspy", -"parate", -"paraxon", -"parbake", -"parboil", -"parcel", -"parch", -"parcher", -"parchy", -"parcook", -"pard", -"pardao", -"parded", -"pardesi", -"pardine", -"pardner", -"pardo", -"pardon", -"pare", -"parel", -"parella", -"paren", -"parent", -"parer", -"paresis", -"paretic", -"parfait", -"pargana", -"parge", -"parget", -"pargo", -"pari", -"pariah", -"parial", -"parian", -"paries", -"parify", -"parilla", -"parine", -"paring", -"parish", -"parisis", -"parison", -"parity", -"park", -"parka", -"parkee", -"parker", -"parkin", -"parking", -"parkish", -"parkway", -"parky", -"parlay", -"parle", -"parley", -"parling", -"parlish", -"parlor", -"parlous", -"parly", -"parma", -"parmak", -"parnas", -"parnel", -"paroch", -"parode", -"parodic", -"parodos", -"parody", -"paroecy", -"parol", -"parole", -"parolee", -"paroli", -"paronym", -"parotic", -"parotid", -"parotis", -"parous", -"parpal", -"parquet", -"parr", -"parrel", -"parrier", -"parrock", -"parrot", -"parroty", -"parry", -"parse", -"parsec", -"parser", -"parsley", -"parsnip", -"parson", -"parsony", -"part", -"partake", -"partan", -"parted", -"parter", -"partial", -"partile", -"partite", -"partlet", -"partly", -"partner", -"parto", -"partook", -"parture", -"party", -"parulis", -"parure", -"paruria", -"parvenu", -"parvis", -"parvule", -"pasan", -"pasang", -"paschal", -"pascual", -"pash", -"pasha", -"pashm", -"pasi", -"pasmo", -"pasquil", -"pasquin", -"pass", -"passade", -"passado", -"passage", -"passant", -"passe", -"passee", -"passen", -"passer", -"passewa", -"passing", -"passion", -"passir", -"passive", -"passkey", -"passman", -"passo", -"passout", -"passus", -"passway", -"past", -"paste", -"pasted", -"pastel", -"paster", -"pastern", -"pasteur", -"pastil", -"pastile", -"pastime", -"pasting", -"pastor", -"pastose", -"pastry", -"pasture", -"pasty", -"pasul", -"pat", -"pata", -"pataca", -"patacao", -"pataco", -"patagon", -"pataka", -"patamar", -"patao", -"patapat", -"pataque", -"patas", -"patball", -"patch", -"patcher", -"patchy", -"pate", -"patefy", -"patel", -"patella", -"paten", -"patency", -"patener", -"patent", -"pater", -"patera", -"patesi", -"path", -"pathed", -"pathema", -"pathic", -"pathlet", -"pathos", -"pathway", -"pathy", -"patible", -"patient", -"patina", -"patine", -"patined", -"patio", -"patly", -"patness", -"pato", -"patois", -"patola", -"patonce", -"patria", -"patrial", -"patrice", -"patrico", -"patrin", -"patriot", -"patrist", -"patrix", -"patrol", -"patron", -"patroon", -"patta", -"patte", -"pattee", -"patten", -"patter", -"pattern", -"pattu", -"patty", -"patu", -"patwari", -"paty", -"pau", -"paucify", -"paucity", -"paughty", -"paukpan", -"paular", -"paulie", -"paulin", -"paunch", -"paunchy", -"paup", -"pauper", -"pausal", -"pause", -"pauser", -"paussid", -"paut", -"pauxi", -"pavage", -"pavan", -"pavane", -"pave", -"paver", -"pavid", -"pavier", -"paving", -"pavior", -"paviour", -"pavis", -"paviser", -"pavisor", -"pavy", -"paw", -"pawdite", -"pawer", -"pawing", -"pawk", -"pawkery", -"pawkily", -"pawkrie", -"pawky", -"pawl", -"pawn", -"pawnage", -"pawnee", -"pawner", -"pawnie", -"pawnor", -"pawpaw", -"pax", -"paxilla", -"paxiuba", -"paxwax", -"pay", -"payable", -"payably", -"payday", -"payed", -"payee", -"payeny", -"payer", -"paying", -"payment", -"paynim", -"payoff", -"payong", -"payor", -"payroll", -"pea", -"peace", -"peach", -"peachen", -"peacher", -"peachy", -"peacoat", -"peacock", -"peacod", -"peafowl", -"peag", -"peage", -"peahen", -"peai", -"peaiism", -"peak", -"peaked", -"peaker", -"peakily", -"peaking", -"peakish", -"peaky", -"peal", -"pealike", -"pean", -"peanut", -"pear", -"pearl", -"pearled", -"pearler", -"pearlet", -"pearlin", -"pearly", -"peart", -"pearten", -"peartly", -"peasant", -"peasen", -"peason", -"peasy", -"peat", -"peatery", -"peatman", -"peaty", -"peavey", -"peavy", -"peba", -"pebble", -"pebbled", -"pebbly", -"pebrine", -"pecan", -"peccant", -"peccary", -"peccavi", -"pech", -"pecht", -"pecite", -"peck", -"pecked", -"pecker", -"pecket", -"peckful", -"peckish", -"peckle", -"peckled", -"peckly", -"pecky", -"pectase", -"pectate", -"pecten", -"pectic", -"pectin", -"pectize", -"pectora", -"pectose", -"pectous", -"pectus", -"ped", -"peda", -"pedage", -"pedagog", -"pedal", -"pedaler", -"pedant", -"pedary", -"pedate", -"pedated", -"pedder", -"peddle", -"peddler", -"pedee", -"pedes", -"pedesis", -"pedicab", -"pedicel", -"pedicle", -"pedion", -"pedlar", -"pedlary", -"pedocal", -"pedrail", -"pedrero", -"pedro", -"pedule", -"pedum", -"pee", -"peed", -"peek", -"peel", -"peele", -"peeled", -"peeler", -"peeling", -"peelman", -"peen", -"peenge", -"peeoy", -"peep", -"peeper", -"peepeye", -"peepy", -"peer", -"peerage", -"peerdom", -"peeress", -"peerie", -"peerly", -"peery", -"peesash", -"peeve", -"peeved", -"peever", -"peevish", -"peewee", -"peg", -"pega", -"pegall", -"pegasid", -"pegbox", -"pegged", -"pegger", -"pegging", -"peggle", -"peggy", -"pegless", -"peglet", -"peglike", -"pegman", -"pegwood", -"peho", -"peine", -"peisage", -"peise", -"peiser", -"peixere", -"pekan", -"pekin", -"pekoe", -"peladic", -"pelage", -"pelagic", -"pelamyd", -"pelanos", -"pelean", -"pelecan", -"pelf", -"pelican", -"pelick", -"pelike", -"peliom", -"pelioma", -"pelisse", -"pelite", -"pelitic", -"pell", -"pellage", -"pellar", -"pellard", -"pellas", -"pellate", -"peller", -"pellet", -"pellety", -"pellile", -"pellock", -"pelmet", -"pelon", -"peloria", -"peloric", -"pelorus", -"pelota", -"peloton", -"pelt", -"pelta", -"peltast", -"peltate", -"pelter", -"pelting", -"peltry", -"pelu", -"peludo", -"pelves", -"pelvic", -"pelvis", -"pembina", -"pemican", -"pen", -"penal", -"penally", -"penalty", -"penance", -"penang", -"penates", -"penbard", -"pence", -"pencel", -"pencil", -"pend", -"penda", -"pendant", -"pendent", -"pending", -"pendle", -"pendom", -"pendule", -"penfold", -"penful", -"pengo", -"penguin", -"penhead", -"penial", -"penide", -"penile", -"penis", -"penk", -"penlike", -"penman", -"penna", -"pennae", -"pennage", -"pennant", -"pennate", -"penner", -"pennet", -"penni", -"pennia", -"pennied", -"pennill", -"penning", -"pennon", -"penny", -"penrack", -"penship", -"pensile", -"pension", -"pensive", -"penster", -"pensum", -"pensy", -"pent", -"penta", -"pentace", -"pentad", -"pentail", -"pentane", -"pentene", -"pentine", -"pentit", -"pentite", -"pentode", -"pentoic", -"pentol", -"pentose", -"pentrit", -"pentyl", -"pentyne", -"penuchi", -"penult", -"penury", -"peon", -"peonage", -"peonism", -"peony", -"people", -"peopler", -"peoplet", -"peotomy", -"pep", -"pepful", -"pepino", -"peplos", -"peplum", -"peplus", -"pepo", -"pepper", -"peppery", -"peppily", -"peppin", -"peppy", -"pepsin", -"pepsis", -"peptic", -"peptide", -"peptize", -"peptone", -"per", -"peracid", -"peract", -"perbend", -"percale", -"percent", -"percept", -"perch", -"percha", -"percher", -"percid", -"percoct", -"percoid", -"percur", -"percuss", -"perdu", -"perdure", -"pereion", -"pereira", -"peres", -"perfect", -"perfidy", -"perform", -"perfume", -"perfumy", -"perfuse", -"pergola", -"perhaps", -"peri", -"periapt", -"peridot", -"perigee", -"perigon", -"peril", -"perine", -"period", -"periost", -"perique", -"perish", -"perit", -"perite", -"periwig", -"perjink", -"perjure", -"perjury", -"perk", -"perkily", -"perkin", -"perking", -"perkish", -"perky", -"perle", -"perlid", -"perlite", -"perloir", -"perm", -"permit", -"permute", -"pern", -"pernine", -"pernor", -"pernyi", -"peroba", -"peropod", -"peropus", -"peroral", -"perosis", -"perotic", -"peroxy", -"peroxyl", -"perpend", -"perpera", -"perplex", -"perrier", -"perron", -"perry", -"persalt", -"perse", -"persico", -"persis", -"persist", -"person", -"persona", -"pert", -"pertain", -"perten", -"pertish", -"pertly", -"perturb", -"pertuse", -"perty", -"peruke", -"perula", -"perule", -"perusal", -"peruse", -"peruser", -"pervade", -"pervert", -"pes", -"pesa", -"pesade", -"pesage", -"peseta", -"peshkar", -"peshwa", -"peskily", -"pesky", -"peso", -"pess", -"pessary", -"pest", -"peste", -"pester", -"pestful", -"pestify", -"pestle", -"pet", -"petal", -"petaled", -"petalon", -"petaly", -"petard", -"petary", -"petasos", -"petasus", -"petcock", -"pete", -"peteca", -"peteman", -"peter", -"petful", -"petiole", -"petit", -"petite", -"petitor", -"petkin", -"petling", -"peto", -"petrary", -"petre", -"petrean", -"petrel", -"petrie", -"petrify", -"petrol", -"petrosa", -"petrous", -"petted", -"petter", -"pettily", -"pettish", -"pettle", -"petty", -"petune", -"petwood", -"petzite", -"peuhl", -"pew", -"pewage", -"pewdom", -"pewee", -"pewful", -"pewing", -"pewit", -"pewless", -"pewmate", -"pewter", -"pewtery", -"pewy", -"peyote", -"peyotl", -"peyton", -"peytrel", -"pfennig", -"pfui", -"pfund", -"phacoid", -"phaeism", -"phaeton", -"phage", -"phalanx", -"phalera", -"phallic", -"phallin", -"phallus", -"phanic", -"phano", -"phantom", -"phare", -"pharmic", -"pharos", -"pharynx", -"phase", -"phaseal", -"phasemy", -"phases", -"phasic", -"phasis", -"phasm", -"phasma", -"phasmid", -"pheal", -"phellem", -"phemic", -"phenate", -"phene", -"phenene", -"phenic", -"phenin", -"phenol", -"phenyl", -"pheon", -"phew", -"phi", -"phial", -"phiale", -"philter", -"philtra", -"phit", -"phiz", -"phizes", -"phizog", -"phlegm", -"phlegma", -"phlegmy", -"phloem", -"phloxin", -"pho", -"phobiac", -"phobic", -"phobism", -"phobist", -"phoby", -"phoca", -"phocal", -"phocid", -"phocine", -"phocoid", -"phoebe", -"phoenix", -"phoh", -"pholad", -"pholcid", -"pholido", -"phon", -"phonal", -"phonate", -"phone", -"phoneme", -"phonic", -"phonics", -"phonism", -"phono", -"phony", -"phoo", -"phoresy", -"phoria", -"phorid", -"phorone", -"phos", -"phose", -"phosis", -"phospho", -"phossy", -"phot", -"photal", -"photic", -"photics", -"photism", -"photo", -"photoma", -"photon", -"phragma", -"phrasal", -"phrase", -"phraser", -"phrasy", -"phrator", -"phratry", -"phrenic", -"phrynid", -"phrynin", -"phthor", -"phu", -"phugoid", -"phulwa", -"phut", -"phycite", -"phyla", -"phyle", -"phylic", -"phyllin", -"phylon", -"phylum", -"phyma", -"phymata", -"physic", -"physics", -"phytase", -"phytic", -"phytin", -"phytoid", -"phytol", -"phytoma", -"phytome", -"phyton", -"phytyl", -"pi", -"pia", -"piaba", -"piacaba", -"piacle", -"piaffe", -"piaffer", -"pial", -"pialyn", -"pian", -"pianic", -"pianino", -"pianism", -"pianist", -"piannet", -"piano", -"pianola", -"piaster", -"piastre", -"piation", -"piazine", -"piazza", -"pibcorn", -"pibroch", -"pic", -"pica", -"picador", -"pical", -"picamar", -"picara", -"picarel", -"picaro", -"picary", -"piccolo", -"pice", -"picene", -"piceous", -"pichi", -"picine", -"pick", -"pickage", -"pickax", -"picked", -"pickee", -"pickeer", -"picker", -"pickery", -"picket", -"pickle", -"pickler", -"pickman", -"pickmaw", -"pickup", -"picky", -"picnic", -"pico", -"picoid", -"picot", -"picotah", -"picotee", -"picra", -"picrate", -"picric", -"picrite", -"picrol", -"picryl", -"pict", -"picture", -"pictury", -"picuda", -"picudo", -"picul", -"piculet", -"pidan", -"piddle", -"piddler", -"piddock", -"pidgin", -"pie", -"piebald", -"piece", -"piecen", -"piecer", -"piecing", -"pied", -"piedly", -"pieless", -"pielet", -"pielum", -"piemag", -"pieman", -"pien", -"piend", -"piepan", -"pier", -"pierage", -"pierce", -"pierced", -"piercel", -"piercer", -"pierid", -"pierine", -"pierrot", -"pieshop", -"piet", -"pietas", -"pietic", -"pietism", -"pietist", -"pietose", -"piety", -"piewife", -"piewipe", -"piezo", -"piff", -"piffle", -"piffler", -"pifine", -"pig", -"pigdan", -"pigdom", -"pigeon", -"pigface", -"pigfish", -"pigfoot", -"pigful", -"piggery", -"piggin", -"pigging", -"piggish", -"piggle", -"piggy", -"pighead", -"pigherd", -"pightle", -"pigless", -"piglet", -"pigling", -"pigly", -"pigman", -"pigment", -"pignon", -"pignus", -"pignut", -"pigpen", -"pigroot", -"pigskin", -"pigsney", -"pigsty", -"pigtail", -"pigwash", -"pigweed", -"pigyard", -"piitis", -"pik", -"pika", -"pike", -"piked", -"pikel", -"pikelet", -"pikeman", -"piker", -"pikey", -"piki", -"piking", -"pikle", -"piky", -"pilage", -"pilapil", -"pilar", -"pilary", -"pilau", -"pilaued", -"pilch", -"pilcher", -"pilcorn", -"pilcrow", -"pile", -"pileata", -"pileate", -"piled", -"pileous", -"piler", -"piles", -"pileus", -"pilfer", -"pilger", -"pilgrim", -"pili", -"pilifer", -"piligan", -"pilikai", -"pilin", -"piline", -"piling", -"pilkins", -"pill", -"pillage", -"pillar", -"pillary", -"pillas", -"pillbox", -"pilled", -"pillet", -"pilleus", -"pillion", -"pillory", -"pillow", -"pillowy", -"pilm", -"pilmy", -"pilon", -"pilori", -"pilose", -"pilosis", -"pilot", -"pilotee", -"pilotry", -"pilous", -"pilpul", -"piltock", -"pilula", -"pilular", -"pilule", -"pilum", -"pilus", -"pily", -"pimaric", -"pimelic", -"pimento", -"pimlico", -"pimola", -"pimp", -"pimpery", -"pimping", -"pimpish", -"pimple", -"pimpled", -"pimplo", -"pimploe", -"pimply", -"pin", -"pina", -"pinaces", -"pinacle", -"pinacol", -"pinang", -"pinax", -"pinball", -"pinbone", -"pinbush", -"pincase", -"pincer", -"pincers", -"pinch", -"pinche", -"pinched", -"pinchem", -"pincher", -"pind", -"pinda", -"pinder", -"pindy", -"pine", -"pineal", -"pined", -"pinene", -"piner", -"pinery", -"pinesap", -"pinetum", -"piney", -"pinfall", -"pinfish", -"pinfold", -"ping", -"pingle", -"pingler", -"pingue", -"pinguid", -"pinguin", -"pinhead", -"pinhold", -"pinhole", -"pinhook", -"pinic", -"pining", -"pinion", -"pinite", -"pinitol", -"pinjane", -"pinjra", -"pink", -"pinked", -"pinkeen", -"pinken", -"pinker", -"pinkeye", -"pinkie", -"pinkify", -"pinkily", -"pinking", -"pinkish", -"pinkly", -"pinky", -"pinless", -"pinlock", -"pinna", -"pinnace", -"pinnae", -"pinnal", -"pinnate", -"pinned", -"pinnel", -"pinner", -"pinnet", -"pinning", -"pinnock", -"pinnula", -"pinnule", -"pinny", -"pino", -"pinole", -"pinolia", -"pinolin", -"pinon", -"pinonic", -"pinrail", -"pinsons", -"pint", -"pinta", -"pintado", -"pintail", -"pintano", -"pinte", -"pintle", -"pinto", -"pintura", -"pinulus", -"pinweed", -"pinwing", -"pinwork", -"pinworm", -"piny", -"pinyl", -"pinyon", -"pioneer", -"pioted", -"piotine", -"piotty", -"pioury", -"pious", -"piously", -"pip", -"pipa", -"pipage", -"pipal", -"pipe", -"pipeage", -"piped", -"pipeful", -"pipeman", -"piper", -"piperic", -"piperly", -"piperno", -"pipery", -"pipet", -"pipette", -"pipi", -"piping", -"pipiri", -"pipit", -"pipkin", -"pipless", -"pipped", -"pipper", -"pippin", -"pippy", -"piprine", -"piproid", -"pipy", -"piquant", -"pique", -"piquet", -"piquia", -"piqure", -"pir", -"piracy", -"piragua", -"piranha", -"pirate", -"piraty", -"pirl", -"pirn", -"pirner", -"pirnie", -"pirny", -"pirogue", -"pirol", -"pirr", -"pirrmaw", -"pisaca", -"pisang", -"pisay", -"piscary", -"piscian", -"piscina", -"piscine", -"pisco", -"pise", -"pish", -"pishaug", -"pishu", -"pisk", -"pisky", -"pismire", -"piso", -"piss", -"pissant", -"pist", -"pistic", -"pistil", -"pistle", -"pistol", -"pistole", -"piston", -"pistrix", -"pit", -"pita", -"pitanga", -"pitapat", -"pitarah", -"pitau", -"pitaya", -"pitch", -"pitcher", -"pitchi", -"pitchy", -"piteous", -"pitfall", -"pith", -"pithful", -"pithily", -"pithole", -"pithos", -"pithy", -"pitier", -"pitiful", -"pitless", -"pitlike", -"pitman", -"pitmark", -"pitmirk", -"pitpan", -"pitpit", -"pitside", -"pitted", -"pitter", -"pittine", -"pitting", -"pittite", -"pittoid", -"pituite", -"pituri", -"pitwood", -"pitwork", -"pity", -"pitying", -"piuri", -"pivalic", -"pivot", -"pivotal", -"pivoter", -"pix", -"pixie", -"pixy", -"pize", -"pizza", -"pizzle", -"placard", -"placate", -"place", -"placebo", -"placer", -"placet", -"placid", -"plack", -"placket", -"placode", -"placoid", -"placula", -"plaga", -"plagal", -"plagate", -"plage", -"plagium", -"plagose", -"plague", -"plagued", -"plaguer", -"plaguy", -"plaice", -"plaid", -"plaided", -"plaidie", -"plaidy", -"plain", -"plainer", -"plainly", -"plaint", -"plait", -"plaited", -"plaiter", -"plak", -"plakat", -"plan", -"planaea", -"planar", -"planate", -"planch", -"plandok", -"plane", -"planer", -"planet", -"planeta", -"planful", -"plang", -"plangor", -"planish", -"planity", -"plank", -"planker", -"planky", -"planner", -"plant", -"planta", -"plantad", -"plantal", -"plantar", -"planter", -"planula", -"planury", -"planxty", -"plap", -"plaque", -"plash", -"plasher", -"plashet", -"plashy", -"plasm", -"plasma", -"plasmic", -"plasome", -"plass", -"plasson", -"plaster", -"plastic", -"plastid", -"plastin", -"plat", -"platan", -"platane", -"platano", -"platch", -"plate", -"platea", -"plateau", -"plated", -"platen", -"plater", -"platery", -"platic", -"platina", -"plating", -"platode", -"platoid", -"platoon", -"platted", -"platten", -"platter", -"platty", -"platy", -"plaud", -"plaudit", -"play", -"playa", -"playbox", -"playboy", -"playday", -"player", -"playful", -"playlet", -"playman", -"playock", -"playpen", -"plaza", -"plea", -"pleach", -"plead", -"pleader", -"please", -"pleaser", -"pleat", -"pleater", -"pleb", -"plebe", -"plebify", -"plebs", -"pleck", -"plectre", -"pled", -"pledge", -"pledgee", -"pledger", -"pledget", -"pledgor", -"pleion", -"plenary", -"plenipo", -"plenish", -"plenism", -"plenist", -"plenty", -"plenum", -"pleny", -"pleon", -"pleonal", -"pleonic", -"pleopod", -"pleroma", -"plerome", -"plessor", -"pleura", -"pleural", -"pleuric", -"pleuron", -"pleurum", -"plew", -"plex", -"plexal", -"plexor", -"plexure", -"plexus", -"pliable", -"pliably", -"pliancy", -"pliant", -"plica", -"plical", -"plicate", -"plied", -"plier", -"plies", -"pliers", -"plight", -"plim", -"plinth", -"pliskie", -"plisky", -"ploat", -"ploce", -"plock", -"plod", -"plodder", -"plodge", -"plomb", -"plook", -"plop", -"plosion", -"plosive", -"plot", -"plote", -"plotful", -"plotted", -"plotter", -"plotty", -"plough", -"plouk", -"plouked", -"plouky", -"plounce", -"plout", -"plouter", -"plover", -"plovery", -"plow", -"plowboy", -"plower", -"plowing", -"plowman", -"ploy", -"pluck", -"plucked", -"plucker", -"plucky", -"plud", -"pluff", -"pluffer", -"pluffy", -"plug", -"plugged", -"plugger", -"pluggy", -"plugman", -"plum", -"pluma", -"plumach", -"plumade", -"plumage", -"plumate", -"plumb", -"plumber", -"plumbet", -"plumbic", -"plumbog", -"plumbum", -"plumcot", -"plume", -"plumed", -"plumer", -"plumery", -"plumet", -"plumier", -"plumify", -"plumist", -"plumlet", -"plummer", -"plummet", -"plummy", -"plumose", -"plumous", -"plump", -"plumpen", -"plumper", -"plumply", -"plumps", -"plumpy", -"plumula", -"plumule", -"plumy", -"plunder", -"plunge", -"plunger", -"plunk", -"plup", -"plural", -"pluries", -"plurify", -"plus", -"plush", -"plushed", -"plushy", -"pluteal", -"plutean", -"pluteus", -"pluvial", -"pluvian", -"pluvine", -"ply", -"plyer", -"plying", -"plywood", -"pneuma", -"po", -"poach", -"poacher", -"poachy", -"poalike", -"pob", -"pobby", -"pobs", -"pochade", -"pochard", -"pochay", -"poche", -"pock", -"pocket", -"pockety", -"pockily", -"pocky", -"poco", -"pocosin", -"pod", -"podagra", -"podal", -"podalic", -"podatus", -"podded", -"podder", -"poddish", -"poddle", -"poddy", -"podeon", -"podesta", -"podex", -"podge", -"podger", -"podgily", -"podgy", -"podial", -"podical", -"podices", -"podite", -"poditic", -"poditti", -"podium", -"podler", -"podley", -"podlike", -"podogyn", -"podsol", -"poduran", -"podurid", -"podware", -"podzol", -"poe", -"poem", -"poemet", -"poemlet", -"poesie", -"poesis", -"poesy", -"poet", -"poetdom", -"poetess", -"poetic", -"poetics", -"poetito", -"poetize", -"poetly", -"poetry", -"pogge", -"poggy", -"pogonip", -"pogrom", -"pogy", -"poh", -"poha", -"pohna", -"poi", -"poietic", -"poignet", -"poil", -"poilu", -"poind", -"poinder", -"point", -"pointed", -"pointel", -"pointer", -"pointy", -"poise", -"poised", -"poiser", -"poison", -"poitrel", -"pokable", -"poke", -"poked", -"pokeful", -"pokeout", -"poker", -"pokey", -"pokily", -"poking", -"pokomoo", -"pokunt", -"poky", -"pol", -"polacca", -"polack", -"polacre", -"polar", -"polaric", -"polarly", -"polaxis", -"poldavy", -"polder", -"pole", -"polearm", -"poleax", -"poleaxe", -"polecat", -"poleman", -"polemic", -"polenta", -"poler", -"poley", -"poliad", -"police", -"policed", -"policy", -"poligar", -"polio", -"polis", -"polish", -"polite", -"politic", -"polity", -"polk", -"polka", -"poll", -"pollack", -"polladz", -"pollage", -"pollam", -"pollan", -"pollard", -"polled", -"pollen", -"pollent", -"poller", -"pollex", -"polling", -"pollock", -"polloi", -"pollute", -"pollux", -"polo", -"poloist", -"polony", -"polos", -"polska", -"polt", -"poltina", -"poly", -"polyact", -"polyad", -"polygam", -"polygon", -"polygyn", -"polymer", -"polyose", -"polyp", -"polyped", -"polypi", -"polypod", -"polypus", -"pom", -"pomace", -"pomade", -"pomane", -"pomate", -"pomato", -"pomatum", -"pombe", -"pombo", -"pome", -"pomelo", -"pomey", -"pomfret", -"pomme", -"pommee", -"pommel", -"pommet", -"pommey", -"pommy", -"pomonal", -"pomonic", -"pomp", -"pompa", -"pompal", -"pompano", -"pompey", -"pomphus", -"pompier", -"pompion", -"pompist", -"pompon", -"pompous", -"pomster", -"pon", -"ponce", -"ponceau", -"poncho", -"pond", -"pondage", -"ponder", -"pondful", -"pondlet", -"pondman", -"pondok", -"pondus", -"pondy", -"pone", -"ponent", -"ponerid", -"poney", -"pong", -"ponga", -"pongee", -"poniard", -"ponica", -"ponier", -"ponja", -"pont", -"pontage", -"pontal", -"pontee", -"pontes", -"pontic", -"pontiff", -"pontify", -"pontil", -"pontile", -"pontin", -"pontine", -"pontist", -"ponto", -"ponton", -"pontoon", -"pony", -"ponzite", -"pooa", -"pooch", -"pooder", -"poodle", -"poof", -"poogye", -"pooh", -"pook", -"pooka", -"pookaun", -"pookoo", -"pool", -"pooler", -"pooli", -"pooly", -"poon", -"poonac", -"poonga", -"poop", -"pooped", -"poor", -"poorish", -"poorly", -"poot", -"pop", -"popadam", -"popal", -"popcorn", -"popdock", -"pope", -"popedom", -"popeism", -"popeler", -"popely", -"popery", -"popess", -"popeye", -"popeyed", -"popgun", -"popify", -"popinac", -"popish", -"popjoy", -"poplar", -"poplin", -"popover", -"poppa", -"poppean", -"poppel", -"popper", -"poppet", -"poppied", -"poppin", -"popple", -"popply", -"poppy", -"popshop", -"popular", -"populin", -"popweed", -"poral", -"porcate", -"porch", -"porched", -"porcine", -"pore", -"pored", -"porer", -"porge", -"porger", -"porgy", -"poring", -"porism", -"porite", -"pork", -"porker", -"porkery", -"porket", -"porkish", -"porkman", -"porkpie", -"porky", -"porogam", -"poroma", -"poros", -"porose", -"porosis", -"porotic", -"porous", -"porr", -"porrect", -"porret", -"porrigo", -"porry", -"port", -"porta", -"portage", -"portail", -"portal", -"portass", -"ported", -"portend", -"portent", -"porter", -"portia", -"portico", -"portify", -"portio", -"portion", -"portlet", -"portly", -"portman", -"porto", -"portray", -"portway", -"porty", -"porule", -"porus", -"pory", -"posca", -"pose", -"poser", -"poseur", -"posey", -"posh", -"posing", -"posit", -"positor", -"positum", -"posnet", -"posole", -"poss", -"posse", -"possess", -"posset", -"possum", -"post", -"postage", -"postal", -"postbag", -"postbox", -"postboy", -"posted", -"posteen", -"poster", -"postern", -"postfix", -"postic", -"postil", -"posting", -"postman", -"posture", -"postwar", -"posy", -"pot", -"potable", -"potamic", -"potash", -"potass", -"potassa", -"potate", -"potato", -"potator", -"potbank", -"potboil", -"potboy", -"potch", -"potcher", -"potdar", -"pote", -"poteen", -"potence", -"potency", -"potent", -"poter", -"poteye", -"potful", -"potgirl", -"potgun", -"pothead", -"potheen", -"pother", -"potherb", -"pothery", -"pothole", -"pothook", -"pothunt", -"potifer", -"potion", -"potleg", -"potlid", -"potlike", -"potluck", -"potman", -"potong", -"potoo", -"potoroo", -"potpie", -"potrack", -"pott", -"pottage", -"pottagy", -"pottah", -"potted", -"potter", -"pottery", -"potting", -"pottle", -"pottled", -"potto", -"potty", -"potware", -"potwork", -"potwort", -"pouce", -"poucer", -"poucey", -"pouch", -"pouched", -"pouchy", -"pouf", -"poulard", -"poulp", -"poulpe", -"poult", -"poulter", -"poultry", -"pounamu", -"pounce", -"pounced", -"pouncer", -"pouncet", -"pound", -"poundal", -"pounder", -"pour", -"pourer", -"pourie", -"pouring", -"pouser", -"pout", -"pouter", -"poutful", -"pouting", -"pouty", -"poverty", -"pow", -"powder", -"powdery", -"powdike", -"powdry", -"power", -"powered", -"powitch", -"pownie", -"powwow", -"pox", -"poxy", -"poy", -"poyou", -"praam", -"prabble", -"prabhu", -"practic", -"prad", -"praecox", -"praetor", -"prairie", -"praise", -"praiser", -"prajna", -"praline", -"pram", -"prana", -"prance", -"prancer", -"prancy", -"prank", -"pranked", -"pranker", -"prankle", -"pranky", -"prase", -"prasine", -"prasoid", -"prastha", -"prat", -"pratal", -"prate", -"prater", -"pratey", -"prating", -"prattle", -"prattly", -"prau", -"pravity", -"prawn", -"prawner", -"prawny", -"praxis", -"pray", -"praya", -"prayer", -"prayful", -"praying", -"preach", -"preachy", -"preacid", -"preact", -"preaged", -"preally", -"preanal", -"prearm", -"preaver", -"prebake", -"prebend", -"prebid", -"prebill", -"preboil", -"preborn", -"preburn", -"precant", -"precary", -"precast", -"precava", -"precede", -"precent", -"precept", -"preces", -"precess", -"precipe", -"precis", -"precise", -"precite", -"precoil", -"precook", -"precool", -"precopy", -"precox", -"precure", -"precut", -"precyst", -"predamn", -"predark", -"predata", -"predate", -"predawn", -"preday", -"predefy", -"predeny", -"predial", -"predict", -"prediet", -"predine", -"predoom", -"predraw", -"predry", -"predusk", -"preen", -"preener", -"preeze", -"prefab", -"preface", -"prefect", -"prefer", -"prefine", -"prefix", -"prefool", -"preform", -"pregain", -"pregust", -"prehaps", -"preheal", -"preheat", -"prehend", -"preidea", -"preknit", -"preknow", -"prelacy", -"prelate", -"prelect", -"prelim", -"preloan", -"preloss", -"prelude", -"premake", -"premate", -"premial", -"premier", -"premise", -"premiss", -"premium", -"premix", -"premold", -"premove", -"prename", -"prender", -"prendre", -"preomit", -"preopen", -"preoral", -"prep", -"prepare", -"prepave", -"prepay", -"prepink", -"preplan", -"preplot", -"prepose", -"prepuce", -"prepupa", -"prerent", -"prerich", -"prerupt", -"presage", -"presay", -"preseal", -"presee", -"presell", -"present", -"preses", -"preset", -"preship", -"preshow", -"preside", -"presift", -"presign", -"prespur", -"press", -"pressel", -"presser", -"pressor", -"prest", -"prester", -"presto", -"presume", -"pretan", -"pretell", -"pretend", -"pretest", -"pretext", -"pretire", -"pretone", -"pretry", -"pretty", -"pretzel", -"prevail", -"prevene", -"prevent", -"preverb", -"preveto", -"previde", -"preview", -"previse", -"prevoid", -"prevote", -"prevue", -"prewar", -"prewarn", -"prewash", -"prewhip", -"prewire", -"prewrap", -"prexy", -"prey", -"preyer", -"preyful", -"prezone", -"price", -"priced", -"pricer", -"prich", -"prick", -"pricked", -"pricker", -"pricket", -"prickle", -"prickly", -"pricks", -"pricky", -"pride", -"pridian", -"priding", -"pridy", -"pried", -"prier", -"priest", -"prig", -"prigdom", -"prigger", -"prigman", -"prill", -"prim", -"prima", -"primacy", -"primage", -"primal", -"primar", -"primary", -"primate", -"prime", -"primely", -"primer", -"primero", -"primine", -"priming", -"primly", -"primost", -"primp", -"primsie", -"primula", -"primus", -"primy", -"prince", -"princox", -"prine", -"pringle", -"prink", -"prinker", -"prinkle", -"prinky", -"print", -"printed", -"printer", -"prion", -"prionid", -"prior", -"prioral", -"priorly", -"priory", -"prisage", -"prisal", -"priscan", -"prism", -"prismal", -"prismed", -"prismy", -"prison", -"priss", -"prissy", -"pritch", -"prithee", -"prius", -"privacy", -"privant", -"private", -"privet", -"privily", -"privity", -"privy", -"prize", -"prizer", -"prizery", -"pro", -"proa", -"proal", -"proarmy", -"prob", -"probabl", -"probal", -"probang", -"probant", -"probate", -"probe", -"probeer", -"prober", -"probity", -"problem", -"procarp", -"proceed", -"process", -"proctal", -"proctor", -"procure", -"prod", -"prodder", -"proddle", -"prodigy", -"produce", -"product", -"proem", -"proetid", -"prof", -"profane", -"profert", -"profess", -"proffer", -"profile", -"profit", -"profuse", -"prog", -"progeny", -"progger", -"progne", -"program", -"project", -"proke", -"proker", -"prolan", -"prolate", -"proleg", -"prolify", -"proline", -"prolix", -"prolong", -"prolyl", -"promic", -"promise", -"promote", -"prompt", -"pronaos", -"pronate", -"pronavy", -"prone", -"pronely", -"proneur", -"prong", -"pronged", -"pronger", -"pronic", -"pronoun", -"pronpl", -"pronto", -"pronuba", -"proo", -"proof", -"proofer", -"proofy", -"prop", -"propago", -"propale", -"propane", -"propend", -"propene", -"proper", -"prophet", -"propine", -"proplex", -"propone", -"propons", -"propose", -"propoxy", -"propper", -"props", -"propupa", -"propyl", -"propyne", -"prorata", -"prorate", -"prore", -"prorean", -"prorsad", -"prorsal", -"prosaic", -"prosar", -"prose", -"prosect", -"proser", -"prosify", -"prosily", -"prosing", -"prosish", -"prosist", -"proso", -"prosode", -"prosody", -"prosoma", -"prosper", -"pross", -"prossy", -"prosy", -"protax", -"prote", -"protea", -"protead", -"protean", -"protect", -"protege", -"proteic", -"protein", -"protend", -"protest", -"protext", -"prothyl", -"protide", -"protist", -"protium", -"proto", -"protoma", -"protome", -"proton", -"protone", -"protore", -"protyl", -"protyle", -"protype", -"proudly", -"provand", -"provant", -"prove", -"provect", -"proved", -"proven", -"prover", -"proverb", -"provide", -"provine", -"proving", -"proviso", -"provoke", -"provost", -"prow", -"prowar", -"prowed", -"prowess", -"prowl", -"prowler", -"proxeny", -"proximo", -"proxy", -"proxysm", -"prozone", -"prude", -"prudely", -"prudent", -"prudery", -"prudish", -"prudist", -"prudity", -"pruh", -"prunase", -"prune", -"prunell", -"pruner", -"pruning", -"prunt", -"prunted", -"prurigo", -"prussic", -"prut", -"prutah", -"pry", -"pryer", -"prying", -"pryler", -"pryse", -"prytany", -"psalis", -"psalm", -"psalmic", -"psalmy", -"psaloid", -"psalter", -"psaltes", -"pschent", -"pseudo", -"psha", -"pshaw", -"psi", -"psiloi", -"psoadic", -"psoas", -"psoatic", -"psocid", -"psocine", -"psoitis", -"psora", -"psoric", -"psoroid", -"psorous", -"pst", -"psych", -"psychal", -"psyche", -"psychic", -"psychid", -"psychon", -"psykter", -"psylla", -"psyllid", -"ptarmic", -"ptereal", -"pteric", -"pterion", -"pteroid", -"pteroma", -"pteryla", -"ptinid", -"ptinoid", -"ptisan", -"ptomain", -"ptosis", -"ptotic", -"ptyalin", -"ptyxis", -"pu", -"pua", -"puan", -"pub", -"pubal", -"pubble", -"puberal", -"puberty", -"pubes", -"pubian", -"pubic", -"pubis", -"public", -"publish", -"puccoon", -"puce", -"pucelle", -"puchero", -"puck", -"pucka", -"pucker", -"puckery", -"puckish", -"puckle", -"puckrel", -"pud", -"puddee", -"pudder", -"pudding", -"puddle", -"puddled", -"puddler", -"puddly", -"puddock", -"puddy", -"pudency", -"pudenda", -"pudent", -"pudge", -"pudgily", -"pudgy", -"pudiano", -"pudic", -"pudical", -"pudsey", -"pudsy", -"pudu", -"pueblo", -"puerer", -"puerile", -"puerman", -"puff", -"puffed", -"puffer", -"puffery", -"puffily", -"puffin", -"puffing", -"pufflet", -"puffwig", -"puffy", -"pug", -"pugged", -"pugger", -"puggi", -"pugging", -"puggish", -"puggle", -"puggree", -"puggy", -"pugh", -"pugil", -"pugman", -"pugmill", -"puisne", -"puist", -"puistie", -"puja", -"puka", -"pukatea", -"puke", -"pukeko", -"puker", -"pukish", -"pukras", -"puku", -"puky", -"pul", -"pulahan", -"pulasan", -"pule", -"pulegol", -"puler", -"puli", -"pulicat", -"pulicid", -"puling", -"pulish", -"pulk", -"pulka", -"pull", -"pulldoo", -"pullen", -"puller", -"pullery", -"pullet", -"pulley", -"pulli", -"pullus", -"pulp", -"pulpal", -"pulper", -"pulpify", -"pulpily", -"pulpit", -"pulpous", -"pulpy", -"pulque", -"pulsant", -"pulsate", -"pulse", -"pulsion", -"pulsive", -"pulton", -"pulu", -"pulvic", -"pulvil", -"pulvino", -"pulwar", -"puly", -"puma", -"pumice", -"pumiced", -"pumicer", -"pummel", -"pummice", -"pump", -"pumpage", -"pumper", -"pumpkin", -"pumple", -"pumpman", -"pun", -"puna", -"punaise", -"punalua", -"punatoo", -"punch", -"puncher", -"punchy", -"punct", -"punctal", -"punctum", -"pundit", -"pundita", -"pundum", -"puneca", -"pung", -"punga", -"pungar", -"pungent", -"punger", -"pungey", -"pungi", -"pungle", -"pungled", -"punicin", -"punily", -"punish", -"punjum", -"punk", -"punkah", -"punkie", -"punky", -"punless", -"punlet", -"punnage", -"punner", -"punnet", -"punnic", -"punster", -"punt", -"punta", -"puntal", -"puntel", -"punter", -"punti", -"puntil", -"puntist", -"punto", -"puntout", -"punty", -"puny", -"punyish", -"punyism", -"pup", -"pupa", -"pupal", -"pupate", -"pupelo", -"pupil", -"pupilar", -"pupiled", -"pupoid", -"puppet", -"puppify", -"puppily", -"puppy", -"pupulo", -"pupunha", -"pur", -"purana", -"puranic", -"puraque", -"purdah", -"purdy", -"pure", -"pured", -"puree", -"purely", -"purer", -"purfle", -"purfled", -"purfler", -"purfly", -"purga", -"purge", -"purger", -"purgery", -"purging", -"purify", -"purine", -"puriri", -"purism", -"purist", -"purity", -"purl", -"purler", -"purlieu", -"purlin", -"purlman", -"purloin", -"purpart", -"purple", -"purply", -"purport", -"purpose", -"purpura", -"purpure", -"purr", -"purre", -"purree", -"purreic", -"purrel", -"purrer", -"purring", -"purrone", -"purry", -"purse", -"pursed", -"purser", -"pursily", -"purslet", -"pursley", -"pursual", -"pursue", -"pursuer", -"pursuit", -"pursy", -"purusha", -"purvey", -"purview", -"purvoe", -"pus", -"push", -"pusher", -"pushful", -"pushing", -"pushpin", -"puss", -"pusscat", -"pussley", -"pussy", -"pustule", -"put", -"putage", -"putamen", -"putback", -"putchen", -"putcher", -"puteal", -"putelee", -"puther", -"puthery", -"putid", -"putidly", -"putlog", -"putois", -"putrefy", -"putrid", -"putt", -"puttee", -"putter", -"puttier", -"puttock", -"putty", -"puture", -"puxy", -"puzzle", -"puzzled", -"puzzler", -"pya", -"pyal", -"pyche", -"pycnia", -"pycnial", -"pycnid", -"pycnite", -"pycnium", -"pyelic", -"pyemia", -"pyemic", -"pygal", -"pygarg", -"pygidid", -"pygmoid", -"pygmy", -"pygofer", -"pygopod", -"pyic", -"pyin", -"pyjama", -"pyke", -"pyknic", -"pyla", -"pylar", -"pylic", -"pylon", -"pyloric", -"pylorus", -"pyocele", -"pyocyst", -"pyocyte", -"pyoid", -"pyosis", -"pyr", -"pyral", -"pyralid", -"pyralis", -"pyramid", -"pyran", -"pyranyl", -"pyre", -"pyrena", -"pyrene", -"pyrenic", -"pyrenin", -"pyretic", -"pyrex", -"pyrexia", -"pyrexic", -"pyrgom", -"pyridic", -"pyridyl", -"pyrite", -"pyrites", -"pyritic", -"pyro", -"pyrogen", -"pyroid", -"pyrone", -"pyrope", -"pyropen", -"pyropus", -"pyrosis", -"pyrotic", -"pyrrhic", -"pyrrol", -"pyrrole", -"pyrroyl", -"pyrryl", -"pyruvic", -"pyruvil", -"pyruvyl", -"python", -"pyuria", -"pyvuril", -"pyx", -"pyxides", -"pyxie", -"pyxis", -"q", -"qasida", -"qere", -"qeri", -"qintar", -"qoph", -"qua", -"quab", -"quabird", -"quachil", -"quack", -"quackle", -"quacky", -"quad", -"quadded", -"quaddle", -"quadra", -"quadral", -"quadrat", -"quadric", -"quadrum", -"quaedam", -"quaff", -"quaffer", -"quag", -"quagga", -"quaggle", -"quaggy", -"quahog", -"quail", -"quaily", -"quaint", -"quake", -"quaker", -"quaking", -"quaky", -"quale", -"qualify", -"quality", -"qualm", -"qualmy", -"quan", -"quandy", -"quannet", -"quant", -"quanta", -"quantic", -"quantum", -"quar", -"quare", -"quark", -"quarl", -"quarle", -"quarred", -"quarrel", -"quarry", -"quart", -"quartan", -"quarter", -"quartet", -"quartic", -"quarto", -"quartz", -"quartzy", -"quash", -"quashey", -"quashy", -"quasi", -"quasky", -"quassin", -"quat", -"quata", -"quatch", -"quatern", -"quaters", -"quatral", -"quatre", -"quatrin", -"quattie", -"quatuor", -"quauk", -"quave", -"quaver", -"quavery", -"quaw", -"quawk", -"quay", -"quayage", -"quayful", -"quayman", -"qubba", -"queach", -"queachy", -"queak", -"queal", -"quean", -"queasom", -"queasy", -"quedful", -"queechy", -"queen", -"queenly", -"queer", -"queerer", -"queerly", -"queery", -"queest", -"queet", -"queeve", -"quegh", -"quei", -"quelch", -"quell", -"queller", -"quemado", -"queme", -"quemely", -"quench", -"quercic", -"quercin", -"querent", -"querier", -"querist", -"querken", -"querl", -"quern", -"quernal", -"query", -"quest", -"quester", -"questor", -"quet", -"quetch", -"quetzal", -"queue", -"quey", -"quiapo", -"quib", -"quibble", -"quiblet", -"quica", -"quick", -"quicken", -"quickie", -"quickly", -"quid", -"quidder", -"quiddit", -"quiddle", -"quiesce", -"quiet", -"quieten", -"quieter", -"quietly", -"quietus", -"quiff", -"quila", -"quiles", -"quilkin", -"quill", -"quillai", -"quilled", -"quiller", -"quillet", -"quilly", -"quilt", -"quilted", -"quilter", -"quin", -"quina", -"quinary", -"quinate", -"quince", -"quinch", -"quinia", -"quinic", -"quinin", -"quinina", -"quinine", -"quinism", -"quinite", -"quinize", -"quink", -"quinnat", -"quinnet", -"quinoa", -"quinoid", -"quinol", -"quinone", -"quinova", -"quinoyl", -"quinse", -"quinsy", -"quint", -"quintad", -"quintal", -"quintan", -"quinte", -"quintet", -"quintic", -"quintin", -"quinto", -"quinton", -"quintus", -"quinyl", -"quinze", -"quip", -"quipful", -"quipo", -"quipper", -"quippy", -"quipu", -"quira", -"quire", -"quirk", -"quirky", -"quirl", -"quirt", -"quis", -"quisby", -"quiscos", -"quisle", -"quit", -"quitch", -"quite", -"quits", -"quitted", -"quitter", -"quittor", -"quiver", -"quivery", -"quiz", -"quizzee", -"quizzer", -"quizzy", -"quo", -"quod", -"quoin", -"quoined", -"quoit", -"quoiter", -"quoits", -"quondam", -"quoniam", -"quop", -"quorum", -"quot", -"quota", -"quote", -"quotee", -"quoter", -"quoth", -"quotha", -"quotity", -"quotum", -"r", -"ra", -"raad", -"raash", -"rab", -"raband", -"rabanna", -"rabat", -"rabatte", -"rabbet", -"rabbi", -"rabbin", -"rabbit", -"rabbity", -"rabble", -"rabbler", -"rabboni", -"rabic", -"rabid", -"rabidly", -"rabies", -"rabific", -"rabinet", -"rabitic", -"raccoon", -"raccroc", -"race", -"raceme", -"racemed", -"racemic", -"racer", -"raceway", -"rach", -"rache", -"rachial", -"rachis", -"racial", -"racily", -"racing", -"racism", -"racist", -"rack", -"rackan", -"racker", -"racket", -"rackett", -"rackety", -"rackful", -"racking", -"rackle", -"rackway", -"racloir", -"racon", -"racoon", -"racy", -"rad", -"rada", -"radar", -"raddle", -"radial", -"radiale", -"radian", -"radiant", -"radiate", -"radical", -"radicel", -"radices", -"radicle", -"radii", -"radio", -"radiode", -"radish", -"radium", -"radius", -"radix", -"radman", -"radome", -"radon", -"radula", -"raff", -"raffe", -"raffee", -"raffery", -"raffia", -"raffing", -"raffish", -"raffle", -"raffler", -"raft", -"raftage", -"rafter", -"raftman", -"rafty", -"rag", -"raga", -"rage", -"rageful", -"rageous", -"rager", -"ragfish", -"ragged", -"raggedy", -"raggee", -"ragger", -"raggery", -"raggety", -"raggil", -"raggily", -"ragging", -"raggle", -"raggled", -"raggy", -"raging", -"raglan", -"raglet", -"raglin", -"ragman", -"ragout", -"ragshag", -"ragtag", -"ragtime", -"ragule", -"raguly", -"ragweed", -"ragwort", -"rah", -"rahdar", -"raia", -"raid", -"raider", -"rail", -"railage", -"railer", -"railing", -"railly", -"railman", -"railway", -"raiment", -"rain", -"rainbow", -"rainer", -"rainful", -"rainily", -"rainy", -"raioid", -"rais", -"raise", -"raised", -"raiser", -"raisin", -"raising", -"raisiny", -"raj", -"raja", -"rajah", -"rakan", -"rake", -"rakeage", -"rakeful", -"raker", -"rakery", -"rakh", -"raki", -"rakily", -"raking", -"rakish", -"rakit", -"raku", -"rallier", -"ralline", -"rally", -"ralph", -"ram", -"ramada", -"ramage", -"ramal", -"ramanas", -"ramass", -"ramate", -"rambeh", -"ramble", -"rambler", -"rambong", -"rame", -"rameal", -"ramed", -"ramekin", -"rament", -"rameous", -"ramet", -"ramex", -"ramhead", -"ramhood", -"rami", -"ramie", -"ramify", -"ramlike", -"ramline", -"rammack", -"rammel", -"rammer", -"rammish", -"rammy", -"ramose", -"ramous", -"ramp", -"rampage", -"rampant", -"rampart", -"ramped", -"ramper", -"rampick", -"rampike", -"ramping", -"rampion", -"rampire", -"rampler", -"ramplor", -"ramrace", -"ramrod", -"ramsch", -"ramson", -"ramstam", -"ramtil", -"ramular", -"ramule", -"ramulus", -"ramus", -"ran", -"rana", -"ranal", -"rance", -"rancel", -"rancer", -"ranch", -"ranche", -"rancher", -"rancho", -"rancid", -"rancor", -"rand", -"randan", -"randem", -"rander", -"randing", -"randir", -"randle", -"random", -"randy", -"rane", -"rang", -"range", -"ranged", -"ranger", -"rangey", -"ranging", -"rangle", -"rangler", -"rangy", -"rani", -"ranid", -"ranine", -"rank", -"ranked", -"ranker", -"rankish", -"rankle", -"rankly", -"rann", -"rannel", -"ranny", -"ransack", -"ransel", -"ransom", -"rant", -"rantan", -"ranter", -"ranting", -"rantock", -"ranty", -"ranula", -"ranular", -"rap", -"rape", -"rapeful", -"raper", -"raphany", -"raphe", -"raphide", -"raphis", -"rapic", -"rapid", -"rapidly", -"rapier", -"rapillo", -"rapine", -"rapiner", -"raping", -"rapinic", -"rapist", -"raploch", -"rappage", -"rappe", -"rappel", -"rapper", -"rapping", -"rappist", -"rapport", -"rapt", -"raptly", -"raptor", -"raptril", -"rapture", -"raptury", -"raptus", -"rare", -"rarebit", -"rarefy", -"rarely", -"rarish", -"rarity", -"ras", -"rasa", -"rasant", -"rascal", -"rasceta", -"rase", -"rasen", -"raser", -"rasgado", -"rash", -"rasher", -"rashful", -"rashing", -"rashly", -"rasion", -"rasp", -"rasped", -"rasper", -"rasping", -"raspish", -"raspite", -"raspy", -"rasse", -"rassle", -"raster", -"rastik", -"rastle", -"rasure", -"rat", -"rata", -"ratable", -"ratably", -"ratafee", -"ratafia", -"ratal", -"ratbite", -"ratch", -"ratchel", -"ratcher", -"ratchet", -"rate", -"rated", -"ratel", -"rater", -"ratfish", -"rath", -"rathe", -"rathed", -"rathely", -"rather", -"rathest", -"rathite", -"rathole", -"ratify", -"ratine", -"rating", -"ratio", -"ration", -"ratite", -"ratlike", -"ratline", -"ratoon", -"rattage", -"rattail", -"rattan", -"ratteen", -"ratten", -"ratter", -"rattery", -"ratti", -"rattish", -"rattle", -"rattled", -"rattler", -"rattles", -"rattly", -"ratton", -"rattrap", -"ratty", -"ratwa", -"ratwood", -"raucid", -"raucity", -"raucous", -"raught", -"rauk", -"raukle", -"rauli", -"raun", -"raunge", -"raupo", -"rauque", -"ravage", -"ravager", -"rave", -"ravel", -"raveler", -"ravelin", -"ravelly", -"raven", -"ravener", -"ravenry", -"ravens", -"raver", -"ravin", -"ravine", -"ravined", -"raviney", -"raving", -"ravioli", -"ravish", -"ravison", -"raw", -"rawhead", -"rawhide", -"rawish", -"rawness", -"rax", -"ray", -"raya", -"rayage", -"rayed", -"rayful", -"rayless", -"raylet", -"rayon", -"raze", -"razee", -"razer", -"razoo", -"razor", -"razz", -"razzia", -"razzly", -"re", -"rea", -"reaal", -"reabuse", -"reach", -"reacher", -"reachy", -"react", -"reactor", -"read", -"readapt", -"readd", -"reader", -"readily", -"reading", -"readmit", -"readopt", -"readorn", -"ready", -"reagent", -"reagin", -"reagree", -"reak", -"real", -"realarm", -"reales", -"realest", -"realgar", -"realign", -"realism", -"realist", -"reality", -"realive", -"realize", -"reallot", -"reallow", -"really", -"realm", -"realter", -"realtor", -"realty", -"ream", -"reamage", -"reamass", -"reamend", -"reamer", -"reamuse", -"reamy", -"reannex", -"reannoy", -"reanvil", -"reap", -"reaper", -"reapply", -"rear", -"rearer", -"reargue", -"rearise", -"rearm", -"rearray", -"reask", -"reason", -"reassay", -"reasty", -"reasy", -"reatus", -"reaudit", -"reavail", -"reave", -"reaver", -"reavoid", -"reavow", -"reawait", -"reawake", -"reaward", -"reaware", -"reb", -"rebab", -"reback", -"rebag", -"rebait", -"rebake", -"rebale", -"reban", -"rebar", -"rebase", -"rebasis", -"rebate", -"rebater", -"rebathe", -"rebato", -"rebawl", -"rebear", -"rebeat", -"rebec", -"rebeck", -"rebed", -"rebeg", -"rebeget", -"rebegin", -"rebel", -"rebelly", -"rebend", -"rebeset", -"rebia", -"rebias", -"rebid", -"rebill", -"rebind", -"rebirth", -"rebite", -"reblade", -"reblame", -"reblast", -"reblend", -"rebless", -"reblock", -"rebloom", -"reblot", -"reblow", -"reblue", -"rebluff", -"reboant", -"reboard", -"reboast", -"rebob", -"reboil", -"reboise", -"rebold", -"rebolt", -"rebone", -"rebook", -"rebop", -"rebore", -"reborn", -"rebound", -"rebox", -"rebrace", -"rebraid", -"rebrand", -"rebreed", -"rebrew", -"rebribe", -"rebrick", -"rebring", -"rebrown", -"rebrush", -"rebud", -"rebuff", -"rebuild", -"rebuilt", -"rebuke", -"rebuker", -"rebulk", -"rebunch", -"rebuoy", -"reburn", -"reburst", -"rebury", -"rebus", -"rebush", -"rebusy", -"rebut", -"rebute", -"rebuy", -"recable", -"recage", -"recalk", -"recall", -"recant", -"recap", -"recarry", -"recart", -"recarve", -"recase", -"recash", -"recast", -"recatch", -"recce", -"recco", -"reccy", -"recede", -"receder", -"receipt", -"receive", -"recency", -"recense", -"recent", -"recept", -"recess", -"rechafe", -"rechain", -"rechal", -"rechant", -"rechaos", -"rechar", -"rechase", -"rechaw", -"recheat", -"recheck", -"recheer", -"rechew", -"rechip", -"rechuck", -"rechurn", -"recipe", -"recital", -"recite", -"reciter", -"reck", -"reckla", -"reckon", -"reclaim", -"reclama", -"reclang", -"reclasp", -"reclass", -"reclean", -"reclear", -"reclimb", -"recline", -"reclose", -"recluse", -"recoach", -"recoal", -"recoast", -"recoat", -"recock", -"recoct", -"recode", -"recoil", -"recoin", -"recoke", -"recolor", -"recomb", -"recon", -"recook", -"recool", -"recopy", -"record", -"recork", -"recount", -"recoup", -"recover", -"recramp", -"recrank", -"recrate", -"recrew", -"recroon", -"recrop", -"recross", -"recrowd", -"recrown", -"recruit", -"recrush", -"rect", -"recta", -"rectal", -"recti", -"rectify", -"rection", -"recto", -"rector", -"rectory", -"rectrix", -"rectum", -"rectus", -"recur", -"recure", -"recurl", -"recurse", -"recurve", -"recuse", -"recut", -"recycle", -"red", -"redact", -"redan", -"redare", -"redarn", -"redart", -"redate", -"redaub", -"redawn", -"redback", -"redbait", -"redbill", -"redbird", -"redbone", -"redbuck", -"redbud", -"redcap", -"redcoat", -"redd", -"redden", -"redder", -"redding", -"reddish", -"reddock", -"reddy", -"rede", -"redeal", -"redebit", -"redeck", -"redeed", -"redeem", -"redefer", -"redefy", -"redeify", -"redelay", -"redeny", -"redeye", -"redfin", -"redfish", -"redfoot", -"redhead", -"redhoop", -"redia", -"redient", -"redig", -"redip", -"redive", -"redleg", -"redlegs", -"redly", -"redness", -"redo", -"redock", -"redoom", -"redoubt", -"redound", -"redowa", -"redox", -"redpoll", -"redraft", -"redrag", -"redrape", -"redraw", -"redream", -"redress", -"redrill", -"redrive", -"redroot", -"redry", -"redsear", -"redskin", -"redtab", -"redtail", -"redtop", -"redub", -"reduce", -"reduced", -"reducer", -"reduct", -"redue", -"redux", -"redward", -"redware", -"redweed", -"redwing", -"redwood", -"redye", -"ree", -"reechy", -"reed", -"reeded", -"reeden", -"reeder", -"reedily", -"reeding", -"reedish", -"reedman", -"reedy", -"reef", -"reefer", -"reefing", -"reefy", -"reek", -"reeker", -"reeky", -"reel", -"reeled", -"reeler", -"reem", -"reeming", -"reemish", -"reen", -"reenge", -"reeper", -"reese", -"reeshle", -"reesk", -"reesle", -"reest", -"reester", -"reestle", -"reesty", -"reet", -"reetam", -"reetle", -"reeve", -"ref", -"reface", -"refall", -"refan", -"refavor", -"refect", -"refeed", -"refeel", -"refeign", -"refel", -"refence", -"refer", -"referee", -"refetch", -"refight", -"refill", -"refilm", -"refind", -"refine", -"refined", -"refiner", -"refire", -"refit", -"refix", -"reflag", -"reflame", -"reflash", -"reflate", -"reflect", -"reflee", -"reflex", -"refling", -"refloat", -"reflog", -"reflood", -"refloor", -"reflow", -"reflush", -"reflux", -"refly", -"refocus", -"refold", -"refont", -"refool", -"refoot", -"reforce", -"reford", -"reforge", -"reform", -"refound", -"refract", -"refrain", -"reframe", -"refresh", -"refront", -"reft", -"refuel", -"refuge", -"refugee", -"refulge", -"refund", -"refurl", -"refusal", -"refuse", -"refuser", -"refutal", -"refute", -"refuter", -"reg", -"regain", -"regal", -"regale", -"regaler", -"regalia", -"regally", -"regard", -"regatta", -"regauge", -"regency", -"regent", -"reges", -"reget", -"regia", -"regift", -"regild", -"regill", -"regime", -"regimen", -"regin", -"reginal", -"region", -"regive", -"reglair", -"reglaze", -"regle", -"reglet", -"regloss", -"reglove", -"reglow", -"reglue", -"regma", -"regnal", -"regnant", -"regorge", -"regrade", -"regraft", -"regrant", -"regrasp", -"regrass", -"regrate", -"regrede", -"regreen", -"regreet", -"regress", -"regret", -"regrind", -"regrip", -"regroup", -"regrow", -"reguard", -"reguide", -"regula", -"regular", -"reguli", -"regulus", -"regur", -"regurge", -"regush", -"reh", -"rehair", -"rehale", -"rehang", -"reharm", -"rehash", -"rehaul", -"rehead", -"reheal", -"reheap", -"rehear", -"reheat", -"rehedge", -"reheel", -"rehoe", -"rehoist", -"rehonor", -"rehood", -"rehook", -"rehoop", -"rehouse", -"rehung", -"reif", -"reify", -"reign", -"reim", -"reimage", -"reimpel", -"reimply", -"rein", -"reina", -"reincur", -"reindue", -"reinfer", -"reins", -"reinter", -"reis", -"reissue", -"reit", -"reitbok", -"reiter", -"reiver", -"rejail", -"reject", -"rejerk", -"rejoice", -"rejoin", -"rejolt", -"rejudge", -"rekick", -"rekill", -"reking", -"rekiss", -"reknit", -"reknow", -"rel", -"relabel", -"relace", -"relade", -"reladen", -"relais", -"relamp", -"reland", -"relap", -"relapse", -"relast", -"relata", -"relatch", -"relate", -"related", -"relater", -"relator", -"relatum", -"relax", -"relaxed", -"relaxer", -"relay", -"relbun", -"relead", -"releap", -"relearn", -"release", -"relend", -"relent", -"relet", -"relevel", -"relevy", -"reliant", -"relic", -"relick", -"relict", -"relief", -"relier", -"relieve", -"relievo", -"relift", -"relight", -"relime", -"relimit", -"reline", -"reliner", -"relink", -"relish", -"relishy", -"relist", -"relive", -"reload", -"reloan", -"relock", -"relodge", -"relook", -"relose", -"relost", -"relot", -"relove", -"relower", -"reluct", -"relume", -"rely", -"remade", -"remail", -"remain", -"remains", -"remake", -"remaker", -"reman", -"remand", -"remanet", -"remap", -"remarch", -"remark", -"remarry", -"remask", -"remass", -"remast", -"rematch", -"remble", -"remeant", -"remede", -"remedy", -"remeet", -"remelt", -"remend", -"remerge", -"remetal", -"remex", -"remica", -"remicle", -"remiges", -"remill", -"remimic", -"remind", -"remint", -"remiped", -"remise", -"remiss", -"remit", -"remix", -"remnant", -"remock", -"remodel", -"remold", -"remop", -"remora", -"remord", -"remorse", -"remote", -"remould", -"remount", -"removal", -"remove", -"removed", -"remover", -"renable", -"renably", -"renail", -"renal", -"rename", -"rend", -"render", -"reneg", -"renege", -"reneger", -"renegue", -"renerve", -"renes", -"renet", -"renew", -"renewal", -"renewer", -"renin", -"renish", -"renk", -"renky", -"renne", -"rennet", -"rennin", -"renown", -"rent", -"rentage", -"rental", -"rented", -"rentee", -"renter", -"renvoi", -"renvoy", -"reoccur", -"reoffer", -"reoil", -"reomit", -"reopen", -"reorder", -"reown", -"rep", -"repace", -"repack", -"repage", -"repaint", -"repair", -"repale", -"repand", -"repanel", -"repaper", -"repark", -"repass", -"repast", -"repaste", -"repatch", -"repave", -"repawn", -"repay", -"repayal", -"repeal", -"repeat", -"repeg", -"repel", -"repen", -"repent", -"repew", -"rephase", -"repic", -"repick", -"repiece", -"repile", -"repin", -"repine", -"repiner", -"repipe", -"repique", -"repitch", -"repkie", -"replace", -"replait", -"replan", -"replane", -"replant", -"replate", -"replay", -"replead", -"repleat", -"replete", -"replevy", -"replica", -"replier", -"replod", -"replot", -"replow", -"replum", -"replume", -"reply", -"repoint", -"repoll", -"repolon", -"repone", -"repope", -"report", -"reposal", -"repose", -"reposed", -"reposer", -"reposit", -"repost", -"repot", -"repound", -"repour", -"repp", -"repped", -"repray", -"repress", -"reprice", -"reprime", -"reprint", -"reprise", -"reproof", -"reprove", -"reprune", -"reps", -"reptant", -"reptile", -"repuff", -"repugn", -"repulse", -"repump", -"repurge", -"repute", -"reputed", -"requeen", -"request", -"requiem", -"requin", -"require", -"requit", -"requite", -"requiz", -"requote", -"rerack", -"rerail", -"reraise", -"rerake", -"rerank", -"rerate", -"reread", -"reredos", -"reree", -"rereel", -"rereeve", -"rereign", -"rerent", -"rerig", -"rering", -"rerise", -"rerival", -"rerivet", -"rerob", -"rerobe", -"reroll", -"reroof", -"reroot", -"rerope", -"reroute", -"rerow", -"rerub", -"rerun", -"resaca", -"resack", -"resail", -"resale", -"resalt", -"resaw", -"resawer", -"resay", -"rescan", -"rescind", -"rescore", -"rescrub", -"rescue", -"rescuer", -"reseal", -"reseam", -"reseat", -"resect", -"reseda", -"resee", -"reseed", -"reseek", -"reseise", -"reseize", -"reself", -"resell", -"resend", -"resene", -"resent", -"reserve", -"reset", -"resever", -"resew", -"resex", -"resh", -"reshake", -"reshape", -"reshare", -"reshave", -"reshear", -"reshift", -"reshine", -"reship", -"reshoe", -"reshoot", -"reshun", -"reshunt", -"reshut", -"reside", -"resider", -"residua", -"residue", -"resift", -"resigh", -"resign", -"resile", -"resin", -"resina", -"resiner", -"resing", -"resinic", -"resink", -"resinol", -"resiny", -"resist", -"resize", -"resizer", -"reskin", -"reslash", -"reslate", -"reslay", -"reslide", -"reslot", -"resmell", -"resmelt", -"resmile", -"resnap", -"resnub", -"resoak", -"resoap", -"resoil", -"resole", -"resolve", -"resorb", -"resort", -"resound", -"resow", -"resp", -"respace", -"respade", -"respan", -"respeak", -"respect", -"respell", -"respin", -"respire", -"respite", -"resplit", -"respoke", -"respond", -"respot", -"respray", -"respue", -"ressala", -"ressaut", -"rest", -"restack", -"restaff", -"restain", -"restake", -"restamp", -"restant", -"restart", -"restate", -"restaur", -"resteal", -"resteel", -"resteep", -"restem", -"restep", -"rester", -"restes", -"restful", -"restiad", -"restiff", -"resting", -"restir", -"restis", -"restive", -"restock", -"restore", -"restow", -"restrap", -"restrip", -"restudy", -"restuff", -"resty", -"restyle", -"resuck", -"resue", -"resuing", -"resuit", -"result", -"resume", -"resumer", -"resun", -"resup", -"resurge", -"reswage", -"resward", -"reswarm", -"reswear", -"resweat", -"resweep", -"reswell", -"reswill", -"reswim", -"ret", -"retable", -"retack", -"retag", -"retail", -"retain", -"retake", -"retaker", -"retalk", -"retama", -"retame", -"retan", -"retape", -"retard", -"retare", -"retaste", -"retax", -"retch", -"reteach", -"retell", -"retem", -"retempt", -"retene", -"retent", -"retest", -"rethank", -"rethaw", -"rethe", -"rethink", -"rethrow", -"retia", -"retial", -"retiary", -"reticle", -"retie", -"retier", -"retile", -"retill", -"retime", -"retin", -"retina", -"retinal", -"retinol", -"retinue", -"retip", -"retiral", -"retire", -"retired", -"retirer", -"retoast", -"retold", -"retomb", -"retook", -"retool", -"retooth", -"retort", -"retoss", -"retotal", -"retouch", -"retour", -"retrace", -"retrack", -"retract", -"retrad", -"retrade", -"retrain", -"retral", -"retramp", -"retread", -"retreat", -"retree", -"retrial", -"retrim", -"retrip", -"retrot", -"retrude", -"retrue", -"retrust", -"retry", -"retted", -"retter", -"rettery", -"retting", -"rettory", -"retube", -"retuck", -"retune", -"returf", -"return", -"retuse", -"retwine", -"retwist", -"retying", -"retype", -"retzian", -"reune", -"reunify", -"reunion", -"reunite", -"reurge", -"reuse", -"reutter", -"rev", -"revalue", -"revamp", -"revary", -"reve", -"reveal", -"reveil", -"revel", -"reveler", -"revelly", -"revelry", -"revend", -"revenge", -"revent", -"revenue", -"rever", -"reverb", -"revere", -"revered", -"reverer", -"reverie", -"revers", -"reverse", -"reversi", -"reverso", -"revert", -"revery", -"revest", -"revet", -"revete", -"revie", -"review", -"revile", -"reviler", -"revisal", -"revise", -"revisee", -"reviser", -"revisit", -"revisor", -"revival", -"revive", -"reviver", -"revivor", -"revoice", -"revoke", -"revoker", -"revolt", -"revolve", -"revomit", -"revote", -"revue", -"revuist", -"rewade", -"rewager", -"rewake", -"rewaken", -"rewall", -"reward", -"rewarm", -"rewarn", -"rewash", -"rewater", -"rewave", -"rewax", -"rewayle", -"rewear", -"reweave", -"rewed", -"reweigh", -"reweld", -"rewend", -"rewet", -"rewhelp", -"rewhirl", -"rewiden", -"rewin", -"rewind", -"rewire", -"rewish", -"rewood", -"reword", -"rework", -"rewound", -"rewove", -"rewoven", -"rewrap", -"rewrite", -"rex", -"rexen", -"reyield", -"reyoke", -"reyouth", -"rhabdom", -"rhabdos", -"rhabdus", -"rhagite", -"rhagon", -"rhagose", -"rhamn", -"rhamnal", -"rhason", -"rhatany", -"rhe", -"rhea", -"rhebok", -"rheeboc", -"rheebok", -"rheen", -"rheic", -"rhein", -"rheinic", -"rhema", -"rheme", -"rhenium", -"rheotan", -"rhesian", -"rhesus", -"rhetor", -"rheum", -"rheumed", -"rheumic", -"rheumy", -"rhexis", -"rhinal", -"rhine", -"rhinion", -"rhino", -"rhizine", -"rhizoid", -"rhizoma", -"rhizome", -"rhizote", -"rho", -"rhodic", -"rhoding", -"rhodite", -"rhodium", -"rhomb", -"rhombic", -"rhombos", -"rhombus", -"rhubarb", -"rhumb", -"rhumba", -"rhyme", -"rhymer", -"rhymery", -"rhymic", -"rhymist", -"rhymy", -"rhyptic", -"rhythm", -"rhyton", -"ria", -"rial", -"riancy", -"riant", -"riantly", -"riata", -"rib", -"ribald", -"riband", -"ribat", -"ribband", -"ribbed", -"ribber", -"ribbet", -"ribbing", -"ribble", -"ribbon", -"ribbony", -"ribby", -"ribe", -"ribless", -"riblet", -"riblike", -"ribonic", -"ribose", -"ribskin", -"ribwork", -"ribwort", -"rice", -"ricer", -"ricey", -"rich", -"richdom", -"richen", -"riches", -"richly", -"richt", -"ricin", -"ricine", -"ricinic", -"ricinus", -"rick", -"ricker", -"rickets", -"rickety", -"rickey", -"rickle", -"ricksha", -"ricrac", -"rictal", -"rictus", -"rid", -"ridable", -"ridably", -"riddam", -"riddel", -"ridden", -"ridder", -"ridding", -"riddle", -"riddler", -"ride", -"rideau", -"riden", -"rident", -"rider", -"ridered", -"ridge", -"ridged", -"ridgel", -"ridger", -"ridgil", -"ridging", -"ridgy", -"riding", -"ridotto", -"rie", -"riem", -"riempie", -"rier", -"rife", -"rifely", -"riff", -"riffle", -"riffler", -"rifle", -"rifler", -"riflery", -"rifling", -"rift", -"rifter", -"rifty", -"rig", -"rigbane", -"riggald", -"rigger", -"rigging", -"riggish", -"riggite", -"riggot", -"right", -"righten", -"righter", -"rightle", -"rightly", -"righto", -"righty", -"rigid", -"rigidly", -"rigling", -"rignum", -"rigol", -"rigor", -"rigsby", -"rikisha", -"rikk", -"riksha", -"rikshaw", -"rilawa", -"rile", -"riley", -"rill", -"rillet", -"rillett", -"rillock", -"rilly", -"rim", -"rima", -"rimal", -"rimate", -"rimbase", -"rime", -"rimer", -"rimfire", -"rimland", -"rimless", -"rimmed", -"rimmer", -"rimose", -"rimous", -"rimpi", -"rimple", -"rimrock", -"rimu", -"rimula", -"rimy", -"rinceau", -"rinch", -"rincon", -"rind", -"rinded", -"rindle", -"rindy", -"rine", -"ring", -"ringe", -"ringed", -"ringent", -"ringer", -"ringeye", -"ringing", -"ringite", -"ringle", -"ringlet", -"ringman", -"ringtaw", -"ringy", -"rink", -"rinka", -"rinker", -"rinkite", -"rinner", -"rinse", -"rinser", -"rinsing", -"rio", -"riot", -"rioter", -"rioting", -"riotist", -"riotous", -"riotry", -"rip", -"ripa", -"ripal", -"ripcord", -"ripe", -"ripely", -"ripen", -"ripener", -"riper", -"ripgut", -"ripieno", -"ripier", -"ripost", -"riposte", -"ripper", -"rippet", -"rippier", -"ripping", -"rippit", -"ripple", -"rippler", -"ripplet", -"ripply", -"rippon", -"riprap", -"ripsack", -"ripsaw", -"ripup", -"risala", -"risberm", -"rise", -"risen", -"riser", -"rishi", -"risible", -"risibly", -"rising", -"risk", -"risker", -"riskful", -"riskily", -"riskish", -"risky", -"risp", -"risper", -"risque", -"risquee", -"rissel", -"risser", -"rissle", -"rissoid", -"rist", -"ristori", -"rit", -"rita", -"rite", -"ritling", -"ritual", -"ritzy", -"riva", -"rivage", -"rival", -"rivalry", -"rive", -"rivel", -"rivell", -"riven", -"river", -"rivered", -"riverly", -"rivery", -"rivet", -"riveter", -"riving", -"rivose", -"rivulet", -"rix", -"rixy", -"riyal", -"rizzar", -"rizzle", -"rizzom", -"roach", -"road", -"roadbed", -"roaded", -"roader", -"roading", -"roadite", -"roadman", -"roadway", -"roam", -"roamage", -"roamer", -"roaming", -"roan", -"roanoke", -"roar", -"roarer", -"roaring", -"roast", -"roaster", -"rob", -"robalo", -"roband", -"robber", -"robbery", -"robbin", -"robbing", -"robe", -"rober", -"roberd", -"robin", -"robinet", -"robing", -"robinin", -"roble", -"robomb", -"robot", -"robotry", -"robur", -"robust", -"roc", -"rocher", -"rochet", -"rock", -"rockaby", -"rocker", -"rockery", -"rocket", -"rockety", -"rocking", -"rockish", -"rocklay", -"rocklet", -"rockman", -"rocky", -"rococo", -"rocta", -"rod", -"rodd", -"roddin", -"rodding", -"rode", -"rodent", -"rodeo", -"rodge", -"rodham", -"roding", -"rodless", -"rodlet", -"rodlike", -"rodman", -"rodney", -"rodsman", -"rodster", -"rodwood", -"roe", -"roebuck", -"roed", -"roelike", -"roer", -"roey", -"rog", -"rogan", -"roger", -"roggle", -"rogue", -"roguery", -"roguing", -"roguish", -"rohan", -"rohob", -"rohun", -"rohuna", -"roi", -"roid", -"roil", -"roily", -"roister", -"roit", -"roka", -"roke", -"rokeage", -"rokee", -"rokelay", -"roker", -"rokey", -"roky", -"role", -"roleo", -"roll", -"rolled", -"roller", -"rolley", -"rollick", -"rolling", -"rollix", -"rollmop", -"rollock", -"rollway", -"roloway", -"romaika", -"romaine", -"romal", -"romance", -"romancy", -"romanza", -"romaunt", -"rombos", -"romeite", -"romero", -"rommack", -"romp", -"romper", -"romping", -"rompish", -"rompu", -"rompy", -"roncet", -"ronco", -"rond", -"ronde", -"rondeau", -"rondel", -"rondino", -"rondle", -"rondo", -"rondure", -"rone", -"rongeur", -"ronquil", -"rontgen", -"ronyon", -"rood", -"roodle", -"roof", -"roofage", -"roofer", -"roofing", -"rooflet", -"roofman", -"roofy", -"rooibok", -"rooinek", -"rook", -"rooker", -"rookery", -"rookie", -"rookish", -"rooklet", -"rooky", -"rool", -"room", -"roomage", -"roomed", -"roomer", -"roomful", -"roomie", -"roomily", -"roomlet", -"roomth", -"roomthy", -"roomy", -"roon", -"roosa", -"roost", -"roosted", -"rooster", -"root", -"rootage", -"rootcap", -"rooted", -"rooter", -"rootery", -"rootle", -"rootlet", -"rooty", -"roove", -"ropable", -"rope", -"ropeman", -"roper", -"ropery", -"ropes", -"ropeway", -"ropily", -"roping", -"ropish", -"ropp", -"ropy", -"roque", -"roquer", -"roquet", -"roquist", -"roral", -"roric", -"rorqual", -"rorty", -"rory", -"rosal", -"rosario", -"rosary", -"rosated", -"roscid", -"rose", -"roseal", -"roseate", -"rosebay", -"rosebud", -"rosed", -"roseine", -"rosel", -"roselet", -"rosella", -"roselle", -"roseola", -"roseous", -"rosery", -"roset", -"rosetan", -"rosette", -"rosetty", -"rosetum", -"rosety", -"rosied", -"rosier", -"rosilla", -"rosillo", -"rosily", -"rosin", -"rosiny", -"rosland", -"rosoli", -"rosolic", -"rosolio", -"ross", -"rosser", -"rossite", -"rostel", -"roster", -"rostra", -"rostral", -"rostrum", -"rosular", -"rosy", -"rot", -"rota", -"rotal", -"rotaman", -"rotan", -"rotang", -"rotary", -"rotate", -"rotated", -"rotator", -"rotch", -"rote", -"rotella", -"roter", -"rotge", -"rotgut", -"rother", -"rotifer", -"roto", -"rotor", -"rottan", -"rotten", -"rotter", -"rotting", -"rottle", -"rottock", -"rottolo", -"rotula", -"rotulad", -"rotular", -"rotulet", -"rotulus", -"rotund", -"rotunda", -"rotundo", -"roub", -"roucou", -"roud", -"roue", -"rouelle", -"rouge", -"rougeau", -"rougeot", -"rough", -"roughen", -"rougher", -"roughet", -"roughie", -"roughly", -"roughy", -"rougy", -"rouille", -"rouky", -"roulade", -"rouleau", -"roun", -"rounce", -"rouncy", -"round", -"rounded", -"roundel", -"rounder", -"roundly", -"roundup", -"roundy", -"roup", -"rouper", -"roupet", -"roupily", -"roupit", -"roupy", -"rouse", -"rouser", -"rousing", -"roust", -"rouster", -"rout", -"route", -"router", -"routh", -"routhie", -"routhy", -"routine", -"routing", -"routous", -"rove", -"rover", -"rovet", -"rovetto", -"roving", -"row", -"rowable", -"rowan", -"rowboat", -"rowdily", -"rowdy", -"rowed", -"rowel", -"rowen", -"rower", -"rowet", -"rowing", -"rowlet", -"rowlock", -"rowport", -"rowty", -"rowy", -"rox", -"roxy", -"royal", -"royale", -"royalet", -"royally", -"royalty", -"royet", -"royt", -"rozum", -"ruach", -"ruana", -"rub", -"rubasse", -"rubato", -"rubbed", -"rubber", -"rubbers", -"rubbery", -"rubbing", -"rubbish", -"rubble", -"rubbler", -"rubbly", -"rubdown", -"rubelet", -"rubella", -"rubelle", -"rubeola", -"rubiate", -"rubican", -"rubidic", -"rubied", -"rubific", -"rubify", -"rubine", -"rubious", -"ruble", -"rublis", -"rubor", -"rubric", -"rubrica", -"rubrify", -"ruby", -"ruche", -"ruching", -"ruck", -"rucker", -"ruckle", -"rucksey", -"ruckus", -"rucky", -"ruction", -"rud", -"rudas", -"rudd", -"rudder", -"ruddied", -"ruddily", -"ruddle", -"ruddock", -"ruddy", -"rude", -"rudely", -"ruderal", -"rudesby", -"rudge", -"rudish", -"rudity", -"rue", -"rueful", -"ruelike", -"ruelle", -"ruen", -"ruer", -"ruesome", -"ruewort", -"ruff", -"ruffed", -"ruffer", -"ruffian", -"ruffin", -"ruffle", -"ruffled", -"ruffler", -"ruffly", -"rufous", -"rufter", -"rufus", -"rug", -"ruga", -"rugate", -"rugged", -"rugging", -"ruggle", -"ruggy", -"ruglike", -"rugosa", -"rugose", -"rugous", -"ruin", -"ruinate", -"ruined", -"ruiner", -"ruing", -"ruinous", -"rukh", -"rulable", -"rule", -"ruledom", -"ruler", -"ruling", -"rull", -"ruller", -"rullion", -"rum", -"rumal", -"rumble", -"rumbler", -"rumbly", -"rumbo", -"rumen", -"ruminal", -"rumkin", -"rumless", -"rumly", -"rummage", -"rummagy", -"rummer", -"rummily", -"rummish", -"rummy", -"rumness", -"rumney", -"rumor", -"rumorer", -"rump", -"rumpad", -"rumpade", -"rumple", -"rumply", -"rumpus", -"rumshop", -"run", -"runaway", -"runback", -"runby", -"runch", -"rundale", -"rundle", -"rundlet", -"rune", -"runed", -"runer", -"runfish", -"rung", -"runic", -"runite", -"runkle", -"runkly", -"runless", -"runlet", -"runman", -"runnel", -"runner", -"runnet", -"running", -"runny", -"runoff", -"runout", -"runover", -"runrig", -"runt", -"runted", -"runtee", -"runtish", -"runty", -"runway", -"rupa", -"rupee", -"rupia", -"rupiah", -"rupial", -"rupie", -"rupitic", -"ruptile", -"ruption", -"ruptive", -"rupture", -"rural", -"rurally", -"rurban", -"ruru", -"ruse", -"rush", -"rushed", -"rushen", -"rusher", -"rushing", -"rushlit", -"rushy", -"rusine", -"rusk", -"ruskin", -"rusky", -"rusma", -"rusot", -"ruspone", -"russel", -"russet", -"russety", -"russia", -"russud", -"rust", -"rustful", -"rustic", -"rustily", -"rustle", -"rustler", -"rustly", -"rustre", -"rustred", -"rusty", -"ruswut", -"rut", -"rutate", -"rutch", -"ruth", -"ruther", -"ruthful", -"rutic", -"rutile", -"rutin", -"ruttee", -"rutter", -"ruttish", -"rutty", -"rutyl", -"ruvid", -"rux", -"ryal", -"ryania", -"rybat", -"ryder", -"rye", -"ryen", -"ryme", -"rynd", -"rynt", -"ryot", -"ryotwar", -"rype", -"rypeck", -"s", -"sa", -"saa", -"sab", -"sabalo", -"sabanut", -"sabbat", -"sabbath", -"sabe", -"sabeca", -"sabella", -"saber", -"sabered", -"sabicu", -"sabina", -"sabine", -"sabino", -"sable", -"sably", -"sabora", -"sabot", -"saboted", -"sabra", -"sabulum", -"saburra", -"sabutan", -"sabzi", -"sac", -"sacaton", -"sacatra", -"saccade", -"saccate", -"saccos", -"saccule", -"saccus", -"sachem", -"sachet", -"sack", -"sackage", -"sackbag", -"sackbut", -"sacked", -"sacken", -"sacker", -"sackful", -"sacking", -"sackman", -"saclike", -"saco", -"sacope", -"sacque", -"sacra", -"sacrad", -"sacral", -"sacred", -"sacring", -"sacrist", -"sacro", -"sacrum", -"sad", -"sadden", -"saddik", -"saddish", -"saddle", -"saddled", -"saddler", -"sade", -"sadh", -"sadhe", -"sadhu", -"sadic", -"sadiron", -"sadism", -"sadist", -"sadly", -"sadness", -"sado", -"sadr", -"saecula", -"saeter", -"saeume", -"safari", -"safe", -"safely", -"safen", -"safener", -"safety", -"saffian", -"safflor", -"safflow", -"saffron", -"safrole", -"saft", -"sag", -"saga", -"sagaie", -"sagaman", -"sagathy", -"sage", -"sagely", -"sagene", -"sagger", -"sagging", -"saggon", -"saggy", -"saging", -"sagitta", -"sagless", -"sago", -"sagoin", -"saguaro", -"sagum", -"saguran", -"sagwire", -"sagy", -"sah", -"sahh", -"sahib", -"sahme", -"sahukar", -"sai", -"saic", -"said", -"saiga", -"sail", -"sailage", -"sailed", -"sailer", -"sailing", -"sailor", -"saily", -"saim", -"saimiri", -"saimy", -"sain", -"saint", -"sainted", -"saintly", -"saip", -"sair", -"sairly", -"sairve", -"sairy", -"saithe", -"saj", -"sajou", -"sake", -"sakeber", -"sakeen", -"saker", -"sakeret", -"saki", -"sakieh", -"sakulya", -"sal", -"salaam", -"salable", -"salably", -"salacot", -"salad", -"salago", -"salal", -"salamo", -"salar", -"salary", -"salat", -"salay", -"sale", -"salele", -"salema", -"salep", -"salfern", -"salic", -"salicin", -"salicyl", -"salient", -"salify", -"saligot", -"salina", -"saline", -"salite", -"salited", -"saliva", -"salival", -"salix", -"salle", -"sallee", -"sallet", -"sallier", -"salloo", -"sallow", -"sallowy", -"sally", -"salma", -"salmiac", -"salmine", -"salmis", -"salmon", -"salol", -"salomon", -"salon", -"saloon", -"saloop", -"salp", -"salpa", -"salpian", -"salpinx", -"salpoid", -"salse", -"salsify", -"salt", -"salta", -"saltant", -"saltary", -"saltate", -"saltcat", -"salted", -"saltee", -"salten", -"salter", -"saltern", -"saltery", -"saltfat", -"saltier", -"saltine", -"salting", -"saltish", -"saltly", -"saltman", -"saltpan", -"saltus", -"salty", -"saluki", -"salung", -"salute", -"saluter", -"salvage", -"salve", -"salver", -"salviol", -"salvo", -"salvor", -"salvy", -"sam", -"samadh", -"samadhi", -"samaj", -"saman", -"samara", -"samaria", -"samarra", -"samba", -"sambal", -"sambar", -"sambo", -"sambuk", -"sambuke", -"same", -"samekh", -"samel", -"samely", -"samen", -"samh", -"samhita", -"samiel", -"samiri", -"samisen", -"samite", -"samkara", -"samlet", -"sammel", -"sammer", -"sammier", -"sammy", -"samovar", -"samp", -"sampan", -"sampi", -"sample", -"sampler", -"samsara", -"samshu", -"samson", -"samurai", -"san", -"sanable", -"sanai", -"sancho", -"sanct", -"sancta", -"sanctum", -"sand", -"sandak", -"sandal", -"sandan", -"sandbag", -"sandbin", -"sandbox", -"sandboy", -"sandbur", -"sanded", -"sander", -"sanders", -"sandhi", -"sanding", -"sandix", -"sandman", -"sandust", -"sandy", -"sane", -"sanely", -"sang", -"sanga", -"sangar", -"sangei", -"sanger", -"sangha", -"sangley", -"sangrel", -"sangsue", -"sanicle", -"sanies", -"sanify", -"sanious", -"sanity", -"sanjak", -"sank", -"sankha", -"sannup", -"sans", -"sansei", -"sansi", -"sant", -"santal", -"santene", -"santimi", -"santims", -"santir", -"santon", -"sao", -"sap", -"sapa", -"sapajou", -"sapan", -"sapbush", -"sapek", -"sapful", -"saphead", -"saphena", -"saphie", -"sapid", -"sapient", -"sapin", -"sapinda", -"saple", -"sapless", -"sapling", -"sapo", -"saponin", -"sapor", -"sapota", -"sapote", -"sappare", -"sapper", -"sapphic", -"sapping", -"sapples", -"sappy", -"saprine", -"sapsago", -"sapsuck", -"sapwood", -"sapwort", -"sar", -"saraad", -"saraf", -"sarangi", -"sarcasm", -"sarcast", -"sarcine", -"sarcle", -"sarcler", -"sarcode", -"sarcoid", -"sarcoma", -"sarcous", -"sard", -"sardel", -"sardine", -"sardius", -"sare", -"sargo", -"sargus", -"sari", -"sarif", -"sarigue", -"sarinda", -"sarip", -"sark", -"sarkar", -"sarkful", -"sarkine", -"sarking", -"sarkit", -"sarlak", -"sarlyk", -"sarment", -"sarna", -"sarod", -"saron", -"sarong", -"saronic", -"saros", -"sarpler", -"sarpo", -"sarra", -"sarraf", -"sarsa", -"sarsen", -"sart", -"sartage", -"sartain", -"sartor", -"sarus", -"sarwan", -"sasa", -"sasan", -"sasani", -"sash", -"sashay", -"sashery", -"sashing", -"sasin", -"sasine", -"sassaby", -"sassy", -"sat", -"satable", -"satan", -"satang", -"satanic", -"satara", -"satchel", -"sate", -"sateen", -"satiate", -"satient", -"satiety", -"satin", -"satine", -"satined", -"satiny", -"satire", -"satiric", -"satisfy", -"satlijk", -"satrap", -"satrapy", -"satron", -"sattle", -"sattva", -"satura", -"satyr", -"satyric", -"sauce", -"saucer", -"saucily", -"saucy", -"sauf", -"sauger", -"saugh", -"saughen", -"sauld", -"saulie", -"sault", -"saulter", -"saum", -"saumon", -"saumont", -"sauna", -"saunter", -"sauqui", -"saur", -"saurel", -"saurian", -"saury", -"sausage", -"saut", -"saute", -"sauteur", -"sauty", -"sauve", -"savable", -"savacu", -"savage", -"savanna", -"savant", -"savarin", -"save", -"saved", -"saveloy", -"saver", -"savin", -"saving", -"savior", -"savola", -"savor", -"savored", -"savorer", -"savory", -"savour", -"savoy", -"savoyed", -"savssat", -"savvy", -"saw", -"sawah", -"sawali", -"sawarra", -"sawback", -"sawbill", -"sawbuck", -"sawbwa", -"sawder", -"sawdust", -"sawed", -"sawer", -"sawfish", -"sawfly", -"sawing", -"sawish", -"sawlike", -"sawman", -"sawmill", -"sawmon", -"sawmont", -"sawn", -"sawney", -"sawt", -"sawway", -"sawwort", -"sawyer", -"sax", -"saxhorn", -"saxten", -"saxtie", -"saxtuba", -"say", -"saya", -"sayable", -"sayer", -"sayette", -"sayid", -"saying", -"sazen", -"sblood", -"scab", -"scabbed", -"scabble", -"scabby", -"scabid", -"scabies", -"scabish", -"scabrid", -"scad", -"scaddle", -"scads", -"scaff", -"scaffer", -"scaffie", -"scaffle", -"scaglia", -"scala", -"scalage", -"scalar", -"scalare", -"scald", -"scalded", -"scalder", -"scaldic", -"scaldy", -"scale", -"scaled", -"scalena", -"scalene", -"scaler", -"scales", -"scaling", -"scall", -"scalled", -"scallom", -"scallop", -"scalma", -"scaloni", -"scalp", -"scalpel", -"scalper", -"scalt", -"scaly", -"scam", -"scamble", -"scamell", -"scamler", -"scamles", -"scamp", -"scamper", -"scan", -"scandal", -"scandia", -"scandic", -"scanmag", -"scanner", -"scant", -"scantle", -"scantly", -"scanty", -"scap", -"scape", -"scapel", -"scapha", -"scapoid", -"scapose", -"scapple", -"scapula", -"scapus", -"scar", -"scarab", -"scarce", -"scarcen", -"scare", -"scarer", -"scarf", -"scarfed", -"scarfer", -"scarfy", -"scarid", -"scarify", -"scarily", -"scarlet", -"scarman", -"scarn", -"scaroid", -"scarp", -"scarred", -"scarrer", -"scarry", -"scart", -"scarth", -"scarus", -"scarved", -"scary", -"scase", -"scasely", -"scat", -"scatch", -"scathe", -"scatter", -"scatty", -"scatula", -"scaul", -"scaum", -"scaup", -"scauper", -"scaur", -"scaurie", -"scaut", -"scavage", -"scavel", -"scaw", -"scawd", -"scawl", -"scazon", -"sceat", -"scena", -"scenary", -"scend", -"scene", -"scenery", -"scenic", -"scenist", -"scenite", -"scent", -"scented", -"scenter", -"scepsis", -"scepter", -"sceptic", -"sceptry", -"scerne", -"schanz", -"schappe", -"scharf", -"schelly", -"schema", -"scheme", -"schemer", -"schemy", -"schene", -"schepel", -"schepen", -"scherm", -"scherzi", -"scherzo", -"schesis", -"schism", -"schisma", -"schist", -"schloop", -"schmelz", -"scho", -"schola", -"scholae", -"scholar", -"scholia", -"schone", -"school", -"schoon", -"schorl", -"schorly", -"schout", -"schtoff", -"schuh", -"schuhe", -"schuit", -"schule", -"schuss", -"schute", -"schwa", -"schwarz", -"sciapod", -"sciarid", -"sciatic", -"scibile", -"science", -"scient", -"scincid", -"scind", -"sciniph", -"scintle", -"scion", -"scious", -"scirrhi", -"scissel", -"scissor", -"sciurid", -"sclaff", -"sclate", -"sclater", -"sclaw", -"scler", -"sclera", -"scleral", -"sclere", -"scliff", -"sclim", -"sclimb", -"scoad", -"scob", -"scobby", -"scobs", -"scoff", -"scoffer", -"scog", -"scoggan", -"scogger", -"scoggin", -"scoke", -"scolb", -"scold", -"scolder", -"scolex", -"scolia", -"scoliid", -"scolion", -"scolite", -"scollop", -"scolog", -"sconce", -"sconcer", -"scone", -"scoon", -"scoop", -"scooped", -"scooper", -"scoot", -"scooter", -"scopa", -"scopate", -"scope", -"scopet", -"scopic", -"scopine", -"scopola", -"scops", -"scopula", -"scorch", -"score", -"scored", -"scorer", -"scoria", -"scoriac", -"scoriae", -"scorify", -"scoring", -"scorn", -"scorned", -"scorner", -"scorny", -"scorper", -"scorse", -"scot", -"scotale", -"scotch", -"scote", -"scoter", -"scotia", -"scotino", -"scotoma", -"scotomy", -"scouch", -"scouk", -"scoup", -"scour", -"scoured", -"scourer", -"scourge", -"scoury", -"scouse", -"scout", -"scouter", -"scouth", -"scove", -"scovel", -"scovy", -"scow", -"scowder", -"scowl", -"scowler", -"scowman", -"scrab", -"scrabe", -"scrae", -"scrag", -"scraggy", -"scraily", -"scram", -"scran", -"scranch", -"scrank", -"scranky", -"scranny", -"scrap", -"scrape", -"scraped", -"scraper", -"scrapie", -"scrappy", -"scrapy", -"scrat", -"scratch", -"scrath", -"scrauch", -"scraw", -"scrawk", -"scrawl", -"scrawly", -"scrawm", -"scrawny", -"scray", -"scraze", -"screak", -"screaky", -"scream", -"screamy", -"scree", -"screech", -"screed", -"screek", -"screel", -"screen", -"screeny", -"screet", -"screeve", -"screich", -"screigh", -"screve", -"screver", -"screw", -"screwed", -"screwer", -"screwy", -"scribal", -"scribe", -"scriber", -"scride", -"scrieve", -"scrike", -"scrim", -"scrime", -"scrimer", -"scrimp", -"scrimpy", -"scrin", -"scrinch", -"scrine", -"scringe", -"scrip", -"scripee", -"script", -"scritch", -"scrive", -"scriven", -"scriver", -"scrob", -"scrobe", -"scrobis", -"scrod", -"scroff", -"scrog", -"scroggy", -"scrolar", -"scroll", -"scrolly", -"scroo", -"scrooch", -"scrooge", -"scroop", -"scrota", -"scrotal", -"scrotum", -"scrouge", -"scrout", -"scrow", -"scroyle", -"scrub", -"scrubby", -"scruf", -"scruff", -"scruffy", -"scruft", -"scrum", -"scrump", -"scrunch", -"scrunge", -"scrunt", -"scruple", -"scrush", -"scruto", -"scruze", -"scry", -"scryer", -"scud", -"scudder", -"scuddle", -"scuddy", -"scudi", -"scudler", -"scudo", -"scuff", -"scuffed", -"scuffer", -"scuffle", -"scuffly", -"scuffy", -"scuft", -"scufter", -"scug", -"sculch", -"scull", -"sculler", -"scullog", -"sculp", -"sculper", -"sculpin", -"sculpt", -"sculsh", -"scum", -"scumber", -"scumble", -"scummed", -"scummer", -"scummy", -"scun", -"scunder", -"scunner", -"scup", -"scupful", -"scupper", -"scuppet", -"scur", -"scurdy", -"scurf", -"scurfer", -"scurfy", -"scurry", -"scurvy", -"scuse", -"scut", -"scuta", -"scutage", -"scutal", -"scutate", -"scutch", -"scute", -"scutel", -"scutter", -"scuttle", -"scutty", -"scutula", -"scutum", -"scybala", -"scye", -"scypha", -"scyphae", -"scyphi", -"scyphoi", -"scyphus", -"scyt", -"scytale", -"scythe", -"sdeath", -"se", -"sea", -"seadog", -"seafare", -"seafolk", -"seafowl", -"seagirt", -"seagoer", -"seah", -"seak", -"seal", -"sealant", -"sealch", -"sealed", -"sealer", -"sealery", -"sealess", -"sealet", -"sealike", -"sealine", -"sealing", -"seam", -"seaman", -"seamark", -"seamed", -"seamer", -"seaming", -"seamlet", -"seamost", -"seamrog", -"seamy", -"seance", -"seaport", -"sear", -"searce", -"searcer", -"search", -"seared", -"searer", -"searing", -"seary", -"seasick", -"seaside", -"season", -"seat", -"seatang", -"seated", -"seater", -"seathe", -"seating", -"seatron", -"seave", -"seavy", -"seawant", -"seaward", -"seaware", -"seaway", -"seaweed", -"seawife", -"seaworn", -"seax", -"sebacic", -"sebait", -"sebate", -"sebific", -"sebilla", -"sebkha", -"sebum", -"sebundy", -"sec", -"secable", -"secalin", -"secancy", -"secant", -"secede", -"seceder", -"secern", -"secesh", -"sech", -"seck", -"seclude", -"secluse", -"secohm", -"second", -"seconde", -"secos", -"secpar", -"secque", -"secre", -"secrecy", -"secret", -"secreta", -"secrete", -"secreto", -"sect", -"sectary", -"sectile", -"section", -"sectism", -"sectist", -"sective", -"sector", -"secular", -"secund", -"secure", -"securer", -"sedan", -"sedate", -"sedent", -"sedge", -"sedged", -"sedging", -"sedgy", -"sedile", -"sedilia", -"seduce", -"seducee", -"seducer", -"seduct", -"sedum", -"see", -"seeable", -"seech", -"seed", -"seedage", -"seedbed", -"seedbox", -"seeded", -"seeder", -"seedful", -"seedily", -"seedkin", -"seedlet", -"seedlip", -"seedman", -"seedy", -"seege", -"seeing", -"seek", -"seeker", -"seeking", -"seel", -"seelful", -"seely", -"seem", -"seemer", -"seeming", -"seemly", -"seen", -"seenie", -"seep", -"seepage", -"seeped", -"seepy", -"seer", -"seeress", -"seerpaw", -"seesaw", -"seesee", -"seethe", -"seg", -"seggar", -"seggard", -"segged", -"seggrom", -"segment", -"sego", -"segol", -"seiche", -"seidel", -"seine", -"seiner", -"seise", -"seism", -"seismal", -"seismic", -"seit", -"seity", -"seize", -"seizer", -"seizin", -"seizing", -"seizor", -"seizure", -"sejant", -"sejoin", -"sejunct", -"sekos", -"selah", -"selamin", -"seldom", -"seldor", -"sele", -"select", -"selenic", -"self", -"selfdom", -"selfful", -"selfish", -"selfism", -"selfist", -"selfly", -"selion", -"sell", -"sella", -"sellar", -"sellate", -"seller", -"sellie", -"selling", -"sellout", -"selly", -"selsyn", -"selt", -"selva", -"selvage", -"semarum", -"sematic", -"semball", -"semble", -"seme", -"semeed", -"semeia", -"semeion", -"semen", -"semence", -"semese", -"semi", -"semiape", -"semiarc", -"semibay", -"semic", -"semicup", -"semidry", -"semiegg", -"semifib", -"semifit", -"semify", -"semigod", -"semihot", -"seminal", -"seminar", -"semiorb", -"semiped", -"semipro", -"semiraw", -"semis", -"semita", -"semitae", -"semital", -"semiurn", -"semmet", -"semmit", -"semola", -"semsem", -"sen", -"senaite", -"senam", -"senary", -"senate", -"senator", -"sence", -"sencion", -"send", -"sendal", -"sendee", -"sender", -"sending", -"senega", -"senegin", -"senesce", -"senile", -"senior", -"senna", -"sennet", -"sennit", -"sennite", -"sensa", -"sensal", -"sensate", -"sense", -"sensed", -"sensify", -"sensile", -"sension", -"sensism", -"sensist", -"sensive", -"sensize", -"senso", -"sensor", -"sensory", -"sensual", -"sensum", -"sensyne", -"sent", -"sentry", -"sepad", -"sepal", -"sepaled", -"sephen", -"sepia", -"sepian", -"sepiary", -"sepic", -"sepioid", -"sepion", -"sepiost", -"sepium", -"sepone", -"sepoy", -"seppuku", -"seps", -"sepsine", -"sepsis", -"sept", -"septa", -"septal", -"septan", -"septane", -"septate", -"septave", -"septet", -"septic", -"septier", -"septile", -"septime", -"septoic", -"septole", -"septum", -"septuor", -"sequa", -"sequel", -"sequela", -"sequent", -"sequest", -"sequin", -"ser", -"sera", -"serab", -"seragli", -"serai", -"serail", -"seral", -"serang", -"serape", -"seraph", -"serau", -"seraw", -"sercial", -"serdab", -"sere", -"sereh", -"serene", -"serf", -"serfage", -"serfdom", -"serfish", -"serfism", -"serge", -"serger", -"serging", -"serial", -"seriary", -"seriate", -"sericea", -"sericin", -"seriema", -"series", -"serif", -"serific", -"serin", -"serine", -"seringa", -"serio", -"serious", -"serment", -"sermo", -"sermon", -"sero", -"serolin", -"seron", -"seroon", -"seroot", -"seropus", -"serosa", -"serous", -"serow", -"serpent", -"serphid", -"serpigo", -"serpula", -"serra", -"serrage", -"serran", -"serrana", -"serrano", -"serrate", -"serried", -"serry", -"sert", -"serta", -"sertule", -"sertum", -"serum", -"serumal", -"serut", -"servage", -"serval", -"servant", -"serve", -"server", -"servery", -"servet", -"service", -"servile", -"serving", -"servist", -"servo", -"sesame", -"sesma", -"sesqui", -"sess", -"sessile", -"session", -"sestet", -"sesti", -"sestiad", -"sestina", -"sestine", -"sestole", -"sestuor", -"set", -"seta", -"setae", -"setal", -"setback", -"setbolt", -"setdown", -"setfast", -"seth", -"sethead", -"setier", -"setline", -"setness", -"setoff", -"seton", -"setose", -"setous", -"setout", -"setover", -"setsman", -"sett", -"settee", -"setter", -"setting", -"settle", -"settled", -"settler", -"settlor", -"setula", -"setule", -"setup", -"setwall", -"setwise", -"setwork", -"seugh", -"seven", -"sevener", -"seventh", -"seventy", -"sever", -"several", -"severe", -"severer", -"severy", -"sew", -"sewable", -"sewage", -"sewan", -"sewed", -"sewen", -"sewer", -"sewered", -"sewery", -"sewing", -"sewless", -"sewn", -"sex", -"sexed", -"sexern", -"sexfid", -"sexfoil", -"sexhood", -"sexifid", -"sexiped", -"sexless", -"sexlike", -"sexly", -"sext", -"sextain", -"sextan", -"sextans", -"sextant", -"sextar", -"sextary", -"sextern", -"sextet", -"sextic", -"sextile", -"sexto", -"sextole", -"sexton", -"sextry", -"sextula", -"sexual", -"sexuale", -"sexuous", -"sexy", -"sey", -"sfoot", -"sh", -"sha", -"shab", -"shabash", -"shabbed", -"shabble", -"shabby", -"shachle", -"shachly", -"shack", -"shackle", -"shackly", -"shacky", -"shad", -"shade", -"shaded", -"shader", -"shadily", -"shadine", -"shading", -"shadkan", -"shadoof", -"shadow", -"shadowy", -"shady", -"shaffle", -"shaft", -"shafted", -"shafter", -"shafty", -"shag", -"shagbag", -"shagged", -"shaggy", -"shaglet", -"shagrag", -"shah", -"shahdom", -"shahi", -"shahin", -"shaikh", -"shaitan", -"shake", -"shaken", -"shaker", -"shakers", -"shakha", -"shakily", -"shaking", -"shako", -"shakti", -"shaku", -"shaky", -"shale", -"shall", -"shallal", -"shallon", -"shallop", -"shallot", -"shallow", -"shallu", -"shalom", -"shalt", -"shalwar", -"shaly", -"sham", -"shama", -"shamal", -"shamalo", -"shaman", -"shamba", -"shamble", -"shame", -"shamed", -"shamer", -"shamir", -"shammed", -"shammer", -"shammy", -"shampoo", -"shan", -"shandry", -"shandy", -"shangan", -"shank", -"shanked", -"shanker", -"shanna", -"shanny", -"shansa", -"shant", -"shanty", -"shap", -"shape", -"shaped", -"shapely", -"shapen", -"shaper", -"shaping", -"shaps", -"shapy", -"shard", -"sharded", -"shardy", -"share", -"sharer", -"shargar", -"shark", -"sharky", -"sharn", -"sharny", -"sharp", -"sharpen", -"sharper", -"sharpie", -"sharply", -"sharps", -"sharpy", -"sharrag", -"sharry", -"shaster", -"shastra", -"shastri", -"shat", -"shatan", -"shatter", -"shaugh", -"shaul", -"shaup", -"shauri", -"shauwe", -"shave", -"shaved", -"shavee", -"shaven", -"shaver", -"shavery", -"shaving", -"shaw", -"shawl", -"shawled", -"shawm", -"shawny", -"shawy", -"shay", -"she", -"shea", -"sheaf", -"sheafy", -"sheal", -"shear", -"sheard", -"shearer", -"shears", -"sheat", -"sheath", -"sheathe", -"sheathy", -"sheave", -"sheaved", -"shebang", -"shebeen", -"shed", -"shedded", -"shedder", -"sheder", -"shedman", -"shee", -"sheely", -"sheen", -"sheenly", -"sheeny", -"sheep", -"sheepy", -"sheer", -"sheered", -"sheerly", -"sheet", -"sheeted", -"sheeter", -"sheety", -"sheik", -"sheikly", -"shekel", -"shela", -"sheld", -"shelder", -"shelf", -"shelfy", -"shell", -"shellac", -"shelled", -"sheller", -"shellum", -"shelly", -"shelta", -"shelter", -"shelty", -"shelve", -"shelver", -"shelvy", -"shend", -"sheng", -"sheolic", -"sheppey", -"sher", -"sherbet", -"sheriat", -"sherif", -"sherifa", -"sheriff", -"sherifi", -"sherify", -"sherry", -"sheth", -"sheugh", -"sheva", -"shevel", -"shevri", -"shewa", -"shewel", -"sheyle", -"shi", -"shibah", -"shibar", -"shice", -"shicer", -"shicker", -"shide", -"shied", -"shiel", -"shield", -"shier", -"shies", -"shiest", -"shift", -"shifter", -"shifty", -"shigram", -"shih", -"shikar", -"shikara", -"shikari", -"shikimi", -"shikken", -"shiko", -"shikra", -"shilf", -"shilfa", -"shill", -"shilla", -"shillet", -"shilloo", -"shilpit", -"shim", -"shimal", -"shimmer", -"shimmy", -"shimose", -"shimper", -"shin", -"shindig", -"shindle", -"shindy", -"shine", -"shiner", -"shingle", -"shingly", -"shinily", -"shining", -"shinner", -"shinny", -"shinty", -"shiny", -"shinza", -"ship", -"shipboy", -"shipful", -"shiplap", -"shiplet", -"shipman", -"shipped", -"shipper", -"shippo", -"shippon", -"shippy", -"shipway", -"shire", -"shirk", -"shirker", -"shirky", -"shirl", -"shirpit", -"shirr", -"shirt", -"shirty", -"shish", -"shisham", -"shisn", -"shita", -"shither", -"shittah", -"shittim", -"shiv", -"shive", -"shiver", -"shivery", -"shivey", -"shivoo", -"shivy", -"sho", -"shoad", -"shoader", -"shoal", -"shoaler", -"shoaly", -"shoat", -"shock", -"shocker", -"shod", -"shodden", -"shoddy", -"shode", -"shoder", -"shoe", -"shoeboy", -"shoeing", -"shoeman", -"shoer", -"shoful", -"shog", -"shogaol", -"shoggie", -"shoggle", -"shoggly", -"shogi", -"shogun", -"shohet", -"shoji", -"shola", -"shole", -"shone", -"shoneen", -"shoo", -"shood", -"shoofa", -"shoofly", -"shooi", -"shook", -"shool", -"shooler", -"shoop", -"shoor", -"shoot", -"shootee", -"shooter", -"shop", -"shopboy", -"shopful", -"shophar", -"shoplet", -"shopman", -"shoppe", -"shopper", -"shoppy", -"shoq", -"shor", -"shoran", -"shore", -"shored", -"shorer", -"shoring", -"shorn", -"short", -"shorten", -"shorter", -"shortly", -"shorts", -"shot", -"shote", -"shotgun", -"shotman", -"shott", -"shotted", -"shotten", -"shotter", -"shotty", -"shou", -"should", -"shout", -"shouter", -"shoval", -"shove", -"shovel", -"shover", -"show", -"showdom", -"shower", -"showery", -"showily", -"showing", -"showish", -"showman", -"shown", -"showup", -"showy", -"shoya", -"shrab", -"shradh", -"shraf", -"shrag", -"shram", -"shrank", -"shrap", -"shrave", -"shravey", -"shred", -"shreddy", -"shree", -"shreeve", -"shrend", -"shrew", -"shrewd", -"shrewdy", -"shrewly", -"shriek", -"shrieky", -"shrift", -"shrike", -"shrill", -"shrilly", -"shrimp", -"shrimpi", -"shrimpy", -"shrinal", -"shrine", -"shrink", -"shrinky", -"shrip", -"shrite", -"shrive", -"shrivel", -"shriven", -"shriver", -"shroff", -"shrog", -"shroud", -"shroudy", -"shrove", -"shrover", -"shrub", -"shrubby", -"shruff", -"shrug", -"shrunk", -"shrups", -"shuba", -"shuck", -"shucker", -"shucks", -"shudder", -"shuff", -"shuffle", -"shug", -"shul", -"shuler", -"shumac", -"shun", -"shune", -"shunner", -"shunt", -"shunter", -"shure", -"shurf", -"shush", -"shusher", -"shut", -"shutoff", -"shutout", -"shutten", -"shutter", -"shuttle", -"shy", -"shyer", -"shyish", -"shyly", -"shyness", -"shyster", -"si", -"siak", -"sial", -"sialic", -"sialid", -"sialoid", -"siamang", -"sib", -"sibbed", -"sibbens", -"sibber", -"sibby", -"sibilus", -"sibling", -"sibness", -"sibrede", -"sibship", -"sibyl", -"sibylic", -"sibylla", -"sic", -"sicca", -"siccant", -"siccate", -"siccity", -"sice", -"sick", -"sickbed", -"sicken", -"sicker", -"sickish", -"sickle", -"sickled", -"sickler", -"sickly", -"sicsac", -"sicula", -"sicular", -"sidder", -"siddur", -"side", -"sideage", -"sidearm", -"sidecar", -"sided", -"sider", -"sideral", -"siderin", -"sides", -"sideway", -"sidhe", -"sidi", -"siding", -"sidle", -"sidler", -"sidling", -"sidth", -"sidy", -"sie", -"siege", -"sieger", -"sienna", -"sier", -"siering", -"sierra", -"sierran", -"siesta", -"sieve", -"siever", -"sievy", -"sifac", -"sifaka", -"sife", -"siffle", -"sifflet", -"sifflot", -"sift", -"siftage", -"sifted", -"sifter", -"sifting", -"sig", -"sigger", -"sigh", -"sigher", -"sighful", -"sighing", -"sight", -"sighted", -"sighten", -"sighter", -"sightly", -"sighty", -"sigil", -"sigla", -"siglos", -"sigma", -"sigmate", -"sigmoid", -"sign", -"signal", -"signary", -"signate", -"signee", -"signer", -"signet", -"signify", -"signior", -"signist", -"signman", -"signory", -"signum", -"sika", -"sikar", -"sikatch", -"sike", -"sikerly", -"siket", -"sikhara", -"sikhra", -"sil", -"silage", -"silane", -"sile", -"silen", -"silence", -"silency", -"sileni", -"silenic", -"silent", -"silenus", -"silesia", -"silex", -"silica", -"silicam", -"silicic", -"silicle", -"silico", -"silicon", -"silicyl", -"siliqua", -"silique", -"silk", -"silked", -"silken", -"silker", -"silkie", -"silkily", -"silkman", -"silky", -"sill", -"sillar", -"siller", -"sillily", -"sillock", -"sillon", -"silly", -"silo", -"siloist", -"silphid", -"silt", -"siltage", -"silting", -"silty", -"silurid", -"silva", -"silvan", -"silver", -"silvern", -"silvery", -"silvics", -"silyl", -"sima", -"simal", -"simar", -"simball", -"simbil", -"simblin", -"simblot", -"sime", -"simiad", -"simial", -"simian", -"similar", -"simile", -"similor", -"simioid", -"simious", -"simity", -"simkin", -"simlin", -"simling", -"simmer", -"simmon", -"simnel", -"simony", -"simool", -"simoom", -"simoon", -"simous", -"simp", -"simpai", -"simper", -"simple", -"simpler", -"simplex", -"simply", -"simsim", -"simson", -"simular", -"simuler", -"sin", -"sina", -"sinaite", -"sinal", -"sinamay", -"sinapic", -"sinapis", -"sinawa", -"since", -"sincere", -"sind", -"sinder", -"sindle", -"sindoc", -"sindon", -"sindry", -"sine", -"sinew", -"sinewed", -"sinewy", -"sinful", -"sing", -"singe", -"singed", -"singer", -"singey", -"singh", -"singing", -"single", -"singled", -"singler", -"singles", -"singlet", -"singly", -"singult", -"sinh", -"sink", -"sinkage", -"sinker", -"sinking", -"sinky", -"sinless", -"sinlike", -"sinnen", -"sinner", -"sinnet", -"sinopia", -"sinople", -"sinsion", -"sinsyne", -"sinter", -"sintoc", -"sinuate", -"sinuose", -"sinuous", -"sinus", -"sinusal", -"sinward", -"siol", -"sion", -"sip", -"sipage", -"sipe", -"siper", -"siphoid", -"siphon", -"sipid", -"siping", -"sipling", -"sipper", -"sippet", -"sippio", -"sir", -"sircar", -"sirdar", -"sire", -"siren", -"sirene", -"sirenic", -"sireny", -"siress", -"sirgang", -"sirian", -"siricid", -"sirih", -"siris", -"sirkeer", -"sirki", -"sirky", -"sirloin", -"siroc", -"sirocco", -"sirpea", -"sirple", -"sirpoon", -"sirrah", -"sirree", -"sirship", -"sirup", -"siruped", -"siruper", -"sirupy", -"sis", -"sisal", -"sise", -"sisel", -"sish", -"sisham", -"sisi", -"siskin", -"siss", -"sissify", -"sissoo", -"sissy", -"sist", -"sister", -"sistern", -"sistle", -"sistrum", -"sit", -"sitao", -"sitar", -"sitch", -"site", -"sitfast", -"sith", -"sithe", -"sithens", -"sitient", -"sitio", -"sittee", -"sitten", -"sitter", -"sittine", -"sitting", -"situal", -"situate", -"situla", -"situlae", -"situs", -"siva", -"siver", -"sivvens", -"siwash", -"six", -"sixain", -"sixer", -"sixfoil", -"sixfold", -"sixsome", -"sixte", -"sixteen", -"sixth", -"sixthet", -"sixthly", -"sixty", -"sizable", -"sizably", -"sizal", -"sizar", -"size", -"sized", -"sizeman", -"sizer", -"sizes", -"sizing", -"sizy", -"sizygia", -"sizz", -"sizzard", -"sizzing", -"sizzle", -"sjambok", -"skaddle", -"skaff", -"skaffie", -"skag", -"skair", -"skal", -"skance", -"skart", -"skasely", -"skat", -"skate", -"skater", -"skatiku", -"skating", -"skatist", -"skatole", -"skaw", -"skean", -"skedge", -"skee", -"skeed", -"skeeg", -"skeel", -"skeely", -"skeen", -"skeer", -"skeered", -"skeery", -"skeet", -"skeeter", -"skeezix", -"skeg", -"skegger", -"skeif", -"skeigh", -"skeily", -"skein", -"skeiner", -"skeipp", -"skel", -"skelder", -"skelf", -"skelic", -"skell", -"skellat", -"skeller", -"skellum", -"skelly", -"skelp", -"skelper", -"skelpin", -"skelter", -"skemmel", -"skemp", -"sken", -"skene", -"skeo", -"skeough", -"skep", -"skepful", -"skeptic", -"sker", -"skere", -"skerret", -"skerry", -"sketch", -"sketchy", -"skete", -"skevish", -"skew", -"skewed", -"skewer", -"skewl", -"skewly", -"skewy", -"skey", -"ski", -"skiapod", -"skibby", -"skice", -"skid", -"skidded", -"skidder", -"skiddoo", -"skiddy", -"skidpan", -"skidway", -"skied", -"skieppe", -"skier", -"skies", -"skiff", -"skift", -"skiing", -"skijore", -"skil", -"skilder", -"skill", -"skilled", -"skillet", -"skilly", -"skilpot", -"skilts", -"skim", -"skime", -"skimmed", -"skimmer", -"skimp", -"skimpy", -"skin", -"skinch", -"skinful", -"skink", -"skinker", -"skinkle", -"skinned", -"skinner", -"skinny", -"skip", -"skipman", -"skippel", -"skipper", -"skippet", -"skipple", -"skippy", -"skirl", -"skirp", -"skirr", -"skirreh", -"skirret", -"skirt", -"skirted", -"skirter", -"skirty", -"skit", -"skite", -"skiter", -"skither", -"skitter", -"skittle", -"skitty", -"skiv", -"skive", -"skiver", -"skiving", -"sklate", -"sklater", -"sklent", -"skoal", -"skoo", -"skookum", -"skoptsy", -"skout", -"skraigh", -"skrike", -"skrupul", -"skua", -"skulk", -"skulker", -"skull", -"skulled", -"skully", -"skulp", -"skun", -"skunk", -"skunky", -"skuse", -"sky", -"skybal", -"skyey", -"skyful", -"skyish", -"skylark", -"skyless", -"skylike", -"skylook", -"skyman", -"skyphoi", -"skyphos", -"skyre", -"skysail", -"skyugle", -"skyward", -"skyway", -"sla", -"slab", -"slabbed", -"slabber", -"slabby", -"slabman", -"slack", -"slacked", -"slacken", -"slacker", -"slackly", -"slad", -"sladang", -"slade", -"slae", -"slag", -"slagger", -"slaggy", -"slagman", -"slain", -"slainte", -"slait", -"slake", -"slaker", -"slaking", -"slaky", -"slam", -"slamp", -"slander", -"slane", -"slang", -"slangy", -"slank", -"slant", -"slantly", -"slap", -"slape", -"slapper", -"slare", -"slart", -"slarth", -"slash", -"slashed", -"slasher", -"slashy", -"slat", -"slatch", -"slate", -"slater", -"slath", -"slather", -"slatify", -"slating", -"slatish", -"slatted", -"slatter", -"slaty", -"slaum", -"slave", -"slaved", -"slaver", -"slavery", -"slavey", -"slaving", -"slavish", -"slaw", -"slay", -"slayer", -"slaying", -"sleathy", -"sleave", -"sleaved", -"sleazy", -"sleck", -"sled", -"sledded", -"sledder", -"sledful", -"sledge", -"sledger", -"slee", -"sleech", -"sleechy", -"sleek", -"sleeken", -"sleeker", -"sleekit", -"sleekly", -"sleeky", -"sleep", -"sleeper", -"sleepry", -"sleepy", -"sleer", -"sleet", -"sleety", -"sleeve", -"sleeved", -"sleever", -"sleigh", -"sleight", -"slender", -"slent", -"slepez", -"slept", -"slete", -"sleuth", -"slew", -"slewed", -"slewer", -"slewing", -"sley", -"sleyer", -"slice", -"sliced", -"slicer", -"slich", -"slicht", -"slicing", -"slick", -"slicken", -"slicker", -"slickly", -"slid", -"slidage", -"slidden", -"slidder", -"slide", -"slided", -"slider", -"sliding", -"slifter", -"slight", -"slighty", -"slim", -"slime", -"slimer", -"slimily", -"slimish", -"slimly", -"slimpsy", -"slimsy", -"slimy", -"sline", -"sling", -"slinge", -"slinger", -"slink", -"slinker", -"slinky", -"slip", -"slipe", -"slipman", -"slipped", -"slipper", -"slippy", -"slipway", -"slirt", -"slish", -"slit", -"slitch", -"slite", -"slither", -"slithy", -"slitted", -"slitter", -"slitty", -"slive", -"sliver", -"slivery", -"sliving", -"sloan", -"slob", -"slobber", -"slobby", -"slock", -"slocken", -"slod", -"slodder", -"slodge", -"slodger", -"sloe", -"slog", -"slogan", -"slogger", -"sloka", -"sloke", -"slon", -"slone", -"slonk", -"sloo", -"sloom", -"sloomy", -"sloop", -"sloosh", -"slop", -"slope", -"sloped", -"slopely", -"sloper", -"sloping", -"slopped", -"sloppy", -"slops", -"slopy", -"slorp", -"slosh", -"slosher", -"sloshy", -"slot", -"slote", -"sloted", -"sloth", -"slotted", -"slotter", -"slouch", -"slouchy", -"slough", -"sloughy", -"slour", -"sloush", -"sloven", -"slow", -"slowish", -"slowly", -"slowrie", -"slows", -"sloyd", -"slub", -"slubber", -"slubby", -"slud", -"sludder", -"sludge", -"sludged", -"sludger", -"sludgy", -"slue", -"sluer", -"slug", -"slugged", -"slugger", -"sluggy", -"sluice", -"sluicer", -"sluicy", -"sluig", -"sluit", -"slum", -"slumber", -"slumdom", -"slumgum", -"slummer", -"slummy", -"slump", -"slumpy", -"slung", -"slunge", -"slunk", -"slunken", -"slur", -"slurbow", -"slurp", -"slurry", -"slush", -"slusher", -"slushy", -"slut", -"slutch", -"slutchy", -"sluther", -"slutter", -"slutty", -"sly", -"slyish", -"slyly", -"slyness", -"slype", -"sma", -"smack", -"smackee", -"smacker", -"smaik", -"small", -"smallen", -"smaller", -"smalls", -"smally", -"smalm", -"smalt", -"smalter", -"smalts", -"smaragd", -"smarm", -"smarmy", -"smart", -"smarten", -"smartly", -"smarty", -"smash", -"smasher", -"smashup", -"smatter", -"smaze", -"smear", -"smeared", -"smearer", -"smeary", -"smectic", -"smectis", -"smeddum", -"smee", -"smeech", -"smeek", -"smeeky", -"smeer", -"smeeth", -"smegma", -"smell", -"smelled", -"smeller", -"smelly", -"smelt", -"smelter", -"smeth", -"smethe", -"smeuse", -"smew", -"smich", -"smicker", -"smicket", -"smiddie", -"smiddum", -"smidge", -"smidgen", -"smilax", -"smile", -"smiler", -"smilet", -"smiling", -"smily", -"smirch", -"smirchy", -"smiris", -"smirk", -"smirker", -"smirkle", -"smirkly", -"smirky", -"smirtle", -"smit", -"smitch", -"smite", -"smiter", -"smith", -"smitham", -"smither", -"smithy", -"smiting", -"smitten", -"smock", -"smocker", -"smog", -"smoke", -"smoked", -"smoker", -"smokery", -"smokily", -"smoking", -"smokish", -"smoky", -"smolder", -"smolt", -"smooch", -"smoochy", -"smoodge", -"smook", -"smoot", -"smooth", -"smopple", -"smore", -"smote", -"smother", -"smotter", -"smouch", -"smous", -"smouse", -"smouser", -"smout", -"smriti", -"smudge", -"smudged", -"smudger", -"smudgy", -"smug", -"smuggle", -"smugism", -"smugly", -"smuisty", -"smur", -"smurr", -"smurry", -"smuse", -"smush", -"smut", -"smutch", -"smutchy", -"smutted", -"smutter", -"smutty", -"smyth", -"smytrie", -"snab", -"snabbie", -"snabble", -"snack", -"snackle", -"snaff", -"snaffle", -"snafu", -"snag", -"snagged", -"snagger", -"snaggy", -"snagrel", -"snail", -"snails", -"snaily", -"snaith", -"snake", -"snaker", -"snakery", -"snakily", -"snaking", -"snakish", -"snaky", -"snap", -"snapbag", -"snape", -"snaper", -"snapped", -"snapper", -"snapps", -"snappy", -"snaps", -"snapy", -"snare", -"snarer", -"snark", -"snarl", -"snarler", -"snarly", -"snary", -"snaste", -"snatch", -"snatchy", -"snath", -"snathe", -"snavel", -"snavvle", -"snaw", -"snead", -"sneak", -"sneaker", -"sneaky", -"sneap", -"sneath", -"sneathe", -"sneb", -"sneck", -"snecker", -"snecket", -"sned", -"snee", -"sneer", -"sneerer", -"sneery", -"sneesh", -"sneest", -"sneesty", -"sneeze", -"sneezer", -"sneezy", -"snell", -"snelly", -"snerp", -"snew", -"snib", -"snibble", -"snibel", -"snicher", -"snick", -"snicker", -"snicket", -"snickey", -"snickle", -"sniddle", -"snide", -"sniff", -"sniffer", -"sniffle", -"sniffly", -"sniffy", -"snift", -"snifter", -"snifty", -"snig", -"snigger", -"sniggle", -"snip", -"snipe", -"sniper", -"sniping", -"snipish", -"snipper", -"snippet", -"snippy", -"snipy", -"snirl", -"snirt", -"snirtle", -"snitch", -"snite", -"snithe", -"snithy", -"snittle", -"snivel", -"snively", -"snivy", -"snob", -"snobber", -"snobby", -"snobdom", -"snocher", -"snock", -"snocker", -"snod", -"snodly", -"snoek", -"snog", -"snoga", -"snoke", -"snood", -"snooded", -"snook", -"snooker", -"snoop", -"snooper", -"snoopy", -"snoose", -"snoot", -"snooty", -"snoove", -"snooze", -"snoozer", -"snoozle", -"snoozy", -"snop", -"snore", -"snorer", -"snoring", -"snork", -"snorkel", -"snorker", -"snort", -"snorter", -"snortle", -"snorty", -"snot", -"snotter", -"snotty", -"snouch", -"snout", -"snouted", -"snouter", -"snouty", -"snow", -"snowcap", -"snowie", -"snowily", -"snowish", -"snowk", -"snowl", -"snowy", -"snozzle", -"snub", -"snubbed", -"snubbee", -"snubber", -"snubby", -"snuck", -"snudge", -"snuff", -"snuffer", -"snuffle", -"snuffly", -"snuffy", -"snug", -"snugger", -"snuggle", -"snugify", -"snugly", -"snum", -"snup", -"snupper", -"snur", -"snurl", -"snurly", -"snurp", -"snurt", -"snuzzle", -"sny", -"snying", -"so", -"soak", -"soakage", -"soaked", -"soaken", -"soaker", -"soaking", -"soakman", -"soaky", -"soally", -"soam", -"soap", -"soapbox", -"soaper", -"soapery", -"soapily", -"soapsud", -"soapy", -"soar", -"soarer", -"soaring", -"soary", -"sob", -"sobber", -"sobbing", -"sobby", -"sobeit", -"sober", -"soberer", -"soberly", -"sobful", -"soboles", -"soc", -"socage", -"socager", -"soccer", -"soce", -"socht", -"social", -"society", -"socii", -"socius", -"sock", -"socker", -"socket", -"sockeye", -"socky", -"socle", -"socman", -"soco", -"sod", -"soda", -"sodaic", -"sodded", -"sodden", -"sodding", -"soddite", -"soddy", -"sodic", -"sodio", -"sodium", -"sodless", -"sodoku", -"sodomic", -"sodomy", -"sodwork", -"sody", -"soe", -"soekoe", -"soever", -"sofa", -"sofane", -"sofar", -"soffit", -"soft", -"softa", -"soften", -"softish", -"softly", -"softner", -"softy", -"sog", -"soger", -"soget", -"soggily", -"sogging", -"soggy", -"soh", -"soho", -"soil", -"soilage", -"soiled", -"soiling", -"soilure", -"soily", -"soiree", -"soja", -"sojourn", -"sok", -"soka", -"soke", -"sokeman", -"soken", -"sol", -"sola", -"solace", -"solacer", -"solan", -"solanal", -"solanum", -"solar", -"solate", -"solatia", -"solay", -"sold", -"soldado", -"soldan", -"solder", -"soldi", -"soldier", -"soldo", -"sole", -"solea", -"soleas", -"soleil", -"solely", -"solemn", -"solen", -"solent", -"soler", -"soles", -"soleus", -"soleyn", -"soli", -"solicit", -"solid", -"solidi", -"solidly", -"solidum", -"solidus", -"solio", -"soliped", -"solist", -"sollar", -"solo", -"solod", -"solodi", -"soloist", -"solon", -"soloth", -"soluble", -"solubly", -"solum", -"solute", -"solvate", -"solve", -"solvend", -"solvent", -"solver", -"soma", -"somal", -"somata", -"somatic", -"somber", -"sombre", -"some", -"someday", -"somehow", -"someone", -"somers", -"someway", -"somewhy", -"somital", -"somite", -"somitic", -"somma", -"somnial", -"somnify", -"somnus", -"sompay", -"sompne", -"sompner", -"son", -"sonable", -"sonance", -"sonancy", -"sonant", -"sonar", -"sonata", -"sond", -"sondeli", -"soneri", -"song", -"songful", -"songish", -"songle", -"songlet", -"songman", -"songy", -"sonhood", -"sonic", -"soniou", -"sonk", -"sonless", -"sonlike", -"sonly", -"sonnet", -"sonny", -"sonoric", -"sons", -"sonship", -"sonsy", -"sontag", -"soodle", -"soodly", -"sook", -"sooky", -"sool", -"sooloos", -"soon", -"sooner", -"soonish", -"soonly", -"soorawn", -"soord", -"soorkee", -"soot", -"sooter", -"sooth", -"soothe", -"soother", -"sootily", -"sooty", -"sop", -"sope", -"soph", -"sophia", -"sophic", -"sophism", -"sophy", -"sopite", -"sopor", -"sopper", -"sopping", -"soppy", -"soprani", -"soprano", -"sora", -"sorage", -"soral", -"sorb", -"sorbate", -"sorbent", -"sorbic", -"sorbile", -"sorbin", -"sorbite", -"sorbose", -"sorbus", -"sorcer", -"sorcery", -"sorchin", -"sorda", -"sordes", -"sordid", -"sordine", -"sordino", -"sordor", -"sore", -"soredia", -"soree", -"sorehon", -"sorely", -"sorema", -"sorgho", -"sorghum", -"sorgo", -"sori", -"soricid", -"sorite", -"sorites", -"sorn", -"sornare", -"sornari", -"sorner", -"sorning", -"soroban", -"sororal", -"sorose", -"sorosis", -"sorra", -"sorrel", -"sorrily", -"sorroa", -"sorrow", -"sorrowy", -"sorry", -"sort", -"sortal", -"sorted", -"sorter", -"sortie", -"sortly", -"sorty", -"sorus", -"sorva", -"sory", -"sosh", -"soshed", -"soso", -"sosoish", -"soss", -"sossle", -"sot", -"sotie", -"sotnia", -"sotnik", -"sotol", -"sots", -"sottage", -"sotted", -"sotter", -"sottish", -"sou", -"souari", -"soubise", -"soucar", -"souchet", -"souchy", -"soud", -"souffle", -"sough", -"sougher", -"sought", -"soul", -"soulack", -"souled", -"soulful", -"soulish", -"souly", -"soum", -"sound", -"sounder", -"soundly", -"soup", -"soupcon", -"souper", -"souple", -"soupy", -"sour", -"source", -"soured", -"souren", -"sourer", -"souring", -"sourish", -"sourly", -"sourock", -"soursop", -"sourtop", -"soury", -"souse", -"souser", -"souslik", -"soutane", -"souter", -"south", -"souther", -"sov", -"soviet", -"sovite", -"sovkhoz", -"sovran", -"sow", -"sowable", -"sowan", -"sowans", -"sowar", -"sowarry", -"sowback", -"sowbane", -"sowel", -"sowens", -"sower", -"sowfoot", -"sowing", -"sowins", -"sowl", -"sowle", -"sowlike", -"sowlth", -"sown", -"sowse", -"sowt", -"sowte", -"soy", -"soya", -"soybean", -"sozin", -"sozolic", -"sozzle", -"sozzly", -"spa", -"space", -"spaced", -"spacer", -"spacing", -"spack", -"spacy", -"spad", -"spade", -"spaded", -"spader", -"spadger", -"spading", -"spadix", -"spadone", -"spae", -"spaedom", -"spaeman", -"spaer", -"spahi", -"spaid", -"spaik", -"spairge", -"spak", -"spald", -"spalder", -"spale", -"spall", -"spaller", -"spalt", -"span", -"spancel", -"spandle", -"spandy", -"spane", -"spanemy", -"spang", -"spangle", -"spangly", -"spaniel", -"spaning", -"spank", -"spanker", -"spanky", -"spann", -"spannel", -"spanner", -"spanule", -"spar", -"sparada", -"sparch", -"spare", -"sparely", -"sparer", -"sparge", -"sparger", -"sparid", -"sparing", -"spark", -"sparked", -"sparker", -"sparkle", -"sparkly", -"sparks", -"sparky", -"sparm", -"sparoid", -"sparred", -"sparrer", -"sparrow", -"sparry", -"sparse", -"spart", -"sparth", -"spartle", -"sparver", -"spary", -"spasm", -"spasmed", -"spasmic", -"spastic", -"spat", -"spate", -"spatha", -"spathal", -"spathe", -"spathed", -"spathic", -"spatial", -"spatted", -"spatter", -"spattle", -"spatula", -"spatule", -"spave", -"spaver", -"spavie", -"spavied", -"spaviet", -"spavin", -"spawn", -"spawner", -"spawny", -"spay", -"spayad", -"spayard", -"spaying", -"speak", -"speaker", -"speal", -"spean", -"spear", -"spearer", -"speary", -"spec", -"spece", -"special", -"specie", -"species", -"specify", -"speck", -"specked", -"speckle", -"speckly", -"specks", -"specky", -"specs", -"specter", -"spectra", -"spectry", -"specula", -"specus", -"sped", -"speech", -"speed", -"speeder", -"speedy", -"speel", -"speen", -"speer", -"speiss", -"spelder", -"spelk", -"spell", -"speller", -"spelt", -"spelter", -"speltz", -"spelunk", -"spence", -"spencer", -"spend", -"spender", -"spense", -"spent", -"speos", -"sperate", -"sperity", -"sperket", -"sperm", -"sperma", -"spermic", -"spermy", -"sperone", -"spet", -"spetch", -"spew", -"spewer", -"spewing", -"spewy", -"spex", -"sphacel", -"sphecid", -"spheges", -"sphegid", -"sphene", -"sphenic", -"spheral", -"sphere", -"spheric", -"sphery", -"sphinx", -"spica", -"spical", -"spicant", -"spicate", -"spice", -"spiced", -"spicer", -"spicery", -"spicily", -"spicing", -"spick", -"spicket", -"spickle", -"spicose", -"spicous", -"spicula", -"spicule", -"spicy", -"spider", -"spidery", -"spidger", -"spied", -"spiegel", -"spiel", -"spieler", -"spier", -"spiff", -"spiffed", -"spiffy", -"spig", -"spignet", -"spigot", -"spike", -"spiked", -"spiker", -"spikily", -"spiking", -"spiky", -"spile", -"spiler", -"spiling", -"spilite", -"spill", -"spiller", -"spillet", -"spilly", -"spiloma", -"spilt", -"spilth", -"spilus", -"spin", -"spina", -"spinach", -"spinae", -"spinage", -"spinal", -"spinate", -"spinder", -"spindle", -"spindly", -"spine", -"spined", -"spinel", -"spinet", -"spingel", -"spink", -"spinner", -"spinney", -"spinoid", -"spinose", -"spinous", -"spinule", -"spiny", -"spionid", -"spiral", -"spirale", -"spiran", -"spirant", -"spirate", -"spire", -"spirea", -"spired", -"spireme", -"spiring", -"spirit", -"spirity", -"spirket", -"spiro", -"spiroid", -"spirous", -"spirt", -"spiry", -"spise", -"spit", -"spital", -"spitbox", -"spite", -"spitful", -"spitish", -"spitted", -"spitten", -"spitter", -"spittle", -"spitz", -"spiv", -"spivery", -"splash", -"splashy", -"splat", -"splatch", -"splay", -"splayed", -"splayer", -"spleen", -"spleeny", -"spleet", -"splenic", -"splet", -"splice", -"splicer", -"spline", -"splint", -"splinty", -"split", -"splodge", -"splodgy", -"splore", -"splosh", -"splotch", -"splunge", -"splurge", -"splurgy", -"splurt", -"spoach", -"spode", -"spodium", -"spoffle", -"spoffy", -"spogel", -"spoil", -"spoiled", -"spoiler", -"spoilt", -"spoke", -"spoken", -"spoky", -"spole", -"spolia", -"spolium", -"spondee", -"spondyl", -"spong", -"sponge", -"sponged", -"sponger", -"spongin", -"spongy", -"sponsal", -"sponson", -"sponsor", -"spoof", -"spoofer", -"spook", -"spooky", -"spool", -"spooler", -"spoom", -"spoon", -"spooner", -"spoony", -"spoor", -"spoorer", -"spoot", -"spor", -"sporal", -"spore", -"spored", -"sporid", -"sporoid", -"sporont", -"sporous", -"sporran", -"sport", -"sporter", -"sportly", -"sports", -"sporty", -"sporule", -"sposh", -"sposhy", -"spot", -"spotted", -"spotter", -"spottle", -"spotty", -"spousal", -"spouse", -"spousy", -"spout", -"spouter", -"spouty", -"sprack", -"sprad", -"sprag", -"spraich", -"sprain", -"spraint", -"sprang", -"sprank", -"sprat", -"spratty", -"sprawl", -"sprawly", -"spray", -"sprayer", -"sprayey", -"spread", -"spready", -"spreath", -"spree", -"spreeuw", -"spreng", -"sprent", -"spret", -"sprew", -"sprewl", -"spried", -"sprier", -"spriest", -"sprig", -"spriggy", -"spring", -"springe", -"springy", -"sprink", -"sprint", -"sprit", -"sprite", -"spritty", -"sproat", -"sprod", -"sprogue", -"sproil", -"sprong", -"sprose", -"sprout", -"sprowsy", -"spruce", -"sprue", -"spruer", -"sprug", -"spruit", -"sprung", -"sprunny", -"sprunt", -"spry", -"spryly", -"spud", -"spudder", -"spuddle", -"spuddy", -"spuffle", -"spug", -"spuke", -"spume", -"spumone", -"spumose", -"spumous", -"spumy", -"spun", -"spung", -"spunk", -"spunkie", -"spunky", -"spunny", -"spur", -"spurge", -"spuriae", -"spurl", -"spurlet", -"spurn", -"spurner", -"spurred", -"spurrer", -"spurry", -"spurt", -"spurter", -"spurtle", -"spurway", -"sput", -"sputa", -"sputter", -"sputum", -"spy", -"spyboat", -"spydom", -"spyer", -"spyhole", -"spyism", -"spyship", -"squab", -"squabby", -"squacco", -"squad", -"squaddy", -"squail", -"squalid", -"squall", -"squally", -"squalm", -"squalor", -"squam", -"squama", -"squamae", -"squame", -"square", -"squared", -"squarer", -"squark", -"squary", -"squash", -"squashy", -"squat", -"squatly", -"squatty", -"squaw", -"squawk", -"squawky", -"squdge", -"squdgy", -"squeak", -"squeaky", -"squeal", -"squeald", -"squeam", -"squeamy", -"squeege", -"squeeze", -"squeezy", -"squelch", -"squench", -"squib", -"squid", -"squidge", -"squidgy", -"squiffy", -"squilla", -"squin", -"squinch", -"squinny", -"squinsy", -"squint", -"squinty", -"squire", -"squiret", -"squirk", -"squirm", -"squirmy", -"squirr", -"squirt", -"squirty", -"squish", -"squishy", -"squit", -"squitch", -"squoze", -"squush", -"squushy", -"sraddha", -"sramana", -"sri", -"sruti", -"ssu", -"st", -"staab", -"stab", -"stabber", -"stabile", -"stable", -"stabler", -"stably", -"staboy", -"stacher", -"stachys", -"stack", -"stacker", -"stacte", -"stadda", -"staddle", -"stade", -"stadia", -"stadic", -"stadion", -"stadium", -"staff", -"staffed", -"staffer", -"stag", -"stage", -"staged", -"stager", -"stagery", -"stagese", -"stagger", -"staggie", -"staggy", -"stagily", -"staging", -"stagnum", -"stagy", -"staia", -"staid", -"staidly", -"stain", -"stainer", -"staio", -"stair", -"staired", -"stairy", -"staith", -"staiver", -"stake", -"staker", -"stale", -"stalely", -"staling", -"stalk", -"stalked", -"stalker", -"stalko", -"stalky", -"stall", -"stallar", -"staller", -"stam", -"stambha", -"stamen", -"stamin", -"stamina", -"stammel", -"stammer", -"stamnos", -"stamp", -"stampee", -"stamper", -"stample", -"stance", -"stanch", -"stand", -"standee", -"standel", -"stander", -"stane", -"stang", -"stanine", -"stanjen", -"stank", -"stankie", -"stannel", -"stanner", -"stannic", -"stanno", -"stannum", -"stannyl", -"stanza", -"stanze", -"stap", -"stapes", -"staple", -"stapled", -"stapler", -"star", -"starch", -"starchy", -"stardom", -"stare", -"staree", -"starer", -"starets", -"starful", -"staring", -"stark", -"starken", -"starkly", -"starky", -"starlet", -"starlit", -"starn", -"starnel", -"starnie", -"starost", -"starred", -"starry", -"start", -"starter", -"startle", -"startly", -"startor", -"starty", -"starve", -"starved", -"starver", -"starvy", -"stary", -"stases", -"stash", -"stashie", -"stasis", -"statal", -"statant", -"state", -"stated", -"stately", -"stater", -"static", -"statics", -"station", -"statism", -"statist", -"stative", -"stator", -"statue", -"statued", -"stature", -"status", -"statute", -"stauk", -"staumer", -"staun", -"staunch", -"staup", -"stauter", -"stave", -"staver", -"stavers", -"staving", -"staw", -"stawn", -"staxis", -"stay", -"stayed", -"stayer", -"staynil", -"stays", -"stchi", -"stead", -"steady", -"steak", -"steal", -"stealed", -"stealer", -"stealth", -"stealy", -"steam", -"steamer", -"steamy", -"stean", -"stearic", -"stearin", -"stearyl", -"steatin", -"stech", -"steddle", -"steed", -"steek", -"steel", -"steeler", -"steely", -"steen", -"steenth", -"steep", -"steepen", -"steeper", -"steeple", -"steeply", -"steepy", -"steer", -"steerer", -"steeve", -"steever", -"steg", -"steid", -"steigh", -"stein", -"stekan", -"stela", -"stelae", -"stelai", -"stelar", -"stele", -"stell", -"stella", -"stellar", -"stem", -"stema", -"stemlet", -"stemma", -"stemmed", -"stemmer", -"stemmy", -"stemple", -"stemson", -"sten", -"stenar", -"stench", -"stenchy", -"stencil", -"stend", -"steng", -"stengah", -"stenion", -"steno", -"stenog", -"stent", -"stenter", -"stenton", -"step", -"steppe", -"stepped", -"stepper", -"stepson", -"stept", -"stepway", -"stere", -"stereo", -"steri", -"steric", -"sterics", -"steride", -"sterile", -"sterin", -"sterk", -"sterlet", -"stern", -"sterna", -"sternad", -"sternal", -"sterned", -"sternly", -"sternum", -"stero", -"steroid", -"sterol", -"stert", -"stertor", -"sterve", -"stet", -"stetch", -"stevel", -"steven", -"stevia", -"stew", -"steward", -"stewed", -"stewpan", -"stewpot", -"stewy", -"stey", -"sthenia", -"sthenic", -"stib", -"stibial", -"stibic", -"stibine", -"stibium", -"stich", -"stichic", -"stichid", -"stick", -"sticked", -"sticker", -"stickit", -"stickle", -"stickly", -"sticks", -"stickum", -"sticky", -"stid", -"stiddy", -"stife", -"stiff", -"stiffen", -"stiffly", -"stifle", -"stifler", -"stigma", -"stigmai", -"stigmal", -"stigme", -"stile", -"stilet", -"still", -"stiller", -"stilly", -"stilt", -"stilted", -"stilter", -"stilty", -"stim", -"stime", -"stimuli", -"stimy", -"stine", -"sting", -"stinge", -"stinger", -"stingo", -"stingy", -"stink", -"stinker", -"stint", -"stinted", -"stinter", -"stinty", -"stion", -"stionic", -"stipe", -"stiped", -"stipel", -"stipend", -"stipes", -"stippen", -"stipple", -"stipply", -"stipula", -"stipule", -"stir", -"stirk", -"stirp", -"stirps", -"stirra", -"stirrer", -"stirrup", -"stitch", -"stite", -"stith", -"stithy", -"stive", -"stiver", -"stivy", -"stoa", -"stoach", -"stoat", -"stoater", -"stob", -"stocah", -"stock", -"stocker", -"stocks", -"stocky", -"stod", -"stodge", -"stodger", -"stodgy", -"stoep", -"stof", -"stoff", -"stog", -"stoga", -"stogie", -"stogy", -"stoic", -"stoical", -"stoke", -"stoker", -"stola", -"stolae", -"stole", -"stoled", -"stolen", -"stolid", -"stolist", -"stollen", -"stolon", -"stoma", -"stomach", -"stomata", -"stomate", -"stomium", -"stomp", -"stomper", -"stond", -"stone", -"stoned", -"stonen", -"stoner", -"stong", -"stonied", -"stonify", -"stonily", -"stoning", -"stonish", -"stonker", -"stony", -"stood", -"stooded", -"stooden", -"stoof", -"stooge", -"stook", -"stooker", -"stookie", -"stool", -"stoon", -"stoond", -"stoop", -"stooper", -"stoory", -"stoot", -"stop", -"stopa", -"stope", -"stoper", -"stopgap", -"stoping", -"stopped", -"stopper", -"stoppit", -"stopple", -"storage", -"storax", -"store", -"storeen", -"storer", -"storge", -"storied", -"storier", -"storify", -"stork", -"storken", -"storm", -"stormer", -"stormy", -"story", -"stosh", -"stoss", -"stot", -"stotter", -"stoun", -"stound", -"stoup", -"stour", -"stoury", -"stoush", -"stout", -"stouten", -"stouth", -"stoutly", -"stouty", -"stove", -"stoven", -"stover", -"stow", -"stowage", -"stowce", -"stower", -"stowing", -"stra", -"strack", -"stract", -"strad", -"strade", -"stradl", -"stradld", -"strae", -"strafe", -"strafer", -"strag", -"straik", -"strain", -"straint", -"strait", -"strake", -"straked", -"straky", -"stram", -"stramp", -"strand", -"strang", -"strange", -"strany", -"strap", -"strass", -"strata", -"stratal", -"strath", -"strati", -"stratic", -"stratum", -"stratus", -"strave", -"straw", -"strawen", -"strawer", -"strawy", -"stray", -"strayer", -"stre", -"streak", -"streaky", -"stream", -"streamy", -"streck", -"stree", -"streek", -"streel", -"streen", -"streep", -"street", -"streets", -"streite", -"streke", -"stremma", -"streng", -"strent", -"strenth", -"strepen", -"strepor", -"stress", -"stret", -"stretch", -"strette", -"stretti", -"stretto", -"strew", -"strewer", -"strewn", -"strey", -"streyne", -"stria", -"striae", -"strial", -"striate", -"strich", -"striche", -"strick", -"strict", -"strid", -"stride", -"strider", -"stridor", -"strife", -"strig", -"striga", -"strigae", -"strigal", -"stright", -"strigil", -"strike", -"striker", -"strind", -"string", -"stringy", -"striola", -"strip", -"stripe", -"striped", -"striper", -"stript", -"stripy", -"strit", -"strive", -"strived", -"striven", -"striver", -"strix", -"stroam", -"strobic", -"strode", -"stroil", -"stroke", -"stroker", -"stroky", -"strold", -"stroll", -"strolld", -"strom", -"stroma", -"stromal", -"stromb", -"strome", -"strone", -"strong", -"strook", -"stroot", -"strop", -"strophe", -"stroth", -"stroud", -"stroup", -"strove", -"strow", -"strowd", -"strown", -"stroy", -"stroyer", -"strub", -"struck", -"strudel", -"strue", -"strum", -"struma", -"strumae", -"strung", -"strunt", -"strut", -"struth", -"struv", -"strych", -"stub", -"stubb", -"stubbed", -"stubber", -"stubble", -"stubbly", -"stubboy", -"stubby", -"stuber", -"stuboy", -"stucco", -"stuck", -"stud", -"studder", -"studdie", -"studdle", -"stude", -"student", -"studia", -"studied", -"studier", -"studio", -"studium", -"study", -"stue", -"stuff", -"stuffed", -"stuffer", -"stuffy", -"stug", -"stuggy", -"stuiver", -"stull", -"stuller", -"stulm", -"stum", -"stumble", -"stumbly", -"stumer", -"stummer", -"stummy", -"stump", -"stumper", -"stumpy", -"stun", -"stung", -"stunk", -"stunner", -"stunsle", -"stunt", -"stunted", -"stunter", -"stunty", -"stupa", -"stupe", -"stupefy", -"stupend", -"stupent", -"stupex", -"stupid", -"stupor", -"stupose", -"stupp", -"stuprum", -"sturdy", -"sturine", -"sturk", -"sturt", -"sturtan", -"sturtin", -"stuss", -"stut", -"stutter", -"sty", -"styan", -"styca", -"styful", -"stylar", -"stylate", -"style", -"styler", -"stylet", -"styline", -"styling", -"stylish", -"stylist", -"stylite", -"stylize", -"stylo", -"styloid", -"stylops", -"stylus", -"stymie", -"stypsis", -"styptic", -"styrax", -"styrene", -"styrol", -"styrone", -"styryl", -"stythe", -"styward", -"suable", -"suably", -"suade", -"suaharo", -"suant", -"suantly", -"suasion", -"suasive", -"suasory", -"suave", -"suavely", -"suavify", -"suavity", -"sub", -"subacid", -"subact", -"subage", -"subah", -"subaid", -"subanal", -"subarch", -"subarea", -"subatom", -"subaud", -"subband", -"subbank", -"subbase", -"subbass", -"subbeau", -"subbias", -"subbing", -"subcase", -"subcash", -"subcast", -"subcell", -"subcity", -"subclan", -"subcool", -"subdate", -"subdean", -"subdeb", -"subdial", -"subdie", -"subdual", -"subduce", -"subduct", -"subdue", -"subdued", -"subduer", -"subecho", -"subedit", -"suber", -"suberic", -"suberin", -"subface", -"subfeu", -"subfief", -"subfix", -"subform", -"subfusc", -"subfusk", -"subgape", -"subgens", -"subget", -"subgit", -"subgod", -"subgrin", -"subgyre", -"subhall", -"subhead", -"subherd", -"subhero", -"subicle", -"subidar", -"subidea", -"subitem", -"subjack", -"subject", -"subjee", -"subjoin", -"subking", -"sublate", -"sublet", -"sublid", -"sublime", -"sublong", -"sublot", -"submaid", -"submain", -"subman", -"submind", -"submiss", -"submit", -"subnect", -"subness", -"subnex", -"subnote", -"subnude", -"suboral", -"suborn", -"suboval", -"subpart", -"subpass", -"subpial", -"subpimp", -"subplat", -"subplot", -"subplow", -"subpool", -"subport", -"subrace", -"subrent", -"subroot", -"subrule", -"subsale", -"subsalt", -"subsea", -"subsect", -"subsept", -"subset", -"subside", -"subsidy", -"subsill", -"subsist", -"subsoil", -"subsult", -"subsume", -"subtack", -"subtend", -"subtext", -"subtile", -"subtill", -"subtle", -"subtly", -"subtone", -"subtype", -"subunit", -"suburb", -"subvein", -"subvene", -"subvert", -"subvola", -"subway", -"subwink", -"subzone", -"succade", -"succeed", -"succent", -"success", -"succi", -"succin", -"succise", -"succor", -"succory", -"succous", -"succub", -"succuba", -"succube", -"succula", -"succumb", -"succuss", -"such", -"suck", -"suckage", -"sucken", -"sucker", -"sucking", -"suckle", -"suckler", -"suclat", -"sucrate", -"sucre", -"sucrose", -"suction", -"sucuri", -"sucuriu", -"sud", -"sudamen", -"sudary", -"sudate", -"sudd", -"sudden", -"sudder", -"suddle", -"suddy", -"sudoral", -"sudoric", -"suds", -"sudsman", -"sudsy", -"sue", -"suede", -"suer", -"suet", -"suety", -"suff", -"suffect", -"suffer", -"suffete", -"suffice", -"suffix", -"sufflue", -"suffuse", -"sugamo", -"sugan", -"sugar", -"sugared", -"sugarer", -"sugary", -"sugent", -"suggest", -"sugh", -"sugi", -"suguaro", -"suhuaro", -"suicide", -"suid", -"suidian", -"suiform", -"suimate", -"suine", -"suing", -"suingly", -"suint", -"suist", -"suit", -"suite", -"suiting", -"suitor", -"suity", -"suji", -"sulcal", -"sulcar", -"sulcate", -"sulcus", -"suld", -"sulea", -"sulfa", -"sulfato", -"sulfion", -"sulfury", -"sulk", -"sulka", -"sulker", -"sulkily", -"sulky", -"sull", -"sulla", -"sullage", -"sullen", -"sullow", -"sully", -"sulpha", -"sulpho", -"sulphur", -"sultam", -"sultan", -"sultana", -"sultane", -"sultone", -"sultry", -"sulung", -"sum", -"sumac", -"sumatra", -"sumbul", -"sumless", -"summage", -"summand", -"summar", -"summary", -"summate", -"summed", -"summer", -"summery", -"summist", -"summit", -"summity", -"summon", -"summons", -"summula", -"summut", -"sumner", -"sump", -"sumpage", -"sumper", -"sumph", -"sumphy", -"sumpit", -"sumple", -"sumpman", -"sumpter", -"sun", -"sunbeam", -"sunbird", -"sunbow", -"sunburn", -"suncup", -"sundae", -"sundang", -"sundari", -"sundek", -"sunder", -"sundew", -"sundial", -"sundik", -"sundog", -"sundown", -"sundra", -"sundri", -"sundry", -"sune", -"sunfall", -"sunfast", -"sunfish", -"sung", -"sungha", -"sunglo", -"sunglow", -"sunk", -"sunken", -"sunket", -"sunlamp", -"sunland", -"sunless", -"sunlet", -"sunlike", -"sunlit", -"sunn", -"sunnily", -"sunnud", -"sunny", -"sunray", -"sunrise", -"sunroom", -"sunset", -"sunsmit", -"sunspot", -"sunt", -"sunup", -"sunward", -"sunway", -"sunways", -"sunweed", -"sunwise", -"sunyie", -"sup", -"supa", -"supari", -"supawn", -"supe", -"super", -"superb", -"supine", -"supper", -"supping", -"supple", -"supply", -"support", -"suppose", -"suppost", -"supreme", -"sur", -"sura", -"surah", -"surahi", -"sural", -"suranal", -"surat", -"surbase", -"surbate", -"surbed", -"surcoat", -"surcrue", -"surculi", -"surd", -"surdent", -"surdity", -"sure", -"surely", -"sures", -"surette", -"surety", -"surf", -"surface", -"surfacy", -"surfeit", -"surfer", -"surfle", -"surfman", -"surfuse", -"surfy", -"surge", -"surgent", -"surgeon", -"surgery", -"surging", -"surgy", -"suriga", -"surlily", -"surly", -"surma", -"surmark", -"surmise", -"surname", -"surnap", -"surnay", -"surpass", -"surplus", -"surra", -"surrey", -"surtax", -"surtout", -"survey", -"survive", -"suscept", -"susi", -"suslik", -"suspect", -"suspend", -"suspire", -"sustain", -"susu", -"susurr", -"suther", -"sutile", -"sutler", -"sutlery", -"sutor", -"sutra", -"suttee", -"sutten", -"suttin", -"suttle", -"sutural", -"suture", -"suum", -"suwarro", -"suwe", -"suz", -"svelte", -"swa", -"swab", -"swabber", -"swabble", -"swack", -"swacken", -"swad", -"swaddle", -"swaddy", -"swag", -"swage", -"swager", -"swagger", -"swaggie", -"swaggy", -"swagman", -"swain", -"swaird", -"swale", -"swaler", -"swaling", -"swallet", -"swallo", -"swallow", -"swam", -"swami", -"swamp", -"swamper", -"swampy", -"swan", -"swang", -"swangy", -"swank", -"swanker", -"swanky", -"swanner", -"swanny", -"swap", -"swape", -"swapper", -"swaraj", -"swarbie", -"sward", -"swardy", -"sware", -"swarf", -"swarfer", -"swarm", -"swarmer", -"swarmy", -"swarry", -"swart", -"swarth", -"swarthy", -"swartly", -"swarty", -"swarve", -"swash", -"swasher", -"swashy", -"swat", -"swatch", -"swath", -"swathe", -"swather", -"swathy", -"swatter", -"swattle", -"swaver", -"sway", -"swayed", -"swayer", -"swayful", -"swaying", -"sweal", -"swear", -"swearer", -"sweat", -"sweated", -"sweater", -"sweath", -"sweaty", -"swedge", -"sweeny", -"sweep", -"sweeper", -"sweepy", -"sweer", -"sweered", -"sweet", -"sweeten", -"sweetie", -"sweetly", -"sweety", -"swego", -"swell", -"swelled", -"sweller", -"swelly", -"swelp", -"swelt", -"swelter", -"swelth", -"sweltry", -"swelty", -"swep", -"swept", -"swerd", -"swerve", -"swerver", -"swick", -"swidge", -"swift", -"swiften", -"swifter", -"swifty", -"swig", -"swigger", -"swiggle", -"swile", -"swill", -"swiller", -"swim", -"swimmer", -"swimmy", -"swimy", -"swindle", -"swine", -"swinely", -"swinery", -"swiney", -"swing", -"swinge", -"swinger", -"swingle", -"swingy", -"swinish", -"swink", -"swinney", -"swipe", -"swiper", -"swipes", -"swiple", -"swipper", -"swipy", -"swird", -"swire", -"swirl", -"swirly", -"swish", -"swisher", -"swishy", -"swiss", -"switch", -"switchy", -"swith", -"swithe", -"swithen", -"swither", -"swivel", -"swivet", -"swiz", -"swizzle", -"swob", -"swollen", -"swom", -"swonken", -"swoon", -"swooned", -"swoony", -"swoop", -"swooper", -"swoosh", -"sword", -"swore", -"sworn", -"swosh", -"swot", -"swotter", -"swounds", -"swow", -"swum", -"swung", -"swungen", -"swure", -"syagush", -"sybotic", -"syce", -"sycee", -"sycock", -"sycoma", -"syconid", -"syconus", -"sycosis", -"sye", -"syenite", -"sylid", -"syllab", -"syllabe", -"syllabi", -"sylloge", -"sylph", -"sylphic", -"sylphid", -"sylphy", -"sylva", -"sylvae", -"sylvage", -"sylvan", -"sylvate", -"sylvic", -"sylvine", -"sylvite", -"symbion", -"symbiot", -"symbol", -"sympode", -"symptom", -"synacme", -"synacmy", -"synange", -"synapse", -"synapte", -"synaxar", -"synaxis", -"sync", -"syncarp", -"synch", -"synchro", -"syncope", -"syndic", -"syndoc", -"syne", -"synema", -"synergy", -"synesis", -"syngamy", -"synod", -"synodal", -"synoecy", -"synonym", -"synopsy", -"synovia", -"syntan", -"syntax", -"synthol", -"syntomy", -"syntone", -"syntony", -"syntype", -"synusia", -"sypher", -"syre", -"syringa", -"syringe", -"syrinx", -"syrma", -"syrphid", -"syrt", -"syrtic", -"syrup", -"syruped", -"syruper", -"syrupy", -"syssel", -"system", -"systole", -"systyle", -"syzygy", -"t", -"ta", -"taa", -"taar", -"tab", -"tabacin", -"tabacum", -"tabanid", -"tabard", -"tabaret", -"tabaxir", -"tabber", -"tabby", -"tabefy", -"tabella", -"taberna", -"tabes", -"tabet", -"tabetic", -"tabic", -"tabid", -"tabidly", -"tabific", -"tabinet", -"tabla", -"table", -"tableau", -"tabled", -"tabler", -"tables", -"tablet", -"tabling", -"tabloid", -"tabog", -"taboo", -"taboot", -"tabor", -"taborer", -"taboret", -"taborin", -"tabour", -"tabret", -"tabu", -"tabula", -"tabular", -"tabule", -"tabut", -"taccada", -"tach", -"tache", -"tachiol", -"tacit", -"tacitly", -"tack", -"tacker", -"tacket", -"tackety", -"tackey", -"tacking", -"tackle", -"tackled", -"tackler", -"tacky", -"tacnode", -"tacso", -"tact", -"tactful", -"tactic", -"tactics", -"tactile", -"taction", -"tactite", -"tactive", -"tactor", -"tactual", -"tactus", -"tad", -"tade", -"tadpole", -"tae", -"tael", -"taen", -"taenia", -"taenial", -"taenian", -"taenite", -"taennin", -"taffeta", -"taffety", -"taffle", -"taffy", -"tafia", -"taft", -"tafwiz", -"tag", -"tagetol", -"tagged", -"tagger", -"taggle", -"taggy", -"taglet", -"taglike", -"taglock", -"tagrag", -"tagsore", -"tagtail", -"tagua", -"taguan", -"tagwerk", -"taha", -"taheen", -"tahil", -"tahin", -"tahr", -"tahsil", -"tahua", -"tai", -"taiaha", -"taich", -"taiga", -"taigle", -"taihoa", -"tail", -"tailage", -"tailed", -"tailer", -"tailet", -"tailge", -"tailing", -"taille", -"taillie", -"tailor", -"tailory", -"tailpin", -"taily", -"tailzee", -"tailzie", -"taimen", -"tain", -"taint", -"taintor", -"taipan", -"taipo", -"tairge", -"tairger", -"tairn", -"taisch", -"taise", -"taissle", -"tait", -"taiver", -"taivers", -"taivert", -"taj", -"takable", -"takar", -"take", -"takeful", -"taken", -"taker", -"takin", -"taking", -"takings", -"takosis", -"takt", -"taky", -"takyr", -"tal", -"tala", -"talabon", -"talahib", -"talaje", -"talak", -"talao", -"talar", -"talari", -"talaria", -"talaric", -"talayot", -"talbot", -"talc", -"talcer", -"talcky", -"talcoid", -"talcose", -"talcous", -"talcum", -"tald", -"tale", -"taled", -"taleful", -"talent", -"taler", -"tales", -"tali", -"taliage", -"taliera", -"talion", -"talipat", -"taliped", -"talipes", -"talipot", -"talis", -"talisay", -"talite", -"talitol", -"talk", -"talker", -"talkful", -"talkie", -"talking", -"talky", -"tall", -"tallage", -"tallboy", -"taller", -"tallero", -"talles", -"tallet", -"talliar", -"tallier", -"tallis", -"tallish", -"tallit", -"tallith", -"talloel", -"tallote", -"tallow", -"tallowy", -"tally", -"tallyho", -"talma", -"talon", -"taloned", -"talonic", -"talonid", -"talose", -"talpid", -"talpify", -"talpine", -"talpoid", -"talthib", -"taluk", -"taluka", -"talus", -"taluto", -"talwar", -"talwood", -"tam", -"tamable", -"tamably", -"tamale", -"tamandu", -"tamanu", -"tamara", -"tamarao", -"tamarin", -"tamas", -"tamasha", -"tambac", -"tamber", -"tambo", -"tamboo", -"tambor", -"tambour", -"tame", -"tamein", -"tamely", -"tamer", -"tamis", -"tamise", -"tamlung", -"tammie", -"tammock", -"tammy", -"tamp", -"tampala", -"tampan", -"tampang", -"tamper", -"tampin", -"tamping", -"tampion", -"tampon", -"tampoon", -"tan", -"tana", -"tanach", -"tanager", -"tanaist", -"tanak", -"tanan", -"tanbark", -"tanbur", -"tancel", -"tandan", -"tandem", -"tandle", -"tandour", -"tane", -"tang", -"tanga", -"tanged", -"tangelo", -"tangent", -"tanger", -"tangham", -"tanghan", -"tanghin", -"tangi", -"tangie", -"tangka", -"tanglad", -"tangle", -"tangler", -"tangly", -"tango", -"tangram", -"tangs", -"tangue", -"tangum", -"tangun", -"tangy", -"tanh", -"tanha", -"tania", -"tanica", -"tanier", -"tanist", -"tanjib", -"tanjong", -"tank", -"tanka", -"tankage", -"tankah", -"tankard", -"tanked", -"tanker", -"tankert", -"tankful", -"tankle", -"tankman", -"tanling", -"tannage", -"tannaic", -"tannaim", -"tannase", -"tannate", -"tanned", -"tanner", -"tannery", -"tannic", -"tannide", -"tannin", -"tanning", -"tannoid", -"tannyl", -"tanoa", -"tanquam", -"tanquen", -"tanrec", -"tansy", -"tantara", -"tanti", -"tantivy", -"tantle", -"tantra", -"tantric", -"tantrik", -"tantrum", -"tantum", -"tanwood", -"tanyard", -"tanzeb", -"tanzib", -"tanzy", -"tao", -"taotai", -"taoyin", -"tap", -"tapa", -"tapalo", -"tapas", -"tapasvi", -"tape", -"tapeman", -"tapen", -"taper", -"tapered", -"taperer", -"taperly", -"tapet", -"tapetal", -"tapete", -"tapeti", -"tapetum", -"taphole", -"tapia", -"tapioca", -"tapir", -"tapis", -"tapism", -"tapist", -"taplash", -"taplet", -"tapmost", -"tapnet", -"tapoa", -"tapoun", -"tappa", -"tappall", -"tappaul", -"tappen", -"tapper", -"tappet", -"tapping", -"tappoon", -"taproom", -"taproot", -"taps", -"tapster", -"tapu", -"tapul", -"taqua", -"tar", -"tara", -"taraf", -"tarage", -"tarairi", -"tarand", -"taraph", -"tarapin", -"tarata", -"taratah", -"tarau", -"tarbet", -"tarboy", -"tarbush", -"tardily", -"tardive", -"tardle", -"tardy", -"tare", -"tarea", -"tarefa", -"tarente", -"tarfa", -"targe", -"targer", -"target", -"tarhood", -"tari", -"tarie", -"tariff", -"tarin", -"tariric", -"tarish", -"tarkhan", -"tarlike", -"tarmac", -"tarman", -"tarn", -"tarnal", -"tarnish", -"taro", -"taroc", -"tarocco", -"tarok", -"tarot", -"tarp", -"tarpan", -"tarpon", -"tarpot", -"tarpum", -"tarr", -"tarrack", -"tarras", -"tarrass", -"tarred", -"tarrer", -"tarri", -"tarrie", -"tarrier", -"tarrify", -"tarrily", -"tarrish", -"tarrock", -"tarrow", -"tarry", -"tars", -"tarsal", -"tarsale", -"tarse", -"tarsi", -"tarsia", -"tarsier", -"tarsome", -"tarsus", -"tart", -"tartago", -"tartan", -"tartana", -"tartane", -"tartar", -"tarten", -"tartish", -"tartle", -"tartlet", -"tartly", -"tartro", -"tartryl", -"tarve", -"tarweed", -"tarwood", -"taryard", -"tasajo", -"tascal", -"tasco", -"tash", -"tashie", -"tashlik", -"tashrif", -"task", -"taskage", -"tasker", -"taskit", -"taslet", -"tass", -"tassago", -"tassah", -"tassal", -"tassard", -"tasse", -"tassel", -"tassely", -"tasser", -"tasset", -"tassie", -"tassoo", -"taste", -"tasted", -"tasten", -"taster", -"tastily", -"tasting", -"tasty", -"tasu", -"tat", -"tataupa", -"tatbeb", -"tatchy", -"tate", -"tater", -"tath", -"tatie", -"tatinek", -"tatler", -"tatou", -"tatouay", -"tatsman", -"tatta", -"tatter", -"tattery", -"tatther", -"tattied", -"tatting", -"tattle", -"tattler", -"tattoo", -"tattva", -"tatty", -"tatu", -"tau", -"taught", -"taula", -"taum", -"taun", -"taunt", -"taunter", -"taupe", -"taupo", -"taupou", -"taur", -"taurean", -"taurian", -"tauric", -"taurine", -"taurite", -"tauryl", -"taut", -"tautaug", -"tauted", -"tauten", -"tautit", -"tautly", -"tautog", -"tav", -"tave", -"tavell", -"taver", -"tavern", -"tavers", -"tavert", -"tavola", -"taw", -"tawa", -"tawdry", -"tawer", -"tawery", -"tawie", -"tawite", -"tawkee", -"tawkin", -"tawn", -"tawney", -"tawnily", -"tawnle", -"tawny", -"tawpi", -"tawpie", -"taws", -"tawse", -"tawtie", -"tax", -"taxable", -"taxably", -"taxator", -"taxed", -"taxeme", -"taxemic", -"taxer", -"taxi", -"taxibus", -"taxicab", -"taximan", -"taxine", -"taxing", -"taxis", -"taxite", -"taxitic", -"taxless", -"taxman", -"taxon", -"taxor", -"taxpaid", -"taxwax", -"taxy", -"tay", -"tayer", -"tayir", -"tayra", -"taysaam", -"tazia", -"tch", -"tchai", -"tcharik", -"tchast", -"tche", -"tchick", -"tchu", -"tck", -"te", -"tea", -"teabox", -"teaboy", -"teacake", -"teacart", -"teach", -"teache", -"teacher", -"teachy", -"teacup", -"tead", -"teadish", -"teaer", -"teaey", -"teagle", -"teaish", -"teaism", -"teak", -"teal", -"tealery", -"tealess", -"team", -"teaman", -"teameo", -"teamer", -"teaming", -"teamman", -"tean", -"teanal", -"teap", -"teapot", -"teapoy", -"tear", -"tearage", -"tearcat", -"tearer", -"tearful", -"tearing", -"tearlet", -"tearoom", -"tearpit", -"teart", -"teary", -"tease", -"teasel", -"teaser", -"teashop", -"teasing", -"teasler", -"teasy", -"teat", -"teated", -"teathe", -"teather", -"teatime", -"teatman", -"teaty", -"teave", -"teaware", -"teaze", -"teazer", -"tebbet", -"tec", -"teca", -"tecali", -"tech", -"techily", -"technic", -"techous", -"techy", -"teck", -"tecomin", -"tecon", -"tectal", -"tectum", -"tecum", -"tecuma", -"ted", -"tedder", -"tedge", -"tedious", -"tedium", -"tee", -"teedle", -"teel", -"teem", -"teemer", -"teemful", -"teeming", -"teems", -"teen", -"teenage", -"teenet", -"teens", -"teensy", -"teenty", -"teeny", -"teer", -"teerer", -"teest", -"teet", -"teetan", -"teeter", -"teeth", -"teethe", -"teethy", -"teeting", -"teety", -"teevee", -"teff", -"teg", -"tegmen", -"tegmina", -"tegua", -"tegula", -"tegular", -"tegumen", -"tehseel", -"tehsil", -"teicher", -"teil", -"teind", -"teinder", -"teioid", -"tejon", -"teju", -"tekiah", -"tekke", -"tekken", -"tektite", -"tekya", -"telamon", -"telang", -"telar", -"telary", -"tele", -"teledu", -"telega", -"teleost", -"teleran", -"telergy", -"telesia", -"telesis", -"teleuto", -"televox", -"telfer", -"telford", -"teli", -"telial", -"telic", -"telical", -"telium", -"tell", -"tellach", -"tellee", -"teller", -"telling", -"tellt", -"telome", -"telomic", -"telpath", -"telpher", -"telson", -"telt", -"telurgy", -"telyn", -"temacha", -"teman", -"tembe", -"temblor", -"temenos", -"temiak", -"temin", -"temp", -"temper", -"tempera", -"tempery", -"tempest", -"tempi", -"templar", -"temple", -"templed", -"templet", -"tempo", -"tempora", -"tempre", -"tempt", -"tempter", -"temse", -"temser", -"ten", -"tenable", -"tenably", -"tenace", -"tenai", -"tenancy", -"tenant", -"tench", -"tend", -"tendant", -"tendent", -"tender", -"tending", -"tendon", -"tendour", -"tendril", -"tendron", -"tenebra", -"tenent", -"teneral", -"tenet", -"tenfold", -"teng", -"tengere", -"tengu", -"tenible", -"tenio", -"tenline", -"tenne", -"tenner", -"tennis", -"tennisy", -"tenon", -"tenoner", -"tenor", -"tenpin", -"tenrec", -"tense", -"tensely", -"tensify", -"tensile", -"tension", -"tensity", -"tensive", -"tenson", -"tensor", -"tent", -"tentage", -"tented", -"tenter", -"tentful", -"tenth", -"tenthly", -"tentigo", -"tention", -"tentlet", -"tenture", -"tenty", -"tenuate", -"tenues", -"tenuis", -"tenuity", -"tenuous", -"tenure", -"teopan", -"tepache", -"tepal", -"tepee", -"tepefy", -"tepid", -"tepidly", -"tepor", -"tequila", -"tera", -"terap", -"teras", -"terbia", -"terbic", -"terbium", -"tercel", -"tercer", -"tercet", -"tercia", -"tercine", -"tercio", -"terebic", -"terebra", -"teredo", -"terek", -"terete", -"tereu", -"terfez", -"tergal", -"tergant", -"tergite", -"tergum", -"term", -"terma", -"termage", -"termen", -"termer", -"termin", -"termine", -"termini", -"termino", -"termite", -"termly", -"termon", -"termor", -"tern", -"terna", -"ternal", -"ternar", -"ternary", -"ternate", -"terne", -"ternery", -"ternion", -"ternize", -"ternlet", -"terp", -"terpane", -"terpene", -"terpin", -"terpine", -"terrace", -"terrage", -"terrain", -"terral", -"terrane", -"terrar", -"terrene", -"terret", -"terrier", -"terrify", -"terrine", -"terron", -"terror", -"terry", -"terse", -"tersely", -"tersion", -"tertia", -"tertial", -"tertian", -"tertius", -"terton", -"tervee", -"terzina", -"terzo", -"tesack", -"teskere", -"tessara", -"tessel", -"tessera", -"test", -"testa", -"testacy", -"testar", -"testata", -"testate", -"teste", -"tested", -"testee", -"tester", -"testes", -"testify", -"testily", -"testing", -"testis", -"teston", -"testone", -"testoon", -"testor", -"testril", -"testudo", -"testy", -"tetanic", -"tetanus", -"tetany", -"tetard", -"tetch", -"tetchy", -"tete", -"tetel", -"teth", -"tether", -"tethery", -"tetra", -"tetract", -"tetrad", -"tetrane", -"tetrazo", -"tetric", -"tetrode", -"tetrole", -"tetrose", -"tetryl", -"tetter", -"tettery", -"tettix", -"teucrin", -"teufit", -"teuk", -"teviss", -"tew", -"tewel", -"tewer", -"tewit", -"tewly", -"tewsome", -"text", -"textile", -"textlet", -"textman", -"textual", -"texture", -"tez", -"tezkere", -"th", -"tha", -"thack", -"thacker", -"thakur", -"thalami", -"thaler", -"thalli", -"thallic", -"thallus", -"thameng", -"than", -"thana", -"thanage", -"thanan", -"thane", -"thank", -"thankee", -"thanker", -"thanks", -"thapes", -"thapsia", -"thar", -"tharf", -"tharm", -"that", -"thatch", -"thatchy", -"thatn", -"thats", -"thaught", -"thave", -"thaw", -"thawer", -"thawn", -"thawy", -"the", -"theah", -"theasum", -"theat", -"theater", -"theatry", -"theave", -"theb", -"theca", -"thecae", -"thecal", -"thecate", -"thecia", -"thecium", -"thecla", -"theclan", -"thecoid", -"thee", -"theek", -"theeker", -"theelin", -"theelol", -"theer", -"theet", -"theezan", -"theft", -"thegn", -"thegnly", -"theine", -"their", -"theirn", -"theirs", -"theism", -"theist", -"thelium", -"them", -"thema", -"themata", -"theme", -"themer", -"themis", -"themsel", -"then", -"thenal", -"thenar", -"thence", -"theody", -"theorbo", -"theorem", -"theoria", -"theoric", -"theorum", -"theory", -"theow", -"therapy", -"there", -"thereas", -"thereat", -"thereby", -"therein", -"thereof", -"thereon", -"theres", -"therese", -"thereto", -"thereup", -"theriac", -"therial", -"therm", -"thermae", -"thermal", -"thermic", -"thermit", -"thermo", -"thermos", -"theroid", -"these", -"theses", -"thesial", -"thesis", -"theta", -"thetch", -"thetic", -"thetics", -"thetin", -"thetine", -"theurgy", -"thew", -"thewed", -"thewy", -"they", -"theyll", -"theyre", -"thiamin", -"thiasi", -"thiasoi", -"thiasos", -"thiasus", -"thick", -"thicken", -"thicket", -"thickly", -"thief", -"thienyl", -"thieve", -"thiever", -"thig", -"thigger", -"thigh", -"thighed", -"thight", -"thilk", -"thill", -"thiller", -"thilly", -"thimber", -"thimble", -"thin", -"thine", -"thing", -"thingal", -"thingly", -"thingum", -"thingy", -"think", -"thinker", -"thinly", -"thinner", -"thio", -"thiol", -"thiolic", -"thionic", -"thionyl", -"thir", -"third", -"thirdly", -"thirl", -"thirst", -"thirsty", -"thirt", -"thirty", -"this", -"thishow", -"thisn", -"thissen", -"thistle", -"thistly", -"thither", -"thiuram", -"thivel", -"thixle", -"tho", -"thob", -"thocht", -"thof", -"thoft", -"thoke", -"thokish", -"thole", -"tholi", -"tholoi", -"tholos", -"tholus", -"thon", -"thonder", -"thone", -"thong", -"thonged", -"thongy", -"thoo", -"thooid", -"thoom", -"thoral", -"thorax", -"thore", -"thoria", -"thoric", -"thorina", -"thorite", -"thorium", -"thorn", -"thorned", -"thornen", -"thorny", -"thoro", -"thoron", -"thorp", -"thort", -"thorter", -"those", -"thou", -"though", -"thought", -"thouse", -"thow", -"thowel", -"thowt", -"thrack", -"thraep", -"thrail", -"thrain", -"thrall", -"thram", -"thrang", -"thrap", -"thrash", -"thrast", -"thrave", -"thraver", -"thraw", -"thrawn", -"thread", -"thready", -"threap", -"threat", -"three", -"threne", -"threnos", -"threose", -"thresh", -"threw", -"thrice", -"thrift", -"thrifty", -"thrill", -"thrilly", -"thrimp", -"thring", -"thrip", -"thripel", -"thrips", -"thrive", -"thriven", -"thriver", -"thro", -"throat", -"throaty", -"throb", -"throck", -"throddy", -"throe", -"thronal", -"throne", -"throng", -"throu", -"throuch", -"through", -"throve", -"throw", -"thrower", -"thrown", -"thrum", -"thrummy", -"thrush", -"thrushy", -"thrust", -"thrutch", -"thruv", -"thrymsa", -"thud", -"thug", -"thugdom", -"thuggee", -"thujene", -"thujin", -"thujone", -"thujyl", -"thulia", -"thulir", -"thulite", -"thulium", -"thulr", -"thuluth", -"thumb", -"thumbed", -"thumber", -"thumble", -"thumby", -"thump", -"thumper", -"thunder", -"thung", -"thunge", -"thuoc", -"thurify", -"thurl", -"thurm", -"thurmus", -"thurse", -"thurt", -"thus", -"thusly", -"thutter", -"thwack", -"thwaite", -"thwart", -"thwite", -"thy", -"thyine", -"thymate", -"thyme", -"thymele", -"thymene", -"thymic", -"thymine", -"thymol", -"thymoma", -"thymus", -"thymy", -"thymyl", -"thynnid", -"thyroid", -"thyrse", -"thyrsus", -"thysel", -"thyself", -"thysen", -"ti", -"tiang", -"tiao", -"tiar", -"tiara", -"tib", -"tibby", -"tibet", -"tibey", -"tibia", -"tibiad", -"tibiae", -"tibial", -"tibiale", -"tiburon", -"tic", -"tical", -"ticca", -"tice", -"ticer", -"tick", -"ticked", -"ticken", -"ticker", -"ticket", -"tickey", -"tickie", -"ticking", -"tickle", -"tickled", -"tickler", -"tickly", -"tickney", -"ticky", -"ticul", -"tid", -"tidal", -"tidally", -"tidbit", -"tiddle", -"tiddler", -"tiddley", -"tiddy", -"tide", -"tided", -"tideful", -"tidely", -"tideway", -"tidily", -"tiding", -"tidings", -"tidley", -"tidy", -"tidyism", -"tie", -"tieback", -"tied", -"tien", -"tiepin", -"tier", -"tierce", -"tierced", -"tiered", -"tierer", -"tietick", -"tiewig", -"tiff", -"tiffany", -"tiffie", -"tiffin", -"tiffish", -"tiffle", -"tiffy", -"tift", -"tifter", -"tig", -"tige", -"tigella", -"tigelle", -"tiger", -"tigerly", -"tigery", -"tigger", -"tight", -"tighten", -"tightly", -"tights", -"tiglic", -"tignum", -"tigress", -"tigrine", -"tigroid", -"tigtag", -"tikka", -"tikker", -"tiklin", -"tikor", -"tikur", -"til", -"tilaite", -"tilaka", -"tilbury", -"tilde", -"tile", -"tiled", -"tiler", -"tilery", -"tilikum", -"tiling", -"till", -"tillage", -"tiller", -"tilley", -"tillite", -"tillot", -"tilly", -"tilmus", -"tilpah", -"tilt", -"tilter", -"tilth", -"tilting", -"tiltup", -"tilty", -"tilyer", -"timable", -"timar", -"timarau", -"timawa", -"timbal", -"timbale", -"timbang", -"timbe", -"timber", -"timbern", -"timbery", -"timbo", -"timbre", -"timbrel", -"time", -"timed", -"timeful", -"timely", -"timeous", -"timer", -"times", -"timid", -"timidly", -"timing", -"timish", -"timist", -"timon", -"timor", -"timothy", -"timpani", -"timpano", -"tin", -"tinamou", -"tincal", -"tinchel", -"tinclad", -"tinct", -"tind", -"tindal", -"tindalo", -"tinder", -"tindery", -"tine", -"tinea", -"tineal", -"tinean", -"tined", -"tineid", -"tineine", -"tineman", -"tineoid", -"tinety", -"tinful", -"ting", -"tinge", -"tinged", -"tinger", -"tingi", -"tingid", -"tingle", -"tingler", -"tingly", -"tinguy", -"tinhorn", -"tinily", -"tining", -"tink", -"tinker", -"tinkle", -"tinkler", -"tinkly", -"tinlet", -"tinlike", -"tinman", -"tinned", -"tinner", -"tinnery", -"tinnet", -"tinnily", -"tinning", -"tinnock", -"tinny", -"tinosa", -"tinsel", -"tinsman", -"tint", -"tinta", -"tintage", -"tinted", -"tinter", -"tintie", -"tinting", -"tintist", -"tinty", -"tintype", -"tinwald", -"tinware", -"tinwork", -"tiny", -"tip", -"tipburn", -"tipcart", -"tipcat", -"tipe", -"tipful", -"tiphead", -"tipiti", -"tiple", -"tipless", -"tiplet", -"tipman", -"tipmost", -"tiponi", -"tipped", -"tippee", -"tipper", -"tippet", -"tipping", -"tipple", -"tippler", -"tipply", -"tippy", -"tipsify", -"tipsily", -"tipster", -"tipsy", -"tiptail", -"tiptilt", -"tiptoe", -"tiptop", -"tipulid", -"tipup", -"tirade", -"tiralee", -"tire", -"tired", -"tiredly", -"tiredom", -"tireman", -"tirer", -"tiriba", -"tiring", -"tirl", -"tirma", -"tirr", -"tirret", -"tirrlie", -"tirve", -"tirwit", -"tisane", -"tisar", -"tissual", -"tissue", -"tissued", -"tissuey", -"tiswin", -"tit", -"titania", -"titanic", -"titano", -"titanyl", -"titar", -"titbit", -"tite", -"titer", -"titfish", -"tithal", -"tithe", -"tither", -"tithing", -"titi", -"titian", -"titien", -"titlark", -"title", -"titled", -"titler", -"titlike", -"titling", -"titlist", -"titmal", -"titman", -"titoki", -"titrate", -"titre", -"titter", -"tittery", -"tittie", -"tittle", -"tittler", -"tittup", -"tittupy", -"titty", -"titular", -"titule", -"titulus", -"tiver", -"tivoli", -"tivy", -"tiza", -"tizeur", -"tizzy", -"tji", -"tjosite", -"tlaco", -"tmema", -"tmesis", -"to", -"toa", -"toad", -"toadeat", -"toader", -"toadery", -"toadess", -"toadier", -"toadish", -"toadlet", -"toady", -"toast", -"toastee", -"toaster", -"toasty", -"toat", -"toatoa", -"tobacco", -"tobe", -"tobine", -"tobira", -"toby", -"tobyman", -"toccata", -"tocher", -"tock", -"toco", -"tocome", -"tocsin", -"tocusso", -"tod", -"today", -"todder", -"toddick", -"toddite", -"toddle", -"toddler", -"toddy", -"tode", -"tody", -"toe", -"toecap", -"toed", -"toeless", -"toelike", -"toenail", -"toetoe", -"toff", -"toffee", -"toffing", -"toffish", -"toffy", -"toft", -"tofter", -"toftman", -"tofu", -"tog", -"toga", -"togaed", -"togata", -"togate", -"togated", -"toggel", -"toggery", -"toggle", -"toggler", -"togless", -"togs", -"togt", -"togue", -"toher", -"toheroa", -"toho", -"tohunga", -"toi", -"toil", -"toiled", -"toiler", -"toilet", -"toilful", -"toiling", -"toise", -"toit", -"toitish", -"toity", -"tokay", -"toke", -"token", -"tokened", -"toko", -"tokopat", -"tol", -"tolan", -"tolane", -"told", -"toldo", -"tole", -"tolite", -"toll", -"tollage", -"toller", -"tollery", -"tolling", -"tollman", -"tolly", -"tolsey", -"tolt", -"tolter", -"tolu", -"toluate", -"toluene", -"toluic", -"toluide", -"toluido", -"toluol", -"toluyl", -"tolyl", -"toman", -"tomato", -"tomb", -"tombac", -"tombal", -"tombe", -"tombic", -"tomblet", -"tombola", -"tombolo", -"tomboy", -"tomcat", -"tomcod", -"tome", -"tomeful", -"tomelet", -"toment", -"tomfool", -"tomial", -"tomin", -"tomish", -"tomium", -"tomjohn", -"tomkin", -"tommy", -"tomnoup", -"tomorn", -"tomosis", -"tompon", -"tomtate", -"tomtit", -"ton", -"tonal", -"tonally", -"tonant", -"tondino", -"tone", -"toned", -"toneme", -"toner", -"tonetic", -"tong", -"tonga", -"tonger", -"tongman", -"tongs", -"tongue", -"tongued", -"tonguer", -"tonguey", -"tonic", -"tonify", -"tonight", -"tonish", -"tonite", -"tonjon", -"tonk", -"tonkin", -"tonlet", -"tonnage", -"tonneau", -"tonner", -"tonnish", -"tonous", -"tonsil", -"tonsor", -"tonsure", -"tontine", -"tonus", -"tony", -"too", -"toodle", -"took", -"tooken", -"tool", -"toolbox", -"tooler", -"tooling", -"toolman", -"toom", -"toomly", -"toon", -"toop", -"toorie", -"toorock", -"tooroo", -"toosh", -"toot", -"tooter", -"tooth", -"toothed", -"toother", -"toothy", -"tootle", -"tootler", -"tootsy", -"toozle", -"toozoo", -"top", -"toparch", -"topass", -"topaz", -"topazy", -"topcap", -"topcast", -"topcoat", -"tope", -"topee", -"topeng", -"topepo", -"toper", -"topfull", -"toph", -"tophus", -"topi", -"topia", -"topiary", -"topic", -"topical", -"topknot", -"topless", -"toplike", -"topline", -"topman", -"topmast", -"topmost", -"topo", -"toponym", -"topped", -"topper", -"topping", -"topple", -"toppler", -"topply", -"toppy", -"toprail", -"toprope", -"tops", -"topsail", -"topside", -"topsl", -"topsman", -"topsoil", -"toptail", -"topwise", -"toque", -"tor", -"tora", -"torah", -"toral", -"toran", -"torc", -"torcel", -"torch", -"torcher", -"torchon", -"tore", -"tored", -"torero", -"torfel", -"torgoch", -"toric", -"torii", -"torma", -"tormen", -"torment", -"tormina", -"torn", -"tornade", -"tornado", -"tornal", -"tornese", -"torney", -"tornote", -"tornus", -"toro", -"toroid", -"torose", -"torous", -"torpedo", -"torpent", -"torpid", -"torpify", -"torpor", -"torque", -"torqued", -"torques", -"torrefy", -"torrent", -"torrid", -"torsade", -"torse", -"torsel", -"torsile", -"torsion", -"torsive", -"torsk", -"torso", -"tort", -"torta", -"torteau", -"tortile", -"tortive", -"tortula", -"torture", -"toru", -"torula", -"torulin", -"torulus", -"torus", -"torve", -"torvid", -"torvity", -"torvous", -"tory", -"tosh", -"tosher", -"toshery", -"toshly", -"toshy", -"tosily", -"toss", -"tosser", -"tossily", -"tossing", -"tosspot", -"tossup", -"tossy", -"tost", -"toston", -"tosy", -"tot", -"total", -"totally", -"totara", -"totchka", -"tote", -"totem", -"totemic", -"totemy", -"toter", -"tother", -"totient", -"toto", -"totora", -"totquot", -"totter", -"tottery", -"totting", -"tottle", -"totty", -"totuava", -"totum", -"toty", -"totyman", -"tou", -"toucan", -"touch", -"touched", -"toucher", -"touchy", -"toug", -"tough", -"toughen", -"toughly", -"tought", -"tould", -"toumnah", -"toup", -"toupee", -"toupeed", -"toupet", -"tour", -"touraco", -"tourer", -"touring", -"tourism", -"tourist", -"tourize", -"tourn", -"tournay", -"tournee", -"tourney", -"tourte", -"tousche", -"touse", -"touser", -"tousle", -"tously", -"tousy", -"tout", -"touter", -"tovar", -"tow", -"towable", -"towage", -"towai", -"towan", -"toward", -"towards", -"towboat", -"towcock", -"towd", -"towel", -"towelry", -"tower", -"towered", -"towery", -"towght", -"towhead", -"towhee", -"towing", -"towkay", -"towlike", -"towline", -"towmast", -"town", -"towned", -"townee", -"towner", -"townet", -"townful", -"townify", -"townish", -"townist", -"townlet", -"townly", -"townman", -"towny", -"towpath", -"towrope", -"towser", -"towy", -"tox", -"toxa", -"toxamin", -"toxcatl", -"toxemia", -"toxemic", -"toxic", -"toxical", -"toxicum", -"toxifer", -"toxin", -"toxity", -"toxoid", -"toxon", -"toxone", -"toxosis", -"toxotae", -"toy", -"toydom", -"toyer", -"toyful", -"toying", -"toyish", -"toyland", -"toyless", -"toylike", -"toyman", -"toyon", -"toyshop", -"toysome", -"toytown", -"toywort", -"toze", -"tozee", -"tozer", -"tra", -"trabal", -"trabant", -"trabea", -"trabeae", -"trabuch", -"trace", -"tracer", -"tracery", -"trachea", -"trachle", -"tracing", -"track", -"tracked", -"tracker", -"tract", -"tractor", -"tradal", -"trade", -"trader", -"trading", -"tradite", -"traduce", -"trady", -"traffic", -"trag", -"tragal", -"tragedy", -"tragi", -"tragic", -"tragus", -"trah", -"traheen", -"traik", -"trail", -"trailer", -"traily", -"train", -"trained", -"trainee", -"trainer", -"trainy", -"traipse", -"trait", -"traitor", -"traject", -"trajet", -"tralira", -"tram", -"trama", -"tramal", -"tramcar", -"trame", -"tramful", -"tramman", -"trammel", -"trammer", -"trammon", -"tramp", -"tramper", -"trample", -"trampot", -"tramway", -"trance", -"tranced", -"traneen", -"trank", -"tranka", -"tranker", -"trankum", -"tranky", -"transit", -"transom", -"trant", -"tranter", -"trap", -"trapes", -"trapeze", -"trapped", -"trapper", -"trappy", -"traps", -"trash", -"traship", -"trashy", -"trass", -"trasy", -"trauma", -"travail", -"travale", -"trave", -"travel", -"travis", -"travois", -"travoy", -"trawl", -"trawler", -"tray", -"trayful", -"treacle", -"treacly", -"tread", -"treader", -"treadle", -"treason", -"treat", -"treatee", -"treater", -"treator", -"treaty", -"treble", -"trebly", -"treddle", -"tree", -"treed", -"treeful", -"treeify", -"treelet", -"treeman", -"treen", -"treetop", -"treey", -"tref", -"trefle", -"trefoil", -"tregerg", -"tregohm", -"trehala", -"trek", -"trekker", -"trellis", -"tremble", -"trembly", -"tremie", -"tremolo", -"tremor", -"trenail", -"trench", -"trend", -"trendle", -"trental", -"trepan", -"trepang", -"trepid", -"tress", -"tressed", -"tresson", -"tressy", -"trest", -"trestle", -"tret", -"trevet", -"trews", -"trey", -"tri", -"triable", -"triace", -"triacid", -"triact", -"triad", -"triadic", -"triaene", -"triage", -"trial", -"triamid", -"triarch", -"triarii", -"triatic", -"triaxon", -"triazin", -"triazo", -"tribade", -"tribady", -"tribal", -"tribase", -"tribble", -"tribe", -"triblet", -"tribrac", -"tribual", -"tribuna", -"tribune", -"tribute", -"trica", -"tricae", -"tricar", -"trice", -"triceps", -"trichi", -"trichia", -"trichy", -"trick", -"tricker", -"trickle", -"trickly", -"tricksy", -"tricky", -"triclad", -"tricorn", -"tricot", -"trident", -"triduan", -"triduum", -"tried", -"triedly", -"triene", -"triens", -"trier", -"trifa", -"trifid", -"trifle", -"trifler", -"triflet", -"trifoil", -"trifold", -"trifoly", -"triform", -"trig", -"trigamy", -"trigger", -"triglid", -"triglot", -"trigly", -"trigon", -"trigone", -"trigram", -"trigyn", -"trikaya", -"trike", -"triker", -"triketo", -"trikir", -"trilabe", -"trilby", -"trilit", -"trilite", -"trilith", -"trill", -"trillet", -"trilli", -"trillo", -"trilobe", -"trilogy", -"trim", -"trimer", -"trimly", -"trimmer", -"trin", -"trinal", -"trinary", -"trindle", -"trine", -"trinely", -"tringle", -"trinity", -"trink", -"trinket", -"trinkle", -"trinode", -"trinol", -"trintle", -"trio", -"triobol", -"triode", -"triodia", -"triole", -"triolet", -"trionym", -"trior", -"triose", -"trip", -"tripal", -"tripara", -"tripart", -"tripe", -"tripel", -"tripery", -"triple", -"triplet", -"triplex", -"triplum", -"triply", -"tripod", -"tripody", -"tripoli", -"tripos", -"tripper", -"trippet", -"tripple", -"tripsis", -"tripy", -"trireme", -"trisalt", -"trisazo", -"trisect", -"triseme", -"trishna", -"trismic", -"trismus", -"trisome", -"trisomy", -"trist", -"trisul", -"trisula", -"tritaph", -"trite", -"tritely", -"tritish", -"tritium", -"tritolo", -"triton", -"tritone", -"tritor", -"trityl", -"triumph", -"triunal", -"triune", -"triurid", -"trivant", -"trivet", -"trivia", -"trivial", -"trivium", -"trivvet", -"trizoic", -"trizone", -"troat", -"troca", -"trocar", -"trochal", -"troche", -"trochee", -"trochi", -"trochid", -"trochus", -"trock", -"troco", -"trod", -"trodden", -"trode", -"troft", -"trog", -"trogger", -"troggin", -"trogon", -"trogs", -"trogue", -"troika", -"troke", -"troker", -"troll", -"troller", -"trolley", -"trollol", -"trollop", -"trolly", -"tromba", -"trombe", -"trommel", -"tromp", -"trompe", -"trompil", -"tromple", -"tron", -"trona", -"tronage", -"tronc", -"trone", -"troner", -"troolie", -"troop", -"trooper", -"troot", -"tropal", -"tropary", -"tropate", -"trope", -"tropeic", -"troper", -"trophal", -"trophi", -"trophic", -"trophy", -"tropic", -"tropine", -"tropism", -"tropist", -"tropoyl", -"tropyl", -"trot", -"troth", -"trotlet", -"trotol", -"trotter", -"trottie", -"trotty", -"trotyl", -"trouble", -"troubly", -"trough", -"troughy", -"trounce", -"troupe", -"trouper", -"trouse", -"trouser", -"trout", -"trouter", -"trouty", -"trove", -"trover", -"trow", -"trowel", -"trowing", -"trowman", -"trowth", -"troy", -"truancy", -"truant", -"trub", -"trubu", -"truce", -"trucial", -"truck", -"trucker", -"truckle", -"trucks", -"truddo", -"trudge", -"trudgen", -"trudger", -"true", -"truer", -"truff", -"truffle", -"trug", -"truish", -"truism", -"trull", -"truller", -"trullo", -"truly", -"trummel", -"trump", -"trumper", -"trumpet", -"trumph", -"trumpie", -"trun", -"truncal", -"trunch", -"trundle", -"trunk", -"trunked", -"trunnel", -"trush", -"trusion", -"truss", -"trussed", -"trusser", -"trust", -"trustee", -"trusten", -"truster", -"trustle", -"trusty", -"truth", -"truthy", -"truvat", -"try", -"trygon", -"trying", -"tryma", -"tryout", -"tryp", -"trypa", -"trypan", -"trypsin", -"tryptic", -"trysail", -"tryst", -"tryster", -"tryt", -"tsadik", -"tsamba", -"tsantsa", -"tsar", -"tsardom", -"tsarina", -"tsatlee", -"tsere", -"tsetse", -"tsia", -"tsine", -"tst", -"tsuba", -"tsubo", -"tsun", -"tsunami", -"tsungtu", -"tu", -"tua", -"tuan", -"tuarn", -"tuart", -"tuatara", -"tuatera", -"tuath", -"tub", -"tuba", -"tubae", -"tubage", -"tubal", -"tubar", -"tubate", -"tubba", -"tubbal", -"tubbeck", -"tubber", -"tubbie", -"tubbing", -"tubbish", -"tubboe", -"tubby", -"tube", -"tubeful", -"tubelet", -"tubeman", -"tuber", -"tuberin", -"tubfish", -"tubful", -"tubicen", -"tubifer", -"tubig", -"tubik", -"tubing", -"tublet", -"tublike", -"tubman", -"tubular", -"tubule", -"tubulet", -"tubuli", -"tubulus", -"tuchit", -"tuchun", -"tuck", -"tucker", -"tucket", -"tucking", -"tuckner", -"tucktoo", -"tucky", -"tucum", -"tucuma", -"tucuman", -"tudel", -"tue", -"tueiron", -"tufa", -"tufan", -"tuff", -"tuffet", -"tuffing", -"tuft", -"tufted", -"tufter", -"tuftily", -"tufting", -"tuftlet", -"tufty", -"tug", -"tugboat", -"tugger", -"tuggery", -"tugging", -"tughra", -"tugless", -"tuglike", -"tugman", -"tugrik", -"tugui", -"tui", -"tuik", -"tuille", -"tuilyie", -"tuism", -"tuition", -"tuitive", -"tuke", -"tukra", -"tula", -"tulare", -"tulasi", -"tulchan", -"tulchin", -"tule", -"tuliac", -"tulip", -"tulipy", -"tulisan", -"tulle", -"tulsi", -"tulwar", -"tum", -"tumasha", -"tumbak", -"tumble", -"tumbled", -"tumbler", -"tumbly", -"tumbrel", -"tume", -"tumefy", -"tumid", -"tumidly", -"tummals", -"tummel", -"tummer", -"tummock", -"tummy", -"tumor", -"tumored", -"tump", -"tumtum", -"tumular", -"tumuli", -"tumult", -"tumulus", -"tun", -"tuna", -"tunable", -"tunably", -"tunca", -"tund", -"tunder", -"tundish", -"tundra", -"tundun", -"tune", -"tuned", -"tuneful", -"tuner", -"tunful", -"tung", -"tungate", -"tungo", -"tunhoof", -"tunic", -"tunicin", -"tunicle", -"tuning", -"tunish", -"tunist", -"tunk", -"tunket", -"tunlike", -"tunmoot", -"tunna", -"tunnel", -"tunner", -"tunnery", -"tunnor", -"tunny", -"tuno", -"tunu", -"tuny", -"tup", -"tupara", -"tupek", -"tupelo", -"tupik", -"tupman", -"tupuna", -"tuque", -"tur", -"turacin", -"turb", -"turban", -"turbary", -"turbeh", -"turbid", -"turbine", -"turbit", -"turbith", -"turbo", -"turbot", -"turco", -"turd", -"turdine", -"turdoid", -"tureen", -"turf", -"turfage", -"turfdom", -"turfed", -"turfen", -"turfing", -"turfite", -"turfman", -"turfy", -"turgent", -"turgid", -"turgite", -"turgoid", -"turgor", -"turgy", -"turio", -"turion", -"turjite", -"turk", -"turken", -"turkey", -"turkis", -"turkle", -"turm", -"turma", -"turment", -"turmit", -"turmoil", -"turn", -"turncap", -"turndun", -"turned", -"turnel", -"turner", -"turnery", -"turney", -"turning", -"turnip", -"turnipy", -"turnix", -"turnkey", -"turnoff", -"turnout", -"turnpin", -"turnrow", -"turns", -"turnup", -"turp", -"turpeth", -"turpid", -"turps", -"turr", -"turret", -"turse", -"tursio", -"turtle", -"turtler", -"turtlet", -"turtosa", -"tururi", -"turus", -"turwar", -"tusche", -"tush", -"tushed", -"tusher", -"tushery", -"tusk", -"tuskar", -"tusked", -"tusker", -"tuskish", -"tusky", -"tussah", -"tussal", -"tusser", -"tussis", -"tussive", -"tussle", -"tussock", -"tussore", -"tussur", -"tut", -"tutania", -"tutball", -"tute", -"tutee", -"tutela", -"tutelar", -"tutenag", -"tuth", -"tutin", -"tutly", -"tutman", -"tutor", -"tutorer", -"tutorly", -"tutory", -"tutoyer", -"tutress", -"tutrice", -"tutrix", -"tuts", -"tutsan", -"tutster", -"tutti", -"tutty", -"tutu", -"tutulus", -"tutwork", -"tuwi", -"tux", -"tuxedo", -"tuyere", -"tuza", -"tuzzle", -"twa", -"twaddle", -"twaddly", -"twaddy", -"twae", -"twagger", -"twain", -"twaite", -"twal", -"twale", -"twalt", -"twang", -"twanger", -"twangle", -"twangy", -"twank", -"twanker", -"twankle", -"twanky", -"twant", -"twarly", -"twas", -"twasome", -"twat", -"twattle", -"tway", -"twazzy", -"tweag", -"tweak", -"tweaker", -"tweaky", -"twee", -"tweed", -"tweeded", -"tweedle", -"tweedy", -"tweeg", -"tweel", -"tween", -"tweeny", -"tweesh", -"tweesht", -"tweest", -"tweet", -"tweeter", -"tweeze", -"tweezer", -"tweil", -"twelfth", -"twelve", -"twenty", -"twere", -"twerp", -"twibil", -"twice", -"twicer", -"twicet", -"twick", -"twiddle", -"twiddly", -"twifoil", -"twifold", -"twig", -"twigful", -"twigged", -"twiggen", -"twigger", -"twiggy", -"twiglet", -"twilit", -"twill", -"twilled", -"twiller", -"twilly", -"twilt", -"twin", -"twindle", -"twine", -"twiner", -"twinge", -"twingle", -"twinism", -"twink", -"twinkle", -"twinkly", -"twinly", -"twinned", -"twinner", -"twinter", -"twiny", -"twire", -"twirk", -"twirl", -"twirler", -"twirly", -"twiscar", -"twisel", -"twist", -"twisted", -"twister", -"twistle", -"twisty", -"twit", -"twitch", -"twitchy", -"twite", -"twitten", -"twitter", -"twitty", -"twixt", -"twizzle", -"two", -"twofold", -"twoling", -"twoness", -"twosome", -"tychism", -"tychite", -"tycoon", -"tyddyn", -"tydie", -"tye", -"tyee", -"tyg", -"tying", -"tyke", -"tyken", -"tykhana", -"tyking", -"tylarus", -"tylion", -"tyloma", -"tylopod", -"tylose", -"tylosis", -"tylote", -"tylotic", -"tylotus", -"tylus", -"tymp", -"tympan", -"tympana", -"tympani", -"tympany", -"tynd", -"typal", -"type", -"typer", -"typeset", -"typhia", -"typhic", -"typhlon", -"typhoid", -"typhoon", -"typhose", -"typhous", -"typhus", -"typic", -"typica", -"typical", -"typicon", -"typicum", -"typify", -"typist", -"typo", -"typobar", -"typonym", -"typp", -"typy", -"tyranny", -"tyrant", -"tyre", -"tyro", -"tyroma", -"tyrone", -"tyronic", -"tyrosyl", -"tyste", -"tyt", -"tzolkin", -"tzontle", -"u", -"uang", -"uayeb", -"uberant", -"uberous", -"uberty", -"ubi", -"ubiety", -"ubiquit", -"ubussu", -"uckia", -"udal", -"udaler", -"udaller", -"udalman", -"udasi", -"udder", -"uddered", -"udell", -"udo", -"ug", -"ugh", -"uglify", -"uglily", -"ugly", -"ugsome", -"uhlan", -"uhllo", -"uhtsong", -"uily", -"uinal", -"uintjie", -"uitspan", -"uji", -"ukase", -"uke", -"ukiyoye", -"ukulele", -"ula", -"ulcer", -"ulcered", -"ulcery", -"ule", -"ulema", -"uletic", -"ulex", -"ulexine", -"ulexite", -"ulitis", -"ull", -"ulla", -"ullage", -"ullaged", -"uller", -"ulling", -"ulluco", -"ulmic", -"ulmin", -"ulminic", -"ulmo", -"ulmous", -"ulna", -"ulnad", -"ulnae", -"ulnar", -"ulnare", -"ulnaria", -"uloid", -"uloncus", -"ulster", -"ultima", -"ultimo", -"ultimum", -"ultra", -"ulu", -"ulua", -"uluhi", -"ululant", -"ululate", -"ululu", -"um", -"umbel", -"umbeled", -"umbella", -"umber", -"umbilic", -"umble", -"umbo", -"umbonal", -"umbone", -"umbones", -"umbonic", -"umbra", -"umbrae", -"umbrage", -"umbral", -"umbrel", -"umbril", -"umbrine", -"umbrose", -"umbrous", -"ume", -"umiak", -"umiri", -"umlaut", -"ump", -"umph", -"umpire", -"umpirer", -"umpteen", -"umpty", -"umu", -"un", -"unable", -"unably", -"unact", -"unacted", -"unacute", -"unadapt", -"unadd", -"unadded", -"unadopt", -"unadorn", -"unadult", -"unafire", -"unaflow", -"unaged", -"unagile", -"unaging", -"unaided", -"unaimed", -"unaired", -"unakin", -"unakite", -"unal", -"unalarm", -"unalert", -"unalike", -"unalist", -"unalive", -"unallow", -"unalone", -"unaloud", -"unamend", -"unamiss", -"unamo", -"unample", -"unamply", -"unangry", -"unannex", -"unapart", -"unapt", -"unaptly", -"unarch", -"unark", -"unarm", -"unarmed", -"unarray", -"unarted", -"unary", -"unasked", -"unau", -"unavian", -"unawake", -"unaware", -"unaway", -"unawed", -"unawful", -"unawned", -"unaxled", -"unbag", -"unbain", -"unbait", -"unbaked", -"unbale", -"unbank", -"unbar", -"unbarb", -"unbare", -"unbark", -"unbase", -"unbased", -"unbaste", -"unbated", -"unbay", -"unbe", -"unbear", -"unbeard", -"unbeast", -"unbed", -"unbefit", -"unbeget", -"unbegot", -"unbegun", -"unbeing", -"unbell", -"unbelt", -"unbench", -"unbend", -"unbent", -"unberth", -"unbeset", -"unbesot", -"unbet", -"unbias", -"unbid", -"unbind", -"unbit", -"unbitt", -"unblade", -"unbled", -"unblent", -"unbless", -"unblest", -"unblind", -"unbliss", -"unblock", -"unbloom", -"unblown", -"unblued", -"unblush", -"unboat", -"unbody", -"unbog", -"unboggy", -"unbokel", -"unbold", -"unbolt", -"unbone", -"unboned", -"unbonny", -"unboot", -"unbored", -"unborn", -"unborne", -"unbosom", -"unbound", -"unbow", -"unbowed", -"unbowel", -"unbox", -"unboxed", -"unboy", -"unbrace", -"unbraid", -"unbran", -"unbrand", -"unbrave", -"unbraze", -"unbred", -"unbrent", -"unbrick", -"unbrief", -"unbroad", -"unbroke", -"unbrown", -"unbrute", -"unbud", -"unbuild", -"unbuilt", -"unbulky", -"unbung", -"unburly", -"unburn", -"unburnt", -"unburst", -"unbury", -"unbush", -"unbusk", -"unbusy", -"unbuxom", -"unca", -"uncage", -"uncaged", -"uncake", -"uncalk", -"uncall", -"uncalm", -"uncaned", -"uncanny", -"uncap", -"uncart", -"uncase", -"uncased", -"uncask", -"uncast", -"uncaste", -"uncate", -"uncave", -"unceded", -"unchain", -"unchair", -"uncharm", -"unchary", -"uncheat", -"uncheck", -"unchid", -"unchild", -"unchurn", -"unci", -"uncia", -"uncial", -"uncinal", -"uncinch", -"uncinct", -"uncini", -"uncinus", -"uncite", -"uncited", -"uncity", -"uncivic", -"uncivil", -"unclad", -"unclamp", -"unclasp", -"unclay", -"uncle", -"unclead", -"unclean", -"unclear", -"uncleft", -"unclew", -"unclick", -"unclify", -"unclimb", -"uncling", -"unclip", -"uncloak", -"unclog", -"unclose", -"uncloud", -"unclout", -"unclub", -"unco", -"uncoach", -"uncoat", -"uncock", -"uncoded", -"uncoif", -"uncoil", -"uncoin", -"uncoked", -"uncolt", -"uncoly", -"uncome", -"uncomfy", -"uncomic", -"uncoop", -"uncope", -"uncord", -"uncore", -"uncored", -"uncork", -"uncost", -"uncouch", -"uncous", -"uncouth", -"uncover", -"uncowed", -"uncowl", -"uncoy", -"uncram", -"uncramp", -"uncream", -"uncrest", -"uncrib", -"uncried", -"uncrime", -"uncrisp", -"uncrook", -"uncropt", -"uncross", -"uncrown", -"uncrude", -"uncruel", -"unction", -"uncubic", -"uncular", -"uncurb", -"uncurd", -"uncured", -"uncurl", -"uncurse", -"uncurst", -"uncus", -"uncut", -"uncuth", -"undaily", -"undam", -"undamn", -"undared", -"undark", -"undate", -"undated", -"undaub", -"undazed", -"unde", -"undead", -"undeaf", -"undealt", -"undean", -"undear", -"undeck", -"undecyl", -"undeep", -"undeft", -"undeify", -"undelve", -"unden", -"under", -"underdo", -"underer", -"undergo", -"underly", -"undern", -"undevil", -"undewed", -"undewy", -"undid", -"undies", -"undig", -"undight", -"undiked", -"undim", -"undine", -"undined", -"undirk", -"undo", -"undock", -"undoer", -"undog", -"undoing", -"undomed", -"undon", -"undone", -"undoped", -"undose", -"undosed", -"undowny", -"undrab", -"undrag", -"undrape", -"undraw", -"undrawn", -"undress", -"undried", -"undrunk", -"undry", -"undub", -"unducal", -"undue", -"undug", -"unduke", -"undular", -"undull", -"unduly", -"unduped", -"undust", -"unduty", -"undwelt", -"undy", -"undye", -"undyed", -"undying", -"uneager", -"unearly", -"unearth", -"unease", -"uneasy", -"uneaten", -"uneath", -"unebbed", -"unedge", -"unedged", -"unelect", -"unempt", -"unempty", -"unended", -"unepic", -"unequal", -"unerect", -"unethic", -"uneven", -"unevil", -"unexact", -"uneye", -"uneyed", -"unface", -"unfaced", -"unfact", -"unfaded", -"unfain", -"unfaint", -"unfair", -"unfaith", -"unfaked", -"unfalse", -"unfamed", -"unfancy", -"unfar", -"unfast", -"unfeary", -"unfed", -"unfeed", -"unfele", -"unfelon", -"unfelt", -"unfence", -"unfeted", -"unfeued", -"unfew", -"unfiber", -"unfiend", -"unfiery", -"unfight", -"unfile", -"unfiled", -"unfill", -"unfilm", -"unfine", -"unfined", -"unfired", -"unfirm", -"unfit", -"unfitly", -"unfitty", -"unfix", -"unfixed", -"unflag", -"unflaky", -"unflank", -"unflat", -"unflead", -"unflesh", -"unflock", -"unfloor", -"unflown", -"unfluid", -"unflush", -"unfoggy", -"unfold", -"unfond", -"unfool", -"unfork", -"unform", -"unfoul", -"unfound", -"unfoxy", -"unfrail", -"unframe", -"unfrank", -"unfree", -"unfreed", -"unfret", -"unfried", -"unfrill", -"unfrizz", -"unfrock", -"unfrost", -"unfroze", -"unfull", -"unfully", -"unfumed", -"unfunny", -"unfur", -"unfurl", -"unfused", -"unfussy", -"ungag", -"ungaged", -"ungain", -"ungaite", -"ungaro", -"ungaudy", -"ungear", -"ungelt", -"unget", -"ungiant", -"ungiddy", -"ungild", -"ungill", -"ungilt", -"ungird", -"ungirt", -"ungirth", -"ungive", -"ungiven", -"ungka", -"unglad", -"unglaze", -"unglee", -"unglobe", -"ungloom", -"unglory", -"ungloss", -"unglove", -"unglue", -"unglued", -"ungnaw", -"ungnawn", -"ungod", -"ungodly", -"ungold", -"ungone", -"ungood", -"ungored", -"ungorge", -"ungot", -"ungouty", -"ungown", -"ungrace", -"ungraft", -"ungrain", -"ungrand", -"ungrasp", -"ungrave", -"ungreat", -"ungreen", -"ungrip", -"ungripe", -"ungross", -"ungrow", -"ungrown", -"ungruff", -"ungual", -"unguard", -"ungueal", -"unguent", -"ungues", -"unguis", -"ungula", -"ungulae", -"ungular", -"unguled", -"ungull", -"ungulp", -"ungum", -"unguyed", -"ungyve", -"ungyved", -"unhabit", -"unhad", -"unhaft", -"unhair", -"unhairy", -"unhand", -"unhandy", -"unhang", -"unhap", -"unhappy", -"unhard", -"unhardy", -"unharsh", -"unhasp", -"unhaste", -"unhasty", -"unhat", -"unhate", -"unhated", -"unhaunt", -"unhave", -"unhayed", -"unhazed", -"unhead", -"unheady", -"unheal", -"unheard", -"unheart", -"unheavy", -"unhedge", -"unheed", -"unheedy", -"unheld", -"unhele", -"unheler", -"unhelm", -"unherd", -"unhero", -"unhewed", -"unhewn", -"unhex", -"unhid", -"unhide", -"unhigh", -"unhinge", -"unhired", -"unhit", -"unhitch", -"unhive", -"unhoard", -"unhoary", -"unhoed", -"unhoist", -"unhold", -"unholy", -"unhome", -"unhoned", -"unhood", -"unhook", -"unhoop", -"unhoped", -"unhorny", -"unhorse", -"unhose", -"unhosed", -"unhot", -"unhouse", -"unhull", -"unhuman", -"unhumid", -"unhung", -"unhurt", -"unhusk", -"uniat", -"uniate", -"uniaxal", -"unible", -"unice", -"uniced", -"unicell", -"unicism", -"unicist", -"unicity", -"unicorn", -"unicum", -"unideal", -"unidle", -"unidly", -"unie", -"uniface", -"unific", -"unified", -"unifier", -"uniflow", -"uniform", -"unify", -"unilobe", -"unimped", -"uninked", -"uninn", -"unio", -"unioid", -"union", -"unioned", -"unionic", -"unionid", -"unioval", -"unipara", -"uniped", -"unipod", -"unique", -"unireme", -"unisoil", -"unison", -"unit", -"unitage", -"unital", -"unitary", -"unite", -"united", -"uniter", -"uniting", -"unition", -"unitism", -"unitive", -"unitize", -"unitude", -"unity", -"univied", -"unjaded", -"unjam", -"unjewel", -"unjoin", -"unjoint", -"unjolly", -"unjoyed", -"unjudge", -"unjuicy", -"unjust", -"unkamed", -"unked", -"unkempt", -"unken", -"unkept", -"unket", -"unkey", -"unkeyed", -"unkid", -"unkill", -"unkin", -"unkind", -"unking", -"unkink", -"unkirk", -"unkiss", -"unkist", -"unknave", -"unknew", -"unknit", -"unknot", -"unknow", -"unknown", -"unlace", -"unlaced", -"unlade", -"unladen", -"unlaid", -"unlame", -"unlamed", -"unland", -"unlap", -"unlarge", -"unlash", -"unlatch", -"unlath", -"unlaugh", -"unlaved", -"unlaw", -"unlawed", -"unlawly", -"unlay", -"unlead", -"unleaf", -"unleaky", -"unleal", -"unlean", -"unlearn", -"unleash", -"unleave", -"unled", -"unleft", -"unlegal", -"unlent", -"unless", -"unlet", -"unlevel", -"unlid", -"unlie", -"unlight", -"unlike", -"unliked", -"unliken", -"unlimb", -"unlime", -"unlimed", -"unlimp", -"unline", -"unlined", -"unlink", -"unlist", -"unlisty", -"unlit", -"unlive", -"unload", -"unloath", -"unlobed", -"unlocal", -"unlock", -"unlodge", -"unlofty", -"unlogic", -"unlook", -"unloop", -"unloose", -"unlord", -"unlost", -"unlousy", -"unlove", -"unloved", -"unlowly", -"unloyal", -"unlucid", -"unluck", -"unlucky", -"unlunar", -"unlured", -"unlust", -"unlusty", -"unlute", -"unluted", -"unlying", -"unmad", -"unmade", -"unmagic", -"unmaid", -"unmail", -"unmake", -"unmaker", -"unman", -"unmaned", -"unmanly", -"unmarch", -"unmarry", -"unmask", -"unmast", -"unmate", -"unmated", -"unmaze", -"unmeant", -"unmeek", -"unmeet", -"unmerge", -"unmerry", -"unmesh", -"unmet", -"unmeted", -"unmew", -"unmewed", -"unmind", -"unmined", -"unmired", -"unmiry", -"unmist", -"unmiter", -"unmix", -"unmixed", -"unmodel", -"unmoist", -"unmold", -"unmoldy", -"unmoor", -"unmoral", -"unmount", -"unmoved", -"unmowed", -"unmown", -"unmuddy", -"unmuted", -"unnail", -"unnaked", -"unname", -"unnamed", -"unneat", -"unneedy", -"unnegro", -"unnerve", -"unnest", -"unneth", -"unnethe", -"unnew", -"unnewly", -"unnice", -"unnigh", -"unnoble", -"unnobly", -"unnose", -"unnosed", -"unnoted", -"unnovel", -"unoared", -"unobese", -"unode", -"unoften", -"unogled", -"unoil", -"unoiled", -"unoily", -"unold", -"unoped", -"unopen", -"unorbed", -"unorder", -"unorn", -"unornly", -"unovert", -"unowed", -"unowing", -"unown", -"unowned", -"unpaced", -"unpack", -"unpagan", -"unpaged", -"unpaid", -"unpaint", -"unpale", -"unpaled", -"unpanel", -"unpapal", -"unpaper", -"unparch", -"unpared", -"unpark", -"unparty", -"unpass", -"unpaste", -"unpave", -"unpaved", -"unpawed", -"unpawn", -"unpeace", -"unpeel", -"unpeg", -"unpen", -"unpenal", -"unpent", -"unperch", -"unpetal", -"unpick", -"unpiece", -"unpiety", -"unpile", -"unpiled", -"unpin", -"unpious", -"unpiped", -"unplace", -"unplaid", -"unplain", -"unplait", -"unplan", -"unplank", -"unplant", -"unplat", -"unpleat", -"unplied", -"unplow", -"unplug", -"unplumb", -"unplume", -"unplump", -"unpoise", -"unpoled", -"unpope", -"unposed", -"unpot", -"unpower", -"unpray", -"unprim", -"unprime", -"unprint", -"unprop", -"unproud", -"unpure", -"unpurse", -"unput", -"unqueen", -"unquick", -"unquiet", -"unquit", -"unquote", -"unraced", -"unrack", -"unrainy", -"unrake", -"unraked", -"unram", -"unrank", -"unraped", -"unrare", -"unrash", -"unrated", -"unravel", -"unray", -"unrayed", -"unrazed", -"unread", -"unready", -"unreal", -"unreave", -"unrebel", -"unred", -"unreel", -"unreeve", -"unregal", -"unrein", -"unrent", -"unrest", -"unresty", -"unrhyme", -"unrich", -"unricht", -"unrid", -"unride", -"unrife", -"unrig", -"unright", -"unrigid", -"unrind", -"unring", -"unrip", -"unripe", -"unriped", -"unrisen", -"unrisky", -"unrived", -"unriven", -"unrivet", -"unroast", -"unrobe", -"unrobed", -"unroll", -"unroof", -"unroomy", -"unroost", -"unroot", -"unrope", -"unroped", -"unrosed", -"unroted", -"unrough", -"unround", -"unrove", -"unroved", -"unrow", -"unrowed", -"unroyal", -"unrule", -"unruled", -"unruly", -"unrun", -"unrung", -"unrural", -"unrust", -"unruth", -"unsack", -"unsad", -"unsafe", -"unsage", -"unsaid", -"unsaint", -"unsalt", -"unsane", -"unsappy", -"unsash", -"unsated", -"unsatin", -"unsaved", -"unsawed", -"unsawn", -"unsay", -"unscale", -"unscaly", -"unscarb", -"unscent", -"unscrew", -"unseal", -"unseam", -"unseat", -"unsee", -"unseen", -"unself", -"unsense", -"unsent", -"unset", -"unsew", -"unsewed", -"unsewn", -"unsex", -"unsexed", -"unshade", -"unshady", -"unshape", -"unsharp", -"unshawl", -"unsheaf", -"unshed", -"unsheet", -"unshell", -"unship", -"unshod", -"unshoe", -"unshoed", -"unshop", -"unshore", -"unshorn", -"unshort", -"unshot", -"unshown", -"unshowy", -"unshrew", -"unshut", -"unshy", -"unshyly", -"unsick", -"unsided", -"unsiege", -"unsight", -"unsilly", -"unsin", -"unsinew", -"unsing", -"unsized", -"unskin", -"unslack", -"unslain", -"unslate", -"unslave", -"unsleek", -"unslept", -"unsling", -"unslip", -"unslit", -"unslot", -"unslow", -"unslung", -"unsly", -"unsmart", -"unsmoky", -"unsmote", -"unsnaky", -"unsnap", -"unsnare", -"unsnarl", -"unsneck", -"unsnib", -"unsnow", -"unsober", -"unsoft", -"unsoggy", -"unsoil", -"unsolar", -"unsold", -"unsole", -"unsoled", -"unsolid", -"unsome", -"unson", -"unsonsy", -"unsooty", -"unsore", -"unsorry", -"unsort", -"unsoul", -"unsound", -"unsour", -"unsowed", -"unsown", -"unspan", -"unspar", -"unspeak", -"unsped", -"unspeed", -"unspell", -"unspelt", -"unspent", -"unspicy", -"unspied", -"unspike", -"unspin", -"unspit", -"unsplit", -"unspoil", -"unspot", -"unspun", -"unstack", -"unstagy", -"unstaid", -"unstain", -"unstar", -"unstate", -"unsteck", -"unsteel", -"unsteep", -"unstep", -"unstern", -"unstick", -"unstill", -"unsting", -"unstock", -"unstoic", -"unstone", -"unstony", -"unstop", -"unstore", -"unstout", -"unstow", -"unstrap", -"unstrip", -"unstuck", -"unstuff", -"unstung", -"unsty", -"unsued", -"unsuit", -"unsulky", -"unsun", -"unsung", -"unsunk", -"unsunny", -"unsure", -"unswear", -"unsweat", -"unsweet", -"unswell", -"unswept", -"unswing", -"unsworn", -"unswung", -"untack", -"untaint", -"untaken", -"untall", -"untame", -"untamed", -"untap", -"untaped", -"untar", -"untaste", -"untasty", -"untaut", -"untawed", -"untax", -"untaxed", -"unteach", -"unteam", -"unteem", -"untell", -"untense", -"untent", -"untenty", -"untewed", -"unthank", -"unthaw", -"unthick", -"unthink", -"unthorn", -"unthrid", -"unthrob", -"untidal", -"untidy", -"untie", -"untied", -"untight", -"until", -"untile", -"untiled", -"untill", -"untilt", -"untimed", -"untin", -"untinct", -"untine", -"untipt", -"untire", -"untired", -"unto", -"untold", -"untomb", -"untone", -"untoned", -"untooth", -"untop", -"untorn", -"untouch", -"untough", -"untown", -"untrace", -"untrain", -"untread", -"untreed", -"untress", -"untried", -"untrig", -"untrill", -"untrim", -"untripe", -"untrite", -"untrod", -"untruck", -"untrue", -"untruly", -"untruss", -"untrust", -"untruth", -"untuck", -"untumid", -"untune", -"untuned", -"unturf", -"unturn", -"untwine", -"untwirl", -"untwist", -"untying", -"untz", -"unugly", -"unultra", -"unupset", -"unurban", -"unurged", -"unurn", -"unurned", -"unuse", -"unused", -"unusual", -"unvain", -"unvalid", -"unvalue", -"unveil", -"unvenom", -"unvest", -"unvexed", -"unvicar", -"unvisor", -"unvital", -"unvivid", -"unvocal", -"unvoice", -"unvote", -"unvoted", -"unvowed", -"unwaded", -"unwaged", -"unwaked", -"unwall", -"unwan", -"unware", -"unwarm", -"unwarn", -"unwarp", -"unwary", -"unwater", -"unwaved", -"unwax", -"unwaxed", -"unwayed", -"unweal", -"unweary", -"unweave", -"unweb", -"unwed", -"unwedge", -"unweel", -"unweft", -"unweld", -"unwell", -"unwept", -"unwet", -"unwheel", -"unwhig", -"unwhip", -"unwhite", -"unwield", -"unwifed", -"unwig", -"unwild", -"unwill", -"unwily", -"unwind", -"unwindy", -"unwiped", -"unwire", -"unwired", -"unwise", -"unwish", -"unwist", -"unwitch", -"unwitty", -"unwive", -"unwived", -"unwoful", -"unwoman", -"unwomb", -"unwon", -"unwooed", -"unwoof", -"unwooly", -"unwordy", -"unwork", -"unworld", -"unwormy", -"unworn", -"unworth", -"unwound", -"unwoven", -"unwrap", -"unwrit", -"unwrite", -"unwrung", -"unyoke", -"unyoked", -"unyoung", -"unze", -"unzen", -"unzone", -"unzoned", -"up", -"upaisle", -"upalley", -"upalong", -"uparch", -"uparise", -"uparm", -"uparna", -"upas", -"upattic", -"upbank", -"upbar", -"upbay", -"upbear", -"upbeat", -"upbelch", -"upbelt", -"upbend", -"upbid", -"upbind", -"upblast", -"upblaze", -"upblow", -"upboil", -"upbolt", -"upboost", -"upborne", -"upbotch", -"upbound", -"upbrace", -"upbraid", -"upbray", -"upbreak", -"upbred", -"upbreed", -"upbrim", -"upbring", -"upbrook", -"upbrow", -"upbuild", -"upbuoy", -"upburn", -"upburst", -"upbuy", -"upcall", -"upcanal", -"upcarry", -"upcast", -"upcatch", -"upchoke", -"upchuck", -"upcity", -"upclimb", -"upclose", -"upcoast", -"upcock", -"upcoil", -"upcome", -"upcover", -"upcrane", -"upcrawl", -"upcreek", -"upcreep", -"upcrop", -"upcrowd", -"upcry", -"upcurl", -"upcurve", -"upcut", -"updart", -"update", -"updeck", -"updelve", -"updive", -"updo", -"updome", -"updraft", -"updrag", -"updraw", -"updrink", -"updry", -"upeat", -"upend", -"upeygan", -"upfeed", -"upfield", -"upfill", -"upflame", -"upflare", -"upflash", -"upflee", -"upfling", -"upfloat", -"upflood", -"upflow", -"upflung", -"upfly", -"upfold", -"upframe", -"upfurl", -"upgale", -"upgang", -"upgape", -"upgaze", -"upget", -"upgird", -"upgirt", -"upgive", -"upglean", -"upglide", -"upgo", -"upgorge", -"upgrade", -"upgrave", -"upgrow", -"upgully", -"upgush", -"uphand", -"uphang", -"uphasp", -"upheal", -"upheap", -"upheave", -"upheld", -"uphelm", -"uphelya", -"upher", -"uphill", -"uphoard", -"uphoist", -"uphold", -"uphung", -"uphurl", -"upjerk", -"upjet", -"upkeep", -"upknell", -"upknit", -"upla", -"uplaid", -"uplake", -"upland", -"uplane", -"uplay", -"uplead", -"upleap", -"upleg", -"uplick", -"uplift", -"uplight", -"uplimb", -"upline", -"uplock", -"uplong", -"uplook", -"uploom", -"uploop", -"uplying", -"upmast", -"upmix", -"upmost", -"upmount", -"upmove", -"upness", -"upo", -"upon", -"uppard", -"uppent", -"upper", -"upperch", -"upperer", -"uppers", -"uppile", -"upping", -"uppish", -"uppity", -"upplow", -"uppluck", -"uppoint", -"uppoise", -"uppop", -"uppour", -"uppowoc", -"upprick", -"upprop", -"uppuff", -"uppull", -"uppush", -"upraise", -"upreach", -"uprear", -"uprein", -"uprend", -"uprest", -"uprid", -"upridge", -"upright", -"uprip", -"uprisal", -"uprise", -"uprisen", -"upriser", -"uprist", -"uprive", -"upriver", -"uproad", -"uproar", -"uproom", -"uproot", -"uprose", -"uprouse", -"uproute", -"uprun", -"uprush", -"upscale", -"upscrew", -"upseal", -"upseek", -"upseize", -"upsend", -"upset", -"upsey", -"upshaft", -"upshear", -"upshoot", -"upshore", -"upshot", -"upshove", -"upshut", -"upside", -"upsides", -"upsilon", -"upsit", -"upslant", -"upslip", -"upslope", -"upsmite", -"upsoak", -"upsoar", -"upsolve", -"upspeak", -"upspear", -"upspeed", -"upspew", -"upspin", -"upspire", -"upspout", -"upspurt", -"upstaff", -"upstage", -"upstair", -"upstamp", -"upstand", -"upstare", -"upstart", -"upstate", -"upstay", -"upsteal", -"upsteam", -"upstem", -"upstep", -"upstick", -"upstir", -"upsuck", -"upsun", -"upsup", -"upsurge", -"upswarm", -"upsway", -"upsweep", -"upswell", -"upswing", -"uptable", -"uptake", -"uptaker", -"uptear", -"uptend", -"upthrow", -"uptide", -"uptie", -"uptill", -"uptilt", -"uptorn", -"uptoss", -"uptower", -"uptown", -"uptrace", -"uptrack", -"uptrail", -"uptrain", -"uptree", -"uptrend", -"uptrill", -"uptrunk", -"uptruss", -"uptube", -"uptuck", -"upturn", -"uptwist", -"upupoid", -"upvomit", -"upwaft", -"upwall", -"upward", -"upwards", -"upwarp", -"upwax", -"upway", -"upways", -"upwell", -"upwent", -"upwheel", -"upwhelm", -"upwhir", -"upwhirl", -"upwind", -"upwith", -"upwork", -"upwound", -"upwrap", -"upwring", -"upyard", -"upyoke", -"ur", -"ura", -"urachal", -"urachus", -"uracil", -"uraemic", -"uraeus", -"ural", -"urali", -"uraline", -"uralite", -"uralium", -"uramido", -"uramil", -"uramino", -"uran", -"uranate", -"uranic", -"uraniid", -"uranin", -"uranine", -"uranion", -"uranism", -"uranist", -"uranite", -"uranium", -"uranous", -"uranyl", -"urao", -"urare", -"urari", -"urase", -"urate", -"uratic", -"uratoma", -"urazine", -"urazole", -"urban", -"urbane", -"urbian", -"urbic", -"urbify", -"urceole", -"urceoli", -"urceus", -"urchin", -"urd", -"urde", -"urdee", -"ure", -"urea", -"ureal", -"urease", -"uredema", -"uredine", -"uredo", -"ureic", -"ureid", -"ureide", -"ureido", -"uremia", -"uremic", -"urent", -"uresis", -"uretal", -"ureter", -"urethan", -"urethra", -"uretic", -"urf", -"urge", -"urgence", -"urgency", -"urgent", -"urger", -"urging", -"urheen", -"urial", -"uric", -"urinal", -"urinant", -"urinary", -"urinate", -"urine", -"urinose", -"urinous", -"urite", -"urlar", -"urled", -"urling", -"urluch", -"urman", -"urn", -"urna", -"urnae", -"urnal", -"urnful", -"urning", -"urnism", -"urnlike", -"urocele", -"urocyst", -"urodele", -"urogram", -"urohyal", -"urolith", -"urology", -"uromere", -"uronic", -"uropod", -"urosis", -"urosome", -"urostea", -"urotoxy", -"uroxin", -"ursal", -"ursine", -"ursoid", -"ursolic", -"urson", -"ursone", -"ursuk", -"urtica", -"urtite", -"urubu", -"urucu", -"urucuri", -"uruisg", -"urunday", -"urus", -"urushi", -"urushic", -"urva", -"us", -"usable", -"usage", -"usager", -"usance", -"usar", -"usara", -"usaron", -"usation", -"use", -"used", -"usedly", -"usednt", -"usee", -"useful", -"usehold", -"useless", -"usent", -"user", -"ush", -"ushabti", -"usher", -"usherer", -"usings", -"usitate", -"usnea", -"usneoid", -"usnic", -"usninic", -"usque", -"usself", -"ussels", -"ust", -"uster", -"ustion", -"usual", -"usually", -"usuary", -"usucapt", -"usure", -"usurer", -"usuress", -"usurp", -"usurper", -"usurpor", -"usury", -"usward", -"uswards", -"ut", -"uta", -"utahite", -"utai", -"utas", -"utch", -"utchy", -"utees", -"utensil", -"uteri", -"uterine", -"uterus", -"utick", -"utile", -"utility", -"utilize", -"utinam", -"utmost", -"utopia", -"utopian", -"utopism", -"utopist", -"utricle", -"utricul", -"utrubi", -"utrum", -"utsuk", -"utter", -"utterer", -"utterly", -"utu", -"utum", -"uva", -"uval", -"uvalha", -"uvanite", -"uvate", -"uvea", -"uveal", -"uveitic", -"uveitis", -"uveous", -"uvic", -"uvid", -"uviol", -"uvitic", -"uvito", -"uvrou", -"uvula", -"uvulae", -"uvular", -"uvver", -"uxorial", -"uzan", -"uzara", -"uzarin", -"uzaron", -"v", -"vaagmer", -"vaalite", -"vacancy", -"vacant", -"vacate", -"vacatur", -"vaccary", -"vaccina", -"vaccine", -"vache", -"vacoa", -"vacona", -"vacoua", -"vacouf", -"vacual", -"vacuate", -"vacuefy", -"vacuist", -"vacuity", -"vacuole", -"vacuome", -"vacuous", -"vacuum", -"vacuuma", -"vade", -"vadium", -"vadose", -"vady", -"vag", -"vagal", -"vagary", -"vagas", -"vage", -"vagile", -"vagina", -"vaginal", -"vagitus", -"vagrant", -"vagrate", -"vagrom", -"vague", -"vaguely", -"vaguish", -"vaguity", -"vagus", -"vahine", -"vail", -"vain", -"vainful", -"vainly", -"vair", -"vairagi", -"vaire", -"vairy", -"vaivode", -"vajra", -"vakass", -"vakia", -"vakil", -"valance", -"vale", -"valence", -"valency", -"valent", -"valeral", -"valeric", -"valerin", -"valeryl", -"valet", -"valeta", -"valetry", -"valeur", -"valgoid", -"valgus", -"valhall", -"vali", -"valiant", -"valid", -"validly", -"valine", -"valise", -"vall", -"vallar", -"vallary", -"vallate", -"valley", -"vallis", -"vallum", -"valonia", -"valor", -"valse", -"valsoid", -"valuate", -"value", -"valued", -"valuer", -"valuta", -"valva", -"valval", -"valvate", -"valve", -"valved", -"valvula", -"valvule", -"valyl", -"vamfont", -"vamoose", -"vamp", -"vamped", -"vamper", -"vampire", -"van", -"vanadic", -"vanadyl", -"vane", -"vaned", -"vanfoss", -"vang", -"vangee", -"vangeli", -"vanglo", -"vanilla", -"vanille", -"vanish", -"vanity", -"vanman", -"vanmost", -"vanner", -"vannet", -"vansire", -"vantage", -"vanward", -"vapid", -"vapidly", -"vapor", -"vapored", -"vaporer", -"vapory", -"vara", -"varahan", -"varan", -"varanid", -"vardy", -"vare", -"varec", -"vareuse", -"vari", -"variant", -"variate", -"varical", -"varices", -"varied", -"varier", -"variety", -"variola", -"variole", -"various", -"varisse", -"varix", -"varlet", -"varment", -"varna", -"varnish", -"varsha", -"varsity", -"varus", -"varve", -"varved", -"vary", -"vas", -"vasa", -"vasal", -"vase", -"vaseful", -"vaselet", -"vassal", -"vast", -"vastate", -"vastily", -"vastity", -"vastly", -"vasty", -"vasu", -"vat", -"vatful", -"vatic", -"vatman", -"vatter", -"vau", -"vaudy", -"vault", -"vaulted", -"vaulter", -"vaulty", -"vaunt", -"vaunted", -"vaunter", -"vaunty", -"vauxite", -"vavasor", -"vaward", -"veal", -"vealer", -"vealy", -"vection", -"vectis", -"vector", -"vecture", -"vedana", -"vedette", -"vedika", -"vedro", -"veduis", -"vee", -"veen", -"veep", -"veer", -"veery", -"vegetal", -"vegete", -"vehicle", -"vei", -"veigle", -"veil", -"veiled", -"veiler", -"veiling", -"veily", -"vein", -"veinage", -"veinal", -"veined", -"veiner", -"veinery", -"veining", -"veinlet", -"veinous", -"veinule", -"veiny", -"vejoces", -"vela", -"velal", -"velamen", -"velar", -"velaric", -"velary", -"velate", -"velated", -"veldman", -"veldt", -"velic", -"veliger", -"vell", -"vellala", -"velleda", -"vellon", -"vellum", -"vellumy", -"velo", -"velours", -"velte", -"velum", -"velumen", -"velure", -"velvet", -"velvety", -"venada", -"venal", -"venally", -"venatic", -"venator", -"vencola", -"vend", -"vendace", -"vendee", -"vender", -"vending", -"vendor", -"vendue", -"veneer", -"venene", -"veneral", -"venerer", -"venery", -"venesia", -"venger", -"venial", -"venie", -"venin", -"venison", -"vennel", -"venner", -"venom", -"venomed", -"venomer", -"venomly", -"venomy", -"venosal", -"venose", -"venous", -"vent", -"ventage", -"ventail", -"venter", -"ventil", -"ventose", -"ventrad", -"ventral", -"ventric", -"venture", -"venue", -"venula", -"venular", -"venule", -"venust", -"vera", -"veranda", -"verb", -"verbal", -"verbate", -"verbena", -"verbene", -"verbid", -"verbify", -"verbile", -"verbose", -"verbous", -"verby", -"verchok", -"verd", -"verdant", -"verdea", -"verdet", -"verdict", -"verdin", -"verdoy", -"verdun", -"verdure", -"verek", -"verge", -"vergent", -"verger", -"vergery", -"vergi", -"verglas", -"veri", -"veridic", -"verify", -"verily", -"verine", -"verism", -"verist", -"verite", -"verity", -"vermeil", -"vermian", -"vermin", -"verminy", -"vermis", -"vermix", -"vernal", -"vernant", -"vernier", -"vernile", -"vernin", -"vernine", -"verre", -"verrel", -"verruca", -"verruga", -"versal", -"versant", -"versate", -"verse", -"versed", -"verser", -"verset", -"versify", -"versine", -"version", -"verso", -"versor", -"verst", -"versta", -"versual", -"versus", -"vert", -"vertex", -"vertigo", -"veruled", -"vervain", -"verve", -"vervel", -"vervet", -"very", -"vesania", -"vesanic", -"vesbite", -"vesicae", -"vesical", -"vesicle", -"veskit", -"vespal", -"vesper", -"vespers", -"vespery", -"vespid", -"vespine", -"vespoid", -"vessel", -"vest", -"vestal", -"vestee", -"vester", -"vestige", -"vesting", -"vestlet", -"vestral", -"vestry", -"vesture", -"vet", -"veta", -"vetanda", -"vetch", -"vetchy", -"veteran", -"vetiver", -"veto", -"vetoer", -"vetoism", -"vetoist", -"vetust", -"vetusty", -"veuve", -"vex", -"vexable", -"vexed", -"vexedly", -"vexer", -"vexful", -"vexil", -"vext", -"via", -"viable", -"viaduct", -"viagram", -"viajaca", -"vial", -"vialful", -"viand", -"viander", -"viatic", -"viatica", -"viator", -"vibex", -"vibgyor", -"vibix", -"vibrant", -"vibrate", -"vibrato", -"vibrion", -"vicar", -"vicarly", -"vice", -"viceroy", -"vicety", -"vicilin", -"vicinal", -"vicine", -"vicious", -"vicoite", -"victim", -"victor", -"victory", -"victrix", -"victual", -"vicuna", -"viddui", -"video", -"vidette", -"vidonia", -"vidry", -"viduage", -"vidual", -"viduate", -"viduine", -"viduity", -"viduous", -"vidya", -"vie", -"vielle", -"vier", -"viertel", -"view", -"viewer", -"viewly", -"viewy", -"vifda", -"viga", -"vigia", -"vigil", -"vignin", -"vigonia", -"vigor", -"vihara", -"vihuela", -"vijao", -"viking", -"vila", -"vilayet", -"vile", -"vilely", -"vilify", -"vility", -"vill", -"villa", -"village", -"villain", -"villar", -"villate", -"ville", -"villein", -"villoid", -"villose", -"villous", -"villus", -"vim", -"vimana", -"vimen", -"vimful", -"viminal", -"vina", -"vinage", -"vinal", -"vinasse", -"vinata", -"vincent", -"vindex", -"vine", -"vinea", -"vineal", -"vined", -"vinegar", -"vineity", -"vinelet", -"viner", -"vinery", -"vinic", -"vinny", -"vino", -"vinose", -"vinous", -"vint", -"vinta", -"vintage", -"vintem", -"vintner", -"vintry", -"viny", -"vinyl", -"vinylic", -"viol", -"viola", -"violal", -"violate", -"violent", -"violer", -"violet", -"violety", -"violin", -"violina", -"violine", -"violist", -"violon", -"violone", -"viper", -"viperan", -"viperid", -"vipery", -"viqueen", -"viragin", -"virago", -"viral", -"vire", -"virelay", -"viremia", -"viremic", -"virent", -"vireo", -"virga", -"virgal", -"virgate", -"virgin", -"virgula", -"virgule", -"virial", -"virid", -"virific", -"virify", -"virile", -"virl", -"virole", -"viroled", -"viron", -"virose", -"virosis", -"virous", -"virtu", -"virtual", -"virtue", -"virtued", -"viruela", -"virus", -"vis", -"visa", -"visage", -"visaged", -"visarga", -"viscera", -"viscid", -"viscin", -"viscose", -"viscous", -"viscus", -"vise", -"viseman", -"visible", -"visibly", -"visie", -"visile", -"vision", -"visit", -"visita", -"visite", -"visitee", -"visiter", -"visitor", -"visive", -"visne", -"vison", -"visor", -"vista", -"vistaed", -"vistal", -"visto", -"visual", -"vita", -"vital", -"vitalic", -"vitally", -"vitals", -"vitamer", -"vitamin", -"vitasti", -"vitiate", -"vitium", -"vitrage", -"vitrail", -"vitrain", -"vitraux", -"vitreal", -"vitrean", -"vitreum", -"vitric", -"vitrics", -"vitrify", -"vitrine", -"vitriol", -"vitrite", -"vitrous", -"vitta", -"vittate", -"vitular", -"viuva", -"viva", -"vivary", -"vivax", -"vive", -"vively", -"vivency", -"viver", -"vivers", -"vives", -"vivid", -"vividly", -"vivific", -"vivify", -"vixen", -"vixenly", -"vizard", -"vizier", -"vlei", -"voar", -"vocable", -"vocably", -"vocal", -"vocalic", -"vocally", -"vocate", -"vocular", -"vocule", -"vodka", -"voe", -"voet", -"voeten", -"vog", -"voglite", -"vogue", -"voguey", -"voguish", -"voice", -"voiced", -"voicer", -"voicing", -"void", -"voided", -"voidee", -"voider", -"voiding", -"voidly", -"voile", -"voivode", -"vol", -"volable", -"volage", -"volant", -"volar", -"volata", -"volatic", -"volcan", -"volcano", -"vole", -"volency", -"volent", -"volery", -"volet", -"volley", -"volost", -"volt", -"voltage", -"voltaic", -"voltize", -"voluble", -"volubly", -"volume", -"volumed", -"volupt", -"volupty", -"voluta", -"volute", -"voluted", -"volutin", -"volva", -"volvate", -"volvent", -"vomer", -"vomica", -"vomit", -"vomiter", -"vomito", -"vomitus", -"voodoo", -"vorago", -"vorant", -"vorhand", -"vorpal", -"vortex", -"vota", -"votable", -"votal", -"votally", -"votary", -"vote", -"voteen", -"voter", -"voting", -"votive", -"votress", -"vouch", -"vouchee", -"voucher", -"vouge", -"vow", -"vowed", -"vowel", -"vowely", -"vower", -"vowess", -"vowless", -"voyage", -"voyager", -"voyance", -"voyeur", -"vraic", -"vrbaite", -"vriddhi", -"vrother", -"vug", -"vuggy", -"vulgar", -"vulgare", -"vulgate", -"vulgus", -"vuln", -"vulnose", -"vulpic", -"vulpine", -"vulture", -"vulturn", -"vulva", -"vulval", -"vulvar", -"vulvate", -"vum", -"vying", -"vyingly", -"w", -"wa", -"waag", -"waapa", -"waar", -"wab", -"wabber", -"wabble", -"wabbly", -"wabby", -"wabe", -"wabeno", -"wabster", -"wacago", -"wace", -"wachna", -"wack", -"wacke", -"wacken", -"wacker", -"wacky", -"wad", -"waddent", -"wadder", -"wadding", -"waddler", -"waddly", -"waddy", -"wade", -"wader", -"wadi", -"wading", -"wadlike", -"wadmal", -"wadmeal", -"wadna", -"wadset", -"wae", -"waeg", -"waer", -"waesome", -"waesuck", -"wafer", -"waferer", -"wafery", -"waff", -"waffle", -"waffly", -"waft", -"waftage", -"wafter", -"wafture", -"wafty", -"wag", -"wagaun", -"wage", -"waged", -"wagedom", -"wager", -"wagerer", -"wages", -"waggel", -"wagger", -"waggery", -"waggie", -"waggish", -"waggle", -"waggly", -"waggy", -"waglike", -"wagling", -"wagon", -"wagoner", -"wagonry", -"wagsome", -"wagtail", -"wagwag", -"wagwit", -"wah", -"wahahe", -"wahine", -"wahoo", -"waiata", -"waif", -"waik", -"waikly", -"wail", -"wailer", -"wailful", -"waily", -"wain", -"wainage", -"wainer", -"wainful", -"wainman", -"waipiro", -"wairch", -"waird", -"wairepo", -"wairsh", -"waise", -"waist", -"waisted", -"waister", -"wait", -"waiter", -"waiting", -"waive", -"waiver", -"waivery", -"waivod", -"waiwode", -"wajang", -"waka", -"wakan", -"wake", -"wakeel", -"wakeful", -"waken", -"wakener", -"waker", -"wakes", -"wakf", -"wakif", -"wakiki", -"waking", -"wakiup", -"wakken", -"wakon", -"wakonda", -"waky", -"walahee", -"wale", -"waled", -"waler", -"wali", -"waling", -"walk", -"walker", -"walking", -"walkist", -"walkout", -"walkway", -"wall", -"wallaba", -"wallaby", -"wallah", -"walled", -"waller", -"wallet", -"walleye", -"wallful", -"walling", -"wallise", -"wallman", -"walloon", -"wallop", -"wallow", -"wally", -"walnut", -"walrus", -"walsh", -"walt", -"walter", -"walth", -"waltz", -"waltzer", -"wamara", -"wambais", -"wamble", -"wambly", -"wame", -"wamefou", -"wamel", -"wamp", -"wampee", -"wample", -"wampum", -"wampus", -"wamus", -"wan", -"wand", -"wander", -"wandery", -"wandle", -"wandoo", -"wandy", -"wane", -"waned", -"wang", -"wanga", -"wangala", -"wangan", -"wanghee", -"wangle", -"wangler", -"wanhope", -"wanhorn", -"wanigan", -"waning", -"wankle", -"wankly", -"wanle", -"wanly", -"wanner", -"wanness", -"wannish", -"wanny", -"wanrufe", -"want", -"wantage", -"wanter", -"wantful", -"wanting", -"wanton", -"wantwit", -"wanty", -"wany", -"wap", -"wapacut", -"wapatoo", -"wapiti", -"wapp", -"wapper", -"wapping", -"war", -"warabi", -"waratah", -"warble", -"warbled", -"warbler", -"warblet", -"warbly", -"warch", -"ward", -"wardage", -"warday", -"warded", -"warden", -"warder", -"warding", -"wardite", -"wardman", -"ware", -"warehou", -"wareman", -"warf", -"warfare", -"warful", -"warily", -"warish", -"warison", -"wark", -"warl", -"warless", -"warlike", -"warlock", -"warluck", -"warly", -"warm", -"warman", -"warmed", -"warmer", -"warmful", -"warming", -"warmish", -"warmly", -"warmth", -"warmus", -"warn", -"warnel", -"warner", -"warning", -"warnish", -"warnoth", -"warnt", -"warp", -"warpage", -"warped", -"warper", -"warping", -"warple", -"warran", -"warrand", -"warrant", -"warree", -"warren", -"warrer", -"warrin", -"warrior", -"warrok", -"warsaw", -"warse", -"warsel", -"warship", -"warsle", -"warsler", -"warst", -"wart", -"warted", -"wartern", -"warth", -"wartime", -"wartlet", -"warty", -"warve", -"warwolf", -"warworn", -"wary", -"was", -"wasabi", -"wase", -"wasel", -"wash", -"washday", -"washed", -"washen", -"washer", -"washery", -"washin", -"washing", -"washman", -"washoff", -"washout", -"washpot", -"washrag", -"washtub", -"washway", -"washy", -"wasnt", -"wasp", -"waspen", -"waspily", -"waspish", -"waspy", -"wassail", -"wassie", -"wast", -"wastage", -"waste", -"wasted", -"wastel", -"waster", -"wasting", -"wastrel", -"wasty", -"wat", -"watap", -"watch", -"watched", -"watcher", -"water", -"watered", -"waterer", -"waterie", -"watery", -"wath", -"watt", -"wattage", -"wattape", -"wattle", -"wattled", -"wattman", -"wauble", -"wauch", -"wauchle", -"waucht", -"wauf", -"waugh", -"waughy", -"wauken", -"waukit", -"waul", -"waumle", -"wauner", -"wauns", -"waup", -"waur", -"wauve", -"wavable", -"wavably", -"wave", -"waved", -"wavelet", -"waver", -"waverer", -"wavery", -"waveson", -"wavey", -"wavicle", -"wavily", -"waving", -"wavy", -"waw", -"wawa", -"wawah", -"wax", -"waxbill", -"waxbird", -"waxbush", -"waxen", -"waxer", -"waxily", -"waxing", -"waxlike", -"waxman", -"waxweed", -"waxwing", -"waxwork", -"waxy", -"way", -"wayaka", -"wayang", -"wayback", -"waybill", -"waybird", -"waybook", -"waybung", -"wayfare", -"waygang", -"waygate", -"waygone", -"waying", -"waylaid", -"waylay", -"wayless", -"wayman", -"waymark", -"waymate", -"waypost", -"ways", -"wayside", -"wayward", -"waywode", -"wayworn", -"waywort", -"we", -"weak", -"weaken", -"weakish", -"weakly", -"weaky", -"weal", -"weald", -"wealth", -"wealthy", -"weam", -"wean", -"weanel", -"weaner", -"weanyer", -"weapon", -"wear", -"wearer", -"wearied", -"wearier", -"wearily", -"wearing", -"wearish", -"weary", -"weasand", -"weasel", -"weaser", -"weason", -"weather", -"weave", -"weaved", -"weaver", -"weaving", -"weazen", -"weazeny", -"web", -"webbed", -"webber", -"webbing", -"webby", -"weber", -"webeye", -"webfoot", -"webless", -"weblike", -"webster", -"webwork", -"webworm", -"wecht", -"wed", -"wedana", -"wedbed", -"wedded", -"wedder", -"wedding", -"wede", -"wedge", -"wedged", -"wedger", -"wedging", -"wedgy", -"wedlock", -"wedset", -"wee", -"weeble", -"weed", -"weeda", -"weedage", -"weeded", -"weeder", -"weedery", -"weedful", -"weedish", -"weedow", -"weedy", -"week", -"weekday", -"weekend", -"weekly", -"weekwam", -"weel", -"weemen", -"ween", -"weeness", -"weening", -"weenong", -"weeny", -"weep", -"weeper", -"weepful", -"weeping", -"weeps", -"weepy", -"weesh", -"weeshy", -"weet", -"weever", -"weevil", -"weevily", -"weewow", -"weeze", -"weft", -"weftage", -"wefted", -"wefty", -"weigh", -"weighed", -"weigher", -"weighin", -"weight", -"weighty", -"weir", -"weird", -"weirdly", -"weiring", -"weism", -"wejack", -"weka", -"wekau", -"wekeen", -"weki", -"welcome", -"weld", -"welder", -"welding", -"weldor", -"welfare", -"welk", -"welkin", -"well", -"wellat", -"welling", -"wellish", -"wellman", -"welly", -"wels", -"welsh", -"welsher", -"welsium", -"welt", -"welted", -"welter", -"welting", -"wem", -"wemless", -"wen", -"wench", -"wencher", -"wend", -"wende", -"wene", -"wennish", -"wenny", -"went", -"wenzel", -"wept", -"wer", -"were", -"werefox", -"werent", -"werf", -"wergil", -"weri", -"wert", -"wervel", -"wese", -"weskit", -"west", -"weste", -"wester", -"western", -"westing", -"westy", -"wet", -"weta", -"wetback", -"wetbird", -"wetched", -"wetchet", -"wether", -"wetly", -"wetness", -"wetted", -"wetter", -"wetting", -"wettish", -"weve", -"wevet", -"wey", -"wha", -"whabby", -"whack", -"whacker", -"whacky", -"whale", -"whaler", -"whalery", -"whaling", -"whalish", -"whally", -"whalm", -"whalp", -"whaly", -"wham", -"whamble", -"whame", -"whammle", -"whamp", -"whampee", -"whample", -"whan", -"whand", -"whang", -"whangam", -"whangee", -"whank", -"whap", -"whappet", -"whapuka", -"whapuku", -"whar", -"whare", -"whareer", -"wharf", -"wharl", -"wharp", -"wharry", -"whart", -"wharve", -"whase", -"whasle", -"what", -"whata", -"whatkin", -"whatna", -"whatnot", -"whats", -"whatso", -"whatten", -"whau", -"whauk", -"whaup", -"whaur", -"whauve", -"wheal", -"whealy", -"wheam", -"wheat", -"wheaten", -"wheaty", -"whedder", -"whee", -"wheedle", -"wheel", -"wheeled", -"wheeler", -"wheely", -"wheem", -"wheen", -"wheenge", -"wheep", -"wheeple", -"wheer", -"wheesht", -"wheetle", -"wheeze", -"wheezer", -"wheezle", -"wheezy", -"wheft", -"whein", -"whekau", -"wheki", -"whelk", -"whelked", -"whelker", -"whelky", -"whelm", -"whelp", -"whelve", -"whemmel", -"when", -"whenas", -"whence", -"wheneer", -"whenso", -"where", -"whereas", -"whereat", -"whereby", -"whereer", -"wherein", -"whereof", -"whereon", -"whereso", -"whereto", -"whereup", -"wherret", -"wherrit", -"wherry", -"whet", -"whether", -"whetile", -"whetter", -"whew", -"whewer", -"whewl", -"whewt", -"whey", -"wheyey", -"wheyish", -"whiba", -"which", -"whick", -"whicken", -"whicker", -"whid", -"whidah", -"whidder", -"whiff", -"whiffer", -"whiffet", -"whiffle", -"whiffy", -"whift", -"whig", -"while", -"whileen", -"whilere", -"whiles", -"whilie", -"whilk", -"whill", -"whilly", -"whilock", -"whilom", -"whils", -"whilst", -"whilter", -"whim", -"whimble", -"whimmy", -"whimper", -"whimsey", -"whimsic", -"whin", -"whincow", -"whindle", -"whine", -"whiner", -"whing", -"whinge", -"whinger", -"whinnel", -"whinner", -"whinny", -"whiny", -"whip", -"whipcat", -"whipman", -"whippa", -"whipped", -"whipper", -"whippet", -"whippy", -"whipsaw", -"whipt", -"whir", -"whirken", -"whirl", -"whirled", -"whirler", -"whirley", -"whirly", -"whirret", -"whirrey", -"whirroo", -"whirry", -"whirtle", -"whish", -"whisk", -"whisker", -"whiskey", -"whisky", -"whisp", -"whisper", -"whissle", -"whist", -"whister", -"whistle", -"whistly", -"whit", -"white", -"whited", -"whitely", -"whiten", -"whites", -"whither", -"whiting", -"whitish", -"whitlow", -"whits", -"whittaw", -"whitten", -"whitter", -"whittle", -"whity", -"whiz", -"whizgig", -"whizzer", -"whizzle", -"who", -"whoa", -"whoever", -"whole", -"wholly", -"whom", -"whomble", -"whomso", -"whone", -"whoo", -"whoof", -"whoop", -"whoopee", -"whooper", -"whoops", -"whoosh", -"whop", -"whopper", -"whorage", -"whore", -"whorish", -"whorl", -"whorled", -"whorly", -"whort", -"whortle", -"whose", -"whosen", -"whud", -"whuff", -"whuffle", -"whulk", -"whulter", -"whummle", -"whun", -"whup", -"whush", -"whuskie", -"whussle", -"whute", -"whuther", -"whutter", -"whuz", -"why", -"whyever", -"whyfor", -"whyness", -"whyo", -"wi", -"wice", -"wicht", -"wichtje", -"wick", -"wicked", -"wicken", -"wicker", -"wicket", -"wicking", -"wickiup", -"wickup", -"wicky", -"wicopy", -"wid", -"widbin", -"widder", -"widdle", -"widdy", -"wide", -"widegab", -"widely", -"widen", -"widener", -"widgeon", -"widish", -"widow", -"widowed", -"widower", -"widowly", -"widowy", -"width", -"widu", -"wield", -"wielder", -"wieldy", -"wiener", -"wienie", -"wife", -"wifedom", -"wifeism", -"wifekin", -"wifelet", -"wifely", -"wifie", -"wifish", -"wifock", -"wig", -"wigan", -"wigdom", -"wigful", -"wigged", -"wiggen", -"wigger", -"wiggery", -"wigging", -"wiggish", -"wiggism", -"wiggle", -"wiggler", -"wiggly", -"wiggy", -"wight", -"wightly", -"wigless", -"wiglet", -"wiglike", -"wigtail", -"wigwag", -"wigwam", -"wiikite", -"wild", -"wildcat", -"wilded", -"wilder", -"wilding", -"wildish", -"wildly", -"wile", -"wileful", -"wilga", -"wilgers", -"wilily", -"wilk", -"wilkin", -"will", -"willawa", -"willed", -"willer", -"willet", -"willey", -"willful", -"willie", -"willier", -"willies", -"willing", -"willock", -"willow", -"willowy", -"willy", -"willyer", -"wilsome", -"wilt", -"wilter", -"wily", -"wim", -"wimble", -"wimbrel", -"wime", -"wimick", -"wimple", -"win", -"wince", -"wincer", -"wincey", -"winch", -"wincher", -"wincing", -"wind", -"windage", -"windbag", -"winddog", -"winded", -"winder", -"windigo", -"windily", -"winding", -"windle", -"windles", -"windlin", -"windock", -"windore", -"window", -"windowy", -"windrow", -"windup", -"windway", -"windy", -"wine", -"wined", -"winemay", -"winepot", -"winer", -"winery", -"winesop", -"winevat", -"winful", -"wing", -"wingcut", -"winged", -"winger", -"wingle", -"winglet", -"wingman", -"wingy", -"winish", -"wink", -"winkel", -"winker", -"winking", -"winkle", -"winklet", -"winly", -"winna", -"winnard", -"winnel", -"winner", -"winning", -"winnle", -"winnow", -"winrace", -"winrow", -"winsome", -"wint", -"winter", -"wintle", -"wintry", -"winy", -"winze", -"wipe", -"wiper", -"wippen", -"wips", -"wir", -"wirable", -"wirble", -"wird", -"wire", -"wirebar", -"wired", -"wireman", -"wirer", -"wireway", -"wirily", -"wiring", -"wirl", -"wirling", -"wirr", -"wirra", -"wirrah", -"wiry", -"wis", -"wisdom", -"wise", -"wisely", -"wiseman", -"wisen", -"wisent", -"wiser", -"wish", -"wisha", -"wished", -"wisher", -"wishful", -"wishing", -"wishly", -"wishmay", -"wisht", -"wisket", -"wisp", -"wispish", -"wispy", -"wiss", -"wisse", -"wissel", -"wist", -"wiste", -"wistful", -"wistit", -"wistiti", -"wit", -"witan", -"witch", -"witched", -"witchen", -"witchet", -"witchy", -"wite", -"witess", -"witful", -"with", -"withal", -"withe", -"withen", -"wither", -"withers", -"withery", -"within", -"without", -"withy", -"witjar", -"witless", -"witlet", -"witling", -"witloof", -"producer", -"witney", -"witship", -"wittal", -"witted", -"witter", -"wittily", -"witting", -"wittol", -"witty", -"witwall", -"wive", -"wiver", -"wivern", -"wiz", -"wizard", -"wizen", -"wizened", -"wizier", -"wizzen", -"wloka", -"wo", -"woad", -"woader", -"woadman", -"woady", -"woak", -"woald", -"woan", -"wob", -"wobble", -"wobbler", -"wobbly", -"wobster", -"wod", -"woddie", -"wode", -"wodge", -"wodgy", -"woe", -"woeful", -"woesome", -"woevine", -"woeworn", -"woffler", -"woft", -"wog", -"wogiet", -"woibe", -"wokas", -"woke", -"wokowi", -"wold", -"woldy", -"wolf", -"wolfdom", -"wolfen", -"wolfer", -"wolfish", -"wolfkin", -"wolfram", -"wollop", -"wolter", -"wolve", -"wolver", -"woman", -"womanly", -"womb", -"wombat", -"wombed", -"womble", -"womby", -"womera", -"won", -"wonder", -"wone", -"wonegan", -"wong", -"wonga", -"wongen", -"wongshy", -"wongsky", -"woning", -"wonky", -"wonna", -"wonned", -"wonner", -"wonning", -"wonnot", -"wont", -"wonted", -"wonting", -"woo", -"wooable", -"wood", -"woodbin", -"woodcut", -"wooded", -"wooden", -"woodeny", -"woodine", -"wooding", -"woodish", -"woodlet", -"woodly", -"woodman", -"woodrow", -"woodsy", -"woodwax", -"woody", -"wooer", -"woof", -"woofed", -"woofell", -"woofer", -"woofy", -"woohoo", -"wooing", -"wool", -"woold", -"woolder", -"wooled", -"woolen", -"wooler", -"woolert", -"woolly", -"woolman", -"woolsey", -"woom", -"woomer", -"woon", -"woons", -"woorali", -"woorari", -"woosh", -"wootz", -"woozle", -"woozy", -"wop", -"woppish", -"wops", -"worble", -"word", -"wordage", -"worded", -"worder", -"wordily", -"wording", -"wordish", -"wordle", -"wordman", -"wordy", -"wore", -"work", -"workbag", -"workbox", -"workday", -"worked", -"worker", -"working", -"workman", -"workout", -"workpan", -"works", -"worky", -"world", -"worlded", -"worldly", -"worldy", -"worm", -"wormed", -"wormer", -"wormil", -"worming", -"wormy", -"worn", -"wornil", -"worral", -"worried", -"worrier", -"worrit", -"worry", -"worse", -"worsen", -"worser", -"worset", -"worship", -"worst", -"worsted", -"wort", -"worth", -"worthy", -"wosbird", -"wot", -"wote", -"wots", -"wottest", -"wotteth", -"woubit", -"wouch", -"wouf", -"wough", -"would", -"wouldnt", -"wouldst", -"wound", -"wounded", -"wounder", -"wounds", -"woundy", -"wourali", -"wourari", -"wournil", -"wove", -"woven", -"wow", -"wowser", -"wowsery", -"wowt", -"woy", -"wrack", -"wracker", -"wraggle", -"wraith", -"wraithe", -"wraithy", -"wraitly", -"wramp", -"wran", -"wrang", -"wrangle", -"wranny", -"wrap", -"wrapped", -"wrapper", -"wrasse", -"wrastle", -"wrath", -"wrathy", -"wraw", -"wrawl", -"wrawler", -"wraxle", -"wreak", -"wreat", -"wreath", -"wreathe", -"wreathy", -"wreck", -"wrecker", -"wrecky", -"wren", -"wrench", -"wrenlet", -"wrest", -"wrester", -"wrestle", -"wretch", -"wricht", -"wrick", -"wride", -"wried", -"wrier", -"wriest", -"wrig", -"wriggle", -"wriggly", -"wright", -"wring", -"wringer", -"wrinkle", -"wrinkly", -"wrist", -"wristed", -"wrister", -"writ", -"write", -"writee", -"writer", -"writh", -"writhe", -"writhed", -"writhen", -"writher", -"writhy", -"writing", -"written", -"writter", -"wrive", -"wro", -"wrocht", -"wroke", -"wroken", -"wrong", -"wronged", -"wronger", -"wrongly", -"wrossle", -"wrote", -"wroth", -"wrothly", -"wrothy", -"wrought", -"wrox", -"wrung", -"wry", -"wrybill", -"wryly", -"wryneck", -"wryness", -"wrytail", -"wud", -"wuddie", -"wudge", -"wudu", -"wugg", -"wulk", -"wull", -"wullcat", -"wulliwa", -"wumble", -"wumman", -"wummel", -"wun", -"wungee", -"wunna", -"wunner", -"wunsome", -"wup", -"wur", -"wurley", -"wurmal", -"wurrus", -"wurset", -"wurzel", -"wush", -"wusp", -"wuss", -"wusser", -"wust", -"wut", -"wuther", -"wuzu", -"wuzzer", -"wuzzle", -"wuzzy", -"wy", -"wyde", -"wye", -"wyke", -"wyle", -"wymote", -"wyn", -"wynd", -"wyne", -"wynn", -"wype", -"wyson", -"wyss", -"wyve", -"wyver", -"x", -"xanthic", -"xanthin", -"xanthyl", -"xarque", -"xebec", -"xenia", -"xenial", -"xenian", -"xenium", -"xenon", -"xenyl", -"xerafin", -"xerarch", -"xerasia", -"xeric", -"xeriff", -"xerogel", -"xeroma", -"xeronic", -"xerosis", -"xerotes", -"xerotic", -"xi", -"xiphias", -"xiphiid", -"xiphoid", -"xoana", -"xoanon", -"xurel", -"xyla", -"xylan", -"xylate", -"xylem", -"xylene", -"xylenol", -"xylenyl", -"xyletic", -"xylic", -"xylidic", -"xylinid", -"xylite", -"xylitol", -"xylogen", -"xyloid", -"xylol", -"xyloma", -"xylon", -"xylonic", -"xylose", -"xyloyl", -"xylyl", -"xylylic", -"xyphoid", -"xyrid", -"xyst", -"xyster", -"xysti", -"xystos", -"xystum", -"xystus", -"y", -"ya", -"yaba", -"yabber", -"yabbi", -"yabble", -"yabby", -"yabu", -"yacal", -"yacca", -"yachan", -"yacht", -"yachter", -"yachty", -"yad", -"yade", -"yaff", -"yaffle", -"yagger", -"yagi", -"yagua", -"yaguaza", -"yah", -"yahan", -"yahoo", -"yair", -"yaird", -"yaje", -"yajeine", -"yak", -"yakalo", -"yakamik", -"yakin", -"yakka", -"yakman", -"yalb", -"yale", -"yali", -"yalla", -"yallaer", -"yallow", -"yam", -"yamamai", -"yamanai", -"yamen", -"yamilke", -"yammer", -"yamp", -"yampa", -"yamph", -"yamshik", -"yan", -"yander", -"yang", -"yangtao", -"yank", -"yanking", -"yanky", -"yaoort", -"yaourti", -"yap", -"yapa", -"yaply", -"yapness", -"yapok", -"yapp", -"yapped", -"yapper", -"yapping", -"yappish", -"yappy", -"yapster", -"yar", -"yarak", -"yaray", -"yarb", -"yard", -"yardage", -"yardang", -"yardarm", -"yarder", -"yardful", -"yarding", -"yardman", -"yare", -"yareta", -"yark", -"yarke", -"yarl", -"yarly", -"yarm", -"yarn", -"yarnen", -"yarner", -"yarpha", -"yarr", -"yarran", -"yarrow", -"yarth", -"yarthen", -"yarwhip", -"yas", -"yashiro", -"yashmak", -"yat", -"yate", -"yati", -"yatter", -"yaud", -"yauld", -"yaupon", -"yautia", -"yava", -"yaw", -"yawl", -"yawler", -"yawn", -"yawner", -"yawney", -"yawnful", -"yawnily", -"yawning", -"yawnups", -"yawny", -"yawp", -"yawper", -"yawroot", -"yaws", -"yawweed", -"yawy", -"yaxche", -"yaya", -"ycie", -"yday", -"ye", -"yea", -"yeah", -"yealing", -"yean", -"year", -"yeara", -"yeard", -"yearday", -"yearful", -"yearly", -"yearn", -"yearock", -"yearth", -"yeast", -"yeasty", -"yeat", -"yeather", -"yed", -"yede", -"yee", -"yeel", -"yees", -"yegg", -"yeggman", -"yeguita", -"yeld", -"yeldrin", -"yelk", -"yell", -"yeller", -"yelling", -"yelloch", -"yellow", -"yellows", -"yellowy", -"yelm", -"yelmer", -"yelp", -"yelper", -"yelt", -"yen", -"yender", -"yeni", -"yenite", -"yeo", -"yeoman", -"yep", -"yer", -"yerb", -"yerba", -"yercum", -"yerd", -"yere", -"yerga", -"yerk", -"yern", -"yerth", -"yes", -"yese", -"yeso", -"yesso", -"yest", -"yester", -"yestern", -"yesty", -"yet", -"yeta", -"yetapa", -"yeth", -"yether", -"yetlin", -"yeuk", -"yeuky", -"yeven", -"yew", -"yex", -"yez", -"yezzy", -"ygapo", -"yield", -"yielden", -"yielder", -"yieldy", -"yigh", -"yill", -"yilt", -"yin", -"yince", -"yinst", -"yip", -"yird", -"yirk", -"yirm", -"yirn", -"yirr", -"yirth", -"yis", -"yite", -"ym", -"yn", -"ynambu", -"yo", -"yobi", -"yocco", -"yochel", -"yock", -"yockel", -"yodel", -"yodeler", -"yodh", -"yoe", -"yoga", -"yogh", -"yoghurt", -"yogi", -"yogin", -"yogism", -"yogist", -"yogoite", -"yohimbe", -"yohimbi", -"yoi", -"yoick", -"yoicks", -"yojan", -"yojana", -"yok", -"yoke", -"yokeage", -"yokel", -"yokelry", -"yoker", -"yoking", -"yoky", -"yolden", -"yolk", -"yolked", -"yolky", -"yom", -"yomer", -"yon", -"yond", -"yonder", -"yonner", -"yonside", -"yont", -"yook", -"yoop", -"yor", -"yore", -"york", -"yorker", -"yot", -"yote", -"you", -"youd", -"youden", -"youdith", -"youff", -"youl", -"young", -"younger", -"youngly", -"youngun", -"younker", -"youp", -"your", -"yourn", -"yours", -"yoursel", -"youse", -"youth", -"youthen", -"youthy", -"youve", -"youward", -"youze", -"yoven", -"yow", -"yowie", -"yowl", -"yowler", -"yowley", -"yowt", -"yox", -"yoy", -"yperite", -"yr", -"yttria", -"yttric", -"yttrium", -"yuan", -"yuca", -"yucca", -"yuck", -"yuckel", -"yucker", -"yuckle", -"yucky", -"yuft", -"yugada", -"yuh", -"yukkel", -"yulan", -"yule", -"yummy", -"yungan", -"yurt", -"yurta", -"yus", -"yusdrum", -"yutu", -"yuzlik", -"yuzluk", -"z", -"za", -"zabeta", -"zabra", -"zabti", -"zabtie", -"zac", -"zacate", -"zacaton", -"zachun", -"zad", -"zadruga", -"zaffar", -"zaffer", -"zafree", -"zag", -"zagged", -"zain", -"zak", -"zakkeu", -"zaman", -"zamang", -"zamarra", -"zamarro", -"zambo", -"zamorin", -"zamouse", -"zander", -"zanella", -"zant", -"zante", -"zany", -"zanyish", -"zanyism", -"zanze", -"zapas", -"zaphara", -"zapota", -"zaptiah", -"zaptieh", -"zapupe", -"zaqqum", -"zar", -"zareba", -"zarf", -"zarnich", -"zarp", -"zat", -"zati", -"zattare", -"zax", -"zayat", -"zayin", -"zeal", -"zealful", -"zealot", -"zealous", -"zebra", -"zebraic", -"zebrass", -"zebrine", -"zebroid", -"zebrula", -"zebrule", -"zebu", -"zebub", -"zeburro", -"zechin", -"zed", -"zedoary", -"zee", -"zeed", -"zehner", -"zein", -"zeism", -"zeist", -"zel", -"zelator", -"zemeism", -"zemi", -"zemmi", -"zemni", -"zemstvo", -"zenana", -"zendik", -"zenick", -"zenith", -"zenu", -"zeolite", -"zephyr", -"zephyry", -"zequin", -"zer", -"zerda", -"zero", -"zeroize", -"zest", -"zestful", -"zesty", -"zeta", -"zetetic", -"zeugma", -"ziamet", -"ziara", -"ziarat", -"zibet", -"zibetum", -"ziega", -"zieger", -"ziffs", -"zig", -"ziganka", -"zigzag", -"zihar", -"zikurat", -"zillah", -"zimarra", -"zimb", -"zimbi", -"zimme", -"zimmi", -"zimmis", -"zimocca", -"zinc", -"zincate", -"zincic", -"zincide", -"zincify", -"zincing", -"zincite", -"zincize", -"zincke", -"zincky", -"zinco", -"zincous", -"zincum", -"zing", -"zingel", -"zink", -"zinsang", -"zip", -"ziphian", -"zipper", -"zipping", -"zippy", -"zira", -"zirai", -"zircite", -"zircon", -"zither", -"zizz", -"zloty", -"zo", -"zoa", -"zoacum", -"zoaria", -"zoarial", -"zoarium", -"zobo", -"zocco", -"zoccolo", -"zodiac", -"zoea", -"zoeal", -"zoeform", -"zoetic", -"zogan", -"zogo", -"zoic", -"zoid", -"zoisite", -"zoism", -"zoist", -"zoistic", -"zokor", -"zoll", -"zolle", -"zombi", -"zombie", -"zonal", -"zonally", -"zonar", -"zonary", -"zonate", -"zonated", -"zone", -"zoned", -"zonelet", -"zonic", -"zoning", -"zonite", -"zonitid", -"zonoid", -"zonular", -"zonule", -"zonulet", -"zonure", -"zonurid", -"zoo", -"zoocarp", -"zoocyst", -"zooecia", -"zoogamy", -"zoogene", -"zoogeny", -"zoogony", -"zooid", -"zooidal", -"zooks", -"zoolite", -"zoolith", -"zoology", -"zoom", -"zoon", -"zoonal", -"zoonic", -"zoonist", -"zoonite", -"zoonomy", -"zoons", -"zoonule", -"zoopery", -"zoopsia", -"zoosis", -"zootaxy", -"zooter", -"zootic", -"zootomy", -"zootype", -"zoozoo", -"zorgite", -"zoril", -"zorilla", -"zorillo", -"zorro", -"zoster", -"zounds", -"zowie", -"zudda", -"zuisin", -"zumatic", -"zunyite", -"zuza", -"zwitter", -"zyga", -"zygal", -"zygion", -"zygite", -"zygoma", -"zygon", -"zygose", -"zygosis", -"zygote", -"zygotic", -"zygous", -"zymase", -"zyme", -"zymic", -"zymin", -"zymite", -"zymogen", -"zymoid", -"zymome", -"zymomin", -"zymosis", -"zymotic", -"zymurgy", -"zythem", -"zythum" }; - - -const uint32_t word_list_size = sizeof(word_list)/sizeof(word_list[0]); - -void hide_unused_warning() { - (void)word_list_size; - (void)word_list; -} - -} } // eosio::words diff --git a/libraries/wabt b/libraries/wabt index 2f5382661f7..bf353aa719c 160000 --- a/libraries/wabt +++ b/libraries/wabt @@ -1 +1 @@ -Subproject commit 2f5382661f7bf77cf7a70dcf0543a44fd5025910 +Subproject commit bf353aa719c88b7152ee09e7f877a507cb7df27b diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 9d4a6ab93b3..0b42bdf41b0 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -9,6 +9,7 @@ add_subdirectory(producer_plugin) add_subdirectory(producer_api_plugin) add_subdirectory(history_plugin) add_subdirectory(history_api_plugin) +add_subdirectory(state_history_plugin) add_subdirectory(wallet_plugin) add_subdirectory(wallet_api_plugin) diff --git a/plugins/COMMUNITY.md b/plugins/COMMUNITY.md index db7d2139d83..55cce74a33b 100644 --- a/plugins/COMMUNITY.md +++ b/plugins/COMMUNITY.md @@ -13,6 +13,10 @@ Third parties are encouraged to make pull requests to this file (`develop` branc | SQL | https://github.com/asiniscalchi/eosio_sql_plugin | | Watch for specific actions and send them to an HTTP URL | https://github.com/eosauthority/eosio-watcher-plugin | | ZMQ / history | https://github.com/cc32d9/eos_zmq_plugin | +| ZMQ Light History API | https://github.com/cc32d9/eos_zmq_light_api | +| Chintai ZMQ Watcher | https://github.com/acoutts/chintai-zeromq-watcher-plugin | +| Mongo History API | https://github.com/CryptoLions/EOS-mongo-history-API | +| State History API | https://github.com/acoutts/EOS-state-history-API | ## DISCLAIMER: diff --git a/plugins/bnet_plugin/bnet_plugin.cpp b/plugins/bnet_plugin/bnet_plugin.cpp index 4052fce2b30..b25631cbabc 100644 --- a/plugins/bnet_plugin/bnet_plugin.cpp +++ b/plugins/bnet_plugin/bnet_plugin.cpp @@ -306,7 +306,7 @@ namespace eosio { int next_session_id()const { - static int session_count = 0; + static std::atomic session_count(0); return ++session_count; } @@ -441,7 +441,7 @@ namespace eosio { if( itr != _transaction_status.end() ) { if( !itr->known_by_peer() ) { _transaction_status.modify( itr, [&]( auto& stat ) { - stat.expired = std::min( fc::time_point::now() + fc::seconds(5), t->trx.expiration ); + stat.expired = std::min( fc::time_point::now() + fc::seconds(5), t->packed_trx->expiration() ); }); } return; @@ -555,8 +555,7 @@ namespace eosio { for( const auto& receipt : s->block->transactions ) { if( receipt.trx.which() == 1 ) { const auto& pt = receipt.trx.get(); - // get id via get_uncached_id() as packed_transaction.id() mutates internal transaction state - const auto& tid = pt.get_uncached_id(); + const auto& tid = pt.id(); auto itr = _transaction_status.find( tid ); if( itr != _transaction_status.end() ) _transaction_status.erase(itr); @@ -765,7 +764,7 @@ namespace eosio { return false; - auto ptrx_ptr = std::make_shared( start->trx->packed_trx ); + auto ptrx_ptr = start->trx->packed_trx; idx.modify( start, [&]( auto& stat ) { stat.mark_known_by_peer(); @@ -788,7 +787,7 @@ namespace eosio { /// if something changed, the next block doesn't link to the last /// block we sent, local chain must have switched forks - if( nextblock->previous != _last_sent_block_id ) { + if( nextblock->previous != _last_sent_block_id && _last_sent_block_id != block_id_type() ) { if( !is_known_by_peer( nextblock->previous ) ) { _last_sent_block_id = _local_lib_id; _last_sent_block_num = _local_lib; @@ -1014,8 +1013,7 @@ namespace eosio { for( const auto& receipt : b->transactions ) { if( receipt.trx.which() == 1 ) { const auto& pt = receipt.trx.get(); - // get id via get_uncached_id() as packed_transaction.id() mutates internal transaction state - const auto& id = pt.get_uncached_id(); + const auto& id = pt.id(); mark_transaction_known_by_peer(id); } } @@ -1041,26 +1039,7 @@ namespace eosio { return false; } - void on( const packed_transaction_ptr& p ) { - peer_ilog(this, "received packed_transaction_ptr"); - if (!p) { - peer_elog(this, "bad packed_transaction_ptr : null pointer"); - EOS_THROW(transaction_exception, "bad transaction"); - } - if( app().get_plugin().chain().get_read_mode() == chain::db_read_mode::READ_ONLY ) - return; - - // ilog( "recv trx ${n}", ("n", id) ); - if( p->expiration() < fc::time_point::now() ) return; - - // get id via get_uncached_id() as packed_transaction.id() mutates internal transaction state - const auto& id = p->get_uncached_id(); - - if( mark_transaction_known_by_peer( id ) ) - return; - - app().get_channel().publish(p); - } + void on( const packed_transaction_ptr& p ); void on_write( boost::system::error_code ec, std::size_t bytes_transferred ) { boost::ignore_unused(bytes_transferred); @@ -1402,8 +1381,10 @@ namespace eosio { if( app().get_plugin().chain().get_read_mode() == chain::db_read_mode::READ_ONLY ) { - my->_request_trx = false; - ilog( "setting bnet-no-trx to true since in read-only mode" ); + if (my->_request_trx) { + my->_request_trx = false; + ilog( "forced bnet-no-trx to true since in read-only mode" ); + } } const auto address = boost::asio::ip::make_address( my->_bnet_endpoint_address ); @@ -1557,4 +1538,25 @@ namespace eosio { } + void session::on( const packed_transaction_ptr& p ) { + peer_ilog(this, "received packed_transaction_ptr"); + if (!p) { + peer_elog(this, "bad packed_transaction_ptr : null pointer"); + EOS_THROW(transaction_exception, "bad transaction"); + } + if( !_net_plugin->_request_trx ) + return; + + // ilog( "recv trx ${n}", ("n", id) ); + if( p->expiration() < fc::time_point::now() ) return; + + const auto& id = p->id(); + + if( mark_transaction_known_by_peer( id ) ) + return; + + auto ptr = std::make_shared(p); + + app().get_channel().publish(ptr); + } } /// namespace eosio diff --git a/plugins/bnet_plugin/include/eosio/bnet_plugin/bnet_plugin.hpp b/plugins/bnet_plugin/include/eosio/bnet_plugin/bnet_plugin.hpp index 5a749ea44ef..9eb3a54c9a4 100644 --- a/plugins/bnet_plugin/include/eosio/bnet_plugin/bnet_plugin.hpp +++ b/plugins/bnet_plugin/include/eosio/bnet_plugin/bnet_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/plugins/chain_api_plugin/chain_api_plugin.cpp b/plugins/chain_api_plugin/chain_api_plugin.cpp index f07e48a7f04..8b9fd3f843c 100644 --- a/plugins/chain_api_plugin/chain_api_plugin.cpp +++ b/plugins/chain_api_plugin/chain_api_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/plugins/chain_api_plugin/include/eosio/chain_api_plugin/chain_api_plugin.hpp b/plugins/chain_api_plugin/include/eosio/chain_api_plugin/chain_api_plugin.hpp index ad64fcaa1d3..9a854cf0b56 100644 --- a/plugins/chain_api_plugin/include/eosio/chain_api_plugin/chain_api_plugin.hpp +++ b/plugins/chain_api_plugin/include/eosio/chain_api_plugin/chain_api_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp index 7303768cab4..b62915b5220 100644 --- a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp +++ b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once @@ -45,19 +45,19 @@ namespace eosio { namespace chain { namespace plugin_interface { namespace incoming { namespace channels { using block = channel_decl; - using transaction = channel_decl; + using transaction = channel_decl; } namespace methods { // synchronously push a block/trx to a single provider using block_sync = method_decl; - using transaction_async = method_decl), first_provider_policy>; + using transaction_async = method_decl), first_provider_policy>; } } namespace compat { namespace channels { - using transaction_ack = channel_decl>; + using transaction_ack = channel_decl>; } } diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 2603a87178b..91d130d3ec5 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include @@ -18,10 +18,6 @@ #include -#include -#include -#include - #include #include #include @@ -222,6 +218,10 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip ("chain-state-db-guard-size-mb", bpo::value()->default_value(config::default_state_guard_size / (1024 * 1024)), "Safely shut down node when free space remaining in the chain state database drops below this size (in MiB).") ("reversible-blocks-db-size-mb", bpo::value()->default_value(config::default_reversible_cache_size / (1024 * 1024)), "Maximum size (in MiB) of the reversible blocks database") ("reversible-blocks-db-guard-size-mb", bpo::value()->default_value(config::default_reversible_guard_size / (1024 * 1024)), "Safely shut down node when free space remaining in the reverseible blocks database drops below this size (in MiB).") + ("signature-cpu-billable-pct", bpo::value()->default_value(config::default_sig_cpu_bill_pct / config::percent_1), + "Percentage of actual signature recovery cpu to bill. Whole number percentages, e.g. 50 for 50%") + ("chain-threads", bpo::value()->default_value(config::default_controller_thread_pool_size), + "Number of worker threads in controller thread pool") ("contracts-console", bpo::bool_switch()->default_value(false), "print contract's output to console") ("actor-whitelist", boost::program_options::value>()->composing()->multitoken(), @@ -236,6 +236,8 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip "Action (in the form code::action) added to action blacklist (may specify multiple times)") ("key-blacklist", boost::program_options::value>()->composing()->multitoken(), "Public key added to blacklist of keys that should not be included in authorities (may specify multiple times)") + ("sender-bypass-whiteblacklist", boost::program_options::value>()->composing()->multitoken(), + "Deferred transactions sent by accounts in this list do not have any of the subjective whitelist/blacklist checks applied to them (may specify multiple times)") ("read-mode", boost::program_options::value()->default_value(eosio::chain::db_read_mode::SPECULATIVE), "Database read mode (\"speculative\", \"head\", or \"read-only\").\n"// or \"irreversible\").\n" "In \"speculative\" mode database contains changes done up to the head block plus changes made by transactions not yet included to the blockchain.\n" @@ -343,6 +345,7 @@ void chain_plugin::plugin_initialize(const variables_map& options) { my->chain_config = controller::config(); + LOAD_VALUE_SET( options, "sender-bypass-whiteblacklist", my->chain_config->sender_bypass_whiteblacklist ); LOAD_VALUE_SET( options, "actor-whitelist", my->chain_config->actor_whitelist ); LOAD_VALUE_SET( options, "actor-blacklist", my->chain_config->actor_blacklist ); LOAD_VALUE_SET( options, "contract-whitelist", my->chain_config->contract_whitelist ); @@ -419,6 +422,17 @@ void chain_plugin::plugin_initialize(const variables_map& options) { if( options.count( "reversible-blocks-db-guard-size-mb" )) my->chain_config->reversible_guard_size = options.at( "reversible-blocks-db-guard-size-mb" ).as() * 1024 * 1024; + if( options.count( "chain-threads" )) { + my->chain_config->thread_pool_size = options.at( "chain-threads" ).as(); + EOS_ASSERT( my->chain_config->thread_pool_size > 0, plugin_config_exception, + "chain-threads ${num} must be greater than 0", ("num", my->chain_config->thread_pool_size) ); + } + + my->chain_config->sig_cpu_bill_pct = options.at("signature-cpu-billable-pct").as(); + EOS_ASSERT( my->chain_config->sig_cpu_bill_pct >= 0 && my->chain_config->sig_cpu_bill_pct <= 100, plugin_config_exception, + "signature-cpu-billable-pct must be 0 - 100, ${pct}", ("pct", my->chain_config->sig_cpu_bill_pct) ); + my->chain_config->sig_cpu_bill_pct *= config::percent_1; + if( my->wasm_runtime ) my->chain_config->wasm_runtime = *my->wasm_runtime; @@ -565,12 +579,17 @@ void chain_plugin::plugin_initialize(const variables_map& options) { } } else { - if( options.count( "genesis-json" )) { - EOS_ASSERT( !fc::exists( my->blocks_dir / "blocks.log" ), - plugin_config_exception, - "Genesis state can only be set on a fresh blockchain." ); + bfs::path genesis_file; + bool genesis_timestamp_specified = false; + fc::optional existing_genesis; - auto genesis_file = options.at( "genesis-json" ).as(); + if( fc::exists( my->blocks_dir / "blocks.log" ) ) { + my->chain_config->genesis = block_log::extract_genesis_state( my->blocks_dir ); + existing_genesis = my->chain_config->genesis; + } + + if( options.count( "genesis-json" )) { + genesis_file = options.at( "genesis-json" ).as(); if( genesis_file.is_relative()) { genesis_file = bfs::current_path() / genesis_file; } @@ -581,28 +600,32 @@ void chain_plugin::plugin_initialize(const variables_map& options) { ("genesis", genesis_file.generic_string())); my->chain_config->genesis = fc::json::from_file( genesis_file ).as(); + } - ilog( "Using genesis state provided in '${genesis}'", ("genesis", genesis_file.generic_string())); + if( options.count( "genesis-timestamp" ) ) { + my->chain_config->genesis.initial_timestamp = calculate_genesis_timestamp( options.at( "genesis-timestamp" ).as() ); + genesis_timestamp_specified = true; + } - if( options.count( "genesis-timestamp" )) { - my->chain_config->genesis.initial_timestamp = calculate_genesis_timestamp( - options.at( "genesis-timestamp" ).as()); + if( !existing_genesis ) { + if( !genesis_file.empty() ) { + if( genesis_timestamp_specified ) { + ilog( "Using genesis state provided in '${genesis}' but with adjusted genesis timestamp", + ("genesis", genesis_file.generic_string()) ); + } else { + ilog( "Using genesis state provided in '${genesis}'", ("genesis", genesis_file.generic_string())); + } + wlog( "Starting up fresh blockchain with provided genesis state." ); + } else if( genesis_timestamp_specified ) { + wlog( "Starting up fresh blockchain with default genesis state but with adjusted genesis timestamp." ); + } else { + wlog( "Starting up fresh blockchain with default genesis state." ); } - - wlog( "Starting up fresh blockchain with provided genesis state." ); - } else if( options.count( "genesis-timestamp" )) { - EOS_ASSERT( !fc::exists( my->blocks_dir / "blocks.log" ), - plugin_config_exception, - "Genesis state can only be set on a fresh blockchain." ); - - my->chain_config->genesis.initial_timestamp = calculate_genesis_timestamp( - options.at( "genesis-timestamp" ).as()); - - wlog( "Starting up fresh blockchain with default genesis state but with adjusted genesis timestamp." ); - } else if( fc::is_regular_file( my->blocks_dir / "blocks.log" )) { - my->chain_config->genesis = block_log::extract_genesis_state( my->blocks_dir ); } else { - wlog( "Starting up fresh blockchain with default genesis state." ); + EOS_ASSERT( my->chain_config->genesis == *existing_genesis, plugin_config_exception, + "Genesis state provided via command line arguments does not match the existing genesis state in blocks.log. " + "It is not necessary to provide genesis state arguments when a blocks.log file already exists." + ); } } @@ -688,13 +711,14 @@ void chain_plugin::plugin_initialize(const variables_map& options) { void chain_plugin::plugin_startup() { try { try { + auto shutdown = [](){ return app().is_quiting(); }; if (my->snapshot_path) { auto infile = std::ifstream(my->snapshot_path->generic_string(), (std::ios::in | std::ios::binary)); auto reader = std::make_shared(infile); - my->chain->startup(reader); + my->chain->startup(shutdown, reader); infile.close(); } else { - my->chain->startup(); + my->chain->startup(shutdown); } } catch (const database_guard_exception& e) { log_guard_exception(e); @@ -721,6 +745,8 @@ void chain_plugin::plugin_shutdown() { my->accepted_transaction_connection.reset(); my->applied_transaction_connection.reset(); my->accepted_confirmation_connection.reset(); + my->chain->get_thread_pool().stop(); + my->chain->get_thread_pool().join(); my->chain.reset(); } @@ -734,16 +760,16 @@ void chain_apis::read_write::validate() const { EOS_ASSERT( db.get_read_mode() != chain::db_read_mode::READ_ONLY, missing_chain_api_plugin_exception, "Not allowed, node in read-only mode" ); } -chain_apis::read_write chain_plugin::get_read_write_api() { - return chain_apis::read_write(chain(), get_abi_serializer_max_time()); -} - void chain_plugin::accept_block(const signed_block_ptr& block ) { my->incoming_block_sync_method(block); } void chain_plugin::accept_transaction(const chain::packed_transaction& trx, next_function next) { - my->incoming_transaction_async_method(std::make_shared(trx), false, std::forward(next)); + my->incoming_transaction_async_method(std::make_shared(std::make_shared(trx)), false, std::forward(next)); +} + +void chain_plugin::accept_transaction(const chain::transaction_metadata_ptr& trx, next_function next) { + my->incoming_transaction_async_method(trx, false, std::forward(next)); } bool chain_plugin::block_is_on_preferred_chain(const block_id_type& block_id) { @@ -888,7 +914,7 @@ bool chain_plugin::import_reversible_blocks( const fc::path& reversible_dir, new_reversible.create( [&]( auto& ubo ) { ubo.blocknum = num; - ubo.set_block( std::make_shared(tmp) ); + ubo.set_block( std::make_shared(std::move(tmp)) ); }); end = num; } @@ -992,10 +1018,19 @@ namespace chain_apis { const string read_only::KEYi64 = "i64"; +template +std::string itoh(I n, size_t hlen = sizeof(I)<<1) { + static const char* digits = "0123456789abcdef"; + std::string r(hlen, '0'); + for(size_t i = 0, j = (hlen - 1) * 4 ; i < hlen; ++i, j -= 4) + r[i] = digits[(n>>j) & 0x0f]; + return r; +} + read_only::get_info_results read_only::get_info(const read_only::get_info_params&) const { const auto& rm = db.get_resource_limits_manager(); return { - eosio::utilities::common::itoh(static_cast(app().version())), + itoh(static_cast(app().version())), db.get_chain_id(), db.fork_db_head_block_num(), db.last_irreversible_block_num(), @@ -1088,6 +1123,19 @@ uint64_t convert_to_type(const string& str, const string& desc) { } } +template<> +double convert_to_type(const string& str, const string& desc) { + double val{}; + try { + val = fc::variant(str).as(); + } FC_RETHROW_EXCEPTIONS(warn, "Could not convert ${desc} string '${str}' to key type.", ("desc", desc)("str",str) ) + + EOS_ASSERT( !std::isnan(val), chain::contract_table_query_exception, + "Converted ${desc} string '${str}' to NaN which is not a permitted value for the key type", ("desc", desc)("str",str) ); + + return val; +} + abi_def get_abi( const controller& db, const name& account ) { const auto &d = db.db(); const account_object *code_accnt = d.find(account); @@ -1166,51 +1214,57 @@ read_only::get_table_rows_result read_only::get_table_rows( const read_only::get } read_only::get_table_by_scope_result read_only::get_table_by_scope( const read_only::get_table_by_scope_params& p )const { + read_only::get_table_by_scope_result result; const auto& d = db.db(); + const auto& idx = d.get_index(); - decltype(idx.lower_bound(boost::make_tuple(0, 0, 0))) lower; - decltype(idx.upper_bound(boost::make_tuple(0, 0, 0))) upper; + auto lower_bound_lookup_tuple = std::make_tuple( p.code.value, std::numeric_limits::lowest(), p.table.value ); + auto upper_bound_lookup_tuple = std::make_tuple( p.code.value, std::numeric_limits::max(), + (p.table.empty() ? std::numeric_limits::max() : p.table.value) ); - if (p.lower_bound.size()) { + if( p.lower_bound.size() ) { uint64_t scope = convert_to_type(p.lower_bound, "lower_bound scope"); - lower = idx.lower_bound( boost::make_tuple(p.code, scope, p.table)); - } else { - lower = idx.lower_bound(boost::make_tuple(p.code, 0, p.table)); + std::get<1>(lower_bound_lookup_tuple) = scope; } - if (p.upper_bound.size()) { + + if( p.upper_bound.size() ) { uint64_t scope = convert_to_type(p.upper_bound, "upper_bound scope"); - upper = idx.lower_bound( boost::make_tuple(p.code, scope, 0)); - } else { - upper = idx.lower_bound(boost::make_tuple((uint64_t)p.code + 1, 0, 0)); + std::get<1>(upper_bound_lookup_tuple) = scope; } - auto end = fc::time_point::now() + fc::microseconds(1000 * 10); /// 10ms max time - unsigned int count = 0; - auto itr = lower; - read_only::get_table_by_scope_result result; - for (; itr != upper; ++itr) { - if (p.table && itr->table != p.table) { - if (fc::time_point::now() > end) { - break; - } - continue; + if( upper_bound_lookup_tuple < lower_bound_lookup_tuple ) + return result; + + auto walk_table_range = [&]( auto itr, auto end_itr ) { + auto cur_time = fc::time_point::now(); + auto end_time = cur_time + fc::microseconds(1000 * 10); /// 10ms max time + for( unsigned int count = 0; cur_time <= end_time && count < p.limit && itr != end_itr; ++itr, cur_time = fc::time_point::now() ) { + if( p.table && itr->table != p.table ) continue; + + result.rows.push_back( {itr->code, itr->scope, itr->table, itr->payer, itr->count} ); + + ++count; } - result.rows.push_back({itr->code, itr->scope, itr->table, itr->payer, itr->count}); - if (++count == p.limit || fc::time_point::now() > end) { - ++itr; - break; + if( itr != end_itr ) { + result.more = string(itr->scope); } + }; + + auto lower = idx.lower_bound( lower_bound_lookup_tuple ); + auto upper = idx.upper_bound( upper_bound_lookup_tuple ); + if( p.reverse && *p.reverse ) { + walk_table_range( boost::make_reverse_iterator(upper), boost::make_reverse_iterator(lower) ); + } else { + walk_table_range( lower, upper ); } - if (itr != upper) { - result.more = (string)itr->scope; - } + return result; } vector read_only::get_currency_balance( const read_only::get_currency_balance_params& p )const { const abi_def abi = eosio::chain_apis::get_abi( db, p.code ); - auto table_type = get_table_type( abi, "accounts" ); + (void)get_table_type( abi, "accounts" ); vector results; walk_key_value_table(p.code, p.account, N(accounts), [&](const key_value_object& obj){ @@ -1237,7 +1291,7 @@ fc::variant read_only::get_currency_stats( const read_only::get_currency_stats_p fc::mutable_variant_object results; const abi_def abi = eosio::chain_apis::get_abi( db, p.code ); - auto table_type = get_table_type( abi, "stat" ); + (void)get_table_type( abi, "stat" ); uint64_t scope = ( eosio::chain::string_to_symbol( 0, boost::algorithm::to_upper_copy(p.symbol).c_str() ) >> 8 ); @@ -1485,9 +1539,9 @@ fc::variant read_only::get_block_header_state(const get_block_header_state_param return vo; } -void read_write::push_block(const read_write::push_block_params& params, next_function next) { +void read_write::push_block(read_write::push_block_params&& params, next_function next) { try { - app().get_method()(std::make_shared(params)); + app().get_method()(std::make_shared(std::move(params))); next(read_write::push_block_results{}); } catch ( boost::interprocess::bad_alloc& ) { chain_plugin::handle_db_exhaustion(); @@ -1499,18 +1553,19 @@ void read_write::push_transaction(const read_write::push_transaction_params& par try { auto pretty_input = std::make_shared(); auto resolver = make_resolver(this, abi_serializer_max_time); + transaction_metadata_ptr ptrx; try { abi_serializer::from_variant(params, *pretty_input, resolver, abi_serializer_max_time); + ptrx = std::make_shared( pretty_input ); } EOS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction") - app().get_method()(pretty_input, true, [this, next](const fc::static_variant& result) -> void{ + app().get_method()(ptrx, true, [this, next](const fc::static_variant& result) -> void{ if (result.contains()) { next(result.get()); } else { auto trx_trace_ptr = result.get(); try { - chain::transaction_id_type id = trx_trace_ptr->id; fc::variant output; try { output = db.to_variant_with_abi( *trx_trace_ptr, abi_serializer_max_time ); @@ -1518,6 +1573,7 @@ void read_write::push_transaction(const read_write::push_transaction_params& par output = *trx_trace_ptr; } + const chain::transaction_id_type& id = trx_trace_ptr->id; next(read_write::push_transaction_results{id, output}); } CATCH_AND_CALL(next); } @@ -1585,17 +1641,12 @@ read_only::get_code_results read_only::get_code( const get_code_params& params ) EOS_ASSERT( params.code_as_wasm, unsupported_feature, "Returning WAST from get_code is no longer supported" ); if( accnt.code.size() ) { - if (params.code_as_wasm) { - result.wasm = string(accnt.code.begin(), accnt.code.end()); - } else { - result.wast = wasm_to_wast( (const uint8_t*)accnt.code.data(), accnt.code.size(), true ); - } + result.wasm = string(accnt.code.begin(), accnt.code.end()); result.code_hash = fc::sha256::hash( accnt.code.data(), accnt.code.size() ); } abi_def abi; if( abi_serializer::to_abi(accnt.abi, abi) ) { - result.abi = std::move(abi); } @@ -1693,7 +1744,7 @@ read_only::get_account_results read_only::get_account( const get_account_params& auto core_symbol = extract_core_symbol(); - if (params.expected_core_symbol.valid()) + if (params.expected_core_symbol.valid()) core_symbol = *(params.expected_core_symbol); const auto* t_id = d.find(boost::make_tuple( token_code, params.account_name, N(accounts) )); diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 0b69a6af89a..4a41d99455c 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include @@ -55,7 +55,7 @@ struct permission { template struct resolver_factory; -// see specialization for uint64_t in source file +// see specializations for uint64_t and double in source file template Type convert_to_type(const string& str, const string& desc) { try { @@ -66,6 +66,9 @@ Type convert_to_type(const string& str, const string& desc) { template<> uint64_t convert_to_type(const string& str, const string& desc); +template<> +double convert_to_type(const string& str, const string& desc); + class read_only { const controller& db; const fc::microseconds abi_serializer_max_time; @@ -269,6 +272,8 @@ class read_only { string key_type; // type of key specified by index_position string index_position; // 1 - primary (first), 2 - secondary index (in order defined by multi_index), 3 - third index, etc string encode_type{"dec"}; //dec, hex , default=dec + optional reverse; + optional show_payer; // show RAM pyer }; struct get_table_rows_result { @@ -284,6 +289,7 @@ class read_only { string lower_bound; // lower bound of scope, optional string upper_bound; // upper bound of scope, optional uint32_t limit = 10; + optional reverse; }; struct get_table_by_scope_result_row { name code; @@ -398,58 +404,78 @@ class read_only { const uint64_t table_with_index = get_table_index_name(p, primary); const auto* t_id = d.find(boost::make_tuple(p.code, scope, p.table)); const auto* index_t_id = d.find(boost::make_tuple(p.code, scope, table_with_index)); - if (t_id != nullptr && index_t_id != nullptr) { - const auto& secidx = d.get_index(); - decltype(index_t_id->id) low_tid(index_t_id->id._id); - decltype(index_t_id->id) next_tid(index_t_id->id._id + 1); - auto lower = secidx.lower_bound(boost::make_tuple(low_tid)); - auto upper = secidx.lower_bound(boost::make_tuple(next_tid)); + if( t_id != nullptr && index_t_id != nullptr ) { + using secondary_key_type = std::result_of_t; + static_assert( std::is_same::value, "Return type of conv does not match type of secondary key for IndexType" ); - if (p.lower_bound.size()) { - if (p.key_type == "name") { + const auto& secidx = d.get_index(); + auto lower_bound_lookup_tuple = std::make_tuple( index_t_id->id._id, + eosio::chain::secondary_key_traits::true_lowest(), + std::numeric_limits::lowest() ); + auto upper_bound_lookup_tuple = std::make_tuple( index_t_id->id._id, + eosio::chain::secondary_key_traits::true_highest(), + std::numeric_limits::max() ); + + if( p.lower_bound.size() ) { + if( p.key_type == "name" ) { name s(p.lower_bound); SecKeyType lv = convert_to_type( s.to_string(), "lower_bound name" ); // avoids compiler error - lower = secidx.lower_bound( boost::make_tuple( low_tid, conv( lv ))); + std::get<1>(lower_bound_lookup_tuple) = conv( lv ); } else { SecKeyType lv = convert_to_type( p.lower_bound, "lower_bound" ); - lower = secidx.lower_bound( boost::make_tuple( low_tid, conv( lv ))); + std::get<1>(lower_bound_lookup_tuple) = conv( lv ); } } - if (p.upper_bound.size()) { - if (p.key_type == "name") { + + if( p.upper_bound.size() ) { + if( p.key_type == "name" ) { name s(p.upper_bound); SecKeyType uv = convert_to_type( s.to_string(), "upper_bound name" ); - upper = secidx.lower_bound( boost::make_tuple( low_tid, conv( uv ))); + std::get<1>(upper_bound_lookup_tuple) = conv( uv ); } else { SecKeyType uv = convert_to_type( p.upper_bound, "upper_bound" ); - upper = secidx.lower_bound( boost::make_tuple( low_tid, conv( uv ))); + std::get<1>(upper_bound_lookup_tuple) = conv( uv ); } } - vector data; - - auto end = fc::time_point::now() + fc::microseconds(1000 * 10); /// 10ms max time - - unsigned int count = 0; - auto itr = lower; - for (; itr != upper; ++itr) { - - const auto* itr2 = d.find(boost::make_tuple(t_id->id, itr->primary_key)); - if (itr2 == nullptr) continue; - copy_inline_row(*itr2, data); - - if (p.json) { - result.rows.emplace_back( abis.binary_to_variant( abis.get_table_type(p.table), data, abi_serializer_max_time, shorten_abi_errors ) ); - } else { - result.rows.emplace_back(fc::variant(data)); + if( upper_bound_lookup_tuple < lower_bound_lookup_tuple ) + return result; + + auto walk_table_row_range = [&]( auto itr, auto end_itr ) { + auto cur_time = fc::time_point::now(); + auto end_time = cur_time + fc::microseconds(1000 * 10); /// 10ms max time + vector data; + for( unsigned int count = 0; cur_time <= end_time && count < p.limit && itr != end_itr; ++itr, cur_time = fc::time_point::now() ) { + const auto* itr2 = d.find( boost::make_tuple(t_id->id, itr->primary_key) ); + if( itr2 == nullptr ) continue; + copy_inline_row(*itr2, data); + + fc::variant data_var; + if( p.json ) { + data_var = abis.binary_to_variant( abis.get_table_type(p.table), data, abi_serializer_max_time, shorten_abi_errors ); + } else { + data_var = fc::variant( data ); + } + + if( p.show_payer && *p.show_payer ) { + result.rows.emplace_back( fc::mutable_variant_object("data", std::move(data_var))("payer", itr->payer) ); + } else { + result.rows.emplace_back( std::move(data_var) ); + } + + ++count; } - - if (++count == p.limit || fc::time_point::now() > end) { - break; + if( itr != end_itr ) { + result.more = true; } - } - if (itr != upper) { - result.more = true; + }; + + auto lower = secidx.lower_bound( lower_bound_lookup_tuple ); + auto upper = secidx.upper_bound( upper_bound_lookup_tuple ); + if( p.reverse && *p.reverse ) { + walk_table_row_range( boost::make_reverse_iterator(upper), boost::make_reverse_iterator(lower) ); + } else { + walk_table_row_range( lower, upper ); } } return result; @@ -465,53 +491,65 @@ class read_only { abi_serializer abis; abis.set_abi(abi, abi_serializer_max_time); const auto* t_id = d.find(boost::make_tuple(p.code, scope, p.table)); - if (t_id != nullptr) { + if( t_id != nullptr ) { const auto& idx = d.get_index(); - decltype(t_id->id) next_tid(t_id->id._id + 1); - auto lower = idx.lower_bound(boost::make_tuple(t_id->id)); - auto upper = idx.lower_bound(boost::make_tuple(next_tid)); + auto lower_bound_lookup_tuple = std::make_tuple( t_id->id, std::numeric_limits::lowest() ); + auto upper_bound_lookup_tuple = std::make_tuple( t_id->id, std::numeric_limits::max() ); - if (p.lower_bound.size()) { - if (p.key_type == "name") { + if( p.lower_bound.size() ) { + if( p.key_type == "name" ) { name s(p.lower_bound); - lower = idx.lower_bound( boost::make_tuple( t_id->id, s.value )); + std::get<1>(lower_bound_lookup_tuple) = s.value; } else { auto lv = convert_to_type( p.lower_bound, "lower_bound" ); - lower = idx.lower_bound( boost::make_tuple( t_id->id, lv )); + std::get<1>(lower_bound_lookup_tuple) = lv; } } - if (p.upper_bound.size()) { - if (p.key_type == "name") { + + if( p.upper_bound.size() ) { + if( p.key_type == "name" ) { name s(p.upper_bound); - upper = idx.lower_bound( boost::make_tuple( t_id->id, s.value )); + std::get<1>(upper_bound_lookup_tuple) = s.value; } else { auto uv = convert_to_type( p.upper_bound, "upper_bound" ); - upper = idx.lower_bound( boost::make_tuple( t_id->id, uv )); + std::get<1>(upper_bound_lookup_tuple) = uv; } } - vector data; - - auto end = fc::time_point::now() + fc::microseconds(1000 * 10); /// 10ms max time - - unsigned int count = 0; - auto itr = lower; - for (; itr != upper; ++itr) { - copy_inline_row(*itr, data); - - if (p.json) { - result.rows.emplace_back( abis.binary_to_variant( abis.get_table_type(p.table), data, abi_serializer_max_time, shorten_abi_errors ) ); - } else { - result.rows.emplace_back(fc::variant(data)); + if( upper_bound_lookup_tuple < lower_bound_lookup_tuple ) + return result; + + auto walk_table_row_range = [&]( auto itr, auto end_itr ) { + auto cur_time = fc::time_point::now(); + auto end_time = cur_time + fc::microseconds(1000 * 10); /// 10ms max time + vector data; + for( unsigned int count = 0; cur_time <= end_time && count < p.limit && itr != end_itr; ++count, ++itr, cur_time = fc::time_point::now() ) { + copy_inline_row(*itr, data); + + fc::variant data_var; + if( p.json ) { + data_var = abis.binary_to_variant( abis.get_table_type(p.table), data, abi_serializer_max_time, shorten_abi_errors ); + } else { + data_var = fc::variant( data ); + } + + if( p.show_payer && *p.show_payer ) { + result.rows.emplace_back( fc::mutable_variant_object("data", std::move(data_var))("payer", itr->payer) ); + } else { + result.rows.emplace_back( std::move(data_var) ); + } } - - if (++count == p.limit || fc::time_point::now() > end) { - ++itr; - break; + if( itr != end_itr ) { + result.more = true; } - } - if (itr != upper) { - result.more = true; + }; + + auto lower = idx.lower_bound( lower_bound_lookup_tuple ); + auto upper = idx.upper_bound( upper_bound_lookup_tuple ); + if( p.reverse && *p.reverse ) { + walk_table_row_range( boost::make_reverse_iterator(upper), boost::make_reverse_iterator(lower) ); + } else { + walk_table_row_range( lower, upper ); } } return result; @@ -531,7 +569,7 @@ class read_write { using push_block_params = chain::signed_block; using push_block_results = empty; - void push_block(const push_block_params& params, chain::plugin_interface::next_function next); + void push_block(push_block_params&& params, chain::plugin_interface::next_function next); using push_transaction_params = fc::variant_object; struct push_transaction_results { @@ -622,10 +660,11 @@ class chain_plugin : public plugin { void plugin_shutdown(); chain_apis::read_only get_read_only_api() const { return chain_apis::read_only(chain(), get_abi_serializer_max_time()); } - chain_apis::read_write get_read_write_api(); + chain_apis::read_write get_read_write_api() { return chain_apis::read_write(chain(), get_abi_serializer_max_time()); } void accept_block( const chain::signed_block_ptr& block ); void accept_transaction(const chain::packed_transaction& trx, chain::plugin_interface::next_function next); + void accept_transaction(const chain::transaction_metadata_ptr& trx, chain::plugin_interface::next_function next); bool block_is_on_preferred_chain(const chain::block_id_type& block_id); @@ -672,10 +711,10 @@ FC_REFLECT(eosio::chain_apis::read_only::get_block_header_state_params, (block_n FC_REFLECT( eosio::chain_apis::read_write::push_transaction_results, (transaction_id)(processed) ) -FC_REFLECT( eosio::chain_apis::read_only::get_table_rows_params, (json)(code)(scope)(table)(table_key)(lower_bound)(upper_bound)(limit)(key_type)(index_position)(encode_type) ) +FC_REFLECT( eosio::chain_apis::read_only::get_table_rows_params, (json)(code)(scope)(table)(table_key)(lower_bound)(upper_bound)(limit)(key_type)(index_position)(encode_type)(reverse)(show_payer) ) FC_REFLECT( eosio::chain_apis::read_only::get_table_rows_result, (rows)(more) ); -FC_REFLECT( eosio::chain_apis::read_only::get_table_by_scope_params, (code)(table)(lower_bound)(upper_bound)(limit) ) +FC_REFLECT( eosio::chain_apis::read_only::get_table_by_scope_params, (code)(table)(lower_bound)(upper_bound)(limit)(reverse) ) FC_REFLECT( eosio::chain_apis::read_only::get_table_by_scope_result_row, (code)(scope)(table)(payer)(count)); FC_REFLECT( eosio::chain_apis::read_only::get_table_by_scope_result, (rows)(more) ); diff --git a/plugins/db_size_api_plugin/db_size_api_plugin.cpp b/plugins/db_size_api_plugin/db_size_api_plugin.cpp index 13b717c0789..8eed8b388ed 100644 --- a/plugins/db_size_api_plugin/db_size_api_plugin.cpp +++ b/plugins/db_size_api_plugin/db_size_api_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/plugins/db_size_api_plugin/include/eosio/db_size_api_plugin/db_size_api_plugin.hpp b/plugins/db_size_api_plugin/include/eosio/db_size_api_plugin/db_size_api_plugin.hpp index 2b0b46bc7ff..54a2d8ef63b 100644 --- a/plugins/db_size_api_plugin/include/eosio/db_size_api_plugin/db_size_api_plugin.hpp +++ b/plugins/db_size_api_plugin/include/eosio/db_size_api_plugin/db_size_api_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp b/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp index 55cbf8eb861..d6f8f53e7b3 100644 --- a/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp +++ b/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp @@ -1,10 +1,9 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include -#include #include #include diff --git a/plugins/faucet_testnet_plugin/include/eosio/faucet_testnet_plugin/faucet_testnet_plugin.hpp b/plugins/faucet_testnet_plugin/include/eosio/faucet_testnet_plugin/faucet_testnet_plugin.hpp index 849745044a1..f59b1ef9bb3 100644 --- a/plugins/faucet_testnet_plugin/include/eosio/faucet_testnet_plugin/faucet_testnet_plugin.hpp +++ b/plugins/faucet_testnet_plugin/include/eosio/faucet_testnet_plugin/faucet_testnet_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/plugins/history_api_plugin/history_api_plugin.cpp b/plugins/history_api_plugin/history_api_plugin.cpp index 286e97f6e54..67321fa58d0 100644 --- a/plugins/history_api_plugin/history_api_plugin.cpp +++ b/plugins/history_api_plugin/history_api_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include @@ -32,12 +32,15 @@ void history_api_plugin::plugin_initialize(const variables_map&) {} }} #define CHAIN_RO_CALL(call_name) CALL(history, ro_api, history_apis::read_only, call_name) +//#define CHAIN_RW_CALL(call_name) CALL(history, rw_api, history_apis::read_write, call_name) void history_api_plugin::plugin_startup() { ilog( "starting history_api_plugin" ); auto ro_api = app().get_plugin().get_read_only_api(); + //auto rw_api = app().get_plugin().get_read_write_api(); app().get_plugin().add_api({ +// CHAIN_RO_CALL(get_transaction), CHAIN_RO_CALL(get_actions), CHAIN_RO_CALL(get_transaction), CHAIN_RO_CALL(get_block_detail), diff --git a/plugins/history_api_plugin/include/eosio/history_api_plugin/history_api_plugin.hpp b/plugins/history_api_plugin/include/eosio/history_api_plugin/history_api_plugin.hpp index 52ac764a45d..5e6dd936e24 100644 --- a/plugins/history_api_plugin/include/eosio/history_api_plugin/history_api_plugin.hpp +++ b/plugins/history_api_plugin/include/eosio/history_api_plugin/history_api_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/plugins/history_plugin/history_plugin.cpp b/plugins/history_plugin/history_plugin.cpp index f3838726726..5ce12dba17f 100644 --- a/plugins/history_plugin/history_plugin.cpp +++ b/plugins/history_plugin/history_plugin.cpp @@ -505,10 +505,9 @@ namespace eosio { for (const auto &receipt: blk->transactions) { if (receipt.trx.contains()) { auto &pt = receipt.trx.get(); - auto mtrx = transaction_metadata(pt); - if (mtrx.id == result.id) { + if (pt.id() == result.id) { fc::mutable_variant_object r("receipt", receipt); - r("trx", chain.to_variant_with_abi(mtrx.trx, abi_serializer_max_time)); + r("trx", chain.to_variant_with_abi(pt.get_signed_transaction(), abi_serializer_max_time)); result.trx = move(r); break; } @@ -529,14 +528,14 @@ namespace eosio { for (const auto& receipt: blk->transactions) { if (receipt.trx.contains()) { auto& pt = receipt.trx.get(); - auto mtrx = transaction_metadata(pt); - if( txn_id_matched(mtrx.id) ) { - result.id = mtrx.id; + const auto& id = pt.id(); + if( txn_id_matched(id) ) { + result.id = id; result.last_irreversible_block = chain.last_irreversible_block_num(); result.block_num = *p.block_num_hint; result.block_time = blk->timestamp; fc::mutable_variant_object r("receipt", receipt); - r("trx", chain.to_variant_with_abi(mtrx.trx, abi_serializer_max_time)); + r("trx", chain.to_variant_with_abi(pt.get_signed_transaction(), abi_serializer_max_time)); result.trx = move(r); found = true; break; diff --git a/plugins/history_plugin/include/eosio/history_plugin/account_control_history_object.hpp b/plugins/history_plugin/include/eosio/history_plugin/account_control_history_object.hpp index 55aec70abe5..5005c279f5a 100644 --- a/plugins/history_plugin/include/eosio/history_plugin/account_control_history_object.hpp +++ b/plugins/history_plugin/include/eosio/history_plugin/account_control_history_object.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/plugins/history_plugin/include/eosio/history_plugin/history_plugin.hpp b/plugins/history_plugin/include/eosio/history_plugin/history_plugin.hpp index 838f9b24662..337bf97c239 100644 --- a/plugins/history_plugin/include/eosio/history_plugin/history_plugin.hpp +++ b/plugins/history_plugin/include/eosio/history_plugin/history_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/plugins/history_plugin/include/eosio/history_plugin/public_key_history_object.hpp b/plugins/history_plugin/include/eosio/history_plugin/public_key_history_object.hpp index 996aff7c04b..2e8e37f0049 100644 --- a/plugins/history_plugin/include/eosio/history_plugin/public_key_history_object.hpp +++ b/plugins/history_plugin/include/eosio/history_plugin/public_key_history_object.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/plugins/http_client_plugin/http_client_plugin.cpp b/plugins/http_client_plugin/http_client_plugin.cpp index dc27ac34681..cb9d7c8e580 100644 --- a/plugins/http_client_plugin/http_client_plugin.cpp +++ b/plugins/http_client_plugin/http_client_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/plugins/http_client_plugin/include/eosio/http_client_plugin/http_client_plugin.hpp b/plugins/http_client_plugin/include/eosio/http_client_plugin/http_client_plugin.hpp index b4bb8a5740e..95803bed1f8 100644 --- a/plugins/http_client_plugin/include/eosio/http_client_plugin/http_client_plugin.hpp +++ b/plugins/http_client_plugin/include/eosio/http_client_plugin/http_client_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/plugins/http_plugin/http_plugin.cpp b/plugins/http_plugin/http_plugin.cpp index d9be006bb45..c808c5bb99f 100644 --- a/plugins/http_plugin/http_plugin.cpp +++ b/plugins/http_plugin/http_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include @@ -548,6 +548,8 @@ namespace eosio { my->server.stop_listening(); if(my->https_server.is_listening()) my->https_server.stop_listening(); + if(my->unix_server.is_listening()) + my->unix_server.stop_listening(); } void http_plugin::add_handler(const string& url, const url_handler& handler) { @@ -561,6 +563,9 @@ namespace eosio { try { try { throw; + } catch (chain::unknown_block_exception& e) { + error_results results{400, "Unknown Block", error_results::error_info(e, verbose_http_errors)}; + cb( 400, fc::json::to_string( results )); } catch (chain::unsatisfied_authorization& e) { error_results results{401, "UnAuthorized", error_results::error_info(e, verbose_http_errors)}; cb( 401, fc::json::to_string( results )); diff --git a/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp b/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp index 7f9aedb01e4..c7bc1ebb2b6 100644 --- a/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp +++ b/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/plugins/login_plugin/include/eosio/login_plugin/login_plugin.hpp b/plugins/login_plugin/include/eosio/login_plugin/login_plugin.hpp index 0bd5d59efed..29c2660c6f3 100644 --- a/plugins/login_plugin/include/eosio/login_plugin/login_plugin.hpp +++ b/plugins/login_plugin/include/eosio/login_plugin/login_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/plugins/login_plugin/login_plugin.cpp b/plugins/login_plugin/login_plugin.cpp index 5a7bc5eae3e..0aeac67dce4 100644 --- a/plugins/login_plugin/login_plugin.cpp +++ b/plugins/login_plugin/login_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/plugins/mongo_db_plugin/include/eosio/mongo_db_plugin/mongo_db_plugin.hpp b/plugins/mongo_db_plugin/include/eosio/mongo_db_plugin/mongo_db_plugin.hpp index b9456898b6d..3b636651056 100644 --- a/plugins/mongo_db_plugin/include/eosio/mongo_db_plugin/mongo_db_plugin.hpp +++ b/plugins/mongo_db_plugin/include/eosio/mongo_db_plugin/mongo_db_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/plugins/mongo_db_plugin/mongo_db_plugin.cpp b/plugins/mongo_db_plugin/mongo_db_plugin.cpp index 3ef0ee252ac..70327c3d96b 100644 --- a/plugins/mongo_db_plugin/mongo_db_plugin.cpp +++ b/plugins/mongo_db_plugin/mongo_db_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include @@ -570,6 +570,15 @@ void handle_mongo_exception( const std::string& desc, int line_num ) { } } +// custom oid to avoid monotonic throttling +// https://docs.mongodb.com/master/core/bulk-write-operations/#avoid-monotonic-throttling +bsoncxx::oid make_custom_oid() { + bsoncxx::oid x = bsoncxx::oid(); + const char* p = x.bytes(); + std::swap((short&)p[0], (short&)p[10]); + return x; +} + } // anonymous namespace void mongo_db_plugin_impl::purge_abi_cache() { @@ -725,7 +734,7 @@ void mongo_db_plugin_impl::_process_accepted_transaction( const chain::transacti using bsoncxx::builder::basic::make_array; namespace bbb = bsoncxx::builder::basic; - const auto& trx = t->trx; + const signed_transaction& trx = t->packed_trx->get_signed_transaction(); if( !filter_include( trx ) ) return; @@ -761,9 +770,10 @@ void mongo_db_plugin_impl::_process_accepted_transaction( const chain::transacti if( t->signing_keys.valid() ) { signing_keys_json = fc::json::to_string( t->signing_keys->second ); } else { - auto signing_keys = trx.get_signature_keys( *chain_id, false, false ); - if( !signing_keys.empty() ) { - signing_keys_json = fc::json::to_string( signing_keys ); + flat_set keys; + trx.get_signature_keys( *chain_id, fc::time_point::maximum(), keys, false ); + if( !keys.empty() ) { + signing_keys_json = fc::json::to_string( keys ); } } @@ -818,6 +828,9 @@ mongo_db_plugin_impl::add_action_trace( mongocxx::bulk_write& bulk_action_traces auto action_traces_doc = bsoncxx::builder::basic::document{}; const chain::base_action_trace& base = atrace; // without inline action traces + // improve data distributivity when using mongodb sharding + action_traces_doc.append( kvp( "_id", make_custom_oid() ) ); + auto v = to_variant_with_abi( base ); string json = fc::json::to_string( v ); try { @@ -1082,11 +1095,8 @@ void mongo_db_plugin_impl::_process_irreversible_block(const chain::block_state_ string trx_id_str; if( receipt.trx.contains() ) { const auto& pt = receipt.trx.get(); - // get id via get_raw_transaction() as packed_transaction.id() mutates internal transaction state - const auto& raw = pt.get_raw_transaction(); - const auto& trx = fc::raw::unpack( raw ); - if( !filter_include( trx ) ) continue; - const auto& id = trx.id(); + if( !filter_include( pt.get_signed_transaction() ) ) continue; + const auto& id = pt.id(); trx_id_str = id.str(); } else { const auto& id = receipt.trx.get(); @@ -1426,7 +1436,7 @@ void mongo_db_plugin_impl::init() { // action traces indexes auto action_traces = mongo_conn[db_name][action_traces_col]; - action_traces.create_index( bsoncxx::from_json( R"xxx({ "trx_id" : 1 })xxx" )); + action_traces.create_index( bsoncxx::from_json( R"xxx({ "block_num" : 1 })xxx" )); // pub_keys indexes auto pub_keys = mongo_conn[db_name][pub_keys_col]; diff --git a/plugins/net_api_plugin/include/eosio/net_api_plugin/net_api_plugin.hpp b/plugins/net_api_plugin/include/eosio/net_api_plugin/net_api_plugin.hpp index 57c5929777e..3c7e1e232ac 100644 --- a/plugins/net_api_plugin/include/eosio/net_api_plugin/net_api_plugin.hpp +++ b/plugins/net_api_plugin/include/eosio/net_api_plugin/net_api_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/plugins/net_api_plugin/net_api_plugin.cpp b/plugins/net_api_plugin/net_api_plugin.cpp index caa31bdad63..3b7327c4313 100644 --- a/plugins/net_api_plugin/net_api_plugin.cpp +++ b/plugins/net_api_plugin/net_api_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp b/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp index 2c7683ccb5e..d732b18cf0c 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index bbdd357eec7..76f11da2411 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include @@ -147,11 +147,10 @@ struct request_p2p_message{ notice_message, request_message, sync_request_message, - signed_block, - packed_transaction, + signed_block, // which = 7 + packed_transaction, // which = 8 response_p2p_message, request_p2p_message>; - } // namespace eosio FC_REFLECT( eosio::select_ids, (mode)(pending)(ids) ) diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 8283c5c9320..889eefb9ed0 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -19,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -27,7 +25,6 @@ #include #include #include -#include using namespace eosio::chain::plugin_interface::compat; @@ -43,13 +40,11 @@ namespace eosio { using boost::asio::ip::tcp; using boost::asio::ip::address_v4; using boost::asio::ip::host_name; - using boost::intrusive::rbtree; using boost::multi_index_container; using fc::time_point; using fc::time_point_sec; using eosio::chain::transaction_id_type; - namespace bip = boost::interprocess; class connection; @@ -61,40 +56,24 @@ namespace eosio { using socket_ptr = std::shared_ptr; - using net_message_ptr = shared_ptr; - struct node_transaction_state { transaction_id_type id; time_point_sec expires; /// time after which this may be purged. - /// Expires increased while the txn is - /// "in flight" to anoher peer - packed_transaction packed_txn; - vector serialized_txn; /// the received raw bundle uint32_t block_num = 0; /// block transaction was included in - uint32_t true_block = 0; /// used to reset block_uum when request is 0 - uint16_t requests = 0; /// the number of "in flight" requests for this txn + std::shared_ptr> serialized_txn; /// the received raw bundle }; - struct update_in_flight { - int32_t incr; - update_in_flight (int32_t delta) : incr (delta) {} - void operator() (node_transaction_state& nts) { - int32_t exp = nts.expires.sec_since_epoch(); - nts.expires = fc::time_point_sec (exp + incr * 60); - if( nts.requests == 0 ) { - nts.true_block = nts.block_num; - nts.block_num = 0; - } - nts.requests += incr; - if( nts.requests == 0 ) { - nts.block_num = nts.true_block; - } - } - } incr_in_flight(1), decr_in_flight(-1); - struct by_expiry; struct by_block_num; + struct sha256_less { + bool operator()( const sha256& lhs, const sha256& rhs ) const { + return + std::tie(lhs._hash[0], lhs._hash[1], lhs._hash[2], lhs._hash[3]) < + std::tie(rhs._hash[0], rhs._hash[1], rhs._hash[2], rhs._hash[3]); + } + }; + typedef multi_index_container< node_transaction_state, indexed_by< @@ -102,7 +81,8 @@ namespace eosio { tag< by_id >, member < node_transaction_state, transaction_id_type, - &node_transaction_state::id > >, + &node_transaction_state::id >, + sha256_less >, ordered_non_unique< tag< by_expiry >, member< node_transaction_state, @@ -150,7 +130,7 @@ namespace eosio { }; possible_connections allowed_connections{None}; - connection_ptr find_connection( string host )const; + connection_ptr find_connection(const string& host)const; std::set< connection_ptr > connections; bool done = false; @@ -174,6 +154,7 @@ namespace eosio { string user_agent_name; chain_plugin* chain_plug = nullptr; + producer_plugin* producer_plug = nullptr; int started_sessions = 0; node_transaction_index local_txns; @@ -184,34 +165,30 @@ namespace eosio { channels::transaction_ack::channel_type::handle incoming_transaction_ack_subscription; - void connect( connection_ptr c ); - void connect( connection_ptr c, tcp::resolver::iterator endpoint_itr ); - bool start_session( connection_ptr c ); - void start_listen_loop( ); - void start_read_message( connection_ptr c); + void connect(const connection_ptr& c); + void connect(const connection_ptr& c, tcp::resolver::iterator endpoint_itr); + bool start_session(const connection_ptr& c); + void start_listen_loop(); + void start_read_message(const connection_ptr& c); - void close( connection_ptr c ); + void close(const connection_ptr& c); size_t count_open_sockets() const; template - void send_all( const net_message &msg, VerifierFunc verify ); + void send_all( const std::shared_ptr>& send_buffer, VerifierFunc verify ); - void accepted_block_header(const block_state_ptr&); void accepted_block(const block_state_ptr&); - void irreversible_block(const block_state_ptr&); - void accepted_transaction(const transaction_metadata_ptr&); - void applied_transaction(const transaction_trace_ptr&); - void accepted_confirmation(const header_confirmation&); - - void transaction_ack(const std::pair&); + void transaction_ack(const std::pair&); bool is_valid( const handshake_message &msg); + void send_p2p_request(connection_ptr c); - void handle_message( connection_ptr c, const handshake_message &msg); - void handle_message( connection_ptr c, const chain_size_message &msg); - void handle_message( connection_ptr c, const go_away_message &msg ); + void handle_message(const connection_ptr& c, const handshake_message& msg); + void handle_message(const connection_ptr& c, const chain_size_message& msg); + void handle_message(const connection_ptr& c, const go_away_message& msg ); + /** \name Peer Timestamps * Time message handling * @{ @@ -225,21 +202,24 @@ namespace eosio { * floating-double arithmetic with rounding done by the hardware. * This is necessary in order to avoid overflow and preserve precision. */ - void handle_message( connection_ptr c, const time_message &msg); + void handle_message(const connection_ptr& c, const time_message& msg); /** @} */ - void handle_message( connection_ptr c, const notice_message &msg); - void handle_message( connection_ptr c, const request_message &msg); - void handle_message( connection_ptr c, const sync_request_message &msg); - void handle_message( connection_ptr c, const signed_block &msg); - void handle_message( connection_ptr c, const packed_transaction &msg); + void handle_message(const connection_ptr& c, const notice_message& msg); + void handle_message(const connection_ptr& c, const request_message& msg); + void handle_message(const connection_ptr& c, const sync_request_message& msg); + void handle_message(const connection_ptr& c, const signed_block& msg) = delete; // signed_block_ptr overload used instead + void handle_message(const connection_ptr& c, const signed_block_ptr& msg); + void handle_message(const connection_ptr& c, const packed_transaction& msg) = delete; // packed_transaction_ptr overload used instead + void handle_message(const connection_ptr& c, const packed_transaction_ptr& msg); void handle_message( connection_ptr c, const request_p2p_message &msg); void handle_message( connection_ptr c, const response_p2p_message &msg); void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); - void start_txn_timer( ); - void start_monitors( ); + void start_txn_timer(); + void start_monitors(); - void expire_txns( ); + void expire_txns(); + void expire_local_txns(); void connection_monitor(std::weak_ptr from_connection); /** \name Peer Timestamps * Time message handling @@ -319,14 +299,16 @@ namespace eosio { */ constexpr auto def_send_buffer_size_mb = 4; constexpr auto def_send_buffer_size = 1024*1024*def_send_buffer_size_mb; + constexpr auto def_max_write_queue_size = def_send_buffer_size*10; + constexpr boost::asio::chrono::milliseconds def_read_delay_for_full_write_queue{100}; + constexpr auto def_max_reads_in_flight = 1000; + constexpr auto def_max_trx_in_progress_size = 100*1024*1024; // 100 MB constexpr auto def_max_clients = 25; // 0 for unlimited clients constexpr auto def_max_nodes_per_host = 1; constexpr auto def_conn_retry_wait = 30; constexpr auto def_txn_expire_wait = std::chrono::seconds(3); constexpr auto def_resp_expected_wait = std::chrono::seconds(5); constexpr auto def_sync_fetch_span = 100; - constexpr uint32_t def_max_just_send = 1500; // roughly 1 "mtu" - constexpr bool large_msg_notify = false; constexpr auto message_header_size = 4; @@ -353,34 +335,16 @@ namespace eosio { constexpr uint16_t net_version = proto_explicit_sync; - /** - * Index by id - * Index by is_known, block_num, validated_time, this is the order we will broadcast - * to peer. - * Index by is_noticed, validated_time - * - */ struct transaction_state { transaction_id_type id; - bool is_known_by_peer = false; ///< true if we sent or received this trx to this peer or received notice from peer - bool is_noticed_to_peer = false; ///< have we sent peer notice we know it (true if we receive from this peer) uint32_t block_num = 0; ///< the block number the transaction was included in time_point_sec expires; - time_point requested_time; /// in case we fetch large trx - }; - - struct update_txn_expiry { - time_point_sec new_expiry; - update_txn_expiry(time_point_sec e) : new_expiry(e) {} - void operator() (transaction_state& ts) { - ts.expires = new_expiry; - } }; typedef multi_index_container< transaction_state, indexed_by< - ordered_unique< tag, member >, + ordered_unique< tag, member, sha256_less >, ordered_non_unique< tag< by_expiry >, member< transaction_state,fc::time_point_sec,&transaction_state::expires >>, ordered_non_unique< tag, @@ -403,10 +367,7 @@ namespace eosio { }; struct update_request_time { - void operator() (struct transaction_state &ts) { - ts.requested_time = time_point::now(); - } - void operator () (struct eosio::peer_block_state &bs) { + void operator() (struct eosio::peer_block_state &bs) { bs.requested_time = time_point::now(); } } set_request_time; @@ -414,7 +375,7 @@ namespace eosio { typedef multi_index_container< eosio::peer_block_state, indexed_by< - ordered_unique< tag, member >, + ordered_unique< tag, member, sha256_less >, ordered_unique< tag, member > > > peer_block_state_index; @@ -424,9 +385,6 @@ namespace eosio { void operator() (eosio::peer_block_state& bs) { bs.is_known = true; } - void operator() (transaction_state& ts) { - ts.is_known_by_peer = true; - } } set_is_known; @@ -434,12 +392,7 @@ namespace eosio { uint32_t new_bnum; update_block_num(uint32_t bnum) : new_bnum(bnum) {} void operator() (node_transaction_state& nts) { - if (nts.requests ) { - nts.true_block = new_bnum; - } - else { - nts.block_num = new_bnum; - } + nts.block_num = new_bnum; } void operator() (transaction_state& ts) { ts.block_num = new_bnum; @@ -467,6 +420,86 @@ namespace eosio { static void populate(handshake_message &hello); }; + class queued_buffer : boost::noncopyable { + public: + void clear_write_queue() { + _write_queue.clear(); + _sync_write_queue.clear(); + _write_queue_size = 0; + } + + void clear_out_queue() { + while ( _out_queue.size() > 0 ) { + _out_queue.pop_front(); + } + } + + uint32_t write_queue_size() const { return _write_queue_size; } + + bool is_out_queue_empty() const { return _out_queue.empty(); } + + bool ready_to_send() const { + // if out_queue is not empty then async_write is in progress + return ((!_sync_write_queue.empty() || !_write_queue.empty()) && _out_queue.empty()); + } + + bool add_write_queue( const std::shared_ptr>& buff, + std::function callback, + bool to_sync_queue ) { + if( to_sync_queue ) { + _sync_write_queue.push_back( {buff, callback} ); + } else { + _write_queue.push_back( {buff, callback} ); + } + _write_queue_size += buff->size(); + if( _write_queue_size > 2 * def_max_write_queue_size ) { + return false; + } + return true; + } + + void fill_out_buffer( std::vector& bufs ) { + if( _sync_write_queue.size() > 0 ) { // always send msgs from sync_write_queue first + fill_out_buffer( bufs, _sync_write_queue ); + } else { // postpone real_time write_queue if sync queue is not empty + fill_out_buffer( bufs, _write_queue ); + EOS_ASSERT( _write_queue_size == 0, plugin_exception, "write queue size expected to be zero" ); + } + } + + void out_callback( boost::system::error_code ec, std::size_t w ) { + for( auto& m : _out_queue ) { + m.callback( ec, w ); + } + } + + private: + struct queued_write; + void fill_out_buffer( std::vector& bufs, + deque& w_queue ) { + while ( w_queue.size() > 0 ) { + auto& m = w_queue.front(); + bufs.push_back( boost::asio::buffer( *m.buff )); + _write_queue_size -= m.buff->size(); + _out_queue.emplace_back( m ); + w_queue.pop_front(); + } + } + + private: + struct queued_write { + std::shared_ptr> buff; + std::function callback; + }; + + uint32_t _write_queue_size = 0; + deque _write_queue; + deque _sync_write_queue; // sync_write_queue will be sent first + deque _out_queue; + + }; // queued_buffer + + class connection : public std::enable_shared_from_this { public: explicit connection( string endpoint ); @@ -482,14 +515,12 @@ namespace eosio { fc::message_buffer<1024*1024> pending_message_buffer; fc::optional outstanding_read_bytes; - vector blk_buffer; - struct queued_write { - std::shared_ptr> buff; - std::function callback; - }; - deque write_queue; - deque out_queue; + + queued_buffer buffer_queue; + + uint32_t reads_in_flight = 0; + uint32_t trx_in_progress_size = 0; fc::sha256 node_id; handshake_message last_handshake_recv; handshake_message last_handshake_sent; @@ -499,6 +530,7 @@ namespace eosio { uint16_t protocol_version = 0; string peer_addr; unique_ptr response_expected; + unique_ptr read_delay_timer; optional pending_fetch; go_away_reason no_retry = no_reason; block_id_type fork_head; @@ -540,10 +572,6 @@ namespace eosio { /** \name Peer Timestamps * Time message handling */ - /** @{ */ - /** \brief Convert an std::chrono nanosecond rep to a human readable string - */ - char* convert_tstamp(const tstamp& t); /** \brief Populate and queue time_message */ void send_time(); @@ -565,18 +593,22 @@ namespace eosio { const string peer_name(); - void txn_send_pending(const vector &ids); - void txn_send(const vector &txn_lis); + void txn_send_pending(const vector& ids); + void txn_send(const vector& txn_lis); void blk_send_branch(); - void blk_send(const vector &txn_lis); + void blk_send(const block_id_type& blkid); void stop_send(); void enqueue( const net_message &msg, bool trigger_send = true ); + void enqueue_block( const signed_block_ptr& sb, bool trigger_send = true, bool to_sync_queue = false ); + void enqueue_buffer( const std::shared_ptr>& send_buffer, + bool trigger_send, go_away_reason close_after_send, + bool to_sync_queue = false); void cancel_sync(go_away_reason); void flush_queues(); bool enqueue_sync_block(); - void request_sync_blocks (uint32_t start, uint32_t end); + void request_sync_blocks(uint32_t start, uint32_t end); void cancel_wait(); void sync_wait(); @@ -584,9 +616,10 @@ namespace eosio { void sync_timeout(boost::system::error_code ec); void fetch_timeout(boost::system::error_code ec); - void queue_write(std::shared_ptr> buff, + void queue_write(const std::shared_ptr>& buff, bool trigger_send, - std::function callback); + std::function callback, + bool to_sync_queue = false); void do_queue_write(); void send_p2p_request(bool discoverable); @@ -602,7 +635,7 @@ namespace eosio { */ bool process_next_message(net_plugin_impl& impl, uint32_t message_length); - bool add_peer_block(const peer_block_state &pbs); + bool add_peer_block(const peer_block_state& pbs); fc::optional _logger_variant; const fc::variant_object& get_logger_variant() { @@ -630,15 +663,35 @@ namespace eosio { } }; - struct msgHandler : public fc::visitor { + struct msg_handler : public fc::visitor { net_plugin_impl &impl; connection_ptr c; - msgHandler( net_plugin_impl &imp, connection_ptr conn) : impl(imp), c(conn) {} + msg_handler( net_plugin_impl &imp, const connection_ptr& conn) : impl(imp), c(conn) {} + + void operator()( const signed_block& msg ) const { + EOS_ASSERT( false, plugin_config_exception, "operator()(signed_block&&) should be called" ); + } + void operator()( signed_block& msg ) const { + EOS_ASSERT( false, plugin_config_exception, "operator()(signed_block&&) should be called" ); + } + void operator()( const packed_transaction& msg ) const { + EOS_ASSERT( false, plugin_config_exception, "operator()(packed_transaction&&) should be called" ); + } + void operator()( packed_transaction& msg ) const { + EOS_ASSERT( false, plugin_config_exception, "operator()(packed_transaction&&) should be called" ); + } + + void operator()( signed_block&& msg ) const { + impl.handle_message( c, std::make_shared( std::move( msg ) ) ); + } + void operator()( packed_transaction&& msg ) const { + impl.handle_message( c, std::make_shared( std::move( msg ) ) ); + } template - void operator()(const T &msg) const + void operator()( T&& msg ) const { - impl.handle_message( c, msg); + impl.handle_message( c, std::forward(msg) ); } }; @@ -666,37 +719,33 @@ namespace eosio { void set_state(stages s); bool sync_required(); void send_handshakes(); - bool is_active(connection_ptr conn); - void reset_lib_num(connection_ptr conn); - void request_next_chunk(connection_ptr conn = connection_ptr() ); - void start_sync(connection_ptr c, uint32_t target); - void reassign_fetch(connection_ptr c, go_away_reason reason); - void verify_catchup(connection_ptr c, uint32_t num, block_id_type id); - void rejected_block(connection_ptr c, uint32_t blk_num); - void recv_block(connection_ptr c, const block_id_type &blk_id, uint32_t blk_num); - void recv_handshake(connection_ptr c, const handshake_message& msg); - void recv_notice(connection_ptr c, const notice_message& msg); + bool is_active(const connection_ptr& conn); + void reset_lib_num(const connection_ptr& conn); + void request_next_chunk(const connection_ptr& conn = connection_ptr()); + void start_sync(const connection_ptr& c, uint32_t target); + void reassign_fetch(const connection_ptr& c, go_away_reason reason); + void verify_catchup(const connection_ptr& c, uint32_t num, const block_id_type& id); + void rejected_block(const connection_ptr& c, uint32_t blk_num); + void recv_block(const connection_ptr& c, const block_id_type& blk_id, uint32_t blk_num); + void recv_handshake(const connection_ptr& c, const handshake_message& msg); + void recv_notice(const connection_ptr& c, const notice_message& msg); }; class dispatch_manager { public: - uint32_t just_send_it_max = 0; - - vector req_trx; + std::multimap received_blocks; + std::multimap received_transactions; - std::multimap received_blocks; - std::multimap received_transactions; + void bcast_transaction(const transaction_metadata_ptr& trx); + void rejected_transaction(const transaction_id_type& msg); + void bcast_block(const block_state_ptr& bs); + void rejected_block(const block_id_type& id); - void bcast_transaction (const packed_transaction& msg); - void rejected_transaction (const transaction_id_type& msg); - void bcast_block (const signed_block& msg); - void rejected_block (const block_id_type &id); + void recv_block(const connection_ptr& conn, const block_id_type& msg, uint32_t bnum); + void recv_transaction(const connection_ptr& conn, const transaction_id_type& id); + void recv_notice(const connection_ptr& conn, const notice_message& msg, bool generated); - void recv_block (connection_ptr conn, const block_id_type& msg, uint32_t bnum); - void recv_transaction(connection_ptr conn, const transaction_id_type& id); - void recv_notice (connection_ptr conn, const notice_message& msg, bool generated); - - void retry_fetch (connection_ptr conn); + void retry_fetch(const connection_ptr& conn); }; //--------------------------------------------------------------------------- @@ -715,6 +764,7 @@ namespace eosio { protocol_version(0), peer_addr(endpoint), response_expected(), + read_delay_timer(), pending_fetch(), no_retry(no_reason), fork_head(), @@ -739,6 +789,7 @@ namespace eosio { protocol_version(0), peer_addr(), response_expected(), + read_delay_timer(), pending_fetch(), no_retry(no_reason), fork_head(), @@ -755,6 +806,7 @@ namespace eosio { auto *rnd = node_id.data(); rnd[0] = 0; response_expected.reset(new boost::asio::steady_timer(app().get_io_service())); + read_delay_timer.reset(new boost::asio::steady_timer(app().get_io_service())); } bool connection::connected() { @@ -772,7 +824,7 @@ namespace eosio { } void connection::flush_queues() { - write_queue.clear(); + buffer_queue.clear_write_queue(); } void connection::close() { @@ -786,7 +838,7 @@ namespace eosio { connecting = false; syncing = false; if( last_req ) { - my_impl->dispatcher->retry_fetch (shared_from_this()); + my_impl->dispatcher->retry_fetch(shared_from_this()); } reset(); sent_handshake_count = 0; @@ -795,60 +847,33 @@ namespace eosio { my_impl->sync_master->reset_lib_num(shared_from_this()); fc_dlog(logger, "canceling wait on ${p}", ("p",peer_name())); cancel_wait(); + if( read_delay_timer ) read_delay_timer->cancel(); pending_message_buffer.reset(); } - void connection::txn_send_pending(const vector &ids) { + void connection::txn_send_pending(const vector& ids) { + const std::set known_ids(ids.cbegin(), ids.cend()); + my_impl->expire_local_txns(); for(auto tx = my_impl->local_txns.begin(); tx != my_impl->local_txns.end(); ++tx ){ - if(tx->serialized_txn.size() && tx->block_num == 0) { - bool found = false; - for(auto known : ids) { - if( known == tx->id) { - found = true; - break; - } - } - if(!found) { - my_impl->local_txns.modify(tx,incr_in_flight); - queue_write(std::make_shared>(tx->serialized_txn), - true, - [tx_id=tx->id](boost::system::error_code ec, std::size_t ) { - auto& local_txns = my_impl->local_txns; - auto tx = local_txns.get().find(tx_id); - if (tx != local_txns.end()) { - local_txns.modify(tx, decr_in_flight); - } else { - fc_wlog(logger, "Local pending TX erased before queued_write called callback"); - } - }); - } + const bool found = known_ids.find( tx->id ) != known_ids.cend(); + if( !found ) { + queue_write( tx->serialized_txn, true, []( boost::system::error_code ec, std::size_t ) {} ); } } } - void connection::txn_send(const vector &ids) { - for(auto t : ids) { + void connection::txn_send(const vector& ids) { + for(const auto& t : ids) { auto tx = my_impl->local_txns.get().find(t); - if( tx != my_impl->local_txns.end() && tx->serialized_txn.size()) { - my_impl->local_txns.modify( tx,incr_in_flight); - queue_write(std::make_shared>(tx->serialized_txn), - true, - [t](boost::system::error_code ec, std::size_t ) { - auto& local_txns = my_impl->local_txns; - auto tx = local_txns.get().find(t); - if (tx != local_txns.end()) { - local_txns.modify(tx, decr_in_flight); - } else { - fc_wlog(logger, "Local TX erased before queued_write called callback"); - } - }); + if( tx != my_impl->local_txns.end() ) { + queue_write( tx->serialized_txn, true, []( boost::system::error_code ec, std::size_t ) {} ); } } } void connection::blk_send_branch() { - controller &cc = my_impl->chain_plug->chain(); - uint32_t head_num = cc.fork_db_head_block_num (); + controller& cc = my_impl->chain_plug->chain(); + uint32_t head_num = cc.fork_db_head_block_num(); notice_message note; note.known_blocks.mode = normal; note.known_blocks.pending = 0; @@ -877,85 +902,53 @@ namespace eosio { } head_id = cc.fork_db_head_block_id(); } - catch (const assert_exception &ex) { + catch (const assert_exception& ex) { elog( "unable to retrieve block info: ${n} for ${p}",("n",ex.to_string())("p",peer_name())); enqueue(note); return; } - catch (const fc::exception &ex) { + catch (const fc::exception& ex) { } catch (...) { } - vector bstack; - block_id_type null_id; - for (auto bid = head_id; bid != null_id && bid != lib_id; ) { - try { - - // if the last handshake received indicates that we are catching up on a fork - // that the peer is already partially aware of, no need to resend blocks - if (remote_head_id == bid) { - break; - } - - signed_block_ptr b = cc.fetch_block_by_id(bid); - if ( b ) { - bid = b->previous; - bstack.push_back(b); - } - else { - break; - } - } catch (...) { - break; - } - } - size_t count = 0; - if (!bstack.empty()) { - if (bstack.back()->previous == lib_id || bstack.back()->previous == remote_head_id) { - count = bstack.size(); - while (bstack.size()) { - enqueue(*bstack.back()); - bstack.pop_back(); - } - } - fc_ilog(logger, "Sent ${n} blocks on my fork",("n",count)); + if( !peer_requested ) { + peer_requested = sync_state( block_header::num_from_id(lib_id)+1, + block_header::num_from_id(head_id), + block_header::num_from_id(lib_id) ); } else { - fc_ilog(logger, "Nothing to send on fork request"); + uint32_t start = std::min( peer_requested->last + 1, block_header::num_from_id(lib_id)+1 ); + uint32_t end = std::max( peer_requested->end_block, block_header::num_from_id(head_id) ); + peer_requested = sync_state( start, end, start - 1 ); } + enqueue_sync_block(); + // still want to send transactions along during blk branch sync syncing = false; } - void connection::blk_send(const vector &ids) { + void connection::blk_send(const block_id_type& blkid) { controller &cc = my_impl->chain_plug->chain(); - int count = 0; - for(auto &blkid : ids) { - ++count; - try { - signed_block_ptr b = cc.fetch_block_by_id(blkid); - if(b) { - fc_dlog(logger,"found block for id at num ${n}",("n",b->block_num())); - enqueue(net_message(*b)); - } - else { - ilog("fetch block by id returned null, id ${id} on block ${c} of ${s} for ${p}", - ("id",blkid)("c",count)("s",ids.size())("p",peer_name())); - break; - } - } - catch (const assert_exception &ex) { - elog( "caught assert on fetch_block_by_id, ${ex}, id ${id} on block ${c} of ${s} for ${p}", - ("ex",ex.to_string())("id",blkid)("c",count)("s",ids.size())("p",peer_name())); - break; - } - catch (...) { - elog( "caught othser exception fetching block id ${id} on block ${c} of ${s} for ${p}", - ("id",blkid)("c",count)("s",ids.size())("p",peer_name())); - break; + try { + signed_block_ptr b = cc.fetch_block_by_id(blkid); + if(b) { + fc_dlog(logger,"found block for id at num ${n}",("n",b->block_num())); + peer_block_state pbstate = {blkid, block_header::num_from_id(blkid), true, true, time_point()}; + add_peer_block(pbstate); + enqueue_block( b ); + } else { + ilog("fetch block by id returned null, id ${id} for ${p}", + ("id",blkid)("p",peer_name())); } } - + catch (const assert_exception &ex) { + elog( "caught assert on fetch_block_by_id, ${ex}, id ${id} for ${p}", + ("ex",ex.to_string())("id",blkid)("p",peer_name())); + } + catch (...) { + elog( "caught other exception fetching block id ${id} for ${p}", + ("id",blkid)("p",peer_name())); + } } void connection::send_p2p_request(bool discoverable) @@ -985,7 +978,7 @@ namespace eosio { syncing = false; } - void connection::send_handshake( ) { + void connection::send_handshake() { handshake_initializer::populate(last_handshake_sent); last_handshake_sent.generation = ++sent_handshake_count; fc_dlog(logger, "Sending handshake generation ${g} to ${ep}", @@ -993,15 +986,6 @@ namespace eosio { enqueue(last_handshake_sent); } - char* connection::convert_tstamp(const tstamp& t) - { - const long long NsecPerSec{1000000000}; - time_t seconds = t / NsecPerSec; - strftime(ts, ts_buffer_size, "%F %T", localtime(&seconds)); - snprintf(ts+19, ts_buffer_size-19, ".%lld", t % NsecPerSec); - return ts; - } - void connection::send_time() { time_message xpkt; xpkt.org = rec; @@ -1019,16 +1003,23 @@ namespace eosio { enqueue(xpkt); } - void connection::queue_write(std::shared_ptr> buff, + void connection::queue_write(const std::shared_ptr>& buff, bool trigger_send, - std::function callback) { - write_queue.push_back({buff, callback}); - if(out_queue.empty() && trigger_send) + std::function callback, + bool to_sync_queue) { + if( !buffer_queue.add_write_queue( buff, callback, to_sync_queue )) { + fc_wlog( logger, "write_queue full ${s} bytes, giving up on connection ${p}", + ("s", buffer_queue.write_queue_size())("p", peer_name()) ); + my_impl->close( shared_from_this() ); + return; + } + if( buffer_queue.is_out_queue_empty() && trigger_send) { do_queue_write(); + } } void connection::do_queue_write() { - if(write_queue.empty() || !out_queue.empty()) + if( !buffer_queue.ready_to_send() ) return; connection_wptr c(shared_from_this()); if(!socket->is_open()) { @@ -1037,21 +1028,14 @@ namespace eosio { return; } std::vector bufs; - while (write_queue.size() > 0) { - auto& m = write_queue.front(); - bufs.push_back(boost::asio::buffer(*m.buff)); - out_queue.push_back(m); - write_queue.pop_front(); - } + buffer_queue.fill_out_buffer( bufs ); boost::asio::async_write(*socket, bufs, [c](boost::system::error_code ec, std::size_t w) { try { auto conn = c.lock(); if(!conn) return; - for (auto& m: conn->out_queue) { - m.callback(ec, w); - } + conn->buffer_queue.out_callback( ec, w ); if(ec) { string pname = conn ? conn->peer_name() : "no connection name"; @@ -1064,9 +1048,7 @@ namespace eosio { my_impl->close(conn); return; } - while (conn->out_queue.size() > 0) { - conn->out_queue.pop_front(); - } + conn->buffer_queue.clear_out_queue(); conn->enqueue_sync_block(); conn->do_queue_write(); } @@ -1089,8 +1071,8 @@ namespace eosio { } void connection::cancel_sync(go_away_reason reason) { - fc_dlog(logger,"cancel sync reason = ${m}, write queue size ${o} peer ${p}", - ("m",reason_str(reason)) ("o", write_queue.size())("p", peer_name())); + fc_dlog(logger,"cancel sync reason = ${m}, write queue size ${o} bytes peer ${p}", + ("m",reason_str(reason)) ("o", buffer_queue.write_queue_size())("p", peer_name())); cancel_wait(); flush_queues(); switch (reason) { @@ -1107,7 +1089,6 @@ namespace eosio { } bool connection::enqueue_sync_block() { - controller& cc = app().find_plugin()->chain(); if (!peer_requested) return false; uint32_t num = ++peer_requested->last; @@ -1116,9 +1097,10 @@ namespace eosio { peer_requested.reset(); } try { + controller& cc = my_impl->chain_plug->chain(); signed_block_ptr sb = cc.fetch_block_by_number(num); if(sb) { - enqueue( *sb, trigger_send); + enqueue_block( sb, trigger_send, true); return true; } } catch ( ... ) { @@ -1127,22 +1109,50 @@ namespace eosio { return false; } - void connection::enqueue( const net_message &m, bool trigger_send ) { + void connection::enqueue( const net_message& m, bool trigger_send ) { go_away_reason close_after_send = no_reason; if (m.contains()) { close_after_send = m.get().reason; } uint32_t payload_size = fc::raw::pack_size( m ); - char * header = reinterpret_cast(&payload_size); - size_t header_size = sizeof(payload_size); + char* header = reinterpret_cast(&payload_size); + size_t header_size = sizeof(payload_size); size_t buffer_size = header_size + payload_size; auto send_buffer = std::make_shared>(buffer_size); fc::datastream ds( send_buffer->data(), buffer_size); ds.write( header, header_size ); fc::raw::pack( ds, m ); + + enqueue_buffer( send_buffer, trigger_send, close_after_send ); + } + + void connection::enqueue_block( const signed_block_ptr& sb, bool trigger_send, bool to_sync_queue ) { + // this implementation is to avoid copy of signed_block to net_message + int which = 7; // matches which of net_message for signed_block + + uint32_t which_size = fc::raw::pack_size( unsigned_int( which )); + uint32_t payload_size = which_size + fc::raw::pack_size( *sb ); + + char* header = reinterpret_cast(&payload_size); + size_t header_size = sizeof(payload_size); + size_t buffer_size = header_size + payload_size; + + auto send_buffer = std::make_shared>(buffer_size); + fc::datastream ds( send_buffer->data(), buffer_size); + ds.write( header, header_size ); + fc::raw::pack( ds, unsigned_int( which )); + fc::raw::pack( ds, *sb ); + + enqueue_buffer( send_buffer, trigger_send, no_reason, to_sync_queue ); + } + + void connection::enqueue_buffer( const std::shared_ptr>& send_buffer, bool trigger_send, + go_away_reason close_after_send, + bool to_sync_queue ) + { connection_wptr weak_this = shared_from_this(); queue_write(send_buffer,trigger_send, [weak_this, close_after_send](boost::system::error_code ec, std::size_t ) { @@ -1156,7 +1166,8 @@ namespace eosio { } else { fc_wlog(logger, "connection expired before enqueued net_message called callback!"); } - }); + }, + to_sync_queue); } void connection::cancel_wait() { @@ -1164,7 +1175,7 @@ namespace eosio { response_expected->cancel(); } - void connection::sync_wait( ) { + void connection::sync_wait() { response_expected->expires_from_now( my_impl->resp_expected_period); connection_wptr c(shared_from_this()); response_expected->async_wait( [c]( boost::system::error_code ec){ @@ -1178,7 +1189,7 @@ namespace eosio { } ); } - void connection::fetch_wait( ) { + void connection::fetch_wait() { response_expected->expires_from_now( my_impl->resp_expected_period); connection_wptr c(shared_from_this()); response_expected->async_wait( [c]( boost::system::error_code ec){ @@ -1194,12 +1205,12 @@ namespace eosio { void connection::sync_timeout( boost::system::error_code ec ) { if( !ec ) { - my_impl->sync_master->reassign_fetch (shared_from_this(),benign_other); + my_impl->sync_master->reassign_fetch(shared_from_this(), benign_other); } else if( ec == boost::asio::error::operation_aborted) { } else { - elog ("setting timer for sync request got error ${ec}",("ec", ec.message())); + elog("setting timer for sync request got error ${ec}",("ec", ec.message())); } } @@ -1215,21 +1226,21 @@ namespace eosio { void connection::fetch_timeout( boost::system::error_code ec ) { if( !ec ) { - if( pending_fetch.valid() && !( pending_fetch->req_trx.empty( ) || pending_fetch->req_blocks.empty( ) ) ) { - my_impl->dispatcher->retry_fetch (shared_from_this() ); + if( pending_fetch.valid() && !( pending_fetch->req_trx.empty() || pending_fetch->req_blocks.empty() ) ) { + my_impl->dispatcher->retry_fetch(shared_from_this()); } } else if( ec == boost::asio::error::operation_aborted ) { - if( !connected( ) ) { + if( !connected() ) { fc_dlog(logger, "fetch timeout was cancelled due to dead connection"); } } else { - elog( "setting timer for fetch request got error ${ec}", ("ec", ec.message( ) ) ); + elog( "setting timer for fetch request got error ${ec}", ("ec", ec.message() ) ); } } - void connection::request_sync_blocks (uint32_t start, uint32_t end) { + void connection::request_sync_blocks(uint32_t start, uint32_t end) { sync_request_message srm = {start,end}; enqueue( net_message(srm)); sync_wait(); @@ -1237,27 +1248,17 @@ namespace eosio { bool connection::process_next_message(net_plugin_impl& impl, uint32_t message_length) { try { - // If it is a signed_block, then save the raw message for the cache - // This must be done before we unpack the message. - // This code is copied from fc::io::unpack(..., unsigned_int) - auto index = pending_message_buffer.read_index(); - uint64_t which = 0; char b = 0; uint8_t by = 0; - do { - pending_message_buffer.peek(&b, 1, index); - which |= uint32_t(uint8_t(b) & 0x7f) << by; - by += 7; - } while( uint8_t(b) & 0x80 && by < 32); - - if (which == uint64_t(net_message::tag::value)) { - blk_buffer.resize(message_length); - auto index = pending_message_buffer.read_index(); - pending_message_buffer.peek(blk_buffer.data(), message_length, index); - } auto ds = pending_message_buffer.create_datastream(); net_message msg; fc::raw::unpack(ds, msg); - msgHandler m(impl, shared_from_this() ); - msg.visit(m); + msg_handler m(impl, shared_from_this() ); + if( msg.contains() ) { + m( std::move( msg.get() ) ); + } else if( msg.contains() ) { + m( std::move( msg.get() ) ); + } else { + msg.visit( m ); + } } catch( const fc::exception& e ) { edump((e.to_detail_string() )); impl.close( shared_from_this() ); @@ -1266,7 +1267,7 @@ namespace eosio { return true; } - bool connection::add_peer_block(const peer_block_state &entry) { + bool connection::add_peer_block(const peer_block_state& entry) { auto bptr = blk_state.get().find(entry.id); bool added = (bptr == blk_state.end()); if (added){ @@ -1294,11 +1295,11 @@ namespace eosio { ,source() ,state(in_sync) { - chain_plug = app( ).find_plugin( ); + chain_plug = app().find_plugin(); EOS_ASSERT( chain_plug, chain::missing_chain_plugin_exception, "" ); } - constexpr auto sync_manager::stage_str(stages s ) { + constexpr auto sync_manager::stage_str(stages s) { switch (s) { case in_sync : return "in sync"; case lib_catchup: return "lib catchup"; @@ -1311,11 +1312,11 @@ namespace eosio { if (state == newstate) { return; } - fc_dlog(logger, "old state ${os} becoming ${ns}",("os",stage_str (state))("ns",stage_str (newstate))); + fc_dlog(logger, "old state ${os} becoming ${ns}",("os",stage_str(state))("ns",stage_str(newstate))); state = newstate; } - bool sync_manager::is_active(connection_ptr c) { + bool sync_manager::is_active(const connection_ptr& c) { if (state == head_catchup && c) { bool fhset = c->fork_head != block_id_type(); fc_dlog(logger, "fork_head_num = ${fn} fork_head set = ${s}", @@ -1325,7 +1326,7 @@ namespace eosio { return state != in_sync; } - void sync_manager::reset_lib_num(connection_ptr c) { + void sync_manager::reset_lib_num(const connection_ptr& c) { if(state == in_sync) { source.reset(); } @@ -1339,19 +1340,19 @@ namespace eosio { } } - bool sync_manager::sync_required( ) { + bool sync_manager::sync_required() { fc_dlog(logger, "last req = ${req}, last recv = ${recv} known = ${known} our head = ${head}", - ("req",sync_last_requested_num)("recv",sync_next_expected_num)("known",sync_known_lib_num)("head",chain_plug->chain( ).fork_db_head_block_num( ))); + ("req",sync_last_requested_num)("recv",sync_next_expected_num)("known",sync_known_lib_num)("head",chain_plug->chain().fork_db_head_block_num())); return( sync_last_requested_num < sync_known_lib_num || - chain_plug->chain( ).fork_db_head_block_num( ) < sync_last_requested_num ); + chain_plug->chain().fork_db_head_block_num() < sync_last_requested_num ); } - void sync_manager::request_next_chunk( connection_ptr conn ) { + void sync_manager::request_next_chunk( const connection_ptr& conn ) { uint32_t head_block = chain_plug->chain().fork_db_head_block_num(); if (head_block < sync_last_requested_num && source && source->current()) { - fc_ilog (logger, "ignoring request, head is ${h} last req = ${r} source is ${p}", + fc_ilog(logger, "ignoring request, head is ${h} last req = ${r} source is ${p}", ("h",head_block)("r",sync_last_requested_num)("p",source->peer_name())); return; } @@ -1430,7 +1431,7 @@ namespace eosio { } } - void sync_manager::send_handshakes () + void sync_manager::send_handshakes() { for( auto &ci : my_impl->connections) { if( ci->current()) { @@ -1439,7 +1440,7 @@ namespace eosio { } } - void sync_manager::start_sync( connection_ptr c, uint32_t target) { + void sync_manager::start_sync(const connection_ptr& c, uint32_t target) { if( target > sync_known_lib_num) { sync_known_lib_num = target; } @@ -1463,20 +1464,20 @@ namespace eosio { request_next_chunk(c); } - void sync_manager::reassign_fetch(connection_ptr c, go_away_reason reason) { + void sync_manager::reassign_fetch(const connection_ptr& c, go_away_reason reason) { fc_ilog(logger, "reassign_fetch, our last req is ${cc}, next expected is ${ne} peer ${p}", ( "cc",sync_last_requested_num)("ne",sync_next_expected_num)("p",c->peer_name())); if (c == source) { - c->cancel_sync (reason); + c->cancel_sync(reason); sync_last_requested_num = 0; request_next_chunk(); } } - void sync_manager::recv_handshake (connection_ptr c, const handshake_message &msg) { + void sync_manager::recv_handshake(const connection_ptr& c, const handshake_message& msg) { controller& cc = chain_plug->chain(); - uint32_t lib_num = cc.last_irreversible_block_num( ); + uint32_t lib_num = cc.last_irreversible_block_num(); uint32_t peer_lib = msg.last_irreversible_block_num; reset_lib_num(c); c->syncing = false; @@ -1484,16 +1485,16 @@ namespace eosio { //-------------------------------- // sync need checks; (lib == last irreversible block) // - // 0. my head block id == peer head id means we are all caugnt up block wise + // 0. my head block id == peer head id means we are all caught up block wise // 1. my head block num < peer lib - start sync locally // 2. my lib > peer head num - send an last_irr_catch_up notice if not the first generation // // 3 my head block num <= peer head block num - update sync state and send a catchup request - // 4 my head block num > peer block num ssend a notice catchup if this is not the first generation + // 4 my head block num > peer block num send a notice catchup if this is not the first generation // //----------------------------- - uint32_t head = cc.fork_db_head_block_num( ); + uint32_t head = cc.fork_db_head_block_num(); block_id_type head_id = cc.fork_db_head_block_id(); if (head_id == msg.head_id) { fc_dlog(logger, "sync check state 0"); @@ -1529,7 +1530,7 @@ namespace eosio { if (head <= msg.head_num ) { fc_dlog(logger, "sync check state 3"); - verify_catchup (c, msg.head_num, msg.head_id); + verify_catchup(c, msg.head_num, msg.head_id); return; } else { @@ -1545,22 +1546,24 @@ namespace eosio { c->syncing = true; return; } - elog ("sync check failed to resolve status"); + elog("sync check failed to resolve status"); } - void sync_manager::verify_catchup(connection_ptr c, uint32_t num, block_id_type id) { + void sync_manager::verify_catchup(const connection_ptr& c, uint32_t num, const block_id_type& id) { request_message req; req.req_blocks.mode = catch_up; - for (auto cc : my_impl->connections) { + for (const auto& cc : my_impl->connections) { if (cc->fork_head == id || - cc->fork_head_num > num) + cc->fork_head_num > num) { req.req_blocks.mode = none; - break; + break; + } } if( req.req_blocks.mode == catch_up ) { c->fork_head = id; c->fork_head_num = num; - ilog ("got a catch_up notice while in ${s}, fork head num = ${fhn} target LIB = ${lib} next_expected = ${ne}", ("s",stage_str(state))("fhn",num)("lib",sync_known_lib_num)("ne", sync_next_expected_num)); + ilog("got a catch_up notice while in ${s}, fork head num = ${fhn} target LIB = ${lib} next_expected = ${ne}", + ("s",stage_str(state))("fhn",num)("lib",sync_known_lib_num)("ne", sync_next_expected_num)); if (state == lib_catchup) return; set_state(head_catchup); @@ -1573,26 +1576,30 @@ namespace eosio { c->enqueue( req ); } - void sync_manager::recv_notice (connection_ptr c, const notice_message &msg) { - fc_ilog (logger, "sync_manager got ${m} block notice",("m",modes_str(msg.known_blocks.mode))); + void sync_manager::recv_notice(const connection_ptr& c, const notice_message& msg) { + fc_ilog(logger, "sync_manager got ${m} block notice",("m",modes_str(msg.known_blocks.mode))); + if( msg.known_blocks.ids.size() > 1 ) { + elog( "Invalid notice_message, known_blocks.ids.size ${s}", ("s", msg.known_blocks.ids.size()) ); + my_impl->close(c); + return; + } if (msg.known_blocks.mode == catch_up) { if (msg.known_blocks.ids.size() == 0) { - elog ("got a catch up with ids size = 0"); - } - else { - verify_catchup(c, msg.known_blocks.pending, msg.known_blocks.ids.back()); + elog("got a catch up with ids size = 0"); + } else { + verify_catchup(c, msg.known_blocks.pending, msg.known_blocks.ids.back()); } } else { c->last_handshake_recv.last_irreversible_block_num = msg.known_trx.pending; - reset_lib_num (c); + reset_lib_num(c); start_sync(c, msg.known_trx.pending); } } - void sync_manager::rejected_block (connection_ptr c, uint32_t blk_num) { + void sync_manager::rejected_block(const connection_ptr& c, uint32_t blk_num) { if (state != in_sync ) { - fc_ilog (logger, "block ${bn} not accepted from ${p}",("bn",blk_num)("p",c->peer_name())); + fc_ilog(logger, "block ${bn} not accepted from ${p}",("bn",blk_num)("p",c->peer_name())); sync_last_requested_num = 0; source.reset(); my_impl->close(c); @@ -1600,23 +1607,23 @@ namespace eosio { send_handshakes(); } } - void sync_manager::recv_block (connection_ptr c, const block_id_type &blk_id, uint32_t blk_num) { + void sync_manager::recv_block(const connection_ptr& c, const block_id_type& blk_id, uint32_t blk_num) { fc_dlog(logger," got block ${bn} from ${p}",("bn",blk_num)("p",c->peer_name())); if (state == lib_catchup) { if (blk_num != sync_next_expected_num) { - fc_ilog (logger, "expected block ${ne} but got ${bn}",("ne",sync_next_expected_num)("bn",blk_num)); + fc_ilog(logger, "expected block ${ne} but got ${bn}",("ne",sync_next_expected_num)("bn",blk_num)); my_impl->close(c); return; } sync_next_expected_num = blk_num + 1; } if (state == head_catchup) { - fc_dlog (logger, "sync_manager in head_catchup state"); + fc_dlog(logger, "sync_manager in head_catchup state"); set_state(in_sync); source.reset(); block_id_type null_id; - for (auto cp : my_impl->connections) { + for (const auto& cp : my_impl->connections) { if (cp->fork_head == null_id) { continue; } @@ -1647,52 +1654,34 @@ namespace eosio { //------------------------------------------------------------------------ - void dispatch_manager::bcast_block (const signed_block &bsum) { + void dispatch_manager::bcast_block(const block_state_ptr& bs) { std::set skips; - auto range = received_blocks.equal_range(bsum.id()); + auto range = received_blocks.equal_range(bs->id); for (auto org = range.first; org != range.second; ++org) { skips.insert(org->second); } received_blocks.erase(range.first, range.second); - net_message msg(bsum); - uint32_t packsiz = fc::raw::pack_size(msg); - uint32_t msgsiz = packsiz + sizeof(packsiz); - notice_message pending_notify; - block_id_type bid = bsum.id(); - uint32_t bnum = bsum.block_num(); - pending_notify.known_blocks.mode = normal; - pending_notify.known_blocks.ids.push_back( bid ); - pending_notify.known_trx.mode = none; - - peer_block_state pbstate = {bid, bnum, false,true,time_point()}; - // skip will be empty if our producer emitted this block so just send it - if (( large_msg_notify && msgsiz > just_send_it_max) && !skips.empty()) { - fc_ilog(logger, "block size is ${ms}, sending notify",("ms", msgsiz)); - my_impl->send_all(pending_notify, [&skips, pbstate](connection_ptr c) -> bool { - if (skips.find(c) != skips.end() || !c->current()) - return false; - - bool unknown = c->add_peer_block(pbstate); - if (!unknown) { - elog("${p} already has knowledge of block ${b}", ("p",c->peer_name())("b",pbstate.block_num)); - } - return unknown; - }); - } - else { - pbstate.is_known = true; - for (auto cp : my_impl->connections) { - if (skips.find(cp) != skips.end() || !cp->current()) { - continue; - } - cp->add_peer_block(pbstate); - cp->enqueue( bsum ); + block_id_type bid = bs->id; + uint32_t bnum = bs->block_num; + peer_block_state pbstate = {bid, bnum, false, true, time_point()}; + + pbstate.is_known = true; + for( auto& cp : my_impl->connections ) { + if( skips.find( cp ) != skips.end() || !cp->current() ) { + continue; + } + bool has_block = cp->last_handshake_recv.last_irreversible_block_num >= bnum; + if( !has_block ) { + fc_dlog(logger, "bcast block ${b} to ${p}", ("b", bnum)("p", cp->peer_name())); + cp->add_peer_block( pbstate ); + cp->enqueue_block( bs->block ); } } + } - void dispatch_manager::recv_block (connection_ptr c, const block_id_type& id, uint32_t bnum) { + void dispatch_manager::recv_block(const connection_ptr& c, const block_id_type& id, uint32_t bnum) { received_blocks.insert(std::make_pair(id, c)); if (c && c->last_req && @@ -1707,15 +1696,15 @@ namespace eosio { c->cancel_wait(); } - void dispatch_manager::rejected_block (const block_id_type& id) { + void dispatch_manager::rejected_block(const block_id_type& id) { fc_dlog(logger,"not sending rejected transaction ${tid}",("tid",id)); auto range = received_blocks.equal_range(id); received_blocks.erase(range.first, range.second); } - void dispatch_manager::bcast_transaction (const packed_transaction& trx) { + void dispatch_manager::bcast_transaction(const transaction_metadata_ptr& ptrx) { std::set skips; - transaction_id_type id = trx.id(); + const auto& id = ptrx->id; auto range = received_transactions.equal_range(id); for (auto org = range.first; org != range.second; ++org) { @@ -1723,78 +1712,49 @@ namespace eosio { } received_transactions.erase(range.first, range.second); - for (auto ref = req_trx.begin(); ref != req_trx.end(); ++ref) { - if (*ref == id) { - req_trx.erase(ref); - break; - } - } - - if( my_impl->local_txns.get().find( id ) != my_impl->local_txns.end( ) ) { //found + if( my_impl->local_txns.get().find( id ) != my_impl->local_txns.end() ) { //found fc_dlog(logger, "found trxid in local_trxs" ); return; } - uint32_t packsiz = 0; - uint32_t bufsiz = 0; - - time_point_sec trx_expiration = trx.expiration(); - - net_message msg(trx); - packsiz = fc::raw::pack_size(msg); - bufsiz = packsiz + sizeof(packsiz); - vector buff(bufsiz); - fc::datastream ds( buff.data(), bufsiz); - ds.write( reinterpret_cast(&packsiz), sizeof(packsiz) ); - fc::raw::pack( ds, msg ); - node_transaction_state nts = {id, - trx_expiration, - trx, - std::move(buff), - 0, 0, 0}; + + time_point_sec trx_expiration = ptrx->packed_trx->expiration(); + const packed_transaction& trx = *ptrx->packed_trx; + + // this implementation is to avoid copy of packed_transaction to net_message + int which = 8; // matches which of net_message for packed_transaction + + uint32_t which_size = fc::raw::pack_size( unsigned_int( which )); + uint32_t payload_size = which_size + fc::raw::pack_size( trx ); + + char* header = reinterpret_cast(&payload_size); + size_t header_size = sizeof(payload_size); + size_t buffer_size = header_size + payload_size; + + auto buff = std::make_shared>(buffer_size); + fc::datastream ds( buff->data(), buffer_size); + ds.write( header, header_size ); + fc::raw::pack( ds, unsigned_int( which )); + fc::raw::pack( ds, trx ); + + node_transaction_state nts = {id, trx_expiration, 0, buff}; my_impl->local_txns.insert(std::move(nts)); - if( !large_msg_notify || bufsiz <= just_send_it_max) { - my_impl->send_all( trx, [id, &skips, trx_expiration](connection_ptr c) -> bool { - if( skips.find(c) != skips.end() || c->syncing ) { - return false; - } - const auto& bs = c->trx_state.find(id); - bool unknown = bs == c->trx_state.end(); - if( unknown) { - c->trx_state.insert(transaction_state({id,true,true,0,trx_expiration,time_point() })); - fc_dlog(logger, "sending whole trx to ${n}", ("n",c->peer_name() ) ); - } else { - update_txn_expiry ute(trx_expiration); - c->trx_state.modify(bs, ute); - } - return unknown; - }); - } - else { - notice_message pending_notify; - pending_notify.known_trx.mode = normal; - pending_notify.known_trx.ids.push_back( id ); - pending_notify.known_blocks.mode = none; - my_impl->send_all(pending_notify, [id, &skips, trx_expiration](connection_ptr c) -> bool { - if (skips.find(c) != skips.end() || c->syncing) { - return false; - } - const auto& bs = c->trx_state.find(id); - bool unknown = bs == c->trx_state.end(); - if( unknown) { - fc_dlog(logger, "sending notice to ${n}", ("n",c->peer_name() ) ); - c->trx_state.insert(transaction_state({id,false,true,0,trx_expiration,time_point() })); - } else { - update_txn_expiry ute(trx_expiration); - c->trx_state.modify(bs, ute); - } - return unknown; - }); - } + my_impl->send_all( buff, [&id, &skips, trx_expiration](const connection_ptr& c) -> bool { + if( skips.find(c) != skips.end() || c->syncing ) { + return false; + } + const auto& bs = c->trx_state.find(id); + bool unknown = bs == c->trx_state.end(); + if( unknown ) { + c->trx_state.insert(transaction_state({id,0,trx_expiration})); + fc_dlog(logger, "sending trx to ${n}", ("n",c->peer_name() ) ); + } + return unknown; + }); } - void dispatch_manager::recv_transaction (connection_ptr c, const transaction_id_type& id) { + void dispatch_manager::recv_transaction(const connection_ptr& c, const transaction_id_type& id) { received_transactions.insert(std::make_pair(id, c)); if (c && c->last_req && @@ -1808,50 +1768,32 @@ namespace eosio { c->cancel_wait(); } - void dispatch_manager::rejected_transaction (const transaction_id_type& id) { + void dispatch_manager::rejected_transaction(const transaction_id_type& id) { fc_dlog(logger,"not sending rejected transaction ${tid}",("tid",id)); auto range = received_transactions.equal_range(id); received_transactions.erase(range.first, range.second); } - void dispatch_manager::recv_notice (connection_ptr c, const notice_message& msg, bool generated) { + void dispatch_manager::recv_notice(const connection_ptr& c, const notice_message& msg, bool generated) { request_message req; req.req_trx.mode = none; req.req_blocks.mode = none; bool send_req = false; - controller &cc = my_impl->chain_plug->chain(); if (msg.known_trx.mode == normal) { req.req_trx.mode = normal; req.req_trx.pending = 0; - for( const auto& t : msg.known_trx.ids ) { - const auto &tx = my_impl->local_txns.get( ).find( t ); - - if( tx == my_impl->local_txns.end( ) ) { - fc_dlog(logger,"did not find ${id}",("id",t)); - - //At this point the details of the txn are not known, just its id. This - //effectively gives 120 seconds to learn of the details of the txn which - //will update the expiry in bcast_transaction - c->trx_state.insert( (transaction_state){t,true,true,0,time_point_sec(time_point::now()) + 120, - time_point()} ); - - req.req_trx.ids.push_back( t ); - req_trx.push_back( t ); - } - else { - fc_dlog(logger,"big msg manager found txn id in table, ${id}",("id", t)); - } - } - send_req = !req.req_trx.ids.empty(); - fc_dlog(logger,"big msg manager send_req ids list has ${ids} entries", ("ids", req.req_trx.ids.size())); + send_req = false; } else if (msg.known_trx.mode != none) { - elog ("passed a notice_message with something other than a normal on none known_trx"); + elog("passed a notice_message with something other than a normal on none known_trx"); return; } if (msg.known_blocks.mode == normal) { req.req_blocks.mode = normal; - for( const auto& blkid : msg.known_blocks.ids) { + controller& cc = my_impl->chain_plug->chain(); + // known_blocks.ids is never > 1 + if( !msg.known_blocks.ids.empty() ) { + const block_id_type& blkid = msg.known_blocks.ids.back(); signed_block_ptr b; peer_block_state entry = {blkid,0,true,true,fc::time_point()}; try { @@ -1873,7 +1815,7 @@ namespace eosio { } } else if (msg.known_blocks.mode != none) { - elog ("passed a notice_message with something other than a normal on none known_blocks"); + elog("passed a notice_message with something other than a normal on none known_blocks"); return; } fc_dlog( logger, "send req = ${sr}", ("sr",send_req)); @@ -1884,7 +1826,7 @@ namespace eosio { } } - void dispatch_manager::retry_fetch( connection_ptr c ) { + void dispatch_manager::retry_fetch(const connection_ptr& c) { if (!c->last_req) { return; } @@ -1904,14 +1846,14 @@ namespace eosio { ("b",modes_str(c->last_req->req_blocks.mode))("t",modes_str(c->last_req->req_trx.mode))); return; } - for (auto conn : my_impl->connections) { + for (auto& conn : my_impl->connections) { if (conn == c || conn->last_req) { continue; } bool sendit = false; if (is_txn) { auto trx = conn->trx_state.get().find(tid); - sendit = trx != conn->trx_state.end() && trx->is_known_by_peer; + sendit = trx != conn->trx_state.end(); } else { auto blk = conn->blk_state.get().find(bid); @@ -1934,7 +1876,7 @@ namespace eosio { //------------------------------------------------------------------------ - void net_plugin_impl::connect( connection_ptr c ) { + void net_plugin_impl::connect(const connection_ptr& c) { if( c->no_retry != go_away_reason::no_reason) { fc_dlog( logger, "Skipping connect due to go_away reason ${r}",("r", reason_str( c->no_retry ))); return; @@ -1943,7 +1885,7 @@ namespace eosio { auto colon = c->peer_addr.find(':'); if (colon == std::string::npos || colon == 0) { - elog ("Invalid peer address. must be \"host:port\": ${p}", ("p",c->peer_addr)); + elog("Invalid peer address. must be \"host:port\": ${p}", ("p",c->peer_addr)); for ( auto itr : connections ) { if((*itr).peer_addr == c->peer_addr) { (*itr).reset(); @@ -1976,7 +1918,7 @@ namespace eosio { }); } - void net_plugin_impl::connect( connection_ptr c, tcp::resolver::iterator endpoint_itr ) { + void net_plugin_impl::connect(const connection_ptr& c, tcp::resolver::iterator endpoint_itr) { if( c->no_retry != go_away_reason::no_reason) { string rsn = reason_str(c->no_retry); return; @@ -2039,7 +1981,9 @@ namespace eosio { } } } - bool net_plugin_impl::start_session( connection_ptr con ) { + + bool net_plugin_impl::start_session(const connection_ptr& con) { + boost::asio::ip::tcp::no_delay nodelay( true ); boost::system::error_code ec; con->socket->set_option( nodelay, ec ); @@ -2061,7 +2005,7 @@ namespace eosio { } - void net_plugin_impl::start_listen_loop( ) { + void net_plugin_impl::start_listen_loop() { auto socket = std::make_shared( std::ref( app().get_io_service() ) ); acceptor->async_accept( *socket, [socket,this]( boost::system::error_code ec ) { if( !ec ) { @@ -2084,7 +2028,7 @@ namespace eosio { } } if (num_clients != visitors) { - ilog ("checking max client, visitors = ${v} num clients ${n}",("v",visitors)("n",num_clients)); + ilog("checking max client, visitors = ${v} num clients ${n}",("v",visitors)("n",num_clients)); num_clients = visitors; } if( from_addr < max_nodes_per_host && (max_client_count == 0 || num_clients < max_client_count )) { @@ -2103,7 +2047,7 @@ namespace eosio { fc_elog(logger, "Error max_client_count ${m} exceeded", ( "m", max_client_count) ); } - socket->close( ); + socket->close(); } } } else { @@ -2125,7 +2069,7 @@ namespace eosio { }); } - void net_plugin_impl::start_read_message( connection_ptr conn ) { + void net_plugin_impl::start_read_message(const connection_ptr& conn) { try { if(!conn->socket) { @@ -2150,6 +2094,37 @@ namespace eosio { } }; + if( conn->buffer_queue.write_queue_size() > def_max_write_queue_size || + conn->reads_in_flight > def_max_reads_in_flight || + conn->trx_in_progress_size > def_max_trx_in_progress_size ) + { + // too much queued up, reschedule + if( conn->buffer_queue.write_queue_size() > def_max_write_queue_size ) { + peer_wlog( conn, "write_queue full ${s} bytes", ("s", conn->buffer_queue.write_queue_size()) ); + } else if( conn->reads_in_flight > def_max_reads_in_flight ) { + peer_wlog( conn, "max reads in flight ${s}", ("s", conn->reads_in_flight) ); + } else { + peer_wlog( conn, "max trx in progress ${s} bytes", ("s", conn->trx_in_progress_size) ); + } + if( conn->buffer_queue.write_queue_size() > 2*def_max_write_queue_size || + conn->reads_in_flight > 2*def_max_reads_in_flight || + conn->trx_in_progress_size > 2*def_max_trx_in_progress_size ) + { + fc_wlog( logger, "queues over full, giving up on connection ${p}", ("p", conn->peer_name()) ); + my_impl->close( conn ); + return; + } + if( !conn->read_delay_timer ) return; + conn->read_delay_timer->expires_from_now( def_read_delay_for_full_write_queue ); + conn->read_delay_timer->async_wait([this, weak_conn]( boost::system::error_code ) { + auto conn = weak_conn.lock(); + if( !conn ) return; + start_read_message( conn ); + } ); + return; + } + + ++conn->reads_in_flight; boost::asio::async_read(*conn->socket, conn->pending_message_buffer.get_buffer_sequence_for_boost_async_read(), completion_handler, [this,weak_conn]( boost::system::error_code ec, std::size_t bytes_transferred ) { @@ -2158,6 +2133,7 @@ namespace eosio { return; } + --conn->reads_in_flight; conn->outstanding_read_bytes.reset(); try { @@ -2180,7 +2156,8 @@ namespace eosio { conn->pending_message_buffer.peek(&message_length, sizeof(message_length), index); if(message_length > def_send_buffer_size*2 || message_length == 0) { boost::system::error_code ec; - elog("incoming message length unexpected (${i}), from ${p}", ("i", message_length)("p",boost::lexical_cast(conn->socket->remote_endpoint(ec)))); + elog("incoming message length unexpected (${i}), from ${p}", + ("i", message_length)("p",boost::lexical_cast(conn->socket->remote_endpoint(ec)))); close(conn); return; } @@ -2250,15 +2227,15 @@ namespace eosio { template - void net_plugin_impl::send_all( const net_message &msg, VerifierFunc verify) { + void net_plugin_impl::send_all(const std::shared_ptr>& send_buffer, VerifierFunc verify) { for( auto &c : connections) { - if( c->current() && verify( c)) { - c->enqueue( msg ); + if( c->current() && verify( c )) { + c->enqueue_buffer( send_buffer, true, no_reason ); } } } - bool net_plugin_impl::is_valid( const handshake_message &msg) { + bool net_plugin_impl::is_valid(const handshake_message& msg) { // Do some basic validation of an incoming handshake_message, so things // that really aren't handshake messages can be quickly discarded without // affecting state. @@ -2283,11 +2260,11 @@ namespace eosio { return valid; } - void net_plugin_impl::handle_message( connection_ptr c, const chain_size_message &msg) { + void net_plugin_impl::handle_message(const connection_ptr& c, const chain_size_message& msg) { peer_ilog(c, "received chain_size_message"); - } + void net_plugin_impl::handle_message( connection_ptr c, const request_p2p_message &msg){ peer_ilog(c, "received request_p2p_message"); string rspm; @@ -2338,7 +2315,9 @@ namespace eosio { }}} } - void net_plugin_impl::handle_message( connection_ptr c, const handshake_message &msg) { + + void net_plugin_impl::handle_message(const connection_ptr& c, const handshake_message& msg) { + peer_ilog(c, "received handshake_message"); if (!is_valid(msg)) { peer_elog( c, "bad handshake message"); @@ -2346,7 +2325,7 @@ namespace eosio { return; } controller& cc = chain_plug->chain(); - uint32_t lib_num = cc.last_irreversible_block_num( ); + uint32_t lib_num = cc.last_irreversible_block_num(); uint32_t peer_lib = msg.last_irreversible_block_num; if( c->connecting ) { c->connecting = false; @@ -2445,7 +2424,7 @@ namespace eosio { sync_master->recv_handshake(c,msg); } - void net_plugin_impl::handle_message( connection_ptr c, const go_away_message &msg ) { + void net_plugin_impl::handle_message(const connection_ptr& c, const go_away_message& msg) { string rsn = reason_str( msg.reason ); peer_ilog(c, "received go_away_message"); ilog( "received a go away message from ${p}, reason = ${r}", @@ -2455,10 +2434,10 @@ namespace eosio { c->node_id = msg.node_id; } c->flush_queues(); - close (c); + close(c); } - void net_plugin_impl::handle_message(connection_ptr c, const time_message &msg) { + void net_plugin_impl::handle_message(const connection_ptr& c, const time_message& msg) { peer_ilog(c, "received time_message"); /* We've already lost however many microseconds it took to dispatch * the message, but it can't be helped. @@ -2491,7 +2470,7 @@ namespace eosio { c->rec = 0; } - void net_plugin_impl::handle_message( connection_ptr c, const notice_message &msg) { + void net_plugin_impl::handle_message(const connection_ptr& c, const notice_message& msg) { // peer tells us about one or more blocks or txns. When done syncing, forward on // notices of previously unknown blocks or txns, // @@ -2500,7 +2479,7 @@ namespace eosio { request_message req; bool send_req = false; if (msg.known_trx.mode != none) { - fc_dlog(logger,"this is a ${m} notice with ${n} blocks", ("m",modes_str(msg.known_trx.mode))("n",msg.known_trx.pending)); + fc_dlog(logger,"this is a ${m} notice with ${n} transactions", ("m",modes_str(msg.known_trx.mode))("n",msg.known_trx.pending)); } switch (msg.known_trx.mode) { case none: @@ -2517,7 +2496,7 @@ namespace eosio { send_req = true; size_t known_sum = local_txns.size(); if( known_sum ) { - for( const auto& t : local_txns.get( ) ) { + for( const auto& t : local_txns.get() ) { req.req_trx.ids.push_back( t.id ); } } @@ -2525,7 +2504,7 @@ namespace eosio { break; } case normal: { - dispatcher->recv_notice (c, msg, false); + dispatcher->recv_notice(c, msg, false); } } @@ -2534,9 +2513,6 @@ namespace eosio { } switch (msg.known_blocks.mode) { case none : { - if (msg.known_trx.mode != normal) { - return; - } break; } case last_irr_catch_up: @@ -2545,7 +2521,7 @@ namespace eosio { break; } case normal : { - dispatcher->recv_notice (c, msg, false); + dispatcher->recv_notice(c, msg, false); break; } default: { @@ -2558,15 +2534,23 @@ namespace eosio { } } - void net_plugin_impl::handle_message( connection_ptr c, const request_message &msg) { + void net_plugin_impl::handle_message(const connection_ptr& c, const request_message& msg) { + if( msg.req_blocks.ids.size() > 1 ) { + elog( "Invalid request_message, req_blocks.ids.size ${s}", ("s", msg.req_blocks.ids.size()) ); + close(c); + return; + } + switch (msg.req_blocks.mode) { case catch_up : peer_ilog(c, "received request_message:catch_up"); - c->blk_send_branch( ); + c->blk_send_branch(); break; case normal : peer_ilog(c, "received request_message:normal"); - c->blk_send(msg.req_blocks.ids); + if( !msg.req_blocks.ids.empty() ) { + c->blk_send(msg.req_blocks.ids.back()); + } break; default:; } @@ -2588,7 +2572,7 @@ namespace eosio { } - void net_plugin_impl::handle_message( connection_ptr c, const sync_request_message &msg) { + void net_plugin_impl::handle_message(const connection_ptr& c, const sync_request_message& msg) { if( msg.end_block == 0) { c->peer_requested.reset(); c->flush_queues(); @@ -2598,7 +2582,14 @@ namespace eosio { } } - void net_plugin_impl::handle_message( connection_ptr c, const packed_transaction &msg) { + size_t calc_trx_size( const packed_transaction_ptr& trx ) { + // transaction is stored packed and unpacked, double packed_size and size of signed as an approximation of use + return (trx->get_packed_transaction().size() * 2 + sizeof(trx->get_signed_transaction())) * 2 + + trx->get_packed_context_free_data().size() * 4 + + trx->get_signatures().size() * sizeof(signature_type); + } + + void net_plugin_impl::handle_message(const connection_ptr& c, const packed_transaction_ptr& trx) { fc_dlog(logger, "got a packed transaction, cancel wait"); peer_ilog(c, "received packed_transaction"); controller& cc = my_impl->chain_plug->chain(); @@ -2610,35 +2601,40 @@ namespace eosio { fc_dlog(logger, "got a txn during sync - dropping"); return; } - transaction_id_type tid = msg.id(); + + auto ptrx = std::make_shared( trx ); + const auto& tid = ptrx->id; + c->cancel_wait(); if(local_txns.get().find(tid) != local_txns.end()) { fc_dlog(logger, "got a duplicate transaction - dropping"); return; } dispatcher->recv_transaction(c, tid); - chain_plug->accept_transaction(msg, [=](const static_variant& result) { + c->trx_in_progress_size += calc_trx_size( ptrx->packed_trx ); + chain_plug->accept_transaction(ptrx, [c, this, ptrx](const static_variant& result) { + c->trx_in_progress_size -= calc_trx_size( ptrx->packed_trx ); if (result.contains()) { peer_dlog(c, "bad packed_transaction : ${m}", ("m",result.get()->what())); } else { auto trace = result.get(); if (!trace->except) { fc_dlog(logger, "chain accepted transaction"); - dispatcher->bcast_transaction(msg); + this->dispatcher->bcast_transaction(ptrx); return; } peer_elog(c, "bad packed_transaction : ${m}", ("m",trace->except->what())); } - dispatcher->rejected_transaction(tid); + dispatcher->rejected_transaction(ptrx->id); }); } - void net_plugin_impl::handle_message( connection_ptr c, const signed_block &msg) { + void net_plugin_impl::handle_message(const connection_ptr& c, const signed_block_ptr& msg) { controller &cc = chain_plug->chain(); - block_id_type blk_id = msg.id(); - uint32_t blk_num = msg.block_num(); + block_id_type blk_id = msg->id(); + uint32_t blk_num = msg->block_num(); fc_dlog(logger, "canceling wait on ${p}", ("p",c->peer_name())); c->cancel_wait(); @@ -2653,14 +2649,13 @@ namespace eosio { } dispatcher->recv_block(c, blk_id, blk_num); - fc::microseconds age( fc::time_point::now() - msg.timestamp); + fc::microseconds age( fc::time_point::now() - msg->timestamp); peer_ilog(c, "received signed_block : #${n} block age in secs = ${age}", ("n",blk_num)("age",age.to_seconds())); go_away_reason reason = fatal_other; try { - signed_block_ptr sbp = std::make_shared(msg); - chain_plug->accept_block(sbp); //, sync_master->is_active(c)); + chain_plug->accept_block(msg); //, sync_master->is_active(c)); reason = no_reason; } catch( const unlinkable_block_exception &ex) { peer_elog(c, "bad signed_block : ${m}", ("m",ex.what())); @@ -2683,7 +2678,7 @@ namespace eosio { update_block_num ubn(blk_num); if( reason == no_reason ) { - for (const auto &recpt : msg.transactions) { + for (const auto &recpt : msg->transactions) { auto id = (recpt.trx.which() == 0) ? recpt.trx.get() : recpt.trx.get().id(); auto ltx = local_txns.get().find(id); if( ltx != local_txns.end()) { @@ -2718,21 +2713,21 @@ namespace eosio { transaction_check->expires_from_now( txn_exp_period); transaction_check->async_wait( [this](boost::system::error_code ec) { if( !ec) { - expire_txns( ); + expire_txns(); } else { elog( "Error from transaction check monitor: ${m}",( "m", ec.message())); - start_txn_timer( ); + start_txn_timer(); } }); } void net_plugin_impl::ticker() { - keepalive_timer->expires_from_now (keepalive_interval); - keepalive_timer->async_wait ([this](boost::system::error_code ec) { - ticker (); + keepalive_timer->expires_from_now(keepalive_interval); + keepalive_timer->async_wait([this](boost::system::error_code ec) { + ticker(); if (ec) { - wlog ("Peer keepalive ticked sooner than expected: ${m}", ("m", ec.message())); + wlog("Peer keepalive ticked sooner than expected: ${m}", ("m", ec.message())); } for (auto &c : connections ) { if (c->socket->is_open()) { @@ -2750,24 +2745,37 @@ namespace eosio { } void net_plugin_impl::expire_txns() { - start_txn_timer( ); - auto &old = local_txns.get(); - auto ex_up = old.upper_bound( time_point::now()); - auto ex_lo = old.lower_bound( fc::time_point_sec( 0)); - old.erase( ex_lo, ex_up); + start_txn_timer(); - auto &stale = local_txns.get(); - controller &cc = chain_plug->chain(); - uint32_t bn = cc.last_irreversible_block_num(); - stale.erase( stale.lower_bound(1), stale.upper_bound(bn) ); + auto now = time_point::now(); + auto start_size = local_txns.size(); + + expire_local_txns(); + + controller& cc = chain_plug->chain(); + uint32_t lib = cc.last_irreversible_block_num(); for ( auto &c : connections ) { auto &stale_txn = c->trx_state.get(); - stale_txn.erase( stale_txn.lower_bound(1), stale_txn.upper_bound(bn) ); + stale_txn.erase( stale_txn.lower_bound(1), stale_txn.upper_bound(lib) ); auto &stale_txn_e = c->trx_state.get(); stale_txn_e.erase(stale_txn_e.lower_bound(time_point_sec()), stale_txn_e.upper_bound(time_point::now())); auto &stale_blk = c->blk_state.get(); - stale_blk.erase( stale_blk.lower_bound(1), stale_blk.upper_bound(bn) ); + stale_blk.erase( stale_blk.lower_bound(1), stale_blk.upper_bound(lib) ); } + fc_dlog(logger, "expire_txns ${n}us size ${s} removed ${r}", + ("n", time_point::now() - now)("s", start_size)("r", start_size - local_txns.size()) ); + } + + void net_plugin_impl::expire_local_txns() { + auto& old = local_txns.get(); + auto ex_lo = old.lower_bound( fc::time_point_sec(0) ); + auto ex_up = old.upper_bound( time_point::now() ); + old.erase( ex_lo, ex_up ); + + auto& stale = local_txns.get(); + controller& cc = chain_plug->chain(); + uint32_t lib = cc.last_irreversible_block_num(); + stale.erase( stale.lower_bound(1), stale.upper_bound(lib) ); } void net_plugin_impl::connection_monitor(std::weak_ptr from_connection) { @@ -2795,8 +2803,8 @@ namespace eosio { start_conn_timer(connector_period, std::weak_ptr()); } - void net_plugin_impl::close( connection_ptr c ) { - if( c->peer_addr.empty( ) && c->socket->is_open() ) { + void net_plugin_impl::close(const connection_ptr& c) { + if( c->peer_addr.empty() && c->socket->is_open() ) { if (num_clients == 0) { fc_wlog( logger, "num_clients already at 0"); } @@ -2807,40 +2815,19 @@ namespace eosio { c->close(); } - void net_plugin_impl::accepted_block_header(const block_state_ptr& block) { - fc_dlog(logger,"signaled, id = ${id}",("id", block->id)); - } - void net_plugin_impl::accepted_block(const block_state_ptr& block) { fc_dlog(logger,"signaled, id = ${id}",("id", block->id)); - dispatcher->bcast_block(*block->block); + dispatcher->bcast_block(block); } - void net_plugin_impl::irreversible_block(const block_state_ptr&block) { - fc_dlog(logger,"signaled, id = ${id}",("id", block->id)); - } - - void net_plugin_impl::accepted_transaction(const transaction_metadata_ptr& md) { - fc_dlog(logger,"signaled, id = ${id}",("id", md->id)); -// dispatcher->bcast_transaction(md->packed_trx); - } - - void net_plugin_impl::applied_transaction(const transaction_trace_ptr& txn) { - fc_dlog(logger,"signaled, id = ${id}",("id", txn->id)); - } - - void net_plugin_impl::accepted_confirmation(const header_confirmation& head) { - fc_dlog(logger,"signaled, id = ${id}",("id", head.block_id)); - } - - void net_plugin_impl::transaction_ack(const std::pair& results) { - transaction_id_type id = results.second->id(); + void net_plugin_impl::transaction_ack(const std::pair& results) { + const auto& id = results.second->id; if (results.first) { fc_ilog(logger,"signaled NACK, trx-id = ${id} : ${why}",("id", id)("why", results.first->to_detail_string())); dispatcher->rejected_transaction(id); } else { fc_ilog(logger,"signaled ACK, trx-id = ${id}",("id", id)); - dispatcher->bcast_transaction(*results.second); + dispatcher->bcast_transaction(results.second); } } @@ -2855,9 +2842,8 @@ namespace eosio { auto allowed_it = std::find(allowed_peers.begin(), allowed_peers.end(), msg.key); auto private_it = private_keys.find(msg.key); bool found_producer_key = false; - producer_plugin* pp = app().find_plugin(); - if(pp != nullptr) - found_producer_key = pp->is_producer_key(msg.key); + if(producer_plug != nullptr) + found_producer_key = producer_plug->is_producer_key(msg.key); if( allowed_it == allowed_peers.end() && private_it == private_keys.end() && !found_producer_key) { elog( "Peer ${peer} sent a handshake with an unauthorized key: ${key}.", ("peer", msg.p2p_address)("key", msg.key)); @@ -2917,9 +2903,8 @@ namespace eosio { auto private_key_itr = private_keys.find(signer); if(private_key_itr != private_keys.end()) return private_key_itr->second.sign(digest); - producer_plugin* pp = app().find_plugin(); - if(pp != nullptr && pp->get_state() == abstract_plugin::started) - return pp->sign_compact(signer, digest); + if(producer_plug != nullptr && producer_plug->get_state() == abstract_plugin::started) + return producer_plug->sign_compact(signer, digest); return chain::signature_type(); } @@ -2998,7 +2983,6 @@ namespace eosio { ( "network-version-match", bpo::value()->default_value(false), "True to require exact match of peer network version.") ( "sync-fetch-span", bpo::value()->default_value(def_sync_fetch_span), "number of blocks to retrieve in a chunk from any individual peer during synchronization") - ( "max-implicit-request", bpo::value()->default_value(def_max_just_send), "maximum sizes of transaction or block messages that are sent without first sending a notice") ( "use-socket-read-watermark", bpo::value()->default_value(false), "Enable expirimental socket read watermark optimization") ( "p2p-discoverable", bpo::value()->default_value(false), "True to p2p discoverable.") @@ -3034,7 +3018,6 @@ namespace eosio { my->max_cleanup_time_ms = options.at("max-cleanup-time-msec").as(); my->txn_exp_period = def_txn_expire_wait; my->resp_expected_period = def_resp_expected_wait; - my->dispatcher->just_send_it_max = options.at( "max-implicit-request" ).as(); my->max_client_count = options.at( "max-clients" ).as(); my->max_nodes_per_host = options.at( "p2p-max-nodes-per-host" ).as(); my->num_clients = 0; @@ -3045,7 +3028,7 @@ namespace eosio { my->p2p_discoverable=options.at( "p2p-discoverable" ).as(); my->resolver = std::make_shared( std::ref( app().get_io_service())); - if( options.count( "p2p-listen-endpoint" )) { + if( options.count( "p2p-listen-endpoint" ) && options.at("p2p-listen-endpoint").as().length()) { my->p2p_address = options.at( "p2p-listen-endpoint" ).as(); auto host = my->p2p_address.substr( 0, my->p2p_address.find( ':' )); auto port = my->p2p_address.substr( host.size() + 1, my->p2p_address.size()); @@ -3056,21 +3039,22 @@ namespace eosio { my->listen_endpoint = *my->resolver->resolve( query ); my->acceptor.reset( new tcp::acceptor( app().get_io_service())); - } - if( options.count( "p2p-server-address" )) { - my->p2p_address = options.at( "p2p-server-address" ).as(); - } else { - if( my->listen_endpoint.address().to_v4() == address_v4::any()) { - boost::system::error_code ec; - auto host = host_name( ec ); - if( ec.value() != boost::system::errc::success ) { - FC_THROW_EXCEPTION( fc::invalid_arg_exception, - "Unable to retrieve host_name. ${msg}", ("msg", ec.message())); + if( options.count( "p2p-server-address" )) { + my->p2p_address = options.at( "p2p-server-address" ).as(); + } else { + if( my->listen_endpoint.address().to_v4() == address_v4::any()) { + boost::system::error_code ec; + auto host = host_name( ec ); + if( ec.value() != boost::system::errc::success ) { + + FC_THROW_EXCEPTION( fc::invalid_arg_exception, + "Unable to retrieve host_name. ${msg}", ("msg", ec.message())); + } + auto port = my->p2p_address.substr( my->p2p_address.find( ':' ), my->p2p_address.size()); + my->p2p_address = host + port; } - auto port = my->p2p_address.substr( my->p2p_address.find( ':' ), my->p2p_address.size()); - my->p2p_address = host + port; } } @@ -3118,7 +3102,7 @@ namespace eosio { my->chain_plug = app().find_plugin(); EOS_ASSERT( my->chain_plug, chain::missing_chain_plugin_exception, "" ); - my->chain_id = app().get_plugin().get_chain_id(); + my->chain_id = my->chain_plug->get_chain_id(); fc::rand_pseudo_bytes( my->node_id.data(), my->node_id.data_size()); ilog( "my node_id is ${id}", ("id", my->node_id)); @@ -3128,6 +3112,7 @@ namespace eosio { } void net_plugin::plugin_startup() { + my->producer_plug = app().find_plugin(); if( my->acceptor ) { my->acceptor->open(my->listen_endpoint.protocol()); my->acceptor->set_option(tcp::acceptor::reuse_address(true)); @@ -3144,12 +3129,7 @@ namespace eosio { } chain::controller&cc = my->chain_plug->chain(); { - cc.accepted_block_header.connect( boost::bind(&net_plugin_impl::accepted_block_header, my.get(), _1)); cc.accepted_block.connect( boost::bind(&net_plugin_impl::accepted_block, my.get(), _1)); - cc.irreversible_block.connect( boost::bind(&net_plugin_impl::irreversible_block, my.get(), _1)); - cc.accepted_transaction.connect( boost::bind(&net_plugin_impl::accepted_transaction, my.get(), _1)); - cc.applied_transaction.connect( boost::bind(&net_plugin_impl::applied_transaction, my.get(), _1)); - cc.accepted_confirmation.connect( boost::bind(&net_plugin_impl::accepted_confirmation, my.get(), _1)); } my->incoming_transaction_ack_subscription = app().get_channel().subscribe(boost::bind(&net_plugin_impl::transaction_ack, my.get(), _1)); @@ -3244,13 +3224,13 @@ namespace eosio { } return result; } - connection_ptr net_plugin_impl::find_connection( string host )const { + connection_ptr net_plugin_impl::find_connection(const string& host )const { for( const auto& c : connections ) if( c->peer_addr == host ) return c; return connection_ptr(); } - uint16_t net_plugin_impl::to_protocol_version (uint16_t v) { + uint16_t net_plugin_impl::to_protocol_version(uint16_t v) { if (v >= net_version_base) { v -= net_version_base; return (v > net_version_range) ? 0 : v; diff --git a/plugins/producer_api_plugin/include/eosio/producer_api_plugin/producer_api_plugin.hpp b/plugins/producer_api_plugin/include/eosio/producer_api_plugin/producer_api_plugin.hpp index 4e7a5925f8a..137ef7b0703 100644 --- a/plugins/producer_api_plugin/include/eosio/producer_api_plugin/producer_api_plugin.hpp +++ b/plugins/producer_api_plugin/include/eosio/producer_api_plugin/producer_api_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/plugins/producer_api_plugin/producer_api_plugin.cpp b/plugins/producer_api_plugin/producer_api_plugin.cpp index 13599d5f834..7fcde1ac98c 100644 --- a/plugins/producer_api_plugin/producer_api_plugin.cpp +++ b/plugins/producer_api_plugin/producer_api_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/plugins/producer_plugin/CMakeLists.txt b/plugins/producer_plugin/CMakeLists.txt index d7f9188d5bb..fe161f8d913 100644 --- a/plugins/producer_plugin/CMakeLists.txt +++ b/plugins/producer_plugin/CMakeLists.txt @@ -5,6 +5,6 @@ add_library( producer_plugin ${HEADERS} ) -target_link_libraries( producer_plugin chain_plugin http_client_plugin appbase eosio_chain eos_utilities ) +target_link_libraries( producer_plugin chain_plugin http_client_plugin appbase eosio_chain ) target_include_directories( producer_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../chain_interface/include" ) diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp index f2e50e92849..c43f0e0f38b 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once @@ -23,6 +23,7 @@ class producer_plugin : public appbase::plugin { fc::optional max_irreversible_block_age; fc::optional produce_time_offset_us; fc::optional last_block_time_offset_us; + fc::optional max_scheduled_transaction_time_per_block_ms; fc::optional subjective_cpu_leeway_us; fc::optional incoming_defer_ratio; }; diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 2d60e92a006..7bcfb7042b7 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -1,11 +1,12 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include #include #include +#include #include #include @@ -131,11 +132,13 @@ class producer_plugin_impl : public std::enable_shared_from_this _producer_watermarks; pending_block_mode _pending_block_mode; transaction_id_with_expiry_index _persistent_transactions; + fc::optional _thread_pool; int32_t _max_transaction_time_ms; fc::microseconds _max_irreversible_block_age_us; int32_t _produce_time_offset_us = 0; int32_t _last_block_time_offset_us = 0; + int32_t _max_scheduled_transaction_time_per_block_ms; fc::time_point _irreversible_block_time; fc::microseconds _keosd_provider_timeout_us; @@ -144,6 +147,7 @@ class producer_plugin_impl : public std::enable_shared_from_this().chain(); + chain::controller& chain = chain_plug->chain(); const auto hbn = bsp->block_num; auto new_block_header = bsp->header; new_block_header.timestamp = new_block_header.timestamp.next(); @@ -285,18 +289,22 @@ class producer_plugin_impl : public std::enable_shared_from_thisid())); + auto id = block->id(); - EOS_ASSERT( block->timestamp < (fc::time_point::now() + fc::seconds(7)), block_from_the_future, "received a block from the future, ignoring it" ); + fc_dlog(_log, "received incoming block ${id}", ("id", id)); + EOS_ASSERT( block->timestamp < (fc::time_point::now() + fc::seconds( 7 )), block_from_the_future, + "received a block from the future, ignoring it: ${id}", ("id", id) ); - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = chain_plug->chain(); /* de-dupe here... no point in aborting block if we already know the block */ - auto id = block->id(); auto existing = chain.fetch_block_by_id( id ); if( existing ) { return; } + // start processing of block + auto bsf = chain.create_block_state_future( block ); + // abort the pending block chain.abort_block(); @@ -308,9 +316,9 @@ class producer_plugin_impl : public std::enable_shared_from_this().handle_guard_exception(e); + chain_plug->handle_guard_exception(e); return; } catch( const fc::exception& e ) { elog((e.to_detail_string())); @@ -338,10 +346,23 @@ class producer_plugin_impl : public std::enable_shared_from_this>> _pending_incoming_transactions; + std::deque>> _pending_incoming_transactions; + + void on_incoming_transaction_async(const transaction_metadata_ptr& trx, bool persist_until_expired, next_function next) { + chain::controller& chain = chain_plug->chain(); + const auto& cfg = chain.get_global_properties().configuration; + transaction_metadata::create_signing_keys_future( trx, *_thread_pool, chain.get_chain_id(), fc::microseconds( cfg.max_transaction_cpu_usage ) ); + boost::asio::post( *_thread_pool, [self = this, trx, persist_until_expired, next]() { + if( trx->signing_keys_future.valid() ) + trx->signing_keys_future.wait(); + app().get_io_service().post( [self, trx, persist_until_expired, next]() { + self->process_incoming_transaction_async( trx, persist_until_expired, next ); + }); + }); + } - void on_incoming_transaction_async(const packed_transaction_ptr& trx, bool persist_until_expired, next_function next) { - chain::controller& chain = app().get_plugin().chain(); + void process_incoming_transaction_async(const transaction_metadata_ptr& trx, bool persist_until_expired, next_function next) { + chain::controller& chain = chain_plug->chain(); if (!chain.pending_block_state()) { _pending_incoming_transactions.emplace_back(trx, persist_until_expired, next); return; @@ -352,34 +373,34 @@ class producer_plugin_impl : public std::enable_shared_from_this& response) { next(response); if (response.contains()) { - _transaction_ack_channel.publish(std::pair(response.get(), trx)); + _transaction_ack_channel.publish(std::pair(response.get(), trx)); if (_pending_block_mode == pending_block_mode::producing) { fc_dlog(_trx_trace_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is REJECTING tx: ${txid} : ${why} ", ("block_num", chain.head_block_num() + 1) ("prod", chain.pending_block_state()->header.producer) - ("txid", trx->id()) + ("txid", trx->id) ("why",response.get()->what())); } else { fc_dlog(_trx_trace_log, "[TRX_TRACE] Speculative execution is REJECTING tx: ${txid} : ${why} ", - ("txid", trx->id()) + ("txid", trx->id) ("why",response.get()->what())); } } else { - _transaction_ack_channel.publish(std::pair(nullptr, trx)); + _transaction_ack_channel.publish(std::pair(nullptr, trx)); if (_pending_block_mode == pending_block_mode::producing) { fc_dlog(_trx_trace_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is ACCEPTING tx: ${txid}", ("block_num", chain.head_block_num() + 1) ("prod", chain.pending_block_state()->header.producer) - ("txid", trx->id())); + ("txid", trx->id)); } else { fc_dlog(_trx_trace_log, "[TRX_TRACE] Speculative execution is ACCEPTING tx: ${txid}", - ("txid", trx->id())); + ("txid", trx->id)); } } }; - auto id = trx->id(); - if( fc::time_point(trx->expiration()) < block_time ) { + const auto& id = trx->id; + if( fc::time_point(trx->packed_trx->expiration()) < block_time ) { send_response(std::static_pointer_cast(std::make_shared(FC_LOG_MESSAGE(error, "expired transaction ${id}", ("id", id)) ))); return; } @@ -391,13 +412,14 @@ class producer_plugin_impl : public std::enable_shared_from_this(*trx), deadline); + auto trace = chain.push_transaction(trx, deadline); if (trace->except) { if (failure_is_subjective(*trace->except, deadline_is_subjective)) { _pending_incoming_transactions.emplace_back(trx, persist_until_expired, next); @@ -405,10 +427,10 @@ class producer_plugin_impl : public std::enable_shared_from_thisheader.producer) - ("txid", trx->id())); + ("txid", trx->id)); } else { fc_dlog(_trx_trace_log, "[TRX_TRACE] Speculative execution COULD NOT FIT tx: ${txid} RETRYING", - ("txid", trx->id())); + ("txid", trx->id)); } } else { auto e_ptr = trace->except->dynamic_copy_exception(); @@ -418,13 +440,13 @@ class producer_plugin_impl : public std::enable_shared_from_thisid(), trx->expiration()}); + _persistent_transactions.insert(transaction_id_with_expiry{trx->id, trx->packed_trx->expiration()}); } send_response(trace); } } catch ( const guard_exception& e ) { - app().get_plugin().handle_guard_exception(e); + chain_plug->handle_guard_exception(e); } catch ( boost::interprocess::bad_alloc& ) { chain_plugin::handle_db_exhaustion(); } CATCH_AND_CALL(send_response); @@ -451,9 +473,10 @@ class producer_plugin_impl : public std::enable_shared_from_this& weak_this, const block_timestamp_type& current_block_time); }; @@ -522,8 +545,12 @@ void producer_plugin::set_program_options( "offset of non last block producing time in microseconds. Negative number results in blocks to go out sooner, and positive number results in blocks to go out later") ("last-block-time-offset-us", boost::program_options::value()->default_value(0), "offset of last block producing time in microseconds. Negative number results in blocks to go out sooner, and positive number results in blocks to go out later") + ("max-scheduled-transaction-time-per-block-ms", boost::program_options::value()->default_value(100), + "Maximum wall-clock time, in milliseconds, spent retiring scheduled transactions in any block before returning to normal transaction processing.") ("incoming-defer-ratio", bpo::value()->default_value(1.0), "ratio between incoming transations and deferred transactions when both are exhausted") + ("producer-threads", bpo::value()->default_value(config::default_controller_thread_pool_size), + "Number of worker threads in producer thread pool") ("snapshots-dir", bpo::value()->default_value("snapshots"), "the location of the snapshots directory (absolute path or relative to application data dir)") ; @@ -595,6 +622,8 @@ make_keosd_signature_provider(const std::shared_ptr& impl, void producer_plugin::plugin_initialize(const boost::program_options::variables_map& options) { try { + my->chain_plug = app().find_plugin(); + EOS_ASSERT( my->chain_plug, plugin_config_exception, "chain_plugin not found" ); my->_options = &options; LOAD_VALUE_SET(options, "producer-name", my->_producers, types::account_name) @@ -648,12 +677,19 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ my->_last_block_time_offset_us = options.at("last-block-time-offset-us").as(); + my->_max_scheduled_transaction_time_per_block_ms = options.at("max-scheduled-transaction-time-per-block-ms").as(); + my->_max_transaction_time_ms = options.at("max-transaction-time").as(); my->_max_irreversible_block_age_us = fc::seconds(options.at("max-irreversible-block-age").as()); my->_incoming_defer_ratio = options.at("incoming-defer-ratio").as(); + auto thread_pool_size = options.at( "producer-threads" ).as(); + EOS_ASSERT( thread_pool_size > 0, plugin_config_exception, + "producer-threads ${num} must be greater than 0", ("num", thread_pool_size)); + my->_thread_pool.emplace( thread_pool_size ); + if( options.count( "snapshots-dir" )) { auto sd = options.at( "snapshots-dir" ).as(); if( sd.is_relative()) { @@ -675,7 +711,7 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ } FC_LOG_AND_DROP(); }); - my->_incoming_transaction_subscription = app().get_channel().subscribe([this](const packed_transaction_ptr& trx){ + my->_incoming_transaction_subscription = app().get_channel().subscribe([this](const transaction_metadata_ptr& trx){ try { my->on_incoming_transaction_async(trx, false, [](const auto&){}); } FC_LOG_AND_DROP(); @@ -685,7 +721,7 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ my->on_incoming_block(block); }); - my->_incoming_transaction_async_provider = app().get_method().register_provider([this](const packed_transaction_ptr& trx, bool persist_until_expired, next_function next) -> void { + my->_incoming_transaction_async_provider = app().get_method().register_provider([this](const transaction_metadata_ptr& trx, bool persist_until_expired, next_function next) -> void { return my->on_incoming_transaction_async(trx, persist_until_expired, next ); }); @@ -713,7 +749,7 @@ void producer_plugin::plugin_startup() ilog("producer plugin: plugin_startup() begin"); - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = my->chain_plug->chain(); EOS_ASSERT( my->_producers.empty() || chain.get_read_mode() == chain::db_read_mode::SPECULATIVE, plugin_config_exception, "node cannot have any producer-name configured because block production is impossible when read_mode is not \"speculative\"" ); @@ -755,6 +791,10 @@ void producer_plugin::plugin_shutdown() { edump((e.to_detail_string())); } + if( my->_thread_pool ) { + my->_thread_pool->join(); + my->_thread_pool->stop(); + } my->_accepted_block_connection.reset(); my->_irreversible_block_connection.reset(); } @@ -769,7 +809,7 @@ void producer_plugin::resume() { // re-evaluate that now // if (my->_pending_block_mode == pending_block_mode::speculating) { - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = my->chain_plug->chain(); chain.abort_block(); my->schedule_production_loop(); } @@ -799,18 +839,22 @@ void producer_plugin::update_runtime_options(const runtime_options& options) { my->_last_block_time_offset_us = *options.last_block_time_offset_us; } + if (options.max_scheduled_transaction_time_per_block_ms) { + my->_max_scheduled_transaction_time_per_block_ms = *options.max_scheduled_transaction_time_per_block_ms; + } + if (options.incoming_defer_ratio) { my->_incoming_defer_ratio = *options.incoming_defer_ratio; } if (check_speculating && my->_pending_block_mode == pending_block_mode::speculating) { - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = my->chain_plug->chain(); chain.abort_block(); my->schedule_production_loop(); } if (options.subjective_cpu_leeway_us) { - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = my->chain_plug->chain(); chain.set_subjective_cpu_leeway(fc::microseconds(*options.subjective_cpu_leeway_us)); } } @@ -820,26 +864,27 @@ producer_plugin::runtime_options producer_plugin::get_runtime_options() const { my->_max_transaction_time_ms, my->_max_irreversible_block_age_us.count() < 0 ? -1 : my->_max_irreversible_block_age_us.count() / 1'000'000, my->_produce_time_offset_us, - my->_last_block_time_offset_us + my->_last_block_time_offset_us, + my->_max_scheduled_transaction_time_per_block_ms }; } void producer_plugin::add_greylist_accounts(const greylist_params& params) { - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = my->chain_plug->chain(); for (auto &acc : params.accounts) { chain.add_resource_greylist(acc); } } void producer_plugin::remove_greylist_accounts(const greylist_params& params) { - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = my->chain_plug->chain(); for (auto &acc : params.accounts) { chain.remove_resource_greylist(acc); } } producer_plugin::greylist_params producer_plugin::get_greylist() const { - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = my->chain_plug->chain(); greylist_params result; const auto& list = chain.get_resource_greylist(); result.accounts.reserve(list.size()); @@ -850,7 +895,7 @@ producer_plugin::greylist_params producer_plugin::get_greylist() const { } producer_plugin::whitelist_blacklist producer_plugin::get_whitelist_blacklist() const { - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = my->chain_plug->chain(); return { chain.get_actor_whitelist(), chain.get_actor_blacklist(), @@ -862,7 +907,7 @@ producer_plugin::whitelist_blacklist producer_plugin::get_whitelist_blacklist() } void producer_plugin::set_whitelist_blacklist(const producer_plugin::whitelist_blacklist& params) { - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = my->chain_plug->chain(); if(params.actor_whitelist.valid()) chain.set_actor_whitelist(*params.actor_whitelist); if(params.actor_blacklist.valid()) chain.set_actor_blacklist(*params.actor_blacklist); if(params.contract_whitelist.valid()) chain.set_contract_whitelist(*params.contract_whitelist); @@ -872,7 +917,7 @@ void producer_plugin::set_whitelist_blacklist(const producer_plugin::whitelist_b } producer_plugin::integrity_hash_information producer_plugin::get_integrity_hash() const { - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = my->chain_plug->chain(); auto reschedule = fc::make_scoped_exit([this](){ my->schedule_production_loop(); @@ -889,7 +934,7 @@ producer_plugin::integrity_hash_information producer_plugin::get_integrity_hash( } producer_plugin::snapshot_information producer_plugin::create_snapshot() const { - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = my->chain_plug->chain(); auto reschedule = fc::make_scoped_exit([this](){ my->schedule_production_loop(); @@ -920,7 +965,7 @@ producer_plugin::snapshot_information producer_plugin::create_snapshot() const { } optional producer_plugin_impl::calculate_next_block_time(const account_name& producer_name, const block_timestamp_type& current_block_time) const { - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = chain_plug->chain(); const auto& hbs = chain.head_block_state(); const auto& active_schedule = hbs->active_schedule.producers; @@ -976,7 +1021,7 @@ optional producer_plugin_impl::calculate_next_block_time(const a } fc::time_point producer_plugin_impl::calculate_pending_block_time() const { - const chain::controller& chain = app().get_plugin().chain(); + const chain::controller& chain = chain_plug->chain(); const fc::time_point now = fc::time_point::now(); const fc::time_point base = std::max(now, chain.head_block_time()); const int64_t min_time_to_next_block = (config::block_interval_us) - (base.time_since_epoch().count() % (config::block_interval_us) ); @@ -989,6 +1034,11 @@ fc::time_point producer_plugin_impl::calculate_pending_block_time() const { return block_time; } +fc::time_point producer_plugin_impl::calculate_block_deadline( const fc::time_point& block_time ) const { + bool last_block = ((block_timestamp_type(block_time).slot % config::producer_repetitions) == config::producer_repetitions - 1); + return block_time + fc::microseconds(last_block ? _last_block_time_offset_us : _produce_time_offset_us); +} + enum class tx_category { PERSISTED, UNEXPIRED_UNPERSISTED, @@ -996,8 +1046,8 @@ enum class tx_category { }; -producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool &last_block) { - chain::controller& chain = app().get_plugin().chain(); +producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { + chain::controller& chain = chain_plug->chain(); if( chain.get_read_mode() == chain::db_read_mode::READ_ONLY ) return start_block_result::waiting; @@ -1012,7 +1062,6 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool _pending_block_mode = pending_block_mode::producing; // Not our turn - last_block = ((block_timestamp_type(block_time).slot % config::producer_repetitions) == config::producer_repetitions - 1); const auto& scheduled_producer = hbs->get_scheduled_producer(block_time); auto currrent_watermark_itr = _producer_watermarks.find(scheduled_producer.producer_name); auto signature_provider_itr = _signature_providers.find(scheduled_producer.block_signing_key); @@ -1082,6 +1131,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool const auto& pbs = chain.pending_block_state(); if (pbs) { + const fc::time_point preprocess_deadline = calculate_block_deadline(block_time); if (_pending_block_mode == pending_block_mode::producing && pbs->block_signing_key != scheduled_producer.block_signing_key) { elog("Block Signing Key is not expected value, reverting to speculative mode! [expected: \"${expected}\", actual: \"${actual\"", ("expected", scheduled_producer.block_signing_key)("actual", pbs->block_signing_key)); @@ -1099,6 +1149,10 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool int orig_count = _persistent_transactions.size(); while(!persisted_by_expiry.empty() && persisted_by_expiry.begin()->expiry <= pbs->header.timestamp.to_time_point()) { + if (preprocess_deadline <= fc::time_point::now()) { + exhausted = true; + break; + } auto const& txid = persisted_by_expiry.begin()->trx_id; if (_pending_block_mode == pending_block_mode::producing) { fc_dlog(_trx_trace_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is EXPIRING PERSISTED tx: ${txid}", @@ -1114,9 +1168,15 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool num_expired_persistent++; } - fc_dlog(_log, "Processed ${n} persisted transactions, Expired ${expired}", - ("n", orig_count) - ("expired", num_expired_persistent)); + if( exhausted ) { + fc_wlog( _log, "Unable to process all ${n} persisted transactions before deadline, Expired ${expired}", + ( "n", orig_count ) + ( "expired", num_expired_persistent ) ); + } else { + fc_dlog( _log, "Processed ${n} persisted transactions, Expired ${expired}", + ( "n", orig_count ) + ( "expired", num_expired_persistent ) ); + } } try { @@ -1127,15 +1187,17 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool if (_producers.empty() && persisted_by_id.empty()) { // if this node can never produce and has no persisted transactions, // there is no need for unapplied transactions they can be dropped - chain.drop_all_unapplied_transactions(); + chain.get_unapplied_transactions().clear(); } else { - std::vector apply_trxs; - { // derive appliable transactions from unapplied_transactions and drop droppable transactions - auto unapplied_trxs = chain.get_unapplied_transactions(); - apply_trxs.reserve(unapplied_trxs.size()); - + // derive appliable transactions from unapplied_transactions and drop droppable transactions + unapplied_transactions_type& unapplied_trxs = chain.get_unapplied_transactions(); + if( !unapplied_trxs.empty() ) { + auto unapplied_trxs_size = unapplied_trxs.size(); + int num_applied = 0; + int num_failed = 0; + int num_processed = 0; auto calculate_transaction_category = [&](const transaction_metadata_ptr& trx) { - if (trx->packed_trx.expiration() < pbs->header.timestamp.to_time_point()) { + if (trx->packed_trx->expiration() < pbs->header.timestamp.to_time_point()) { return tx_category::EXPIRED; } else if (persisted_by_id.find(trx->id) != persisted_by_id.end()) { return tx_category::PERSISTED; @@ -1144,64 +1206,66 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool } }; - for (auto& trx: unapplied_trxs) { + auto itr = unapplied_trxs.begin(); + while( itr != unapplied_trxs.end() ) { + auto itr_next = itr; // save off next since itr may be invalidated by loop + ++itr_next; + + if( preprocess_deadline <= fc::time_point::now() ) exhausted = true; + if( exhausted ) break; + const auto& trx = itr->second; auto category = calculate_transaction_category(trx); - if (category == tx_category::EXPIRED || (category == tx_category::UNEXPIRED_UNPERSISTED && _producers.empty())) { + if (category == tx_category::EXPIRED || + (category == tx_category::UNEXPIRED_UNPERSISTED && _producers.empty())) + { if (!_producers.empty()) { fc_dlog(_trx_trace_log, "[TRX_TRACE] Node with producers configured is dropping an EXPIRED transaction that was PREVIOUSLY ACCEPTED : ${txid}", ("txid", trx->id)); } - chain.drop_unapplied_transaction(trx); - } else if (category == tx_category::PERSISTED || (category == tx_category::UNEXPIRED_UNPERSISTED && _pending_block_mode == pending_block_mode::producing)) { - apply_trxs.emplace_back(std::move(trx)); - } - } - } - - if (!apply_trxs.empty()) { - int num_applied = 0; - int num_failed = 0; - int num_processed = 0; - - for (const auto& trx: apply_trxs) { - if (block_time <= fc::time_point::now()) exhausted = true; - if (exhausted) { - break; - } - num_processed++; - - try { - auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); - bool deadline_is_subjective = false; - if (_max_transaction_time_ms < 0 || (_pending_block_mode == pending_block_mode::producing && block_time < deadline)) { - deadline_is_subjective = true; - deadline = block_time; - } + itr = unapplied_trxs.erase( itr ); // unapplied_trxs map has not been modified, so simply erase and continue + continue; + } else if (category == tx_category::PERSISTED || + (category == tx_category::UNEXPIRED_UNPERSISTED && _pending_block_mode == pending_block_mode::producing)) + { + ++num_processed; + + try { + auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); + bool deadline_is_subjective = false; + if (_max_transaction_time_ms < 0 || (_pending_block_mode == pending_block_mode::producing && preprocess_deadline < deadline)) { + deadline_is_subjective = true; + deadline = preprocess_deadline; + } - auto trace = chain.push_transaction(trx, deadline); - if (trace->except) { - if (failure_is_subjective(*trace->except, deadline_is_subjective)) { - exhausted = true; + auto trace = chain.push_transaction(trx, deadline); + if (trace->except) { + if (failure_is_subjective(*trace->except, deadline_is_subjective)) { + exhausted = true; + break; + } else { + // this failed our configured maximum transaction time, we don't want to replay it + // chain.plus_transactions can modify unapplied_trxs, so erase by id + unapplied_trxs.erase( trx->signed_id ); + ++num_failed; + } } else { - // this failed our configured maximum transaction time, we don't want to replay it - chain.drop_unapplied_transaction(trx); - num_failed++; + ++num_applied; } - } else { - num_applied++; - } - } catch ( const guard_exception& e ) { - app().get_plugin().handle_guard_exception(e); - return start_block_result::failed; - } FC_LOG_AND_DROP(); + } catch ( const guard_exception& e ) { + chain_plug->handle_guard_exception(e); + return start_block_result::failed; + } FC_LOG_AND_DROP(); + } + + itr = itr_next; } fc_dlog(_log, "Processed ${m} of ${n} previously applied transactions, Applied ${applied}, Failed/Dropped ${failed}", - ("m", num_processed) - ("n", apply_trxs.size()) - ("applied", num_applied) - ("failed", num_failed)); + ("m", num_processed) + ("n", unapplied_trxs_size) + ("applied", num_applied) + ("failed", num_failed)); } } @@ -1214,6 +1278,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool int orig_count = _blacklisted_transactions.size(); while (!blacklist_by_expiry.empty() && blacklist_by_expiry.begin()->expiry <= now) { + if (preprocess_deadline <= fc::time_point::now()) break; blacklist_by_expiry.erase(blacklist_by_expiry.begin()); num_expired++; } @@ -1223,78 +1288,108 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool ("expired", num_expired)); } - auto scheduled_trxs = chain.get_scheduled_transactions(); - if (!scheduled_trxs.empty()) { - int num_applied = 0; - int num_failed = 0; - int num_processed = 0; + // scheduled transactions + int num_applied = 0; + int num_failed = 0; + int num_processed = 0; + + auto scheduled_trx_deadline = preprocess_deadline; + if (_max_scheduled_transaction_time_per_block_ms >= 0) { + scheduled_trx_deadline = std::min( + scheduled_trx_deadline, + fc::time_point::now() + fc::milliseconds(_max_scheduled_transaction_time_per_block_ms) + ); + } + time_point pending_block_time = chain.pending_block_time(); + const auto& sch_idx = chain.db().get_index(); + const auto scheduled_trxs_size = sch_idx.size(); + auto sch_itr = sch_idx.begin(); + while( sch_itr != sch_idx.end() ) { + if( sch_itr->delay_until > pending_block_time) break; // not scheduled yet + if( sch_itr->published >= pending_block_time ) { + ++sch_itr; + continue; // do not allow schedule and execute in same block + } + if( scheduled_trx_deadline <= fc::time_point::now() ) { + exhausted = true; + break; + } - for (const auto& trx : scheduled_trxs) { - if (block_time <= fc::time_point::now()) exhausted = true; - if (exhausted) { - break; - } + const transaction_id_type trx_id = sch_itr->trx_id; // make copy since reference could be invalidated + if (blacklist_by_id.find(trx_id) != blacklist_by_id.end()) { + ++sch_itr; + continue; + } - num_processed++; + auto sch_itr_next = sch_itr; // save off next since sch_itr may be invalidated by loop + ++sch_itr_next; + const auto next_delay_until = sch_itr_next != sch_idx.end() ? sch_itr_next->delay_until : sch_itr->delay_until; + const auto next_id = sch_itr_next != sch_idx.end() ? sch_itr_next->id : sch_itr->id; - // configurable ratio of incoming txns vs deferred txns - while (_incoming_trx_weight >= 1.0 && orig_pending_txn_size && _pending_incoming_transactions.size()) { - auto e = _pending_incoming_transactions.front(); - _pending_incoming_transactions.pop_front(); - --orig_pending_txn_size; - _incoming_trx_weight -= 1.0; - on_incoming_transaction_async(std::get<0>(e), std::get<1>(e), std::get<2>(e)); - } + num_processed++; - if (block_time <= fc::time_point::now()) { - exhausted = true; - break; - } + // configurable ratio of incoming txns vs deferred txns + while (_incoming_trx_weight >= 1.0 && orig_pending_txn_size && _pending_incoming_transactions.size()) { + if (scheduled_trx_deadline <= fc::time_point::now()) break; - if (blacklist_by_id.find(trx) != blacklist_by_id.end()) { - continue; - } + auto e = _pending_incoming_transactions.front(); + _pending_incoming_transactions.pop_front(); + --orig_pending_txn_size; + _incoming_trx_weight -= 1.0; + process_incoming_transaction_async(std::get<0>(e), std::get<1>(e), std::get<2>(e)); + } - try { - auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); - bool deadline_is_subjective = false; - if (_max_transaction_time_ms < 0 || (_pending_block_mode == pending_block_mode::producing && block_time < deadline)) { - deadline_is_subjective = true; - deadline = block_time; - } + if (scheduled_trx_deadline <= fc::time_point::now()) { + exhausted = true; + break; + } - auto trace = chain.push_scheduled_transaction(trx, deadline); - if (trace->except) { - if (failure_is_subjective(*trace->except, deadline_is_subjective)) { - exhausted = true; - } else { - auto expiration = fc::time_point::now() + fc::seconds(chain.get_global_properties().configuration.deferred_trx_expiration_window); - // this failed our configured maximum transaction time, we don't want to replay it add it to a blacklist - _blacklisted_transactions.insert(transaction_id_with_expiry{trx, expiration}); - num_failed++; - } + try { + auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); + bool deadline_is_subjective = false; + if (_max_transaction_time_ms < 0 || (_pending_block_mode == pending_block_mode::producing && scheduled_trx_deadline < deadline)) { + deadline_is_subjective = true; + deadline = scheduled_trx_deadline; + } + + auto trace = chain.push_scheduled_transaction(trx_id, deadline); + if (trace->except) { + if (failure_is_subjective(*trace->except, deadline_is_subjective)) { + exhausted = true; + break; } else { - num_applied++; + auto expiration = fc::time_point::now() + fc::seconds(chain.get_global_properties().configuration.deferred_trx_expiration_window); + // this failed our configured maximum transaction time, we don't want to replay it add it to a blacklist + _blacklisted_transactions.insert(transaction_id_with_expiry{trx_id, expiration}); + num_failed++; } - } catch ( const guard_exception& e ) { - app().get_plugin().handle_guard_exception(e); - return start_block_result::failed; - } FC_LOG_AND_DROP(); + } else { + num_applied++; + } + } catch ( const guard_exception& e ) { + chain_plug->handle_guard_exception(e); + return start_block_result::failed; + } FC_LOG_AND_DROP(); - _incoming_trx_weight += _incoming_defer_ratio; - if (!orig_pending_txn_size) _incoming_trx_weight = 0.0; - } + _incoming_trx_weight += _incoming_defer_ratio; + if (!orig_pending_txn_size) _incoming_trx_weight = 0.0; - fc_dlog(_log, "Processed ${m} of ${n} scheduled transactions, Applied ${applied}, Failed/Dropped ${failed}", - ("m", num_processed) - ("n", scheduled_trxs.size()) - ("applied", num_applied) - ("failed", num_failed)); + if( sch_itr_next == sch_idx.end() ) break; + sch_itr = sch_idx.lower_bound( boost::make_tuple( next_delay_until, next_id ) ); + } + if( scheduled_trxs_size > 0 ) { + fc_dlog( _log, + "Processed ${m} of ${n} scheduled transactions, Applied ${applied}, Failed/Dropped ${failed}", + ( "m", num_processed ) + ( "n", scheduled_trxs_size ) + ( "applied", num_applied ) + ( "failed", num_failed ) ); } + } - if (exhausted || block_time <= fc::time_point::now()) { + if (exhausted || preprocess_deadline <= fc::time_point::now()) { return start_block_result::exhausted; } else { // attempt to apply any pending incoming transactions @@ -1303,11 +1398,11 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool if (!_pending_incoming_transactions.empty()) { fc_dlog(_log, "Processing ${n} pending transactions"); while (orig_pending_txn_size && _pending_incoming_transactions.size()) { + if (preprocess_deadline <= fc::time_point::now()) return start_block_result::exhausted; auto e = _pending_incoming_transactions.front(); _pending_incoming_transactions.pop_front(); --orig_pending_txn_size; - on_incoming_transaction_async(std::get<0>(e), std::get<1>(e), std::get<2>(e)); - if (block_time <= fc::time_point::now()) return start_block_result::exhausted; + process_incoming_transaction_async(std::get<0>(e), std::get<1>(e), std::get<2>(e)); } } return start_block_result::succeeded; @@ -1324,12 +1419,11 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool } void producer_plugin_impl::schedule_production_loop() { - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = chain_plug->chain(); _timer.cancel(); std::weak_ptr weak_this = shared_from_this(); - bool last_block; - auto result = start_block(last_block); + auto result = start_block(); if (result == start_block_result::failed) { elog("Failed to start a pending block, will try again later"); @@ -1355,11 +1449,12 @@ void producer_plugin_impl::schedule_production_loop() { // we succeeded but block may be exhausted static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); - if (result == start_block_result::succeeded) { + auto deadline = calculate_block_deadline(chain.pending_block_time()); + + if (deadline > fc::time_point::now()) { // ship this block off no later than its deadline EOS_ASSERT( chain.pending_block_state(), missing_pending_block_state, "producing without pending_block_state, start_block succeeded" ); - auto deadline = chain.pending_block_time().time_since_epoch().count() + (last_block ? _last_block_time_offset_us : _produce_time_offset_us); - _timer.expires_at( epoch + boost::posix_time::microseconds( deadline )); + _timer.expires_at( epoch + boost::posix_time::microseconds( deadline.time_since_epoch().count() )); fc_dlog(_log, "Scheduling Block Production on Normal Block #${num} for ${time}", ("num", chain.pending_block_state()->block_num)("time",deadline)); } else { EOS_ASSERT( chain.pending_block_state(), missing_pending_block_state, "producing without pending_block_state" ); @@ -1435,7 +1530,7 @@ bool producer_plugin_impl::maybe_produce_block() { produce_block(); return true; } catch ( const guard_exception& e ) { - app().get_plugin().handle_guard_exception(e); + chain_plug->handle_guard_exception(e); return false; } FC_LOG_AND_DROP(); } catch ( boost::interprocess::bad_alloc&) { @@ -1444,7 +1539,7 @@ bool producer_plugin_impl::maybe_produce_block() { } fc_dlog(_log, "Aborting block due to produce_block error"); - chain::controller& chain = app().get_plugin().chain(); + chain::controller& chain = chain_plug->chain(); chain.abort_block(); return false; } @@ -1467,7 +1562,7 @@ static auto maybe_make_debug_time_logger() -> fc::optional().chain(); + chain::controller& chain = chain_plug->chain(); const auto& pbs = chain.pending_block_state(); const auto& hbs = chain.head_block_state(); EOS_ASSERT(pbs, missing_pending_block_state, "pending_block_state does not exist but it should, another plugin may have corrupted it"); diff --git a/plugins/state_history_plugin/.clang-format b/plugins/state_history_plugin/.clang-format new file mode 100644 index 00000000000..42dd5b7832c --- /dev/null +++ b/plugins/state_history_plugin/.clang-format @@ -0,0 +1,8 @@ +BasedOnStyle: LLVM +IndentWidth: 3 +ColumnLimit: 120 +PointerAlignment: Left +AlwaysBreakTemplateDeclarations: true +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +BreakConstructorInitializers: BeforeComma diff --git a/plugins/state_history_plugin/CMakeLists.txt b/plugins/state_history_plugin/CMakeLists.txt new file mode 100644 index 00000000000..21f0e10a900 --- /dev/null +++ b/plugins/state_history_plugin/CMakeLists.txt @@ -0,0 +1,8 @@ +file(GLOB HEADERS "include/eosio/state_history_plugin/*.hpp") +add_library( state_history_plugin + state_history_plugin.cpp + state_history_plugin_abi.cpp + ${HEADERS} ) + +target_link_libraries( state_history_plugin chain_plugin eosio_chain appbase ) +target_include_directories( state_history_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp new file mode 100644 index 00000000000..1644d29a404 --- /dev/null +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp @@ -0,0 +1,279 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace eosio { + +/* + * *.log: + * +---------+----------------+-----------+------------------+-----+---------+----------------+ + * | Entry i | Pos of Entry i | Entry i+1 | Pos of Entry i+1 | ... | Entry z | Pos of Entry z | + * +---------+----------------+-----------+------------------+-----+---------+----------------+ + * + * *.index: + * +-----------+-------------+-----+-----------+ + * | Summary i | Summary i+1 | ... | Summary z | + * +-----------+-------------+-----+-----------+ + * + * each entry: + * uint32_t block_num + * block_id_type block_id + * uint64_t size of payload + * uint8_t version + * payload + * + * each summary: + * uint64_t position of entry in *.log + * + * state payload: + * uint32_t size of deltas + * char[] deltas + */ + +// todo: look into switching this to serialization instead of memcpy +// todo: consider reworking versioning +// todo: consider dropping block_num since it's included in block_id +// todo: currently only checks version on the first record. Need in recover_blocks +struct state_history_log_header { + uint32_t block_num = 0; + chain::block_id_type block_id; + uint64_t payload_size = 0; + uint8_t version = 0; +}; + +struct state_history_summary { + uint64_t pos = 0; +}; + +class state_history_log { + private: + const char* const name = ""; + std::string log_filename; + std::string index_filename; + std::fstream log; + std::fstream index; + uint32_t _begin_block = 0; + uint32_t _end_block = 0; + chain::block_id_type last_block_id; + + public: + state_history_log(const char* const name, std::string log_filename, std::string index_filename) + : name(name) + , log_filename(std::move(log_filename)) + , index_filename(std::move(index_filename)) { + open_log(); + open_index(); + } + + uint32_t begin_block() const { return _begin_block; } + uint32_t end_block() const { return _end_block; } + + template + void write_entry(const state_history_log_header& header, const chain::block_id_type& prev_id, F write_payload) { + EOS_ASSERT(_begin_block == _end_block || header.block_num <= _end_block, chain::plugin_exception, + "missed a block in ${name}.log", ("name", name)); + + if (_begin_block != _end_block && header.block_num > _begin_block) { + if (header.block_num == _end_block) { + EOS_ASSERT(prev_id == last_block_id, chain::plugin_exception, "missed a fork change in ${name}.log", + ("name", name)); + } else { + state_history_log_header prev; + get_entry(header.block_num - 1, prev); + EOS_ASSERT(prev_id == prev.block_id, chain::plugin_exception, "missed a fork change in ${name}.log", + ("name", name)); + } + } + + if (header.block_num < _end_block) + truncate(header.block_num); + log.seekg(0, std::ios_base::end); + uint64_t pos = log.tellg(); + log.write((char*)&header, sizeof(header)); + write_payload(log); + uint64_t end = log.tellg(); + EOS_ASSERT(end == pos + sizeof(header) + header.payload_size, chain::plugin_exception, + "wrote payload with incorrect size to ${name}.log", ("name", name)); + log.write((char*)&pos, sizeof(pos)); + + index.seekg(0, std::ios_base::end); + state_history_summary summary{.pos = pos}; + index.write((char*)&summary, sizeof(summary)); + if (_begin_block == _end_block) + _begin_block = header.block_num; + _end_block = header.block_num + 1; + last_block_id = header.block_id; + } + + // returns stream positioned at payload + std::fstream& get_entry(uint32_t block_num, state_history_log_header& header) { + EOS_ASSERT(block_num >= _begin_block && block_num < _end_block, chain::plugin_exception, + "read non-existing block in ${name}.log", ("name", name)); + log.seekg(get_pos(block_num)); + log.read((char*)&header, sizeof(header)); + return log; + } + + chain::block_id_type get_block_id(uint32_t block_num) { + state_history_log_header header; + get_entry(block_num, header); + return header.block_id; + } + + private: + bool get_last_block(uint64_t size) { + state_history_log_header header; + uint64_t suffix; + log.seekg(size - sizeof(suffix)); + log.read((char*)&suffix, sizeof(suffix)); + if (suffix > size || suffix + sizeof(header) > size) { + elog("corrupt ${name}.log (2)", ("name", name)); + return false; + } + log.seekg(suffix); + log.read((char*)&header, sizeof(header)); + if (suffix + sizeof(header) + header.payload_size + sizeof(suffix) != size) { + elog("corrupt ${name}.log (3)", ("name", name)); + return false; + } + _end_block = header.block_num + 1; + last_block_id = header.block_id; + if (_begin_block >= _end_block) { + elog("corrupt ${name}.log (4)", ("name", name)); + return false; + } + return true; + } + + void recover_blocks(uint64_t size) { + ilog("recover ${name}.log", ("name", name)); + uint64_t pos = 0; + uint32_t num_found = 0; + while (true) { + state_history_log_header header; + if (pos + sizeof(header) > size) + break; + log.seekg(pos); + log.read((char*)&header, sizeof(header)); + uint64_t suffix; + if (header.payload_size > size || pos + sizeof(header) + header.payload_size + sizeof(suffix) > size) + break; + log.seekg(pos + sizeof(header) + header.payload_size); + log.read((char*)&suffix, sizeof(suffix)); + if (suffix != pos) + break; + pos = pos + sizeof(header) + header.payload_size + sizeof(suffix); + if (!(++num_found % 10000)) { + printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos); + fflush(stdout); + } + } + log.flush(); + boost::filesystem::resize_file(log_filename, pos); + log.sync(); + EOS_ASSERT(get_last_block(pos), chain::plugin_exception, "recover ${name}.log failed", ("name", name)); + } + + void open_log() { + log.open(log_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app); + log.seekg(0, std::ios_base::end); + uint64_t size = log.tellg(); + if (size >= sizeof(state_history_log_header)) { + state_history_log_header header; + log.seekg(0); + log.read((char*)&header, sizeof(header)); + EOS_ASSERT(header.version == 0 && sizeof(header) + header.payload_size + sizeof(uint64_t) <= size, + chain::plugin_exception, "corrupt ${name}.log (1)", ("name", name)); + _begin_block = header.block_num; + last_block_id = header.block_id; + if (!get_last_block(size)) + recover_blocks(size); + ilog("${name}.log has blocks ${b}-${e}", ("name", name)("b", _begin_block)("e", _end_block - 1)); + } else { + EOS_ASSERT(!size, chain::plugin_exception, "corrupt ${name}.log (5)", ("name", name)); + ilog("${name}.log is empty", ("name", name)); + } + } + + void open_index() { + index.open(index_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app); + index.seekg(0, std::ios_base::end); + if (index.tellg() == (_end_block - _begin_block) * sizeof(state_history_summary)) + return; + ilog("Regenerate ${name}.index", ("name", name)); + index.close(); + index.open(index_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc); + + log.seekg(0, std::ios_base::end); + uint64_t size = log.tellg(); + uint64_t pos = 0; + uint32_t num_found = 0; + while (pos < size) { + state_history_log_header header; + EOS_ASSERT(pos + sizeof(header) <= size, chain::plugin_exception, "corrupt ${name}.log (6)", ("name", name)); + log.seekg(pos); + log.read((char*)&header, sizeof(header)); + uint64_t suffix_pos = pos + sizeof(header) + header.payload_size; + uint64_t suffix; + EOS_ASSERT(suffix_pos + sizeof(suffix) <= size, chain::plugin_exception, "corrupt ${name}.log (7)", + ("name", name)); + log.seekg(suffix_pos); + log.read((char*)&suffix, sizeof(suffix)); + // ilog("block ${b} at ${pos}-${end} suffix=${suffix} file_size=${fs}", + // ("b", header.block_num)("pos", pos)("end", suffix_pos + sizeof(suffix))("suffix", suffix)("fs", size)); + EOS_ASSERT(suffix == pos, chain::plugin_exception, "corrupt ${name}.log (8)", ("name", name)); + + state_history_summary summary{.pos = pos}; + index.write((char*)&summary, sizeof(summary)); + pos = suffix_pos + sizeof(suffix); + if (!(++num_found % 10000)) { + printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos); + fflush(stdout); + } + } + } + + uint64_t get_pos(uint32_t block_num) { + state_history_summary summary; + index.seekg((block_num - _begin_block) * sizeof(summary)); + index.read((char*)&summary, sizeof(summary)); + return summary.pos; + } + + void truncate(uint32_t block_num) { + log.flush(); + index.flush(); + uint64_t num_removed = 0; + if (block_num <= _begin_block) { + num_removed = _end_block - _begin_block; + log.seekg(0); + index.seekg(0); + boost::filesystem::resize_file(log_filename, 0); + boost::filesystem::resize_file(index_filename, 0); + _begin_block = _end_block = 0; + } else { + num_removed = _end_block - block_num; + uint64_t pos = get_pos(block_num); + log.seekg(0); + index.seekg(0); + boost::filesystem::resize_file(log_filename, pos); + boost::filesystem::resize_file(index_filename, (block_num - _begin_block) * sizeof(state_history_summary)); + _end_block = block_num; + } + log.sync(); + index.sync(); + ilog("fork or replay: removed ${n} blocks from ${name}.log", ("n", num_removed)("name", name)); + } +}; // state_history_log + +} // namespace eosio diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp new file mode 100644 index 00000000000..f3429e2d190 --- /dev/null +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp @@ -0,0 +1,101 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#pragma once +#include + +#include + +template +struct history_serial_big_vector_wrapper { + T obj; +}; + +namespace fc { +class variant; +} + +namespace eosio { +using chain::bytes; +using std::shared_ptr; + +typedef shared_ptr state_history_ptr; + +struct table_delta { + fc::unsigned_int struct_version = 0; + std::string name{}; + history_serial_big_vector_wrapper>> rows{}; +}; + +struct block_position { + uint32_t block_num = 0; + chain::block_id_type block_id = {}; +}; + +struct get_status_request_v0 {}; + +struct get_status_result_v0 { + block_position head = {}; + block_position last_irreversible = {}; + uint32_t trace_begin_block = 0; + uint32_t trace_end_block = 0; + uint32_t chain_state_begin_block = 0; + uint32_t chain_state_end_block = 0; +}; + +struct get_blocks_request_v0 { + uint32_t start_block_num = 0; + uint32_t end_block_num = 0; + uint32_t max_messages_in_flight = 0; + std::vector have_positions = {}; + bool irreversible_only = false; + bool fetch_block = false; + bool fetch_traces = false; + bool fetch_deltas = false; +}; + +struct get_blocks_ack_request_v0 { + uint32_t num_messages = 0; +}; + +struct get_blocks_result_v0 { + block_position head; + block_position last_irreversible; + fc::optional this_block; + fc::optional prev_block; + fc::optional block; + fc::optional traces; + fc::optional deltas; +}; + +using state_request = fc::static_variant; +using state_result = fc::static_variant; + +class state_history_plugin : public plugin { + public: + APPBASE_PLUGIN_REQUIRES((chain_plugin)) + + state_history_plugin(); + virtual ~state_history_plugin(); + + virtual void set_program_options(options_description& cli, options_description& cfg) override; + + void plugin_initialize(const variables_map& options); + void plugin_startup(); + void plugin_shutdown(); + + private: + state_history_ptr my; +}; + +} // namespace eosio + +// clang-format off +FC_REFLECT(eosio::table_delta, (struct_version)(name)(rows)); +FC_REFLECT(eosio::block_position, (block_num)(block_id)); +FC_REFLECT_EMPTY(eosio::get_status_request_v0); +FC_REFLECT(eosio::get_status_result_v0, (head)(last_irreversible)(trace_begin_block)(trace_end_block)(chain_state_begin_block)(chain_state_end_block)); +FC_REFLECT(eosio::get_blocks_request_v0, (start_block_num)(end_block_num)(max_messages_in_flight)(have_positions)(irreversible_only)(fetch_block)(fetch_traces)(fetch_deltas)); +FC_REFLECT(eosio::get_blocks_ack_request_v0, (num_messages)); +// clang-format on diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp new file mode 100644 index 00000000000..37c817dd9cc --- /dev/null +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp @@ -0,0 +1,557 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +struct history_serial_wrapper { + const chainbase::database& db; + const T& obj; +}; + +template +history_serial_wrapper make_history_serial_wrapper(const chainbase::database& db, const T& obj) { + return {db, obj}; +} + +template +struct history_context_wrapper { + const chainbase::database& db; + const P& context; + const T& obj; +}; + +template +history_context_wrapper make_history_context_wrapper(const chainbase::database& db, P& context, const T& obj) { + return {db, context, obj}; +} + +namespace fc { + +template +const T& as_type(const T& x) { + return x; +} + +template +datastream& history_serialize_container(datastream& ds, const chainbase::database& db, const T& v) { + fc::raw::pack(ds, unsigned_int(v.size())); + for (auto& x : v) + ds << make_history_serial_wrapper(db, x); + return ds; +} + +template +datastream& history_serialize_container(datastream& ds, const chainbase::database& db, + const std::vector>& v) { + fc::raw::pack(ds, unsigned_int(v.size())); + for (auto& x : v) { + EOS_ASSERT(!!x, eosio::chain::plugin_exception, "null inside container"); + ds << make_history_serial_wrapper(db, *x); + } + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_big_vector_wrapper& obj) { + FC_ASSERT(obj.obj.size() <= 1024 * 1024 * 1024); + fc::raw::pack(ds, unsigned_int((uint32_t)obj.obj.size())); + for (auto& x : obj.obj) + fc::raw::pack(ds, x); + return ds; +} + +template +void history_pack_big_bytes(datastream& ds, const eosio::chain::bytes& v) { + FC_ASSERT(v.size() <= 1024 * 1024 * 1024); + fc::raw::pack(ds, unsigned_int((uint32_t)v.size())); + if (v.size()) + ds.write(&v.front(), (uint32_t)v.size()); +} + +template +void history_pack_big_bytes(datastream& ds, const fc::optional& v) { + fc::raw::pack(ds, v.valid()); + if (v) + history_pack_big_bytes(ds, *v); +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper>& obj) { + return history_serialize_container(ds, obj.db, obj.obj); +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper>& obj) { + fc::raw::pack(ds, obj.obj.first); + fc::raw::pack(ds, obj.obj.second); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.name.value)); + fc::raw::pack(ds, as_type(obj.obj.vm_type)); + fc::raw::pack(ds, as_type(obj.obj.vm_version)); + fc::raw::pack(ds, as_type(obj.obj.privileged)); + fc::raw::pack(ds, as_type(obj.obj.last_code_update)); + fc::raw::pack(ds, as_type(obj.obj.code_version)); + fc::raw::pack(ds, as_type(obj.obj.creation_date)); + fc::raw::pack(ds, as_type(obj.obj.code)); + fc::raw::pack(ds, as_type(obj.obj.abi)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.code.value)); + fc::raw::pack(ds, as_type(obj.obj.scope.value)); + fc::raw::pack(ds, as_type(obj.obj.table.value)); + fc::raw::pack(ds, as_type(obj.obj.payer.value)); + return ds; +} + +template +datastream& +operator<<(datastream& ds, + const history_context_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.context.code.value)); + fc::raw::pack(ds, as_type(obj.context.scope.value)); + fc::raw::pack(ds, as_type(obj.context.table.value)); + fc::raw::pack(ds, as_type(obj.obj.primary_key)); + fc::raw::pack(ds, as_type(obj.obj.payer.value)); + fc::raw::pack(ds, as_type(obj.obj.value)); + return ds; +} + +template +void serialize_secondary_index_data(datastream& ds, const T& obj) { + fc::raw::pack(ds, obj); +} + +template +void serialize_secondary_index_data(datastream& ds, const float64_t& obj) { + uint64_t i; + memcpy(&i, &obj, sizeof(i)); + fc::raw::pack(ds, i); +} + +template +void serialize_secondary_index_data(datastream& ds, const float128_t& obj) { + __uint128_t i; + memcpy(&i, &obj, sizeof(i)); + fc::raw::pack(ds, i); +} + +template +void serialize_secondary_index_data(datastream& ds, const eosio::chain::key256_t& obj) { + auto rev = [&](__uint128_t x) { + char* ch = reinterpret_cast(&x); + std::reverse(ch, ch + sizeof(x)); + return x; + }; + fc::raw::pack(ds, rev(obj[0])); + fc::raw::pack(ds, rev(obj[1])); +} + +template +datastream& serialize_secondary_index(datastream& ds, const eosio::chain::table_id_object& context, + const T& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(context.code.value)); + fc::raw::pack(ds, as_type(context.scope.value)); + fc::raw::pack(ds, as_type(context.table.value)); + fc::raw::pack(ds, as_type(obj.primary_key)); + fc::raw::pack(ds, as_type(obj.payer.value)); + serialize_secondary_index_data(ds, obj.secondary_key); + return ds; +} + +template +datastream& +operator<<(datastream& ds, + const history_context_wrapper& obj) { + return serialize_secondary_index(ds, obj.context, obj.obj); +} + +template +datastream& +operator<<(datastream& ds, + const history_context_wrapper& obj) { + return serialize_secondary_index(ds, obj.context, obj.obj); +} + +template +datastream& +operator<<(datastream& ds, + const history_context_wrapper& obj) { + return serialize_secondary_index(ds, obj.context, obj.obj); +} + +template +datastream& +operator<<(datastream& ds, + const history_context_wrapper& obj) { + return serialize_secondary_index(ds, obj.context, obj.obj); +} + +template +datastream& operator<<( + datastream& ds, + const history_context_wrapper& obj) { + return serialize_secondary_index(ds, obj.context, obj.obj); +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.producer_name.value)); + fc::raw::pack(ds, as_type(obj.obj.block_signing_key)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.version)); + history_serialize_container(ds, obj.db, + as_type>(obj.obj.producers)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.max_block_net_usage)); + fc::raw::pack(ds, as_type(obj.obj.target_block_net_usage_pct)); + fc::raw::pack(ds, as_type(obj.obj.max_transaction_net_usage)); + fc::raw::pack(ds, as_type(obj.obj.base_per_transaction_net_usage)); + fc::raw::pack(ds, as_type(obj.obj.net_usage_leeway)); + fc::raw::pack(ds, as_type(obj.obj.context_free_discount_net_usage_num)); + fc::raw::pack(ds, as_type(obj.obj.context_free_discount_net_usage_den)); + fc::raw::pack(ds, as_type(obj.obj.max_block_cpu_usage)); + fc::raw::pack(ds, as_type(obj.obj.target_block_cpu_usage_pct)); + fc::raw::pack(ds, as_type(obj.obj.max_transaction_cpu_usage)); + fc::raw::pack(ds, as_type(obj.obj.min_transaction_cpu_usage)); + fc::raw::pack(ds, as_type(obj.obj.max_transaction_lifetime)); + fc::raw::pack(ds, as_type(obj.obj.deferred_trx_expiration_window)); + fc::raw::pack(ds, as_type(obj.obj.max_transaction_delay)); + fc::raw::pack(ds, as_type(obj.obj.max_inline_action_size)); + fc::raw::pack(ds, as_type(obj.obj.max_inline_action_depth)); + fc::raw::pack(ds, as_type(obj.obj.max_authority_depth)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type>(obj.obj.proposed_schedule_block_num)); + fc::raw::pack(ds, make_history_serial_wrapper( + obj.db, as_type(obj.obj.proposed_schedule))); + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.configuration))); + + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.sender.value)); + fc::raw::pack(ds, as_type<__uint128_t>(obj.obj.sender_id)); + fc::raw::pack(ds, as_type(obj.obj.payer.value)); + fc::raw::pack(ds, as_type(obj.obj.trx_id)); + fc::raw::pack(ds, as_type(obj.obj.packed_trx)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.key)); + fc::raw::pack(ds, as_type(obj.obj.weight)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.actor.value)); + fc::raw::pack(ds, as_type(obj.obj.permission.value)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.permission))); + fc::raw::pack(ds, as_type(obj.obj.weight)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.wait_sec)); + fc::raw::pack(ds, as_type(obj.obj.weight)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.threshold)); + history_serialize_container(ds, obj.db, obj.obj.keys); + history_serialize_container(ds, obj.db, obj.obj.accounts); + history_serialize_container(ds, obj.db, obj.obj.waits); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.owner.value)); + fc::raw::pack(ds, as_type(obj.obj.name.value)); + if (obj.obj.parent._id) { + auto& index = obj.db.get_index(); + const auto* parent = index.find(obj.obj.parent); + if (!parent) { + auto& undo = index.stack().back(); + auto it = undo.removed_values.find(obj.obj.parent); + EOS_ASSERT(it != undo.removed_values.end(), eosio::chain::plugin_exception, + "can not find parent of permission_object"); + parent = &it->second; + } + fc::raw::pack(ds, as_type(parent->name.value)); + } else { + fc::raw::pack(ds, as_type(0)); + } + fc::raw::pack(ds, as_type(obj.obj.last_updated)); + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.auth))); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.account.value)); + fc::raw::pack(ds, as_type(obj.obj.code.value)); + fc::raw::pack(ds, as_type(obj.obj.message_type.value)); + fc::raw::pack(ds, as_type(obj.obj.required_permission.value)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + EOS_ASSERT(!obj.obj.pending, eosio::chain::plugin_exception, + "accepted_block sent while resource_limits_object in pending state"); + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.owner.value)); + fc::raw::pack(ds, as_type(obj.obj.net_weight)); + fc::raw::pack(ds, as_type(obj.obj.cpu_weight)); + fc::raw::pack(ds, as_type(obj.obj.ram_bytes)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.last_ordinal)); + fc::raw::pack(ds, as_type(obj.obj.value_ex)); + fc::raw::pack(ds, as_type(obj.obj.consumed)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.owner.value)); + fc::raw::pack(ds, make_history_serial_wrapper( + obj.db, as_type(obj.obj.net_usage))); + fc::raw::pack(ds, make_history_serial_wrapper( + obj.db, as_type(obj.obj.cpu_usage))); + fc::raw::pack(ds, as_type(obj.obj.ram_usage)); + return ds; +} + +template +datastream& +operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type( + obj.obj.average_block_net_usage))); + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type( + obj.obj.average_block_cpu_usage))); + fc::raw::pack(ds, as_type(obj.obj.total_net_weight)); + fc::raw::pack(ds, as_type(obj.obj.total_cpu_weight)); + fc::raw::pack(ds, as_type(obj.obj.total_ram_bytes)); + fc::raw::pack(ds, as_type(obj.obj.virtual_net_limit)); + fc::raw::pack(ds, as_type(obj.obj.virtual_cpu_limit)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.numerator)); + fc::raw::pack(ds, as_type(obj.obj.denominator)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.target)); + fc::raw::pack(ds, as_type(obj.obj.max)); + fc::raw::pack(ds, as_type(obj.obj.periods)); + fc::raw::pack(ds, as_type(obj.obj.max_multiplier)); + fc::raw::pack( + ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.contract_rate))); + fc::raw::pack( + ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.expand_rate))); + return ds; +} + +template +datastream& +operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack( + ds, make_history_serial_wrapper( + obj.db, as_type(obj.obj.cpu_limit_parameters))); + fc::raw::pack( + ds, make_history_serial_wrapper( + obj.db, as_type(obj.obj.net_limit_parameters))); + fc::raw::pack(ds, as_type(obj.obj.account_cpu_usage_average_window)); + fc::raw::pack(ds, as_type(obj.obj.account_net_usage_average_window)); + return ds; +}; + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.account.value)); + fc::raw::pack(ds, as_type(obj.obj.name.value)); + history_serialize_container(ds, obj.db, as_type>(obj.obj.authorization)); + fc::raw::pack(ds, as_type(obj.obj.data)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.receiver.value)); + fc::raw::pack(ds, as_type(obj.obj.act_digest)); + fc::raw::pack(ds, as_type(obj.obj.global_sequence)); + fc::raw::pack(ds, as_type(obj.obj.recv_sequence)); + history_serialize_container(ds, obj.db, as_type>(obj.obj.auth_sequence)); + fc::raw::pack(ds, as_type(obj.obj.code_sequence)); + fc::raw::pack(ds, as_type(obj.obj.abi_sequence)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.account.value)); + fc::raw::pack(ds, as_type(obj.obj.delta)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.receipt))); + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.act))); + fc::raw::pack(ds, as_type(obj.obj.context_free)); + fc::raw::pack(ds, as_type(obj.obj.elapsed.count())); + fc::raw::pack(ds, as_type(obj.obj.console)); + history_serialize_container(ds, obj.db, as_type>(obj.obj.account_ram_deltas)); + + fc::optional e; + if (obj.obj.except) + e = obj.obj.except->to_string(); + fc::raw::pack(ds, as_type>(e)); + + history_serialize_container(ds, obj.db, as_type>(obj.obj.inline_traces)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_context_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.id)); + if (obj.obj.receipt) { + if (obj.obj.failed_dtrx_trace && + obj.obj.receipt->status.value == eosio::chain::transaction_receipt_header::soft_fail) + fc::raw::pack(ds, uint8_t(eosio::chain::transaction_receipt_header::executed)); + else + fc::raw::pack(ds, as_type(obj.obj.receipt->status.value)); + fc::raw::pack(ds, as_type(obj.obj.receipt->cpu_usage_us)); + fc::raw::pack(ds, as_type(obj.obj.receipt->net_usage_words)); + } else { + fc::raw::pack(ds, uint8_t(obj.context)); + fc::raw::pack(ds, uint32_t(0)); + fc::raw::pack(ds, fc::unsigned_int(0)); + } + fc::raw::pack(ds, as_type(obj.obj.elapsed.count())); + fc::raw::pack(ds, as_type(obj.obj.net_usage)); + fc::raw::pack(ds, as_type(obj.obj.scheduled)); + history_serialize_container(ds, obj.db, as_type>(obj.obj.action_traces)); + + fc::optional e; + if (obj.obj.except) + e = obj.obj.except->to_string(); + fc::raw::pack(ds, as_type>(e)); + + fc::raw::pack(ds, bool(obj.obj.failed_dtrx_trace)); + if (obj.obj.failed_dtrx_trace) { + uint8_t stat = eosio::chain::transaction_receipt_header::hard_fail; + if (obj.obj.receipt && obj.obj.receipt->status.value == eosio::chain::transaction_receipt_header::soft_fail) + stat = eosio::chain::transaction_receipt_header::soft_fail; + fc::raw::pack(ds, make_history_context_wrapper(obj.db, stat, *obj.obj.failed_dtrx_trace)); + } + + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + uint8_t stat = eosio::chain::transaction_receipt_header::hard_fail; + ds << make_history_context_wrapper(obj.db, stat, obj.obj); + return ds; +} + +template +datastream& operator<<(datastream& ds, const eosio::get_blocks_result_v0& obj) { + fc::raw::pack(ds, obj.head); + fc::raw::pack(ds, obj.last_irreversible); + fc::raw::pack(ds, obj.this_block); + fc::raw::pack(ds, obj.prev_block); + history_pack_big_bytes(ds, obj.block); + history_pack_big_bytes(ds, obj.traces); + history_pack_big_bytes(ds, obj.deltas); + return ds; +} + +} // namespace fc diff --git a/plugins/state_history_plugin/state_history_plugin.cpp b/plugins/state_history_plugin/state_history_plugin.cpp new file mode 100644 index 00000000000..67b61587440 --- /dev/null +++ b/plugins/state_history_plugin/state_history_plugin.cpp @@ -0,0 +1,571 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using tcp = boost::asio::ip::tcp; +namespace ws = boost::beast::websocket; + +extern const char* const state_history_plugin_abi; + +namespace eosio { +using namespace chain; +using boost::signals2::scoped_connection; + +static appbase::abstract_plugin& _state_history_plugin = app().register_plugin(); + +template +auto catch_and_log(F f) { + try { + return f(); + } catch (const fc::exception& e) { + elog("${e}", ("e", e.to_detail_string())); + } catch (const std::exception& e) { + elog("${e}", ("e", e.what())); + } catch (...) { + elog("unknown exception"); + } +} + +namespace bio = boost::iostreams; +static bytes zlib_compress_bytes(bytes in) { + bytes out; + bio::filtering_ostream comp; + comp.push(bio::zlib_compressor(bio::zlib::default_compression)); + comp.push(bio::back_inserter(out)); + bio::write(comp, in.data(), in.size()); + bio::close(comp); + return out; +} + +struct state_history_plugin_impl : std::enable_shared_from_this { + chain_plugin* chain_plug = nullptr; + fc::optional trace_log; + fc::optional chain_state_log; + bool stopping = false; + fc::optional applied_transaction_connection; + fc::optional accepted_block_connection; + string endpoint_address = "0.0.0.0"; + uint16_t endpoint_port = 8080; + std::unique_ptr acceptor; + std::map cached_traces; + transaction_trace_ptr onblock_trace; + + void get_log_entry(state_history_log& log, uint32_t block_num, fc::optional& result) { + if (block_num < log.begin_block() || block_num >= log.end_block()) + return; + state_history_log_header header; + auto& stream = log.get_entry(block_num, header); + uint32_t s; + stream.read((char*)&s, sizeof(s)); + result.emplace(); + result->resize(s); + if (s) + stream.read(result->data(), s); + } + + void get_block(uint32_t block_num, fc::optional& result) { + chain::signed_block_ptr p; + try { + p = chain_plug->chain().fetch_block_by_number(block_num); + } catch (...) { + return; + } + result = fc::raw::pack(*p); + } + + fc::optional get_block_id(uint32_t block_num) { + if (trace_log && block_num >= trace_log->begin_block() && block_num < trace_log->end_block()) + return trace_log->get_block_id(block_num); + if (chain_state_log && block_num >= chain_state_log->begin_block() && block_num < chain_state_log->end_block()) + return chain_state_log->get_block_id(block_num); + try { + auto block = chain_plug->chain().fetch_block_by_number(block_num); + if (block) + return block->id(); + } catch (...) { + } + return {}; + } + + struct session : std::enable_shared_from_this { + std::shared_ptr plugin; + std::unique_ptr> socket_stream; + bool sending = false; + bool sent_abi = false; + std::vector> send_queue; + fc::optional current_request; + bool need_to_send_update = false; + + session(std::shared_ptr plugin) + : plugin(std::move(plugin)) {} + + void start(tcp::socket socket) { + ilog("incoming connection"); + socket_stream = std::make_unique>(std::move(socket)); + socket_stream->binary(true); + socket_stream->next_layer().set_option(boost::asio::ip::tcp::no_delay(true)); + socket_stream->next_layer().set_option(boost::asio::socket_base::send_buffer_size(1024 * 1024)); + socket_stream->next_layer().set_option(boost::asio::socket_base::receive_buffer_size(1024 * 1024)); + socket_stream->async_accept([self = shared_from_this(), this](boost::system::error_code ec) { + callback(ec, "async_accept", [&] { + start_read(); + send(state_history_plugin_abi); + }); + }); + } + + void start_read() { + auto in_buffer = std::make_shared(); + socket_stream->async_read( + *in_buffer, [self = shared_from_this(), this, in_buffer](boost::system::error_code ec, size_t) { + callback(ec, "async_read", [&] { + auto d = boost::asio::buffer_cast(boost::beast::buffers_front(in_buffer->data())); + auto s = boost::asio::buffer_size(in_buffer->data()); + fc::datastream ds(d, s); + state_request req; + fc::raw::unpack(ds, req); + req.visit(*this); + start_read(); + }); + }); + } + + void send(const char* s) { + send_queue.push_back({s, s + strlen(s)}); + send(); + } + + template + void send(T obj) { + send_queue.push_back(fc::raw::pack(state_result{std::move(obj)})); + send(); + } + + void send() { + if (sending) + return; + if (send_queue.empty()) + return send_update(); + sending = true; + socket_stream->binary(sent_abi); + sent_abi = true; + socket_stream->async_write( // + boost::asio::buffer(send_queue[0]), + [self = shared_from_this(), this](boost::system::error_code ec, size_t) { + callback(ec, "async_write", [&] { + send_queue.erase(send_queue.begin()); + sending = false; + send(); + }); + }); + } + + using result_type = void; + void operator()(get_status_request_v0&) { + auto& chain = plugin->chain_plug->chain(); + get_status_result_v0 result; + result.head = {chain.head_block_num(), chain.head_block_id()}; + result.last_irreversible = {chain.last_irreversible_block_num(), chain.last_irreversible_block_id()}; + if (plugin->trace_log) { + result.trace_begin_block = plugin->trace_log->begin_block(); + result.trace_end_block = plugin->trace_log->end_block(); + } + if (plugin->chain_state_log) { + result.chain_state_begin_block = plugin->chain_state_log->begin_block(); + result.chain_state_end_block = plugin->chain_state_log->end_block(); + } + send(std::move(result)); + } + + void operator()(get_blocks_request_v0& req) { + for (auto& cp : req.have_positions) { + if (req.start_block_num <= cp.block_num) + continue; + auto id = plugin->get_block_id(cp.block_num); + if (!id || *id != cp.block_id) + req.start_block_num = std::min(req.start_block_num, cp.block_num); + } + req.have_positions.clear(); + current_request = req; + send_update(true); + } + + void operator()(get_blocks_ack_request_v0& req) { + if (!current_request) + return; + current_request->max_messages_in_flight += req.num_messages; + send_update(); + } + + void send_update(bool changed = false) { + if (changed) + need_to_send_update = true; + if (!send_queue.empty() || !need_to_send_update || !current_request || + !current_request->max_messages_in_flight) + return; + auto& chain = plugin->chain_plug->chain(); + get_blocks_result_v0 result; + result.head = {chain.head_block_num(), chain.head_block_id()}; + result.last_irreversible = {chain.last_irreversible_block_num(), chain.last_irreversible_block_id()}; + uint32_t current = + current_request->irreversible_only ? result.last_irreversible.block_num : result.head.block_num; + if (current_request->start_block_num <= current && + current_request->start_block_num < current_request->end_block_num) { + auto block_id = plugin->get_block_id(current_request->start_block_num); + if (block_id) { + result.this_block = block_position{current_request->start_block_num, *block_id}; + auto prev_block_id = plugin->get_block_id(current_request->start_block_num - 1); + if (prev_block_id) + result.prev_block = block_position{current_request->start_block_num - 1, *prev_block_id}; + if (current_request->fetch_block) + plugin->get_block(current_request->start_block_num, result.block); + if (current_request->fetch_traces && plugin->trace_log) + plugin->get_log_entry(*plugin->trace_log, current_request->start_block_num, result.traces); + if (current_request->fetch_deltas && plugin->chain_state_log) + plugin->get_log_entry(*plugin->chain_state_log, current_request->start_block_num, result.deltas); + } + ++current_request->start_block_num; + } + send(std::move(result)); + --current_request->max_messages_in_flight; + need_to_send_update = current_request->start_block_num <= current && + current_request->start_block_num < current_request->end_block_num; + } + + template + void catch_and_close(F f) { + try { + f(); + } catch (const fc::exception& e) { + elog("${e}", ("e", e.to_detail_string())); + close(); + } catch (const std::exception& e) { + elog("${e}", ("e", e.what())); + close(); + } catch (...) { + elog("unknown exception"); + close(); + } + } + + template + void callback(boost::system::error_code ec, const char* what, F f) { + if (plugin->stopping) + return; + if (ec) + return on_fail(ec, what); + catch_and_close(f); + } + + void on_fail(boost::system::error_code ec, const char* what) { + try { + elog("${w}: ${m}", ("w", what)("m", ec.message())); + close(); + } catch (...) { + elog("uncaught exception on close"); + } + } + + void close() { + socket_stream->next_layer().close(); + plugin->sessions.erase(this); + } + }; + std::map> sessions; + + void listen() { + boost::system::error_code ec; + + auto address = boost::asio::ip::make_address(endpoint_address); + auto endpoint = tcp::endpoint{address, endpoint_port}; + acceptor = std::make_unique(app().get_io_service()); + + auto check_ec = [&](const char* what) { + if (!ec) + return; + elog("${w}: ${m}", ("w", what)("m", ec.message())); + EOS_ASSERT(false, plugin_exception, "unable to open listen socket"); + }; + + acceptor->open(endpoint.protocol(), ec); + check_ec("open"); + acceptor->set_option(boost::asio::socket_base::reuse_address(true)); + acceptor->bind(endpoint, ec); + check_ec("bind"); + acceptor->listen(boost::asio::socket_base::max_listen_connections, ec); + check_ec("listen"); + do_accept(); + } + + void do_accept() { + auto socket = std::make_shared(app().get_io_service()); + acceptor->async_accept(*socket, [self = shared_from_this(), socket, this](auto ec) { + if (stopping) + return; + if (ec) { + if (ec == boost::system::errc::too_many_files_open) + catch_and_log([&] { do_accept(); }); + return; + } + catch_and_log([&] { + auto s = std::make_shared(self); + sessions[s.get()] = s; + s->start(std::move(*socket)); + }); + catch_and_log([&] { do_accept(); }); + }); + } + + static bool is_onblock(const transaction_trace_ptr& p) { + if (p->action_traces.size() != 1) + return false; + auto& act = p->action_traces[0].act; + if (act.account != eosio::chain::config::system_account_name || act.name != N(onblock) || + act.authorization.size() != 1) + return false; + auto& auth = act.authorization[0]; + return auth.actor == eosio::chain::config::system_account_name && + auth.permission == eosio::chain::config::active_name; + } + + void on_applied_transaction(const transaction_trace_ptr& p) { + if (p->receipt) { + if (is_onblock(p)) + onblock_trace = p; + else if (p->failed_dtrx_trace) + cached_traces[p->failed_dtrx_trace->id] = p; + else + cached_traces[p->id] = p; + } + } + + void on_accepted_block(const block_state_ptr& block_state) { + store_traces(block_state); + store_chain_state(block_state); + for (auto& s : sessions) { + auto& p = s.second; + if (p) { + if (p->current_request && block_state->block_num < p->current_request->start_block_num) + p->current_request->start_block_num = block_state->block_num; + p->send_update(true); + } + } + } + + void store_traces(const block_state_ptr& block_state) { + if (!trace_log) + return; + std::vector traces; + if (onblock_trace) + traces.push_back(onblock_trace); + for (auto& r : block_state->block->transactions) { + transaction_id_type id; + if (r.trx.contains()) + id = r.trx.get(); + else + id = r.trx.get().id(); + auto it = cached_traces.find(id); + EOS_ASSERT(it != cached_traces.end() && it->second->receipt, plugin_exception, + "missing trace for transaction ${id}", ("id", id)); + traces.push_back(it->second); + } + cached_traces.clear(); + onblock_trace.reset(); + + auto& db = chain_plug->chain().db(); + auto traces_bin = zlib_compress_bytes(fc::raw::pack(make_history_serial_wrapper(db, traces))); + EOS_ASSERT(traces_bin.size() == (uint32_t)traces_bin.size(), plugin_exception, "traces is too big"); + + state_history_log_header header{.block_num = block_state->block->block_num(), + .block_id = block_state->block->id(), + .payload_size = sizeof(uint32_t) + traces_bin.size()}; + trace_log->write_entry(header, block_state->block->previous, [&](auto& stream) { + uint32_t s = (uint32_t)traces_bin.size(); + stream.write((char*)&s, sizeof(s)); + if (!traces_bin.empty()) + stream.write(traces_bin.data(), traces_bin.size()); + }); + } + + void store_chain_state(const block_state_ptr& block_state) { + if (!chain_state_log) + return; + bool fresh = chain_state_log->begin_block() == chain_state_log->end_block(); + if (fresh) + ilog("Placing initial state in block ${n}", ("n", block_state->block->block_num())); + + std::vector deltas; + auto& db = chain_plug->chain().db(); + + const auto& table_id_index = db.get_index(); + std::map removed_table_id; + for (auto& rem : table_id_index.stack().back().removed_values) + removed_table_id[rem.first._id] = &rem.second; + + auto get_table_id = [&](uint64_t tid) -> const table_id_object& { + auto obj = table_id_index.find(tid); + if (obj) + return *obj; + auto it = removed_table_id.find(tid); + EOS_ASSERT(it != removed_table_id.end(), chain::plugin_exception, "can not found table id ${tid}", + ("tid", tid)); + return *it->second; + }; + + auto pack_row = [&](auto& row) { return fc::raw::pack(make_history_serial_wrapper(db, row)); }; + auto pack_contract_row = [&](auto& row) { + return fc::raw::pack(make_history_context_wrapper(db, get_table_id(row.t_id._id), row)); + }; + + auto process_table = [&](auto* name, auto& index, auto& pack_row) { + if (fresh) { + if (index.indices().empty()) + return; + deltas.push_back({}); + auto& delta = deltas.back(); + delta.name = name; + for (auto& row : index.indices()) + delta.rows.obj.emplace_back(true, pack_row(row)); + } else { + if (index.stack().empty()) + return; + auto& undo = index.stack().back(); + if (undo.old_values.empty() && undo.new_ids.empty() && undo.removed_values.empty()) + return; + deltas.push_back({}); + auto& delta = deltas.back(); + delta.name = name; + for (auto& old : undo.old_values) { + auto& row = index.get(old.first); + delta.rows.obj.emplace_back(true, pack_row(row)); + } + for (auto& old : undo.removed_values) + delta.rows.obj.emplace_back(false, pack_row(old.second)); + for (auto id : undo.new_ids) { + auto& row = index.get(id); + delta.rows.obj.emplace_back(true, pack_row(row)); + } + } + }; + + process_table("account", db.get_index(), pack_row); + + process_table("contract_table", db.get_index(), pack_row); + process_table("contract_row", db.get_index(), pack_contract_row); + process_table("contract_index64", db.get_index(), pack_contract_row); + process_table("contract_index128", db.get_index(), pack_contract_row); + process_table("contract_index256", db.get_index(), pack_contract_row); + process_table("contract_index_double", db.get_index(), pack_contract_row); + process_table("contract_index_long_double", db.get_index(), pack_contract_row); + + process_table("global_property", db.get_index(), pack_row); + process_table("generated_transaction", db.get_index(), pack_row); + + process_table("permission", db.get_index(), pack_row); + process_table("permission_link", db.get_index(), pack_row); + + process_table("resource_limits", db.get_index(), pack_row); + process_table("resource_usage", db.get_index(), pack_row); + process_table("resource_limits_state", db.get_index(), pack_row); + process_table("resource_limits_config", db.get_index(), pack_row); + + auto deltas_bin = zlib_compress_bytes(fc::raw::pack(deltas)); + EOS_ASSERT(deltas_bin.size() == (uint32_t)deltas_bin.size(), plugin_exception, "deltas is too big"); + state_history_log_header header{.block_num = block_state->block->block_num(), + .block_id = block_state->block->id(), + .payload_size = sizeof(uint32_t) + deltas_bin.size()}; + chain_state_log->write_entry(header, block_state->block->previous, [&](auto& stream) { + uint32_t s = (uint32_t)deltas_bin.size(); + stream.write((char*)&s, sizeof(s)); + if (!deltas_bin.empty()) + stream.write(deltas_bin.data(), deltas_bin.size()); + }); + } // store_chain_state +}; // state_history_plugin_impl + +state_history_plugin::state_history_plugin() + : my(std::make_shared()) {} + +state_history_plugin::~state_history_plugin() {} + +void state_history_plugin::set_program_options(options_description& cli, options_description& cfg) { + auto options = cfg.add_options(); + options("state-history-dir", bpo::value()->default_value("state-history"), + "the location of the state-history directory (absolute path or relative to application data dir)"); + cli.add_options()("delete-state-history", bpo::bool_switch()->default_value(false), "clear state history files"); + options("trace-history", bpo::bool_switch()->default_value(false), "enable trace history"); + options("chain-state-history", bpo::bool_switch()->default_value(false), "enable chain state history"); + options("state-history-endpoint", bpo::value()->default_value("0.0.0.0:8080"), + "the endpoint upon which to listen for incoming connections"); +} + +void state_history_plugin::plugin_initialize(const variables_map& options) { + try { + EOS_ASSERT(options.at("disable-replay-opts").as(), plugin_exception, + "state_history_plugin requires --disable-replay-opts"); + + my->chain_plug = app().find_plugin(); + EOS_ASSERT(my->chain_plug, chain::missing_chain_plugin_exception, ""); + auto& chain = my->chain_plug->chain(); + my->applied_transaction_connection.emplace( + chain.applied_transaction.connect([&](const transaction_trace_ptr& p) { my->on_applied_transaction(p); })); + my->accepted_block_connection.emplace( + chain.accepted_block.connect([&](const block_state_ptr& p) { my->on_accepted_block(p); })); + + auto dir_option = options.at("state-history-dir").as(); + boost::filesystem::path state_history_dir; + if (dir_option.is_relative()) + state_history_dir = app().data_dir() / dir_option; + else + state_history_dir = dir_option; + + auto ip_port = options.at("state-history-endpoint").as(); + auto port = ip_port.substr(ip_port.find(':') + 1, ip_port.size()); + auto host = ip_port.substr(0, ip_port.find(':')); + my->endpoint_address = host; + my->endpoint_port = std::stoi(port); + idump((ip_port)(host)(port)); + + if (options.at("delete-state-history").as()) { + ilog("Deleting state history"); + boost::filesystem::remove_all(state_history_dir); + } + boost::filesystem::create_directories(state_history_dir); + + if (options.at("trace-history").as()) + my->trace_log.emplace("trace_history", (state_history_dir / "trace_history.log").string(), + (state_history_dir / "trace_history.index").string()); + if (options.at("chain-state-history").as()) + my->chain_state_log.emplace("chain_state_history", (state_history_dir / "chain_state_history.log").string(), + (state_history_dir / "chain_state_history.index").string()); + } + FC_LOG_AND_RETHROW() +} // state_history_plugin::plugin_initialize + +void state_history_plugin::plugin_startup() { my->listen(); } + +void state_history_plugin::plugin_shutdown() { + my->applied_transaction_connection.reset(); + my->accepted_block_connection.reset(); + while (!my->sessions.empty()) + my->sessions.begin()->second->close(); + my->stopping = true; +} + +} // namespace eosio diff --git a/plugins/state_history_plugin/state_history_plugin_abi.cpp b/plugins/state_history_plugin/state_history_plugin_abi.cpp new file mode 100644 index 00000000000..bdedcc81cd9 --- /dev/null +++ b/plugins/state_history_plugin/state_history_plugin_abi.cpp @@ -0,0 +1,475 @@ +extern const char* const state_history_plugin_abi = R"({ + "version": "eosio::abi/1.1", + "structs": [ + { + "name": "get_status_request_v0", "fields": [] + }, + { + "name": "block_position", "fields": [ + { "name": "block_num", "type": "uint32" }, + { "name": "block_id", "type": "checksum256" } + ] + }, + { + "name": "get_status_result_v0", "fields": [ + { "name": "head", "type": "block_position" }, + { "name": "last_irreversible", "type": "block_position" }, + { "name": "trace_begin_block", "type": "uint32" }, + { "name": "trace_end_block", "type": "uint32" }, + { "name": "chain_state_begin_block", "type": "uint32" }, + { "name": "chain_state_end_block", "type": "uint32" } + ] + }, + { + "name": "get_blocks_request_v0", "fields": [ + { "name": "start_block_num", "type": "uint32" }, + { "name": "end_block_num", "type": "uint32" }, + { "name": "max_messages_in_flight", "type": "uint32" }, + { "name": "have_positions", "type": "block_position[]" }, + { "name": "irreversible_only", "type": "bool" }, + { "name": "fetch_block", "type": "bool" }, + { "name": "fetch_traces", "type": "bool" }, + { "name": "fetch_deltas", "type": "bool" } + ] + }, + { + "name": "get_blocks_ack_request_v0", "fields": [ + { "name": "num_messages", "type": "uint32" } + ] + }, + { + "name": "get_blocks_result_v0", "fields": [ + { "name": "head", "type": "block_position" }, + { "name": "last_irreversible", "type": "block_position" }, + { "name": "this_block", "type": "block_position?" }, + { "name": "prev_block", "type": "block_position?" }, + { "name": "block", "type": "bytes?" }, + { "name": "traces", "type": "bytes?" }, + { "name": "deltas", "type": "bytes?" } + ] + }, + { + "name": "row", "fields": [ + { "name": "present", "type": "bool" }, + { "name": "data", "type": "bytes" } + ] + }, + { + "name": "table_delta_v0", "fields": [ + { "name": "name", "type": "string" }, + { "name": "rows", "type": "row[]" } + ] + }, + { + "name": "action", "fields": [ + { "name": "account", "type": "name" }, + { "name": "name", "type": "name" }, + { "name": "authorization", "type": "permission_level[]" }, + { "name": "data", "type": "bytes" } + ] + }, + { + "name": "account_auth_sequence", "fields": [ + { "name": "account", "type": "name" }, + { "name": "sequence", "type": "uint64" } + ] + }, + { + "name": "action_receipt_v0", "fields": [ + { "name": "receiver", "type": "name" }, + { "name": "act_digest", "type": "checksum256" }, + { "name": "global_sequence", "type": "uint64" }, + { "name": "recv_sequence", "type": "uint64" }, + { "name": "auth_sequence", "type": "account_auth_sequence[]" }, + { "name": "code_sequence", "type": "varuint32" }, + { "name": "abi_sequence", "type": "varuint32" } + ] + }, + { + "name": "account_delta", "fields": [ + { "name": "account", "type": "name" }, + { "name": "delta", "type": "int64" } + ] + }, + { + "name": "action_trace_v0", "fields": [ + { "name": "receipt", "type": "action_receipt" }, + { "name": "act", "type": "action" }, + { "name": "context_free", "type": "bool" }, + { "name": "elapsed", "type": "int64" }, + { "name": "console", "type": "string" }, + { "name": "account_ram_deltas", "type": "account_delta[]" }, + { "name": "except", "type": "string?" }, + { "name": "inline_traces", "type": "action_trace[]" } + ] + }, + { + "name": "transaction_trace_v0", "fields": [ + { "name": "id", "type": "checksum256" }, + { "name": "status", "type": "uint8" }, + { "name": "cpu_usage_us", "type": "uint32" }, + { "name": "net_usage_words", "type": "varuint32" }, + { "name": "elapsed", "type": "int64" }, + { "name": "net_usage", "type": "uint64" }, + { "name": "scheduled", "type": "bool" }, + { "name": "action_traces", "type": "action_trace[]" }, + { "name": "except", "type": "string?" }, + { "name": "failed_dtrx_trace", "type": "transaction_trace?" } + ] + }, + { + "name": "packed_transaction", "fields": [ + { "name": "signatures", "type": "signature[]" }, + { "name": "compression", "type": "uint8" }, + { "name": "packed_context_free_data", "type": "bytes" }, + { "name": "packed_trx", "type": "bytes" } + ] + }, + { + "name": "transaction_receipt_header", "fields": [ + { "name": "status", "type": "uint8" }, + { "name": "cpu_usage_us", "type": "uint32" }, + { "name": "net_usage_words", "type": "varuint32" } + ] + }, + { + "name": "transaction_receipt", "base": "transaction_receipt_header", "fields": [ + { "name": "trx", "type": "transaction_variant" } + ] + }, + { + "name": "extension", "fields": [ + { "name": "type", "type": "uint16" }, + { "name": "data", "type": "bytes" } + ] + }, + { + "name": "block_header", "fields": [ + { "name": "timestamp", "type": "block_timestamp_type" }, + { "name": "producer", "type": "name" }, + { "name": "confirmed", "type": "uint16" }, + { "name": "previous", "type": "checksum256" }, + { "name": "transaction_mroot", "type": "checksum256" }, + { "name": "action_mroot", "type": "checksum256" }, + { "name": "schedule_version", "type": "uint32" }, + { "name": "new_producers", "type": "producer_schedule?" }, + { "name": "header_extensions", "type": "extension[]" } + ] + }, + { + "name": "signed_block_header", "base": "block_header", "fields": [ + { "name": "producer_signature", "type": "signature" } + ] + }, + { + "name": "signed_block", "base": "signed_block_header", "fields": [ + { "name": "transactions", "type": "transaction_receipt[]" }, + { "name": "block_extensions", "type": "extension[]" } + ] + }, + { "name": "transaction_header", "fields": [ + { "name": "expiration", "type": "time_point_sec" }, + { "name": "ref_block_num", "type": "uint16" }, + { "name": "ref_block_prefix", "type": "uint32" }, + { "name": "max_net_usage_words", "type": "varuint32" }, + { "name": "max_cpu_usage_ms", "type": "uint8" }, + { "name": "delay_sec", "type": "varuint32" } + ] + }, + { "name": "transaction", "base": "transaction_header", "fields": [ + { "name": "context_free_actions", "type": "action[]" }, + { "name": "actions", "type": "action[]" }, + { "name": "transaction_extensions", "type": "extension[]" } + ] + }, + { + "name": "account_v0", "fields": [ + { "type": "name", "name": "name" }, + { "type": "uint8", "name": "vm_type" }, + { "type": "uint8", "name": "vm_version" }, + { "type": "bool", "name": "privileged" }, + { "type": "time_point", "name": "last_code_update" }, + { "type": "checksum256", "name": "code_version" }, + { "type": "block_timestamp_type", "name": "creation_date" }, + { "type": "bytes", "name": "code" }, + { "type": "bytes", "name": "abi" } + ] + }, + { + "name": "contract_table_v0", "fields": [ + { "type": "name", "name": "code" }, + { "type": "name", "name": "scope" }, + { "type": "name", "name": "table" }, + { "type": "name", "name": "payer" } + ] + }, + { + "name": "contract_row_v0", "fields": [ + { "type": "name", "name": "code" }, + { "type": "name", "name": "scope" }, + { "type": "name", "name": "table" }, + { "type": "uint64", "name": "primary_key" }, + { "type": "name", "name": "payer" }, + { "type": "bytes", "name": "value" } + ] + }, + { + "name": "contract_index64_v0", "fields": [ + { "type": "name", "name": "code" }, + { "type": "name", "name": "scope" }, + { "type": "name", "name": "table" }, + { "type": "uint64", "name": "primary_key" }, + { "type": "name", "name": "payer" }, + { "type": "uint64", "name": "secondary_key" } + ] + }, + { + "name": "contract_index128_v0", "fields": [ + { "type": "name", "name": "code" }, + { "type": "name", "name": "scope" }, + { "type": "name", "name": "table" }, + { "type": "uint64", "name": "primary_key" }, + { "type": "name", "name": "payer" }, + { "type": "uint128", "name": "secondary_key" } + ] + }, + { + "name": "contract_index256_v0", "fields": [ + { "type": "name", "name": "code" }, + { "type": "name", "name": "scope" }, + { "type": "name", "name": "table" }, + { "type": "uint64", "name": "primary_key" }, + { "type": "name", "name": "payer" }, + { "type": "checksum256", "name": "secondary_key" } + ] + }, + { + "name": "contract_index_double_v0", "fields": [ + { "type": "name", "name": "code" }, + { "type": "name", "name": "scope" }, + { "type": "name", "name": "table" }, + { "type": "uint64", "name": "primary_key" }, + { "type": "name", "name": "payer" }, + { "type": "float64", "name": "secondary_key" } + ] + }, + { + "name": "contract_index_long_double_v0", "fields": [ + { "type": "name", "name": "code" }, + { "type": "name", "name": "scope" }, + { "type": "name", "name": "table" }, + { "type": "uint64", "name": "primary_key" }, + { "type": "name", "name": "payer" }, + { "type": "float128", "name": "secondary_key" } + ] + }, + { + "name": "producer_key", "fields": [ + { "type": "name", "name": "producer_name" }, + { "type": "public_key", "name": "block_signing_key" } + ] + }, + { + "name": "producer_schedule", "fields": [ + { "type": "uint32", "name": "version" }, + { "type": "producer_key[]", "name": "producers" } + ] + }, + { + "name": "chain_config_v0", "fields": [ + { "type": "uint64", "name": "max_block_net_usage" }, + { "type": "uint32", "name": "target_block_net_usage_pct" }, + { "type": "uint32", "name": "max_transaction_net_usage" }, + { "type": "uint32", "name": "base_per_transaction_net_usage" }, + { "type": "uint32", "name": "net_usage_leeway" }, + { "type": "uint32", "name": "context_free_discount_net_usage_num" }, + { "type": "uint32", "name": "context_free_discount_net_usage_den" }, + { "type": "uint32", "name": "max_block_cpu_usage" }, + { "type": "uint32", "name": "target_block_cpu_usage_pct" }, + { "type": "uint32", "name": "max_transaction_cpu_usage" }, + { "type": "uint32", "name": "min_transaction_cpu_usage" }, + { "type": "uint32", "name": "max_transaction_lifetime" }, + { "type": "uint32", "name": "deferred_trx_expiration_window" }, + { "type": "uint32", "name": "max_transaction_delay" }, + { "type": "uint32", "name": "max_inline_action_size" }, + { "type": "uint16", "name": "max_inline_action_depth" }, + { "type": "uint16", "name": "max_authority_depth" } + ] + }, + { + "name": "global_property_v0", "fields": [ + { "type": "uint32?", "name": "proposed_schedule_block_num" }, + { "type": "producer_schedule", "name": "proposed_schedule" }, + { "type": "chain_config", "name": "configuration" } + ] + }, + { + "name": "generated_transaction_v0", "fields": [ + { "type": "name", "name": "sender" }, + { "type": "uint128", "name": "sender_id" }, + { "type": "name", "name": "payer" }, + { "type": "checksum256", "name": "trx_id" }, + { "type": "bytes", "name": "packed_trx" } + ] + }, + { + "name": "key_weight", "fields": [ + { "type": "public_key", "name": "key" }, + { "type": "uint16", "name": "weight" } + ] + }, + { + "name": "permission_level", "fields": [ + { "type": "name", "name": "actor" }, + { "type": "name", "name": "permission" } + ] + }, + { + "name": "permission_level_weight", "fields": [ + { "type": "permission_level", "name": "permission" }, + { "type": "uint16", "name": "weight" } + ] + }, + { + "name": "wait_weight", "fields": [ + { "type": "uint32", "name": "wait_sec" }, + { "type": "uint16", "name": "weight" } + ] + }, + { + "name": "authority", "fields": [ + { "type": "uint32", "name": "threshold" }, + { "type": "key_weight[]", "name": "keys" }, + { "type": "permission_level_weight[]", "name": "accounts" }, + { "type": "wait_weight[]", "name": "waits" } + ] + }, + { + "name": "permission_v0", "fields": [ + { "type": "name", "name": "owner" }, + { "type": "name", "name": "name" }, + { "type": "name", "name": "parent" }, + { "type": "time_point", "name": "last_updated" }, + { "type": "authority", "name": "auth" } + ] + }, + { + "name": "permission_link_v0", "fields": [ + { "type": "name", "name": "account" }, + { "type": "name", "name": "code" }, + { "type": "name", "name": "message_type" }, + { "type": "name", "name": "required_permission" } + ] + }, + { + "name": "resource_limits_v0", "fields": [ + { "type": "name", "name": "owner" }, + { "type": "int64", "name": "net_weight" }, + { "type": "int64", "name": "cpu_weight" }, + { "type": "int64", "name": "ram_bytes" } + ] + }, + { + "name": "usage_accumulator_v0", "fields": [ + { "type": "uint32", "name": "last_ordinal" }, + { "type": "uint64", "name": "value_ex" }, + { "type": "uint64", "name": "consumed" } + ] + }, + { + "name": "resource_usage_v0", "fields": [ + { "type": "name", "name": "owner" }, + { "type": "usage_accumulator", "name": "net_usage" }, + { "type": "usage_accumulator", "name": "cpu_usage" }, + { "type": "uint64", "name": "ram_usage" } + ] + }, + { + "name": "resource_limits_state_v0", "fields": [ + { "type": "usage_accumulator", "name": "average_block_net_usage" }, + { "type": "usage_accumulator", "name": "average_block_cpu_usage" }, + { "type": "uint64", "name": "total_net_weight" }, + { "type": "uint64", "name": "total_cpu_weight" }, + { "type": "uint64", "name": "total_ram_bytes" }, + { "type": "uint64", "name": "virtual_net_limit" }, + { "type": "uint64", "name": "virtual_cpu_limit" } + ] + }, + { + "name": "resource_limits_ratio_v0", "fields": [ + { "type": "uint64", "name": "numerator" }, + { "type": "uint64", "name": "denominator" } + ] + }, + { + "name": "elastic_limit_parameters_v0", "fields": [ + { "type": "uint64", "name": "target" }, + { "type": "uint64", "name": "max" }, + { "type": "uint32", "name": "periods" }, + { "type": "uint32", "name": "max_multiplier" }, + { "type": "resource_limits_ratio", "name": "contract_rate" }, + { "type": "resource_limits_ratio", "name": "expand_rate" } + ] + }, + { + "name": "resource_limits_config_v0", "fields": [ + { "type": "elastic_limit_parameters", "name": "cpu_limit_parameters" }, + { "type": "elastic_limit_parameters", "name": "net_limit_parameters" }, + { "type": "uint32", "name": "account_cpu_usage_average_window" }, + { "type": "uint32", "name": "account_net_usage_average_window" } + ] + } + ], + "types": [ + { "new_type_name": "transaction_id", "type": "checksum256" } + ], + "variants": [ + { "name": "request", "types": ["get_status_request_v0", "get_blocks_request_v0", "get_blocks_ack_request_v0"] }, + { "name": "result", "types": ["get_status_result_v0", "get_blocks_result_v0"] }, + + { "name": "action_receipt", "types": ["action_receipt_v0"] }, + { "name": "action_trace", "types": ["action_trace_v0"] }, + { "name": "transaction_trace", "types": ["transaction_trace_v0"] }, + { "name": "transaction_variant", "types": ["transaction_id", "packed_transaction"] }, + + { "name": "table_delta", "types": ["table_delta_v0"] }, + { "name": "account", "types": ["account_v0"] }, + { "name": "contract_table", "types": ["contract_table_v0"] }, + { "name": "contract_row", "types": ["contract_row_v0"] }, + { "name": "contract_index64", "types": ["contract_index64_v0"] }, + { "name": "contract_index128", "types": ["contract_index128_v0"] }, + { "name": "contract_index256", "types": ["contract_index256_v0"] }, + { "name": "contract_index_double", "types": ["contract_index_double_v0"] }, + { "name": "contract_index_long_double", "types": ["contract_index_long_double_v0"] }, + { "name": "chain_config", "types": ["chain_config_v0"] }, + { "name": "global_property", "types": ["global_property_v0"] }, + { "name": "generated_transaction", "types": ["generated_transaction_v0"] }, + { "name": "permission", "types": ["permission_v0"] }, + { "name": "permission_link", "types": ["permission_link_v0"] }, + { "name": "resource_limits", "types": ["resource_limits_v0"] }, + { "name": "usage_accumulator", "types": ["usage_accumulator_v0"] }, + { "name": "resource_usage", "types": ["resource_usage_v0"] }, + { "name": "resource_limits_state", "types": ["resource_limits_state_v0"] }, + { "name": "resource_limits_ratio", "types": ["resource_limits_ratio_v0"] }, + { "name": "elastic_limit_parameters", "types": ["elastic_limit_parameters_v0"] }, + { "name": "resource_limits_config", "types": ["resource_limits_config_v0"] } + ], + "tables": [ + { "name": "account", "type": "account", "key_names": ["name"] }, + { "name": "contract_table", "type": "contract_table", "key_names": ["code", "scope", "table"] }, + { "name": "contract_row", "type": "contract_row", "key_names": ["code", "scope", "table", "primary_key"] }, + { "name": "contract_index64", "type": "contract_index64", "key_names": ["code", "scope", "table", "primary_key"] }, + { "name": "contract_index128", "type": "contract_index128", "key_names": ["code", "scope", "table", "primary_key"] }, + { "name": "contract_index256", "type": "contract_index256", "key_names": ["code", "scope", "table", "primary_key"] }, + { "name": "contract_index_double", "type": "contract_index_double", "key_names": ["code", "scope", "table", "primary_key"] }, + { "name": "contract_index_long_double", "type": "contract_index_long_double", "key_names": ["code", "scope", "table", "primary_key"] }, + { "name": "global_property", "type": "global_property", "key_names": [] }, + { "name": "generated_transaction", "type": "generated_transaction", "key_names": ["sender", "sender_id"] }, + { "name": "permission", "type": "permission", "key_names": ["owner", "name"] }, + { "name": "permission_link", "type": "permission_link", "key_names": ["account", "code", "message_type"] }, + { "name": "resource_limits", "type": "resource_limits", "key_names": ["owner"] }, + { "name": "resource_usage", "type": "resource_usage", "key_names": ["owner"] }, + { "name": "resource_limits_state", "type": "resource_limits_state", "key_names": [] }, + { "name": "resource_limits_config", "type": "resource_limits_config", "key_names": [] } + ] +})"; diff --git a/plugins/template_plugin/include/eosio/template_plugin/template_plugin.hpp b/plugins/template_plugin/include/eosio/template_plugin/template_plugin.hpp index 52b88b12ea0..3217b3b1640 100644 --- a/plugins/template_plugin/include/eosio/template_plugin/template_plugin.hpp +++ b/plugins/template_plugin/include/eosio/template_plugin/template_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/plugins/template_plugin/template_plugin.cpp b/plugins/template_plugin/template_plugin.cpp index 74dc6d7a508..d8a738c30bc 100644 --- a/plugins/template_plugin/template_plugin.cpp +++ b/plugins/template_plugin/template_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/plugins/test_control_api_plugin/include/eosio/test_control_api_plugin/test_control_api_plugin.hpp b/plugins/test_control_api_plugin/include/eosio/test_control_api_plugin/test_control_api_plugin.hpp index feac39a95ff..b9c165b8993 100644 --- a/plugins/test_control_api_plugin/include/eosio/test_control_api_plugin/test_control_api_plugin.hpp +++ b/plugins/test_control_api_plugin/include/eosio/test_control_api_plugin/test_control_api_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/plugins/test_control_api_plugin/test_control_api_plugin.cpp b/plugins/test_control_api_plugin/test_control_api_plugin.cpp index 16510b06460..307cccc197e 100644 --- a/plugins/test_control_api_plugin/test_control_api_plugin.cpp +++ b/plugins/test_control_api_plugin/test_control_api_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/plugins/test_control_plugin/CMakeLists.txt b/plugins/test_control_plugin/CMakeLists.txt index aa6b1cff397..7e2a79d6c5c 100644 --- a/plugins/test_control_plugin/CMakeLists.txt +++ b/plugins/test_control_plugin/CMakeLists.txt @@ -4,6 +4,6 @@ add_library( test_control_plugin test_control_plugin.cpp ${HEADERS} ) -target_link_libraries( test_control_plugin producer_plugin chain_plugin http_client_plugin appbase eosio_chain eos_utilities ) +target_link_libraries( test_control_plugin producer_plugin chain_plugin http_client_plugin appbase eosio_chain ) target_include_directories( test_control_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/plugins/test_control_plugin/include/eosio/test_control_plugin/test_control_plugin.hpp b/plugins/test_control_plugin/include/eosio/test_control_plugin/test_control_plugin.hpp index 0a40d9b6e36..96badb10c83 100644 --- a/plugins/test_control_plugin/include/eosio/test_control_plugin/test_control_plugin.hpp +++ b/plugins/test_control_plugin/include/eosio/test_control_plugin/test_control_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/plugins/test_control_plugin/test_control_plugin.cpp b/plugins/test_control_plugin/test_control_plugin.cpp index f2d630c6c59..483e859c30f 100644 --- a/plugins/test_control_plugin/test_control_plugin.cpp +++ b/plugins/test_control_plugin/test_control_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/plugins/txn_test_gen_plugin/include/eosio/txn_test_gen_plugin/txn_test_gen_plugin.hpp b/plugins/txn_test_gen_plugin/include/eosio/txn_test_gen_plugin/txn_test_gen_plugin.hpp index b33e4835158..ebfe3bfb77c 100644 --- a/plugins/txn_test_gen_plugin/include/eosio/txn_test_gen_plugin/txn_test_gen_plugin.hpp +++ b/plugins/txn_test_gen_plugin/include/eosio/txn_test_gen_plugin/txn_test_gen_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp index 6288e8c347d..707f75bd9de 100644 --- a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp +++ b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp @@ -1,11 +1,10 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include #include -#include #include #include @@ -88,19 +87,38 @@ using namespace eosio::chain; api_handle->call_name(vs.at(0).as(), vs.at(1).as(), result_handler); struct txn_test_gen_plugin_impl { - static void push_next_transaction(const std::shared_ptr>& trxs, size_t index, const std::function& next ) { + + uint64_t _total_us = 0; + uint64_t _txcount = 0; + + int _remain = 0; + + void push_next_transaction(const std::shared_ptr>& trxs, size_t index, const std::function& next ) { chain_plugin& cp = app().get_plugin(); - cp.accept_transaction( packed_transaction(trxs->at(index)), [=](const fc::static_variant& result){ - if (result.contains()) { - next(result.get()); - } else { - if (index + 1 < trxs->size()) { - push_next_transaction(trxs, index + 1, next); + + const int overlap = 20; + int end = std::min(index + overlap, trxs->size()); + _remain = end - index; + for (int i = index; i < end; ++i) { + cp.accept_transaction( packed_transaction(trxs->at(i)), [=](const fc::static_variant& result){ + if (result.contains()) { + next(result.get()); } else { - next(nullptr); + if (result.contains() && result.get()->receipt) { + _total_us += result.get()->receipt->cpu_usage_us; + ++_txcount; + } + --_remain; + if (_remain == 0 ) { + if (end < trxs->size()) { + push_next_transaction(trxs, index + overlap, next); + } else { + next(nullptr); + } + } } - } - }); + }); + } } void push_transactions( std::vector&& trxs, const std::function& next ) { @@ -296,13 +314,11 @@ struct txn_test_gen_plugin_impl { try { controller& cc = app().get_plugin().chain(); auto chainid = app().get_plugin().get_chain_id(); - auto abi_serializer_max_time = app().get_plugin().get_abi_serializer_max_time(); - fc::crypto::private_key a_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'a'))); - fc::crypto::private_key b_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'b'))); + static fc::crypto::private_key a_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'a'))); + static fc::crypto::private_key b_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'b'))); static uint64_t nonce = static_cast(fc::time_point::now().sec_since_epoch()) << 32; - abi_serializer eosio_serializer(cc.db().find(config::system_account_name)->get_abi(), abi_serializer_max_time); uint32_t reference_block_num = cc.last_irreversible_block_num(); if (txn_reference_block_lag >= 0) { @@ -352,6 +368,11 @@ struct txn_test_gen_plugin_impl { timer.cancel(); running = false; ilog("Stopping transaction generation test"); + + if (_txcount) { + ilog("${d} transactions executed, ${t}us / transaction", ("d", _txcount)("t", _total_us / (double)_txcount)); + _txcount = _total_us = 0; + } } boost::asio::high_resolution_timer timer{app().get_io_service()}; diff --git a/plugins/wallet_api_plugin/include/eosio/wallet_api_plugin/wallet_api_plugin.hpp b/plugins/wallet_api_plugin/include/eosio/wallet_api_plugin/wallet_api_plugin.hpp index 74fc2878943..611eed638d9 100644 --- a/plugins/wallet_api_plugin/include/eosio/wallet_api_plugin/wallet_api_plugin.hpp +++ b/plugins/wallet_api_plugin/include/eosio/wallet_api_plugin/wallet_api_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/plugins/wallet_api_plugin/wallet_api_plugin.cpp b/plugins/wallet_api_plugin/wallet_api_plugin.cpp index 315ce810b16..0d88ec2966d 100644 --- a/plugins/wallet_api_plugin/wallet_api_plugin.cpp +++ b/plugins/wallet_api_plugin/wallet_api_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet.hpp b/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet.hpp index e8b7c91a7e3..480e7a32a44 100644 --- a/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet.hpp +++ b/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet_api.hpp b/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet_api.hpp index 0c80be0d880..0627eceff33 100644 --- a/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet_api.hpp +++ b/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet_api.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet_manager.hpp b/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet_manager.hpp index efc10f1a7f9..e73bc32d971 100644 --- a/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet_manager.hpp +++ b/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet_manager.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet_plugin.hpp b/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet_plugin.hpp index 1b0986fe8f9..c23911fa6fb 100644 --- a/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet_plugin.hpp +++ b/plugins/wallet_plugin/include/eosio/wallet_plugin/wallet_plugin.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/plugins/wallet_plugin/se_wallet.cpp b/plugins/wallet_plugin/se_wallet.cpp index 6e1a4fe0e17..8b43d569881 100644 --- a/plugins/wallet_plugin/se_wallet.cpp +++ b/plugins/wallet_plugin/se_wallet.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include @@ -305,6 +305,14 @@ se_wallet::se_wallet() : my(new detail::se_wallet_impl()) { return; } } + if(sscanf(model, "Macmini%u", &major) == 1 && major >= 8) { + my->populate_existing_keys(); + return; + } + if(sscanf(model, "MacBookAir%u", &major) == 1 && major >= 8) { + my->populate_existing_keys(); + return; + } } EOS_THROW(secure_enclave_exception, "Secure Enclave not supported on this hardware"); diff --git a/plugins/wallet_plugin/wallet.cpp b/plugins/wallet_plugin/wallet.cpp index accb2f948b9..53d57697ccd 100644 --- a/plugins/wallet_plugin/wallet.cpp +++ b/plugins/wallet_plugin/wallet.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/plugins/wallet_plugin/wallet_manager.cpp b/plugins/wallet_plugin/wallet_manager.cpp index d851d8156f6..15a39c9d9bd 100644 --- a/plugins/wallet_plugin/wallet_manager.cpp +++ b/plugins/wallet_plugin/wallet_manager.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/plugins/wallet_plugin/wallet_plugin.cpp b/plugins/wallet_plugin/wallet_plugin.cpp index 0416227b3a4..cfd435390a6 100644 --- a/plugins/wallet_plugin/wallet_plugin.cpp +++ b/plugins/wallet_plugin/wallet_plugin.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/plugins/wallet_plugin/yubihsm_wallet.cpp b/plugins/wallet_plugin/yubihsm_wallet.cpp index d3856ad8ee5..682fc02bbb0 100644 --- a/plugins/wallet_plugin/yubihsm_wallet.cpp +++ b/plugins/wallet_plugin/yubihsm_wallet.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt index b3a656c3b10..a40ef3b423c 100644 --- a/programs/CMakeLists.txt +++ b/programs/CMakeLists.txt @@ -2,5 +2,4 @@ add_subdirectory( nodeos ) add_subdirectory( cleos ) add_subdirectory( keosd ) add_subdirectory( eosio-launcher ) -add_subdirectory( eosio-abigen ) add_subdirectory( eosio-blocklog ) diff --git a/programs/cleos/config.hpp.in b/programs/cleos/config.hpp.in index 18673e9c8c2..3fe2051d74c 100644 --- a/programs/cleos/config.hpp.in +++ b/programs/cleos/config.hpp.in @@ -1,5 +1,5 @@ /** @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE * * \warning This file is machine generated. DO NOT EDIT. See config.hpp.in for changes. */ diff --git a/programs/cleos/eosc.pot b/programs/cleos/eosc.pot index 8196aad741d..d0927037809 100644 --- a/programs/cleos/eosc.pot +++ b/programs/cleos/eosc.pot @@ -343,16 +343,16 @@ msgstr "" msgid "set or update blockchain action state" msgstr "" -msgid "Transfer EOS from account to account" +msgid "Transfer tokens from account to account" msgstr "" -msgid "The account sending EOS" +msgid "The account sending tokens" msgstr "" -msgid "The account receiving EOS" +msgid "The account receiving tokens" msgstr "" -msgid "The amount of EOS to send" +msgid "The amount of tokens to send" msgstr "" msgid "The memo for the transfer" diff --git a/programs/cleos/help_text.cpp b/programs/cleos/help_text.cpp index 84173e0dda8..b1f9161a54d 100644 --- a/programs/cleos/help_text.cpp +++ b/programs/cleos/help_text.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include "help_text.hpp" #include "localize.hpp" diff --git a/programs/cleos/help_text.hpp b/programs/cleos/help_text.hpp index cb0f21a828e..dbae493d714 100644 --- a/programs/cleos/help_text.hpp +++ b/programs/cleos/help_text.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once #include diff --git a/programs/cleos/httpc.hpp b/programs/cleos/httpc.hpp index 850b7bab787..a5db5dbe90f 100644 --- a/programs/cleos/httpc.hpp +++ b/programs/cleos/httpc.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/programs/cleos/localize.hpp b/programs/cleos/localize.hpp index 72cd073e813..ea15ea3009b 100644 --- a/programs/cleos/localize.hpp +++ b/programs/cleos/localize.hpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #pragma once diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index af70e0683b8..bc9373b84a1 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE * @defgroup eosclienttool EOSIO Command Line Client Reference * @brief Tool for sending transactions and querying state from @ref nodeos * @ingroup eosclienttool @@ -35,7 +35,7 @@ Usage: programs/cleos/cleos [OPTIONS] SUBCOMMAND create Create various items, on and off the blockchain get Retrieve various items and information from the blockchain set Set or update blockchain state - transfer Transfer EOS from account to account + transfer Transfer tokens from account to account net Interact with local p2p network connections wallet Interact with local wallet sign Sign a transaction @@ -84,7 +84,6 @@ Usage: ./cleos create account [OPTIONS] creator name OwnerKey ActiveKey #include #include #include -#include #include #include @@ -129,7 +128,6 @@ Usage: ./cleos create account [OPTIONS] creator name OwnerKey ActiveKey using namespace std; using namespace eosio; using namespace eosio::chain; -using namespace eosio::utilities; using namespace eosio::client::help; using namespace eosio::client::http; using namespace eosio::client::localize; @@ -234,6 +232,13 @@ vector get_account_permissions(const vector& pe return accountPermissions; } +vector get_account_permissions(const vector& permissions, const chain::permission_level& default_permission) { + if (permissions.empty()) + return vector{default_permission}; + else + return get_account_permissions(tx_permission); +} + template fc::variant call( const std::string& url, const std::string& path, @@ -509,7 +514,7 @@ void send_transaction( signed_transaction& trx, int32_t extra_kcpu, packed_trans chain::action create_newaccount(const name& creator, const name& newaccount, public_key_type owner, public_key_type active) { return action { - tx_permission.empty() ? vector{{creator,config::active_name}} : get_account_permissions(tx_permission), + get_account_permissions(tx_permission, {creator,config::active_name}), eosio::chain::newaccount{ .creator = creator, .name = newaccount, @@ -528,7 +533,7 @@ chain::action create_buyram(const name& creator, const name& newaccount, const a ("payer", creator.to_string()) ("receiver", newaccount.to_string()) ("quant", quantity.to_string()); - return create_action(tx_permission.empty() ? vector{{creator,config::active_name}} : get_account_permissions(tx_permission), + return create_action(get_account_permissions(tx_permission, {creator,config::active_name}), config::system_account_name, N(buyram), act_payload); } @@ -537,7 +542,7 @@ chain::action create_buyrambytes(const name& creator, const name& newaccount, ui ("payer", creator.to_string()) ("receiver", newaccount.to_string()) ("bytes", numbytes); - return create_action(tx_permission.empty() ? vector{{creator,config::active_name}} : get_account_permissions(tx_permission), + return create_action(get_account_permissions(tx_permission, {creator,config::active_name}), config::system_account_name, N(buyrambytes), act_payload); } @@ -548,19 +553,18 @@ chain::action create_delegate(const name& from, const name& receiver, const asse ("stake_net_quantity", net.to_string()) ("stake_cpu_quantity", cpu.to_string()) ("transfer", transfer); - return create_action(tx_permission.empty() ? vector{{from,config::active_name}} : get_account_permissions(tx_permission), + return create_action(get_account_permissions(tx_permission, {from,config::active_name}), config::system_account_name, N(delegatebw), act_payload); } -fc::variant regproducer_variant(const account_name& producer, const public_key_type& key, const string& url, const string& location) { -auto _location=atoi(location.c_str()); - FC_ASSERT(_location>-12&&_location<=12,"time zone setting is not legal"); - _location=_location>=0?_location:24+_location; +fc::variant regproducer_variant(const account_name& producer, const public_key_type& key, const string& url, int16_t location) { + FC_ASSERT(location>-12&&location<=12,"time zone setting is not legal"); + location=location>=0?location:24+location; return fc::mutable_variant_object() ("producer", producer) ("producer_key", key) ("url", url) - ("location", _location) + ("location", location) ; } @@ -570,7 +574,7 @@ chain::action create_open(const string& contract, const name& owner, symbol sym, ("symbol", sym) ("ram_payer", ram_payer); return action { - tx_permission.empty() ? vector{{ram_payer,config::active_name}} : get_account_permissions(tx_permission), + get_account_permissions(tx_permission, {ram_payer,config::active_name}), contract, "open", variant_to_bin( contract, N(open), open_ ) }; } @@ -584,14 +588,14 @@ chain::action create_transfer(const string& contract, const name& sender, const ("memo", memo); return action { - tx_permission.empty() ? vector{{sender,config::active_name}} : get_account_permissions(tx_permission), + get_account_permissions(tx_permission, {sender,config::active_name}), contract, "transfer", variant_to_bin( contract, N(transfer), transfer ) }; } chain::action create_setabi(const name& account, const bytes& abi) { return action { - tx_permission.empty() ? vector{{account,config::active_name}} : get_account_permissions(tx_permission), + get_account_permissions(tx_permission, {account,config::active_name}), setabi{ .account = account, .abi = abi @@ -601,7 +605,7 @@ chain::action create_setabi(const name& account, const bytes& abi) { chain::action create_setcode(const name& account, const bytes& code) { return action { - tx_permission.empty() ? vector{{account,config::active_name}} : get_account_permissions(tx_permission), + get_account_permissions(tx_permission, {account,config::active_name}), setcode{ .account = account, .vmtype = 0, @@ -612,22 +616,22 @@ chain::action create_setcode(const name& account, const bytes& code) { } chain::action create_updateauth(const name& account, const name& permission, const name& parent, const authority& auth) { - return action { tx_permission.empty() ? vector{{account,config::active_name}} : get_account_permissions(tx_permission), + return action { get_account_permissions(tx_permission, {account,config::active_name}), updateauth{account, permission, parent, auth}}; } chain::action create_deleteauth(const name& account, const name& permission) { - return action { tx_permission.empty() ? vector{{account,config::active_name}} : get_account_permissions(tx_permission), + return action { get_account_permissions(tx_permission, {account,config::active_name}), deleteauth{account, permission}}; } chain::action create_linkauth(const name& account, const name& code, const name& type, const name& requirement) { - return action { tx_permission.empty() ? vector{{account,config::active_name}} : get_account_permissions(tx_permission), + return action { get_account_permissions(tx_permission, {account,config::active_name}), linkauth{account, code, type, requirement}}; } chain::action create_unlinkauth(const name& account, const name& code, const name& type) { - return action { tx_permission.empty() ? vector{{account,config::active_name}} : get_account_permissions(tx_permission), + return action { get_account_permissions(tx_permission, {account,config::active_name}), unlinkauth{account, code, type}}; } @@ -686,58 +690,134 @@ inline asset to_asset( const string& s ) { } struct set_account_permission_subcommand { - string accountStr; - string permissionStr; - string authorityJsonOrFile; - string parentStr; + name account; + name permission; + string authority_json_or_file; + name parent; + bool add_code; + bool remove_code; set_account_permission_subcommand(CLI::App* accountCmd) { auto permissions = accountCmd->add_subcommand("permission", localized("set parameters dealing with account permissions")); - permissions->add_option("account", accountStr, localized("The account to set/delete a permission authority for"))->required(); - permissions->add_option("permission", permissionStr, localized("The permission name to set/delete an authority for"))->required(); - permissions->add_option("authority", authorityJsonOrFile, localized("[delete] NULL, [create/update] public key, JSON string, or filename defining the authority"))->required(); - permissions->add_option("parent", parentStr, localized("[create] The permission name of this parents permission (Defaults to: \"Active\")")); + permissions->add_option("account", account, localized("The account to set/delete a permission authority for"))->required(); + permissions->add_option("permission", permission, localized("The permission name to set/delete an authority for"))->required(); + permissions->add_option("authority", authority_json_or_file, localized("[delete] NULL, [create/update] public key, JSON string or filename defining the authority, [code] contract name")); + permissions->add_option("parent", parent, localized("[create] The permission name of this parents permission, defaults to 'active'")); + permissions->add_flag("--add-code", add_code, localized("[code] add '${code}' permission to specified permission authority", ("code", name(config::eosio_code_name)))); + permissions->add_flag("--remove-code", remove_code, localized("[code] remove '${code}' permission from specified permission authority", ("code", name(config::eosio_code_name)))); add_standard_transaction_options(permissions, "account@active"); permissions->set_callback([this] { - name account = name(accountStr); - name permission = name(permissionStr); - bool is_delete = boost::iequals(authorityJsonOrFile, "null"); + EOSC_ASSERT( !(add_code && remove_code), "ERROR: Either --add-code or --remove-code can be set" ); + EOSC_ASSERT( (add_code ^ remove_code) || !authority_json_or_file.empty(), "ERROR: authority should be specified unless add or remove code permission" ); - if (is_delete) { - send_actions({create_deleteauth(account, permission)}); - } else { - authority auth = parse_json_authority_or_key(authorityJsonOrFile); + authority auth; + + bool need_parent = parent.empty() && (permission != name("owner")); + bool need_auth = add_code || remove_code; + + if ( !need_auth && boost::iequals(authority_json_or_file, "null") ) { + send_actions( { create_deleteauth(account, permission) } ); + return; + } + + if ( need_parent || need_auth ) { + fc::variant json = call(get_account_func, fc::mutable_variant_object("account_name", account.to_string())); + auto res = json.as(); + auto itr = std::find_if(res.permissions.begin(), res.permissions.end(), [&](const auto& perm) { + return perm.perm_name == permission; + }); - name parent; - if (parentStr.size() == 0 && permissionStr != "owner") { + if ( need_parent ) { // see if we can auto-determine the proper parent - const auto account_result = call(get_account_func, fc::mutable_variant_object("account_name", accountStr)); - const auto& existing_permissions = account_result.get_object()["permissions"].get_array(); - auto permissionPredicate = [this](const auto& perm) { - return perm.is_object() && - perm.get_object().contains("perm_name") && - boost::equals(perm.get_object()["perm_name"].get_string(), permissionStr); - }; - - auto itr = boost::find_if(existing_permissions, permissionPredicate); - if (itr != existing_permissions.end()) { - parent = name((*itr).get_object()["parent"].get_string()); + if ( itr != res.permissions.end() ) { + parent = (*itr).parent; } else { // if this is a new permission and there is no parent we default to "active" parent = name(config::active_name); + } + } + if ( need_auth ) { + auto actor = (authority_json_or_file.empty()) ? account : name(authority_json_or_file); + auto code_name = name(config::eosio_code_name); + + if ( itr != res.permissions.end() ) { + // fetch existing authority + auth = std::move((*itr).required_auth); + + auto code_perm = permission_level { actor, code_name }; + auto itr2 = std::lower_bound(auth.accounts.begin(), auth.accounts.end(), code_perm, [&](const auto& perm_level, const auto& value) { + return perm_level.permission < value; // Safe since valid authorities must order the permissions in accounts in ascending order + }); + + if ( add_code ) { + if ( itr2 != auth.accounts.end() && itr2->permission == code_perm ) { + // authority already contains code permission, promote its weight to satisfy threshold + if ( (*itr2).weight < auth.threshold ) { + if ( auth.threshold > std::numeric_limits::max() ) { + std::cerr << "ERROR: Threshold is too high to be satisfied by sole code permission" << std::endl; + return; + } + std::cerr << localized("The weight of '${actor}@${code}' in '${permission}' permission authority will be increased up to threshold", + ("actor", actor)("code", code_name)("permission", permission)) << std::endl; + (*itr2).weight = static_cast(auth.threshold); + } else { + std::cerr << localized("ERROR: The permission '${permission}' already contains '${actor}@${code}'", + ("permission", permission)("actor", actor)("code", code_name)) << std::endl; + return ; + } + } else { + // add code permission to specified authority + if ( auth.threshold > std::numeric_limits::max() ) { + std::cerr << "ERROR: Threshold is too high to be satisfied by sole code permission" << std::endl; + return; + } + auth.accounts.insert( itr2, permission_level_weight { + .permission = { actor, code_name }, + .weight = static_cast(auth.threshold) + }); + } + } else { + if ( itr2 != auth.accounts.end() && itr2->permission == code_perm ) { + // remove code permission, if authority becomes empty by the removal of code permission, delete permission + auth.accounts.erase( itr2 ); + if ( auth.keys.empty() && auth.accounts.empty() && auth.waits.empty() ) { + send_actions( { create_deleteauth(account, permission) } ); + return; + } + } else { + // authority doesn't contain code permission + std::cerr << localized("ERROR: '${actor}@${code}' does not exist in '${permission}' permission authority", + ("actor", actor)("code", code_name)("permission", permission)) << std::endl; + return; + } + } + } else { + if ( add_code ) { + // create new permission including code permission + auth.threshold = 1; + auth.accounts.push_back( permission_level_weight { + .permission = { actor, code_name }, + .weight = 1 + }); + } else { + // specified permission doesn't exist, so failed to remove code permission from it + std::cerr << localized("ERROR: The permission '${permission}' does not exist", ("permission", permission)) << std::endl; + return; + } } - } else { - parent = name(parentStr); } + } - send_actions({create_updateauth(account, permission, parent, auth)}); + if ( !need_auth ) { + auth = parse_json_authority_or_key(authority_json_or_file); } + + send_actions( { create_updateauth(account, permission, parent, auth) } ); }); } - }; struct set_action_permission_subcommand { @@ -864,15 +944,15 @@ struct register_producer_subcommand { string producer_str; string producer_key_str; string url; - string loc; + int16_t loc = 0; register_producer_subcommand(CLI::App* actionRoot) { auto register_producer = actionRoot->add_subcommand("regproducer", localized("Register a new producer")); register_producer->add_option("account", producer_str, localized("The account to register as a producer"))->required(); register_producer->add_option("producer_key", producer_key_str, localized("The producer's public key"))->required(); register_producer->add_option("url", url, localized("url where info about producer can be found"), true); - register_producer->add_option("location", loc, localized("time zone from -11 to 12 "))->required(); - add_standard_transaction_options(register_producer); + register_producer->add_option("location", loc, localized("time zone from -11 to 12"), true)->required(); + add_standard_transaction_options(register_producer, "account@active"); register_producer->set_callback([this] { @@ -882,7 +962,8 @@ struct register_producer_subcommand { } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid producer public key: ${public_key}", ("public_key", producer_key_str)) auto regprod_var = regproducer_variant(producer_str, producer_key, url, loc ); - send_actions({create_action({permission_level{producer_str,config::active_name}}, config::system_account_name, N(regproducer), regprod_var)}); + auto accountPermissions = get_account_permissions(tx_permission, {producer_str,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(regproducer), regprod_var)}); }); } }; @@ -913,20 +994,20 @@ struct create_account_subcommand { if (!simple) { createAccount->add_option("--stake-net", stake_net, - (localized("The amount of EOS delegated for net bandwidth")))->required(); + (localized("The amount of tokens delegated for net bandwidth")))->required(); createAccount->add_option("--stake-cpu", stake_cpu, - (localized("The amount of EOS delegated for CPU bandwidth")))->required(); + (localized("The amount of tokens delegated for CPU bandwidth")))->required(); createAccount->add_option("--buy-ram-kbytes", buy_ram_bytes_in_kbytes, (localized("The amount of RAM bytes to purchase for the new account in kibibytes (KiB)"))); createAccount->add_option("--buy-ram-bytes", buy_ram_bytes, (localized("The amount of RAM bytes to purchase for the new account in bytes"))); createAccount->add_option("--buy-ram", buy_ram_eos, - (localized("The amount of RAM bytes to purchase for the new account in EOS"))); + (localized("The amount of RAM bytes to purchase for the new account in tokens"))); createAccount->add_flag("--transfer", transfer, - (localized("Transfer voting power and right to unstake EOS to receiver"))); + (localized("Transfer voting power and right to unstake tokens to receiver"))); } - add_standard_transaction_options(createAccount); + add_standard_transaction_options(createAccount, "creator@active"); createAccount->set_callback([this] { if( !active_key_str.size() ) @@ -965,13 +1046,14 @@ struct unregister_producer_subcommand { unregister_producer_subcommand(CLI::App* actionRoot) { auto unregister_producer = actionRoot->add_subcommand("unregprod", localized("Unregister an existing producer")); unregister_producer->add_option("account", producer_str, localized("The account to unregister as a producer"))->required(); - add_standard_transaction_options(unregister_producer); + add_standard_transaction_options(unregister_producer, "account@active"); unregister_producer->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("producer", producer_str); - send_actions({create_action({permission_level{producer_str,config::active_name}}, config::system_account_name, N(unregprod), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {producer_str,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(unregprod), act_payload)}); }); } }; @@ -984,14 +1066,15 @@ struct vote_producer_proxy_subcommand { auto vote_proxy = actionRoot->add_subcommand("proxy", localized("Vote your stake through a proxy")); vote_proxy->add_option("voter", voter_str, localized("The voting account"))->required(); vote_proxy->add_option("proxy", proxy_str, localized("The proxy account"))->required(); - add_standard_transaction_options(vote_proxy); + add_standard_transaction_options(vote_proxy, "voter@active"); vote_proxy->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("voter", voter_str) ("proxy", proxy_str) ("producers", std::vector{}); - send_actions({create_action({permission_level{voter_str,config::active_name}}, config::system_account_name, N(voteproducer), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {voter_str,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } }; @@ -1004,7 +1087,7 @@ struct vote_producers_subcommand { auto vote_producers = actionRoot->add_subcommand("prods", localized("Vote for one or more producers")); vote_producers->add_option("voter", voter_str, localized("The voting account"))->required(); vote_producers->add_option("producers", producer_names, localized("The account(s) to vote for. All options from this position and following will be treated as the producer list."))->required(); - add_standard_transaction_options(vote_producers); + add_standard_transaction_options(vote_producers, "voter@active"); vote_producers->set_callback([this] { @@ -1014,7 +1097,8 @@ struct vote_producers_subcommand { ("voter", voter_str) ("proxy", "") ("producers", producer_names); - send_actions({create_action({permission_level{voter_str,config::active_name}}, config::system_account_name, N(voteproducer), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {voter_str,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } }; @@ -1027,7 +1111,7 @@ struct approve_producer_subcommand { auto approve_producer = actionRoot->add_subcommand("approve", localized("Add one producer to list of voted producers")); approve_producer->add_option("voter", voter, localized("The voting account"))->required(); approve_producer->add_option("producer", producer_name, localized("The account to vote for"))->required(); - add_standard_transaction_options(approve_producer); + add_standard_transaction_options(approve_producer, "voter@active"); approve_producer->set_callback([this] { auto result = call(get_table_func, fc::mutable_variant_object("json", true) @@ -1036,10 +1120,16 @@ struct approve_producer_subcommand { ("table", "voters") ("table_key", "owner") ("lower_bound", voter.value) + ("upper_bound", voter.value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to voter.value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) ); auto res = result.as(); - if ( res.rows.empty() || res.rows[0]["owner"].as_string() != name(voter).to_string() ) { + // Condition in if statement below can simply be res.rows.empty() when cleos no longer needs to support nodeos versions older than 1.5.0 + // Although since this subcommand will actually change the voter's vote, it is probably better to just keep this check to protect + // against future potential chain_plugin bugs. + if( res.rows.empty() || res.rows[0].get_object()["owner"].as_string() != name(voter).to_string() ) { std::cerr << "Voter info not found for account " << voter << std::endl; return; } @@ -1060,7 +1150,8 @@ struct approve_producer_subcommand { ("voter", voter) ("proxy", "") ("producers", prods); - send_actions({create_action({permission_level{voter,config::active_name}}, config::system_account_name, N(voteproducer), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {voter,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } }; @@ -1073,7 +1164,7 @@ struct unapprove_producer_subcommand { auto approve_producer = actionRoot->add_subcommand("unapprove", localized("Remove one producer from list of voted producers")); approve_producer->add_option("voter", voter, localized("The voting account"))->required(); approve_producer->add_option("producer", producer_name, localized("The account to remove from voted producers"))->required(); - add_standard_transaction_options(approve_producer); + add_standard_transaction_options(approve_producer, "voter@active"); approve_producer->set_callback([this] { auto result = call(get_table_func, fc::mutable_variant_object("json", true) @@ -1082,10 +1173,16 @@ struct unapprove_producer_subcommand { ("table", "voters") ("table_key", "owner") ("lower_bound", voter.value) + ("upper_bound", voter.value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to voter.value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) ); auto res = result.as(); - if ( res.rows.empty() || res.rows[0]["owner"].as_string() != name(voter).to_string() ) { + // Condition in if statement below can simply be res.rows.empty() when cleos no longer needs to support nodeos versions older than 1.5.0 + // Although since this subcommand will actually change the voter's vote, it is probably better to just keep this check to protect + // against future potential chain_plugin bugs. + if( res.rows.empty() || res.rows[0].get_object()["owner"].as_string() != name(voter).to_string() ) { std::cerr << "Voter info not found for account " << voter << std::endl; return; } @@ -1105,7 +1202,8 @@ struct unapprove_producer_subcommand { ("voter", voter) ("proxy", "") ("producers", prods); - send_actions({create_action({permission_level{voter,config::active_name}}, config::system_account_name, N(voteproducer), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {voter,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } }; @@ -1211,12 +1309,12 @@ struct delegate_bandwidth_subcommand { auto delegate_bandwidth = actionRoot->add_subcommand("delegatebw", localized("Delegate bandwidth")); delegate_bandwidth->add_option("from", from_str, localized("The account to delegate bandwidth from"))->required(); delegate_bandwidth->add_option("receiver", receiver_str, localized("The account to receive the delegated bandwidth"))->required(); - delegate_bandwidth->add_option("stake_net_quantity", stake_net_amount, localized("The amount of EOS to stake for network bandwidth"))->required(); - delegate_bandwidth->add_option("stake_cpu_quantity", stake_cpu_amount, localized("The amount of EOS to stake for CPU bandwidth"))->required(); - delegate_bandwidth->add_option("--buyram", buy_ram_amount, localized("The amount of EOS to buyram")); + delegate_bandwidth->add_option("stake_net_quantity", stake_net_amount, localized("The amount of tokens to stake for network bandwidth"))->required(); + delegate_bandwidth->add_option("stake_cpu_quantity", stake_cpu_amount, localized("The amount of tokens to stake for CPU bandwidth"))->required(); + delegate_bandwidth->add_option("--buyram", buy_ram_amount, localized("The amount of tokens to buyram")); delegate_bandwidth->add_option("--buy-ram-bytes", buy_ram_bytes, localized("The amount of RAM to buy in number of bytes")); - delegate_bandwidth->add_flag("--transfer", transfer, localized("Transfer voting power and right to unstake EOS to receiver")); - add_standard_transaction_options(delegate_bandwidth); + delegate_bandwidth->add_flag("--transfer", transfer, localized("Transfer voting power and right to unstake tokens to receiver")); + add_standard_transaction_options(delegate_bandwidth, "from@active"); delegate_bandwidth->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() @@ -1225,7 +1323,8 @@ struct delegate_bandwidth_subcommand { ("stake_net_quantity", to_asset(stake_net_amount)) ("stake_cpu_quantity", to_asset(stake_cpu_amount)) ("transfer", transfer); - std::vector acts{create_action({permission_level{from_str,config::active_name}}, config::system_account_name, N(delegatebw), act_payload)}; + auto accountPermissions = get_account_permissions(tx_permission, {from_str,config::active_name}); + std::vector acts{create_action(accountPermissions, config::system_account_name, N(delegatebw), act_payload)}; EOSC_ASSERT( !(buy_ram_amount.size()) || !buy_ram_bytes, "ERROR: --buyram and --buy-ram-bytes cannot be set at the same time" ); if (buy_ram_amount.size()) { acts.push_back( create_buyram(from_str, receiver_str, to_asset(buy_ram_amount)) ); @@ -1248,9 +1347,9 @@ struct undelegate_bandwidth_subcommand { auto undelegate_bandwidth = actionRoot->add_subcommand("undelegatebw", localized("Undelegate bandwidth")); undelegate_bandwidth->add_option("from", from_str, localized("The account undelegating bandwidth"))->required(); undelegate_bandwidth->add_option("receiver", receiver_str, localized("The account to undelegate bandwidth from"))->required(); - undelegate_bandwidth->add_option("unstake_net_quantity", unstake_net_amount, localized("The amount of EOS to undelegate for network bandwidth"))->required(); - undelegate_bandwidth->add_option("unstake_cpu_quantity", unstake_cpu_amount, localized("The amount of EOS to undelegate for CPU bandwidth"))->required(); - add_standard_transaction_options(undelegate_bandwidth); + undelegate_bandwidth->add_option("unstake_net_quantity", unstake_net_amount, localized("The amount of tokens to undelegate for network bandwidth"))->required(); + undelegate_bandwidth->add_option("unstake_cpu_quantity", unstake_cpu_amount, localized("The amount of tokens to undelegate for CPU bandwidth"))->required(); + add_standard_transaction_options(undelegate_bandwidth, "from@active"); undelegate_bandwidth->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() @@ -1258,7 +1357,8 @@ struct undelegate_bandwidth_subcommand { ("receiver", receiver_str) ("unstake_net_quantity", to_asset(unstake_net_amount)) ("unstake_cpu_quantity", to_asset(unstake_cpu_amount)); - send_actions({create_action({permission_level{from_str,config::active_name}}, config::system_account_name, N(undelegatebw), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {from_str,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(undelegatebw), act_payload)}); }); } }; @@ -1271,14 +1371,15 @@ struct bidname_subcommand { auto bidname = actionRoot->add_subcommand("bidname", localized("Name bidding")); bidname->add_option("bidder", bidder_str, localized("The bidding account"))->required(); bidname->add_option("newname", newname_str, localized("The bidding name"))->required(); - bidname->add_option("bid", bid_amount, localized("The amount of EOS to bid"))->required(); - add_standard_transaction_options(bidname); + bidname->add_option("bid", bid_amount, localized("The amount of tokens to bid"))->required(); + add_standard_transaction_options(bidname, "bidder@active"); bidname->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("bidder", bidder_str) ("newname", newname_str) ("bid", to_asset(bid_amount)); - send_actions({create_action({permission_level{bidder_str, config::active_name}}, config::system_account_name, N(bidname), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {bidder_str,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(bidname), act_payload)}); }); } }; @@ -1293,13 +1394,18 @@ struct bidname_info_subcommand { list_producers->set_callback([this] { auto rawResult = call(get_table_func, fc::mutable_variant_object("json", true) ("code", "eosio")("scope", "eosio")("table", "namebids") - ("lower_bound", newname.value)("limit", 1)); + ("lower_bound", newname.value) + ("upper_bound", newname.value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to newname.value when cleos no longer needs to support nodeos versions older than 1.5.0 + ("limit", 1)); + if ( print_json ) { std::cout << fc::json::to_pretty_string(rawResult) << std::endl; return; } auto result = rawResult.as(); - // Condition in if statement below can simply be res.rows.empty() when cleos no longer needs to support nodeos versions older than 1.5.0 + // Condition in if statement below can simply be res.rows.empty() when cleos no longer needs to support nodeos versions older than 1.5.0 if( result.rows.empty() || result.rows[0].get_object()["newname"].as_string() != newname.to_string() ) { std::cout << "No bidname record found" << std::endl; return; @@ -1311,12 +1417,11 @@ struct bidname_info_subcommand { } catch (fc::parse_error_exception&) { } int64_t bid = row["high_bid"].as_int64(); - std::cout << std::left << std::setw(18) << "bidname:" << std::right << std::setw(24) << row["newname"].as_string() << "\n" + std::cout << std::left << std::setw(18) << "bidname:" << std::right << std::setw(24) << row["newname"].as_string() << "\n" << std::left << std::setw(18) << "highest bidder:" << std::right << std::setw(24) << row["high_bidder"].as_string() << "\n" << std::left << std::setw(18) << "highest bid:" << std::right << std::setw(24) << (bid > 0 ? bid : -bid) << "\n" << std::left << std::setw(18) << "last bid time:" << std::right << std::setw(24) << time << std::endl; - if (bid < 0) std::cout << "This auction has already closed" << std::endl; - + if (bid < 0) std::cout << "This auction has already closed" << std::endl; }); } }; @@ -1369,10 +1474,10 @@ struct buyram_subcommand { auto buyram = actionRoot->add_subcommand("buyram", localized("Buy RAM")); buyram->add_option("payer", from_str, localized("The account paying for RAM"))->required(); buyram->add_option("receiver", receiver_str, localized("The account receiving bought RAM"))->required(); - buyram->add_option("amount", amount, localized("The amount of EOS to pay for RAM, or number of bytes/kibibytes of RAM if --bytes/--kbytes is set"))->required(); + buyram->add_option("amount", amount, localized("The amount of tokens to pay for RAM, or number of bytes/kibibytes of RAM if --bytes/--kbytes is set"))->required(); buyram->add_flag("--kbytes,-k", kbytes, localized("buyram in number of kibibytes (KiB)")); buyram->add_flag("--bytes,-b", bytes, localized("buyram in number of bytes")); - add_standard_transaction_options(buyram); + add_standard_transaction_options(buyram, "payer@active"); buyram->set_callback([this] { EOSC_ASSERT( !kbytes || !bytes, "ERROR: --kbytes and --bytes cannot be set at the same time" ); if (kbytes || bytes) { @@ -1391,15 +1496,16 @@ struct sellram_subcommand { sellram_subcommand(CLI::App* actionRoot) { auto sellram = actionRoot->add_subcommand("sellram", localized("Sell RAM")); - sellram->add_option("account", receiver_str, localized("The account to receive EOS for sold RAM"))->required(); + sellram->add_option("account", receiver_str, localized("The account to receive tokens for sold RAM"))->required(); sellram->add_option("bytes", amount, localized("Number of RAM bytes to sell"))->required(); - add_standard_transaction_options(sellram); + add_standard_transaction_options(sellram, "account@active"); sellram->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("account", receiver_str) ("bytes", amount); - send_actions({create_action({permission_level{receiver_str,config::active_name}}, config::system_account_name, N(sellram), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {receiver_str,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(sellram), act_payload)}); }); } }; @@ -1410,12 +1516,13 @@ struct claimrewards_subcommand { claimrewards_subcommand(CLI::App* actionRoot) { auto claim_rewards = actionRoot->add_subcommand("claimrewards", localized("Claim producer rewards")); claim_rewards->add_option("owner", owner, localized("The account to claim rewards for"))->required(); - add_standard_transaction_options(claim_rewards); + add_standard_transaction_options(claim_rewards, "owner@active"); claim_rewards->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("owner", owner); - send_actions({create_action({permission_level{owner,config::active_name}}, config::system_account_name, N(claimrewards), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {owner,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(claimrewards), act_payload)}); }); } }; @@ -1426,13 +1533,14 @@ struct regproxy_subcommand { regproxy_subcommand(CLI::App* actionRoot) { auto register_proxy = actionRoot->add_subcommand("regproxy", localized("Register an account as a proxy (for voting)")); register_proxy->add_option("proxy", proxy, localized("The proxy account to register"))->required(); - add_standard_transaction_options(register_proxy); + add_standard_transaction_options(register_proxy, "proxy@active"); register_proxy->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("proxy", proxy) ("isproxy", true); - send_actions({create_action({permission_level{proxy,config::active_name}}, config::system_account_name, N(regproxy), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {proxy,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(regproxy), act_payload)}); }); } }; @@ -1443,13 +1551,14 @@ struct unregproxy_subcommand { unregproxy_subcommand(CLI::App* actionRoot) { auto unregister_proxy = actionRoot->add_subcommand("unregproxy", localized("Unregister an account as a proxy (for voting)")); unregister_proxy->add_option("proxy", proxy, localized("The proxy account to unregister"))->required(); - add_standard_transaction_options(unregister_proxy); + add_standard_transaction_options(unregister_proxy, "proxy@active"); unregister_proxy->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("proxy", proxy) ("isproxy", false); - send_actions({create_action({permission_level{proxy,config::active_name}}, config::system_account_name, N(regproxy), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {proxy,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(regproxy), act_payload)}); }); } }; @@ -1464,14 +1573,15 @@ struct canceldelay_subcommand { cancel_delay->add_option("canceling_account", canceling_account, localized("Account from authorization on the original delayed transaction"))->required(); cancel_delay->add_option("canceling_permission", canceling_permission, localized("Permission from authorization on the original delayed transaction"))->required(); cancel_delay->add_option("trx_id", trx_id, localized("The transaction id of the original delayed transaction"))->required(); - add_standard_transaction_options(cancel_delay); + add_standard_transaction_options(cancel_delay, "canceling_account@canceling_permission"); cancel_delay->set_callback([this] { - const auto canceling_auth = permission_level{canceling_account, canceling_permission}; + auto canceling_auth = permission_level{canceling_account, canceling_permission}; fc::variant act_payload = fc::mutable_variant_object() ("canceling_auth", canceling_auth) ("trx_id", trx_id); - send_actions({create_action({canceling_auth}, config::system_account_name, N(canceldelay), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, canceling_auth); + send_actions({create_action(accountPermissions, config::system_account_name, N(canceldelay), act_payload)}); }); } }; @@ -2026,6 +2136,8 @@ int main( int argc, char** argv ) { bool binary = false; uint32_t limit = 10; string index_position; + bool reverse = false; + bool show_payer = false; auto getTable = get->add_subcommand( "table", localized("Retrieve the contents of a database table"), false); getTable->add_option( "account", code, localized("The account who owns the table") )->required(); getTable->add_option( "scope", scope, localized("The scope within the contract in which the table is found") )->required(); @@ -2043,7 +2155,9 @@ int main( int argc, char** argv ) { "\t\t\t\tSpecial type 'name' indicates an account name.")); getTable->add_option( "--encode-type", encode_type, localized("The encoding type of key_type (i64 , i128 , float64, float128) only support decimal encoding e.g. 'dec'" - "i256 - supports both 'dec' and 'hex', ripemd160 and sha256 is 'hex' only\n")); + "i256 - supports both 'dec' and 'hex', ripemd160 and sha256 is 'hex' only")); + getTable->add_flag("-r,--reverse", reverse, localized("Iterate in reverse order")); + getTable->add_flag("--show-payer", show_payer, localized("show RAM payer")); getTable->set_callback([&] { @@ -2058,6 +2172,8 @@ int main( int argc, char** argv ) { ("key_type",key_type) ("index_position", index_position) ("encode_type", encode_type) + ("reverse", reverse) + ("show_payer", show_payer) ); std::cout << fc::json::to_pretty_string(result) @@ -2070,12 +2186,14 @@ int main( int argc, char** argv ) { getScope->add_option( "-l,--limit", limit, localized("The maximum number of rows to return") ); getScope->add_option( "-L,--lower", lower, localized("lower bound of scope") ); getScope->add_option( "-U,--upper", upper, localized("upper bound of scope") ); + getScope->add_flag("-r,--reverse", reverse, localized("Iterate in reverse order")); getScope->set_callback([&] { auto result = call(get_table_by_scope_func, fc::mutable_variant_object("code",code) ("table",table) ("lower_bound",lower) ("upper_bound",upper) ("limit",limit) + ("reverse", reverse) ); std::cout << fc::json::to_pretty_string(result) << std::endl; @@ -2370,9 +2488,7 @@ int main( int argc, char** argv ) { bytes code_bytes; if(!contract_clear){ std::string wasm; - fc::path cpath(contractPath); - - if( cpath.filename().generic_string() == "." ) cpath = cpath.parent_path(); + fc::path cpath = fc::canonical(fc::path(contractPath)); if( wasmPath.empty() ) wasmPath = (cpath / (cpath.filename().generic_string()+".wasm")).generic_string(); @@ -2381,7 +2497,7 @@ int main( int argc, char** argv ) { std::cerr << localized(("Reading WASM from " + wasmPath + "...").c_str()) << std::endl; fc::read_file_contents(wasmPath, wasm); - EOS_ASSERT( !wasm.empty(), wast_file_not_found, "no wasm file found ${f}", ("f", wasmPath) ); + EOS_ASSERT( !wasm.empty(), wasm_file_not_found, "no wasm file found ${f}", ("f", wasmPath) ); const string binary_wasm_header("\x00\x61\x73\x6d\x01\x00\x00\x00", 8); if(wasm.compare(0, 8, binary_wasm_header)) @@ -2425,8 +2541,7 @@ int main( int argc, char** argv ) { bytes abi_bytes; if(!contract_clear){ - fc::path cpath(contractPath); - if( cpath.filename().generic_string() == "." ) cpath = cpath.parent_path(); + fc::path cpath = fc::canonical(fc::path(contractPath)); if( abiPath.empty() ) { abiPath = (cpath / (cpath.filename().generic_string()+".abi")).generic_string(); @@ -2495,10 +2610,10 @@ int main( int argc, char** argv ) { string amount; string memo; bool pay_ram = false; - auto transfer = app.add_subcommand("transfer", localized("Transfer EOS from account to account"), false); - transfer->add_option("sender", sender, localized("The account sending EOS"))->required(); - transfer->add_option("recipient", recipient, localized("The account receiving EOS"))->required(); - transfer->add_option("amount", amount, localized("The amount of EOS to send"))->required(); + auto transfer = app.add_subcommand("transfer", localized("Transfer tokens from account to account"), false); + transfer->add_option("sender", sender, localized("The account sending tokens"))->required(); + transfer->add_option("recipient", recipient, localized("The account receiving tokens"))->required(); + transfer->add_option("amount", amount, localized("The amount of tokens to send"))->required(); transfer->add_option("memo", memo, localized("The memo for the transfer")); transfer->add_option("--contract,-c", con, localized("The contract which controls the token")); transfer->add_flag("--pay-ram-to-open", pay_ram, localized("Pay ram to open recipient's token balance row")); @@ -2745,7 +2860,7 @@ int main( int argc, char** argv ) { fc::set_console_echo(true); } - auto priv_key = fc::crypto::private_key::regenerate(*utilities::wif_to_key(str_private_key)); + auto priv_key = private_key_type(str_private_key); trx.sign(priv_key, *chain_id); if(push_trx) { @@ -2846,7 +2961,7 @@ int main( int argc, char** argv ) { }; auto propose_action = msig->add_subcommand("propose", localized("Propose action")); - add_standard_transaction_options(propose_action); + add_standard_transaction_options(propose_action, "proposer@active"); propose_action->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); propose_action->add_option("requested_permissions", requested_perm, localized("The JSON string or filename defining requested permissions"))->required(); propose_action->add_option("trx_permissions", transaction_perm, localized("The JSON string or filename defining transaction permissions"))->required(); @@ -2915,9 +3030,9 @@ int main( int argc, char** argv ) { send_actions({chain::action{accountPermissions, "eosio.msig", "propose", variant_to_bin( N(eosio.msig), N(propose), args ) }}); }); - //multisige propose transaction + //multisig propose transaction auto propose_trx = msig->add_subcommand("propose_trx", localized("Propose transaction")); - add_standard_transaction_options(propose_trx); + add_standard_transaction_options(propose_trx, "proposer@active"); propose_trx->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); propose_trx->add_option("requested_permissions", requested_perm, localized("The JSON string or filename defining requested permissions"))->required(); propose_trx->add_option("transaction", trx_to_push, localized("The JSON string or filename defining the transaction to push"))->required(); @@ -2957,80 +3072,258 @@ int main( int argc, char** argv ) { // multisig review + bool show_approvals_in_multisig_review = false; auto review = msig->add_subcommand("review", localized("Review transaction")); review->add_option("proposer", proposer, localized("proposer name (string)"))->required(); review->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); + review->add_flag( "--show-approvals", show_approvals_in_multisig_review, localized("Show the status of the approvals requested within the proposal") ); review->set_callback([&] { - auto result = call(get_table_func, fc::mutable_variant_object("json", true) - ("code", "eosio.msig") - ("scope", proposer) - ("table", "proposal") - ("table_key", "") - ("lower_bound", eosio::chain::string_to_name(proposal_name.c_str())) - ("upper_bound", "") - ("limit", 1) - ); + const auto result1 = call(get_table_func, fc::mutable_variant_object("json", true) + ("code", "eosio.msig") + ("scope", proposer) + ("table", "proposal") + ("table_key", "") + ("lower_bound", name(proposal_name).value) + ("upper_bound", name(proposal_name).value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 + ("limit", 1) + ); //std::cout << fc::json::to_pretty_string(result) << std::endl; - fc::variants rows = result.get_object()["rows"].get_array(); - if (rows.empty()) { + const auto& rows1 = result1.get_object()["rows"].get_array(); + // Condition in if statement below can simply be rows.empty() when cleos no longer needs to support nodeos versions older than 1.5.0 + if( rows1.empty() || rows1[0].get_object()["proposal_name"] != proposal_name ) { std::cerr << "Proposal not found" << std::endl; return; } - fc::mutable_variant_object obj = rows[0].get_object(); - if (obj["proposal_name"] != proposal_name) { - std::cerr << "Proposal not found" << std::endl; - return; + + const auto& proposal_object = rows1[0].get_object(); + + enum class approval_status { + unapproved, + approved, + invalidated + }; + + std::map> all_approvals; + std::map>> provided_approvers; + + bool new_multisig = true; + if( show_approvals_in_multisig_review ) { + fc::variants rows2; + + try { + const auto& result2 = call(get_table_func, fc::mutable_variant_object("json", true) + ("code", "eosio.msig") + ("scope", proposer) + ("table", "approvals2") + ("table_key", "") + ("lower_bound", name(proposal_name).value) + ("upper_bound", name(proposal_name).value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 + ("limit", 1) + ); + rows2 = result2.get_object()["rows"].get_array(); + } catch( ... ) { + new_multisig = false; + } + + if( !rows2.empty() && rows2[0].get_object()["proposal_name"] == proposal_name ) { + const auto& approvals_object = rows2[0].get_object(); + + for( const auto& ra : approvals_object["requested_approvals"].get_array() ) { + const auto& ra_obj = ra.get_object(); + auto pl = ra["level"].as(); + auto res = all_approvals.emplace( pl, std::make_pair(ra["time"].as(), approval_status::unapproved) ); + } + + for( const auto& pa : approvals_object["provided_approvals"].get_array() ) { + const auto& pa_obj = pa.get_object(); + auto pl = pa["level"].as(); + auto res = all_approvals.emplace( pl, std::make_pair(pa["time"].as(), approval_status::approved) ); + provided_approvers[pl.actor].second.push_back( res.first ); + } + } else { + const auto result3 = call(get_table_func, fc::mutable_variant_object("json", true) + ("code", "eosio.msig") + ("scope", proposer) + ("table", "approvals") + ("table_key", "") + ("lower_bound", name(proposal_name).value) + ("upper_bound", name(proposal_name).value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 + ("limit", 1) + ); + const auto& rows3 = result3.get_object()["rows"].get_array(); + if( rows3.empty() || rows3[0].get_object()["proposal_name"] != proposal_name ) { + std::cerr << "Proposal not found" << std::endl; + return; + } + + const auto& approvals_object = rows3[0].get_object(); + + for( const auto& ra : approvals_object["requested_approvals"].get_array() ) { + auto pl = ra.as(); + auto res = all_approvals.emplace( pl, std::make_pair(fc::time_point{}, approval_status::unapproved) ); + } + + for( const auto& pa : approvals_object["provided_approvals"].get_array() ) { + auto pl = pa.as(); + auto res = all_approvals.emplace( pl, std::make_pair(fc::time_point{}, approval_status::approved) ); + provided_approvers[pl.actor].second.push_back( res.first ); + } + } + + if( new_multisig ) { + for( auto& a : provided_approvers ) { + const auto result4 = call(get_table_func, fc::mutable_variant_object("json", true) + ("code", "eosio.msig") + ("scope", "eosio.msig") + ("table", "invals") + ("table_key", "") + ("lower_bound", a.first.value) + ("upper_bound", a.first.value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 + ("limit", 1) + ); + const auto& rows4 = result4.get_object()["rows"].get_array(); + if( rows4.empty() || rows4[0].get_object()["account"].as() != a.first ) { + continue; + } + + auto invalidation_time = rows4[0].get_object()["last_invalidation_time"].as(); + a.second.first = invalidation_time; + + for( auto& itr : a.second.second ) { + if( invalidation_time >= itr->second.first ) { + itr->second.second = approval_status::invalidated; + } + } + } + } } - auto trx_hex = obj["packed_transaction"].as_string(); + + auto trx_hex = proposal_object["packed_transaction"].as_string(); vector trx_blob(trx_hex.size()/2); fc::from_hex(trx_hex, trx_blob.data(), trx_blob.size()); transaction trx = fc::raw::unpack(trx_blob); + fc::mutable_variant_object obj; + obj["proposer"] = proposer; + obj["proposal_name"] = proposal_object["proposal_name"]; + obj["transaction_id"] = trx.id(); + + for( const auto& entry : proposal_object ) { + if( entry.key() == "proposal_name" ) continue; + obj.set( entry.key(), entry.value() ); + } + fc::variant trx_var; abi_serializer abi; abi.to_variant(trx, trx_var, abi_serializer_resolver, abi_serializer_max_time); obj["transaction"] = trx_var; - std::cout << fc::json::to_pretty_string(obj) - << std::endl; + + if( show_approvals_in_multisig_review ) { + fc::variants approvals; + + for( const auto& approval : all_approvals ) { + fc::mutable_variant_object approval_obj; + approval_obj["level"] = approval.first; + switch( approval.second.second ) { + case approval_status::unapproved: + { + approval_obj["status"] = "unapproved"; + if( approval.second.first != fc::time_point{} ) { + approval_obj["last_unapproval_time"] = approval.second.first; + } + } + break; + case approval_status::approved: + { + approval_obj["status"] = "approved"; + if( new_multisig ) { + approval_obj["last_approval_time"] = approval.second.first; + } + } + break; + case approval_status::invalidated: + { + approval_obj["status"] = "invalidated"; + approval_obj["last_approval_time"] = approval.second.first; + approval_obj["invalidation_time"] = provided_approvers[approval.first.actor].first; + } + break; + } + + approvals.push_back( std::move(approval_obj) ); + } + + obj["approvals"] = std::move(approvals); + } + + std::cout << fc::json::to_pretty_string(obj) << std::endl; }); string perm; + string proposal_hash; auto approve_or_unapprove = [&](const string& action) { fc::variant perm_var; try { perm_var = json_from_file_or_string(perm); } EOS_RETHROW_EXCEPTIONS(transaction_type_exception, "Fail to parse permissions JSON '${data}'", ("data",perm)) + auto args = fc::mutable_variant_object() ("proposer", proposer) ("proposal_name", proposal_name) ("level", perm_var); - auto accountPermissions = tx_permission.empty() ? vector{{sender,config::active_name}} : get_account_permissions(tx_permission); + if( proposal_hash.size() ) { + args("proposal_hash", proposal_hash); + } + + auto accountPermissions = get_account_permissions(tx_permission, {proposer,config::active_name}); send_actions({chain::action{accountPermissions, "eosio.msig", action, variant_to_bin( N(eosio.msig), action, args ) }}); }; // multisig approve auto approve = msig->add_subcommand("approve", localized("Approve proposed transaction")); - add_standard_transaction_options(approve); + add_standard_transaction_options(approve, "proposer@active"); approve->add_option("proposer", proposer, localized("proposer name (string)"))->required(); approve->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); approve->add_option("permissions", perm, localized("The JSON string of filename defining approving permissions"))->required(); + approve->add_option("proposal_hash", proposal_hash, localized("Hash of proposed transaction (i.e. transaction ID) to optionally enforce as a condition of the approval")); approve->set_callback([&] { approve_or_unapprove("approve"); }); // multisig unapprove auto unapprove = msig->add_subcommand("unapprove", localized("Unapprove proposed transaction")); - add_standard_transaction_options(unapprove); + add_standard_transaction_options(unapprove, "proposer@active"); unapprove->add_option("proposer", proposer, localized("proposer name (string)"))->required(); unapprove->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); unapprove->add_option("permissions", perm, localized("The JSON string of filename defining approving permissions"))->required(); unapprove->set_callback([&] { approve_or_unapprove("unapprove"); }); + // multisig invalidate + string invalidator; + auto invalidate = msig->add_subcommand("invalidate", localized("Invalidate all multisig approvals of an account")); + add_standard_transaction_options(invalidate, "invalidator@active"); + invalidate->add_option("invalidator", invalidator, localized("invalidator name (string)"))->required(); + invalidate->set_callback([&] { + auto args = fc::mutable_variant_object() + ("account", invalidator); + + auto accountPermissions = get_account_permissions(tx_permission, {invalidator,config::active_name}); + send_actions({chain::action{accountPermissions, "eosio.msig", "invalidate", variant_to_bin( N(eosio.msig), "invalidate", args ) }}); + }); + // multisig cancel string canceler; auto cancel = msig->add_subcommand("cancel", localized("Cancel proposed transaction")); - add_standard_transaction_options(cancel); + add_standard_transaction_options(cancel, "canceler@active"); cancel->add_option("proposer", proposer, localized("proposer name (string)"))->required(); cancel->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); cancel->add_option("canceler", canceler, localized("canceler name (string)")); @@ -3058,7 +3351,7 @@ int main( int argc, char** argv ) { // multisig exec string executer; auto exec = msig->add_subcommand("exec", localized("Execute proposed transaction")); - add_standard_transaction_options(exec); + add_standard_transaction_options(exec, "executer@active"); exec->add_option("proposer", proposer, localized("proposer name (string)"))->required(); exec->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); exec->add_option("executer", executer, localized("account paying for execution (string)")); @@ -3093,7 +3386,7 @@ int main( int argc, char** argv ) { executer = ""; string trx_to_exec; auto wrap_exec = wrap->add_subcommand("exec", localized("Execute a transaction while bypassing authorization checks")); - add_standard_transaction_options(wrap_exec); + add_standard_transaction_options(wrap_exec, "executer@active & --contract@active"); wrap_exec->add_option("executer", executer, localized("Account executing the transaction and paying for the deferred transaction RAM"))->required(); wrap_exec->add_option("transaction", trx_to_exec, localized("The JSON string or filename defining the transaction to execute"))->required(); wrap_exec->add_option("--contract,-c", wrap_con, localized("The account which controls the wrap contract")); diff --git a/programs/eosio-abigen/CMakeLists.txt b/programs/eosio-abigen/CMakeLists.txt deleted file mode 100644 index 93df3c89ef4..00000000000 --- a/programs/eosio-abigen/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -set(SOURCES main.cpp) -find_package(LLVM 4.0 REQUIRED CONFIG) - -link_directories(${LLVM_LIBRARY_DIR}) - -add_executable(eosio-abigen ${SOURCES}) - -set( CMAKE_CXX_STANDARD 14 ) - -if( UNIX AND NOT APPLE ) - set(rt_library rt ) -endif() - -find_package( Gperftools QUIET ) -if( GPERFTOOLS_FOUND ) - message( STATUS "Found gperftools; compiling with TCMalloc") - list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc ) -endif() - -target_link_libraries(eosio-abigen abi_generator) - - -install( TARGETS - eosio-abigen - RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} -) diff --git a/programs/eosio-abigen/main.cpp b/programs/eosio-abigen/main.cpp deleted file mode 100644 index f15cd138ee4..00000000000 --- a/programs/eosio-abigen/main.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include -#include -#include -#include - -using namespace eosio; -using namespace eosio::chain; - -using mvo = fc::mutable_variant_object; - -std::unique_ptr create_factory(bool verbose, bool opt_sfs, string abi_context, abi_def& output, const string& contract, const vector& actions) { - - struct abi_frontend_action_factory : public FrontendActionFactory { - - bool verbose; - bool opt_sfs; - string abi_context; - abi_def& output; - const string& contract; - const vector& actions; - - abi_frontend_action_factory(bool verbose, bool opt_sfs, string abi_context, - abi_def& output, const string& contract, const vector& actions) : verbose(verbose), - abi_context(abi_context), output(output), contract(contract), actions(actions) {} - - clang::FrontendAction *create() override { - return new generate_abi_action(verbose, opt_sfs, abi_context, output, contract, actions); - } - - }; - - return std::unique_ptr( - new abi_frontend_action_factory(verbose, opt_sfs, abi_context, output, contract, actions) - ); -} - -std::unique_ptr create_find_macro_factory(string& contract, vector& actions, string abi_context) { - - struct abi_frontend_macro_action_factory : public FrontendActionFactory { - - string& contract; - vector& actions; - string abi_context; - - abi_frontend_macro_action_factory (string& contract, vector& actions, - string abi_context ) : contract(contract), actions(actions), abi_context(abi_context) {} - - clang::FrontendAction *create() override { - return new find_eosio_abi_macro_action(contract, actions, abi_context); - } - - }; - - return std::unique_ptr( - new abi_frontend_macro_action_factory(contract, actions, abi_context) - ); -} - -static cl::OptionCategory abi_generator_category("ABI generator options"); - -static cl::opt abi_context( - "context", - cl::desc("ABI context"), - cl::cat(abi_generator_category)); - -static cl::opt abi_destination( - "destination-file", - cl::desc("destination json file"), - cl::cat(abi_generator_category)); - -static cl::opt abi_verbose( - "verbose", - cl::desc("show debug info"), - cl::cat(abi_generator_category)); - -static cl::opt abi_opt_sfs( - "optimize-sfs", - cl::desc("Optimize single field struct"), - cl::cat(abi_generator_category)); - -int main(int argc, const char **argv) { abi_def output; try { - CommonOptionsParser op(argc, argv, abi_generator_category); - ClangTool Tool(op.getCompilations(), op.getSourcePathList()); - - string contract; - vector actions; - int result = Tool.run(create_find_macro_factory(contract, actions, abi_context).get()); - if(!result) { - output.version = "eosio::abi/1.0"; - result = Tool.run(create_factory(abi_verbose, abi_opt_sfs, abi_context, output, contract, actions).get()); - if(!result) { - abi_serializer abis(output, fc::seconds(1)); // No risk to client side serialization taking a long time - fc::variant vabi; - to_variant(output, vabi); - - auto comment = fc::format_string( - "This file was generated by eosio-abigen. DO NOT EDIT - ${ts}", - mvo("ts",fc::time_point_sec(fc::time_point::now()).to_iso_string())); - - auto abi_with_comment = mvo("____comment", comment)(mvo(vabi)); - - fc::json::save_to_file(abi_with_comment, abi_destination, true); - } - } - return result; -} FC_CAPTURE_AND_LOG((output)); return -1; } diff --git a/programs/eosio-launcher/config.hpp.in b/programs/eosio-launcher/config.hpp.in index 1bb4d10b59a..f60e6ab19e5 100644 --- a/programs/eosio-launcher/config.hpp.in +++ b/programs/eosio-launcher/config.hpp.in @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE * * \warning This file is machine generated. DO NOT EDIT. See config.hpp.in for changes. */ diff --git a/programs/eosio-launcher/main.cpp b/programs/eosio-launcher/main.cpp index 597e473b677..55a027b6928 100644 --- a/programs/eosio-launcher/main.cpp +++ b/programs/eosio-launcher/main.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE * @brief launch testnet nodes **/ #include diff --git a/programs/keosd/config.hpp.in b/programs/keosd/config.hpp.in index a7d34f390dc..370f88db1a9 100644 --- a/programs/keosd/config.hpp.in +++ b/programs/keosd/config.hpp.in @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE * * \warning This file is machine generated. DO NOT EDIT. See config.hpp.in for changes. */ diff --git a/programs/keosd/main.cpp b/programs/keosd/main.cpp index c457af3c0e3..efbf2d567f2 100644 --- a/programs/keosd/main.cpp +++ b/programs/keosd/main.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include diff --git a/programs/nodeos/CMakeLists.txt b/programs/nodeos/CMakeLists.txt index 946c8c83200..7d03ce0001f 100644 --- a/programs/nodeos/CMakeLists.txt +++ b/programs/nodeos/CMakeLists.txt @@ -51,6 +51,7 @@ target_link_libraries( ${NODE_EXECUTABLE_NAME} PRIVATE appbase PRIVATE -Wl,${whole_archive_flag} login_plugin -Wl,${no_whole_archive_flag} PRIVATE -Wl,${whole_archive_flag} history_plugin -Wl,${no_whole_archive_flag} + PRIVATE -Wl,${whole_archive_flag} state_history_plugin -Wl,${no_whole_archive_flag} PRIVATE -Wl,${whole_archive_flag} bnet_plugin -Wl,${no_whole_archive_flag} PRIVATE -Wl,${whole_archive_flag} history_api_plugin -Wl,${no_whole_archive_flag} PRIVATE -Wl,${whole_archive_flag} chain_api_plugin -Wl,${no_whole_archive_flag} diff --git a/programs/nodeos/config.hpp.in b/programs/nodeos/config.hpp.in index ac595383297..dbeba72a3d1 100644 --- a/programs/nodeos/config.hpp.in +++ b/programs/nodeos/config.hpp.in @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE * * \warning This file is machine generated. DO NOT EDIT. See config.hpp.in for changes. */ diff --git a/programs/nodeos/main.cpp b/programs/nodeos/main.cpp index 9ed46f9cb24..52eb9a0e9ab 100644 --- a/programs/nodeos/main.cpp +++ b/programs/nodeos/main.cpp @@ -6,10 +6,8 @@ #include #include -#include #include #include -#include #include #include @@ -94,7 +92,6 @@ int main(int argc, char** argv) { try { app().set_version(eosio::nodeos::config::version); - app().register_plugin(); auto root = fc::app_path(); app().set_default_data_dir(root / "eosio/nodeos/data" ); diff --git a/scripts/abi_to_rc/README.md b/scripts/abi_to_rc/README.md deleted file mode 100644 index 70a5439c913..00000000000 --- a/scripts/abi_to_rc/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Purpose -The `abi_to_rc.py` script processes a contract's .abi file in order to generate an overview Ricardian Contract and a Ricardian Contract for each action. The overview Ricardian Contract provides a description of the contract's purpose and also specifies the contract's action(s), input(s), and input type(s). The action Ricardian Contract provides a description of the action's purpose and also specifies the action's input(s), and input type(s). - -## How to run -`$ python abi_to_rc.py /path/to/smart-contract.abi` - -## Example -`$ python abi_to_rc.py ../../contracts/currency/currency.abi` - -## Results -For the example above, `abi_to_rc.py` should generate output files that have the following names: `currency-rc.md`, `currency-transfer-rc.md`, `currency-issue-rc.md`, `currency-create-rc.md`. - -## Notes -Be sure to have `abi_to_rc.py`, `rc-overview-template.md`, and `rc-action-template.md` in the same folder. diff --git a/scripts/abi_to_rc/abi_to_rc.py b/scripts/abi_to_rc/abi_to_rc.py deleted file mode 100644 index 49ccb77bca6..00000000000 --- a/scripts/abi_to_rc/abi_to_rc.py +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env python3 - -# By: Jon-Eric Cook -# Github: @joneric - -from string import Template -import argparse -import json -import sys -import os -import re - -# argument parser -parser = argparse.ArgumentParser( - prog="abi_to_rc.py", - description="The abi_to_rc.py script processes a contract's .abi file in order to generate an overview Ricardian Contract and a Ricardian Contract for each action. The overview Ricardian Contract provides a description of the contract's purpose and also specifies the contract's action(s), input(s), and input type(s). The action Ricardian Contract provides a description of the action's purpose and also specifies the action's input(s), and input type(s).", - epilog="example: $ python abi_to_rc.py ../../contracts/currency/currency.abi", - usage="$ python %(prog)s [-h] abi_file") -parser.add_argument("abi_file", help="path to smart contract's .abi file") -args = parser.parse_args() - -# global variables -_RC_OVERVIEW = "rc-overview-template.md" -_RC_ACTION = "rc-action-template.md" -actions = [] -inputs = {} -types = {} - -# checks for abi and template files -def check_for_files(): - if not os.path.isfile(args.abi_file): - abi_filename = os.path.split(args.abi_file)[1] - print("ERROR: %s could not be found" % abi_filename) - exit(1) - if not os.path.isfile(os.path.join(os.path.dirname(sys.argv[0]), _RC_OVERVIEW)): - print("ERROR: %s could not be found" % _RC_OVERVIEW) - exit(1) - if not os.path.isfile(os.path.join(os.path.dirname(sys.argv[0]), _RC_ACTION)): - print("ERROR: %s could not be found" % _RC_ACTION) - exit(1) - -# gets actions, inputs and input types from abi file -def get_actions_inputs_types(): - abi_file = open(args.abi_file,'r') - abi_text = abi_file.read() - abi_file.close() - abi_json = json.loads(abi_text) - actions_json = abi_json['actions'] - for obj in actions_json: - actions.append(obj) - structs_json = abi_json['structs'] - for action in actions: - inputs[action['name']] = [] - types[action['name']] = [] - for struct in structs_json: - for action in actions: - if struct['name'] == action['type']: - for field in struct['fields']: - inputs[action['name']].append(field['name']) - types[action['name']].append(field['type']) - -# builds rows for the table -def build_table_rows(is_action): - table_rows = [] - for action in actions: - action_string = "`{{ " + action['name'] + " }}`" - input_string = "" - input_list = [] - type_string = "" - type_list =[] - if len(inputs[action['name']]) >= 1: - for name in inputs[action['name']]: - input_list.append("`{{ " + name + ("Var }}`" if is_action else " }}`")) - input_string = '
'.join(input_list) - else: - input_string = "`{{ " + action['type'] + ("Var }}`" if is_action else " }}`") - if len(types[action['name']]) >= 1: - for name in types[action['name']]: - type_list.append("`{{ " + name + " }}`") - type_string = '
'.join(type_list) - else: - type_string = "`{{ " + action['type'] + " }}`" - table_rows.append('| ' + action_string + ' | ' + input_string + ' | ' + type_string + ' |') - return table_rows - -# generates an overview ricardian contract from the overview template -def generate_rc_overview_file(): - tr = build_table_rows(False) - abi_file_name = os.path.split(args.abi_file)[1] - contract_name = os.path.splitext(abi_file_name)[0] - rc_file_name = contract_name + '-rc.md' - dirname = os.path.split(args.abi_file)[0] - subs = {'contract': "{{ " + contract_name + " }}", - 'action': 'actions' if len(actions) > 1 else 'action', - 'input': 'inputs' if len(inputs) > 1 else 'input', - 'type': 'types' if len(types) > 1 else 'type'} - subs.update([(k+'_header',v.title()) for k,v in subs.copy().items()]) - rc_file = open(os.path.join(dirname, rc_file_name),"w+") - with open(os.path.join(os.path.dirname(sys.argv[0]), _RC_OVERVIEW)) as fp: - overview_template = Template(fp.read()) - rc_file.write(overview_template.substitute(subs)) - rc_file.write('\n'.join(tr)) - rc_file.close() - -# generates a ricardian contract for each action from the action template -def generate_rc_action_files(): - tr = build_table_rows(True) - abi_filename = os.path.split(args.abi_file)[1] - contract_name = os.path.splitext(abi_filename)[0] - dirname = os.path.split(args.abi_file)[0] - for action in actions: - subs = {'action': "{{ " + action['name'] + " }}", - 'input': 'inputs' if len(inputs[action['name']]) > 1 else 'input', - 'type': 'types' if len(types[action['name']]) > 1 else 'type'} - subs.update([(k+'_header',v.title()) for k,v in subs.copy().items()]) - rc_action_file_name = contract_name + "-" + action['name'] + '-rc.md' - rc_file = open(os.path.join(dirname, rc_action_file_name),"w+") - with open(os.path.join(os.path.dirname(sys.argv[0]), _RC_ACTION)) as fp: - action_template = Template(fp.read()) - rc_file.write(action_template.substitute(subs)) - for row in tr: - if re.search("\\b" + action['name'] + "\\b", row): - rc_file.write(row + "\n") - rc_file.close() - -# main program -def main(): - check_for_files() - get_actions_inputs_types() - generate_rc_overview_file() - generate_rc_action_files() - -# runs main -if __name__== "__main__": - main() \ No newline at end of file diff --git a/scripts/abi_to_rc/rc-action-template.md b/scripts/abi_to_rc/rc-action-template.md deleted file mode 100644 index 04934c92e32..00000000000 --- a/scripts/abi_to_rc/rc-action-template.md +++ /dev/null @@ -1,14 +0,0 @@ -# Action - `$action` - -This Contract is legally binding and can be used in the event of a dispute. Disputes shall be settled through the standard arbitration process established by EOS.IO. - -### Description - -The `$action` action... - -### $input_header and Input $type_header - -The `$action` action requires the following `$input` and `input $type`: - -| Action | Input | Input Type | -|:--|:--|:--| diff --git a/scripts/abi_to_rc/rc-overview-template.md b/scripts/abi_to_rc/rc-overview-template.md deleted file mode 100644 index 1f197b1c08e..00000000000 --- a/scripts/abi_to_rc/rc-overview-template.md +++ /dev/null @@ -1,14 +0,0 @@ -# Smart Contract - `$contract` - -This is an overview of the actions for the `$contract` smart contract. This Contract is legally binding and can be used in the event of a dispute. Disputes shall be settled through the standard arbitration process established by EOS.IO. - -### Description - -The `$contract` contract... - -### $action_header, $input_header and Input $type_header - -The table below contains the `$action`, `$input` and `input $type` for the `$contract` contract. - -| Action | Input | Input Type | -|:--|:--|:--| diff --git a/scripts/abigen.sh b/scripts/abigen.sh deleted file mode 100755 index eb5cce98357..00000000000 --- a/scripts/abigen.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -if (( $# < 3 )); then - echo "$0 SOURCE_DIR BUILD_DIR ARGS..." - exit 0 -fi - -function get_absolute_dir_path() { - pushd $1 > /dev/null - echo $PWD - popd > /dev/null -} - -SOURCE_DIR=$(get_absolute_dir_path $1) - -BUILD_DIR=$2 - -shift; shift - -#echo "Source directory: ${SOURCE_DIR}" - -eval "${BUILD_DIR}/programs/eosio-abigen/eosio-abigen -extra-arg=--std=c++14 -extra-arg=--target=wasm32 -extra-arg=\"-I${SOURCE_DIR}/contracts/libc++/upstream/include\" -extra-arg=\"-I${SOURCE_DIR}/contracts/musl/upstream/include\" -extra-arg=\"-I${SOURCE_DIR}/externals/magic_get/include\" -extra-arg=\"-I${SOURCE_DIR}/contracts\" $@" diff --git a/scripts/boost.rb b/scripts/boost.rb new file mode 100644 index 00000000000..a322acbdd11 --- /dev/null +++ b/scripts/boost.rb @@ -0,0 +1,131 @@ +class Boost < Formula + desc "Collection of portable C++ source libraries" + homepage "https://www.boost.org/" + revision 1 + head "https://github.com/boostorg/boost.git" + + stable do + url "https://dl.bintray.com/boostorg/release/1.67.0/source/boost_1_67_0.tar.bz2" + sha256 "2684c972994ee57fc5632e03bf044746f6eb45d4920c343937a465fd67a5adba" + + # Remove for > 1.67.0 + # Fix "error: no member named 'next' in namespace 'boost'" + # Upstream commit from 1 Dec 2017 "Add #include ; no + # longer in utility.hpp" + patch :p2 do + url "https://github.com/boostorg/lockfree/commit/12726cd.patch?full_index=1" + sha256 "f165823d961a588b622b20520668b08819eb5fdc08be7894c06edce78026ce0a" + end + end + + bottle do + cellar :any + sha256 "265ab8beaa6fa26a7c305ef2e6aec8bd26ca1db105aca0aaca028f32c5245a90" => :high_sierra + sha256 "567f3e9a294413c1701b698d666a521cfdeec846e256c6e66576d5b70eb26f08" => :sierra + sha256 "3f3f687a620f656fe2ac54f01306e00e6bbc0e9797db284a8d272648d427e640" => :el_capitan + end + + option "with-icu4c", "Build regexp engine with icu support" + option "without-single", "Disable building single-threading variant" + option "without-static", "Disable building static library variant" + + deprecated_option "with-icu" => "with-icu4c" + + depends_on "icu4c" => :optional + + def install + # Force boost to compile with the desired compiler + open("user-config.jam", "a") do |file| + file.write "using darwin : : #{ENV.cxx} ;\n" + end + + # libdir should be set by --prefix but isn't + bootstrap_args = ["--prefix=#{prefix}", "--libdir=#{lib}"] + + if build.with? "icu4c" + icu4c_prefix = Formula["icu4c"].opt_prefix + bootstrap_args << "--with-icu=#{icu4c_prefix}" + else + bootstrap_args << "--without-icu" + end + + # Handle libraries that will not be built. + without_libraries = ["python", "mpi"] + + # Boost.Log cannot be built using Apple GCC at the moment. Disabled + # on such systems. + without_libraries << "log" if ENV.compiler == :gcc + + bootstrap_args << "--without-libraries=#{without_libraries.join(",")}" + + # layout should be synchronized with boost-python and boost-mpi + args = ["--prefix=#{prefix}", + "--libdir=#{lib}", + "-d2", + "-j#{ENV.make_jobs}", + "--layout=tagged", + "--user-config=user-config.jam", + "-sNO_LZMA=1", + "install"] + + if build.with? "single" + args << "threading=multi,single" + else + args << "threading=multi" + end + + if build.with? "static" + args << "link=shared,static" + else + args << "link=shared" + end + + # Trunk starts using "clang++ -x c" to select C compiler which breaks C++11 + # handling using ENV.cxx11. Using "cxxflags" and "linkflags" still works. + args << "cxxflags=-std=c++11" + if ENV.compiler == :clang + args << "cxxflags=-stdlib=libc++" << "linkflags=-stdlib=libc++" + end + + system "./bootstrap.sh", *bootstrap_args + system "./b2", "headers" + system "./b2", *args + end + + def caveats + s = "" + # ENV.compiler doesn't exist in caveats. Check library availability + # instead. + if Dir["#{lib}/libboost_log*"].empty? + s += <<~EOS + Building of Boost.Log is disabled because it requires newer GCC or Clang. + EOS + end + + s + end + + test do + (testpath/"test.cpp").write <<~EOS + #include + #include + #include + #include + using namespace boost::algorithm; + using namespace std; + + int main() + { + string str("a,b"); + vector strVec; + split(strVec, str, is_any_of(",")); + assert(strVec.size()==2); + assert(strVec[0]=="a"); + assert(strVec[1]=="b"); + return 0; + } + EOS + system ENV.cxx, "test.cpp", "-std=c++1y", "-L#{lib}", "-lboost_system", "-o", "test" + system "./test" + end +end diff --git a/scripts/eosio_build_amazon.sh b/scripts/eosio_build_amazon.sh index b32d2a51315..ea690973846 100644 --- a/scripts/eosio_build_amazon.sh +++ b/scripts/eosio_build_amazon.sh @@ -56,11 +56,11 @@ if [[ "${OS_NAME}" == "Amazon Linux AMI" ]]; then DEP_ARRAY=( git gcc72.x86_64 gcc72-c++.x86_64 autoconf automake libtool make bzip2 \ bzip2-devel.x86_64 openssl-devel.x86_64 gmp-devel.x86_64 libstdc++72.x86_64 \ - python27.x86_64 python36-devel.x86_64 libedit-devel.x86_64 doxygen.x86_64 graphviz.x86_64) + python27.x86_64 python27-devel.x86_64 python36-devel.x86_64 libedit-devel.x86_64 doxygen.x86_64 graphviz.x86_64) else - DEP_ARRAY=( git gcc.x86_64 gcc-c++.x86_64 autoconf automake libtool make bzip2 \ - bzip2-devel.x86_64 openssl-devel.x86_64 gmp-devel.x86_64 libstdc++.x86_64 \ - python3.x86_64 python3-devel.x86_64 libedit-devel.x86_64 doxygen.x86_64 graphviz.x86_64) + DEP_ARRAY=( git gcc gcc-c++ autoconf automake libtool make bzip2 \ + bzip2-devel openssl-devel gmp-devel libstdc++ \ + python3 python3-devel python-devel libedit-devel doxygen graphviz) fi COUNT=1 DISPLAY="" @@ -70,7 +70,7 @@ for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); do - pkg=$( sudo "$YUM" info "${DEP_ARRAY[$i]}" 2>/dev/null | grep Repo | tr -s ' ' | cut -d: -f2 | sed 's/ //g' ) + pkg=$("$YUM" info "${DEP_ARRAY[$i]}" 2>/dev/null | grep Repo | tr -s ' ' | cut -d: -f2 | sed 's/ //g' ) if [ "$pkg" != "installed" ]; then DEP=$DEP" ${DEP_ARRAY[$i]} " @@ -87,6 +87,7 @@ printf "\\n\\tThe following dependencies are required to install EOSIO.\\n" printf "\\n\\t${DISPLAY}\\n\\n" printf "\\tDo you wish to install these dependencies?\\n" + if is_noninteractive; then exec <<< "1"; fi select yn in "Yes" "No"; do case $yn in [Yy]* ) diff --git a/scripts/eosio_build_centos.sh b/scripts/eosio_build_centos.sh index 06fff117032..49debdf68e8 100644 --- a/scripts/eosio_build_centos.sh +++ b/scripts/eosio_build_centos.sh @@ -63,6 +63,7 @@ SCL=$( rpm -qa | grep -E 'centos-release-scl-[0-9].*' ) if [ -z "${SCL}" ]; then printf "\\t - Do you wish to install and enable this repository?\\n" + if is_noninteractive; then exec <<< "1"; fi select yn in "Yes" "No"; do case $yn in [Yy]* ) @@ -87,6 +88,7 @@ DEVTOOLSET=$( rpm -qa | grep -E 'devtoolset-7-[0-9].*' ) if [ -z "${DEVTOOLSET}" ]; then printf "\\tDo you wish to install devtoolset-7?\\n" + if is_noninteractive; then exec <<< "1"; fi select yn in "Yes" "No"; do case $yn in [Yy]* ) @@ -118,6 +120,7 @@ PYTHON33=$( rpm -qa | grep -E 'python33-[0-9].*' ) if [ -z "${PYTHON33}" ]; then printf "\\tDo you wish to install python33?\\n" + if is_noninteractive; then exec <<< "1"; fi select yn in "Yes" "No"; do case $yn in [Yy]* ) @@ -152,7 +155,7 @@ for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); do - pkg=$( sudo "${YUM}" info "${DEP_ARRAY[$i]}" 2>/dev/null | grep Repo | tr -s ' ' | cut -d: -f2 | sed 's/ //g' ) + pkg=$( "${YUM}" info "${DEP_ARRAY[$i]}" 2>/dev/null | grep Repo | tr -s ' ' | cut -d: -f2 | sed 's/ //g' ) if [ "$pkg" != "installed" ]; then DEP=$DEP" ${DEP_ARRAY[$i]} " DISPLAY="${DISPLAY}${COUNT}. ${DEP_ARRAY[$i]}\\n\\t" @@ -170,6 +173,7 @@ printf "\\tThe following dependencies are required to install EOSIO.\\n" printf "\\t${DISPLAY}\\n\\n" printf "\\tDo you wish to install these dependencies?\\n" + if is_noninteractive; then exec <<< "1"; fi select yn in "Yes" "No"; do case $yn in [Yy]* ) diff --git a/scripts/eosio_build_darwin.sh b/scripts/eosio_build_darwin.sh index f3ee81cf467..bc4a20ebd58 100644 --- a/scripts/eosio_build_darwin.sh +++ b/scripts/eosio_build_darwin.sh @@ -70,6 +70,7 @@ then printf "\\tHomebrew must be installed to compile EOS.IO\\n\\n" printf "\\tDo you wish to install Home Brew?\\n" + if is_noninteractive; then exec <<< "1"; fi select yn in "Yes" "No"; do case "${yn}" in [Yy]* ) @@ -138,6 +139,7 @@ printf "\\n\\tThe following dependencies are required to install EOSIO.\\n" printf "\\n\\t${DISPLAY}\\n\\n" echo "Do you wish to install these packages?" + if is_noninteractive; then exec <<< "1"; fi select yn in "Yes" "No"; do case $yn in [Yy]* ) @@ -159,13 +161,12 @@ printf "\\tExiting now.\\n\\n" exit 1; fi - if [[ "$DEP" == "llvm@4" ]]; then - "${BREW}" unlink ${DEP} - elif ! "${BREW}" unlink ${DEP} && "${BREW}" link --force ${DEP} - then - printf "\\tHomebrew exited with the above errors.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; + if [ $PERMISSION_GETTEXT -eq 1 ]; then + if ! "${BREW}" link --force gettext; then + printf "\\tHomebrew exited with the above errors.\\n" + printf "\\tExiting now.\\n\\n" + exit 1; + fi fi break;; [Nn]* ) echo "User aborting installation of required dependencies, Exiting now."; exit;; @@ -184,6 +185,7 @@ printf "\\tFound Boost Version %s.\\n" "${BVERSION}" printf "\\tEOS.IO requires Boost version 1.67.\\n" printf "\\tWould you like to uninstall version %s and install Boost version 1.67.\\n" "${BVERSION}" + if is_noninteractive; then exec <<< "1"; fi select yn in "Yes" "No"; do case $yn in [Yy]* ) @@ -218,7 +220,7 @@ done fi printf "\\tInstalling boost libraries.\\n" - if ! "${BREW}" install https://raw.githubusercontent.com/Homebrew/homebrew-core/f946d12e295c8a27519b73cc810d06593270a07f/Formula/boost.rb + if ! "${BREW}" install "${SOURCE_DIR}/scripts/boost.rb" then printf "\\tUnable to install boost 1.67 libraries at this time. 0\\n" printf "\\tExiting now.\\n\\n" diff --git a/scripts/eosio_build_fedora.sh b/scripts/eosio_build_fedora.sh index 238781f2f8f..b608cf00978 100644 --- a/scripts/eosio_build_fedora.sh +++ b/scripts/eosio_build_fedora.sh @@ -69,7 +69,7 @@ for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); do - pkg=$( sudo "${YUM}" info "${DEP_ARRAY[$i]}" 2>/dev/null | grep Repo | tr -s ' ' | cut -d: -f2 | sed 's/ //g' ) + pkg=$( "${YUM}" info "${DEP_ARRAY[$i]}" 2>/dev/null | grep Repo | tr -s ' ' | cut -d: -f2 | sed 's/ //g' ) if [ "$pkg" != "@System" ]; then DEP=$DEP" ${DEP_ARRAY[$i]} " @@ -86,6 +86,7 @@ printf "\\n\\tThe following dependencies are required to install EOSIO.\\n" printf "\\n\\t${DISPLAY}\\n\\n" printf "\\tDo you wish to install these dependencies?\\n" + if is_noninteractive; then exec <<< "1"; fi select yn in "Yes" "No"; do case $yn in [Yy]* ) diff --git a/scripts/eosio_build_ubuntu.sh b/scripts/eosio_build_ubuntu.sh index ab3e8823d8e..373093e237d 100644 --- a/scripts/eosio_build_ubuntu.sh +++ b/scripts/eosio_build_ubuntu.sh @@ -91,6 +91,7 @@ printf "\\n\\tThe following dependencies are required to install EOSIO.\\n" printf "\\n\\t${DISPLAY}\\n\\n" printf "\\tDo you wish to install these packages?\\n" + if is_noninteractive; then exec <<< "1"; fi select yn in "Yes" "No"; do case $yn in [Yy]* ) diff --git a/scripts/generate_deb.sh b/scripts/generate_deb.sh index 9b7cb9a54f0..9af16c069f3 100644 --- a/scripts/generate_deb.sh +++ b/scripts/generate_deb.sh @@ -1,24 +1,28 @@ #! /bin/bash -NAME="${PROJECT}_${VERSION}-1_amd64" PREFIX="usr" SPREFIX=${PREFIX} SUBPREFIX="opt/${PROJECT}/${VERSION}" SSUBPREFIX="opt\/${PROJECT}\/${VERSION}" +RELEASE="${VERSION_SUFFIX}" + +# default release to "1" if there is no suffix +if [[ -z $RELEASE ]]; then + RELEASE="1" +fi + +NAME="${PROJECT}_${VERSION_NO_SUFFIX}-${RELEASE}_amd64" -DEPS_STR="" -for dep in "${DEPS[@]}"; do - DEPS_STR="${DEPS_STR} Depends: ${dep}" -done mkdir -p ${PROJECT}/DEBIAN -echo "Package: ${PROJECT} -Version: ${VERSION} +chmod 0755 ${PROJECT}/DEBIAN +echo "Package: ${PROJECT} +Version: ${VERSION_NO_SUFFIX}-${RELEASE} Section: devel Priority: optional -Depends: libbz2-dev (>= 1.0), libssl-dev (>= 1.0), libgmp3-dev, build-essential, libicu-dev, zlib1g-dev +Depends: libbz2-dev (>= 1.0), libssl-dev (>= 1.0), libgmp3-dev, build-essential, libicu-dev, zlib1g-dev, libtinfo5 Architecture: amd64 -Homepage: ${URL} -Maintainer: ${EMAIL} +Homepage: ${URL} +Maintainer: ${EMAIL} Description: ${DESC}" &> ${PROJECT}/DEBIAN/control export PREFIX @@ -28,7 +32,10 @@ export SSUBPREFIX bash generate_tarball.sh ${NAME}.tar.gz -tar -xvzf ${NAME}.tar.gz -C ${PROJECT} -dpkg-deb --build ${PROJECT} +tar -xvzf ${NAME}.tar.gz -C ${PROJECT} +dpkg-deb --build ${PROJECT} +BUILDSTATUS=$? mv ${PROJECT}.deb ${NAME}.deb rm -r ${PROJECT} + +exit $BUILDSTATUS diff --git a/scripts/generate_package.sh.in b/scripts/generate_package.sh.in index 909598cf5d0..9c190ed7d87 100644 --- a/scripts/generate_package.sh.in +++ b/scripts/generate_package.sh.in @@ -2,8 +2,9 @@ VARIANT=$1 -VERSION="@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@" - +VERSION_NO_SUFFIX="@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@" +VERSION_SUFFIX="@VERSION_SUFFIX@" +VERSION="@VERSION_FULL@" BUILD_DIR="@CMAKE_BINARY_DIR@" VENDOR="@VENDOR@" @@ -13,6 +14,8 @@ URL="@URL@" EMAIL="@EMAIL@" export BUILD_DIR +export VERSION_NO_SUFFIX +export VERSION_SUFFIX export VERSION export VENDOR export PROJECT @@ -32,4 +35,9 @@ else echo "Error, unknown package type. Use either ['brew', 'deb', 'rpm']." exit -1 fi + +BUILDSTATUS=$? + rm -r tmp + +exit $BUILDSTATUS diff --git a/scripts/generate_rpm.sh b/scripts/generate_rpm.sh index a35efde71ec..8d7ebf03caa 100644 --- a/scripts/generate_rpm.sh +++ b/scripts/generate_rpm.sh @@ -1,10 +1,17 @@ #! /bin/bash -NAME="${PROJECT}-${VERSION}-1" PREFIX="usr" SPREFIX=${PREFIX} SUBPREFIX="opt/${PROJECT}/${VERSION}" SSUBPREFIX="opt\/${PROJECT}\/${VERSION}" +RELEASE="${VERSION_SUFFIX}" + +# default release to "1" if there is no suffix +if [[ -z $RELEASE ]]; then + RELEASE="1" +fi + +NAME="${PROJECT}-${VERSION_NO_SUFFIX}-${RELEASE}" export PREFIX export SUBPREFIX @@ -26,19 +33,22 @@ echo -e ${PFILES} &> ~/rpmbuild/BUILD/filenames.txt mkdir -p ${PROJECT} echo -e "Name: ${PROJECT} -Version: ${VERSION} +Version: ${VERSION_NO_SUFFIX} License: MIT Vendor: ${VENDOR} Source: ${URL} -Requires: openssl-devel.x86_64, gmp-devel.x86_64, libstdc++-devel.x86_64, bzip2.x86_64, bzip2-devel.x86_64, mongodb.x86_64, mongodb-server.x86_64 +Requires: openssl-devel, gmp-devel, libstdc++-devel, bzip2, bzip2-devel, mongodb, mongodb-server URL: ${URL} Packager: ${VENDOR} <${EMAIL}> Summary: ${DESC} -Release: 1 +Release: ${RELEASE} %description ${DESC} %files -f filenames.txt" &> ${PROJECT}.spec rpmbuild -bb ${PROJECT}.spec +BUILDSTATUS=$? mv ~/rpmbuild/RPMS/x86_64 ./ rm -r ${PROJECT} ~/rpmbuild/BUILD/filenames.txt ${PROJECT}.spec + +exit $BUILDSTATUS diff --git a/scripts/ricardeos/README.md b/scripts/ricardeos/README.md deleted file mode 100644 index cac5023d953..00000000000 --- a/scripts/ricardeos/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Purpose -The `ricardeos.py` imports or exports recardian contracts to and from a contracts abi - -## Import Example -`$ python3 ricardeos.py import /path/to/sorce-contract.abi /path/to/new-smart-contract-abi.abi` - -Running this will scan the directory of the abi for all rc.md files and add them to their respective actions. All files with a path format of *clause*-rc.md will be added to the ricardian_clauses section. You can provide the same name for the source and new smart contract abi, the script will prompt you before overwriting. - -The script will also notify the user of any actions that the script cannot find rc.md files for. - -## Export Example -`$ python3 ricardeos.py export /path/to/sorce-contract.abi` - -Running this will dump the contents of all ricardian contracts: - -Actions will be exported in the following format: `--rc.md` - -Clauses will be exported in the following format: `-clause--rc.md` - -If a file already exists the user will be asked if they wish to overwrite the file diff --git a/scripts/ricardeos/ricardeos.py b/scripts/ricardeos/ricardeos.py deleted file mode 100755 index 1110328a529..00000000000 --- a/scripts/ricardeos/ricardeos.py +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env python3 - -import json -import sys -import os.path -import fnmatch - -def add_ricardian_contracts_to_actions(source_abi_directory, contract_name, abi_actions): - abi_actions_with_ricardian_contracts = [] - - for abi_action in abi_actions: - action_name = abi_action["name"] - contract_action_filename = '{contract_name}-{action_name}-rc.md'.format(contract_name = contract_name, action_name = action_name) - - # check for rc file - rc_contract_path = os.path.join(source_abi_directory, contract_action_filename) - if os.path.exists(rc_contract_path): - print('Importing Contract {contract_action_filename} for {contract_name}:{action_name}'.format( - contract_action_filename = contract_action_filename, - contract_name = contract_name, - action_name = action_name - )) - - with open(rc_contract_path) as contract_file_handle: - contract_contents = contract_file_handle.read() - - abi_action['ricardian_contract'] = contract_contents - else: - print('Did not find recardian contract file {contract_action_filename} for {contract_name}:{action_name}, skipping inclusion'.format( - contract_action_filename = contract_action_filename, - contract_name = contract_name, - action_name = action_name - )) - - abi_actions_with_ricardian_contracts.append(abi_action) - - return abi_actions_with_ricardian_contracts - -def create_ricardian_clauses_list(source_abi_directory, contract_name): - clause_file_pattern = '*-clause*-rc.md' - clause_files = fnmatch.filter(os.listdir(source_abi_directory), clause_file_pattern) - - clause_prefix = 'clause-' - clause_postfix = '-rc.md' - - abi_ricardian_clauses = [] - - for clause_file_name in clause_files: - rc_contract_path = os.path.join(source_abi_directory, clause_file_name) - with open(rc_contract_path) as contract_file_handle: - contract_contents = contract_file_handle.read() - - start_of_clause_id = clause_file_name.index( clause_prefix ) + len( clause_prefix ) - end_of_clause_id = clause_file_name.rindex(clause_postfix, start_of_clause_id) - - clause_id = clause_file_name[start_of_clause_id:end_of_clause_id] - - abi_ricardian_clauses.append({ - 'id': clause_id, - 'body': contract_contents - }) - - return abi_ricardian_clauses - -def add_ricardian_contracts_to_abi(source_abi, output_abi): - source_abi_directory = os.path.dirname(source_abi) - contract_name = os.path.split(source_abi)[1].rpartition(".")[0] - - print('Creating {output_abi} with ricardian contracts included'.format(output_abi = output_abi)) - - with open(source_abi, 'r') as source_abi_file: - source_abi_json = json.load(source_abi_file) - - source_abi_json['actions'] = add_ricardian_contracts_to_actions(source_abi_directory, contract_name, source_abi_json['actions']) - source_abi_json['ricardian_clauses'] = create_ricardian_clauses_list(source_abi_directory, contract_name) - - with open(output_abi, 'w') as output_abi_file: - json.dump(source_abi_json, output_abi_file, indent=2) - -def import_ricardian_to_abi(source_abi, output_abi): - if not os.path.exists(source_abi): - print('Source ABI not found in {source_abi}'.format(source_abi = source_abi)) - sys.exit(0) - - if os.path.exists(output_abi): - overwrite_prompt_response = input('Output ABI {output_abi} already exists, do you want to proceed? (y|n): '.format(output_abi = output_abi)) - if overwrite_prompt_response == 'y': - print('Overwriting existing output abi') - add_ricardian_contracts_to_abi(source_abi, output_abi) - sys.exit(0) - else: - print('User aborted, not overwriting existing abi') - sys.exit(0) - else: - add_ricardian_contracts_to_abi(source_abi, output_abi) - -def write_rc_file(path, filename, content): - output_filename = os.path.join(path, filename) - write_file = True - - if os.path.exists(output_filename): - overwrite_prompt_response = input('Output rc {output_filename} already exists, do you want to proceed? (y|n): '.format(output_filename = output_filename)) - if overwrite_prompt_response == 'y': - print('Overwriting existing output rc') - elif overwrite_prompt_response == 'n': - print('Skipping overwrite of {output_filename}'.format(output_filename = output_filename)) - write_file = False - - if write_file: - with open(output_filename, 'w') as text_file: - print(content, file=text_file) - - print('Wrote {output_filename}'.format(output_filename = output_filename)) - -def export_ricardian_from_abi(source_abi): - source_abi_directory = os.path.dirname(source_abi) - contract_name = os.path.split(source_abi)[1].rpartition(".")[0] - - if not os.path.exists(source_abi): - print('Source ABI not found in {source_abi}'.format(source_abi = source_abi)) - sys.exit(0) - - with open(source_abi, 'r') as source_abi_file: - source_abi_json = json.load(source_abi_file) - - for abi_action in source_abi_json['actions']: - output_action_rc_file_name = '{contract_name}-{action_name}-rc.md'.format(contract_name = contract_name, action_name = abi_action['name']) - write_rc_file(source_abi_directory, output_action_rc_file_name, abi_action['ricardian_contract']) - - for abi_clause in source_abi_json['ricardian_clauses']: - output_clause_rc_file_name = '{contract_name}-clause-{clause_id}-rc.md'.format(contract_name = contract_name, clause_id = abi_clause['id']) - write_rc_file(source_abi_directory, output_clause_rc_file_name, abi_clause['body']) - -def main(): - if len(sys.argv) == 1: - print('Please specify an operation of export or import: ./ricardeos.py ') - sys.exit(1) - - if sys.argv[1] == 'import': - if len(sys.argv) != 4: - print('Please specify a source and destination abi:') - print('Usage: ./ricardeos.py import /eos/contracts/contract/mycontract.abi /eos/contracts/contract/withricardian-mycontract.abi') - - sys.exit(0) - else: - import_ricardian_to_abi(sys.argv[2], sys.argv[3]) - - sys.exit(0) - elif sys.argv[1] == 'export': - if len(sys.argv) != 3: - print('Please specify a source abi:') - print('Usage: ./ricardeos.py export /eos/contracts/contract/mycontract.abi') - - sys.exit(0) - else: - export_ricardian_from_abi(sys.argv[2]) - - sys.exit(0) - - else: - print('Operation not recognized only import and export operations are supported') - -if __name__ == '__main__': - main() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ad77d850285..c88caa1f995 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,12 +16,11 @@ include_directories("${CMAKE_SOURCE_DIR}/plugins/wallet_plugin/include") file(GLOB UNIT_TESTS "*.cpp") add_executable( plugin_test ${UNIT_TESTS} ${WASM_UNIT_TESTS} ) -target_link_libraries( plugin_test eosio_testing eosio_chain chainbase eos_utilities chain_plugin wallet_plugin abi_generator fc ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( plugin_test eosio_testing eosio_chain chainbase chain_plugin wallet_plugin fc ${PLATFORM_SPECIFIC_LIBS} ) target_include_directories( plugin_test PUBLIC ${CMAKE_SOURCE_DIR}/plugins/net_plugin/include ${CMAKE_SOURCE_DIR}/plugins/chain_plugin/include ) -add_dependencies(plugin_test asserter test_api test_api_mem test_api_db test_api_multi_index proxy identity identity_test stltest infinite eosio.system eosio.token eosio.bios test.inline multi_index_test noop eosio.msig) # configure_file(${CMAKE_CURRENT_SOURCE_DIR}/core_symbol.py.in ${CMAKE_CURRENT_BINARY_DIR}/core_symbol.py) @@ -87,6 +86,8 @@ add_test(NAME nodeos_sanity_bnet_lr_test COMMAND tests/nodeos_run_test.py -v --s set_property(TEST nodeos_sanity_bnet_lr_test PROPERTY LABELS long_running_tests) add_test(NAME nodeos_run_check_lr_test COMMAND tests/nodeos_run_test.py -v --clean-run --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST nodeos_run_check_lr_test PROPERTY LABELS long_running_tests) +add_test(NAME nodeos_remote_lr_test COMMAND tests/nodeos_run_remote_test.py -v --clean-run --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +set_property(TEST nodeos_remote_lr_test PROPERTY LABELS long_running_tests) #add_test(NAME distributed_transactions_lr_test COMMAND tests/distributed-transactions-test.py -d 2 -p 21 -n 21 -v --clean-run --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) #set_property(TEST distributed_transactions_lr_test PROPERTY LABELS long_running_tests) diff --git a/tests/Cluster.py b/tests/Cluster.py index 070edd9b3ba..06a5357e9af 100644 --- a/tests/Cluster.py +++ b/tests/Cluster.py @@ -126,6 +126,9 @@ def launch(self, pnodes=1, totalNodes=1, prodCount=1, topo="mesh", p2pPlugin="ne if len(self.nodes) > 0: raise RuntimeError("Cluster already running.") + if pnodes > totalNodes: + raise RuntimeError("totalNodes (%d) must be equal to or greater than pnodes(%d)." % (totalNodes, pnodes)) + if self.walletMgr is None: self.walletMgr=WalletMgr(True) @@ -893,7 +896,7 @@ def bios_bootstrap(totalNodes, biosHost, biosPort, walletMgr, silent=False): contract="eosio.token" action="transfer" for name, keys in producerKeys.items(): - data="{\"from\":\"eosio\",\"to\":\"%s\",\"quantity\":\"%s\",\"memo\":\"%s\"}" % (name, initialFunds, "init transfer") + data="{\"from\":\"eosio\",\"to\":\"%s\",\"quantity\":\"%s\",\"memo\":\"%s\"}" % (name, initialFunds, "init eosio transfer") opts="--permission eosio@active" if name != "eosio": trans=biosNode.pushMessage(contract, action, data, opts) diff --git a/tests/Node.py b/tests/Node.py index 82d6581bb02..5fc4e95dcce 100644 --- a/tests/Node.py +++ b/tests/Node.py @@ -259,14 +259,20 @@ def getBlock(self, blockNum, silentErrors=False, exitOnError=False): cmd="%s %s" % (Utils.MongoPath, self.mongoEndpointArgs) subcommand='db.blocks.findOne( { "block_num": %d } )' % (blockNum) if Utils.Debug: Utils.Print("cmd: echo '%s' | %s" % (subcommand, cmd)) + start=time.perf_counter() try: block=Node.runMongoCmdReturnJson(cmd.split(), subcommand, exitOnError=exitOnError) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) + if block is not None: return block except subprocess.CalledProcessError as ex: if not silentErrors: + end=time.perf_counter() msg=ex.output.decode("utf-8") - errorMsg="Exception during get db node get block. %s" % (msg) + errorMsg="Exception during get db node get block. cmd Duration: %.3f sec. %s" % (end-start, msg) if exitOnError: Utils.cmdError(errorMsg) Utils.errorExit(errorMsg) @@ -280,14 +286,19 @@ def getBlockByIdMdb(self, blockId, silentErrors=False): cmd="%s %s" % (Utils.MongoPath, self.mongoEndpointArgs) subcommand='db.blocks.findOne( { "block_id": "%s" } )' % (blockId) if Utils.Debug: Utils.Print("cmd: echo '%s' | %s" % (subcommand, cmd)) + start=time.perf_counter() try: trans=Node.runMongoCmdReturnJson(cmd.split(), subcommand) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) if trans is not None: return trans except subprocess.CalledProcessError as ex: if not silentErrors: + end=time.perf_counter() msg=ex.output.decode("utf-8") - Utils.Print("ERROR: Exception during db get block by id. %s" % (msg)) + Utils.Print("ERROR: Exception during db get block by id. cmd Duration: %.3f sec. %s" % (end-start, msg)) return None return None @@ -360,13 +371,18 @@ def getTransactionMdb(self, transId, silentErrors=False, exitOnError=False): #subcommand='db.Transactions.findOne( { $and : [ { "trx_id": "%s" }, {"irreversible":true} ] } )' % (transId) subcommand='db.transactions.findOne( { "trx_id": "%s" } )' % (transId) if Utils.Debug: Utils.Print("cmd: echo '%s' | %s" % (subcommand, cmd)) + start=time.perf_counter() try: trans=Node.runMongoCmdReturnJson(cmd.split(), subcommand, exitOnError=exitOnError) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) if trans is not None: return trans except subprocess.CalledProcessError as ex: + end=time.perf_counter() msg=ex.output.decode("utf-8") - errorMsg="Exception during get db node get trans in mongodb with transaction id=%s. %s" % (transId,msg) + errorMsg="Exception during get db node get trans in mongodb with transaction id=%s. cmd Duration: %.3f sec. %s" % (transId, end-start, msg) if exitOnError: Utils.cmdError("" % (errorMsg)) Utils.errorExit("Failed to retrieve transaction in mongodb for transaction id=%s" % (transId)) @@ -548,15 +564,20 @@ def getEosAccountFromDb(self, name, exitOnError=False): try: timeout = 3 for i in range(0,(int(60/timeout) - 1)): + start=time.perf_counter() trans=Node.runMongoCmdReturnJson(cmd.split(), subcommand, exitOnError=exitOnError) if trans is not None: + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) return trans time.sleep(timeout) return trans except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") if exitOnError: - Utils.cmdError("Exception during get account from db for %s. %s" % (name, msg)) + end=time.perf_counter() + Utils.cmdError("Exception during get account from db for %s. cmd Duration: %.3f sec. %s" % (name, end-start, msg)) Utils.errorExit("Failed during get account from db for %s. %s" % (name, msg)) Utils.Print("ERROR: Exception during get account from db for %s. %s" % (name, msg)) @@ -675,12 +696,17 @@ def transferFunds(self, source, destination, amountStr, memo="memo", force=False s=" ".join(cmdArr) if Utils.Debug: Utils.Print("cmd: %s" % (s)) trans=None + start=time.perf_counter() try: trans=Utils.runCmdArrReturnJson(cmdArr) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) self.trackCmdTransaction(trans) except subprocess.CalledProcessError as ex: + end=time.perf_counter() msg=ex.output.decode("utf-8") - Utils.Print("ERROR: Exception during funds transfer. %s" % (msg)) + Utils.Print("ERROR: Exception during funds transfer. cmd Duration: %.3f sec. %s" % (end-start, msg)) if exitOnError: Utils.cmdError("could not transfer \"%s\" from %s to %s" % (amountStr, source, destination)) Utils.errorExit("Failed to transfer \"%s\" from %s to %s" % (amountStr, source, destination)) @@ -784,13 +810,18 @@ def getActionsMdb(self, account, pos=-1, offset=-1, exitOnError=False): cmd="%s %s" % (Utils.MongoPath, self.mongoEndpointArgs) subcommand='db.action_traces.find({$or: [{"act.data.from":"%s"},{"act.data.to":"%s"}]}).sort({"_id":%d}).limit(%d)' % (account.name, account.name, pos, abs(offset)) if Utils.Debug: Utils.Print("cmd: echo '%s' | %s" % (subcommand, cmd)) + start=time.perf_counter() try: actions=Node.runMongoCmdReturnJson(cmd.split(), subcommand, exitOnError=exitOnError) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) if actions is not None: return actions except subprocess.CalledProcessError as ex: + end=time.perf_counter() msg=ex.output.decode("utf-8") - errorMsg="Exception during get db actions. %s" % (msg) + errorMsg="Exception during get db actions. cmd Duration: %.3f sec. %s" % (end-start, msg) if exitOnError: Utils.cmdError(errorMsg) Utils.errorExit(errorMsg) @@ -834,8 +865,12 @@ def getAccountEosBalance(self, scope): def getAccountCodeHash(self, account): cmd="%s %s get code %s" % (Utils.EosClientPath, self.eosClientArgs(), account) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) + start=time.perf_counter() try: retStr=Utils.checkOutput(cmd.split()) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) #Utils.Print ("get code> %s"% retStr) p=re.compile(r'code\shash: (\w+)\n', re.MULTILINE) m=p.search(retStr) @@ -846,8 +881,9 @@ def getAccountCodeHash(self, account): return m.group(1) except subprocess.CalledProcessError as ex: + end=time.perf_counter() msg=ex.output.decode("utf-8") - Utils.Print("ERROR: Exception during code hash retrieval. %s" % (msg)) + Utils.Print("ERROR: Exception during code hash retrieval. cmd Duration: %.3f sec. %s" % (end-start, msg)) return None # publish contract and return transaction as json object @@ -857,13 +893,18 @@ def publishContract(self, account, contractDir, wasmFile, abiFile, waitForTransB cmd += "" if abiFile is None else (" " + abiFile) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) trans=None + start=time.perf_counter() try: trans=Utils.runCmdReturnJson(cmd, trace=False) self.trackCmdTransaction(trans) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) except subprocess.CalledProcessError as ex: if not shouldFail: + end=time.perf_counter() msg=ex.output.decode("utf-8") - Utils.Print("ERROR: Exception during code hash retrieval. %s" % (msg)) + Utils.Print("ERROR: Exception during code hash retrieval. cmd Duration: %.3f sec. %s" % (end-start, msg)) return None else: retMap={} @@ -915,14 +956,19 @@ def pushMessage(self, account, action, data, opts, silentErrors=False): cmdArr += opts.split() s=" ".join(cmdArr) if Utils.Debug: Utils.Print("cmd: %s" % (cmdArr)) + start=time.perf_counter() try: trans=Utils.runCmdArrReturnJson(cmdArr) self.trackCmdTransaction(trans, ignoreNonTrans=True) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) return (True, trans) except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") if not silentErrors: - Utils.Print("ERROR: Exception during push message. %s" % (msg)) + end=time.perf_counter() + Utils.Print("ERROR: Exception during push message. cmd Duration=%.3f sec. %s" % (end - start, msg)) return (False, msg) def setPermission(self, account, code, pType, requirement, waitForTransBlock=False, exitOnError=False): @@ -976,6 +1022,7 @@ def processCleosCmd(self, cmd, cmdDesc, silentErrors=True, exitOnError=False, ex else: exitMsg="" trans=None + start=time.perf_counter() try: if returnType==ReturnType.json: trans=Utils.runCmdReturnJson(cmd, silentErrors=silentErrors) @@ -983,10 +1030,15 @@ def processCleosCmd(self, cmd, cmdDesc, silentErrors=True, exitOnError=False, ex trans=Utils.runCmdReturnStr(cmd) else: unhandledEnumType(returnType) + + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) except subprocess.CalledProcessError as ex: if not silentErrors: + end=time.perf_counter() msg=ex.output.decode("utf-8") - errorMsg="Exception during \"%s\". Exception message: %s. %s" % (cmdDesc, msg, exitMsg) + errorMsg="Exception during \"%s\". Exception message: %s. cmd Duration=%.3f sec. %s" % (cmdDesc, msg, end-start, exitMsg) if exitOnError: Utils.cmdError(errorMsg) Utils.errorExit(errorMsg) @@ -1010,6 +1062,7 @@ def killNodeOnProducer(self, producer, whereInSequence, blockType=BlockType.head (self.endpointHttp, producer, whereInSequence, basedOnLib) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) rtn=None + start=time.perf_counter() try: if returnType==ReturnType.json: rtn=Utils.runCmdReturnJson(cmd, silentErrors=silentErrors) @@ -1017,10 +1070,15 @@ def killNodeOnProducer(self, producer, whereInSequence, blockType=BlockType.head rtn=Utils.runCmdReturnStr(cmd) else: unhandledEnumType(returnType) + + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) except subprocess.CalledProcessError as ex: if not silentErrors: + end=time.perf_counter() msg=ex.output.decode("utf-8") - errorMsg="Exception during \"%s\". %s" % (cmd, msg) + errorMsg="Exception during \"%s\". %s. cmd Duration=%.3f sec." % (cmd, msg, end-start) if exitOnError: Utils.cmdError(errorMsg) Utils.errorExit(errorMsg) @@ -1065,12 +1123,17 @@ def getBlockFromDb(self, idx): cmd="%s %s" % (Utils.MongoPath, self.mongoEndpointArgs) subcommand="db.blocks.find().sort({\"_id\":%d}).limit(1).pretty()" % (idx) if Utils.Debug: Utils.Print("cmd: echo \"%s\" | %s" % (subcommand, cmd)) + start=time.perf_counter() try: trans=Node.runMongoCmdReturnJson(cmd.split(), subcommand) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) return trans except subprocess.CalledProcessError as ex: + end=time.perf_counter() msg=ex.output.decode("utf-8") - Utils.Print("ERROR: Exception during get db block. %s" % (msg)) + Utils.Print("ERROR: Exception during get db block. cmd Duration: %.3f sec. %s" % (end-start, msg)) return None def checkPulse(self, exitOnError=False): diff --git a/tests/chain_plugin_tests.cpp b/tests/chain_plugin_tests.cpp index 2b7867a07e9..5a489c255b4 100644 --- a/tests/chain_plugin_tests.cpp +++ b/tests/chain_plugin_tests.cpp @@ -12,15 +12,6 @@ #include #include -#include -#include - -#include -#include - -#include -#include - #include #include diff --git a/tests/chain_tests/proof_tests.cpp b/tests/chain_tests/proof_tests.cpp deleted file mode 100644 index 6240443d77d..00000000000 --- a/tests/chain_tests/proof_tests.cpp +++ /dev/null @@ -1,340 +0,0 @@ -#include -#include -#include -#include - -#ifdef NON_VALIDATING_TEST -#define TESTER tester -#else -#define TESTER validating_tester -#endif - -using namespace eosio; -using namespace eosio::chain; -using namespace eosio::testing; - -struct action_proof_data { - account_name receiver; - scope_name scope; - action_name name; - bytes data; - uint64_t region_id; - uint64_t cycle_index; - vector data_access; -}; -FC_REFLECT(action_proof_data, (receiver)(scope)(name)(data)(region_id)(cycle_index)(data_access)); - - -struct merkle_node { - digest_type digest; - optional left; - optional right; - optional parent; -}; - -digest_type process_merkle(vector& nodes, vector leaf_indices) { - size_t num_nodes = leaf_indices.size(); - size_t base = 0; - - if (num_nodes == 0) { - return digest_type(); - } else if (num_nodes == 1) { - return nodes[leaf_indices.front()].digest; - } - - while (num_nodes > 1) { - size_t new_nodes = (num_nodes / 2) + (num_nodes % 2); - for(size_t idx = 0; idx < new_nodes; idx++) { - size_t l_idx = idx * 2; - size_t r_idx = l_idx + 1; - size_t left = leaf_indices.at(base + l_idx); - if (r_idx >= num_nodes) { - nodes.emplace_back( - merkle_node{ - digest_type::hash(make_canonical_pair(nodes[left].digest, nodes[left].digest)), - left - }); - nodes[left].parent.emplace(nodes.size() - 1); - } else { - size_t right = leaf_indices.at(base + r_idx); - nodes.emplace_back( - merkle_node{ - digest_type::hash(make_canonical_pair(nodes[left].digest, nodes[right].digest)), - left, - right - }); - nodes[left].parent.emplace(nodes.size() - 1); - nodes[right].parent.emplace(nodes.size() - 1); - } - - leaf_indices.emplace_back(nodes.size() - 1); - } - - base += num_nodes; - num_nodes = new_nodes; - } - - return nodes.back().digest; -} - -auto get_proof_path(const vector& nodes, size_t leaf) { - vector path; - digest_type current = nodes[leaf].digest; - while (nodes[leaf].parent.valid()) { - size_t parent = *nodes[leaf].parent; - if (leaf == *nodes[parent].left) { - if (nodes[parent].right.valid()) { - size_t right = *nodes[parent].right; - path.emplace_back(make_canonical_right(nodes[right].digest)); - current = digest_type::hash(make_canonical_pair(nodes[leaf].digest, nodes[right].digest)); - } else { - path.emplace_back(make_canonical_right(nodes[leaf].digest)); - current = digest_type::hash(make_canonical_pair(nodes[leaf].digest, nodes[leaf].digest)); - } - } else { - size_t left = *nodes[parent].left; - path.emplace_back(make_canonical_left(nodes[left].digest)); - current = digest_type::hash(make_canonical_pair(nodes[left].digest, nodes[leaf].digest)); - } - - leaf = parent; - } - - return path; -} - -digest_type apply_path(const digest_type& digest, const vector& path) { - digest_type current = digest; - - for (const auto& p: path ) { - if (is_canonical_left(p)) { - current = digest_type::hash(make_canonical_pair(p, current)); - } else { - current = digest_type::hash(make_canonical_pair(current, p)); - } - } - - return current; -} - -bool proof_is_valid(const digest_type& digest, const vector& path, const digest_type& expected_root) { - return apply_path(digest, path) == expected_root; -} - -BOOST_AUTO_TEST_SUITE(proof_tests) - -BOOST_FIXTURE_TEST_CASE( prove_block_in_chain, validating_tester ) { try { - vector known_blocks; - known_blocks.reserve(100); - block_header last_block_header; - - // register a callback on new blocks to record block information - validating_node->applied_block.connect([&](const block_trace& bt){ - known_blocks.emplace_back(bt.block.id()); - last_block_header = bt.block; - }); - - produce_blocks(100); - return; - vector nodes; - vector ids; - vector block_leaves; - nodes.reserve(100); - ids.reserve(100); - for (const auto& blk_id: known_blocks) { - nodes.emplace_back(merkle_node{blk_id}); - ids.push_back(blk_id); - block_leaves.push_back(nodes.size() - 1); - } - - digest_type block_mroot = process_merkle(nodes, move(block_leaves)); - - BOOST_REQUIRE_EQUAL((std::string)block_mroot, (std::string)merkle(ids)); - - produce_block(); - - BOOST_REQUIRE_EQUAL((std::string)block_mroot, (std::string)last_block_header.block_mroot); - - for (int idx = 0; idx < 100; idx++) { - vector path = get_proof_path(nodes, idx); - - BOOST_REQUIRE_EQUAL(true, proof_is_valid(nodes[idx].digest, path, last_block_header.block_mroot)); - - /** UNCOMMENT TO PRODUCE PROOFS TO STD OUT - std::cout << idx << ":" << std::string(known_blocks.at(idx)) << " = "; - for (const auto& e: path) { - std::cout << std::string(e) << " "; - } - - std::cout << "-> " << std::string(last_block_header.block_mroot) << std::endl; - */ - } - -} FC_LOG_AND_RETHROW() } /// transfer_test - - -struct action_proof_info { - action_trace trace; - - size_t action_leaf; - size_t block_leaf; - - uint32_t cycle_index; - uint32_t region_id; -}; - -/** - * This test case will attempt to allow one account to transfer on behalf - * of another account by updating the active authority. - */ -BOOST_FIXTURE_TEST_CASE( prove_action_in_block, validating_tester ) { try { - vector nodes; - vector block_leaves; - vector known_actions; - map block_action_mroots; - block_header last_block_header; - block_id_type last_block_id; - - // register a callback on new blocks to record block information - validating_node->applied_block.connect([&](const block_trace& bt){ - nodes.emplace_back(merkle_node{bt.block.id()}); - size_t block_leaf = nodes.size() - 1; - block_leaves.push_back(block_leaf); - - vector region_leaves; - - for (uint32_t r_idx = 0; r_idx < bt.region_traces.size(); r_idx++) { - const auto& rt = bt.region_traces.at(r_idx); - - vector shard_leaves; - - for (uint32_t c_idx = 0; c_idx < rt.cycle_traces.size(); c_idx++) { - const auto& ct = rt.cycle_traces.at(c_idx); - - for (const auto& st: ct.shard_traces) { - vector action_leaves; - - for (const auto& tt: st.transaction_traces) { - for (const auto& at: tt.action_traces) { - digest_type::encoder enc; - - auto a_data = action_proof_data { - at.receiver, - at.act.account, - at.act.name, - at.act.data, - tt.region_id, - tt.cycle_index, - at.data_access - }; - fc::raw::pack(enc, a_data); - nodes.emplace_back(merkle_node{enc.result()}); - size_t action_leaf = nodes.size() - 1; - known_actions.emplace_back(action_proof_info{at, action_leaf, block_leaf, c_idx, r_idx }); - action_leaves.emplace_back(action_leaf); - } - } - - if (action_leaves.size() > 0) { - process_merkle(nodes, move(action_leaves)); - } else { - nodes.emplace_back(merkle_node{digest_type()}); - } - shard_leaves.emplace_back(nodes.size() - 1); - } - } - - if (shard_leaves.size() > 0) { - process_merkle(nodes, move(shard_leaves)); - } else { - nodes.emplace_back(merkle_node{digest_type()}); - } - - region_leaves.emplace_back(nodes.size() - 1); - } - - digest_type action_mroot = process_merkle(nodes, move(region_leaves)); - BOOST_REQUIRE_EQUAL((std::string)bt.block.action_mroot, (std::string)action_mroot); - - last_block_header = bt.block; - last_block_id = bt.block.id(); - block_action_mroots[bt.block.id()] = bt.block.action_mroot; - }); - - create_accounts( { N(alice), N(bob), N(carol), N(david), N(elvis) }); - - produce_blocks(50); - - push_dummy(N(alice), "AB"); - push_dummy(N(bob), "BC"); - push_dummy(N(carol), "CD"); - push_dummy(N(david), "DE"); - push_dummy(N(elvis), "EF"); - - produce_blocks(50); - digest_type block_mroot = process_merkle(nodes, move(block_leaves)); - - produce_block(); - BOOST_REQUIRE_EQUAL((std::string)block_mroot, (std::string)last_block_header.block_mroot); - - /* UNCOMMENT TO PRODUCE PROOFS TO STDOUT - std::cout << "Best Block ID: " << (std::string)last_block_id << std::endl; - std::cout << " Merkle Root: " << (std::string)last_block_header.block_mroot << std::endl; - - for(const auto& ai : known_actions) { - auto block_path = get_proof_path(nodes, ai.action_leaf); - auto chain_path = get_proof_path(nodes, ai.block_leaf); - - // prove action in block - auto shard_root = apply_path(nodes[ai.action_leaf].digest, block_path); - BOOST_REQUIRE_EQUAL((std::string)shard_root, (std::string)block_action_mroots[nodes[ai.block_leaf].digest]); - - // prove that block is part of the chain - auto expected_block_mroot = apply_path(nodes[ai.block_leaf].digest, chain_path); - BOOST_REQUIRE_EQUAL((std::string)expected_block_mroot, (std::string)last_block_header.block_mroot); - - std::cout << "Proof for Action:" << std::endl; - std::cout << std::setw(14) << "reciever" << ":" << (std::string) ai.trace.receiver << std::endl; - std::cout << std::setw(14) << "scope" << ":" << (std::string) ai.trace.act.scope << std::endl; - std::cout << std::setw(14) << "name" << ":" << (std::string) ai.trace.act.name << std::endl; - std::cout << std::setw(14) << "data" << ":" << fc::json::to_string(ai.trace.act.as()) << std::endl; - std::cout << std::setw(14) << "data_access" << ":" << fc::json::to_string(ai.trace.data_access) << std::endl; - std::cout << std::setw(14) << "region" << ":" << ai.region_id << std::endl; - std::cout << std::setw(14) << "cycle" << ":" << ai.cycle_index << std::endl; - std::cout << std::setw(14) << "block" << ":" << (std::string)nodes[ai.block_leaf].digest << std::endl; - std::cout << std::setw(14) << "am_root" << ":" << (std::string)block_action_mroots[nodes[ai.block_leaf].digest] << std::endl; - std::cout << std::endl; - - auto a_data = action_proof_data { - ai.trace.receiver, - ai.trace.act.scope, - ai.trace.act.name, - ai.trace.act.data, - ai.trace.region_id, - ai.trace.cycle_index, - ai.trace.data_access - }; - auto action_data = fc::raw::pack(a_data); - - std::cout << "Action Hex: " << fc::to_hex(action_data) << std::endl; - std::cout << "Action Hash: " << (std::string)nodes[ai.action_leaf].digest << std::endl; - - std::cout << "Action Path: "; - for (const auto& p: block_path) { - std::cout << (std::string)p << " "; - } - std::cout << std::endl; - - std::cout << "Block Path: "; - for (const auto& p: chain_path) { - std::cout << (std::string)p << " "; - } - std::cout << std::endl; - }*/ - - -} FC_LOG_AND_RETHROW() } - - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/distributed-transactions-remote-test.py b/tests/distributed-transactions-remote-test.py index 1b678f3be03..9e79b352329 100755 --- a/tests/distributed-transactions-remote-test.py +++ b/tests/distributed-transactions-remote-test.py @@ -58,7 +58,7 @@ Print ("producing nodes: %s, non-producing nodes: %d, topology: %s, delay between nodes launch(seconds): %d" % (pnodes, total_nodes-pnodes, topo, delay)) Print("Stand up cluster") - if cluster.launch(pnodes=pnodes, totalNodes=total_nodes, prodCount=prodCount, topo=topo, delay=delay, dontKill=dontKill) is False: + if cluster.launch(pnodes=pnodes, totalNodes=total_nodes, prodCount=prodCount, topo=topo, delay=delay) is False: errorExit("Failed to stand up eos cluster.") Print ("Wait for Cluster stabilization") diff --git a/tests/get_table_tests.cpp b/tests/get_table_tests.cpp index 818ca5562d2..bb332b9a000 100644 --- a/tests/get_table_tests.cpp +++ b/tests/get_table_tests.cpp @@ -12,15 +12,12 @@ #include #include -#include -#include +#include +#include #include #include -#include -#include - #include #include @@ -58,7 +55,7 @@ BOOST_FIXTURE_TEST_CASE( get_scope_test, TESTER ) try { set_abi( N(eosio.token), eosio_token_abi ); produce_blocks(1); - // create currency + // create currency auto act = mutable_variant_object() ("issuer", "eosio") ("maximum_supply", eosio::chain::asset::from_string("1000000000.0000 SYS")); @@ -94,13 +91,13 @@ BOOST_FIXTURE_TEST_CASE( get_scope_test, TESTER ) try { } param.lower_bound = "initb"; - param.upper_bound = "initd"; + param.upper_bound = "initc"; result = plugin.read_only::get_table_by_scope(param); BOOST_REQUIRE_EQUAL(2, result.rows.size()); BOOST_REQUIRE_EQUAL("", result.more); if (result.rows.size() >= 2) { BOOST_REQUIRE_EQUAL(name(N(initb)), result.rows[0].scope); - BOOST_REQUIRE_EQUAL(name(N(initc)), result.rows[1].scope); + BOOST_REQUIRE_EQUAL(name(N(initc)), result.rows[1].scope); } param.limit = 1; @@ -116,9 +113,337 @@ BOOST_FIXTURE_TEST_CASE( get_scope_test, TESTER ) try { param.table = N(invalid); result = plugin.read_only::get_table_by_scope(param); BOOST_REQUIRE_EQUAL(0, result.rows.size()); - BOOST_REQUIRE_EQUAL("", result.more); + BOOST_REQUIRE_EQUAL("", result.more); } FC_LOG_AND_RETHROW() /// get_scope_test -BOOST_AUTO_TEST_SUITE_END() +BOOST_FIXTURE_TEST_CASE( get_table_test, TESTER ) try { + produce_blocks(2); + + create_accounts({ N(eosio.token), N(eosio.ram), N(eosio.ramfee), N(eosio.stake), + N(eosio.bpay), N(eosio.vpay), N(eosio.saving), N(eosio.names) }); + + std::vector accs{N(inita), N(initb)}; + create_accounts(accs); + produce_block(); + + set_code( N(eosio.token), eosio_token_wast ); + set_abi( N(eosio.token), eosio_token_abi ); + produce_blocks(1); + // create currency + auto act = mutable_variant_object() + ("issuer", "eosio") + ("maximum_supply", eosio::chain::asset::from_string("1000000000.0000 SYS")); + push_action(N(eosio.token), N(create), N(eosio.token), act ); + + // issue + for (account_name a: accs) { + push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() + ("to", name(a) ) + ("quantity", eosio::chain::asset::from_string("10000.0000 SYS") ) + ("memo", "") + ); + } + produce_blocks(1); + + // create currency 2 + act = mutable_variant_object() + ("issuer", "eosio") + ("maximum_supply", eosio::chain::asset::from_string("1000000000.0000 AAA")); + push_action(N(eosio.token), N(create), N(eosio.token), act ); + // issue + for (account_name a: accs) { + push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() + ("to", name(a) ) + ("quantity", eosio::chain::asset::from_string("9999.0000 AAA") ) + ("memo", "") + ); + } + produce_blocks(1); + + // create currency 3 + act = mutable_variant_object() + ("issuer", "eosio") + ("maximum_supply", eosio::chain::asset::from_string("1000000000.0000 CCC")); + push_action(N(eosio.token), N(create), N(eosio.token), act ); + // issue + for (account_name a: accs) { + push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() + ("to", name(a) ) + ("quantity", eosio::chain::asset::from_string("7777.0000 CCC") ) + ("memo", "") + ); + } + produce_blocks(1); + + // create currency 3 + act = mutable_variant_object() + ("issuer", "eosio") + ("maximum_supply", eosio::chain::asset::from_string("1000000000.0000 BBB")); + push_action(N(eosio.token), N(create), N(eosio.token), act ); + // issue + for (account_name a: accs) { + push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() + ("to", name(a) ) + ("quantity", eosio::chain::asset::from_string("8888.0000 BBB") ) + ("memo", "") + ); + } + produce_blocks(1); + + // get table: normal case + eosio::chain_apis::read_only plugin(*(this->control), fc::microseconds(INT_MAX)); + eosio::chain_apis::read_only::get_table_rows_params p; + p.code = N(eosio.token); + p.scope = "inita"; + p.table = N(accounts); + p.json = true; + p.index_position = "primary"; + eosio::chain_apis::read_only::get_table_rows_result result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(4, result.rows.size()); + BOOST_REQUIRE_EQUAL(false, result.more); + if (result.rows.size() >= 4) { + BOOST_REQUIRE_EQUAL("9999.0000 AAA", result.rows[0]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("8888.0000 BBB", result.rows[1]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("7777.0000 CCC", result.rows[2]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("10000.0000 SYS", result.rows[3]["balance"].as_string()); + } + + // get table: reverse ordered + p.reverse = true; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(4, result.rows.size()); + BOOST_REQUIRE_EQUAL(false, result.more); + if (result.rows.size() >= 4) { + BOOST_REQUIRE_EQUAL("9999.0000 AAA", result.rows[3]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("8888.0000 BBB", result.rows[2]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("7777.0000 CCC", result.rows[1]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("10000.0000 SYS", result.rows[0]["balance"].as_string()); + } + + // get table: reverse ordered, with ram payer + p.reverse = true; + p.show_payer = true; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(4, result.rows.size()); + BOOST_REQUIRE_EQUAL(false, result.more); + if (result.rows.size() >= 4) { + BOOST_REQUIRE_EQUAL("9999.0000 AAA", result.rows[3]["data"]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("8888.0000 BBB", result.rows[2]["data"]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("7777.0000 CCC", result.rows[1]["data"]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("10000.0000 SYS", result.rows[0]["data"]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("eosio", result.rows[0]["payer"].as_string()); + BOOST_REQUIRE_EQUAL("eosio", result.rows[1]["payer"].as_string()); + BOOST_REQUIRE_EQUAL("eosio", result.rows[2]["payer"].as_string()); + BOOST_REQUIRE_EQUAL("eosio", result.rows[3]["payer"].as_string()); + } + p.show_payer = false; + + // get table: normal case, with bound + p.lower_bound = "BBB"; + p.upper_bound = "CCC"; + p.reverse = false; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(2, result.rows.size()); + BOOST_REQUIRE_EQUAL(false, result.more); + if (result.rows.size() >= 2) { + BOOST_REQUIRE_EQUAL("8888.0000 BBB", result.rows[0]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("7777.0000 CCC", result.rows[1]["balance"].as_string()); + } + + // get table: reverse case, with bound + p.lower_bound = "BBB"; + p.upper_bound = "CCC"; + p.reverse = true; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(2, result.rows.size()); + BOOST_REQUIRE_EQUAL(false, result.more); + if (result.rows.size() >= 2) { + BOOST_REQUIRE_EQUAL("8888.0000 BBB", result.rows[1]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("7777.0000 CCC", result.rows[0]["balance"].as_string()); + } + + // get table: normal case, with limit + p.lower_bound = p.upper_bound = ""; + p.limit = 1; + p.reverse = false; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(1, result.rows.size()); + BOOST_REQUIRE_EQUAL(true, result.more); + if (result.rows.size() >= 1) { + BOOST_REQUIRE_EQUAL("9999.0000 AAA", result.rows[0]["balance"].as_string()); + } + + // get table: reverse case, with limit + p.lower_bound = p.upper_bound = ""; + p.limit = 1; + p.reverse = true; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(1, result.rows.size()); + BOOST_REQUIRE_EQUAL(true, result.more); + if (result.rows.size() >= 1) { + BOOST_REQUIRE_EQUAL("10000.0000 SYS", result.rows[0]["balance"].as_string()); + } + + // get table: normal case, with bound & limit + p.lower_bound = "BBB"; + p.upper_bound = "CCC"; + p.limit = 1; + p.reverse = false; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(1, result.rows.size()); + BOOST_REQUIRE_EQUAL(true, result.more); + if (result.rows.size() >= 1) { + BOOST_REQUIRE_EQUAL("8888.0000 BBB", result.rows[0]["balance"].as_string()); + } + + // get table: reverse case, with bound & limit + p.lower_bound = "BBB"; + p.upper_bound = "CCC"; + p.limit = 1; + p.reverse = true; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(1, result.rows.size()); + BOOST_REQUIRE_EQUAL(true, result.more); + if (result.rows.size() >= 1) { + BOOST_REQUIRE_EQUAL("7777.0000 CCC", result.rows[0]["balance"].as_string()); + } + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( get_table_by_seckey_test, TESTER ) try { + produce_blocks(2); + + create_accounts({ N(eosio.token), N(eosio.ram), N(eosio.ramfee), N(eosio.stake), + N(eosio.bpay), N(eosio.vpay), N(eosio.saving), N(eosio.names) }); + + std::vector accs{N(inita), N(initb), N(initc), N(initd)}; + create_accounts(accs); + produce_block(); + + set_code( N(eosio.token), eosio_token_wast ); + set_abi( N(eosio.token), eosio_token_abi ); + produce_blocks(1); + + // create currency + auto act = mutable_variant_object() + ("issuer", "eosio") + ("maximum_supply", eosio::chain::asset::from_string("1000000000.0000 SYS")); + push_action(N(eosio.token), N(create), N(eosio.token), act ); + + // issue + for (account_name a: accs) { + push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() + ("to", name(a) ) + ("quantity", eosio::chain::asset::from_string("10000.0000 SYS") ) + ("memo", "") + ); + } + produce_blocks(1); + + set_code( config::system_account_name, eosio_system_wast ); + set_abi( config::system_account_name, eosio_system_abi ); + + // bidname + auto bidname = [this]( const account_name& bidder, const account_name& newname, const asset& bid ) { + return push_action( N(eosio), N(bidname), bidder, fc::mutable_variant_object() + ("bidder", bidder) + ("newname", newname) + ("bid", bid) + ); + }; + + bidname(N(inita), N(com), eosio::chain::asset::from_string("10.0000 SYS")); + bidname(N(initb), N(org), eosio::chain::asset::from_string("11.0000 SYS")); + bidname(N(initc), N(io), eosio::chain::asset::from_string("12.0000 SYS")); + bidname(N(initd), N(html), eosio::chain::asset::from_string("14.0000 SYS")); + produce_blocks(1); + + // get table: normal case + eosio::chain_apis::read_only plugin(*(this->control), fc::microseconds(INT_MAX)); + eosio::chain_apis::read_only::get_table_rows_params p; + p.code = N(eosio); + p.scope = "eosio"; + p.table = N(namebids); + p.json = true; + p.index_position = "secondary"; // ordered by high_bid + p.key_type = "i64"; + eosio::chain_apis::read_only::get_table_rows_result result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(4, result.rows.size()); + BOOST_REQUIRE_EQUAL(false, result.more); + if (result.rows.size() >= 4) { + BOOST_REQUIRE_EQUAL("html", result.rows[0]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("initd", result.rows[0]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("140000", result.rows[0]["high_bid"].as_string()); + + BOOST_REQUIRE_EQUAL("io", result.rows[1]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("initc", result.rows[1]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("120000", result.rows[1]["high_bid"].as_string()); + + BOOST_REQUIRE_EQUAL("org", result.rows[2]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("initb", result.rows[2]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("110000", result.rows[2]["high_bid"].as_string()); + + BOOST_REQUIRE_EQUAL("com", result.rows[3]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("inita", result.rows[3]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("100000", result.rows[3]["high_bid"].as_string()); + } + + // reverse search, with show ram payer + p.reverse = true; + p.show_payer = true; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(4, result.rows.size()); + BOOST_REQUIRE_EQUAL(false, result.more); + if (result.rows.size() >= 4) { + BOOST_REQUIRE_EQUAL("html", result.rows[3]["data"]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("initd", result.rows[3]["data"]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("140000", result.rows[3]["data"]["high_bid"].as_string()); + BOOST_REQUIRE_EQUAL("initd", result.rows[3]["payer"].as_string()); + + BOOST_REQUIRE_EQUAL("io", result.rows[2]["data"]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("initc", result.rows[2]["data"]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("120000", result.rows[2]["data"]["high_bid"].as_string()); + BOOST_REQUIRE_EQUAL("initc", result.rows[2]["payer"].as_string()); + + BOOST_REQUIRE_EQUAL("org", result.rows[1]["data"]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("initb", result.rows[1]["data"]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("110000", result.rows[1]["data"]["high_bid"].as_string()); + BOOST_REQUIRE_EQUAL("initb", result.rows[1]["payer"].as_string()); + + BOOST_REQUIRE_EQUAL("com", result.rows[0]["data"]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("inita", result.rows[0]["data"]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("100000", result.rows[0]["data"]["high_bid"].as_string()); + BOOST_REQUIRE_EQUAL("inita", result.rows[0]["payer"].as_string()); + } + + // limit to 1 (get the highest bidname) + p.reverse = false; + p.show_payer = false; + p.limit = 1; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(1, result.rows.size()); + BOOST_REQUIRE_EQUAL(true, result.more); + if (result.rows.size() >= 1) { + BOOST_REQUIRE_EQUAL("html", result.rows[0]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("initd", result.rows[0]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("140000", result.rows[0]["high_bid"].as_string()); + } + + // limit to 1 reverse, (get the lowest bidname) + p.reverse = true; + p.show_payer = false; + p.limit = 1; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(1, result.rows.size()); + BOOST_REQUIRE_EQUAL(true, result.more); + if (result.rows.size() >= 1) { + BOOST_REQUIRE_EQUAL("com", result.rows[0]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("inita", result.rows[0]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("100000", result.rows[0]["high_bid"].as_string()); + } + +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/launcher_test.py b/tests/launcher_test.py index 9179a69b58d..b7d21b41179 100755 --- a/tests/launcher_test.py +++ b/tests/launcher_test.py @@ -52,7 +52,8 @@ cluster.killall(allInstances=killAll) cluster.cleanup() Print("Stand up cluster") - if cluster.launch(pnodes=4, p2pPlugin=p2pPlugin) is False: + pnodes=4 + if cluster.launch(pnodes=pnodes, totalNodes=pnodes, p2pPlugin=p2pPlugin) is False: cmdError("launcher") errorExit("Failed to stand up eos cluster.") else: diff --git a/tests/main.cpp b/tests/main.cpp index ad2b5846210..0644ce80545 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -1,6 +1,6 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in eos/LICENSE */ #include #include diff --git a/tests/nodeos_forked_chain_test.py b/tests/nodeos_forked_chain_test.py index 01115285a6e..1ef2079e878 100755 --- a/tests/nodeos_forked_chain_test.py +++ b/tests/nodeos_forked_chain_test.py @@ -30,7 +30,12 @@ def analyzeBPs(bps0, bps1, expectDivergence): length=len(bps0) firstDivergence=None errorInDivergence=False + analysysPass=0 + bpsStr=None + bpsStr0=None + bpsStr1=None while start < length: + analysysPass+=1 bpsStr=None for i in range(start,length): bp0=bps0[i] diff --git a/tests/nodeos_run_remote_test.py b/tests/nodeos_run_remote_test.py index 6c918f71c64..21e15bb9c72 100755 --- a/tests/nodeos_run_remote_test.py +++ b/tests/nodeos_run_remote_test.py @@ -43,7 +43,7 @@ (pnodes, total_nodes-pnodes, topo, delay)) Print("Stand up cluster") - if cluster.launch(pnodes=pnodes, totalNodes=total_nodes, prodCount=prodCount, topo=topo, delay=delay, onlyBios=onlyBios, dontKill=dontKill) is False: + if cluster.launch(pnodes=pnodes, totalNodes=total_nodes, prodCount=prodCount, topo=topo, delay=delay, onlyBios=onlyBios) is False: errorExit("Failed to stand up eos cluster.") Print ("Wait for Cluster stabilization") diff --git a/tests/nodeos_run_test.py b/tests/nodeos_run_test.py index 37b46613aaf..4196eb58a2b 100755 --- a/tests/nodeos_run_test.py +++ b/tests/nodeos_run_test.py @@ -42,7 +42,7 @@ Utils.Debug=debug localTest=True if server == TestHelper.LOCAL_HOST else False -cluster=Cluster(walletd=True, enableMongo=enableMongo, defproduceraPrvtKey=defproduceraPrvtKey, defproducerbPrvtKey=defproducerbPrvtKey) +cluster=Cluster(host=server, port=port, walletd=True, enableMongo=enableMongo, defproduceraPrvtKey=defproduceraPrvtKey, defproducerbPrvtKey=defproducerbPrvtKey) walletMgr=WalletMgr(True, port=walletPort) testSuccessful=False killEosInstances=not dontKill diff --git a/tests/p2p_tests/fuzz_test_generic.sh b/tests/p2p_tests/fuzz_test_generic.sh deleted file mode 100644 index ae913565c86..00000000000 --- a/tests/p2p_tests/fuzz_test_generic.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -# -# This script captures the generic fuzz testing to which -# net_plugin has been subjected. It typically results in -# message buffers in excess of 1 gigabyte. -# -if ! pgrep nodeos > /dev/null; then - echo "Run nodeos with net_plugin configured for port 9876." - exit 1 -fi -for i in `seq 1 10000`; do netcat localhost 9876 < /dev/urandom; done diff --git a/tests/p2p_tests/pump/run_test.pl b/tests/p2p_tests/pump/run_test.pl deleted file mode 100755 index 11e467a5d2e..00000000000 --- a/tests/p2p_tests/pump/run_test.pl +++ /dev/null @@ -1,285 +0,0 @@ -#!/usr/bin/perl - -use strict; -use Getopt::Long; -use Env; -use File::Basename; -use File::copy; -use File::Spec; -use File::Path; -use Cwd; - -my $eos_home = defined $ENV{EOS_HOME} ? $ENV{EOS_HOME} : getcwd; -my $eosd = $eos_home . "/programs/eosd/eosd"; -my $eosc = $eos_home . "/programs/eosc/eosc"; - -my $nodes = defined $ENV{EOS_TEST_RING} ? $ENV{EOS_TEST_RING} : "1"; -my $pnodes = defined $ENV{EOS_TEST_PRODUCERS} ? $ENV{EOS_TEST_PRODUCERS} : "1"; - -my $prods = 21; -my $genesis = "$eos_home/genesis.json"; -my $http_port_base = 8888; -my $p2p_port_base = 9876; -my $data_dir_base = "tdn"; -my $hostname = "127.0.0.1"; -my $first_pause = 0; -my $launch_pause = 0; -my $run_duration = 60; -my $topo = "ring"; -my $override_gts = ""; -my $no_delay=0; -my $test=1; - -if (!GetOptions("nodes=i" => \$nodes, - "first-pause=i" => \$first_pause, - "launch-pause=i" => \$launch_pause, - "duration=i" => \$run_duration, - "topo=s" => \$topo, - "test=i" => \$test, - "time-stamp=s" => \$override_gts, - "pnodes=i" => \$pnodes)) { - print "usage: $ARGV[0] [--nodes=] [--pnodes=] [--topo=] [--first-pause=] [--launch-pause=] [--duration=] [--time-stamp=