Updated on 2026-08-14
This commit is contained in:
commit
94a78fb08c
142 changed files with 5224 additions and 1101 deletions
|
|
@ -11,18 +11,18 @@ public enum Blockchain {
|
|||
BitcoinTestNet("BTC/test", "BTC", 100000000.0, R.drawable.ic_logo_bitcoin_testnet, "Bitcoin Testnet"),
|
||||
BitcoinDual("BTC/dual", "BTC", 100000000.0, R.drawable.ic_logo_bitcoin, "Bitcoin"),
|
||||
Ethereum("ETH", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"),
|
||||
EthereumId("ETH/ID", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum ID"),
|
||||
EthereumId("ETH/ID", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"),
|
||||
EthereumTestNet("ETH/test", "ETH", 1.0, R.drawable.ic_logo_ethereum_testnet, "Ethereum Testnet"),
|
||||
Token("Token", "ETH", 1.0, R.drawable.ic_logo_bat_token, "Ethereum"),
|
||||
NftToken("NftToken", "", 1.0, R.drawable.tangem2, "Ethereum"),
|
||||
Token("Token", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"),
|
||||
NftToken("NftToken", "", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"),
|
||||
BitcoinCash("BCH", "BCH", 100000000.0, R.drawable.ic_logo_bitcoin_cash, "Bitcoin Cash"),
|
||||
Litecoin("LTC", "LTC", 100000000.0, R.drawable.tangem2, "Litecoin"),
|
||||
Litecoin("LTC", "LTC", 100000000.0, R.drawable.ic_logo_litecoin, "Litecoin"),
|
||||
Rootstock("RSK", "RBTC", 1.0, R.drawable.tangem2, "RSK"),
|
||||
RootstockToken("RskToken", "RBTC", 1.0, R.drawable.tangem2, "RSK"),
|
||||
Cardano("CARDANO", "ADA", 1000000.0, R.drawable.tangem2, "Cardano"),
|
||||
Ripple ("XRP", "XRP", 1000000.0, R.drawable.tangem2, "XRP"),
|
||||
Binance("BINANCE", "BNB", 100000000.0, R.drawable.tangem2, "Binance"),
|
||||
BinanceTestNet("BINANCE/test", "BNB", 100000000.0, R.drawable.tangem2, "Binance Testnet"),
|
||||
Ripple ("XRP", "XRP", 1000000.0, R.drawable.ic_logo_xrp, "XRP"),
|
||||
Binance("BINANCE", "BNB", 100000000.0, R.drawable.ic_logo_binance, "Binance"),
|
||||
BinanceTestNet("BINANCE/test", "BNB", 100000000.0, R.drawable.ic_logo_binance, "Binance Testnet"),
|
||||
Matic("MATIC", "MTX", 1.0, R.drawable.tangem2, "Matic"),
|
||||
MaticTestNet("MATIC/test", "MTX", 1.0, R.drawable.tangem2, "Matic Testnet"),
|
||||
Stellar("XLM", "XLM", 10000000.0, R.drawable.ic_logo_stellar, "Stellar"),
|
||||
|
|
@ -31,7 +31,7 @@ public enum Blockchain {
|
|||
StellarTag("XLM-Tag", "XLM", 1000000.0, R.drawable.ic_logo_stellar, "Stellar"),
|
||||
Eos("EOS", "EOS", 10000.0, R.drawable.tangem2, "EOS"),
|
||||
Ducatus("DUC", "DUC", 100000000.0, R.drawable.tangem2, "Ducatus"),
|
||||
Tezos("TEZOS", "XTZ", 10000000.0, R.drawable.tangem2, "Tezos");
|
||||
Tezos("TEZOS", "XTZ", 10000000.0, R.drawable.ic_logo_tezos, "Tezos");
|
||||
|
||||
Blockchain(String ID, String currency, double multiplier, int imageResource, String officialName) {
|
||||
mID = ID;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
|
|||
|
||||
private fun navigateSafelyToMainFragment() {
|
||||
try {
|
||||
findNavController(R.id.nav_host_fragment).navigate(R.id.main)
|
||||
findNavController(R.id.nav_host_fragment).popBackStack()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Log.w(this::class.java.simpleName, e.message)
|
||||
} catch (e: IllegalStateException) {
|
||||
|
|
|
|||
|
|
@ -481,7 +481,6 @@ public class EthEngine extends CoinEngine {
|
|||
BigInteger l = new BigInteger(balanceCap, 16);
|
||||
coinData.setBalanceReceived(true);
|
||||
coinData.setBalanceInInternalUnits(new CoinEngine.InternalAmount(l, "wei"));
|
||||
|
||||
// Log.i("$TAG eth_get_balance", balanceCap)
|
||||
}
|
||||
break;
|
||||
|
|
@ -491,8 +490,9 @@ public class EthEngine extends CoinEngine {
|
|||
nonce = nonce.substring(2);
|
||||
BigInteger count = new BigInteger(nonce, 16);
|
||||
coinData.setConfirmedTXCount(count);
|
||||
|
||||
|
||||
if (serverApiInfura.isRequestsSequenceCompleted()) { //getting balances after checking for pending to avoid showing old balance as verified
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
}
|
||||
// Log.i("$TAG eth_getTransCount", nonce)
|
||||
}
|
||||
break;
|
||||
|
|
@ -502,7 +502,9 @@ public class EthEngine extends CoinEngine {
|
|||
pending = pending.substring(2);
|
||||
BigInteger count = new BigInteger(pending, 16);
|
||||
coinData.setUnconfirmedTXCount(count);
|
||||
|
||||
if (serverApiInfura.isRequestsSequenceCompleted()) { //getting balances after checking for pending to avoid showing old balance as verified
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
}
|
||||
// Log.i("$TAG eth_getPendingTxCount", pending)
|
||||
}
|
||||
break;
|
||||
|
|
@ -582,7 +584,6 @@ public class EthEngine extends CoinEngine {
|
|||
};
|
||||
serverApiBlockcypher.setResponseListener(blockcypherListener);
|
||||
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_GET_TRANSACTION_COUNT, 67, coinData.getWallet(), "", "");
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_GET_PENDING_COUNT, 67, coinData.getWallet(), "", "");
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,6 @@ public class MaticTokenEngine extends TokenEngine {
|
|||
BigInteger l = new BigInteger(balanceCap, 16);
|
||||
coinData.setBalanceReceived(true);
|
||||
coinData.setBalanceAlterInInternalUnits(new CoinEngine.InternalAmount(l, "wei"));
|
||||
|
||||
// Log.i("$TAG eth_get_balance", balanceCap)
|
||||
}
|
||||
break;
|
||||
|
|
@ -119,8 +118,10 @@ public class MaticTokenEngine extends TokenEngine {
|
|||
nonce = nonce.substring(2);
|
||||
BigInteger count = new BigInteger(nonce, 16);
|
||||
coinData.setConfirmedTXCount(count);
|
||||
|
||||
|
||||
if (serverApiMatic.isRequestsSequenceCompleted()) { //getting balances after checking for pending to avoid showing old balance as verified
|
||||
serverApiMatic.requestData(ServerApiMatic.MATIC_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), "");
|
||||
serverApiMatic.requestData(ServerApiMatic.MATIC_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
}
|
||||
// Log.i("$TAG eth_getTransCount", nonce)
|
||||
}
|
||||
break;
|
||||
|
|
@ -130,7 +131,10 @@ public class MaticTokenEngine extends TokenEngine {
|
|||
pending = pending.substring(2);
|
||||
BigInteger count = new BigInteger(pending, 16);
|
||||
coinData.setUnconfirmedTXCount(count);
|
||||
|
||||
if (serverApiMatic.isRequestsSequenceCompleted()) { //getting balances after checking for pending to avoid showing old balance as verified
|
||||
serverApiMatic.requestData(ServerApiMatic.MATIC_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), "");
|
||||
serverApiMatic.requestData(ServerApiMatic.MATIC_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
}
|
||||
// Log.i("$TAG eth_getPendingTxCount", pending)
|
||||
}
|
||||
break;
|
||||
|
|
@ -143,16 +147,6 @@ public class MaticTokenEngine extends TokenEngine {
|
|||
BigInteger l = new BigInteger(balanceCap, 16);
|
||||
coinData.setBalanceInInternalUnits(new CoinEngine.InternalAmount(l, ctx.getCard().tokenSymbol));
|
||||
// Log.i("$TAG eth_call", balanceCap)
|
||||
|
||||
|
||||
if (blockchainRequestsCallbacks.allowAdvance()) {
|
||||
serverApiMatic.requestData(ServerApiMatic.MATIC_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
serverApiMatic.requestData(ServerApiMatic.MATIC_ETH_GET_TRANSACTION_COUNT, 67, coinData.getWallet(), "", "");
|
||||
serverApiMatic.requestData(ServerApiMatic.MATIC_ETH_GET_PENDING_COUNT, 67, coinData.getWallet(), "", "");
|
||||
} else {
|
||||
ctx.setError("Terminated by user");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
@ -181,7 +175,8 @@ public class MaticTokenEngine extends TokenEngine {
|
|||
serverApiMatic.setResponseListener(responseListener);
|
||||
|
||||
if (validateAddress(getContractAddress(ctx.getCard()))) {
|
||||
serverApiMatic.requestData(ServerApiMatic.MATIC_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), "");
|
||||
serverApiMatic.requestData(ServerApiMatic.MATIC_ETH_GET_TRANSACTION_COUNT, 67, coinData.getWallet(), "", "");
|
||||
serverApiMatic.requestData(ServerApiMatic.MATIC_ETH_GET_PENDING_COUNT, 67, coinData.getWallet(), "", "");
|
||||
} else {
|
||||
ctx.setError("Smart contract address not defined");
|
||||
blockchainRequestsCallbacks.onComplete(false);
|
||||
|
|
|
|||
|
|
@ -85,8 +85,9 @@ public class RskEngine extends EthEngine {
|
|||
nonce = nonce.substring(2);
|
||||
BigInteger count = new BigInteger(nonce, 16);
|
||||
coinData.setConfirmedTXCount(count);
|
||||
|
||||
|
||||
if (serverApiRootstock.isRequestsSequenceCompleted()) {
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
}
|
||||
// Log.i("$TAG eth_getTransCount", nonce)
|
||||
}
|
||||
break;
|
||||
|
|
@ -96,7 +97,9 @@ public class RskEngine extends EthEngine {
|
|||
pending = pending.substring(2);
|
||||
BigInteger count = new BigInteger(pending, 16);
|
||||
coinData.setUnconfirmedTXCount(count);
|
||||
|
||||
if (serverApiRootstock.isRequestsSequenceCompleted()) {
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
}
|
||||
// Log.i("$TAG eth_getPendingTxCount", pending)
|
||||
}
|
||||
break;
|
||||
|
|
@ -122,7 +125,6 @@ public class RskEngine extends EthEngine {
|
|||
};
|
||||
serverApiRootstock.setResponseListener(responseListener);
|
||||
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_GET_TRANSACTION_COUNT, 67, coinData.getWallet(), "", "");
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_GET_PENDING_COUNT, 67, coinData.getWallet(), "", "");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ public class RskTokenEngine extends TokenEngine {
|
|||
BigInteger l = new BigInteger(balanceCap, 16);
|
||||
coinData.setBalanceReceived(true);
|
||||
coinData.setBalanceAlterInInternalUnits(new CoinEngine.InternalAmount(l, "wei"));
|
||||
|
||||
// Log.i("$TAG eth_get_balance", balanceCap)
|
||||
}
|
||||
break;
|
||||
|
|
@ -92,8 +91,10 @@ public class RskTokenEngine extends TokenEngine {
|
|||
nonce = nonce.substring(2);
|
||||
BigInteger count = new BigInteger(nonce, 16);
|
||||
coinData.setConfirmedTXCount(count);
|
||||
|
||||
|
||||
if (serverApiRootstock.isRequestsSequenceCompleted()) { //getting balances after checking for pending to avoid showing old balance as verified
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), "");
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
}
|
||||
// Log.i("$TAG eth_getTransCount", nonce)
|
||||
}
|
||||
break;
|
||||
|
|
@ -103,7 +104,10 @@ public class RskTokenEngine extends TokenEngine {
|
|||
pending = pending.substring(2);
|
||||
BigInteger count = new BigInteger(pending, 16);
|
||||
coinData.setUnconfirmedTXCount(count);
|
||||
|
||||
if (serverApiRootstock.isRequestsSequenceCompleted()) { //getting balances after checking for pending to avoid showing old balance as verified
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), "");
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
}
|
||||
// Log.i("$TAG eth_getPendingTxCount", pending)
|
||||
}
|
||||
break;
|
||||
|
|
@ -115,15 +119,6 @@ public class RskTokenEngine extends TokenEngine {
|
|||
BigInteger l = new BigInteger(balanceCap, 16);
|
||||
coinData.setBalanceInInternalUnits(new CoinEngine.InternalAmount(l, ctx.getCard().tokenSymbol));
|
||||
// Log.i("$TAG eth_call", balanceCap)
|
||||
|
||||
if (blockchainRequestsCallbacks.allowAdvance()) {
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_GET_TRANSACTION_COUNT, 67, coinData.getWallet(), "", "");
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_GET_PENDING_COUNT, 67, coinData.getWallet(), "", "");
|
||||
} else {
|
||||
ctx.setError("Terminated by user");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
@ -152,7 +147,8 @@ public class RskTokenEngine extends TokenEngine {
|
|||
serverApiRootstock.setResponseListener(responseListener);
|
||||
|
||||
if (validateAddress(getContractAddress(ctx.getCard()))) {
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), "");
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_GET_TRANSACTION_COUNT, 67, coinData.getWallet(), "", "");
|
||||
serverApiRootstock.requestData(ServerApiRootstock.ROOTSTOCK_ETH_GET_PENDING_COUNT, 67, coinData.getWallet(), "", "");
|
||||
} else {
|
||||
ctx.setError("Smart contract address not defined");
|
||||
blockchainRequestsCallbacks.onComplete(false);
|
||||
|
|
|
|||
|
|
@ -655,7 +655,6 @@ public class TokenEngine extends CoinEngine {
|
|||
BigInteger l = new BigInteger(balanceCap, 16);
|
||||
coinData.setBalanceReceived(true);
|
||||
coinData.setBalanceAlterInInternalUnits(new CoinEngine.InternalAmount(l, "wei"));
|
||||
|
||||
// Log.i("$TAG eth_get_balance", balanceCap)
|
||||
}
|
||||
break;
|
||||
|
|
@ -665,8 +664,10 @@ public class TokenEngine extends CoinEngine {
|
|||
nonce = nonce.substring(2);
|
||||
BigInteger count = new BigInteger(nonce, 16);
|
||||
coinData.setConfirmedTXCount(count);
|
||||
|
||||
|
||||
if (serverApiInfura.isRequestsSequenceCompleted()) { //getting balances after checking for pending to avoid showing old balance as verified
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), "");
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
}
|
||||
// Log.i("$TAG eth_getTransCount", nonce)
|
||||
}
|
||||
break;
|
||||
|
|
@ -676,29 +677,21 @@ public class TokenEngine extends CoinEngine {
|
|||
pending = pending.substring(2);
|
||||
BigInteger count = new BigInteger(pending, 16);
|
||||
coinData.setUnconfirmedTXCount(count);
|
||||
|
||||
if (serverApiInfura.isRequestsSequenceCompleted()) { //getting balances after checking for pending to avoid showing old balance as verified
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), "");
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
}
|
||||
// Log.i("$TAG eth_getPendingTxCount", pending)
|
||||
}
|
||||
break;
|
||||
//
|
||||
case ServerApiInfura.INFURA_ETH_CALL: {
|
||||
try {
|
||||
|
||||
String balanceCap = infuraResponse.getResult();
|
||||
balanceCap = balanceCap.substring(2);
|
||||
BigInteger l = new BigInteger(balanceCap, 16);
|
||||
coinData.setBalanceInInternalUnits(new CoinEngine.InternalAmount(l, ctx.getCard().tokenSymbol));
|
||||
// Log.i("$TAG eth_call", balanceCap)
|
||||
|
||||
|
||||
if (blockchainRequestsCallbacks.allowAdvance()) {
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_GET_BALANCE, 67, coinData.getWallet(), "", "");
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_GET_TRANSACTION_COUNT, 67, coinData.getWallet(), "", "");
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_GET_PENDING_COUNT, 67, coinData.getWallet(), "", "");
|
||||
} else {
|
||||
ctx.setError("Terminated by user");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
@ -706,7 +699,7 @@ public class TokenEngine extends CoinEngine {
|
|||
break;
|
||||
|
||||
}
|
||||
if (serverApiInfura.isRequestsSequenceCompleted()&& serverApiBlockcypher.isRequestsSequenceCompleted()) {
|
||||
if (serverApiInfura.isRequestsSequenceCompleted() && serverApiBlockcypher.isRequestsSequenceCompleted()) {
|
||||
blockchainRequestsCallbacks.onComplete(!ctx.hasError());
|
||||
} else {
|
||||
blockchainRequestsCallbacks.onProgress();
|
||||
|
|
@ -771,13 +764,13 @@ public class TokenEngine extends CoinEngine {
|
|||
serverApiBlockcypher.setResponseListener(blockcypherListener);
|
||||
|
||||
if (validateAddress(getContractAddress(ctx.getCard()))) {
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_CALL, 67, coinData.getWallet(), getContractAddress(ctx.getCard()), "");
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_GET_TRANSACTION_COUNT, 67, coinData.getWallet(), "", "");
|
||||
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_GET_PENDING_COUNT, 67, coinData.getWallet(), "", "");
|
||||
serverApiBlockcypher.requestData(ctx.getBlockchain().getID(), ServerApiBlockcypher.BLOCKCYPHER_ADDRESS, ctx.getCoinData().getWallet(), "");
|
||||
} else {
|
||||
ctx.setError("Smart contract address not defined");
|
||||
blockchainRequestsCallbacks.onComplete(false);
|
||||
}
|
||||
|
||||
serverApiBlockcypher.requestData(ctx.getBlockchain().getID(), ServerApiBlockcypher.BLOCKCYPHER_ADDRESS, ctx.getCoinData().getWallet(), "");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -109,14 +109,14 @@ public class XlmAssetEngine extends CoinEngine {
|
|||
@Override
|
||||
public boolean isBalanceNotZero() {
|
||||
if (coinData == null) return false;
|
||||
if (coinData.getXlmBalance() == null) return false;
|
||||
return coinData.getXlmBalance().notZero();
|
||||
return (coinData.getXlmBalance() != null && coinData.getXlmBalance().notZero() &&
|
||||
coinData.getAssetBalance() != null && coinData.getAssetBalance().notZero());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBalanceInfo() {
|
||||
if (coinData == null) return false;
|
||||
return coinData.getXlmBalance() != null;
|
||||
return (coinData.getXlmBalance() != null && coinData.getAssetBalance() != null) || (coinData.isError404());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -122,6 +122,6 @@ public class XrpData extends CoinData {
|
|||
}
|
||||
|
||||
public boolean hasUnconfirmed() {
|
||||
return !balanceConfirmed.equals(balanceUnconfirmed);
|
||||
return hasBalanceInfo() && !balanceConfirmed.equals(balanceUnconfirmed);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue