<commit_before>#include <iostream>
#include <string>

#include "gtest/gtest.h"

// nom::UnitTest framework
#include "nomlib/tests/common.hpp"

#include <nomlib/config.hpp>
#include <nomlib/system.hpp>
#include <nomlib/graphics.hpp>

// #if ! defined( NOM_USE_SCALEX )
//   #pragma message("NOM_BUILD_EXTRA_RESCALE_ALGO_UNIT should be enabled for GradientTest::Margins")
// #endif

namespace nom {

class GradientTest: public nom::VisualUnitTest
{
  public:
    /// \remarks This method is called at the start of each unit test.
    GradientTest()
    {
      // NOM_LOG_TRACE( NOM );

      this->set_window_flags( SDL_WINDOW_RESIZABLE );

      // The frame image to compare against the reference image set
      this->append_screenshot_frame( 0 );
    }

    /// \remarks This method is called at the end of each unit test.
    virtual ~GradientTest()
    {
      // NOM_LOG_TRACE( NOM );
    }

    /// \remarks This method is called after construction, at the start of each
    /// unit test.
    virtual void SetUp()
    {
      // NOM_LOG_TRACE( NOM );

      std::string res_file = nom::UnitTest::test_set() + ".json";

      if( resources.load_file( res_file, "resources" ) == false )
      {
        FAIL()
        << "Could not resolve the resource path from file: " << res_file;
      }

      // VisualUnitTest environment init...
      VisualUnitTest::SetUp();

      EventCallback debug_info( [&] ( const Event& evt )
        {
          NOM_LOG_INFO( NOM_LOG_CATEGORY_TEST, "x:", evt.mouse.x, "y:", evt.mouse.y );
        }
      );

      InputActionMapper state;

      state.insert( "debug_info", nom::MouseButtonAction(
                    SDL_MOUSEBUTTONDOWN, SDL_BUTTON_LEFT ),
                    debug_info );

      this->input_mapper_.insert( "debug_info", state, true );

      this->colors[0] = {
                          Color4iColors{
                            Color4i::Gray,
                            Color4i::LightGray
                          }
                        };
      this->colors[1] = {
                          Color4iColors{
                            nom::Color4i( 114, 66, 66 ),
                            nom::Color4i( 251, 222, 232 )
                          }
                        };

      int w = this->resolution().w;
      int h = this->resolution().h;
      this->pos1 = Point2i( 0, 0 );
      this->dims1 = Size2i( w, h / 2 );

      this->pos2 = Point2i( 0, h / 2 );
      this->dims2 = Size2i( w, h / 2 );

      // Not used
      this->pos3 = Point2i( w/3, h/2 );
      this->dims3 = Size2i( w/3, h/3 );

      this->grad1.set_colors( this->colors[0] );
      this->grad1.set_position( this->pos1 );
      this->grad1.set_size( this->dims1 );

      this->grad2.set_colors( this->colors[1] );
      this->grad2.set_position( this->pos2 );
      this->grad2.set_size( this->dims2 );

      // Not used
      this->grad3.set_colors( this->colors[0] );
      this->grad3.set_position( this->pos3 );
      this->grad3.set_size( this->dims3 );

      // Register our main loop
      this->append_render_callback( [&] ( const RenderWindow& win ) { this->grad1.draw( this->render_window() ); } );
      this->append_render_callback( [&] ( const RenderWindow& win ) { this->grad2.draw( this->render_window() ); } );
      // this->append_render_callback( [&] ( const RenderWindow& win ) { this->grad3.draw( this->render_window() ); } );
    }

    /// \remarks This method is called before destruction, at the end of each
    /// unit test.
    virtual void TearDown()
    {
      // NOM_LOG_TRACE( NOM );
    }

    /// \remarks This method is called at the start of each test case.
    static void SetUpTestCase()
    {
      // NOM_LOG_TRACE( NOM );
    }

    /// \remarks This method is called at the end of each test case.
    static void TearDownTestCase()
    {
      // NOM_LOG_TRACE( NOM );
    }

  protected:
    SearchPath resources;

    Gradient grad1;
    Gradient grad2;
    // Not used
    Gradient grad3;

    Point2i pos1;
    Size2i dims1;

    Point2i pos2;
    Size2i dims2;

    // Not used
    Point2i pos3;
    Size2i dims3;

    /// \brief Colors used to create the gradient

    /// \remarks One of two used
    Color4iColors colors[2];
};

TEST_F( GradientTest, TopToBottomLinearFill )
{
  this->grad1.set_fill_direction( Gradient::FillDirection::Top );
  this->grad2.set_fill_direction( Gradient::FillDirection::Top );
  // this->grad3.set_fill_direction( Gradient::FillDirection::Top );

  EXPECT_EQ( NOM_EXIT_SUCCESS, this->on_run() );
  EXPECT_TRUE( this->compare() );
}

TEST_F( GradientTest, BottomToTopLinearFill )
{
  this->grad1.set_fill_direction( Gradient::FillDirection::Bottom );
  this->grad2.set_fill_direction( Gradient::FillDirection::Bottom );
  // this->grad3.set_fill_direction( Gradient::FillDirection::Bottom );

  EXPECT_EQ( NOM_EXIT_SUCCESS, this->on_run() );
  EXPECT_TRUE( this->compare() );
}

TEST_F( GradientTest, LeftToRightLinearFill )
{
  this->grad1.set_fill_direction( Gradient::FillDirection::Left );
  this->grad2.set_fill_direction( Gradient::FillDirection::Left );
  // this->grad3.set_fill_direction( Gradient::FillDirection::Left );

  EXPECT_EQ( NOM_EXIT_SUCCESS, this->on_run() );
  EXPECT_TRUE( this->compare() );
}

TEST_F( GradientTest, RightToLeftLinearFill )
{
  this->grad1.set_fill_direction( Gradient::FillDirection::Right );
  this->grad2.set_fill_direction( Gradient::FillDirection::Right );
  // this->grad3.set_fill_direction( Gradient::FillDirection::Right );

  EXPECT_EQ( NOM_EXIT_SUCCESS, this->on_run() );
  EXPECT_TRUE( this->compare() );
}

// TOOD: Verify / fix margins calculations for left to right directions
TEST_F( GradientTest, Margins )
{
  std::shared_ptr<Gradient> card_background;
  std::shared_ptr<SpriteBatch> card_face;

  // Loosely emulate TTcards scale resolution (scale up)
  const std::string sheet_coords = resources.path()+"faces.json";
  const std::string sheet_img = resources.path()+"faces.png";
  const int SCALE_FACTOR = 2;
  const int CARD_WIDTH = 64;
  const int CARD_HEIGHT = 64;
  const int CARD_ORIGIN_X =
    ( (this->resolution().w / SCALE_FACTOR) - CARD_WIDTH ) / 2;
  const int CARD_ORIGIN_Y =
    ( (this->resolution().h / SCALE_FACTOR) - CARD_HEIGHT ) / 2;

  Color4iColors player1_grad_bg = { Color4i( 208, 223, 255 ),
                                    Color4i( 50, 59, 114 )
                                  };
  Size2i dims;
  dims.w = this->resolution().w / SCALE_FACTOR;
  dims.h = this->resolution().h / SCALE_FACTOR;
  this->render_window().set_logical_size( dims );

  card_background = std::make_shared<Gradient>( Gradient() );

  card_face =
    std::make_shared<SpriteBatch>( SpriteBatch( sheet_coords ) );

  if( card_face->load( sheet_img ) == false )
  {
    FAIL() << "Could not load image from file: " << sheet_img;
  }
  // card_face->resize( nom::Texture::ResizeAlgorithm::scale2x );

  // Geezard
  card_face->set_frame( 0 );

  card_face->set_position( Point2i(CARD_ORIGIN_X, CARD_ORIGIN_Y) );
  card_background->set_position( nom::Point2i(CARD_ORIGIN_X, CARD_ORIGIN_Y) );

  // The gradient should be bound within the
  //
  // Note that the 1 pixel border surrounding each card is why these
  // calculations are necessary; we want the gradient to be inside the card's
  // border
  card_background->set_size( Size2i(CARD_WIDTH-2, CARD_HEIGHT-2) );
  card_background->set_margins( Point2i(1,1) );
  card_background->set_colors( player1_grad_bg );
  card_background->set_fill_direction( nom::Gradient::FillDirection::Top );

  // 62, 62
  // NOM_DUMP( card_background->size() );
  // 128, 88
  // NOM_DUMP( card_background->position() );

  // Need to first clear out the default grad objects in here
  this->clear_render_callbacks();

  // Re-add the default rendering callback
  this->append_render_callback( this->default_render_callback() );

  this->append_render_callback( [&] ( const RenderWindow& win ) {
    card_background->draw( this->render_window() );
  });

  this->append_render_callback( [&] ( const RenderWindow& win ) {
    card_face->draw ( this->render_window() );
  });

  EXPECT_EQ( NOM_EXIT_SUCCESS, this->on_run() );
  EXPECT_TRUE( this->compare() );
}

} // namespace nom

int main( int argc, char** argv )
{
  ::testing::InitGoogleTest( &argc, argv );

  // Set the current working directory path to the path leading to this
  // executable file; used for unit tests that require file-system I/O.
  if( nom::init( argc, argv ) == false )
  {
    nom::DialogMessageBox( "Critical Error", "Could not initialize nomlib.", nom::MessageBoxType::NOM_DIALOG_ERROR );
    return NOM_EXIT_FAILURE;
  }
  atexit( nom::quit );

  // nom::UnitTest framework integration
  nom::init_test( argc, argv );

  nom::SDL2Logger::set_logging_priority( NOM_LOG_CATEGORY_RENDER, nom::NOM_LOG_PRIORITY_VERBOSE );
  // nom::SDL2Logger::set_logging_priority( NOM_LOG_CATEGORY_TRACE, nom::NOM_LOG_PRIORITY_VERBOSE );

  return RUN_ALL_TESTS();
}
<commit_msg>GradientTest: Use set_scale in Margins test<commit_after>#include <iostream>
#include <string>

#include "gtest/gtest.h"

// nom::UnitTest framework
#include "nomlib/tests/common.hpp"

#include <nomlib/config.hpp>
#include <nomlib/system.hpp>
#include <nomlib/graphics.hpp>

// #if ! defined( NOM_USE_SCALEX )
//   #pragma message("NOM_BUILD_EXTRA_RESCALE_ALGO_UNIT should be enabled for GradientTest::Margins")
// #endif

namespace nom {

class GradientTest: public nom::VisualUnitTest
{
  public:
    /// \remarks This method is called at the start of each unit test.
    GradientTest()
    {
      // NOM_LOG_TRACE( NOM );

      this->set_window_flags( SDL_WINDOW_RESIZABLE );

      // The frame image to compare against the reference image set
      this->append_screenshot_frame( 0 );
    }

    /// \remarks This method is called at the end of each unit test.
    virtual ~GradientTest()
    {
      // NOM_LOG_TRACE( NOM );
    }

    /// \remarks This method is called after construction, at the start of each
    /// unit test.
    virtual void SetUp()
    {
      // NOM_LOG_TRACE( NOM );

      std::string res_file = nom::UnitTest::test_set() + ".json";

      if( resources.load_file( res_file, "resources" ) == false )
      {
        FAIL()
        << "Could not resolve the resource path from file: " << res_file;
      }

      // VisualUnitTest environment init...
      VisualUnitTest::SetUp();

      EventCallback debug_info( [&] ( const Event& evt )
        {
          NOM_LOG_INFO( NOM_LOG_CATEGORY_TEST, "x:", evt.mouse.x, "y:", evt.mouse.y );
        }
      );

      InputActionMapper state;

      state.insert( "debug_info", nom::MouseButtonAction(
                    SDL_MOUSEBUTTONDOWN, SDL_BUTTON_LEFT ),
                    debug_info );

      this->input_mapper_.insert( "debug_info", state, true );

      this->colors[0] = {
                          Color4iColors{
                            Color4i::Gray,
                            Color4i::LightGray
                          }
                        };
      this->colors[1] = {
                          Color4iColors{
                            nom::Color4i( 114, 66, 66 ),
                            nom::Color4i( 251, 222, 232 )
                          }
                        };

      int w = this->resolution().w;
      int h = this->resolution().h;
      this->pos1 = Point2i( 0, 0 );
      this->dims1 = Size2i( w, h / 2 );

      this->pos2 = Point2i( 0, h / 2 );
      this->dims2 = Size2i( w, h / 2 );

      // Not used
      this->pos3 = Point2i( w/3, h/2 );
      this->dims3 = Size2i( w/3, h/3 );

      this->grad1.set_colors( this->colors[0] );
      this->grad1.set_position( this->pos1 );
      this->grad1.set_size( this->dims1 );

      this->grad2.set_colors( this->colors[1] );
      this->grad2.set_position( this->pos2 );
      this->grad2.set_size( this->dims2 );

      // Not used
      this->grad3.set_colors( this->colors[0] );
      this->grad3.set_position( this->pos3 );
      this->grad3.set_size( this->dims3 );

      // Register our main loop
      this->append_render_callback( [&] ( const RenderWindow& win ) { this->grad1.draw( this->render_window() ); } );
      this->append_render_callback( [&] ( const RenderWindow& win ) { this->grad2.draw( this->render_window() ); } );
      // this->append_render_callback( [&] ( const RenderWindow& win ) { this->grad3.draw( this->render_window() ); } );
    }

    /// \remarks This method is called before destruction, at the end of each
    /// unit test.
    virtual void TearDown()
    {
      // NOM_LOG_TRACE( NOM );
    }

    /// \remarks This method is called at the start of each test case.
    static void SetUpTestCase()
    {
      // NOM_LOG_TRACE( NOM );
    }

    /// \remarks This method is called at the end of each test case.
    static void TearDownTestCase()
    {
      // NOM_LOG_TRACE( NOM );
    }

  protected:
    SearchPath resources;

    Gradient grad1;
    Gradient grad2;
    // Not used
    Gradient grad3;

    Point2i pos1;
    Size2i dims1;

    Point2i pos2;
    Size2i dims2;

    // Not used
    Point2i pos3;
    Size2i dims3;

    /// \brief Colors used to create the gradient

    /// \remarks One of two used
    Color4iColors colors[2];
};

TEST_F( GradientTest, TopToBottomLinearFill )
{
  this->grad1.set_fill_direction( Gradient::FillDirection::Top );
  this->grad2.set_fill_direction( Gradient::FillDirection::Top );
  // this->grad3.set_fill_direction( Gradient::FillDirection::Top );

  EXPECT_EQ( NOM_EXIT_SUCCESS, this->on_run() );
  EXPECT_TRUE( this->compare() );
}

TEST_F( GradientTest, BottomToTopLinearFill )
{
  this->grad1.set_fill_direction( Gradient::FillDirection::Bottom );
  this->grad2.set_fill_direction( Gradient::FillDirection::Bottom );
  // this->grad3.set_fill_direction( Gradient::FillDirection::Bottom );

  EXPECT_EQ( NOM_EXIT_SUCCESS, this->on_run() );
  EXPECT_TRUE( this->compare() );
}

TEST_F( GradientTest, LeftToRightLinearFill )
{
  this->grad1.set_fill_direction( Gradient::FillDirection::Left );
  this->grad2.set_fill_direction( Gradient::FillDirection::Left );
  // this->grad3.set_fill_direction( Gradient::FillDirection::Left );

  EXPECT_EQ( NOM_EXIT_SUCCESS, this->on_run() );
  EXPECT_TRUE( this->compare() );
}

TEST_F( GradientTest, RightToLeftLinearFill )
{
  this->grad1.set_fill_direction( Gradient::FillDirection::Right );
  this->grad2.set_fill_direction( Gradient::FillDirection::Right );
  // this->grad3.set_fill_direction( Gradient::FillDirection::Right );

  EXPECT_EQ( NOM_EXIT_SUCCESS, this->on_run() );
  EXPECT_TRUE( this->compare() );
}

// TOOD: Verify / fix margins calculations for left to right directions
TEST_F( GradientTest, Margins )
{
  std::shared_ptr<Gradient> card_background;
  std::shared_ptr<SpriteBatch> card_face;

  // Loosely emulate TTcards scale resolution (scale up)
  const std::string sheet_coords = resources.path()+"faces.json";
  const std::string sheet_img = resources.path()+"faces.png";
  const int SCALE_FACTOR = 2;
  const int CARD_WIDTH = 64;
  const int CARD_HEIGHT = 64;
  const int CARD_ORIGIN_X =
    ( (this->resolution().w / SCALE_FACTOR) - CARD_WIDTH ) / 2;
  const int CARD_ORIGIN_Y =
    ( (this->resolution().h / SCALE_FACTOR) - CARD_HEIGHT ) / 2;

  Color4iColors player1_grad_bg = { Color4i( 208, 223, 255 ),
                                    Color4i( 50, 59, 114 )
                                  };
  Size2i dims;
  dims.w = this->resolution().w;
  dims.h = this->resolution().h;
  this->render_window().set_logical_size( dims );
  this->render_window().set_scale( Point2f(2) );

  card_background = std::make_shared<Gradient>( Gradient() );

  card_face =
    std::make_shared<SpriteBatch>( SpriteBatch( sheet_coords ) );

  if( card_face->load( sheet_img ) == false )
  {
    FAIL() << "Could not load image from file: " << sheet_img;
  }
  // card_face->resize( nom::Texture::ResizeAlgorithm::scale2x );

  // Geezard
  card_face->set_frame( 0 );

  card_face->set_position( Point2i(CARD_ORIGIN_X, CARD_ORIGIN_Y) );
  card_background->set_position( nom::Point2i(CARD_ORIGIN_X, CARD_ORIGIN_Y) );

  // The gradient should be bound within the
  //
  // Note that the 1 pixel border surrounding each card is why these
  // calculations are necessary; we want the gradient to be inside the card's
  // border
  card_background->set_size( Size2i(CARD_WIDTH-2, CARD_HEIGHT-2) );
  card_background->set_margins( Point2i(1,1) );
  card_background->set_colors( player1_grad_bg );
  card_background->set_fill_direction( nom::Gradient::FillDirection::Top );

  // 62, 62
  // NOM_DUMP( card_background->size() );
  // 128, 88
  // NOM_DUMP( card_background->position() );

  // Need to first clear out the default grad objects in here
  this->clear_render_callbacks();

  // Re-add the default rendering callback
  this->append_render_callback( this->default_render_callback() );

  this->append_render_callback( [&] ( const RenderWindow& win ) {
    card_background->draw( this->render_window() );
  });

  this->append_render_callback( [&] ( const RenderWindow& win ) {
    card_face->draw ( this->render_window() );
  });

  EXPECT_EQ( NOM_EXIT_SUCCESS, this->on_run() );
  EXPECT_TRUE( this->compare() );
}

} // namespace nom

int main( int argc, char** argv )
{
  ::testing::InitGoogleTest( &argc, argv );

  // Set the current working directory path to the path leading to this
  // executable file; used for unit tests that require file-system I/O.
  if( nom::init( argc, argv ) == false )
  {
    nom::DialogMessageBox( "Critical Error", "Could not initialize nomlib.", nom::MessageBoxType::NOM_DIALOG_ERROR );
    return NOM_EXIT_FAILURE;
  }
  atexit( nom::quit );

  // nom::UnitTest framework integration
  nom::init_test( argc, argv );

  nom::SDL2Logger::set_logging_priority( NOM_LOG_CATEGORY_RENDER, nom::NOM_LOG_PRIORITY_VERBOSE );
  // nom::SDL2Logger::set_logging_priority( NOM_LOG_CATEGORY_TRACE, nom::NOM_LOG_PRIORITY_VERBOSE );

  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <map>
#include <vector>

#include <stout/lambda.hpp>
#include <stout/os.hpp>
#include <stout/result.hpp>
#include <stout/strings.hpp>

#include <stout/os/read.hpp>

#include <process/check.hpp>
#include <process/collect.hpp>
#include <process/io.hpp>

#include "common/status_utils.hpp"

#include "docker/docker.hpp"

#include "linux/cgroups.hpp"

#include "slave/containerizer/isolators/cgroups/cpushare.hpp"
#include "slave/containerizer/isolators/cgroups/mem.hpp"

using namespace mesos::internal::slave;

using namespace process;

using std::list;
using std::map;
using std::string;
using std::vector;

template<class T>
static Future<T> failure(
    const string& cmd,
    int status,
    const string& err)
{
  return Failure(
      "Failed to '" + cmd + "': exit status = " +
      WSTRINGIFY(status) + " stderr = " + err);
}

// Asynchronously read stderr from subprocess.
static Future<string> err(const Subprocess& s)
{
  CHECK_SOME(s.err());

  Try<Nothing> nonblock = os::nonblock(s.err().get());
  if (nonblock.isError()) {
    return Failure("Cannot set nonblock for stderr: " + nonblock.error());
  }

  // TODO(tnachen): Although unlikely, it's possible to not capture
  // the caller's failure message if io::read stderr fails. Can
  // chain a callback to at least log.
  return io::read(s.err().get());
}

static Future<Nothing> _checkError(const string& cmd, const Subprocess& s)
{
  Option<int> status = s.status().get();
  if (status.isNone()) {
    return Failure("No status found for '" + cmd + "'");
  }

  if (status.get() != 0) {
    // TODO(tnachen): Consider returning stdout as well.
    return err(s).then(
        lambda::bind(failure<Nothing>, cmd, status.get(), lambda::_1));
  }

  return Nothing();
}

// Returns a failure if no status or non-zero status returned from
// subprocess.
static Future<Nothing> checkError(const string& cmd, const Subprocess& s)
{
  return s.status().then(lambda::bind(_checkError, cmd, s));
}

Try<Docker> Docker::create(const string& path, bool validate)
{
  if (!validate) {
    return Docker(path);
  }

  // Make sure that cgroups are mounted, and at least the 'cpu'
  // subsystem is attached.
  Result<string> hierarchy = cgroups::hierarchy("cpu");

  if (hierarchy.isNone()) {
    return Error("Failed to find a mounted cgroups hierarchy "
                 "for the 'cpu' subsystem, you probably need "
                 "to mount cgroups manually!");
  }

  std::string cmd = path + " info";

  Try<Subprocess> s = subprocess(
      cmd,
      Subprocess::PATH("/dev/null"),
      Subprocess::PIPE(),
      Subprocess::PATH("/dev/null"));

  if (s.isError()) {
    return Error(s.error());
  }

  Try<Nothing> nonblock = os::nonblock(s.get().out().get());
  if (nonblock.isError()) {
    return Error("Failed to accept nonblock stdout:" + nonblock.error());
  }

  Future<string> output = io::read(s.get().out().get());

  if (!output.await(Seconds(5))) {
    return Error("Docker info failed with time out");
  } else if (output.isFailed()) {
    return Error("Docker info failed: " + output.failure());
  }

  return Docker(path);
}

Try<Docker::Container> Docker::Container::create(const JSON::Object& json)
{
  map<string, JSON::Value>::const_iterator entry =
    json.values.find("Id");
  if (entry == json.values.end()) {
    return Error("Unable to find Id in container");
  }

  JSON::Value idValue = entry->second;
  if (!idValue.is<JSON::String>()) {
    return Error("Id in container is not a string type");
  }

  string id = idValue.as<JSON::String>().value;

  entry = json.values.find("Name");
  if (entry == json.values.end()) {
    return Error("Unable to find Name in container");
  }

  JSON::Value nameValue = entry->second;
  if (!nameValue.is<JSON::String>()) {
    return Error("Name in container is not string type");
  }

  string name = nameValue.as<JSON::String>().value;

  entry = json.values.find("State");
  if (entry == json.values.end()) {
    return Error("Unable to find State in container");
  }

  JSON::Value stateValue = entry->second;
  if (!stateValue.is<JSON::Object>()) {
    return Error("State in container is not object type");
  }

  entry = stateValue.as<JSON::Object>().values.find("Pid");
  if (entry == json.values.end()) {
    return Error("Unable to find Pid in State");
  }

  // TODO(yifan): Reload operator '=' to reuse the value variable above.
  JSON::Value pidValue = entry->second;
  if (!pidValue.is<JSON::Number>()) {
    return Error("Pid in State is not number type");
  }

  pid_t pid = pid_t(pidValue.as<JSON::Number>().value);

  Option<pid_t> optionalPid;
  if (pid != 0) {
    optionalPid = pid;
  }

  return Docker::Container(id, name, optionalPid);
}

Future<Nothing> Docker::run(
    const string& image,
    const string& command,
    const string& name,
    const Option<mesos::Resources>& resources,
    const Option<map<string, string> >& env) const
{
  string cmd = path + " run -d";

  if (resources.isSome()) {
    // TODO(yifan): Support other resources (e.g. disk, ports).
    Option<double> cpus = resources.get().cpus();
    if (cpus.isSome()) {
      uint64_t cpuShare =
        std::max((uint64_t) (CPU_SHARES_PER_CPU * cpus.get()), MIN_CPU_SHARES);
      cmd += " -c " + stringify(cpuShare);
    }

    Option<Bytes> mem = resources.get().mem();
    if (mem.isSome()) {
      Bytes memLimit = std::max(mem.get(), MIN_MEMORY);
      cmd += " -m " + stringify(memLimit.bytes());
    }
  }

  if (env.isSome()) {
    // TODO(tnachen): Use subprocess with args instead once we can
    // handle splitting command string into args.
    foreachpair (string key, string value, env.get()) {
      key = strings::replace(key, "\"", "\\\"");
      value = strings::replace(value, "\"", "\\\"");
      cmd += " -e \"" + key + "=" + value + "\"";
    }
  }

  cmd += " --net=host --name=" + name + " " + image + " " + command;

  VLOG(1) << "Running " << cmd;

  Try<Subprocess> s = subprocess(
      cmd,
      Subprocess::PATH("/dev/null"),
      Subprocess::PATH("/dev/null"),
      Subprocess::PIPE());

  if (s.isError()) {
    return Failure(s.error());
  }

  return checkError(cmd, s.get());
}

Future<Nothing> Docker::kill(const string& container, bool remove) const
{
  const string cmd = path + " kill " + container;

  VLOG(1) << "Running " << cmd;

  Try<Subprocess> s = subprocess(
      cmd,
      Subprocess::PATH("/dev/null"),
      Subprocess::PATH("/dev/null"),
      Subprocess::PIPE());

  if (s.isError()) {
    return Failure(s.error());
  }

  return s.get().status()
    .then(lambda::bind(
        &Docker::_kill,
        *this,
        container,
        cmd,
        s.get(),
        remove));
}

Future<Nothing> Docker::_kill(
    const Docker& docker,
    const string& container,
    const string& cmd,
    const Subprocess& s,
    bool remove)
{
  Option<int> status = s.status().get();

  if (remove) {
    bool force = !status.isSome() || status.get() != 0;
    return docker.rm(container, force);
  }

  return checkError(cmd, s);
}

Future<Nothing> Docker::rm(
    const string& container,
    bool force) const
{
  const string cmd = path + (force ? " rm -f " : " rm ") + container;

  VLOG(1) << "Running " << cmd;

  Try<Subprocess> s = subprocess(
      cmd,
      Subprocess::PATH("/dev/null"),
      Subprocess::PATH("/dev/null"),
      Subprocess::PIPE());

  if (s.isError()) {
    return Failure(s.error());
  }

  return checkError(cmd, s.get());
}

Future<Docker::Container> Docker::inspect(const string& container) const
{
  const string cmd =  path + " inspect " + container;
  VLOG(1) << "Running " << cmd;

  Try<Subprocess> s = subprocess(
      cmd,
      Subprocess::PATH("/dev/null"),
      Subprocess::PIPE(),
      Subprocess::PIPE());

  if (s.isError()) {
    return Failure(s.error());
  }

  return s.get().status()
    .then(lambda::bind(&Docker::_inspect, cmd, s.get()));
}

Future<Docker::Container> Docker::_inspect(
    const string& cmd,
    const Subprocess& s)
{
  // Check the exit status of 'docker inspect'.
  CHECK_READY(s.status());

  Option<int> status = s.status().get();

  if (!status.isSome()) {
    return Failure("No status found from '" + cmd + "'");
  } else if (status.get() != 0) {
    return err(s).then(
        lambda::bind(
            failure<Docker::Container>,
            cmd,
            status.get(),
            lambda::_1));
  }

  // Read to EOF.
  CHECK_SOME(s.out());
  Try<Nothing> nonblock = os::nonblock(s.out().get());
  if (nonblock.isError()) {
    return Failure("Failed to accept nonblock stdout:" + nonblock.error());
  }
  Future<string> output = io::read(s.out().get());
  return output.then(lambda::bind(&Docker::__inspect, lambda::_1));
}

Future<Docker::Container> Docker::__inspect(const string& output)
{
  Try<JSON::Array> parse = JSON::parse<JSON::Array>(output);

  if (parse.isError()) {
    return Failure("Failed to parse JSON: " + parse.error());
  }

  JSON::Array array = parse.get();
  // Only return if only one container identified with name.
  if (array.values.size() == 1) {
    CHECK(array.values.front().is<JSON::Object>());
    Try<Docker::Container> container =
      Docker::Container::create(array.values.front().as<JSON::Object>());

    if (container.isError()) {
      return Failure("Unable to create container: " + container.error());
    }

    return container.get();
  }

  // TODO(benh): Handle the case where the short container ID was
  // not sufficiently unique and 'array.values.size() > 1'.

  return Failure("Failed to find container");
}

Future<list<Docker::Container> > Docker::ps(
    bool all,
    const Option<string>& prefix) const
{
  string cmd = path + (all ? " ps -a" : " ps");

  VLOG(1) << "Running " << cmd;

  Try<Subprocess> s = subprocess(
      cmd,
      Subprocess::PATH("/dev/null"),
      Subprocess::PIPE(),
      Subprocess::PIPE());

  if (s.isError()) {
    return Failure(s.error());
  }

  return s.get().status()
    .then(lambda::bind(&Docker::_ps, *this, cmd, s.get(), prefix));
}

Future<list<Docker::Container> > Docker::_ps(
    const Docker& docker,
    const string& cmd,
    const Subprocess& s,
    const Option<string>& prefix)
{
  Option<int> status = s.status().get();

  if (!status.isSome()) {
    return Failure("No status found from '" + cmd + "'");
  } else if (status.get() != 0) {
    return err(s).then(
        lambda::bind(
            failure<list<Docker::Container> >,
            cmd,
            status.get(),
            lambda::_1));
  }

  // Read to EOF.
  CHECK_SOME(s.out());
  Try<Nothing> nonblock = os::nonblock(s.out().get());
  if (nonblock.isError()) {
    return Failure("Failed to accept nonblock stdout:" + nonblock.error());
  }
  Future<string> output = io::read(s.out().get());
  return output.then(lambda::bind(&Docker::__ps, docker, prefix, lambda::_1));
}

Future<list<Docker::Container> > Docker::__ps(
    const Docker& docker,
    const Option<string>& prefix,
    const string& output)
{
  vector<string> lines = strings::tokenize(output, "\n");

  // Skip the header.
  CHECK(!lines.empty());
  lines.erase(lines.begin());

  list<Future<Docker::Container> > futures;

  foreach (const string& line, lines) {
    // Inspect the containers that we are interested in depending on
    // whether or not a 'prefix' was specified.
    vector<string> columns = strings::split(strings::trim(line), " ");
    // We expect the name column to be the last column from ps.
    string name = columns[columns.size() - 1];
    if (prefix.isNone()) {
      futures.push_back(docker.inspect(name));
    } else if (strings::startsWith(name, prefix.get())) {
      futures.push_back(docker.inspect(name));
    }
  }

  return collect(futures);
}
<commit_msg>Checked docker validation status code.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <map>
#include <vector>

#include <stout/lambda.hpp>
#include <stout/os.hpp>
#include <stout/result.hpp>
#include <stout/strings.hpp>

#include <stout/os/read.hpp>

#include <process/check.hpp>
#include <process/collect.hpp>
#include <process/io.hpp>

#include "common/status_utils.hpp"

#include "docker/docker.hpp"

#include "linux/cgroups.hpp"

#include "slave/containerizer/isolators/cgroups/cpushare.hpp"
#include "slave/containerizer/isolators/cgroups/mem.hpp"

using namespace mesos::internal::slave;

using namespace process;

using std::list;
using std::map;
using std::string;
using std::vector;

template<class T>
static Future<T> failure(
    const string& cmd,
    int status,
    const string& err)
{
  return Failure(
      "Failed to '" + cmd + "': exit status = " +
      WSTRINGIFY(status) + " stderr = " + err);
}

// Asynchronously read stderr from subprocess.
static Future<string> err(const Subprocess& s)
{
  CHECK_SOME(s.err());

  Try<Nothing> nonblock = os::nonblock(s.err().get());
  if (nonblock.isError()) {
    return Failure("Cannot set nonblock for stderr: " + nonblock.error());
  }

  // TODO(tnachen): Although unlikely, it's possible to not capture
  // the caller's failure message if io::read stderr fails. Can
  // chain a callback to at least log.
  return io::read(s.err().get());
}

static Future<Nothing> _checkError(const string& cmd, const Subprocess& s)
{
  Option<int> status = s.status().get();
  if (status.isNone()) {
    return Failure("No status found for '" + cmd + "'");
  }

  if (status.get() != 0) {
    // TODO(tnachen): Consider returning stdout as well.
    return err(s).then(
        lambda::bind(failure<Nothing>, cmd, status.get(), lambda::_1));
  }

  return Nothing();
}

// Returns a failure if no status or non-zero status returned from
// subprocess.
static Future<Nothing> checkError(const string& cmd, const Subprocess& s)
{
  return s.status().then(lambda::bind(_checkError, cmd, s));
}

Try<Docker> Docker::create(const string& path, bool validate)
{
  if (!validate) {
    return Docker(path);
  }

  // Make sure that cgroups are mounted, and at least the 'cpu'
  // subsystem is attached.
  Result<string> hierarchy = cgroups::hierarchy("cpu");

  if (hierarchy.isNone()) {
    return Error("Failed to find a mounted cgroups hierarchy "
                 "for the 'cpu' subsystem, you probably need "
                 "to mount cgroups manually!");
  }

  std::string cmd = path + " info";

  Try<Subprocess> s = subprocess(
      cmd,
      Subprocess::PATH("/dev/null"),
      Subprocess::PATH("/dev/null"),
      Subprocess::PATH("/dev/null"));

  if (s.isError()) {
    return Error(s.error());
  }

  Future<Option<int> > status = s.get().status();

  if (!status.await(Seconds(5))) {
    return Error("Docker info failed with time out");
  } else if (status.isFailed()) {
    return Error("Docker info failed: " + status.failure());
  } else if (!status.get().isSome() || status.get().get() != 0) {
    string msg = "Docker info failed to execute";
    if (status.get().isSome()) {
      msg += ", exited with status (" + WSTRINGIFY(status.get().get()) + ")";
    }
    return Error(msg);
  }

  return Docker(path);
}

Try<Docker::Container> Docker::Container::create(const JSON::Object& json)
{
  map<string, JSON::Value>::const_iterator entry =
    json.values.find("Id");
  if (entry == json.values.end()) {
    return Error("Unable to find Id in container");
  }

  JSON::Value idValue = entry->second;
  if (!idValue.is<JSON::String>()) {
    return Error("Id in container is not a string type");
  }

  string id = idValue.as<JSON::String>().value;

  entry = json.values.find("Name");
  if (entry == json.values.end()) {
    return Error("Unable to find Name in container");
  }

  JSON::Value nameValue = entry->second;
  if (!nameValue.is<JSON::String>()) {
    return Error("Name in container is not string type");
  }

  string name = nameValue.as<JSON::String>().value;

  entry = json.values.find("State");
  if (entry == json.values.end()) {
    return Error("Unable to find State in container");
  }

  JSON::Value stateValue = entry->second;
  if (!stateValue.is<JSON::Object>()) {
    return Error("State in container is not object type");
  }

  entry = stateValue.as<JSON::Object>().values.find("Pid");
  if (entry == json.values.end()) {
    return Error("Unable to find Pid in State");
  }

  // TODO(yifan): Reload operator '=' to reuse the value variable above.
  JSON::Value pidValue = entry->second;
  if (!pidValue.is<JSON::Number>()) {
    return Error("Pid in State is not number type");
  }

  pid_t pid = pid_t(pidValue.as<JSON::Number>().value);

  Option<pid_t> optionalPid;
  if (pid != 0) {
    optionalPid = pid;
  }

  return Docker::Container(id, name, optionalPid);
}

Future<Nothing> Docker::run(
    const string& image,
    const string& command,
    const string& name,
    const Option<mesos::Resources>& resources,
    const Option<map<string, string> >& env) const
{
  string cmd = path + " run -d";

  if (resources.isSome()) {
    // TODO(yifan): Support other resources (e.g. disk, ports).
    Option<double> cpus = resources.get().cpus();
    if (cpus.isSome()) {
      uint64_t cpuShare =
        std::max((uint64_t) (CPU_SHARES_PER_CPU * cpus.get()), MIN_CPU_SHARES);
      cmd += " -c " + stringify(cpuShare);
    }

    Option<Bytes> mem = resources.get().mem();
    if (mem.isSome()) {
      Bytes memLimit = std::max(mem.get(), MIN_MEMORY);
      cmd += " -m " + stringify(memLimit.bytes());
    }
  }

  if (env.isSome()) {
    // TODO(tnachen): Use subprocess with args instead once we can
    // handle splitting command string into args.
    foreachpair (string key, string value, env.get()) {
      key = strings::replace(key, "\"", "\\\"");
      value = strings::replace(value, "\"", "\\\"");
      cmd += " -e \"" + key + "=" + value + "\"";
    }
  }

  cmd += " --net=host --name=" + name + " " + image + " " + command;

  VLOG(1) << "Running " << cmd;

  Try<Subprocess> s = subprocess(
      cmd,
      Subprocess::PATH("/dev/null"),
      Subprocess::PATH("/dev/null"),
      Subprocess::PIPE());

  if (s.isError()) {
    return Failure(s.error());
  }

  return checkError(cmd, s.get());
}

Future<Nothing> Docker::kill(const string& container, bool remove) const
{
  const string cmd = path + " kill " + container;

  VLOG(1) << "Running " << cmd;

  Try<Subprocess> s = subprocess(
      cmd,
      Subprocess::PATH("/dev/null"),
      Subprocess::PATH("/dev/null"),
      Subprocess::PIPE());

  if (s.isError()) {
    return Failure(s.error());
  }

  return s.get().status()
    .then(lambda::bind(
        &Docker::_kill,
        *this,
        container,
        cmd,
        s.get(),
        remove));
}

Future<Nothing> Docker::_kill(
    const Docker& docker,
    const string& container,
    const string& cmd,
    const Subprocess& s,
    bool remove)
{
  Option<int> status = s.status().get();

  if (remove) {
    bool force = !status.isSome() || status.get() != 0;
    return docker.rm(container, force);
  }

  return checkError(cmd, s);
}

Future<Nothing> Docker::rm(
    const string& container,
    bool force) const
{
  const string cmd = path + (force ? " rm -f " : " rm ") + container;

  VLOG(1) << "Running " << cmd;

  Try<Subprocess> s = subprocess(
      cmd,
      Subprocess::PATH("/dev/null"),
      Subprocess::PATH("/dev/null"),
      Subprocess::PIPE());

  if (s.isError()) {
    return Failure(s.error());
  }

  return checkError(cmd, s.get());
}

Future<Docker::Container> Docker::inspect(const string& container) const
{
  const string cmd =  path + " inspect " + container;
  VLOG(1) << "Running " << cmd;

  Try<Subprocess> s = subprocess(
      cmd,
      Subprocess::PATH("/dev/null"),
      Subprocess::PIPE(),
      Subprocess::PIPE());

  if (s.isError()) {
    return Failure(s.error());
  }

  return s.get().status()
    .then(lambda::bind(&Docker::_inspect, cmd, s.get()));
}

Future<Docker::Container> Docker::_inspect(
    const string& cmd,
    const Subprocess& s)
{
  // Check the exit status of 'docker inspect'.
  CHECK_READY(s.status());

  Option<int> status = s.status().get();

  if (!status.isSome()) {
    return Failure("No status found from '" + cmd + "'");
  } else if (status.get() != 0) {
    return err(s).then(
        lambda::bind(
            failure<Docker::Container>,
            cmd,
            status.get(),
            lambda::_1));
  }

  // Read to EOF.
  CHECK_SOME(s.out());
  Try<Nothing> nonblock = os::nonblock(s.out().get());
  if (nonblock.isError()) {
    return Failure("Failed to accept nonblock stdout:" + nonblock.error());
  }
  Future<string> output = io::read(s.out().get());
  return output.then(lambda::bind(&Docker::__inspect, lambda::_1));
}

Future<Docker::Container> Docker::__inspect(const string& output)
{
  Try<JSON::Array> parse = JSON::parse<JSON::Array>(output);

  if (parse.isError()) {
    return Failure("Failed to parse JSON: " + parse.error());
  }

  JSON::Array array = parse.get();
  // Only return if only one container identified with name.
  if (array.values.size() == 1) {
    CHECK(array.values.front().is<JSON::Object>());
    Try<Docker::Container> container =
      Docker::Container::create(array.values.front().as<JSON::Object>());

    if (container.isError()) {
      return Failure("Unable to create container: " + container.error());
    }

    return container.get();
  }

  // TODO(benh): Handle the case where the short container ID was
  // not sufficiently unique and 'array.values.size() > 1'.

  return Failure("Failed to find container");
}

Future<list<Docker::Container> > Docker::ps(
    bool all,
    const Option<string>& prefix) const
{
  string cmd = path + (all ? " ps -a" : " ps");

  VLOG(1) << "Running " << cmd;

  Try<Subprocess> s = subprocess(
      cmd,
      Subprocess::PATH("/dev/null"),
      Subprocess::PIPE(),
      Subprocess::PIPE());

  if (s.isError()) {
    return Failure(s.error());
  }

  return s.get().status()
    .then(lambda::bind(&Docker::_ps, *this, cmd, s.get(), prefix));
}

Future<list<Docker::Container> > Docker::_ps(
    const Docker& docker,
    const string& cmd,
    const Subprocess& s,
    const Option<string>& prefix)
{
  Option<int> status = s.status().get();

  if (!status.isSome()) {
    return Failure("No status found from '" + cmd + "'");
  } else if (status.get() != 0) {
    return err(s).then(
        lambda::bind(
            failure<list<Docker::Container> >,
            cmd,
            status.get(),
            lambda::_1));
  }

  // Read to EOF.
  CHECK_SOME(s.out());
  Try<Nothing> nonblock = os::nonblock(s.out().get());
  if (nonblock.isError()) {
    return Failure("Failed to accept nonblock stdout:" + nonblock.error());
  }
  Future<string> output = io::read(s.out().get());
  return output.then(lambda::bind(&Docker::__ps, docker, prefix, lambda::_1));
}

Future<list<Docker::Container> > Docker::__ps(
    const Docker& docker,
    const Option<string>& prefix,
    const string& output)
{
  vector<string> lines = strings::tokenize(output, "\n");

  // Skip the header.
  CHECK(!lines.empty());
  lines.erase(lines.begin());

  list<Future<Docker::Container> > futures;

  foreach (const string& line, lines) {
    // Inspect the containers that we are interested in depending on
    // whether or not a 'prefix' was specified.
    vector<string> columns = strings::split(strings::trim(line), " ");
    // We expect the name column to be the last column from ps.
    string name = columns[columns.size() - 1];
    if (prefix.isNone()) {
      futures.push_back(docker.inspect(name));
    } else if (strings::startsWith(name, prefix.get())) {
      futures.push_back(docker.inspect(name));
    }
  }

  return collect(futures);
}
<|endoftext|>


<commit_before>/* -*- mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/* tests/test-charpoly.C
 * Written by bds (starting from test-charpoly.C)
 *
 * See COPYING for license information.
 */

#include "linbox/linbox-config.h"

#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <cstdio>
template<class T, template <class T> class Container>
std::ostream& operator<< (std::ostream& o, const Container<T>& C) {
	for(typename Container<T>::const_iterator refs =  C.begin();
	    refs != C.end() ;
	    ++refs )
		o << (*refs) << " " ;
	return o << std::endl;
}

#include "linbox/blackbox/sparse.h"
#include "linbox/blackbox/scalar-matrix.h"
#include "linbox/solutions/charpoly.h"
#include "linbox/util/commentator.h"
//#include "linbox/ring/givaro-polynomial.h"
#include "linbox/vector/stream.h"

#include "test-common.h"

using namespace LinBox;

/* Test 1: charpoly of the identity matrix
 *
 * Construct the identity matrix and compute its characteristic polynomial. Confirm
 * that the result is (x-1)^n
 *
 * Z - Integers representation over which to perform computations
 * n - Dimension to which to make matrix
 *
 * Return true on success and false on failure
 */

template <class Dom, class Polynomial>
typename Dom::Element eval (const Dom& D,
			    typename Dom::Element& value,
			    const Polynomial& P,
			    const typename Dom::Element x){
	typename Dom::Element tmp = P[P.size()-1];
	for (int i = P.size()-2; i >= 0; --i){
		D.mulin (tmp, x);
		D.addin (tmp, P[i]);
	}
	return value = tmp;
}

template <class Dom>
static bool testIdentityCharpoly (Dom &Z, size_t n, bool symmetrizing=false)
{
	typedef typename Dom::Element Element;
	typedef vector<Element> Vector;
	typedef ScalarMatrix<Dom> Blackbox;
	//typedef GivPolynomialRing<Dom, Dense> PolDom;
	//typedef typename PolDom::Element Polynomial;
	typedef Vector Polynomial;

	commentator.start ("Testing identity Charpoly", "testIdentityCharpoly");

	bool ret = true;
	Element one; Z.init(one, 1);
	Element negone; Z.init(negone, -1);

	//PolDom IPD(Z);

	Blackbox A (Z, n, one);

	Polynomial phi;

	charpoly (phi, A);

	ostream &report = commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_DESCRIPTION);
	report << "Characteristic polynomial is: ";
	printPolynomial<Dom, Polynomial> (Z, report, phi);

	// partial check - just that charpoly has right values at 0, 1, -1.
	Element val, val2, neg2, pow2;
	// value at 1 should be zero
	eval(Z, val, phi, one);
	if (! Z.isZero(val) ) ret = false;
	// value at zero should be (-1)^n
	val = (n % 2 == 0) ? one : negone;
	if (! Z.areEqual(val, phi[0])) ret = false;
	// value at -1 should be (-2)^n
	eval(Z, val2, phi, negone);
	Z.mulin(val2, val);
	Z.init(neg2, -2); Z.init(pow2, 1);
	for (size_t i = 0; i < n; ++i) Z.mulin(pow2, neg2);
	if (! Z.areEqual(val2, pow2)) ret = false;

	if (! ret){
		commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_ERROR)
			<< "ERROR: Characteristic polynomial is incorrect" << endl;
	}

	commentator.stop (MSG_STATUS (ret), (const char *) 0, "testIdentityCharpoly");

	return ret;
}

/* Test 2: characteristic polynomial of a nilpotent matrix
 *
 * Construct an index-n nilpotent matrix and compute its characteristic
 * polynomial. Confirm that the result is x^n
 *
 * F - Field over which to perform computations
 * n - Dimension to which to make matrix
 *
 * Return true on success and false on failure
 */

template <class Field>
static bool testNilpotentCharpoly (Field &F, size_t n)
{
	typedef vector <typename Field::Element> Vector;
// 	typedef GivPolynomialRing<Field, Dense> PolDom;
// 	typedef typename PolDom::Element Polynomial;
	typedef Vector Polynomial;
	typedef pair <vector <size_t>, vector <typename Field::Element> > Row;
	typedef SparseMatrix <Field> Blackbox;

	commentator.start ("Testing nilpotent charpoly", "testNilpotentCharpoly");

	bool ret = true;
	bool lowerTermsCorrect = true;

	size_t i;

	StandardBasisStream<Field, Row> stream (F, n);
	Row v;
	stream.next (v);
	Blackbox A (F, stream);

	Polynomial phi;

	charpoly (phi, A);

	ostream &report = commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_DESCRIPTION);
	report << "characteristic polynomial is: ";
	printPolynomial (F, report, phi);

	for (i = 0; i < n - 1; i++)
		if (!F.isZero (phi[i]))
			lowerTermsCorrect = false;

	if (phi.size () != n + 1 || !F.isOne (phi[n]) || !lowerTermsCorrect) {
		ret = false;
		commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_ERROR)
			<< "ERROR: characteristic polynomial is incorrect" << endl;
	}

	commentator.stop (MSG_STATUS (ret), (const char *) 0, "testNilpotentCharpoly");

	return ret;
}

#if 1
/* Test 3: Random charpoly of sparse matrix
 *
 * Generates a random sparse matrix with K nonzero elements per row and computes
 * its characteristic polynomial. Then computes random vectors and applies the
 * polynomial to them in Horner style, checking whether the result is 0.
 *
 * F - Field over which to perform computations
 * n - Dimension to which to make matrix
 * K - Number of nonzero elements per row
 * numVectors - Number of random vectors to which to apply the characteristic polynomial
 *
 * Return true on success and false on failure
 */

template <class Field, class Row, class Vector>
bool testRandomCharpoly (Field                 &F,
			int                    iterations,
			VectorStream<Row>    &A_stream,
			VectorStream<Vector> &v_stream)
{
	//typedef GivPolynomialRing<Field, Dense> PolDom;
	//typedef typename PolDom::Element Polynomial;
	typedef std::vector<typename Field::Element> Polynomial;
	typedef SparseMatrix <Field> Blackbox;

	commentator.start ("Testing sparse random charpoly", "testRandomCharpoly", iterations);

	bool ret = true;
	bool iter_passed;

	VectorDomain<Field> VD (F);

	Vector v, w;

	VectorWrapper::ensureDim (v, v_stream.n ());
	VectorWrapper::ensureDim (w, v_stream.n ());

	for (int i = 0; i < iterations; i++) {
		commentator.startIteration (i);

		iter_passed = true;

		A_stream.reset ();
		Blackbox A (F, A_stream);

		ostream &report = commentator.report (Commentator::LEVEL_UNIMPORTANT, INTERNAL_DESCRIPTION);
		report << "Matrix:" << endl;
		A.write (report, FORMAT_PRETTY);

		Polynomial phi;

		charpoly (phi, A);

		report << "characteristic polynomial is: ";
		printPolynomial (F, report, phi);

		commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_DESCRIPTION)
			<< "deg charpoly (A) = " << phi.size () - 1 << endl;

		v_stream.reset ();

		while (v_stream) {
			v_stream.next (v);

			report << "Input vector  " << v_stream.j () << ": ";
			VD.write (report, v);
			report << endl;

			applyPoly (F, w, A, phi, v);

			report << "Output vector " << v_stream.j () << ": ";
			VD.write (report, w);
			report << endl;

			if (!VD.isZero (w))
				ret = iter_passed = false;
		}

		if (!iter_passed)
			commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_ERROR)
				<< "ERROR: Output vector was incorrect" << endl;

		commentator.stop ("done");
		commentator.progress ();
	}

	commentator.stop (MSG_STATUS (ret), (const char *) 0, "testRandomCharpoly");

	return ret;
}
#endif

int main (int argc, char **argv)
{
	bool pass = true;

	std::cout<<setprecision(8);
	std::cerr<<setprecision(8);
	static size_t n = 50;
	static integer q = 33554467U;
	//static integer q = 1000003U; // 33554467U;
	static int iterations = 1;
	static int numVectors = 100;
	static int k = 3;

	static Argument args[] = {
		{ 'n', "-n N", "Set dimension of test matrices to NxN.",                 TYPE_INT,     &n },
		{ 'q', "-q Q", "Operate over the \"field\" GF(Q) [1].",          TYPE_INTEGER, &q },
		{ 'i', "-i I", "Perform each test for I iterations.",                    TYPE_INT,     &iterations },
		{ 'v', "-v V", "Use V test vectors for the random charpoly tests.",      TYPE_INT,     &numVectors },
		{ 'k', "-k K", "K nonzero Elements per row in sparse random apply test.", TYPE_INT,     &k },
		{ '\0' }
	};

	parseArguments (argc, argv, args);

	typedef Modular<int> Field;
	//typedef Modular<double> Field;
	typedef vector<Field::Element> DenseVector;
	typedef SparseMatrix<Field>::Row SparseVector;
	//typedef pair<vector<size_t>, vector<Field::Element> > SparseVector;
	Field F (q);
	srand (time (NULL));

	commentator.getMessageClass (TIMING_MEASURE).setMaxDepth (10);
	commentator.getMessageClass (INTERNAL_DESCRIPTION).setMaxDepth (10);
	commentator.getMessageClass (INTERNAL_DESCRIPTION).setMaxDetailLevel (Commentator::LEVEL_UNIMPORTANT);

	ostream &report = commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_DESCRIPTION);
	report << endl << "Black box characteristic polynomial of a matrix over a prime field test suite" << endl;

	RandomDenseStream<Field, DenseVector, NonzeroRandIter<Field> >
		v_stream (F, NonzeroRandIter<Field> (F, Field::RandIter (F)), n, numVectors);
	RandomSparseStream<Field, SparseVector, NonzeroRandIter<Field> >
		A_stream (F, NonzeroRandIter<Field> (F, Field::RandIter (F)), (double) k / (double) n, n, n);

	if (!testNilpotentCharpoly (F, n)) pass = false;
	if (!testRandomCharpoly    (F, iterations, A_stream, v_stream)) pass = false;

	// symmetrizing
	if (!testIdentityCharpoly  (F, n, true)) pass = false;
	//need other tests...

	typedef vector<PID_integer::Element> ZDenseVector;
	typedef SparseMatrix<PID_integer>::Row ZSparseVector;
	typedef pair<vector<size_t>, vector<Field::Element> > SparseVector;
	PID_integer  Z;
	srand (time (NULL));

	commentator.getMessageClass (TIMING_MEASURE).setMaxDepth (10);
	commentator.getMessageClass (INTERNAL_DESCRIPTION).setMaxDepth (10);
	commentator.getMessageClass (INTERNAL_DESCRIPTION).setMaxDetailLevel (Commentator::LEVEL_UNIMPORTANT);

	report << endl << "Black box characteristic polynomial of an integer matrix test suite" << endl;

	RandomDenseStream<PID_integer, ZDenseVector, NonzeroRandIter<PID_integer> >
		zv_stream (Z, NonzeroRandIter<PID_integer> (Z, PID_integer::RandIter (Z)), n, numVectors);
	RandomSparseStream<PID_integer, SparseVector, NonzeroRandIter<PID_integer> >
		zA_stream (Z, NonzeroRandIter<PID_integer> (Z, PID_integer::RandIter (Z)), (double) k / (double) n, n, n);

	//no symmetrizing
	if (!testIdentityCharpoly  (Z, n)) pass = false;
	if (!testNilpotentCharpoly (Z, n)) pass = false;

	//Comment by Z. Wan. Stream doesn't work here
	//if (!testRandomCharpoly    (Z, iterations, zA_stream, zv_stream)) pass = false;

	// symmetrizing
	if (!testIdentityCharpoly  (Z, n, true)) pass = false;
	//need other tests...

	return pass ? 0 : -1;
}
<commit_msg>Fix a bug with odd dimension nilpotent matrix test<commit_after>/* -*- mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/* tests/test-charpoly.C
 * Written by bds (starting from test-charpoly.C)
 *
 * See COPYING for license information.
 */

#include "linbox/linbox-config.h"

#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <cstdio>
template<class T, template <class T> class Container>
std::ostream& operator<< (std::ostream& o, const Container<T>& C) {
	for(typename Container<T>::const_iterator refs =  C.begin();
	    refs != C.end() ;
	    ++refs )
		o << (*refs) << " " ;
	return o << std::endl;
}

#include "linbox/blackbox/sparse.h"
#include "linbox/blackbox/scalar-matrix.h"
#include "linbox/solutions/charpoly.h"
#include "linbox/util/commentator.h"
//#include "linbox/ring/givaro-polynomial.h"
#include "linbox/vector/stream.h"

#include "test-common.h"

using namespace LinBox;

/* Test 1: charpoly of the identity matrix
 *
 * Construct the identity matrix and compute its characteristic polynomial. Confirm
 * that the result is (x-1)^n
 *
 * Z - Integers representation over which to perform computations
 * n - Dimension to which to make matrix
 *
 * Return true on success and false on failure
 */

template <class Dom, class Polynomial>
typename Dom::Element eval (const Dom& D,
			    typename Dom::Element& value,
			    const Polynomial& P,
			    const typename Dom::Element x){
	typename Dom::Element tmp = P[P.size()-1];
	for (int i = P.size()-2; i >= 0; --i){
		D.mulin (tmp, x);
		D.addin (tmp, P[i]);
	}
	return value = tmp;
}

template <class Dom>
static bool testIdentityCharpoly (Dom &Z, size_t n, bool symmetrizing=false)
{
	typedef typename Dom::Element Element;
	typedef vector<Element> Vector;
	typedef ScalarMatrix<Dom> Blackbox;
	//typedef GivPolynomialRing<Dom, Dense> PolDom;
	//typedef typename PolDom::Element Polynomial;
	typedef Vector Polynomial;

	commentator.start ("Testing identity Charpoly", "testIdentityCharpoly");

	bool ret = true;
	Element one; Z.init(one, 1);
	Element negone; Z.init(negone, -1);

	//PolDom IPD(Z);

	Blackbox A (Z, n, one);

	Polynomial phi;

	charpoly (phi, A);

	ostream &report = commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_DESCRIPTION);
	report << "Characteristic polynomial is: ";
	printPolynomial<Dom, Polynomial> (Z, report, phi);

	// partial check - just that charpoly has right values at 0, 1, -1.
	Element val, val2, neg2, pow2;
	// value at 1 should be zero
	eval(Z, val, phi, one);
	if (! Z.isZero(val) ) ret = false;
	// value at zero should be (-1)^n
	val = (n % 2 == 0) ? one : negone;
	if (! Z.areEqual(val, phi[0])) ret = false;
	// value at -1 should be (-2)^n
	eval(Z, val2, phi, negone);
	Z.init(neg2, -2); Z.init(pow2, 1);
	for (size_t i = 0; i < n; ++i) Z.mulin(pow2, neg2);
	if (! Z.areEqual(val2, pow2)) ret = false;

	if (! ret){
		commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_ERROR)
			<< "ERROR: Characteristic polynomial is incorrect" << endl;
	}

	commentator.stop (MSG_STATUS (ret), (const char *) 0, "testIdentityCharpoly");

	return ret;
}

/* Test 2: characteristic polynomial of a nilpotent matrix
 *
 * Construct an index-n nilpotent matrix and compute its characteristic
 * polynomial. Confirm that the result is x^n
 *
 * F - Field over which to perform computations
 * n - Dimension to which to make matrix
 *
 * Return true on success and false on failure
 */

template <class Field>
static bool testNilpotentCharpoly (Field &F, size_t n)
{
	typedef vector <typename Field::Element> Vector;
// 	typedef GivPolynomialRing<Field, Dense> PolDom;
// 	typedef typename PolDom::Element Polynomial;
	typedef Vector Polynomial;
	typedef pair <vector <size_t>, vector <typename Field::Element> > Row;
	typedef SparseMatrix <Field> Blackbox;

	commentator.start ("Testing nilpotent charpoly", "testNilpotentCharpoly");

	bool ret = true;
	bool lowerTermsCorrect = true;

	size_t i;

	StandardBasisStream<Field, Row> stream (F, n);
	Row v;
	stream.next (v);
	Blackbox A (F, stream);

	Polynomial phi;

	charpoly (phi, A);

	ostream &report = commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_DESCRIPTION);
	report << "characteristic polynomial is: ";
	printPolynomial (F, report, phi);

	for (i = 0; i < n - 1; i++)
		if (!F.isZero (phi[i]))
			lowerTermsCorrect = false;

	if (phi.size () != n + 1 || !F.isOne (phi[n]) || !lowerTermsCorrect) {
		ret = false;
		commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_ERROR)
			<< "ERROR: characteristic polynomial is incorrect" << endl;
	}

	commentator.stop (MSG_STATUS (ret), (const char *) 0, "testNilpotentCharpoly");

	return ret;
}

#if 1
/* Test 3: Random charpoly of sparse matrix
 *
 * Generates a random sparse matrix with K nonzero elements per row and computes
 * its characteristic polynomial. Then computes random vectors and applies the
 * polynomial to them in Horner style, checking whether the result is 0.
 *
 * F - Field over which to perform computations
 * n - Dimension to which to make matrix
 * K - Number of nonzero elements per row
 * numVectors - Number of random vectors to which to apply the characteristic polynomial
 *
 * Return true on success and false on failure
 */

template <class Field, class Row, class Vector>
bool testRandomCharpoly (Field                 &F,
			int                    iterations,
			VectorStream<Row>    &A_stream,
			VectorStream<Vector> &v_stream)
{
	//typedef GivPolynomialRing<Field, Dense> PolDom;
	//typedef typename PolDom::Element Polynomial;
	typedef std::vector<typename Field::Element> Polynomial;
	typedef SparseMatrix <Field> Blackbox;

	commentator.start ("Testing sparse random charpoly", "testRandomCharpoly", iterations);

	bool ret = true;
	bool iter_passed;

	VectorDomain<Field> VD (F);

	Vector v, w;

	VectorWrapper::ensureDim (v, v_stream.n ());
	VectorWrapper::ensureDim (w, v_stream.n ());

	for (int i = 0; i < iterations; i++) {
		commentator.startIteration (i);

		iter_passed = true;

		A_stream.reset ();
		Blackbox A (F, A_stream);

		ostream &report = commentator.report (Commentator::LEVEL_UNIMPORTANT, INTERNAL_DESCRIPTION);
		report << "Matrix:" << endl;
		A.write (report, FORMAT_PRETTY);

		Polynomial phi;

		charpoly (phi, A);

		report << "characteristic polynomial is: ";
		printPolynomial (F, report, phi);

		commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_DESCRIPTION)
			<< "deg charpoly (A) = " << phi.size () - 1 << endl;

		v_stream.reset ();

		while (v_stream) {
			v_stream.next (v);

			report << "Input vector  " << v_stream.j () << ": ";
			VD.write (report, v);
			report << endl;

			applyPoly (F, w, A, phi, v);

			report << "Output vector " << v_stream.j () << ": ";
			VD.write (report, w);
			report << endl;

			if (!VD.isZero (w))
				ret = iter_passed = false;
		}

		if (!iter_passed)
			commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_ERROR)
				<< "ERROR: Output vector was incorrect" << endl;

		commentator.stop ("done");
		commentator.progress ();
	}

	commentator.stop (MSG_STATUS (ret), (const char *) 0, "testRandomCharpoly");

	return ret;
}
#endif

int main (int argc, char **argv)
{
	bool pass = true;

	std::cout<<setprecision(8);
	std::cerr<<setprecision(8);
	static size_t n = 50;
	static integer q = 33554467U;
	//static integer q = 1000003U; // 33554467U;
	static int iterations = 1;
	static int numVectors = 100;
	static int k = 3;

	static Argument args[] = {
		{ 'n', "-n N", "Set dimension of test matrices to NxN.",                 TYPE_INT,     &n },
		{ 'q', "-q Q", "Operate over the \"field\" GF(Q) [1].",          TYPE_INTEGER, &q },
		{ 'i', "-i I", "Perform each test for I iterations.",                    TYPE_INT,     &iterations },
		{ 'v', "-v V", "Use V test vectors for the random charpoly tests.",      TYPE_INT,     &numVectors },
		{ 'k', "-k K", "K nonzero Elements per row in sparse random apply test.", TYPE_INT,     &k },
		{ '\0' }
	};

	parseArguments (argc, argv, args);

	typedef Modular<int> Field;
	//typedef Modular<double> Field;
	typedef vector<Field::Element> DenseVector;
	typedef SparseMatrix<Field>::Row SparseVector;
	//typedef pair<vector<size_t>, vector<Field::Element> > SparseVector;
	Field F (q);
	srand (time (NULL));

	commentator.getMessageClass (TIMING_MEASURE).setMaxDepth (10);
	commentator.getMessageClass (INTERNAL_DESCRIPTION).setMaxDepth (10);
	commentator.getMessageClass (INTERNAL_DESCRIPTION).setMaxDetailLevel (Commentator::LEVEL_UNIMPORTANT);

	ostream &report = commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_DESCRIPTION);
	report << endl << "Black box characteristic polynomial of a matrix over a prime field test suite" << endl;

	RandomDenseStream<Field, DenseVector, NonzeroRandIter<Field> >
		v_stream (F, NonzeroRandIter<Field> (F, Field::RandIter (F)), n, numVectors);
	RandomSparseStream<Field, SparseVector, NonzeroRandIter<Field> >
		A_stream (F, NonzeroRandIter<Field> (F, Field::RandIter (F)), (double) k / (double) n, n, n);

	if (!testNilpotentCharpoly (F, n)) pass = false;
	if (!testRandomCharpoly    (F, iterations, A_stream, v_stream)) pass = false;

	// symmetrizing
	if (!testIdentityCharpoly  (F, n, true)) pass = false;
	//need other tests...

	typedef vector<PID_integer::Element> ZDenseVector;
	typedef SparseMatrix<PID_integer>::Row ZSparseVector;
	typedef pair<vector<size_t>, vector<Field::Element> > SparseVector;
	PID_integer  Z;
	srand (time (NULL));

	commentator.getMessageClass (TIMING_MEASURE).setMaxDepth (10);
	commentator.getMessageClass (INTERNAL_DESCRIPTION).setMaxDepth (10);
	commentator.getMessageClass (INTERNAL_DESCRIPTION).setMaxDetailLevel (Commentator::LEVEL_UNIMPORTANT);

	report << endl << "Black box characteristic polynomial of an integer matrix test suite" << endl;

	RandomDenseStream<PID_integer, ZDenseVector, NonzeroRandIter<PID_integer> >
		zv_stream (Z, NonzeroRandIter<PID_integer> (Z, PID_integer::RandIter (Z)), n, numVectors);
	RandomSparseStream<PID_integer, SparseVector, NonzeroRandIter<PID_integer> >
		zA_stream (Z, NonzeroRandIter<PID_integer> (Z, PID_integer::RandIter (Z)), (double) k / (double) n, n, n);

	//no symmetrizing
	if (!testIdentityCharpoly  (Z, n)) pass = false;
	if (!testNilpotentCharpoly (Z, n)) pass = false;

	//Comment by Z. Wan. Stream doesn't work here
	//if (!testRandomCharpoly    (Z, iterations, zA_stream, zv_stream)) pass = false;

	// symmetrizing
	if (!testIdentityCharpoly  (Z, n, true)) pass = false;
	//need other tests...

	return pass ? 0 : -1;
}
<|endoftext|>


<commit_before>/*******************************************************************************
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2011
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
* "@(#) $Id: bulkDataNTGenSender.cpp,v 1.8 2012/09/06 10:50:30 bjeram Exp $"
*
* who       when      what
* --------  --------  ----------------------------------------------
* bjeram  2011-04-19  created
*/
#include "bulkDataNTSenderFlow.h"
#include <iostream>
#include <ace/Get_Opt.h>
#include <ace/Tokenizer_T.h>

using namespace AcsBulkdata;
using namespace std;

void print_usage(char *argv[]) {
	cout << "Usage: " << argv[0] << " [-s streamName] -f flow1Name[,flow2Name,flow3Name...] [-b data size in bytes] [-p parameter] [-l # of loops]" << endl;
	exit(1);
}

int main(int argc, char *argv[])
{
	char c;
	bool sendData=true;
	bool recreate=true;
	double send_time;
	ACE_Time_Value start_time, elapsed_time;
	char *streamName = "DefaultStream";
	std::string param="defalutParamter";
	unsigned int dataSize=65000;
	unsigned int loop=1;
	list<char *> flowNames;

	// Parse the args
    ACE_Get_Opt get_opts (argc, argv, "f:s:b:p:l:");
    while(( c = get_opts()) != -1 ) {
    	switch(c) {
    	case 'l':
    	{
    		loop = atoi(get_opts.opt_arg());
    		break;
    	}
    	case 'p':
    	{
    		param = get_opts.opt_arg();
    		break;
    	}
    	case 's':
    	{
    		streamName = get_opts.opt_arg();
    		break;
    	}
    	case 'f':
    	{
    		ACE_Tokenizer tok(get_opts.opt_arg());
    		tok.delimiter_replace(',', 0);
    		for(char *p = tok.next(); p; p = tok.next())
    			flowNames.push_back(p);

    		break;
    	}
    	case 'b':
    	{
    		dataSize = atoi(get_opts.opt_arg());
    		break;
    	}
    	default:
    	{
    		print_usage(argv);
    		break;
    	}
    	}
    }//while

    if( flowNames.size() == 0 )
    		print_usage(argv);

	LoggingProxy m_logger(0, 0, 31, 0);
	LoggingProxy::init (&m_logger);
    ACS_CHECK_LOGGER;

    ACS_SHORT_LOG((LM_INFO, "Is new bulk data enabled (ENABLE_BULKDATA_NT) %d", isBulkDataNTEnabled()));
    while(recreate)
    {
    	try
    	{
    		double throuhgput=0;
    		double sumThrouhgput=0;
    		vector<double> 	throughputSums;
    		vector<BulkDataNTSenderFlow*> flows;
    		// first we need a stream
    		BulkDataNTSenderStream senderStream(streamName);

    		// let's create flows
    		list<char *>::iterator it;
    		for(it = flowNames.begin(); it != flowNames.end(); it++) {
    			SenderFlowConfiguration cfg;
    			BulkDataNTSenderFlow *flow = senderStream.createFlow((*it), cfg);
    			flows.push_back(flow);
    		}

    		// print out what we have created
    		std::vector<string> tmpFlowNames = senderStream.getFlowNames();
    		std::cout << "The following " << senderStream.getFlowNumber() << " flow(s) has/have been created:[ ";
    		for(unsigned int i=0;i<tmpFlowNames.size(); i++)
    			std::cout << tmpFlowNames[i] << " ";
    		std::cout << "] on stream: " << streamName << std::endl;

    		unsigned int numOfCreatedFlows = senderStream.getFlowNumber();

    		std::cout << "press ENTER to send data (start/data/stop) to connected receivers ..." << std::endl;
    		getchar();
    		sendData=true;

    		throughputSums.resize(numOfCreatedFlows);

    		while(sendData)
    		{
    			// first startSend
    			for(unsigned int i=0; i<numOfCreatedFlows; i++)
    			{
    				ACS_SHORT_LOG((LM_INFO, "Going to send paramter: '%s' to flow: '%s' to %d receiver(s)", param.c_str(), tmpFlowNames[i].c_str(), flows[i]->getNumberOfReceivers()));
    				flows[i]->startSend((const unsigned char*)param.c_str(), param.size());
    				throughputSums[i]=0.0;
    			}//for
    			sumThrouhgput=0.0;
    			// then sendData
    			unsigned char *data= new unsigned char[dataSize];
    			for (unsigned int i=0; i<dataSize; i++)	data[i]=i;

    			for(unsigned int j=1; j<=loop; j++)
    			{
    				std::cout << "Loop: " << j << " of " << loop << std::endl;
    				for(unsigned int i=0; i<numOfCreatedFlows; i++)
    				{
    					ACS_SHORT_LOG((LM_INFO, "Going to send [%d/%d]: %d Bytes of data to flow: '%s' to %d receiver(s)", j, loop, dataSize, tmpFlowNames[i].c_str(), flows[i]->getNumberOfReceivers()));
    					start_time = ACE_OS::gettimeofday();
    					flows[i]->sendData(data, dataSize);
    					elapsed_time = ACE_OS::gettimeofday() - start_time;
    					send_time = (elapsed_time.sec()+( elapsed_time.usec() / 1000000. ));
    					throuhgput = (dataSize/(1024.0*1024.0))/send_time;
    					ACS_SHORT_LOG((LM_INFO, "Transfer rate for flow '%s': %f MBytes/sec",
    							tmpFlowNames[i].c_str(), throuhgput));
    					sumThrouhgput+=throuhgput;
    					throughputSums[i]+=throuhgput;
    				}//for i
    			}//for j

    			// and stopSend
    			for(unsigned int i=0; i<numOfCreatedFlows; i++)
    			{
    				ACS_SHORT_LOG((LM_INFO, "Average transfer rate for flow '%s': %f MBytes/sec",
    										tmpFlowNames[i].c_str(), throughputSums[i]/loop));
    				ACS_SHORT_LOG((LM_INFO, "Going to send stop to flow: '%s' to %d receiver(s)",
    										tmpFlowNames[i].c_str(), flows[i]->getNumberOfReceivers()));
    				flows[i]->stopSend();
    			}//for

    			ACS_SHORT_LOG((LM_INFO, "Average transfer rate for all the flow(s): %f MBytes/sec",
    			    					sumThrouhgput/(loop*numOfCreatedFlows)));

    			std::cout << "press 'r' for re-send data, 'c' for re-create stream+flow(s), and any other key for exit + ENTER" << std::endl;
    			int c=getchar();
    			switch(c)
    			{
    			case 'r':
    			{
    				getchar();
    				sendData=true;
    				break;
    			}
    			case 'c':
    			{
    				getchar();
    				sendData=false;
    				recreate=true;
    				break;
    			}
    			default:
    			{
    				sendData=false;
    				recreate=false;
    				break;
    			}
    			}//switch
    		}//while(sendData)

    	}catch(ACSErr::ACSbaseExImpl &ex)
    	{
    		ex.log();
    	}

    }//while(recreate)
    m_logger.flush();
};//main
<commit_msg>added -n option for non-interactive mode<commit_after>/*******************************************************************************
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2011
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
* "@(#) $Id: bulkDataNTGenSender.cpp,v 1.9 2012/10/23 07:32:42 bjeram Exp $"
*
* who       when      what
* --------  --------  ----------------------------------------------
* bjeram  2011-04-19  created
*/
#include "bulkDataNTSenderFlow.h"
#include <iostream>
#include <ace/Get_Opt.h>
#include <ace/Tokenizer_T.h>

using namespace AcsBulkdata;
using namespace std;

void print_usage(char *argv[]) {
	cout << "Usage: " << argv[0] << " [-s streamName] -f flow1Name[,flow2Name,flow3Name...] [-b data size in bytes] [-p parameter] [-l # of loops] [-n no wait for a key]" << endl;
	exit(1);
}

int main(int argc, char *argv[])
{
	char c;
	bool sendData=true;
	bool recreate=true;
	bool waitForKey=true;
	double send_time;
	ACE_Time_Value start_time, elapsed_time;
	char *streamName = "DefaultStream";
	std::string param="defalutParamter";
	unsigned int dataSize=65000;
	unsigned int loop=1;
	list<char *> flowNames;

	// Parse the args
    ACE_Get_Opt get_opts (argc, argv, "f:s:b:p:l:n");
    while(( c = get_opts()) != -1 ) {
    	switch(c) {
    	case 'l':
    	{
    		loop = atoi(get_opts.opt_arg());
    		break;
    	}
    	case 'p':
    	{
    		param = get_opts.opt_arg();
    		break;
    	}
    	case 's':
    	{
    		streamName = get_opts.opt_arg();
    		break;
    	}
    	case 'f':
    	{
    		ACE_Tokenizer tok(get_opts.opt_arg());
    		tok.delimiter_replace(',', 0);
    		for(char *p = tok.next(); p; p = tok.next())
    			flowNames.push_back(p);

    		break;
    	}
    	case 'b':
    	{
    		dataSize = atoi(get_opts.opt_arg());
    		break;
    	}
    	case 'n':
    	{
    		waitForKey = false;
    		break;
    	}
    	default:
    	{
    		print_usage(argv);
    		break;
    	}
    	}
    }//while

    if( flowNames.size() == 0 )
    		print_usage(argv);

	LoggingProxy m_logger(0, 0, 31, 0);
	LoggingProxy::init (&m_logger);
    ACS_CHECK_LOGGER;

    ACS_SHORT_LOG((LM_INFO, "Is new bulk data enabled (ENABLE_BULKDATA_NT) %d", isBulkDataNTEnabled()));
    while(recreate)
    {
    	try
    	{
    		double throuhgput=0;
    		double sumThrouhgput=0;
    		vector<double> 	throughputSums;
    		vector<BulkDataNTSenderFlow*> flows;
    		// first we need a stream
    		BulkDataNTSenderStream senderStream(streamName);

    		// let's create flows
    		list<char *>::iterator it;
    		for(it = flowNames.begin(); it != flowNames.end(); it++) {
    			SenderFlowConfiguration cfg;
    			BulkDataNTSenderFlow *flow = senderStream.createFlow((*it), cfg);
    			flows.push_back(flow);
    		}

    		// print out what we have created
    		std::vector<string> tmpFlowNames = senderStream.getFlowNames();
    		std::cout << "The following " << senderStream.getFlowNumber() << " flow(s) has/have been created:[ ";
    		for(unsigned int i=0;i<tmpFlowNames.size(); i++)
    			std::cout << tmpFlowNames[i] << " ";
    		std::cout << "] on stream: " << streamName << std::endl;

    		unsigned int numOfCreatedFlows = senderStream.getFlowNumber();

    		std::cout << "press ENTER to send data (start/data/stop) to connected receivers ..." << std::endl;
    		if (waitForKey) getchar();
    		sendData=true;

    		throughputSums.resize(numOfCreatedFlows);

    		while(sendData)
    		{
    			// first startSend
    			for(unsigned int i=0; i<numOfCreatedFlows; i++)
    			{
    				ACS_SHORT_LOG((LM_INFO, "Going to send paramter: '%s' to flow: '%s' to %d receiver(s)", param.c_str(), tmpFlowNames[i].c_str(), flows[i]->getNumberOfReceivers()));
    				flows[i]->startSend((const unsigned char*)param.c_str(), param.size());
    				throughputSums[i]=0.0;
    			}//for
    			sumThrouhgput=0.0;
    			// then sendData
    			unsigned char *data= new unsigned char[dataSize];
    			for (unsigned int i=0; i<dataSize; i++)	data[i]=i;

    			for(unsigned int j=1; j<=loop; j++)
    			{
    				std::cout << "Loop: " << j << " of " << loop << std::endl;
    				for(unsigned int i=0; i<numOfCreatedFlows; i++)
    				{
    					ACS_SHORT_LOG((LM_INFO, "Going to send [%d/%d]: %d Bytes of data to flow: '%s' to %d receiver(s)", j, loop, dataSize, tmpFlowNames[i].c_str(), flows[i]->getNumberOfReceivers()));
    					start_time = ACE_OS::gettimeofday();
    					flows[i]->sendData(data, dataSize);
    					elapsed_time = ACE_OS::gettimeofday() - start_time;
    					send_time = (elapsed_time.sec()+( elapsed_time.usec() / 1000000. ));
    					throuhgput = (dataSize/(1024.0*1024.0))/send_time;
    					ACS_SHORT_LOG((LM_INFO, "Transfer rate for flow '%s': %f MBytes/sec",
    							tmpFlowNames[i].c_str(), throuhgput));
    					sumThrouhgput+=throuhgput;
    					throughputSums[i]+=throuhgput;
    				}//for i
    			}//for j

    			// and stopSend
    			for(unsigned int i=0; i<numOfCreatedFlows; i++)
    			{
    				ACS_SHORT_LOG((LM_INFO, "Average transfer rate for flow '%s': %f MBytes/sec",
    										tmpFlowNames[i].c_str(), throughputSums[i]/loop));
    				ACS_SHORT_LOG((LM_INFO, "Going to send stop to flow: '%s' to %d receiver(s)",
    										tmpFlowNames[i].c_str(), flows[i]->getNumberOfReceivers()));
    				flows[i]->stopSend();
    			}//for

    			ACS_SHORT_LOG((LM_INFO, "Average transfer rate for all the flow(s): %f MBytes/sec",
    			    					sumThrouhgput/(loop*numOfCreatedFlows)));

    			if (!waitForKey) //we exit both loops
    				{
    				recreate=false;
    				break;
    				}

    			std::cout << "press 'r' for re-send data, 'c' for re-create stream+flow(s), and any other key for exit + ENTER" << std::endl;
    			int c=getchar();
    			switch(c)
    			{
    			case 'r':
    			{
    				getchar();
    				sendData=true;
    				break;
    			}
    			case 'c':
    			{
    				getchar();
    				sendData=false;
    				recreate=true;
    				break;
    			}
    			default:
    			{
    				sendData=false;
    				recreate=false;
    				break;
    			}
    			}//switch
    		}//while(sendData)

    	}catch(ACSErr::ACSbaseExImpl &ex)
    	{
    		ex.log();
    	}

    }//while(recreate)
    m_logger.flush();
};//main
<|endoftext|>


<commit_before><commit_msg>fix syntax of transactions in SQLite wrapper code<commit_after><|endoftext|>


<commit_before><commit_msg>Add robust SPD to smoothing.<commit_after><|endoftext|>


<commit_before>// Copyright 2005-2016 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#include "../mumble_plugin_win32_x86.h" // Include standard plugin header.
#include "../mumble_plugin_utils.h" // Include plugin header for special functions, like "escape".

static int fetch(float *avatar_pos, float *avatar_front, float *avatar_top, float *camera_pos, float *camera_front, float *camera_top, std::string &context, std::wstring &identity) {
	for (int i=0;i<3;i++) {
		avatar_pos[i] = avatar_front[i] = avatar_top[i] = camera_pos[i] = camera_front[i] = camera_top[i] = 0.0f;
	}

	// Boolean values to check if game addresses retrieval is successful and if player is in-game
	bool ok, state, spec;
	// Create containers to stuff our raw data into, so we can convert it to Mumble's coordinate system
	float avatar_pos_corrector[3], camera_pos_corrector[3], viewHor, viewVer;
	// Char values for extra features
	char host[22], map[30];
	// Team
	BYTE team;

	// Peekproc and assign game addresses to our containers, so we can retrieve positional data
	ok = peekProc(pModule + 0x0188248, &state, 1) && // Magical state value: 1 when in-game and 0 when in main menu.
			peekProc(pModule + 0x1041C68, &spec, 1) && // Spectator state value: 1 when spectating and 0 when playing.
			peekProc(pModule + 0x0EB8950, avatar_pos_corrector, 12) && // Avatar Position values (Z, X and Y, respectively).
			peekProc(pModule + 0x0E6093C, camera_pos_corrector, 12) && // Camera Position values (Z, X and Y, respectively).
			peekProc(pModule + 0x106CE04, &viewHor, 4) && // Changes in a range from 180 to -180 when moving the view to left/right.
			peekProc(pModule + 0x106CE00, &viewVer, 4) && // Changes in a range from 87.890625 (looking down) to -87.890625 (looking up).
			peekProc(pModule + 0x0E4A638, host) && // Server value: "IP:Port" when in a remote server, "loopback" when on a local server.
			peekProc(pModule + 0x12DE8D8, map) && // Map name.
			peekProc(pModule + 0x106CE6C, team); // Team value: 0 when in a FFA game (no team); 1 when in Red team; 2 when in Blue team; 3 when in Spectators.

	if (! ok) {
		return false;
	}

	if (! state) { // If not in-game
		context.clear(); // Clear context
		identity.clear(); // Clear identity

		return true; // This results in all vectors beeing zero which tells Mumble to ignore them.
	}

	if (state && spec) { // If in-game as spectator
		// Set to 0 avatar and camera values.
		for (int i=0;i<3;i++) {
			avatar_pos[i] = avatar_front[i] = avatar_top[i] = camera_pos[i] =  camera_front[i] = camera_top[i] = 0.0f;
		}
		// Set team to SPEC.
		std::wostringstream oidentity;
		oidentity << "{\"team\": \"SPEC\"}";
		identity = oidentity.str();

		return true; // This results in all vectors beeing zero which tells Mumble to ignore them.
	}

	// Begin context
	host[sizeof(host)-1] = 0; // NUL terminate queried C strings. We do this to ensure the strings from the game are NUL terminated. They should be already, but we can't take any chances.
	escape(host);
	std::ostringstream ocontext;
	ocontext << " {";
	if (strcmp(host, "") != 0 && strstr(host, "loopback") == NULL) { // Only include host (IP:Port) if it is not empty and does not include the string "loopback" (which means it's a local server).
		ocontext << "\"Host\": \"" << host << "\""; // Set host address in identity.
	} else {
		ocontext << "\"Host\": null";
	}

	ocontext << "}";
	context = ocontext.str();
	// End context

	// Begin identity
	std::wostringstream oidentity;
	oidentity << "{";

	// Map
	map[sizeof(map)-1] = 0; // NUL terminate queried C strings. We do this to ensure the strings from the game are NUL terminated. They should be already, but we can't take any chances.
	escape(map);
	if (strcmp(map, "") != 0) {
		oidentity << std::endl;
		oidentity << "\"Map\": \"" << map << "\","; // Set map name in identity.
	} else {
		oidentity << std::endl << "\"Map\": null,";
	}

	// Team
	if (team >= 0 && team <= 3) {
		if (team == 0)
			oidentity << std::endl << "\"Team\": \"FFA\""; // If team value is 0, set "FFA" as team in identity.
		else if (team == 1)
			oidentity << std::endl << "\"Team\": \"Red\""; // If team value is 1, set "Red" as team in identity.
		else if (team == 2)
			oidentity << std::endl << "\"Team\": \"Blue\""; // If team value is 2, set "Blue" as team in identity.
		else if (team == 3)
			oidentity << std::endl << "\"Team\": \"Spectators\""; // If team value is 3, set "Spectators" as team in identity.
	} else {
		oidentity << std::endl << "\"Team\": null";
	}

	oidentity << std::endl << "}";
	identity = oidentity.str();
	// End identity

	/*
	Mumble | Game
	X      | Y
	Y      | Z
	Z      | X
	*/
	avatar_pos[0] = avatar_pos_corrector[1];
	avatar_pos[1] = avatar_pos_corrector[2];
	avatar_pos[2] = avatar_pos_corrector[0];

	camera_pos[0] = camera_pos_corrector[1];
	camera_pos[1] = camera_pos_corrector[2];
	camera_pos[2] = camera_pos_corrector[0];

	// Calculate view unit vector
	viewVer *= static_cast<float>(M_PI / 180.0f);
	viewHor *= static_cast<float>(M_PI / 180.0f);

	avatar_front[0] = camera_front[0] = cos(viewVer) * cos(viewHor);
	avatar_front[1] = camera_front[1] = -sin(viewVer);
	avatar_front[2] = camera_front[2] = cos(viewVer) * sin(viewHor);

	avatar_top[2] = camera_top[2] = -1; // This tells Mumble to automatically calculate top vector using front vector.

	// Scale to meters
	for (int i=0;i<3;i++) {
		avatar_pos[i]/=70.0f;
		camera_pos[i]/=70.0f;
	}

	return true;
}

static int trylock(const std::multimap<std::wstring, unsigned long long int> &pids) {

	if (! initialize(pids, L"quakelive_steam.exe")) { // Retrieve game executable's memory address
		return false;
	}

	// Check if we can get meaningful data from it
	float apos[3], afront[3], atop[3], cpos[3], cfront[3], ctop[3];
	std::wstring sidentity;
	std::string scontext;

	if (fetch(apos, afront, atop, cpos, cfront, ctop, scontext, sidentity)) {
		return true;
	} else {
		generic_unlock();
		return false;
	}
}

static const std::wstring longdesc() {
	return std::wstring(L"Supports Quake Live version 1069 with context and identity support."); // Plugin long description
}

static std::wstring description(L"Quake Live (v1069)"); // Plugin short description
static std::wstring shortname(L"Quake Live"); // Plugin short name

static int trylock1() {
	return trylock(std::multimap<std::wstring, unsigned long long int>());
}

static MumblePlugin qlplug = {
	MUMBLE_PLUGIN_MAGIC,
	description,
	shortname,
	NULL,
	NULL,
	trylock1,
	generic_unlock,
	longdesc,
	fetch
};

static MumblePlugin2 qlplug2 = {
	MUMBLE_PLUGIN_MAGIC_2,
	MUMBLE_PLUGIN_VERSION,
	trylock
};

extern "C" __declspec(dllexport) MumblePlugin *getMumblePlugin() {
	return &qlplug;
}

extern "C" __declspec(dllexport) MumblePlugin2 *getMumblePlugin2() {
	return &qlplug2;
}
<commit_msg>plugins/ql: Native front and top vectors<commit_after>// Copyright 2005-2016 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#include "../mumble_plugin_win32_x86.h" // Include standard plugin header.
#include "../mumble_plugin_utils.h" // Include plugin header for special functions, like "escape".

static int fetch(float *avatar_pos, float *avatar_front, float *avatar_top, float *camera_pos, float *camera_front, float *camera_top, std::string &context, std::wstring &identity) {
	for (int i=0;i<3;i++) {
		avatar_pos[i] = avatar_front[i] = avatar_top[i] = camera_pos[i] = camera_front[i] = camera_top[i] = 0.0f;
	}

	// Boolean values to check if game addresses retrieval is successful and if player is in-game
	bool ok, state, spec;
	// Create containers to stuff our raw data into, so we can convert it to Mumble's coordinate system
	float avatar_pos_corrector[3], camera_pos_corrector[3], avatar_front_corrector[3], avatar_top_corrector[3];
	// Char values for extra features
	char host[22], servername[50], map[30];
	// Team
	BYTE team;

	// Peekproc and assign game addresses to our containers, so we can retrieve positional data
	ok = peekProc(pModule + 0x0188248, &state, 1) && // Magical state value: 1 when in-game and 0 when in main menu.
			peekProc(pModule + 0x1041C68, &spec, 1) && // Spectator state value: 1 when spectating and 0 when playing.
			peekProc(pModule + 0x0EB8950, avatar_pos_corrector, 12) && // Avatar Position values (X, Z and Y, respectively).
			peekProc(pModule + 0x0E6093C, camera_pos_corrector, 12) && // Camera Position values (X, Z and Y, respectively).
			peekProc(pModule + 0x0EC5B50, avatar_front_corrector, 12) && // Avatar front values (X, Z and Y, respectively).
			peekProc(pModule + 0x0EC5B68, avatar_top_corrector, 12) && // Avatar top values (X, Z and Y, respectively).
			peekProc(pModule + 0x0E4A638, host) && // Server value: "IP:Port" when in a remote server, "loopback" when on a local server.
			peekProc(pModule + 0x106E24B, servername) && // Server name.
			peekProc(pModule + 0x12DE8D8, map) && // Map name.
			peekProc(pModule + 0x106CE6C, team); // Team value: 0 when in a FFA game (no team); 1 when in Red team; 2 when in Blue team; 3 when in Spectators.

	if (! ok) {
		return false;
	}

	if (! state) { // If not in-game
		context.clear(); // Clear context
		identity.clear(); // Clear identity

		return true; // This results in all vectors beeing zero which tells Mumble to ignore them.
	}

	if (state && spec) { // If in-game as spectator
		// Set to 0 avatar and camera values.
		for (int i=0;i<3;i++) {
			avatar_pos[i] = avatar_front[i] = avatar_top[i] = camera_pos[i] =  camera_front[i] = camera_top[i] = 0.0f;
		}
		// Set team to SPEC.
		std::wostringstream oidentity;
		oidentity << "{\"team\": \"SPEC\"}";
		identity = oidentity.str();

		return true; // This results in all vectors beeing zero which tells Mumble to ignore them.
	}

	// Begin context
	host[sizeof(host)-1] = 0; // NUL terminate queried C strings. We do this to ensure the strings from the game are NUL terminated. They should be already, but we can't take any chances.
	escape(host);
	std::ostringstream ocontext;
	ocontext << " {";
	if (strcmp(host, "") != 0 && strstr(host, "loopback") == NULL) { // Only include host (IP:Port) if it is not empty and does not include the string "loopback" (which means it's a local server).
		ocontext << "\"Host\": \"" << host << "\""; // Set host address in identity.
	} else {
		ocontext << "\"Host\": null";
	}

	ocontext << "}";
	context = ocontext.str();
	// End context

	// Begin identity
	std::wostringstream oidentity;
	oidentity << "{";

	// Map
	map[sizeof(map)-1] = 0; // NUL terminate queried C strings. We do this to ensure the strings from the game are NUL terminated. They should be already, but we can't take any chances.
	escape(map);
	if (strcmp(map, "") != 0) {
		oidentity << std::endl;
		oidentity << "\"Map\": \"" << map << "\","; // Set map name in identity.
	} else {
		oidentity << std::endl << "\"Map\": null,";
	}

	// Team
	if (team >= 0 && team <= 3) {
		if (team == 0)
			oidentity << std::endl << "\"Team\": \"FFA\""; // If team value is 0, set "FFA" as team in identity.
		if (team == 1)
			oidentity << std::endl << "\"Team\": \"Red\""; // If team value is 1, set "Red" as team in identity.
		if (team == 2)
			oidentity << std::endl << "\"Team\": \"Blue\""; // If team value is 2, set "Blue" as team in identity.
		if (team == 3)
			oidentity << std::endl << "\"Team\": \"Spectators\""; // If team value is 3, set "Spectators" as team in identity.
	} else {
		oidentity << std::endl << "\"Team\": null";
	}

	oidentity << std::endl << "}";
	identity = oidentity.str();
	// End identity

	/*
	Mumble | Game
	X      | X
	Y      | Z
	Z      | Y
	*/
	avatar_pos[0] = avatar_pos_corrector[0];
	avatar_pos[1] = avatar_pos_corrector[2];
	avatar_pos[2] = avatar_pos_corrector[1];

	camera_pos[0] = camera_pos_corrector[0];
	camera_pos[1] = camera_pos_corrector[2];
	camera_pos[2] = camera_pos_corrector[1];

	avatar_front[0] = avatar_front_corrector[0];
	avatar_front[1] = avatar_front_corrector[2];
	avatar_front[2] = avatar_front_corrector[1];

	avatar_top[0] = avatar_top_corrector[0];
	avatar_top[1] = avatar_top_corrector[2];
	avatar_top[2] = avatar_top_corrector[1];

	// Scale to meters
	for (int i=0;i<3;i++) {
		camera_front[i] = avatar_front[i];
		camera_top[i] = avatar_top[i];
		avatar_pos[i]/=70.0f;
		camera_pos[i]/=70.0f;
	}

	return true;
}

static int trylock(const std::multimap<std::wstring, unsigned long long int> &pids) {

	if (! initialize(pids, L"quakelive_steam.exe")) { // Retrieve game executable's memory address
		return false;
	}

	// Check if we can get meaningful data from it
	float apos[3], afront[3], atop[3], cpos[3], cfront[3], ctop[3];
	std::wstring sidentity;
	std::string scontext;

	if (fetch(apos, afront, atop, cpos, cfront, ctop, scontext, sidentity)) {
		return true;
	} else {
		generic_unlock();
		return false;
	}
}

static const std::wstring longdesc() {
	return std::wstring(L"Supports Quake Live version 1069 with context and identity support."); // Plugin long description
}

static std::wstring description(L"Quake Live (v1069)"); // Plugin short description
static std::wstring shortname(L"Quake Live"); // Plugin short name

static int trylock1() {
	return trylock(std::multimap<std::wstring, unsigned long long int>());
}

static MumblePlugin qlplug = {
	MUMBLE_PLUGIN_MAGIC,
	description,
	shortname,
	NULL,
	NULL,
	trylock1,
	generic_unlock,
	longdesc,
	fetch
};

static MumblePlugin2 qlplug2 = {
	MUMBLE_PLUGIN_MAGIC_2,
	MUMBLE_PLUGIN_VERSION,
	trylock
};

extern "C" __declspec(dllexport) MumblePlugin *getMumblePlugin() {
	return &qlplug;
}

extern "C" __declspec(dllexport) MumblePlugin2 *getMumblePlugin2() {
	return &qlplug2;
}
<|endoftext|>