/*
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "Global.h"
#include "LOGIC_ELSE.h"

void LOGIC_ELSE::Parse_and(char* pBuf) {
	int index = 0, i = 0;
	char t

	index += ParseSpace(temp, pBuf+index);
	memcpy(m_LogicCmd, temp, strlen(temp) + 1);

	if(!strcmp(temp, "CHECK_LV")) {
		m_LogicElse = LOGIC_CHECK_LEVEL;

		index += ParseSpace(temp, pBuf+index); m_LogicElseInt[i++] = atoi(temp); // minimum level
		index += ParseSpace(temp, pBuf+index); m_LogicElseInt[i++] = atoi(temp); // maximum level

	} else if(!strcmp(temp, "CHECK_EXIST_EVENT")) {
		m_LogicElse = LOGIC_EXIST_COM_EVENT;

		index += ParseSpace(temp, pBuf+index); m_LogicElseInt[i++] = atoi(temp); // event number
		index += ParseSpace(temp, pBuf+index); m_LogicElseInt[i++] = atoi(temp); // state (is the event at this state?)

	} else if (!strcmp(temp, "HOWMUCH_ITEM")) {
		m_LogicElse = LOGIC_HOWMUCH_ITEM;

		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); // item number
		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); // minimum amount
		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); // maximum amount

	} else if (!strcmp(temp, "CHECK_PROMOTION_ELIGIBLE")) {
		m_LogicElse = LOGIC_CHECK_PROMOTION_ELIGIBLE;

		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); // typically -1

	} else if (!strcmp(temp, "CHECK_CLASS")) {
		m_LogicElse = LOGIC_CHECK_CLASS;

		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); // class 1

		int old_index = index;
		index += ParseSpace(temp, pBuf + index);

		if (index != old_index) {
			m_LogicElseInt[i++] = atoi(temp); // class 2
			index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); // class 3
			index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); // class 4
			index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); // class 5
			index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); // class 6
		}
		else {
			m_LogicElseInt[i++] = -1;
			m_LogicElseInt[i++] = -1; m_LogicElseInt[i++] = -1;
			m_LogicElseInt[i++] = -1; m_LogicElseInt[i++] = -1;
		}

	} else if(!strcmp(temp, "CHECK_NOCLASS")) {
		m_LogicElse = LOGIC_CHECK_NOCLASS;

		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); // class 1

		int old_index = index;
		index += ParseSpace(temp, pBuf + index);

		if (index != old_index) {
			m_LogicElseInt[i++] = atoi(temp); // class 2
			index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); // class 3
			index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); // class 4
			index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); // class 5
			index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); // class 6
		}
		else {
			m_LogicElseInt[i++] = -1;
			m_LogicElseInt[i++] = -1; m_LogicElseInt[i++] = -1;
			m_LogicElseInt[i++] = -1; m_LogicElseInt[i++] = -1;
		}

	} else if (!strcmp(temp, "CHECK_NOAH")) {
		m_LogicElse = LOGIC_CHECK_NOAH;

		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp);
		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp);

	} else if (!strcmp(temp, "CHECK_EXIST_ITEM")) {
		m_LogicElse = LOGIC_CHECK_EXIST_ITEM;

		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp);
		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp);

	} else if (!strcmp(temp, "CHECK_DICE")) {
		m_LogicElse = LOGIC_CHECK_DICE;

		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp);

	} else if (!strcmp(temp, "CHECK_EMPTY_SLOT")) {
		m_LogicElse = LOGIC_CHECK_EMPTY_SLOT;

		// NOTE: number of empty slots to check for
		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp);

	} else if (!strcmp(temp, "CHECK_EXIST_EVENT")){
		m_LogicElse = LOGIC_CHECK_EXITS_EVENT;

		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); //event id
		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); //state
	} else if (!strcmp(temp, "CHECK_NOEXIST_EVENT")){
		m_LogicElse = LOGIC_CHECK_NOEXITS_EVENT;

		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); //event id
		index += ParseSpace(temp, pBuf + index); m_LogicElseInt[i++] = atoi(temp); //state
	} else {
		m_LogicElse = LOGIC_UNKNOWN;
		printf("Unknown logic command: %s\n", temp);
	}

	m_bAnd = true;
}


bool operator==(const CurveSpec& lhs, const CurveSpec& rhs)

/*
 All rights reserved.

 This file is part of ORE, a free-software/open-source library
 for transparent pricing and risk analysis - http://opensourcerisk.org

*/

#include <ored/marketdata/curvespec.hpp>
#include <ored/utilities/to_string.hpp>

namespace ore {
namespace data {

string CurveSpec::baseName() const { return ore::data::to_string(baseType()); }

bool operator<(const CurveSpec& lhs, const CurveSpec& rhs) {
    if (lhs == rhs) {
        /* If CurveSpecs are equal (i.e. have same name), return false. */
        return false;
    } else if (lhs.baseType() != rhs.baseType()) {
        /* If types are not the same, use the enum value for ordering along type.
         * The enum order in the header file is deliberate, it ensures that FX comes before FXVol
         * this property is used in data::order() (see curveloader.hpp)
         */
        return lhs.baseType() < rhs.baseType();
    } else {
        /* If types are the same and CurveSpecs are different, use default < for string */
        return lhs.name() < rhs.name();
    }
}

{
    /* We consider two CurveSpecs equal if they have the same name. */
    return lhs.name() == rhs.name();
}

bool operator<(const boost::shared_ptr<CurveSpec>& lhs, const boost::shared_ptr<CurveSpec>& rhs) { return *lhs < *rhs; }

bool operator==(const boost::shared_ptr<CurveSpec>& lhs, const boost::shared_ptr<CurveSpec>& rhs) {
    return *lhs == *rhs;
}

std::ostream& operator<<(std::ostream& os, const CurveSpec& spec) { return os << spec.name(); }

std::ostream& operator<<(std::ostream& os, const CurveSpec::CurveType& t) {
    switch (t) {
    case CurveSpec::CurveType::Yield:
        return os << "Yield";
    case CurveSpec::CurveType::CapFloorVolatility:
        return os << "CapFloorVolatility";
    case CurveSpec::CurveType::SwaptionVolatility:
        return os << "SwaptionVolatility";
    case CurveSpec::CurveType::YieldVolatility:
        return os << "YieldVolatility";
    case CurveSpec::CurveType::FX:
        return os << "FX";
    case CurveSpec::CurveType::FXVolatility:
        return os << "FXVolatility";
    case CurveSpec::CurveType::Security:
        return os << "Security";
    case CurveSpec::CurveType::Default:
        return os << "Default";
    case CurveSpec::CurveType::CDSVolatility:
        return os << "CDSVolatility";
    case CurveSpec::CurveType::Inflation:
        return os << "Inflation";
    case CurveSpec::CurveType::InflationCapFloorVolatility:
        return os << "InflationCapFloorVolatility";
    case CurveSpec::CurveType::Equity:
        return os << "Equity";
    case CurveSpec::CurveType::EquityVolatility:
        return os << "EquityVolatility";
    case CurveSpec::CurveType::BaseCorrelation:
        return os << "BaseCorrelation";
    case CurveSpec::CurveType::Commodity:
        return os << "Commodity";
    case CurveSpec::CurveType::CommodityVolatility:
        return os << "CommodityVolatility";
    case CurveSpec::CurveType::Correlation:
        return os << "Correlation";
    default:
        return os << "N/A";
    }
}
} // namespace data
} // namespace ore


{ return ore::data::to_string(baseType()); }

/*
 All rights reserved.

 This file is part of ORE, a free-software/open-source library
 for transparent pricing and risk analysis - http://opensourcerisk.org

*/

#include <ored/marketdata/curvespec.hpp>
#include <ored/utilities/to_string.hpp>

namespace ore {
namespace data {

string CurveSpec::baseName() const

bool operator<(const CurveSpec& lhs, const CurveSpec& rhs) {
    if (lhs == rhs) {
        /* If CurveSpecs are equal (i.e. have same name), return false. */
        return false;
    } else if (lhs.baseType() != rhs.baseType()) {
        /* If types are not the same, use the enum value for ordering along type.
         * The enum order in the header file is deliberate, it ensures that FX comes before FXVol
         * this property is used in data::order() (see curveloader.hpp)
         */
        return lhs.baseType() < rhs.baseType();
    } else {
        /* If types are the same and CurveSpecs are different, use default < for string */
        return lhs.name() < rhs.name();
    }
}

bool operator==(const CurveSpec& lhs, const CurveSpec& rhs) {
    /* We consider two CurveSpecs equal if they have the same name. */
    return lhs.name() == rhs.name();
}

bool operator<(const boost::shared_ptr<CurveSpec>& lhs, const boost::shared_ptr<CurveSpec>& rhs) { return *lhs < *rhs; }

bool operator==(const boost::shared_ptr<CurveSpec>& lhs, const boost::shared_ptr<CurveSpec>& rhs) {
    return *lhs == *rhs;
}

std::ostream& operator<<(std::ostream& os, const CurveSpec& spec) { return os << spec.name(); }

std::ostream& operator<<(std::ostream& os, const CurveSpec::CurveType& t) {
    switch (t) {
    case CurveSpec::CurveType::Yield:
        return os << "Yield";
    case CurveSpec::CurveType::CapFloorVolatility:
        return os << "CapFloorVolatility";
    case CurveSpec::CurveType::SwaptionVolatility:
        return os << "SwaptionVolatility";
    case CurveSpec::CurveType::YieldVolatility:
        return os << "YieldVolatility";
    case CurveSpec::CurveType::FX:
        return os << "FX";
    case CurveSpec::CurveType::FXVolatility:
        return os << "FXVolatility";
    case CurveSpec::CurveType::Security:
        return os << "Security";
    case CurveSpec::CurveType::Default:
        return os << "Default";
    case CurveSpec::CurveType::CDSVolatility:
        return os << "CDSVolatility";
    case CurveSpec::CurveType::Inflation:
        return os << "Inflation";
    case CurveSpec::CurveType::InflationCapFloorVolatility:
        return os << "InflationCapFloorVolatility";
    case CurveSpec::CurveType::Equity:
        return os << "Equity";
    case CurveSpec::CurveType::EquityVolatility:
        return os << "EquityVolatility";
    case CurveSpec::CurveType::BaseCorrelation:
        return os << "BaseCorrelation";
    case CurveSpec::CurveType::Commodity:
        return os << "Commodity";
    case CurveSpec::CurveType::CommodityVolatility:
        return os << "CommodityVolatility";
    case CurveSpec::CurveType::Correlation:
        return os << "Correlation";
    default:
        return os << "N/A";
    }
}
} // namespace data
} // namespace ore


/*
 All rights reserved.

 This file is part of ORE, a free-software/open-source library
 for transparent pricing and risk analysis - http://opensourcerisk.org

*/

#include <ored/marketdata/curvespec.hpp>
#include <ored/utilities/to_string.hpp>

namespace ore {
namespace data {

string CurveSpec::baseName() const { return ore::data::to_string(bas

 }

bool operator<(const CurveSpec& lhs, const CurveSpec& rhs) {
    if (lhs == rhs) {
        /* If CurveSpecs are equal (i.e. have same name), return false. */
        return false;
    } else if (lhs.baseType() != rhs.baseType()) {
        /* If types are not the same, use the enum value for ordering along type.
         * The enum order in the header file is deliberate, it ensures that FX comes before FXVol
         * this property is used in data::order() (see curveloader.hpp)
         */
        return lhs.baseType() < rhs.baseType();
    } else {
        /* If types are the same and CurveSpecs are different, use default < for string */
        return lhs.name() < rhs.name();
    }
}

bool operator==(const CurveSpec& lhs, const CurveSpec& rhs) {
    /* We consider two CurveSpecs equal if they have the same name. */
    return lhs.name() == rhs.name();
}

bool operator<(const boost::shared_ptr<CurveSpec>& lhs, const boost::shared_ptr<CurveSpec>& rhs) { return *lhs < *rhs; }

bool operator==(const boost::shared_ptr<CurveSpec>& lhs, const boost::shared_ptr<CurveSpec>& rhs) {
    return *lhs == *rhs;
}

std::ostream& operator<<(std::ostream& os, const CurveSpec& spec) { return os << spec.name(); }

std::ostream& operator<<(std::ostream& os, const CurveSpec::CurveType& t) {
    switch (t) {
    case CurveSpec::CurveType::Yield:
        return os << "Yield";
    case CurveSpec::CurveType::CapFloorVolatility:
        return os << "CapFloorVolatility";
    case CurveSpec::CurveType::SwaptionVolatility:
        return os << "SwaptionVolatility";
    case CurveSpec::CurveType::YieldVolatility:
        return os << "YieldVolatility";
    case CurveSpec::CurveType::FX:
        return os << "FX";
    case CurveSpec::CurveType::FXVolatility:
        return os << "FXVolatility";
    case CurveSpec::CurveType::Security:
        return os << "Security";
    case CurveSpec::CurveType::Default:
        return os << "Default";
    case CurveSpec::CurveType::CDSVolatility:
        return os << "CDSVolatility";
    case CurveSpec::CurveType::Inflation:
        return os << "Inflation";
    case CurveSpec::CurveType::InflationCapFloorVolatility:
        return os << "InflationCapFloorVolatility";
    case CurveSpec::CurveType::Equity:
        return os << "Equity";
    case CurveSpec::CurveType::EquityVolatility:
        return os << "EquityVolatility";
    case CurveSpec::CurveType::BaseCorrelation:
        return os << "BaseCorrelation";
    case CurveSpec::CurveType::Commodity:
        return os << "Commodity";
    case CurveSpec::CurveType::CommodityVolatility:
        return os << "CommodityVolatility";
    case CurveSpec::CurveType::Correlation:
        return os << "Correlation";
    default:
        return os << "N/A";
    }
}
} // namespace data
} // namespace ore


/*

Contact us at example@nnthink.com.

*/

#include "Common.h"
#include "UtilFunction.h"

class ExtractMCF : public UtilFunction
{
public:
	ExtractMCF()
	{
		s_uiLastFlag = -1;
	}

	virtual uint32 getNumArgs()
	{
		return 2;
	}

	virtual const char* getArgDesc(size_t index)
	{
		if (index == 0)
			return "Src Mcf";

		return "Dest Mcf";
	}

	virtual const char* getFullArg()
	{
		return "extract";
	}

	virtual const char getShortArg()
	{
		return 'x';
	}

	virtual const char* getDescription()
	{
		return "Extracts a mcf into a folder";
	}

	virtual int performAction(std::vector<std::string> &args)
	{
		MCFCore::MCFI* mcfHandle = mcfFactory();

		mcfHandle->setFile(args[0].c_str());
		mcfHandle->parseMCF();

		mcfHandle->getProgEvent() += delegate(this, &ExtractMCF::mcfProgress);
		mcfHandle->getErrorEvent() += delegate(this, &ExtractMCF::mcfError);
		mcfHandle->saveFiles(args[1].c_str());

		mcfDelFactory(mcfHandle);
		return 0;
	}

protected:
	void mcfProgress(MCFCore::Misc::ProgressInfo& prog)
	{
		if (s_uiLastFlag != prog.flag)
		{
			if (prog.flag == 1)
				printf("\nInit Extraction...\n");
			else
				printf("\nExtracting...\n");

			s_uiLastFlag = prog.flag;
		}

		printProgress(prog);
	}

	void mcfError(gcException& e)
	{
		gcString err("{0}", e);
		printf("\nMCF Error: %s\n", err.c_str());
	}

	uint32 s_uiLastFlag;
};

class SaveXML : public UtilFunction
{
public:
	virtual uint32 getNumArgs()
	{
		return 2;
	}

	virtual const char* getArgDesc(size_t index)
	{
		if (index == 0)
			return "Src Mcf";

		return "Dest Xml";
	}

	virtual const char* getFullArg()
	{
		return "savexml";
	}

	virtual const char getShortArg()
	{
		return 's';
	}

	virtual const char* getDescription()
	{
		return "Saves mcf xml to a file";
	}

	virtual int performAction(std::vector<std::string> &args)
	{
		MCFCore::MCFI* mcfSrc = mcfFactory();

		printf("Parsing MCF: %s\n", args[0].c_str());
		mcfSrc->setFile(args[0].c_str());
		mcfSrc->parseMCF();
		mcfSrc->saveXml(args[1].c_str());

		mcfDelFactory(mcfSrc);
		return 0;
	}
};

class UpdateMCF : public UtilFunction
{
public:
	virtual uint32 getNumArgs()
	{
		return 2;
	}

	virtual const char* getArgDesc(size_t index)
	{
		if (index == 0)
			return "Src Mcf";

		return "Dest Mcf";
	}

	virtual const char* getFullArg()
	{
		return "update";
	}

	virtual const char getShortArg()
	{
		return 'u';
	}

	virtual const char* getDescription()
	{
		return "Updates a mcf to newest mcf format";
	}

{
		MCFCore::MCFI* mcfSrc = mcfFactory();

		printf("Parsing MCF: %s\n", args[0].c_str());
		mcfSrc->setFile(args[0].c_str());
		mcfSrc->parseMCF();

		printf("Exporting MCF: %s\n", args[1].c_str());
		mcfSrc->exportMcf(args[1].c_str());

		mcfDelFactory(mcfSrc);

		return 0;
	}
};

class OptimiseMCF : public UtilFunction
{
public:
	virtual uint32 getNumArgs()
	{
		return 3;
	}

	virtual const char* getArgDesc(size_t index)
	{
		if (index == 0)
			return "Last Build Src Mcf";

		if (index == 1)
			return "Current Build Src Mcf";

		return "Dest Mcf";
	}

	virtual const char* getFullArg()
	{
		return "optimise";
	}

	virtual const char getShortArg()
	{
		return 'o';
	}

	virtual const char* getDescription()
	{
		return "Moves all changed and new files to the start of the mcf";
	}

	virtual int performAction(std::vector<std::string> &args)
	{
		MCFCore::MCFI* mcfPrevSrc = mcfFactory();
		MCFCore::MCFI* mcfCurSrc = mcfFactory();

		printf("Parsing Prev MCF: %s\n", args[0].c_str());
		mcfPrevSrc->setFile(args[0].c_str());
		mcfPrevSrc->parseMCF();

		printf("Parsing Cur MCF: %s\n", args[1].c_str());
		mcfCurSrc->setFile(args[1].c_str());
		mcfCurSrc->parseMCF();

		printf("Exporting Optimised MCF: %s\n", args[2].c_str());
		mcfCurSrc->optimiseAndSaveMcf(mcfPrevSrc, args[2].c_str());

		mcfDelFactory(mcfPrevSrc);
		mcfDelFactory(mcfCurSrc);
		return 0;
	}
};

REG_FUNCTION(ExtractMCF)
REG_FUNCTION(SaveXML)
REG_FUNCTION(UpdateMCF)
REG_FUNCTION(OptimiseMCF)


/*

Contact us at example@nnthink.com.

*/

#include "Common.h"
#include "UtilFunction.h"

class ExtractMCF : public UtilFunction
{
public:
	ExtractMCF()

	virtual uint32 getNumArgs()
	{
		return 2;
	}

	virtual const char* getArgDesc(size_t index)
	{
		if (index == 0)
			return "Src Mcf";

		return "Dest Mcf";
	}

	virtual const char* getFullArg()
	{
		return "extract";
	}

	virtual const char getShortArg()
	{
		return 'x';
	}

	virtual const char* getDescription()
	{
		return "Extracts a mcf into a folder";
	}

	virtual int performAction(std::vector<std::string> &args)
	{
		MCFCore::MCFI* mcfHandle = mcfFactory();

		mcfHandle->setFile(args[0].c_str());
		mcfHandle->parseMCF();

		mcfHandle->getProgEvent() += delegate(this, &ExtractMCF::mcfProgress);
		mcfHandle->getErrorEvent() += delegate(this, &ExtractMCF::mcfError);
		mcfHandle->saveFiles(args[1].c_str());

		mcfDelFactory(mcfHandle);
		return 0;
	}

protected:
	void mcfProgress(MCFCore::Misc::ProgressInfo& prog)
	{
		if (s_uiLastFlag != prog.flag)
		{
			if (prog.flag == 1)
				printf("\nInit Extraction...\n");
			else
				printf("\nExtracting...\n");

			s_uiLastFlag = prog.flag;
		}

		printProgress(prog);
	}

	void mcfError(gcException& e)
	{
		gcString err("{0}", e);
		printf("\nMCF Error: %s\n", err.c_str());
	}

	uint32 s_uiLastFlag;
};

class SaveXML : public UtilFunction
{
public:
	virtual uint32 getNumArgs()
	{
		return 2;
	}

	virtual const char* getArgDesc(size_t index)
	{
		if (index == 0)
			return "Src Mcf";

		return "Dest Xml";
	}

	virtual const char* getFullArg()
	{
		return "savexml";
	}

	virtual const char getShortArg()
	{
		return 's';
	}

	virtual const char* getDescription()
	{
		return "Saves mcf xml to a file";
	}

	virtual int performAction(std::vector<std::string> &args)
	{
		MCFCore::MCFI* mcfSrc = mcfFactory();

		printf("Parsing MCF: %s\n", args[0].c_str());
		mcfSrc->setFile(args[0].c_str());
		mcfSrc->parseMCF();
		mcfSrc->saveXml(args[1].c_str());

		mcfDelFactory(mcfSrc);
		return 0;
	}
};

class UpdateMCF : public UtilFunction
{
public:
	virtual uint32 getNumArgs()
	{
		return 2;
	}

	virtual const char* getArgDesc(size_t index)
	{
		if (index == 0)
			return "Src Mcf";

		return "Dest Mcf";
	}

	virtual const char* getFullArg()
	{
		return "update";
	}

	virtual const char getShortArg()
	{
		return 'u';
	}

	virtual const char* getDescription()
	{
		return "Updates a mcf to newest mcf format";
	}

	virtual int performAction(std::vector<std::string> &args)
	{
		MCFCore::MCFI* mcfSrc = mcfFactory();

		printf("Parsing MCF: %s\n", args[0].c_str());
		mcfSrc->setFile(args[0].c_str());
		mcfSrc->parseMCF();

		printf("Exporting MCF: %s\n", args[1].c_str());
		mcfSrc->exportMcf(args[1].c_str());

		mcfDelFactory(mcfSrc);

		return 0;
	}
};

class OptimiseMCF : public UtilFunction
{
public:
	virtual uint32 getNumArgs()
	{
		return 3;
	}

	virtual const char* getArgDesc(size_t index)
	{
		if (index == 0)
			return "Last Build Src Mcf";

		if (index == 1)
			return "Current Build Src Mcf";

		return "Dest Mcf";
	}

	virtual const char* getFullArg()
	{
		return "optimise";
	}

	virtual const char getShortArg()
	{
		return 'o';
	}

	virtual const char* getDescription()
	{
		return "Moves all changed and new files to the start of the mcf";
	}

	virtual int performAction(std::vector<std::string> &args)
	{
		MCFCore::MCFI* mcfPrevSrc = mcfFactory();
		MCFCore::MCFI* mcfCurSrc = mcfFactory();

		printf("Parsing Prev MCF: %s\n", args[0].c_str());
		mcfPrevSrc->setFile(args[0].c_str());
		mcfPrevSrc->parseMCF();

		printf("Parsing Cur MCF: %s\n", args[1].c_str());
		mcfCurSrc->setFile(args[1].c_str());
		mcfCurSrc->parseMCF();

		printf("Exporting Optimised MCF: %s\n", args[2].c_str());
		mcfCurSrc->optimiseAndSaveMcf(mcfPrevSrc, args[2].c_str());

		mcfDelFactory(mcfPrevSrc);
		mcfDelFactory(mcfCurSrc);
		return 0;
	}
};

REG_FUNCTION(ExtractMCF)
REG_FUNCTION(SaveXML)
REG_FUNCTION(UpdateMCF)
REG_FUNCTION(OptimiseMCF)


/*

Contact us at example@nnthink.com.

*/

#include "Common.h"
#include "UtilFunction.h"

class ExtractMCF : public UtilFunction
{
public:
	ExtractMCF()
	{
		s_uiLastFlag = -1;
	}

	virtual uint32 getNumArgs()
	{
		return 2;
	}

	virtual const char* getArgDesc(size_t index)
	{
		if (index == 0)
			return "Src Mcf";

		return "Dest Mcf";
	}

	virtual const char* getFullArg()
	{
		return "extract";
	}

	virtual const char getShortArg()
	{
		return 'x';
	}

	virtual const char* getDescription()
	{
		return "Extracts a mcf into a folder";
	}

	virtual int performAction(std::vector<std::string> &args)
	{
		MCFCore::MCFI* mcfHandle = mcfFactory();

		mcfHandle->setFile(args[0].c_str());
		mcfHandle->parseMCF();

		mcfHandle->getProgEvent() += delegate(this, &ExtractMCF::mcfProgress);
		mcfHandle->getErrorEvent() += delegate(this, &ExtractMCF::mcfError);
		mcfHandle->saveFiles(args[1].c_str());

		mcfDelFactory(mcfHandle);
		return 0;
	}

protected:
	void mcfProgress(MCFCore::Misc::ProgressInfo& prog)
	{
		if (s_uiLastFlag != prog.flag)
		{
			if (prog.flag == 1)
				printf("\nInit Extraction...\n");
			else
				printf("\nExtracting...\n");

			s_uiLastFlag = prog.flag;
		}

		printProgress(prog);
	}

	void mcfError(gcException& e)
	{
		gcString err("{0}", e);
		printf("\nMCF Error: %s\n", err.c_str());
	}

	uint32 s_uiLastFlag;
};

class SaveXML : public UtilFunction
{
public:
	virtual uint32 getNumArgs()
	{
		return 2;
	}

	virtual const char* getArgDesc(size_t index)
	{
		if (index == 0)
			return "Src Mcf";

		return "Dest Xml";
	}

	virtual const char* getFullArg()
	{
		return "savexml";
	}

	virtual const char getShortArg()
	{
		return 's';
	}

	virtual const char* getDescription()
	{
		return "Saves mcf xml to a file";
	}

	virtual int performAction(std::vector<std::string> &args)
	{
		MCFCore::MCFI* mcfSrc = mcfFactory();

		printf("Parsing MCF: %s\n", args[0].c_str());
		mcfSrc->setFile(args[0].c_str());
		mcfSrc->parseMCF();
		mcfSrc->saveXml(args[1].c_str());

		mcfDelFactory(mcfSrc);
		return 0;
	}
};

class UpdateMCF : public UtilFunction
{
public:
	virtual uint32 getNumArgs()
	{
		return 2;
	}

	virtual const char* getArgDesc(size_t index)
	{
		if (index == 0)
			return "Src Mcf";

		return "Dest Mcf";
	}

	virtual const char* getFullArg()
	{
		return "update";
	}

	virtual const char getShortArg()
	{
		return 'u';
	}

	virtual const char* getDescription()
	{
		return "Updates a mcf to newest mcf format";
	}

	virtual int performAction(std::vector<std::string> &args)
	{
		MCFCore::MCFI* mcfSrc = mcfFactory();

		printf("Parsing MCF: %s\n", args[0].c_str());
		mcfSrc->setFile(args[0].c_str());
		mcfSrc->parseMCF();

		printf("Exporting MCF: %s\n", args[1].c_str());
		mcfSrc->exportMcf(args[1].c_str());

		mcfDelFactory(mcfSrc);

		return 0;
	}
};

class OptimiseMCF : public UtilFunction
{
public:
	virtual uint32 getNumArgs()
	{
		return 3;
	}

	virtual const char* getArgDesc(size_t index)
	{
		if (index == 0)
			return "Last Build Src Mcf";

		if (index == 1)
			return "Current Build Src Mcf";

		return "Dest Mcf";
	}

	virtual const char* getFullArg()
	{
		return "optimise";
	}

	virtual const char getShortArg()
	{
		return 'o';
	}

	virtual const char* getDescription()
	{
		return "Moves all changed and new files to the start of the mcf";
	}

	virtual int performAction(std::vector<std::string> &args)
	{
		MCFCore::MCFI* mcfPrevSrc = mcfFactory();
		MCFCore::MCFI* mcfCurSrc = mcfFactory();

		printf("Parsing Prev MCF: %s\n", args[0].c_str());
		mcfPrevSrc->setFile(args[0].c_str());
		mcfPrevSrc->parseMCF();

		printf("Parsing Cur MCF: %s\n", args[1].c_st

		mcfCurSrc->setFile(args[1].c_str());
		mcfCurSrc->parseMCF();

		printf("Exporting Optimised MCF: %s\n", args[2].c_str());
		mcfCurSrc->optimiseAndSaveMcf(mcfPrevSrc, args[2].c_str());

		mcfDelFactory(mcfPrevSrc);
		mcfDelFactory(mcfCurSrc);
		return 0;
	}
};

REG_FUNCTION(ExtractMCF)
REG_FUNCTION(SaveXML)
REG_FUNCTION(UpdateMCF)
REG_FUNCTION(OptimiseMCF)


MD5::MD5 (const MemoryBlock& data) noexcept

/*
  ==============================================================================

   This file is part of the JUCE library.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   27th April 2017).

   Privacy Policy: www.juce.com/juce-5-privacy-policy

   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

class MD5Generator
{
public:
    MD5Generator() noexcept
    {
        state[0] = 0x67452301;
        state[1] = 0xefcdab89;
        state[2] = 0x98badcfe;
        state[3] = 0x10325476;

        count[0] = 0;
        count[1] = 0;
    }

    void processBlock (const void* data, size_t dataSize) noexcept
    {
        int bufferPos = ((count[0] >> 3) & 0x3F);

        count[0] += (uint32) (dataSize << 3);

        if (count[0] < ((uint32) dataSize << 3))
            count[1]++;

        count[1] += (uint32) (dataSize >> 29);

        const size_t spaceLeft = 64 - (size_t) bufferPos;
        size_t i = 0;

        if (dataSize >= spaceLeft)
        {
            memcpy (buffer + bufferPos, data, spaceLeft);
            transform (buffer);

            for (i = spaceLeft; i + 64 <= dataSize; i += 64)
                transform (static_cast<const char*> (data) + i);

            bufferPos = 0;
        }

        memcpy (buffer + bufferPos, static_cast<const char*> (data) + i, dataSize - i);
    }

    void transform (const void* bufferToTransform) noexcept
    {
        uint32 a = state[0];
        uint32 b = state[1];
        uint32 c = state[2];
        uint32 d = state[3];
        uint32 x[16];

        encode (x, bufferToTransform, 64);

        enum Constants
        {
            S11 = 7, S12 = 12, S13 = 17, S14 = 22, S21 = 5, S22 = 9,  S23 = 14, S24 = 20,
            S31 = 4, S32 = 11, S33 = 16, S34 = 23, S41 = 6, S42 = 10, S43 = 15, S44 = 21
        };

        FF (a, b, c, d, x[ 0], S11, 0xd76aa478);     FF (d, a, b, c, x[ 1], S12, 0xe8c7b756);
        FF (c, d, a, b, x[ 2], S13, 0x242070db);     FF (b, c, d, a, x[ 3], S14, 0xc1bdceee);
        FF (a, b, c, d, x[ 4], S11, 0xf57c0faf);     FF (d, a, b, c, x[ 5], S12, 0x4787c62a);
        FF (c, d, a, b, x[ 6], S13, 0xa8304613);     FF (b, c, d, a, x[ 7], S14, 0xfd469501);
        FF (a, b, c, d, x[ 8], S11, 0x698098d8);     FF (d, a, b, c, x[ 9], S12, 0x8b44f7af);
        FF (c, d, a, b, x[10], S13, 0xffff5bb1);     FF (b, c, d, a, x[11], S14, 0x895cd7be);
        FF (a, b, c, d, x[12], S11, 0x6b901122);     FF (d, a, b, c, x[13], S12, 0xfd987193);
        FF (c, d, a, b, x[14], S13, 0xa679438e);     FF (b, c, d, a, x[15], S14, 0x49b40821);

        GG (a, b, c, d, x[ 1], S21, 0xf61e2562);     GG (d, a, b, c, x[ 6], S22, 0xc040b340);
        GG (c, d, a, b, x[11], S23, 0x265e5a51);     GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa);
        GG (a, b, c, d, x[ 5], S21, 0xd62f105d);     GG (d, a, b, c, x[10], S22, 0x02441453);
        GG (c, d, a, b, x[15], S23, 0xd8a1e681);     GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8);
        GG (a, b, c, d, x[ 9], S21, 0x21e1cde6);     GG (d, a, b, c, x[14], S22, 0xc33707d6);
        GG (c, d, a, b, x[ 3], S23, 0xf4d50d87);     GG (b, c, d, a, x[ 8], S24, 0x455a14ed);
        GG (a, b, c, d, x[13], S21, 0xa9e3e905);     GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8);
        GG (c, d, a, b, x[ 7], S23, 0x676f02d9);     GG (b, c, d, a, x[12], S24, 0x8d2a4c8a);

        HH (a, b, c, d, x[ 5], S31, 0xfffa3942);     HH (d, a, b, c, x[ 8], S32, 0x8771f681);
        HH (c, d, a, b, x[11], S33, 0x6d9d6122);     HH (b, c, d, a, x[14], S34, 0xfde5380c);
        HH (a, b, c, d, x[ 1], S31, 0xa4beea44);     HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9);
        HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60);     HH (b, c, d, a, x[10], S34, 0xbebfbc70);
        HH (a, b, c, d, x[13], S31, 0x289b7ec6);     HH (d, a, b, c, x[ 0], S32, 0xeaa127fa);
        HH (c, d, a, b, x[ 3], S33, 0xd4ef3085);     HH (b, c, d, a, x[ 6], S34, 0x04881d05);
        HH (a, b, c, d, x[ 9], S31, 0xd9d4d039);     HH (d, a, b, c, x[12], S32, 0xe6db99e5);
        HH (c, d, a, b, x[15], S33, 0x1fa27cf8);     HH (b, c, d, a, x[ 2], S34, 0xc4ac5665);

        II (a, b, c, d, x[ 0], S41, 0xf4292244);     II (d, a, b, c, x[ 7], S42, 0x432aff97);
        II (c, d, a, b, x[14], S43, 0xab9423a7);     II (b, c, d, a, x[ 5], S44, 0xfc93a039);
        II (a, b, c, d, x[12], S41, 0x655b59c3);     II (d, a, b, c, x[ 3], S42, 0x8f0ccc92);
        II (c, d, a, b, x[10], S43, 0xffeff47d);     II (b, c, d, a, x[ 1], S44, 0x85845dd1);
        II (a, b, c, d, x[ 8], S41, 0x6fa87e4f);     II (d, a, b, c, x[15], S42, 0xfe2ce6e0);
        II (c, d, a, b, x[ 6], S43, 0xa3014314);     II (b, c, d, a, x[13], S44, 0x4e0811a1);
        II (a, b, c, d, x[ 4], S41, 0xf7537e82);     II (d, a, b, c, x[11], S42, 0xbd3af235);
        II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb);     II (b, c, d, a, x[ 9], S44, 0xeb86d391);

        state[0] += a;
        state[1] += b;
        state[2] += c;
        state[3] += d;

        zerostruct (x);
    }

    void finish (void* result) noexcept
    {
        unsigned char encodedLength[8];
        encode (encodedLength, count, 8);

        // Pad out to 56 mod 64.
        const int index = (count[0] >> 3) & 0x3f;

        const int paddingLength = (index < 56) ? (56 - index)
                                               : (120 - index);

        uint8 paddingBuffer[64] = { 0x80 }; // first byte is 0x80, remaining bytes are zero.
        processBlock (paddingBuffer, (size_t) paddingLength);

        processBlock (encodedLength, 8);

        encode (result, state, 16);
        zerostruct (buffer);
    }

private:
    uint8 buffer [64];
    uint32 state [4];
    uint32 count [2];

    static void encode (void* const output, const void* const input, const int numBytes) noexcept
    {
        for (int i = 0; i < (numBytes >> 2); ++i)
            static_cast<uint32*> (output)[i] = ByteOrder::swapIfBigEndian (static_cast<const uint32*> (input) [i]);
    }

    static inline uint32 rotateLeft (const uint32 x, const uint32 n) noexcept          { return (x << n) | (x >> (32 - n)); }

    static inline uint32 F (const uint32 x, const uint32 y, const uint32 z) noexcept   { return (x & y) | (~x & z); }
    static inline uint32 G (const uint32 x, const uint32 y, const uint32 z) noexcept   { return (x & z) | (y & ~z); }
    static inline uint32 H (const uint32 x, const uint32 y, const uint32 z) noexcept   { return x ^ y ^ z; }
    static inline uint32 I (const uint32 x, const uint32 y, const uint32 z) noexcept   { return y ^ (x | ~z); }

    static void FF (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) noexcept
    {
        a += F (b, c, d) + x + ac;
        a = rotateLeft (a, s) + b;
    }

    static void GG (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) noexcept
    {
        a += G (b, c, d) + x + ac;
        a = rotateLeft (a, s) + b;
    }

    static void HH (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) noexcept
    {
        a += H (b, c, d) + x + ac;
        a = rotateLeft (a, s) + b;
    }

    static void II (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) noexcept
    {
        a += I (b, c, d) + x + ac;
        a = rotateLeft (a, s) + b;
    }
};

MD5::MD5() noexcept
{
    zerostruct (result);
}

MD5::MD5 (const MD5& other) noexcept
{
    memcpy (result, other.result, sizeof (result));
}

MD5& MD5::operator= (const MD5& other) noexcept
{
    memcpy (result, other.result, sizeof (result));
    return *this;
}

{
    processData (data.getData(), data.getSize());
}

MD5::MD5 (const void* data, const size_t numBytes) noexcept
{
    processData (data, numBytes);
}

MD5::MD5 (CharPointer_UTF8 utf8) noexcept
{
    jassert (utf8.getAddress() != nullptr);
    processData (utf8.getAddress(), utf8.sizeInBytes() - 1);
}

MD5 MD5::fromUTF32 (StringRef text)
{
    MD5Generator generator;
    String::CharPointerType t (text.text);

    while (! t.isEmpty())
    {
        uint32 unicodeChar = ByteOrder::swapIfBigEndian ((uint32) t.getAndAdvance());
        generator.processBlock (&unicodeChar, sizeof (unicodeChar));
    }

    MD5 m;
    generator.finish (m.result);
    return m;
}

MD5::MD5 (InputStream& input, int64 numBytesToRead)
{
    processStream (input, numBytesToRead);
}

MD5::MD5 (const File& file)
{
    FileInputStream fin (file);

    if (fin.getStatus().wasOk())
        processStream (fin, -1);
    else
        zerostruct (result);
}

MD5::~MD5() noexcept {}

void MD5::processData (const void* data, size_t numBytes) noexcept
{
    MD5Generator generator;
    generator.processBlock (data, numBytes);
    generator.finish (result);
}

void MD5::processStream (InputStream& input, int64 numBytesToRead)
{
    MD5Generator generator;

    if (numBytesToRead < 0)
        numBytesToRead = std::numeric_limits<int64>::max();

    while (numBytesToRead > 0)
    {
        uint8 tempBuffer [512];
        const int bytesRead = input.read (tempBuffer, (int) jmin (numBytesToRead, (int64) sizeof (tempBuffer)));

        if (bytesRead <= 0)
            break;

        numBytesToRead -= bytesRead;
        generator.processBlock (tempBuffer, (size_t) bytesRead);
    }

    generator.finish (result);
}

MemoryBlock MD5::getRawChecksumData() const
{
    return MemoryBlock (result, sizeof (result));
}

String MD5::toHexString() const
{
    return String::toHexString (result, sizeof (result), 0);
}

bool MD5::operator== (const MD5& other) const noexcept   { return memcmp (result, other.result, sizeof (result)) == 0; }
bool MD5::operator!= (const MD5& other) const noexcept   { return ! operator== (other); }

#if JUCE_UNIT_TESTS

class MD5Tests  : public UnitTest
{
public:
    MD5Tests() : UnitTest ("MD5") {}

    void test (const char* input, const char* expected)
    {
        {
            MD5 hash (input, strlen (input));
            expectEquals (hash.toHexString(), String (expected));
        }

        {
            MemoryInputStream m (input, strlen (input), false);
            MD5 hash (m);
            expectEquals (hash.toHexString(), String (expected));
        }
    }

    void runTest() override
    {
        beginTest ("MD5");

        test ("", "d41d8cd98f00b204e9800998ecf8427e");
        test ("The quick brown fox jumps over the lazy dog",  "9e107d9d372bb6826bd81d3542a419d6");
        test ("The quick brown fox jumps over the lazy dog.", "e4d909c290d0fb1ca068ffaddf22cbd0");
    }
};

static MD5Tests MD5UnitTests;

#endif


/*
  ==============================================================================

   This file is part of the JUCE library.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   27th April 2017).

   Privacy Policy: www.juce.com/juce-5-privacy-policy

   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

class MD5Generator
{
public:
    MD5Generator() noexcept
    {
        state[0] = 0x67452301;
        state[1] = 0xefcdab89;
        state[2] = 0x98badcfe;
        state[3] = 0x10325476;

        count[0] = 0;
        count[1] = 0;
    }

    void processBlock (const void* data, size_t dataSize) noexcept
    {
        int bufferPos = ((count[0] >> 3) & 0x3F);

        count[0] += (uint32) (dataSize << 3);

        if (count[0] < ((uint32) dataSize << 3))
            count[1]++;

        count[1] += (uint32) (dataSize >> 29);

        const size_t spaceLeft = 64 - (size_t) bufferPos;
        size_t i = 0;

        if (dataSize >= spaceLeft)
        {
            memcpy (buffer + bufferPos, data, spaceLeft);
            transform (buffer);

            for (i = spaceLeft; i + 64 <= dataSize; i += 64)
                transform (static_cast<const char*> (data) + i);

            bufferPos = 0;
        }

        memcpy (buffer + bufferPos, static_cast<const char*> (data) + i, dataSize - i);
    }

    void transform (const void* bufferToTransform) noexcept
    {
        uint32 a = state[0];
        uint32 b = state[1];
        uint32 c = state[2];
        uint32 d = state[3];
        uint32 x[16];

        encode (x, bufferToTransform, 64);

        enum Constants
        {
            S11 = 7, S12 = 12, S13 = 17, S14 = 22, S21 = 5, S22 = 9,  S23 = 14, S24 = 20,
            S31 = 4, S32 = 11, S33 = 16, S34 = 23, S41 = 6, S42 = 10, S43 = 15, S44 = 21
        };

        FF (a, b, c, d, x[ 0], S11, 0xd76aa478);     FF (d, a, b, c, x[ 1], S12, 0xe8c7b756);
        FF (c, d, a, b, x[ 2], S13, 0x242070db);     FF (b, c, d, a, x[ 3], S14, 0xc1bdceee);
        FF (a, b, c, d, x[ 4], S11, 0xf57c0faf);     FF (d, a, b, c, x[ 5], S12, 0x4787c62a);
        FF (c, d, a, b, x[ 6], S13, 0xa8304613);     FF (b, c, d, a, x[ 7], S14, 0xfd469501);
        FF (a, b, c, d, x[ 8], S11, 0x698098d8);     FF (d, a, b, c, x[ 9], S12, 0x8b44f7af);
        FF (c, d, a, b, x[10], S13, 0xffff5bb1);     FF (b, c, d, a, x[11], S14, 0x895cd7be);
        FF (a, b, c, d, x[12], S11, 0x6b901122);     FF (d, a, b, c, x[13], S12, 0xfd987193);
        FF (c, d, a, b, x[14], S13, 0xa679438e);     FF (b, c, d, a, x[15], S14, 0x49b40821);

        GG (a, b, c, d, x[ 1], S21, 0xf61e2562);     GG (d, a, b, c, x[ 6], S22, 0xc040b340);
        GG (c, d, a, b, x[11], S23, 0x265e5a51);     GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa);
        GG (a, b, c, d, x[ 5], S21, 0xd62f105d);     GG (d, a, b, c, x[10], S22, 0x02441453);
        GG (c, d, a, b, x[15], S23, 0xd8a1e681);     GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8);
        GG (a, b, c, d, x[ 9], S21, 0x21e1cde6);     GG (d, a, b, c, x[14], S22, 0xc33707d6);
        GG (c, d, a, b, x[ 3], S23, 0xf4d50d87);     GG (b, c, d, a, x[ 8], S24, 0x455a14ed);
        GG (a, b, c, d, x[13], S21, 0xa9e3e905);     GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8);
        GG (c, d, a, b, x[ 7], S23, 0x676f02d9);     GG (b, c, d, a, x[12], S24, 0x8d2a4c8a);

        HH (a, b, c, d, x[ 5], S31, 0xfffa3942);     HH (d, a, b, c, x[ 8], S32, 0x8771f681);
        HH (c, d, a, b, x[11], S33, 0x6d9d6122);     HH (b, c, d, a, x[14], S34, 0xfde5380c);
        HH (a, b, c, d, x[ 1], S31, 0xa4beea44);     HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9);
        HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60);     HH (b, c, d, a, x[10], S34, 0xbebfbc70);
        HH (a, b, c, d, x[13], S31, 0x289b7ec6);     HH (d, a, b, c, x[ 0], S32, 0xeaa127fa);
        HH (c, d, a, b, x[ 3], S33, 0xd4ef3085);     HH (b, c, d, a, x[ 6], S34, 0x04881d05);
        HH (a, b, c, d, x[ 9], S31, 0xd9d4d039);     HH (d, a, b, c, x[12], S32, 0xe6db99e5);
        HH (c, d, a, b, x[15], S33, 0x1fa27cf8);     HH (b, c, d, a, x[ 2], S34, 0xc4ac5665);

        II (a, b, c, d, x[ 0], S41, 0xf4292244);     II (d, a, b, c, x[ 7], S42, 0x432aff97);
        II (c, d, a, b, x[14], S43, 0xab9423a7);     II (b, c, d, a, x[ 5], S44, 0xfc93a039);
        II (a, b, c, d, x[12], S41, 0x655b59c3);     II (d, a, b, c, x[ 3], S42, 0x8f0ccc92);
        II (c, d, a, b, x[10], S43, 0xffeff47d);     II (b, c, d, a, x[ 1], S44, 0x85845dd1);
        II (a, b, c, d, x[ 8], S41, 0x6fa87e4f);     II (d, a, b, c, x[15], S42, 0xfe2ce6e0);
        II (c, d, a, b, x[ 6], S43, 0xa3014314);     II (b, c, d, a, x[13], S44, 0x4e0811a1);
        II (a, b, c, d, x[ 4], S41, 0xf7537e82);     II (d, a, b, c, x[11], S42, 0xbd3af235);
        II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb);     II (b, c, d, a, x[ 9], S44, 0xeb86d391);

        state[0] += a;
        state[1] += b;
        state[2] += c;
        state[3] += d;

        zerostruct (x);
    }

    void finish (void* result) noexcept
    {
        unsigned char encodedLength[8];
        encode (encodedLength, count, 8);

        // Pad out to 56 mod 64.
        const int index = (count[0] >> 3) & 0x3f;

        const int paddingLength = (index < 56) ? (56 - index)
                                               : (120 - index);

        uint8 paddingBuffer[64] = { 0x80 }; // first byte is 0x80, remaining bytes are zero.
        processBlock (paddingBuffer, (size_t) paddingLength);

        processBlock (encodedLength, 8);

        encode (result, state, 16);
        zerostruct (buffer);
    }

private:
    uint8 buffer [64];
    uint32 state [4];
    uint32 count [2];

    static void encode (void* const output, const void* const input, const int numBytes) noexcept
    {
        for (int i = 0; i < (numBytes >> 2); ++i)
            static_cast<uint32*> (output)[i] = ByteOrder::swapIfBigEndian (static_cast<const uint32*> (input) [i]);
    }

    static inline uint32 rotateLeft (const uint32 x, const uint32 n) noexcept          { return (x << n) | (x >> (32 - n)); }

    static inline uint32 F (const uint32 x, const uint32 y, const uint32 z) noexcept   { return (x & y) | (~x & z); }
    static inline uint32 G (const uint32 x, const uint32 y, const uint32 z) noexcept   { return (x & z) | (y & ~z); }
    static inline uint32 H (const uint32 x, const uint32 y, const uint32 z) noexcept   { return x ^ y ^ z; }
    static inline uint32 I (const uint32 x, const uint32 y, const uint32 z) noexcept   { return y ^ (x | ~z); }

    static void FF (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) noexcept
    {
        a += F (b, c, d) + x + ac;
        a = rotateLeft (a, s) + b;
    }

    static void GG (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) noexcept
    {
        a += G (b, c, d) + x + ac;
        a = rotateLeft (a, s) + b;
    }

    static void HH (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) noexcept
    {
        a += H (b, c, d) + x + ac;
        a = rotateLeft (a, s) + b;
    }

    static void II (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) noexcept
    {
        a += I (b, c, d) + x + ac;
        a = rotateLeft (a, s) + b;
    }
};

MD5::MD5() noexcept
{
    zerostruct (result);
}

MD5::MD5 (const MD5& other) noexcept
{
    memcpy (result, other.result, sizeof (result));
}

MD5& MD5::operator= (const MD5& other) noexcept
{
    memcpy (result, other.result, sizeof (result));
    return *this;
}

MD5::MD5 (const MemoryBlock& data) noexcept
{
    processData (data.getData(), data.getSize());
}

MD5::MD5 (const void* data, const size_t numBytes) noexcept

MD5::MD5 (CharPointer_UTF8 utf8) noexcept
{
    jassert (utf8.getAddress() != nullptr);
    processData (utf8.getAddress(), utf8.sizeInBytes() - 1);
}

MD5 MD5::fromUTF32 (StringRef text)
{
    MD5Generator generator;
    String::CharPointerType t (text.text);

    while (! t.isEmpty())
    {
        uint32 unicodeChar = ByteOrder::swapIfBigEndian ((uint32) t.getAndAdvance());
        generator.processBlock (&unicodeChar, sizeof (unicodeChar));
    }

    MD5 m;
    generator.finish (m.result);
    return m;
}

MD5::MD5 (InputStream& input, int64 numBytesToRead)
{
    processStream (input, numBytesToRead);
}

MD5::MD5 (const File& file)
{
    FileInputStream fin (file);

    if (fin.getStatus().wasOk())
        processStream (fin, -1);
    else
        zerostruct (result);
}

MD5::~MD5() noexcept {}

void MD5::processData (const void* data, size_t numBytes) noexcept
{
    MD5Generator generator;
    generator.processBlock (data, numBytes);
    generator.finish (result);
}

void MD5::processStream (InputStream& input, int64 numBytesToRead)
{
    MD5Generator generator;

    if (numBytesToRead < 0)
        numBytesToRead = std::numeric_limits<int64>::max();

    while (numBytesToRead > 0)
    {
        uint8 tempBuffer [512];
        const int bytesRead = input.read (tempBuffer, (int) jmin (numBytesToRead, (int64) sizeof (tempBuffer)));

        if (bytesRead <= 0)
            break;

        numBytesToRead -= bytesRead;
        generator.processBlock (tempBuffer, (size_t) bytesRead);
    }

    generator.finish (result);
}

MemoryBlock MD5::getRawChecksumData() const
{
    return MemoryBlock (result, sizeof (result));
}

String MD5::toHexString() const
{
    return String::toHexString (result, sizeof (result), 0);
}

bool MD5::operator== (const MD5& other) const noexcept   { return memcmp (result, other.result, sizeof (result)) == 0; }
bool MD5::operator!= (const MD5& other) const noexcept   { return ! operator== (other); }

#if JUCE_UNIT_TESTS

class MD5Tests  : public UnitTest
{
public:
    MD5Tests() : UnitTest ("MD5") {}

    void test (const char* input, const char* expected)
    {
        {
            MD5 hash (input, strlen (input));
            expectEquals (hash.toHexString(), String (expected));
        }

        {
            MemoryInputStream m (input, strlen (input), false);
            MD5 hash (m);
            expectEquals (hash.toHexString(), String (expected));
        }
    }

    void runTest() override
    {
        beginTest ("MD5");

        test ("", "d41d8cd98f00b204e9800998ecf8427e");
        test ("The quick brown fox jumps over the lazy dog",  "9e107d9d372bb6826bd81d3542a419d6");
        test ("The quick brown fox jumps over the lazy dog.", "e4d909c290d0fb1ca068ffaddf22cbd0");
    }
};

static MD5Tests MD5UnitTests;

#endif


/*
  ==============================================================================

   This file is part of the JUCE library.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   27th April 2017).

   Privacy Policy: www.juce.com/juce-5-privacy-policy

   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

class MD5Generator
{
public:
    MD5Generator() noexcept
    {
        state[0] = 0x67452301;
        state[1] = 0xefcdab89;
        state[2] = 0x98badcfe;
        state[3] = 0x10325476;

        count[0] = 0;
        count[1] = 0;
    }

    void processBlock (const void* data, size_t dataSize) noexcept
    {
        int bufferPos = ((count[0] >> 3) & 0x3F);

        count[0] += (uint32) (dataSize << 3);

        if (count[0] < ((uint32) dataSize << 3))
            count[1]++;

        count[1] += (uint32) (dataSize >> 29);

        const size_t spaceLeft = 64 - (size_t) bufferPos;
        size_t i = 0;

        if (dataSize >= spaceLeft)
        {
            memcpy (buffer + bufferPos, data, spaceLeft);
            transform (buffer);

            for (i = spaceLeft; i + 64 <= dataSize; i += 64)
                transform (static_cast<const char*> (data) + i);

            bufferPos = 0;
        }

        memcpy (buffer + bufferPos, static_cast<const char*> (data) + i, dataSize - i);
    }

    void transform (const void* bufferToTransform) noexcept
    {
        uint32 a = state[0];
        uint32 b = state[1];
        uint32 c = state[2];
        uint32 d = state[3];
        uint32 x[16];

        encode (x, bufferToTransform, 64);

        enum Constants
        {
            S11 = 7, S12 = 12, S13 = 17, S14 = 22, S21 = 5, S22 = 9,  S23 = 14, S24 = 20,
            S31 = 4, S32 = 11, S33 = 16, S34 = 23, S41 = 6, S42 = 10, S43 = 15, S44 = 21
        };

        FF (a, b, c, d, x[ 0], S11, 0xd76aa478);     FF (d, a, b, c, x[ 1], S12, 0xe8c7b756);
        FF (c, d, a, b, x[ 2], S13, 0x242070db);     FF (b, c, d, a, x[ 3], S14, 0xc1bdceee);
        FF (a, b, c, d, x[ 4], S11, 0xf57c0faf);     FF (d, a, b, c, x[ 5], S12, 0x4787c62a);
        FF (c, d, a, b, x[ 6], S13, 0xa8304613);     FF (b, c, d, a, x[ 7], S14, 0xfd469501);
        FF (a, b, c, d, x[ 8], S11, 0x698098d8);     FF (d, a, b, c, x[ 9], S12, 0x8b44f7af);
        FF (c, d, a, b, x[10], S13, 0xffff5bb1);     FF (b, c, d, a, x[11], S14, 0x895cd7be);
        FF (a, b, c, d, x[12], S11, 0x6b901122);     FF (d, a, b, c, x[13], S12, 0xfd987193);
        FF (c, d, a, b, x[14], S13, 0xa679438e);     FF (b, c, d, a, x[15], S14, 0x49b40821);

        GG (a, b, c, d, x[ 1], S21, 0xf61e2562);     GG (d, a, b, c, x[ 6], S22, 0xc040b340);
        GG (c, d, a, b, x[11], S23, 0x265e5a51);     GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa);
        GG (a, b, c, d, x[ 5], S21, 0xd62f105d);     GG (d, a, b, c, x[10], S2


for (i = spaceLeft; i + 64 <= dataSize; i += 64)
                transform (static_cast<const char*> (data) + i);

/*
  ==============================================================================

   This file is part of the JUCE library.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   27th April 2017).

   Privacy Policy: www.juce.com/juce-5-privacy-policy

   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

class MD5Generator
{
public:
    MD5Generator() noexcept
    {
        state[0] = 0x67452301;
        state[1] = 0xefcdab89;
        state[2] = 0x98badcfe;
        state[3] = 0x10325476;

        count[0] = 0;
        count[1] = 0;
    }

    void processBlock (const void* data, size_t dataSize) noexcept
    {
        int bufferPos = ((count[0] >> 3) & 0x3F);

        count[0] += (uint32) (dataSize << 3);

        if (count[0] < ((uint32) dataSize << 3))
            count[1]++;

        count[1] += (uint32) (dataSize >> 29);

        const size_t spaceLeft = 64 - (size_t) bufferPos;
        size_t i = 0;

        if (dataSize >= spaceLeft)
        {
            memcpy (buffer + bufferPos, data, spaceLeft);
            transform (buffer);


while (! t.isEmpty())
    {
        uint32 unicodeChar = ByteOrder::swapIfBigEndian ((uint32) t.getAndAdvance());
        generator.processBlock (&unicodeChar, sizeof (unicodeChar));
    }

/*
  ==============================================================================

   This file is part of the JUCE library.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   27th April 2017).

   Privacy Policy: www.juce.com/juce-5-privacy-policy

   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

class MD5Generator
{
public:
    MD5Generator() noexcept
    {
        state[0] = 0x67452301;
        state[1] = 0xefcdab89;
        state[2] = 0x98badcfe;
        state[3] = 0x10325476;

        count[0] = 0;
        count[1] = 0;
    }

    void processBlock (const void* data, size_t dataSize) noexcept
    {
        int bufferPos = ((count[0] >> 3) & 0x3F);

        count[0] += (uint32) (dataSize << 3);

        if (count[0] < ((uint32) dataSize << 3))
            count[1]++;

        count[1] += (uint32) (dataSize >> 29);

        const size_t spaceLeft = 64 - (size_t) bufferPos;
        size_t i = 0;

        if (dataSize >= spaceLeft)
        {
            memcpy (buffer + bufferPos, data, spaceLeft);
            transform (buffer);

            for (i = spaceLeft; i + 64 <= dataSize; i += 64)
                transform (static_cast<const char*> (data) + i);

            bufferPos = 0;
        }

        memcpy (buffer + bufferPos, static_cast<const char*> (data) + i, dataSize - i);
    }

    void transform (const void* bufferToTransform) noexcept
    {
        uint32 a = state[0];
        uint32 b = state[1];
        uint32 c = state[2];
        uint32 d = state[3];
        uint32 x[16];

        encode (x, bufferToTransform, 64);

        enum Constants
        {
            S11 = 7, S12 = 12, S13 = 17, S14 = 22, S21 = 5, S22 = 9,  S23 = 14, S24 = 20,
            S31 = 4, S32 = 11, S33 = 16, S34 = 23, S41 = 6, S42 = 10, S43 = 15, S44 = 21
        };

        FF (a, b, c, d, x[ 0], S11, 0xd76aa478);     FF (d, a, b, c, x[ 1], S12, 0xe8c7b756);
        FF (c, d, a, b, x[ 2], S13, 0x242070db);     FF (b, c, d, a, x[ 3], S14, 0xc1bdceee);
        FF (a, b, c, d, x[ 4], S11, 0xf57c0faf);     FF (d, a, b, c, x[ 5], S12, 0x4787c62a);
        FF (c, d, a, b, x[ 6], S13, 0xa8304613);     FF (b, c, d, a, x[ 7], S14, 0xfd469501);
        FF (a, b, c, d, x[ 8], S11, 0x698098d8);     FF (d, a, b, c, x[ 9], S12, 0x8b44f7af);
        FF (c, d, a, b, x[10], S13, 0xffff5bb1);     FF (b, c, d, a, x[11], S14, 0x895cd7be);
        FF (a, b, c, d, x[12], S11, 0x6b901122);     FF (d, a, b, c, x[13], S12, 0xfd987193);
        FF (c, d, a, b, x[14], S13, 0xa679438e);     FF (b, c, d, a, x[15], S14, 0x49b40821);

        GG (a, b, c, d, x[ 1], S21, 0xf61e2562);     GG (d, a, b, c, x[ 6], S22, 0xc040b340);
        GG (c, d, a, b, x[11], S23, 0x265e5a51);     GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa);
        GG (a, b, c, d, x[ 5], S21, 0xd62f105d);     GG (d, a, b, c, x[10], S22, 0x02441453);
        GG (c, d, a, b, x[15], S23, 0xd8a1e681);     GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8);
        GG (a, b, c, d, x[ 9], S21, 0x21e1cde6);     GG (d, a, b, c, x[14], S22, 0xc33707d6);
        GG (c, d, a, b, x[ 3], S23, 0xf4d50d87);     GG (b, c, d, a, x[ 8], S24, 0x455a14ed);
        GG (a, b, c, d, x[13], S21, 0xa9e3e905);     GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8);
        GG (c, d, a, b, x[ 7], S23, 0x676f02d9);     GG (b, c, d, a, x[12], S24, 0x8d2a4c8a);

        HH (a, b, c, d, x[ 5], S31, 0xfffa3942);     HH (d, a, b, c, x[ 8], S32, 0x8771f681);
        HH (c, d, a, b, x[11], S33, 0x6d9d6122);     HH (b, c, d, a, x[14], S34, 0xfde5380c);
        HH (a, b, c, d, x[ 1], S31, 0xa4beea44);     HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9);
        HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60);     HH (b, c, d, a, x[10], S34, 0xbebfbc70);
        HH (a, b, c, d, x[13], S31, 0x289b7ec6);     HH (d, a, b, c, x[ 0], S32, 0xeaa127fa);
        HH (c, d, a, b, x[ 3], S33, 0xd4ef3085);     HH (b, c, d, a, x[ 6], S34, 0x04881d05);
        HH (a, b, c, d, x[ 9], S31, 0xd9d4d039);     HH (d, a, b, c, x[12], S32, 0xe6db99e5);
        HH (c, d, a, b, x[15], S33, 0x1fa27cf8);     HH (b, c, d, a, x[ 2], S34, 0xc4ac5665);

        II (a, b, c, d, x[ 0], S41, 0xf4292244);     II (d, a, b, c, x[ 7], S42, 0x432aff97);
        II (c, d, a, b, x[14], S43, 0xab9423a7);     II (b, c, d, a, x[ 5], S44, 0xfc93a039);
        II (a, b, c, d, x[12], S41, 0x655b59c3);     II (d, a, b, c, x[ 3], S42, 0x8f0ccc92);
        II (c, d, a, b, x[10], S43, 0xffeff47d);     II (b, c, d, a, x[ 1], S44, 0x85845dd1);
        II (a, b, c, d, x[ 8], S41, 0x6fa87e4f);     II (d, a, b, c, x[15], S42, 0xfe2ce6e0);
        II (c, d, a, b, x[ 6], S43, 0xa3014314);     II (b, c, d, a, x[13], S44, 0x4e0811a1);
        II (a, b, c, d, x[ 4], S41, 0xf7537e82);     II (d, a, b, c, x[11], S42, 0xbd3af235);
        II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb);     II (b, c, d, a, x[ 9], S44, 0xeb86d391);

        state[0] += a;
        state[1] += b;
        state[2] += c;
        state[3] += d;

        zerostruct (x);
    }

    void finish (void* result) noexcept
    {
        unsigned char encodedLength[8];
        encode (encodedLength, count, 8);

        // Pad out to 56 mod 64.
        const int index = (count[0] >> 3) & 0x3f;

        const int paddingLength = (index < 56) ? (56 - index)
                                               : (120 - index);

        uint8 paddingBuffer[64] = { 0x80 }; // first byte is 0x80, remaining bytes are zero.
        processBlock (paddingBuffer, (size_t) paddingLength);

        processBlock (encodedLength, 8);

        encode (result, state, 16);
        zerostruct (buffer);
    }

private:
    uint8 buffer [64];
    uint32 state [4];
    uint32 count [2];

    static void encode (void* const output, const void* const input, const int numBytes) noexcept
    {
        for (int i = 0; i < (numBytes >> 2); ++i)
            static_cast<uint32*> (output)[i] = ByteOrder::swapIfBigEndian (static_cast<const uint32*> (input) [i]);
    }

    static inline uint32 rotateLeft (const uint32 x, const uint32 n) noexcept          { return (x << n) | (x >> (32 - n)); }

    static inline uint32 F (const uint32 x, const uint32 y, const uint32 z) noexcept   { return (x & y) | (~x & z); }
    static inline uint32 G (const uint32 x, const uint32 y, const uint32 z) noexcept   { return (x & z) | (y & ~z); }
    static inline uint32 H (const uint32 x, const uint32 y, const uint32 z) noexcept   { return x ^ y ^ z; }
    static inline uint32 I (const uint32 x, const uint32 y, const uint32 z) noexcept   { return y ^ (x | ~z); }

    static void FF (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) noexcept
    {
        a += F (b, c, d) + x + ac;
        a = rotateLeft (a, s) + b;
    }

    static void GG (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) noexcept
    {
        a += G (b, c, d) + x + ac;
        a = rotateLeft (a, s) + b;
    }

    static void HH (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) noexcept
    {
        a += H (b, c, d) + x + ac;
        a = rotateLeft (a, s) + b;
    }

    static void II (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) noexcept
    {
        a += I (b, c, d) + x + ac;
        a = rotateLeft (a, s) + b;
    }
};

MD5::MD5() noexcept
{
    zerostruct (result);
}

MD5::MD5 (const MD5& other) noexcept
{
    memcpy (result, other.result, sizeof (result));
}

MD5& MD5::operator= (const MD5& other) noexcept
{
    memcpy (result, other.result, sizeof (result));
    return *this;
}

MD5::MD5 (const MemoryBlock& data) noexcept
{
    processData (data.getData(), data.getSize());
}

MD5::MD5 (const void* data, const size_t numBytes) noexcept
{
    processData (data, numBytes);
}

MD5::MD5 (CharPointer_UTF8 utf8) noexcept
{
    jassert (utf8.getAddress() != nullptr);
    processData (utf8.getAddress(), utf8.sizeInBytes() - 1);
}

MD5 MD5::fromUTF32 (StringRef text)
{
    MD5Generator generator;
    String::CharPointerType t (text.text);

    MD5 m;
    generator.finish (m.result);
    return m;
}

MD5::MD5 (InputStream& input, int64 numBytesToRead)
{
    processStream (input, numBytesToRead);
}

MD5::MD5 (const File& file)
{
    FileInputStream fin (file);

    if (fin.getStatus().wasOk())
        processStream (fin, -1);
    else
        zerostruct (result);
}

MD5::~MD5() noexcept {}

void MD5::processData (const void* data, size_t numBytes) noexcept
{
    MD5Generator generator;
    generator.processBlock (data, numBytes);
    generator.finish (result);
}

void MD5::processStream (InputStream& input, int64 numBytesToRead)
{
    MD5Generator generator;

    if (numBytesToRead < 0)
        numBytesToRead = std::numeric_limits<int64>::max();

    while (numBytesToRead > 0)
    {
        uint8 tempBuffer [512];
        const int bytesRead = input.read (tempBuffer, (int) jmin (numBytesToRead, (int64) sizeof (tempBuffer)));

        if (bytesRead <= 0)
            break;

        numBytesToRead -= bytesRead;
        generator.processBlock (tempBuffer, (size_t) bytesRead);
    }

    generator.finish (result);
}

MemoryBlock MD5::getRawChecksumData() const
{
    return MemoryBlock (result, sizeof (result));
}

String MD5::toHexString() const
{
    return String::toHexString (result, sizeof (result), 0);
}

bool MD5::operator== (const MD5& other) const noexcept   { return memcmp (result, other.result, sizeof (result)) == 0; }
bool MD5::operator!= (const MD5& other) const noexcept   { return ! operator== (other); }

#if JUCE_UNIT_TESTS

class MD5Tests  : public UnitTest
{
public:
    MD5Tests() : UnitTest ("MD5") {}

    void test (const char* input, const char* expected)
    {
        {
            MD5 hash (input, strlen (input));
            expectEquals (hash.toHexString(), String (expected));
        }

        {
            MemoryInputStream m (input, strlen (input), false);
            MD5 hash (m);
            expectEquals (hash.toHexString(), String (expected));
        }
    }

    void runTest() override
    {
        beginTest ("MD5");

        test ("", "d41d8cd98f00b204e9800998ecf8427e");
        test ("The quick brown fox jumps over the lazy dog",  "9e107d9d372bb6826bd81d3542a419d6");
        test ("The quick brown fox jumps over the lazy dog.", "e4d909c290d0fb1ca068ffaddf22cbd0");
    }
};

static MD5Tests MD5UnitTests;

#endif


#include <iostream>
using namespace std;

{

	int i = 10;

	//NOTE: this is how while increments should be done
	while(i-- > 1){
		cout << i << " ";
	}

	cout << endl;
	return 0;
}


{

	int i = 10;

	//NOTE: this is how while increments should be done
	while(i-- > 1){
		cout << i << " ";
	}

	cout << endl;
	return 0;
}

#include <iostream>
using namespace std;

int main()


#include <iostream>
using namespace std;

int main(){

	int i = 10;

	//NOTE: this is how while increments should be done
	while(i-- > 1){
		cout << i << " ";
	}

	cout << endl;
	retu


#include <iostream>
using namespace std;

int main(){

	int i = 10;

	//NOTE: this is how while increments should be done


SpotDriver::SpotDriver(VuEntity *entity) : VuMaster(entity)

/** @file simvudrv.cpp
* Implementation of SimVuDrv.h classes
* sfr: rewrite
*/

#include <vector>

#include "SimDrive.h"
#include "stdhdr.h"
#include "simvudrv.h"
#include "simmover.h"
#include "object.h"
#include "mesg.h"
#include "airframe.h"
#include "aircrft.h"
#include "falcsess.h"

using namespace std;

// useful constants

/** factor from units bubble to send fine updates */
#define FINE_DISTANCE_FACTOR   (0.2f) // % of bubble
/** rough update distance (ft) */
#define ROUGH_DISTANCE_FACTOR  (1.0f) // bubble range

/** number of position updates sent for objects inside fine distance */
#define FINE_POSITIONAL_UPDATES_PER_SEC    (5)
#define FINE_POSITIONAL_UPDATES_PERIOD     (VU_TICS_PER_SECOND / FINE_POSITIONAL_UPDATES_PER_SEC)
/** number of seconds per rough position updates (outside fine, less than rough)*/
#define ROUGH_POSITIONAL_UPDATE_TIME       (2)
#define ROUGH_POSITIONAL_UPDATES_PERIOD    (VU_TICS_PER_SECOND * ROUGH_POSITIONAL_UPDATE_TIME)
/** number of seconds per mandatory position update (outside rough) */
#define MANDATORY_POSITIONAL_UPDATE_TIME   (10)
#define MANDATORY_POSITIONAL_UPDATE_PERIOD (VU_TICS_PER_SECOND*MANDATORY_POSITIONAL_UPDATE_TIME)

/** we predict unit position in current time + prediction period
* the higher this time, smoother updates, but errors get bigger too
*/
#define PREDICTION_PERIOD (VU_TICS_PER_SECOND*MANDATORY_POSITIONAL_UPDATE_TIME/3)

{
    last_time = 0;
    lx = ly = lz = 0;
}

VU_BOOL SpotDriver::ExecModel(VU_TIME)
{
    return TRUE;
}

void SpotDriver::Exec(VU_TIME time)
{
    float dx, dy, dz;

    if (time - last_time > 2000)
    {
        last_time = time;

        dx = vuabs(lx - entity_->XPos());
        dy = vuabs(ly - entity_->YPos());
        dz = vuabs(lz - entity_->ZPos());

        if (dx + dy + dz < 4000)
        {
            if (dx + dy + dz < 1.0)
            {
                entity_->SetDelta(0.0, 0.0, 0.0);

            }
            else
            {
                entity_->SetDelta(0.001F, 0.001F, 0.001F);
            }

            VuMaster::Exec(time);
        }

        lx = entity_->XPos();
        ly = entity_->YPos();
        lz = entity_->ZPos();
    }
}

VU_BOOL SimVuDriver::ExecModel(VU_TIME timestamp)
{
    SimBaseClass *ptr = static_cast<SimBaseClass*>(entity_);
    VU_BOOL retval = (VU_BOOL)(ptr->Exec());
    // sfr: i think this is being called twice (one in vudriver, other here)
    entity_->SetUpdateTime(timestamp);
    return retval;
}

VuMaster::SEND_SCORE SimVuDriver::SendScore(const VuSessionEntity *vs, VU_TIME timeDelta)
{
    // TODO2 implement const functions at FalconSessionEntity
    FalconSessionEntity *localSession = static_cast<FalconSessionEntity*>(vuLocalSessionEntity.get());
    const FalconSessionEntity *targetSession = static_cast<const FalconSessionEntity*>(vs);
    SimBaseClass *pEntity = static_cast<SimBaseClass*>(targetSession->GetPlayerEntity());
    SimMoverClass *entity = static_cast<SimMoverClass*>(entity_);

    // invalid entity or time smaller than fine
    if (
        (timeDelta < FINE_POSITIONAL_UPDATES_PERIOD) or
        (entity->VuState() not_eq VU_MEM_ACTIVE)
        /* or ( not ToleranceReached())*/
    )
    {
        return SEND_SCORE(DONT_SEND, 0.0f);
    }

    // here we are above fine delta
    // fine checks

    // to server, always send fine and out of band
    if (targetSession->Id() == vuLocalGame->OwnerId())
    {
        return SEND_SCORE(SEND_OOB, 0.0f);
    }

    // if entity is in the same group as the player entity, fine OOB
    // for example, player in the same flight
    if (pEntity not_eq NULL)
    {
        CampBaseClass *pCampObj = pEntity->GetCampaignObject();
        CampBaseClass *eCampObj = entity->GetCampaignObject();

        if ((pCampObj not_eq NULL) and (pCampObj == eCampObj))
        {
            return SEND_SCORE(SEND_OOB, 0.0f);
        }
    }

    // if entity is in interest list of a session, send fine
    // TODO make targets interest of entities, like missile and radar stuff
#if FINE_INT

    if (targetSession->HasFineInterest(entity))
    {
        return SEND_SCORE(SEND_OOB, 0.0f);
    }

#endif

    BIG_SCALAR fineDist = entity->EntityType()->bubbleRange_ * FINE_DISTANCE_FACTOR;
    BIG_SCALAR fineDistD2 = fineDist * fineDist;

    // distance from entity to session squared
    BIG_SCALAR sessionD2;

    if (pEntity not_eq NULL)
    {
        // if entity is closer to session entity than fine update distance, send
        BIG_SCALAR x2, y2, z2;
        x2 = entity_->XPos() - pEntity->XPos();
        y2 = entity_->YPos() - pEntity->YPos();
        z2 = entity_->ZPos() - pEntity->ZPos();
        x2 *= x2;
        y2 *= y2;
        z2 *= z2;
        sessionD2 = x2 + y2 + z2;

        if (sessionD2 <= fineDistD2)
        {
            return SEND_SCORE(ENQUEUE_SEND, sessionD2);
        }
    }

    // distance from camera entities squared
    std::vector<BIG_SCALAR> cameraD2 = std::vector<BIG_SCALAR>(targetSession->CameraCount());

    // if entity is close to any of session camera, send
    for (int i = 0; i < targetSession->CameraCount(); ++i)
    {
        VuEntity *ce = targetSession->GetCameraEntity(i);

        if ((ce == NULL) or ce->IsSession())
        {
            continue;
        }

        FalconEntity *cameraEntity = static_cast<FalconEntity*>(ce);

        // session camera has entity... (like flight has a plane)
        if (cameraEntity->HasEntity(entity_))
        {
            // we are using 0 here, which means high priority...
            // should we use SEND_OOB instead?
            return SEND_SCORE(ENQUEUE_SEND, 0.0f);;
        }

        // ... or is close to it
        BIG_SCALAR x2, y2, z2;
        x2 = entity_->XPos() - cameraEntity->XPos();
        x2 *= x2;
        y2 = entity_->YPos() - cameraEntity->YPos();
        y2 *= y2;
        z2 = entity_->ZPos() - cameraEntity->ZPos();
        z2 *= z2;
        cameraD2[i] = x2 + y2 + z2;

        if (cameraD2[i] <= fineDistD2)
        {
            return SEND_SCORE(ENQUEUE_SEND, cameraD2[i]);
        }
    }

    // here we are above fine period but didnt send, check rough

    // not enough time for rough update
    if (timeDelta < ROUGH_POSITIONAL_UPDATES_PERIOD)
    {
        return SEND_SCORE(DONT_SEND, 0.0f);
    }

    // get rough distance squared
    BIG_SCALAR roughDistD2 = entity->EntityType()->bubbleRange_ * ROUGH_DISTANCE_FACTOR;
    roughDistD2 *= roughDistD2;

    // if entity is in rough range of session entity, check rough (distance is already computed)
    if ((pEntity not_eq NULL) and (sessionD2 <= roughDistD2))
    {
        return SEND_SCORE(ENQUEUE_SEND, roughDistD2);
    }

    // if entity is in rough range from any of session camera, send rough (distance already computed)
    for (unsigned int i = 0; i < cameraD2.size(); ++i)
    {
        VuEntity *ce = targetSession->GetCameraEntity(i);

        if ((ce == NULL) or ce->IsSession())
        {
            continue;
        }

        if (cameraD2[i] <= roughDistD2)
        {
            return SEND_SCORE(ENQUEUE_SEND, cameraD2[i]);
        }
    }

    // last, maximum time reached, send out of band
    if (timeDelta > MANDATORY_POSITIONAL_UPDATE_PERIOD)
    {
        return SEND_SCORE(SEND_OOB, 0.0f);
    }

    // no checks passed, dont send
    return SEND_SCORE(DONT_SEND, 0.0f);
}

void SimVuSlave::Exec(VU_TIME timestamp)
{
    // base class call. zero turn speed if interval is greater than fine period
    // avoids infinite turning in case we stop receiving updates from the unit (changed to rough for example)
    if (timestamp > ((lastRemoteUpdateTime_ + FINE_POSITIONAL_UPDATES_PERIOD)))
    {
        d_dryaw_ = d_drpitch_ = d_drroll_ = 0;
    }

    VuDelaySlave::Exec(timestamp);
    // tricles down to all the inheritance classes
    ((SimBaseClass*)entity_)->Exec();
}

VU_ERRCODE SimVuSlave::Handle(VuPositionUpdateEvent *event)
{
    VU_ERRCODE err = VU_SUCCESS;

    if ( not ((SimBaseClass*)entity_)->IsAwake())
    {
        VuDelaySlave::Handle(event);
        entity_->SetUpdateTime(vuxGameTime);
        // if we are not awake - (and also by implication remote)
        // then noexec because we are not actually in the simobjectlist
        NoExec(vuxGameTime);
    }
    else
    {
        VuSessionEntity *localSession = vuLocalSessionEntity.get();
        VuEntity *localEntity = static_cast<FalconSessionEntity*>(localSession)->GetPlayerEntity();

        if (predictedTime_ == 0)
        {
            // just set position, no predictions
            entity_->SetPosition(event->x_, event->y_, event->z_);
            entity_->SetDelta(event->dx_, event->dy_, event->dz_);
            entity_->SetYPR(event->yaw_, event->pitch_, event->roll_);
            VuDelaySlave::Reset();
            predictedTime_ = event->updateTime_;
        }
        // predict
        else
        {
            double px, py, pz;

            // past or almost present event
            if (event->updateTime_ < vuxGameTime + PREDICTION_PERIOD)
            {
                predictedTime_ = vuxGameTime + PREDICTION_PERIOD;
                double dt_ev = GetDT(predictedTime_, event->updateTime_);
                // predicted position in future
                px = (event->x_ + event->dx_ * dt_ev);
                py = (event->y_ + event->dy_ * dt_ev);
                pz = (event->z_ + event->dz_ * dt_ev);
            }
            // far future event, use update as prediction
            else
            {
                predictedTime_ = event->updateTime_;
                // position
                px = (event->x_);
                py = (event->y_);
                pz = (event->z_);
            }

            // set DR speed to reach predicted position in time
            double dt_inv = 1.0f / GetDT(predictedTime_, vuxGameTime);
            SM_SCALAR dx, dy, dz;
            dx = static_cast<SM_SCALAR>((px - drx_) * dt_inv);
            dy = static_cast<SM_SCALAR>((py - dry_) * dt_inv);
            dz = static_cast<SM_SCALAR>((pz - drz_) * dt_inv);

            // speed can never get bigger than 1.5 event speed
            SM_SCALAR drsp = (dx * dx + dy * dy + dz * dz);
            // use *2.25 here because its 1.5 squared
            SM_SCALAR evsp = (event->dx_ * event->dx_ + event->dy_ * event->dy_ + event->dz_ * event->dz_) * 2.25f;

            if (drsp > evsp)
            {
                SM_SCALAR adjFactor = sqrt(evsp / drsp);
                // adjust values so that speed becomes 1.5 event speed
                d_drx_ = adjFactor * dx;
                d_dry_ = adjFactor * dy;
                d_drz_ = adjFactor * dz;
            }
            else
            {
                // under limit, no prob
                d_drx_ = dx;
                d_dry_ = dy;
                d_drz_ = dz;
            }

            // since we dont receive turn speed, we cant predict like position
            // so compute turn speed such that we reach the received position until next update
            SM_SCALAR et[3], pdt[3], ct[3];
            ct[0] = dryaw_;
            ct[1] = drpitch_;
            ct[2] = drroll_;
            et[0] = event->yaw_;
            et[1] = event->pitch_;
            et[2] = event->roll_;

            for (unsigned int i = 0; i < 3; ++i)
            {
                // always below 2PI
                et[i] = fmod(et[i], VU_TWOPI);
                ct[i] = fmod(ct[i], VU_TWOPI);
                SM_SCALAR dist = et[i] - ct[i];

                // if turn too big, go other way around
                if (dist > VU_PI)
                {
                    dist -= VU_TWOPI;
                }
                else if (dist < -VU_PI)
                {
                    dist += VU_TWOPI;
                }

                // speed is dist / time for next update
                // time is the fine update period, in seconds, which is 1 / FINE_POSITIONAL_UPDATES_PER_SEC
                pdt[i] = dist * FINE_POSITIONAL_UPDATES_PER_SEC;
            }

            d_dryaw_ = pdt[0];
            d_drpitch_ = pdt[1];
            d_drroll_ = pdt[2];
        }

        lastRemoteUpdateTime_ = vuxGameTime;//event->updateTime_;
        err = VU_SUCCESS;
    }

    return err;
}


{
    SimBaseClass *ptr = static_cast<SimBaseClass*>(entity_);
    VU_BOOL retval = (VU_BOOL)(ptr->Exec());
    // sfr: i think this is being called twice (one in vudriver, other here)
    entity_->SetUpdateTime(timestamp);
    return retval;
}

/** @file simvudrv.cpp
* Implementation of SimVuDrv.h classes
* sfr: rewrite
*/

#include <vector>

#include "SimDrive.h"
#include "stdhdr.h"
#include "simvudrv.h"
#include "simmover.h"
#include "object.h"
#include "mesg.h"
#include "airframe.h"
#include "aircrft.h"
#include "falcsess.h"

using namespace std;

// useful constants

/** factor from units bubble to send fine updates */
#define FINE_DISTANCE_FACTOR   (0.2f) // % of bubble
/** rough update distance (ft) */
#define ROUGH_DISTANCE_FACTOR  (1.0f) // bubble range

/** number of position updates sent for objects inside fine distance */
#define FINE_POSITIONAL_UPDATES_PER_SEC    (5)
#define FINE_POSITIONAL_UPDATES_PERIOD     (VU_TICS_PER_SECOND / FINE_POSITIONAL_UPDATES_PER_SEC)
/** number of seconds per rough position updates (outside fine, less than rough)*/
#define ROUGH_POSITIONAL_UPDATE_TIME       (2)
#define ROUGH_POSITIONAL_UPDATES_PERIOD    (VU_TICS_PER_SECOND * ROUGH_POSITIONAL_UPDATE_TIME)
/** number of seconds per mandatory position update (outside rough) */
#define MANDATORY_POSITIONAL_UPDATE_TIME   (10)
#define MANDATORY_POSITIONAL_UPDATE_PERIOD (VU_TICS_PER_SECOND*MANDATORY_POSITIONAL_UPDATE_TIME)

/** we predict unit position in current time + prediction period
* the higher this time, smoother updates, but errors get bigger too
*/
#define PREDICTION_PERIOD (VU_TICS_PER_SECOND*MANDATORY_POSITIONAL_UPDATE_TIME/3)

SpotDriver::SpotDriver(VuEntity *entity) : VuMaster(entity)
{
    last_time = 0;
    lx = ly = lz = 0;
}

VU_BOOL SpotDriver::ExecModel(VU_TIME)
{
    return TRUE;
}

void SpotDriver::Exec(VU_TIME time)
{
    float dx, dy, dz;

    if (time - last_time > 2000)
    {
        last_time = time;

        dx = vuabs(lx - entity_->XPos());
        dy = vuabs(ly - entity_->YPos());
        dz = vuabs(lz - entity_->ZPos());

        if (dx + dy + dz < 4000)
        {
            if (dx + dy + dz < 1.0)
            {
                entity_->SetDelta(0.0, 0.0, 0.0);

            }
            else
            {
                entity_->SetDelta(0.001F, 0.001F, 0.001F);
            }

            VuMaster::Exec(time);
        }

        lx = entity_->XPos();
        ly = entity_->YPos();
        lz = entity_->ZPos();
    }
}

VU_BOOL SimVuDriver::ExecModel(VU_TIME timestamp)

VuMaster::SEND_SCORE SimVuDriver::SendScore(const VuSessionEntity *vs, VU_TIME timeDelta)
{
    // TODO2 implement const functions at FalconSessionEntity
    FalconSessionEntity *localSession = static_cast<FalconSessionEntity*>(vuLocalSessionEntity.get());
    const FalconSessionEntity *targetSession = static_cast<const FalconSessionEntity*>(vs);
    SimBaseClass *pEntity = static_cast<SimBaseClass*>(targetSession->GetPlayerEntity());
    SimMoverClass *entity = static_cast<SimMoverClass*>(entity_);

    // invalid entity or time smaller than fine
    if (
        (timeDelta < FINE_POSITIONAL_UPDATES_PERIOD) or
        (entity->VuState() not_eq VU_MEM_ACTIVE)
        /* or ( not ToleranceReached())*/
    )
    {
        return SEND_SCORE(DONT_SEND, 0.0f);
    }

    // here we are above fine delta
    // fine checks

    // to server, always send fine and out of band
    if (targetSession->Id() == vuLocalGame->OwnerId())
    {
        return SEND_SCORE(SEND_OOB, 0.0f);
    }

    // if entity is in the same group as the player entity, fine OOB
    // for example, player in the same flight
    if (pEntity not_eq NULL)
    {
        CampBaseClass *pCampObj = pEntity->GetCampaignObject();
        CampBaseClass *eCampObj = entity->GetCampaignObject();

        if ((pCampObj not_eq NULL) and (pCampObj == eCampObj))
        {
            return SEND_SCORE(SEND_OOB, 0.0f);
        }
    }

    // if entity is in interest list of a session, send fine
    // TODO make targets interest of entities, like missile and radar stuff
#if FINE_INT

    if (targetSession->HasFineInterest(entity))
    {
        return SEND_SCORE(SEND_OOB, 0.0f);
    }

#endif

    BIG_SCALAR fineDist = entity->EntityType()->bubbleRange_ * FINE_DISTANCE_FACTOR;
    BIG_SCALAR fineDistD2 = fineDist * fineDist;

    // distance from entity to session squared
    BIG_SCALAR sessionD2;

    if (pEntity not_eq NULL)
    {
        // if entity is closer to session entity than fine update distance, send
        BIG_SCALAR x2, y2, z2;
        x2 = entity_->XPos() - pEntity->XPos();
        y2 = entity_->YPos() - pEntity->YPos();
        z2 = entity_->ZPos() - pEntity->ZPos();
        x2 *= x2;
        y2 *= y2;
        z2 *= z2;
        sessionD2 = x2 + y2 + z2;

        if (sessionD2 <= fineDistD2)
        {
            return SEND_SCORE(ENQUEUE_SEND, sessionD2);
        }
    }

    // distance from camera entities squared
    std::vector<BIG_SCALAR> cameraD2 = std::vector<BIG_SCALAR>(targetSession->CameraCount());

    // if entity is close to any of session camera, send
    for (int i = 0; i < targetSession->CameraCount(); ++i)
    {
        VuEntity *ce = targetSession->GetCameraEntity(i);

        if ((ce == NULL) or ce->IsSession())
        {
            continue;
        }

        FalconEntity *cameraEntity = static_cast<FalconEntity*>(ce);

        // session camera has entity... (like flight has a plane)
        if (cameraEntity->HasEntity(entity_))
        {
            // we are using 0 here, which means high priority...
            // should we use SEND_OOB instead?
            return SEND_SCORE(ENQUEUE_SEND, 0.0f);;
        }

        // ... or is close to it
        BIG_SCALAR x2, y2, z2;
        x2 = entity_->XPos() - cameraEntity->XPos();
        x2 *= x2;
        y2 = entity_->YPos() - cameraEntity->YPos();
        y2 *= y2;
        z2 = entity_->ZPos() - cameraEntity->ZPos();
        z2 *= z2;
        cameraD2[i] = x2 + y2 + z2;

        if (cameraD2[i] <= fineDistD2)
        {
            return SEND_SCORE(ENQUEUE_SEND, cameraD2[i]);
        }
    }

    // here we are above fine period but didnt send, check rough

    // not enough time for rough update
    if (timeDelta < ROUGH_POSITIONAL_UPDATES_PERIOD)
    {
        return SEND_SCORE(DONT_SEND, 0.0f);
    }

    // get rough distance squared
    BIG_SCALAR roughDistD2 = entity->EntityType()->bubbleRange_ * ROUGH_DISTANCE_FACTOR;
    roughDistD2 *= roughDistD2;

    // if entity is in rough range of session entity, check rough (distance is already computed)
    if ((pEntity not_eq NULL) and (sessionD2 <= roughDistD2))
    {
        return SEND_SCORE(ENQUEUE_SEND, roughDistD2);
    }

    // if entity is in rough range from any of session camera, send rough (distance already computed)
    for (unsigned int i = 0; i < cameraD2.size(); ++i)
    {
        VuEntity *ce = targetSession->GetCameraEntity(i);

        if ((ce == NULL) or ce->IsSession())
        {
            continue;
        }

        if (cameraD2[i] <= roughDistD2)
        {
            return SEND_SCORE(ENQUEUE_SEND, cameraD2[i]);
        }
    }

    // last, maximum time reached, send out of band
    if (timeDelta > MANDATORY_POSITIONAL_UPDATE_PERIOD)
    {
        return SEND_SCORE(SEND_OOB, 0.0f);
    }

    // no checks passed, dont send
    return SEND_SCORE(DONT_SEND, 0.0f);
}

void SimVuSlave::Exec(VU_TIME timestamp)
{
    // base class call. zero turn speed if interval is greater than fine period
    // avoids infinite turning in case we stop receiving updates from the unit (changed to rough for example)
    if (timestamp > ((lastRemoteUpdateTime_ + FINE_POSITIONAL_UPDATES_PERIOD)))
    {
        d_dryaw_ = d_drpitch_ = d_drroll_ = 0;
    }

    VuDelaySlave::Exec(timestamp);
    // tricles down to all the inheritance classes
    ((SimBaseClass*)entity_)->Exec();
}

VU_ERRCODE SimVuSlave::Handle(VuPositionUpdateEvent *event)
{
    VU_ERRCODE err = VU_SUCCESS;

    if ( not ((SimBaseClass*)entity_)->IsAwake())
    {
        VuDelaySlave::Handle(event);
        entity_->SetUpdateTime(vuxGameTime);
        // if we are not awake - (and also by implication remote)
        // then noexec because we are not actually in the simobjectlist
        NoExec(vuxGameTime);
    }
    else
    {
        VuSessionEntity *localSession = vuLocalSessionEntity.get();
        VuEntity *localEntity = static_cast<FalconSessionEntity*>(localSession)->GetPlayerEntity();

        if (predictedTime_ == 0)
        {
            // just set position, no predictions
            entity_->SetPosition(event->x_, event->y_, event->z_);
            entity_->SetDelta(event->dx_, event->dy_, event->dz_);
            entity_->SetYPR(event->yaw_, event->pitch_, event->roll_);
            VuDelaySlave::Reset();
            predictedTime_ = event->updateTime_;
        }
        // predict
        else
        {
            double px, py, pz;

            // past or almost present event
            if (event->updateTime_ < vuxGameTime + PREDICTION_PERIOD)
            {
                predictedTime_ = vuxGameTime + PREDICTION_PERIOD;
                double dt_ev = GetDT(predictedTime_, event->updateTime_);
                // predicted position in future
                px = (event->x_ + event->dx_ * dt_ev);
                py = (event->y_ + event->dy_ * dt_ev);
                pz = (event->z_ + event->dz_ * dt_ev);
            }
            // far future event, use update as prediction
            else
            {
                predictedTime_ = event->updateTime_;
                // position
                px = (event->x_);
                py = (event->y_);
                pz = (event->z_);
            }

            // set DR speed to reach predicted position in time
            double dt_inv = 1.0f / GetDT(predictedTime_, vuxGameTime);
            SM_SCALAR dx, dy, dz;
            dx = static_cast<SM_SCALAR>((px - drx_) * dt_inv);
            dy = static_cast<SM_SCALAR>((py - dry_) * dt_inv);
            dz = static_cast<SM_SCALAR>((pz - drz_) * dt_inv);

            // speed can never get bigger than 1.5 event speed
            SM_SCALAR drsp = (dx * dx + dy * dy + dz * dz);
            // use *2.25 here because its 1.5 squared
            SM_SCALAR evsp = (event->dx_ * event->dx_ + event->dy_ * event->dy_ + event->dz_ * event->dz_) * 2.25f;

            if (drsp > evsp)
            {
                SM_SCALAR adjFactor = sqrt(evsp / drsp);
                // adjust values so that speed becomes 1.5 event speed
                d_drx_ = adjFactor * dx;
                d_dry_ = adjFactor * dy;
                d_drz_ = adjFactor * dz;
            }
            else
            {
                // under limit, no prob
                d_drx_ = dx;
                d_dry_ = dy;
                d_drz_ = dz;
            }

            // since we dont receive turn speed, we cant predict like position
            // so compute turn speed such that we reach the received position until next update
            SM_SCALAR et[3], pdt[3], ct[3];
            ct[0] = dryaw_;
            ct[1] = drpitch_;
            ct[2] = drroll_;
            et[0] = event->yaw_;
            et[1] = event->pitch_;
            et[2] = event->roll_;

            for (unsigned int i = 0; i < 3; ++i)
            {
                // always below 2PI
                et[i] = fmod(et[i], VU_TWOPI);
                ct[i] = fmod(ct[i], VU_TWOPI);
                SM_SCALAR dist = et[i] - ct[i];

                // if turn too big, go other way around
                if (dist > VU_PI)
                {
                    dist -= VU_TWOPI;
                }
                else if (dist < -VU_PI)
                {
                    dist += VU_TWOPI;
                }

                // speed is dist / time for next update
                // time is the fine update period, in seconds, which is 1 / FINE_POSITIONAL_UPDATES_PER_SEC
                pdt[i] = dist * FINE_POSITIONAL_UPDATES_PER_SEC;
            }

            d_dryaw_ = pdt[0];
            d_drpitch_ = pdt[1];
            d_drroll_ = pdt[2];
        }

        lastRemoteUpdateTime_ = vuxGameTime;//event->updateTime_;
        err = VU_SUCCESS;
    }

    return err;
}