bool isFileSparse(string fn) {
  ifstream fin(fn.c_str());
  string line;
  std::getline(fin, line);
  fin.close();
  return line.find(':') != string::npos;
}

#include <utility.h>
#include <data-io.h>
#include <stdexcept>
#include <algorithm>
#include <cassert>

#define CFRE(x) { if (x == 0) throw std::runtime_error(RED_ERROR + "Failed when read features. "); }
#define DEBUG_STR(x) ("\33[33m"#x"\33[0m = " + to_string(x) + "\t")

/* \brief Factory method for class DataStream
 *
 * */

DataStream::DataStream() : _size(0) {
}

DataStream::DataStream(const string& filename) : _filename(filename), _size(0) {
}

DataStream::DataStream(const DataStream& src) : _filename(src._filename), _size(src._size) {
}

DataStream* DataStream::create(const string& filename, size_t start, size_t end) {
  // Find if filename contains "ark:" as prefix. if yes, we'll read it from pipe.
  bool is_kaldi = (filename.size() > 4 && filename.substr(0, 4) == "ark:");

  if (is_kaldi)
    return new KaldiStream(filename);
  else
    return new BasicStream(filename, start, end);
}

size_t DataStream::size() const {
  return _size;
}

string DataStream::get_filename() const {
  return _filename;
}

/* Other Utility Functions
 *
 * */

/* \brief constructor of class BasicStream
 *
 * */
BasicStream::BasicStream(): _sparse(true), _line_number(0), _start(0), _end(-1) {
}

BasicStream::BasicStream(const string& filename, size_t start, size_t end):
  DataStream(filename), _sparse(isFileSparse(filename)), _line_number(0), _start(start), _end(end) {
  this->init(start, end);
}

BasicStream::BasicStream(const BasicStream& src) : DataStream(src),
  _sparse(src._sparse), _line_number(src._line_number), _start(src._start), _end(src._end) {
  this->init(_start, _end);
}

BasicStream::~BasicStream() {
  _fs.close();
}

BasicStream& BasicStream::operator = (BasicStream that) {
  swap(*this, that);
  return *this;
}

void BasicStream::init(size_t start, size_t end) {

  _start = start;
  _end = end;
  _line_number = _start;

  // Read from normal file
  if (_fs.is_open())
    _fs.close();

  _fs.open(DataStream::_filename.c_str());

  if (!_fs.is_open())
    throw std::runtime_error(RED_ERROR + "Cannot load file: " + DataStream::_filename);

  if (DataStream::_size == 0)
    DataStream::_size = count_lines(DataStream::_filename);

  go_to_line(_fs, _start);

  _end = min(DataStream::_size, _end);
  DataStream::_size = min(DataStream::_size, _end - _start);
}

DataStream* BasicStream::clone() const {
  return new BasicStream(*this);
}

BatchData BasicStream::read(int N, size_t dim, size_t base) {

  if (_sparse)
    return this->readSparseFeature(N, dim, base);
  else
    return this->readDenseFeature(N, dim, base);
}

BatchData BasicStream::readSparseFeature(int N, size_t dim, size_t base) {

  BatchData data;
  data.x.resize(N, dim + 1, 0);
  data.y.resize(N, 1, 0);

  string token;

  for (int i=0; i<N; ++i) {
    stringstream ss(this->getline());

    ss >> token;
    data.y[i] = stof(token);

    while (ss >> token) {
      size_t pos = token.find(':');
      if (pos == string::npos)
	continue;

      size_t j = stof(token.substr(0, pos));

      if (j == 0)
	throw std::runtime_error(RED_ERROR + "Index in sparse format should"
	    " be started from 1 instead of 0. ( like 1:... not 0:... )");

      float value = stof(token.substr(pos + 1));

      data.x(i, j - 1) = value;
    }

    // FIXME I'll remove it and move this into DNN. Since bias is only need by DNN,
    // not by CNN or other classifier.
    data.x(i, dim) = 1;
  }

  for (int i=0; i<N; ++i)
    data.y[i] -= base;

  return data;
}

BatchData BasicStream::readDenseFeature(int N, size_t dim, size_t base) {

  BatchData data;
  data.x.resize(N, dim + 1, 0);
  data.y.resize(N, 1, 0);

  string token;

  for (int i=0; i<N; ++i) {
    stringstream ss(this->getline());

    ss >> token;
    data.y[i] = stof(token);

    size_t j = 0;
    while (ss >> token)
      data.x(i, j++) = stof(token);

    // FIXME I'll remove it and move this into DNN. Since bias is only need by DNN,
    // not by CNN or other classifier.
    data.x(i, dim) = 1;
  }

  for (int i=0; i<N; ++i)
    data.y[i] -= base;

  return data;
}

string BasicStream::getline() {
  string line;

  if ( _line_number >= _end )
    this->rewind();

  if ( !std::getline(_fs, line) ) {
    this->rewind();
    std::getline(_fs, line);
  }

  ++_line_number;

  return line;
}

void BasicStream::rewind() {
  _fs.clear();
  go_to_line(_fs, _start);
  _line_number = _start;
}

void swap(BasicStream& a, BasicStream& b) {
  std::swap(a._sparse, b._sparse);
  std::swap(a._line_number, b._line_number);
  std::swap(a._start, b._start);
  std::swap(a._end, b._end);
}

/*
 * implementation of Kaldi DataStream
 *
 * */
string read_uid(FILE* fid) {
  char buffer[512];
  int result = fscanf(fid, "%s ", buffer);

  return (result != 1) ? "" : string(buffer);
}

KaldiStream::KaldiStream(): _remained(0), _ffid(nullptr), _lfid(nullptr) {
}

KaldiStream::KaldiStream(const string& filename): DataStream(filename),
  _remained(0), _ffid(nullptr), _lfid(nullptr) {
  this->init();
}

KaldiStream::KaldiStream(const KaldiStream& src): _remained(src._remained),
  _ffid(src._ffid), _lfid(src._lfid) {
}

KaldiStream::~KaldiStream() {
  if (_ffid) pclose(_ffid);
  if (_lfid) pclose(_lfid);
}

KaldiStream& KaldiStream::operator = (KaldiStream that) {
  swap(*this, that);
  return *this;
}

void KaldiStream::init(size_t start, size_t end) {

  clog << "Reading feature from \33[33m\"" << this->get_feature_command() << "\"\33[0m" << endl;
  clog << "Reading label from \33[33m\"" << this->get_label_command() << "\"\33[0m" << endl;

  // Use wc to count # of features
  string wc_count_words = this->get_label_command() + "| cut -f 2- -d ' ' | wc -w";

  FILE* fid = popen(wc_count_words.c_str(), "r");
  if (fscanf(fid, "%lu", &(DataStream::_size)) != 1)
    throw std::runtime_error(RED_ERROR + "Failed to count number of labels");
  pclose(fid);

  clog << util::blue("[Info]") << " Found " << util::green(to_string(DataStream::_size))
       << " labels in \"" << this->get_label_command() << "\"" << endl;

  _ffid = popen(this->get_feature_command().c_str(), "r");

  if (! (this->get_label_command().empty()) )
    _lfid = popen(this->get_label_command().c_str(), "r");
}

DataStream* KaldiStream::clone() const {
  return new KaldiStream(*this);
}

BatchData KaldiStream::read(int N, size_t dim, size_t base) {
  BatchData data;
  data.x.resize(N, dim + 1, 0);
  data.y.resize(N, 1, 0);

  // Read kaldi feature
  FILE* &fis = this->_ffid;
  FILE* &lis = this->_lfid;

  int counter = 0;
  int& r = this->_remained;

  while (true) {

    if (r == 0) {
      string uid1, uid2;
      uid1 = read_uid(fis);

      if (lis != nullptr) {
	uid2 = read_uid(lis);

	if (uid1.empty() or uid2.empty()) {
	  this->rewind();
	  uid1 = read_uid(fis);
	  uid2 = read_uid(lis);
	}

	if (uid1 != uid2)
	  throw std::runtime_error(RED_ERROR + "uid1 != uid2 (\"" + uid1 + "\" != \"" + uid2 + "\")");
      }

      char s[6];
      int frame;
      int dimension;

      CFRE(fread((void*) s, 6, 1, fis));
      CFRE(fread((void*) &frame, 4, 1, fis));
      CFRE(fread((void*) s, 1, 1, fis));
      CFRE(fread((void*) &dimension, 4, 1, fis));

      if (dimension != (int) dim)
	throw std::runtime_error(RED_ERROR + "feature dimension in kaldi archive (=" +
	    to_string(dimension) + ") does not match --input-dim (=" +
	    to_string(dim) + ").");

      r = frame;
    }

    for(int i = 0; i < r; i++) {
      for(int j = 0; j < (int) dim; j++)
	CFRE(fread((void*) &data.x(counter, j), sizeof(float), 1, fis));
      data.x(counter, dim) = 1;

      if (lis != nullptr) {
	size_t y;
	CFRE(fscanf(lis, "%lu", &y));
	data.y[counter] = y;
      }

      if (++counter == N) {
	r -= i + 1;
	return data;
      }
    }

    r = 0;
  }

  return data;
}

void KaldiStream::rewind() {
  pclose(_ffid);
  _ffid = popen(this->get_feature_command().c_str(), "r");

  if (_lfid != nullptr)
    pclose(_lfid);

  if (! (this->get_label_command().empty()) )
    _lfid = popen(this->get_label_command().c_str(), "r");

  this->_remained = 0;
}

string KaldiStream::get_feature_command() const {
  size_t pos = DataStream::_filename.find_first_of(",");

  /*if (pos == string::npos)
    throw runtime_error(RED_ERROR + "Please specify feature and label like ark:feat.ark,label.ark");*/

  return DataStream::_filename.substr(4, pos - 4);
}

string KaldiStream::get_label_command() const {
  size_t pos = DataStream::_filename.find_first_of(",");

  /*if (pos == string::npos)
    throw runtime_error(RED_ERROR + "Please specify feature and label like ark:feat.ark,label.ark");*/

  if (pos == string::npos)
    return "";
  else
    return DataStream::_filename.substr(pos + 1);
}

void swap(KaldiStream& a, KaldiStream& b) {
  std::swap(a._remained, b._remained);
  std::swap(a._ffid, b._ffid);
  std::swap(a._lfid, b._lfid);
}

/*
 * Other utilities
 *
 * */
size_t count_lines(const string& fn) {

  clog << "Loading file: \33[32m" << fn << "\33[0m (try to find out how many data) ...";
  clog.flush();

  std::ifstream fin(fn.c_str());
  size_t N = std::count(std::istreambuf_iterator<char>(fin),
      std::istreambuf_iterator<char>(), '\n');
  fin.close();

  clog << "\t\33[32m[Done]\33[0m" << endl;
  return N;
}

std::istream& go_to_line(std::istream& file, unsigned long num){
  file.seekg(std::ios::beg);

  if (num == 0)
    return file;

  for(size_t i=0; i < num; ++i)
    file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');

  return file;
}


switch (c) {
          case '+':
          case 'w':
          case 'a':
          case 'x':
          case 'c':
            return "w+b";
          default:
            break;
        }

/*
   +----------------------------------------------------------------------+
   | HipHop for PHP                                                       |
   +----------------------------------------------------------------------+
   +----------------------------------------------------------------------+
   +----------------------------------------------------------------------+
*/

#include "hphp/runtime/base/php-stream-wrapper.h"
#include "hphp/runtime/base/runtime-error.h"
#include "hphp/runtime/base/plain-file.h"
#include "hphp/runtime/base/temp-file.h"
#include "hphp/runtime/base/mem-file.h"
#include "hphp/runtime/base/output-file.h"
#include "hphp/runtime/server/cli-server.h"
#include "hphp/runtime/server/http-protocol.h"
#include "hphp/runtime/ext/stream/ext_stream.h"
#include <memory>

namespace HPHP {

const StaticString s_php("PHP");
const StaticString s_input("Input");
const StaticString s_temp("TEMP");
const StaticString s_memory("MEMORY");

req::ptr<File> PhpStreamWrapper::openFD(const char *sFD) {
  if (is_cli_server_mode()) {
    raise_warning("Direct access to file descriptors is not "
                  "available via remote unix server execution");
    return nullptr;
  }
  if (RuntimeOption::ServerExecutionMode()) {
    raise_warning("Direct access to file descriptors "
                  "is only available from command-line");
    return nullptr;
  }

  char *end = nullptr;
  long nFD = strtol(sFD, &end, 10);
  if ((sFD == end) || (*end != '\0')) {
    raise_warning("php://fd/ stream must be specified in the form "
                  "php://fd/<orig fd>");
    return nullptr;
  }
  long dtablesize = getdtablesize();
  if ((nFD < 0) || (nFD >= dtablesize)) {
    raise_warning("The file descriptors must be non-negative numbers "
                  "smaller than %ld", dtablesize);
    return nullptr;
  }

  return req::make<PlainFile>(dup(nFD), true, s_php);
}

req::ptr<File>
PhpStreamWrapper::open(const String& filename, const String& mode,
                       int options, const req::ptr<StreamContext>& context) {
  if (strncasecmp(filename.c_str(), "php://", 6)) {
    return nullptr;
  }

  const char *req = filename.c_str() + sizeof("php://") - 1;

  auto make_from = [] (const Variant& f) -> req::ptr<File> {
    auto res = dyn_cast_or_null<PlainFile>(f);
    if (!res || res->isClosed()) return nullptr;
    return req::make<PlainFile>(dup(res->fd()), true, s_php);
  };

  if (!strcasecmp(req, "stdin")) {
    return make_from(BuiltinFiles::getSTDIN());
  }
  if (!strcasecmp(req, "stdout")) {
    return make_from(BuiltinFiles::getSTDOUT());
  }
  if (!strcasecmp(req, "stderr")) {
    return make_from(BuiltinFiles::getSTDERR());
  }
  if (!strncasecmp(req, "fd/", sizeof("fd/") - 1)) {
    return openFD(req + sizeof("fd/") - 1);
  }
  if (!strncasecmp(req, "temp", sizeof("temp") - 1)) {
    auto file = req::make<TempFile>(true, s_php, s_temp);
    if (!file->valid()) {
      raise_warning("Unable to create temporary file");
      return nullptr;
    }
    return file;
  }
  if (!strcasecmp(req, "memory")) {
    auto file = req::make<TempFile>(true, s_php, s_memory);
    if (!file->valid()) {
      raise_warning("Unable to create temporary file");
      return nullptr;
    }

    file->getData()->m_mode = [mode] {
      if (mode.empty()) {
        return "w+b";
      }
      for (auto c : mode.slice()) {

      }
      return "rb";
    }();
    return file;
  }

  if (!strcasecmp(req, "input")) {
    auto raw_post = g_context->getRawPostData();
    return req::make<MemFile>(
      raw_post.c_str(), raw_post.size(), s_php, s_input);
  }

  if (!strcasecmp(req, "output")) {
    return req::make<OutputFile>(filename);
  }

  return nullptr;
}

}


int FloatDatatypeValidator::compare(const XMLCh* const lValue
                                  , const XMLCh* const rValue
                                  , MemoryManager* const manager)
{
    XMLFloat lObj(lValue, manager);
    XMLFloat rObj(rValue, manager);

    return compareValues(&lObj, &rObj);
}

/*
 */

/*
 * $Id$
 */

//  Includes
#include <xercesc/validators/datatype/FloatDatatypeValidator.hpp>
#include <xercesc/validators/schema/SchemaSymbols.hpp>
#include <xercesc/validators/datatype/InvalidDatatypeFacetException.hpp>
#include <xercesc/validators/datatype/InvalidDatatypeValueException.hpp>

XERCES_CPP_NAMESPACE_BEGIN

//  Constructors and Destructor
FloatDatatypeValidator::FloatDatatypeValidator(MemoryManager* const manager)
:AbstractNumericValidator(0, 0, 0, DatatypeValidator::Float, manager)
{
    setOrdered(XSSimpleTypeDefinition::ORDERED_PARTIAL);
    setBounded(true);
    setFinite(true);
    setNumeric(true);
}

FloatDatatypeValidator::FloatDatatypeValidator(
                          DatatypeValidator*            const baseValidator
                        , RefHashTableOf<KVStringPair>* const facets
                        , RefArrayVectorOf<XMLCh>*      const enums
                        , const int                           finalSet
                        , MemoryManager* const                manager)
:AbstractNumericValidator(baseValidator, facets, finalSet, DatatypeValidator::Float, manager)
{
    init(enums, manager);
}

FloatDatatypeValidator::~FloatDatatypeValidator()
{}

// Compare methods

DatatypeValidator* FloatDatatypeValidator::newInstance
(
      RefHashTableOf<KVStringPair>* const facets
    , RefArrayVectorOf<XMLCh>* const      enums
    , const int                           finalSet
    , MemoryManager* const                manager
)
{
    return (DatatypeValidator*) new (manager) FloatDatatypeValidator(this, facets, enums, finalSet, manager);
}

// ctor provided to be used by derived classes
FloatDatatypeValidator::FloatDatatypeValidator(DatatypeValidator*            const baseValidator
                                             , RefHashTableOf<KVStringPair>* const facets
                                             , const int                           finalSet
                                             , const ValidatorType                 type
                                             , MemoryManager* const                manager)
:AbstractNumericValidator(baseValidator, facets, finalSet, type, manager)
{
    //do not invoke init here !!!
}

int  FloatDatatypeValidator::compareValues(const XMLNumber* const lValue
                                         , const XMLNumber* const rValue)
{
    return XMLFloat::compareValues((XMLFloat*) lValue, (XMLFloat*) rValue);
}

void  FloatDatatypeValidator::setMaxInclusive(const XMLCh* const value)
{
    fMaxInclusive = new (fMemoryManager) XMLFloat(value, fMemoryManager);
}

void  FloatDatatypeValidator::setMaxExclusive(const XMLCh* const value)
{
    fMaxExclusive = new (fMemoryManager) XMLFloat(value, fMemoryManager);
}

void  FloatDatatypeValidator::setMinInclusive(const XMLCh* const value)
{
    fMinInclusive = new (fMemoryManager) XMLFloat(value, fMemoryManager);
}

void  FloatDatatypeValidator::setMinExclusive(const XMLCh* const value)
{
    fMinExclusive = new (fMemoryManager) XMLFloat(value, fMemoryManager);
}

void  FloatDatatypeValidator::setEnumeration(MemoryManager* const manager)
{
    // check 4.3.5.c0 must: enumeration values from the value space of base
    // 1. shall be from base value space
    // 2. shall be from current value space as well ( shall go through boundsCheck() )
    if (!fStrEnumeration)
        return;

    XMLSize_t i = 0;
    XMLSize_t enumLength = fStrEnumeration->size();

    FloatDatatypeValidator *numBase = (FloatDatatypeValidator*) getBaseValidator();
    if (numBase)
    {
        try
        {
            for ( i = 0; i < enumLength; i++)
            {
                numBase->checkContent(fStrEnumeration->elementAt(i), (ValidationContext*)0, false, manager);
            }
        }
        catch (XMLException&)
        {
            ThrowXMLwithMemMgr1(InvalidDatatypeFacetException
                , XMLExcepts::FACET_enum_base
                , fStrEnumeration->elementAt(i)
                , manager);

        }
    }
#if 0
// spec says that only base has to checkContent
    // We put the this->checkContent in a separate loop
    // to not block original message with in that method.
    for ( i = 0; i < enumLength; i++)
    {
        checkContent(fStrEnumeration->elementAt(i), (ValidationContext*)0, false, manager);
    }
#endif

    fEnumeration = new (fMemoryManager) RefVectorOf<XMLNumber>(enumLength, true,  fMemoryManager);
    fEnumerationInherited = false;

    for ( i = 0; i < enumLength; i++)
    {
        fEnumeration->insertElementAt(new (fMemoryManager) XMLFloat(fStrEnumeration->elementAt(i), fMemoryManager), i);
    }
}

// Abstract interface from AbstractNumericValidator
void FloatDatatypeValidator::checkContent(const XMLCh*             const content
                                         ,      ValidationContext* const context
                                         ,      bool                     asBase
                                         ,      MemoryManager*     const manager)
{

    //validate against base validator if any
    FloatDatatypeValidator *pBase = (FloatDatatypeValidator*) this->getBaseValidator();
    if (pBase)
        pBase->checkContent(content, context, true, manager);

    // we check pattern first
    if ( (getFacetsDefined() & DatatypeValidator::FACET_PATTERN ) != 0 )
    {
        if (getRegex()->matches(content, manager) ==false)
        {
            ThrowXMLwithMemMgr2(InvalidDatatypeValueException
                    , XMLExcepts::VALUE_NotMatch_Pattern
                    , content
                    , getPattern()
                    , manager);
        }
    }

    // if this is a base validator, we only need to check pattern facet
    // all other facet were inherited by the derived type
    if (asBase)
        return;

    XMLFloat theValue(content, manager);
    XMLFloat *theData = &theValue;

    if (getEnumeration() != 0)
    {
        XMLSize_t i=0;
        XMLSize_t enumLength = getEnumeration()->size();
        for ( ; i < enumLength; i++)
        {
            if (compareValues(theData, (XMLFloat*) getEnumeration()->elementAt(i))==0)
                break;
        }

        if (i == enumLength)
            ThrowXMLwithMemMgr1(InvalidDatatypeValueException, XMLExcepts::VALUE_NotIn_Enumeration, content, manager);
    }

    boundsCheck(theData, manager);
}

/***
 * Support for Serialization/De-serialization
 ***/

IMPL_XSERIALIZABLE_TOCREATE(FloatDatatypeValidator)

void FloatDatatypeValidator::serialize(XSerializeEngine& serEng)
{
    /***
     * Note:
     *
     *     During storing, we need write the specific number
     *     type info before calling base::serialize().
     *
     *     While loading, we do nothing here
     ***/

    if (serEng.isStoring())
    {
        serEng<<(int) (XMLNumber::Float);
    }

    AbstractNumericValidator::serialize(serEng);

}

XERCES_CPP_NAMESPACE_END

/**
  * End of file FloatDatatypeValidator::cpp
  */


try
        {
            for ( i = 0; i < enumLength; i++)
            {
                numBase->checkContent(fStrEnumeration->elementAt(i), (ValidationContext*)0, false, manager);
            }
        }
        catch (XMLException&)
        {
            ThrowXMLwithMemMgr1(InvalidDatatypeFacetException
                , XMLExcepts::FACET_enum_base
                , fStrEnumeration->elementAt(i)
                , manager);

        }

/*
 */

/*
 * $Id$
 */

//  Includes
#include <xercesc/validators/datatype/FloatDatatypeValidator.hpp>
#include <xercesc/validators/schema/SchemaSymbols.hpp>
#include <xercesc/validators/datatype/InvalidDatatypeFacetException.hpp>
#include <xercesc/validators/datatype/InvalidDatatypeValueException.hpp>

XERCES_CPP_NAMESPACE_BEGIN

//  Constructors and Destructor
FloatDatatypeValidator::FloatDatatypeValidator(MemoryManager* const manager)
:AbstractNumericValidator(0, 0, 0, DatatypeValidator::Float, manager)
{
    setOrdered(XSSimpleTypeDefinition::ORDERED_PARTIAL);
    setBounded(true);
    setFinite(true);
    setNumeric(true);
}

FloatDatatypeValidator::FloatDatatypeValidator(
                          DatatypeValidator*            const baseValidator
                        , RefHashTableOf<KVStringPair>* const facets
                        , RefArrayVectorOf<XMLCh>*      const enums
                        , const int                           finalSet
                        , MemoryManager* const                manager)
:AbstractNumericValidator(baseValidator, facets, finalSet, DatatypeValidator::Float, manager)
{
    init(enums, manager);
}

FloatDatatypeValidator::~FloatDatatypeValidator()
{}

// Compare methods
int FloatDatatypeValidator::compare(const XMLCh* const lValue
                                  , const XMLCh* const rValue
                                  , MemoryManager* const manager)
{
    XMLFloat lObj(lValue, manager);
    XMLFloat rObj(rValue, manager);

    return compareValues(&lObj, &rObj);
}

DatatypeValidator* FloatDatatypeValidator::newInstance
(
      RefHashTableOf<KVStringPair>* const facets
    , RefArrayVectorOf<XMLCh>* const      enums
    , const int                           finalSet
    , MemoryManager* const                manager
)
{
    return (DatatypeValidator*) new (manager) FloatDatatypeValidator(this, facets, enums, finalSet, manager);
}

// ctor provided to be used by derived classes
FloatDatatypeValidator::FloatDatatypeValidator(DatatypeValidator*            const baseValidator
                                             , RefHashTableOf<KVStringPair>* const facets
                                             , const int                           finalSet
                                             , const ValidatorType                 type
                                             , MemoryManager* const                manager)
:AbstractNumericValidator(baseValidator, facets, finalSet, type, manager)
{
    //do not invoke init here !!!
}

int  FloatDatatypeValidator::compareValues(const XMLNumber* const lValue
                                         , const XMLNumber* const rValue)
{
    return XMLFloat::compareValues((XMLFloat*) lValue, (XMLFloat*) rValue);
}

void  FloatDatatypeValidator::setMaxInclusive(const XMLCh* const value)
{
    fMaxInclusive = new (fMemoryManager) XMLFloat(value, fMemoryManager);
}

void  FloatDatatypeValidator::setMaxExclusive(const XMLCh* const value)
{
    fMaxExclusive = new (fMemoryManager) XMLFloat(value, fMemoryManager);
}

void  FloatDatatypeValidator::setMinInclusive(const XMLCh* const value)
{
    fMinInclusive = new (fMemoryManager) XMLFloat(value, fMemoryManager);
}

void  FloatDatatypeValidator::setMinExclusive(const XMLCh* const value)
{
    fMinExclusive = new (fMemoryManager) XMLFloat(value, fMemoryManager);
}

void  FloatDatatypeValidator::setEnumeration(MemoryManager* const manager)
{
    // check 4.3.5.c0 must: enumeration values from the value space of base
    // 1. shall be from base value space
    // 2. shall be from current value space as well ( shall go through boundsCheck() )
    if (!fStrEnumeration)
        return;

    XMLSize_t i = 0;
    XMLSize_t enumLength = fStrEnumeration->size();

    FloatDatatypeValidator *numBase = (FloatDatatypeValidator*) getBaseValidator();
    if (numBase)
    {

    }
#if 0
// spec says that only base has to checkContent
    // We put the this->checkContent in a separate loop
    // to not block original message with in that method.
    for ( i = 0; i < enumLength; i++)
    {
        checkContent(fStrEnumeration->elementAt(i), (ValidationContext*)0, false, manager);
    }
#endif

    fEnumeration = new (fMemoryManager) RefVectorOf<XMLNumber>(enumLength, true,  fMemoryManager);
    fEnumerationInherited = false;

    for ( i = 0; i < enumLength; i++)
    {
        fEnumeration->insertElementAt(new (fMemoryManager) XMLFloat(fStrEnumeration->elementAt(i), fMemoryManager), i);
    }
}

// Abstract interface from AbstractNumericValidator
void FloatDatatypeValidator::checkContent(const XMLCh*             const content
                                         ,      ValidationContext* const context
                                         ,      bool                     asBase
                                         ,      MemoryManager*     const manager)
{

    //validate against base validator if any
    FloatDatatypeValidator *pBase = (FloatDatatypeValidator*) this->getBaseValidator();
    if (pBase)
        pBase->checkContent(content, context, true, manager);

    // we check pattern first
    if ( (getFacetsDefined() & DatatypeValidator::FACET_PATTERN ) != 0 )
    {
        if (getRegex()->matches(content, manager) ==false)
        {
            ThrowXMLwithMemMgr2(InvalidDatatypeValueException
                    , XMLExcepts::VALUE_NotMatch_Pattern
                    , content
                    , getPattern()
                    , manager);
        }
    }

    // if this is a base validator, we only need to check pattern facet
    // all other facet were inherited by the derived type
    if (asBase)
        return;

    XMLFloat theValue(content, manager);
    XMLFloat *theData = &theValue;

    if (getEnumeration() != 0)
    {
        XMLSize_t i=0;
        XMLSize_t enumLength = getEnumeration()->size();
        for ( ; i < enumLength; i++)
        {
            if (compareValues(theData, (XMLFloat*) getEnumeration()->elementAt(i))==0)
                break;
        }

        if (i == enumLength)
            ThrowXMLwithMemMgr1(InvalidDatatypeValueException, XMLExcepts::VALUE_NotIn_Enumeration, content, manager);
    }

    boundsCheck(theData, manager);
}

/***
 * Support for Serialization/De-serialization
 ***/

IMPL_XSERIALIZABLE_TOCREATE(FloatDatatypeValidator)

void FloatDatatypeValidator::serialize(XSerializeEngine& serEng)
{
    /***
     * Note:
     *
     *     During storing, we need write the specific number
     *     type info before calling base::serialize().
     *
     *     While loading, we do nothing here
     ***/

    if (serEng.isStoring())
    {
        serEng<<(int) (XMLNumber::Float);
    }

    AbstractNumericValidator::serialize(serEng);

}

XERCES_CPP_NAMESPACE_END

/**
  * End of file FloatDatatypeValidator::cpp
  */


bool WindowManager::openDisplayImpl(QString *errorMessage)
{
    *errorMessage = QLatin1String("Not implemented.");
    return false;
}

/****************************************************************************
**
** All rights reserved.
** Contact: Nokia Corporation (example@nnthink.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
**
****************************************************************************/

#include "windowmanager.h"
#include <QtCore/QTime>
#include <QtCore/QThread>
#include <QtCore/QDebug>
#include <QtCore/QTextStream>

#ifdef Q_WS_X11
#  include <string.h>     // memset
#  include <X11/Xlib.h>
#  include <X11/Xatom.h>  // XA_WM_STATE
#  include <X11/Xutil.h>
#  include <X11/Xmd.h>    // CARD32
#endif

#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
#  include <windows.h>
#endif

// Export the sleep function
class FriendlySleepyThread : public QThread {
public:
    static void sleepMS(int milliSeconds) { msleep(milliSeconds); }
};

#ifdef Q_WS_X11
// X11 Window manager

// Register our own error handler to prevent the defult crashing
// behaviour. It simply counts errors in global variables that
// can be checked after calls.

static unsigned x11ErrorCount = 0;
static const char *currentX11Function = 0;

int xErrorHandler(Display *, XErrorEvent *e)
{
    x11ErrorCount++;

    QString msg;
    QTextStream str(&msg);
    str << "An X11 error (#" << x11ErrorCount<< ") occurred: ";
    if (currentX11Function)
        str << ' ' << currentX11Function << "()";
    str << " code: " << e->error_code;
    str.setIntegerBase(16);
    str << " resource: 0x" << e->resourceid;
    qWarning("%s", qPrintable(msg));

    return 0;
}

static bool isMapped(Display *display, Atom xa_wm_state, Window window, bool *isMapped)
{
    Atom actual_type;
    int actual_format;
    unsigned long nitems;
    unsigned long bytes_after;
    unsigned char *prop;

    *isMapped = false;
    currentX11Function = "XGetWindowProperty";
    const int retv = XGetWindowProperty(display, window, xa_wm_state, 0L, 1L, False, xa_wm_state,
                                        &actual_type, &actual_format, &nitems, &bytes_after, &prop);

    if (retv != Success || actual_type == None || actual_type != xa_wm_state
        || nitems != 1 || actual_format != 32)
        return false;

    const CARD32 state = * reinterpret_cast<CARD32 *>(prop);

    switch ((int) state) {
    case WithdrawnState:
        *isMapped = false;
        break;
    case NormalState:
    case IconicState:
        *isMapped = true;
        break;
    default:
        *isMapped = true;
        break;
    }
    return true;
}

// Wait until a X11 top level has been mapped, courtesy of xtoolwait.
static Window waitForTopLevelMapped(Display *display, unsigned count, int timeOutMS, QString * errorMessage)
{
    unsigned mappingsCount = count;
    Atom xa_wm_state;
    XEvent event;

    // Discard all pending events
    currentX11Function = "XSync";
    XSync(display, True);

    // Listen for top level creation
    currentX11Function = "XSelectInput";
    XSelectInput(display, DefaultRootWindow(display), SubstructureNotifyMask);

    /* We assume that the window manager provides the WM_STATE property on top-level
     * windows, as required by ICCCM 2.0.
     * If the window manager has not yet completed its initialisation, the WM_STATE atom
     * might not exist, in which case we create it. */

#ifdef XA_WM_STATE    /* probably in X11R7 */
    xa_wm_state = XA_WM_STATE;
#else
    xa_wm_state = XInternAtom(display, "WM_STATE", False);
#endif

    QTime elapsedTime;
    elapsedTime.start();
    while (mappingsCount) {
        if (elapsedTime.elapsed() > timeOutMS) {
            *errorMessage = QString::fromLatin1("X11: Timed out waiting for toplevel %1ms").arg(timeOutMS);
            return 0;
        }
        currentX11Function = "XNextEvent";
        unsigned errorCount = x11ErrorCount;
        XNextEvent(display, &event);
        if (x11ErrorCount > errorCount) {
            *errorMessage = QString::fromLatin1("X11: Error in XNextEvent");
            return 0;
        }
        switch (event.type) {
        case CreateNotify:
            // Window created, listen for its mapping now
            if (!event.xcreatewindow.send_event && !event.xcreatewindow.override_redirect)
                XSelectInput(display, event.xcreatewindow.window, PropertyChangeMask);
            break;
        case PropertyNotify:
            // Watch for map
            if (!event.xproperty.send_event && event.xproperty.atom == xa_wm_state) {
                bool mapped;
                if (isMapped(display, xa_wm_state, event.xproperty.window, &mapped)) {
                    if (mapped && --mappingsCount == 0)
                        return event.xproperty.window;
                    // Past splash screen, listen for next window to be created
                    XSelectInput(display, DefaultRootWindow(display), SubstructureNotifyMask);
                } else {
                    // Some temporary window disappeared. Listen for next creation
                    XSelectInput(display, DefaultRootWindow(display), SubstructureNotifyMask);
                }
                // Main app window opened?
            }
            break;
        default:
            break;
        }
    }
    *errorMessage = QString::fromLatin1("X11: Timed out waiting for toplevel %1ms").arg(timeOutMS);
    return 0;
}

class X11_WindowManager : public WindowManager
{
public:
    X11_WindowManager();
    ~X11_WindowManager();

protected:
    virtual bool isDisplayOpenImpl() const;
    virtual bool openDisplayImpl(QString *errorMessage);
    virtual QString waitForTopLevelWindowImpl(unsigned count, Q_PID, int timeOutMS, QString *errorMessage);
    virtual bool sendCloseEventImpl(const QString &winId, Q_PID pid, QString *errorMessage);

private:
    Display *m_display;
    const QByteArray m_displayVariable;
    XErrorHandler m_oldErrorHandler;
};

X11_WindowManager::X11_WindowManager() :
    m_display(0),
    m_displayVariable(qgetenv("DISPLAY")),
    m_oldErrorHandler(0)
{
}

X11_WindowManager::~X11_WindowManager()
{
    if (m_display) {
        XSetErrorHandler(m_oldErrorHandler);
        XCloseDisplay(m_display);
    }
}

bool X11_WindowManager::isDisplayOpenImpl() const
{
    return m_display != 0;
}

bool X11_WindowManager::openDisplayImpl(QString *errorMessage)
{
    if (m_displayVariable.isEmpty()) {
        *errorMessage = QLatin1String("X11: Display not set");
        return false;
    }
    m_display = XOpenDisplay(NULL);
    if (!m_display) {
        *errorMessage = QString::fromLatin1("X11: Cannot open display %1.").arg(QString::fromLocal8Bit(m_displayVariable));
        return false;
    }

    m_oldErrorHandler = XSetErrorHandler(xErrorHandler);
    return true;
}

QString X11_WindowManager::waitForTopLevelWindowImpl(unsigned count, Q_PID, int timeOutMS, QString *errorMessage)
{
    const Window w = waitForTopLevelMapped(m_display, count, timeOutMS, errorMessage);
    if (w == 0)
        return QString();
    return QLatin1String("0x") + QString::number(w, 16);
}

 bool X11_WindowManager::sendCloseEventImpl(const QString &winId, Q_PID, QString *errorMessage)
 {
     // Get win id
     bool ok;
     const Window window = winId.toULong(&ok, 16);
     if (!ok) {
         *errorMessage = QString::fromLatin1("Invalid win id %1.").arg(winId);
         return false;
     }
     // Send a window manager close event
     XEvent ev;
     memset(&ev, 0, sizeof (ev));
     ev.xclient.type = ClientMessage;
     ev.xclient.window = window;
     ev.xclient.message_type = XInternAtom(m_display, "WM_PROTOCOLS", true);
     ev.xclient.format = 32;
     ev.xclient.data.l[0] = XInternAtom(m_display, "WM_DELETE_WINDOW", false);
     ev.xclient.data.l[1] = CurrentTime;
     // Window disappeared or some error triggered?
     unsigned errorCount = x11ErrorCount;
     currentX11Function = "XSendEvent";
     XSendEvent(m_display, window, False, NoEventMask, &ev);
     if (x11ErrorCount > errorCount) {
         *errorMessage = QString::fromLatin1("Error sending event to win id %1.").arg(winId);
         return false;
     }
     currentX11Function = "XSync";
     errorCount = x11ErrorCount;
     XSync(m_display, False);
     if (x11ErrorCount > errorCount) {
         *errorMessage = QString::fromLatin1("Error sending event to win id %1 (XSync).").arg(winId);
         return false;
     }
     return true;
 }

#endif

#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
// Windows

 QString winErrorMessage(unsigned long error)
{
    QString rc = QString::fromLatin1("#%1: ").arg(error);
    ushort *lpMsgBuf;

    const int len = FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
    if (len) {
        rc = QString::fromUtf16(lpMsgBuf, len);
        LocalFree(lpMsgBuf);
    } else {
        rc += QString::fromLatin1("<unknown error>");
    }
    return rc;
}

 class Win_WindowManager : public WindowManager
 {
 public:
     Win_WindowManager() {}

 protected:
     virtual bool isDisplayOpenImpl() const;
     virtual bool openDisplayImpl(QString *errorMessage);
     virtual QString waitForTopLevelWindowImpl(unsigned count, Q_PID, int timeOutMS, QString *errorMessage);
     virtual bool sendCloseEventImpl(const QString &winId, Q_PID pid, QString *errorMessage);

 private:
 };

bool Win_WindowManager::isDisplayOpenImpl() const
{
    return true;
}

bool Win_WindowManager::openDisplayImpl(QString *)
{
    return true;
}

// Enumerate window looking for toplevel of process id
struct FindProcessWindowEnumContext {
    FindProcessWindowEnumContext(DWORD pid) : window(0),processId(pid) {}

    HWND window;
    DWORD processId;
};

/* Check for the active main window of the Application
 * of class QWidget. */
static inline bool isQtMainWindow(HWND hwnd)
{
    static char buffer[MAX_PATH];
    if (!GetClassNameA(hwnd, buffer, MAX_PATH) || qstrcmp(buffer, "QWidget"))
        return false;
    WINDOWINFO windowInfo;
    if (!GetWindowInfo(hwnd, &windowInfo))
        return false;
    if (!(windowInfo.dwWindowStatus & WS_ACTIVECAPTION))
        return false;
    // Check the style for a real mainwindow
    const DWORD excluded = WS_DISABLED | WS_POPUP;
    const DWORD required = WS_CAPTION | WS_SYSMENU | WS_VISIBLE;
    return (windowInfo.dwStyle & excluded) == 0
            && (windowInfo.dwStyle & required) == required;
}

static BOOL CALLBACK findProcessWindowEnumWindowProc(HWND hwnd, LPARAM lParam)
{
    DWORD processId = 0;
    FindProcessWindowEnumContext *context= reinterpret_cast<FindProcessWindowEnumContext *>(lParam);
    GetWindowThreadProcessId(hwnd, &processId);
    if (context->processId == processId && isQtMainWindow(hwnd)) {
        context->window = hwnd;
        return FALSE;
    }
    return TRUE;
}

QString Win_WindowManager::waitForTopLevelWindowImpl(unsigned /* count */, Q_PID pid, int timeOutMS, QString *errorMessage)
{
    QTime elapsed;
    elapsed.start();
    // First, wait until the application is up
    if (WaitForInputIdle(pid->hProcess, timeOutMS) != 0) {
        *errorMessage = QString::fromLatin1("WaitForInputIdle time out after %1ms").arg(timeOutMS);
        return QString();
    }
    // Try to locate top level app window. App still might be in splash screen or initialization
    const int remainingMilliSeconds = qMax(timeOutMS - elapsed.elapsed(), 500);
    const int attempts = 10;
    const int intervalMilliSeconds = remainingMilliSeconds / attempts;
    for (int a = 0; a < attempts; a++) {
        FindProcessWindowEnumContext context(pid->dwProcessId);
        EnumWindows(findProcessWindowEnumWindowProc, reinterpret_cast<LPARAM>(&context));
        if (context.window)
            return QLatin1String("0x") + QString::number(reinterpret_cast<quintptr>(context.window), 16);
        sleepMS(intervalMilliSeconds);
    }
    *errorMessage = QString::fromLatin1("Unable to find toplevel of process %1 after %2ms.").arg(pid->dwProcessId).arg(timeOutMS);
    return QString();
}

bool Win_WindowManager::sendCloseEventImpl(const QString &winId, Q_PID, QString *errorMessage)
{
    // Convert window back.
    quintptr winIdIntPtr;
    QTextStream str(const_cast<QString*>(&winId), QIODevice::ReadOnly);
    str.setIntegerBase(16);
    str >> winIdIntPtr;
    if (str.status() != QTextStream::Ok) {
        *errorMessage = QString::fromLatin1("Invalid win id %1.").arg(winId);
        return false;
    }
    if (!PostMessage(reinterpret_cast<HWND>(winIdIntPtr), WM_CLOSE, 0, 0)) {
        *errorMessage = QString::fromLatin1("Cannot send event to 0x%1: %2").arg(winIdIntPtr, 0, 16).arg(winErrorMessage(GetLastError()));
        return false;
    }
    return true;
}
#endif

WindowManager::WindowManager()
{
}

WindowManager::~WindowManager()
{
}

QSharedPointer<WindowManager> WindowManager::create()
{
#ifdef Q_WS_X11
    return QSharedPointer<WindowManager>(new X11_WindowManager);
#endif
#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
    return QSharedPointer<WindowManager>(new Win_WindowManager);
#else
    return QSharedPointer<WindowManager>(new WindowManager);
#endif
}

static inline QString msgNoDisplayOpen() { return QLatin1String("No display opened."); }

bool WindowManager::openDisplay(QString *errorMessage)
{
    if (isDisplayOpen())
        return true;
    return openDisplayImpl(errorMessage);
}

bool WindowManager::isDisplayOpen() const
{
    return isDisplayOpenImpl();
}

QString WindowManager::waitForTopLevelWindow(unsigned count, Q_PID pid, int timeOutMS, QString *errorMessage)
{
    if (!isDisplayOpen()) {
        *errorMessage = msgNoDisplayOpen();
        return QString();
    }
    return waitForTopLevelWindowImpl(count, pid, timeOutMS, errorMessage);
}

bool WindowManager::sendCloseEvent(const QString &winId, Q_PID pid, QString *errorMessage)
{
    if (!isDisplayOpen()) {
        *errorMessage = msgNoDisplayOpen();
        return false;
    }
    return sendCloseEventImpl(winId, pid, errorMessage);
}

// Default Implementation

bool WindowManager::isDisplayOpenImpl() const
{
    return false;
}

QString WindowManager::waitForTopLevelWindowImpl(unsigned, Q_PID, int, QString *errorMessage)
{
    *errorMessage = QLatin1String("Not implemented.");
    return QString();
}

bool WindowManager::sendCloseEventImpl(const QString &, Q_PID, QString *errorMessage)
{
    *errorMessage = QLatin1String("Not implemented.");
    return false;
}

void WindowManager::sleepMS(int milliSeconds)
{
    FriendlySleepyThread::sleepMS(milliSeconds);
}


switch ((int) state) {
    case WithdrawnState:
        *isMapped = false;
        break;
    case NormalState:
    case IconicState:
        *isMapped = true;
        break;
    default:
        *isMapped = true;
        break;
    }

/****************************************************************************
**
** All rights reserved.
** Contact: Nokia Corporation (example@nnthink.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
**
****************************************************************************/

#include "windowmanager.h"
#include <QtCore/QTime>
#include <QtCore/QThread>
#include <QtCore/QDebug>
#include <QtCore/QTextStream>

#ifdef Q_WS_X11
#  include <string.h>     // memset
#  include <X11/Xlib.h>
#  include <X11/Xatom.h>  // XA_WM_STATE
#  include <X11/Xutil.h>
#  include <X11/Xmd.h>    // CARD32
#endif

#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
#  include <windows.h>
#endif

// Export the sleep function
class FriendlySleepyThread : public QThread {
public:
    static void sleepMS(int milliSeconds) { msleep(milliSeconds); }
};

#ifdef Q_WS_X11
// X11 Window manager

// Register our own error handler to prevent the defult crashing
// behaviour. It simply counts errors in global variables that
// can be checked after calls.

static unsigned x11ErrorCount = 0;
static const char *currentX11Function = 0;

int xErrorHandler(Display *, XErrorEvent *e)
{
    x11ErrorCount++;

    QString msg;
    QTextStream str(&msg);
    str << "An X11 error (#" << x11ErrorCount<< ") occurred: ";
    if (currentX11Function)
        str << ' ' << currentX11Function << "()";
    str << " code: " << e->error_code;
    str.setIntegerBase(16);
    str << " resource: 0x" << e->resourceid;
    qWarning("%s", qPrintable(msg));

    return 0;
}

static bool isMapped(Display *display, Atom xa_wm_state, Window window, bool *isMapped)
{
    Atom actual_type;
    int actual_format;
    unsigned long nitems;
    unsigned long bytes_after;
    unsigned char *prop;

    *isMapped = false;
    currentX11Function = "XGetWindowProperty";
    const int retv = XGetWindowProperty(display, window, xa_wm_state, 0L, 1L, False, xa_wm_state,
                                        &actual_type, &actual_format, &nitems, &bytes_after, &prop);

    if (retv != Success || actual_type == None || actual_type != xa_wm_state
        || nitems != 1 || actual_format != 32)
        return false;

    const CARD32 state = * reinterpret_cast<CARD32 *>(prop);

    return true;
}

// Wait until a X11 top level has been mapped, courtesy of xtoolwait.
static Window waitForTopLevelMapped(Display *display, unsigned count, int timeOutMS, QString * errorMessage)
{
    unsigned mappingsCount = count;
    Atom xa_wm_state;
    XEvent event;

    // Discard all pending events
    currentX11Function = "XSync";
    XSync(display, True);

    // Listen for top level creation
    currentX11Function = "XSelectInput";
    XSelectInput(display, DefaultRootWindow(display), SubstructureNotifyMask);

    /* We assume that the window manager provides the WM_STATE property on top-level
     * windows, as required by ICCCM 2.0.
     * If the window manager has not yet completed its initialisation, the WM_STATE atom
     * might not exist, in which case we create it. */

#ifdef XA_WM_STATE    /* probably in X11R7 */
    xa_wm_state = XA_WM_STATE;
#else
    xa_wm_state = XInternAtom(display, "WM_STATE", False);
#endif

    QTime elapsedTime;
    elapsedTime.start();
    while (mappingsCount) {
        if (elapsedTime.elapsed() > timeOutMS) {
            *errorMessage = QString::fromLatin1("X11: Timed out waiting for toplevel %1ms").arg(timeOutMS);
            return 0;
        }
        currentX11Function = "XNextEvent";
        unsigned errorCount = x11ErrorCount;
        XNextEvent(display, &event);
        if (x11ErrorCount > errorCount) {
            *errorMessage = QString::fromLatin1("X11: Error in XNextEvent");
            return 0;
        }
        switch (event.type) {
        case CreateNotify:
            // Window created, listen for its mapping now
            if (!event.xcreatewindow.send_event && !event.xcreatewindow.override_redirect)
                XSelectInput(display, event.xcreatewindow.window, PropertyChangeMask);
            break;
        case PropertyNotify:
            // Watch for map
            if (!event.xproperty.send_event && event.xproperty.atom == xa_wm_state) {
                bool mapped;
                if (isMapped(display, xa_wm_state, event.xproperty.window, &mapped)) {
                    if (mapped && --mappingsCount == 0)
                        return event.xproperty.window;
                    // Past splash screen, listen for next window to be created
                    XSelectInput(display, DefaultRootWindow(display), SubstructureNotifyMask);
                } else {
                    // Some temporary window disappeared. Listen for next creation
                    XSelectInput(display, DefaultRootWindow(display), SubstructureNotifyMask);
                }
                // Main app window opened?
            }
            break;
        default:
            break;
        }
    }
    *errorMessage = QString::fromLatin1("X11: Timed out waiting for toplevel %1ms").arg(timeOutMS);
    return 0;
}

class X11_WindowManager : public WindowManager
{
public:
    X11_WindowManager();
    ~X11_WindowManager();

protected:
    virtual bool isDisplayOpenImpl() const;
    virtual bool openDisplayImpl(QString *errorMessage);
    virtual QString waitForTopLevelWindowImpl(unsigned count, Q_PID, int timeOutMS, QString *errorMessage);
    virtual bool sendCloseEventImpl(const QString &winId, Q_PID pid, QString *errorMessage);

private:
    Display *m_display;
    const QByteArray m_displayVariable;
    XErrorHandler m_oldErrorHandler;
};

X11_WindowManager::X11_WindowManager() :
    m_display(0),
    m_displayVariable(qgetenv("DISPLAY")),
    m_oldErrorHandler(0)
{
}

X11_WindowManager::~X11_WindowManager()
{
    if (m_display) {
        XSetErrorHandler(m_oldErrorHandler);
        XCloseDisplay(m_display);
    }
}

bool X11_WindowManager::isDisplayOpenImpl() const
{
    return m_display != 0;
}

bool X11_WindowManager::openDisplayImpl(QString *errorMessage)
{
    if (m_displayVariable.isEmpty()) {
        *errorMessage = QLatin1String("X11: Display not set");
        return false;
    }
    m_display = XOpenDisplay(NULL);
    if (!m_display) {
        *errorMessage = QString::fromLatin1("X11: Cannot open display %1.").arg(QString::fromLocal8Bit(m_displayVariable));
        return false;
    }

    m_oldErrorHandler = XSetErrorHandler(xErrorHandler);
    return true;
}

QString X11_WindowManager::waitForTopLevelWindowImpl(unsigned count, Q_PID, int timeOutMS, QString *errorMessage)
{
    const Window w = waitForTopLevelMapped(m_display, count, timeOutMS, errorMessage);
    if (w == 0)
        return QString();
    return QLatin1String("0x") + QString::number(w, 16);
}

 bool X11_WindowManager::sendCloseEventImpl(const QString &winId, Q_PID, QString *errorMessage)
 {
     // Get win id
     bool ok;
     const Window window = winId.toULong(&ok, 16);
     if (!ok) {
         *errorMessage = QString::fromLatin1("Invalid win id %1.").arg(winId);
         return false;
     }
     // Send a window manager close event
     XEvent ev;
     memset(&ev, 0, sizeof (ev));
     ev.xclient.type = ClientMessage;
     ev.xclient.window = window;
     ev.xclient.message_type = XInternAtom(m_display, "WM_PROTOCOLS", true);
     ev.xclient.format = 32;
     ev.xclient.data.l[0] = XInternAtom(m_display, "WM_DELETE_WINDOW", false);
     ev.xclient.data.l[1] = CurrentTime;
     // Window disappeared or some error triggered?
     unsigned errorCount = x11ErrorCount;
     currentX11Function = "XSendEvent";
     XSendEvent(m_display, window, False, NoEventMask, &ev);
     if (x11ErrorCount > errorCount) {
         *errorMessage = QString::fromLatin1("Error sending event to win id %1.").arg(winId);
         return false;
     }
     currentX11Function = "XSync";
     errorCount = x11ErrorCount;
     XSync(m_display, False);
     if (x11ErrorCount > errorCount) {
         *errorMessage = QString::fromLatin1("Error sending event to win id %1 (XSync).").arg(winId);
         return false;
     }
     return true;
 }

#endif

#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
// Windows

 QString winErrorMessage(unsigned long error)
{
    QString rc = QString::fromLatin1("#%1: ").arg(error);
    ushort *lpMsgBuf;

    const int len = FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
    if (len) {
        rc = QString::fromUtf16(lpMsgBuf, len);
        LocalFree(lpMsgBuf);
    } else {
        rc += QString::fromLatin1("<unknown error>");
    }
    return rc;
}

 class Win_WindowManager : public WindowManager
 {
 public:
     Win_WindowManager() {}

 protected:
     virtual bool isDisplayOpenImpl() const;
     virtual bool openDisplayImpl(QString *errorMessage);
     virtual QString waitForTopLevelWindowImpl(unsigned count, Q_PID, int timeOutMS, QString *errorMessage);
     virtual bool sendCloseEventImpl(const QString &winId, Q_PID pid, QString *errorMessage);

 private:
 };

bool Win_WindowManager::isDisplayOpenImpl() const
{
    return true;
}

bool Win_WindowManager::openDisplayImpl(QString *)
{
    return true;
}

// Enumerate window looking for toplevel of process id
struct FindProcessWindowEnumContext {
    FindProcessWindowEnumContext(DWORD pid) : window(0),processId(pid) {}

    HWND window;
    DWORD processId;
};

/* Check for the active main window of the Application
 * of class QWidget. */
static inline bool isQtMainWindow(HWND hwnd)
{
    static char buffer[MAX_PATH];
    if (!GetClassNameA(hwnd, buffer, MAX_PATH) || qstrcmp(buffer, "QWidget"))
        return false;
    WINDOWINFO windowInfo;
    if (!GetWindowInfo(hwnd, &windowInfo))
        return false;
    if (!(windowInfo.dwWindowStatus & WS_ACTIVECAPTION))
        return false;
    // Check the style for a real mainwindow
    const DWORD excluded = WS_DISABLED | WS_POPUP;
    const DWORD required = WS_CAPTION | WS_SYSMENU | WS_VISIBLE;
    return (windowInfo.dwStyle & excluded) == 0
            && (windowInfo.dwStyle & required) == required;
}

static BOOL CALLBACK findProcessWindowEnumWindowProc(HWND hwnd, LPARAM lParam)
{
    DWORD processId = 0;
    FindProcessWindowEnumContext *context= reinterpret_cast<FindProcessWindowEnumContext *>(lParam);
    GetWindowThreadProcessId(hwnd, &processId);
    if (context->processId == processId && isQtMainWindow(hwnd)) {
        context->window = hwnd;
        return FALSE;
    }
    return TRUE;
}

QString Win_WindowManager::waitForTopLevelWindowImpl(unsigned /* count */, Q_PID pid, int timeOutMS, QString *errorMessage)
{
    QTime elapsed;
    elapsed.start();
    // First, wait until the application is up
    if (WaitForInputIdle(pid->hProcess, timeOutMS) != 0) {
        *errorMessage = QString::fromLatin1("WaitForInputIdle time out after %1ms").arg(timeOutMS);
        return QString();
    }
    // Try to locate top level app window. App still might be in splash screen or initialization
    const int remainingMilliSeconds = qMax(timeOutMS - elapsed.elapsed(), 500);
    const int attempts = 10;
    const int intervalMilliSeconds = remainingMilliSeconds / attempts;
    for (int a = 0; a < attempts; a++) {
        FindProcessWindowEnumContext context(pid->dwProcessId);
        EnumWindows(findProcessWindowEnumWindowProc, reinterpret_cast<LPARAM>(&context));
        if (context.window)
            return QLatin1String("0x") + QString::number(reinterpret_cast<quintptr>(context.window), 16);
        sleepMS(intervalMilliSeconds);
    }
    *errorMessage = QString::fromLatin1("Unable to find toplevel of process %1 after %2ms.").arg(pid->dwProcessId).arg(timeOutMS);
    return QString();
}

bool Win_WindowManager::sendCloseEventImpl(const QString &winId, Q_PID, QString *errorMessage)
{
    // Convert window back.
    quintptr winIdIntPtr;
    QTextStream str(const_cast<QString*>(&winId), QIODevice::ReadOnly);
    str.setIntegerBase(16);
    str >> winIdIntPtr;
    if (str.status() != QTextStream::Ok) {
        *errorMessage = QString::fromLatin1("Invalid win id %1.").arg(winId);
        return false;
    }
    if (!PostMessage(reinterpret_cast<HWND>(winIdIntPtr), WM_CLOSE, 0, 0)) {
        *errorMessage = QString::fromLatin1("Cannot send event to 0x%1: %2").arg(winIdIntPtr, 0, 16).arg(winErrorMessage(GetLastError()));
        return false;
    }
    return true;
}
#endif

WindowManager::WindowManager()
{
}

WindowManager::~WindowManager()
{
}

QSharedPointer<WindowManager> WindowManager::create()
{
#ifdef Q_WS_X11
    return QSharedPointer<WindowManager>(new X11_WindowManager);
#endif
#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
    return QSharedPointer<WindowManager>(new Win_WindowManager);
#else
    return QSharedPointer<WindowManager>(new WindowManager);
#endif
}

static inline QString msgNoDisplayOpen() { return QLatin1String("No display opened."); }

bool WindowManager::openDisplay(QString *errorMessage)
{
    if (isDisplayOpen())
        return true;
    return openDisplayImpl(errorMessage);
}

bool WindowManager::isDisplayOpen() const
{
    return isDisplayOpenImpl();
}

QString WindowManager::waitForTopLevelWindow(unsigned count, Q_PID pid, int timeOutMS, QString *errorMessage)
{
    if (!isDisplayOpen()) {
        *errorMessage = msgNoDisplayOpen();
        return QString();
    }
    return waitForTopLevelWindowImpl(count, pid, timeOutMS, errorMessage);
}

bool WindowManager::sendCloseEvent(const QString &winId, Q_PID pid, QString *errorMessage)
{
    if (!isDisplayOpen()) {
        *errorMessage = msgNoDisplayOpen();
        return false;
    }
    return sendCloseEventImpl(winId, pid, errorMessage);
}

// Default Implementation
bool WindowManager::openDisplayImpl(QString *errorMessage)
{
    *errorMessage = QLatin1String("Not implemented.");
    return false;
}

bool WindowManager::isDisplayOpenImpl() const
{
    return false;
}

QString WindowManager::waitForTopLevelWindowImpl(unsigned, Q_PID, int, QString *errorMessage)
{
    *errorMessage = QLatin1String("Not implemented.");
    return QString();
}

bool WindowManager::sendCloseEventImpl(const QString &, Q_PID, QString *errorMessage)
{
    *errorMessage = QLatin1String("Not implemented.");
    return false;
}

void WindowManager::sleepMS(int milliSeconds)
{
    FriendlySleepyThread::sleepMS(milliSeconds);
}


value SerialRecursiveFib(int n) {
    value result;
    if (n < 2)
        result = n;
    else
        result = SerialRecursiveFib(n - 1) + SerialRecursiveFib(n - 2);
    return result;
}

/*

*/

/* Example program that computes Fibonacci numbers in different ways.
   Arguments are: [ Number [Threads [Repeats]]]
   The defaults are Number=500 Threads=1:4 Repeats=1.

   The point of this program is to check that the library is working properly.
   Most of the computations are deliberately silly and not expected to
   show any speedup on multiprocessors.
*/

// enable assertions
#ifdef NDEBUG
#undef NDEBUG
#endif

#include <cstdio>
#include <cstdlib>
#include <cassert>

#include <utility>
#include <thread>
#include <atomic>
#include <mutex>

#include "oneapi/tbb/tick_count.h"
#include "oneapi/tbb/blocked_range.h"
#include "oneapi/tbb/concurrent_vector.h"
#include "oneapi/tbb/concurrent_queue.h"
#include "oneapi/tbb/concurrent_hash_map.h"
#include "oneapi/tbb/parallel_for.h"
#include "oneapi/tbb/parallel_reduce.h"
#include "oneapi/tbb/parallel_scan.h"
#include "oneapi/tbb/parallel_pipeline.h"
#include "oneapi/tbb/spin_mutex.h"
#include "oneapi/tbb/queuing_mutex.h"
#include "oneapi/tbb/global_control.h"

//! type used for Fibonacci number computations
typedef long long value;

struct Matrix2x2 {
    //! Array of values
    value v[2][2];
    Matrix2x2() {}
    Matrix2x2(value v00, value v01, value v10, value v11) {
        v[0][0] = v00;
        v[0][1] = v01;
        v[1][0] = v10;
        v[1][1] = v11;
    }
    Matrix2x2 operator*(const Matrix2x2 &to) const; //< Multiply two Matrices
};
//! Identity matrix
static const Matrix2x2 MatrixIdentity(1, 0, 0, 1);
//! Default matrix to multiply
static const Matrix2x2 Matrix1110(1, 1, 1, 0);
//! Raw arrays matrices multiply
void Matrix2x2Multiply(const value a[2][2], const value b[2][2], value c[2][2]);

//! Plain serial sum
value SerialFib(int n) {
    if (n < 2)
        return n;
    value a = 0, b = 1, sum;
    int i;
    for (i = 2; i <= n; i++) { // n is really index of Fibonacci number
        sum = a + b;
        a = b;
        b = sum;
    }
    return sum;
}
//! Serial n-1 matrices multiplication
value SerialMatrixFib(int n) {
    value c[2][2], a[2][2] = { { 1, 1 }, { 1, 0 } }, b[2][2] = { { 1, 1 }, { 1, 0 } };
    int i;
    for (i = 2; i < n; i++) { // Using condition to prevent copying of values
        if (i & 1)
            Matrix2x2Multiply(a, c, b);
        else
            Matrix2x2Multiply(a, b, c);
    }
    return (i & 1) ? c[0][0] : b[0][0]; // get result from upper left cell
}
//! Recursive summing. Just for complete list of serial algorithms, not used

// GCC 4.8 C++ standard library implements std::this_thread::yield as no-op.
#if __TBB_GLIBCXX_THIS_THREAD_YIELD_BROKEN
static inline void yield() {
    sched_yield();
}
#else
using std::this_thread::yield;
#endif

//! Introducing of queue method in serial
value SerialQueueFib(int n) {
    oneapi::tbb::concurrent_queue<Matrix2x2> Q;
    for (int i = 1; i < n; i++)
        Q.push(Matrix1110);
    Matrix2x2 A, B;
    while (true) {
        while (!Q.try_pop(A))
            yield();
        if (Q.empty())
            break;
        while (!Q.try_pop(B))
            yield();
        Q.push(A * B);
    }
    return A.v[0][0];
}
//! Trying to use concurrent_vector
value SerialVectorFib(int n) {
    oneapi::tbb::concurrent_vector<value> A;
    A.grow_by(2);
    A[0] = 0;
    A[1] = 1;
    for (int i = 2; i <= n; i++) {
        A.grow_to_at_least(i + 1);
        A[i] = A[i - 1] + A[i - 2];
    }
    return A[n];
}

// *** Serial shared by mutexes *** //

//! Shared glabals
value SharedA = 0, SharedB = 1;
int SharedI = 1, SharedN;

//! Template task class which computes Fibonacci numbers with shared globals
template <typename M>
class SharedSerialFibBody {
    M &mutex;

public:
    SharedSerialFibBody(M &m) : mutex(m) {}
    //! main loop
    void operator()(const oneapi::tbb::blocked_range<int> &range) const {
        for (;;) {
            typename M::scoped_lock lock(mutex);
            if (SharedI >= SharedN)
                break;
            value sum = SharedA + SharedB;
            SharedA = SharedB;
            SharedB = sum;
            ++SharedI;
        }
    }
};

template <>
void SharedSerialFibBody<std::mutex>::operator()(
    const oneapi::tbb::blocked_range<int> &range) const {
    for (;;) {
        std::lock_guard<std::mutex> lock(mutex);
        if (SharedI >= SharedN)
            break;
        value sum = SharedA + SharedB;
        SharedA = SharedB;
        SharedB = sum;
        ++SharedI;
    }
}

//! Root function
template <class M>
value SharedSerialFib(int n) {
    SharedA = 0;
    SharedB = 1;
    SharedI = 1;
    SharedN = n;
    M mutex;
    parallel_for(oneapi::tbb::blocked_range<int>(0, 4, 1), SharedSerialFibBody<M>(mutex));
    return SharedB;
}

// *** Serial shared by concurrent hash map *** //

//! Hash comparer
struct IntHashCompare {
    bool equal(const int j, const int k) const {
        return j == k;
    }
    std::size_t hash(const int k) const {
        return (std::size_t)k;
    }
};
//! NumbersTable type based on concurrent_hash_map
typedef oneapi::tbb::concurrent_hash_map<int, value, IntHashCompare> NumbersTable;
//! task for serial method using shared concurrent_hash_map
class ConcurrentHashSerialFibTask {
    NumbersTable &Fib;
    int my_n;

public:
    ConcurrentHashSerialFibTask(NumbersTable &cht, int n) : Fib(cht), my_n(n) {}
    //! executing task
    void operator()() const {
        for (int i = 2; i <= my_n; ++i) { // there is no difference in to recycle or to make loop
            NumbersTable::const_accessor f1, f2; // same as iterators
            if (!Fib.find(f1, i - 1) || !Fib.find(f2, i - 2)) {
                // Something is seriously wrong, because i-1 and i-2 must have been inserted
                // earlier by this thread or another thread.
                assert(0);
            }
            value sum = f1->second + f2->second;
            NumbersTable::const_accessor fsum;
            Fib.insert(fsum, std::make_pair(i, sum)); // inserting
            assert(fsum->second == sum); // check value
        }
    }
};

//! Root function
value ConcurrentHashSerialFib(int n) {
    NumbersTable Fib;
    bool okay;
    okay = Fib.insert(std::make_pair(0, 0));
    assert(okay); // assign initial values
    okay = Fib.insert(std::make_pair(1, 1));
    assert(okay);

    // task_list list;
    oneapi::tbb::task_group tg;
    // allocate tasks
    tg.run(ConcurrentHashSerialFibTask(Fib, n));
    tg.run(ConcurrentHashSerialFibTask(Fib, n));
    tg.wait();
    NumbersTable::const_accessor fresult;
    okay = Fib.find(fresult, n);
    assert(okay);
    return fresult->second;
}

// *** Queue with parallel_pipeline *** //

typedef oneapi::tbb::concurrent_queue<Matrix2x2> queue_t;
namespace parallel_pipeline_ns {
std::atomic<int> N; //< index of Fibonacci number minus 1
queue_t Queue;
} // namespace parallel_pipeline_ns

//! functor to fills queue
struct InputFunc {
    InputFunc() {}
    queue_t *operator()(oneapi::tbb::flow_control &fc) const {
        using namespace parallel_pipeline_ns;

        int n = --N;
        if (n <= 0) {
            fc.stop();
            return nullptr;
        }
        Queue.push(Matrix1110);
        return &Queue;
    }
};
//! functor to process queue
struct MultiplyFunc {
    MultiplyFunc() {}
    void operator()(queue_t *queue) const {
        Matrix2x2 m1, m2;
        // get two elements
        while (!queue->try_pop(m1))
            yield();
        while (!queue->try_pop(m2))
            yield();
        m1 = m1 * m2; // process them
        queue->push(m1); // and push back
    }
};
//! Root function
value ParallelPipeFib(int n) {
    using namespace parallel_pipeline_ns;

    N = n - 1;
    Queue.push(Matrix1110);

    oneapi::tbb::parallel_pipeline(
        n,
        oneapi::tbb::make_filter<void, queue_t *>(oneapi::tbb::filter_mode::parallel, InputFunc()) &
            oneapi::tbb::make_filter<queue_t *, void>(oneapi::tbb::filter_mode::parallel,
                                                      MultiplyFunc()));

    assert(Queue.unsafe_size() == 1);
    Matrix2x2 M;
    bool result = Queue.try_pop(M); // get last element
    assert(result);
    value res = M.v[0][0]; // get value
    Queue.clear();
    return res;
}

struct parallel_reduceFibBody {
    Matrix2x2 sum;
    int split_flag; //< flag to make one less operation for split bodies
    //! Constructor fills sum with initial matrix
    parallel_reduceFibBody() : sum(Matrix1110), split_flag(0) {}
    parallel_reduceFibBody(parallel_reduceFibBody &other, oneapi::tbb::split)
            : sum(Matrix1110),
              split_flag(1 /*note that it is split*/) {}
    //! Join point
    void join(parallel_reduceFibBody &s) {
        sum = sum * s.sum;
    }
    //! Process multiplications
    void operator()(const oneapi::tbb::blocked_range<int> &r) {
        for (int k = r.begin() + split_flag; k < r.end(); ++k)
            sum = sum * Matrix1110;
        split_flag = 0; // reset flag, because this method can be reused for next range
    }
};
//! Root function
value parallel_reduceFib(int n) {
    parallel_reduceFibBody b;
    oneapi::tbb::parallel_reduce(oneapi::tbb::blocked_range<int>(2, n, 3),
                                 b); // do parallel reduce on range [2, n) for b
    return b.sum.v[0][0];
}

struct parallel_scanFibBody {
    /** Though parallel_scan is usually used to accumulate running sums,
        it can be used to accumulate running products too. */
    Matrix2x2 product;
    /** Pointer to output sequence */
    value *const output;
    //! Constructor sets product to identity matrix
    parallel_scanFibBody(value *output_) : product(MatrixIdentity), output(output_) {}
    parallel_scanFibBody(parallel_scanFibBody &b, oneapi::tbb::split)
            : product(MatrixIdentity),
              output(b.output) {}
    //! Method for merging summary information from a, which was split off from *this, into *this.
    void reverse_join(parallel_scanFibBody &a) {
        // When using non-commutative reduction operation, reverse_join
        // should put argument "a" on the left side of the operation.
        // The reversal from the argument order is why the method is
        product = a.product * product;
    }
    //! Method for assigning final result back to original body.
    void assign(parallel_scanFibBody &b) {
        product = b.product;
    }
    //! Compute matrix running product.
    /** Tag indicates whether is is the final scan over the range, or
        just a helper "prescan" that is computing a partial reduction. */
    template <typename Tag>
    void operator()(const oneapi::tbb::blocked_range<int> &r, Tag tag) {
        for (int k = r.begin(); k < r.end(); ++k) {
            // Code performs an "exclusive" scan, which outputs a value *before* updating the product.
            // For an "inclusive" scan, output the value after the update.
            if (tag.is_final_scan())
                output[k] = product.v[0][1];
            product = product * Matrix1110;
        }
    }
};
//! Root function
value parallel_scanFib(int n) {
    value *output = new value[n];
    parallel_scanFibBody b(output);
    oneapi::tbb::parallel_scan(oneapi::tbb::blocked_range<int>(0, n, 3), b);
    // output[0..n-1] now contains the Fibonacci sequence (modulo integer wrap-around).
    // Check the last two values for correctness.
    assert(n < 2 || output[n - 2] + output[n - 1] == b.product.v[0][1]);
    delete[] output;
    return b.product.v[0][1];
}

//! A closed range of int.
struct IntRange {
    int low;
    int high;
    void set_from_string(const char *s);
    IntRange(int low_, int high_) : low(low_), high(high_) {}
};

void IntRange::set_from_string(const char *s) {
    char *end;
    high = low = strtol(s, &end, 0);
    switch (*end) {
        case ':': high = strtol(end + 1, 0, 0); break;
        case '\0': break;
        default: printf("unexpected character = %c\n", *end);
    }
}

//! Tick count for start
static oneapi::tbb::tick_count t0;

//! Verbose output flag
static bool Verbose = false;

typedef value (*MeasureFunc)(int);
//! Measure ticks count in loop [2..n]
value Measure(const char *name, MeasureFunc func, int n) {
    value result;
    if (Verbose)
        printf("%s", name);
    t0 = oneapi::tbb::tick_count::now();
    for (int number = 2; number <= n; number++)
        result = func(number);
    if (Verbose)
        printf("\t- in %f msec\n", (oneapi::tbb::tick_count::now() - t0).seconds() * 1000);
    return result;
}

//! program entry
int main(int argc, char *argv[]) {
    if (argc > 1)
        Verbose = true;
    int NumbersCount = argc > 1 ? strtol(argv[1], 0, 0) : 500;
    IntRange NThread(1, 4); // Number of threads to use.
    if (argc > 2)
        NThread.set_from_string(argv[2]);
    unsigned long ntrial = argc > 3 ? (unsigned long)strtoul(argv[3], 0, 0) : 1;
    value result, sum;

    if (Verbose)
        printf("Fibonacci numbers example. Generating %d numbers..\n", NumbersCount);

    result = Measure("Serial loop", SerialFib, NumbersCount);
    sum = Measure("Serial matrix", SerialMatrixFib, NumbersCount);
    assert(result == sum);
    sum = Measure("Serial vector", SerialVectorFib, NumbersCount);
    assert(result == sum);
    sum = Measure("Serial queue", SerialQueueFib, NumbersCount);
    assert(result == sum);
    // now in parallel
    for (unsigned long i = 0; i < ntrial; ++i) {
        for (int threads = NThread.low; threads <= NThread.high; threads *= 2) {
            oneapi::tbb::global_control c(oneapi::tbb::global_control::max_allowed_parallelism,
                                          threads);
            if (Verbose)
                printf("\nThreads number is %d\n", threads);

            sum = Measure("Shared serial (mutex)\t", SharedSerialFib<std::mutex>, NumbersCount);
            assert(result == sum);
            sum = Measure("Shared serial (spin_mutex)",
                          SharedSerialFib<oneapi::tbb::spin_mutex>,
                          NumbersCount);
            assert(result == sum);
            sum = Measure("Shared serial (queuing_mutex)",
                          SharedSerialFib<oneapi::tbb::queuing_mutex>,
                          NumbersCount);
            assert(result == sum);
            sum = Measure("Shared serial (Conc.HashTable)", ConcurrentHashSerialFib, NumbersCount);
            assert(result == sum);
            sum = Measure("Parallel pipe/queue\t", ParallelPipeFib, NumbersCount);
            assert(result == sum);
            sum = Measure("Parallel reduce\t\t", parallel_reduceFib, NumbersCount);
            assert(result == sum);
            sum = Measure("Parallel scan\t\t", parallel_scanFib, NumbersCount);
            assert(result == sum);
        }

#ifdef __GNUC__
        if (Verbose)
            printf("Fibonacci number #%d modulo 2^64 is %lld\n\n", NumbersCount, result);
#else
        if (Verbose)
            printf("Fibonacci number #%d modulo 2^64 is %I64d\n\n", NumbersCount, result);
#endif
    }
    if (!Verbose)
        printf("TEST PASSED\n");
    // flush to prevent bufferization on exit
    fflush(stdout);
    return 0;
}

// Utils

void Matrix2x2Multiply(const value a[2][2], const value b[2][2], value c[2][2]) {
    for (int i = 0; i <= 1; i++)
        for (int j = 0; j <= 1; j++)
            c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];
}

Matrix2x2 Matrix2x2::operator*(const Matrix2x2 &to) const {
    Matrix2x2 result;
    Matrix2x2Multiply(v, to.v, result.v);
    return result;
}


switch (*end) {
        case ':': high = strtol(end + 1, 0, 0); break;
        case '\0': break;
        default: printf("unexpected character = %c\n", *end);
    }

/*

*/

/* Example program that computes Fibonacci numbers in different ways.
   Arguments are: [ Number [Threads [Repeats]]]
   The defaults are Number=500 Threads=1:4 Repeats=1.

   The point of this program is to check that the library is working properly.
   Most of the computations are deliberately silly and not expected to
   show any speedup on multiprocessors.
*/

// enable assertions
#ifdef NDEBUG
#undef NDEBUG
#endif

#include <cstdio>
#include <cstdlib>
#include <cassert>

#include <utility>
#include <thread>
#include <atomic>
#include <mutex>

#include "oneapi/tbb/tick_count.h"
#include "oneapi/tbb/blocked_range.h"
#include "oneapi/tbb/concurrent_vector.h"
#include "oneapi/tbb/concurrent_queue.h"
#include "oneapi/tbb/concurrent_hash_map.h"
#include "oneapi/tbb/parallel_for.h"
#include "oneapi/tbb/parallel_reduce.h"
#include "oneapi/tbb/parallel_scan.h"
#include "oneapi/tbb/parallel_pipeline.h"
#include "oneapi/tbb/spin_mutex.h"
#include "oneapi/tbb/queuing_mutex.h"
#include "oneapi/tbb/global_control.h"

//! type used for Fibonacci number computations
typedef long long value;

struct Matrix2x2 {
    //! Array of values
    value v[2][2];
    Matrix2x2() {}
    Matrix2x2(value v00, value v01, value v10, value v11) {
        v[0][0] = v00;
        v[0][1] = v01;
        v[1][0] = v10;
        v[1][1] = v11;
    }
    Matrix2x2 operator*(const Matrix2x2 &to) const; //< Multiply two Matrices
};
//! Identity matrix
static const Matrix2x2 MatrixIdentity(1, 0, 0, 1);
//! Default matrix to multiply
static const Matrix2x2 Matrix1110(1, 1, 1, 0);
//! Raw arrays matrices multiply
void Matrix2x2Multiply(const value a[2][2], const value b[2][2], value c[2][2]);

//! Plain serial sum
value SerialFib(int n) {
    if (n < 2)
        return n;
    value a = 0, b = 1, sum;
    int i;
    for (i = 2; i <= n; i++) { // n is really index of Fibonacci number
        sum = a + b;
        a = b;
        b = sum;
    }
    return sum;
}
//! Serial n-1 matrices multiplication
value SerialMatrixFib(int n) {
    value c[2][2], a[2][2] = { { 1, 1 }, { 1, 0 } }, b[2][2] = { { 1, 1 }, { 1, 0 } };
    int i;
    for (i = 2; i < n; i++) { // Using condition to prevent copying of values
        if (i & 1)
            Matrix2x2Multiply(a, c, b);
        else
            Matrix2x2Multiply(a, b, c);
    }
    return (i & 1) ? c[0][0] : b[0][0]; // get result from upper left cell
}
//! Recursive summing. Just for complete list of serial algorithms, not used
value SerialRecursiveFib(int n) {
    value result;
    if (n < 2)
        result = n;
    else
        result = SerialRecursiveFib(n - 1) + SerialRecursiveFib(n - 2);
    return result;
}

// GCC 4.8 C++ standard library implements std::this_thread::yield as no-op.
#if __TBB_GLIBCXX_THIS_THREAD_YIELD_BROKEN
static inline void yield() {
    sched_yield();
}
#else
using std::this_thread::yield;
#endif

//! Introducing of queue method in serial
value SerialQueueFib(int n) {
    oneapi::tbb::concurrent_queue<Matrix2x2> Q;
    for (int i = 1; i < n; i++)
        Q.push(Matrix1110);
    Matrix2x2 A, B;
    while (true) {
        while (!Q.try_pop(A))
            yield();
        if (Q.empty())
            break;
        while (!Q.try_pop(B))
            yield();
        Q.push(A * B);
    }
    return A.v[0][0];
}
//! Trying to use concurrent_vector
value SerialVectorFib(int n) {
    oneapi::tbb::concurrent_vector<value> A;
    A.grow_by(2);
    A[0] = 0;
    A[1] = 1;
    for (int i = 2; i <= n; i++) {
        A.grow_to_at_least(i + 1);
        A[i] = A[i - 1] + A[i - 2];
    }
    return A[n];
}

// *** Serial shared by mutexes *** //

//! Shared glabals
value SharedA = 0, SharedB = 1;
int SharedI = 1, SharedN;

//! Template task class which computes Fibonacci numbers with shared globals
template <typename M>
class SharedSerialFibBody {
    M &mutex;

public:
    SharedSerialFibBody(M &m) : mutex(m) {}
    //! main loop
    void operator()(const oneapi::tbb::blocked_range<int> &range) const {
        for (;;) {
            typename M::scoped_lock lock(mutex);
            if (SharedI >= SharedN)
                break;
            value sum = SharedA + SharedB;
            SharedA = SharedB;
            SharedB = sum;
            ++SharedI;
        }
    }
};

template <>
void SharedSerialFibBody<std::mutex>::operator()(
    const oneapi::tbb::blocked_range<int> &range) const {
    for (;;) {
        std::lock_guard<std::mutex> lock(mutex);
        if (SharedI >= SharedN)
            break;
        value sum = SharedA + SharedB;
        SharedA = SharedB;
        SharedB = sum;
        ++SharedI;
    }
}

//! Root function
template <class M>
value SharedSerialFib(int n) {
    SharedA = 0;
    SharedB = 1;
    SharedI = 1;
    SharedN = n;
    M mutex;
    parallel_for(oneapi::tbb::blocked_range<int>(0, 4, 1), SharedSerialFibBody<M>(mutex));
    return SharedB;
}

// *** Serial shared by concurrent hash map *** //

//! Hash comparer
struct IntHashCompare {
    bool equal(const int j, const int k) const {
        return j == k;
    }
    std::size_t hash(const int k) const {
        return (std::size_t)k;
    }
};
//! NumbersTable type based on concurrent_hash_map
typedef oneapi::tbb::concurrent_hash_map<int, value, IntHashCompare> NumbersTable;
//! task for serial method using shared concurrent_hash_map
class ConcurrentHashSerialFibTask {
    NumbersTable &Fib;
    int my_n;

public:
    ConcurrentHashSerialFibTask(NumbersTable &cht, int n) : Fib(cht), my_n(n) {}
    //! executing task
    void operator()() const {
        for (int i = 2; i <= my_n; ++i) { // there is no difference in to recycle or to make loop
            NumbersTable::const_accessor f1, f2; // same as iterators
            if (!Fib.find(f1, i - 1) || !Fib.find(f2, i - 2)) {
                // Something is seriously wrong, because i-1 and i-2 must have been inserted
                // earlier by this thread or another thread.
                assert(0);
            }
            value sum = f1->second + f2->second;
            NumbersTable::const_accessor fsum;
            Fib.insert(fsum, std::make_pair(i, sum)); // inserting
            assert(fsum->second == sum); // check value
        }
    }
};

//! Root function
value ConcurrentHashSerialFib(int n) {
    NumbersTable Fib;
    bool okay;
    okay = Fib.insert(std::make_pair(0, 0));
    assert(okay); // assign initial values
    okay = Fib.insert(std::make_pair(1, 1));
    assert(okay);

    // task_list list;
    oneapi::tbb::task_group tg;
    // allocate tasks
    tg.run(ConcurrentHashSerialFibTask(Fib, n));
    tg.run(ConcurrentHashSerialFibTask(Fib, n));
    tg.wait();
    NumbersTable::const_accessor fresult;
    okay = Fib.find(fresult, n);
    assert(okay);
    return fresult->second;
}

// *** Queue with parallel_pipeline *** //

typedef oneapi::tbb::concurrent_queue<Matrix2x2> queue_t;
namespace parallel_pipeline_ns {
std::atomic<int> N; //< index of Fibonacci number minus 1
queue_t Queue;
} // namespace parallel_pipeline_ns

//! functor to fills queue
struct InputFunc {
    InputFunc() {}
    queue_t *operator()(oneapi::tbb::flow_control &fc) const {
        using namespace parallel_pipeline_ns;

        int n = --N;
        if (n <= 0) {
            fc.stop();
            return nullptr;
        }
        Queue.push(Matrix1110);
        return &Queue;
    }
};
//! functor to process queue
struct MultiplyFunc {
    MultiplyFunc() {}
    void operator()(queue_t *queue) const {
        Matrix2x2 m1, m2;
        // get two elements
        while (!queue->try_pop(m1))
            yield();
        while (!queue->try_pop(m2))
            yield();
        m1 = m1 * m2; // process them
        queue->push(m1); // and push back
    }
};
//! Root function
value ParallelPipeFib(int n) {
    using namespace parallel_pipeline_ns;

    N = n - 1;
    Queue.push(Matrix1110);

    oneapi::tbb::parallel_pipeline(
        n,
        oneapi::tbb::make_filter<void, queue_t *>(oneapi::tbb::filter_mode::parallel, InputFunc()) &
            oneapi::tbb::make_filter<queue_t *, void>(oneapi::tbb::filter_mode::parallel,
                                                      MultiplyFunc()));

    assert(Queue.unsafe_size() == 1);
    Matrix2x2 M;
    bool result = Queue.try_pop(M); // get last element
    assert(result);
    value res = M.v[0][0]; // get value
    Queue.clear();
    return res;
}

struct parallel_reduceFibBody {
    Matrix2x2 sum;
    int split_flag; //< flag to make one less operation for split bodies
    //! Constructor fills sum with initial matrix
    parallel_reduceFibBody() : sum(Matrix1110), split_flag(0) {}
    parallel_reduceFibBody(parallel_reduceFibBody &other, oneapi::tbb::split)
            : sum(Matrix1110),
              split_flag(1 /*note that it is split*/) {}
    //! Join point
    void join(parallel_reduceFibBody &s) {
        sum = sum * s.sum;
    }
    //! Process multiplications
    void operator()(const oneapi::tbb::blocked_range<int> &r) {
        for (int k = r.begin() + split_flag; k < r.end(); ++k)
            sum = sum * Matrix1110;
        split_flag = 0; // reset flag, because this method can be reused for next range
    }
};
//! Root function
value parallel_reduceFib(int n) {
    parallel_reduceFibBody b;
    oneapi::tbb::parallel_reduce(oneapi::tbb::blocked_range<int>(2, n, 3),
                                 b); // do parallel reduce on range [2, n) for b
    return b.sum.v[0][0];
}

struct parallel_scanFibBody {
    /** Though parallel_scan is usually used to accumulate running sums,
        it can be used to accumulate running products too. */
    Matrix2x2 product;
    /** Pointer to output sequence */
    value *const output;
    //! Constructor sets product to identity matrix
    parallel_scanFibBody(value *output_) : product(MatrixIdentity), output(output_) {}
    parallel_scanFibBody(parallel_scanFibBody &b, oneapi::tbb::split)
            : product(MatrixIdentity),
              output(b.output) {}
    //! Method for merging summary information from a, which was split off from *this, into *this.
    void reverse_join(parallel_scanFibBody &a) {
        // When using non-commutative reduction operation, reverse_join
        // should put argument "a" on the left side of the operation.
        // The reversal from the argument order is why the method is
        product = a.product * product;
    }
    //! Method for assigning final result back to original body.
    void assign(parallel_scanFibBody &b) {
        product = b.product;
    }
    //! Compute matrix running product.
    /** Tag indicates whether is is the final scan over the range, or
        just a helper "prescan" that is computing a partial reduction. */
    template <typename Tag>
    void operator()(const oneapi::tbb::blocked_range<int> &r, Tag tag) {
        for (int k = r.begin(); k < r.end(); ++k) {
            // Code performs an "exclusive" scan, which outputs a value *before* updating the product.
            // For an "inclusive" scan, output the value after the update.
            if (tag.is_final_scan())
                output[k] = product.v[0][1];
            product = product * Matrix1110;
        }
    }
};
//! Root function
value parallel_scanFib(int n) {
    value *output = new value[n];
    parallel_scanFibBody b(output);
    oneapi::tbb::parallel_scan(oneapi::tbb::blocked_range<int>(0, n, 3), b);
    // output[0..n-1] now contains the Fibonacci sequence (modulo integer wrap-around).
    // Check the last two values for correctness.
    assert(n < 2 || output[n - 2] + output[n - 1] == b.product.v[0][1]);
    delete[] output;
    return b.product.v[0][1];
}

//! A closed range of int.
struct IntRange {
    int low;
    int high;
    void set_from_string(const char *s);
    IntRange(int low_, int high_) : low(low_), high(high_) {}
};

void IntRange::set_from_string(const char *s) {
    char *end;
    high = low = strtol(s, &end, 0);

}

//! Tick count for start
static oneapi::tbb::tick_count t0;

//! Verbose output flag
static bool Verbose = false;

typedef value (*MeasureFunc)(int);
//! Measure ticks count in loop [2..n]
value Measure(const char *name, MeasureFunc func, int n) {
    value result;
    if (Verbose)
        printf("%s", name);
    t0 = oneapi::tbb::tick_count::now();
    for (int number = 2; number <= n; number++)
        result = func(number);
    if (Verbose)
        printf("\t- in %f msec\n", (oneapi::tbb::tick_count::now() - t0).seconds() * 1000);
    return result;
}

//! program entry
int main(int argc, char *argv[]) {
    if (argc > 1)
        Verbose = true;
    int NumbersCount = argc > 1 ? strtol(argv[1], 0, 0) : 500;
    IntRange NThread(1, 4); // Number of threads to use.
    if (argc > 2)
        NThread.set_from_string(argv[2]);
    unsigned long ntrial = argc > 3 ? (unsigned long)strtoul(argv[3], 0, 0) : 1;
    value result, sum;

    if (Verbose)
        printf("Fibonacci numbers example. Generating %d numbers..\n", NumbersCount);

    result = Measure("Serial loop", SerialFib, NumbersCount);
    sum = Measure("Serial matrix", SerialMatrixFib, NumbersCount);
    assert(result == sum);
    sum = Measure("Serial vector", SerialVectorFib, NumbersCount);
    assert(result == sum);
    sum = Measure("Serial queue", SerialQueueFib, NumbersCount);
    assert(result == sum);
    // now in parallel
    for (unsigned long i = 0; i < ntrial; ++i) {
        for (int threads = NThread.low; threads <= NThread.high; threads *= 2) {
            oneapi::tbb::global_control c(oneapi::tbb::global_control::max_allowed_parallelism,
                                          threads);
            if (Verbose)
                printf("\nThreads number is %d\n", threads);

            sum = Measure("Shared serial (mutex)\t", SharedSerialFib<std::mutex>, NumbersCount);
            assert(result == sum);
            sum = Measure("Shared serial (spin_mutex)",
                          SharedSerialFib<oneapi::tbb::spin_mutex>,
                          NumbersCount);
            assert(result == sum);
            sum = Measure("Shared serial (queuing_mutex)",
                          SharedSerialFib<oneapi::tbb::queuing_mutex>,
                          NumbersCount);
            assert(result == sum);
            sum = Measure("Shared serial (Conc.HashTable)", ConcurrentHashSerialFib, NumbersCount);
            assert(result == sum);
            sum = Measure("Parallel pipe/queue\t", ParallelPipeFib, NumbersCount);
            assert(result == sum);
            sum = Measure("Parallel reduce\t\t", parallel_reduceFib, NumbersCount);
            assert(result == sum);
            sum = Measure("Parallel scan\t\t", parallel_scanFib, NumbersCount);
            assert(result == sum);
        }

#ifdef __GNUC__
        if (Verbose)
            printf("Fibonacci number #%d modulo 2^64 is %lld\n\n", NumbersCount, result);
#else
        if (Verbose)
            printf("Fibonacci number #%d modulo 2^64 is %I64d\n\n", NumbersCount, result);
#endif
    }
    if (!Verbose)
        printf("TEST PASSED\n");
    // flush to prevent bufferization on exit
    fflush(stdout);
    return 0;
}

// Utils

void Matrix2x2Multiply(const value a[2][2], const value b[2][2], value c[2][2]) {
    for (int i = 0; i <= 1; i++)
        for (int j = 0; j <= 1; j++)
            c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];
}

Matrix2x2 Matrix2x2::operator*(const Matrix2x2 &to) const {
    Matrix2x2 result;
    Matrix2x2Multiply(v, to.v, result.v);
    return result;
}


constexpr
bool isShorter(const string &s1, const string &s2)
{
	return s1.size() < s2.size();
}

/*
 * 练习6.46：能把isShorter函数定义成constexpr函数吗？如果能，将他改写成constexpr函数；
 * 如果不能，说明原因。
 */

// 不能，G++报错：error: call to non-constexpr function，因为其参数非字面值类型。
// 关于此问题的一个讨论：http://example.com

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::cin;
using std::string;

// 比较两个string对象的长度

int main()
{
	cout << isShorter("Hello", "Hi") << endl;

	return 0;
}


BaseDemo* Create_App_KdTreeView() { return new App_KdTreeView; }

/**************************************************************************************/
/*                                                                                */
/*  Visualization Library                                                             */
/*  http://visualizationlibrary.org                                                   */
/*                                                                                */
/*  All rights reserved.                                                              */
/*                                                                                */
/*                                                                                */
/**************************************************************************************/

#include "BaseDemo.hpp"
#include <vlCore/Colors.hpp>
#include <vlGraphics/GeometryPrimitives.hpp>
#include <vlGraphics/Light.hpp>
#include <vlGraphics/Text.hpp>
#include <vlGraphics/FontManager.hpp>
#include <vlGraphics/SceneManagerActorKdTree.hpp>
#include <vlGraphics/SceneManagerActorTree.hpp>

class App_KdTreeView: public BaseDemo
{
public:
  virtual void initEvent()
  {
    vl::Log::notify(appletInfo());

    mSceneKdTree = new vl::SceneManagerActorKdTree;
    rendering()->as<vl::Rendering>()->sceneManagers()->push_back(mSceneKdTree.get());

    mText = new vl::Text;
    mText->setFont( vl::defFontManager()->acquireFont("/font/bitstream-vera/VeraMono.ttf", 10, false) );
    mText->setAlignment(vl::AlignHCenter | vl::AlignTop);
    mText->setViewportAlignment(vl::AlignHCenter | vl::AlignTop);
    mText->setColor(vl::white);
    mText->translate(0,-10,0);
    mTextActor = sceneManager()->tree()->addActor(mText.get(), new vl::Effect);
    mTextActor->effect()->shader()->enable(vl::EN_BLEND);

    mTestNumber = 0;
    mViewDepth  = -1;

    createScene();
    mText->setText( mText->text() + "\nPress left/right to change the test number\nPress up/down to change the visible tree level");
  }

  void createScene()
  {
    vl::ActorCollection actors;

    vl::ref<vl::Effect> effect = new vl::Effect;
    effect->shader()->enable(vl::EN_DEPTH_TEST);
    effect->shader()->enable(vl::EN_LIGHTING);
    effect->shader()->setRenderState( new vl::Light, 0 );

    vl::ref<vl::Geometry> ball = vl::makeUVSphere(vl::vec3(0,0,0),1,20,20);
    ball->computeNormals();

    vl::ref<vl::Geometry> pyramid = vl::makePyramid(vl::vec3(0,0,0),2,2);
    pyramid->computeNormals();

    switch(mTestNumber)
    {
      case 0:
      {
        for(int i=-3; i<+3; ++i)
        {
          vl::ref<vl::Actor> actor = new vl::Actor(ball.get(),effect.get(),new vl::Transform);
          actors.push_back(actor.get());
          vl::mat4 mat = vl::mat4::getTranslation(i*2.0f,0,0);
          actor->transform()->setLocalMatrix(mat);
          actor->transform()->computeWorldMatrix();
        }
        break;
      }
      case 1:
      {
        for(int i=-3; i<+3; ++i)
        {
          vl::ref<vl::Actor> actor = new vl::Actor(ball.get(),effect.get(),new vl::Transform);
          actors.push_back(actor.get());
          vl::mat4 mat = vl::mat4::getTranslation(0,i*2.0f,0);
          actor->transform()->setLocalMatrix(mat);
          actor->transform()->computeWorldMatrix();
        }
        break;
      }
      case 2:
      {
        for(int i=-3; i<+3; ++i)
        {
          vl::ref<vl::Actor> actor = new vl::Actor(ball.get(),effect.get(),new vl::Transform);
          actors.push_back(actor.get());
          vl::mat4 mat = vl::mat4::getTranslation(0,0,i*2.0f);
          actor->transform()->setLocalMatrix(mat);
          actor->transform()->computeWorldMatrix();
        }
        break;
      }
      case 3:
      {
        for(int x=-4; x<+4; ++x)
        {
          for(int y=-4; y<+4; ++y)
          {
            vl::ref<vl::Actor> actor = new vl::Actor(pyramid.get(),effect.get(),new vl::Transform);
            actors.push_back(actor.get());
            vl::mat4 mat = vl::mat4::getTranslation(x*2.0f,0,y*2.0f);
            actor->transform()->setLocalMatrix(mat);
            actor->transform()->computeWorldMatrix();
          }
        }
        break;
      }
      case 4:
      {
        for(int x=-4; x<+4; ++x)
        {
          for(int y=-4; y<+4; ++y)
          {
            vl::ref<vl::Actor> actor = new vl::Actor(pyramid.get(),effect.get(),new vl::Transform);
            actors.push_back(actor.get());
            vl::mat4 mat = vl::mat4::getTranslation(x*2.0f,y*2.0f,0);
            actor->transform()->setLocalMatrix(mat);
            actor->transform()->computeWorldMatrix();
          }
        }
        break;
      }
      case 5:
      {
        for(int x=-4; x<+4; ++x)
        {
          for(int y=-4; y<+4; ++y)
          {
            vl::ref<vl::Actor> actor = new vl::Actor(pyramid.get(),effect.get(),new vl::Transform);
            actors.push_back(actor.get());
            vl::mat4 mat = vl::mat4::getTranslation(0,x*2.0f,y*2.0f);
            actor->transform()->setLocalMatrix(mat);
            actor->transform()->computeWorldMatrix();
          }
        }
        break;
      }
      case 6:
      {
        for(int i=0; i<10; ++i)
        {
          vl::ref<vl::Actor> actor = new vl::Actor(pyramid.get(),effect.get(),new vl::Transform);
          actors.push_back(actor.get());
          vl::mat4 mat = vl::mat4::getTranslation(rand()%8-4.0f, rand()%8-4.0f, rand()%8-4.0f);
          actor->transform()->setLocalMatrix(mat);
          actor->transform()->computeWorldMatrix();
        }
        break;
      }
    }

    /* compile ActorKdTree */
    mSceneKdTree->tree()->buildKdTree(actors);

    updateKdTreeView();
  }

  void updateKdTreeView()
  {
    /* regenerate scene manager containing the text and the boxes representing the ActorKdTree nodes */
    sceneManager()->tree()->actors()->clear();

    sceneManager()->tree()->addActor( mTextActor.get() );
    mText->setText( vl::Say("Test #%n, Level #%n") << mTestNumber << mViewDepth );

    viewTreeNodes(mSceneKdTree->tree(),0);
  }

  void viewTreeNodes(vl::ActorTreeAbstract* tree, int level)
  {
    if (tree && !tree->aabb().isNull())
    {
      if (level == mViewDepth || mViewDepth == -1)
      {
        vl::ref<vl::Effect> effect = new vl::Effect;
        effect->shader()->gocPolygonMode()->set(vl::PM_LINE, vl::PM_LINE);
        effect->shader()->enable(vl::EN_DEPTH_TEST);
        effect->shader()->gocColor()->setValue(vl::gold);
        vl::ref<vl::Geometry> box = vl::makeBox(tree->aabb());
        sceneManager()->tree()->addActor(box.get(), effect.get());

        if (mViewDepth != -1)
          return;
      }

      for(int i=0; i<tree->childrenCount(); ++i)
        viewTreeNodes(tree->child(i), level+1);
    }
  }

  void keyPressEvent(unsigned short ch, vl::EKey key)
  {
    BaseDemo::keyPressEvent(ch,key);
    switch(key)
    {
      case vl::Key_Up:    mViewDepth--;  break;
      case vl::Key_Down:  mViewDepth++;  break;
      case vl::Key_Left:  mTestNumber--; break;
      case vl::Key_Right: mTestNumber++; break;
      default:
        break;
    }

    mViewDepth  = vl::clamp(mViewDepth,-1,10);
    mTestNumber = vl::clamp(mTestNumber,0,10);
    switch(key)
    {
      case vl::Key_Up:    updateKdTreeView(); break;
      case vl::Key_Down:  updateKdTreeView(); break;
      case vl::Key_Left:  createScene();      break;
      case vl::Key_Right: createScene();      break;
      default:
        break;
    }
  }

protected:
  vl::ref<vl::SceneManagerActorKdTree> mSceneKdTree;
  vl::ref<vl::Text> mText;
  vl::ref<vl::Actor> mTextActor;
  int mTestNumber;
  int mViewDepth;
};

// Have fun!