text:
#ifndef BOOST_ADAPTBX_GRAPH_MAXIMUM_CLIQUE_GREEDY_H
#define BOOST_ADAPTBX_GRAPH_MAXIMUM_CLIQUE_GREEDY_H

#include <boost_adaptbx/graph/vertex_map.hpp>

#include <boost/graph/graph_traits.hpp>
#include <boost/tuple/tuple.hpp>

#include <vector>
#include <set>
#include <queue>
#include <algorithm>
#include <iterator>
#include <utility>

namespace boost_adaptbx
{
namespace graph
{
namespace greedy
{

class maximum_clique_exception
{};

class bad_vertex_exception : public maximum_clique_exception
{};

template< typename AdjacencyGraph >
class partition
{
public:
  typedef AdjacencyGraph graph_type;
  typedef boost::graph_traits< AdjacencyGraph > graph_traits;
  typedef typename graph_traits::vertex_descriptor vertex_descriptor;
  typedef typename graph_traits::adjacency_iterator adjacency_iterator;

  typedef std::set< vertex_descriptor > vertex_set_type;
  typedef typename vertex_set_type::iterator vertex_set_iterator;
  typedef typename vertex_set_type::const_iterator vertex_set_const_iterator;

private:
  vertex_set_type clique_;
  vertex_set_type neighbours_;

public:
  partition(graph_type const& graph)
    : neighbours_( boost::vertices( graph ).first, boost::vertices( graph ).second )
  {}

  vertex_set_type const& clique() const
  {
    return clique_;
  }

  vertex_set_type const& neighbours() const
  {
    return neighbours_;
  }

  void add(graph_type const& graph, vertex_descriptor vertex)
  {
    if ( neighbours_.find( vertex ) == neighbours_.end() )
    {
      throw bad_vertex_exception();
    }

    clique_.insert( vertex );

    adjacency_iterator v, vend;
    boost::tie( v, vend ) = boost::adjacent_vertices( vertex, graph );
    vertex_set_type adjacents( v, vend );

    vertex_set_iterator it1 = neighbours_.begin();
    vertex_set_iterator it2 = adjacents.begin();

    while ( ( it1 != neighbours_.end() ) && ( it2 != adjacents.end() ) )
    {
      if ( *it1 < *it2 )
      {
        neighbours_.erase( it1++ );
      }
      else if ( *it2 < *it1 )
      {
        ++it2;
      }
      else
      {
        ++it1;
        ++it2;
      }
    }

    neighbours_.erase( it1, neighbours_.end() );
  }
};

template< typename Partition >
struct degree_scorer
{
  typedef Partition partition_type;
  typedef typename partition_type::vertex_set_type vertex_set_type;
  typedef typename vertex_set_type::size_type set_size_type;
  typedef set_size_type result_type;

public:
  degree_scorer()
  {}

  result_type operator ()(partition_type const& partition) const
  {
    return result_type( partition.neighbours().size() );
  }
};

template< typename AdjacencyGraph, typename Partition >
struct exdegree_scorer
{
  typedef AdjacencyGraph graph_type;
  typedef boost::graph_traits< AdjacencyGraph > graph_traits;
  typedef typename graph_traits::adjacency_iterator adjacency_iterator;
  typedef typename graph_traits::vertices_size_type vertices_size_type;
  typedef typename graph_traits::vertex_descriptor vertex_descriptor;
  typedef typename graph_traits::vertex_iterator vertex_iterator;

  typedef Partition partition_type;
  typedef typename partition_type::vertex_set_type vertex_set_type;
  typedef typename vertex_set_type::size_type set_size_type;
  typedef typename vertex_set_type::const_iterator vertices_set_const_iterator;
  typedef std::pair< set_size_type, vertices_size_type > result_type;

private:
  graph_type const& graph_;

public:
  exdegree_scorer(graph_type const& graph)
    : graph_( graph )
  {}

  result_type operator ()(partition_type const& partition) const
  {
    vertices_size_type vertices_count( 0 );
    adjacency_iterator av, avend;
    vertex_set_type const& neighbours = partition.neighbours();

    for (
      vertices_set_const_iterator it = neighbours.begin();
       it != neighbours.end();
       ++it
       )
    {
      boost::tie( av, avend ) = boost::adjacent_vertices( *it, graph_ );
      vertices_count += std::distance( av, avend );
    }

    return result_type( neighbours.size(), vertices_count );
  }
};

template< typename AdjacencyGraph, typename Partition >
struct exdegree_scorer_cached
{
  typedef AdjacencyGraph graph_type;
  typedef boost::graph_traits< AdjacencyGraph > graph_traits;
  typedef typename graph_traits::adjacency_iterator adjacency_iterator;
  typedef typename graph_traits::vertices_size_type vertices_size_type;
  typedef typename graph_traits::vertex_descriptor vertex_descriptor;
  typedef typename graph_traits::vertex_iterator vertex_iterator;

  typedef vertex_map::generic_vertex_map< graph_type, vertices_size_type >
    vertex_exdegree_mapping_type;
  typedef typename vertex_exdegree_mapping_type::property_map_type
    vertex_exdegree_property_map_type;

  typedef Partition partition_type;
  typedef typename partition_type::vertex_set_type vertex_set_type;
  typedef typename vertex_set_type::size_type set_size_type;
  typedef typename vertex_set_type::const_iterator vertices_set_const_iterator;
  typedef std::pair< set_size_type, vertices_size_type > result_type;

private:
  vertex_exdegree_mapping_type exdegree_for_;

public:
  exdegree_scorer_cached(graph_type const& graph) : exdegree_for_( graph )
  {
    vertex_iterator v, vend;
    adjacency_iterator av, avend;
    vertex_exdegree_property_map_type ve_propmap( exdegree_for_.get() );

    for ( boost::tie( v, vend ) = boost::vertices( graph ); v != vend; ++v )
    {
      boost::tie( av, avend ) = boost::adjacent_vertices( *v, graph );
      boost::put( ve_propmap, *v, std::distance( av, avend ) );
    }
  }

  result_type operator ()(partition_type const& partition) const
  {
    vertices_size_type vertices_count( 0 );
    vertex_set_type const& neighbours = partition.neighbours();
    vertex_exdegree_property_map_type ve_propmap( exdegree_for_.get() );

    for (
      vertices_set_const_iterator it = neighbours.begin();
      it != neighbours.end();
      ++it
      )
    {
      vertices_count += boost::get( ve_propmap, *it );
    }

    result_type( neighbours.size(), vertices_count );
  }
};

template< typename Pair >
struct greater_on_second_type
{
  typedef typename Pair::second_type score_type;

  bool operator ()(Pair const& lhs, Pair const& rhs) const
  {
    return lhs.second > rhs.second;
  }
};

template< typename AdjacencyGraph, typename Scorer >
std::vector< partition< AdjacencyGraph > >
maximum_clique(
  AdjacencyGraph const& graph,
  Scorer const& scorer = Scorer(),
  std::size_t maxsol = 0
  )
{
  typedef boost::graph_traits< AdjacencyGraph > graph_traits;
  typedef typename graph_traits::vertex_iterator vertex_iterator;

  typedef partition< AdjacencyGraph > partition_type;
  typedef typename partition_type::vertex_set_type vertex_set_type;
  typedef typename partition_type::vertex_set_const_iterator vertex_set_const_iterator;

  typedef std::vector< partition_type > partition_list;
  typedef typename partition_list::const_iterator partition_const_iterator;

  typedef Scorer scorer_type;
  typedef typename scorer_type::result_type score_type;
  typedef std::pair< partition_type, score_type > partition_score_data;
  typedef greater_on_second_type< partition_score_data > ranker_type;
  typedef std::priority_queue<
    partition_score_data,
    std::vector< partition_score_data >,
    ranker_type >
    partition_data_priority_queue;

  typedef std::set< vertex_set_type > clique_set_type;

  if ( maxsol == 0 )
  {
    vertex_iterator v, vend;
    boost::tie( v, vend ) = boost::vertices( graph );
    maxsol = std::distance( v, vend );
  }
  assert ( 0 < maxsol );

  partition_list solutions;
  solutions.push_back( partition_type( graph ) );
  partition_data_priority_queue solution_queue;
  clique_set_type known_cliques;

  while ( true )
  {
    assert ( solution_queue.empty() );

    for (
      partition_const_iterator pit = solutions.begin();
      pit != solutions.end();
      ++pit
      )
    {
      vertex_set_type const& neighbours = pit->neighbours();

      for (
        vertex_set_const_iterator nit = neighbours.begin();
        nit != neighbours.end();
        ++nit
        )
      {
        partition_type nextpart( *pit );
        nextpart.add( graph, *nit );
        score_type nextscore = scorer( nextpart );

        if ( solution_queue.size() < maxsol )
        {
          if ( known_cliques.insert( nextpart.clique() ).second )
          {
            solution_queue.push( partition_score_data( nextpart, nextscore ) );
          }
        }

        else if ( solution_queue.top().second < nextscore )
        {
          if ( known_cliques.insert( nextpart.clique() ).second )
          {
            known_cliques.erase( solution_queue.top().first.clique() );
            solution_queue.pop();
            solution_queue.push( partition_score_data( nextpart, nextscore ) );
          }
        }
      }
    }

    assert ( solution_queue.size() <= maxsol );

    if ( solution_queue.size() == 0 )
    {
      break;
    }

    solutions.clear();

    while ( !solution_queue.empty() )
    {
      solutions.push_back( solution_queue.top().first );
      solution_queue.pop();
    }

    known_cliques.clear();
  }

  return solutions;
}

} // namespace greedy
} // namespace graph
} // namespace boost_adaptbx

#endif // BOOST_ADAPTBX_GRAPH_MAXIMUM_CLIQUE_GREEDY_H

ext: hpp


text:
//
// Created by miguelyermo on 23/7/20.
//

#include "AccumTime.h"
#include "convexHull.hpp"
#include "handlers.h"
#include "laspec.h"
#include "pseudoInverseMoorePenrose.h"
#include "SMRF.h"

#include <algorithm>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <limits>
#include <map>
#include <memory>
#include <omp.h>
#include <ostream>
#include <stack>
#include <utility>
#include <vector>

//
// Created by miguelyermo on 9/7/20.
//

/*
* FILENAME :  dtm.h
* PROJECT  :  rule-based-classifier-cpp
* DESCRIPTION : Creation and handling of a dtm.
*
*
*
*
*
* AUTHOR :    Miguel Yermo        START DATE : 09:20 9/7/20
*
*/

namespace SMRF
{

constexpr unsigned g_cluster_max_size{ 128 };

void classify(std::vector<Lpoint> & points, DTMGrid & dtm)
{
	int count = 0;

	std::ofstream f(mainOptions.outputDirName + "/smrf/result.xyz");

	f << std::fixed << std::setprecision(3);

	std::cout << "Labeling points...\n";

	for (Lpoint & p : points)
	{
		double dtmZ = dtm.nnInterpolation(p);
		p.setClass(p.z() < dtmZ + MAX_HEIGHT ? GROUND : UNCLASSIFIED);
		count += p.getClass() == GROUND;
		f << p.x() << " " << p.y() << " " << p.z() << " "
			<< p.I() << " " << p.rn() << " " << p.nor() << " " << p.dir() << " " << p.edge()
			<< " " << p.getClass() << "\n";
	}
	std::cout << "Ground " << count / double(points.size()) * 100 << "%\n";
}

/* Distance from point to cell center */
double distP2C(Lpoint & p, DTMCell * cell)
{
	return sqrt((p.x() - cell->center[0]) * (p.x() - cell->center[0]) +
	            (p.y() - cell->center[1]) * (p.y() - cell->center[1]));
}

/* Ensure neighbors indices are inside grid boundaries **/
inline void DTMGrid::clampNeighIdcs(int ci, int cj, int r, int min[2], int max[2]) const
{
	min[0] = ci - r >= 0 ? ci - r : 0;
	min[1] = cj - r >= 0 ? cj - r : 0;
	max[0] = ci + r < rows ? ci + r : rows - 1;
	max[1] = cj + r < cols ? cj + r : cols - 1;
}

/** Get non-empty neighboring cells in (row,col) pairs for a given radius (starts from left-bottom) */
// TODO: Funcion muy optimizable si se asignan los vecinos al crear la malla
// (8 vecinos salvo en esquinas y bordes) Ver computeCellNeighbors()
// Tambien son necesarios los vecinos de orden superior
inline std::vector<size_t> DTMGrid::getNeighCells(int Ci, int Cj, int r)
{
	int min[2], max[2], maxNeighs = 0;

	clampNeighIdcs(Ci, Cj, r, min, max);
	maxNeighs = (2 * r + 1) * (2 * r + 1) - 1;
	std::vector<size_t> neighs;
	neighs.reserve(2 * maxNeighs);
	for (size_t i = min[0]; i <= max[0]; i++)
		for (size_t j = min[1]; j <= max[1]; j++)
			if ((i != Ci || j != Cj) && (!cells[i * cols + j].empty || cells[i * cols + j].inpainted))
			{
				neighs.push_back(i);
				neighs.push_back(j);
			}
	return neighs;
}

double DTMGrid::nnInterpolation(Lpoint& p)
{
	int    Ci = 0, Cj = 0, i = 0, j = 0, n = 0;
	double dist = 0, minDist = 0, z = 0;
	Ci                         = ci[p.id()];
	Cj                         = cj[p.id()];
	z                          = cells[Ci * cols + Cj].z;
	minDist                    = distP2C(p, &cells[Ci * cols + Cj]);
	std::vector<size_t> neighs = getNeighCells(Ci, Cj, 1);
	for (n = 0; n < neighs.size(); n += 2)
	{
		i = neighs[n];
		j = neighs[n + 1];
		if ((int) cells[i * cols + j].z == NO_DATA_VAL) continue;
		dist = distP2C(p, &cells[i * cols + j]);
		if (dist < minDist)
		{
			z       = cells[i * cols + j].z;
			minDist = dist;
		}
	}
	return z;
}

double DTMGrid::slopeInterpolation(Lpoint & p)
{
	int    Ci = 0, Cj = 0, i = 0, j = 0, n = 0;
	double dist = 0, minDist = 0, slope = 0;
	Ci                         = ci[p.id()];
	Cj                         = cj[p.id()];
	slope                      = cells[Ci * cols + Cj].slope;
	minDist                    = distP2C(p, &cells[Ci * cols + Cj]);
	std::vector<size_t> neighs = getNeighCells(Ci, Cj, 1);
	for (n = 0; n < neighs.size(); n += 2)
	{
		i = neighs[n];
		j = neighs[n + 1];
		if ((int) cells[i * cols + j].z == NO_DATA_VAL) continue;
		dist = distP2C(p, &cells[i * cols + j]);
		if (dist < minDist)
		{
			slope   = cells[i * cols + j].slope;
			minDist = dist;
		}
	}
	return slope;
}

void DTMGrid::computeDtmZ(std::vector<Lpoint> & points, Octree & octree)
{
	std::cout << "Computing dtm...\n";

	for (auto& p : points)
	{
		p.setSlopeDTM(slopeInterpolation(p));
		p.setDtmZ(nnInterpolation(p));
		// TODO: check DTM and solve the bug to avoid it
		if ((p.z() - p.getDtmZ()) < 0)
			p.setRealZ(0.01);
		else
			p.setRealZ(p.z() - p.getDtmZ());
	}
}

/** Compare pairs by value (descending order) */
static int pairCmpDesc(const void * p1, const void * p2)
{
	int v1 = ((Pair *) p1)->value;
	int v2 = ((Pair *) p2)->value;
	return v2 - v1;
}

static int cmpX(const void * a, const void * b)
{
	double v1 = ((struct Coordinate *) a)->value;
	double v2 = ((struct Coordinate *) b)->value;

	return (v1 > v2) - (v1 < v2);
}

extern DTMGrid* createGridDTM(double * min, double * max, int numPts, double cs)
{
	int       i = 0, j = 0;
	double    r    = cs / 2.0;
	DTMGrid * grid = nullptr;

	grid         = new DTMGrid;
	grid->min[0] = ceil(min[0]);
	grid->min[1] = ceil(min[1]);
	grid->rows   = ceil((floor(max[0]) - grid->min[0]) / cs);
	grid->cols   = ceil((floor(max[1]) - grid->min[1]) / cs);
	grid->size   = grid->rows * grid->cols;
	grid->ci.resize(numPts);
	grid->cj.resize(numPts);
	grid->cells.resize(grid->size);
	for (i = 0; i < grid->rows; i++)
	{
		for (j = 0; j < grid->cols; j++)
		{
			grid->cells[i * grid->cols + j].id        = i * grid->cols + j;
			grid->cells[i * grid->cols + j].obj       = false;
			grid->cells[i * grid->cols + j].empty     = true;
			grid->cells[i * grid->cols + j].inpainted = false;
			grid->cells[i * grid->cols + j].center[0] = grid->min[0] + (i * cs) + r;
			grid->cells[i * grid->cols + j].center[1] = grid->min[1] + (j * cs) + r;
			grid->cells[i * grid->cols + j].z         = std::numeric_limits<double>::max();
		}
	}
	return grid;
}

/** Get the adjacent cells for BE Surface */
std::vector<indexOfCell_t> DTMGrid::getAdjCellsBE(int ci, int cj)
{
	int min[2], max[2];

	clampNeighIdcs(ci, cj, 1, min, max);

	std::vector<indexOfCell_t> neighs{};

	for (int i = min[0]; i <= max[0]; i++)
		for (int j = min[1]; j <= max[1]; j++)
		{
			if ((i != ci || j != cj) && cells[i * cols + j].inhull)
			{
				neighs.emplace_back(i, j);
			}
		}
	return neighs;
}

/** Get the adjacent cells for Minimun Surface */
std::vector<indexOfCell_t> DTMGrid::getAdjCellsMS(int Ci, int Cj)
{
	int min[2], max[2]; // range of index for neighbours

	clampNeighIdcs(Ci, Cj, 1, min, max);
	std::vector<indexOfCell_t> neighs{};

	for (int i = min[0]; i <= max[0]; i++)
		for (int j = min[1]; j <= max[1]; j++)
			if ((i != Ci || j != Cj) && cells[i * cols + j].inhull)
				neighs.emplace_back(i, j);

	return neighs;
}

/** Check if a set have at least one cell which is not object */
bool checkFullObj(DTMGrid *grid, std::vector<indexOfCell_t>& vec)
{
	for(const auto& cell : vec)
	{
		int pos{cell.first * grid->cols + cell.second};
		if (!grid->cells[pos].obj || (grid->cells[pos].obj && grid->cells[pos].inpainted))
		{
			return false;
		}
	}
	return true;
}

/** Filter the set taking object cells */
std::vector<indexOfCell_t> checkForObjCells(DTMGrid *grid, std::vector<indexOfCell_t>& vec)
{
	std::vector<indexOfCell_t> tmp{};
	for (const auto& cell : vec)
	{
		int pos{cell.first * grid->cols + cell.second};
		if (grid->cells[pos].obj && !grid->cells[pos].inpainted)
			tmp.emplace_back(cell);
	}
	return tmp;
}

void DTMGrid::createClusters(std::vector<indexOfCell_t>& inpaintCells, std::map<indexOfCell_t, std::vector<indexOfCell_t>>& neighbourCells,
		std::vector<Cluster>& clusters, ListNeighsFn listNeighsFn, CheckNeighsFn chNeighsFn)
{
	std::vector<indexOfCell_t> remainingCells(inpaintCells);

	while (!remainingCells.empty())
	{
		Cluster cluster{};
		// stackCheckCell: cola que contén as celas baleiras adxacentes pendentes de comprobar
		// se teñen a súa vez máis celas adxacentes
		std::stack<indexOfCell_t> stackCells{};

		stackCells.emplace(remainingCells[0]);

		// introducimos a primeira cela das que quedan por facer o inpainting
		// bucle para buscar veciños
		while (!stackCells.empty())
		{
			auto& cell = stackCells.top();
			stackCells.pop();

			// evita que caia en bucle infinito: para que non volva a revisar a mesma cela
			auto begin(remainingCells.begin());
			auto end(remainingCells.end());
			if (std::find(begin, end, cell) == end)
			{
				continue;
			}

			std::vector<indexOfCell_t> neighbours;

			neighbours = neighbourCells.at(cell);

			// quitamos esa cela da lista de pendentes por ver
			std::erase(remainingCells, cell);

            // anotamos esa cela para despois usala no sistema de ecuacións
			cluster.emplace_back(cell);

            // lista de veciños do mesmo tipo da cela extraida
			auto listNeighs(listNeighsFn(this, neighbours));

			for (int pos = 0; pos < listNeighs.size(); ++pos)
			{
				auto& empty = listNeighs[pos];
				stackCells.push(empty);
			}
		}
		clusters.emplace_back(cluster);
	}
}

void DTMGrid::solveSystems(std::vector<Cluster>& clusters, std::map<indexOfCell_t, std::vector<indexOfCell_t>>& neighbourCells,
	CheckValueCellFn chValueCellFn, ListNeighsFn listNeighsFn, CheckNeighsFn chNeighsFn, ChangeCellStateFn chCellStateFn)
{
	/* resolución dos clusters */
	for (auto pos{clusters.begin()}; pos != clusters.end(); ++pos)
	{
		Cluster cluster{*pos};

		while (!cluster.empty())
		{
			int col{};
			std::vector<indexOfCell_t> columns{};
			std::stack<indexOfCell_t> stackCells{};

			stackCells.emplace(cluster[0]);

			while (!stackCells.empty() && columns.size() < g_cluster_max_size)
			{
				auto& cell = stackCells.top();
				stackCells.pop();

				// evita que caia en bucle infinito: para que non volva a revisar a mesma cela
				auto begin{cluster.begin()};
				auto end{cluster.end()};
				if (std::find(begin, end, cell) == end)
				{
					continue;
				}

				auto neighbours(neighbourCells.at(cell));
				if (chNeighsFn(this, neighbours))
				{
					if (columns.empty())
					{
						std::erase(cluster, cell);
						cluster.emplace_back(cell);
						stackCells.emplace(cluster[0]);
					}
					continue;
				}

				// quitamos esa cela da lista de pendentes por ver
				std::erase(cluster, cell);

				// anotamos esa cela para despois usala no sistema de ecuacións
				columns.emplace_back(cell);

				// lista de veciños do mesmo tipo da cela extraida
				auto listNeighs(listNeighsFn(this, neighbours));

				for (auto neigh{listNeighs.begin()}; neigh != listNeighs.end(); ++neigh)
				{
					stackCells.push(*neigh);
				}
			}

			Eigen::MatrixXd M{columns.size() * 8, columns.size()};
			M.setZero();
			Eigen::VectorXd b{columns.size() * 8};
			b.setZero();

			auto columnBegin{columns.begin()};
			auto columnEnd{columns.end()};

			int currentRow{};
			for (int posCell{}; posCell < columns.size(); ++posCell)
			{
				auto cell{columns[posCell]};
				auto local{neighbourCells.at(cell)};

				int currentCol(posCell);

				// obtemos os valores Z das celas veciñas
				for (int posNeigh = 0; posNeigh < local.size(); ++posNeigh)
				{
					bool emptyNeigh{false};
                    std::vector<indexOfCell_t>::iterator found{};
                    indexOfCell_t neighbour(local[posNeigh]);

                    emptyNeigh = chValueCellFn(this, neighbour);
					found = std::find(columnBegin, columnEnd, neighbour);

					if (emptyNeigh && found == columnEnd)
						continue;

					double z{emptyNeigh ? 0.0 : cells[neighbour.first * cols + neighbour.second].z};

					if (emptyNeigh)
					{
						M(currentRow, std::distance(columnBegin, found)) = -1.0;
					}

					M(currentRow, currentCol) = 1.0;
					b[currentRow] = z;

					++currentRow;
				}
			}

			Eigen::VectorXd x = pseudoInverse(M) * b;

			for (int posCell = 0; posCell < columns.size(); ++posCell)
			{
				auto cell{columns[posCell]};
				cells[cell.first * cols + cell.second].z = x[posCell];
				chCellStateFn(this, cell);
			}
		}
	}
}

bool isObj(DTMGrid* grid, indexOfCell_t cell)
{
	return grid->cells[cell.first * grid->cols + cell.second].obj;
}

void changeObjToFalse(DTMGrid* grid, indexOfCell_t& cell)
{
	grid->cells[cell.first * grid->cols + cell.second].obj = false;
	grid->cells[cell.first * grid->cols + cell.second].inpainted = true;
}

/** Inpaint Bare Earth */
void DTMGrid::inpaintBE()
{
	std::vector<indexOfCell_t> vectorOfObjCells{};

	// assign column for every cell
	for (int i = 0; i < rows; ++i)
		for (int j = 0; j < cols; ++j)
			if (cells[i * cols + j].inhull && cells[i * cols + j].obj)
			{
				vectorOfObjCells.emplace_back(std::make_pair(i, j));
			}

	const int numObj{static_cast<int>(vectorOfObjCells.size())};
	std::cout << numObj << " obj cells " << numObj * 100.0 / size << "%\n";
	std::cout << "Inpainting... " << std::flush;

	// collemos tódolas celas baleiras e almacenamos os seus veciños nunha lista
	std::map<indexOfCell_t, std::vector<indexOfCell_t>> neighbourOfObjCells{};
	// remainingCells contén as celas restantes para o inpainting (inicialmente todas)

	for (int pos = 0; pos < vectorOfObjCells.size(); ++pos)
	{
		auto cell{vectorOfObjCells.at(pos)};
		neighbourOfObjCells.emplace(cell, getAdjCellsBE(cell.first, cell.second));
	}

	auto chValueFn{ &isObj };
	auto chCellStateFn{ &changeObjToFalse };
	auto lsNeighsFn{ &checkForObjCells };
	auto chNeighsFn{ &checkFullObj};

	std::vector<Cluster> clusters{};

	createClusters(vectorOfObjCells, neighbourOfObjCells, clusters, lsNeighsFn, chNeighsFn);
	solveSystems(clusters, neighbourOfObjCells, chValueFn, lsNeighsFn, chNeighsFn, chCellStateFn);

	std::cout << numObj << " inpainted" << '\n';
}

/** Get number of valid adjacent cells for Minimum Surface */
int DTMGrid::getNumAdjMS(int Ci, int Cj)
{
	int num = 0, min[2], max[2];

	clampNeighIdcs(Ci, Cj, 1, min, max);
	for (size_t i = min[0]; i <= max[0]; i++)
		for (size_t j = min[1]; j <= max[1]; j++)
			if ((i != Ci || j != Cj) && (!cells[i * cols + j].empty || cells[i * cols + j].inpainted)) num++;
	return num;
}

bool areAdjacent(indexOfCell_t c1, indexOfCell_t c2)
{
	// first, we check if c2 is in a near row
	if (c1.first == c2.first || c1.first == c2.first + 1 || c1.first == c2.first - 1)
		// second, the same with the column
		if (c1.second == c2.second || c1.second == c2.second + 1 || c1.second == c2.second - 1)
			return true;

	return false;
}

bool checkFullEmpty(DTMGrid *grid, std::vector<indexOfCell_t> & vec)
{
	for(auto cell{vec.begin()}; cell != vec.end(); ++cell)
	{
		int pos{cell->first * grid->cols + cell->second};
		if (!grid->cells[pos].empty || (grid->cells[pos].empty && grid->cells[pos].inpainted))
		{
			return false;
		}
	}
	return true;
}

std::vector<indexOfCell_t> checkForEmptyCells(DTMGrid *grid, std::vector<indexOfCell_t> & vec)
{
	std::vector<indexOfCell_t> tmp{};

	for (auto& cell : vec)
	{
		int pos{cell.first * grid->cols + cell.second};
		if (grid->cells[pos].empty && !grid->cells[pos].inpainted)
			tmp.emplace_back(cell);
	}
	return tmp;
}

void changeInpaintedToTrue(DTMGrid *grid, indexOfCell_t& cell)
{
	grid->cells[cell.first * grid->cols + cell.second].inpainted = true;
}

bool isEmpty(DTMGrid* grid, indexOfCell_t cell)
{
	return grid->cells[cell.first * grid->cols + cell.second].empty && !grid->cells[cell.first * grid->cols + cell.second].inpainted;
}

/** Inpaint Minimum Surface */
void DTMGrid::inpaintMS(std::vector<indexOfCell_t>& vectorOfEmptyCells)
{
	const int numEmpty(vectorOfEmptyCells.size());
	std::cout << "Inpainting... " << std::flush;

	// collemos tódolas celas baleiras e almacenamos os seus veciños nunnha lista
	std::map<indexOfCell_t, std::vector<indexOfCell_t>> neighbourOfEmptyCells{};

	for (int pos = 0; pos < vectorOfEmptyCells.size(); ++pos)
	{
		auto& cell{vectorOfEmptyCells.at(pos)};
		neighbourOfEmptyCells.emplace(cell, getAdjCellsMS(cell.first, cell.second));
	}

	auto chValueFn{ &isEmpty };
	auto chCellStateFn{ &changeInpaintedToTrue };
	auto lsNeighsFn{ &checkForEmptyCells };
	auto chNeighsFn{ &checkFullEmpty };

	std::vector<Cluster> clusters{};

	createClusters(vectorOfEmptyCells, neighbourOfEmptyCells, clusters, lsNeighsFn, chNeighsFn);
	solveSystems(clusters, neighbourOfEmptyCells, chValueFn, lsNeighsFn, chNeighsFn, chCellStateFn);

	std::cout << numEmpty << " inpainted" << '\n';
}

/** Generate a minimun surface with the lowest cell points */
void DTMGrid::genMinSurface(Octree & octree, ConvexHull & hull)
{
	Lpoint center(0, 0, 0, 0);
	std::vector<indexOfCell_t> emptyCells{};

	for (int i{}; i < rows; ++i)
		for (int j{}; j < cols; ++j)
		{
			center.id(-1);
			center.setX(cells[i * cols + j].center[0]);
			center.setY(cells[i * cols + j].center[1]);
			cells[i * cols + j].inhull = hull.inHull(center);
			if (!cells[i * cols + j].inhull) continue;
			std::vector<Lpoint *> points = octree.searchNeighbors2D(center, CELL_SIZE);
			if (!points.empty())
			{
				for (int k{}; k < points.size(); ++k)
				{
					ci[points[k]->id()] = i;
					cj[points[k]->id()] = j;
					if (points[k]->z() < cells[i * cols + j].z) cells[i * cols + j].z = points[k]->z();
				}
				cells[i * cols + j].empty = false;
			}
			else
			{
				emptyCells.emplace_back(std::make_pair(i, j));
			}
		}

	int numEmpty{static_cast<int>(emptyCells.size())};

	std::cout << std::setprecision(2);
	std::cout << numEmpty << " empty cells " << numEmpty * 100.0 / size << "%\n";
	AccumTime::instance().start();
	inpaintMS(emptyCells);
	AccumTime::instance().stop("Inpaint Minimum Surface");
}

/** Perform morphological opening */
DTMGrid DTMGrid::morphologicalOpening(int radius, int numPts)
{
	int i = 0, j = 0, n = 0, ni = 0, nj = 0, numNeighs = 0;

	DTMGrid eGrid = *this;

#pragma omp parallel for default(none) private(i, j, n, ni, nj, numNeighs) \
    shared(radius, eGrid)
	for (i = 0; i < rows; i++) // Erosion
		for (j = 0; j < cols; j++)
		{
#if USE_DISK
			neighs = getDiskNeighCells(grid, i, j, radius, &numNeighs);
#else
			std::vector<size_t> neighs = getNeighCells(i, j, radius);
#endif
			for (n = 0; n < neighs.size(); n += 2)
			{
				ni = neighs[n];
				nj = neighs[n + 1];
				if (cells[ni * cols + nj].z < eGrid.cells[i * cols + j].z) eGrid.cells[i * cols + j].z = cells[ni * cols + nj].z;
			}
		}

	DTMGrid oGrid = eGrid;
#pragma omp parallel for default(none) private(i, j, n, ni, nj, numNeighs) \
    shared(radius, eGrid, oGrid)
	for (i = 0; i < eGrid.rows; i++) // Dilation
		for (j = 0; j < eGrid.cols; j++)
		{
#if USE_DISK
			neighs = getDiskNeighCells(eGrid, i, j, radius, &numNeighs);
#else
			std::vector<size_t> neighs = eGrid.getNeighCells(i, j, radius);
#endif
			for (n = 0; n < neighs.size(); n += 2)
			{
				ni = neighs[n];
				nj = neighs[n + 1];
				if (eGrid.cells[ni * cols + nj].z > oGrid.cells[i * cols + j].z)
					oGrid.cells[i * cols + j].z = eGrid.cells[ni * cols + nj].z;
			}
		}

	return oGrid;
}

void getMinMaxCoordinates(std::vector<Lpoint> & points, double * min, double * max)
{
	min[0] = min[1] = min[2] = std::numeric_limits<double>::max();
	max[0] = max[1] = max[2] = -std::numeric_limits<double>::max();
	for (auto & p : points)
	{
		if (p.x() < min[0]) min[0] = p.x();
		if (p.y() < min[1]) min[1] = p.y();
		if (p.z() < min[2]) min[2] = p.z();
		if (p.x() > max[0]) max[0] = p.x();
		if (p.y() > max[1]) max[1] = p.y();
		if (p.z() > max[2]) max[2] = p.z();
	}
}

/** Calculate plane slope by average maximum technique (ArGIS)
 *  @todo Handle slope when the cell it's at the grid boundary
 */
void DTMGrid::calcSlopes()
{
	double a = 0, b = 0, c = 0, d = 0, f = 0, g = 0, h = 0, I = 0, dzdx = 0, dzdy = 0,
	       rise = 0;

	for (int i = 0; i < rows; i++)
		for (int j = 0; j < cols; j++)
			if (!cells[i * cols + j].empty || cells[i * cols + j].inpainted)
			{
				std::vector<size_t> neighs = getNeighCells(i, j, 1);
				if (neighs.size() == 16)
				{
					g                 = cells[neighs[0] * cols + neighs[1]].z;
					h                 = cells[neighs[2] * cols + neighs[3]].z;
					I                 = cells[neighs[4] * cols + neighs[5]].z;
					d                 = cells[neighs[6] * cols + neighs[7]].z;
					f                 = cells[neighs[8] * cols + neighs[9]].z;
					a                 = cells[neighs[10] * cols + neighs[11]].z;
					b                 = cells[neighs[12] * cols + neighs[13]].z;
					c                 = cells[neighs[14] * cols + neighs[15]].z;
					dzdx              = ((c + 2 * f + I) - (a + 2 * d + g)) / (8 * CELL_SIZE);
					dzdy              = ((g + 2 * h + I) - (a + 2 * b + c)) / (8 * CELL_SIZE);
					rise              = sqrt(dzdx * dzdx + dzdy * dzdy);
					cells[i * cols +j].slope = atan(rise) * 180 / M_PI;
				}
				else
				{
					// see todo
				}
			}
}

void DTMGrid::computeDTM(std::vector<Lpoint>& points, Octree & octree, double * Min,
                         double * max)
{
	AccumTime::instance().start();
	ConvexHull hull(points);
	AccumTime::instance().stop("Computing Convex Hull");

	// medición de inpaintMS no interior
	genMinSurface(octree, hull);

	AccumTime::instance().start();
	identifyCells(points.size());
	AccumTime::instance().stop("Identifying cells");

	AccumTime::instance().start();
	identifyOutliers(points.size(), Min[2], max[2]);
	AccumTime::instance().stop("Identifying outliers");

	AccumTime::instance().start();
	inpaintBE();
	AccumTime::instance().stop("Inpainting Bare Earth");
}

/** Improved Simple Morphological Filter (SMRF) (Pingel, 2013) */
DTMGrid smrf(std::vector<Lpoint> & points, Octree & octree, double min[3], double max[3])
{
	std::cout << "---- Computing DTM (SMRF) ----\n";
	DTMGrid dtm(min, max, points.size(), CELL_SIZE);
	dtm.computeDTM(points, octree, min, max);

	dtm.calcSlopes();
	dtm.computeDtmZ(points, octree);

	std::string outDir = mainOptions.outputDirName + "/smrf";
	createDirectory(outDir);
	dtm.writeToFile(outDir + "/dtm.xyz");
	dtm.createDTM(outDir + "/dtm.asc");

	classify(points, dtm);

	return dtm;
}

DTMGrid::DTMGrid(double * min, double * max, int numPts_, double cs)
{
	int    i = 0, j = 0;
	double r = cs / 2.0;

	min[0] = ceil(min[0]);
	min[1] = ceil(min[1]);
	cols   = ceil((floor(max[0]) - min[0]) / cs);
	rows   = ceil((floor(max[1]) - min[1]) / cs);
	size   = rows * cols;
	numPts = numPts_;
	ci.resize(numPts);
	cj.resize(numPts);
	cells.resize(size);

	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			cells[i * cols + j].id        = i * cols + j;
			cells[i * cols + j].obj       = false;
			cells[i * cols + j].empty     = true;
			cells[i * cols + j].inpainted = false;
			cells[i * cols + j].center[0] = min[0] + (j * cs) + r;
			cells[i * cols + j].center[1] = min[1] + (i * cs) + r;
			cells[i * cols + j].z         = std::numeric_limits<double>::max();
		}
	}

	std::cout << "Cols: " << cols << ", Rows: " <<  rows << "\n";
}

// Copy Constructor
DTMGrid::DTMGrid(const DTMGrid & dtm)
{
	rows  = dtm.rows;
	cols  = dtm.cols;
	size  = dtm.size;
	ci    = dtm.ci;
	cj    = dtm.cj;
	min   = dtm.min;
	cells = dtm.cells;
}

void DTMGrid::identifyOutliers(int numPts_, double minZ, double maxZ)
{
	int     i = 0, j = 0, count = 0;
	double  maxHeight = 0;
	DTMGrid oInvMinSurface;

	std::cout << "Identifying outliers... " << std::flush;

	DTMGrid invMinSurface = *this;

	for (i = 0; i < invMinSurface.rows; i++)
		for (j = 0; j < invMinSurface.cols; j++)
			invMinSurface.cells[i * cols + j].z = (maxZ + minZ) - invMinSurface.cells[i * cols + j].z;

	maxHeight      = 5 * MAX_SLOPE * 1 * CELL_SIZE;
	oInvMinSurface = invMinSurface.morphologicalOpening(1, numPts_);

	for (i = 0; i < invMinSurface.rows; i++)
		for (j = 0; j < invMinSurface.cols; j++)
			if (invMinSurface.cells[i * cols + j].z - oInvMinSurface.cells[i * cols + j].z > maxHeight)
			{
				cells[i * cols + j].obj = true;
				count++;
			}
	std::cout << count << " outliers\n";
}

void DTMGrid::identifyCells(int numPts_)
{
	int     maxWindow = 0;
	double  maxHeight = 0;

	DTMGrid lastSurface = *this;

	maxWindow = std::ceil(MAX_WINDOW_SIZE / CELL_SIZE);
	for (int window = 1; window <= maxWindow; window++)
	{
		maxHeight = MAX_SLOPE * (float) window * CELL_SIZE;

#if DEBUG
		std::cout << std::setprecision(2);
		std::cout << "SMRF w=" << window << "/" << maxWindow << " h=" << maxHeight << "...\n";
#endif

		DTMGrid thisSurface = lastSurface.morphologicalOpening(window, numPts_);
		for (int i = 0; i < thisSurface.rows; i++)
			for (int j = 0; j < thisSurface.cols; j++)
				if (lastSurface.cells[i * cols + j].z - thisSurface.cells[i * cols + j].z > maxHeight)
					thisSurface.cells[i * cols + j].obj = true;

		lastSurface = thisSurface;
	}
	for (int i = 0; i < lastSurface.rows; i++)
		for (int j = 0; j < lastSurface.cols; j++)
			cells[i * cols + j].obj = lastSurface.cells[i * cols + j].obj;
}

} // namespace dtm

ext: cpp

max_stars_repo_name: xannieto/rule-based-classifier-cpp

max_issues_repo_name: xannieto/rule-based-classifier-cpp

max_forks_repo_name: xannieto/rule-based-classifier-cpp


text:
/* Copyright 2013 10gen Inc.
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    As a special exception, the copyright holders give permission to link the
 *    code of portions of this program with the OpenSSL library under certain
 *    conditions as described in each individual source file and distribute
 *    linked combinations including the program with the OpenSSL library. You
 *    must comply with the GNU Affero General Public License in all respects
 *    for all of the code used other than as permitted herein. If you modify
 *    file(s) with this exception, you may extend this exception to your
 *    version of the file(s), but you are not obligated to do so. If you do not
 *    wish to do so, delete this exception statement from your version. If you
 *    delete this exception statement from all source files in the program,
 *    then also delete it in the license file.
 */

#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault

#include "mongo/platform/basic.h"

#include "mongo/config.h"

#if defined(MONGO_CONFIG_HAVE_HEADER_UNISTD_H)
#include <unistd.h>
#endif
#ifndef _WIN32
#include <sys/types.h>
#include <sys/wait.h>
#endif

#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif

#include <boost/filesystem.hpp>

#include "mongo/bson/util/builder.h"
#include "mongo/db/server_options.h"
#include "mongo/db/server_options_server_helpers.h"
#include "mongo/logger/logger.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/log.h"
#include "mongo/util/options_parser/environment.h"
#include "mongo/util/options_parser/option_section.h"
#include "mongo/util/options_parser/options_parser.h"
#include "mongo/util/scopeguard.h"

namespace {

using mongo::ErrorCodes;
using mongo::Status;
namespace moe = mongo::optionenvironment;

class OptionsParserTester : public moe::OptionsParser {
public:
    Status readConfigFile(const std::string& filename, std::string* config) {
        if (filename != _filename) {
            ::mongo::StringBuilder sb;
            sb << "Parser using filename: " << filename
               << " which does not match expected filename: " << _filename;
            return Status(ErrorCodes::InternalError, sb.str());
        }
        *config = _config;
        return Status::OK();
    }
    void setConfig(const std::string& filename, const std::string& config) {
        _filename = filename;
        _config = config;
    }

private:
    std::string _filename;
    std::string _config;
};

TEST(Verbosity, Default) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    // Reset the log level before we test
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogSeverity::Info());

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    std::map<std::string, std::string> env_map;

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    // Make sure the log level didn't change since we didn't specify any verbose options
    ASSERT_EQUALS(::mongo::logger::globalLogDomain()->getMinimumLogSeverity(),
                  ::mongo::logger::LogSeverity::Info());
}

TEST(Verbosity, CommandLineImplicit) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    // Reset the log level before we test
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogSeverity::Info());

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--verbose");
    std::map<std::string, std::string> env_map;

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    int verbosity = 1;
    ASSERT_EQUALS(::mongo::logger::globalLogDomain()->getMinimumLogSeverity(),
                  ::mongo::logger::LogSeverity::Debug(verbosity));
}

TEST(Verbosity, CommandLineString) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    // Reset the log level before we test
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogSeverity::Info());

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--verbose");
    argv.push_back("vvvv");
    std::map<std::string, std::string> env_map;

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    int verbosity = 4;
    ASSERT_EQUALS(::mongo::logger::globalLogDomain()->getMinimumLogSeverity(),
                  ::mongo::logger::LogSeverity::Debug(verbosity));
}

TEST(Verbosity, CommandLineStringDisguisedLongForm) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    // Reset the log level before we test
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogSeverity::Info());

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("-verbose");
    argv.push_back("vvvv");
    std::map<std::string, std::string> env_map;

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    int verbosity = 4;
    ASSERT_EQUALS(::mongo::logger::globalLogDomain()->getMinimumLogSeverity(),
                  ::mongo::logger::LogSeverity::Debug(verbosity));
}

TEST(Verbosity, CommandLineEmptyString) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    // Reset the log level before we test
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogSeverity::Info());

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--verbose");
    argv.push_back("");
    std::map<std::string, std::string> env_map;

    ASSERT_NOT_OK(parser.run(options, argv, env_map, &environment));
}

TEST(Verbosity, CommandLineBadString) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    // Reset the log level before we test
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogSeverity::Info());

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--verbose");
    argv.push_back("beloud");
    std::map<std::string, std::string> env_map;

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_NOT_OK(::mongo::validateServerOptions(environment));
}

TEST(Verbosity, CommandLineBadStringOnlyDash) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    // Reset the log level before we test
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogSeverity::Info());

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("-");
    std::map<std::string, std::string> env_map;

    ASSERT_NOT_OK(parser.run(options, argv, env_map, &environment));
}

TEST(Verbosity, CommandLineBadStringOnlyTwoDashes) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    // Reset the log level before we test
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogSeverity::Info());

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--");
    std::map<std::string, std::string> env_map;

    ASSERT_OK(parser.run(options, argv, env_map, &environment));
}

TEST(Verbosity, INIConfigString) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    // Reset the log level before we test
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogSeverity::Info());

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--config");
    argv.push_back("config.ini");
    std::map<std::string, std::string> env_map;

    parser.setConfig("config.ini", "verbose=vvvv");

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    int verbosity = 4;
    ASSERT_EQUALS(::mongo::logger::globalLogDomain()->getMinimumLogSeverity(),
                  ::mongo::logger::LogSeverity::Debug(verbosity));
}

TEST(Verbosity, INIConfigBadString) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    // Reset the log level before we test
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogSeverity::Info());

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--config");
    argv.push_back("config.ini");
    std::map<std::string, std::string> env_map;

    parser.setConfig("config.ini", "verbose=beloud");

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_NOT_OK(::mongo::validateServerOptions(environment));
}

TEST(Verbosity, INIConfigEmptyString) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    // Reset the log level before we test
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogSeverity::Info());

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--config");
    argv.push_back("config.ini");
    std::map<std::string, std::string> env_map;

    parser.setConfig("config.ini", "verbose=");

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    int verbosity = 0;
    ASSERT_EQUALS(::mongo::logger::globalLogDomain()->getMinimumLogSeverity(),
                  ::mongo::logger::LogSeverity::Debug(verbosity));
}

TEST(Verbosity, JSONConfigString) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    // Reset the log level before we test
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogSeverity::Info());

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--config");
    argv.push_back("config.json");
    std::map<std::string, std::string> env_map;

    parser.setConfig("config.json", "{ \"systemLog.verbosity\" : 4 }");

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    int verbosity = 4;
    ASSERT_EQUALS(::mongo::logger::globalLogDomain()->getMinimumLogSeverity(),
                  ::mongo::logger::LogSeverity::Debug(verbosity));
}

TEST(Verbosity, MultipleSourcesMultipleOptions) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    // Reset the log level before we test
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogSeverity::Info());

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--config");
    argv.push_back("config.json");
    argv.push_back("--verbose");
    argv.push_back("vvv");
    std::map<std::string, std::string> env_map;

    parser.setConfig("config.json", "{ \"systemLog.verbosity\" : 4 }");

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    int verbosity = 3;
    ASSERT_EQUALS(::mongo::logger::globalLogDomain()->getMinimumLogSeverity(),
                  ::mongo::logger::LogSeverity::Debug(verbosity));
}

TEST(Verbosity, YAMLConfigStringLogComponent) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    // Reset the log level before we test
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogSeverity::Info());
    // Log level for Storage will be cleared by config file value.
    ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(
        ::mongo::logger::LogComponent::kStorage, ::mongo::logger::LogSeverity::Debug(1));

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--config");
    argv.push_back("config.yaml");
    std::map<std::string, std::string> env_map;

    parser.setConfig("config.yaml",
                     "systemLog:\n"
                     "    verbosity: 4\n"
                     "    component:\n"
                     "        accessControl:\n"
                     "            verbosity: 0\n"
                     "        storage:\n"
                     "            verbosity: -1\n"
                     "            journal:\n"
                     "                verbosity: 2\n");

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    // Verify component log levels using global log domain.
    int verbosity = 4;

    // Default
    ASSERT_EQUALS(::mongo::logger::globalLogDomain()->getMinimumLogSeverity(),
                  ::mongo::logger::LogSeverity::Debug(verbosity));
    ASSERT_EQUALS(::mongo::logger::globalLogDomain()->getMinimumLogSeverity(
                      ::mongo::logger::LogComponent::kDefault),
                  ::mongo::logger::LogSeverity::Debug(verbosity));

    // AccessControl
    ASSERT_TRUE(::mongo::logger::globalLogDomain()->hasMinimumLogSeverity(
        ::mongo::logger::LogComponent::kAccessControl));
    ASSERT_EQUALS(::mongo::logger::globalLogDomain()->getMinimumLogSeverity(
                      ::mongo::logger::LogComponent::kAccessControl),
                  ::mongo::logger::LogSeverity::Log());

    // Query - not mentioned in configuration. should match default.
    ASSERT_FALSE(::mongo::logger::globalLogDomain()->hasMinimumLogSeverity(
        ::mongo::logger::LogComponent::kStorage));
    ASSERT_EQUALS(::mongo::logger::globalLogDomain()->getMinimumLogSeverity(
                      ::mongo::logger::LogComponent::kStorage),
                  ::mongo::logger::LogSeverity::Debug(verbosity));

    // Storage - cleared by -1 value in configuration. should match default.
    ASSERT_FALSE(::mongo::logger::globalLogDomain()->hasMinimumLogSeverity(
        ::mongo::logger::LogComponent::kStorage));
    ASSERT_EQUALS(::mongo::logger::globalLogDomain()->getMinimumLogSeverity(
                      ::mongo::logger::LogComponent::kStorage),
                  ::mongo::logger::LogSeverity::Debug(verbosity));

    // Journaling - explicitly set to 2 in configuration.
    ASSERT_TRUE(::mongo::logger::globalLogDomain()->hasMinimumLogSeverity(
        ::mongo::logger::LogComponent::kJournal));
    ASSERT_EQUALS(::mongo::logger::globalLogDomain()->getMinimumLogSeverity(
                      ::mongo::logger::LogComponent::kJournal),
                  ::mongo::logger::LogSeverity::Debug(2));
}

TEST(SetupOptions, Default) {
    std::vector<std::string> argv;
    argv.push_back("binaryname");

    ASSERT_OK(::mongo::setupServerOptions(argv));

    ASSERT_EQUALS(::mongo::serverGlobalParams.binaryName, "binaryname");
    ASSERT_FALSE(::mongo::serverGlobalParams.cwd.empty());
    ASSERT_EQUALS(::mongo::serverGlobalParams.argvArray.nFields(), static_cast<int>(argv.size()));
}

TEST(SetupOptions, RelativeBinaryPath) {
    std::vector<std::string> argv;
    argv.push_back("foo/bar/baz/binaryname");

    ASSERT_OK(::mongo::setupServerOptions(argv));

    ASSERT_EQUALS(::mongo::serverGlobalParams.binaryName, "binaryname");
    ASSERT_FALSE(::mongo::serverGlobalParams.cwd.empty());
    ASSERT_EQUALS(::mongo::serverGlobalParams.argvArray.nFields(), static_cast<int>(argv.size()));
}

TEST(SetupOptions, AbsoluteBinaryPath) {
    std::vector<std::string> argv;
    argv.push_back("/foo/bar/baz/binaryname");

    ASSERT_OK(::mongo::setupServerOptions(argv));

    ASSERT_EQUALS(::mongo::serverGlobalParams.binaryName, "binaryname");
    ASSERT_FALSE(::mongo::serverGlobalParams.cwd.empty());
    ASSERT_EQUALS(::mongo::serverGlobalParams.argvArray.nFields(), static_cast<int>(argv.size()));
}

TEST(SetupOptions, EmptyBinaryName) {
    std::vector<std::string> argv;
    argv.push_back("");

    ASSERT_OK(::mongo::setupServerOptions(argv));

    ASSERT_EQUALS(::mongo::serverGlobalParams.binaryName, "");
    ASSERT_FALSE(::mongo::serverGlobalParams.cwd.empty());
    ASSERT_EQUALS(::mongo::serverGlobalParams.argvArray.nFields(), static_cast<int>(argv.size()));
}

TEST(SetupOptions, MissingBinaryName) {
    std::vector<std::string> argv;

    ASSERT_NOT_OK(::mongo::setupServerOptions(argv));
}

TEST(SetupOptions, SlowMsCommandLineParamParsesSuccessfully) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--slowms");
    argv.push_back("300");
    std::map<std::string, std::string> env_map;

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    ASSERT_EQ(::mongo::serverGlobalParams.slowMS, 300);
}

TEST(SetupOptions, SlowMsParamInitializedSuccessfullyFromINIConfigFile) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--config");
    argv.push_back("config.ini");
    std::map<std::string, std::string> env_map;

    parser.setConfig("config.ini", "slowms=300");

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    ASSERT_EQ(::mongo::serverGlobalParams.slowMS, 300);
}

TEST(SetupOptions, SlowMsParamInitializedSuccessfullyFromYAMLConfigFile) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--config");
    argv.push_back("config.yaml");
    std::map<std::string, std::string> env_map;

    parser.setConfig("config.yaml",
                     "operationProfiling:\n"
                     "    slowOpThresholdMs: 300\n");

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    ASSERT_EQ(::mongo::serverGlobalParams.slowMS, 300);
}

TEST(SetupOptions, NonNumericSlowMsCommandLineOptionFailsToParse) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--slowms");
    argv.push_back("invalid");
    std::map<std::string, std::string> env_map;

    ASSERT_NOT_OK(parser.run(options, argv, env_map, &environment));
}

TEST(SetupOptions, NonNumericSlowMsYAMLConfigOptionFailsToParse) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--config");
    argv.push_back("config.yaml");
    std::map<std::string, std::string> env_map;

    parser.setConfig("config.yaml",
                     "operationProfiling:\n"
                     "    slowOpThresholdMs: invalid\n");

    ASSERT_NOT_OK(parser.run(options, argv, env_map, &environment));
}

TEST(SetupOptions, SampleRateCommandLineParamParsesSuccessfully) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--slowOpSampleRate");
    argv.push_back("0.5");
    std::map<std::string, std::string> env_map;

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    ASSERT_EQ(::mongo::serverGlobalParams.sampleRate, 0.5);
}

TEST(SetupOptions, SampleRateParamInitializedSuccessfullyFromINIConfigFile) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--config");
    argv.push_back("config.ini");
    std::map<std::string, std::string> env_map;

    parser.setConfig("config.ini", "slowOpSampleRate=0.5");

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    ASSERT_EQ(::mongo::serverGlobalParams.sampleRate, 0.5);
}

TEST(SetupOptions, SampleRateParamInitializedSuccessfullyFromYAMLConfigFile) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--config");
    argv.push_back("config.yaml");
    std::map<std::string, std::string> env_map;

    parser.setConfig("config.yaml",
                     "operationProfiling:\n"
                     "    slowOpSampleRate: 0.5\n");

    ASSERT_OK(parser.run(options, argv, env_map, &environment));

    ASSERT_OK(::mongo::validateServerOptions(environment));
    ASSERT_OK(::mongo::canonicalizeServerOptions(&environment));
    ASSERT_OK(::mongo::setupServerOptions(argv));
    ASSERT_OK(::mongo::storeServerOptions(environment));

    ASSERT_EQ(::mongo::serverGlobalParams.sampleRate, 0.5);
}

TEST(SetupOptions, NonNumericSampleRateCommandLineOptionFailsToParse) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--slowOpSampleRate");
    argv.push_back("invalid");
    std::map<std::string, std::string> env_map;

    ASSERT_NOT_OK(parser.run(options, argv, env_map, &environment));
}

TEST(SetupOptions, NonNumericSampleRateYAMLConfigOptionFailsToParse) {
    OptionsParserTester parser;
    moe::Environment environment;
    moe::OptionSection options;

    ASSERT_OK(::mongo::addGeneralServerOptions(&options));

    std::vector<std::string> argv;
    argv.push_back("binaryname");
    argv.push_back("--config");
    argv.push_back("config.yaml");
    std::map<std::string, std::string> env_map;

    parser.setConfig("config.yaml",
                     "operationProfiling:\n"
                     "    slowOpSampleRate: invalid\n");

    ASSERT_NOT_OK(parser.run(options, argv, env_map, &environment));
}

#if !defined(_WIN32) && !(defined(__APPLE__) && TARGET_OS_TV)

#define ASSERT_BOOST_SUCCESS(ec) ASSERT_FALSE(ec) << ec.message()

TEST(SetupOptions, DeepCwd) {
    std::vector<std::string> argv;
    argv.push_back("binaryname");

    // Save the original cwd.
    boost::system::error_code ec;
    boost::filesystem::path cwd = boost::filesystem::current_path(ec);
    ASSERT_BOOST_SUCCESS(ec);

    // All work is done under a temporary base directory.
    ::mongo::StringBuilder sb;
    sb << "/tmp/deepcwd-" << getpid();
    boost::filesystem::path deepBaseDir = sb.str();

    auto cleanup = ::mongo::MakeGuard([&] {
        boost::filesystem::current_path(cwd, ec);
        boost::filesystem::remove_all(deepBaseDir, ec);
    });

    // Clear out any old base dir, and create an empty dir.
    boost::filesystem::remove_all(deepBaseDir, ec);
    ASSERT_BOOST_SUCCESS(ec);
    boost::filesystem::create_directories(deepBaseDir, ec);
    ASSERT_BOOST_SUCCESS(ec);

    // Resolve the canonical base dir, in case /tmp is a symlink (eg. on OSX).
    // This involves chdir into it, then getcwd() again (since getcwd() returns a canonical path).
    boost::filesystem::current_path(deepBaseDir, ec);
    ASSERT_BOOST_SUCCESS(ec);
    deepBaseDir = boost::filesystem::current_path(ec);
    ASSERT_BOOST_SUCCESS(ec);

    boost::filesystem::path deepCwd = deepBaseDir;
    boost::filesystem::path pathComponent = std::string(40, 'a');
    while (deepCwd.size() < 3800) {
        if (!boost::filesystem::create_directory(deepCwd / pathComponent, ec)) {
            // Could not mkdir, so we are done and will stick with the previous level, thanks.
            break;
        }

        boost::filesystem::current_path(deepCwd / pathComponent, ec);
        if (ec) {
            // Could not chdir, so we are done and will stick with the previous level, thanks.
            break;
        }

        deepCwd /= pathComponent;
    }

    // Run the actual test.
    Status res = ::mongo::setupServerOptions(argv);

    ASSERT_OK(res);
    ASSERT_FALSE(::mongo::serverGlobalParams.cwd.empty());
    ASSERT_EQUALS(::mongo::serverGlobalParams.cwd, deepCwd.native())
        << "serverGlobalParams.cwd is " << ::mongo::serverGlobalParams.cwd.size()
        << " bytes long and deepCwd is " << deepCwd.size() << " bytes long.";
    ASSERT_EQUALS(::mongo::serverGlobalParams.argvArray.nFields(), static_cast<int>(argv.size()));
}

TEST(SetupOptions, UnlinkedCwd) {
    std::vector<std::string> argv;
    argv.push_back("binaryname");

    // Save the original cwd.
    boost::system::error_code ec;
    boost::filesystem::path cwd = boost::filesystem::current_path(ec);
    ASSERT_BOOST_SUCCESS(ec);

    std::string unlinkDir;

    auto cleanup = ::mongo::MakeGuard([&] {
        boost::filesystem::current_path(cwd, ec);
        if (!unlinkDir.empty()) {
            boost::filesystem::remove(cwd / unlinkDir, ec);
        }
    });

    // mkdir our own unlink dir
    unsigned int i = 0;
    while (1) {
        ::mongo::StringBuilder sb;
        sb << "unlink" << i;
        unlinkDir = sb.str();
        if (boost::filesystem::create_directory(unlinkDir, ec)) {
            // New directory was created, great.
            break;
        } else {
            // Directory failed to create, or already existed (so try the next one).
            ASSERT_BOOST_SUCCESS(ec);
            i++;
        }
    }

    // chdir into the unlink dir
    boost::filesystem::current_path(unlinkDir, ec);
    ASSERT_BOOST_SUCCESS(ec);

    // Naive "rmdir ." doesn't work on Linux.
    // Naive rmdir of cwd doesn't work on Solaris doesn't work (no matter how it's specified).
    // So we use a subprocess to unlink the dir.
    pid_t pid = fork();
    ASSERT_NOT_EQUALS(pid, -1) << "unable to fork: " << ::mongo::errnoWithDescription();
    if (pid == 0) {
        // Subprocess
        // No exceptions, ASSERT(), FAIL() or logging.
        // Only signalling to the parent process via exit status.
        // Only quickexit via _exit() (which prevents the cleanup guard from running, which is
        // what we want).

        // cd to root
        boost::filesystem::current_path("/", ec);
        if (ec) {
            _exit(1);
        }

        // rmdir using absolute path
        boost::filesystem::remove(cwd / unlinkDir, ec);
        if (ec) {
            _exit(2);
        }

        _exit(0);
    }

    // Wait for the subprocess to finish running the above code and exit, and check its result.
    int status;
    ASSERT_NOT_EQUALS(-1, waitpid(pid, &status, 0));
    ASSERT(WIFEXITED(status));
    int exitstatus = WEXITSTATUS(status);
    if (exitstatus == 1) {
        FAIL("subprocess was unable to cd to /");
    } else if (exitstatus == 2) {
        FAIL("subprocess was unable to remove unlink dir");
    } else {
        ASSERT_EQUALS(0, exitstatus);
    }

    // Run the actual test.
    Status res = ::mongo::setupServerOptions(argv);

    ASSERT_NOT_OK(res);
    ASSERT_STRING_CONTAINS(res.toString(), "Cannot get current working directory");
    ASSERT_STRING_CONTAINS(res.toString(), "No such file or directory");  // message for ENOENT
}

#endif  // !defined(_WIN32)

}  // unnamed namespace


text:
// Copyright 2021 Danil Postvaykin <postvaykin01@mail.ru>

#ifndef INCLUDE_HTTP_CLIENT_HPP_
#define INCLUDE_HTTP_CLIENT_HPP_

#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/connect.hpp>
#include <boost/config.hpp>
#include <nlohmann/json.hpp>
#include <cstdlib>
#include <iostream>
#include <string>

using nlohmann::json;

namespace beast = boost::beast;
namespace http = beast::http;
namespace net = boost::asio;

class HTTP_Client
{
 public:
  HTTP_Client();
  void create_req();
  void start();
  ~HTTP_Client();
 private:
  std::string require = "";
};

#endif // INCLUDE_HTTP_CLIENT_HPP_


text:
#include "RHGamestationUpgrade.h"
#include "Settings.h"
#include "Log.h"
#include <Locale.h>
#include <boost/algorithm/string/replace.hpp>

RHGamestationUpgrade *RHGamestationUpgrade::instance = NULL;

RHGamestationUpgrade *RHGamestationUpgrade::getInstance() {
    if (RHGamestationUpgrade::instance == NULL) {
        RHGamestationUpgrade::instance = new RHGamestationUpgrade();
    }
    return RHGamestationUpgrade::instance;
}

std::string RHGamestationUpgrade::getVersion() {
    std::string version = Settings::getInstance()->getString("VersionFile");
    return system->readFile(version);
}

std::string RHGamestationUpgrade::getUpdateVersion() {
    std::pair<std::string, int> res = system->execute(Settings::getInstance()->getString("RHGamestationUpgradeScript") + " canupgrade");
    if(res.second != 0){
        return _("NO UPGRADE AVAILABLE");
    }else {
        res.first.erase(std::remove(res.first.begin(), res.first.end(), '\n'), res.first.end());
        return res.first;
    }
}

bool RHGamestationUpgrade::updateLastChangelogFile() {
    std::ostringstream oss;
    oss << "cp  " << Settings::getInstance()->getString("Changelog").c_str() << " " <<
        Settings::getInstance()->getString("LastChangelog").c_str();
    if (std::system(oss.str().c_str())) {
        LOG(LogWarning) << "Error executing " << oss.str().c_str();
        return false;
    } else {
        LOG(LogError) << "Last version file updated";
        return true;
    }
}

std::string RHGamestationUpgrade::getUpdateChangelog() {
    std::pair<std::string, int> res = system->execute(Settings::getInstance()->getString("RHGamestationUpgradeScript") + " diffremote");
    if(res.second == 0){
        return res.first;
    }else {
        return "";
    }
}

std::string RHGamestationUpgrade::getChangelog() {
    std::pair<std::string, int> res = system->execute(Settings::getInstance()->getString("RHGamestationUpgradeScript") + " difflocal");
    if(res.second == 0){
        return res.first;
    }else {
        return "";
    }
}

std::pair<std::string, int> RHGamestationUpgrade::updateSystem(BusyComponent* ui) {
    std::string updatecommand = Settings::getInstance()->getString("RHGamestationUpgradeScript") + " upgrade";
    FILE *pipe = popen(updatecommand.c_str(), "r");
    char line[1024] = "";
    if (pipe == NULL) {
        return std::pair<std::string, int>(std::string("Cannot call upgrade command"), -1);
    }
    while (fgets(line, 1024, pipe)) {
        strtok(line, "\n");
        std::string output = line;
        boost::replace_all(output, "\e[1A\e[K", "");
		if (output.find(':') != std::string::npos) {

			int p1 = output.find(":");
			std::string i18n = output.substr(0, p1);
			std::string percent = output.substr(p1 + 1, std::string::npos);
			ui->setText(_(i18n.c_str()) + ": " + percent);
		} else
			ui->setText(_(output.c_str()));
    }

    int exitCode = pclose(pipe);
    return std::pair<std::string, int>(std::string(line), exitCode);
}

bool RHGamestationUpgrade::canUpdate() {

    std::pair<std::string, int> res = system->execute(Settings::getInstance()->getString("RHGamestationUpgradeScript") + " canupgrade");
    if(res.second == 0){
        LOG(LogInfo) << "Can upgrade";
        return true;
    }else {
        LOG(LogInfo) << "Cannot upgrade";
        return false;
    }
}


text: #include <boost/mpl/aux_/preprocessed/plain/times.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
#pragma once

#include <boost/container/pmr/memory_resource.hpp>
#include <boost/container/pmr/monotonic_buffer_resource.hpp>
#include <boost/container/pmr/vector.hpp>
namespace FMPmr = boost::container::pmr;

const auto FM_MAX_NUM_PARTITIONS = 255U;
const auto FM_MAX_DEGREE = 65536U;

// workaround clang


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

 /*
  * Author: Hang Qu <quhang@stanford.edu>
  */
#include <boost/functional/hash.hpp>
#include <string>
#include "src/data/physbam/physbam_data.h"
#include "src/data/physbam/protobuf_compiled/pd_message.pb.h"
#include "src/shared/dbg.h"
#include "src/data/physbam/physbam_data_with_meta.h"

namespace nimbus {

PhysBAMDataWithMeta::PhysBAMDataWithMeta() {
  ResetMetaData();
}

Data* PhysBAMDataWithMeta::Clone() {
  PhysBAMDataWithMeta* d = new PhysBAMDataWithMeta();
  d->set_buffer(NULL, size_);
  return d;
}

void PhysBAMDataWithMeta::Create() {
  PhysBAMData::Create();
  ResetMetaData();
}

void PhysBAMDataWithMeta::Destroy() {
  PhysBAMData::Destroy();
  ResetMetaData();
}

void PhysBAMDataWithMeta::Copy(Data *from) {
  PhysBAMData::Copy(from);
  PhysBAMDataWithMeta* pfrom = dynamic_cast<PhysBAMDataWithMeta*>(from);  // NOLINT
  assert(pfrom != NULL);
  has_meta_data_ = pfrom->has_meta_data();
  meta_data_size_ = pfrom->meta_data_size();
  meta_data_hash_ = pfrom->meta_data_hash();
}

bool PhysBAMDataWithMeta::Serialize(SerializedData* ser_data) {
  nimbus_message::pd_message pd; // NOLINT
  if (buffer_) {
    std::string buf(buffer_, size_);
    pd.set_buffer(buf);
  }
  if (size_) {
    pd.set_size(size_);
  } else {
    pd.set_size(0);
  }
  pd.set_hash(0);
  if (has_meta_data_) {
    pd.set_meta_data_size(meta_data_size_);
    pd.set_meta_data_hash(meta_data_hash_);
  }
  std::string ser;
  bool success = pd.SerializeToString(&ser);
  char *buf = new char[ser.length() + 1];
  memcpy(buf, ser.c_str(), sizeof(char) * (ser.length() + 1)); // NOLINT
  if (!success)
    return success;
  ser_data->set_data_ptr(buf);
  ser_data->set_size(sizeof(char) * ser.length() + 1); // NOLINT
  return success;
}

bool PhysBAMDataWithMeta::DeSerialize(const SerializedData& ser_data,
                                      Data** result) {
  const char *buf = ser_data.data_ptr_raw();
  const int buf_size = ser_data.size();
  if (buf_size <= 0)
    return false;
  assert(buf);

  nimbus_message::pd_message pd; // NOLINT
  std::string temp(buf, buf_size-1); // NOLINT
  bool success = pd.ParseFromString(temp);
  if (!success)
    return success;

  PhysBAMDataWithMeta *data = new PhysBAMDataWithMeta();
  (*result) = static_cast<Data *>(data);
  if (pd.has_buffer()) {
    int size = pd.size();
    char *buffer = new char[size];
    memcpy(buffer, pd.buffer().c_str(), sizeof(char) * size); // NOLINT
    data->set_buffer(buffer, size);
  } else {
    data->set_buffer(NULL, pd.size());
  }

  data->ResetMetaData();
  if (!pd.has_meta_data_size()) {
    dbg(DBG_WARN, "No meta data received.\n");
  }
  if (pd.has_meta_data_size()) {
    data->set_has_meta_data();
    data->set_meta_data_size(pd.meta_data_size());
  }
  if (pd.has_meta_data_hash()) {
    data->set_meta_data_hash(pd.meta_data_hash());
  }
  return success;
}

void PhysBAMDataWithMeta::ResetMetaData() {
  has_meta_data_ = false;
  meta_data_size_ = 0;
  meta_data_hash_ = 0;
}

void PhysBAMDataWithMeta::MarkMetaDataInTempBuffer() {
  meta_data_size_ = temp_buffer_->tellp();
  has_meta_data_ = true;
  std::size_t temp = HASH_SEED;
  /*
  const std::string& temp_str = temp_buffer_->str();
  const char* pointer = temp_str.c_str();
  if (meta_data_size_ != 0) {
    boost::hash_range(temp, pointer, pointer + meta_data_size_);
  }
  */
  meta_data_hash_ = static_cast<int64_t>(temp);
}

}  // namespace nimbus

ext: cc

max_stars_repo_name: schinmayee/nimbus

max_issues_repo_name: schinmayee/nimbus

max_forks_repo_name: schinmayee/nimbus


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

#include <boost/lexical_cast.hpp>
#include <boost/utility/in_place_factory.hpp>

#include "jsoncpp/json.hpp"
#include "jsoncpp/as.hpp"

#include "vts-libs/registry/json.hpp"
#include "vts-libs/registry/py.hpp"

#include "../support/python.hpp"
#include "../support/serialization.hpp"

#include "./geodata.hpp"

namespace vf = geo::vectorformat;

namespace resource {

namespace {

void parseLayers(boost::optional<geo::heightcoding::Config::LayerNames> &result
                 , const std::string &name, const Json::Value &value)
{
    if (!value.isMember(name)) { return; }

    const auto layers(value[name]);
    if (!layers.isArray()) {
        LOGTHROW(err1, FormatError)
            << "Geodata definition[layers] is not an array.";
    }

    result = boost::in_place();
    for (const auto &layer : layers) {
        result->push_back(layer.asString());
    }
    std::sort(result->begin(), result->end());
}

void parse(vf::GeodataConfig &config, const Json::Value &value)
{
    Json::getOpt(config.resolution, value, "resolution");
}

void parseDefinition(GeodataVectorBase &def
                     , const Json::Value &value)
{
    std::string s;

    Json::get(def.dataset, value, "dataset");
    Json::get(def.dem.dataset, value, "demDataset");

    if (value.isMember("geoidGrid")) {
        def.dem.geoidGrid = boost::in_place();
        Json::get(*def.dem.geoidGrid, value, "geoidGrid");
    }

    parseLayers(def.layers, "layers", value);
    parseLayers(def.clipLayers, "clipLayers", value);

    if (value.isMember("format")) {
        Json::get(s, value, "format");
        try {
            def.format  = boost::lexical_cast<geo::VectorFormat>(s);
        } catch (boost::bad_lexical_cast) {
            utility::raise<FormatError>
                ("Value stored in format is not a valid height"
                 " coded data format.");
        }
    }

    if (value.isMember("formatConfig")) {
        const auto formatConfig(value["formatConfig"]);
        if (!formatConfig.isObject()) {
            LOGTHROW(err1, FormatError)
                << "Geodata definition[formatConfig] is not an object.";
        }

        switch (def.format) {
        case geo::VectorFormat::geodataJson:
            parse(createGeodataConfig(def.formatConfig), formatConfig);
            break;

        default:
            // ignore
            break;
        }
    }

    Json::getOpt(def.styleUrl, value, "styleUrl");
    Json::get(def.displaySize, value, "displaySize");
    Json::getOpt(def.mode, value, "mode");

    if (value.isMember("enhance")) {
        const auto enhance(value["enhance"]);
        if (!enhance.isObject()) {
            LOGTHROW(err1, FormatError)
                << "Geodata definition[enhance] is not an object.";
        }

        for (const auto &layerName : enhance.getMemberNames()) {
            const auto &layer(enhance[layerName]);
            auto &lh(def.layerEnhancers[layerName]);
            Json::get(lh.key, layer, "key");
            Json::get(lh.databasePath, layer, "db");
            Json::get(lh.table, layer, "table");
        }
    }

    def.heightFunction = HeightFunction::parse(value, "heightFunction");

    if (value.isMember("introspection")) {
        const auto &jintrospection(value["introspection"]);

        def.introspection.surface
            = introspectionIdFrom(jintrospection, "surface");

        if (jintrospection.isMember("browserOptions")) {
            def.introspection.browserOptions
                = Json::check(jintrospection["browserOptions"]
                              , Json::objectValue);
        }
    }
}

void buildLayers(const boost::optional
                 <geo::heightcoding::Config::LayerNames> &layers
                 , const std::string &name, Json::Value &value)
{
    if (!layers) { return; }
    auto &players(value[name] = Json::arrayValue);
    for (const auto &layer : *layers) {
        players.append(layer);
    }
}

void build(Json::Value &value, const vf::GeodataConfig *config)
{
    if (!config) { return; }
    value["resolution"] = config->resolution;
}

void buildDefinition(Json::Value &value
                     , const GeodataVectorBase &def)
{
    value["dataset"] = def.dataset;
    value["demDataset"] = def.dem.dataset;

    if (def.dem.geoidGrid) {
        value["geoidGrid"] = *def.dem.geoidGrid;
    }

    buildLayers(def.layers, "layers", value);
    buildLayers(def.clipLayers, "clipLayers", value);

    value["format"] = boost::lexical_cast<std::string>(def.format);
    auto &formatConfig(value["formatConfig"] = Json::objectValue);
    switch (def.format) {

    case geo::VectorFormat::geodataJson:
        build(formatConfig, boost::get<vf::GeodataConfig>(&def.formatConfig));
        break;

    default:
        // ignore
        break;
    }

    value["displaySize"] = def.displaySize;
    value["styleUrl"] = def.styleUrl;
    value["mode"] = boost::lexical_cast<std::string>(def.mode);

    if (!def.layerEnhancers.empty()) {
        auto &layerEnhancers(value["enhance"] = Json::objectValue);
        for (const auto &item : def.layerEnhancers) {
            auto &layer(layerEnhancers[item.first] = Json::objectValue);
            layer["key"] = item.second.key;
            layer["db"] = item.second.databasePath;
            layer["table"] = item.second.table;
        }
    }

    if (def.heightFunction) {
        boost::any tmp(Json::Value(Json::objectValue));
        def.heightFunction->build(tmp);
        value["heightFunction"] = boost::any_cast<const Json::Value&>(tmp);
    }

    if (!def.introspection.empty()) {
        auto &jintrospection(value["introspection"] = Json::objectValue);
        introspectionIdTo(jintrospection, "surface"
                          , def.introspection.surface);

        if (!def.introspection.browserOptions.empty()) {
            jintrospection["browserOptions"]
                = boost::any_cast<const Json::Value&>
                (def.introspection.browserOptions);
        }
    }
}

void parseLayers(boost::optional<geo::heightcoding::Config::LayerNames> &result
                 , const std::string &name, const boost::python::dict &value)
{
    if (!value.has_key(name)) { return; }

    result = boost::in_place();
    auto pylayers(value[name]);
    for (boost::python::stl_input_iterator<boost::python::object>
             ipylayers(pylayers), epylayers;
         ipylayers != epylayers; ++ipylayers)
    {
        result->push_back(py2utf8(*ipylayers));
    }
    std::sort(result->begin(), result->end());
}

void parse(vf::GeodataConfig &config, const boost::python::dict &value)
{
    if (value.has_key("resolution")) {
        config.resolution
            = boost::python::extract<int>(value["resolution"]);
    }
}

void parseDefinition(GeodataVectorBase &def
                     , const boost::python::dict &value)
{
    def.dataset = py2utf8(value["dataset"]);
    def.dem.dataset = py2utf8(value["demDataset"]);

    if (value.has_key("geoidGrid")) {
        def.dem.geoidGrid = py2utf8(value["geoidGrid"]);
    }

    parseLayers(def.layers, "layers", value);
    parseLayers(def.clipLayers, "clipLayers", value);

    if (value.has_key("format")) {
        try {
            def.format = boost::lexical_cast<geo::VectorFormat>
                (py2utf8(value["format"]));
        } catch (boost::bad_lexical_cast) {
            utility::raise<Error>
                ("Value stored in format is not a valid height"
                 " coded data format.");
        }
    }

    if (value.has_key("formatConfig")) {
        boost::python::dict formatConfig(value["formatConfig"]);
        switch (def.format) {
        case geo::VectorFormat::geodataJson:
            parse(createGeodataConfig(def.formatConfig), formatConfig);
            break;

        default:
            // ignore
            break;
        }
    }

    def.displaySize = boost::python::extract<int>(value["displaySize"]);
    def.styleUrl = py2utf8(value["styleUrl"]);

    if (value.has_key("mode")) {
        try {
            def.mode = boost::lexical_cast<geo::heightcoding::Mode>
                (py2utf8(value["mode"]));
        } catch (boost::bad_lexical_cast) {
            utility::raise<Error>
                ("Value stored in mode is not a valid height coding mode.");
        }
    }

    if (value.has_key("enhance")) {
        const auto enhance(value["enhance"]);
        for (boost::python::stl_input_iterator<boost::python::str>
                 ilayer(enhance), elayer; ilayer != elayer; ++ilayer)
        {
            const auto name(py2utf8(*ilayer));
            const auto content(enhance[*ilayer]);

            auto &lh(def.layerEnhancers[name]);
            lh.key = py2utf8(content["key"]);
            lh.databasePath = py2utf8(content["db"]);
            lh.table = py2utf8(content["table"]);
        }
    }

    def.heightFunction = HeightFunction::parse(value, "heightFunction");

    if (value.has_key("introspection")) {
        boost::python::dict pintrospection(value["introspection"]);
        def.introspection.surface
            = introspectionIdFrom(pintrospection, "surface");
    }
}

bool differ(const vf::GeodataConfig &l, const vf::GeodataConfig *r)
{
    // different type?
    if (!r) { return true; }
    // same types
    if (l.resolution != r->resolution) { return true; }
    return false;
}

bool differ(const vf::Config &l, const vf::Config &r)
{
    if (const auto *cl = boost::get<vf::GeodataConfig>(&l)) {
        return differ(*cl, boost::get<vf::GeodataConfig>(&r));
    }
    // add more config types here
    return true;
}

} // namespace

bool GeodataVectorBase::Introspection::empty() const
{
    return (!surface && browserOptions.empty());
}

bool GeodataVectorBase::Introspection::operator!=(const Introspection &other)
    const
{
    // introspection can safely change
    if (surface != other.surface) { return true; }

    if (browserOptions.empty() != other.browserOptions.empty()) {
        return true;
    }
    if (!browserOptions.empty()
        && (boost::any_cast<const Json::Value&>(browserOptions)
            != boost::any_cast<const Json::Value&>(other.browserOptions)))
    {
        return true;
    }

    return false;
}

void GeodataVectorBase::from_impl(const boost::any &value)
{
    if (const auto *json = boost::any_cast<Json::Value>(&value)) {
        parseDefinition(*this, *json);
    } else if (const auto *py
               = boost::any_cast<boost::python::dict>(&value))
    {
        parseDefinition(*this, *py);
    } else {
        LOGTHROW(err1, Error)
            << "GeodataVectorBase: Unsupported configuration from: <"
            << value.type().name() << ">.";
    }
}

void GeodataVectorBase::to_impl(boost::any &value) const
{
    if (auto *json = boost::any_cast<Json::Value>(&value)) {
        buildDefinition(*json, *this);
    } else {
        LOGTHROW(err1, Error)
            << "GeodataVectorBase:: Unsupported serialization into: <"
            << value.type().name() << ">.";
    }
}

Changed GeodataVectorBase::changed_impl(const DefinitionBase &o) const
{
    const auto &other(o.as<GeodataVectorBase>());

    // accumulate revision bump/safe changes
    bool bump(false);
    bool safe(false);

    // changing these bumps version
    if (dem != other.dem) { bump = true; }
    if (dataset != other.dataset) { bump = true; }
    if (layers != other.layers) { bump = true; }
    if (clipLayers != other.clipLayers) { bump = true; }
    if (mode != other.mode) { bump = true; }
    if (layerEnhancers != other.layerEnhancers) { bump = true; }
    if (HeightFunction::changed(heightFunction, other.heightFunction)) {
        bump = true;
    }

    // different format leads to version bump!
    if (format != other.format) { bump = true; }
    // different format config leads to version bump!
    if (differ(formatConfig, other.formatConfig)) { bump = true; }
    // displaySize can change
    if (displaySize != other.displaySize) { safe = true; }
    // styleUrl can change
    if (styleUrl != other.styleUrl) { safe = true; }

    // introspection can change
    if (introspection != other.introspection) { safe = true; }

    // interpret change type
    if (bump) { return Changed::withRevisionBump; }
    if (safe) { return Changed::safely; }
    return Changed::no;
}

} // namespace resource

max_stars_repo_name: maka-io/vts-mapproxy

max_issues_repo_name: maka-io/vts-mapproxy

max_forks_repo_name: maka-io/vts-mapproxy