<commit_before>/* Copyright (c) 2009-2014 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/**
 * \file
 * This file provides the main program for RAMCloud storage servers.
 */

#include "Context.h"
#include "CoordinatorSession.h"
#if INFINIBAND
#include "InfRcTransport.h"
#endif
#include "OptionParser.h"
#include "PortAlarm.h"
#include "Server.h"
#include "ShortMacros.h"
#include "TransportManager.h"

int
main(int argc, char *argv[])
{
    using namespace RAMCloud;
    Logger::installCrashBacktraceHandlers();
    Context context(true);
    try {
        ServerConfig config = ServerConfig::forExecution();
        string masterTotalMemory, hashTableMemory;

        bool masterOnly;
        bool backupOnly;

        OptionsDescription serverOptions("Server");
        serverOptions.add_options()
            ("backupInMemory,m",
             ProgramOptions::bool_switch(&config.backup.inMemory),
             "Backup will store segment replicas in memory")
            ("backupOnly,B",
             ProgramOptions::bool_switch(&backupOnly),
             "The server should run the backup service only (no master)")
            ("backupStrategy",
             ProgramOptions::value<int>(&config.backup.strategy)->
               default_value(RANDOM_REFINE_AVG),
             "0 random refine min, 1 random refine avg, 2 even distribution, "
             "3 uniform random")
            ("cleanerBalancer",
             ProgramOptions::value<string>(&config.master.cleanerBalancer)->
                default_value("tombstoneRatio:0.40"),
             "Which balancing algorithm to use to schedule cleaning on disk "
             "and in-memory compaction, as well as how to orchestrate multiple "
             "cleaner threads. You will almost certainly want to use the "
             "default value. Currently the only other option is \"fixed:X\", "
             "where 0 <= X <= 100 represents the percentage of CPU time the "
             "disk cleaner will be limited to (the rest is for compaction).")
            ("disableLogCleaner,d",
             ProgramOptions::bool_switch(&config.master.disableLogCleaner),
             "Disable the log cleaner entirely. You will eventually run out "
             "of memory, but at least you can do so faster this way.")
            ("disableInMemoryCleaning,D",
             ProgramOptions::bool_switch(
                &config.master.disableInMemoryCleaning),
             "Disable the in-memory cleaning portion of the log cleaner. When "
             "turned off, the cleaner will always clean both in memory and on "
             "backup disks at the same time.")
            ("diskExpansionFactor,E",
             ProgramOptions::value<double>(&config.master.diskExpansionFactor)->
                default_value(2.0),
             "Factor (>= 1.0) controlling how much backup disk space this "
             "master will use beyond its in-memory log size. For example, if "
             "the master has memory for 100 full segments and the expansion "
             "factor is 2.0, it will place up to 200 segments (each replicated "
             "R times) on backups.")
            ("file,f",
             ProgramOptions::value<string>(&config.backup.file)->
                default_value("/var/tmp/backup.log"),
             "The file path to the backup storage.")
            ("hashTableMemory,h",
             ProgramOptions::value<string>(&hashTableMemory)->
                default_value("10%"),
             "Percentage or megabytes of master memory allocated to "
             "the hash table")
            ("masterOnly,M",
             ProgramOptions::bool_switch(&masterOnly),
             "The server should run the master service only (no backup)")
            ("totalMasterMemory,t",

             // Note: we have tried changing the default value below to
             // something that would make sense in production (80%?), but
             // as of 6/2014 that causes too many problems in test and
             // development environments (e.g. hooks/pre-commit will take
             // forever, and if two people do this, rcmaster will run out
             // of memory).
             ProgramOptions::value<string>(&masterTotalMemory)->
                default_value("500"),
             "Percentage or megabytes of system memory for master log & "
             "hash table")
            ("replicas,r",
             ProgramOptions::value<uint32_t>(&config.master.numReplicas)->
                default_value(0),
             "Number of backup copies to make for each segment")
            ("useMinCopysets",
             ProgramOptions::value<bool>(&config.master.useMinCopysets)->
                default_value(false),
             "Whether to use MinCopysets or random replication")
            ("allowLocalBackup",
             ProgramOptions::bool_switch(&config.master.allowLocalBackup),
             "Allow replication to local backup")
            ("segmentFrames",
             ProgramOptions::value<uint32_t>(&config.backup.numSegmentFrames)->
                default_value(512),
             "Number of segment frames in backup storage")
            ("maxNonVolatileBuffers",
             ProgramOptions::value<uint32_t>(
               &config.backup.maxNonVolatileBuffers)->default_value(0),
             "Maximum number of segments the backup will buffer in memory. The "
             "0 value (default) is special: it tells the server to set the "
             "limit equal to the \"segmentFrames\" value, effectively making "
             "buffering unlimited.")
            ("detectFailures",
             ProgramOptions::value<bool>(&config.detectFailures)->
                default_value(true),
             "Whether to use the randomized failure detector")
            ("writeCostThreshold,w",
             ProgramOptions::value<uint32_t>(
                &config.master.cleanerWriteCostThreshold)->default_value(8),
             "If in-memory cleaning is enabled, do disk cleaning when the "
             "write cost of memory freed by the in-memory cleaner exceeds "
             "this value. Lower values cause the disk cleaner to run more "
             "frequently. Higher values do more in-memory cleaning and "
             "reduce the amount of backup disk bandwidth used during disk "
             "cleaning.")
            ("sync",
             ProgramOptions::bool_switch(&config.backup.sync),
             "Make all updates completely synchronous all the way down to "
             "stable storage.")
            ("masterServiceThreads",
             ProgramOptions::value<uint32_t>(
                &config.master.masterServiceThreadCount)->default_value(5),
             "The number of threads in MasterService determines the maximum "
             "number of client RPCs that may be processed in parallel. "
             "Increasing this value will use more cores and may improve client "
             "throuphput, especially for reads.")
            ("logCleanerThreads",
             ProgramOptions::value<uint32_t>(
                &config.master.cleanerThreadCount)->default_value(1),
             "The number of cleaner threads controls the amount of parallelism "
             "in the cleaner. More threads will use more cores, but may be "
             "able to better keep up with high write rates.")
            ("backupWriteRateLimit",
             ProgramOptions::value<size_t>(
                &config.backup.writeRateLimit)->default_value(0),
             "If non-0, specifies the maximum number of megabytes per second "
             "of bandwidth this backup should use. Useful for artificially "
             "restricting bandwidth when measuring various parts of the "
             "system.");

        OptionParser optionParser(serverOptions, argc, argv);

        // Log all the command-line arguments.
        string args;
        for (int i = 0; i < argc; i++) {
            if (i != 0)
                args.append(" ");
            args.append(argv[i]);
        }
        LOG(NOTICE, "Command line: %s", args.c_str());

        if (masterOnly && backupOnly)
            DIE("Can't specify both -B and -M options");

        if (masterOnly) {
            config.services = {WireFormat::MASTER_SERVICE,
                               WireFormat::MEMBERSHIP_SERVICE,
                               WireFormat::PING_SERVICE};
        } else if (backupOnly) {
            config.services = {WireFormat::BACKUP_SERVICE,
                               WireFormat::MEMBERSHIP_SERVICE,
                               WireFormat::PING_SERVICE};
        } else {
            config.services = {WireFormat::MASTER_SERVICE,
                               WireFormat::BACKUP_SERVICE,
                               WireFormat::MEMBERSHIP_SERVICE,
                               WireFormat::PING_SERVICE};
        }

        const string localLocator = optionParser.options.getLocalLocator();

#if INFINIBAND
        InfRcTransport::setName(localLocator.c_str());
#endif
        context.transportManager->setSessionTimeout(
                optionParser.options.getSessionTimeout());
        context.transportManager->initialize(localLocator.c_str());
        // Transports may augment the local locator somewhat.
        // Make sure the server is aware of that augmented locator.
        config.localLocator =
            context.transportManager->getListeningLocatorsString();
        LOG(NOTICE, "%s: Listening on %s",
            config.services.toString().c_str(), config.localLocator.c_str());

        config.coordinatorLocator =
            optionParser.options.getExternalStorageLocator();
        if (config.coordinatorLocator.size() == 0) {
            config.coordinatorLocator =
                optionParser.options.getCoordinatorLocator();
        }
        config.clusterName = optionParser.options.getClusterName();
        context.coordinatorSession->setLocation(
                config.coordinatorLocator.c_str(),
                config.clusterName.c_str());

        if (!backupOnly) {
            LOG(NOTICE, "Using %u backups", config.master.numReplicas);
            config.setLogAndHashTableSize(masterTotalMemory, hashTableMemory);
        }

        // Set PortTimeout and start portTimer
        LOG(NOTICE, "PortTimeOut=%d", optionParser.options.getPortTimeout());
        context.portAlarmTimer->setPortTimeout(
            optionParser.options.getPortTimeout());

        Server server(&context, &config);
        server.run(); // Never returns except for exceptions.

        return 0;
    } catch (const Exception& e) {
        LOG(ERROR, "Fatal error in server at %s: %s",
            context.transportManager->getListeningLocatorsString().c_str(),
            e.what());
        return 1;
    } catch (const std::exception& e) {
        LOG(ERROR, "Fatal error in server at %s: %s",
            context.transportManager->getListeningLocatorsString().c_str(),
            e.what());
        return 1;
    } catch (...) {
        LOG(ERROR, "Unknown fatal error in server at %s",
            context.transportManager->getListeningLocatorsString().c_str());
        return 1;
    }
}
<commit_msg>Changed default number of master service threads from 5 to 3 (5 is too many for optimum performance in our cluster).<commit_after>/* Copyright (c) 2009-2014 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/**
 * \file
 * This file provides the main program for RAMCloud storage servers.
 */

#include "Context.h"
#include "CoordinatorSession.h"
#if INFINIBAND
#include "InfRcTransport.h"
#endif
#include "OptionParser.h"
#include "PortAlarm.h"
#include "Server.h"
#include "ShortMacros.h"
#include "TransportManager.h"

int
main(int argc, char *argv[])
{
    using namespace RAMCloud;
    Logger::installCrashBacktraceHandlers();
    Context context(true);
    try {
        ServerConfig config = ServerConfig::forExecution();
        string masterTotalMemory, hashTableMemory;

        bool masterOnly;
        bool backupOnly;

        OptionsDescription serverOptions("Server");
        serverOptions.add_options()
            ("backupInMemory,m",
             ProgramOptions::bool_switch(&config.backup.inMemory),
             "Backup will store segment replicas in memory")
            ("backupOnly,B",
             ProgramOptions::bool_switch(&backupOnly),
             "The server should run the backup service only (no master)")
            ("backupStrategy",
             ProgramOptions::value<int>(&config.backup.strategy)->
               default_value(RANDOM_REFINE_AVG),
             "0 random refine min, 1 random refine avg, 2 even distribution, "
             "3 uniform random")
            ("cleanerBalancer",
             ProgramOptions::value<string>(&config.master.cleanerBalancer)->
                default_value("tombstoneRatio:0.40"),
             "Which balancing algorithm to use to schedule cleaning on disk "
             "and in-memory compaction, as well as how to orchestrate multiple "
             "cleaner threads. You will almost certainly want to use the "
             "default value. Currently the only other option is \"fixed:X\", "
             "where 0 <= X <= 100 represents the percentage of CPU time the "
             "disk cleaner will be limited to (the rest is for compaction).")
            ("disableLogCleaner,d",
             ProgramOptions::bool_switch(&config.master.disableLogCleaner),
             "Disable the log cleaner entirely. You will eventually run out "
             "of memory, but at least you can do so faster this way.")
            ("disableInMemoryCleaning,D",
             ProgramOptions::bool_switch(
                &config.master.disableInMemoryCleaning),
             "Disable the in-memory cleaning portion of the log cleaner. When "
             "turned off, the cleaner will always clean both in memory and on "
             "backup disks at the same time.")
            ("diskExpansionFactor,E",
             ProgramOptions::value<double>(&config.master.diskExpansionFactor)->
                default_value(2.0),
             "Factor (>= 1.0) controlling how much backup disk space this "
             "master will use beyond its in-memory log size. For example, if "
             "the master has memory for 100 full segments and the expansion "
             "factor is 2.0, it will place up to 200 segments (each replicated "
             "R times) on backups.")
            ("file,f",
             ProgramOptions::value<string>(&config.backup.file)->
                default_value("/var/tmp/backup.log"),
             "The file path to the backup storage.")
            ("hashTableMemory,h",
             ProgramOptions::value<string>(&hashTableMemory)->
                default_value("10%"),
             "Percentage or megabytes of master memory allocated to "
             "the hash table")
            ("masterOnly,M",
             ProgramOptions::bool_switch(&masterOnly),
             "The server should run the master service only (no backup)")
            ("totalMasterMemory,t",

             // Note: we have tried changing the default value below to
             // something that would make sense in production (80%?), but
             // as of 6/2014 that causes too many problems in test and
             // development environments (e.g. hooks/pre-commit will take
             // forever, and if two people do this, rcmaster will run out
             // of memory).
             ProgramOptions::value<string>(&masterTotalMemory)->
                default_value("500"),
             "Percentage or megabytes of system memory for master log & "
             "hash table")
            ("replicas,r",
             ProgramOptions::value<uint32_t>(&config.master.numReplicas)->
                default_value(0),
             "Number of backup copies to make for each segment")
            ("useMinCopysets",
             ProgramOptions::value<bool>(&config.master.useMinCopysets)->
                default_value(false),
             "Whether to use MinCopysets or random replication")
            ("allowLocalBackup",
             ProgramOptions::bool_switch(&config.master.allowLocalBackup),
             "Allow replication to local backup")
            ("segmentFrames",
             ProgramOptions::value<uint32_t>(&config.backup.numSegmentFrames)->
                default_value(512),
             "Number of segment frames in backup storage")
            ("maxNonVolatileBuffers",
             ProgramOptions::value<uint32_t>(
               &config.backup.maxNonVolatileBuffers)->default_value(0),
             "Maximum number of segments the backup will buffer in memory. The "
             "0 value (default) is special: it tells the server to set the "
             "limit equal to the \"segmentFrames\" value, effectively making "
             "buffering unlimited.")
            ("detectFailures",
             ProgramOptions::value<bool>(&config.detectFailures)->
                default_value(true),
             "Whether to use the randomized failure detector")
            ("writeCostThreshold,w",
             ProgramOptions::value<uint32_t>(
                &config.master.cleanerWriteCostThreshold)->default_value(8),
             "If in-memory cleaning is enabled, do disk cleaning when the "
             "write cost of memory freed by the in-memory cleaner exceeds "
             "this value. Lower values cause the disk cleaner to run more "
             "frequently. Higher values do more in-memory cleaning and "
             "reduce the amount of backup disk bandwidth used during disk "
             "cleaning.")
            ("sync",
             ProgramOptions::bool_switch(&config.backup.sync),
             "Make all updates completely synchronous all the way down to "
             "stable storage.")
            ("masterServiceThreads",
             ProgramOptions::value<uint32_t>(
                &config.master.masterServiceThreadCount)->default_value(3),
             "The number of threads in MasterService determines the maximum "
             "number of client RPCs that may be processed in parallel. "
             "Increasing this value will use more cores and may improve client "
             "throuphput, especially for reads.")
            ("logCleanerThreads",
             ProgramOptions::value<uint32_t>(
                &config.master.cleanerThreadCount)->default_value(1),
             "The number of cleaner threads controls the amount of parallelism "
             "in the cleaner. More threads will use more cores, but may be "
             "able to better keep up with high write rates.")
            ("backupWriteRateLimit",
             ProgramOptions::value<size_t>(
                &config.backup.writeRateLimit)->default_value(0),
             "If non-0, specifies the maximum number of megabytes per second "
             "of bandwidth this backup should use. Useful for artificially "
             "restricting bandwidth when measuring various parts of the "
             "system.");

        OptionParser optionParser(serverOptions, argc, argv);

        // Log all the command-line arguments.
        string args;
        for (int i = 0; i < argc; i++) {
            if (i != 0)
                args.append(" ");
            args.append(argv[i]);
        }
        LOG(NOTICE, "Command line: %s", args.c_str());

        if (masterOnly && backupOnly)
            DIE("Can't specify both -B and -M options");

        if (masterOnly) {
            config.services = {WireFormat::MASTER_SERVICE,
                               WireFormat::MEMBERSHIP_SERVICE,
                               WireFormat::PING_SERVICE};
        } else if (backupOnly) {
            config.services = {WireFormat::BACKUP_SERVICE,
                               WireFormat::MEMBERSHIP_SERVICE,
                               WireFormat::PING_SERVICE};
        } else {
            config.services = {WireFormat::MASTER_SERVICE,
                               WireFormat::BACKUP_SERVICE,
                               WireFormat::MEMBERSHIP_SERVICE,
                               WireFormat::PING_SERVICE};
        }

        const string localLocator = optionParser.options.getLocalLocator();

#if INFINIBAND
        InfRcTransport::setName(localLocator.c_str());
#endif
        context.transportManager->setSessionTimeout(
                optionParser.options.getSessionTimeout());
        context.transportManager->initialize(localLocator.c_str());
        // Transports may augment the local locator somewhat.
        // Make sure the server is aware of that augmented locator.
        config.localLocator =
            context.transportManager->getListeningLocatorsString();
        LOG(NOTICE, "%s: Listening on %s",
            config.services.toString().c_str(), config.localLocator.c_str());

        config.coordinatorLocator =
            optionParser.options.getExternalStorageLocator();
        if (config.coordinatorLocator.size() == 0) {
            config.coordinatorLocator =
                optionParser.options.getCoordinatorLocator();
        }
        config.clusterName = optionParser.options.getClusterName();
        context.coordinatorSession->setLocation(
                config.coordinatorLocator.c_str(),
                config.clusterName.c_str());

        if (!backupOnly) {
            LOG(NOTICE, "Using %u backups", config.master.numReplicas);
            config.setLogAndHashTableSize(masterTotalMemory, hashTableMemory);
        }

        // Set PortTimeout and start portTimer
        LOG(NOTICE, "PortTimeOut=%d", optionParser.options.getPortTimeout());
        context.portAlarmTimer->setPortTimeout(
            optionParser.options.getPortTimeout());

        Server server(&context, &config);
        server.run(); // Never returns except for exceptions.

        return 0;
    } catch (const Exception& e) {
        LOG(ERROR, "Fatal error in server at %s: %s",
            context.transportManager->getListeningLocatorsString().c_str(),
            e.what());
        return 1;
    } catch (const std::exception& e) {
        LOG(ERROR, "Fatal error in server at %s: %s",
            context.transportManager->getListeningLocatorsString().c_str(),
            e.what());
        return 1;
    } catch (...) {
        LOG(ERROR, "Unknown fatal error in server at %s",
            context.transportManager->getListeningLocatorsString().c_str());
        return 1;
    }
}
<|endoftext|>


<commit_before>#include "app.hpp"

namespace rack {

void Light::draw(NVGcontext *vg) {
	float radius = box.size.x / 2.0;
	float oradius = radius + 40.0;

	// Solid
	nvgBeginPath(vg);
	nvgCircle(vg, radius, radius, radius);
	nvgFillColor(vg, bgColor);
	nvgFill(vg);

	// Border
	nvgStrokeWidth(vg, 1.0);
	NVGcolor borderColor = bgColor;
	borderColor.a *= 0.5;
	nvgStrokeColor(vg, borderColor);
	nvgStroke(vg);

	// Inner glow
	nvgGlobalCompositeOperation(vg, NVG_LIGHTER);
	nvgFillColor(vg, color);
	nvgFill(vg);

	// Outer glow
	nvgBeginPath(vg);
	nvgRect(vg, radius - oradius, radius - oradius, 2*oradius, 2*oradius);
	NVGpaint paint;
	NVGcolor icol = color;
	icol.a *= 0.15;
	NVGcolor ocol = color;
	ocol.a = 0.0;
	paint = nvgRadialGradient(vg, radius, radius, radius, oradius, icol, ocol);
	nvgFillPaint(vg, paint);
	nvgFill(vg);
}

} // namespace rack
<commit_msg>Reduce Light radius<commit_after>#include "app.hpp"

namespace rack {

void Light::draw(NVGcontext *vg) {
	float radius = box.size.x / 2.0;
	float oradius = radius + 20.0;

	// Solid
	nvgBeginPath(vg);
	nvgCircle(vg, radius, radius, radius);
	nvgFillColor(vg, bgColor);
	nvgFill(vg);

	// Border
	nvgStrokeWidth(vg, 1.0);
	NVGcolor borderColor = bgColor;
	borderColor.a *= 0.5;
	nvgStrokeColor(vg, borderColor);
	nvgStroke(vg);

	// Inner glow
	nvgGlobalCompositeOperation(vg, NVG_LIGHTER);
	nvgFillColor(vg, color);
	nvgFill(vg);

	// Outer glow
	nvgBeginPath(vg);
	nvgRect(vg, radius - oradius, radius - oradius, 2*oradius, 2*oradius);
	NVGpaint paint;
	NVGcolor icol = color;
	icol.a *= 0.15;
	NVGcolor ocol = color;
	ocol.a = 0.0;
	paint = nvgRadialGradient(vg, radius, radius, radius, oradius, icol, ocol);
	nvgFillPaint(vg, paint);
	nvgFill(vg);
}

} // namespace rack
<|endoftext|>


<commit_before>#include <glibmm/i18n.h>
#include <iostream>

#include "page.h"
using namespace AhoViewer::Booru;

#include "curler.h"
#include "image.h"
#include "settings.h"

Page::Page(Gtk::Menu *menu)
  : Gtk::ScrolledWindow(),
    m_PopupMenu(menu),
    m_ImageFetcher(std::unique_ptr<ImageFetcher>(new ImageFetcher())),
    m_IconView(Gtk::manage(new Gtk::IconView())),
    m_Tab(Gtk::manage(new Gtk::EventBox())),
    m_TabIcon(Gtk::manage(new Gtk::Image(Gtk::Stock::NEW, Gtk::ICON_SIZE_MENU))),
    m_TabLabel(Gtk::manage(new Gtk::Label(_("New Tab")))),
    m_TabButton(Gtk::manage(new Gtk::Button())),
    m_ImageList(std::make_shared<ImageList>(this)),
    m_Page(0),
    m_NumPosts(0),
    m_LastPage(false),
    m_Saving(false),
    m_SaveCancel(Gio::Cancellable::create()),
    m_GetPostsThread(nullptr),
    m_SaveImagesThread(nullptr)
{
    set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
    set_shadow_type(Gtk::SHADOW_ETCHED_IN);

    // Create page tab {{{
    Glib::RefPtr<Gtk::RcStyle> style = m_TabButton->get_modifier_style();
    style->set_ythickness(0);
    style->set_xthickness(0);

    m_TabButton->modify_style(style);
    m_TabButton->add(*(Gtk::manage(new Gtk::Image(Gtk::Stock::CLOSE, Gtk::ICON_SIZE_MENU))));
    m_TabButton->property_relief() = Gtk::RELIEF_NONE;
    m_TabButton->set_focus_on_click(false);
    m_TabButton->set_tooltip_text(_("Close Tab"));
    m_TabButton->signal_clicked().connect([ this ]() { m_SignalClosed(this); });

    m_TabLabel->set_alignment(0.0, 0.5);
    m_TabLabel->set_ellipsize(Pango::ELLIPSIZE_END);

    Gtk::HBox *hbox = Gtk::manage(new Gtk::HBox());
    hbox->pack_start(*m_TabIcon, false, false);
    hbox->pack_start(*m_TabLabel, true, true, 2);
    hbox->pack_start(*m_TabButton, false, false);
    hbox->show_all();

    m_Tab->set_visible_window(false);
    m_Tab->add(*hbox);
    m_Tab->signal_button_release_event().connect(sigc::mem_fun(*this, &Page::on_tab_button_release_event));
    // }}}

    get_vadjustment()->signal_value_changed().connect(sigc::mem_fun(*this, &Page::on_value_changed));

    ModelColumns columns;
    m_ListStore = Gtk::ListStore::create(columns);
    m_IconView->set_model(m_ListStore);
    m_IconView->set_selection_mode(Gtk::SELECTION_BROWSE);
    m_IconView->set_item_width(Image::BooruThumbnailSize - m_IconView->get_margin()
                                                         - m_IconView->property_item_padding().get_value());
    m_IconView->signal_selection_changed().connect(sigc::mem_fun(*this, &Page::on_selection_changed));
    m_IconView->signal_button_press_event().connect(sigc::mem_fun(*this, &Page::on_button_press_event));

    // Workaround to have fully centered pixbufs
    Gtk::CellRendererPixbuf *cell = Gtk::manage(new Gtk::CellRendererPixbuf());
    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(m_IconView->gobj()),
                               GTK_CELL_RENDERER(cell->gobj()), TRUE);
    gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(m_IconView->gobj()),
                                  GTK_CELL_RENDERER(cell->gobj()), "pixbuf", 0);

    m_SignalPostsDownloaded.connect(sigc::mem_fun(*this, &Page::on_posts_downloaded));
    m_SignalSaveProgressDisp.connect([ this ]()
    {
        m_SignalSaveProgress(m_SaveImagesCurrent, m_SaveImagesTotal);
    });

    add(*m_IconView);
    show_all();
}

Page::~Page()
{
    m_Curler.cancel();
    m_CountsCurler.cancel();

    if (m_GetPostsThread)
    {
        m_GetPostsThread->join();
        m_GetPostsThread = nullptr;
    }

    cancel_save();
}

void Page::set_selected(const size_t index)
{
    get_window()->freeze_updates();

    Gtk::TreePath path(std::to_string(index));
    m_IconView->select_path(path);
    scroll_to_selected();

    get_window()->thaw_updates();
}

void Page::scroll_to_selected()
{
    std::vector<Gtk::TreePath> paths = m_IconView->get_selected_items();

    if (!paths.empty())
    {
        Gtk::TreePath path = paths[0];
        if (path)
            m_IconView->scroll_to_path(path, false, 0, 0);
    }
}

void Page::search(const std::shared_ptr<Site> &site)
{
    if (!ask_cancel_save())
        return;

    m_Curler.cancel();
    m_CountsCurler.cancel();

    cancel_save();
    m_ImageList->clear();

    if (m_GetPostsThread)
        m_GetPostsThread->join();

    m_Site = site;
    m_Page = 1;
    m_LastPage = false;

    std::string tags = m_Tags;

    // Trim whitespace for the tab label text
    if (!tags.empty())
    {
        size_t f = tags.find_first_not_of(' '),
               l = tags.find_last_not_of(' ');
        tags = f == std::string::npos ? "" : " - " + tags.substr(f, l - f + 1);
    }

    m_TabLabel->set_text(site->get_name() + tags);
    m_TabIcon->set(site->get_icon_pixbuf());

    get_posts();
}

void Page::save_image(const std::string &path, const std::shared_ptr<Image> &img)
{
    m_SaveCancel->reset();

    m_Saving            = true;
    m_SaveImagesThread  = Glib::Threads::Thread::create([ this, path, img ]()
    {
        img->save(path);
        m_Saving = false;
    });
}

void Page::save_images(const std::string &path)
{
    m_SaveCancel->reset();

    m_Saving            = true;
    m_SaveImagesCurrent = 0;
    m_SaveImagesTotal   = m_ImageList->get_vector_size();
    m_SaveImagesThread  = Glib::Threads::Thread::create([ this, path ]()
    {
        // 2 if cachesize is 0, 8 if cachesize > 2
        Glib::ThreadPool pool(std::max(std::min(Settings.get_int("CacheSize") * 4, 8), 2));
        for (const std::shared_ptr<AhoViewer::Image> &img : *m_ImageList)
        {
            pool.push([ this, path, img ]()
            {
                if (m_SaveCancel->is_cancelled())
                    return;

                std::shared_ptr<Image> bimage = std::static_pointer_cast<Image>(img);
                bimage->save(Glib::build_filename(path, Glib::path_get_basename(bimage->get_filename())));
                ++m_SaveImagesCurrent;

                if (!m_SaveCancel->is_cancelled())
                    m_SignalSaveProgressDisp();
            });
        }

        pool.shutdown(m_SaveCancel->is_cancelled());
        m_Saving = false;
    });
}

/**
 * Returns true if we want to cancel or we're not saving
 **/
bool Page::ask_cancel_save()
{
    if (!m_Saving)
        return true;

    Gtk::Window *window = static_cast<Gtk::Window*>(get_toplevel());
    Gtk::MessageDialog dialog(*window, _("Are you sure that you want to stop saving images?"),
                              false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true);
    dialog.set_secondary_text(_("Closing this tab will stop the save operation."));

    return dialog.run() == Gtk::RESPONSE_YES;
}

void Page::cancel_save()
{
    m_SaveCancel->cancel();

    for (const std::shared_ptr<AhoViewer::Image> &img : *m_ImageList)
    {
        std::shared_ptr<Image> bimage = std::static_pointer_cast<Image>(img);
        bimage->cancel_download();
    }

    if (m_SaveImagesThread)
    {
        m_SaveImagesThread->join();
        m_SaveImagesThread = nullptr;
    }
}

void Page::get_posts()
{
    std::string tags(m_Tags);

    if (m_Tags.find("rating:") == std::string::npos)
    {
        if (Settings.get_booru_max_rating() == Site::Rating::SAFE)
        {
            tags += " rating:safe";
        }
        else if (Settings.get_booru_max_rating() == Site::Rating::QUESTIONABLE)
        {
            tags += " -rating:explicit";
        }
    }

    tags = m_Curler.escape(tags);
    m_Curler.set_url(m_Site->get_posts_url(tags, m_Page));

    m_GetPostsThread = Glib::Threads::Thread::create([ this, tags ]()
    {
        size_t postsCount = 0;
        // Danbooru doesn't give the post count with the posts
        // Get it from thier counts api
        if (m_Page == 1 && m_Site->get_type() == Site::Type::DANBOORU)
        {
            m_CountsCurler.set_url(m_Site->get_url() + "/counts/posts.xml?tags=" + tags);
            if (m_CountsCurler.perform())
            {
                xmlDocument doc(reinterpret_cast<char*>(m_CountsCurler.get_data()), m_CountsCurler.get_data_size());
                postsCount = std::stoul(doc.get_children()[0].get_value());
            }
        }

        if (m_Curler.perform())
        {
            m_Posts = std::unique_ptr<xmlDocument>(
                    new xmlDocument(reinterpret_cast<char*>(m_Curler.get_data()),
                                    m_Curler.get_data_size()));
            m_NumPosts = m_Posts->get_n_nodes();

            if (postsCount)
                m_Posts->set_attribute("count", std::to_string(postsCount));
        }
        else
        {
            m_NumPosts = 0;
            std::cerr << "Error while downloading posts on " << m_Curler.get_url() << std::endl
                      << "  " << m_Curler.get_error() << std::endl;
        }

        if (!m_Curler.is_cancelled())
            m_SignalPostsDownloaded();
    });
}

bool Page::get_next_page()
{
    // Do not fetch the next page if this is the last
    // or the current page is still loading
    if (m_LastPage || m_GetPostsThread)
        return false;

    if (!m_Saving)
    {
        ++m_Page;
        get_posts();

        return false;
    }
    else if (!m_GetNextPageConn)
    {
        m_GetNextPageConn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &Page::get_next_page), 1000);
    }

    return true;
}

/**
 * Adds the downloaded posts to the image list.
 **/
void Page::on_posts_downloaded()
{
    if (m_Posts->get_attribute("success") == "false" && !m_Posts->get_attribute("reason").empty())
    {
        m_SignalDownloadError(m_Posts->get_attribute("reason"));
    }
    else if (m_NumPosts > 0)
    {
        reserve(m_NumPosts);
        m_ImageList->load(*m_Posts, *this);
    }
    else if (m_Page == 1)
    {
        m_SignalDownloadError(_("No results found"));
    }

    if (m_NumPosts < static_cast<size_t>(Settings.get_int("BooruLimit")))
        m_LastPage = true;

    m_Posts = nullptr;
    m_GetPostsThread->join();
    m_GetPostsThread = nullptr;
}

void Page::on_selection_changed()
{
    std::vector<Gtk::TreePath> paths = m_IconView->get_selected_items();

    if (!paths.empty())
    {
        Gtk::TreePath path = paths[0];
        if (path)
        {
            size_t index = path[0];

            if (index + Settings.get_int("CacheSize") >= m_ImageList->get_vector_size() - 1)
                get_next_page();

            m_SignalSelectedChanged(index);
        }
    }
}

/**
 * Vertical scrollbar value changed
 **/
void Page::on_value_changed()
{
    double value = get_vadjustment()->get_value(),
           limit = get_vadjustment()->get_upper() -
                   get_vadjustment()->get_page_size() -
                   get_vadjustment()->get_step_increment();

    if (value >= limit)
        get_next_page();
}

bool Page::on_button_press_event(GdkEventButton *e)
{
    if (e->type == GDK_BUTTON_PRESS && e->button == 3)
    {
        Gtk::TreePath path = m_IconView->get_path_at_pos(e->x, e->y);

        if (path)
        {
            m_IconView->select_path(path);
            m_IconView->scroll_to_path(path, false, 0, 0);

            m_PopupMenu->popup(e->button, e->time);

            return true;
        }
    }

    return false;
}

bool Page::on_tab_button_release_event(GdkEventButton *e)
{
    if (e->type == GDK_BUTTON_RELEASE && e->button == 2)
        m_SignalClosed(this);

    return false;
}
<commit_msg>booru/page: Null check posts<commit_after>#include <glibmm/i18n.h>
#include <iostream>

#include "page.h"
using namespace AhoViewer::Booru;

#include "curler.h"
#include "image.h"
#include "settings.h"

Page::Page(Gtk::Menu *menu)
  : Gtk::ScrolledWindow(),
    m_PopupMenu(menu),
    m_ImageFetcher(std::unique_ptr<ImageFetcher>(new ImageFetcher())),
    m_IconView(Gtk::manage(new Gtk::IconView())),
    m_Tab(Gtk::manage(new Gtk::EventBox())),
    m_TabIcon(Gtk::manage(new Gtk::Image(Gtk::Stock::NEW, Gtk::ICON_SIZE_MENU))),
    m_TabLabel(Gtk::manage(new Gtk::Label(_("New Tab")))),
    m_TabButton(Gtk::manage(new Gtk::Button())),
    m_ImageList(std::make_shared<ImageList>(this)),
    m_Page(0),
    m_NumPosts(0),
    m_LastPage(false),
    m_Saving(false),
    m_SaveCancel(Gio::Cancellable::create()),
    m_GetPostsThread(nullptr),
    m_SaveImagesThread(nullptr)
{
    set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
    set_shadow_type(Gtk::SHADOW_ETCHED_IN);

    // Create page tab {{{
    Glib::RefPtr<Gtk::RcStyle> style = m_TabButton->get_modifier_style();
    style->set_ythickness(0);
    style->set_xthickness(0);

    m_TabButton->modify_style(style);
    m_TabButton->add(*(Gtk::manage(new Gtk::Image(Gtk::Stock::CLOSE, Gtk::ICON_SIZE_MENU))));
    m_TabButton->property_relief() = Gtk::RELIEF_NONE;
    m_TabButton->set_focus_on_click(false);
    m_TabButton->set_tooltip_text(_("Close Tab"));
    m_TabButton->signal_clicked().connect([ this ]() { m_SignalClosed(this); });

    m_TabLabel->set_alignment(0.0, 0.5);
    m_TabLabel->set_ellipsize(Pango::ELLIPSIZE_END);

    Gtk::HBox *hbox = Gtk::manage(new Gtk::HBox());
    hbox->pack_start(*m_TabIcon, false, false);
    hbox->pack_start(*m_TabLabel, true, true, 2);
    hbox->pack_start(*m_TabButton, false, false);
    hbox->show_all();

    m_Tab->set_visible_window(false);
    m_Tab->add(*hbox);
    m_Tab->signal_button_release_event().connect(sigc::mem_fun(*this, &Page::on_tab_button_release_event));
    // }}}

    get_vadjustment()->signal_value_changed().connect(sigc::mem_fun(*this, &Page::on_value_changed));

    ModelColumns columns;
    m_ListStore = Gtk::ListStore::create(columns);
    m_IconView->set_model(m_ListStore);
    m_IconView->set_selection_mode(Gtk::SELECTION_BROWSE);
    m_IconView->set_item_width(Image::BooruThumbnailSize - m_IconView->get_margin()
                                                         - m_IconView->property_item_padding().get_value());
    m_IconView->signal_selection_changed().connect(sigc::mem_fun(*this, &Page::on_selection_changed));
    m_IconView->signal_button_press_event().connect(sigc::mem_fun(*this, &Page::on_button_press_event));

    // Workaround to have fully centered pixbufs
    Gtk::CellRendererPixbuf *cell = Gtk::manage(new Gtk::CellRendererPixbuf());
    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(m_IconView->gobj()),
                               GTK_CELL_RENDERER(cell->gobj()), TRUE);
    gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(m_IconView->gobj()),
                                  GTK_CELL_RENDERER(cell->gobj()), "pixbuf", 0);

    m_SignalPostsDownloaded.connect(sigc::mem_fun(*this, &Page::on_posts_downloaded));
    m_SignalSaveProgressDisp.connect([ this ]()
    {
        m_SignalSaveProgress(m_SaveImagesCurrent, m_SaveImagesTotal);
    });

    add(*m_IconView);
    show_all();
}

Page::~Page()
{
    m_Curler.cancel();
    m_CountsCurler.cancel();

    if (m_GetPostsThread)
    {
        m_GetPostsThread->join();
        m_GetPostsThread = nullptr;
    }

    cancel_save();
}

void Page::set_selected(const size_t index)
{
    get_window()->freeze_updates();

    Gtk::TreePath path(std::to_string(index));
    m_IconView->select_path(path);
    scroll_to_selected();

    get_window()->thaw_updates();
}

void Page::scroll_to_selected()
{
    std::vector<Gtk::TreePath> paths = m_IconView->get_selected_items();

    if (!paths.empty())
    {
        Gtk::TreePath path = paths[0];
        if (path)
            m_IconView->scroll_to_path(path, false, 0, 0);
    }
}

void Page::search(const std::shared_ptr<Site> &site)
{
    if (!ask_cancel_save())
        return;

    m_Curler.cancel();
    m_CountsCurler.cancel();

    cancel_save();
    m_ImageList->clear();

    if (m_GetPostsThread)
        m_GetPostsThread->join();

    m_Site = site;
    m_Page = 1;
    m_LastPage = false;

    std::string tags = m_Tags;

    // Trim whitespace for the tab label text
    if (!tags.empty())
    {
        size_t f = tags.find_first_not_of(' '),
               l = tags.find_last_not_of(' ');
        tags = f == std::string::npos ? "" : " - " + tags.substr(f, l - f + 1);
    }

    m_TabLabel->set_text(site->get_name() + tags);
    m_TabIcon->set(site->get_icon_pixbuf());

    get_posts();
}

void Page::save_image(const std::string &path, const std::shared_ptr<Image> &img)
{
    m_SaveCancel->reset();

    m_Saving            = true;
    m_SaveImagesThread  = Glib::Threads::Thread::create([ this, path, img ]()
    {
        img->save(path);
        m_Saving = false;
    });
}

void Page::save_images(const std::string &path)
{
    m_SaveCancel->reset();

    m_Saving            = true;
    m_SaveImagesCurrent = 0;
    m_SaveImagesTotal   = m_ImageList->get_vector_size();
    m_SaveImagesThread  = Glib::Threads::Thread::create([ this, path ]()
    {
        // 2 if cachesize is 0, 8 if cachesize > 2
        Glib::ThreadPool pool(std::max(std::min(Settings.get_int("CacheSize") * 4, 8), 2));
        for (const std::shared_ptr<AhoViewer::Image> &img : *m_ImageList)
        {
            pool.push([ this, path, img ]()
            {
                if (m_SaveCancel->is_cancelled())
                    return;

                std::shared_ptr<Image> bimage = std::static_pointer_cast<Image>(img);
                bimage->save(Glib::build_filename(path, Glib::path_get_basename(bimage->get_filename())));
                ++m_SaveImagesCurrent;

                if (!m_SaveCancel->is_cancelled())
                    m_SignalSaveProgressDisp();
            });
        }

        pool.shutdown(m_SaveCancel->is_cancelled());
        m_Saving = false;
    });
}

/**
 * Returns true if we want to cancel or we're not saving
 **/
bool Page::ask_cancel_save()
{
    if (!m_Saving)
        return true;

    Gtk::Window *window = static_cast<Gtk::Window*>(get_toplevel());
    Gtk::MessageDialog dialog(*window, _("Are you sure that you want to stop saving images?"),
                              false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true);
    dialog.set_secondary_text(_("Closing this tab will stop the save operation."));

    return dialog.run() == Gtk::RESPONSE_YES;
}

void Page::cancel_save()
{
    m_SaveCancel->cancel();

    for (const std::shared_ptr<AhoViewer::Image> &img : *m_ImageList)
    {
        std::shared_ptr<Image> bimage = std::static_pointer_cast<Image>(img);
        bimage->cancel_download();
    }

    if (m_SaveImagesThread)
    {
        m_SaveImagesThread->join();
        m_SaveImagesThread = nullptr;
    }
}

void Page::get_posts()
{
    std::string tags(m_Tags);

    if (m_Tags.find("rating:") == std::string::npos)
    {
        if (Settings.get_booru_max_rating() == Site::Rating::SAFE)
        {
            tags += " rating:safe";
        }
        else if (Settings.get_booru_max_rating() == Site::Rating::QUESTIONABLE)
        {
            tags += " -rating:explicit";
        }
    }

    tags = m_Curler.escape(tags);
    m_Curler.set_url(m_Site->get_posts_url(tags, m_Page));

    m_GetPostsThread = Glib::Threads::Thread::create([ this, tags ]()
    {
        size_t postsCount = 0;
        // Danbooru doesn't give the post count with the posts
        // Get it from thier counts api
        if (m_Page == 1 && m_Site->get_type() == Site::Type::DANBOORU)
        {
            m_CountsCurler.set_url(m_Site->get_url() + "/counts/posts.xml?tags=" + tags);
            if (m_CountsCurler.perform())
            {
                xmlDocument doc(reinterpret_cast<char*>(m_CountsCurler.get_data()), m_CountsCurler.get_data_size());
                postsCount = std::stoul(doc.get_children()[0].get_value());
            }
        }

        if (m_Curler.perform())
        {
            m_Posts = std::unique_ptr<xmlDocument>(
                    new xmlDocument(reinterpret_cast<char*>(m_Curler.get_data()),
                                    m_Curler.get_data_size()));
            m_NumPosts = m_Posts->get_n_nodes();

            if (postsCount)
                m_Posts->set_attribute("count", std::to_string(postsCount));
        }
        else
        {
            m_NumPosts = 0;
            std::cerr << "Error while downloading posts on " << m_Curler.get_url() << std::endl
                      << "  " << m_Curler.get_error() << std::endl;
        }

        if (!m_Curler.is_cancelled())
            m_SignalPostsDownloaded();
    });
}

bool Page::get_next_page()
{
    // Do not fetch the next page if this is the last
    // or the current page is still loading
    if (m_LastPage || m_GetPostsThread)
        return false;

    if (!m_Saving)
    {
        ++m_Page;
        get_posts();

        return false;
    }
    else if (!m_GetNextPageConn)
    {
        m_GetNextPageConn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &Page::get_next_page), 1000);
    }

    return true;
}

/**
 * Adds the downloaded posts to the image list.
 **/
void Page::on_posts_downloaded()
{
    if (m_Posts && m_Posts->get_attribute("success") == "false" && !m_Posts->get_attribute("reason").empty())
    {
        m_SignalDownloadError(m_Posts->get_attribute("reason"));
    }
    else if (m_NumPosts > 0)
    {
        reserve(m_NumPosts);
        m_ImageList->load(*m_Posts, *this);
    }
    else if (m_Page == 1)
    {
        m_SignalDownloadError(_("No results found"));
    }

    if (m_NumPosts < static_cast<size_t>(Settings.get_int("BooruLimit")))
        m_LastPage = true;

    m_Posts = nullptr;
    m_GetPostsThread->join();
    m_GetPostsThread = nullptr;
}

void Page::on_selection_changed()
{
    std::vector<Gtk::TreePath> paths = m_IconView->get_selected_items();

    if (!paths.empty())
    {
        Gtk::TreePath path = paths[0];
        if (path)
        {
            size_t index = path[0];

            if (index + Settings.get_int("CacheSize") >= m_ImageList->get_vector_size() - 1)
                get_next_page();

            m_SignalSelectedChanged(index);
        }
    }
}

/**
 * Vertical scrollbar value changed
 **/
void Page::on_value_changed()
{
    double value = get_vadjustment()->get_value(),
           limit = get_vadjustment()->get_upper() -
                   get_vadjustment()->get_page_size() -
                   get_vadjustment()->get_step_increment();

    if (value >= limit)
        get_next_page();
}

bool Page::on_button_press_event(GdkEventButton *e)
{
    if (e->type == GDK_BUTTON_PRESS && e->button == 3)
    {
        Gtk::TreePath path = m_IconView->get_path_at_pos(e->x, e->y);

        if (path)
        {
            m_IconView->select_path(path);
            m_IconView->scroll_to_path(path, false, 0, 0);

            m_PopupMenu->popup(e->button, e->time);

            return true;
        }
    }

    return false;
}

bool Page::on_tab_button_release_event(GdkEventButton *e)
{
    if (e->type == GDK_BUTTON_RELEASE && e->button == 2)
        m_SignalClosed(this);

    return false;
}
<|endoftext|>


<commit_before>/*
 * cli_geo2emp.C
 *
 * command line frontend for converting BGEO to EMP files
 *
 * Copyright (c) 2010 Van Aarde Krynauw.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "geo2emp.h"
#include "geo2emp_utils.h"
#include "anyoption.h"
#include "pystring.h"

#include <stdio.h>
#include <iostream>
#include <unistd.h>

#include <CMD/CMD_Args.h>

using namespace geo2emp;

/**************************************************************************************************/

/*
 * Initialise the commandline option parser
 */
void processOpts(AnyOption& opt)
{

	opt.addUsage("Naiad Buddy for Houdini toolkit - command line geo2emp converter");
	opt.addUsage("");
	opt.addUsage("Usage: geo2emp [options] input.bgeo output.emp");
	opt.addUsage("Usage: geo2emp [options] -s startframe -e endframe input.#.bgeo output.#.emp");
	opt.addUsage("");
  opt.addUsage("  This tool is used to convert BGEO files to EMP files. The input");
	opt.addUsage("  will be regarded as a BGEO file and the output will be regarded");
	opt.addUsage("  as an EMP file regardless of their extensions.");
	opt.addUsage("  Sequence conversion is also supported");
	opt.addUsage("");
	opt.addUsage("\t-h\t--help\t\t Prints this help");
	opt.addUsage("\t-v\t--verbose [lvl]\t Verbosity level:");
	opt.addUsage("\t\t\t\t     0 - Stealth mode");
	opt.addUsage("\t\t\t\t     1 - Informative");
	opt.addUsage("\t\t\t\t     2 - Talkative");
	opt.addUsage("\t\t\t\t     3 - Debug");
	opt.addUsage("\t-p\t--particles\t Interpret bgeo data as particles");
	opt.addUsage("\t-m\t--mesh\t\t Interpret bgeo data as one or more meshes");
	opt.addUsage("\t-f\t--field\t\t Interpret bgeo data as volume data");
	opt.addUsage("\t-s\t--startframe\t\t Start frame of the sequence");
	opt.addUsage("\t-e\t--endframe\t\t End frame of the sequence");
	opt.addUsage("\t-i\t--initframe\t\t Frame that is considered zero time for Naiad sim (default: 0)");
	opt.addUsage("\t-d\t--pad\t\t Frame number padding (default: 4)");
	opt.addUsage("\t-t\t--time\t\t Timestep of the EMP file (only use this if you know what you are doing)");
	opt.addUsage("\t-b\t--bodyname\t\t Force to use this body name (default: trimesh)");
	opt.addUsage("");

	//opt->setOption( "verbose", 'v' );

	/* by default all  options  will be checked on the command line and from option/resource file */
	opt.setOption( "verbose", 'v' );
	opt.setOption( "startframe", 's' );
	opt.setOption( "endframe", 'e' );
	opt.setOption( "initframe", 'i' );
	opt.setOption( "pad", 'd' );
	opt.setOption( "time", 't' );
	opt.setOption( "bodyname", 'b' );
  opt.setFlag( "help", 'h' );   /* a flag (takes no argument), supporting long and short form */
	opt.setFlag( "particles", 'p' );
	opt.setFlag( "mesh", 'm' );
	opt.setFlag( "field", 'f' );
}
/**************************************************************************************************/

#include <IMG/IMG_Format.h>
#include <IMG/IMG_File.h>
#include <PXL/PXL_Common.h>

int main(int argc, char *argv[])
{
	Geo2Emp geo2emp;
	AnyOption opt;
	GU_Detail gdp;
	int shapeMask = 0;
	float time = 0;
	bool seqconv = false;
	int sframe = 0;
	int eframe = 0;
	int initframe = 0;
	int pad = 0;
	char pwd[BUFSIZ];

	geo2emp.setGdpIn(&gdp);
	geo2emp.setGdpOut(&gdp);

	processOpts(opt);

	opt.processCommandArgs(argc, argv);

	//If we don't have exactly two args (input & output file name) then bug out.
	if (! opt.hasOptions() || opt.getArgc() != 2)
	{
		/* print usage if no options */
 		opt.printUsage();
		return 0;
	}

	if( opt.getFlag( "help" ) || opt.getFlag( 'h' ) )
	{
		opt.printUsage();
		return 0;
	}

	if ( opt.getValue("verbose") != NULL || opt.getValue( 'v' ) != NULL )
	{
		istringstream intstream( opt.getValue('v') );
		int i;
		if (intstream >> i)
		{
			geo2emp.setLogLevel( (Geo2Emp::LogLevel)i );
		}
	}

	if ( opt.getValue("bodyname") != NULL || opt.getValue( 'b' ) != NULL )
	{
		geo2emp.setBodyName( opt.getValue('b') );
	}

	if ( opt.getValue("particle") != NULL || opt.getValue( 'p' ) != NULL )
	{
		shapeMask = Geo2Emp::BT_PARTICLE;
	}

	if ( opt.getValue("mesh") != NULL || opt.getValue( 'm' ) != NULL )
	{
		shapeMask = Geo2Emp::BT_MESH;
	}

	if ( opt.getValue("field") != NULL || opt.getValue( 'f' ) != NULL )
	{
		shapeMask = Geo2Emp::BT_FIELD;
	}

	if ( opt.getValue("startframe") != NULL || opt.getValue( 's' ) != NULL )
	{
		geo2emp.setStartFrame( stringToInt( opt.getValue('s') ) );
	}
	if ( opt.getValue("endframe") != NULL || opt.getValue( 'e' ) != NULL )
	{
		sframe = stringToInt( opt.getValue('e') );
	}
	if ( opt.getValue("initframe") != NULL || opt.getValue( 's' ) != NULL )
	{
		sframe = stringToInt( opt.getValue('s') );
	}

	if ( opt.getValue("pad") != NULL || opt.getValue( 'd' ) != NULL )
	{
		istringstream padstream( opt.getValue('d') );
		padstream >> pad;
	}

	geo2emp.redirect( std::cerr );

	UT_String	inputname, outputname, lowerin, lowerout;

	inputname.harden(opt.getArgv(0));
	outputname.harden(opt.getArgv(1));
	lowerout = outputname;
	lowerout.toLower();

	//If the input or ouput name has a hash, then we enable sequence conversion
	if ( pystring::find( inputname.toStdString(), "#" ) != -1 || pystring::find( outputname.toStdString(), "#" ) != -1 )
	{
		seqconv = true;
	}

	//Do some parm integrity checks
	if (shapeMask == 0)
	{
		//Require, for now, that a conversion needs to be specified.
		geo2emp.LogInfo() << "No conversion mode found. Please specify the conversion mode using -p, -m, or -f." << std::endl;
		return 1;
	}

	if (seqconv == true)
	{
		geo2emp.LogInfo() << "Sequence conversion not yet supported!" << std::endl;
		return 1;
	}

	// Naiad's EmpReader and EmpWriter classes require absolute paths from 0.96. Check whether
	// lowerin and lowerout start with /, if not prefix it with the current working directory
	getcwd(pwd, BUFSIZ);
	if ( ( lowerin != "stdin.bgeo" ) && ( !inputname.startsWith("/") ) )
	{
		// Not an absolute path, prefix current working directory
		inputname.prepend("/");
		inputname.prepend(pwd);
	}
	if ( ( lowerout != "stdout.bgeo" ) && ( !outputname.startsWith("/") ) )
	{
		// Not an absolute path, prefix current working directory
		outputname.prepend("/");
		outputname.prepend(pwd);
	}

	geo2emp.LogInfo() << "Absolute input path: " << inputname << std::endl;
	geo2emp.LogInfo() << "Absolute output path: " << outputname << std::endl;

	lowerin = inputname;
	lowerin.toLower();
	lowerout = outputname;
	lowerout.toLower();

  //if ( ! (lowerin.endsWith(".emp") || lowerin.endsWith(".geo") || lowerin.endsWith(".bgeo") ) )
	//{
	//	geo2emp.LogInfo() << "Unrecognized extension for source file: " << inputname << std::endl;
	//	return 1;
	//}
	if (not inputname.match("stdin.bgeo"))
	{
		//Check whether the input filename actually exist
		ifstream inp;
		inp.open( inputname );
		inp.close();
		if (inp.fail())
		{
			geo2emp.LogInfo() << "Error: The input file does not exist: " << inputname << std::endl;
		}

	}

	//if ( ! (lowerout.endsWith(".emp") || lowerout.endsWith(".geo") || lowerout.endsWith(".bgeo") ) )
	//{
	//	geo2emp.LogInfo() << "Unrecognized extension for destination file: " << outputname << std::endl;
	//	return 1;
	//}

	//Dont bother checking extensions. Assume the input is BGEO and the output is EMP
  //if (lowerin.endsWith(".geo") || lowerin.endsWith(".bgeo") )

		if ( opt.getValue("time") != NULL || opt.getValue( 't' ) != NULL )
		{
			istringstream timestream( opt.getValue('t') );
			timestream >> time;
			geo2emp.LogInfo() << "Time is set to: " << time << std::endl;
		}

		// Convert to emp.
		geo2emp.LogInfo() << "Loading GDP: " << inputname << std::endl;
		int result = gdp.load((const char *) inputname, 0);

		if (result >= 0)
		{
			geo2emp.LogInfo() << "Saving EMP: " << outputname << std::endl;
			//geo2emp.saveEmpBodies(outputname.toStdString(), time, frame, pad, shapeMask);
		}
		else
		{
			geo2emp.LogInfo() << "Error occured while loading BGEO. Does the file exist? " << inputname.toStdString() << std::endl;
			return 1;
		}
	/*
	else
	{
		geo2emp.LogInfo() << "Unrecognized extension for source file: " << inputname << std::endl;
		geo2emp.LogInfo() << "How did you get to this point anyways? You should've been kicked out at the extension integrity checks already!" << std::endl;
		return 1;
	}
	*/

	return 0;
}

<commit_msg>Added initframe parameter handling in cli_geo2emp<commit_after>/*
 * cli_geo2emp.C
 *
 * command line frontend for converting BGEO to EMP files
 *
 * Copyright (c) 2010 Van Aarde Krynauw.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "geo2emp.h"
#include "geo2emp_utils.h"
#include "anyoption.h"
#include "pystring.h"

#include <stdio.h>
#include <iostream>
#include <unistd.h>

#include <CMD/CMD_Args.h>

using namespace geo2emp;

/**************************************************************************************************/

/*
 * Initialise the commandline option parser
 */
void processOpts(AnyOption& opt)
{

	opt.addUsage("Naiad Buddy for Houdini toolkit - command line geo2emp converter");
	opt.addUsage("");
	opt.addUsage("Usage: geo2emp [options] input.bgeo output.emp");
	opt.addUsage("Usage: geo2emp [options] -s startframe -e endframe input.#.bgeo output.#.emp");
	opt.addUsage("");
  opt.addUsage("  This tool is used to convert BGEO files to EMP files. The input");
	opt.addUsage("  will be regarded as a BGEO file and the output will be regarded");
	opt.addUsage("  as an EMP file regardless of their extensions.");
	opt.addUsage("  Sequence conversion is also supported");
	opt.addUsage("");
	opt.addUsage("\t-h\t--help\t\t Prints this help");
	opt.addUsage("\t-v\t--verbose [lvl]\t Verbosity level:");
	opt.addUsage("\t\t\t\t     0 - Stealth mode");
	opt.addUsage("\t\t\t\t     1 - Informative");
	opt.addUsage("\t\t\t\t     2 - Talkative");
	opt.addUsage("\t\t\t\t     3 - Debug");
	opt.addUsage("\t-p\t--particles\t Interpret bgeo data as particles");
	opt.addUsage("\t-m\t--mesh\t\t Interpret bgeo data as one or more meshes");
	opt.addUsage("\t-f\t--field\t\t Interpret bgeo data as volume data");
	opt.addUsage("\t-s\t--startframe\t\t Start frame of the sequence");
	opt.addUsage("\t-e\t--endframe\t\t End frame of the sequence");
	opt.addUsage("\t-i\t--initframe\t\t Frame that is considered zero time for Naiad sim (default: 0)");
	opt.addUsage("\t-d\t--pad\t\t Frame number padding (default: 4)");
	opt.addUsage("\t-t\t--time\t\t Timestep of the EMP file (only use this if you know what you are doing)");
	opt.addUsage("\t-b\t--bodyname\t\t Force to use this body name (default: trimesh)");
	opt.addUsage("");

	//opt->setOption( "verbose", 'v' );

	/* by default all  options  will be checked on the command line and from option/resource file */
	opt.setOption( "verbose", 'v' );
	opt.setOption( "startframe", 's' );
	opt.setOption( "endframe", 'e' );
	opt.setOption( "initframe", 'i' );
	opt.setOption( "pad", 'd' );
	opt.setOption( "time", 't' );
	opt.setOption( "bodyname", 'b' );
  opt.setFlag( "help", 'h' );   /* a flag (takes no argument), supporting long and short form */
	opt.setFlag( "particles", 'p' );
	opt.setFlag( "mesh", 'm' );
	opt.setFlag( "field", 'f' );
}
/**************************************************************************************************/

#include <IMG/IMG_Format.h>
#include <IMG/IMG_File.h>
#include <PXL/PXL_Common.h>

int main(int argc, char *argv[])
{
	Geo2Emp geo2emp;
	AnyOption opt;
	GU_Detail gdp;
	int shapeMask = 0;
	float time = 0;
	bool seqconv = false;
	int sframe = 0;
	int eframe = 0;
	int initframe = 0;
	int pad = 0;
	char pwd[BUFSIZ];

	geo2emp.setGdpIn(&gdp);
	geo2emp.setGdpOut(&gdp);

	processOpts(opt);

	opt.processCommandArgs(argc, argv);

	//If we don't have exactly two args (input & output file name) then bug out.
	if (! opt.hasOptions() || opt.getArgc() != 2)
	{
		/* print usage if no options */
 		opt.printUsage();
		return 0;
	}

	if( opt.getFlag( "help" ) || opt.getFlag( 'h' ) )
	{
		opt.printUsage();
		return 0;
	}

	if ( opt.getValue("verbose") != NULL || opt.getValue( 'v' ) != NULL )
	{
		istringstream intstream( opt.getValue('v') );
		int i;
		if (intstream >> i)
		{
			geo2emp.setLogLevel( (Geo2Emp::LogLevel)i );
		}
	}

	if ( opt.getValue("bodyname") != NULL || opt.getValue( 'b' ) != NULL )
	{
		geo2emp.setBodyName( opt.getValue('b') );
	}

	if ( opt.getValue("particle") != NULL || opt.getValue( 'p' ) != NULL )
	{
		shapeMask = Geo2Emp::BT_PARTICLE;
	}

	if ( opt.getValue("mesh") != NULL || opt.getValue( 'm' ) != NULL )
	{
		shapeMask = Geo2Emp::BT_MESH;
	}

	if ( opt.getValue("field") != NULL || opt.getValue( 'f' ) != NULL )
	{
		shapeMask = Geo2Emp::BT_FIELD;
	}

	if ( opt.getValue("startframe") != NULL || opt.getValue( 's' ) != NULL )
	{
		geo2emp.setStartFrame( stringToInt( opt.getValue('s') ) );
	}
	if ( opt.getValue("endframe") != NULL || opt.getValue( 'e' ) != NULL )
	{
		geo2emp.setEndFrame( stringToInt( opt.getValue('e') ) );
	}
	if ( opt.getValue("initframe") != NULL || opt.getValue( 'i' ) != NULL )
	{
		geo2emp.setInitialFrame( stringToInt( opt.getValue('i') ) );
	}

	if ( opt.getValue("pad") != NULL || opt.getValue( 'd' ) != NULL )
	{
		istringstream padstream( opt.getValue('d') );
		padstream >> pad;
	}

	geo2emp.redirect( std::cerr );

	UT_String	inputname, outputname, lowerin, lowerout;

	inputname.harden(opt.getArgv(0));
	outputname.harden(opt.getArgv(1));
	lowerout = outputname;
	lowerout.toLower();

	//If the input or ouput name has a hash, then we enable sequence conversion
	if ( pystring::find( inputname.toStdString(), "#" ) != -1 || pystring::find( outputname.toStdString(), "#" ) != -1 )
	{
		seqconv = true;
	}

	//Do some parm integrity checks
	if (shapeMask == 0)
	{
		//Require, for now, that a conversion needs to be specified.
		geo2emp.LogInfo() << "No conversion mode found. Please specify the conversion mode using -p, -m, or -f." << std::endl;
		return 1;
	}

	if (seqconv == true)
	{
		geo2emp.LogInfo() << "Sequence conversion not yet supported!" << std::endl;
		return 1;
	}

	// Naiad's EmpReader and EmpWriter classes require absolute paths from 0.96. Check whether
	// lowerin and lowerout start with /, if not prefix it with the current working directory
	getcwd(pwd, BUFSIZ);
	if ( ( lowerin != "stdin.bgeo" ) && ( !inputname.startsWith("/") ) )
	{
		// Not an absolute path, prefix current working directory
		inputname.prepend("/");
		inputname.prepend(pwd);
	}
	if ( ( lowerout != "stdout.bgeo" ) && ( !outputname.startsWith("/") ) )
	{
		// Not an absolute path, prefix current working directory
		outputname.prepend("/");
		outputname.prepend(pwd);
	}

	geo2emp.LogInfo() << "Absolute input path: " << inputname << std::endl;
	geo2emp.LogInfo() << "Absolute output path: " << outputname << std::endl;

	lowerin = inputname;
	lowerin.toLower();
	lowerout = outputname;
	lowerout.toLower();

  //if ( ! (lowerin.endsWith(".emp") || lowerin.endsWith(".geo") || lowerin.endsWith(".bgeo") ) )
	//{
	//	geo2emp.LogInfo() << "Unrecognized extension for source file: " << inputname << std::endl;
	//	return 1;
	//}
	if (not inputname.match("stdin.bgeo"))
	{
		//Check whether the input filename actually exist
		ifstream inp;
		inp.open( inputname );
		inp.close();
		if (inp.fail())
		{
			geo2emp.LogInfo() << "Error: The input file does not exist: " << inputname << std::endl;
		}

	}

	//if ( ! (lowerout.endsWith(".emp") || lowerout.endsWith(".geo") || lowerout.endsWith(".bgeo") ) )
	//{
	//	geo2emp.LogInfo() << "Unrecognized extension for destination file: " << outputname << std::endl;
	//	return 1;
	//}

	//Dont bother checking extensions. Assume the input is BGEO and the output is EMP
  //if (lowerin.endsWith(".geo") || lowerin.endsWith(".bgeo") )

		if ( opt.getValue("time") != NULL || opt.getValue( 't' ) != NULL )
		{
			istringstream timestream( opt.getValue('t') );
			timestream >> time;
			geo2emp.LogInfo() << "Time is set to: " << time << std::endl;
		}

		// Convert to emp.
		geo2emp.LogInfo() << "Loading GDP: " << inputname << std::endl;
		int result = gdp.load((const char *) inputname, 0);

		if (result >= 0)
		{
			geo2emp.LogInfo() << "Saving EMP: " << outputname << std::endl;
			//geo2emp.saveEmpBodies(outputname.toStdString(), time, frame, pad, shapeMask);
		}
		else
		{
			geo2emp.LogInfo() << "Error occured while loading BGEO. Does the file exist? " << inputname.toStdString() << std::endl;
			return 1;
		}
	/*
	else
	{
		geo2emp.LogInfo() << "Unrecognized extension for source file: " << inputname << std::endl;
		geo2emp.LogInfo() << "How did you get to this point anyways? You should've been kicked out at the extension integrity checks already!" << std::endl;
		return 1;
	}
	*/

	return 0;
}

<|endoftext|>


<commit_before>/*
 * This file is part of the colouri.se project.
 * See the appropriate repository at http://colouri.se/.git for exact file
 * modification records.
*/

/*
 * Copyright (c) 2012, ef.gy Project Members
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
*/

#include <ef.gy/http.h>
#include <ef.gy/fractions.h>
#include <ef.gy/colour-space-hsl.h>

#include <iostream>
#include <boost/regex.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>

#include <ef.gy/render-xml.h>

#include <ef.gy/continued-fractions.h>

using namespace efgy::colour;
using namespace efgy::math;
using namespace efgy::render;
using namespace boost::filesystem;
using namespace boost::iostreams;
using namespace boost::asio;
using namespace boost;
using namespace std;

class processColourise
{
    public:
        bool operator () (efgy::net::http::session<processColourise> &a)
        {
            static const regex rq
                ("/generated/(x?html|svg)/("
                  "(hsl:(-?\\d+)(/(-?\\d+))?:(-?\\d+)(/(-?\\d+))?:(-?\\d+)(/(-?\\d+))?)"
                 "|(rgb:(-?\\d+)(/(-?\\d+))?:(-?\\d+)(/(-?\\d+))?:(-?\\d+)(/(-?\\d+))?)"
                 ")(.(\\d+))?");
            boost::smatch matches;

            if (regex_match(a.resource, matches, rq))
            {
                string reply = string("<colour xmlns='http://colouri.se/2012'>")
                             + a.method + " " + a.resource
                             + "</colour>";

                unsigned long precision = 24;
                string sPrecision;

                if (matches[24].matched)
                {
                    sPrecision = matches[24];
                    precision = atoi(sPrecision.c_str());
                    sPrecision = "<precision>" + sPrecision + "</precision>";
                }

                if (matches[3].matched) // hsl:x:y:z
                {
                    long hNumerator = atoi(string(matches[4]).c_str());
                    long sNumerator = atoi(string(matches[7]).c_str());
                    long lNumerator = atoi(string(matches[10]).c_str());
                    long hDenominator = 1;
                    long sDenominator = 1;
                    long lDenominator = 1;

                    if (matches[6].matched)
                    {
                        hDenominator = atoi(string(matches[6]).c_str());
                        if (hDenominator == 0)
                        {
                            hNumerator = 0;
                            hDenominator = 1;
                        }
                    }
                    if (matches[9].matched)
                    {
                        sDenominator = atoi(string(matches[9]).c_str());
                        if (sDenominator == 0)
                        {
                            sNumerator = 0;
                            sDenominator = 1;
                        }
                    }
                    if (matches[12].matched)
                    {
                        lDenominator = atoi(string(matches[12]).c_str());
                        if (lDenominator == 0)
                        {
                            lNumerator = 0;
                            lDenominator = 1;
                        }
                    }

                    if (hNumerator >= hDenominator)
                    {
                        hNumerator %= hDenominator;
                    }

                    HSL<fraction>::vector t (round(fraction(hNumerator, hDenominator), precision),
                                            round(fraction(sNumerator, sDenominator), precision),
                                            round(fraction(lNumerator, lDenominator), precision));

                    reply  = "<set xmlns='http://colouri.se/2012'>";
                    if (sPrecision != "")
                    {
                        reply += sPrecision;
                    }
                    reply += xml(t, false, precision);

                    RGB<fraction>::vector tr = t;
                    reply += xml(tr, false, precision);

                    reply += xmlpicker (t, precision);

                    reply += "</set>";
                }

                if (matches[13].matched) // rgb:x:y:z
                {
                    long rNumerator = atoi(string(matches[14]).c_str());
                    long gNumerator = atoi(string(matches[17]).c_str());
                    long bNumerator = atoi(string(matches[20]).c_str());
                    long rDenominator = 1;
                    long gDenominator = 1;
                    long bDenominator = 1;

                    if (matches[16].matched)
                    {
                        rDenominator = atoi(string(matches[16]).c_str());
                        if (rDenominator == 0)
                        {
                            rNumerator = 0;
                            rDenominator = 1;
                        }
                    }
                    if (matches[19].matched)
                    {
                        gDenominator = atoi(string(matches[19]).c_str());
                        if (gDenominator == 0)
                        {
                            gNumerator = 0;
                            gDenominator = 1;
                        }
                    }
                    if (matches[22].matched)
                    {
                        bDenominator = atoi(string(matches[22]).c_str());
                        if (bDenominator == 0)
                        {
                            bNumerator = 0;
                            bDenominator = 1;
                        }
                    }

                    RGB<fraction>::vector t (round(fraction(rNumerator, rDenominator), precision),
                                            round(fraction(gNumerator, gDenominator), precision),
                                            round(fraction(bNumerator, bDenominator), precision));

                    reply  = "<set xmlns='http://colouri.se/2012'>";
                    if (sPrecision != "")
                    {
                        reply += sPrecision;
                    }
                    reply += xml(t, false, precision);

                    HSL<fraction>::vector tr = t;
                    reply += xml(tr, false, precision);

                    reply += xmlpicker (t, precision);

                    reply += "</set>";
                }

                a.reply (200,
                         "Content-Type: text/xml; charset=utf-8\r\n",
                         string("<?xml version='1.0' encoding='utf-8'?>")
                         + reply);
            }
            else
            {
                a.reply (404,
                         "Content-Type: text/xml; charset=utf-8\r\n",
                         "<?xml version='1.0' encoding='utf-8'?>"
                         "<error xmlns='http://colouri.se/2012'>404</error>");
            }

            return true;
        }
};

int main (int argc, char* argv[])
{
    try
    {
        if (argc != 2)
        {
            std::cerr << "Usage: colourise <socket>\n";
            return 1;
        }

        boost::asio::io_service io_service;

        efgy::net::http::server<processColourise> s(io_service, argv[1]);

        io_service.run();
    }
    catch (std::exception &e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }

    return 0;
}
<commit_msg>updated to use the new vectors<commit_after>/*
 * This file is part of the colouri.se project.
 * See the appropriate repository at http://colouri.se/.git for exact file
 * modification records.
*/

/*
 * Copyright (c) 2012, ef.gy Project Members
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
*/

#include <ef.gy/http.h>
#include <ef.gy/fractions.h>
#include <ef.gy/colour-space-hsl.h>

#include <iostream>
#include <boost/regex.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>

#include <ef.gy/render-xml.h>

#include <ef.gy/continued-fractions.h>

using namespace efgy;
using namespace efgy::math;
using namespace efgy::render;
using namespace boost::filesystem;
using namespace boost::iostreams;
using namespace boost::asio;
using namespace boost;
using namespace std;

class processColourise
{
    public:
        bool operator () (efgy::net::http::session<processColourise> &a)
        {
            static const regex rq
                ("/generated/(x?html|svg)/("
                  "(hsl:(-?\\d+)(/(-?\\d+))?:(-?\\d+)(/(-?\\d+))?:(-?\\d+)(/(-?\\d+))?)"
                 "|(rgb:(-?\\d+)(/(-?\\d+))?:(-?\\d+)(/(-?\\d+))?:(-?\\d+)(/(-?\\d+))?)"
                 ")(.(\\d+))?");
            boost::smatch matches;

            if (regex_match(a.resource, matches, rq))
            {
                string reply = string("<colour xmlns='http://colouri.se/2012'>")
                             + a.method + " " + a.resource
                             + "</colour>";

                unsigned long precision = 24;
                string sPrecision;

                if (matches[24].matched)
                {
                    sPrecision = matches[24];
                    precision = atoi(sPrecision.c_str());
                    sPrecision = "<precision>" + sPrecision + "</precision>";
                }

                if (matches[3].matched) // hsl:x:y:z
                {
                    long hNumerator = atoi(string(matches[4]).c_str());
                    long sNumerator = atoi(string(matches[7]).c_str());
                    long lNumerator = atoi(string(matches[10]).c_str());
                    long hDenominator = 1;
                    long sDenominator = 1;
                    long lDenominator = 1;

                    if (matches[6].matched)
                    {
                        hDenominator = atoi(string(matches[6]).c_str());
                        if (hDenominator == 0)
                        {
                            hNumerator = 0;
                            hDenominator = 1;
                        }
                    }
                    if (matches[9].matched)
                    {
                        sDenominator = atoi(string(matches[9]).c_str());
                        if (sDenominator == 0)
                        {
                            sNumerator = 0;
                            sDenominator = 1;
                        }
                    }
                    if (matches[12].matched)
                    {
                        lDenominator = atoi(string(matches[12]).c_str());
                        if (lDenominator == 0)
                        {
                            lNumerator = 0;
                            lDenominator = 1;
                        }
                    }

                    if (hNumerator >= hDenominator)
                    {
                        hNumerator %= hDenominator;
                    }

                    math::vector<fraction,3,space::HSL> t (round(fraction(hNumerator, hDenominator), precision),
                                            round(fraction(sNumerator, sDenominator), precision),
                                            round(fraction(lNumerator, lDenominator), precision));

                    reply  = "<set xmlns='http://colouri.se/2012'>";
                    if (sPrecision != "")
                    {
                        reply += sPrecision;
                    }
                    reply += xml(t, false, precision);

                    math::vector<fraction,3,space::RGB> tr = t;
                    reply += xml(tr, false, precision);

                    reply += xmlpicker (t, precision);

                    reply += "</set>";
                }

                if (matches[13].matched) // rgb:x:y:z
                {
                    long rNumerator = atoi(string(matches[14]).c_str());
                    long gNumerator = atoi(string(matches[17]).c_str());
                    long bNumerator = atoi(string(matches[20]).c_str());
                    long rDenominator = 1;
                    long gDenominator = 1;
                    long bDenominator = 1;

                    if (matches[16].matched)
                    {
                        rDenominator = atoi(string(matches[16]).c_str());
                        if (rDenominator == 0)
                        {
                            rNumerator = 0;
                            rDenominator = 1;
                        }
                    }
                    if (matches[19].matched)
                    {
                        gDenominator = atoi(string(matches[19]).c_str());
                        if (gDenominator == 0)
                        {
                            gNumerator = 0;
                            gDenominator = 1;
                        }
                    }
                    if (matches[22].matched)
                    {
                        bDenominator = atoi(string(matches[22]).c_str());
                        if (bDenominator == 0)
                        {
                            bNumerator = 0;
                            bDenominator = 1;
                        }
                    }

                    math::vector<fraction,3,space::RGB> t (round(fraction(rNumerator, rDenominator), precision),
                                            round(fraction(gNumerator, gDenominator), precision),
                                            round(fraction(bNumerator, bDenominator), precision));

                    reply  = "<set xmlns='http://colouri.se/2012'>";
                    if (sPrecision != "")
                    {
                        reply += sPrecision;
                    }
                    reply += xml(t, false, precision);

                    math::vector<fraction,3,space::HSL> tr = t;
                    reply += xml(tr, false, precision);

                    reply += xmlpicker (t, precision);

                    reply += "</set>";
                }

                a.reply (200,
                         "Content-Type: text/xml; charset=utf-8\r\n",
                         string("<?xml version='1.0' encoding='utf-8'?>")
                         + reply);
            }
            else
            {
                a.reply (404,
                         "Content-Type: text/xml; charset=utf-8\r\n",
                         "<?xml version='1.0' encoding='utf-8'?>"
                         "<error xmlns='http://colouri.se/2012'>404</error>");
            }

            return true;
        }
};

int main (int argc, char* argv[])
{
    try
    {
        if (argc != 2)
        {
            std::cerr << "Usage: colourise <socket>\n";
            return 1;
        }

        boost::asio::io_service io_service;

        efgy::net::http::server<processColourise> s(io_service, argv[1]);

        io_service.run();
    }
    catch (std::exception &e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "common/io.h"

#include "3rd_party/cnpy/cnpy.h"
#include "common/shape.h"
#include "common/types.h"

#include "common/io_item.h"
#include "common/binary.h"

namespace marian {

namespace io {

bool isNpz(const std::string& fileName) {
  return fileName.size() >= 4 && fileName.substr(fileName.length() - 4) == ".npz";
}

bool isBin(const std::string& fileName) {
  return fileName.size() >= 4 && fileName.substr(fileName.length() - 4) == ".bin";
}

void getYamlFromNpz(YAML::Node& yaml,
                    const std::string& varName,
                    const std::string& fileName) {
  auto item = cnpy::npz_load(fileName, varName);
  if(item->size() > 0)
    yaml = YAML::Load(item->data());
}

void getYamlFromBin(YAML::Node& yaml,
                    const std::string& varName,
                    const std::string& fileName) {
  auto item = binary::getItem(fileName, varName);
  if(item.size() > 0)
    yaml = YAML::Load(item.data());
}

void getYamlFromModel(YAML::Node& yaml,
                      const std::string& varName,
                      const std::string& fileName) {
  if(io::isNpz(fileName)) {
    io::getYamlFromNpz(yaml, varName, fileName);
  }
  else if(io::isBin(fileName)) {
    io::getYamlFromBin(yaml, varName, fileName);
  }
  else {
    ABORT("Unknown model file format for file {}", fileName);
  }
}

void getYamlFromModel(YAML::Node& yaml,
                      const std::string& varName,
                      const void* ptr) {
  auto item = binary::getItem(ptr, varName);
  if(item.size() > 0)
    yaml = YAML::Load(item.data());
}

void addMetaToItems(const std::string& meta,
                    const std::string& varName,
                    std::vector<io::Item>& items) {
  Item item;

  item.name = varName;

  // increase size by 1 to add \0
  item.shape = Shape({(int)meta.size() + 1});

  item.bytes.resize(item.shape[0]);
  std::copy(meta.begin(), meta.end() + item.shape[0], item.bytes.begin());

  item.type = Type::int8;

  items.push_back(item);
}

void loadItemsFromNpz(const std::string& fileName, std::vector<Item>& items) {
    auto numpy = cnpy::npz_load(fileName);
    for(auto it : numpy) {

      Shape shape;
      if(it.second->shape.size() == 1) {
        shape.resize(2);
        shape.set(0, 1);
        shape.set(1, it.second->shape[0]);
      } else {
        shape.resize(it.second->shape.size());
        for(size_t i = 0; i < it.second->shape.size(); ++i)
          shape.set(i, it.second->shape[i]);
      }

      Item item;
      item.name = it.first;
      item.shape = shape;
      item.bytes.swap(it.second->bytes);

      items.emplace_back(std::move(item));
    }
}

std::vector<Item> loadItems(const std::string& fileName) {
  std::vector<Item> items;
  if(isNpz(fileName)) {
    loadItemsFromNpz(fileName, items);
  }
  else if(isBin(fileName)) {
    binary::loadItems(fileName, items);
  }
  else {
    ABORT("Unknown model file format for file {}", fileName);
  }

  return items;
}

std::vector<Item> loadItems(const void* ptr) {
  std::vector<Item> items;
  binary::loadItems(ptr, items, false);
  return items;
}

std::vector<Item> mmapItems(const void* ptr) {
  std::vector<Item> items;
  binary::loadItems(ptr, items, true);
  return items;
}

// @TODO: make cnpy and our wrapper talk to each other in terms of types
// or implement our own saving routines for npz based on npy, probably better.
void saveItemsNpz(const std::string& fileName, const std::vector<Item>& items) {
  std::vector<cnpy::NpzItem> npzItems;
  for(auto& item : items) {
    std::vector<unsigned int> shape(item.shape.begin(), item.shape.end());
    if(item.type == Type::float32)
      npzItems.push_back(cnpy::NpzItem(item.name,
                                       item.bytes,
                                       shape,
                                       cnpy::map_type(typeid(float)),
                                       sizeOf(Type::float32)));
    else if(item.type == Type::int8) {
      npzItems.push_back(cnpy::NpzItem(item.name,
                                       item.bytes,
                                       shape,
                                       cnpy::map_type(typeid(char)),
                                       sizeOf(Type::int8)));
    }
    else {
      ABORT("Type currently not supported");
    }
  }
  cnpy::npz_save(fileName, npzItems);
}

void saveItems(const std::string& fileName, const std::vector<Item>& items) {
  if(isNpz(fileName)) {
    saveItemsNpz(fileName, items);
  }
  else if(isBin(fileName)) {
    binary::saveItems(fileName, items);
  }
  else {
    ABORT("Unknown file format for file {}", fileName);
  }
}

}
}
<commit_msg>use emplace_back<commit_after>#include "common/io.h"

#include "3rd_party/cnpy/cnpy.h"
#include "common/shape.h"
#include "common/types.h"

#include "common/io_item.h"
#include "common/binary.h"

namespace marian {

namespace io {

bool isNpz(const std::string& fileName) {
  return fileName.size() >= 4 && fileName.substr(fileName.length() - 4) == ".npz";
}

bool isBin(const std::string& fileName) {
  return fileName.size() >= 4 && fileName.substr(fileName.length() - 4) == ".bin";
}

void getYamlFromNpz(YAML::Node& yaml,
                    const std::string& varName,
                    const std::string& fileName) {
  auto item = cnpy::npz_load(fileName, varName);
  if(item->size() > 0)
    yaml = YAML::Load(item->data());
}

void getYamlFromBin(YAML::Node& yaml,
                    const std::string& varName,
                    const std::string& fileName) {
  auto item = binary::getItem(fileName, varName);
  if(item.size() > 0)
    yaml = YAML::Load(item.data());
}

void getYamlFromModel(YAML::Node& yaml,
                      const std::string& varName,
                      const std::string& fileName) {
  if(io::isNpz(fileName)) {
    io::getYamlFromNpz(yaml, varName, fileName);
  }
  else if(io::isBin(fileName)) {
    io::getYamlFromBin(yaml, varName, fileName);
  }
  else {
    ABORT("Unknown model file format for file {}", fileName);
  }
}

void getYamlFromModel(YAML::Node& yaml,
                      const std::string& varName,
                      const void* ptr) {
  auto item = binary::getItem(ptr, varName);
  if(item.size() > 0)
    yaml = YAML::Load(item.data());
}

void addMetaToItems(const std::string& meta,
                    const std::string& varName,
                    std::vector<io::Item>& items) {
  Item item;

  item.name = varName;

  // increase size by 1 to add \0
  item.shape = Shape({(int)meta.size() + 1});

  item.bytes.resize(item.shape[0]);
  std::copy(meta.begin(), meta.end() + item.shape[0], item.bytes.begin());

  item.type = Type::int8;

  items.push_back(item);
}

void loadItemsFromNpz(const std::string& fileName, std::vector<Item>& items) {
    auto numpy = cnpy::npz_load(fileName);
    for(auto it : numpy) {

      Shape shape;
      if(it.second->shape.size() == 1) {
        shape.resize(2);
        shape.set(0, 1);
        shape.set(1, it.second->shape[0]);
      } else {
        shape.resize(it.second->shape.size());
        for(size_t i = 0; i < it.second->shape.size(); ++i)
          shape.set(i, it.second->shape[i]);
      }

      Item item;
      item.name = it.first;
      item.shape = shape;
      item.bytes.swap(it.second->bytes);

      items.emplace_back(std::move(item));
    }
}

std::vector<Item> loadItems(const std::string& fileName) {
  std::vector<Item> items;
  if(isNpz(fileName)) {
    loadItemsFromNpz(fileName, items);
  }
  else if(isBin(fileName)) {
    binary::loadItems(fileName, items);
  }
  else {
    ABORT("Unknown model file format for file {}", fileName);
  }

  return items;
}

std::vector<Item> loadItems(const void* ptr) {
  std::vector<Item> items;
  binary::loadItems(ptr, items, false);
  return items;
}

std::vector<Item> mmapItems(const void* ptr) {
  std::vector<Item> items;
  binary::loadItems(ptr, items, true);
  return items;
}

// @TODO: make cnpy and our wrapper talk to each other in terms of types
// or implement our own saving routines for npz based on npy, probably better.
void saveItemsNpz(const std::string& fileName, const std::vector<Item>& items) {
  std::vector<cnpy::NpzItem> npzItems;
  for(auto& item : items) {
    std::vector<unsigned int> shape(item.shape.begin(), item.shape.end());
    if(item.type == Type::float32)
      npzItems.emplace_back(item.name,
                            item.bytes,
                            shape,
                            cnpy::map_type(typeid(float)),
                            sizeOf(Type::float32));
    else if(item.type == Type::int8) {
      npzItems.emplace_back(item.name,
                            item.bytes,
                            shape,
                            cnpy::map_type(typeid(char)),
                            sizeOf(Type::int8));
    }
    else {
      ABORT("Type currently not supported");
    }
  }
  cnpy::npz_save(fileName, npzItems);
}

void saveItems(const std::string& fileName, const std::vector<Item>& items) {
  if(isNpz(fileName)) {
    saveItemsNpz(fileName, items);
  }
  else if(isBin(fileName)) {
    binary::saveItems(fileName, items);
  }
  else {
    ABORT("Unknown file format for file {}", fileName);
  }
}

}
}
<|endoftext|>