aboutsummaryrefslogtreecommitdiff
path: root/framework
diff options
context:
space:
mode:
authorMoritz Pflanzer <moritz.pflanzer@arm.com>2017-07-17 13:50:12 +0100
committerAnthony Barbier <anthony.barbier@arm.com>2018-09-17 14:16:42 +0100
commitd03b00acd71847fa2db1c5308c87d3b57c781bf9 (patch)
tree7c58283ca1a067428ccafd0f310c8c0e89800306 /framework
parentee493ae23b8cd6de5a6c578cea34bccb478d2f64 (diff)
downloadComputeLibrary-d03b00acd71847fa2db1c5308c87d3b57c781bf9.tar.gz
COMPMID-415: Fix dataset modes
Change-Id: I266e8a22890c914edb3335104f073e79d2bf0ad9 Reviewed-on: http://mpd-gerrit.cambridge.arm.com/80766 Tested-by: Kaizen <jeremy.johnson+kaizengerrit@arm.com> Reviewed-by: Anthony Barbier <anthony.barbier@arm.com>
Diffstat (limited to 'framework')
-rw-r--r--framework/DatasetModes.cpp54
-rw-r--r--framework/DatasetModes.h106
-rw-r--r--framework/Framework.cpp31
-rw-r--r--framework/Framework.h24
-rw-r--r--framework/Macros.h32
-rw-r--r--framework/Registrars.h15
-rw-r--r--framework/TestCaseFactory.h27
7 files changed, 247 insertions, 42 deletions
diff --git a/framework/DatasetModes.cpp b/framework/DatasetModes.cpp
new file mode 100644
index 0000000000..0a9e92a38b
--- /dev/null
+++ b/framework/DatasetModes.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017 ARM Limited.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "DatasetModes.h"
+
+#include <map>
+
+namespace arm_compute
+{
+namespace test
+{
+namespace framework
+{
+DatasetMode dataset_mode_from_name(const std::string &name)
+{
+ static const std::map<std::string, DatasetMode> modes =
+ {
+ { "all", DatasetMode::ALL },
+ { "precommit", DatasetMode::PRECOMMIT },
+ { "nightly", DatasetMode::NIGHTLY },
+ };
+
+ try
+ {
+ return modes.at(name);
+ }
+ catch(const std::out_of_range &)
+ {
+ throw std::invalid_argument(name);
+ }
+}
+} // namespace framework
+} // namespace test
+} // namespace arm_compute
diff --git a/framework/DatasetModes.h b/framework/DatasetModes.h
new file mode 100644
index 0000000000..27638b0504
--- /dev/null
+++ b/framework/DatasetModes.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2017 ARM Limited.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef ARM_COMPUTE_TEST_DATASET_MODES
+#define ARM_COMPUTE_TEST_DATASET_MODES
+
+#include <istream>
+#include <ostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+namespace arm_compute
+{
+namespace test
+{
+namespace framework
+{
+/** Possible dataset modes. */
+enum class DatasetMode : unsigned int
+{
+ ALL = ~0U,
+ DISABLED = 0,
+ PRECOMMIT = 1,
+ NIGHTLY = 2
+};
+
+inline DatasetMode operator&(DatasetMode t1, DatasetMode t2)
+{
+ using type = std::underlying_type<DatasetMode>::type;
+ return static_cast<DatasetMode>(static_cast<type>(t1) & static_cast<type>(t2));
+}
+
+inline DatasetMode operator|(DatasetMode t1, DatasetMode t2)
+{
+ using type = std::underlying_type<DatasetMode>::type;
+ return static_cast<DatasetMode>(static_cast<type>(t1) | static_cast<type>(t2));
+}
+
+inline DatasetMode &operator|=(DatasetMode &t1, DatasetMode t2)
+{
+ using type = std::underlying_type<DatasetMode>::type;
+ t1 = static_cast<DatasetMode>(static_cast<type>(t1) | static_cast<type>(t2));
+ return t1;
+}
+
+DatasetMode dataset_mode_from_name(const std::string &name);
+
+inline ::std::istream &operator>>(::std::istream &stream, DatasetMode &mode)
+{
+ std::string value;
+ stream >> value;
+ mode = dataset_mode_from_name(value);
+ return stream;
+}
+
+inline ::std::ostream &operator<<(::std::ostream &stream, DatasetMode mode)
+{
+ switch(mode)
+ {
+ case DatasetMode::PRECOMMIT:
+ stream << "PRECOMMIT";
+ break;
+ case DatasetMode::NIGHTLY:
+ stream << "NIGHTLY";
+ break;
+ case DatasetMode::ALL:
+ stream << "ALL";
+ break;
+ default:
+ throw std::invalid_argument("Unsupported dataset mode");
+ }
+
+ return stream;
+}
+
+inline std::string to_string(DatasetMode mode)
+{
+ std::stringstream stream;
+ stream << mode;
+ return stream.str();
+}
+} // namespace framework
+} // namespace test
+} // namespace arm_compute
+#endif /* ARM_COMPUTE_TEST_DATASET_MODES */
diff --git a/framework/Framework.cpp b/framework/Framework.cpp
index 72fa1981fc..c25b3e5d4c 100644
--- a/framework/Framework.cpp
+++ b/framework/Framework.cpp
@@ -92,11 +92,12 @@ Framework &Framework::get()
return instance;
}
-void Framework::init(const std::vector<InstrumentType> &instruments, int num_iterations, const std::string &name_filter, const std::string &id_filter)
+void Framework::init(const std::vector<InstrumentType> &instruments, int num_iterations, DatasetMode mode, const std::string &name_filter, const std::string &id_filter)
{
_test_name_filter = std::regex{ name_filter };
_test_id_filter = std::regex{ id_filter };
_num_iterations = num_iterations;
+ _dataset_mode = mode;
_instruments = InstrumentType::NONE;
@@ -170,7 +171,27 @@ bool Framework::throw_errors() const
bool Framework::is_enabled(const TestId &id) const
{
- return (std::regex_search(support::cpp11::to_string(id.first), _test_id_filter) && std::regex_search(id.second, _test_name_filter));
+ int test_id = 0;
+ std::string name;
+ DatasetMode mode = DatasetMode::ALL;
+ std::tie(test_id, name, mode) = id;
+
+ if((mode & _dataset_mode) == DatasetMode::DISABLED)
+ {
+ return false;
+ }
+
+ if(!std::regex_search(support::cpp11::to_string(test_id), _test_id_filter))
+ {
+ return false;
+ }
+
+ if(!std::regex_search(name, _test_name_filter))
+ {
+ return false;
+ }
+
+ return true;
}
void Framework::run_test(TestCaseFactory &test_factory)
@@ -276,7 +297,7 @@ bool Framework::run()
{
const std::string test_case_name = test_factory->name();
- if(!is_enabled(TestId(id, test_case_name)))
+ if(!is_enabled(TestId(id, test_case_name, test_factory->mode())))
{
log_test_skipped(test_case_name);
}
@@ -355,9 +376,9 @@ std::vector<Framework::TestId> Framework::test_ids() const
for(const auto &factory : _test_factories)
{
- if(is_enabled(TestId(id, factory->name())))
+ if(is_enabled(TestId(id, factory->name(), factory->mode())))
{
- ids.emplace_back(id, factory->name());
+ ids.emplace_back(id, factory->name(), factory->mode());
}
++id;
diff --git a/framework/Framework.h b/framework/Framework.h
index fbb6b9c04c..a7d8a15541 100644
--- a/framework/Framework.h
+++ b/framework/Framework.h
@@ -24,6 +24,7 @@
#ifndef ARM_COMPUTE_TEST_FRAMEWORK
#define ARM_COMPUTE_TEST_FRAMEWORK
+#include "DatasetModes.h"
#include "Profiler.h"
#include "TestCase.h"
#include "TestCaseFactory.h"
@@ -60,12 +61,13 @@ class Framework final
public:
/** Type of a test identifier.
*
- * A test can be identified either via its id or via its name.
+ * A test can be identified either via its id or via its name. Additionally
+ * each test is tagged with the data set mode in which it will be used.
*
* @note The mapping between test id and test name is not guaranteed to be
* stable. It is subject to change as new test are added.
*/
- using TestId = std::pair<int, std::string>;
+ using TestId = std::tuple<int, std::string, DatasetMode>;
/** Access to the singleton.
*
@@ -83,10 +85,11 @@ public:
*
* @param[in] instruments Instrument types that will be used for benchmarking.
* @param[in] num_iterations Number of iterations per test.
+ * @param[in] mode Dataset mode.
* @param[in] name_filter Regular expression to filter tests by name. Only matching tests will be executed.
* @param[in] id_filter Regular expression to filter tests by id. Only matching tests will be executed.
*/
- void init(const std::vector<InstrumentType> &instruments, int num_iterations, const std::string &name_filter, const std::string &id_filter);
+ void init(const std::vector<InstrumentType> &instruments, int num_iterations, DatasetMode mode, const std::string &name_filter, const std::string &id_filter);
/** Add a new test suite.
*
@@ -109,18 +112,20 @@ public:
/** Add a test case to the framework.
*
* @param[in] test_name Name of the new test case.
+ * @param[in] mode Mode in which to include the test.
*/
template <typename T>
- void add_test_case(std::string test_name);
+ void add_test_case(std::string test_name, DatasetMode mode);
/** Add a data test case to the framework.
*
* @param[in] test_name Name of the new test case.
+ * @param[in] mode Mode in which to include the test.
* @param[in] description Description of @p data.
* @param[in] data Data that will be used as input to the test.
*/
template <typename T, typename D>
- void add_data_test_case(std::string test_name, std::string description, D &&data);
+ void add_data_test_case(std::string test_name, DatasetMode mode, std::string description, D &&data);
/** Tell the framework that execution of a test starts.
*
@@ -255,21 +260,22 @@ private:
InstrumentType _instruments{ InstrumentType::NONE };
std::regex _test_name_filter{ ".*" };
std::regex _test_id_filter{ ".*" };
+ DatasetMode _dataset_mode{ DatasetMode::ALL };
};
template <typename T>
-inline void Framework::add_test_case(std::string test_name)
+inline void Framework::add_test_case(std::string test_name, DatasetMode mode)
{
- _test_factories.emplace_back(support::cpp14::make_unique<SimpleTestCaseFactory<T>>(current_suite_name(), std::move(test_name)));
+ _test_factories.emplace_back(support::cpp14::make_unique<SimpleTestCaseFactory<T>>(current_suite_name(), std::move(test_name), mode));
}
template <typename T, typename D>
-inline void Framework::add_data_test_case(std::string test_name, std::string description, D &&data)
+inline void Framework::add_data_test_case(std::string test_name, DatasetMode mode, std::string description, D &&data)
{
// WORKAROUND for GCC 4.9
// The function should get *it which is tuple but that seems to trigger a
// bug in the compiler.
- auto tmp = std::unique_ptr<DataTestCaseFactory<T, decltype(*std::declval<D>())>>(new DataTestCaseFactory<T, decltype(*std::declval<D>())>(current_suite_name(), std::move(test_name),
+ auto tmp = std::unique_ptr<DataTestCaseFactory<T, decltype(*std::declval<D>())>>(new DataTestCaseFactory<T, decltype(*std::declval<D>())>(current_suite_name(), std::move(test_name), mode,
std::move(description), *data));
_test_factories.emplace_back(std::move(tmp));
}
diff --git a/framework/Macros.h b/framework/Macros.h
index e3ef71ac56..38eb29c6a1 100644
--- a/framework/Macros.h
+++ b/framework/Macros.h
@@ -76,28 +76,28 @@
{ \
FIXTURE::teardown(); \
}
-#define TEST_REGISTRAR(TEST_NAME) \
+#define TEST_REGISTRAR(TEST_NAME, MODE) \
static arm_compute::test::framework::detail::TestCaseRegistrar<TEST_NAME> TEST_NAME##_reg \
{ \
- #TEST_NAME \
+ #TEST_NAME, MODE \
}
-#define DATA_TEST_REGISTRAR(TEST_NAME, DATASET) \
+#define DATA_TEST_REGISTRAR(TEST_NAME, MODE, DATASET) \
static arm_compute::test::framework::detail::TestCaseRegistrar<TEST_NAME> TEST_NAME##_reg \
{ \
- #TEST_NAME, DATASET \
+ #TEST_NAME, MODE, DATASET \
}
-#define TEST_CASE(TEST_NAME) \
+#define TEST_CASE(TEST_NAME, MODE) \
class TEST_NAME : public arm_compute::test::framework::TestCase \
{ \
public: \
TEST_CASE_CONSTRUCTOR(TEST_NAME) \
void do_run() override; \
}; \
- TEST_REGISTRAR(TEST_NAME); \
+ TEST_REGISTRAR(TEST_NAME, MODE); \
void TEST_NAME::do_run()
-#define DATA_TEST_CASE(TEST_NAME, DATASET, ...) \
+#define DATA_TEST_CASE(TEST_NAME, MODE, DATASET, ...) \
class TEST_NAME : public arm_compute::test::framework::DataTestCase<decltype(DATASET)::type> \
{ \
public: \
@@ -108,10 +108,10 @@
} \
void run(__VA_ARGS__); \
}; \
- DATA_TEST_REGISTRAR(TEST_NAME, DATASET); \
+ DATA_TEST_REGISTRAR(TEST_NAME, MODE, DATASET); \
void TEST_NAME::run(__VA_ARGS__)
-#define FIXTURE_TEST_CASE(TEST_NAME, FIXTURE) \
+#define FIXTURE_TEST_CASE(TEST_NAME, FIXTURE, MODE) \
class TEST_NAME : public arm_compute::test::framework::TestCase, public FIXTURE \
{ \
public: \
@@ -120,10 +120,10 @@
void do_run() override; \
FIXTURE_TEARDOWN(FIXTURE) \
}; \
- TEST_REGISTRAR(TEST_NAME); \
+ TEST_REGISTRAR(TEST_NAME, MODE); \
void TEST_NAME::do_run()
-#define FIXTURE_DATA_TEST_CASE(TEST_NAME, FIXTURE, DATASET) \
+#define FIXTURE_DATA_TEST_CASE(TEST_NAME, FIXTURE, MODE, DATASET) \
class TEST_NAME : public arm_compute::test::framework::DataTestCase<decltype(DATASET)::type>, public FIXTURE \
{ \
public: \
@@ -132,10 +132,10 @@
void do_run() override; \
FIXTURE_TEARDOWN(FIXTURE) \
}; \
- DATA_TEST_REGISTRAR(TEST_NAME, DATASET); \
+ DATA_TEST_REGISTRAR(TEST_NAME, MODE, DATASET); \
void TEST_NAME::do_run()
-#define REGISTER_FIXTURE_TEST_CASE(TEST_NAME, FIXTURE) \
+#define REGISTER_FIXTURE_TEST_CASE(TEST_NAME, FIXTURE, MODE) \
class TEST_NAME : public arm_compute::test::framework::TestCase, public FIXTURE \
{ \
public: \
@@ -144,9 +144,9 @@
FIXTURE_RUN(FIXTURE) \
FIXTURE_TEARDOWN(FIXTURE) \
}; \
- TEST_REGISTRAR(TEST_NAME)
+ TEST_REGISTRAR(TEST_NAME, MODE)
-#define REGISTER_FIXTURE_DATA_TEST_CASE(TEST_NAME, FIXTURE, DATASET) \
+#define REGISTER_FIXTURE_DATA_TEST_CASE(TEST_NAME, FIXTURE, MODE, DATASET) \
class TEST_NAME : public arm_compute::test::framework::DataTestCase<decltype(DATASET)::type>, public FIXTURE \
{ \
public: \
@@ -155,7 +155,7 @@
FIXTURE_RUN(FIXTURE) \
FIXTURE_TEARDOWN(FIXTURE) \
}; \
- DATA_TEST_REGISTRAR(TEST_NAME, DATASET)
+ DATA_TEST_REGISTRAR(TEST_NAME, MODE, DATASET)
//
// TEST CASE MACROS END
//
diff --git a/framework/Registrars.h b/framework/Registrars.h
index 19064c07f5..ddbffabee4 100644
--- a/framework/Registrars.h
+++ b/framework/Registrars.h
@@ -24,6 +24,7 @@
#ifndef ARM_COMPUTE_TEST_FRAMEWORK_REGISTRARS
#define ARM_COMPUTE_TEST_FRAMEWORK_REGISTRARS
+#include "DatasetModes.h"
#include "Framework.h"
#include <string>
@@ -45,16 +46,18 @@ public:
/** Add a new test case with the given name to the framework.
*
* @param[in] test_name Name of the test case.
+ * @param[in] mode Mode in which the test should be activated.
*/
- TestCaseRegistrar(std::string test_name);
+ TestCaseRegistrar(std::string test_name, DatasetMode mode);
/** Add a new data test case with the given name to the framework.
*
* @param[in] test_name Name of the test case.
+ * @param[in] mode Mode in which the test should be activated.
* @param[in] dataset Dataset used as input for the test case.
*/
template <typename D>
- TestCaseRegistrar(std::string test_name, D &&dataset);
+ TestCaseRegistrar(std::string test_name, DatasetMode mode, D &&dataset);
};
/** Helper class to statically begin and end a test suite. */
@@ -72,14 +75,14 @@ public:
};
template <typename T>
-inline TestCaseRegistrar<T>::TestCaseRegistrar(std::string test_name)
+inline TestCaseRegistrar<T>::TestCaseRegistrar(std::string test_name, DatasetMode mode)
{
- Framework::get().add_test_case<T>(std::move(test_name));
+ Framework::get().add_test_case<T>(std::move(test_name), mode);
}
template <typename T>
template <typename D>
-inline TestCaseRegistrar<T>::TestCaseRegistrar(std::string test_name, D &&dataset)
+inline TestCaseRegistrar<T>::TestCaseRegistrar(std::string test_name, DatasetMode mode, D &&dataset)
{
auto it = dataset.begin();
@@ -88,7 +91,7 @@ inline TestCaseRegistrar<T>::TestCaseRegistrar(std::string test_name, D &&datase
// WORKAROUND for GCC 4.9
// The last argument should be *it to pass just the data and not the
// iterator.
- Framework::get().add_data_test_case<T>(test_name, it.description(), it);
+ Framework::get().add_data_test_case<T>(test_name, mode, it.description(), it);
}
}
diff --git a/framework/TestCaseFactory.h b/framework/TestCaseFactory.h
index 09e9d198d6..e275e298d6 100644
--- a/framework/TestCaseFactory.h
+++ b/framework/TestCaseFactory.h
@@ -24,6 +24,7 @@
#ifndef ARM_COMPUTE_TEST_TEST_CASE_FACTORY
#define ARM_COMPUTE_TEST_TEST_CASE_FACTORY
+#include "DatasetModes.h"
#include "TestCase.h"
#include "support/ToolchainSupport.h"
@@ -44,9 +45,10 @@ public:
*
* @param[in] suite_name Name of the test suite to which the test case has been added.
* @param[in] name Name of the test case.
+ * @param[in] mode Datset mode of the test case.
* @param[in] description Description of data arguments.
*/
- TestCaseFactory(std::string suite_name, std::string name, std::string description = "");
+ TestCaseFactory(std::string suite_name, std::string name, DatasetMode mode, std::string description = "");
/** Default destructor. */
virtual ~TestCaseFactory() = default;
@@ -57,6 +59,12 @@ public:
*/
std::string name() const;
+ /** Get the mode for which test case will be enabled.
+ *
+ * @return Dataset mode of the test case.
+ */
+ DatasetMode mode() const;
+
/** Factory function to create the test case
*
* @return Unique pointer to a newly created test case.
@@ -67,6 +75,7 @@ private:
const std::string _suite_name;
const std::string _test_name;
const std::string _data_description;
+ const DatasetMode _mode{ DatasetMode::ALL };
};
/** Implementation of a test case factory to create non-data test cases. */
@@ -88,10 +97,11 @@ public:
*
* @param[in] suite_name Name of the test suite to which the test case has been added.
* @param[in] test_name Name of the test case.
+ * @param[in] mode Mode in which the test case is enabled.
* @param[in] description Description of data arguments.
* @param[in] data Input data for the test case.
*/
- DataTestCaseFactory(std::string suite_name, std::string test_name, std::string description, const D &data);
+ DataTestCaseFactory(std::string suite_name, std::string test_name, DatasetMode mode, std::string description, const D &data);
std::unique_ptr<TestCase> make() const override;
@@ -99,8 +109,8 @@ private:
D _data;
};
-inline TestCaseFactory::TestCaseFactory(std::string suite_name, std::string test_name, std::string description)
- : _suite_name{ std::move(suite_name) }, _test_name{ std::move(test_name) }, _data_description{ std::move(description) }
+inline TestCaseFactory::TestCaseFactory(std::string suite_name, std::string test_name, DatasetMode mode, std::string description)
+ : _suite_name{ std::move(suite_name) }, _test_name{ std::move(test_name) }, _data_description{ std::move(description) }, _mode{ mode }
{
}
@@ -116,6 +126,11 @@ inline std::string TestCaseFactory::name() const
return name;
}
+inline DatasetMode TestCaseFactory::mode() const
+{
+ return _mode;
+}
+
template <typename T>
inline std::unique_ptr<TestCase> SimpleTestCaseFactory<T>::make() const
{
@@ -123,8 +138,8 @@ inline std::unique_ptr<TestCase> SimpleTestCaseFactory<T>::make() const
}
template <typename T, typename D>
-inline DataTestCaseFactory<T, D>::DataTestCaseFactory(std::string suite_name, std::string test_name, std::string description, const D &data)
- : TestCaseFactory{ std::move(suite_name), std::move(test_name), std::move(description) }, _data{ data }
+inline DataTestCaseFactory<T, D>::DataTestCaseFactory(std::string suite_name, std::string test_name, DatasetMode mode, std::string description, const D &data)
+ : TestCaseFactory{ std::move(suite_name), std::move(test_name), mode, std::move(description) }, _data{ data }
{
}