<commit_before>#include <functional>
#include <future>
#include "kernel.h"
#include "raster.h"
#include "symboltable.h"
#include "ilwisoperation.h"
#include "pixeliterator.h"
#include "unarymath.h"
#include "unarymathoperations.h"

using namespace Ilwis;
using namespace BaseOperations;

REGISTER_OPERATION(Sine)

Sine::Sine(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "min1to1", sin)
{}
OperationImplementation *Sine::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Sine(metaid,expr);}

quint64 Sine::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/sin"), "sine", "min1to1");
    resource.addProperty("pin_1_desc", QString("input data source with a numerical domain; values are considered to be radians"));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain; values are between -1 and 1"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
REGISTER_OPERATION(Cosine)
Cosine::Cosine(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "min1to1", sin)
{}
OperationImplementation *Cosine::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Cosine(metaid,expr);}

quint64 Cosine::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/cos"), "cosine", "min1to1");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain; values are considered to be radians"));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain; values are between -1 and 1"));

    mastercatalog()->addItems({resource});
    return resource.id();
}

//----------------------------------------------------------
double tangent(double v){
    if ( std::abs(v) == M_PI / 2)
        return rUNDEF;
    return tan(v);
}

REGISTER_OPERATION(Tangent)
Tangent::Tangent(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", tangent)
{}
OperationImplementation *Tangent::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Tangent(metaid,expr);}

quint64 Tangent::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/tan"), "Tangent", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain; values are considered to be radians"));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain; "));

    mastercatalog()->addItems({resource});
    return resource.id();
}

//----------------------------------------------------------
double arcsine(double v){
    if ( v < -1 || v > 1)
        return rUNDEF;
    return asin(v);
}

REGISTER_OPERATION(Arcsine)

Arcsine::Arcsine(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", arcsine)
{}
OperationImplementation *Arcsine::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Arcsine(metaid,expr);}

quint64 Arcsine::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/asin"), "Arcsine", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain;with value between -1 and 1 "));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain; values are between pi/2 and -pi/2"));

    mastercatalog()->addItems({resource});
    return resource.id();
}

//----------------------------------------------------------
double arccosine(double v){
    if ( v < -1 || v > 1)
        return rUNDEF;
    return asin(v);
}

REGISTER_OPERATION(Arccosine)
Arccosine::Arccosine(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", arccosine)
{}
OperationImplementation *Arccosine::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Arccosine(metaid,expr);}

quint64 Arccosine::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/acos"), "Arccosine", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain with value between -1 and 1; "));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain; values are between 0 and pi"));

    mastercatalog()->addItems({resource});
    return resource.id();
}

//----------------------------------------------------------
REGISTER_OPERATION(ArcTangent)
ArcTangent::ArcTangent(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", atan)
{}
OperationImplementation *ArcTangent::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new ArcTangent(metaid,expr);}

quint64 ArcTangent::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/atan"), "ArcTangent", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain;with value between -pi/2 and pi/2 "));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain; values are between -1 and 1"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
double logten(double v){
    if ( v > 0)
        return log10(v);
    return rUNDEF;
}
REGISTER_OPERATION(Log10)
Log10::Log10(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", logten)
{}
OperationImplementation *Log10::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Log10(metaid,expr);}

quint64 Log10::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/log10"), "Log10", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain;with value larger than zero "));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
double naturallog(double v){
    if ( v > 0)
        return log(v);
    return rUNDEF;
}

REGISTER_OPERATION(NaturalLogarithm)
NaturalLogarithm::NaturalLogarithm(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", naturallog)
{}
OperationImplementation *NaturalLogarithm::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new NaturalLogarithm(metaid,expr);}

quint64 NaturalLogarithm::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/ln"), "Natural Logarithm", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain;with value larger than zero "));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------

double abs2(double v){
    if ( v == rUNDEF)
        return rUNDEF;
    return v;
}
REGISTER_OPERATION(Abs)
Abs::Abs(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", abs2)
{}
OperationImplementation *Abs::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Abs(metaid,expr);}

quint64 Abs::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/abs"), "Absolute value", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain"));
    resource.addProperty("pout_1_desc",QString("output data source with a positive numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}

//---------------------------------------------------------
//----------------------------------------------------------
double sqrt2(double v){
    if ( v < 0)
        return rUNDEF;
    return std::sqrt(v);
}
REGISTER_OPERATION(Sqrt)
Sqrt::Sqrt(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", sqrt2)
{}
OperationImplementation *Sqrt::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Sqrt(metaid,expr);}

quint64 Sqrt::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/sqrt"), "Absolute value", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a positive numerical domain (or 0)"));
    resource.addProperty("pout_1_desc",QString("output data source with a positive numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
REGISTER_OPERATION(Ceil)
Ceil::Ceil(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "integer", std::ceil<int>)
{}
OperationImplementation *Ceil::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Ceil(metaid,expr);}

quint64 Ceil::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/ceil"), "Ceiling value", "integer");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain"));
    resource.addProperty("pout_1_desc",QString("output data source with a integer numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
REGISTER_OPERATION(Floor)
Floor::Floor(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "integer", std::floor<int>)
{}
OperationImplementation *Floor::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Floor(metaid,expr);}

quint64 Floor::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/floor"), "Floor value", "integer");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain"));
    resource.addProperty("pout_1_desc",QString("output data source with a integer numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
double sign(double v) {
    if ( v < 0)
        return -1;
    if ( v > 0)
        return 1;
    return 0;
}

REGISTER_OPERATION(Sign)
Sign::Sign(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "integer", sign)
{}
OperationImplementation *Sign::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Floor(metaid,expr);}

quint64 Sign::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/sgn"), "Sign", "integer");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain"));
    resource.addProperty("pout_1_desc",QString("output data source with values -1,0,1 depending on the sign of the input value"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
REGISTER_OPERATION(CosineH)
CosineH::CosineH(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", cosh)
{}
OperationImplementation *CosineH::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new CosineH(metaid,expr);}

quint64 CosineH::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/cosh"), "Hyperbolic cosine", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain; values are considered to be radians"));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
REGISTER_OPERATION(SineH)
SineH::SineH(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", sinh)
{}
OperationImplementation *SineH::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new SineH(metaid,expr);}

quint64 SineH::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/sinh"), "Hyperbolic sine", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain; values are considered to be radians"));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
<commit_msg>sin != cos; apparently one copy/paste too much<commit_after>#include <functional>
#include <future>
#include "kernel.h"
#include "raster.h"
#include "symboltable.h"
#include "ilwisoperation.h"
#include "pixeliterator.h"
#include "unarymath.h"
#include "unarymathoperations.h"

using namespace Ilwis;
using namespace BaseOperations;

REGISTER_OPERATION(Sine)

Sine::Sine(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "min1to1", sin)
{}
OperationImplementation *Sine::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Sine(metaid,expr);}

quint64 Sine::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/sin"), "sine", "min1to1");
    resource.addProperty("pin_1_desc", QString("input data source with a numerical domain; values are considered to be radians"));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain; values are between -1 and 1"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
REGISTER_OPERATION(Cosine)
Cosine::Cosine(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "min1to1", cos)
{}
OperationImplementation *Cosine::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Cosine(metaid,expr);}

quint64 Cosine::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/cos"), "cosine", "min1to1");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain; values are considered to be radians"));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain; values are between -1 and 1"));

    mastercatalog()->addItems({resource});
    return resource.id();
}

//----------------------------------------------------------
double tangent(double v){
    if ( std::abs(v) == M_PI / 2)
        return rUNDEF;
    return tan(v);
}

REGISTER_OPERATION(Tangent)
Tangent::Tangent(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", tangent)
{}
OperationImplementation *Tangent::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Tangent(metaid,expr);}

quint64 Tangent::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/tan"), "Tangent", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain; values are considered to be radians"));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain; "));

    mastercatalog()->addItems({resource});
    return resource.id();
}

//----------------------------------------------------------
double arcsine(double v){
    if ( v < -1 || v > 1)
        return rUNDEF;
    return asin(v);
}

REGISTER_OPERATION(Arcsine)

Arcsine::Arcsine(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", arcsine)
{}
OperationImplementation *Arcsine::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Arcsine(metaid,expr);}

quint64 Arcsine::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/asin"), "Arcsine", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain;with value between -1 and 1 "));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain; values are between pi/2 and -pi/2"));

    mastercatalog()->addItems({resource});
    return resource.id();
}

//----------------------------------------------------------
double arccosine(double v){
    if ( v < -1 || v > 1)
        return rUNDEF;
    return asin(v);
}

REGISTER_OPERATION(Arccosine)
Arccosine::Arccosine(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", arccosine)
{}
OperationImplementation *Arccosine::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Arccosine(metaid,expr);}

quint64 Arccosine::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/acos"), "Arccosine", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain with value between -1 and 1; "));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain; values are between 0 and pi"));

    mastercatalog()->addItems({resource});
    return resource.id();
}

//----------------------------------------------------------
REGISTER_OPERATION(ArcTangent)
ArcTangent::ArcTangent(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", atan)
{}
OperationImplementation *ArcTangent::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new ArcTangent(metaid,expr);}

quint64 ArcTangent::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/atan"), "ArcTangent", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain;with value between -pi/2 and pi/2 "));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain; values are between -1 and 1"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
double logten(double v){
    if ( v > 0)
        return log10(v);
    return rUNDEF;
}
REGISTER_OPERATION(Log10)
Log10::Log10(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", logten)
{}
OperationImplementation *Log10::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Log10(metaid,expr);}

quint64 Log10::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/log10"), "Log10", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain;with value larger than zero "));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
double naturallog(double v){
    if ( v > 0)
        return log(v);
    return rUNDEF;
}

REGISTER_OPERATION(NaturalLogarithm)
NaturalLogarithm::NaturalLogarithm(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", naturallog)
{}
OperationImplementation *NaturalLogarithm::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new NaturalLogarithm(metaid,expr);}

quint64 NaturalLogarithm::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/ln"), "Natural Logarithm", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain;with value larger than zero "));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------

double abs2(double v){
    if ( v == rUNDEF)
        return rUNDEF;
    return v;
}
REGISTER_OPERATION(Abs)
Abs::Abs(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", abs2)
{}
OperationImplementation *Abs::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Abs(metaid,expr);}

quint64 Abs::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/abs"), "Absolute value", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain"));
    resource.addProperty("pout_1_desc",QString("output data source with a positive numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}

//---------------------------------------------------------
//----------------------------------------------------------
double sqrt2(double v){
    if ( v < 0)
        return rUNDEF;
    return std::sqrt(v);
}
REGISTER_OPERATION(Sqrt)
Sqrt::Sqrt(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", sqrt2)
{}
OperationImplementation *Sqrt::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Sqrt(metaid,expr);}

quint64 Sqrt::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/sqrt"), "Absolute value", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a positive numerical domain (or 0)"));
    resource.addProperty("pout_1_desc",QString("output data source with a positive numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
REGISTER_OPERATION(Ceil)
Ceil::Ceil(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "integer", std::ceil<int>)
{}
OperationImplementation *Ceil::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Ceil(metaid,expr);}

quint64 Ceil::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/ceil"), "Ceiling value", "integer");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain"));
    resource.addProperty("pout_1_desc",QString("output data source with a integer numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
REGISTER_OPERATION(Floor)
Floor::Floor(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "integer", std::floor<int>)
{}
OperationImplementation *Floor::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Floor(metaid,expr);}

quint64 Floor::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/floor"), "Floor value", "integer");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain"));
    resource.addProperty("pout_1_desc",QString("output data source with a integer numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
double sign(double v) {
    if ( v < 0)
        return -1;
    if ( v > 0)
        return 1;
    return 0;
}

REGISTER_OPERATION(Sign)
Sign::Sign(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "integer", sign)
{}
OperationImplementation *Sign::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new Floor(metaid,expr);}

quint64 Sign::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/sgn"), "Sign", "integer");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain"));
    resource.addProperty("pout_1_desc",QString("output data source with values -1,0,1 depending on the sign of the input value"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
REGISTER_OPERATION(CosineH)
CosineH::CosineH(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", cosh)
{}
OperationImplementation *CosineH::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new CosineH(metaid,expr);}

quint64 CosineH::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/cosh"), "Hyperbolic cosine", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain; values are considered to be radians"));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
REGISTER_OPERATION(SineH)
SineH::SineH(quint64 metaid,const Ilwis::OperationExpression& expr) : UnaryMath(metaid, expr, "value", sinh)
{}
OperationImplementation *SineH::create(quint64 metaid, const Ilwis::OperationExpression &expr){return new SineH(metaid,expr);}

quint64 SineH::createMetadata() {
    Resource resource = UnaryMath::populateMetadata(QString("ilwis://operations/sinh"), "Hyperbolic sine", "value");
    resource.addProperty("pin_1_desc",QString("input data source with a numerical domain; values are considered to be radians"));
    resource.addProperty("pout_1_desc",QString("output data source with a numerical domain"));

    mastercatalog()->addItems({resource});
    return resource.id();
}
//----------------------------------------------------------
<|endoftext|>


<commit_before>#include "tiramisu/tiramisu.h"
#include "wrapper_optical_flow.h"

// This code is the Tiramisu implementation of the following Matlab code
// https://www.mathworks.com/examples/computer-vision/community/35625-lucas-kanade-method-example-2?s_tid=examples_p1_BOTH

using namespace tiramisu;

int main(int argc, char* argv[])
{
    // Declare the function name
    tiramisu::init("optical_flow_tiramisu");

    // Declare input sizes
    input SIZES("SIZES", {var("S", 0, 2)}, p_int32);

    constant N0("N0", SIZES(0));
    constant N1("N1", SIZES(1));
    constant NC("NC", _NC); // Number of corners

    // Loop iterators
    var x("x", 0, N1-1), y("y", 0, N0-1), k("k", 0, NC);

    // input images
    input im1("im1", {y, x}, p_uint8);
    input im2("im2", {y, x}, p_uint8);

    // Corners
    input C1("C1", {k}, p_int32);
    input C2("C2", {k}, p_int32);

    // First convolution (partial on x)
    expr e1 = cast(p_float32, cast(p_int32, im1(y,     x)) - cast(p_int32, im1(y,     x + 1)) +
			      cast(p_int32, im1(y + 1, x)) - cast(p_int32, im1(y + 1, x + 1)));
    computation Ix_m("Ix_m", {y, x}, e1);

    // Second convolution  (partial on y)
    expr e2 = cast(p_float32, cast(p_int32, im1(y,     x)) + cast(p_int32, im1(y,     x + 1))
			    - cast(p_int32, im1(y + 1, x)) - cast(p_int32, im1(y + 1, x + 1)));
    computation Iy_m("Iy_m", {y, x}, e2);

    // Third convolution
    expr e3 = cast(p_float32, cast(p_int32, im1(y,     x)) + cast(p_int32, im1(y,     x + 1))
			    + cast(p_int32, im1(y + 1, x)) + cast(p_int32, im1(y + 1, x + 1)));
    expr e4 = cast(p_float32, (- cast(p_int32, im2(y,     x))) - cast(p_int32, im2(y,     x + 1))
			       - cast(p_int32, im2(y + 1, x))  - cast(p_int32, im2(y + 1, x + 1)));
    computation It_m("It_m", {y, x}, e3 + e4);

    // Second part of the algorithm
    // Compute "u" and "v" for each corner "k"
    computation i("i", {k}, C2(k));
    computation j("j", {k}, C1(k));

    // Ix = Ix_m(i-w:i+w, j-w:j+w);
    // Iy = Iy_m(i-w:i+w, j-w:j+w);
    // It = It_m(i-w:i+w, j-w:j+w);
    // Ix = Ix(:); % flatten the IX 2D array into a vector
    // Iy = Iy(:);
    // A = [Ix Iy];
    // b = -It(:);
    var xp("xp", 0, 2*w);
    var yp("yp", 0, 2*w);
    computation        A1("A1",        {k, yp, xp},   Ix_m(i(0)+yp-w, j(0)+xp-w));
    computation  A1_right("A1_right",  {k, yp, xp},   Iy_m(i(0)+yp-w, j(0)+xp-w));
    computation        b1("b1",        {k, yp, xp}, (-It_m(i(0)+yp-w, j(0)+xp-w)));

    // Reshape A1 to A
    var x1("x1", 0, 2);
    var y1("y1", 0, 4*w*w);
    input        A("A",        {k, y1, x1}, p_float32); // Use A to reshape A1 and A1_right
    input        b("b",        {k, y1}, p_float32);     // Use b to reshape b1

    // Compute pinv(A):
    // 1)    tA = transpose(A)
    // 2)    tAA = tA * A
    // 3)    X = inv(tAA)
    // 4)    pinv(A) = X * tA

    // 1) Computing tA = transpose(A)
    computation tA("tA", {k, x1, y1}, A(k, y1, x1));

    // 2) Computing tAA = tA * A
    var y2("y2", 0, 2);
    var l1("l1", 0, 4*w*w);
    computation tAA("tAA", {k, x1, y2}, expr((float) 0));
    computation tAA_update("tAA_update", {k, x1, y2, l1}, tAA(k, x1, y2) + (tA(k, x1, l1) * A(k, l1, y2)));

    // 3) Computing X = inv(tAA)
    computation determinant("determinant", {k}, cast(p_float64,tAA(k,0,0))*cast(p_float64, tAA(k,1,1)) - (cast(p_float64, tAA(k,0,1))*cast(p_float64, tAA(k,1,0))));
    computation tAAp_00("tAAp_00", {k},  cast(p_float64, tAA(k,1,1))/determinant(k));
    computation tAAp_11("tAAp_11", {k},  cast(p_float64, tAA(k,0,0))/determinant(k));
    computation tAAp_01("tAAp_01", {k}, -cast(p_float64, tAA(k,0,1))/determinant(k));
    computation tAAp_10("tAAp_10", {k}, -cast(p_float64, tAA(k,1,0))/determinant(k));
    input X("X", {k, x1, y2}, p_float64);

    // 4) Computing pinv(A) = X*tA
    var l2("l2", 0, 2);
    computation    pinvA("pinvA", {k, x1, y1}, expr((double) 0));
    computation    pinvA_update("pinvA_update", {k, x1, y1, l2}, pinvA(k, x1, y1) + X(k, x1, l2)*cast(p_float64, tA(k, l2, y1)));

    // Compute nu = pinv(A)*b
    computation nu("nu", {k, x1}, expr((float) 0));
    computation nu_update("nu_update", {k, x1, y1}, nu(k, x1) + cast(p_float32, pinvA(k, x1, y1))*b(k, y1));

    // Results
    computation u("u", {k}, nu(k, 0));
    computation v("v", {k}, nu(k, 1));

    // Schedule
    Ix_m.then(Iy_m, x)
	.then(It_m, x)
	.then(i, computation::root)
	.then(j, k)
	.then(A1, k)
	.then(A1_right, xp)
	.then(b1, xp)
	.then(tA, k)
	.then(tAA, k)
	.then(tAA_update, y2)
	.then(determinant, k)
	.then(tAAp_00, k)
	.then(tAAp_11, k)
	.then(tAAp_01, k)
	.then(tAAp_10, k)
	.then(X, k)
	.then(pinvA, k)
	.then(pinvA_update, y1)
	.then(nu, k)
	.then(nu_update, x1)
	.then(u, k)
	.then(v, k);

    Ix_m.parallelize(y);
    Ix_m.vectorize(x, 32);
    Iy_m.vectorize(x, 32);
    It_m.vectorize(x, 32);
    A1.vectorize(xp, 32);
    A1_right.vectorize(xp, 32);
    b1.vectorize(xp, 32);
    tA.vectorize(y1, 16);

    // Buffer allocation and mapping computations to buffers
    buffer b_SIZES("b_SIZES", {2}, p_int32, a_input);
    buffer b_im1("b_im1", {N0, N1}, p_uint8, a_input);
    buffer b_im2("b_im2", {N0, N1}, p_uint8, a_input);
    buffer b_Ix_m("b_Ix_m", {N0, N1}, p_float32, a_output);
    buffer b_Iy_m("b_Iy_m", {N0, N1}, p_float32, a_output);
    buffer b_It_m("b_It_m", {N0, N1}, p_float32, a_output);
    buffer b_C1("b_C1", {NC}, p_int32, a_input);
    buffer b_C2("b_C2", {NC}, p_int32, a_input);
    buffer b_i("b_i", {1}, p_int32, a_temporary);
    buffer b_j("b_j", {1}, p_int32, a_temporary);
    buffer b_A("b_A", {4*w*w, 2}, p_float32, a_output);
    buffer b_b("b_b", {4*w*w}, p_float32, a_temporary);
    buffer b_tA("b_tA", {2, 4*w*w}, p_float32, a_output);
    buffer b_tAA("b_tAA", {2, 2}, p_float32, a_output);
    buffer b_determinant("b_determinant", {1}, p_float64, a_output);
    buffer b_X("b_X", {2, 2}, p_float64, a_output);
    buffer b_pinvA("b_pinvA", {2, 4*w*w}, p_float64, a_output);
    buffer b_nu("b_nu", {2}, p_float32, a_temporary);
    buffer b_u("b_u", {NC}, p_float32, a_output);
    buffer b_v("b_v", {NC}, p_float32, a_output);

    SIZES.store_in(&b_SIZES);
    im1.store_in(&b_im1);
    im2.store_in(&b_im2);
    Ix_m.store_in(&b_Ix_m);
    Iy_m.store_in(&b_Iy_m);
    It_m.store_in(&b_It_m);
    C1.store_in(&b_C1);
    C2.store_in(&b_C2);
    i.store_in(&b_i, {0});
    j.store_in(&b_j, {0});
    A1.store_in(&b_A, {xp+yp*2*w, 0});
    A1_right.store_in(&b_A, {xp+yp*2*w, 1});
    b1.store_in(&b_b, {xp+yp*2*w});
    A.store_in(&b_A, {y1, x1});
    b.store_in(&b_b, {y1});
    tA.store_in(&b_tA, {x1, y1});
    tAA.store_in(&b_tAA, {x1, y2});
    tAA_update.store_in(&b_tAA, {x1, y2});
    determinant.store_in(&b_determinant, {0});
    tAAp_00.store_in(&b_X, {0, 0});
    tAAp_01.store_in(&b_X, {0, 1});
    tAAp_10.store_in(&b_X, {1, 0});
    tAAp_11.store_in(&b_X, {1, 1});
    X.store_in(&b_X, {x1, y2});
    pinvA.store_in(&b_pinvA, {x1, y1});
    pinvA_update.store_in(&b_pinvA, {x1, y1});
    nu.store_in(&b_nu, {x1});
    nu_update.store_in(&b_nu, {x1});
    u.store_in(&b_u, {k});
    v.store_in(&b_v, {k});

    tiramisu::codegen({&b_SIZES, &b_im1, &b_im2, &b_Ix_m, &b_Iy_m, &b_It_m, &b_C1, &b_C2, &b_u, &b_v, &b_A, &b_pinvA, &b_determinant, &b_tAA, &b_tA, &b_X}, "build/generated_fct_optical_flow.o");

    return 0;
}
<commit_msg>Update optical flow<commit_after>#include "tiramisu/tiramisu.h"
#include "wrapper_optical_flow.h"

// This code is the Tiramisu implementation of the following Matlab code
// https://www.mathworks.com/examples/computer-vision/community/35625-lucas-kanade-method-example-2?s_tid=examples_p1_BOTH

using namespace tiramisu;

int main(int argc, char* argv[])
{
    // Declare the function name
    tiramisu::init("optical_flow_tiramisu");

    // Declare input sizes
    input SIZES("SIZES", {var("S", 0, 2)}, p_int32);

    constant N0("N0", SIZES(0));
    constant N1("N1", SIZES(1));
    constant NC("NC", _NC); // Number of corners

    // Loop iterators
    var x("x", 0, N1-1), y("y", 0, N0-1), k("k", 0, NC);

    // input images
    input im1("im1", {y, x}, p_uint8);
    input im2("im2", {y, x}, p_uint8);

    // Corners
    input C1("C1", {k}, p_int32);
    input C2("C2", {k}, p_int32);

    // First convolution (partial on x)
    expr e1 = cast(p_float32, cast(p_int32, im1(y,     x)) - cast(p_int32, im1(y,     x + 1)) +
			      cast(p_int32, im1(y + 1, x)) - cast(p_int32, im1(y + 1, x + 1)));
    computation Ix_m("Ix_m", {y, x}, e1);

    // Second convolution  (partial on y)
    expr e2 = cast(p_float32, cast(p_int32, im1(y,     x)) + cast(p_int32, im1(y,     x + 1))
			    - cast(p_int32, im1(y + 1, x)) - cast(p_int32, im1(y + 1, x + 1)));
    computation Iy_m("Iy_m", {y, x}, e2);

    // Third convolution
    expr e3 = cast(p_float32, cast(p_int32, im1(y,     x)) + cast(p_int32, im1(y,     x + 1))
			    + cast(p_int32, im1(y + 1, x)) + cast(p_int32, im1(y + 1, x + 1)));
    expr e4 = cast(p_float32, (- cast(p_int32, im2(y,     x))) - cast(p_int32, im2(y,     x + 1))
			       - cast(p_int32, im2(y + 1, x))  - cast(p_int32, im2(y + 1, x + 1)));
    computation It_m("It_m", {y, x}, e3 + e4);

    // Second part of the algorithm
    // Compute "u" and "v" for each corner "k"
    computation i("i", {k}, C2(k));
    computation j("j", {k}, C1(k));

    // Ix = Ix_m(i-w:i+w, j-w:j+w);
    // Iy = Iy_m(i-w:i+w, j-w:j+w);
    // It = It_m(i-w:i+w, j-w:j+w);
    // Ix = Ix(:); % flatten the IX 2D array into a vector
    // Iy = Iy(:);
    // A = [Ix Iy];
    // b = -It(:);
    var xp("xp", 0, 2*w);
    var yp("yp", 0, 2*w);
    computation        A1("A1",        {k, yp, xp},   Ix_m(i(0)+yp-w, j(0)+xp-w));
    computation  A1_right("A1_right",  {k, yp, xp},   Iy_m(i(0)+yp-w, j(0)+xp-w));
    computation        b1("b1",        {k, yp, xp}, (-It_m(i(0)+yp-w, j(0)+xp-w)));

    // Reshape A1 to A
    var x1("x1", 0, 2);
    var y1("y1", 0, 4*w*w);
    input        A("A",        {k, y1, x1}, p_float32); // Use A to reshape A1 and A1_right
    input        b("b",        {k, y1}, p_float32);     // Use b to reshape b1

    // Compute pinv(A):
    // 1)    tA = transpose(A)
    // 2)    tAA = tA * A
    // 3)    X = inv(tAA)
    // 4)    pinv(A) = X * tA

    // 1) Computing tA = transpose(A)
    computation tA("tA", {k, x1, y1}, A(k, y1, x1));

    // 2) Computing tAA = tA * A
    var y2("y2", 0, 2);
    var l1("l1", 0, 4*w*w);
    computation tAA("tAA", {k, x1, y2}, expr((float) 0));
    computation tAA_update("tAA_update", {k, x1, y2, l1}, tAA(k, x1, y2) + (tA(k, x1, l1) * A(k, l1, y2)));

    // 3) Computing X = inv(tAA)
    computation determinant("determinant", {k}, cast(p_float64,tAA(k,0,0))*cast(p_float64, tAA(k,1,1)) - (cast(p_float64, tAA(k,0,1))*cast(p_float64, tAA(k,1,0))));
    computation tAAp_00("tAAp_00", {k},  cast(p_float64, tAA(k,1,1))/determinant(k));
    computation tAAp_11("tAAp_11", {k},  cast(p_float64, tAA(k,0,0))/determinant(k));
    computation tAAp_01("tAAp_01", {k}, -cast(p_float64, tAA(k,0,1))/determinant(k));
    computation tAAp_10("tAAp_10", {k}, -cast(p_float64, tAA(k,1,0))/determinant(k));
    input X("X", {k, x1, y2}, p_float64);

    // 4) Computing pinv(A) = X*tA
    var l2("l2", 0, 2);
    computation    pinvA("pinvA", {k, x1, y1}, expr((double) 0));
    computation    pinvA_update("pinvA_update", {k, x1, y1, l2}, pinvA(k, x1, y1) + X(k, x1, l2)*cast(p_float64, tA(k, l2, y1)));

    // Compute nu = pinv(A)*b
    computation nu("nu", {k, x1}, expr((float) 0));
    computation nu_update("nu_update", {k, x1, y1}, nu(k, x1) + cast(p_float32, pinvA(k, x1, y1))*b(k, y1));

    // Results
    computation u("u", {k}, nu(k, 0));
    computation v("v", {k}, nu(k, 1));

    // Schedule
    Ix_m.then(Iy_m, x)
	.then(It_m, x)
	.then(i, computation::root)
	.then(j, k)
	.then(A1, k)
	.then(A1_right, xp)
	.then(b1, xp)
	.then(tA, k)
	.then(tAA, k)
	.then(tAA_update, y2)
	.then(determinant, k)
	.then(tAAp_00, k)
	.then(tAAp_11, k)
	.then(tAAp_01, k)
	.then(tAAp_10, k)
	.then(X, k)
	.then(pinvA, k)
	.then(pinvA_update, y1)
	.then(nu, k)
	.then(nu_update, x1)
	.then(u, k)
	.then(v, k);

    Ix_m.parallelize(y);
    Ix_m.vectorize(x, 32);
    Iy_m.vectorize(x, 32);
    It_m.vectorize(x, 32);
    A1.vectorize(xp, 32);
    A1_right.vectorize(xp, 32);
    b1.vectorize(xp, 32);
    tA.vectorize(y1, 16);
    tAA_update.vectorize(l1, 32);

    // Buffer allocation and mapping computations to buffers
    buffer b_SIZES("b_SIZES", {2}, p_int32, a_input);
    buffer b_im1("b_im1", {N0, N1}, p_uint8, a_input);
    buffer b_im2("b_im2", {N0, N1}, p_uint8, a_input);
    buffer b_Ix_m("b_Ix_m", {N0, N1}, p_float32, a_output);
    buffer b_Iy_m("b_Iy_m", {N0, N1}, p_float32, a_output);
    buffer b_It_m("b_It_m", {N0, N1}, p_float32, a_output);
    buffer b_C1("b_C1", {NC}, p_int32, a_input);
    buffer b_C2("b_C2", {NC}, p_int32, a_input);
    buffer b_i("b_i", {1}, p_int32, a_temporary);
    buffer b_j("b_j", {1}, p_int32, a_temporary);
    buffer b_A("b_A", {4*w*w, 2}, p_float32, a_output);
    buffer b_b("b_b", {4*w*w}, p_float32, a_temporary);
    buffer b_tA("b_tA", {2, 4*w*w}, p_float32, a_output);
    buffer b_tAA("b_tAA", {2, 2}, p_float32, a_output);
    buffer b_determinant("b_determinant", {1}, p_float64, a_output);
    buffer b_X("b_X", {2, 2}, p_float64, a_output);
    buffer b_pinvA("b_pinvA", {2, 4*w*w}, p_float64, a_output);
    buffer b_nu("b_nu", {2}, p_float32, a_temporary);
    buffer b_u("b_u", {NC}, p_float32, a_output);
    buffer b_v("b_v", {NC}, p_float32, a_output);

    SIZES.store_in(&b_SIZES);
    im1.store_in(&b_im1);
    im2.store_in(&b_im2);
    Ix_m.store_in(&b_Ix_m);
    Iy_m.store_in(&b_Iy_m);
    It_m.store_in(&b_It_m);
    C1.store_in(&b_C1);
    C2.store_in(&b_C2);
    i.store_in(&b_i, {0});
    j.store_in(&b_j, {0});
    A1.store_in(&b_A, {xp+yp*2*w, 0});
    A1_right.store_in(&b_A, {xp+yp*2*w, 1});
    b1.store_in(&b_b, {xp+yp*2*w});
    A.store_in(&b_A, {y1, x1});
    b.store_in(&b_b, {y1});
    tA.store_in(&b_tA, {x1, y1});
    tAA.store_in(&b_tAA, {x1, y2});
    tAA_update.store_in(&b_tAA, {x1, y2});
    determinant.store_in(&b_determinant, {0});
    tAAp_00.store_in(&b_X, {0, 0});
    tAAp_01.store_in(&b_X, {0, 1});
    tAAp_10.store_in(&b_X, {1, 0});
    tAAp_11.store_in(&b_X, {1, 1});
    X.store_in(&b_X, {x1, y2});
    pinvA.store_in(&b_pinvA, {x1, y1});
    pinvA_update.store_in(&b_pinvA, {x1, y1});
    nu.store_in(&b_nu, {x1});
    nu_update.store_in(&b_nu, {x1});
    u.store_in(&b_u, {k});
    v.store_in(&b_v, {k});

    tiramisu::codegen({&b_SIZES, &b_im1, &b_im2, &b_Ix_m, &b_Iy_m, &b_It_m, &b_C1, &b_C2, &b_u, &b_v, &b_A, &b_pinvA, &b_determinant, &b_tAA, &b_tA, &b_X}, "build/generated_fct_optical_flow.o");

    return 0;
}
<|endoftext|>


<commit_before>#ifndef QUEUES_H_INCLUDED
#define QUEUES_H_INCLUDED

#include <wiz/global.h>
#include <wiz/wizardError.h>
#include <wiz/newarrays.h>

/// #define QUEUES_DEBUG

namespace wiz{
class QueueEmptyError : public wiz::Error
{
public:
    QueueEmptyError() : wiz::Error( "queueEmptyError" )
    {

    }
};
class QueueFullError : public wiz::Error
{
public:
    QueueFullError() : wiz::Error( "queueFullError" )
    {

    }
};

// check array Queue, array stack?
template <typename T>
class Queue //: public wizObject
{
private:
    class Element
    {
    public:
        Element* next;
        T data;
    public:
        explicit Element( const T d = T() )
        {
            data = d;
            next =  nullptr;
        }
    };
private:
    Element* Head; //
    Element* Rear; //
public:
    explicit Queue() : Head( nullptr ), Rear( nullptr ) { Head = new Element(); Rear = Head; }

    virtual ~Queue(){
        clear();
        delete Head; Head = Rear = nullptr;
    }
    void clear()
    {
        while( !isEmpty() ){
           deleteq();
        }
     }
    bool isEmpty() const
    {
        return nullptr == Head->next; /// size == 0, empty..
    }
    bool empty() const { return isEmpty(); }
    //
    void addq( const T& p ) /// push
    {
        Element* temp = new Element(p); //
        //
        Rear->next = temp;//
        temp->next = nullptr;// auto look def of Element
        Rear = Rear->next; //
    }//
    void push( const T& p ) { addq( p ); }
    T deleteq(){ /// pop
        if( isEmpty() )
        {
            throw QueueEmptyError();
        }
        //
        Element* temp = Head->next;//
        Head->next = temp->next;
        //Rear 처리
        if( nullptr == Head->next )
            Rear = Head;
        T returnTemp = temp->data;
        delete temp;
        return returnTemp;
    }
    T pop() { return deleteq(); }
    Queue& operator<<( const T& p ){
        addq( p ); //
        return *this;
    }
private:
    void copy( const Queue<T>& q )
    {
        //this->clear();

        Element* qTemp = q.Head->next;

        while( qTemp != nullptr )
        {
            addq( qTemp->data );
            qTemp = qTemp->next;
        }
    }
public:
    //
    Queue( const Queue<T>& q ) : Head( nullptr ), Rear( nullptr )
    {// clear();
        Head = new Element(); Rear = Head;
        copy( q );
    }
    Queue& operator=( const Queue<T>& q )
    {
        if( Head == q.Head ) { return *this; }

        clear();

        // head, rear reser..!!
        copy( q );

        return *this;
    }
    Queue( Queue<T>&& q )
    {
        Head->next = q.Head->next;
        Rear = q.Rear;

        /// do-empty..
        q.Head->next = nullptr;
        q.Rear = q.Head;
    }
    Queue<T>& operator=( Queue<T>&& q )
    {
        if( Head == q.Head ) { return *this; }
        this->clear();
        Head->next = q.Head->next;
        Rear = q.Rear;

		q.Head->next = nullptr;
		q.Rear = q.Head;
		return *this;
	}
};

// Queue using Array
template <class T>
class ArrayQueue
{
public:
	ArrayQueue(const ArrayQueue<T>& aq)
		:que(aq.que), start(aq.start), num(aq.num)
	{
		//
	}
	ArrayQueue(ArrayQueue<T>&& aq)
	{
		que = std::move(aq.que);
		start = aq.start;
		num = aq.num;

		aq.que = Array<T>(2);
		aq.start = 0;
		aq.num = 0;
	}
	ArrayQueue<T>& operator=(ArrayQueue<T>&& aq)
	{
		if (que == aq.que) { return *this; }
		this->que.DoEmpty();
		que = std::move(aq.que);
		start = aq.start;
		num = aq.num;

		aq.que = Array<T>(2);
		aq.start = 0;
		aq.num = 0;
		return *this;
	}
	ArrayQueue<T>& operator=(const ArrayQueue<T>& aq)
	{
		if (que == aq.que) { return *this; }
		que.DoEmpty();
		this->que = aq.que;
		this->start = aq.start;
		this->num = aq.num;
		return *this;
	}
private:
	Array<T> que;
	int start;
	int num;
public:
	struct Iter
	{
		T* ptr;
		int pos;

		Iter() { }
		Iter(T* ptr, int pos)
			: ptr(ptr), pos(pos)
		{

		}

		bool operator==(const Iter& other) {
			return ptr == other.ptr;
		}
	};

	Iter begin(int count = 0) { return Iter(&((*this)[count]), count); }

	Iter end() { return Iter(&((*this)[size()]), size()); }

	Iter erase(Iter ptr) {
		for (int i = ptr.pos; i < size() - 1; ++i) {
			(*this)[i] = (*this)[i + 1];
		}
		(*this)[size() - 1] = T();

		num--;

		return ptr;
	}
public:
	explicit ArrayQueue(const int max = 2) : start(0), num(0)
	{
#ifdef QUEUES_DEBUG
		// max > 0
		wiz::checkUnderError(0, max, 1);
#endif
		que = Array<T>(max);
	}
	virtual ~ArrayQueue()
	{
	}
public:
	const T& operator[](const int idx) const
	{
		return que[(start + idx) % (que.size())];
	}
	T& operator[](const int idx)
	{
		return que[(start + idx) % (que.size())];
	}
public:
	void push(const ArrayQueue<T>& val) {
		if (val.empty()) { return; }
		int newSize = this->que.size();

		while (newSize - num - 1 < val.size()) {
			newSize = newSize * 1.5;
		}
		if (newSize != this->que.size()) {
			// expand array queue.
			ArrayQueue<T> temp(newSize);
			temp.start = 0;
			//
			for (int i = 0; i < this->size(); ++i) {
				temp[i] = std::move((*this)[i]);
			}

			const int iend = val.num;
			for (int i = 0; i < iend; ++i) {
				temp[i + this->num] = val[i];
			}

			temp.num = this->num + val.num;
			*this = std::move(temp);
		}
		else {
			for (int i = 0; i < val.size(); ++i) {
				this->push(val.que[i]);
			}
		}
	}
	void push(ArrayQueue<T>&& val) { // chk..
		if (val.empty()) { return; }
		int newSize = this->que.size();

		while (newSize - num - 1 < val.size()) {
			newSize = newSize * 1.5;
		}
		if (newSize != this->que.size()) {
			// expand array queue.
			ArrayQueue temp(newSize);
			temp.start = 0;
			//
			for (int i = 0; i < this->size(); ++i) {
				temp[i] = std::move((*this)[i]);
			}

			const int iend = val.num;
			for (int i = 0; i < iend; ++i) {
				temp[i + this->num] = std::move(val[i]);
			}

			temp.num = this->num + val.num;
			*this = std::move(temp);
		}
		else {
			for (int i = 0; i < val.size(); ++i) {
				this->push(std::move(val[i]));
			}
		}
	}
    void push( const T& val )
    {
        if( isFull() )
        {
            // expand array queue.
            ArrayQueue temp( que.size() * 1.5 );
            //
			for (int i = 0; i < que.size(); ++i) {
				temp[i] = std::move(que[(start + i) % (que.size())]);
			}
			temp.start = 0;
			temp.num = que.size() - 1;

            *this = std::move( temp );
        }
        que[(start+num) % (que.size())] = val;
        num++;
    }

	void push(T&& val)
	{
		if (isFull())
		{
			// expand array queue.
			ArrayQueue temp(que.size() * 1.5);
			//
			for (int i = 0; i < que.size(); ++i) {
				temp[i] = std::move(que[(start + i) % (que.size())]);
			}
			temp.start = 0;
			temp.num = que.size() - 1;

			*this = std::move(temp);
		}
		que[(start + num) % (que.size())] = std::move(val);
		num++;
	}

	void pop(T* t = nullptr) {
		if (isEmpty()) { throw QueueEmptyError(); }

		T temp = std::move(que[start]);

		//que[start] = T();

		start = (start + 1) % (que.size()); // % que.size(), 2^n.
		num--;

		if (nullptr != t) {
			*t = move(temp);
		}
	}
	void pop_front(T* t = nullptr) {
		pop(t);
	}

	T pop_back()
	{
		if (isEmpty()) { throw QueueEmptyError(); }
		T temp = std::move((*this)[num - 1]);

		//(*this)[num - 1] = T();

		num--;

		return temp;
	}

    bool isFull()const
    {
        return num >= ( que.size() - 1);
    }

    bool isEmpty()const
    {
        return 0 == num;
    }
    int size()const{ return num; }
    bool empty()const { return isEmpty(); }
    int getNumMax()const { return que.size(); }
    int getNum()const { return num; }
	T& front() { return (*this)[0]; }
	const T& front()const { return (*this)[0]; }
    Array<T> toArray()const
    {
        Array<T> temp;

        if( num > 0 )
        {
            temp = Array<T>( num );
            int count=0;

            for( int i=0; i < num; i++ )
            {
                temp[i] = que[ ( start + i ) % (que.size()) ];
            }
        }

        return temp;
    }

    ArrayQueue<T>& operator<<( const T& data )
    {
        push( data );

        return *this;
    }
};

}
#endif // QUEUES_H_INCLUDED
<commit_msg>Delete QUEUES.H<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "bitcoinrpc.h"
#include "main.h"
#include <atomic>

#include <algorithm>

using namespace json_spirit;
using namespace std;

extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, json_spirit::Object& entry);
extern enum Checkpoints::CPMode CheckpointsMode;

double GetDifficulty(const CBlockIndex* blockindex)
{
    // Floating point number that is a multiple of the minimum difficulty,
    // minimum difficulty = 1.0.
    if (blockindex == NULL) {
        if (pindexBest == NULL)
            return 1.0;
        else
            blockindex = GetLastBlockIndex(pindexBest, false);
    }

    int nShift = (blockindex->nBits >> 24) & 0xff;

    double dDiff = (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);

    while (nShift < 29) {
        dDiff *= 256.0;
        nShift++;
    }
    while (nShift > 29) {
        dDiff /= 256.0;
        nShift--;
    }

    return dDiff;
}

double GetPoWMHashPS()
{
    if (pindexBest->nHeight >= LAST_POW_BLOCK)
        return 0;

    int     nPoWInterval          = 72;
    int64_t nTargetSpacingWorkMin = 30, nTargetSpacingWork = 30;

    CBlockIndex* pindex         = pindexGenesisBlock;
    CBlockIndex* pindexPrevWork = pindexGenesisBlock;

    while (pindex) {
        if (pindex->IsProofOfWork()) {
            int64_t nActualSpacingWork = pindex->GetBlockTime() - pindexPrevWork->GetBlockTime();
            nTargetSpacingWork =
                ((nPoWInterval - 1) * nTargetSpacingWork + nActualSpacingWork + nActualSpacingWork) /
                (nPoWInterval + 1);
            nTargetSpacingWork = max(nTargetSpacingWork, nTargetSpacingWorkMin);
            pindexPrevWork     = pindex;
        }

        pindex = pindex->pnext;
    }

    return GetDifficulty() * 4294.967296 / nTargetSpacingWork;
}

double GetPoSKernelPS()
{
    int    nPoSInterval          = 72;
    double dStakeKernelsTriedAvg = 0;
    int    nStakesHandled = 0, nStakesTime = 0;

    CBlockIndex* pindex = pindexBest;
    ;
    CBlockIndex* pindexPrevStake = NULL;

    while (pindex && nStakesHandled < nPoSInterval) {
        if (pindex->IsProofOfStake()) {
            dStakeKernelsTriedAvg += GetDifficulty(pindex) * 4294967296.0;
            nStakesTime += pindexPrevStake ? (pindexPrevStake->nTime - pindex->nTime) : 0;
            pindexPrevStake = pindex;
            nStakesHandled++;
        }

        pindex = pindex->pprev;
    }

    return nStakesTime ? dStakeKernelsTriedAvg / nStakesTime : 0;
}

Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
{
    Object result;
    result.push_back(Pair("hash", block.GetHash().GetHex()));
    CMerkleTx txGen(block.vtx[0]);
    txGen.SetMerkleBranch(&block);
    result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain()));
    result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
    result.push_back(Pair("height", blockindex->nHeight));
    result.push_back(Pair("version", block.nVersion));
    result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
    result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
    result.push_back(Pair("time", (int64_t)block.GetBlockTime()));
    result.push_back(Pair("nonce", (uint64_t)block.nNonce));
    result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
    result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
    result.push_back(Pair("blocktrust", leftTrim(blockindex->GetBlockTrust().GetHex(), '0')));
    result.push_back(Pair("chaintrust", leftTrim(blockindex->nChainTrust.GetHex(), '0')));
    if (blockindex->pprev)
        result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
    if (blockindex->pnext)
        result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));

    result.push_back(Pair(
        "flags", strprintf("%s%s", blockindex->IsProofOfStake() ? "proof-of-stake" : "proof-of-work",
                           blockindex->GeneratedStakeModifier() ? " stake-modifier" : "")));
    result.push_back(Pair("proofhash", blockindex->hashProof.GetHex()));
    result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit()));
    result.push_back(Pair("modifier", strprintf("%016" PRIx64, blockindex->nStakeModifier)));
    result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
    Array txinfo;
    BOOST_FOREACH (const CTransaction& tx, block.vtx) {
        if (fPrintTransactionDetail) {
            Object entry;

            entry.push_back(Pair("txid", tx.GetHash().GetHex()));
            TxToJSON(tx, 0, entry);

            txinfo.push_back(entry);
        } else
            txinfo.push_back(tx.GetHash().GetHex());
    }

    result.push_back(Pair("tx", txinfo));

    if (block.IsProofOfStake())
        result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end())));

    return result;
}

Value getbestblockhash(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error("getbestblockhash\n"
                            "Returns the hash of the best block in the longest block chain.");

    return hashBestChain.GetHex();
}

Value getblockcount(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error("getblockcount\n"
                            "Returns the number of blocks in the longest block chain.");

    return nBestHeight.load();
}

Value getdifficulty(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error("getdifficulty\n"
                            "Returns the difficulty as a multiple of the minimum difficulty.");

    Object obj;
    obj.push_back(Pair("proof-of-work", GetDifficulty()));
    obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
    obj.push_back(Pair("search-interval", (int)nLastCoinStakeSearchInterval));
    return obj;
}

Value settxfee(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
        throw runtime_error("settxfee <amount>\n"
                            "<amount> is a real and is rounded to the nearest 0.01");

    nTransactionFee = AmountFromValue(params[0]);
    nTransactionFee = (nTransactionFee / MIN_TX_FEE) * MIN_TX_FEE; // round to nearest 0.0001

    return true;
}

Value getrawmempool(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error("getrawmempool\n"
                            "Returns all transaction ids in memory pool.");

    vector<uint256> vtxid;
    mempool.queryHashes(vtxid);

    Array a;
    BOOST_FOREACH (const uint256& hash, vtxid)
        a.push_back(hash.ToString());

    return a;
}

Value getblockhash(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error("getblockhash <index>\n"
                            "Returns hash of block in best-block-chain at <index>.");

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > nBestHeight)
        throw runtime_error("Block number out of range.");

    CBlockIndex* pblockindex = FindBlockByHeight(nHeight);
    return pblockindex->phashBlock->GetHex();
}

// Experimentally deprecated in an effort to support the getblock() call electrum requires
// Value getblock(const Array& params, bool fHelp)
// {
//     if (fHelp || params.size() < 1 || params.size() > 2)
//         throw runtime_error(
//             "getblock <hash> [txinfo]\n"
//             "txinfo optional to print more detailed tx info\n"
//             "Returns details of a block with given block-hash.");

//     std::string strHash = params[0].get_str();
//     uint256 hash(strHash);

//     if (mapBlockIndex.count(hash) == 0)
//         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

//     CBlock block;
//     CBlockIndex* pblockindex = mapBlockIndex[hash];
//     block.ReadFromDisk(pblockindex, true);

//     return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
// }

Value getblock(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getblock <hash> [verbose=true]\n"
            "If verbose is false, returns a string that is serialized, hex-encoded data for block "
            "<hash>.\n"
            "If verbose is true, returns an Object with information about block <hash>.");

    std::string strHash = params[0].get_str();
    uint256     hash(strHash);

    bool fVerbose = true;
    if (params.size() > 1)
        fVerbose = params[1].get_bool();

    if (mapBlockIndex.count(hash) == 0)
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

    CBlock       block;
    CBlockIndex* pblockindex = mapBlockIndex[hash];
    block.ReadFromDisk(pblockindex, true);

    if (!fVerbose) {
        CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
        ssBlock << block;
        std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
        return strHex;
    }

    return blockToJSON(block, pblockindex, false);
}

Value getblockbynumber(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error("getblockbynumber <number> [txinfo]\n"
                            "txinfo optional to print more detailed tx info\n"
                            "Returns details of a block with given block-number.");

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > nBestHeight)
        throw runtime_error("Block number out of range.");

    CBlock       block;
    CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
    while (pblockindex->nHeight > nHeight)
        pblockindex = pblockindex->pprev;

    uint256 hash = *pblockindex->phashBlock;

    pblockindex = mapBlockIndex[hash];
    block.ReadFromDisk(pblockindex, true);

    return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
}

// ppcoin: get information of sync-checkpoint
Value getcheckpoint(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error("getcheckpoint\n"
                            "Show info of synchronized checkpoint.\n");

    Object       result;
    CBlockIndex* pindexCheckpoint;

    result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
    pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
    result.push_back(Pair("height", pindexCheckpoint->nHeight));
    result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));

    // Check that the block satisfies synchronized checkpoint
    if (CheckpointsMode == Checkpoints::STRICT)
        result.push_back(Pair("policy", "strict"));

    if (CheckpointsMode == Checkpoints::ADVISORY)
        result.push_back(Pair("policy", "advisory"));

    if (CheckpointsMode == Checkpoints::PERMISSIVE)
        result.push_back(Pair("policy", "permissive"));

    if (mapArgs.count("-checkpointkey"))
        result.push_back(Pair("checkpointmaster", true));

    return result;
}

Value exportblockchain(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 1)
        throw runtime_error("exportblockchain <path-dir>\n"
                            "Exports the blockchain bootstrap.dat file to <path-dir>.\n"
                            "<path-dir> must be a directory that exists.");

    boost::filesystem::path bdir(params[0].get_str());
    if (!boost::filesystem::exists(bdir))
        throw runtime_error("Directory " + bdir.string() + " does not exist.");

    boost::filesystem::path filename = bdir / "bootstrap.dat";

    boost::promise<void>       finished;
    boost::unique_future<void> finished_future = finished.get_future();
    std::atomic<bool>          stopped{false};
    std::atomic<double>        progress{false};
    boost::thread              exporterThread(boost::bind(&ExportBootstrapBlockchain, filename.string(),
                                             boost::ref(stopped), boost::ref(progress),
                                             boost::ref(finished)));
    exporterThread.detach();

    printf("Export blockchain to path started in another thread. Writing to path: %s\n",
           filename.string().c_str());

    int progVal            = 0;
    int lastPrintedProgVal = -1;
    while (!finished_future.is_ready()) {
        progVal = static_cast<int>(progress.load() * 100);
        if (progVal > lastPrintedProgVal) {
            printf("Export blockchain progress: %i%%\n", progVal);
            lastPrintedProgVal = progVal;
        }
        boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
        if (fShutdown) {
            stopped.store(true);
        }
    }

    finished_future.get(); // throws, but that's compatible with exception handle in this function

    printf("Export blockchain to path %s is done.\n", filename.string().c_str());

    return Value();
}
<commit_msg>Enable txn information in getblock<commit_after>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "bitcoinrpc.h"
#include "main.h"
#include <atomic>

#include <algorithm>

using namespace json_spirit;
using namespace std;

extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, json_spirit::Object& entry);
extern enum Checkpoints::CPMode CheckpointsMode;

double GetDifficulty(const CBlockIndex* blockindex)
{
    // Floating point number that is a multiple of the minimum difficulty,
    // minimum difficulty = 1.0.
    if (blockindex == NULL) {
        if (pindexBest == NULL)
            return 1.0;
        else
            blockindex = GetLastBlockIndex(pindexBest, false);
    }

    int nShift = (blockindex->nBits >> 24) & 0xff;

    double dDiff = (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);

    while (nShift < 29) {
        dDiff *= 256.0;
        nShift++;
    }
    while (nShift > 29) {
        dDiff /= 256.0;
        nShift--;
    }

    return dDiff;
}

double GetPoWMHashPS()
{
    if (pindexBest->nHeight >= LAST_POW_BLOCK)
        return 0;

    int     nPoWInterval          = 72;
    int64_t nTargetSpacingWorkMin = 30, nTargetSpacingWork = 30;

    CBlockIndex* pindex         = pindexGenesisBlock;
    CBlockIndex* pindexPrevWork = pindexGenesisBlock;

    while (pindex) {
        if (pindex->IsProofOfWork()) {
            int64_t nActualSpacingWork = pindex->GetBlockTime() - pindexPrevWork->GetBlockTime();
            nTargetSpacingWork =
                ((nPoWInterval - 1) * nTargetSpacingWork + nActualSpacingWork + nActualSpacingWork) /
                (nPoWInterval + 1);
            nTargetSpacingWork = max(nTargetSpacingWork, nTargetSpacingWorkMin);
            pindexPrevWork     = pindex;
        }

        pindex = pindex->pnext;
    }

    return GetDifficulty() * 4294.967296 / nTargetSpacingWork;
}

double GetPoSKernelPS()
{
    int    nPoSInterval          = 72;
    double dStakeKernelsTriedAvg = 0;
    int    nStakesHandled = 0, nStakesTime = 0;

    CBlockIndex* pindex = pindexBest;
    ;
    CBlockIndex* pindexPrevStake = NULL;

    while (pindex && nStakesHandled < nPoSInterval) {
        if (pindex->IsProofOfStake()) {
            dStakeKernelsTriedAvg += GetDifficulty(pindex) * 4294967296.0;
            nStakesTime += pindexPrevStake ? (pindexPrevStake->nTime - pindex->nTime) : 0;
            pindexPrevStake = pindex;
            nStakesHandled++;
        }

        pindex = pindex->pprev;
    }

    return nStakesTime ? dStakeKernelsTriedAvg / nStakesTime : 0;
}

Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
{
    Object result;
    result.push_back(Pair("hash", block.GetHash().GetHex()));
    CMerkleTx txGen(block.vtx[0]);
    txGen.SetMerkleBranch(&block);
    result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain()));
    result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
    result.push_back(Pair("height", blockindex->nHeight));
    result.push_back(Pair("version", block.nVersion));
    result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
    result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
    result.push_back(Pair("time", (int64_t)block.GetBlockTime()));
    result.push_back(Pair("nonce", (uint64_t)block.nNonce));
    result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
    result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
    result.push_back(Pair("blocktrust", leftTrim(blockindex->GetBlockTrust().GetHex(), '0')));
    result.push_back(Pair("chaintrust", leftTrim(blockindex->nChainTrust.GetHex(), '0')));
    if (blockindex->pprev)
        result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
    if (blockindex->pnext)
        result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));

    result.push_back(Pair(
        "flags", strprintf("%s%s", blockindex->IsProofOfStake() ? "proof-of-stake" : "proof-of-work",
                           blockindex->GeneratedStakeModifier() ? " stake-modifier" : "")));
    result.push_back(Pair("proofhash", blockindex->hashProof.GetHex()));
    result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit()));
    result.push_back(Pair("modifier", strprintf("%016" PRIx64, blockindex->nStakeModifier)));
    result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
    Array txinfo;
    BOOST_FOREACH (const CTransaction& tx, block.vtx) {
        if (fPrintTransactionDetail) {
            Object entry;

            entry.push_back(Pair("txid", tx.GetHash().GetHex()));
            TxToJSON(tx, 0, entry);

            txinfo.push_back(entry);
        } else
            txinfo.push_back(tx.GetHash().GetHex());
    }

    result.push_back(Pair("tx", txinfo));

    if (block.IsProofOfStake())
        result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end())));

    return result;
}

Value getbestblockhash(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error("getbestblockhash\n"
                            "Returns the hash of the best block in the longest block chain.");

    return hashBestChain.GetHex();
}

Value getblockcount(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error("getblockcount\n"
                            "Returns the number of blocks in the longest block chain.");

    return nBestHeight.load();
}

Value getdifficulty(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error("getdifficulty\n"
                            "Returns the difficulty as a multiple of the minimum difficulty.");

    Object obj;
    obj.push_back(Pair("proof-of-work", GetDifficulty()));
    obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
    obj.push_back(Pair("search-interval", (int)nLastCoinStakeSearchInterval));
    return obj;
}

Value settxfee(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
        throw runtime_error("settxfee <amount>\n"
                            "<amount> is a real and is rounded to the nearest 0.01");

    nTransactionFee = AmountFromValue(params[0]);
    nTransactionFee = (nTransactionFee / MIN_TX_FEE) * MIN_TX_FEE; // round to nearest 0.0001

    return true;
}

Value getrawmempool(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error("getrawmempool\n"
                            "Returns all transaction ids in memory pool.");

    vector<uint256> vtxid;
    mempool.queryHashes(vtxid);

    Array a;
    BOOST_FOREACH (const uint256& hash, vtxid)
        a.push_back(hash.ToString());

    return a;
}

Value getblockhash(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error("getblockhash <index>\n"
                            "Returns hash of block in best-block-chain at <index>.");

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > nBestHeight)
        throw runtime_error("Block number out of range.");

    CBlockIndex* pblockindex = FindBlockByHeight(nHeight);
    return pblockindex->phashBlock->GetHex();
}

// Experimentally deprecated in an effort to support the getblock() call electrum requires
// Value getblock(const Array& params, bool fHelp)
// {
//     if (fHelp || params.size() < 1 || params.size() > 2)
//         throw runtime_error(
//             "getblock <hash> [txinfo]\n"
//             "txinfo optional to print more detailed tx info\n"
//             "Returns details of a block with given block-hash.");

//     std::string strHash = params[0].get_str();
//     uint256 hash(strHash);

//     if (mapBlockIndex.count(hash) == 0)
//         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

//     CBlock block;
//     CBlockIndex* pblockindex = mapBlockIndex[hash];
//     block.ReadFromDisk(pblockindex, true);

//     return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
// }

Value getblock(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getblock <hash> [verbose=true]\n"
            "If verbose is false, returns a string that is serialized, hex-encoded data for block "
            "<hash>.\n"
            "If verbose is true, returns an Object with information about block <hash> and information about each transaction.");

    std::string strHash = params[0].get_str();
    uint256     hash(strHash);

    bool fVerbose = true;
    if (params.size() > 1)
        fVerbose = params[1].get_bool();

    if (mapBlockIndex.count(hash) == 0)
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

    CBlock       block;
    CBlockIndex* pblockindex = mapBlockIndex[hash];
    block.ReadFromDisk(pblockindex, true);

    if (!fVerbose) {
        CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
        ssBlock << block;
        std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
        return strHex;
    }

    return blockToJSON(block, pblockindex, true);
}

Value getblockbynumber(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error("getblockbynumber <number> [txinfo]\n"
                            "txinfo optional to print more detailed tx info\n"
                            "Returns details of a block with given block-number.");

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > nBestHeight)
        throw runtime_error("Block number out of range.");

    CBlock       block;
    CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
    while (pblockindex->nHeight > nHeight)
        pblockindex = pblockindex->pprev;

    uint256 hash = *pblockindex->phashBlock;

    pblockindex = mapBlockIndex[hash];
    block.ReadFromDisk(pblockindex, true);

    return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
}

// ppcoin: get information of sync-checkpoint
Value getcheckpoint(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error("getcheckpoint\n"
                            "Show info of synchronized checkpoint.\n");

    Object       result;
    CBlockIndex* pindexCheckpoint;

    result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
    pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
    result.push_back(Pair("height", pindexCheckpoint->nHeight));
    result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));

    // Check that the block satisfies synchronized checkpoint
    if (CheckpointsMode == Checkpoints::STRICT)
        result.push_back(Pair("policy", "strict"));

    if (CheckpointsMode == Checkpoints::ADVISORY)
        result.push_back(Pair("policy", "advisory"));

    if (CheckpointsMode == Checkpoints::PERMISSIVE)
        result.push_back(Pair("policy", "permissive"));

    if (mapArgs.count("-checkpointkey"))
        result.push_back(Pair("checkpointmaster", true));

    return result;
}

Value exportblockchain(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 1)
        throw runtime_error("exportblockchain <path-dir>\n"
                            "Exports the blockchain bootstrap.dat file to <path-dir>.\n"
                            "<path-dir> must be a directory that exists.");

    boost::filesystem::path bdir(params[0].get_str());
    if (!boost::filesystem::exists(bdir))
        throw runtime_error("Directory " + bdir.string() + " does not exist.");

    boost::filesystem::path filename = bdir / "bootstrap.dat";

    boost::promise<void>       finished;
    boost::unique_future<void> finished_future = finished.get_future();
    std::atomic<bool>          stopped{false};
    std::atomic<double>        progress{false};
    boost::thread              exporterThread(boost::bind(&ExportBootstrapBlockchain, filename.string(),
                                             boost::ref(stopped), boost::ref(progress),
                                             boost::ref(finished)));
    exporterThread.detach();

    printf("Export blockchain to path started in another thread. Writing to path: %s\n",
           filename.string().c_str());

    int progVal            = 0;
    int lastPrintedProgVal = -1;
    while (!finished_future.is_ready()) {
        progVal = static_cast<int>(progress.load() * 100);
        if (progVal > lastPrintedProgVal) {
            printf("Export blockchain progress: %i%%\n", progVal);
            lastPrintedProgVal = progVal;
        }
        boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
        if (fShutdown) {
            stopped.store(true);
        }
    }

    finished_future.get(); // throws, but that's compatible with exception handle in this function

    printf("Export blockchain to path %s is done.\n", filename.string().c_str());

    return Value();
}
<|endoftext|>


<commit_before>/*
 * DesktopWebPage.cpp
 *
 * Copyright (C) 2009-18 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "DesktopWebPage.hpp"

#include <boost/algorithm/string.hpp>

#include <core/Thread.hpp>

#include <QFileDialog>
#include <QWebEngineSettings>

#include "DesktopDownloadItemHelper.hpp"
#include "DesktopMainWindow.hpp"
#include "DesktopSatelliteWindow.hpp"
#include "DesktopSecondaryWindow.hpp"
#include "DesktopWebProfile.hpp"
#include "DesktopWindowTracker.hpp"

using namespace rstudio::core;

extern QString sharedSecret;

namespace rstudio {
namespace desktop {

namespace {

WindowTracker s_windowTracker;
std::mutex s_mutex;

void onDownloadRequested(QWebEngineDownloadItem* downloadItem)
{
   // request directory from user
   QString downloadPath = QFileDialog::getSaveFileName(
            nullptr,
            QStringLiteral("Save File"),
            downloadItem->path());

   if (downloadPath.isEmpty())
      return;

   DownloadHelper::manageDownload(downloadItem, downloadPath);
}

} // anonymous namespace

WebPage::WebPage(QUrl baseUrl, QWidget *parent, bool allowExternalNavigate) :
      QWebEnginePage(new WebProfile(baseUrl, parent)),
      baseUrl_(baseUrl),
      allowExternalNav_(allowExternalNavigate)
{
   settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true);
   settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);
   settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true);
   settings()->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, true);
   settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);

   defaultSaveDir_ = QDir::home();
   connect(this, SIGNAL(windowCloseRequested()), SLOT(closeRequested()));
   connect(profile(), &QWebEngineProfile::downloadRequested, onDownloadRequested);
}

void WebPage::setBaseUrl(const QUrl& baseUrl)
{
   const WebProfile* pProfile = dynamic_cast<const WebProfile*>(profile());
   if (pProfile != nullptr)
   {
      // if we're using our own WebProfile implementation, update its base URL
      const_cast<WebProfile*>(pProfile)->setBaseUrl(baseUrl);
   }

   baseUrl_ = baseUrl;
}

void WebPage::activateWindow(QString name)
{
   BrowserWindow* pWindow = s_windowTracker.getWindow(name);
   if (pWindow)
      desktop::raiseAndActivateWindow(pWindow);
}

void WebPage::closeWindow(QString name)
{
   BrowserWindow* pWindow = s_windowTracker.getWindow(name);
   if (pWindow)
      desktop::closeWindow(pWindow);
}

void WebPage::prepareForWindow(const PendingWindow& pendingWindow)
{
   std::lock_guard<std::mutex> lock(s_mutex);

   pendingWindows_.push(pendingWindow);
}

QWebEnginePage* WebPage::createWindow(QWebEnginePage::WebWindowType type)
{
   std::lock_guard<std::mutex> lock(s_mutex);

   QString name;
   bool isSatellite = false;
   bool showToolbar = true;
   bool allowExternalNavigate = false;
   int width = 0;
   int height = 0;
   int x = -1;
   int y = -1;
   MainWindow* pMainWindow = nullptr;
   BrowserWindow* pWindow = nullptr;
   bool show = true;

   // check if this is target="_blank";
   if (type == QWebEnginePage::WebWindowType::WebBrowserTab)
   {
      // QtWebEngine behavior is to open a new browser window and send it the
      // acceptNavigationRequest we use to redirect to system browser; don't want
      // that to be visible
      show = false;
      name = tr("_blank_redirector");

      // check for an existing hidden window
      pWindow = s_windowTracker.getWindow(name);
      if (pWindow)
      {
         return pWindow->webView()->webPage();
      }
   }

   // check if we have a satellite window waiting to come up
   if (!pendingWindows_.empty())
   {
      // retrieve the window
      PendingWindow pendingWindow = pendingWindows_.front();
      pendingWindows_.pop();

      // capture pending window params then clear them (one time only)
      name = pendingWindow.name;
      isSatellite = pendingWindow.isSatellite;
      showToolbar = pendingWindow.showToolbar;
      pMainWindow = pendingWindow.pMainWindow;
      allowExternalNavigate = pendingWindow.allowExternalNavigate;

      // get width and height, and adjust for high DPI
      double dpiZoomScaling = getDpiZoomScaling();
      width = pendingWindow.width * dpiZoomScaling;
      height = pendingWindow.height * dpiZoomScaling;
      x = pendingWindow.x;
      y = pendingWindow.y;

      // check for an existing window of this name
      pWindow = s_windowTracker.getWindow(name);
      if (pWindow)
      {
         // activate the browser then return NULL to indicate
         // we didn't create a new WebView
         desktop::raiseAndActivateWindow(pWindow);
         return nullptr;
      }
   }

   if (isSatellite)
   {
      // create and size
      pWindow = new SatelliteWindow(pMainWindow, name);
      pWindow->resize(width, height);

      if (x >= 0 && y >= 0)
      {
         // if the window specified its location, use it
         pWindow->move(x, y);
      }
      else if (name != QString::fromUtf8("pdf"))
      {
         // window location was left for us to determine; try to tile the window
         // (but leave pdf window alone since it is so large)

         // calculate location to move to

         // y always attempts to be 25 pixels above then faults back
         // to 25 pixels below if that would be offscreen
         const int OVERLAP = 25;
         int moveY = pMainWindow->y() - OVERLAP;
         if (moveY < 0)
            moveY = pMainWindow->y() + OVERLAP;

         // x is based on centering over main window
         int moveX = pMainWindow->x() +
               (pMainWindow->width() / 2) -
               (width / 2);

         // perform move
         pWindow->move(moveX, moveY);
      }
   }
   else
   {
      pWindow = new SecondaryWindow(showToolbar, name, baseUrl_, nullptr, this,
                                    allowExternalNavigate);
   }

   // if we have a name set, start tracking this window
   if (!name.isEmpty())
   {
      s_windowTracker.addWindow(name, pWindow);
   }

   // show and return the browser
   if (show)
      pWindow->show();
   return pWindow->webView()->webPage();
}

void WebPage::closeRequested()
{
   // invoked when close is requested via script (i.e. window.close()); honor
   // this request by closing the window in which the view is hosted
   view()->window()->close();
}

bool WebPage::shouldInterruptJavaScript()
{
   return false;
}

void WebPage::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel /*level*/, const QString& message,
                                       int /*lineNumber*/, const QString& /*sourceID*/)
{
   qDebug() << message;
}

// NOTE: NavigationType is unreliable, as per:
//
//    https://bugreports.qt.io/browse/QTBUG-56805
//
// so we avoid querying it here.
bool WebPage::acceptNavigationRequest(const QUrl &url,
                                      NavigationType /* navType*/,
                                      bool isMainFrame)
{
   if (url.toString() == QStringLiteral("about:blank"))
      return true;

   if (url.scheme() != QStringLiteral("http") &&
       url.scheme() != QStringLiteral("https") &&
       url.scheme() != QStringLiteral("mailto") &&
       url.scheme() != QStringLiteral("data"))
   {
      qDebug() << url.toString();
      return false;
   }

   // determine if this is a local request (handle internally only if local)
   std::string host = url.host().toStdString();
   bool isLocal = host == "localhost" || host == "127.0.0.1";

   if ((baseUrl_.isEmpty() && isLocal) ||
       (url.scheme() == baseUrl_.scheme() &&
        url.host() == baseUrl_.host() &&
        url.port() == baseUrl_.port()))
   {
      return true;
   }
   // allow viewer urls to be handled internally by Qt. note that the client is responsible for
   // ensuring that non-local viewer urls are appropriately sandboxed.
   else if (!viewerUrl_.isEmpty() &&
            url.toString().startsWith(viewerUrl_))
   {
      return true;
   }
   // allow shiny dialog urls to be handled internally by Qt
   else if (isLocal && !shinyDialogUrl_.isEmpty() &&
            url.toString().startsWith(shinyDialogUrl_))
   {
      return true;
   }
   else
   {
      bool navigated = false;

      if (allowExternalNav_)
      {
         // if allowing external navigation, follow this (even if a link click)
         return true;
      }
      else if (boost::algorithm::ends_with(host, ".youtube.com") ||
               boost::algorithm::ends_with(host, ".vimeo.com")   ||
               boost::algorithm::ends_with(host, ".c9.ms"))
      {
         return true;
      }
      else
      {
         // when not allowing external navigation, open an external browser
         // to view the URL
         desktop::openUrl(url);
         navigated = true;
      }

      if (!navigated)
         this->view()->window()->deleteLater();

      return false;
   }
}

void WebPage::setViewerUrl(const QString& viewerUrl)
{
   // record about:blank literally
   if (viewerUrl == QString::fromUtf8("about:blank"))
   {
      viewerUrl_ = viewerUrl;
      return;
   }

   // extract the authority (domain and port) from the URL; we'll agree to
   // serve requests for the viewer pane that match this prefix.
   QUrl url(viewerUrl);
   viewerUrl_ = url.scheme() + QString::fromUtf8("://") +
                url.authority() + QString::fromUtf8("/");
}

void WebPage::setShinyDialogUrl(const QString &shinyDialogUrl)
{
   shinyDialogUrl_ = shinyDialogUrl;
}

void WebPage::triggerAction(WebAction action, bool checked)
{
   QWebEnginePage::triggerAction(action, checked);
}

} // namespace desktop
} // namespace rstudio
<commit_msg>pass parent to correct constructor; fixes downstream crash after closure<commit_after>/*
 * DesktopWebPage.cpp
 *
 * Copyright (C) 2009-18 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "DesktopWebPage.hpp"

#include <boost/algorithm/string.hpp>

#include <core/Thread.hpp>

#include <QFileDialog>
#include <QWebEngineSettings>

#include "DesktopDownloadItemHelper.hpp"
#include "DesktopMainWindow.hpp"
#include "DesktopSatelliteWindow.hpp"
#include "DesktopSecondaryWindow.hpp"
#include "DesktopWebProfile.hpp"
#include "DesktopWindowTracker.hpp"

using namespace rstudio::core;

extern QString sharedSecret;

namespace rstudio {
namespace desktop {

namespace {

WindowTracker s_windowTracker;
std::mutex s_mutex;

void onDownloadRequested(QWebEngineDownloadItem* downloadItem)
{
   // request directory from user
   QString downloadPath = QFileDialog::getSaveFileName(
            nullptr,
            QStringLiteral("Save File"),
            downloadItem->path());

   if (downloadPath.isEmpty())
      return;

   DownloadHelper::manageDownload(downloadItem, downloadPath);
}

} // anonymous namespace

WebPage::WebPage(QUrl baseUrl, QWidget *parent, bool allowExternalNavigate) :
      QWebEnginePage(new WebProfile(baseUrl), parent),
      baseUrl_(baseUrl),
      allowExternalNav_(allowExternalNavigate)
{
   settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true);
   settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);
   settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true);
   settings()->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, true);
   settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);

   defaultSaveDir_ = QDir::home();
   connect(this, SIGNAL(windowCloseRequested()), SLOT(closeRequested()));
   connect(profile(), &QWebEngineProfile::downloadRequested, onDownloadRequested);
}

void WebPage::setBaseUrl(const QUrl& baseUrl)
{
   const WebProfile* pProfile = dynamic_cast<const WebProfile*>(profile());
   if (pProfile != nullptr)
   {
      // if we're using our own WebProfile implementation, update its base URL
      const_cast<WebProfile*>(pProfile)->setBaseUrl(baseUrl);
   }

   baseUrl_ = baseUrl;
}

void WebPage::activateWindow(QString name)
{
   BrowserWindow* pWindow = s_windowTracker.getWindow(name);
   if (pWindow)
      desktop::raiseAndActivateWindow(pWindow);
}

void WebPage::closeWindow(QString name)
{
   BrowserWindow* pWindow = s_windowTracker.getWindow(name);
   if (pWindow)
      desktop::closeWindow(pWindow);
}

void WebPage::prepareForWindow(const PendingWindow& pendingWindow)
{
   std::lock_guard<std::mutex> lock(s_mutex);

   pendingWindows_.push(pendingWindow);
}

QWebEnginePage* WebPage::createWindow(QWebEnginePage::WebWindowType type)
{
   std::lock_guard<std::mutex> lock(s_mutex);

   QString name;
   bool isSatellite = false;
   bool showToolbar = true;
   bool allowExternalNavigate = false;
   int width = 0;
   int height = 0;
   int x = -1;
   int y = -1;
   MainWindow* pMainWindow = nullptr;
   BrowserWindow* pWindow = nullptr;
   bool show = true;

   // check if this is target="_blank";
   if (type == QWebEnginePage::WebWindowType::WebBrowserTab)
   {
      // QtWebEngine behavior is to open a new browser window and send it the
      // acceptNavigationRequest we use to redirect to system browser; don't want
      // that to be visible
      show = false;
      name = tr("_blank_redirector");

      // check for an existing hidden window
      pWindow = s_windowTracker.getWindow(name);
      if (pWindow)
      {
         return pWindow->webView()->webPage();
      }
   }

   // check if we have a satellite window waiting to come up
   if (!pendingWindows_.empty())
   {
      // retrieve the window
      PendingWindow pendingWindow = pendingWindows_.front();
      pendingWindows_.pop();

      // capture pending window params then clear them (one time only)
      name = pendingWindow.name;
      isSatellite = pendingWindow.isSatellite;
      showToolbar = pendingWindow.showToolbar;
      pMainWindow = pendingWindow.pMainWindow;
      allowExternalNavigate = pendingWindow.allowExternalNavigate;

      // get width and height, and adjust for high DPI
      double dpiZoomScaling = getDpiZoomScaling();
      width = pendingWindow.width * dpiZoomScaling;
      height = pendingWindow.height * dpiZoomScaling;
      x = pendingWindow.x;
      y = pendingWindow.y;

      // check for an existing window of this name
      pWindow = s_windowTracker.getWindow(name);
      if (pWindow)
      {
         // activate the browser then return NULL to indicate
         // we didn't create a new WebView
         desktop::raiseAndActivateWindow(pWindow);
         return nullptr;
      }
   }

   if (isSatellite)
   {
      // create and size
      pWindow = new SatelliteWindow(pMainWindow, name);
      pWindow->resize(width, height);

      if (x >= 0 && y >= 0)
      {
         // if the window specified its location, use it
         pWindow->move(x, y);
      }
      else if (name != QString::fromUtf8("pdf"))
      {
         // window location was left for us to determine; try to tile the window
         // (but leave pdf window alone since it is so large)

         // calculate location to move to

         // y always attempts to be 25 pixels above then faults back
         // to 25 pixels below if that would be offscreen
         const int OVERLAP = 25;
         int moveY = pMainWindow->y() - OVERLAP;
         if (moveY < 0)
            moveY = pMainWindow->y() + OVERLAP;

         // x is based on centering over main window
         int moveX = pMainWindow->x() +
               (pMainWindow->width() / 2) -
               (width / 2);

         // perform move
         pWindow->move(moveX, moveY);
      }
   }
   else
   {
      pWindow = new SecondaryWindow(showToolbar, name, baseUrl_, nullptr, this,
                                    allowExternalNavigate);
   }

   // if we have a name set, start tracking this window
   if (!name.isEmpty())
   {
      s_windowTracker.addWindow(name, pWindow);
   }

   // show and return the browser
   if (show)
      pWindow->show();
   return pWindow->webView()->webPage();
}

void WebPage::closeRequested()
{
   // invoked when close is requested via script (i.e. window.close()); honor
   // this request by closing the window in which the view is hosted
   view()->window()->close();
}

bool WebPage::shouldInterruptJavaScript()
{
   return false;
}

void WebPage::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel /*level*/, const QString& message,
                                       int /*lineNumber*/, const QString& /*sourceID*/)
{
   qDebug() << message;
}

// NOTE: NavigationType is unreliable, as per:
//
//    https://bugreports.qt.io/browse/QTBUG-56805
//
// so we avoid querying it here.
bool WebPage::acceptNavigationRequest(const QUrl &url,
                                      NavigationType /* navType*/,
                                      bool isMainFrame)
{
   if (url.toString() == QStringLiteral("about:blank"))
      return true;

   if (url.scheme() != QStringLiteral("http") &&
       url.scheme() != QStringLiteral("https") &&
       url.scheme() != QStringLiteral("mailto") &&
       url.scheme() != QStringLiteral("data"))
   {
      qDebug() << url.toString();
      return false;
   }

   // determine if this is a local request (handle internally only if local)
   std::string host = url.host().toStdString();
   bool isLocal = host == "localhost" || host == "127.0.0.1";

   if ((baseUrl_.isEmpty() && isLocal) ||
       (url.scheme() == baseUrl_.scheme() &&
        url.host() == baseUrl_.host() &&
        url.port() == baseUrl_.port()))
   {
      return true;
   }
   // allow viewer urls to be handled internally by Qt. note that the client is responsible for
   // ensuring that non-local viewer urls are appropriately sandboxed.
   else if (!viewerUrl_.isEmpty() &&
            url.toString().startsWith(viewerUrl_))
   {
      return true;
   }
   // allow shiny dialog urls to be handled internally by Qt
   else if (isLocal && !shinyDialogUrl_.isEmpty() &&
            url.toString().startsWith(shinyDialogUrl_))
   {
      return true;
   }
   else
   {
      bool navigated = false;

      if (allowExternalNav_)
      {
         // if allowing external navigation, follow this (even if a link click)
         return true;
      }
      else if (boost::algorithm::ends_with(host, ".youtube.com") ||
               boost::algorithm::ends_with(host, ".vimeo.com")   ||
               boost::algorithm::ends_with(host, ".c9.ms"))
      {
         return true;
      }
      else
      {
         // when not allowing external navigation, open an external browser
         // to view the URL
         desktop::openUrl(url);
         navigated = true;
      }

      if (!navigated)
         this->view()->window()->deleteLater();

      return false;
   }
}

void WebPage::setViewerUrl(const QString& viewerUrl)
{
   // record about:blank literally
   if (viewerUrl == QString::fromUtf8("about:blank"))
   {
      viewerUrl_ = viewerUrl;
      return;
   }

   // extract the authority (domain and port) from the URL; we'll agree to
   // serve requests for the viewer pane that match this prefix.
   QUrl url(viewerUrl);
   viewerUrl_ = url.scheme() + QString::fromUtf8("://") +
                url.authority() + QString::fromUtf8("/");
}

void WebPage::setShinyDialogUrl(const QString &shinyDialogUrl)
{
   shinyDialogUrl_ = shinyDialogUrl;
}

void WebPage::triggerAction(WebAction action, bool checked)
{
   QWebEnginePage::triggerAction(action, checked);
}

} // namespace desktop
} // namespace rstudio
<|endoftext|>