//
// Copyright (C) 2015-2019 Yahoo Japan Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#pragma once

#include	<string>
#include	<vector>
#include	<map>
#include	<set>
#include	<bitset>
#include	<iomanip>
#include	<unordered_set>

#include	<sys/time.h>
#include	<sys/stat.h>
#include	<stdint.h>

#include	"NGT/defines.h"
#include	"NGT/Common.h"
#include	"NGT/Tree.h"
#include	"NGT/Thread.h"
#include	"NGT/Graph.h"

namespace NGT {

  class Property;

  class Index {
  public:

    class Property {
    public:
      typedef ObjectSpace::ObjectType		ObjectType;
      typedef ObjectSpace::DistanceType		DistanceType;
      typedef NeighborhoodGraph::SeedType	SeedType;
      typedef NeighborhoodGraph::GraphType	GraphType;
      enum ObjectAlignment {
	ObjectAlignmentNone	= 0,
	ObjectAlignmentTrue	= 1,
	ObjectAlignmentFalse	= 2
      };
      enum IndexType {
	IndexTypeNone		= 0,
	GraphAndTree		= 1,
	Graph			= 2
      };
      enum DatabaseType {
	DatabaseTypeNone	= 0,
	Memory			= 1,
	MemoryMappedFile	= 2
      };
      Property() { setDefault(); }
      void setDefault() {
	dimension 	= 0;
	threadPoolSize	= 32;
	objectType	= ObjectSpace::ObjectType::Float;
	distanceType	= DistanceType::DistanceTypeL2;
	indexType	= IndexType::GraphAndTree;
	objectAlignment	= ObjectAlignment::ObjectAlignmentFalse;
	pathAdjustmentInterval = 0;
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
	databaseType	= DatabaseType::MemoryMappedFile;
      	graphSharedMemorySize	= 512; // MB
      	treeSharedMemorySize	= 512; // MB
      	objectSharedMemorySize	= 512; // MB  512 is up to 20M objects.
#else
	databaseType	= DatabaseType::Memory;
#endif
      }
      void clear() {
	dimension 	= -1;
	threadPoolSize	= -1;
	objectType	= ObjectSpace::ObjectTypeNone;
	distanceType	= DistanceType::DistanceTypeNone;
	indexType	= IndexTypeNone;
	databaseType	= DatabaseTypeNone;
	objectAlignment	= ObjectAlignment::ObjectAlignmentNone;
	pathAdjustmentInterval	= -1;
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
      	graphSharedMemorySize	= -1;
      	treeSharedMemorySize	= -1;
      	objectSharedMemorySize	= -1;
#endif
      }

      void exportProperty(NGT::PropertySet &p) {
	p.set("Dimension", dimension);
	p.set("ThreadPoolSize", threadPoolSize);
	switch (objectType) {
	case ObjectSpace::ObjectType::Uint8: p.set("ObjectType", "Integer-1"); break;
	case ObjectSpace::ObjectType::Float: p.set("ObjectType", "Float-4"); break;
	default : cerr << "Fatal error. Invalid object type. " << objectType <<endl; abort();
	}
	switch (distanceType) {
	case DistanceType::DistanceTypeNone:			p.set("DistanceType", "None"); break;
	case DistanceType::DistanceTypeL1:			p.set("DistanceType", "L1"); break;
	case DistanceType::DistanceTypeL2:			p.set("DistanceType", "L2"); break;
	case DistanceType::DistanceTypeHamming:			p.set("DistanceType", "Hamming"); break;
	case DistanceType::DistanceTypeJaccard:			p.set("DistanceType", "Jaccard"); break;
	case DistanceType::DistanceTypeAngle:			p.set("DistanceType", "Angle"); break;
	case DistanceType::DistanceTypeCosine:			p.set("DistanceType", "Cosine"); break;
	case DistanceType::DistanceTypeNormalizedAngle:		p.set("DistanceType", "NormalizedAngle"); break;
	case DistanceType::DistanceTypeNormalizedCosine:	p.set("DistanceType", "NormalizedCosine"); break;
	default : cerr << "Fatal error. Invalid distance type. " << distanceType << endl; abort();
	}
	switch (indexType) {
	case IndexType::GraphAndTree:	p.set("IndexType", "GraphAndTree"); break;
	case IndexType::Graph:		p.set("IndexType", "Graph"); break;
	default : cerr << "Fatal error. Invalid index type. " << indexType << endl; abort();
	}
	switch (databaseType) {
	case DatabaseType::Memory:		p.set("DatabaseType", "Memory"); break;
	case DatabaseType::MemoryMappedFile:	p.set("DatabaseType", "MemoryMappedFile"); break;
	default : cerr << "Fatal error. Invalid database type. " << databaseType << endl; abort();
	}
	switch (objectAlignment) {
	case ObjectAlignment::ObjectAlignmentNone:	p.set("ObjectAlignment", "None"); break;
	case ObjectAlignment::ObjectAlignmentTrue:	p.set("ObjectAlignment", "True"); break;
	case ObjectAlignment::ObjectAlignmentFalse:	p.set("ObjectAlignment", "False"); break;
	default : cerr << "Fatal error. Invalid objectAlignment. " << objectAlignment << endl; abort();
	}
	p.set("PathAdjustmentInterval", pathAdjustmentInterval);
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
	p.set("GraphSharedMemorySize", graphSharedMemorySize);
	p.set("TreeSharedMemorySize", treeSharedMemorySize);
	p.set("ObjectSharedMemorySize", objectSharedMemorySize);
#endif
      }

      void importProperty(NGT::PropertySet &p) {
	setDefault();
	dimension = p.getl("Dimension", dimension);
	threadPoolSize = p.getl("ThreadPoolSize", threadPoolSize);
	PropertySet::iterator it = p.find("ObjectType");
	if (it != p.end()) {
	  if (it->second == "Float-4") {
	    objectType = ObjectSpace::ObjectType::Float;
	  } else if (it->second == "Integer-1") {
	    objectType = ObjectSpace::ObjectType::Uint8;
	  } else {
	    cerr << "Invalid Object Type in the property. " << it->first << ":" << it->second << endl;
	  }
	} else {
	  cerr << "Not found \"ObjectType\"" << endl;
	}
	it = p.find("DistanceType");
	if (it != p.end()) {
	  if (it->second == "None") {
	    distanceType = DistanceType::DistanceTypeNone;
	  } else if (it->second == "L1") {
	    distanceType = DistanceType::DistanceTypeL1;
	  } else if (it->second == "L2") {
	    distanceType = DistanceType::DistanceTypeL2;
	  } else if (it->second == "Hamming") {
	    distanceType = DistanceType::DistanceTypeHamming;
	  } else if (it->second == "Jaccard") {
	    distanceType = DistanceType::DistanceTypeJaccard;
	  } else if (it->second == "Angle") {
	    distanceType = DistanceType::DistanceTypeAngle;
	  } else if (it->second == "Cosine") {
	    distanceType = DistanceType::DistanceTypeCosine;
	  } else if (it->second == "NormalizedAngle") {
	    distanceType = DistanceType::DistanceTypeNormalizedAngle;
	  } else if (it->second == "NormalizedCosine") {
	    distanceType = DistanceType::DistanceTypeNormalizedCosine;
	  } else {
	    cerr << "Invalid Distance Type in the property. " << it->first << ":" << it->second << endl;
	  }
	} else {
	  cerr << "Not found \"DistanceType\"" << endl;
	}
	it = p.find("IndexType");
	if (it != p.end()) {
	  if (it->second == "GraphAndTree") {
	    indexType = IndexType::GraphAndTree;
	  } else if (it->second == "Graph") {
	    indexType = IndexType::Graph;
	  } else {
	    cerr << "Invalid Index Type in the property. " << it->first << ":" << it->second << endl;
	  }
	} else {
	  cerr << "Not found \"IndexType\"" << endl;
	}
	it = p.find("DatabaseType");
	if (it != p.end()) {
	  if (it->second == "Memory") {
	    databaseType = DatabaseType::Memory;
	  } else if (it->second == "MemoryMappedFile") {
	    databaseType = DatabaseType::MemoryMappedFile;
	  } else {
	    cerr << "Invalid Database Type in the property. " << it->first << ":" << it->second << endl;
	  }
	} else {
	  cerr << "Not found \"DatabaseType\"" << endl;
	}
	it = p.find("ObjectAlignment");
	if (it != p.end()) {
	  if (it->second == "None") {
	    objectAlignment = ObjectAlignment::ObjectAlignmentNone;
	  } else if (it->second == "True") {
	    objectAlignment = ObjectAlignment::ObjectAlignmentTrue;
	  } else if (it->second == "False") {
	    objectAlignment = ObjectAlignment::ObjectAlignmentFalse;
	  } else {
	    cerr << "Invalid Object Alignment in the property. " << it->first << ":" << it->second << endl;
	  }
	} else {
	  cerr << "Not found \"ObjectAlignment\"" << endl;
	  objectAlignment = ObjectAlignment::ObjectAlignmentFalse;
	}
	pathAdjustmentInterval  = p.getl("PathAdjustmentInterval", pathAdjustmentInterval);
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
	graphSharedMemorySize  = p.getl("GraphSharedMemorySize", graphSharedMemorySize);
	treeSharedMemorySize   = p.getl("TreeSharedMemorySize", treeSharedMemorySize);
	objectSharedMemorySize = p.getl("ObjectSharedMemorySize", objectSharedMemorySize);
#endif
      }

      void set(NGT::Property &prop);
      void get(NGT::Property &prop);
      int		dimension;
      int		threadPoolSize;
      ObjectSpace::ObjectType	objectType;
      DistanceType	distanceType;
      IndexType		indexType;
      DatabaseType	databaseType;
      ObjectAlignment	objectAlignment;
      int		pathAdjustmentInterval;
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
      int		graphSharedMemorySize;
      int		treeSharedMemorySize;
      int		objectSharedMemorySize;
#endif
    };

    class InsertionResult {
    public:
      InsertionResult():id(0), identical(false), distance(0.0) {}
      InsertionResult(size_t i, bool tf, Distance d):id(i), identical(tf), distance(d) {}
      size_t	id;
      bool	identical;
      Distance	distance; // the distance between the centroid and the inserted object.
    };

    Index():index(0) {}
    Index(const string &database, bool rdOnly = false):index(0) { open(database, rdOnly); }
    Index(const string &database, NGT::Property &prop):index(0) { open(database, prop);  }
    virtual ~Index() { close(); }

    void open(const string &database, NGT::Property &prop) {
      open(database);
      setProperty(prop);
    }
    void open(const string &database, bool rdOnly = false);

    void close() {
      if (index != 0) {
	delete index;
	index = 0;
      }
      path.clear();
    }
    void save() {
      if (path.empty()) {
	NGTThrowException("NGT::Index::saveIndex: path is empty");
      }
      saveIndex(path);
    }
    static void mkdir(const string &dir) {
      if (::mkdir(dir.c_str(), S_IRWXU | S_IRGRP | S_IXGRP |  S_IROTH | S_IXOTH) != 0) {
	stringstream msg;
	msg << "NGT::Index::mkdir: Cannot make the specified directory. " << dir;
	NGTThrowException(msg);
      }
    }
    static void createGraphAndTree(const string &database, NGT::Property &prop, const string &dataFile, size_t dataSize = 0);
    static void createGraphAndTree(const string &database, NGT::Property &prop) { createGraphAndTree(database, prop, ""); }
    static void createGraph(const string &database, NGT::Property &prop, const string &dataFile, size_t dataSize = 0);
    template<typename T> size_t insert(vector<T> &object);
    template<typename T> size_t append(vector<T> &object);
    static void append(const string &database, const string &dataFile, size_t threadSize, size_t dataSize);
    static void append(const string &database, const float *data, size_t dataSize, size_t threadSize);
    static void remove(const string &database, vector<ObjectID> &objects);
    static void exportIndex(const string &database, const string &file);
    static void importIndex(const string &database, const string &file);
    virtual void load(const string &ifile, size_t dataSize) { getIndex().load(ifile, dataSize); }
    virtual void append(const string &ifile, size_t dataSize) { getIndex().append(ifile, dataSize); }
    virtual void append(const float *data, size_t dataSize) { getIndex().append(data, dataSize); }
    virtual void append(const double *data, size_t dataSize) { getIndex().append(data, dataSize); }
    virtual size_t getObjectRepositorySize() { return getIndex().getObjectRepositorySize(); }
    virtual void createIndex(size_t threadNumber) { getIndex().createIndex(threadNumber); }
    virtual void saveIndex(const string &ofile) { getIndex().saveIndex(ofile); }
    virtual void loadIndex(const string &ofile) { getIndex().loadIndex(ofile); }
    virtual Object *allocateObject(const string &textLine, const string &sep) { return getIndex().allocateObject(textLine, sep); }
    virtual Object *allocateObject(const vector<double> &obj) { return getIndex().allocateObject(obj); }
    virtual Object *allocateObject(const vector<float> &obj) { return getIndex().allocateObject(obj); }
    virtual Object *allocateObject(const float *obj, size_t size) { return getIndex().allocateObject(obj, size); }
    virtual size_t getSizeOfElement() { return getIndex().getSizeOfElement(); }
    virtual void setProperty(NGT::Property &prop) { getIndex().setProperty(prop); }
    virtual void getProperty(NGT::Property &prop) { getIndex().getProperty(prop); }
    virtual void deleteObject(Object *po) { getIndex().deleteObject(po); }
    virtual void linearSearch(NGT::SearchContainer &sc) { getIndex().linearSearch(sc); }
    virtual void search(NGT::SearchContainer &sc) { getIndex().search(sc); }
    virtual void search(NGT::SearchContainer &sc, ObjectDistances &seeds) { getIndex().search(sc, seeds); }
    virtual void remove(ObjectID id) { getIndex().remove(id); }
    virtual void exportIndex(const string &file) { getIndex().exportIndex(file); }
    virtual void importIndex(const string &file) { getIndex().importIndex(file); }
    virtual void verify() { getIndex().verify(); }
    virtual ObjectSpace &getObjectSpace() { return getIndex().getObjectSpace(); }
    virtual size_t getSharedMemorySize(ostream &os, SharedMemoryAllocator::GetMemorySizeType t = SharedMemoryAllocator::GetTotalMemorySize) {
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
      size_t osize = getObjectSpace().getRepository().getAllocator().getMemorySize(t);
#else
      size_t osize = 0;
#endif
      os << "object=" << osize << endl;
      size_t isize = getIndex().getSharedMemorySize(os, t);
      return osize + isize;
    }
    void searchUsingOnlyGraph(NGT::SearchContainer &sc) {
      sc.distanceComputationCount = 0;
      ObjectDistances seeds;
      getIndex().search(sc, seeds);
    }
    Index &getIndex() {
      if (index == 0) {
	assert(index != 0);
	NGTThrowException("NGT::Index::getIndex: Index is unavailable.");
      }
      return *index;
    }

    static void destroy(const string &path) {
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
      std::remove(string(path + "/grp").c_str());
      std::remove(string(path + "/grpc").c_str());
      std::remove(string(path + "/trei").c_str());
      std::remove(string(path + "/treic").c_str());
      std::remove(string(path + "/trel").c_str());
      std::remove(string(path + "/trelc").c_str());
      std::remove(string(path + "/objpo").c_str());
      std::remove(string(path + "/objpoc").c_str());
#else
      std::remove(string(path + "/grp").c_str());
      std::remove(string(path + "/tre").c_str());
      std::remove(string(path + "/obj").c_str());
#endif
      std::remove(string(path + "/prf").c_str());
      std::remove(path.c_str());
    }

    static void version(ostream &os);
    string getPath(){ return path; }
  protected:
    static void loadAndCreateIndex(Index &index, const string &database, const string &dataFile,
				   size_t threadSize, size_t dataSize);

    Index *index;
    string path;
  };

  class GraphIndex : public Index,
    public NeighborhoodGraph {
  public:

#ifdef NGT_SHARED_MEMORY_ALLOCATOR
    GraphIndex(const string &allocator, bool rdOnly = false);
    GraphIndex(const string &allocator, NGT::Property &prop):readOnly(false) {
      initialize(allocator, prop);
    }
    void initialize(const string &allocator, NGT::Property &prop);
#else // NGT_SHARED_MEMORY_ALLOCATOR
    GraphIndex(const string &database, bool rdOnly = false);
    GraphIndex(NGT::Property &prop):readOnly(false) {
      initialize(prop);
    }

    void initialize(NGT::Property &prop) {
      constructObjectSpace(prop);
      setProperty(prop);
    }

#endif // NGT_SHARED_MEMORY_ALLOCATOR

    virtual ~GraphIndex() {
      destructObjectSpace();
    }
    void constructObjectSpace(NGT::Property &prop);

    void destructObjectSpace() {
      if (objectSpace == 0) {
	return;
      }
      if (property.objectType == NGT::ObjectSpace::ObjectType::Float) {
	ObjectSpaceRepository<float, double> *os = (ObjectSpaceRepository<float, double>*)objectSpace;
#ifndef NGT_SHARED_MEMORY_ALLOCATOR
	os->deleteAll();
#endif
	delete os;
      } else if (property.objectType == NGT::ObjectSpace::ObjectType::Uint8) {
	ObjectSpaceRepository<unsigned char, int> *os = (ObjectSpaceRepository<unsigned char, int>*)objectSpace;
#ifndef NGT_SHARED_MEMORY_ALLOCATOR
	os->deleteAll();
#endif
	delete os;
      } else {
	cerr << "Cannot find Object Type in the property. " << property.objectType << endl;
	return;
      }
      objectSpace = 0;
    }

    virtual void load(const string &ifile, size_t dataSize = 0) {
      if (ifile.empty()) {
	return;
      }
      istream *is;
      ifstream *ifs = 0;
      if (ifile == "-") {
	is = &cin;
      } else {
	ifs = new ifstream;
	ifs->ifstream::open(ifile);
	if (!(*ifs)) {
	  stringstream msg;
	  msg << "Index::load: Cannot open the specified file. " << ifile;
	  NGTThrowException(msg);
	}
	is = ifs;
      }
      try {
	objectSpace->readText(*is, dataSize);
      } catch(Exception &err) {
	if (ifile != "-") {
	  delete ifs;
	}
	throw(err);
      }
      if (ifile != "-") {
	delete ifs;
      }
    }

    virtual void append(const string &ifile, size_t dataSize = 0) {
      ifstream is(ifile.c_str());
      objectSpace->appendText(is, dataSize);
    }

    virtual void append(const float *data, size_t dataSize) { objectSpace->append(data, dataSize); }
    virtual void append(const double *data, size_t dataSize) { objectSpace->append(data, dataSize); }

    virtual void saveIndex(const string &ofile) {
#ifndef NGT_SHARED_MEMORY_ALLOCATOR
      try {
	mkdir(ofile);
      } catch(...) {}
      if (objectSpace != 0) {
	objectSpace->serialize(ofile + "/obj");
      } else {
	cerr << "saveIndex::Warning! ObjectSpace is null. continue saving..." << endl;
      }
      string fname = ofile + "/grp";
      ofstream osg(fname);
      if (!osg.is_open()) {
	stringstream msg;
	msg << "saveIndex:: Cannot open. " << fname;
	NGTThrowException(msg);
      }
      repository.serialize(osg);
#endif
      saveProperty(ofile);
    }

    void saveProperty(const string &file) {
      NGT::PropertySet prop;
      assert(property.dimension != 0);
      GraphIndex::property.exportProperty(prop);
      NeighborhoodGraph::property.exportProperty(prop);
      prop.save(file + "/prf");
    }

    void exportProperty(const string &file) {
      NGT::PropertySet prop;
      assert(property.dimension != 0);
      GraphIndex::property.exportProperty(prop);
      NeighborhoodGraph::property.exportProperty(prop);
      prop.save(file + "/prf");
    }

    virtual void loadIndex(const string &ifile, bool readOnly);

    virtual void exportIndex(const string &ofile) {
      try {
	mkdir(ofile);
      } catch(...) {
	stringstream msg;
	msg << "exportIndex:: Cannot make the directory. " << ofile;
	NGTThrowException(msg);
      }
      objectSpace->serializeAsText(ofile + "/obj");
      ofstream osg(ofile + "/grp");
      repository.serializeAsText(osg);
      exportProperty(ofile);
    }

    virtual void importIndex(const string &ifile) {
      objectSpace->deserializeAsText(ifile + "/obj");
      string fname = ifile + "/grp";
      ifstream isg(fname);
      if (!isg.is_open()) {
	stringstream msg;
	msg << "importIndex:: Cannot open. " << fname;
	NGTThrowException(msg);
      }
      repository.deserializeAsText(isg);
    }

    void linearSearch(NGT::SearchContainer &sc) {
      ObjectSpace::ResultSet results;
      objectSpace->linearSearch(sc.object, sc.radius, sc.size, results);
      ObjectDistances &qresults = sc.getResult();
      qresults.moveFrom(results);
    }

    // GraphIndex
    virtual void search(NGT::SearchContainer &sc) {
      sc.distanceComputationCount = 0;
      ObjectDistances seeds;
      search(sc, seeds);
    }

    // get randomly nodes as seeds.
    template<class REPOSITORY> void getRandomSeeds(REPOSITORY &repo, ObjectDistances &seeds, size_t seedSize) {
      // clear all distances to find the same object as a randomized object.
      for (ObjectDistances::iterator i = seeds.begin(); i != seeds.end(); i++) {
	(*i).distance = 0.0;
      }
      size_t repositorySize = repo.size();
      repositorySize = repositorySize == 0 ? 0 : repositorySize - 1; // Because the head of repository is a dummy.
      seedSize = seedSize > repositorySize ? repositorySize : seedSize;
      vector<ObjectID> deteted;
      while (seedSize > seeds.size()) {
	double random = ((double)rand() + 1.0) / ((double)RAND_MAX + 2.0);
	size_t idx = floor(repositorySize * random) + 1;
	if (repo.isEmpty(idx)) {
	  continue;
	}
	ObjectDistance obj(idx, 0.0);
	if (find(seeds.begin(), seeds.end(), obj) != seeds.end()) {
	  continue;
	}
	seeds.push_back(obj);
      }
    }

    void remove(const ObjectID id) {
      removeEdgesReliably(id);
      try {
	getObjectRepository().remove(id);
      } catch(Exception &err) {
	cerr << "NGT::GraphIndex::remove:: cannot remove from feature. id=" << id << " " << err.what() << endl;
	throw err;
      }
    }

    virtual void searchForNNGInsertion(Object &po, ObjectDistances &result) {
      NGT::SearchContainer sc(po);
      sc.setResults(&result);
      sc.size = NeighborhoodGraph::property.edgeSizeForCreation;
      sc.radius = FLT_MAX;
      sc.explorationCoefficient = NeighborhoodGraph::property.insertionRadiusCoefficient;
      try {
	GraphIndex::search(sc);
      } catch(Exception &err) {
	throw err;
      }
      if (static_cast<int>(result.size()) < NeighborhoodGraph::property.edgeSizeForCreation &&
	  result.size() < repository.size()) {
	if (sc.edgeSize != 0) {
	  sc.edgeSize = 0;	// not prune edges.
	  try {
	    GraphIndex::search(sc);
	  } catch(Exception &err) {
	    throw err;
	  }
	}
      }
    }

    void searchForKNNGInsertion(Object &po, ObjectID id, ObjectDistances &result) {
      double radius = FLT_MAX;
      size_t size = NeighborhoodGraph::property.edgeSizeForCreation;
      if (id > 0) {
	size = NeighborhoodGraph::property.edgeSizeForCreation + 1;
      }
      ObjectSpace::ResultSet rs;
      objectSpace->linearSearch(po, radius, size, rs);
      result.moveFrom(rs, id);
      if ((size_t)NeighborhoodGraph::property.edgeSizeForCreation != result.size()) {
	cerr << "searchForKNNGInsert::Warning! inconsistency of the sizes. ID=" << id
	     << " " << NeighborhoodGraph::property.edgeSizeForCreation << ":" << result.size() << endl;
	for (size_t i = 0; i < result.size(); i++) {
	  cerr << result[i].id << ":" << result[i].distance << " ";
	}
	cerr << endl;
      }
    }

    virtual void insert(
			ObjectID id
			) {
      ObjectRepository &fr = objectSpace->getRepository();
      if (fr[id] == 0) {
	cerr << "NGTIndex::insert empty " << id << endl;
	return;
      }
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
      Object &po = *objectSpace->allocateObject(*fr[id]);
#else
      Object &po = *fr[id];
#endif
      ObjectDistances rs;
      if (NeighborhoodGraph::property.graphType == NeighborhoodGraph::GraphTypeANNG) {
	searchForNNGInsertion(po, rs);
      } else {
	searchForKNNGInsertion(po, id, rs);
      }
      insertNode(id, rs);
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
      objectSpace->deleteObject(&po);
#endif
    }

    virtual void createIndex();
    virtual void createIndex(size_t threadNumber);

    void checkGraph()
    {
      GraphRepository &repo = repository;
      ObjectRepository &fr = objectSpace->getRepository();
      for (size_t id = 0; id < fr.size(); id++){
	if (repo[id] == 0) {
	  cerr << id << " empty" << endl;
	  continue;
	}
	if ((id % 10000) == 0) {
	  cerr << "checkGraph: Processed size=" << id << endl;
	}
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
	Object &po = *objectSpace->allocateObject(*fr[id]);
#else
	Object &po = *fr[id];
#endif
	GraphNode *objects = getNode(id);

	ObjectDistances rs;
	NeighborhoodGraph::property.edgeSizeForCreation = objects->size() + 1;
	searchForNNGInsertion(po, rs);
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
	objectSpace->deleteObject(&po);
#endif

	if (rs.size() != objects->size()) {
	  cerr << "Cannot get the specified number of the results. " << rs.size() << ":" << objects->size() << endl;
	}
	size_t count = 0;
	ObjectDistances::iterator rsi = rs.begin();
#if defined(NGT_SHARED_MEMORY_ALLOCATOR)
	for (GraphNode::iterator ri = objects->begin(repo.allocator);
	     ri != objects->end(repo.allocator) && rsi != rs.end();) {
#else
	for (GraphNode::iterator ri = objects->begin();
	     ri != objects->end() && rsi != rs.end();) {
#endif
	  if ((*ri).distance == (*rsi).distance && (*ri).id == (*rsi).id) {
	    count++;
	    ri++;
	    rsi++;
	  } else if ((*ri).distance < (*rsi).distance) {
	    ri++;
	  } else {
	    rsi++;
	  }
	}
	if (count != objects->size()) {
	  cerr << "id=" << id << " identities=" << count << " " << objects->size() << " " << rs.size() << endl;
	}
      }
    }

    virtual void verify()
    {
      cerr << "Started verifying graph and objects" << endl;
      GraphRepository &repo = repository;
      ObjectRepository &fr = objectSpace->getRepository();
      for (size_t id = 1; id < fr.size(); id++){
	if (repo[id] == 0) {
	  cerr << "No." << id << " is empty." << endl;
	  if (fr[id] != 0) {
	    cerr << "Graph and object set are inconsistency." << endl;
	  }
	  continue;
	}
	if ((id % 1000000) == 0) {
	  cerr << "  verified " << id << " entries." << endl;
	}
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
	Object *po = objectSpace->allocateObject(*fr[id]);
#else
	Object *po = fr[id];
#endif
	if (po == 0) {
	  cerr << "Cannot get the object." << endl;
	  continue;
	}
	GraphNode *objects = getNode(id);
	if (objects == 0) {
	  cerr << "Cannot get the node." << endl;
	}

#ifdef NGT_SHARED_MEMORY_ALLOCATOR
	objectSpace->deleteObject(po);
#endif
#if defined(NGT_SHARED_MEMORY_ALLOCATOR)
	for (GraphNode::iterator ri = objects->begin(repo.allocator);
	     ri != objects->end(repo.allocator); ++ri) {
#else
	for (GraphNode::iterator ri = objects->begin();
	     ri != objects->end(); ++ri) {
#endif
	  if ((*ri).id == 0 || (*ri).id >= repo.size()) {
	    cerr << "Neighbor's ID of the node is wrong." << endl;
	  }
	  if ((*ri).distance < 0.0) {
	    cerr << "Neighbor's distance is munus." << endl;
	  }
	}
      }
    }

    static void showStatisticsOfGraph(NGT::GraphIndex &outGraph, char mode = '-', size_t edgeSize = UINT_MAX)
    {
      long double distance = 0.0;
      size_t numberOfNodes = 0;
      size_t numberOfOutdegree = 0;
      size_t numberOfNodesWithoutEdges = 0;
      size_t maxNumberOfOutdegree = 0;
      size_t minNumberOfOutdegree = SIZE_MAX;
      vector<int64_t> indegreeCount;
      vector<size_t> outdegreeHistogram;
      vector<size_t> indegreeHistogram;
      vector<vector<float> > indegree;
      NGT::GraphRepository &graph = outGraph.repository;
      indegreeCount.resize(graph.size(), 0);
      indegree.resize(graph.size());
      for (size_t id = 1; id < graph.size(); id++) {
	NGT::GraphNode *node = 0;
	try {
	  node = outGraph.getNode(id);
	} catch(NGT::Exception &err) {
	  cerr << "ngt info: Warning. Cannot get the node. ID=" << id << ":" << err.what() << endl;
	  indegreeCount[id] = -1;
	  continue;
	}
	numberOfNodes++;
	if (numberOfNodes % 1000000 == 0) {
	  cerr << "Processed " << numberOfNodes << endl;
	}
	size_t esize = node->size() > edgeSize ? edgeSize : node->size();
	if (esize == 0) {
	  numberOfNodesWithoutEdges++;
	}
	if (esize > maxNumberOfOutdegree) {
	  maxNumberOfOutdegree = esize;
	}
	if (esize < minNumberOfOutdegree) {
	  minNumberOfOutdegree = esize;
	}
	if (outdegreeHistogram.size() <= esize) {
	  outdegreeHistogram.resize(esize + 1);
	}
	outdegreeHistogram[esize]++;
	if (mode == 'e') {
	  cout << id << "," << esize << ": ";
	}
	for (size_t i = 0; i < esize; i++) {
#if defined(NGT_SHARED_MEMORY_ALLOCATOR)
	  NGT::ObjectDistance &n = (*node).at(i, graph.allocator);
#else
	  NGT::ObjectDistance &n = (*node)[i];
#endif
	  if (n.id == 0) {
	    cerr << "ngt info: Warning. id is zero." << endl;
	  }
	  indegreeCount[n.id]++;
	  indegree[n.id].push_back(n.distance);
	  numberOfOutdegree++;
	  double d = n.distance;
	  if (mode == 'e') {
	    cout << n.id << ":" << d << " ";
	  }
	  distance += d;
	}
	if (mode == 'e') {
	  cout << endl;
	}
      }

      // calculate outdegree distance 10
      size_t d10count = 0;
      long double distance10 = 0.0;
      size_t d10SkipCount = 0;
      const size_t dcsize = 10;
      for (size_t id = 1; id < graph.size(); id++) {
	NGT::GraphNode *n = 0;
	try {
	  n = outGraph.getNode(id);
	} catch(NGT::Exception &err) {
	  cerr << "ngt info: Warning. Cannot get the node. ID=" << id << ":" << err.what() << endl;
	  continue;
	}
	NGT::GraphNode &node = *n;
	if (node.size() < dcsize - 1) {
	  d10SkipCount++;
	  continue;
	}
	for (size_t i = 0; i < node.size(); i++) {
	  if (i >= dcsize) {
	    break;
	  }
#if defined(NGT_SHARED_MEMORY_ALLOCATOR)
	  distance10 += node.at(i, graph.allocator).distance;
#else
	  distance10 += node[i].distance;
#endif
	  d10count++;
	}
      }
      distance10 /= (long double)d10count;

      // calculate indegree distance 10
      size_t ind10count = 0;
      long double indegreeDistance10 = 0.0;
      size_t ind10SkipCount = 0;
      for (size_t id = 1; id < indegree.size(); id++) {
	vector<float> &node = indegree[id];
	if (node.size() < dcsize - 1) {
	  ind10SkipCount++;
	  continue;
	}
	std::sort(node.begin(), node.end());
	for (size_t i = 0; i < node.size(); i++) {
	  assert(i == 0 || node[i - 1] <= node[i]);
	  if (i >= dcsize) {
	    break;
	  }
	  indegreeDistance10 += node[i];
	  ind10count++;
	}
      }
      indegreeDistance10 /= (long double)ind10count;

      // calculate variance
      double averageNumberOfOutdegree = (double)numberOfOutdegree / (double)numberOfNodes;
      double sumOfSquareOfOutdegree = 0;
      double sumOfSquareOfIndegree = 0;
      for (size_t id = 1; id < graph.size(); id++) {
	NGT::GraphNode *node = 0;
	try {
	  node = outGraph.getNode(id);
	} catch(NGT::Exception &err) {
	  cerr << "ngt info: Warning. Cannot get the node. ID=" << id << ":" << err.what() << endl;
	  continue;
	}
	size_t esize = node->size();
	sumOfSquareOfOutdegree += ((double)esize - averageNumberOfOutdegree) * ((double)esize - averageNumberOfOutdegree);
	sumOfSquareOfIndegree += ((double)indegreeCount[id] - averageNumberOfOutdegree) * ((double)indegreeCount[id] - averageNumberOfOutdegree);
      }

      size_t numberOfNodesWithoutIndegree = 0;
      size_t maxNumberOfIndegree = 0;
      size_t minNumberOfIndegree = INT64_MAX;
      for (size_t id = 1; id < graph.size(); id++) {
	if (indegreeCount[id] < 0) {
	  continue;
	}
	if (indegreeCount[id] == 0) {
	  numberOfNodesWithoutIndegree++;
	}
	if (indegreeCount[id] > static_cast<int>(maxNumberOfIndegree)) {
	  maxNumberOfIndegree = indegreeCount[id];
	}
	if (indegreeCount[id] < static_cast<int64_t>(minNumberOfIndegree)) {
	  minNumberOfIndegree = indegreeCount[id];
	}
	if (static_cast<int>(indegreeHistogram.size()) <= indegreeCount[id]) {
	  indegreeHistogram.resize(indegreeCount[id] + 1);
	}
	indegreeHistogram[indegreeCount[id]]++;
      }

      size_t count = 0;
      int medianOutdegree = -1;
      size_t modeOutdegree = 0;
      size_t max = 0;
      double c95 = 0.0;
      double c99 = 0.0;
      for (size_t i = 0; i < outdegreeHistogram.size(); i++) {
	count += outdegreeHistogram[i];
	if (medianOutdegree == -1 && count >= numberOfNodes / 2) {
	  medianOutdegree = i;
	}
	if (max < outdegreeHistogram[i]) {
	  max = outdegreeHistogram[i];
	  modeOutdegree = i;
	}
	if (count > numberOfNodes * 0.95) {
	  if (c95 == 0.0) {
	    c95 += i * (count - numberOfNodes * 0.95);
	  } else {
	    c95 += i * outdegreeHistogram[i];
	  }
	}
	if (count > numberOfNodes * 0.99) {
	  if (c99 == 0.0) {
	    c99 += i * (count - numberOfNodes * 0.99);
	  } else {
	    c99 += i * outdegreeHistogram[i];
	  }
	}
      }
      c95 /= (double)numberOfNodes * 0.05;
      c99 /= (double)numberOfNodes * 0.01;

      count = 0;
      int medianIndegree = -1;
      size_t modeIndegree = 0;
      max = 0;
      double c5 = 0.0;
      double c1 = 0.0;
      for (size_t i = 0; i < indegreeHistogram.size(); i++) {
	if (count < numberOfNodes * 0.05) {
	  if (count + indegreeHistogram[i] >= numberOfNodes * 0.05) {
	    c5 += i * (numberOfNodes * 0.05 - count);
	  } else {
	    c5 += i * indegreeHistogram[i];
	  }
	}
	if (count < numberOfNodes * 0.01) {
	  if (count + indegreeHistogram[i] >= numberOfNodes * 0.01) {
	    c1 += i * (numberOfNodes * 0.01 - count);
	  } else {
	    c1 += i * indegreeHistogram[i];
	  }
	}
	count += indegreeHistogram[i];
	if (medianIndegree == -1 && count >= numberOfNodes / 2) {
	  medianIndegree = i;
	}
	if (max < indegreeHistogram[i]) {
	  max = indegreeHistogram[i];
	  modeIndegree = i;
	}
      }
      c5 /= (double)numberOfNodes * 0.05;
      c1 /= (double)numberOfNodes * 0.01;

      cerr << "# of nodes=" << numberOfNodes << endl;
      cerr << "# of edges=" << numberOfOutdegree << endl;
      cerr << "# of nodes without edges=" << numberOfNodesWithoutEdges << endl;
      cerr << "Max outdegree=" << maxNumberOfOutdegree << endl;
      cerr << "Min outdegree=" << minNumberOfOutdegree << endl;
      cerr << "Average number of edges=" << (double)numberOfOutdegree / (double)numberOfNodes << endl;
      cerr << "Average distance of edges=" << setprecision(10) << distance / (double)numberOfOutdegree << endl;
      cerr << "# of nodes where indegree is 0=" << numberOfNodesWithoutIndegree << endl;
      cerr << "Max indegree=" << maxNumberOfIndegree << endl;
      cerr << "Min indegree=" << minNumberOfIndegree << endl;
      cerr << "#-nodes,#-edges,#-no-indegree,avg-edges,avg-dist,max-out,min-out,v-out,max-in,min-in,v-in,med-out,"
	"med-in,mode-out,mode-in,c95,c5,o-distance(10),o-skip,i-distance(10),i-skip:"
	   << numberOfNodes << ":" << numberOfOutdegree << ":" << numberOfNodesWithoutIndegree << ":"
	   << setprecision(10) << (double)numberOfOutdegree / (double)numberOfNodes << ":"
	   << distance / (double)numberOfOutdegree << ":"
	   << maxNumberOfOutdegree << ":" << minNumberOfOutdegree << ":" << sumOfSquareOfOutdegree / (double)numberOfOutdegree<< ":"
	   << maxNumberOfIndegree << ":" << minNumberOfIndegree << ":" << sumOfSquareOfIndegree / (double)numberOfOutdegree << ":"
	   << medianOutdegree << ":" << medianIndegree << ":" << modeOutdegree << ":" << modeIndegree
	   << ":" << c95 << ":" << c5 << ":" << c99 << ":" << c1 << ":" << distance10 << ":" << d10SkipCount << ":"
	   << indegreeDistance10 << ":" << ind10SkipCount << endl;

      if (mode == 'h') {
	cerr << "#\tout\tin" << endl;
	for (size_t i = 0; i < outdegreeHistogram.size() || i < indegreeHistogram.size(); i++) {
	  size_t out = outdegreeHistogram.size() <= i ? 0 : outdegreeHistogram[i];
	  size_t in = indegreeHistogram.size() <= i ? 0 : indegreeHistogram[i];
	  cerr << i << "\t" << out << "\t" << in << endl;
	}
      }
    }

    size_t getObjectRepositorySize() { return objectSpace->getRepository().size(); }

    size_t getSizeOfElement() { return objectSpace->getSizeOfElement(); }

    Object *allocateObject(const string &textLine, const string &sep) {
      return objectSpace->allocateNormalizedObject(textLine, sep);
    }
    Object *allocateObject(const vector<double> &obj) {
      return objectSpace->allocateNormalizedObject(obj);
    }
    Object *allocateObject(const vector<float> &obj) {
      return objectSpace->allocateNormalizedObject(obj);
    }
    Object *allocateObject(const float *obj, size_t size) {
      return objectSpace->allocateNormalizedObject(obj, size);
    }

    void deleteObject(Object *po) {
      return objectSpace->deleteObject(po);
    }

    ObjectSpace &getObjectSpace() { return *objectSpace; }

    void setProperty(NGT::Property &prop) {
      GraphIndex::property.set(prop);
      NeighborhoodGraph::property.set(prop);
      assert(property.dimension != 0);
    }

    void getProperty(NGT::Property &prop) {
      GraphIndex::property.get(prop);
      NeighborhoodGraph::property.get(prop);
    }

    NeighborhoodGraph::Property &getGraphProperty() { return NeighborhoodGraph::property; }

    virtual size_t getSharedMemorySize(ostream &os, SharedMemoryAllocator::GetMemorySizeType t) {
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
      size_t size = repository.getAllocator().getMemorySize(t);
#else
      size_t size = 0;
#endif
      os << "graph=" << size << endl;
      return size;
    }

    protected:

    template <class REPOSITORY> void getSeedsFromGraph(REPOSITORY &repo, ObjectDistances &seeds) {
      if (repo.size() != 0) {
	size_t seedSize = repo.size() - 1 < (size_t)NeighborhoodGraph::property.seedSize ?
	  repo.size() - 1 : (size_t)NeighborhoodGraph::property.seedSize;
	if (NeighborhoodGraph::property.seedType == NeighborhoodGraph::SeedTypeRandomNodes ||
	    NeighborhoodGraph::property.seedType == NeighborhoodGraph::SeedTypeNone) {
	  getRandomSeeds(repo, seeds, seedSize);
	} else if (NeighborhoodGraph::property.seedType == NeighborhoodGraph::SeedTypeFixedNodes) {
	  // To check speed using fixed seeds.
	  for (size_t i = 1; i <= seedSize; i++) {
	    ObjectDistance obj(i, 0.0);
	    seeds.push_back(obj);
	  }
	} else if (NeighborhoodGraph::property.seedType == NeighborhoodGraph::SeedTypeFirstNode) {
	  ObjectDistance obj(1, 0.0);
	  seeds.push_back(obj);
	} else {
	  getRandomSeeds(repo, seeds, seedSize);
	}
      }
    }

    // GraphIndex
    virtual void search(NGT::SearchContainer &sc, ObjectDistances &seeds) {
      if (sc.size == 0) {
	while (!sc.workingResult.empty()) sc.workingResult.pop();
	return;
      }
      if (seeds.size() == 0) {
#if defined(NGT_SHARED_MEMORY_ALLOCATOR) || !defined(NGT_GRAPH_READ_ONLY_GRAPH)
	getSeedsFromGraph(repository, seeds);
#else
	if (readOnly) {
	  getSeedsFromGraph(searchRepository, seeds);
	} else {
	  getSeedsFromGraph(repository, seeds);
	}
#endif
      }
      NGT::SearchContainer so(sc);
      try {
	if (readOnly) {
#if defined(NGT_SHARED_MEMORY_ALLOCATOR) || !defined(NGT_GRAPH_READ_ONLY_GRAPH)
	  NeighborhoodGraph::search(so, seeds);
#else
	  (*searchUnupdatableGraph)(*this, so, seeds);
#endif
	} else {
	  NeighborhoodGraph::search(so, seeds);
	}
	sc.workingResult = std::move(so.workingResult);
	sc.distanceComputationCount = so.distanceComputationCount;
      } catch(Exception &err) {
	cerr << err.what() << endl;
	Exception e(err);
	throw e;
      }
    }

    Index::Property			property;

    bool readOnly;
#ifdef NGT_GRAPH_READ_ONLY_GRAPH
    void (*searchUnupdatableGraph)(NGT::NeighborhoodGraph&, NGT::SearchContainer&, NGT::ObjectDistances&);
#endif
  };

  class GraphAndTreeIndex : public GraphIndex, public DVPTree {
  public:

#ifdef NGT_SHARED_MEMORY_ALLOCATOR
    GraphAndTreeIndex(const string &allocator, bool rdOnly = false):GraphIndex(allocator, false) {
      initialize(allocator, 0);
    }
    GraphAndTreeIndex(const string &allocator, NGT::Property &prop);
    void initialize(const string &allocator, size_t sharedMemorySize) {
      DVPTree::objectSpace = GraphIndex::objectSpace;
      DVPTree::open(allocator + "/tre", sharedMemorySize);
    }
#else
    GraphAndTreeIndex(const string &database, bool rdOnly = false) : GraphIndex(database, rdOnly) {
      GraphAndTreeIndex::loadIndex(database, rdOnly);
    }

    GraphAndTreeIndex(NGT::Property &prop) : GraphIndex(prop) {
      DVPTree::objectSpace = GraphIndex::objectSpace;
    }
#endif
    virtual ~GraphAndTreeIndex() {}

    void create() {}

#ifdef NGT_SHARED_MEMORY_ALLOCATOR
    void alignObjects()
    {
    }
#else
    void alignObjects()
    {
      NGT::ObjectSpace &space = getObjectSpace();
      NGT::ObjectRepository &repo = space.getRepository();
      Object **object = repo.getPtr();
      vector<bool> exist(repo.size(), false);
      vector<NGT::Node::ID> leafNodeIDs;
      DVPTree::getAllLeafNodeIDs(leafNodeIDs);
      size_t objectCount = 0;
      for (size_t i = 0; i < leafNodeIDs.size(); i++) {
	ObjectDistances objects;
	DVPTree::getObjectIDsFromLeaf(leafNodeIDs[i], objects);
	for (size_t j = 0; j < objects.size(); j++) {
	  exist[objects[j].id] = true;
	  objectCount++;
	}
      }
      multimap<uint32_t, uint32_t> notexist;
      if (objectCount != repo.size()) {
        for (size_t id = 1; id < exist.size(); id++) {
	  if (!exist[id]) {
            DVPTree::SearchContainer tso(*object[id]);
            tso.mode = DVPTree::SearchContainer::SearchLeaf;
            tso.radius = 0.0;
            tso.size = 1;
      	    try {
	      DVPTree::search(tso);
      	    } catch (Exception &err) {
	      stringstream msg;
	      msg << "GraphAndTreeIndex::getSeeds: Cannot search for tree.:" << err.what();
	      NGTThrowException(msg);
      	    }
	    notexist.insert(pair<uint32_t, uint32_t>(tso.nodeID.getID(), id));
	    objectCount++;
	  }
	}
      }
      assert(objectCount == repo.size() - 1);

      objectCount = 1;
      vector<pair<uint32_t, uint32_t> > order;
      for (size_t i = 0; i < leafNodeIDs.size(); i++) {
	ObjectDistances objects;
	DVPTree::getObjectIDsFromLeaf(leafNodeIDs[i], objects);
	for (size_t j = 0; j < objects.size(); j++) {
	  order.push_back(pair<uint32_t, uint32_t>(objects[j].id, objectCount));
	  objectCount++;
	}
	auto nei = notexist.equal_range(leafNodeIDs[i].getID());
	for (auto ii = nei.first; ii != nei.second; ++ii) {
	  order.push_back(pair<uint32_t, uint32_t>((*ii).second, objectCount));
	  objectCount++;
	}
      }
      assert(objectCount == repo.size());
      Object *tmp = space.allocateObject();
      unordered_set<uint32_t> uncopiedObjects;
      for (size_t i = 1; i < repo.size(); i++) {
	uncopiedObjects.insert(i);
      }
      size_t copycount = 0;
      while (!uncopiedObjects.empty()) {
	size_t startID = *uncopiedObjects.begin();
	if (startID == order[startID - 1].first) {
	  uncopiedObjects.erase(startID);
	  copycount++;
	  continue;
	}
	size_t id = startID;
	space.copy(*tmp, *object[id]);
	uncopiedObjects.erase(id);
	do {
	  space.copy(*object[id], *object[order[id - 1].first]);
	  copycount++;
	  id = order[id - 1].first;
	  uncopiedObjects.erase(id);
	} while (order[id - 1].first != startID);
	space.copy(*object[id], *tmp);
	copycount++;
      }
      space.deleteObject(tmp);

      assert(copycount == repo.size() - 1);

      sort(order.begin(), order.end());
      uncopiedObjects.clear();
      for (size_t i = 1; i < repo.size(); i++) {
	uncopiedObjects.insert(i);
      }
      copycount = 0;
      Object *tmpPtr;
      while (!uncopiedObjects.empty()) {
	size_t startID = *uncopiedObjects.begin();
	if (startID == order[startID - 1].second) {
	  uncopiedObjects.erase(startID);
	  copycount++;
	  continue;
	}
	size_t id = startID;
	tmpPtr = object[id];
	uncopiedObjects.erase(id);
	do {
	  object[id] = object[order[id - 1].second];
	  copycount++;
	  id = order[id - 1].second;
	  uncopiedObjects.erase(id);
	} while (order[id - 1].second != startID);
	object[id] = tmpPtr;
	copycount++;
      }
      assert(copycount == repo.size() - 1);
    }
#endif // NGT_SHARED_MEMORY_ALLOCATOR

    void load(const string &ifile) {
      GraphIndex::load(ifile);
      DVPTree::objectSpace = GraphIndex::objectSpace;
    }

    void saveIndex(const string &ofile) {
      GraphIndex::saveIndex(ofile);
#ifndef NGT_SHARED_MEMORY_ALLOCATOR
      string fname = ofile + "/tre";
      ofstream ost(fname);
      if (!ost.is_open()) {
	stringstream msg;
	msg << "saveIndex:: Cannot open. " << fname;
	NGTThrowException(msg);
      }
      DVPTree::serialize(ost);
#endif
    }

    void loadIndex(const string &ifile, bool readOnly) {
      DVPTree::objectSpace = GraphIndex::objectSpace;
      ifstream ist(ifile + "/tre");
      DVPTree::deserialize(ist);
#ifdef NGT_GRAPH_READ_ONLY_GRAPH
      if (readOnly) {
	if (property.objectAlignment == NGT::Index::Property::ObjectAlignmentTrue) {
	  alignObjects();
	}
	GraphIndex::NeighborhoodGraph::loadSearchGraph(ifile);
      }
#endif
    }

    void exportIndex(const string &ofile) {
      GraphIndex::exportIndex(ofile);
      ofstream ost(ofile + "/tre");
      DVPTree::serializeAsText(ost);
    }

    void importIndex(const string &ifile) {
      string fname = ifile + "/tre";
      ifstream ist(fname);
      if (!ist.is_open()) {
	stringstream msg;
	msg << "importIndex:: Cannot open. " << fname;
	NGTThrowException(msg);
      }
      DVPTree::deserializeAsText(ist);
      GraphIndex::importIndex(ifile);
    }

    void remove(const ObjectID id) {
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
      Object &f = *GraphIndex::objectSpace->allocateObject(*GraphIndex::objectSpace->getRepository().get(id));
#else
      Object &f = *GraphIndex::objectSpace->getRepository().get(id);
#endif
      NGT::SearchContainer so(f);
      ObjectDistances results;
      so.setResults(&results);
      so.id = 0;
      so.size = 2;
      so.radius = 0.0;
      so.explorationCoefficient = 1.1;
      ObjectDistances	seeds;
      seeds.push_back(ObjectDistance(id, 0.0));
      GraphIndex::search(so, seeds);
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
      GraphIndex::objectSpace->deleteObject(&f);
#endif
      if (results.size() == 0) {
	NGTThrowException("No found the specified id");
      }
      if (results.size() == 1) {
	try {
	  DVPTree::remove(id);
	} catch(Exception &err) {
	  cerr << "remove:: cannot remove from tree. id=" << id << " " << err.what() << endl;
	  throw err;
	}
      } else {
	try {
	  DVPTree::replace(id, results[1].id);
	} catch(Exception &err) {
	  cerr << "remove:: warning: cannot replace from tree. id=" << id << " " << err.what() << endl;
	}
      }
      GraphIndex::remove(id);
    }

    void searchForNNGInsertion(Object &po, ObjectDistances &result) {
      NGT::SearchContainer sc(po);
      sc.setResults(&result);
      sc.size = NeighborhoodGraph::property.edgeSizeForCreation;
      sc.radius = FLT_MAX;
      sc.explorationCoefficient = NeighborhoodGraph::property.insertionRadiusCoefficient;
      try {
	GraphAndTreeIndex::search(sc);
      } catch(Exception &err) {
	throw err;
      }
      if (static_cast<int>(result.size()) < NeighborhoodGraph::property.edgeSizeForCreation &&
	  result.size() < repository.size()) {
	if (sc.edgeSize != 0) {
	  try {
	    GraphAndTreeIndex::search(sc);
	  } catch(Exception &err) {
	    throw err;
	  }
	}
      }
    }

    void insert(ObjectID id) {
      ObjectRepository &fr = GraphIndex::objectSpace->getRepository();
      if (fr[id] == 0) {
	cerr << "GraphAndTreeIndex::insert empty " << id << endl;
	return;
      }
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
      Object &po = *GraphIndex::objectSpace->allocateObject(*fr[id]);
#else
      Object &po = *fr[id];
#endif
      ObjectDistances rs;
      if (NeighborhoodGraph::property.graphType == NeighborhoodGraph::GraphTypeANNG) {
	searchForNNGInsertion(po, rs);
      } else {
	searchForKNNGInsertion(po, id, rs);
      }

      GraphIndex::insertNode(id, rs);

      if (((rs.size() > 0) && (rs[0].distance != 0.0)) || rs.size() == 0) {
	DVPTree::InsertContainer tiobj(po, id);
	try {
	  DVPTree::insert(tiobj);
	} catch (Exception &err) {
	  cerr << "GraphAndTreeIndex::insert: Fatal error" << endl;
	  cerr << err.what() << endl;
	  return;
	}
      }
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
      GraphIndex::objectSpace->deleteObject(&po);
#endif
    }

    void createIndex(size_t threadNumber);

    void createIndex(const vector<pair<NGT::Object*, size_t> > &objects, vector<InsertionResult> &ids,
		     double range, size_t threadNumber);

    void createTreeIndex();

    // GraphAndTreeIndex
    void getSeedsFromTree(NGT::SearchContainer &sc, ObjectDistances &seeds) {
      DVPTree::SearchContainer tso(sc.object);
      tso.mode = DVPTree::SearchContainer::SearchLeaf;
      tso.radius = 0.0;
      tso.size = 1;
      tso.distanceComputationCount = 0;
      try {
	DVPTree::search(tso);
      } catch (Exception &err) {
	stringstream msg;
	msg << "GraphAndTreeIndex::getSeeds: Cannot search for tree.:" << err.what();
	NGTThrowException(msg);
      }

      try {
	DVPTree::getObjectIDsFromLeaf(tso.nodeID, seeds);
      } catch (Exception &err) {
	stringstream msg;
	msg << "GraphAndTreeIndex::getSeeds: Cannot get a leaf.:" << err.what();
	NGTThrowException(msg);
      }
      sc.distanceComputationCount += tso.distanceComputationCount;
      if (NeighborhoodGraph::property.seedType == NeighborhoodGraph::SeedTypeAllLeafNodes) {
	return;
      }
      // if seedSize is zero, the result size of the query is used as seedSize.
      size_t seedSize = NeighborhoodGraph::property.seedSize == 0 ? sc.size : NeighborhoodGraph::property.seedSize;
      seedSize = seedSize > sc.size ? sc.size : seedSize;
      if (seeds.size() > seedSize) {
	srand(tso.nodeID.getID());
	// to accelerate thinning data.
	for (size_t i = seeds.size(); i > seedSize; i--) {
	  double random = ((double)rand() + 1.0) / ((double)RAND_MAX + 2.0);
	  size_t idx = floor(i * random);
	  seeds[idx] = seeds[i - 1];
	}
	seeds.resize(seedSize);
      } else if (seeds.size() < seedSize) {
	// A lack of the seeds is compansated by random seeds.
	//getRandomSeeds(seeds, seedSize);
      }
    }

    // GraphAndTreeIndex
    void search(NGT::SearchContainer &sc) {
      sc.distanceComputationCount = 0;
      ObjectDistances	seeds;
      getSeedsFromTree(sc, seeds);
      GraphIndex::search(sc, seeds);
    }

    size_t getSharedMemorySize(ostream &os, SharedMemoryAllocator::GetMemorySizeType t) {
      return GraphIndex::getSharedMemorySize(os, t) + DVPTree::getSharedMemorySize(os, t);
    }

    void verify() {
      DVPTree::verify(GraphIndex::objectSpace->getRepository().size());
      GraphIndex::verify();
    }

  };

  class Property : public Index::Property, public NeighborhoodGraph::Property {
  public:
    void setDefault() {
      Index::Property::setDefault();
      NeighborhoodGraph::Property::setDefault();
    }
    void clear() {
      Index::Property::clear();
      NeighborhoodGraph::Property::clear();
    }
    void set(NGT::Property &p) {
      Index::Property::set(p);
      NeighborhoodGraph::Property::set(p);
    }
    void load(const string &file) {
      NGT::PropertySet prop;
      prop.load(file + "/prf");
      Index::Property::importProperty(prop);
      NeighborhoodGraph::Property::importProperty(prop);
    }
    void importProperty(const string &file) {
      NGT::PropertySet prop;
      prop.load(file + "/prf");
      Index::Property::importProperty(prop);
      NeighborhoodGraph::Property::importProperty(prop);
    }
  };

} // namespace NGT

inline void
NGT::Index::open(const string &database, bool rdOnly) {
  Index* idx = 0;
  NGT::Property prop;
  prop.load(database);
  if (prop.indexType == NGT::Index::Property::GraphAndTree) {
    idx = new NGT::GraphAndTreeIndex(database, rdOnly);
  } else if (prop.indexType == NGT::Index::Property::Graph) {
    idx = new NGT::GraphIndex(database, rdOnly);
  } else {
    NGTThrowException("Index::Open: Not found IndexType in property file.");
  }
  if (idx == 0) {
    stringstream msg;
    msg << "Index::open: Cannot open. " << database;
    NGTThrowException(msg);
  }
  index = idx;
  path = database;
}

inline void
  NGT::Index::createGraphAndTree(const string &database, NGT::Property &prop, const string &dataFile,
					   size_t dataSize) {
  if (prop.dimension == 0) {
    NGTThrowException("Index::createGraphAndTree. Dimension is not specified.");
  }
  prop.indexType = NGT::Index::Property::IndexType::GraphAndTree;
  Index *idx = 0;
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
  mkdir(database);
  idx = new NGT::GraphAndTreeIndex(database, prop);
#else
  idx = new NGT::GraphAndTreeIndex(prop);
#endif
  assert(idx != 0);
  try {
    loadAndCreateIndex(*idx, database, dataFile, prop.threadPoolSize, dataSize);
  } catch(Exception &err) {
    delete idx;
    throw err;
  }
  delete idx;
}
template<typename T>
size_t NGT::Index::append(vector<T> &object)
{
  if (getObjectSpace().getRepository().size() == 0) {
    getObjectSpace().getRepository().initialize();
  }

  auto *o = getObjectSpace().getRepository().allocateNormalizedPersistentObject(object);
  getObjectSpace().getRepository().push_back(dynamic_cast<PersistentObject*>(o));

  return getObjectSpace().getRepository().size() - 1;
}
template<typename T>
size_t NGT::Index::insert(vector<T> &object)
{
  if (getObjectSpace().getRepository().size() == 0) {
    getObjectSpace().getRepository().initialize();
  }

  auto *o = getObjectSpace().getRepository().allocateNormalizedPersistentObject(object);
  return getObjectSpace().getRepository().insert(dynamic_cast<PersistentObject*>(o));
}

inline void
  NGT::Index::createGraph(const string &database, NGT::Property &prop, const string &dataFile, size_t dataSize) {
  if (prop.dimension == 0) {
    NGTThrowException("Index::createGraphAndTree. Dimension is not specified.");
  }
  prop.indexType = NGT::Index::Property::IndexType::Graph;
  Index *idx = 0;
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
  mkdir(database);
  idx = new NGT::GraphIndex(database, prop);
#else
  idx = new NGT::GraphIndex(prop);
#endif
  assert(idx != 0);
  try {
    loadAndCreateIndex(*idx, database, dataFile, prop.threadPoolSize, dataSize);
  } catch(Exception &err) {
    delete idx;
    throw err;
  }
  delete idx;
}

inline void
NGT::Index::loadAndCreateIndex(Index &index, const string &database, const string &dataFile, size_t threadSize, size_t dataSize) {
  NGT::Timer timer;
  timer.start();
  if (dataFile.size() != 0) {
    index.load(dataFile, dataSize);
  } else {
    index.saveIndex(database);
    return;
  }
  timer.stop();
  cerr << "Data loading time=" << timer.time << " (sec) " << timer.time * 1000.0 << " (msec)" << endl;
  if (index.getObjectRepositorySize() == 0) {
    NGTThrowException("Index::create: Data file is empty.");
  }
  cerr << "# of objects=" << index.getObjectRepositorySize() - 1 << endl;
  timer.reset();
  timer.start();
  index.createIndex(threadSize);
  timer.stop();
  index.saveIndex(database);
  cerr << "Index creation time=" << timer.time << " (sec) " << timer.time * 1000.0 << " (msec)" << endl;
}

inline void
NGT::Index::append(const string &database, const string &dataFile, size_t threadSize, size_t dataSize) {
  NGT::Index	index(database);
  NGT::Timer	timer;
  timer.start();
  if (dataFile.size() != 0) {
    index.append(dataFile, dataSize);
  } else {
    NGTThrowException("Index::append: No data file.");
  }
  timer.stop();
  cerr << "Data loading time=" << timer.time << " (sec) " << timer.time * 1000.0 << " (msec)" << endl;
  cerr << "# of objects=" << index.getObjectRepositorySize() - 1 << endl;
  timer.reset();
  timer.start();
  index.createIndex(threadSize);
  timer.stop();
  index.saveIndex(database);
  cerr << "Index creation time=" << timer.time << " (sec) " << timer.time * 1000.0 << " (msec)" << endl;
  return;
}

inline void
NGT::Index::append(const string &database, const float *data, size_t dataSize, size_t threadSize) {
  NGT::Index	index(database);
  NGT::Timer	timer;
  timer.start();
  if (data != 0 && dataSize != 0) {
    index.append(data, dataSize);
  } else {
    NGTThrowException("Index::append: No data.");
  }
  timer.stop();
  cerr << "Data loading time=" << timer.time << " (sec) " << timer.time * 1000.0 << " (msec)" << endl;
  cerr << "# of objects=" << index.getObjectRepositorySize() - 1 << endl;
  timer.reset();
  timer.start();
  index.createIndex(threadSize);
  timer.stop();
  index.saveIndex(database);
  cerr << "Index creation time=" << timer.time << " (sec) " << timer.time * 1000.0 << " (msec)" << endl;
  return;
}

inline void
NGT::Index::remove(const string &database, vector<ObjectID> &objects) {
  NGT::Index	index(database);
  NGT::Timer	timer;
  timer.start();
  for (vector<ObjectID>::iterator i = objects.begin(); i != objects.end(); i++) {
    try {
      index.remove(*i);
    } catch (Exception &err) {
      cerr << "Warning: Cannot remove the node. ID=" << *i << " : " << err.what() << endl;
      continue;
    }
  }
  timer.stop();
  cerr << "Data removing time=" << timer.time << " (sec) " << timer.time * 1000.0 << " (msec)" << endl;
  cerr << "# of objects=" << index.getObjectRepositorySize() - 1 << endl;
  index.saveIndex(database);
  return;
}

inline void
NGT::Index::importIndex(const string &database, const string &file) {
  Index *idx = 0;
  NGT::Property property;
  property.importProperty(file);
  NGT::Timer	timer;
  timer.start();
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
  property.databaseType = NGT::Index::Property::DatabaseType::MemoryMappedFile;
  mkdir(database);
#else
  property.databaseType = NGT::Index::Property::DatabaseType::Memory;
#endif
  if (property.indexType == NGT::Index::Property::IndexType::GraphAndTree) {
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
    idx = new NGT::GraphAndTreeIndex(database, property);
#else
    idx = new NGT::GraphAndTreeIndex(property);
#endif
    assert(idx != 0);
  } else if (property.indexType == NGT::Index::Property::IndexType::Graph) {
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
    idx = new NGT::GraphIndex(database, property);
#else
    idx = new NGT::GraphIndex(property);
#endif
    assert(idx != 0);
  } else {
    NGTThrowException("Index::Open: Not found IndexType in property file.");
  }
  idx->importIndex(file);
  timer.stop();
  cerr << "Data importing time=" << timer.time << " (sec) " << timer.time * 1000.0 << " (msec)" << endl;
  cerr << "# of objects=" << idx->getObjectRepositorySize() - 1 << endl;
  idx->saveIndex(database);
  delete idx;
}

inline void
NGT::Index::exportIndex(const string &database, const string &file) {
  NGT::Index	idx(database);
  NGT::Timer	timer;
  timer.start();
  idx.exportIndex(file);
  timer.stop();
  cerr << "Data exporting time=" << timer.time << " (sec) " << timer.time * 1000.0 << " (msec)" << endl;
  cerr << "# of objects=" << idx.getObjectRepositorySize() - 1 << endl;
}

inline void
NGT::GraphIndex::constructObjectSpace(NGT::Property &prop) {
  assert(prop.dimension != 0);
  switch (prop.objectType) {
  case NGT::ObjectSpace::ObjectType::Float :
    objectSpace = new ObjectSpaceRepository<float, double>(prop.dimension, typeid(float), prop.distanceType);
    break;
  case NGT::ObjectSpace::ObjectType::Uint8 :
    objectSpace = new ObjectSpaceRepository<unsigned char, int>(prop.dimension, typeid(uint8_t), prop.distanceType);
    break;
  default:
    cerr << "Invalid Object Type in the property. " << prop.objectType << endl;
  }
#ifdef NGT_GRAPH_READ_ONLY_GRAPH
  searchUnupdatableGraph = NeighborhoodGraph::Search::getMethod(prop.distanceType, prop.objectType);
#endif
}

inline void
NGT::Index::Property::set(NGT::Property &prop) {
  if (prop.dimension != -1) dimension = prop.dimension;
  if (prop.threadPoolSize != -1) threadPoolSize = prop.threadPoolSize;
  if (prop.objectType != ObjectSpace::ObjectTypeNone) objectType = prop.objectType;
  if (prop.distanceType != DistanceType::DistanceTypeNone) distanceType = prop.distanceType;
  if (prop.indexType != IndexTypeNone) indexType = prop.indexType;
  if (prop.databaseType != DatabaseTypeNone) databaseType = prop.databaseType;
  if (prop.objectAlignment != ObjectAlignmentNone) objectAlignment = prop.objectAlignment;
  if (prop.pathAdjustmentInterval != -1) pathAdjustmentInterval = prop.pathAdjustmentInterval;
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
  if (prop.graphSharedMemorySize != -1) graphSharedMemorySize = prop.graphSharedMemorySize;
  if (prop.treeSharedMemorySize != -1) treeSharedMemorySize = prop.treeSharedMemorySize;
  if (prop.objectSharedMemorySize != -1) objectSharedMemorySize = prop.objectSharedMemorySize;
#endif
}

inline void
NGT::Index::Property::get(NGT::Property &prop) {
  prop.dimension = dimension;
  prop.threadPoolSize = threadPoolSize;
  prop.objectType = objectType;
  prop.distanceType = distanceType;
  prop.indexType = indexType;
  prop.databaseType = databaseType;
  prop.pathAdjustmentInterval = pathAdjustmentInterval;
#ifdef NGT_SHARED_MEMORY_ALLOCATOR
  prop.graphSharedMemorySize = graphSharedMemorySize;
  prop.treeSharedMemorySize = treeSharedMemorySize;
  prop.objectSharedMemorySize = objectSharedMemorySize;
#endif
}

inline void
  NGT::GraphIndex::loadIndex(const string &ifile, bool readOnly) {
  objectSpace->deserialize(ifile + "/obj");
#ifdef NGT_GRAPH_READ_ONLY_GRAPH
  if (readOnly && property.indexType == NGT::Index::Property::IndexType::Graph) {
    GraphIndex::NeighborhoodGraph::loadSearchGraph(ifile);
  } else {
    ifstream isg(ifile + "/grp");
    repository.deserialize(isg);
  }
#else
  ifstream isg(ifile + "/grp");
  repository.deserialize(isg);
#endif
}

#ifdef NGT_SHARED_MEMORY_ALLOCATOR
inline
NGT::GraphIndex::GraphIndex(const string &allocator, bool rdonly):readOnly(rdonly) {
  NGT::Property prop;
  prop.load(allocator);
  if (prop.databaseType != NGT::Index::Property::DatabaseType::MemoryMappedFile) {
    NGTThrowException("GraphIndex: Cannot open. Not memory mapped file type.");
  }
  initialize(allocator, prop);
}

inline
NGT::GraphAndTreeIndex::GraphAndTreeIndex(const string &allocator, NGT::Property &prop):GraphIndex(allocator, prop) {
  initialize(allocator, prop.treeSharedMemorySize);
}

inline
void NGT::GraphIndex::initialize(const string &allocator, NGT::Property &prop) {
  constructObjectSpace(prop);
  repository.open(allocator + "/grp", prop.graphSharedMemorySize);
  objectSpace->open(allocator + "/obj", prop.objectSharedMemorySize);
  setProperty(prop);
}
#else // NGT_SHARED_MEMORY_ALLOCATOR
inline
NGT::GraphIndex::GraphIndex(const string &database, bool rdOnly):readOnly(rdOnly) {
  NGT::Property prop;
  prop.load(database);
  if (prop.databaseType != NGT::Index::Property::DatabaseType::Memory) {
    NGTThrowException("GraphIndex: Cannot open. Not memory type.");
  }
  assert(prop.dimension != 0);
  initialize(prop);
  loadIndex(database, readOnly);
}
#endif


/*
  Source: http://www.schneier.com/code/constants.txt
*/

#ifndef Q_BLOWFISH_P_H
#define Q_BLOWFISH_P_H

#define SBOX_SIZE_BYTES (256 * 4)
#define PARRAY_SIZE_BYTES (18 * 4)

char sbox0[] =
    "d1310ba698dfb5ac2ffd72dbd01adfb7b8e1afed6a267e96"
    "ba7c9045f12c7f9924a19947b3916cf70801f2e2858efc16"
    "636920d871574e69a458fea3f4933d7e0d95748f728eb658"
    "718bcd5882154aee7b54a41dc25a59b59c30d5392af26013"
    "c5d1b023286085f0ca417918b8db38ef8e79dcb0603a180e"
    "6c9e0e8bb01e8a3ed71577c1bd314b2778af2fda55605c60"
    "e65525f3aa55ab945748986263e8144055ca396a2aab10b6"
    "b4cc5c341141e8cea15486af7c72e993b3ee1411636fbc2a"
    "2ba9c55d741831f6ce5c3e169b87931eafd6ba336c24cf5c"
    "7a325381289586773b8f48986b4bb9afc4bfe81b66282193"
    "61d809ccfb21a991487cac605dec8032ef845d5de98575b1"
    "dc262302eb651b8823893e81d396acc50f6d6ff383f44239"
    "2e0b4482a484200469c8f04a9e1f9b5e21c66842f6e96c9a"
    "670c9c61abd388f06a51a0d2d8542f68960fa728ab5133a3"
    "6eef0b6c137a3be4ba3bf0507efb2a98a1f1651d39af0176"
    "66ca593e82430e888cee8619456f9fb47d84a5c33b8b5ebe"
    "e06f75d885c12073401a449f56c16aa64ed3aa62363f7706"
    "1bfedf72429b023d37d0d724d00a1248db0fead349f1c09b"
    "075372c980991b7b25d479d8f6e8def7e3fe501ab6794c3b"
    "976ce0bd04c006bac1a94fb6409f60c45e5c9ec2196a2463"
    "68fb6faf3e6c53b51339b2eb3b52ec6f6dfc511f9b30952c"
    "cc814544af5ebd09bee3d004de334afd660f2807192e4bb3"
    "c0cba85745c8740fd20b5f39b9d3fbdb5579c0bd1a60320a"
    "d6a100c6402c7279679f25fefb1fa3cc8ea5e9f8db3222f8"
    "3c7516dffd616b152f501ec8ad0552ab323db5fafd238760"
    "53317b483e00df829e5c57bbca6f8ca01a87562edf1769db"
    "d542a8f6287effc3ac6732c68c4f5573695b27b0bbca58c8"
    "e1ffa35db8f011a010fa3d98fd2183b84afcb56c2dd1d35b"
    "9a53e479b6f84565d28e49bc4bfb9790e1ddf2daa4cb7e33"
    "62fb1341cee4c6e8ef20cada36774c01d07e9efe2bf11fb4"
    "95dbda4dae909198eaad8e716b93d5a0d08ed1d0afc725e0"
    "8e3c5b2f8e7594b78ff6e2fbf2122b648888b812900df01c"
    "4fad5ea0688fc31cd1cff191b3a8c1ad2f2f2218be0e1777"
    "ea752dfe8b021fa1e5a0cc0fb56f74e818acf3d6ce89e299"
    "b4a84fe0fd13e0b77cc43b81d2ada8d9165fa26680957705"
    "93cc7314211a1477e6ad206577b5fa86c75442f5fb9d35cf"
    "ebcdaf0c7b3e89a0d6411bd3ae1e7e4900250e2d2071b35e"
    "226800bb57b8e0af2464369bf009b91e5563911d59dfa6aa"
    "78c14389d95a537f207d5ba202e5b9c5832603766295cfa9"
    "11c819684e734a41b3472dca7b14a94a1b5100529a532915"
    "d60f573fbc9bc6e42b60a47681e6740008ba6fb5571be91f"
    "f296ec6b2a0dd915b6636521e7b9f9b6ff34052ec5855664"
    "53b02d5da99f8fa108ba47996e85076a"
;

char sbox1[] =
    "4b7a70e9b5b32944db75092ec4192623ad6ea6b049a7df7d"
    "9cee60b88fedb266ecaa8c71699a17ff5664526cc2b19ee1"
    "193602a575094c29a0591340e4183a3e3f54989a5b429d65"
    "6b8fe4d699f73fd6a1d29c07efe830f54d2d38e6f0255dc1"
    "4cdd20868470eb266382e9c6021ecc5e09686b3f3ebaefc9"
    "3c9718146b6a70a1687f358452a0e286b79c5305aa500737"
    "3e07841c7fdeae5c8e7d44ec5716f2b8b03ada37f0500c0d"
    "f01c1f040200b3ffae0cf51a3cb574b225837a58dc0921bd"
    "d19113f97ca92ff69432477322f547013ae5e58137c2dadc"
    "c8b576349af3dda7a94461460fd0030eecc8c73ea4751e41"
    "e238cd993bea0e2f3280bba1183eb3314e548b384f6db908"
    "6f420d03f60a04bf2cb8129024977c795679b072bcaf89af"
    "de9a771fd9930810b38bae12dccf3f2e5512721f2e6b7124"
    "501adde69f84cd877a5847187408da17bc9f9abce94b7d8c"
    "ec7aec3adb851dfa63094366c464c3d2ef1c18473215d908"
    "dd433b3724c2ba1612a14d432a65c45150940002133ae4dd"
    "71dff89e10314e5581ac77d65f11199b043556f1d7a3c76b"
    "3c11183b5924a509f28fe6ed97f1fbfa9ebabf2c1e153c6e"
    "86e34570eae96fb1860e5e0a5a3e2ab3771fe71c4e3d06fa"
    "2965dcb999e71d0f803e89d65266c8252e4cc9789c10b36a"
    "c6150eba94e2ea78a5fc3c531e0a2df4f2f74ea7361d2b3d"
    "1939260f19c279605223a708f71312b6ebadfe6eeac31f66"
    "e3bc4595a67bc883b17f37d1018cff28c332ddefbe6c5aa5"
    "6558218568ab9802eecea50fdb2f953b2aef7dad5b6e2f84"
    "1521b62829076170ecdd4775619f151013cca830eb61bd96"
    "0334fe1eaa0363cfb5735c904c70a239d59e9e0bcbaade14"
    "eecc86bc60622ca79cab5cabb2f3846e648b1eaf19bdf0ca"
    "a02369b9655abb5040685a323c2ab4b3319ee9d5c021b8f7"
    "9b540b19875fa09995f7997e623d7da8f837889a97e32d77"
    "11ed935f166812810e358829c7e61fd696dedfa17858ba99"
    "57f584a51b2272639b83c3ff1ac24696cdb30aeb532e3054"
    "8fd948e46dbc312858ebf2ef34c6ffeafe28ed61ee7c3c73"
    "5d4a14d9e864b7e342105d14203e13e045eee2b6a3aaabea"
    "db6c4f15facb4fd0c742f442ef6abbb5654f3b1d41cd2105"
    "d81e799e86854dc7e44b476a3d816250cf62a1f25b8d2646"
    "fc8883a0c1c7b6a37f1524c369cb749247848a0b5692b285"
    "095bbf00ad19489d1462b17423820e0058428d2a0c55f5ea"
    "1dadf43e233f70613372f0928d937e41d65fecf16c223bdb"
    "7cde3759cbee74604085f2a7ce77326ea607808419f8509e"
    "e8efd85561d99735a969a7aac50c06c25a04abfc800bcadc"
    "9e447a2ec3453484fdd567050e1e9ec9db73dbd3105588cd"
    "675fda79e3674340c5c43465713e38d83d28f89ef16dff20"
    "153e21e78fb03d4ae6e39f2bdb83adf7"
;

char sbox2[] =
    "e93d5a68948140f7f64c261c94692934411520f77602d4f7"
    "bcf46b2ed4a20068d40824713320f46a43b7d4b7500061af"
    "1e39f62e9724454614214f74bf8b88404d95fc1d96b591af"
    "70f4ddd366a02f45bfbc09ec03bd97857fac6dd031cb8504"
    "96eb27b355fd3941da2547e6abca0a9a28507825530429f4"
    "0a2c86dae9b66dfb68dc1462d7486900680ec0a427a18dee"
    "4f3ffea2e887ad8cb58ce0067af4d6b6aace1e7cd3375fec"
    "ce78a399406b2a4220fe9e35d9f385b9ee39d7ab3b124e8b"
    "1dc9faf74b6d185626a36631eae397b23a6efa74dd5b4332"
    "6841e7f7ca7820fbfb0af54ed8feb397454056acba489527"
    "55533a3a20838d87fe6ba9b7d096954b55a867bca1159a58"
    "cca9296399e1db33a62a4a563f3125f95ef47e1c9029317c"
    "fdf8e80204272f7080bb155c05282ce395c11548e4c66d22"
    "48c1133fc70f86dc07f9c9ee41041f0f404779a45d886e17"
    "325f51ebd59bc0d1f2bcc18f41113564257b7834602a9c60"
    "dff8e8a31f636c1b0e12b4c202e1329eaf664fd1cad18115"
    "6b2395e0333e92e13b240b62eebeb92285b2a20ee6ba0d99"
    "de720c8c2da2f728d012784595b794fd647d0862e7ccf5f0"
    "5449a36f877d48fac39dfd27f33e8d1e0a476341992eff74"
    "3a6f6eabf4f8fd37a812dc60a1ebddf8991be14cdb6e6b0d"
    "c67b55106d672c372765d43bdcd0e804f1290dc7cc00ffa3"
    "b5390f92690fed0b667b9ffbcedb7d9ca091cf0bd9155ea3"
    "bb132f88515bad247b9479bf763bd6eb37392eb3cc115979"
    "8026e297f42e312d6842ada7c66a2b3b12754ccc782ef11c"
    "6a124237b79251e706a1bbe64bfb63501a6b101811caedfa"
    "3d25bdd8e2e1c3c9444216590a121386d90cec6ed5abea2a"
    "64af674eda86a85fbebfe98864e4c3fe9dbc8057f0f7c086"
    "60787bf86003604dd1fd8346f6381fb07745ae04d736fccc"
    "83426b33f01eab71b08041873c005e5f77a057bebde8ae24"
    "55464299bf582e614e58f48ff2ddfda2f474ef388789bdc2"
    "5366f9c3c8b38e74b475f25546fcd9b97aeb26618b1ddf84"
    "846a0e79915f95e2466e598e20b457708cd55591c902de4c"
    "b90bace1bb8205d011a862487574a99eb77f19b6e0a9dc09"
    "662d09a1c4324633e85a1f0209f0be8c4a99a0251d6efe10"
    "1ab93d1d0ba5a4dfa186f20f2868f169dcb7da83573906fe"
    "a1e2ce9b4fcd7f5250115e01a70683faa002b5c40de6d027"
    "9af88c27773f8641c3604c0661a806b5f0177a28c0f586e0"
    "006058aa30dc7d6211e69ed72338ea6353c2dd94c2c21634"
    "bbcbee5690bcb6deebfc7da1ce591d766f05e4094b7c0188"
    "39720a3d7c927c2486e3725f724d9db91ac15bb4d39eb8fc"
    "ed54557808fca5b5d83d7cd34dad0fc41e50ef5eb161e6f8"
    "a28514d96c51133c6fd5c7e756e14ec4362abfceddc6c837"
    "d79a323492638212670efa8e406000e0"
;

char sbox3[] =
    "3a39ce37d3faf5cfabc277375ac52d1b5cb0679e4fa33742"
    "d382274099bc9bbed5118e9dbf0f7315d62d1c7ec700c47b"
    "b78c1b6b21a19045b26eb1be6a366eb45748ab2fbc946e79"
    "c6a376d26549c2c8530ff8ee468dde7dd5730a1d4cd04dc6"
    "2939bbdba9ba4650ac9526e8be5ee304a1fad5f06a2d519a"
    "63ef8ce29a86ee22c089c2b843242ef6a51e03aa9cf2d0a4"
    "83c061ba9be96a4d8fe51550ba645bd62826a2f9a73a3ae1"
    "4ba99586ef5562e9c72fefd3f752f7da3f046f6977fa0a59"
    "80e4a91587b086019b09e6ad3b3ee593e990fd5a9e34d797"
    "2cf0b7d9022b8b5196d5ac3a017da67dd1cf3ed67c7d2d28"
    "1f9f25cfadf2b89b5ad6b4725a88f54ce029ac71e019a5e6"
    "47b0acfded93fa9be8d3c48d283b57ccf8d5662979132e28"
    "785f0191ed756055f7960e44e3d35e8c15056dd488f46dba"
    "03a161250564f0bdc3eb9e153c9057a297271aeca93a072a"
    "1b3f6d9b1e6321f5f59c66fb26dcf3197533d928b155fdf5"
    "035634828aba3cbb28517711c20ad9f8abcc5167ccad925f"
    "4de817513830dc8e379d58629320f991ea7a90c2fb3e7bce"
    "5121ce64774fbe32a8b6e37ec3293d4648de53696413e680"
    "a2ae0810dd6db22469852dfd09072166b39a460a6445c0dd"
    "586cdecf1c20c8ae5bbef7dd1b588d40ccd2017f6bb4e3bb"
    "dda26a7e3a59ff453e350a44bcb4cdd572eacea8fa6484bb"
    "8d6612aebf3c6f47d29be463542f5d9eaec2771bf64e6370"
    "740e0d8de75b1357f8721671af537d5d4040cb084eb4e2cc"
    "34d2466a0115af84e1b0042895983a1d06b89fb4ce6ea048"
    "6f3f3b823520ab82011a1d4b277227f8611560b1e7933fdc"
    "bb3a792b344525bda08839e151ce794b2f32c9b7a01fbac9"
    "e01cc87ebcc7d1f6cf0111c3a1e8aac71a908749d44fbd9a"
    "d0dadecbd50ada380339c32ac69136678df9317ce0b12b4f"
    "f79e59b743f5bb3af2d519ff27d9459cbf97222c15e6fc2a"
    "0f91fc719b941525fae59361ceb69cebc2a8645912baa8d1"
    "b6c1075ee3056a0c10d25065cb03a442e0ec6e0e1698db3b"
    "4c98a0be3278e9649f1f9532e0d392dfd3a0342b8971f21e"
    "1b0a74414ba3348cc5be7120c37632d8df359f8d9b992f2e"
    "e60b6f470fe3f11de54cda541edad891ce6279cfcd3e7e6f"
    "1618b166fd2c1d05848fd2c5f6fb2299f523f357a6327623"
    "93a8353156cccd02acf081625a75ebb56e16369788d273cc"
    "de96629281b949d04c50901b71c65614e6c6c7bd327a140a"
    "45e1d006c3f27b9ac9aa53fd62a80f00bb25bfe235bdd2f6"
    "71126905b2040222b6cbcf7ccd769c2b53113ec01640e3d3"
    "38abbd602547adf0ba38209cf746ce7677afa1c520756060"
    "85cbfe4e8ae88dd87aaaf9b04cf9aa7e1948c25c02fb8a8c"
    "01c36ae4d6ebe1f990d4f869a65cdea03f09252dc208e69f"
    "b74e6132ce77e25b578fdfe33ac372e6"
;

char parray[] =
    "243f6a8885a308d313198a2e03707344a4093822299f31d0"
    "082efa98ec4e6c89452821e638d01377be5466cf34e90c6c"
    "c0ac29b7c97c50dd3f84d5b5b54709179216d5d98979fb1b"
;

#endif // Q_BLOWFISH_P_H


Enjoy the best of the action from this five star display as Casey Stoney’s side secure promotion to the Women’s Super League!
Subscribe to Manchester United on YouTube at http://bit.ly/ManU_YT
Visit Manchester United at http://www.manutd.com
Like Manchester United on Facebook at http://www.facebook.com/manchesterunited
Follow Manchester United on Twitter at http://www.twitter.com/ManUtd
Follow Manchester on Instagram at http://www.instagram.com/manchesterunited
Subscribe to MUTV at https://bit.ly/2L9ymRs


is there an order to learn Desgin Patterns?
I'm new in Desgin Patterns, and I dont know how to start. is there an order to learn? I try to learn with the first one in the list (Abstract factory) but its complicated for me then I try with Singleton and I think I understand that one. I dont know, can you recommend an order please?
Alberto Chargoy, Jul 29, 2016
I recommend starting with the Strategy pattern. It was the first pattern I learned, and actually learned it from this site years ago. It is, IMO, the most fundamental of patterns. I would recommend going in this order:
2. Factory Method
3. Abstract Factory
4. Chain of Command
After those, there are some very useful small patterns:
Above all, my favorite (arguable) pattern / construct is the Rules Engine pattern. It's sole purpose is to eliminate those forever-scrolling long blocks of if else if if if else if if else hell.
Jonathan Hart, Aug 09, 2016


I have downloaded a .net source code from the Internet.
The source code has 2 projects.
First is a Windows class lib.
Second is a WeSite project whose name is [
When I run the Web Site, VS2005 searches that location and finds nothing. So the WebSite is not run.
How can I change this setting so that I can run it from VS2005's development web server.


When you launch the CPQ Admin console, Manage Product page is displayed. All the existing products are listed on this page along with their details. You can configure the columns displayed on the Manage Product Page. There are various functionalities available for you to manage the products.
Search for the product to narrow down the product list using the Search Products box. Enter a keyword related to your product details like Product Name, Product Code, Configuration type, description. Search Product box returns all the products that contain that keyword in the product details.
There are two types of search available on the products homepage. Saved Search and Product search query.
Either of the search filters is applicable at a time.
Saved Search provides you with various options to search, sort, and filter products. You can either define search criteria to search for a range of products or use the product search option. The search query uses options provided in the Field, Operator, and value and displays a search result that matches the criteria. Saved Search functionality lets you save a set of filters you define that narrows down the list of products according to your requirement.
Perform the following steps to view and search configured products in the Saved Search:
- Click View All to view all products that are configured in CPQ on the dashboard. If you have queried a filter or a product, then a select View All to disable the existing search filter.
- Click New Search. A window that consists of various fields, operators, and values are displayed.
- Field: All product Fields are available in the drop-down list such as Text, Checkbox, Date, Date/Time, Number, Percent, Picklist, Multi-Select Picklist, Currency.
- Operator: Operators that are available for selection helps create the filter expression. Operators are displayed based on the field types. For example, a picklist value will display equal to and not equal operators and a text field will display equal to, not equal to, starts with, contain, does not contain operators. If it is a multi-value picklist, the application displays include and does not include operators.
- Value: Enter a value.
- Click one of the following options to execute the search:
- Click Save As to save the search filter and use the filter criteria.
- Click Apply to enable the search filter.
- Click Cancel to cancel the search criteria.
- To search a product in the Product Search, enter the name of the product that you want to search in the search field. Products that match the search are displayed.
- Click field headers in the product's dashboard to sort dashboard based on the field.
You can simply click the saved search record you created and the system filters the search results. You can see the saved searches dropdown list in alphabetical order for better accessibility of your list of saved searches. If you have configured a customized view, click the menu icon () next to the New Search button. The following options are displayed.
- Edit View: Displays a new search window.
- Save View As: Displays options to Save the edit view.
- Remove View: Removes the filter.
You can also narrow down the list using the column search (inline search). Enter a keyword related to the column in space under the column name. Unlike the Search Product field, column search matches the keyword in that particular column. Use the keywords True and False for the checkbox type columns. You can enter keywords in multiple columns at the same time, the result displayed contains the products with details matching to all keywords you entered in different columns.
Refresh the page to clear all the filters.
Sorting and Adjusting the Columns
You can sort the product by clicking the column names. The products are sorted alphabetically, every time you click the column name the sorting switched between ascending and descending order. You can adjust the column width by dragging the columns. Hover near the column boundaries till two-way arrow appear. Click when the arrow appears and drag left or right to adjust the column width. At the bottom of the page, you can control the number of products to be displayed on each page. You can select the number of products from a pre-defined list. You cannot configure this list. By default, you see 50 records on each page.
Product details hold the information about the product. You can view them on the Manage Product page or the product details page. When you click the product name displayed in blue color, the DETAILS tab is displayed. All the primary details of the products are displayed on this page. Other tabs on the secondary toolbar hold additional information like options information, price list associated with the product, rules associated with the products. You can edit the details on this page.
You can use the Mini Display functionality to view the details without leaving the Manage Product page. Click the information in any column other than the product name for the respective product. A panel on the right-hand side displays the details of the product. You cannot edit any details on the mini display. Click the edit icon to go to the DETAILS tab, to edit the details.
You can see a list of all the existing products displayed in a panel on the left. When you hover the cursor over the product name, product details are displayed in a pop-up. You can configure the pop-up to display other fields. For more information, refer to Configuring the Tooltips.


I’m curious if anyone here has successfully integrated Discourse into their own Trellis/WP install? I’d like to run Discourse from a sub-domain i.e. community.mysite.com but run a staging version at community.mysite.test, as well. I’m thinking that this repo https://github.com/jamielinux/ansible-discourse will get me 99% of the way there but I don’t want to overwrite any crucial information that Trellis relies on during the installation and deployment. Any heads up would be appreciated if you’ve tried this successfully or not. Thanks in advance
This topic was automatically closed after 42 days. New replies are no longer allowed.


I'm considering the following reaction:
CO + Mo(CO)5
I think this is an example of a dissociative mechanism because an associative mechanism would lead to a 20-electron complex, making it unstable because it isn't in agreement with the 18-electron rule. But I'm a bit confused because if it is dissociative, then wouldn't Mo(CO)5
form an unstable intermediate because it would be a 16-electron complex?
I'm pretty sure it's dissociative because there's a similar example with W(CO)6
to form W(CO)5
), but wouldn't this lead to the same problem? I first thought that the solvent might temporarily interact with the intermediate to stabilise it before the pip ligand interacts, but the reaction is in toluene and I'm not sure if it can do η2
as well as η6
- I would say that it does because I know benzene can do η2
bonding, but I'm not sure if the methyl group in toluene would change this.
Any help would be greatly appreciated!


I will teach the way you prefer, depending to the number of students.
I Am a Java developer, with 4 years development experience. I only offer teaching within 3 miles radius from colindale station. I have been working as a developer since 2016, moreover had completed several software projects.
you can go through my CV and find out about the details of my programming knowledge.
The best tutor I have ever seen. I do recommend him.
computer programming lessons closeby? Here's a selection of tutor listings that you can check out.
Superprof can also suggest HTML lessons to help you.
Learning isn't a problem, programming languages lessons for all!
Taking java lessons has never been easier: you're going to learn new skills.
|at his home||at your home||By webcam|
|1 hour||Not available||£20||£20|
|5 hours||Not available||£90||£100|
|10 hours||Not available||£170||£200|


Lists Home |
Date Index |
On Thursday 31 January 2002 06:50 pm, Jonathan Borden wrote:
> > I think this is a misnomer carried over from the ancient days of
> > SGML.
> When you say "misnomer" do you mean that XML 1.0's usage of the term
> "type" as in:
> "The Name in the start- and end-tags gives the element's type..."
> is wrong?
Yes.... or at least ambiguous.
I think the term "type" here is often interpreted to mean "type" in
the sense of "int", "float" etc. as found in strongly typed computer
programming languages. Perhaps for SGML, which required DTD's , and so
to a degree was statically typed (hah!) it was similar, but I think
for XML, the notion of "type" is really much looser.... very much
closer to the Common Lisp way, where type is by projection, as Joe
pointed out. In practise, this was usually true of SGML too...
> XML 1.0 does say this, and an element's name _is_ different than
> other attributes of the element. Purely from a definitional
Yes, because it is required. Whether this is largely a feature of
syntax could be a point of discussion, though not overly interesting.
Just to clarify terminology, I am using attribute in a slightly wider
sense than XML... more like the notion of "field" or "named data
> I am not sure what you mean. I am saying that I find it useful from
> a processing POV, to consider an element's name, just as what XML
> 1.0 says, its "type" and moreover that this defines the "isa" link.
Sure. I think many people find this useful. My point is that the
'is-a" is not intrinsic... though the XML specification's use of the
word 'type' might lead you to believe so. The application decides how
'is-a' relationships are decided.
> What is the myth? "isa" links have been used forever. A "name" is a
> character string, right, what is open to interpretation?
I should have been more precise, sorry. When I say "isa is a myth", I
meant "isa links are intrinsic is a myth". Again, my assertion is
that 'is-a' only exists in the context of a given interpreter.
> At the end of the day, we do all this because it is useful, and the
> utility of thinking about namespaces in one way or another is purely
> the usefulness of doing so.
Sure, in the context of a given application, one style is preferrable
to another mostly because of it's utility.


During a recent Vanderbilt baseball game, play-by-play broadcaster Max Herz brought up the unconventionally high uniform numbers assigned by Tim Corbin in recent years. Having some already-existing code that parses rosters from the official Vanderbilt Baseball roster page, I threw together a quick visualization of the uniform number distribution from 2005 (the earliest roster available) to 2021:
The next day, I spent a little more time improving the graphic by distinguishing between pitchers and position players and using opacity to indicate tenure of the same player wearing the number across multiple seasons:
I put these together with some inelegant HTML + CSS exported as an image. Some day I might make an interacive version. Even more interesting would be to do this for MLB teams across a much longer history of seasons. A cursory look at MLB uniform numbers reveals that I'll need to handle the uniform number 1⁄8!


AWS Glue and Azure Data Factory serve similar purposes. Both provide managed extract, transform and load services. Organizations can use these services to build integrated data pipelines in the cloud.
There are, however, important differences between Glue and Data Factory. The main differences lie in pricing models as well as support for data connectors and SQL Server Integration Services (SSIS) packages. Understanding these differences is crucial when it’s time to choose the right cloud ETL service for your workloads.
What is AWS Glue?
AWS Glue is a managed service on the Amazon cloud. It lets users collect, process and move data across data pipelines.
AWS Glue is a serverless offering; it doesn’t require that users set up and manage the underlying ETL hosting infrastructure. AWS Glue provides the functionality businesses need to create ETL pipelines. The only requirement for the user is defining a data pipeline and the processes they want to run as data moves through it.
What is Azure Data Factory?
Azure Data Factory is a managed ETL service on the Microsoft Azure cloud. Like AWS Glue, Azure Data Factory is designed simplify processing and moving data across user-defined pipelines.
Data Factory is also a serverless offering; Azure provides and manages all the underlying infrastructure. Users can focus on their data pipelines without worrying about how those pipelines are hosted.
How to use AWS Glue and Azure Data Factory
The prerequisites for using AWS Glue and Azure Data Factory are essentially the same:
- Data sources. Data sources are the places where data originates. They could be a database; an object storage service, such as Amazon S3 or Azure Blob Storage; or any other place where data is stored or streamed. Although Glue and Data Factory integrate most easily with data sources in their own respective clouds, they can support external data sources.
- Data targets. Data targets are where data is located after it has been processed as part of an ETL pipeline. Usually, data targets are an object storage service or a database.
To build a data pipeline on either service, you must configure rules that define how the service collects data from data sources. The rules also define which processing methods, if any, are applied to data after collection. For example, you could pull data from an external data set to fill in missing information within a data source as part of a data pipeline. Alternatively, you could remove duplicate data entries from a data source.
The rules specify which targets the data should be pushed to after processing is complete. Users can manage Glue and Data Factory through cloud consoles or command line interface tools.
AWS Glue vs. Azure Data Factory: The main differences
Although Glue and Data Factory offer similar services and operate comparably, there are small but important differences between them.
Glue's pricing model is more standardized and, as a result, likely more predictable.
Glue charges mainly by data processing unit (DPU) hours. The DPU charge is consistent across most types of AWS Glue jobs and operations. At the time of publication, the DPU charge is $0.44/DPU-Hour in the AWS U.S. East (Ohio) region. There may be extra fees to extract data from data sources and for data catalog storage. There are no extra fees for services like pipeline runs.
With Azure Data Factory, you face more cost variables. Azure charges $0.25 per data integration unit, a unit similar to DPUs. Azure charges separate fees for the amount of time a pipeline is operational, data read/writes and total pipeline runs.
AWS Glue and Azure Data Factory both provide a variety of data connectors. Connectors let the services connect to data stores that serve as data sources. However, there are some differences in which data stores they support.
Data Factory offers connector support for Microsoft products. Glue can integrate with the most popular Microsoft-based data stores, including SharePoint, but it doesn’t currently offer connectors for stores like Microsoft Access.
AWS Glue and Azure Data Factory both import packages from SSIS. This a platform for creating data pipelines using Microsoft SQL Server. SSIS is commonly used to set up data pipelines in on-premises environments. Some businesses have SSIS packages that they want to migrate into the cloud to serve as the basis of their serverless ETL pipelines.
Importing SSIS packages to AWS Glue requires more effort than with Azure Data Factory. Glue requires packages be converted, whereas Azure Data Factory lets users deploy and run SSIS packages directly without converting or migrating them.


Getting Started with Jupyter Notebook and Python
MP4 | Video: AVC 1280x720 | Audio: AAC 44KHz 2ch | Duration: 2 Hours 14M | 307 MB
Genre: eLearning | Language: English
Jupyter Notebook is an interactive computing environment that transcends code, and it has completely disrupted the way that many Python developers work and think about software development. This course shows how you can let it do the same for you.


hey i am wondering how i would go about creating a program that does the following things:
1. opens up an internet browser.
2. takes you to a specified website.
3. logs you in with specified name and password.
4. takes you to a link on the post-login page.
5. then inserts a value into a specified typing box such as "150"
6. the value would be no greater than the the maximum amount possible(ex. you have 1,500,000 each 1 value you enter counts as 15, you can only therefore enter 100,000)
7. it would then close and reopen every four hours.
Any ideas, im kinda noobish so any help is appreciated


We have recently upgraded to WeBWorK 2.8. When editing a homework set problem, I used the 'create unattached problem' option under the New Version tab. The problem was created within the local subdirectory of the templates directory, but the following error was opened in a new window.
Any help with fixing this error would be appreciated. Thank you
Cannot find a problem record for set Undefined_Set / problem Undefined_Set at /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor2.pm line 1032.
The information below can help locate the source of the problem.
in WeBWorK::ContentGenerator::Instructor::PGProblemEditor2::getFilePaths called at line 275 of /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor2.pm
in WeBWorK::ContentGenerator::Instructor::PGProblemEditor2::pre_header_initialize called at line 183 of /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator.pm
in WeBWorK::ContentGenerator::go called at line 370 of /opt/webwork/webwork2/lib/WeBWorK.pm


//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================

#ifndef BASE_GAMESTATS_PARSE_H
#define BASE_GAMESTATS_PARSE_H
#ifdef _WIN32
#pragma once
#endif

enum CustomDataReturnCode
{
	CUSTOMDATA_NONE = 0,
	CUSTOMDATA_FAILED,
	CUSTOMDATA_SUCCESS
};

class IMySQL;

struct ParseContext_t
{
	char const *file;
	char const *gamename;
	bool		describeonly;
	IMySQL		*mysql;
	int			skipcount;
	bool		bCustomDirectoryNotMade;
};

void ProcessPerfData( IMySQL *pSQL, time_t fileTime, char const *pGameName, char const *pPerfString );

#endif // BASE_GAMESTATS_PARSE_H


Two neighboring kingdoms decided to build a wall between them with some gates to enable the citizens to go from one kingdom to another. Each time a citizen passes through a gate, he has to pay one silver coin.

The world can be represented by the first quadrant of a plane and the wall is built along the identity line (i.e. the line with the equation x = y). Any point below the wall belongs to the first kingdom while any point above the wall belongs to the second kingdom. There is a gate at any integer point on the line (i.e. at points (0, 0), (1, 1), (2, 2), ...). The wall and the gates do not belong to any of the kingdoms.

Fafa is at the gate at position (0, 0) and he wants to walk around in the two kingdoms. He knows the sequence S of moves he will do. This sequence is a string where each character represents a move. The two possible moves Fafa will do are 'U' (move one step up, from (x, y) to (x, y + 1)) and 'R' (move one step right, from (x, y) to (x + 1, y)).

Fafa wants to know the number of silver coins he needs to pay to walk around the two kingdoms following the sequence S. Note that if Fafa visits a gate without moving from one kingdom to another, he pays no silver coins. Also assume that he doesn't pay at the gate at point (0, 0), i. e. he is initially on the side he needs.


You are given an array $$$a$$$ of length $$$n$$$, and an integer $$$x$$$. You can perform the following operation as many times as you would like (possibly zero): replace two adjacent elements of the array by their sum. For example, if the initial array was $$$[3, 6, 9]$$$, in a single operation one can replace the last two elements by their sum, yielding an array $$$[3, 15]$$$, or replace the first two elements to get an array $$$[9, 9]$$$. Note that the size of the array decreases after each operation.

The beauty of an array $$$b=[b_1, \ldots, b_k]$$$ is defined as $$$\sum_{i=1}^k \left\lceil \frac{b_i}{x} \right\rceil$$$, which means that we divide each element by $$$x$$$, round it up to the nearest integer, and sum up the resulting values. For example, if $$$x = 3$$$, and the array is $$$[4, 11, 6]$$$, the beauty of the array is equal to $$$\left\lceil \frac{4}{3} \right\rceil + \left\lceil \frac{11}{3} \right\rceil + \left\lceil \frac{6}{3} \right\rceil = 2 + 4 + 2 = 8$$$.

Please determine the minimum and the maximum beauty you can get by performing some operations on the original array.


New Insertion Policy UI and API functionality to target insertion policies against tags.
New Insertion Policy functionality available in Pulse UI
Previously, you had to configure a unique insertion policy for each combination of category, device container, and content play length, which allowed for no flexibility and could result in many duplicate insertion policies. Any changes you wanted to make had to be separately entered for each combination.
- The tags specified in the insertion policy need to match at least one tag coming in the ad request to Pulse.
- You can rank the tag based insertion policies, so when more than one insertion policy matches the tag targeting coming in the ad request, then the insertion policy with the highest rank gets selected.
- If there are no matching tags, the old category based ad insertion policy acts as the default.
To access Insertion Policies in the Pulse UI, select Settings - Insertion Policy from the menu bar:
By default, you can create up to 50 insertion policies for your Pulse account and up to 20 tags per one insertion policy. Contact your Account Manager if you need to change these values.
New Insertion Policy API
- retrieve an insertion policy template,
- create and update insertion policies,
- update the rank of an insertion policy,
- and get information about insertion policies.
This release includes the following documentation updates:


Connected undirected weighted graph without self-loops and multiple edges is given. Graph contains n vertices and m edges.

For each edge (u, v) find the minimal possible weight of the spanning tree that contains the edge (u, v).

The weight of the spanning tree is the sum of weights of all edges included in spanning tree.


App developers may get their first glimpse at the new system starting today, with the release of the first developer preview of Privacy Sandbox on Android, following in the footsteps of previous tests in Google's Chrome browser on the desktop.
Last year, Apple added App Tracking Transparency to iOS, and the resulting shift in the data flow from mobile users shook even Facebook. Now, Google, whose business model is based on targeted advertising, is planning its multi-year adjustment to mobile ad tracking and privacy.
This new strategy is expected to replace Android's present advertising ID, which is a user-resettable ID for each device, with a Privacy Sandbox with "new, more private advertising solutions," similar to Apple's approach, but we still don't know which technology would be used. This developer preview runs on top of the Android 13 Developer Beta and includes images for Pixel phones ranging from the Pixel 4 to the Pixel 6.
Google's pitch has been that it can protect user privacy better than previous methods while still giving data for targeted advertising on websites like this one and inside many free apps. Competitors, privacy groups, and regulators have all said that Google's strategies will threaten privacy and possibly offer Google an unfair competitive edge. Last year, 15 state attorneys general filed an antitrust lawsuit against Google, targeting the Privacy Sandbox.
Developers who participate in the beta will receive an early peek at the Privacy Sandbox and Google's cookie-replacing Topics API, as well as learn how they might work in practice.


Barcode for .NET Free Download
Barcode for .NET
Barcode for .NET Free Download.
.NET library to generate barcode images, supports Linear (1D), PDF417, Data Matrix, MaxiCode, QRCode
Barcode for .NET keywords: bar code, linear, 2d pdf417, pdf417, one code, data matrix, datamatrix, maxicode
Java Barcode Reader
Barcode Reader for Java, a library to read barcode, supports Linear (1D), PDF417 (2D), Data Matrix, QRCode
Reporting Services Barcode CRI
This component creates barcodes in Microsoft Reporting Services as an integrated drag-and-drop Custom Report Item CRI control, without the use of barcode fonts. Includes installers for Reporting Services SQL Server 2005 and 2008.
VB Barcode Integration Kit
Integrate barcodes into VB 6 and Visual Basic .NET with this package. Select from several integration options. Includes documentation and encoder source code for both VB and VB Dotnet by IDAutomation .com.
TMS Smooth Controls Pack-Delphi6
Your applications never get a second chance on a first impression! Use feature-rich sophisticated looking & smoothly animated controls including calendar, listbox, imagelist, panel, buttons, pagecontrol, LEDs, spinner, jogwheel, gauge, step control...


Example protein complexes. White interactions indicate shared PPI between protein complexes. Purple nodes are bottleneck nodes. Protein complexes were obtained from DIP dataset and annotated using GO database (p-value < 0.01). Red interactions are core mediator complex, orange interactions are ubiquintin conjugating enzyme complex, yellow interactions are negative cofactor 2 complex and lime interactions are transcription factor TFIIF complex.