<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "UiModule.h"
#include "UiProxyWidget.h"
#include "UiWidgetProperties.h"
#include "UiProxyStyle.h"
#include "UiStateMachine.h"

// Private managers
#include "Console/UiConsoleManager.h"
#include "Ether/EtherLogic.h"
#include "Ether/View/EtherScene.h"

#include "NetworkEvents.h"
#include "SceneEvents.h"
#include "ConsoleEvents.h"

#include <QApplication>
#include <QDir>

namespace UiServices
{
    UiModule::UiModule()
        : Foundation::ModuleInterfaceImpl(Foundation::Module::MT_UiServices),
          event_query_categories_(QStringList()),
          ui_scene_manager_(0),
          ui_notification_manager_(0)
    {
    }

    UiModule::~UiModule()
    {
        SAFE_DELETE(ui_state_machine_);
        SAFE_DELETE(ui_scene_manager_);
        SAFE_DELETE(ui_notification_manager_);
    }

    /*************** ModuleInterfaceImpl ***************/

    void UiModule::Load()
    {
        QApplication::setStyle(new UiProxyStyle());
        event_query_categories_ << "Framework" << "Scene"  << "Console";
        LogInfo(Name() + " loaded.");
    }

    void UiModule::Unload()
    {
        LogInfo(Name() + " unloaded.");
    }

    void UiModule::Initialize()
    {
        ui_view_ = framework_->GetUIView();
        if (ui_view_)
        {
            LogDebug("Acquired Ogre QGraphicsView shared pointer from framework");

            ui_state_machine_ = new UiStateMachine(0, ui_view_);
            ui_state_machine_->RegisterScene("Inworld", ui_view_->scene());
            LogDebug("State Machine STARTED");

            ui_scene_manager_ = new UiSceneManager(GetFramework(), ui_view_);
            LogDebug("Scene Manager service READY");

            ui_notification_manager_ = new UiNotificationManager(GetFramework(), ui_view_);
            LogDebug("Notification Manager service READY");

            ui_console_manager_ = new CoreUi::UiConsoleManager(GetFramework(), ui_view_);
            LogDebug("Console UI READY");

            LogInfo(Name() + " initialized.");
        }
        else
            LogWarning("Could not accuire QGraphicsView shared pointer from framework, UiServices are disabled");
    }

    void UiModule::PostInitialize()
    {
        SubscribeToEventCategories();
        ui_console_manager_->SendInitializationReadyEvent();

        ether_logic_ = new Ether::Logic::EtherLogic(GetFramework(), ui_view_);
        ui_state_machine_->RegisterScene("Ether", ether_logic_->GetScene());
        ether_logic_->Start();
        //ui_state_machine_->SwitchToEtherScene(); // uncomment when ether is default on startup
        LogDebug("Ether Logic STARTED");
    }

    void UiModule::Uninitialize()
    {
        LogInfo(Name() + " uninitialized.");
    }

    void UiModule::Update(f64 frametime)
    {
    }

    bool UiModule::HandleEvent(event_category_id_t category_id, event_id_t event_id, Foundation::EventDataInterface* data)
    {
        PROFILE(UiModule_HandleEvent);

        QString category = service_category_identifiers_.keys().value(service_category_identifiers_.values().indexOf(category_id));
        if (category == "Framework")
        {
            switch (event_id)
            {
                case Foundation::NETWORKING_REGISTERED:
                    event_query_categories_ << "NetworkState";
                    SubscribeToEventCategories();
                    break;
                default:
                    break;
            }
        }
        else if (category == "NetworkState")
        {
            switch (event_id)
            {
                case ProtocolUtilities::Events::EVENT_SERVER_DISCONNECTED:
                {
                    ether_logic_->UpdateUiPixmaps();
                    //ui_state_machine_->SwitchToEtherScene();
                    ui_scene_manager_->Disconnected();
                    break;
                }
                case ProtocolUtilities::Events::EVENT_SERVER_CONNECTED:
                {
                    ProtocolUtilities::AuthenticationEventData *auth_data = dynamic_cast<ProtocolUtilities::AuthenticationEventData *>(data);
                    if (auth_data)
                    {
                        current_avatar_ = QString::fromStdString(auth_data->identityUrl);
                        current_server_ = QString::fromStdString(auth_data->hostUrl);
                    }
                    break;
                }
                default:
                    break;
            }
        }
        else if (category == "Console")
        {
            switch (event_id)
            {
            case Console::Events::EVENT_CONSOLE_TOGGLE:
                ui_console_manager_->ToggleConsole();
                break;
            case Console::Events::EVENT_CONSOLE_PRINT_LINE:
                Console::ConsoleEventData* console_data=dynamic_cast<Console::ConsoleEventData*>(data);
                ui_console_manager_->QueuePrintRequest(QString(console_data->message.c_str()));
                break;
            }
        }
        else if (category == "Scene")
        {
            switch (event_id)
            {
                case Scene::Events::EVENT_CONTROLLABLE_ENTITY:
                {
                    ui_state_machine_->SwitchToInworldScene();
                    ui_scene_manager_->Connected();
                    QString welcome_message;
                    if (!current_avatar_.isEmpty())
                        welcome_message = current_avatar_ + " welcome to " + current_server_;
                    else
                        welcome_message = "Welcome to " + current_server_;
                    ui_notification_manager_->ShowInformationString(welcome_message, 10000);
                    break;
                }
                default:
                    break;
            }
        }

        return false;
    }

    void UiModule::SubscribeToEventCategories()
    {
        service_category_identifiers_.clear();
        foreach (QString category, event_query_categories_)
        {
            service_category_identifiers_[category] = framework_->GetEventManager()->QueryEventCategory(category.toStdString());
            LogDebug(QString("Listening to event category %1").arg(category).toStdString());
        }
    }

    void UiModule::SetLoginHandlers(RexLogic::OpenSimLoginHandler *os_login_handler)
    {
        ether_logic_->SetLoginHandlers(os_login_handler);
    }

    QPair<QString, QString> UiModule::GetScreenshotPaths()
    {
        return ether_logic_->GetLastLoginScreenshotData(framework_->GetConfigManager()->GetPath());
    }

}

/************** Poco Module Loading System **************/

extern "C" void POCO_LIBRARY_API SetProfiler(Foundation::Profiler *profiler);
void SetProfiler(Foundation::Profiler *profiler)
{
    Foundation::ProfilerSection::SetProfiler(profiler);
}

using namespace UiServices;

POCO_BEGIN_MANIFEST(Foundation::ModuleInterface)
   POCO_EXPORT_CLASS(UiModule)
POCO_END_MANIFEST

<commit_msg>* Removed code back to get correct internal events to make login animations work again<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "UiModule.h"
#include "UiProxyWidget.h"
#include "UiWidgetProperties.h"
#include "UiProxyStyle.h"
#include "UiStateMachine.h"

// Private managers
#include "Console/UiConsoleManager.h"
#include "Ether/EtherLogic.h"
#include "Ether/View/EtherScene.h"

#include "NetworkEvents.h"
#include "SceneEvents.h"
#include "ConsoleEvents.h"

#include <QApplication>
#include <QDir>

namespace UiServices
{
    UiModule::UiModule()
        : Foundation::ModuleInterfaceImpl(Foundation::Module::MT_UiServices),
          event_query_categories_(QStringList()),
          ui_scene_manager_(0),
          ui_notification_manager_(0)
    {
    }

    UiModule::~UiModule()
    {
        SAFE_DELETE(ui_state_machine_);
        SAFE_DELETE(ui_scene_manager_);
        SAFE_DELETE(ui_notification_manager_);
    }

    /*************** ModuleInterfaceImpl ***************/

    void UiModule::Load()
    {
        QApplication::setStyle(new UiProxyStyle());
        event_query_categories_ << "Framework" << "Scene"  << "Console";
        LogInfo(Name() + " loaded.");
    }

    void UiModule::Unload()
    {
        LogInfo(Name() + " unloaded.");
    }

    void UiModule::Initialize()
    {
        ui_view_ = framework_->GetUIView();
        if (ui_view_)
        {
            LogDebug("Acquired Ogre QGraphicsView shared pointer from framework");

            ui_state_machine_ = new UiStateMachine(0, ui_view_);
            ui_state_machine_->RegisterScene("Inworld", ui_view_->scene());
            LogDebug("State Machine STARTED");

            ui_scene_manager_ = new UiSceneManager(GetFramework(), ui_view_);
            LogDebug("Scene Manager service READY");

            ui_notification_manager_ = new UiNotificationManager(GetFramework(), ui_view_);
            LogDebug("Notification Manager service READY");

            ui_console_manager_ = new CoreUi::UiConsoleManager(GetFramework(), ui_view_);
            LogDebug("Console UI READY");

            LogInfo(Name() + " initialized.");
        }
        else
            LogWarning("Could not accuire QGraphicsView shared pointer from framework, UiServices are disabled");
    }

    void UiModule::PostInitialize()
    {
        SubscribeToEventCategories();
        ui_console_manager_->SendInitializationReadyEvent();

        ether_logic_ = new Ether::Logic::EtherLogic(GetFramework(), ui_view_);
        ui_state_machine_->RegisterScene("Ether", ether_logic_->GetScene());
        ether_logic_->Start();
        //ui_state_machine_->SwitchToEtherScene(); // uncomment when ether is default on startup
        LogDebug("Ether Logic STARTED");
    }

    void UiModule::Uninitialize()
    {
        LogInfo(Name() + " uninitialized.");
    }

    void UiModule::Update(f64 frametime)
    {
    }

    bool UiModule::HandleEvent(event_category_id_t category_id, event_id_t event_id, Foundation::EventDataInterface* data)
    {
        PROFILE(UiModule_HandleEvent);

        QString category = service_category_identifiers_.keys().value(service_category_identifiers_.values().indexOf(category_id));
        if (category == "Framework")
        {
            switch (event_id)
            {
                case Foundation::NETWORKING_REGISTERED:
                    event_query_categories_ << "NetworkState";
                    SubscribeToEventCategories();
                    break;
                default:
                    break;
            }
        }
        else if (category == "NetworkState")
        {
            switch (event_id)
            {
                case ProtocolUtilities::Events::EVENT_CONNECTION_FAILED:
                {
                    ether_logic_->SetConnectionState("failed");
                    break;
                }
                case ProtocolUtilities::Events::EVENT_SERVER_DISCONNECTED:
                {
                    ether_logic_->UpdateUiPixmaps();
                    ether_logic_->SetConnectionState("disconnected");
                    //ui_state_machine_->SwitchToEtherScene();
                    ui_scene_manager_->Disconnected();
                    break;
                }
                case ProtocolUtilities::Events::EVENT_SERVER_CONNECTED:
                {
                    ProtocolUtilities::AuthenticationEventData *auth_data = dynamic_cast<ProtocolUtilities::AuthenticationEventData *>(data);
                    if (auth_data)
                    {
                        current_avatar_ = QString::fromStdString(auth_data->identityUrl);
                        current_server_ = QString::fromStdString(auth_data->hostUrl);
                    }
                    break;
                }
                default:
                    break;
            }
        }
        else if (category == "Console")
        {
            switch (event_id)
            {
            case Console::Events::EVENT_CONSOLE_TOGGLE:
                ui_console_manager_->ToggleConsole();
                break;
            case Console::Events::EVENT_CONSOLE_PRINT_LINE:
                Console::ConsoleEventData* console_data=dynamic_cast<Console::ConsoleEventData*>(data);
                ui_console_manager_->QueuePrintRequest(QString(console_data->message.c_str()));
                break;
            }
        }
        else if (category == "Scene")
        {
            switch (event_id)
            {
                case Scene::Events::EVENT_CONTROLLABLE_ENTITY:
                {
                    ui_state_machine_->SwitchToInworldScene();
                    ui_scene_manager_->Connected();
                    ether_logic_->SetConnectionState("connected");

                    QString welcome_message;
                    if (!current_avatar_.isEmpty())
                        welcome_message = current_avatar_ + " welcome to " + current_server_;
                    else
                        welcome_message = "Welcome to " + current_server_;
                    ui_notification_manager_->ShowInformationString(welcome_message, 10000);
                    break;
                }
                default:
                    break;
            }
        }

        return false;
    }

    void UiModule::SubscribeToEventCategories()
    {
        service_category_identifiers_.clear();
        foreach (QString category, event_query_categories_)
        {
            service_category_identifiers_[category] = framework_->GetEventManager()->QueryEventCategory(category.toStdString());
            LogDebug(QString("Listening to event category %1").arg(category).toStdString());
        }
    }

    void UiModule::SetLoginHandlers(RexLogic::OpenSimLoginHandler *os_login_handler)
    {
        ether_logic_->SetLoginHandlers(os_login_handler);
    }

    QPair<QString, QString> UiModule::GetScreenshotPaths()
    {
        return ether_logic_->GetLastLoginScreenshotData(framework_->GetConfigManager()->GetPath());
    }

}

/************** Poco Module Loading System **************/

extern "C" void POCO_LIBRARY_API SetProfiler(Foundation::Profiler *profiler);
void SetProfiler(Foundation::Profiler *profiler)
{
    Foundation::ProfilerSection::SetProfiler(profiler);
}

using namespace UiServices;

POCO_BEGIN_MANIFEST(Foundation::ModuleInterface)
   POCO_EXPORT_CLASS(UiModule)
POCO_END_MANIFEST

<|endoftext|>


<commit_before>#include <cstring>
#include <string>
#include <vector>
#include <istream>
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <map>

#include "status.hpp"

Status::Status() {
    //std::cout << "status constructor called\n";
};

Status::~Status() {
    //std::cout << "status destructor called\n";
};

CommandLineArgs Status::options(int n_opts, char *opts[]) {
    CommandLineArgs args;

    args.group = "Default";

    for (int i = 1; i < n_opts; ++i) {
        if (opts[i][1] == 'f') {
            ++i;
            args.format = opts[i];
        } else if (opts[i][1] == 'q') {
            args.quiet = true;
        } else if (opts[i][1] == 'v') {
            args.verbose = true;
        } else if (opts[i][1] == 'r') {
            ++i;
            args.resource = opts[i];
        } else if (opts[i][1] == 'g') {
            ++i;
            args.group = opts[i];
        } else if (opts[i][1] == 'h') {
            usage(opts[0]);
            exit(1);
        } else if (opts[i][1] == 'c') {
            ++i;
            args.config = opts[i];
        } else {
            //usage(opts[0]);
        }
    }
    args.check(opts[0]);
    return args;
}

int Status::usage(const char *progname) {
    const char *name = progname;
    while (*progname != 0) {
        if (*progname == '/' || *progname == '\\') {
            ++progname;
            name = progname;
        } else {
            ++progname;
        }
    }

    cout << "ml-utils: ml-status 1.0 | copyright (c)2015 Jim Fuller | see https://github.com/xquery/ml-utils" << endl;
    cout << "retrieve MarkLogic resource status" << endl;
    cout << ">" << name << " Resources/resource [options]" << endl;
    cout << "    -c    : config file (ex. /home/jfuller/.ml-utils)" << endl;
    cout << "    -f    : format (xml|json)" << endl;
    cout << "    -v    : verbose (show http call)" << endl;
    cout << "    -q    : quiet (suppress banner)" << endl;
    return EXIT_SUCCESS;
}<commit_msg>correct help for ml-status<commit_after>#include <cstring>
#include <string>
#include <vector>
#include <istream>
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <map>

#include "status.hpp"

Status::Status() {
    //std::cout << "status constructor called\n";
};

Status::~Status() {
    //std::cout << "status destructor called\n";
};

CommandLineArgs Status::options(int n_opts, char *opts[]) {
    CommandLineArgs args;

    args.group = "Default";

    for (int i = 1; i < n_opts; ++i) {
        if (opts[i][1] == 'f') {
            ++i;
            args.format = opts[i];
        } else if (opts[i][1] == 'q') {
            args.quiet = true;
        } else if (opts[i][1] == 'v') {
            args.verbose = true;
        } else if (opts[i][1] == 'r') {
            ++i;
            args.resource = opts[i];
        } else if (opts[i][1] == 'g') {
            ++i;
            args.group = opts[i];
        } else if (opts[i][1] == 'h') {
            usage(opts[0]);
            exit(1);
        } else if (opts[i][1] == 'c') {
            ++i;
            args.config = opts[i];
        } else {
            //usage(opts[0]);
        }
    }
    args.check(opts[0]);
    return args;
}

int Status::usage(const char *progname) {
    const char *name = progname;
    while (*progname != 0) {
        if (*progname == '/' || *progname == '\\') {
            ++progname;
            name = progname;
        } else {
            ++progname;
        }
    }

    cout << "ml-utils: ml-status 1.0 | copyright (c)2015 Jim Fuller | see https://github.com/xquery/ml-utils" << endl;
    cout << "retrieve MarkLogic resource status" << endl;
    cout << ">" << name << " Resources/resource [options]" << endl;
    cout << "    -c    : config file (ex. /home/jfuller/.ml-utils)" << endl;
    cout << "    -f    : format (xml|json)" << endl;
    cout << "    -r    : resource (databases|forests|servers|hosts) / resource-name" << endl;
    cout << "    -v    : verbose (show http call)" << endl;
    cout << "    -q    : quiet (suppress banner)" << endl;
    return EXIT_SUCCESS;
}<|endoftext|>


<commit_before>#include <DuiLocale>
#include <DuiTheme>

#include "sysuid.h"

Sysuid::Sysuid() : QObject()
{
    qDebug() << "starting sysuidaemon";

    /* Pincode query variables */
    DuiTheme::addPixmapDirectory("./");
    DuiTheme::loadCSS("pinquery.css");
    pinCodeQueryLogic = new PinCodeQueryBusinessLogic();

    /* Energy UI */
    batteryLogic = new BatteryBusinessLogic();

    /* Lockscreen */
    lockScreenLogic = new LockScreenBusinessLogic();
    connect(lockScreenLogic, SIGNAL(lockScreenOff()), batteryLogic, SLOT(checkBattery()));

}

Sysuid::~Sysuid()
{
    delete pinCodeQueryLogic;
    pinCodeQueryLogic = NULL;
    //delete batteryLogic;
    //batteryLogic = NULL;
}
<commit_msg>Minor additions to prevent possible memory leaks<commit_after>#include <DuiLocale>
#include <DuiTheme>

#include "sysuid.h"

Sysuid::Sysuid() : QObject()
{
    qDebug() << "starting sysuidaemon";

    /* Pincode query variables */
    DuiTheme::addPixmapDirectory("./");
    DuiTheme::loadCSS("pinquery.css");
    pinCodeQueryLogic = new PinCodeQueryBusinessLogic();

    /* Energy UI */
    batteryLogic = new BatteryBusinessLogic();

    /* Lockscreen */
    lockScreenLogic = new LockScreenBusinessLogic();
    connect(lockScreenLogic, SIGNAL(lockScreenOff()), batteryLogic, SLOT(checkBattery()));

}

Sysuid::~Sysuid()
{
    delete pinCodeQueryLogic;
    pinCodeQueryLogic = NULL;
    delete batteryLogic;
    batteryLogic = NULL;
    delete lockScreenLogic;
    lockScreenLogic = NULL;
}
<|endoftext|>


<commit_before>#ifndef unicode_hh_INCLUDED
#define unicode_hh_INCLUDED

#include <wctype.h>
#include <wchar.h>
#include <locale>

namespace Kakoune
{

using Codepoint = char32_t;

inline bool is_eol(Codepoint c)
{
    return c == '\n';
}

inline bool is_horizontal_blank(Codepoint c)
{
    return c == ' ' or c == '\t';
}

inline bool is_blank(Codepoint c)
{
    return c == ' ' or c == '\t' or c == '\n';
}

enum WordType { Word, WORD };

template<WordType word_type = Word>
inline bool is_word(Codepoint c)
{
    return c == '_' or iswalnum((wchar_t)c);
}

template<>
inline bool is_word<WORD>(Codepoint c)
{
    return not is_horizontal_blank(c) and not is_eol(c);
}

inline bool is_punctuation(Codepoint c)
{
    return not (is_word(c) or is_horizontal_blank(c) or is_eol(c));
}

inline bool is_basic_alpha(Codepoint c)
{
    return (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z');
}

inline size_t codepoint_width(Codepoint c)
{
    return wcwidth((wchar_t)c);
}

enum class CharCategories
{
    Blank,
    EndOfLine,
    Word,
    Punctuation,
};

template<WordType word_type = Word>
inline CharCategories categorize(Codepoint c)
{
    if (is_eol(c))
        return CharCategories::EndOfLine;
    if (is_horizontal_blank(c))
        return CharCategories::Blank;
    if (word_type == WORD or is_word(c))
        return CharCategories::Word;
    return CharCategories::Punctuation;
}

inline Codepoint to_lower(Codepoint cp) { return towlower((wchar_t)cp); }
inline Codepoint to_upper(Codepoint cp) { return towupper((wchar_t)cp); }

inline char to_lower(char c) { return c >= 'A' and c <= 'Z' ? c - 'A' + 'a' : c; }
inline char to_upper(char c) { return c >= 'a' and c <= 'z' ? c - 'a' + 'A' : c; }

}

#endif // unicode_hh_INCLUDED
<commit_msg>Treat '\n' as 1 column wide<commit_after>#ifndef unicode_hh_INCLUDED
#define unicode_hh_INCLUDED

#include <wctype.h>
#include <wchar.h>
#include <locale>

namespace Kakoune
{

using Codepoint = char32_t;

inline bool is_eol(Codepoint c)
{
    return c == '\n';
}

inline bool is_horizontal_blank(Codepoint c)
{
    return c == ' ' or c == '\t';
}

inline bool is_blank(Codepoint c)
{
    return c == ' ' or c == '\t' or c == '\n';
}

enum WordType { Word, WORD };

template<WordType word_type = Word>
inline bool is_word(Codepoint c)
{
    return c == '_' or iswalnum((wchar_t)c);
}

template<>
inline bool is_word<WORD>(Codepoint c)
{
    return not is_horizontal_blank(c) and not is_eol(c);
}

inline bool is_punctuation(Codepoint c)
{
    return not (is_word(c) or is_horizontal_blank(c) or is_eol(c));
}

inline bool is_basic_alpha(Codepoint c)
{
    return (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z');
}

inline size_t codepoint_width(Codepoint c)
{
    return c == '\n' ? 1 : wcwidth((wchar_t)c);
}

enum class CharCategories
{
    Blank,
    EndOfLine,
    Word,
    Punctuation,
};

template<WordType word_type = Word>
inline CharCategories categorize(Codepoint c)
{
    if (is_eol(c))
        return CharCategories::EndOfLine;
    if (is_horizontal_blank(c))
        return CharCategories::Blank;
    if (word_type == WORD or is_word(c))
        return CharCategories::Word;
    return CharCategories::Punctuation;
}

inline Codepoint to_lower(Codepoint cp) { return towlower((wchar_t)cp); }
inline Codepoint to_upper(Codepoint cp) { return towupper((wchar_t)cp); }

inline char to_lower(char c) { return c >= 'A' and c <= 'Z' ? c - 'A' + 'a' : c; }
inline char to_upper(char c) { return c >= 'a' and c <= 'z' ? c - 'a' + 'A' : c; }

}

#endif // unicode_hh_INCLUDED
<|endoftext|>


<commit_before>/*

Copyright (c) 2006, MassaRoddel, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/shared_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/peer_connection.hpp"
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/extensions.hpp"

#include "libtorrent/extensions/ut_pex.hpp"

namespace libtorrent { namespace
{
	const char extension_name[] = "ut_pex";

	enum
	{
		extension_index = 1,
		max_peer_entries = 100
	};

	bool send_peer(peer_connection const& p)
	{
		// don't send out peers that we haven't connected to
		// (that have connected to us)
		if (!p.is_local()) return false;
		// don't send out peers that we haven't successfully connected to
		if (p.is_connecting()) return false;
		return true;
	}

	struct ut_pex_plugin: torrent_plugin
	{
		ut_pex_plugin(torrent& t): m_torrent(t), m_1_minute(55) {}

		virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection* pc);

		std::vector<char>& get_ut_pex_msg()
		{
			return m_ut_pex_msg;
		}

		// the second tick of the torrent
		// each minute the new lists of "added" + "added.f" and "dropped"
		// are calculated here and the pex message is created
		// each peer connection will use this message
		// max_peer_entries limits the packet size
		virtual void tick()
		{
			if (++m_1_minute < 60) return;

			m_1_minute = 0;

			entry pex;
			std::string& pla = pex["added"].string();
			std::string& pld = pex["dropped"].string();
			std::string& plf = pex["added.f"].string();
			std::string& pla6 = pex["added6"].string();
			std::string& pld6 = pex["dropped6"].string();
			std::string& plf6 = pex["added6.f"].string();
			std::back_insert_iterator<std::string> pla_out(pla);
			std::back_insert_iterator<std::string> pld_out(pld);
			std::back_insert_iterator<std::string> plf_out(plf);
			std::back_insert_iterator<std::string> pla6_out(pla6);
			std::back_insert_iterator<std::string> pld6_out(pld6);
			std::back_insert_iterator<std::string> plf6_out(plf6);

			std::set<tcp::endpoint> dropped;
			m_old_peers.swap(dropped);

			int num_added = 0;
			for (torrent::peer_iterator i = m_torrent.begin()
				, end(m_torrent.end()); i != end; ++i)
			{
				peer_connection* peer = *i;
				if (!send_peer(*peer)) continue;

				tcp::endpoint const& remote = peer->remote();
				m_old_peers.insert(remote);

				std::set<tcp::endpoint>::iterator di = dropped.find(remote);
				if (di == dropped.end())
				{
					// don't write too big of a package
					if (num_added >= max_peer_entries) break;

					// only send proper bittorrent peers
					bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
					if (!p) continue;

					// no supported flags to set yet
					// 0x01 - peer supports encryption
					// 0x02 - peer is a seed
					int flags = p->is_seed() ? 2 : 0;
#ifndef TORRENT_DISABLE_ENCRYPTION
					flags |= p->supports_encryption() ? 1 : 0;
#endif
					// i->first was added since the last time
					if (remote.address().is_v4())
					{
						detail::write_endpoint(remote, pla_out);
						detail::write_uint8(flags, plf_out);
					}
					else
					{
						detail::write_endpoint(remote, pla6_out);
						detail::write_uint8(flags, plf6_out);
					}
					++num_added;
				}
				else
				{
					// this was in the previous message
					// so, it wasn't dropped
					dropped.erase(di);
				}
			}

			for (std::set<tcp::endpoint>::const_iterator i = dropped.begin()
				, end(dropped.end()); i != end; ++i)
			{
				if (i->address().is_v4())
					detail::write_endpoint(*i, pld_out);
				else
					detail::write_endpoint(*i, pld6_out);
			}

			m_ut_pex_msg.clear();
			bencode(std::back_inserter(m_ut_pex_msg), pex);
		}

	private:
		torrent& m_torrent;

		std::set<tcp::endpoint> m_old_peers;
		int m_1_minute;
		std::vector<char> m_ut_pex_msg;
	};

	struct ut_pex_peer_plugin : peer_plugin
	{
		ut_pex_peer_plugin(torrent& t, peer_connection& pc, ut_pex_plugin& tp)
			: m_torrent(t)
			, m_pc(pc)
			, m_tp(tp)
			, m_1_minute(55)
			, m_message_index(0)
			, m_first_time(true)
		{}

		virtual void add_handshake(entry& h)
		{
			entry& messages = h["m"];
			messages[extension_name] = extension_index;
		}

		virtual bool on_extension_handshake(entry const& h)
		{
			entry const& messages = h["m"];

			if (entry const* index = messages.find_key(extension_name))
			{
				m_message_index = index->integer();
				return true;
			}
			else
			{
				m_message_index = 0;
				return false;
			}
		}

		virtual bool on_extended(int length, int msg, buffer::const_interval body)
		{
			if (msg != extension_index) return false;
			if (m_message_index == 0) return false;

			if (length > 500 * 1024)
				throw protocol_error("uT peer exchange message larger than 500 kB");

			if (body.left() < length) return true;

			try
			{
				entry pex_msg = bdecode(body.begin, body.end);
				std::string const& peers = pex_msg["added"].string();
				std::string const& peer_flags = pex_msg["added.f"].string();

				int num_peers = peers.length() / 6;
				char const* in = peers.c_str();
				char const* fin = peer_flags.c_str();

				if (int(peer_flags.size()) != num_peers)
					return true;

				peer_id pid(0);
				policy& p = m_torrent.get_policy();
				for (int i = 0; i < num_peers; ++i)
				{
					tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in);
					char flags = detail::read_uint8(fin);
					p.peer_from_tracker(adr, pid, peer_info::pex, flags);
				}

				if (entry const* p6 = pex_msg.find_key("added6"))
				{
					std::string const& peers6 = p6->string();
					std::string const& peer6_flags = pex_msg["added6.f"].string();

					int num_peers = peers6.length() / 18;
					char const* in = peers6.c_str();
					char const* fin = peer6_flags.c_str();

					if (int(peer6_flags.size()) != num_peers)
						return true;

					peer_id pid(0);
					policy& p = m_torrent.get_policy();
					for (int i = 0; i < num_peers; ++i)
					{
						tcp::endpoint adr = detail::read_v6_endpoint<tcp::endpoint>(in);
						char flags = detail::read_uint8(fin);
						p.peer_from_tracker(adr, pid, peer_info::pex, flags);
					}
				}
			}
			catch (std::exception&)
			{
				throw protocol_error("invalid uT peer exchange message");
			}
			return true;
		}

		// the peers second tick
		// every minute we send a pex message
		virtual void tick()
		{
			if (!m_message_index) return;	// no handshake yet
			if (++m_1_minute <= 60) return;

			if (m_first_time)
			{
				send_ut_peer_list();
				m_first_time = false;
			}
			else
			{
				send_ut_peer_diff();
			}
			m_1_minute = 0;
		}

	private:

		void send_ut_peer_diff()
		{
			std::vector<char> const& pex_msg = m_tp.get_ut_pex_msg();

			buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());

			detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
			detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
			detail::write_uint8(m_message_index, i.begin);
			std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
			i.begin += pex_msg.size();

			TORRENT_ASSERT(i.begin == i.end);
			m_pc.setup_send();
		}

		void send_ut_peer_list()
		{
			entry pex;
			// leave the dropped string empty
			pex["dropped"].string();
			std::string& pla = pex["added"].string();
			std::string& plf = pex["added.f"].string();
			pex["dropped6"].string();
			std::string& pla6 = pex["added6"].string();
			std::string& plf6 = pex["added6.f"].string();
			std::back_insert_iterator<std::string> pla_out(pla);
			std::back_insert_iterator<std::string> plf_out(plf);
			std::back_insert_iterator<std::string> pla6_out(pla6);
			std::back_insert_iterator<std::string> plf6_out(plf6);

			int num_added = 0;
			for (torrent::peer_iterator i = m_torrent.begin()
				, end(m_torrent.end()); i != end; ++i)
			{
				peer_connection* peer = *i;
				if (!send_peer(*peer)) continue;

				// don't write too big of a package
				if (num_added >= max_peer_entries) break;

				// only send proper bittorrent peers
				bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
				if (!p) continue;

				// no supported flags to set yet
				// 0x01 - peer supports encryption
				// 0x02 - peer is a seed
				int flags = p->is_seed() ? 2 : 0;
#ifndef TORRENT_DISABLE_ENCRYPTION
				flags |= p->supports_encryption() ? 1 : 0;
#endif
				tcp::endpoint const& remote = peer->remote();
				// i->first was added since the last time
				if (remote.address().is_v4())
				{
					detail::write_endpoint(remote, pla_out);
					detail::write_uint8(flags, plf_out);
				}
				else
				{
					detail::write_endpoint(remote, pla6_out);
					detail::write_uint8(flags, plf6_out);
				}
				++num_added;
			}
			std::vector<char> pex_msg;
			bencode(std::back_inserter(pex_msg), pex);

			buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());

			detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
			detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
			detail::write_uint8(m_message_index, i.begin);
			std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
			i.begin += pex_msg.size();

			TORRENT_ASSERT(i.begin == i.end);
			m_pc.setup_send();
		}

		torrent& m_torrent;
		peer_connection& m_pc;
		ut_pex_plugin& m_tp;
		int m_1_minute;
		int m_message_index;

		// this is initialized to true, and set to
		// false after the first pex message has been sent.
		// it is used to know if a diff message or a full
		// message should be sent.
		bool m_first_time;
	};

	boost::shared_ptr<peer_plugin> ut_pex_plugin::new_connection(peer_connection* pc)
	{
		bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(pc);
		if (!c) return boost::shared_ptr<peer_plugin>();
		return boost::shared_ptr<peer_plugin>(new ut_pex_peer_plugin(m_torrent
			, *pc, *this));
	}
}}

namespace libtorrent
{

	boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent* t, void*)
	{
		if (t->torrent_file().priv())
		{
			return boost::shared_ptr<torrent_plugin>();
		}
		return boost::shared_ptr<torrent_plugin>(new ut_pex_plugin(*t));
	}

}

<commit_msg>made ut_pex not rely on exceptions<commit_after>/*

Copyright (c) 2006, MassaRoddel, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/shared_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/peer_connection.hpp"
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/extensions.hpp"

#include "libtorrent/extensions/ut_pex.hpp"

namespace libtorrent { namespace
{
	const char extension_name[] = "ut_pex";

	enum
	{
		extension_index = 1,
		max_peer_entries = 100
	};

	bool send_peer(peer_connection const& p)
	{
		// don't send out peers that we haven't connected to
		// (that have connected to us)
		if (!p.is_local()) return false;
		// don't send out peers that we haven't successfully connected to
		if (p.is_connecting()) return false;
		return true;
	}

	struct ut_pex_plugin: torrent_plugin
	{
		ut_pex_plugin(torrent& t): m_torrent(t), m_1_minute(55) {}

		virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection* pc);

		std::vector<char>& get_ut_pex_msg()
		{
			return m_ut_pex_msg;
		}

		// the second tick of the torrent
		// each minute the new lists of "added" + "added.f" and "dropped"
		// are calculated here and the pex message is created
		// each peer connection will use this message
		// max_peer_entries limits the packet size
		virtual void tick()
		{
			if (++m_1_minute < 60) return;

			m_1_minute = 0;

			entry pex;
			std::string& pla = pex["added"].string();
			std::string& pld = pex["dropped"].string();
			std::string& plf = pex["added.f"].string();
			std::string& pla6 = pex["added6"].string();
			std::string& pld6 = pex["dropped6"].string();
			std::string& plf6 = pex["added6.f"].string();
			std::back_insert_iterator<std::string> pla_out(pla);
			std::back_insert_iterator<std::string> pld_out(pld);
			std::back_insert_iterator<std::string> plf_out(plf);
			std::back_insert_iterator<std::string> pla6_out(pla6);
			std::back_insert_iterator<std::string> pld6_out(pld6);
			std::back_insert_iterator<std::string> plf6_out(plf6);

			std::set<tcp::endpoint> dropped;
			m_old_peers.swap(dropped);

			int num_added = 0;
			for (torrent::peer_iterator i = m_torrent.begin()
				, end(m_torrent.end()); i != end; ++i)
			{
					peer_connection* peer = *i;
				if (!send_peer(*peer)) continue;

				tcp::endpoint const& remote = peer->remote();
				m_old_peers.insert(remote);

				std::set<tcp::endpoint>::iterator di = dropped.find(remote);
				if (di == dropped.end())
				{
					// don't write too big of a package
					if (num_added >= max_peer_entries) break;

					// only send proper bittorrent peers
					bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
					if (!p) continue;

					// no supported flags to set yet
					// 0x01 - peer supports encryption
					// 0x02 - peer is a seed
					int flags = p->is_seed() ? 2 : 0;
#ifndef TORRENT_DISABLE_ENCRYPTION
					flags |= p->supports_encryption() ? 1 : 0;
#endif
					// i->first was added since the last time
					if (remote.address().is_v4())
					{
						detail::write_endpoint(remote, pla_out);
						detail::write_uint8(flags, plf_out);
					}
					else
					{
						detail::write_endpoint(remote, pla6_out);
						detail::write_uint8(flags, plf6_out);
					}
					++num_added;
				}
				else
				{
					// this was in the previous message
					// so, it wasn't dropped
					dropped.erase(di);
				}
			}

			for (std::set<tcp::endpoint>::const_iterator i = dropped.begin()
				, end(dropped.end()); i != end; ++i)
			{
				if (i->address().is_v4())
					detail::write_endpoint(*i, pld_out);
				else
					detail::write_endpoint(*i, pld6_out);
			}

			m_ut_pex_msg.clear();
			bencode(std::back_inserter(m_ut_pex_msg), pex);
		}

	private:
		torrent& m_torrent;

		std::set<tcp::endpoint> m_old_peers;
		int m_1_minute;
		std::vector<char> m_ut_pex_msg;
	};

	struct ut_pex_peer_plugin : peer_plugin
	{
		ut_pex_peer_plugin(torrent& t, peer_connection& pc, ut_pex_plugin& tp)
			: m_torrent(t)
			, m_pc(pc)
			, m_tp(tp)
			, m_1_minute(55)
			, m_message_index(0)
			, m_first_time(true)
		{}

		virtual void add_handshake(entry& h)
		{
			entry& messages = h["m"];
			messages[extension_name] = extension_index;
		}

		virtual bool on_extension_handshake(entry const& h)
		{
			m_message_index = 0;
			entry const* messages = h.find_key("m");
			if (!messages || messages->type() != entry::dictionary_t) return false;

			entry const* index = messages->find_key(extension_name);
			if (!index || index->type() != entry::int_t) return false;

			m_message_index = index->integer();
			return true;
		}

		virtual bool on_extended(int length, int msg, buffer::const_interval body)
		{
			if (msg != extension_index) return false;
			if (m_message_index == 0) return false;

			if (length > 500 * 1024)
				throw protocol_error("uT peer exchange message larger than 500 kB");

			if (body.left() < length) return true;

			entry pex_msg = bdecode(body.begin, body.end);

			entry const* p = pex_msg.find_key("added");
			entry const* pf = pex_msg.find_key("added.f");

			if (p != 0 && pf != 0 && p->type() == entry::string_t && pf->type() == entry::string_t)
			{
				std::string const& peers = p->string();
				std::string const& peer_flags = pf->string();

				int num_peers = peers.length() / 6;
				char const* in = peers.c_str();
				char const* fin = peer_flags.c_str();

				if (int(peer_flags.size()) != num_peers)
					return true;

				peer_id pid(0);
				policy& p = m_torrent.get_policy();
				for (int i = 0; i < num_peers; ++i)
				{
					tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in);
					char flags = detail::read_uint8(fin);
					p.peer_from_tracker(adr, pid, peer_info::pex, flags);
				}
			}

			entry const* p6 = pex_msg.find_key("added6");
			entry const* p6f = pex_msg.find_key("added6.f");
			if (p6 && p6f && p6->type() == entry::string_t && p6f->type() == entry::string_t)
			{
				std::string const& peers6 = p6->string();
				std::string const& peer6_flags = p6f->string();

				int num_peers = peers6.length() / 18;
				char const* in = peers6.c_str();
				char const* fin = peer6_flags.c_str();

				if (int(peer6_flags.size()) != num_peers)
					return true;

				peer_id pid(0);
				policy& p = m_torrent.get_policy();
				for (int i = 0; i < num_peers; ++i)
				{
					tcp::endpoint adr = detail::read_v6_endpoint<tcp::endpoint>(in);
					char flags = detail::read_uint8(fin);
					p.peer_from_tracker(adr, pid, peer_info::pex, flags);
				}
			}
			return true;
		}

		// the peers second tick
		// every minute we send a pex message
		virtual void tick()
		{
			if (!m_message_index) return;	// no handshake yet
			if (++m_1_minute <= 60) return;

			if (m_first_time)
			{
				send_ut_peer_list();
				m_first_time = false;
			}
			else
			{
				send_ut_peer_diff();
			}
			m_1_minute = 0;
		}

	private:

		void send_ut_peer_diff()
		{
			std::vector<char> const& pex_msg = m_tp.get_ut_pex_msg();

			buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());

			detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
			detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
			detail::write_uint8(m_message_index, i.begin);
			std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
			i.begin += pex_msg.size();

			TORRENT_ASSERT(i.begin == i.end);
			m_pc.setup_send();
		}

		void send_ut_peer_list()
		{
			entry pex;
			// leave the dropped string empty
			pex["dropped"].string();
			std::string& pla = pex["added"].string();
			std::string& plf = pex["added.f"].string();
			pex["dropped6"].string();
			std::string& pla6 = pex["added6"].string();
			std::string& plf6 = pex["added6.f"].string();
			std::back_insert_iterator<std::string> pla_out(pla);
			std::back_insert_iterator<std::string> plf_out(plf);
			std::back_insert_iterator<std::string> pla6_out(pla6);
			std::back_insert_iterator<std::string> plf6_out(plf6);

			int num_added = 0;
			for (torrent::peer_iterator i = m_torrent.begin()
				, end(m_torrent.end()); i != end; ++i)
			{
				peer_connection* peer = *i;
				if (!send_peer(*peer)) continue;

				// don't write too big of a package
				if (num_added >= max_peer_entries) break;

				// only send proper bittorrent peers
				bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
				if (!p) continue;

				// no supported flags to set yet
				// 0x01 - peer supports encryption
				// 0x02 - peer is a seed
				int flags = p->is_seed() ? 2 : 0;
#ifndef TORRENT_DISABLE_ENCRYPTION
				flags |= p->supports_encryption() ? 1 : 0;
#endif
				tcp::endpoint const& remote = peer->remote();
				// i->first was added since the last time
				if (remote.address().is_v4())
				{
					detail::write_endpoint(remote, pla_out);
					detail::write_uint8(flags, plf_out);
				}
				else
				{
					detail::write_endpoint(remote, pla6_out);
					detail::write_uint8(flags, plf6_out);
				}
				++num_added;
			}
			std::vector<char> pex_msg;
			bencode(std::back_inserter(pex_msg), pex);

			buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());

			detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
			detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
			detail::write_uint8(m_message_index, i.begin);
			std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
			i.begin += pex_msg.size();

			TORRENT_ASSERT(i.begin == i.end);
			m_pc.setup_send();
		}

		torrent& m_torrent;
		peer_connection& m_pc;
		ut_pex_plugin& m_tp;
		int m_1_minute;
		int m_message_index;

		// this is initialized to true, and set to
		// false after the first pex message has been sent.
		// it is used to know if a diff message or a full
		// message should be sent.
		bool m_first_time;
	};

	boost::shared_ptr<peer_plugin> ut_pex_plugin::new_connection(peer_connection* pc)
	{
		bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(pc);
		if (!c) return boost::shared_ptr<peer_plugin>();
		return boost::shared_ptr<peer_plugin>(new ut_pex_peer_plugin(m_torrent
			, *pc, *this));
	}
}}

namespace libtorrent
{

	boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent* t, void*)
	{
		if (t->torrent_file().priv())
		{
			return boost::shared_ptr<torrent_plugin>();
		}
		return boost::shared_ptr<torrent_plugin>(new ut_pex_plugin(*t));
	}

}

<|endoftext|>


<commit_before>// Copyright (c) 2016 Kasper Kronborg Isager and Radoslaw Niemczyk.
#include "vector.hpp"

namespace lsh {
  /**
   * Create a new vector from existing component chunks.
   *
   * @param components The existing component chunks.
   * @param size The number of components.
   */
  vector::vector(const std::vector<unsigned int>& cs, unsigned int s) {
    this->size_ = s;

    unsigned int n = cs.size();

    for (unsigned int i = 0; i < n; i++) {
      this->components_.push_back(cs[i]);
    }
  }

  /**
   * Construct a new vector.
   *
   * @param components The components of the vector.
   */
  vector::vector(const std::vector<bool>& cs) {
    this->size_ = cs.size();

    unsigned int s = this->size_;
    unsigned int c = this->chunk_size_;
    unsigned int i = 0;
    unsigned int k = 0;

    while (i < s) {
      this->components_.push_back(0);

      // Compute the number of bits in the current chunk.
      unsigned int b = i + c > s ? s - i : c;

      for (unsigned int j = 0; j < b; j++) {
        this->components_[k] |= cs[i + j] << (b - j - 1);
      }

      i += b;
      k += 1;
    }
  }

  /**
   * Get the number of components in this vector.
   *
   * @return The number of components in this vector.
   */
  unsigned int vector::size() const {
    return this->size_;
  }

  /**
   * Get the component at the specified index of this vector.
   *
   * @param index The index of the component to get.
   * @return The component at the index.
   */
  bool vector::get(unsigned int i) const {
    unsigned int s = this->size_;
    unsigned int c = this->chunk_size_;

    if (i >= s) {
      throw std::out_of_range("Invalid index");
    }

    // Compute the index of the target chunk.
    unsigned int d = i / s;

    // Compute the index of the first bit of the target chunk.
    unsigned int j = d * s;

    // Compute the number of bits in the target chunk.
    unsigned int b = j + c > s ? s - j : c;

    return (this->components_[d] >> (b - (i % s) - 1)) & 1;
  }

  /**
   * Get a string representation of this vector.
   *
   * @return The string representation of the vector.
   */
  std::string vector::to_string() const {
    unsigned int n = this->size_;

    std::string value = "Vector[";

    for (unsigned int i = 0; i < n; i++) {
      value += std::to_string(this->get(i));
    }

    return value + "]";
  }

  /**
   * Check if this vector equals another vector.
   *
   * @param vector The other vector.
   * @return `true` if this vector equals the other vector, otherwise `false`.
   */
  bool vector::operator==(const vector& v) const {
    if (this->size() != v.size()) {
      throw std::invalid_argument("Invalid vector size");
    }

    return vector::distance(*this, v) == 0;
  }

  /**
   * Compute the dot product of this and another vector.
   *
   * @param vector The other vector.
   * @return The dot product of this and another vector.
   */
  unsigned int vector::operator*(const vector& v) const {
    if (this->size() != v.size()) {
      throw std::invalid_argument("Invalid vector size");
    }

    unsigned int d = 0;
    unsigned int n = this->components_.size();

    for (unsigned int i = 0; i < n; i++) {
      d += __builtin_popcount(this->components_[i] & v.components_[i]);
    }

    return d;
  }

  /**
   * Compute the dot product of this vector and an integer.
   *
   * @param integer The integer.
   * @return The dot product of this vector and an integer.
   */
  unsigned int vector::operator*(unsigned int it) const {
    unsigned int d = 0;
    unsigned int s = this->size_;
    unsigned int c = this->chunk_size_;
    unsigned int n = this->components_.size();

    for (unsigned int i = 0; i < n; i++) {
      // Compute the index of the first bit of the current chunk.
      unsigned int j = c * i;

      // Compute the number of bits in the current chunk.
      unsigned int m = j + c > s ? s - j : c;

      // Grab the bits of the integer that correspond to the current chunk.
      unsigned int b = (it >> (s - j - m)) % (1 << m);

      d += __builtin_popcount(this->components_[i] & b);
    }

    return d;
  }

  /**
   * Compute the bitwise AND of this and another vector.
   *
   * @param vector The other vector.
   * @return The bitwise AND of this and another vector.
   */
  vector vector::operator&(const vector& v) const {
    if (this->size() != v.size()) {
      throw std::invalid_argument("Invalid vector size");
    }

    std::vector<unsigned int> c;

    unsigned int n = this->components_.size();

    for (unsigned int i = 0; i < n; i++) {
      c.push_back(this->components_[i] & v.components_[i]);
    }

    return vector(c, this->size_);
  }

  /**
   * Compupte the hash of this vector.
   *
   * @return The hash of this vector.
   */
  int vector::hash() const {
    unsigned int n = this->components_.size();
    unsigned long h = 7;

    for (unsigned int i = 0; i < n; i++) {
      h = 31 * h + this->components_[i];
    }

    return h ^ (h >> 32);
  }

  /**
   * Compute the distance between two vectors.
   *
   * @param u The first vector.
   * @param v The second vector.
   * @return The distance between the two vectors.
   */
  int vector::distance(const vector& u, const vector& v) {
    if (u.size() != v.size()) {
      throw std::invalid_argument("Invalid vector size");
    }

    unsigned int d = 0;
    unsigned int n = u.components_.size();

    for (unsigned int i = 0; i < n; i++) {
      d += __builtin_popcount(u.components_[i] ^ v.components_[i]);
    }

    return d;
  }

  /**
   * Construct a random vector of a given dimensionality.
   *
   * @param dimensions The number of dimensions in the vector.
   * @return The randomly generated vector.
   */
  vector vector::random(unsigned int d) {
    std::random_device random;
    std::mt19937 generator(random());
    std::uniform_int_distribution<> components(0, 1);

    std::vector<bool> c;

    for (unsigned int i = 0; i < d; i++) {
      c.push_back(components(generator));
    }

    return vector(c);
  }
}
<commit_msg>Improve performance of vector access<commit_after>// Copyright (c) 2016 Kasper Kronborg Isager and Radoslaw Niemczyk.
#include "vector.hpp"

namespace lsh {
  /**
   * Create a new vector from existing component chunks.
   *
   * @param components The existing component chunks.
   * @param size The number of components.
   */
  vector::vector(const std::vector<unsigned int>& cs, unsigned int s) {
    this->size_ = s;

    unsigned int n = cs.size();

    this->components_.reserve(n);

    for (unsigned int i = 0; i < n; i++) {
      this->components_[i] = cs[i];
    }
  }

  /**
   * Construct a new vector.
   *
   * @param components The components of the vector.
   */
  vector::vector(const std::vector<bool>& cs) {
    this->size_ = cs.size();

    unsigned int s = this->size_;
    unsigned int c = this->chunk_size_;
    unsigned int i = 0;
    unsigned int k = 0;

    while (i < s) {
      this->components_.push_back(0);

      // Compute the number of bits in the current chunk.
      unsigned int b = i + c > s ? s - i : c;

      for (unsigned int j = 0; j < b; j++) {
        this->components_[k] |= cs[i + j] << (b - j - 1);
      }

      i += b;
      k += 1;
    }
  }

  /**
   * Get the number of components in this vector.
   *
   * @return The number of components in this vector.
   */
  unsigned int vector::size() const {
    return this->size_;
  }

  /**
   * Get the component at the specified index of this vector.
   *
   * @param index The index of the component to get.
   * @return The component at the index.
   */
  bool vector::get(unsigned int i) const {
    unsigned int s = this->size_;
    unsigned int c = this->chunk_size_;

    if (i >= s) {
      throw std::out_of_range("Invalid index");
    }

    // Compute the index of the target chunk.
    unsigned int d = i / s;

    // Compute the index of the first bit of the target chunk.
    unsigned int j = d * s;

    // Compute the number of bits in the target chunk.
    unsigned int b = j + c > s ? s - j : c;

    return (this->components_[d] >> (b - (i % s) - 1)) & 1;
  }

  /**
   * Get a string representation of this vector.
   *
   * @return The string representation of the vector.
   */
  std::string vector::to_string() const {
    unsigned int n = this->size_;

    std::string value = "Vector[";

    for (unsigned int i = 0; i < n; i++) {
      value += std::to_string(this->get(i));
    }

    return value + "]";
  }

  /**
   * Check if this vector equals another vector.
   *
   * @param vector The other vector.
   * @return `true` if this vector equals the other vector, otherwise `false`.
   */
  bool vector::operator==(const vector& v) const {
    if (this->size() != v.size()) {
      throw std::invalid_argument("Invalid vector size");
    }

    return vector::distance(*this, v) == 0;
  }

  /**
   * Compute the dot product of this and another vector.
   *
   * @param vector The other vector.
   * @return The dot product of this and another vector.
   */
  unsigned int vector::operator*(const vector& v) const {
    if (this->size() != v.size()) {
      throw std::invalid_argument("Invalid vector size");
    }

    unsigned int d = 0;
    unsigned int n = this->components_.size();

    for (unsigned int i = 0; i < n; i++) {
      d += __builtin_popcount(this->components_[i] & v.components_[i]);
    }

    return d;
  }

  /**
   * Compute the dot product of this vector and an integer.
   *
   * @param integer The integer.
   * @return The dot product of this vector and an integer.
   */
  unsigned int vector::operator*(unsigned int it) const {
    unsigned int d = 0;
    unsigned int s = this->size_;
    unsigned int c = this->chunk_size_;
    unsigned int n = this->components_.size();

    for (unsigned int i = 0; i < n; i++) {
      // Compute the index of the first bit of the current chunk.
      unsigned int j = c * i;

      // Compute the number of bits in the current chunk.
      unsigned int m = j + c > s ? s - j : c;

      // Grab the bits of the integer that correspond to the current chunk.
      unsigned int b = (it >> (s - j - m)) % (1 << m);

      d += __builtin_popcount(this->components_[i] & b);
    }

    return d;
  }

  /**
   * Compute the bitwise AND of this and another vector.
   *
   * @param vector The other vector.
   * @return The bitwise AND of this and another vector.
   */
  vector vector::operator&(const vector& v) const {
    if (this->size() != v.size()) {
      throw std::invalid_argument("Invalid vector size");
    }

    unsigned int n = this->components_.size();

    std::vector<unsigned int> c(n);

    for (unsigned int i = 0; i < n; i++) {
      c[i] = this->components_[i] & v.components_[i];
    }

    return vector(c, this->size_);
  }

  /**
   * Compupte the hash of this vector.
   *
   * @return The hash of this vector.
   */
  int vector::hash() const {
    unsigned int n = this->components_.size();
    unsigned long h = 7;

    for (unsigned int i = 0; i < n; i++) {
      h = 31 * h + this->components_[i];
    }

    return h ^ (h >> 32);
  }

  /**
   * Compute the distance between two vectors.
   *
   * @param u The first vector.
   * @param v The second vector.
   * @return The distance between the two vectors.
   */
  int vector::distance(const vector& u, const vector& v) {
    if (u.size() != v.size()) {
      throw std::invalid_argument("Invalid vector size");
    }

    unsigned int d = 0;
    unsigned int n = u.components_.size();

    for (unsigned int i = 0; i < n; i++) {
      d += __builtin_popcount(u.components_[i] ^ v.components_[i]);
    }

    return d;
  }

  /**
   * Construct a random vector of a given dimensionality.
   *
   * @param dimensions The number of dimensions in the vector.
   * @return The randomly generated vector.
   */
  vector vector::random(unsigned int d) {
    std::random_device random;
    std::mt19937 generator(random());
    std::uniform_int_distribution<> components(0, 1);

    std::vector<bool> c(d);

    for (unsigned int i = 0; i < d; i++) {
      c[i] = components(generator);
    }

    return vector(c);
  }
}
<|endoftext|>


<commit_before>#include "internal.hpp"
#include "macros.hpp"
#include "message.hpp"

namespace CaDiCaL {

// Vivification is a special case of asymmetric tautology elimination.  It
// strengthens and removes irredundant clauses proven redundant through unit
// propagation.  The original algorithm is due to a paper by Piette, Hamadi
// published at ECAI'08.  We have an inprocessing version, e.g., it does not
// necessarily run-to-completion.  It does no conflict analysis and uses a
// new heuristic for selecting clauses to vivify.

/*------------------------------------------------------------------------*/

struct ClauseScore {
  Clause * clause;
  double score;
  ClauseScore (Clause * c) : clause (c), score (0) { }
};

struct less_clause_score {
  bool operator () (const ClauseScore & a, const ClauseScore & b) const {
    return a.score < b.score;
  }
};

// Check whether negated literal occurs less often.
//
struct less_negated_noccs2 {
  Internal * internal;
  less_negated_noccs2 (Internal * i) : internal (i) { }
  bool operator () (int a, int b) {
    long u = internal->noccs2 (-a), v = internal->noccs2 (-b);
    if (u < v) return true;
    if (u > v) return false;
    int i = abs (a), j = abs (b);
    if (i < j) return true;
    if (i > j) return false;
    return a < b;
  }
};

/*------------------------------------------------------------------------*/

void Internal::vivify () {

  assert (opts.vivify);

  SWITCH_AND_START (search, simplify, vivify);

  assert (!vivifying);
  vivifying = true;

  stats.vivifications++;
  if (level) backtrack ();

  // Refill the schedule every time.  Unchecked clauses are 'saved' by
  // setting their 'vivify' bit, such that they can be tried next time.
  //
  vector<ClauseScore> schedule;

  const const_clause_iterator end = clauses.end ();
  const_clause_iterator i;

  // After an arithmetic increasing number of calls to 'vivify' we
  // reschedule all clauses, instead of only those not tried before.  Then
  // this limit is increased by one. The argument is that we should focus on
  // clauses with many occurrences of their negated literals (also long
  // clauses), but in the limit eventually still should vivify all clauses.
  //
  bool reschedule_all = !lim.vivify_wait_reschedule;
  if (reschedule_all) {
    VRB ("vivification", stats.vivifications,
      "forced to reschedule all clauses");
    lim.vivify_wait_reschedule = ++inc.vivify_wait_reschedule;
  } else lim.vivify_wait_reschedule--;

  // In the first round check whether there are still clauses left, which
  // are scheduled to but have not been vivified yet.  In the second round
  // if no such clauses are found in the first round.  This is also
  // performed if rescheduling is forced because 'reschedule_all' is  true.
  //
  for (int round = 0; schedule.empty () && round <= 1; round++) {
    for (i = clauses.begin (); i != end; i++) {
      Clause * c = *i;
      if (c->garbage) continue;
      if (c->redundant) continue;
      if (c->size == 2) continue;	// see also (NO-BINARY) below
      if (!reschedule_all && !round && !c->vivify) continue;
      schedule.push_back (c);
      c->vivify = true;
    }
  }
  shrink_vector (schedule);

  // Count the number of occurrences of literals in all irredundant clauses,
  // particularly the irredundant binary clauses, responsible for most of
  // the propagation usually.
  //
  init_noccs2 ();

  for (i = clauses.begin (); i != end; i++) {
    Clause * c = *i;
    if (c->garbage) continue;
    if (c->redundant) continue;

    // Compute score as 'pow (2, -c->size)' without 'math.h' (it actually
    // could be faster even, since second argument is always an integer).
    // This is the same score the Jeroslow-Wang heuristic would give.
    //
    double base = 0.5, score = 0.25;
    for (int n = c->size - 2; n; n >>= 1) {
      if (n & 1) score *= base;
      base *= base;
    }

    const const_literal_iterator eoc = c->end ();
    const_literal_iterator j;
    for (j = c->begin (); j != eoc; j++)
      noccs2 (*j) += score;
  }

  // Then update the score of the candidate clauses by adding up the number
  // of occurrences of the negation of its literals.
  //
  const vector<ClauseScore>::const_iterator eos = schedule.end ();
  vector<ClauseScore>::iterator k;

  for (k = schedule.begin (); k != eos; k++) {
    ClauseScore & cs = *k;
    const const_literal_iterator eoc = cs.clause->end ();
    const_literal_iterator j;
    long score = 0;
    for (j = cs.clause->begin (); j != eoc; j++)
      score += noccs2 (-*j);
    cs.score = score;
  }

  // Now sort candidates, with best clause (many negative occurrences) last.
  //
  stable_sort (schedule.begin (), schedule.end (), less_clause_score ());

  long scheduled = schedule.size ();
  VRB ("vivification", stats.vivifications,
    "scheduled %ld clauses to be vivified %.0f%%",
    scheduled, percent (scheduled, stats.irredundant));

  // We need to make sure to propagate only over irredundant clauses.
  //
  flush_redundant_watches ();
  size_t old_propagated = propagated;	// see [RE-PROPAGATE] below.

  // Counters, for what happened.
  //
  long checked = 0, subsumed = 0, strengthened = 0, units = 0;

  // Temporarily save and sort the candidate clause literals here.
  //
  vector<int> sorted;

  // Limit the number of propagations during vivification as in 'probe'.
  //
  long delta = opts.vivifyreleff * stats.propagations.search;
  if (delta < opts.vivifymineff) delta = opts.vivifymineff;
  if (delta > opts.vivifymaxeff) delta = opts.vivifymaxeff;
  long limit = stats.propagations.vivify + delta;

  while (!unsat &&
         !schedule.empty () &&
         stats.propagations.vivify < limit) {

    // Next candidate clause to vivify.
    //
    Clause * c = schedule.back ().clause;
    schedule.pop_back ();
    assert (c->vivify);
    c->vivify = false;

    assert (!c->garbage);
    assert (!c->redundant);
    assert (c->size > 2);		// see
    assert (!level);

    // First check whether it is already satisfied.
    //
    const const_literal_iterator eoc = c->end ();
    const_literal_iterator j;
    bool satisfied = false;

    sorted.clear ();

    for (j = c->begin (); !satisfied && j != eoc; j++) {
      const int lit = *j, tmp = val (lit);
      if (tmp > 0) satisfied = true;
      else if (!tmp) sorted.push_back (lit);
    }

    if (satisfied) { mark_garbage (c); continue; }

    // The actual vivification checking is performed here, by assuming the
    // negation of each of the remaining literals of the clause in turn and
    // propagating it.  If a conflict occurs or another literal in the
    // clause becomes assigned during propagation, we can stop.
    //
    LOG (c, "vivification checking");
    checked++;

    // Sort the literals of the candidate with respect to the largest number
    // of negative occurrences.  The idea is that more negative occurrences
    // lead to more propagations and thus potentially higher earlier effect.
    //
    sort (sorted.begin (), sorted.end (), less_negated_noccs2 (this));

    // Make sure to ignore this clause during propagation.  This is not that
    // easy for binary clauses (NO-BINARY), e.g., ignoring binary clauses,
    // without changing 'propagate' and actually we also do not want to
    // remove binary clauses which are subsumed.  Those are hyper binary
    // resolvents and should be kept as learned clauses instead unless they
    // are transitive in the binary implication graph (TODO).
    //
    c->ignore = true;		// see also (NO-BINARY) above

    bool redundant = false;	// determined to be redundant / subsumed
    int remove = 0;		// at least literal 'remove' can be removed

    while (!redundant && !remove && !sorted.empty ()) {
      const int lit = sorted.back (), tmp = val (lit);
      sorted.pop_back ();
      if (tmp > 0) {
	LOG ("redundant since literal %d already true", lit);
	redundant = true;
      } else if (tmp < 0) {
	LOG ("removing at least literal %d which is already false", lit);
	remove = lit;
      } else {
	assume_decision (-lit);
	if (propagate ()) continue;
	LOG ("redundant since propagation produced conflict");
	redundant = true;
	conflict = 0;
      }
    }

    if (redundant) {
REDUNDANT:
      subsumed++;
      LOG (c, "redundant asymmetric tautology");
      mark_garbage (c);
    } else if (remove) {
      strengthened++;
      assert (level);
      assert (clause.empty ());
#ifndef NDEBUG
      bool found = false;
#endif
      // There might be other literals implied to false (or even root level
      // falsified).  Those should be removed in addition to 'remove'.
      //
      for (j = c->begin (); j != eoc; j++) {
	const int other = *j, tmp = val (other);
	Var & v = var (other);
	if (tmp > 0) {
	  LOG ("redundant since literal %d already true", other);
	  clause.clear ();
	  goto REDUNDANT;
	}
	if (tmp < 0 && !v.level) continue;
	if (tmp < 0 && v.level && v.reason) {
	  assert (v.level);
	  assert (v.reason);
	  LOG ("flushing literal %d", other);
	  mark_removed (other);
#ifndef NDEBUG
	  if (other == remove) found = true;
#endif
	} else clause.push_back (other);
      }
      assert (found);
      assert (!clause.empty ());
      backtrack ();
      if (clause.size () == 1) {
	const int unit = clause[0];
	LOG (c, "vivification shrunken to unit %d", unit);
	assert (!val (unit));
	assign_unit (unit);
	units++;
	bool ok = propagate ();
	if (!ok) learn_empty_clause ();
      } else {
#ifdef LOGGING
	Clause * d =
#endif
	new_clause_as (c);
	LOG (c, "before vivification");
	LOG (d, "after vivification");
      }
      clause.clear ();
      mark_garbage (c);
    }
    if (level) backtrack ();
    c->ignore = false;
  }

  if (!unsat) {

    erase_vector (sorted);
    reset_noccs2 ();
    erase_vector (schedule);
    disconnect_watches ();
    connect_watches ();

    // [RE-PROPAGATE] Since redundant clause were disconnected during
    // propagating vivified units above, we have propagate all those fixed
    // literals again after connecting the redundant clauses back.
    // Otherwise, the invariants for watching and blocking literals break.
    //
    if (old_propagated < propagated) {
      propagated = old_propagated;
      if (!propagate ()) {
	LOG ("propagating vivified units leads to conflict");
	learn_empty_clause ();
      }
    }
  }

  VRB ("vivification", stats.vivifications,
    "checked %ld clauses %.02f%% out of scheduled",
    checked, percent (checked, scheduled));
  if (units)
  VRB ("vivification", stats.vivifications,
    "found %ld units %.02f%% out of checked",
    units, percent (units, checked));
  VRB ("vivification", stats.vivifications,
    "subsumed %ld clauses %.02f%% out of checked",
    subsumed, percent (subsumed, checked));
  VRB ("vivification", stats.vivifications,
    "strengthened %ld clauses %.02f%% out of checked",
    strengthened, percent (strengthened, checked));

  stats.vivifychecks += checked;
  stats.vivifysubs += subsumed;
  stats.vivifystrs += strengthened;
  stats.vivifyunits += units;

  stats.subsumed += subsumed;
  stats.strengthened += strengthened;

  assert (vivifying);
  vivifying = false;

  report ('v');
  STOP_AND_SWITCH (vivify, simplify, search);
}

};
<commit_msg>finished comment<commit_after>#include "internal.hpp"
#include "macros.hpp"
#include "message.hpp"

namespace CaDiCaL {

// Vivification is a special case of asymmetric tautology elimination.  It
// strengthens and removes irredundant clauses proven redundant through unit
// propagation.  The original algorithm is due to a paper by Piette, Hamadi
// published at ECAI'08.  We have an inprocessing version, e.g., it does not
// necessarily run-to-completion.  It does no conflict analysis and uses a
// new heuristic for selecting clauses to vivify.

/*------------------------------------------------------------------------*/

struct ClauseScore {
  Clause * clause;
  double score;
  ClauseScore (Clause * c) : clause (c), score (0) { }
};

struct less_clause_score {
  bool operator () (const ClauseScore & a, const ClauseScore & b) const {
    return a.score < b.score;
  }
};

// Check whether negated literal occurs less often.
//
struct less_negated_noccs2 {
  Internal * internal;
  less_negated_noccs2 (Internal * i) : internal (i) { }
  bool operator () (int a, int b) {
    long u = internal->noccs2 (-a), v = internal->noccs2 (-b);
    if (u < v) return true;
    if (u > v) return false;
    int i = abs (a), j = abs (b);
    if (i < j) return true;
    if (i > j) return false;
    return a < b;
  }
};

/*------------------------------------------------------------------------*/

void Internal::vivify () {

  assert (opts.vivify);

  SWITCH_AND_START (search, simplify, vivify);

  assert (!vivifying);
  vivifying = true;

  stats.vivifications++;
  if (level) backtrack ();

  // Refill the schedule every time.  Unchecked clauses are 'saved' by
  // setting their 'vivify' bit, such that they can be tried next time.
  //
  vector<ClauseScore> schedule;

  const const_clause_iterator end = clauses.end ();
  const_clause_iterator i;

  // After an arithmetic increasing number of calls to 'vivify' we
  // reschedule all clauses, instead of only those not tried before.  Then
  // this limit is increased by one. The argument is that we should focus on
  // clauses with many occurrences of their negated literals (also long
  // clauses), but in the limit eventually still should vivify all clauses.
  //
  bool reschedule_all = !lim.vivify_wait_reschedule;
  if (reschedule_all) {
    VRB ("vivification", stats.vivifications,
      "forced to reschedule all clauses");
    lim.vivify_wait_reschedule = ++inc.vivify_wait_reschedule;
  } else lim.vivify_wait_reschedule--;

  // In the first round check whether there are still clauses left, which
  // are scheduled to but have not been vivified yet.  In the second round
  // if no such clauses are found in the first round.  This is also
  // performed if rescheduling is forced because 'reschedule_all' is  true.
  //
  for (int round = 0; schedule.empty () && round <= 1; round++) {
    for (i = clauses.begin (); i != end; i++) {
      Clause * c = *i;
      if (c->garbage) continue;
      if (c->redundant) continue;
      if (c->size == 2) continue;	// see also [NO-BINARY] below
      if (!reschedule_all && !round && !c->vivify) continue;
      schedule.push_back (c);
      c->vivify = true;
    }
  }
  shrink_vector (schedule);

  // Count the number of occurrences of literals in all irredundant clauses,
  // particularly the irredundant binary clauses, responsible for most of
  // the propagation usually.
  //
  init_noccs2 ();

  for (i = clauses.begin (); i != end; i++) {
    Clause * c = *i;
    if (c->garbage) continue;
    if (c->redundant) continue;

    // Compute score as 'pow (2, -c->size)' without 'math.h' (it actually
    // could be faster even, since second argument is always an integer).
    // This is the same score the Jeroslow-Wang heuristic would give.
    //
    double base = 0.5, score = 0.25;
    for (int n = c->size - 2; n; n >>= 1) {
      if (n & 1) score *= base;
      base *= base;
    }

    const const_literal_iterator eoc = c->end ();
    const_literal_iterator j;
    for (j = c->begin (); j != eoc; j++)
      noccs2 (*j) += score;
  }

  // Then update the score of the candidate clauses by adding up the number
  // of occurrences of the negation of its literals.
  //
  const vector<ClauseScore>::const_iterator eos = schedule.end ();
  vector<ClauseScore>::iterator k;

  for (k = schedule.begin (); k != eos; k++) {
    ClauseScore & cs = *k;
    const const_literal_iterator eoc = cs.clause->end ();
    const_literal_iterator j;
    long score = 0;
    for (j = cs.clause->begin (); j != eoc; j++)
      score += noccs2 (-*j);
    cs.score = score;
  }

  // Now sort candidates, with best clause (many negative occurrences) last.
  //
  stable_sort (schedule.begin (), schedule.end (), less_clause_score ());

  long scheduled = schedule.size ();
  VRB ("vivification", stats.vivifications,
    "scheduled %ld clauses to be vivified %.0f%%",
    scheduled, percent (scheduled, stats.irredundant));

  // We need to make sure to propagate only over irredundant clauses.
  //
  flush_redundant_watches ();
  size_t old_propagated = propagated;	// see [RE-PROPAGATE] below.

  // Counters, for what happened.
  //
  long checked = 0, subsumed = 0, strengthened = 0, units = 0;

  // Temporarily save and sort the candidate clause literals here.
  //
  vector<int> sorted;

  // Limit the number of propagations during vivification as in 'probe'.
  //
  long delta = opts.vivifyreleff * stats.propagations.search;
  if (delta < opts.vivifymineff) delta = opts.vivifymineff;
  if (delta > opts.vivifymaxeff) delta = opts.vivifymaxeff;
  long limit = stats.propagations.vivify + delta;

  while (!unsat &&
         !schedule.empty () &&
         stats.propagations.vivify < limit) {

    // Next candidate clause to vivify.
    //
    Clause * c = schedule.back ().clause;
    schedule.pop_back ();
    assert (c->vivify);
    c->vivify = false;

    assert (!c->garbage);
    assert (!c->redundant);
    assert (c->size > 2);		// see [NO-BINARY] above
    assert (!level);

    // First check whether it is already satisfied.
    //
    const const_literal_iterator eoc = c->end ();
    const_literal_iterator j;
    bool satisfied = false;

    sorted.clear ();

    for (j = c->begin (); !satisfied && j != eoc; j++) {
      const int lit = *j, tmp = val (lit);
      if (tmp > 0) satisfied = true;
      else if (!tmp) sorted.push_back (lit);
    }

    if (satisfied) { mark_garbage (c); continue; }

    // The actual vivification checking is performed here, by assuming the
    // negation of each of the remaining literals of the clause in turn and
    // propagating it.  If a conflict occurs or another literal in the
    // clause becomes assigned during propagation, we can stop.
    //
    LOG (c, "vivification checking");
    checked++;

    // Sort the literals of the candidate with respect to the largest number
    // of negative occurrences.  The idea is that more negative occurrences
    // lead to more propagations and thus potentially higher earlier effect.
    //
    sort (sorted.begin (), sorted.end (), less_negated_noccs2 (this));

    // Make sure to ignore this clause during propagation.  This is not that
    // easy for binary clauses [NO-BINARY], e.g., ignoring binary clauses,
    // without changing 'propagate' and actually we also do not want to
    // remove binary clauses which are subsumed.  Those are hyper binary
    // resolvents and should be kept as learned clauses instead unless they
    // are transitive in the binary implication graph (TODO).
    //
    c->ignore = true;		// see also [NO-BINARY] above

    bool redundant = false;	// determined to be redundant / subsumed
    int remove = 0;		// at least literal 'remove' can be removed

    while (!redundant && !remove && !sorted.empty ()) {
      const int lit = sorted.back (), tmp = val (lit);
      sorted.pop_back ();
      if (tmp > 0) {
	LOG ("redundant since literal %d already true", lit);
	redundant = true;
      } else if (tmp < 0) {
	LOG ("removing at least literal %d which is already false", lit);
	remove = lit;
      } else {
	assume_decision (-lit);
	if (propagate ()) continue;
	LOG ("redundant since propagation produced conflict");
	redundant = true;
	conflict = 0;
      }
    }

    if (redundant) {
REDUNDANT:
      subsumed++;
      LOG (c, "redundant asymmetric tautology");
      mark_garbage (c);
    } else if (remove) {
      strengthened++;
      assert (level);
      assert (clause.empty ());
#ifndef NDEBUG
      bool found = false;
#endif
      // There might be other literals implied to false (or even root level
      // falsified).  Those should be removed in addition to 'remove'.
      //
      for (j = c->begin (); j != eoc; j++) {
	const int other = *j, tmp = val (other);
	Var & v = var (other);
	if (tmp > 0) {
	  LOG ("redundant since literal %d already true", other);
	  clause.clear ();
	  goto REDUNDANT;
	}
	if (tmp < 0 && !v.level) continue;
	if (tmp < 0 && v.level && v.reason) {
	  assert (v.level);
	  assert (v.reason);
	  LOG ("flushing literal %d", other);
	  mark_removed (other);
#ifndef NDEBUG
	  if (other == remove) found = true;
#endif
	} else clause.push_back (other);
      }
      assert (found);
      assert (!clause.empty ());
      backtrack ();
      if (clause.size () == 1) {
	const int unit = clause[0];
	LOG (c, "vivification shrunken to unit %d", unit);
	assert (!val (unit));
	assign_unit (unit);
	units++;
	bool ok = propagate ();
	if (!ok) learn_empty_clause ();
      } else {
#ifdef LOGGING
	Clause * d =
#endif
	new_clause_as (c);
	LOG (c, "before vivification");
	LOG (d, "after vivification");
      }
      clause.clear ();
      mark_garbage (c);
    }
    if (level) backtrack ();
    c->ignore = false;
  }

  if (!unsat) {

    erase_vector (sorted);
    reset_noccs2 ();
    erase_vector (schedule);
    disconnect_watches ();
    connect_watches ();

    // [RE-PROPAGATE] Since redundant clause were disconnected during
    // propagating vivified units above, we have propagate all those fixed
    // literals again after connecting the redundant clauses back.
    // Otherwise, the invariants for watching and blocking literals break.
    //
    if (old_propagated < propagated) {
      propagated = old_propagated;
      if (!propagate ()) {
	LOG ("propagating vivified units leads to conflict");
	learn_empty_clause ();
      }
    }
  }

  VRB ("vivification", stats.vivifications,
    "checked %ld clauses %.02f%% out of scheduled",
    checked, percent (checked, scheduled));
  if (units)
  VRB ("vivification", stats.vivifications,
    "found %ld units %.02f%% out of checked",
    units, percent (units, checked));
  VRB ("vivification", stats.vivifications,
    "subsumed %ld clauses %.02f%% out of checked",
    subsumed, percent (subsumed, checked));
  VRB ("vivification", stats.vivifications,
    "strengthened %ld clauses %.02f%% out of checked",
    strengthened, percent (strengthened, checked));

  stats.vivifychecks += checked;
  stats.vivifysubs += subsumed;
  stats.vivifystrs += strengthened;
  stats.vivifyunits += units;

  stats.subsumed += subsumed;
  stats.strengthened += strengthened;

  assert (vivifying);
  vivifying = false;

  report ('v');
  STOP_AND_SWITCH (vivify, simplify, search);
}

};
<|endoftext|>


<commit_before>/**
* pty.js
* Copyright (c) 2013, Christopher Jeffrey, Peter Sunde (MIT License)
*
* pty.cc:
*   This file is responsible for starting processes
*   with pseudo-terminal file descriptors.
*/

#include <v8.h>
#include <node.h>
#include <node_buffer.h>
#include <string.h>
#include <stdlib.h>
#include <winpty.h>
#include <string>
#include <sstream>
#include <iostream>
#include <vector>

using namespace v8;
using namespace std;
using namespace node;

/**
* Misc
*/
extern "C" void init(Handle<Object>);

#define WINPTY_DBG_VARIABLE TEXT("WINPTYDBG")

/**
* winpty
*/
static std::vector<winpty_t *> ptyHandles;
static volatile LONG ptyCounter;

struct winpty_s {
  winpty_s();
  HANDLE controlPipe;
  HANDLE dataPipe;
};

winpty_s::winpty_s() :
  controlPipe(nullptr),
  dataPipe(nullptr)
{
}

/**
* Helpers
*/

const wchar_t* to_wstring(const String::Utf8Value& str)
{
  const char *bytes = *str;
  unsigned int sizeOfStr = MultiByteToWideChar(CP_ACP, 0, bytes, -1, NULL, 0);
  wchar_t *output = new wchar_t[sizeOfStr];
  MultiByteToWideChar(CP_ACP, 0, bytes, -1, output, sizeOfStr);
  return output;
}

static winpty_t *get_pipe_handle(int handle) {
  for(winpty_t *ptyHandle : ptyHandles) {
    int current = (int)ptyHandle->controlPipe;
    if(current == handle) {
      return ptyHandle;
    }
  }
  return nullptr;
}

static bool remove_pipe_handle(int handle) {
  for(winpty_t *ptyHandle : ptyHandles) {
    if((int)ptyHandle->controlPipe == handle) {
      delete ptyHandle;
      ptyHandle = nullptr;
      return true;
    }
  }
  return false;
}

/*
* PtyOpen
* pty.open(dataPipe, cols, rows)
*
* If you need to debug winpty-agent.exe do the following:
* ======================================================
*
* 1) Install python 2.7
* 2) Install win32pipe
x86) http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/pywin32-218.win32-py2.7.exe/download
x64) http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/pywin32-218.win-amd64-py2.7.exe/download
* 3) Start deps/winpty/misc/DebugServer.py (Before you start node)
*
* Then you'll see output from winpty-agent.exe.
*
* Important part:
* ===============
* CreateProcess: success 8896 0 (Windows error code)
*
* Create test.js:
* ===============
*
* var pty = require('./');
*
* var term = pty.fork('cmd', [], {
*   name: 'Windows Shell',
*	  cols: 80,
*	  rows: 30,
*	  cwd: process.env.HOME,
*	  env: process.env,
*	  debug: true
* });
*
* term.on('data', function(data) {
* 	console.log(data);
* });
*
*/

static Handle<Value> PtyOpen(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 4
    || !args[0]->IsString() // dataPipe
    || !args[1]->IsNumber() // cols
    || !args[2]->IsNumber() // rows
    || !args[3]->IsBoolean()) // debug
  {
    return ThrowException(Exception::Error(
      String::New("Usage: pty.open(dataPipe, cols, rows, debug)")));
  }

  const wchar_t *pipeName = to_wstring(String::Utf8Value(args[0]->ToString()));
  int cols = args[1]->Int32Value();
  int rows = args[2]->Int32Value();
  bool debug = args[3]->ToBoolean()->IsTrue();

  // Enable/disable debugging
  SetEnvironmentVariable(WINPTY_DBG_VARIABLE, debug ? "1" : NULL); // NULL = deletes variable

  // Open a new pty session.
  winpty_t *pc = winpty_open_use_own_datapipe(pipeName, cols, rows);

  // Error occured during startup of agent process.
  assert(pc != nullptr);

  // Save pty struct fpr later use.
  ptyHandles.insert(ptyHandles.end(), pc);

  // Pty object values.
  Local<Object> marshal = Object::New();
  marshal->Set(String::New("pid"), Number::New((int)pc->controlPipe));
  marshal->Set(String::New("pty"), Number::New(InterlockedIncrement(&ptyCounter)));
  marshal->Set(String::New("fd"), Number::New(-1));

  delete pipeName;

  return scope.Close(marshal);

}

/*
* PtyStartProcess
* pty.startProcess(pid, file, env, cwd);
*/

static Handle<Value> PtyStartProcess(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 5
    || !args[0]->IsNumber() // pid
    || !args[1]->IsString() // file
    || !args[2]->IsString() // cmdline
    || !args[3]->IsArray() // env
    || !args[4]->IsString()) // cwd
  {
    return ThrowException(Exception::Error(
      String::New("Usage: pty.startProcess(pid, file, cmdline, env, cwd)")));
  }

  // Get winpty_t by control pipe handle
  int pid = args[0]->Int32Value();

  winpty_t *pc = get_pipe_handle(pid);
  assert(pc != nullptr);

  const wchar_t *file = to_wstring(String::Utf8Value(args[1]->ToString()));
  const wchar_t *cmdline = to_wstring(String::Utf8Value(args[2]->ToString()));
  const wchar_t *cwd = to_wstring(String::Utf8Value(args[4]->ToString()));

  // create environment block
  wchar_t *env = NULL;
  const Handle<Array> envValues = Handle<Array>::Cast(args[3]);
  if(!envValues.IsEmpty()) {

    std::wstringstream envBlock;

    for(uint32_t i = 0; i < envValues->Length(); i++) {
      std::wstring envValue(to_wstring(String::Utf8Value(envValues->Get(i)->ToString())));
      envBlock << envValue << L' ';
    }

    std::wstring output = envBlock.str();

    size_t count = output.size();
    env = new wchar_t[count + 2];
    wcsncpy(env, output.c_str(), count);

    wcscat(env, L"\0");
  }

  // Start new terminal
  int result = winpty_start_process(pc, file, cmdline, cwd, env);
  delete env;

  assert(0 == result);

  return scope.Close(Undefined());
}

/*
* PtyResize
* pty.resize(pid, cols, rows);
*/
static Handle<Value> PtyResize(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 3
    || !args[0]->IsNumber() // pid
    || !args[1]->IsNumber() // cols
    || !args[2]->IsNumber()) // rows
  {
    return ThrowException(Exception::Error(String::New("Usage: pty.resize(pid, cols, rows)")));
  }

  int handle = args[0]->Int32Value();
  int cols = args[1]->Int32Value();
  int rows = args[2]->Int32Value();

  winpty_t *pc = get_pipe_handle(handle);

  assert(pc != nullptr);
  assert(0 == winpty_set_size(pc, cols, rows));

  return scope.Close(Undefined());
}

/*
* PtyKill
* pty.kill(pid);
*/
static Handle<Value> PtyKill(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 1
    || !args[0]->IsNumber()) // pid
  {
    return ThrowException(Exception::Error(String::New("Usage: pty.kill(pid)")));
  }

  int handle = args[0]->Int32Value();

  winpty_t *pc = get_pipe_handle(handle);

  assert(pc != nullptr);
  winpty_exit(pc);
  assert(true == remove_pipe_handle(handle));

  return scope.Close(Undefined());

}

/**
* Init
*/

extern "C" void init(Handle<Object> target) {
  HandleScope scope;
  NODE_SET_METHOD(target, "open", PtyOpen);
  NODE_SET_METHOD(target, "startProcess", PtyStartProcess);
  NODE_SET_METHOD(target, "resize", PtyResize);
  NODE_SET_METHOD(target, "kill", PtyKill);
};

NODE_MODULE(pty, init);
<commit_msg>:lipstick: Remove trailing spaces in lines.<commit_after>/**
* pty.js
* Copyright (c) 2013, Christopher Jeffrey, Peter Sunde (MIT License)
*
* pty.cc:
*   This file is responsible for starting processes
*   with pseudo-terminal file descriptors.
*/

#include <v8.h>
#include <node.h>
#include <node_buffer.h>
#include <string.h>
#include <stdlib.h>
#include <winpty.h>
#include <string>
#include <sstream>
#include <iostream>
#include <vector>

using namespace v8;
using namespace std;
using namespace node;

/**
* Misc
*/
extern "C" void init(Handle<Object>);

#define WINPTY_DBG_VARIABLE TEXT("WINPTYDBG")

/**
* winpty
*/
static std::vector<winpty_t *> ptyHandles;
static volatile LONG ptyCounter;

struct winpty_s {
  winpty_s();
  HANDLE controlPipe;
  HANDLE dataPipe;
};

winpty_s::winpty_s() :
  controlPipe(nullptr),
  dataPipe(nullptr)
{
}

/**
* Helpers
*/

const wchar_t* to_wstring(const String::Utf8Value& str)
{
  const char *bytes = *str;
  unsigned int sizeOfStr = MultiByteToWideChar(CP_ACP, 0, bytes, -1, NULL, 0);
  wchar_t *output = new wchar_t[sizeOfStr];
  MultiByteToWideChar(CP_ACP, 0, bytes, -1, output, sizeOfStr);
  return output;
}

static winpty_t *get_pipe_handle(int handle) {
  for(winpty_t *ptyHandle : ptyHandles) {
    int current = (int)ptyHandle->controlPipe;
    if(current == handle) {
      return ptyHandle;
    }
  }
  return nullptr;
}

static bool remove_pipe_handle(int handle) {
  for(winpty_t *ptyHandle : ptyHandles) {
    if((int)ptyHandle->controlPipe == handle) {
      delete ptyHandle;
      ptyHandle = nullptr;
      return true;
    }
  }
  return false;
}

/*
* PtyOpen
* pty.open(dataPipe, cols, rows)
*
* If you need to debug winpty-agent.exe do the following:
* ======================================================
*
* 1) Install python 2.7
* 2) Install win32pipe
x86) http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/pywin32-218.win32-py2.7.exe/download
x64) http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/pywin32-218.win-amd64-py2.7.exe/download
* 3) Start deps/winpty/misc/DebugServer.py (Before you start node)
*
* Then you'll see output from winpty-agent.exe.
*
* Important part:
* ===============
* CreateProcess: success 8896 0 (Windows error code)
*
* Create test.js:
* ===============
*
* var pty = require('./');
*
* var term = pty.fork('cmd', [], {
*   name: 'Windows Shell',
*	  cols: 80,
*	  rows: 30,
*	  cwd: process.env.HOME,
*	  env: process.env,
*	  debug: true
* });
*
* term.on('data', function(data) {
* 	console.log(data);
* });
*
*/

static Handle<Value> PtyOpen(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 4
    || !args[0]->IsString() // dataPipe
    || !args[1]->IsNumber() // cols
    || !args[2]->IsNumber() // rows
    || !args[3]->IsBoolean()) // debug
  {
    return ThrowException(Exception::Error(
      String::New("Usage: pty.open(dataPipe, cols, rows, debug)")));
  }

  const wchar_t *pipeName = to_wstring(String::Utf8Value(args[0]->ToString()));
  int cols = args[1]->Int32Value();
  int rows = args[2]->Int32Value();
  bool debug = args[3]->ToBoolean()->IsTrue();

  // Enable/disable debugging
  SetEnvironmentVariable(WINPTY_DBG_VARIABLE, debug ? "1" : NULL); // NULL = deletes variable

  // Open a new pty session.
  winpty_t *pc = winpty_open_use_own_datapipe(pipeName, cols, rows);

  // Error occured during startup of agent process.
  assert(pc != nullptr);

  // Save pty struct fpr later use.
  ptyHandles.insert(ptyHandles.end(), pc);

  // Pty object values.
  Local<Object> marshal = Object::New();
  marshal->Set(String::New("pid"), Number::New((int)pc->controlPipe));
  marshal->Set(String::New("pty"), Number::New(InterlockedIncrement(&ptyCounter)));
  marshal->Set(String::New("fd"), Number::New(-1));

  delete pipeName;

  return scope.Close(marshal);

}

/*
* PtyStartProcess
* pty.startProcess(pid, file, env, cwd);
*/

static Handle<Value> PtyStartProcess(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 5
    || !args[0]->IsNumber() // pid
    || !args[1]->IsString() // file
    || !args[2]->IsString() // cmdline
    || !args[3]->IsArray() // env
    || !args[4]->IsString()) // cwd
  {
    return ThrowException(Exception::Error(
      String::New("Usage: pty.startProcess(pid, file, cmdline, env, cwd)")));
  }

  // Get winpty_t by control pipe handle
  int pid = args[0]->Int32Value();

  winpty_t *pc = get_pipe_handle(pid);
  assert(pc != nullptr);

  const wchar_t *file = to_wstring(String::Utf8Value(args[1]->ToString()));
  const wchar_t *cmdline = to_wstring(String::Utf8Value(args[2]->ToString()));
  const wchar_t *cwd = to_wstring(String::Utf8Value(args[4]->ToString()));

  // create environment block
  wchar_t *env = NULL;
  const Handle<Array> envValues = Handle<Array>::Cast(args[3]);
  if(!envValues.IsEmpty()) {

    std::wstringstream envBlock;

    for(uint32_t i = 0; i < envValues->Length(); i++) {
      std::wstring envValue(to_wstring(String::Utf8Value(envValues->Get(i)->ToString())));
      envBlock << envValue << L' ';
    }

    std::wstring output = envBlock.str();

    size_t count = output.size();
    env = new wchar_t[count + 2];
    wcsncpy(env, output.c_str(), count);

    wcscat(env, L"\0");
  }

  // Start new terminal
  int result = winpty_start_process(pc, file, cmdline, cwd, env);
  delete env;

  assert(0 == result);

  return scope.Close(Undefined());
}

/*
* PtyResize
* pty.resize(pid, cols, rows);
*/
static Handle<Value> PtyResize(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 3
    || !args[0]->IsNumber() // pid
    || !args[1]->IsNumber() // cols
    || !args[2]->IsNumber()) // rows
  {
    return ThrowException(Exception::Error(String::New("Usage: pty.resize(pid, cols, rows)")));
  }

  int handle = args[0]->Int32Value();
  int cols = args[1]->Int32Value();
  int rows = args[2]->Int32Value();

  winpty_t *pc = get_pipe_handle(handle);

  assert(pc != nullptr);
  assert(0 == winpty_set_size(pc, cols, rows));

  return scope.Close(Undefined());
}

/*
* PtyKill
* pty.kill(pid);
*/
static Handle<Value> PtyKill(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 1
    || !args[0]->IsNumber()) // pid
  {
    return ThrowException(Exception::Error(String::New("Usage: pty.kill(pid)")));
  }

  int handle = args[0]->Int32Value();

  winpty_t *pc = get_pipe_handle(handle);

  assert(pc != nullptr);
  winpty_exit(pc);
  assert(true == remove_pipe_handle(handle));

  return scope.Close(Undefined());

}

/**
* Init
*/

extern "C" void init(Handle<Object> target) {
  HandleScope scope;
  NODE_SET_METHOD(target, "open", PtyOpen);
  NODE_SET_METHOD(target, "startProcess", PtyStartProcess);
  NODE_SET_METHOD(target, "resize", PtyResize);
  NODE_SET_METHOD(target, "kill", PtyKill);
};

NODE_MODULE(pty, init);
<|endoftext|>