<commit_before>/* This source file is part of the Tomviz project, https://tomviz.org/.
   It is released under the 3-Clause BSD License, see "LICENSE". */

#include "ExternalPythonExecutor.h"
#include "DataSource.h"
#include "EmdFormat.h"
#include "Operator.h"
#include "OperatorPython.h"
#include "Pipeline.h"
#include "PipelineWorker.h"

namespace tomviz {

ExternalPythonExecutor::ExternalPythonExecutor(Pipeline* pipeline)
  : ExternalPipelineExecutor(pipeline)
{
}

ExternalPythonExecutor::~ExternalPythonExecutor() = default;

Pipeline::Future* ExternalPythonExecutor::execute(vtkDataObject* data,
                                                  QList<Operator*> operators,
                                                  int start, int end)
{

  auto future = ExternalPipelineExecutor::execute(data, operators, start, end);

  // We are now ready to run the pipeline
  QStringList args = executorArgs(start);

  PipelineSettings settings;
  auto pythonExecutable = settings.externalPythonExecutablePath();

  // Find the tomviz-pipeline executable
  auto pythonExecutableFile = QFileInfo(pythonExecutable);

  if (!pythonExecutableFile.exists()) {
    displayError("External Python Error",
                 QString("The external python executable doesn't exist: %1\n")
                   .arg(pythonExecutable));

    return Pipeline::emptyFuture();
  }

  auto baseDir = pythonExecutableFile.dir();
  auto tomvizPipelineExecutable =
    QFileInfo(baseDir.filePath("tomviz-pipeline"));
  if (!tomvizPipelineExecutable.exists()) {
    displayError(
      "External Python Error",
      QString("Unable to find tomviz-pipeline executable, please ensure "
              "tomviz package has been installed in python environment."
              "Click the Help button for more details on setting up your "
              "Python environment."));

    return Pipeline::emptyFuture();
  }

  m_process.reset(new QProcess(this));

  connect(m_process.data(), &QProcess::errorOccurred, this,
          &ExternalPythonExecutor::error);
  connect(
    m_process.data(),
    QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
    [this](int exitCode, QProcess::ExitStatus exitStatus) {

      if (exitStatus == QProcess::CrashExit) {
        displayError("External Python Error",
                     QString("The external python process crash: %1\n\n "
                             "stderr:\n%2 \n\n stdout:\n%3 \n")
                       .arg(commandLine(this->m_process.data()))
                       .arg(QString(this->m_process->readAllStandardError()))
                       .arg(QString(this->m_process->readAllStandardOutput())));

      } else if (exitCode != 0) {
        displayError(
          "External Python Error",
          QString("The external python return a non-zero exist code: %1\n\n "
                  "command: %2 \n\n stderr:\n%3 \n\n stdout:\n%4 \n")
            .arg(exitCode)
            .arg(commandLine(this->m_process.data()))
            .arg(QString(this->m_process->readAllStandardError()))
            .arg(QString(this->m_process->readAllStandardOutput())));
      }
    });

  // We have to get the process environment and unset TOMVIZ_APPLICATION and
  // set that as the process environment for the process, otherwise the
  // python package will think its running in the applicaton.
  auto processEnv = QProcessEnvironment::systemEnvironment();
  processEnv.remove("TOMVIZ_APPLICATION");
  m_process->setProcessEnvironment(processEnv);

  m_process->start(tomvizPipelineExecutable.filePath(), args);

  return future;
}

void ExternalPythonExecutor::cancel(std::function<void()> canceled)
{

  reset();

  m_process->kill();

  canceled();
}

bool ExternalPythonExecutor::cancel(Operator* op)
{
  Q_UNUSED(op);

  // Stop the progress reader
  m_progressReader->stop();

  m_process->kill();

  // Clean update state.
  reset();

  // We can't cancel an individual operator so we return false, so the caller
  // knows
  return false;
}

bool ExternalPythonExecutor::isRunning()
{
  return !m_process.isNull() && m_process->state() != QProcess::NotRunning;
}

void ExternalPythonExecutor::error(QProcess::ProcessError error)
{
  auto process = qobject_cast<QProcess*>(sender());
  auto invocation = commandLine(process);

  displayError("Execution Error",
               QString("An error occurred executing '%1', '%2'")
                 .arg(invocation)
                 .arg(error));
}

void ExternalPythonExecutor::pipelineStarted()
{
  qDebug("Pipeline started in external python!");
}

void ExternalPythonExecutor::reset()
{
  ExternalPipelineExecutor::reset();

  m_process->waitForFinished();
  m_process.reset();
}

QString ExternalPythonExecutor::executorWorkingDir()
{
  return workingDir();
}

QString ExternalPythonExecutor::commandLine(QProcess* process)
{
  return QString("%1 %2")
    .arg(process->program())
    .arg(process->arguments().join(" "));
}

} // namespace tomviz
<commit_msg>Send stdout and stderr to the message console<commit_after>/* This source file is part of the Tomviz project, https://tomviz.org/.
   It is released under the 3-Clause BSD License, see "LICENSE". */

#include "ExternalPythonExecutor.h"
#include "DataSource.h"
#include "EmdFormat.h"
#include "Operator.h"
#include "OperatorPython.h"
#include "Pipeline.h"
#include "PipelineWorker.h"

namespace tomviz {

ExternalPythonExecutor::ExternalPythonExecutor(Pipeline* pipeline)
  : ExternalPipelineExecutor(pipeline)
{
}

ExternalPythonExecutor::~ExternalPythonExecutor() = default;

Pipeline::Future* ExternalPythonExecutor::execute(vtkDataObject* data,
                                                  QList<Operator*> operators,
                                                  int start, int end)
{

  auto future = ExternalPipelineExecutor::execute(data, operators, start, end);

  // We are now ready to run the pipeline
  QStringList args = executorArgs(start);

  PipelineSettings settings;
  auto pythonExecutable = settings.externalPythonExecutablePath();

  // Find the tomviz-pipeline executable
  auto pythonExecutableFile = QFileInfo(pythonExecutable);

  if (!pythonExecutableFile.exists()) {
    displayError("External Python Error",
                 QString("The external python executable doesn't exist: %1\n")
                   .arg(pythonExecutable));

    return Pipeline::emptyFuture();
  }

  auto baseDir = pythonExecutableFile.dir();
  auto tomvizPipelineExecutable =
    QFileInfo(baseDir.filePath("tomviz-pipeline"));
  if (!tomvizPipelineExecutable.exists()) {
    displayError(
      "External Python Error",
      QString("Unable to find tomviz-pipeline executable, please ensure "
              "tomviz package has been installed in python environment."
              "Click the Help button for more details on setting up your "
              "Python environment."));

    return Pipeline::emptyFuture();
  }

  m_process.reset(new QProcess(this));

  connect(m_process.data(), &QProcess::errorOccurred, this,
          &ExternalPythonExecutor::error);
  connect(
    m_process.data(),
    QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
    [this](int exitCode, QProcess::ExitStatus exitStatus) {

      QString standardOut(this->m_process->readAllStandardOutput());
      QString standardErr(this->m_process->readAllStandardError());

      if (exitStatus == QProcess::CrashExit) {
        displayError("External Python Error",
                     QString("The external python process crash: %1\n\n "
                             "stderr:\n%2 \n\n stdout:\n%3 \n")
                       .arg(commandLine(this->m_process.data()))
                       .arg(standardErr)
                       .arg(standardOut));

      } else if (exitCode != 0) {
        displayError(
          "External Python Error",
          QString("The external python return a non-zero exist code: %1\n\n "
                  "command: %2 \n\n stderr:\n%3 \n\n stdout:\n%4 \n")
            .arg(exitCode)
            .arg(commandLine(this->m_process.data()))
            .arg(standardErr)
            .arg(standardOut));
      }

      qDebug().noquote() << standardErr;
      qDebug().noquote() << standardOut;
    });

  // We have to get the process environment and unset TOMVIZ_APPLICATION and
  // set that as the process environment for the process, otherwise the
  // python package will think its running in the applicaton.
  auto processEnv = QProcessEnvironment::systemEnvironment();
  processEnv.remove("TOMVIZ_APPLICATION");
  m_process->setProcessEnvironment(processEnv);

  m_process->start(tomvizPipelineExecutable.filePath(), args);

  return future;
}

void ExternalPythonExecutor::cancel(std::function<void()> canceled)
{

  reset();

  m_process->kill();

  canceled();
}

bool ExternalPythonExecutor::cancel(Operator* op)
{
  Q_UNUSED(op);

  // Stop the progress reader
  m_progressReader->stop();

  m_process->kill();

  // Clean update state.
  reset();

  // We can't cancel an individual operator so we return false, so the caller
  // knows
  return false;
}

bool ExternalPythonExecutor::isRunning()
{
  return !m_process.isNull() && m_process->state() != QProcess::NotRunning;
}

void ExternalPythonExecutor::error(QProcess::ProcessError error)
{
  auto process = qobject_cast<QProcess*>(sender());
  auto invocation = commandLine(process);

  displayError("Execution Error",
               QString("An error occurred executing '%1', '%2'")
                 .arg(invocation)
                 .arg(error));
}

void ExternalPythonExecutor::pipelineStarted()
{
  qDebug("Pipeline started in external python!");
}

void ExternalPythonExecutor::reset()
{
  ExternalPipelineExecutor::reset();

  m_process->waitForFinished();
  m_process.reset();
}

QString ExternalPythonExecutor::executorWorkingDir()
{
  return workingDir();
}

QString ExternalPythonExecutor::commandLine(QProcess* process)
{
  return QString("%1 %2")
    .arg(process->program())
    .arg(process->arguments().join(" "));
}

} // namespace tomviz
<|endoftext|>


<commit_before>#include "hphp/runtime/base/base-includes.h"
#include "hphp/runtime/ext/std/ext_std_errorfunc.h"
#include "hphp/runtime/base/php-globals.h"
#include "hphp/runtime/base/hphp-system.h"
#include "hphp/runtime/ext/ext_hotprofiler.h"
#include "newrelic_transaction.h"
#include "newrelic_collector_client.h"
#include "newrelic_common.h"
#include "newrelic_profiler.h"

#include <string>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <thread>
#include <unistd.h>

using namespace std;

namespace HPHP {

bool keep_running = true;

class ScopedGenericSegment : public SweepableResourceData {
public:
    DECLARE_RESOURCE_ALLOCATION(ScopedGenericSegment)
    CLASSNAME_IS("scoped_generic_segment")

    virtual const String& o_getClassNameHook() const { return classnameof(); }

    explicit ScopedGenericSegment(string name) : name(name) {
        segment_id = newrelic_segment_generic_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, name.c_str());
    }

    virtual ~ScopedGenericSegment() {
        if (segment_id < 0) return;
        newrelic_segment_end(NEWRELIC_AUTOSCOPE, segment_id);
    }

private:
    int64_t segment_id;
    string name;
};

void ScopedGenericSegment::sweep() { }

class ScopedDatastoreSegment : public SweepableResourceData {
public:
    DECLARE_RESOURCE_ALLOCATION(ScopedDatastoreSegment)
    CLASSNAME_IS("scoped_database_segment")

    virtual const String& o_getClassNameHook() const { return classnameof(); }

    explicit ScopedDatastoreSegment(string table, string operation) : table(table), operation(operation) {
// TODO        segment_id = newrelic_segment_datastore_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, table.c_str(), operation.c_str());
    }

    virtual ~ScopedDatastoreSegment() {
        if (segment_id < 0) return;
        newrelic_segment_end(NEWRELIC_AUTOSCOPE, segment_id);
    }

private:
    int64_t segment_id;
    string table;
    string operation;
};

void ScopedDatastoreSegment::sweep() { }

class ScopedExternalSegment : public SweepableResourceData {
public:
    DECLARE_RESOURCE_ALLOCATION(ScopedExternalSegment)
    CLASSNAME_IS("scoped_external_segment")

    virtual const String& o_getClassNameHook() const { return classnameof(); }

    explicit ScopedExternalSegment(string host, string name) : host(host), name(name) {
        segment_id = newrelic_segment_external_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, host.c_str(), name.c_str());
    }

    virtual ~ScopedExternalSegment() {
        if (segment_id < 0) return;
        newrelic_segment_end(NEWRELIC_AUTOSCOPE, segment_id);
    }

private:
    int64_t segment_id;
    string host;
    string name;
};

void ScopedExternalSegment::sweep() { }

// Profiler factory- for starting and stopping the profiler
DECLARE_EXTERN_REQUEST_LOCAL(ProfilerFactory, s_profiler_factory);

static int64_t HHVM_FUNCTION(newrelic_start_transaction_intern) {
    int64_t transaction_id = newrelic_transaction_begin();
    return transaction_id;
}

static int64_t HHVM_FUNCTION(newrelic_name_transaction_intern, const String & name) {
    return newrelic_transaction_set_name(NEWRELIC_AUTOSCOPE, name.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_transaction_set_request_url, const String & request_url) {
    return newrelic_transaction_set_request_url(NEWRELIC_AUTOSCOPE, request_url.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_transaction_set_max_trace_segments, int threshold) {
    return newrelic_transaction_set_max_trace_segments(NEWRELIC_AUTOSCOPE, threshold);
}

static int64_t HHVM_FUNCTION(newrelic_transaction_set_threshold, int threshold) {
    //deprecated
    return false;
}

static int64_t HHVM_FUNCTION(newrelic_end_transaction) {
    return newrelic_transaction_end(NEWRELIC_AUTOSCOPE);
}

static int64_t HHVM_FUNCTION(newrelic_segment_generic_begin, const String & name) {
    return newrelic_segment_generic_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, name.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_segment_datastore_begin, const String & table, const String & operation, const String & sql, const String & sql_trace_rollup_name, String & sql_obfuscator) {
// TODO    return newrelic_segment_datastore_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, table.c_str(), operation.c_str(), sql.c_str(), sql_trace_rollup_name.c_str(), sql_obfuscator.c_str());
    return false;
}

static int64_t HHVM_FUNCTION(newrelic_segment_external_begin, const String & host, const String & name) {
    return newrelic_segment_external_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, host.c_str(), name.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_segment_end, int64_t id) {
    return newrelic_segment_end(NEWRELIC_AUTOSCOPE, id);
}

static int64_t HHVM_FUNCTION(newrelic_notice_error_intern, const String & exception_type,  const String & error_message,  const String & stack_trace,  const String & stack_frame_delimiter) {
    return newrelic_transaction_notice_error(NEWRELIC_AUTOSCOPE, exception_type.c_str(), error_message.c_str(), stack_trace.c_str(), stack_frame_delimiter.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_add_attribute_intern, const String & name, const String & value) {
    return newrelic_transaction_add_attribute(NEWRELIC_AUTOSCOPE, name.c_str(), value.c_str());
}

static void HHVM_FUNCTION(newrelic_set_external_profiler, int64_t maxdepth ) {
    Profiler *pr = new NewRelicProfiler(maxdepth);
    s_profiler_factory->setExternalProfiler(pr);
}

static Variant HHVM_FUNCTION(newrelic_get_scoped_generic_segment, const String & name) {
    ScopedGenericSegment * segment = nullptr;
    segment = newres<ScopedGenericSegment>(name.c_str());
    return Resource(segment);
}

static Variant HHVM_FUNCTION(newrelic_get_scoped_database_segment, const String & table, const String & operation) {
    ScopedDatastoreSegment * segment = nullptr;
    segment = newres<ScopedDatastoreSegment>(table.c_str(), operation.c_str());
    return Resource(segment);
}

static Variant HHVM_FUNCTION(newrelic_get_scoped_external_segment, const String & host, const String & name) {
    ScopedExternalSegment * segment = nullptr;
    segment = newres<ScopedExternalSegment>(host.c_str(), name.c_str());
    return Resource(segment);
}

const StaticString
  s__NR_ERROR_CALLBACK("NewRelicExtensionHelper::errorCallback"),
  s__NR_EXCEPTION_CALLBACK("NewRelicExtensionHelper::exceptionCallback");

static class NewRelicExtension : public Extension {
public:
    NewRelicExtension () : Extension("newrelic") {
        config_loaded = false;
    }

    virtual void init_newrelic() {
        newrelic_register_message_handler(newrelic_message_handler);
        newrelic_init(license_key.c_str(), app_name.c_str(), app_language.c_str(), app_language_version.c_str());
    }

    virtual void moduleLoad(const IniSetting::Map& ini, Hdf config) {

        license_key = RuntimeOption::EnvVariables["NEWRELIC_LICENSE_KEY"];
        app_name = RuntimeOption::EnvVariables["NEWRELIC_APP_NAME"];
        app_language = RuntimeOption::EnvVariables["NEWRELIC_APP_LANGUAGE"];
        app_language_version = RuntimeOption::EnvVariables["NEWRELIC_APP_LANGUAGE_VERSION"];

        if (app_language.empty()) {
            app_language = "php-hhvm";
        }

        if (app_language_version.empty()) {
            app_language_version = HPHP::getHphpCompilerVersion();
        }

        setenv("NEWRELIC_LICENSE_KEY", license_key.c_str(), 1);
        setenv("NEWRELIC_APP_NAME", app_name.c_str(), 1);
        setenv("NEWRELIC_APP_LANGUAGE", app_language.c_str(), 1);
        setenv("NEWRELIC_APP_LANGUAGE_VERSION", app_language_version.c_str(), 1);

        if (!license_key.empty() && !app_name.empty() && !app_language.empty() && !app_language_version.empty())
            config_loaded = true;

    }

    virtual void moduleInit () {
        if (config_loaded) init_newrelic();

        HHVM_FE(newrelic_start_transaction_intern);
        HHVM_FE(newrelic_name_transaction_intern);
        HHVM_FE(newrelic_transaction_set_request_url);
        HHVM_FE(newrelic_transaction_set_max_trace_segments);
        HHVM_FE(newrelic_transaction_set_threshold);
        HHVM_FE(newrelic_end_transaction);
        HHVM_FE(newrelic_segment_generic_begin);
        HHVM_FE(newrelic_segment_datastore_begin);
        HHVM_FE(newrelic_segment_external_begin);
        HHVM_FE(newrelic_segment_end);
        HHVM_FE(newrelic_get_scoped_generic_segment);
        HHVM_FE(newrelic_get_scoped_database_segment);
        HHVM_FE(newrelic_get_scoped_external_segment);
        HHVM_FE(newrelic_notice_error_intern);
        HHVM_FE(newrelic_add_attribute_intern);
        HHVM_FE(newrelic_set_external_profiler);

        loadSystemlib();
    }

    virtual void requestShutdown() {

        newrelic_transaction_end(NEWRELIC_AUTOSCOPE);
    }

    virtual void requestInit() {
        f_set_error_handler(s__NR_ERROR_CALLBACK);
        f_set_exception_handler(s__NR_EXCEPTION_CALLBACK);
        //TODO: make it possible to disable that via ini
        newrelic_transaction_begin();
        String request_url = php_global(s__SERVER).toArray()[s__REQUEST_URI].toString();
        newrelic_transaction_set_request_url(NEWRELIC_AUTOSCOPE, request_url.c_str());
        String script_name = php_global(s__SERVER).toArray()[s__SCRIPT_NAME].toString();
        newrelic_transaction_set_name(NEWRELIC_AUTOSCOPE, script_name.c_str());
    }

private:
    std::string license_key;
    std::string app_name;
    std::string app_language;
    std::string app_language_version;
    int64_t global_transaction_id = 0;
    bool config_loaded;

} s_newrelic_extension;

HHVM_GET_MODULE(newrelic)

} // namespace HPHP
<commit_msg>Add NO_EXTENSION_VERSION_YET<commit_after>#include "hphp/runtime/base/base-includes.h"
#include "hphp/runtime/ext/std/ext_std_errorfunc.h"
#include "hphp/runtime/base/php-globals.h"
#include "hphp/runtime/base/hphp-system.h"
#include "hphp/runtime/ext/ext_hotprofiler.h"
#include "newrelic_transaction.h"
#include "newrelic_collector_client.h"
#include "newrelic_common.h"
#include "newrelic_profiler.h"

#include <string>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <thread>
#include <unistd.h>

using namespace std;

namespace HPHP {

bool keep_running = true;

class ScopedGenericSegment : public SweepableResourceData {
public:
    DECLARE_RESOURCE_ALLOCATION(ScopedGenericSegment)
    CLASSNAME_IS("scoped_generic_segment")

    virtual const String& o_getClassNameHook() const { return classnameof(); }

    explicit ScopedGenericSegment(string name) : name(name) {
        segment_id = newrelic_segment_generic_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, name.c_str());
    }

    virtual ~ScopedGenericSegment() {
        if (segment_id < 0) return;
        newrelic_segment_end(NEWRELIC_AUTOSCOPE, segment_id);
    }

private:
    int64_t segment_id;
    string name;
};

void ScopedGenericSegment::sweep() { }

class ScopedDatastoreSegment : public SweepableResourceData {
public:
    DECLARE_RESOURCE_ALLOCATION(ScopedDatastoreSegment)
    CLASSNAME_IS("scoped_database_segment")

    virtual const String& o_getClassNameHook() const { return classnameof(); }

    explicit ScopedDatastoreSegment(string table, string operation) : table(table), operation(operation) {
// TODO        segment_id = newrelic_segment_datastore_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, table.c_str(), operation.c_str());
    }

    virtual ~ScopedDatastoreSegment() {
        if (segment_id < 0) return;
        newrelic_segment_end(NEWRELIC_AUTOSCOPE, segment_id);
    }

private:
    int64_t segment_id;
    string table;
    string operation;
};

void ScopedDatastoreSegment::sweep() { }

class ScopedExternalSegment : public SweepableResourceData {
public:
    DECLARE_RESOURCE_ALLOCATION(ScopedExternalSegment)
    CLASSNAME_IS("scoped_external_segment")

    virtual const String& o_getClassNameHook() const { return classnameof(); }

    explicit ScopedExternalSegment(string host, string name) : host(host), name(name) {
        segment_id = newrelic_segment_external_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, host.c_str(), name.c_str());
    }

    virtual ~ScopedExternalSegment() {
        if (segment_id < 0) return;
        newrelic_segment_end(NEWRELIC_AUTOSCOPE, segment_id);
    }

private:
    int64_t segment_id;
    string host;
    string name;
};

void ScopedExternalSegment::sweep() { }

// Profiler factory- for starting and stopping the profiler
DECLARE_EXTERN_REQUEST_LOCAL(ProfilerFactory, s_profiler_factory);

static int64_t HHVM_FUNCTION(newrelic_start_transaction_intern) {
    int64_t transaction_id = newrelic_transaction_begin();
    return transaction_id;
}

static int64_t HHVM_FUNCTION(newrelic_name_transaction_intern, const String & name) {
    return newrelic_transaction_set_name(NEWRELIC_AUTOSCOPE, name.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_transaction_set_request_url, const String & request_url) {
    return newrelic_transaction_set_request_url(NEWRELIC_AUTOSCOPE, request_url.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_transaction_set_max_trace_segments, int threshold) {
    return newrelic_transaction_set_max_trace_segments(NEWRELIC_AUTOSCOPE, threshold);
}

static int64_t HHVM_FUNCTION(newrelic_transaction_set_threshold, int threshold) {
    //deprecated
    return false;
}

static int64_t HHVM_FUNCTION(newrelic_end_transaction) {
    return newrelic_transaction_end(NEWRELIC_AUTOSCOPE);
}

static int64_t HHVM_FUNCTION(newrelic_segment_generic_begin, const String & name) {
    return newrelic_segment_generic_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, name.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_segment_datastore_begin, const String & table, const String & operation, const String & sql, const String & sql_trace_rollup_name, String & sql_obfuscator) {
// TODO    return newrelic_segment_datastore_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, table.c_str(), operation.c_str(), sql.c_str(), sql_trace_rollup_name.c_str(), sql_obfuscator.c_str());
    return false;
}

static int64_t HHVM_FUNCTION(newrelic_segment_external_begin, const String & host, const String & name) {
    return newrelic_segment_external_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, host.c_str(), name.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_segment_end, int64_t id) {
    return newrelic_segment_end(NEWRELIC_AUTOSCOPE, id);
}

static int64_t HHVM_FUNCTION(newrelic_notice_error_intern, const String & exception_type,  const String & error_message,  const String & stack_trace,  const String & stack_frame_delimiter) {
    return newrelic_transaction_notice_error(NEWRELIC_AUTOSCOPE, exception_type.c_str(), error_message.c_str(), stack_trace.c_str(), stack_frame_delimiter.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_add_attribute_intern, const String & name, const String & value) {
    return newrelic_transaction_add_attribute(NEWRELIC_AUTOSCOPE, name.c_str(), value.c_str());
}

static void HHVM_FUNCTION(newrelic_set_external_profiler, int64_t maxdepth ) {
    Profiler *pr = new NewRelicProfiler(maxdepth);
    s_profiler_factory->setExternalProfiler(pr);
}

static Variant HHVM_FUNCTION(newrelic_get_scoped_generic_segment, const String & name) {
    ScopedGenericSegment * segment = nullptr;
    segment = newres<ScopedGenericSegment>(name.c_str());
    return Resource(segment);
}

static Variant HHVM_FUNCTION(newrelic_get_scoped_database_segment, const String & table, const String & operation) {
    ScopedDatastoreSegment * segment = nullptr;
    segment = newres<ScopedDatastoreSegment>(table.c_str(), operation.c_str());
    return Resource(segment);
}

static Variant HHVM_FUNCTION(newrelic_get_scoped_external_segment, const String & host, const String & name) {
    ScopedExternalSegment * segment = nullptr;
    segment = newres<ScopedExternalSegment>(host.c_str(), name.c_str());
    return Resource(segment);
}

const StaticString
  s__NR_ERROR_CALLBACK("NewRelicExtensionHelper::errorCallback"),
  s__NR_EXCEPTION_CALLBACK("NewRelicExtensionHelper::exceptionCallback");

static class NewRelicExtension : public Extension {
public:
    NewRelicExtension () : Extension("newrelic", NO_EXTENSION_VERSION_YET) {
        config_loaded = false;
    }

    virtual void init_newrelic() {
        newrelic_register_message_handler(newrelic_message_handler);
        newrelic_init(license_key.c_str(), app_name.c_str(), app_language.c_str(), app_language_version.c_str());
    }

    virtual void moduleLoad(const IniSetting::Map& ini, Hdf config) {

        license_key = RuntimeOption::EnvVariables["NEWRELIC_LICENSE_KEY"];
        app_name = RuntimeOption::EnvVariables["NEWRELIC_APP_NAME"];
        app_language = RuntimeOption::EnvVariables["NEWRELIC_APP_LANGUAGE"];
        app_language_version = RuntimeOption::EnvVariables["NEWRELIC_APP_LANGUAGE_VERSION"];

        if (app_language.empty()) {
            app_language = "php-hhvm";
        }

        if (app_language_version.empty()) {
            app_language_version = HPHP::getHphpCompilerVersion();
        }

        setenv("NEWRELIC_LICENSE_KEY", license_key.c_str(), 1);
        setenv("NEWRELIC_APP_NAME", app_name.c_str(), 1);
        setenv("NEWRELIC_APP_LANGUAGE", app_language.c_str(), 1);
        setenv("NEWRELIC_APP_LANGUAGE_VERSION", app_language_version.c_str(), 1);

        if (!license_key.empty() && !app_name.empty() && !app_language.empty() && !app_language_version.empty())
            config_loaded = true;

    }

    virtual void moduleInit () {
        if (config_loaded) init_newrelic();

        HHVM_FE(newrelic_start_transaction_intern);
        HHVM_FE(newrelic_name_transaction_intern);
        HHVM_FE(newrelic_transaction_set_request_url);
        HHVM_FE(newrelic_transaction_set_max_trace_segments);
        HHVM_FE(newrelic_transaction_set_threshold);
        HHVM_FE(newrelic_end_transaction);
        HHVM_FE(newrelic_segment_generic_begin);
        HHVM_FE(newrelic_segment_datastore_begin);
        HHVM_FE(newrelic_segment_external_begin);
        HHVM_FE(newrelic_segment_end);
        HHVM_FE(newrelic_get_scoped_generic_segment);
        HHVM_FE(newrelic_get_scoped_database_segment);
        HHVM_FE(newrelic_get_scoped_external_segment);
        HHVM_FE(newrelic_notice_error_intern);
        HHVM_FE(newrelic_add_attribute_intern);
        HHVM_FE(newrelic_set_external_profiler);

        loadSystemlib();
    }

    virtual void requestShutdown() {

        newrelic_transaction_end(NEWRELIC_AUTOSCOPE);
    }

    virtual void requestInit() {
        f_set_error_handler(s__NR_ERROR_CALLBACK);
        f_set_exception_handler(s__NR_EXCEPTION_CALLBACK);
        //TODO: make it possible to disable that via ini
        newrelic_transaction_begin();
        String request_url = php_global(s__SERVER).toArray()[s__REQUEST_URI].toString();
        newrelic_transaction_set_request_url(NEWRELIC_AUTOSCOPE, request_url.c_str());
        String script_name = php_global(s__SERVER).toArray()[s__SCRIPT_NAME].toString();
        newrelic_transaction_set_name(NEWRELIC_AUTOSCOPE, script_name.c_str());
    }

private:
    std::string license_key;
    std::string app_name;
    std::string app_language;
    std::string app_language_version;
    int64_t global_transaction_id = 0;
    bool config_loaded;

} s_newrelic_extension;

HHVM_GET_MODULE(newrelic)

} // namespace HPHP
<|endoftext|>


<commit_before>/*
Copyright (c) 2011, Wesley Moore http://www.wezm.net/
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 node-genx Project, Wesley Moore, 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 HOLDER 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 <node.h>
#include <node_events.h>
#include <iostream>
extern "C" {
#include "genx.h"
}

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

static Persistent<String> sym_data;

class Writer: public EventEmitter
{
private:
  genxWriter writer;
  genxSender sender;
  Persistent<Object> stream;
public:

  static void Initialize(Handle<Object> target)
  {
    HandleScope scope;

    Local<FunctionTemplate> t = FunctionTemplate::New(New);
    t->Inherit(EventEmitter::constructor_template);
    t->InstanceTemplate()->SetInternalFieldCount(1);
    t->SetClassName(String::NewSymbol("Writer"));

    NODE_SET_PROTOTYPE_METHOD(t, "startDocument", StartDoc);
    NODE_SET_PROTOTYPE_METHOD(t, "endDocument", EndDocument);

    NODE_SET_PROTOTYPE_METHOD(t, "startElementLiteral", StartElementLiteral);

    NODE_SET_PROTOTYPE_METHOD(t, "addText", AddText);
    NODE_SET_PROTOTYPE_METHOD(t, "addComment", AddComment);
    NODE_SET_PROTOTYPE_METHOD(t, "addAttributeLiteral", AddAttributeLiteral);

    NODE_SET_PROTOTYPE_METHOD(t, "endElement", EndElement);

    target->Set(String::NewSymbol("Writer"), t->GetFunction());

    sym_data = NODE_PSYMBOL("data");
  }

  Writer()
  {
    // alloc, free, userData
    writer = genxNew(NULL, NULL, this);
    sender.send = sender_send;
    sender.sendBounded = sender_sendBounded;
    sender.flush = sender_flush;
    stream = Persistent<Object>::Persistent();
  }

  ~Writer()
  {
    if(!stream.IsEmpty()) stream.Dispose(); // or Clear?
    genxDispose(writer);
  }

protected:

  static Handle<Value> New(const Arguments& args)
  {
    HandleScope scope;
    Writer* writer = new Writer();
    writer->Wrap(args.This());
    return args.This();
  }

  static Handle<Value> StartDoc(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());

    w->startDoc();
    return args.This();
  }

  genxStatus startDoc()
  {
    return genxStartDocSender(writer, &sender);
  }

  static Handle<Value> EndDocument(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());

    w->endDocument();
    return args.This();
  }

  genxStatus endDocument()
  {
    return genxEndDocument(writer);
  }

  static Handle<Value> StartElementLiteral(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());
    utf8 type = NULL;

    if (args.Length() <1 ||
        !args[0]->IsString()) {
      return ThrowException(Exception::Error(String::New(
        "First argument must be a String")));
    }

    Local<String> Type = args[0]->ToString();

    // Get the raw UTF-8 element type
    int length = Type->Utf8Length();
    type = new unsigned char[length];

    Type->WriteUtf8((char *)type, length);

    w->startElementLiteral(type);
    delete[] type;

    return args.This();
  }

  genxStatus startElementLiteral(constUtf8 type)
  {
    return genxStartElementLiteral(writer, NULL, type);
  }

  static Handle<Value> AddText(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());
    utf8 text = NULL;
    genxStatus status;

    if (args.Length() <1 ||
        !args[0]->IsString()) {
      return ThrowException(Exception::Error(String::New(
        "First argument must be a String")));
    }

    // Get the raw UTF-8 text
    Local<String> Text = args[0]->ToString();
    int length = Text->Utf8Length();
    text = new unsigned char[length];
    Text->WriteUtf8((char *)text, length);

    status = w->addText(text);
    delete[] text;

    return args.This();
  }

  genxStatus addText(constUtf8 text)
  {
    // TODO handle the return value from genx here?
    return genxAddText(writer, text);
  }

  static Handle<Value> AddComment(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());
    utf8 text = NULL;
    genxStatus status;

    if (args.Length() <1 ||
        !args[0]->IsString()) {
      return ThrowException(Exception::Error(String::New(
        "First argument must be a String")));
    }

    Local<String> Text = args[0]->ToString();
    text = createUtf8FromString(Text);

    status = w->addComment(text);
    delete[] text;

    return args.This();
  }

  genxStatus addComment(constUtf8 comment)
  {
    // TODO handle the return value from genx here?
    return genxComment(writer, comment);
  }

  static Handle<Value> AddAttributeLiteral(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());
    utf8 name = NULL;
    utf8 value = NULL;

    if (args.Length() < 2    ||
       !args[0]->IsString() ||
       !args[1]->IsString()) {
      return ThrowException(Exception::Error(String::New(
        "Must supply two string arguments")));
    }

    Local<String> Name = args[0]->ToString();
    Local<String> Value = args[1]->ToString();

    // Get the raw UTF-8 strings
    name = createUtf8FromString(Name);
    value = createUtf8FromString(Value);

    w->addAttributeLiteral(name, value);
    delete[] name;
    delete[] value;

    return args.This();
  }

  genxStatus addAttributeLiteral(constUtf8 name, constUtf8 value)
  {
    constUtf8 xmlns = NULL;
    return genxAddAttributeLiteral(writer, xmlns, name, value);
  }

  static Handle<Value> EndElement(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());

    w->endElement();
    return args.This();
  }

  genxStatus endElement()
  {
    return genxEndElement(writer);
  }

private:
  static utf8 createUtf8FromString(Handle<String> String)
  {
    utf8 string = NULL;
    int length = String->Utf8Length();

    string = new unsigned char[length];
    String->WriteUtf8((char *)string, length);

    return string;
  }

  static genxStatus sender_send(void *userData, constUtf8 s)
  {
    HandleScope scope;
    Writer *w = reinterpret_cast<Writer *>(userData);

    // Deliver the data event
    Local<String> dataString = String::New((const char *)s);
    Handle<Value> argv[1] = { dataString };
    w->Emit(sym_data, 1, argv);

  	return GENX_SUCCESS;
  }

  static genxStatus sender_sendBounded(void *userData, constUtf8 start, constUtf8 end)
  {
    HandleScope scope;
    Writer *w = reinterpret_cast<Writer *>(userData);

    // Deliver the data event
    Local<String> dataString = String::New((const char *)start, end - start);
    Handle<Value> argv[1] = { dataString };
    w->Emit(sym_data, 1, argv);

  	return GENX_SUCCESS;
  }

  static genxStatus sender_flush(void * userData)
  {
  	return GENX_SUCCESS;
  }

};

extern "C" {
  static void init (Handle<Object> target)
  {
    Writer::Initialize(target);
  }

  NODE_MODULE(genx, init);
}
<commit_msg>Simplify addText<commit_after>/*
Copyright (c) 2011, Wesley Moore http://www.wezm.net/
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 node-genx Project, Wesley Moore, 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 HOLDER 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 <node.h>
#include <node_events.h>
#include <iostream>
extern "C" {
#include "genx.h"
}

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

static Persistent<String> sym_data;

class Writer: public EventEmitter
{
private:
  genxWriter writer;
  genxSender sender;
  Persistent<Object> stream;
public:

  static void Initialize(Handle<Object> target)
  {
    HandleScope scope;

    Local<FunctionTemplate> t = FunctionTemplate::New(New);
    t->Inherit(EventEmitter::constructor_template);
    t->InstanceTemplate()->SetInternalFieldCount(1);
    t->SetClassName(String::NewSymbol("Writer"));

    NODE_SET_PROTOTYPE_METHOD(t, "startDocument", StartDoc);
    NODE_SET_PROTOTYPE_METHOD(t, "endDocument", EndDocument);

    NODE_SET_PROTOTYPE_METHOD(t, "startElementLiteral", StartElementLiteral);

    NODE_SET_PROTOTYPE_METHOD(t, "addText", AddText);
    NODE_SET_PROTOTYPE_METHOD(t, "addComment", AddComment);
    NODE_SET_PROTOTYPE_METHOD(t, "addAttributeLiteral", AddAttributeLiteral);

    NODE_SET_PROTOTYPE_METHOD(t, "endElement", EndElement);

    target->Set(String::NewSymbol("Writer"), t->GetFunction());

    sym_data = NODE_PSYMBOL("data");
  }

  Writer()
  {
    // alloc, free, userData
    writer = genxNew(NULL, NULL, this);
    sender.send = sender_send;
    sender.sendBounded = sender_sendBounded;
    sender.flush = sender_flush;
    stream = Persistent<Object>::Persistent();
  }

  ~Writer()
  {
    if(!stream.IsEmpty()) stream.Dispose(); // or Clear?
    genxDispose(writer);
  }

protected:

  static Handle<Value> New(const Arguments& args)
  {
    HandleScope scope;
    Writer* writer = new Writer();
    writer->Wrap(args.This());
    return args.This();
  }

  static Handle<Value> StartDoc(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());

    w->startDoc();
    return args.This();
  }

  genxStatus startDoc()
  {
    return genxStartDocSender(writer, &sender);
  }

  static Handle<Value> EndDocument(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());

    w->endDocument();
    return args.This();
  }

  genxStatus endDocument()
  {
    return genxEndDocument(writer);
  }

  static Handle<Value> StartElementLiteral(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());
    utf8 type = NULL;

    if (args.Length() <1 ||
        !args[0]->IsString()) {
      return ThrowException(Exception::Error(String::New(
        "First argument must be a String")));
    }

    Local<String> Type = args[0]->ToString();

    // Get the raw UTF-8 element type
    int length = Type->Utf8Length();
    type = new unsigned char[length];

    Type->WriteUtf8((char *)type, length);

    w->startElementLiteral(type);
    delete[] type;

    return args.This();
  }

  genxStatus startElementLiteral(constUtf8 type)
  {
    return genxStartElementLiteral(writer, NULL, type);
  }

  static Handle<Value> AddText(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());
    utf8 text = NULL;
    genxStatus status;

    if (args.Length() <1 ||
        !args[0]->IsString()) {
      return ThrowException(Exception::Error(String::New(
        "First argument must be a String")));
    }

    Local<String> Text = args[0]->ToString();
    text = createUtf8FromString(Text);

    status = w->addText(text);
    delete[] text;

    return args.This();
  }

  genxStatus addText(constUtf8 text)
  {
    // TODO handle the return value from genx here?
    return genxAddText(writer, text);
  }

  static Handle<Value> AddComment(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());
    utf8 text = NULL;
    genxStatus status;

    if (args.Length() <1 ||
        !args[0]->IsString()) {
      return ThrowException(Exception::Error(String::New(
        "First argument must be a String")));
    }

    Local<String> Text = args[0]->ToString();
    text = createUtf8FromString(Text);

    status = w->addComment(text);
    delete[] text;

    return args.This();
  }

  genxStatus addComment(constUtf8 comment)
  {
    // TODO handle the return value from genx here?
    return genxComment(writer, comment);
  }

  static Handle<Value> AddAttributeLiteral(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());
    utf8 name = NULL;
    utf8 value = NULL;

    if (args.Length() < 2    ||
       !args[0]->IsString() ||
       !args[1]->IsString()) {
      return ThrowException(Exception::Error(String::New(
        "Must supply two string arguments")));
    }

    Local<String> Name = args[0]->ToString();
    Local<String> Value = args[1]->ToString();

    // Get the raw UTF-8 strings
    name = createUtf8FromString(Name);
    value = createUtf8FromString(Value);

    w->addAttributeLiteral(name, value);
    delete[] name;
    delete[] value;

    return args.This();
  }

  genxStatus addAttributeLiteral(constUtf8 name, constUtf8 value)
  {
    constUtf8 xmlns = NULL;
    return genxAddAttributeLiteral(writer, xmlns, name, value);
  }

  static Handle<Value> EndElement(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());

    w->endElement();
    return args.This();
  }

  genxStatus endElement()
  {
    return genxEndElement(writer);
  }

private:
  static utf8 createUtf8FromString(Handle<String> String)
  {
    utf8 string = NULL;
    int length = String->Utf8Length();

    string = new unsigned char[length];
    String->WriteUtf8((char *)string, length);

    return string;
  }

  static genxStatus sender_send(void *userData, constUtf8 s)
  {
    HandleScope scope;
    Writer *w = reinterpret_cast<Writer *>(userData);

    // Deliver the data event
    Local<String> dataString = String::New((const char *)s);
    Handle<Value> argv[1] = { dataString };
    w->Emit(sym_data, 1, argv);

  	return GENX_SUCCESS;
  }

  static genxStatus sender_sendBounded(void *userData, constUtf8 start, constUtf8 end)
  {
    HandleScope scope;
    Writer *w = reinterpret_cast<Writer *>(userData);

    // Deliver the data event
    Local<String> dataString = String::New((const char *)start, end - start);
    Handle<Value> argv[1] = { dataString };
    w->Emit(sym_data, 1, argv);

  	return GENX_SUCCESS;
  }

  static genxStatus sender_flush(void * userData)
  {
  	return GENX_SUCCESS;
  }

};

extern "C" {
  static void init (Handle<Object> target)
  {
    Writer::Initialize(target);
  }

  NODE_MODULE(genx, init);
}
<|endoftext|>


<commit_before>/*
 * observer.hpp
 * Base classes for observer pattern of GoF design patterns
 *
 * written by janus_wel<janus.wel.3@gmail.com>
 * This source code is in public domain, and has NO WARRANTY.
 * */

#ifndef OBSERBER_HPP
#define OBSERBER_HPP

#include <list>

namespace pattern {
    namespace observer {
        // forward declarations
        template<typename T> class basic_subject;
        template<typename T> class basic_observer;

        /*
         * The class to change states
         * To use, you must define the class or struct that is derived from this class.
         * */
        template<typename T>
            class basic_subject {
                public:
                    // typedefs
                    typedef T                       state_t;
                    typedef basic_observer<state_t> observer_t;

                    /* I think that std::list is best container to contain observers, because:
                     *
                     *  - The order of items that are added is kept, so the user of this class
                     *    can handle the order of notifications.
                     *      - For now, I exclude a sort of the list and sorted addition of a
                     *        new items for simplicity.
                     *  - There is a need for successive accesses to all items from start to
                     *    end once, so it isn't the disadvantage that randome access is slow.
                     *  - Adding and removing items are fast.
                     *
                     *  */
                    typedef std::list<observer_t*>              observer_list_t;
                    typedef typename observer_list_t::iterator  observer_it;

                protected:
                    // the list of observers
                    observer_list_t observers;

                protected:
                    // the member function to get current (latest) states
                    virtual const state_t& state(void) const = 0;

                public:
                    // register an observer
                    inline basic_subject& attach(observer_t& o) {
                        observers.push_back(&o);
                        return *this;
                    }

                    inline basic_subject& attach(observer_t* o) {
                        observers.push_back(o);
                        return *this;
                    }

                    // release an observer
                    inline basic_subject& detach(observer_t& o) {
                        observers.remove(&o);
                        return *this;
                    }

                    inline basic_subject& detach(observer_t* o) {
                        observers.remove(o);
                        return *this;
                    }

                    // notice the current states to all of observers
                    // Should we use std::for_each(3) ?
                    void notify(void) {
                        state_t s = state();
                        for (observer_it it = observers.begin(); it != observers.end(); ++it) {
                            (*it)->update(s);
                        }
                    }

                    // typical destructor
                    virtual ~basic_subject(void) {}
            };

        /*
         * The class to observe children of basic_subject class
         * To use, you must define the class or struct that is derived from this class.
         * */
        template<typename T>
            class basic_observer {
                public:
                    // typedefs
                    typedef T state_t;

                public:
                    // Objects of this class are identified by the memory address of its instance.
                    inline bool operator==(const basic_observer& rhs) const { return this == &rhs; }
                    inline bool operator!=(const basic_observer& rhs) const { return !(*this == rhs); }

                    // typical destructor
                    virtual ~basic_observer(void) {}

                public:
                    // virtual functions
                    virtual void update(const state_t& s) = 0;
            };
    }
}

#endif // OBSERBER_HPP

<commit_msg>Add and fix some comments and fairing<commit_after>/*
 * observer.hpp
 * Base classes for observer pattern of GoF design patterns
 *
 * written by janus_wel<janus.wel.3@gmail.com>
 * This source code is in public domain, and has NO WARRANTY.
 * */

#ifndef OBSERBER_HPP
#define OBSERBER_HPP

#include <list>

namespace pattern {
    namespace observer {
        // forward declarations
        template<typename T> class basic_subject;
        template<typename T> class basic_observer;

        /*
         *  a base class to change states
         *  To use:
         *
         *      1. Define the class or struct that is derived from this class.
         *      2. Define new member variables to indicates the state of the
         *         object and new member functions to change states if those
         *         variables aren't public.
         *      3. Implement the member function state(0). This function must
         *         return the value that is contained in the derived class as
         *         member variables.
         * */
        template<typename T> class basic_subject {
            public:
                // typedefs
                typedef T                       state_t;
                typedef basic_subject<state_t>  this_t;
                typedef basic_observer<state_t> observer_t;

                /*
                 *  I think that std::list is best container to contain
                 *  observers, because:
                 *
                 *      - The order of items that are added is kept, so the
                 *        user of this class can handle the order of
                 *        notifications.
                 *          - For now, I exclude a sort of the list and sorted
                 *            addition of a new items for simplicity.
                 *      - There is a need for successive accesses to all items
                 *        from start to end once, so it isn't the disadvantage
                 *        that randome access is slow.
                 *      - Adding and removing items are fast.
                 *  */
                typedef std::list<observer_t*>              observer_array_t;
                typedef typename observer_array_t::iterator observer_array_it_t;

            protected:
                // a list of observers
                observer_array_t observers;

            public:
                // typical destructor
                virtual ~basic_subject(void) {}

                // register an observer
                inline this_t& attach(observer_t& o) {
                    observers.push_back(&o);
                    return *this;
                }

                inline this_t& attach(observer_t* o) {
                    observers.push_back(o);
                    return *this;
                }

                // release an observer
                inline this_t& detach(observer_t& o) {
                    observers.remove(&o);
                    return *this;
                }

                inline this_t& detach(observer_t* o) {
                    observers.remove(o);
                    return *this;
                }

                // notice the current states to all of observers
                // Should we use std::for_each(3) ?
                void notify(void) {
                    state_t s = state();
                    for (observer_array_it_t it = observers.begin();
                            it != observers.end();
                            ++it) {
                        (*it)->update(s);
                    }
                }

            protected:
                // the member function to get current (latest) states
                virtual const state_t& state(void) const = 0;
        };

        /*
         *  a base class to observe children of basic_subject class
         *  To use:
         *
         *      1. Define the class or struct that is derived from this class.
         *      2. Implement the member function handle(1).
         * */
        template<typename T> class basic_observer {
            public:
                // typedefs
                typedef T                       state_t;
                typedef basic_observer<state_t> this_t;

            public:
                // typical destructor
                virtual ~basic_observer(void) {}

                // Objects of this class are identified by the memory
                // address of its instance.
                inline bool operator==(const this_t& rhs) const {
                    return this == &rhs;
                }
                inline bool operator!=(const this_t& rhs) const {
                    return !(*this == rhs);
                }

            public:
                // a virtual function which should be implemented by
                // derived classes
                virtual void update(const state_t& s) = 0;
        };
    }
}

#endif // OBSERBER_HPP

<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int main () {
  ll N, A, B, C, D;
  cin >> N >> A >> B >> C >> D;
  ll T = B + D * N - A;
  ll delta = D - C;
  ll wari = 2 * D - delta;
  cerr << T << " " << delta << " " << wari << endl;
  assert(wari >= 0);
  ll sup = T / wari;
  ll inf = (T - N * delta + wari - 1) / wari;
  for (auto i = inf; i <= sup; ++i) {
    cerr << i << endl;
    cout << "YES" << endl;
    return 0;
  }
  cout << "NO" << endl;
}
<commit_msg>submit B.cpp to 'B - Moderate Differences' (agc017) [C++14 (GCC 5.4.1)]<commit_after>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int main () {
  ll N, A, B, C, D;
  cin >> N >> A >> B >> C >> D;
  --N;
  ll T = B + D * N - A;
  ll delta = D - C;
  ll wari = 2 * D - delta;
  cerr << T << " " << delta << " " << wari << endl;
  assert(wari >= 0);
  ll sup = T / wari;
  ll inf = (T - N * delta + wari - 1) / wari;
  for (auto i = inf; i <= sup; ++i) {
    cerr << i << endl;
    cout << "YES" << endl;
    return 0;
  }
  cout << "NO" << endl;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

vector<int> V[100010];
bool visited[100010];

typedef tuple<int, int> state;

int main () {
  int N;
  cin >> N;
  for (auto i = 0; i < N-1; ++i) {
    int a, b;
    a--;
    b--;
    cin >> a >> b;
    V[a].push_back(b);
    V[b].push_back(a);
  }
  stack<state> S;
  S.push(state(0, 0));
  int parent;
  int D;
  fill(visited, visited+N, false);
  while (!S.empty()) {
    int now = get<0>(S.top());
    int d = get<1>(S.top());
    S.pop();
    if (!visited[now]) {
      visited[now] = true;
      if (now == N-1) {
        D = d;
        parent = now;
        break;
      }
      for (auto x : V[now]) {
        if (!visited[x]) {
          S.push(state(x, d+1));
        }
      }
    }
  }
  stack<state> SS;
  SS.push(state(N-1, 0));
  int cnt = 0;
  fill(visited, visited+N, false);
  while (!SS.empty()) {
    int now = get<0>(SS.top());
    int d = get<1>(SS.top());
    SS.pop();
    if (!visited[now]) {
      visited[now] = true;
      cnt++;
      for (auto x : V[now]) {
        if (!visited[x] && x != parent) {
          SS.push(state(x, d+1));
        }
      }
    }
  }
  int su = (D-1)/2 + cnt - 1;
  int fa = N - 2 - fa;
  if (fa > su) {
    cout << "Fennec" << endl;
  } else {
    cout << "Snuke" << endl;
  }
}
<commit_msg>tried D.cpp to 'D'<commit_after>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

vector<int> V[100010];
bool visited[100010];

typedef tuple<int, int> state;

int main () {
  int N;
  cin >> N;
  for (auto i = 0; i < N-1; ++i) {
    int a, b;
    a--;
    b--;
    cin >> a >> b;
    V[a].push_back(b);
    V[b].push_back(a);
  }
  stack<state> S;
  S.push(state(N-1, 0));
  int parent;
  int D;
  fill(visited, visited+N, false);
  while (!S.empty()) {
    int now = get<0>(S.top());
    int d = get<1>(S.top());
    S.pop();
    if (!visited[now]) {
      visited[now] = true;
      if (now == 0) {
        D = d;
        parent = now;
        break;
      }
      for (auto x : V[now]) {
        if (!visited[x]) {
          S.push(state(x, d+1));
        }
      }
    }
  }
  stack<state> SS;
  SS.push(state(0, 0));
  int cnt = 0;
  fill(visited, visited+N, false);
  while (!SS.empty()) {
    int now = get<0>(SS.top());
    int d = get<1>(SS.top());
    SS.pop();
    if (!visited[now]) {
      visited[now] = true;
      cnt++;
      for (auto x : V[now]) {
        if (!visited[x] && x != parent) {
          SS.push(state(x, d+1));
        }
      }
    }
  }
  int su = (D-1)/2 + cnt - 1;
  int fa = N - 2 - fa;
  if (fa > su) {
    cout << "Fennec" << endl;
  } else {
    cout << "Snuke" << endl;
  }
}
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int main () {
  string S;
  cin >> S;
  int x[2];
  cin >> x[0] >> x[1];
  vector<int> V[2];
  bool isx = 0;
  int cnt = 0;
  for (auto e : S) {
    if (e == 'F') cnt++;
    else {
      if (cnt > 0) {
        V[isx].push_back(cnt);
      }
      cnt = 0;
      isx = !isx;
    }
  }
  if (cnt > 0) {
    V[isx].push_back(cnt);
  }
  for (auto k = 0; k < 2; ++k) {
    int sum = 0;
    for (auto e : V[k]) {
      sum += e;
    }
    if ((x[k] + sum) %2 != 0) {
      cout << "No" << endl;
      return 0;
    }
    int mokuhyo = (x[k] + sum)/2;
    bool dp[10000];
    fill(dp, dp+10000, false);
    dp[0] = true;
    for (auto e : V[k]) {
      for (auto i = 9999; i >= 0; --i) {
        if (dp[i] && i + e < 10000) {
          dp[i+e] = true;
        }
      }
    }
    if (!dp[mokuhyo]) {
      cout << "No" << endl;
      return 0;
    }
  }
  cout << "Yes" << endl;
}
<commit_msg>submit D.cpp to 'D - FT Robot' (arc087) [C++14 (GCC 5.4.1)]<commit_after>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int main () {
  string S;
  cin >> S;
  int x[2];
  cin >> x[0] >> x[1];
  vector<int> V[2];
  bool isx = 0;
  int cnt = 0;
  for (auto e : S) {
    if (e == 'F') cnt++;
    else {
      if (cnt > 0) {
        V[isx].push_back(cnt);
      }
      cnt = 0;
      isx = !isx;
    }
  }
  if (cnt > 0) {
    V[isx].push_back(cnt);
  }
  for (auto k = 0; k < 2; ++k) {
    int sum = 0;
    for (auto e : V[k]) {
      sum += e;
    }
    if ((x[k] + sum) %2 != 0) {
      cout << "No" << endl;
      return 0;
    }
    int mokuhyo = (x[k] + sum)/2;
    if (mokuhyo < 0 || mokuhyo > sum) {
      cout << "No" << endl;
      return 0;
    }
    bool dp[10000];
    fill(dp, dp+10000, false);
    dp[0] = true;
    for (auto e : V[k]) {
      for (auto i = 9999; i >= 0; --i) {
        if (dp[i] && i + e < 10000) {
          dp[i+e] = true;
        }
      }
    }
    if (!dp[mokuhyo]) {
      cout << "No" << endl;
      return 0;
    }
  }
  cout << "Yes" << endl;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int main () {
  string S;
  cin >> S;
  int x[2];
  cin >> x[0] >> x[1];
  vector<int> V[2];
  bool isx = 0;
  int cnt = 0;
  bool isfirst = true;
  for (auto e : S) {
    if (e == 'F') cnt++;
    else {
      if (isfirst) {
        x[0] -= cnt;
        isfirst = false;
      } else if (cnt > 0) {
        V[isx].push_back(cnt);
      }
      cnt = 0;
      isx = !isx;
    }
  }
  if (cnt > 0) {
    V[isx].push_back(cnt);
  }
  for (auto k = 0; k < 2; ++k) {
    int sum = 0;
    for (auto e : V[k]) {
      sum += e;
    }
    if ((x[k] + sum) %2 != 0) {
      cout << "No" << endl;
      return 0;
    }
    int mokuhyo = (x[k] + sum)/2;
    if (mokuhyo < 0 || mokuhyo > sum) {
      cout << "No" << endl;
      return 0;
    }
    bool dp[10000];
    fill(dp, dp+10000, false);
    dp[0] = true;
    for (auto e : V[k]) {
      for (auto i = 9999; i >= 0; --i) {
        if (dp[i] && i + e < 10000) {
          dp[i+e] = true;
        }
      }
    }
    if (!dp[mokuhyo]) {
      cout << "No" << endl;
      return 0;
    }
  }
  cout << "Yes" << endl;
}
<commit_msg>submit D.cpp to 'D - FT Robot' (arc087) [C++14 (GCC 5.4.1)]<commit_after>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int main () {
  string S;
  cin >> S;
  int x[2];
  cin >> x[0] >> x[1];
  vector<int> V[2];
  bool isx = 0;
  int cnt = 0;
  bool isfirst = true;
  for (auto e : S) {
    if (e == 'F') cnt++;
    else {
      if (isfirst) {
        x[0] -= cnt;
        isfirst = false;
      } else if (cnt > 0) {
        V[isx].push_back(cnt);
      }
      cnt = 0;
      isx = !isx;
    }
  }
  if (isfirst) {
    x[0] -= cnt;
    isfirst = false;
  } else if (cnt > 0) {
    V[isx].push_back(cnt);
  }
  for (auto k = 0; k < 2; ++k) {
    int sum = 0;
    for (auto e : V[k]) {
      sum += e;
    }
    if ((x[k] + sum) %2 != 0) {
      cout << "No" << endl;
      return 0;
    }
    int mokuhyo = (x[k] + sum)/2;
    if (mokuhyo < 0 || mokuhyo > sum) {
      cout << "No" << endl;
      return 0;
    }
    bool dp[10000];
    fill(dp, dp+10000, false);
    dp[0] = true;
    for (auto e : V[k]) {
      for (auto i = 9999; i >= 0; --i) {
        if (dp[i] && i + e < 10000) {
          dp[i+e] = true;
        }
      }
    }
    if (!dp[mokuhyo]) {
      cout << "No" << endl;
      return 0;
    }
  }
  cout << "Yes" << endl;
}
<|endoftext|>


<commit_before>/**
 * File    : C.cpp
 * Author  : Kazune Takahashi
 * Created : 2018-4-15 21:25:15
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 1 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

string S;
int N;
bool par[20010];
bool used[20010];

bool solve()
{
  N = S.size();
  int cnt = 0;
  for (auto i = 0; i < N; i++)
  {
    par[i] = (S[i] == '(');
    if (par[i])
    {
      ++cnt;
    }
  }
  if (cnt != N/2)
  {
    return false;
  }
  fill(used, used + N, false);
  int c[2] = {0, 0};
  int now = 0;
  while (now < N && (c[0] < N / 4 || c[1] < N / 4))
  {
    assert(c[0] >= c[1]);
    if (c[0] == N/4)
    {
      if (!par[now])
      {
        used[now] = true;
        c[1]++;
      }
    }
    else if (c[0] == c[1])
    {
      if (par[now])
      {
        used[now] = true;
        c[0]++;
      }
    }
    else
    {
      used[now] = true;
      c[par[now]]++;
    }
    now++;
  }
  if (c[0] < N/4 || c[1] < N/4)
  {
    return false;
  }
  c[0] = c[1] = 0;
  now = 0;
#if DEBUG == 1
  cerr << "S = " << S << endl;
  cerr << "S1 = ";
  for (auto i = 0; i < N; i++)
  {
    if (used[i])
    {
      cerr << S[i];
    }
    cerr << endl;
  }
  cerr << "S2 = ";
  for (auto i = 0; i < N; i++)
  {
    if (!used[i])
    {
      cerr << S[i];
    }
    cerr << endl;
  }
#endif
  while (now < N && (c[0] < N / 4 || c[1] < N / 4))
  {
    if (used[now])
    {
      now++;
      continue;
    }
    assert(c[0] >= c[1]);
    if (c[0] == N/4)
    {
      if (par[now])
      {
        used[now] = true;
        c[1]++;
      }
    }
    else if (c[0] == c[1])
    {
      if (!par[now])
      {
        used[now] = true;
        c[0]++;
      }
    }
    else
    {
      used[now] = true;
      c[1 - (int)par[now]]++;
    }
    now++;
  }
  if (c[0] < N/4 || c[1] < N/4)
  {
    return false;
  }
  return true;
}

int main()
{
  int Q;
  cin >> Q;
  for (auto i = 0; i < Q; i++)
  {
    cin >> S;
    cout << (solve() ? "Yes" : "No") << endl;
  }
}<commit_msg>tried C.cpp to 'C'<commit_after>/**
 * File    : C.cpp
 * Author  : Kazune Takahashi
 * Created : 2018-4-15 21:25:15
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 1 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

string S;
int N;
bool par[20010];
bool used[20010];

bool solve()
{
  N = S.size();
  int cnt = 0;
  for (auto i = 0; i < N; i++)
  {
    par[i] = (S[i] == '(');
    if (par[i])
    {
      ++cnt;
    }
  }
  if (cnt != N/2)
  {
    return false;
  }
  fill(used, used + N, false);
  int c[2] = {0, 0};
  int now = 0;
  while (now < N && (c[0] < N / 4 || c[1] < N / 4))
  {
    assert(c[0] >= c[1]);
    if (c[0] == N/4)
    {
      if (!par[now])
      {
        used[now] = true;
        c[1]++;
      }
    }
    else if (c[0] == c[1])
    {
      if (par[now])
      {
        used[now] = true;
        c[0]++;
      }
    }
    else
    {
      used[now] = true;
      c[par[now]]++;
    }
    now++;
  }
  if (c[0] < N/4 || c[1] < N/4)
  {
    return false;
  }
  c[0] = c[1] = 0;
  now = 0;
#if DEBUG == 1
  cerr << "S = " << S << endl;
  cerr << "S1 = ";
  for (auto i = 0; i < N; i++)
  {
    if (used[i])
    {
      cerr << S[i];
    }
  }
  cerr << endl;
  cerr << "S2 = ";
  for (auto i = 0; i < N; i++)
  {
    if (!used[i])
    {
      cerr << S[i];
    }
  }
  cerr << endl;
#endif
  while (now < N && (c[0] < N / 4 || c[1] < N / 4))
  {
    if (used[now])
    {
      now++;
      continue;
    }
    assert(c[0] >= c[1]);
    if (c[0] == N/4)
    {
      if (par[now])
      {
        used[now] = true;
        c[1]++;
      }
    }
    else if (c[0] == c[1])
    {
      if (!par[now])
      {
        used[now] = true;
        c[0]++;
      }
    }
    else
    {
      used[now] = true;
      c[1 - (int)par[now]]++;
    }
    now++;
  }
  if (c[0] < N/4 || c[1] < N/4)
  {
    return false;
  }
  return true;
}

int main()
{
  int Q;
  cin >> Q;
  for (auto i = 0; i < Q; i++)
  {
    cin >> S;
    cout << (solve() ? "Yes" : "No") << endl;
  }
}<|endoftext|>


<commit_before>/**
 * File    : B.cpp
 * Author  : Kazune Takahashi
 * Created : 2018-5-20 21:05:39
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <random> // random_device rd; mt19937 mt(rd());
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int N;
int P[200010];

int solve()
{
  int now = 0;
  for (auto i = 0; i < N; i++)
  {
    if (P[i] == now + 1)
    {
      now++;
    }
  }
  return N - now;
}

int main()
{
  cin >> N;
  for (auto i = 0; i < N; i++)
  {
    cin >> P[i];
  }
  int ans = solve();
  reverse(P, P + N);
  for (auto i = 0; i < N; i++)
  {
    P[i] = N - P[i] + 1;
    // cerr << "P[" << i << "] = " << P[i] << endl;
  }
  ans = min(ans, solve());
  cout << ans << endl;
}<commit_msg>tried B.cpp to 'B'<commit_after>/**
 * File    : B.cpp
 * Author  : Kazune Takahashi
 * Created : 2018-5-20 21:05:39
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <random> // random_device rd; mt19937 mt(rd());
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const int infty = 1000000007;

int N;
int P[200010];
int dp[200010];

int solve()
{
  fill(dp, dp + 200010, infty);
  for (auto i = 0; i < N; i++)
  {
    *lower_bound(dp, dp + N, P[i]) = P[i];
  }
  return N - (lower_bound(dp, dp + N, infty) - dp);
}

int main()
{
  cin >> N;
  for (auto i = 0; i < N; i++)
  {
    cin >> P[i];
  }
  int ans = solve();
  reverse(P, P + N);
  for (auto i = 0; i < N; i++)
  {
    P[i] = N - P[i] + 1;
    // cerr << "P[" << i << "] = " << P[i] << endl;
  }
  ans = min(ans, solve());
  cout << ans << endl;
}<|endoftext|>


<commit_before>/**
 * File    : E.cpp
 * Author  : Kazune Takahashi
 * Created : 2018-7-1 22:00:11
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <random> // random_device rd; mt19937 mt(rd());
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

typedef tuple<int, int> D;

int N;
int A[100010];
int DP[100010];
int DP2[100010];

set<D> S[100010];

void make_S(int i)
{
  if (!S[i].empty())
  {
    return;
  }
  S[i].insert(D(-A[0], 0));
  S[i].insert(D(-A[i], i));
  for (auto j = 0; j < N; j++)
  {
    int mask = (1 << N) - 1 - (1 << j);
    int new_i = mask & i;
    if (new_i == i || new_i == 0)
    {
      continue;
    }
    make_S(new_i);
    auto it = S[new_i].begin();
    S[i].insert(*it);
    it++;
    S[i].insert(*it);
  }
}

int main()
{
  cin >> N;
  for (auto i = 0; i < N; i++)
  {
    cin >> A[i];
  }
  for (auto i = 0; i < (1 << N); i++)
  {
    make_S(i);
    auto it = S[i].begin();
    cerr << "i = " << i << endl;
    cerr << "(" << -get<0>(*it) << ", " << get<1>(*it) << ")" << endl;
    DP2[i] = -(get<0>(*it));
    it++;
    cerr << "(" << -get<0>(*it) << ", " << get<1>(*it) << ")" << endl;
    DP2[i] += -(get<0>(*it));
  }
  // flush
  DP[0] = 0;
  for (auto i = 1; i < (1 << N); i++)
  {
    DP[i] = max(DP[i - 1], DP2[i]);
    cout << DP[i] << endl;
  }
}<commit_msg>submit E.cpp to 'E - Or Plus Max' (arc100) [C++14 (GCC 5.4.1)]<commit_after>/**
 * File    : E.cpp
 * Author  : Kazune Takahashi
 * Created : 2018-7-1 22:00:11
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <random> // random_device rd; mt19937 mt(rd());
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

typedef tuple<int, int> D;

int N;
int A[100010];
int DP[100010];
int DP2[100010];

set<D> S[100010];

void make_S(int i)
{
  if (!S[i].empty())
  {
    return;
  }
  S[i].insert(D(-A[0], 0));
  S[i].insert(D(-A[i], i));
  for (auto j = 0; j < N; j++)
  {
    int mask = (1 << N) - 1 - (1 << j);
    int new_i = mask & i;
    if (new_i == i || new_i == 0)
    {
      continue;
    }
    make_S(new_i);
    auto it = S[new_i].begin();
    S[i].insert(*it);
    it++;
    S[i].insert(*it);
  }
}

int main()
{
  cin >> N;
  for (auto i = 0; i < (1 << N); i++)
  {
    cin >> A[i];
  }
  for (auto i = 0; i < (1 << N); i++)
  {
    make_S(i);
    auto it = S[i].begin();
    // cerr << "i = " << i << endl;
    // cerr << "(" << -get<0>(*it) << ", " << get<1>(*it) << ")" << endl;
    DP2[i] = -(get<0>(*it));
    it++;
    // cerr << "(" << -get<0>(*it) << ", " << get<1>(*it) << ")" << endl;
    DP2[i] += -(get<0>(*it));
  }
  // flush
  DP[0] = 0;
  for (auto i = 1; i < (1 << N); i++)
  {
    DP[i] = max(DP[i - 1], DP2[i]);
    cout << DP[i] << endl;
  }
}<|endoftext|>


<commit_before>/**
 * File    : C.cpp
 * Author  : Kazune Takahashi
 * Created : 2018-12-15 21:49:53
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <functional>
#include <random> // auto rd = bind(uniform_int_distribution<int>(0, 9), mt19937(19920725));
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int N;
int A[200010];
int K[100];
int S;

bool solve(int X)
{
  fill(K, K + A[0], 0);
  for (auto i = 0; i < N - 1; i++)
  {
    if (A[i] > A[i + 1])
    {
      S = A[i + 1];
    }
    else
    {
      bool ok = false;
      for (auto j = A[i] - 1; j >= 0; j--)
      {
        K[j]++;
        if (K[j] == X)
        {
          K[j] = 0;
        }
        else
        {
          ok = true;
          break;
        }
      }
      if (!ok)
      {
        return false;
      }
      for (auto j = A[i]; j < A[i + 1]; j++)
      {
        K[j] = 0;
      }
    }
  }
  return true;
}

int main()
{
  cin >> N;
  for (auto i = 0; i < N; i++)
  {
    cin >> A[i];
    A[i] = min(100, A[i]);
  }
  reverse(A, A + N);
  int ub = N;
  int lb = 0;
  while (ub - lb > 1)
  {
    int t = (ub + lb) / 2;
    if (solve(t))
    {
      ub = t;
    }
    else
    {
      lb = t;
    }
  }
  cout << ub << endl;
}<commit_msg>submit C.cpp to 'C - Lexicographic constraints' (agc029) [C++14 (GCC 5.4.1)]<commit_after>/**
 * File    : C.cpp
 * Author  : Kazune Takahashi
 * Created : 2018-12-15 21:49:53
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <functional>
#include <random> // auto rd = bind(uniform_int_distribution<int>(0, 9), mt19937(19920725));
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int N;
int A[200010];
int K[1000];

bool solve(int X)
{
  fill(K, K + A[0], 0);
  for (auto i = 0; i < N - 1; i++)
  {
    if (A[i] > A[i + 1])
    {
      continue;
    }
    else
    {
      bool ok = false;
      for (auto j = A[i] - 1; j >= 0; j--)
      {
        K[j]++;
        if (K[j] == X)
        {
          K[j] = 0;
        }
        else
        {
          ok = true;
          break;
        }
      }
      if (!ok)
      {
        return false;
      }
      for (auto j = A[i]; j < A[i + 1]; j++)
      {
        K[j] = 0;
      }
    }
  }
  return true;
}

int main()
{
  cin >> N;
  for (auto i = 0; i < N; i++)
  {
    cin >> A[i];
    A[i] = min(1000, A[i]);
  }
  reverse(A, A + N);
  int ub = N;
  int lb = 0;
  while (ub - lb > 1)
  {
    int t = (ub + lb) / 2;
    if (solve(t))
    {
      ub = t;
    }
    else
    {
      lb = t;
    }
  }
  cout << ub << endl;
}<|endoftext|>


<commit_before>#define DEBUG 1

/**
 * File    : C.cpp
 * Author  : Kazune Takahashi
 * Created : 2019-6-2 21:52:44
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <string>
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <functional>
#include <random>
#include <chrono>
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

typedef long long ll;

/*
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}

void No()
{
  cout << "No" << endl;
  exit(0);
}
*/

/*
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};
*/

// const ll MOD = 1000000007;

int N;
ll X;
ll b[100010];
ll l[100010];
ll u[100010];
ll maxi = 0;
ll now = 0;
ll ans = 0;

typedef tuple<ll, ll, ll, ll> card;  // maxi, b, l, u;
typedef tuple<ll, ll, ll, ll> card2; // u, l, b, cost;
vector<card> V;
vector<card2> W;

int main()
{
  cin >> N >> X;
  for (auto i = 0; i < N; i++)
  {
    cin >> b[i] >> l[i] >> u[i];
  }
  for (auto i = 0; i < N; i++)
  {
    maxi += b[i] * l[i];
  }
  for (auto i = 0; i < N; i++)
  {
    ll t = (l[i] * b[i] + u[i] * (X - b[i]));
    V.emplace_back(t, b[i], l[i], u[i]);
  }
  sort(V.begin(), V.end());
  reverse(V.begin(), V.end());
  int ind = 0;
  while (maxi >= now)
  {
    ll t, b, l, u;
    tie(t, b, l, u) = V[ind++];
    now += t;
    ans += X;
    W.emplace_back(u, l, b, X);
#if DEBUG == 1
    cerr << "(" << t << ", " << b << ", " << l << ", " << u << ")" << endl;
#endif
  }
  sort(W.begin(), W.end());
  ind = 0;
#if DEBUG == 1
  ll u, l, b, x;
  tie(u, l, b, x) = W[0];
  cerr << "W[0]: ";
  cerr << "(" << u << ", " << l << ", " << b << ", " << x << ")" << endl;
#endif
  while (now >= maxi)
  {
    if (get<3>(W[0]) > get<2>(W[0]))
    {
      now -= get<0>(W[0]);
    }
    else
    {
      now -= get<1>(W[0]);
    }
    get<3>(W[0])--;
    ans--;
  }
  cout << ans + 1 << endl;
}<commit_msg>tried C.cpp to 'C'<commit_after>#define DEBUG 1

/**
 * File    : C.cpp
 * Author  : Kazune Takahashi
 * Created : 2019-6-2 21:52:44
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <string>
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <functional>
#include <random>
#include <chrono>
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

typedef long long ll;

/*
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}

void No()
{
  cout << "No" << endl;
  exit(0);
}
*/

/*
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};
*/

// const ll MOD = 1000000007;

int N;
ll X;
ll b[100010];
ll l[100010];
ll u[100010];
ll maxi = 0;
ll now = 0;
ll ans = 0;

typedef tuple<ll, ll, ll, ll> card; // maxi, b, l, u;
typedef tuple<ll, ll, ll> card2;    // b, l, u;

vector<card> V;

int main()
{
  cin >> N >> X;
  for (auto i = 0; i < N; i++)
  {
    cin >> b[i] >> l[i] >> u[i];
  }
  for (auto i = 0; i < N; i++)
  {
    maxi += b[i] * l[i];
  }
  for (auto i = 0; i < N; i++)
  {
    ll t = (l[i] * b[i] + u[i] * (X - b[i]));
    V.emplace_back(t, b[i], l[i], u[i]);
  }
  sort(V.begin(), V.end());
  reverse(V.begin(), V.end());
  int ind = 0;
  while (true)
  {
    ll t, b, l, u;
    tie(t, b, l, u) = V[ind++];
    if (now + t >= maxi)
    {
      break;
    }
  }
  ans = X;
  ll dx = maxi - now;
  for (auto i = ind; i < N; i++)
  {
    ll t, b, l, u;
    tie(t, b, l, u) = V[i];
    ll tmp = 0;
    if (dx >= l * b)
    {
      tmp = b + (dx - l * b + u - 1) / u;
    }
    else
    {
      tmp = (dx + b - 1) / b;
    }
    ans = min(tmp, ans);
  }
  cout << ans + X * ind << endl;
}<|endoftext|>