text:
//Copyright (c) 2014 Singapore-MIT Alliance for Research and Technology
//Licensed under the terms of the MIT License, as described in the file:
//   license.txt   (http://opensource.org/licenses/MIT)

/**
 * \file main_impl.cpp
 * A first approximation of the basic pseudo-code in C++. The main file loads several
 * properties from data/config.xml, and attempts a simulation run. Currently, the various
 * granularities and pedestrian starting locations are loaded.
 *
 * \note
 * This file contains everything except a main method, which is contained within main.cpp.
 * The function main_impl() has the exact same signature as main(), and serves the exact same purpose.
 * See the note in main.cpp if you have any questions.
 *
 * \author Seth N. Hetu
 * \author LIM Fung Chai
 * \author Xu Yan
 */

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp>

//main.cpp (top-level) files can generally get away with including GenConfig.h
#include "GenConfig.h"

#include "buffering/BufferedDataManager.hpp"
#include "buffering/Buffered.hpp"
#include "buffering/Locked.hpp"
#include "buffering/Shared.hpp"
#include "conf/ConfigManager.hpp"
#include "config/ExpandShortTermConfigFile.hpp"
#include "config/ParseShortTermConfigFile.hpp"
#include "conf/ParseConfigFile.hpp"
#include "entities/BusStopAgent.hpp"
#include "entities/ClosedLoopRunManager.hpp"
#include "entities/commsim/broker/Broker.hpp"
#include "entities/LoopDetectorEntity.hpp"
#include "entities/IntersectionManager.hpp"
#include "entities/profile/ProfileBuilder.hpp"
#include "entities/PT_Statistics.hpp"
#include "entities/roles/activityRole/ActivityPerformer.hpp"
#include "entities/roles/driver/driverCommunication/DriverComm.hpp"
#include "entities/roles/pedestrian/Pedestrian.hpp"
#include "entities/fmodController/FMOD_Controller.hpp"
#include "geospatial/network/NetworkLoader.hpp"
#include "logging/ControllerLog.hpp"
#include "logging/Log.hpp"
#include "network/CommunicationManager.hpp"
#include "network/ControlManager.hpp"
#include "partitions/ParitionDebugOutput.hpp"
#include "partitions/ShortTermBoundaryProcessor.hpp"
#include "util/StateSwitcher.hpp"
#include "util/Utils.hpp"
#include "workers/WorkGroupManager.hpp"
#include "entities/roles/waitTaxiActivity/WaitTaxiActivity.hpp"
#include <entities/FleetController_ST.hpp>
#include "entities/roles/driver/OnCallDriver.hpp"

//Note: This must be the LAST include, so that other header files don't have
//      access to cout if SIMMOB_DISABLE_OUTPUT is true.

using std::endl;
using std::vector;
using std::string;

using namespace sim_mob;

//Start time of program
timeval start_time;

//Current software version.
const string SIMMOB_VERSION = string(SIMMOB_VERSION_MAJOR) + ":" + SIMMOB_VERSION_MINOR;

/**
 * Main simulation loop.
 * \note
 * For doxygen, we are setting the variable JAVADOC AUTOBRIEF to "true"
 * This isn't necessary for class-level documentation, but if we want
 * documentation for a short method (like "get" or "set") then it makes sense to
 * have a few lines containing brief/full comments. (See the manual's description
 * of JAVADOC AUTOBRIEF). Of course, we can discuss this first.
 *
 * \par
 * See Buffered.hpp for an example of this in action.
 *
 * \par
 * ~Seth
 *
 * This function is separate from main() to allow for easy scoping of WorkGroup objects.
 */
bool performMain(const std::string& configFileName, const std::string& shortConfigFile, std::list<std::string>& resLogFiles, const std::string& XML_OutPutFileName)
{
    Print() <<"Starting SimMobility, version " << SIMMOB_VERSION << endl;
    DailyTime::initAllTimes();

    ST_Config& stCfg = ST_Config::getInstance();

    //Parse the config file (this *does not* create anything, it just reads it.).
    ParseConfigFile parse(configFileName, ConfigManager::GetInstanceRW().FullConfig());

    ParseShortTermConfigFile stParse(shortConfigFile, ConfigManager::GetInstanceRW().FullConfig(), stCfg);

    //Enable or disable logging (all together, for now).
    //NOTE: This may seem like an odd place to put this, but it makes sense in context.
    //      OutputEnabled is always set to the correct value, regardless of whether ConfigParams()
    //      has been loaded or not. The new Config class makes this much clearer.
    if (ConfigManager::GetInstance().CMakeConfig().OutputEnabled())
    {
        Warn::Init("warn.log");
        Print::Init("<stdout>");
        ControllerLog::Init("controller.log");
    }
    else
    {
        Warn::Ignore();
        Print::Ignore();
        ControllerLog::Ignore();
    }

    ProfileBuilder* prof = nullptr;

    if (ConfigManager::GetInstance().CMakeConfig().ProfileOn())
    {
        ProfileBuilder::InitLogFile("profile_trace.txt");
        prof = new ProfileBuilder();
    }

    //Save a handle to the shared definition of the configuration.
    const ConfigParams &config = ConfigManager::GetInstance().FullConfig();
    const MutexStrategy &mtx = config.mutexStategy();

    //Create an instance of role factory
    RoleFactory<Person_ST> *rf = new RoleFactory<Person_ST>;
    RoleFactory<Person_ST>::setInstance(rf);

    //Register our Role types.
    if (stCfg.commSimEnabled())
    {
        rf->registerRole("driver", new DriverComm(nullptr, mtx));
    }
    else
    {
        rf->registerRole("driver", new Driver(nullptr, mtx));
    }

    rf->registerRole("pedestrian", new Pedestrian(nullptr));
    rf->registerRole("passenger",new Passenger(nullptr));
    rf->registerRole("busdriver", new BusDriver(nullptr, mtx));
    rf->registerRole("activityRole", new ActivityPerformer<Person_ST>(nullptr));
    rf->registerRole("waitBusActivity", new WaitBusActivity(nullptr));
    rf->registerRole("taxidriver", new Driver(nullptr, mtx));
    rf->registerRole("waitTaxiActivity", new WaitTaxiActivity(nullptr));
    rf->registerRole("onCallDriver", new OnCallDriver(nullptr,mtx));

    //Loader params for our Agents
    WorkGroup::EntityLoadParams entLoader(Agent::pending_agents, Agent::all_agents);

    //Load the configuration file
    Print() << "\nLoading the configuration files: " << configFileName << ", " << shortConfigFile << "..." << std::endl;
    ExpandShortTermConfigFile expand(stCfg, ConfigManager::GetInstanceRW().FullConfig(), Agent::all_agents, Agent::pending_agents);

    if (config.PathSetMode())
    {
        //Initialise path-set manager
        PrivateTrafficRouteChoice* pvtRtChoice = PrivateTrafficRouteChoice::getInstance();
        std::string name = configFileName;
        pvtRtChoice->setScenarioName(name);
    }

    //Initialise the control manager and wait for an IDLE state (interactive mode only).
    ControlManager* ctrlMgr = nullptr;

    if (ConfigManager::GetInstance().CMakeConfig().InteractiveMode())
    {
        Print() << "Scenario loaded...\nSimulation state is IDLE"<<std::endl;

        ctrlMgr = ConfigManager::GetInstance().FullConfig().getControlMgr();
        ctrlMgr->setSimState(IDLE);

        while(ctrlMgr->getSimState() == IDLE)
        {
            boost::this_thread::sleep(boost::posix_time::milliseconds(10));
        }
    }

    //Start boundaries
    if (!config.MPI_Disabled() && config.using_MPI)
    {
        PartitionManager::instance().initBoundaryTrafficItems();
    }

    //bool NoDynamicDispatch = config.DynamicDispatchDisabled();

    PartitionManager* partMgr = nullptr;

    if (!config.MPI_Disabled() && config.using_MPI)
    {
        partMgr = &PartitionManager::instance();
    }

    {
    //Begin scope: WorkGroups
    //TODO: WorkGroup scope currently does nothing. We need to re-enable WorkGroup deletion at some later point. ~Seth
    WorkGroupManager wgMgr;
    wgMgr.setSingleThreadMode(false);

    //Work Group specifications
    WorkGroup* personWorkers = wgMgr.newWorkGroup(stCfg.personWorkGroupSize(), config.totalRuntimeTicks, stCfg.granPersonTicks, &AuraManager::instance(), partMgr);
    WorkGroup* signalStatusWorkers = wgMgr.newWorkGroup(stCfg.signalWorkGroupSize(), config.totalRuntimeTicks, stCfg.granSignalsTicks);
    WorkGroup* intMgrWorkers = wgMgr.newWorkGroup(stCfg.intMgrWorkGroupSize(), config.totalRuntimeTicks, stCfg.granIntMgrTicks);

    //TODO: Ideally, the Broker would go on the agent Work Group. However, the Broker often has to wait for all Agents to finish.
    //      If an Agent is "behind" the Broker, we have two options:
    //        1) Have some way of specifying that the Broker agent goes "last" (Agent priority?)
    //        2) Have some way of telling the parent Worker to "delay" this Agent (e.g., add it to a temporary list) from *within* update.
    WorkGroup* communicationWorkers = wgMgr.newWorkGroup(stCfg.commWorkGroupSize(), config.totalRuntimeTicks, stCfg.granCommunicationTicks);

    //Initialise the aura manager
    AuraManager::instance().init(stCfg.aura_manager_impl());

    //Initialise all work groups (this creates barriers, and locks down creation of new groups).
    wgMgr.initAllGroups();

    messaging::MessageBus::RegisterHandler(PT_Statistics::getInstance());

    //Initialise each work group individually
    personWorkers->initWorkers(&entLoader);
    signalStatusWorkers->initWorkers(nullptr);
    intMgrWorkers->initWorkers(nullptr);
    communicationWorkers->initWorkers(nullptr);

    //If communication simulator is enabled, start the Broker.
    if(stCfg.commSimEnabled())
    {
        //NOTE: I am fairly sure that MtxStrat_Locked is the wrong mutex strategy. However, Broker doesn't
        //      register any buffered properties (except x/y, which Agent registers), and it never updates these.
        //      I am changing this back to buffered; if this runs smoothly for a while, then you can remove this comment. ~Seth
        //NOTE: I am also changing the Agent ID; manually specifying it as 0 is dangerous.
        Broker *broker =  new Broker(MtxStrat_Buffered);
        Broker::SetSingleBroker(broker);
        communicationWorkers->assignAWorker(broker);
    }

    //Create and register bus stop agents
    const std::map<unsigned int, BusStop *> &busStops = RoadNetwork::getInstance()->getMapOfIdvsBusStops();

    for(std::map<unsigned int, BusStop *>::const_iterator itStops = busStops.begin(); itStops != busStops.end(); ++itStops)
    {
        BusStopAgent *busStopAgent = new BusStopAgent(mtx, -1, itStops->second);
        BusStopAgent::registerBusStopAgent(busStopAgent, *personWorkers);
    }

    //Assign all signals to the signals worker
    const std::map<unsigned int, Signal *> &signals = Signal::getMapOfIdVsSignals();

    for (std::map<unsigned int, Signal *>::const_iterator it = signals.begin(); it != signals.end(); ++it)
    {
        Signal_SCATS *signalScats = dynamic_cast<Signal_SCATS *>(it->second);

        //Create and initialise loop detectors
        LoopDetectorEntity *loopDetectorEntity = new LoopDetectorEntity(mtx);
        loopDetectorEntity->init(*signalScats);
        Agent::all_agents.insert((Entity *&&) loopDetectorEntity);
        signalScats->setLoopDetector(loopDetectorEntity);
        signalStatusWorkers->assignAWorker(it->second);
    }

    //Anything in all_agents is starting on time 0, and should be added now.
    for (std::set<Entity*>::iterator it = Agent::all_agents.begin(); it != Agent::all_agents.end(); ++it)
    {
        personWorkers->assignAWorker(*it);
    }

    //Assign all intersection managers to the signal worker
    const map<unsigned int, IntersectionManager *> &intManagers = IntersectionManager::getIntManagers();
    for (map<unsigned int, IntersectionManager *>::const_iterator it = intManagers.begin(); it != intManagers.end(); ++it)
    {
        intMgrWorkers->assignAWorker(it->second);
    }

    if (stCfg.amod.enabled && amod::AMODController::instanceExists())
    {
        personWorkers->assignAWorker(amod::AMODController::getInstance());
    }

    if (FMOD::FMOD_Controller::instanceExists())
    {
        personWorkers->assignAWorker(FMOD::FMOD_Controller::instance());
    }
    if (MobilityServiceControllerManager::HasMobilityServiceControllerManager())
    {
        personWorkers->assignAWorker(FleetController_ST::getInstance());
        auto controllers = MobilityServiceControllerManager::GetInstance()->getControllers();
        for (auto it = controllers.get<ctrlrId>().begin(); it != controllers.get<ctrlrId>().end(); ++it)
        {
            personWorkers->assignAWorker(*it);
        }
    }

    if(config.simulation.closedLoop.enabled)
    {
        const ClosedLoopParams &params = config.simulation.closedLoop;
        ClosedLoopRunManager::initialise(params.guidanceFile, params.tollFile, params.incentivesFile);
    }

    Print() << "Simulating...\n";

    //Start work groups and all threads.
    wgMgr.startAllWorkGroups();

    if (!config.MPI_Disabled() && config.using_MPI)
    if (!config.MPI_Disabled() && config.using_MPI)
    {
        PartitionManager& partitionImpl = PartitionManager::instance();
        partitionImpl.setEntityWorkGroup(personWorkers, signalStatusWorkers);

        Print() << "partition_solution_id in main function:" << partitionImpl.partition_config->partition_solution_id << std::endl;
    }

    /////////////////////////////////////////////////////////////////
    // NOTE: WorkGroups are able to handle skipping steps by themselves.
    //       So, we simply call "wait()" on every tick, and on non-divisible
    //       time ticks, the WorkGroups will return without performing
    //       a barrier sync.
    /////////////////////////////////////////////////////////////////
    timeval loop_start_time;
    gettimeofday(&loop_start_time, nullptr);
    int loop_start_offset = (int) ProfileBuilder::diff_ms(loop_start_time, start_time);

    StateSwitcher<int> numTicksShown(0); //Only goes up to 10
    StateSwitcher<int> lastTickPercent(0); //So we have some idea how much time is left.
    int endTick = config.totalRuntimeTicks;

    for (unsigned int currTick = 0; currTick < endTick; currTick++)
    {
        if (config.InteractiveMode())
        {
            if(ctrlMgr->getSimState() == STOP)
            {
                while (ctrlMgr->getEndTick() < 0)
                {
                    ctrlMgr->setEndTick(currTick+2);
                }

                endTick = ctrlMgr->getEndTick();
            }
        }

        //Output. We show every 10% change. (just to give some indication of progress)
        int currTickPercent = (currTick * 100) / config.totalRuntimeTicks;
        currTickPercent /= 10; //Only update 10%, 20%, etc.

        //Determine whether to print this time tick or not.
        bool printTick = lastTickPercent.update(currTickPercent);

        //Note that OutputEnabled also affects locking.
        if (printTick)
        {
            std::stringstream msg;
            msg << currTickPercent << "0%" << std::endl;
            PrintOut(msg.str());
            ControllerLogOut(msg.str());
        }

        //Agent-based cycle, steps 1,2,3,4 of 4
        wgMgr.waitAllGroups();

        unsigned long currTimeMS = currTick * config.baseGranMS();

        //Check if we are running in closed loop with DynaMIT
        if(config.simulation.closedLoop.enabled && (currTimeMS + config.baseGranMS()) % (config.simulation.closedLoop.sensorStepSize * 1000) == 0)
        {
            SurveillanceStation::writeSurveillanceOutput(config, currTimeMS + config.baseGranMS());
            ClosedLoopRunManager::waitForDynaMIT(config);
        }

        if(stCfg.outputStats.segDensityMap.outputEnabled && ((currTimeMS + config.baseGranMS()) % stCfg.outputStats.segDensityMap.updateInterval == 0))
        {
            DriverMovement::outputDensityMap((unsigned int) (currTimeMS / stCfg.outputStats.segDensityMap.updateInterval));
        }
    }

    timeval loop_end_time;
    gettimeofday(&loop_end_time, nullptr);
    int loop_time = (int) ProfileBuilder::diff_ms(loop_end_time, loop_start_time);
    Print() << "100%\n\nTime required to execute the simulation: "
            << DailyTime((uint32_t) loop_time).getStrRepr() << std::endl;

    //Finalize partition manager
    if (!config.MPI_Disabled() && config.using_MPI)
    {
        PartitionManager& partitionImpl = PartitionManager::instance();
        partitionImpl.stopMPIEnvironment();
    }

    //Store the segment travel times
    if (config.PathSetMode())
    {
        TravelTimeManager::getInstance()->storeCurrentSimulationTT();;
    }

    if(config.odTTConfig.enabled)
    {
        TravelTimeManager::getInstance()->dumpODTravelTimeToFile(config.odTTConfig.fileName);
    }

    if(config.rsTTConfig.enabled)
    {
        TravelTimeManager::getInstance()->dumpSegmentTravelTimeToFile(config.rsTTConfig.fileName);
    }

    Print() << "Time required for initialisation [Loading configuration, network, demand ...]: "
            << DailyTime((uint32_t) loop_start_offset).getStrRepr() << std::endl;

    if(config.numPathNotFound > 0)
    {
        Print() << "\nPersons not simulated as the path was not found [Refer to warn.log for more details]: "
                << config.numPathNotFound << endl;
    }

    Print() << "\nNumber of trips/activities [demand] loaded: " << config.numTripsLoaded
            << "\nNumber of trips/activities [demand] completed: " << config.numTripsCompleted << "\n";

    size_t numActivities = 0, numBusDriver = 0, numCarPassenger = 0, numDriver = 0, numPassenger = 0, numPedestrian = 0;
    size_t numPersons = 0, numPrivateBusPassenger = 0, numTrainPassenger = 0, numWaitBus = 0, numTaxiPassenger=0;
    size_t numTravelPedestrian = 0, numWaitTaxi = 0;

    for (std::set<Entity*>::iterator it = Agent::all_agents.begin(); it != Agent::all_agents.end(); ++it)
    {
        Person_ST *person = dynamic_cast<Person_ST *> (*it);

        if (person)
        {
            Role<Person_ST> *role = person->getRole();

            if (role)
            {
                numPersons++;
                switch (role->roleType)
                {
                case Role<Person_ST>::RL_ACTIVITY:
                    numActivities++;
                    break;
                case Role<Person_ST>::RL_BUSDRIVER:
                    numBusDriver++;
                    break;
                case Role<Person_ST>::RL_CARPASSENGER:
                    numCarPassenger++;
                    break;
                case Role<Person_ST>::RL_DRIVER:
                    numDriver++;
                    break;
                case Role<Person_ST>::RL_PASSENGER:
                    numPassenger++;
                    break;
                case Role<Person_ST>::RL_PEDESTRIAN:
                    numPedestrian++;
                    break;
                case Role<Person_ST>::RL_PRIVATEBUSPASSENGER:
                    numPrivateBusPassenger++;
                    break;
                case Role<Person_ST>::RL_TRAINPASSENGER:
                    numTrainPassenger++;
                    break;
                case Role<Person_ST>::RL_WAITBUSACTIVITY:
                    numWaitBus++;
                    break;
                case Role<Person_ST>::RL_TAXIPASSENGER:
                    numTaxiPassenger++;
                    break;
                case Role<Person_ST>::RL_TRAVELPEDESTRIAN:
                    numTravelPedestrian++;
                    break;
                    case Role<Person_ST>::RL_WAITTAXIACTIVITY:
                        numWaitTaxi++;
                        break;
                    case Role<Person_ST>::RL_TAXIDRIVER:
                    case Role<Person_ST>::RL_ON_HAIL_DRIVER:
                    case Role<Person_ST>::RL_ON_CALL_DRIVER:
                        numPersons--;
                        break;
                }
            }
        }
    }

    Print() << "\nPersons still in the simulation: " << numPersons << "\n"
            << numActivities << " Performing activity,\t" << numBusDriver << " BusDrivers,\t"
            << numCarPassenger << " CarPassengers,\t" << numDriver << " Drivers,\t"
            << numPassenger << " Passengers,\t" << numPedestrian << " Pedestrians,\t"
            << numPrivateBusPassenger << " PrivateBusPassenger,\t"
            << numTrainPassenger << " TrainPassengers,\t"   << numWaitBus << " Waiting for bus\t"
            << numPassenger << " Passengers,\t" << numPedestrian << " Pedestrians,\t"
            << numTravelPedestrian << " Travel pedestrians,\t"<< numWaitTaxi << " Waiting for Taxi,\t"<< numTaxiPassenger << " TaxiPassenger\n" ;

    if (config.numAgentsKilled > 0)
    {
        Print() << "\nAgents removed from simulation due to errors [Refer to warn.log for more details]: "
                << config.numAgentsKilled << endl;
    }

    if (!Agent::pending_agents.empty())
    {
        Print() << "\nWARNING! There are still " << Agent::pending_agents.size()
                << " agents waiting to be scheduled. Next start time is: "
                << Agent::pending_agents.top()->getStartTime() << " ms\n";
    }

    PT_Statistics::getInstance()->storeStatistics();
    PT_Statistics::resetInstance();

    //Save our output files if we are merging them later.
    if (ConfigManager::GetInstance().CMakeConfig().OutputEnabled() && config.mergeLogFiles)
    {
        resLogFiles = wgMgr.retrieveOutFileNames();
    }

    //Here, we will simply scope-out the WorkGroups, and they will migrate out all remaining Agents.
    }  //End scope: WorkGroups. (Todo: should move this into its own function later)
    //WorkGroup::FinalizeAllWorkGroups();

    //At this point, it should be possible to delete all Signals and Agents.
    //TODO: For some reason, clear_delete_vector() does (may?) not work in INTERACTIVE mode.
    //      We can address this later, but it should *definitely* be possible to cleanly
    //      exit (even early) from the simulation.
    //TODO: I think that the WorkGroups and Workers need to have the "endTick" value propagated to
    //      them from the main loop, in the event that the simulator is shutting down early. This is
    //      probably causing the Workers to hang if clear_delete_vector is called. ~Seth
    //EDIT: Actually, Worker seems to handle the synchronisation fine too.... but I still think the main
    //      loop should propagate this value down. ~Seth
    if (ConfigManager::GetInstance().CMakeConfig().InteractiveMode())
    {
        Agent::all_agents.clear();
    }
    else
    {
        clear_delete_map(IntersectionManager::getIntManagers());
        clear_delete_map(Signal::getMapOfIdVsSignals());
        BusStopAgent::removeAllBusStopAgents();
        clear_delete_vector(Agent::all_agents);
    }

    Print() << "\nSimulation complete. Closing worker threads...\n" << endl;

    //Destroy the road network
    NetworkLoader::deleteInstance();

    //Delete the AMOD controller instance
    amod::AMODController::deleteInstance();

    if(FMOD::FMOD_Controller::instanceExists())
    {
        FMOD::FMOD_Controller::instance()->finalizeMessageToFMOD();
    }

    //Delete the aura manger implementation instance
    AuraManager::instance().destroy();

    //Delete our profiler, if it exists.
    safe_delete_item(prof);

    return true;
}

/**
 * Run the main loop of Sim Mobility, using command-line input.
 * Returns the value of the last completed run of performMain().
 */
int run_simmob_interactive_loop()
{
    ControlManager *ctrlMgr = ConfigManager::GetInstance().FullConfig().getControlMgr();
    std::list<std::string> resLogFiles;
    int retVal = 1;

    for (;;)
    {
        if(ctrlMgr->getSimState() == LOADSCENARIO)
        {
            ctrlMgr->setSimState(RUNNING);
            std::map<std::string,std::string> paras;
            ctrlMgr->getLoadScenarioParas(paras);
            std::string configFileName = paras["configFileName"];
            std::string stConfigFile = paras["shortTermConfigFile"];
            retVal = performMain(configFileName, stConfigFile, resLogFiles, "XML_OutPut.xml") ? 0 : 1;
            ctrlMgr->setSimState(STOP);
            ConfigManager::GetInstanceRW().reset();
            Print() << "scenario finished" << std::endl;
        }
        if(ctrlMgr->getSimState() == QUIT)
        {
            Print() <<"Thank you for using SIMMOB. Have a good day!" <<std::endl;
            break;
        }
    }

    return retVal;
}

int main_impl(int ARGC, char* ARGV[])
{
    std::vector<std::string> args = Utils::parseArgs(ARGC, ARGV);

    //Argument 1: Configuration file
    //Note: Don't change this here; change it by supplying an argument on the
    //      command line, or through Eclipse's "Run Configurations" dialog.
    std::string configFileName = "data/config.xml";
    std::string shortConfigFile = "data/shortTerm.xml";

    if (args.size() > 2)
    {
        configFileName = args[1];
        shortConfigFile = args[2];
    }
    else if (args.size() > 1)
    {
        configFileName = args[1];
        Print() << "No short term configuration file specified; Using default short term configuration file..." << endl;
    }
    else
    {
        Print() << "No configuration files specified. \nUsing default short term configuration file: " << shortConfigFile << endl;
        Print() << "Using the default configuration file: " << configFileName << endl;
    }

    std::string outputFileName = "out.txt";

    if(args.size() > 3)
    {
        outputFileName = args[2];
    }

    //Currently needs the #ifdef because of the way threads initialize.
#ifdef SIMMOB_INTERACTIVE_MODE
    CommunicationManager *dataServer = new CommunicationManager(13333, ConfigManager::GetInstance().FullConfig().getCommDataMgr(), *ConfigManager::GetInstance().FullConfig().getControlMgr());
    boost::thread dataWorkerThread(boost::bind(&CommunicationManager::start, dataServer));
    CommunicationManager *cmdServer = new CommunicationManager(13334, ConfigManager::GetInstance().FullConfig().getCommDataMgr(), *ConfigManager::GetInstance().FullConfig().getControlMgr());
    boost::thread cmdWorkerThread(boost::bind(&CommunicationManager::start, cmdServer));
    CommunicationManager *roadNetworkServer = new CommunicationManager(13335, ConfigManager::GetInstance().FullConfig().getCommDataMgr(), *ConfigManager::GetInstance().FullConfig().getControlMgr());
    boost::thread roadNetworkWorkerThread(boost::bind(&CommunicationManager::start, roadNetworkServer));
    boost::thread workerThread2(boost::bind(&ControlManager::start, ConfigManager::GetInstance().FullConfig().getControlMgr()));
#endif

    //Save start time
    gettimeofday(&start_time, nullptr);

    /**
     * Check whether to run SimMobility or SimMobility-MPI
     */
    ConfigParams& config = ConfigManager::GetInstanceRW().FullConfig();
    config.using_MPI = false;

#ifndef SIMMOB_DISABLE_MPI
    if (args.size()>2 && args[2]=="mpi") {
        config.using_MPI = true;
    }
#endif

    /**
     * set random be repeatable
     */
    config.is_simulation_repeatable = true;

    /**
     * set run mode as short-term
     */
    config.simMobRunMode = ConfigParams::SHORT_TERM;

    /**
     * Start MPI if using_MPI is true
     */
#ifndef SIMMOB_DISABLE_MPI
    if (config.using_MPI)
    {
        PartitionManager& partitionImpl = PartitionManager::instance();
        std::string mpi_result = partitionImpl.startMPIEnvironment(ARGC, ARGV); //NOTE: MPI_Init needs the raw argc/argv.
        if (mpi_result.compare("") != 0)
        {
            Warn() << "MPI Error:" << mpi_result << endl;
            exit(1);
        }

        ShortTermBoundaryProcessor* boundary_processor = new ShortTermBoundaryProcessor();
        partitionImpl.setBoundaryProcessor(boundary_processor);
    }
#endif

    //Perform main loop (this differs for interactive mode)
    int returnVal;
    std::list<std::string> resLogFiles;

    if (ConfigManager::GetInstance().CMakeConfig().InteractiveMode())
    {
        returnVal = run_simmob_interactive_loop();
    }
    else
    {
        returnVal = performMain(configFileName, shortConfigFile, resLogFiles, "XML_OutPut.xml") ? 0 : 1;
    }

    //Concatenate output files?
    if (!resLogFiles.empty())
    {
        resLogFiles.insert(resLogFiles.begin(), config.outNetworkFileName);
        Utils::printAndDeleteLogFiles(resLogFiles,outputFileName);
    }

    int retVal = std::system("rm out_*.txt out.network.txt");

    //Delete the config manager instance
    ConfigManager::DeleteConfigMgrInstance();

    return returnVal;
}


text: #include <boost/accumulators/statistics/extended_p_square_quantile.hpp>

ext: hpp

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
#ifndef BOOST_MPL_ALWAYS_HPP_INCLUDED
#define BOOST_MPL_ALWAYS_HPP_INCLUDED

// Copyright Aleksey Gurtovoy 2001-2004
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/mpl for documentation.

// $Source: /cvsroot/boost/boost/boost/mpl/always.hpp,v $
// $Date: 2004/09/02 15:40:41 $
// $Revision: 1.5 $

#include <boost/mpl/aux_/preprocessor/def_params_tail.hpp>
#include <boost/mpl/aux_/na.hpp>
#include <boost/mpl/aux_/arity_spec.hpp>

namespace boost { namespace mpl {

template< typename Value > struct always
{
    template<
          typename T
        BOOST_MPL_PP_NESTED_DEF_PARAMS_TAIL(1, typename T, na)
        >
    struct apply
    {
        typedef Value type;
    };
};

BOOST_MPL_AUX_ARITY_SPEC(1, always)

}}

#endif // BOOST_MPL_ALWAYS_HPP_INCLUDED

max_stars_repo_name: dstrigl/mcotf

max_issues_repo_name: dstrigl/mcotf

max_forks_repo_name: dstrigl/mcotf


text:
#include <vtkDataArrayCollection.h>
#include <vtkEnSightGoldBinaryReader.h>
#include <vtkEnSightGoldReader.h>
#include <vtkInformation.h>
#include <vtkParticleTracer.h>
#include <vtkPointSource.h>
#include <vtkSmartPointer.h>
#include <vtkStreamingDemandDrivenPipeline.h>
#include <vtkXMLPolyDataWriter.h>

#include <vtkPVOptions.h>
#include <vtkInitializationHelper.h>
#include <vtkProcessModule.h>

#include <vtksys/SystemTools.hxx>

#include <vtkPointData.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>

#include <iostream>
#include <string>
#include <vector>
#include <fstream>

#include <boost/program_options.hpp>
#include <boost/tokenizer.hpp>

using namespace boost;
namespace po = boost::program_options;

#ifdef _cplusplus
extern "C" {
#endif
#include "hdf5.h"
#ifdef _cplusplus
}
#endif

hid_t fileID;
hid_t plist;

/* Initialize hdf5 reading */
void initHDF5(const char * filename)
{
    /* Open the file (Truncate it if it already exists */
    fileID = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);

    /* To enable extendable datasets, we need to enable chunking */
    /* So do the following lines */
    plist = H5Pcreate (H5P_DATASET_CREATE);
    hsize_t chunk_dims[1] = {500};
    H5Pset_layout( plist, H5D_CHUNKED );
    herr_t status = H5Pset_chunk (plist, 1, chunk_dims);
}

/* Finalize hdf5 reading */
void finalizeHDF5()
{
    H5Fclose(fileID);
}

int main(int argc, char ** argv)
{
    /* Parses arguments using boost::program_options */
    po::variables_map vm;

    try {
        po::options_description desc("Allowed options");
        desc.add_options()
            ("help", "produce help message")
            ("input.data.filename", po::value<std::string>(), "Sets the hdf5 output filename.")
            ("input.pointsources.filename", po::value<std::string>()->default_value("points.csv"), "Sets the input point source csv filename (format: pos_x,pos_y,pos_z,radius,nbpoints).")
            ("output.filename", po::value<std::string>()->default_value("/tmp/PT/points.h5"), "Sets the hdf5 output filename.")
            ("output.vtk.enable", po::value<bool>()->default_value(false), "Sets whether to output vtk files or not.")
            ;

        po::store(po::parse_command_line(argc, argv, desc), vm);
        po::notify(vm);

        if (vm.count("help")) {
            std::cout << desc << "\n";
            return 0;
        }
    }
    catch(std::exception& e)
    {
        cout << e.what() << "\n";
        return 1;
    }

    /* Read the info about the point sources */
    /* Data is read from a csv file */
    /* Each line represents: */
    /* position_x, position_y, position_z, radius, number_of_points */
    std::vector<vtkSmartPointer<vtkPointSource> > vps;
    if(vm.count("input.pointsources.filename"))
    {
        /* Open the file given as argument */
        std::ifstream infile(vm["input.pointsources.filename"].as<std::string>().c_str());
        std::string line;
        /* Iterate over the lines in the file */
        while (std::getline(infile, line))
        {
            /* Tokenize the line and store the result in result */
            std::vector<std::string> result;
            typedef boost::tokenizer< boost::escaped_list_separator<char> , std::string::const_iterator, std::string> Tokenizer;
            Tokenizer tok(line);
            result.assign(tok.begin(),tok.end());

            /* Check that we read enough elements */
            if(result.size() < 5)
            {
                std::cout << "Bad entry: " << line << std::endl;
                return 0;
            }

            /* Create a point source for the particle tracer */
            vtkSmartPointer<vtkPointSource> ps = vtkSmartPointer<vtkPointSource>::New();
            ps->SetCenter(boost::lexical_cast<double>(result[0]), boost::lexical_cast<double>(result[1]), boost::lexical_cast<double>(result[2]));
            ps->SetRadius(boost::lexical_cast<double>(result[3]));
            ps->SetNumberOfPoints(boost::lexical_cast<int>(result[4]));

            /* Store it in a vector */
            vps.push_back(ps);
        }
        /* close the file */
        infile.close();
    }
    else
    {
        std::cout << "Input points file was not set (--input.pointsources.filename)" << std::endl;
        return 1;
    }

    /* If we don't have any vtkPointSource data, we exit the application */
    if(vps.size() == 0)
    {
        std::cout << "No input point sources were set (--input.pointsources.filename)" << std::endl;
        return 1;
    }

    /* Initialize ParaView environement */
    /* Needed for the particle tracer */
    static vtkSmartPointer<vtkPVOptions> options = vtkSmartPointer<vtkPVOptions>::New();
    char** execName = new char*[1];
    execName[0] = vtksys::SystemTools::DuplicateString("foobar_string");
    vtkInitializationHelper::Initialize( 1, execName, vtkProcessModule::PROCESS_CLIENT, options );

    /* Read input dataset (Ensight gold format for now) */
    if(! vm.count("input.data.filename"))
    {
        std::cout << "No input data specified (--input.data.filename)" << std::endl;
        return 1;
    }
    vtkSmartPointer<vtkEnSightGoldBinaryReader> egr = vtkEnSightGoldBinaryReader::New();
    //egr->SetCaseFileName("/ssd/ancel/angiotk/pipelines/script_angiotk_phantom/feelpp/export/applications/models/fluid/phantom/np_16/fluid.exports/Export.case");
    egr->SetCaseFileName(vm["input.data.filename"].as<std::string>().c_str());
    egr->Update();

    /* Get Information about input data */
    std::cout << egr->GetTimeValue() << " " << egr->GetMaximumTimeValue() << std::endl;

    vtkDataArrayCollection* dac = egr->GetTimeSets();
    std::cout << dac->GetNumberOfItems() << std::endl;
    dac->InitTraversal();
    vtkDataArray * da = dac->GetNextItem();
    std::cout << da->GetNumberOfTuples() << std::endl;
    //for(int i = 0; i < da->GetNumberOfTuples(); i=i+10)
    //{
        //std::cout << da->GetTuple1(i) << std::endl;
    //}

    std::cout << "Using " << vps.size() << " point sources" << std::endl;

    /* Initialize the particle tracer */
    vtkSmartPointer<vtkParticleTracer> pt = vtkSmartPointer<vtkParticleTracer>::New();
    pt->SetInputConnection(0, egr->GetOutputPort());
    for(int i = 0; i < 1; i++)
    {
        pt->SetInputConnection(i + 1, vps[i]->GetOutputPort());
    }
    pt->SetComputeVorticity(0);
    pt->SetForceReinjectionEveryNSteps(12);

    /* Initialize output file */
    if(vm.count("output.filename"))
    { initHDF5(vm["output.filename"].as<std::string>().c_str()); }
    else
    {
        std::cout << "Output hdf5 file was not set (--output.filename)" << std::endl;
        return 1;
    }

    hsize_t entryDims[1] = {3};
    hsize_t offset[1] = {0};
    hsize_t maxDims[1] = {H5S_UNLIMITED};

    hid_t rootGID = H5Gopen(fileID, "/", H5P_DEFAULT);

    /* Iterate over all the timesteps */
    double t1 = da->GetTuple1(0);
    double t2;
    for(int i = 1; i < da->GetNumberOfTuples(); i++)
    {
        /* Display time information */
        t2 = da->GetTuple1(i);
        t1 = da->GetTuple1(0);
        std::cout << t1 << " -> " << t2 << std::endl;

        pt->SetStartTime(t1);
        pt->SetTerminationTime(t2);
        pt->Update();

        /* Get particle data */
        vtkPolyData * pd = pt->GetOutput();
        //std::cout << pd->GetPoints()->GetNumberOfPoints() << std::endl;

        /* We can also access useful field data in the data */
        vtkDataArray * pids = pd->GetPointData()->GetScalars("ParticleId");
        //if(pids)
        //{
            //std::cout << pids->GetNumberOfComponents() << " " << pids->GetNumberOfTuples() << std::endl;
        //}
        vtkDataArray * page = pd->GetPointData()->GetScalars("ParticleAge");

        /* Enable outputting data to vtk format if required */
        /* Allow the users to check that the particle tracer behaves accordingly */
        if(vm.count("output.vtk.enable"))
        {
            if(vm["output.vtk.enable"].as<bool>())
            {
                std::ostringstream oss;
                oss << "particles." << i << ".vtp";
                vtkSmartPointer<vtkXMLPolyDataWriter> pdw = vtkSmartPointer<vtkXMLPolyDataWriter>::New();
                    pdw->SetInputData(pt->GetOutput());
                    pdw->SetFileName(oss.str().c_str());
                    pdw->Write();
            }
        }

        /* Iterate over the points (each particle) and save the associated data */
        for(int j = 0; j < pd->GetNumberOfPoints(); j++)
        {
            std::ostringstream oss;
            oss << j << std::endl;

            /* Test if the group corresponding to the particle id under the root node exists */
            /* Create it if not */
            hid_t groupID;
            if( H5Lexists( rootGID, oss.str().c_str(), H5P_DEFAULT ) )
            { groupID = H5Gopen(rootGID, oss.str().c_str(), H5P_DEFAULT); }
            else
            { groupID = H5Gcreate(rootGID, oss.str().c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); }

            /* Test if the coords dataset exists for the current particle group */
            /* If not, we create it */
            if(!(H5Lexists( groupID, "coords", H5P_DEFAULT )))
            {
                /* Create a dataspace to store data */
                /* Only store a 3-uple corresponding to the first (x, y, z) coordinates */
                hid_t dataspace = H5Screate_simple(1, entryDims, maxDims);
                hid_t dataset = H5Dcreate(groupID, "coords", H5T_NATIVE_FLOAT, dataspace, H5P_DEFAULT, plist, H5P_DEFAULT);

                /* Get the current point position and store it in the file */
                double * data = pd->GetPoint(j);
                /* Convert data to float (needed by JEMRIS) */
                float fdata[3];
                for(int i = 0; i < 3; i++)
                { fdata[i] = (float)(data[i]); }
                herr_t status = H5Dwrite (dataset, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, fdata);

                /* close all opened objects */
                H5Dclose(dataset);
                H5Sclose(dataspace);
            }
            /* Here we switch to an append mode for the hdf5 file */
            else
            {
                herr_t status;
                /* Open the coords dataset */
                hid_t dataset = H5Dopen(groupID, "coords", H5P_DEFAULT);

                /* Get information about the current dimension of the dataset */
                hsize_t curDims[1];
                hsize_t curMaxDims[1];
                hid_t filespace = H5Dget_space (dataset);
                H5Sget_simple_extent_dims(filespace, curDims, curMaxDims);
                H5Sclose(filespace);

                /* Fill the offset (from where we will be writing) and the current dimensions (to extend the dataset) */
                offset[0] = curDims[0];
                curDims[0] = curDims[0] + entryDims[0];

                /* We extend the dataset and get the new data size */
                status = H5Dset_extent (dataset, curDims);
                filespace = H5Dget_space (dataset);

                /* We select the hyperslab corresponding to the current 3-uple that we want to fill */
                /* with teh previoulsy computed offset */
                status = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, offset, NULL, entryDims, NULL);
                //std::cout << "offset[0]:" << offset[0] << " " << " curDims[0]: " << curDims[0] << " entryDims[0]: " << entryDims[0] << std::endl;

                hid_t memspace = H5Screate_simple(1, entryDims, NULL);

                double * data = pd->GetPoint(j);

                /* Convert data to float (needed by JEMRIS) */
                float fdata[3];
                for(int i = 0; i < 3; i++)
                { fdata[i] = (float)(data[i]); }

                /* Write data to the file */
                status = H5Dwrite(dataset, H5T_NATIVE_FLOAT, memspace, filespace, H5P_DEFAULT, fdata);

                /* Close all unused object */
                H5Sclose(filespace);
                H5Sclose(memspace);

                H5Dclose(dataset);
            }

            /* Check if the starttime dataset exists */
            if(!(H5Lexists( groupID, "starttime", H5P_DEFAULT )))
            {
                /* Store the start time for the current particle */
                /* (Here we are at the point when we first encounter it */
                hsize_t st_dims[1] = {1};
                hsize_t st_max_dims[1] = {1};
                hid_t dataspace = H5Screate_simple(1, st_dims, st_max_dims);
                hid_t dataset = H5Dcreate(groupID, "starttime", H5T_NATIVE_INT, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
                int starttime = 0;
                herr_t status = H5Dwrite (dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &starttime);
                H5Dclose(dataset);
            }

            /* Close the current particle group */
            H5Gclose(groupID);
        }

        t1 = t2;
    }

    finalizeHDF5();

#if 0
    vtkSmartPointer<vtkPolyDataMapper> pdm = vtkSmartPointer<vtkPolyDataMapper>::New();
        pdm->SetInputConnection(pt->GetOutputPort());

    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
        actor->SetMapper(pdm);

    vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
    vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer(renderer);
    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
    renderWindowInteractor->SetRenderWindow(renderWindow);

    renderer->AddActor(actor);
      renderer->SetBackground(1,1,1); //white

        // Render and interact
           renderWindow->Render();
             renderWindowInteractor->Start();
#endif

    //for(int i = 0; i < da->GetNumberOfTuples(); i=i+10)
    //{
        //vtkInformation * info = pt->GetInformation();

        //info->Set(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP(), da->GetTuple1(i));

        //pt->Update();
    //}

	return 0;
}

ext: cpp

max_stars_repo_name: vivabrain/angiotk

max_issues_repo_name: feelpp/angiotk

max_forks_repo_name: feelpp/angiotk


text:
#include <Eigen/Jacobi>
#include <Eigen/SVD>

#include <sphericalsfm/so3.h>
#include <sphericalsfm/spherical_utils.h>

namespace sphericalsfm {
    void make_spherical_essential_matrix( const Eigen::Matrix3d &R, bool inward, Eigen::Matrix3d &E )
    {
        Eigen::Vector3d t( R(0,2), R(1,2), R(2,2)-1 );
        if ( inward ) t = -t;
        E = skew3(t)*R;
    }

    void decompose_spherical_essential_matrix( const Eigen::Matrix3d &E, bool inward, Eigen::Vector3d &r, Eigen::Vector3d &t )
    {
        Eigen::JacobiSVD<Eigen::Matrix3d> svdE(E,Eigen::ComputeFullU|Eigen::ComputeFullV);

        Eigen::Matrix3d U = svdE.matrixU();
        Eigen::Matrix3d V = svdE.matrixV();

        // from theia sfm
        if (U.determinant() < 0) {
            U.col(2) *= -1.0;
        }

        if (V.determinant() < 0) {
            V.col(2) *= -1.0;
        }

        Eigen::Matrix3d D;
        D <<
        0,1,0,
        -1,0,0,
        0,0,1;

        Eigen::Matrix3d DT;
        DT <<
        0,-1,0,
        1,0,0,
        0,0,1;

        Eigen::Matrix3d VT = V.transpose().eval();

        Eigen::Vector3d tu = U.col(2);

        Eigen::Matrix3d R1 = U*D*VT;
        Eigen::Matrix3d R2 = U*DT*VT;

        Eigen::Vector3d t1( R1(0,2), R1(1,2), R1(2,2)-1 );
        Eigen::Vector3d t2( R2(0,2), R2(1,2), R2(2,2)-1 );

        if ( inward ) { t1 = -t1; t2 = -t2; }

        Eigen::Vector3d myt1 = t1/t1.norm();
        Eigen::Vector3d myt2 = t2/t2.norm();

        Eigen::Vector3d r1 = so3ln(R1);
        Eigen::Vector3d r2 = so3ln(R2);

        double score1 = fabs(myt1.dot(tu));
        double score2 = fabs(myt2.dot(tu));

        if ( score1 > score2 ) { r = r1; t = t1; }
        else { r = r2; t = t2; }
    }

    static Eigen::Vector3d triangulateMidpoint( const Eigen::Matrix4d &rel_pose, const Eigen::Vector3d &u, const Eigen::Vector3d &v )
    {
        Eigen::Vector3d cu( 0, 0, 0 );
        Eigen::Vector3d cv( -rel_pose.block<3,3>(0,0).transpose() * rel_pose.block<3,1>(0,3) );

        Eigen::Matrix3d A;
        A <<
        u(0), -v(0), cu(0) - cv(0),
        u(1), -v(1), cu(1) - cv(1),
        u(2), -v(2), cu(2) - cv(2);

        const Eigen::Vector3d soln = A.jacobiSvd( Eigen::ComputeFullV ).matrixV().col(2);
        const double du = soln(0)/soln(2);
        const double dv = soln(1)/soln(2);

        const Eigen::Vector3d Xu = cu + u*du;
        const Eigen::Vector3d Xv = cv + v*dv;

        return (Xu+Xv)*0.5;
    }

    void decompose_spherical_essential_matrix( const Eigen::Matrix3d &E, bool inward,
                     RayPairList::iterator begin, RayPairList::iterator end, const std::vector<bool> &inliers,
                     Eigen::Vector3d &r, Eigen::Vector3d &t )
    {
        Eigen::JacobiSVD<Eigen::Matrix3d> svdE(E,Eigen::ComputeFullU|Eigen::ComputeFullV);

        Eigen::Matrix3d U = svdE.matrixU();
        Eigen::Matrix3d V = svdE.matrixV();

        // from theia sfm
        if (U.determinant() < 0) {
            U.col(2) *= -1.0;
        }

        if (V.determinant() < 0) {
            V.col(2) *= -1.0;
        }

        Eigen::Matrix3d D;
        D <<
        0,1,0,
        -1,0,0,
        0,0,1;

        Eigen::Matrix3d DT;
        DT <<
        0,-1,0,
        1,0,0,
        0,0,1;

        Eigen::Matrix3d VT = V.transpose().eval();

        Eigen::Matrix3d R1 = U*D*VT;
        Eigen::Matrix3d R2 = U*DT*VT;

        Eigen::Vector3d t1( R1(0,2), R1(1,2), (inward) ? R1(2,2)+1 : R1(2,2)-1 );
        Eigen::Vector3d t2( R2(0,2), R2(1,2), (inward) ? R2(2,2)+1 : R2(2,2)-1 );

        Eigen::Vector3d r1 = so3ln(R1);
        Eigen::Vector3d r2 = so3ln(R2);

        double r1test = r1.norm();
        double r2test = r2.norm();

        if ( r2test > M_PI/2 && r1test < M_PI/2 ) { r = r1; t = t1; return; }
        if ( r1test > M_PI/2 && r2test < M_PI/2 ) { r = r2; t = t2; return; }

        Eigen::Matrix4d P1( Eigen::Matrix4d::Identity() );
        Eigen::Matrix4d P2( Eigen::Matrix4d::Identity() );

        P1.block(0,0,3,3) = R1;
        P1.block(0,3,3,1) = t1;

        P2.block(0,0,3,3) = R2;
        P2.block(0,3,3,1) = t2;

        int ninfront1 = 0;
        int ninfront2 = 0;

        int i = 0;
        for ( RayPairList::iterator it = begin; it != end; it++,i++ )
        {
            if ( !inliers[i] ) continue;

            Eigen::Vector3d u = it->first.head(3);
            Eigen::Vector3d v = it->second.head(3);

            Eigen::Vector3d X1 = triangulateMidpoint(P1, u, v);
            Eigen::Vector3d X2 = triangulateMidpoint(P2, u, v);

            if ( X1(2) > 0 ) ninfront1++;
            if ( X2(2) > 0 ) ninfront2++;
        }

        if ( ninfront1 > ninfront2 )
        {
            r = so3ln(R1);
            t = t1;
        }
        else
        {
            r = so3ln(R2);
            t = t2;
        }
    }
}

max_stars_repo_name: jonathanventura/spherical-sfm

max_issues_repo_name: jonathanventura/spherical-sfm

max_forks_repo_name: jonathanventura/spherical-sfm


text:
/**
 * Copyright (c) 2011-2013 Andreas Sembrant
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *  - Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  - Neither the name of the copyright holders nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Andreas Sembrant
 *
 */

#ifndef __SCARPHASE_PERFEVENT_EVENT_HPP
#define __SCARPHASE_PERFEVENT_EVENT_HPP

#include <vector>
#include <signal.h>
#include <stdint.h>
#include <algorithm>

#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <boost/exception/all.hpp>

#include <linux/perf_event.h>

//----------------------------------------------------------------------------//

namespace scarphase {
namespace internal {
namespace util {
namespace perf_event_wrapper {

/**
 * @brief The PerfEventError struct
 */
struct PerfEventError : virtual std::exception, virtual boost::exception { };

/**
 * @brief Group perf events together.
 */
class ChildEvent: public boost::noncopyable //--------------------------------//
{

    /**
     * @brief Set Event as a friend class.
     */
    friend class Event;

public: //--------------------------------------------------------------------//

    /**
     * @brief C-tor for child events.
     * @param[in]  config           The counter config, what to count.
     * @param[in]  type             The perf_event type, HW, RAW, etc
     */
    ChildEvent(uint64_t config, uint32_t type);

    /**
     * @brief D-tor
     */
    ~ChildEvent();

    /**
     * @brief Get the unique kernel identifier.
     */
    uint64_t GetId() const;

    /**
     * @brief Read from the file descriptor.
     * @returns The value read.
     */
    template<typename T>
    T ReadNow();

    /**
     * @brief Read from the file descriptor.
     * @param[out]  value variable to save the read data.
     */
    template<typename T>
    void ReadNow(T &value);

    /**
     * @brief Conviniance function.
     */
    void Start();
    void Stop();

    /**
     * @brief Refresh for another sample.
     */
    void Refresh();

    /**
     * @brief Enable
     */
    void Enable();

    /**
     * @brief Disable
     */
    void Disable();

    /**
     * @brief Reset
     */
    void Reset();

private: //-------------------------------------------------------------------//

    /**
     * Perf event attributes.
     */
    perf_event_attr attr;

    /**
     * The event file descriptor.
     */
    int fd;

    /**
     * Kernel event id.
     */
    uint64_t id;

};

/**
 * @brief Class to handle perf_event.
 */
class Event: public boost::noncopyable //-------------------------------------//
{

public: //--------------------------------------------------------------------//

    enum State {
        UNCONFIGURED,
        CONFIGURED,
        STARTED,
        STOPPED
    };

    /**
     * @brief A callback when an event occur.
     * @param[in]   e The event.
     * @param[in]   v User defind data.
     */
    typedef void (*ProcessEventCallback)(Event *e, void *v, int status);

    /**
     * @brief Shared ptr for the child event.
     */
    typedef boost::shared_ptr<ChildEvent> ChildEventPtr;

    //------------------------------------------------------------------------//
    //

    /**
     * C-tor for leader events
     * @param[in]  tid              Thread id.
     * @param[in]  ctr_config       The counter config, what to count.
     * @param[in]  ctr_type         The perf_event type, HW, RAW, etc
     * @param[in]  sample_period    The sample period to sample with.
     * @param[in]  sample_type      The sample type. sample_type
     */
    Event(pid_t    tid,
          uint64_t ctr_config,
          uint32_t ctr_type,
          uint64_t sample_period,
          uint64_t sample_type);

    /**
     * @brief D-tor.
     */
    ~Event();

    //------------------------------------------------------------------------//
    // Settings

    /**
     * @brief Add an child event to the group.
     */
    void AttachEvent(ChildEventPtr event);

    /**
     * @brief Get the unique kernel identifier.
     */
    uint64_t GetId() const;

    /**
     * @brief Get the unique kernel identifier.
     */
    int GetFd() const;

    /**
     * @brief Get the unique kernel identifier.
     */
    uint64_t GetSamplePeriod() const;

    /**
     * @brief Set frequency instead of sample period.
     */
    void SetSamplePeriod(uint64_t sample_period);

    /**
     * @brief Set pid to monitor.
     * @warning Must be called before configure or it will not have any effects.
     */
    void SetTID(pid_t tid);

    /**
     * @brief Set number of event to wake up after. When SIGIO will be sent.
     */
    void SetWakeup(uint32_t wakeup);

    /**
     * @brief The counter must always be on PMU.
     */
    void SetPinned();

    /**
     * @brief Set frequency instead of sample period.
     */
    void SetFrequency(uint64_t frequency);

    /**
     * @brief Set precise ip.
     *
     * precise_ip:
     *
     *  0 - SAMPLE_IP can have arbitrary skid
     *  1 - SAMPLE_IP must have constant skid
     *  2 - SAMPLE_IP requested to have 0 skid
     *  3 - SAMPLE_IP must have 0 skid
     *
     *  See also PERF_RECORD_MISC_EXACT_IP
     */
    void SetPreciseIp(int precise_ip);

    /**
     * @brief Set number of pages to allocate.
     */
    void SetKernalBufferSize(size_t size);

    /**
     * @brief
     */
    void SetExcludeUser(bool exclude);

    /**
     * @brief
     */
    void SetExcludeKernel(bool exclude);

    /**
     * @brief
     */
    void SetExcludeHyperVisor(bool exclude);

    /**
     * @brief
     */
    void SetExcludeIdle(bool exclude);

    /**
     * @brief Enable sigio so a signal will be generated when event triggers.
     */
    void EnableSigIO();

    /**
     * @brief Enable sigio so a signal will be generated when event triggers.
     */
    void DisableSigIO();

    //------------------------------------------------------------------------//
    // Open and configure event

    /**
     * @brief Start the performance event.
     */
    void Configure();

    /**
     * @brief Reconfigure event.
     */
    void Reconfigure();

    //------------------------------------------------------------------------//
    // Read data from ProcessEvents callback

    /**
     * @brief Get number of bytes that are available in the buffer.
     */
    size_t GetAvailableBytes() const;

    /**
     * @brief Read from the buffer when an event has occured.
     * @returns The value that was read.
     * @throws std::runtime_error if buffer underflow.
     */
    template<typename T>
    T Peak();

    /**
     * @brief Read from the buffer when an event has occured.
     * @param[out]  value variable to save the read data.
     * @throws std::runtime_error if buffer underflow.
     */
    template<typename T>
    void Peak(T &value);

    /**
     * @brief Read from the buffer when an event has occured.
     * @returns The value that was read.
     * @throws std::runtime_error if buffer underflow.
     */
    template<typename T>
    T Read();

    /**
     * @brief Read from the buffer when an event has occured.
     * @param[out]  value variable to save the read data.
     * @throws std::runtime_error if buffer underflow.
     */
    template<typename T>
    void Read(T &value);

    /**
     * @brief Skip n bytes from buffer.
     */
    template<typename T>
    void Skip();

    /**
     * @brief Skip n bytes from buffer.
     * @param[in]   n    Number of bytes to skip.
     */
    void Skip(size_t n);

    //------------------------------------------------------------------------//
    // Read data

    /**
     * @brief Read from the file descriptor.
     * @returns The value read.
     */
    template<typename T>
    T ReadNow();

    /**
     * @brief Read from the file descriptor.
     * @param[out]  value variable to save the read data.
     */
    template<typename T>
    void ReadNow(T &value);

    //------------------------------------------------------------------------//
    // Runtime management

    /**
     * @brief Conviniace function.
     */
    void Start();
    void Stop();

    /**
     * @brief Refresh for attr.wakeup_events samples.
     */
    void Refresh();

    /**
     * @brief Enable
     */
    void Enable();

    /**
     * @brief Disable
     */
    void Disable();

    /**
     * @brief Reset
     */
    void Reset();

    /**
     * @brief Process events in the buffer.
     */
    void ProcessEvents(ProcessEventCallback event_callback,
                       void *event_callback_data);

    //------------------------------------------------------------------------//
    // Settings

    /**
     * @brief Check if signal belongs to event
     * @returns
     */
    bool CheckSignal(int signum, siginfo_t *info, void *uc);

    /**
     * @brief Find the event the signal belongs to.
     */
    static Event* FindEvent(int signum, siginfo_t *info, void *uc);

private: //-------------------------------------------------------------------//

    //------------------------------------------------------------------------//
    // Static

    /**
     * @brief Lookup events from fd.
     */
    static std::vector<Event*> *event_lookup;

    //------------------------------------------------------------------------//
    // Settings

    /**
     * @brief Perf event attributes.
     */
    perf_event_attr attr;

    /**
     * @brief If enable, a signal will be sent when event occures.
     */
    bool enable_sigio;

    /**
     * @brief Number of pages to allocate.
     */
    size_t kernal_buffer_size;

    /**
     * @brief The page size and size.
     */
    size_t page_size, page_mask;

    //------------------------------------------------------------------------//
    // Properties

    /**
     * @brief The event file descriptor.
     */
    int fd;

    /**
     * @brief Kernel event id.
     */
    uint64_t id;

    /**
     * @brief The process/thread id to monitor.
     */
    int tid;

    /**
     * @brief state
     */
    State state;

    /**
     * @brief The child events.
     */
    std::vector<ChildEventPtr> child_events;

    //------------------------------------------------------------------------//
    // Buffer state

    /**
     * @brief Pointer to the header of the buffer.
     */
    struct perf_event_mmap_page *hdr;

    /**
     * @brief Memory buffer.
     */
    uint8_t *data;

    /**
     * @brief The head in the buffer.
     */
    uint64_t data_head, data_tail;

};

} /* namespace perf_event_wrapper */
} /* namespace util */
} /* namespace internal */
} /* namespace scarphase */

//---------------------------------------------------------------------------//
// Inline Definitions                                                        //
//---------------------------------------------------------------------------//

#include <cstring>
#include <errno.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

namespace scarphase {
namespace internal {
namespace util {
namespace perf_event_wrapper {

inline uint64_t
ChildEvent::GetId() const
{
    return id;
}

//----------------------------------------------------------------------------//

template<typename T>
inline T
ChildEvent::ReadNow()
{
    T value;
    ReadNow(value);
    return value;
}

template<typename T>
inline void
ChildEvent::ReadNow(T &value)
{
    // Read value
    if (read(fd, &value, sizeof(T)) == -1)
    {
        BOOST_THROW_EXCEPTION(PerfEventError() <<
                              boost::errinfo_errno(errno) <<
                              boost::errinfo_api_function("read"));
    }

}

//----------------------------------------------------------------------------//

inline void
ChildEvent::Start()
{
    Refresh();
}

inline void
ChildEvent::Stop()
{
    Disable();
}

inline void
ChildEvent::Refresh()
{
    if (ioctl(fd, PERF_EVENT_IOC_REFRESH, 1) == -1)
    {
        BOOST_THROW_EXCEPTION(PerfEventError() <<
                              boost::errinfo_errno(errno) <<
                              boost::errinfo_api_function("ioctl"));
    }
}

inline void
ChildEvent::Enable()
{
    if (ioctl(fd, PERF_EVENT_IOC_ENABLE, 1) == -1)
    {
        BOOST_THROW_EXCEPTION(PerfEventError() <<
                              boost::errinfo_errno(errno) <<
                              boost::errinfo_api_function("ioctl"));
    }
}

inline void
ChildEvent::Disable()
{
    if (ioctl(fd, PERF_EVENT_IOC_DISABLE, 1) == -1)
    {
        BOOST_THROW_EXCEPTION(PerfEventError() <<
                              boost::errinfo_errno(errno) <<
                              boost::errinfo_api_function("ioctl"));
    }
}

inline void
ChildEvent::Reset()
{
    if (ioctl(fd, PERF_EVENT_IOC_RESET, 1) == -1)
    {
        BOOST_THROW_EXCEPTION(PerfEventError() <<
                              boost::errinfo_errno(errno) <<
                              boost::errinfo_api_function("ioctl"));
    }
}

//----------------------------------------------------------------------------//

inline void
Event::AttachEvent(ChildEventPtr event)
{
    // Add the child event
    child_events.push_back(event);

    // Set the attribute to group
    attr.read_format = attr.read_format | PERF_FORMAT_GROUP;
}

//----------------------------------------------------------------------------//

inline uint64_t
Event::GetId() const
{
    return id;
}

inline int
Event::GetFd() const
{
    return fd;
}

inline size_t
Event::GetAvailableBytes() const
{
    return (data_head - data_tail);
}

inline void
Event::SetTID(int pid)
{
    this->tid = pid;
}

inline void
Event::SetWakeup(uint32_t wakeup)
{
    attr.wakeup_events = wakeup;
}

inline void
Event::SetPinned()
{
    attr.pinned = true;
}

inline void
Event::SetFrequency(uint64_t frequency)
{
    attr.freq = true;
    attr.sample_freq = frequency;
}

inline uint64_t
Event::GetSamplePeriod() const
{
    return attr.sample_period;
}

inline void
Event::SetSamplePeriod(uint64_t sample_period)
{
    attr.sample_period = sample_period;

    if (state == UNCONFIGURED)
    {
        attr.freq = false;
    }
    else
    {
        if (ioctl(fd, PERF_EVENT_IOC_PERIOD, &attr.sample_period) == -1)
        {
            BOOST_THROW_EXCEPTION(PerfEventError() <<
                                  boost::errinfo_errno(errno) <<
                                  boost::errinfo_api_function("ioctl"));
        }
    }
}

inline void
Event::SetPreciseIp(int precise_ip = 0)
{
    attr.precise_ip = precise_ip;
}

inline void
Event::SetKernalBufferSize(size_t size)
{
    kernal_buffer_size = size;
    page_mask = (kernal_buffer_size * page_size) - 1;
}

inline void
Event::SetExcludeUser(bool exclude)
{
    attr.exclude_user = exclude;
}

inline void
Event::SetExcludeKernel(bool exclude)
{
    attr.exclude_kernel = exclude;
}

inline void
Event::SetExcludeHyperVisor(bool exclude)
{
    attr.exclude_hv = exclude;
}

inline void
Event::SetExcludeIdle(bool exclude)
{
    attr.exclude_idle = exclude;
}

inline void
Event::EnableSigIO()
{
    enable_sigio = true;
}

inline void
Event::DisableSigIO()
{
    enable_sigio = false;
}

//--------------------------------------------------------------------------//

template<typename T>
inline T
Event::Peak()
{
    T value;
    Peak(value);
    return value;
}

template<typename T>
inline void
Event::Peak(T &value)
{

    // Position of tail within the buffer payload
    uint64_t tail = data_tail & page_mask;

    // Size of what is available
    // data_head, data_tail never wrap around
    BOOST_ASSERT (sizeof(T) <= data_head - data_tail);

    // sz <= avail_sz, we can satisfy the request

    // c = size till end of buffer
    // buffer payload size is necessarily
    // a power of two, so we can do:
    // |           buffer             |
    //                      ^ tail     ^ page_mack + 1
    //                      |     c    |
    size_t c = page_mask + 1 - tail;

    // Min with requested size
    size_t m = std::min(c, sizeof(T));

    // Copy beginning
    std::memcpy((uint8_t*) &value, data + tail, m);

    // Copy wrapped around leftover
    if ((sizeof(T) - m) > 0)
    {
        std::memcpy(((uint8_t*) &value) + m, data, sizeof(T) - m);
    }

}

template<typename T>
inline T
Event::Read()
{
    T value;
    Read(value);
    return value;
}

template<typename T>
inline void
Event::Read(T &value)
{
    // Read value
    value = Peak<T>();

    // Update tail to tell kernel we have read from the buffer.
    data_tail += sizeof(T);
}

//--------------------------------------------------------------------------//

template<typename T>
inline void
Event::Skip()
{
    Skip(sizeof(T));
}

inline void
Event::Skip(size_t n)
{

    if ((data_tail + n) > data_head)
    {
        n = data_head - data_tail;
    }

    data_tail += n;
}

//--------------------------------------------------------------------------//

template<typename T>
inline T
Event::ReadNow()
{
    T value;
    ReadNow(value);
    return value;
}

template<typename T>
inline void
Event::ReadNow(T &value)
{
    // Read value
    if (read(fd, &value, sizeof(T)) == -1)
    {
        BOOST_THROW_EXCEPTION(PerfEventError() <<
                              boost::errinfo_errno(errno) <<
                              boost::errinfo_api_function("read"));
    }

}

//--------------------------------------------------------------------------//

inline void
Event::Start()
{
    (enable_sigio) ? Refresh() : Enable();
}

inline void
Event::Stop()
{
    Disable();
}

inline void
Event::Refresh()
{
    if (ioctl(fd, PERF_EVENT_IOC_REFRESH, attr.wakeup_events) == -1)
    {
        BOOST_THROW_EXCEPTION(PerfEventError() <<
                              boost::errinfo_errno(errno) <<
                              boost::errinfo_api_function("ioctl"));
    }
    state = STARTED;
}

inline void
Event::Enable()
{
    if (ioctl(fd, PERF_EVENT_IOC_ENABLE, 1) == -1)
    {
        BOOST_THROW_EXCEPTION(PerfEventError() <<
                              boost::errinfo_errno(errno) <<
                              boost::errinfo_api_function("ioctl"));
    }
    state = STARTED;
}

inline void
Event::Disable()
{
    if (ioctl(fd, PERF_EVENT_IOC_DISABLE, 1) == -1)
    {
        BOOST_THROW_EXCEPTION(PerfEventError() <<
                              boost::errinfo_errno(errno) <<
                              boost::errinfo_api_function("ioctl"));
    }
    state = STOPPED;
}

inline void
Event::Reset()
{
    if (ioctl(fd, PERF_EVENT_IOC_RESET, 1) == -1)
    {
        BOOST_THROW_EXCEPTION(PerfEventError() <<
                              boost::errinfo_errno(errno) <<
                              boost::errinfo_api_function("ioctl"));
    }
}

//----------------------------------------------------------------------------//

} /* namespace perf_event_wrapper */
} /* namespace util */
} /* namespace internal */
} /* namespace scarphase */

#endif /* __SCARPHASE_PERFEVENT_EVENT_HPP */

max_stars_repo_name: uart/libscarphase

max_issues_repo_name: uart/libscarphase

max_forks_repo_name: uart/libscarphase


text:
// Copyright (c) 2018 The Gulden developers
// Authored by: Malcolm MacLeod (mmacleod@gmx.com)
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "init.h"
#include "chainparams.h"
#include "chain.h"
#include "generation/miner.h"
#include "httprpc.h"
#include "httpserver.h"
#include "net.h"
#include "net_processing.h"
#include "policy/policy.h"
#include "rpc/blockchain.h"
#include "rpc/register.h"
#include "rpc/server.h"
#include "script/sigcache.h"
#include "torcontrol.h"
#include "txdb.h"
#include "ui_interface.h"
#include "util.h"
#include "utilmoneystr.h"
#include "validation/validation.h"
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
#endif
#include "warnings.h"

#include <boost/thread.hpp>

//If we want to translate help messages in future we can replace helptr with _ and everything will just work.
#define helptr(x) std::string(x)
//If we want to translate error messages in future we can replace helptr with _ and everything will just work.
#define errortr(x) std::string(x)

std::string HelpMessage(HelpMessageMode mode)
{
    const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
    const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);
    const auto defaultChainParams = CreateChainParams(CBaseChainParams::MAIN);
    const auto testnetChainParams = CreateChainParams(CBaseChainParams::TESTNET);
    const bool showDebug = GetBoolArg("-help-debug", false);

    // When adding new options to the categories, please keep and ensure alphabetical ordering.
    // Do not translate helptr(...) -help-debug options, Many technical terms, and only a very small audience, so is unnecessary stress to translators.
    std::string strUsage = HelpMessageGroup(helptr("Options:"));
    strUsage += HelpMessageOpt("-?", helptr("Print this help message and exit"));
    strUsage += HelpMessageOpt("-version", helptr("Print version and exit"));
    strUsage += HelpMessageOpt("-alerts", strprintf(helptr("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS));
    strUsage += HelpMessageOpt("-alertnotify=<cmd>", helptr("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)"));
    strUsage += HelpMessageOpt("-blocknotify=<cmd>", helptr("Execute command when the best block changes (%s in cmd is replaced by block hash)"));
    if (showDebug)
        strUsage += HelpMessageOpt("-blocksonly", strprintf(helptr("Whether to operate in a blocks only mode (default: %u)"), DEFAULT_BLOCKSONLY));
    strUsage +=HelpMessageOpt("-assumevalid=<hex>", strprintf(helptr("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)"), defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()));
    strUsage += HelpMessageOpt("-fullsync", strprintf(_("Synchronize the whole chain for full validation mode. If used with SPV the sync will start when SPV if catched up. If disabled, blocks will not be requested automatically (default: %u)"), DEFAULT_FULL_SYNC_MODE));
    strUsage += HelpMessageOpt("-conf=<file>", strprintf(helptr("Specify configuration file (default: %s)"), DEFAULT_CONF_FILENAME));
    if (mode == HMM_GULDEND)
    {
#if HAVE_DECL_FORK
        strUsage += HelpMessageOpt("-daemon", helptr("Run in the background as a daemon and accept commands"));
#endif
    }
    strUsage += HelpMessageOpt("-datadir=<dir>", helptr("Specify data directory"));
    strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(helptr("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
    if (showDebug)
        strUsage += HelpMessageOpt("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER));
    strUsage += HelpMessageOpt("-loadblock=<file>", helptr("Imports blocks from external blk000??.dat file on startup"));
    strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(helptr("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
    strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(helptr("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE));
    strUsage += HelpMessageOpt("-mempoolexpiry=<n>", strprintf(helptr("Do not keep transactions in the mempool longer than <n> hours (default: %u)"), DEFAULT_MEMPOOL_EXPIRY));
    strUsage += HelpMessageOpt("-persistmempool", strprintf(helptr("Whether to save the mempool on shutdown and load on restart (default: %u)"), DEFAULT_PERSIST_MEMPOOL));
    strUsage += HelpMessageOpt("-blockreconstructionextratxn=<n>", strprintf(helptr("Extra transactions to keep in memory for compact block reconstructions (default: %u)"), DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN));
    strUsage += HelpMessageOpt("-par=<n>", strprintf(helptr("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"),
        -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));
#ifndef WIN32
    strUsage += HelpMessageOpt("-pid=<file>", strprintf(helptr("Specify pid file (default: %s)"), DEFAULT_PID_FILENAME));
#endif
    strUsage += HelpMessageOpt("-prune=<n>", strprintf(helptr("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. "
            "Warning: Reverting this setting requires re-downloading the entire blockchain. "
            "(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >%u = automatically prune block files to stay under the specified target size in MiB)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
    strUsage += HelpMessageOpt("-reindex-chainstate", helptr("Rebuild chain state from the currently indexed blocks"));
    strUsage += HelpMessageOpt("-reindex", helptr("Rebuild chain state and block index from the blk*.dat files on disk"));
    strUsage += HelpMessageOpt("-resyncforblockindexupgrade", helptr("In the event that the system requires an expensive block index upgrade, the system will bypass the upgrade in favour of simply doing a complete resync. This might be favourable for unattended devices like pis."));
#ifndef WIN32
    strUsage += HelpMessageOpt("-sysperms", helptr("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)"));
#endif
    strUsage += HelpMessageOpt("-txindex", strprintf(helptr("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), DEFAULT_TXINDEX));

    strUsage += HelpMessageGroup(helptr("Connection options:"));
    strUsage += HelpMessageOpt("-addnode=<ip>", helptr("Add a node to connect to and attempt to keep the connection open"));
    strUsage += HelpMessageOpt("-banscore=<n>", strprintf(helptr("Threshold for disconnecting misbehaving peers (default: %u)"), DEFAULT_BANSCORE_THRESHOLD));
    strUsage += HelpMessageOpt("-bantime=<n>", strprintf(helptr("Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), DEFAULT_MISBEHAVING_BANTIME));
    strUsage += HelpMessageOpt("-bind=<addr>", helptr("Bind to given address and always listen on it. Use [host]:port notation for IPv6"));
    strUsage += HelpMessageOpt("-connect=<ip>", helptr("Connect only to the specified node(s); -connect=0 disables automatic connections"));
    strUsage += HelpMessageOpt("-discover", helptr("Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)"));
    strUsage += HelpMessageOpt("-dns", helptr("Allow DNS lookups for -addnode, -seednode and -connect") + " " + strprintf(helptr("(default: %u)"), DEFAULT_NAME_LOOKUP));
    strUsage += HelpMessageOpt("-dnsseed", helptr("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)"));
    strUsage += HelpMessageOpt("-externalip=<ip>", helptr("Specify your own public address"));
    strUsage += HelpMessageOpt("-forcednsseed", strprintf(helptr("Always query for peer addresses via DNS lookup (default: %u)"), DEFAULT_FORCEDNSSEED));
    strUsage += HelpMessageOpt("-listen", helptr("Accept connections from outside (default: 1 if no -proxy or -connect)"));
    strUsage += HelpMessageOpt("-listenonion", strprintf(helptr("Automatically create Tor hidden service (default: %d)"), DEFAULT_LISTEN_ONION));
    strUsage += HelpMessageOpt("-maxconnections=<n>", strprintf(helptr("Maintain at most <n> connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS));
    strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf(helptr("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXRECEIVEBUFFER));
    strUsage += HelpMessageOpt("-maxsendbuffer=<n>", strprintf(helptr("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXSENDBUFFER));
    strUsage += HelpMessageOpt("-maxtimeadjustment", strprintf(helptr("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)"), DEFAULT_MAX_TIME_ADJUSTMENT));
    strUsage += HelpMessageOpt("-onion=<ip:port>", strprintf(helptr("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy"));
    strUsage += HelpMessageOpt("-onlynet=<net>", helptr("Only connect to nodes in network <net> (ipv4, ipv6 or onion)"));
    strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(helptr("Relay non-P2SH multisig (default: %u)"), DEFAULT_PERMIT_BAREMULTISIG));
    strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(helptr("Support filtering of blocks and transaction with bloom filters (default: %u)"), DEFAULT_PEERBLOOMFILTERS));
    strUsage += HelpMessageOpt("-port=<port>", strprintf(helptr("Listen for connections on <port> (default: %u or testnet: %u)"), defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort()));
    strUsage += HelpMessageOpt("-proxy=<ip:port>", helptr("Connect through SOCKS5 proxy"));
    strUsage += HelpMessageOpt("-proxyrandomize", strprintf(helptr("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE));
    strUsage += HelpMessageOpt("-seednode=<ip>", helptr("Connect to a node to retrieve peer addresses, and disconnect"));
    strUsage += HelpMessageOpt("-timeout=<n>", strprintf(helptr("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT));
    strUsage += HelpMessageOpt("-torcontrol=<ip>:<port>", strprintf(helptr("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL));
    strUsage += HelpMessageOpt("-torpassword=<pass>", helptr("Tor control port password (default: empty)"));
#ifdef USE_UPNP
#if USE_UPNP
    strUsage += HelpMessageOpt("-upnp", helptr("Use UPnP to map the listening port (default: 1 when listening and no -proxy)"));
#else
    strUsage += HelpMessageOpt("-upnp", strprintf(helptr("Use UPnP to map the listening port (default: %u)"), 0));
#endif
#endif
    strUsage += HelpMessageOpt("-whitebind=<addr>", helptr("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6"));
    strUsage += HelpMessageOpt("-whitelist=<IP address or network>", helptr("Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.") +
        " " + helptr("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
    strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(helptr("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET));

#ifdef ENABLE_WALLET
    strUsage += CWallet::GetWalletHelpString(showDebug);
#endif
    strUsage += HelpMessageOpt("-mininput=<amt>", helptr("When creating transactions, ignore inputs with value less than this (default: 0.0001)"));

#if ENABLE_ZMQ
    strUsage += HelpMessageGroup(helptr("ZeroMQ notification options:"));
    strUsage += HelpMessageOpt("-zmqpubhashblock=<address>", helptr("Enable publish hash block in <address>"));
    strUsage += HelpMessageOpt("-zmqpubhashtx=<address>", helptr("Enable publish hash transaction in <address>"));
    strUsage += HelpMessageOpt("-zmqpubrawblock=<address>", helptr("Enable publish raw block in <address>"));
    strUsage += HelpMessageOpt("-zmqpubrawtx=<address>", helptr("Enable publish raw transaction in <address>"));
    strUsage += HelpMessageOpt("-zmqpubwallettx=<address>", helptr("Enable publish wallet transaction in <address>"));
    strUsage += HelpMessageOpt("-zmqpubstalledwitness=<address>", helptr("Enable publish of slow witnesses in <address>"));
#endif

    strUsage += HelpMessageGroup(helptr("Debugging/Testing options:"));
    strUsage += HelpMessageOpt("-uacomment=<cmt>", helptr("Append comment to the user agent string"));
    if (showDebug)
    {
        strUsage += HelpMessageOpt("-checkblocks=<n>", strprintf(helptr("How many blocks to check at startup (default: %u, 0 = all)"), DEFAULT_CHECKBLOCKS));
        strUsage += HelpMessageOpt("-checklevel=<n>", strprintf(helptr("How thorough the block verification of -checkblocks is (0-4, default: %u)"), DEFAULT_CHECKLEVEL));
        strUsage += HelpMessageOpt("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)", defaultChainParams->DefaultConsistencyChecks()));
        strUsage += HelpMessageOpt("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u)", defaultChainParams->DefaultConsistencyChecks()));
        strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED));
        strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", DEFAULT_DISABLE_SAFEMODE));
        strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", DEFAULT_TESTSAFEMODE));
        strUsage += HelpMessageOpt("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages");
        strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", "Randomly fuzz 1 of every <n> network messages");
        strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT));
        strUsage += HelpMessageOpt("-stopatheight", strprintf("Stop running after reaching the given height in the main chain (default: %u)", DEFAULT_STOPATHEIGHT));

        strUsage += HelpMessageOpt("-limitancestorcount=<n>", strprintf("Do not accept transactions if number of in-mempool ancestors is <n> or more (default: %u)", DEFAULT_ANCESTOR_LIMIT));
        strUsage += HelpMessageOpt("-limitancestorsize=<n>", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds <n> kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT));
        strUsage += HelpMessageOpt("-limitdescendantcount=<n>", strprintf("Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT));
        strUsage += HelpMessageOpt("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT));
        strUsage += HelpMessageOpt("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest-only)");
    }
    strUsage += HelpMessageOpt("-debug=<category>", strprintf(helptr("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
        helptr("If <category> is not supplied or if <category> = 1, output all debugging information.") + " " + helptr("<category> can be:") + " " + ListLogCategories() + ".");
    strUsage += HelpMessageOpt("-debugexclude=<category>", strprintf(helptr("Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories.")));
    strUsage += HelpMessageOpt("-gen", strprintf(helptr("Generate coins (default: %u)"), DEFAULT_GENERATE));
    strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(helptr("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), DEFAULT_GENERATE_THREADS));
    strUsage += HelpMessageOpt("-genarenaproclimit=<n>", strprintf(helptr("Set the number of threads for arena setup potrion of coin generation if enabled (-1 = all cores, default: %d)"), DEFAULT_GENERATE_THREADS));
    strUsage += HelpMessageOpt("-help-debug", helptr("Show all debugging options (usage: --help -help-debug)"));
    strUsage += HelpMessageOpt("-logips", strprintf(helptr("Include IP addresses in debug output (default: %u)"), DEFAULT_LOGIPS));
    strUsage += HelpMessageOpt("-logtimestamps", strprintf(helptr("Prepend debug output with timestamp (default: %u)"), DEFAULT_LOGTIMESTAMPS));
    if (showDebug)
    {
        strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS));
        strUsage += HelpMessageOpt("-mocktime=<n>", "Replace actual time with <n> seconds since epoch (default: 0)");
        strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE));
        strUsage += HelpMessageOpt("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE));
    }
    strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(helptr("Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)"),
        CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)));
    strUsage += HelpMessageOpt("-printtoconsole", helptr("Send trace/debug info to console instead of debug.log file"));
    if (showDebug)
    {
        strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY));
    }
    strUsage += HelpMessageOpt("-shrinkdebugfile", helptr("Shrink debug.log file on client startup (default: 1 when no -debug)"));

    AppendParamsHelpMessages(strUsage, showDebug);

    strUsage += HelpMessageGroup(helptr("Node relay options:"));
    if (showDebug) {
        strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", defaultChainParams->RequireStandard()));
        strUsage += HelpMessageOpt("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)));
        strUsage += HelpMessageOpt("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost about 1/3 of its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)));
    }
    strUsage += HelpMessageOpt("-bytespersigop", strprintf(helptr("Equivalent bytes per sigop in transactions for relay and mining (default: %u)"), DEFAULT_BYTES_PER_SIGOP));
    strUsage += HelpMessageOpt("-datacarrier", strprintf(helptr("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER));
    strUsage += HelpMessageOpt("-datacarriersize", strprintf(helptr("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY));
    strUsage += HelpMessageOpt("-mempoolreplacement", strprintf(helptr("Enable transaction replacement in the memory pool (default: %u)"), DEFAULT_ENABLE_REPLACEMENT));
    strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(helptr("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)"),
        CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)));
    strUsage += HelpMessageOpt("-whitelistrelay", strprintf(helptr("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY));
    strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(helptr("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY));

    strUsage += HelpMessageGroup(helptr("Block generation options:"));
    strUsage += HelpMessageOpt("-blockmaxweight=<n>", strprintf(helptr("Set maximum BIP141 block weight (default: %d)"), DEFAULT_BLOCK_MAX_WEIGHT));
    strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(helptr("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE));
    strUsage += HelpMessageOpt("-blockmintxfee=<amt>", strprintf(helptr("Set lowest fee rate (in %s/kB) for transactions to be included in block generation. (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)));
    if (showDebug)
        strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios");

    strUsage += HelpMessageGroup(helptr("RPC server options:"));
    strUsage += HelpMessageOpt("-server", helptr("Accept command line and JSON-RPC commands"));
    strUsage += HelpMessageOpt("-rest", strprintf(helptr("Accept public REST requests (default: %u)"), DEFAULT_REST_ENABLE));
    strUsage += HelpMessageOpt("-rpcbind=<addr>[:port]", helptr("Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)"));
    strUsage += HelpMessageOpt("-rpccookiefile=<loc>", helptr("Location of the auth cookie (default: data dir)"));
    strUsage += HelpMessageOpt("-rpcuser=<user>", helptr("Username for JSON-RPC connections"));
    strUsage += HelpMessageOpt("-rpcpassword=<pw>", helptr("Password for JSON-RPC connections"));
    strUsage += HelpMessageOpt("-rpcauth=<userpw>", helptr("Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times"));
    strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(helptr("Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"), defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()));
    strUsage += HelpMessageOpt("-rpcallowip=<ip>", helptr("Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times"));
    strUsage += HelpMessageOpt("-rpcthreads=<n>", strprintf(helptr("Set the number of threads to service RPC calls (default: %d)"), DEFAULT_HTTP_THREADS));

    strUsage += HelpMessageGroup(helptr("Developer options:"));
    strUsage += HelpMessageOpt("-genkeypair", helptr("Generate a random public/private keypair for use with alert system and other similar functionality."));
    strUsage += HelpMessageOpt("-setwindowtitle", helptr("Change the window title name, useful for distinguishing multiple program instances during testing."));
    strUsage += HelpMessageOpt("-coinbasesignature", helptr("Insert value into coinbase of generated blocks, useful during testing."));
    strUsage += HelpMessageOpt("-accountpool", helptr("Use to increase the default account pool look ahead size. (Needed in some cases to find accounts on rescan when large account gaps are present)"));
    //fixme: (UNITY) (SPV) decide if we want to keep this option
    strUsage += HelpMessageOpt("-phrase=<phrase>", _("When creating a new wallet use this phrase. Useful for repeatedly starting fresh with the same seed when testing SPV"));

    if (showDebug) {
        strUsage += HelpMessageOpt("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE));
        strUsage += HelpMessageOpt("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT));
    }

    return strUsage;
}

void InitRegisterRPC()
{
    RegisterAllCoreRPCCommands(tableRPC);
    #ifdef ENABLE_WALLET
        RegisterWalletRPCCommands(tableRPC);
    #endif
}
void ServerInterrupt(boost::thread_group& threadGroup)
{
    InterruptHTTPServer();
    InterruptHTTPRPC();
    InterruptRPC();
    InterruptREST();
    InterruptTorControl();
}

void ServerShutdown(boost::thread_group& threadGroup)
{
    StopHTTPServer();
    StopHTTPRPC();
    MilliSleep(20); //Allow other threads (UI etc. a chance to cleanup as well)
    StopRPC();
    StopREST();
    MilliSleep(20); //Allow other threads (UI etc. a chance to cleanup as well)
    StopTorControl();
}

static void OnRPCStarted()
{
    uiInterface.NotifyBlockTip.connect(&RPCNotifyBlockChange);
}

static void OnRPCStopped()
{
    uiInterface.NotifyBlockTip.disconnect(&RPCNotifyBlockChange);
    RPCNotifyBlockChange(false, nullptr);
    cvBlockChange.notify_all();
    LogPrint(BCLog::RPC, "RPC stopped.\n");
}

static void OnRPCPreCommand(const CRPCCommand& cmd)
{
    // Observe safe mode
    std::string strWarning = GetWarnings("rpc");
    if (strWarning != "" && !GetBoolArg("-disablesafemode", DEFAULT_DISABLE_SAFEMODE) &&
        !cmd.okSafeMode)
        throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string("Safe mode: ") + strWarning);
}

static bool AppInitServers(boost::thread_group& threadGroup)
{
    RPCServer::OnStarted(&OnRPCStarted);
    RPCServer::OnStopped(&OnRPCStopped);
    RPCServer::OnPreCommand(&OnRPCPreCommand);
    if (!InitHTTPServer())
        return false;
    if (!StartRPC())
        return false;
    if (!StartHTTPRPC())
        return false;
    if (GetBoolArg("-rest", DEFAULT_REST_ENABLE) && !StartREST())
        return false;
    if (!StartHTTPServer())
        return false;
    return true;
}

bool InitRPCWarmup(boost::thread_group& threadGroup)
{
    if (GetBoolArg("-server", false))
    {
        uiInterface.InitMessage.connect(SetRPCWarmupStatus);
        if (!AppInitServers(threadGroup))
            return InitError(errortr("Unable to start HTTP server. See debug log for details."));
    }
    return true;
}

bool InitTor(boost::thread_group& threadGroup, CScheduler& scheduler)
{
    if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
        StartTorControl(threadGroup, scheduler);
    return true;
}

max_stars_repo_name: orobio/gulden-official

max_issues_repo_name: orobio/gulden-official

max_forks_repo_name: orobio/gulden-official