text:
#include <fstream>
#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include "Config.h"
#include "FS.h"
#include "Log.h"
#include "Identity.h"
#include "util.h"
#include "ClientContext.h"
#include "SOCKS.h"
#include "WebSocks.h"
#include "MatchedDestination.h"

namespace dotnet
{
namespace client
{
	ClientContext context;

	ClientContext::ClientContext (): m_SharedLocalDestination (nullptr),
		m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_SamBridge (nullptr),
		m_BOBCommandChannel (nullptr), m_DNCPServer (nullptr)
	{
	}

	ClientContext::~ClientContext ()
	{
		delete m_HttpProxy;
		delete m_SocksProxy;
		delete m_SamBridge;
		delete m_BOBCommandChannel;
		delete m_DNCPServer;
	}

	void ClientContext::Start ()
	{
		// shared local destination
		if (!m_SharedLocalDestination)
			CreateNewSharedLocalDestination ();

		// addressbook
		m_AddressBook.Start ();

		// HTTP proxy
		ReadHttpProxy ();

		// SOCKS proxy
		ReadSocksProxy ();

		// DOTNET tunnels
		ReadTunnels ();

		// SAM
		bool sam; dotnet::config::GetOption("sam.enabled", sam);
		if (sam) {
			std::string samAddr; dotnet::config::GetOption("sam.address", samAddr);
			uint16_t    samPort; dotnet::config::GetOption("sam.port",    samPort);
			LogPrint(eLogInfo, "Clients: starting SAM bridge at ", samAddr, ":", samPort);
			try {
			  m_SamBridge = new SAMBridge (samAddr, samPort);
			  m_SamBridge->Start ();
			} catch (std::exception& e) {
			  LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what());
			}
		}

		// BOB
		bool bob; dotnet::config::GetOption("bob.enabled", bob);
		if (bob) {
			std::string bobAddr; dotnet::config::GetOption("bob.address", bobAddr);
			uint16_t    bobPort; dotnet::config::GetOption("bob.port",    bobPort);
			LogPrint(eLogInfo, "Clients: starting BOB command channel at ", bobAddr, ":", bobPort);
			try {
			  m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort);
			  m_BOBCommandChannel->Start ();
			} catch (std::exception& e) {
			  LogPrint(eLogError, "Clients: Exception in BOB bridge: ", e.what());
			}
		}

		// DNCP
		bool dncp; dotnet::config::GetOption("dncp.enabled", dncp);
		if (dncp)
		{
			std::string dncpAddr; dotnet::config::GetOption("dncp.address", dncpAddr);
			uint16_t dncpPort; dotnet::config::GetOption("dncp.port", dncpPort);
			LogPrint(eLogInfo, "Clients: starting DNCP at ", dncpAddr, ":", dncpPort);
			try
			{
				m_DNCPServer = new DNCPServer (dncpAddr, dncpPort);
				m_DNCPServer->Start ();
			}
			catch (std::exception& e)
			{
				LogPrint(eLogError, "Clients: Exception in DNCP: ", e.what());
			}
		}

		m_AddressBook.StartResolvers ();

		// start UDP cleanup
		if (!m_ServerForwards.empty ())
		{
			m_CleanupUDPTimer.reset (new boost::asio::deadline_timer(m_SharedLocalDestination->GetService ()));
			ScheduleCleanupUDP();
		}
	}

	void ClientContext::Stop ()
	{
		if (m_HttpProxy)
		{
			LogPrint(eLogInfo, "Clients: stopping HTTP Proxy");
			m_HttpProxy->Stop();
			delete m_HttpProxy;
			m_HttpProxy = nullptr;
		}

		if (m_SocksProxy)
		{
			LogPrint(eLogInfo, "Clients: stopping SOCKS Proxy");
			m_SocksProxy->Stop();
			delete m_SocksProxy;
			m_SocksProxy = nullptr;
		}

		for (auto& it: m_ClientTunnels)
		{
			LogPrint(eLogInfo, "Clients: stopping .NET client tunnel on port ", it.first);
			it.second->Stop ();
		}
		m_ClientTunnels.clear ();

		for (auto& it: m_ServerTunnels)
		{
			LogPrint(eLogInfo, "Clients: stopping .NET server tunnel");
			it.second->Stop ();
		}
		m_ServerTunnels.clear ();

		if (m_SamBridge)
		{
			LogPrint(eLogInfo, "Clients: stopping SAM bridge");
			m_SamBridge->Stop ();
			delete m_SamBridge;
			m_SamBridge = nullptr;
		}

		if (m_BOBCommandChannel)
		{
			LogPrint(eLogInfo, "Clients: stopping BOB command channel");
			m_BOBCommandChannel->Stop ();
			delete m_BOBCommandChannel;
			m_BOBCommandChannel = nullptr;
		}

		if (m_DNCPServer)
		{
			LogPrint(eLogInfo, "Clients: stopping DNCP");
			m_DNCPServer->Stop ();
			delete m_DNCPServer;
			m_DNCPServer = nullptr;
		}

		LogPrint(eLogInfo, "Clients: stopping AddressBook");
		m_AddressBook.Stop ();

	{
			std::lock_guard<std::mutex> lock(m_ForwardsMutex);
			m_ServerForwards.clear();
			m_ClientForwards.clear();
		}

		if (m_CleanupUDPTimer)
		{
			m_CleanupUDPTimer->cancel ();
			m_CleanupUDPTimer = nullptr;
		}

		for (auto& it: m_Destinations)
			it.second->Stop ();
		m_Destinations.clear ();
		m_SharedLocalDestination = nullptr;
	}

	void ClientContext::ReloadConfig ()
	{
		// TODO: handle config changes
		/*std::string config; dotnet::config::GetOption("conf", config);
		dotnet::config::ParseConfig(config);*/

		// handle tunnels
		// reset isUpdated for each tunnel
		VisitTunnels ([](DotNetService * s)->bool { s->isUpdated = false; return true; });
		// reload tunnels
		ReadTunnels();
		// delete not updated tunnels (not in config anymore)
		VisitTunnels ([](DotNetService * s)->bool { return s->isUpdated; });

		// change shared local destination
		m_SharedLocalDestination->Release ();
		CreateNewSharedLocalDestination ();

		// recreate HTTP proxy
		if (m_HttpProxy)
		{
			m_HttpProxy->Stop ();
			m_HttpProxy = nullptr;
		}
		ReadHttpProxy ();

		// recreate SOCKS proxy
		if (m_SocksProxy)
		{
			m_SocksProxy->Stop ();
			m_SocksProxy = nullptr;
		}
		ReadSocksProxy ();

		// delete unused destinations
		std::unique_lock<std::mutex> l(m_DestinationsMutex);
		for (auto it = m_Destinations.begin (); it != m_Destinations.end ();)
		{
			auto dest = it->second;
			if (dest->GetRefCounter () > 0) ++it; // skip
			else
			{
				dest->Stop ();
				it = m_Destinations.erase (it);
			}
		}
	}

	bool ClientContext::LoadPrivateKeys (dotnet::data::PrivateKeys& keys, const std::string& filename,
		dotnet::data::SigningKeyType sigType, dotnet::data::CryptoKeyType cryptoType)
	{
		if (filename == "transient")
		{
			keys = dotnet::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
			LogPrint (eLogInfo, "Clients: New transient keys address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
			return true;
		}

		bool success = true;
		std::string fullPath = dotnet::fs::DataDirPath (filename);
		std::ifstream s(fullPath, std::ifstream::binary);
		if (s.is_open ())
		{
			s.seekg (0, std::ios::end);
			size_t len = s.tellg();
			s.seekg (0, std::ios::beg);
			uint8_t * buf = new uint8_t[len];
			s.read ((char *)buf, len);
			if(!keys.FromBuffer (buf, len))
			{
				LogPrint (eLogError, "Clients: failed to load keyfile ", filename);
				success = false;
			}
			else
				LogPrint (eLogInfo, "Clients: Local address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " loaded");
			delete[] buf;
		}
		else
		{
			LogPrint (eLogError, "Clients: can't open file ", fullPath, " Creating new one with signature type ", sigType, " crypto type ", cryptoType);
			keys = dotnet::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
			std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
			size_t len = keys.GetFullLen ();
			uint8_t * buf = new uint8_t[len];
			len = keys.ToBuffer (buf, len);
			f.write ((char *)buf, len);
			delete[] buf;

			LogPrint (eLogInfo, "Clients: New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
		}
		return success;
	}

	std::vector<std::shared_ptr<DatagramSessionInfo> > ClientContext::GetForwardInfosFor(const dotnet::data::IdentHash & destination)
	{
		std::vector<std::shared_ptr<DatagramSessionInfo> > infos;
		std::lock_guard<std::mutex> lock(m_ForwardsMutex);
		for(const auto & c : m_ClientForwards)
		{
			if (c.second->IsLocalDestination(destination))
			{
				for (auto & i : c.second->GetSessions()) infos.push_back(i);
				break;
			}
		}
		for(const auto & s : m_ServerForwards)
		{
			if(std::get<0>(s.first) == destination)
			{
				for( auto & i : s.second->GetSessions()) infos.push_back(i);
				break;
			}
		}
		return infos;
	}

	std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (bool isPublic,
		dotnet::data::SigningKeyType sigType, dotnet::data::CryptoKeyType cryptoType,
		const std::map<std::string, std::string> * params)
	{
		dotnet::data::PrivateKeys keys = dotnet::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
		auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
		std::unique_lock<std::mutex> l(m_DestinationsMutex);
		m_Destinations[localDestination->GetIdentHash ()] = localDestination;
		localDestination->Start ();
		return localDestination;
	}

	std::shared_ptr<ClientDestination> ClientContext::CreateNewMatchedTunnelDestination(const dotnet::data::PrivateKeys &keys, const std::string & name, const std::map<std::string, std::string> * params)
	{
		MatchedTunnelDestination * cl = new MatchedTunnelDestination(keys, name, params);
		auto localDestination = std::shared_ptr<ClientDestination>(cl);
		std::unique_lock<std::mutex> l(m_DestinationsMutex);
		m_Destinations[localDestination->GetIdentHash ()] = localDestination;
		localDestination->Start ();
		return localDestination;
	}

	void ClientContext::DeleteLocalDestination (std::shared_ptr<ClientDestination> destination)
	{
		if (!destination) return;
		auto it = m_Destinations.find (destination->GetIdentHash ());
		if (it != m_Destinations.end ())
		{
			auto d = it->second;
			{
				std::unique_lock<std::mutex> l(m_DestinationsMutex);
				m_Destinations.erase (it);
			}
			d->Stop ();
		}
	}

	std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (const dotnet::data::PrivateKeys& keys, bool isPublic,
		const std::map<std::string, std::string> * params)
	{
		auto it = m_Destinations.find (keys.GetPublic ()->GetIdentHash ());
		if (it != m_Destinations.end ())
		{
			LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists");
			if (!it->second->IsRunning ())
				it->second->Start ();
			return it->second;
		}
		auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
		std::unique_lock<std::mutex> l(m_DestinationsMutex);
		m_Destinations[keys.GetPublic ()->GetIdentHash ()] = localDestination;
		localDestination->Start ();
		return localDestination;
	}

	void ClientContext::CreateNewSharedLocalDestination ()
	{
		m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, EDDSA
		m_SharedLocalDestination->Acquire ();
	}

	std::shared_ptr<ClientDestination> ClientContext::FindLocalDestination (const dotnet::data::IdentHash& destination) const
	{
		auto it = m_Destinations.find (destination);
		if (it != m_Destinations.end ())
			return it->second;
		return nullptr;
	}

	template<typename Section, typename Type>
	std::string ClientContext::GetDNCPOption (const Section& section, const std::string& name, const Type& value) const
	{
        return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::to_string (value));
	}

	template<typename Section>
	std::string ClientContext::GetDNCPStringOption (const Section& section, const std::string& name, const std::string& value) const
	{
        return section.second.get (boost::property_tree::ptree::path_type (name, '/'), value);
	}

	template<typename Section>
	void ClientContext::ReadDNCPOptions (const Section& section, std::map<std::string, std::string>& options) const
	{
		options[DNCP_PARAM_INBOUND_TUNNEL_LENGTH] = GetDNCPOption (section, DNCP_PARAM_INBOUND_TUNNEL_LENGTH,  DEFAULT_INBOUND_TUNNEL_LENGTH);
		options[DNCP_PARAM_OUTBOUND_TUNNEL_LENGTH] = GetDNCPOption (section, DNCP_PARAM_OUTBOUND_TUNNEL_LENGTH, DEFAULT_OUTBOUND_TUNNEL_LENGTH);
		options[DNCP_PARAM_INBOUND_TUNNELS_QUANTITY] = GetDNCPOption (section, DNCP_PARAM_INBOUND_TUNNELS_QUANTITY, DEFAULT_INBOUND_TUNNELS_QUANTITY);
		options[DNCP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = GetDNCPOption (section, DNCP_PARAM_OUTBOUND_TUNNELS_QUANTITY, DEFAULT_OUTBOUND_TUNNELS_QUANTITY);
		options[DNCP_PARAM_TAGS_TO_SEND] = GetDNCPOption (section, DNCP_PARAM_TAGS_TO_SEND, DEFAULT_TAGS_TO_SEND);
		options[DNCP_PARAM_MIN_TUNNEL_LATENCY] = GetDNCPOption(section, DNCP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY);
		options[DNCP_PARAM_MAX_TUNNEL_LATENCY] = GetDNCPOption(section, DNCP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY);
		options[DNCP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetDNCPOption(section, DNCP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY);
		options[DNCP_PARAM_LEASESET_TYPE] = GetDNCPOption(section, DNCP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE);
		std::string encType = GetDNCPStringOption(section, DNCP_PARAM_LEASESET_ENCRYPTION_TYPE, "");
		if (encType.length () > 0) options[DNCP_PARAM_LEASESET_ENCRYPTION_TYPE] = encType;
	}

	void ClientContext::ReadDNCPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const
	{
		std::string value;
		if (dotnet::config::GetOption(prefix + DNCP_PARAM_INBOUND_TUNNEL_LENGTH, value))
			options[DNCP_PARAM_INBOUND_TUNNEL_LENGTH] = value;
		if (dotnet::config::GetOption(prefix + DNCP_PARAM_INBOUND_TUNNELS_QUANTITY, value))
			options[DNCP_PARAM_INBOUND_TUNNELS_QUANTITY] = value;
		if (dotnet::config::GetOption(prefix + DNCP_PARAM_OUTBOUND_TUNNEL_LENGTH, value))
			options[DNCP_PARAM_OUTBOUND_TUNNEL_LENGTH] = value;
		if (dotnet::config::GetOption(prefix + DNCP_PARAM_OUTBOUND_TUNNELS_QUANTITY, value))
			options[DNCP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = value;
		if (dotnet::config::GetOption(prefix + DNCP_PARAM_MIN_TUNNEL_LATENCY, value))
			options[DNCP_PARAM_MIN_TUNNEL_LATENCY] = value;
		if (dotnet::config::GetOption(prefix + DNCP_PARAM_MAX_TUNNEL_LATENCY, value))
			options[DNCP_PARAM_MAX_TUNNEL_LATENCY] = value;
	}

	void ClientContext::ReadTunnels ()
	{
		int numClientTunnels = 0, numServerTunnels = 0;
		std::string tunConf; dotnet::config::GetOption("tunconf", tunConf);
		if (tunConf.empty ())
		{
			// TODO: cleanup this in 2.8.0
			tunConf = dotnet::fs::DataDirPath ("tunnels.cfg");
			if (dotnet::fs::Exists(tunConf))
				LogPrint(eLogWarning, "Clients: please rename tunnels.cfg -> tunnels.conf here: ", tunConf);
			else
				tunConf = dotnet::fs::DataDirPath ("tunnels.conf");
		}
		LogPrint(eLogDebug, "Clients: tunnels config file: ", tunConf);
		ReadTunnels (tunConf, numClientTunnels, numServerTunnels);

		std::string tunDir; dotnet::config::GetOption("tunnelsdir", tunDir);
		if (tunDir.empty ())
			tunDir = dotnet::fs::DataDirPath ("tunnels.d");
		if (dotnet::fs::Exists (tunDir))
		{
			std::vector<std::string> files;
			if (dotnet::fs::ReadDir (tunDir, files))
			{
				for (auto& it: files)
				{
					LogPrint(eLogDebug, "Clients: tunnels extra config file: ", it);
					ReadTunnels (it, numClientTunnels, numServerTunnels);
				}
			}
		}

		LogPrint (eLogInfo, "Clients: ", numClientTunnels, " client tunnels created");
		LogPrint (eLogInfo, "Clients: ", numServerTunnels, " server tunnels created");
	}

	void ClientContext::ReadTunnels (const std::string& tunConf, int& numClientTunnels, int& numServerTunnels)
	{
		boost::property_tree::ptree pt;
		try
		{
			boost::property_tree::read_ini (tunConf, pt);
		}
		catch (std::exception& ex)
		{
			LogPrint (eLogWarning, "Clients: Can't read ", tunConf, ": ", ex.what ());
			return;
		}

		for (auto& section: pt)
		{
			std::string name = section.first;
			try
			{
				std::string type = section.second.get<std::string> (DOTNET_TUNNELS_SECTION_TYPE);
				if (type == DOTNET_TUNNELS_SECTION_TYPE_CLIENT
						|| type == DOTNET_TUNNELS_SECTION_TYPE_SOCKS
						|| type == DOTNET_TUNNELS_SECTION_TYPE_WEBSOCKS
						|| type == DOTNET_TUNNELS_SECTION_TYPE_HTTPPROXY
						|| type == DOTNET_TUNNELS_SECTION_TYPE_UDPCLIENT)
				{
					// mandatory params
					std::string dest;
					if (type == DOTNET_TUNNELS_SECTION_TYPE_CLIENT || type == DOTNET_TUNNELS_SECTION_TYPE_UDPCLIENT)
						dest = section.second.get<std::string> (DOTNET_CLIENT_TUNNEL_DESTINATION);
					int port = section.second.get<int> (DOTNET_CLIENT_TUNNEL_PORT);
					// optional params
					bool matchTunnels = section.second.get(DOTNET_CLIENT_TUNNEL_MATCH_TUNNELS, false);
					std::string keys = section.second.get (DOTNET_CLIENT_TUNNEL_KEYS, "transient");
					std::string address = section.second.get (DOTNET_CLIENT_TUNNEL_ADDRESS, "127.0.0.1");
					int destinationPort = section.second.get (DOTNET_CLIENT_TUNNEL_DESTINATION_PORT, 0);
					dotnet::data::SigningKeyType sigType = section.second.get (DOTNET_CLIENT_TUNNEL_SIGNATURE_TYPE, dotnet::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
					dotnet::data::CryptoKeyType cryptoType = section.second.get (DOTNET_CLIENT_TUNNEL_CRYPTO_TYPE, dotnet::data::CRYPTO_KEY_TYPE_ELGAMAL);
					// DNCP
					std::map<std::string, std::string> options;
					ReadDNCPOptions (section, options);

					std::shared_ptr<ClientDestination> localDestination = nullptr;
					if (keys.length () > 0)
					{
						dotnet::data::PrivateKeys k;
						if(LoadPrivateKeys (k, keys, sigType, cryptoType))
						{
							localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ());
							if (!localDestination)
							{
								if(matchTunnels)
									localDestination = CreateNewMatchedTunnelDestination(k, dest, &options);
								else
									localDestination = CreateNewLocalDestination (k, type == DOTNET_TUNNELS_SECTION_TYPE_UDPCLIENT, &options);
							}
						}
					}

					if (type == DOTNET_TUNNELS_SECTION_TYPE_UDPCLIENT) {
						// udp client
						// TODO: hostnames
						boost::asio::ip::udp::endpoint end(boost::asio::ip::address::from_string(address), port);
						if (!localDestination)
						{
							localDestination = m_SharedLocalDestination;
						}
						auto clientTunnel = std::make_shared<DOTNETUDPClientTunnel>(name, dest, end, localDestination, destinationPort);
						if(m_ClientForwards.insert(std::make_pair(end, clientTunnel)).second)
						{
							clientTunnel->Start();
						}
						else
							LogPrint(eLogError, "Clients: .NET Client forward for endpoint ", end, " already exists");

					} else {
						boost::asio::ip::tcp::endpoint clientEndpoint;
						std::shared_ptr<DotNetService> clientTunnel;
						if (type == DOTNET_TUNNELS_SECTION_TYPE_SOCKS)
						{
							// socks proxy
							std::string outproxy = section.second.get("outproxy", "");
							auto tun = std::make_shared<dotnet::proxy::SOCKSProxy>(name, address, port, !outproxy.empty(), outproxy, destinationPort, localDestination);
							clientTunnel = tun;
							clientEndpoint = tun->GetLocalEndpoint ();
						}
						else if (type == DOTNET_TUNNELS_SECTION_TYPE_HTTPPROXY)
						{
							// http proxy
							std::string outproxy = section.second.get("outproxy", "");
							bool addresshelper = section.second.get("addresshelper", true);
							auto tun = std::make_shared<dotnet::proxy::HTTPProxy>(name, address, port, outproxy, addresshelper, localDestination);
							clientTunnel = tun;
							clientEndpoint = tun->GetLocalEndpoint ();
						}
						else if (type == DOTNET_TUNNELS_SECTION_TYPE_WEBSOCKS)
						{
							// websocks proxy
							auto tun = std::make_shared<WebSocks>(address, port, localDestination);
							clientTunnel = tun;
							clientEndpoint = tun->GetLocalEndpoint();
						}
						else
						{
							// tcp client
							auto tun = std::make_shared<DOTNETClientTunnel> (name, dest, address, port, localDestination, destinationPort);
							clientTunnel = tun;
							clientEndpoint = tun->GetLocalEndpoint ();
						}
						uint32_t timeout = section.second.get<uint32_t>(DOTNET_CLIENT_TUNNEL_CONNECT_TIMEOUT, 0);
						if(timeout)
						{
							clientTunnel->SetConnectTimeout(timeout);
							LogPrint(eLogInfo, "Clients: .NET Client tunnel connect timeout set to ", timeout);
						}

						auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, clientTunnel));
						if (ins.second)
						{
							clientTunnel->Start ();
							numClientTunnels++;
						}
						else
						{
							// TODO: update
							if (ins.first->second->GetLocalDestination () != clientTunnel->GetLocalDestination ())
							{
								LogPrint (eLogInfo, "Clients: .NET client tunnel destination updated");
								ins.first->second->SetLocalDestination (clientTunnel->GetLocalDestination ());
							}
							ins.first->second->isUpdated = true;
							LogPrint (eLogInfo, "Clients: .NET client tunnel for endpoint ", clientEndpoint, " already exists");
						}
					}
				}
				else if (type == DOTNET_TUNNELS_SECTION_TYPE_SERVER
								 || type == DOTNET_TUNNELS_SECTION_TYPE_HTTP
								 || type == DOTNET_TUNNELS_SECTION_TYPE_IRC
								 || type == DOTNET_TUNNELS_SECTION_TYPE_UDPSERVER)
				{
					// mandatory params
					std::string host = section.second.get<std::string> (DOTNET_SERVER_TUNNEL_HOST);
					int port = section.second.get<int> (DOTNET_SERVER_TUNNEL_PORT);
					std::string keys = section.second.get<std::string> (DOTNET_SERVER_TUNNEL_KEYS);
					// optional params
					int inPort = section.second.get (DOTNET_SERVER_TUNNEL_INPORT, 0);
					std::string accessList = section.second.get (DOTNET_SERVER_TUNNEL_ACCESS_LIST, "");
					std::string hostOverride = section.second.get (DOTNET_SERVER_TUNNEL_HOST_OVERRIDE, "");
					std::string webircpass = section.second.get<std::string> (DOTNET_SERVER_TUNNEL_WEBIRC_PASSWORD, "");
					bool gzip = section.second.get (DOTNET_SERVER_TUNNEL_GZIP, true);
					dotnet::data::SigningKeyType sigType = section.second.get (DOTNET_SERVER_TUNNEL_SIGNATURE_TYPE, dotnet::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
					dotnet::data::CryptoKeyType cryptoType = section.second.get (DOTNET_CLIENT_TUNNEL_CRYPTO_TYPE, dotnet::data::CRYPTO_KEY_TYPE_ELGAMAL);

					std::string address = section.second.get<std::string> (DOTNET_SERVER_TUNNEL_ADDRESS, "127.0.0.1");
					bool isUniqueLocal = section.second.get(DOTNET_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);

					// DNCP
					std::map<std::string, std::string> options;
					ReadDNCPOptions (section, options);

					std::shared_ptr<ClientDestination> localDestination = nullptr;
					dotnet::data::PrivateKeys k;
					if(!LoadPrivateKeys (k, keys, sigType, cryptoType))
						continue;
					localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ());
					if (!localDestination)
						localDestination = CreateNewLocalDestination (k, true, &options);
					if (type == DOTNET_TUNNELS_SECTION_TYPE_UDPSERVER)
					{
						// udp server tunnel
						// TODO: hostnames
						auto localAddress = boost::asio::ip::address::from_string(address);
						boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(host), port);
						auto serverTunnel = std::make_shared<DOTNETUDPServerTunnel>(name, localDestination, localAddress, endpoint, port);
						if(!isUniqueLocal)
						{
							LogPrint(eLogInfo, "Clients: disabling loopback address mapping");
							serverTunnel->SetUniqueLocal(isUniqueLocal);
						}
						std::lock_guard<std::mutex> lock(m_ForwardsMutex);
						if(m_ServerForwards.insert(
							std::make_pair(
								std::make_pair(
									localDestination->GetIdentHash(), port),
								serverTunnel)).second)
						{
							serverTunnel->Start();
							LogPrint(eLogInfo, "Clients: .NET Server Forward created for UDP Endpoint ", host, ":", port, " bound on ", address, " for ",localDestination->GetIdentHash().ToBase32());
						}
						else
							LogPrint(eLogError, "Clients: .NET Server Forward for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash()), "/", port, "already exists");

						continue;
					}

					std::shared_ptr<DOTNETServerTunnel>  serverTunnel;
					if (type == DOTNET_TUNNELS_SECTION_TYPE_HTTP)
						serverTunnel = std::make_shared<DOTNETServerTunnelHTTP> (name, host, port, localDestination, hostOverride, inPort, gzip);
					else if (type == DOTNET_TUNNELS_SECTION_TYPE_IRC)
						serverTunnel = std::make_shared<DOTNETServerTunnelIRC> (name, host, port, localDestination, webircpass, inPort, gzip);
					else // regular server tunnel by default
						serverTunnel = std::make_shared<DOTNETServerTunnel> (name, host, port, localDestination, inPort, gzip);

					if(!isUniqueLocal)
					{
						LogPrint(eLogInfo, "Clients: disabling loopback address mapping");
						serverTunnel->SetUniqueLocal(isUniqueLocal);
					}

					if (accessList.length () > 0)
					{
						std::set<dotnet::data::IdentHash> idents;
						size_t pos = 0, comma;
						do
						{
							comma = accessList.find (',', pos);
							dotnet::data::IdentHash ident;
							ident.FromBase32 (accessList.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos));
							idents.insert (ident);
							pos = comma + 1;
						}
						while (comma != std::string::npos);
						serverTunnel->SetAccessList (idents);
					}
					auto ins = m_ServerTunnels.insert (std::make_pair (
							std::make_pair (localDestination->GetIdentHash (), inPort),
							serverTunnel));
					if (ins.second)
					{
						serverTunnel->Start ();
						numServerTunnels++;
					}
					else
					{
						// TODO: update
						if (ins.first->second->GetLocalDestination () != serverTunnel->GetLocalDestination ())
						{
							LogPrint (eLogInfo, "Clients: .NET server tunnel destination updated");
							ins.first->second->SetLocalDestination (serverTunnel->GetLocalDestination ());
						}
						ins.first->second->isUpdated = true;
						LogPrint (eLogInfo, "Clients: .NET server tunnel for destination/port ",   m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists");
					}

				}
				else
					LogPrint (eLogWarning, "Clients: Unknown section type=", type, " of ", name, " in ", tunConf);

			}
			catch (std::exception& ex)
			{
				LogPrint (eLogError, "Clients: Can't read tunnel ", name, " params: ", ex.what ());
			}
		}
	}

	void ClientContext::ReadHttpProxy ()
	{
		std::shared_ptr<ClientDestination> localDestination;
		bool httproxy; dotnet::config::GetOption("httpproxy.enabled", httproxy);
		if (httproxy)
		{
			std::string httpProxyKeys; dotnet::config::GetOption("httpproxy.keys",    httpProxyKeys);
			std::string httpProxyAddr; dotnet::config::GetOption("httpproxy.address", httpProxyAddr);
			uint16_t    httpProxyPort; dotnet::config::GetOption("httpproxy.port",    httpProxyPort);
			dotnet::data::SigningKeyType sigType; dotnet::config::GetOption("httpproxy.signaturetype",  sigType);
			std::string httpOutProxyURL; dotnet::config::GetOption("httpproxy.outproxy",     httpOutProxyURL);
			bool httpAddresshelper; dotnet::config::GetOption("httpproxy.addresshelper", httpAddresshelper);
			LogPrint(eLogInfo, "Clients: starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort);
			if (httpProxyKeys.length () > 0)
			{
				dotnet::data::PrivateKeys keys;
				if(LoadPrivateKeys (keys, httpProxyKeys, sigType))
				{
					std::map<std::string, std::string> params;
					ReadDNCPOptionsFromConfig ("httpproxy.", params);
					localDestination = CreateNewLocalDestination (keys, false, &params);
					if (localDestination) localDestination->Acquire ();
				}
				else
					LogPrint(eLogError, "Clients: failed to load HTTP Proxy key");
			}
			try
			{
				m_HttpProxy = new dotnet::proxy::HTTPProxy("HTTP Proxy", httpProxyAddr, httpProxyPort, httpOutProxyURL, httpAddresshelper, localDestination);
				m_HttpProxy->Start();
			}
			catch (std::exception& e)
			{
				LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what());
			}
		}
	}

	void ClientContext::ReadSocksProxy ()
	{
		std::shared_ptr<ClientDestination> localDestination;
		bool socksproxy; dotnet::config::GetOption("socksproxy.enabled", socksproxy);
		if (socksproxy)
		{
			std::string socksProxyKeys; dotnet::config::GetOption("socksproxy.keys",     socksProxyKeys);
			std::string socksProxyAddr; dotnet::config::GetOption("socksproxy.address",  socksProxyAddr);
			uint16_t    socksProxyPort; dotnet::config::GetOption("socksproxy.port",     socksProxyPort);
			bool socksOutProxy; dotnet::config::GetOption("socksproxy.outproxy.enabled", socksOutProxy);
			std::string socksOutProxyAddr; dotnet::config::GetOption("socksproxy.outproxy",     socksOutProxyAddr);
			uint16_t    socksOutProxyPort; dotnet::config::GetOption("socksproxy.outproxyport", socksOutProxyPort);
			dotnet::data::SigningKeyType sigType; dotnet::config::GetOption("socksproxy.signaturetype",  sigType);
			LogPrint(eLogInfo, "Clients: starting SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort);
			if (socksProxyKeys.length () > 0)
			{
				dotnet::data::PrivateKeys keys;
				if (LoadPrivateKeys (keys, socksProxyKeys, sigType))
				{
					std::map<std::string, std::string> params;
					ReadDNCPOptionsFromConfig ("socksproxy.", params);
					localDestination = CreateNewLocalDestination (keys, false, &params);
					if (localDestination) localDestination->Acquire ();
				}
				else
					LogPrint(eLogError, "Clients: failed to load SOCKS Proxy key");
			}
			try
			{
				m_SocksProxy = new dotnet::proxy::SOCKSProxy("SOCKS", socksProxyAddr, socksProxyPort,
					socksOutProxy, socksOutProxyAddr, socksOutProxyPort, localDestination);
				m_SocksProxy->Start();
			}
			catch (std::exception& e)
			{
				LogPrint(eLogError, "Clients: Exception in SOCKS Proxy: ", e.what());
			}
		}
	}

	void ClientContext::ScheduleCleanupUDP()
	{
		if (m_CleanupUDPTimer)
		{
			// schedule cleanup in 17 seconds
			m_CleanupUDPTimer->expires_from_now (boost::posix_time::seconds (17));
			m_CleanupUDPTimer->async_wait(std::bind(&ClientContext::CleanupUDP, this, std::placeholders::_1));
		}
	}

	void ClientContext::CleanupUDP(const boost::system::error_code & ecode)
	{
		if(!ecode)
		{
			std::lock_guard<std::mutex> lock(m_ForwardsMutex);
			for (auto & s : m_ServerForwards ) s.second->ExpireStale();
			ScheduleCleanupUDP();
		}
	}

	template<typename Container, typename Visitor>
	void VisitTunnelsContainer (Container& c, Visitor v)
	{
		for (auto it = c.begin (); it != c.end ();)
		{
			if (!v (it->second.get ()))
			{
				it->second->Stop ();
				it = c.erase (it);
			}
			else
				it++;
		}
	}

	template<typename Visitor>
	void ClientContext::VisitTunnels (Visitor v)
	{
		VisitTunnelsContainer (m_ClientTunnels, v);
		VisitTunnelsContainer (m_ServerTunnels, v);
		// TODO: implement UDP forwards
	}
}
}


text:
// Copyright 2015-2017 Hans Dembinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_HISTOGRAM_DETAIL_CAT_HPP
#define BOOST_HISTOGRAM_DETAIL_CAT_HPP

#include <boost/config.hpp>
#include <sstream>

namespace boost {
namespace histogram {
namespace detail {
BOOST_ATTRIBUTE_UNUSED inline void cat_impl(std::ostringstream&) {}

template <typename T, typename... Ts>
void cat_impl(std::ostringstream& os, const T& t, const Ts&... ts) {
  os << t;
  cat_impl(os, ts...);
}

template <typename... Ts>
std::string cat(const Ts&... args) {
  std::ostringstream os;
  cat_impl(os, args...);
  return os.str();
}
} // namespace detail
} // namespace histogram
} // namespace boost

#endif

ext: hpp


text:
// Copyright (C) 2001 Vladimir Prus <ghost@cs.msu.su>
// Copyright (C) 2001 Jeremy Siek <jsiek@cs.indiana.edu>
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// NOTE: this final is generated by libs/graph/doc/transitive_closure.w

#ifndef BOOST_GRAPH_TRANSITIVE_CLOSURE_HPP
#define BOOST_GRAPH_TRANSITIVE_CLOSURE_HPP

#include <vector>
#include <algorithm> // for std::min and std::max
#include <functional>
#include <boost/config.hpp>
#include <boost/bind.hpp>
#include <boost/graph/strong_components.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/concept/assert.hpp>

namespace boost
{

  namespace detail
  {
    inline void
      union_successor_sets(const std::vector < std::size_t > &s1,
                           const std::vector < std::size_t > &s2,
                           std::vector < std::size_t > &s3)
    {
      BOOST_USING_STD_MIN();
      for (std::size_t k = 0; k < s1.size(); ++k)
        s3[k] = min BOOST_PREVENT_MACRO_SUBSTITUTION(s1[k], s2[k]);
    }
  }                             // namespace detail

  namespace detail
  {
    template < typename TheContainer, typename ST = std::size_t,
      typename VT = typename TheContainer::value_type >
      struct subscript_t:public std::unary_function < ST, VT >
    {
      typedef VT& result_type;

      subscript_t(TheContainer & c):container(&c)
      {
      }
      VT & operator() (const ST & i) const
      {
        return (*container)[i];
      }
    protected:
        TheContainer * container;
    };
    template < typename TheContainer >
      subscript_t < TheContainer > subscript(TheContainer & c) {
      return subscript_t < TheContainer > (c);
    }
  }                             // namespace detail

  template < typename Graph, typename GraphTC,
    typename G_to_TC_VertexMap,
    typename VertexIndexMap >
    void transitive_closure(const Graph & g, GraphTC & tc,
                            G_to_TC_VertexMap g_to_tc_map,
                            VertexIndexMap index_map)
  {
    if (num_vertices(g) == 0)
      return;
    typedef typename graph_traits < Graph >::vertex_descriptor vertex;
    typedef typename graph_traits < Graph >::vertex_iterator vertex_iterator;
    typedef typename property_traits < VertexIndexMap >::value_type size_type;
    typedef typename graph_traits <
      Graph >::adjacency_iterator adjacency_iterator;

    BOOST_CONCEPT_ASSERT(( VertexListGraphConcept < Graph > ));
    BOOST_CONCEPT_ASSERT(( AdjacencyGraphConcept < Graph > ));
    BOOST_CONCEPT_ASSERT(( VertexMutableGraphConcept < GraphTC > ));
    BOOST_CONCEPT_ASSERT(( EdgeMutableGraphConcept < GraphTC > ));
    BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept < VertexIndexMap,
      vertex > ));

    typedef size_type cg_vertex;
    std::vector < cg_vertex > component_number_vec(num_vertices(g));
    iterator_property_map < cg_vertex *, VertexIndexMap, cg_vertex, cg_vertex& >
      component_number(&component_number_vec[0], index_map);

    int num_scc = strong_components(g, component_number,
                                    vertex_index_map(index_map));

    std::vector < std::vector < vertex > >components;
    build_component_lists(g, num_scc, component_number, components);

    typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS> CG_t;
    CG_t CG(num_scc);
    for (cg_vertex s = 0; s < components.size(); ++s) {
      std::vector < cg_vertex > adj;
      for (size_type i = 0; i < components[s].size(); ++i) {
        vertex u = components[s][i];
        adjacency_iterator v, v_end;
        for (boost::tie(v, v_end) = adjacent_vertices(u, g); v != v_end; ++v) {
          cg_vertex t = component_number[*v];
          if (s != t)           // Avoid loops in the condensation graph
            adj.push_back(t);
        }
      }
      std::sort(adj.begin(), adj.end());
      typename std::vector<cg_vertex>::iterator di =
        std::unique(adj.begin(), adj.end());
      if (di != adj.end())
        adj.erase(di, adj.end());
      for (typename std::vector<cg_vertex>::const_iterator i = adj.begin();
           i != adj.end(); ++i) {
        add_edge(s, *i, CG);
      }
    }

    std::vector<cg_vertex> topo_order;
    std::vector<cg_vertex> topo_number(num_vertices(CG));
    topological_sort(CG, std::back_inserter(topo_order),
                     vertex_index_map(identity_property_map()));
    std::reverse(topo_order.begin(), topo_order.end());
    size_type n = 0;
    for (typename std::vector<cg_vertex>::iterator iter = topo_order.begin();
         iter != topo_order.end(); ++iter)
      topo_number[*iter] = n++;

    std::vector<std::vector<cg_vertex> > CG_vec(num_vertices(CG));
    for (size_type i = 0; i < num_vertices(CG); ++i) {
      typedef typename boost::graph_traits<CG_t>::adjacency_iterator cg_adj_iter;
      std::pair<cg_adj_iter, cg_adj_iter> pr = adjacent_vertices(i, CG);
      CG_vec[i].assign(pr.first, pr.second);
      std::sort(CG_vec[i].begin(), CG_vec[i].end(),
                boost::bind(std::less<cg_vertex>(),
                            boost::bind(detail::subscript(topo_number), _1),
                            boost::bind(detail::subscript(topo_number), _2)));
    }

    std::vector<std::vector<cg_vertex> > chains;
    {
      std::vector<cg_vertex> in_a_chain(CG_vec.size());
      for (typename std::vector<cg_vertex>::iterator i = topo_order.begin();
           i != topo_order.end(); ++i) {
        cg_vertex v = *i;
        if (!in_a_chain[v]) {
          chains.resize(chains.size() + 1);
          std::vector<cg_vertex>& chain = chains.back();
          for (;;) {
            chain.push_back(v);
            in_a_chain[v] = true;
            typename std::vector<cg_vertex>::const_iterator next
              = std::find_if(CG_vec[v].begin(), CG_vec[v].end(),
                             std::not1(detail::subscript(in_a_chain)));
            if (next != CG_vec[v].end())
              v = *next;
            else
              break;            // end of chain, dead-end

          }
        }
      }
    }
    std::vector<size_type> chain_number(CG_vec.size());
    std::vector<size_type> pos_in_chain(CG_vec.size());
    for (size_type i = 0; i < chains.size(); ++i)
      for (size_type j = 0; j < chains[i].size(); ++j) {
        cg_vertex v = chains[i][j];
        chain_number[v] = i;
        pos_in_chain[v] = j;
      }

    cg_vertex inf = (std::numeric_limits< cg_vertex >::max)();
    std::vector<std::vector<cg_vertex> > successors(CG_vec.size(),
                                                    std::vector<cg_vertex>
                                                    (chains.size(), inf));
    for (typename std::vector<cg_vertex>::reverse_iterator
           i = topo_order.rbegin(); i != topo_order.rend(); ++i) {
      cg_vertex u = *i;
      typename std::vector<cg_vertex>::const_iterator adj, adj_last;
      for (adj = CG_vec[u].begin(), adj_last = CG_vec[u].end();
           adj != adj_last; ++adj) {
        cg_vertex v = *adj;
        if (topo_number[v] < successors[u][chain_number[v]]) {
          // Succ(u) = Succ(u) U Succ(v)
          detail::union_successor_sets(successors[u], successors[v],
                                       successors[u]);
          // Succ(u) = Succ(u) U {v}
          successors[u][chain_number[v]] = topo_number[v];
        }
      }
    }

    for (size_type i = 0; i < CG_vec.size(); ++i)
      CG_vec[i].clear();
    for (size_type i = 0; i < CG_vec.size(); ++i)
      for (size_type j = 0; j < chains.size(); ++j) {
        size_type topo_num = successors[i][j];
        if (topo_num < inf) {
          cg_vertex v = topo_order[topo_num];
          for (size_type k = pos_in_chain[v]; k < chains[j].size(); ++k)
            CG_vec[i].push_back(chains[j][k]);
        }
      }

    // Add vertices to the transitive closure graph
    {
      vertex_iterator i, i_end;
      for (boost::tie(i, i_end) = vertices(g); i != i_end; ++i)
        g_to_tc_map[*i] = add_vertex(tc);
    }
    // Add edges between all the vertices in two adjacent SCCs
    typename std::vector<std::vector<cg_vertex> >::const_iterator si, si_end;
    for (si = CG_vec.begin(), si_end = CG_vec.end(); si != si_end; ++si) {
      cg_vertex s = si - CG_vec.begin();
      typename std::vector<cg_vertex>::const_iterator i, i_end;
      for (i = CG_vec[s].begin(), i_end = CG_vec[s].end(); i != i_end; ++i) {
        cg_vertex t = *i;
        for (size_type k = 0; k < components[s].size(); ++k)
          for (size_type l = 0; l < components[t].size(); ++l)
            add_edge(g_to_tc_map[components[s][k]],
                     g_to_tc_map[components[t][l]], tc);
      }
    }
    // Add edges connecting all vertices in a SCC
    for (size_type i = 0; i < components.size(); ++i)
      if (components[i].size() > 1)
        for (size_type k = 0; k < components[i].size(); ++k)
          for (size_type l = 0; l < components[i].size(); ++l) {
            vertex u = components[i][k], v = components[i][l];
            add_edge(g_to_tc_map[u], g_to_tc_map[v], tc);
          }

    // Find loopbacks in the original graph.
    // Need to add it to transitive closure.
    {
      vertex_iterator i, i_end;
      for (boost::tie(i, i_end) = vertices(g); i != i_end; ++i)
        {
          adjacency_iterator ab, ae;
          for (boost::tie(ab, ae) = adjacent_vertices(*i, g); ab != ae; ++ab)
            {
              if (*ab == *i)
                if (components[component_number[*i]].size() == 1)
                  add_edge(g_to_tc_map[*i], g_to_tc_map[*i], tc);
            }
        }
    }
  }

  template <typename Graph, typename GraphTC>
  void transitive_closure(const Graph & g, GraphTC & tc)
  {
    if (num_vertices(g) == 0)
      return;
    typedef typename property_map<Graph, vertex_index_t>::const_type
      VertexIndexMap;
    VertexIndexMap index_map = get(vertex_index, g);

    typedef typename graph_traits<GraphTC>::vertex_descriptor tc_vertex;
    std::vector<tc_vertex> to_tc_vec(num_vertices(g));
    iterator_property_map < tc_vertex *, VertexIndexMap, tc_vertex, tc_vertex&>
      g_to_tc_map(&to_tc_vec[0], index_map);

    transitive_closure(g, tc, g_to_tc_map, index_map);
  }

  namespace detail
  {
    template < typename Graph, typename GraphTC, typename G_to_TC_VertexMap,
      typename VertexIndexMap>
    void transitive_closure_dispatch
      (const Graph & g, GraphTC & tc,
       G_to_TC_VertexMap g_to_tc_map, VertexIndexMap index_map)
    {
      typedef typename graph_traits < GraphTC >::vertex_descriptor tc_vertex;
      typename std::vector < tc_vertex >::size_type
        n = is_default_param(g_to_tc_map) ? num_vertices(g) : 1;
      std::vector < tc_vertex > to_tc_vec(n);

      transitive_closure
        (g, tc,
         choose_param(g_to_tc_map, make_iterator_property_map
                      (to_tc_vec.begin(), index_map, to_tc_vec[0])),
         index_map);
    }
  }                             // namespace detail

  template < typename Graph, typename GraphTC,
    typename P, typename T, typename R >
    void transitive_closure(const Graph & g, GraphTC & tc,
                            const bgl_named_params < P, T, R > &params)
  {
    if (num_vertices(g) == 0)
      return;
    detail::transitive_closure_dispatch
      (g, tc, get_param(params, orig_to_copy_t()),
       choose_const_pmap(get_param(params, vertex_index), g, vertex_index) );
  }

  template < typename G > void warshall_transitive_closure(G & g)
  {
    typedef typename graph_traits < G >::vertex_iterator vertex_iterator;

    BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept < G > ));
    BOOST_CONCEPT_ASSERT(( EdgeMutableGraphConcept < G > ));

    // Matrix form:
    // for k
    //  for i
    //    if A[i,k]
    //      for j
    //        A[i,j] = A[i,j] | A[k,j]
    vertex_iterator ki, ke, ii, ie, ji, je;
    for (boost::tie(ki, ke) = vertices(g); ki != ke; ++ki)
      for (boost::tie(ii, ie) = vertices(g); ii != ie; ++ii)
        if (edge(*ii, *ki, g).second)
          for (boost::tie(ji, je) = vertices(g); ji != je; ++ji)
            if (!edge(*ii, *ji, g).second && edge(*ki, *ji, g).second) {
              add_edge(*ii, *ji, g);
            }
  }

  template < typename G > void warren_transitive_closure(G & g)
  {
    using namespace boost;
    typedef typename graph_traits < G >::vertex_iterator vertex_iterator;

    BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept < G > ));
    BOOST_CONCEPT_ASSERT(( EdgeMutableGraphConcept < G > ));

    // Make sure second loop will work
    if (num_vertices(g) == 0)
      return;

    // for i = 2 to n
    //    for k = 1 to i - 1
    //      if A[i,k]
    //        for j = 1 to n
    //          A[i,j] = A[i,j] | A[k,j]

    vertex_iterator ic, ie, jc, je, kc, ke;
    for (boost::tie(ic, ie) = vertices(g), ++ic; ic != ie; ++ic)
      for (boost::tie(kc, ke) = vertices(g); *kc != *ic; ++kc)
        if (edge(*ic, *kc, g).second)
          for (boost::tie(jc, je) = vertices(g); jc != je; ++jc)
            if (!edge(*ic, *jc, g).second && edge(*kc, *jc, g).second) {
              add_edge(*ic, *jc, g);
            }
    //  for i = 1 to n - 1
    //    for k = i + 1 to n
    //      if A[i,k]
    //        for j = 1 to n
    //          A[i,j] = A[i,j] | A[k,j]

    for (boost::tie(ic, ie) = vertices(g), --ie; ic != ie; ++ic)
      for (kc = ic, ke = ie, ++kc; kc != ke; ++kc)
        if (edge(*ic, *kc, g).second)
          for (boost::tie(jc, je) = vertices(g); jc != je; ++jc)
            if (!edge(*ic, *jc, g).second && edge(*kc, *jc, g).second) {
              add_edge(*ic, *jc, g);
            }
  }

}                               // namespace boost

#endif // BOOST_GRAPH_TRANSITIVE_CLOSURE_HPP

max_stars_repo_name: multi-os-engine/cinder-natj-binding


text:
/*
 Copyright (C) GridGain Systems. All Rights Reserved.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

/*  _________        _____ __________________        _____
 *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
 *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
 *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
 *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
 */

#ifndef GRIDTESTCOMMON_HPP_
#define GRIDTESTCOMMON_HPP_

#include <string>
#include <vector>
#include <map>

#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>

#include "gridgain/gridclientconfiguration.hpp"
#include "gridgain/gridclienttopologylistener.hpp"
#include "gridgain/gridclientnode.hpp"

using std::string;
using std::vector;

/** Cache name to use. */
const string CACHE_NAME = "partitioned";

/** Number of configured caches. */
const int CACHE_CNT = 5;

/** TCP port. */
const int TEST_TCP_PORT = 10080;

/** HTTP port. */
const int TEST_HTTP_PORT = 11080;

/** Host name. */
const string TEST_HOST = "127.0.0.1";

/** Default thread count for multithreaded tests. */
const int DLFT_THREADS_CNT = 20;

/** Client credentials. */
const string CREDS = "s3cret";

/**
 * Topology listener, that forms a node map according
 * to topology events.
 */
class GridTestTopologyListener : public GridClientTopologyListener {
public:
    /** Virtual destructor. */
    virtual ~GridTestTopologyListener() {}

    /**
     * Callback for new nodes joining the remote grid.
     *
     * @param node New remote node.
     */
    virtual void onNodeAdded(const GridClientNode& node) {
        boost::lock_guard<boost::mutex> g(nodesMux);

        nodes[node.getNodeId()] = node;
    }

    /**
     * Callback for nodes leaving the remote grid.
     *
     * @param node Left node.
     */
    virtual void onNodeRemoved(const GridClientNode& node) {
        boost::lock_guard<boost::mutex> g(nodesMux);

        nodes.erase(node.getNodeId());
    }

    /**
     * @return Number of nodes in map.
     */
    size_t getNodesCount() const {
        boost::lock_guard<boost::mutex> g(nodesMux);

        return nodes.size();
    }

private:
    /** Nodes map. */
    std::map<GridClientUuid, GridClientNode> nodes;

    /** Nodes map mutex. */
    mutable boost::mutex nodesMux;
};

string genRandomUniqueString(string prefix = "");

/**
 * Returns current system time in milliseconds.
 */
int64_t currentTimeMillis();

/**
 * Returns a random string, based on the prefix.
 *
 * @param prefix A prefix for random string.
 * @return Random string.
 */
string getRandomName(string prefix);

/**
 * Returns a client configuration for the test.
 */
GridClientConfiguration clientConfig();

/**
 * Tries to read the value of command line arg from provided
 * argc-argv pair. The value of an arg is expected to be
 * next to it's name. For exampe, if we run the program in
 * the following way:
 *
 * <pre>./program -param 1234</pre>
 *
 * "-param" will be the name of an argument, and "1234" will
 * be the value.
 *
 * @param argc The argc parameter in main().
 * @param argv The argv parameter in main().
 * @param name The name of the argument to read.
 * @param defaultValue The default value, if the argument (or value) was not found.
 */
template<class T>
T readArg(int argc, const char** argv, const string& name, const T& defaultValue) {
    for (int i = 1; i < argc - 1; i++) {
        if (name == argv[i]) {
            return boost::lexical_cast<T>(argv[i + 1]);
        }
    }

    return defaultValue;
}

/**********************************************************************
 * Stuff for multithreaded tests.                                     *
 **********************************************************************/

extern boost::mutex checkMux;

/**
 * Thread-safe expression check.
 *
 * This macro assumes the expression is boolean.
 *
 * @param P Predicate to check.
 */
#define SYNC_CHECK(E) {                            \
    bool v = E;                                    \
    boost::lock_guard<boost::mutex> g(checkMux);   \
    BOOST_CHECK(v);                                \
}

/**
 * Thread-safe equality check.
 *
 * @param L Left operand.
 * @param R Right operand.
 */
#define SYNC_CHECK_EQUAL(L, R) {                 \
    boost::lock_guard<boost::mutex> g(checkMux); \
    BOOST_CHECK_EQUAL(L, R);                     \
}

/**
 * Thread-safe exception check.
 *
 * @param E Expression to run.
 * @param T Expected exception type.
 */
#define SYNC_CHECK_THROW(E, T) {                 \
    boost::lock_guard<boost::mutex> g(checkMux); \
    BOOST_CHECK_THROW(E, T);                     \
}

/**
 * Runs the specified callable within multiple threads.
 *
 * @param f A callable to run (function, bind, function object or any class with operator() ).
 * @param nthreads Number of running threads.
 */
template<class F>
void multithreaded(F f, int nthreads = DLFT_THREADS_CNT) {
    vector<boost::thread> threads;
    vector<boost::unique_future<void> > futures;

    for (int i = 0; i < nthreads; i++) {
        boost::packaged_task<void> pt(f);
        futures.push_back(pt.get_future());

        threads.push_back(boost::thread(boost::move(pt)));
    }

    // wait for all threads to finish
    for (auto i = threads.begin(); i != threads.end(); i++)
        i->join();

    // gather all futures to possibly get an exception
    for (auto i = futures.begin(); i != futures.end(); i++)
        i->get();
}

#endif /* GRIDTESTCOMMON_HPP_ */

max_stars_repo_name: cybernetics/gridgain

max_issues_repo_name: cybernetics/gridgain

max_forks_repo_name: cybernetics/gridgain


text:
#include "Ssl.h"

#include <openssl/engine.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>

#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/remove_whitespace.hpp>
#include <jde/Assert.h>
#define var const auto

namespace Jde
{
	string Ssl::Encode( sv url )noexcept
	{
		ostringstream os;
		std::ostream hexcout{ os.rdbuf() };
		hexcout << std::hex << std::uppercase << std::setfill('0');
		var end = url.data()+url.size();
		for( auto p=url.data(); p<end; ++p )
		{
			char ch = *p;
			if( ch>=0 )//&& ch<128
			{
				char ch = (char)*p;
				if( isalnum(*p) || ch == '-' || ch == '_' || ch == '.' || ch == '~' )
					os << ch;
				else
				{
					os << '%';
					int x = ch;
					hexcout << std::setw(2) << x;
				}
			}
			else
			{
				//%E2%89%88
				os << '%';
				unsigned char value = ch;
				hexcout << std::setw(2) << static_cast<uint>(value);
			}
		}
		return os.str();
	}

	//TODO: very bad!  https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store
	bool Ssl::verify_certificate( bool preverified, boost::asio::ssl::verify_context& ctx )noexcept
	{
		char subject_name[256];
		X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
		X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
		//std::cout << "Verifying:  " << subject_name << std::endl;
		preverified = true;
		return preverified;
	}

	RSA* CreatePrivateRsa( string key )
	{
		BIO* keybio = BIO_new_mem_buf( (void*)key.c_str(), -1 ); THROW_IF( !keybio, "!keybio" );
		RSA* pRsa = nullptr;
		pRsa = PEM_read_bio_RSAPrivateKey( keybio, &pRsa, nullptr, nullptr );
		if( !pRsa )
		{
			char buffer[120];
			ERR_error_string( ERR_get_error(), buffer );
			THROW( buffer );
		}
		return pRsa;
	}

	bool RSASign( RSA* rsa, const unsigned char* Msg, size_t MsgLen, unsigned char** EncMsg,  size_t* MsgLenEnc )
	{
		EVP_MD_CTX* m_RSASignCtx = EVP_MD_CTX_create();
		EVP_PKEY* priKey  = EVP_PKEY_new(); //free?
		EVP_PKEY_assign_RSA(priKey, rsa);
		if( EVP_DigestSignInit(m_RSASignCtx,nullptr, EVP_sha1(), nullptr,priKey)<=0 )
			return false;
		if( EVP_DigestSignUpdate(m_RSASignCtx, Msg, MsgLen) <= 0 )
			return false;
		if( EVP_DigestSignFinal(m_RSASignCtx, nullptr, MsgLenEnc) <=0 )
			return false;

		*EncMsg = (unsigned char*)malloc(*MsgLenEnc);
		if (EVP_DigestSignFinal(m_RSASignCtx, *EncMsg, MsgLenEnc) <= 0)
			return false;

		EVP_MD_CTX_reset( m_RSASignCtx );
		return true;
	}
	//https://stackoverflow.com/questions/7053538/how-do-i-encode-a-string-to-base64-using-only-boost
	std::string Ssl::Encode64( const std::string &val )
	{
		using namespace boost::archive::iterators;
		using It = base64_from_binary<transform_width<std::string::const_iterator, 6, 8>>;
		auto tmp = std::string( It(std::begin(val)), It(std::end(val)) );
		return tmp.append( (3 - val.size() % 3) % 3, '=' );
	}

	string Ssl::RsaSign( sv value, sv key )
	{
		auto p = HMAC_CTX_new();
		HMAC_Init_ex( p, (void*)key.data(), (int)key.size(), EVP_sha1(), nullptr );
		HMAC_Update( p, (const unsigned char*)value.data(), value.size() );
		unsigned length = 2048;
		unsigned char buffer[2048];
		HMAC_Final( p, buffer, &length );
		HMAC_CTX_free( p );
		return Encode64( string(buffer, buffer+length) );
	}

	std::string Ssl::Decode64( const std::string& s )noexcept(false) //https://stackoverflow.com/questions/10521581/base64-encode-using-boost-throw-exception
	{
		namespace bai = boost::archive::iterators; typedef bai::transform_width< bai::binary_from_base64<bai::remove_whitespace<std::string::const_iterator> >, 8, 6 > IT;
		return std::string{ IT(s.begin()), IT(s.end()) };
	}

	auto RsaDeleter=[](RSA* p){ RSA_free(p); };
	auto PKeyDeleter=[](EVP_PKEY* p){ EVP_PKEY_free(p); };

	//https://stackoverflow.com/questions/28770426/rsa-public-key-conversion-with-just-modulus
	unique_ptr<EVP_PKEY,decltype(PKeyDeleter)> RsaPemFromModExp( const string& modulus, const string& exponent )noexcept(false)
	{
		BIGNUM* pMod = BN_bin2bn( (const unsigned char *)modulus.c_str(), (int)modulus.size(), nullptr ); THROW_IF( !pMod, "BN_bin2bn"sv );
		BIGNUM *pExp = BN_bin2bn( (const unsigned char *)exponent.c_str(), (int)exponent.size(), nullptr ); THROW_IF( !pMod, "BN_bin2bn({})"sv, exponent );
		unique_ptr<RSA,decltype(RsaDeleter)> pRsa{ RSA_new(), RsaDeleter };
		RSA_set0_key( pRsa.get(), pMod, pExp, nullptr );

		unique_ptr<EVP_PKEY,decltype(PKeyDeleter)> pKey{ EVP_PKEY_new(), PKeyDeleter };
		int rc = EVP_PKEY_set1_RSA(pKey.get(), pRsa.get()); ASSERT(rc == 1);
		return pKey;
	}

	void rsatest();
	void Ssl::Verify( const string& modulus, const string& exponent, const string& decrypted, const string& signature )noexcept(false)
	{
		rsatest();
    	auto pCtx = EVP_MD_CTX_create();
    	var pMd = EVP_get_digestbyname( "SHA256" ); THROW_IF( !pMd, "EVP_get_digestbyname({})", "SHA256" ); //"SHA256"
		EVP_VerifyInit_ex( pCtx, pMd, nullptr );
		EVP_VerifyUpdate( pCtx, decrypted.c_str(), decrypted.size() );
		var pKey = RsaPemFromModExp( modulus, exponent );
		std::string decodedSignature = Encode64( signature );
		var result = EVP_VerifyFinal( pCtx, (const unsigned char *)decodedSignature.c_str(), (int)decodedSignature.size(), pKey.get() );
		THROW_IFX( result!=1, CodeException("Ssl::Verify - failed", {result, std::generic_category()} ) );
	}

	void rsatest()
	{
		const EVP_MD *sha256 = EVP_get_digestbyname("sha256");

		if(!sha256){
		fprintf(stderr,"SHA256 not available\n");
		return;
		}

		printf("Now try signing with X.509 certificates and EVP\n");

		char ptext[16];
		memset(ptext,0,sizeof(ptext));
		strcpy(ptext,"Simson");

		unsigned char sig[1024]={0};
		uint32_t  siglen = sizeof(sig);

		BIO *bp = BIO_new_file( "../signing_key.pem", "r" );

		auto pCtx = EVP_MD_CTX_create();
		//EVP_MD_CTX md;
		EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bp,0,0,0);

		EVP_SignInit(pCtx,sha256);
		EVP_SignUpdate(pCtx,ptext,sizeof(ptext));
		EVP_SignFinal(pCtx,sig,&siglen,pkey);

		/* let's try to verify it */
		BIO* bp2 = BIO_new_file( "../signing_key.pub", "r" );
		X509 *x = 0;
		PEM_read_bio_X509( bp2,&x,0,0 );
		EVP_PKEY *pubkey = X509_get_pubkey(x);

		printf("pubkey=%p\n",pubkey);

		EVP_VerifyInit(pCtx,sha256);
		EVP_VerifyUpdate(pCtx,ptext,sizeof(ptext));
		int r = EVP_VerifyFinal(pCtx,sig,siglen,pubkey);
		printf("r=%d\n",r);

		printf("do it again...\n");
		EVP_VerifyInit(pCtx,sha256);
		EVP_VerifyUpdate(pCtx,ptext,sizeof(ptext));
		r = EVP_VerifyFinal(pCtx,sig,siglen,pubkey);
		printf("r=%d\n",r);

		printf("make a tiny change...\n");
		ptext[0]='f';
		EVP_VerifyInit(pCtx,sha256);
		EVP_VerifyUpdate(pCtx,ptext,sizeof(ptext));
		r = EVP_VerifyFinal(pCtx,sig,siglen,pubkey);
		printf("r=%d\n",r);
	}

	string Ssl::SendEmpty( sv host, sv target, sv authorization, http::verb verb )noexcept(false)
	{
		http::request<http::empty_body> req{ verb, string(target), 11 };
		SetRequest( req, host, "application/x-www-form-urlencoded"sv, authorization );
		return Send( req, host, target );
	}

}

ext: cpp

max_stars_repo_name: Jde-cpp/Ssl

max_issues_repo_name: Jde-cpp/Ssl

max_forks_repo_name: Jde-cpp/Ssl


text:
// Copyright (c) 2013-2021 niXman (github dotty nixman doggy pm dotty me)
// All rights reserved.
//
// This file is part of EASYNET(https://github.com/niXman/easynet) project.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
//   Redistributions in binary form must reproduce the above copyright notice, this
//   list of conditions and the following disclaimer in the documentation and/or
//   other materials provided with the distribution.
//
//   Neither the name of the {organization} nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef __easynet__typedefs_hpp
#define __easynet__typedefs_hpp

#include <cstdint>
#include <string>
#include <ostream>
#include <memory>

#include <boost/system/error_code.hpp>

/***************************************************************************/

namespace boost {
namespace asio {
class io_context;
} // ns asio
} // ns boost

/***************************************************************************/

namespace easynet {

using error_code = boost::system::error_code;
using impl_holder = std::shared_ptr<void>;

struct socket;
struct acceptor;
struct timer;

/***************************************************************************/

struct endpoint {
    std::string ip;
    std::uint16_t port;

    friend std::ostream& operator<< (std::ostream &os, const endpoint &ep) {
        return os << ep.ip << ":" << ep.port;
    }
};

/***************************************************************************/

} // ns easynet

#endif // __easynet__typedefs_hpp

max_stars_repo_name: niXman/easynet

max_issues_repo_name: niXman/easynet

max_forks_repo_name: niXman/easynet


text:
#include <boost/test/unit_test.hpp>
#include <boost/mp11.hpp>
#include <boost/mp11/mpl.hpp>

#include <QtTools/ToolsBase.hpp>
#include <viewed/sftree_string_traits.hpp>
#include <viewed/sftree_facade_qtbase.hpp>

using traits_list = boost::mp11::mp_list<viewed::sftree_string_traits, viewed::sftree_qstring_traits>;

BOOST_AUTO_TEST_SUITE(sftree_traits_tests)

BOOST_AUTO_TEST_CASE_TEMPLATE(get_name_tests, traits_type, traits_list)
{
	traits_type traits;

	BOOST_CHECK_EQUAL(traits.get_name("test/leaf"), "leaf");
	BOOST_CHECK_EQUAL(traits.get_name("/test/leaf/"), "");
}

BOOST_AUTO_TEST_CASE_TEMPLATE(parse_path_test, traits_type, traits_list)
{
	traits_type traits;
	using pathview_type = typename traits_type::pathview_type;

	pathview_type name, curname, context;
	std::uintptr_t type;

	curname = "//test//inner//leaf";

	std::tie(type, name, context) = traits.parse_path(curname, context);
	BOOST_CHECK_EQUAL(type, viewed::sftree_constants::NODE);
	BOOST_CHECK_EQUAL(name, "test");
	BOOST_CHECK_EQUAL(context, "//test//");

	std::tie(type, name, context) = traits.parse_path(curname, context);
	BOOST_CHECK_EQUAL(type, viewed::sftree_constants::NODE);
	BOOST_CHECK_EQUAL(name, "inner");
	BOOST_CHECK_EQUAL(context, "//test//inner//");

	std::tie(type, name, context) = traits.parse_path(curname, context);
	BOOST_CHECK_EQUAL(type, viewed::sftree_constants::LEAF);
	BOOST_CHECK_EQUAL(name, "leaf");
	BOOST_CHECK_EQUAL(context, "//test//inner//");
}

BOOST_AUTO_TEST_CASE_TEMPLATE(tricky_parse_path_test, traits_type, traits_list)
{
	traits_type traits;
	using pathview_type = typename traits_type::pathview_type;

	pathview_type name, curname, context;
	std::uintptr_t type;

	curname = "//test//inner//leaf///";

	std::tie(type, name, context) = traits.parse_path(curname, context);
	BOOST_CHECK_EQUAL(type, viewed::sftree_constants::NODE);
	BOOST_CHECK_EQUAL(name, "test");
	BOOST_CHECK_EQUAL(context, "//test//");

	std::tie(type, name, context) = traits.parse_path(curname, context);
	BOOST_CHECK_EQUAL(type, viewed::sftree_constants::NODE);
	BOOST_CHECK_EQUAL(name, "inner");
	BOOST_CHECK_EQUAL(context, "//test//inner//");

	std::tie(type, name, context) = traits.parse_path(curname, context);
	BOOST_CHECK_EQUAL(type, viewed::sftree_constants::NODE);
	BOOST_CHECK_EQUAL(name, "leaf");
	BOOST_CHECK_EQUAL(context, "//test//inner//leaf///");

	std::tie(type, name, context) = traits.parse_path(curname, context);
	BOOST_CHECK_EQUAL(type, viewed::sftree_constants::LEAF);
	BOOST_CHECK_EQUAL(name, "");
	BOOST_CHECK_EQUAL(context, "//test//inner//leaf///");
}

BOOST_AUTO_TEST_CASE_TEMPLATE(is_child_test, traits_type, traits_list)
{
	traits_type traits;
	using pathview_type = typename traits_type::pathview_type;

	pathview_type name, curname, context;
	std::uintptr_t type;

	curname = "//test/inner//leaf";

	std::tie(type, name, context) = traits.parse_path(curname, context);
	BOOST_REQUIRE_EQUAL(type, viewed::sftree_constants::NODE);
	BOOST_REQUIRE_EQUAL(name, "test");
	BOOST_REQUIRE_EQUAL(context, "//test/");

	BOOST_CHECK(traits.is_child(curname, context));
	BOOST_CHECK(traits.is_child("//test/another", context));
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: dmlys/QtTools

max_issues_repo_name: dmlys/QtTools

max_forks_repo_name: dmlys/QtTools


text:
#include "moja/flint/errorscreenwriter.h"

#include "moja/flint/ivariable.h"
#include "moja/flint/spatiallocationinfo.h"

#include <moja/logging.h>
#include <moja/notificationcenter.h>
#include <moja/signals.h>

#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>

namespace moja {
namespace flint {

// --------------------------------------------------------------------------------------------

void ErrorScreenWriter::subscribe(NotificationCenter& notificationCenter) {
   notificationCenter.subscribe(signals::LocalDomainInit, &ErrorScreenWriter::onLocalDomainInit, *this);
   notificationCenter.subscribe(signals::Error, &ErrorScreenWriter::onError, *this);
}

// --------------------------------------------------------------------------------------------

void ErrorScreenWriter::onLocalDomainInit() {
   _spatiallocationinfo = std::static_pointer_cast<flint::SpatialLocationInfo>(
       _landUnitData->getVariable("spatialLocationInfo")->value().extract<std::shared_ptr<flint::IFlintData>>());
}

// --------------------------------------------------------------------------------------------

void ErrorScreenWriter::onError(std::string msg) {
   if (_spatiallocationinfo != nullptr) {
      boost::replace_all(msg, "\n", " ");
      auto errorMsg =
          (boost::format("Libarry %5%, Module %6% - Error at location [tileIdx %1%, blockIdx %2%, cellIdx %3%], random "
                         "seed [global %8%, block %9%, cell %10%], code %4% : Message - %7%") %
           _spatiallocationinfo->_tileIdx % _spatiallocationinfo->_blockIdx % _spatiallocationinfo->_cellIdx %
           _spatiallocationinfo->_errorCode % _spatiallocationinfo->_library % _spatiallocationinfo->_module % msg %
           _spatiallocationinfo->_randomSeedGlobal % _spatiallocationinfo->_randomSeedBlock %
           _spatiallocationinfo->_randomSeedCell)
              .str();
      MOJA_LOG_ERROR << errorMsg;
   } else {
      boost::replace_all(msg, "\n", " ");
      auto errorMsg = (boost::format("Error: %1%") % msg).str();
      MOJA_LOG_ERROR << errorMsg;
   }
}

}  // namespace flint
}  // namespace moja

max_stars_repo_name: moja-global/flint

max_issues_repo_name: moja-global/flint

max_forks_repo_name: moja-global/flint


text:
#include <boost/test/unit_test.hpp>
#include "switch_repeat_expr.h"
#include <iostream>
#include <fstream>
#include <vector>

BOOST_AUTO_TEST_CASE(test_switch_repeat_expr) {
    std::ifstream ifs("src/switch_tlv.bin", std::ifstream::binary);
    kaitai::kstream ks(&ifs);
    switch_repeat_expr_t* r = new switch_repeat_expr_t(&ks);

    BOOST_CHECK_EQUAL(r->code(), 17);
    BOOST_CHECK_EQUAL(r->size(), 9);
    BOOST_CHECK_EQUAL(static_cast<switch_repeat_expr_t::one_t*>(r->body()->at(0).get())->first(), std::string("\x53\x74\x75\x66\x66\x00\x4D\x65\x00", 9));

    delete r;
}


text:
#include <b0/utils/thread_name.h>

#ifdef _WIN32

#ifndef __MINGW64__

#include <windows.h>

const DWORD MS_VC_EXCEPTION=0x406D1388;

#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
    DWORD dwType;     // Must be 0x1000.
    LPCSTR szName;    // Pointer to name (in user addr space).
    DWORD dwThreadID; // Thread ID (-1=caller thread).
    DWORD dwFlags;    // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)

void dbg_set_thread_name(uint32_t dwThreadID, const char* threadName)
{
    // DWORD dwThreadID = ::GetThreadId( static_cast<HANDLE>( t.native_handle() ) );

    THREADNAME_INFO info;
    info.dwType = 0x1000;
    info.szName = threadName;
    info.dwThreadID = dwThreadID;
    info.dwFlags = 0;

    __try
    {
        RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
    }
}

void dbg_set_thread_name(const char *threadName)
{
    dbg_set_thread_name(GetCurrentThreadId(), threadName);
}

#if 0
void set_thread_name(std::thread *thread, const char *threadName)
{
    DWORD threadId = ::GetThreadId(static_cast<HANDLE>(thread->native_handle()));
    set_thread_name(threadId, threadName);
}
#endif

#endif // !__MINGW64__

#include <string>
#include <map>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>

static std::map<std::string, std::string> thread_name;

void set_thread_name(const char *threadName)
{
#ifndef __MINGW64__
    dbg_set_thread_name(threadName);
#endif
    std::string this_thread_id = boost::lexical_cast<std::string>(boost::this_thread::get_id());
    thread_name[this_thread_id] = std::string(threadName);
}

std::string get_thread_name()
{
    std::string this_thread_id = boost::lexical_cast<std::string>(boost::this_thread::get_id());
    auto i = thread_name.find(this_thread_id);
    return i == thread_name.end() ? "" : i->second;
}

#else // _WIN32

#include <pthread.h>

#if 0
void set_thread_name(std::thread *thread, const char *threadName)
{
    auto handle = thread->native_handle();
    pthread_setname_np(handle, threadName);
}
#endif

void set_thread_name(const char *threadName)
{
#if defined(HAVE_PTHREAD_SETNAME_3)
    pthread_setname_np(pthread_self(), threadName, (void*)0);
#elif defined(HAVE_PTHREAD_SETNAME_2)
    pthread_setname_np(pthread_self(), threadName);
#elif defined(HAVE_PTHREAD_SETNAME_1)
    pthread_setname_np(threadName);
#else
#error "pthread_setname_np() not available"
#endif
}

std::string get_thread_name()
{
    char buf[64];
    pthread_getname_np(pthread_self(), &buf[0], 64);
    return std::string(&buf[0]);
}

#endif // _WIN32

max_stars_repo_name: YueErro/ModernRobotics

max_issues_repo_name: YueErro/ModernRobotics

max_forks_repo_name: YueErro/ModernRobotics


text:
// Boost.Units - A C++ library for zero-overhead dimensional analysis and
// unit/quantity manipulation and conversion
//
// Copyright (C) 2003-2008 Matthias Christian Schabel
// Copyright (C) 2007-2008 Steven Watanabe
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_UNITS_CONVERSION_HPP
#define BOOST_UNITS_CONVERSION_HPP

/// \file
/// \brief Template for defining conversions between quantities.

#include <boost/units/detail/conversion_impl.hpp>

namespace boost {

namespace units {

template<class From, class To>
struct conversion_helper;

#ifdef BOOST_UNITS_DOXYGEN

/// Template for defining conversions between
/// quantities.  This template should be specialized
/// for every quantity that allows conversions.
/// For example, if you have a two units
/// called pair and dozen you would write
/// @code
/// namespace boost {
/// namespace units {
/// template<class T0, class T1>
/// struct conversion_helper<quantity<dozen, T0>, quantity<pair, T1> >
/// {
///     static quantity<pair, T1> convert(const quantity<dozen, T0>& source)
///     {
///         return(quantity<pair, T1>::from_value(6 * source.value()));
///     }
/// };
/// }
/// }
/// @endcode
///
/// In most cases, the predefined specializations for @c unit
/// and @c absolute should be sufficient, so users should rarely
/// need to use this.
template<class From, class To>
struct conversion_helper
{
    static BOOST_CONSTEXPR To convert(const From&);
};

#endif

/// Defines the conversion factor from a base unit to any unit
/// or to another base unit with the correct dimensions.  Uses
/// of this macro must appear at global scope.
/// If the destination unit is a base unit or a unit that contains
/// only one base unit which is raised to the first power (e.g. feet->meters)
/// the reverse (meters->feet in this example) need not be defined explicitly.
#define BOOST_UNITS_DEFINE_CONVERSION_FACTOR(Source, Destination, type_, value_)    \
    namespace boost {                                                       \
    namespace units {                                                       \
    template<>                                                              \
    struct select_base_unit_converter<                                      \
        unscale<Source>::type,                                              \
        unscale<reduce_unit<Destination::unit_type>::type>::type            \
    >                                                                       \
    {                                                                       \
        typedef Source source_type;                                         \
        typedef reduce_unit<Destination::unit_type>::type destination_type; \
    };                                                                      \
    template<>                                                              \
    struct base_unit_converter<Source, reduce_unit<Destination::unit_type>::type>   \
    {                                                                       \
        BOOST_STATIC_CONSTEXPR bool is_defined = true;                      \
        typedef type_ type;                                                 \
        static BOOST_CONSTEXPR type value() { return(value_); }             \
    };                                                                      \
    }                                                                       \
    }                                                                       \
    void boost_units_require_semicolon()

/// Defines the conversion factor from a base unit to any other base
/// unit with the same dimensions.  Params should be a Boost.Preprocessor
/// Seq of template parameters, such as (class T1)(class T2)
/// All uses of must appear at global scope. The reverse conversion will
/// be defined automatically.  This macro is a little dangerous, because,
/// unlike the non-template form, it will silently fail if either base
/// unit is scaled.  This is probably not an issue if both the source
/// and destination types depend on the template parameters, but be aware
/// that a generic conversion to kilograms is not going to work.
#define BOOST_UNITS_DEFINE_CONVERSION_FACTOR_TEMPLATE(Params, Source, Destination, type_, value_)   \
    namespace boost {                                                       \
    namespace units {                                                       \
    template<BOOST_PP_SEQ_ENUM(Params)>                                     \
    struct base_unit_converter<                                             \
        Source,                                                             \
        BOOST_UNITS_MAKE_HETEROGENEOUS_UNIT(Destination, typename Source::dimension_type)\
    >                                                                       \
    {                                                                       \
        BOOST_STATIC_CONSTEXPR bool is_defined = true;                      \
        typedef type_ type;                                                 \
        static BOOST_CONSTEXPR type value() { return(value_); }             \
    };                                                                      \
    }                                                                       \
    }                                                                       \
    void boost_units_require_semicolon()

/// Specifies the default conversion to be applied when
/// no direct conversion is available.
/// Source is a base unit.  Dest is any unit with the
/// same dimensions.
#define BOOST_UNITS_DEFAULT_CONVERSION(Source, Dest)                \
    namespace boost {                                               \
    namespace units {                                               \
    template<>                                                      \
    struct unscaled_get_default_conversion<unscale<Source>::type>   \
    {                                                               \
        BOOST_STATIC_CONSTEXPR bool is_defined = true;              \
        typedef Dest::unit_type type;                               \
    };                                                              \
    }                                                               \
    }                                                               \
    void boost_units_require_semicolon()

/// Specifies the default conversion to be applied when
/// no direct conversion is available.
/// Params is a PP Sequence of template arguments.
/// Source is a base unit.  Dest is any unit with the
/// same dimensions.  The source must not be a scaled
/// base unit.
#define BOOST_UNITS_DEFAULT_CONVERSION_TEMPLATE(Params, Source, Dest)   \
    namespace boost {                                                   \
    namespace units {                                                   \
    template<BOOST_PP_SEQ_ENUM(Params)>                                 \
    struct unscaled_get_default_conversion<Source>                      \
    {                                                                   \
        BOOST_STATIC_CONSTEXPR bool is_defined = true;                  \
        typedef typename Dest::unit_type type;                          \
    };                                                                  \
    }                                                                   \
    }                                                                   \
    void boost_units_require_semicolon()

/// INTERNAL ONLY
/// Users should not create their units in namespace boost::units.
/// If we want to make this public it needs to allow better control over
/// the namespaces. --SJW.
/// template that defines a base_unit and conversion to another dimensionally-consistent unit
#define BOOST_UNITS_DEFINE_BASE_UNIT_WITH_CONVERSIONS(namespace_, name_, name_string_, symbol_string_, factor, unit, id)\
namespace boost {                                                           \
namespace units {                                                           \
namespace namespace_ {                                                      \
struct name_ ## _base_unit                                                  \
  : base_unit<name_ ## _base_unit, unit::dimension_type, id> {              \
    static BOOST_CONSTEXPR const char* name() { return(name_string_); }     \
    static BOOST_CONSTEXPR const char* symbol() { return(symbol_string_); } \
};                                                                          \
}                                                                           \
}                                                                           \
}                                                                           \
BOOST_UNITS_DEFINE_CONVERSION_FACTOR(namespace_::name_ ## _base_unit, unit, double, factor); \
BOOST_UNITS_DEFAULT_CONVERSION(namespace_::name_ ## _base_unit, unit)

/// Find the conversion factor between two units.
template<class FromUnit,class ToUnit>
inline
BOOST_CONSTEXPR
typename one_to_double_type<
    typename detail::conversion_factor_helper<FromUnit, ToUnit>::type
>::type
conversion_factor(const FromUnit&,const ToUnit&)
{
    return(one_to_double(detail::conversion_factor_helper<FromUnit, ToUnit>::value()));
}

} // namespace units

} // namespace boost

#endif // BOOST_UNITS_CONVERSION_HPP


text:
/*
Copyright (c) 2019 - 2022 Advanced Micro Devices, Inc. All rights reserved.

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 <iostream>
#include <utility>
#include <algorithm>
#include <memory.h>
#include <stdint.h>
#include "mxnet_meta_data_reader.h"
#include <boost/filesystem.hpp>

namespace filesys = boost::filesystem;
using namespace std;

void MXNetMetaDataReader::init(const MetaDataConfig &cfg)
{
    _path = cfg.path();
    _output = new LabelBatch();
    _src_dir = nullptr;
    _entity = nullptr;
}

bool MXNetMetaDataReader::exists(const std::string& _image_name)
{
    return _map_content.find(_image_name) != _map_content.end();
}

void MXNetMetaDataReader::add(std::string image_name, int label)
{
    pMetaData info = std::make_shared<Label>(label);
    if(exists(image_name))
    {
        WRN("Entity with the same name exists")
        return;
    }
    _map_content.insert(std::pair<std::string, std::shared_ptr<Label>>(image_name, info));
}

void MXNetMetaDataReader::lookup(const std::vector<std::string> &_image_names)
{
    if(_image_names.empty())
    {
        WRN("No image names passed")
        return;
    }
    if(_image_names.size() != (unsigned)_output->size())
        _output->resize(_image_names.size());

    for(unsigned i = 0; i < _image_names.size(); i++)
    {
        auto _image_name = _image_names[i];
        auto it = _map_content.find(_image_name);
        if(_map_content.end() == it)
            THROW("MXNetMetaDataReader ERROR: Given name not present in the map"+ _image_name )
        _output->get_label_batch()[i] = it->second->get_label();
    }
}

void MXNetMetaDataReader::print_map_contents()
{
    std::cerr << "\nMap contents: \n";
    for (auto& elem : _map_content) {
        std::cerr << "Name :\t " << elem.first << "\t ID:  " << elem.second->get_label() << std::endl;
    }
}

void MXNetMetaDataReader::read_all(const std::string &_path)
{
    std::string _rec_file, _idx_file;
    if ((_src_dir = opendir (_path.c_str())) == nullptr)
        THROW("MXNetMetaDataReader ERROR: Failed opening the directory at " + _path);

    while((_entity = readdir (_src_dir)) != nullptr)
    {
        std::string file_name = _path + "/" + _entity->d_name;
        filesys::path pathObj(file_name);
        if(filesys::exists(pathObj) && filesys::is_regular_file(pathObj))
        {
            auto file_extension_idx = file_name.find_last_of(".");
            if (file_extension_idx  != std::string::npos)
            {
                std::string file_extension = file_name.substr(file_extension_idx+1);
                if (file_extension == "rec")
                    _rec_file = file_name;
                else if(file_extension == "idx")
                    _idx_file = file_name;
                else
                    continue;
            }
        }
    }
    closedir(_src_dir);
    uint rec_size;
    _file_contents.open(_rec_file);
    if (!_file_contents)
        THROW("MXNetMetaDataReader ERROR: Failed opening the file " + _rec_file);
    _file_contents.seekg(0, ifstream::end);
    rec_size = _file_contents.tellg();
    _file_contents.seekg(0, ifstream::beg);

    ifstream index_file(_idx_file);
    if(!index_file)
        THROW("MXNetMetaDataReader ERROR: Could not open RecordIO index file. Provided path: " + _idx_file);

    std::vector<size_t> _index_list;
    size_t _index, _offset;
    while (index_file >> _index >> _offset)
        _index_list.push_back(_offset);
    if(_index_list.empty())
        THROW("MXNetMetaDataReader ERROR: RecordIO index file doesn't contain any indices. Provided path: " + _idx_file);
    _index_list.push_back(rec_size);
    std::sort(_index_list.begin(), _index_list.end());
    for (size_t i = 0; i < _index_list.size() - 1; ++i)
        _indices.emplace_back(_index_list[i], _index_list[i + 1] - _index_list[i]);
    read_images();
}

void MXNetMetaDataReader::release(std::string _image_name)
{
    if(!exists(_image_name))
    {
        WRN("ERROR: Given not present in the map" + _image_name);
        return;
    }
    _map_content.erase(_image_name);
}

void MXNetMetaDataReader::release() {
    _map_content.clear();
}

void MXNetMetaDataReader::read_images()
{
    for(int current_index = 0; current_index < (int)_indices.size(); current_index++ )
    {
        uint32_t _magic, _length_flag;
        int64_t _seek_pos, _data_size_to_read;
        std::tie(_seek_pos, _data_size_to_read) = _indices[current_index];
        _file_contents.seekg(_seek_pos, ifstream::beg);
        uint8_t* _data = new uint8_t[_data_size_to_read];
        uint8_t* _data_ptr = _data;
        auto ret = _file_contents.read((char *)_data_ptr, _data_size_to_read).gcount();
        if(ret == -1 || ret != _data_size_to_read)
            THROW("MXNetMetaDataReader ERROR:  Unable to read the data from the file ");
        _magic = *((uint32_t *) _data_ptr);
        _data_ptr += sizeof(_magic);
        if(_magic != _kMagic)
            THROW("MXNetMetaDataReader ERROR: Invalid RecordIO: wrong magic number");
        _length_flag = *((uint32_t *) _data_ptr);
        _data_ptr += sizeof(_length_flag);
        _hdr = *((ImageRecordIOHeader *) _data_ptr);

        if (_hdr.flag == 0)
        {
            add((to_string(_hdr.image_id[0])), _hdr.label);
        }
        else
        {
            WRN("\nMultiple record reading has not supported");
            continue;
        }
        delete[] _data;
    }
}

MXNetMetaDataReader::MXNetMetaDataReader()
{
}

max_stars_repo_name: acxz/MIVisionX

max_issues_repo_name: acxz/MIVisionX

max_forks_repo_name: acxz/MIVisionX


text:
/*******************************************************************************
Copyright (c) 2011, Dr. D. Studios
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
Neither the name of the Dr. D. Studios nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/

/**
 * This differs from the API in that the Color3-related functions now return
 * Color3 objects rather than Vec3s. This is so that equality works as expected.
 * Note they will still accept any Vec3.
 */

#ifndef _PIMATH_COLORALGO__H_
#define _PIMATH_COLORALGO__H_

#include <boost/python.hpp>
#include <ImathColorAlgo.h>
#include <ImathColor.h>
#include "util.h"

namespace pimath
{
	namespace bp = boost::python;

	struct ColorAlgoBindUnteplated
	{
		ColorAlgoBindUnteplated()
		{
			Imath::Color4<double> (*hsv2rgb_d4)(
					const Imath::Color4<double> &) = &Imath::hsv2rgb_d;
			Imath::Color4<double> (*rgb2hsv_d4)(
					const Imath::Color4<double> &) = &Imath::rgb2hsv_d;

			bp::def("hsv2rgb_d", hsv2rgb_d3);
			bp::def("hsv2rgb_d", hsv2rgb_d4);
			bp::def("rgb2hsv_d", rgb2hsv_d3);
			bp::def("rgb2hsv_d", rgb2hsv_d4);
		}

		static Imath::Color3<double> hsv2rgb_d3(
				const Imath::Vec3<double> & hsv)
		{
			return Imath::Color3<double>( Imath::hsv2rgb_d( hsv ));
		}

		static Imath::Color3<double> rgb2hsv_d3(
				const Imath::Vec3<double> & rgb)
		{
			return Imath::Color3<double>( Imath::rgb2hsv_d( rgb ));
		}
	};

	template<typename T>
	struct ColorAlgoBind
	{
		typedef Imath::Vec3<T> 		vec3_type;
		typedef Imath::Color3<T>	col3_type;
		typedef Imath::Color4<T>	col4_type;
		ColorAlgoBind()
		{
			col4_type (*hsv2rgb4)(
					const col4_type &) = &Imath::hsv2rgb;
			col4_type (*rgb2hsv4)(
					const col4_type &) = &Imath::rgb2hsv;
			Imath::PackedColor (*rgb2packed3)(
					const vec3_type &) = &Imath::rgb2packed;
			Imath::PackedColor (*rgb2packed4)(
					const col4_type &) = &Imath::rgb2packed;

			bp::def("hsv2rgb", hsv2rgb3);
			bp::def("hsv2rgb", hsv2rgb4);
			bp::def("rgb2hsv", rgb2hsv3);
			bp::def("rgb2hsv", rgb2hsv4);
			bp::def("rgb2packed", rgb2packed3);
			bp::def("rgb2packed", rgb2packed4);
			bp::def("packed2rgb", packed2rgb );
			bp::def("packed2rgba", packed2rgba );
		}

		static col3_type hsv2rgb3( const vec3_type & vec )
		{
			return col3_type( Imath::hsv2rgb( vec ) );
		}

		static col3_type rgb2hsv3( const vec3_type & vec )
		{
			return col3_type( Imath::rgb2hsv( vec ) );
		}

		static bp::object
		packed2rgb( Imath::PackedColor packed )
		{
			col3_type rv;
			Imath::packed2rgb<T>( packed, rv );
			return  bp::object( rv );
		}

		static bp::object
		packed2rgba( Imath::PackedColor packed )
		{
			col4_type rv;
			Imath::packed2rgb<T>( packed, rv);
			return  bp::object( rv );
		}
	};
}

#endif

max_stars_repo_name: madpianist/pimath

max_issues_repo_name: madpianist/pimath

max_forks_repo_name: madpianist/pimath


text:
#include <type_traits>
#include <cassert>

#include <boost/mpl/apply.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/lambda.hpp>

namespace mpl = boost::mpl;
using namespace mpl::placeholders;

max_stars_repo_name: HelloCodeMing/TMP

max_issues_repo_name: HelloCodeMing/TMP

max_forks_repo_name: HelloCodeMing/TMP