#pragma once
#include <ctime>
#include <cstdlib>

#include <opencv2/highgui.hpp>
#include <opencv2/videoio.hpp>
#include <vpp/vpp.hh>
#include <Eigen/Core>
#include <list>

using namespace vpp;
using namespace std;
using namespace Eigen;
using namespace iod;
using namespace cv;

namespace vpp
{

void get_vanishing_points(int N, std::list<vint2> dominant_lines, int T_theta, int rhomax)
{
    int discr_phi = 1400;
    int discr_the = 1400;
    float scale = rhomax/2.0;
    VectorXf vanish_accumulator(discr_phi*discr_the);
    vanish_accumulator.setZero();
    std::vector<vfloat3> acc_;
    for(auto &dl1 : dominant_lines)
    {
        for(auto &dl2 : dominant_lines)
        {
            if((dl1-dl2).norm()!=0)
            {
                float rho1,rho2,theta1,theta2;
                theta1 = ((2*M_PI*(dl1[1]))/ (T_theta-1)) - M_PI;
                rho1 = dl1[0];
                theta2 = ((2*M_PI*(dl2[1]))/ (T_theta-1)) - M_PI;
                rho2 = dl2[0];
                float x = (rho2/sin(theta2) - rho1/sin(theta1)) / ( 1/tan(theta2) - 1/tan(theta1));
                float y = (rho2 - x*cos(theta2) ) / sin(theta2) ;
                float x_2 = x/2;
                float y_2 = y/2;
                float diag_2 = sqrt(x_2*x_2 + y_2*y_2);
                float phi = acos(y_2/diag_2);
                float big_diag_2 = sqrt(rhomax + diag_2*diag_2);
                float theta = acos(diag_2/big_diag_2);
                int ind_theta = discr_the * theta / (M_PI/2);
                int ind_phi = discr_phi * phi / (2 * M_PI);
                vanish_accumulator[ind_theta*discr_phi + ind_phi]++;
                //cout << "valeurs : x = " << x_2 << " y = " << y_2 << " diag2 " << diag_2 << " bid " << big_diag_2 << endl;
                float ph = 2*M_PI*ind_phi / discr_phi;
                float th = (M_PI/2)*ind_theta / discr_the;
                cout << "valeurs " << ph << "  " << th << endl;
                cout << "valeurs " << phi << "  " << theta << endl << endl << endl;
            }
        }
    }
    std::list<vint3> max_accu;
    for(int t = 0 ; t < discr_the ; t++)
    {
        for(int p = 0 ; p < discr_phi ; p++)
        {
            int ind = t*discr_phi + p ;
            if(vanish_accumulator[ind]>0)
            {
                cout << "valeur accumulée " << vanish_accumulator[ind] << endl;
                max_accu.push_back(vint3(t,p,vanish_accumulator[ind]));
            }

        }
    }
    max_accu.sort( [&](vint3& a, vint3& b){return a[2] > b[2];});
    int i =0;
    for(auto &val : max_accu)
    {
        int t = val[0];
        int p = val[1];
        float phi = 2*M_PI*p / discr_phi;
        float theta = 2*M_PI * t / discr_the;
        cout << " les angles  phi :" << phi << " theta " << theta << endl;
        if(i==2)
            break;
        i++;
    }
}

void get_vanishing_points1(int N, std::vector<vfloat3> dominant_lines, int T_theta, int rhomax, int nrows,int ncols)
{
    //int discr_phi = 1400;
    //int discr_the = 1400;
    //float scale = rhomax/2.0;
    //VectorXf vanish_accumulator(discr_phi*discr_the);
    std::vector<vfloat4> coord(3,vfloat4(0,0,0,-1));
    for(int i = 0 ; i < 3 ; i++)
    {
        (coord[i])[3] = i;
    }
    //vanish_accumulator.setZero();
    float mx = ncols/2;
    float my = nrows/2;
    std::vector<vfloat3> acc_;
    std::vector<vfloat3> cluster1;
    std::vector<vfloat3> cluster2;
    std::vector<vfloat3> cluster3;
    std::vector<vfloat3> outliers;
    for(int i = 0 ; i < dominant_lines.size(); i++)
    {
        cout <<" i = " << i << endl;
        for(int j = i+1 ; j < dominant_lines.size(); j++)
        {
            if(j!=i && j < dominant_lines.size())
            {
                cout << " j = " << j << endl;
                float rho1,rho2,theta1,theta2;
                theta1 = ((2*M_PI*(dominant_lines[i])[1])/ (T_theta-1)) - M_PI;
                rho1 = (dominant_lines[i])[0];
                theta2 = ((2*M_PI*(dominant_lines[j])[1])/ (T_theta-1)) - M_PI;
                rho2 = (dominant_lines[j])[0];
                float x = (rho2/sin(theta2) - rho1/sin(theta1)) / ( 1/tan(theta2) - 1/tan(theta1));
                float y = (rho2 - x*cos(theta2) ) / sin(theta2);
                if(fabs(theta1-theta2)<0.1)
                {
                    vfloat3 point= vfloat3(x,y,2);
                    for(int k = 0 ; k < dominant_lines.size() ; k++)
                    {
                        if(k!=i && k!=j)
                        {
                            float rho3,theta3;
                            rho3 = (dominant_lines[k])[0];
                            theta3 = ((2*M_PI*(dominant_lines[k])[1])/ (T_theta-1)) - M_PI;
                            float res = cos(theta3)*x + sin(theta3)*y - rho3;
                            if(fabs(res) < 10)
                            {
                                point[2]++;
                            }
                        }
                    }
                    acc_.push_back(point);
                    cout << " x " << point[0] << " y " << point[1] << " val " << point[2] << endl;
                }
            }
        }
    }
    std::sort(acc_.begin(), acc_.end(),[&](vfloat3& a, vfloat3& b){return a[2] > b[2];});
    //std::vector<vint2> vanishing_point(3);
    double inf = std::numeric_limits<float>::infinity();
    for(int i = 0 ; i < acc_.size() ; i++)
    {
        if((acc_[i])[2]>=2)
        {
            cout << " x " << (acc_[i])[0] << " y " << (acc_[i])[1] << " val " << (acc_[i])[2] << endl;
            if(i==0)
            {
                cluster1.push_back(acc_[i]);
                continue;
            }
            if( fabs((acc_[i])[0]) == inf && fabs((acc_[i])[1]) == inf)
            {
                if( cluster1.size()>0 &&  (acc_[i])[0]==(cluster1[0])[0]   && (acc_[i])[1]==(cluster1[0])[1]   )
                {
                    cluster1.push_back(acc_[i]);
                }
                else if( cluster2.size()>0 &&  (acc_[i])[0]==(cluster2[0])[0]   && (acc_[i])[1]==(cluster2[0])[1]   )
                {
                    cluster2.push_back(acc_[i]);
                }
                else if( cluster3.size()>0 &&  (acc_[i])[0]==(cluster3[0])[0]   && (acc_[i])[1]==(cluster3[0])[1]   )
                {
                    cluster3.push_back(acc_[i]);
                }
            }
            else
            {
                if( cluster1.size()>0 && ( (acc_[i])[0]*(cluster1[0])[0] > 0  && (acc_[i])[1]*(cluster1[0])[1] > 0 ) )
                {
                    if(( (acc_[i]).segment(0,1) - (cluster1[0]).segment(0,1) ).norm() < 100  )
                    cluster1.push_back(acc_[i]);
                }
                else if(  cluster2.size()>0 && ( (acc_[i])[0]*(cluster2[0])[0] > 0  && (acc_[i])[1]*(cluster2[0])[1] > 0 ) )
                {
                    if(( (acc_[i]).segment(0,1) - (cluster2[0]).segment(0,1) ).norm() < 100 )
                    cluster2.push_back(acc_[i]);
                }
                else if(  cluster3.size()>0 && ( (acc_[i])[0]*(cluster3[0])[0] > 0  && (acc_[i])[1]*(cluster3[0])[1] > 0 )  )
                {
                          if(( (acc_[i]).segment(0,1) - (cluster3[0]).segment(0,1) ).norm() < 100)
                    cluster3.push_back(acc_[i]);
                }
                else
                {
                    if(cluster1.size()==0)
                    {
                        cluster1.push_back(acc_[i]);
                    }
                    else if(cluster2.size()==0)
                    {
                        cluster2.push_back(acc_[i]);
                    }
                    else if(cluster3.size()==0)
                    {
                        cluster3.push_back(acc_[i]);
                    }
                    else
                    {
                        outliers.push_back(acc_[i]);
                    }
                }
            }
        }
    }
    vfloat3 C1;
    vfloat3 C2;
    vfloat3 C3;
    if(cluster1.size() == 0 || cluster2.size() == 0 || cluster3.size() == 0 )
    {
        return;
    }

    if(cluster1.size()>0 &&  fabs((cluster1[0])[0]) == inf && fabs((cluster1[0])[1]) == inf )
    {
        C1 = cluster1[0];
    }
    else if ( cluster1.size()>0 )
    {
        float cf1 = 0;
        cout << "cluster 1" << endl;
        for(int i = 0 ; i < cluster1.size() ; i++)
        {
            cout << " x " << (cluster1[i])[0] << " y " << (cluster1[i])[1] << " val " << (cluster1[i])[2] << endl;
            C1[0] += (cluster1[i])[0] * (cluster1[i])[2];
            C1[1] += (cluster1[i])[1] * (cluster1[i])[2];
            cf1 += (cluster1[i])[2];
        }
        C1[0] /= cf1;
        C1[1] /= cf1;
        C1[2] = -1;
    }
    cout << endl << endl << endl;

    if(cluster2.size()>0 &&  fabs((cluster2[0])[0]) == inf && fabs((cluster2[0])[1]) == inf )
    {
        C2 = cluster2[0];
    }
    else if ( cluster2.size()>0 )
    {
        float cf2 = 0;
        cout << "cluster 2" << endl;
        for(int i = 0 ; i < cluster2.size() ; i++)
        {
            cout << " x " << (cluster2[i])[0] << " y " << (cluster2[i])[1] << " val " << (cluster2[i])[2] << endl;
            C2[0] += (cluster2[i])[0] * (cluster2[i])[2];
            C2[1] += (cluster2[i])[1] * (cluster2[i])[2];
            cf2 += (cluster2[i])[2];
        }
        C2[0] /= cf2;
        C2[1] /= cf2;
        C2[2] = -1;
    }

    cout << endl << endl << endl;

    if(cluster3.size()>0 &&  fabs((cluster3[0])[0]) == inf && fabs((cluster3[0])[1]) == inf )
    {
        C3 = cluster3[0];
    }
    else if ( cluster3.size()>0 )
    {
        float cf3 = 0;
        cout << "cluster 3" << endl;
        for(int i = 0 ; i < cluster3.size() ; i++)
        {
            cout << " x " << (cluster3[i])[0] << " y " << (cluster3[i])[1] << " val " << (cluster3[i])[2] << endl;
            C3[0] += (cluster3[i])[0] * (cluster3[i])[2];
            C3[1] += (cluster3[i])[1] * (cluster3[i])[2];
            cf3 += (cluster3[i])[2];
        }
        C3[0] /= cf3;
        C3[1] /= cf3;
        C3[2] = -1;
    }

    cout << endl << endl << endl;

    cout << "cluster 1 " << C1 << endl;
    cout << "cluster 2 " << C2 << endl;
    cout << "cluster 3 " << C3 << endl;/**/

}

void get_vanishing_points2(int N, std::vector<vfloat3> dominant_lines, int T_theta, int rhomax)
{
    int discr_phi = 1400;
    int discr_the = 1400;
    float scale = rhomax/2.0;
    VectorXf vanish_accumulator(discr_phi*discr_the);
    vanish_accumulator.setZero();
    std::vector<vfloat3> acc_;
    for(int i = 0 ; i < dominant_lines.size(); i++)
    {
        cout <<" i = " << i << endl;
        for(int j = i+1 ; j < dominant_lines.size(); j++)
        {
            if(j!=i && j < dominant_lines.size())
            {
                cout << " j = " << j << endl;
                float rho1,rho2,theta1,theta2;
                theta1 = ((2*M_PI*(dominant_lines[i])[1])/ (T_theta-1)) - M_PI;
                rho1 = (dominant_lines[i])[0];
                theta2 = ((2*M_PI*(dominant_lines[j])[1])/ (T_theta-1)) - M_PI;
                rho2 = (dominant_lines[j])[0];
                float x = (rho2/sin(theta2) - rho1/sin(theta1)) / ( 1/tan(theta2) - 1/tan(theta1));
                float y = (rho2 - x*cos(theta2) ) / sin(theta2);
                if(fabs(theta1-theta2)<0.5)
                {
                    vfloat3 point= vfloat3(x,y,(dominant_lines[i])[2] + (dominant_lines[j])[2]);
                    for(int k = 0 ; k < dominant_lines.size() ; k++)
                    {
                        if(k!=i && k!=j)
                        {
                            float rho3,theta3;
                            rho3 = (dominant_lines[k])[0];
                            theta3 = ((2*M_PI*(dominant_lines[k])[1])/ (T_theta-1)) - M_PI;
                            float res = cos(theta3)*x + sin(theta3)*y - rho3;
                            if(fabs(res) < 50)
                            {
                                point[2] += (dominant_lines[k])[2];
                            }
                        }
                    }
                    acc_.push_back(point);
                    cout << " x " << point[0] << " y " << point[1] << " val " << point[2] << endl;
                }
            }
        }
    }
    std::sort(acc_.begin(), acc_.end(),[&](vfloat3& a, vfloat3& b){return a[2] > b[2];});
    for(int i = 0 ; i < acc_.size() ; i++)
    {
        if((acc_[i])[2]>2)
        {
            cout << " x " << (acc_[i])[0] << " y " << (acc_[i])[1] << " val " << (acc_[i])[2] << endl;
        }
    }
}

inline
float compute_a(float thetaj)
{
    return 2*M_PI*(1-cos(thetaj));
}

inline
float compute_theta(float nz,float nx,float ny, float phi)
{
    return asin(nz/(sqrt(nz*nz+ pow(nx*cos(phi)+ny*sin(phi),2))));
}

inline
float compute_psi(float nz,float nx,float ny, float phi)
{
    float alpha = nx*cos(phi) + ny*sin(phi);
    return M_PI/2 * alpha /(sqrt(nz*nz + alpha*alpha));
}

}


#include <cmath>
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <algorithm>
#include <boost/range/algorithm.hpp>
#include <boost/integer/common_factor_rt.hpp>

using namespace std;

int N, M, ret;
bool b[100001];
int dp[100001];

int step(int s) {
    if (b[s]) {
        return 0;
    }
    if (s == N) {
        return 1;
    }
    long long int ret = dp[s + 1];
    if (s + 2 != N + 1) {
        ret += dp[s + 2];
    }
    return ret % 1000000007;
}

int main() {

    while (cin >> N >> M) {
        for (int i = 0; i <= N; i++) {
            b[i] = false;
        }
        for (int i = 0; i < M; i++) {
            int a;
            cin >> a;
            b[a] = true;
        }
        for (int i = 0; i <= N; i++) {
            dp[N - i] = step(N - i);
        }

        cout << dp[0] << endl;
    }

    return 0;
}


#include "ql/qldefines.hpp"
#include <boost/config.hpp>
#ifdef BOOST_MSVC
#  include <ql/auto_link.hpp>
#endif

/*CVAIRS*/
#include <ql/instruments/vanillaswap.hpp>
#include <ql/instruments/makevanillaswap.hpp>
#include <ql/pricingengines/swap/discountingswapengine.hpp>
#include <ql/pricingengines/swap/cvaswapengine.hpp>
#include <ql/termstructures/yield/piecewiseyieldcurve.hpp>
#include <ql/termstructures/yield/ratehelpers.hpp>
#include <ql/termstructures/credit/interpolatedhazardratecurve.hpp>
#include <ql/indexes/ibor/euribor.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/daycounters/actualactual.hpp>
#include <ql/time/daycounters/actual360.hpp>
/*end CVAIRS*/

/*Bonds*/
#include <ql/instruments/bonds/zerocouponbond.hpp>
#include <ql/instruments/bonds/floatingratebond.hpp>
#include <ql/pricingengines/bond/discountingbondengine.hpp>
#include <ql/cashflows/couponpricer.hpp>
#include <ql/termstructures/yield/piecewiseyieldcurve.hpp>
#include <ql/termstructures/yield/bondhelpers.hpp>
#include <ql/termstructures/volatility/optionlet/constantoptionletvol.hpp>
#include <ql/indexes/ibor/euribor.hpp>
#include <ql/indexes/ibor/usdlibor.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/calendars/unitedstates.hpp>
#include <ql/time/daycounters/actualactual.hpp>
#include <ql/time/daycounters/actual360.hpp>
#include <ql/time/daycounters/thirty360.hpp>
#include <ql/utilities/dataparsers.hpp>
/*end Bonds */

/*Convertible Bonds */
#include <ql/experimental/convertiblebonds/convertiblebond.hpp>
#include <ql/experimental/convertiblebonds/binomialconvertibleengine.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/daycounters/thirty360.hpp>
#include <ql/utilities/dataformatters.hpp>
#define LENGTH(a) (sizeof(a)/sizeof(a[0]))
/* end Convertible Bonds */

/*BermudanSwaptions*/
#include <ql/instruments/swaption.hpp>
#include <ql/pricingengines/swap/discountingswapengine.hpp>
#include <ql/pricingengines/swaption/treeswaptionengine.hpp>
#include <ql/pricingengines/swaption/jamshidianswaptionengine.hpp>
#include <ql/pricingengines/swaption/g2swaptionengine.hpp>
#include <ql/pricingengines/swaption/fdhullwhiteswaptionengine.hpp>
#include <ql/pricingengines/swaption/fdg2swaptionengine.hpp>
#include <ql/models/shortrate/calibrationhelpers/swaptionhelper.hpp>
#include <ql/models/shortrate/onefactormodels/blackkarasinski.hpp>
#include <ql/math/optimization/levenbergmarquardt.hpp>
#include <ql/indexes/ibor/euribor.hpp>
#include <ql/cashflows/coupon.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/daycounters/thirty360.hpp>
#include <ql/utilities/dataformatters.hpp>
/*end BermudanSwaptions*/

/*Callable Bonds */
#include <ql/experimental/callablebonds/callablebond.hpp>
#include <ql/experimental/callablebonds/treecallablebondengine.hpp>
#include <ql/models/shortrate/onefactormodels/hullwhite.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/time/calendars/unitedstates.hpp>
#include <ql/time/daycounters/actualactual.hpp>

#include <vector>
#include <cmath>
/* end of Callable Bonds */

#include <iostream>
#include <iomanip>
#include <string>
#include "json.hpp"

//using namespace emscripten;
using namespace QuantLib;
using json = nlohmann::json;

//using namespace std;
//using namespace std::string_literals;

#if defined(QL_ENABLE_SESSIONS)
namespace QuantLib {

    ThreadKey sessionId() { return {}; }

}
#endif

ext::shared_ptr<YieldTermStructure>
        flatRate(const Date& today,
            const ext::shared_ptr<Quote>& forward,
            const DayCounter& dc,
            const Compounding& compounding,
            const Frequency& frequency) {
        return ext::shared_ptr<YieldTermStructure>(
            new FlatForward(today,
                Handle<Quote>(forward),
                dc,
                compounding,
                frequency));
}

                ext::shared_ptr<YieldTermStructure>
        flatRate(const Date& today,
                Rate forward,
                const DayCounter& dc,
                const Compounding &compounding,
                const Frequency &frequency) {
        return flatRate(today,
                ext::shared_ptr<Quote>(new SimpleQuote(forward)),
                dc,
                compounding,
                frequency);
}

std::string calculateCallableBonds(std::string data){

        try {
                json jData = json::parse(data);

                Date today = Date(DateParser::parseISO( jData["request"]["referenceDate"].get<std::string>()));
                Settings::instance().evaluationDate() = today;

                Rate bbCurveRate = jData["request"]["bbCurveRate"].get<float>();

                DayCounter bbDayCounter = ActualActual(ActualActual::Bond);
                InterestRate bbIR(bbCurveRate,bbDayCounter,Compounded,Semiannual);

                Handle<YieldTermStructure> termStructure(flatRate(today,
                                                                bbIR.rate(),
                                                                bbIR.dayCounter(),
                                                                bbIR.compounding(),
                                                                bbIR.frequency()));

                CallabilitySchedule callSchedule;
                Real callPrice = jData["request"]["callPrice"].get<int>();
                Size numberOfCallDates = jData["request"]["numberOfCallDates"].get<int>();
                Date callDate = Date(DateParser::parseISO( jData["request"]["callDate"].get<std::string>()));

                for (Size i=0; i< numberOfCallDates; i++) {
                Calendar nullCalendar = NullCalendar();

                Bond::Price myPrice(callPrice, Bond::Price::Clean);
                callSchedule.push_back(
                        ext::make_shared<Callability>(
                                        myPrice,
                                        Callability::Call,
                                        callDate ));
                callDate = nullCalendar.advance(callDate, 3, Months);
                }

                Date dated = Date(DateParser::parseISO(jData["request"]["callableBond"]["issueDate"].get<std::string>()));
                Date issue = dated;
                Date maturity = Date(DateParser::parseISO( jData["request"]["callableBond"]["maturityDate"].get<std::string>()));

                Natural settlementDays = jData["request"]["callableBond"]["settlementDays"].get<int>();
                Calendar bondCalendar = UnitedStates(UnitedStates::GovernmentBond);
                Real coupon = jData["request"]["callableBond"]["coupon"].get<float>();

                Frequency frequency = Quarterly;

                Real redemption = jData["request"]["callableBond"]["redemption"].get<float>();

                Real faceAmount = jData["request"]["callableBond"]["faceAmount"].get<float>();

                DayCounter bondDayCounter = ActualActual(ActualActual::Bond);

                // PFC1 shows no indication dates are being adjusted
                // for weekends/holidays for vanilla bonds
                BusinessDayConvention accrualConvention = Unadjusted;
                BusinessDayConvention paymentConvention = Unadjusted;

                Schedule sch(dated, maturity, Period(frequency), bondCalendar,
                        accrualConvention, accrualConvention,
                        DateGeneration::Backward, false);

                Size maxIterations = jData["request"]["maxIterations"];

                //Real accuracy = 1e-8;
                Real accuracy = jData["request"]["accuracy"];

                //Integer gridIntervals = 40;
                Integer gridIntervals = jData["request"]["gridIntervals"];

                //Real reversionParameter = .03;
                Real reversionParameter = jData["request"]["reversionParameter"].get<float>();

                // output price/yield results for varying volatility parameter

                Real sigma = QL_EPSILON;

                for (long unsigned int i = 0; i < jData["request"]["sigma"].size(); i++){
                        switch (i){
                                case 0:{
                                        ext::shared_ptr<ShortRateModel> hw0(new HullWhite(termStructure,reversionParameter,sigma));
                                        ext::shared_ptr<PricingEngine> engine0(new TreeCallableFixedRateBondEngine(hw0,gridIntervals));
                                        CallableFixedRateBond callableBond(settlementDays,faceAmount, sch,std::vector<Rate>(1, coupon),bondDayCounter, paymentConvention,redemption,issue,callSchedule);
                                        callableBond.setPricingEngine(engine0);
                                        jData["response"][std::to_string(i)]["sigma"] = 0.0;//jData["request"]["sigma"][0];
                                        jData["response"][std::to_string(i)]["cleanPrice"] =  callableBond.cleanPrice();
                                        jData["response"][std::to_string(i)]["yield"] =  100. * callableBond.yield(bondDayCounter,Compounded,frequency,accuracy,maxIterations);
                                        break;
                                }
                                case 1:{
                                        sigma = jData["request"]["sigma"][i];
                                        ext::shared_ptr<ShortRateModel> hw1(new HullWhite(termStructure,reversionParameter,sigma));
                                        ext::shared_ptr<PricingEngine> engine1(new TreeCallableFixedRateBondEngine(hw1,gridIntervals));
                                        CallableFixedRateBond callableBond(settlementDays,faceAmount, sch,std::vector<Rate>(1, coupon),bondDayCounter, paymentConvention,redemption,issue,callSchedule);
                                        callableBond.setPricingEngine(engine1);
                                        jData["response"][std::to_string(i)]["sigma"] = 0.01;//jData["request"]["sigma"][i];
                                        jData["response"][std::to_string(i)]["cleanPrice"] =  callableBond.cleanPrice();
                                        jData["response"][std::to_string(i)]["yield"] =  100. * callableBond.yield(bondDayCounter,Compounded,frequency,accuracy,maxIterations);
                                        break;
                                }
                                case 2: {
                                        sigma = jData["request"]["sigma"][i];
                                        ext::shared_ptr<ShortRateModel> hw2(new HullWhite(termStructure, reversionParameter, sigma));
                                        ext::shared_ptr<PricingEngine> engine2(new TreeCallableFixedRateBondEngine(hw2,gridIntervals));
                                        CallableFixedRateBond callableBond(settlementDays,faceAmount, sch,std::vector<Rate>(1, coupon),bondDayCounter, paymentConvention,redemption,issue,callSchedule);
                                        callableBond.setPricingEngine(engine2);
                                        jData["response"][std::to_string(i)]["sigma"] = 0.03;//jData["request"]["sigma"][2];
                                        jData["response"][std::to_string(i)]["cleanPrice"] =  callableBond.cleanPrice();
                                        jData["response"][std::to_string(i)]["yield"] =  100. * callableBond.yield(bondDayCounter,Compounded,frequency,accuracy,maxIterations);
                                        break;
                                }
                                case 3: {
                                        sigma = jData["request"]["sigma"][i];
                                        ext::shared_ptr<ShortRateModel> hw3(new HullWhite(termStructure, reversionParameter, sigma));
                                        ext::shared_ptr<PricingEngine> engine3(new TreeCallableFixedRateBondEngine(hw3,gridIntervals));
                                        CallableFixedRateBond callableBond(settlementDays,faceAmount, sch,std::vector<Rate>(1, coupon),bondDayCounter, paymentConvention,redemption,issue,callSchedule);
                                        callableBond.setPricingEngine(engine3);
                                        jData["response"][std::to_string(i)]["sigma"] = 0.06;//jData["request"]["sigma"][3];
                                        jData["response"][std::to_string(i)]["cleanPrice"] =  callableBond.cleanPrice();
                                        jData["response"][std::to_string(i)]["yield"] =  100. * callableBond.yield(bondDayCounter,Compounded,frequency,accuracy,maxIterations);
                                        break;
                                }
                                case 4:{
                                        sigma = jData["request"]["sigma"][i];
                                        ext::shared_ptr<ShortRateModel> hw4(new HullWhite(termStructure, reversionParameter, sigma));
                                        ext::shared_ptr<PricingEngine> engine4(new TreeCallableFixedRateBondEngine(hw4,gridIntervals));
                                        CallableFixedRateBond callableBond(settlementDays,faceAmount, sch,std::vector<Rate>(1, coupon),bondDayCounter, paymentConvention,redemption,issue,callSchedule);
                                        callableBond.setPricingEngine(engine4);
                                        jData["response"][std::to_string(i)]["sigma"] = 0.012;//jData["request"]["sigma"][4];
                                        jData["response"][std::to_string(i)]["cleanPrice"] =  callableBond.cleanPrice();
                                        jData["response"][std::to_string(i)]["yield"] =  100. * callableBond.yield(bondDayCounter,Compounded,frequency,accuracy,maxIterations);
                                        break;
                                }
                                default: break;
                        }
                }

                std::cout << "JDATA" << std::setw(4) << jData["response"] << std::endl;
                std::string result = jData.dump();
                return result;

        } catch (std::exception& e) {
                std::cerr << e.what() << std::endl;
                return "1";
        } catch (...) {
                std::cerr << "unknown error" << std::endl;
                return "1";
        }
};

std::string calculateRegularBond(std::string data){

    try {

        json incomingJsonData = json::parse(data);

        std::cout << std::endl;

        /*********************
         ***  MARKET DATA  ***
         *********************/

        Calendar calendar = TARGET();

        Date settlementDate = DateParser::parseISO( incomingJsonData["request"]["settlementDate"].get<std::string>());
        // must be a business day
        settlementDate = calendar.adjust(settlementDate);

        Integer fixingDays = incomingJsonData["request"]["fixingDays"];
        Natural settlementDays = incomingJsonData["request"]["settlementDays"];

        Date todaysDate = calendar.advance(settlementDate, -fixingDays, Days);
        // nothing to do with Date::todaysDate
        Settings::instance().evaluationDate() = todaysDate;

        Rate zc3mQuote = incomingJsonData["request"]["zeroCoupnRates"]["zc3mQuote"];
        Rate zc6mQuote = incomingJsonData["request"]["zeroCoupnRates"]["zc6mQuote"];
        Rate zc1yQuote = incomingJsonData["request"]["zeroCoupnRates"]["zc1yQuote"];

        ext::shared_ptr<Quote> zc3mRate(new SimpleQuote(zc3mQuote));
        ext::shared_ptr<Quote> zc6mRate(new SimpleQuote(zc6mQuote));
        ext::shared_ptr<Quote> zc1yRate(new SimpleQuote(zc1yQuote));

        DayCounter zcBondsDayCounter = Actual365Fixed();

        ext::shared_ptr<RateHelper> zc3m(new DepositRateHelper(
                Handle<Quote>(zc3mRate),
                3*Months, fixingDays,
                calendar, ModifiedFollowing,
                true, zcBondsDayCounter));
        ext::shared_ptr<RateHelper> zc6m(new DepositRateHelper(
                Handle<Quote>(zc6mRate),
                6*Months, fixingDays,
                calendar, ModifiedFollowing,
                true, zcBondsDayCounter));
        ext::shared_ptr<RateHelper> zc1y(new DepositRateHelper(
                Handle<Quote>(zc1yRate),
                1*Years, fixingDays,
                calendar, ModifiedFollowing,
                true, zcBondsDayCounter));

        // setup bonds
        Real redemption = 100.0;

        const Size numberOfBonds = 5;

        Date issueDates[] = {
                Date (DateParser::parseISO( incomingJsonData["request"]["issueDate"][0].get<std::string>())),
                Date (DateParser::parseISO( incomingJsonData["request"]["issueDate"][1].get<std::string>())),
                Date (DateParser::parseISO( incomingJsonData["request"]["issueDate"][2].get<std::string>())),
                Date (DateParser::parseISO( incomingJsonData["request"]["issueDate"][3].get<std::string>())),
                Date (DateParser::parseISO( incomingJsonData["request"]["issueDate"][4].get<std::string>()))
        };

        Date maturities[] = {
                Date (DateParser::parseISO( incomingJsonData["request"]["maturities"][0].get<std::string>())),
                Date (DateParser::parseISO( incomingJsonData["request"]["maturities"][1].get<std::string>())),
                Date (DateParser::parseISO( incomingJsonData["request"]["maturities"][2].get<std::string>())),
                Date (DateParser::parseISO( incomingJsonData["request"]["maturities"][3].get<std::string>())),
                Date (DateParser::parseISO( incomingJsonData["request"]["maturities"][4].get<std::string>()))
        };

        Real couponRates[] = {
                incomingJsonData["request"]["couponRates"][0],
                incomingJsonData["request"]["couponRates"][1],
                incomingJsonData["request"]["couponRates"][2],
                incomingJsonData["request"]["couponRates"][3],
                incomingJsonData["request"]["couponRates"][4]
        };

        Real marketQuotes[] = {
                incomingJsonData["request"]["marketQuotes"][0],
                incomingJsonData["request"]["marketQuotes"][1],
                incomingJsonData["request"]["marketQuotes"][2],
                incomingJsonData["request"]["marketQuotes"][3],
                incomingJsonData["request"]["marketQuotes"][4]
        };

        std::vector< ext::shared_ptr<SimpleQuote> > quote;
        for (double marketQuote : marketQuotes) {
            ext::shared_ptr<SimpleQuote> cp(new SimpleQuote(marketQuote));
            quote.push_back(cp);
        }

        RelinkableHandle<Quote> quoteHandle[numberOfBonds];
        for (Size i=0; i<numberOfBonds; i++) {
            quoteHandle[i].linkTo(quote[i]);
        }

        // Definition of the rate helpers
        std::vector<ext::shared_ptr<BondHelper> > bondsHelpers;

        for (Size i=0; i<numberOfBonds; i++) {

                Schedule schedule(issueDates[i], maturities[i], Period(Semiannual), UnitedStates(UnitedStates::GovernmentBond),
                        Unadjusted, Unadjusted, DateGeneration::Backward, false);

                ext::shared_ptr<FixedRateBondHelper> bondHelper(new FixedRateBondHelper(
                        quoteHandle[i],
                        settlementDays,
                        100.0,
                        schedule,
                        std::vector<Rate>(1,couponRates[i]),
                        ActualActual(ActualActual::Bond),
                        Unadjusted,
                        redemption,
                        issueDates[i]));

            // the above could also be done by creating a
            // FixedRateBond instance and writing:
            //
            // ext::shared_ptr<BondHelper> bondHelper(
            //         new BondHelper(quoteHandle[i], bond));
            //
            // This would also work for bonds that still don't have a
            // specialized helper, such as floating-rate bonds.

            bondsHelpers.push_back(bondHelper);
        }

        /*********************
        **  CURVE BUILDING **
        *********************/

        // Any DayCounter would be fine.
        // ActualActual::ISDA ensures that 30 years is 30.0
        DayCounter termStructureDayCounter =
        ActualActual(ActualActual::ISDA);

        // A depo-bond curve
        std::vector<ext::shared_ptr<RateHelper> > bondInstruments;

        // Adding the ZC bonds to the curve for the short end
        bondInstruments.push_back(zc3m);
        bondInstruments.push_back(zc6m);
        bondInstruments.push_back(zc1y);

        // Adding the Fixed rate bonds to the curve for the long end
        for (Size i=0; i<numberOfBonds; i++) {
        bondInstruments.push_back(bondsHelpers[i]);
        }

        ext::shared_ptr<YieldTermStructure> bondDiscountingTermStructure(
                new PiecewiseYieldCurve<Discount,LogLinear>(
                        settlementDate, bondInstruments,
                        termStructureDayCounter));

        // Building of the Libor forecasting curve
        // deposits
        Rate d1wQuote = incomingJsonData["request"]["liborRates"]["d1wQuote"];
        Rate d1mQuote = incomingJsonData["request"]["liborRates"]["d1mQuote"];
        Rate d3mQuote = incomingJsonData["request"]["liborRates"]["d3mQuote"];
        Rate d6mQuote = incomingJsonData["request"]["liborRates"]["d6mQuote"];
        Rate d9mQuote = incomingJsonData["request"]["liborRates"]["d9mQuote"];
        Rate d1yQuote = incomingJsonData["request"]["liborRates"]["d1yQuote"];
        // swaps
        Rate s2yQuote = incomingJsonData["request"]["swapRates"]["s2yQuote"];
        Rate s3yQuote = incomingJsonData["request"]["swapRates"]["s3yQuote"];
        Rate s5yQuote = incomingJsonData["request"]["swapRates"]["s5yQuote"];
        Rate s10yQuote = incomingJsonData["request"]["swapRates"]["s10yQuote"];
        Rate s15yQuote = incomingJsonData["request"]["swapRates"]["s15yQuote"];

        /********************
         ***    QUOTES    ***
        ********************/

        // SimpleQuote stores a value which can be manually changed;
        // other Quote subclasses could read the value from a database
        // or some kind of data feed.

        // deposits
        ext::shared_ptr<Quote> d1wRate(new SimpleQuote(d1wQuote));
        ext::shared_ptr<Quote> d1mRate(new SimpleQuote(d1mQuote));
        ext::shared_ptr<Quote> d3mRate(new SimpleQuote(d3mQuote));
        ext::shared_ptr<Quote> d6mRate(new SimpleQuote(d6mQuote));
        ext::shared_ptr<Quote> d9mRate(new SimpleQuote(d9mQuote));
        ext::shared_ptr<Quote> d1yRate(new SimpleQuote(d1yQuote));
        // swaps
        ext::shared_ptr<Quote> s2yRate(new SimpleQuote(s2yQuote));
        ext::shared_ptr<Quote> s3yRate(new SimpleQuote(s3yQuote));
        ext::shared_ptr<Quote> s5yRate(new SimpleQuote(s5yQuote));
        ext::shared_ptr<Quote> s10yRate(new SimpleQuote(s10yQuote));
        ext::shared_ptr<Quote> s15yRate(new SimpleQuote(s15yQuote));

        /*********************
         ***  RATE HELPERS ***
        *********************/

        // RateHelpers are built from the above quotes together with
        // other instrument dependant infos.  Quotes are passed in
        // relinkable handles which could be relinked to some other
        // data source later.

        // deposits
        DayCounter depositDayCounter = Actual360();

        ext::shared_ptr<RateHelper> d1w(new DepositRateHelper(
                Handle<Quote>(d1wRate),
                1*Weeks, fixingDays,
                calendar, ModifiedFollowing,
                true, depositDayCounter));
        ext::shared_ptr<RateHelper> d1m(new DepositRateHelper(
                Handle<Quote>(d1mRate),
                1*Months, fixingDays,
                calendar, ModifiedFollowing,
                true, depositDayCounter));
        ext::shared_ptr<RateHelper> d3m(new DepositRateHelper(
                Handle<Quote>(d3mRate),
                3*Months, fixingDays,
                calendar, ModifiedFollowing,
                true, depositDayCounter));
        ext::shared_ptr<RateHelper> d6m(new DepositRateHelper(
                Handle<Quote>(d6mRate),
                6*Months, fixingDays,
                calendar, ModifiedFollowing,
                true, depositDayCounter));
        ext::shared_ptr<RateHelper> d9m(new DepositRateHelper(
                Handle<Quote>(d9mRate),
                9*Months, fixingDays,
                calendar, ModifiedFollowing,
                true, depositDayCounter));
        ext::shared_ptr<RateHelper> d1y(new DepositRateHelper(
                Handle<Quote>(d1yRate),
                1*Years, fixingDays,
                calendar, ModifiedFollowing,
                true, depositDayCounter));

        // setup swaps
        Frequency swFixedLegFrequency = Annual;
        BusinessDayConvention swFixedLegConvention = Unadjusted;
        DayCounter swFixedLegDayCounter = Thirty360(Thirty360::European);
        ext::shared_ptr<IborIndex> swFloatingLegIndex(new Euribor6M);

        const Period forwardStart(1*Days);

        ext::shared_ptr<RateHelper> s2y(new SwapRateHelper(
                Handle<Quote>(s2yRate), 2*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));
        ext::shared_ptr<RateHelper> s3y(new SwapRateHelper(
                Handle<Quote>(s3yRate), 3*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));
        ext::shared_ptr<RateHelper> s5y(new SwapRateHelper(
                Handle<Quote>(s5yRate), 5*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));
        ext::shared_ptr<RateHelper> s10y(new SwapRateHelper(
                Handle<Quote>(s10yRate), 10*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));
        ext::shared_ptr<RateHelper> s15y(new SwapRateHelper(
                Handle<Quote>(s15yRate), 15*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));

        /*********************
         **  CURVE BUILDING **
        *********************/

        // Any DayCounter would be fine.
        // ActualActual::ISDA ensures that 30 years is 30.0

        // A depo-swap curve
        std::vector<ext::shared_ptr<RateHelper> > depoSwapInstruments;
        depoSwapInstruments.push_back(d1w);
        depoSwapInstruments.push_back(d1m);
        depoSwapInstruments.push_back(d3m);
        depoSwapInstruments.push_back(d6m);
        depoSwapInstruments.push_back(d9m);
        depoSwapInstruments.push_back(d1y);
        depoSwapInstruments.push_back(s2y);
        depoSwapInstruments.push_back(s3y);
        depoSwapInstruments.push_back(s5y);
        depoSwapInstruments.push_back(s10y);
        depoSwapInstruments.push_back(s15y);
        ext::shared_ptr<YieldTermStructure> depoSwapTermStructure(
                new PiecewiseYieldCurve<Discount,LogLinear>(
                        settlementDate, depoSwapInstruments,
                        termStructureDayCounter));

        // Term structures that will be used for pricing:
        // the one used for discounting cash flows
        RelinkableHandle<YieldTermStructure> discountingTermStructure;
        // the one used for forward rate forecasting
        RelinkableHandle<YieldTermStructure> forecastingTermStructure;

        /*********************
         * BONDS TO BE PRICED *
         **********************/
        //Date (DateParser::parseISO( incomingJsonData["maturities"][0].get<std::string>())),
        // Common data
        Real faceAmount = 100;

        // Pricing engine
        ext::shared_ptr<PricingEngine> bondEngine(new DiscountingBondEngine(discountingTermStructure));

        // Zero coupon bond

        ZeroCouponBond zeroCouponBond(
                settlementDays,
                UnitedStates(UnitedStates::GovernmentBond),
                faceAmount,
                Date(DateParser::parseISO( incomingJsonData["request"]["bondsToEvaluate"]["zeroCouponBond"]["expiryDate"].get<std::string>())),
                Following,
                Real(incomingJsonData["request"]["bondsToEvaluate"]["zeroCouponBond"]["realPrice"]),
                Date(DateParser::parseISO( incomingJsonData["request"]["bondsToEvaluate"]["zeroCouponBond"]["issueDate"].get<std::string>())));

        zeroCouponBond.setPricingEngine(bondEngine);

        // Fixed 4.5% US Treasury Note

        Schedule fixedBondSchedule(Date(DateParser::parseISO( incomingJsonData["request"]["bondsToEvaluate"]["FixedRateBond"]["issueDate"].get<std::string>())),
                Date(DateParser::parseISO( incomingJsonData["request"]["bondsToEvaluate"]["FixedRateBond"]["expiryDate"].get<std::string>())), Period(Semiannual),
                UnitedStates(UnitedStates::GovernmentBond),
                Unadjusted, Unadjusted, DateGeneration::Backward, false);

        FixedRateBond fixedRateBond(
                settlementDays,
                faceAmount,
                fixedBondSchedule,
                std::vector<Rate>(1, 0.045),
                ActualActual(ActualActual::Bond),
                ModifiedFollowing,
                100.0, Date(DateParser::parseISO( incomingJsonData["request"]["bondsToEvaluate"]["FixedRateBond"]["issueDate"].get<std::string>())));

        fixedRateBond.setPricingEngine(bondEngine);

        // Floating rate bond (3M USD Libor + 0.1%)
        // Should and will be priced on another curve later...

        // need to find out what is the deal with Libor here
        RelinkableHandle<YieldTermStructure> liborTermStructure;
        const ext::shared_ptr<IborIndex> libor3m(
                new USDLibor(Period(3,Months),liborTermStructure));
        libor3m->addFixing(Date(17, July, 2008),0.0278625);

        // need to find out what is the deal with Libor here
        Schedule floatingBondSchedule(Date(21, October, 2005),
                Date(21, October, 2010), Period(Quarterly),
                UnitedStates(UnitedStates::NYSE),
                Unadjusted, Unadjusted, DateGeneration::Backward, true);

        FloatingRateBond floatingRateBond(
                settlementDays,
                faceAmount,
                floatingBondSchedule,
                libor3m,
                Actual360(),
                ModifiedFollowing,
                Natural(2),
                // Gearings
                std::vector<Real>(1, 1.0),
                // Spreads
                std::vector<Rate>(1, 0.001),
                // Caps
                std::vector<Rate>(),
                // Floors
                std::vector<Rate>(),
                // Fixing in arrears
                true,
                Real(incomingJsonData["request"]["bondsToEvaluate"]["FloatingRateBond"]["realPrice"]),
                Date(DateParser::parseISO( incomingJsonData["request"]["bondsToEvaluate"]["FloatingRateBond"]["issueDate"].get<std::string>())));

        floatingRateBond.setPricingEngine(bondEngine);

        // Coupon pricers
        ext::shared_ptr<IborCouponPricer> pricer(new BlackIborCouponPricer);

        // optionLet volatilities
        Volatility volatility = 0.0;
        Handle<OptionletVolatilityStructure> vol;
        vol = Handle<OptionletVolatilityStructure>(
                ext::shared_ptr<OptionletVolatilityStructure>(new
                        ConstantOptionletVolatility(
                                settlementDays,
                                calendar,
                                ModifiedFollowing,
                                volatility,
                                Actual365Fixed())));

        pricer->setCapletVolatility(vol);
        setCouponPricer(floatingRateBond.cashflows(),pricer);

        // Yield curve bootstrapping
        forecastingTermStructure.linkTo(depoSwapTermStructure);
        discountingTermStructure.linkTo(bondDiscountingTermStructure);

        // We are using the depo & swap curve to estimate the future Libor rates
        liborTermStructure.linkTo(depoSwapTermStructure);

        /***************
         * BOND PRICING *
         ****************/

        incomingJsonData["response"]["zeroCouponBond"]["NPV"] = zeroCouponBond.NPV();
        incomingJsonData["response"]["FixedRateBond"]["NPV"] = fixedRateBond.NPV();
        incomingJsonData["response"]["FloatingRateBond"]["NPV"] = floatingRateBond.NPV();

        incomingJsonData["response"]["zeroCouponBond"]["cleanPrice"] = zeroCouponBond.cleanPrice();
        incomingJsonData["response"]["FixedRateBond"]["cleanPrice"] = fixedRateBond.cleanPrice();
        incomingJsonData["response"]["FloatingRateBond"]["cleanPrice"] = floatingRateBond.cleanPrice();

        incomingJsonData["response"]["zeroCouponBond"]["dirtyPrice"] = zeroCouponBond.dirtyPrice();
        incomingJsonData["response"]["FixedRateBond"]["dirtyPrice"] = fixedRateBond.dirtyPrice();
        incomingJsonData["response"]["FloatingRateBond"]["dirtyPrice"] = floatingRateBond.dirtyPrice();

        incomingJsonData["response"]["FixedRateBond"]["accruedAmount"] = fixedRateBond.accruedAmount();
        incomingJsonData["response"]["FloatingRateBond"]["accruedAmount"] = floatingRateBond.accruedAmount();

        incomingJsonData["response"]["zeroCouponBond"]["previousCouponRate"] = "N/A";
        incomingJsonData["response"]["FixedRateBond"]["previousCouponRate"] = fixedRateBond.previousCouponRate();
        incomingJsonData["response"]["FloatingRateBond"]["previousCouponRate"] = floatingRateBond.previousCouponRate();

        incomingJsonData["response"]["zeroCouponBond"]["nextCouponRate"] = "N/A";
        incomingJsonData["response"]["FixedRateBond"]["nextCouponRate"] = fixedRateBond.nextCouponRate();
        incomingJsonData["response"]["FloatingRateBond"]["nextCouponRate"] = floatingRateBond.nextCouponRate();

        incomingJsonData["response"]["zeroCouponBond"]["Yield"] = zeroCouponBond.yield(Actual360(),Compounded,Annual);
        incomingJsonData["response"]["FixedRateBond"]["Yield"] = fixedRateBond.yield(Actual360(),Compounded,Annual);
        incomingJsonData["response"]["FloatingRateBond"]["Yield"] = floatingRateBond.yield(Actual360(),Compounded,Annual);

        incomingJsonData["response"]["FloatingRateBond"]["YieldtoCleanPrice"] = floatingRateBond.cleanPrice(floatingRateBond.yield(Actual360(),Compounded,Annual),Actual360(),Compounded,Annual,settlementDate);
        incomingJsonData["response"]["FloatingRateBond"]["CleanPriceToYield"] = floatingRateBond.yield(floatingRateBond.cleanPrice(),Actual360(),Compounded,Annual,settlementDate);
         /* "Yield to Price"
            "Price to Yield" */

        std::cout << std::setw(4) << "Request: " << std::endl;
        std::cout << std::setw(4) << incomingJsonData << std::endl;

        std::cout << std::setw(4) << "Result: " << std::endl;
        std::cout << std::setw(4) << incomingJsonData["response"] << std::endl;

        std::string result = incomingJsonData.dump();
        std::cout << "result: " << result << std::endl;

         return result;

        } catch (std::exception& e) {
                std::cerr << e.what() << std::endl;
                return "1";
        } catch (...) {
                std::cerr << "unknown error" << std::endl;
                return "1";
        }
}

std::string calculateConvertibleBonds(std::string data){
        try {

                json jData = json::parse(data);
                std::cout << std::endl;

                Option::Type type(Option::Put);
                Real underlying = jData["request"]["underlying"];
                Real spreadRate = jData["request"]["spreadRate"];

                Spread dividendYield = jData["request"]["dividendYield"];
                Rate riskFreeRate = jData["request"]["riskFreeRate"];
                Volatility volatility =jData["request"]["volatility"];

                Integer settlementDays = jData["request"]["settlementDays"];
                Integer length = jData["request"]["length"];
                Real redemption = jData["request"]["redemption"];
                Real conversionRatio = redemption/underlying; // at the money

                // set up dates/schedules
                Calendar calendar = TARGET();
                Date today = calendar.adjust(Date::todaysDate());

                Settings::instance().evaluationDate() = today;
                Date settlementDate = calendar.advance(today, settlementDays, Days);
                Date exerciseDate = calendar.advance(settlementDate, length, Years);
                Date issueDate = calendar.advance(exerciseDate, -length, Years);

                BusinessDayConvention convention = ModifiedFollowing;

                Frequency frequency = Annual;

                Schedule schedule(issueDate, exerciseDate,
                                Period(frequency), calendar,
                                convention, convention,
                                DateGeneration::Backward, false);

                DividendSchedule dividends;
                CallabilitySchedule callability;

                std::vector<Real> coupons(1, 0.05);

                DayCounter bondDayCount = Thirty360(Thirty360::BondBasis);

                Integer callLength[] = {
                        jData["request"]["calls"]["callLength"]["1"].get<int>(),
                        jData["request"]["calls"]["callLength"]["2"].get<int>()
                };
                Integer putLength[] = {
                        jData["request"]["puts"]["putLength"]["1"].get<int>()
                };

                Real callPrices[] = {
                        jData["request"]["calls"]["callPrices"]["1"].get<double>(),
                        jData["request"]["calls"]["callPrices"]["2"].get<double>()
                };
                Real putPrices[]= {
                        jData["request"]["puts"]["putPrices"]["1"].get<double>()
                };

                // Load call schedules
                for (Size i=0; i<LENGTH(callLength); i++) {
                callability.push_back(
                        ext::make_shared<SoftCallability>(Bond::Price(callPrices[i],
                                                                        Bond::Price::Clean),
                                                        schedule.date(callLength[i]),
                                                        1.20));
                }

                for (Size j=0; j<LENGTH(putLength); j++) {
                callability.push_back(
                        ext::make_shared<Callability>(Bond::Price(putPrices[j],
                                                                Bond::Price::Clean),
                                                        Callability::Put,
                                                        schedule.date(putLength[j])));
                }

                // Assume dividends are paid every 6 months.
                for (Date d = today + 6*Months; d < exerciseDate; d += 6*Months) {
                dividends.push_back(
                        ext::shared_ptr<Dividend>(new FixedDividend(1.0, d)));
                }

                DayCounter dayCounter = Actual365Fixed();
                Time maturity = dayCounter.yearFraction(settlementDate,
                                                        exerciseDate);

                std::cout << "option type = "  << type << std::endl;
                std::cout << "Time to maturity = "        << maturity
                        << std::endl;
                std::cout << "Underlying price = "        << underlying
                        << std::endl;
                std::cout << "Risk-free interest rate = " << io::rate(riskFreeRate)
                        << std::endl;
                std::cout << "Dividend yield = " << io::rate(dividendYield)
                        << std::endl;
                std::cout << "Volatility = " << io::volatility(volatility)
                        << std::endl;
                std::cout << std::endl;

                std::string method;
                std::cout << std::endl ;

                // write column headings
                Size widths[] = { 35, 14, 14 };
                Size totalWidth = widths[0] + widths[1] + widths[2];
                std::string rule(totalWidth, '-'), dblrule(totalWidth, '=');

                std::cout << dblrule << std::endl;
                std::cout << "Tsiveriotis-Fernandes method" << std::endl;
                std::cout << dblrule << std::endl;
                std::cout << std::setw(widths[0]) << std::left << "Tree type"
                        << std::setw(widths[1]) << std::left << "European"
                        << std::setw(widths[1]) << std::left << "American"
                        << std::endl;

                std::cout << rule << std::endl;

                ext::shared_ptr<Exercise> exercise(
                                                new EuropeanExercise(exerciseDate));
                ext::shared_ptr<Exercise> amExercise(
                                                new AmericanExercise(settlementDate,
                                                                exerciseDate));

                Handle<Quote> underlyingH(
                ext::shared_ptr<Quote>(new SimpleQuote(underlying)));

                Handle<YieldTermStructure> flatTermStructure(
                ext::shared_ptr<YieldTermStructure>(
                        new FlatForward(settlementDate, riskFreeRate, dayCounter)));

                Handle<YieldTermStructure> flatDividendTS(
                ext::shared_ptr<YieldTermStructure>(
                        new FlatForward(settlementDate, dividendYield, dayCounter)));

                Handle<BlackVolTermStructure> flatVolTS(
                ext::shared_ptr<BlackVolTermStructure>(
                        new BlackConstantVol(settlementDate, calendar,
                                        volatility, dayCounter)));

                ext::shared_ptr<BlackScholesMertonProcess> stochasticProcess(
                                new BlackScholesMertonProcess(underlyingH,
                                                                flatDividendTS,
                                                                flatTermStructure,
                                                                flatVolTS));

                Size timeSteps = jData["request"]["timeSteps"].get<int>();

                Handle<Quote> creditSpread(
                        ext::shared_ptr<Quote>(new SimpleQuote(spreadRate)));

                ext::shared_ptr<Quote> rate(new SimpleQuote(riskFreeRate));

                Handle<YieldTermStructure> discountCurve(
                        ext::shared_ptr<YieldTermStructure>(
                        new FlatForward(today, Handle<Quote>(rate), dayCounter)));

                ext::shared_ptr<PricingEngine> engine(
                        new BinomialConvertibleEngine<JarrowRudd>(stochasticProcess,
                                                                timeSteps));

                ConvertibleFixedCouponBond europeanBond(
                                exercise, conversionRatio, dividends, callability,
                                creditSpread, issueDate, settlementDays,
                                coupons, bondDayCount, schedule, redemption);
                europeanBond.setPricingEngine(engine);

                ConvertibleFixedCouponBond americanBond(
                                amExercise, conversionRatio, dividends, callability,
                                creditSpread, issueDate, settlementDays,
                                coupons, bondDayCount, schedule, redemption);
                americanBond.setPricingEngine(engine);

                method = "Jarrow-Rudd";
                europeanBond.setPricingEngine(ext::shared_ptr<PricingEngine>(
                        new BinomialConvertibleEngine<JarrowRudd>(stochasticProcess,
                                                                timeSteps)));
                americanBond.setPricingEngine(ext::shared_ptr<PricingEngine>(
                        new BinomialConvertibleEngine<JarrowRudd>(stochasticProcess,
                                                                timeSteps)));
                std::cout << std::setw(widths[0]) << std::left << method
                        << std::fixed
                        << std::setw(widths[1]) << std::left << europeanBond.NPV()
                        << std::setw(widths[2]) << std::left << americanBond.NPV()
                        << std::endl;

                jData["response"]["Tsiveriotis-Fernandes method"]["treeType"]["Jarrow-Rudd"]["American"]["NPV"] = americanBond.NPV();
                jData["response"]["Tsiveriotis-Fernandes method"]["treeType"]["Jarrow-Rudd"]["European"]["NPV"] = europeanBond.NPV();

                method = "Cox-Ross-Rubinstein";
                europeanBond.setPricingEngine(ext::shared_ptr<PricingEngine>(
                new BinomialConvertibleEngine<CoxRossRubinstein>(stochasticProcess,
                                                                timeSteps)));
                americanBond.setPricingEngine(ext::shared_ptr<PricingEngine>(
                new BinomialConvertibleEngine<CoxRossRubinstein>(stochasticProcess,
                                                                timeSteps)));
                std::cout << std::setw(widths[0]) << std::left << method
                        << std::fixed
                        << std::setw(widths[1]) << std::left << europeanBond.NPV()
                        << std::setw(widths[2]) << std::left << americanBond.NPV()
                        << std::endl;
                jData["response"]["Tsiveriotis-Fernandes method"]["treeType"]["Cox-Ross-Rubinstein"]["American"]["NPV"] = americanBond.NPV();
                jData["response"]["Tsiveriotis-Fernandes method"]["treeType"]["Cox-Ross-Rubinstein"]["European"]["NPV"] = europeanBond.NPV();

                method = "Additive equiprobabilities";
                europeanBond.setPricingEngine(ext::shared_ptr<PricingEngine>(
                        new BinomialConvertibleEngine<AdditiveEQPBinomialTree>(
                                                                stochasticProcess,
                                                                timeSteps)));
                americanBond.setPricingEngine(ext::shared_ptr<PricingEngine>(
                        new BinomialConvertibleEngine<AdditiveEQPBinomialTree>(
                                                                stochasticProcess,
                                                                timeSteps)));
                std::cout << std::setw(widths[0]) << std::left << method
                        << std::fixed
                        << std::setw(widths[1]) << std::left << europeanBond.NPV()
                        << std::setw(widths[2]) << std::left << americanBond.NPV()
                        << std::endl;

                jData["response"]["Tsiveriotis-Fernandes method"]["treeType"]["Additive equiprobabilities"]["American"]["NPV"] = americanBond.NPV();
                jData["response"]["Tsiveriotis-Fernandes method"]["treeType"]["Additive equiprobabilities"]["European"]["NPV"] = europeanBond.NPV();

                method = "Trigeorgis";
                europeanBond.setPricingEngine(ext::shared_ptr<PricingEngine>(
                        new BinomialConvertibleEngine<Trigeorgis>(stochasticProcess,
                                                                timeSteps)));
                americanBond.setPricingEngine(ext::shared_ptr<PricingEngine>(
                        new BinomialConvertibleEngine<Trigeorgis>(stochasticProcess,
                                                                timeSteps)));
                std::cout << std::setw(widths[0]) << std::left << method
                        << std::fixed
                        << std::setw(widths[1]) << std::left << europeanBond.NPV()
                        << std::setw(widths[2]) << std::left << americanBond.NPV()
                        << std::endl;

                jData["response"]["Tsiveriotis-Fernandes method"]["treeType"]["Trigeorgis"]["American"]["NPV"] = americanBond.NPV();
                jData["response"]["Tsiveriotis-Fernandes method"]["treeType"]["Trigeorgis"]["European"]["NPV"] = europeanBond.NPV();

                method = "Tian";
                europeanBond.setPricingEngine(ext::shared_ptr<PricingEngine>(
                                new BinomialConvertibleEngine<Tian>(stochasticProcess,
                                                                timeSteps)));
                americanBond.setPricingEngine(ext::shared_ptr<PricingEngine>(
                                new BinomialConvertibleEngine<Tian>(stochasticProcess,
                                                                timeSteps)));
                std::cout << std::setw(widths[0]) << std::left << method
                        << std::fixed
                        << std::setw(widths[1]) << std::left << europeanBond.NPV()
                        << std::setw(widths[2]) << std::left << americanBond.NPV()
                        << std::endl;

                jData["response"]["Tsiveriotis-Fernandes method"]["treeType"]["Tian"]["American"]["NPV"] = americanBond.NPV();
                jData["response"]["Tsiveriotis-Fernandes method"]["treeType"]["Tian"]["European"]["NPV"] = europeanBond.NPV();

                method = "Leisen-Reimer";
                europeanBond.setPricingEngine(ext::shared_ptr<PricingEngine>(
                        new BinomialConvertibleEngine<LeisenReimer>(stochasticProcess,
                                                                timeSteps)));
                americanBond.setPricingEngine(ext::shared_ptr<PricingEngine>(
                        new BinomialConvertibleEngine<LeisenReimer>(stochasticProcess,
                                                                timeSteps)));
                std::cout << std::setw(widths[0]) << std::left << method
                        << std::fixed
                        << std::setw(widths[1]) << std::left << europeanBond.NPV()
                        << std::setw(widths[2]) << std::left << americanBond.NPV()
                        << std::endl;

                jData["response"]["Tsiveriotis-Fernandes method"]["treeType"]["Leisen-Reimer"]["American"]["NPV"] = americanBond.NPV();
                jData["response"]["Tsiveriotis-Fernandes method"]["treeType"]["Leisen-Reimer"]["European"]["NPV"] = europeanBond.NPV();

                method = "Joshi";
                europeanBond.setPricingEngine(ext::shared_ptr<PricingEngine>(
                        new BinomialConvertibleEngine<Joshi4>(stochasticProcess,
                                                                timeSteps)));
                americanBond.setPricingEngine(ext::shared_ptr<PricingEngine>(
                        new BinomialConvertibleEngine<Joshi4>(stochasticProcess,
                                                                timeSteps)));
                std::cout << std::setw(widths[0]) << std::left << method
                        << std::fixed
                        << std::setw(widths[1]) << std::left << europeanBond.NPV()
                        << std::setw(widths[2]) << std::left << americanBond.NPV()
                        << std::endl;

                jData["response"]["Tsiveriotis-Fernandes method"]["treeType"]["Joshi"]["American"]["NPV"] = americanBond.NPV();
                jData["response"]["Tsiveriotis-Fernandes method"]["treeType"]["Joshi"]["European"]["NPV"] = europeanBond.NPV();

                std::cout << dblrule << std::endl;
                std::cout << "result: " << std::setw(4) << jData["response"] << std::endl;
                std::string result = jData.dump();
                return result;
        } catch (std::exception& e) {
                std::cerr << e.what() << std::endl;
                return "1";
        } catch (...) {
                std::cerr << "unknown error" << std::endl;
                return "1";
        }
};

std::string calculateCVAIRS(std::string data){
try {

        json jData = json::parse(data);

        std::cout << std::endl;

        Calendar calendar = TARGET();
        Date todaysDate(DateParser::parseISO( jData["request"]["todaysDate"].get<std::string>()));
        // must be a business day
        todaysDate = calendar.adjust(todaysDate);

        Settings::instance().evaluationDate() = todaysDate;

        ext::shared_ptr<IborIndex>  yieldIndx(new Euribor3M());
        Size tenorsSwapMkt[] = {5, 10, 15, 20, 25, 30};

        // rates ignoring counterparty risk:
        Rate ratesSwapmkt[] = {.03249, .04074, .04463, .04675, .04775, .04811};

        std::vector<ext::shared_ptr<RateHelper> > swapHelpers;
        for(Size i=0; i<sizeof(tenorsSwapMkt)/sizeof(Size); i++)
        swapHelpers.push_back(ext::make_shared<SwapRateHelper>(
                Handle<Quote>(ext::shared_ptr<Quote>(
                                new SimpleQuote(ratesSwapmkt[i]))),
                tenorsSwapMkt[i] * Years,
                TARGET(),
                Quarterly,
                ModifiedFollowing,
                ActualActual(ActualActual::ISDA),
                yieldIndx));

        ext::shared_ptr<YieldTermStructure> swapTS(
        new PiecewiseYieldCurve<Discount,LogLinear>(
        2, TARGET(), swapHelpers, ActualActual(ActualActual::ISDA)));
        swapTS->enableExtrapolation();

        ext::shared_ptr<PricingEngine> riskFreeEngine(
        ext::make_shared<DiscountingSwapEngine>(
                Handle<YieldTermStructure>(swapTS)));

        std::vector<Handle<DefaultProbabilityTermStructure> >
        defaultIntensityTS;

        Size defaultTenors[] = {0, 12, 36, 60, 84, 120, 180, 240, 300,
                                360};// months
        // Three risk levels:
        Real intensitiesLow[] = {0.0036, 0.0036, 0.0065, 0.0099, 0.0111,
                                0.0177, 0.0177, 0.0177, 0.0177, 0.0177,
                                0.0177};
        Real intensitiesMedium[] = {0.0202, 0.0202, 0.0231, 0.0266, 0.0278,
                                0.0349, 0.0349, 0.0349, 0.0349, 0.0349,
                                0.0349};
        Real intensitiesHigh[] = {0.0534, 0.0534, 0.0564, 0.06, 0.0614, 0.0696,
                                0.0696, 0.0696, 0.0696, 0.0696, 0.0696};
        // Recovery rates:
        Real ctptyRRLow = 0.4, ctptyRRMedium = 0.35, ctptyRRHigh = 0.3;

        std::vector<Date> defaultTSDates;
        std::vector<Real> intesitiesVLow, intesitiesVMedium, intesitiesVHigh;

        for(Size i=0; i<sizeof(defaultTenors)/sizeof(Size); i++) {
        defaultTSDates.push_back(TARGET().advance(todaysDate,
                Period(defaultTenors[i], Months)));
        intesitiesVLow.push_back(intensitiesLow[i]);
        intesitiesVMedium.push_back(intensitiesMedium[i]);
        intesitiesVHigh.push_back(intensitiesHigh[i]);
        }

        defaultIntensityTS.emplace_back(ext::shared_ptr<DefaultProbabilityTermStructure>(
        new InterpolatedHazardRateCurve<BackwardFlat>(defaultTSDates, intesitiesVLow,
                                                        Actual360(), TARGET())));
        defaultIntensityTS.emplace_back(ext::shared_ptr<DefaultProbabilityTermStructure>(
        new InterpolatedHazardRateCurve<BackwardFlat>(defaultTSDates, intesitiesVMedium,
                                                        Actual360(), TARGET())));
        defaultIntensityTS.emplace_back(ext::shared_ptr<DefaultProbabilityTermStructure>(
        new InterpolatedHazardRateCurve<BackwardFlat>(defaultTSDates, intesitiesVHigh,
                                                        Actual360(), TARGET())));

        Volatility blackVol = 0.15;
        ext::shared_ptr<PricingEngine> ctptySwapCvaLow =
        ext::make_shared<CounterpartyAdjSwapEngine>(
                Handle<YieldTermStructure>(swapTS),
                blackVol,
                defaultIntensityTS[0],
                ctptyRRLow
                );

        ext::shared_ptr<PricingEngine> ctptySwapCvaMedium =
        ext::make_shared<CounterpartyAdjSwapEngine>(
                Handle<YieldTermStructure>(swapTS),
                blackVol,
                defaultIntensityTS[1],
                ctptyRRMedium);
        ext::shared_ptr<PricingEngine> ctptySwapCvaHigh =
        ext::make_shared<CounterpartyAdjSwapEngine>(
                Handle<YieldTermStructure>(swapTS),
                blackVol,
                defaultIntensityTS[2],
                ctptyRRHigh);

        defaultIntensityTS[0]->enableExtrapolation();
        defaultIntensityTS[1]->enableExtrapolation();
        defaultIntensityTS[2]->enableExtrapolation();

        /// SWAP RISKY REPRICE----------------------------------------------

        // fixed leg
        Frequency fixedLegFrequency = Quarterly;
        BusinessDayConvention fixedLegConvention = ModifiedFollowing;
        DayCounter fixedLegDayCounter = ActualActual(ActualActual::ISDA);
        DayCounter floatingLegDayCounter = ActualActual(ActualActual::ISDA);

        QuantLib::VanillaSwap::Type swapType = QuantLib::VanillaSwap::Payer;
        ext::shared_ptr<IborIndex> yieldIndxS(
        new Euribor3M(Handle<YieldTermStructure>(swapTS)));
        std::vector<VanillaSwap> riskySwaps;
        for(Size i=0; i<sizeof(tenorsSwapMkt)/sizeof(Size); i++)
        riskySwaps.push_back(MakeVanillaSwap(tenorsSwapMkt[i]*Years,
                yieldIndxS,
                ratesSwapmkt[i],
                0*Days)
        .withSettlementDays(2)
        .withFixedLegDayCount(fixedLegDayCounter)
        .withFixedLegTenor(Period(fixedLegFrequency))
        .withFixedLegConvention(fixedLegConvention)
        .withFixedLegTerminationDateConvention(fixedLegConvention)
        .withFixedLegCalendar(calendar)
        .withFloatingLegCalendar(calendar)
        .withNominal(100.)
        .withType(swapType));

        std::cout << "-- Correction in the contract fix rate in bp --" << std::endl;
        /* The paper plots correction to be substracted, here is printed
        with its sign
        */
        for(Size i=0; i<riskySwaps.size(); i++) {
            std::cout << std::fixed << std::setprecision(3);
            std::cout << std::setw(4);
            riskySwaps[i].setPricingEngine(riskFreeEngine);
            // should recover the input here:
            Real nonRiskyFair = riskySwaps[i].fairRate();
            std::cout << tenorsSwapMkt[i];
            std::cout << std::setw(5);

            std::cout << " | " << io::rate(nonRiskyFair);
            std::cout << std::fixed << std::setprecision(2);
            std::cout << std::setw(5);
            // Low Risk:
            riskySwaps[i].setPricingEngine(ctptySwapCvaLow);
            std::cout << " | " << std::setw(6)
                    << 10000.*(riskySwaps[i].fairRate() - nonRiskyFair);
            //cout << " | " << setw(6) << riskySwaps[i].NPV() ;

            // Medium Risk:
            riskySwaps[i].setPricingEngine(ctptySwapCvaMedium);
            std::cout << " | " << std::setw(6)
                    << 10000.*(riskySwaps[i].fairRate() - nonRiskyFair);
            //cout << " | " << setw(6) << riskySwaps[i].NPV() ;

            riskySwaps[i].setPricingEngine(ctptySwapCvaHigh);
            std::cout << " | " << std::setw(6)
                    << 10000.*(riskySwaps[i].fairRate() - nonRiskyFair);
            //cout << " | " << setw(6) << riskySwaps[i].NPV() ;

            std::cout << std::endl;
        }

        std::cout << std::endl;
        std::cout << "JDATA" << std::setw(4) << jData << std::endl;
        std::string result = jData.dump();
        return result;

    }

    catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
        return "1";
    }

    catch (...) {
        std::cerr << "unknown error" << std::endl;
        return "1";
    }
}


#ifndef ASLAM_CAMERAS_EQUI_DISTORTION_HPP
#define ASLAM_CAMERAS_EQUI_DISTORTION_HPP

#include <eigen3/Eigen/Dense>
#include <boost/serialization/nvp.hpp>
#include "StaticAssert.hpp"
#include <sm/PropertyTree.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/version.hpp>
#include <sm/boost/serialization.hpp>

namespace aslam {
namespace cameras {

/**
 * \class EquidistantDistortion
 * \brief An implementation of the equidistant distortion model for pinhole cameras.
 *
 * See "A Generic Camera Model and Calibration Method for Conventional, Wide-Angle, and Fish-Eye Lenses" by Juho Kannala and Sami S. Brandt for further information
 *
 *
 * The usual model of a pinhole camera follows these steps:
 *   - Transformation: Transform the point into a coordinate frame associated with the camera
 *   - Normalization:  Project the point onto the normalized image plane: \f$\mathbf y := \left[ x/z,y/z\right] \f$
 *   - Distortion:     apply a nonlinear transformation to \f$y\f$ to account for distortions caused by the optics
 *   - Projection:     Project the point into the image using a standard \f$3 \time 3\f$ projection matrix
 *
 * This class represents a standard implementation of the distortion block. The function "distort" applies this nonlinear transformation.
 * The function "undistort" applies the inverse transformation. Note that the inverse transformation in this case is not avaialable in
 * closed form and so it is computed iteratively.
 *
 */
class EquidistantDistortion {
 public:

  enum {
    IntrinsicsDimension = 4
  };
  enum {
    DesignVariableDimension = IntrinsicsDimension
  };

  /// \brief The default constructor sets all values to zero.
  EquidistantDistortion();

  /// \brief A constructor that initializes all values.
  EquidistantDistortion(double k1, double k2, double k3, double k4);

  /// \brief initialize from a property tree
  EquidistantDistortion(const sm::PropertyTree & config);

  virtual ~EquidistantDistortion();

  /**
   * \brief Apply distortion to a point in the normalized image plane
   *
   * @param y The point in the normalized image plane. After the function, this point is distorted.
   */
  template<typename DERIVED_Y>
  void distort(const Eigen::MatrixBase<DERIVED_Y> & y) const;

  /**
   *
   * \brief Apply distortion to a point in the normalized image plane
   *
   * @param y The point in the normalized image plane. After the function, this point is distorted.
   * @param outJy The Jacobian of the distortion function with respect to small changes in the input point.
   */
  template<typename DERIVED_Y, typename DERIVED_JY>
  void distort(const Eigen::MatrixBase<DERIVED_Y> & y,
               const Eigen::MatrixBase<DERIVED_JY> & outJy) const;

  /**
   * \brief Apply undistortion to recover a point in the normalized image plane.
   *
   * @param y The distorted point. After the function, this point is in the normalized image plane.
   */
  template<typename DERIVED>
  void undistort(const Eigen::MatrixBase<DERIVED> & y) const;

  /**
   * \brief Apply undistortion to recover a point in the normalized image plane.
   *
   * @param y The distorted point. After the function, this point is in the normalized image plane.
   * @param outJy The Jacobian of the undistortion function with respect to small changes in the input point.
   */
  template<typename DERIVED, typename DERIVED_JY>
  void undistort(const Eigen::MatrixBase<DERIVED> & y,
                 const Eigen::MatrixBase<DERIVED_JY> & outJy) const;

  /**
   * \brief Apply distortion to the point and provide the Jacobian of the distortion with respect to small changes in the distortion parameters
   *
   * @param imageY the point in the normalized image plane.
   * @param outJd  the Jacobian of the distortion with respect to small changes in the distortion parameters.
   */
  template<typename DERIVED_Y, typename DERIVED_JD>
  void distortParameterJacobian(
      const Eigen::MatrixBase<DERIVED_Y> & imageY,
      const Eigen::MatrixBase<DERIVED_JD> & outJd) const;

  /**
   * \brief A function for compatibility with the aslam backend. This implements an update of the distortion parameter.
   *
   * @param v A double array representing the update vector.
   */
  void update(const double * v);

  /**
   * \brief A function for compatibility with the aslam backend.
   *
   * @param v The number of parameters expected by the update equation. This should also define the number of columns in the matrix returned by distortParameterJacobian.
   */
  int minimalDimensions() const;

  /**
   * \brief A function for compatibility with the aslam backend.
   *
   * @param P This matrix is resized and filled with parameters representing the full state of the distortion.
   */
  void getParameters(Eigen::MatrixXd & P) const;

  /**
   * \brief A function for compatibility with the aslam backend.
   *
   * @param P The full state of the distortion class is set from the matrix of parameters.
   */
  void setParameters(const Eigen::MatrixXd & P);

  Eigen::Vector2i parameterSize() const;

  /// \brief the first radial distortion parameter
  double k1() {
    return _k1;
  }
  /// \brief the second radial distortion parameter
  double k2() {
    return _k2;
  }
  /// \brief the first tangential distortion parameter
  double k3() {
    return _k3;
  }
  /// \brief the second tangential distortion parameter
  double k4() {
    return _k4;
  }

  /// \brief Compatibility with boost::serialization.
  enum {
    CLASS_SERIALIZATION_VERSION = 0
  };BOOST_SERIALIZATION_SPLIT_MEMBER();

  template<class Archive>
  void load(Archive & ar, const unsigned int version);

  template<class Archive>
  void save(Archive & ar, const unsigned int version) const;

  bool isBinaryEqual(const EquidistantDistortion & rhs) const;

  static EquidistantDistortion getTestDistortion();

  void clear();

  /// \brief the first distortion parameter
  double _k1;
  /// \brief the second distortion parameter
  double _k2;
  /// \brief the third distortion parameter
  double _k3;
  /// \brief the forth distortion parameter
  double _k4;

};

}  // namespace cameras
}  // namespace aslam

#include "implementation/EquidistantDistortion.hpp"

SM_BOOST_CLASS_VERSION (aslam::cameras::EquidistantDistortion);

#endif /* ASLAM_CAMERAS_EQUI_DISTORTION_HPP */


#ifndef INCLUDED_DENSITY_VISUALIZATION_HPP
#define INCLUDED_DENSITY_VISUALIZATION_HPP

#include <Danvil/Color.h>
#include <Slimage/Slimage.hpp>
#include <Eigen/Dense>
#include <vector>

namespace density
{

	inline Eigen::Vector3f DensityColor(float x, float a, float b)
	{
		static auto cm = Danvil::ContinuousIntervalColorMapping<float, float>::Factor_Black_Blue_Red_Yellow_White();
		cm.setRange(a, b);
		Danvil::Colorf color = cm(x);
		return {color.r,color.g,color.b};
	}

	inline Eigen::Vector3f DeltaDensityColor(float x, float a)
	{
		static auto cm = Danvil::ContinuousIntervalColorMapping<float, float>::Factor_MinusPlus();
		cm.setRange(-a, +a);
		Danvil::Colorf color = cm(x);
		return {color.r,color.g,color.b};
	}

	slimage::Image3ub PlotDensity(const Eigen::MatrixXf& d, float a, float b);

	slimage::Image3ub PlotDensity(const Eigen::MatrixXf& d);

	slimage::Image3ub PlotDeltaDensity(const Eigen::MatrixXf& dd, float a);

	slimage::Image3ub PlotDeltaDensity(const Eigen::MatrixXf& dd);

	slimage::Image3ub PlotDeltaDensity(const Eigen::MatrixXf& actual, const Eigen::MatrixXf& reference);

}

#endif


#include <bits/stdc++.h>
#include <boost/tokenizer.hpp>

struct FieldSpec {
  std::string field_name;
  std::vector<std::pair<uint, uint>> ranges;
  uint field_id;

  bool is_value_ok(uint value) {
    for (auto &[a, b]: ranges)
      if (value >= a && value <= b)
        return true;
    return false;
  }
};
bool operator==(const FieldSpec &f1, const FieldSpec &f2) {
  return f1.field_name == f2.field_name;
}
bool operator<(const FieldSpec &f1, const FieldSpec &f2) {
  return f1.field_name < f2.field_name;
}

std::vector<FieldSpec> fields;

using Ticket = std::vector<uint>;
Ticket my_ticket;
std::vector<Ticket> tickets;
std::vector<Ticket> valid_tickets;

void part1() {
  uint error = 0;
  for (auto &t: tickets) {
    bool is_valid = true;
    for (auto v: t) {
      bool valid = false;
      for (auto &f: fields) {
        valid = f.is_value_ok(v);
        if (valid)
          break;
      }

      if (!valid) {
        error += v;
        is_valid = false;
      }
    }

    if (is_valid)
      valid_tickets.push_back(t);
  }

  std::cout << "Part 1 : " << error << std::endl;
}

using Set = std::set<int>;
void eliminate() {
  const uint Nf = fields.size();

  std::vector<bool> def(Nf, false);
  std::vector<std::vector<bool>> valid(Nf, def);

  // 1- Initialize
  std::vector<int> count_field;

  auto update_counts = [&]() {
    count_field.clear();
    count_field.resize(Nf, 0);

    for (uint i=0; i < Nf; ++i) {
      for (uint j=0; j < Nf; ++j) {
        if (valid[i][j])
          count_field[i]++;
      }
    }
  };

  // 2- Filling validity matrix
  for (uint fi=0; fi < Nf; ++fi) {
    FieldSpec &f = fields[fi];

    for (uint pos=0; pos < Nf; ++pos) {
      bool is_valid = true;
      for (auto t: valid_tickets) {
        if (!f.is_value_ok(t[pos])) {
          is_valid = false;
          break;
        }
      }

      valid[fi][pos] = is_valid;
    }
  }

  auto done = [&]() {
    bool res = true;
    for (auto c: count_field)
      if (c!=0)
        return false;

    return true;
  };

  // And iterating on solutions
  update_counts();
  while (!done()) {
    int idf = -1;
    // Finding the field that is alone
    for (int i=0; i < Nf; ++i) {
      if (count_field[i] == 1) {
        idf = i;
        break;
      }
    }

    // Finding its position
    int pos_id;
    for (int j=0; j < Nf; ++j) {
      if (valid[idf][j]) {
        pos_id = j;
        break;
      }
    }

    // Associating then removing it from the table
    fields[idf].field_id = pos_id;

    for (int i=0; i < Nf; ++i) {
      valid[idf][i] = false;
      valid[i][pos_id] = false;
    }

    //std::cout << "Field #" << pos_id << " is " << fields[idf].field_name << std::endl;
    // And looping
    update_counts();
  }
}

void part2() {
  eliminate();

  uint64_t res = 1;
  for (auto f: fields) {
    if (f.field_name.find("departure") != std::string::npos) {
      res *= my_ticket[f.field_id];
    }
  }

  std::cout << "Part 2 : " << res << std::endl;
}

int mode = 0;

std::regex field_re("([a-z\\ ]+):(.*)");
std::regex range_re("([0-9]+)-([0-9]+)");

void read_field_spec(std::string line) {
  std::smatch match;
  std::regex_search(line, match, field_re);
  FieldSpec field;
  field.field_name = match[1];
  std::string ranges = match[2];
  std::smatch range_match;

  while(std::regex_search(ranges, range_match, range_re)) {
    uint min_val = std::stoi(range_match[1]);
    uint max_val = std::stoi(range_match[2]);
    field.ranges.push_back(std::make_pair(min_val, max_val));
    ranges = range_match.suffix();
  }

  fields.push_back(field);
}

void read_ticket(std::string line, bool mine) {
  boost::char_separator<char> sep{","};
  boost::tokenizer tokenizer{line, sep};
  Ticket ticket;
  for (const auto &t: tokenizer)
    ticket.push_back(std::stoi(t));

  if (mine)
    my_ticket = ticket;
  else
    tickets.push_back(ticket);
}

int main(int argc, char **argv) {
  std::ifstream f_in;
  f_in.open("16.in");

  while (!f_in.eof()) {
    std::string line;
    std::getline(f_in, line);

    if (line == "") {
      mode++;
      if (mode > 0)
        std::getline(f_in, line);
    }
    else {
      switch(mode) {
        case 0: read_field_spec(line);    break;
        case 1: read_ticket(line, true);  break;
        case 2: read_ticket(line, false); break;
      }
    }
  }
  f_in.close();

  part1();
  part2();
  return 0;
}


#include <algorithm>
#include <memory>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <climits>
#include <numeric>

#include <Eigen/Dense>

#undef N_DEBUG
#include <assert.h>

#define loop(x,n) for(std::size_t (x) = 0; (x) < (n); ++(x))

using namespace std;

using UInt = uint64_t;
using Int = int64_t;
using Vector3d = Eigen::Matrix<double, 3, 1>;

struct Asteroid
{
  using Ptr = std::shared_ptr<Asteroid>;
  using ConstPtr = std::shared_ptr<const Asteroid>;

  EIGEN_MAKE_ALIGNED_OPERATOR_NEW;

  Asteroid()  {}
  Asteroid(Vector3d pos, Vector3d vel)
    : position(pos)
    , velocity(vel)
  {}

  Vector3d position;
  Vector3d velocity;
};

double getMinDistance(Asteroid::ConstPtr a, Asteroid::ConstPtr b)
{
  const auto w = a->position - b->position;
  const auto v = a->velocity - b->velocity;
  const auto t_cpa = -w.dot(v) / v.squaredNorm();
  const auto p_a = a->position + t_cpa * a->velocity;
  const auto p_b = b->position + t_cpa * b->velocity;
  return (p_a - p_b).norm();
}

double getMinDistanceWithin(Asteroid::ConstPtr a, Asteroid::ConstPtr b, double t_min, double t_max)
{
  const auto w = a->position - b->position;
  const auto v = a->velocity - b->velocity;
  const auto t_cpa = -w.dot(v) / v.squaredNorm();

  double t;
  if (t_cpa < t_min)
    t = t_min;
  else if (t_cpa > t_max)
    t = t_max;
  else
    t = t_cpa;

  const auto p_a = a->position + t * a->velocity;
  const auto p_b = b->position + t * b->velocity;
  return (p_a - p_b).norm();
}

struct Edge
{
  Edge(size_t first, size_t second, double weight)
    : first_vertex(first)
    , second_vertex(second)
    , weight(weight)
  {}
  size_t first_vertex;
  size_t second_vertex;
  double weight;

  bool operator <(const Edge& other) const
  {
    if (weight != other.weight)
      return weight < other.weight;
    if (first_vertex != other.first_vertex)
      return first_vertex < other.first_vertex;
    return second_vertex < other.second_vertex;
  }
  bool contains(size_t vertex) const  { return first_vertex == vertex || second_vertex == vertex; }
  size_t getOther(size_t vertex) const
  {
    if (first_vertex == vertex)
      return second_vertex;
    return first_vertex;
  }
};

struct Cluster
{
  Cluster() {}
  Cluster(const auto& asteroids, auto velocity)
    : asteroids(asteroids)
    , velocity(velocity)
  {}
  Cluster(const auto& asteroid)
    : asteroids({asteroid})
    , velocity(asteroid->velocity)
  {}

  double getMaxJumpDistance(Asteroid::ConstPtr start, Asteroid::ConstPtr end) const
  {
    const auto s = find(asteroids.cbegin(), asteroids.cend(), start);
    if (s == asteroids.cend())
      throw (int)1;

    size_t index_start = std::distance(asteroids.cbegin(), s);

    const auto e = find(asteroids.cbegin(), asteroids.cend(), end);
    if (e == asteroids.cend())
      throw (int)2;

    size_t index_end = std::distance(asteroids.cbegin(), e);

    auto unexplored = edges;
    set<size_t> explored;
    explored.insert(index_start);
    double max_jump = 0.0;
    size_t added = 0;
    do
    {
      for (auto it = unexplored.begin(); it != unexplored.end(); it++)
      {
        const auto first_it = explored.find(it->first_vertex);
        const auto second_it = explored.find(it->second_vertex);

        auto ex = explored.cend();
        if (first_it != explored.cend())
          ex = first_it;
        else if (second_it != explored.cend())
          ex = second_it;
        else
          continue;

        added = it->getOther(*ex);
        explored.insert(added);
        if (it->weight > max_jump)
          max_jump = it->weight;
        unexplored.erase(it);

        break;
      }
    }
    while (added != index_end);

    return sqrt(max_jump);
  }

  const vector<Asteroid::ConstPtr> getAllReachedAsteroids(Asteroid::ConstPtr start, double max_jump)
  {
    max_jump = max_jump*max_jump;

    const auto s = find(asteroids.cbegin(), asteroids.cend(), start);
    if (s == asteroids.cend())
      throw (int)3;

    vector<Asteroid::ConstPtr> reached({start});
    size_t index_start = std::distance(asteroids.cbegin(), s);

    vector<bool> explored(asteroids.size(), false);
    explored[index_start] = true;

    size_t added;
    do
    {
      added = asteroids.size();

      loop(ex, explored.size())
      {
        if (!explored[ex])
          continue;

        loop(unex, explored.size())
        {
          if (explored[unex])
            continue;

          if (getWeight(ex, unex) <= max_jump)
          {
            added = unex;
            explored[unex] = true;
            break;
          }

        }
        if (added != asteroids.size())
          break;

      }

      reached.push_back(asteroids[added]);

    }
    while (added < asteroids.size());

    return reached;
  }

  vector<Asteroid::Ptr> asteroids;
  Vector3d velocity;

  double getWeight(size_t first, size_t second) const
  {
    assert(first != second);
    const auto min_index = min(first, second);
    const auto max_index = max(first, second);
    return weights[min_index][max_index-min_index-1];
  }
  void calcWeights()
  {
    weights.resize(asteroids.size() - 1);
    loop(ii, asteroids.size() - 1)
    {
      weights[ii].reserve(asteroids.size() - ii - 1);
      for (size_t jj = ii + 1; jj < asteroids.size(); ++jj)
      {
        weights[ii].push_back((asteroids[ii]->position - asteroids[jj]->position).squaredNorm());
        edges.emplace(ii, jj, weights[ii].back());
      }
    }
  }
  vector<vector<double>> weights;
  set<Edge> edges;
};

int main()
{
  size_t num_test_cases;
  cin >> num_test_cases;

  for (size_t i = 0; i < num_test_cases; i++)
  {
    size_t N, S;
    cin >> N >> S;

    vector<Asteroid::Ptr> asteroids;
    asteroids.reserve(N);

    loop(ii, N)
    {
      Vector3d pos;
      Vector3d vel;

      cin >> pos[0] >> pos[1] >> pos[2]
          >> vel[0] >> vel[1] >> vel[2];

      Asteroid a;
      a.position = pos;
      a.velocity = vel;
      asteroids.emplace_back(make_shared<Asteroid>(pos, vel));
    }

    // sort into clusters
    vector<Cluster> clusters;
    for (const auto& a : asteroids)
    {
      const auto it = std::find_if(clusters.begin(), clusters.end(), [&a](const vector<Cluster>::value_type& c){
          return c.velocity == a->velocity;});

      if (it == clusters.end())
      {
        clusters.emplace_back(a);
      }
      else
      {
        it->asteroids.push_back(a);
      }
    }

    //cout <<"Number of clusters: " <<clusters.size() <<endl;
    for (auto& a : clusters)
      a.calcWeights();

    double res = 0.0;
    if (clusters.size() == 1)
    {
      res = clusters.front().getMaxJumpDistance(asteroids[0], asteroids[1]);
      std::cout <<"Case #" <<(i+1) <<": "  <<setprecision(10) <<res <<endl;
    }
    else
    {
      if (asteroids[0]->velocity != asteroids[1]->velocity)
        res = getMinDistanceWithin(asteroids[0], asteroids[1], 0.0, S);
      else
        res = -1.0;

      std::cout <<"Case #" <<(i+1) <<": "  <<setprecision(10) <<res <<endl;
    }

  }

  return 0;
}


// Software License for MTL
//
// Copyright (c) 2007 The Trustees of Indiana University.
//               2008 Dresden University of Technology and the Trustees of Indiana University.
//               2010 SimuNova UG (haftungsbeschrÃ¤nkt), www.simunova.com.
// All rights reserved.
// Authors: Peter Gottschling and Andrew Lumsdaine
//
// This file is part of the Matrix Template Library
//
// See also license.mtl.txt in the distribution.

#include <iostream>
#include <boost/numeric/mtl/mtl.hpp>

using namespace std;

int main(int argc, char** argv)
{
    using namespace mtl;

    using mblock= matrix<double, dim<2, 2> >;
    using vblock= mtl::vector<double, dim<2> >;

    using mtype= matrix<mblock, sparse>;
    using vtype= mtl::vector<vblock>;

    mtype A(2, 3);
    {
	mat::inserter<mtype> ins(A);
	mblock mb;
	mb[0][0]= 1; mb[0][1]= 2;
	mb[1][0]= 3; mb[1][1]= 4;

	ins[0][0] << mb;

	mb[1][1]= 5;
	ins[1][1] << mb;

	// ins(0, 0) << mblock{{1, 2}, {3, 4}};
	// ins[1][1] << mblock{{3, 4}, {5, 6}};
    }
    // cout << "A = " << A;

    vtype x{vblock{1, 3}, vblock{1, 2}, vblock{9, 3}};
    cout << "x = " << x << endl;

    vtype y( A * x );
    cout << "y= " << y << endl;

    return 0;
}


/*
@copyright Louis Dionne 2014
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#include <boost/hana/identity.hpp>

#include <boost/hana/detail/assert.hpp>
#include <boost/hana/detail/minimal/orderable.hpp>
#include <boost/hana/functional.hpp>
#include <boost/hana/list/instance.hpp>
#include <boost/hana/logical/logical.hpp>
#include <boost/hana/orderable/laws.hpp>
using namespace boost::hana;

auto implies = infix([](auto p, auto q) {
    return or_(not_(p), q);
});

auto iff = infix([](auto p, auto q) {
    return and_(p ^implies^ q, q ^implies^ p);
});

auto check = [](auto x, auto y) {
    return less(x, y) ^iff^ less(identity(x), identity(y));
};

int main() {
    constexpr auto x = detail::minimal::orderable<>(1);
    constexpr auto y = detail::minimal::orderable<>(2);
    constexpr auto z = detail::minimal::orderable<>(3);

    BOOST_HANA_CONSTEXPR_ASSERT(
        all_of(ap(list(check), list(x, y, z), list(x, y, z)))
    );

    BOOST_HANA_CONSTEXPR_ASSERT(Orderable::laws::check(
        list(identity(x), identity(y), identity(z))
    ));
}


#include <boost/test/unit_test.hpp>
#include "functions/multi_matrix_reduction.hh"
#include <boost/mpl/distance.hpp>

BOOST_AUTO_TEST_CASE(multi_matrix_reduction_test) {
  using namespace manifolds;
  Reduction<ReduxPair<0, 1> > r;
  MultiMatrix<double, 3, 3, 1> m(0, 1, 2, 0, 1, 4, 1, 2, 9);
  BOOST_CHECK_EQUAL(r(m).Coeff(0), 10);
  Reduction<ReduxPair<1, 2> > r2;
  MultiMatrix<double, 1, 3> m2(0, 1, 2);
  MultiMatrix<double, 3, 1> m3(0, 1, 2);
  auto m4 = m2 * m3;
  static_assert(decltype(m4)::dimension<0>::value == 1,
                "Error conglomerating MultiMatrices' dimensions");
  static_assert(decltype(m4)::dimension<1>::value == 3,
                "Error conglomerating MultiMatrices' dimensions");
  static_assert(decltype(m4)::dimension<2>::value == 3,
                "Error conglomerating MultiMatrices' dimensions");
  static_assert(decltype(m4)::dimension<3>::value == 1,
                "Error conglomerating MultiMatrices' dimensions");
  BOOST_CHECK_EQUAL(r2(m4).Coeff(0, 0), 5);
  auto m5 = r2(m3 * m2);
  BOOST_CHECK_EQUAL(m5.Coeff(0, 0), 0);
  BOOST_CHECK_EQUAL(m5.Coeff(0, 1), 0);
  BOOST_CHECK_EQUAL(m5.Coeff(0, 2), 0);
  BOOST_CHECK_EQUAL(m5.Coeff(1, 0), 0);
  BOOST_CHECK_EQUAL(m5.Coeff(1, 1), 1);
  BOOST_CHECK_EQUAL(m5.Coeff(1, 2), 2);
  BOOST_CHECK_EQUAL(m5.Coeff(2, 0), 0);
  BOOST_CHECK_EQUAL(m5.Coeff(2, 1), 2);
  BOOST_CHECK_EQUAL(m5.Coeff(2, 2), 4);
}