text:
// Copyright (c) 2011-2015 The Bitcoin Core developers
// Copyright (c) 2014-2021 The DÃSH Core Developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/biblepay-config.h>
#endif

#include <qt/rpcconsole.h>
#include <qt/forms/ui_debugwindow.h>

#include <qt/bantablemodel.h>
#include <qt/clientmodel.h>
#include <qt/walletmodel.h>
#include <chainparams.h>
#include <interfaces/node.h>
#include <netbase.h>
#include <rpc/server.h>
#include <rpc/client.h>
#include <util.h>

#include <openssl/crypto.h>

#include <univalue.h>

#ifdef ENABLE_WALLET
#include <db_cxx.h>
#endif

#include <QButtonGroup>
#include <QDir>
#include <QDesktopWidget>
#include <QFontDatabase>
#include <QKeyEvent>
#include <QMenu>
#include <QMessageBox>
#include <QScrollBar>
#include <QSettings>
#include <QSignalMapper>
#include <QTime>
#include <QTimer>
#include <QStringList>
#include <QStyledItemDelegate>

// TODO: add a scrollback limit, as there is currently none
// TODO: make it possible to filter out categories (esp debug messages when implemented)
// TODO: receive errors and debug messages through ClientModel

const int CONSOLE_HISTORY = 50;
const QSize FONT_RANGE(4, 40);
const char fontSizeSettingsKey[] = "consoleFontSize";

const TrafficGraphData::GraphRange INITIAL_TRAFFIC_GRAPH_SETTING = TrafficGraphData::Range_30m;

// Repair parameters
const QString SALVAGEWALLET("-salvagewallet");
const QString RESCAN1("-rescan=1");
const QString RESCAN2("-rescan=2");
const QString ZAPTXES1("-zapwallettxes=1 -persistmempool=0");
const QString ZAPTXES2("-zapwallettxes=2 -persistmempool=0");
const QString UPGRADEWALLET("-upgradewallet");
const QString REINDEX("-reindex");

namespace {

// don't add private key handling cmd's to the history
const QStringList historyFilter = QStringList()
    << "importprivkey"
    << "importmulti"
    << "signmessagewithprivkey"
    << "signrawtransaction"
    << "signrawtransactionwithkey"
    << "walletpassphrase"
    << "walletpassphrasechange"
    << "encryptwallet";

}

/* Object for executing console RPC commands in a separate thread.
*/
class RPCExecutor : public QObject
{
    Q_OBJECT
public:
    RPCExecutor(interfaces::Node& node) : m_node(node) {}

public Q_SLOTS:
    void request(const QString &command, const QString &walletID);

Q_SIGNALS:
    void reply(int category, const QString &command);

private:
    interfaces::Node& m_node;
};

/** Class for handling RPC timers
 * (used for e.g. re-locking the wallet after a timeout)
 */
class QtRPCTimerBase: public QObject, public RPCTimerBase
{
    Q_OBJECT
public:
    QtRPCTimerBase(std::function<void(void)>& _func, int64_t millis):
        func(_func)
    {
        timer.setSingleShot(true);
        connect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
        timer.start(millis);
    }
    ~QtRPCTimerBase() {}
private Q_SLOTS:
    void timeout() { func(); }
private:
    QTimer timer;
    std::function<void(void)> func;
};

class QtRPCTimerInterface: public RPCTimerInterface
{
public:
    ~QtRPCTimerInterface() {}
    const char *Name() override { return "Qt"; }
    RPCTimerBase* NewTimer(std::function<void(void)>& func, int64_t millis) override
    {
        return new QtRPCTimerBase(func, millis);
    }
};

#include <qt/rpcconsole.moc>

/**
 * Split shell command line into a list of arguments and optionally execute the command(s).
 * Aims to emulate \c bash and friends.
 *
 * - Command nesting is possible with parenthesis; for example: validateaddress(getnewaddress())
 * - Arguments are delimited with whitespace or comma
 * - Extra whitespace at the beginning and end and between arguments will be ignored
 * - Text can be "double" or 'single' quoted
 * - The backslash \c \ is used as escape character
 *   - Outside quotes, any character can be escaped
 *   - Within double quotes, only escape \c " and backslashes before a \c " or another backslash
 *   - Within single quotes, no escaping is possible and no special interpretation takes place
 *
 * @param[in]    node    optional node to execute command on
 * @param[out]   result      stringified Result from the executed command(chain)
 * @param[in]    strCommand  Command line to split
 * @param[in]    fExecute    set true if you want the command to be executed
 * @param[out]   pstrFilteredOut  Command line, filtered to remove any sensitive data
 */

bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut, const std::string *walletID)
{
    std::vector< std::vector<std::string> > stack;
    stack.push_back(std::vector<std::string>());

    enum CmdParseState
    {
        STATE_EATING_SPACES,
        STATE_EATING_SPACES_IN_ARG,
        STATE_EATING_SPACES_IN_BRACKETS,
        STATE_ARGUMENT,
        STATE_SINGLEQUOTED,
        STATE_DOUBLEQUOTED,
        STATE_ESCAPE_OUTER,
        STATE_ESCAPE_DOUBLEQUOTED,
        STATE_COMMAND_EXECUTED,
        STATE_COMMAND_EXECUTED_INNER
    } state = STATE_EATING_SPACES;
    std::string curarg;
    UniValue lastResult;
    unsigned nDepthInsideSensitive = 0;
    size_t filter_begin_pos = 0, chpos;
    std::vector<std::pair<size_t, size_t>> filter_ranges;

    auto add_to_current_stack = [&](const std::string& strArg) {
        if (stack.back().empty() && (!nDepthInsideSensitive) && historyFilter.contains(QString::fromStdString(strArg), Qt::CaseInsensitive)) {
            nDepthInsideSensitive = 1;
            filter_begin_pos = chpos;
        }
        // Make sure stack is not empty before adding something
        if (stack.empty()) {
            stack.push_back(std::vector<std::string>());
        }
        stack.back().push_back(strArg);
    };

    auto close_out_params = [&]() {
        if (nDepthInsideSensitive) {
            if (!--nDepthInsideSensitive) {
                assert(filter_begin_pos);
                filter_ranges.push_back(std::make_pair(filter_begin_pos, chpos));
                filter_begin_pos = 0;
            }
        }
        stack.pop_back();
    };

    std::string strCommandTerminated = strCommand;
    if (strCommandTerminated.back() != '\n')
        strCommandTerminated += "\n";
    for (chpos = 0; chpos < strCommandTerminated.size(); ++chpos)
    {
        char ch = strCommandTerminated[chpos];
        switch(state)
        {
            case STATE_COMMAND_EXECUTED_INNER:
            case STATE_COMMAND_EXECUTED:
            {
                bool breakParsing = true;
                switch(ch)
                {
                    case '[': curarg.clear(); state = STATE_COMMAND_EXECUTED_INNER; break;
                    default:
                        if (state == STATE_COMMAND_EXECUTED_INNER)
                        {
                            if (ch != ']')
                            {
                                // append char to the current argument (which is also used for the query command)
                                curarg += ch;
                                break;
                            }
                            if (curarg.size() && fExecute)
                            {
                                // if we have a value query, query arrays with index and objects with a string key
                                UniValue subelement;
                                if (lastResult.isArray())
                                {
                                    for(char argch: curarg)
                                        if (!std::isdigit(argch))
                                            throw std::runtime_error("Invalid result query");
                                    subelement = lastResult[atoi(curarg.c_str())];
                                }
                                else if (lastResult.isObject())
                                    subelement = find_value(lastResult, curarg);
                                else
                                    throw std::runtime_error("Invalid result query"); //no array or object: abort
                                lastResult = subelement;
                            }

                            state = STATE_COMMAND_EXECUTED;
                            break;
                        }
                        // don't break parsing when the char is required for the next argument
                        breakParsing = false;

                        // pop the stack and return the result to the current command arguments
                        close_out_params();

                        // don't stringify the json in case of a string to avoid doublequotes
                        if (lastResult.isStr())
                            curarg = lastResult.get_str();
                        else
                            curarg = lastResult.write(2);

                        // if we have a non empty result, use it as stack argument otherwise as general result
                        if (curarg.size())
                        {
                            if (stack.size())
                                add_to_current_stack(curarg);
                            else
                                strResult = curarg;
                        }
                        curarg.clear();
                        // assume eating space state
                        state = STATE_EATING_SPACES;
                }
                if (breakParsing)
                    break;
            }
            case STATE_ARGUMENT: // In or after argument
            case STATE_EATING_SPACES_IN_ARG:
            case STATE_EATING_SPACES_IN_BRACKETS:
            case STATE_EATING_SPACES: // Handle runs of whitespace
                switch(ch)
            {
                case '"': state = STATE_DOUBLEQUOTED; break;
                case '\'': state = STATE_SINGLEQUOTED; break;
                case '\\': state = STATE_ESCAPE_OUTER; break;
                case '(': case ')': case '\n':
                    if (state == STATE_EATING_SPACES_IN_ARG)
                        throw std::runtime_error("Invalid Syntax");
                    if (state == STATE_ARGUMENT)
                    {
                        if (ch == '(' && stack.size() && stack.back().size() > 0)
                        {
                            if (nDepthInsideSensitive) {
                                ++nDepthInsideSensitive;
                            }
                            stack.push_back(std::vector<std::string>());
                        }

                        // don't allow commands after executed commands on baselevel
                        if (!stack.size())
                            throw std::runtime_error("Invalid Syntax");

                        add_to_current_stack(curarg);
                        curarg.clear();
                        state = STATE_EATING_SPACES_IN_BRACKETS;
                    }
                    if ((ch == ')' || ch == '\n') && stack.size() > 0)
                    {
                        if (fExecute) {
                            // Convert argument list to JSON objects in method-dependent way,
                            // and pass it along with the method name to the dispatcher.
                            UniValue params = RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()));
                            std::string method = stack.back()[0];
                            std::string uri;
#ifdef ENABLE_WALLET
                            if (walletID) {
                                QByteArray encodedName = QUrl::toPercentEncoding(QString::fromStdString(*walletID));
                                uri = "/wallet/"+std::string(encodedName.constData(), encodedName.length());
                            }
#endif
                            assert(node);
                            lastResult = node->executeRpc(method, params, uri);
                        }

                        state = STATE_COMMAND_EXECUTED;
                        curarg.clear();
                    }
                    break;
                case ' ': case ',': case '\t':
                    if(state == STATE_EATING_SPACES_IN_ARG && curarg.empty() && ch == ',')
                        throw std::runtime_error("Invalid Syntax");

                    else if(state == STATE_ARGUMENT) // Space ends argument
                    {
                        add_to_current_stack(curarg);
                        curarg.clear();
                    }
                    if ((state == STATE_EATING_SPACES_IN_BRACKETS || state == STATE_ARGUMENT) && ch == ',')
                    {
                        state = STATE_EATING_SPACES_IN_ARG;
                        break;
                    }
                    state = STATE_EATING_SPACES;
                    break;
                default: curarg += ch; state = STATE_ARGUMENT;
            }
                break;
            case STATE_SINGLEQUOTED: // Single-quoted string
                switch(ch)
            {
                case '\'': state = STATE_ARGUMENT; break;
                default: curarg += ch;
            }
                break;
            case STATE_DOUBLEQUOTED: // Double-quoted string
                switch(ch)
            {
                case '"': state = STATE_ARGUMENT; break;
                case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break;
                default: curarg += ch;
            }
                break;
            case STATE_ESCAPE_OUTER: // '\' outside quotes
                curarg += ch; state = STATE_ARGUMENT;
                break;
            case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
                if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself
                curarg += ch; state = STATE_DOUBLEQUOTED;
                break;
        }
    }
    if (pstrFilteredOut) {
        if (STATE_COMMAND_EXECUTED == state) {
            assert(!stack.empty());
            close_out_params();
        }
        *pstrFilteredOut = strCommand;
        for (auto i = filter_ranges.rbegin(); i != filter_ranges.rend(); ++i) {
            pstrFilteredOut->replace(i->first, i->second - i->first, "(…)");
        }
    }
    switch(state) // final state
    {
        case STATE_COMMAND_EXECUTED:
            if (lastResult.isStr())
                strResult = lastResult.get_str();
            else
                strResult = lastResult.write(2);
        case STATE_ARGUMENT:
        case STATE_EATING_SPACES:
            return true;
        default: // ERROR to end in one of the other states
            return false;
    }
}

void RPCExecutor::request(const QString &command, const QString &walletID)
{
    try
    {
        std::string result;
        std::string executableCommand = command.toStdString() + "\n";

        // Catch the console-only-help command before RPC call is executed and reply with help text as-if a RPC reply.
        if(executableCommand == "help-console\n")
        {
            Q_EMIT reply(RPCConsole::CMD_REPLY, QString(("\n"
                "This console accepts RPC commands using the standard syntax.\n"
                "   example:    getblockhash 0\n\n"

                "This console can also accept RPC commands using parenthesized syntax.\n"
                "   example:    getblockhash(0)\n\n"

                "Commands may be nested when specified with the parenthesized syntax.\n"
                "   example:    getblock(getblockhash(0) 1)\n\n"

                "A space or a comma can be used to delimit arguments for either syntax.\n"
                "   example:    getblockhash 0\n"
                "               getblockhash,0\n\n"

                "Named results can be queried with a non-quoted key string in brackets.\n"
                "   example:    getblock(getblockhash(0) true)[tx]\n\n"

                "Results without keys can be queried using an integer in brackets.\n"
                "   example:    getblock(getblockhash(0),true)[tx][0]\n\n")));
            return;
        }
        std::string wallet_id = walletID.toStdString();
        if (!RPCConsole::RPCExecuteCommandLine(m_node, result, executableCommand, nullptr, walletID.isNull() ? nullptr : &wallet_id))
        {
            Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
            return;
        }

        Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(result));
    }
    catch (UniValue& objError)
    {
        try // Nice formatting for standard-format error
        {
            int code = find_value(objError, "code").get_int();
            std::string message = find_value(objError, "message").get_str();
            Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")");
        }
        catch (const std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message
        {   // Show raw JSON object
            Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write()));
        }
    }
    catch (const std::exception& e)
    {
        Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what()));
    }
}

RPCConsole::RPCConsole(interfaces::Node& node, QWidget* parent, Qt::WindowFlags flags) :
    QWidget(parent, flags),
    m_node(node),
    ui(new Ui::RPCConsole),
    clientModel(0),
    historyPtr(0),
    peersTableContextMenu(0),
    banTableContextMenu(0),
    consoleFontSize(0),
    pageButtons(0)
{
    ui->setupUi(this);

    GUIUtil::setFont({ui->label_9,
                      ui->labelNetwork,
                      ui->label_10,
                      ui->labelMempoolTitle,
                      ui->peerHeading,
                      ui->label_repair_header,
                      ui->banHeading
                     }, GUIUtil::FontWeight::Bold, 16);

    GUIUtil::updateFonts();

    GUIUtil::disableMacFocusRect(this);

    QSettings settings;
    if (!restoreGeometry(settings.value("RPCConsoleWindowGeometry").toByteArray())) {
        // Restore failed (perhaps missing setting), center the window
        move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center());
    }

    ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(tr(PACKAGE_NAME)));

    setButtonIcons();

    // Install event filter for up and down arrow
    ui->lineEdit->installEventFilter(this);
    ui->messagesWidget->installEventFilter(this);

    connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
    connect(ui->fontBiggerButton, SIGNAL(clicked()), this, SLOT(fontBigger()));
    connect(ui->fontSmallerButton, SIGNAL(clicked()), this, SLOT(fontSmaller()));
    connect(ui->btnClearTrafficGraph, SIGNAL(clicked()), ui->trafficGraph, SLOT(clear()));

    // disable the wallet selector by default
    ui->WalletSelector->setVisible(false);
    ui->WalletSelectorLabel->setVisible(false);

    // Wallet Repair Buttons
    // connect(ui->btn_salvagewallet, SIGNAL(clicked()), this, SLOT(walletSalvage()));
    // Disable salvage option in GUI, it's way too powerful and can lead to funds loss
    ui->btn_salvagewallet->setEnabled(false);
    connect(ui->btn_rescan1, SIGNAL(clicked()), this, SLOT(walletRescan1()));
    connect(ui->btn_rescan2, SIGNAL(clicked()), this, SLOT(walletRescan2()));
    connect(ui->btn_zapwallettxes1, SIGNAL(clicked()), this, SLOT(walletZaptxes1()));
    connect(ui->btn_zapwallettxes2, SIGNAL(clicked()), this, SLOT(walletZaptxes2()));
    connect(ui->btn_upgradewallet, SIGNAL(clicked()), this, SLOT(walletUpgrade()));
    connect(ui->btn_reindex, SIGNAL(clicked()), this, SLOT(walletReindex()));

    // set library version labels
#ifdef ENABLE_WALLET
    ui->berkeleyDBVersion->setText(DbEnv::version(0, 0, 0));
    std::string walletPath = GetDataDir().string();
    walletPath += QDir::separator().toLatin1() + gArgs.GetArg("-wallet", "wallet.dat");
    ui->wallet_path->setText(QString::fromStdString(walletPath));
#else
    ui->label_berkeleyDBVersion->hide();
    ui->berkeleyDBVersion->hide();
#endif
    // Register RPC timer interface
    rpcTimerInterface = new QtRPCTimerInterface();
    // avoid accidentally overwriting an existing, non QTThread
    // based timer interface
    m_node.rpcSetTimerInterfaceIfUnset(rpcTimerInterface);

    setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_SETTING);

    ui->peerHeading->setText(tr("Select a peer to view detailed information."));

    setFontSize(settings.value(fontSizeSettingsKey, QFontInfo(QFontDatabase::systemFont(QFontDatabase::FixedFont)).pointSize()).toInt());

    pageButtons = new QButtonGroup(this);
    pageButtons->addButton(ui->btnInfo, pageButtons->buttons().size());
    pageButtons->addButton(ui->btnConsole, pageButtons->buttons().size());
    pageButtons->addButton(ui->btnNetTraffic, pageButtons->buttons().size());
    pageButtons->addButton(ui->btnPeers, pageButtons->buttons().size());
    pageButtons->addButton(ui->btnRepair, pageButtons->buttons().size());
    connect(pageButtons, SIGNAL(buttonClicked(int)), this, SLOT(showPage(int)));

    showPage(TAB_INFO);

    reloadThemedWidgets();
}

RPCConsole::~RPCConsole()
{
    QSettings settings;
    settings.setValue("RPCConsoleWindowGeometry", saveGeometry());
    m_node.rpcUnsetTimerInterface(rpcTimerInterface);
    delete rpcTimerInterface;
    delete pageButtons;
    delete ui;
}

bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
{
    if(event->type() == QEvent::KeyPress) // Special key handling
    {
        QKeyEvent *keyevt = static_cast<QKeyEvent*>(event);
        int key = keyevt->key();
        Qt::KeyboardModifiers mod = keyevt->modifiers();
        switch(key)
        {
        case Qt::Key_Up: if(obj == ui->lineEdit) { browseHistory(-1); return true; } break;
        case Qt::Key_Down: if(obj == ui->lineEdit) { browseHistory(1); return true; } break;
        case Qt::Key_PageUp: /* pass paging keys to messages widget */
        case Qt::Key_PageDown:
            if(obj == ui->lineEdit)
            {
                QApplication::postEvent(ui->messagesWidget, new QKeyEvent(*keyevt));
                return true;
            }
            break;
        case Qt::Key_Return:
        case Qt::Key_Enter:
            // forward these events to lineEdit
            if(obj == autoCompleter->popup()) {
                autoCompleter->popup()->hide();
                QApplication::postEvent(ui->lineEdit, new QKeyEvent(*keyevt));
                return true;
            }
            break;
        default:
            // Typing in messages widget brings focus to line edit, and redirects key there
            // Exclude most combinations and keys that emit no text, except paste shortcuts
            if(obj == ui->messagesWidget && (
                  (!mod && !keyevt->text().isEmpty() && key != Qt::Key_Tab) ||
                  ((mod & Qt::ControlModifier) && key == Qt::Key_V) ||
                  ((mod & Qt::ShiftModifier) && key == Qt::Key_Insert)))
            {
                ui->lineEdit->setFocus();
                QApplication::postEvent(ui->lineEdit, new QKeyEvent(*keyevt));
                return true;
            }
        }
    }
    return QWidget::eventFilter(obj, event);
}

void RPCConsole::setClientModel(ClientModel *model)
{
    clientModel = model;
    ui->trafficGraph->setClientModel(model);
    if (model && clientModel->getPeerTableModel() && clientModel->getBanTableModel()) {
        // Keep up to date with client
        setNumConnections(model->getNumConnections());
        connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));

        interfaces::Node& node = clientModel->node();
        setNumBlocks(node.getNumBlocks(), QDateTime::fromTime_t(node.getLastBlockTime()), QString::fromStdString(node.getLastBlockHash()), node.getVerificationProgress(), false);
        connect(model, SIGNAL(numBlocksChanged(int,QDateTime,QString,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,QString,double,bool)));

        updateNetworkState();
        connect(model, SIGNAL(networkActiveChanged(bool)), this, SLOT(setNetworkActive(bool)));

        connect(model, SIGNAL(masternodeListChanged()), this, SLOT(updateMasternodeCount()));
        clientModel->refreshMasternodeList();

        connect(model, SIGNAL(mempoolSizeChanged(long,size_t)), this, SLOT(setMempoolSize(long,size_t)));
        connect(model, SIGNAL(islockCountChanged(size_t)), this, SLOT(setInstantSendLockCount(size_t)));

        // set up peer table
        ui->peerWidget->setModel(model->getPeerTableModel());
        ui->peerWidget->verticalHeader()->hide();
        ui->peerWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
        ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
        ui->peerWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
        ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
        ui->peerWidget->setColumnWidth(PeerTableModel::Address, ADDRESS_COLUMN_WIDTH);
        ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH);
        ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH);
        ui->peerWidget->horizontalHeader()->setStretchLastSection(true);

        // create peer table context menu actions
        QAction* disconnectAction = new QAction(tr("&Disconnect"), this);
        QAction* banAction1h      = new QAction(tr("Ban for") + " " + tr("1 &hour"), this);
        QAction* banAction24h     = new QAction(tr("Ban for") + " " + tr("1 &day"), this);
        QAction* banAction7d      = new QAction(tr("Ban for") + " " + tr("1 &week"), this);
        QAction* banAction365d    = new QAction(tr("Ban for") + " " + tr("1 &year"), this);

        // create peer table context menu
        peersTableContextMenu = new QMenu(this);
        peersTableContextMenu->addAction(disconnectAction);
        peersTableContextMenu->addAction(banAction1h);
        peersTableContextMenu->addAction(banAction24h);
        peersTableContextMenu->addAction(banAction7d);
        peersTableContextMenu->addAction(banAction365d);

        // Add a signal mapping to allow dynamic context menu arguments.
        // We need to use int (instead of int64_t), because signal mapper only supports
        // int or objects, which is okay because max bantime (1 year) is < int_max.
        QSignalMapper* signalMapper = new QSignalMapper(this);
        signalMapper->setMapping(banAction1h, 60*60);
        signalMapper->setMapping(banAction24h, 60*60*24);
        signalMapper->setMapping(banAction7d, 60*60*24*7);
        signalMapper->setMapping(banAction365d, 60*60*24*365);
        connect(banAction1h, SIGNAL(triggered()), signalMapper, SLOT(map()));
        connect(banAction24h, SIGNAL(triggered()), signalMapper, SLOT(map()));
        connect(banAction7d, SIGNAL(triggered()), signalMapper, SLOT(map()));
        connect(banAction365d, SIGNAL(triggered()), signalMapper, SLOT(map()));
        connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(banSelectedNode(int)));

        // peer table context menu signals
        connect(ui->peerWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showPeersTableContextMenu(const QPoint&)));
        connect(disconnectAction, SIGNAL(triggered()), this, SLOT(disconnectSelectedNode()));

        // peer table signal handling - update peer details when selecting new node
        connect(ui->peerWidget->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
            this, SLOT(peerSelected(const QItemSelection &, const QItemSelection &)));
        // peer table signal handling - update peer details when new nodes are added to the model
        connect(model->getPeerTableModel(), SIGNAL(layoutChanged()), this, SLOT(peerLayoutChanged()));
        // peer table signal handling - cache selected node ids
        connect(model->getPeerTableModel(), SIGNAL(layoutAboutToBeChanged()), this, SLOT(peerLayoutAboutToChange()));

        // set up ban table
        ui->banlistWidget->setModel(model->getBanTableModel());
        ui->banlistWidget->verticalHeader()->hide();
        ui->banlistWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
        ui->banlistWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
        ui->banlistWidget->setSelectionMode(QAbstractItemView::SingleSelection);
        ui->banlistWidget->setContextMenuPolicy(Qt::CustomContextMenu);
        ui->banlistWidget->setColumnWidth(BanTableModel::Address, BANSUBNET_COLUMN_WIDTH);
        ui->banlistWidget->setColumnWidth(BanTableModel::Bantime, BANTIME_COLUMN_WIDTH);
        ui->banlistWidget->horizontalHeader()->setStretchLastSection(true);

        // create ban table context menu action
        QAction* unbanAction = new QAction(tr("&Unban"), this);

        // create ban table context menu
        banTableContextMenu = new QMenu(this);
        banTableContextMenu->addAction(unbanAction);

        // ban table context menu signals
        connect(ui->banlistWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showBanTableContextMenu(const QPoint&)));
        connect(unbanAction, SIGNAL(triggered()), this, SLOT(unbanSelectedNode()));

        // ban table signal handling - clear peer details when clicking a peer in the ban table
        connect(ui->banlistWidget, SIGNAL(clicked(const QModelIndex&)), this, SLOT(clearSelectedNode()));
        // ban table signal handling - ensure ban table is shown or hidden (if empty)
        connect(model->getBanTableModel(), SIGNAL(layoutChanged()), this, SLOT(showOrHideBanTableIfRequired()));
        showOrHideBanTableIfRequired();

        // Provide initial values
        ui->clientVersion->setText(model->formatFullVersion());
        ui->clientUserAgent->setText(model->formatSubVersion());
        ui->dataDir->setText(model->dataDir());
        ui->startupTime->setText(model->formatClientStartupTime());
        ui->networkName->setText(QString::fromStdString(Params().NetworkIDString()));

        //Setup autocomplete and attach it
        QStringList wordList;
        std::vector<std::string> commandList = m_node.listRpcCommands();
        for (size_t i = 0; i < commandList.size(); ++i)
        {
            wordList << commandList[i].c_str();
            wordList << ("help " + commandList[i]).c_str();
        }

        wordList << "help-console";
        wordList.sort();
        autoCompleter = new QCompleter(wordList, this);
        autoCompleter->popup()->setItemDelegate(new QStyledItemDelegate(this));
        autoCompleter->popup()->setObjectName("rpcAutoCompleter");
        autoCompleter->setModelSorting(QCompleter::CaseSensitivelySortedModel);
        ui->lineEdit->setCompleter(autoCompleter);
        autoCompleter->popup()->installEventFilter(this);
        // Start thread to execute RPC commands.
        startExecutor();
    }
    if (!model) {
        // Client model is being set to 0, this means shutdown() is about to be called.
        // Make sure we clean up the executor thread
        Q_EMIT stopExecutor();
        thread.wait();
    }
}

#ifdef ENABLE_WALLET
void RPCConsole::addWallet(WalletModel * const walletModel)
{
    const QString name = walletModel->getWalletName();
    // use name for text and internal data object (to allow to move to a wallet id later)
    QString display_name = name.isEmpty() ? "["+tr("default wallet")+"]" : name;
    ui->WalletSelector->addItem(display_name, name);
    if (ui->WalletSelector->count() == 2 && !isVisible()) {
        // First wallet added, set to default so long as the window isn't presently visible (and potentially in use)
        ui->WalletSelector->setCurrentIndex(1);
    }
    if (ui->WalletSelector->count() > 2) {
        ui->WalletSelector->setVisible(true);
        ui->WalletSelectorLabel->setVisible(true);
    }
}

void RPCConsole::removeWallet(WalletModel * const walletModel)
{
    const QString name = walletModel->getWalletName();
    ui->WalletSelector->removeItem(ui->WalletSelector->findData(name));
    if (ui->WalletSelector->count() == 2) {
        ui->WalletSelector->setVisible(false);
        ui->WalletSelectorLabel->setVisible(false);
    }
}
#endif

static QString categoryClass(int category)
{
    switch(category)
    {
    case RPCConsole::CMD_REQUEST:  return "cmd-request"; break;
    case RPCConsole::CMD_REPLY:    return "cmd-reply"; break;
    case RPCConsole::CMD_ERROR:    return "cmd-error"; break;
    default:                       return "misc";
    }
}

void RPCConsole::fontBigger()
{
    setFontSize(consoleFontSize+1);
}

void RPCConsole::fontSmaller()
{
    setFontSize(consoleFontSize-1);
}

void RPCConsole::setFontSize(int newSize)
{
    QSettings settings;

    newSize = std::min(std::max(newSize, FONT_RANGE.width()), FONT_RANGE.height());

    // temp. store the console content
    QString str = ui->messagesWidget->toHtml();

    // replace font tags size in current content
    str.replace(QString("font-size:%1pt").arg(consoleFontSize), QString("font-size:%1pt").arg(newSize));

    // store the new font size
    consoleFontSize = newSize;
    settings.setValue(fontSizeSettingsKey, consoleFontSize);

    // clear console (reset icon sizes, default stylesheet) and re-add the content
    float oldPosFactor = 1.0 / ui->messagesWidget->verticalScrollBar()->maximum() * ui->messagesWidget->verticalScrollBar()->value();
    clear(false);
    ui->messagesWidget->setHtml(str);
    ui->messagesWidget->verticalScrollBar()->setValue(oldPosFactor * ui->messagesWidget->verticalScrollBar()->maximum());
}

/** Restart wallet with "-salvagewallet" */
void RPCConsole::walletSalvage()
{
    buildParameterlist(SALVAGEWALLET);
}

/** Restart wallet with "-rescan=1" */
void RPCConsole::walletRescan1()
{
    buildParameterlist(RESCAN1);
}

/** Restart wallet with "-rescan=2" */
void RPCConsole::walletRescan2()
{
    buildParameterlist(RESCAN2);
}

/** Restart wallet with "-zapwallettxes=1" */
void RPCConsole::walletZaptxes1()
{
    buildParameterlist(ZAPTXES1);
}

/** Restart wallet with "-zapwallettxes=2" */
void RPCConsole::walletZaptxes2()
{
    buildParameterlist(ZAPTXES2);
}

/** Restart wallet with "-upgradewallet" */
void RPCConsole::walletUpgrade()
{
    buildParameterlist(UPGRADEWALLET);
}

/** Restart wallet with "-reindex" */
void RPCConsole::walletReindex()
{
    buildParameterlist(REINDEX);
}

/** Build command-line parameter list for restart */
void RPCConsole::buildParameterlist(QString arg)
{
    // Get command-line arguments and remove the application name
    QStringList args = QApplication::arguments();
    args.removeFirst();

    // Remove existing repair-options
    args.removeAll(SALVAGEWALLET);
    args.removeAll(RESCAN1);
    args.removeAll(RESCAN2);
    args.removeAll(ZAPTXES1);
    args.removeAll(ZAPTXES2);
    args.removeAll(UPGRADEWALLET);
    args.removeAll(REINDEX);

    // Append repair parameter to command line.
    args.append(arg);

    // Send command-line arguments to BitcoinGUI::handleRestart()
    Q_EMIT handleRestart(args);
}

void RPCConsole::clear(bool clearHistory)
{
    ui->messagesWidget->clear();
    if(clearHistory)
    {
        history.clear();
        historyPtr = 0;
    }
    ui->lineEdit->clear();
    ui->lineEdit->setFocus();

    // Set default style sheet
    ui->messagesWidget->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
    ui->messagesWidget->document()->setDefaultStyleSheet(
        QString(
                "table { }"
                "td.time { " + GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_SECONDARY) + " font-size: %1pt; } "
                "td.message { " + GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_PRIMARY) + " font-size: %1pt; white-space:pre-wrap; } "
                "td.cmd-request, b { " + GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_COMMAND) + " } "
                "td.cmd-error, .secwarning { " + GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR) + " }"
            ).arg(consoleFontSize)
        );

#ifdef Q_OS_MAC
    QString clsKey = "(⌘)-L";
#else
    QString clsKey = "Ctrl-L";
#endif

    message(CMD_REPLY, (tr("Welcome to the %1 RPC console.").arg(tr(PACKAGE_NAME)) + "<br>" +
                        tr("Use up and down arrows to navigate history, and %1 to clear screen.").arg("<b>"+clsKey+"</b>") + "<br>" +
                        tr("Type %1 for an overview of available commands.").arg("<b>help</b>") + "<br>" +
                        tr("For more information on using this console type %1.").arg("<b>help-console</b>") +
                        "<br><span class=\"secwarning\"><br>" +
                        tr("WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.") +
                        "</span>"),
                        true);
}

void RPCConsole::keyPressEvent(QKeyEvent *event)
{
    if(windowType() != Qt::Widget && event->key() == Qt::Key_Escape)
    {
        close();
    }
}

void RPCConsole::message(int category, const QString &message, bool html)
{
    QTime time = QTime::currentTime();
    QString timeString = time.toString();
    QString out;
    out += "<table><tr><td class=\"time\" width=\"65\">" + timeString + "</td>";
    out += "<td class=\"message " + categoryClass(category) + "\" valign=\"middle\">";
    if(html)
        out += message;
    else
        out += GUIUtil::HtmlEscape(message, false);
    out += "</td></tr></table>";
    ui->messagesWidget->append(out);
}

void RPCConsole::updateNetworkState()
{
    QString connections = QString::number(clientModel->getNumConnections()) + " (";
    connections += tr("In:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_IN)) + " / ";
    connections += tr("Out:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_OUT)) + ")";

    if(!clientModel->node().getNetworkActive()) {
        connections += " (" + tr("Network activity disabled") + ")";
    }

    ui->numberOfConnections->setText(connections);
}

void RPCConsole::setNumConnections(int count)
{
    if (!clientModel)
        return;

    updateNetworkState();
}

void RPCConsole::setNetworkActive(bool networkActive)
{
    updateNetworkState();
}

void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate, const QString& blockHash, double nVerificationProgress, bool headers)
{
    if (!headers) {
        ui->numberOfBlocks->setText(QString::number(count));
        ui->lastBlockTime->setText(blockDate.toString());
        ui->lastBlockHash->setText(blockHash);
    }
}

void RPCConsole::updateMasternodeCount()
{
    if (!clientModel) {
        return;
    }
    auto mnList = clientModel->getMasternodeList();
    QString strMasternodeCount = tr("Total: %1 (Enabled: %2)")
        .arg(QString::number(mnList.GetAllMNsCount()))
        .arg(QString::number(mnList.GetValidMNsCount()));
    ui->masternodeCount->setText(strMasternodeCount);
}

void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage)
{
    ui->mempoolNumberTxs->setText(QString::number(numberOfTxs));

    if (dynUsage < 1000000)
        ui->mempoolSize->setText(QString::number(dynUsage/1000.0, 'f', 2) + " KB");
    else
        ui->mempoolSize->setText(QString::number(dynUsage/1000000.0, 'f', 2) + " MB");
}

void RPCConsole::setInstantSendLockCount(size_t count)
{
    ui->instantSendLockCount->setText(QString::number(count));
}

void RPCConsole::showPage(int index)
{
    std::vector<QWidget*> vecNormal;
    QAbstractButton* btnActive = pageButtons->button(index);
    for (QAbstractButton* button : pageButtons->buttons()) {
        if (button != btnActive) {
            vecNormal.push_back(button);
        }
    }

    GUIUtil::setFont({btnActive}, GUIUtil::FontWeight::Bold, 16);
    GUIUtil::setFont(vecNormal, GUIUtil::FontWeight::Normal, 16);
    GUIUtil::updateFonts();

    ui->stackedWidgetRPC->setCurrentIndex(index);
    btnActive->setChecked(true);
}

void RPCConsole::on_lineEdit_returnPressed()
{
    QString cmd = ui->lineEdit->text();

    if(!cmd.isEmpty())
    {
        std::string strFilteredCmd;
        try {
            std::string dummy;
            if (!RPCParseCommandLine(nullptr, dummy, cmd.toStdString(), false, &strFilteredCmd)) {
                // Failed to parse command, so we cannot even filter it for the history
                throw std::runtime_error("Invalid command line");
            }
        } catch (const std::exception& e) {
            QMessageBox::critical(this, "Error", QString("Error: ") + QString::fromStdString(e.what()));
            return;
        }

        ui->lineEdit->clear();

        cmdBeforeBrowsing = QString();

        QString walletID;
#ifdef ENABLE_WALLET
        const int wallet_index = ui->WalletSelector->currentIndex();
        if (wallet_index > 0) {
            walletID = (QString)ui->WalletSelector->itemData(wallet_index).value<QString>();
        }

        if (m_last_wallet_id != walletID) {
            if (walletID.isNull()) {
                message(CMD_REQUEST, tr("Executing command without any wallet"));
            } else {
                message(CMD_REQUEST, tr("Executing command using \"%1\" wallet").arg(walletID));
            }
            m_last_wallet_id = walletID;
        }
#endif

        message(CMD_REQUEST, QString::fromStdString(strFilteredCmd));
        Q_EMIT cmdRequest(cmd, walletID);

        cmd = QString::fromStdString(strFilteredCmd);

        // Remove command, if already in history
        history.removeOne(cmd);
        // Append command to history
        history.append(cmd);
        // Enforce maximum history size
        while(history.size() > CONSOLE_HISTORY)
            history.removeFirst();
        // Set pointer to end of history
        historyPtr = history.size();

        // Scroll console view to end
        scrollToEnd();
    }
}

void RPCConsole::browseHistory(int offset)
{
    // store current text when start browsing through the history
    if (historyPtr == history.size()) {
        cmdBeforeBrowsing = ui->lineEdit->text();
    }

    historyPtr += offset;
    if(historyPtr < 0)
        historyPtr = 0;
    if(historyPtr > history.size())
        historyPtr = history.size();
    QString cmd;
    if(historyPtr < history.size())
        cmd = history.at(historyPtr);
    else if (!cmdBeforeBrowsing.isNull()) {
        cmd = cmdBeforeBrowsing;
    }
    ui->lineEdit->setText(cmd);
}

void RPCConsole::startExecutor()
{
    RPCExecutor *executor = new RPCExecutor(m_node);
    executor->moveToThread(&thread);

    // Replies from executor object must go to this object
    connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString)));
    // Requests from this object must go to executor
    connect(this, SIGNAL(cmdRequest(QString, QString)), executor, SLOT(request(QString, QString)));

    // On stopExecutor signal
    // - quit the Qt event loop in the execution thread
    connect(this, SIGNAL(stopExecutor()), &thread, SLOT(quit()));
    // - queue executor for deletion (in execution thread)
    connect(&thread, SIGNAL(finished()), executor, SLOT(deleteLater()), Qt::DirectConnection);

    // Default implementation of QThread::run() simply spins up an event loop in the thread,
    // which is what we want.
    thread.start();
}

void RPCConsole::on_stackedWidgetRPC_currentChanged(int index)
{
    if (ui->stackedWidgetRPC->widget(index) == ui->pageConsole)
        ui->lineEdit->setFocus();
    else if (ui->stackedWidgetRPC->widget(index) != ui->pagePeers)
        clearSelectedNode();
}

void RPCConsole::on_openDebugLogfileButton_clicked()
{
    GUIUtil::openDebugLogfile();
}

void RPCConsole::scrollToEnd()
{
    QScrollBar *scrollbar = ui->messagesWidget->verticalScrollBar();
    scrollbar->setValue(scrollbar->maximum());
}

void RPCConsole::on_sldGraphRange_valueChanged(int value)
{
    setTrafficGraphRange(static_cast<TrafficGraphData::GraphRange>(value));
}

void RPCConsole::setTrafficGraphRange(TrafficGraphData::GraphRange range)
{
    ui->trafficGraph->setGraphRangeMins(range);
    ui->lblGraphRange->setText(GUIUtil::formatDurationStr(TrafficGraphData::RangeMinutes[range] * 60));
}

void RPCConsole::peerSelected(const QItemSelection &selected, const QItemSelection &deselected)
{
    Q_UNUSED(deselected);

    if (!clientModel || !clientModel->getPeerTableModel() || selected.indexes().isEmpty())
        return;

    const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected.indexes().first().row());
    if (stats)
        updateNodeDetail(stats);
}

void RPCConsole::peerLayoutAboutToChange()
{
    QModelIndexList selected = ui->peerWidget->selectionModel()->selectedIndexes();
    cachedNodeids.clear();
    for(int i = 0; i < selected.size(); i++)
    {
        const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected.at(i).row());
        cachedNodeids.append(stats->nodeStats.nodeid);
    }
}

void RPCConsole::peerLayoutChanged()
{
    if (!clientModel || !clientModel->getPeerTableModel())
        return;

    const CNodeCombinedStats *stats = nullptr;
    bool fUnselect = false;
    bool fReselect = false;

    if (cachedNodeids.empty()) // no node selected yet
        return;

    // find the currently selected row
    int selectedRow = -1;
    QModelIndexList selectedModelIndex = ui->peerWidget->selectionModel()->selectedIndexes();
    if (!selectedModelIndex.isEmpty()) {
        selectedRow = selectedModelIndex.first().row();
    }

    // check if our detail node has a row in the table (it may not necessarily
    // be at selectedRow since its position can change after a layout change)
    int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(cachedNodeids.first());

    if (detailNodeRow < 0)
    {
        // detail node disappeared from table (node disconnected)
        fUnselect = true;
    }
    else
    {
        if (detailNodeRow != selectedRow)
        {
            // detail node moved position
            fUnselect = true;
            fReselect = true;
        }

        // get fresh stats on the detail node.
        stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
    }

    if (fUnselect && selectedRow >= 0) {
        clearSelectedNode();
    }

    if (fReselect)
    {
        for(int i = 0; i < cachedNodeids.size(); i++)
        {
            ui->peerWidget->selectRow(clientModel->getPeerTableModel()->getRowByNodeId(cachedNodeids.at(i)));
        }
    }

    if (stats)
        updateNodeDetail(stats);
}

void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
{
    // update the detail ui with latest node information
    QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) + " ");
    peerAddrDetails += tr("(node id: %1)").arg(QString::number(stats->nodeStats.nodeid));
    if (!stats->nodeStats.addrLocal.empty())
        peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
    ui->peerHeading->setText(peerAddrDetails);
    ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStats.nServices));
    ui->peerLastSend->setText(stats->nodeStats.nLastSend ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nLastSend) : tr("never"));
    ui->peerLastRecv->setText(stats->nodeStats.nLastRecv ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nLastRecv) : tr("never"));
    ui->peerBytesSent->setText(GUIUtil::formatBytes(stats->nodeStats.nSendBytes));
    ui->peerBytesRecv->setText(GUIUtil::formatBytes(stats->nodeStats.nRecvBytes));
    ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nTimeConnected));
    ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingTime));
    ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingWait));
    ui->peerMinPing->setText(GUIUtil::formatPingTime(stats->nodeStats.dMinPing));
    ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
    ui->peerVersion->setText(QString("%1").arg(QString::number(stats->nodeStats.nVersion)));
    ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
    ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound"));
    ui->peerHeight->setText(QString("%1").arg(QString::number(stats->nodeStats.nStartingHeight)));
    ui->peerWhitelisted->setText(stats->nodeStats.fWhitelisted ? tr("Yes") : tr("No"));
    auto dmn = clientModel->getMasternodeList().GetMNByService(stats->nodeStats.addr);
    if (dmn == nullptr) {
        ui->peerNodeType->setText(tr("Regular"));
        ui->peerPoSeScore->setText(tr("N/A"));
    } else {
        if (stats->nodeStats.verifiedProRegTxHash.IsNull()) {
            ui->peerNodeType->setText(tr("Masternode"));
        } else {
            ui->peerNodeType->setText(tr("Verified Masternode"));
        }
        ui->peerPoSeScore->setText(QString::number(dmn->pdmnState->nPoSePenalty));
    }

    // This check fails for example if the lock was busy and
    // nodeStateStats couldn't be fetched.
    if (stats->fNodeStateStatsAvailable) {
        // Ban score is init to 0
        ui->peerBanScore->setText(QString("%1").arg(stats->nodeStateStats.nMisbehavior));

        // Sync height is init to -1
        if (stats->nodeStateStats.nSyncHeight > -1)
            ui->peerSyncHeight->setText(QString("%1").arg(stats->nodeStateStats.nSyncHeight));
        else
            ui->peerSyncHeight->setText(tr("Unknown"));

        // Common height is init to -1
        if (stats->nodeStateStats.nCommonHeight > -1)
            ui->peerCommonHeight->setText(QString("%1").arg(stats->nodeStateStats.nCommonHeight));
        else
            ui->peerCommonHeight->setText(tr("Unknown"));
    }

    ui->detailWidget->show();
}

void RPCConsole::setButtonIcons()
{
    const QSize consoleButtonsSize(BUTTON_ICONSIZE * 0.8, BUTTON_ICONSIZE * 0.8);
    GUIUtil::setIcon(ui->clearButton, "remove", GUIUtil::ThemedColor::RED, consoleButtonsSize);
    GUIUtil::setIcon(ui->fontBiggerButton, "fontbigger", GUIUtil::ThemedColor::BLUE, consoleButtonsSize);
    GUIUtil::setIcon(ui->fontSmallerButton, "fontsmaller", GUIUtil::ThemedColor::BLUE, consoleButtonsSize);
}

void RPCConsole::reloadThemedWidgets()
{
    clear();
    ui->promptLabel->setHidden(GUIUtil::biblepayThemeActive());
    // Adjust button icon colors on theme changes
    setButtonIcons();
}

void RPCConsole::resizeEvent(QResizeEvent *event)
{
    QWidget::resizeEvent(event);
}

void RPCConsole::showEvent(QShowEvent *event)
{
    QWidget::showEvent(event);

    GUIUtil::updateButtonGroupShortcuts(pageButtons);

    if (!clientModel || !clientModel->getPeerTableModel())
        return;

    // start PeerTableModel auto refresh
    clientModel->getPeerTableModel()->startAutoRefresh();
}

void RPCConsole::hideEvent(QHideEvent *event)
{
    QWidget::hideEvent(event);

    if (!clientModel || !clientModel->getPeerTableModel())
        return;

    // stop PeerTableModel auto refresh
    clientModel->getPeerTableModel()->stopAutoRefresh();
}

void RPCConsole::changeEvent(QEvent* e)
{
    if (e->type() == QEvent::StyleChange) {
        reloadThemedWidgets();
    }

    QWidget::changeEvent(e);
}

void RPCConsole::showPeersTableContextMenu(const QPoint& point)
{
    QModelIndex index = ui->peerWidget->indexAt(point);
    if (index.isValid())
        peersTableContextMenu->exec(QCursor::pos());
}

void RPCConsole::showBanTableContextMenu(const QPoint& point)
{
    QModelIndex index = ui->banlistWidget->indexAt(point);
    if (index.isValid())
        banTableContextMenu->exec(QCursor::pos());
}

void RPCConsole::disconnectSelectedNode()
{
    // Get selected peer addresses
    QList<QModelIndex> nodes = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
    for(int i = 0; i < nodes.count(); i++)
    {
        // Get currently selected peer address
        NodeId id = nodes.at(i).data().toLongLong();
        // Find the node, disconnect it and clear the selected node
        if(m_node.disconnect(id))
            clearSelectedNode();
    }
}

void RPCConsole::banSelectedNode(int bantime)
{
    if (!clientModel)
        return;

    // Get selected peer addresses
    QList<QModelIndex> nodes = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
    for(int i = 0; i < nodes.count(); i++)
    {
        // Get currently selected peer address
        NodeId id = nodes.at(i).data().toLongLong();

	// Get currently selected peer address
	int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(id);
	if(detailNodeRow < 0)
	    return;

	// Find possible nodes, ban it and clear the selected node
	const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
	if(stats) {
            m_node.ban(stats->nodeStats.addr, BanReasonManuallyAdded, bantime);
	}
    }
    clearSelectedNode();
    clientModel->getBanTableModel()->refresh();
}

void RPCConsole::unbanSelectedNode()
{
    if (!clientModel)
        return;

    // Get selected ban addresses
    QList<QModelIndex> nodes = GUIUtil::getEntryData(ui->banlistWidget, BanTableModel::Address);
    for(int i = 0; i < nodes.count(); i++)
    {
        // Get currently selected ban address
        QString strNode = nodes.at(i).data().toString();
        CSubNet possibleSubnet;

        LookupSubNet(strNode.toStdString().c_str(), possibleSubnet);
        if (possibleSubnet.IsValid() && m_node.unban(possibleSubnet))
        {
            clientModel->getBanTableModel()->refresh();
        }
    }
}

void RPCConsole::clearSelectedNode()
{
    ui->peerWidget->selectionModel()->clearSelection();
    cachedNodeids.clear();
    ui->detailWidget->hide();
    ui->peerHeading->setText(tr("Select a peer to view detailed information."));
}

void RPCConsole::showOrHideBanTableIfRequired()
{
    if (!clientModel)
        return;

    bool visible = clientModel->getBanTableModel()->shouldShow();
    ui->banlistWidget->setVisible(visible);
    ui->banHeading->setVisible(visible);
}

void RPCConsole::setTabFocus(enum TabTypes tabType)
{
    showPage(tabType);
}


text:
var assert = require("assert");
var minMax = require("./../scripts/minMax");

describe("minMax function", function() {
    "use strict";

    var bigNumber = 100;
    var bigFloatNumber = 100.3221;
    var smallNumber = 7;
    var smallFloatNumber = 6.777777;
    var negNumber = -50;
    var zero = 0;

    it('should return number if number is within range', function() {
        assert.equal(minMax(smallNumber, zero, bigNumber), smallNumber);
        assert.equal(minMax(smallFloatNumber, zero, bigFloatNumber), smallFloatNumber);
    });

    it('should return low border if number is less than low border', function() {
        assert.equal(minMax(negNumber, zero, bigNumber), zero);
        assert.equal(minMax(negNumber, zero, bigFloatNumber), zero);
    });

    it('should return upper border if number is greater than upper border', function() {
        assert.equal(minMax(bigNumber, zero, smallNumber), smallNumber);
        assert.equal(minMax(bigFloatNumber, zero, smallFloatNumber), smallFloatNumber);
    });

    it('should return the input value if any other type than Number is given', function() {
        assert.equal(minMax("string", zero, bigNumber), "string");
        assert.deepEqual(minMax({
            a: 1,
            b: 2
        }, zero, bigNumber), {
            a: 1,
            b: 2
        });
        assert.deepEqual(minMax([1, 2, 3, 4, 5], zero, bigNumber), [1, 2, 3, 4, 5]);

        assert.equal(minMax(undefined, zero, bigNumber), undefined);
        assert.equal(minMax("", zero, bigNumber), "");
        assert.deepEqual(minMax({}, zero, bigNumber), {});
        assert.deepEqual(minMax([], zero, bigNumber), []);
    });
});

redpajama_set_name: RedPajamaGithub


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.7"/>
<title>MAGMA: Conventions for variables</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>

<link href="navtree.css" rel="stylesheet" type="text/css"/>

<link href="search/search.css" rel="stylesheet" type="text/css"/>

<link href="doxygen.css" rel="stylesheet" type="text/css" />

MAGMA
    1.6.2

Matrix Algebra for GPU and Multicore Architectures

Main Page

Related Pages

Modules

Classes

Files

          <input type="text" id="MSearchField" value="Search" accesskey="S"
               onfocus="searchBox.OnSearchFieldFocus(true)"
               onblur="searchBox.OnSearchFieldFocus(false)"
               onkeyup="searchBox.OnSearchFieldChange(event)"/>

 All Classes Files Functions Friends Groups Pages

Conventions for variables

Here are general guidelines for variable names; there are of course exceptions to these.

Uppercase letters indicate matrices: A, B, C, X.

Lowercase letters indicate vectors: b, x, y, z.

"d" prefix indicates matrix or vector on GPU device: dA, dB, dC, dX; db, dx, dy, dz.

Greek words indicate scalars: alpha, beta.

m, n, k are matrix dimensions.

Typically, the order of arguments is:

options (uplo, etc.)

matrix sizes (m, n, k, etc.),

input matrices & vectors (A, lda, x, incx, etc.)

output matrices & vectors

workspaces (work, lwork, etc.)

info error code

LAPACK and MAGMA use column-major matrices. For matrix X with dimension (lda,n), element X(i, j) is X[ i + j*lda ]. For symmetric, Hermitian, and triangular matrices, only the lower or upper triangle is accessed, as specified by the uplo argument; the other triangle is ignored.

lda is the leading dimension of matrix A; similarly ldb for B, ldda for dA, etc. It should immediately follow the matrix pointer in the argument list. The leading dimension can be the number of rows, or if A is a sub-matrix of a larger parent matrix, lda is the leading dimension (e.g., rows) of the parent matrix.

On the GPU, it is often beneficial to round the leading dimension up to a multiple of 32, to provide better performance. This aligns memory reads so they are coalesced. This is provided by the magma_roundup function:

ldda = magma_roundup( m, 32 );

The formula ((m + 31)/32)*32 also works, relying on floored integer division, but the roundup function is clearer to use.

On the CPU, it is often beneficial to ensure that the leading dimension is not a multiple of the page size (often 4 KiB), to minimize TLB misses.

For vectors, incx is the increment or stride between elements of vector x. In all cases, incx != 0. In most cases, if incx < 0, then the vector is indexed in reverse order, for instance, using Matlab notation,

incx =  1   means   x( 1 : 1 : n     )
incx =  2   means   x( 1 : 2 : 2*n-1 )

while

incx = -1   means   x( n     : -1 : 1 )
incx = -2   means   x( 2*n-1 : -2 : 1 )

For several routines (amax, amin, asum, nrm2, scal), the order is irrelevant, so negative incx are not allowed; incx > 0.

Generated on Mon May 11 2015 10:07:12 for MAGMA by

     1.8.7


text:
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.io.pjflate;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Objects;
import javax.annotation.Nullable;

/**
 * Inflater.
 *
 * <p>The code is a pure Java port of Go's flate code
 * (https://golang.org/src/compress/flate/inflate.go).
 */
public class Inflater {
  private static final int MAX_LITERALS = 286;
  private static final int MAX_DISTANCES = 30;
  private static final int[] META_CODE_ORDER =
      new int[] {
        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
      };

  private final BitReader br = new BitReader();
  private final HuffmanTreeIndex tempIndex1 = new HuffmanTreeIndex();
  private final HuffmanTreeIndex tempIndex2 = new HuffmanTreeIndex();
  private final InflateOutputBuffer out = new InflateOutputBuffer();
  private final int[] bits = new int[MAX_LITERALS + MAX_DISTANCES];
  private final int[] codebits = new int[META_CODE_ORDER.length];

  private InternalState internalState;
  private boolean finalBlock;
  private int dataBlockCopyLength;
  private int historyCopyDistance;
  private int historyCopyLength;
  @Nullable private CustomHuffmanBlockReadState customHuffmanBlockReadState;
  @Nullable private HuffmanTreeIndex distanceIndex;
  @Nullable private HuffmanTreeIndex lengthIndex;

  public Inflater() {
    reset();
  }

  public void reset() {
    internalState = InternalState.READ_NEXT_BLOCK;
    finalBlock = false;
    br.b = 0;
    br.nb = 0;
    out.reset();
  }

  public State inflate(ByteBuffer dst, ByteBuffer src) throws InflationException {
    try {
      br.setByteBuffer(src);
      while (true) {
        if (out.readAvailable() > 0) {
          if (!out.writeTo(dst)) {
            return State.NEED_MORE_OUTPUT;
          }
        }
        if (out.readAvailable() == 0 && finalBlock) {
          if (internalState == InternalState.READ_NEXT_BLOCK) {
            return State.DONE;
          }
        }

        State s;
        switch (internalState) {
          case READ_NEXT_BLOCK:
            s = readNextBlock();
            break;
          case PROCESS_DATA_BLOCK:
            s = processDataBlock(src);
            break;
          case PROCESS_HISTORY_COPY_LENGTH:
            s = processHistoryCopyLength();
            break;
          case PROCESS_HISTORY_COPY_DISTANCE:
            s = processHistoryCopyDistance();
            break;
          case PROCESS_HISTORY_COPY:
            s = processHistoryCopy();
            break;
          case READ_CUSTOM_HUFFMAN_BLOCK:
            s = processCustomHuffmanBlock();
            break;
          default:
            throw new AssertionError();
        }
        if (s != null) {
          return s;
        }
      }
    } finally {
      br.setByteBuffer(null);
    }
  }

  @Nullable
  private State readNextBlock() throws InflationException {
    while (br.nb < 3) {
      if (!br.readMore()) {
        return State.NEED_MORE_INPUT;
      }
    }
    finalBlock = (br.b & 0b1) == 1;
    br.b >>= 1;
    int type = br.b & 0b11;
    br.b >>= 2;
    br.nb -= 3;

    switch (type) {
      case 0:
        internalState = InternalState.PROCESS_DATA_BLOCK;
        br.b = 0;
        br.nb = 0;
        dataBlockCopyLength = 0;
        return null;
      case 1:
        internalState = InternalState.PROCESS_HISTORY_COPY_LENGTH;
        lengthIndex = HuffmanTreeIndex.FIXED_INDEX;
        distanceIndex = null;
        historyCopyLength = 0;
        historyCopyDistance = 0;
        return null;
      case 2:
        internalState = InternalState.READ_CUSTOM_HUFFMAN_BLOCK;
        customHuffmanBlockReadState = new CustomHuffmanBlockReadState();
        lengthIndex = null;
        distanceIndex = null;
        return null;
    }
    throw new InflationException();
  }

  @Nullable
  private State processDataBlock(ByteBuffer src) throws InflationException {
    if (dataBlockCopyLength == 0) {
      if (src.remaining() < 4) {
        return State.NEED_MORE_INPUT;
      }

      try (CommitGuard g = new CommitGuard(src)) {
        ByteOrder originalOrder = src.order();
        src.order(ByteOrder.LITTLE_ENDIAN);
        dataBlockCopyLength = src.getShort();
        int inverted = ~src.getShort();
        if ((dataBlockCopyLength & 0xFFFF) != (inverted & 0xFFFF)) {
          throw new InflationException();
        }
        src.order(originalOrder);
        g.commit();
      }

      if (dataBlockCopyLength == 0) {
        internalState = InternalState.READ_NEXT_BLOCK;
        return null;
      }
    }

    int len = Math.min(dataBlockCopyLength, src.remaining());
    int written = out.writeFrom(src, len);
    dataBlockCopyLength -= written;
    if (written < len) {
      return State.NEED_MORE_OUTPUT;
    }
    if (dataBlockCopyLength > 0) {
      return State.NEED_MORE_INPUT;
    }
    internalState = InternalState.READ_NEXT_BLOCK;
    return null;
  }

  @Nullable
  private State processHistoryCopyLength() throws InflationException {
    try {
      while (true) {
        int value = Objects.requireNonNull(lengthIndex).lookup(br);
        if (value < 0) {
          return State.NEED_MORE_INPUT;
        }
        int symbol = value >> HuffmanTreeIndex.CHUNK_VALUE_SHIFT;
        int symbolLen = value & HuffmanTreeIndex.CHUNK_COUNT_MASK;

        int n;
        int length;
        if (symbol < 256) {
          if (out.writeAvailable() == 0) {
            return State.NEED_MORE_OUTPUT;
          }
          out.write((byte) symbol);
          br.b >>= symbolLen;
          br.nb -= symbolLen;
          continue;
        } else if (symbol == 256) {
          br.b >>= symbolLen;
          br.nb -= symbolLen;
          internalState = InternalState.READ_NEXT_BLOCK;
          return null;
        } else if (symbol < 265) {
          length = symbol - (257 - 3);
          n = 0;
        } else if (symbol < 269) {
          length = symbol * 2 - (265 * 2 - 11);
          n = 1;
        } else if (symbol < 273) {
          length = symbol * 4 - (269 * 4 - 19);
          n = 2;
        } else if (symbol < 277) {
          length = symbol * 8 - (273 * 8 - 35);
          n = 3;
        } else if (symbol < 281) {
          length = symbol * 16 - (277 * 16 - 67);
          n = 4;
        } else if (symbol < 285) {
          length = symbol * 32 - (281 * 32 - 131);
          n = 5;
        } else if (symbol < MAX_LITERALS) {
          length = 258;
          n = 0;
        } else {
          throw new InflationException();
        }
        if (n > 0) {
          while (br.nb < symbolLen + n) {
            if (!br.readMore()) {
              return State.NEED_MORE_INPUT;
            }
          }
          length += (br.b >> symbolLen) & ((1 << n) - 1);
        }
        br.b >>= symbolLen + n;
        br.nb -= symbolLen + n;
        historyCopyLength = length;
        internalState = InternalState.PROCESS_HISTORY_COPY_DISTANCE;
        return null;
      }
    } catch (HuffmanTreeIndex.HuffmanCodeDataException e) {
      throw new InflationException(e);
    }
  }

  @Nullable
  private State processHistoryCopyDistance() throws InflationException {
    try {
      int dist;
      int bitConsumed;
      if (distanceIndex == null) {
        while (br.nb < 5) {
          if (!br.readMore()) {
            return State.NEED_MORE_INPUT;
          }
        }
        dist = Integer.reverse((br.b & 0x1F) << 27);
        bitConsumed = 5;
      } else {
        int value = distanceIndex.lookup(br);
        if (value < 0) {
          return State.NEED_MORE_INPUT;
        }
        dist = value >> HuffmanTreeIndex.CHUNK_VALUE_SHIFT;
        bitConsumed = value & HuffmanTreeIndex.CHUNK_COUNT_MASK;
      }

      if (dist < 4) {
        dist++;
      } else if (dist < MAX_DISTANCES) {
        int nb = (dist - 2) >> 1;
        int extra = (dist & 1) << nb;
        while (br.nb < bitConsumed + nb) {
          if (!br.readMore()) {
            return State.NEED_MORE_INPUT;
          }
        }
        extra |= (br.b >> bitConsumed) & ((1 << nb) - 1);
        bitConsumed += nb;
        dist = (1 << (nb + 1)) + 1 + extra;
      } else {
        throw new InflationException();
      }

      if (dist > out.historySize()) {
        throw new InflationException();
      }
      br.b >>= bitConsumed;
      br.nb -= bitConsumed;
      historyCopyDistance = dist;
      internalState = InternalState.PROCESS_HISTORY_COPY;
      return null;
    } catch (HuffmanTreeIndex.HuffmanCodeDataException e) {
      throw new InflationException(e);
    }
  }

  @Nullable
  private State processHistoryCopy() {
    if (out.writeAvailable() == 0) {
      return State.NEED_MORE_OUTPUT;
    }
    if (historyCopyLength > 0) {
      int written = out.writeCopy(historyCopyDistance, historyCopyLength);
      historyCopyLength -= written;

      if (out.writeAvailable() == 0 || historyCopyLength > 0) {
        return State.NEED_MORE_OUTPUT;
      }
    }
    internalState = InternalState.PROCESS_HISTORY_COPY_LENGTH;
    historyCopyLength = 0;
    historyCopyDistance = 0;
    return null;
  }

  @Nullable
  private State processCustomHuffmanBlock() throws InflationException {
    CustomHuffmanBlockReadState state = Objects.requireNonNull(customHuffmanBlockReadState);

    if (state.numDistance == 0) {
      while (br.nb < 5 + 5 + 4) {
        if (!br.readMore()) {
          return State.NEED_MORE_INPUT;
        }
      }

      state.numLiteral = (br.b & 0x1F) + 257;
      if (state.numLiteral > MAX_LITERALS) {
        throw new InflationException();
      }
      br.b >>= 5;
      state.numDistance = (br.b & 0x1F) + 1;
      if (state.numDistance > MAX_DISTANCES) {
        throw new InflationException();
      }
      br.b >>= 5;
      state.numCodeLen = (br.b & 0x0F) + 4;
      br.b >>= 4;
      br.nb -= 5 + 5 + 4;
    }

    if (state.codeIndex == null) {
      for (; state.numReadCodeLen < state.numCodeLen; state.numReadCodeLen++) {
        while (br.nb < 3) {
          if (!br.readMore()) {
            return State.NEED_MORE_INPUT;
          }
        }
        codebits[META_CODE_ORDER[state.numReadCodeLen]] = br.b & 0x07;
        br.b >>= 3;
        br.nb -= 3;
      }
      for (int i = state.numCodeLen; i < META_CODE_ORDER.length; i++) {
        codebits[META_CODE_ORDER[i]] = 0;
      }

      try {
        state.codeIndex = tempIndex1;
        state.codeIndex.init(codebits, 0, codebits.length);
      } catch (HuffmanTreeIndex.HuffmanCodeDataException e) {
        throw new InflationException(e);
      }
    }

    try {
      while (state.numReadLen < state.numLiteral + state.numDistance) {
        int value = state.codeIndex.lookup(br);
        if (value < 0) {
          return State.NEED_MORE_INPUT;
        }
        int symbol = value >> HuffmanTreeIndex.CHUNK_VALUE_SHIFT;
        int symbolLen = value & HuffmanTreeIndex.CHUNK_COUNT_MASK;
        if (symbol < 16) {
          bits[state.numReadLen] = symbol;
          br.b >>= symbolLen;
          br.nb -= symbolLen;
          state.numReadLen++;
          continue;
        }

        int rep;
        int nb;
        int b;
        switch (symbol) {
          case 16:
            rep = 3;
            nb = 2;
            if (state.numReadLen == 0) {
              throw new InflationException();
            }
            b = bits[state.numReadLen - 1];
            break;
          case 17:
            rep = 3;
            nb = 3;
            b = 0;
            break;
          case 18:
            rep = 11;
            nb = 7;
            b = 0;
            break;
          default:
            throw new AssertionError();
        }
        while (br.nb < symbolLen + nb) {
          if (!br.readMore()) {
            return State.NEED_MORE_INPUT;
          }
        }
        rep += (br.b >> symbolLen) & ((1 << nb) - 1);
        br.b >>= symbolLen + nb;
        br.nb -= symbolLen + nb;
        if (state.numReadLen > state.numLiteral + state.numDistance) {
          throw new InflationException();
        }
        for (int j = 0; j < rep; j++) {
          bits[state.numReadLen] = b;
          state.numReadLen++;
        }
      }

      lengthIndex = tempIndex1;
      lengthIndex.init(bits, 0, state.numLiteral);
      distanceIndex = tempIndex2;
      distanceIndex.init(bits, state.numLiteral, state.numDistance);
    } catch (HuffmanTreeIndex.HuffmanCodeDataException e) {
      throw new InflationException(e);
    }

    internalState = InternalState.PROCESS_HISTORY_COPY_LENGTH;
    customHuffmanBlockReadState = null;
    historyCopyLength = 0;
    historyCopyDistance = 0;
    return null;
  }

  public enum State {
    NEED_MORE_INPUT,
    NEED_MORE_OUTPUT,
    DONE,
  }

  private enum InternalState {
    READ_NEXT_BLOCK,
    PROCESS_DATA_BLOCK,
    PROCESS_HISTORY_COPY_LENGTH,
    PROCESS_HISTORY_COPY_DISTANCE,
    PROCESS_HISTORY_COPY,
    READ_CUSTOM_HUFFMAN_BLOCK,
  }

  private static class CustomHuffmanBlockReadState {
    int numLiteral;
    int numDistance;
    int numCodeLen;

    int numReadCodeLen;
    int numReadLen;

    HuffmanTreeIndex codeIndex;
  }

  public static class InflationException extends Exception {
    InflationException() {
      super();
    }

    InflationException(Throwable cause) {
      super(cause);
    }
  }
}


text:
<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
<meta name=Generator content="Microsoft Word 15 (filtered)">
<title>November 24</title>

November 24

Let Your Life Shine

Be
thou an example of the believers in word, in conversation, in charity, in
spirit, in faith, in purity.

 1
Timothy 4:12

One thing the world needs to see
is good examples. They need to see believers walk in love and purity and faith
in their homes, in their schools and in their businesses. The Apostle Paul
exhorts us in Romans 12:17 to live above reproach in the sight of all men.
Other scriptures teach us to avoid all appearance of evil. So, when you go
after God, don't walk out on the edge, trying to see how much you can get by
with. Go all out in God's direction. Conduct yourself in a way that will put to
rest any question about whether or not you're a Christian. Let the people
around you see your love and faith and purity in every situation.

Your example will go a lot
further than your words. When our son, John, was a little boy, we were spending
time with my grandparents. John was sleeping with my granddaddy and he woke him
up in the night and said, "Pop, I have an earache. Would you pray for
it?" Well, my grandparents were raised in a church that didn't believe in
healing. I don't know what Pop did, but it didn't work. So, John just got up
and said, "I'm going to go get in bed with my mother. When she prays, it
stops hurting." About 18 years later, Pop told me the story.

You see, I had set an example of
faith and love and John remembered it. While your children are growing up, they
might forget some of the sermons you've preached or act like they're not
interested in the things of God. But they'll never forget your example. Even at
the place where you work or go to school or just in your neighborhood, people
might reject or argue with the words you say. But they'll never refute or
forget your acts of love.

Don't let petty sins and spiritual
compromises cast a shadow over your example. Live above reproach and let the
light of Jesus shine brightly through you. Scripture Reading: Romans
12:9-21


text:
from unittest import TestCase
from unittest.mock import Mock

from py3njection import inject

class ToInject:
    def return_type(self):
        return ToInject

class ToInjectWithInstanceFactory:
    @classmethod
    def _instance_factory(cls):
        return 'special instance'

class BeingInjected:
    @inject
    def __init__(self, to_inject: ToInject):
        self.to_inject = to_inject

    def call_dependency(self):
        return self.to_inject.return_type()

    @inject
    def use_dependency(self, to_inject: ToInject):
        return to_inject.return_type()

    @inject
    def use_scoped_dependency(self, to_inject: ToInjectWithInstanceFactory):
        return to_inject

class TestInject(TestCase):
    def test_injectObject_inConstructor_whenNotOverrided(self):
        # When
        being_injected = BeingInjected()

        # Then
        result = being_injected.call_dependency()
        self.assertEqual(result, ToInject)

    def test_doNotInjectObject_inConstructor_WhenOverrided(self):
        # Given
        mock = Mock(ToInject)
        mock.return_type.return_value = str

        # When
        being_injected = BeingInjected(to_inject=mock)

        # Then
        result = being_injected.call_dependency()
        self.assertEqual(result, str)

    def test_injectObject_inMethod_whenNotOverrided(self):
        # Given
        injected = BeingInjected()

        # When
        result = injected.use_dependency()

        # Then
        self.assertEqual(result, ToInject)

    def test_doNotInjectObject_inMethod_whenOverrided(self):
        # Given
        injected = BeingInjected()
        mock = Mock(ToInject)
        mock.return_type.return_value = str

        # When
        result = injected.use_dependency(to_inject=mock)

        # Then
        self.assertEqual(result, str)

    def test_shouldUseInstanceFactory_whenExists(self):
        # Given
        injected = BeingInjected()

        # When
        result = injected.use_scoped_dependency()

        # Then
        self.assertEqual(result, 'special instance')


text:
var fs = require('fs-extra');
var express = require('express');
var router = express.Router();
module.exports = router;

//////////////////////////////////////////////
//////////////////////////////////////////////
// GET

router.get('/store', function(req, res) {
    res.render('./backend/gallery/store');
});

//////////////////////////////////////////////
//////////////////////////////////////////////
// POST

multiparty = require('connect-multiparty'),
multipartyMiddleware = multiparty(),

router.post('/upload', multipartyMiddleware, function(req, res) {
    var fsold = require('fs');
    fsold.readFile(req.files.file.path, function (err, data) {
        var newPath = GLOBAL.OPTION_UPLOAD.UPLOAD_DIR + "/" + req.files.file.name;
        fsold.writeFile(newPath, data, function (err) {
            res.json(true);
        });
    });
});

router.post('/create-folder', function(req, res) {
    body = req.body.folder;
    body = GLOBAL.OPTION_UPLOAD.UPLOAD_DIR + '/' + body;
    fs.mkdirs(body, function (err) {
        if (err) {
            res.json(false);
            return
        };
        res.json(true);
    });
});

router.post('/remove', function(req, res) {
    var body = req.body.name;
    body = GLOBAL.OPTION_UPLOAD.UPLOAD_DIR + '/' + body;
    fs.remove(body, function (err) {
        if (err) {
            res.json(false);
            return;
        }
        res.json(true);
    });
});


text:
<!DOCTYPE html>

    <meta charset='utf-8'>
    <meta name='viewport' content='width=device-width,initial-scale=1'>
    <title>rapiro.js 02: ポージング</title>

            名前
            <input type='text' size='4' id='txtname' value='testPose'>

            頭
            <input type='text' size='4' id='txtheadYaw' value='90'>
            右
            <input type='range' id='rngheadYaw' min='0' max='180' value='90'>
            左

            腰
            <input type='text' size='4' id='txtwaistYaw' value='90'>
            右
            <input type='range' id='rngwaistYaw' min='0' max='180' value='90'>
            左

            右肩
            <input type='text' size='4' id='txtrightShoulderPitch' value='90'>
            下
            <input type='range' id='rngrightShoulderPitch' min='0' max='180' value='0'>
            上

            右肩
            <input type='text' size='4' id='txtrightShoulderRoll' value='90'>
            開
            <input type='range' id='rngrightShoulderRoll' min='40' max='130' value='130'>
            閉

            右手
            <input type='text' size='4' id='txtrightHandOpen' value='90'>
            閉
            <input type='range' id='rngrightHandOpen' min='70' max='120' value='90'>
            開

            左肩
            <input type='text' size='4' id='txtleftShoulderPitch' value='90'>
            上
            <input type='range' id='rngleftShoulderPitch' min='0' max='180' value='180'>
            下

            左肩
            <input type='text' size='4' id='txtleftShoulderRoll' value='90'>
            閉
            <input type='range' id='rngleftShoulderRoll' min='40' max='130' value='40'>
            開

            左手
            <input type='text' size='4' id='txtleftHandOpen' value='90'>
            開
            <input type='range' id='rngleftHandOpen' min='70' max='120' value='90'>
            閉

            右脚
            <input type='text' size='4' id='txtrightLegYaw' value='90'>
            内
            <input type='range' id='rngrightLegYaw' min='0' max='180' value='90'>
            外

            右足
            <input type='text' size='4' id='txtrightFootRoll' value='90'>
            内
            <input type='range' id='rngrightFootRoll' min='0' max='180' value='90'>
            外

            左脚
            <input type='text' size='4' id='txtleftLegYaw' value='90'>
            外
            <input type='range' id='rngleftLegYaw' min='0' max='180' value='90'>
            内

            左足
            <input type='text' size='4' id='txtleftFootRoll' value='90'>
            外
            <input type='range' id='rngleftFootRoll' min='0' max='180' value='90'>
            内

            色R
            <input type='text' size='4' id='txtR' value='90'>
            暗
            <input type='range' id='rngR' min='0' max='255' value='127'>
            明

            色G
            <input type='text' size='4' id='txtG' value='90'>
            暗
            <input type='range' id='rngG' min='0' max='255' value='127'>
            明

            色B
            <input type='text' size='4' id='txtB' value='90'>
            暗
            <input type='range' id='rngB' min='0' max='255' value='127'>
            明

            速度
            <input type='text' size='4' id='txttimeInMs' value='90'>
            速
            <input type='range' id='rngtimeInMs' min='100' max='1000' value='500'>
            遅

    リセットはページをリロードして→<input type='button' id='btnSend' value='リセット'>


text:
package com.frameworkset.common.tag.tree.impl;

import javax.servlet.jsp.JspException;

import com.frameworkset.common.tag.BaseTag;

/**
 * 记录树的一些参数
 * @author biaoping.yin
 * created on 2005-7-8
 * version 1.0
 */
public class ParamTag extends BaseTag {
    String name;
    String scope;
    String value;
    boolean encode = true;
    private String defaultValue = null;
    public int doEndTag() throws JspException
    {

    	return super.doEndTag();
    }
    @Override
	public void doFinally() {
    	this.name = null;
    	this.scope = null;
    	this.value = null;
    	this.encode = true;
    	super.doFinally();
    }
    /**
     * Description:
     * @return defaultValue

     */
    public String getDefaultValue() {
        return defaultValue;
    }

    /**
     * Description:defaultValue
     * @return void

     */
    public void setDefaultValue(String string) {
        defaultValue = string;
    }

    public void setEncode(boolean encode)
    {
        this.encode = encode;
    }

    public boolean getEncode()
    {
        return this.encode;
    }
    /**
     * @return Returns the name.
     */
    public String getName() {
        return name;
    }
    /**
     * @param name The name to set.
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * @return Returns the scope.
     */
    public String getScope() {
        return scope;
    }
    /**
     * @param scope The scope to set.
     */
    public void setScope(String scope) {
        this.scope = scope;
    }
    private void addParam(TreeTag parent,String name,String value)
    {
        parent.addParam(name,value);
    }
    public int doStartTag()
    {
        TreeTag parent = (TreeTag) this.getParent();
        if(scope == null || scope.equals("request"))
        {
            if(value == null)
            {
	            String[] values = this.getHttpServletRequest().getParameterValues(name);
	            if(values != null)
                {
                    for(int i = 0; i < values.length; i ++)
                    {
                    	if(values[i] != null)
                    	{
	                        if(this.encode)
	                        {
	                            this.addParam(parent,name,java.net.URLEncoder.encode(values[i]));
	                        }
	                        else
	                            this.addParam(parent,name,values[i]);
                    	}
                    }
                }
                else if(this.defaultValue != null)
                {
                    if(this.encode)
                    {
                            this.addParam(parent,name,java.net.URLEncoder.encode(defaultValue));
                    }
                    else
                        this.addParam(parent,name,defaultValue);
                }
	        }
            else
            {
                if(encode)
                    addParam(parent,name,java.net.URLEncoder.encode(value));
                else
                    addParam(parent,name,value);
            }
        }
        else if(this.getSession() != null && scope.equals("session"))
        {
            String value = (String)getSession().getAttribute(name);
            if(value != null )
            {
                if(encode)
                    addParam(parent, name, java.net.URLEncoder.encode(value));
                else
                    addParam(parent, name, value);
            }
            else if(this.defaultValue != null)
            {
                if(this.encode)
                        this.addParam(parent,name,java.net.URLEncoder.encode(defaultValue));
                else
                    this.addParam(parent,name,defaultValue);
            }

        }
        else if(scope.equals("pageContext"))
        {
            String value = (String)pageContext.getAttribute(name);
            if(value != null )
            {
                if(encode)
                    addParam(parent, name, java.net.URLEncoder.encode(value));
                else
                    addParam(parent, name, value);
            }
            else if(this.defaultValue != null)
            {
                if(this.encode)
                        this.addParam(parent,name,java.net.URLEncoder.encode(defaultValue));
                else
                    this.addParam(parent,name,defaultValue);
            }

        }

        return SKIP_BODY;
    }
    /**
     * @return Returns the value.
     */
    public String getValue() {
        return value;
    }
    /**
     * @param value The value to set.
     */
    public void setValue(String value) {
        this.value = value;
    }
}


text:
@interface TLPlaceViewController ()

@end

@implementation TLPlaceViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
-(IBAction)click:(id)sender event:(id)event{
    UIButton *button = (UIButton *)sender;
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
    TLChangsuoViewController *changsuo = [storyboard instantiateViewControllerWithIdentifier:@"changsuo"];
    [changsuo setBranchName:self.branchName];
    [changsuo setChangsuo:button.titleLabel.text];
    [self.navigationController pushViewController:changsuo animated:YES];
}
@end


text:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>se.kth.karamel</groupId>
  <artifactId>karamel-parent</artifactId>
  <packaging>pom</packaging>
  <version>0.8</version>
  <name>karamel-parent</name>
  <url>http://maven.apache.org</url>

  <!-- Modules in the Project.-->
  <modules>
    <module>karamel-ui</module>
    <module>karamel-core</module>
    <module>karamel-common</module>
  </modules>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <jclouds.version>2.1.2</jclouds.version>
    <java.compiler.version>1.8</java.compiler.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-all</artifactId>
      <version>1.9.5</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <developers>
    <developer>
      <id>jdowling</id>
      <name>Jim Dowling</name>
      <email>jdowling>sics.se</email>
      <url>http://www.sics.se/node/1405</url>
      <organization>Swedish Institute of Computer Science (SICS)</organization>
      <organizationUrl>http://www.sics.se/</organizationUrl>
      <roles>
        <role>architect</role>
        <role>developer</role>
      </roles>
      <timezone>+1</timezone>
    </developer>
    <developer>
      <id>kamal</id>
      <name>Kamal Hakimzadeh</name>
      <email>kamal2>kth.se</email>
      <organization>KTH</organization>
      <organizationUrl>http://www.kth.se/</organizationUrl>
      <roles>
        <role>architect</role>
        <role>developer</role>
      </roles>
      <timezone>+1</timezone>
    </developer>
    <developer>
      <id>abhi</id>
      <name>Abhimanyu Babbar</name>
      <email>babbar>kth.se</email>
      <organization>KTH</organization>
      <organizationUrl>http://www.kth.se/</organizationUrl>
      <roles>
        <role>developer</role>
      </roles>
      <timezone>+1</timezone>
    </developer>
    <developer>
      <id>alorlea</id>
      <name>Alberto Lorente Leal</name>
      <email>a.lorenteleal>gmail.com</email>
      <organization>Free contributor</organization>
      <organizationUrl>http://alorlea.github.io/</organizationUrl>
      <roles>
        <role>developer</role>
      </roles>
      <timezone>+1</timezone>
    </developer>
  </developers>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>se.kth.karamel</groupId>
        <artifactId>karamel-common</artifactId>
        <version>${project.version}</version>
      </dependency>
      <dependency>
        <groupId>se.kth</groupId>
        <artifactId>karamel-core</artifactId>
        <version>${project.version}</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <distributionManagement>
    <repository>
      <id>sics-release-repository</id>
      <name>SICS Repository</name>
      <url>scpexe://kompics.i.sics.se/home/maven/repository</url>
    </repository>
    <snapshotRepository>
      <id>sics-snapshot-repository</id>
      <name>SICS Snapshot Repository</name>
      <url>scpexe://kompics.i.sics.se/home/maven/snapshotrepository</url>
    </snapshotRepository>
    <site>
      <id>kompics-site</id>
      <url>scpexe://kompics.i.sics.se/var/www/kompics/report/trunk</url>
    </site>
    <downloadUrl>http://kompics.i.sics.se/maven/repository</downloadUrl>
  </distributionManagement>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-checkstyle-plugin</artifactId>
        <version>2.15</version>
        <executions>
          <execution>
            <id>validate</id>
            <phase>validate</phase>
            <goals>
              <goal>check</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <suppressionsLocation>/tools/maven/suppressions.xml</suppressionsLocation>
          <suppressionsFileExpression>/checkstyle.suppressions.file</suppressionsFileExpression>
          <configLocation>/tools/maven/checkstyle.xml</configLocation>
          <logViolationsToConsole>true</logViolationsToConsole>
          <failsOnError>true</failsOnError>
          <consoleOutput>true</consoleOutput>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>${java.compiler.version}</source>
          <target>${java.compiler.version}</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>versions-maven-plugin</artifactId>
        <version>2.1</version>
      </plugin>
      <plugin>
        <artifactId>maven-scm-plugin</artifactId>
        <version>1.8.1</version>
        <configuration>
          <tag>${project.artifactId}-${project.version}</tag>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <scm>
    <connection>scm:git:git@github.com:karamelchef/karamel.git</connection>
  </scm>

  <repositories>
    <repository>
      <id>sics-release</id>
      <name>SICS Release Repository</name>
      <url>http://kompics.sics.se/maven/repository</url>
      <releases>
      </releases>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
    <repository>
      <id>sics-snapshot</id>
      <name>SICS Snapshot Repository</name>
      <url>http://kompics.sics.se/maven/snapshotrepository</url>
      <releases>
        <enabled>false</enabled>
      </releases>
      <snapshots>
      </snapshots>
    </repository>
  </repositories>
</project>


text:
exports.route_err404 = function(req, res){

        res.render('err404', {locals: {title: ' Multipart Form example'}, status: 404})
};