text:
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "base58.h"
#include "checkpoints.h"
#include "clientversion.h"
#include "kernel.h"
#include "main.h"
#include "rpc/server.h"
#include "sync.h"
#include "txdb.h"
#include "util.h"
#include "utilmoneystr.h"
#include "wallet/wallet.h"
#include "zpiv/zpivmodule.h"
#include "zpivchain.h"

#include <stdint.h>
#include <fstream>
#include <iostream>
#include <univalue.h>
#include <mutex>
#include <numeric>
#include <condition_variable>

struct CUpdatedBlock
{
    uint256 hash;
    int height;
};
static std::mutex cs_blockchange;
static std::condition_variable cond_blockchange;
static CUpdatedBlock latestblock;

extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);

double GetDifficulty(const CBlockIndex* blockindex)
{
    // Floating point number that is a multiple of the minimum difficulty,
    // minimum difficulty = 1.0.
    if (blockindex == NULL) {
        if (chainActive.Tip() == NULL)
            return 1.0;
        else
            blockindex = chainActive.Tip();
    }

    int nShift = (blockindex->nBits >> 24) & 0xff;

    double dDiff =
        (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);

    while (nShift < 29) {
        dDiff *= 256.0;
        nShift++;
    }
    while (nShift > 29) {
        dDiff /= 256.0;
        nShift--;
    }

    return dDiff;
}

UniValue blockheaderToJSON(const CBlockIndex* blockindex)
{
    UniValue result(UniValue::VOBJ);
    result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex()));
    int confirmations = -1;
    // Only report confirmations if the block is on the main chain
    if (chainActive.Contains(blockindex))
        confirmations = chainActive.Height() - blockindex->nHeight + 1;
    result.push_back(Pair("confirmations", confirmations));
    result.push_back(Pair("height", blockindex->nHeight));
    result.push_back(Pair("version", blockindex->nVersion));
    result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex()));
    result.push_back(Pair("time", (int64_t)blockindex->nTime));
    result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast()));
    result.push_back(Pair("nonce", (uint64_t)blockindex->nNonce));
    result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits)));
    result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
    result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
    result.push_back(Pair("acc_checkpoint", blockindex->nAccumulatorCheckpoint.GetHex()));

    if (blockindex->pprev)
        result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
    CBlockIndex *pnext = chainActive.Next(blockindex);
    if (pnext)
        result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex()));
    return result;
}

UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
{
    UniValue result(UniValue::VOBJ);
    result.push_back(Pair("hash", block.GetHash().GetHex()));
    int confirmations = -1;
    // Only report confirmations if the block is on the main chain
    if (chainActive.Contains(blockindex))
        confirmations = chainActive.Height() - blockindex->nHeight + 1;
    result.push_back(Pair("confirmations", confirmations));
    result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
    result.push_back(Pair("height", blockindex->nHeight));
    result.push_back(Pair("version", block.nVersion));
    result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
    result.push_back(Pair("acc_checkpoint", block.nAccumulatorCheckpoint.GetHex()));
    UniValue txs(UniValue::VARR);
    for (const CTransaction& tx : block.vtx) {
        if (txDetails) {
            UniValue objTx(UniValue::VOBJ);
            TxToJSON(tx, uint256(0), objTx);
            txs.push_back(objTx);
        } else
            txs.push_back(tx.GetHash().GetHex());
    }
    result.push_back(Pair("tx", txs));
    result.push_back(Pair("time", block.GetBlockTime()));
    result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast()));
    result.push_back(Pair("nonce", (uint64_t)block.nNonce));
    result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
    result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
    result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));

    if (blockindex->pprev)
        result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
    CBlockIndex* pnext = chainActive.Next(blockindex);
    if (pnext)
        result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex()));

    result.push_back(Pair("modifier", strprintf("%016x", blockindex->nStakeModifier)));
    result.push_back(Pair("modifierV2", blockindex->nStakeModifierV2.GetHex()));

    result.push_back(Pair("moneysupply",ValueFromAmount(blockindex->nMoneySupply)));

    UniValue zpivObj(UniValue::VOBJ);
    for (auto denom : libzerocoin::zerocoinDenomList) {
        zpivObj.push_back(Pair(std::to_string(denom), ValueFromAmount(blockindex->mapZerocoinSupply.at(denom) * (denom*COIN))));
    }
    zpivObj.push_back(Pair("total", ValueFromAmount(blockindex->GetZerocoinSupply())));
    result.push_back(Pair("zPIVsupply", zpivObj));

    //////////
    ////////// Coin stake data ////////////////
    /////////
    if (block.IsProofOfStake()) {
        // First grab it
        uint256 hashProofOfStakeRet;
        std::unique_ptr <CStakeInput> stake;
        // Initialize the stake object (we should look for this in some other place and not initialize it every time..)
        if (!initStakeInput(block, stake, blockindex->nHeight - 1))
            throw JSONRPCError(RPC_INTERNAL_ERROR, "Cannot initialize stake input");

        unsigned int nTxTime = block.nTime;
        // todo: Add the debug as param..
        if (!GetHashProofOfStake(blockindex->pprev, stake.get(), nTxTime, false, hashProofOfStakeRet))
            throw JSONRPCError(RPC_INTERNAL_ERROR, "Cannot get proof of stake hash");

        UniValue stakeData(UniValue::VOBJ);
        stakeData.push_back(Pair("hashProofOfStake", hashProofOfStakeRet.GetHex()));
        stakeData.push_back(Pair("stakeModifierHeight", ((stake->IsZPIV()) ? "Not available" : std::to_string(
                stake->getStakeModifierHeight()))));
        result.push_back(Pair("CoinStake", stakeData));
    }

    return result;
}

UniValue getblockcount(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw std::runtime_error(
            "getblockcount\n"
            "\nReturns the number of blocks in the longest block chain.\n"

            "\nResult:\n"
            "n    (numeric) The current block count\n"

            "\nExamples:\n" +
            HelpExampleCli("getblockcount", "") + HelpExampleRpc("getblockcount", ""));

    LOCK(cs_main);
    return chainActive.Height();
}

UniValue getbestblockhash(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw std::runtime_error(
            "getbestblockhash\n"
            "\nReturns the hash of the best (tip) block in the longest block chain.\n"

            "\nResult\n"
            "\"hex\"      (string) the block hash hex encoded\n"

            "\nExamples\n" +
            HelpExampleCli("getbestblockhash", "") + HelpExampleRpc("getbestblockhash", ""));

    LOCK(cs_main);
    return chainActive.Tip()->GetBlockHash().GetHex();
}

void RPCNotifyBlockChange(const uint256 hashBlock)
{
    CBlockIndex* pindex = nullptr;
    pindex = mapBlockIndex.at(hashBlock);
    if(pindex) {
        std::lock_guard<std::mutex> lock(cs_blockchange);
        latestblock.hash = pindex->GetBlockHash();
        latestblock.height = pindex->nHeight;
    }
    cond_blockchange.notify_all();
}

UniValue waitfornewblock(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() > 1)
        throw std::runtime_error(
            "waitfornewblock ( timeout )\n"
            "\nWaits for a specific new block and returns useful info about it.\n"
            "\nReturns the current block on timeout or exit.\n"

            "\nArguments:\n"
            "1. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"

            "\nResult:\n"
            "{                           (json object)\n"
            "  \"hash\" : {       (string) The blockhash\n"
            "  \"height\" : {     (int) Block height\n"
            "}\n"

            "\nExamples:\n"
            + HelpExampleCli("waitfornewblock", "1000")
            + HelpExampleRpc("waitfornewblock", "1000")
        );
    int timeout = 0;
    if (params.size() > 0)
        timeout = params[0].get_int();
    CUpdatedBlock block;
    {
        std::unique_lock<std::mutex> lock(cs_blockchange);
        block = latestblock;
        if(timeout)
            cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
        else
            cond_blockchange.wait(lock, [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
        block = latestblock;
    }
    UniValue ret(UniValue::VOBJ);
    ret.push_back(Pair("hash", block.hash.GetHex()));
    ret.push_back(Pair("height", block.height));
    return ret;
}

UniValue waitforblock(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw std::runtime_error(
            "waitforblock blockhash ( timeout )\n"
            "\nWaits for a specific new block and returns useful info about it.\n"
            "\nReturns the current block on timeout or exit.\n"

            "\nArguments:\n"
            "1. \"blockhash\" (required, std::string) Block hash to wait for.\n"
            "2. timeout       (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"

            "\nResult:\n"
            "{                           (json object)\n"
            "  \"hash\" : {       (string) The blockhash\n"
            "  \"height\" : {     (int) Block height\n"
            "}\n"

            "\nExamples:\n"
            + HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
            + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
        );
    int timeout = 0;

    uint256 hash = uint256S(params[0].get_str());

    if (params.size() > 1)
        timeout = params[1].get_int();

    CUpdatedBlock block;
    {
        std::unique_lock<std::mutex> lock(cs_blockchange);
        if(timeout)
            cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]{return latestblock.hash == hash || !IsRPCRunning();});
        else
            cond_blockchange.wait(lock, [&hash]{return latestblock.hash == hash || !IsRPCRunning(); });
        block = latestblock;
    }

    UniValue ret(UniValue::VOBJ);
    ret.push_back(Pair("hash", block.hash.GetHex()));
    ret.push_back(Pair("height", block.height));
    return ret;
}

UniValue waitforblockheight(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw std::runtime_error(
            "waitforblockheight height ( timeout )\n"
            "\nWaits for (at least) block height and returns the height and hash\n"
            "of the current tip.\n"
            "\nReturns the current block on timeout or exit.\n"

            "\nArguments:\n"
            "1. height  (required, int) Block height to wait for (int)\n"
            "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"

            "\nResult:\n"
            "{                           (json object)\n"
            "  \"hash\" : {       (string) The blockhash\n"
            "  \"height\" : {     (int) Block height\n"
            "}\n"

            "\nExamples:\n"
            + HelpExampleCli("waitforblockheight", "\"100\", 1000")
            + HelpExampleRpc("waitforblockheight", "\"100\", 1000")
        );
    int timeout = 0;

    int height = params[0].get_int();

    if (params.size() > 1)
        timeout = params[1].get_int();

    CUpdatedBlock block;
    {
        std::unique_lock<std::mutex> lock(cs_blockchange);
        if(timeout)
            cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]{return latestblock.height >= height || !IsRPCRunning();});
        else
            cond_blockchange.wait(lock, [&height]{return latestblock.height >= height || !IsRPCRunning(); });
        block = latestblock;
    }
    UniValue ret(UniValue::VOBJ);
    ret.push_back(Pair("hash", block.hash.GetHex()));
    ret.push_back(Pair("height", block.height));
    return ret;
}

UniValue getdifficulty(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw std::runtime_error(
            "getdifficulty\n"
            "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n"

            "\nResult:\n"
            "n.nnn       (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\n"

            "\nExamples:\n" +
            HelpExampleCli("getdifficulty", "") + HelpExampleRpc("getdifficulty", ""));

    LOCK(cs_main);
    return GetDifficulty();
}

UniValue mempoolToJSON(bool fVerbose = false)
{
    if (fVerbose) {
        LOCK(mempool.cs);
        UniValue o(UniValue::VOBJ);
        for (const PAIRTYPE(uint256, CTxMemPoolEntry) & entry : mempool.mapTx) {
            const uint256& hash = entry.first;
            const CTxMemPoolEntry& e = entry.second;
            UniValue info(UniValue::VOBJ);
            info.push_back(Pair("size", (int)e.GetTxSize()));
            info.push_back(Pair("fee", ValueFromAmount(e.GetFee())));
            info.push_back(Pair("time", e.GetTime()));
            info.push_back(Pair("height", (int)e.GetHeight()));
            info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight())));
            info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height())));
            const CTransaction& tx = e.GetTx();
            std::set<std::string> setDepends;
            for (const CTxIn& txin : tx.vin) {
                if (mempool.exists(txin.prevout.hash))
                    setDepends.insert(txin.prevout.hash.ToString());
            }

            UniValue depends(UniValue::VARR);
            for (const std::string& dep : setDepends) {
                depends.push_back(dep);
            }

            info.push_back(Pair("depends", depends));
            o.push_back(Pair(hash.ToString(), info));
        }
        return o;
    } else {
        std::vector<uint256> vtxid;
        mempool.queryHashes(vtxid);

        UniValue a(UniValue::VARR);
        for (const uint256& hash : vtxid)
            a.push_back(hash.ToString());

        return a;
    }
}

UniValue getrawmempool(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() > 1)
        throw std::runtime_error(
            "getrawmempool ( verbose )\n"
            "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"

            "\nArguments:\n"
            "1. verbose           (boolean, optional, default=false) true for a json object, false for array of transaction ids\n"

            "\nResult: (for verbose = false):\n"
            "[                     (json array of string)\n"
            "  \"transactionid\"     (string) The transaction id\n"
            "  ,...\n"
            "]\n"

            "\nResult: (for verbose = true):\n"
            "{                           (json object)\n"
            "  \"transactionid\" : {       (json object)\n"
            "    \"size\" : n,             (numeric) transaction size in bytes\n"
            "    \"fee\" : n,              (numeric) transaction fee in pivx\n"
            "    \"time\" : n,             (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
            "    \"height\" : n,           (numeric) block height when transaction entered pool\n"
            "    \"startingpriority\" : n, (numeric) priority when transaction entered pool\n"
            "    \"currentpriority\" : n,  (numeric) transaction priority now\n"
            "    \"depends\" : [           (array) unconfirmed transactions used as inputs for this transaction\n"
            "        \"transactionid\",    (string) parent transaction id\n"
            "       ... ]\n"
            "  }, ...\n"
            "]\n"

            "\nExamples\n" +
            HelpExampleCli("getrawmempool", "true") + HelpExampleRpc("getrawmempool", "true"));

    LOCK(cs_main);

    bool fVerbose = false;
    if (params.size() > 0)
        fVerbose = params[0].get_bool();

    return mempoolToJSON(fVerbose);
}

UniValue getblockhash(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw std::runtime_error(
            "getblockhash index\n"
            "\nReturns hash of block in best-block-chain at index provided.\n"

            "\nArguments:\n"
            "1. index         (numeric, required) The block index\n"

            "\nResult:\n"
            "\"hash\"         (string) The block hash\n"

            "\nExamples:\n" +
            HelpExampleCli("getblockhash", "1000") + HelpExampleRpc("getblockhash", "1000"));

    LOCK(cs_main);

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > chainActive.Height())
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");

    CBlockIndex* pblockindex = chainActive[nHeight];
    return pblockindex->GetBlockHash().GetHex();
}

UniValue getblock(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw std::runtime_error(
            "getblock \"hash\" ( verbose )\n"
            "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
            "If verbose is true, returns an Object with information about block <hash>.\n"

            "\nArguments:\n"
            "1. \"hash\"          (string, required) The block hash\n"
            "2. verbose           (boolean, optional, default=true) true for a json object, false for the hex encoded data\n"

            "\nResult (for verbose = true):\n"
            "{\n"
            "  \"hash\" : \"hash\",     (string) the block hash (same as provided)\n"
            "  \"confirmations\" : n,   (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
            "  \"size\" : n,            (numeric) The block size\n"
            "  \"height\" : n,          (numeric) The block height or index\n"
            "  \"version\" : n,         (numeric) The block version\n"
            "  \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
            "  \"tx\" : [               (array of string) The transaction ids\n"
            "     \"transactionid\"     (string) The transaction id\n"
            "     ,...\n"
            "  ],\n"
            "  \"time\" : ttt,          (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
            "  \"mediantime\" : ttt,    (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n"
            "  \"nonce\" : n,           (numeric) The nonce\n"
            "  \"bits\" : \"1d00ffff\", (string) The bits\n"
            "  \"difficulty\" : x.xxx,  (numeric) The difficulty\n"
            "  \"previousblockhash\" : \"hash\",  (string) The hash of the previous block\n"
            "  \"nextblockhash\" : \"hash\"       (string) The hash of the next block\n"
            "  \"moneysupply\" : \"supply\"       (numeric) The money supply when this block was added to the blockchain\n"
            "  \"zPIVsupply\" :\n"
            "  {\n"
            "     \"1\" : n,            (numeric) supply of 1 zPIV denomination\n"
            "     \"5\" : n,            (numeric) supply of 5 zPIV denomination\n"
            "     \"10\" : n,           (numeric) supply of 10 zPIV denomination\n"
            "     \"50\" : n,           (numeric) supply of 50 zPIV denomination\n"
            "     \"100\" : n,          (numeric) supply of 100 zPIV denomination\n"
            "     \"500\" : n,          (numeric) supply of 500 zPIV denomination\n"
            "     \"1000\" : n,         (numeric) supply of 1000 zPIV denomination\n"
            "     \"5000\" : n,         (numeric) supply of 5000 zPIV denomination\n"
            "     \"total\" : n,        (numeric) The total supply of all zPIV denominations\n"
            "  },\n"
            "  \"CoinStake\" :\n"
            "    \"hashProofOfStake\" : \"hash\",   (string) Proof of Stake hash\n"
            "    \"stakeModifierHeight\" : \"nnn\"  (string) Stake modifier block height\n"
            "  }\n"
            "}\n"

            "\nResult (for verbose=false):\n"
            "\"data\"             (string) A string that is serialized, hex-encoded data for block 'hash'.\n"

            "\nExamples:\n" +
            HelpExampleCli("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") +
            HelpExampleRpc("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\""));

    LOCK(cs_main);

    std::string strHash = params[0].get_str();
    uint256 hash(strHash);

    bool fVerbose = true;
    if (params.size() > 1)
        fVerbose = params[1].get_bool();

    if (mapBlockIndex.count(hash) == 0)
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

    CBlock block;
    CBlockIndex* pblockindex = mapBlockIndex[hash];

    if (!ReadBlockFromDisk(block, pblockindex))
        throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");

    if (!fVerbose) {
        CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
        ssBlock << block;
        std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
        return strHex;
    }

    return blockToJSON(block, pblockindex);
}

UniValue getblockheader(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw std::runtime_error(
            "getblockheader \"hash\" ( verbose )\n"
            "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash' header.\n"
            "If verbose is true, returns an Object with information about block <hash> header.\n"

            "\nArguments:\n"
            "1. \"hash\"          (string, required) The block hash\n"
            "2. verbose           (boolean, optional, default=true) true for a json object, false for the hex encoded data\n"

            "\nResult (for verbose = true):\n"
            "{\n"
            "  \"version\" : n,         (numeric) The block version\n"
            "  \"previousblockhash\" : \"hash\",  (string) The hash of the previous block\n"
            "  \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
            "  \"time\" : ttt,          (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
            "  \"mediantime\" : ttt,    (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n"
            "  \"nonce\" : n,           (numeric) The nonce\n"
            "  \"bits\" : \"1d00ffff\", (string) The bits\n"
            "}\n"

            "\nResult (for verbose=false):\n"
            "\"data\"             (string) A string that is serialized, hex-encoded data for block 'hash' header.\n"

            "\nExamples:\n" +
            HelpExampleCli("getblockheader", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") +
            HelpExampleRpc("getblockheader", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\""));

    std::string strHash = params[0].get_str();
    uint256 hash(strHash);

    bool fVerbose = true;
    if (params.size() > 1)
        fVerbose = params[1].get_bool();

    if (mapBlockIndex.count(hash) == 0)
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

    CBlockIndex* pblockindex = mapBlockIndex[hash];

    if (!fVerbose) {
        CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
        ssBlock << pblockindex->GetBlockHeader();
        std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
        return strHex;
    }

    return blockheaderToJSON(pblockindex);
}

UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw std::runtime_error(
            "gettxoutsetinfo\n"
            "\nReturns statistics about the unspent transaction output set.\n"
            "Note this call may take some time.\n"

            "\nResult:\n"
            "{\n"
            "  \"height\":n,     (numeric) The current block height (index)\n"
            "  \"bestblock\": \"hex\",   (string) the best block hash hex\n"
            "  \"transactions\": n,      (numeric) The number of transactions\n"
            "  \"txouts\": n,            (numeric) The number of output transactions\n"
            "  \"bytes_serialized\": n,  (numeric) The serialized size\n"
            "  \"hash_serialized\": \"hash\",   (string) The serialized hash\n"
            "  \"total_amount\": x.xxx          (numeric) The total amount\n"
            "}\n"

            "\nExamples:\n" +
            HelpExampleCli("gettxoutsetinfo", "") + HelpExampleRpc("gettxoutsetinfo", ""));

    LOCK(cs_main);

    UniValue ret(UniValue::VOBJ);

    CCoinsStats stats;
    FlushStateToDisk();
    if (pcoinsTip->GetStats(stats)) {
        ret.push_back(Pair("height", (int64_t)stats.nHeight));
        ret.push_back(Pair("bestblock", stats.hashBlock.GetHex()));
        ret.push_back(Pair("transactions", (int64_t)stats.nTransactions));
        ret.push_back(Pair("txouts", (int64_t)stats.nTransactionOutputs));
        ret.push_back(Pair("bytes_serialized", (int64_t)stats.nSerializedSize));
        ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex()));
        ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount)));
    }
    return ret;
}

UniValue gettxout(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() < 2 || params.size() > 3)
        throw std::runtime_error(
            "gettxout \"txid\" n ( includemempool )\n"
            "\nReturns details about an unspent transaction output.\n"

            "\nArguments:\n"
            "1. \"txid\"       (string, required) The transaction id\n"
            "2. n              (numeric, required) vout value\n"
            "3. includemempool  (boolean, optional) Whether to included the mem pool\n"

            "\nResult:\n"
            "{\n"
            "  \"bestblock\" : \"hash\",    (string) the block hash\n"
            "  \"confirmations\" : n,       (numeric) The number of confirmations\n"
            "  \"value\" : x.xxx,           (numeric) The transaction value in btc\n"
            "  \"scriptPubKey\" : {         (json object)\n"
            "     \"asm\" : \"code\",       (string) \n"
            "     \"hex\" : \"hex\",        (string) \n"
            "     \"reqSigs\" : n,          (numeric) Number of required signatures\n"
            "     \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n"
            "     \"addresses\" : [          (array of string) array of pivx addresses\n"
            "     \"pivxaddress\"            (string) pivx address\n"
            "        ,...\n"
            "     ]\n"
            "  },\n"
            "  \"version\" : n,            (numeric) The version\n"
            "  \"coinbase\" : true|false   (boolean) Coinbase or not\n"
            "}\n"

            "\nExamples:\n"
            "\nGet unspent transactions\n" +
            HelpExampleCli("listunspent", "") +
            "\nView the details\n" +
            HelpExampleCli("gettxout", "\"txid\" 1") +
            "\nAs a json rpc call\n" +
            HelpExampleRpc("gettxout", "\"txid\", 1"));

    LOCK(cs_main);

    UniValue ret(UniValue::VOBJ);

    std::string strHash = params[0].get_str();
    uint256 hash(strHash);
    int n = params[1].get_int();
    bool fMempool = true;
    if (params.size() > 2)
        fMempool = params[2].get_bool();

    CCoins coins;
    if (fMempool) {
        LOCK(mempool.cs);
        CCoinsViewMemPool view(pcoinsTip, mempool);
        if (!view.GetCoins(hash, coins))
            return NullUniValue;
        mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool
    } else {
        if (!pcoinsTip->GetCoins(hash, coins))
            return NullUniValue;
    }
    if (n < 0 || (unsigned int)n >= coins.vout.size() || coins.vout[n].IsNull())
        return NullUniValue;

    BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
    CBlockIndex* pindex = it->second;
    ret.push_back(Pair("bestblock", pindex->GetBlockHash().GetHex()));
    if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT)
        ret.push_back(Pair("confirmations", 0));
    else
        ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1));
    ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue)));
    UniValue o(UniValue::VOBJ);
    ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true);
    ret.push_back(Pair("scriptPubKey", o));
    ret.push_back(Pair("version", coins.nVersion));
    ret.push_back(Pair("coinbase", coins.fCoinBase));

    return ret;
}

UniValue verifychain(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() > 1)
        throw std::runtime_error(
            "verifychain ( numblocks )\n"
            "\nVerifies blockchain database.\n"

            "\nArguments:\n"
            "1. numblocks    (numeric, optional, default=288, 0=all) The number of blocks to check.\n"

            "\nResult:\n"
            "true|false       (boolean) Verified or not\n"

            "\nExamples:\n" +
            HelpExampleCli("verifychain", "") + HelpExampleRpc("verifychain", ""));

    LOCK(cs_main);

    int nCheckLevel = 4;
    int nCheckDepth = GetArg("-checkblocks", 288);
    if (params.size() > 0)
        nCheckDepth = params[0].get_int();

    fVerifyingBlocks = true;
    bool fVerified = CVerifyDB().VerifyDB(pcoinsTip, nCheckLevel, nCheckDepth);
    fVerifyingBlocks = false;

    return fVerified;
}

/** Implementation of IsSuperMajority with better feedback */
static UniValue SoftForkMajorityDesc(int minVersion, CBlockIndex* pindex, int nRequired)
{
    int nFound = 0;
    CBlockIndex* pstart = pindex;
    for (int i = 0; i < Params().ToCheckBlockUpgradeMajority() && pstart != NULL; i++)
    {
        if (pstart->nVersion >= minVersion)
            ++nFound;
        pstart = pstart->pprev;
    }
    UniValue rv(UniValue::VOBJ);
    rv.push_back(Pair("status", nFound >= nRequired));
    rv.push_back(Pair("found", nFound));
    rv.push_back(Pair("required", nRequired));
    rv.push_back(Pair("window", Params().ToCheckBlockUpgradeMajority()));
    return rv;
}
static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* pindex)
{
    UniValue rv(UniValue::VOBJ);
    rv.push_back(Pair("id", name));
    rv.push_back(Pair("version", version));
    rv.push_back(Pair("enforce", SoftForkMajorityDesc(version, pindex, Params().EnforceBlockUpgradeMajority())));
    rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, Params().RejectBlockOutdatedMajority())));
    return rv;
}

UniValue getblockchaininfo(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw std::runtime_error(
            "getblockchaininfo\n"
            "Returns an object containing various state info regarding block chain processing.\n"

            "\nResult:\n"
            "{\n"
            "  \"chain\": \"xxxx\",        (string) current network name as defined in BIP70 (main, test, regtest)\n"
            "  \"blocks\": xxxxxx,         (numeric) the current number of blocks processed in the server\n"
            "  \"headers\": xxxxxx,        (numeric) the current number of headers we have validated\n"
            "  \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
            "  \"difficulty\": xxxxxx,     (numeric) the current difficulty\n"
            "  \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
            "  \"chainwork\": \"xxxx\"     (string) total amount of work in active chain, in hexadecimal\n"
            "  \"softforks\": [            (array) status of softforks in progress\n"
            "     {\n"
            "        \"id\": \"xxxx\",        (string) name of softfork\n"
            "        \"version\": xx,         (numeric) block version\n"
            "        \"enforce\": {           (object) progress toward enforcing the softfork rules for new-version blocks\n"
            "           \"status\": xx,       (boolean) true if threshold reached\n"
            "           \"found\": xx,        (numeric) number of blocks with the new version found\n"
            "           \"required\": xx,     (numeric) number of blocks required to trigger\n"
            "           \"window\": xx,       (numeric) maximum size of examined window of recent blocks\n"
            "        },\n"
            "        \"reject\": { ... }      (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
            "     }, ...\n"
            "  ]\n"
            "}\n"

            "\nExamples:\n" +
            HelpExampleCli("getblockchaininfo", "") + HelpExampleRpc("getblockchaininfo", ""));

    LOCK(cs_main);

    UniValue obj(UniValue::VOBJ);
    obj.push_back(Pair("chain", Params().NetworkIDString()));
    obj.push_back(Pair("blocks", (int)chainActive.Height()));
    obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1));
    obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()));
    obj.push_back(Pair("difficulty", (double)GetDifficulty()));
    obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(chainActive.Tip())));
    obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
    CBlockIndex* tip = chainActive.Tip();
    UniValue softforks(UniValue::VARR);
    softforks.push_back(SoftForkDesc("bip65", 5, tip));
    obj.push_back(Pair("softforks",             softforks));
    return obj;
}

/** Comparison function for sorting the getchaintips heads.  */
struct CompareBlocksByHeight {
    bool operator()(const CBlockIndex* a, const CBlockIndex* b) const
    {
        /* Make sure that unequal blocks with the same height do not compare
           equal. Use the pointers themselves to make a distinction. */

        if (a->nHeight != b->nHeight)
            return (a->nHeight > b->nHeight);

        return a < b;
    }
};

UniValue getchaintips(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw std::runtime_error(
            "getchaintips\n"
            "Return information about all known tips in the block tree,"
            " including the main chain as well as orphaned branches.\n"

            "\nResult:\n"
            "[\n"
            "  {\n"
            "    \"height\": xxxx,         (numeric) height of the chain tip\n"
            "    \"hash\": \"xxxx\",         (string) block hash of the tip\n"
            "    \"branchlen\": 0          (numeric) zero for main chain\n"
            "    \"status\": \"active\"      (string) \"active\" for the main chain\n"
            "  },\n"
            "  {\n"
            "    \"height\": xxxx,\n"
            "    \"hash\": \"xxxx\",\n"
            "    \"branchlen\": 1          (numeric) length of branch connecting the tip to the main chain\n"
            "    \"status\": \"xxxx\"        (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n"
            "  }\n"
            "]\n"

            "Possible values for status:\n"
            "1.  \"invalid\"               This branch contains at least one invalid block\n"
            "2.  \"headers-only\"          Not all blocks for this branch are available, but the headers are valid\n"
            "3.  \"valid-headers\"         All blocks are available for this branch, but they were never fully validated\n"
            "4.  \"valid-fork\"            This branch is not part of the active chain, but is fully validated\n"
            "5.  \"active\"                This is the tip of the active main chain, which is certainly valid\n"

            "\nExamples:\n" +
            HelpExampleCli("getchaintips", "") + HelpExampleRpc("getchaintips", ""));

    LOCK(cs_main);

    /* Build up a list of chain tips.  We start with the list of all
       known blocks, and successively remove blocks that appear as pprev
       of another block.  */
    std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;
    for (const PAIRTYPE(const uint256, CBlockIndex*) & item : mapBlockIndex)
        setTips.insert(item.second);
    for (const PAIRTYPE(const uint256, CBlockIndex*) & item : mapBlockIndex) {
        const CBlockIndex* pprev = item.second->pprev;
        if (pprev)
            setTips.erase(pprev);
    }

    // Always report the currently active tip.
    setTips.insert(chainActive.Tip());

    /* Construct the output array.  */
    UniValue res(UniValue::VARR);
    for (const CBlockIndex* block : setTips) {
        UniValue obj(UniValue::VOBJ);
        obj.push_back(Pair("height", block->nHeight));
        obj.push_back(Pair("hash", block->phashBlock->GetHex()));

        const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight;
        obj.push_back(Pair("branchlen", branchLen));

        std::string status;
        if (chainActive.Contains(block)) {
            // This block is part of the currently active chain.
            status = "active";
        } else if (block->nStatus & BLOCK_FAILED_MASK) {
            // This block or one of its ancestors is invalid.
            status = "invalid";
        } else if (block->nChainTx == 0) {
            // This block cannot be connected because full block data for it or one of its parents is missing.
            status = "headers-only";
        } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
            // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
            status = "valid-fork";
        } else if (block->IsValid(BLOCK_VALID_TREE)) {
            // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
            status = "valid-headers";
        } else {
            // No clue.
            status = "unknown";
        }
        obj.push_back(Pair("status", status));

        res.push_back(obj);
    }

    return res;
}

UniValue getfeeinfo(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw std::runtime_error(
            "getfeeinfo blocks\n"
            "\nReturns details of transaction fees over the last n blocks.\n"

            "\nArguments:\n"
            "1. blocks     (int, required) the number of blocks to get transaction data from\n"

            "\nResult:\n"
            "{\n"
            "  \"txcount\": xxxxx                (numeric) Current tx count\n"
            "  \"txbytes\": xxxxx                (numeric) Sum of all tx sizes\n"
            "  \"ttlfee\": xxxxx                 (numeric) Sum of all fees\n"
            "  \"feeperkb\": xxxxx               (numeric) Average fee per kb over the block range\n"
            "  \"rec_highpriorityfee_perkb\": xxxxx    (numeric) Recommended fee per kb to use for a high priority tx\n"
            "}\n"

            "\nExamples:\n" +
            HelpExampleCli("getfeeinfo", "5") + HelpExampleRpc("getfeeinfo", "5"));

    int nBlocks = params[0].get_int();
    int nBestHeight;
    {
        LOCK(cs_main);
        nBestHeight = chainActive.Height();
    }
    int nStartHeight = nBestHeight - nBlocks;
    if (nBlocks < 0 || nStartHeight <= 0)
        throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid start height");

    UniValue newParams(UniValue::VARR);
    newParams.push_back(UniValue(nStartHeight));
    newParams.push_back(UniValue(nBlocks));
    newParams.push_back(UniValue(true));    // fFeeOnly

    return getblockindexstats(newParams, false);
}

UniValue mempoolInfoToJSON()
{
    UniValue ret(UniValue::VOBJ);
    ret.push_back(Pair("size", (int64_t) mempool.size()));
    ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize()));
    //ret.push_back(Pair("usage", (int64_t) mempool.DynamicMemoryUsage()));

    return ret;
}

UniValue getmempoolinfo(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw std::runtime_error(
            "getmempoolinfo\n"
            "\nReturns details on the active state of the TX memory pool.\n"

            "\nResult:\n"
            "{\n"
            "  \"size\": xxxxx                (numeric) Current tx count\n"
            "  \"bytes\": xxxxx               (numeric) Sum of all tx sizes\n"
            "}\n"

            "\nExamples:\n" +
            HelpExampleCli("getmempoolinfo", "") + HelpExampleRpc("getmempoolinfo", ""));

    return mempoolInfoToJSON();
}

UniValue invalidateblock(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw std::runtime_error(
            "invalidateblock \"hash\"\n"
            "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n"

            "\nArguments:\n"
            "1. hash   (string, required) the hash of the block to mark as invalid\n"

            "\nExamples:\n" +
            HelpExampleCli("invalidateblock", "\"blockhash\"") + HelpExampleRpc("invalidateblock", "\"blockhash\""));

    std::string strHash = params[0].get_str();
    uint256 hash(strHash);
    CValidationState state;

    {
        LOCK(cs_main);
        if (mapBlockIndex.count(hash) == 0)
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

        CBlockIndex* pblockindex = mapBlockIndex[hash];
        InvalidateBlock(state, pblockindex);
    }

    if (state.IsValid()) {
        ActivateBestChain(state);
    }

    if (!state.IsValid()) {
        throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
    }

    return NullUniValue;
}

UniValue reconsiderblock(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw std::runtime_error(
            "reconsiderblock \"hash\"\n"
            "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n"
            "This can be used to undo the effects of invalidateblock.\n"

            "\nArguments:\n"
            "1. hash   (string, required) the hash of the block to reconsider\n"

            "\nExamples:\n" +
            HelpExampleCli("reconsiderblock", "\"blockhash\"") + HelpExampleRpc("reconsiderblock", "\"blockhash\""));

    std::string strHash = params[0].get_str();
    uint256 hash(strHash);
    CValidationState state;

    {
        LOCK(cs_main);
        if (mapBlockIndex.count(hash) == 0)
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

        CBlockIndex* pblockindex = mapBlockIndex[hash];
        ReconsiderBlock(state, pblockindex);
    }

    if (state.IsValid()) {
        ActivateBestChain(state);
    }

    if (!state.IsValid()) {
        throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
    }

    return NullUniValue;
}

UniValue findserial(const UniValue& params, bool fHelp)
{
    if(fHelp || params.size() != 1)
        throw std::runtime_error(
            "findserial \"serial\"\n"
            "\nSearches the zerocoin database for a zerocoin spend transaction that contains the specified serial\n"

            "\nArguments:\n"
            "1. serial   (string, required) the serial of a zerocoin spend to search for.\n"

            "\nResult:\n"
            "{\n"
            "  \"success\": true|false        (boolean) Whether the serial was found\n"
            "  \"txid\": \"xxx\"              (string) The transaction that contains the spent serial\n"
            "}\n"

            "\nExamples:\n" +
            HelpExampleCli("findserial", "\"serial\"") + HelpExampleRpc("findserial", "\"serial\""));

    std::string strSerial = params[0].get_str();
    CBigNum bnSerial = 0;
    bnSerial.SetHex(strSerial);
    if (!bnSerial)
    throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid serial");

    uint256 txid = 0;
    bool fSuccess = zerocoinDB->ReadCoinSpend(bnSerial, txid);

    UniValue ret(UniValue::VOBJ);
    ret.push_back(Pair("success", fSuccess));
    ret.push_back(Pair("txid", txid.GetHex()));
    return ret;
}

void validaterange(const UniValue& params, int& heightStart, int& heightEnd, int minHeightStart)
{
    if (params.size() < 2) {
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Not enough parameters in validaterange");
    }

    int nBestHeight;
    {
        LOCK(cs_main);
        nBestHeight = chainActive.Height();
    }

    heightStart = params[0].get_int();
    if (heightStart > nBestHeight) {
        throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid starting block (%d). Out of range.", heightStart));
    }

    const int range = params[1].get_int();
    if (range < 1) {
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block range. Must be strictly positive.");
    }

    heightEnd = heightStart + range - 1;

    if (heightStart < minHeightStart && heightEnd >= minHeightStart) {
        heightStart = minHeightStart;
    }

    if (heightEnd > nBestHeight) {
        throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid ending block (%d). Out of range.", heightEnd));
    }
}

UniValue getmintsinblocks(const UniValue& params, bool fHelp) {
    if (fHelp || params.size() != 3)
        throw std::runtime_error(
                "getmintsinblocks height range coinDenomination\n"
                "\nReturns the number of mints of a certain denomination"
                "\noccurred in blocks [height, height+1, height+2, ..., height+range-1]\n"

                "\nArguments:\n"
                "1. height             (numeric, required) block height where the search starts.\n"
                "2. range              (numeric, required) number of blocks to include.\n"
                "3. coinDenomination   (numeric, required) coin denomination.\n"

                "\nResult:\n"
                "{\n"
                "  \"Starting block\": \"x\"           (integer) First counted block\n"
                "  \"Ending block\": \"x\"             (integer) Last counted block\n"
                "  \"Number of d-denom mints\": \"x\"  (integer) number of mints of the required d denomination\n"
                "}\n"

                "\nExamples:\n" +
                HelpExampleCli("getmintsinblocks", "1200000 1000 5") +
                HelpExampleRpc("getmintsinblocks", "1200000, 1000, 5"));

    int heightStart, heightEnd;
    validaterange(params, heightStart, heightEnd, Params().Zerocoin_StartHeight());

    int d = params[2].get_int();
    libzerocoin::CoinDenomination denom = libzerocoin::IntToZerocoinDenomination(d);
    if (denom == libzerocoin::CoinDenomination::ZQ_ERROR)
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid denomination. Must be in {1, 5, 10, 50, 100, 500, 1000, 5000}");

    int num_of_mints = 0;
    {
        LOCK(cs_main);
        CBlockIndex* pindex = chainActive[heightStart];

        while (true) {
            num_of_mints += count(pindex->vMintDenominationsInBlock.begin(), pindex->vMintDenominationsInBlock.end(), denom);
            if (pindex->nHeight < heightEnd) {
                pindex = chainActive.Next(pindex);
            } else {
                break;
            }
        }
    }

    UniValue obj(UniValue::VOBJ);
    obj.push_back(Pair("Starting block", heightStart));
    obj.push_back(Pair("Ending block", heightEnd-1));
    obj.push_back(Pair("Number of "+ std::to_string(d) +"-denom mints", num_of_mints));

    return obj;
}

UniValue getserials(const UniValue& params, bool fHelp) {
    if (fHelp || params.size() < 2 || params.size() > 3)
        throw std::runtime_error(
            "getserials height range ( fVerbose )\n"
            "\nLook the inputs of any tx in a range of blocks and returns the serial numbers for any coinspend.\n"

            "\nArguments:\n"
            "1. starting_height   (numeric, required) the height of the first block to check\n"
            "2. range             (numeric, required) the amount of blocks to check\n"
            "3. fVerbose          (boolean, optional, default=False) return verbose output\n"

            "\nExamples:\n" +
            HelpExampleCli("getserials", "1254000 1000") +
            HelpExampleRpc("getserials", "1254000, 1000"));

    int heightStart, heightEnd;
    validaterange(params, heightStart, heightEnd, Params().Zerocoin_StartHeight());

    bool fVerbose = false;
    if (params.size() > 2) {
        fVerbose = params[2].get_bool();
    }

    CBlockIndex* pblockindex = nullptr;
    {
        LOCK(cs_main);
        pblockindex = chainActive[heightStart];
    }

    if (!pblockindex)
        throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid block height");

    UniValue serialsObj(UniValue::VOBJ);    // for fVerbose
    UniValue serialsArr(UniValue::VARR);

    while (true) {
        CBlock block;
        if (!ReadBlockFromDisk(block, pblockindex))
                throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");

        // loop through each tx in the block
        for (const CTransaction& tx : block.vtx) {
            std::string txid = tx.GetHash().GetHex();
            // collect the destination (first output) if fVerbose
            std::string spentTo = "";
            if (fVerbose) {
                if (tx.vout[0].IsZerocoinMint()) {
                    spentTo = "Zerocoin Mint";
                } else if (tx.vout[0].IsEmpty()) {
                    spentTo = "Zerocoin Stake";
                } else {
                    txnouttype type;
                    std::vector<CTxDestination> addresses;
                    int nRequired;
                    if (!ExtractDestinations(tx.vout[0].scriptPubKey, type, addresses, nRequired)) {
                        spentTo = strprintf("type: %d", GetTxnOutputType(type));
                    } else {
                        spentTo = CBitcoinAddress(addresses[0]).ToString();
                    }
                }
            }
            // loop through each input
            for (const CTxIn& txin : tx.vin) {
                bool isPublicSpend =  txin.IsZerocoinPublicSpend();
                if (txin.IsZerocoinSpend() || isPublicSpend) {
                    std::string serial_str;
                    int denom;
                    if (isPublicSpend) {
                        CTxOut prevOut;
                        CValidationState state;
                        if(!GetOutput(txin.prevout.hash, txin.prevout.n, state, prevOut)){
                            throw JSONRPCError(RPC_INTERNAL_ERROR, "public zerocoin spend prev output not found");
                        }
                        libzerocoin::ZerocoinParams *params = Params().Zerocoin_Params(false);
                        PublicCoinSpend publicSpend(params);
                        if (!ZPIVModule::parseCoinSpend(txin, tx, prevOut, publicSpend)) {
                            throw JSONRPCError(RPC_INTERNAL_ERROR, "public zerocoin spend parse failed");
                        }
                        serial_str = publicSpend.getCoinSerialNumber().ToString(16);
                        denom = libzerocoin::ZerocoinDenominationToInt(publicSpend.getDenomination());
                    } else {
                        libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txin);
                        serial_str = spend.getCoinSerialNumber().ToString(16);
                        denom = libzerocoin::ZerocoinDenominationToInt(spend.getDenomination());
                    }
                    if (!fVerbose) {
                        serialsArr.push_back(serial_str);
                    } else {
                        UniValue s(UniValue::VOBJ);
                        s.push_back(Pair("serial", serial_str));
                        s.push_back(Pair("denom", denom));
                        s.push_back(Pair("bitsize", (int)serial_str.size()*4));
                        s.push_back(Pair("spentTo", spentTo));
                        s.push_back(Pair("txid", txid));
                        s.push_back(Pair("blocknum", pblockindex->nHeight));
                        s.push_back(Pair("blocktime", block.GetBlockTime()));
                        serialsArr.push_back(s);
                    }
                }

            } // end for vin in tx
        } // end for tx in block

        if (pblockindex->nHeight < heightEnd) {
            LOCK(cs_main);
            pblockindex = chainActive.Next(pblockindex);
        } else {
            break;
        }

    } // end for blocks

    return serialsArr;

}

UniValue getblockindexstats(const UniValue& params, bool fHelp) {
    if (fHelp || params.size() < 2 || params.size() > 3)
        throw std::runtime_error(
                "getblockindexstats height range ( fFeeOnly )\n"
                "\nReturns aggregated BlockIndex data for blocks "
                "\n[height, height+1, height+2, ..., height+range-1]\n"

                "\nArguments:\n"
                "1. height             (numeric, required) block height where the search starts.\n"
                "2. range              (numeric, required) number of blocks to include.\n"
                "3. fFeeOnly           (boolean, optional, default=False) return only fee info.\n"

                "\nResult:\n"
                "{\n"
                "  \"first_block\": \"x\"            (integer) First counted block\n"
                "  \"last_block\": \"x\"             (integer) Last counted block\n"
                "  \"txcount\": xxxxx                (numeric) tx count (excluding coinbase/coinstake)\n"
                "  \"txcount_all\": xxxxx            (numeric) tx count (including coinbase/coinstake)\n"
                "  \"mintcount\": {              [if fFeeOnly=False]\n"
                "        \"denom_1\": xxxx           (numeric) number of mints of denom_1 occurred over the block range\n"
                "        \"denom_5\": xxxx           (numeric) number of mints of denom_5 occurred over the block range\n"
                "         ...                    ... number of mints of other denominations: ..., 10, 50, 100, 500, 1000, 5000\n"
                "  }\n"
                "  \"spendcount\": {             [if fFeeOnly=False]\n"
                "        \"denom_1\": xxxx           (numeric) number of spends of denom_1 occurred over the block range\n"
                "        \"denom_5\": xxxx           (numeric) number of spends of denom_5 occurred over the block range\n"
                "         ...                    ... number of spends of other denominations: ..., 10, 50, 100, 500, 1000, 5000\n"
                "  }\n"
                "  \"pubspendcount\": {             [if fFeeOnly=False]\n"
                "        \"denom_1\": xxxx           (numeric) number of PUBLIC spends of denom_1 occurred over the block range\n"
                "        \"denom_5\": xxxx           (numeric) number of PUBLIC spends of denom_5 occurred over the block range\n"
                "         ...                    ... number of PUBLIC spends of other denominations: ..., 10, 50, 100, 500, 1000, 5000\n"
                "  }\n"
                "  \"txbytes\": xxxxx                (numeric) Sum of the size of all txes (zPIV excluded) over block range\n"
                "  \"ttlfee\": xxxxx                 (numeric) Sum of the fee amount of all txes (zPIV mints excluded) over block range\n"
                "  \"ttlfee_all\": xxxxx             (numeric) Sum of the fee amount of all txes (zPIV mints included) over block range\n"
                "  \"feeperkb\": xxxxx               (numeric) Average fee per kb (excluding zc txes)\n"
                "}\n"

                "\nExamples:\n" +
                HelpExampleCli("getblockindexstats", "1200000 1000") +
                HelpExampleRpc("getblockindexstats", "1200000, 1000"));

    int heightStart, heightEnd;
    validaterange(params, heightStart, heightEnd);
    // return object
    UniValue ret(UniValue::VOBJ);
    ret.push_back(Pair("Starting block", heightStart));
    ret.push_back(Pair("Ending block", heightEnd));

    bool fFeeOnly = false;
    if (params.size() > 2) {
        fFeeOnly = params[2].get_bool();
    }

    CAmount nFees = 0;
    CAmount nFees_all = 0;
    int64_t nBytes = 0;
    int64_t nTxCount = 0;
    int64_t nTxCount_all = 0;

    std::map<libzerocoin::CoinDenomination, int64_t> mapMintCount;
    std::map<libzerocoin::CoinDenomination, int64_t> mapSpendCount;
    std::map<libzerocoin::CoinDenomination, int64_t> mapPublicSpendCount;
    for (auto& denom : libzerocoin::zerocoinDenomList) {
        mapMintCount.insert(std::make_pair(denom, 0));
        mapSpendCount.insert(std::make_pair(denom, 0));
        mapPublicSpendCount.insert(std::make_pair(denom, 0));
    }

    CBlockIndex* pindex = nullptr;
    {
        LOCK(cs_main);
        pindex = chainActive[heightStart];
    }

    if (!pindex)
        throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid block height");

    while (true) {
        CBlock block;
        if (!ReadBlockFromDisk(block, pindex)) {
            throw JSONRPCError(RPC_DATABASE_ERROR, "failed to read block from disk");
        }

        CAmount nValueIn = 0;
        CAmount nValueOut = 0;
        const int ntx = block.vtx.size();
        nTxCount_all += ntx;
        nTxCount = block.IsProofOfStake() ? nTxCount + ntx - 2 : nTxCount + ntx - 1;

        // loop through each tx in block and save size and fee
        for (const CTransaction& tx : block.vtx) {
            if (tx.IsCoinBase() || (tx.IsCoinStake() && !tx.HasZerocoinSpendInputs()))
                continue;

            // fetch input value from prevouts and count spends
            for (unsigned int j = 0; j < tx.vin.size(); j++) {
                if (tx.vin[j].IsZerocoinSpend()) {
                    if (!fFeeOnly)
                        mapSpendCount[libzerocoin::IntToZerocoinDenomination(tx.vin[j].nSequence)]++;
                    continue;
                }
                if (tx.vin[j].IsZerocoinPublicSpend()) {
                    if (!fFeeOnly)
                        mapPublicSpendCount[libzerocoin::IntToZerocoinDenomination(tx.vin[j].nSequence)]++;
                    continue;
                }

                COutPoint prevout = tx.vin[j].prevout;
                CTransaction txPrev;
                uint256 hashBlock;
                if(!GetTransaction(prevout.hash, txPrev, hashBlock, true))
                    throw JSONRPCError(RPC_DATABASE_ERROR, "failed to read tx from disk");
                nValueIn += txPrev.vout[prevout.n].nValue;
            }

            // zc spends have no fee
            if (tx.HasZerocoinSpendInputs())
                continue;

            // sum output values in nValueOut
            for (unsigned int j = 0; j < tx.vout.size(); j++) {
                nValueOut += tx.vout[j].nValue;
            }

            // update sums
            nFees_all += nValueIn - nValueOut;
            if (!tx.HasZerocoinMintOutputs()) {
                nFees += nValueIn - nValueOut;
                nBytes += tx.GetSerializeSize(SER_NETWORK, CLIENT_VERSION);
            }
        }

        // add mints to map
        if (!fFeeOnly) {
            for (auto& denom : libzerocoin::zerocoinDenomList) {
                mapMintCount[denom] += count(pindex->vMintDenominationsInBlock.begin(), pindex->vMintDenominationsInBlock.end(), denom);
            }
        }

        if (pindex->nHeight < heightEnd) {
            LOCK(cs_main);
            pindex = chainActive.Next(pindex);
        } else {
            break;
        }
    }

    // get fee rate
    CFeeRate nFeeRate = CFeeRate(nFees, nBytes);

    // return UniValue object
    ret.push_back(Pair("txcount", (int64_t)nTxCount));
    ret.push_back(Pair("txcount_all", (int64_t)nTxCount_all));
    if (!fFeeOnly) {
        UniValue mint_obj(UniValue::VOBJ);
        UniValue spend_obj(UniValue::VOBJ);
        UniValue pubspend_obj(UniValue::VOBJ);
        for (auto& denom : libzerocoin::zerocoinDenomList) {
            mint_obj.push_back(Pair(strprintf("denom_%d", ZerocoinDenominationToInt(denom)), mapMintCount[denom]));
            spend_obj.push_back(Pair(strprintf("denom_%d", ZerocoinDenominationToInt(denom)), mapSpendCount[denom]));
            pubspend_obj.push_back(Pair(strprintf("denom_%d", ZerocoinDenominationToInt(denom)), mapPublicSpendCount[denom]));
        }
        ret.push_back(Pair("mintcount", mint_obj));
        ret.push_back(Pair("spendcount", spend_obj));
        ret.push_back(Pair("publicspendcount", pubspend_obj));

    }
    ret.push_back(Pair("txbytes", (int64_t)nBytes));
    ret.push_back(Pair("ttlfee", FormatMoney(nFees)));
    ret.push_back(Pair("ttlfee_all", FormatMoney(nFees_all)));
    ret.push_back(Pair("feeperkb", FormatMoney(nFeeRate.GetFeePerK())));

    return ret;

}


text:
<?php
$this->breadcrumbs=array(
	'Modules',
);

$this->menu=array(
	array('label'=>'Create Module','url'=>array('create')),
	array('label'=>'Manage Module','url'=>array('admin')),
);
?>

Modules

<?php $this->widget('bootstrap.widgets.TbListView',array(
	'dataProvider'=>$dataProvider,
	'itemView'=>'_view',
)); ?>

redpajama_set_name: RedPajamaGithub


text:
This crawler is intended to crawl specific files from GitHub. It uses the GitHub search API [search code functionality](https://developer.github.com/v3/search/#search-code) to search for specific keywords in code files and certain extensions. When it finds these files, they are stored locally on the file system and indexed in a SQL database. The crawler is based on Python and is written in Python 2. In case you want to use it with Python 3, you will need to update the ```print``` statements. Also, this project is intended as a "quick and dirty" crawler, so it is not properly tested and there is currently no logging. Please feel free to extend/alter the program the program to your specifications.

## Setup python
Copy the repository files to a local directory. It is a good practice to have a virtualenv setup. From your local folder you can install the python requirements in your virtualenv.

```
pip install -r requirements.txt
```

## Setup PostgreSQL
I like and use PostgreSQL, but you can also use another SQL like DB with minimal adjustments. If you also want to use PostgreSQL install it on your machine.

```
sudo apt-get install postgresql postgresql-contrib
```

If you like a GUI then install it.

```
sudo apt-get install pgadmin3
```

Then set up the server according to this tutorial: [https://help.ubuntu.com/community/PostgreSQL](https://help.ubuntu.com/community/PostgreSQL)

The crawler expects a PostgreSQL user and a database to store the contracts. You could for example create the following users and databases. Make sure your user has the rights to create and alter tables in the DB.

```
user: github-crawler
password: your-password-here
db: smartcontracts
```

## Setup the crawler
In the root folder of the crawler create a ```config.yml``` file. To crawl all GitHub repositories you will need to create a token on GitHub. Follow the steps described here: [https://help.github.com/articles/creating-an-access-token-for-command-line-use/](https://help.github.com/articles/creating-an-access-token-for-command-line-use/)
Fill in the details to setup the crawler as described below. You can of course change the configuration, if you e.g. have a remote SQL server or want to search for different queries/extensions.

```
sql:
    host: localhost
    user: github-crawler
    password: your-password-here
    db: smartcontracts
    port: 5432
github:
    token:  your-github-token
    user: your-github-user
types:
    ethereum:
        extension: sol
        term: contract
        language: solidity
        platform: ethereum
```

In types, the search is configured. If you like to extend it, just add your new types and then instantiate the objects in the main method. Please note that GitHub limits your API requests!

```
types:
    ethereum:
        extension: sol
        term: contract
        language: solidity
        platform: ethereum
    hyperledger-java:
        extension: java
        term: ChaincodeBase
        language: Java
        platform: hyperledger-fabric
    hyperledger-go:
        extension: go
        term: chaincode
        language: go
        platform: hyperledger-fabric
```

## Run the crawler

```
python __main__.py >> /tmp/github-crawler.log 2>&1
```

You could also run it as a cronjob in the background. Just edit your cronfile.

```
crontab -e
```

Add this line to crawl it at noon every day.

```
00 12 * * * /usr/bin/python2.7 /home/github-crawler/crawler/__main__.py >> /tmp/github-crawler.log 2>&1
```

## Userful links
[https://developer.github.com/v3/rate_limit/](https://developer.github.com/v3/rate_limit/)

[help.github.com/articles/searching-code/](help.github.com/articles/searching-code/)

## ToDo
- include logging
- include unit tests
- package to deb


text:
package mailbox.exceptions;

public class PostingNotFound extends MailHandlerException {
    private static final long serialVersionUID = 6604209946955366044L;

    public PostingNotFound(Long number) {
        super(String.format("Posting %d not found", number));
    }
}


text:
package org.apache.continuum.web.test;

import org.apache.continuum.web.test.parent.AbstractAdminTest;
import org.testng.annotations.Test;

/**
 * @author José Morales Martínez
 */
@Test( groups = { "schedule" } )
public class ScheduleTest
    extends AbstractAdminTest
{
    public void testAddScheduleNoBuildQueueToBeUsed()
    {
        String SCHEDULE_NAME = getProperty( "SCHEDULE_NAME" );
        String SCHEDULE_DESCRIPTION = getProperty( "SCHEDULE_DESCRIPTION" );
        String SCHEDULE_EXPR_SECOND = getProperty( "SCHEDULE_EXPR_SECOND" );
        String SCHEDULE_EXPR_MINUTE = getProperty( "SCHEDULE_EXPR_MINUTE" );
        String SCHEDULE_EXPR_HOUR = getProperty( "SCHEDULE_EXPR_HOUR" );
        String SCHEDULE_EXPR_DAY_MONTH = getProperty( "SCHEDULE_EXPR_DAY_MONTH" );
        String SCHEDULE_EXPR_MONTH = getProperty( "SCHEDULE_EXPR_MONTH" );
        String SCHEDULE_EXPR_DAY_WEEK = getProperty( "SCHEDULE_EXPR_DAY_WEEK" );
        String SCHEDULE_EXPR_YEAR = getProperty( "SCHEDULE_EXPR_YEAR" );
        String SCHEDULE_MAX_TIME = getProperty( "SCHEDULE_MAX_TIME" );
        String SCHEDULE_PERIOD = getProperty( "SCHEDULE_PERIOD" );
        goToAddSchedule();
        addEditSchedule( SCHEDULE_NAME, SCHEDULE_DESCRIPTION, SCHEDULE_EXPR_SECOND, SCHEDULE_EXPR_MINUTE,
                         SCHEDULE_EXPR_HOUR, SCHEDULE_EXPR_DAY_MONTH, SCHEDULE_EXPR_MONTH, SCHEDULE_EXPR_DAY_WEEK,
                         SCHEDULE_EXPR_YEAR, SCHEDULE_MAX_TIME, SCHEDULE_PERIOD, false, false );
        assertTextPresent( "Used Build Queues cannot be empty" );
    }

    @Test( dependsOnMethods = { "testAddScheduleNoBuildQueueToBeUsed" } )
    public void testAddSchedule()
    {
        String SCHEDULE_NAME = getProperty( "SCHEDULE_NAME" );
        String SCHEDULE_DESCRIPTION = getProperty( "SCHEDULE_DESCRIPTION" );
        String SCHEDULE_EXPR_SECOND = getProperty( "SCHEDULE_EXPR_SECOND" );
        String SCHEDULE_EXPR_MINUTE = getProperty( "SCHEDULE_EXPR_MINUTE" );
        String SCHEDULE_EXPR_HOUR = getProperty( "SCHEDULE_EXPR_HOUR" );
        String SCHEDULE_EXPR_DAY_MONTH = getProperty( "SCHEDULE_EXPR_DAY_MONTH" );
        String SCHEDULE_EXPR_MONTH = getProperty( "SCHEDULE_EXPR_MONTH" );
        String SCHEDULE_EXPR_DAY_WEEK = getProperty( "SCHEDULE_EXPR_DAY_WEEK" );
        String SCHEDULE_EXPR_YEAR = getProperty( "SCHEDULE_EXPR_YEAR" );
        String SCHEDULE_MAX_TIME = getProperty( "SCHEDULE_MAX_TIME" );
        String SCHEDULE_PERIOD = getProperty( "SCHEDULE_PERIOD" );
        goToAddSchedule();
        addEditSchedule( SCHEDULE_NAME, SCHEDULE_DESCRIPTION, SCHEDULE_EXPR_SECOND, SCHEDULE_EXPR_MINUTE,
                         SCHEDULE_EXPR_HOUR, SCHEDULE_EXPR_DAY_MONTH, SCHEDULE_EXPR_MONTH, SCHEDULE_EXPR_DAY_WEEK,
                         SCHEDULE_EXPR_YEAR, SCHEDULE_MAX_TIME, SCHEDULE_PERIOD, true, true );
    }

    @Test( dependsOnMethods = { "testAddScheduleNoBuildQueueToBeUsed" } )
    public void testAddScheduleWithInvalidValues()
    {
        String SCHEDULE_NAME = "!@#$<>?etc";
        String SCHEDULE_DESCRIPTION = "![]<>'^&etc";
        String SCHEDULE_EXPR_SECOND = getProperty( "SCHEDULE_EXPR_SECOND" );
        String SCHEDULE_EXPR_MINUTE = getProperty( "SCHEDULE_EXPR_MINUTE" );
        String SCHEDULE_EXPR_HOUR = getProperty( "SCHEDULE_EXPR_HOUR" );
        String SCHEDULE_EXPR_DAY_MONTH = getProperty( "SCHEDULE_EXPR_DAY_MONTH" );
        String SCHEDULE_EXPR_MONTH = getProperty( "SCHEDULE_EXPR_MONTH" );
        String SCHEDULE_EXPR_DAY_WEEK = getProperty( "SCHEDULE_EXPR_DAY_WEEK" );
        String SCHEDULE_EXPR_YEAR = getProperty( "SCHEDULE_EXPR_YEAR" );
        String SCHEDULE_MAX_TIME = getProperty( "SCHEDULE_MAX_TIME" );
        String SCHEDULE_PERIOD = getProperty( "SCHEDULE_PERIOD" );
        goToAddSchedule();
        addEditSchedule( SCHEDULE_NAME, SCHEDULE_DESCRIPTION, SCHEDULE_EXPR_SECOND, SCHEDULE_EXPR_MINUTE,
                         SCHEDULE_EXPR_HOUR, SCHEDULE_EXPR_DAY_MONTH, SCHEDULE_EXPR_MONTH, SCHEDULE_EXPR_DAY_WEEK,
                         SCHEDULE_EXPR_YEAR, SCHEDULE_MAX_TIME, SCHEDULE_PERIOD, true, false );
        assertTextPresent( "Name contains invalid characters." );
    }

    public void testAddInvalidSchedule()
    {
        goToAddSchedule();
        addEditSchedule( "", "", "", "", "", "", "", "", "", "", "", true, false );
        assertTextPresent( "Invalid cron expression value(s)" );
        assertTextPresent( "Name is required and cannot contain spaces only" );
        assertTextPresent( "Description is required and cannot contain spaces only" );
    }

    @Test( dependsOnMethods = { "testAddSchedule" } )
    public void testAddDuplicatedSchedule()
    {
        String SCHEDULE_NAME = getProperty( "SCHEDULE_NAME" );
        String SCHEDULE_DESCRIPTION = getProperty( "SCHEDULE_DESCRIPTION" );
        String SCHEDULE_EXPR_SECOND = getProperty( "SCHEDULE_EXPR_SECOND" );
        String SCHEDULE_EXPR_MINUTE = getProperty( "SCHEDULE_EXPR_MINUTE" );
        String SCHEDULE_EXPR_HOUR = getProperty( "SCHEDULE_EXPR_HOUR" );
        String SCHEDULE_EXPR_DAY_MONTH = getProperty( "SCHEDULE_EXPR_DAY_MONTH" );
        String SCHEDULE_EXPR_MONTH = getProperty( "SCHEDULE_EXPR_MONTH" );
        String SCHEDULE_EXPR_DAY_WEEK = getProperty( "SCHEDULE_EXPR_DAY_WEEK" );
        String SCHEDULE_EXPR_YEAR = getProperty( "SCHEDULE_EXPR_YEAR" );
        String SCHEDULE_MAX_TIME = getProperty( "SCHEDULE_MAX_TIME" );
        String SCHEDULE_PERIOD = getProperty( "SCHEDULE_PERIOD" );
        goToAddSchedule();
        addEditSchedule( SCHEDULE_NAME, SCHEDULE_DESCRIPTION, SCHEDULE_EXPR_SECOND, SCHEDULE_EXPR_MINUTE,
                         SCHEDULE_EXPR_HOUR, SCHEDULE_EXPR_DAY_MONTH, SCHEDULE_EXPR_MONTH, SCHEDULE_EXPR_DAY_WEEK,
                         SCHEDULE_EXPR_YEAR, SCHEDULE_MAX_TIME, SCHEDULE_PERIOD, true, false );
        assertTextPresent( "A Schedule with the same name already exists" );
    }

    @Test( dependsOnMethods = { "testAddDuplicatedSchedule" } )
    public void testEditSchedule()
    {
        String SCHEDULE_NAME = getProperty( "SCHEDULE_NAME" );
        String SCHEDULE_DESCRIPTION = getProperty( "SCHEDULE_DESCRIPTION" );
        String SCHEDULE_EXPR_SECOND = getProperty( "SCHEDULE_EXPR_SECOND" );
        String SCHEDULE_EXPR_MINUTE = getProperty( "SCHEDULE_EXPR_MINUTE" );
        String SCHEDULE_EXPR_HOUR = getProperty( "SCHEDULE_EXPR_HOUR" );
        String SCHEDULE_EXPR_DAY_MONTH = getProperty( "SCHEDULE_EXPR_DAY_MONTH" );
        String SCHEDULE_EXPR_MONTH = getProperty( "SCHEDULE_EXPR_MONTH" );
        String SCHEDULE_EXPR_DAY_WEEK = getProperty( "SCHEDULE_EXPR_DAY_WEEK" );
        String SCHEDULE_EXPR_YEAR = getProperty( "SCHEDULE_EXPR_YEAR" );
        String SCHEDULE_MAX_TIME = getProperty( "SCHEDULE_MAX_TIME" );
        String SCHEDULE_PERIOD = getProperty( "SCHEDULE_PERIOD" );
        String name = "new_name";
        String description = "new_description";
        String second = "1";
        String minute = "20";
        String hour = "15";
        String dayMonth = "20";
        String month = "9";
        String dayWeek = "?";
        String year = "";
        String maxTime = "9000";
        String period = "0";
        goToEditSchedule( SCHEDULE_NAME, SCHEDULE_DESCRIPTION, SCHEDULE_EXPR_SECOND, SCHEDULE_EXPR_MINUTE,
                          SCHEDULE_EXPR_HOUR, SCHEDULE_EXPR_DAY_MONTH, SCHEDULE_EXPR_MONTH, SCHEDULE_EXPR_DAY_WEEK,
                          SCHEDULE_EXPR_YEAR, SCHEDULE_MAX_TIME, SCHEDULE_PERIOD );
        addEditSchedule( name, description, second, minute, hour, dayMonth, month, dayWeek, year, maxTime, period,
                         false, true );
        goToEditSchedule( name, description, second, minute, hour, dayMonth, month, dayWeek, year, maxTime, period );
        addEditSchedule( SCHEDULE_NAME, SCHEDULE_DESCRIPTION, SCHEDULE_EXPR_SECOND, SCHEDULE_EXPR_MINUTE,
                         SCHEDULE_EXPR_HOUR, SCHEDULE_EXPR_DAY_MONTH, SCHEDULE_EXPR_MONTH, SCHEDULE_EXPR_DAY_WEEK,
                         SCHEDULE_EXPR_YEAR, SCHEDULE_MAX_TIME, SCHEDULE_PERIOD, false, true );
    }

    @Test( dependsOnMethods = { "testEditSchedule" } )
    public void testDeleteSchedule()
    {
        String SCHEDULE_NAME = getProperty( "SCHEDULE_NAME" );
        removeSchedule( SCHEDULE_NAME );
    }
}


text:
/*
 * This file is part of Beads. See http://www.beadsproject.net for all information.
 */
package net.beadsproject.beads.data.buffers;

import net.beadsproject.beads.data.Buffer;
import net.beadsproject.beads.data.BufferFactory;

/**
 * Creates a {@link Buffer} consisting of a triangle wave in the range [-1,1].
 *
 * @see Buffer BufferFactory
 * @author ollie
 */
public class TriangleBuffer extends BufferFactory {

    /* (non-Javadoc)
     * @see net.beadsproject.beads.data.BufferFactory#generateBuffer(int)
     */
    public Buffer generateBuffer(int bufferSize) {
    	Buffer b = new Buffer(bufferSize);
        for(int i = 0; i < bufferSize; i++) {
        	if(i < bufferSize / 2) {
        		b.buf[i] = (float)i / ((float)bufferSize / 2f) * 2.0f - 1.0f;
        	} else {
        		b.buf[i] = 1f - ((float)(i - (bufferSize / 2)) / ((float)bufferSize / 2f) * 2.0f - 1.0f);
        	}
        }
    	return b;
    }

    /* (non-Javadoc)
     * @see net.beadsproject.beads.data.BufferFactory#getName()
     */
    public String getName() {
    	return "Triangle";
    }

}


text:
import os
from datetime import datetime

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
from django.utils.translation import ugettext_lazy as _

from model_utils.models import TimeStampedModel
from audit_log.models import AuthStampedModel

class AttachmentManager(models.Manager):
    def attachments_for_object(self, obj):
        object_type = ContentType.objects.get_for_model(obj)
        return self.filter(content_type__pk=object_type.id,
                           object_id=obj.id)

class Attachment(TimeStampedModel, AuthStampedModel):
    def attachment_upload(instance, filename):
        """Stores the attachment in a "per module/appname/primary key" folder"""

        return 'attachments/%s/%s/%s' % (
            '%s_%s' % (instance.content_object._meta.app_label,
                       instance.content_object._meta.object_name.lower()),
            instance.content_object.pk,
            datetime.now().strftime("%Y%m%d%H%M-%f") + os.path.splitext(filename)[1])

    objects = AttachmentManager()

    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')
    attachment_file = models.FileField('attachment', upload_to=attachment_upload)
    description = models.CharField(max_length=255, blank=True)

    ATTACHMENT_TYPE_CHOICES = (
        ('passport', _('Passport')),
        ('cheque', _('Cheque')),
        ('other', _('Other Document')),
    )
    attachment_type = models.CharField(
        "Attachment Type", max_length=50, choices=ATTACHMENT_TYPE_CHOICES)

    class Meta:
        # ordering = ['-created']
        permissions = (
            ('delete_foreign_attachments', 'Can delete foreign attachments'),
        )

    def __str__(self):
        return 'Attached file: %s' % self.attachment_type

    @property
    def filename(self):
        return os.path.split(self.attachment_file.name)[1]


text:
package org.pinae.rafiki.trigger;

import org.pinae.rafiki.trigger.Trigger;
import org.pinae.rafiki.trigger.TriggerException;
import org.pinae.rafiki.trigger.impl.CronTrigger;

import static org.pinae.rafiki.trigger.helper.DateHelper.today;

import org.apache.log4j.Logger;

public class CronTriggerExample {

	private static Logger logger = Logger.getLogger(CronTriggerExample.class);

	public static Trigger getTrigger0(){
		CronTrigger trigger = null;
		try {
			trigger = new CronTrigger("0-30/5 * * * * * *");
		} catch (TriggerException e) {
			logger.error(String.format("getTrigger Exception: exception=%s", e.getMessage()));
		}
		return trigger;
	}

	public static Trigger getTrigger1(){
		CronTrigger trigger = null;
		try {
			trigger = new CronTrigger("0 * * * * * *");
		} catch (TriggerException e) {
			logger.error(String.format("getTrigger Exception: exception=%s", e.getMessage()));
		}
		return trigger;
	}

	public static Trigger getTrigger2(){
		CronTrigger trigger = null;
		try {
			trigger = new CronTrigger("30 1-5 * * * * *");
		} catch (TriggerException e) {
			logger.error(String.format("getTrigger Exception: exception=%s", e.getMessage()));
		}
		return trigger;
	}

	public static Trigger getTrigger3(){
		CronTrigger trigger = null;
		try {
			trigger = new CronTrigger("0 * 12-17 * * * *");
		} catch (TriggerException e) {
			logger.error(String.format("getTrigger Exception: exception=%s", e.getMessage()));
		}
		return trigger;
	}

	public static Trigger getTrigger4(){
		CronTrigger trigger = null;
		try {
			trigger = new CronTrigger("0 * * 25-30 * * *");
		} catch (TriggerException e) {
			logger.error(String.format("getTrigger Exception: exception=%s", e.getMessage()));
		}
		return trigger;
	}

	public static Trigger getTrigger5(){
		CronTrigger trigger = null;
		try {
			trigger = new CronTrigger("0 * * * DEC SUN *");
		} catch (TriggerException e) {
			logger.error(String.format("getTrigger Exception: exception=%s", e.getMessage()));
		}
		return trigger;
	}

	public static Trigger getTrigger6(){
		CronTrigger trigger = null;
		try {
			trigger = new CronTrigger("0 * * * DEC * 2013");
		} catch (TriggerException e) {
			logger.error(String.format("getTrigger Exception: exception=%s", e.getMessage()));
		}
		return trigger;
	}

	public static Trigger getTrigger7(){
		CronTrigger trigger = null;
		try {
			trigger = new CronTrigger("0-30/10 * * 5-12 MAY * 2014");
			trigger.setStartTime(today(15, 10, 0));
			trigger.setEndTime(today(21, 30, 0));
		} catch (TriggerException e) {
			logger.error(String.format("getTrigger Exception: exception=%s", e.getMessage()));
		}
		return trigger;
	}
}


text:
// Copyright (c) André N. Klingsheim. See License.txt in the project root for license information.

using System.Configuration;

namespace NWebsec.Modules.Configuration.Validation
{
    public class RedirectSameHostConfigurationElementValidatorAttribute : ConfigurationValidatorAttribute
    {
        public override ConfigurationValidatorBase ValidatorInstance => new RedirectSameHostConfigurationElementValidator();
    }
}


text:
using System;
using System.Threading.Tasks;
using Nimbus.StressTests.ThroughputTests.MessageContracts;
using NUnit.Framework;

namespace Nimbus.StressTests.ThroughputTests
{
    [TestFixture]
    public class WhenSendingManyCommandsOfTheSameType : ThroughputSpecificationForBus
    {
        public override async Task SendMessages(IBus bus, Func<bool> shouldKeepSending)
        {
            while (shouldKeepSending())
            {
                await bus.Send(new FooCommand());
                IncrementExpectedMessageCount();
            }
        }
    }
}


text:
/*
 * File:   StartResult.h
 * Author: rmartins
 *
 * Created on August 5, 2010, 10:42 AM
 */

#ifndef STARTRESULT_H
#define	STARTRESULT_H

class StartResult {
public:
    StartResult();
    StartResult(const StartResult& orig);
    virtual ~StartResult();
private:

};

#endif	/* STARTRESULT_H */


text:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
       xsi:schemaLocation="http://www.springframework.org/schema/data/elasticsearch http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

    <elasticsearch:transport-client id="client" cluster-name="elasticsearch" cluster-nodes="127.0.0.1:9300"/>

    <bean name="elasticsearchTemplate" class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
        <constructor-arg name="client" ref="client"/>
    </bean>

</beans>


text:
//
//  YOFMDBExecutor.m
//
//  Created by Yusuke Ohashi on 1/23/15.
//  Copyright (c) 2015 Ohashi Yusuke. All rights reserved.
//

#import "YOFMDBExecutor.h"

@implementation YOFMDBExecutor
@synthesize db = _db;

static YOFMDBExecutor *SINGLETON = nil;
static bool isFirstAccess = YES;

#pragma mark - Public Method

+ (id)sharedInstance {
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
	    isFirstAccess = NO;
	    SINGLETON = [[super allocWithZone:NULL] init];
	});

	return SINGLETON;
}

#pragma mark - Life Cycle

+ (id)allocWithZone:(NSZone *)zone {
	return [self sharedInstance];
}

+ (id)copyWithZone:(struct _NSZone *)zone {
	return [self sharedInstance];
}

+ (id)mutableCopyWithZone:(struct _NSZone *)zone {
	return [self sharedInstance];
}

- (id)copy {
	return [[YOFMDBExecutor alloc] init];
}

- (id)mutableCopy {
	return [[YOFMDBExecutor alloc] init];
}

- (id)init {
	if (SINGLETON) {
		return SINGLETON;
	}
	if (isFirstAccess) {
		[self doesNotRecognizeSelector:_cmd];
	}
	self = [super init];
	return self;
}

/**
 *  Create Database if it doesn't exist.
 *
 *  @param dbname database name.
 */
- (void)setup:(NSString *)dbname {
	BOOL success;

	NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
	NSString *documentDir = [documentPaths objectAtIndex:0];
	NSString *databasePath = [documentDir stringByAppendingPathComponent:dbname];
	NSFileManager *fileManager = [NSFileManager defaultManager];
	success = [fileManager fileExistsAtPath:databasePath];

	if (!success) {
		NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:dbname];
		[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
	}

	_db = [FMDatabase databaseWithPath:databasePath];
}

- (void)exec:(void (^)(FMDatabase *db))block;
{
	if ([self.db open]) {
		if (block) {
			block(self.db);
		}
		[self.db close];
	}
}

@end


text:
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>static_buffer_base::prepare</title>
<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../../index.html" title="Chapter 1. Boost.Beast">
<link rel="up" href="../boost__beast__static_buffer_base.html" title="static_buffer_base">
<link rel="prev" href="mutable_data.html" title="static_buffer_base::mutable_data">
<link rel="next" href="reset.html" title="static_buffer_base::reset">

Home
Libraries
People
FAQ
More

static_buffer_base::prepare

Get a list of buffers that represent the output
          sequence, with the given size.

          Synopsis

mutable_buffers_type
prepare(
    std::size_t size);

          Description

          Parameters

<colgroup>
<col>
<col>
</colgroup>

                    Name

                    Description

                    size

                    The number of bytes to request.

          Exceptions

<colgroup>
<col>
<col>
</colgroup>

                    Type

                    Thrown On

                    std::length_error

                    if the size would exceed the capacity.

Copyright © 2016, 2017 Vinnie Falco

        Distributed under the Boost Software License, Version 1.0. (See accompanying
        file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


text:
package com.dianping.zebra.shard.jdbc.parallel;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

import org.junit.Test;

import com.dianping.zebra.group.jdbc.DataSourceEntry;
import com.dianping.zebra.group.jdbc.GroupDataSource;
import com.dianping.zebra.group.jdbc.MultiDatabaseTestCase;
import com.dianping.zebra.group.util.SqlAliasManager;

import junit.framework.Assert;

public class ParallelPerformanceTest extends MultiDatabaseTestCase {

	@Override
	protected String getConfigManagerType() {
		return "local";
	}

	@Override
	protected DataSourceEntry[] getDataSourceEntryArray() {
		DataSourceEntry[] entries = new DataSourceEntry[3];

		entries[0] = new DataSourceEntry("jdbc:h2:mem:test;MVCC=TRUE;DB_CLOSE_DELAY=-1", "datasets.xml", true);
		entries[1] = new DataSourceEntry("jdbc:h2:mem:test1;MVCC=TRUE;DB_CLOSE_DELAY=-1", "datasets1.xml", false);
		entries[2] = new DataSourceEntry("jdbc:h2:mem:test2;MVCC=TRUE;DB_CLOSE_DELAY=-1", "datasets2.xml", false);

		return entries;
	}

	@Override
	protected String getResourceId() {
		return "sample.ds.v2";
	}

	@Override
	protected String getSchema() {
		return getClass().getResource("/schema.sql").getPath();
	}

	@Test
	public void test() {
		GroupDataSource ds = new GroupDataSource(getResourceId());
		ds.setConfigManagerType(getConfigManagerType());
		ds.init();

		List<Callable<UpdateResult>> tasks = new ArrayList<Callable<UpdateResult>>();
		try {
			Connection conn = ds.getConnection();

			long now = System.currentTimeMillis();
			for (int i = 0; i < 5; i++) {

				PreparedStatement stmt = conn.prepareStatement("update PERSON p set p.Name = ?");
				stmt.setString(1, "leo6");

				List<PreparedStatement> stmts = new ArrayList<PreparedStatement>();
				stmts.add(stmt);

				tasks.add(new PreparedStatementExecuteUpdateCallable(stmts, SqlAliasManager.getSqlAlias()));
			}

			List<Future<UpdateResult>> futures = SQLThreadPoolExecutor.getInstance(false).invokeSQLs(tasks);

			int affectedRows = 0;
			for (Future<UpdateResult> f : futures) {
				try {
					UpdateResult updateResult = f.get();

					affectedRows += updateResult.getAffectedRows();
				} catch (Exception e) {
					// normally can't be here
					throw new SQLException(e);
				}
			}

			Assert.assertEquals(5, affectedRows);

			System.out.println("Time = " + (System.currentTimeMillis() - now));
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

}


text:
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DbContextProductRepository.cs" company="Catel development team">
//   Copyright (c) 2008 - 2015 Catel development team. All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace Catel.Test.EntityFramework5.DbContextTest.Repositories
{
    using System.Data.Entity;

    using Catel.Data.Repositories;

    public interface IDbContextProductRepository : IEntityRepository<DbContextProduct, int>
    {
    }

    public class DbContextProductRepository : EntityRepositoryBase<DbContextProduct, int>, IDbContextProductRepository
    {
        #region Constructors
        public DbContextProductRepository(DbContext dbContext)
            : base(dbContext)
        {
        }
        #endregion
    }
}


text:
import * as CrossFilter from 'crossfilter';
import * as d3 from 'd3';
import * as moment from 'moment';

import {Base} from './Base';
import {ColorMap} from './colormap';

/**
 * See examples on GitHub.
 */
export class WeekdayRect extends Base {

    protected dayOfWeekScale: d3.scale.Ordinal<any, any>;
    protected xFrom: number;
    protected xTo: number;

    /**
     * Constructor method for making a punchcard visualization with the day of
     * week on the horizontal axis, and hour of day on the vertical axis, using
     * rectangular symbols to represent how many rows from the input data fall
     * within the area covered by each rectangle.
     * @param  {CrossFilter.CrossFilter<any>} cf Crossfilter object
     * containing the data.
     * @param  {string} domElemId Name of the DOM element in which to draw.
     * @return {[type]} A reference to the instance of WeekdayRect.
     */
    constructor(cf: CrossFilter.CrossFilter<any>, domElemId: string, datekey: string) {

        super(cf, domElemId, datekey);

        this.marginBottom = 50;
        this.xlabel = 'Day of week';
        this.title = 'WeekdayRect title';
        this.colormap = new ColorMap('summer');
        this.defineDimensions();
        this.domElem.classList.add('punchcard-weekday-rect');
        this.update();

    }

    /**
     * define the crossfilter dimensions as used by this class
     * @return {WeekdayRect} A reference to the instance of WeekdayRect
     */
    protected defineDimensions(): WeekdayRect {

        // based on example from
        // http://stackoverflow.com/questions/16766986/is-it-possible-to-group-by-multiple-dimensions-in-crossfilter

        this.dim.weekdayAndHourOfDay = this.cf.dimension((d: any) => {
            // stringify() and later, parse() to get keyed objects
            let m: moment.Moment;
            if (d.hasOwnProperty(this.datekey)) {
                m = moment(d[this.datekey]);
                const obj: any = {};
                obj.weekday = m.format('ddd');
                obj.hourOfDay = m.hour();
                return JSON.stringify(obj);
            } else {
                throw new Error('datekey undefined');
            }
        });
        this.canDraw = true;

        return this;
    }

    /**
     * This method defines which other methods to call in order to create
     * a punchcard graph with the day of week on the horizontal axis and the
     * time of day on the vertical axis. Mostly calls methods of the parent
     * class, Base, but for example the symbols for this class are SVG rects,
     * so it calls its own method .drawSymbols() for that.
     *
     * Successful drawing depends on whether the container is currently visible,
     * and whether there is enough information in the instance to draw anything
     * at all.
     *
     * This method overrides stub method in parent class.
     *
     * @return {WeekdayRect} A reference to an instance of WeekdayRect.
     */
    protected draw(): WeekdayRect {

        if (this.domElem.classList.contains('hidden')) {
            // div is hidden
            return this;
        } else {
            // div is visible
            if (this.canDraw) {
                // dimensions have been defined
                super.drawSvg();
                super.drawChartBody();
                this.drawHorizontalAxis();
                super.drawHorizontalAxisLabel();
                super.drawVerticalAxis();
                super.drawVerticalAxisLabel();
                super.drawTitle();
                this.drawSymbols();
                super.drawBox();
                super.drawLegend();
                super.drawFooter();
            }

            return this;
        }
    }

    /**
     * This method adds an SVG g element with many SVG rects in it. Each rect
     * represents the count of how many data rows fall within the area covered
     * by the rect, where the horizontal boundaries dictate the day-of-week and
     * the vertical boundaries dictate the time of day range.
     * @return {WeekdayRect} A reference to the instance of WeekdayRect.
     */
    protected drawSymbols(): WeekdayRect {

        const w: number = this.domElem.clientWidth - this.marginLeft - this.marginRight - this.legendWidth;
        const h: number = this.domElem.clientHeight - this.marginTop - this.marginBottom;
        const dx: number = this.marginLeft;
        const dy: number = this.marginTop + h;
        const symbolMargin = {left: 0, right: 0, top: 0, bottom: 0}; // pixels
        const symbolWidth: number = w / 7 - symbolMargin.left - symbolMargin.right;
        const symbolHeight: number = h / 24 - symbolMargin.top - symbolMargin.bottom;

        // based on example from
        // http://stackoverflow.com/questions/16766986/is-it-possible-to-group-by-multiple-dimensions-in-crossfilter
        // forEach method could be very expensive on write.
        const group = this.dim.weekdayAndHourOfDay.group();
        group.all().forEach((d: any) => {
            // parse the json string created above
            d.key = JSON.parse(d.key);
        });
        const data: any = group.all();

        // determine the min and max in the count in order to set the color
        // limits on the colormap later
        let lowest = Number.POSITIVE_INFINITY;
        let highest = Number.NEGATIVE_INFINITY;
        for (const elem of data) {
            if (elem.value < lowest) {
                lowest = elem.value;
            }
            if (elem.value > highest) {
                highest = elem.value;
            }
        }
        this.colormap.cLimLow = lowest;
        this.colormap.cLimHigh = highest;

        // draw the rects
        this.svg
            .append('g')
            .attr('class', 'symbol')
            .attr('transform', 'translate(' + dx + ',' + dy + ')')
            .selectAll('rect.symbol')
                .data(data)
                .enter()
                .append('rect')
                    .attr('class', 'symbol')
                    .attr('x', (d: any) => {
                        return this.dayOfWeekScale(d.key.weekday) - symbolWidth / 2;
                    })
                    .attr('y', (d: any) => {
                        return this.todScale(d.key.hourOfDay);
                    })
                    .attr('width', symbolWidth)
                    .attr('height', symbolHeight)
                    .attr('fill', (d: any) => {
                        return this.colormap.getColorRGB(d.value);
                    })
                    .on('click', (d: any) => {
                        this.onClick(d);
                    })
                    .on('mouseover', (d: any) => {
                        this.onMouseOver(d);
                    })
                    .on('mouseout', () => {
                        this.onMouseOut();
                    });

        return this;
    }

    /*
     * overrides method from Base
     */
    protected onMouseOver(d: any): WeekdayRect {

        const str: string = 'x:' + d.key.weekday +
            ', y:' + d.key.hourOfDay +
            ', count:' + d.value;
        this.svg.select('g.footer').select('text').text(str);
        return this;
    }

    protected onMouseOut(): WeekdayRect {
        this.svg.select('g.footer').select('text').text('');
        return this;
    }

    /**
     * Adds an SVG g element containing a d3.scale.ordinal for plotting
     * the day of the week on the horizontal axis of the punchcard graph.
     * @return {WeekdayRect} A reference to the instance of WeekdayRect.
     */
    private drawHorizontalAxis(): WeekdayRect {

        const w: number = this.domElem.clientWidth - this.marginLeft - this.marginRight - this.legendWidth;
        const dx: number = this.marginLeft;
        const dy: number = this.domElem.clientHeight - this.marginBottom;

        const range: number[] = [];
        const ndays: number = 7.0;
        for (const r of [0, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.0]) {
            range.push(w * r / ndays);
        }

        this.dayOfWeekScale = d3.scale.ordinal()
            .range(range)
            .domain(['', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun', '']);

        const xAxis = d3.svg.axis()
            .orient('bottom')
            .scale(this.dayOfWeekScale)
            .tickValues(['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'])
            .innerTickSize(5)
            .outerTickSize(0);

        this.svg.append('g')
            .attr('class', 'horizontal-axis')
            .attr('transform', 'translate(' + dx + ',' + dy + ')' )
            .call(xAxis);

        return this;

    }

}