text:
#include "oidc_filter.h"
#include <sstream>
#include <boost/beast.hpp>
#include "absl/strings/str_join.h"
#include "google/rpc/code.pb.h"
#include "spdlog/spdlog.h"
#include "src/common/http/headers.h"
#include "src/common/http/http.h"
#include "src/common/utilities/time_service.h"
#include <algorithm>

namespace beast = boost::beast;    // from <boost/beast.hpp>
namespace http = beast::http;      // from <boost/beast/http.hpp>
namespace net = boost::asio;       // from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp;  // from <boost/asio/ip/tcp.hpp>

namespace authservice {
namespace filters {
namespace oidc {

namespace {
const char *filter_name_ = "oidc";
const char *mandatory_scope_ = "openid";
const char *https_scheme_ = "https";
const int64_t NO_TIMEOUT = -1;

const std::map<const char *, const char *> standard_headers = {
    {common::http::headers::CacheControl, common::http::headers::CacheControlDirectives::NoCache},
    {common::http::headers::Pragma, common::http::headers::PragmaDirectives::NoCache},
};
}  // namespace

OidcFilter::OidcFilter(common::http::ptr_t http_ptr,
                       const config::oidc::OIDCConfig &idp_config,
                       TokenResponseParserPtr parser,
                       common::session::SessionStringGeneratorPtr session_string_generator,
                       SessionStorePtr session_store)
    : http_ptr_(http_ptr),
      idp_config_(idp_config),
      parser_(parser),
      session_string_generator_(session_string_generator),
      session_store_(session_store) {
  spdlog::trace("{}", __func__);
}

google::rpc::Code OidcFilter::Process(
    const ::envoy::service::auth::v2::CheckRequest *request,
    ::envoy::service::auth::v2::CheckResponse *response,
    boost::asio::io_context &ioc,
    boost::asio::yield_context yield) {
  spdlog::trace("{}", __func__);
  spdlog::debug(
      "Call from {}@{} to {}@{}", request->attributes().source().principal(),
      request->attributes().source().address().socket_address().address(),
      request->attributes().destination().principal(),
      request->attributes().destination().address().socket_address().address());

  if (!request->attributes().request().has_http()) {
    spdlog::info("{}: missing http in request", __func__);
    SetStandardResponseHeaders(response);
    return google::rpc::Code::INVALID_ARGUMENT;
  }

  // Verify the request was via a secure scheme.
  /* TODO: Reinstate
  if (request->attributes().request().http().scheme() != https_scheme_) {
    spdlog::info("invalid request scheme, wanted {}, got {}", https_scheme_,
                 request->attributes().request().http().scheme());
    return google::rpc::Code::INVALID_ARGUMENT;
  }
  */

  auto httpRequest = request->attributes().request().http();
  auto headers = httpRequest.headers();
  auto session_id_optional = GetSessionIdFromCookie(headers);

  // If the request is for the configured logout path,
  // then logout and redirect to the configured logout redirect uri.
  if (MatchesLogoutRequest(request)) {
    spdlog::info("{}: Handling logout", __func__);
    if (session_id_optional.has_value()) {
      spdlog::info("{}: Removing session info from session store during logout", __func__);
      try {
        session_store_->RemoveSession(session_id_optional.value());
      } catch (SessionError &err) {
        spdlog::error("{}: Session error in RemoveSession: {}", __func__, err.what());
        return SessionErrorResponse(response, err);
      }
    }
    SetLogoutHeaders(response);
    spdlog::info("{}: Logout complete. Sending user to re-authenticate.", __func__);
    return google::rpc::Code::UNAUTHENTICATED;
  }

  // If the id_token header already exists,
  // then let request continue.
  // (It is up to the downstream system to validate the header is valid.)
  if (headers.contains(idp_config_.id_token().header())) {
    spdlog::info(
        "{}: ID Token header already present. Allowing request to proceed without adding any additional headers.",
        __func__);
    return google::rpc::Code::OK;
  }

  // If the request does not have a session_id cookie,
  // then generate a session id, put it in a header, and redirect for login.
  if (!session_id_optional.has_value()) {
    spdlog::info("{}: No session cookie detected. Generating new session and sending user to re-authenticate.",
                 __func__);
    return RedirectToIdp(response, httpRequest);
  }

  auto session_id = session_id_optional.value();

  // If the request path is the callback for receiving the authorization code, has a session id
  // then exchange it for tokens and redirects end-user back to their originally requested URL.
  if (MatchesCallbackRequest(request)) {
    return RetrieveToken(request, response, session_id, ioc, yield);
  }

  spdlog::trace("{}: attempting session retrieval", __func__);
  std::shared_ptr<TokenResponse> token_response_ptr;
  try {
    token_response_ptr = session_store_->GetTokenResponse(session_id);
  } catch (SessionError &err) {
    spdlog::error("{}: Session error in GetTokenResponse: {}", __func__, err.what());
    return SessionErrorResponse(response, err);
  }

  spdlog::trace("{}: checking retrieved token response for expected tokens", __func__);
  // If the user has a session_id cookie but there are no required tokens in the session store associated with it,
  // then redirect for login.
  if (!RequiredTokensPresent(token_response_ptr)) {
    spdlog::info("{}: Required tokens are not present. Sending user to re-authenticate.", __func__);
    return RedirectToIdp(response, httpRequest, session_id);
  }

  auto token_response = *token_response_ptr;

  // If both ID & Access token are still unexpired,
  // then allow the request to proceed (no need to intervene).
  spdlog::trace("{}: checking token expiration", __func__);
  if (!RequiredTokensExpired(token_response)) {
    AddTokensToRequestHeaders(response, token_response);
    spdlog::info("{}: Tokens not expired. Allowing request to proceed.", __func__);
    return google::rpc::Code::OK;
  }

  // If there is no refresh token,
  // then direct the request to the identity provider for authentication
  auto refresh_token_optional = token_response.RefreshToken();
  if (!refresh_token_optional.has_value()) {
    spdlog::info(
        "{}: A token was expired, but session did not contain a refresh token. Sending user to re-authenticate.",
        __func__);
    return RedirectToIdp(response, httpRequest, session_id);
  }

  // If the user has an unexpired refresh token then use it to request a fresh token_response.
  // If successful, allow the request to proceed. If unsuccessful, redirect for login.
  spdlog::trace("{}: attempting to refresh token", __func__);
  auto refreshed_token_response = RefreshToken(token_response, refresh_token_optional.value(), ioc, yield);
  if (refreshed_token_response) {
    try {
      spdlog::trace("{}: storing refreshed token", __func__);
      session_store_->SetTokenResponse(session_id, refreshed_token_response);
    } catch (SessionError &err) {
      spdlog::error("{}: Session error in SetTokenResponse: {}", __func__, err.what());
      return SessionErrorResponse(response, err);
    }
    spdlog::info("{}: Updated session store with newly refreshed access token. Allowing request to proceed.",
                 __func__);
    AddTokensToRequestHeaders(response, *refreshed_token_response);
    return google::rpc::Code::OK;
  } else {
    spdlog::info(
        "{}: Attempt to refresh access token did not yield refreshed token. Sending user to re-authenticate.",
        __func__);
    return RedirectToIdp(response, httpRequest, session_id);
  }
}

google::rpc::Code OidcFilter::SessionErrorResponse(CheckResponse *response, const SessionError &err) {
  response->mutable_denied_response()->mutable_status()->set_code(envoy::type::Unauthorized);
  response->mutable_denied_response()->mutable_body()->append(
      "There was an error accessing your session data. Try again later.");
  return google::rpc::UNAUTHENTICATED;
}

google::rpc::Code OidcFilter::RedirectToIdp(
    CheckResponse *response,
    const AttributeContext_HttpRequest &httpRequest,
    absl::optional<std::string> old_session_id) {
  if (old_session_id.has_value()) {
    try {
      // remove old session and regenerate session_id to prevent session fixation attacks
      session_store_->RemoveSession(old_session_id.value());
    } catch (SessionError &err) {
      spdlog::error("{}: Session error in RemoveSession: {}", __func__, err.what());
      return SessionErrorResponse(response, err);
    }
  }

  auto session_id = session_string_generator_->GenerateSessionId();
  auto state = session_string_generator_->GenerateState();
  auto nonce = session_string_generator_->GenerateNonce();

  std::set<absl::string_view> scopes = {mandatory_scope_};
  for (const auto &scope : idp_config_.scopes()) {
    scopes.insert(scope);
  }

  auto encoded_scopes = absl::StrJoin(scopes, " ");
  std::multimap<absl::string_view, absl::string_view> params = {
      {"response_type", "code"},
      {"scope", encoded_scopes},
      {"client_id", idp_config_.client_id()},
      {"nonce", nonce},
      {"state", state},
      {"redirect_uri", idp_config_.callback_uri()}};
  auto query = common::http::Http::EncodeQueryData(params);

  SetStandardResponseHeaders(response);

  auto redirect_location = absl::StrJoin({idp_config_.authorization_uri(), query}, "?");
  SetRedirectHeaders(redirect_location, response);

  try {
    session_store_->SetAuthorizationState(session_id.data(),
                                          std::make_shared<AuthorizationState>(state,
                                                                               nonce,
                                                                               GetRequestUrl(httpRequest)));
  } catch (SessionError &err) {
    spdlog::error("{}: Session error in SetAuthorizationState: {}", __func__, err.what());
    return SessionErrorResponse(response, err);
  }

  SetSessionIdCookie(response, session_id.data());

  return google::rpc::UNAUTHENTICATED;
}

std::string OidcFilter::GetRequestUrl(const AttributeContext_HttpRequest &http_request) {
  auto request_without_query =
      std::string(https_scheme_) + "://" + http_request.host() + http_request.path();

  if (http_request.query().empty()) {
    return request_without_query;
  }

  return absl::StrJoin({request_without_query, http_request.query()}, "?");
}

void OidcFilter::SetHeader(
    ::google::protobuf::RepeatedPtrField<
        ::envoy::api::v2::core::HeaderValueOption> *headers,
    absl::string_view name, absl::string_view value) {
  auto header_value_option = headers->Add();
  auto header = header_value_option->mutable_header();
  header->set_key(name.data());
  header->set_value(value.data());
}

void OidcFilter::SetStandardResponseHeaders(
    ::envoy::service::auth::v2::CheckResponse *response) {
  for (auto to_add : standard_headers) {
    SetHeader(response->mutable_denied_response()->mutable_headers(),
              to_add.first, to_add.second);
  }
}

void OidcFilter::SetRedirectHeaders(
    absl::string_view redirect_url,
    ::envoy::service::auth::v2::CheckResponse *response) {
  response->mutable_denied_response()->mutable_status()->set_code(
      envoy::type::StatusCode::Found);
  SetHeader(response->mutable_denied_response()->mutable_headers(),
            common::http::headers::Location, redirect_url.data());
}

std::string OidcFilter::EncodeCookieTimeoutDirective(int64_t timeout) {
  return std::string(common::http::headers::SetCookieDirectives::MaxAge) + "=" + std::to_string(timeout);
}

std::string OidcFilter::GetCookieName(const std::string &cookie) const {
  if (idp_config_.cookie_name_prefix() == "") {
    return "__Host-authservice-" + cookie + "-cookie";
  }
  return "__Host-" + idp_config_.cookie_name_prefix() + "-authservice-" +
      cookie + "-cookie";
}

std::string OidcFilter::GetSessionIdCookieName() const {
  return GetCookieName("session-id");
}

std::string OidcFilter::EncodeHeaderValue(const std::string &preamble,
                                          const std::string &value) {
  if (preamble != "") {
    return preamble + " " + value;
  }
  return value;
}

void OidcFilter::SetCookie(
    ::google::protobuf::RepeatedPtrField<::envoy::api::v2::core::HeaderValueOption> *responseHeaders,
    const std::string &cookie_name,
    absl::string_view value,
    int64_t timeout
) {
  std::set<std::string> cookie_directives = GetCookieDirectives(timeout);
  std::set<absl::string_view> cookie_directives_string_view(cookie_directives.begin(), cookie_directives.end());
  auto cookie_header = common::http::Http::EncodeSetCookie(cookie_name, value, cookie_directives_string_view);
  SetHeader(responseHeaders, common::http::headers::SetCookie, cookie_header);
}

void OidcFilter::DeleteCookie(
    ::google::protobuf::RepeatedPtrField<::envoy::api::v2::core::HeaderValueOption> *responseHeaders,
    const std::string &cookieName
) {
  SetCookie(responseHeaders, cookieName, "deleted", 0);
}

std::set<std::string> OidcFilter::GetCookieDirectives(int64_t timeout) {
  std::set<std::string> token_set_cookie_header_directives =
      {
          common::http::headers::SetCookieDirectives::HttpOnly,
          common::http::headers::SetCookieDirectives::SameSiteLax,
          common::http::headers::SetCookieDirectives::Secure,
          "Path=/"
      };

  if (timeout != NO_TIMEOUT) {
    std::string timeoutDirective = EncodeCookieTimeoutDirective(timeout);
    token_set_cookie_header_directives.insert(timeoutDirective);
  }
  return token_set_cookie_header_directives;
}

absl::optional<std::string> OidcFilter::CookieFromHeaders(
    const ::google::protobuf::Map<::std::string, ::std::string> &headers,
    const std::string &cookie) {
  const auto &cookie_header_value = headers.find(common::http::headers::Cookie);
  if (cookie_header_value == headers.cend()) {
    return absl::nullopt;
  }
  auto cookies = common::http::Http::DecodeCookies(cookie_header_value->second);
  if (!cookies.has_value()) {
    return absl::nullopt;
  }
  const auto &iter = cookies->find(cookie);
  if (iter != cookies->cend()) {
    return iter->second;
  }
  return absl::nullopt;
}

void OidcFilter::SetLogoutHeaders(CheckResponse *response) {
  SetRedirectHeaders(idp_config_.logout().redirect_uri(), response);
  SetStandardResponseHeaders(response);
  auto responseHeaders = response->mutable_denied_response()->mutable_headers();
  DeleteCookie(responseHeaders, GetSessionIdCookieName());
}

void OidcFilter::AddTokensToRequestHeaders(CheckResponse *response, TokenResponse &tokenResponse) {
  auto id_token = tokenResponse.IDToken().jwt_;
  SetIdTokenHeader(response, id_token);
  if (idp_config_.has_access_token() && tokenResponse.AccessToken().has_value()) {
    SetAccessTokenHeader(response, tokenResponse.AccessToken().value());
  }
}

bool OidcFilter::RequiredTokensPresent(std::shared_ptr<TokenResponse> token_response) {
  return token_response &&
      (!idp_config_.has_access_token() || token_response->AccessToken().has_value());
}

bool OidcFilter::RequiredTokensExpired(TokenResponse &token_response) {
  common::utilities::TimeService timeService;
  int64_t now_seconds = timeService.GetCurrentTimeInSecondsSinceEpoch();

  if (token_response.GetIDTokenExpiry() < now_seconds) {
    return true;
  }

  // Don't require expires_in. Rely on presence of field to determine if check should be made.
  //  The oauth spec does not require a expires_in https://tools.ietf.org/html/rfc6749#section-5.1
  const absl::optional<int64_t> &accessTokenExpiry = token_response.GetAccessTokenExpiry();
  return idp_config_.has_access_token() && accessTokenExpiry.has_value() && accessTokenExpiry.value() < now_seconds;
}

bool OidcFilter::MatchesLogoutRequest(const ::envoy::service::auth::v2::CheckRequest *request) {
  return idp_config_.has_logout() && RequestPath(request) == idp_config_.logout().path();
}

std::string OidcFilter::RequestPath(const CheckRequest *request) {
  return common::http::PathQueryFragment(request->attributes().request().http().path()).Path();
}

std::string OidcFilter::RequestQueryString(const CheckRequest *request) {
  return common::http::PathQueryFragment(request->attributes().request().http().path()).Query();
}

bool OidcFilter::MatchesCallbackRequest(const ::envoy::service::auth::v2::CheckRequest *request) {
  auto path = request->attributes().request().http().path();
  auto request_host = request->attributes().request().http().host();
  auto scheme = request->attributes().request().http().scheme();
  spdlog::trace("{}: checking handler for {}://{}{}", __func__, scheme, request_host, path);

  auto request_path_parts = common::http::PathQueryFragment(path);
  auto configured_uri = idp_config_.callback_uri();
  auto parsed_uri = common::http::Uri(configured_uri);
  auto configured_port = parsed_uri.GetPort();
  auto configured_hostname = parsed_uri.GetHost();
  auto configured_scheme = parsed_uri.GetScheme();
  auto configured_path = parsed_uri.GetPathQueryFragment();

  std::stringstream buf;
  buf << configured_hostname << ':' << std::dec << configured_port;

  std::string configured_callback_host_with_port = buf.str();

  bool path_matches = request_path_parts.Path() == configured_path;

  bool host_matches = request_host == configured_callback_host_with_port ||
      (configured_scheme == "https" && configured_port == 443 && request_host == configured_hostname);

  auto matches_callback = path_matches && host_matches;

  spdlog::trace("{}: matches_callback: {} ", __func__, matches_callback);

  return matches_callback;
}

absl::optional<std::string> OidcFilter::GetSessionIdFromCookie(const ::google::protobuf::Map<::std::string,
                                                                                ::std::string> &headers) {
  auto cookie_name = GetSessionIdCookieName();
  auto cookie = CookieFromHeaders(headers, cookie_name);
  if (cookie.has_value()) {
    return cookie.value();
  } else {
    spdlog::info("{}: {} session id cookie missing", __func__, cookie_name);
    return absl::nullopt;
  }
}

void OidcFilter::SetAccessTokenHeader(::envoy::service::auth::v2::CheckResponse *response,
                                      const std::string &access_token) {
  auto value = EncodeHeaderValue(idp_config_.access_token().preamble(), access_token);
  SetHeader(response->mutable_ok_response()->mutable_headers(), idp_config_.access_token().header(), value);
}

void OidcFilter::SetIdTokenHeader(::envoy::service::auth::v2::CheckResponse *response,
                                  const std::string &id_token) {
  auto value = EncodeHeaderValue(idp_config_.id_token().preamble(), id_token);
  SetHeader(response->mutable_ok_response()->mutable_headers(), idp_config_.id_token().header(), value);
}

void OidcFilter::SetSessionIdCookie(::envoy::service::auth::v2::CheckResponse *response, std::string session_id) {
  SetCookie(response->mutable_denied_response()->mutable_headers(), GetSessionIdCookieName(), session_id, NO_TIMEOUT);
}

// https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokens
std::shared_ptr<TokenResponse> OidcFilter::RefreshToken(
    const TokenResponse &existing_token_response,
    const std::string &refresh_token,
    boost::asio::io_context &ioc,
    boost::asio::yield_context yield) {

  std::map<absl::string_view, absl::string_view> headers = {
      {common::http::headers::ContentType, common::http::headers::ContentTypeDirectives::FormUrlEncoded},
  };

  std::multimap<absl::string_view, absl::string_view> params = {
      {"client_id", idp_config_.client_id()},
      {"client_secret", idp_config_.client_secret()},
      {"grant_type", "refresh_token"},
      {"refresh_token", refresh_token},
      // according to this link, omitting the `scope` param should return new
      // tokens with the previously requested `scope`
      // https://www.oauth.com/oauth2-servers/access-tokens/refreshing-access-tokens/
  };

  spdlog::info("{}: POSTing to refresh access token", __func__);
  auto retrieved_token_response = http_ptr_->Post(
      idp_config_.token_uri(), headers, common::http::Http::EncodeFormData(params),
      idp_config_.trusted_certificate_authority(), idp_config_.proxy_uri(), ioc, yield);

  if (retrieved_token_response == nullptr) {
    spdlog::warn("{}: Received null pointer as response from identity provider.", __func__);
    return nullptr;
  }

  http::status status = retrieved_token_response->result();
  if (status != boost::beast::http::status::ok) {
    spdlog::warn("{}: Received (non-OK) status {} from identity provider when refreshing the access token.", __func__,
                 std::to_string(static_cast<unsigned>(status)));
    return nullptr;
  }

  return parser_->ParseRefreshTokenResponse(existing_token_response, retrieved_token_response->body());
}

// Performs an HTTP POST and prints the response
google::rpc::Code OidcFilter::RetrieveToken(
    const ::envoy::service::auth::v2::CheckRequest *request,
    ::envoy::service::auth::v2::CheckResponse *response,
    absl::string_view session_id,
    boost::asio::io_context &ioc,
    boost::asio::yield_context yield) {
  spdlog::trace("{}", __func__);

  SetStandardResponseHeaders(response);

  // Extract expected state and authorization code from request
  auto query = RequestQueryString(request);
  auto query_data = common::http::Http::DecodeQueryData(query);
  if (!query_data.has_value()) {
    spdlog::info("{}: form data is invalid", __func__);
    return google::rpc::Code::INVALID_ARGUMENT;
  }
  const auto state_from_request = query_data->find("state");
  const auto code_from_request = query_data->find("code");
  if (state_from_request == query_data->end() || code_from_request == query_data->end()) {
    spdlog::info("{}: form data does not contain expected state and code parameters", __func__);
    return google::rpc::Code::INVALID_ARGUMENT;
  }

  std::shared_ptr<AuthorizationState> authorization_state;
  try {
    authorization_state = session_store_->GetAuthorizationState(session_id);
  } catch (SessionError &err) {
    spdlog::error("{}: Session error in GetAuthorizationState: {}", __func__, err.what());
    return SessionErrorResponse(response, err);
  }

  if (!authorization_state) {
    spdlog::info("{}: Missing state, nonce, and original url requested by the user. Cannot redirect.", __func__);
    response->mutable_denied_response()->mutable_status()->set_code(envoy::type::StatusCode::BadRequest);
    response->mutable_denied_response()->set_body("Oops, your session has expired. Please try again.");
    return google::rpc::Code::UNAUTHENTICATED;
  }

  // Compare state from request and session
  if (state_from_request->second != authorization_state->GetState()) {
    spdlog::info("{}: mismatch state", __func__);
    return google::rpc::Code::INVALID_ARGUMENT;
  }

  // Build headers
  auto authorization = common::http::Http::EncodeBasicAuth(idp_config_.client_id(), idp_config_.client_secret());
  std::map<absl::string_view, absl::string_view> headers = {
      {common::http::headers::ContentType, common::http::headers::ContentTypeDirectives::FormUrlEncoded},
      {common::http::headers::Authorization, authorization},
  };

  // Build body
  std::multimap<absl::string_view, absl::string_view> params = {
      {"code", code_from_request->second},
      {"redirect_uri", idp_config_.callback_uri()},
      {"grant_type", "authorization_code"},
  };

  auto retrieve_token_response = http_ptr_->Post(
      idp_config_.token_uri(), headers, common::http::Http::EncodeFormData(params),
      idp_config_.trusted_certificate_authority(), idp_config_.proxy_uri(), ioc, yield);
  if (retrieve_token_response == nullptr) {
    spdlog::info("{}: HTTP error encountered: {}", __func__,
                 "IdP connection error");
    return google::rpc::Code::INTERNAL;
  }
  if (retrieve_token_response->result() != boost::beast::http::status::ok) {
    spdlog::info("{}: HTTP token response error: {}", __func__,
                 retrieve_token_response->result_int());
    return google::rpc::Code::UNKNOWN;
  } else {
    auto nonce = authorization_state->GetNonce();
    auto token_response = parser_->Parse(idp_config_.client_id(), nonce, retrieve_token_response->body());
    if (!token_response) {
      spdlog::info("{}: Invalid token response", __func__);
      return google::rpc::Code::INVALID_ARGUMENT;
    }

    // If access_token forwarding is configured but there is not an access token in the token response
    // then there is a problem
    if (idp_config_.has_access_token()) {
      auto access_token = token_response->AccessToken();
      if (!access_token.has_value()) {
        spdlog::info("{}: Missing expected access_token", __func__);
        return google::rpc::Code::INVALID_ARGUMENT;
      }
    }

    try {
      session_store_->ClearAuthorizationState(session_id);
    } catch (SessionError &err) {
      spdlog::error("{}: Session error in ClearAuthorizationState: {}", __func__, err.what());
      return SessionErrorResponse(response, err);
    }

    spdlog::info("{}: Saving token response to session store", __func__);
    try {
      session_store_->SetTokenResponse(session_id, token_response);
    } catch (SessionError &err) {
      spdlog::error("{}: Session error in SetTokenResponse: {}", __func__, err.what());
      return SessionErrorResponse(response, err);
    }

    SetRedirectHeaders(authorization_state->GetRequestedUrl(), response);
    return google::rpc::Code::UNAUTHENTICATED;
  }
}

absl::string_view OidcFilter::Name() const { return filter_name_; }

}  // namespace oidc
}  // namespace filters
}  // namespace authservice

ext: cc

max_stars_repo_name: joshuatcasey/authservice

max_issues_repo_name: joshuatcasey/authservice

max_forks_repo_name: joshuatcasey/authservice


text:
#include <boost/test/unit_test.hpp>

#include <iostream>
#include <iomanip>
#include <sstream>
#include <stdexcept>

#include <koinos/serialization.hpp>
#include <koinos/block_store/block_store.pb.h>
#include <koinos/common.pb.h>
#include <koinos/test_map.pb.h>

struct proto_fixture{};

BOOST_FIXTURE_TEST_SUITE( proto_tests, proto_fixture )

BOOST_AUTO_TEST_CASE( canonical_test )
{
   BOOST_TEST_MESSAGE( "Testing canonical serialization" );

   // {"id": "foo", "height": 1, "previous": "bar"}
   constexpr char canon_cstr[] = { 0x0A, 0x03, 0x66, 0x6F, 0x6F, 0x10, 0x01, 0x1a, 0x03, 0x62, 0x61, 0x72 };
   std::string canon( canon_cstr, sizeof( canon_cstr ) );

   koinos::block_topology topo;
   topo.set_id( "foo" );
   topo.set_height( 1 );
   topo.set_previous( "bar" );

   BOOST_CHECK( serialize_canonically( topo ) == canon );

   std::stringstream ss;
   serialize_canonically( ss, topo );

   BOOST_CHECK( ss.str() == canon );

   koinos::test_map tm;
   auto m = tm.mutable_im_the_map();
   (*m)[0] = "foo";
   (*m)[1] = "bar";

   try
   {
      auto ser = serialize_canonically( tm );
      BOOST_CHECK( false );
   }
   catch( std::runtime_error& ) {}

   try
   {
      std::stringstream ss;
      serialize_canonically( ss, tm );
      BOOST_CHECK( false );
   }
   catch( std::runtime_error& ) {}

   koinos::map_wrapper mw;
   m = mw.mutable_nested_map()->mutable_im_the_map();
   (*m)[0] = "foo";
   (*m)[1] = "bar";

   try
   {
      auto ser = serialize_canonically( mw );
      BOOST_CHECK( false );
   }
   catch( std::runtime_error& ) {}

   try
   {
      std::stringstream ss;
      serialize_canonically( ss, mw );
      BOOST_CHECK( false );
   }
   catch( std::runtime_error& ) {}
}

std::string to_hex( const std::string& s )
{
   std::stringstream stream;
   stream << "0x" << std::hex << std::setfill( '0' );
   for ( const auto& c : s )
   {
      stream << std::setw( 2 ) << static_cast< unsigned int >( static_cast< unsigned char >( c ) );
   }
   return stream.str();
}

BOOST_AUTO_TEST_CASE( unknown_field_test )
{
   koinos::block_store::block_item bi;
   koinos::block_store::block_record br;

   br.set_block_id( std::string( "123" ) );
   br.set_block_height( 123 );

   koinos::protocol::block b;
   b.set_id( std::string( "456" ) );

   koinos::protocol::block_receipt r;
   r.set_id( std::string( "456" ) );

   *br.mutable_block() = b;
   *br.mutable_receipt() = r;

   *br.add_previous_block_ids() = std::string( "789" );
   *br.add_previous_block_ids() = std::string( "101112" );

   bi.ParseFromString( koinos::serialize_canonically( br ) );

   BOOST_REQUIRE_EQUAL( koinos::serialize_canonically( bi ), koinos::serialize_canonically( br ) );

   // Put the repeated fields first and then check canonical serialization
   constexpr char noncanon_cstr[] = { 0x2a, 0x03, 0x37, 0x38, 0x39, 0x2a, 0x06, 0x31, 0x30, 0x31, 0x31, 0x31, 0x32, 0x0a, 0x03, 0x31, 0x32, 0x33, 0x10, 0x7b, 0x1a, 0x05, 0x0a, 0x03, 0x34, 0x35, 0x36, 0x22, 0x05, 0x0a, 0x03, 0x34, 0x35, 0x36 };

   koinos::block_store::block_item bi2;
   bi2.ParseFromArray( noncanon_cstr, sizeof( noncanon_cstr ) );

   BOOST_CHECK_EQUAL( koinos::serialize_canonically( bi2 ), koinos::serialize_canonically( br ) );
}

BOOST_AUTO_TEST_SUITE_END()

ext: cpp

max_stars_repo_name: koinos/koinos-proto-cpp

max_issues_repo_name: koinos/koinos-proto-cpp

max_forks_repo_name: koinos/koinos-proto-cpp


text:
/*
 * Copyright (c) 2015, Jonathan Ventura
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef POLYNOMIAL_HPP
#define POLYNOMIAL_HPP

#include <Eigen/Core>
#include <unsupported/Eigen/Polynomials>
#include <vector>

#include <Polynomial/PolynomialInternal.hpp>

namespace polynomial
{
    /**
     * Polynomial
     *
     * Templated class for representing a polynomial expression.
     *
     * The template parameter indicates the degree of polynomial.  An n-th degree polynomial has n+1 coefficients.
     *
     * The coefficients are stored in this order:
     * c0 x^deg + c1 x^(deg-1) + ...
     *
     * A dynamically-sized version is available: Polynomial<Eigen::Dynamic>
     *
     * Note that the static and dynamic versions should not be mixed, i.e. do not add a dynamic polynomial to a static one.
     */
    template<int deg>
    class Polynomial
    {
        Eigen::Matrix<double,deg+1,1> coef;
    public:
        Polynomial()
        : coef( Eigen::Matrix<double,1,deg+1>::Zero() )
        {

        }

        Polynomial( const Eigen::Matrix<double,deg+1,1> &coefin )
        : coef( coefin )
        {

        }

        Polynomial( const Polynomial<deg> &polyin )
        : coef( polyin.coef )
        {

        }

        Polynomial( const double *coefin )
        : coef( Internal::vecmap<deg+1>( coefin ) )
        {

        }

        const Eigen::Matrix<double,deg+1,1> &coefficients() const
        {
            return coef;
        }

        Eigen::Matrix<double,deg+1,1> &coefficients()
        {
            return coef;
        }

        template<int degin>
        Polynomial<Internal::max<degin,deg>::value> operator+(const Polynomial<degin> &poly) const
        {
            Polynomial<Internal::max<degin,deg>::value> p;
            p.coefficients().tail(degin+1) = poly.coefficients();
            p.coefficients().tail(deg+1) += coef;
            return p;
        }

        template<int degin>
        Polynomial<Internal::max<degin,deg>::value> operator-(const Polynomial<degin> &poly) const
        {
            Polynomial<Internal::max<degin,deg>::value> p;
            p.coefficients().tail(deg+1) = coef;
            p.coefficients().tail(degin+1) -= poly.coefficients();
            return p;
        }

        template<int degin>
        Polynomial<degin+deg> operator*(const Polynomial<degin> &poly) const
        {
            Polynomial<degin+deg> p;
            Internal::PolyConv<deg,degin>::compute(p.coefficients(),coef,poly.coefficients());
            return p;
        }

        Polynomial<deg> operator*(const double c) const
        {
            return Polynomial<deg>(coef*c);
        }

        double eval(double x) const
        {
            return Internal::PolyVal<deg>::compute(coef,x);
        }

        void realRoots(std::vector<double> &roots) const
        {
            if ( coef[0] == 0 )
            {
                Internal::RootFinder<deg-1>::compute(coef.tail(deg),roots);
            } else {
                Internal::RootFinder<deg>::compute(coef,roots);
            }
        }

        void realRootsSturm(const double lb, const double ub, std::vector<double> &roots) const
        {
            if ( coef[0] == 0 )
            {
                Internal::SturmRootFinder<deg-1> sturm( coef.tail(deg) );
                sturm.realRoots( lb, ub, roots );
            } else {
                Internal::SturmRootFinder<deg> sturm( coef );
                sturm.realRoots( lb, ub, roots );
            }
        }

        void rootBounds( double &lb, double &ub )
        {
            Eigen::Matrix<double,deg,1> mycoef = coef.tail(deg).array().abs();
            mycoef /= fabs(coef(0));
            mycoef(0) += 1.;
            ub = mycoef.maxCoeff();
            lb = -ub;
        }
    };

    template <>
    class Polynomial<Eigen::Dynamic>
    {
        Eigen::VectorXd coef;
    public:
        Polynomial(const int deg)
        : coef( Eigen::VectorXd::Zero(deg+1) )
        {

        }

        Polynomial( const Eigen::VectorXd &coefin)
        : coef( coefin )
        {

        }

        Polynomial(const Polynomial<Eigen::Dynamic> &polyin)
        : coef( polyin.coef )
        {

        }

        const Eigen::VectorXd &coefficients() const
        {
            return coef;
        }

        Eigen::VectorXd &coefficients()
        {
            return coef;
        }

        Polynomial<Eigen::Dynamic> operator+(const Polynomial<Eigen::Dynamic> &poly) const
        {
            int deg = coef.rows()-1;
            int degin = poly.coef.rows()-1;
            Polynomial<Eigen::Dynamic> p( std::max(deg,degin) );
            p.coef.tail(degin+1) = poly.coef;
            p.coef.tail(deg+1) += coef;
            return p;
        }

        Polynomial<Eigen::Dynamic> operator-(const Polynomial<Eigen::Dynamic> &poly) const
        {
            int deg = coef.rows()-1;
            int degin = poly.coef.rows()-1;
            Polynomial<Eigen::Dynamic> p( std::max(deg,degin) );
            p.coef.tail(deg+1) = coef;
            p.coef.tail(degin+1) -= poly.coef;
            return p;
        }

        Polynomial<Eigen::Dynamic> operator*(const Polynomial<Eigen::Dynamic> &poly) const
        {
            int deg = coef.rows()-1;
            int degin = poly.coef.rows()-1;
            Polynomial<Eigen::Dynamic> p( deg+degin );
            Internal::PolyConv<Eigen::Dynamic,Eigen::Dynamic>::compute(p.coef,coef,poly.coef);
            return p;
        }

        Polynomial<Eigen::Dynamic> operator*(const double c) const
        {
            return Polynomial<Eigen::Dynamic>(coef*c);
        }

        double eval(double x) const
        {
            return Internal::PolyVal<Eigen::Dynamic>::compute(coef,x);
        }

        void realRoots(std::vector<double> &roots) const
        {
            if ( coef[0] == 0 )
            {
                int deg = coef.rows()-1;
                Internal::RootFinder<Eigen::Dynamic>::compute(coef.tail(deg),roots);
            } else {
                Internal::RootFinder<Eigen::Dynamic>::compute(coef,roots);
            }
        }

        void realRootsSturm(const double lb, const double ub, std::vector<double> &roots) const
        {
            if ( coef[0] == 0 )
            {
                int deg = coef.rows()-1;
                Internal::SturmRootFinder<Eigen::Dynamic> sturm( coef.tail(deg) );
                sturm.realRoots( lb, ub, roots );
            } else {
                Internal::SturmRootFinder<Eigen::Dynamic> sturm( coef );
                sturm.realRoots( lb, ub, roots );
            }
        }

        void rootBounds( double &lb, double &ub )
        {
            int deg = coef.rows()-1;
            Eigen::VectorXd mycoef = coef.tail(deg).array().abs()/fabs(coef(0));
            mycoef(0) += 1.;
            ub = mycoef.maxCoeff();
            lb = -ub;
        }
    };

} // end namespace Polynomial

#endif

ext: hpp

max_stars_repo_name: jonathanventura/polynomial

max_issues_repo_name: jonathanventura/polynomial

max_forks_repo_name: jonathanventura/polynomial


text:
//! \file
//! \brief Libre Office Cell Related Internal Functions
#ifndef _LIBRE_CELL_FUNC_CPP
#define _LIBRE_CELL_FUNC_CPP

//          Copyright Anurag Ghosh 2015.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#include <string>
#include <iostream>
#include <cstdlib>

#include <boost/filesystem.hpp>
#include <boost/throw_exception.hpp>

#include <sal/main.h>

#include <com/sun/star/awt/FontSlant.hpp>

#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/bridge/XUnoUrlResolver.hpp>

#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>

#include <com/sun/star/registry/XSimpleRegistry.hpp>

#include <com/sun/star/sheet/XSpreadsheet.hpp>

#include <com/sun/star/table/XCell.hpp>
#include <com/sun/star/table/CellContentType.hpp>
#include <com/sun/star/table/CellHoriJustify.hpp>
#include <com/sun/star/table/CellVertJustify.hpp>

#include <com/sun/star/table/TableBorder.hpp>
#include <com/sun/star/table/BorderLine.hpp>

#include <com/sun/star/table/TableBorder2.hpp>
#include <com/sun/star/table/BorderLine2.hpp>
#include <com/sun/star/table/BorderLineStyle.hpp>

#include <com/sun/star/text/XText.hpp>

#include <boost/document/detail/cell_content_type.hpp>
#include <boost/document/detail/cell_alignment_type.hpp>
#include <boost/document/detail/cell_border_type.hpp>
#include <boost/document/detail/cell_format_property.hpp>

#include <boost/document/detail/document_exception.hpp>

using namespace com::sun::star;
using namespace com::sun::star::awt;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::beans;
using namespace com::sun::star::bridge;
using namespace com::sun::star::registry;
using namespace com::sun::star::sheet;
using namespace com::sun::star::table;
using namespace com::sun::star::text;

using namespace rtl;
using namespace cppu;

using ::rtl::OString;
using ::rtl::OUString;
using ::rtl::OUStringToOString;

namespace boost { namespace doc { namespace libre_cell_func {

/*template<typename U>
void __debug_find_props(Reference < U > xSomething) {
        Reference < XPropertySet > xChartProps(xSomething, UNO_QUERY);
        Reference < XPropertySetInfo > xPropInfo(xChartProps->getPropertySetInfo());
        Sequence < Property > props = xPropInfo->getProperties();
        for(int i = 0; i < props.getLength(); i++) {
            std::cout << props[i].Name << std::endl;
        }
}*/

//! \fn Helper function to throw an unwrapped
//!     exception
//!
void throw_document_exception(Exception& e) {
    OString o = OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US );
    boost::throw_exception(document_exception(o.pData->buffer));
}

//! \fn Returns an XCell Reference by the position
//!     with Exception Handling.
//!
Reference < XCell > get_cell(Reference <XSpreadsheet> xSheet,int i, int j) {
    try {
        Reference< XCell > xCell = xSheet->getCellByPosition(i, j);
        return xCell;
    }
    catch( Exception &e ){
        throw_document_exception(e);
    }
}

//! \fn Sets Cell value as string str. the enum value of the cell
//!     changes to CellContentType_STRING
//!
void set_cell_value(Reference< XCell > xCell, const std::string& str) {
    try {
        xCell->setFormula(OUString::createFromAscii(str.c_str()));
    }
    catch( Exception &e ){
        throw_document_exception(e);
    }
}

//! \fn Sets Cell value as string str. the enum value of the cell
//!     changes to CellContentType_STRING
//!
void reset(Reference< XCell > xCell) {
    try {
        Reference< XText > xText(xCell, UNO_QUERY);
        xText->setString(OUString());
    }
    catch( Exception &e ){
        throw_document_exception(e);
    }
}

//! \fn Sets Cell value as float x. the enum value of the cell
//!     changes to CellContentType_VALUE
//!
void set_cell_value(Reference< XCell > xCell, float x) {
    try {
        xCell->setValue(x);
    }
    catch( Exception &e ){
        throw_document_exception(e);
    }
}

//! \fn Gets the cell content type of the cell. Returns the boost enum value
//!     depending upon the Internal OO enum.
//!
boost::cell_content_type::type get_content_type(Reference < XCell > xCell) {
    switch (xCell->getType()){
        case CellContentType_EMPTY : return boost::cell_content_type::EMPTY;
        case CellContentType_VALUE : return boost::cell_content_type::VALUE;
        case CellContentType_TEXT : return boost::cell_content_type::STRING;
        case CellContentType_FORMULA : return boost::cell_content_type::FORMULA;
        case CellContentType_MAKE_FIXED_SIZE: return boost::cell_content_type::ERROR;
    }
    return boost::cell_content_type::ERROR;
}

//! \fn Gets the string value of the Cell
//!     if it is present.
//!
std::string get_string(Reference < XCell > xCell) {
    try {
        OString s = OUStringToOString( xCell->getFormula(), RTL_TEXTENCODING_ASCII_US );
        return std::string(s.pData->buffer);
    }
    catch( Exception &e ){
        throw_document_exception(e);
    }
}

//! \fn Gets the formula value of the cell
//!     if it is present.
//!
std::string get_formula(Reference < XCell > xCell) {
    try {
        OString s = OUStringToOString( xCell->getFormula(), RTL_TEXTENCODING_ASCII_US );
        return std::string(s.pData->buffer);
    }
    catch( Exception &e ){
        throw_document_exception(e);
    }
}

//! \fn Gets the float value of the cell if
//!     it is present.
//!
double get_value(Reference < XCell > xCell) {
    try {
        return xCell->getValue();
    }
    catch( Exception &e ){
        throw_document_exception(e);
    }
}

template<typename T>
void set_cell_property(Reference < XCell > xCell,const OUString& prop, const T& val) {
    try {
        Reference < XPropertySet > xCellProps(xCell, UNO_QUERY);
        Any propVal;
        propVal <<= val;
        xCellProps->setPropertyValue(prop, propVal);
    }
    catch( Exception &e ){
        throw_document_exception(e);
    }
}

Any get_cell_property(Reference < XCell > xCell,const OUString& prop) {
    try {
        Reference < XPropertySet > xCellProps(xCell, UNO_QUERY);
        return xCellProps->getPropertyValue(prop);
    }
    catch( Exception &e ){
        throw_document_exception(e);
    }
}

void set_cell_style(Reference < XCell > xCell, const std::string& str) {
    set_cell_property(xCell, OUString::createFromAscii("CellStyle"), OUString::createFromAscii(str.c_str()));
}

// \fn Helper to maintain standards,
// Libreoffice and MS Office have different color standards.
int colorref_to_librecolor(int val) {
    // COLORREF -> 0x00BBGGRR
    // LIBRE -> 0x00RRGGBB
    int b = (val & 0x00FF0000) >> 16;
    int g = val & 0x0000FF00;
    int r = (val & 0x000000FF) << 16;
    return (b | g | r);
}

void set_cell_background_color(Reference < XCell > xCell, int val) {
    set_cell_property(xCell, OUString::createFromAscii("CellBackColor"), colorref_to_librecolor(val));
}

void set_cell_foreground_color(Reference < XCell > xCell, int val) {
    set_cell_property(xCell, OUString::createFromAscii("CharColor"), colorref_to_librecolor(val));
}

void set_cell_font_size(Reference < XCell > xCell, double val) {
    set_cell_property(xCell, OUString::createFromAscii("CharHeight"), (float)val);
    set_cell_property(xCell, OUString::createFromAscii("CharHeightAsian"), (float)val);
    set_cell_property(xCell, OUString::createFromAscii("CharHeightComplex"), (float)val);
}

void set_cell_font_name(Reference < XCell > xCell, const std::string& str) {
    set_cell_property(xCell, OUString::createFromAscii("CharFontName"), OUString::createFromAscii(str.c_str()));
    set_cell_property(xCell, OUString::createFromAscii("CharFontNameAsian"), OUString::createFromAscii(str.c_str()));
    set_cell_property(xCell, OUString::createFromAscii("CharFontNameComplex"), OUString::createFromAscii(str.c_str()));
}

void set_cell_horizontal_alignment(Reference < XCell > xCell, boost::cell_horizontal_alignment::type t) {
        switch(t) {
            case boost::cell_horizontal_alignment::LEFT :
                    set_cell_property(xCell, OUString::createFromAscii("HoriJustify"), CellHoriJustify_LEFT);
                    break;
            case boost::cell_horizontal_alignment::CENTER :
                    set_cell_property(xCell, OUString::createFromAscii("HoriJustify"), CellHoriJustify_CENTER);
                    break;
            case boost::cell_horizontal_alignment::RIGHT :
                    set_cell_property(xCell, OUString::createFromAscii("HoriJustify"), CellHoriJustify_RIGHT);
                    break;
        }
}

void set_cell_vertical_alignment(Reference < XCell > xCell, boost::cell_vertical_alignment::type t) {
        switch(t) {
            case boost::cell_vertical_alignment::TOP :
                    set_cell_property(xCell, OUString::createFromAscii("VertJustify"), CellVertJustify_TOP);
                    break;
            case boost::cell_vertical_alignment::CENTER :
                    set_cell_property(xCell, OUString::createFromAscii("VertJustify"), CellVertJustify_CENTER);
                    break;
            case boost::cell_vertical_alignment::BOTTOM :
                    set_cell_property(xCell, OUString::createFromAscii("VertJustify"), CellVertJustify_BOTTOM);
                    break;
        }
}

// Documentation Link: https://wiki.openoffice.org/wiki/Documentation/DevGuide/Text/Formatting
void set_cell_formatting_property(::com::sun::star::uno::Reference < ::com::sun::star::table::XCell > xCell, boost::cell_format_property::type t, bool set) {
    if(t == boost::cell_format_property::BOLD) {
            float val = (set == true)?150.0:100.0; // 150 = BOLD, NORMAL = 100, THIN = 50
            set_cell_property(xCell, OUString::createFromAscii("CharWeight"), val);
    }
    else if(t == boost::cell_format_property::ITALIC) {
            int val = (set==true)?(FontSlant_ITALIC):(FontSlant_NONE);
            set_cell_property(xCell, OUString::createFromAscii("CharPosture"), val);

    }
    else if(t == boost::cell_format_property::STRIKETHROUGH ) { // CharCrossedOut, CharStrikeout (specifies type of strikeout)
            set_cell_property(xCell, OUString::createFromAscii("CharCrossedOut"), (sal_Bool)set); // crossedout or not
    }
    else if(t == boost::cell_format_property::UNDERLINE) { // CharUnderline, CharUnderlineHasColor, CharUnderlineColor
            int val = (set == true)?1:0; // 1 = SINGLE, 0 = NONE, DASH = 5, DOTTED = 3, DASHDOT = 7
            set_cell_property(xCell, OUString::createFromAscii("CharUnderline"), val);
            if(set) {
                    // Set the color of the underline same as the font color
                    set_cell_property(xCell, OUString::createFromAscii("CharUnderlineHasColor"), (sal_Bool)true);
                    Reference < XPropertySet > xCellProps(xCell, UNO_QUERY);
                    xCellProps->setPropertyValue(OUString::createFromAscii("CharUnderlineColor"), get_cell_property(xCell,"CharColor"));
            }
    }
}

void set_cell_border(Reference < XCell > xCell, boost::cell_border_style::type t, boost::cell_border_weight::type w, int color) {
        // This code is supported by Libreoffice 5+, it seems. :(
        // Border Weight: MEDIUM, THICK, THIN
        int style_weight = 50; // MEDIUM
        if(w == boost::cell_border_weight::THICK) {
            style_weight = 100;
        }
        else if(w == boost::cell_border_weight::THIN) {
            style_weight = 20;
        }
        sal_Bool x = (sal_Bool)true;
        try {
                // NONE, CONTINUOUS, DASH, DASHDOT
                int style_type = BorderLineStyle::SOLID;
                if(t == boost::cell_border_style::DASH) {
                        style_type = BorderLineStyle::DASHED;
                }
                else if(t == boost::cell_border_style::DASHDOT) {
                        style_type = BorderLineStyle::DASH_DOT;
                }
                else if(t == boost::cell_border_style::NONE) {
                        x = (sal_Bool)false;
                        style_type = BorderLineStyle::NONE;
                }
                BorderLine2 b2(colorref_to_librecolor(color), 0, style_weight, 0, style_type, 0);
                TableBorder2 val2(
                    b2, x,
                    b2, x,
                    b2, x,
                    b2, x,
                    b2, x,
                    b2, x,
                    0, (sal_Bool)true
                );
                set_cell_property(xCell, OUString::createFromAscii("TableBorder2"), val2);
        }
        catch( Exception &e ){
                // Open Office: API Difference with  Libreoffice
                // Open Office doesn't support the BorderLine2 interface and thus TableBorder2
                // interface. There is no support for style of the border AFAIK.
                // This code is supported by both Libreoffice 4+ and Openoffice
                if(t == boost::cell_border_style::NONE) {
                        x = (sal_Bool)false;
                }
                BorderLine b(colorref_to_librecolor(color), 0, style_weight, 0);
                TableBorder val(
                    b, x,
                    b, x,
                    b, x,
                    b, x,
                    b, x,
                    b, x,
                    0, (sal_Bool)true
                );
                set_cell_property(xCell, OUString::createFromAscii("TableBorder"), val);
        }
}

}}}

#endif

max_stars_repo_name: anuragxel/generic-document-library

max_issues_repo_name: anuragxel/generic-document-library

max_forks_repo_name: anuragxel/generic-document-library


text:
/*
 * gpcxx/tree/detail/tree_base_cursor.hpp
 * Date: 2015-02-09
 * Author: Karsten Ahnert (karsten.ahnert@gmx.de)
 * Copyright: Karsten Ahnert
 *
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or
 * copy at http://www.boost.org/LICENSE_1_0.txt)
 */

#ifndef GPCXX_TREE_DETAIL_TREE_BASE_CURSOR_HPP_INCLUDED
#define GPCXX_TREE_DETAIL_TREE_BASE_CURSOR_HPP_INCLUDED

#include <gpcxx/tree/detail/node_helpers.hpp>
#include <gpcxx/tree/cursor_traits.hpp>
#include <gpcxx/util/assert.hpp>

#include <boost/iterator/iterator_facade.hpp>
#include <boost/iterator/iterator_concepts.hpp>

#include <type_traits>

namespace gpcxx {
namespace detail {

/**
 * cursor consist of node pointer of parent and index for the current node, which is the child index in the parent
 *
 * cursor validity:
 * # complete invalid cursor: parent node is nullptr, exist if default constructed
 * # invalid cursor - current node is not present, but parent is ok
 *   * the root of an empty tree is such kind of invalid node
 *   * the end cursor of a node is such kind of invalid node
 *
 * TODO: Find a better name for complete invalid cursors and implement a check in cursor
 *
 * special cursors:
 * # root: invalid cursor can be used to insert
 * # shoot: invalid cursor symbolizing the very last element
 */
template< typename Node >
class tree_base_cursor : public boost::iterator_facade<
    tree_base_cursor< Node > ,                           // Derived-Iterator
    typename node_value_getter< Node >::type ,            // Value
    boost::random_access_traversal_tag // ,               // Category
    // boost::use_default ,                               // Reference
    // boost::use_default
    >
{

    friend class boost::iterator_core_access;

    //
    // private types:
    //
    using node_type = Node;
    using node_pointer = node_type* ;
    using real_node_type = typename std::remove_const< Node >::type;
    using node_base = typename node_base_getter< Node >::type;
    using node_base_pointer = node_base*;
    using real_node_base = typename std::remove_const< node_base >::type;
    using real_node_base_pointer = real_node_base*;
    using const_real_node_base_pointer = real_node_base const* ;

    using base_type = boost::iterator_facade<
        tree_base_cursor< Node > ,                        // Derived-Iterator
        typename node_value_getter< Node >::type ,         // Value
        boost::random_access_traversal_tag >;

    template< typename OtherNode >
    using other_node_enabler = std::enable_if< std::is_convertible< OtherNode* , node_pointer >::value >;

public:

    //
    // types:
    //
    using size_type = size_t;
    using cursor = tree_base_cursor< node_type >;
    using const_cursor = tree_base_cursor< real_node_type const >;

    //
    // construct:
    //
    tree_base_cursor( node_base_pointer node = nullptr , size_type pos = 0 )
    : m_node( node ) , m_pos( pos ) { }

    template< typename OtherNode , typename Enabler = typename other_node_enabler< OtherNode >::type >
    tree_base_cursor( tree_base_cursor< OtherNode > const& other )
    : m_node( other.parent_node() ) , m_pos( other.pos() ) { }

    tree_base_cursor( tree_base_cursor const& ) = default;
    tree_base_cursor( tree_base_cursor&& ) = default;
    tree_base_cursor& operator=( tree_base_cursor const& ) = default;
    tree_base_cursor& operator=( tree_base_cursor&& ) = default;

    //
    // capacity:
    //
    size_type size( void ) const noexcept
    {
        return m_node->child_node( m_pos )->size();
    }

    size_type max_size( void ) const noexcept
    {
        return m_node->max_size();
    }

    bool empty( void ) const noexcept
    {
        return ( size() == 0 );
    }

    // operator==
    // operator!=

    // a.parity() size_type   (std::distance(b.begin(), a) if b is a's parent.)

    //
    // cursors:
    //
    cursor begin( void )
    {
        return cursor( m_node->child_node( m_pos ) , 0 );
    }

    const_cursor begin( void ) const
    {
        return cbegin();
    }

    const_cursor cbegin( void ) const
    {
        return const_cursor( m_node->child_node( m_pos ) , 0 );
    }

    cursor end( void )
    {
        return cursor( m_node->child_node( m_pos ) , this->size() );
    }

    const_cursor end( void ) const
    {
        return cend();
    }

    const_cursor cend( void ) const
    {
        return const_cursor( m_node->child_node( m_pos ) , this->size() );
    }

    cursor parent( void )
    {
        GPCXX_ASSERT( ! is_root() );
        auto parent_node = m_node->parent_node();
        return cursor( parent_node , parent_node->child_index( m_node ) );
    }

    const_cursor parent( void ) const
    {
        return cparent();
    }

    const_cursor cparent( void ) const
    {
        GPCXX_ASSERT( ! is_root() );
        auto parent_node = m_node->parent_node();
        return const_cursor( parent_node , parent_node->child_index( m_node ) );
    }

    cursor children( size_type i )
    {
        return cursor( m_node->child_node( m_pos ) , i );
    }

    const_cursor children( size_type i ) const
    {
        return const_cursor( m_node->child_node( m_pos ) , i );
    }

    //
    // structure queries:
    //
    size_type height( void ) const noexcept
    {
        return node()->height();
    }

    size_type level( void ) const noexcept
    {
        return parent_node()->level();   // level is shifted, because the root is not the very first node.
    }

    size_t num_nodes( void ) const noexcept
    {
        return node()->count_nodes();
    }

    bool is_root( void ) const noexcept
    {
        return ( ( m_node->parent_node() == nullptr ) && ( m_pos == 0 ) );
    }

    bool is_shoot( void ) const noexcept
    {
        return ( ( m_node->parent_node() == nullptr ) && ( m_pos == 1 ) );
    }

    bool valid( void ) const
    {
        return ( m_node != nullptr ) && ( m_node->valid_child( m_pos ) );
    }

    bool invalid( void ) const
    {
        return ( m_node == nullptr ) || ( m_node->invalid_child( m_pos ) );
    }

//protected:
public:

    //
    // node accessors:
    //
    node_base_pointer parent_node( void ) noexcept
    {
        return m_node;
    }

    const node_base_pointer parent_node( void ) const noexcept
    {
        return m_node;
    }

    node_base_pointer node( void ) noexcept
    {
        return m_node->child_node( m_pos );
    }

    const node_base_pointer node( void ) const noexcept
    {
        return m_node->child_node( m_pos );
    }

    size_type pos( void ) const noexcept
    {
        return m_pos;
    }

private:

    //
    // iterator interface:
    //
    void increment( void )
    {
        ++m_pos;
    }

    void decrement( void )
    {
        --m_pos;
    }

    void advance( typename base_type::difference_type n )
    {
        m_pos += n;
    }

    typename base_type::difference_type distance_to( tree_base_cursor const& other ) const
    {
        using diff_type = typename base_type::difference_type;
        return static_cast< diff_type >( other.m_pos ) - static_cast< diff_type >( m_pos );
    }

    bool equal( tree_base_cursor const& other) const
    {
        return ( other.m_node == m_node ) && ( other.m_pos == m_pos );
    }

    typename base_type::reference dereference() const
    {
        return static_cast< node_pointer >( m_node->child_node( m_pos ) )->get();
    }

    node_base_pointer m_node;
    size_type m_pos;
};

} // namespace detail

template< typename Node >
struct is_cursor< detail::tree_base_cursor< Node > > : public std::true_type { };

} // namespace gpcxx

#endif // GPCXX_TREE_DETAIL_TREE_BASE_CURSOR_HPP_INCLUDED

max_stars_repo_name: gchoinka/gpcxx

max_issues_repo_name: gchoinka/gpcxx

max_forks_repo_name: gchoinka/gpcxx


text:
#include "script.hxx"
#include "dbl/core/common.hxx"

#include <cstdlib>
#include <boost/filesystem.hpp>

namespace dbl {
namespace sys {
namespace script {

Script::Script(std::shared_ptr<core::Api> api, const std::string& name)
	: api_(api),
	  name_(name)
{
}

void Script::set_env(const std::string& var, const std::string& value)
{
	env_[var] = value;
}

bool Script::is_success() const
{
	return (status_ == 0);
}

int Script::get_status() const
{
	return status_;
}

bool Script::run()
{
	using boost::filesystem::path;
	using boost::filesystem::exists;
	std::string platform = api_->config.platform;

	path base_dir = api_->config.base_dir;
	path script_dir = api_->config.script_dir;
	path script_path =  base_dir / script_dir;
	script_path /= platform;
	script_path /= name_;

	if(!exists(script_path)) {
		std::string msg("Script not found: " + script_path.string());
		throw std::runtime_error(msg);
	}

	path_ = script_path.string();

	this->export_env();
	status_ = this->execute();
	this->unexport_env();

	return this->is_success();
}

int Script::execute() const
{
	return system(path_.c_str());
}

} // script
} // sys
} // dbl

ext: cxx

max_stars_repo_name: mcptr/dbl-service

max_issues_repo_name: mcptr/dbl-service

max_forks_repo_name: mcptr/dbl-service


text:
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE JPetParamManagerTest
#include <boost/test/unit_test.hpp>

#define private public
#include "../../JPetParamManager/JPetParamManager.h"

#include <cstddef>

const char* gDefaultConfigFile = "DBConfig/configDB.cfg";

BOOST_AUTO_TEST_SUITE(JPetParamManagerTestSuite)

void checkContainersSize(const JPetParamBank &bank)
{
  BOOST_REQUIRE_EQUAL(bank.getScintillatorsSize(), 2);
  BOOST_REQUIRE_EQUAL(bank.getPMsSize(), 4);
  BOOST_REQUIRE_EQUAL(bank.getPMCalibsSize(), 0);	// It is not 0 for e.g. run_id = 2 - FOR run_id=2 NOT for run_id=1 YES. In test run_id is set to 1 so the size=0
  BOOST_REQUIRE_EQUAL(bank.getFEBsSize(), 1);
  BOOST_REQUIRE_EQUAL(bank.getTRBsSize(), 1);
  BOOST_REQUIRE_EQUAL(bank.getBarrelSlotsSize(), 2);
  BOOST_REQUIRE_EQUAL(bank.getTOMBChannelsSize(), 4);
}

BOOST_AUTO_TEST_CASE(default_constructor)
{
  JPetParamManager paramMgr;
}

BOOST_AUTO_TEST_CASE(constructor)
{
  JPetParamManager paramMgr(gDefaultConfigFile);
}

BOOST_AUTO_TEST_CASE(generateParamBankTest)
{
  JPetParamManager l_paramManagerInstance(gDefaultConfigFile);
  l_paramManagerInstance.getParametersFromDatabase(1);

  BOOST_REQUIRE_EQUAL(l_paramManagerInstance.fBank != NULL, true);

  checkContainersSize(*l_paramManagerInstance.fBank);
}

BOOST_AUTO_TEST_CASE(writeAndReadDataFromFileByWriterAndReaderObjectsTest)
{
  JPetParamManager l_paramManagerInstance(gDefaultConfigFile);

  l_paramManagerInstance.getParametersFromDatabase(1);

  /*
  const char* testDatafile = "testDataFile.txt";
  JPetWriter writer(testDatafile);
  BOOST_CHECK(l_paramManagerInstance.saveParametersToFile(testDatafile) == true);

  Error in <TFile::ReadBuffer>: error reading all requested bytes from file testDataFile.txt, got 228 of 300
  Error in 	: testDataFile.txt failed to read the file type data.
  Error in <TFile::WriteObject>: File testDataFile.txt is not writable
  */

  /*
  JPetReader reader(testDatafile);
  BOOST_CHECK(l_paramManagerInstance.readParametersFromFile(&reader) == true);

  // Errors after writing objects to file and start reading
  Error in <TFile::ReadBuffer>: error reading all requested bytes from file testDataFile.txt, got 228 of 300
  Error in <TFile::Init>: testDataFile.txt failed to read the file type data.
  Error in <TFile::WriteObject>: File testDataFile.txt is not writable
  Error in <TFile::ReadBuffer>: error reading all requested bytes from file testDataFile.txt, got 228 of 300
  Error in <TFile::Init>: testDataFile.txt failed to read the file type data.
  */
}

BOOST_AUTO_TEST_CASE(writeAndReadDataFromFileByFileNameTest)
{
  const char* testDatafile = "testDataFile.txt";
  JPetParamManager l_paramManagerInstance(gDefaultConfigFile);

  l_paramManagerInstance.getParametersFromDatabase(1);

  BOOST_REQUIRE_EQUAL(l_paramManagerInstance.fBank != NULL, true);

  BOOST_CHECK(l_paramManagerInstance.saveParametersToFile(testDatafile) == true);

  l_paramManagerInstance.fBank->clear();

  BOOST_CHECK(l_paramManagerInstance.readParametersFromFile(testDatafile) == true);

  checkContainersSize(*l_paramManagerInstance.fBank);
}

BOOST_AUTO_TEST_CASE(clearParametersTest)
{
  JPetParamManager l_paramManagerInstance(gDefaultConfigFile);

  l_paramManagerInstance.getParametersFromDatabase(1);

  BOOST_REQUIRE_EQUAL(l_paramManagerInstance.fBank != NULL, true);

  checkContainersSize(*l_paramManagerInstance.fBank);

  l_paramManagerInstance.clearParameters();

  BOOST_REQUIRE_EQUAL(l_paramManagerInstance.fBank->getScintillatorsSize(), 0);
  BOOST_REQUIRE_EQUAL(l_paramManagerInstance.fBank->getPMsSize(), 0);
  BOOST_REQUIRE_EQUAL(l_paramManagerInstance.fBank->getPMCalibsSize(), 0);
  BOOST_REQUIRE_EQUAL(l_paramManagerInstance.fBank->getFEBsSize(), 0);
  BOOST_REQUIRE_EQUAL(l_paramManagerInstance.fBank->getTRBsSize(), 0);
  BOOST_REQUIRE_EQUAL(l_paramManagerInstance.fBank->getBarrelSlotsSize(), 0);
  BOOST_REQUIRE_EQUAL(l_paramManagerInstance.fBank->getTOMBChannelsSize(), 0);
}

BOOST_AUTO_TEST_CASE(getParamBankTest)
{
  JPetParamManager l_paramManagerInstance(gDefaultConfigFile);

  l_paramManagerInstance.getParametersFromDatabase(1);

  const JPetParamBank &bank = l_paramManagerInstance.getParamBank();

  checkContainersSize(bank);
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: wictus/oldScopeAnalysis

max_issues_repo_name: wictus/oldScopeAnalysis

max_forks_repo_name: wictus/oldScopeAnalysis


text:
/* Copyright (c) 2017, United States Government, as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 *
 * All rights reserved.
 *
 * The Astrobee platform is 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
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

#include <sim_wrapper/sim.h>

#include <Eigen/Geometry>
#include <geometry_msgs/PoseStamped.h>
#include <msg_conversions/msg_conversions.h>
#include <rosgraph_msgs/Clock.h>

#include <ff_msgs/SetBool.h>
#include <ff_util/ff_names.h>

#include <sensor_msgs/Image.h>
#include <sensor_msgs/PointCloud2.h>

#include <camera/camera_model.h>
#include <sparse_mapping/reprojection.h>

#include <ff_common/init.h>

// parameters sim_model_lib0_P are set in
//  matlab/code_generation/sim_model_lib0_ert_rtw/sim_model_lib0_data.c

namespace sim_wrapper {
Sim::Sim(ros::NodeHandle* nh) :
  cam_params_(Eigen::Vector2i(0, 0), Eigen::Vector2d(0, 0), Eigen::Vector2d(0, 0)),
  cur_time_(0, 0), ml_camera_count_(0), ar_camera_count_(0), of_camera_count_(0), dl_camera_count_(0),
  en_landmark_(false), en_tag_(false), en_optical_(false), en_depth_(false),
  pmc_command_id_(0) {
  config_.AddFile("cameras.config");
  config_.AddFile("geometry.config");
  config_.AddFile("gnc.config");

  ReadParams();
  gnc_.Initialize();

  // TODO(bcoltin): load these from gnc autocode
  of_history_size_ = 4;
  of_max_features_ = 50;
  ml_max_features_ = 50;
  hr_max_features_ = 50;
  ar_max_features_ = 50;

  // initialize ROS
  config_timer_ = nh->createTimer(ros::Duration(1), [this](ros::TimerEvent e) {
    config_.CheckFilesUpdated(std::bind(&Sim::ReadParams, this));
  }, false, true);

  pub_imu_ = nh->advertise<sensor_msgs::Imu>(TOPIC_HARDWARE_IMU, 5);
  pub_pmc_ = nh->advertise<ff_hw_msgs::PmcTelemetry>(TOPIC_HARDWARE_PMC_TELEMETRY, 5);
  pub_clock_ = nh->advertise<rosgraph_msgs::Clock>(TOPIC_CLOCK, 1);
  // Mapped landmarks
  pub_landmark_camera_ = nh->advertise<sensor_msgs::Image>(TOPIC_HARDWARE_NAV_CAM, 1);
  srv_landmark_enable_ = nh->advertiseService(SERVICE_LOCALIZATION_ML_ENABLE, &Sim::LandmarkEnable, this);
  pub_landmark_pulse_ = nh->advertise<ff_msgs::CameraRegistration>(TOPIC_LOCALIZATION_ML_REGISTRATION, 1);
  pub_landmarks_ = nh->advertise<ff_msgs::VisualLandmarks>(TOPIC_LOCALIZATION_ML_FEATURES, 1);
  // Optical flow
  pub_optical_ = nh->advertise<ff_msgs::Feature2dArray>(TOPIC_LOCALIZATION_OF_FEATURES, 1);
  srv_optical_enable_ = nh->advertiseService(SERVICE_LOCALIZATION_OF_ENABLE, &Sim::OpticalEnable, this);
  pub_optical_pulse_ = nh->advertise<ff_msgs::CameraRegistration>(TOPIC_LOCALIZATION_OF_REGISTRATION, 1);
  // AR tags
  pub_ar_tags_camera_ = nh->advertise<sensor_msgs::Image>(TOPIC_HARDWARE_DOCK_CAM, 1);
  srv_ar_tags_enable_ = nh->advertiseService(SERVICE_LOCALIZATION_AR_ENABLE, &Sim::TagEnable, this);
  pub_ar_tags_pulse_ = nh->advertise<ff_msgs::CameraRegistration>(TOPIC_LOCALIZATION_AR_REGISTRATION, 1);
  pub_ar_tags_ = nh->advertise<ff_msgs::VisualLandmarks>(TOPIC_LOCALIZATION_AR_FEATURES, 1);
  // Handrail localization
  pub_depth_camera_ = nh->advertise<sensor_msgs::PointCloud2>((std::string) TOPIC_HARDWARE_PICOFLEXX_PREFIX
      + (std::string) TOPIC_HARDWARE_NAME_PERCH_CAM + (std::string) TOPIC_HARDWARE_PICOFLEXX_SUFFIX, 1);
  srv_depth_enable_ = nh->advertiseService(SERVICE_LOCALIZATION_HR_ENABLE, &Sim::DepthEnable, this);
  pub_depth_ = nh->advertise<ff_msgs::DepthLandmarks>(TOPIC_LOCALIZATION_HR_FEATURES, 1);
  pub_depth_pulse_ = nh->advertise<ff_msgs::CameraRegistration>(TOPIC_LOCALIZATION_HR_REGISTRATION, 1);
  // Ground truth
  pub_truth_pose_ = nh->advertise<geometry_msgs::PoseStamped>(TOPIC_LOCALIZATION_TRUTH, 1);
  // FAM callback
  sub_fam_pmc_ = nh->subscribe(TOPIC_HARDWARE_PMC_COMMAND, 5, &Sim::PmcFamCallBack, this,
                               ros::TransportHints().tcpNoDelay());
}

Sim::~Sim() {}

void Sim::ReadParams(void) {
  if (!config_.ReadFiles()) {
    ROS_ERROR("Failed to read config files.");
    return;
  }

  gnc_.ReadParams(&config_);

  cam_params_ = camera::CameraParameters(&config_, "nav_cam");

  auto& p = gnc_.sim_->defaultParam;
  std::string imu_filename;
  if (!config_.GetStr("imu_bias_file", &imu_filename)) {
    ROS_FATAL("IMU bias file not specified.");
  }
  std::string bias_file = std::string(ff_common::GetConfigDir()) + std::string("/") + imu_filename;

  // set the biases to what the EKF expects
  Eigen::Map<Eigen::Vector3f> accel_bias(p->epson_accel_bias_ic);
  Eigen::Map<Eigen::Vector3d> gyro_bias(p->epson_gyro_bias_ic);
  std::vector<real32_T> new_bias(3);
  FILE* f = fopen(bias_file.c_str(), "r");
  if (f) {
    int ret = fscanf(f, "%g %g %g\n", &new_bias[0], &new_bias[1], &new_bias[2]);
    if (ret == 3)
      gyro_bias = Eigen::Vector3d(new_bias[0], new_bias[1], new_bias[2]);
    ret = fscanf(f, "%g %g %g\n", &new_bias[0], &new_bias[1], &new_bias[2]);
    if (ret == 3)
      accel_bias = Eigen::Vector3f(new_bias[0], new_bias[1], new_bias[2]);
    fclose(f);
  } else {
    ROS_WARN("No bias file found at %s.", bias_file.c_str());
  }
}

void Sim::PmcFamCallBack(ff_hw_msgs::PmcCommand::ConstPtr const& pmc) {
  gnc_.act_msg_.act_timestamp_sec  = cur_time_.sec;
  gnc_.act_msg_.act_timestamp_nsec = cur_time_.nsec;

  gnc_.act_msg_.act_impeller_speed_cmd[0] = pmc->goals[0].motor_speed;
  gnc_.act_msg_.act_impeller_speed_cmd[1] = pmc->goals[1].motor_speed;
  for (int i = 0; i < 6; i++) {
    gnc_.act_msg_.act_servo_pwm_cmd[i] = pmc->goals[0].nozzle_positions[i];
    gnc_.act_msg_.act_servo_pwm_cmd[6 + i] = pmc->goals[1].nozzle_positions[i];
  }
}

void Sim::Step() {
  gnc_.Step();

  // Publish the clock msg from the simulator
  rosgraph_msgs::Clock clock_msg;
  clock_msg.clock.sec = cur_time_.sec;
  clock_msg.clock.nsec = cur_time_.nsec;
  pub_clock_.publish(clock_msg);

  cur_time_.nsec += 16000000;
  if (cur_time_.nsec >= 1000000000) {
    cur_time_.nsec -= 1000000000;
    cur_time_.sec++;
  }

  ////////////////////////////////////////
  // Publish all the simulated messages //
  ////////////////////////////////////////
  // Ground truth
  PublishTruth();
  // IMU
  if (PullImuMsg())
    pub_imu_.publish(ros_imu_);
  // PMC
  if (PullPmcMsg())
    pub_pmc_.publish(ros_pmc_);
  // 1 - Mapped landmarks
  if (PullLandmarkMsg())
    if (en_landmark_) pub_landmarks_.publish(ros_landmark_);
  if (PullLandmarkPulseMsg()) {
    if (en_landmark_) pub_landmark_pulse_.publish(ros_reg_pulse_);
    if (en_landmark_) pub_landmark_camera_.publish(sensor_msgs::Image());
  }
  // 2 - AR tags
  if (PullTagMsg())
    if (en_tag_) pub_ar_tags_.publish(ros_tag_);
  if (PullTagPulseMsg()) {
    if (en_tag_) pub_ar_tags_pulse_.publish(ros_reg_pulse_);
    if (en_tag_) pub_ar_tags_camera_.publish(sensor_msgs::Image());
  }
  // 3 - Optical flow
  if (PullOpticalMsg())
    if (en_optical_) pub_optical_.publish(ros_optical_);
  if (PullOpticalPulseMsg())
    if (en_optical_) pub_optical_pulse_.publish(ros_reg_pulse_);
  // 4 - Handrail
  if (PullDepthMsg())
    if (en_depth_) pub_depth_.publish(ros_depth_);
  if (PullDepthPulseMsg()) {
    if (en_depth_) pub_depth_camera_.publish(sensor_msgs::PointCloud2());
    if (en_depth_) pub_depth_pulse_.publish(ros_reg_pulse_);
  }
}

void Sim::PublishTruth() {
  ros_truth_pose_.header.seq++;
  ros_truth_pose_.header.stamp.sec = gnc_.ex_time_msg_.timestamp_sec;
  ros_truth_pose_.header.stamp.nsec = gnc_.ex_time_msg_.timestamp_nsec;
  ros_truth_pose_.header.frame_id = "world";
  ros_truth_pose_.pose.position = msg_conversions::array_to_ros_point(gnc_.env_msg_.P_B_ISS_ISS);
  ros_truth_pose_.pose.orientation = msg_conversions::array_to_ros_quat(gnc_.env_msg_.Q_ISS2B);
  pub_truth_pose_.publish(ros_truth_pose_);
}

bool Sim::PullImuMsg() {
  // check if value is updated
  // publish on every tick

  ros_imu_.header.stamp = ros::Time::now();
  ros_imu_.header.frame_id = "body";

  // set angular vel, ros message is double cast from float
  ros_imu_.angular_velocity.x = static_cast<double>(gnc_.imu_msg_.imu_omega_B_ECI_sensor[0]);
  ros_imu_.angular_velocity.y = static_cast<double>(gnc_.imu_msg_.imu_omega_B_ECI_sensor[1]);
  ros_imu_.angular_velocity.z = static_cast<double>(gnc_.imu_msg_.imu_omega_B_ECI_sensor[2]);

  // set linear accel
  ros_imu_.linear_acceleration.x = static_cast<double>(gnc_.imu_msg_.imu_A_B_ECI_sensor[0]);
  ros_imu_.linear_acceleration.y = static_cast<double>(gnc_.imu_msg_.imu_A_B_ECI_sensor[1]);
  ros_imu_.linear_acceleration.z = static_cast<double>(gnc_.imu_msg_.imu_A_B_ECI_sensor[2]);

  return true;
}

bool Sim::PullPmcMsg() {
  ros_pmc_.header.stamp.sec  = gnc_.act_msg_.act_timestamp_sec;
  ros_pmc_.header.stamp.nsec = gnc_.act_msg_.act_timestamp_nsec;
  ros_pmc_.header.frame_id = "body";
  ros_pmc_.statuses.clear();

  for (int i = 0; i < 2; i++) {
    ff_hw_msgs::PmcStatus s;
    s.motor_speed = gnc_.bpm_msg_.bpm_motor_speed[i];
    s.motor_current = gnc_.bpm_msg_.bpm_motor_curr[i];
    s.pressure = -1;
    s.status_1 = 0;
    s.status_2 = 0;
    s.command_id = pmc_command_id_;
    ros_pmc_.statuses.push_back(s);
  }
  pmc_command_id_++;

  return true;
}

bool Sim::PullLandmarkPulseMsg() {
  if (!(!last_landmark_pulse_ && gnc_.reg_pulse_.cvs_landmark_pulse > 0)) {
    // early exit condition, not a rising edge
    last_landmark_pulse_ = gnc_.reg_pulse_.cvs_landmark_pulse > 0;
    return false;
  }

  ros_reg_pulse_.camera_id = ++ml_camera_count_;

  last_landmark_pulse_ = gnc_.reg_pulse_.cvs_landmark_pulse > 0;
  return true;
}

bool Sim::PullLandmarkMsg() {
  if (last_landmark_time_.sec == gnc_.landmark_msg_.cvs_timestamp_sec &&
      last_landmark_time_.nsec == gnc_.landmark_msg_.cvs_timestamp_nsec) {
    return false;
  }

  // Count how many landmarks there are
  size_t landmark_count = 0;
  for (auto flag : gnc_.landmark_msg_.cvs_valid_flag) {
    if (flag > 0) {
      landmark_count++;
    }
  }
  std::vector<Eigen::Vector3d> landmarks, inlier_landmarks;
  std::vector<Eigen::Vector2d> observations, inlier_observations;
  landmarks.resize(landmark_count);
  observations.resize(landmark_count);
  size_t output_i = 0;
  for (size_t i = 0; i < ml_max_features_; i++) {
    if (gnc_.landmark_msg_.cvs_valid_flag[i] > 0) {
      landmarks[output_i].x() = gnc_.landmark_msg_.cvs_landmarks[i];
      landmarks[output_i].y() = gnc_.landmark_msg_.cvs_landmarks[ml_max_features_ + i];
      landmarks[output_i].z() = gnc_.landmark_msg_.cvs_landmarks[2 * ml_max_features_ + i];
      observations[output_i].x() = gnc_.landmark_msg_.cvs_observations[i];
      observations[output_i].y() = gnc_.landmark_msg_.cvs_observations[ml_max_features_ + i];
      output_i++;
    }
  }
  camera::CameraModel camera(Eigen::Vector3d(), Eigen::Matrix3d::Identity(), cam_params_);
  if (sparse_mapping::RansacEstimateCamera(landmarks, observations, 1000, 3,
      &camera, &inlier_landmarks, &inlier_observations))
    return false;
  Eigen::Affine3d global_pose = camera.GetTransform().inverse();
  Eigen::Quaterniond quat(global_pose.rotation());

  ros_landmark_.header.seq++;
  ros_landmark_.header.stamp.sec = gnc_.landmark_msg_.cvs_timestamp_sec;
  ros_landmark_.header.stamp.nsec = gnc_.landmark_msg_.cvs_timestamp_nsec;
  ros_landmark_.camera_id = ml_camera_count_;

  ros_landmark_.pose.position = msg_conversions::eigen_to_ros_point(global_pose.translation());
  ros_landmark_.pose.orientation = msg_conversions::eigen_to_ros_quat(quat);
  assert(inlier_landmarks.size() == inlier_observations.size());
  ros_landmark_.landmarks.resize(inlier_landmarks.size());
  for (size_t i = 0; i < inlier_landmarks.size(); i++) {
    ff_msgs::VisualLandmark l;
    l.x = inlier_landmarks[i].x();
    l.y = inlier_landmarks[i].y();
    l.z = inlier_landmarks[i].z();
    l.u = inlier_observations[i].x();
    l.v = inlier_observations[i].y();
    ros_landmark_.landmarks[i] = l;
  }

  last_landmark_time_.sec = gnc_.landmark_msg_.cvs_timestamp_sec;
  last_landmark_time_.nsec = gnc_.landmark_msg_.cvs_timestamp_nsec;
  return true;
}

bool Sim::LandmarkEnable(ff_msgs::SetBool::Request &req, ff_msgs::SetBool::Response &res) {
  en_landmark_ = req.enable;
  res.success = true;
  return true;
}

/* TODO(Jesse, Brian) Implement this for AR tag? */
bool Sim::PullTagPulseMsg() {
  if (!(!last_tag_pulse_ && gnc_.reg_pulse_.cvs_ar_tag_pulse > 0)) {
    // early exit condition, not a rising edge
    last_tag_pulse_ = gnc_.reg_pulse_.cvs_ar_tag_pulse > 0;
    return false;
  }
  ros_reg_pulse_.camera_id = ++ar_camera_count_;
  last_tag_pulse_ = gnc_.reg_pulse_.cvs_ar_tag_pulse > 0;
  return true;
}

/* TODO(Jesse, Brian) Implement this for AR tag? */
bool Sim::PullTagMsg() {
  if (last_tag_time_.sec == gnc_.ar_tag_msg_.cvs_timestamp_sec &&
      last_tag_time_.nsec == gnc_.ar_tag_msg_.cvs_timestamp_nsec) {
    return false;
  }

  // Count how many landmarks there are
  size_t landmark_count = 0;
  for (auto flag : gnc_.ar_tag_msg_.cvs_valid_flag) {
    if (flag > 0) {
      landmark_count++;
    }
  }

  std::vector<Eigen::Vector3d> landmarks, inlier_landmarks;
  std::vector<Eigen::Vector2d> observations, inlier_observations;
  landmarks.resize(landmark_count);
  observations.resize(landmark_count);
  size_t output_i = 0;
  for (size_t i = 0; i < ar_max_features_; i++) {
    if (gnc_.ar_tag_msg_.cvs_valid_flag[i] > 0) {
      landmarks[output_i].x() = gnc_.ar_tag_msg_.cvs_landmarks[i];
      landmarks[output_i].y() = gnc_.ar_tag_msg_.cvs_landmarks[ar_max_features_ + i];
      landmarks[output_i].z() = gnc_.ar_tag_msg_.cvs_landmarks[2 * ar_max_features_ + i];
      observations[output_i].x() = gnc_.ar_tag_msg_.cvs_observations[i];
      observations[output_i].y() = gnc_.ar_tag_msg_.cvs_observations[ar_max_features_ + i];
      output_i++;
    }
  }
  camera::CameraModel camera(Eigen::Vector3d(), Eigen::Matrix3d::Identity(), cam_params_);
  if (sparse_mapping::RansacEstimateCamera(landmarks, observations, 1000, 3,
      &camera, &inlier_landmarks, &inlier_observations))
    return false;
  Eigen::Affine3d global_pose = camera.GetTransform().inverse();
  Eigen::Quaterniond quat(global_pose.rotation());

  ros_tag_.header.seq++;
  ros_tag_.header.stamp.sec = gnc_.ar_tag_msg_.cvs_timestamp_sec;
  ros_tag_.header.stamp.nsec = gnc_.ar_tag_msg_.cvs_timestamp_nsec;
  ros_tag_.camera_id = ar_camera_count_;

  ros_tag_.pose.position = msg_conversions::eigen_to_ros_point(global_pose.translation());
  ros_tag_.pose.orientation = msg_conversions::eigen_to_ros_quat(quat);
  assert(inlier_landmarks.size() == inlier_observations.size());
  ros_tag_.landmarks.resize(landmarks.size());
  for (size_t i = 0; i < landmarks.size(); i++) {
    ff_msgs::VisualLandmark l;
    l.x = landmarks[i].x();
    l.y = landmarks[i].y();
    l.z = landmarks[i].z();
    l.u = observations[i].x();
    l.v = observations[i].y();
    ros_tag_.landmarks[i] = l;
  }

  last_tag_time_.sec = gnc_.ar_tag_msg_.cvs_timestamp_sec;
  last_tag_time_.nsec = gnc_.ar_tag_msg_.cvs_timestamp_nsec;
  return true;
}

bool Sim::TagEnable(ff_msgs::SetBool::Request &req, ff_msgs::SetBool::Response &res) {
  en_tag_ = req.enable;
  res.success = true;
  return true;
}

bool Sim::PullOpticalPulseMsg() {
  if (!(!last_optical_pulse_ && gnc_.reg_pulse_.cvs_optical_flow_pulse > 0)) {
    // early exit condition, not a rising edge
    last_optical_pulse_ = gnc_.reg_pulse_.cvs_optical_flow_pulse > 0;
    return false;
  }

  ros_reg_pulse_.camera_id = ++of_camera_count_;

  last_optical_pulse_ = gnc_.reg_pulse_.cvs_optical_flow_pulse > 0;
  return true;
}

bool Sim::PullOpticalMsg() {
  if (last_optical_time_.sec == gnc_.optical_msg_.cvs_timestamp_sec &&
      last_optical_time_.nsec == gnc_.optical_msg_.cvs_timestamp_nsec) {
    return false;
  }

  ros_optical_.header.seq++;
  ros_optical_.header.stamp.sec = gnc_.optical_msg_.cvs_timestamp_sec;
  ros_optical_.header.stamp.nsec = gnc_.optical_msg_.cvs_timestamp_nsec;
  ros_optical_.camera_id = of_camera_count_;

  ros_optical_.feature_array.clear();

  // send message with all new features from this frame
  for (size_t i = 0; i < of_max_features_; i++) {
    int index = (of_history_size_ - 1) * of_max_features_;
    int valid = gnc_.optical_msg_.cvs_valid_flag[index + i];
    if (!valid)
      continue;
    float x = gnc_.optical_msg_.cvs_observations[index * 2 + i];
    float y = gnc_.optical_msg_.cvs_observations[index * 2 + i + of_max_features_];
    int id = gnc_.optical_msg_.cvs_id_tag[i];
    ff_msgs::Feature2d feature;
    feature.id = id;
    feature.x = x;
    feature.y = y;
    ros_optical_.feature_array.push_back(feature);
  }

  last_optical_time_.sec = gnc_.optical_msg_.cvs_timestamp_sec;
  last_optical_time_.nsec = gnc_.optical_msg_.cvs_timestamp_nsec;
  return true;
}

bool Sim::OpticalEnable(ff_msgs::SetBool::Request &req, ff_msgs::SetBool::Response &res) {
  en_optical_ = req.enable;
  res.success = true;
  return true;
}

bool Sim::PullDepthPulseMsg() {
  if (!(!last_depth_pulse_ && gnc_.reg_pulse_.cvs_handrail_pulse > 0)) {
    // early exit condition, not a rising edge
    last_depth_pulse_ = gnc_.reg_pulse_.cvs_handrail_pulse > 0;
    return false;
  }

  ros_reg_pulse_.camera_id = ++dl_camera_count_;

  last_depth_pulse_ = gnc_.reg_pulse_.cvs_handrail_pulse > 0;
  return true;
}

bool Sim::PullDepthMsg() {
  if (last_depth_time_.sec == gnc_.hand_msg_.cvs_timestamp_sec &&
      last_depth_time_.nsec == gnc_.hand_msg_.cvs_timestamp_nsec) {
    return false;
  }

  ros_depth_.header.seq++;
  ros_depth_.header.stamp.sec = gnc_.hand_msg_.cvs_timestamp_sec;
  ros_depth_.header.stamp.nsec = gnc_.hand_msg_.cvs_timestamp_nsec;
  ros_depth_.camera_id = dl_camera_count_;

  // Count how many landmarks there are
  size_t landmark_count = 0;
  for (auto flag : gnc_.hand_msg_.cvs_valid_flag) {
    if (flag > 0) {
      landmark_count++;
    }
  }
  ros_depth_.landmarks.resize(landmark_count);
  size_t output_i = 0;
  for (size_t i = 0; i < hr_max_features_; i++) {
    if (gnc_.hand_msg_.cvs_valid_flag[i] > 0) {
      /*
      ros_depth_.landmarks[output_i].x = gnc_.hand_msg_.cvs_landmarks[i];
      ros_depth_.landmarks[output_i].y = gnc_.hand_msg_.cvs_landmarks[hr_max_features_ + i];
      ros_depth_.landmarks[output_i].z = gnc_.hand_msg_.cvs_landmarks[2 * hr_max_features_ + i];
      */
      ros_depth_.landmarks[output_i].u = gnc_.hand_msg_.cvs_observations[i];
      ros_depth_.landmarks[output_i].v = gnc_.hand_msg_.cvs_observations[hr_max_features_ + i];
      ros_depth_.landmarks[output_i].w = gnc_.hand_msg_.cvs_observations[2 * hr_max_features_ + i];
      output_i++;
    }
  }
  ros_depth_.end_seen = gnc_.hand_msg_.cvs_3d_knowledge_flag;

  last_depth_time_.sec = gnc_.hand_msg_.cvs_timestamp_sec;
  last_depth_time_.nsec = gnc_.hand_msg_.cvs_timestamp_nsec;
  return true;
}

bool Sim::DepthEnable(ff_msgs::SetBool::Request &req, ff_msgs::SetBool::Response &res) {
  en_depth_ = req.enable;
  res.success = true;
  return true;
}

}  // end namespace sim_wrapper

max_stars_repo_name: nathantsoi/astrobee

max_issues_repo_name: nathantsoi/astrobee

max_forks_repo_name: nathantsoi/astrobee


text:
#include <iostream>
#include <armadillo>
#include <vector>
#include <cstdlib>
#include <fstream>
#include "libsnnlfisrm/snn.h"

/**
 * Calculates initial delays
*/
arma::Col<double> get_initial_delays();

/**
 * Calculates initial weights for lateral synapses
*/
arma::Col<double> get_initial_weights();

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

    // Test individual LIF/SRM neuron
    int snn_id = 2;
    int n_inputs = 2;
    int n_lateral = 1;
    std::vector<double> init_d({2, 4});
    std::vector<double> init_w({4});
    double tau_m = 1;
    double u_rest = 3;
    double init_v = 20;
    unsigned char t_rest = 2;
    double kappa_naugh = 3;
    double round_zero = 0.1;
    double u_max = 10;

    SpikeResponseModelNeuron neuron(snn_id, n_inputs, init_d, tau_m,
    u_rest, init_v, t_rest, kappa_naugh, round_zero, u_max);

    printf("delay vector: [");
    for(unsigned int i = 0; i < neuron.d_j.size(); i++)
    {
        printf(" %f ", neuron.d_j.at(i));
    }
    printf("]\n");

    // test t_pulse is working and making kappas...
    std::vector<double> u;
    printf("number of kappas: %d\n", (int)neuron.k_filter_list.at(K_LIST_INPUT_SYNAPSES).size());
    neuron.dendrite = std::vector<DelayedSpike>({DelayedSpike(0, true), DelayedSpike(0, 0)});
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.dendrite = std::vector<DelayedSpike>({DelayedSpike(0, false), DelayedSpike(0, 0)});
    neuron.t_pulse();
    u.push_back(neuron.membrane_potential());
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.dendrite = std::vector<DelayedSpike>({DelayedSpike(0, true), DelayedSpike(0, 0)});
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("membrane potential: %f\n", neuron.membrane_potential());
    u.push_back(neuron.membrane_potential());
    neuron.t_pulse();
    printf("number of kappas: %d\n", (int)neuron.k_filter_list.at(K_LIST_INPUT_SYNAPSES).size());

    printf("u plot: [ %f", u.at(0));
    for(unsigned int v = 1; v < u.size(); v++)
        printf(", %f", u.at(v));
    printf("]\n");

    // Testing FSTN
    printf("Testing Fisrt spike time neuron\n");
    double alpha = 1;
    FirstSpikeTimeNeuron fstn(0, alpha);
    fstn.dendrite = (double)2;
    fstn.t_pulse();
    fstn.dendrite = (double)2;
    fstn.t_pulse();
    fstn.dendrite = (double)2;
    fstn.t_pulse();
    fstn.dendrite = (double)2;
    fstn.t_pulse();
    fstn.dendrite = (double)2;
    fstn.t_pulse();
    fstn.dendrite = (double)2;
    fstn.t_pulse();
    fstn.dendrite = (double)2;
    fstn.t_pulse();
    fstn.dendrite = (double)2;
    fstn.t_pulse();
    fstn.dendrite = (double)5;
    fstn.t_pulse();
    fstn.dendrite = (double)5;
    fstn.t_pulse();
    fstn.dendrite = (double)5;
    fstn.t_pulse();
    fstn.dendrite = (double)5;
    fstn.t_pulse();
    fstn.dendrite = (double)5;
    fstn.t_pulse();
    fstn.dendrite = (double)5;
    fstn.t_pulse();
    fstn.dendrite = (double)5;
    fstn.t_pulse();
    fstn.dendrite = (double)5;
    fstn.t_pulse();
    fstn.dendrite = (double)5;
    fstn.t_pulse();
    fstn.dendrite = (double)5;
    fstn.t_pulse();
    fstn.dendrite = (double)5;
    fstn.t_pulse();
    fstn.dendrite = (double)5;
    fstn.t_pulse();

    // Testing neural network
    // parameters:
    unsigned int i_layer_size = 2;
    unsigned int h_layer_size = 16;
    std::vector<std::vector<double>> d_init({
        {4, 3, 2, 3, 4, 3, 3, 2, 1, 4, 3, 3, 3, 2, 5, 2},
        {1, 4, 2, 4, 6, 2, 1, 3, 5, 3, 3, 3, 3, 2, 5, 2}
    });
    std::vector<std::vector<double>> w_init({
        {1, 3, 2, -1, 3, 1, -2, 1, -2, 1, 3, 3, 3, 2, 5, 2},
        {3, 4, 2, 3, 4, 12, 1, 1, 2, 1, 3, 3, 3, 2, 5, 2},
        {2, 3, 2, 1, 2, 1, 2, 1, 1, 2, 3, 3, 3, 2, 5, 2},
        {-1, -2, -1, -2, -3, -4, -9, -1, 2, -2, 3, 3, 3, 2, 5, 2},
        {3, 4, 2, 1, 3, 6, 3, 1, 2, 3, 3, 3, 3, 2, 5, 2},
        {1, 3, 1, 3, 5, 3, 1, 0, 3, 1, 3, 3, 3, 2, 5, 2},
        {-2, -3, -1, -3, -5, 3, 2, 4, 5, 4, 3, 3, 3, 2, 5, 2},
        {1, 6, 2, 2, 4, 6, 3, 2, 4, 5, 3, 3, 3, 2, 5, 2},
        {-2, -5, -1, 4, -1, -3, 2, -7, -1, 3, 3, 3, 3, 2, 5, 2},
        {1, 5, 7, 2, 4, 6, 4, 1, 3, 5, 3, 3, 3, 2, 5, 2},
        {1, 5, 7, 2, 4, 6, 4, 1, 3, 5, 3, 3, 3, 2, 5, 2},
        {1, 5, 7, 2, 4, 6, 4, 1, 3, 5, 3, 3, 3, 2, 5, 2},
        {1, 5, 7, 2, 4, 6, 4, 1, 3, 5, 3, 3, 3, 2, 5, 2},
        {1, 5, 7, 2, 4, 6, 4, 1, 3, 5, 3, 3, 3, 2, 5, 2},
        {1, 5, 7, 2, 4, 6, 4, 1, 3, 5, 3, 3, 3, 2, 5, 2},
        {1, 5, 7, 2, 4, 6, 4, 1, 3, 5, 3, 3, 3, 2, 5, 2},
    });
    tau_m = 4;
    u_rest = 0;
    init_v = 20;
    double t_reset = 3;
    double k_nought = 10;
    round_zero = 0.1;
    alpha = 2;

    BaseSNN snn(i_layer_size, d_init, tau_m, u_rest, init_v, t_reset, k_nought,
    round_zero, alpha, u_max);

    snn.re_process({0, 0});
    for(int p = 0; p < 20; p++)
    {
        snn.process();
        for(unsigned int i = 0; i < h_layer_size; i++)
        {
            double u_i = snn.hidden_layer.at(i).membrane_potential();
            printf("U_%u = %f\n", i, u_i);
            if(snn.hidden_layer.at(i).axon.signal)
            {
                // this neuron is the "winner"
                printf("Spike %u winner (Reached threshold)\n", i);
                goto next_test;
            }
        }
    }
    next_test:
    // Test euclidean_distance_matrix function
    double distance_unit = 2;

    printf("Testing matrices.\n");
    arma::Mat<double> e_mat = euclidean_distance_matrix (&snn, distance_unit);
    printf("Matrix Content\n\n");
    for(unsigned int i = 0; i < snn.h_layer_size; i++)
    {
        for(unsigned int j = 0; j < snn.h_layer_size; j++)
        {
            printf("%f\t", e_mat(i, j));
        }
        printf("\n");
    }

    // Test euclidean initial weight function
    double sigma_1 = .5;
    double sigma_2 = 2;
    std::vector<arma::Col<double>> w_mat = initial_weight_euclidean(e_mat, sigma_1, sigma_2);
    printf("\nPrinting weight matrix's contents:\n\n");
    printf("Weight Matrix Content\n\n");
    for(unsigned int i = 0; i < snn.h_layer_size; i++)
    {
        for(unsigned int j = 0; j < snn.h_layer_size; j++)
        {
            printf("%f\t", w_mat.at(i).at(j));
        }
        printf("\n");
    }

    // Testing euclidean_distance_matrix without snn
    std::vector<std::vector<double>> point_list({
        {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3},
        {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3}
    });

    printf("Testing matrices.\n");
    arma::Mat<double> e_mat_init = euclidean_distance_matrix(&point_list, distance_unit);
    printf("Matrix Content\n\n");
    for(unsigned int i = 0; i < e_mat_init.n_rows; i++)
    {
        for(unsigned int j = 0; j < e_mat_init.n_cols; j++)
        {
            printf("%f\t", e_mat_init(i, j));
        }
        printf("\n");
    }

    // Testing Random delay generator
    printf("\nTesting Random Delay generator\n");
    std::vector<std::vector<double>> initial_delays;

    unsigned int n_x = 10;
    unsigned int n_y = 10;
    unsigned int delays_per_row = 10;
    unsigned int delays_per_column = 10;

    initial_delays = initial_delay_vector_2d_map(n_x, n_y,
    delays_per_row, delays_per_column);

    printf("Delay Matrix Content\n\n");
    for(unsigned int i = 0; i < initial_delays.size(); i++)
    {
        for(unsigned int j = 0; j < initial_delays.at(i).size(); j++)
        {
            printf("%f\t", initial_delays.at(i).at(j));
        }
        printf("\n");
    }

    // Test point map creator
    printf("\nTesting point map creator.\n");
    unsigned int x_size = 4;
    unsigned int y_size = 7;
    std::vector<std::vector<double>> map_ = euclidean_point_map(x_size, y_size);
    printf("Point Map Matrix Content\n\n");

    for(unsigned int j = 0; j < x_size*y_size; j++)
    {
        printf("(%f, %f)\t", map_.at(0).at(j), map_.at(1).at(j));
    }

    // Testing training algorthm
    unsigned int n_data = 2;
    tau_m = 1.5;
    u_rest = 2;
    init_v = 4.5;
    t_reset = 3;
    k_nought = 2.5;
    round_zero = 0.05;
    alpha = 4;
    // note that n_x * n_y = h_layer_size
    n_x = 10;
    n_y = 10;
    double delay_distance = 1;
    distance_unit = 1;
    sigma_1 = 0.7;
    sigma_2 = 1.6;

    double sigma_neighbor = 1;

    double eta_d = .5;
    unsigned int t_max = 25;
    unsigned int t_delta = 3;
    double ltd_max = -0.45;
    SNN model(n_data, tau_m, u_rest, init_v,
    t_reset, k_nought, round_zero, alpha, n_x, n_y, delay_distance,
    distance_unit, sigma_neighbor, eta_d, t_max, u_max);

    std::vector<std::vector<double>> data = {
        {0, 0, 0, 1, 2, 2, 3, 3, 3, 3, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0},
        {0, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0}
    };
    std::vector<std::vector<double>> data_2 = {
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1},
    };

    // save delays into file:
    std::ofstream delay_file;
    delay_file.open("snn_data_delays.txt");

    // print out delays
    delay_file << "Delays before training:" << std::endl;
    for(unsigned int i = 0; i < model.snn->d_ji.size(); i++)
    {
        delay_file << "[ ";
        for(unsigned int j = 0; j < model.snn->d_ji.at(i).size(); j++)
        {
            delay_file << model.snn->d_ji.at(i).at(j) << ", ";
        }
        delay_file << "]" << std::endl;
    }
    // print out weights

    for(unsigned int p = 0; p < 1; p++)
        model.train(data);

    delay_file << std::endl << "Delays after training:"<< std::endl;
     for(unsigned int i = 0; i < model.snn->d_ji.size(); i++)
    {
        delay_file << "[ ";
        for(unsigned int j = 0; j < model.snn->d_ji.at(i).size(); j++)
        {
            delay_file << model.snn->d_ji.at(i).at(j) << ", ";
        }
        delay_file << "]" << std::endl;
    }
    delay_file.close();

    // Armadillo version printout
    arma::arma_version ver;
    printf("\nArmadillo Version: %s\n", ver.as_string().c_str());
    return 0;
}