<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkPointwiseMutualInformation.cxx

-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkArrayCoordinates.h"
#include "vtkCommand.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkPointwiseMutualInformation.h"
#include "vtkObjectFactory.h"
#include "vtkSmartPointer.h"
#include "vtkTypedArray.h"

#include <cmath>
#include <algorithm>
#include <vtkstd/stdexcept>

///////////////////////////////////////////////////////////////////////////////
// vtkPointwiseMutualInformation

vtkCxxRevisionMacro(vtkPointwiseMutualInformation, "1.1");
vtkStandardNewMacro(vtkPointwiseMutualInformation);

vtkPointwiseMutualInformation::vtkPointwiseMutualInformation()
{
}

vtkPointwiseMutualInformation::~vtkPointwiseMutualInformation()
{
}

void vtkPointwiseMutualInformation::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}

int vtkPointwiseMutualInformation::RequestData(
  vtkInformation*,
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  try
    {
    // Enforce our input preconditions ...
    vtkArrayData* const input_data = vtkArrayData::GetData(inputVector[0]);
    if(!input_data)
      throw vtkstd::runtime_error("Missing vtkArrayData on input port 0.");
    if(input_data->GetNumberOfArrays() != 1)
      throw vtkstd::runtime_error("vtkArrayData on input port 0 must contain exactly one vtkArray.");
    vtkTypedArray<double>* const input_array = vtkTypedArray<double>::SafeDownCast(input_data->GetArray(0));
    if(!input_array)
      throw vtkstd::runtime_error("Unsupported input array type.");

    const vtkIdType dimension_count = input_array->GetDimensions();
    const vtkIdType value_count = input_array->GetNonNullSize();

    // This is a portable way to compute log base-2 ...
    static const double ln2 = log(2.0);

    // Compute array value sums along each dimension ...
    double array_sum = 0.0;
    vtkstd::vector<vtkstd::vector<double> > dimension_sums(dimension_count);
    for(vtkIdType i = 0; i != dimension_count; ++i)
      {
      dimension_sums[i].resize(input_array->GetExtents()[i], 0.0);
      }

    vtkArrayCoordinates coordinates;
    for(vtkIdType n = 0; n != value_count; ++n)
      {
      const double value = input_array->GetValueN(n);
      input_array->GetCoordinatesN(n, coordinates);

      array_sum += value;
      for(vtkIdType i = 0; i != dimension_count; ++i)
        {
        dimension_sums[i][coordinates[i]] += value;
        }
      }

    if(!array_sum)
      throw vtkstd::runtime_error("Cannot compute PMI with zero array probability.");
    for(vtkIdType i = 0; i != dimension_count; ++i)
      {
      if(vtkstd::count(dimension_sums[i].begin(), dimension_sums[i].end(), 0))
        throw vtkstd::runtime_error("Cannot compute PMI with zero dimension sums.");
      }

    // Create an output array ...
    vtkTypedArray<double>* const output_array = vtkTypedArray<double>::SafeDownCast(input_array->DeepCopy());
    vtkArrayData* const output = vtkArrayData::GetData(outputVector);
    output->ClearArrays();
    output->AddArray(output_array);
    output_array->Delete();

    // Compute the PMI for each array value ...
    for(vtkIdType n = 0; n != value_count; ++n)
      {
      const double value = input_array->GetValueN(n);
      if(!value)
        {
        output_array->SetValueN(n, 0);
        continue;
        }

      input_array->GetCoordinatesN(n, coordinates);

      double result = value / array_sum;
      for(vtkIdType i = 0; i != dimension_count; ++i)
        {
        result /= (value / dimension_sums[i][coordinates[i]]);
        }

      output_array->SetValueN(n, vtkstd::log(result) / ln2);
      }
    }
  catch(vtkstd::exception& e)
    {
    vtkErrorMacro(<< "unhandled exception: " << e.what());
    return 0;
    }
  catch(...)
    {
    vtkErrorMacro(<< "unknown exception");
    return 0;
    }

  return 1;
}

<commit_msg>BUG: Enable vtkPointwiseMutualInformation filter to handle empty input data gracefully.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkPointwiseMutualInformation.cxx

-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkArrayCoordinates.h"
#include "vtkCommand.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkPointwiseMutualInformation.h"
#include "vtkObjectFactory.h"
#include "vtkSmartPointer.h"
#include "vtkTypedArray.h"

#include <cmath>
#include <algorithm>
#include <vtkstd/stdexcept>

///////////////////////////////////////////////////////////////////////////////
// vtkPointwiseMutualInformation

vtkCxxRevisionMacro(vtkPointwiseMutualInformation, "1.2");
vtkStandardNewMacro(vtkPointwiseMutualInformation);

vtkPointwiseMutualInformation::vtkPointwiseMutualInformation()
{
}

vtkPointwiseMutualInformation::~vtkPointwiseMutualInformation()
{
}

void vtkPointwiseMutualInformation::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}

int vtkPointwiseMutualInformation::RequestData(
  vtkInformation*,
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  try
    {
    // Enforce our input preconditions ...
    vtkArrayData* const input_data = vtkArrayData::GetData(inputVector[0]);
    if(!input_data)
      throw vtkstd::runtime_error("Missing vtkArrayData on input port 0.");
    if(input_data->GetNumberOfArrays() != 1)
      throw vtkstd::runtime_error("vtkArrayData on input port 0 must contain exactly one vtkArray.");
    vtkTypedArray<double>* const input_array = vtkTypedArray<double>::SafeDownCast(input_data->GetArray(0));
    if(!input_array)
      throw vtkstd::runtime_error("Unsupported input array type.");

    // Create an output array ...
    vtkTypedArray<double>* const output_array = vtkTypedArray<double>::SafeDownCast(input_array->DeepCopy());
    vtkArrayData* const output = vtkArrayData::GetData(outputVector);
    output->ClearArrays();
    output->AddArray(output_array);
    output_array->Delete();

    const vtkIdType dimension_count = input_array->GetDimensions();
    const vtkIdType value_count = input_array->GetNonNullSize();

    if(value_count == 0)
      {
      // Allow for an empty input
      return 1;
      }

    // This is a portable way to compute log base-2 ...
    static const double ln2 = log(2.0);

    // Compute array value sums along each dimension ...
    double array_sum = 0.0;
    vtkstd::vector<vtkstd::vector<double> > dimension_sums(dimension_count);
    for(vtkIdType i = 0; i != dimension_count; ++i)
      {
      dimension_sums[i].resize(input_array->GetExtents()[i], 0.0);
      }

    vtkArrayCoordinates coordinates;
    for(vtkIdType n = 0; n != value_count; ++n)
      {
      const double value = input_array->GetValueN(n);
      input_array->GetCoordinatesN(n, coordinates);

      array_sum += value;
      for(vtkIdType i = 0; i != dimension_count; ++i)
        {
        dimension_sums[i][coordinates[i]] += value;
        }
      }

    if(!array_sum)
      throw vtkstd::runtime_error("Cannot compute PMI with zero array probability.");
    for(vtkIdType i = 0; i != dimension_count; ++i)
      {
      if(vtkstd::count(dimension_sums[i].begin(), dimension_sums[i].end(), 0))
        throw vtkstd::runtime_error("Cannot compute PMI with zero dimension sums.");
      }

    // Compute the PMI for each array value ...
    for(vtkIdType n = 0; n != value_count; ++n)
      {
      const double value = input_array->GetValueN(n);
      if(!value)
        {
        output_array->SetValueN(n, 0);
        continue;
        }

      input_array->GetCoordinatesN(n, coordinates);

      double result = value / array_sum;
      for(vtkIdType i = 0; i != dimension_count; ++i)
        {
        result /= (value / dimension_sums[i][coordinates[i]]);
        }

      output_array->SetValueN(n, vtkstd::log(result) / ln2);
      }
    }
  catch(vtkstd::exception& e)
    {
    vtkErrorMacro(<< "unhandled exception: " << e.what());
    return 0;
    }
  catch(...)
    {
    vtkErrorMacro(<< "unknown exception");
    return 0;
    }

  return 1;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2004-2007 Marc Boris Duerner
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

namespace std {

locale::id numpunct<cxxtools::Char>::id;

numpunct<cxxtools::Char>::numpunct(size_t refs)
: locale::facet(refs)
{ }

numpunct<cxxtools::Char>::~numpunct()
{ }

cxxtools::Char numpunct<cxxtools::Char>::decimal_point() const
{ return this->do_decimal_point(); }

cxxtools::Char numpunct<cxxtools::Char>::thousands_sep() const
{ return this->do_thousands_sep(); }

string numpunct<cxxtools::Char>::grouping() const
{ return this->do_grouping(); }

cxxtools::String numpunct<cxxtools::Char>::truename() const
{ return this->do_truename(); }

cxxtools::String numpunct<cxxtools::Char>::falsename() const
{ return this->do_falsename(); }

cxxtools::Char numpunct<cxxtools::Char>::do_decimal_point() const
{ return '.'; }

cxxtools::Char numpunct<cxxtools::Char>::do_thousands_sep() const
{ return ','; }

std::string numpunct<cxxtools::Char>::do_grouping() const
{ return ""; }

cxxtools::String numpunct<cxxtools::Char>::do_truename() const
{
    static const cxxtools::Char truename[] = {'t', 'r', 'u', 'e', '\0'};
    return truename;
}

cxxtools::String numpunct<cxxtools::Char>::do_falsename() const
{
    static const cxxtools::Char falsename[] = {'f', 'a', 'l', 's', 'e', '\0'};
    return falsename;
}

}
<commit_msg>added #include facets.h in facets.cpp<commit_after>/*
 * Copyright (C) 2004-2007 Marc Boris Duerner
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <cxxtools/facets.h>

namespace std {

locale::id numpunct<cxxtools::Char>::id;

numpunct<cxxtools::Char>::numpunct(size_t refs)
: locale::facet(refs)
{ }

numpunct<cxxtools::Char>::~numpunct()
{ }

cxxtools::Char numpunct<cxxtools::Char>::decimal_point() const
{ return this->do_decimal_point(); }

cxxtools::Char numpunct<cxxtools::Char>::thousands_sep() const
{ return this->do_thousands_sep(); }

string numpunct<cxxtools::Char>::grouping() const
{ return this->do_grouping(); }

cxxtools::String numpunct<cxxtools::Char>::truename() const
{ return this->do_truename(); }

cxxtools::String numpunct<cxxtools::Char>::falsename() const
{ return this->do_falsename(); }

cxxtools::Char numpunct<cxxtools::Char>::do_decimal_point() const
{ return '.'; }

cxxtools::Char numpunct<cxxtools::Char>::do_thousands_sep() const
{ return ','; }

std::string numpunct<cxxtools::Char>::do_grouping() const
{ return ""; }

cxxtools::String numpunct<cxxtools::Char>::do_truename() const
{
    static const cxxtools::Char truename[] = {'t', 'r', 'u', 'e', '\0'};
    return truename;
}

cxxtools::String numpunct<cxxtools::Char>::do_falsename() const
{
    static const cxxtools::Char falsename[] = {'f', 'a', 'l', 's', 'e', '\0'};
    return falsename;
}

}
<|endoftext|>


<commit_before>#include <AndroidClient.h>
#include <jni.h>
#include <android/log.h>
#include <vector>

AndroidClientCache::AndroidClientCache(JNIEnv * _env) {
  _env->GetJavaVM(&javaVM);
  auto env = getJNIEnv();

  cookieManagerClass = (jclass) env->NewGlobalRef(env->FindClass("android/webkit/CookieManager"));
  httpClass = (jclass) env->NewGlobalRef(env->FindClass("java/net/HttpURLConnection"));
  urlClass = (jclass) env->NewGlobalRef(env->FindClass("java/net/URL"));
  inputStreamClass = (jclass) env->NewGlobalRef(env->FindClass("java/io/InputStream"));
  frameworkClass = (jclass) env->NewGlobalRef(env->FindClass("com/sometrik/framework/FrameWork"));

  getHeaderMethod = env->GetMethodID(httpClass, "getHeaderField", "(Ljava/lang/String;)Ljava/lang/String;");
  getHeaderMethodInt = env->GetMethodID(httpClass, "getHeaderField", "(I)Ljava/lang/String;");
  getHeaderKeyMethod = env->GetMethodID(httpClass, "getHeaderFieldKey", "(I)Ljava/lang/String;");
  readMethod = env->GetMethodID(inputStreamClass, "read", "([B)I");
  urlConstructor = env->GetMethodID(urlClass, "<init>", "(Ljava/lang/String;)V");
  openConnectionMethod = env->GetMethodID(urlClass, "openConnection", "()Ljava/net/URLConnection;");
  setRequestProperty = env->GetMethodID(httpClass, "setRequestProperty", "(Ljava/lang/String;Ljava/lang/String;)V");
  setRequestMethod = env->GetMethodID(httpClass, "setRequestMethod", "(Ljava/lang/String;)V");
  setFollowMethod = env->GetMethodID(httpClass, "setInstanceFollowRedirects", "(Z)V");
  setDoInputMethod = env->GetMethodID(httpClass, "setDoInput", "(Z)V");
  connectMethod = env->GetMethodID(httpClass, "connect", "()V");
  getResponseCodeMethod = env->GetMethodID(httpClass, "getResponseCode", "()I");
  getResponseMessageMethod = env->GetMethodID(httpClass, "getResponseMessage", "()Ljava/lang/String;");
  setRequestPropertyMethod = env->GetMethodID(httpClass, "setRequestProperty", "(Ljava/lang/String;Ljava/lang/String;)V");
  clearCookiesMethod = env->GetMethodID(cookieManagerClass, "removeAllCookie", "()V");
  getInputStreamMethod = env->GetMethodID(httpClass, "getInputStream", "()Ljava/io/InputStream;");
  getErrorStreamMethod = env->GetMethodID(httpClass, "getErrorStream", "()Ljava/io/InputStream;");
  handleThrowableMethod = env->GetStaticMethodID(frameworkClass, "handleNativeException", "(Ljava/lang/Throwable;)V");
}

AndroidClientCache::~AndroidClientCache() {
  auto env = getJNIEnv();
  env->DeleteGlobalRef(cookieManagerClass);
  env->DeleteGlobalRef(httpClass);
  env->DeleteGlobalRef(urlClass);
  env->DeleteGlobalRef(inputStreamClass);
  env->DeleteGlobalRef(frameworkClass);
}

class AndroidClient : public HTTPClient {
public:
  AndroidClient(const std::shared_ptr<AndroidClientCache> & _cache, const std::string & _user_agent, bool _enable_cookies, bool _enable_keepalive)
    : HTTPClient(_user_agent, _enable_cookies, _enable_keepalive), cache(_cache) {
  }

  void request(const HTTPRequest & req, const Authorization & auth, HTTPClientInterface & callback) {
    JNIEnv * env = cache->getJNIEnv();

    __android_log_print(ANDROID_LOG_INFO, "AndroidClien", "Host = %s", req.getURI().c_str());

    jobject url = env->NewObject(cache->urlClass, cache->urlConstructor, env->NewStringUTF(req.getURI().c_str()));

    jobject connection = env->CallObjectMethod(url, cache->openConnectionMethod);
    env->DeleteLocalRef(url),

    //Authorization example
//    env->CallVoidMethod(connection, setRequestPropertyMethod, env->NewStringUTF("Authorization"), env->NewStringUTF("myUsername"));
//    std::string auth_header = auth.createHeader();
//    if (!auth_header.empty()) {
//      env->CallVoidMethod(connection, setRequestPropertyMethod, env->NewStringUTF(auth.getHeaderName()), env->NewStringUTF(auth_header.c_str()));
//    }

    env->CallVoidMethod(connection, cache->setFollowMethod, req.getFollowLocation() ? JNI_TRUE : JNI_FALSE);

    //Apply user agent
    const char * cuser_agent = user_agent.c_str();
    const char * cuser_agent_key = "User-Agent";
    jstring juser_agent = env->NewStringUTF(user_agent.c_str());
    jstring juser_agent_key = env->NewStringUTF(cuser_agent_key);
    env->CallVoidMethod(connection, cache->setRequestProperty, juser_agent_key, juser_agent);
    env->DeleteLocalRef(juser_agent);
    env->DeleteLocalRef(juser_agent_key);

    // Setting headers for request
    std::map<std::string, std::string> combined_headers;
    for (auto & hd : default_headers) {
      combined_headers[hd.first] = hd.second;
    }
    for (auto & hd : req.getHeaders()) {
      combined_headers[hd.first] = hd.second;
    }
    for (auto & hd : combined_headers) {
      jstring firstHeader = env->NewStringUTF(hd.first.c_str());
      jstring secondHeader = env->NewStringUTF(hd.second.c_str());
      env->CallVoidMethod(connection, cache->setRequestPropertyMethod, firstHeader, secondHeader);
      env->ReleaseStringUTFChars(firstHeader, hd.first.c_str());
      env->ReleaseStringUTFChars(secondHeader, hd.second.c_str());
    }

    env->CallVoidMethod(connection, cache->setRequestMethod, env->NewStringUTF(req.getTypeString()));
    int responseCode = env->CallIntMethod(connection, cache->getResponseCodeMethod);

    __android_log_print(ANDROID_LOG_VERBOSE, "AndroidClient", "the real problem is here?");
    // Server not found error
    if (env->ExceptionCheck()) {
      jthrowable error = env->ExceptionOccurred();
      env->ExceptionClear();
      env->CallStaticVoidMethod(cache->frameworkClass, cache->handleThrowableMethod, error);
      env->DeleteLocalRef(error);

      __android_log_print(ANDROID_LOG_INFO, "AndroidClient", "EXCEPTION http request responsecode = %i", responseCode);
      callback.handleResultCode(500);
      // callback->handleResultText("Server not found");
      return;
    }

    callback.handleResultCode(responseCode);

    const char *errorMessage = "";
    jobject input;

    if (responseCode >= 400 && responseCode <= 599) {
      __android_log_print(ANDROID_LOG_INFO, "AndroidClient", "request responsecode = %i", responseCode);
      jstring javaMessage = (jstring)env->CallObjectMethod(connection, cache->getResponseMessageMethod);
      errorMessage = env->GetStringUTFChars(javaMessage, 0);
      __android_log_print(ANDROID_LOG_INFO, "AndroidClient", "errorMessage = %s", errorMessage);

      input = env->CallObjectMethod(connection, cache->getErrorStreamMethod);
    } else {
      __android_log_print(ANDROID_LOG_INFO, "AndroidClient", "http request responsecode = %i", responseCode);

      input = env->CallObjectMethod(connection, cache->getInputStreamMethod);
      env->ExceptionClear();
    }

    jbyteArray array = env->NewByteArray(4096);
    int g = 0;

    __android_log_print(ANDROID_LOG_VERBOSE, "Sometrik", "Starting to gather content");

    // Gather headers and values
    for (int i = 0; ; i++) {
      jstring jheaderKey = (jstring)env->CallObjectMethod(connection, cache->getHeaderKeyMethod, i);
      const char * headerKey = env->GetStringUTFChars(jheaderKey, 0);
      __android_log_print(ANDROID_LOG_INFO, "content", "header key = %s", headerKey);

      jstring jheader = (jstring)env->CallObjectMethod(connection, cache->getHeaderMethodInt, i);
      const char * header = env->GetStringUTFChars(jheader, 0);
      __android_log_print(ANDROID_LOG_INFO, "content", "header value = %s", header);
      if (headerKey == NULL) {
	break;
      }
      callback.handleHeader(headerKey, header);
      env->ReleaseStringUTFChars(jheaderKey, headerKey);
      env->ReleaseStringUTFChars(jheader, header);
      env->DeleteLocalRef(jheaderKey);
      env->DeleteLocalRef(jheader);
    }

    // Gather content
    while ((g = env->CallIntMethod(input, cache->readMethod, array)) != -1) {
      jbyte* content_array = env->GetByteArrayElements(array, NULL);
      callback.handleChunk(g, (char*) content_array);
      env->ReleaseByteArrayElements(array, content_array, JNI_ABORT);
    }
    env->DeleteLocalRef(array);

    if (responseCode >= 300 && responseCode <= 399) {
      jstring followURL = (jstring)env->CallObjectMethod(connection, cache->getHeaderMethod, env->NewStringUTF("location"));
      const char *followString = env->GetStringUTFChars(followURL, 0);
      callback.handleRedirectUrl(followString);
      __android_log_print(ANDROID_LOG_INFO, "content", "followURL = %s", followString);
      env->ReleaseStringUTFChars(followURL, followString);
      env->DeleteLocalRef(followURL);
    }

    __android_log_print(ANDROID_LOG_VERBOSE, "AndroidClient", "nope");
    env->DeleteLocalRef(input);
    env->DeleteLocalRef(connection);
}

  void clearCookies() {
    JNIEnv * env = cache->getJNIEnv();
    env->CallVoidMethod(cache->cookieManagerClass, cache->clearCookiesMethod);
  }

private:
  std::shared_ptr<AndroidClientCache> cache;
};

std::unique_ptr<HTTPClient>
AndroidClientFactory::createClient2(const std::string & _user_agent, bool _enable_cookies, bool _enable_keepalive) {
  return std::unique_ptr<AndroidClient>(new AndroidClient(cache, _user_agent, _enable_cookies, _enable_keepalive));
}
<commit_msg>Remove stupid print<commit_after>#include <AndroidClient.h>
#include <jni.h>
#include <android/log.h>
#include <vector>

AndroidClientCache::AndroidClientCache(JNIEnv * _env) {
  _env->GetJavaVM(&javaVM);
  auto env = getJNIEnv();

  cookieManagerClass = (jclass) env->NewGlobalRef(env->FindClass("android/webkit/CookieManager"));
  httpClass = (jclass) env->NewGlobalRef(env->FindClass("java/net/HttpURLConnection"));
  urlClass = (jclass) env->NewGlobalRef(env->FindClass("java/net/URL"));
  inputStreamClass = (jclass) env->NewGlobalRef(env->FindClass("java/io/InputStream"));
  frameworkClass = (jclass) env->NewGlobalRef(env->FindClass("com/sometrik/framework/FrameWork"));

  getHeaderMethod = env->GetMethodID(httpClass, "getHeaderField", "(Ljava/lang/String;)Ljava/lang/String;");
  getHeaderMethodInt = env->GetMethodID(httpClass, "getHeaderField", "(I)Ljava/lang/String;");
  getHeaderKeyMethod = env->GetMethodID(httpClass, "getHeaderFieldKey", "(I)Ljava/lang/String;");
  readMethod = env->GetMethodID(inputStreamClass, "read", "([B)I");
  urlConstructor = env->GetMethodID(urlClass, "<init>", "(Ljava/lang/String;)V");
  openConnectionMethod = env->GetMethodID(urlClass, "openConnection", "()Ljava/net/URLConnection;");
  setRequestProperty = env->GetMethodID(httpClass, "setRequestProperty", "(Ljava/lang/String;Ljava/lang/String;)V");
  setRequestMethod = env->GetMethodID(httpClass, "setRequestMethod", "(Ljava/lang/String;)V");
  setFollowMethod = env->GetMethodID(httpClass, "setInstanceFollowRedirects", "(Z)V");
  setDoInputMethod = env->GetMethodID(httpClass, "setDoInput", "(Z)V");
  connectMethod = env->GetMethodID(httpClass, "connect", "()V");
  getResponseCodeMethod = env->GetMethodID(httpClass, "getResponseCode", "()I");
  getResponseMessageMethod = env->GetMethodID(httpClass, "getResponseMessage", "()Ljava/lang/String;");
  setRequestPropertyMethod = env->GetMethodID(httpClass, "setRequestProperty", "(Ljava/lang/String;Ljava/lang/String;)V");
  clearCookiesMethod = env->GetMethodID(cookieManagerClass, "removeAllCookie", "()V");
  getInputStreamMethod = env->GetMethodID(httpClass, "getInputStream", "()Ljava/io/InputStream;");
  getErrorStreamMethod = env->GetMethodID(httpClass, "getErrorStream", "()Ljava/io/InputStream;");
  handleThrowableMethod = env->GetStaticMethodID(frameworkClass, "handleNativeException", "(Ljava/lang/Throwable;)V");
}

AndroidClientCache::~AndroidClientCache() {
  auto env = getJNIEnv();
  env->DeleteGlobalRef(cookieManagerClass);
  env->DeleteGlobalRef(httpClass);
  env->DeleteGlobalRef(urlClass);
  env->DeleteGlobalRef(inputStreamClass);
  env->DeleteGlobalRef(frameworkClass);
}

class AndroidClient : public HTTPClient {
public:
  AndroidClient(const std::shared_ptr<AndroidClientCache> & _cache, const std::string & _user_agent, bool _enable_cookies, bool _enable_keepalive)
    : HTTPClient(_user_agent, _enable_cookies, _enable_keepalive), cache(_cache) {
  }

  void request(const HTTPRequest & req, const Authorization & auth, HTTPClientInterface & callback) {
    JNIEnv * env = cache->getJNIEnv();

    __android_log_print(ANDROID_LOG_INFO, "AndroidClien", "Host = %s", req.getURI().c_str());

    jobject url = env->NewObject(cache->urlClass, cache->urlConstructor, env->NewStringUTF(req.getURI().c_str()));

    jobject connection = env->CallObjectMethod(url, cache->openConnectionMethod);
    env->DeleteLocalRef(url),

    //Authorization example
//    env->CallVoidMethod(connection, setRequestPropertyMethod, env->NewStringUTF("Authorization"), env->NewStringUTF("myUsername"));
//    std::string auth_header = auth.createHeader();
//    if (!auth_header.empty()) {
//      env->CallVoidMethod(connection, setRequestPropertyMethod, env->NewStringUTF(auth.getHeaderName()), env->NewStringUTF(auth_header.c_str()));
//    }

    env->CallVoidMethod(connection, cache->setFollowMethod, req.getFollowLocation() ? JNI_TRUE : JNI_FALSE);

    //Apply user agent
    const char * cuser_agent = user_agent.c_str();
    const char * cuser_agent_key = "User-Agent";
    jstring juser_agent = env->NewStringUTF(user_agent.c_str());
    jstring juser_agent_key = env->NewStringUTF(cuser_agent_key);
    env->CallVoidMethod(connection, cache->setRequestProperty, juser_agent_key, juser_agent);
    env->DeleteLocalRef(juser_agent);
    env->DeleteLocalRef(juser_agent_key);

    // Setting headers for request
    std::map<std::string, std::string> combined_headers;
    for (auto & hd : default_headers) {
      combined_headers[hd.first] = hd.second;
    }
    for (auto & hd : req.getHeaders()) {
      combined_headers[hd.first] = hd.second;
    }
    for (auto & hd : combined_headers) {
      jstring firstHeader = env->NewStringUTF(hd.first.c_str());
      jstring secondHeader = env->NewStringUTF(hd.second.c_str());
      env->CallVoidMethod(connection, cache->setRequestPropertyMethod, firstHeader, secondHeader);
      env->ReleaseStringUTFChars(firstHeader, hd.first.c_str());
      env->ReleaseStringUTFChars(secondHeader, hd.second.c_str());
    }

    env->CallVoidMethod(connection, cache->setRequestMethod, env->NewStringUTF(req.getTypeString()));
    int responseCode = env->CallIntMethod(connection, cache->getResponseCodeMethod);

    __android_log_print(ANDROID_LOG_VERBOSE, "AndroidClient", "the real problem is here?");
    // Server not found error
    if (env->ExceptionCheck()) {
      jthrowable error = env->ExceptionOccurred();
      env->ExceptionClear();
      env->CallStaticVoidMethod(cache->frameworkClass, cache->handleThrowableMethod, error);
      env->DeleteLocalRef(error);

      __android_log_print(ANDROID_LOG_INFO, "AndroidClient", "EXCEPTION http request responsecode = %i", responseCode);
      callback.handleResultCode(500);
      // callback->handleResultText("Server not found");
      return;
    }

    callback.handleResultCode(responseCode);

    const char *errorMessage = "";
    jobject input;

    if (responseCode >= 400 && responseCode <= 599) {
      __android_log_print(ANDROID_LOG_INFO, "AndroidClient", "request responsecode = %i", responseCode);
      jstring javaMessage = (jstring)env->CallObjectMethod(connection, cache->getResponseMessageMethod);
      errorMessage = env->GetStringUTFChars(javaMessage, 0);
      __android_log_print(ANDROID_LOG_INFO, "AndroidClient", "errorMessage = %s", errorMessage);

      input = env->CallObjectMethod(connection, cache->getErrorStreamMethod);
    } else {
      __android_log_print(ANDROID_LOG_INFO, "AndroidClient", "http request responsecode = %i", responseCode);

      input = env->CallObjectMethod(connection, cache->getInputStreamMethod);
      env->ExceptionClear();
    }

    jbyteArray array = env->NewByteArray(4096);
    int g = 0;

    __android_log_print(ANDROID_LOG_VERBOSE, "Sometrik", "Starting to gather content");

    // Gather headers and values
    for (int i = 0; ; i++) {
      jstring jheaderKey = (jstring)env->CallObjectMethod(connection, cache->getHeaderKeyMethod, i);
      if (jheaderKey == NULL) {
        break;
      }
      const char * headerKey = env->GetStringUTFChars(jheaderKey, 0);
      __android_log_print(ANDROID_LOG_INFO, "content", "header key = %s", headerKey);

      jstring jheader = (jstring)env->CallObjectMethod(connection, cache->getHeaderMethodInt, i);
      const char * header = env->GetStringUTFChars(jheader, 0);
      __android_log_print(ANDROID_LOG_INFO, "content", "header value = %s", header);

      callback.handleHeader(headerKey, header);
      env->ReleaseStringUTFChars(jheaderKey, headerKey);
      env->ReleaseStringUTFChars(jheader, header);
      env->DeleteLocalRef(jheaderKey);
      env->DeleteLocalRef(jheader);
    }

    // Gather content
    while ((g = env->CallIntMethod(input, cache->readMethod, array)) != -1) {
      jbyte* content_array = env->GetByteArrayElements(array, NULL);
      callback.handleChunk(g, (char*) content_array);
      env->ReleaseByteArrayElements(array, content_array, JNI_ABORT);
    }
    env->DeleteLocalRef(array);

    if (responseCode >= 300 && responseCode <= 399) {
      jstring followURL = (jstring)env->CallObjectMethod(connection, cache->getHeaderMethod, env->NewStringUTF("location"));
      const char *followString = env->GetStringUTFChars(followURL, 0);
      callback.handleRedirectUrl(followString);
      __android_log_print(ANDROID_LOG_INFO, "content", "followURL = %s", followString);
      env->ReleaseStringUTFChars(followURL, followString);
      env->DeleteLocalRef(followURL);
    }

    env->DeleteLocalRef(input);
    env->DeleteLocalRef(connection);
}

  void clearCookies() {
    JNIEnv * env = cache->getJNIEnv();
    env->CallVoidMethod(cache->cookieManagerClass, cache->clearCookiesMethod);
  }

private:
  std::shared_ptr<AndroidClientCache> cache;
};

std::unique_ptr<HTTPClient>
AndroidClientFactory::createClient2(const std::string & _user_agent, bool _enable_cookies, bool _enable_keepalive) {
  return std::unique_ptr<AndroidClient>(new AndroidClient(cache, _user_agent, _enable_cookies, _enable_keepalive));
}
<|endoftext|>


<commit_before>// ElementSet.cpp

#include "ElementSet.h"

//------------------------------------------------------------------------------------------
//									         Element
//------------------------------------------------------------------------------------------

Element::Element( void )
{
	collection = nullptr;
}

Element::Element( const Element& element )
{
	collection = nullptr;
	element.permutation.GetCopy( permutation );
	element.word.GetCopy( word );
}

Element::~Element( void )
{
}

void Element::Identity( void )
{
	word.termList.clear();
	permutation.map->clear();
}

bool Element::operator==( const Element& element ) const
{
	if( collection )
		return collection->AreEqual( *this, element );

	return permutation.IsEqualTo( element.permutation );
}

void Element::operator=( const Element& element )
{
	element.word.GetCopy( word );
	element.permutation.GetCopy( permutation );
}

bool Element::Multiply( const Element& elementA, const Element& elementB )
{
	word.Multiply( elementA.word, elementB.word );
	permutation.Multiply( elementA.permutation, elementB.permutation );
	return true;
}

bool Element::MultiplyOnRight( const Element& element )
{
	word.MultiplyOnRight( element.word );
	permutation.MultiplyOnRight( element.permutation );
	return true;
}

bool Element::MultiplyOnLeft( const Element& element )
{
	word.MultiplyOnLeft( element.word );
	permutation.MultiplyOnleft( element.permutation );
	return true;
}

bool Element::SetInverse( const Element& element )
{
	return element.GetInverse( *this );
}

bool Element::GetInverse( Element& element ) const
{
	word.GetInverse( element.word );
	return permutation.GetInverse( element.permutation );
}

std::size_t Element::CalcHash( void ) const
{
	if( collection )
		return collection->CalcHash( *this );

	return permutation.CalcHash();
}

void Element::Print( std::ostream& ostream ) const
{
	word.Print( ostream );
	ostream << " = ";
	permutation.Print( ostream );
	ostream << "\n";
}

//------------------------------------------------------------------------------------------
//									   ElementCollection
//------------------------------------------------------------------------------------------

ElementCollection::ElementCollection( void )
{
}

/*virtual*/ ElementCollection::~ElementCollection( void )
{
}

bool ElementCollection::AddElement( Element& element )
{
	ElementSet::iterator iter;
	if( IsMember( element, &iter ) )
		return false;
	element.collection = this;
	elementSet.insert( element );
	return true;
}

bool ElementCollection::RemoveElement( Element& element )
{
	ElementSet::iterator iter;
	if( !IsMember( element, &iter ) )
		return false;
	element.collection = nullptr;
	elementSet.erase( iter );
	return true;
}

void ElementCollection::RemoveAllElements( void )
{
	elementSet.clear();
}

bool ElementCollection::IsMember( Element& element, ElementSet::iterator* foundIter /*= nullptr*/ )
{
	ElementSet::iterator iter = elementSet.find( element );
	if( iter == elementSet.end() )
		return false;
	if( foundIter )
		*foundIter = iter;
	return true;
}

/*virtual*/ bool ElementCollection::AreEqual( const Element& elementA, const Element& elementB )
{
	return elementA.permutation.IsEqualTo( elementB.permutation );
}

/*virtual*/ std::size_t ElementCollection::CalcHash( const Element& element ) const
{
	return element.permutation.CalcHash();
}

bool ElementCollection::GenerateGroup( std::ostream* ostream /*= nullptr*/ )
{
	ElementSet elementQueue;
	while( elementSet.size() > 0 )
	{
		ElementSet::iterator iter = elementSet.begin();
		const Element& element = *iter;
		if( !element.permutation.IsValid() )
			return false;
		elementQueue.insert( element );
		elementSet.erase( iter );
	}

	Element identity;
	elementSet.insert( identity );

	while( elementQueue.size() > 0 )
	{
		ElementSet::iterator queueIter = elementQueue.begin();
		Element newElement = *queueIter;
		elementQueue.erase( queueIter );

		// TODO: Despite this conditional, can I prove the correctness of this algorithm?
		if( !IsMember( newElement ) )
		{
			for( ElementSet::const_iterator iter = elementSet.cbegin(); iter != elementSet.cend(); iter++ )
			{
				const Element& element = *iter;

				for( int i = 0; i < 2; i++ )
				{
					Element product;

					if( i == 0 )
						product.Multiply( newElement, element );
					else
						product.Multiply( element, newElement );

					bool foundInSet = IsMember( product );
					bool foundInQueue = ( elementQueue.find( product ) == elementQueue.end() ) ? false : true;

					if( !( foundInSet || foundInQueue ) )
						elementQueue.insert( product );
				}
			}

			elementSet.insert( newElement );

			if( ostream )
				*ostream << "SetSize: " << elementSet.size() << ", QueueSize: " << elementQueue.size() << "\n";
		}
	}

	return true;
}

// Of course, if we're a group, then this is the order of the group.
uint ElementCollection::Cardinality( void ) const
{
	return ( uint )elementSet.size();
}

void ElementCollection::Print( std::ostream& ostream ) const
{
	ostream << "Cardinality: " << Cardinality() << "\n";

	for( ElementSet::const_iterator iter = elementSet.cbegin(); iter != elementSet.cend(); iter++ )
	{
		const Element& element = *iter;
		element.Print( ostream );
	}
}

//------------------------------------------------------------------------------------------
//									     CosetCollection
//------------------------------------------------------------------------------------------

CosetCollection::CosetCollection( void )
{
}

/*virtual*/ CosetCollection::~CosetCollection( void )
{
}

bool CosetCollection::AreInSameCoset( const Permutation& permutationA, const Permutation& permutationB ) const
{
	Permutation invPermutationA;
	permutationA.GetInverse( invPermutationA );

	Permutation product;
	product.Multiply( invPermutationA, permutationB );

	return IsInQuotientGroup( product );
}

bool CosetCollection::IsInQuotientGroup( const Permutation& permutation ) const
{
	NaturalNumberSet permUnstableSet;
	permutation.GetUnstableSet( permUnstableSet );

	return permUnstableSet.IsSubsetOf( unstableSet );
}

/*virtual*/ bool CosetCollection::AreEqual( const Element& elementA, const Element& elementB )
{
	return AreInSameCoset( elementA.permutation, elementB.permutation );
}

/*virtual*/ std::size_t CosetCollection::CalcHash( const Element& element ) const
{
	// Unfortunately, I'm not sure how to get around doing this linear search.
	// What it means is that we're essentially defeating the purpose of using a hash table.
	// What we would have to do to fix this is make sure that elements that would fall
	// under the same coset always hash to the same value.  I'm not sure how to do that.
	const Element* cosetRepresentative = FindCosetRepresentative( element );
	if( cosetRepresentative )
		return cosetRepresentative->CalcHash();

	return element.CalcHash();
}

const Element* CosetCollection::FindCosetRepresentative( const Element& element ) const
{
	for( ElementSet::const_iterator iter = elementSet.cbegin(); iter != elementSet.cend(); iter++ )
	{
		const Element& existingElement = *iter;
		if( AreInSameCoset( existingElement.permutation, element.permutation ) )
			return &existingElement;
	}

	return nullptr;
}

// ElementSet.cpp<commit_msg>i feel dumb<commit_after>// ElementSet.cpp

#include "ElementSet.h"

//------------------------------------------------------------------------------------------
//									         Element
//------------------------------------------------------------------------------------------

Element::Element( void )
{
	collection = nullptr;
}

Element::Element( const Element& element )
{
	collection = nullptr;
	element.permutation.GetCopy( permutation );
	element.word.GetCopy( word );
}

Element::~Element( void )
{
}

void Element::Identity( void )
{
	word.termList.clear();
	permutation.map->clear();
}

bool Element::operator==( const Element& element ) const
{
	if( collection )
		return collection->AreEqual( *this, element );

	return permutation.IsEqualTo( element.permutation );
}

void Element::operator=( const Element& element )
{
	element.word.GetCopy( word );
	element.permutation.GetCopy( permutation );
}

bool Element::Multiply( const Element& elementA, const Element& elementB )
{
	word.Multiply( elementA.word, elementB.word );
	permutation.Multiply( elementA.permutation, elementB.permutation );
	return true;
}

bool Element::MultiplyOnRight( const Element& element )
{
	word.MultiplyOnRight( element.word );
	permutation.MultiplyOnRight( element.permutation );
	return true;
}

bool Element::MultiplyOnLeft( const Element& element )
{
	word.MultiplyOnLeft( element.word );
	permutation.MultiplyOnLeft( element.permutation );
	return true;
}

bool Element::SetInverse( const Element& element )
{
	return element.GetInverse( *this );
}

bool Element::GetInverse( Element& element ) const
{
	word.GetInverse( element.word );
	return permutation.GetInverse( element.permutation );
}

std::size_t Element::CalcHash( void ) const
{
	if( collection )
		return collection->CalcHash( *this );

	return permutation.CalcHash();
}

void Element::Print( std::ostream& ostream ) const
{
	word.Print( ostream );
	ostream << " = ";
	permutation.Print( ostream );
	ostream << "\n";
}

//------------------------------------------------------------------------------------------
//									   ElementCollection
//------------------------------------------------------------------------------------------

ElementCollection::ElementCollection( void )
{
}

/*virtual*/ ElementCollection::~ElementCollection( void )
{
}

bool ElementCollection::AddElement( Element& element )
{
	ElementSet::iterator iter;
	if( IsMember( element, &iter ) )
		return false;
	element.collection = this;
	elementSet.insert( element );
	return true;
}

bool ElementCollection::RemoveElement( Element& element )
{
	ElementSet::iterator iter;
	if( !IsMember( element, &iter ) )
		return false;
	element.collection = nullptr;
	elementSet.erase( iter );
	return true;
}

void ElementCollection::RemoveAllElements( void )
{
	elementSet.clear();
}

bool ElementCollection::IsMember( Element& element, ElementSet::iterator* foundIter /*= nullptr*/ )
{
	ElementSet::iterator iter = elementSet.find( element );
	if( iter == elementSet.end() )
		return false;
	if( foundIter )
		*foundIter = iter;
	return true;
}

/*virtual*/ bool ElementCollection::AreEqual( const Element& elementA, const Element& elementB )
{
	return elementA.permutation.IsEqualTo( elementB.permutation );
}

/*virtual*/ std::size_t ElementCollection::CalcHash( const Element& element ) const
{
	return element.permutation.CalcHash();
}

bool ElementCollection::GenerateGroup( std::ostream* ostream /*= nullptr*/ )
{
	ElementSet elementQueue;
	while( elementSet.size() > 0 )
	{
		ElementSet::iterator iter = elementSet.begin();
		const Element& element = *iter;
		if( !element.permutation.IsValid() )
			return false;
		elementQueue.insert( element );
		elementSet.erase( iter );
	}

	Element identity;
	elementSet.insert( identity );

	while( elementQueue.size() > 0 )
	{
		ElementSet::iterator queueIter = elementQueue.begin();
		Element newElement = *queueIter;
		elementQueue.erase( queueIter );

		// TODO: Despite this conditional, can I prove the correctness of this algorithm?
		//       One approach is to use an inductive argument on the size of the generating
		//       set under the condition that our queue be a stack.  I just can't quite see
		//       the final argument.  We have H<G, and g in G-H.  Will we take H to G using g?
		//       I think we can argue that we'll get H, gH, ..., g^{|g|-1}H, but the index of
		//       H in G is not necessarily |g|.  Here's a better argument.  We know the algorithm
		//       terminates.  Fine.  Now consider the result as an array of elements.  Can we
		//       argue that for any element in that array, it has been compared with all elements
		//       left of it and all elements right of it in the array?  I think we can, but that's
		//       not quite enough.
		if( !IsMember( newElement ) )
		{
			for( ElementSet::const_iterator iter = elementSet.cbegin(); iter != elementSet.cend(); iter++ )
			{
				const Element& element = *iter;

				for( int i = 0; i < 2; i++ )
				{
					Element product;

					if( i == 0 )
						product.Multiply( newElement, element );
					else
						product.Multiply( element, newElement );

					bool foundInSet = IsMember( product );
					bool foundInQueue = ( elementQueue.find( product ) == elementQueue.end() ) ? false : true;

					if( !( foundInSet || foundInQueue ) )
						elementQueue.insert( product );
				}
			}

			elementSet.insert( newElement );

			if( ostream )
				*ostream << "SetSize: " << elementSet.size() << ", QueueSize: " << elementQueue.size() << "\n";
		}
	}

	return true;
}

// Of course, if we're a group, then this is the order of the group.
uint ElementCollection::Cardinality( void ) const
{
	return ( uint )elementSet.size();
}

void ElementCollection::Print( std::ostream& ostream ) const
{
	ostream << "Cardinality: " << Cardinality() << "\n";

	for( ElementSet::const_iterator iter = elementSet.cbegin(); iter != elementSet.cend(); iter++ )
	{
		const Element& element = *iter;
		element.Print( ostream );
	}
}

//------------------------------------------------------------------------------------------
//									     CosetCollection
//------------------------------------------------------------------------------------------

CosetCollection::CosetCollection( void )
{
}

/*virtual*/ CosetCollection::~CosetCollection( void )
{
}

bool CosetCollection::AreInSameCoset( const Permutation& permutationA, const Permutation& permutationB ) const
{
	Permutation invPermutationA;
	permutationA.GetInverse( invPermutationA );

	Permutation product;
	product.Multiply( invPermutationA, permutationB );

	return IsInQuotientGroup( product );
}

bool CosetCollection::IsInQuotientGroup( const Permutation& permutation ) const
{
	NaturalNumberSet permUnstableSet;
	permutation.GetUnstableSet( permUnstableSet );

	return permUnstableSet.IsSubsetOf( unstableSet );
}

/*virtual*/ bool CosetCollection::AreEqual( const Element& elementA, const Element& elementB )
{
	return AreInSameCoset( elementA.permutation, elementB.permutation );
}

/*virtual*/ std::size_t CosetCollection::CalcHash( const Element& element ) const
{
	// Unfortunately, I'm not sure how to get around doing this linear search.
	// What it means is that we're essentially defeating the purpose of using a hash table.
	// What we would have to do to fix this is make sure that elements that would fall
	// under the same coset always hash to the same value.  I'm not sure how to do that.
	const Element* cosetRepresentative = FindCosetRepresentative( element );
	if( cosetRepresentative )
		return cosetRepresentative->CalcHash();

	return element.CalcHash();
}

const Element* CosetCollection::FindCosetRepresentative( const Element& element ) const
{
	for( ElementSet::const_iterator iter = elementSet.cbegin(); iter != elementSet.cend(); iter++ )
	{
		const Element& existingElement = *iter;
		if( AreInSameCoset( existingElement.permutation, element.permutation ) )
			return &existingElement;
	}

	return nullptr;
}

// ElementSet.cpp<|endoftext|>


<commit_before>#include "pch.h"
#include "AudioRenderer.h"

namespace SaneAudioRenderer
{
    AudioRenderer::AudioRenderer(ISettings* pSettings, IMyClock* pClock, HRESULT& result)
        : m_deviceManager(result)
        , m_myClock(pClock)
        , m_flush(TRUE/*manual reset*/)
        , m_dspVolume(*this)
        , m_dspBalance(*this)
        , m_settings(pSettings)
    {
        if (FAILED(result))
            return;

        try
        {
            if (!m_settings || !m_myClock)
                throw E_UNEXPECTED;

            ThrowIfFailed(m_myClock->QueryInterface(IID_PPV_ARGS(&m_myGraphClock)));

            if (static_cast<HANDLE>(m_flush) == NULL)
            {
                throw E_OUTOFMEMORY;
            }
        }
        catch (HRESULT ex)
        {
            result = ex;
        }
    }

    AudioRenderer::~AudioRenderer()
    {
        // Just in case.
        if (m_state != State_Stopped)
            Stop();
    }

    void AudioRenderer::SetClock(IReferenceClock* pClock)
    {
        CAutoLock objectLock(this);

        m_graphClock = pClock;

        if (m_graphClock && m_graphClock != m_myGraphClock)
        {
            if (!m_externalClock)
                ClearDevice();

            m_externalClock = true;
        }
        else
        {
            if (m_externalClock)
                ClearDevice();

            m_externalClock = false;
        }
    }

    bool AudioRenderer::OnExternalClock()
    {
        CAutoLock objectLock(this);

        return m_externalClock;
    }

    bool AudioRenderer::Enqueue(IMediaSample* pSample, AM_SAMPLE2_PROPERTIES& sampleProps, CAMEvent* pFilledEvent)
    {
        DspChunk chunk;

        {
            CAutoLock objectLock(this);
            assert(m_inputFormat);
            assert(m_state != State_Stopped);

            try
            {
                // Clear the device if related settings were changed.
                CheckDeviceSettings();

                // Create the device if needed.
                if (!m_device)
                    CreateDevice();

                // Apply sample corrections (pad, crop, guess timings).
                chunk = m_sampleCorrection.ProcessSample(pSample, sampleProps);

                // Apply clock corrections (graph clock and rate dsp).
                if (m_device && m_state == State_Running)
                    ApplyClockCorrection();

                // Apply dsp chain.
                if (m_device && !m_device->IsBitstream())
                {
                    auto f = [&](DspBase* pDsp)
                    {
                        pDsp->Process(chunk);
                    };

                    EnumerateProcessors(f);

                    DspChunk::ToFormat(m_device->GetDspFormat(), chunk);
                }
            }
            catch (std::bad_alloc&)
            {
                ClearDevice();
                chunk = DspChunk();
            }
        }

        // Send processed sample to the device.
        return Push(chunk, pFilledEvent);
    }

    bool AudioRenderer::Finish(bool blockUntilEnd, CAMEvent* pFilledEvent)
    {
        DspChunk chunk;

        {
            CAutoLock objectLock(this);
            assert(m_state != State_Stopped);

            // No device - nothing to block on.
            if (!m_device)
                blockUntilEnd = false;

            try
            {
                // Apply dsp chain.
                if (m_device && !m_device->IsBitstream())
                {
                    auto f = [&](DspBase* pDsp)
                    {
                        pDsp->Finish(chunk);
                    };

                    EnumerateProcessors(f);

                    DspChunk::ToFormat(m_device->GetDspFormat(), chunk);
                }
            }
            catch (std::bad_alloc&)
            {
                chunk = DspChunk();
                assert(chunk.IsEmpty());
            }
        }

        auto doBlock = [this]
        {
            // Increase system timer resolution.
            TimePeriodHelper timePeriodHelper(1);

            // Unslave the clock because no more samples are going to be pushed.
            m_myClock->UnslaveClockFromAudio();

            for (;;)
            {
                int64_t actual = INT64_MAX;
                int64_t target;

                {
                    CAutoLock objectLock(this);

                    if (!m_device)
                        return true;

                    const auto previous = actual;
                    actual = m_device->GetPosition();
                    target = m_device->GetEnd();

                    // Return if the end of stream is reached.
                    if (actual == target)
                        return true;

                    // Stalling protection.
                    if (actual == previous && m_state == State_Running)
                        return true;
                }

                // Sleep until predicted end of stream.
                if (m_flush.Wait(std::max(1, (int32_t)((target - actual) * 1000 / OneSecond))))
                    return false;
            }
        };

        // Send processed sample to the device, and block until the buffer is drained (if requested).
        return Push(chunk, pFilledEvent) && (!blockUntilEnd || doBlock());
    }

    void AudioRenderer::BeginFlush()
    {
        m_flush.Set();
    }

    void AudioRenderer::EndFlush()
    {
        CAutoLock objectLock(this);
        assert(m_state != State_Running);

        if (m_device)
        {
            m_device->Reset();
            m_sampleCorrection.NewDeviceBuffer();
        }

        m_flush.Reset();
    }

    bool AudioRenderer::CheckFormat(SharedWaveFormat inputFormat)
    {
        assert(inputFormat);

        if (DspFormatFromWaveFormat(*inputFormat) != DspFormat::Unknown)
            return true;

        BOOL exclusive;
        m_settings->GetOuputDevice(nullptr, &exclusive, nullptr);
        BOOL bitstreamingAllowed;
        m_settings->GetAllowBitstreaming(&bitstreamingAllowed);

        if (!exclusive || !bitstreamingAllowed)
            return false;

        CAutoLock objectLock(this);

        return m_deviceManager.BitstreamFormatSupported(inputFormat, m_settings);
    }

    void AudioRenderer::SetFormat(SharedWaveFormat inputFormat, bool live)
    {
        CAutoLock objectLock(this);

        m_inputFormat = inputFormat;
        m_live = live;

        m_sampleCorrection.NewFormat(inputFormat);

        ClearDevice();
    }

    void AudioRenderer::NewSegment(double rate)
    {
        CAutoLock objectLock(this);

        m_startClockOffset = 0;
        m_rate = rate;

        m_sampleCorrection.NewSegment(m_rate);

        assert(m_inputFormat);
        if (m_device)
            InitializeProcessors();
    }

    void AudioRenderer::Play(REFERENCE_TIME startTime)
    {
        CAutoLock objectLock(this);
        assert(m_state != State_Running);
        m_state = State_Running;

        m_startTime = startTime;
        StartDevice();
    }

    void AudioRenderer::Pause()
    {
        CAutoLock objectLock(this);
        m_state = State_Paused;

        if (m_device)
        {
            m_myClock->UnslaveClockFromAudio();
            m_device->Stop();
        }
    }

    void AudioRenderer::Stop()
    {
        CAutoLock objectLock(this);
        m_state = State_Stopped;

        ClearDevice();
    }

    SharedWaveFormat AudioRenderer::GetInputFormat()
    {
        CAutoLock objectLock(this);

        return m_inputFormat;
    }

    AudioDevice const* AudioRenderer::GetAudioDevice()
    {
        assert(CritCheckIn(this));

        return m_device.get();
    }

    std::vector<std::wstring> AudioRenderer::GetActiveProcessors()
    {
        CAutoLock objectLock(this);

        std::vector<std::wstring> ret;

        if (m_inputFormat && m_device && !m_device->IsBitstream())
        {
            auto f = [&](DspBase* pDsp)
            {
                if (pDsp->Active())
                    ret.emplace_back(pDsp->Name());
            };

            EnumerateProcessors(f);
        }

        return ret;
    }

    void AudioRenderer::CheckDeviceSettings()
    {
        CAutoLock objectLock(this);

        UINT32 serial = m_settings->GetSerial();

        if (m_device && m_deviceSettingsSerial != serial)
        {
            LPWSTR pDeviceName = nullptr;
            BOOL exclusive;
            UINT32 buffer;
            if (SUCCEEDED(m_settings->GetOuputDevice(&pDeviceName, &exclusive, &buffer)))
            {
                if (m_device->IsExclusive() != !!exclusive ||
                    m_device->GetBufferDuration() != buffer ||
                    (pDeviceName && *pDeviceName && wcscmp(pDeviceName, m_device->GetFriendlyName()->c_str())) ||
                    ((!pDeviceName || !*pDeviceName) && !m_device->IsDefault()))
                {
                    ClearDevice();
                    assert(!m_device);
                }
                else
                {
                    m_deviceSettingsSerial = serial;
                }
                CoTaskMemFree(pDeviceName);
            }
        }
    }

    void AudioRenderer::StartDevice()
    {
        CAutoLock objectLock(this);
        assert(m_state == State_Running);

        if (m_device)
        {
            m_myClock->SlaveClockToAudio(m_device->GetClock(), m_startTime + m_startClockOffset);
            m_startClockOffset = 0;
            m_device->Start();
        }
    }

    void AudioRenderer::CreateDevice()
    {
        CAutoLock objectLock(this);

        assert(!m_device);
        assert(m_inputFormat);

        m_deviceSettingsSerial = m_settings->GetSerial();
        m_device = m_deviceManager.CreateDevice(m_inputFormat, m_live, m_settings);

        if (m_device)
        {
            m_sampleCorrection.NewDeviceBuffer();

            InitializeProcessors();

            m_startClockOffset = m_sampleCorrection.GetLastSampleEnd();

            if (m_state == State_Running)
                StartDevice();
        }
    }

    void AudioRenderer::ClearDevice()
    {
        CAutoLock objectLock(this);

        if (m_device)
        {
            m_myClock->UnslaveClockFromAudio();
            m_device->Stop();
            m_device = nullptr;
        }
    }

    void AudioRenderer::ApplyClockCorrection()
    {
        CAutoLock objectLock(this);
        assert(m_inputFormat);
        assert(m_device);
        assert(m_state == State_Running);

        // Apply corrections to internal clock.
        {
            REFERENCE_TIME offset = m_sampleCorrection.GetTimingsError() - m_myClock->GetSlavedClockOffset();
            if (std::abs(offset) > 1000)
            {
                m_myClock->OffsetSlavedClock(offset);
                DebugOut("AudioRenderer offset internal clock by", offset / 10000., "ms");
            }
        }

        /*
        // Try to match internal clock with graph clock if they're different.
        // We do it in the roundabout way by dynamically changing audio sampling rate.
        if (m_externalClock && !m_device->bitstream)
        {
            assert(m_dspRate.Active());
            REFERENCE_TIME graphTime, myTime, myStartTime;
            if (SUCCEEDED(m_myClock->GetAudioClockStartTime(&myStartTime)) &&
                SUCCEEDED(m_myClock->GetAudioClockTime(&myTime, nullptr)) &&
                SUCCEEDED(GetGraphTime(graphTime)) &&
                myTime > myStartTime)
            {
                REFERENCE_TIME offset = graphTime - myTime - m_correctedWithRateDsp;
                if (std::abs(offset) > MILLISECONDS_TO_100NS_UNITS(2))
                {
                    m_dspRate.Adjust(offset);
                    m_correctedWithRateDsp += offset;
                    DebugOut("AudioRenderer offset internal clock indirectly by", offset / 10000., "ms");
                }
            }
        }
        */
    }

    HRESULT AudioRenderer::GetGraphTime(REFERENCE_TIME& time)
    {
        CAutoLock objectLock(this);

        return m_graphClock ?
                   m_graphClock->GetTime(&time) :
                   m_myGraphClock->GetTime(&time);
    }

    void AudioRenderer::InitializeProcessors()
    {
        CAutoLock objectLock(this);
        assert(m_inputFormat);
        assert(m_device);

        m_correctedWithRateDsp = 0;

        if (m_device->IsBitstream())
            return;

        const auto inRate = m_inputFormat->nSamplesPerSec;
        const auto inChannels = m_inputFormat->nChannels;
        const auto inMask = DspMatrix::GetChannelMask(*m_inputFormat);
        const auto outRate = m_device->GetWaveFormat()->nSamplesPerSec;
        const auto outChannels = m_device->GetWaveFormat()->nChannels;
        const auto outMask = DspMatrix::GetChannelMask(*m_device->GetWaveFormat());

        m_dspMatrix.Initialize(inChannels, inMask, outChannels, outMask);
        m_dspRate.Initialize(m_externalClock, inRate, outRate, outChannels);
        m_dspVariableRate.Initialize(m_externalClock, inRate, outRate, outChannels);
        m_dspTempo.Initialize(m_rate, outRate, outChannels);
        m_dspCrossfeed.Initialize(m_settings, outRate, outChannels, outMask);
        m_dspVolume.Initialize(m_device->IsExclusive());
        m_dspLimiter.Initialize(m_settings, outRate, m_device->IsExclusive());
        m_dspDither.Initialize(m_device->GetDspFormat());
    }

    bool AudioRenderer::Push(DspChunk& chunk, CAMEvent* pFilledEvent)
    {
        bool firstIteration = true;
        uint32_t sleepDuration = 0;
        while (!chunk.IsEmpty())
        {
            // The device buffer is full or almost full at the beginning of the second and subsequent iterations.
            // Sleep until the buffer may have significant amount of free space. Unless interrupted.
            if (!firstIteration && m_flush.Wait(sleepDuration))
                return false;

            firstIteration = false;

            CAutoLock objectLock(this);

            assert(m_state != State_Stopped);

            if (m_device)
            {
                try
                {
                    m_device->Push(chunk, pFilledEvent);
                    sleepDuration = m_device->GetBufferDuration() / 4;
                }
                catch (HRESULT)
                {
                    ClearDevice();
                    sleepDuration = 0;
                }
            }
            else
            {
                // The code below emulates null audio device.

                if (pFilledEvent)
                    pFilledEvent->Set();

                sleepDuration = 1;

                // Loop until the graph time passes the current sample end.
                REFERENCE_TIME graphTime;
                if (m_state == State_Running &&
                    SUCCEEDED(GetGraphTime(graphTime)) &&
                    graphTime > m_startTime + m_sampleCorrection.GetLastSampleEnd())
                {
                    break;
                }
            }
        }

        return true;
    }
}
<commit_msg>Don't slave graph clock in live mode<commit_after>#include "pch.h"
#include "AudioRenderer.h"

namespace SaneAudioRenderer
{
    AudioRenderer::AudioRenderer(ISettings* pSettings, IMyClock* pClock, HRESULT& result)
        : m_deviceManager(result)
        , m_myClock(pClock)
        , m_flush(TRUE/*manual reset*/)
        , m_dspVolume(*this)
        , m_dspBalance(*this)
        , m_settings(pSettings)
    {
        if (FAILED(result))
            return;

        try
        {
            if (!m_settings || !m_myClock)
                throw E_UNEXPECTED;

            ThrowIfFailed(m_myClock->QueryInterface(IID_PPV_ARGS(&m_myGraphClock)));

            if (static_cast<HANDLE>(m_flush) == NULL)
            {
                throw E_OUTOFMEMORY;
            }
        }
        catch (HRESULT ex)
        {
            result = ex;
        }
    }

    AudioRenderer::~AudioRenderer()
    {
        // Just in case.
        if (m_state != State_Stopped)
            Stop();
    }

    void AudioRenderer::SetClock(IReferenceClock* pClock)
    {
        CAutoLock objectLock(this);

        m_graphClock = pClock;

        if (m_graphClock && m_graphClock != m_myGraphClock)
        {
            if (!m_externalClock)
                ClearDevice();

            m_externalClock = true;
        }
        else
        {
            if (m_externalClock)
                ClearDevice();

            m_externalClock = false;
        }
    }

    bool AudioRenderer::OnExternalClock()
    {
        CAutoLock objectLock(this);

        return m_externalClock;
    }

    bool AudioRenderer::Enqueue(IMediaSample* pSample, AM_SAMPLE2_PROPERTIES& sampleProps, CAMEvent* pFilledEvent)
    {
        DspChunk chunk;

        {
            CAutoLock objectLock(this);
            assert(m_inputFormat);
            assert(m_state != State_Stopped);

            try
            {
                // Clear the device if related settings were changed.
                CheckDeviceSettings();

                // Create the device if needed.
                if (!m_device)
                    CreateDevice();

                // Apply sample corrections (pad, crop, guess timings).
                chunk = m_sampleCorrection.ProcessSample(pSample, sampleProps);

                // Apply clock corrections (graph clock and rate dsp).
                if (m_device && m_state == State_Running)
                    ApplyClockCorrection();

                // Apply dsp chain.
                if (m_device && !m_device->IsBitstream())
                {
                    auto f = [&](DspBase* pDsp)
                    {
                        pDsp->Process(chunk);
                    };

                    EnumerateProcessors(f);

                    DspChunk::ToFormat(m_device->GetDspFormat(), chunk);
                }
            }
            catch (std::bad_alloc&)
            {
                ClearDevice();
                chunk = DspChunk();
            }
        }

        // Send processed sample to the device.
        return Push(chunk, pFilledEvent);
    }

    bool AudioRenderer::Finish(bool blockUntilEnd, CAMEvent* pFilledEvent)
    {
        DspChunk chunk;

        {
            CAutoLock objectLock(this);
            assert(m_state != State_Stopped);

            // No device - nothing to block on.
            if (!m_device)
                blockUntilEnd = false;

            try
            {
                // Apply dsp chain.
                if (m_device && !m_device->IsBitstream())
                {
                    auto f = [&](DspBase* pDsp)
                    {
                        pDsp->Finish(chunk);
                    };

                    EnumerateProcessors(f);

                    DspChunk::ToFormat(m_device->GetDspFormat(), chunk);
                }
            }
            catch (std::bad_alloc&)
            {
                chunk = DspChunk();
                assert(chunk.IsEmpty());
            }
        }

        auto doBlock = [this]
        {
            // Increase system timer resolution.
            TimePeriodHelper timePeriodHelper(1);

            // Unslave the clock because no more samples are going to be pushed.
            m_myClock->UnslaveClockFromAudio();

            for (;;)
            {
                int64_t actual = INT64_MAX;
                int64_t target;

                {
                    CAutoLock objectLock(this);

                    if (!m_device)
                        return true;

                    const auto previous = actual;
                    actual = m_device->GetPosition();
                    target = m_device->GetEnd();

                    // Return if the end of stream is reached.
                    if (actual == target)
                        return true;

                    // Stalling protection.
                    if (actual == previous && m_state == State_Running)
                        return true;
                }

                // Sleep until predicted end of stream.
                if (m_flush.Wait(std::max(1, (int32_t)((target - actual) * 1000 / OneSecond))))
                    return false;
            }
        };

        // Send processed sample to the device, and block until the buffer is drained (if requested).
        return Push(chunk, pFilledEvent) && (!blockUntilEnd || doBlock());
    }

    void AudioRenderer::BeginFlush()
    {
        m_flush.Set();
    }

    void AudioRenderer::EndFlush()
    {
        CAutoLock objectLock(this);
        assert(m_state != State_Running);

        if (m_device)
        {
            m_device->Reset();
            m_sampleCorrection.NewDeviceBuffer();
        }

        m_flush.Reset();
    }

    bool AudioRenderer::CheckFormat(SharedWaveFormat inputFormat)
    {
        assert(inputFormat);

        if (DspFormatFromWaveFormat(*inputFormat) != DspFormat::Unknown)
            return true;

        BOOL exclusive;
        m_settings->GetOuputDevice(nullptr, &exclusive, nullptr);
        BOOL bitstreamingAllowed;
        m_settings->GetAllowBitstreaming(&bitstreamingAllowed);

        if (!exclusive || !bitstreamingAllowed)
            return false;

        CAutoLock objectLock(this);

        return m_deviceManager.BitstreamFormatSupported(inputFormat, m_settings);
    }

    void AudioRenderer::SetFormat(SharedWaveFormat inputFormat, bool live)
    {
        CAutoLock objectLock(this);

        m_inputFormat = inputFormat;
        m_live = live;

        m_sampleCorrection.NewFormat(inputFormat);

        ClearDevice();
    }

    void AudioRenderer::NewSegment(double rate)
    {
        CAutoLock objectLock(this);

        m_startClockOffset = 0;
        m_rate = rate;

        m_sampleCorrection.NewSegment(m_rate);

        assert(m_inputFormat);
        if (m_device)
            InitializeProcessors();
    }

    void AudioRenderer::Play(REFERENCE_TIME startTime)
    {
        CAutoLock objectLock(this);
        assert(m_state != State_Running);
        m_state = State_Running;

        m_startTime = startTime;
        StartDevice();
    }

    void AudioRenderer::Pause()
    {
        CAutoLock objectLock(this);
        m_state = State_Paused;

        if (m_device)
        {
            m_myClock->UnslaveClockFromAudio();
            m_device->Stop();
        }
    }

    void AudioRenderer::Stop()
    {
        CAutoLock objectLock(this);
        m_state = State_Stopped;

        ClearDevice();
    }

    SharedWaveFormat AudioRenderer::GetInputFormat()
    {
        CAutoLock objectLock(this);

        return m_inputFormat;
    }

    AudioDevice const* AudioRenderer::GetAudioDevice()
    {
        assert(CritCheckIn(this));

        return m_device.get();
    }

    std::vector<std::wstring> AudioRenderer::GetActiveProcessors()
    {
        CAutoLock objectLock(this);

        std::vector<std::wstring> ret;

        if (m_inputFormat && m_device && !m_device->IsBitstream())
        {
            auto f = [&](DspBase* pDsp)
            {
                if (pDsp->Active())
                    ret.emplace_back(pDsp->Name());
            };

            EnumerateProcessors(f);
        }

        return ret;
    }

    void AudioRenderer::CheckDeviceSettings()
    {
        CAutoLock objectLock(this);

        UINT32 serial = m_settings->GetSerial();

        if (m_device && m_deviceSettingsSerial != serial)
        {
            LPWSTR pDeviceName = nullptr;
            BOOL exclusive;
            UINT32 buffer;
            if (SUCCEEDED(m_settings->GetOuputDevice(&pDeviceName, &exclusive, &buffer)))
            {
                if (m_device->IsExclusive() != !!exclusive ||
                    m_device->GetBufferDuration() != buffer ||
                    (pDeviceName && *pDeviceName && wcscmp(pDeviceName, m_device->GetFriendlyName()->c_str())) ||
                    ((!pDeviceName || !*pDeviceName) && !m_device->IsDefault()))
                {
                    ClearDevice();
                    assert(!m_device);
                }
                else
                {
                    m_deviceSettingsSerial = serial;
                }
                CoTaskMemFree(pDeviceName);
            }
        }
    }

    void AudioRenderer::StartDevice()
    {
        CAutoLock objectLock(this);
        assert(m_state == State_Running);

        if (m_device)
        {
            assert(m_live == m_device->IsLive());

            if (!m_live)
                m_myClock->SlaveClockToAudio(m_device->GetClock(), m_startTime + m_startClockOffset);

            m_device->Start();
        }
    }

    void AudioRenderer::CreateDevice()
    {
        CAutoLock objectLock(this);

        assert(!m_device);
        assert(m_inputFormat);

        m_deviceSettingsSerial = m_settings->GetSerial();
        m_device = m_deviceManager.CreateDevice(m_inputFormat, m_live, m_settings);

        if (m_device)
        {
            m_sampleCorrection.NewDeviceBuffer();

            InitializeProcessors();

            m_startClockOffset = m_sampleCorrection.GetLastSampleEnd();

            if (m_state == State_Running)
                StartDevice();
        }
    }

    void AudioRenderer::ClearDevice()
    {
        CAutoLock objectLock(this);

        if (m_device)
        {
            m_myClock->UnslaveClockFromAudio();
            m_device->Stop();
            m_device = nullptr;
        }
    }

    void AudioRenderer::ApplyClockCorrection()
    {
        CAutoLock objectLock(this);
        assert(m_inputFormat);
        assert(m_device);
        assert(m_state == State_Running);

        // Apply corrections to internal clock.
        {
            REFERENCE_TIME offset = m_sampleCorrection.GetTimingsError() - m_myClock->GetSlavedClockOffset();
            if (std::abs(offset) > 1000)
            {
                m_myClock->OffsetSlavedClock(offset);
                DebugOut("AudioRenderer offset internal clock by", offset / 10000., "ms");
            }
        }

        /*
        // Try to match internal clock with graph clock if they're different.
        // We do it in the roundabout way by dynamically changing audio sampling rate.
        if (m_externalClock && !m_device->bitstream)
        {
            assert(m_dspRate.Active());
            REFERENCE_TIME graphTime, myTime, myStartTime;
            if (SUCCEEDED(m_myClock->GetAudioClockStartTime(&myStartTime)) &&
                SUCCEEDED(m_myClock->GetAudioClockTime(&myTime, nullptr)) &&
                SUCCEEDED(GetGraphTime(graphTime)) &&
                myTime > myStartTime)
            {
                REFERENCE_TIME offset = graphTime - myTime - m_correctedWithRateDsp;
                if (std::abs(offset) > MILLISECONDS_TO_100NS_UNITS(2))
                {
                    m_dspRate.Adjust(offset);
                    m_correctedWithRateDsp += offset;
                    DebugOut("AudioRenderer offset internal clock indirectly by", offset / 10000., "ms");
                }
            }
        }
        */
    }

    HRESULT AudioRenderer::GetGraphTime(REFERENCE_TIME& time)
    {
        CAutoLock objectLock(this);

        return m_graphClock ?
                   m_graphClock->GetTime(&time) :
                   m_myGraphClock->GetTime(&time);
    }

    void AudioRenderer::InitializeProcessors()
    {
        CAutoLock objectLock(this);
        assert(m_inputFormat);
        assert(m_device);

        m_correctedWithRateDsp = 0;

        if (m_device->IsBitstream())
            return;

        const auto inRate = m_inputFormat->nSamplesPerSec;
        const auto inChannels = m_inputFormat->nChannels;
        const auto inMask = DspMatrix::GetChannelMask(*m_inputFormat);
        const auto outRate = m_device->GetWaveFormat()->nSamplesPerSec;
        const auto outChannels = m_device->GetWaveFormat()->nChannels;
        const auto outMask = DspMatrix::GetChannelMask(*m_device->GetWaveFormat());

        m_dspMatrix.Initialize(inChannels, inMask, outChannels, outMask);
        m_dspRate.Initialize(m_externalClock, inRate, outRate, outChannels);
        m_dspVariableRate.Initialize(m_externalClock, inRate, outRate, outChannels);
        m_dspTempo.Initialize(m_rate, outRate, outChannels);
        m_dspCrossfeed.Initialize(m_settings, outRate, outChannels, outMask);
        m_dspVolume.Initialize(m_device->IsExclusive());
        m_dspLimiter.Initialize(m_settings, outRate, m_device->IsExclusive());
        m_dspDither.Initialize(m_device->GetDspFormat());
    }

    bool AudioRenderer::Push(DspChunk& chunk, CAMEvent* pFilledEvent)
    {
        bool firstIteration = true;
        uint32_t sleepDuration = 0;
        while (!chunk.IsEmpty())
        {
            // The device buffer is full or almost full at the beginning of the second and subsequent iterations.
            // Sleep until the buffer may have significant amount of free space. Unless interrupted.
            if (!firstIteration && m_flush.Wait(sleepDuration))
                return false;

            firstIteration = false;

            CAutoLock objectLock(this);

            assert(m_state != State_Stopped);

            if (m_device)
            {
                try
                {
                    m_device->Push(chunk, pFilledEvent);
                    sleepDuration = m_device->GetBufferDuration() / 4;
                }
                catch (HRESULT)
                {
                    ClearDevice();
                    sleepDuration = 0;
                }
            }
            else
            {
                // The code below emulates null audio device.

                if (pFilledEvent)
                    pFilledEvent->Set();

                sleepDuration = 1;

                // Loop until the graph time passes the current sample end.
                REFERENCE_TIME graphTime;
                if (m_state == State_Running &&
                    SUCCEEDED(GetGraphTime(graphTime)) &&
                    graphTime > m_startTime + m_sampleCorrection.GetLastSampleEnd())
                {
                    break;
                }
            }
        }

        return true;
    }
}
<|endoftext|>


<commit_before>#include <vector>
#include <fstream>
#include <iostream>
#include <cassert>
#include <cmath>
#include "RandomNumberGenerator.h"

using namespace std;
using namespace DNest3;

class Data
{
	private:
		vector<double> logw, run_id;
		vector< vector<double> > scalars;
		int N;

	public:
		Data()
		{ }

		void load()
		{
			logw.clear(); run_id.clear(); scalars.clear();

			double temp;
			fstream fin("logw.txt", ios::in);
			int k = 0;
			while(fin >> temp)
			{
				logw.push_back(temp);
				if(k == 0)
					run_id.push_back(0);
				else if(logw.back() == -1.)
					run_id.push_back(run_id.back() + 1);
				else
					run_id.push_back(run_id.back());
				k++;
			}
			fin.close();

			fin.open("scalars.txt", ios::in);
			double temp2;
			while(fin >> temp && fin >> temp2)
			{
				vector<double> vec(2);
				vec[0] = temp; vec[1] = temp2;
				scalars.push_back(vec);
			}
			fin.close();

			if(scalars.size() < logw.size())
			{
				logw.erase(logw.begin() + scalars.size(),
						logw.end());
				run_id.erase(run_id.begin() + scalars.size(),
						run_id.end());
			}
			if(logw.size() < scalars.size())
			{
				scalars.erase(scalars.begin() + logw.size(),
						scalars.end());
			}

			assert(logw.size() == scalars.size());
			assert(logw.size() == run_id.size());
			N = logw.size();
			cout<<"# Loaded "<<N<<" points."<<endl;
	}

	friend class Assignment;
};

/************************************************************************/

class Assignment
{
	private:
		const Data& data;
		vector<double> logX;

	public:
		Assignment(const Data& data)
		:data(data)
		{
		}

		void initialise()
		{
			logX.assign(data.N, 0.);

			for(int i=0; i<data.N; i++)
			{
				if(data.logw[i] == -1.)
					logX[i] = log(randomU());
				else
					logX[i] = logX[i-1] + log(randomU());
			}
		}

		int update_all()
		{
			int total = 0;
			for(int i=0; i<data.N; i++)
			{
				total += update(i);
				cout<<"."<<flush;
			}
			cout<<endl;
			return total;
		}

		// Gibbs sample one value
		int update(int i)
		{
			double proposal;

			// Range of values for proposal
			double lower = -1E300;
			double upper = 0.;

			// Lower limit -- next point in same run (if it exists)
  			if( (i != (data.N-1)) &&
					(data.run_id[i+1] == data.run_id[i]))
    				lower = logX[i+1];
			// Upper limit -- previous point in same run (if it exists)
  			if( (i != 0) &&
					(data.run_id[i-1] == data.run_id[i]))
    				upper = logX[i-1];

			// If lower limit exists, generate uniformly between limits
			if(lower != -1E300)
				proposal = lower + (upper - lower)*randomU();
			else // otherwise use exponential distribution
				proposal = upper + log(randomU());

			// Measure inconsistency
			int inconsistency_old = 0;
			int inconsistency_new = 0;

			bool outside, inside;
			for(int j=0; j<data.N; j++)
			{
				if(data.run_id[j] != data.run_id[i])
				{
					// See if distribution j is outside,
					// inside, or unknown
					outside = true;
					inside  = true;
					for(int k=0; k<2; k++)
					{
						if(data.scalars[j][k] > data.scalars[i][k])
							outside = false;
						if(data.scalars[j][k] < data.scalars[i][k])
							inside = false;
					}

					if(outside && (logX[j] < logX[i]))
						inconsistency_old++;
					if(inside  && (logX[j] > logX[i]))
						inconsistency_old++;

					if(outside && (logX[j] < proposal))
						inconsistency_new++;
					if(inside  && (logX[j] > proposal))
						inconsistency_new++;
				}
			}

			int inconsistency = inconsistency_old;
			if(inconsistency_new <= inconsistency_old)
			{
				logX[i] = proposal;
				inconsistency = inconsistency_new;
			}
			return inconsistency;
		}

		void save()
		{
			fstream fout("logX.txt", ios::out);
			for(int i=0; i<data.N; i++)
				fout<<logX[i]<<endl;
			fout.close();
		}

};

int main()
{
	RandomNumberGenerator::initialise_instance();
	RandomNumberGenerator::get_instance().set_seed(time(0));

	Data data;
	data.load();

	Assignment assignment(data);
	assignment.initialise();

	for(int i=0; i<10000000; i++)
	{
		cout<<assignment.update_all()<<endl;
		assignment.save();
	}
	return 0;
}

<commit_msg>Do 100 sweeps (can be increased)<commit_after>#include <vector>
#include <fstream>
#include <iostream>
#include <cassert>
#include <cmath>
#include "RandomNumberGenerator.h"

using namespace std;
using namespace DNest3;

class Data
{
	private:
		vector<double> logw, run_id;
		vector< vector<double> > scalars;
		int N;

	public:
		Data()
		{ }

		void load()
		{
			logw.clear(); run_id.clear(); scalars.clear();

			double temp;
			fstream fin("logw.txt", ios::in);
			int k = 0;
			while(fin >> temp)
			{
				logw.push_back(temp);
				if(k == 0)
					run_id.push_back(0);
				else if(logw.back() == -1.)
					run_id.push_back(run_id.back() + 1);
				else
					run_id.push_back(run_id.back());
				k++;
			}
			fin.close();

			fin.open("scalars.txt", ios::in);
			double temp2;
			while(fin >> temp && fin >> temp2)
			{
				vector<double> vec(2);
				vec[0] = temp; vec[1] = temp2;
				scalars.push_back(vec);
			}
			fin.close();

			if(scalars.size() < logw.size())
			{
				logw.erase(logw.begin() + scalars.size(),
						logw.end());
				run_id.erase(run_id.begin() + scalars.size(),
						run_id.end());
			}
			if(logw.size() < scalars.size())
			{
				scalars.erase(scalars.begin() + logw.size(),
						scalars.end());
			}

			assert(logw.size() == scalars.size());
			assert(logw.size() == run_id.size());
			N = logw.size();
			cout<<"# Loaded "<<N<<" points."<<endl;
	}

	friend class Assignment;
};

/************************************************************************/

class Assignment
{
	private:
		const Data& data;
		vector<double> logX;

	public:
		Assignment(const Data& data)
		:data(data)
		{
		}

		void initialise()
		{
			logX.assign(data.N, 0.);

			for(int i=0; i<data.N; i++)
			{
				if(data.logw[i] == -1.)
					logX[i] = log(randomU());
				else
					logX[i] = logX[i-1] + log(randomU());
			}
		}

		int update_all()
		{
			int total = 0;
			for(int i=0; i<data.N; i++)
			{
				total += update(i);
				cout<<"."<<flush;
			}
			cout<<endl;
			return total;
		}

		// Gibbs sample one value
		int update(int i)
		{
			double proposal;

			// Range of values for proposal
			double lower = -1E300;
			double upper = 0.;

			// Lower limit -- next point in same run (if it exists)
  			if( (i != (data.N-1)) &&
					(data.run_id[i+1] == data.run_id[i]))
    				lower = logX[i+1];
			// Upper limit -- previous point in same run (if it exists)
  			if( (i != 0) &&
					(data.run_id[i-1] == data.run_id[i]))
    				upper = logX[i-1];

			// If lower limit exists, generate uniformly between limits
			if(lower != -1E300)
				proposal = lower + (upper - lower)*randomU();
			else // otherwise use exponential distribution
				proposal = upper + log(randomU());

			// Measure inconsistency
			int inconsistency_old = 0;
			int inconsistency_new = 0;

			bool outside, inside;
			for(int j=0; j<data.N; j++)
			{
				if(data.run_id[j] != data.run_id[i])
				{
					// See if distribution j is outside,
					// inside, or unknown
					outside = true;
					inside  = true;
					for(int k=0; k<2; k++)
					{
						if(data.scalars[j][k] > data.scalars[i][k])
							outside = false;
						if(data.scalars[j][k] < data.scalars[i][k])
							inside = false;
					}

					if(outside && (logX[j] < logX[i]))
						inconsistency_old++;
					if(inside  && (logX[j] > logX[i]))
						inconsistency_old++;

					if(outside && (logX[j] < proposal))
						inconsistency_new++;
					if(inside  && (logX[j] > proposal))
						inconsistency_new++;
				}
			}

			int inconsistency = inconsistency_old;
			if(inconsistency_new <= inconsistency_old)
			{
				logX[i] = proposal;
				inconsistency = inconsistency_new;
			}
			return inconsistency;
		}

		void save()
		{
			fstream fout("logX.txt", ios::out);
			for(int i=0; i<data.N; i++)
				fout<<logX[i]<<endl;
			fout.close();
		}

};

int main()
{
	RandomNumberGenerator::initialise_instance();
	RandomNumberGenerator::get_instance().set_seed(time(0));

	Data data;
	data.load();

	Assignment assignment(data);
	assignment.initialise();

	for(int i=0; i<100; i++)
	{
		cout<<assignment.update_all()<<endl;
		assignment.save();
	}
	return 0;
}

<|endoftext|>


<commit_before>///
/// @file  help.cpp
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount.hpp>

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

using namespace std;

namespace {

const string helpMenu(
  "Usage: primecount x [OPTION]...\n"
  "Count the primes below x < 2^63 using the prime counting function, by\n"
  "default uses the Deleglise & Rivat algorithm (-d).\n"
  "\n"
  "Options:\n"
  "  -d,    --deleglise_rivat  LMO with Deleglise and Rivat improvements\n"
  "         --legendre         Count primes using Legendre's formula\n"
  "  -m,    --meissel          Count primes using Meissel's formula\n"
  "  -l,    --lehmer           Count primes using Lehmer's formula\n"
  "         --lmo              Count primes using Lagarias-Miller-Odlyzko\n"
  "         --Li               Approximate pi(x) using the logarithmic integral\n"
  "         --Li_inverse       Approximate the nth prime using Li^-1(x)\n"
  "  -n,    --nthprime         Calculate the nth prime\n"
  "         --phi              Calculate phi(x, a), requires 2 arguments\n"
  "  -p,    --primesieve       Count primes using the sieve of Eratosthenes\n"
  "         --test             Run various correctness tests and exit\n"
  "         --time             Print the time elapsed in seconds\n"
  "  -t<N>, --threads=<N>      Set the number of threads, 1 <= N <= CPU cores\n"
  "  -v,    --version          Print version and license information\n"
  "  -h,    --help             Print this help menu\n"
  "\n"
  "Examples:\n"
  "  primecount 10**13\n"
  "  primecount 10**13 --nthprime"
);

const string versionInfo(
  "primecount " PRIMECOUNT_VERSION ", <https://github.com/kimwalisch/primecount>\n"
  "Copyright (C) 2014 Kim Walisch\n"
  "BSD 2-Clause License <http://opensource.org/licenses/BSD-2-Clause>"
);

} // end namespace

namespace primecount {

void help()
{
  cout << helpMenu << endl;
  exit(1);
}

void version()
{
  cout << versionInfo << endl;
  exit(1);
}

} // namespace primecount
<commit_msg>Update help text<commit_after>///
/// @file  help.cpp
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount.hpp>

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

using namespace std;

namespace {

const string helpMenu(
  "Usage: primecount x [OPTION]...\n"
  "Count the primes below x <= 10^27 using the prime counting function,\n"
  "by default the Deleglise-Rivat algorithm (-d) is used.\n"
  "\n"
  "Options:\n"
  "  -d,    --deleglise_rivat  LMO with Deleglise and Rivat improvements\n"
  "         --legendre         Count primes using Legendre's formula\n"
  "  -m,    --meissel          Count primes using Meissel's formula\n"
  "  -l,    --lehmer           Count primes using Lehmer's formula\n"
  "         --lmo              Count primes using Lagarias-Miller-Odlyzko\n"
  "         --Li               Approximate pi(x) using the logarithmic integral\n"
  "         --Li_inverse       Approximate the nth prime using Li^-1(x)\n"
  "  -n,    --nthprime         Calculate the nth prime\n"
  "         --phi              Calculate phi(x, a), requires 2 arguments\n"
  "  -p,    --primesieve       Count primes using the sieve of Eratosthenes\n"
  "         --test             Run various correctness tests and exit\n"
  "         --time             Print the time elapsed in seconds\n"
  "  -t<N>, --threads=<N>      Set the number of threads, 1 <= N <= CPU cores\n"
  "  -v,    --version          Print version and license information\n"
  "  -h,    --help             Print this help menu\n"
  "\n"
  "Examples:\n"
  "  primecount 10**13\n"
  "  primecount 10**13 --nthprime"
);

const string versionInfo(
  "primecount " PRIMECOUNT_VERSION ", <https://github.com/kimwalisch/primecount>\n"
  "Copyright (C) 2014 Kim Walisch\n"
  "BSD 2-Clause License <http://opensource.org/licenses/BSD-2-Clause>"
);

} // end namespace

namespace primecount {

void help()
{
  cout << helpMenu << endl;
  exit(1);
}

void version()
{
  cout << versionInfo << endl;
  exit(1);
}

} // namespace primecount
<|endoftext|>


<commit_before>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

#include "http_server.h"
#include "date.h"
#include "file_interpreter.h"
#include "path_resolution.h"

using namespace std;

#define BUFFER_SIZE 32

HTTPServer::HTTPServer(unsigned short port) : Server(port) {

}

void HTTPServer::handle() {
	Socket client = socket_.accept();
	string reply = process(accept(client));
	client.send(reply);
	client.close();
}

string HTTPServer::accept(Socket& client) {
	char buffer[BUFFER_SIZE];
    memset(buffer, 0, BUFFER_SIZE);
	int received_size = 0;

	string message = "";
	received_size = client.receive(BUFFER_SIZE, buffer);
    message.append(buffer);

    while (!is_valid_http_message(message) && received_size > 0) {
	    memset(buffer, 0, BUFFER_SIZE);
		received_size = client.receive(BUFFER_SIZE, buffer);
	    message.append(buffer);
    }

    return message;
}

string HTTPServer::process(const string& message) {
	string type;
	std::stringstream trimmer;
	trimmer << message;
	trimmer >> type;

	if (type == "GET") {
		string path;
		trimmer << message;
		trimmer >> path;

		path = vv::resolve_path(path, "/");

		if (path[path.length() - 1] == '/') {
			if (vv::file_exists(path + "index.ssjs")) {
				path += "index.ssjs";
			} else if (vv::file_exists(path + "index.html")) {
				path += "index.html";
			}
		}

		unique_ptr<FileInterpreter> interpreter = FileInterpreter::file_interpreter_for_path(path);

		string content = "";
		try {
			content = interpreter.get()->interpret();
		} catch (const HTTPException& e) {
			switch (e.code()) {
				case 404: return NotFound();
				default:  return InternalServerError();
			}
		}

		return OK(content, interpreter.get()->mime());
	}

	return NotImplemented();
}

bool HTTPServer::is_valid_http_message(string& message) {
	if (message[message.length() - 1] == '\n') {
		return true;
	}

	return false;
}

string HTTPServer::OK(const string& message, const string mime) {
	stringstream response;
	response << "HTTP/1.1 200 OK" << endl;
	response << "Date: " << Date::now("%a, %d %b %Y %H:%M:%S %Z") << endl;
	response << "Accept-Ranges: bytes" << endl;
	response << "Content-Length: " << message.length() << endl;
	response << "Connection: close" << endl;
	response << "Content-Type: " << mime << endl << endl;
	response << message << endl;
	return response.str();
}

string HTTPServer::BadRequest(const string& message) {
	stringstream response;
	response << "HTTP/1.0 400 Bad Request" << endl;
	response << "Date: " << Date::now("%a, %d %b %Y %H:%M:%S %Z") << endl;
	response << "Content-Type: text/html" << endl;
	response << "Content-Length: " << message.length() << endl;
	response << message;
	return response.str();
}

string HTTPServer::NotFound(const string& message) {
	stringstream response;
	response << "HTTP/1.0 404 Not Found" << endl;
	response << "Date: " << Date::now("%a, %d %b %Y %H:%M:%S %Z") << endl;
	response << "Content-Type: text/html" << endl;
	response << "Content-Length: " << message.length() << endl;
	response << message;
	return response.str();
}

string HTTPServer::InternalServerError(const string& message) {
	stringstream response;
	response << "HTTP/1.0 500 Internal Server Error" << endl;
	response << "Date: " << Date::now("%a, %d %b %Y %H:%M:%S %Z") << endl;
	response << "Content-Type: text/html" << endl;
	response << "Content-Length: " << message.length() << endl;
	response << message;
	return response.str();
}

string HTTPServer::NotImplemented(const string& message) {
	stringstream response;
	response << "HTTP/1.0 502 Not Implemented" << endl;
	response << "Date: " << Date::now("%a, %d %b %Y %H:%M:%S %Z") << endl;
	response << "Content-Type: text/html" << endl;
	response << "Content-Length: " << message.length() << endl;
	response << message;
	return response.str();
}
<commit_msg>Fix buffer issue with receiving data from a socket.<commit_after>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

#include "http_server.h"
#include "date.h"
#include "file_interpreter.h"
#include "path_resolution.h"

using namespace std;

#define BUFFER_SIZE 128

HTTPServer::HTTPServer(unsigned short port) : Server(port) {

}

void HTTPServer::handle() {
	Socket client = socket_.accept();
	string reply = process(accept(client));
	client.send(reply);
	client.close();
}

string HTTPServer::accept(Socket& client) {
	char buffer[BUFFER_SIZE];
    memset(buffer, 0, BUFFER_SIZE);
	int received_size = 0;

	string message = "";
	received_size = client.receive(BUFFER_SIZE, buffer);
    message.append(buffer, received_size);

    while (!is_valid_http_message(message) && received_size > 0) {
	    memset(buffer, 0, BUFFER_SIZE);
		received_size = client.receive(BUFFER_SIZE, buffer);
	    message.append(buffer, received_size);
    }

    return message;
}

string HTTPServer::process(const string& message) {
	string type;
	std::stringstream trimmer;
	trimmer << message;
	trimmer >> type;

	if (type == "GET") {
		string path;
		trimmer << message;
		trimmer >> path;

		path = vv::resolve_path(path, "/");

		if (path[path.length() - 1] == '/') {
			if (vv::file_exists(path + "index.ssjs")) {
				path += "index.ssjs";
			} else if (vv::file_exists(path + "index.html")) {
				path += "index.html";
			}
		}

		unique_ptr<FileInterpreter> interpreter = FileInterpreter::file_interpreter_for_path(path);

		string content = "";
		try {
			content = interpreter.get()->interpret();
		} catch (const HTTPException& e) {
			switch (e.code()) {
				case 404: return NotFound();
				default:  return InternalServerError();
			}
		}

		return OK(content, interpreter.get()->mime());
	}

	return NotImplemented();
}

bool HTTPServer::is_valid_http_message(string& message) {
	if (message[message.length() - 1] == '\n') {
		return true;
	}

	return false;
}

string HTTPServer::OK(const string& message, const string mime) {
	stringstream response;
	response << "HTTP/1.1 200 OK" << endl;
	response << "Date: " << Date::now("%a, %d %b %Y %H:%M:%S %Z") << endl;
	response << "Accept-Ranges: bytes" << endl;
	response << "Content-Length: " << message.length() << endl;
	response << "Connection: close" << endl;
	response << "Content-Type: " << mime << endl << endl;
	response << message << endl;
	return response.str();
}

string HTTPServer::BadRequest(const string& message) {
	stringstream response;
	response << "HTTP/1.0 400 Bad Request" << endl;
	response << "Date: " << Date::now("%a, %d %b %Y %H:%M:%S %Z") << endl;
	response << "Content-Type: text/html" << endl;
	response << "Content-Length: " << message.length() << endl;
	response << message;
	return response.str();
}

string HTTPServer::NotFound(const string& message) {
	stringstream response;
	response << "HTTP/1.0 404 Not Found" << endl;
	response << "Date: " << Date::now("%a, %d %b %Y %H:%M:%S %Z") << endl;
	response << "Content-Type: text/html" << endl;
	response << "Content-Length: " << message.length() << endl;
	response << message;
	return response.str();
}

string HTTPServer::InternalServerError(const string& message) {
	stringstream response;
	response << "HTTP/1.0 500 Internal Server Error" << endl;
	response << "Date: " << Date::now("%a, %d %b %Y %H:%M:%S %Z") << endl;
	response << "Content-Type: text/html" << endl;
	response << "Content-Length: " << message.length() << endl;
	response << message;
	return response.str();
}

string HTTPServer::NotImplemented(const string& message) {
	stringstream response;
	response << "HTTP/1.0 502 Not Implemented" << endl;
	response << "Date: " << Date::now("%a, %d %b %Y %H:%M:%S %Z") << endl;
	response << "Content-Type: text/html" << endl;
	response << "Content-Length: " << message.length() << endl;
	response << message;
	return response.str();
}
<|endoftext|>