This commit is contained in:
Ara Ayvazyan 2020-02-08 22:32:02 -08:00 коммит произвёл GitHub
Родитель 2c46869792
Коммит 147ae6f480
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
30 изменённых файлов: 81 добавлений и 58 удалений

Просмотреть файл

@ -37,12 +37,12 @@ namespace IPC
using typename PacketConnectionHolder::OutputPacket;
public:
static_assert(!std::is_void<Request>::value, "Request cannot be void.");
static_assert(std::is_same<Connection, ClientConnection<Request, Response, Traits>>::value, "Connection definitions must be the same.");
using typename PacketConnectionHolder::Connection;
using TransactionManager = typename PacketConnectionHolder::Context;
static_assert(!std::is_void<Request>::value, "Request cannot be void.");
static_assert(std::is_same<Connection, ClientConnection<Request, Response, Traits>>::value, "Connection definitions must be the same.");
template <typename CloseHandler, typename U = Response, std::enable_if_t<!std::is_void<U>::value>* = nullptr>
Client(std::unique_ptr<Connection> connection, CloseHandler&& closeHandler, TransactionManager transactionManager = {})
: PacketConnectionHolder{

Просмотреть файл

@ -161,9 +161,7 @@ namespace IPC
}
private:
using Client = Client<detail::ConnectorInfo, detail::AcceptorInfo, Traits>;
class ConnectorClient : public Client
class ConnectorClient : public Client<detail::ConnectorInfo, detail::AcceptorInfo, Traits>
{
public:
ConnectorClient(
@ -202,8 +200,8 @@ namespace IPC
typename Traits::TransactionManagerFactory&& transactionManagerFactory,
detail::Callback<void()>&& closeHandler,
detail::KernelProcess process)
: Client{
std::make_unique<Connection>(
: ConnectorClient::Client{
std::make_unique<typename ConnectorClient::Connection>(
detail::KernelEvent{ create_only, false, false, pingInfo.m_connectorCloseEventName.c_str() },
true,
detail::KernelEvent{ open_only, acceptorHostInfo.m_acceptorCloseEventName.c_str() },
@ -212,7 +210,7 @@ namespace IPC
std::move(channels.first),
std::move(channels.second)),
std::move(closeHandler),
std::move(transactionManagerFactory)(detail::Identity<typename Client::TransactionManager>{}) },
std::move(transactionManagerFactory)(detail::Identity<typename ConnectorClient::Client::TransactionManager>{}) },
m_process{ std::move(process) },
m_channelFactory{ std::move(channelFactory) }
{}
@ -222,8 +220,10 @@ namespace IPC
auto channelFactoryInstance = channelFactory.MakeInstance();
// Create in a strict order. Must be the reverse of the acceptor.
auto output = channelFactoryInstance.template CreateOutput<typename Client::OutputPacket>(pingInfo.m_connectorInfoChannelName.c_str());
auto input = channelFactoryInstance.template CreateInput<typename Client::InputPacket>(pingInfo.m_acceptorInfoChannelName.c_str());
auto output = channelFactoryInstance.template CreateOutput<typename ConnectorClient::Client::OutputPacket>(
pingInfo.m_connectorInfoChannelName.c_str());
auto input = channelFactoryInstance.template CreateInput<typename ConnectorClient::Client::InputPacket>(
pingInfo.m_acceptorInfoChannelName.c_str());
return std::make_pair(std::move(input), std::move(output));
}
@ -425,7 +425,7 @@ namespace IPC
public:
template <typename... Args>
PacketConnector(Args&&... args) // TODO: Inherit constructors instead when VC14 bugs are fixed.
: Connector{ std::forward<Args>(args)... }
: PacketConnector::Connector{ std::forward<Args>(args)... }
{}
};

Просмотреть файл

@ -36,7 +36,7 @@ namespace Managed
template <typename T>
Vector<T>::Iterator::Iterator(const BaseIterator& it)
: shared_ptr{ std::make_shared<BaseIterator>(it) }
: std::shared_ptr<BaseIterator>{ std::make_shared<BaseIterator>(it) }
{}
template <typename T>
@ -53,7 +53,7 @@ namespace Managed
{
if (!this->operator bool())
{
shared_ptr::operator=(std::make_shared<BaseIterator>(container.m_impl->begin()));
std::shared_ptr<BaseIterator>::operator=(std::make_shared<BaseIterator>(container.m_impl->begin()));
}
else if (*this->get() != container.m_impl->end())
{
@ -126,13 +126,13 @@ namespace Managed
template <typename T>
auto Vector<T>::begin() -> Iterator
{
return m_impl->begin();
return { m_impl->begin() };
}
template <typename T>
auto Vector<T>::end() -> Iterator
{
return m_impl->end();
return { m_impl->end() };
}
template <typename T>

Просмотреть файл

@ -11,7 +11,7 @@ namespace Containers
template <typename T>
class Vector : public detail::Container<boost::interprocess::vector<T, SharedMemory::Allocator<T>>>
{
using Container::Container;
using Vector::Container::Container;
};
} // Containers

Просмотреть файл

@ -64,7 +64,7 @@ namespace Managed
{
public:
ServerFactoryLambda(HandlerFactory^ handlerFactory, const NativeConfig& config, ServersAccessor^ accessor)
: ComponentFactoryLambdaBase{ config, accessor },
: ServerFactoryLambda::ComponentFactoryLambdaBase{ config, accessor },
m_handlerFactory{ handlerFactory }
{}

Просмотреть файл

@ -26,7 +26,7 @@ namespace Managed
{
try
{
(*m_component)(
(*this->m_component)(
Cast(request),
MakeManagedCallback(gcnew InvokeLambda{ promise }),
std::chrono::milliseconds{ static_cast<std::chrono::milliseconds::rep>(timeout.TotalMilliseconds) });
@ -46,11 +46,11 @@ namespace Managed
internal:
Client(typename NativeClient::ConnectionPtr&& connection, const NativeConfig& config)
: Component{ std::move(connection), nullptr, *config }
: Client::Component{ std::move(connection), nullptr, *config }
{}
Client(typename NativeClient::ConnectionPtr&& connection, Interop::Callback<void()>&& closeHandler, const NativeConfig& config)
: Component{ std::move(connection), std::move(closeHandler), *config }
: Client::Component{ std::move(connection), std::move(closeHandler), *config }
{}
ref struct InvokeLambda

Просмотреть файл

@ -22,7 +22,7 @@ namespace Managed
ref struct SelfDisposer : NativeObject<T>
{
explicit SelfDisposer(const T& obj)
: NativeObject{ obj }
: NativeObject<T>{ obj }
{}
void operator()(void*)

Просмотреть файл

@ -56,7 +56,7 @@ namespace Managed
{
public:
ClientFactoryLambda(const NativeConfig& config, ClientAccessor^ accessor)
: ComponentFactoryLambdaBase{ config, accessor }
: ClientFactoryLambda::ComponentFactoryLambdaBase{ config, accessor }
{}
protected:

Просмотреть файл

@ -14,7 +14,7 @@ namespace Managed
{
template <typename Request, typename Response>
Transport<Request, Response>::ClientConnector::ClientConnector(const Config& config)
: shared_ptr{ std::make_shared<IPC::ClientConnector<Request, Response, Traits>>(
: ClientConnector::shared_ptr{ std::make_shared<IPC::ClientConnector<Request, Response, Traits>>(
config.m_channelSettings,
Policies::TransactionManagerFactory{ config.m_timeoutFactory, config.m_defaultRequestTimeout }) }
{}

Просмотреть файл

@ -34,7 +34,7 @@ namespace Managed
template <typename Request, typename Response>
Transport<Request, Response>::Client::Client(ConnectionPtr&& connection, CloseHandler&& closeHandler, const Config& config)
: unique_ptr{ std::make_unique<IPC::Client<Request, Response, Traits>>(
: Client::unique_ptr{ std::make_unique<IPC::Client<Request, Response, Traits>>(
std::move(connection),
std::move(closeHandler),
typename IPC::Client<Request, Response, Traits>::TransactionManager{ config.m_timeoutFactory, config.m_defaultRequestTimeout }) }

Просмотреть файл

@ -14,7 +14,7 @@ namespace Managed
{
template <typename Request, typename Response>
Transport<Request, Response>::ServerAcceptor::ServerAcceptor(const char* name, HandlerFactory&& handlerFactory, const Config& config)
: unique_ptr{ std::make_unique<IPC::ServerAcceptor<Request, Response, Traits>>(
: ServerAcceptor::unique_ptr{ std::make_unique<IPC::ServerAcceptor<Request, Response, Traits>>(
name,
[handlerFactory = std::move(handlerFactory)](auto&& futureConnection) mutable
{

Просмотреть файл

@ -33,7 +33,7 @@ namespace Managed
template <typename Request, typename Response>
Transport<Request, Response>::Server::Server(ConnectionPtr&& connection, CloseHandler&& closeHandler, Handler&& handler, const Config& /*config*/)
: unique_ptr{ std::make_unique<IPC::Server<Request, Response, Traits>>(std::move(connection), std::move(handler), std::move(closeHandler)) }
: Server::unique_ptr{ std::make_unique<IPC::Server<Request, Response, Traits>>(std::move(connection), std::move(handler), std::move(closeHandler)) }
{}
template <typename Request, typename Response>

Просмотреть файл

@ -46,7 +46,7 @@ namespace Managed
class Transport
{
public:
using CloseHandler = Callback<void()>;
typedef Callback<void()> CloseHandler;
class Server : public std::unique_ptr<IPC::Server<Request, Response, Traits>>
@ -54,7 +54,7 @@ namespace Managed
public:
struct ConnectionPtr : std::unique_ptr<IPC::ServerConnection<Request, Response, Traits>>
{
using unique_ptr::unique_ptr;
using std::unique_ptr<IPC::ServerConnection<Request, Response, Traits>>::unique_ptr;
ConnectionPtr(ConnectionPtr&& other);
@ -88,7 +88,7 @@ namespace Managed
public:
struct ConnectionPtr : std::unique_ptr<IPC::ClientConnection<Request, Response, Traits>>
{
using unique_ptr::unique_ptr;
using std::unique_ptr<IPC::ClientConnection<Request, Response, Traits>>::unique_ptr;
ConnectionPtr(ConnectionPtr&& other);

Просмотреть файл

@ -3,11 +3,6 @@
#include "IPC/Connect.h"
#include "IPC/Accept.h"
#include "Transport.h"
#include "ClientImpl.h"
#include "ServerImpl.h"
#include "ClientConnectorImpl.h"
#include "ServerAcceptorImpl.h"
#include <chrono>
namespace IPC
@ -34,7 +29,28 @@ namespace Managed
Traits::TimeoutFactory m_timeoutFactory;
};
} // Interop
} // detail
} // Managed
} // IPC
#include "ClientImpl.h"
#include "ServerImpl.h"
#include "ClientConnectorImpl.h"
#include "ServerAcceptorImpl.h"
#include <chrono>
namespace IPC
{
namespace Managed
{
namespace detail
{
namespace Interop
{
auto MakeChannelSettings(std::size_t memorySize, Traits::ReceiverFactory receiverFactory, Traits::WaitHandleFactory waitHandleFactory)
{
ChannelSettings<Traits> settings{ std::move(waitHandleFactory), std::move(receiverFactory) };

Просмотреть файл

@ -89,7 +89,7 @@ namespace Managed
{
if (!m_obj)
{
throw gcnew System::ObjectDisposedException{ gcnew System::String{ typeid(T).name() } };
throw gcnew System::ObjectDisposedException{ NativeObject::typeid->FullName };
}
return *m_obj;

Просмотреть файл

@ -36,11 +36,11 @@ namespace Managed
internal:
Server(typename NativeServer::ConnectionPtr&& connection, HandlerFactory^ handlerFactory, const NativeConfig& config)
: Component{ std::move(connection), nullptr, MakeHandlerFactory(connection, handlerFactory), *config }
: Server::Component{ std::move(connection), nullptr, MakeHandlerFactory(connection, handlerFactory), *config }
{}
Server(typename NativeServer::ConnectionPtr&& connection, HandlerFactory^ handlerFactory, Interop::Callback<void()>&& closeHandler, const NativeConfig& config)
: Component{ std::move(connection), std::move(closeHandler), MakeHandlerFactory(connection, handlerFactory), *config }
: Server::Component{ std::move(connection), std::move(closeHandler), MakeHandlerFactory(connection, handlerFactory), *config }
{}
~Server()

Просмотреть файл

@ -36,12 +36,12 @@ namespace IPC
using typename PacketConnectionHolder::OutputPacket;
public:
static_assert(!std::is_void<Request>::value, "Request cannot be void.");
static_assert(std::is_same<Connection, ServerConnection<Request, Response, Traits>>::value, "Connection definitions must be the same.");
using typename PacketConnectionHolder::Connection;
using HandlerCallback = typename PacketConnectionHolder::HandlerCallback;
static_assert(!std::is_void<Request>::value, "Request cannot be void.");
static_assert(std::is_same<Connection, ServerConnection<Request, Response, Traits>>::value, "Connection definitions must be the same.");
template <typename Handler, typename CloseHandler>
Server(std::unique_ptr<Connection> connection, Handler&& handler, CloseHandler&& closeHandler)
: PacketConnectionHolder{

Просмотреть файл

@ -39,7 +39,7 @@ namespace IPC
{
public:
explicit Instance(ChannelSettings<Traits> settings)
: ChannelSettings{ std::move(settings) }
: Instance::ChannelSettings{ std::move(settings) }
{}
template <typename T>
@ -71,7 +71,7 @@ namespace IPC
auto MakeInput(OpenOrCreate openOrCreate, const char* name)
{
return InputChannel<T, Traits>{
openOrCreate, name, GetMemory(openOrCreate, true, name, *this), GetWaitHandleFactory(), GetReceiverFactory() };
openOrCreate, name, GetMemory(openOrCreate, true, name, *this), this->GetWaitHandleFactory(), this->GetReceiverFactory() };
}
template <typename T, typename OpenOrCreate>
@ -83,7 +83,7 @@ namespace IPC
explicit ChannelFactory(ChannelSettings<Traits> settings)
: ChannelSettings{ std::move(settings) }
: ChannelFactory::ChannelSettings{ std::move(settings) }
{}
auto MakeInstance() const

Просмотреть файл

@ -23,7 +23,7 @@ namespace IPC
ComponentFactory&& componentFactory,
TransactionArgs&&... transactionArgs)
{
using Component = decltype(componentFactory(
using Component = typename decltype(componentFactory(
std::declval<std::unique_ptr<typename Connector::Connection>>(),
std::declval<Callback<void()>>()))::element_type; // Deduce the component type.

Просмотреть файл

@ -26,7 +26,7 @@ namespace IPC
protected:
template <typename... Handlers>
PacketConnectionHolder(std::unique_ptr<typename PacketConnectionHolder::Connection> connection, Context context, Handlers&&... handlers)
: ConnectionHolder{ std::move(connection) },
: PacketConnectionHolder::ConnectionHolder{ std::move(connection) },
Context{ std::move(context) }
{
this->Register(std::forward<Handlers>(handlers)...);

Просмотреть файл

@ -65,12 +65,13 @@
<AdditionalIncludeDirectories>..\..\Inc;..\Inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;BOOST_USE_WINDOWS_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4494;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<WholeProgramOptimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</WholeProgramOptimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AnySuitable</InlineFunctionExpansion>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Speed</FavorSizeOrSpeed>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

Просмотреть файл

@ -44,8 +44,9 @@
</Lib>
<ClCompile>
<AdditionalIncludeDirectories>..\Inc;..\..\Inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>IPC_MANAGED_EXPORT;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>IPC_MANAGED_EXPORT;_SCL_SECURE_NO_WARNINGS;BOOST_USE_WINDOWS_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>

Просмотреть файл

@ -77,7 +77,7 @@ namespace Managed
Interop::Policies::ReceiverFactory MakeReceiverFactory()
{
return []
return { []
{
msclr::gcroot<Scheduler^> scheduler{ gcnew Scheduler{} };
@ -87,7 +87,7 @@ namespace Managed
{
scheduler->Schedule(std::move(callback));
};
};
} };
}
} // Policies

Просмотреть файл

@ -41,8 +41,9 @@
</Lib>
<ClCompile>
<AdditionalIncludeDirectories>..\Inc;..\..\Inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;BOOST_USE_WINDOWS_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>

Просмотреть файл

@ -127,9 +127,10 @@
<AdditionalIncludeDirectories>..\..\Inc;..\Inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;BOOST_USE_WINDOWS_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NDEBUG;BOOST_USE_WINDOWS_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4494;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

Просмотреть файл

@ -46,8 +46,9 @@
<ClCompile>
<AdditionalIncludeDirectories>..\..\Inc;..\Inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;BOOST_USE_WINDOWS_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

Просмотреть файл

@ -42,9 +42,10 @@
</Lib>
<ClCompile>
<AdditionalIncludeDirectories>..\Inc;..\..\Inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;BOOST_USE_WINDOWS_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4494;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>

Просмотреть файл

@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE(AcceptedServerAutoRemovalTest)
BOOST_TEST(context.use_count() == 2);
BOOST_TEST(serversAccessor()->empty());
std::make_unique<decltype(serversAccessor)>(std::move(serversAccessor));
(void)std::make_unique<decltype(serversAccessor)>(std::move(serversAccessor));
BOOST_TEST(waitHandleFactory.Process() != 0);
BOOST_TEST(context.unique());

Просмотреть файл

@ -42,9 +42,10 @@
<AdditionalIncludeDirectories>..\..\Inc;..\..\Native\Inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<PrecompiledHeader>Use</PrecompiledHeader>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;BOOST_USE_WINDOWS_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4494;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

Просмотреть файл

@ -262,7 +262,7 @@ BOOST_AUTO_TEST_CASE(ServerReconnectionTest)
BOOST_TEST(!connection->IsClosed());
}
std::make_unique<decltype(serverAccessor)>(std::move(serverAccessor));
(void)std::make_unique<decltype(serverAccessor)>(std::move(serverAccessor));
BOOST_TEST(context.unique());
}