<commit_before>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "base58.h"
#include "init.h"
#include "main.h"
#include "net.h"
#include "netbase.h"
#include "rpcserver.h"
#include "timedata.h"
#include "util.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
#include "walletdb.h"
#endif

#include <stdint.h>

#include <boost/assign/list_of.hpp>
#include "json/json_spirit_utils.h"
#include "json/json_spirit_value.h"

using namespace boost;
using namespace boost::assign;
using namespace json_spirit;
using namespace std;

Value getinfo(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getinfo\n"
            "Returns an object containing various state info.\n"
            "\nResult:\n"
            "{\n"
            "  \"version\": xxxxx,           (numeric) the server version\n"
            "  \"protocolversion\": xxxxx,   (numeric) the protocol version\n"
            "  \"walletversion\": xxxxx,     (numeric) the wallet version\n"
            "  \"balance\": xxxxxxx,         (numeric) the total bitcoin balance of the wallet\n"
            "  \"blocks\": xxxxxx,           (numeric) the current number of blocks processed in the server\n"
            "  \"timeoffset\": xxxxx,        (numeric) the time offset\n"
            "  \"connections\": xxxxx,       (numeric) the number of connections\n"
            "  \"proxy\": \"host:port\",     (string, optional) the proxy used by the server\n"
            "  \"difficulty\": xxxxxx,       (numeric) the current difficulty\n"
            "  \"testnet\": true|false,      (boolean) if the server is using testnet or not\n"
            "  \"keypoololdest\": xxxxxx,    (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
            "  \"keypoolsize\": xxxx,        (numeric) how many new keys are pre-generated\n"
            "  \"unlocked_until\": ttt,      (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
            "  \"paytxfee\": x.xxxx,         (numeric) the transaction fee set in btc/kb\n"
            "  \"relayfee\": x.xxxx,         (numeric) minimum relay fee for non-free transactions in btc/kb\n"
            "  \"errors\": \"...\"           (string) any error messages\n"
            "}\n"
            "\nExamples:\n"
            + HelpExampleCli("getinfo", "")
            + HelpExampleRpc("getinfo", "")
        );

    proxyType proxy;
    GetProxy(NET_IPV4, proxy);

    Object obj;
    obj.push_back(Pair("version",       (int)CLIENT_VERSION));
    obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
#ifdef ENABLE_WALLET
    if (pwalletMain) {
        obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
        obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
    }
#endif
    obj.push_back(Pair("blocks",        (int)chainActive.Height()));
    obj.push_back(Pair("timeoffset",    GetTimeOffset()));
    obj.push_back(Pair("connections",   (int)vNodes.size()));
    obj.push_back(Pair("proxy",         (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
    obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
    obj.push_back(Pair("testnet",       Params().NetworkID() == CBaseChainParams::TESTNET));
#ifdef ENABLE_WALLET
    if (pwalletMain) {
        obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
        obj.push_back(Pair("keypoolsize",   (int)pwalletMain->GetKeyPoolSize()));
    }
    if (pwalletMain && pwalletMain->IsCrypted())
        obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
    obj.push_back(Pair("paytxfee",      ValueFromAmount(payTxFee.GetFeePerK())));
#endif
    obj.push_back(Pair("relayfee",      ValueFromAmount(CTransaction::minRelayTxFee.GetFeePerK())));
    obj.push_back(Pair("errors",        GetWarnings("statusbar")));
    return obj;
}

#ifdef ENABLE_WALLET
class DescribeAddressVisitor : public boost::static_visitor<Object>
{
private:
    isminetype mine;

public:
    DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}

    Object operator()(const CNoDestination &dest) const { return Object(); }

    Object operator()(const CKeyID &keyID) const {
        Object obj;
        CPubKey vchPubKey;
        obj.push_back(Pair("isscript", false));
        if (mine == MINE_SPENDABLE) {
            pwalletMain->GetPubKey(keyID, vchPubKey);
            obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
            obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
        }
        return obj;
    }

    Object operator()(const CScriptID &scriptID) const {
        Object obj;
        obj.push_back(Pair("isscript", true));
        if (mine == MINE_SPENDABLE) {
            CScript subscript;
            pwalletMain->GetCScript(scriptID, subscript);
            std::vector<CTxDestination> addresses;
            txnouttype whichType;
            int nRequired;
            ExtractDestinations(subscript, whichType, addresses, nRequired);
            obj.push_back(Pair("script", GetTxnOutputType(whichType)));
            obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
            Array a;
            BOOST_FOREACH(const CTxDestination& addr, addresses)
                a.push_back(CBitcoinAddress(addr).ToString());
            obj.push_back(Pair("addresses", a));
            if (whichType == TX_MULTISIG)
                obj.push_back(Pair("sigsrequired", nRequired));
        }
        return obj;
    }
};
#endif

Value validateaddress(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "validateaddress \"bitcoinaddress\"\n"
            "\nReturn information about the given bitcoin address.\n"
            "\nArguments:\n"
            "1. \"bitcoinaddress\"     (string, required) The bitcoin address to validate\n"
            "\nResult:\n"
            "{\n"
            "  \"isvalid\" : true|false,         (boolean) If the address is valid or not. If not, this is the only property returned.\n"
            "  \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n"
            "  \"ismine\" : true|false,          (boolean) If the address is yours or not\n"
            "  \"isscript\" : true|false,        (boolean) If the key is a script\n"
            "  \"pubkey\" : \"publickeyhex\",    (string) The hex value of the raw public key\n"
            "  \"iscompressed\" : true|false,    (boolean) If the address is compressed\n"
            "  \"account\" : \"account\"         (string) The account associated with the address, \"\" is the default account\n"
            "}\n"
            "\nExamples:\n"
            + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
            + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
        );

    CBitcoinAddress address(params[0].get_str());
    bool isValid = address.IsValid();

    Object ret;
    ret.push_back(Pair("isvalid", isValid));
    if (isValid)
    {
        CTxDestination dest = address.Get();
        string currentAddress = address.ToString();
        ret.push_back(Pair("address", currentAddress));
#ifdef ENABLE_WALLET
        isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : MINE_NO;
        ret.push_back(Pair("ismine", (mine & MINE_SPENDABLE) ? true : false));
        if (mine != MINE_NO) {
            ret.push_back(Pair("iswatchonly", (mine & MINE_WATCH_ONLY) ? true: false));
            Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
            ret.insert(ret.end(), detail.begin(), detail.end());
        }
        if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
            ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
#endif
    }
    return ret;
}

//
// Used by addmultisigaddress / createmultisig:
//
CScript _createmultisig_redeemScript(const Array& params)
{
    int nRequired = params[0].get_int();
    const Array& keys = params[1].get_array();

    // Gather public keys
    if (nRequired < 1)
        throw runtime_error("a multisignature address must require at least one key to redeem");
    if ((int)keys.size() < nRequired)
        throw runtime_error(
            strprintf("not enough keys supplied "
                      "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired));
    std::vector<CPubKey> pubkeys;
    pubkeys.resize(keys.size());
    for (unsigned int i = 0; i < keys.size(); i++)
    {
        const std::string& ks = keys[i].get_str();
#ifdef ENABLE_WALLET
        // Case 1: Bitcoin address and we have full public key:
        CBitcoinAddress address(ks);
        if (pwalletMain && address.IsValid())
        {
            CKeyID keyID;
            if (!address.GetKeyID(keyID))
                throw runtime_error(
                    strprintf("%s does not refer to a key",ks));
            CPubKey vchPubKey;
            if (!pwalletMain->GetPubKey(keyID, vchPubKey))
                throw runtime_error(
                    strprintf("no full public key for address %s",ks));
            if (!vchPubKey.IsFullyValid())
                throw runtime_error(" Invalid public key: "+ks);
            pubkeys[i] = vchPubKey;
        }

        // Case 2: hex public key
        else
#endif
        if (IsHex(ks))
        {
            CPubKey vchPubKey(ParseHex(ks));
            if (!vchPubKey.IsFullyValid())
                throw runtime_error(" Invalid public key: "+ks);
            pubkeys[i] = vchPubKey;
        }
        else
        {
            throw runtime_error(" Invalid public key: "+ks);
        }
    }
    CScript result;
    result.SetMultisig(nRequired, pubkeys);

    if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)
        throw runtime_error(
                strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE));

    return result;
}

Value createmultisig(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 2 || params.size() > 2)
    {
        string msg = "createmultisig nrequired [\"key\",...]\n"
            "\nCreates a multi-signature address with n signature of m keys required.\n"
            "It returns a json object with the address and redeemScript.\n"

            "\nArguments:\n"
            "1. nrequired      (numeric, required) The number of required signatures out of the n keys or addresses.\n"
            "2. \"keys\"       (string, required) A json array of keys which are bitcoin addresses or hex-encoded public keys\n"
            "     [\n"
            "       \"key\"    (string) bitcoin address or hex-encoded public key\n"
            "       ,...\n"
            "     ]\n"

            "\nResult:\n"
            "{\n"
            "  \"address\":\"multisigaddress\",  (string) The value of the new multisig address.\n"
            "  \"redeemScript\":\"script\"       (string) The string value of the hex-encoded redemption script.\n"
            "}\n"

            "\nExamples:\n"
            "\nCreate a multisig address from 2 addresses\n"
            + HelpExampleCli("createmultisig", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
            "\nAs a json rpc call\n"
            + HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
        ;
        throw runtime_error(msg);
    }

    // Construct using pay-to-script-hash:
    CScript inner = _createmultisig_redeemScript(params);
    CScriptID innerID = inner.GetID();
    CBitcoinAddress address(innerID);

    Object result;
    result.push_back(Pair("address", address.ToString()));
    result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));

    return result;
}

Value verifymessage(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 3)
        throw runtime_error(
            "verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n"
            "\nVerify a signed message\n"
            "\nArguments:\n"
            "1. \"bitcoinaddress\"  (string, required) The bitcoin address to use for the signature.\n"
            "2. \"signature\"       (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n"
            "3. \"message\"         (string, required) The message that was signed.\n"
            "\nResult:\n"
            "true|false   (boolean) If the signature is verified or not.\n"
            "\nExamples:\n"
            "\nUnlock the wallet for 30 seconds\n"
            + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
            "\nCreate the signature\n"
            + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
            "\nVerify the signature\n"
            + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
            "\nAs json rpc\n"
            + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
        );

    string strAddress  = params[0].get_str();
    string strSign     = params[1].get_str();
    string strMessage  = params[2].get_str();

    CBitcoinAddress addr(strAddress);
    if (!addr.IsValid())
        throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");

    CKeyID keyID;
    if (!addr.GetKeyID(keyID))
        throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");

    bool fInvalid = false;
    vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);

    if (fInvalid)
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");

    CHashWriter ss(SER_GETHASH, 0);
    ss << strMessageMagic;
    ss << strMessage;

    CPubKey pubkey;
    if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
        return false;

    return (pubkey.GetID() == keyID);
}
<commit_msg>fixed bug where validateaddress doesn't display information<commit_after>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "base58.h"
#include "init.h"
#include "main.h"
#include "net.h"
#include "netbase.h"
#include "rpcserver.h"
#include "timedata.h"
#include "util.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
#include "walletdb.h"
#endif

#include <stdint.h>

#include <boost/assign/list_of.hpp>
#include "json/json_spirit_utils.h"
#include "json/json_spirit_value.h"

using namespace boost;
using namespace boost::assign;
using namespace json_spirit;
using namespace std;

Value getinfo(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getinfo\n"
            "Returns an object containing various state info.\n"
            "\nResult:\n"
            "{\n"
            "  \"version\": xxxxx,           (numeric) the server version\n"
            "  \"protocolversion\": xxxxx,   (numeric) the protocol version\n"
            "  \"walletversion\": xxxxx,     (numeric) the wallet version\n"
            "  \"balance\": xxxxxxx,         (numeric) the total bitcoin balance of the wallet\n"
            "  \"blocks\": xxxxxx,           (numeric) the current number of blocks processed in the server\n"
            "  \"timeoffset\": xxxxx,        (numeric) the time offset\n"
            "  \"connections\": xxxxx,       (numeric) the number of connections\n"
            "  \"proxy\": \"host:port\",     (string, optional) the proxy used by the server\n"
            "  \"difficulty\": xxxxxx,       (numeric) the current difficulty\n"
            "  \"testnet\": true|false,      (boolean) if the server is using testnet or not\n"
            "  \"keypoololdest\": xxxxxx,    (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
            "  \"keypoolsize\": xxxx,        (numeric) how many new keys are pre-generated\n"
            "  \"unlocked_until\": ttt,      (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
            "  \"paytxfee\": x.xxxx,         (numeric) the transaction fee set in btc/kb\n"
            "  \"relayfee\": x.xxxx,         (numeric) minimum relay fee for non-free transactions in btc/kb\n"
            "  \"errors\": \"...\"           (string) any error messages\n"
            "}\n"
            "\nExamples:\n"
            + HelpExampleCli("getinfo", "")
            + HelpExampleRpc("getinfo", "")
        );

    proxyType proxy;
    GetProxy(NET_IPV4, proxy);

    Object obj;
    obj.push_back(Pair("version",       (int)CLIENT_VERSION));
    obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
#ifdef ENABLE_WALLET
    if (pwalletMain) {
        obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
        obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
    }
#endif
    obj.push_back(Pair("blocks",        (int)chainActive.Height()));
    obj.push_back(Pair("timeoffset",    GetTimeOffset()));
    obj.push_back(Pair("connections",   (int)vNodes.size()));
    obj.push_back(Pair("proxy",         (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
    obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
    obj.push_back(Pair("testnet",       Params().NetworkID() == CBaseChainParams::TESTNET));
#ifdef ENABLE_WALLET
    if (pwalletMain) {
        obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
        obj.push_back(Pair("keypoolsize",   (int)pwalletMain->GetKeyPoolSize()));
    }
    if (pwalletMain && pwalletMain->IsCrypted())
        obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
    obj.push_back(Pair("paytxfee",      ValueFromAmount(payTxFee.GetFeePerK())));
#endif
    obj.push_back(Pair("relayfee",      ValueFromAmount(CTransaction::minRelayTxFee.GetFeePerK())));
    obj.push_back(Pair("errors",        GetWarnings("statusbar")));
    return obj;
}

#ifdef ENABLE_WALLET
class DescribeAddressVisitor : public boost::static_visitor<Object>
{
private:
    isminetype mine;

public:
    DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}

    Object operator()(const CNoDestination &dest) const { return Object(); }

    Object operator()(const CKeyID &keyID) const {
        Object obj;
        CPubKey vchPubKey;
        obj.push_back(Pair("isscript", false));
        if (mine == MINE_SPENDABLE) {
            pwalletMain->GetPubKey(keyID, vchPubKey);
            obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
            obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
        }
        return obj;
    }

    Object operator()(const CScriptID &scriptID) const {
        Object obj;
        obj.push_back(Pair("isscript", true));
        if (mine != MINE_NO) {
            CScript subscript;
            pwalletMain->GetCScript(scriptID, subscript);
            std::vector<CTxDestination> addresses;
            txnouttype whichType;
            int nRequired;
            ExtractDestinations(subscript, whichType, addresses, nRequired);
            obj.push_back(Pair("script", GetTxnOutputType(whichType)));
            obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
            Array a;
            BOOST_FOREACH(const CTxDestination& addr, addresses)
                a.push_back(CBitcoinAddress(addr).ToString());
            obj.push_back(Pair("addresses", a));
            if (whichType == TX_MULTISIG)
                obj.push_back(Pair("sigsrequired", nRequired));
        }
        return obj;
    }
};
#endif

Value validateaddress(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "validateaddress \"bitcoinaddress\"\n"
            "\nReturn information about the given bitcoin address.\n"
            "\nArguments:\n"
            "1. \"bitcoinaddress\"     (string, required) The bitcoin address to validate\n"
            "\nResult:\n"
            "{\n"
            "  \"isvalid\" : true|false,         (boolean) If the address is valid or not. If not, this is the only property returned.\n"
            "  \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n"
            "  \"ismine\" : true|false,          (boolean) If the address is yours or not\n"
            "  \"isscript\" : true|false,        (boolean) If the key is a script\n"
            "  \"pubkey\" : \"publickeyhex\",    (string) The hex value of the raw public key\n"
            "  \"iscompressed\" : true|false,    (boolean) If the address is compressed\n"
            "  \"account\" : \"account\"         (string) The account associated with the address, \"\" is the default account\n"
            "}\n"
            "\nExamples:\n"
            + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
            + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
        );

    CBitcoinAddress address(params[0].get_str());
    bool isValid = address.IsValid();

    Object ret;
    ret.push_back(Pair("isvalid", isValid));
    if (isValid)
    {
        CTxDestination dest = address.Get();
        string currentAddress = address.ToString();
        ret.push_back(Pair("address", currentAddress));
#ifdef ENABLE_WALLET
        isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : MINE_NO;
        ret.push_back(Pair("ismine", (mine & MINE_SPENDABLE) ? true : false));
        if (mine != MINE_NO) {
            ret.push_back(Pair("iswatchonly", (mine & MINE_WATCH_ONLY) ? true: false));
            Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
            ret.insert(ret.end(), detail.begin(), detail.end());
        }
        if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
            ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
#endif
    }
    return ret;
}

//
// Used by addmultisigaddress / createmultisig:
//
CScript _createmultisig_redeemScript(const Array& params)
{
    int nRequired = params[0].get_int();
    const Array& keys = params[1].get_array();

    // Gather public keys
    if (nRequired < 1)
        throw runtime_error("a multisignature address must require at least one key to redeem");
    if ((int)keys.size() < nRequired)
        throw runtime_error(
            strprintf("not enough keys supplied "
                      "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired));
    std::vector<CPubKey> pubkeys;
    pubkeys.resize(keys.size());
    for (unsigned int i = 0; i < keys.size(); i++)
    {
        const std::string& ks = keys[i].get_str();
#ifdef ENABLE_WALLET
        // Case 1: Bitcoin address and we have full public key:
        CBitcoinAddress address(ks);
        if (pwalletMain && address.IsValid())
        {
            CKeyID keyID;
            if (!address.GetKeyID(keyID))
                throw runtime_error(
                    strprintf("%s does not refer to a key",ks));
            CPubKey vchPubKey;
            if (!pwalletMain->GetPubKey(keyID, vchPubKey))
                throw runtime_error(
                    strprintf("no full public key for address %s",ks));
            if (!vchPubKey.IsFullyValid())
                throw runtime_error(" Invalid public key: "+ks);
            pubkeys[i] = vchPubKey;
        }

        // Case 2: hex public key
        else
#endif
        if (IsHex(ks))
        {
            CPubKey vchPubKey(ParseHex(ks));
            if (!vchPubKey.IsFullyValid())
                throw runtime_error(" Invalid public key: "+ks);
            pubkeys[i] = vchPubKey;
        }
        else
        {
            throw runtime_error(" Invalid public key: "+ks);
        }
    }
    CScript result;
    result.SetMultisig(nRequired, pubkeys);

    if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)
        throw runtime_error(
                strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE));

    return result;
}

Value createmultisig(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 2 || params.size() > 2)
    {
        string msg = "createmultisig nrequired [\"key\",...]\n"
            "\nCreates a multi-signature address with n signature of m keys required.\n"
            "It returns a json object with the address and redeemScript.\n"

            "\nArguments:\n"
            "1. nrequired      (numeric, required) The number of required signatures out of the n keys or addresses.\n"
            "2. \"keys\"       (string, required) A json array of keys which are bitcoin addresses or hex-encoded public keys\n"
            "     [\n"
            "       \"key\"    (string) bitcoin address or hex-encoded public key\n"
            "       ,...\n"
            "     ]\n"

            "\nResult:\n"
            "{\n"
            "  \"address\":\"multisigaddress\",  (string) The value of the new multisig address.\n"
            "  \"redeemScript\":\"script\"       (string) The string value of the hex-encoded redemption script.\n"
            "}\n"

            "\nExamples:\n"
            "\nCreate a multisig address from 2 addresses\n"
            + HelpExampleCli("createmultisig", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
            "\nAs a json rpc call\n"
            + HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
        ;
        throw runtime_error(msg);
    }

    // Construct using pay-to-script-hash:
    CScript inner = _createmultisig_redeemScript(params);
    CScriptID innerID = inner.GetID();
    CBitcoinAddress address(innerID);

    Object result;
    result.push_back(Pair("address", address.ToString()));
    result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));

    return result;
}

Value verifymessage(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 3)
        throw runtime_error(
            "verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n"
            "\nVerify a signed message\n"
            "\nArguments:\n"
            "1. \"bitcoinaddress\"  (string, required) The bitcoin address to use for the signature.\n"
            "2. \"signature\"       (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n"
            "3. \"message\"         (string, required) The message that was signed.\n"
            "\nResult:\n"
            "true|false   (boolean) If the signature is verified or not.\n"
            "\nExamples:\n"
            "\nUnlock the wallet for 30 seconds\n"
            + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
            "\nCreate the signature\n"
            + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
            "\nVerify the signature\n"
            + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
            "\nAs json rpc\n"
            + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
        );

    string strAddress  = params[0].get_str();
    string strSign     = params[1].get_str();
    string strMessage  = params[2].get_str();

    CBitcoinAddress addr(strAddress);
    if (!addr.IsValid())
        throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");

    CKeyID keyID;
    if (!addr.GetKeyID(keyID))
        throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");

    bool fInvalid = false;
    vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);

    if (fInvalid)
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");

    CHashWriter ss(SER_GETHASH, 0);
    ss << strMessageMagic;
    ss << strMessage;

    CPubKey pubkey;
    if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
        return false;

    return (pubkey.GetID() == keyID);
}
<|endoftext|>


<commit_before>/**
 * @file s3Helper.cc
 * @author Krzysztof Trzepla
 * @copyright (C) 2015 ACK CYFRONET AGH
 * @copyright This software is released under the MIT license cited in
 * 'LICENSE.txt'
 */

#include "s3Helper.h"
#include "logging.h"

#include <algorithm>
#include <ctime>
#include <functional>
#include <sstream>
#include <vector>

namespace one {
namespace helpers {

std::mutex S3Helper::s_mutex{};

const std::map<int, error_t> S3Helper::s_errorsTranslation = {
    {S3StatusOutOfMemory, makePosixError(std::errc::not_enough_memory)},
    {S3StatusInterrupted, makePosixError(std::errc::interrupted)},
    {S3StatusConnectionFailed, makePosixError(std::errc::connection_refused)},
    {S3StatusErrorAccessDenied, makePosixError(std::errc::permission_denied)},
    {S3StatusErrorInvalidArgument, makePosixError(std::errc::invalid_argument)},
    {S3StatusErrorNoSuchKey,
        makePosixError(std::errc::no_such_file_or_directory)},
    {S3StatusHttpErrorNotFound,
        makePosixError(std::errc::no_such_file_or_directory)},
    {S3StatusErrorNotImplemented, makePosixError(std::errc::not_supported)},
    {S3StatusErrorOperationAborted,
        makePosixError(std::errc::connection_aborted)},
    {S3StatusErrorRequestTimeout, makePosixError(std::errc::timed_out)},
    {S3StatusHttpErrorForbidden, makePosixError(std::errc::permission_denied)}};

S3Helper::S3Helper(std::unordered_map<std::string, std::string> args,
    asio::io_service &service)
    : m_service{service}
    , m_args{std::move(args)}
{
    std::lock_guard<std::mutex> guard{s_mutex};
    S3_initialize(nullptr, S3_INIT_ALL, nullptr);
}

S3Helper::~S3Helper() { S3_deinitialize(); }

CTXPtr S3Helper::createCTX() { return std::make_shared<S3HelperCTX>(m_args); }

void S3Helper::ash_unlink(
    CTXPtr rawCTX, const boost::filesystem::path &p, VoidCallback callback)
{
    auto ctx = getCTX(std::move(rawCTX));
    auto fileId = p.string();

    asio::post(m_service,
        [
          this,
          ctx = std::move(ctx),
          fileId = std::move(fileId),
          callback = std::move(callback)
        ]() {
            try {
                sh_unlink(*ctx, fileId);
                callback(SUCCESS_CODE);
            }
            catch (const std::system_error &e) {
                callback(e.code());
            }
        });
}

void S3Helper::ash_read(CTXPtr rawCTX, const boost::filesystem::path &p,
    asio::mutable_buffer buf, off_t offset,
    GeneralCallback<asio::mutable_buffer> callback)
{
    auto ctx = getCTX(std::move(rawCTX));
    auto fileId = p.string();

    asio::post(m_service,
        [
          =,
          ctx = std::move(ctx),
          buf = std::move(buf),
          fileId = std::move(fileId),
          callback = std::move(callback)
        ]() mutable {
            try {
                callback(sh_read(*ctx, fileId, std::move(buf), offset),
                    SUCCESS_CODE);
            }
            catch (const std::system_error &e) {
                callback(asio::mutable_buffer{}, e.code());
            }
        });
}

void S3Helper::ash_write(CTXPtr rawCTX, const boost::filesystem::path &p,
    asio::const_buffer buf, off_t offset, GeneralCallback<std::size_t> callback)
{
    auto ctx = getCTX(std::move(rawCTX));
    auto fileId = p.string();

    asio::post(m_service,
        [
          =,
          ctx = std::move(ctx),
          buf = std::move(buf),
          fileId = std::move(fileId),
          callback = std::move(callback)
        ]() mutable {
            try {
                callback(sh_write(*ctx, fileId, std::move(buf), offset),
                    SUCCESS_CODE);
            }
            catch (const std::system_error &e) {
                callback(0, e.code());
            }
        });
}

void S3Helper::ash_truncate(CTXPtr rawCTX, const boost::filesystem::path &p,
    off_t size, VoidCallback callback)
{
    auto ctx = getCTX(std::move(rawCTX));
    auto fileId = p.string();

    asio::post(m_service,
        [
          =,
          ctx = std::move(ctx),
          fileId = std::move(fileId),
          callback = std::move(callback)
        ]() {
            try {
                sh_truncate(*ctx, fileId, size);
                callback(SUCCESS_CODE);
            }
            catch (const std::system_error &e) {
                callback(e.code());
            }
        });
}

void S3Helper::sh_unlink(const S3HelperCTX &ctx, const std::string &fileId)
{
    S3ResponseHandler responseHandler;
    responseHandler.propertiesCallback = [](
        const S3ResponseProperties *properties, void *callbackData) {
        return S3StatusOK;
    };
    responseHandler.completeCallback = [](S3Status status,
        const S3ErrorDetails *errorDetails, void *callbackData) {
        if (status != S3StatusOK)
            throwPosixError("sh_unlink", status, errorDetails);
    };

    S3_delete_object(
        &ctx.bucketCTX, fileId.c_str(), nullptr, &responseHandler, nullptr);
}

asio::mutable_buffer S3Helper::sh_read(const S3HelperCTX &ctx,
    const std::string &fileId, asio::mutable_buffer buf, off_t offset)
{
    struct CallbackData {
        std::size_t size = 0;
        asio::mutable_buffer buffer;
    } data;
    data.buffer = std::move(buf);

    S3GetObjectHandler getObjectHandler;
    getObjectHandler.responseHandler = S3ResponseHandler{};
    getObjectHandler.responseHandler.propertiesCallback = [](
        const S3ResponseProperties *properties, void *callbackData) {
        return S3StatusOK;
    };
    getObjectHandler.responseHandler.completeCallback = [](S3Status status,
        const S3ErrorDetails *errorDetails, void *callbackData) {
        if (status != S3StatusOK)
            throwPosixError("sh_read", status, errorDetails);
    };
    getObjectHandler.getObjectDataCallback = [](
        int bufferSize, const char *buffer, void *callbackData) {
        auto dataPtr = static_cast<CallbackData *>(callbackData);
        std::memcpy(asio::buffer_cast<char *>(dataPtr->buffer) + dataPtr->size,
            buffer, bufferSize);
        dataPtr->size += bufferSize;
        return S3StatusOK;
    };

    S3_get_object(&ctx.bucketCTX, fileId.c_str(), nullptr, offset,
        asio::buffer_size(data.buffer), nullptr, &getObjectHandler,
        static_cast<void *>(&data));

    return asio::buffer(data.buffer, data.size);
}

std::size_t S3Helper::sh_write(const S3HelperCTX &ctx,
    const std::string &fileId, asio::const_buffer buf, off_t offset)
{
    std::size_t fileSize = 0;
    try {
        fileSize = sh_getFileSize(ctx, fileId);
    }
    catch (const std::system_error &e) {
        if (e.code() != makePosixError(std::errc::no_such_file_or_directory))
            throw;
    }
    return sh_write(ctx, fileId, std::move(buf), offset, fileSize);
}

std::size_t S3Helper::sh_write(const S3HelperCTX &ctx,
    const std::string &fileId, asio::const_buffer buf, off_t offset,
    std::size_t fileSize)
{
    struct CallbackData {
        CallbackData(const std::string &_fileId, const S3HelperCTX &_helperCTX,
            S3Helper &_helper)
            : fileId{_fileId}
            , helperCTX{_helperCTX}
            , helper{_helper}
        {
        }

        off_t offset = 0;
        std::size_t fileSize;
        off_t bufferOffset;
        std::size_t bufferSize;
        asio::const_buffer buffer;
        const std::string &fileId;
        const S3HelperCTX &helperCTX;
        S3Helper &helper;
    };

    CallbackData data{fileId, ctx, *this};
    data.fileSize = fileSize;
    data.bufferOffset = offset;
    data.bufferSize = asio::buffer_size(buf);
    data.buffer = std::move(buf);

    auto tmpFileId = temporaryFileId(fileId);
    auto newFileSize =
        std::max(data.fileSize, data.bufferOffset + data.bufferSize);
    S3PutObjectHandler putObjectHandler;
    putObjectHandler.responseHandler = S3ResponseHandler{};
    putObjectHandler.responseHandler.propertiesCallback = [](
        const S3ResponseProperties *properties, void *callbackData) {
        return S3StatusOK;
    };
    putObjectHandler.responseHandler.completeCallback = [](S3Status status,
        const S3ErrorDetails *errorDetails, void *callbackData) {
        if (status != S3StatusOK)
            throwPosixError("sh_write", status, errorDetails);
    };
    putObjectHandler.putObjectDataCallback = [](
        int bufferSize, char *buffer, void *callbackData) {
        auto dataPtr = static_cast<CallbackData *>(callbackData);

        auto srcBufBegin = static_cast<std::size_t>(dataPtr->bufferOffset);
        auto srcBufEnd = srcBufBegin + dataPtr->bufferSize;
        auto dstBufBegin = static_cast<std::size_t>(dataPtr->offset);
        auto dstBufEnd = dstBufBegin + static_cast<std::size_t>(bufferSize);
        auto commonBegin = std::max(srcBufBegin, dstBufBegin);
        auto commonEnd = std::min(srcBufEnd, dstBufEnd);

        std::memset(buffer, 0, bufferSize);

        if (dstBufBegin < dataPtr->fileSize) {
            auto size = std::min(dstBufEnd, dataPtr->fileSize);
            dataPtr->helper.sh_read(dataPtr->helperCTX, dataPtr->fileId,
                asio::mutable_buffer(buffer, size), dataPtr->offset);
        }

        if (commonBegin < commonEnd) {
            auto srcBufShift = commonBegin - srcBufBegin;
            auto dstBufShift = commonBegin - dstBufBegin;

            std::memcpy(buffer + dstBufShift,
                asio::buffer_cast<const char *>(dataPtr->buffer) + srcBufShift,
                commonEnd - commonBegin);
        }

        return bufferSize;
    };

    S3_put_object(&ctx.bucketCTX, tmpFileId.c_str(), newFileSize, nullptr,
        nullptr, &putObjectHandler, static_cast<void *>(&data));

    sh_copy(ctx, tmpFileId, fileId);
    sh_unlink(ctx, tmpFileId);

    return data.bufferSize;
}

void S3Helper::sh_truncate(
    const S3HelperCTX &ctx, const std::string &fileId, off_t size)
{
    sh_write(ctx, fileId, asio::const_buffer{}, 0, size);
}

std::size_t S3Helper::sh_getFileSize(
    const S3HelperCTX &ctx, const std::string &fileId)
{
    std::size_t fileSize;
    S3ResponseHandler responseHandler;
    responseHandler.propertiesCallback = [](
        const S3ResponseProperties *properties, void *callbackData) {
        auto fileSizePtr = static_cast<off_t *>(callbackData);
        *fileSizePtr = properties->contentLength;
        return S3StatusOK;
    };
    responseHandler.completeCallback = [](S3Status status,
        const S3ErrorDetails *errorDetails, void *callbackData) {
        if (status != S3StatusOK)
            throwPosixError("sh_getFileSize", status, errorDetails);
    };

    S3_head_object(&ctx.bucketCTX, fileId.c_str(), nullptr, &responseHandler,
        static_cast<void *>(&fileSize));

    return fileSize;
}

void S3Helper::sh_copy(const S3HelperCTX &ctx, const std::string &srcFileId,
    const std::string &dstFileId)
{
    S3ResponseHandler responseHandler;
    responseHandler.completeCallback = [](S3Status status,
        const S3ErrorDetails *errorDetails, void *callbackData) {
        if (status != S3StatusOK)
            throwPosixError("sh_copy", status, errorDetails);
    };

    S3_copy_object(&ctx.bucketCTX, srcFileId.c_str(), nullptr,
        dstFileId.c_str(), nullptr, nullptr, 0, nullptr, nullptr,
        &responseHandler, nullptr);
}

std::shared_ptr<S3HelperCTX> S3Helper::getCTX(CTXPtr rawCTX) const
{
    auto ctx = std::dynamic_pointer_cast<S3HelperCTX>(rawCTX);
    if (ctx == nullptr)
        throw std::system_error{
            std::make_error_code(std::errc::invalid_argument)};
    return ctx;
}

std::string S3Helper::temporaryFileId(const std::string &fileId)
{
    std::stringstream ss;
    ss << fileId << "." << std::time(nullptr);
    return ss.str();
}

error_t S3Helper::makePosixError(std::errc code)
{
    return error_t(static_cast<int>(code), std::system_category());
}

void S3Helper::throwPosixError(const std::string &operation, S3Status status,
    const S3ErrorDetails *errorDetails)
{
    std::stringstream ss;
    ss << "Operation '" << operation << "' completed returning an error: '"
       << S3_get_status_name(status) << "'";
    if (errorDetails != nullptr) {
        if (errorDetails->resource)
            ss << ", resource: '" << errorDetails->resource << "'";
        if (errorDetails->message)
            ss << ", message: '" << errorDetails->message << "'";
        if (errorDetails->furtherDetails)
            ss << ", details: '" << errorDetails->furtherDetails << "'";
        if (errorDetails->extraDetailsCount) {
            ss << ", extras: {";
            for (int i = 0; i < errorDetails->extraDetailsCount; ++i) {
                const auto &detail = errorDetails->extraDetails[i];
                ss << "{'" << detail.name << "', '" << detail.value << "'}";
            }
            ss << "}";
        }
    }
    LOG(ERROR) << ss.str();

    auto result = s_errorsTranslation.find(status);
    if (result != s_errorsTranslation.end())
        throw std::system_error{result->second};
    throw std::system_error{makePosixError(std::errc::io_error)};
}

S3HelperCTX::S3HelperCTX(std::unordered_map<std::string, std::string> args)
    : m_args{std::move(args)}
{
    bucketCTX.hostName = m_args.at("host_name").c_str();
    bucketCTX.bucketName = m_args.at("bucket_name").c_str();
    bucketCTX.protocol = S3ProtocolHTTP;
    bucketCTX.uriStyle = S3UriStylePath;

    auto result = m_args.find("access_key");
    if (result != m_args.end())
        bucketCTX.accessKeyId = result->second.c_str();

    result = m_args.find("secret_key");
    if (result != m_args.end())
        bucketCTX.secretAccessKey = result->second.c_str();
}

void S3HelperCTX::setUserCTX(std::unordered_map<std::string, std::string> args)
{
    m_args.swap(args);
    m_args.insert(args.begin(), args.end());
    bucketCTX.accessKeyId = m_args.at("access_key").c_str();
    bucketCTX.secretAccessKey = m_args.at("secret_key").c_str();
}

std::unordered_map<std::string, std::string> S3HelperCTX::getUserCTX()
{
    return {{"access_key", m_args.at("access_key")},
        {"secret_key", m_args.at("secret_key")}};
}

} // namespace helpers
} // namespace one
<commit_msg>Squashed 'helpers/' changes from bc04786..3142e3c<commit_after>/**
 * @file s3Helper.cc
 * @author Krzysztof Trzepla
 * @copyright (C) 2015 ACK CYFRONET AGH
 * @copyright This software is released under the MIT license cited in
 * 'LICENSE.txt'
 */

#include "s3Helper.h"
#include "logging.h"

#include <algorithm>
#include <ctime>
#include <functional>
#include <sstream>
#include <vector>

namespace one {
namespace helpers {

std::mutex S3Helper::s_mutex{};

const std::map<int, error_t> S3Helper::s_errorsTranslation = {
    {S3StatusOutOfMemory, makePosixError(std::errc::not_enough_memory)},
    {S3StatusInterrupted, makePosixError(std::errc::interrupted)},
    {S3StatusConnectionFailed, makePosixError(std::errc::connection_refused)},
    {S3StatusErrorAccessDenied, makePosixError(std::errc::permission_denied)},
    {S3StatusErrorInvalidArgument, makePosixError(std::errc::invalid_argument)},
    {S3StatusErrorNoSuchKey,
        makePosixError(std::errc::no_such_file_or_directory)},
    {S3StatusHttpErrorNotFound,
        makePosixError(std::errc::no_such_file_or_directory)},
    {S3StatusErrorNotImplemented, makePosixError(std::errc::not_supported)},
    {S3StatusErrorOperationAborted,
        makePosixError(std::errc::connection_aborted)},
    {S3StatusErrorRequestTimeout, makePosixError(std::errc::timed_out)},
    {S3StatusHttpErrorForbidden, makePosixError(std::errc::permission_denied)}};

S3Helper::S3Helper(std::unordered_map<std::string, std::string> args,
    asio::io_service &service)
    : m_service{service}
    , m_args{std::move(args)}
{
    std::lock_guard<std::mutex> guard{s_mutex};
    S3_initialize(nullptr, S3_INIT_ALL, nullptr);
}

S3Helper::~S3Helper() { S3_deinitialize(); }

CTXPtr S3Helper::createCTX() { return std::make_shared<S3HelperCTX>(m_args); }

void S3Helper::ash_unlink(
    CTXPtr rawCTX, const boost::filesystem::path &p, VoidCallback callback)
{
    auto ctx = getCTX(std::move(rawCTX));
    auto fileId = p.string();

    asio::post(m_service,
        [
          this,
          ctx = std::move(ctx),
          fileId = std::move(fileId),
          callback = std::move(callback)
        ]() {
            try {
                sh_unlink(*ctx, fileId);
                callback(SUCCESS_CODE);
            }
            catch (const std::system_error &e) {
                callback(e.code());
            }
        });
}

void S3Helper::ash_read(CTXPtr rawCTX, const boost::filesystem::path &p,
    asio::mutable_buffer buf, off_t offset,
    GeneralCallback<asio::mutable_buffer> callback)
{
    auto ctx = getCTX(std::move(rawCTX));
    auto fileId = p.string();

    asio::post(m_service,
        [
          =,
          ctx = std::move(ctx),
          buf = std::move(buf),
          fileId = std::move(fileId),
          callback = std::move(callback)
        ]() mutable {
            try {
                callback(sh_read(*ctx, fileId, std::move(buf), offset),
                    SUCCESS_CODE);
            }
            catch (const std::system_error &e) {
                callback(asio::mutable_buffer{}, e.code());
            }
        });
}

void S3Helper::ash_write(CTXPtr rawCTX, const boost::filesystem::path &p,
    asio::const_buffer buf, off_t offset, GeneralCallback<std::size_t> callback)
{
    auto ctx = getCTX(std::move(rawCTX));
    auto fileId = p.string();

    asio::post(m_service,
        [
          =,
          ctx = std::move(ctx),
          buf = std::move(buf),
          fileId = std::move(fileId),
          callback = std::move(callback)
        ]() mutable {
            try {
                callback(sh_write(*ctx, fileId, std::move(buf), offset),
                    SUCCESS_CODE);
            }
            catch (const std::system_error &e) {
                callback(0, e.code());
            }
        });
}

void S3Helper::ash_truncate(CTXPtr rawCTX, const boost::filesystem::path &p,
    off_t size, VoidCallback callback)
{
    auto ctx = getCTX(std::move(rawCTX));
    auto fileId = p.string();

    asio::post(m_service,
        [
          =,
          ctx = std::move(ctx),
          fileId = std::move(fileId),
          callback = std::move(callback)
        ]() {
            try {
                sh_truncate(*ctx, fileId, size);
                callback(SUCCESS_CODE);
            }
            catch (const std::system_error &e) {
                callback(e.code());
            }
        });
}

void S3Helper::sh_unlink(const S3HelperCTX &ctx, const std::string &fileId)
{
    S3ResponseHandler responseHandler;
    responseHandler.propertiesCallback = [](
        const S3ResponseProperties *properties, void *callbackData) {
        return S3StatusOK;
    };
    responseHandler.completeCallback = [](S3Status status,
        const S3ErrorDetails *errorDetails, void *callbackData) {
        if (status != S3StatusOK)
            throwPosixError("sh_unlink", status, errorDetails);
    };

    S3_delete_object(
        &ctx.bucketCTX, fileId.c_str(), nullptr, &responseHandler, nullptr);
}

asio::mutable_buffer S3Helper::sh_read(const S3HelperCTX &ctx,
    const std::string &fileId, asio::mutable_buffer buf, off_t offset)
{
    struct CallbackData {
        std::size_t size = 0;
        asio::mutable_buffer buffer;
    } data;
    data.buffer = std::move(buf);

    S3GetObjectHandler getObjectHandler;
    getObjectHandler.responseHandler = S3ResponseHandler{};
    getObjectHandler.responseHandler.propertiesCallback = [](
        const S3ResponseProperties *properties, void *callbackData) {
        return S3StatusOK;
    };
    getObjectHandler.responseHandler.completeCallback = [](S3Status status,
        const S3ErrorDetails *errorDetails, void *callbackData) {
        if (status != S3StatusOK)
            throwPosixError("sh_read", status, errorDetails);
    };
    getObjectHandler.getObjectDataCallback = [](
        int bufferSize, const char *buffer, void *callbackData) {
        auto dataPtr = static_cast<CallbackData *>(callbackData);
        std::memcpy(asio::buffer_cast<char *>(dataPtr->buffer) + dataPtr->size,
            buffer, bufferSize);
        dataPtr->size += bufferSize;
        return S3StatusOK;
    };

    S3_get_object(&ctx.bucketCTX, fileId.c_str(), nullptr, offset,
        asio::buffer_size(data.buffer), nullptr, &getObjectHandler,
        static_cast<void *>(&data));

    return asio::buffer(data.buffer, data.size);
}

std::size_t S3Helper::sh_write(const S3HelperCTX &ctx,
    const std::string &fileId, asio::const_buffer buf, off_t offset)
{
    std::size_t fileSize = 0;
    try {
        fileSize = sh_getFileSize(ctx, fileId);
    }
    catch (const std::system_error &e) {
        if (e.code() != makePosixError(std::errc::no_such_file_or_directory))
            throw;
    }
    return sh_write(ctx, fileId, std::move(buf), offset, fileSize);
}

std::size_t S3Helper::sh_write(const S3HelperCTX &ctx,
    const std::string &fileId, asio::const_buffer buf, off_t offset,
    std::size_t fileSize)
{
    struct CallbackData {
        CallbackData(const std::string &_fileId, const S3HelperCTX &_helperCTX,
            S3Helper &_helper)
            : fileId{_fileId}
            , helperCTX{_helperCTX}
            , helper{_helper}
        {
        }

        off_t offset = 0;
        std::size_t fileSize;
        off_t bufferOffset;
        std::size_t bufferSize;
        asio::const_buffer buffer;
        const std::string &fileId;
        const S3HelperCTX &helperCTX;
        S3Helper &helper;
    };

    CallbackData data{fileId, ctx, *this};
    data.fileSize = fileSize;
    data.bufferOffset = offset;
    data.bufferSize = asio::buffer_size(buf);
    data.buffer = std::move(buf);

    auto tmpFileId = temporaryFileId(fileId);
    auto newFileSize =
        std::max(data.fileSize, data.bufferOffset + data.bufferSize);
    S3PutObjectHandler putObjectHandler;
    putObjectHandler.responseHandler = S3ResponseHandler{};
    putObjectHandler.responseHandler.propertiesCallback = [](
        const S3ResponseProperties *properties, void *callbackData) {
        return S3StatusOK;
    };
    putObjectHandler.responseHandler.completeCallback = [](S3Status status,
        const S3ErrorDetails *errorDetails, void *callbackData) {
        if (status != S3StatusOK)
            throwPosixError("sh_write", status, errorDetails);
    };
    putObjectHandler.putObjectDataCallback = [](
        int bufferSize, char *buffer, void *callbackData) {
        auto dataPtr = static_cast<CallbackData *>(callbackData);

        auto srcBufBegin = static_cast<std::size_t>(dataPtr->bufferOffset);
        auto srcBufEnd = srcBufBegin + dataPtr->bufferSize;
        auto dstBufBegin = static_cast<std::size_t>(dataPtr->offset);
        auto dstBufEnd = dstBufBegin + static_cast<std::size_t>(bufferSize);
        auto commonBegin = std::max(srcBufBegin, dstBufBegin);
        auto commonEnd = std::min(srcBufEnd, dstBufEnd);

        std::memset(buffer, 0, bufferSize);

        if (dstBufBegin < dataPtr->fileSize) {
            auto size = std::min(dstBufEnd, dataPtr->fileSize);
            dataPtr->helper.sh_read(dataPtr->helperCTX, dataPtr->fileId,
                asio::mutable_buffer(buffer, size), dataPtr->offset);
        }

        if (commonBegin < commonEnd) {
            auto srcBufShift = commonBegin - srcBufBegin;
            auto dstBufShift = commonBegin - dstBufBegin;

            std::memcpy(buffer + dstBufShift,
                asio::buffer_cast<const char *>(dataPtr->buffer) + srcBufShift,
                commonEnd - commonBegin);
        }

        return bufferSize;
    };

    S3_put_object(&ctx.bucketCTX, tmpFileId.c_str(), newFileSize, nullptr,
        nullptr, &putObjectHandler, static_cast<void *>(&data));

    sh_copy(ctx, tmpFileId, fileId);
    sh_unlink(ctx, tmpFileId);

    return data.bufferSize;
}

void S3Helper::sh_truncate(
    const S3HelperCTX &ctx, const std::string &fileId, off_t size)
{
    sh_write(ctx, fileId, asio::const_buffer{}, 0, size);
}

std::size_t S3Helper::sh_getFileSize(
    const S3HelperCTX &ctx, const std::string &fileId)
{
    std::size_t fileSize;
    S3ResponseHandler responseHandler;
    responseHandler.propertiesCallback = [](
        const S3ResponseProperties *properties, void *callbackData) {
        auto fileSizePtr = static_cast<off_t *>(callbackData);
        *fileSizePtr = properties->contentLength;
        return S3StatusOK;
    };
    responseHandler.completeCallback = [](S3Status status,
        const S3ErrorDetails *errorDetails, void *callbackData) {
        if (status != S3StatusOK)
            throwPosixError("sh_getFileSize", status, errorDetails);
    };

    S3_head_object(&ctx.bucketCTX, fileId.c_str(), nullptr, &responseHandler,
        static_cast<void *>(&fileSize));

    return fileSize;
}

void S3Helper::sh_copy(const S3HelperCTX &ctx, const std::string &srcFileId,
    const std::string &dstFileId)
{
    S3ResponseHandler responseHandler;
    responseHandler.completeCallback = [](S3Status status,
        const S3ErrorDetails *errorDetails, void *callbackData) {
        if (status != S3StatusOK)
            throwPosixError("sh_copy", status, errorDetails);
    };

    S3_copy_object(&ctx.bucketCTX, srcFileId.c_str(), nullptr,
        dstFileId.c_str(), nullptr, nullptr, 0, nullptr, nullptr,
        &responseHandler, nullptr);
}

std::shared_ptr<S3HelperCTX> S3Helper::getCTX(CTXPtr rawCTX) const
{
    auto ctx = std::dynamic_pointer_cast<S3HelperCTX>(rawCTX);
    if (ctx == nullptr)
        throw std::system_error{
            std::make_error_code(std::errc::invalid_argument)};
    return ctx;
}

std::string S3Helper::temporaryFileId(const std::string &fileId)
{
    std::stringstream ss;
    ss << fileId << "." << std::time(nullptr);
    return ss.str();
}

error_t S3Helper::makePosixError(std::errc code)
{
    return error_t(static_cast<int>(code), std::system_category());
}

void S3Helper::throwPosixError(const std::string &operation, S3Status status,
    const S3ErrorDetails *errorDetails)
{
    std::stringstream ss;
    ss << "Operation '" << operation << "' completed returning an error: '"
       << S3_get_status_name(status) << "'";
    if (errorDetails != nullptr) {
        if (errorDetails->resource)
            ss << ", resource: '" << errorDetails->resource << "'";
        if (errorDetails->message)
            ss << ", message: '" << errorDetails->message << "'";
        if (errorDetails->furtherDetails)
            ss << ", details: '" << errorDetails->furtherDetails << "'";
        if (errorDetails->extraDetailsCount) {
            ss << ", extras: {";
            for (int i = 0; i < errorDetails->extraDetailsCount; ++i) {
                const auto &detail = errorDetails->extraDetails[i];
                ss << "{'" << detail.name << "', '" << detail.value << "'}";
            }
            ss << "}";
        }
    }
    LOG(ERROR) << ss.str();

    auto result = s_errorsTranslation.find(status);
    if (result != s_errorsTranslation.end())
        throw std::system_error{result->second};
    throw std::system_error{makePosixError(std::errc::io_error)};
}

S3HelperCTX::S3HelperCTX(std::unordered_map<std::string, std::string> args)
    : m_args{std::move(args)}
{
    bucketCTX.hostName = m_args.at("host_name").c_str();
    bucketCTX.bucketName = m_args.at("bucket_name").c_str();
    bucketCTX.protocol = S3ProtocolHTTP;
    bucketCTX.uriStyle = S3UriStylePath;

    auto result = m_args.find("access_key");
    if (result != m_args.end())
        bucketCTX.accessKeyId = result->second.c_str();

    result = m_args.find("secret_key");
    if (result != m_args.end())
        bucketCTX.secretAccessKey = result->second.c_str();
}

void S3HelperCTX::setUserCTX(std::unordered_map<std::string, std::string> args)
{
    m_args.swap(args);
    m_args.insert(args.begin(), args.end());
    bucketCTX.hostName = m_args.at("host_name").c_str();
    bucketCTX.bucketName = m_args.at("bucket_name").c_str();
    bucketCTX.accessKeyId = m_args.at("access_key").c_str();
    bucketCTX.secretAccessKey = m_args.at("secret_key").c_str();
}

std::unordered_map<std::string, std::string> S3HelperCTX::getUserCTX()
{
    return {{"access_key", m_args.at("access_key")},
        {"secret_key", m_args.at("secret_key")}};
}

} // namespace helpers
} // namespace one
<|endoftext|>


<commit_before>#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <SPI.h>
#include <SD.h>

#include "session.h"
#include "bits.h"

#include "config.h"

void init_session_header(uint8_t* buf, uint64_t timestamp, uint16_t channels)
{
	buf[0] = 0xec; // Magic #1.
	buf[1] = 0x09; // Magic #2.
	buf[2] = 0x00; // Format epoch.
	buf[3] = 0x00; // Unused 1.
	buf[4] = 0x00; // Unused 2.
	buf[5] = 0x00; // Unused 3.
	uint16_t be_channels = swap_endian_16(channels);
	memcpy(&(buf[6]), &be_channels, 2);
	// Last eight bytes are for the timestamp.
	// XXX: this assumes we're compiled little-endian. Better to make it
	//      endianness-agnostic.
	uint64_t be_ts = swap_endian_64(timestamp);
	memcpy(&(buf[8]), &be_ts, 8);
}

int session_write(session *s, uint8_t *buf, size_t len)
{
	int written = s->fh.write(buf, len);
	s->fh.flush();
	return written;
}

// Given a *char of length at least 11, get_fname stores a string of the
// form "ecgses.XXX", where XXX is a hexadecimal integer between 0x0 and
// 0xfff. If no such unused filename exists -1 will be returned,
// otherwise the value of the integer used for the suffix plus one
// (assuming contiguity of session files, this is likely to be valid for
// the next one).
int get_fname(char *fname, int base_suffix)
{
	int suf = base_suffix;
	strncpy(fname, "ecgses.", 7);
	char valid = 0;
	while (!valid && suf < 0x1000) {
		snprintf(fname+7, 4, "%03x", suf);
		if (!SD.exists(fname)) {
			valid = 1;
		}
		suf++;
	}
	return (valid ? suf : -1);
}

session* session_init(uint64_t timestamp, uint16_t channels)
{
	session *s = (session*) malloc(sizeof(session));
	if (s == NULL) {
		return NULL;
	}
	uint8_t buf[SESSION_HEADER_SIZE];
	init_session_header(buf, timestamp, channels);
	char fname[11];
	int next_suffix = get_fname(fname, 0);
	if (next_suffix < 0) {
		#ifdef DEBUG
		Serial.println("Could not find an unused filename.");
		Serial.println("Is the SD card full?");
		#endif
		free(s);
		return NULL;
	}
	s->next_suffix = next_suffix;
	s->init_time = timestamp;
	s->fh = SD.open(fname, FILE_WRITE);
	if (!s->fh) {
		#ifdef DEBUG
		Serial.print("Could not open file ");
		Serial.print(fname);
		Serial.println(" for writing.");
		#endif
		free(s);
		return NULL;
	}
	session_write(s, buf, SESSION_HEADER_SIZE);
	return s;
}

void session_close(session *s)
{
	s->fh.close();
	free(s);
}
<commit_msg>More debug output<commit_after>#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <SPI.h>
#include <SD.h>

#include "session.h"
#include "bits.h"

#include "config.h"

void init_session_header(uint8_t* buf, uint64_t timestamp, uint16_t channels)
{
	buf[0] = 0xec; // Magic #1.
	buf[1] = 0x09; // Magic #2.
	buf[2] = 0x00; // Format epoch.
	buf[3] = 0x00; // Unused 1.
	buf[4] = 0x00; // Unused 2.
	buf[5] = 0x00; // Unused 3.
	uint16_t be_channels = swap_endian_16(channels);
	memcpy(buf+6, &be_channels, 2);
	// Last eight bytes are for the timestamp.
	// XXX: this assumes we're compiled little-endian. Better to make it
	//      endianness-agnostic.
	uint64_t be_ts = swap_endian_64(timestamp);
	memcpy(buf+8, &be_ts, 8);
}

int session_write(session *s, uint8_t *buf, size_t len)
{
	int written = s->fh.write(buf, len);
	s->fh.flush();
	return written;
}

// Given a *char of length at least 11, get_fname stores a string of the
// form "ecgses.XXX", where XXX is a hexadecimal integer between 0x0 and
// 0xfff. If no such unused filename exists -1 will be returned,
// otherwise the value of the integer used for the suffix plus one
// (assuming contiguity of session files, this is likely to be valid for
// the next one).
int get_fname(char *fname, int base_suffix)
{
	int suf = base_suffix;
	strncpy(fname, "ecgses.", 7);
	char valid = 0;
	while (!valid && suf < 0x1000) {
		snprintf(fname+7, 4, "%03x", suf);
		if (!SD.exists(fname)) {
			valid = 1;
		}
		suf++;
	}
	return (valid ? suf : -1);
}

session* session_init(uint64_t timestamp, uint16_t channels)
{
	session *s = (session*) malloc(sizeof(session));
	if (s == NULL) {
		return NULL;
	}
	char fname[11];
	int next_suffix = get_fname(fname, 0);
	if (next_suffix < 0) {
		#ifdef DEBUG
		Serial.println("Could not find an unused filename.");
		Serial.println("Is the SD card full?");
		#endif
		free(s);
		return NULL;
	}
	s->next_suffix = next_suffix;
	s->init_time = timestamp;
	s->fh = SD.open(fname, FILE_WRITE);
	if (!s->fh) {
		#ifdef DEBUG
		Serial.print("Could not open file ");
		Serial.print(fname);
		Serial.println(" for writing.");
		#endif
		free(s);
		return NULL;
	}
	uint8_t buf[SESSION_HEADER_SIZE];
	#ifdef DEBUG
	Serial.print("Writing session header: ");
	for (int i = 0; i < 16; i++) {
		Serial.print(buf[i], HEX);
	}
	Serial.print('\n');
	#endif
	init_session_header(buf, timestamp, channels);
	session_write(s, buf, SESSION_HEADER_SIZE);
	return s;
}

void session_close(session *s)
{
	s->fh.close();
	free(s);
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2014 Alexander Bezsilko <demonsboots@gmail.com>

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
 */
#include "session.h"

namespace tclient
{

Session::Session(uint32_t start_port, uint32_t end_port)
        : port_range_(std::make_pair(start_port, end_port)),
          session_ptr_(new session())

{

}

Session::~Session()
{}

void Session::start_listen() throw(TCException)
{
    error_code e;
    session_ptr_->listen_on(port_range_, e);
    if (e) {
        throw TCException("Error occured with session start listening:\n" +
                          e.message());
    }
}

void Session::add_entity(const TorrentEntity& entity) throw (TCException)
{
    error_code ec;
    session_ptr_->add_torrent(entity.params(), ec);

    if (ec) {
        throw TCException("Error occurred with addition new torrent:\n" +
                          ec.message());
    }
}

void Session::add_entries(const std::vector<TorrentEntity>& entries)
{
    // TODO
    // Add all valid entries from vector to session
}

}
<commit_msg>Implemented multiple torrents addition to the session<commit_after>/*
  Copyright (c) 2014 Alexander Bezsilko <demonsboots@gmail.com>

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
 */

#include "session.h"

namespace tclient
{

Session::Session(uint32_t start_port, uint32_t end_port)
        : port_range_(std::make_pair(start_port, end_port)),
          session_ptr_(new session())

{

}

Session::~Session()
{}

void Session::start_listen() throw(TCException)
{
    error_code e;
    session_ptr_->listen_on(port_range_, e);
    if (e) {
        throw TCException("Error occured with session start listening:\n" +
                          e.message());
    }
}

void Session::add_entity(const TorrentEntity& entity) throw (TCException)
{
    error_code ec;
    session_ptr_->add_torrent(entity.params(), ec);

    if (ec) {
        throw TCException("Error occurred with addition new torrent:\n" +
                          ec.message());
    }
}

void Session::add_entries(const Session::Tasks_t& entities)
{
    error_code ec;
    for (const Session::TorrentEntity_ptr& entity : entities) {
        session_ptr_->add_torrent(entity->params(), ec);
        if (ec) {
            // TODO
            // Add logging
        }
    }
}

}
<|endoftext|>


<commit_before><?hh // strict

/**
 * This file is part of hhpack\process package.
 *
 * (c) Noritaka Horio <holy.shared.design@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace hhpack\process;

use hhpack\process\output\OutputBufferedStream;

async function exec(
    string $command,
    ProcessOptions $options = new ProcessOptions()
) : Awaitable<ProcessResult>
{
    $builder = new ProcessBuilder($command, $options);
    return await $builder->start()->wait();
}

function fork(
    string $script,
    ?Traversable<mixed> $args = [],
    ProcessOptions $options = new ProcessOptions()
) : ChildProcess
{
    $arguments = ImmSet::fromItems($args)->map(($value) ==> {
        return trim((string) $value);
    })->toArray();

    $command = 'hhvm ' . trim($script) . ' ' . implode(' ', $arguments);
    $builder = new ProcessBuilder($command, $options);

    return $builder->start();
}
<commit_msg>to sprintf<commit_after><?hh // strict

/**
 * This file is part of hhpack\process package.
 *
 * (c) Noritaka Horio <holy.shared.design@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace hhpack\process;

use hhpack\process\output\OutputBufferedStream;

async function exec(
    string $command,
    ProcessOptions $options = new ProcessOptions()
) : Awaitable<ProcessResult>
{
    $builder = new ProcessBuilder($command, $options);
    return await $builder->start()->wait();
}

function fork(
    string $script,
    ?Traversable<mixed> $args = [],
    ProcessOptions $options = new ProcessOptions()
) : ChildProcess
{
    $arguments = ImmSet::fromItems($args)->map(($value) ==> {
        return trim((string) $value);
    })->toArray();

    $command = sprintf('hhvm %s %s', trim($script), implode(' ', $arguments));
    $builder = new ProcessBuilder($command, $options);

    return $builder->start();
}
<|endoftext|>


<commit_before>// Copyright 2016 Chris Drake
//
// 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 <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <boost/optional.hpp>
#include <cryptominisat4/cryptominisat.h>

#include "boolexpr/boolexpr.h"
#include "argset.h"

using namespace boolexpr;

// Atoms are already simple
bx_t
Atom::simplify() const
{
    return shared_from_this();
}

// Use the positive form to simplify inverted operators
static bx_t
_nop_simplify(BoolExpr const * const bx)
{
    auto self = bx->shared_from_this();
    auto nop = std::static_pointer_cast<Operator const>(self);
    if (nop->simple) return nop;
    auto op = ~nop;
    return ~op->simplify();
}

bx_t Nor::simplify() const { return _nop_simplify(this); }
bx_t Nand::simplify() const { return _nop_simplify(this); }
bx_t Xnor::simplify() const { return _nop_simplify(this); }
bx_t Unequal::simplify() const { return _nop_simplify(this); }
bx_t NotImplies::simplify() const { return _nop_simplify(this); }
bx_t NotIfThenElse::simplify() const { return _nop_simplify(this); }

bx_t
Or::simplify() const
{
    auto self = shared_from_this();
    auto op = std::static_pointer_cast<Or const>(self);
    if (op->simple) return op;
    return OrArgSet(op->args).reduce();
}

bx_t
And::simplify() const
{
    auto self = shared_from_this();
    auto op = std::static_pointer_cast<And const>(self);
    if (op->simple) return op;
    return AndArgSet(op->args).reduce();
}

bx_t
Xor::simplify() const
{
    auto self = shared_from_this();
    auto op = std::static_pointer_cast<Xor const>(self);
    if (op->simple) return op;
    return XorArgSet(op->args).reduce();
}

bx_t
Equal::simplify() const
{
    auto self = shared_from_this();
    auto op = std::static_pointer_cast<Equal const>(self);
    if (op->simple) return op;
    return EqArgSet(op->args).reduce();
}

bx_t
Implies::simplify() const
{
    auto self = shared_from_this();
    auto op = std::static_pointer_cast<Implies const>(self);

    if (op->simple) return op;

    auto p = op->args[0]->simplify();
    auto q = op->args[1]->simplify();

    if (IS_ILL(p) || IS_ILL(q))
        return illogical();

    // 0 => q <=> p => 1 <=> 1
    if (IS_ZERO(p) || IS_ONE(q))
        return one();

    // 1 => q <=> q
    if (IS_ONE(p))
        return q;

    // p => 0 <=> ~p
    if (IS_ZERO(q))
        return ~p;

    // X => q <=> p => X <=> X
    if (IS_LOG(p) || IS_LOG(q))
        return logical();

    // q => q <=> 1
    if (p == q)
        return one();

    // ~q => q <=> q
    if (IS_LIT(p) && IS_LIT(q) && (p == ~q))
        return q;

    return std::make_shared<Implies>(true, p, q);
}

bx_t
IfThenElse::simplify() const
{
    auto self = shared_from_this();
    auto op = std::static_pointer_cast<IfThenElse const>(self);

    if (op->simple) return op;

    auto s = op->args[0]->simplify();
    auto d1 = op->args[1]->simplify();
    auto d0 = op->args[2]->simplify();

    if (IS_ILL(s) || IS_ILL(d1) || IS_ILL(d0))
        return illogical();

    // 0 ? d1 : d0 <=> d0
    if (IS_ZERO(s))
        return d0;
    // 1 ? d1 : d0 <=> d1
    if (IS_ONE(s))
        return d1;

    if (IS_ZERO(d1)) {
        // s ? 0 : 0 <=> 0
        if (IS_ZERO(d0))
            return zero();
        // s ? 0 : 1 <=> ~s
        if (IS_ONE(d0))
            return ~s;
        // s ? 0 : d0 <=> ~s & d0
        return and_s({~s, d0});
    }

    if (IS_ONE(d1)) {
        // s ? 1 : 0 <=> s
        if (IS_ZERO(d0))
            return s;
        // s ? 1 : 1 <=> 1
        if (IS_ONE(d0))
            return one();
        // s ? 1 : d0 <=> s | d0
        return or_s({s, d0});
    }

    // s ? d1 : 0 <=> s & d1
    if (IS_ZERO(d0))
        return and_s({s, d1});
    // s ? d1 : 1 <=> ~s | d1
    if (IS_ONE(d0))
        return or_s({~s, d1});

    // (s ? X : d0) <=> (s ? d1 : X) <=> X
    if (IS_LOG(d1) || IS_LOG(d0))
        return logical();

    // s ? d1 : d1 <=> d1
    if (d1 == d0)
        return d1;

    // X ? d1 : d0 <=> X
    // NOTE: If you an prove d0 <=> d1, then should return d0.
    //       But that proof is too expensive to gate this operation.
    if (IS_LOG(s))
        return logical();

    // s ? s : d0 <=> s | d0
    if (s == d1)
        return or_s({s, d0});
    // s ? d1 : s <=> s & d1
    if (s == d0)
        return and_s({s, d1});

    return std::make_shared<IfThenElse>(true, s, d1, d0);
}
<commit_msg>Correct comment typo<commit_after>// Copyright 2016 Chris Drake
//
// 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 <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <boost/optional.hpp>
#include <cryptominisat4/cryptominisat.h>

#include "boolexpr/boolexpr.h"
#include "argset.h"

using namespace boolexpr;

// Atoms are already simple
bx_t
Atom::simplify() const
{
    return shared_from_this();
}

// Use the positive form to simplify inverted operators
static bx_t
_nop_simplify(BoolExpr const * const bx)
{
    auto self = bx->shared_from_this();
    auto nop = std::static_pointer_cast<Operator const>(self);
    if (nop->simple) return nop;
    auto op = ~nop;
    return ~op->simplify();
}

bx_t Nor::simplify() const { return _nop_simplify(this); }
bx_t Nand::simplify() const { return _nop_simplify(this); }
bx_t Xnor::simplify() const { return _nop_simplify(this); }
bx_t Unequal::simplify() const { return _nop_simplify(this); }
bx_t NotImplies::simplify() const { return _nop_simplify(this); }
bx_t NotIfThenElse::simplify() const { return _nop_simplify(this); }

bx_t
Or::simplify() const
{
    auto self = shared_from_this();
    auto op = std::static_pointer_cast<Or const>(self);
    if (op->simple) return op;
    return OrArgSet(op->args).reduce();
}

bx_t
And::simplify() const
{
    auto self = shared_from_this();
    auto op = std::static_pointer_cast<And const>(self);
    if (op->simple) return op;
    return AndArgSet(op->args).reduce();
}

bx_t
Xor::simplify() const
{
    auto self = shared_from_this();
    auto op = std::static_pointer_cast<Xor const>(self);
    if (op->simple) return op;
    return XorArgSet(op->args).reduce();
}

bx_t
Equal::simplify() const
{
    auto self = shared_from_this();
    auto op = std::static_pointer_cast<Equal const>(self);
    if (op->simple) return op;
    return EqArgSet(op->args).reduce();
}

bx_t
Implies::simplify() const
{
    auto self = shared_from_this();
    auto op = std::static_pointer_cast<Implies const>(self);

    if (op->simple) return op;

    auto p = op->args[0]->simplify();
    auto q = op->args[1]->simplify();

    if (IS_ILL(p) || IS_ILL(q))
        return illogical();

    // 0 => q <=> p => 1 <=> 1
    if (IS_ZERO(p) || IS_ONE(q))
        return one();

    // 1 => q <=> q
    if (IS_ONE(p))
        return q;

    // p => 0 <=> ~p
    if (IS_ZERO(q))
        return ~p;

    // X => q <=> p => X <=> X
    if (IS_LOG(p) || IS_LOG(q))
        return logical();

    // q => q <=> 1
    if (p == q)
        return one();

    // ~q => q <=> q
    if (IS_LIT(p) && IS_LIT(q) && (p == ~q))
        return q;

    return std::make_shared<Implies>(true, p, q);
}

bx_t
IfThenElse::simplify() const
{
    auto self = shared_from_this();
    auto op = std::static_pointer_cast<IfThenElse const>(self);

    if (op->simple) return op;

    auto s = op->args[0]->simplify();
    auto d1 = op->args[1]->simplify();
    auto d0 = op->args[2]->simplify();

    if (IS_ILL(s) || IS_ILL(d1) || IS_ILL(d0))
        return illogical();

    // 0 ? d1 : d0 <=> d0
    if (IS_ZERO(s))
        return d0;
    // 1 ? d1 : d0 <=> d1
    if (IS_ONE(s))
        return d1;

    if (IS_ZERO(d1)) {
        // s ? 0 : 0 <=> 0
        if (IS_ZERO(d0))
            return zero();
        // s ? 0 : 1 <=> ~s
        if (IS_ONE(d0))
            return ~s;
        // s ? 0 : d0 <=> ~s & d0
        return and_s({~s, d0});
    }

    if (IS_ONE(d1)) {
        // s ? 1 : 0 <=> s
        if (IS_ZERO(d0))
            return s;
        // s ? 1 : 1 <=> 1
        if (IS_ONE(d0))
            return one();
        // s ? 1 : d0 <=> s | d0
        return or_s({s, d0});
    }

    // s ? d1 : 0 <=> s & d1
    if (IS_ZERO(d0))
        return and_s({s, d1});
    // s ? d1 : 1 <=> ~s | d1
    if (IS_ONE(d0))
        return or_s({~s, d1});

    // (s ? X : d0) <=> (s ? d1 : X) <=> X
    if (IS_LOG(d1) || IS_LOG(d0))
        return logical();

    // s ? d1 : d1 <=> d1
    if (d1 == d0)
        return d1;

    // X ? d1 : d0 <=> X
    // NOTE: If you can prove d0 <=> d1, then should return d0.
    //       But that proof is too expensive to gate this operation.
    if (IS_LOG(s))
        return logical();

    // s ? s : d0 <=> s | d0
    if (s == d1)
        return or_s({s, d0});
    // s ? d1 : s <=> s & d1
    if (s == d0)
        return and_s({s, d1});

    return std::make_shared<IfThenElse>(true, s, d1, d0);
}
<|endoftext|>


<commit_before>#include "Configuration.h"
#include "Log.h"

#define DS1307_RAM_SIZE 30

Preferences _preferences;

namespace SkyeTracker
{
Configuration::Configuration()
{
	_isDirty = false;
}

Configuration::~Configuration()
{
}

void Configuration::setDual(bool val)
{
	_dualAxis = val;
	_isDirty = true;
}

void Configuration::setHasAnemometer(bool val)
{
	_hasAnemometer = val;
	_isDirty = true;
}

void Configuration::SetLocation(float lat, float lon)
{
	_latitude = lat;
	_longitude = lon;
	_isDirty = true;
}

void Configuration::SetLimits(int minAzimuth, int maxAzimuth, int minElevation, int maxElevation)
{
	_eastAzimuth = minAzimuth;
	_westAzimuth = maxAzimuth;
	_minimumElevation = minElevation;
	_maximumElevation = maxElevation;
	// verify limits
	if (_maximumElevation > 90)
	{
		_maximumElevation = 90;
	}
	if (_maximumElevation < 45)
	{
		_maximumElevation = 45;
	}

	if (_minimumElevation > 44)
	{
		_minimumElevation = 44;
	}
	if (_minimumElevation < 0)
	{
		_minimumElevation = 0;
	}

	if (_eastAzimuth < 0)
	{
		_eastAzimuth = 0;
	}
	if (_eastAzimuth > 180)
	{
		_eastAzimuth = 180;
	}

	if (_westAzimuth < 182)
	{
		_westAzimuth = 182;
	}
	if (_westAzimuth > 359)
	{
		_westAzimuth = 359;
	}
	_isDirty = true;
}

void Configuration::SetActuatorParameters(int horizontalLength, int verticalLength, int horizontalSpeed, int verticalSpeed)
{
	_horizontalLength = horizontalLength;
	_verticalLength = verticalLength;
	_horizontalSpeed = horizontalSpeed;
	_verticalSpeed = verticalSpeed;
	_isDirty = true;
}

float deserialFloat(byte *buffer)
{
	float f = 0;
	byte *b = (byte *)&f;
	b[0] = buffer[0];
	b[1] = buffer[1];
	b[2] = buffer[2];
	b[3] = buffer[3];
	return f;
}

int deserialInt(byte *buffer)
{
	int i = 0;
	byte *b = (byte *)&i;
	b[0] = buffer[0];
	b[1] = buffer[1];
	return i;
}

void Configuration::Load()
{
	if (_preferences.begin("SkyeTracker", false))
	{
		byte _buffer[DS1307_RAM_SIZE + 1];
		_preferences.getBytes("Configuration", _buffer, DS1307_RAM_SIZE);
		if (CalcChecksum(_buffer) == 0)
		{
			logi("Checksum passed, loading saved settings");
			if (_buffer[0] == 1)
				_dualAxis = true;
			else
				_dualAxis = false;
			_eastAzimuth = deserialInt(&(_buffer[2]));
			_westAzimuth = deserialInt(&(_buffer[4]));
			_minimumElevation = deserialInt(&(_buffer[6]));
			_maximumElevation = deserialInt(&(_buffer[8]));
			_latitude = deserialFloat(&(_buffer[10]));
			_longitude = deserialFloat(&(_buffer[14]));
			_horizontalLength = deserialInt(&(_buffer[18]));
			_verticalLength = deserialInt(&(_buffer[20]));
			_horizontalSpeed = deserialInt(&(_buffer[22]));
			_verticalSpeed = deserialInt(&(_buffer[24]));
			if (_buffer[26] == 1)
				_hasAnemometer = true;
			else
				_hasAnemometer = false;
			_isDirty = false;
		}
		else
		{
			logi("Checksum failed, loading default settings");
			LoadFactoryDefault();
		}
	}
	else
	{
		logi("Could not initialize preferences, loading default settings");
		LoadFactoryDefault();
	}
}

void Configuration::LoadFactoryDefault()
{
	setDual(true);
	setHasAnemometer(false);
	SetLimits(90, 270, 0, 90);
	SetActuatorParameters(12, 8, 31, 31);
	//45.936527, -75.091259 Lac Simon
	SetLocation(45.936527, -75.091259);
	Save();
}

void serialFloat(byte *buffer, float f)
{
	byte *b = (byte *)&f;
	buffer[0] = b[0];
	buffer[1] = b[1];
	buffer[2] = b[2];
	buffer[3] = b[3];
}

void serialInt(byte *buffer, int f)
{
	byte *b = (byte *)&f;
	buffer[0] = b[0];
	buffer[1] = b[1];
}

void Configuration::Save()
{
	byte _buffer[DS1307_RAM_SIZE + 1];
	for (int i = 0; i < DS1307_RAM_SIZE; i++)
	{
		_buffer[i] = 0x00;
	}
	if (_dualAxis)
		_buffer[0] = 1;
	else
		_buffer[0] = 0;

	serialInt(&(_buffer[2]), _eastAzimuth);
	serialInt(&(_buffer[4]), _westAzimuth);
	serialInt(&(_buffer[6]), _minimumElevation);
	serialInt(&(_buffer[8]), _maximumElevation);
	serialFloat(&(_buffer[10]), _latitude); // arduino nano double is the same as float
	serialFloat(&(_buffer[14]), _longitude);

	serialInt(&(_buffer[18]), _horizontalLength);
	serialInt(&(_buffer[20]), _verticalLength);
	serialInt(&(_buffer[22]), _horizontalSpeed);
	serialInt(&(_buffer[24]), _verticalSpeed);
	if (_hasAnemometer)
		_buffer[26] = 1;
	else
		_buffer[26] = 0;
	_buffer[28] = CalcChecksum(_buffer);
	_preferences.putBytes("Configuration", _buffer, DS1307_RAM_SIZE);
	_isDirty = false;
	logi("Saved settings");
}

byte Configuration::CalcChecksum(byte _buffer[])
{
	byte crc = 0;
	for (int i = 0; i < DS1307_RAM_SIZE; i++)
		crc += _buffer[i];
	crc = -crc;
	logi("Checksum cal: %x", crc);
	return crc;
}

/*
	Configuration|{"_dual":true,"_lat":45.936527,"_long":75.091255,"_eastAz":90.0,"_westAz":270.0,"_minElevation":0.0,"_maxElevation":90.0,"_secondsTime":1444033308}
	*/

void Configuration::SendConfiguration()
{
	ESP_BT.print(F("Cf|{"));
	ESP_BT.print(F("\"d\":"));
	ESP_BT.print(isDual() ? F("true") : F("false"));
	ESP_BT.print(F(",\"a\":"));
	ESP_BT.print(getLat(), 6);
	ESP_BT.print(F(",\"o\":"));
	ESP_BT.print(getLon(), 6);
	ESP_BT.print(F(",\"e\":"));
	ESP_BT.print(getEastAzimuth());
	ESP_BT.print(F(",\"w\":"));
	ESP_BT.print(getWestAzimuth());
	ESP_BT.print(F(",\"n\":"));
	ESP_BT.print(getMinimumElevation());
	ESP_BT.print(F(",\"x\":"));
	ESP_BT.print(getMaximumElevation());
	ESP_BT.print(F(",\"lh\":"));
	ESP_BT.print(getHorizontalLength());
	ESP_BT.print(F(",\"lv\":"));
	ESP_BT.print(getVerticalLength());
	ESP_BT.print(F(",\"sh\":"));
	ESP_BT.print(getHorizontalSpeed());
	ESP_BT.print(F(",\"sv\":"));
	ESP_BT.print(getVerticalSpeed());
	ESP_BT.print(F(",\"an\":"));
	ESP_BT.print(hasAnemometer() ? F("true") : F("false"));
	ESP_BT.println(F("}"));
}

time_t GetSystemTime()
{
	uint32_t start = millis();
	time_t now;
	while ((millis() - start) <= 100)
	{
		time(&now);
		if (now > 1573996930)
		{
			return now;
		}
		delay(10);
	}
	return (time_t)0;
}

// try to get valid time from system, last resort use last saved time from watchdog reset
time_t Configuration::GetTime()
{
	time_t now = GetSystemTime();
	if (now == 0)
	{
		return (time_t)_preferences.getLong("time");
	}
	return now;
}

void Configuration::SaveTime()
{
	time_t now = GetSystemTime();
	if (now != 0)
	{
		_preferences.putLong("time", (int32_t)now);
	}
}

} // namespace SkyeTracker<commit_msg>rename DS1307_RAM_SIZE to STORAGE_SIZE<commit_after>#include "Configuration.h"
#include "Log.h"

#define STORAGE_SIZE 30

Preferences _preferences;

namespace SkyeTracker
{
Configuration::Configuration()
{
	_isDirty = false;
}

Configuration::~Configuration()
{
}

void Configuration::setDual(bool val)
{
	_dualAxis = val;
	_isDirty = true;
}

void Configuration::setHasAnemometer(bool val)
{
	_hasAnemometer = val;
	_isDirty = true;
}

void Configuration::SetLocation(float lat, float lon)
{
	_latitude = lat;
	_longitude = lon;
	_isDirty = true;
}

void Configuration::SetLimits(int minAzimuth, int maxAzimuth, int minElevation, int maxElevation)
{
	_eastAzimuth = minAzimuth;
	_westAzimuth = maxAzimuth;
	_minimumElevation = minElevation;
	_maximumElevation = maxElevation;
	// verify limits
	if (_maximumElevation > 90)
	{
		_maximumElevation = 90;
	}
	if (_maximumElevation < 45)
	{
		_maximumElevation = 45;
	}

	if (_minimumElevation > 44)
	{
		_minimumElevation = 44;
	}
	if (_minimumElevation < 0)
	{
		_minimumElevation = 0;
	}

	if (_eastAzimuth < 0)
	{
		_eastAzimuth = 0;
	}
	if (_eastAzimuth > 180)
	{
		_eastAzimuth = 180;
	}

	if (_westAzimuth < 182)
	{
		_westAzimuth = 182;
	}
	if (_westAzimuth > 359)
	{
		_westAzimuth = 359;
	}
	_isDirty = true;
}

void Configuration::SetActuatorParameters(int horizontalLength, int verticalLength, int horizontalSpeed, int verticalSpeed)
{
	_horizontalLength = horizontalLength;
	_verticalLength = verticalLength;
	_horizontalSpeed = horizontalSpeed;
	_verticalSpeed = verticalSpeed;
	_isDirty = true;
}

float deserialFloat(byte *buffer)
{
	float f = 0;
	byte *b = (byte *)&f;
	b[0] = buffer[0];
	b[1] = buffer[1];
	b[2] = buffer[2];
	b[3] = buffer[3];
	return f;
}

int deserialInt(byte *buffer)
{
	int i = 0;
	byte *b = (byte *)&i;
	b[0] = buffer[0];
	b[1] = buffer[1];
	return i;
}

void Configuration::Load()
{
	if (_preferences.begin("SkyeTracker", false))
	{
		byte _buffer[STORAGE_SIZE + 1];
		_preferences.getBytes("Configuration", _buffer, STORAGE_SIZE);
		if (CalcChecksum(_buffer) == 0)
		{
			logi("Checksum passed, loading saved settings");
			if (_buffer[0] == 1)
				_dualAxis = true;
			else
				_dualAxis = false;
			_eastAzimuth = deserialInt(&(_buffer[2]));
			_westAzimuth = deserialInt(&(_buffer[4]));
			_minimumElevation = deserialInt(&(_buffer[6]));
			_maximumElevation = deserialInt(&(_buffer[8]));
			_latitude = deserialFloat(&(_buffer[10]));
			_longitude = deserialFloat(&(_buffer[14]));
			_horizontalLength = deserialInt(&(_buffer[18]));
			_verticalLength = deserialInt(&(_buffer[20]));
			_horizontalSpeed = deserialInt(&(_buffer[22]));
			_verticalSpeed = deserialInt(&(_buffer[24]));
			if (_buffer[26] == 1)
				_hasAnemometer = true;
			else
				_hasAnemometer = false;
			_isDirty = false;
		}
		else
		{
			logi("Checksum failed, loading default settings");
			LoadFactoryDefault();
		}
	}
	else
	{
		logi("Could not initialize preferences, loading default settings");
		LoadFactoryDefault();
	}
}

void Configuration::LoadFactoryDefault()
{
	setDual(true);
	setHasAnemometer(false);
	SetLimits(90, 270, 0, 90);
	SetActuatorParameters(12, 8, 31, 31);
	//45.936527, -75.091259 Lac Simon
	SetLocation(45.936527, -75.091259);
	Save();
}

void serialFloat(byte *buffer, float f)
{
	byte *b = (byte *)&f;
	buffer[0] = b[0];
	buffer[1] = b[1];
	buffer[2] = b[2];
	buffer[3] = b[3];
}

void serialInt(byte *buffer, int f)
{
	byte *b = (byte *)&f;
	buffer[0] = b[0];
	buffer[1] = b[1];
}

void Configuration::Save()
{
	byte _buffer[STORAGE_SIZE + 1];
	for (int i = 0; i < STORAGE_SIZE; i++)
	{
		_buffer[i] = 0x00;
	}
	if (_dualAxis)
		_buffer[0] = 1;
	else
		_buffer[0] = 0;

	serialInt(&(_buffer[2]), _eastAzimuth);
	serialInt(&(_buffer[4]), _westAzimuth);
	serialInt(&(_buffer[6]), _minimumElevation);
	serialInt(&(_buffer[8]), _maximumElevation);
	serialFloat(&(_buffer[10]), _latitude); // arduino nano double is the same as float
	serialFloat(&(_buffer[14]), _longitude);

	serialInt(&(_buffer[18]), _horizontalLength);
	serialInt(&(_buffer[20]), _verticalLength);
	serialInt(&(_buffer[22]), _horizontalSpeed);
	serialInt(&(_buffer[24]), _verticalSpeed);
	if (_hasAnemometer)
		_buffer[26] = 1;
	else
		_buffer[26] = 0;
	_buffer[28] = CalcChecksum(_buffer);
	_preferences.putBytes("Configuration", _buffer, STORAGE_SIZE);
	_isDirty = false;
	logi("Saved settings");
}

byte Configuration::CalcChecksum(byte _buffer[])
{
	byte crc = 0;
	for (int i = 0; i < STORAGE_SIZE; i++)
		crc += _buffer[i];
	crc = -crc;
	logi("Checksum cal: %x", crc);
	return crc;
}

/*
	Configuration|{"_dual":true,"_lat":45.936527,"_long":75.091255,"_eastAz":90.0,"_westAz":270.0,"_minElevation":0.0,"_maxElevation":90.0,"_secondsTime":1444033308}
	*/

void Configuration::SendConfiguration()
{
	ESP_BT.print(F("Cf|{"));
	ESP_BT.print(F("\"d\":"));
	ESP_BT.print(isDual() ? F("true") : F("false"));
	ESP_BT.print(F(",\"a\":"));
	ESP_BT.print(getLat(), 6);
	ESP_BT.print(F(",\"o\":"));
	ESP_BT.print(getLon(), 6);
	ESP_BT.print(F(",\"e\":"));
	ESP_BT.print(getEastAzimuth());
	ESP_BT.print(F(",\"w\":"));
	ESP_BT.print(getWestAzimuth());
	ESP_BT.print(F(",\"n\":"));
	ESP_BT.print(getMinimumElevation());
	ESP_BT.print(F(",\"x\":"));
	ESP_BT.print(getMaximumElevation());
	ESP_BT.print(F(",\"lh\":"));
	ESP_BT.print(getHorizontalLength());
	ESP_BT.print(F(",\"lv\":"));
	ESP_BT.print(getVerticalLength());
	ESP_BT.print(F(",\"sh\":"));
	ESP_BT.print(getHorizontalSpeed());
	ESP_BT.print(F(",\"sv\":"));
	ESP_BT.print(getVerticalSpeed());
	ESP_BT.print(F(",\"an\":"));
	ESP_BT.print(hasAnemometer() ? F("true") : F("false"));
	ESP_BT.println(F("}"));
}

time_t GetSystemTime()
{
	uint32_t start = millis();
	time_t now;
	while ((millis() - start) <= 100)
	{
		time(&now);
		if (now > 1573996930)
		{
			return now;
		}
		delay(10);
	}
	return (time_t)0;
}

// try to get valid time from system, last resort use last saved time from watchdog reset
time_t Configuration::GetTime()
{
	time_t now = GetSystemTime();
	if (now == 0)
	{
		return (time_t)_preferences.getLong("time");
	}
	return now;
}

void Configuration::SaveTime()
{
	time_t now = GetSystemTime();
	if (now != 0)
	{
		_preferences.putLong("time", (int32_t)now);
	}
}

} // namespace SkyeTracker<|endoftext|>


<commit_before>#ifndef WARGEN_CPP
#define WARGEN_CPP

#include <algorithm>
#include <vector>
#include <iostream>

int main() {

char cards[52] = {'1','1','1','1','2','2','2','2','3','3','3','3','4','4','4','4','5','5','5','5','6','6','6','6','7','7','7','7','8','8','8','8','9','9','9','9','T','T','T','T','J','J','J','J','Q','Q','Q','Q','K','K','K','K'};

std::random_shuffle(&cards[0], &cards[51]);

for(int i = 0; i < 52; i++) {
  std::cout << cards[i];
  if(i==25) {
    std::cout << "\n";
  }
}

};

#endif
<commit_msg>erge branch 'master' of https://www.github.com/acmatku/ku-ipc-2016<commit_after>#ifndef WARGEN_CPP
#define WARGEN_CPP

#include <algorithm>
#include <vector>
#include <iostream>

int main() {

char cards[52] = {'1','1','1','1','2','2','2','2','3','3','3','3','4','4','4','4','5','5','5','5','6','6','6','6','7','7','7','7','8','8','8','8','9','9','9','9','T','T','T','T','J','J','J','J','Q','Q','Q','Q','K','K','K','K'};

std::random_shuffle(&cards[0], &cards[51]);

for(int i = 0; i < 52; i++) {
  std::cout << cards[i];
  std::cout << " ";
  if(i==25) {
    std::cout << "\n";
  }
}

};

#endif
<|endoftext|>