<commit_before>#
# Copyright 2021 Google LLC
#
# Licensed 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
#
#     https://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 <fcntl.h>

#include <cstdint>
#include <ostream>
#include <string>
#include <vector>

#include "schedulers/netPreemptDelay/cgroup_watcher.h"
#include "schedulers/netPreemptDelay/net_scheduler.h"
#include "absl/debugging/symbolize.h"
#include "absl/flags/parse.h"
#include "lib/agent.h"
#include "lib/channel.h"
#include "lib/enclave.h"
#include "lib/topology.h"

#include <filesystem>
namespace fs = std::filesystem;

ABSL_FLAG(int32_t, globalcpu, -1,
          "Global cpu. If -1, then defaults to <firstcpu>)");
ABSL_FLAG(std::string, ghost_cpus, "1-5", "cpulist");
ABSL_FLAG(bool, enforce_affinity, true, "Enforce affinity requests");
ABSL_FLAG(absl::Duration, cgroup_period, absl::Seconds(1),
          "The period of cgroup scrapes");

namespace ghost {

void ParseNetConfig(NetConfig* config) {
  int globalcpu = absl::GetFlag(FLAGS_globalcpu);
  bool enforce_affinity = absl::GetFlag(FLAGS_enforce_affinity);
  CpuList ghost_cpus =
      ghost::MachineTopology()->ParseCpuStr(absl::GetFlag(FLAGS_ghost_cpus));
  CHECK_GT(ghost_cpus.Size(), 1);

  if (globalcpu < 0) {
    CHECK_EQ(globalcpu, -1);
    globalcpu = ghost_cpus.GetNthCpu(0).id();
    absl::SetFlag(&FLAGS_globalcpu, globalcpu);
  }

  CHECK(ghost_cpus.IsSet(globalcpu));

  Topology* topology = MachineTopology();
  config->topology_ = topology;
  config->cpus_ = ghost_cpus;
  config->global_cpu_ = topology->cpu(globalcpu);
  config->enforce_affinity_mask_ = enforce_affinity;

  printf("Dumping config->cpus_ bitmap\n");
  std::cout << config->cpus_ << std::endl;
  for (const Cpu cpu : config->cpus_)
    std::cout << cpu << ",";
  std::cout << std::endl;
}

// Puts the calling thread to sleep for a duration of `duration`. Wakes up
// and returns immediately when a signal is received. If `duration` is 0 or
// negative, returns immediately.
//
// We implement our own `SleepFor` function rather than use `absl::SleepFor`
// because Abseil's function does not immediately return when a signal is
// received. We need to return immediately when SIGINT is received so that the
// process can quickly exit.
void SleepFor(absl::Duration duration) {
  // `kMaxSleep` is the maximum duration a thread can sleep for at once.
  constexpr absl::Duration kMaxSleep =
      absl::Seconds(std::numeric_limits<time_t>::max());
  while (duration > absl::ZeroDuration()) {
    absl::Duration to_sleep = std::min(duration, kMaxSleep);

    struct timespec sleep_time = absl::ToTimespec(to_sleep);
    int ret = nanosleep(&sleep_time, &sleep_time);
    if (ret == -1) {
      CHECK_EQ(errno, EINTR);
      // We received a signal, so return immediately.
      return;
    }
    CHECK_EQ(ret, 0);
    duration -= to_sleep;
  }
}

}  // namespace ghost

int main(int argc, char* argv[]) {
  ghost::Notification exit;

  absl::InitializeSymbolizer(argv[0]);
  absl::ParseCommandLine(argc, argv);
  ghost::NetConfig config;
  ghost::ParseNetConfig(&config);

  printf("Core map\n");

  int n = 0;
  for (const ghost::Cpu& c : config.topology_->all_cores()) {
    printf("( ");
    for (const ghost::Cpu& s : c.siblings()) printf("%2d ", s.id());
    printf(")%c", ++n % 8 == 0 ? '\n' : '\t');
  }
  printf("\n");

  printf("L3 siblings map\n");
  n = 0;
  for (const ghost::Cpu& c : config.topology_->all_cores()) {
    printf("( ");
    for (const ghost::Cpu& s : c.l3_siblings()) printf("%2d ", s.id());
    printf(")%c", ++n % 8 == 0 ? '\n' : '\t');
  }
  printf("\n");

  printf("Initializing...\n");

  // Using new so we can destruct the object before printing Done
  auto uap =
      new ghost::AgentProcess<ghost::FullNetAgent<ghost::LocalEnclave>,
                              ghost::NetConfig>(config);

  ghost::Ghost::InitCore();
  printf("Initialization complete, ghOSt active\n");
  fflush(stdout);

  // In the future we'll let the agent know which enclave to use via cmdline.
  // Until then look for the first one that's available.
  ghost::GhostThread::SetGlobalEnclaveCtlFdOnce();

  // TODO(brho): this is racy - uap could be deleted already
  ghost::GhostSignals::AddHandler(SIGINT, [&exit](int) {
    static bool first = true;  // We only modify the first SIGINT.

    if (first) {
      first = false;
      exit.Notify();
      return false;  // We'll exit on subsequent SIGTERMs.
    }
    return true;
  });

  // TODO(brho): this is racy - uap could be deleted already
  ghost::GhostSignals::AddHandler(SIGUSR1, [uap](int) {
    uap->Rpc(ghost::NetScheduler::kDebugRunqueue);
    return false;
  });

  const absl::Duration sleep_duration = absl::GetFlag(FLAGS_cgroup_period);
  // The agent may have been started from a cgroup within a ghost-enabled cgroup
  // hierarchy. In that case ScrapeCgroups needs to skip the agent's container.
  //const std::string cwd = file_util::LinuxFileOps::GetCWD();
  const std::string cwd = fs::current_path();

  // We use a cgroup mygroup1 and move the DPDK threads to this cgroup.
  // We also get all the docker threads by scraping the docker cgroup.
  absl::flat_hash_map<std::string, std::string> containers_to_tasks_rules;
  containers_to_tasks_rules["mygroup1"] = "*";
  containers_to_tasks_rules["docker"] = "memcached";

  // Keep scraping cgroups periodically until exit notification.
  while (!exit.HasBeenNotified()) {
    if (int moved = ghost::cgroup_watcher::ScrapeCgroups(cwd,
                                                     containers_to_tasks_rules);
        moved != 0) {
      printf("Moved %d tasks into ghost\n", moved);
    }
    ghost::SleepFor(sleep_duration);
  }

  delete uap;

  printf("Done!\n");
  return 0;
}
<commit_msg>Update agent_net.cc<commit_after>/*

Copyright 2021 Google LLC

Licensed 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

 https://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 <fcntl.h>

#include <cstdint>
#include <ostream>
#include <string>
#include <vector>

#include "schedulers/netPreemptDelay/cgroup_watcher.h"
#include "schedulers/netPreemptDelay/net_scheduler.h"
#include "absl/debugging/symbolize.h"
#include "absl/flags/parse.h"
#include "lib/agent.h"
#include "lib/channel.h"
#include "lib/enclave.h"
#include "lib/topology.h"

#include <filesystem>
namespace fs = std::filesystem;

ABSL_FLAG(int32_t, globalcpu, -1,
          "Global cpu. If -1, then defaults to <firstcpu>)");
ABSL_FLAG(std::string, ghost_cpus, "1-5", "cpulist");
ABSL_FLAG(bool, enforce_affinity, true, "Enforce affinity requests");
ABSL_FLAG(absl::Duration, cgroup_period, absl::Seconds(1),
          "The period of cgroup scrapes");

namespace ghost {

void ParseNetConfig(NetConfig* config) {
  int globalcpu = absl::GetFlag(FLAGS_globalcpu);
  bool enforce_affinity = absl::GetFlag(FLAGS_enforce_affinity);
  CpuList ghost_cpus =
      ghost::MachineTopology()->ParseCpuStr(absl::GetFlag(FLAGS_ghost_cpus));
  CHECK_GT(ghost_cpus.Size(), 1);

  if (globalcpu < 0) {
    CHECK_EQ(globalcpu, -1);
    globalcpu = ghost_cpus.GetNthCpu(0).id();
    absl::SetFlag(&FLAGS_globalcpu, globalcpu);
  }

  CHECK(ghost_cpus.IsSet(globalcpu));

  Topology* topology = MachineTopology();
  config->topology_ = topology;
  config->cpus_ = ghost_cpus;
  config->global_cpu_ = topology->cpu(globalcpu);
  config->enforce_affinity_mask_ = enforce_affinity;

  printf("Dumping config->cpus_ bitmap\n");
  std::cout << config->cpus_ << std::endl;
  for (const Cpu cpu : config->cpus_)
    std::cout << cpu << ",";
  std::cout << std::endl;
}

// Puts the calling thread to sleep for a duration of `duration`. Wakes up
// and returns immediately when a signal is received. If `duration` is 0 or
// negative, returns immediately.
//
// We implement our own `SleepFor` function rather than use `absl::SleepFor`
// because Abseil's function does not immediately return when a signal is
// received. We need to return immediately when SIGINT is received so that the
// process can quickly exit.
void SleepFor(absl::Duration duration) {
  // `kMaxSleep` is the maximum duration a thread can sleep for at once.
  constexpr absl::Duration kMaxSleep =
      absl::Seconds(std::numeric_limits<time_t>::max());
  while (duration > absl::ZeroDuration()) {
    absl::Duration to_sleep = std::min(duration, kMaxSleep);

    struct timespec sleep_time = absl::ToTimespec(to_sleep);
    int ret = nanosleep(&sleep_time, &sleep_time);
    if (ret == -1) {
      CHECK_EQ(errno, EINTR);
      // We received a signal, so return immediately.
      return;
    }
    CHECK_EQ(ret, 0);
    duration -= to_sleep;
  }
}

}  // namespace ghost

int main(int argc, char* argv[]) {
  ghost::Notification exit;

  absl::InitializeSymbolizer(argv[0]);
  absl::ParseCommandLine(argc, argv);
  ghost::NetConfig config;
  ghost::ParseNetConfig(&config);

  printf("Core map\n");

  int n = 0;
  for (const ghost::Cpu& c : config.topology_->all_cores()) {
    printf("( ");
    for (const ghost::Cpu& s : c.siblings()) printf("%2d ", s.id());
    printf(")%c", ++n % 8 == 0 ? '\n' : '\t');
  }
  printf("\n");

  printf("L3 siblings map\n");
  n = 0;
  for (const ghost::Cpu& c : config.topology_->all_cores()) {
    printf("( ");
    for (const ghost::Cpu& s : c.l3_siblings()) printf("%2d ", s.id());
    printf(")%c", ++n % 8 == 0 ? '\n' : '\t');
  }
  printf("\n");

  printf("Initializing...\n");

  // Using new so we can destruct the object before printing Done
  auto uap =
      new ghost::AgentProcess<ghost::FullNetAgent<ghost::LocalEnclave>,
                              ghost::NetConfig>(config);

  ghost::Ghost::InitCore();
  printf("Initialization complete, ghOSt active\n");
  fflush(stdout);

  // In the future we'll let the agent know which enclave to use via cmdline.
  // Until then look for the first one that's available.
  ghost::GhostThread::SetGlobalEnclaveCtlFdOnce();

  // TODO(brho): this is racy - uap could be deleted already
  ghost::GhostSignals::AddHandler(SIGINT, [&exit](int) {
    static bool first = true;  // We only modify the first SIGINT.

    if (first) {
      first = false;
      exit.Notify();
      return false;  // We'll exit on subsequent SIGTERMs.
    }
    return true;
  });

  // TODO(brho): this is racy - uap could be deleted already
  ghost::GhostSignals::AddHandler(SIGUSR1, [uap](int) {
    uap->Rpc(ghost::NetScheduler::kDebugRunqueue);
    return false;
  });

  const absl::Duration sleep_duration = absl::GetFlag(FLAGS_cgroup_period);
  // The agent may have been started from a cgroup within a ghost-enabled cgroup
  // hierarchy. In that case ScrapeCgroups needs to skip the agent's container.
  //const std::string cwd = file_util::LinuxFileOps::GetCWD();
  const std::string cwd = fs::current_path();

  // We use a cgroup mygroup1 and move the DPDK threads to this cgroup.
  // We also get all the docker threads by scraping the docker cgroup.
  absl::flat_hash_map<std::string, std::string> containers_to_tasks_rules;
  containers_to_tasks_rules["mygroup1"] = "*";
  containers_to_tasks_rules["docker"] = "memcached";

  // Keep scraping cgroups periodically until exit notification.
  while (!exit.HasBeenNotified()) {
    if (int moved = ghost::cgroup_watcher::ScrapeCgroups(cwd,
                                                     containers_to_tasks_rules);
        moved != 0) {
      printf("Moved %d tasks into ghost\n", moved);
    }
    ghost::SleepFor(sleep_duration);
  }

  delete uap;

  printf("Done!\n");
  return 0;
}
<|endoftext|>


<commit_before>#ifndef HEADER_GUARD_CHANGE_H
#define HEADER_GUARD_CHANGE_H

#include <boost/optional.hpp>
#include <functional>
#include <string>
#include <vector>
#include <memory>

namespace vick {

class contents;

/*!
 * \file change.hh
 *
 * \brief Defines the change class and the undo_change(),
 * redo_change(), and reapply_change() functions.
 */

/*!
 * \class change change.hh "../../../src/change.hh"
 * \brief Represents a change from one \c contents to another
 *
 * The change class represents a change from one \c contents to
 * another.  It is basically a
 * \code{.cpp}
 * std::pair < std::function<void(contents&)>, std::function<void(contents&)> >
 * \endcode
 * but allows you to link two changes together using
 * \code{.cpp}
 * operator>>
 * \endcode
 *
 * You can link them together and put them in random places in the
 * undo tree/list.
 *
 * \see contents
 */
struct change {
    virtual ~change()
    {
    }

    /*!
     * \brief Return true if you edit in any way anything but the x and y
     * coordinate
     */
    virtual bool is_overriding() = 0;

    /*!
     * \brief Undoes this edit
     */
    virtual void undo(contents&) = 0;

    /*!
     * \brief Performs this edit again (Use after an undo)
     */
    virtual void redo(contents&) = 0;

    /*!
     * \brief Generates a change that will act over the new contents
     */
    virtual std::shared_ptr<change> regenerate(const contents&) const = 0;

    /*!
     * \brief Calls regenerate and then calls redo on the result and
     * returns the regenerated change.
     */
    std::shared_ptr<change> regenerate_and_apply(contents& cont);
};

}

#endif
<commit_msg>Fix `change`'s documentation<commit_after>#ifndef HEADER_GUARD_CHANGE_H
#define HEADER_GUARD_CHANGE_H

#include <boost/optional.hpp>
#include <functional>
#include <string>
#include <vector>
#include <memory>

namespace vick {

class contents;

/*!
 * \file change.hh
 *
 * \brief Defines the change class and the undo_change(),
 * redo_change(), and reapply_change() functions.
 */

/*!
 * \class change change.hh "../../../src/change.hh"
 * \brief Represents a change from one \c contents to another
 *
 * The change class represents a change from one \c contents to
 * another.  It is an interface that allows for undoing, redoing, and
 * regeneration of a change.  `undo` will put the contents in the
 * state it was before the edit.  `redo` will put the contents in the
 * state it was after the edit.  `regenerate` generates a new change
 * at the new position in the buffer, or acting on the new buffer
 * state that must be manually `redo`ne on the contents.
 *
 * \see contents
 */
struct change {
    virtual ~change()
    {
    }

    /*!
     * \brief Return true if you edit in any way anything but the x and y
     * coordinate
     */
    virtual bool is_overriding() = 0;

    /*!
     * \brief Undoes this edit
     */
    virtual void undo(contents&) = 0;

    /*!
     * \brief Performs this edit again (Use after an undo)
     */
    virtual void redo(contents&) = 0;

    /*!
     * \brief Generates a change that will act over the new contents
     */
    virtual std::shared_ptr<change> regenerate(const contents&) const = 0;

    /*!
     * \brief Calls regenerate and then calls redo on the result and
     * returns the regenerated change.
     */
    std::shared_ptr<change> regenerate_and_apply(contents& cont);
};

}

#endif
<|endoftext|>


<commit_before>/**
*************************************************************
* @file glovehttpclient.cpp
* @brief HTTP Client for Glove
*
* @author Gaspar Fernández <blakeyed@totaki.com>
* @version 0.3
* @date 1 jun 2016
*
* Notes:
*   - Lots of ideas borrowed from other projects
*
* Changelog
*  20170127 : - Error handler for background requests
*  20170112 : - SSL condition to compile without SSL support
*  20161004 : - Use CRLF from utils.hpp
*  20160927 : - GloveHttpClientRequest / GloveHttpClientResponse / request methods
*             - Separated cpp and hpp file
*  20160830 : - Just requests by URL
*  20160816 : - First release
*
* To-do:
*  0 - Multipart management
*  1 - Optimization
*  2 - Some more control over requests
*  3 - Have to improve request() some inputs may fail
*
* MIT Licensed:
* Copyright (c) 2016 Gaspar Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*************************************************************/

#include "glovehttpclient.hpp"
#include <thread>

GloveHttpClient::GloveHttpClient()
{
	clientConfig.userAgent = GLOVEHTTPCLIENT_DEFAULT_USERAGENT;
	clientConfig.timeout = GLOVEHTTPCLIENT_DEFAULT_TIMEOUT;
	clientConfig.checkCertificates = GLOVEHTTPCLIENT_DEFAULT_CHECKCERTS;
	clientConfig.maxRedirects = GLOVEHTTPCLIENT_DEFAULT_MAXREDIRECTS;
	clientConfig.followRedirects = GLOVEHTTPCLIENT_DEFAULT_FOLLOWREDIRECTS;
	_callback = nullptr;
}

GloveHttpClient::GloveHttpClient(std::string url, GloveHttpClientResponse& r, std::string reqType): GloveHttpClient()
{
	r = request(url, reqType);
}

GloveHttpClient::GloveHttpClient(std::string url, GloveHttpClientResponse& r, std::string reqType, std::string& data): GloveHttpClient()
{
	r = request(url, reqType, data);
}

GloveHttpClient::GloveHttpClient(std::string url, GloveHttpClientResponse& r, std::string reqType, std::string& data, std::map<std::string, std::string>& headers, std::string contentType): GloveHttpClient()
{
	r = request(url, reqType, data, headers, contentType);
}

GloveHttpClient::GloveHttpClient(Callback callback, ErrorHandler errhandler): GloveHttpClient()
{
	_callback = callback;
	_errhandler = errhandler;
}

GloveHttpClient::~GloveHttpClient()
{
}

GloveHttpClientResponse GloveHttpClient::request(std::string url, std::string reqType)
{
	std::string data = "";
	std::map < std::string, std::string> headers;
	GloveHttpClientRequest request (url, data, "", headers, reqType);
	return getUrlData(request, clientConfig.timeout, clientConfig.checkCertificates, clientConfig.maxRedirects);
}

GloveHttpClientResponse GloveHttpClient::request(std::string url, std::string reqType, std::string& data)
{
	std::map < std::string, std::string> headers;
	GloveHttpClientRequest request (url, data, "", headers, reqType);
	return getUrlData(request, clientConfig.timeout, clientConfig.checkCertificates, clientConfig.maxRedirects);
}

GloveHttpClientResponse GloveHttpClient::request(std::string url, std::string reqType, std::string& data, std::map<std::string, std::string>& headers, std::string contentType)
{
	GloveHttpClientRequest request (url, data, contentType, headers, reqType);
	return getUrlData(request, clientConfig.timeout, clientConfig.checkCertificates, clientConfig.maxRedirects);
}

void GloveHttpClient::bgrequest(std::string url, std::string reqType)
{
	std::string data = "";
	std::map < std::string, std::string> headers;
	GloveHttpClientRequest request (url, data, "", headers, reqType);
	addRequestToQueue(request);
}

void GloveHttpClient::bgrequest(std::string url, std::string reqType, std::string& data)
{
	std::map < std::string, std::string> headers;
	GloveHttpClientRequest request (url, data, "", headers, reqType);
	addRequestToQueue(request);
}

void GloveHttpClient::bgrequest(std::string url, std::string reqType, std::string& data, std::map<std::string, std::string>& headers, std::string contentType)
{
	GloveHttpClientRequest request (url, data, contentType, headers, reqType);
	addRequestToQueue(request);
}

int GloveHttpClient::parseFirstLine(std::string input, std::string& protocol, std::string &statusmsg)
{
	std::string::size_type space_pos, space_pos2;
	std::string temp_status;
	int status=0;

	space_pos = input.find(' ');

	if (space_pos == std::string::npos)
		throw GloveHttpClientException (5, "Couldn't parse protocol from received data");

	protocol = input.substr(0, space_pos);
	space_pos2 = input.find(' ', space_pos+1);

	if (space_pos == std::string::npos)
		throw GloveHttpClientException (6, "Couldn't parse status from received data");

	temp_status = input.substr(space_pos+1, space_pos2-space_pos-1);
	statusmsg = input.substr(space_pos2+1);

	try
		{
			status = std::stoi(temp_status);
		}
	catch (std::invalid_argument ia)
		{
			throw GloveHttpClientException (7, "Wrong status code");
		}
	catch (std::out_of_range org)
		{
			throw GloveHttpClientException (8, "Wrong status code");
		}

	return status;
}

GloveHttpClientResponse GloveHttpClient::getUrlData(GloveHttpClientRequest &request, double timeout, bool checkCertificates, int max_redirects)
{
	if (max_redirects < 0)
		throw GloveHttpClientException (1, "Max redirects reached!");

	/* No keepAlive for now */
	Glove g;
	GloveBase::uri u = Glove::get_from_uri(request.url);
	std::map<std::string, std::string> httpheaders;
	std::string protocol, statusmsg;
	int status;
	std::string out;
	/* We can debug uri here */
	/* u.host="localhost"; */
	/* u.port=1234; */
#if ENABLE_OPENSSL
	if (checkCertificates)
		g.SSLFlags(Glove::SSL_FLAG_ALL);
#endif
	g.shutdown_on_destroy(true);
	g.timeout_when_data(false);
	g.remove_exceptions (Glove::EXCEPTION_DISCONNECTED);
	/* this->say("Connecting "+url+" with timeout "+std::to_string(timeout), 2); */
	if (timeout != -1)
		g.timeout(timeout);
	g.connect(u);
	if (u.rawpath.empty())
		u.rawpath = "/";
	auto startTime = std::chrono::steady_clock::now();
	std::string reqStr = request.reqType+" "+u.rawpath+" HTTP/1.1"+GloveDef::CRLF+
		"Host: "+u.host+GloveDef::CRLF+
		"Accept: text/html,application/xhtml+xml,application/xml"+GloveDef::CRLF+
		"Connection: close"+GloveDef::CRLF+
		"User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/45.0.2454.101 Chrome/45.0.2454.101 Safari/537.36"+GloveDef::CRLF;
	for (auto header : request.headers)
		{
			reqStr+=header.first+": "+header.second+GloveDef::CRLF;
		}
	if (!request.data.empty())
		{
			if (request.contentType.empty())
				request.contentType = "application/x-www-form-urlencoded";
			reqStr+="Content-Type: "+request.contentType+GloveDef::CRLF;
			reqStr+="Content-Length: "+std::to_string(request.data.length())+GloveDef::CRLF;
		}
	g.send(reqStr+ GloveDef::CRLF +request.data);

	out = g.receive();
	auto firstByte = std::chrono::steady_clock::now();
	auto firstline = out.find(GloveDef::CRLF); /* End of first line. Protocol Code Status...*/
	if (firstline == std::string::npos)
		throw GloveHttpClientException (2, "Didn't receive protocol or status");

	status = parseFirstLine(out.substr(0, firstline), protocol, statusmsg);

	auto headerend = out.find(GloveDef::CRLF2);
	if (headerend == std::string::npos)
		throw GloveHttpClientException (3, "Unexpected data received");

	extract_headers(out.substr(firstline+1, headerend-firstline-1), httpheaders, 0);
	/* this->say("Return status: "+std::to_string(status), 3); */
	namespace chr = std::chrono;
	if ( (status>=300) && (status<400) )
		{
			auto location = httpheaders.find("Location");
			if ( (location != httpheaders.end()) || ((location = httpheaders.find("location")) != httpheaders.end()) )
				{
					std::string newUrl = location->second;
					newUrl = newUrl.substr(newUrl.find_first_not_of("/")); /* remove starting / */
					if (newUrl.find(u.service)!=0)
						newUrl=u.service+"://"+u.host+"/"+newUrl;
					request.url = newUrl;
					GloveHttpClientResponse response = getUrlData(request, timeout, checkCertificates, max_redirects-1);
					response.prevRedirect(request.url);
					return response;
				}
			else
				{
					throw GloveHttpClientException (4, "Redirection requested but Location not found");
				}
		}
	else
		{
			out = out.substr(headerend+4);
			return GloveHttpClientResponse(status, out, httpheaders, { request.url },
																		 chr::duration_cast<chr::milliseconds>(firstByte - startTime),
																		 chr::duration_cast<chr::milliseconds>(firstByte - startTime));
		}
}

void GloveHttpClient::addRequestToQueue(GloveHttpClientRequest& req)
{
	if (_callback == nullptr)
		throw GloveHttpClientException (9, "No callback specified");

	queueMutex.lock();
	unsigned queueLen = requestQueue.size();
	requestQueue.push_back(req);
	queueMutex.unlock();

	if (queueLen==0)
		processBackgroundQueue();
}

void GloveHttpClient::processBackgroundQueue()
{
	std::lock_guard<std::mutex> lock(queueMutex);

	if (requestQueue.size()==0)
		return;

	std::thread(&GloveHttpClient::backgroundThread, this).detach();
}

void GloveHttpClient::backgroundThread()
{
	queueMutex.lock();
	if (requestQueue.size()==0)
		{
			queueMutex.unlock();
			return ;
		}

	GloveHttpClientRequest request = requestQueue.front();
	try
		{
			requestQueue.erase(requestQueue.begin());
			queueMutex.unlock();

			GloveHttpClientResponse response = getUrlData(request, clientConfig.timeout, clientConfig.checkCertificates, clientConfig.maxRedirects);
			_callback(request, response);
		}
	catch (GloveException &e)
		{
			if (_errhandler)
				_errhandler(request.url, e);
		}
	backgroundThread();
}
<commit_msg>HTTP client fixes<commit_after>/**
*************************************************************
* @file glovehttpclient.cpp
* @brief HTTP Client for Glove
*
* @author Gaspar Fernández <blakeyed@totaki.com>
* @version 0.3
* @date 1 jun 2016
*
* Notes:
*   - Lots of ideas borrowed from other projects
*
* Changelog
*  20170127 : - Error handler for background requests
*  20170112 : - SSL condition to compile without SSL support
*  20161004 : - Use CRLF from utils.hpp
*  20160927 : - GloveHttpClientRequest / GloveHttpClientResponse / request methods
*             - Separated cpp and hpp file
*  20160830 : - Just requests by URL
*  20160816 : - First release
*
* To-do:
*  0 - Multipart management
*  1 - Optimization
*  2 - Some more control over requests
*
* MIT Licensed:
* Copyright (c) 2016 Gaspar Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*************************************************************/

#include "glovehttpclient.hpp"
#include <thread>

GloveHttpClient::GloveHttpClient()
{
	clientConfig.userAgent = GLOVEHTTPCLIENT_DEFAULT_USERAGENT;
	clientConfig.timeout = GLOVEHTTPCLIENT_DEFAULT_TIMEOUT;
	clientConfig.checkCertificates = GLOVEHTTPCLIENT_DEFAULT_CHECKCERTS;
	clientConfig.maxRedirects = GLOVEHTTPCLIENT_DEFAULT_MAXREDIRECTS;
	clientConfig.followRedirects = GLOVEHTTPCLIENT_DEFAULT_FOLLOWREDIRECTS;
	_callback = nullptr;
}

GloveHttpClient::GloveHttpClient(std::string url, GloveHttpClientResponse& r, std::string reqType): GloveHttpClient()
{
	r = request(url, reqType);
}

GloveHttpClient::GloveHttpClient(std::string url, GloveHttpClientResponse& r, std::string reqType, std::string& data): GloveHttpClient()
{
	r = request(url, reqType, data);
}

GloveHttpClient::GloveHttpClient(std::string url, GloveHttpClientResponse& r, std::string reqType, std::string& data, std::map<std::string, std::string>& headers, std::string contentType): GloveHttpClient()
{
	r = request(url, reqType, data, headers, contentType);
}

GloveHttpClient::GloveHttpClient(Callback callback, ErrorHandler errhandler): GloveHttpClient()
{
	_callback = callback;
	_errhandler = errhandler;
}

GloveHttpClient::~GloveHttpClient()
{
}

GloveHttpClientResponse GloveHttpClient::request(std::string url, std::string reqType)
{
	std::string data = "";
	std::map < std::string, std::string> headers;
	GloveHttpClientRequest request (url, data, "", headers, reqType);
	return getUrlData(request, clientConfig.timeout, clientConfig.checkCertificates, clientConfig.maxRedirects);
}

GloveHttpClientResponse GloveHttpClient::request(std::string url, std::string reqType, std::string& data)
{
	std::map < std::string, std::string> headers;
	GloveHttpClientRequest request (url, data, "", headers, reqType);
	return getUrlData(request, clientConfig.timeout, clientConfig.checkCertificates, clientConfig.maxRedirects);
}

GloveHttpClientResponse GloveHttpClient::request(std::string url, std::string reqType, std::string& data, std::map<std::string, std::string>& headers, std::string contentType)
{
	GloveHttpClientRequest request (url, data, contentType, headers, reqType);
	return getUrlData(request, clientConfig.timeout, clientConfig.checkCertificates, clientConfig.maxRedirects);
}

void GloveHttpClient::bgrequest(std::string url, std::string reqType)
{
	std::string data = "";
	std::map < std::string, std::string> headers;
	GloveHttpClientRequest request (url, data, "", headers, reqType);
	addRequestToQueue(request);
}

void GloveHttpClient::bgrequest(std::string url, std::string reqType, std::string& data)
{
	std::map < std::string, std::string> headers;
	GloveHttpClientRequest request (url, data, "", headers, reqType);
	addRequestToQueue(request);
}

void GloveHttpClient::bgrequest(std::string url, std::string reqType, std::string& data, std::map<std::string, std::string>& headers, std::string contentType)
{
	GloveHttpClientRequest request (url, data, contentType, headers, reqType);
	addRequestToQueue(request);
}

int GloveHttpClient::parseFirstLine(std::string input, std::string& protocol, std::string &statusmsg)
{
	std::string::size_type space_pos, space_pos2;
	std::string temp_status;
	int status=0;

	space_pos = input.find(' ');

	if (space_pos == std::string::npos)
		throw GloveHttpClientException (5, "Couldn't parse protocol from received data");

	protocol = input.substr(0, space_pos);
	space_pos2 = input.find(' ', space_pos+1);

	if (space_pos == std::string::npos)
		throw GloveHttpClientException (6, "Couldn't parse status from received data");

	temp_status = input.substr(space_pos+1, space_pos2-space_pos-1);
	statusmsg = input.substr(space_pos2+1);

	try
		{
			status = std::stoi(temp_status);
		}
	catch (std::invalid_argument ia)
		{
			throw GloveHttpClientException (7, "Wrong status code");
		}
	catch (std::out_of_range org)
		{
			throw GloveHttpClientException (8, "Wrong status code");
		}

	return status;
}

GloveHttpClientResponse GloveHttpClient::getUrlData(GloveHttpClientRequest &request, double timeout, bool checkCertificates, int max_redirects)
{
	if (max_redirects < 0)
		throw GloveHttpClientException (1, "Max redirects reached!");

	/* No keepAlive for now */
	Glove g;
	GloveBase::uri u = Glove::get_from_uri(request.url);
	std::map<std::string, std::string> httpheaders;
	std::string protocol, statusmsg;
	int status;
	std::string out;
	/* We can debug uri here */
	/* u.host="localhost"; */
	/* u.port=1234; */
#if ENABLE_OPENSSL
	if (checkCertificates)
		g.SSLFlags(Glove::SSL_FLAG_ALL);
#endif
	g.shutdown_on_destroy(true);
	g.timeout_when_data(false);
	g.remove_exceptions (Glove::EXCEPTION_DISCONNECTED);
	/* this->say("Connecting "+url+" with timeout "+std::to_string(timeout), 2); */
	if (timeout != -1)
		g.timeout(timeout);
	g.connect(u);
	if (u.rawpath.empty())
		u.rawpath = "/";
	auto startTime = std::chrono::steady_clock::now();
	std::string reqStr = request.reqType+" "+u.rawpath+" HTTP/1.1\r\n"
		"Host: "+u.host+"\r\n"
		"Accept: text/html,application/xhtml+xml,application/xml\r\n"
		"Connection: close\r\n"
		"User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/45.0.2454.101 Chrome/45.0.2454.101 Safari/537.36\r\n";
	for (auto header : request.headers)
		{
			reqStr+=header.first+": "+header.second+"\r\n";
		}

	if (!request.data.empty())
		{
			if (request.contentType.empty())
				request.contentType = "application/x-www-form-urlencoded";
			reqStr+="Content-Type: "+request.contentType+"\r\n";
			reqStr+="Content-Length: "+std::to_string(request.data.length())+"\r\n";
		}

	g.send(reqStr+ "\r\n"+request.data);
	out = g.receive();
	auto firstByte = std::chrono::steady_clock::now();
	auto firstline = out.find(GloveDef::CRLF); /* End of first line. Protocol Code Status...*/
	if (firstline == std::string::npos)
		throw GloveHttpClientException (2, "Didn't receive protocol or status");

	status = parseFirstLine(out.substr(0, firstline), protocol, statusmsg);

	auto headerend = out.find(GloveDef::CRLF2);
	if (headerend == std::string::npos)
		throw GloveHttpClientException (3, "Unexpected data received");

	extract_headers(out.substr(firstline+1, headerend-firstline-1), httpheaders, 0);
	/* this->say("Return status: "+std::to_string(status), 3); */
	namespace chr = std::chrono;
	if ( (status>=300) && (status<400) )
		{
			auto location = httpheaders.find("Location");
			if ( (location != httpheaders.end()) || ((location = httpheaders.find("location")) != httpheaders.end()) )
				{
					std::string newUrl = location->second;
					newUrl = newUrl.substr(newUrl.find_first_not_of("/")); /* remove starting / */
					if (newUrl.find(u.service)!=0)
						newUrl=u.service+"://"+u.host+"/"+newUrl;
					request.url = newUrl;
					GloveHttpClientResponse response = getUrlData(request, timeout, checkCertificates, max_redirects-1);
					response.prevRedirect(request.url);
					return response;
				}
			else
				{
					throw GloveHttpClientException (4, "Redirection requested but Location not found");
				}
		}
	else
		{
			out = out.substr(headerend+4);
			return GloveHttpClientResponse(status, out, httpheaders, { request.url },
																		 chr::duration_cast<chr::milliseconds>(firstByte - startTime),
																		 chr::duration_cast<chr::milliseconds>(firstByte - startTime));
		}
}

void GloveHttpClient::addRequestToQueue(GloveHttpClientRequest& req)
{
	if (_callback == nullptr)
		throw GloveHttpClientException (9, "No callback specified");

	queueMutex.lock();
	unsigned queueLen = requestQueue.size();
	requestQueue.push_back(req);
	queueMutex.unlock();

	if (queueLen==0)
		processBackgroundQueue();
}

void GloveHttpClient::processBackgroundQueue()
{
	std::lock_guard<std::mutex> lock(queueMutex);

	if (requestQueue.size()==0)
		return;

	std::thread(&GloveHttpClient::backgroundThread, this).detach();
}

void GloveHttpClient::backgroundThread()
{
	queueMutex.lock();
	if (requestQueue.size()==0)
		{
			queueMutex.unlock();
			return ;
		}

	GloveHttpClientRequest request = requestQueue.front();
	try
		{
			requestQueue.erase(requestQueue.begin());
			queueMutex.unlock();

			GloveHttpClientResponse response = getUrlData(request, clientConfig.timeout, clientConfig.checkCertificates, clientConfig.maxRedirects);
			_callback(request, response);
		}
	catch (GloveException &e)
		{
			if (_errhandler)
				_errhandler(request.url, e);
		}
	backgroundThread();
}
<|endoftext|>


<commit_before>// Copyright Hugh Perkins 2014 hughperkins at gmail
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include <stdexcept>
#include <random>

#include "Timer.h"
#include "ConvolutionalLayer.h"
#include "LayerMaker.h"
#include "ActivationFunction.h"
#include "StatefulTimer.h"
#include "AccuracyHelper.h"
#include "NeuralNetMould.h"
#include "Layer.h"
#include "InputLayer.h"
#include "FullyConnectedLayer.h"
#include "EpochMaker.h"
#include "LossLayer.h"
#include "IAcceptsLabels.h"
#include "ExceptionMacros.h"

#include "NeuralNet.h"

using namespace std;

//static std::mt19937 random;

#undef VIRTUAL
#define VIRTUAL
#undef STATIC
#define STATIC

NeuralNet::NeuralNet() {
    cout << "NeuralNet()" << endl;
    cl = OpenCLHelper::createForFirstGpuOtherwiseCpu();
//    InputLayerMaker<T> *maker = new InputLayerMaker<T>( this, numPlanes, boardSize );
//    maker->insert();
}
NeuralNet::NeuralNet( int numPlanes, int boardSize ) {
    cout << "NeuralNet(planes,boardsize)" << endl;
    cl = new OpenCLHelper();
    InputLayerMaker<float> *maker = ( new InputLayerMaker<float>( this ) )
        ->numPlanes( numPlanes )->boardSize( boardSize );
    maker->insert();
}
NeuralNet::~NeuralNet() {
    for( int i = 0; i < layers.size(); i++ ) {
        delete layers[i];
    }
    delete cl;
}
OpenCLHelper *NeuralNet::getCl() {
    return cl;
}
STATIC NeuralNetMould *NeuralNet::maker() {
    return new NeuralNetMould();
}
template< typename T >InputLayerMaker<T> *NeuralNet::inputMaker() {
    if( layers.size() != 0 ) {
        throw runtime_error("Already added an InputLayer to this net");
    }
    return new InputLayerMaker<T>( this );
}
FullyConnectedMaker *NeuralNet::fullyConnectedMaker() {
    return new FullyConnectedMaker( this, getLastLayer() );
}
ConvolutionalMaker *NeuralNet::convolutionalMaker() {
    return new ConvolutionalMaker( this, getLastLayer() );
}
PoolingMaker *NeuralNet::poolingMaker() {
    return new PoolingMaker( this, getLastLayer() );
}
NormalizationLayerMaker *NeuralNet::normalizationMaker() {
    return new NormalizationLayerMaker( this, getLastLayer() );
}
SquareLossMaker *NeuralNet::squareLossMaker() {
    return new SquareLossMaker( this, getLastLayer() );
}
CrossEntropyLossMaker *NeuralNet::crossEntropyLossMaker() {
    return new CrossEntropyLossMaker( this, getLastLayer() );
}
SoftMaxMaker *NeuralNet::softMaxLossMaker() {
    return new SoftMaxMaker( this, getLastLayer() );
}
void NeuralNet::initWeights( int layerIndex, float *weights, float *biasWeights ) {
    initWeights( layerIndex, weights );
    initBiasWeights( layerIndex, biasWeights );
}
void NeuralNet::initWeights( int layerIndex, float *weights ) {
    layers[layerIndex]->initWeights( weights );
}
void NeuralNet::initBiasWeights( int layerIndex, float *weights ) {
    layers[layerIndex]->initBiasWeights( weights );
}
void NeuralNet::printWeightsAsCode() {
    for( int layer = 1; layer < layers.size(); layer++ ) {
        layers[layer]->printWeightsAsCode();
    }
}
void NeuralNet::printBiasWeightsAsCode() {
    for( int layer = 1; layer < layers.size(); layer++ ) {
        layers[layer]->printBiasWeightsAsCode();
    }
}
float NeuralNet::calcLoss(float const *expectedValues ) {
    return dynamic_cast<LossLayer*>(layers[layers.size()-1])->calcLoss( expectedValues );
}
float NeuralNet::calcLossFromLabels(int const *labels ) {
    return dynamic_cast<IAcceptsLabels*>(layers[layers.size()-1])->calcLossFromLabels( labels );
}
EpochMaker *NeuralNet::epochMaker() {
     return new EpochMaker(this);
}
template< typename T > InputLayer<T> *NeuralNet::getFirstLayer() {
    return dynamic_cast<InputLayer<T> *>( layers[0] );
}
Layer *NeuralNet::getLastLayer() {
    return layers[layers.size() - 1];
}
Layer *NeuralNet::addLayer( LayerMaker *maker ) {
    Layer *previousLayer = 0;
    if( layers.size() > 0 ) {
        previousLayer = layers[ layers.size() - 1 ];
    }
//    maker->setPreviousLayer( previousLayer );
    Layer *layer = maker->instance();
    layers.push_back( layer );
    return layer;
}
void NeuralNet::setBatchSize( int batchSize ) {
    for( std::vector<Layer*>::iterator it = layers.begin(); it != layers.end(); it++ ) {
        (*it)->setBatchSize( batchSize );
    }
}
float NeuralNet::doEpochFromLabels( float learningRate, int batchSize, int numImages, float const* images, int const *labels ) {
    return doEpochFromLabels( learningRate, batchSize, numImages, images, labels, 0 );
}
float NeuralNet::doEpochFromLabels( float learningRate, int batchSize, int numImages, float const* images, int const *labels, int *p_totalCorrect ) {
//        Timer timer;
    IAcceptsLabels *acceptsLabels = dynamic_cast<IAcceptsLabels*>(getLastLayer());
    if( acceptsLabels == 0 ) {
        THROW("You need to add a IAcceptsLabels as the last layer, in order to use doEpochFromLabels");
    }
    setBatchSize( batchSize );
    int numBatches = ( numImages + batchSize - 1 ) / batchSize;
    float loss = 0;
    int total = 0;
    int numRight = 0;
    int numLabelsPerExample = acceptsLabels->getNumLabelsPerExample();
    for( int batch = 0; batch < numBatches; batch++ ) {
        int batchStart = batch * batchSize;
        int thisBatchSize = batchSize;
        if( batch == numBatches - 1 ) {
            thisBatchSize = numImages - batchStart;  // eg, we have 5 images, and batchsize is 3
                                                         // so last batch size is: 2 = 5 - 3
            setBatchSize( thisBatchSize );
        }
        learnBatchFromLabels( learningRate, &(images[batchStart*getInputCubeSize()]), &(labels[batchStart * numLabelsPerExample]) );
        loss += acceptsLabels->calcLossFromLabels( &(labels[batchStart * numLabelsPerExample]) );
        if( p_totalCorrect != 0 ) {
            numRight += acceptsLabels->calcNumRight( &(labels[batchStart * numLabelsPerExample]) );
        }
    }
    if( p_totalCorrect != 0 ) {
        *p_totalCorrect = numRight;
    }
    return loss;
}
float NeuralNet::doEpoch( float learningRate, int batchSize, int numImages, float const* images, float const *expectedResults ) {
//        Timer timer;
    if( dynamic_cast<LossLayer*>(getLastLayer()) == 0 ) {
        THROW("You need to add a LossLayer as the last layer of the network");
    }
    setBatchSize( batchSize );
    int numBatches = ( numImages + batchSize - 1 ) / batchSize;
    float loss = 0;
    int total = 0;
    for( int batch = 0; batch < numBatches; batch++ ) {
        int batchStart = batch * batchSize;
        int thisBatchSize = batchSize;
        if( batch == numBatches - 1 ) {
            thisBatchSize = numImages - batchStart;  // eg, we have 5 images, and batchsize is 3
                                                         // so last batch size is: 2 = 5 - 3
            setBatchSize( thisBatchSize );
        }
//            std::cout << " batch " << batch << " start " << batchStart << " inputsizeperex " << getInputSizePerExample() <<
//             " resultssizeperex " << getResultsSizePerExample() << std::endl;
        learnBatch( learningRate, &(images[batchStart*getInputCubeSize()]), &(expectedResults[batchStart*getOutputCubeSize()]) );
        loss += calcLoss( &(expectedResults[batchStart*getOutputCubeSize()]) );
    }
    return loss;
}
int NeuralNet::calcNumRight( int const *labels ) {
    IAcceptsLabels *acceptsLabels = dynamic_cast<IAcceptsLabels*>(getLastLayer());
    if( acceptsLabels == 0 ) {
        THROW("You need to add a IAcceptsLabels as the last layer, in order to use calcNumRight");
    }
    return acceptsLabels->calcNumRight( labels );
}
float NeuralNet::doEpochWithCalcTrainingAccuracy( float learningRate, int batchSize, int numImages, float const* images, float const *expectedResults, int const *labels, int *p_totalCorrect ) {
    setBatchSize( batchSize );
    int numBatches = ( numImages + batchSize - 1 ) / batchSize;
    std::cout << "numBatches: " << numBatches << std::endl;
    float loss = 0;
    int numRight = 0;
    int total = 0;
    if( getLastLayer()->getOutputBoardSize() != 1 ) {
        THROW("Last layer should have board size of 1, and number of planes equal number of categories, if you want to measure training accuracy");
    }
    for( int batch = 0; batch < numBatches; batch++ ) {
        int batchStart = batch * batchSize;
        int thisBatchSize = batchSize;
        if( batch == numBatches - 1 ) {
            thisBatchSize = numImages - batchStart;  // eg, we have 5 images, and batchsize is 3
                                                         // so last batch size is: 2 = 5 - 3
            setBatchSize( thisBatchSize );
        }
//            std::cout << " batch " << batch << " start " << batchStart << " inputsizeperex " << getInputSizePerExample() <<
//             " resultssizeperex " << getResultsSizePerExample() << std::endl;
        learnBatch( learningRate, &(images[batchStart*getInputCubeSize()]), &(expectedResults[batchStart*getOutputCubeSize()]) );
        StatefulTimer::timeCheck("after batch forward-backward prop");
        numRight += AccuracyHelper::calcNumRight( thisBatchSize, getLastLayer()->getOutputPlanes(), &(labels[batchStart]), getResults() );
        StatefulTimer::timeCheck("after batch calc training num right");
        loss += calcLoss( &(expectedResults[batchStart*getOutputCubeSize()]) );
        StatefulTimer::timeCheck("after batch calc loss");
    }
    *p_totalCorrect = numRight;
    return loss;
}
template< typename T > void NeuralNet::propagate( T const*images) {
    // forward...
    dynamic_cast<InputLayer<T> *>(layers[0])->in( images );
    for( int layerId = 0; layerId < layers.size(); layerId++ ) {
        StatefulTimer::setPrefix("layer" + toString(layerId) + " " );
        layers[layerId]->propagate();
        StatefulTimer::setPrefix("" );
    }
}
void NeuralNet::backPropFromLabels( float learningRate, int const *labels) {
    IAcceptsLabels *acceptsLabels = dynamic_cast<IAcceptsLabels*>(getLastLayer());
    if( acceptsLabels == 0 ) {
        throw std::runtime_error("Must add a child of IAcceptsLabels as last layer, to use backPropFromLabels");
    }
    acceptsLabels->calcErrorsFromLabels( labels );
    for( int layerIdx = (int)layers.size() - 2; layerIdx >= 1; layerIdx-- ) { // no point in propagating to input layer :-P
        StatefulTimer::setPrefix("layer" + toString(layerIdx) + " " );
        Layer *layer = layers[layerIdx];
        if( layer->needsBackProp() ) {
            layer->backProp( learningRate );
        }
        StatefulTimer::setPrefix("" );
    }
}
void NeuralNet::backProp( float learningRate, float const *expectedResults) {
    LossLayer *lossLayer = dynamic_cast<LossLayer*>(getLastLayer());
    if( lossLayer == 0 ) {
        throw std::runtime_error("Must add a LossLayer as last layer of net");
    }
    lossLayer->calcErrors( expectedResults );
    for( int layerIdx = (int)layers.size() - 2; layerIdx >= 1; layerIdx-- ) { // no point in propagating to input layer :-P
        StatefulTimer::setPrefix("layer" + toString(layerIdx) + " " );
        layers[layerIdx]->backProp( learningRate );
        StatefulTimer::setPrefix("" );
    }
}
template< typename T > void NeuralNet::learnBatch( float learningRate, T const*images, float const *expectedResults ) {
    propagate( images);
    backProp( learningRate, expectedResults );
}
template< typename T > void NeuralNet::learnBatchFromLabels( float learningRate, T const*images, int const *labels ) {
    propagate( images);
    backPropFromLabels( learningRate, labels );
}
int NeuralNet::getNumLayers() {
    return (int)layers.size();
}
float const *NeuralNet::getResults( int layer ) const {
    return layers[layer]->getResults();
}
int NeuralNet::getInputCubeSize() const {
    return layers[ 0 ]->getOutputCubeSize();
}
int NeuralNet::getOutputCubeSize() const {
    return layers[ layers.size() - 1 ]->getOutputCubeSize();
}
float const *NeuralNet::getResults() const {
    return getResults( (int)layers.size() - 1 );
}
void NeuralNet::print() {
    int i = 0;
    for( std::vector< Layer* >::iterator it = layers.begin(); it != layers.end(); it++ ) {
        std::cout << "layer " << i << ":" << std::endl;
        //(*it)->print();
        cout << (*it)->asString() << endl;
        i++;
    }
}
void NeuralNet::printWeights() {
    int i = 0;
    for( std::vector< Layer* >::iterator it = layers.begin(); it != layers.end(); it++ ) {
        std::cout << "layer " << i << ":" << std::endl;
        (*it)->printWeights();
        i++;
    }
}
void NeuralNet::printOutput() {
    int i = 0;
    for( std::vector< Layer* >::iterator it = layers.begin(); it != layers.end(); it++ ) {
        std::cout << "layer " << i << ":" << std::endl;
        (*it)->printOutput();
        i++;
    }
}

template InputLayerMaker<unsigned char> *NeuralNet::inputMaker<unsigned char>();
template InputLayerMaker<float> *NeuralNet::inputMaker<float>();
template void NeuralNet::propagate( unsigned char const*images);
template void NeuralNet::propagate( float const*images);
template void NeuralNet::learnBatchFromLabels<unsigned char>(float learningRate, unsigned char const*images, int const *labels );
template void NeuralNet::learnBatchFromLabels<float>(float learningRate, float const *images, int const *labels );

<commit_msg>export NeuralNet template instantiations, for windows<commit_after>// Copyright Hugh Perkins 2014 hughperkins at gmail
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include <stdexcept>
#include <random>

#include "Timer.h"
#include "ConvolutionalLayer.h"
#include "LayerMaker.h"
#include "ActivationFunction.h"
#include "StatefulTimer.h"
#include "AccuracyHelper.h"
#include "NeuralNetMould.h"
#include "Layer.h"
#include "InputLayer.h"
#include "FullyConnectedLayer.h"
#include "EpochMaker.h"
#include "LossLayer.h"
#include "IAcceptsLabels.h"
#include "ExceptionMacros.h"

#include "NeuralNet.h"

using namespace std;

//static std::mt19937 random;

#undef VIRTUAL
#define VIRTUAL
#undef STATIC
#define STATIC

NeuralNet::NeuralNet() {
    cout << "NeuralNet()" << endl;
    cl = OpenCLHelper::createForFirstGpuOtherwiseCpu();
//    InputLayerMaker<T> *maker = new InputLayerMaker<T>( this, numPlanes, boardSize );
//    maker->insert();
}
NeuralNet::NeuralNet( int numPlanes, int boardSize ) {
    cout << "NeuralNet(planes,boardsize)" << endl;
    cl = new OpenCLHelper();
    InputLayerMaker<float> *maker = ( new InputLayerMaker<float>( this ) )
        ->numPlanes( numPlanes )->boardSize( boardSize );
    maker->insert();
}
NeuralNet::~NeuralNet() {
    for( int i = 0; i < layers.size(); i++ ) {
        delete layers[i];
    }
    delete cl;
}
OpenCLHelper *NeuralNet::getCl() {
    return cl;
}
STATIC NeuralNetMould *NeuralNet::maker() {
    return new NeuralNetMould();
}
template< typename T >InputLayerMaker<T> *NeuralNet::inputMaker() {
    if( layers.size() != 0 ) {
        throw runtime_error("Already added an InputLayer to this net");
    }
    return new InputLayerMaker<T>( this );
}
FullyConnectedMaker *NeuralNet::fullyConnectedMaker() {
    return new FullyConnectedMaker( this, getLastLayer() );
}
ConvolutionalMaker *NeuralNet::convolutionalMaker() {
    return new ConvolutionalMaker( this, getLastLayer() );
}
PoolingMaker *NeuralNet::poolingMaker() {
    return new PoolingMaker( this, getLastLayer() );
}
NormalizationLayerMaker *NeuralNet::normalizationMaker() {
    return new NormalizationLayerMaker( this, getLastLayer() );
}
SquareLossMaker *NeuralNet::squareLossMaker() {
    return new SquareLossMaker( this, getLastLayer() );
}
CrossEntropyLossMaker *NeuralNet::crossEntropyLossMaker() {
    return new CrossEntropyLossMaker( this, getLastLayer() );
}
SoftMaxMaker *NeuralNet::softMaxLossMaker() {
    return new SoftMaxMaker( this, getLastLayer() );
}
void NeuralNet::initWeights( int layerIndex, float *weights, float *biasWeights ) {
    initWeights( layerIndex, weights );
    initBiasWeights( layerIndex, biasWeights );
}
void NeuralNet::initWeights( int layerIndex, float *weights ) {
    layers[layerIndex]->initWeights( weights );
}
void NeuralNet::initBiasWeights( int layerIndex, float *weights ) {
    layers[layerIndex]->initBiasWeights( weights );
}
void NeuralNet::printWeightsAsCode() {
    for( int layer = 1; layer < layers.size(); layer++ ) {
        layers[layer]->printWeightsAsCode();
    }
}
void NeuralNet::printBiasWeightsAsCode() {
    for( int layer = 1; layer < layers.size(); layer++ ) {
        layers[layer]->printBiasWeightsAsCode();
    }
}
float NeuralNet::calcLoss(float const *expectedValues ) {
    return dynamic_cast<LossLayer*>(layers[layers.size()-1])->calcLoss( expectedValues );
}
float NeuralNet::calcLossFromLabels(int const *labels ) {
    return dynamic_cast<IAcceptsLabels*>(layers[layers.size()-1])->calcLossFromLabels( labels );
}
EpochMaker *NeuralNet::epochMaker() {
     return new EpochMaker(this);
}
template< typename T > InputLayer<T> *NeuralNet::getFirstLayer() {
    return dynamic_cast<InputLayer<T> *>( layers[0] );
}
Layer *NeuralNet::getLastLayer() {
    return layers[layers.size() - 1];
}
Layer *NeuralNet::addLayer( LayerMaker *maker ) {
    Layer *previousLayer = 0;
    if( layers.size() > 0 ) {
        previousLayer = layers[ layers.size() - 1 ];
    }
//    maker->setPreviousLayer( previousLayer );
    Layer *layer = maker->instance();
    layers.push_back( layer );
    return layer;
}
void NeuralNet::setBatchSize( int batchSize ) {
    for( std::vector<Layer*>::iterator it = layers.begin(); it != layers.end(); it++ ) {
        (*it)->setBatchSize( batchSize );
    }
}
float NeuralNet::doEpochFromLabels( float learningRate, int batchSize, int numImages, float const* images, int const *labels ) {
    return doEpochFromLabels( learningRate, batchSize, numImages, images, labels, 0 );
}
float NeuralNet::doEpochFromLabels( float learningRate, int batchSize, int numImages, float const* images, int const *labels, int *p_totalCorrect ) {
//        Timer timer;
    IAcceptsLabels *acceptsLabels = dynamic_cast<IAcceptsLabels*>(getLastLayer());
    if( acceptsLabels == 0 ) {
        THROW("You need to add a IAcceptsLabels as the last layer, in order to use doEpochFromLabels");
    }
    setBatchSize( batchSize );
    int numBatches = ( numImages + batchSize - 1 ) / batchSize;
    float loss = 0;
    int total = 0;
    int numRight = 0;
    int numLabelsPerExample = acceptsLabels->getNumLabelsPerExample();
    for( int batch = 0; batch < numBatches; batch++ ) {
        int batchStart = batch * batchSize;
        int thisBatchSize = batchSize;
        if( batch == numBatches - 1 ) {
            thisBatchSize = numImages - batchStart;  // eg, we have 5 images, and batchsize is 3
                                                         // so last batch size is: 2 = 5 - 3
            setBatchSize( thisBatchSize );
        }
        learnBatchFromLabels( learningRate, &(images[batchStart*getInputCubeSize()]), &(labels[batchStart * numLabelsPerExample]) );
        loss += acceptsLabels->calcLossFromLabels( &(labels[batchStart * numLabelsPerExample]) );
        if( p_totalCorrect != 0 ) {
            numRight += acceptsLabels->calcNumRight( &(labels[batchStart * numLabelsPerExample]) );
        }
    }
    if( p_totalCorrect != 0 ) {
        *p_totalCorrect = numRight;
    }
    return loss;
}
float NeuralNet::doEpoch( float learningRate, int batchSize, int numImages, float const* images, float const *expectedResults ) {
//        Timer timer;
    if( dynamic_cast<LossLayer*>(getLastLayer()) == 0 ) {
        THROW("You need to add a LossLayer as the last layer of the network");
    }
    setBatchSize( batchSize );
    int numBatches = ( numImages + batchSize - 1 ) / batchSize;
    float loss = 0;
    int total = 0;
    for( int batch = 0; batch < numBatches; batch++ ) {
        int batchStart = batch * batchSize;
        int thisBatchSize = batchSize;
        if( batch == numBatches - 1 ) {
            thisBatchSize = numImages - batchStart;  // eg, we have 5 images, and batchsize is 3
                                                         // so last batch size is: 2 = 5 - 3
            setBatchSize( thisBatchSize );
        }
//            std::cout << " batch " << batch << " start " << batchStart << " inputsizeperex " << getInputSizePerExample() <<
//             " resultssizeperex " << getResultsSizePerExample() << std::endl;
        learnBatch( learningRate, &(images[batchStart*getInputCubeSize()]), &(expectedResults[batchStart*getOutputCubeSize()]) );
        loss += calcLoss( &(expectedResults[batchStart*getOutputCubeSize()]) );
    }
    return loss;
}
int NeuralNet::calcNumRight( int const *labels ) {
    IAcceptsLabels *acceptsLabels = dynamic_cast<IAcceptsLabels*>(getLastLayer());
    if( acceptsLabels == 0 ) {
        THROW("You need to add a IAcceptsLabels as the last layer, in order to use calcNumRight");
    }
    return acceptsLabels->calcNumRight( labels );
}
float NeuralNet::doEpochWithCalcTrainingAccuracy( float learningRate, int batchSize, int numImages, float const* images, float const *expectedResults, int const *labels, int *p_totalCorrect ) {
    setBatchSize( batchSize );
    int numBatches = ( numImages + batchSize - 1 ) / batchSize;
    std::cout << "numBatches: " << numBatches << std::endl;
    float loss = 0;
    int numRight = 0;
    int total = 0;
    if( getLastLayer()->getOutputBoardSize() != 1 ) {
        THROW("Last layer should have board size of 1, and number of planes equal number of categories, if you want to measure training accuracy");
    }
    for( int batch = 0; batch < numBatches; batch++ ) {
        int batchStart = batch * batchSize;
        int thisBatchSize = batchSize;
        if( batch == numBatches - 1 ) {
            thisBatchSize = numImages - batchStart;  // eg, we have 5 images, and batchsize is 3
                                                         // so last batch size is: 2 = 5 - 3
            setBatchSize( thisBatchSize );
        }
//            std::cout << " batch " << batch << " start " << batchStart << " inputsizeperex " << getInputSizePerExample() <<
//             " resultssizeperex " << getResultsSizePerExample() << std::endl;
        learnBatch( learningRate, &(images[batchStart*getInputCubeSize()]), &(expectedResults[batchStart*getOutputCubeSize()]) );
        StatefulTimer::timeCheck("after batch forward-backward prop");
        numRight += AccuracyHelper::calcNumRight( thisBatchSize, getLastLayer()->getOutputPlanes(), &(labels[batchStart]), getResults() );
        StatefulTimer::timeCheck("after batch calc training num right");
        loss += calcLoss( &(expectedResults[batchStart*getOutputCubeSize()]) );
        StatefulTimer::timeCheck("after batch calc loss");
    }
    *p_totalCorrect = numRight;
    return loss;
}
template< typename T > void NeuralNet::propagate( T const*images) {
    // forward...
    dynamic_cast<InputLayer<T> *>(layers[0])->in( images );
    for( int layerId = 0; layerId < layers.size(); layerId++ ) {
        StatefulTimer::setPrefix("layer" + toString(layerId) + " " );
        layers[layerId]->propagate();
        StatefulTimer::setPrefix("" );
    }
}
void NeuralNet::backPropFromLabels( float learningRate, int const *labels) {
    IAcceptsLabels *acceptsLabels = dynamic_cast<IAcceptsLabels*>(getLastLayer());
    if( acceptsLabels == 0 ) {
        throw std::runtime_error("Must add a child of IAcceptsLabels as last layer, to use backPropFromLabels");
    }
    acceptsLabels->calcErrorsFromLabels( labels );
    for( int layerIdx = (int)layers.size() - 2; layerIdx >= 1; layerIdx-- ) { // no point in propagating to input layer :-P
        StatefulTimer::setPrefix("layer" + toString(layerIdx) + " " );
        Layer *layer = layers[layerIdx];
        if( layer->needsBackProp() ) {
            layer->backProp( learningRate );
        }
        StatefulTimer::setPrefix("" );
    }
}
void NeuralNet::backProp( float learningRate, float const *expectedResults) {
    LossLayer *lossLayer = dynamic_cast<LossLayer*>(getLastLayer());
    if( lossLayer == 0 ) {
        throw std::runtime_error("Must add a LossLayer as last layer of net");
    }
    lossLayer->calcErrors( expectedResults );
    for( int layerIdx = (int)layers.size() - 2; layerIdx >= 1; layerIdx-- ) { // no point in propagating to input layer :-P
        StatefulTimer::setPrefix("layer" + toString(layerIdx) + " " );
        layers[layerIdx]->backProp( learningRate );
        StatefulTimer::setPrefix("" );
    }
}
template< typename T > void NeuralNet::learnBatch( float learningRate, T const*images, float const *expectedResults ) {
    propagate( images);
    backProp( learningRate, expectedResults );
}
template< typename T > void NeuralNet::learnBatchFromLabels( float learningRate, T const*images, int const *labels ) {
    propagate( images);
    backPropFromLabels( learningRate, labels );
}
int NeuralNet::getNumLayers() {
    return (int)layers.size();
}
float const *NeuralNet::getResults( int layer ) const {
    return layers[layer]->getResults();
}
int NeuralNet::getInputCubeSize() const {
    return layers[ 0 ]->getOutputCubeSize();
}
int NeuralNet::getOutputCubeSize() const {
    return layers[ layers.size() - 1 ]->getOutputCubeSize();
}
float const *NeuralNet::getResults() const {
    return getResults( (int)layers.size() - 1 );
}
void NeuralNet::print() {
    int i = 0;
    for( std::vector< Layer* >::iterator it = layers.begin(); it != layers.end(); it++ ) {
        std::cout << "layer " << i << ":" << std::endl;
        //(*it)->print();
        cout << (*it)->asString() << endl;
        i++;
    }
}
void NeuralNet::printWeights() {
    int i = 0;
    for( std::vector< Layer* >::iterator it = layers.begin(); it != layers.end(); it++ ) {
        std::cout << "layer " << i << ":" << std::endl;
        (*it)->printWeights();
        i++;
    }
}
void NeuralNet::printOutput() {
    int i = 0;
    for( std::vector< Layer* >::iterator it = layers.begin(); it != layers.end(); it++ ) {
        std::cout << "layer " << i << ":" << std::endl;
        (*it)->printOutput();
        i++;
    }
}

template ClConvolve_EXPORT InputLayerMaker<unsigned char> *NeuralNet::inputMaker<unsigned char>();
template ClConvolve_EXPORT InputLayerMaker<float> *NeuralNet::inputMaker<float>();
template ClConvolve_EXPORT void NeuralNet::propagate(unsigned char const*images);
template ClConvolve_EXPORT void NeuralNet::propagate(float const*images);
template ClConvolve_EXPORT void NeuralNet::learnBatchFromLabels<unsigned char>(float learningRate, unsigned char const*images, int const *labels);
template ClConvolve_EXPORT void NeuralNet::learnBatchFromLabels<float>(float learningRate, float const *images, int const *labels);

<|endoftext|>


<commit_before>//
// Simple QtWeb
//
// Also it read STDIN and execute that as JS code
// And some commands: see Options.*Prefix
//

#include <QtGui/QApplication>
#include <QObject>

#include <QDebug>

#include <QWebView>
#include <QWebFrame>
#include <QUrl>
#include <QWebElement>
#include <QPoint>
#include <QRect>
#include <QMouseEvent>
#include <QCursor>
#include <QStringList>
#include <QNetworkProxy>
#include <QSocketNotifier>
#include <QTextStream>

#include <memory>

#include <signal.h>
#include <unistd.h> // STDIN_FILENO

#include "lambda.h"
#include "qwebpage.h"

std::unique_ptr<QWebView> view;
std::unique_ptr<QSocketNotifier> stdinNotifier;

struct Options {
	bool maximize;
	QString url; // default url is "google.com"
	QString userAgent; // default is that using in ga-kw
	QString socks;
	QString moveToElementPrefix;
	QString clickToElementPrefix;
	QString cursorSetToElementPrefix;
	bool socksResolver;
};
Options options = {
	false,
	QString("google.com"),
	QString("Mozilla/5.0 (X11; U; Linux i686;) Gecko/20110101 Firefox/3.6.13"),
	QString(""),
	QString("Move to "),
	QString("Click to "),
	QString("Cursor to "),
	false,
};

int main(int argc, char** argv) {
	QApplication a(argc, argv);

	// Parse options
	// TODO: http://api.kde.org/4.x-api/kdelibs-apidocs/kdecore/html/classKCmdLineArgs.html
	{
		auto arguments = a.arguments();
		if ((arguments.indexOf("-h") != -1) || (arguments.indexOf("--help") != -1)) {
			qDebug() << "QtWeb options:";
			qDebug() << "";
			qDebug() << "--maximize";
			qDebug() << "";
			qDebug() << "--url";
			qDebug() << "--user-agent";
			qDebug() << "--socks host:port";
			qDebug() << "--socks-resolver";

			return EXIT_SUCCESS;
		}

		int optionIndex = 0;

		// maximize
		if ((optionIndex = arguments.indexOf("--maximize")) != -1) {
			options.maximize = true;
		}
		// url
		if ((optionIndex = arguments.indexOf("--url")) != -1) {
			options.url = arguments.at(optionIndex + 1);
		}
		// user agent
		if ((optionIndex = arguments.indexOf("--user-agent")) != -1) {
			options.userAgent = arguments.at(optionIndex + 1);
			Wrapper::QWebPage::userAgent = options.userAgent;
		}
		// socks
		if ((optionIndex = arguments.indexOf("--socks")) != -1) {
			options.socks = arguments.at(optionIndex + 1);
		}
		// socks resolver
		if ((optionIndex = arguments.indexOf("--socks-resolver")) != -1) {
			options.socksResolver = true;
		}

		qDebug() << "Maximize" << options.maximize;
		qDebug() << "Load" << options.url;
		qDebug() << "User-agent" << options.userAgent;
		qDebug() << "Socks" << options.socks;
		qDebug() << "Socks resolver" << options.socksResolver;
	}

	// release view
	Lambda qHandler([&]() {
		view.reset();
	});
	QObject::connect(&a, SIGNAL(aboutToQuit()), &qHandler, SLOT(call()));

	view.reset(new QWebView);
	view->setPage(new Wrapper::QWebPage);

	// add "http://"
	if (options.url.indexOf("://") == -1) {
		options.url = QLatin1String("http://") + options.url;
	}

	// socks
	if (options.socks.length()) {
		QNetworkProxy proxy;
		proxy.setType(QNetworkProxy::Socks5Proxy);

		int colonPosition = options.socks.lastIndexOf(":");
		if (colonPosition == -1) {
			qDebug() << "Malformed proxy (HOST:PORT is needed)";
			return EXIT_FAILURE;
		}

		proxy.setHostName(options.socks.left(colonPosition));
		proxy.setPort(options.socks.right(options.socks.length() - 1 - colonPosition).toInt());

		if (options.socksResolver) {
			proxy.setCapabilities(proxy.capabilities() | QNetworkProxy::HostNameLookupCapability);
		} else {
			proxy.setCapabilities(proxy.capabilities() & ~QNetworkProxy::HostNameLookupCapability);
		}

		view->page()->networkAccessManager()->setProxy(proxy);

		qDebug() << "Proxy installed";
	}

	view->load(QUrl(options.url));
	if (options.maximize) {
		view->showMaximized();
	} else {
		view->show();
	}

	// execute JS
	{
		// Reinterpret pointer to Wrapper class
		Wrapper::QWebPage *page = reinterpret_cast<Wrapper::QWebPage *>(view->page());

		// async read from STDIN
		// and eval this as JS code
		stdinNotifier.reset(new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read));
		QObject::connect(&(*stdinNotifier), SIGNAL(activated(int)), new Lambda([&] {
			qDebug() << Q_FUNC_INFO;

			QTextStream stream(stdin, QIODevice::ReadOnly);
			QString jsToExecute;

			forever {
				fd_set stdinfd;
				FD_ZERO( &stdinfd );
				FD_SET( STDIN_FILENO, &stdinfd );
				struct timeval tv;
				tv.tv_sec = 0;
				tv.tv_usec = 0;
				int ready = select(1, &stdinfd, NULL, NULL, &tv);

				if (ready > 0) {
					jsToExecute += stream.readLine();
				} else {
					break;
				}
			}

			// TODO : drop code duplicating
			if (jsToExecute.startsWith(options.moveToElementPrefix)) {
				QString moveMouseToElementSelector = jsToExecute.remove(0, options.moveToElementPrefix.length());

				page->moveMouseTo(page->mainFrame()->findFirstElement(moveMouseToElementSelector));
			} else if (jsToExecute.startsWith(options.clickToElementPrefix)) {
				QString clickMouseToElementSelector = jsToExecute.remove(0, options.clickToElementPrefix.length());

				page->clickTo(page->mainFrame()->findFirstElement(clickMouseToElementSelector));
			} else if (jsToExecute.startsWith(options.cursorSetToElementPrefix)) {
				QString setCursorToElementSelector = jsToExecute.remove(0, options.cursorSetToElementPrefix.length());

				page->setCursorTo(page->mainFrame()->findFirstElement(setCursorToElementSelector));
			} else {
				view->page()->mainFrame()->evaluateJavaScript(jsToExecute);
			}
		}), SLOT(call()));
		stdinNotifier->setEnabled(true);
	}

	return a.exec();
}

<commit_msg>Make help ("--help" or "-h") available without gui.<commit_after>//
// Simple QtWeb
//
// Also it read STDIN and execute that as JS code
// And some commands: see Options.*Prefix
//

#include <QtGui/QApplication>
#include <QObject>

#include <QDebug>

#include <QWebView>
#include <QWebFrame>
#include <QUrl>
#include <QWebElement>
#include <QPoint>
#include <QRect>
#include <QMouseEvent>
#include <QCursor>
#include <QStringList>
#include <QNetworkProxy>
#include <QSocketNotifier>
#include <QTextStream>

#include <memory>

#include <signal.h>
#include <unistd.h> // STDIN_FILENO

#include "lambda.h"
#include "qwebpage.h"

std::unique_ptr<QWebView> view;
std::unique_ptr<QSocketNotifier> stdinNotifier;

struct Options {
	bool maximize;
	QString url; // default url is "google.com"
	QString userAgent; // default is that using in ga-kw
	QString socks;
	QString moveToElementPrefix;
	QString clickToElementPrefix;
	QString cursorSetToElementPrefix;
	bool socksResolver;
};
Options options = {
	false,
	QString("google.com"),
	QString("Mozilla/5.0 (X11; U; Linux i686;) Gecko/20110101 Firefox/3.6.13"),
	QString(""),
	QString("Move to "),
	QString("Click to "),
	QString("Cursor to "),
	false,
};

QStringList getCliArguments(int argc, char** argv) {
	QStringList cliArguments;

	for (int i = 0; i < argc; ++i) {
		cliArguments << QString::fromLocal8Bit(argv[i]);
	}

	return cliArguments;
}

int main(int argc, char** argv) {
	// Parse options
	// TODO: http://api.kde.org/4.x-api/kdelibs-apidocs/kdecore/html/classKCmdLineArgs.html
	{
		QStringList arguments = getCliArguments(argc, argv);
		if ((arguments.indexOf("-h") != -1) || (arguments.indexOf("--help") != -1)) {
			qDebug() << "QtWeb options:";
			qDebug() << "";
			qDebug() << "--maximize";
			qDebug() << "";
			qDebug() << "--url";
			qDebug() << "--user-agent";
			qDebug() << "--socks host:port";
			qDebug() << "--socks-resolver";

			return EXIT_SUCCESS;
		}

		int optionIndex = 0;

		// maximize
		if ((optionIndex = arguments.indexOf("--maximize")) != -1) {
			options.maximize = true;
		}
		// url
		if ((optionIndex = arguments.indexOf("--url")) != -1) {
			options.url = arguments.at(optionIndex + 1);
		}
		// user agent
		if ((optionIndex = arguments.indexOf("--user-agent")) != -1) {
			options.userAgent = arguments.at(optionIndex + 1);
			Wrapper::QWebPage::userAgent = options.userAgent;
		}
		// socks
		if ((optionIndex = arguments.indexOf("--socks")) != -1) {
			options.socks = arguments.at(optionIndex + 1);
		}
		// socks resolver
		if ((optionIndex = arguments.indexOf("--socks-resolver")) != -1) {
			options.socksResolver = true;
		}

		qDebug() << "Maximize" << options.maximize;
		qDebug() << "Load" << options.url;
		qDebug() << "User-agent" << options.userAgent;
		qDebug() << "Socks" << options.socks;
		qDebug() << "Socks resolver" << options.socksResolver;
	}

	QApplication a(argc, argv);

	// release view
	Lambda qHandler([&]() {
		view.reset();
	});
	QObject::connect(&a, SIGNAL(aboutToQuit()), &qHandler, SLOT(call()));

	view.reset(new QWebView);
	view->setPage(new Wrapper::QWebPage);

	// add "http://"
	if (options.url.indexOf("://") == -1) {
		options.url = QLatin1String("http://") + options.url;
	}

	// socks
	if (options.socks.length()) {
		QNetworkProxy proxy;
		proxy.setType(QNetworkProxy::Socks5Proxy);

		int colonPosition = options.socks.lastIndexOf(":");
		if (colonPosition == -1) {
			qDebug() << "Malformed proxy (HOST:PORT is needed)";
			return EXIT_FAILURE;
		}

		proxy.setHostName(options.socks.left(colonPosition));
		proxy.setPort(options.socks.right(options.socks.length() - 1 - colonPosition).toInt());

		if (options.socksResolver) {
			proxy.setCapabilities(proxy.capabilities() | QNetworkProxy::HostNameLookupCapability);
		} else {
			proxy.setCapabilities(proxy.capabilities() & ~QNetworkProxy::HostNameLookupCapability);
		}

		view->page()->networkAccessManager()->setProxy(proxy);

		qDebug() << "Proxy installed";
	}

	view->load(QUrl(options.url));
	if (options.maximize) {
		view->showMaximized();
	} else {
		view->show();
	}

	// execute JS
	{
		// Reinterpret pointer to Wrapper class
		Wrapper::QWebPage *page = reinterpret_cast<Wrapper::QWebPage *>(view->page());

		// async read from STDIN
		// and eval this as JS code
		stdinNotifier.reset(new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read));
		QObject::connect(&(*stdinNotifier), SIGNAL(activated(int)), new Lambda([&] {
			qDebug() << Q_FUNC_INFO;

			QTextStream stream(stdin, QIODevice::ReadOnly);
			QString jsToExecute;

			forever {
				fd_set stdinfd;
				FD_ZERO( &stdinfd );
				FD_SET( STDIN_FILENO, &stdinfd );
				struct timeval tv;
				tv.tv_sec = 0;
				tv.tv_usec = 0;
				int ready = select(1, &stdinfd, NULL, NULL, &tv);

				if (ready > 0) {
					jsToExecute += stream.readLine();
				} else {
					break;
				}
			}

			// TODO : drop code duplicating
			if (jsToExecute.startsWith(options.moveToElementPrefix)) {
				QString moveMouseToElementSelector = jsToExecute.remove(0, options.moveToElementPrefix.length());

				page->moveMouseTo(page->mainFrame()->findFirstElement(moveMouseToElementSelector));
			} else if (jsToExecute.startsWith(options.clickToElementPrefix)) {
				QString clickMouseToElementSelector = jsToExecute.remove(0, options.clickToElementPrefix.length());

				page->clickTo(page->mainFrame()->findFirstElement(clickMouseToElementSelector));
			} else if (jsToExecute.startsWith(options.cursorSetToElementPrefix)) {
				QString setCursorToElementSelector = jsToExecute.remove(0, options.cursorSetToElementPrefix.length());

				page->setCursorTo(page->mainFrame()->findFirstElement(setCursorToElementSelector));
			} else {
				view->page()->mainFrame()->evaluateJavaScript(jsToExecute);
			}
		}), SLOT(call()));
		stdinNotifier->setEnabled(true);
	}

	return a.exec();
}

<|endoftext|>


<commit_before>#include "Arduino.h"

#include "FastLED.h"
FASTLED_USING_NAMESPACE

#if FASTLED_VERSION < 3001000
#error "Requires FastLED 3.1 or later; check github for latest code."
#endif

#define DATA_PIN 3
#define CLK_PIN 4
#define LED_TYPE WS2801
#define COLOR_ORDER RGB
#define NUM_LEDS 50
CRGB leds[NUM_LEDS];

#define EYE_SET_COUNT 10
long eyeDelays[EYE_SET_COUNT];
uint8_t eyeColor[EYE_SET_COUNT];

#define BRIGHTNESS 200

unsigned long now;

void setup() {
  delay(3000); // 3 second delay for recovery
  //FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  //FastLED.setBrightness(BRIGHTNESS);

  fill_solid(leds, NUM_LEDS, 0x000000);
  FastLED.show();
  delay(3000);

  now = millis();
  for(uint8_t i=0; i<EYE_SET_COUNT; i++) {
      eyeColor[i] = 1;
      eyeDelays[i] = now + 1000;
    }
  FastLED.show();
}

void loop() {
  now = millis();
  for(uint8_t i=0; i<EYE_SET_COUNT; i++) {
    if(eyeDelays[i] < now) {
      CRGB c = 0xFF0000;
      if(eyeColor[i] == 1) {
        eyeColor[i] = 0;
        eyeDelays[i] = now + random16(2000,6000);
        c = 0x000000;
      }
      else {
        eyeColor[i] = 1;
        eyeDelays[i] = now + random16(200,3000);
      }
      leds[i*5] = c;
      leds[i*5+1] = c;
    }
  }
  FastLED.show();
}

<commit_msg>small update<commit_after>#include "Arduino.h"

#include "FastLED.h"
FASTLED_USING_NAMESPACE

#if FASTLED_VERSION < 3001000
#error "Requires FastLED 3.1 or later; check github for latest code."
#endif

#define DATA_PIN 3
#define CLK_PIN 4
#define LED_TYPE WS2801
#define COLOR_ORDER RGB
#define NUM_LEDS 50
CRGB leds[NUM_LEDS];

#define EYE_SET_COUNT 10
long eyeDelays[EYE_SET_COUNT];
uint8_t eyeColor[EYE_SET_COUNT];

#define BRIGHTNESS 200

unsigned long now;

void setup() {
  delay(3000); // 3 second delay for recovery
  //FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  //FastLED.setBrightness(BRIGHTNESS);

  fill_solid(leds, NUM_LEDS, 0x111111);
  FastLED.show();
  delay(200);

  now = millis();
  for(uint8_t i=0; i<EYE_SET_COUNT; i++) {
      eyeColor[i] = 1;
      eyeDelays[i] = now + 1000;
    }
  FastLED.show();
}

void loop() {
  now = millis();
  for(uint8_t i=0; i<EYE_SET_COUNT; i++) {
    if(eyeDelays[i] < now) {
      CRGB c = 0xFF0000;
      if(eyeColor[i] == 1) {
        eyeColor[i] = 0;
        eyeDelays[i] = now + random16(2000,6000);
        c = 0x000000;
      }
      else {
        eyeColor[i] = 1;
        eyeDelays[i] = now + random16(200,3000);
      }
      leds[i*5] = c;
      leds[i*5+1] = c;
    }
  }
  FastLED.show();
}

<|endoftext|>


<commit_before>
#include "HS.hpp"
#include <onions-common/Utils.hpp>
#include <botan/botan.h>
#include <fstream>
#include <iostream>

// Botan::LibraryInitializer init("thread_safe");

uint8_t countAvailableCPUs();

int main(int argc, char** argv)
{
  char* keyPath = 0;
  bool license = false;
  short port = 9050;
  uint8_t workers = countAvailableCPUs();

  struct poptOption po[] = {
      {
       "hsKey",
       'k',
       POPT_ARG_STRING,
       &keyPath,
       11001,
       "Specifies a path to a HS private key",
       "<path>",
      },
      {"port",
       'p',
       POPT_ARG_SHORT,
       &port,
       0,
       "SOCKS port to use for anonymous communication.",
       "<port>"},
      {"license",
       'l',
       POPT_ARG_NONE,
       &license,
       11002,
       "Print software license and exit",
       NULL},
      {"workers",
       'w',
       POPT_ARG_SHORT,
       &workers,
       0,
       "Number of worker threads to use to make a Record valid.",
       "<1 - 255>"},
      POPT_AUTOHELP{NULL, 0, 0, NULL, 0, NULL, NULL}};

  if (!Utils::parse(
          poptGetContext(NULL, argc, const_cast<const char**>(argv), po, 0)))
  {
    std::cout << "Failed to parse command-line arguments. Aborting.\n";
    return EXIT_FAILURE;
  }

  if (license)
  {
    std::cout << "Modified/New BSD License" << std::endl;
    return EXIT_SUCCESS;
  }

  if (keyPath)
  {
    HS::setKeyPath(keyPath);
    if (!Utils::loadKey(keyPath))  // test if it can be loaded
      return EXIT_FAILURE;
  }
  else
  {
    std::cerr << "Missing path to HS key! Specify with -k or --hsKey!\n";
    return EXIT_FAILURE;
  }

  auto r = HS::createRecord(workers);
  HS::sendRecord(r, port);

  return EXIT_SUCCESS;
}

uint8_t countAvailableCPUs()
{
  std::ifstream cpuinfo;
  cpuinfo.open("/proc/cpuinfo", std::fstream::in);
  if (!cpuinfo.is_open())
  {
    std::cerr << "Cannot open /proc/cpuinfo" << std::endl;
    exit(EXIT_FAILURE);
  }

  // grep -c ^processor /proc/cpuinfo
  uint8_t cpus = 0;
  std::string line;
  while (std::getline(cpuinfo, line))
    if (Utils::strBeginsWith(line, "processor"))
      cpus++;

  return cpus;
}
<commit_msg>Fix #8<commit_after>
#include "HS.hpp"
#include <onions-common/Common.hpp>
#include <onions-common/Log.hpp>
#include <onions-common/Utils.hpp>
#include <botan/botan.h>
#include <fstream>
#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
#include <pwd.h>

// Botan::LibraryInitializer init("thread_safe");

void manageRecord(uint8_t, short);
uint8_t countAvailableCPUs();

int main(int argc, char** argv)
{
  char* keyPath = 0;
  bool license = false;
  short port = 9050;
  uint8_t workers = countAvailableCPUs();

  struct poptOption po[] = {
      {
       "hsKey",
       'k',
       POPT_ARG_STRING,
       &keyPath,
       11001,
       "Specifies a path to a HS private key",
       "<path>",
      },
      {"port",
       'p',
       POPT_ARG_SHORT,
       &port,
       0,
       "SOCKS port to use for anonymous communication.",
       "<port>"},
      {"license",
       'l',
       POPT_ARG_NONE,
       &license,
       11002,
       "Print software license and exit",
       NULL},
      {"workers",
       'w',
       POPT_ARG_SHORT,
       &workers,
       0,
       "Number of worker threads to use to make a Record valid.",
       "<1 - 255>"},
      POPT_AUTOHELP{NULL, 0, 0, NULL, 0, NULL, NULL}};

  if (!Utils::parse(
          poptGetContext(NULL, argc, const_cast<const char**>(argv), po, 0)))
  {
    std::cout << "Failed to parse command-line arguments. Aborting.\n";
    return EXIT_FAILURE;
  }

  if (license)
  {
    std::cout << "Modified/New BSD License" << std::endl;
    return EXIT_SUCCESS;
  }

  if (keyPath)
  {
    HS::setKeyPath(keyPath);
    if (!Utils::loadKey(keyPath))  // test if it can be loaded
      return EXIT_FAILURE;
  }
  else
  {
    std::cerr << "Missing path to HS key! Specify with -k or --hsKey!\n";
    return EXIT_FAILURE;
  }

  manageRecord(workers, port);

  return EXIT_SUCCESS;
}

void manageRecord(uint8_t workers, short port)
{
  std::string workingDir(getpwuid(getuid())->pw_dir);
  workingDir += "/.OnioNS/";

  std::ifstream recordFile;
  recordFile.open(workingDir + "record.save", std::fstream::in);
  if (recordFile.is_open())
  {
    Log::get().notice("Loading cached Record from disk...");

    Json::Value obj;
    recordFile >> obj;
    HS::sendRecord(Common::parseRecord(obj), port);
  }
  else
  {
    auto r = HS::createRecord(workers);

    Log::get().notice("Caching Record to disk...");
    mkdir(workingDir.c_str(), 0755);
    std::fstream recordOut(workingDir + "record.save", std::fstream::out);
    recordOut << r->asJSON();
    recordOut.close();

    HS::sendRecord(r, port);
  }
}

uint8_t countAvailableCPUs()
{
  std::ifstream cpuinfo;
  cpuinfo.open("/proc/cpuinfo", std::fstream::in);
  if (!cpuinfo.is_open())
  {
    std::cerr << "Cannot open /proc/cpuinfo" << std::endl;
    exit(EXIT_FAILURE);
  }

  // grep -c ^processor /proc/cpuinfo
  uint8_t cpus = 0;
  std::string line;
  while (std::getline(cpuinfo, line))
    if (Utils::strBeginsWith(line, "processor"))
      cpus++;

  return cpus;
}
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/

#include <osgUtil/Optimizer>
#include <osgDB/ReadFile>
#include <osgProducer/Viewer>

#include <osg/Material>
#include <osg/Geode>
#include <osg/BlendFunc>
#include <osg/Depth>
#include <osg/Projection>
#include <osg/PolygonOffset>
#include <osg/MatrixTransform>
#include <osg/CameraNode>

#include <osgText/Text>

osg::Node* createHUD()
{
    osg::Geode* geode = new osg::Geode();

    std::string timesFont("fonts/arial.ttf");

    // turn lighting off for the text and disable depth test to ensure its always ontop.
    osg::StateSet* stateset = geode->getOrCreateStateSet();
    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);

    osg::Vec3 position(150.0f,800.0f,0.0f);
    osg::Vec3 delta(0.0f,-120.0f,0.0f);

    {
        osgText::Text* text = new  osgText::Text;
        geode->addDrawable( text );

        text->setFont(timesFont);
        text->setPosition(position);
        text->setText("Head Up Displays are simple :-)");

        position += delta;
    }

    {
        osgText::Text* text = new  osgText::Text;
        geode->addDrawable( text );

        text->setFont(timesFont);
        text->setPosition(position);
        text->setText("All you need to do is create your text in a subgraph.");

        position += delta;
    }

    {
        osgText::Text* text = new  osgText::Text;
        geode->addDrawable( text );

        text->setFont(timesFont);
        text->setPosition(position);
        text->setText("Disable depth test in this subgraph to ensure its always ontop.");

        position += delta;
    }

    {
        osgText::Text* text = new  osgText::Text;
        geode->addDrawable( text );

        text->setFont(timesFont);
        text->setPosition(position);
        text->setText("Then place an osg::Projection node above the subgraph\nto create an orthographic projection.");

        position += delta;
    }

    {
        osgText::Text* text = new  osgText::Text;
        geode->addDrawable( text );

        text->setFont(timesFont);
        text->setPosition(position);
        text->setText("And add an osg::ModelViewMatrix set to ABSOLUTE_RF to ensure\nit remains independent from any external model view matrices.");

        position += delta;
    }

    {
        osg::BoundingBox bb;
        for(unsigned int i=0;i<geode->getNumDrawables();++i)
        {
            bb.expandBy(geode->getDrawable(i)->getBound());
        }

        osg::Geometry* geom = new osg::Geometry;

        osg::Vec3Array* vertices = new osg::Vec3Array;
        float depth = bb.zMin()-0.1;
        vertices->push_back(osg::Vec3(bb.xMin(),bb.yMax(),depth));
        vertices->push_back(osg::Vec3(bb.xMin(),bb.yMin(),depth));
        vertices->push_back(osg::Vec3(bb.xMax(),bb.yMin(),depth));
        vertices->push_back(osg::Vec3(bb.xMax(),bb.yMax(),depth));
        geom->setVertexArray(vertices);

        osg::Vec3Array* normals = new osg::Vec3Array;
        normals->push_back(osg::Vec3(0.0f,0.0f,1.0f));
        geom->setNormalArray(normals);
        geom->setNormalBinding(osg::Geometry::BIND_OVERALL);

        osg::Vec4Array* colors = new osg::Vec4Array;
        colors->push_back(osg::Vec4(1.0f,1.0,0.8f,0.2f));
        geom->setColorArray(colors);
        geom->setColorBinding(osg::Geometry::BIND_OVERALL);

        geom->addPrimitiveSet(new osg::DrawArrays(GL_QUADS,0,4));

        osg::StateSet* stateset = geom->getOrCreateStateSet();
        stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
        //stateset->setAttribute(new osg::PolygonOffset(1.0f,1.0f),osg::StateAttribute::ON);
        stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);

        geode->addDrawable(geom);
    }

    osg::CameraNode* camera = new osg::CameraNode;

    // set the projection matrix
    camera->setProjectionMatrix(osg::Matrix::ortho2D(0,1280,0,1024));

    // set the view matrix
    camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
    camera->setViewMatrix(osg::Matrix::identity());

    // only clear the depth buffer
    camera->setClearMask(GL_DEPTH_BUFFER_BIT);

    // draw subgraph after main camera view.
    camera->setRenderOrder(osg::CameraNode::POST_RENDER);

    camera->addChild(geode);

    return camera;

}

int main( int argc, char **argv )
{

    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    // set up the usage document, in case we need to print out how to use this program.
    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates how to do Head Up Displays.");
    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] [filename] ...");
    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");

    // construct the viewer.
    osgProducer::Viewer viewer(arguments);

    // set up the value with sensible default event handlers.
    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);

    // get details on keyboard and mouse bindings used by the viewer.
    viewer.getUsage(*arguments.getApplicationUsage());

    // if user request help write it out to cout.
    if (arguments.read("-h") || arguments.read("--help"))
    {
        arguments.getApplicationUsage()->write(std::cout);
        return 1;
    }

    // any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized();

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(std::cout);
        return 1;
    }

    // read the scene from the list of file specified commandline args.
    osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles(arguments);

    osg::ref_ptr<osg::Group> group  = new osg::Group;

    // add the HUD subgraph.
    if (scene.valid()) group->addChild(scene.get());
    group->addChild(createHUD());

    // set the scene to render
    viewer.setSceneData(group.get());

    // create the windows and run the threads.
    viewer.realize();

    while( !viewer.done() )
    {
        // wait for all cull and draw threads to complete.
        viewer.sync();

        // update the scene by traversing it with the the update visitor which will
        // call all node update callbacks and animations.
        viewer.update();

        // fire off the cull and draw traversals of the scene.
        viewer.frame();

    }

    // wait for all cull and draw threads to complete before exit.
    viewer.sync();

    return 0;
}
<commit_msg>Fixed the text to match the implementation.<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/

#include <osgUtil/Optimizer>
#include <osgDB/ReadFile>
#include <osgProducer/Viewer>

#include <osg/Material>
#include <osg/Geode>
#include <osg/BlendFunc>
#include <osg/Depth>
#include <osg/PolygonOffset>
#include <osg/MatrixTransform>
#include <osg/CameraNode>

#include <osgText/Text>

osg::Node* createHUD()
{
    osg::Geode* geode = new osg::Geode();

    std::string timesFont("fonts/arial.ttf");

    // turn lighting off for the text and disable depth test to ensure its always ontop.
    osg::StateSet* stateset = geode->getOrCreateStateSet();
    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);

    osg::Vec3 position(150.0f,800.0f,0.0f);
    osg::Vec3 delta(0.0f,-120.0f,0.0f);

    {
        osgText::Text* text = new  osgText::Text;
        geode->addDrawable( text );

        text->setFont(timesFont);
        text->setPosition(position);
        text->setText("Head Up Displays are simple :-)");

        position += delta;
    }

    {
        osgText::Text* text = new  osgText::Text;
        geode->addDrawable( text );

        text->setFont(timesFont);
        text->setPosition(position);
        text->setText("All you need to do is create your text in a subgraph.");

        position += delta;
    }

    {
        osgText::Text* text = new  osgText::Text;
        geode->addDrawable( text );

        text->setFont(timesFont);
        text->setPosition(position);
        text->setText("Then place an osg::CameraNode above the subgraph\n"
                      "to create an orthographic projection.\n");

        position += delta;
    }

    {
        osgText::Text* text = new  osgText::Text;
        geode->addDrawable( text );

        text->setFont(timesFont);
        text->setPosition(position);
        text->setText("Set the CameraNode's ReferenceFrame to ABSOLUTE_RF to ensure\n"
                      "it remains independent from any external model view matrices.");

        position += delta;
    }

    {
        osgText::Text* text = new  osgText::Text;
        geode->addDrawable( text );

        text->setFont(timesFont);
        text->setPosition(position);
        text->setText("And set the CameraNode's clear mask to just clear the depth buffer.");

        position += delta;
    }

    {
        osgText::Text* text = new  osgText::Text;
        geode->addDrawable( text );

        text->setFont(timesFont);
        text->setPosition(position);
        text->setText("And finally set the CameraNode's RenderOrder to POST_RENDER\n"
                      "to make sure its drawn last.");

        position += delta;
    }

    {
        osg::BoundingBox bb;
        for(unsigned int i=0;i<geode->getNumDrawables();++i)
        {
            bb.expandBy(geode->getDrawable(i)->getBound());
        }

        osg::Geometry* geom = new osg::Geometry;

        osg::Vec3Array* vertices = new osg::Vec3Array;
        float depth = bb.zMin()-0.1;
        vertices->push_back(osg::Vec3(bb.xMin(),bb.yMax(),depth));
        vertices->push_back(osg::Vec3(bb.xMin(),bb.yMin(),depth));
        vertices->push_back(osg::Vec3(bb.xMax(),bb.yMin(),depth));
        vertices->push_back(osg::Vec3(bb.xMax(),bb.yMax(),depth));
        geom->setVertexArray(vertices);

        osg::Vec3Array* normals = new osg::Vec3Array;
        normals->push_back(osg::Vec3(0.0f,0.0f,1.0f));
        geom->setNormalArray(normals);
        geom->setNormalBinding(osg::Geometry::BIND_OVERALL);

        osg::Vec4Array* colors = new osg::Vec4Array;
        colors->push_back(osg::Vec4(1.0f,1.0,0.8f,0.2f));
        geom->setColorArray(colors);
        geom->setColorBinding(osg::Geometry::BIND_OVERALL);

        geom->addPrimitiveSet(new osg::DrawArrays(GL_QUADS,0,4));

        osg::StateSet* stateset = geom->getOrCreateStateSet();
        stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
        //stateset->setAttribute(new osg::PolygonOffset(1.0f,1.0f),osg::StateAttribute::ON);
        stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);

        geode->addDrawable(geom);
    }

    osg::CameraNode* camera = new osg::CameraNode;

    // set the projection matrix
    camera->setProjectionMatrix(osg::Matrix::ortho2D(0,1280,0,1024));

    // set the view matrix
    camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
    camera->setViewMatrix(osg::Matrix::identity());

    // only clear the depth buffer
    camera->setClearMask(GL_DEPTH_BUFFER_BIT);

    // draw subgraph after main camera view.
    camera->setRenderOrder(osg::CameraNode::POST_RENDER);

    camera->addChild(geode);

    return camera;

}

int main( int argc, char **argv )
{

    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    // set up the usage document, in case we need to print out how to use this program.
    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates how to do Head Up Displays.");
    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] [filename] ...");
    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");

    // construct the viewer.
    osgProducer::Viewer viewer(arguments);

    // set up the value with sensible default event handlers.
    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);

    // get details on keyboard and mouse bindings used by the viewer.
    viewer.getUsage(*arguments.getApplicationUsage());

    // if user request help write it out to cout.
    if (arguments.read("-h") || arguments.read("--help"))
    {
        arguments.getApplicationUsage()->write(std::cout);
        return 1;
    }

    // any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized();

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(std::cout);
        return 1;
    }

    // read the scene from the list of file specified commandline args.
    osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles(arguments);

    osg::ref_ptr<osg::Group> group  = new osg::Group;

    // add the HUD subgraph.
    if (scene.valid()) group->addChild(scene.get());
    group->addChild(createHUD());

    // set the scene to render
    viewer.setSceneData(group.get());

    // create the windows and run the threads.
    viewer.realize();

    while( !viewer.done() )
    {
        // wait for all cull and draw threads to complete.
        viewer.sync();

        // update the scene by traversing it with the the update visitor which will
        // call all node update callbacks and animations.
        viewer.update();

        // fire off the cull and draw traversals of the scene.
        viewer.frame();

    }

    // wait for all cull and draw threads to complete before exit.
    viewer.sync();

    return 0;
}
<|endoftext|>