diff --git a/libraries/client/CMakeLists.txt b/libraries/client/CMakeLists.txt index ea7ec5b5e..a2d8aa77f 100644 --- a/libraries/client/CMakeLists.txt +++ b/libraries/client/CMakeLists.txt @@ -3,6 +3,7 @@ file(GLOB HEADERS "include/bts/client/*.hpp") add_library( bts_client client.cpp messages.cpp + notifier.cpp ${HEADERS} ) target_link_libraries( bts_client diff --git a/libraries/client/client.cpp b/libraries/client/client.cpp index 2ab230757..428091ce2 100644 --- a/libraries/client/client.cpp +++ b/libraries/client/client.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -123,6 +124,7 @@ program_options::variables_map parse_option_variables(int argc, char** argv) "fresh copy of the entire blockchain from the network") ("p2p-port", program_options::value(), "Set network port to listen on") + ("accept-incoming-connections", program_options::value()->default_value(true), "Set to false to reject incoming p2p connections and only establish outbound connections") ("upnp", program_options::value()->default_value(true), "Enable UPNP") ("max-connections", program_options::value(), @@ -149,6 +151,8 @@ program_options::variables_map parse_option_variables(int argc, char** argv) ("input-log", program_options::value< vector >(), "Set log file with CLI commands to execute at startup") ("log-commands", "Log all command input and output") + ("growl", program_options::value()->implicit_value("127.0.0.1"), "Send notifications about potential problems to Growl") + ("growl-password", program_options::value(), "Password for authenticating to a Growl server") ; program_options::variables_map option_variables; @@ -555,6 +559,7 @@ config load_config( const fc::path& datadir ) virtual ~client_impl() override { + cancel_blocks_too_old_monitor_task(); cancel_rebroadcast_pending_loop(); _p2p_node.reset(); delete _cli; @@ -562,7 +567,16 @@ config load_config( const fc::path& datadir ) void start() { + try + { _cli->start(); + } + catch (...) + { + if (_notifier) + _notifier->notify_client_exiting_unexpectedly(); + throw; + } } void reschedule_delegate_loop(); @@ -586,6 +600,8 @@ config load_config( const fc::path& datadir ) bool sync_mode); bool on_new_transaction(const signed_transaction& trx); + void blocks_too_old_monitor_task(); + void cancel_blocks_too_old_monitor_task(); /* Implement node_delegate */ // @{ @@ -654,6 +670,9 @@ config load_config( const fc::path& datadir ) rpc_server_config _tmp_rpc_config; bts::net::node_ptr _p2p_node = nullptr; + bts_gntp_notifier_ptr _notifier; + fc::future _blocks_too_old_monitor_done; + //-------------------------------------------------- JSON-RPC Method Implementations // include all of the method overrides generated by the bts_api_generator @@ -1429,11 +1448,13 @@ config load_config( const fc::path& datadir ) } } - void client_impl::connection_count_changed(uint32_t c) + void client_impl::connection_count_changed(uint32_t new_connection_count) { std::ostringstream message; - message << "--- there are now " << c << " active connections to the p2p network"; + message << "--- there are now " << new_connection_count << " active connections to the p2p network"; ulog( message.str() ); + if (_notifier) + _notifier->notify_connection_count_changed(new_connection_count); } uint32_t client_impl::get_block_number(const bts::net::item_hash_t& block_id) @@ -1478,6 +1499,35 @@ config load_config( const fc::path& datadir ) ulog( message ); } + void client_impl::blocks_too_old_monitor_task() + { + // if we have no connections, don't warn about the head block too old -- + // we should already be warning about no connections + // if we're syncing, don't warn, we wouldn't be syncing if the head block weren't old + if (_chain_db->get_head_block().timestamp < bts::blockchain::now() - fc::seconds(BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC * 2) && + !_sync_mode && + _p2p_node->get_connection_count() > 0 && + _notifier) + _notifier->notify_head_block_too_old(_chain_db->get_head_block().timestamp); + + if (!_blocks_too_old_monitor_done.canceled()) + _blocks_too_old_monitor_done = fc::schedule([=]() { blocks_too_old_monitor_task(); }, + fc::time_point::now() + fc::seconds(BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC), + "block_monitor_task"); + } + + void client_impl::cancel_blocks_too_old_monitor_task() + { + try + { + _blocks_too_old_monitor_done.cancel_and_wait(); + } + catch( const fc::exception& e ) + { + wlog( "Unexpected exception thrown while canceling blocks_too_old_monitor(): ${e}", ("e",e.to_detail_string() ) ); + } + } + } // end namespace detail client::client() @@ -1580,6 +1630,8 @@ config load_config( const fc::path& datadir ) client::~client() { + if (my->_notifier) + my->_notifier->client_is_shutting_down(); my->cancel_delegate_loop(); } @@ -2305,6 +2357,8 @@ config load_config( const fc::path& datadir ) uint16_t p2pport = option_variables["p2p-port"].as(); listen_on_port(p2pport, option_variables.count("p2p-port") != 0); } + accept_incoming_p2p_connections(option_variables["accept-incoming-connections"].as()); + // else we use the default set in bts::net::node //initialize cli @@ -2376,6 +2430,25 @@ config load_config( const fc::path& datadir ) get_node()->clear_peer_database(); } + if (option_variables.count("growl")) + { + std::string host_to_notify = option_variables["growl"].as(); + uint16_t port_to_notify = 23053; + std::string::size_type colon_pos = host_to_notify.find(':'); + if (colon_pos != std::string::npos) + { + port_to_notify = boost::lexical_cast(host_to_notify.substr(colon_pos + 1)); + host_to_notify = host_to_notify.substr(0, colon_pos); + } + fc::optional growl_password; + if (option_variables.count("growl-password")) + growl_password = option_variables["growl-password"].as(); + my->_notifier = std::make_shared(host_to_notify, port_to_notify, growl_password); + my->_blocks_too_old_monitor_done = fc::schedule([=]() { my->blocks_too_old_monitor_task(); }, + fc::time_point::now() + fc::seconds(BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC), + "block_monitor_task"); + } + start_networking([=]{ fc::ip::endpoint actual_p2p_endpoint = this->get_p2p_listening_endpoint(); std::ostringstream port_stream; @@ -2385,13 +2458,19 @@ config load_config( const fc::path& datadir ) port_stream << (string)actual_p2p_endpoint; if( option_variables.count("log-commands") <= 0) /* Was breaking regression tests */ - ulog("Listening for P2P connections on ${port}",("port",port_stream.str())); - - if (option_variables.count("p2p-port")) { - uint16_t p2p_port = option_variables["p2p-port"].as(); - if (p2p_port != 0 && p2p_port != actual_p2p_endpoint.port()) - ulog(" (unable to bind to the desired port ${p2p_port} )", ("p2p_port",p2p_port)); + if (option_variables["accept-incoming-connections"].as()) + { + ulog("Listening for P2P connections on ${port}",("port",port_stream.str())); + if (option_variables.count("p2p-port")) + { + uint16_t p2p_port = option_variables["p2p-port"].as(); + if (p2p_port != 0 && p2p_port != actual_p2p_endpoint.port()) + ulog(" (unable to bind to the desired port ${p2p_port} )", ("p2p_port",p2p_port)); + } + } + else + ulog("Not accepting incoming P2P connections"); } if (option_variables.count("connect-to")) @@ -2433,7 +2512,12 @@ config load_config( const fc::path& datadir ) void client::listen_on_port(uint16_t port_to_listen, bool wait_if_not_available) { - my->_p2p_node->listen_on_port(port_to_listen, wait_if_not_available); + my->_p2p_node->listen_on_port(port_to_listen, wait_if_not_available); + } + + void client::accept_incoming_p2p_connections(bool accept) + { + my->_p2p_node->accept_incoming_connections(accept); } const config& client::configure( const fc::path& configuration_directory ) diff --git a/libraries/client/include/bts/client/client.hpp b/libraries/client/include/bts/client/client.hpp index e0e3c5c12..7b0eb45e5 100644 --- a/libraries/client/include/bts/client/client.hpp +++ b/libraries/client/include/bts/client/client.hpp @@ -143,6 +143,7 @@ namespace bts { namespace client { // functions for taking command-line parameters and passing them on to the p2p node void listen_on_port( uint16_t port_to_listen, bool wait_if_not_available); + void accept_incoming_p2p_connections(bool accept); void listen_to_p2p_network(); void connect_to_peer( const string& remote_endpoint ); void connect_to_p2p_network(); diff --git a/libraries/client/include/bts/client/notifier.hpp b/libraries/client/include/bts/client/notifier.hpp new file mode 100644 index 000000000..a2446faa3 --- /dev/null +++ b/libraries/client/include/bts/client/notifier.hpp @@ -0,0 +1,28 @@ +#pragma once +#include +#include +#include + +#include + +namespace bts { namespace client { + namespace detail { + class bts_gntp_notifier_impl; + } + + class bts_gntp_notifier { + public: + bts_gntp_notifier(const std::string& host_to_notify = "127.0.0.1", uint16_t port = 23053, + const fc::optional& password = fc::optional()); + ~bts_gntp_notifier(); + + void client_is_shutting_down(); + void notify_connection_count_changed(uint32_t new_connection_count); + void notify_client_exiting_unexpectedly(); + void notify_head_block_too_old(const fc::time_point_sec& head_block_age); + private: + std::unique_ptr my; + }; + typedef std::shared_ptr bts_gntp_notifier_ptr; + +} } // end namespace bts::client \ No newline at end of file diff --git a/libraries/client/notifier.cpp b/libraries/client/notifier.cpp new file mode 100644 index 000000000..2be24dc58 --- /dev/null +++ b/libraries/client/notifier.cpp @@ -0,0 +1,662 @@ +#include +#include +#include + +#include + +#include + +namespace bts { namespace client { + namespace detail + { + class bts_gntp_notifier_impl + { + public: + fc::gntp_notifier _notifier; + fc::gntp_icon_ptr _bitshares_icon; + + bool _shutting_down; + + uint32_t _last_reported_connection_count; + uint32_t _connection_count_notification_threshold; + fc::time_point _last_connection_count_notification_time; + fc::microseconds _connection_count_notification_interval; + fc::time_point _last_head_block_too_old_notification_time; + fc::microseconds _head_block_too_old_notification_interval; + uint32_t _missed_block_count_threshold; + + bts_gntp_notifier_impl(const std::string& host_to_notify = "127.0.0.1", uint16_t port = 23053, + const fc::optional& password = fc::optional()); + void register_notification_types(); + }; + extern unsigned char bitshares_icon_png[]; + extern unsigned bitshares_icon_png_len; + + bts_gntp_notifier_impl::bts_gntp_notifier_impl(const std::string& host_to_notify /* = "127.0.0.1" */, uint16_t port /* = 23053 */, + const fc::optional& password /* = optional() */) : + _notifier(host_to_notify, port, password), + _bitshares_icon(std::make_shared((const char*)bitshares_icon_png, bitshares_icon_png_len)), + _shutting_down(false), + _last_reported_connection_count(0), + _connection_count_notification_threshold(5), + _connection_count_notification_interval(fc::seconds(300)), + _head_block_too_old_notification_interval(fc::seconds(300)), + _missed_block_count_threshold(3) + { + } + + void bts_gntp_notifier_impl::register_notification_types() + { + fc::gntp_notification_type notification_type; + + notification_type.name = "connection_count_below_threshold"; + notification_type.display_name = "Connection Count Below Threshold"; + notification_type.enabled = true; + notification_type.icon = _bitshares_icon; + _notifier.add_notification_type(notification_type); + + notification_type.name = "client_exiting_unexpectedly"; + notification_type.display_name = "Client Exiting Unexpectedly"; + notification_type.enabled = true; + notification_type.icon = _bitshares_icon; + _notifier.add_notification_type(notification_type); + + notification_type.name = "head_block_too_old"; + notification_type.display_name = "Head Block is Too Old"; + notification_type.enabled = true; + notification_type.icon = _bitshares_icon; + _notifier.add_notification_type(notification_type); + + _notifier.register_notifications(); + } + } + + bts_gntp_notifier::bts_gntp_notifier(const std::string& host_to_notify /* = "127.0.0.1" */, uint16_t port /* = 23053 */, + const fc::optional& password /* = fc::optional() */) : + my(new detail::bts_gntp_notifier_impl(host_to_notify, port, password)) + { + my->_notifier.set_application_name("BitShares"); + my->_notifier.set_application_icon(my->_bitshares_icon); + my->register_notification_types(); + } + + bts_gntp_notifier::~bts_gntp_notifier() + { + } + + void bts_gntp_notifier::client_is_shutting_down() + { + my->_shutting_down = true; + } + + void bts_gntp_notifier::notify_connection_count_changed(uint32_t new_connection_count) + { + // notify any time we drop below the threshold, unless we've already done so recently + // (to cut down on noise if we're oscillating around the threshold) + if (new_connection_count >= my->_connection_count_notification_threshold) + my->_last_reported_connection_count = new_connection_count; + else if (new_connection_count < my->_connection_count_notification_threshold && + my->_last_reported_connection_count >= my->_connection_count_notification_threshold) + { + fc::time_point notification_time_cutoff = fc::time_point::now() - my->_connection_count_notification_interval; + if (my->_last_connection_count_notification_time < notification_time_cutoff) + { + std::ostringstream message; + message << "The BitShares client's peer connection count dropped to " << new_connection_count << + ", which is below the warning threshold of " << my->_connection_count_notification_threshold; + my->_notifier.send_notification("connection_count_below_threshold", "Connection Count Below Threshold", message.str(), my->_bitshares_icon); + my->_last_reported_connection_count = new_connection_count; + my->_last_connection_count_notification_time = fc::time_point::now(); + } + } + } + + void bts_gntp_notifier::notify_client_exiting_unexpectedly() + { + std::ostringstream message; + message << "The BitShares client is exiting due to an unhandled exception"; + my->_notifier.send_notification("client_exiting_unexpectedly", "Client Exiting Unexpectedly", message.str(), my->_bitshares_icon); + } + + void bts_gntp_notifier::notify_head_block_too_old(const fc::time_point_sec& head_block_age) + { + fc::time_point block_age_cutoff = fc::time_point::now() - fc::seconds(BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC * my->_missed_block_count_threshold); + if (head_block_age < block_age_cutoff) + { + fc::time_point notification_time_cutoff = fc::time_point::now() - my->_head_block_too_old_notification_interval; + if (my->_last_head_block_too_old_notification_time < notification_time_cutoff) + { + std::ostringstream message; + uint32_t age_in_sec = bts::blockchain::now().sec_since_epoch() - head_block_age.sec_since_epoch(); + uint32_t missed_block_count = age_in_sec / BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC; + message << "The last block on our blockchain is " << fc::get_approximate_relative_time_string(head_block_age, bts::blockchain::now(), " old") << + " seconds old, meaning we've missed " << missed_block_count << " blocks"; + my->_notifier.send_notification("head_block_too_old", "Head Block is Too Old", message.str(), my->_bitshares_icon); + my->_last_head_block_too_old_notification_time = fc::time_point::now(); + } + } + } + + + namespace detail + { + unsigned char bitshares_icon_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, + 0x08, 0x02, 0x00, 0x00, 0x00, 0x25, 0x0b, 0xe6, 0x89, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, + 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x0a, 0x4f, 0x69, 0x43, + 0x43, 0x50, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x20, + 0x49, 0x43, 0x43, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x00, + 0x00, 0x78, 0xda, 0x9d, 0x53, 0x67, 0x54, 0x53, 0xe9, 0x16, 0x3d, 0xf7, + 0xde, 0xf4, 0x42, 0x4b, 0x88, 0x80, 0x94, 0x4b, 0x6f, 0x52, 0x15, 0x08, + 0x20, 0x52, 0x42, 0x8b, 0x80, 0x14, 0x91, 0x26, 0x2a, 0x21, 0x09, 0x10, + 0x4a, 0x88, 0x21, 0xa1, 0xd9, 0x15, 0x51, 0xc1, 0x11, 0x45, 0x45, 0x04, + 0x1b, 0xc8, 0xa0, 0x88, 0x03, 0x8e, 0x8e, 0x80, 0x8c, 0x15, 0x51, 0x2c, + 0x0c, 0x8a, 0x0a, 0xd8, 0x07, 0xe4, 0x21, 0xa2, 0x8e, 0x83, 0xa3, 0x88, + 0x8a, 0xca, 0xfb, 0xe1, 0x7b, 0xa3, 0x6b, 0xd6, 0xbc, 0xf7, 0xe6, 0xcd, + 0xfe, 0xb5, 0xd7, 0x3e, 0xe7, 0xac, 0xf3, 0x9d, 0xb3, 0xcf, 0x07, 0xc0, + 0x08, 0x0c, 0x96, 0x48, 0x33, 0x51, 0x35, 0x80, 0x0c, 0xa9, 0x42, 0x1e, + 0x11, 0xe0, 0x83, 0xc7, 0xc4, 0xc6, 0xe1, 0xe4, 0x2e, 0x40, 0x81, 0x0a, + 0x24, 0x70, 0x00, 0x10, 0x08, 0xb3, 0x64, 0x21, 0x73, 0xfd, 0x23, 0x01, + 0x00, 0xf8, 0x7e, 0x3c, 0x3c, 0x2b, 0x22, 0xc0, 0x07, 0xbe, 0x00, 0x01, + 0x78, 0xd3, 0x0b, 0x08, 0x00, 0xc0, 0x4d, 0x9b, 0xc0, 0x30, 0x1c, 0x87, + 0xff, 0x0f, 0xea, 0x42, 0x99, 0x5c, 0x01, 0x80, 0x84, 0x01, 0xc0, 0x74, + 0x91, 0x38, 0x4b, 0x08, 0x80, 0x14, 0x00, 0x40, 0x7a, 0x8e, 0x42, 0xa6, + 0x00, 0x40, 0x46, 0x01, 0x80, 0x9d, 0x98, 0x26, 0x53, 0x00, 0xa0, 0x04, + 0x00, 0x60, 0xcb, 0x63, 0x62, 0xe3, 0x00, 0x50, 0x2d, 0x00, 0x60, 0x27, + 0x7f, 0xe6, 0xd3, 0x00, 0x80, 0x9d, 0xf8, 0x99, 0x7b, 0x01, 0x00, 0x5b, + 0x94, 0x21, 0x15, 0x01, 0xa0, 0x91, 0x00, 0x20, 0x13, 0x65, 0x88, 0x44, + 0x00, 0x68, 0x3b, 0x00, 0xac, 0xcf, 0x56, 0x8a, 0x45, 0x00, 0x58, 0x30, + 0x00, 0x14, 0x66, 0x4b, 0xc4, 0x39, 0x00, 0xd8, 0x2d, 0x00, 0x30, 0x49, + 0x57, 0x66, 0x48, 0x00, 0xb0, 0xb7, 0x00, 0xc0, 0xce, 0x10, 0x0b, 0xb2, + 0x00, 0x08, 0x0c, 0x00, 0x30, 0x51, 0x88, 0x85, 0x29, 0x00, 0x04, 0x7b, + 0x00, 0x60, 0xc8, 0x23, 0x23, 0x78, 0x00, 0x84, 0x99, 0x00, 0x14, 0x46, + 0xf2, 0x57, 0x3c, 0xf1, 0x2b, 0xae, 0x10, 0xe7, 0x2a, 0x00, 0x00, 0x78, + 0x99, 0xb2, 0x3c, 0xb9, 0x24, 0x39, 0x45, 0x81, 0x5b, 0x08, 0x2d, 0x71, + 0x07, 0x57, 0x57, 0x2e, 0x1e, 0x28, 0xce, 0x49, 0x17, 0x2b, 0x14, 0x36, + 0x61, 0x02, 0x61, 0x9a, 0x40, 0x2e, 0xc2, 0x79, 0x99, 0x19, 0x32, 0x81, + 0x34, 0x0f, 0xe0, 0xf3, 0xcc, 0x00, 0x00, 0xa0, 0x91, 0x15, 0x11, 0xe0, + 0x83, 0xf3, 0xfd, 0x78, 0xce, 0x0e, 0xae, 0xce, 0xce, 0x36, 0x8e, 0xb6, + 0x0e, 0x5f, 0x2d, 0xea, 0xbf, 0x06, 0xff, 0x22, 0x62, 0x62, 0xe3, 0xfe, + 0xe5, 0xcf, 0xab, 0x70, 0x40, 0x00, 0x00, 0xe1, 0x74, 0x7e, 0xd1, 0xfe, + 0x2c, 0x2f, 0xb3, 0x1a, 0x80, 0x3b, 0x06, 0x80, 0x6d, 0xfe, 0xa2, 0x25, + 0xee, 0x04, 0x68, 0x5e, 0x0b, 0xa0, 0x75, 0xf7, 0x8b, 0x66, 0xb2, 0x0f, + 0x40, 0xb5, 0x00, 0xa0, 0xe9, 0xda, 0x57, 0xf3, 0x70, 0xf8, 0x7e, 0x3c, + 0x3c, 0x45, 0xa1, 0x90, 0xb9, 0xd9, 0xd9, 0xe5, 0xe4, 0xe4, 0xd8, 0x4a, + 0xc4, 0x42, 0x5b, 0x61, 0xca, 0x57, 0x7d, 0xfe, 0x67, 0xc2, 0x5f, 0xc0, + 0x57, 0xfd, 0x6c, 0xf9, 0x7e, 0x3c, 0xfc, 0xf7, 0xf5, 0xe0, 0xbe, 0xe2, + 0x24, 0x81, 0x32, 0x5d, 0x81, 0x47, 0x04, 0xf8, 0xe0, 0xc2, 0xcc, 0xf4, + 0x4c, 0xa5, 0x1c, 0xcf, 0x92, 0x09, 0x84, 0x62, 0xdc, 0xe6, 0x8f, 0x47, + 0xfc, 0xb7, 0x0b, 0xff, 0xfc, 0x1d, 0xd3, 0x22, 0xc4, 0x49, 0x62, 0xb9, + 0x58, 0x2a, 0x14, 0xe3, 0x51, 0x12, 0x71, 0x8e, 0x44, 0x9a, 0x8c, 0xf3, + 0x32, 0xa5, 0x22, 0x89, 0x42, 0x92, 0x29, 0xc5, 0x25, 0xd2, 0xff, 0x64, + 0xe2, 0xdf, 0x2c, 0xfb, 0x03, 0x3e, 0xdf, 0x35, 0x00, 0xb0, 0x6a, 0x3e, + 0x01, 0x7b, 0x91, 0x2d, 0xa8, 0x5d, 0x63, 0x03, 0xf6, 0x4b, 0x27, 0x10, + 0x58, 0x74, 0xc0, 0xe2, 0xf7, 0x00, 0x00, 0xf2, 0xbb, 0x6f, 0xc1, 0xd4, + 0x28, 0x08, 0x03, 0x80, 0x68, 0x83, 0xe1, 0xcf, 0x77, 0xff, 0xef, 0x3f, + 0xfd, 0x47, 0xa0, 0x25, 0x00, 0x80, 0x66, 0x49, 0x92, 0x71, 0x00, 0x00, + 0x5e, 0x44, 0x24, 0x2e, 0x54, 0xca, 0xb3, 0x3f, 0xc7, 0x08, 0x00, 0x00, + 0x44, 0xa0, 0x81, 0x2a, 0xb0, 0x41, 0x1b, 0xf4, 0xc1, 0x18, 0x2c, 0xc0, + 0x06, 0x1c, 0xc1, 0x05, 0xdc, 0xc1, 0x0b, 0xfc, 0x60, 0x36, 0x84, 0x42, + 0x24, 0xc4, 0xc2, 0x42, 0x10, 0x42, 0x0a, 0x64, 0x80, 0x1c, 0x72, 0x60, + 0x29, 0xac, 0x82, 0x42, 0x28, 0x86, 0xcd, 0xb0, 0x1d, 0x2a, 0x60, 0x2f, + 0xd4, 0x40, 0x1d, 0x34, 0xc0, 0x51, 0x68, 0x86, 0x93, 0x70, 0x0e, 0x2e, + 0xc2, 0x55, 0xb8, 0x0e, 0x3d, 0x70, 0x0f, 0xfa, 0x61, 0x08, 0x9e, 0xc1, + 0x28, 0xbc, 0x81, 0x09, 0x04, 0x41, 0xc8, 0x08, 0x13, 0x61, 0x21, 0xda, + 0x88, 0x01, 0x62, 0x8a, 0x58, 0x23, 0x8e, 0x08, 0x17, 0x99, 0x85, 0xf8, + 0x21, 0xc1, 0x48, 0x04, 0x12, 0x8b, 0x24, 0x20, 0xc9, 0x88, 0x14, 0x51, + 0x22, 0x4b, 0x91, 0x35, 0x48, 0x31, 0x52, 0x8a, 0x54, 0x20, 0x55, 0x48, + 0x1d, 0xf2, 0x3d, 0x72, 0x02, 0x39, 0x87, 0x5c, 0x46, 0xba, 0x91, 0x3b, + 0xc8, 0x00, 0x32, 0x82, 0xfc, 0x86, 0xbc, 0x47, 0x31, 0x94, 0x81, 0xb2, + 0x51, 0x3d, 0xd4, 0x0c, 0xb5, 0x43, 0xb9, 0xa8, 0x37, 0x1a, 0x84, 0x46, + 0xa2, 0x0b, 0xd0, 0x64, 0x74, 0x31, 0x9a, 0x8f, 0x16, 0xa0, 0x9b, 0xd0, + 0x72, 0xb4, 0x1a, 0x3d, 0x8c, 0x36, 0xa1, 0xe7, 0xd0, 0xab, 0x68, 0x0f, + 0xda, 0x8f, 0x3e, 0x43, 0xc7, 0x30, 0xc0, 0xe8, 0x18, 0x07, 0x33, 0xc4, + 0x6c, 0x30, 0x2e, 0xc6, 0xc3, 0x42, 0xb1, 0x38, 0x2c, 0x09, 0x93, 0x63, + 0xcb, 0xb1, 0x22, 0xac, 0x0c, 0xab, 0xc6, 0x1a, 0xb0, 0x56, 0xac, 0x03, + 0xbb, 0x89, 0xf5, 0x63, 0xcf, 0xb1, 0x77, 0x04, 0x12, 0x81, 0x45, 0xc0, + 0x09, 0x36, 0x04, 0x77, 0x42, 0x20, 0x61, 0x1e, 0x41, 0x48, 0x58, 0x4c, + 0x58, 0x4e, 0xd8, 0x48, 0xa8, 0x20, 0x1c, 0x24, 0x34, 0x11, 0xda, 0x09, + 0x37, 0x09, 0x03, 0x84, 0x51, 0xc2, 0x27, 0x22, 0x93, 0xa8, 0x4b, 0xb4, + 0x26, 0xba, 0x11, 0xf9, 0xc4, 0x18, 0x62, 0x32, 0x31, 0x87, 0x58, 0x48, + 0x2c, 0x23, 0xd6, 0x12, 0x8f, 0x13, 0x2f, 0x10, 0x7b, 0x88, 0x43, 0xc4, + 0x37, 0x24, 0x12, 0x89, 0x43, 0x32, 0x27, 0xb9, 0x90, 0x02, 0x49, 0xb1, + 0xa4, 0x54, 0xd2, 0x12, 0xd2, 0x46, 0xd2, 0x6e, 0x52, 0x23, 0xe9, 0x2c, + 0xa9, 0x9b, 0x34, 0x48, 0x1a, 0x23, 0x93, 0xc9, 0xda, 0x64, 0x6b, 0xb2, + 0x07, 0x39, 0x94, 0x2c, 0x20, 0x2b, 0xc8, 0x85, 0xe4, 0x9d, 0xe4, 0xc3, + 0xe4, 0x33, 0xe4, 0x1b, 0xe4, 0x21, 0xf2, 0x5b, 0x0a, 0x9d, 0x62, 0x40, + 0x71, 0xa4, 0xf8, 0x53, 0xe2, 0x28, 0x52, 0xca, 0x6a, 0x4a, 0x19, 0xe5, + 0x10, 0xe5, 0x34, 0xe5, 0x06, 0x65, 0x98, 0x32, 0x41, 0x55, 0xa3, 0x9a, + 0x52, 0xdd, 0xa8, 0xa1, 0x54, 0x11, 0x35, 0x8f, 0x5a, 0x42, 0xad, 0xa1, + 0xb6, 0x52, 0xaf, 0x51, 0x87, 0xa8, 0x13, 0x34, 0x75, 0x9a, 0x39, 0xcd, + 0x83, 0x16, 0x49, 0x4b, 0xa5, 0xad, 0xa2, 0x95, 0xd3, 0x1a, 0x68, 0x17, + 0x68, 0xf7, 0x69, 0xaf, 0xe8, 0x74, 0xba, 0x11, 0xdd, 0x95, 0x1e, 0x4e, + 0x97, 0xd0, 0x57, 0xd2, 0xcb, 0xe9, 0x47, 0xe8, 0x97, 0xe8, 0x03, 0xf4, + 0x77, 0x0c, 0x0d, 0x86, 0x15, 0x83, 0xc7, 0x88, 0x67, 0x28, 0x19, 0x9b, + 0x18, 0x07, 0x18, 0x67, 0x19, 0x77, 0x18, 0xaf, 0x98, 0x4c, 0xa6, 0x19, + 0xd3, 0x8b, 0x19, 0xc7, 0x54, 0x30, 0x37, 0x31, 0xeb, 0x98, 0xe7, 0x99, + 0x0f, 0x99, 0x6f, 0x55, 0x58, 0x2a, 0xb6, 0x2a, 0x7c, 0x15, 0x91, 0xca, + 0x0a, 0x95, 0x4a, 0x95, 0x26, 0x95, 0x1b, 0x2a, 0x2f, 0x54, 0xa9, 0xaa, + 0xa6, 0xaa, 0xde, 0xaa, 0x0b, 0x55, 0xf3, 0x55, 0xcb, 0x54, 0x8f, 0xa9, + 0x5e, 0x53, 0x7d, 0xae, 0x46, 0x55, 0x33, 0x53, 0xe3, 0xa9, 0x09, 0xd4, + 0x96, 0xab, 0x55, 0xaa, 0x9d, 0x50, 0xeb, 0x53, 0x1b, 0x53, 0x67, 0xa9, + 0x3b, 0xa8, 0x87, 0xaa, 0x67, 0xa8, 0x6f, 0x54, 0x3f, 0xa4, 0x7e, 0x59, + 0xfd, 0x89, 0x06, 0x59, 0xc3, 0x4c, 0xc3, 0x4f, 0x43, 0xa4, 0x51, 0xa0, + 0xb1, 0x5f, 0xe3, 0xbc, 0xc6, 0x20, 0x0b, 0x63, 0x19, 0xb3, 0x78, 0x2c, + 0x21, 0x6b, 0x0d, 0xab, 0x86, 0x75, 0x81, 0x35, 0xc4, 0x26, 0xb1, 0xcd, + 0xd9, 0x7c, 0x76, 0x2a, 0xbb, 0x98, 0xfd, 0x1d, 0xbb, 0x8b, 0x3d, 0xaa, + 0xa9, 0xa1, 0x39, 0x43, 0x33, 0x4a, 0x33, 0x57, 0xb3, 0x52, 0xf3, 0x94, + 0x66, 0x3f, 0x07, 0xe3, 0x98, 0x71, 0xf8, 0x9c, 0x74, 0x4e, 0x09, 0xe7, + 0x28, 0xa7, 0x97, 0xf3, 0x7e, 0x8a, 0xde, 0x14, 0xef, 0x29, 0xe2, 0x29, + 0x1b, 0xa6, 0x34, 0x4c, 0xb9, 0x31, 0x65, 0x5c, 0x6b, 0xaa, 0x96, 0x97, + 0x96, 0x58, 0xab, 0x48, 0xab, 0x51, 0xab, 0x47, 0xeb, 0xbd, 0x36, 0xae, + 0xed, 0xa7, 0x9d, 0xa6, 0xbd, 0x45, 0xbb, 0x59, 0xfb, 0x81, 0x0e, 0x41, + 0xc7, 0x4a, 0x27, 0x5c, 0x27, 0x47, 0x67, 0x8f, 0xce, 0x05, 0x9d, 0xe7, + 0x53, 0xd9, 0x53, 0xdd, 0xa7, 0x0a, 0xa7, 0x16, 0x4d, 0x3d, 0x3a, 0xf5, + 0xae, 0x2e, 0xaa, 0x6b, 0xa5, 0x1b, 0xa1, 0xbb, 0x44, 0x77, 0xbf, 0x6e, + 0xa7, 0xee, 0x98, 0x9e, 0xbe, 0x5e, 0x80, 0x9e, 0x4c, 0x6f, 0xa7, 0xde, + 0x79, 0xbd, 0xe7, 0xfa, 0x1c, 0x7d, 0x2f, 0xfd, 0x54, 0xfd, 0x6d, 0xfa, + 0xa7, 0xf5, 0x47, 0x0c, 0x58, 0x06, 0xb3, 0x0c, 0x24, 0x06, 0xdb, 0x0c, + 0xce, 0x18, 0x3c, 0xc5, 0x35, 0x71, 0x6f, 0x3c, 0x1d, 0x2f, 0xc7, 0xdb, + 0xf1, 0x51, 0x43, 0x5d, 0xc3, 0x40, 0x43, 0xa5, 0x61, 0x95, 0x61, 0x97, + 0xe1, 0x84, 0x91, 0xb9, 0xd1, 0x3c, 0xa3, 0xd5, 0x46, 0x8d, 0x46, 0x0f, + 0x8c, 0x69, 0xc6, 0x5c, 0xe3, 0x24, 0xe3, 0x6d, 0xc6, 0x6d, 0xc6, 0xa3, + 0x26, 0x06, 0x26, 0x21, 0x26, 0x4b, 0x4d, 0xea, 0x4d, 0xee, 0x9a, 0x52, + 0x4d, 0xb9, 0xa6, 0x29, 0xa6, 0x3b, 0x4c, 0x3b, 0x4c, 0xc7, 0xcd, 0xcc, + 0xcd, 0xa2, 0xcd, 0xd6, 0x99, 0x35, 0x9b, 0x3d, 0x31, 0xd7, 0x32, 0xe7, + 0x9b, 0xe7, 0x9b, 0xd7, 0x9b, 0xdf, 0xb7, 0x60, 0x5a, 0x78, 0x5a, 0x2c, + 0xb6, 0xa8, 0xb6, 0xb8, 0x65, 0x49, 0xb2, 0xe4, 0x5a, 0xa6, 0x59, 0xee, + 0xb6, 0xbc, 0x6e, 0x85, 0x5a, 0x39, 0x59, 0xa5, 0x58, 0x55, 0x5a, 0x5d, + 0xb3, 0x46, 0xad, 0x9d, 0xad, 0x25, 0xd6, 0xbb, 0xad, 0xbb, 0xa7, 0x11, + 0xa7, 0xb9, 0x4e, 0x93, 0x4e, 0xab, 0x9e, 0xd6, 0x67, 0xc3, 0xb0, 0xf1, + 0xb6, 0xc9, 0xb6, 0xa9, 0xb7, 0x19, 0xb0, 0xe5, 0xd8, 0x06, 0xdb, 0xae, + 0xb6, 0x6d, 0xb6, 0x7d, 0x61, 0x67, 0x62, 0x17, 0x67, 0xb7, 0xc5, 0xae, + 0xc3, 0xee, 0x93, 0xbd, 0x93, 0x7d, 0xba, 0x7d, 0x8d, 0xfd, 0x3d, 0x07, + 0x0d, 0x87, 0xd9, 0x0e, 0xab, 0x1d, 0x5a, 0x1d, 0x7e, 0x73, 0xb4, 0x72, + 0x14, 0x3a, 0x56, 0x3a, 0xde, 0x9a, 0xce, 0x9c, 0xee, 0x3f, 0x7d, 0xc5, + 0xf4, 0x96, 0xe9, 0x2f, 0x67, 0x58, 0xcf, 0x10, 0xcf, 0xd8, 0x33, 0xe3, + 0xb6, 0x13, 0xcb, 0x29, 0xc4, 0x69, 0x9d, 0x53, 0x9b, 0xd3, 0x47, 0x67, + 0x17, 0x67, 0xb9, 0x73, 0x83, 0xf3, 0x88, 0x8b, 0x89, 0x4b, 0x82, 0xcb, + 0x2e, 0x97, 0x3e, 0x2e, 0x9b, 0x1b, 0xc6, 0xdd, 0xc8, 0xbd, 0xe4, 0x4a, + 0x74, 0xf5, 0x71, 0x5d, 0xe1, 0x7a, 0xd2, 0xf5, 0x9d, 0x9b, 0xb3, 0x9b, + 0xc2, 0xed, 0xa8, 0xdb, 0xaf, 0xee, 0x36, 0xee, 0x69, 0xee, 0x87, 0xdc, + 0x9f, 0xcc, 0x34, 0x9f, 0x29, 0x9e, 0x59, 0x33, 0x73, 0xd0, 0xc3, 0xc8, + 0x43, 0xe0, 0x51, 0xe5, 0xd1, 0x3f, 0x0b, 0x9f, 0x95, 0x30, 0x6b, 0xdf, + 0xac, 0x7e, 0x4f, 0x43, 0x4f, 0x81, 0x67, 0xb5, 0xe7, 0x23, 0x2f, 0x63, + 0x2f, 0x91, 0x57, 0xad, 0xd7, 0xb0, 0xb7, 0xa5, 0x77, 0xaa, 0xf7, 0x61, + 0xef, 0x17, 0x3e, 0xf6, 0x3e, 0x72, 0x9f, 0xe3, 0x3e, 0xe3, 0x3c, 0x37, + 0xde, 0x32, 0xde, 0x59, 0x5f, 0xcc, 0x37, 0xc0, 0xb7, 0xc8, 0xb7, 0xcb, + 0x4f, 0xc3, 0x6f, 0x9e, 0x5f, 0x85, 0xdf, 0x43, 0x7f, 0x23, 0xff, 0x64, + 0xff, 0x7a, 0xff, 0xd1, 0x00, 0xa7, 0x80, 0x25, 0x01, 0x67, 0x03, 0x89, + 0x81, 0x41, 0x81, 0x5b, 0x02, 0xfb, 0xf8, 0x7a, 0x7c, 0x21, 0xbf, 0x8e, + 0x3f, 0x3a, 0xdb, 0x65, 0xf6, 0xb2, 0xd9, 0xed, 0x41, 0x8c, 0xa0, 0xb9, + 0x41, 0x15, 0x41, 0x8f, 0x82, 0xad, 0x82, 0xe5, 0xc1, 0xad, 0x21, 0x68, + 0xc8, 0xec, 0x90, 0xad, 0x21, 0xf7, 0xe7, 0x98, 0xce, 0x91, 0xce, 0x69, + 0x0e, 0x85, 0x50, 0x7e, 0xe8, 0xd6, 0xd0, 0x07, 0x61, 0xe6, 0x61, 0x8b, + 0xc3, 0x7e, 0x0c, 0x27, 0x85, 0x87, 0x85, 0x57, 0x86, 0x3f, 0x8e, 0x70, + 0x88, 0x58, 0x1a, 0xd1, 0x31, 0x97, 0x35, 0x77, 0xd1, 0xdc, 0x43, 0x73, + 0xdf, 0x44, 0xfa, 0x44, 0x96, 0x44, 0xde, 0x9b, 0x67, 0x31, 0x4f, 0x39, + 0xaf, 0x2d, 0x4a, 0x35, 0x2a, 0x3e, 0xaa, 0x2e, 0x6a, 0x3c, 0xda, 0x37, + 0xba, 0x34, 0xba, 0x3f, 0xc6, 0x2e, 0x66, 0x59, 0xcc, 0xd5, 0x58, 0x9d, + 0x58, 0x49, 0x6c, 0x4b, 0x1c, 0x39, 0x2e, 0x2a, 0xae, 0x36, 0x6e, 0x6c, + 0xbe, 0xdf, 0xfc, 0xed, 0xf3, 0x87, 0xe2, 0x9d, 0xe2, 0x0b, 0xe3, 0x7b, + 0x17, 0x98, 0x2f, 0xc8, 0x5d, 0x70, 0x79, 0xa1, 0xce, 0xc2, 0xf4, 0x85, + 0xa7, 0x16, 0xa9, 0x2e, 0x12, 0x2c, 0x3a, 0x96, 0x40, 0x4c, 0x88, 0x4e, + 0x38, 0x94, 0xf0, 0x41, 0x10, 0x2a, 0xa8, 0x16, 0x8c, 0x25, 0xf2, 0x13, + 0x77, 0x25, 0x8e, 0x0a, 0x79, 0xc2, 0x1d, 0xc2, 0x67, 0x22, 0x2f, 0xd1, + 0x36, 0xd1, 0x88, 0xd8, 0x43, 0x5c, 0x2a, 0x1e, 0x4e, 0xf2, 0x48, 0x2a, + 0x4d, 0x7a, 0x92, 0xec, 0x91, 0xbc, 0x35, 0x79, 0x24, 0xc5, 0x33, 0xa5, + 0x2c, 0xe5, 0xb9, 0x84, 0x27, 0xa9, 0x90, 0xbc, 0x4c, 0x0d, 0x4c, 0xdd, + 0x9b, 0x3a, 0x9e, 0x16, 0x9a, 0x76, 0x20, 0x6d, 0x32, 0x3d, 0x3a, 0xbd, + 0x31, 0x83, 0x92, 0x91, 0x90, 0x71, 0x42, 0xaa, 0x21, 0x4d, 0x93, 0xb6, + 0x67, 0xea, 0x67, 0xe6, 0x66, 0x76, 0xcb, 0xac, 0x65, 0x85, 0xb2, 0xfe, + 0xc5, 0x6e, 0x8b, 0xb7, 0x2f, 0x1e, 0x95, 0x07, 0xc9, 0x6b, 0xb3, 0x90, + 0xac, 0x05, 0x59, 0x2d, 0x0a, 0xb6, 0x42, 0xa6, 0xe8, 0x54, 0x5a, 0x28, + 0xd7, 0x2a, 0x07, 0xb2, 0x67, 0x65, 0x57, 0x66, 0xbf, 0xcd, 0x89, 0xca, + 0x39, 0x96, 0xab, 0x9e, 0x2b, 0xcd, 0xed, 0xcc, 0xb3, 0xca, 0xdb, 0x90, + 0x37, 0x9c, 0xef, 0x9f, 0xff, 0xed, 0x12, 0xc2, 0x12, 0xe1, 0x92, 0xb6, + 0xa5, 0x86, 0x4b, 0x57, 0x2d, 0x1d, 0x58, 0xe6, 0xbd, 0xac, 0x6a, 0x39, + 0xb2, 0x3c, 0x71, 0x79, 0xdb, 0x0a, 0xe3, 0x15, 0x05, 0x2b, 0x86, 0x56, + 0x06, 0xac, 0x3c, 0xb8, 0x8a, 0xb6, 0x2a, 0x6d, 0xd5, 0x4f, 0xab, 0xed, + 0x57, 0x97, 0xae, 0x7e, 0xbd, 0x26, 0x7a, 0x4d, 0x6b, 0x81, 0x5e, 0xc1, + 0xca, 0x82, 0xc1, 0xb5, 0x01, 0x6b, 0xeb, 0x0b, 0x55, 0x0a, 0xe5, 0x85, + 0x7d, 0xeb, 0xdc, 0xd7, 0xed, 0x5d, 0x4f, 0x58, 0x2f, 0x59, 0xdf, 0xb5, + 0x61, 0xfa, 0x86, 0x9d, 0x1b, 0x3e, 0x15, 0x89, 0x8a, 0xae, 0x14, 0xdb, + 0x17, 0x97, 0x15, 0x7f, 0xd8, 0x28, 0xdc, 0x78, 0xe5, 0x1b, 0x87, 0x6f, + 0xca, 0xbf, 0x99, 0xdc, 0x94, 0xb4, 0xa9, 0xab, 0xc4, 0xb9, 0x64, 0xcf, + 0x66, 0xd2, 0x66, 0xe9, 0xe6, 0xde, 0x2d, 0x9e, 0x5b, 0x0e, 0x96, 0xaa, + 0x97, 0xe6, 0x97, 0x0e, 0x6e, 0x0d, 0xd9, 0xda, 0xb4, 0x0d, 0xdf, 0x56, + 0xb4, 0xed, 0xf5, 0xf6, 0x45, 0xdb, 0x2f, 0x97, 0xcd, 0x28, 0xdb, 0xbb, + 0x83, 0xb6, 0x43, 0xb9, 0xa3, 0xbf, 0x3c, 0xb8, 0xbc, 0x65, 0xa7, 0xc9, + 0xce, 0xcd, 0x3b, 0x3f, 0x54, 0xa4, 0x54, 0xf4, 0x54, 0xfa, 0x54, 0x36, + 0xee, 0xd2, 0xdd, 0xb5, 0x61, 0xd7, 0xf8, 0x6e, 0xd1, 0xee, 0x1b, 0x7b, + 0xbc, 0xf6, 0x34, 0xec, 0xd5, 0xdb, 0x5b, 0xbc, 0xf7, 0xfd, 0x3e, 0xc9, + 0xbe, 0xdb, 0x55, 0x01, 0x55, 0x4d, 0xd5, 0x66, 0xd5, 0x65, 0xfb, 0x49, + 0xfb, 0xb3, 0xf7, 0x3f, 0xae, 0x89, 0xaa, 0xe9, 0xf8, 0x96, 0xfb, 0x6d, + 0x5d, 0xad, 0x4e, 0x6d, 0x71, 0xed, 0xc7, 0x03, 0xd2, 0x03, 0xfd, 0x07, + 0x23, 0x0e, 0xb6, 0xd7, 0xb9, 0xd4, 0xd5, 0x1d, 0xd2, 0x3d, 0x54, 0x52, + 0x8f, 0xd6, 0x2b, 0xeb, 0x47, 0x0e, 0xc7, 0x1f, 0xbe, 0xfe, 0x9d, 0xef, + 0x77, 0x2d, 0x0d, 0x36, 0x0d, 0x55, 0x8d, 0x9c, 0xc6, 0xe2, 0x23, 0x70, + 0x44, 0x79, 0xe4, 0xe9, 0xf7, 0x09, 0xdf, 0xf7, 0x1e, 0x0d, 0x3a, 0xda, + 0x76, 0x8c, 0x7b, 0xac, 0xe1, 0x07, 0xd3, 0x1f, 0x76, 0x1d, 0x67, 0x1d, + 0x2f, 0x6a, 0x42, 0x9a, 0xf2, 0x9a, 0x46, 0x9b, 0x53, 0x9a, 0xfb, 0x5b, + 0x62, 0x5b, 0xba, 0x4f, 0xcc, 0x3e, 0xd1, 0xd6, 0xea, 0xde, 0x7a, 0xfc, + 0x47, 0xdb, 0x1f, 0x0f, 0x9c, 0x34, 0x3c, 0x59, 0x79, 0x4a, 0xf3, 0x54, + 0xc9, 0x69, 0xda, 0xe9, 0x82, 0xd3, 0x93, 0x67, 0xf2, 0xcf, 0x8c, 0x9d, + 0x95, 0x9d, 0x7d, 0x7e, 0x2e, 0xf9, 0xdc, 0x60, 0xdb, 0xa2, 0xb6, 0x7b, + 0xe7, 0x63, 0xce, 0xdf, 0x6a, 0x0f, 0x6f, 0xef, 0xba, 0x10, 0x74, 0xe1, + 0xd2, 0x45, 0xff, 0x8b, 0xe7, 0x3b, 0xbc, 0x3b, 0xce, 0x5c, 0xf2, 0xb8, + 0x74, 0xf2, 0xb2, 0xdb, 0xe5, 0x13, 0x57, 0xb8, 0x57, 0x9a, 0xaf, 0x3a, + 0x5f, 0x6d, 0xea, 0x74, 0xea, 0x3c, 0xfe, 0x93, 0xd3, 0x4f, 0xc7, 0xbb, + 0x9c, 0xbb, 0x9a, 0xae, 0xb9, 0x5c, 0x6b, 0xb9, 0xee, 0x7a, 0xbd, 0xb5, + 0x7b, 0x66, 0xf7, 0xe9, 0x1b, 0x9e, 0x37, 0xce, 0xdd, 0xf4, 0xbd, 0x79, + 0xf1, 0x16, 0xff, 0xd6, 0xd5, 0x9e, 0x39, 0x3d, 0xdd, 0xbd, 0xf3, 0x7a, + 0x6f, 0xf7, 0xc5, 0xf7, 0xf5, 0xdf, 0x16, 0xdd, 0x7e, 0x72, 0x27, 0xfd, + 0xce, 0xcb, 0xbb, 0xd9, 0x77, 0x27, 0xee, 0xad, 0xbc, 0x4f, 0xbc, 0x5f, + 0xf4, 0x40, 0xed, 0x41, 0xd9, 0x43, 0xdd, 0x87, 0xd5, 0x3f, 0x5b, 0xfe, + 0xdc, 0xd8, 0xef, 0xdc, 0x7f, 0x6a, 0xc0, 0x77, 0xa0, 0xf3, 0xd1, 0xdc, + 0x47, 0xf7, 0x06, 0x85, 0x83, 0xcf, 0xfe, 0x91, 0xf5, 0x8f, 0x0f, 0x43, + 0x05, 0x8f, 0x99, 0x8f, 0xcb, 0x86, 0x0d, 0x86, 0xeb, 0x9e, 0x38, 0x3e, + 0x39, 0x39, 0xe2, 0x3f, 0x72, 0xfd, 0xe9, 0xfc, 0xa7, 0x43, 0xcf, 0x64, + 0xcf, 0x26, 0x9e, 0x17, 0xfe, 0xa2, 0xfe, 0xcb, 0xae, 0x17, 0x16, 0x2f, + 0x7e, 0xf8, 0xd5, 0xeb, 0xd7, 0xce, 0xd1, 0x98, 0xd1, 0xa1, 0x97, 0xf2, + 0x97, 0x93, 0xbf, 0x6d, 0x7c, 0xa5, 0xfd, 0xea, 0xc0, 0xeb, 0x19, 0xaf, + 0xdb, 0xc6, 0xc2, 0xc6, 0x1e, 0xbe, 0xc9, 0x78, 0x33, 0x31, 0x5e, 0xf4, + 0x56, 0xfb, 0xed, 0xc1, 0x77, 0xdc, 0x77, 0x1d, 0xef, 0xa3, 0xdf, 0x0f, + 0x4f, 0xe4, 0x7c, 0x20, 0x7f, 0x28, 0xff, 0x68, 0xf9, 0xb1, 0xf5, 0x53, + 0xd0, 0xa7, 0xfb, 0x93, 0x19, 0x93, 0x93, 0xff, 0x04, 0x03, 0x98, 0xf3, + 0xfc, 0x63, 0x33, 0x2d, 0xdb, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, + 0x4d, 0x00, 0x00, 0x7a, 0x25, 0x00, 0x00, 0x80, 0x83, 0x00, 0x00, 0xf9, + 0xff, 0x00, 0x00, 0x80, 0xe9, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, + 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, 0x00, 0x17, 0x6f, 0x92, 0x5f, 0xc5, + 0x46, 0x00, 0x00, 0x0d, 0x34, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xd4, + 0x5a, 0x6b, 0x90, 0x5c, 0xc5, 0x75, 0x3e, 0xa7, 0x6f, 0xf7, 0xbd, 0x33, + 0xb3, 0xb3, 0x3b, 0x33, 0xfb, 0xd4, 0x0b, 0x90, 0x10, 0x2b, 0x09, 0x84, + 0xc1, 0xac, 0xa0, 0x2a, 0x40, 0xec, 0x08, 0x83, 0xb0, 0x21, 0x26, 0x71, + 0xd9, 0x31, 0xa9, 0x80, 0x5d, 0x81, 0x72, 0x1c, 0x52, 0x94, 0xa1, 0x2a, + 0xa2, 0x2a, 0x86, 0x58, 0x79, 0x19, 0x8c, 0x7f, 0xa4, 0xca, 0x94, 0xf1, + 0x2f, 0x27, 0x3f, 0x12, 0xdb, 0x18, 0x01, 0xc6, 0x4e, 0x95, 0xb1, 0xbd, + 0x20, 0xca, 0x76, 0x00, 0x61, 0x24, 0xf3, 0x70, 0x78, 0x78, 0x01, 0x09, + 0x90, 0x6c, 0x49, 0xd6, 0xa2, 0x7d, 0xcc, 0xcc, 0xce, 0xcc, 0xce, 0xcc, + 0xed, 0xc7, 0xc9, 0x8f, 0x79, 0xdd, 0xe7, 0xce, 0x5d, 0x5b, 0x38, 0x95, + 0xae, 0xdd, 0xda, 0x9d, 0x7b, 0xbb, 0x4f, 0x7f, 0xa7, 0xfb, 0x3c, 0xbe, + 0xd3, 0x3d, 0xb8, 0xf9, 0xf1, 0x85, 0xb2, 0x24, 0x4d, 0x80, 0x08, 0xff, + 0xbf, 0x1a, 0x03, 0xc8, 0x09, 0xe4, 0x65, 0x69, 0xbe, 0x72, 0x41, 0xf6, + 0xb2, 0x11, 0x91, 0x67, 0xa4, 0x7e, 0x7b, 0x69, 0xb8, 0xaa, 0x97, 0x08, + 0x40, 0x89, 0x46, 0x46, 0x37, 0xc1, 0xa0, 0xa8, 0x70, 0xff, 0xbc, 0x7b, + 0xc7, 0x2b, 0x55, 0xcc, 0x7d, 0x7f, 0xfe, 0xc4, 0x87, 0xf3, 0x25, 0x6d, + 0x1e, 0x7d, 0x57, 0x8d, 0x0a, 0x04, 0x6a, 0x4b, 0xa6, 0xc0, 0x20, 0x8a, + 0xf8, 0xaf, 0x05, 0x80, 0x08, 0x10, 0xa8, 0x4f, 0xaf, 0xd6, 0x67, 0xcf, + 0x43, 0xa2, 0x95, 0x20, 0x12, 0x50, 0x50, 0x02, 0x01, 0x75, 0xb4, 0x9d, + 0x6b, 0x9a, 0xeb, 0x37, 0xd8, 0xa3, 0x19, 0xb1, 0x6e, 0xba, 0xc4, 0x05, + 0xc3, 0xaa, 0x2b, 0x1f, 0x39, 0xd1, 0xd8, 0xfd, 0x16, 0xac, 0x4f, 0x51, + 0xb7, 0x6b, 0x00, 0x47, 0x84, 0xc4, 0x10, 0x96, 0x1e, 0x26, 0xf2, 0xcc, + 0xe9, 0x47, 0xd0, 0xfd, 0xf5, 0x4b, 0xc4, 0xf6, 0x68, 0xaf, 0x24, 0xf2, + 0x0f, 0xf4, 0x3c, 0x59, 0xa8, 0x92, 0x76, 0xdd, 0x9b, 0xb7, 0x0c, 0x0a, + 0x86, 0x9c, 0x00, 0x14, 0x41, 0x5e, 0xe0, 0x86, 0x34, 0x9c, 0x95, 0x42, + 0xa0, 0xc0, 0x92, 0x45, 0x6d, 0x35, 0x05, 0x40, 0x21, 0xc5, 0x3c, 0xf7, + 0x2d, 0x7d, 0xaf, 0x13, 0x52, 0xc4, 0xde, 0xfa, 0x41, 0x47, 0xad, 0x63, + 0xb7, 0x03, 0x02, 0x15, 0x6c, 0xa6, 0x08, 0x08, 0x80, 0xf7, 0x3a, 0x50, + 0xe7, 0x07, 0x62, 0x56, 0xbb, 0x3d, 0x18, 0x14, 0x11, 0x02, 0x30, 0x80, + 0x18, 0xdc, 0x10, 0x83, 0x1b, 0x7e, 0x47, 0xdc, 0xfe, 0xc1, 0xed, 0x47, + 0xdc, 0xfb, 0x84, 0x28, 0x16, 0x77, 0x57, 0x36, 0x43, 0x90, 0x9a, 0x8a, + 0x92, 0x26, 0x1c, 0x66, 0x01, 0x98, 0xdf, 0x37, 0xee, 0xa0, 0x83, 0x31, + 0x8f, 0x21, 0x53, 0x84, 0x92, 0x2d, 0x31, 0x44, 0x40, 0xd4, 0xea, 0xf1, + 0x9b, 0xba, 0xb9, 0x6e, 0x8d, 0xf3, 0xb9, 0x4d, 0xe9, 0x99, 0xb2, 0x6a, + 0x68, 0xb2, 0x5a, 0x33, 0x53, 0xb7, 0x17, 0x10, 0x41, 0xe7, 0x97, 0xc8, + 0xab, 0x08, 0x01, 0x50, 0x5b, 0x50, 0xef, 0x45, 0x77, 0x14, 0x84, 0x85, + 0x84, 0xa0, 0xf8, 0x27, 0xf2, 0xef, 0x40, 0xac, 0x7d, 0x07, 0xed, 0xa4, + 0x2c, 0xcd, 0x10, 0x87, 0xdd, 0x93, 0x19, 0xd7, 0xd0, 0x97, 0xde, 0xa8, + 0x6d, 0xca, 0x58, 0x39, 0x81, 0xea, 0xf7, 0xb3, 0xde, 0xd4, 0xd3, 0xba, + 0xdb, 0xc9, 0x6b, 0x42, 0x04, 0x84, 0x71, 0xb8, 0xbb, 0xcf, 0x05, 0xc0, + 0x6c, 0xc3, 0x00, 0xc0, 0x9d, 0x5b, 0x07, 0x46, 0x6c, 0xf6, 0x77, 0xaf, + 0x54, 0x9a, 0x0e, 0x1b, 0x77, 0x50, 0x45, 0xc4, 0xae, 0xd3, 0x8c, 0x1b, + 0xa2, 0x3c, 0x93, 0x77, 0x23, 0x4c, 0xcb, 0x44, 0xfa, 0xfb, 0x25, 0x81, + 0xd5, 0x09, 0x48, 0x9f, 0xdd, 0x94, 0x9e, 0x70, 0xf0, 0x96, 0x97, 0x96, + 0x9a, 0x06, 0xcf, 0x48, 0x5b, 0xd2, 0xd0, 0x7b, 0x8d, 0xbb, 0x37, 0x01, + 0xf9, 0x7d, 0xa0, 0x63, 0xa2, 0x41, 0xbb, 0x8f, 0xb6, 0x6f, 0xcf, 0xdc, + 0x7f, 0xb2, 0x2e, 0xf5, 0xbd, 0x4b, 0x0b, 0x1c, 0xe1, 0x70, 0x45, 0x72, + 0x3c, 0x0d, 0xf6, 0xed, 0x19, 0xe5, 0x45, 0xe3, 0x87, 0xe7, 0x11, 0xc1, + 0x7a, 0x72, 0x4c, 0x3f, 0xdc, 0x40, 0x04, 0x64, 0x42, 0x6b, 0x77, 0xe9, + 0x88, 0x98, 0xfe, 0x40, 0x61, 0x5d, 0xca, 0xfa, 0x65, 0x59, 0xb7, 0x36, + 0xe7, 0xbd, 0xc2, 0xdd, 0x92, 0x4d, 0x5e, 0x1f, 0x6e, 0x29, 0x80, 0x5d, + 0xe8, 0x89, 0xe3, 0x89, 0xbf, 0x4d, 0x66, 0xf9, 0x93, 0x3b, 0x87, 0xa7, + 0xf2, 0xe2, 0xe5, 0xa2, 0x02, 0x02, 0x7c, 0x8f, 0x70, 0x53, 0x27, 0xce, + 0x87, 0x4d, 0x68, 0x55, 0x71, 0x30, 0xd2, 0x99, 0x46, 0x6c, 0xf6, 0xc4, + 0xce, 0xe1, 0x8f, 0xae, 0x4d, 0xfd, 0xcf, 0xa2, 0x52, 0xd4, 0x5e, 0x93, + 0xf7, 0x04, 0x77, 0x67, 0xfd, 0xd1, 0xe7, 0x03, 0xab, 0x8a, 0xdf, 0x31, + 0xa4, 0x88, 0x23, 0x3c, 0x7c, 0x79, 0xfe, 0xaf, 0x37, 0xa7, 0x5f, 0x2d, + 0xc9, 0x86, 0x26, 0x0b, 0x4f, 0x37, 0xee, 0x5e, 0xcf, 0x16, 0x46, 0x6c, + 0x47, 0x21, 0xec, 0xe5, 0x32, 0xec, 0x1f, 0x07, 0xe3, 0x49, 0x5d, 0xab, + 0x7d, 0xed, 0xe2, 0xdc, 0x44, 0x9a, 0xdd, 0xf3, 0x5a, 0x65, 0xd3, 0x00, + 0xcf, 0x09, 0xd4, 0xb4, 0x52, 0x3c, 0x09, 0x64, 0x0d, 0xa2, 0xf8, 0xb0, + 0x44, 0x2b, 0x85, 0xd1, 0x60, 0xfe, 0xef, 0x13, 0x07, 0xa9, 0x0f, 0x5f, + 0xdf, 0xb3, 0x7d, 0x70, 0x8d, 0x63, 0xfd, 0xed, 0x4b, 0xe5, 0x86, 0xcd, + 0x26, 0xd2, 0x4c, 0xd1, 0x69, 0xc6, 0xed, 0x85, 0xc0, 0xfc, 0x72, 0x92, + 0xc5, 0xc1, 0x04, 0x35, 0xc7, 0x5f, 0x9d, 0x93, 0x79, 0xf0, 0xb2, 0x82, + 0xc5, 0xa0, 0xaa, 0x7e, 0x47, 0x3b, 0xa1, 0x08, 0x72, 0xe3, 0xe1, 0xc7, + 0xcc, 0x1b, 0x9c, 0x12, 0xc5, 0x6f, 0x4a, 0x82, 0x1f, 0x00, 0xe0, 0xba, + 0x0d, 0xa9, 0x7f, 0x3c, 0x3f, 0x7b, 0xbc, 0xa6, 0xda, 0x05, 0xcf, 0xe9, + 0xc2, 0xed, 0x37, 0x01, 0xee, 0x2d, 0x4b, 0x88, 0x12, 0xe6, 0xcb, 0xa4, + 0x3a, 0x8c, 0x09, 0xd0, 0x52, 0x12, 0x71, 0x0c, 0x18, 0x4a, 0x32, 0x3b, + 0x89, 0xfa, 0x1c, 0x04, 0xc0, 0xc3, 0x6a, 0xf6, 0xc9, 0xf3, 0x94, 0x1c, + 0x3f, 0x54, 0x35, 0x69, 0xad, 0x5c, 0xd7, 0x75, 0x6c, 0x1b, 0x01, 0x29, + 0x50, 0xaf, 0xae, 0x1a, 0x77, 0xc4, 0x26, 0xc4, 0xec, 0x40, 0x3c, 0x3f, + 0xd1, 0x86, 0x9c, 0xd5, 0x1c, 0x60, 0x20, 0x30, 0xad, 0x8c, 0x0b, 0xae, + 0x2d, 0x6c, 0x40, 0xa4, 0x9e, 0x69, 0xfe, 0x56, 0xb8, 0xa3, 0xa3, 0x10, + 0x86, 0xad, 0x2e, 0x96, 0x57, 0x31, 0xa4, 0xaa, 0x4a, 0xbc, 0x05, 0x2d, + 0xb1, 0x88, 0x4a, 0x69, 0x22, 0xd7, 0x16, 0x02, 0xa3, 0x4b, 0xee, 0x55, + 0xe3, 0x8e, 0x28, 0x68, 0x12, 0xe6, 0xcb, 0x0d, 0x03, 0xfc, 0xd1, 0x63, + 0xf5, 0x87, 0x8e, 0xd6, 0x93, 0x1f, 0xdf, 0x2c, 0xb9, 0xfa, 0xf0, 0x92, + 0x3c, 0x5c, 0x6c, 0x9c, 0x58, 0xaa, 0x4b, 0x43, 0x0c, 0x31, 0xda, 0x2f, + 0x03, 0x69, 0x32, 0xd2, 0x5c, 0xd1, 0xf3, 0x13, 0x2c, 0x68, 0xbc, 0x51, + 0x28, 0x3e, 0xef, 0xa4, 0x19, 0x58, 0x00, 0x9f, 0x7e, 0x76, 0x11, 0xa1, + 0xf0, 0xe7, 0x1b, 0x33, 0x7d, 0xf1, 0xbb, 0x35, 0x79, 0xf9, 0xe4, 0xd0, + 0x07, 0xd6, 0xa6, 0x0f, 0x95, 0xdc, 0x57, 0x16, 0x9a, 0x33, 0xe5, 0x46, + 0x05, 0xac, 0xf5, 0x19, 0x9e, 0xb7, 0x51, 0x9b, 0xc4, 0xeb, 0x8d, 0xb1, + 0x9f, 0x23, 0x7d, 0x60, 0xa5, 0xbc, 0xa3, 0x0c, 0x8d, 0x3a, 0xb8, 0xd8, + 0x84, 0x4f, 0xed, 0x5f, 0x04, 0x80, 0x3e, 0x3a, 0x10, 0xa8, 0x65, 0xfd, + 0xfe, 0x11, 0xe7, 0xb6, 0xf3, 0x72, 0x00, 0x60, 0x08, 0x0e, 0xbc, 0x5b, + 0x7f, 0xec, 0x78, 0xfd, 0xbf, 0x8e, 0x35, 0x5f, 0x2b, 0xca, 0xcd, 0x83, + 0x56, 0xda, 0x42, 0x4d, 0xab, 0xc4, 0x8d, 0x9d, 0x63, 0x0d, 0x0a, 0x70, + 0xa1, 0x64, 0xfc, 0xe4, 0x58, 0x4d, 0x7f, 0xec, 0x8c, 0xf4, 0xbf, 0x4e, + 0xe5, 0x94, 0x6b, 0x6e, 0xdc, 0xbf, 0xf8, 0xd0, 0xd1, 0xe5, 0x3e, 0x5b, + 0x60, 0x61, 0xd9, 0x6d, 0x2f, 0x35, 0x43, 0xb8, 0x6c, 0x4d, 0xfa, 0xcb, + 0x17, 0x0f, 0x3f, 0x79, 0xf5, 0xd8, 0xad, 0xdb, 0xb2, 0xc7, 0xaa, 0xfa, + 0x54, 0xdd, 0x08, 0xc4, 0x58, 0x3b, 0xf1, 0x7e, 0x46, 0xf4, 0x3f, 0x0c, + 0x67, 0xe2, 0x64, 0xf9, 0xb2, 0xa6, 0xc8, 0x42, 0xb8, 0x65, 0x4b, 0x76, + 0xcf, 0x54, 0x4e, 0x37, 0xf4, 0x8d, 0x4f, 0x2f, 0x3c, 0x74, 0x64, 0x19, + 0x56, 0xd9, 0xce, 0x18, 0xe0, 0xf7, 0x5d, 0x52, 0x78, 0xe2, 0xea, 0xf1, + 0x73, 0x86, 0xc4, 0x5c, 0xc3, 0x24, 0xc7, 0x1d, 0x72, 0x01, 0x8f, 0x02, + 0x09, 0xf3, 0xbc, 0x05, 0x30, 0xbb, 0xac, 0x01, 0xe0, 0xee, 0xf7, 0xe7, + 0xee, 0x9a, 0xca, 0x99, 0xa6, 0xb9, 0xe1, 0xe9, 0x85, 0xbd, 0x47, 0x6a, + 0xfd, 0x22, 0x51, 0x44, 0xbb, 0x6c, 0xdc, 0xc9, 0xa0, 0xfe, 0x55, 0x55, + 0x96, 0x24, 0x09, 0x2b, 0x11, 0xee, 0xf8, 0x28, 0xd4, 0x31, 0x9c, 0x24, + 0x79, 0x9e, 0xb3, 0xb6, 0xa8, 0x7b, 0xa7, 0xf2, 0x77, 0xed, 0xc8, 0x91, + 0x34, 0x37, 0x3c, 0xbd, 0xb8, 0x37, 0x6a, 0x1f, 0xba, 0xc5, 0x69, 0xb8, + 0x35, 0x34, 0x7d, 0xf0, 0x07, 0xc7, 0x7f, 0xf4, 0x7a, 0xf1, 0x13, 0x67, + 0x3a, 0x67, 0x0f, 0xf1, 0xd9, 0x3a, 0x59, 0x98, 0x10, 0x77, 0xab, 0x5b, + 0xfb, 0x80, 0x98, 0xf5, 0x68, 0xf2, 0x6a, 0xf8, 0x49, 0xb7, 0xdd, 0x3b, + 0x95, 0xff, 0xfb, 0x1d, 0x79, 0x68, 0x9a, 0x1b, 0x9e, 0x9a, 0x5f, 0x71, + 0x1f, 0x82, 0xe8, 0xaf, 0x9e, 0x3e, 0xf1, 0xcc, 0x4c, 0xf9, 0x8a, 0xc9, + 0xdc, 0xa3, 0x57, 0x4e, 0xdc, 0x7f, 0x49, 0x61, 0xa1, 0xa9, 0x1b, 0xd4, + 0x1f, 0x37, 0x22, 0xb6, 0xc1, 0x77, 0x1c, 0x87, 0x41, 0x5c, 0xd9, 0x14, + 0xcf, 0xab, 0x02, 0xed, 0x4b, 0x17, 0xe5, 0xbe, 0x70, 0x71, 0x0e, 0x5c, + 0x7d, 0xc3, 0x53, 0x0b, 0x7b, 0xdf, 0xa9, 0x25, 0x41, 0xbf, 0x6b, 0xfa, + 0xc4, 0x33, 0x33, 0xe5, 0x3f, 0xda, 0x5e, 0x98, 0xfe, 0xc8, 0x3a, 0x00, + 0x3c, 0xbf, 0x20, 0x6e, 0xdf, 0x3a, 0x70, 0xa8, 0x24, 0x85, 0xc5, 0x56, + 0xc2, 0xed, 0xd5, 0xcf, 0x6b, 0x42, 0xbe, 0x92, 0x38, 0x21, 0x1f, 0xf4, + 0xb7, 0x7b, 0xa6, 0xf2, 0x5f, 0xb8, 0xb8, 0x00, 0xcd, 0xa0, 0x0e, 0x29, + 0x0b, 0x81, 0xc8, 0xb6, 0x7a, 0x13, 0xd6, 0x35, 0xed, 0x9a, 0x3e, 0xb1, + 0x7f, 0xa6, 0xbc, 0x73, 0x7b, 0x7e, 0xdf, 0x35, 0x6b, 0x9d, 0xce, 0xab, + 0x3d, 0x17, 0xe6, 0xce, 0x70, 0xcc, 0x62, 0x43, 0x61, 0x9b, 0xa7, 0xc4, + 0xe0, 0x6e, 0x5b, 0x59, 0xef, 0x31, 0x6b, 0xbf, 0x4c, 0xce, 0x63, 0x63, + 0x6c, 0xe9, 0x9e, 0xa9, 0xfc, 0x9e, 0x4b, 0x0a, 0xad, 0x7d, 0x78, 0xe0, + 0xed, 0xb6, 0x0e, 0x75, 0x45, 0x80, 0xb8, 0xdc, 0xa1, 0x1e, 0x4b, 0xae, + 0xd9, 0xf5, 0xa3, 0x36, 0xfa, 0x27, 0xae, 0x59, 0x67, 0x7b, 0x96, 0x3b, + 0x6b, 0x5b, 0x37, 0x4d, 0x66, 0xdf, 0x29, 0xd6, 0x19, 0x22, 0x32, 0x16, + 0x8d, 0x1b, 0x01, 0xd1, 0xe3, 0xe2, 0xfe, 0x44, 0xb6, 0x4a, 0x7e, 0x12, + 0xd5, 0xee, 0x9e, 0xca, 0x23, 0xc2, 0xdd, 0xcf, 0x17, 0x6f, 0x3d, 0xb8, + 0xa8, 0x0c, 0x9d, 0x5a, 0x76, 0x1f, 0x7c, 0xbb, 0xba, 0x69, 0x22, 0x33, + 0x7d, 0x6c, 0xb9, 0xae, 0xe6, 0xfe, 0xf8, 0xcc, 0xcc, 0x7f, 0x1e, 0xaa, + 0x3c, 0xfb, 0xfa, 0xd2, 0x15, 0xdb, 0xf3, 0x8f, 0xfb, 0xd1, 0xb7, 0xda, + 0xf5, 0x9b, 0x87, 0xbe, 0x3a, 0xb3, 0x54, 0x6d, 0x34, 0x07, 0x52, 0x0e, + 0xb0, 0x36, 0x75, 0x45, 0xf4, 0xa7, 0xb4, 0x56, 0x2a, 0xc3, 0x50, 0x3d, + 0x10, 0xc1, 0x3b, 0x56, 0xe0, 0xb1, 0xf1, 0xba, 0x7c, 0xf1, 0xa2, 0xfc, + 0x80, 0x60, 0xf7, 0xbf, 0x5e, 0xbb, 0xed, 0xf9, 0x92, 0x51, 0xaa, 0x60, + 0xd1, 0x68, 0x86, 0xd7, 0xa4, 0xf9, 0xc6, 0xe1, 0xa5, 0x07, 0xde, 0xae, + 0x48, 0x43, 0x7f, 0xb6, 0x63, 0xf8, 0xc1, 0x2b, 0x26, 0x04, 0x8b, 0x08, + 0x89, 0xdb, 0x72, 0xe2, 0x92, 0xf1, 0xd4, 0xf3, 0x73, 0x75, 0x61, 0x81, + 0x6d, 0x3b, 0x8c, 0x21, 0x51, 0x30, 0x05, 0xaf, 0x40, 0xe6, 0x56, 0xc1, + 0xab, 0x56, 0x26, 0xd3, 0x9f, 0x3f, 0x7f, 0x68, 0x44, 0xd0, 0x58, 0x9a, + 0x6f, 0x19, 0x4e, 0x0f, 0x67, 0x6c, 0x57, 0x19, 0xdb, 0xc2, 0x4d, 0x43, + 0x62, 0x4d, 0xc6, 0x22, 0x80, 0x3d, 0x17, 0x0d, 0x47, 0xa2, 0x6f, 0xb5, + 0x0b, 0x47, 0xec, 0xaa, 0x06, 0x22, 0x92, 0xd2, 0x05, 0x68, 0x7b, 0x40, + 0x38, 0xb4, 0xb6, 0x4d, 0xc9, 0x7f, 0xb0, 0x95, 0x94, 0x0f, 0x2a, 0xa2, + 0x14, 0x5f, 0x49, 0x85, 0x6f, 0x1e, 0xae, 0xbc, 0x3a, 0x57, 0xcb, 0x32, + 0xc3, 0x10, 0x85, 0xcd, 0xb9, 0xb0, 0x5a, 0xc6, 0x60, 0x5b, 0x0c, 0x11, + 0xff, 0xfd, 0xcd, 0xa5, 0x15, 0xc6, 0x5e, 0x34, 0xec, 0xb8, 0x06, 0x10, + 0x99, 0x31, 0xe4, 0xba, 0x4d, 0x40, 0x62, 0x5d, 0x9f, 0x6e, 0x41, 0xef, + 0xe6, 0x00, 0x88, 0x38, 0x5e, 0x27, 0xef, 0xa5, 0x50, 0x1c, 0xaf, 0x5a, + 0x3f, 0xc0, 0x7f, 0xbe, 0xe0, 0xee, 0x3e, 0x30, 0x4f, 0x44, 0x18, 0x55, + 0xd9, 0xfc, 0xec, 0x54, 0x63, 0x7d, 0x96, 0x6b, 0x29, 0x11, 0x80, 0x73, + 0xce, 0x85, 0x0d, 0x20, 0x95, 0xd2, 0x0c, 0xe1, 0xac, 0x2c, 0xff, 0xc9, + 0xc9, 0xfa, 0xee, 0x9f, 0xcf, 0xb7, 0xc4, 0x05, 0x06, 0x23, 0xc2, 0xb1, + 0x9a, 0xde, 0x38, 0xc0, 0x01, 0x80, 0x21, 0x92, 0x26, 0xd9, 0x94, 0xb6, + 0x6d, 0x23, 0xb2, 0xde, 0x89, 0x0f, 0x06, 0x6d, 0x80, 0xf7, 0x49, 0xf9, + 0x21, 0x3e, 0x38, 0x96, 0x62, 0x6f, 0x94, 0xd5, 0x93, 0xef, 0x34, 0xc1, + 0x75, 0xc1, 0x78, 0xae, 0x97, 0x3b, 0x7f, 0x87, 0x72, 0x62, 0x6b, 0xde, + 0xae, 0x49, 0x23, 0xa5, 0x02, 0x44, 0xc1, 0xb9, 0xb0, 0x6d, 0x44, 0xa9, + 0x94, 0x1a, 0xb4, 0xd9, 0x5c, 0x43, 0xdf, 0xf7, 0xc2, 0x62, 0x14, 0x7e, + 0x00, 0x80, 0x81, 0x2c, 0xbf, 0xa0, 0xe0, 0xb4, 0x0a, 0x26, 0xb4, 0xd0, + 0x18, 0x72, 0x5d, 0xe9, 0xa4, 0xec, 0xae, 0x4f, 0x87, 0x95, 0xe0, 0x31, + 0x77, 0xa7, 0x31, 0x3c, 0x16, 0xe0, 0x68, 0x4d, 0xed, 0x9c, 0x48, 0xfd, + 0xc5, 0x1f, 0x0c, 0x1b, 0x63, 0xc8, 0x98, 0xf0, 0xfd, 0xf8, 0x37, 0xde, + 0xaa, 0xfc, 0xe4, 0x37, 0xf5, 0xb3, 0xb2, 0xc2, 0x10, 0x29, 0x29, 0x11, + 0x81, 0x73, 0x2e, 0x6c, 0x0e, 0x08, 0xb3, 0x75, 0x77, 0x6d, 0x46, 0xdc, + 0xff, 0xd1, 0xd1, 0xc0, 0x04, 0xe8, 0xd9, 0xbd, 0xff, 0x38, 0x5c, 0x9d, + 0xc8, 0xb4, 0xb3, 0x03, 0x5a, 0x48, 0xc6, 0xb8, 0x4d, 0xd7, 0x4e, 0xd9, + 0x88, 0xac, 0xa7, 0x03, 0xf6, 0xae, 0x9a, 0x79, 0x42, 0xdc, 0xdd, 0x56, + 0x91, 0x34, 0xec, 0xb0, 0xeb, 0x36, 0xa4, 0xe2, 0xec, 0x78, 0xe3, 0xa0, + 0x78, 0xea, 0xe4, 0x89, 0x86, 0x31, 0x36, 0x43, 0x44, 0x94, 0x52, 0x02, + 0x80, 0x10, 0x42, 0x08, 0x31, 0xbf, 0x24, 0xff, 0x79, 0xcb, 0xe0, 0x9f, + 0x9e, 0x39, 0x10, 0x37, 0x76, 0x49, 0xd2, 0x5c, 0xb3, 0xbc, 0x66, 0xc0, + 0xea, 0xe1, 0xb4, 0x18, 0x19, 0x72, 0x9b, 0xd2, 0x76, 0x6c, 0x44, 0x6c, + 0xdd, 0xc1, 0x78, 0xd2, 0x40, 0x37, 0x0a, 0x25, 0xe6, 0xb1, 0x23, 0x36, + 0x7b, 0xb5, 0xe8, 0xea, 0xf8, 0xd3, 0xa1, 0x6d, 0x39, 0x31, 0x9e, 0xb6, + 0xe6, 0x1b, 0xda, 0x35, 0x64, 0x31, 0x64, 0x0c, 0xb5, 0x52, 0xae, 0x52, + 0x25, 0x45, 0x69, 0xc7, 0xb6, 0x3d, 0xb4, 0x33, 0xdc, 0x9e, 0x9b, 0x6f, + 0x64, 0x05, 0x6b, 0x79, 0x6b, 0x87, 0xf4, 0x00, 0x5a, 0x08, 0x64, 0xa4, + 0x6c, 0x22, 0x02, 0x63, 0x18, 0x41, 0x25, 0x56, 0xc5, 0x63, 0x07, 0x6d, + 0x76, 0x68, 0x49, 0xbf, 0x56, 0x8a, 0xfe, 0x5a, 0x42, 0x55, 0x9a, 0x0f, + 0xef, 0x3b, 0xf9, 0xe6, 0x92, 0x3a, 0x7b, 0xc8, 0xae, 0x29, 0xf8, 0x75, + 0x55, 0xa7, 0x84, 0x55, 0x72, 0xe9, 0xad, 0xc5, 0xe5, 0x71, 0x41, 0x39, + 0xdb, 0xfa, 0xdc, 0x0b, 0x4b, 0x0f, 0x1c, 0x89, 0xae, 0xa7, 0x35, 0xc1, + 0xcb, 0x8b, 0x6e, 0xc1, 0xb1, 0xda, 0x66, 0xd9, 0xcd, 0xbe, 0xad, 0x7d, + 0x20, 0x72, 0xa5, 0x0b, 0x00, 0x8c, 0xb5, 0xd3, 0x71, 0x48, 0x81, 0x64, + 0x3c, 0xd6, 0x66, 0x58, 0x94, 0xe6, 0xc7, 0x27, 0x1b, 0x91, 0xe8, 0x77, + 0xed, 0x9b, 0x7d, 0xfa, 0x8d, 0xca, 0xc7, 0x37, 0x66, 0xa7, 0x77, 0xad, + 0x79, 0x78, 0xe7, 0xf8, 0x55, 0xeb, 0x52, 0xc7, 0x8b, 0xee, 0xe6, 0x21, + 0xfe, 0x6f, 0x97, 0x8f, 0x3f, 0xb6, 0x73, 0x74, 0xf7, 0xb6, 0x81, 0x4a, + 0xc3, 0xdc, 0xf4, 0x5c, 0xf1, 0x81, 0x28, 0xee, 0xfd, 0xec, 0x5c, 0xf3, + 0xe5, 0xa2, 0xcc, 0x3b, 0xac, 0x8b, 0xbb, 0xcb, 0x1f, 0x00, 0x01, 0x19, + 0xeb, 0xe4, 0x07, 0x40, 0x86, 0x7e, 0x05, 0x92, 0xf3, 0x58, 0x00, 0x42, + 0x98, 0x48, 0x5b, 0xdf, 0xf9, 0x75, 0x3d, 0xe0, 0xf7, 0x15, 0x69, 0xae, + 0xda, 0x37, 0x7b, 0xe0, 0x70, 0xe5, 0x23, 0xdb, 0x73, 0x7b, 0x3f, 0x38, + 0x36, 0x96, 0xb2, 0xfe, 0x70, 0x22, 0x75, 0xdb, 0xb9, 0xb9, 0xd9, 0x45, + 0x77, 0xd7, 0xfa, 0xcc, 0x8d, 0x9b, 0xb3, 0x23, 0x29, 0xeb, 0xf6, 0xad, + 0x03, 0xf7, 0xee, 0xc8, 0x69, 0x4d, 0x37, 0x1d, 0x2c, 0x85, 0xf7, 0x61, + 0xef, 0x91, 0x2a, 0x01, 0x59, 0xcc, 0x87, 0xbb, 0x07, 0x08, 0x81, 0x31, + 0x34, 0x04, 0xae, 0x94, 0x08, 0xc8, 0x90, 0xf9, 0x76, 0xa0, 0x2f, 0x6e, + 0x6f, 0xa7, 0xb1, 0x14, 0x7b, 0x69, 0xd1, 0xfd, 0x96, 0x87, 0xfd, 0x57, + 0xa4, 0xb9, 0x7a, 0xdf, 0xec, 0xc1, 0x43, 0x95, 0x6b, 0xb6, 0xe7, 0x7e, + 0xb8, 0x6b, 0x4d, 0x97, 0x7e, 0xce, 0x37, 0x35, 0x08, 0xb6, 0x2c, 0x7b, + 0xba, 0xde, 0xb5, 0x3d, 0x7b, 0xef, 0x8e, 0x9c, 0x56, 0xf0, 0x97, 0x07, + 0x4b, 0xdf, 0xf2, 0x9c, 0xcd, 0x1c, 0x5a, 0x92, 0x8f, 0x1c, 0x5d, 0xde, + 0x38, 0x28, 0x08, 0x82, 0xb8, 0x5b, 0x89, 0xb7, 0xf5, 0x94, 0x21, 0x92, + 0x21, 0x57, 0x4a, 0x22, 0x13, 0x43, 0x25, 0x56, 0xe6, 0xb1, 0xd8, 0x4e, + 0x86, 0xeb, 0x33, 0xfc, 0x8b, 0xaf, 0x55, 0x16, 0x9a, 0x06, 0x00, 0x8a, + 0xae, 0xd9, 0xf5, 0xc4, 0xc9, 0x03, 0x87, 0x2a, 0xd7, 0x9e, 0x9f, 0xfb, + 0xc1, 0x55, 0x6b, 0x58, 0xe0, 0x4b, 0x15, 0x0c, 0xc8, 0xbf, 0x36, 0x77, + 0x9d, 0x97, 0xfd, 0xf2, 0xd4, 0x90, 0xd1, 0x74, 0xf3, 0xc1, 0xd2, 0x37, + 0x3b, 0xfb, 0x70, 0xc7, 0x8b, 0x25, 0x85, 0x90, 0xe2, 0x2c, 0x12, 0xb7, + 0x0f, 0x1d, 0x43, 0xad, 0xb5, 0xd6, 0xa6, 0x95, 0x46, 0x79, 0x7b, 0xa2, + 0x76, 0x77, 0x0c, 0x87, 0xd4, 0x30, 0x1f, 0x24, 0x80, 0xf1, 0x34, 0x9b, + 0x29, 0xab, 0x7f, 0x79, 0xb5, 0x72, 0xfb, 0x96, 0xcc, 0xad, 0xcf, 0xcd, + 0x1f, 0x7c, 0xab, 0x76, 0xed, 0xfb, 0xf2, 0x8f, 0x5d, 0x39, 0xc1, 0x30, + 0xaa, 0xfc, 0x0b, 0xb5, 0x3b, 0xcf, 0xcb, 0x22, 0xc2, 0x9d, 0xbf, 0x58, + 0xba, 0xe5, 0x85, 0xf2, 0x44, 0x9a, 0xcd, 0x2d, 0xcb, 0x27, 0x67, 0xeb, + 0xdb, 0xf3, 0x42, 0x03, 0x21, 0xc6, 0x7c, 0xc1, 0xc8, 0x1b, 0xd8, 0x99, + 0x9f, 0x4e, 0x93, 0xb7, 0x4f, 0x3c, 0x6e, 0xaf, 0x1c, 0x65, 0x60, 0xdb, + 0xa0, 0xf8, 0xf1, 0xac, 0xfb, 0xdf, 0xb3, 0x8d, 0x99, 0xf9, 0xc6, 0x27, + 0x2f, 0xcc, 0x3f, 0x7c, 0xc5, 0x38, 0xc6, 0x9d, 0x8e, 0x46, 0xbd, 0xf8, + 0xfc, 0xb9, 0x59, 0xce, 0xf0, 0x2b, 0x87, 0x6a, 0x7f, 0xf3, 0x62, 0x99, + 0x19, 0x3d, 0x39, 0xc8, 0x21, 0xac, 0x2b, 0x46, 0x25, 0xa4, 0xce, 0x9a, + 0x10, 0x05, 0xf2, 0x00, 0x0b, 0xd5, 0x0d, 0x1d, 0x73, 0x8c, 0x0e, 0xad, + 0x08, 0xb6, 0x05, 0x25, 0x0d, 0x5b, 0x47, 0xd3, 0x8f, 0xc4, 0xa1, 0xc7, + 0x38, 0xfc, 0x00, 0x00, 0x77, 0x6c, 0x1d, 0xb8, 0x72, 0x5c, 0x34, 0x0c, + 0x14, 0x32, 0x4e, 0xda, 0xe1, 0x86, 0x28, 0xe2, 0xf0, 0xa4, 0x3b, 0xbb, + 0xcf, 0x31, 0x30, 0x18, 0x46, 0xb1, 0x63, 0xfb, 0x7d, 0x71, 0x77, 0x23, + 0x04, 0x21, 0x70, 0x06, 0xa3, 0x0e, 0x43, 0x8b, 0x7f, 0xe6, 0x60, 0xe9, + 0x48, 0x45, 0xc6, 0x9c, 0x8d, 0x46, 0x5b, 0x91, 0x6b, 0xe8, 0x1f, 0x5e, + 0x29, 0xbf, 0x38, 0x57, 0x1f, 0x17, 0x60, 0x5b, 0xc8, 0x05, 0xe7, 0xdc, + 0xa2, 0x16, 0x69, 0x5b, 0x09, 0x37, 0x02, 0xa2, 0xd7, 0x73, 0xb9, 0xff, + 0xac, 0x22, 0x4c, 0x1d, 0xd0, 0x6f, 0x51, 0x41, 0x16, 0xc3, 0x11, 0x04, + 0x83, 0xef, 0x1d, 0x6f, 0xee, 0x3f, 0xd5, 0xf8, 0xec, 0xd9, 0xe9, 0x9b, + 0xcf, 0xc9, 0x8e, 0x38, 0x96, 0x17, 0x7c, 0xd8, 0xa2, 0x09, 0xe0, 0x91, + 0x5f, 0x2d, 0x7f, 0xed, 0xcd, 0xca, 0xf3, 0x8b, 0xee, 0x96, 0x41, 0xce, + 0x49, 0x2b, 0x89, 0x42, 0x70, 0xdb, 0x16, 0xc0, 0x50, 0x49, 0xc5, 0xd0, + 0xbf, 0x6b, 0x21, 0xbe, 0xe8, 0xf5, 0x6b, 0x1e, 0xc2, 0x9f, 0x08, 0x77, + 0xa0, 0x6e, 0x3b, 0x37, 0x67, 0x2d, 0xba, 0xf0, 0x4f, 0xbf, 0xac, 0x7e, + 0xfb, 0x48, 0xed, 0xda, 0xf5, 0x99, 0x0f, 0xad, 0x4d, 0x5d, 0x90, 0xb7, + 0xc7, 0x52, 0x2c, 0xcb, 0x11, 0x80, 0xd2, 0x1c, 0x01, 0xa0, 0xaa, 0x68, + 0xa6, 0x2c, 0xf7, 0x9f, 0x6a, 0x4e, 0x9f, 0xac, 0x1f, 0x98, 0x77, 0xb3, + 0x02, 0x2f, 0x28, 0x08, 0x43, 0x40, 0x00, 0x52, 0x29, 0x40, 0xb0, 0x85, + 0x70, 0x04, 0x47, 0x24, 0xa5, 0x34, 0x7a, 0xbd, 0xdf, 0xfb, 0xd7, 0xbb, + 0x15, 0x40, 0xe1, 0xaf, 0xdb, 0x24, 0xc5, 0xed, 0x73, 0x4e, 0x04, 0x45, + 0x90, 0x13, 0x30, 0x3c, 0x9a, 0x9e, 0x5f, 0x96, 0xf7, 0xbd, 0x51, 0xfe, + 0xfa, 0xdb, 0x95, 0x8d, 0x03, 0x62, 0x72, 0x88, 0xbb, 0x86, 0x26, 0xc7, + 0x52, 0xcf, 0xcc, 0xb9, 0x9f, 0xfe, 0xd9, 0xc2, 0xd1, 0x9a, 0x3a, 0x5a, + 0xd3, 0x8b, 0xae, 0xc9, 0xdb, 0x38, 0x39, 0xc4, 0x19, 0x82, 0x86, 0xae, + 0x9d, 0xa0, 0x52, 0x0a, 0x19, 0x08, 0x2e, 0x6c, 0x61, 0x03, 0x28, 0xa9, + 0x15, 0xf3, 0xfa, 0x2e, 0xfa, 0x7c, 0x19, 0x23, 0x8f, 0xd7, 0xbd, 0x75, + 0x5a, 0x42, 0xdc, 0x01, 0x6d, 0xb5, 0x31, 0x23, 0x19, 0x5e, 0x70, 0x32, + 0x75, 0x57, 0x95, 0xa4, 0xf9, 0xe9, 0xbb, 0x4d, 0x87, 0xe1, 0xba, 0x8c, + 0xf5, 0x4e, 0x55, 0xbd, 0x54, 0x34, 0x59, 0x8e, 0x79, 0x1b, 0xc7, 0xd3, + 0xbd, 0x2a, 0xdc, 0x17, 0xb4, 0x11, 0xdd, 0x76, 0xfd, 0x20, 0x6c, 0x5b, + 0x80, 0x24, 0xa5, 0x35, 0x6b, 0x4f, 0x86, 0x81, 0x60, 0x86, 0xe1, 0x7b, + 0x62, 0xf4, 0xab, 0xb5, 0x2a, 0xdc, 0xde, 0xb7, 0x04, 0xc0, 0x84, 0x95, + 0x42, 0xb4, 0x5c, 0x39, 0xc8, 0x19, 0x32, 0x68, 0x1a, 0xca, 0x0a, 0xcc, + 0xda, 0x56, 0x38, 0x52, 0x07, 0xec, 0x9b, 0x11, 0x4a, 0x29, 0x01, 0xc1, + 0xe6, 0xc2, 0xb1, 0x6d, 0x94, 0x52, 0x69, 0x8d, 0x51, 0x55, 0x5f, 0x94, + 0x0f, 0x44, 0x8b, 0x4f, 0x88, 0xdb, 0xef, 0xaa, 0x86, 0xb8, 0xc5, 0xd0, + 0x16, 0xae, 0x94, 0x04, 0xfe, 0x8c, 0xbe, 0xa2, 0x5f, 0x02, 0x03, 0x24, + 0xa6, 0xa4, 0x42, 0x44, 0x21, 0x84, 0x6d, 0xdb, 0xa0, 0xa4, 0x56, 0x2a, + 0x98, 0x92, 0x30, 0xba, 0xa4, 0xc4, 0x00, 0x1d, 0x5d, 0x2d, 0x6e, 0xf4, + 0x5d, 0xbd, 0x03, 0xe7, 0x16, 0x20, 0xb4, 0xaa, 0x19, 0x0f, 0xdc, 0x78, + 0xbf, 0xec, 0x5c, 0x5b, 0x23, 0x61, 0xcb, 0xa7, 0x39, 0x17, 0x36, 0x17, + 0x92, 0x40, 0x69, 0x7f, 0x5c, 0x0a, 0x5f, 0x31, 0x71, 0xa0, 0xa2, 0x84, + 0xf9, 0xa6, 0xc5, 0x45, 0x28, 0xf3, 0xa1, 0x17, 0xb4, 0x17, 0x76, 0x17, + 0x02, 0xf9, 0xd3, 0x7f, 0xb7, 0x1f, 0x30, 0x66, 0x29, 0xb4, 0x5c, 0x29, + 0x09, 0x3a, 0xee, 0x85, 0xe1, 0x3d, 0xc0, 0x40, 0x96, 0x6d, 0x1f, 0x35, + 0xbb, 0x46, 0x08, 0x2d, 0x84, 0x8d, 0x8c, 0x4b, 0xed, 0x2a, 0xa5, 0xbc, + 0x78, 0xe6, 0x24, 0x14, 0x15, 0xf0, 0x56, 0x14, 0xd2, 0x04, 0x83, 0x8e, + 0xb8, 0x7e, 0x2d, 0x94, 0x2b, 0x95, 0xf1, 0xb4, 0xd5, 0xcf, 0xa0, 0x7a, + 0xc7, 0xc2, 0x2b, 0xc5, 0x5c, 0x4f, 0x58, 0xd0, 0xda, 0x68, 0xa3, 0xa1, + 0x43, 0xef, 0xe3, 0xce, 0x3b, 0x10, 0x82, 0x62, 0x89, 0x88, 0x73, 0xc1, + 0x18, 0x03, 0x00, 0xa5, 0x15, 0x91, 0xe9, 0x2e, 0xdd, 0xa9, 0x86, 0xfe, + 0xe4, 0xf8, 0xd0, 0xa0, 0x63, 0x6b, 0x5a, 0xe6, 0x1c, 0xe8, 0xbb, 0x27, + 0xf5, 0xa5, 0x43, 0xe9, 0x5b, 0xb6, 0xa1, 0x8a, 0x20, 0xa7, 0xa1, 0xd3, + 0xfe, 0x55, 0x36, 0x8c, 0xbb, 0x54, 0xee, 0x27, 0x89, 0x3a, 0x5f, 0x03, + 0x09, 0xab, 0x6e, 0x91, 0xd1, 0x56, 0xea, 0xbb, 0xb3, 0x8a, 0x03, 0xe1, + 0xe6, 0xc7, 0x17, 0x4a, 0xd2, 0x10, 0x5a, 0x82, 0x5b, 0x44, 0xab, 0xc6, + 0xf7, 0x7f, 0xd2, 0x10, 0x51, 0x2a, 0x8d, 0xa4, 0xf3, 0x82, 0xfd, 0xef, + 0x00, 0x12, 0xc2, 0xcb, 0x56, 0xae, 0xbc, 0xa9, 0x59, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + }; + unsigned bitshares_icon_png_len = 6153; + + } + +} } // end namespace bts::client diff --git a/libraries/net/include/bts/net/node.hpp b/libraries/net/include/bts/net/node.hpp index 1b65849a2..41b6c8e93 100644 --- a/libraries/net/include/bts/net/node.hpp +++ b/libraries/net/include/bts/net/node.hpp @@ -175,6 +175,11 @@ namespace bts { namespace net { */ void listen_on_endpoint( const fc::ip::endpoint& ep ); + /** + * Call with true to enable listening for incoming connections + */ + void accept_incoming_connections(bool accept); + /** * Specifies the port upon which incoming connections should be accepted. * @param port the port to listen on diff --git a/libraries/net/node.cpp b/libraries/net/node.cpp index c2beff6be..0f0f97373 100644 --- a/libraries/net/node.cpp +++ b/libraries/net/node.cpp @@ -192,7 +192,10 @@ namespace bts { namespace net { // in the configuration directory (application data directory) struct node_configuration { + node_configuration() : accept_incoming_connections(true), wait_if_endpoint_is_busy(true) {} + fc::ip::endpoint listen_endpoint; + bool accept_incoming_connections; bool wait_if_endpoint_is_busy; /** * Originally, our p2p code just had a 'node-id' that was a random number identifying this node @@ -206,6 +209,7 @@ namespace bts { namespace net { } } } // end namespace bts::net::detail FC_REFLECT(bts::net::detail::node_configuration, (listen_endpoint) + (accept_incoming_connections) (wait_if_endpoint_is_busy) (private_key)); @@ -592,6 +596,7 @@ namespace bts { namespace net { namespace detail { void add_node( const fc::ip::endpoint& ep ); void connect_to( const fc::ip::endpoint& ep ); void listen_on_endpoint( const fc::ip::endpoint& ep ); + void accept_incoming_connections(bool accept); void listen_on_port( uint16_t port, bool wait_if_not_available ); fc::ip::endpoint get_actual_listening_endpoint() const; @@ -1654,57 +1659,6 @@ namespace bts { namespace net { namespace detail { void node_impl::on_connection_accepted_message( peer_connection* originating_peer, const connection_accepted_message& connection_accepted_message_received ) { VERIFY_CORRECT_THREAD(); -#if 0 - bool already_connected_to_this_peer = is_already_connected_to_id( hello_reply_message_received.node_id ); - - // store off the data provided in the hello message - originating_peer->user_agent = hello_reply_message_received.user_agent; - originating_peer->node_id = hello_reply_message_received.node_id; - originating_peer->core_protocol_version = hello_reply_message_received.core_protocol_version; - parse_hello_user_data_for_peer( originating_peer, hello_reply_message_received.user_data ); - - // report whether this peer will think we're behind a firewall - if( originating_peer->inbound_port != 0 ) - { - // if we sent inbound_port = 0 we were telling them that we're firewalled and don't accept incoming connections - if( originating_peer->inbound_address == hello_reply_message_received.remote_endpoint.get_address() && - originating_peer->outbound_port == hello_reply_message_received.remote_endpoint.port() ) - dlog( "peer ${peer} does not think we're behind a firewall", ("peer", originating_peer->get_remote_endpoint() ) ); - else - dlog( "peer ${peer} thinks we're firewalled (we think we were connecting from ${we_saw}, they saw ${they_saw})", - ( "peer", originating_peer->get_remote_endpoint() ) - ( "we_saw", fc::ip::endpoint(originating_peer->inbound_address, originating_peer->outbound_port ) ) - ( "they_saw", hello_reply_message_received.remote_endpoint ) ); - } - if( originating_peer->state == peer_connection::hello_sent && - originating_peer->direction == peer_connection_direction::outbound ) - { - if( already_connected_to_this_peer ) - { - dlog( "Established a connection with peer ${peer}, but I'm already connected to it. Closing the connection", - ( "peer", originating_peer->get_remote_endpoint() ) ); - disconnect_from_peer( originating_peer, "I'm already connected to you" ); - } -#ifdef ENABLE_P2P_DEBUGGING_API - else if( !_allowed_peers.empty() && - _allowed_peers.find( originating_peer->node_id ) == _allowed_peers.end() ) - { - dlog( "Established a connection with peer ${peer}, but it's not in my _accepted_peers list. Closing the connection", - ( "peer", originating_peer->get_remote_endpoint() ) ); - disconnect_from_peer( originating_peer, "You're not in my accepted_peers list" ); - } -#endif // ENABLE_P2P_DEBUGGING_API - else - { - dlog( "Received a reply to my \"hello\" from ${peer}, connection is accepted", ("peer", originating_peer->get_remote_endpoint() ) ); - dlog( "Remote server sees my connection as ${endpoint}", ("endpoint", hello_reply_message_received.remote_endpoint ) ); - originating_peer->state = peer_connection::connected; - originating_peer->send_message( address_request_message() ); - } - } - else - FC_THROW( "unexpected hello_reply_message from peer" ); -#endif dlog( "Received a connection_accepted in response to my \"hello\" from ${peer}", ("peer", originating_peer->get_remote_endpoint() ) ); originating_peer->negotiation_status = peer_connection::connection_negotiation_status::peer_connection_accepted; originating_peer->our_state = peer_connection::our_connection_state::connection_accepted; @@ -3068,11 +3022,12 @@ namespace bts { namespace net { namespace detail { fc::ecc::compact_signature signature = _node_configuration.private_key.sign_compact(shared_secret_encoder.result()); fc::ip::endpoint local_endpoint(peer->get_socket().local_endpoint()); + uint16_t listening_port = _node_configuration.accept_incoming_connections ? _actual_listening_endpoint.port() : 0; hello_message hello(_user_agent_string, core_protocol_version, local_endpoint.get_address(), - _actual_listening_endpoint.port(), + listening_port, local_endpoint.port(), _node_id, signature, @@ -3133,7 +3088,7 @@ namespace bts { namespace net { namespace detail { fc::ip::endpoint local_endpoint = new_peer->get_local_endpoint(); new_peer->inbound_address = local_endpoint.get_address(); - new_peer->inbound_port = _actual_listening_endpoint.port(); + new_peer->inbound_port = _node_configuration.accept_incoming_connections ? _actual_listening_endpoint.port() : 0; new_peer->outbound_port = local_endpoint.port(); new_peer->our_state = peer_connection::our_connection_state::just_connected; @@ -3182,11 +3137,15 @@ namespace bts { namespace net { namespace detail { if( !node_configuration_loaded ) { _node_configuration = detail::node_configuration(); - ilog( "generating new private key for this node" ); + uint32_t port = BTS_NET_DEFAULT_P2P_PORT; - if( BTS_TEST_NETWORK ) port += BTS_TEST_NETWORK_VERSION; + if( BTS_TEST_NETWORK ) + port += BTS_TEST_NETWORK_VERSION; _node_configuration.listen_endpoint.set_port( port ); + _node_configuration.accept_incoming_connections = true; _node_configuration.wait_if_endpoint_is_busy = false; + + ilog( "generating new private key for this node" ); _node_configuration.private_key = fc::ecc::private_key::generate(); } @@ -3219,6 +3178,12 @@ namespace bts { namespace net { namespace detail { void node_impl::listen_to_p2p_network() { VERIFY_CORRECT_THREAD(); + if (!_node_configuration.accept_incoming_connections) + { + wlog("accept_incoming_connections is false, p2p network will not accept any incoming connections"); + return; + } + assert( _node_id != fc::ecc::public_key_data() ); fc::ip::endpoint listen_endpoint = _node_configuration.listen_endpoint; @@ -3311,7 +3276,8 @@ namespace bts { namespace net { namespace detail { !_fetch_updated_peer_lists_loop_done.valid() && !_bandwidth_monitor_loop_done.valid() && !_dump_node_status_task_done.valid()); - _accept_loop_complete = fc::async( [=](){ accept_loop(); }, "accept_loop"); + if (_node_configuration.accept_incoming_connections) + _accept_loop_complete = fc::async( [=](){ accept_loop(); }, "accept_loop"); _p2p_network_connect_loop_done = fc::async( [=]() { p2p_network_connect_loop(); }, "p2p_network_connect_loop" ); _fetch_sync_items_loop_done = fc::async( [=]() { fetch_sync_items_loop(); }, "fetch_sync_items_loop" ); _fetch_item_loop_done = fc::async( [=]() { fetch_items_loop(); }, "fetch_items_loop" ); @@ -3426,6 +3392,9 @@ namespace bts { namespace net { namespace detail { ( "in_sync_with_us", !peer->peer_needs_sync_items_from_us )("in_sync_with_them", !peer->we_need_sync_items_from_peer ) ); if( peer->we_need_sync_items_from_peer ) ilog( " above peer has ${count} sync items we might need", ("count", peer->ids_of_items_to_get.size() ) ); + if (peer->inhibit_fetching_sync_blocks) + ilog( " we are not fetching sync blocks from the above peer (inhibit_fetching_sync_blocks == true)" ); + } for( const peer_connection_ptr& peer : _handshaking_connections ) { @@ -3503,6 +3472,13 @@ namespace bts { namespace net { namespace detail { save_node_configuration(); } + void node_impl::accept_incoming_connections(bool accept) + { + VERIFY_CORRECT_THREAD(); + _node_configuration.accept_incoming_connections = accept; + save_node_configuration(); + } + void node_impl::listen_on_port( uint16_t port, bool wait_if_not_available ) { VERIFY_CORRECT_THREAD(); @@ -3831,6 +3807,11 @@ namespace bts { namespace net { namespace detail { INVOKE_IN_IMPL(listen_on_endpoint, ep); } + void node::accept_incoming_connections(bool accept) + { + INVOKE_IN_IMPL(accept_incoming_connections, accept); + } + void node::listen_on_port( uint16_t port, bool wait_if_not_available ) { INVOKE_IN_IMPL(listen_on_port, port, wait_if_not_available); diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index cef9f4eaf..75370abec 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -553,6 +553,7 @@ namespace bts { namespace wallet { transaction_record = wallet_transaction_record(); transaction_record->created_time = block_timestamp; transaction_record->received_time = received_time; + transaction_record->record_id = record_id; } bool new_transaction = !transaction_record->is_confirmed; @@ -661,6 +662,19 @@ namespace bts { namespace wallet { } transaction_record->fee = total_fee; + /* For market orders with only the fee being a withdrawal for asset 0 (bids) */ + if( transaction_record->ledger_entries.size() > 1 ) + { + const auto entries = transaction_record->ledger_entries; + transaction_record->ledger_entries.clear(); + for( const auto& entry : entries ) + { + if( entry.amount != transaction_record->fee ) + transaction_record->ledger_entries.push_back( entry ); + } + + } + for( const auto& op : transaction.operations ) { switch( operation_type_enum( op.type ) ) diff --git a/tests/regression_tests/simple_wallet_commands/simple_wallet_commands.log b/tests/regression_tests/simple_wallet_commands/simple_wallet_commands.log index 7a01e86d2..35432f983 100644 --- a/tests/regression_tests/simple_wallet_commands/simple_wallet_commands.log +++ b/tests/regression_tests/simple_wallet_commands/simple_wallet_commands.log @@ -10,11 +10,12 @@ wallet (unlocked) >>> wallet_get_info "last_scanned_block_num": null, "last_scanned_block_timestamp": null, "transaction_fee": "0.50000 XTS", + "transaction_expiration_secs": 7200, "unlocked": true, "unlocked_until": "[redacted]", "unlocked_until_timestamp": "[redacted]", "scan_progress": "100.00 %", - "version": 103 + "version": 105 } wallet (unlocked) >>> wallet_set_automatic_backups false false @@ -103,11 +104,12 @@ wallet (unlocked) >>> wallet_get_info "last_scanned_block_num": null, "last_scanned_block_timestamp": null, "transaction_fee": "99,999.00000 XTS", + "transaction_expiration_secs": 7200, "unlocked": true, "unlocked_until": "[redacted]", "unlocked_until_timestamp": "[redacted]", "scan_progress": "100.00 %", - "version": 103 + "version": 105 } wallet (unlocked) >>> wallet_close OK diff --git a/tests/regression_tests/update_active_key/client0.log b/tests/regression_tests/update_active_key/client0.log index 257c490dd..f6a42f799 100644 --- a/tests/regression_tests/update_active_key/client0.log +++ b/tests/regression_tests/update_active_key/client0.log @@ -60,7 +60,7 @@ default (unlocked) >>> debug_wait_for_block_by_number 2 OK default (unlocked) >>> wallet_get_account delegate4 { - "index": 15, + "index": 16, "id": 5, "name": "delegate4", "public_data": null, @@ -94,7 +94,7 @@ default (unlocked) >>> wallet_get_account delegate4 } default (unlocked) >>> wallet_get_account delegate5 { - "index": 17, + "index": 18, "id": 6, "name": "delegate5", "public_data": null, diff --git a/tests/regression_tests/wallet_get_account/wallet_get_account.log b/tests/regression_tests/wallet_get_account/wallet_get_account.log index 0406a5927..41b844e0c 100644 --- a/tests/regression_tests/wallet_get_account/wallet_get_account.log +++ b/tests/regression_tests/wallet_get_account/wallet_get_account.log @@ -15,7 +15,7 @@ Returns: wallet_account_record default (unlocked) >>> wallet_get_account testaccount { - "index": 413, + "index": 414, "id": 0, "name": "testaccount", "public_data": null, diff --git a/tests/regression_tests/wallet_get_info/wallet_get_info.log b/tests/regression_tests/wallet_get_info/wallet_get_info.log index 531af396e..9aa1ff035 100644 --- a/tests/regression_tests/wallet_get_info/wallet_get_info.log +++ b/tests/regression_tests/wallet_get_info/wallet_get_info.log @@ -18,10 +18,11 @@ default (unlocked) >>> wallet_get_info "last_scanned_block_num": null, "last_scanned_block_timestamp": null, "transaction_fee": "0.50000 XTS", + "transaction_expiration_secs": 7200, "unlocked": true, "unlocked_until": "[redacted]", "unlocked_until_timestamp": "[redacted]", "scan_progress": "100.00 %", - "version": 103 + "version": 105 } default (unlocked) >>> quit diff --git a/tests/regression_tests/wallet_get_setting/wallet_get_setting.log b/tests/regression_tests/wallet_get_setting/wallet_get_setting.log index 7ed5d9202..0758bf679 100644 --- a/tests/regression_tests/wallet_get_setting/wallet_get_setting.log +++ b/tests/regression_tests/wallet_get_setting/wallet_get_setting.log @@ -18,25 +18,25 @@ default (unlocked) >>> wallet_set_setting ac y OK default (unlocked) >>> wallet_get_setting abc { - "index": 7, + "index": 8, "name": "abc", "value": 12345678 } default (unlocked) >>> wallet_get_setting 123 { - "index": 8, + "index": 9, "name": "123", "value": 2 } default (unlocked) >>> wallet_get_setting 1 { - "index": 9, + "index": 10, "name": "1", "value": "abcd" } default (unlocked) >>> wallet_get_setting ac { - "index": 10, + "index": 11, "name": "ac", "value": "y" } @@ -50,25 +50,25 @@ default (unlocked) >>> wallet_set_setting ac 1 OK default (unlocked) >>> wallet_get_setting abc { - "index": 7, + "index": 8, "name": "abc", "value": "HHH" } default (unlocked) >>> wallet_get_setting 123 { - "index": 8, + "index": 9, "name": "123", "value": "F2" } default (unlocked) >>> wallet_get_setting 1 { - "index": 9, + "index": 10, "name": "1", "value": 12345 } default (unlocked) >>> wallet_get_setting ac { - "index": 10, + "index": 11, "name": "ac", "value": 1 } diff --git a/tests/regression_tests/wallet_relock/wallet_relock.log b/tests/regression_tests/wallet_relock/wallet_relock.log index 076a2f06c..841497c3d 100644 --- a/tests/regression_tests/wallet_relock/wallet_relock.log +++ b/tests/regression_tests/wallet_relock/wallet_relock.log @@ -10,11 +10,12 @@ default (locked) >>> wallet_get_info "last_scanned_block_num": null, "last_scanned_block_timestamp": null, "transaction_fee": "0.50000 XTS", + "transaction_expiration_secs": 7200, "unlocked": false, "unlocked_until": null, "unlocked_until_timestamp": null, "scan_progress": null, - "version": 103 + "version": 105 } default (locked) >>> help wallet_unlock Usage: @@ -60,11 +61,12 @@ default (locked) >>> wallet_get_info "last_scanned_block_num": null, "last_scanned_block_timestamp": null, "transaction_fee": "0.50000 XTS", + "transaction_expiration_secs": 7200, "unlocked": false, "unlocked_until": null, "unlocked_until_timestamp": null, "scan_progress": null, - "version": 103 + "version": 105 } default (locked) >>> debug_wait 6 OK @@ -78,10 +80,11 @@ default (locked) >>> wallet_get_info "last_scanned_block_num": null, "last_scanned_block_timestamp": null, "transaction_fee": "0.50000 XTS", + "transaction_expiration_secs": 7200, "unlocked": false, "unlocked_until": null, "unlocked_until_timestamp": null, "scan_progress": null, - "version": 103 + "version": 105 } default (locked) >>> quit diff --git a/tests/regression_tests/wallet_set_transaction_scanning/wallet_set_transaction_scanning.log b/tests/regression_tests/wallet_set_transaction_scanning/wallet_set_transaction_scanning.log index 0fba1101b..6f1dc0192 100644 --- a/tests/regression_tests/wallet_set_transaction_scanning/wallet_set_transaction_scanning.log +++ b/tests/regression_tests/wallet_set_transaction_scanning/wallet_set_transaction_scanning.log @@ -8,11 +8,12 @@ default (unlocked) >>> wallet_get_info "last_scanned_block_num": null, "last_scanned_block_timestamp": null, "transaction_fee": "0.50000 XTS", + "transaction_expiration_secs": 7200, "unlocked": true, "unlocked_until": "[redacted]", "unlocked_until_timestamp": "[redacted]", "scan_progress": "100.00 %", - "version": 103 + "version": 105 } default (unlocked) >>> wallet_set_transaction_scanning false false @@ -26,11 +27,12 @@ default (unlocked) >>> wallet_get_info "last_scanned_block_num": null, "last_scanned_block_timestamp": null, "transaction_fee": "0.50000 XTS", + "transaction_expiration_secs": 7200, "unlocked": true, "unlocked_until": "[redacted]", "unlocked_until_timestamp": "[redacted]", "scan_progress": "100.00 %", - "version": 103 + "version": 105 } default (unlocked) >>> wallet_set_transaction_scanning true true @@ -44,10 +46,11 @@ default (unlocked) >>> wallet_get_info "last_scanned_block_num": null, "last_scanned_block_timestamp": null, "transaction_fee": "0.50000 XTS", + "transaction_expiration_secs": 7200, "unlocked": true, "unlocked_until": "[redacted]", "unlocked_until_timestamp": "[redacted]", "scan_progress": "100.00 %", - "version": 103 + "version": 105 } default (unlocked) >>> quit diff --git a/tests/regression_tests/wallet_transfer_from/wallet_transfer_from.log b/tests/regression_tests/wallet_transfer_from/wallet_transfer_from.log index 5ef10644b..934946ba3 100644 --- a/tests/regression_tests/wallet_transfer_from/wallet_transfer_from.log +++ b/tests/regression_tests/wallet_transfer_from/wallet_transfer_from.log @@ -31,7 +31,7 @@ Returns: transaction_record default (unlocked) >>> wallet_transfer_from 100 XTS delegate1 delegate0 test { - "index": 414, + "index": 415, "record_id": "9f0fad037607d57266cb20d94ed39e5b4cce8f7a", "block_num": 0, "is_virtual": false,