From 15a2c5f3629da7e1259e606811fa3637ca10031e Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 20 Oct 2023 14:14:52 +0000 Subject: [PATCH 1/9] cake wallet extension --- src/wallet/plain_wallet_api.cpp | 15 +-------------- src/wallet/plain_wallet_api_ex.h | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 14 deletions(-) create mode 100644 src/wallet/plain_wallet_api_ex.h diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index d628446e..49a8b08c 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -17,7 +17,7 @@ #include "common/config_encrypt_helper.h" #include "static_helpers.h" #include "wallet_helpers.h" - +#include "plain_wallet_api_ex.h" #define ANDROID_PACKAGE_NAME "com.zano_mobile" @@ -34,19 +34,6 @@ //TODO: global objects, subject to refactoring - -struct plain_wallet_instance -{ - plain_wallet_instance() :initialized(false), gjobs_counter(1) - {} - wallets_manager gwm; - std::atomic initialized; - - std::atomic gjobs_counter; - std::map gjobs; - epee::critical_section gjobs_lock; -}; - std::shared_ptr ginstance_ptr; #define GET_INSTANCE_PTR(ptr_name) \ diff --git a/src/wallet/plain_wallet_api_ex.h b/src/wallet/plain_wallet_api_ex.h new file mode 100644 index 00000000..a56cd108 --- /dev/null +++ b/src/wallet/plain_wallet_api_ex.h @@ -0,0 +1,31 @@ +// Copyright (c) 2014-2020 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +#pragma once + +#include + +#include "wallet2.h" + +namespace plain_wallet +{ + struct plain_wallet_instance +{ + plain_wallet_instance() :initialized(false), gjobs_counter(1) + {} + wallets_manager gwm; + std::atomic initialized; + + std::atomic gjobs_counter; + std::map gjobs; + epee::critical_section gjobs_lock; +}; + + + extern std::shared_ptr ginstance_ptr; + + + +} \ No newline at end of file From fe77c50e2c2260139600188b46689ddbb32f5398 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 20 Oct 2023 16:09:12 +0000 Subject: [PATCH 2/9] few cake-specifik tweaks --- src/wallet/plain_wallet_api.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index 49a8b08c..99b90450 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -205,6 +205,8 @@ namespace plain_wallet LOG_PRINT_L0("[INIT PLAIN_WALLET_INSTANCE] Ver:" << PROJECT_VERSION_LONG << "(" << BUILD_TYPE << ")"); + +#ifndef CAKEWALLET std::string wallets_folder = get_wallets_folder(); boost::system::error_code ec; boost::filesystem::create_directories(wallets_folder, ec); @@ -225,11 +227,15 @@ namespace plain_wallet err_result.error.message = LOCATION_STR + " \nmessage:" + ec.message(); return epee::serialization::store_t_to_json(err_result); } - +#endif std::atomic_store(&ginstance_ptr, ptr); +#ifndef CAKEWALLET epee::json_rpc::response ok_response = AUTO_VAL_INIT(ok_response); ok_response.result.return_code = API_RETURN_CODE_OK; return epee::serialization::store_t_to_json(ok_response); +#else + return API_RETURN_CODE_OK; +#endif } std::string get_appconfig(const std::string& encryption_key) From 0b563cc2b8a731d725fd5f83482ef5f79fa7c1ae Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 20 Oct 2023 16:39:43 +0000 Subject: [PATCH 3/9] fixed compilation issue --- src/wallet/plain_wallet_api.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index 99b90450..3235b435 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -34,7 +34,7 @@ //TODO: global objects, subject to refactoring -std::shared_ptr ginstance_ptr; +std::shared_ptr ginstance_ptr; #define GET_INSTANCE_PTR(ptr_name) \ auto ptr_name = std::atomic_load(&ginstance_ptr); \ From 2682a719b04631be5c40724d14690ab0626a73fc Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 25 Oct 2023 17:29:12 +0000 Subject: [PATCH 4/9] changes related to extend plain api for cake --- src/common/error_codes.h | 1 + src/wallet/plain_wallet_api.cpp | 46 ++++++++++++++++++++++++- src/wallet/plain_wallet_api.h | 9 +++++ src/wallet/view_iface.h | 4 ++- src/wallet/wallet_public_structs_defs.h | 20 +++++++++-- src/wallet/wallets_manager.cpp | 19 ++++++++++ src/wallet/wallets_manager.h | 1 + 7 files changed, 96 insertions(+), 4 deletions(-) diff --git a/src/common/error_codes.h b/src/common/error_codes.h index 313a9aad..0582e529 100644 --- a/src/common/error_codes.h +++ b/src/common/error_codes.h @@ -4,6 +4,7 @@ #pragma once +#include "../currency_core/basic_api_response_codes.h" #define API_RETURN_CODE_OK BASIC_RESPONSE_STATUS_OK #define API_RETURN_CODE_FAIL BASIC_RESPONSE_STATUS_FAILED diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index 3235b435..38626878 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -161,7 +161,19 @@ namespace plain_wallet ok_response.result.return_code = API_RETURN_CODE_OK; return epee::serialization::store_t_to_json(ok_response); } - + + std::string init(const std::string& address, const std::string& working_dir, int log_level) + { + epee::net_utils::http::url_content url_data = AUTO_VAL_INIT(url_data); + if(!epee::net_utils::parse_url(address, url_data)) + { + LOG_ERROR("Failed to parse address"); + return API_RETURN_CODE_BAD_ARG; + } + return init(url_data.ip, url_data.port, const std::string& working_dir, int log_level); + } + + std::string init(const std::string& ip, const std::string& port, const std::string& working_dir, int log_level) { auto local_ptr = std::atomic_load(&ginstance_ptr); @@ -268,6 +280,11 @@ namespace plain_wallet return epee::serialization::store_t_to_json(ok_response); } } + bool is_wallet_exist(const std::string& path) + { + boost::system::error_code ec; + return exists(path, ec); + } std::string generate_random_key(uint64_t lenght) { @@ -608,4 +625,31 @@ namespace plain_wallet return res; } + std::string get_wallet_info(hwallet h) + { + GET_INSTANCE_PTR(inst_ptr); + epee::json_rpc::response, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response); + + struct wallet_extended_info + { + view::wallet_info wi; + view::wallet_info_extended wi_extended; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wi) + KV_SERIALIZE(wi_extended) + END_KV_SERIALIZE_MAP() + } + wallet_extended_info wei = AUTO_VAL_INIT(wei); + + inst_ptr->gwm.get_wallet_info(h, wei.wi); + inst_ptr->gwm.get_wallet_info_extended(h, wei.wi_extended); + return epee::serialization::store_t_to_json(wei); + } + std::string reset_wallet_password(hwallet h, const std::string& password) + { + GET_INSTANCE_PTR(inst_ptr); + return inst_ptr->gwm.reset_wallet_password(h, password); + } + } \ No newline at end of file diff --git a/src/wallet/plain_wallet_api.h b/src/wallet/plain_wallet_api.h index 40873070..8f0a4b1b 100644 --- a/src/wallet/plain_wallet_api.h +++ b/src/wallet/plain_wallet_api.h @@ -6,10 +6,12 @@ #pragma once #include +#include "../common/error_codes.h" namespace plain_wallet { typedef int64_t hwallet; + std::string init(const std::string& address, const std::string& working_dir, int log_level); std::string init(const std::string& ip, const std::string& port, const std::string& working_dir, int log_level); std::string reset(); std::string set_log_level(int log_level); @@ -31,6 +33,7 @@ namespace plain_wallet std::string generate(const std::string& path, const std::string& password); std::string get_opened_wallets(); + std::string get_wallet_status(hwallet h); std::string close_wallet(hwallet h); std::string invoke(hwallet h, const std::string& params); @@ -39,4 +42,10 @@ namespace plain_wallet std::string async_call(const std::string& method_name, uint64_t instance_id, const std::string& params); std::string try_pull_result(uint64_t); std::string sync_call(const std::string& method_name, uint64_t instance_id, const std::string& params); + + //cake wallet api extension + bool is_wallet_exist(const std::string& path); + std::string get_wallet_info(hwallet h); + std::string reset_wallet_password(hwallet h, const std::string& password); + } \ No newline at end of file diff --git a/src/wallet/view_iface.h b/src/wallet/view_iface.h index ebce8c5e..d315a041 100644 --- a/src/wallet/view_iface.h +++ b/src/wallet/view_iface.h @@ -210,7 +210,7 @@ public: }; typedef tools::wallet_public::wallet_info wallet_info; - + typedef tools::wallet_public::wallet_info_extra wallet_info_extra; typedef tools::wallet_public::wallet_entry_info wallet_entry_info; @@ -591,6 +591,7 @@ public: bool is_in_long_refresh; uint64_t progress; uint64_t current_daemon_height; + uint64_t current_wallet_height; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(is_daemon_connected) @@ -598,6 +599,7 @@ public: KV_SERIALIZE(is_in_long_refresh) KV_SERIALIZE(progress) KV_SERIALIZE(current_daemon_height) + KV_SERIALIZE(current_wallet_height) END_KV_SERIALIZE_MAP() }; diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 54963525..5cd9fab3 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -1463,11 +1463,27 @@ namespace wallet_public KV_SERIALIZE(address) KV_SERIALIZE(view_sec_key) KV_SERIALIZE(path) - KV_SERIALIZE(is_auditable); - KV_SERIALIZE(is_watch_only); + KV_SERIALIZE(is_auditable) + KV_SERIALIZE(is_watch_only) END_KV_SERIALIZE_MAP() }; + struct wallet_info_extra + { + std::string view_private_key; + std::string view_public_key; + std::string spend_private_key; + std::string spend_public_key; + std::string seed; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(view_private_key) + KV_SERIALIZE(view_public_key) + KV_SERIALIZE(spend_private_key) + KV_SERIALIZE(spend_public_key) + KV_SERIALIZE(seed) + END_KV_SERIALIZE_MAP() + } struct wallet_entry_info diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index 9775ebfd..3889ea4c 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -1613,6 +1613,7 @@ std::string wallets_manager::get_wallet_status(uint64_t wallet_id) wsi.progress = wo.w.unlocked_get().get()->get_sync_progress(); wsi.wallet_state = wo.wallet_state; wsi.current_daemon_height = m_last_daemon_height; + wsi.current_wallet_height = wo.w.unlocked_get().get()->get_top_block_height(); return epee::serialization::store_t_to_json(wsi); } @@ -1648,6 +1649,24 @@ std::string wallets_manager::get_wallet_info(uint64_t wallet_id, view::wallet_in GET_WALLET_OPT_BY_ID(wallet_id, w); return get_wallet_info(w, wi); } + +std::string wallets_manager::get_wallet_info_extra(uint64_t wallet_id, view::wallet_info_extra& wi) +{ + GET_WALLET_OPT_BY_ID(wallet_id, wo); + + auto locker_object = wo.w.lock(); + tools::wallet2& rw = *(*(*locker_object)); //this looks a bit crazy, i know + + auto& keys = rw.get_account().get_keys(); + + wi.view_private_key = epee::string_tools::pod_to_hex(keys.view_secret_key); + wi.view_public_key = epee::string_tools::pod_to_hex(keys.account_address.view_public_key); + wi.spend_private_key = epee::string_tools::pod_to_hex(keys.spend_secret_key); + wi.spend_public_key = epee::string_tools::pod_to_hex(keys.account_address.spend_public_key); + wi.seed = rw.get_account().get_seed_phrase(""); + return API_RETURN_CODE_OK; +} + std::string wallets_manager::get_contracts(size_t wallet_id, std::vector& contracts) { tools::wallet2::escrow_contracts_container cc; diff --git a/src/wallet/wallets_manager.h b/src/wallet/wallets_manager.h index bcd4c794..012aba5e 100644 --- a/src/wallet/wallets_manager.h +++ b/src/wallet/wallets_manager.h @@ -106,6 +106,7 @@ public: std::string run_wallet(uint64_t wallet_id); std::string get_recent_transfers(size_t wallet_id, uint64_t offset, uint64_t count, view::transfers_array& tr_hist, bool exclude_mining_txs = false); std::string get_wallet_info(uint64_t wallet_id, view::wallet_info& wi); + std::string get_wallet_info_extra(uint64_t wallet_id, view::wallet_info_extra& wi); std::string get_contracts(size_t wallet_id, std::vector& contracts); std::string create_proposal(const view::create_proposal_param_gui& cpp); std::string accept_proposal(size_t wallet_id, const crypto::hash& contract_id); From 54d229f746b20005f28ea3012611cd92c4891c47 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 25 Oct 2023 18:51:53 +0000 Subject: [PATCH 5/9] fixed compilation issues --- src/wallet/plain_wallet_api.cpp | 51 ++++++++++++------------- src/wallet/wallet_public_structs_defs.h | 2 +- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index 38626878..1413e093 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -162,17 +162,6 @@ namespace plain_wallet return epee::serialization::store_t_to_json(ok_response); } - std::string init(const std::string& address, const std::string& working_dir, int log_level) - { - epee::net_utils::http::url_content url_data = AUTO_VAL_INIT(url_data); - if(!epee::net_utils::parse_url(address, url_data)) - { - LOG_ERROR("Failed to parse address"); - return API_RETURN_CODE_BAD_ARG; - } - return init(url_data.ip, url_data.port, const std::string& working_dir, int log_level); - } - std::string init(const std::string& ip, const std::string& port, const std::string& working_dir, int log_level) { @@ -250,6 +239,18 @@ namespace plain_wallet #endif } + std::string init(const std::string& address, const std::string& working_dir, int log_level) + { + epee::net_utils::http::url_content url_data = AUTO_VAL_INIT(url_data); + if(!epee::net_utils::parse_url(address, url_data)) + { + LOG_ERROR("Failed to parse address"); + return API_RETURN_CODE_BAD_ARG; + } + return init(url_data.host, std::to_string(url_data.port), working_dir, log_level); + } + + std::string get_appconfig(const std::string& encryption_key) { std::string res_str; @@ -283,7 +284,7 @@ namespace plain_wallet bool is_wallet_exist(const std::string& path) { boost::system::error_code ec; - return exists(path, ec); + return boost::filesystem::exists(path, ec); } std::string generate_random_key(uint64_t lenght) @@ -625,25 +626,23 @@ namespace plain_wallet return res; } + struct wallet_extended_info + { + view::wallet_info wi; + view::wallet_info_extra wi_extended; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wi) + KV_SERIALIZE(wi_extended) + END_KV_SERIALIZE_MAP() + }; + std::string get_wallet_info(hwallet h) { GET_INSTANCE_PTR(inst_ptr); - epee::json_rpc::response, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response); - - struct wallet_extended_info - { - view::wallet_info wi; - view::wallet_info_extended wi_extended; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(wi) - KV_SERIALIZE(wi_extended) - END_KV_SERIALIZE_MAP() - } wallet_extended_info wei = AUTO_VAL_INIT(wei); - inst_ptr->gwm.get_wallet_info(h, wei.wi); - inst_ptr->gwm.get_wallet_info_extended(h, wei.wi_extended); + inst_ptr->gwm.get_wallet_info_extra(h, wei.wi_extended); return epee::serialization::store_t_to_json(wei); } std::string reset_wallet_password(hwallet h, const std::string& password) diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 5cd9fab3..9658dca3 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -1483,7 +1483,7 @@ namespace wallet_public KV_SERIALIZE(spend_public_key) KV_SERIALIZE(seed) END_KV_SERIALIZE_MAP() - } + }; struct wallet_entry_info From f19acdee4b413bc881d04dd630380bb62db8ddcd Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Thu, 26 Oct 2023 12:56:37 +0000 Subject: [PATCH 6/9] revoked unneeded changes --- src/wallet/plain_wallet_api.cpp | 13 +++++++++++++ src/wallet/plain_wallet_api_ex.h | 31 ------------------------------- 2 files changed, 13 insertions(+), 31 deletions(-) delete mode 100644 src/wallet/plain_wallet_api_ex.h diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index 1413e093..8105ff83 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -34,6 +34,19 @@ //TODO: global objects, subject to refactoring +struct plain_wallet_instance +{ + plain_wallet_instance() :initialized(false), gjobs_counter(1) + {} + wallets_manager gwm; + std::atomic initialized; + + std::atomic gjobs_counter; + std::map gjobs; + epee::critical_section gjobs_lock; +}; + + std::shared_ptr ginstance_ptr; #define GET_INSTANCE_PTR(ptr_name) \ diff --git a/src/wallet/plain_wallet_api_ex.h b/src/wallet/plain_wallet_api_ex.h deleted file mode 100644 index a56cd108..00000000 --- a/src/wallet/plain_wallet_api_ex.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2014-2020 Zano Project -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - - -#pragma once - -#include - -#include "wallet2.h" - -namespace plain_wallet -{ - struct plain_wallet_instance -{ - plain_wallet_instance() :initialized(false), gjobs_counter(1) - {} - wallets_manager gwm; - std::atomic initialized; - - std::atomic gjobs_counter; - std::map gjobs; - epee::critical_section gjobs_lock; -}; - - - extern std::shared_ptr ginstance_ptr; - - - -} \ No newline at end of file From 767dbebe54c56a2dbd733fce99394d6ce3e21bc7 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Thu, 26 Oct 2023 13:19:06 +0000 Subject: [PATCH 7/9] removed include of deleted file --- src/wallet/plain_wallet_api.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index 8105ff83..e8c923a3 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -17,7 +17,6 @@ #include "common/config_encrypt_helper.h" #include "static_helpers.h" #include "wallet_helpers.h" -#include "plain_wallet_api_ex.h" #define ANDROID_PACKAGE_NAME "com.zano_mobile" From 9dd4f107b63b16eeab5d8ad805bc71c0eaea3ffb Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Thu, 26 Oct 2023 14:32:56 +0000 Subject: [PATCH 8/9] Fix compilation issue --- src/wallet/plain_wallet_api.cpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index e8c923a3..deb09878 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -33,20 +33,7 @@ //TODO: global objects, subject to refactoring -struct plain_wallet_instance -{ - plain_wallet_instance() :initialized(false), gjobs_counter(1) - {} - wallets_manager gwm; - std::atomic initialized; - std::atomic gjobs_counter; - std::map gjobs; - epee::critical_section gjobs_lock; -}; - - -std::shared_ptr ginstance_ptr; #define GET_INSTANCE_PTR(ptr_name) \ auto ptr_name = std::atomic_load(&ginstance_ptr); \ @@ -71,6 +58,22 @@ void static_destroy_handler() namespace plain_wallet { + struct plain_wallet_instance + { + plain_wallet_instance() :initialized(false), gjobs_counter(1) + {} + wallets_manager gwm; + std::atomic initialized; + + std::atomic gjobs_counter; + std::map gjobs; + epee::critical_section gjobs_lock; + }; + + std::shared_ptr ginstance_ptr; + + + typedef epee::json_rpc::response error_response; From 208f50ce64cb2cc5056061498bcd2b5280a95c7f Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Mon, 30 Oct 2023 19:22:33 +0000 Subject: [PATCH 9/9] additional changes for cake --- src/wallet/plain_wallet_api.cpp | 6 ++++++ src/wallet/plain_wallet_api.h | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index deb09878..8b720c7b 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -666,4 +666,10 @@ namespace plain_wallet return inst_ptr->gwm.reset_wallet_password(h, password); } + + // 0 (default), 1 (unimportant), 2 (normal), 3 (elevated), 4 (priority) + uint64_t get_current_tx_fee(uint64_t priority) + { + return TX_DEFAULT_FEE; + } } \ No newline at end of file diff --git a/src/wallet/plain_wallet_api.h b/src/wallet/plain_wallet_api.h index 8f0a4b1b..f12eba03 100644 --- a/src/wallet/plain_wallet_api.h +++ b/src/wallet/plain_wallet_api.h @@ -47,5 +47,7 @@ namespace plain_wallet bool is_wallet_exist(const std::string& path); std::string get_wallet_info(hwallet h); std::string reset_wallet_password(hwallet h, const std::string& password); + uint64_t get_current_tx_fee(uint64_t priority); // 0 (default), 1 (unimportant), 2 (normal), 3 (elevated), 4 (priority) +} + -} \ No newline at end of file