mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-21 11:35:53 +00:00
jtx: Add JTx properties.
This commit is contained in:
committed by
Vinnie Falco
parent
cd5e36045c
commit
27274c9620
@@ -3341,6 +3341,8 @@
|
|||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\test\jtx\balance.h">
|
<ClInclude Include="..\..\src\ripple\test\jtx\balance.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ripple\test\jtx\basic_prop.h">
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\test\jtx\Env.h">
|
<ClInclude Include="..\..\src\ripple\test\jtx\Env.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\test\jtx\fee.h">
|
<ClInclude Include="..\..\src\ripple\test\jtx\fee.h">
|
||||||
@@ -3457,6 +3459,8 @@
|
|||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\test\jtx\pay.h">
|
<ClInclude Include="..\..\src\ripple\test\jtx\pay.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ripple\test\jtx\prop.h">
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\test\jtx\rate.h">
|
<ClInclude Include="..\..\src\ripple\test\jtx\rate.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\test\jtx\regkey.h">
|
<ClInclude Include="..\..\src\ripple\test\jtx\regkey.h">
|
||||||
|
|||||||
@@ -4074,6 +4074,9 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\test\jtx\balance.h">
|
<ClInclude Include="..\..\src\ripple\test\jtx\balance.h">
|
||||||
<Filter>ripple\test\jtx</Filter>
|
<Filter>ripple\test\jtx</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ripple\test\jtx\basic_prop.h">
|
||||||
|
<Filter>ripple\test\jtx</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\test\jtx\Env.h">
|
<ClInclude Include="..\..\src\ripple\test\jtx\Env.h">
|
||||||
<Filter>ripple\test\jtx</Filter>
|
<Filter>ripple\test\jtx</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -4179,6 +4182,9 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\test\jtx\pay.h">
|
<ClInclude Include="..\..\src\ripple\test\jtx\pay.h">
|
||||||
<Filter>ripple\test\jtx</Filter>
|
<Filter>ripple\test\jtx</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ripple\test\jtx\prop.h">
|
||||||
|
<Filter>ripple\test\jtx</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\test\jtx\rate.h">
|
<ClInclude Include="..\..\src\ripple\test\jtx\rate.h">
|
||||||
<Filter>ripple\test\jtx</Filter>
|
<Filter>ripple\test\jtx</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include <ripple/test/jtx/owners.h>
|
#include <ripple/test/jtx/owners.h>
|
||||||
#include <ripple/test/jtx/paths.h>
|
#include <ripple/test/jtx/paths.h>
|
||||||
#include <ripple/test/jtx/pay.h>
|
#include <ripple/test/jtx/pay.h>
|
||||||
|
#include <ripple/test/jtx/prop.h>
|
||||||
#include <ripple/test/jtx/rate.h>
|
#include <ripple/test/jtx/rate.h>
|
||||||
#include <ripple/test/jtx/regkey.h>
|
#include <ripple/test/jtx/regkey.h>
|
||||||
#include <ripple/test/jtx/require.h>
|
#include <ripple/test/jtx/require.h>
|
||||||
|
|||||||
@@ -21,9 +21,12 @@
|
|||||||
#define RIPPLE_TEST_JTX_JTX_H_INCLUDED
|
#define RIPPLE_TEST_JTX_JTX_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/test/jtx/requires.h>
|
#include <ripple/test/jtx/requires.h>
|
||||||
|
#include <ripple/test/jtx/basic_prop.h>
|
||||||
#include <ripple/json/json_value.h>
|
#include <ripple/json/json_value.h>
|
||||||
#include <ripple/protocol/TER.h>
|
#include <ripple/protocol/TER.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace test {
|
namespace test {
|
||||||
@@ -46,6 +49,34 @@ struct JTx
|
|||||||
|
|
||||||
JTx() = default;
|
JTx() = default;
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||||
|
JTx(JTx&& src)
|
||||||
|
: jv(std::move(src.jv))
|
||||||
|
, fill_fee(std::move(src.fill_fee))
|
||||||
|
, fill_seq(std::move(src.fill_seq))
|
||||||
|
, fill_sig(std::move(src.fill_sig))
|
||||||
|
, signer(std::move(src.signer))
|
||||||
|
, requires(std::move(src.requires))
|
||||||
|
, ter(std::move(src.ter))
|
||||||
|
, props_(std::move(src.props_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
JTx& operator=(JTx&& src) noexcept
|
||||||
|
{
|
||||||
|
jv = std::move(src.jv);
|
||||||
|
fill_fee = std::move(src.fill_fee);
|
||||||
|
fill_seq = std::move(src.fill_seq);
|
||||||
|
fill_sig = std::move(src.fill_sig);
|
||||||
|
signer = std::move(src.signer);
|
||||||
|
requires = std::move(src.requires);
|
||||||
|
ter = std::move(src.ter);
|
||||||
|
props_ = std::move(src.props_);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
JTx (Json::Value&& jv_)
|
JTx (Json::Value&& jv_)
|
||||||
: jv(std::move(jv_))
|
: jv(std::move(jv_))
|
||||||
{
|
{
|
||||||
@@ -62,6 +93,115 @@ struct JTx
|
|||||||
{
|
{
|
||||||
return jv[key];
|
return jv[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Return a property if it exists
|
||||||
|
|
||||||
|
@return nullptr if the Prop does not exist
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
template <class Prop>
|
||||||
|
Prop*
|
||||||
|
get()
|
||||||
|
{
|
||||||
|
for (auto& prop : props_.list)
|
||||||
|
{
|
||||||
|
if (auto test = dynamic_cast<
|
||||||
|
prop_type<Prop>*>(
|
||||||
|
prop.get()))
|
||||||
|
return &test->t;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Prop>
|
||||||
|
Prop const*
|
||||||
|
get() const
|
||||||
|
{
|
||||||
|
for (auto& prop : props_.list)
|
||||||
|
{
|
||||||
|
if (auto test = dynamic_cast<
|
||||||
|
prop_type<Prop> const*>(
|
||||||
|
prop.get()))
|
||||||
|
return &test->t;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** Set a property
|
||||||
|
If the property already exists,
|
||||||
|
it is replaced.
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
void
|
||||||
|
set(std::unique_ptr<basic_prop> p)
|
||||||
|
{
|
||||||
|
for (auto& prop : props_.list)
|
||||||
|
{
|
||||||
|
if (prop->assignable(p.get()))
|
||||||
|
{
|
||||||
|
prop = std::move(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
props_.list.emplace_back(std::move(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Prop, class... Args>
|
||||||
|
void
|
||||||
|
set(Args&&... args)
|
||||||
|
{
|
||||||
|
set(std::make_unique<
|
||||||
|
prop_type<Prop>>(
|
||||||
|
std::forward <Args> (
|
||||||
|
args)...));
|
||||||
|
}
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct prop_list
|
||||||
|
{
|
||||||
|
prop_list() = default;
|
||||||
|
|
||||||
|
prop_list(prop_list const& src)
|
||||||
|
{
|
||||||
|
for (auto const& prop : src.list)
|
||||||
|
list.emplace_back(prop->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
prop_list& operator=(prop_list const& src)
|
||||||
|
{
|
||||||
|
if (this != &src)
|
||||||
|
{
|
||||||
|
list.clear();
|
||||||
|
for (auto const& prop : src.list)
|
||||||
|
list.emplace_back(prop->clone());
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||||
|
prop_list(prop_list&& src)
|
||||||
|
: list(std::move(src.list))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
prop_list& operator=(prop_list&& src)
|
||||||
|
{
|
||||||
|
list = std::move(src.list);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
prop_list(prop_list&& src) = default;
|
||||||
|
prop_list& operator=(prop_list&& src) = default;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<
|
||||||
|
basic_prop>> list;
|
||||||
|
};
|
||||||
|
|
||||||
|
prop_list props_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // jtx
|
} // jtx
|
||||||
|
|||||||
67
src/ripple/test/jtx/basic_prop.h
Normal file
67
src/ripple/test/jtx/basic_prop.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_TEST_JTX_BASIC_PROP_H_INCLUDED
|
||||||
|
#define RIPPLE_TEST_JTX_BASIC_PROP_H_INCLUDED
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace test {
|
||||||
|
namespace jtx {
|
||||||
|
|
||||||
|
struct basic_prop
|
||||||
|
{
|
||||||
|
virtual ~basic_prop() = default;
|
||||||
|
virtual std::unique_ptr<
|
||||||
|
basic_prop> clone() const = 0;
|
||||||
|
virtual bool assignable(
|
||||||
|
basic_prop const*) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct prop_type : basic_prop
|
||||||
|
{
|
||||||
|
T t;
|
||||||
|
|
||||||
|
template <class... Args>
|
||||||
|
prop_type(Args&&... args)
|
||||||
|
: t(std::forward <Args>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<
|
||||||
|
basic_prop> clone() const override
|
||||||
|
{
|
||||||
|
return std::make_unique<
|
||||||
|
prop_type<T>>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool assignable(
|
||||||
|
basic_prop const* src) const override
|
||||||
|
{
|
||||||
|
return dynamic_cast<
|
||||||
|
prop_type<T> const*>(
|
||||||
|
src);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // jtx
|
||||||
|
} // test
|
||||||
|
} // ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -239,7 +239,7 @@ Env::autofill_sig (JTx& jt)
|
|||||||
auto const account =
|
auto const account =
|
||||||
lookup(jv[jss::Account].asString());
|
lookup(jv[jss::Account].asString());
|
||||||
auto const ar = le(account);
|
auto const ar = le(account);
|
||||||
if (ar->isFieldPresent(sfRegularKey))
|
if (ar && ar->isFieldPresent(sfRegularKey))
|
||||||
jtx::sign(jv, lookup(
|
jtx::sign(jv, lookup(
|
||||||
ar->getFieldAccount160(sfRegularKey)));
|
ar->getFieldAccount160(sfRegularKey)));
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -414,6 +414,106 @@ public:
|
|||||||
Env env(*this);
|
Env env(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testJTxProperties()
|
||||||
|
{
|
||||||
|
using namespace jtx;
|
||||||
|
JTx jt1;
|
||||||
|
// Test a straightforward
|
||||||
|
// property
|
||||||
|
expect(!jt1.get<int>());
|
||||||
|
jt1.set<int>(7);
|
||||||
|
expect(jt1.get<int>());
|
||||||
|
expect(*jt1.get<int>() == 7);
|
||||||
|
expect(!jt1.get<Env>());
|
||||||
|
|
||||||
|
// Test that the property is
|
||||||
|
// replaced if it exists.
|
||||||
|
jt1.set<int>(17);
|
||||||
|
expect(jt1.get<int>());
|
||||||
|
expect(*jt1.get<int>() == 17);
|
||||||
|
expect(!jt1.get<Env>());
|
||||||
|
|
||||||
|
// Test that modifying the
|
||||||
|
// returned prop is saved
|
||||||
|
*jt1.get<int>() = 42;
|
||||||
|
expect(jt1.get<int>());
|
||||||
|
expect(*jt1.get<int>() == 42);
|
||||||
|
expect(!jt1.get<Env>());
|
||||||
|
|
||||||
|
// Test get() const
|
||||||
|
auto const& jt2 = jt1;
|
||||||
|
expect(jt2.get<int>());
|
||||||
|
expect(*jt2.get<int>() == 42);
|
||||||
|
expect(!jt2.get<Env>());
|
||||||
|
}
|
||||||
|
|
||||||
|
void testProp()
|
||||||
|
{
|
||||||
|
using namespace jtx;
|
||||||
|
Env env(*this);
|
||||||
|
env.memoize("alice");
|
||||||
|
|
||||||
|
auto jt1 = env.jt(noop("alice"));
|
||||||
|
expect(!jt1.get<std::uint16_t>());
|
||||||
|
|
||||||
|
auto jt2 = env.jt(noop("alice"),
|
||||||
|
prop<std::uint16_t>(-1));
|
||||||
|
expect(jt2.get<std::uint16_t>());
|
||||||
|
expect(*jt2.get<std::uint16_t>() ==
|
||||||
|
65535);
|
||||||
|
|
||||||
|
auto jt3 = env.jt(noop("alice"),
|
||||||
|
prop<std::string>(
|
||||||
|
"Hello, world!"),
|
||||||
|
prop<bool>(false));
|
||||||
|
expect(jt3.get<std::string>());
|
||||||
|
expect(*jt3.get<std::string>() ==
|
||||||
|
"Hello, world!");
|
||||||
|
expect(jt3.get<bool>());
|
||||||
|
expect(!*jt3.get<bool>());
|
||||||
|
}
|
||||||
|
|
||||||
|
void testJTxCopy()
|
||||||
|
{
|
||||||
|
using namespace jtx;
|
||||||
|
JTx jt1;
|
||||||
|
jt1.set<int>(7);
|
||||||
|
expect(jt1.get<int>());
|
||||||
|
expect(*jt1.get<int>() == 7);
|
||||||
|
expect(!jt1.get<Env>());
|
||||||
|
JTx jt2(jt1);
|
||||||
|
expect(jt2.get<int>());
|
||||||
|
expect(*jt2.get<int>() == 7);
|
||||||
|
expect(!jt2.get<Env>());
|
||||||
|
JTx jt3;
|
||||||
|
jt3 = jt1;
|
||||||
|
expect(jt3.get<int>());
|
||||||
|
expect(*jt3.get<int>() == 7);
|
||||||
|
expect(!jt3.get<Env>());
|
||||||
|
}
|
||||||
|
|
||||||
|
void testJTxMove()
|
||||||
|
{
|
||||||
|
using namespace jtx;
|
||||||
|
JTx jt1;
|
||||||
|
jt1.set<int>(7);
|
||||||
|
expect(jt1.get<int>());
|
||||||
|
expect(*jt1.get<int>() == 7);
|
||||||
|
expect(!jt1.get<Env>());
|
||||||
|
JTx jt2(std::move(jt1));
|
||||||
|
expect(!jt1.get<int>());
|
||||||
|
expect(!jt1.get<Env>());
|
||||||
|
expect(jt2.get<int>());
|
||||||
|
expect(*jt2.get<int>() == 7);
|
||||||
|
expect(!jt2.get<Env>());
|
||||||
|
jt1 = std::move(jt2);
|
||||||
|
expect(!jt2.get<int>());
|
||||||
|
expect(!jt2.get<Env>());
|
||||||
|
expect(jt1.get<int>());
|
||||||
|
expect(*jt1.get<int>() == 7);
|
||||||
|
expect(!jt1.get<Env>());
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testMemo()
|
testMemo()
|
||||||
{
|
{
|
||||||
@@ -447,6 +547,10 @@ public:
|
|||||||
testMultiSign();
|
testMultiSign();
|
||||||
testMultiSign2();
|
testMultiSign2();
|
||||||
testTicket();
|
testTicket();
|
||||||
|
testJTxProperties();
|
||||||
|
testProp();
|
||||||
|
testJTxCopy();
|
||||||
|
testJTxMove();
|
||||||
testMemo();
|
testMemo();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ fill_seq (Json::Value& jv,
|
|||||||
auto const ar = ledger.fetch(
|
auto const ar = ledger.fetch(
|
||||||
getAccountRootIndex(ra.getAccountID()));
|
getAccountRootIndex(ra.getAccountID()));
|
||||||
|
|
||||||
|
if (!ar)
|
||||||
|
return;
|
||||||
|
|
||||||
jv[jss::Sequence] =
|
jv[jss::Sequence] =
|
||||||
ar->getFieldU32(sfSequence);
|
ar->getFieldU32(sfSequence);
|
||||||
}
|
}
|
||||||
|
|||||||
56
src/ripple/test/jtx/prop.h
Normal file
56
src/ripple/test/jtx/prop.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_TEST_JTX_PROP_H_INCLUDED
|
||||||
|
#define RIPPLE_TEST_JTX_PROP_H_INCLUDED
|
||||||
|
|
||||||
|
#include <ripple/test/jtx/Env.h>
|
||||||
|
#include <beast/cxx14/memory.h> // <memory>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace test {
|
||||||
|
namespace jtx {
|
||||||
|
|
||||||
|
/** Set a property on a JTx. */
|
||||||
|
template <class Prop>
|
||||||
|
struct prop
|
||||||
|
{
|
||||||
|
std::unique_ptr<basic_prop> p_;
|
||||||
|
|
||||||
|
template <class... Args>
|
||||||
|
prop(Args&&... args)
|
||||||
|
: p_(std::make_unique<
|
||||||
|
prop_type<Prop>>(
|
||||||
|
std::forward <Args> (
|
||||||
|
args)...))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(Env const& env, JTx& jt) const
|
||||||
|
{
|
||||||
|
jt.set(p_->clone());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // jtx
|
||||||
|
} // test
|
||||||
|
} // ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user