text:
/*Basic includes.*/
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <vector>

/*Includes for ROS.*/
#include <ros/ros.h>

/*Includes for Markers.*/
#include <visualization_msgs/Marker.h>
#include <visualization_msgs/MarkerArray.h>

/*Includes for GUI.*/
#include <dynamic_reconfigure/server.h>
#include <urban_road_filter/LidarFiltersConfig.h>

/*Includes for PCL.*/
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/point_cloud.h>
#include <pcl_ros/point_cloud.h>
#include <pcl/point_types.h>

#include "starShapedSearch.cpp"

/*ramer-douglas-peucker*/
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/assign.hpp>

using namespace boost::assign;

typedef boost::geometry::model::d2::point_xy<float> xy;
boost::geometry::model::linestring<xy> line;
boost::geometry::model::linestring<xy> simplified;

/*Global variables.*/
int channels = 32;                                    /* The number of channels of the LIDAR .*/
std::string fixedFrame;                               /* Fixed Frame.*/
std::string topicName;                                /* subscribed topic.*/
bool x_zero_method, y_zero_method, star_shaped_method ; /*Three methods of roadside detection*/
bool blind_spots;                                     /*Vakfolt javító algoritmus.*/
int xDirection;                                       /*A vakfolt levágás milyen irányú.*/
float interval;                                       /*A LIDAR vertikális szögfelbontásának, elfogadott intervalluma.*/
float curbHeight;                                     /*Becsült minimum szegély magasság.*/
int curbPoints;                                       /*A pontok becsült száma, a szegélyen.*/
float beamZone;                                       /*A vizsgált sugárzóna mérete.*/
float angleFilter1;                                   /*X = 0 érték mellett, három pont által bezárt szög.*/
float angleFilter2;                                   /*Z = 0 érték mellett, két vektor által bezárt szög.*/
float angleFilter3;                                   /*Csaplár László kódjához szükséges. Sugár irányú határérték (fokban).*/
float min_X, max_X, min_Y, max_Y, min_Z, max_Z;       /*A vizsgált terület méretei.*/

bool polysimp_allow = true;                           /*polygon-eygszerűsítés engedélyezése*/
bool zavg_allow = true;                               /*egyszerűsített polygon z-koordinátái átlagból (engedély)*/
float polysimp = 0.5;                                 /*polygon-egyszerűsítési tényező (Ramer-Douglas-Peucker)*/
float polyz = -1.5;                                   /*manuálisan megadott z-koordináta (polygon)*/

int ghostcount = 0;                                   /* segédváltozó az elavult markerek (ghost) eltávolításához */

/*A paraméterek beállítása.*/
void paramsCallback(lidar_filters_pkg::LidarFiltersConfig &config, uint32_t level)
{
    fixedFrame = config.fixed_frame;
    topicName = config.topic_name;
    x_zero_method = config.x_zero_method;
    y_zero_method = config.z_zero_method;
    star_shaped_method  = config.star_shaped_method ;
    blind_spots = config.blind_spots;
    xDirection = config.xDirection;
    interval = config.interval;
    curbHeight = config.curb_height;
    curbPoints = config.curb_points;
    beamZone = config.beamZone;
    angleFilter1 = config.cylinder_deg_x;
    angleFilter2 = config.cylinder_deg_z;
    angleFilter3 = config.sector_deg;
    min_X = config.min_x;
    max_X = config.max_x;
    min_Y = config.min_y;
    max_Y = config.max_y;
    min_Z = config.min_z;
    max_Z = config.max_z;
    dmin_param = config.dmin_param;
    kdev_param = config.kdev_param;
    kdist_param = config.kdist_param;
    polysimp_allow = config.simple_poly_allow;
    polysimp = config.poly_s_param;
    zavg_allow = config.poly_z_avg_allow;
    polyz = config.poly_z_manual;
    ROS_INFO("Updated params %s", ros::this_node::getName().c_str());
}

/*Publish.*/
ros::Publisher pub_road;        /*Filtered points (passable roadway).*/
ros::Publisher pub_high;        /*Filtered points (not roadway).*/
ros::Publisher pub_box;         /*Szűrt pontok (nem úttest).*/
ros::Publisher pub_pobroad;     /*All points in the study area.*/
ros::Publisher pub_marker;      /*Marker.*/

/*FÜGGVÉNYEK*/
/*Recursive, fast sorting function. (1/3)*/
void swap(float *a, float *b)
{
    float t = *a;
    *a = *b;
    *b = t;
}

/*Recursive, fast sorting function. (2/3)*/
int partition(float *array3D, int arc, int piece, int low, int high)
{
    float pivot = *(array3D + arc * piece * 7 + high * 7 + 4);
    int i = (low - 1);
    for (int j = low; j <= high - 1; j++)
    {
        if (*(array3D + arc * piece * 7 + j * 7 + 4) < pivot)
        {
            i++;
            for(int sw = 0; sw < 7; sw++){
                swap(&*(array3D + arc * piece * 7 + i * 7 + sw), &*(array3D + arc * piece * 7 + j * 7 + sw));
            }
        }
    }
    for(int sw = 0; sw < 7; sw++){
        swap(&*(array3D + arc * piece * 7 + (i + 1) * 7 + sw), &*(array3D + arc * piece * 7 + high * 7 + sw));
    }
    return (i + 1);
}

/*Recursive, fast sorting function. (3/3)*/
void quickSort(float *array3D, int arc, int piece, int low, int high)
{
    if (low < high)
    {
        int pi = partition(array3D, arc, piece, low, high);
        quickSort(array3D, arc, piece, low, pi - 1);
        quickSort(array3D, arc, piece, pi + 1, high);
    }
}

/*Ez a függvény végzi a szűrést.*/
void filtered(const pcl::PointCloud<pcl::PointXYZ> &cloud)
{
    /*Segédváltozók, a "for" ciklusokhoz.*/
    int i, j, k, l;

    pcl::PointXYZ pt;                                           /*Egy db pont tárolásához szükséges.*/
    pcl::PointCloud<pcl::PointXYZ> cloud_filtered_Road;         /*Szűrt pontok (járható úttest).*/
    pcl::PointCloud<pcl::PointXYZ> cloud_filtered_ProbablyRoad; /*Szűrt pontok (nem járható úttest).*/
    pcl::PointCloud<pcl::PointXYZ> cloud_filtered_High;         /*Szűrt pontok (nem úttest).*/
    pcl::PointCloud<pcl::PointXYZ> cloud_filtered_Box;          /*A vizsgált terület, összes pontja.*/

    /*Upload the "cloud_filtered_Box" topic with the points.
    We go through the input cloud and select the points that
    match the criteria, are added to the "cloud_filtered_Box" topic.*/
    for (i = 0; i <= cloud.size(); i++)
    {
        if (cloud.points[i].x >= min_X && cloud.points[i].x <= max_X &&
            cloud.points[i].y >= min_Y && cloud.points[i].y <= max_Y &&
            cloud.points[i].z >= min_Z && cloud.points[i].z <= max_Z &&
            cloud.points[i].x + cloud.points[i].y + cloud.points[i].z != 0)
        {
            pt.x = cloud.points[i].x;
            pt.y = cloud.points[i].y;
            pt.z = cloud.points[i].z;
            cloud_filtered_Box.push_back(pt);
        }
    }

    /*A pontok darabszáma, a vizsgált területen.*/
    int piece = cloud_filtered_Box.points.size();

    /*Minimum 30 pont legyen a vizsgált területen, különben programhibák lesznek.
    Illetve nincs is értelme vizsgálni ilyen kevés pontot.*/
    if (piece >= 30)
    {
        /*Csaplár László kódjának meghívása és a szükséges határérték beállítása.*/
        if (star_shaped_method )
        {
            slope_param = angleFilter3 * (M_PI / 180);
            callback(cloud_filtered_Box);
        }

        /*
        2D tömb:
        - A pontok értékei: (0: X, 1: Y, 2: Z),
        - A pontok origótól vett távolsága: (3: D),
        - A pontok szögfelbontása: (4: Alpha),
        - Csaplár László kódja alapján felismert szegély pontok: Csoportszámok (5: Road = 1, High = 2).
        */
        float *array2D = new float[piece * 6]();

        /*A szögfüggvények, zárójelbeli értékeinek tárolásához.*/
        float bracket;

        /*Egy 1D tömb, melyben a különböző szögfelbontások találhatóak.
        Ez a LIDAR csatornaszámával egyenlő.
        Fontos, hogy 0 értékekkel töltsük fel.*/
        float angle[channels] = {0};

        /*A szögfelbontásokat tároló 1D tömböt, segít feltölteni.*/
        int index = 0;

        /*Új körvonalhoz tartozik az adott szög?*/
        int newCircle;

        /*A 2D tömb feltöltése.*/
        for (i = 0; i < piece; i++)
        {
            /*--- Az első 4 oszlop feltöltése. ---*/
            *(array2D + i * 6 + 0) = cloud_filtered_Box.points[i].x;
            *(array2D + i * 6 + 1) = cloud_filtered_Box.points[i].y;
            *(array2D + i * 6 + 2) = cloud_filtered_Box.points[i].z;
            *(array2D + i * 6 + 3) = sqrt(pow(*(array2D + i * 6 + 0), 2) + pow(*(array2D + i * 6 + 1), 2) + pow(*(array2D + i * 6 + 2), 2));

            /*--- Az 5. oszlop feltöltése. ---*/
            bracket = abs(*(array2D + i * 6 + 2)) / *(array2D + i * 6 + 3);

            /*A kerekítési hibák miatt szükséges sorok.*/
            if (bracket < -1)
                bracket = -1;
            else if (bracket > 1)
                bracket = 1;

            /*Számolás és konvertálás fokba.*/
            if (*(array2D + i * 6 + 2) < 0)
            {
                *(array2D + i * 6 + 4) = acos(bracket) * 180 / M_PI;
            }
            else if (*(array2D + i * 6 + 2) >= 0)
            {
                *(array2D + i * 6 + 4) = (asin(bracket) * 180 / M_PI) + 90;
            }

            /*A megfelelő index beállítása.*/
            /*Azt vesszük alapul, hogy az adott szög, egy új körvonahoz tartozik (azaz newCircle = 1).*/
            newCircle = 1;

            /*Ha már korábban volt ilyen érték (a meghatározott intervallumon belül), akkor ez nem egy új körív.
            Azaz "newCircle = 0", a folyamatból kiléphetünk, nincs szükség további vizsgálatra.*/
            for (j = 0; j < channels; j++)
            {
                if (angle[j] == 0)
                    break;

                if (abs(angle[j] - *(array2D + i * 6 + 4)) <= interval)
                {
                    newCircle = 0;
                    break;
                }
            }

            /*Ha ilyen érték, nem szerepel még a tömbben, akkor ez egy új körív.*/
            if (newCircle == 1)
            {
                /*Feltétel, hogy a program ne lépjen ki szegmentálási hibával.
                Ha valamilyen okból, több körív keletkezne mint 64, hiba lépne fel.*/
                if (index < channels)
                {
                    angle[index] = *(array2D + i * 6 + 4);
                    index++;
                }
            }
        }

        /*--- A 6. oszlop feltöltése. ---*/
        /*Csaplár László kódja által, magaspontoknak jelölt pontok felvétele a 2D tömbbe.*/
        if (star_shaped_method )
        {
            for (i = 0; i < padkaIDs.size(); i++)
            {
                *(array2D + padkaIDs[i] * 6 + 5) = 2;
            }
        }

        /*A szögfelbontások növekvő sorrendbe rendezése.
        A legkisebb lesz az első körív és így tovább.*/
        std::sort(angle, angle + index);

        /*
        3D tömb:
        - A pontok értékei: (0: X, 1: Y, 2: Z),
        - A pontok origótól vett távolsága, z = 0 értékkel: (3: D),
        - A pontok helyzete egy körben (360°). (4: Alpha),
        - X = 0 érték mellett, az új Y koordináták (5: új Y),
        - Csoportszámok (6: Road = 1, High = 2).
        */
        float *array3D = new float[channels * piece * 7]();

        /*Az adott köríveket tartalmazó csoportok (azaz a "channels"),
        megfelelő sorindexeinek beállításához szükséges.
        Fontos, hogy 0 értékekkel töltsük fel.*/
        int indexArray[channels] = {0};

        /*Egy 1D tömb. Az adott köríven, az origótól, a legnagyobb távolsággal rendelkező pontok értékei.*/
        float maxDistance[channels] = {0};

        /*Hibás LIDAR csatornaszám esetén szükséges.*/
        int results;

        /*A 3D tömb feltöltése.*/
        for (i = 0; i < piece; i++)
        {
            results = 0;

            /*A megfelelő körív kiválasztása.*/
            for (j = 0; j < index; j++)
            {
                if (abs(angle[j] - *(array2D + i * 6 + 4)) <= interval)
                {
                    results = 1;
                    break;
                }
            }

            if (results == 1)
            {
                /*Az értékek hozzáadás, a 2D tömbből.*/
                *(array3D + j * piece * 7 + indexArray[j] * 7 + 0) = *(array2D + i * 6 + 0); /*X koordináta.*/
                *(array3D + j * piece * 7 + indexArray[j] * 7 + 1) = *(array2D + i * 6 + 1); /*Y koordináta.*/
                *(array3D + j * piece * 7 + indexArray[j] * 7 + 2) = *(array2D + i * 6 + 2); /*Z koordináta.*/

                /*A már ismert magaspontok.*/
                if (star_shaped_method )
                    *(array3D + j * piece * 7 + indexArray[j] * 7 + 6) = *(array2D + i * 6 + 5);

                /*Itt annyi különbség lesz, hogy a "z" érték nélkül adjuk hozzá a távolságot.*/
                *(array3D + j * piece * 7 + indexArray[j] * 7 + 3) = sqrt(pow(*(array2D + i * 6 + 0), 2) + pow(*(array2D + i * 6 + 1), 2));

                /*Az 5. oszlop feltöltése, a szögekkel. 360 fokban, minden pontnak van egy szöge.*/
                bracket = (abs(*(array3D + j * piece * 7 + indexArray[j] * 7 + 0))) / (*(array3D + j * piece * 7 + indexArray[j] * 7 + 3));
                if (bracket < -1)
                    bracket = -1;
                else if (bracket > 1)
                    bracket = 1;

                if (*(array3D + j * piece * 7 + indexArray[j] * 7 + 0) >= 0 && *(array3D + j * piece * 7 + indexArray[j] * 7 + 1) <= 0)
                {
                    *(array3D + j * piece * 7 + indexArray[j] * 7 + 4) = asin(bracket) * 180 / M_PI;
                }
                else if (*(array3D + j * piece * 7 + indexArray[j] * 7 + 0) >= 0 && *(array3D + j * piece * 7 + indexArray[j] * 7 + 1) > 0)
                {
                    *(array3D + j * piece * 7 + indexArray[j] * 7 + 4) = 180 - (asin(bracket) * 180 / M_PI);
                }
                else if (*(array3D + j * piece * 7 + indexArray[j] * 7 + 0) < 0 && *(array3D + j * piece * 7 + indexArray[j] * 7 + 1) >= 0)
                {
                    *(array3D + j * piece * 7 + indexArray[j] * 7 + 4) = 180 + (asin(bracket) * 180 / M_PI);
                }
                else
                {
                    *(array3D + j * piece * 7 + indexArray[j] * 7 + 4) = 360 - (asin(bracket) * 180 / M_PI);
                }

                if (*(array3D + j * piece * 7 + indexArray[j] * 7 + 3) > maxDistance[j])
                {
                    maxDistance[j] = *(array3D + j * piece * 7 + indexArray[j] * 7 + 3);
                }

                indexArray[j]++;
            }
        }

        /*A lefoglalt terület felszabadítása.*/
        delete[] array2D;

        /*-- 1. lépés: A NEM út pontok szűrése. --*/
        int p2, p3; /*p2, p3 - A három vizsgált pontból, a második és a harmadik.*/

        /*
        --> alpha - A három pont és a két vektor által bezárt szög.
        --> x1, x2, x3 - A három pont által bezárt háromszög oldalainak hossza.
        --> curbPoints - A pontok becsült száma, a szegélyen.
        --> va1, va2, vb1, vb2 - A két vektor.
        --> max1, max2 - Nem csak a szöget, hanem a magasságot is vizsgálni kell.
        --> d - A két szélső pont közötti távolság. A LIDAR forgása és a körív szakadások miatt.
            d - Ez a változó a program későbbi részein is felhasználásra kerül.
        */
        float alpha, x1, x2, x3, va1, va2, vb1, vb2, max1, max2, d;

        /*Az összes kör vizsgálata.*/
        for (i = 0; i < index; i++)
        {
            if (x_zero_method)
            {
                /*Új Y értékek beállítása, X = 0 értékek mellett.*/
                for (j = 1; j < indexArray[i]; j++)
                {
                    *(array3D + i * piece * 7 + j * 7 + 5) = *(array3D + i * piece * 7 + (j - 1) * 7 + 5) + 0.0100;
                }

                /*A kör pontjainak vizsgálata. X = 0 módszer.*/
                for (j = curbPoints; j <= (indexArray[i] - 1) - curbPoints; j++)
                {
                    p2 = j + curbPoints / 2;
                    p3 = j + curbPoints;

                    d = sqrt(
                        pow(*(array3D + i * piece * 7 + p3 * 7 + 0) - *(array3D + i * piece * 7 + j * 7 + 0), 2) +
                        pow(*(array3D + i * piece * 7 + p3 * 7 + 1) - *(array3D + i * piece * 7 + j * 7 + 1), 2));

                    /*A távolság, 5 méternél kisebb legyen.*/
                    if (d < 5.0000)
                    {
                        x1 = sqrt(
                            pow(*(array3D + i * piece * 7 + p2 * 7 + 5) - *(array3D + i * piece * 7 + j * 7 + 5), 2) +
                            pow(*(array3D + i * piece * 7 + p2 * 7 + 2) - *(array3D + i * piece * 7 + j * 7 + 2), 2));
                        x2 = sqrt(
                            pow(*(array3D + i * piece * 7 + p3 * 7 + 5) - *(array3D + i * piece * 7 + p2 * 7 + 5), 2) +
                            pow(*(array3D + i * piece * 7 + p3 * 7 + 2) - *(array3D + i * piece * 7 + p2 * 7 + 2), 2));
                        x3 = sqrt(
                            pow(*(array3D + i * piece * 7 + p3 * 7 + 5) - *(array3D + i * piece * 7 + j * 7 + 5), 2) +
                            pow(*(array3D + i * piece * 7 + p3 * 7 + 2) - *(array3D + i * piece * 7 + j * 7 + 2), 2));

                        bracket = (pow(x3, 2) - pow(x1, 2) - pow(x2, 2)) / (-2 * x1 * x2);
                        if (bracket < -1)
                            bracket = -1;
                        else if (bracket > 1)
                            bracket = 1;

                        alpha = acos(bracket) * 180 / M_PI;

                        /*Feltétel és csoporthoz adás.*/
                        if (alpha <= angleFilter1 &&
                            (abs(*(array3D + i * piece * 7 + j * 7 + 2) - *(array3D + i * piece * 7 + p2 * 7 + 2)) >= curbHeight ||
                             abs(*(array3D + i * piece * 7 + p3 * 7 + 2) - *(array3D + i * piece * 7 + p2 * 7 + 2)) >= curbHeight) &&
                            abs(*(array3D + i * piece * 7 + j * 7 + 2) - *(array3D + i * piece * 7 + p3 * 7 + 2)) >= 0.05)
                        {
                            *(array3D + i * piece * 7 + p2 * 7 + 6) = 2;
                        }
                    }
                }
            }

            if (y_zero_method)
            {
                /*A kör pontjainak vizsgálata. Z = 0 módszer.*/
                for (j = curbPoints; j <= (indexArray[i] - 1) - curbPoints; j++)
                {
                    d = sqrt(
                        pow(*(array3D + i * piece * 7 + (j + curbPoints) * 7 + 0) - *(array3D + i * piece * 7 + (j - curbPoints) * 7 + 0), 2) +
                        pow(*(array3D + i * piece * 7 + (j + curbPoints) * 7 + 1) - *(array3D + i * piece * 7 + (j - curbPoints) * 7 + 1), 2));

                    /*A távolság, 5 méternél kisebb legyen.*/
                    if (d < 5.0000)
                    {
                        /*Kezdeti értékek beállítása.*/
                        max1 = abs(*(array3D + i * piece * 7 + j * 7 + 2)), max2 = abs(*(array3D + i * piece * 7 + j * 7 + 2));
                        va1 = 0, va2 = 0, vb1 = 0, vb2 = 0;

                        /*Az 'a' vektor és a legnagyobb magasság beállítása.*/
                        for (k = j - 1; k >= j - curbPoints; k--)
                        {
                            va1 = va1 + (*(array3D + i * piece * 7 + k * 7 + 0) - *(array3D + i * piece * 7 + j * 7 + 0));
                            va2 = va2 + (*(array3D + i * piece * 7 + k * 7 + 1) - *(array3D + i * piece * 7 + j * 7 + 1));
                            if (abs(*(array3D + i * piece * 7 + k * 7 + 2)) > max1)
                                max1 = abs(*(array3D + i * piece * 7 + k * 7 + 2));
                        }

                        /*A 'b' vektor és a legnagyobb magasság beállítása.*/
                        for (k = j + 1; k <= j + curbPoints; k++)
                        {
                            vb1 = vb1 + (*(array3D + i * piece * 7 + k * 7 + 0) - *(array3D + i * piece * 7 + j * 7 + 0));
                            vb2 = vb2 + (*(array3D + i * piece * 7 + k * 7 + 1) - *(array3D + i * piece * 7 + j * 7 + 1));
                            if (abs(*(array3D + i * piece * 7 + k * 7 + 2)) > max2)
                                max2 = abs(*(array3D + i * piece * 7 + k * 7 + 2));
                        }

                        va1 = (1 / (float)curbPoints) * va1;
                        va2 = (1 / (float)curbPoints) * va2;
                        vb1 = (1 / (float)curbPoints) * vb1;
                        vb2 = (1 / (float)curbPoints) * vb2;

                        bracket = (va1 * vb1 + va2 * vb2) / (sqrt(pow(va1, 2) + pow(va2, 2)) * sqrt(pow(vb1, 2) + pow(vb2, 2)));
                        if (bracket < -1)
                            bracket = -1;
                        else if (bracket > 1)
                            bracket = 1;

                        alpha = acos(bracket) * 180 / M_PI;

                        /*Feltétel és csoporthoz adás.*/
                        if (alpha <= angleFilter2 &&
                            (max1 - abs(*(array3D + i * piece * 7 + j * 7 + 2)) >= curbHeight ||
                             max2 - abs(*(array3D + i * piece * 7 + j * 7 + 2)) >= curbHeight) &&
                            abs(max1 - max2) >= 0.05)
                        {
                            *(array3D + i * piece * 7 + j * 7 + 6) = 2;
                        }
                    }
                }
            }
        }

        /*-- 2. lépés: Az út pontok szűrése. --*/
        /*A tömb elemeinek rendezése oly módon, hogy körönként, a szögeknek megfelelő sorrendben legyenek.*/
        for (i = 0; i < index; i++)
        {
            quickSort(array3D, i, piece, 0, indexArray[i] - 1);
        }

        /*Vakfolt keresés:
        Megvizsgáljuk a második körvonalat. (Az elsővel pontatlan.)
        Főleg a [90°-180° --- 180°-270°] tartomány és a [0°-90° --- 270°-360°] tartomány a lényeg, az autó két oldalán.
        Mind a kettő tartományban keresünk 2db magaspontot. Ha az adott tartományban az első körvonalon van két magaspont,
        a közte lévő terület nagy valószínűséggel egy vakfolt lesz.*/
        float q1 = 0, q2 = 180, q3 = 180, q4 = 360; /*A kör négy része. (1. 2. 3. 4. negyed.)*/
        int c1 = -1, c2 = -1, c3 = -1, c4 = -1;     /*A talált pontok ID-ja az első körvonalon.*/

        if (blind_spots)
        {
            for (i = 0; i < indexArray[1]; i++)
            {
                if (*(array3D + 1 * piece * 7 + i * 7 + 6) == 2)
                {
                    if (*(array3D + 1 * piece * 7 + i * 7 + 4) >= 0 && *(array3D + 1 * piece * 7 + i * 7 + 4) < 90)
                    {
                        if (*(array3D + 1 * piece * 7 + i * 7 + 4) > q1)
                        {
                            q1 = *(array3D + 1 * piece * 7 + i * 7 + 4);
                            c1 = i;
                        }
                    }
                    else if (*(array3D + 1 * piece * 7 + i * 7 + 4) >= 90 && *(array3D + 1 * piece * 7 + i * 7 + 4) < 180)
                    {
                        if (*(array3D + 1 * piece * 7 + i * 7 + 4) < q2)
                        {
                            q2 = *(array3D + 1 * piece * 7 + i * 7 + 4);
                            c2 = i;
                        }
                    }
                    else if (*(array3D + 1 * piece * 7 + i * 7 + 4) >= 180 && *(array3D + 1 * piece * 7 + i * 7 + 4) < 270)
                    {
                        if (*(array3D + 1 * piece * 7 + i * 7 + 4) > q3)
                        {
                            q3 = *(array3D + 1 * piece * 7 + i * 7 + 4);
                            c3 = i;
                        }
                    }
                    else
                    {
                        if (*(array3D + 1 * piece * 7 + i * 7 + 4) < q4)
                        {
                            q4 = *(array3D + 1 * piece * 7 + i * 7 + 4);
                            c4 = i;
                        }
                    }
                }
            }
        }

        float arcDistance;   /*Körív mérete, a megadott foknál. Fontos minden körön, ugyanakkora körív méretet vizsgálni.*/
        int notRoad;         /*Ha az adott köríven, az adott szakaszon, található magaspont, akkor 1-es értéket vesz fel, amúgy 0-át.*/
        int blindSpot;       /*Vakfoltok az autó mellett.*/
        float currentDegree; /*Az aktuális köríven, a szög nagysága.*/

        /*A körív méret meghatározása.*/
        arcDistance = ((maxDistance[0] * M_PI) / 180) * beamZone;

        /*0°-tól 360° - beamZone-ig.*/
        for (i = 0; i <= 360 - beamZone; i++)
        {
            blindSpot = 0;

            if (blind_spots)
            {
                /*Ha ezek a feltételek teljesülnek, akkor egy vakfoltba léptünk és itt nem vizsgálódunk.*/
                if (xDirection == 0)
                {
                    /*+-X irányba is vizsgáljuk a pontokat.*/
                    if ((q1 != 0 && q4 != 360 && (i <= q1 || i >= q4)) || (q2 != 180 && q3 != 180 && i >= q2 && i <= q3))
                    {
                        blindSpot = 1;
                    }
                }
                else if (xDirection == 1)
                {
                    /*+X irányba vizsgáljuk a pontokat.*/
                    if ((q2 != 180 && i >= q2 && i <= 270) || (q1 != 0 && (i <= q1 || i >= 270)))
                    {
                        blindSpot = 1;
                    }
                }
                else
                {
                    /*-X vizsgáljuk a pontokat.*/
                    if ((q4 != 360 && (i >= q4 || i <= 90)) || (q3 != 180 && i <= q3 && i >= 90))
                    {
                        blindSpot = 1;
                    }
                }
            }

            if (blindSpot == 0)
            {
                /*Alap beállítás, hogy az adott szakaszon nincs magaspont.*/
                notRoad = 0;

                /*Az első kör adott szakaszának vizsgálata.*/
                for (j = 0; *(array3D + 0 * piece * 7 + j * 7 + 4) <= i + beamZone && j < indexArray[0]; j++)
                {
                    if (*(array3D + 0 * piece * 7 + j * 7 + 4) >= i)
                    {
                        /*Nem vizsgáljuk tovább az adott szakaszt, ha találunk benne magaspontot.*/
                        if (*(array3D + 0 * piece * 7 + j * 7 + 6) == 2)
                        {
                            notRoad = 1;
                            break;
                        }
                    }
                }

                /*Ha nem találtunk az első kör, adott szakaszán magaspontot, továbbléphetünk a következő körre.*/
                if (notRoad == 0)
                {
                    /*Az első kör szakaszát elfogadjuk.*/
                    for (j = 0; *(array3D + 0 * piece * 7 + j * 7 + 4) <= i + beamZone && j < indexArray[0]; j++)
                    {
                        if (*(array3D + 0 * piece * 7 + j * 7 + 4) >= i)
                        {
                            *(array3D + 0 * piece * 7 + j * 7 + 6) = 1;
                        }
                    }

                    /*A további körök vizsgálata.*/
                    for (k = 1; k < index; k++)
                    {
                        /*Új szöget kell meghatározni, hogy a távolabbi körvonalakon is, ugyanakkora körív hosszt vizsgáljunk.*/
                        if (i == 360 - beamZone)
                        {
                            currentDegree = 360;
                        }
                        else
                        {
                            currentDegree = i + arcDistance / ((maxDistance[k] * M_PI) / 180);
                        }

                        /*Az új kör pontjait vizsgáljuk.*/
                        for (l = 0; *(array3D + k * piece * 7 + l * 7 + 4) <= currentDegree && l < indexArray[k]; l++)
                        {
                            if (*(array3D + k * piece * 7 + l * 7 + 4) >= i)
                            {
                                /*Nem vizsgáljuk tovább az adott szakaszt, ha találunk benne magaspontot.*/
                                if (*(array3D + k * piece * 7 + l * 7 + 6) == 2)
                                {
                                    notRoad = 1;
                                    break;
                                }
                            }
                        }

                        /*A többi kört nem vizsgáljuk, ha a sugár, elakadt egy magasponton.*/
                        if (notRoad == 1)
                            break;

                        /*Egyébként, elfogadjuk az adott kör, adott szakaszát.*/
                        for (l = 0; *(array3D + k * piece * 7 + l * 7 + 4) <= currentDegree && l < indexArray[k]; l++)
                        {
                            if (*(array3D + k * piece * 7 + l * 7 + 4) >= i)
                            {
                                *(array3D + k * piece * 7 + l * 7 + 6) = 1;
                            }
                        }
                    }
                }
            }
        }

        /*Ugyanaz, mint az előző, csak itt 360°-tól 0° + beamZone-ig vizsgáljuk a pontokat.*/
        for (i = 360; i >= 0 + beamZone; --i)
        {
            blindSpot = 0;

            if (blind_spots)
            {
                /*Ha ezek a feltételek teljesülnek, akkor egy vakfoltba léptünk és itt nem vizsgálódunk.*/
                if (xDirection == 0)
                {
                    /*+-X irányba is vizsgáljuk a pontokat.*/
                    if ((q1 != 0 && q4 != 360 && (i <= q1 || i >= q4)) || (q2 != 180 && q3 != 180 && i >= q2 && i <= q3))
                    {
                        blindSpot = 1;
                    }
                }
                else if (xDirection == 1)
                {
                    /*+X irányba vizsgáljuk a pontokat.*/
                    if ((q2 != 180 && i >= q2 && i <= 270) || (q1 != 0 && (i <= q1 || i >= 270)))
                    {
                        blindSpot = 1;
                    }
                }
                else
                {
                    /*-X vizsgáljuk a pontokat.*/
                    if ((q4 != 360 && (i >= q4 || i <= 90)) || (q3 != 180 && i <= q3 && i >= 90))
                    {
                        blindSpot = 1;
                    }
                }
            }

            if (blindSpot == 0)
            {
                /*Alap beállítás, hogy az adott szakaszon nincs magaspont.*/
                notRoad = 0;

                /*Az első kör adott szakaszának vizsgálata.*/
                for (j = indexArray[0] - 1; *(array3D + 0 * piece * 7 + j * 7 + 4) >= i - beamZone && j >= 0; --j)
                {
                    if (*(array3D + 0 * piece * 7 + j * 7 + 4) <= i)
                    {
                        /*Nem vizsgáljuk tovább az adott szakaszt, ha találunk benne magaspontot.*/
                        if (*(array3D + 0 * piece * 7 + j * 7 + 6) == 2)
                        {
                            notRoad = 1;
                            break;
                        }
                    }
                }

                /*Ha nem találtunk az első kör, adott szakaszán magaspontot, továbbléphetünk a következő körre.*/
                if (notRoad == 0)
                {
                    /*Az első kör szakaszát elfogadjuk.*/
                    for (j = indexArray[0] - 1; *(array3D + 0 * piece * 7 + j * 7 + 4) >= i - beamZone && j >= 0; --j)
                    {
                        if (*(array3D + 0 * piece * 7 + j * 7 + 4) <= i)
                        {
                            *(array3D + 0 * piece * 7 + j * 7 + 6) = 1;
                        }
                    }

                    /*A további körök vizsgálata.*/
                    for (k = 1; k < index; k++)
                    {
                        /*Új szöget kell meghatározni, hogy a távolabbi körvonalakon is, ugyanakkora körív hosszt vizsgáljunk.*/
                        if (i == 0 + beamZone)
                        {
                            currentDegree = 0;
                        }
                        else
                        {
                            currentDegree = i - arcDistance / ((maxDistance[k] * M_PI) / 180);
                        }

                        /*Az új kör pontjait vizsgáljuk.*/
                        for (l = indexArray[k] - 1; *(array3D + k * piece * 7 + l * 7 + 4) >= currentDegree && l >= 0; --l)
                        {
                            if (*(array3D + k * piece * 7 + l * 7 + 4) <= i)
                            {
                                /*Nem vizsgáljuk tovább az adott szakaszt, ha találunk benne magaspontot.*/
                                if (*(array3D + k * piece * 7 + l * 7 + 6) == 2)
                                {
                                    notRoad = 1;
                                    break;
                                }
                            }
                        }

                        /*A többi kört nem vizsgáljuk, ha a sugár, elakadt egy magasponton.*/
                        if (notRoad == 1)
                            break;

                        /*Egyébként, elfogadjuk az adott kör, adott szakaszát.*/
                        for (l = indexArray[k] - 1; *(array3D + k * piece * 7 + l * 7 + 4) >= currentDegree && l >= 0; --l)
                        {
                            if (*(array3D + k * piece * 7 + l * 7 + 4) <= i)
                            {
                                *(array3D + k * piece * 7 + l * 7 + 6) = 1;
                            }
                        }
                    }
                }
            }
        }

        /*-- 3. lépés: A marker pontjainak keresése. Adott fokban a legtávolabbi zöld pont. --*/
        /*A marker pontjait tartalmazza. Az első három oszlopban az X - Y - Z koordinátát,
        a negyedikben pedig 0 - 1 érték szerepel attól függően, hogy az adott fokban található-e olyan pont, ami nincs útnak jelölve.*/
        float markerPointsArray[piece][4];
        float maxDistanceRoad; /*Adott fokban, a legtávolabbi zöld pont távolsága.*/
        int cM = 0;            /*Segédváltozó, a marker pontok feltöltéséhez (c - counter, M - Marker).*/
        int ID1, ID2;          /*Az adott pont melyik körvonalon van (ID1) és hányadik pont (ID2).*/
        int redPoints;         /*A vizsgált sávban van-e magaspont, vagy olyan pont, amit nem jelölt a program útnak, se magaspontnak.*/

        /*360 fokban megvizsgáljuk a pontokat, 1 fokonként.*/
        for (i = 0; i <= 360; i++)
        {
            ID1 = -1;
            ID2 = -1;
            maxDistanceRoad = 0;
            redPoints = 0;

            /*Itt végigmegyünk az összes körvonal, összes pontján.*/
            for (j = 0; j < index; j++)
            {
                for (k = 0; k < indexArray[j]; k++)
                {
                    /*Ha találunk az adott fokban nem út pontot, akkor kilépünk, mert utána úgyse lesz már út pont és a "redPoints" változó 1-es érétket kap.*/
                    if (*(array3D + j * piece * 7 + k * 7 + 6) != 1 && *(array3D + j * piece * 7 + k * 7 + 4) >= i && *(array3D + j * piece * 7 + k * 7 + 4) < i + 1)
                    {
                        redPoints = 1;
                        break;
                    }

                    /*A talált zöld pont távolságának vizsgálata.*/
                    if (*(array3D + j * piece * 7 + k * 7 + 6) == 1 && *(array3D + j * piece * 7 + k * 7 + 4) >= i && *(array3D + j * piece * 7 + k * 7 + 4) < i + 1)
                    {
                        d = sqrt(pow(0 - *(array3D + j * piece * 7 + k * 7 + 0), 2) + pow(0 - *(array3D + j * piece * 7 + k * 7 + 1), 2));

                        if (d > maxDistanceRoad)
                        {
                            maxDistanceRoad = d;
                            ID1 = j;
                            ID2 = k;
                        }
                    }
                }
                /*A korábbi "break", kilépett az adott körvonalból, ez a továbbiakból is kilép, és jön a következő fok vizsgálata.*/
                if (redPoints == 1)
                    break;
            }

            /*A marker pontok hozzáadása a tömbhöz.*/
            if (ID1 != -1 && ID2 != -1)
            {
                markerPointsArray[cM][0] = *(array3D + ID1 * piece * 7 + ID2 * 7 + 0);
                markerPointsArray[cM][1] = *(array3D + ID1 * piece * 7 + ID2 * 7 + 1);
                markerPointsArray[cM][2] = *(array3D + ID1 * piece * 7 + ID2 * 7 + 2);
                markerPointsArray[cM][3] = redPoints;
                cM++;
            }
        }

        /*-- 4. lépés: A csoportok feltöltése. --*/
        for (i = 0; i < index; i++)
        {
            for (j = 0; j < indexArray[i]; j++)
            {
                /*Az út pontok.*/
                if (*(array3D + i * piece * 7 + j * 7 + 6) == 1)
                {
                    pt.x = *(array3D + i * piece * 7 + j * 7 + 0);
                    pt.y = *(array3D + i * piece * 7 + j * 7 + 1);
                    pt.z = *(array3D + i * piece * 7 + j * 7 + 2);
                    cloud_filtered_Road.push_back(pt);
                }

                /*A magas pontok.*/
                else if (*(array3D + i * piece * 7 + j * 7 + 6) == 2)
                {
                    pt.x = *(array3D + i * piece * 7 + j * 7 + 0);
                    pt.y = *(array3D + i * piece * 7 + j * 7 + 1);
                    pt.z = *(array3D + i * piece * 7 + j * 7 + 2);
                    cloud_filtered_High.push_back(pt);
                }
            }
        }

        /*-- 5. lépés: A marker beállítása. --*/
        /*Legyen minimum 3 pont, amit össze lehet kötni, különben hibák lépnének fel.*/
        if (cM > 2)
        {
            /*Lehet olyan eset, hogy piros - zöld - prios (vagy fordítva) pont van egymás mellett.
            Ez azért rossz, mert a zöld / piros marker (line strip) ebben az esetben csak 1 pont lesz.
            Ez nem javasolt, ezért minden pontnak lennie kell egy azonos színű párjának.
            A "markerPointsArray" tömb 3. oszlopában ha 1-es szerepel, akkor az a piros line strip-hez tartozik,
            ellenkező esetben a zöldhöz.*/

            /*Ha az első pont zöld, de a második piros, akkor az első is a piros line strip-be kerül.*/
            if (markerPointsArray[0][3] == 0 && markerPointsArray[1][3] == 1)
                markerPointsArray[0][3] = 1;

            /*Ha az utolsó pont zöld, de az utolsó előtti piros, akkor az utolsó is a piros line strip-be kerül.*/
            if (markerPointsArray[cM - 1][3] == 0 && markerPointsArray[cM - 2][3] == 1)
                markerPointsArray[cM - 1][3] = 1;

            /*Ha az első pont piros, de a második zöld, akkor az első is a zöld line strip-be kerül.*/
            if (markerPointsArray[0][3] == 1 && markerPointsArray[1][3] == 0)
                markerPointsArray[0][3] = 0;

            /*Ha az utolsó pont piros, de az utolsó előtti zöld, akkor az utolsó is a zöld line strip-be kerül.*/
            if (markerPointsArray[cM - 1][3] == 1 && markerPointsArray[cM - 2][3] == 0)
                markerPointsArray[cM - 1][3] = 0;

            /*Itt végig megyünk a pontokon, ha egy zöld pontot két piros fog közre, akkor az is a piros line strip-be kerül.
            Az első kettő és az utolsó kettő pontot nem vizsgáljuk, ezek már be vannak állítva.*/
            for (i = 2; i <= cM - 3; i++)
            {
                if (markerPointsArray[i][3] == 0 && markerPointsArray[i - 1][3] == 1 && markerPointsArray[i + 1][3] == 1)
                    markerPointsArray[i][3] = 1;
            }

            /*Itt végig megyünk az összes ponton, ha egy piros pontot két zöld fog közre, akkor az is a zöld line strip-be kerül.
            Az első kettő és az utolsó kettő pontot nem vizsgáljuk, ezek már be vannak állítva.*/
            for (i = 2; i <= cM - 3; i++)
            {
                if (markerPointsArray[i][3] == 1 && markerPointsArray[i - 1][3] == 0 && markerPointsArray[i + 1][3] == 0)
                    markerPointsArray[i][3] = 0;
            }

            visualization_msgs::MarkerArray ma;    /*Egy marker array, amiben a zöld / piros line strip-ek kerülnek.*/
            visualization_msgs::Marker line_strip; /*Az adott zöld vagy piros szakasz / line strip.*/
            geometry_msgs::Point point;            /*Az adott pont értékei. Ez tölti fel az adott line stip-et.*/
float zavg = 0.0;                      /*Átlagos z-érték (egyszerűsített polygonhoz)*/

            int lineStripID = 0; /*Az adott line strip ID-ja.*/

            line_strip.header.frame_id = fixedFrame;
            line_strip.header.stamp = ros::Time();
            line_strip.type = visualization_msgs::Marker::LINE_STRIP;
            line_strip.action = visualization_msgs::Marker::ADD;

            /*Végigmegyünk a pontokon, amik a markert fogják alkotni.*/
            for (i = 0; i < cM; i++)
            {
                /*Az adott pont hozzáadása egy "geometry_msgs::Point" típusú változóhoz.*/
                point.x = markerPointsArray[i][0];
                point.y = markerPointsArray[i][1];
                point.z = markerPointsArray[i][2];
                zavg *= i;
                zavg += point.z;
                zavg /= i+1;

                /*Az első pont hozzáadása az adott line strip-hez.
                Az első pontnál semmilyen feltétel nem kell.*/
                if (i == 0)
                {
                    line_strip.points.push_back(point);
                    line += xy(point.x,point.y);
                }

                /*Ha a következő pont is ugyanabba a csoportba (piros vagy zöld) tartozik, mint az előző,
                akkor ezt is hozzáadjuk az adott line strip-hez.*/
                else if (markerPointsArray[i][3] == markerPointsArray[i - 1][3])
                {
                    line_strip.points.push_back(point);
                    line += xy(point.x,point.y);

                    /*Ebben az "else if" feltételben fogjuk elérni az utolsó pontot, itt elkészül az utolsó line strip.*/
                    if (i == cM - 1)
                    {
                        line_strip.id = lineStripID;

                        line_strip.pose.position.x = 0;
                        line_strip.pose.position.y = 0;
                        line_strip.pose.position.z = 0;

                        line_strip.pose.orientation.x = 0.0;
                        line_strip.pose.orientation.y = 0.0;
                        line_strip.pose.orientation.z = 0.0;
                        line_strip.pose.orientation.w = 1.0;

                        line_strip.scale.x = 0.5;
                        line_strip.scale.y = 0.5;
                        line_strip.scale.z = 0.5;

                        /*A line strip színének a beállítása.*/
                        if (markerPointsArray[i][3] == 0)
                        {
                            line_strip.color.a = 1.0;
                            line_strip.color.r = 0.0;
                            line_strip.color.g = 1.0;
                            line_strip.color.b = 0.0;
                        }
                        else
                        {
                            line_strip.color.a = 1.0;
                            line_strip.color.r = 1.0;
                            line_strip.color.g = 0.0;
                            line_strip.color.b = 0.0;
                        }

                        if (polysimp_allow)
                        {
                            line_strip.points.clear();
                            boost::geometry::clear(simplified);
                            boost::geometry::simplify(line, simplified, polysimp);
                            for(boost::geometry::model::linestring<xy>::const_iterator it = simplified.begin(); it != simplified.end(); it++)
                            {
                                geometry_msgs::Point p;
                                p.x = boost::geometry::get<0>(*it);
                                p.y = boost::geometry::get<1>(*it);
                                p.z = polyz;

                                line_strip.points.push_back(p);
                            }
                        }

                        ma.markers.push_back(line_strip); /*A line strip hozzáadása a marker array-hez.*/
                        line_strip.points.clear();        /*Az utolsó line strip-ből is töröljük a pontokat, feleslegesen ne tárolódjon.*/
                        boost::geometry::clear(line);
                    }
                }

                /*Csoportváltozás --> pirosról - zöldre.
                Ilyenkor még piros marker köti össze a két pontot, szóval hozzáadjuk a pontot az adott line strip-hez.*/
                else if (markerPointsArray[i][3] != markerPointsArray[i - 1][3] && markerPointsArray[i][3] == 0)
                {
                    line_strip.points.push_back(point);
                    line += xy(point.x,point.y);

                    /*A következő pontok már új line strip-hez fognak tartozni, szóval itt elkészül az egyik piros.*/
                    line_strip.id = lineStripID;
                    lineStripID++;

                    line_strip.pose.position.x = 0;
                    line_strip.pose.position.y = 0;
                    line_strip.pose.position.z = 0;

                    line_strip.pose.orientation.x = 0.0;
                    line_strip.pose.orientation.y = 0.0;
                    line_strip.pose.orientation.z = 0.0;
                    line_strip.pose.orientation.w = 1.0;

                    line_strip.scale.x = 0.5;
                    line_strip.scale.y = 0.5;
                    line_strip.scale.z = 0.5;

                    line_strip.color.a = 1.0;
                    line_strip.color.r = 1.0;
                    line_strip.color.g = 0.0;
                    line_strip.color.b = 0.0;

                    if (polysimp_allow)
                    {
                        line_strip.points.clear();
                        boost::geometry::clear(simplified);
                        boost::geometry::simplify(line, simplified, polysimp);
                        for(boost::geometry::model::linestring<xy>::const_iterator it = simplified.begin(); it != simplified.end(); it++)
                        {
                            geometry_msgs::Point p;
                            p.x = boost::geometry::get<0>(*it);
                            p.y = boost::geometry::get<1>(*it);
                            p.z = polyz;

                            line_strip.points.push_back(p);
                        }
                    }

                    ma.markers.push_back(line_strip);   /*A line strip hozzáadása a marker array-hez.*/
                    line_strip.points.clear();          /*A benne lévő pontok már nem kellenek.*/
                    boost::geometry::clear(line);
                    line_strip.points.push_back(point); /*A következő zöld line strip-nél is szükség van erre a pontra, szóval hozzáadjuk.*/
                    line += xy(point.x,point.y);
                }

                /*Csoportváltozás --> zöldről - pirosra.
                Előszőr beállítjuk a zöld line stip-et, majd az utolsó pontot hozzáadjuk a piroshoz is,
                mivel zöld és piros pont között mindig piros line srip van.*/
                else if (markerPointsArray[i][3] != markerPointsArray[i - 1][3] && markerPointsArray[i][3] == 1)
                {
                    /*A zöld marker.*/
                    line_strip.id = lineStripID;
                    lineStripID++;

                    line_strip.pose.position.x = 0;
                    line_strip.pose.position.y = 0;
                    line_strip.pose.position.z = 0;

                    line_strip.pose.orientation.x = 0.0;
                    line_strip.pose.orientation.y = 0.0;
                    line_strip.pose.orientation.z = 0.0;
                    line_strip.pose.orientation.w = 1.0;

                    line_strip.scale.x = 0.5;
                    line_strip.scale.y = 0.5;
                    line_strip.scale.z = 0.5;

                    line_strip.color.a = 1.0;
                    line_strip.color.r = 0.0;
                    line_strip.color.g = 1.0;
                    line_strip.color.b = 0.0;

                    if (polysimp_allow)
                    {
                        line_strip.points.clear();
                        boost::geometry::clear(simplified);
                        boost::geometry::simplify(line, simplified, polysimp);
                        for(boost::geometry::model::linestring<xy>::const_iterator it = simplified.begin(); it != simplified.end(); it++)
                        {
                            geometry_msgs::Point p;
                            p.x = boost::geometry::get<0>(*it);
                            p.y = boost::geometry::get<1>(*it);
                            p.z = polyz;

                            line_strip.points.push_back(p);
                        }
                    }

                    ma.markers.push_back(line_strip); /*A line strip hozzáadása a marker array-hez.*/
                    line_strip.points.clear();        /*A benne lévő pontok már nem kellenek.*/
                    boost::geometry::clear(line);

                    /*A követkető piros line srip-hez szükség van az előző pontra is.*/
                    point.x = markerPointsArray[i - 1][0];
                    point.y = markerPointsArray[i - 1][1];
                    point.z = markerPointsArray[i - 1][2];
                    line_strip.points.push_back(point);
                    line += xy(point.x,point.y);

                    /*A követkető piros line srip-hez szükség van a jelenlegi pontra.*/
                    point.x = markerPointsArray[i][0];
                    point.y = markerPointsArray[i][1];
                    point.z = markerPointsArray[i][2];
                    line_strip.points.push_back(point);
                    line += xy(point.x,point.y);
                }
                line_strip.lifetime = ros::Duration(0);
            }
            if (zavg_allow)
            {
                for (int seg=0; seg < ma.markers.size(); seg++)
                {
                    for (int mz = 0; mz < ma.markers[seg].points.size(); mz++) /*Egyszerűsített polygon z-koordinátáinak megadása átlagból. */
                    {
                        ma.markers[seg].points[mz].z = zavg;
                    }
                }
                /* polyz = zavg; /* Be- és kikapcsolással a konstans z-érték az átlagérték alapján beállítja magát. (kell?) */
            }

            /*érvényét vesztett markerek eltávolítása*/
            line_strip.action = visualization_msgs::Marker::DELETE;
            for (int del = lineStripID; del<ghostcount; del++)
            {
                line_strip.id++;
                ma.markers.push_back(line_strip);
            }
            ghostcount = lineStripID;

            /*A marker array hírdetése.*/
            pub_marker.publish(ma);
        }

        for (j = 0; j < indexArray[10]; j++)
        {
            pt.x = *(array3D + 10 * piece * 7 + j * 7 + 0);
            pt.y = *(array3D + 10 * piece * 7 + j * 7 + 1);
            pt.z = *(array3D + 10 * piece * 7 + j * 7 + 2);
            cloud_filtered_ProbablyRoad.push_back(pt);
        }

        /*A lefoglalt terület felszabadítása.*/
        delete[] array3D;
    }

    /*Road és High topic header.*/
    cloud_filtered_Road.header = cloud.header;
    cloud_filtered_ProbablyRoad.header = cloud.header;
    cloud_filtered_High.header = cloud.header;
    cloud_filtered_Box.header = cloud.header;

    /*Publish.*/
    pub_road.publish(cloud_filtered_Road); /*Szűrt pontok (úttest).*/
    pub_high.publish(cloud_filtered_High); /*Szűrt pontok (nem úttest).*/
    pub_box.publish(cloud_filtered_Box);  /*A vizsgált terület, összes pontja.*/
    pub_pobroad.publish(cloud_filtered_ProbablyRoad);
}

/*MAIN*/
int main(int argc, char **argv)
{

    /*Az ROS inicializálása.*/
    ros::init(argc, argv, "lidarSegmentation");
    ROS_INFO("Initializing %s", ros::this_node::getName().c_str());

    /*A GUI felülethez szükséges sorok.*/
    dynamic_reconfigure::Server<lidar_filters_pkg::LidarFiltersConfig> server;
    dynamic_reconfigure::Server<lidar_filters_pkg::LidarFiltersConfig>::CallbackType f;
    f = boost::bind(&paramsCallback, _1, _2);
    server.setCallback(f);

    /*NodeHandle*/
    ros::NodeHandle nh;

    /*Subscribe to the topic.*/
    // trigger the callback function (filter) when new cloud points arrives
    ros::Subscriber sub = nh.subscribe(topicName, 1, filtered);

    /*Announcement of filtered data.*/
    pub_road = nh.advertise<pcl::PCLPointCloud2>("cloud_filtered_Road", 1);
    pub_high = nh.advertise<pcl::PCLPointCloud2>("cloud_filtered_High", 1);
    pub_box = nh.advertise<pcl::PCLPointCloud2>("cloud_filtered_Box", 1);
    pub_pobroad = nh.advertise<pcl::PCLPointCloud2>("cloud_filtered_ProbablyRoad", 1);
    pub_marker = nh.advertise<visualization_msgs::MarkerArray>("visualization_MarkerArray", 1);

    /*Required for the code of László Csaplár.*/
    beam_init();

    ROS_INFO("Ready");

    ros::spin();
    return 0;
}


text:
#include "traffic_signmainwindow.h"
#include "ui_traffic_signmainwindow.h"
#include "MainWindowSink.hpp"
#include <QFileDialog>
#include <QDebug>
#include <boost/make_shared.hpp>
#include <signal.h>

Traffic_signMainWindow::Traffic_signMainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Traffic_signMainWindow),
    running_timer(new QTimer(this))
{
    ui->setupUi(this);
    sp_Event = boost::static_pointer_cast<INotification>(
            boost::make_shared<MainWindowSink>(this));

    connect(running_timer, SIGNAL(timeout()), this, SLOT(run()));
}

Traffic_signMainWindow::~Traffic_signMainWindow()
{
    delete ui;
}
QLabel * Traffic_signMainWindow::GetLabel(const std::string &s)
{
    if (s=="video") return ui->VideoLabel;
    if (s=="mark") return ui->SignLabel;
}

boost::shared_ptr<QImage> Traffic_signMainWindow::GetImage(const int &x)
{
    if (x==0) return sp_Image;
    else return sp_Mark;
}

boost::shared_ptr<INotification> Traffic_signMainWindow::GetEvent()
{
    return sp_Event;
}

void Traffic_signMainWindow::SetOpenCommand(const boost::shared_ptr<ICommand> &ptr) {
    sp_OpenCommand = ptr;
}

void Traffic_signMainWindow::SetReadCommand(const boost::shared_ptr<ICommand> &ptr) {
    sp_ReadCommand = ptr;
}

void Traffic_signMainWindow::SetRunCommand(const boost::shared_ptr<ICommand> &ptr) {
    sp_RunCommand = ptr;
}

void Traffic_signMainWindow::SetImage(const boost::shared_ptr<QImage> &ptr) {
    sp_Image = ptr;
}

void Traffic_signMainWindow::SetMark(const boost::shared_ptr<QImage> &ptr) {
    sp_Mark = ptr;
}

void Traffic_signMainWindow::on_VideoButton_clicked()
{
	QString fileName = QFileDialog::getOpenFileName(this,
            tr("Open Video"), ".",
            tr("Video Files (*.mp4 *.avi)"));
	qDebug()<<"filenames:"<<fileName;
    if (fileName.toStdString()=="") return;
	boost::shared_ptr<OpenCommandParam> param = boost::make_shared<OpenCommandParam>();
	param->SetParam(fileName.toStdString());
	sp_OpenCommand->Execute(boost::static_pointer_cast<ICommandParam>(param));

    //ui->VideoLabel->setPixmap(QPixmap::fromImage(*sp_ViewModel->GetImage()));
	//ui->VideoLabel->setPixmap(QPixmap::fromImage(*sp_ViewModel->GetImage()));
	//ui->VideoLabel->setScaledContents(true);
}

void Traffic_signMainWindow::on_RunButton_clicked()
{
    init_flag = true;

    QString fileName = QFileDialog::getOpenFileName(this,
            tr("Open Mark Information"), ".",
            tr("Mark Files (*.txt)"));
	qDebug()<<"filenames:"<<fileName;
    if (fileName.toStdString()=="") return;
    boost::shared_ptr<OpenCommandParam> param = boost::make_shared<OpenCommandParam>();
	param->SetParam(fileName.toStdString());
	sp_ReadCommand->Execute(boost::static_pointer_cast<ICommandParam>(param));

    running_timer->start(100);
}

void Traffic_signMainWindow::on_ExitButton_clicked()
{
    exit(0);
}

void Traffic_signMainWindow::run()
{
    boost::shared_ptr<OpenCommandParam> param = boost::make_shared<OpenCommandParam>();
    if (init_flag)
    {
	    param->SetParam("init");
	    init_flag = false;
	}
	else param->SetParam("run");
    sp_RunCommand->Execute(boost::static_pointer_cast<ICommandParam>(param));
}

ext: cpp

max_stars_repo_name: ketian/tracker

max_issues_repo_name: ketian/tracker

max_forks_repo_name: ketian/tracker


text:
// Author(s): Wieger Wesselink
// Copyright: see the accompanying file COPYING or copy at
// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//

#define BOOST_TEST_MODULE constructors
#include <boost/test/included/unit_test.hpp>

#include "mcrl2/atermpp/aterm_string.h"
#include "mcrl2/atermpp/aterm_io.h"

using namespace atermpp;

BOOST_AUTO_TEST_CASE(test_main)
{
  aterm_int i(10);
  atermpp::aterm x=aterm_appl(function_symbol("x",0));
  atermpp::aterm y=aterm_appl(function_symbol("y",0));
  aterm_appl f(function_symbol("f", 2), x, y);
  BOOST_CHECK(pp(f) == "f(x,y)");
  aterm_appl f1(function_symbol("f", 0));
  BOOST_CHECK(pp(f1) == "f");

  function_symbol f2("f2", 8);
  aterm_int d(1);
  aterm_appl long_term(f2,d,d,d,d,d,d,d,d);
  BOOST_CHECK(pp(long_term) == "f2(1,1,1,1,1,1,1,1)");

  atermpp::aterm_string s("s"); // g++ 3.4.4 complains if atermpp:: is removed :-(
  // aterm_string s1("s1(x)"); will generate an error!
}


text:
/*
 The MIT License (MIT)

 Copyright (c) [2016] [BTC.COM]

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */
#include "StratumSession.h"
#include "Utils.h"
#include "utilities_js.hpp"

#include <arpa/inet.h>
#include <boost/algorithm/string.hpp>

#include "StratumServer.h"

//////////////////////////////// DiffController ////////////////////////////////
void DiffController::setMinDiff(uint64 minDiff) {
  if (minDiff < kMinDiff_) {
    minDiff = kMinDiff_;
  }
  minDiff_ = minDiff;
}

void DiffController::resetCurDiff(uint64 curDiff) {
  if (curDiff < kMinDiff_) {
    curDiff = kMinDiff_;
  }
  if (curDiff < minDiff_) {
    curDiff = minDiff_;
  }

  // set to zero
  sharesNum_.mapMultiply(0);
  shares_.mapMultiply(0);

  curDiff_ = curDiff;
}

void DiffController::addAcceptedShare(const uint64 share) {
  const int64 k = time(nullptr) / kRecordSeconds_;
  sharesNum_.insert(k, 1.0);
  shares_.insert(k, share);
}

//
// level:  min ~ max, coefficient
//
// 0 :    0 ~    4 T,  1.0
// 1 :    4 ~    8 T,  1.0
// 2 :    8 ~   16 T,  1.0
// 3 :   16 ~   32 T,  1.2
// 4 :   32 ~   64 T,  1.5
// 5 :   64 ~  128 T,  2.0
// 6 :  128 ~  256 T,  3.0
// 7 :  256 ~  512 T,  4.0
// 8 :  512 ~  ... T,  6.0
//

static int __hashRateDown(int level) {
  const int levels[] = {0, 4, 8, 16,   32, 64, 128, 256};
  if (level >= 8) {
    return 512;
  }
  assert(level >= 0 && level <= 7);
  return levels[level];
}

static int __hashRateUp(int level) {
  const int levels[] = {4, 8, 16, 32,   64, 128, 256, 512};
  assert(level >= 0 && level <= 7);
  if (level >= 8) {
    return 0x7fffffffL;  // INT32_MAX
  }
  return levels[level];
}

// TODO: test case
int DiffController::adjustHashRateLevel(const double hashRateT) {
  // hashrate is always danceing,
  // so need to use rate high and low to check it's level
  const double rateHigh = 1.50;
  const double rateLow  = 0.75;

  // reduce level
  if (curHashRateLevel_ > 0 && hashRateT < __hashRateDown(curHashRateLevel_)) {
    while (curHashRateLevel_ > 0 &&
           hashRateT <= __hashRateDown(curHashRateLevel_) * rateLow) {
      curHashRateLevel_--;
    }
    return curHashRateLevel_;
  }

  // increase level
  if (curHashRateLevel_ <= 7 && hashRateT > __hashRateUp(curHashRateLevel_)) {
    while (curHashRateLevel_ <= 7 &&
           hashRateT >= __hashRateUp(curHashRateLevel_) * rateHigh) {
      curHashRateLevel_++;
    }
    return curHashRateLevel_;
  }

  return curHashRateLevel_;
}

double DiffController::minerCoefficient(const time_t now, const int64_t idx) {
  if (now <= startTime_) {
    return 1.0;
  }
  uint64_t shares    = shares_.sum(idx);
  time_t shareWindow = isFullWindow(now) ? kDiffWindow_ : (now - startTime_);
  double hashRateT   = (double)shares * pow(2, 32) / shareWindow / pow(10, 12);
  adjustHashRateLevel(hashRateT);
  assert(curHashRateLevel_ >= 0 && curHashRateLevel_ <= 8);

  const double c[] = {1.0, 1.0, 1.0, 1.2, 1.5, 2.0, 3.0, 4.0, 6.0};
  assert(sizeof(c)/sizeof(c[0]) == 9);
  return c[curHashRateLevel_];
}

uint64 DiffController::calcCurDiff() {
  uint64 diff = _calcCurDiff();
  if (diff < minDiff_) {
    diff = minDiff_;
  }
  return diff;
}

uint64 DiffController::_calcCurDiff() {
  const time_t now = time(nullptr);
  const int64 k = now / kRecordSeconds_;
  const double sharesCount = (double)sharesNum_.sum(k);
  if (startTime_ == 0) {  // first time, we set the start time
    startTime_ = time(nullptr);
  }

  const double kRateHigh = 1.40;
  const double kRateLow  = 0.40;
  double expectedCount = round(kDiffWindow_ / (double)shareAvgSeconds_);

  if (isFullWindow(now)) { /* have a full window now */
    // big miner have big expected share count to make it looks more smooth.
    expectedCount *= minerCoefficient(now, k);
  }
  if (expectedCount > kDiffWindow_) {
    expectedCount = kDiffWindow_;  // one second per share is enough
  }

  // this is for very low hashrate miner, eg. USB miners
  // should received at least one share every 60 seconds
  if (!isFullWindow(now) && now >= startTime_ + 60 &&
      sharesCount <= (int32_t)((now - startTime_)/60.0) &&
      curDiff_ >= minDiff_*2) {
    curDiff_ /= 2;
    sharesNum_.mapMultiply(2.0);
    return curDiff_;
  }

  // too fast
  if (sharesCount > expectedCount * kRateHigh) {
    while (sharesNum_.sum(k) > expectedCount) {
      curDiff_ *= 2;
      sharesNum_.mapDivide(2.0);
    }
    return curDiff_;
  }

  // too slow
  if (isFullWindow(now) && curDiff_ >= minDiff_*2) {
    while (sharesNum_.sum(k) < expectedCount * kRateLow &&
           curDiff_ >= minDiff_*2) {
      curDiff_ /= 2;
      sharesNum_.mapMultiply(2.0);
    }
    assert(curDiff_ >= minDiff_);
    return curDiff_;
  }

  return curDiff_;
}

//////////////////////////////// StratumSession ////////////////////////////////
StratumSession::StratumSession(evutil_socket_t fd, struct bufferevent *bev,
                               Server *server, struct sockaddr *saddr,
                               const int32_t shareAvgSeconds,
                               const uint32_t extraNonce1) :
shareAvgSeconds_(shareAvgSeconds), diffController_(shareAvgSeconds_),
shortJobIdIdx_(0), agentSessions_(nullptr), isDead_(false),
bev_(bev), fd_(fd), server_(server)
{
  state_ = CONNECTED;
  currDiff_    = 0U;
  extraNonce1_ = extraNonce1;

  // usually stratum job interval is 30~60 seconds, 10 is enough for miners
  // should <= 10, we use short_job_id,  range: [0 ~ 9]. do NOT change it.
  kMaxNumLocalJobs_ = 10;
  assert(kMaxNumLocalJobs_ <= 10);

  inBuf_  = evbuffer_new();
  isLongTimeout_    = false;
  isNiceHashClient_ = false;

  clientAgent_ = "unknown";
  // ipv4
  clientIp_.resize(INET_ADDRSTRLEN);
  struct sockaddr_in *saddrin = (struct sockaddr_in *)saddr;
  clientIp_ = inet_ntop(AF_INET, &saddrin->sin_addr,
                        (char *)clientIp_.data(), (socklen_t)clientIp_.size());
  clientIpInt_ = saddrin->sin_addr.s_addr;

  setup();

  LOG(INFO) << "client connect, ip: " << clientIp_;
}

StratumSession::~StratumSession() {
  if (agentSessions_ != nullptr) {
    delete agentSessions_;
    agentSessions_ = nullptr;
  }

  LOG(INFO) << "close stratum session, ip: " << clientIp_
  << ", name: \"" << worker_.fullName_ << "\""
  << ", agent: \"" << clientAgent_ << "\"";

//  close(fd_);  // we don't need to close because we set 'BEV_OPT_CLOSE_ON_FREE'
  evbuffer_free(inBuf_);
  bufferevent_free(bev_);
}

void StratumSession::markAsDead() {
  // mark as dead
  isDead_ = true;

  // sent event to kafka: miner_dead
  if (worker_.userId_ > 0) {
    string eventJson;
    eventJson = Strings::Format("{\"created_at\":\"%s\","
                                "\"type\":\"miner_dead\","
                                "\"content\":{"
                                "\"user_id\":%d,\"user_name\":\"%s\","
                                "\"worker_name\":\"%s\","
                                "\"client_agent\":\"%s\",\"ip\":\"%s\""
                                "}}",
                                date("%F %T").c_str(),
                                worker_.userId_, worker_.userName_.c_str(),
                                worker_.workerName_.c_str(),
                                clientAgent_.c_str(), clientIp_.c_str());
    server_->sendCommonEvents2Kafka(eventJson);
  }
}

bool StratumSession::isDead() {
  return (isDead_ == true) ? true : false;
}

void StratumSession::setup() {
  // we set 15 seconds, will increase the timeout after sub & auth
  setReadTimeout(15);
}

void StratumSession::setReadTimeout(const int32_t timeout) {
  // clear it
  bufferevent_set_timeouts(bev_, NULL, NULL);

  // set a new one
  struct timeval rtv = {timeout, 0};
  struct timeval wtv = {120, 0};
  bufferevent_set_timeouts(bev_, &rtv, &wtv);
}

// if read success, will remove data from eventbuf
bool StratumSession::tryReadLine(string &line) {
  line.clear();

  // find eol
  struct evbuffer_ptr loc;
  loc = evbuffer_search_eol(inBuf_, nullptr, nullptr, EVBUFFER_EOL_LF);
  if (loc.pos == -1) {
    return false;  // not found
  }

  // copies and removes the first datlen bytes from the front of buf
  // into the memory at data
  line.resize(loc.pos + 1);  // containing "\n"
  evbuffer_remove(inBuf_, (void *)line.data(), line.size());
  return true;
}

void StratumSession::handleLine(const string &line) {
  DLOG(INFO) << "recv(" << line.size() << "): " << line;

  JsonNode jnode;
  if (!JsonNode::parse(line.data(), line.data() + line.size(), jnode)) {
    LOG(ERROR) << "decode line fail, not a json string";
    return;
  }
  JsonNode jid = jnode["id"];
  JsonNode jmethod = jnode["method"];
  JsonNode jparams = jnode["params"];

  string idStr = "null";
  if (jid.type() == Utilities::JS::type::Int) {
    idStr = jid.str();
  } else if (jid.type() == Utilities::JS::type::Str) {
    idStr = "\"" + jnode["id"].str() + "\"";
  }

  if (jmethod.type() == Utilities::JS::type::Str &&
      jmethod.size() != 0 &&
      jparams.type() == Utilities::JS::type::Array) {
    handleRequest(idStr, jmethod.str(), jparams);
    return;
  }

  // invalid params
  responseError(idStr, StratumError::ILLEGAL_PARARMS);
}

void StratumSession::responseError(const string &idStr, int errCode) {
  //
  // {"id": 10, "result": null, "error":[21, "Job not found", null]}
  //
  char buf[1024];
  int len = snprintf(buf, sizeof(buf),
                     "{\"id\":%s,\"result\":null,\"error\":[%d,\"%s\",null]}\n",
                     idStr.empty() ? "null" : idStr.c_str(),
                     errCode, StratumError::toString(errCode));
  sendData(buf, len);
}

void StratumSession::responseTrue(const string &idStr) {
  const string s = "{\"id\":" + idStr + ",\"result\":true,\"error\":null}\n";
  sendData(s);
}

void StratumSession::handleRequest(const string &idStr, const string &method,
                                   const JsonNode &jparams) {
  if (method == "mining.submit") {  // most of requests are 'mining.submit'
    handleRequest_Submit(idStr, jparams);
  }
  else if (method == "mining.subscribe") {
    handleRequest_Subscribe(idStr, jparams);
  }
  else if (method == "mining.authorize") {
    handleRequest_Authorize(idStr, jparams);
  }
  else if (method == "mining.multi_version") {
    handleRequest_MultiVersion(idStr, jparams);
  }
  else if (method == "mining.suggest_target") {
    handleRequest_SuggestTarget(idStr, jparams);
  }
  else if (method == "mining.suggest_difficulty") {
    handleRequest_SuggestDifficulty(idStr, jparams);
  } else {
    // unrecognised method, just ignore it
    LOG(WARNING) << "unrecognised method: \"" << method << "\""
    << ", client: " << clientIp_ << "/" << clientAgent_;
  }
}

void StratumSession::handleRequest_MultiVersion(const string &idStr,
                                                const JsonNode &jparams) {
//  // we ignore right now, 2016-07-04
//  const string s = Strings::Format("{\"id\":%s,\"method\":\"mining.midstate_change\",\"params\":[4]}",
//                                   idStr.c_str());
//  sendData(s);
}

static
bool _isNiceHashAgent(const string &clientAgent) {
  if (clientAgent.length() < 9) {
    return false;
  }
  string agent = clientAgent;
  // tolower
  std::transform(agent.begin(), agent.end(), agent.begin(), ::tolower);
  if (agent.substr(0, 9) == "nicehash/") {
    return true;
  }
  return false;
}

void StratumSession::handleRequest_Subscribe(const string &idStr,
                                             const JsonNode &jparams) {
  if (state_ != CONNECTED) {
    responseError(idStr, StratumError::UNKNOWN);
    return;
  }
  state_ = SUBSCRIBED;

  //
  //  params[0] = client version     [optional]
  //  params[1] = session id of pool [optional]
  //
  // client request eg.:
  //  {"id": 1, "method": "mining.subscribe", "params": ["bfgminer/4.4.0-32-gac4e9b3", "01ad557d"]}
  //
  if (jparams.children()->size() >= 1) {
    clientAgent_ = jparams.children()->at(0).str().substr(0, 30);  // 30 is max len
    clientAgent_ = filterWorkerName(clientAgent_);
  }

  //  result[0] = 2-tuple with name of subscribed notification and subscription ID.
  //              Theoretically it may be used for unsubscribing, but obviously miners won't use it.
  //  result[1] = ExtraNonce1, used for building the coinbase.
  //  result[2] = Extranonce2_size, the number of bytes that the miner users for its ExtraNonce2 counter
  assert(kExtraNonce2Size_ == 8);
  const string s = Strings::Format("{\"id\":%s,\"result\":[[[\"mining.set_difficulty\",\"%08x\"]"
                                   ",[\"mining.notify\",\"%08x\"]],\"%08x\",%d],\"error\":null}\n",
                                   idStr.c_str(), extraNonce1_, extraNonce1_, extraNonce1_, kExtraNonce2Size_);
  sendData(s);

  if (clientAgent_ == "__PoolWatcher__") {
    isLongTimeout_ = true;
  }

  // check if it's NinceHash/x.x.x
  if (_isNiceHashAgent(clientAgent_))
    isNiceHashClient_ = true;

  //
  // check if it's BTCAgent
  //
  if (strncmp(clientAgent_.c_str(), BTCCOM_MINER_AGENT_PREFIX,
              std::min(clientAgent_.length(), strlen(BTCCOM_MINER_AGENT_PREFIX))) == 0) {
    LOG(INFO) << "agent model, client: " << clientAgent_;
    agentSessions_ = new AgentSessions(shareAvgSeconds_, this);

    isLongTimeout_ = true;  // will set long timeout
  }
}

void StratumSession::_handleRequest_AuthorizePassword(const string &password) {
  // testcase: TEST(StratumSession, SetDiff)
  using namespace boost::algorithm;

  uint64_t d = 0u, md = 0u;
  vector<string> arr;  // key=value,key=value
  split(arr, password, is_any_of(","));
  if (arr.size() == 0)
    return;

  for (auto it = arr.begin(); it != arr.end(); it++) {
    vector<string> arr2;  // key,value
    split(arr2, *it, is_any_of("="));
    if (arr2.size() != 2 || arr2[1].empty()) {
      continue;
    }

    if (arr2[0] == "d") {
      // 'd' : start difficulty
      d = strtoull(arr2[1].c_str(), nullptr, 10);
    }
    else if (arr2[0] == "md") {
      // 'md' : minimum difficulty
      md = strtoull(arr2[1].c_str(), nullptr, 10);
    }
  }

  d  = formatDifficulty(d);
  md = formatDifficulty(md);

  // set min diff first
  if (md >= DiffController::kMinDiff_) {
    diffController_.setMinDiff(md);
  }

  // than set current diff
  if (d >= DiffController::kMinDiff_) {
    diffController_.resetCurDiff(d);
  }
}

void StratumSession::handleRequest_Authorize(const string &idStr,
                                             const JsonNode &jparams) {
  if (state_ != SUBSCRIBED) {
    responseError(idStr, StratumError::NOT_SUBSCRIBED);
    return;
  }

  //
  //  params[0] = user[.worker]
  //  params[1] = password
  //  eg. {"params": ["slush.miner1", "password"], "id": 2, "method": "mining.authorize"}
  //
  if (jparams.children()->size() < 1) {
    responseError(idStr, StratumError::INVALID_USERNAME);
    return;
  }

  const string password = jparams.children()->at(1).str();
  if (!password.empty()) {
    _handleRequest_AuthorizePassword(password);
  }

  const string fullName = jparams.children()->at(0).str();
  const string userName = worker_.getUserName(fullName);

  const int32_t userId = server_->userInfo_->getUserId(userName);
  if (userId <= 0) {
    responseError(idStr, StratumError::INVALID_USERNAME);
    return;
  }

  // auth success
  responseTrue(idStr);
  state_ = AUTHENTICATED;

  // set id & names, will filter workername in this func
  worker_.setUserIDAndNames(userId, fullName);
  server_->userInfo_->addWorker(worker_.userId_, worker_.workerHashId_,
                                worker_.workerName_, clientAgent_);
  DLOG(INFO) << "userId: " << worker_.userId_
  << ", wokerHashId: " << worker_.workerHashId_ << ", workerName:" << worker_.workerName_;

  // set read timeout to 10 mins, it's enought for most miners even usb miner.
  // if it's a pool watcher, set timeout to a week
  setReadTimeout(isLongTimeout_ ? 86400*7 : 60*10);

  // send latest stratum job
  sendMiningNotify(server_->jobRepository_->getLatestStratumJobEx());

  // sent events to kafka: miner_connect
  {
    string eventJson;
    eventJson = Strings::Format("{\"created_at\":\"%s\","
                                "\"type\":\"miner_connect\","
                                "\"content\":{"
                                "\"user_id\":%d,\"user_name\":\"%s\","
                                "\"worker_name\":\"%s\","
                                "\"client_agent\":\"%s\",\"ip\":\"%s\""
                                "}}",
                                date("%F %T").c_str(),
                                worker_.userId_, worker_.userName_.c_str(),
                                worker_.workerName_.c_str(),
                                clientAgent_.c_str(), clientIp_.c_str());
    server_->sendCommonEvents2Kafka(eventJson);
  }
}

void StratumSession::handleExMessage_AuthorizeAgentWorker(const int64_t workerId,
                                                          const string &clientAgent,
                                                          const string &workerName) {
  if (state_ != AUTHENTICATED) {
    LOG(ERROR) << "curr stratum session has NOT auth yet";
    return;
  }
  server_->userInfo_->addWorker(worker_.userId_, workerId,
                                workerName, clientAgent);
}

void StratumSession::_handleRequest_SetDifficulty(uint64_t suggestDiff) {
  diffController_.resetCurDiff(formatDifficulty(suggestDiff));
}

void StratumSession::handleRequest_SuggestTarget(const string &idStr,
                                                 const JsonNode &jparams) {
  if (state_ != CONNECTED) {
    return;  // suggest should be call before subscribe
  }
  if (jparams.children()->size() == 0) {
    responseError(idStr, StratumError::ILLEGAL_PARARMS);
    return;
  }
  _handleRequest_SetDifficulty(TargetToDiff(jparams.children()->at(0).str()));
}

void StratumSession::handleRequest_SuggestDifficulty(const string &idStr,
                                                     const JsonNode &jparams) {
  if (state_ != CONNECTED) {
    return;  // suggest should be call before subscribe
  }
  if (jparams.children()->size() == 0) {
    responseError(idStr, StratumError::ILLEGAL_PARARMS);
    return;
  }
  _handleRequest_SetDifficulty(jparams.children()->at(0).uint64());
}

void StratumSession::handleRequest_Submit(const string &idStr,
                                          const JsonNode &jparams) {
  if (state_ != AUTHENTICATED) {
    responseError(idStr, StratumError::UNAUTHORIZED);

    // there must be something wrong, send reconnect command
    const string s = "{\"id\":null,\"method\":\"client.reconnect\",\"params\":[]}\n";
    sendData(s);

    return;
  }

  //  params[0] = Worker Name
  //  params[1] = Job ID
  //  params[2] = ExtraNonce 2
  //  params[3] = nTime
  //  params[4] = nonce
  if (jparams.children()->size() < 5) {
    responseError(idStr, StratumError::ILLEGAL_PARARMS);
    return;
  }

  uint8_t shortJobId;
  if (isNiceHashClient_) {
    shortJobId = (uint8_t)(jparams.children()->at(1).uint64() % 10);
  } else {
    shortJobId = (uint8_t)jparams.children()->at(1).uint32();
  }
  const uint64_t extraNonce2 = jparams.children()->at(2).uint64_hex();
  uint32_t nTime             = jparams.children()->at(3).uint32_hex();
  const uint32_t nonce       = jparams.children()->at(4).uint32_hex();

  handleRequest_Submit(idStr, shortJobId, extraNonce2, nonce, nTime,
                       false /* not agent session */, nullptr);
}

void StratumSession::handleRequest_Submit(const string &idStr,
                                          const uint8_t shortJobId,
                                          const uint64_t extraNonce2,
                                          const uint32_t nonce,
                                          uint32_t nTime,
                                          bool isAgentSession,
                                          DiffController *sessionDiffController) {
  //
  // if share is from agent session, we don't need to send reply json
  //
  if (isAgentSession == true && agentSessions_ == nullptr) {
    LOG(ERROR) << "can't find agentSession";
    return;
  }

  const string extraNonce2Hex = Strings::Format("%016llx", extraNonce2);
  assert(extraNonce2Hex.length()/2 == kExtraNonce2Size_);

  LocalJob *localJob = findLocalJob(shortJobId);
  if (localJob == nullptr) {
    // if can't find localJob, could do nothing
    if (isAgentSession == false)
    	responseError(idStr, StratumError::JOB_NOT_FOUND);
    return;
  }

  // 0 means miner use stratum job's default block time
  if (nTime == 0) {
    shared_ptr<StratumJobEx> exjob;
    exjob = server_->jobRepository_->getStratumJobEx(localJob->jobId_);
    if (exjob.get() != NULL)
    	nTime = exjob->sjob_->nTime_;
  }

  Share share;
  share.jobId_        = localJob->jobId_;
  share.workerHashId_ = worker_.workerHashId_;
  share.ip_           = clientIpInt_;
  share.userId_       = worker_.userId_;
  share.share_        = localJob->jobDifficulty_;
  share.blkBits_      = localJob->blkBits_;
  share.timestamp_    = (uint32_t)time(nullptr);
  share.result_       = Share::Result::REJECT;

  if (isAgentSession == true) {
    const uint16_t sessionId = (uint16_t)(extraNonce2 >> 32);

    // reset to agent session's workerId
    share.workerHashId_ = agentSessions_->getWorkerId(sessionId);
    if (share.workerHashId_ == 0) {
      LOG(ERROR) << "invalid workerId 0, sessionId: " << sessionId;
      return;
    }

    // reset to agent session's diff
    if (localJob->agentSessionsDiff2Exp_.size() < (size_t)sessionId + 1) {
      LOG(ERROR) << "can't find agent session's diff, sessionId: " << sessionId;
      return;
    }
    share.share_ = (uint64_t)exp2(localJob->agentSessionsDiff2Exp_[sessionId]);
  }

  // calc jobTarget
  uint256 jobTarget;
  DiffToTarget(share.share_, jobTarget);

  int submitResult;
  LocalShare localShare(extraNonce2, nonce, nTime);
  if (!localJob->addLocalShare(localShare)) {
    if (isAgentSession == false)
      responseError(idStr, StratumError::DUPLICATE_SHARE);
    goto finish;
  }

  submitResult = server_->checkShare(share, extraNonce1_, extraNonce2Hex,
                                     nTime, nonce, jobTarget,
                                     worker_.fullName_);
  if (submitResult == StratumError::NO_ERROR) {
    // accepted share
    share.result_ = Share::Result::ACCEPT;

    // agent miner's diff controller
    if (isAgentSession && sessionDiffController != nullptr) {
      sessionDiffController->addAcceptedShare(share.share_);
    }

    if (isAgentSession == false) {
    	diffController_.addAcceptedShare(share.share_);
      responseTrue(idStr);
    }
  } else {
    if (isAgentSession == false)
    	responseError(idStr, submitResult);
  }

finish:
  DLOG(INFO) << share.toString();
  server_->sendShare2Kafka((const uint8_t *)&share, sizeof(Share));
  return;
}

StratumSession::LocalJob *StratumSession::findLocalJob(uint8_t shortJobId) {
  for (auto rit = localJobs_.rbegin(); rit != localJobs_.rend(); ++rit) {
    if (rit->shortJobId_ == shortJobId) {
      return &(*rit);
    }
  }
  return nullptr;
}

void StratumSession::sendSetDifficulty(const uint64_t difficulty) {
  string s = Strings::Format("{\"id\":null,\"method\":\"mining.set_difficulty\""
                             ",\"params\":[%" PRIu64"]}\n",
                             difficulty);
  sendData(s);
}

uint8_t StratumSession::allocShortJobId() {
  // return range: [0, 9]
  if (shortJobIdIdx_ >= 10) {
    shortJobIdIdx_ = 0;
  }
  return shortJobIdIdx_++;
}

void StratumSession::sendMiningNotify(shared_ptr<StratumJobEx> exJobPtr) {
  if (state_ < AUTHENTICATED || exJobPtr == nullptr) {
    return;
  }
  StratumJob *sjob = exJobPtr->sjob_;

  localJobs_.push_back(LocalJob());
  LocalJob &ljob = *(localJobs_.rbegin());
  ljob.blkBits_       = sjob->nBits_;
  ljob.jobId_         = sjob->jobId_;
  ljob.shortJobId_    = allocShortJobId();
  ljob.jobDifficulty_ = diffController_.calcCurDiff();

  if (agentSessions_ != nullptr)
  {
    // calc diff and save to ljob
    agentSessions_->calcSessionsJobDiff(ljob.agentSessionsDiff2Exp_);

    // get ex-message
    string exMessage;
    agentSessions_->getSessionsChangedDiff(ljob.agentSessionsDiff2Exp_, exMessage);
    if (exMessage.size())
    	sendData(exMessage);
  }

  // set difficulty
  if (currDiff_ != ljob.jobDifficulty_) {
    sendSetDifficulty(ljob.jobDifficulty_);
    currDiff_ = ljob.jobDifficulty_;
  }

  string notifyStr;
  notifyStr.reserve(2048);

  // notify1
  notifyStr.append(exJobPtr->miningNotify1_);

  // jobId
  if (isNiceHashClient_) {
    //
    // we need to send unique JobID to NiceHash Client, they have problems with
    // short Job ID
    //
    const uint64_t niceHashJobId = (uint64_t)time(nullptr) * 10 + ljob.shortJobId_;
    notifyStr.append(Strings::Format("% " PRIu64"", niceHashJobId));
  } else {
    notifyStr.append(Strings::Format("%u", ljob.shortJobId_));  // short jobId
  }

  // notify2
  notifyStr.append(exJobPtr->miningNotify2_);

  sendData(notifyStr);  // send notify string

  // clear localJobs_
  while (localJobs_.size() >= kMaxNumLocalJobs_) {
    localJobs_.pop_front();
  }
}

void StratumSession::sendData(const char *data, size_t len) {
  // add data to a bufferevent’s output buffer
  // it is automatically locked so we don't need to lock
  bufferevent_write(bev_, data, len);
//  DLOG(INFO) << "send(" << len << "): " << data;
}

// if read a message (ex-message or stratum) success should return true,
// otherwise return false.
bool StratumSession::handleMessage() {
  //
  // handle ex-message
  //
  const size_t evBufLen = evbuffer_get_length(inBuf_);

  // no matter what kind of messages, length should at least 4 bytes
  if (evBufLen < 4)
    return false;

  uint8_t buf[4];
  evbuffer_copyout(inBuf_, buf, 4);

  // handle ex-message
  if (buf[0] == CMD_MAGIC_NUMBER) {
    const uint16_t exMessageLen = *(uint16_t *)(buf + 2);

    if (evBufLen < exMessageLen)  // didn't received the whole message yet
      return false;

    // copies and removes the first datlen bytes from the front of buf
    // into the memory at data
    string exMessage;
    exMessage.resize(exMessageLen);
    evbuffer_remove(inBuf_, (uint8_t *)exMessage.data(), exMessage.size());

    switch (buf[1]) {
      case CMD_SUBMIT_SHARE:
        handleExMessage_SubmitShare(&exMessage);
        break;
      case CMD_SUBMIT_SHARE_WITH_TIME:
        handleExMessage_SubmitShareWithTime(&exMessage);
        break;
      case CMD_REGISTER_WORKER:
        handleExMessage_RegisterWorker(&exMessage);
        break;
      case CMD_UNREGISTER_WORKER:
        handleExMessage_UnRegisterWorker(&exMessage);
        break;

      default:
        LOG(ERROR) << "received unknown ex-message, type: " << buf[1]
        << ", len: " << exMessageLen;
        break;
    }
    return true;  // read message success, return true
  }

  //
  // handle stratum message
  //
  string line;
  if (tryReadLine(line)) {
    handleLine(line);
    return true;
  }

  return false;  // read mesasge failure
}

void StratumSession::readBuf(struct evbuffer *buf) {
  // moves all data from src to the end of dst
  evbuffer_add_buffer(inBuf_, buf);

  while (handleMessage()) {
  }
}

void StratumSession::handleExMessage_RegisterWorker(const string *exMessage) {
  if (agentSessions_ == nullptr) {
    return;
  }
  agentSessions_->handleExMessage_RegisterWorker(exMessage);
}

void StratumSession::handleExMessage_SubmitShare(const string *exMessage) {
  if (agentSessions_ == nullptr) {
    return;
  }
  // without timestamp
  agentSessions_->handleExMessage_SubmitShare(exMessage, false);
}

void StratumSession::handleExMessage_SubmitShareWithTime(const string *exMessage) {
  if (agentSessions_ == nullptr) {
    return;
  }
  // with timestamp
  agentSessions_->handleExMessage_SubmitShare(exMessage, true);
}

void StratumSession::handleExMessage_UnRegisterWorker(const string *exMessage) {
  if (agentSessions_ == nullptr) {
    return;
  }
  agentSessions_->handleExMessage_UnRegisterWorker(exMessage);
}

uint32_t StratumSession::getSessionId() const {
  return extraNonce1_;
}

///////////////////////////////// AgentSessions ////////////////////////////////
AgentSessions::AgentSessions(const int32_t shareAvgSeconds,
                             StratumSession *stratumSession)
:shareAvgSeconds_(shareAvgSeconds), stratumSession_(stratumSession)
{
  kDefaultDiff2Exp_ = (uint8_t)log2(DiffController::kDefaultDiff_);

  // we just pre-alloc all
  workerIds_.resize(UINT16_MAX, 0);
  diffControllers_.resize(UINT16_MAX, nullptr);
  curDiff2ExpVec_.resize(UINT16_MAX, kDefaultDiff2Exp_);
}

AgentSessions::~AgentSessions() {
  for (auto ptr : diffControllers_) {
    if (ptr != nullptr) {
      delete ptr;
    }
  }
}

int64_t AgentSessions::getWorkerId(const uint16_t sessionId) {
  return workerIds_[sessionId];
}

void AgentSessions::handleExMessage_RegisterWorker(const string *exMessage) {
  //
  // CMD_REGISTER_WORKER:
  // | magic_number(1) | cmd(1) | len (2) | session_id(2) | clientAgent | worker_name |
  //
  if (exMessage->size() < 8 || exMessage->size() > 100 /* 100 bytes is big enough */)
    return;

  const uint8_t *p = (uint8_t *)exMessage->data();
  const uint16_t sessionId = *(uint16_t *)(p + 4);
  if (sessionId > AGENT_MAX_SESSION_ID)
    return;

  // copy out string and make sure end with zero
  string clientStr;
  clientStr.append(exMessage->begin() + 6, exMessage->end());
  clientStr[clientStr.size() - 1] = '\0';

  // client agent
  const char *clientAgentPtr = clientStr.c_str();
  const string clientAgent = filterWorkerName(clientAgentPtr);

  // worker name
  string workerName;
  if (strlen(clientAgentPtr) < clientStr.size() - 2) {
    workerName = filterWorkerName(clientAgentPtr + strlen(clientAgentPtr) + 1);
  }
  if (workerName.empty())
    workerName = DEFAULT_WORKER_NAME;

  // worker Id
  const int64_t workerId = StratumWorker::calcWorkerId(workerName);

  DLOG(INFO) << "[agent] clientAgent: " << clientAgent
  << ", workerName: " << workerName << ", workerId: "
  << workerId << ", session id:" << sessionId;

  // set sessionId -> workerId
  workerIds_[sessionId] = workerId;

  // deletes managed object
  if (diffControllers_[sessionId] != nullptr) {
    delete diffControllers_[sessionId];
    diffControllers_[sessionId] = nullptr;
  }

  // acquires new pointer
  assert(diffControllers_[sessionId] == nullptr);
  diffControllers_[sessionId] = new DiffController(shareAvgSeconds_);

  // set curr diff to default Diff
  curDiff2ExpVec_[sessionId] = kDefaultDiff2Exp_;

  // submit worker info to stratum session
  // ptr can't be nullptr, just make it easy for test
  if (stratumSession_ != nullptr)
    stratumSession_->handleExMessage_AuthorizeAgentWorker(workerId, clientAgent,
                                                          workerName);
}

void AgentSessions::handleExMessage_SubmitShare(const string *exMessage,
                                                const bool isWithTime) {
  //
  // CMD_SUBMIT_SHARE / CMD_SUBMIT_SHARE_WITH_TIME:
  // | magic_number(1) | cmd(1) | len (2) | jobId (uint8_t) | session_id (uint16_t) |
  // | extra_nonce2 (uint32_t) | nNonce (uint32_t) | [nTime (uint32_t) |]
  //
  if (exMessage->size() != (isWithTime ? 19 : 15))
    return;

  const uint8_t *p = (uint8_t *)exMessage->data();
  const uint8_t shortJobId = *(uint8_t  *)(p +  4);
  const uint16_t sessionId = *(uint16_t *)(p +  5);
  if (sessionId > AGENT_MAX_SESSION_ID)
    return;

  const uint32_t  exNonce2 = *(uint32_t *)(p +  7);
  const uint32_t     nonce = *(uint32_t *)(p + 11);
  const uint32_t time = (isWithTime == false ? 0 : *(uint32_t *)(p + 15));

  const uint64_t fullExtraNonce2 = ((uint64_t)sessionId << 32) | (uint64_t)exNonce2;

  // debug
  string logLine = Strings::Format("[agent] shortJobId: %02x, sessionId: %08x"
                                   ", exNonce2: %016llx, nonce: %08x, time: %08x",
                                   shortJobId, (uint32_t)sessionId,
                                   fullExtraNonce2, nonce, time);
  DLOG(INFO) << logLine;

  if (stratumSession_ != nullptr)
    stratumSession_->handleRequest_Submit("null", shortJobId,
                                          fullExtraNonce2, nonce, time,
                                          true /* submit by agent's miner */,
                                          diffControllers_[sessionId]);
}

void AgentSessions::handleExMessage_UnRegisterWorker(const string *exMessage) {
  //
  // CMD_UNREGISTER_WORKER:
  // | magic_number(1) | cmd(1) | len (2) | session_id(2) |
  //
  if (exMessage->size() != 6)
    return;

  const uint8_t *p = (uint8_t *)exMessage->data();
  const uint16_t sessionId = *(uint16_t *)(p +  4);
  if (sessionId > AGENT_MAX_SESSION_ID)
    return;

  DLOG(INFO) << "[agent] sessionId: " << sessionId;

  // un-register worker
  workerIds_[sessionId] = 0;

  // set curr diff to default Diff
  curDiff2ExpVec_[sessionId] = kDefaultDiff2Exp_;

  // release diff controller
  if (diffControllers_[sessionId] != nullptr) {
    delete diffControllers_[sessionId];
    diffControllers_[sessionId] = nullptr;
  }
}

void AgentSessions::calcSessionsJobDiff(vector<uint8_t> &sessionsDiff2Exp) {
  sessionsDiff2Exp.clear();
  sessionsDiff2Exp.resize(UINT16_MAX, kDefaultDiff2Exp_);

  for (size_t i = 0; i < diffControllers_.size(); i++) {
    if (diffControllers_[i] == nullptr) {
      continue;
    }
    const uint64_t diff = diffControllers_[i]->calcCurDiff();
    sessionsDiff2Exp[i] = (uint8_t)log2(diff);
  }
}

void AgentSessions::getSessionsChangedDiff(const vector<uint8_t> &sessionsDiff2Exp,
                                           string &data) {
  vector<uint32_t> changedDiff2Exp;
  changedDiff2Exp.resize(UINT16_MAX, 0u);
  assert(curDiff2ExpVec_.size() == sessionsDiff2Exp.size());

  // get changed diff and set to new diff
  for (size_t i = 0; i < curDiff2ExpVec_.size(); i++) {
    if (curDiff2ExpVec_[i] == sessionsDiff2Exp[i]) {
      continue;
    }
    changedDiff2Exp[i] = sessionsDiff2Exp[i];
    curDiff2ExpVec_[i] = sessionsDiff2Exp[i];  // set new diff
  }

  // diff_2exp -> session_id | session_id | ... | session_id
  map<uint8_t, vector<uint16_t> > diffSessionIds;
  for (uint32_t i = 0; i < changedDiff2Exp.size(); i++) {
    if (changedDiff2Exp[i] == 0u) {
      continue;
    }
    diffSessionIds[changedDiff2Exp[i]].push_back((uint16_t)i);
  }

  getSetDiffCommand(diffSessionIds, data);
}

void AgentSessions::getSetDiffCommand(map<uint8_t, vector<uint16_t> > &diffSessionIds,
                                      string &data) {
  //
  // CMD_MINING_SET_DIFF:
  // | magic_number(1) | cmd(1) | len (2) | diff_2_exp(1) | count(2) | session_id (2) ... |
  //
  //
  // max session id count is 32,764, each message's max length is UINT16_MAX.
  //     65535 -1-1-2-1-2 = 65,528
  //     65,528 / 2 = 32,764
  //
  data.clear();
  const size_t kMaxCount = 32764;

  for (auto it = diffSessionIds.begin(); it != diffSessionIds.end(); it++) {

    while (it->second.size() > 0) {
      size_t count = std::min(kMaxCount, it->second.size());

      string buf;
      const uint16_t len = 1+1+2+1+2+ count * 2;
      buf.resize(len);
      uint8_t *p = (uint8_t *)buf.data();

      // cmd
      *p++ = CMD_MAGIC_NUMBER;
      *p++ = CMD_MINING_SET_DIFF;

      // len
      *(uint16_t *)p = len;
      p += 2;

      // diff, 2 exp
      *p++ = it->first;

      // count
      *(uint16_t *)p = (uint16_t)count;
      p += 2;

      // session ids
      for (size_t j = 0; j < count; j++) {
        *(uint16_t *)p = it->second[j];
        p += 2;
      }

      // remove the first `count` elements from vector
      it->second.erase(it->second.begin(), it->second.begin() + count);

      data.append(buf);

    } /* /while */
  } /* /for */
}

ext: cc

max_stars_repo_name: Guptacoin/guptapool

max_issues_repo_name: Guptacoin/guptapool

max_forks_repo_name: Guptacoin/guptapool


text:
//
// Copyright (c) 2009 Rutger ter Borg
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BOOST_NUMERIC_BINDINGS_DETAIL_OFFSET_HPP
#define BOOST_NUMERIC_BINDINGS_DETAIL_OFFSET_HPP

#include <boost/utility/enable_if.hpp>
#include <boost/mpl/and.hpp>
#include <boost/numeric/bindings/is_column_major.hpp>
#include <boost/numeric/bindings/has_linear_array.hpp>
#include <boost/numeric/bindings/has_band_array.hpp>
#include <boost/numeric/bindings/stride.hpp>

namespace boost {
namespace numeric {
namespace bindings {
namespace detail {

template< typename T, typename Enable = void >
struct offset_impl {};

template< typename T >
struct offset_impl< T, typename boost::enable_if< has_linear_array< T > >::type > {

    static std::ptrdiff_t invoke( const T& t, std::ptrdiff_t i1 ) {
        return i1 * bindings::stride1( t );
    }

    static std::ptrdiff_t invoke( const T& t, std::ptrdiff_t i1, std::ptrdiff_t i2 ) {
        return i1 * bindings::stride1( t ) +
               i2 * bindings::stride2( t );
    }

};

template< typename T >
struct offset_impl< T,
        typename boost::enable_if<
            mpl::and_<
                has_band_array< T >,
                is_column_major< T >
            >
        >::type > {

    static std::ptrdiff_t invoke( const T& t, std::ptrdiff_t i1, std::ptrdiff_t i2 ) {
        return i1 * bindings::stride1( t ) +
               i2 * (bindings::stride2( t )-1);
    }

};

template< typename T >
std::ptrdiff_t offset( const T& t, std::ptrdiff_t i1 ) {
    return offset_impl< T >::invoke( t, i1 );
}

template< typename T >
std::ptrdiff_t offset( const T& t, std::ptrdiff_t i1, std::ptrdiff_t i2 ) {
    return offset_impl< T >::invoke( t, i1, i2 );
}

} // namespace detail
} // namespace bindings
} // namespace numeric
} // namespace boost

#endif

ext: hpp

max_stars_repo_name: ljktest/siconos

max_issues_repo_name: ljktest/siconos

max_forks_repo_name: ljktest/siconos