text:
/********************************************************************************
 * Copyright 2009 The Robotics Group, The Maersk Mc-Kinney Moller Institute,
 * Faculty of Engineering, University of Southern Denmark
 *
 * 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.
 ********************************************************************************/

#include "IOUtil.hpp"

#include "Log.hpp"
#include "Message.hpp"
#include "StringUtil.hpp"
#include "macros.hpp"

#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/version.hpp>
#include <fstream>
#include <iostream>
#if (BOOST_VERSION < 104100)
#include <boost/spirit/include/classic.hpp>
#include <boost/spirit/include/classic_ast.hpp>
#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_parse_tree.hpp>
#include <boost/spirit/include/classic_position_iterator.hpp>
#include <boost/spirit/include/classic_symbols.hpp>
#include <boost/spirit/include/phoenix1.hpp>
#include <boost/spirit/iterator/file_iterator.hpp>

#else
//#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/spirit/include/qi.hpp>
#endif

#include <boost/bind.hpp>
//#include <boost/lambda/lambda.hpp>

//#include <cassert>
//#include <algorithm>
#include <regex>

#if !(defined __MINGW32__) && !(defined _WIN32)
#include <unistd.h>    // for getcwd on linux
#endif
#ifdef _WIN32
#include <direct.h>    // for getcwd
#endif

using namespace rw::core;

void IOUtil::readFile (const std::string& file_name, std::vector< char >& result)
{
    std::ifstream inp (file_name.c_str (), std::ios::binary);

    // Check input.
    if (!inp.is_open ())
        RW_THROW ("Can't read file " << StringUtil::quote (file_name));

    // The file length.
    inp.seekg (0, std::ios::end);
    const int len = (int) inp.tellg ();

    inp.seekg (0, std::ios::beg);

    // The buffer.
    result.resize (len);

    // Read the file.
    inp.read (&result.front (), len);

    // Check if we succeeded.
    if (inp.bad ())
        RW_THROW ("Reading of file " << StringUtil::quote (file_name) << " failed.");

    // Close the file.
    inp.close ();
}

namespace {
std::string intersperse (const std::vector< std::string >& vals, const std::string& sep)
{
    std::stringstream sum;
    typedef std::vector< std::string >::const_iterator I;

    I p = vals.begin ();
    if (p != vals.end ())
        sum << *p;

    for (++p; p != vals.end (); ++p) {
        sum << sep << *p;
    }

    return sum.str ();
}

bool isReadable (const std::string& file)
{
    std::ifstream in (file.c_str ());
    return in.is_open ();
}

std::string resolveSuffix (const std::string& raw_filename, const std::string& suffix)
{
    const std::string& v1 = raw_filename + suffix;
    const std::string& v2 = raw_filename + StringUtil::toLower (suffix);
    const std::string& v3 = raw_filename + StringUtil::toUpper (suffix);

    return isReadable (v1) ? v1 : isReadable (v2) ? v2 : isReadable (v3) ? v3 : "";
}

std::string resolveFileNameHelper (const std::string& raw_filename,
                                   const std::vector< std::string >& extensions)
{
    typedef std::vector< std::string >::const_iterator I;
    for (I p = extensions.begin (); p != extensions.end (); ++p) {
        const std::string& file = resolveSuffix (raw_filename, *p);
        if (!file.empty ())
            return file;
    }
    return "";
}
}    // namespace

std::string IOUtil::resolveFileName (const std::string& raw_filename,
                                     const std::vector< std::string >& extensions)
{
    // First check the raw file name.
    std::ifstream in (raw_filename.c_str ());
    if (in.is_open ()) {
        return raw_filename;
    }

    // Then check with suffixes.
    const std::string& file = resolveFileNameHelper (raw_filename, extensions);

    if (!file.empty ()) {
        return file;
    }
    else {
        // Throw a nice exception.
        RW_THROW ("Can't open file "
                  << StringUtil::quote (raw_filename)
                  << ". Optional extensions considered: " << intersperse (extensions, " "));

        // To avoid a compiler warning.
        return "";
    }
}

void IOUtil::rwAssert (const char* expression, const char* file, int line)
{
    Message msg (file, line, expression);
    Log::errorLog ().write (msg);
    Log::errorLog () << std::endl;
    // exit(-1);
    abort ();
}

std::string IOUtil::getAbsoluteFileName (const std::string& file)
{
    if (StringUtil::isAbsoluteFileName (file)) {
        return file;
    }
    // prepend the working directory
    char buffer[500];

    char* res = NULL;
    // Previously this was called without the _. This however should be more compliant with ISO C++
    // (according to Visual Studio)
#ifdef _MSC_VER
    res = _getcwd (buffer, 500);
#else
    res = getcwd (buffer, 500);
#endif
    if (res == NULL)
        RW_THROW ("Absolute filename could not be derived, for file: " << file);
    std::string workDir (buffer);
    return workDir + "/" + file;
}

bool IOUtil::isLittleEndian ()
{
    union
    {
        int testWord;
        char testByte[4];
    } endianTest;

    endianTest.testWord = 1;
    if (endianTest.testByte[0] == 1) {
        // litle endian - least significant byte first
        return true;
    }
    return false;
}

void IOUtil::getFilesInFolder (const std::string& path, const std::string& fileMask, bool recursive,
                               bool addPath, std::vector< std::string >& result)
{
    try {
        // Depending on how string has been generated boost::replace_all sometimes fails.
        // A fix of this is to convert it with c_str().
        std::string regStr = fileMask.c_str ();

        boost::replace_all (regStr, "\\", "\\\\");
        boost::replace_all (regStr, ".", "\\.");
        boost::replace_all (regStr, "*", ".*");
        boost::replace_all (regStr, "(", "\\(");
        boost::replace_all (regStr, ")", "\\)");
        boost::replace_all (regStr, "+", "\\+");

        const std::regex regex (regStr);
        std::cmatch match;

        boost::filesystem::directory_iterator end;
        for (boost::filesystem::directory_iterator it (path); it != end; it++) {
            if (boost::filesystem::is_directory (it->status ())) {
                if (recursive)
                    getFilesInFolder (it->path ().string (), fileMask, recursive, addPath, result);
                continue;
            }

            if (!boost::filesystem::is_regular_file (it->status ()))    // If not a regular file
                continue;
#if (BOOST_FILESYSTEM_VERSION == 2)
            std::string filename = it->path ().filename ();
#else
            std::string filename = it->path ().filename ().string ();
#endif
            if (!std::regex_match (filename.c_str (), match, regex))
                continue;

            if (addPath)
                result.push_back (it->path ().string ());
            else {
#if (BOOST_FILESYSTEM_VERSION == 2)
                result.push_back (it->path ().filename ());
#else
                result.push_back (it->path ().filename ().string ());
#endif
            }
        }
    }
    catch (const std::exception& e) {
        RW_THROW ("Unable to retrieve files in folder: " << e.what ());
    }
}

std::vector< std::string > IOUtil::getFilesInFolder (const std::string& path, bool recursive,
                                                     bool addPath, const std::string& fileMask)
{
    std::vector< std::string > result;
    getFilesInFolder (path, fileMask, recursive, addPath, result);
    return result;
}

size_t IOUtil::getFileSize (const std::string& filename)
{
    namespace fs = boost::filesystem;
    fs::path p (filename);
    return (size_t) fs::file_size (p);
}

std::time_t IOUtil::getLastFileWrite (const std::string& filename)
{
    namespace fs = boost::filesystem;
    fs::path p (filename);
    std::time_t ft = fs::last_write_time (p);
    return ft;
}

std::string IOUtil::getFirstXMLElement (const std::string& filename)
{
    using namespace boost;

#if (BOOST_VERSION < 104100)
    using namespace boost::spirit;
    using namespace boost::spirit::classic;
    using namespace phoenix;

    file_iterator<> first (filename.c_str ());

    if (!first) {
        // Clean up, throw an exception, whatever
        RW_THROW ("Unable to open file!\n");
    }

    file_iterator<> last = first.make_end ();

    std::string result;
    // use iterator to parse file data
    parse_info< file_iterator< char > > info = parse (
        first,
        last,
        !("<?" >> *(anychar_p - '>')    //[std::cout << boost::lambda::_1]
          >> '>') >>
            "<"
            //>> *( (anychar_p - '>') | (anychar_p -' '))[boost::bind(static_cast<std::string&
            //(std::string::*)( size_t, char )>(&std::string::append),&result, 1, ::_1)]
            >> *((anychar_p - '>') |
                 (anychar_p - ' '))[var (result) = construct_< std::string > (arg1, arg2)] >>
            *(anychar_p - '>')    //[std::cout << boost::lambda::_1]
            >> ">"
        // THE skip parser comes next
        ,
        (blank_p - ' ') | (space_p - ' ') | ("<!--" >> *(anychar_p - '>') >> '>')

    );
    if (!info.hit)
        RW_THROW ("file \"" << filename << "\" is not a wellformed xml document!");
    return result;

#else
    using namespace boost::spirit::qi;
    // check the first element of the file
    std::ifstream input (filename.c_str ());
    input.unsetf (std::ios::skipws);

    spirit::istream_iterator begin (input);
    spirit::istream_iterator end;
    std::string result;
    // use iterator to parse file data
    bool res = spirit::qi::phrase_parse (
        begin,
        end,
        -("<?" >> *(char_ - '>') /*[std::cout << boost::lambda::_1]*/ >> char_ ('>')) >> "<" >>
            *(char_ - (char_ ('>')))[boost::bind (
                static_cast< std::string& (std::string::*) (size_t, char) > (&std::string::append),
                &result,
                1,
                ::_1)] >>
            *(char_ - char_ ('>')) /*[std::cout << boost::lambda::_1]*/ >> ">"
        // THE skip parser comes next
        ,
        spirit::qi::blank | spirit::qi::space | ("<!--" >> *(char_ - '>') >> '>')

    );
    if (!res)
        RW_THROW ("file \"" << filename << "\" is not a wellformed xml document! " << result);
    return result;
#endif
}

std::string IOUtil::getFirstXMLElement (std::istream& inputStream)
{
    using namespace boost;

#if (BOOST_VERSION < 104100)
#warning Your boost version is not new enough
    RW_THROW ("Your boost version is not new enough!");
#else
    using namespace boost::spirit::qi;
    inputStream.unsetf (std::ios::skipws);

    spirit::istream_iterator begin (inputStream);
    spirit::istream_iterator end;
    std::string result;
    // use iterator to parse file data
    bool res = spirit::qi::phrase_parse (
        begin,
        end,
        -("<?" >> *(char_ - '>') /*[std::cout << boost::lambda::_1]*/ >> char_ ('>')) >> "<" >>
            *(char_ - (char_ ('>')))[boost::bind (
                static_cast< std::string& (std::string::*) (size_t, char) > (&std::string::append),
                &result,
                1,
                ::_1)] >>
            *(char_ - char_ ('>')) /*[std::cout << boost::lambda::_1]*/ >> ">"
        // THE skip parser comes next
        ,
        spirit::qi::blank | spirit::qi::space | ("<!--" >> *(char_ - '>') >> '>')

    );
    if (!res)
        RW_THROW ("The provided ifstream does not consist of a wellformed xml document! "
                  << result);
    return result;
#endif
}


text:
// Copyright (c) 2017-2018 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "services/assetallocation.h"
#include "services/asset.h"
#include "init.h"
#include "validation.h"
#include "txmempool.h"
#include "util.h"
#include "random.h"
#include "base58.h"
#include "core_io.h"
#include "rpc/server.h"
#include "wallet/wallet.h"
#include "chainparams.h"
#include "wallet/coincontrol.h"
#include <boost/algorithm/hex.hpp>
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/algorithm/string.hpp>
#include <future>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <key_io.h>
#include <bech32.h>
using namespace std;
using namespace boost::multiprecision;
AssetAllocationIndexItemMap AssetAllocationIndex;
AssetBalanceMap mempoolMapAssetBalances;
ArrivalTimesMapImpl arrivalTimesMap;
bool IsAssetAllocationOp(int op) {
	return op == OP_ASSET_ALLOCATION_SEND || op == OP_ASSET_ALLOCATION_BURN;
}
string CAssetAllocationTuple::ToString() const {
	return boost::lexical_cast<string>(nAsset) + "-" + GetAddressString();
}
string CAssetAllocationTuple::GetAddressString() const {
	if (vchAddress.size() <= 4 && stringFromVchUint8(vchAddress) == "burn")
		return "burn";
	else
		return bech32::Encode(Params().Bech32HRP(), vchAddress);
}
string assetAllocationFromOp(int op) {
    switch (op) {
	case OP_ASSET_SEND:
		return "assetsend";
	case OP_ASSET_ALLOCATION_SEND:
		return "assetallocationsend";
	case OP_ASSET_ALLOCATION_BURN:
		return "assetallocationburn";
    default:
        return "<unknown assetallocation op>";
    }
}
bool CAssetAllocation::UnserializeFromData(const vector<unsigned char> &vchData) {
    try {
        CDataStream dsAsset(vchData, SER_NETWORK, PROTOCOL_VERSION);
        dsAsset >> *this;
    } catch (std::exception &e) {
		SetNull();
        return false;
    }
	return true;
}
bool CAssetAllocation::UnserializeFromTx(const CTransaction &tx) {
	vector<unsigned char> vchData;
	int nOut, op;
	if (!GetSyscoinData(tx, vchData, nOut, op) || op != OP_SYSCOIN_ASSET_ALLOCATION)
	{
		SetNull();
		return false;
	}
	if(!UnserializeFromData(vchData))
	{
		return false;
	}
    return true;
}
void CAssetAllocation::Serialize( vector<unsigned char> &vchData) {
    CDataStream dsAsset(SER_NETWORK, PROTOCOL_VERSION);
    dsAsset << *this;
	vchData = vector<unsigned char>(dsAsset.begin(), dsAsset.end());

}
void CAssetAllocationDB::WriteAssetAllocationIndex(const CAssetAllocation& assetallocation, const uint256 &txHash, int nHeight, const CAsset& asset, const CAmount& nSenderBalance, const CAmount& nAmount, const std::string& strSender) {
	if (gArgs.IsArgSet("-zmqpubassetallocation") || fAssetAllocationIndex) {
		UniValue oName(UniValue::VOBJ);
		bool isMine = true;
        const string& strReceiver = assetallocation.assetAllocationTuple.GetAddressString();
		if (BuildAssetAllocationIndexerJson(assetallocation, asset, nSenderBalance, nAmount, strSender, strReceiver, isMine, oName)) {
			const string& strObj = oName.write();
			GetMainSignals().NotifySyscoinUpdate(strObj.c_str(), "assetallocation");
			if (isMine && fAssetAllocationIndex) {
				const string& strKey = txHash.GetHex()+"-"+boost::lexical_cast<string>(asset.nAsset)+"-"+ strSender +"-"+ strReceiver;
				{
					LOCK2(mempool.cs, cs_assetallocationindex);
					// we want to the height from mempool if it exists or use the one passed in
					CTxMemPool::txiter it = mempool.mapTx.find(txHash);
					if (it != mempool.mapTx.end())
						nHeight = (*it).GetHeight();
					AssetAllocationIndex[nHeight][strKey] = strObj;
				}
			}
		}
	}

}
bool GetAssetAllocation(const CAssetAllocationTuple &assetAllocationTuple, CAssetAllocation& txPos) {
    if (passetallocationdb == nullptr || !passetallocationdb->ReadAssetAllocation(assetAllocationTuple, txPos))
        return false;
    return true;
}
bool DecodeAndParseAssetAllocationTx(const CTransaction& tx, int& op,
		vector<vector<unsigned char> >& vvch, char &type)
{
	CAssetAllocation assetallocation;
	// parse asset allocation, if not try to parse asset
	bool decode = DecodeAssetAllocationTx(tx, op, vvch)? true: DecodeAssetTx(tx, op, vvch);
	bool parse = assetallocation.UnserializeFromTx(tx);
	if (decode&&parse) {
		type = OP_SYSCOIN_ASSET_ALLOCATION;
		return true;
	}
	return false;
}
bool DecodeAssetAllocationTx(const CTransaction& tx, int& op,
        vector<vector<unsigned char> >& vvch) {
    bool found = false;

    // Strict check - bug disallowed
    for (unsigned int i = 0; i < tx.vout.size(); i++) {
        const CTxOut& out = tx.vout[i];
        vector<vector<unsigned char> > vvchRead;
        if (DecodeAssetAllocationScript(out.scriptPubKey, op, vvchRead)) {
            found = true; vvch = vvchRead;
            break;
        }
    }
    if (!found) vvch.clear();
    return found;
}

bool DecodeAssetAllocationScript(const CScript& script, int& op,
        vector<vector<unsigned char> > &vvch, CScript::const_iterator& pc) {
    opcodetype opcode;
	vvch.clear();
    if (!script.GetOp(pc, opcode)) return false;
    if (opcode < OP_1 || opcode > OP_16) return false;
    op = CScript::DecodeOP_N(opcode);
	if (op != OP_SYSCOIN_ASSET_ALLOCATION)
		return false;
	if (!script.GetOp(pc, opcode))
		return false;
	if (opcode < OP_1 || opcode > OP_16)
		return false;
	op = CScript::DecodeOP_N(opcode);
	if (!IsAssetAllocationOp(op))
		return false;

	bool found = false;
	for (;;) {
		vector<unsigned char> vch;
		if (!script.GetOp(pc, opcode, vch))
			return false;
		if (opcode == OP_DROP || opcode == OP_2DROP)
		{
			found = true;
			break;
		}
		if (!(opcode >= 0 && opcode <= OP_PUSHDATA4))
			return false;
		vvch.emplace_back(std::move(vch));
	}

	// move the pc to after any DROP or NOP
	while (opcode == OP_DROP || opcode == OP_2DROP) {
		if (!script.GetOp(pc, opcode))
			break;
	}

	pc--;
	return found;
}
bool DecodeAssetAllocationScript(const CScript& script, int& op,
        vector<vector<unsigned char> > &vvch) {
    CScript::const_iterator pc = script.begin();
    return DecodeAssetAllocationScript(script, op, vvch, pc);
}
bool RemoveAssetAllocationScriptPrefix(const CScript& scriptIn, CScript& scriptOut) {
    int op;
    vector<vector<unsigned char> > vvch;
    CScript::const_iterator pc = scriptIn.begin();

    if (!DecodeAssetAllocationScript(scriptIn, op, vvch, pc))
		return false;
	scriptOut = CScript(pc, scriptIn.end());
	return true;
}

bool ResetAssetAllocation(const CAssetAllocationTuple &assetAllocationToRemove,  const uint256 &txHash, const bool &bMiner=false) {

    if(!bMiner){
        const string& receiverStr = assetAllocationToRemove.ToString();
        {
            LOCK(cs_assetallocationarrival);
        	// remove the conflict once we revert since it is assumed to be resolved on POW
        	ArrivalTimesMap &arrivalTimes = arrivalTimesMap[receiverStr];

        	bool removeAllConflicts = true;
        	// remove only if all arrival times are either expired (30 mins) or no more zdag transactions left for this sender
        	for(auto& arrivalTime: arrivalTimes){
        		if((chainActive.Tip()->GetMedianTimePast() - arrivalTime.second) <= 1800000){
        			removeAllConflicts = false;
        			break;
        		}
        	}
        	if(removeAllConflicts){
                arrivalTimesMap.erase(receiverStr);
                sorted_vector<string>::const_iterator it = assetAllocationConflicts.find(receiverStr);
                if (it != assetAllocationConflicts.end()) {
                    assetAllocationConflicts.V.erase(const_iterator_cast(assetAllocationConflicts.V, it));
                }
        	}
            else
                arrivalTimes.erase(txHash);
        }
    }

	return true;

}

bool CheckAssetAllocationInputs(const CTransaction &tx, const CCoinsViewCache &inputs, int op, const vector<vector<unsigned char> > &vvchArgs,
        bool fJustCheck, int nHeight, AssetAllocationMap &mapAssetAllocations, AssetBalanceMap &blockMapAssetBalances, string &errorMessage, bool bSanityCheck, bool bMiner) {
    if (passetallocationdb == nullptr)
		return false;
	const uint256 & txHash = tx.GetHash();
	if (!bSanityCheck)
		LogPrint(BCLog::SYS,"*** ASSET ALLOCATION %d %d %s %s\n", nHeight,
			chainActive.Tip()->nHeight, txHash.ToString().c_str(),
			fJustCheck ? "JUSTCHECK" : "BLOCK");

	// unserialize assetallocation from txn, check for valid
	CAssetAllocation theAssetAllocation;
	vector<unsigned char> vchData;
	int nDataOut, tmpOp;
	if(!GetSyscoinData(tx, vchData, nDataOut, tmpOp) || tmpOp != OP_SYSCOIN_ASSET_ALLOCATION || !theAssetAllocation.UnserializeFromData(vchData))
	{
		errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR ERRCODE: 1001 - " + _("Cannot unserialize data inside of this transaction relating to an assetallocation");
		return error(errorMessage.c_str());
	}

	if(fJustCheck)
	{
		if(op == OP_ASSET_ALLOCATION_BURN && vvchArgs.size() != 3)
		{
			errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1002 - " + _("Asset arguments incorrect size");
			return error(errorMessage.c_str());
		}

	}
	string retError = "";
	if(fJustCheck)
	{
		switch (op) {
		case OP_ASSET_ALLOCATION_SEND:
			if (theAssetAllocation.listSendingAllocationAmounts.empty())
			{
				errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1004 - " + _("Asset send must send an input or transfer balance");
				return error(errorMessage.c_str());
			}
			if (theAssetAllocation.listSendingAllocationAmounts.size() > 250)
			{
				errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1005 - " + _("Too many receivers in one allocation send, maximum of 250 is allowed at once");
				return error(errorMessage.c_str());
			}
			break;
		case OP_ASSET_ALLOCATION_BURN:
			if (theAssetAllocation.listSendingAllocationAmounts.size() != 1)
			{
				errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1007 - " + _("Must send exactly one output to burn transaction");
				return error(errorMessage.c_str());
			}
			break;
		default:
			errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1009 - " + _("Asset transaction has unknown op");
			return error(errorMessage.c_str());
		}
	}
	const string &user1 = theAssetAllocation.assetAllocationTuple.GetAddressString();
	const CAssetAllocationTuple &assetAllocationTuple = theAssetAllocation.assetAllocationTuple;
    const string & senderTupleStr = assetAllocationTuple.ToString();

	CAssetAllocation dbAssetAllocation;
	CAsset dbAsset;
	bool bReset = false;
	bool bBalanceOverrun = false;
	bool bAddAllReceiversToConflictList = false;
	if (op == OP_ASSET_ALLOCATION_BURN)
	{

		if (!GetAssetAllocation(assetAllocationTuple, dbAssetAllocation))
		{
			errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1010 - " + _("Cannot find asset allocation to burn");
			return error(errorMessage.c_str());
		}
		if (dbAssetAllocation.assetAllocationTuple != theAssetAllocation.assetAllocationTuple || !FindAssetOwnerInTx(inputs, tx, user1))
		{
			errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1015 - " + _("Cannot send this asset. Asset allocation owner must sign off on this change");
			return error(errorMessage.c_str());
		}
		if(assetAllocationTuple.nAsset != boost::lexical_cast<int>(stringFromVch(vvchArgs[0])))
		{
			errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1010 - " + _("Invalid asset details entered in the script output");
			return error(errorMessage.c_str());
		}
		if (!GetAsset(dbAssetAllocation.assetAllocationTuple.nAsset, dbAsset))
		{
			errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1011 - " + _("Failed to read from asset DB");
			return error(errorMessage.c_str());
		}
		if(dbAsset.vchContract.empty() || dbAsset.vchContract != vvchArgs[2])
		{
			errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1010 - " + _("Invalid contract entered in the script output or Syscoin Asset does not have the ethereum contract configured");
			return error(errorMessage.c_str());
		}
        const auto amountTuple = theAssetAllocation.listSendingAllocationAmounts[0];
        if (amountTuple.second <= 0)
        {
            errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1020 - " + _("Burning amount must be positive");
            return error(errorMessage.c_str());
        }
        if(AssetAmountFromValueNonNeg(stringFromVch(vvchArgs[1]), dbAsset.nPrecision) != amountTuple.second)
        {
            errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1015 - " + _("Invalid amount entered in the script output");
            return error(errorMessage.c_str());
        }
        if(amountTuple.first != vchFromStringUint8("burn"))
        {
            errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1015 - " + _("Must send output to burn address");
            return error(errorMessage.c_str());
        }
		if (!bSanityCheck) {
			bReset = !fJustCheck;
			if (bReset) {
				if (!ResetAssetAllocation(assetAllocationTuple, txHash))
				{
					errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1014 - " + _("Failed to revert asset allocation");
					return error(errorMessage.c_str());
                }
            }
        }

        theAssetAllocation.nBalance = dbAssetAllocation.nBalance;

        CAmount mapBalanceSenderCopy;
        if(fJustCheck){
            LOCK(cs_assetallocation);
            AssetBalanceMap::iterator mapBalanceSender = mempoolMapAssetBalances.find(senderTupleStr);
            if(mapBalanceSender == mempoolMapAssetBalances.end()){
                mempoolMapAssetBalances.emplace(std::make_pair(senderTupleStr, theAssetAllocation.nBalance));
                mapBalanceSenderCopy = theAssetAllocation.nBalance;
            }
            else{
                mapBalanceSenderCopy = mapBalanceSender->second;
            }
        } else{
            AssetBalanceMap::iterator mapBalanceSender = blockMapAssetBalances.find(senderTupleStr);
            if(mapBalanceSender == blockMapAssetBalances.end()){
                blockMapAssetBalances.emplace(std::make_pair(senderTupleStr, theAssetAllocation.nBalance));
                mapBalanceSenderCopy = theAssetAllocation.nBalance;
            }
            else{
                mapBalanceSenderCopy = mapBalanceSender->second;
            }
        }

		const CAmount &nBalanceAfterSend = mapBalanceSenderCopy - amountTuple.second;
		if (nBalanceAfterSend < 0) {
			errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1016 - " + _("Sender balance is insufficient");
			return error(errorMessage.c_str());
		}
		if (!fJustCheck && !bSanityCheck) {
			const CAssetAllocationTuple receiverAllocationTuple(theAssetAllocation.assetAllocationTuple.nAsset, amountTuple.first);
            if (bReset) {
                if (!ResetAssetAllocation(receiverAllocationTuple, txHash, bMiner))
                {
                    errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1019 - " + _("Failed to revert asset allocation");
                    return error(errorMessage.c_str());
                }
            }
			CAssetAllocation receiverAllocation;
			if (!GetAssetAllocation(receiverAllocationTuple, receiverAllocation)) {
				receiverAllocation.assetAllocationTuple = receiverAllocationTuple;
			}

            passetallocationdb->WriteAssetAllocationIndex(receiverAllocation, txHash, nHeight, dbAsset, nBalanceAfterSend, amountTuple.second, user1);
            const string& receiverTupleStr = receiverAllocationTuple.ToString();
            if(fJustCheck){
                LOCK(cs_assetallocation);
                AssetBalanceMap::iterator mapBalanceReceiver = mempoolMapAssetBalances.find(receiverTupleStr);
                if(mapBalanceReceiver == mempoolMapAssetBalances.end()){
                    receiverAllocation.nBalance += amountTuple.second;
                    mempoolMapAssetBalances.emplace(std::make_pair(receiverTupleStr, receiverAllocation.nBalance));
                }
                else{
                    mapBalanceReceiver->second += amountTuple.second;
                    receiverAllocation.nBalance = mapBalanceReceiver->second;
                }

                AssetBalanceMap::iterator mapBalanceSender = mempoolMapAssetBalances.find(senderTupleStr);
                if(mapBalanceSender == mempoolMapAssetBalances.end()){
                    theAssetAllocation.nBalance -= amountTuple.second;
                    mempoolMapAssetBalances.emplace(std::make_pair(senderTupleStr, theAssetAllocation.nBalance));
                }
                else{
                    mapBalanceSender->second -= amountTuple.second;
                    theAssetAllocation.nBalance = mapBalanceSender->second;
                }
            }else{
                AssetBalanceMap::iterator mapBalanceReceiver = blockMapAssetBalances.find(receiverTupleStr);
                if(mapBalanceReceiver == blockMapAssetBalances.end()){
                    receiverAllocation.nBalance += amountTuple.second;
                    blockMapAssetBalances.emplace(std::make_pair(receiverTupleStr, receiverAllocation.nBalance));
                }
                else{
                    mapBalanceReceiver->second += amountTuple.second;
                    receiverAllocation.nBalance = mapBalanceReceiver->second;
                }

                AssetBalanceMap::iterator mapBalanceSender = blockMapAssetBalances.find(senderTupleStr);
                if(mapBalanceSender == blockMapAssetBalances.end()){
                    theAssetAllocation.nBalance -= amountTuple.second;
                    blockMapAssetBalances.emplace(std::make_pair(senderTupleStr, theAssetAllocation.nBalance));
                }
                else{
                    mapBalanceSender->second -= amountTuple.second;
                    theAssetAllocation.nBalance = mapBalanceSender->second;
                }
            }
            auto rv = mapAssetAllocations.emplace(std::move(receiverTupleStr), std::move(receiverAllocation));
            if (!rv.second)
                rv.first->second = std::move(receiverAllocation);

		}else if (!bSanityCheck) {
            LOCK(cs_assetallocationarrival);
			// add conflicting sender if using ZDAG
			assetAllocationConflicts.insert(senderTupleStr);
		}
	}
	else if (op == OP_ASSET_ALLOCATION_SEND)
	{
		if (!GetAssetAllocation(assetAllocationTuple, dbAssetAllocation))
		{
			errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1015 - " + _("Cannot find sender asset allocation.");
			return error(errorMessage.c_str());
		}
		if (dbAssetAllocation.assetAllocationTuple != theAssetAllocation.assetAllocationTuple || !FindAssetOwnerInTx(inputs, tx, user1))
		{
			errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1015a - " + _("Cannot send this asset. Asset allocation owner must sign off on this change");
			return error(errorMessage.c_str());
		}
		if (!GetAsset(assetAllocationTuple.nAsset, dbAsset))
		{
			errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1016 - " + _("Failed to read from asset DB");
			return error(errorMessage.c_str());
		}
		if (!bSanityCheck) {
			bReset = !fJustCheck;
			if (bReset) {
				if (!ResetAssetAllocation(assetAllocationTuple, txHash, bMiner))
				{
					errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1014 - " + _("Failed to revert asset allocation");
					return error(errorMessage.c_str());
				}
			}
		}
		theAssetAllocation.nBalance = dbAssetAllocation.nBalance;

		// check balance is sufficient on sender
		CAmount nTotal = 0;
		for (const auto& amountTuple : theAssetAllocation.listSendingAllocationAmounts) {
			const CAssetAllocationTuple receiverAllocationTuple(theAssetAllocation.assetAllocationTuple.nAsset, amountTuple.first);

			if (bReset) {
				if (!ResetAssetAllocation(receiverAllocationTuple, txHash, bMiner))
				{
					errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1019 - " + _("Failed to revert asset allocation");
					return error(errorMessage.c_str());
				}
			}
			nTotal += amountTuple.second;
			if (amountTuple.second <= 0)
			{
				errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1020 - " + _("Receiving amount must be positive");
				return error(errorMessage.c_str());
			}
		}
        CAmount mapBalanceSenderCopy;

        if(fJustCheck){
            LOCK(cs_assetallocation);
            AssetBalanceMap::iterator mapBalanceSender = mempoolMapAssetBalances.find(senderTupleStr);
            if(mapBalanceSender == mempoolMapAssetBalances.end()){
                mempoolMapAssetBalances.emplace(std::make_pair(senderTupleStr, dbAssetAllocation.nBalance));
                mapBalanceSenderCopy = dbAssetAllocation.nBalance;
            }
            else{
                mapBalanceSenderCopy = mapBalanceSender->second;
            }
        } else{
            AssetBalanceMap::iterator mapBalanceSender = blockMapAssetBalances.find(senderTupleStr);
            if(mapBalanceSender == blockMapAssetBalances.end()){
                blockMapAssetBalances.emplace(std::make_pair(senderTupleStr, dbAssetAllocation.nBalance));
                mapBalanceSenderCopy = dbAssetAllocation.nBalance;
            }
            else{
                mapBalanceSenderCopy = mapBalanceSender->second;
            }
        }
		const CAmount &nBalanceAfterSend = mapBalanceSenderCopy - nTotal;
		if (nBalanceAfterSend < 0) {
			bBalanceOverrun = true;
			if(bSanityCheck)
				errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1021 - " + _("Sender balance is insufficient");
			if (fJustCheck && !bSanityCheck) {
                LOCK(cs_assetallocationarrival);
				// add conflicting sender
				assetAllocationConflicts.insert(senderTupleStr);
			}
		}
		else if (fJustCheck) {
            LOCK(cs_assetallocationarrival);
			// if sender was is flagged as conflicting, add all receivers to conflict list
			if (assetAllocationConflicts.find(senderTupleStr) != assetAllocationConflicts.end())
			{
				bAddAllReceiversToConflictList = true;
			}
		}
		for (const auto& amountTuple : theAssetAllocation.listSendingAllocationAmounts) {

			CAssetAllocation receiverAllocation;
			if (amountTuple.first == theAssetAllocation.assetAllocationTuple.vchAddress) {
				errorMessage = "SYSCOIN_ASSET_ALLOCATION_CONSENSUS_ERROR: ERRCODE: 1022 - " + _("Cannot send an asset allocation to yourself");
				return error(errorMessage.c_str());
			}
			if (!bSanityCheck) {
				const CAssetAllocationTuple receiverAllocationTuple(theAssetAllocation.assetAllocationTuple.nAsset, amountTuple.first);
                const string &receiverTupleStr = receiverAllocationTuple.ToString();

				if (fJustCheck) {
					if (bAddAllReceiversToConflictList || bBalanceOverrun) {
                        LOCK(cs_assetallocationarrival);
						assetAllocationConflicts.insert(receiverTupleStr);
					}
				}

				if (!bBalanceOverrun) {
					CAssetAllocation receiverAllocation;
					if (!GetAssetAllocation(receiverAllocationTuple, receiverAllocation)) {
                        if(!fJustCheck){
							receiverAllocation.assetAllocationTuple = receiverAllocationTuple;
                        }
					}

                    if(fJustCheck){
                        LOCK(cs_assetallocation);
                        AssetBalanceMap::iterator mapBalanceReceiver = mempoolMapAssetBalances.find(receiverTupleStr);
                        if(mapBalanceReceiver == mempoolMapAssetBalances.end()){
                            receiverAllocation.nBalance += amountTuple.second;
                            mempoolMapAssetBalances.emplace(std::make_pair(receiverTupleStr, receiverAllocation.nBalance));
                        }
                        else{
                            mapBalanceReceiver->second += amountTuple.second;
                            receiverAllocation.nBalance = mapBalanceReceiver->second;
                        }

                        AssetBalanceMap::iterator mapBalanceSender = mempoolMapAssetBalances.find(senderTupleStr);
                        if(mapBalanceSender == mempoolMapAssetBalances.end()){
                            theAssetAllocation.nBalance -= amountTuple.second;
                            mempoolMapAssetBalances.emplace(std::make_pair(senderTupleStr, theAssetAllocation.nBalance));
                        }
                        else{
                            mapBalanceSender->second -= amountTuple.second;
                            theAssetAllocation.nBalance = mapBalanceSender->second;
                        }
                    }
                    else{

                        AssetBalanceMap::iterator mapBalanceReceiver = blockMapAssetBalances.find(receiverTupleStr);
                        if(mapBalanceReceiver == blockMapAssetBalances.end()){
                            receiverAllocation.nBalance += amountTuple.second;
                            blockMapAssetBalances.emplace(std::make_pair(receiverTupleStr, receiverAllocation.nBalance));
                        }
                        else{
                            mapBalanceReceiver->second += amountTuple.second;
                            receiverAllocation.nBalance = mapBalanceReceiver->second;
                        }

                        AssetBalanceMap::iterator mapBalanceSender = blockMapAssetBalances.find(senderTupleStr);
                        if(mapBalanceSender == blockMapAssetBalances.end()){
                            theAssetAllocation.nBalance -= amountTuple.second;
                            blockMapAssetBalances.emplace(std::make_pair(senderTupleStr, theAssetAllocation.nBalance));
                        }
                        else{
                            mapBalanceSender->second -= amountTuple.second;
                            theAssetAllocation.nBalance = mapBalanceSender->second;
                        }
                    }

                    if(!fJustCheck){

                        passetallocationdb->WriteAssetAllocationIndex(receiverAllocation, txHash, nHeight, dbAsset, nBalanceAfterSend, amountTuple.second, user1);

                        auto rv = mapAssetAllocations.emplace(std::move(receiverTupleStr), std::move(receiverAllocation));
                        if (!rv.second)
                            rv.first->second = std::move(receiverAllocation);
                    }
				}
			}
		}
	}
	// write assetallocation
	// asset sends are the only ones confirming without PoW
	if (!bBalanceOverrun && !bSanityCheck) {
		// set the assetallocation's txn-dependent
		if(fJustCheck && op == OP_ASSET_ALLOCATION_SEND){
            LOCK(cs_assetallocationarrival);
            ArrivalTimesMap &arrivalTimes = arrivalTimesMap[senderTupleStr];
            arrivalTimes[txHash] = GetTimeMillis();

        }
        else if(!fJustCheck){
    		theAssetAllocation.listSendingAllocationAmounts.clear();
            passetallocationdb->WriteAssetAllocationIndex(theAssetAllocation, txHash, nHeight, dbAsset, theAssetAllocation.nBalance, 0, "");
            auto rv = mapAssetAllocations.emplace(std::move(senderTupleStr), std::move(theAssetAllocation));
            if (!rv.second)
                rv.first->second = std::move(theAssetAllocation);

    		LogPrint(BCLog::SYS,"CONNECTED ASSET ALLOCATION: op=%s assetallocation=%s hash=%s height=%d fJustCheck=%d\n",
    				assetAllocationFromOp(op).c_str(),
    				senderTupleStr.c_str(),
    				txHash.ToString().c_str(),
    				nHeight,
    				fJustCheck ? 1 : 0);
        }
	}

    return true;
}
UniValue tpstestinfo(const JSONRPCRequest& request) {
	const UniValue &params = request.params;
	if (request.fHelp || 0 != params.size())
		throw runtime_error("tpstestinfo\n"
			"Gets TPS Test information for receivers of assetallocation transfers\n");
	if(!fTPSTest)
		throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1501 - " + _("This function requires tpstest configuration to be set upon startup. Please shutdown and enable it by adding it to your syscoin.conf file and then call 'tpstestsetenabled true'."));

	UniValue oTPSTestResults(UniValue::VOBJ);
	UniValue oTPSTestReceivers(UniValue::VARR);
	UniValue oTPSTestReceiversMempool(UniValue::VARR);
	oTPSTestResults.pushKV("enabled", fTPSTestEnabled);
    oTPSTestResults.pushKV("testinitiatetime", (int64_t)nTPSTestingStartTime);
	oTPSTestResults.pushKV("teststarttime", (int64_t)nTPSTestingSendRawEndTime);

	for (auto &receivedTime : vecTPSTestReceivedTimesMempool) {
		UniValue oTPSTestStatusObj(UniValue::VOBJ);
		oTPSTestStatusObj.pushKV("txid", receivedTime.first.GetHex());
		oTPSTestStatusObj.pushKV("time", receivedTime.second);
		oTPSTestReceiversMempool.push_back(oTPSTestStatusObj);
	}
	oTPSTestResults.pushKV("receivers", oTPSTestReceiversMempool);
	return oTPSTestResults;
}
UniValue tpstestsetenabled(const JSONRPCRequest& request) {
	const UniValue &params = request.params;
	if (request.fHelp || 1 != params.size())
		throw runtime_error("tpstestsetenabled [enabled]\n"
			"\nSet TPS Test to enabled/disabled state. Must have -tpstest configuration set to make this call.\n"
			"\nArguments:\n"
			"1. enabled                  (boolean, required) TPS Test enabled state. Set to true for enabled and false for disabled.\n"
			"\nExample:\n"
			+ HelpExampleCli("tpstestsetenabled", "true"));
	if(!fTPSTest)
		throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1501 - " + _("This function requires tpstest configuration to be set upon startup. Please shutdown and enable it by adding it to your syscoin.conf file and then try again."));
	fTPSTestEnabled = params[0].get_bool();
	if (!fTPSTestEnabled) {
		vecTPSTestReceivedTimesMempool.clear();
		nTPSTestingSendRawEndTime = 0;
		nTPSTestingStartTime = 0;
	}
	UniValue result(UniValue::VOBJ);
	result.pushKV("status", "success");
	return result;
}
UniValue tpstestadd(const JSONRPCRequest& request) {
	const UniValue &params = request.params;
	if (request.fHelp || 1 > params.size() || params.size() > 2)
		throw runtime_error("tpstestadd [starttime] [{\"tx\":\"hex\"},...]\n"
			"\nAdds raw transactions to the test raw tx queue to be sent to the network at starttime.\n"
			"\nArguments:\n"
			"1. starttime                  (numeric, required) Unix epoch time in micro seconds for when to send the raw transaction queue to the network. If set to 0, will not send transactions until you call this function again with a defined starttime.\n"
			"2. \"raw transactions\"                (array, not-required) A json array of signed raw transaction strings\n"
			"     [\n"
			"       {\n"
			"         \"tx\":\"hex\",    (string, required) The transaction hex\n"
			"       } \n"
			"       ,...\n"
			"     ]\n"
			"\nExample:\n"
			+ HelpExampleCli("tpstestadd", "\"223233433839384\" \"[{\\\"tx\\\":\\\"first raw hex tx\\\"},{\\\"tx\\\":\\\"second raw hex tx\\\"}]\""));
	if (!fTPSTest)
		throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1501 - " + _("This function requires tpstest configuration to be set upon startup. Please shutdown and enable it by adding it to your syscoin.conf file and then call 'tpstestsetenabled true'."));

	bool bFirstTime = vecTPSRawTransactions.empty();
	nTPSTestingStartTime = params[0].get_int64();
	UniValue txs;
	if(params.size() > 1)
		txs = params[1].get_array();
	if (fTPSTestEnabled) {
		for (unsigned int idx = 0; idx < txs.size(); idx++) {
			const UniValue& tx = txs[idx];
			UniValue paramsRawTx(UniValue::VARR);
			paramsRawTx.push_back(find_value(tx.get_obj(), "tx").get_str());

			JSONRPCRequest request;
			request.params = paramsRawTx;
			vecTPSRawTransactions.push_back(request);
		}
		if (bFirstTime) {
			// define a task for the worker to process
			std::packaged_task<void()> task([]() {
				while (nTPSTestingStartTime <= 0 || GetTimeMicros() < nTPSTestingStartTime) {
					MilliSleep(0);
				}
				nTPSTestingSendRawStartTime = nTPSTestingStartTime;

				for (auto &txReq : vecTPSRawTransactions) {
					sendrawtransaction(txReq);
				}
			});
			bool isThreadPosted = false;
			for (int numTries = 1; numTries <= 50; numTries++)
			{
				// send task to threadpool pointer from init.cpp
				isThreadPosted = threadpool->tryPost(task);
				if (isThreadPosted)
				{
					break;
				}
				MilliSleep(10);
			}
			if (!isThreadPosted)
				throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1501 - " + _("thread pool queue is full"));
		}
	}
	UniValue result(UniValue::VOBJ);
	result.pushKV("status", "success");
	return result;
}
UniValue assetallocationburn(const JSONRPCRequest& request) {
    std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    CWallet* const pwallet = wallet.get();
	const UniValue &params = request.params;
	if (request.fHelp || 3 != params.size())
		throw runtime_error(
			"assetallocationburn [asset] [owner] [amount]\n"
			"<asset> Asset guid.\n"
			"<owner> Address that owns this asset allocation.\n"
			"<amount> Amount of asset to burn to SYSX.\n"
			+ HelpRequiringPassphrase(pwallet));

	const int &nAsset = params[0].get_int();
	string strAddress = params[1].get_str();

	string strAddressFrom;
	const CTxDestination &addressFrom = DecodeDestination(strAddress);
	strAddressFrom = strAddress;

	CAssetAllocation theAssetAllocation;
	const CAssetAllocationTuple assetAllocationTuple(nAsset, bech32::Decode(strAddress).second);
	if (!GetAssetAllocation(assetAllocationTuple, theAssetAllocation))
		throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1500 - " + _("Could not find a asset allocation with this key"));

	CAsset theAsset;
	if (!GetAsset(nAsset, theAsset))
		throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1501 - " + _("Could not find a asset with this key"));

	CScript scriptPubKeyFromOrig;
	if (!strAddressFrom.empty()) {
		scriptPubKeyFromOrig = GetScriptForDestination(addressFrom);
	}

	CAmount amount = AssetAmountFromValueNonNeg(params[2], theAsset.nPrecision);

	theAssetAllocation.ClearAssetAllocation();
	theAssetAllocation.assetAllocationTuple = assetAllocationTuple;
    string burnAddr = "burn";
	theAssetAllocation.listSendingAllocationAmounts.push_back(make_pair(vchFromStringUint8("burn"), amount));

    vector<unsigned char> data;
    theAssetAllocation.Serialize(data);

	CScript scriptPubKey;
	scriptPubKey << CScript::EncodeOP_N(OP_SYSCOIN_ASSET_ALLOCATION) << CScript::EncodeOP_N(OP_ASSET_ALLOCATION_BURN) << vchFromString(boost::lexical_cast<string>(nAsset)) << vchFromString(ValueFromAssetAmount(amount,theAsset.nPrecision).getValStr()) << theAsset.vchContract << OP_2DROP << OP_2DROP << OP_2DROP;
	scriptPubKey += scriptPubKeyFromOrig;
	// send the asset pay txn
	vector<CRecipient> vecSend;
	CRecipient recipient;
	CreateRecipient(scriptPubKey, recipient);
	vecSend.push_back(recipient);

	CScript scriptData;
	scriptData << OP_RETURN << CScript::EncodeOP_N(OP_SYSCOIN_ASSET_ALLOCATION) << data;
	CRecipient fee;
	CreateFeeRecipient(scriptData, fee);
	vecSend.push_back(fee);

	return syscointxfund_helper("", vecSend);
}
UniValue assetallocationsend(const JSONRPCRequest& request) {
    std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    CWallet* const pwallet = wallet.get();
	const UniValue &params = request.params;
	if (request.fHelp || params.size() != 4)
		throw runtime_error(
			"assetallocationsend [asset] [owner] ([{\"ownerto\":\"address\",\"amount\":amount},...] [witness]\n"
			"Send an asset allocation you own to another address. Maximimum recipients is 250.\n"
			"<asset> Asset guid.\n"
			"<owner> Address that owns this asset allocation.\n"
			"<ownerto> Address to transfer to.\n"
			"<amount> Quantity of asset to send.\n"
			"<witness> Witness address that will sign for web-of-trust notarization of this transaction.\n"
			+ HelpRequiringPassphrase(pwallet));

	// gather & validate inputs
	const int &nAsset = params[0].get_int();
	string vchAddressFrom = params[1].get_str();
	UniValue valueTo = params[2];
	vector<unsigned char> vchWitness;
    string strWitness = params[3].get_str();
	if (!valueTo.isArray())
		throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Array of receivers not found");
	string strAddressFrom;
	const string &strAddress = vchAddressFrom;
    CTxDestination addressFrom;
    if(strAddress != "burn"){
	    addressFrom = DecodeDestination(strAddress);
    	if (IsValidDestination(addressFrom)) {
    		strAddressFrom = strAddress;
    	}
    }
	CAssetAllocation theAssetAllocation;
	const CAssetAllocationTuple assetAllocationTuple(nAsset, strAddress == "burn"? vchFromStringUint8("burn"): bech32::Decode(strAddress).second);
	if (!GetAssetAllocation(assetAllocationTuple, theAssetAllocation))
		throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1500 - " + _("Could not find a asset allocation with this key"));

	CAsset theAsset;
	if (!GetAsset(nAsset, theAsset))
		throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1501 - " + _("Could not find a asset with this key"));

	theAssetAllocation.ClearAssetAllocation();
	theAssetAllocation.assetAllocationTuple = assetAllocationTuple;
	UniValue receivers = valueTo.get_array();

	for (unsigned int idx = 0; idx < receivers.size(); idx++) {
		const UniValue& receiver = receivers[idx];
		if (!receiver.isObject())
			throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"ownerto'\" or \"amount\"}");

		const UniValue &receiverObj = receiver.get_obj();
		const string &toStr = find_value(receiverObj, "ownerto").get_str();
        const CTxDestination &dest = DecodeDestination(toStr);
		if (!IsValidDestination(dest))
			throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1502 - " + _("Asset must be sent to a valid syscoin address"));
        vector<uint8_t> vchAddressTo = bech32::Decode(toStr).second;

		UniValue amountObj = find_value(receiverObj, "amount");
		if (amountObj.isNum()) {
			const CAmount &amount = AssetAmountFromValue(amountObj, theAsset.nPrecision);
			if (amount <= 0)
				throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "amount must be positive");
			theAssetAllocation.listSendingAllocationAmounts.push_back(make_pair(vchAddressTo, amount));
		}
		else
			throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected amount as number in receiver array");

	}

	CScript scriptPubKeyFromOrig;
	if (!strAddressFrom.empty()) {
		scriptPubKeyFromOrig = GetScriptForDestination(addressFrom);
	}

	CScript scriptPubKey;
    {
        LOCK(cs_assetallocationarrival);
    	// check to see if a transaction for this asset/address tuple has arrived before minimum latency period
    	const ArrivalTimesMap &arrivalTimes = arrivalTimesMap[assetAllocationTuple.ToString()];
    	const int64_t & nNow = GetTimeMillis();
    	int minLatency = ZDAG_MINIMUM_LATENCY_SECONDS * 1000;
    	if (fUnitTest)
    		minLatency = 1000;
    	for (auto& arrivalTime : arrivalTimes) {
    		// if this tx arrived within the minimum latency period flag it as potentially conflicting
    		if ((nNow - arrivalTime.second) < minLatency) {
    			throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1503 - " + _("Please wait a few more seconds and try again..."));
    		}
    	}
    }

	vector<unsigned char> data;
	theAssetAllocation.Serialize(data);

	scriptPubKey << CScript::EncodeOP_N(OP_SYSCOIN_ASSET_ALLOCATION) << CScript::EncodeOP_N(OP_ASSET_ALLOCATION_SEND) << OP_2DROP;
	scriptPubKey += scriptPubKeyFromOrig;
	// send the asset pay txn
	vector<CRecipient> vecSend;
	CRecipient recipient;
	CreateRecipient(scriptPubKey, recipient);
	vecSend.push_back(recipient);

	CScript scriptData;
	scriptData << OP_RETURN << CScript::EncodeOP_N(OP_SYSCOIN_ASSET_ALLOCATION) << data;
	CRecipient fee;
	CreateFeeRecipient(scriptData, fee);
	vecSend.push_back(fee);

	return syscointxfund_helper(strWitness, vecSend);
}

UniValue assetallocationinfo(const JSONRPCRequest& request) {
	const UniValue &params = request.params;
    if (request.fHelp || 2 != params.size())
        throw runtime_error("assetallocationinfo <asset> <owner>\n"
                "Show stored values of a single asset allocation.\n");

    const int &nAsset = params[0].get_int();
	string strAddressFrom = params[1].get_str();
	UniValue oAssetAllocation(UniValue::VOBJ);
	const CAssetAllocationTuple assetAllocationTuple(nAsset, strAddressFrom == "burn"? vchFromStringUint8("burn"): bech32::Decode(strAddressFrom).second);
	CAssetAllocation txPos;
	if (passetallocationdb == nullptr || !passetallocationdb->ReadAssetAllocation(assetAllocationTuple, txPos))
		throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1507 - " + _("Failed to read from assetallocation DB"));

	CAsset theAsset;
	if (!GetAsset(nAsset, theAsset))
		throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1508 - " + _("Could not find a asset with this key"));

	if(!BuildAssetAllocationJson(txPos, theAsset, oAssetAllocation))
		oAssetAllocation.clear();
    return oAssetAllocation;
}
int DetectPotentialAssetAllocationSenderConflicts(const CAssetAllocationTuple& assetAllocationTupleSender, const uint256& lookForTxHash) {
	CAssetAllocation dbAssetAllocation;
	// get last POW asset allocation balance to ensure we use POW balance to check for potential conflicts in mempool (real-time balances).
	// The idea is that real-time spending amounts can in some cases overrun the POW balance safely whereas in some cases some of the spends are
	// put in another block due to not using enough fees or for other reasons that miners don't mine them.
	// We just want to flag them as level 1 so it warrants deeper investigation on receiver side if desired (if fund amounts being transferred are not negligible)
	if (passetallocationdb == nullptr || !passetallocationdb->ReadAssetAllocation(assetAllocationTupleSender, dbAssetAllocation))
		return ZDAG_NOT_FOUND;

	// ensure that this transaction exists in the arrivalTimes DB (which is the running stored lists of all real-time asset allocation sends not in POW)
	// the arrivalTimes DB is only added to for valid asset allocation sends that happen in real-time and it is removed once there is POW on that transaction
    const ArrivalTimesMap& arrivalTimes = arrivalTimesMap[assetAllocationTupleSender.ToString()];
	if(arrivalTimes.empty())
		return ZDAG_NOT_FOUND;
	// sort the arrivalTimesMap ascending based on arrival time value

	// Declaring the type of Predicate for comparing arrivalTimesMap
	typedef std::function<bool(std::pair<uint256, int64_t>, std::pair<uint256, int64_t>)> Comparator;

	// Defining a lambda function to compare two pairs. It will compare two pairs using second field
	Comparator compFunctor =
		[](std::pair<uint256, int64_t> elem1, std::pair<uint256, int64_t> elem2)
	{
		return elem1.second < elem2.second;
	};

	// Declaring a set that will store the pairs using above comparision logic
	std::set<std::pair<uint256, int64_t>, Comparator> arrivalTimesSet(
		arrivalTimes.begin(), arrivalTimes.end(), compFunctor);

	// go through arrival times and check that balances don't overrun the POW balance
	pair<uint256, int64_t> lastArrivalTime;
	lastArrivalTime.second = GetTimeMillis();
	map<std::vector<uint8_t>, CAmount> mapBalances;
	// init sender balance, track balances by address
	// this is important because asset allocations can be sent/received within blocks and will overrun balances prematurely if not tracked properly, for example pow balance 3, sender sends 3, gets 2 sends 2 (total send 3+2=5 > balance of 3 from last stored state, this is a valid scenario and shouldn't be flagged)
	CAmount &senderBalance = mapBalances[assetAllocationTupleSender.vchAddress];
	senderBalance = dbAssetAllocation.nBalance;
	int minLatency = ZDAG_MINIMUM_LATENCY_SECONDS * 1000;
	if (fUnitTest)
		minLatency = 1000;
	for (auto& arrivalTime : arrivalTimesSet)
	{
		// ensure mempool has this transaction and it is not yet mined, get the transaction in question
		const CTransactionRef txRef = mempool.get(arrivalTime.first);
		if (!txRef)
			continue;
		const CTransaction &tx = *txRef;

		// if this tx arrived within the minimum latency period flag it as potentially conflicting
		if (abs(arrivalTime.second - lastArrivalTime.second) < minLatency) {
			return ZDAG_MINOR_CONFLICT;
		}
		const uint256& txHash = tx.GetHash();
		// get asset allocation object from this tx, if for some reason it doesn't have it, just skip (shouldn't happen)
		CAssetAllocation assetallocation(tx);
		if (assetallocation.IsNull())
			continue;

		if (!assetallocation.listSendingAllocationAmounts.empty()) {
			for (auto& amountTuple : assetallocation.listSendingAllocationAmounts) {
				senderBalance -= amountTuple.second;
				mapBalances[amountTuple.first] += amountTuple.second;
				// if running balance overruns the stored balance then we have a potential conflict
				if (senderBalance < 0) {
					return ZDAG_MINOR_CONFLICT;
				}
			}
		}
		// even if the sender may be flagged, the order of events suggests that this receiver should get his money confirmed upon pow because real-time balance is sufficient for this receiver
		if (txHash == lookForTxHash) {
			return ZDAG_STATUS_OK;
		}
	}
	return lookForTxHash.IsNull()? ZDAG_STATUS_OK: ZDAG_NOT_FOUND;
}
UniValue assetallocationsenderstatus(const JSONRPCRequest& request) {
	const UniValue &params = request.params;
	if (request.fHelp || 3 != params.size())
		throw runtime_error("assetallocationsenderstatus <asset> <owner> <txid>\n"
			"Show status as it pertains to any current Z-DAG conflicts or warnings related to a sender or sender/txid combination of an asset allocation transfer. Leave txid empty if you are not checking for a specific transfer.\n"
			"Return value is in the status field and can represent 3 levels(0, 1 or 2)\n"
			"Level -1 means not found, not a ZDAG transaction, perhaps it is already confirmed.\n"
			"Level 0 means OK.\n"
			"Level 1 means warning (checked that in the mempool there are more spending balances than current POW sender balance). An active stance should be taken and perhaps a deeper analysis as to potential conflicts related to the sender.\n"
			"Level 2 means an active double spend was found and any depending asset allocation sends are also flagged as dangerous and should wait for POW confirmation before proceeding.\n");

	const int &nAsset = params[0].get_int();
	string vchAddressSender = params[1].get_str();
	const string &strAddressSender = vchAddressSender;
	uint256 txid;
	txid.SetNull();
	if(!params[2].get_str().empty())
		txid.SetHex(params[2].get_str());
	UniValue oAssetAllocationStatus(UniValue::VOBJ);
    LOCK2(cs_main, mempool.cs);
    LOCK(cs_assetallocationarrival);

    const int64_t & nNow = GetTimeMillis();
	const CAssetAllocationTuple assetAllocationTupleSender(nAsset, bech32::Decode(strAddressSender).second);

       // if arrival times have expired, then expire any conflicting status for this sender as well
    const ArrivalTimesMap &arrivalTimes = arrivalTimesMap[assetAllocationTupleSender.ToString()];
    bool allArrivalsExpired = true;
    for (auto& arrivalTime : arrivalTimes) {
        // if its been less than 30m then we keep conflict status
        if((nNow - arrivalTime.second) <= 1800000){
            allArrivalsExpired = false;
            break;
        }
    }

    if(allArrivalsExpired){
        arrivalTimesMap.erase(assetAllocationTupleSender.ToString());
        sorted_vector<string>::const_iterator it = assetAllocationConflicts.find(assetAllocationTupleSender.ToString());
        if (it != assetAllocationConflicts.end()) {
            assetAllocationConflicts.V.erase(const_iterator_cast(assetAllocationConflicts.V, it));
        }
    }

	int nStatus = ZDAG_STATUS_OK;
	if (assetAllocationConflicts.find(assetAllocationTupleSender.ToString()) != assetAllocationConflicts.end())
		nStatus = ZDAG_MAJOR_CONFLICT;
	else {
		nStatus = DetectPotentialAssetAllocationSenderConflicts(assetAllocationTupleSender, txid);
	}
	oAssetAllocationStatus.pushKV("status", nStatus);
	return oAssetAllocationStatus;
}
bool BuildAssetAllocationJson(CAssetAllocation& assetallocation, const CAsset& asset, UniValue& oAssetAllocation)
{
    CAmount nBalanceZDAG = assetallocation.nBalance;
    const string &allocationTupleStr = assetallocation.assetAllocationTuple.ToString();
    {
        LOCK(cs_assetallocation);
        AssetBalanceMap::iterator mapIt =  mempoolMapAssetBalances.find(allocationTupleStr);
        if(mapIt != mempoolMapAssetBalances.end())
            nBalanceZDAG = mapIt->second;
    }
    oAssetAllocation.pushKV("_id", allocationTupleStr);
	oAssetAllocation.pushKV("asset", assetallocation.assetAllocationTuple.nAsset);
	oAssetAllocation.pushKV("owner",  assetallocation.assetAllocationTuple.GetAddressString());
	oAssetAllocation.pushKV("balance", ValueFromAssetAmount(assetallocation.nBalance, asset.nPrecision));
    oAssetAllocation.pushKV("balance_zdag", ValueFromAssetAmount(nBalanceZDAG, asset.nPrecision));
	return true;
}
bool BuildAssetAllocationIndexerJson(const CAssetAllocation& assetallocation, const CAsset& asset, const CAmount& nSenderBalance, const CAmount& nAmount, const string& strSender, const string& strReceiver, bool &isMine, UniValue& oAssetAllocation)
{
	CAmount nAmountDisplay = nAmount;
	oAssetAllocation.pushKV("_id", assetallocation.assetAllocationTuple.ToString());
	oAssetAllocation.pushKV("asset", assetallocation.assetAllocationTuple.nAsset);
	oAssetAllocation.pushKV("sender", strSender);
	oAssetAllocation.pushKV("sender_balance", ValueFromAssetAmount(nSenderBalance, asset.nPrecision));
	oAssetAllocation.pushKV("receiver", strReceiver);
	oAssetAllocation.pushKV("receiver_balance", ValueFromAssetAmount(assetallocation.nBalance, asset.nPrecision));
	if (fAssetAllocationIndex) {
        CWallet* const pwallet = GetDefaultWallet();
		string strCat = "";
		if (!strSender.empty() || !strReceiver.empty()) {
			isminefilter filter = ISMINE_SPENDABLE;
            if(!strSender.empty() && strSender != "burn" && pwallet)
            {
    			isminefilter mine = IsMine(*pwallet, DecodeDestination(strSender));
    			if ((mine & filter)) {
    				strCat = "send";
    				nAmountDisplay *= -1;
    			}
            }
			else if(!strReceiver.empty() && strReceiver != "burn" && pwallet){
				isminefilter mine = IsMine(*pwallet, DecodeDestination(strReceiver));
				if ((mine & filter))
					strCat = "receive";
			}
		}

		oAssetAllocation.pushKV("category", strCat);
	}
	oAssetAllocation.pushKV("amount", ValueFromAssetAmount(nAmountDisplay, asset.nPrecision));
	return true;
}
void AssetAllocationTxToJSON(const int op, const std::vector<unsigned char> &vchData, UniValue &entry)
{
	string opName = assetAllocationFromOp(op);
	CAssetAllocation assetallocation;
	if(!assetallocation.UnserializeFromData(vchData))
		return;
	CAsset dbAsset;
	GetAsset(assetallocation.assetAllocationTuple.nAsset, dbAsset);

	entry.pushKV("txtype", opName);
	entry.pushKV("_id", assetallocation.assetAllocationTuple.ToString());
	entry.pushKV("asset", assetallocation.assetAllocationTuple.nAsset);
	entry.pushKV("owner", assetallocation.assetAllocationTuple.GetAddressString());
	UniValue oAssetAllocationReceiversArray(UniValue::VARR);
	if (!assetallocation.listSendingAllocationAmounts.empty()) {
		for (auto& amountTuple : assetallocation.listSendingAllocationAmounts) {
			UniValue oAssetAllocationReceiversObj(UniValue::VOBJ);
			oAssetAllocationReceiversObj.pushKV("owner", bech32::Encode(Params().Bech32HRP(),amountTuple.first));
			oAssetAllocationReceiversObj.pushKV("amount", ValueFromAssetAmount(amountTuple.second, dbAsset.nPrecision));
			oAssetAllocationReceiversArray.push_back(oAssetAllocationReceiversObj);
		}
	}
	entry.pushKV("allocations", oAssetAllocationReceiversArray);

}
bool CAssetAllocationTransactionsDB::ScanAssetAllocationIndex(const int count, const int from, const UniValue& oOptions, UniValue& oRes) {
	string strTxid = "";
	vector<string> vecSenders;
	vector<string> vecReceivers;
	string strAsset = "";
	bool bParseKey = false;
	if (!oOptions.isNull()) {
		const UniValue &txid = find_value(oOptions, "txid");
		if (txid.isStr()) {
			strTxid = txid.get_str();
			bParseKey = true;
		}
		const UniValue &asset = find_value(oOptions, "asset");
		if (asset.isStr()) {
			strAsset = asset.get_str();
			bParseKey = true;
		}

		const UniValue &owners = find_value(oOptions, "receivers");
		if (owners.isArray()) {
			const UniValue &ownersArray = owners.get_array();
			for (unsigned int i = 0; i < ownersArray.size(); i++) {
				const UniValue &owner = ownersArray[i].get_obj();
				const UniValue &ownerStr = find_value(owner, "receiver");
				if (ownerStr.isStr()) {
					bParseKey = true;
					vecReceivers.push_back(ownerStr.get_str());
				}
			}
		}

		const UniValue &senders = find_value(oOptions, "senders");
		if (senders.isArray()) {
			const UniValue &sendersArray = senders.get_array();
			for (unsigned int i = 0; i < sendersArray.size(); i++) {
				const UniValue &sender = sendersArray[i].get_obj();
				const UniValue &senderStr = find_value(sender, "sender");
				if (senderStr.isStr()) {
					bParseKey = true;
					vecSenders.push_back(senderStr.get_str());
				}
			}
		}
	}
	int index = 0;
	UniValue assetValue;
	vector<string> contents;
	contents.reserve(5);
    LOCK(cs_assetallocationindex);
	for (auto&indexObj : boost::adaptors::reverse(AssetAllocationIndex)) {
		for (auto& indexItem : indexObj.second) {
			if (bParseKey) {
				boost::algorithm::split(contents, indexItem.first, boost::is_any_of("-"));
				if (!strTxid.empty() && strTxid != contents[0])
					continue;
				if (!strAsset.empty() && strAsset != contents[1])
					continue;
				if (!vecSenders.empty() && std::find(vecSenders.begin(), vecSenders.end(), contents[2]) == vecSenders.end())
					continue;
				if (!vecReceivers.empty() && std::find(vecReceivers.begin(), vecReceivers.end(), contents[3]) == vecReceivers.end())
					continue;
			}
			index += 1;
			if (index <= from) {
				continue;
			}
			if (assetValue.read(indexItem.second))
				oRes.push_back(assetValue);
			if (index >= count + from)
				break;
		}
		if (index >= count + from)
			break;
	}
	return true;
}
bool CAssetAllocationDB::Flush(const AssetAllocationMap &mapAssetAllocations){
    if(mapAssetAllocations.empty())
        return true;
    CDBBatch batch(*this);
    for (const auto &key : mapAssetAllocations) {
        const CAssetAllocation &assetallocation = key.second;
        batch.Write(make_pair(assetAllocationKey, assetallocation.assetAllocationTuple), assetallocation);
    }
    LogPrint(BCLog::SYS, "Flushing %d asset allocations\n", mapAssetAllocations.size());
    return WriteBatch(batch);
}
bool CAssetAllocationDB::ScanAssetAllocations(const int count, const int from, const UniValue& oOptions, UniValue& oRes) {
	string strTxid = "";
	vector<vector<uint8_t> > vchAddresses;
	int32_t nAsset = 0;
	if (!oOptions.isNull()) {
		const UniValue &assetObj = find_value(oOptions, "asset");
		if(assetObj.isNum()) {
			nAsset = boost::lexical_cast<int32_t>(assetObj.get_int());
		}

		const UniValue &owners = find_value(oOptions, "receivers");
		if (owners.isArray()) {
			const UniValue &ownersArray = owners.get_array();
			for (unsigned int i = 0; i < ownersArray.size(); i++) {
				const UniValue &owner = ownersArray[i].get_obj();
				const UniValue &ownerStr = find_value(owner, "receiver");
				if (ownerStr.isStr()) {
					vchAddresses.push_back(bech32::Decode(ownerStr.get_str()).second);
				}
			}
		}
	}

	boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
	pcursor->SeekToFirst();
	CAssetAllocation txPos;
	pair<string, CAssetAllocationTuple > key;
	CAsset theAsset;
	int index = 0;
	while (pcursor->Valid()) {
		boost::this_thread::interruption_point();
		try {
			if (pcursor->GetKey(key) && key.first == assetAllocationKey && (nAsset == 0 || nAsset != key.second.nAsset)) {
				pcursor->GetValue(txPos);
				if (!vchAddresses.empty() && std::find(vchAddresses.begin(), vchAddresses.end(), txPos.assetAllocationTuple.vchAddress) == vchAddresses.end())
				{
					pcursor->Next();
					continue;
				}
				UniValue oAssetAllocation(UniValue::VOBJ);
				if (!BuildAssetAllocationJson(txPos, theAsset, oAssetAllocation))
				{
					pcursor->Next();
					continue;
				}
				index += 1;
				if (index <= from) {
					pcursor->Next();
					continue;
				}
				oRes.push_back(oAssetAllocation);
				if (index >= count + from) {
					break;
				}
			}
			pcursor->Next();
		}
		catch (std::exception &e) {
			return error("%s() : deserialize error", __PRETTY_FUNCTION__);
		}
	}
	return true;
}
UniValue listassetallocationtransactions(const JSONRPCRequest& request) {
	const UniValue &params = request.params;
	if (request.fHelp || 3 < params.size())
		throw runtime_error("listassetallocationtransactions [count] [from] [{options}]\n"
			"list asset allocations sent or recieved in this wallet. -assetallocationindex must be set as a startup parameter to use this function.\n"
			"[count]          (numeric, optional, default=10) The number of results to return, 0 to return all.\n"
			"[from]           (numeric, optional, default=0) The number of results to skip.\n"
			"[options]        (object, optional) A json object with options to filter results\n"
			"    {\n"
			"      \"txid\":txid					(string) Transaction ID to filter.\n"
			"	   \"asset\":guid					(number) Asset GUID to filter.\n"
			"	   \"senders\"						(array) a json array with senders\n"
			"		[\n"
			"			{\n"
			"				\"sender\":string		(string) Sender address to filter.\n"
			"			} \n"
			"			,...\n"
			"		]\n"
			"	   \"receivers\"					(array) a json array with receivers\n"
			"		[\n"
			"			{\n"
			"				\"receiver\":string		(string) Receiver address to filter.\n"
			"			} \n"
			"			,...\n"
			"		]\n"
			"    }\n"
			+ HelpExampleCli("listassetallocationtransactions", "0 10")
			+ HelpExampleCli("listassetallocationtransactions", "0 0 '{\"asset\":343773}'")
			+ HelpExampleCli("listassetallocationtransactions", "0 0 '{\"senders\":[{\"sender\":\"SfaMwYY19Dh96B9qQcJQuiNykVRTzXMsZR\"},{\"sender\":\"SfaMwYY19Dh96B9qQcJQuiNykVRTzXMsZR\"}]}'")
			+ HelpExampleCli("listassetallocationtransactions", "0 0 '{\"txid\":\"1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1\"}'")
		);
	UniValue options;
	int count = 10;
	int from = 0;
	if (params.size() > 0)
		count = params[0].get_int();
	if (params.size() > 1)
		from = params[1].get_int();
	if (params.size() > 2)
		options = params[2];
	if (!fAssetAllocationIndex) {
		throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1509 - " + _("Asset allocation index not enabled, you must enable -assetallocationindex as a startup parameter or through syscoin.conf file to use this function."));
	}
	LOCK(cs_assetallocationindex);
	UniValue oRes(UniValue::VARR);
	if (!passetallocationtransactionsdb->ScanAssetAllocationIndex(count, from, options, oRes))
		throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1509 - " + _("Scan failed"));
	return oRes;
}
UniValue listassetallocations(const JSONRPCRequest& request) {
	const UniValue &params = request.params;
	if (request.fHelp || 3 < params.size())
		throw runtime_error("listassetallocations [count] [from] [{options}]\n"
			"scan through all asset allocations.\n"
			"[count]          (numeric, optional, default=10) The number of results to return.\n"
			"[from]           (numeric, optional, default=0) The number of results to skip.\n"
			"[options]        (array, optional) A json object with options to filter results\n"
			"    {\n"
			"	   \"asset\":guid					(number) Asset GUID to filter.\n"
			"	   \"receivers\"					(array) a json array with receivers\n"
			"		[\n"
			"			{\n"
			"				\"receiver\":string		(string) Receiver address to filter.\n"
			"			} \n"
			"			,...\n"
			"		]\n"
			"    }\n"
			+ HelpExampleCli("listassetallocations", "0")
			+ HelpExampleCli("listassetallocations", "10 10")
			+ HelpExampleCli("listassetallocations", "0 0 '{\"asset\":92922}'")
			+ HelpExampleCli("listassetallocations", "0 0 '{\"receivers\":[{\"receiver\":\"SfaMwYY19Dh96B9qQcJQuiNykVRTzXMsZR\"},{\"receiver\":\"SfaMwYY19Dh96B9qQcJQuiNykVRTzXMsZR\"}]}'")
		);
	UniValue options;
	int count = 10;
	int from = 0;
	if (params.size() > 0) {
		count = params[0].get_int();
		if (count == 0) {
			count = 10;
		} else
		if (count < 0) {
			throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1510 - " + _("'count' must be 0 or greater"));
		}
	}
	if (params.size() > 1) {
		from = params[1].get_int();
		if (from < 0) {
			throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1510 - " + _("'from' must be 0 or greater"));
		}
	}
	if (params.size() > 2) {
		options = params[2];
	}
	UniValue oRes(UniValue::VARR);
	if (!passetallocationdb->ScanAssetAllocations(count, from, options, oRes))
		throw runtime_error("SYSCOIN_ASSET_ALLOCATION_RPC_ERROR: ERRCODE: 1510 - " + _("Scan failed"));
	return oRes;
}

ext: cpp

max_stars_repo_name: willyko/temp

max_issues_repo_name: willyko/temp

max_forks_repo_name: willyko/temp


text:
/*
 * Copyright (c) 2013, Christian Gehring, Hannes Sommer, Paul Furgale, Remo Diethelm
 * 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 Autonomous Systems Lab, ETH Zurich 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 Christian Gehring, Hannes Sommer, Paul Furgale,
 * Remo Diethelm 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.
 *
*/

#pragma once

#include <Eigen/Core>

#include "kindr/math/LinearAlgebra.hpp"
#include "kindr/common/common.hpp"
#include "kindr/common/assert_macros.hpp"
#include "kindr/common/assert_macros_eigen.hpp"
#include "kindr/rotations/RotationDiffBase.hpp"
#include "kindr/rotations/Rotation.hpp"

namespace kindr {

/*! \class EulerAnglesZyxDiff
 * \brief Implementation of time derivatives of Euler angles (Z,Y',X'' / yaw,pitch,roll) based on Eigen::Matrix<Scalar, 3, 1>
 *
 * The following two typedefs are provided for convenience:
 *   - EulerAnglesZyxDiffAD for primitive type double
 *   - EulerAnglesZyxDoffAF for primitive type float
 * \tparam PrimType_ the primitive type of the data (double or float)
 * \ingroup rotations
 */
template<typename PrimType_>
class EulerAnglesZyxDiff : public RotationDiffBase<EulerAnglesZyxDiff<PrimType_>> {
 private:
  /*! \brief The base type.
   */
  typedef Eigen::Matrix<PrimType_, 3, 1> Base;

  /*! \brief data container [yaw; pitch; roll]
   */
  Base zyxDiff_;

 public:
  /*! \brief The implementation type.
   *  The implementation type is always an Eigen object.
   */
  typedef Base Implementation;

  /*! \brief The primitive type.
   *  Float/Double
   */
  typedef PrimType_ Scalar;

  /*! \brief Default constructor.
   */
  EulerAnglesZyxDiff()
    : zyxDiff_(Base::Zero()) {
  }

  /*! \brief Constructor using three scalars.
   *  \param yaw      time derivative of first rotation angle around Z axis
   *  \param pitch    time derivative of second rotation angle around Y' axis
   *  \param roll     time derivative of third rotation angle around X'' axis
   */
  EulerAnglesZyxDiff(Scalar yaw, Scalar pitch, Scalar roll)
    : zyxDiff_(yaw,pitch,roll) {
  }

  /*! \brief Constructor using a time derivative with a different parameterization
   *
   * \param rotation  rotation
   * \param other     other time derivative
   */
  template<typename RotationDerived_, typename OtherDerived_>
  inline explicit EulerAnglesZyxDiff(const RotationBase<RotationDerived_>& rotation, const RotationDiffBase<OtherDerived_>& other)
    : zyxDiff_(internal::RotationDiffConversionTraits<EulerAnglesZyxDiff, OtherDerived_, RotationDerived_>::convert(rotation.derived(), other.derived()).toImplementation()){
  }

  /*! \brief Cast to another representation of the time derivative of a rotation
   *  \param other   other rotation
   *  \returns reference
   */
  template<typename OtherDerived_, typename RotationDerived_>
  OtherDerived_ cast(const RotationBase<RotationDerived_>& rotation) const {
    return internal::RotationDiffConversionTraits<OtherDerived_, EulerAnglesZyxDiff, RotationDerived_>::convert(rotation.derived(), *this);
  }

  /*! \brief Constructor using Eigen::Matrix.
   *  \param other   Eigen::Matrix<Scalar, 3, 1> [yaw; pitch; roll]
   */
  explicit EulerAnglesZyxDiff(const Base& other)
    : zyxDiff_(other) {
  }

  /*! \brief Cast to the implementation type.
   *  \returns the implementation for direct manipulation (recommended only for advanced users)
   */
  inline Base& toImplementation() {
    return static_cast<Base&>(zyxDiff_);
  }

  /*! \brief Cast to the implementation type.
   *  \returns the implementation for direct manipulation (recommended only for advanced users)
   */
  inline const Base& toImplementation() const {
    return static_cast<const Base&>(zyxDiff_);
  }

  inline Base& vector() {
    return toImplementation();
  }

  inline const Base& vector() const {
    return toImplementation();
  }

  /*! \brief Reading access to time derivative of yaw (Z) angle.
    *  \returns time derivative of yaw angle (scalar) with reading access
    */
   inline Scalar yaw() const {
     return toImplementation()(0);
   }

   /*! \brief Reading access to time derivative of pitch (Y') angle.
    *  \returns time derivative of pitch angle (scalar) with reading access
    */
   inline Scalar pitch() const {
     return toImplementation()(1);
   }

   /*! \brief Reading access to time derivative of roll (X'') angle.
    *  \returns time derivative of roll angle (scalar) with reading access
    */
   inline Scalar roll() const {
     return toImplementation()(2);
   }

   /*! \brief Writing access to time derivative of yaw (Z) angle.
    *  \returns time derivative of yaw angle (scalar) with writing access
    */
   inline Scalar& yaw() {
     return toImplementation()(0);
   }

   /*! \brief Writing access to time derivative of pitch (Y') angle.
    *  \returns time derivative of pitch angle (scalar) with writing access
    */
   inline Scalar& pitch() {
     return toImplementation()(1);
   }

   /*! \brief Writing access to time derivative of roll (X'') angle.
    *  \returns time derivative of roll angle (scalar) with writing access
    */
   inline Scalar& roll() {
     return toImplementation()(2);
   }

   /*! \brief Reading access to time derivative of yaw (Z) angle.
    *  \returns time derivative of yaw angle (scalar) with reading access
    */
   inline Scalar z() const {
     return toImplementation()(0);
   }

   /*! \brief Reading access to time derivative of pitch (Y') angle.
    *  \returns time derivative of pitch angle (scalar) with reading access
    */
   inline Scalar y() const {
     return toImplementation()(1);
   }

   /*! \brief Reading access to time derivative of roll (X'') angle.
    *  \returns time derivative of roll angle (scalar) with reading access
    */
   inline Scalar x() const {
     return toImplementation()(2);
   }

   /*! \brief Writing access to time derivative of yaw (Z) angle.
    *  \returns time derivative of yaw angle (scalar) with writing access
    */
   inline Scalar& z() {
     return toImplementation()(0);
   }

   /*! \brief Writing access to time derivative of pitch (Y') angle.
    *  \returns time derivative of pitch angle (scalar) with writing access
    */
   inline Scalar& y() {
     return toImplementation()(1);
   }

   /*! \brief Writing access to time derivative of roll (X'') angle.
    *  \returns time derivative of roll angle (scalar) with writing access
    */
   inline Scalar& x() {
     return toImplementation()(2);
   }

   /*! \brief Sets all time derivatives to zero.
    *  \returns reference
    */
   EulerAnglesZyxDiff& setZero() {
     this->toImplementation().setZero();
     return *this;
   }

   /*! \brief Get zero element.
    *  \returns zero element
    */
   static EulerAnglesZyxDiff Zero() {
     return EulerAnglesZyxDiff(Base::Zero());
   }

   /*! \brief Addition of two angular velocities.
    */
   using RotationDiffBase<EulerAnglesZyxDiff<PrimType_>>::operator+; // otherwise ambiguous EulerAnglesDiffBase and Eigen

   /*! \brief Subtraction of two angular velocities.
    */
   using RotationDiffBase<EulerAnglesZyxDiff<PrimType_>>::operator-; // otherwise ambiguous EulerAnglesDiffBase and Eigen

   /*! \brief Used for printing the object with std::cout.
    *
    *   Prints: yaw pitch roll
    *  \returns std::stream object
    */
   friend std::ostream& operator << (std::ostream& out, const EulerAnglesZyxDiff& diff) {
     out << diff.toImplementation().transpose();
     return out;
   }
};

//! \brief Time derivative of Euler angles with z-y-x convention and primitive type double
typedef EulerAnglesZyxDiff<double> EulerAnglesZyxDiffPD;
//! \brief Time derivative of Euler angles with z-y-x convention and primitive type float
typedef EulerAnglesZyxDiff<float> EulerAnglesZyxDiffPF;
//! \brief Time derivative of Euler angles with z-y-x convention and primitive type double
typedef EulerAnglesZyxDiff<double> EulerAnglesZyxDiffD;
//! \brief Time derivative of Euler angles with z-y-x convention and primitive type float
typedef EulerAnglesZyxDiff<float> EulerAnglesZyxDiffF;

namespace internal {

template<typename PrimType_>
class RotationDiffConversionTraits<EulerAnglesZyxDiff<PrimType_>, LocalAngularVelocity<PrimType_>, EulerAnglesZyx<PrimType_>> {
 public:
  inline static EulerAnglesZyxDiff<PrimType_> convert(const EulerAnglesZyx<PrimType_>& eulerAngles, const LocalAngularVelocity<PrimType_>& angularVelocity) {
    return EulerAnglesZyxDiff<PrimType_>(eulerAngles.getMappingFromLocalAngularVelocityToDiff()*angularVelocity.vector());
  }
};

} // namespace internal
} // namespace kindr

ext: hpp

max_stars_repo_name: mcx/kindr

max_issues_repo_name: mcx/kindr

max_forks_repo_name: mcx/kindr


text:
#include "lexer.hpp"
#include "args-parser.hpp"

#include <exception>
#include <iostream>
#include <map>
#include <regex>

#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

const std::map<TokenType, std::regex> tokenRegexMap {
  { TokenType::WORD, std::regex("(\\b[\\w_][\\w\\d_]*\\b)") },
  { TokenType::SEMICOLON, std::regex("(;)") },
  { TokenType::KW_IMPORT, std::regex("(\\bimport\\b)") },
  { TokenType::COMMA, std::regex("(,)") },
  { TokenType::KW_FROM, std::regex("(\\bfrom\\b)") },
  { TokenType::IMPORT_SOURCE, std::regex("(\"(\\\\[^\\n]|[^\"\\\\\\n])*\")") }, // ("(\\[^\n]|[^"\\\n])*")
  { TokenType::COLON, std::regex("(::)") },
  { TokenType::BASE_TYPE, std::regex("(\\b((u|s)(8|16|32|64))|(f(32|64))\\b)") },
  { TokenType::DECIMAL_LITERAL, std::regex("(\\b-?\\d+\\b)") },
  { TokenType::FLOATING_POINT_LITERAL, std::regex("(\\b(-?\\d+)f|-?\\d+\\.\\d+\\b)") },
  { TokenType::OPEN_BRACKET, std::regex("(\\[)") },
  { TokenType::CLOSE_BRACKET, std::regex("(\\])") },
  { TokenType::EQUALS, std::regex("(=)") },
  { TokenType::PLUS, std::regex("(\\+)") },
  { TokenType::MINUS, std::regex("(-)") },
  { TokenType::MULT, std::regex("(\\*)") },
  { TokenType::DIV, std::regex("(/)") },
  { TokenType::MOD, std::regex("(%)") },
  { TokenType::PLUS_EQ, std::regex("(\\+=)") },
  { TokenType::MINUS_EQ, std::regex("(-=)") },
  { TokenType::MULT_EQ, std::regex("(\\*=)") },
  { TokenType::DIV_EQ, std::regex("(/=)") },
  { TokenType::MOD_EQ, std::regex("(%=)") },
  { TokenType::KW_STRUCT, std::regex("(\\bstruct\\b)") },
  { TokenType::KW_UNION, std::regex("(\\bunion\\b)") },
  { TokenType::PERIOD, std::regex("(\\.)") },
  { TokenType::OPEN_BRACE, std::regex("(\\{)") },
  { TokenType::CLOSE_BRACE, std::regex("(\\})") },
  { TokenType::LINE_COMMENT, std::regex("(//)") },
  { TokenType::OPEN_BLK_CMT, std::regex("(/\\*)") },
  { TokenType::CLOSE_BLK_CMT, std::regex("(\\*/)") },
  { TokenType::OPEN_PAREN, std::regex("(\\()") },
  { TokenType::CLOSE_PAREN, std::regex("(\\))") },
  { TokenType::KW_RETURN, std::regex("(\\breturn\\b)") },
  { TokenType::KW_IF, std::regex("(\\bif\\b)") },
  { TokenType::KW_WHILE, std::regex("(\\bwhile\\b)") },
  { TokenType::DOUBLE_EQ, std::regex("(==)") },
  { TokenType::TRIPLE_EQ, std::regex("(===)") },
  { TokenType::LSS, std::regex("(<)") },
  { TokenType::GTR, std::regex("(>)") },
  { TokenType::LEQ, std::regex("(<=)") },
  { TokenType::GEQ, std::regex("(>=)") },
  { TokenType::WHITESPACE, std::regex("(\\s+)") },
};

std::ostream& operator<< (std::ostream& out, const TokenType& type) {
  switch(type) {
    case TokenType::WORD: out << "WORD"; break;
    case TokenType::SEMICOLON: out << "SEMICOLON"; break;
    case TokenType::KW_IMPORT: out << "KW_IMPORT"; break;
    case TokenType::COMMA: out << "COMMA"; break;
    case TokenType::KW_FROM: out << "KW_FROM"; break;
    case TokenType::IMPORT_SOURCE: out << "IMPORT_SOURCE"; break;
    case TokenType::COLON: out << "COLON"; break;
    case TokenType::BASE_TYPE: out << "BASE_TYPE"; break;
    case TokenType::DECIMAL_LITERAL: out << "DECIMAL_LITERAL"; break;
    case TokenType::FLOATING_POINT_LITERAL: out << "FLOATING_POINT_LITERAL"; break;
    case TokenType::OPEN_BRACKET: out << "OPEN_BRACKET"; break;
    case TokenType::CLOSE_BRACKET: out << "CLOSE_BRACKET"; break;
    case TokenType::EQUALS: out << "EQUALS"; break;
    case TokenType::PLUS: out << "PLUS"; break;
    case TokenType::MINUS: out << "MINUS"; break;
    case TokenType::MULT: out << "MULT"; break;
    case TokenType::DIV: out << "DIV"; break;
    case TokenType::MOD: out << "MOD"; break;
    case TokenType::PLUS_EQ: out << "PLUS_EQ"; break;
    case TokenType::MINUS_EQ: out << "MINUS_EQ"; break;
    case TokenType::MULT_EQ: out << "MULT_EQ"; break;
    case TokenType::DIV_EQ: out << "DIV_EQ"; break;
    case TokenType::MOD_EQ: out << "MOD_EQ"; break;
    case TokenType::KW_STRUCT: out << "KW_STRUCT"; break;
    case TokenType::KW_UNION: out << "KW_UNION"; break;
    case TokenType::PERIOD: out << "PERIOD"; break;
    case TokenType::OPEN_BRACE: out << "OPEN_BRACE"; break;
    case TokenType::CLOSE_BRACE: out << "CLOSE_BRACE"; break;
    case TokenType::LINE_COMMENT: out << "LINE_COMMENT"; break;
    case TokenType::OPEN_BLK_CMT: out << "OPEN_BLK_CMT"; break;
    case TokenType::CLOSE_BLK_CMT: out << "CLOSE_BLK_CMT"; break;
    case TokenType::OPEN_PAREN: out << "OPEN_PAREN"; break;
    case TokenType::CLOSE_PAREN: out << "CLOSE_PAREN"; break;
    case TokenType::KW_RETURN: out << "KW_RETURN"; break;
    case TokenType::KW_IF: out << "KW_IF"; break;
    case TokenType::KW_WHILE: out << "KW_WHILE"; break;
    case TokenType::DOUBLE_EQ: out << "DOUBLE_EQ"; break;
    case TokenType::TRIPLE_EQ: out << "TRIPLE_EQ"; break;
    case TokenType::LSS: out << "LSS"; break;
    case TokenType::GTR: out << "GTR"; break;
    case TokenType::LEQ: out << "LEQ"; break;
    case TokenType::GEQ: out << "GEQ"; break;
    case TokenType::WHITESPACE: out << "WHITESPACE"; break;
    default: out << "FATAL ERROR: UNKNOWN TOKEN TYPE: " << static_cast<int>(type) << std::endl; throw new std::runtime_error("no stringification for token type!");
  }
  return out;
}

//    (^[^\S\n]*\/\/[^\n]*)|(\/\*(\*(?!\/)|[^*]|[\n])*\*\/)
// const std::regex COMMENT_REGEX("^[^\\S\\n]*((//)|(\\/\\*(\\*(?!\\/)|[^*]|[\\n])*\\*\\/))[^\\n]*$");

//    (\s(?!(?<="((\\[^\n]|[^"\\\n])*))((\\[^\n]|[^"\\\n])*)"))
// const std::regex NON_STRING_SPACE_REGEX

Lexer::Lexer(Options &options) {
  assert(tokenRegexMap.size() == TokenType::NUM_TOKEN_TYPES && "Must define regex for every token type!");
}

//

bool Lexer::validateOptionsAndSource(std::string sourceCode) {
  if (sourceCode.empty()) {
    std::cout << "Cannot lex empty file!" << std::endl;
    return false;
  }
  return true;
}

std::string Lexer::preprocessSource(std::string processed) {
  processed = std::regex_replace(processed, std::regex{"\\\\[^\\S\\n]*\\n"}, " "); // replace \\n with ` `
  processed = std::regex_replace(processed, std::regex{"\\n+"}, "\n"); // replace multiple \n with single `\n`
  return processed;
}

typedef std::match_results<std::string::iterator>::value_type lexing_match;

LexerResult Lexer::run(std::string sourceCode, std::vector<Token> &resultTokens) {
  if (!validateOptionsAndSource(sourceCode)) {
    return LexerResult::INVALID_LEXING_OPTIONS;
  }

  std::string processedSource = preprocessSource(sourceCode);

  auto sourceBegin = processedSource.begin();
  auto sourceEnd = processedSource.end();

  while (sourceBegin != sourceEnd) {
    // std::cout << "Finding token for index: " << sourceBegin - processedSource.begin() << "\n\tSource: " << processedSource.substr(sourceBegin-processedSource.begin(), 10) << std::endl;
    TokenType longestMatchType = TokenType::NUM_TOKEN_TYPES;
    lexing_match longestMatch;
    for (auto tokenRegex : tokenRegexMap) {
      auto regex = tokenRegex.second;
      if (tokenRegex.first == TokenType::NUM_TOKEN_TYPES) {
        std::cout << "\tNo matches found, collecting bad token..." << std::endl;
        regex = std::regex{"(^\\B+)"};
      }
      std::match_results<std::string::iterator> match_result;

      bool hasMatch = std::regex_search(
        sourceBegin, sourceEnd, // match starting at beginning of unmatched portion
        match_result, regex, // save result based on applied regex
        std::regex_constants::match_continuous); // ensure match starts at `sourceBegin`
      if (!hasMatch) { // no match_result found for this regex
        // std::cout << "\tNo match for type: " << tokenRegex.first << std::endl;
        continue;
      }
      lexing_match match = match_result[0];
      // std::cout << "\tFound match! Type: " << tokenRegex.first << std::endl;
      size_t matchLen = match.length();
      if (tokenRegex.first == TokenType::NUM_TOKEN_TYPES) {
        std::cout << "Invalid token found!\n\tLocation: " << sourceBegin-processedSource.begin() << "\n\tToken: " << match.str() << "\n";
        return LexerResult::INVALID_TOKENS;
      }
      if (matchLen > longestMatch.length()) {
        longestMatchType = tokenRegex.first;
        longestMatch = match;
      }
    }
    if (longestMatchType == TokenType::NUM_TOKEN_TYPES) {
      std::cout << "FATAL LEXING ERROR!\n";
      return LexerResult::INVALID_TOKENS;
    }
    // std::cout << "Register token{" << longestMatchType << "}: `" << longestMatch.str() << "`" << std::endl;
    resultTokens.push_back(Token{longestMatch.str(), longestMatchType});
    sourceBegin += longestMatch.length();
  }

  return LexerResult::LEXING_SUCCESS;
}


text:
/*
 * pacific_connect.cc
 *
 *  Created on: 27/07/2019
 *      Author: Ajo Robert
 */

#include <iostream>
#include "serial_interface.h"
#include "data_manager.h"
#include <boost/thread.hpp>

static DataManager *manager;
#define	TIMER_DRIFT_CORRECTION_LOOP 6

void DisplayLoop() {
	boost::posix_time::ptime timeLocal = boost::posix_time::second_clock::local_time();
	int counter = TIMER_DRIFT_CORRECTION_LOOP;

	/* Findout the time needed to hit a 10 Second boundary. */
	int remaining = 10 - (timeLocal.time_of_day().seconds() % 10);
	sleep (remaining);
	while (1) {
		manager->PrintRecord();
		--counter;

		if (counter == 0) {
			/* Adjust the timer. */
			boost::posix_time::ptime timeLocal = boost::posix_time::second_clock::local_time();
			/* Findout the time needed to hit a 10 Second boundary. */
			remaining = 10 - (timeLocal.time_of_day().seconds() % 10);
			counter = TIMER_DRIFT_CORRECTION_LOOP;
		} else {
			/* Assume we are at 10 second boundary and sleep for another 10s. */
			remaining = 10;
		}
		boost::this_thread::sleep_for(boost::chrono::seconds(remaining));
	}
}

void DisplayTimer() {
	try {
		DisplayLoop();
	} catch (...) {
		return;
	}
}

int main(int argc, char* argv[]) {
	if (argc != 2) {
		std::cout << "Invalid use of the application. Please specify the serial interface as an argument.";
		std::cout << std::endl;
		return -1;
	}
	DeviceInterface *device = new SerialInterface(argv[1]);
	if (!device){
		std::cout << "Serial interface init failed." << std::endl;
		return -1;
	}

	manager = new DataManager(device);
	if (!manager){
		std::cout << "Data manager module init failed." << std::endl;
		return -1;
	}

	boost::thread timer = boost::thread(DisplayTimer);

	try {
		while (manager->ReadRecord() == 0);
	} catch (...) {
		std::cout << "There is an error while processing stream." << std::endl;
	}

	/* close the timer loop. */
	timer.interrupt();
	timer.join();

	return 0;
}

ext: cc

max_stars_repo_name: ajorobert/PacificConnect

max_issues_repo_name: ajorobert/PacificConnect

max_forks_repo_name: ajorobert/PacificConnect