diff --git a/include/xrpl/ledger/View.h b/include/xrpl/ledger/View.h index b91ecd72ae..b6b3307718 100644 --- a/include/xrpl/ledger/View.h +++ b/include/xrpl/ledger/View.h @@ -543,19 +543,6 @@ adjustOwnerCount( inline void adjustOwnerCount( ApplyView& view, - STTx const& tx, - std::shared_ptr const& accountSle, - std::shared_ptr const& sponsorSle, - std::int32_t amount, - beast::Journal j) -{ - adjustOwnerCount(view, accountSle, sponsorSle, amount, j); -} - -inline void -adjustOwnerCount( - ApplyView& view, - STTx const& tx, AccountID const& account, std::optional const& sponsor, std::int32_t amount, @@ -563,7 +550,6 @@ adjustOwnerCount( { return adjustOwnerCount( view, - tx, view.peek(keylet::account(account)), sponsor ? view.peek(keylet::account(*sponsor)) : std::shared_ptr(), amount, diff --git a/src/libxrpl/ledger/View.cpp b/src/libxrpl/ledger/View.cpp index eaf33d2e42..b1022df1e6 100644 --- a/src/libxrpl/ledger/View.cpp +++ b/src/libxrpl/ledger/View.cpp @@ -1769,7 +1769,7 @@ authorizeMPToken( view.insert(mptoken); // Update owner count. - adjustOwnerCount(view, tx, sleAcct, sponsor, 1, journal); + adjustOwnerCount(view, sleAcct, sponsor, 1, journal); addSponsorToLedgerEntry(mptoken, sponsor); return tesSUCCESS; diff --git a/src/libxrpl/tx/transactors/Sponsor/SponsorshipSet.cpp b/src/libxrpl/tx/transactors/Sponsor/SponsorshipSet.cpp index d5e4c21ea8..dca59ec669 100644 --- a/src/libxrpl/tx/transactors/Sponsor/SponsorshipSet.cpp +++ b/src/libxrpl/tx/transactors/Sponsor/SponsorshipSet.cpp @@ -266,7 +266,7 @@ SponsorshipSet::doApply() auto viewJ = ctx_.registry.journal("View"); - adjustOwnerCount(view(), ctx_.tx, sponsorAccSle, reserveSponsorAccSle, 1, viewJ); + adjustOwnerCount(view(), sponsorAccSle, reserveSponsorAccSle, 1, viewJ); addSponsorToLedgerEntry(newSle, reserveSponsorAccSle); ctx_.view().insert(newSle); diff --git a/src/libxrpl/tx/transactors/account/SetSignerList.cpp b/src/libxrpl/tx/transactors/account/SetSignerList.cpp index aa4d04dcb1..d30dfc952d 100644 --- a/src/libxrpl/tx/transactors/account/SetSignerList.cpp +++ b/src/libxrpl/tx/transactors/account/SetSignerList.cpp @@ -328,7 +328,7 @@ SetSignerList::replaceSignerList() // If we succeeded, the new entry counts against the // creator's reserve. - adjustOwnerCount(view(), ctx_.tx, sle, sponsor, addedOwnerCount, viewJ); + adjustOwnerCount(view(), sle, sponsor, addedOwnerCount, viewJ); addSponsorToLedgerEntry(signerList, sponsor); return tesSUCCESS; } diff --git a/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp b/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp index 8941d56fce..6b4f8866cb 100644 --- a/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp +++ b/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp @@ -1113,7 +1113,7 @@ applyCreateAccountAttestations( // Reserve was already checked auto const sponsor = getTxReserveSponsor(psb, tx); - adjustOwnerCount(psb, tx, sleDoor, sponsor, 1, j); + adjustOwnerCount(psb, sleDoor, sponsor, 1, j); addSponsorToLedgerEntry(createdSleClaimID, sponsor); psb.insert(createdSleClaimID); psb.update(sleDoor); @@ -1452,7 +1452,7 @@ XChainCreateBridge::doApply() } auto const sponsor = getTxReserveSponsor(ctx_.view(), ctx_.tx); - adjustOwnerCount(ctx_.view(), ctx_.tx, sleAcct, sponsor, 1, ctx_.journal); + adjustOwnerCount(ctx_.view(), sleAcct, sponsor, 1, ctx_.journal); addSponsorToLedgerEntry(sleBridge, sponsor); ctx_.view().insert(sleBridge); @@ -1992,7 +1992,7 @@ XChainCreateClaimID::doApply() } auto const sponsor = getTxReserveSponsor(ctx_.view(), ctx_.tx); - adjustOwnerCount(ctx_.view(), ctx_.tx, sleAcct, sponsor, 1, ctx_.journal); + adjustOwnerCount(ctx_.view(), sleAcct, sponsor, 1, ctx_.journal); addSponsorToLedgerEntry(sleClaimID, sponsor); ctx_.view().insert(sleClaimID); diff --git a/src/libxrpl/tx/transactors/check/CreateCheck.cpp b/src/libxrpl/tx/transactors/check/CreateCheck.cpp index 143fa5e15d..71743625fc 100644 --- a/src/libxrpl/tx/transactors/check/CreateCheck.cpp +++ b/src/libxrpl/tx/transactors/check/CreateCheck.cpp @@ -194,7 +194,7 @@ CreateCheck::doApply() } // If we succeeded, the new entry counts against the creator's reserve. - adjustOwnerCount(view(), ctx_.tx, sle, sponsor, 1, viewJ); + adjustOwnerCount(view(), sle, sponsor, 1, viewJ); addSponsorToLedgerEntry(sleCheck, sponsor); return tesSUCCESS; } diff --git a/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp b/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp index e58ed4aaaa..219990edb6 100644 --- a/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp +++ b/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp @@ -106,7 +106,7 @@ CredentialAccept::doApply() adjustOwnerCount(view(), sleIssuer, currentSponsor, -1, j_); removeSponsorFromLedgerEntry(sleCred); - adjustOwnerCount(view(), ctx_.tx, sleSubject, newSponsor, 1, j_); + adjustOwnerCount(view(), sleSubject, newSponsor, 1, j_); addSponsorToLedgerEntry(sleCred, newSponsor); return tesSUCCESS; diff --git a/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp b/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp index 5bb06e4667..6cc60f7d98 100644 --- a/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp +++ b/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp @@ -136,7 +136,7 @@ CredentialCreate::doApply() return tecDIR_FULL; sleCred->setFieldU64(sfIssuerNode, *page); - adjustOwnerCount(view(), ctx_.tx, sleIssuer, sponsor, 1, j_); + adjustOwnerCount(view(), sleIssuer, sponsor, 1, j_); addSponsorToLedgerEntry(sleCred, sponsor); } diff --git a/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp b/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp index 98a0e30edc..8128e27974 100644 --- a/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp +++ b/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp @@ -89,7 +89,7 @@ DelegateSet::doApply() (*sle)[sfOwnerNode] = *page; ctx_.view().insert(sle); - adjustOwnerCount(ctx_.view(), ctx_.tx, sleOwner, sponsor, 1, ctx_.journal); + adjustOwnerCount(ctx_.view(), sleOwner, sponsor, 1, ctx_.journal); addSponsorToLedgerEntry(sle, sponsor); } diff --git a/src/libxrpl/tx/transactors/dex/CreateOffer.cpp b/src/libxrpl/tx/transactors/dex/CreateOffer.cpp index c7f8dee226..e28adafc4b 100644 --- a/src/libxrpl/tx/transactors/dex/CreateOffer.cpp +++ b/src/libxrpl/tx/transactors/dex/CreateOffer.cpp @@ -762,7 +762,7 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) // Update owner count. auto const sponsor = getTxReserveSponsor(sb, ctx_.tx); - adjustOwnerCount(sb, ctx_.tx, sleCreator, sponsor, 1, viewJ); + adjustOwnerCount(sb, sleCreator, sponsor, 1, viewJ); JLOG(j_.trace()) << "adding to book: " << to_string(saTakerPays.issue()) << " : " << to_string(saTakerGets.issue()) diff --git a/src/libxrpl/tx/transactors/did/DIDSet.cpp b/src/libxrpl/tx/transactors/did/DIDSet.cpp index 61f1eee92a..534995b3c2 100644 --- a/src/libxrpl/tx/transactors/did/DIDSet.cpp +++ b/src/libxrpl/tx/transactors/did/DIDSet.cpp @@ -73,7 +73,7 @@ addSLE(ApplyContext& ctx, std::shared_ptr const& sle, AccountID const& owne return tecDIR_FULL; // LCOV_EXCL_LINE (*sle)[sfOwnerNode] = *page; } - adjustOwnerCount(ctx.view(), ctx.tx, sleAccount, sponsor, 1, ctx.journal); + adjustOwnerCount(ctx.view(), sleAccount, sponsor, 1, ctx.journal); addSponsorToLedgerEntry(sle, sponsor); ctx.view().update(sleAccount); diff --git a/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp b/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp index 6fa4522f47..0edb548a0e 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp +++ b/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp @@ -493,7 +493,7 @@ EscrowCreate::doApply() } // increment owner count - adjustOwnerCount(ctx_.view(), ctx_.tx, sle, sponsor, 1, ctx_.journal); + adjustOwnerCount(ctx_.view(), sle, sponsor, 1, ctx_.journal); addSponsorToLedgerEntry(slep, sponsor); ctx_.view().update(sle); return tesSUCCESS; diff --git a/src/libxrpl/tx/transactors/escrow/EscrowHelpers.h b/src/libxrpl/tx/transactors/escrow/EscrowHelpers.h index d5a50daf4e..c71b8882fc 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowHelpers.h +++ b/src/libxrpl/tx/transactors/escrow/EscrowHelpers.h @@ -197,7 +197,7 @@ escrowUnlockApplyHelper( } // update owner count. - adjustOwnerCount(view, tx, sleDest, sponsor, 1, journal); + adjustOwnerCount(view, sleDest, sponsor, 1, journal); auto mptSle = view.peek(mptKeylet); addSponsorToLedgerEntry(mptSle, sponsor); } diff --git a/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp b/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp index a4090da6b8..45594a0fcc 100644 --- a/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp +++ b/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp @@ -275,7 +275,6 @@ insertToken( } adjustOwnerCount( view, - tx, view.peek(keylet::account(owner)), sponsorSle, 1, @@ -1033,7 +1032,7 @@ tokenOfferCreateApply( } // Update owner count. - adjustOwnerCount(view, tx, view.peek(acctKeylet), sponsor, 1, j); + adjustOwnerCount(view, view.peek(acctKeylet), sponsor, 1, j); return tesSUCCESS; } diff --git a/src/libxrpl/tx/transactors/oracle/SetOracle.cpp b/src/libxrpl/tx/transactors/oracle/SetOracle.cpp index d5f305b968..39c7e42be0 100644 --- a/src/libxrpl/tx/transactors/oracle/SetOracle.cpp +++ b/src/libxrpl/tx/transactors/oracle/SetOracle.cpp @@ -161,21 +161,6 @@ SetOracle::preclaim(PreclaimContext const& ctx) return tesSUCCESS; } -static bool -adjustOwnerCount(ApplyContext& ctx, std::shared_ptr const& sponsor, int count) -{ - if (auto const sleAccount = ctx.view().peek(keylet::account(ctx.tx[sfAccount]))) - { - if (count > 0) - adjustOwnerCount(ctx.view(), ctx.tx, sleAccount, sponsor, count, ctx.journal); - else - adjustOwnerCount(ctx.view(), sleAccount, sponsor, count, ctx.journal); - return true; - } - - return false; // LCOV_EXCL_LINE -} - static void setPriceDataInnerObjTemplate(STObject& obj) { @@ -255,6 +240,10 @@ SetOracle::doApply() auto const newCount = calculateOracleReserve(pairs.size()); int32_t const adjust = newCount - oldCount; + auto const accountSle = ctx_.view().peek(keylet::account(ctx_.tx[sfAccount])); + if (!accountSle) + return tefINTERNAL; // LCOV_EXCL_LINE + if (adjust > 0) { // To continue receiving sponsorship from the same account after the @@ -262,24 +251,21 @@ SetOracle::doApply() // the sponsor decrease current sponsored owner count. // Otherwise, the sponsorship will be deleted. - auto const currentsponsor = getLedgerEntryReserveSponsor(ctx_.view(), sle); - auto const newSponsor = getTxReserveSponsor(ctx_.view(), ctx_.tx); + auto const currentSponsorSle = getLedgerEntryReserveSponsor(ctx_.view(), sle); + auto const newSponsorSle = getTxReserveSponsor(ctx_.view(), ctx_.tx); // decrease current sponsored owner count - if (!adjustOwnerCount(ctx_, currentsponsor, -oldCount)) - return tefINTERNAL; // LCOV_EXCL_LINE + adjustOwnerCount(ctx_.view(), accountSle, currentSponsorSle, -oldCount, ctx_.journal); removeSponsorFromLedgerEntry(sle); // increase new owner count - if (!adjustOwnerCount(ctx_, newSponsor, newCount)) - return tefINTERNAL; // LCOV_EXCL_LINE - addSponsorToLedgerEntry(sle, newSponsor); + adjustOwnerCount(ctx_.view(), accountSle, newSponsorSle, newCount, ctx_.journal); + addSponsorToLedgerEntry(sle, newSponsorSle); } else if (adjust < 0) { // decrease owner count - auto const sponsor = getLedgerEntryReserveSponsor(ctx_.view(), sle); - if (!adjustOwnerCount(ctx_, sponsor, adjust)) - return tefINTERNAL; // LCOV_EXCL_LINE + auto const sponsorSle = getLedgerEntryReserveSponsor(ctx_.view(), sle); + adjustOwnerCount(ctx_.view(), accountSle, sponsorSle, adjust, ctx_.journal); } ctx_.view().update(sle); @@ -330,8 +316,10 @@ SetOracle::doApply() auto const count = calculateOracleReserve(series.size()); auto const sponsor = getTxReserveSponsor(ctx_.view(), ctx_.tx); - if (!adjustOwnerCount(ctx_, sponsor, count)) + auto const accountSle = ctx_.view().peek(keylet::account(ctx_.tx[sfAccount])); + if (!accountSle) return tefINTERNAL; // LCOV_EXCL_LINE + adjustOwnerCount(ctx_.view(), accountSle, sponsor, count, ctx_.journal); addSponsorToLedgerEntry(sle, sponsor); diff --git a/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp b/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp index 2ed31221e1..295e5b278f 100644 --- a/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp +++ b/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp @@ -171,7 +171,7 @@ DepositPreauth::doApply() slePreauth->setFieldU64(sfOwnerNode, *page); // If we succeeded, the new entry counts against the creator's reserve. - adjustOwnerCount(view(), ctx_.tx, sleOwner, sponsor, 1, j_); + adjustOwnerCount(view(), sleOwner, sponsor, 1, j_); addSponsorToLedgerEntry(slePreauth, sponsor); } else if (ctx_.tx.isFieldPresent(sfUnauthorize)) @@ -231,7 +231,7 @@ DepositPreauth::doApply() slePreauth->setFieldU64(sfOwnerNode, *page); // If we succeeded, the new entry counts against the creator's reserve. - adjustOwnerCount(view(), ctx_.tx, sleOwner, sponsor, 1, j_); + adjustOwnerCount(view(), sleOwner, sponsor, 1, j_); addSponsorToLedgerEntry(slePreauth, sponsor); } else if (ctx_.tx.isFieldPresent(sfUnauthorizeCredentials)) diff --git a/src/libxrpl/tx/transactors/payment_channel/PayChanCreate.cpp b/src/libxrpl/tx/transactors/payment_channel/PayChanCreate.cpp index d124fa7360..909027e1ee 100644 --- a/src/libxrpl/tx/transactors/payment_channel/PayChanCreate.cpp +++ b/src/libxrpl/tx/transactors/payment_channel/PayChanCreate.cpp @@ -167,7 +167,7 @@ PayChanCreate::doApply() // Deduct owner's balance, increment owner count (*sle)[sfBalance] = (*sle)[sfBalance] - ctx_.tx[sfAmount]; auto const sponsor = getTxReserveSponsor(ctx_.view(), ctx_.tx); - adjustOwnerCount(ctx_.view(), ctx_.tx, sle, sponsor, 1, ctx_.journal); + adjustOwnerCount(ctx_.view(), sle, sponsor, 1, ctx_.journal); addSponsorToLedgerEntry(slep, sponsor); ctx_.view().update(sle); diff --git a/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp b/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp index 22b7cb6382..850bb60254 100644 --- a/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp +++ b/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp @@ -113,7 +113,7 @@ PermissionedDomainSet::doApply() slePd->setFieldU64(sfOwnerNode, *page); // If we succeeded, the new entry counts against the creator's reserve. - adjustOwnerCount(view(), ctx_.tx, ownerSle, sponsor, 1, ctx_.journal); + adjustOwnerCount(view(), ownerSle, sponsor, 1, ctx_.journal); addSponsorToLedgerEntry(slePd, sponsor); view().insert(slePd); } diff --git a/src/libxrpl/tx/transactors/system/CreateTicket.cpp b/src/libxrpl/tx/transactors/system/CreateTicket.cpp index 23d0db2760..4d6e74197b 100644 --- a/src/libxrpl/tx/transactors/system/CreateTicket.cpp +++ b/src/libxrpl/tx/transactors/system/CreateTicket.cpp @@ -111,7 +111,7 @@ CreateTicket::doApply() sleAccountRoot->setFieldU32(sfTicketCount, oldTicketCount + ticketCount); // Every added Ticket counts against the creator's reserve. - adjustOwnerCount(view(), ctx_.tx, sleAccountRoot, sponsor, ticketCount, viewJ); + adjustOwnerCount(view(), sleAccountRoot, sponsor, ticketCount, viewJ); // TicketCreate is the only transaction that can cause an account root's // Sequence field to increase by more than one. October 2018. diff --git a/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp b/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp index c093b14ce5..39f04edf55 100644 --- a/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp +++ b/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp @@ -137,7 +137,7 @@ MPTokenIssuanceCreate::create( } // Update owner count. - adjustOwnerCount(view, tx, acct, sponsor, 1, journal); + adjustOwnerCount(view, acct, sponsor, 1, journal); return mptId; } diff --git a/src/libxrpl/tx/transactors/token/SetTrust.cpp b/src/libxrpl/tx/transactors/token/SetTrust.cpp index e04dbdd875..bedfb8398b 100644 --- a/src/libxrpl/tx/transactors/token/SetTrust.cpp +++ b/src/libxrpl/tx/transactors/token/SetTrust.cpp @@ -547,7 +547,7 @@ SetTrust::doApply() return tecINSUF_RESERVE_LINE; // Set reserve for low account. - adjustOwnerCount(view(), ctx_.tx, sleLowAccount, txSponsorSle, 1, viewJ); + adjustOwnerCount(view(), sleLowAccount, txSponsorSle, 1, viewJ); uFlagsOut |= lsfLowReserve; addSponsorToLedgerEntry(sleRippleState, txSponsorSle, sfLowSponsor); @@ -574,7 +574,7 @@ SetTrust::doApply() return tecINSUF_RESERVE_LINE; // Set reserve for high account. - adjustOwnerCount(view(), ctx_.tx, sleHighAccount, txSponsorSle, 1, viewJ); + adjustOwnerCount(view(), sleHighAccount, txSponsorSle, 1, viewJ); uFlagsOut |= lsfHighReserve; addSponsorToLedgerEntry(sleRippleState, txSponsorSle, sfHighSponsor); @@ -602,10 +602,9 @@ SetTrust::doApply() terResult = trustDelete(view(), sleRippleState, uLowAccountID, uHighAccountID, viewJ); } // Reserve is not scaled by load. - else if ( - auto const ret = - checkInsufficientReserve(view(), ctx_.tx, sle, mPriorBalance, txSponsorSle, 0); - !freeTrustLine && bReserveIncrease && !isTesSuccess(ret)) + else if (auto const ret = + checkInsufficientReserve(view(), ctx_.tx, sle, mPriorBalance, txSponsorSle, 0); + !freeTrustLine && bReserveIncrease && !isTesSuccess(ret)) { JLOG(j_.trace()) << "Delay transaction: Insufficent reserve to " "add trust line."; @@ -633,15 +632,14 @@ SetTrust::doApply() JLOG(j_.trace()) << "Redundant: Setting non-existent ripple line to defaults."; return tecNO_LINE_REDUNDANT; } - else if ( - auto const ret = checkInsufficientReserve( - ctx_.view(), - ctx_.tx, - sle, - mPriorBalance, - txSponsorSle, - 1); - !freeTrustLine && !isTesSuccess(ret)) // Reserve is not scaled by load. + else if (auto const ret = checkInsufficientReserve( + ctx_.view(), + ctx_.tx, + sle, + mPriorBalance, + txSponsorSle, + 1); + !freeTrustLine && !isTesSuccess(ret)) // Reserve is not scaled by load. { JLOG(j_.trace()) << "Delay transaction: Line does not exist. " "Insufficent reserve to create line."; diff --git a/src/libxrpl/tx/transactors/vault/VaultCreate.cpp b/src/libxrpl/tx/transactors/vault/VaultCreate.cpp index e2e795b22a..7c33946e49 100644 --- a/src/libxrpl/tx/transactors/vault/VaultCreate.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultCreate.cpp @@ -138,7 +138,7 @@ VaultCreate::doApply() auto const sponsor = getTxReserveSponsor(view(), tx); if (!ctx_.view().rules().enabled(featureSponsor)) { - adjustOwnerCount(view(), tx, owner, sponsor, 2, j_); + adjustOwnerCount(view(), owner, sponsor, 2, j_); addSponsorToLedgerEntry(vault, sponsor); if (auto const ret = checkInsufficientReserve(view(), tx, owner, mPriorBalance, sponsor, 0); !isTesSuccess(ret)) @@ -150,7 +150,7 @@ VaultCreate::doApply() if (auto const ret = checkInsufficientReserve(view(), tx, owner, mPriorBalance, sponsor, 2); !isTesSuccess(ret)) return ret; - adjustOwnerCount(view(), tx, owner, sponsor, 2, j_); + adjustOwnerCount(view(), owner, sponsor, 2, j_); addSponsorToLedgerEntry(vault, sponsor); }