static void test_underflow(skiatest::Reporter* reporter) {
    SkPoint pt = { 1.0e-37f, 1.0e-37f };
    SkPoint copy = pt;

    REPORTER_ASSERT(reporter, 0 == SkPoint::Normalize(&pt));
    REPORTER_ASSERT(reporter, pt == copy);  // pt is unchanged

    REPORTER_ASSERT(reporter, !pt.setLength(SK_Scalar1));
    REPORTER_ASSERT(reporter, pt == copy);  // pt is unchanged
}

/*
 *
 */
// Unit tests for src/core/SkPoint.cpp and its header

#include "SkPoint.h"
#include "SkRect.h"
#include "Test.h"

static void test_casts(skiatest::Reporter* reporter) {
    SkPoint p = { 0, 0 };
    SkRect  r = { 0, 0, 0, 0 };

    const SkScalar* pPtr = SkTCast<const SkScalar*>(&p);
    const SkScalar* rPtr = SkTCast<const SkScalar*>(&r);

    REPORTER_ASSERT(reporter, p.asScalars() == pPtr);
    REPORTER_ASSERT(reporter, r.asScalars() == rPtr);
}

static void test_Normalize(skiatest::Reporter* reporter,
                           SkScalar x, SkScalar y) {
    SkPoint point;
    point.set(x, y);
    SkScalar oldLength = point.length();
    SkScalar returned = SkPoint::Normalize(&point);
    SkScalar newLength = point.length();
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(returned, oldLength));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(newLength, SK_Scalar1));
}

// Tests that SkPoint::length() and SkPoint::Length() both return
static void test_length(skiatest::Reporter* reporter, SkScalar x, SkScalar y,
                        SkScalar expectedLength) {
    SkPoint point;
    point.set(x, y);
    SkScalar s1 = point.length();
    SkScalar s2 = SkPoint::Length(x, y);
    //The following should be exactly the same, but need not be.
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(s1, s2));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(s1, expectedLength));

    test_Normalize(reporter, x, y);
}

// Ugh. Windows compiler can dive into other .cpp files, and sometimes
// notices that I will generate an overflow... which is exactly the point
// To avoid this warning, I need to convince the compiler that I might not
// use that big value, hence this hacky helper function: reporter is
// ALWAYS non-null. (shhhhhh, don't tell the compiler that).
template <typename T> T get_value(skiatest::Reporter* reporter, T value) {
    return reporter ? value : 0;
}

// On linux gcc, 32bit, we are seeing the compiler propagate up the value
// of SkPoint::length() as a double (which we use sometimes to avoid overflow
// during the computation), even though the signature says float (SkScalar).
// force_as_float is meant to capture our latest technique (horrible as
// it is) to force the value to be a float, so we can test whether it was
// finite or not.
static float force_as_float(skiatest::Reporter* reporter, float value) {
    uint32_t storage;
    memcpy(&storage, &value, 4);
    // even the pair of memcpy calls are not sufficient, since those seem to
    // be no-op'd, so we add a runtime tests (just like get_value) to force
    // the compiler to give us an actual float.
    if (NULL == reporter) {
        storage = ~storage;
    }
    memcpy(&value, &storage, 4);
    return value;
}

// test that we handle very large values correctly. i.e. that we can
// successfully normalize something whose mag overflows a float.
static void test_overflow(skiatest::Reporter* reporter) {
    SkScalar bigFloat = get_value(reporter, 3.4e38f);
    SkPoint pt = { bigFloat, bigFloat };

    SkScalar length = pt.length();
    length = force_as_float(reporter, length);

    // expect this to be non-finite, but dump the results if not.
    if (SkScalarIsFinite(length)) {
        SkDebugf("length(%g, %g) == %g\n", pt.fX, pt.fY, length);
        REPORTER_ASSERT(reporter, !SkScalarIsFinite(length));
    }

    // this should succeed, even though we can't represent length
    REPORTER_ASSERT(reporter, pt.setLength(SK_Scalar1));

    // now that pt is normalized, we check its length
    length = pt.length();
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(length, SK_Scalar1));
}

// test that we handle very small values correctly. i.e. that we can
// report failure if we try to normalize them.

DEF_TEST(Point, reporter) {
    test_casts(reporter);

    static const struct {
        SkScalar fX;
        SkScalar fY;
        SkScalar fLength;
    } gRec[] = {
        { SkIntToScalar(3), SkIntToScalar(4), SkIntToScalar(5) },
        { 0.6f, 0.8f, SK_Scalar1 },
    };

    for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
        test_length(reporter, gRec[i].fX, gRec[i].fY, gRec[i].fLength);
    }

    test_underflow(reporter);
    test_overflow(reporter);
}

DEF_TEST(Point_setLengthFast, reporter) {
    // Scale a (1,1) point to a bunch of different lengths,
    // making sure the slow and fast paths are within 0.1%.
    const float tests[] = { 1.0f, 0.0f, 1.0e-37f, 3.4e38f, 42.0f, 0.00012f };

    const SkPoint kOne = {1.0f, 1.0f};
    for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); i++) {
        SkPoint slow = kOne, fast = kOne;

        slow.setLength(tests[i]);
        fast.setLengthFast(tests[i]);

        if (slow.length() < FLT_MIN && fast.length() < FLT_MIN) continue;

        SkScalar ratio = slow.length() / fast.length();
        REPORTER_ASSERT(reporter, ratio > 0.999f);
        REPORTER_ASSERT(reporter, ratio < 1.001f);
    }
}


SharableMemBlockNode::SharableMemBlockNode(int64_t chain_id,
                                           const HashSet<const RegstDescProto*>& regst_descs)
    : chain_id_(chain_id), regst_descs_(regst_descs.begin(), regst_descs.end()) {}

/*

*/
#include "oneflow/core/graph/sharable_mem_block_graph.h"
#include "oneflow/core/register/register_desc.h"
#include "oneflow/core/register/runtime_register_desc.h"
#include "oneflow/core/graph/inplace_regst_graph.h"

namespace oneflow {

namespace {

bool IsConsumersAndProducerInSameChain(const RegstDescProto& regst_desc,
                                       const PlanTaskGraph& plan_task_graph) {
  auto ChainId4TaskId = [&](int64_t task_id) {
    return plan_task_graph.TaskProto4TaskId(task_id)->task_set_info().chain_id();
  };
  int64_t producer_chain_id = ChainId4TaskId(regst_desc.producer_task_id());
  for (int64_t consumer_task_id : regst_desc.consumer_task_id()) {
    if (ChainId4TaskId(consumer_task_id) != producer_chain_id) { return false; }
  }
  return true;
}
void ForEachInplacedRegstDescs(
    const HashSet<const RegstDescProto*> regst_desc,
    const std::function<void(const HashSet<const RegstDescProto*>&)>& Handler) {
  InplaceRegstGraph inplace_gph(regst_desc);
  inplace_gph.ForEachConnectedComponent([&](const HashSet<const InplaceRegstNode*>& nodes) {
    if (nodes.size() == 1) { return; }
    HashSet<const RegstDescProto*> regst_descs;
    for (const auto* node : nodes) { CHECK(regst_descs.emplace(node->regst_desc()).second); }
    Handler(regst_descs);
  });
}

}  // namespace

SharableMemBlockGraph::SharableMemBlockGraph(
    const PlanTaskGraph& plan_task_gph,
    const std::function<bool(const RegstDescProto&)>& IsSharable) {
  HashMap<int64_t, HashSet<const RegstDescProto*>> chain_id2regst_descs;
  for (const TaskProto& task : plan_task_gph.plan().task()) {
    for (const auto& pair : task.produced_regst_desc()) {
      if (IsConsumersAndProducerInSameChain(pair.second, plan_task_gph)
          && IsSharable(pair.second)) {
        CHECK(chain_id2regst_descs[task.task_set_info().chain_id()].emplace(&pair.second).second);
      }
    }
  }
  for (const auto& pair : chain_id2regst_descs) {
    HashMap<const RegstDescProto*, SharableMemBlockNode*> regst_desc2node;
    for (const auto* regst_desc : pair.second) {
      auto* node = new SharableMemBlockNode(pair.first, {regst_desc});
      AddAllocatedNode(node);
      CHECK(regst_desc2node.emplace(regst_desc, node).second);
    }
    ForEachInplacedRegstDescs(pair.second, [&](const HashSet<const RegstDescProto*>& regst_descs) {
      auto* parent = new SharableMemBlockNode(pair.first, regst_descs);
      AddAllocatedNode(parent);
      for (const RegstDescProto* regst_desc : regst_descs) {
        auto* edge = new SharableMemBlockEdge();
        AddAllocatedEdge(edge);
        Connect(parent, edge, regst_desc2node.at(regst_desc));
      }
    });
  }
}

void SharableMemBlockGraph::ForEachSourceNodeGroup(
    const std::function<int64_t(const SharableMemBlockNode*)>& GroupBy,
    const std::function<void(const std::vector<const SharableMemBlockNode*>&)>& Handler) const {
  HashMap<int64_t, std::vector<const SharableMemBlockNode*>> group_key2source_nodes;
  for (const SharableMemBlockNode* source : source_nodes()) {
    group_key2source_nodes[GroupBy(source)].push_back(source);
  }
  for (const auto& pair : group_key2source_nodes) {
    if (pair.second.size() > 1) { Handler(pair.second); }
  }
}

}  // namespace oneflow


void PVRTTransformArrayBack(
	PVRTVECTOR3			* const pTransformedVertex,
	const PVRTVECTOR3	* const pVertex,
	const int			nNumberOfVertices,
	const PVRTMATRIX	* const pMatrix)
{
	PVRTMATRIX	mBack;

	PVRTMatrixInverse(mBack, *pMatrix);
	PVRTTransformArray(pTransformedVertex, pVertex, nNumberOfVertices, &mBack);
}

/******************************************************************************

 @File         PVRTTrans.cpp

 @Title        PVRTTrans

 @Version

 @Platform     ANSI compatible

 @Description  Set of functions used for 3D transformations and projections.

******************************************************************************/
#include <string.h>

#include "PVRTGlobal.h"
#include "PVRTContext.h"
#include "PVRTFixedPoint.h"
#include "PVRTMatrix.h"
#include "PVRTTrans.h"

/****************************************************************************
** Functions
****************************************************************************/

/*!***************************************************************************
 @Function			PVRTBoundingBoxCompute
 @Output			pBoundingBox
 @Input				pV
 @Input				nNumberOfVertices
 @Description		Calculate the eight vertices that surround an object.
					This "bounding box" is used later to determine whether
					the object is visible or not.
					This function should only be called once to determine the
					object's bounding box.
*****************************************************************************/
void PVRTBoundingBoxCompute(
	PVRTBOUNDINGBOX		* const pBoundingBox,
	const PVRTVECTOR3	* const pV,
	const int			nNumberOfVertices)
{
	int			i;
	VERTTYPE	MinX, MaxX, MinY, MaxY, MinZ, MaxZ;

	/* Inialise values to first vertex */
	MinX=pV->x;	MaxX=pV->x;
	MinY=pV->y;	MaxY=pV->y;
	MinZ=pV->z;	MaxZ=pV->z;

	/* Loop through all vertices to find extremas */
	for (i=1; i<nNumberOfVertices; i++)
	{
		/* Minimum and Maximum X */
		if (pV[i].x < MinX) MinX = pV[i].x;
		if (pV[i].x > MaxX) MaxX = pV[i].x;

		/* Minimum and Maximum Y */
		if (pV[i].y < MinY) MinY = pV[i].y;
		if (pV[i].y > MaxY) MaxY = pV[i].y;

		/* Minimum and Maximum Z */
		if (pV[i].z < MinZ) MinZ = pV[i].z;
		if (pV[i].z > MaxZ) MaxZ = pV[i].z;
	}

	/* Assign the resulting extremas to the bounding box structure */
	/* Point 0 */
	pBoundingBox->Point[0].x=MinX;
	pBoundingBox->Point[0].y=MinY;
	pBoundingBox->Point[0].z=MinZ;

	/* Point 1 */
	pBoundingBox->Point[1].x=MinX;
	pBoundingBox->Point[1].y=MinY;
	pBoundingBox->Point[1].z=MaxZ;

	/* Point 2 */
	pBoundingBox->Point[2].x=MinX;
	pBoundingBox->Point[2].y=MaxY;
	pBoundingBox->Point[2].z=MinZ;

	/* Point 3 */
	pBoundingBox->Point[3].x=MinX;
	pBoundingBox->Point[3].y=MaxY;
	pBoundingBox->Point[3].z=MaxZ;

	/* Point 4 */
	pBoundingBox->Point[4].x=MaxX;
	pBoundingBox->Point[4].y=MinY;
	pBoundingBox->Point[4].z=MinZ;

	/* Point 5 */
	pBoundingBox->Point[5].x=MaxX;
	pBoundingBox->Point[5].y=MinY;
	pBoundingBox->Point[5].z=MaxZ;

	/* Point 6 */
	pBoundingBox->Point[6].x=MaxX;
	pBoundingBox->Point[6].y=MaxY;
	pBoundingBox->Point[6].z=MinZ;

	/* Point 7 */
	pBoundingBox->Point[7].x=MaxX;
	pBoundingBox->Point[7].y=MaxY;
	pBoundingBox->Point[7].z=MaxZ;
}

/*!***************************************************************************
 @Function			PVRTBoundingBoxComputeInterleaved
 @Output			pBoundingBox
 @Input				pV
 @Input				nNumberOfVertices
 @Input				i32Offset
 @Input				i32Stride
 @Description		Calculate the eight vertices that surround an object.
					This "bounding box" is used later to determine whether
					the object is visible or not.
					This function should only be called once to determine the
					object's bounding box.
					Takes interleaved data using the first vertex's offset
					and the stride to the next vertex thereafter
*****************************************************************************/
void PVRTBoundingBoxComputeInterleaved(
	PVRTBOUNDINGBOX		* const pBoundingBox,
	const unsigned char			* const pV,
	const int			nNumberOfVertices,
	const int			i32Offset,
	const int			i32Stride)
{
	int			i;
	VERTTYPE	MinX, MaxX, MinY, MaxY, MinZ, MaxZ;

	// point ot first vertex
	PVRTVECTOR3 *pVertex =(PVRTVECTOR3*)(pV+i32Offset);

	/* Inialise values to first vertex */
	MinX=pVertex->x;	MaxX=pVertex->x;
	MinY=pVertex->y;	MaxY=pVertex->y;
	MinZ=pVertex->z;	MaxZ=pVertex->z;

	/* Loop through all vertices to find extremas */
	for (i=1; i<nNumberOfVertices; i++)
	{
		pVertex = (PVRTVECTOR3*)( (unsigned char*)(pVertex)+i32Stride);

		/* Minimum and Maximum X */
		if (pVertex->x < MinX) MinX = pVertex->x;
		if (pVertex->x > MaxX) MaxX = pVertex->x;

		/* Minimum and Maximum Y */
		if (pVertex->y < MinY) MinY = pVertex->y;
		if (pVertex->y > MaxY) MaxY = pVertex->y;

		/* Minimum and Maximum Z */
		if (pVertex->z < MinZ) MinZ = pVertex->z;
		if (pVertex->z > MaxZ) MaxZ = pVertex->z;
	}

	/* Assign the resulting extremas to the bounding box structure */
	/* Point 0 */
	pBoundingBox->Point[0].x=MinX;
	pBoundingBox->Point[0].y=MinY;
	pBoundingBox->Point[0].z=MinZ;

	/* Point 1 */
	pBoundingBox->Point[1].x=MinX;
	pBoundingBox->Point[1].y=MinY;
	pBoundingBox->Point[1].z=MaxZ;

	/* Point 2 */
	pBoundingBox->Point[2].x=MinX;
	pBoundingBox->Point[2].y=MaxY;
	pBoundingBox->Point[2].z=MinZ;

	/* Point 3 */
	pBoundingBox->Point[3].x=MinX;
	pBoundingBox->Point[3].y=MaxY;
	pBoundingBox->Point[3].z=MaxZ;

	/* Point 4 */
	pBoundingBox->Point[4].x=MaxX;
	pBoundingBox->Point[4].y=MinY;
	pBoundingBox->Point[4].z=MinZ;

	/* Point 5 */
	pBoundingBox->Point[5].x=MaxX;
	pBoundingBox->Point[5].y=MinY;
	pBoundingBox->Point[5].z=MaxZ;

	/* Point 6 */
	pBoundingBox->Point[6].x=MaxX;
	pBoundingBox->Point[6].y=MaxY;
	pBoundingBox->Point[6].z=MinZ;

	/* Point 7 */
	pBoundingBox->Point[7].x=MaxX;
	pBoundingBox->Point[7].y=MaxY;
	pBoundingBox->Point[7].z=MaxZ;
}

/*!******************************************************************************
 @Function			PVRTBoundingBoxIsVisible
 @Output			pNeedsZClipping
 @Input				pBoundingBox
 @Input				pMatrix
 @Return			TRUE if the object is visible, FALSE if not.
 @Description		Determine if a bounding box is "visible" or not along the
					Z axis.
					If the function returns TRUE, the object is visible and should
					be displayed (check bNeedsZClipping to know if Z Clipping needs
					to be done).
					If the function returns FALSE, the object is not visible and thus
					does not require to be displayed.
					bNeedsZClipping indicates whether the object needs Z Clipping
					(i.e. the object is partially visible).
					- *pBoundingBox is a pointer to the bounding box structure.
					- *pMatrix is the World, View & Projection matrices combined.
					- *bNeedsZClipping is TRUE if Z clipping is required.
*****************************************************************************/
bool PVRTBoundingBoxIsVisible(
	const PVRTBOUNDINGBOX	* const pBoundingBox,
	const PVRTMATRIX		* const pMatrix,
	bool					* const pNeedsZClipping)
{
	VERTTYPE	fX, fY, fZ, fW;
	int			i, nX0, nX1, nY0, nY1, nZ;

	nX0 = 8;
	nX1 = 8;
	nY0 = 8;
	nY1 = 8;
	nZ  = 8;

	/* Transform the eight bounding box vertices */
	i = 8;
	while(i)
	{
		i--;
		fX =	pMatrix->f[ 0]*pBoundingBox->Point[i].x +
				pMatrix->f[ 4]*pBoundingBox->Point[i].y +
				pMatrix->f[ 8]*pBoundingBox->Point[i].z +
				pMatrix->f[12];
		fY =	pMatrix->f[ 1]*pBoundingBox->Point[i].x +
				pMatrix->f[ 5]*pBoundingBox->Point[i].y +
				pMatrix->f[ 9]*pBoundingBox->Point[i].z +
				pMatrix->f[13];
		fZ =	pMatrix->f[ 2]*pBoundingBox->Point[i].x +
				pMatrix->f[ 6]*pBoundingBox->Point[i].y +
				pMatrix->f[10]*pBoundingBox->Point[i].z +
				pMatrix->f[14];
		fW =	pMatrix->f[ 3]*pBoundingBox->Point[i].x +
				pMatrix->f[ 7]*pBoundingBox->Point[i].y +
				pMatrix->f[11]*pBoundingBox->Point[i].z +
				pMatrix->f[15];

		if(fX < -fW)
			nX0--;
		else if(fX > fW)
			nX1--;

		if(fY < -fW)
			nY0--;
		else if(fY > fW)
			nY1--;

		if(fZ < 0)
			nZ--;
	}

	if(nZ)
	{
		if(!(nX0 * nX1 * nY0 * nY1))
		{
			*pNeedsZClipping = false;
			return false;
		}

		if(nZ == 8)
		{
			*pNeedsZClipping = false;
			return true;
		}

		*pNeedsZClipping = true;
		return true;
	}
	else
	{
		*pNeedsZClipping = false;
		return false;
	}
}

/*!***************************************************************************
 @Function Name		PVRTTransformVec3Array
 @Output			pOut				Destination for transformed vectors
 @Input				nOutStride			Stride between vectors in pOut array
 @Input				pV					Input vector array
 @Input				nInStride			Stride between vectors in pV array
 @Input				pMatrix				Matrix to transform the vectors
 @Input				nNumberOfVertices	Number of vectors to transform
 @Description		Transform all vertices [X Y Z 1] in pV by pMatrix and
 					store them in pOut.
*****************************************************************************/
void PVRTTransformVec3Array(
	PVRTVECTOR4			* const pOut,
	const int			nOutStride,
	const PVRTVECTOR3	* const pV,
	const int			nInStride,
	const PVRTMATRIX	* const pMatrix,
	const int			nNumberOfVertices)
{
	const PVRTVECTOR3	*pSrc;
	PVRTVECTOR4			*pDst;
	int					i;

	pSrc = pV;
	pDst = pOut;

	/* Transform all vertices with *pMatrix */
	for (i=0; i<nNumberOfVertices; ++i)
	{
		pDst->x =	VERTTYPEMUL(pMatrix->f[ 0], pSrc->x) +
					VERTTYPEMUL(pMatrix->f[ 4], pSrc->y) +
					VERTTYPEMUL(pMatrix->f[ 8], pSrc->z) +
					pMatrix->f[12];
		pDst->y =	VERTTYPEMUL(pMatrix->f[ 1], pSrc->x) +
					VERTTYPEMUL(pMatrix->f[ 5], pSrc->y) +
					VERTTYPEMUL(pMatrix->f[ 9], pSrc->z) +
					pMatrix->f[13];
		pDst->z =	VERTTYPEMUL(pMatrix->f[ 2], pSrc->x) +
					VERTTYPEMUL(pMatrix->f[ 6], pSrc->y) +
					VERTTYPEMUL(pMatrix->f[10], pSrc->z) +
					pMatrix->f[14];
		pDst->w =	VERTTYPEMUL(pMatrix->f[ 3], pSrc->x) +
					VERTTYPEMUL(pMatrix->f[ 7], pSrc->y) +
					VERTTYPEMUL(pMatrix->f[11], pSrc->z) +
					pMatrix->f[15];

		pDst = (PVRTVECTOR4*)((char*)pDst + nOutStride);
		pSrc = (PVRTVECTOR3*)((char*)pSrc + nInStride);
	}
}

/*!***************************************************************************
 @Function			PVRTTransformArray
 @Output			pTransformedVertex	Destination for transformed vectors
 @Input				pV					Input vector array
 @Input				nNumberOfVertices	Number of vectors to transform
 @Input				pMatrix				Matrix to transform the vectors
 @Input				fW					W coordinate of input vector (e.g. use 1 for position, 0 for normal)
 @Description		Transform all vertices in pVertex by pMatrix and store them in
					pTransformedVertex
					- pTransformedVertex is the pointer that will receive transformed vertices.
					- pVertex is the pointer to untransformed object vertices.
					- nNumberOfVertices is the number of vertices of the object.
					- pMatrix is the matrix used to transform the object.
*****************************************************************************/
void PVRTTransformArray(
	PVRTVECTOR3			* const pTransformedVertex,
	const PVRTVECTOR3	* const pV,
	const int			nNumberOfVertices,
	const PVRTMATRIX	* const pMatrix,
	const VERTTYPE		fW)
{
	int			i;

	/* Transform all vertices with *pMatrix */
	for (i=0; i<nNumberOfVertices; ++i)
	{
		pTransformedVertex[i].x =	VERTTYPEMUL(pMatrix->f[ 0], pV[i].x) +
									VERTTYPEMUL(pMatrix->f[ 4], pV[i].y) +
									VERTTYPEMUL(pMatrix->f[ 8], pV[i].z) +
									VERTTYPEMUL(pMatrix->f[12], fW);
		pTransformedVertex[i].y =	VERTTYPEMUL(pMatrix->f[ 1], pV[i].x) +
									VERTTYPEMUL(pMatrix->f[ 5], pV[i].y) +
									VERTTYPEMUL(pMatrix->f[ 9], pV[i].z) +
									VERTTYPEMUL(pMatrix->f[13], fW);
		pTransformedVertex[i].z =	VERTTYPEMUL(pMatrix->f[ 2], pV[i].x) +
									VERTTYPEMUL(pMatrix->f[ 6], pV[i].y) +
									VERTTYPEMUL(pMatrix->f[10], pV[i].z) +
									VERTTYPEMUL(pMatrix->f[14], fW);
	}
}

/*!***************************************************************************
 @Function			PVRTTransformArrayBack
 @Output			pTransformedVertex
 @Input				pVertex
 @Input				nNumberOfVertices
 @Input				pMatrix
 @Description		Transform all vertices in pVertex by the inverse of pMatrix
					and store them in pTransformedVertex.
					- pTransformedVertex is the pointer that will receive transformed vertices.
					- pVertex is the pointer to untransformed object vertices.
					- nNumberOfVertices is the number of vertices of the object.
					- pMatrix is the matrix used to transform the object.
*****************************************************************************/

/*!***************************************************************************
 @Function			PVRTTransformBack
 @Output			pOut
 @Input				pV
 @Input				pM
 @Description		Transform vertex pV by the inverse of pMatrix
					and store in pOut.
*****************************************************************************/
void PVRTTransformBack(
	PVRTVECTOR4			* const pOut,
	const PVRTVECTOR4	* const pV,
	const PVRTMATRIX	* const pM)
{
	VERTTYPE *ppfRows[4];
	VERTTYPE pfIn[20];
	int i;
	const PVRTMATRIX	*pMa;

#if defined(BUILD_OGL) || defined(BUILD_OGLES) || defined(BUILD_OGLES2) || defined(BUILD_OGLES3)
	PVRTMATRIX mT;
	PVRTMatrixTranspose(mT, *pM);
	pMa = &mT;
#else
	pMa = pM;
#endif

	for(i = 0; i < 4; ++i)
	{
		/*
			Set up the array of pointers to matrix coefficients
		*/
		ppfRows[i] = &pfIn[i * 5];

		/*
			Copy the 4x4 matrix into RHS of the 5x4 matrix
		*/
		memcpy(&ppfRows[i][1], &pMa->f[i * 4], 4 * sizeof(float));
	}

	/*
		Copy the "result" vector into the first column of the 5x4 matrix
	*/
	ppfRows[0][0] = pV->x;
	ppfRows[1][0] = pV->y;
	ppfRows[2][0] = pV->z;
	ppfRows[3][0] = pV->w;

	/*
		Solve a set of 4 linear equations
	*/
	PVRTMatrixLinearEqSolve(&pOut->x, ppfRows, 4);
}

/*!***************************************************************************
 @Function			PVRTTransform
 @Output			pOut
 @Input				pV
 @Input				pM
 @Description		Transform vertex pV by pMatrix and store in pOut.
*****************************************************************************/
void PVRTTransform(
	PVRTVECTOR4			* const pOut,
	const PVRTVECTOR4	* const pV,
	const PVRTMATRIX	* const pM)
{
	pOut->x = VERTTYPEMUL(pM->f[0], pV->x) + VERTTYPEMUL(pM->f[4], pV->y) + VERTTYPEMUL(pM->f[8],  pV->z) + VERTTYPEMUL(pM->f[12], pV->w);
	pOut->y = VERTTYPEMUL(pM->f[1], pV->x) + VERTTYPEMUL(pM->f[5], pV->y) + VERTTYPEMUL(pM->f[9],  pV->z) + VERTTYPEMUL(pM->f[13], pV->w);
	pOut->z = VERTTYPEMUL(pM->f[2], pV->x) + VERTTYPEMUL(pM->f[6], pV->y) + VERTTYPEMUL(pM->f[10], pV->z) + VERTTYPEMUL(pM->f[14], pV->w);
	pOut->w = VERTTYPEMUL(pM->f[3], pV->x) + VERTTYPEMUL(pM->f[7], pV->y) + VERTTYPEMUL(pM->f[11], pV->z) + VERTTYPEMUL(pM->f[15], pV->w);
}

/*****************************************************************************
 End of file (PVRTTrans.cpp)
*****************************************************************************/


WebPrerender::WebPrerender(PassRefPtr<Prerender> prerender)
    : m_private(prerender)
{
}

/*
 *
 */

#include "config.h"
#include "public/platform/WebPrerender.h"

#include "platform/Prerender.h"
#include "wtf/PassRefPtr.h"

namespace blink {

namespace {

class ExtraDataContainer : public Prerender::ExtraData {
public:
    static PassRefPtr<ExtraDataContainer> create(WebPrerender::ExtraData* extraData) { return adoptRef(new ExtraDataContainer(extraData)); }

    ~ExtraDataContainer() override {}

    WebPrerender::ExtraData* extraData() const { return m_extraData.get(); }

private:
    explicit ExtraDataContainer(WebPrerender::ExtraData* extraData)
        : m_extraData(adoptPtr(extraData))
    {
    }

    OwnPtr<WebPrerender::ExtraData> m_extraData;
};

} // anon namespace

const Prerender* WebPrerender::toPrerender() const
{
    return m_private.get();
}

void WebPrerender::reset()
{
    m_private.reset();
}

void WebPrerender::assign(const WebPrerender& other)
{
    m_private = other.m_private;
}

bool WebPrerender::isNull() const
{
    return m_private.isNull();
}

WebURL WebPrerender::url() const
{
    return WebURL(m_private->url());
}

unsigned WebPrerender::relTypes() const
{
    return m_private->relTypes();
}

WebString WebPrerender::referrer() const
{
    return m_private->referrer();
}

WebReferrerPolicy WebPrerender::referrerPolicy() const
{
    return static_cast<WebReferrerPolicy>(m_private->referrerPolicy());
}

void WebPrerender::setExtraData(WebPrerender::ExtraData* extraData)
{
    m_private->setExtraData(ExtraDataContainer::create(extraData));
}

const WebPrerender::ExtraData* WebPrerender::extraData() const
{
    RefPtr<Prerender::ExtraData> webcoreExtraData = m_private->extraData();
    if (!webcoreExtraData)
        return 0;
    return static_cast<ExtraDataContainer*>(webcoreExtraData.get())->extraData();
}

void WebPrerender::didStartPrerender()
{
    m_private->didStartPrerender();
}

void WebPrerender::didStopPrerender()
{
    m_private->didStopPrerender();
}

void WebPrerender::didSendLoadForPrerender()
{
    m_private->didSendLoadForPrerender();
}

void WebPrerender::didSendDOMContentLoadedForPrerender()
{
    m_private->didSendDOMContentLoadedForPrerender();
}

} // namespace blink


bool setup(BelaContext *context, void *userData)
{
	// Set LED pin to an output
	pinMode(context, 0, kLEDPin, OUTPUT);
	// Set button pin to an input
	pinMode(context, 0, kButtonPin, INPUT);

	// Initialise the scope
	gScope.setup(1, context->digitalSampleRate);

	return true;
}

/*
 ____  _____ _        _
| __ )| ____| |      / \
|  _ \|  _| | |     / _ \
| |_) | |___| |___ / ___ \
|____/|_____|_____/_/   \_\

http://bela.io

C++ Real-Time Audio Programming with Bela - Lecture 13: State Machines
scope-button: show the digital input on the oscilloscope
*/

#include <Bela.h>
#include <libraries/Scope/Scope.h>

// Oscilloscope
Scope gScope;

// Pin declarations
const unsigned int kLEDPin = 0;					// Pin number of the LED
const unsigned int kButtonPin = 1;				// Pin number of the pushbutton

void render(BelaContext *context, void *userData)
{
   for(unsigned int n = 0; n < context->digitalFrames; n++) {
   		// Read the button state
   		int value = digitalRead(context, n, kButtonPin);

   		// Write the state to the scope
   		gScope.log((float)value);

   		// Write the inverted output to the LED (since button is active low)
   		digitalWriteOnce(context, n, kLEDPin, !value);
    }
}

void cleanup(BelaContext *context, void *userData)
{

}


try
        {
            deserialize(mb->rd_ptr(), h);
        }
        catch (...)
        {
            GDEBUG("Error parsing ISMRMRD Header");
        }

#include "GenericReconKSpaceFilteringGadget.h"
#include <iomanip>

#include "mri_core_kspace_filter.h"
#include "hoNDArray_reductions.h"
#include "mri_core_def.h"
#include "hoNDArray_utils.h"
#include "hoNDArray_elemwise.h"
#include "hoNDFFT.h"
#include "mri_core_utility.h"

namespace Gadgetron {

    GenericReconKSpaceFilteringGadget::GenericReconKSpaceFilteringGadget() : BaseClass()
    {
    }

    GenericReconKSpaceFilteringGadget::~GenericReconKSpaceFilteringGadget()
    {
    }

    int GenericReconKSpaceFilteringGadget::process_config(ACE_Message_Block* mb)
    {
        GADGET_CHECK_RETURN(BaseClass::process_config(mb) == GADGET_OK, GADGET_FAIL);

        ISMRMRD::IsmrmrdHeader h;

        if (!h.acquisitionSystemInformation)
        {
            GDEBUG("acquisitionSystemInformation not found in header. Bailing out");
            return GADGET_FAIL;
        }

        size_t NE = h.encoding.size();

        num_encoding_spaces_ = NE;

        GDEBUG_CONDITION_STREAM(verbose.value(), "Number of encoding spaces: " << NE);

        // get the encoding FOV and recon FOV

        encoding_FOV_.resize(NE);
        recon_FOV_.resize(NE);

        size_t e;
        for (e = 0; e < NE; e++)
        {
            encoding_FOV_[e].resize(3, 0);
            encoding_FOV_[e][0] = h.encoding[e].encodedSpace.fieldOfView_mm.x;
            encoding_FOV_[e][1] = h.encoding[e].encodedSpace.fieldOfView_mm.y;
            encoding_FOV_[e][2] = h.encoding[e].encodedSpace.fieldOfView_mm.z;

            recon_FOV_[e].resize(3, 0);
            recon_FOV_[e][0] = h.encoding[e].reconSpace.fieldOfView_mm.x;
            recon_FOV_[e][1] = h.encoding[e].reconSpace.fieldOfView_mm.y;
            recon_FOV_[e][2] = h.encoding[e].reconSpace.fieldOfView_mm.z;

            GDEBUG_CONDITION_STREAM(verbose.value(), "Encoding space : " << e << " - encoding FOV : [" << encoding_FOV_[e][0] << " " << encoding_FOV_[e][1] << " " << encoding_FOV_[e][2] << " ]");
            GDEBUG_CONDITION_STREAM(verbose.value(), "Encoding space : " << e << " - recon    FOV : [" << recon_FOV_[e][0]    << " " << recon_FOV_[e][1]    << " " << recon_FOV_[e][2] << " ]");
        }

        filter_RO_.resize(NE);
        filter_E1_.resize(NE);
        filter_E2_.resize(NE);

        return GADGET_OK;
    }

    int GenericReconKSpaceFilteringGadget::process(Gadgetron::GadgetContainerMessage< IsmrmrdImageArray >* m1)
    {
        if (perform_timing.value()) { gt_timer_.start("GenericReconKSpaceFilteringGadget::process"); }

        GDEBUG_CONDITION_STREAM(verbose.value(), "GenericReconKSpaceFilteringGadget::process(...) starts ... ");

        process_called_times_++;

        IsmrmrdImageArray* recon_res_ = m1->getObjectPtr();

        // print out recon info
        if (verbose.value())
        {
            GDEBUG_STREAM("----> GenericReconKSpaceFilteringGadget::process(...) has been called " << process_called_times_ << " times ...");
            std::stringstream os;
            recon_res_->data_.print(os);
            GDEBUG_STREAM(os.str());
        }

        // some images do not need kspace filter
        if (recon_res_->meta_[0].length(skip_processing_meta_field.value().c_str())>0)
        {
            if (this->next()->putq(m1) == -1)
            {
                GERROR("GenericReconKSpaceFilteringGadget::process, passing incoming image array on to next gadget");
                return GADGET_FAIL;
            }

            return GADGET_OK;
        }

        size_t encoding = (size_t)recon_res_->meta_[0].as_long("encoding", 0);
        GADGET_CHECK_RETURN(encoding<num_encoding_spaces_, GADGET_FAIL);

        std::string dataRole = std::string(recon_res_->meta_[0].as_str(GADGETRON_DATA_ROLE));

        std::stringstream os;
        os << "encoding_" << encoding << "_" << dataRole;
        std::string str = os.str();

        size_t RO = recon_res_->data_.get_size(0);
        size_t E1 = recon_res_->data_.get_size(1);
        size_t E2 = recon_res_->data_.get_size(2);
        size_t CHA = recon_res_->data_.get_size(3);
        size_t N = recon_res_->data_.get_size(4);
        size_t S = recon_res_->data_.get_size(5);
        size_t SLC = recon_res_->data_.get_size(6);

        // perform SNR unit scaling
        SamplingLimit sampling_limits[3];

        if (recon_res_->meta_[0].length("sampling_limits_RO")>0)
        {
            sampling_limits[0].min_    = (uint16_t)recon_res_->meta_[0].as_long("sampling_limits_RO", 0);
            sampling_limits[0].center_ = (uint16_t)recon_res_->meta_[0].as_long("sampling_limits_RO", 1);
            sampling_limits[0].max_    = (uint16_t)recon_res_->meta_[0].as_long("sampling_limits_RO", 2);
        }

        if ( !( (sampling_limits[0].min_ >= 0) && (sampling_limits[0].max_ < RO) && (sampling_limits[0].min_ <= sampling_limits[0].max_)) )
        {
            sampling_limits[0].min_    = 0;
            sampling_limits[0].center_ = RO / 2;
            sampling_limits[0].max_    = RO - 1;
        }

        if (recon_res_->meta_[0].length("sampling_limits_E1") > 0)
        {
            sampling_limits[1].min_    = (uint16_t)recon_res_->meta_[0].as_long("sampling_limits_E1", 0);
            sampling_limits[1].center_ = (uint16_t)recon_res_->meta_[0].as_long("sampling_limits_E1", 1);
            sampling_limits[1].max_    = (uint16_t)recon_res_->meta_[0].as_long("sampling_limits_E1", 2);
        }

        if (!((sampling_limits[1].min_ >= 0) && (sampling_limits[1].max_ < E1) && (sampling_limits[1].min_ <= sampling_limits[1].max_)))
        {
            sampling_limits[1].min_    = 0;
            sampling_limits[1].center_ = E1 / 2;
            sampling_limits[1].max_    = E1 - 1;
        }

        if (recon_res_->meta_[0].length("sampling_limits_E2") > 0)
        {
            sampling_limits[2].min_    = (uint16_t)recon_res_->meta_[0].as_long("sampling_limits_E2", 0);
            sampling_limits[2].center_ = (uint16_t)recon_res_->meta_[0].as_long("sampling_limits_E2", 1);
            sampling_limits[2].max_    = (uint16_t)recon_res_->meta_[0].as_long("sampling_limits_E2", 2);
        }

        if (!((sampling_limits[2].min_ >= 0) && (sampling_limits[2].max_ < E2) && (sampling_limits[2].min_ <= sampling_limits[2].max_)))
        {
            sampling_limits[2].min_    = 0;
            sampling_limits[2].center_ = E2 / 2;
            sampling_limits[2].max_    = E2 - 1;
        }

        // filter create if needed
        size_t ii;

        if (filter_RO_[encoding].get_number_of_elements() != RO)
        {
            if (sampling_limits[0].min_ == 0 || sampling_limits[0].max_ == RO - 1)
            {
                if (filterRO.value() != "None")
                {
                    filter_RO_[encoding].create(RO);
                    Gadgetron::generate_symmetric_filter(RO, filter_RO_[encoding], Gadgetron::get_kspace_filter_type(filterRO.value()), filterRO_sigma.value(), (size_t)std::ceil(filterRO_width.value()*RO));
                }
            }
            else
            {
                if (filterRO.value() != "None")
                {
                    size_t len;
                    this->find_kspace_sampled_range(sampling_limits[0].min_, sampling_limits[0].max_, RO, len);

                    hoNDArray< std::complex<float> > f;
                    Gadgetron::generate_symmetric_filter(len, f, Gadgetron::get_kspace_filter_type(filterRO.value()), filterRO_sigma.value(), (size_t)std::ceil(filterRO_width.value()*len));
                    Gadgetron::pad(RO, f, filter_RO_[encoding]);
                }
            }

            if (filter_RO_[encoding].get_number_of_elements() == RO)
            {
                if (sampling_limits[0].min_ != 0 || sampling_limits[0].max_ != RO - 1)
                {
                    // compensate the sacling from min_ to max_
                    std::complex<float> sos = 0.0f;
                    for (ii = sampling_limits[0].min_; ii <= sampling_limits[0].max_; ii++)
                    {
                        sos += filter_RO_[encoding](ii)* std::conj(filter_RO_[encoding](ii));
                    }

                    Gadgetron::scal((float)(1.0 / std::sqrt(std::abs(sos) / (sampling_limits[0].max_ - sampling_limits[0].min_ + 1))), filter_RO_[encoding]);
                }
            }

            if (!debug_folder_full_path_.empty())
            {
                if(filter_RO_[encoding].get_number_of_elements()>0)
                    gt_exporter_.export_array_complex(filter_RO_[encoding], debug_folder_full_path_ + "filterRO_" + str);
            }
        }

        if (filter_E1_[encoding].get_number_of_elements() != E1)
        {
            if (sampling_limits[1].min_ == 0 || sampling_limits[1].max_ == E1 - 1)
            {
                if (filterE1.value() != "None")
                {
                    filter_E1_[encoding].create(E1);
                    Gadgetron::generate_symmetric_filter(E1, filter_E1_[encoding], Gadgetron::get_kspace_filter_type(filterE1.value()), filterE1_sigma.value(), (size_t)std::ceil(filterE1_width.value()*E1));
                }
            }
            else
            {
                if (filterE1.value() != "None")
                {
                    size_t len;
                    this->find_kspace_sampled_range(sampling_limits[1].min_, sampling_limits[1].max_, E1, len);

                    hoNDArray< std::complex<float> > f;
                    Gadgetron::generate_symmetric_filter(len, f, Gadgetron::get_kspace_filter_type(filterE1.value()), filterE1_sigma.value(), (size_t)std::ceil(filterE1_width.value()*len));
                    Gadgetron::pad(E1, f, filter_E1_[encoding]);
                }
            }

            if (filter_E1_[encoding].get_number_of_elements() == E1)
            {
                if (sampling_limits[1].min_ != 0 || sampling_limits[1].max_ != E1 - 1)
                {
                    // compensate the sacling from min_ to max_
                    std::complex<float> sos = 0.0f;
                    for (ii = sampling_limits[1].min_; ii <= sampling_limits[1].max_; ii++)
                    {
                        sos += filter_E1_[encoding](ii)* std::conj(filter_E1_[encoding](ii));
                    }

                    Gadgetron::scal((float)(1.0 / std::sqrt(std::abs(sos) / (sampling_limits[1].max_ - sampling_limits[1].min_ + 1))), filter_E1_[encoding]);
                }
            }

            if (!debug_folder_full_path_.empty())
            {
                if (filter_E1_[encoding].get_number_of_elements()>0)
                    gt_exporter_.export_array_complex(filter_E1_[encoding], debug_folder_full_path_ + "filterE1_" + str);
            }
        }

        if (E2>1 && filter_E2_[encoding].get_number_of_elements() != E2)
        {
            if (sampling_limits[2].min_ == 0 || sampling_limits[2].max_ == E1 - 1)
            {
                if (filterE2.value() != "None")
                {
                    filter_E2_[encoding].create(E2);
                    Gadgetron::generate_symmetric_filter(E2, filter_E2_[encoding], Gadgetron::get_kspace_filter_type(filterE2.value()), filterE2_sigma.value(), (size_t)std::ceil(filterE2_width.value()*E2));
                }
            }
            else
            {
                if (filterE2.value() != "None")
                {
                    size_t len;
                    this->find_kspace_sampled_range(sampling_limits[2].min_, sampling_limits[2].max_, E2, len);

                    hoNDArray< std::complex<float> > f;
                    Gadgetron::generate_symmetric_filter(len, f, Gadgetron::get_kspace_filter_type(filterE2.value()), filterE2_sigma.value(), (size_t)std::ceil(filterE2_width.value()*len));
                    Gadgetron::pad(E2, f, filter_E2_[encoding]);
                }
            }

            if (filter_E2_[encoding].get_number_of_elements() == E2)
            {
                if (sampling_limits[2].min_ != 0 || sampling_limits[2].max_ != E1 - 1)
                {
                    // compensate the sacling from min_ to max_
                    std::complex<float> sos = 0.0f;
                    for (ii = sampling_limits[2].min_; ii <= sampling_limits[2].max_; ii++)
                    {
                        sos += filter_E2_[encoding](ii)* std::conj(filter_E2_[encoding](ii));
                    }

                    Gadgetron::scal((float)(1.0 / std::sqrt(std::abs(sos) / (sampling_limits[2].max_ - sampling_limits[2].min_ + 1))), filter_E2_[encoding]);
                }
            }

            if (!debug_folder_full_path_.empty())
            {
                if (filter_E2_[encoding].get_number_of_elements()>0)
                    gt_exporter_.export_array_complex(filter_E2_[encoding], debug_folder_full_path_ + "filterE2_" + str);
            }
        }

        // perform kspace filter
        if ( (filter_RO_[encoding].get_number_of_elements() == RO)
                || (filter_E1_[encoding].get_number_of_elements() == E1)
                || ((E2>1) && (filter_E2_[encoding].get_number_of_elements() == E2)) )
        {
            // go to kspace
            if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(recon_res_->data_, debug_folder_full_path_ + "image_before_filtering_" + str); }

            if (perform_timing.value()) { gt_timer_.start("GenericReconKSpaceFilteringGadget: fftc"); }
            if (E2 > 1)
            {
                Gadgetron::hoNDFFT<float>::instance()->fft3c(recon_res_->data_, kspace_buf_);
            }
            else
            {
                Gadgetron::hoNDFFT<float>::instance()->fft2c(recon_res_->data_, kspace_buf_);
            }
            if (perform_timing.value()) { gt_timer_.stop(); }

            if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(kspace_buf_, debug_folder_full_path_ + "kspace_before_filtering_" + str); }

            // filtering

            bool inKSpace = true;

            if ( (filter_RO_[encoding].get_number_of_elements() == RO)
                && (filter_E1_[encoding].get_number_of_elements() == E1)
                && (E2>1) && (filter_E2_[encoding].get_number_of_elements() == E2) )
            {
                if (perform_timing.value()) { gt_timer_.start("GenericReconKSpaceFilteringGadget, apply_kspace_filter_ROE1E2 ... "); }
                Gadgetron::apply_kspace_filter_ROE1E2(kspace_buf_, filter_RO_[encoding], filter_E1_[encoding], filter_E2_[encoding], filter_res_);
                if (perform_timing.value()) { gt_timer_.stop(); }

                if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(filter_res_, debug_folder_full_path_ + "kspace_after_filtered_" + str); }
                inKSpace = true;
            }
            else if ( (filter_RO_[encoding].get_number_of_elements() == RO) && (filter_E1_[encoding].get_number_of_elements() == E1) )
            {
                if (perform_timing.value()) { gt_timer_.start("GenericReconKSpaceFilteringGadget, apply_kspace_filter_ROE1 ... "); }
                Gadgetron::apply_kspace_filter_ROE1(kspace_buf_, filter_RO_[encoding], filter_E1_[encoding], filter_res_);
                if (perform_timing.value()) { gt_timer_.stop(); }

                if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(filter_res_, debug_folder_full_path_ + "kspace_after_filtered_" + str); }

                inKSpace = true;
            }
            else
            {
                filter_res_ = kspace_buf_;

                hoNDArray< std::complex<float> >* pSrc = &kspace_buf_;
                hoNDArray< std::complex<float> >* pDst = &filter_res_;

                bool filterPerformed = false;

                if (filter_RO_[encoding].get_number_of_elements() == RO)
                {
                    Gadgetron::apply_kspace_filter_RO(*pSrc, filter_RO_[encoding], *pDst);
                    std::swap(pSrc, pDst);
                    filterPerformed = true;
                }

                if (filter_E1_[encoding].get_number_of_elements() == E1)
                {
                    Gadgetron::apply_kspace_filter_E1(*pSrc, filter_E1_[encoding], *pDst);
                    std::swap(pSrc, pDst);
                    filterPerformed = true;
                }

                if (filter_E2_[encoding].get_number_of_elements() == E2)
                {
                    Gadgetron::apply_kspace_filter_E2(*pSrc, filter_E2_[encoding], *pDst);
                    std::swap(pSrc, pDst);
                    filterPerformed = true;
                }

                if (filterPerformed)
                {
                    if (pDst != &filter_res_)
                    {
                        filter_res_ = *pDst;
                    }
                }

                inKSpace = true;
            }

            if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(filter_res_, debug_folder_full_path_ + "kspace_after_filtering_" + str); }

            // go back to image domain
            if (E2 > 1)
            {
                Gadgetron::hoNDFFT<float>::instance()->ifft3c(filter_res_, recon_res_->data_);
            }
            else
            {
                Gadgetron::hoNDFFT<float>::instance()->ifft2c(filter_res_, recon_res_->data_);
            }

            if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(recon_res_->data_, debug_folder_full_path_ + "image_after_filtering_" + str); }

            GDEBUG_CONDITION_STREAM(verbose.value(), "GenericReconKSpaceFilteringGadget::process(...) ends ... ");
        }

        // send out results
        if (this->next()->putq(m1) == -1)
        {
            GERROR("GenericReconKSpaceFilteringGadget::process, passing data on to next gadget");
            return GADGET_FAIL;
        }

        if (perform_timing.value()) { gt_timer_.stop(); }

        return GADGET_OK;
    }

    void GenericReconKSpaceFilteringGadget::find_kspace_sampled_range(size_t min, size_t max, size_t len, size_t& r)
    {
        GADGET_CHECK_THROW(min < max);
        GADGET_CHECK_THROW(min < len);
        GADGET_CHECK_THROW(max < len);

        size_t hmin = len / 2 - min;
        size_t hmax = max - len / 2;
        r = (hmax>hmin) ? 2*hmax+1 : 2*hmin+1;

        if (r > len) r = len;
    }

    GADGET_FACTORY_DECLARE(GenericReconKSpaceFilteringGadget)

}


void idMenuHandler_HUD::ShowTip( const char * title, const char * tip, bool autoHide ) {
	autoHideTip = autoHideTip;
	tipStartTime = gameLocal.time;
	hiding = false;
	idMenuScreen_HUD * screen = GetHud();
	if ( screen != NULL ) {
		screen->ShowTip( title, tip );
	}
}

/*
===========================================================================

If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.

===========================================================================
*/
#pragma hdrstop
#include "../../idLib/precompiled.h"
#include "../Game_local.h"

static const int TIP_DISPLAY_TIME = 5000;

/*
========================
idMenuHandler_HUD::Update
========================
*/
void idMenuHandler_HUD::Update() {

	if ( gui == NULL || !gui->IsActive() ) {
		return;
	}

	if ( nextScreen != activeScreen ) {

		if ( activeScreen > HUD_AREA_INVALID && activeScreen < HUD_NUM_AREAS && menuScreens[ activeScreen ] != NULL ) {
			menuScreens[ activeScreen ]->HideScreen( static_cast<mainMenuTransition_t>(transition) );
		}

		if ( nextScreen > HUD_AREA_INVALID && nextScreen < HUD_NUM_AREAS && menuScreens[ nextScreen ] != NULL ) {
			menuScreens[ nextScreen ]->ShowScreen( static_cast<mainMenuTransition_t>(transition) );
		}

		transition = MENU_TRANSITION_INVALID;
		activeScreen = nextScreen;
	}

	idPlayer * player = gameLocal.GetLocalPlayer();
	if ( player != NULL ) {
		if ( player->IsTipVisible() && autoHideTip && !hiding ) {
			if ( gameLocal.time >= tipStartTime + TIP_DISPLAY_TIME ) {
				player->HideTip();
			}
		}

		if ( player->IsSoundChannelPlaying( SND_CHANNEL_PDA_AUDIO ) && GetHud() != NULL ) {
			GetHud()->UpdateAudioLog( true );
		} else {
			GetHud()->UpdateAudioLog( false );
		}

		if ( radioMessage ) {
			GetHud()->UpdateCommunication( true, player );
		} else {
			GetHud()->UpdateCommunication( false, player );
		}

	}

	idMenuHandler::Update();
}

/*
========================
idMenuHandler_HUD::ActivateMenu
========================
*/
void idMenuHandler_HUD::ActivateMenu( bool show ) {

	idMenuHandler::ActivateMenu( show );

	idPlayer * player = gameLocal.GetLocalPlayer();
	if ( player == NULL ) {
		return;
	}

	if ( show ) {
		activeScreen = HUD_AREA_INVALID;
		nextScreen = HUD_AREA_PLAYING;
	} else {
		activeScreen = HUD_AREA_INVALID;
		nextScreen = HUD_AREA_INVALID;
	}

}

/*
========================
idMenuHandler_HUD::Initialize
========================
*/
void idMenuHandler_HUD::Initialize( const char * swfFile, idSoundWorld * sw ) {
	idMenuHandler::Initialize( swfFile, sw );

	// Initialize the menus
#define BIND_HUD_SCREEN( screenId, className, menuHandler )				\
	menuScreens[ (screenId) ] = new className();						\
	menuScreens[ (screenId) ]->Initialize( menuHandler );				\
	menuScreens[ (screenId) ]->AddRef();

	for ( int i = 0; i < HUD_NUM_AREAS; ++i ) {
		menuScreens[ i ] = NULL;
	}

	BIND_HUD_SCREEN( HUD_AREA_PLAYING, idMenuScreen_HUD, this );
}

/*
========================
idMenuHandler_HUD::GetMenuScreen
========================
*/
idMenuScreen * idMenuHandler_HUD::GetMenuScreen( int index ) {

	if ( index < 0 || index >= HUD_NUM_AREAS ) {
		return NULL;
	}

	return menuScreens[ index ];

}

/*
========================
idMenuHandler_HUD::GetHud
========================
*/
idMenuScreen_HUD * idMenuHandler_HUD::GetHud() {
	idMenuScreen_HUD * screen = dynamic_cast< idMenuScreen_HUD * >( menuScreens[ HUD_AREA_PLAYING ] );
	return screen;
}

/*
========================
idMenuHandler_HUD::ShowTip
========================
*/

/*
========================
idMenuHandler_HUD::HideTip
========================
*/
void idMenuHandler_HUD::HideTip() {
	idMenuScreen_HUD * screen = GetHud();
	if ( screen != NULL && !hiding ) {
		screen->HideTip();
	}
	hiding = true;
}