text:
namespace PlatformRig { namespace Overlays
{
    class CollectIntersectionPts
    {
    public:
        std::vector<Float2> _intr;

        void operator()(XLEMath::Int2 s0, XLEMath::Int2 s1, float edgeAlpha)
        {
            _intr.push_back(LinearInterpolate(Float2(s0), Float2(s1), edgeAlpha));
        }

        void operator()(XLEMath::Float2 s0, XLEMath::Float2 s1, float edgeAlpha)
        {
            _intr.push_back(LinearInterpolate(s0, s1, edgeAlpha));
        }
    };

    void    GridIteratorDisplay::Render(IOverlayContext* context, Layout& layout, Interactables&interactables, InterfaceState& interfaceState)
    {
        auto maxSize = layout.GetMaximumSize();
        Rect gridArea(maxSize._topLeft + Coord2(50, 50), maxSize._bottomRight - Coord2(50, 50));

        const unsigned elementDim = 32;
        unsigned segmentsX = gridArea.Width() / elementDim;
        unsigned segmentsY = gridArea.Height() / elementDim;

        auto segsX = std::make_unique<Coord2[]>(segmentsX*2);
        auto segsY = std::make_unique<Coord2[]>(segmentsY*2);
        auto colours = std::make_unique<ColorB[]>(std::max(segmentsX, segmentsY)*2);
        for (unsigned c=0; c<segmentsX; ++c) {
            segsX[c*2+0] = Coord2(gridArea._topLeft[0] + c * elementDim, gridArea._topLeft[1]);
            segsX[c*2+1] = Coord2(gridArea._topLeft[0] + c * elementDim, gridArea._bottomRight[1]);
            colours[c*2+0] = ColorB(0xffafafaf);
            colours[c*2+1] = ColorB(0xffafafaf);
        }
        for (unsigned c=0; c<segmentsY; ++c) {
            segsY[c*2+0] = Coord2(gridArea._topLeft[0], gridArea._topLeft[1] + c * elementDim);
            segsY[c*2+1] = Coord2(gridArea._bottomRight[0], gridArea._topLeft[1] + c * elementDim);
            colours[c*2+0] = ColorB(0xffafafaf);
            colours[c*2+1] = ColorB(0xffafafaf);
        }

        DrawLines(context, segsX.get(), colours.get(), segmentsX);
        DrawLines(context, segsY.get(), colours.get(), segmentsY);

        Float2 start = Float2(float(gridArea._bottomRight[0] - gridArea._topLeft[0]), float(gridArea._bottomRight[1] - gridArea._topLeft[1])) / float(elementDim) / 2.f;
        Float2 end = Float2(float(_currentMousePosition[0] - gridArea._topLeft[0]), float(_currentMousePosition[1] - gridArea._topLeft[1])) / float(elementDim);

        // start[0] = XlFloor(start[0]);
        // start[1] = XlFloor(start[1]);
        // end[0] = XlFloor(end[0]);
        // end[1] = XlFloor(end[1]);

        Coord2 testLine[] =
        {
            Coord2(int(start[0]*elementDim), int(start[1]*elementDim)) + gridArea._topLeft,
            Coord2(int(end[0]*elementDim), int(end[1]*elementDim)) + gridArea._topLeft,
        };
        ColorB testLineCol[] = { ColorB(0xffffffff), ColorB(0xffffffff) };
        DrawLines(context, testLine, testLineCol, 1);

        CollectIntersectionPts intersections;
        // GridEdgeIterator(Int2(start), Int2(end), intersections);
        GridEdgeIterator2(start, end, intersections);

        for (auto i=intersections._intr.cbegin(); i!=intersections._intr.cend(); ++i) {
            Coord2 centre(int((*i)[0] * elementDim) + gridArea._topLeft[0], int((*i)[1] * elementDim) + gridArea._topLeft[1]);
            Rect rect(centre - Coord2(2,2), centre + Coord2(2,2));
            DrawElipse(context, rect, ColorB(0xffff0000));
        }
    }

    bool    GridIteratorDisplay::ProcessInput(InterfaceState& interfaceState, const InputSnapshot& input)
    {
        if (input.IsHeld_LButton()) {
            _currentMousePosition = input._mousePosition;
        }
        return false;
    }

    GridIteratorDisplay::GridIteratorDisplay() : _currentMousePosition(0,0) {}
    GridIteratorDisplay::~GridIteratorDisplay() {}

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    class FieldIntersection
    {
    public:
        Float2 _position, _normal;
        bool _isGood;
        FieldIntersection(Float2 position, Float2 normal) : _position(position), _normal(normal), _isGood(true) {}
        FieldIntersection() : _position(0.f, 0.f), _normal(0.f, 0.f), _isGood(false) {}
    };

    static std::pair<float, float> RayVsCircle(const Float2& rayStart, const Float2& rayDirection, const Float2& sphereCenter, float sphereRadius)
    {
            //  we're going to look for intersections between this ray and the sphere.
            //  there can be maximum of 2 intersections.
            //  The return values are the length along the line to the intersection points.
            //  When no intersection is found (or only one) the unused return values will be negative).
            //  We solve this using algebra, looking for the points where the equations
            //  for the line and the ray agree.

        const float a = Dot(rayDirection, rayStart - sphereCenter);
        const float m = Magnitude(rayStart - sphereCenter);
        const float x = a*a - m*m + sphereRadius*sphereRadius;
        if (x < 0.f) {
            return std::make_pair(-1.f, -1.f);
        }

        const float A = -a;
        const float B = XlSqrt(x);
        return std::make_pair(A+B, A-B);
    }

    static float CalculateDensity(const Float2& pt)
    {
        const float circleRadius = 20.f;
        // const float theta = atan2(pt[1], pt[0]);
        const float r = Magnitude(pt);
        // static float s0 = 5.f;
        // static float s1 = 0.25f;
        // float noiseValue = SimplexNoise(Float2(s0 * theta, s1 * r));
        //
        // static float noiseScale = 10.f;
        // return r - (circleRadius + noiseScale * noiseValue);
        return r - circleRadius;
    }

    static FieldIntersection GetIntersection(const Float2& e0, const Float2& e1)
    {
            //  For the given edge, find the intersection with the equation.
            //  We're just using a sphere, so it should be easy.
            //
            //  We're interested for the smallest positive value that come out of RayVsCircle

        const bool useDensitySample = true;

        if (useDensitySample) {

            float d0 = CalculateDensity(e0);
            float d1 = CalculateDensity(e1);
            if (d0 < 0.f == d1 < 0.f) {
                return FieldIntersection(); // no intersections here
            }

                //  -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                //      When we get a change in sign, it means there
                //      is an intersection along this edge somewhere.
                //      We can't know exactly where. But we can take
                //      an estimate based on the density values.
                //
                //      It might be a good idea to further improve the
                //      result by taking a few steps to try to get to the
                //      smallest density value. note that a very strange
                //      density function might behave very non-linearly,
                //      and so produce strange results when trying to
                //      find the intersection (particularly if there are
                //      really multiple intersections).

                //  -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

            float x0 = 0.f, x1 = 1.f;
            float x = 1.f, d = FLT_MAX;
            unsigned improvementSteps = 3;
            for (unsigned c=0; ; ++c) {
                float prevD = d; float prevX = x;
                x = LinearInterpolate(x0, x1, -d0 / (d1 - d0));
                d = CalculateDensity(LinearInterpolate(e0, e1, x));

                    // along noisy edges we could end up getting a worse result after a step
                    //  In these cases, just give up at the last reasonable result
                if (XlAbs(d) > XlAbs(prevD)) {
                    x = prevX;
                    break;
                }

                if ((c+1)>=improvementSteps) break;

                    //  We're going to attempt another improvement.
                    //  Divide the search area again, depending on where
                    //  the origin falls
                if ((d < 0.f) != (d1 < 0.f)) {
                    x0 = x;
                    d0 = d;
                } else {
                    x1 = x;
                    d1 = d;
                }
            }

                //  -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

            Float2 bestIntersection = LinearInterpolate(e0, e1, x);

                //  We need to calculate the normal for this point. We can
                //  use finite different method for this. The normal is just
                //  in the same direction as the partial derivatives of the
                //  density function.
            // static float normalCalcDistance = 1.f;  // changing this distance produces some interesting results in very noisy fields. Larger numbers will generally be smoother
            // float dx0 = CalculateDensity(bestIntersection + Float2(-normalCalcDistance, 0.f));
            // float dx1 = CalculateDensity(bestIntersection + Float2( normalCalcDistance, 0.f));
            // float dy0 = CalculateDensity(bestIntersection + Float2(0.f, -normalCalcDistance));
            // float dy1 = CalculateDensity(bestIntersection + Float2(0.f,  normalCalcDistance));
            //     // (actually the shouldn't matter if the normal is pointing positive or negative)
            // Float2 normal = -Normalize(Float2(dx1-dx0, dy1-dy0));
            Float2 normal = -Normalize(bestIntersection);

            return FieldIntersection(bestIntersection, normal);

        } else {
            const float radius = 28.5f;
            Float2 dir = e1-e0;
            const float length = Magnitude(e1-e0);
            dir *= XlRSqrt(length);
            auto intersection = RayVsCircle(e0, dir, Float2(0.f, 0.f), radius);
            if (intersection.first < 0.f) {
                return FieldIntersection();
            }

            float distance = intersection.first;
            if (intersection.second > 0.f && intersection.second < distance) {
                distance = intersection.second;
            }

            if (distance > length) {
                return FieldIntersection();
            }

            Float2 intersectionPt = e0 + dir * distance;
            return FieldIntersection(intersectionPt, Normalize(intersectionPt));
        }
    }

    // static void RotateToUpperTriangle(cml::matrix<float, cml::fixed<5,4>, cml::col_basis>& matrix)
    // {
    //         // Convert this matrix into a upper triangle using the Householder method
    // }

    static void RotateToUpperTriangle(Eigen::Matrix<float,5,4>& A)
    {
        // Eigen::ColPivHouseholderQR<Eigen::Matrix<float,5,4>> qr(A);
        // A = qr.matrixR().triangularView<Eigen::Upper>();
        Eigen::HouseholderQR<Eigen::Matrix<float,5,4>> qr2(A);
        A = qr2.matrixQR().triangularView<Eigen::Upper>();
    }

    Float2 CalculateDualContouringPt(const FieldIntersection intersections[], unsigned intersectionCount, const Float2& massPoint)
    {
            //  Each intersection point defines a plane. We want to find the point within the grid cell that
            //  is closest to lying on all planes. There might not be an exact solution. However, the following
            //  math will find the solution that minimizes the least squares of the distances from the planes.
            //
            //  Also note the use of the "mass point". This is described in the original dual contouring paper.
            //  This can help avoid cases where the solution is outside of the grid cell.
            //      http://www.cs.rice.edu/~jwarren/papers/techreport02408.pdf

            //  The simplest version of this just involves creating a matrix from the planes
            //  defined by the intersection pts, and using SVD decomposition to calculate
            //  the pseudo-inverse (which will give us a solution).
            //  Let's do this using the "eigen" library. That means using the matrix tpyes from
            //  that library.

        static unsigned method = 2;
        if (method == 1) {

                //  Most basic method. We're just going to solve the linear equations
                //  directly. This doesn't involve any more optimisations or accuracy
                //  improvements
            Eigen::MatrixXf A(intersectionCount, 2);
            Eigen::MatrixXf B(intersectionCount, 1);
            for (unsigned c=0; c<intersectionCount; ++c) {
                A(c, 0) = intersections[c]._normal[0];
                A(c, 1) = intersections[c]._normal[1];
                B(c, 0) = Dot(intersections[c]._position, intersections[c]._normal);
            }

                //  Calculate the decomposition.
                //
                //  The paper suggests that we might not have to do all of this. It uses A multiplied
                //  by it's transpose, which reduces some of the SVD math. It doesn't look like
                //  the eigen library supports this simplification, however.
            Eigen::JacobiSVD<Eigen::MatrixXf> svd(A, Eigen::ComputeFullU | Eigen::ComputeFullV);

            Eigen::MatrixXf x(2, 1);
            svd.solve(B).evalTo(x);

                // that's our basic solution...
            return Float2(x(0, 0), x(1, 0));

        } else if (method == 0) {

                //  This is the QR decomposition method. This transforms the matrices
                //  beforehand into a form that can be more accurate for later math.

            typedef Eigen::Matrix<float,5,4> Float5x4;
            Float5x4 mat = Float5x4::Zero();

            for (unsigned c=0; c<intersectionCount; ++c) {
                mat(4, 0) = intersections[c]._normal[0];
                mat(4, 1) = intersections[c]._normal[1];
                mat(4, 2) = 0.f;
                mat(4, 3) = Dot(intersections[c]._position, intersections[c]._normal);
                RotateToUpperTriangle(mat);
            }

            Eigen::Matrix<float,3,3> Ahat;
            Eigen::Matrix<float,3,1> Bhat;
            for (unsigned c=0; c<3; ++c) {
                Ahat(c,0) = mat(c,0);
                Ahat(c,1) = mat(c,1);
                Ahat(c,2) = mat(c,2);
                Bhat(c,0) = mat(c,3);
            }

            Eigen::JacobiSVD<Eigen::MatrixXf> svd(Ahat, Eigen::ComputeFullU | Eigen::ComputeFullV);

            Eigen::MatrixXf x(2, 1);
            svd.solve(Bhat).evalTo(x);

            return Float2(x(0, 0), x(1, 0));

        } else if (method == 2) {

                // same as above, but using the mass point

            typedef Eigen::Matrix<float,5,4> Float5x4;
            Float5x4 mat = Float5x4::Zero();

            for (unsigned c=0; c<intersectionCount; ++c) {
                mat(4, 0) = intersections[c]._normal[0];
                mat(4, 1) = intersections[c]._normal[1];
                mat(4, 2) = 0.f;
                mat(4, 3) = Dot(intersections[c]._position, intersections[c]._normal);
                RotateToUpperTriangle(mat);
            }

            Eigen::Matrix<float,3,3> Ahat;
            Eigen::Matrix<float,3,1> Bhat;
            for (unsigned c=0; c<3; ++c) {
                Ahat(c,0) = mat(c,0);
                Ahat(c,1) = mat(c,1);
                Ahat(c,2) = mat(c,2);
                Bhat(c,0) = mat(c,3);
            }

            // const float r = mat(3,3);        (not clear what I should do with "r". It always seem to be 0.f in tests so far)

            Eigen::Matrix<float,3,1> massPointVec;
            massPointVec(0,0) = massPoint[0];
            massPointVec(1,0) = massPoint[1];
            massPointVec(2,0) = 0.f;

            Eigen::MatrixXf x(2, 1);

                //  The original dual contour multiplies through with the transpose of A. This might
                //  reduce the work when calculating the SVD, but the Eigen library doesn't seem to
                //  support this optimisation, however. So I'm not sure if we need to multiply
                //  through with AHatTranspose here.
            static bool useTranspose = true;
            if (useTranspose) {
                auto AhatTranspose = Ahat.transpose();
                Eigen::JacobiSVD<Eigen::MatrixXf> svd(AhatTranspose * Ahat, Eigen::ComputeFullU | Eigen::ComputeFullV);
                svd.solve(AhatTranspose * Bhat - AhatTranspose * Ahat * massPointVec).evalTo(x);
            } else {
                    //  note that if we know the mass point when we're calculating Ahat, we can probably
                    //  just take into account the mass point then. However, if we're using a marching
                    //  cubes-like algorithm to move through the data field, and so visiting each cube
                    //  element multiple times, we might not be able to calculate the mass point until
                    //  after AHat has been fully built. But we can compensate during the solution, as so ---
                Eigen::JacobiSVD<Eigen::MatrixXf> svd(Ahat, Eigen::ComputeFullU | Eigen::ComputeFullV);
                svd.solve(Bhat - Ahat * massPointVec).evalTo(x);
            }

            auto result = Float2(x(0, 0) + massPoint[0], x(1, 0) + massPoint[1]);

                //  We can still get some results where the solution is outside of the
                //  grid element we're building. This can happen when there is significant
                //  curvature inside a single grid element. It produces very strange results
                //  so we have to detect these cases, and use some other solution. In these
                //  cases, the mass point is probably the best estimate of what we need.
                //  The only other option would be to use higher order primitives than cubes
                //  (eg. bezier surfaces). But that would require lots of extra work and calculations.

            if (    result[0] < -.5f || result[0] > .5f
                ||  result[1] < -.5f || result[1] > .5f) {
                return massPoint;       // got a poor result from the QEF test -- too much curvature in a small area.
            }

            return result;

        } else if (method == 3) {
                //  When the normal method isn't working, this can give a rough estimate
                //  of what it should look like
            return massPoint;
        }

        return Float2(0.f, 0.f);
    }

    static Float2 MulAcross(const Float2& zero, const Float2& one)
    {
        return Float2(zero[0]*one[0], zero[1]*one[1]);
    }

    void    DualContouringTest::Render(IOverlayContext* context, Layout& layout, Interactables&interactables, InterfaceState& interfaceState)
    {
        int gridSize = 64;
        std::vector<std::pair<Float2, Float2>> lines;
        for (int y=-gridSize/2; y<gridSize; ++y) {
            for (int x=-gridSize/2; x<gridSize; ++x) {

                    //  Here we're going to test one grid element at a time (in 2d)
                    //  Let's look at the 4 edges of this grid element and find
                    //  the signs and intersection points. We also need the positions
                    //  of the intersections and the normals at those coordinates.
                    //
                    //  Let's start with a simple equation where we can calculate those
                    //  things easily

                Float2 p0 = Float2(  float(x),     float(y));
                Float2 p1 = Float2(float(x+1),     float(y));
                Float2 p2 = Float2(  float(x),   float(y+1));
                Float2 p3 = Float2(float(x+1),   float(y+1));

                auto i0 = GetIntersection(p0, p1);
                auto i1 = GetIntersection(p1, p3);
                auto i2 = GetIntersection(p3, p2);
                auto i3 = GetIntersection(p2, p0);

                FieldIntersection intrs[4];
                Float2 massPoint(0.f, 0.f);
                unsigned intersectionCount = 0;
                if (i0._isGood) { intrs[intersectionCount++] = i0; massPoint += i0._position; }
                if (i1._isGood) { intrs[intersectionCount++] = i1; massPoint += i1._position; }
                if (i2._isGood) { intrs[intersectionCount++] = i2; massPoint += i2._position; }
                if (i3._isGood) { intrs[intersectionCount++] = i3; massPoint += i3._position; }
                if (!intersectionCount) { continue; }

                massPoint /= float(intersectionCount);

                //  We offset the whole system to bring it near
                    //  the origin.
                Float2 offset(float(x) + .5f, float(y) + .5f);
                for (unsigned c=0; c<intersectionCount; ++c) {
                    intrs[c]._position -= offset;
                }
                massPoint -= offset;

                    //  Now we have all our intersection. We need to solve a system
                    //  of linear equations to calculate the point that is closest to
                    //  meeting the planes defined.
                auto cellPt = CalculateDualContouringPt(intrs, intersectionCount, massPoint);

                    //  now we must add lines from each of the intersection points to the
                    //  cell pt.
                for (unsigned c=0; c<intersectionCount; ++c) {
                    lines.push_back(std::make_pair(intrs[c]._position + offset, cellPt + offset));
                }
            }
        }

        auto maxSize = layout.GetMaximumSize();
        Rect gridArea(maxSize._topLeft + Coord2(50, 50), maxSize._bottomRight - Coord2(50, 50));

        Float2 o = LinearInterpolate(AsFloat2(gridArea._topLeft), AsFloat2(gridArea._bottomRight), 0.5f);
        Float2 s = Float2(gridArea.Width() / float(gridSize), gridArea.Height() / float(gridSize));

            //////////////////////////////////////////////////////////////
                    //  draw a background grid          //

        {
            const unsigned segmentsX = gridSize+1;
            const unsigned segmentsY = gridSize+1;
            auto segsX = std::make_unique<Coord2[]>(segmentsX*2);
            auto segsY = std::make_unique<Coord2[]>(segmentsY*2);
            auto colours = std::make_unique<ColorB[]>(std::max(segmentsX, segmentsY)*2);
            unsigned c=0;
            for (int x=-gridSize/2; x<=gridSize/2; ++x, ++c) {
                segsX[c*2+0] = AsCoord2(MulAcross(Float2(float(x), float(-gridSize/2)), s) + o);
                segsX[c*2+1] = AsCoord2(MulAcross(Float2(float(x), float( gridSize/2)), s) + o);
                colours[c*2+0] = ColorB(0xff5f5f5f);
                colours[c*2+1] = ColorB(0xff5f5f5f);
            }
            assert(c==segmentsX);
            c=0;
            for (int y=-gridSize/2; y<=gridSize/2; ++y, ++c) {
                segsY[c*2+0] = AsCoord2(MulAcross(Float2(float(-gridSize/2), float(y)), s) + o);
                segsY[c*2+1] = AsCoord2(MulAcross(Float2(float( gridSize/2), float(y)), s) + o);
                colours[c*2+0] = ColorB(0xff5f5f5f);
                colours[c*2+1] = ColorB(0xff5f5f5f);
            }
            assert(c==segmentsY);

            DrawLines(context, segsX.get(), colours.get(), segmentsX);
            DrawLines(context, segsY.get(), colours.get(), segmentsY);
        }

            //////////////////////////////////////////////////////////////

        {
            std::vector<Coord2> transformedLines;
            std::vector<ColorB> lineColours;
            transformedLines.reserve(lines.size()*2);
            lineColours.reserve(lines.size()*2);
            for (auto i=lines.cbegin(); i!=lines.cend(); ++i) {
                transformedLines.push_back(AsCoord2(MulAcross(i->first, s) + o));
                transformedLines.push_back(AsCoord2(MulAcross(i->second, s) + o));
                lineColours.push_back(ColorB(0xffffffff));
                lineColours.push_back(ColorB(0xffffffff));
            }

            DrawLines(context,
                AsPointer(transformedLines.cbegin()),
                AsPointer(lineColours.cbegin()),
                unsigned(transformedLines.size()/2));
        }

    }

    bool    DualContouringTest::ProcessInput(InterfaceState& interfaceState, const InputSnapshot& input)
    {
        return false;
    }

    DualContouringTest::DualContouringTest()
    {
    }

    DualContouringTest::~DualContouringTest()
    {}

}}

#include "../../RenderCore/Metal/DeviceContext.h"
#include "../../RenderCore/Metal/Shader.h"
#include "../../RenderCore/Metal/ShaderResource.h"
#include "../../RenderCore/Metal/RenderTargetView.h"
#include "../../RenderCore/Metal/InputLayout.h"
#include "../../RenderCore/Assets/Services.h"
#include "../../RenderCore/Techniques/ResourceBox.h"
#include "../../RenderCore/Techniques/CommonResources.h"
#include "../../BufferUploads/IBufferUploads.h"
#include "../../BufferUploads/ResourceLocator.h"
#include "../../SceneEngine/SceneEngineUtils.h"
#include "../../Assets/Assets.h"

namespace PlatformRig { namespace Overlays
{
    using namespace RenderCore;

    class CRTBox
    {
    public:
        class Desc {};

        using ResLocator = intrusive_ptr<BufferUploads::ResourceLocator>;
        using SRV = Metal::ShaderResourceView;
        using RTV = Metal::RenderTargetView;

        ResLocator _buffer;
        RTV _bufferRTV;
        SRV _bufferSRV;
        Metal::ViewportDesc _viewport;

        CRTBox(const Desc&);
        ~CRTBox();
    };

    const unsigned width = 64;
    const unsigned height = 64;

    CRTBox::CRTBox(const Desc&)
    {
        using namespace BufferUploads;
        auto& bufferUploads = RenderCore::Assets::Services::GetBufferUploads();
        _buffer = bufferUploads.Transaction_Immediate(
            CreateDesc(BindFlag::RenderTarget|BindFlag::ShaderResource, 0, GPUAccess::Read|GPUAccess::Write,
                TextureDesc::Plain2D(64, 64, Metal::NativeFormat::R8_UNORM), "ConsRasterTest"));
        _bufferRTV = RTV(_buffer->GetUnderlying());
        _bufferSRV = SRV(_buffer->GetUnderlying());
        _viewport = Metal::ViewportDesc(0.f, 0.f, float(width), float(height), 0.f, 1.f);
    }

    CRTBox::~CRTBox() {}

    void    ConservativeRasterTest::Render(
        IOverlayContext* context, Layout& layout,
        Interactables&interactables, InterfaceState& interfaceState)
    {
        auto& box = Techniques::FindCachedBox2<CRTBox>();
        auto metalContext = Metal::DeviceContext::Get(*context->GetDeviceContext());
        SceneEngine::SavedTargets savedTargets(metalContext.get());

        //
        //  we're going to test the conversative rasterization geometry shader
        //  to do this, we need to render to a low-res offscreen texture. Then
        //  we blow that up to fill the screen.
        //

        auto& commonResources = Techniques::CommonResources();
        metalContext->Bind(commonResources._blendOpaque);
        metalContext->Bind(commonResources._dssDisable);
        metalContext->Bind(commonResources._defaultRasterizer);
        // metalContext->Bind(commonResources._cullDisable);
        metalContext->Bind(Metal::Topology::TriangleList);

        Metal::ViewportDesc mainViewport(*metalContext);
        const float scale = XlFloor((mainViewport.Height - 150.f) / box._viewport.Height);
        const Float2 base(5.f, 100.f);

        Float2 triPoints[] =
        {
            Float2(3.f, 3.f),
            Float2(40.f, 58.f),
            Float2(55.f, 5.f)
        };

        if (interfaceState.IsMouseButtonHeld(0)) {
            auto mp = interfaceState.MousePosition();
            triPoints[0] = (mp - base) / scale;
            triPoints[0][0] = XlFloor(triPoints[0][0]*10.f) / 10.f;
            triPoints[0][1] = XlFloor(triPoints[0][1]*10.f) / 10.f;
        }

        if (interfaceState.IsMouseButtonHeld(1)) {
            auto mp = interfaceState.MousePosition();
            triPoints[1] = (mp - base) / scale;
            triPoints[1][0] = XlFloor(triPoints[1][0]*10.f) / 10.f;
            triPoints[1][1] = XlFloor(triPoints[1][1]*10.f) / 10.f;
        }

        TRY
        {
            float clearCol[] = {0.f, 0.f, 0.f, 0.f};
            metalContext->Clear(box._bufferRTV, clearCol);
            metalContext->Bind(MakeResourceList(box._bufferRTV), nullptr);
            metalContext->Bind(box._viewport);

            auto& shader = ::Assets::GetAssetDep<Metal::ShaderProgram>(
                "game/xleres/basic2d.vsh:P2C:vs_*",
                "game/xleres/shadowgen/consraster.sh:gs_conservativeRasterization:gs_*",
                "game/xleres/basic.psh:P:ps_*",
                "");

            class Vertex
            {
            public:
                Float2 p; unsigned col;
            }
            vertices[3] =
            {
                { triPoints[0], 0xffff0000 },
                { triPoints[1], 0xff0000ff },
                { triPoints[2], 0xff00ff00 }
            };
            Metal::VertexBuffer vb(vertices, sizeof(vertices));
            metalContext->Bind(MakeResourceList(vb), sizeof(Vertex), 0);
            Metal::BoundInputLayout inputLayout(Metal::GlobalInputLayouts::P2C, shader);
            metalContext->Bind(inputLayout);

            Float4 recipViewport(1.f / box._viewport.Width, 1.f / box._viewport.Height, 0.f, 0.f);
            SharedPkt constants[] = { MakeSharedPkt(recipViewport) };

            Metal::BoundUniforms uniforms(shader);
            uniforms.BindConstantBuffers(1, {"ReciprocalViewportDimensions"});
            uniforms.Apply(
                *metalContext, context->GetGlobalUniformsStream(),
                Metal::UniformsStream(constants));

            metalContext->Bind(shader);
            metalContext->Draw(3);

        } CATCH (...) {
        } CATCH_END

        savedTargets.ResetToOldTargets(metalContext.get());

        // now render this texture onto the main render target
        TRY
        {
            auto& shader = ::Assets::GetAssetDep<Metal::ShaderProgram>(
                "game/xleres/basic2d.vsh:P2CT:vs_*",
                "game/xleres/basic.psh:PCT:ps_*",
                "");

            class Vertex
            {
            public:
                Float2 p; unsigned col; Float2 tc;
            }
            vertices[6] =
            {
                { Float2(5.f, 100.f), ~0u, Float2(0.f, 0.f) },
                { Float2(5.f, 100.f + scale * box._viewport.Height), ~0u, Float2(0.f, 1.f) },
                { Float2(5.f + scale * box._viewport.Width, 100.f), ~0u, Float2(1.f, 0.f) },
                { Float2(5.f + scale * box._viewport.Width, 100.f), ~0u, Float2(1.f, 0.f) },
                { Float2(5.f, 100.f + scale * box._viewport.Height), ~0u, Float2(0.f, 1.f) },
                { Float2(5.f + scale * box._viewport.Width, 100.f + scale * box._viewport.Height), ~0u, Float2(1.f, 1.f) }
            };
            Metal::VertexBuffer vb(vertices, sizeof(vertices));
            metalContext->Bind(MakeResourceList(vb), sizeof(Vertex), 0);
            Metal::BoundInputLayout inputLayout(Metal::GlobalInputLayouts::P2CT, shader);
            metalContext->Bind(inputLayout);

            Float4 recipViewport(1.f / mainViewport.Width, 1.f / mainViewport.Height, 0.f, 0.f);
            SharedPkt constants[] = { MakeSharedPkt(recipViewport) };
            const Metal::ShaderResourceView* srvs[] = {&box._bufferSRV};

            Metal::BoundUniforms uniforms(shader);
            uniforms.BindShaderResources(1, {"DiffuseTexture"});
            uniforms.BindConstantBuffers(1, {"ReciprocalViewportDimensions"});
            uniforms.Apply(
                *metalContext, context->GetGlobalUniformsStream(),
                Metal::UniformsStream(constants, srvs));

            metalContext->BindPS(MakeResourceList(commonResources._pointClampSampler));
            metalContext->Bind(shader);
            metalContext->Draw(6);

        } CATCH (...) {
        } CATCH_END

                // draw the triangle in wireframe
        context->DrawLine(
            ProjectionMode::P2D,
            Expand(Float2(base + scale * triPoints[0]), 0.f), ColorB(0xffffffff),
            Expand(Float2(base + scale * triPoints[1]), 0.f), ColorB(0xffffffff),
            1.f);

        context->DrawLine(
            ProjectionMode::P2D,
            Expand(Float2(base + scale * triPoints[1]), 0.f), ColorB(0xffffffff),
            Expand(Float2(base + scale * triPoints[2]), 0.f), ColorB(0xffffffff),
            1.f);

        context->DrawLine(
            ProjectionMode::P2D,
            Expand(Float2(base + scale * triPoints[2]), 0.f), ColorB(0xffffffff),
            Expand(Float2(base + scale * triPoints[0]), 0.f), ColorB(0xffffffff),
            1.f);

        metalContext->BindPS(MakeResourceList(commonResources._linearClampSampler));
        metalContext->Bind(commonResources._blendStraightAlpha);
    }

    bool    ConservativeRasterTest::ProcessInput(
        InterfaceState& interfaceState, const InputSnapshot& input)
    {
        return false;
    }

    ConservativeRasterTest::ConservativeRasterTest() {}
    ConservativeRasterTest::~ConservativeRasterTest() {}

}}


text:
package com.alipay.api.request;

import java.util.Map;

import com.alipay.api.AlipayRequest;
import com.alipay.api.internal.util.AlipayHashMap;
import com.alipay.api.response.AlipayMobilePublicAppinfoUpdateResponse;
import com.alipay.api.AlipayObject;

/**
 * ALIPAY API: alipay.mobile.public.appinfo.update request
 *
 * @author auto create
 * @since 1.0, 2016-01-06 21:23:43
 */
public class AlipayMobilePublicAppinfoUpdateRequest implements AlipayRequest<AlipayMobilePublicAppinfoUpdateResponse> {

	private AlipayHashMap udfParams; // add user-defined text parameters
	private String apiVersion="1.0";

	/**
	* 业务json
	 */
	private String bizContent;

	public void setBizContent(String bizContent) {
		this.bizContent = bizContent;
	}
	public String getBizContent() {
		return this.bizContent;
	}
	private String terminalType;
	private String terminalInfo;
	private String prodCode;
	private String notifyUrl;
	private String returnUrl;
	private boolean needEncrypt=false;
	private AlipayObject bizModel=null;

	public String getNotifyUrl() {
		return this.notifyUrl;
	}

	public void setNotifyUrl(String notifyUrl) {
		this.notifyUrl = notifyUrl;
	}

	public String getReturnUrl() {
		return this.returnUrl;
	}

	public void setReturnUrl(String returnUrl) {
		this.returnUrl = returnUrl;
	}

	public String getApiVersion() {
		return this.apiVersion;
	}

	public void setApiVersion(String apiVersion) {
		this.apiVersion = apiVersion;
	}

	public void setTerminalType(String terminalType){
		this.terminalType=terminalType;
	}

    public String getTerminalType(){
    	return this.terminalType;
    }

    public void setTerminalInfo(String terminalInfo){
    	this.terminalInfo=terminalInfo;
    }

    public String getTerminalInfo(){
    	return this.terminalInfo;
    }

	public void setProdCode(String prodCode) {
		this.prodCode=prodCode;
	}

	public String getProdCode() {
		return this.prodCode;
	}

	public String getApiMethodName() {
		return "alipay.mobile.public.appinfo.update";
	}

	public Map<String, String> getTextParams() {
		AlipayHashMap txtParams = new AlipayHashMap();
		txtParams.put("biz_content", this.bizContent);
		if(udfParams != null) {
			txtParams.putAll(this.udfParams);
		}
		return txtParams;
	}

	public void putOtherTextParam(String key, String value) {
		if(this.udfParams == null) {
			this.udfParams = new AlipayHashMap();
		}
		this.udfParams.put(key, value);
	}

	public Class<AlipayMobilePublicAppinfoUpdateResponse> getResponseClass() {
		return AlipayMobilePublicAppinfoUpdateResponse.class;
	}

    public boolean isNeedEncrypt() {

      return this.needEncrypt;
    }

    public void setNeedEncrypt(boolean needEncrypt) {

         this.needEncrypt=needEncrypt;
    }

    public AlipayObject getBizModel() {

      return this.bizModel;
    }

    public void setBizModel(AlipayObject bizModel) {

         this.bizModel=bizModel;
    }

}

redpajama_set_name: RedPajamaGithub


text:
#import "EC2InstanceStateChange.h"

#import "EC2Response.h"

/**
 * Stop Instances Response
 */

@interface EC2StopInstancesResponse:EC2Response

{
    NSMutableArray *stoppingInstances;
}

-(void)setException:(AmazonServiceException *)theException;

/**
 * Default constructor for a new  object.  Callers should use the
 * property methods to initialize this object after creating it.
 */
-(id)init;

/**
 * The list of the stopping instances and details on how their state has
 * changed.
 */
@property (nonatomic, retain) NSMutableArray *stoppingInstances;

/**
 * Returns a value from the stoppingInstances array for the specified index
 */
-(EC2InstanceStateChange *)stoppingInstancesObjectAtIndex:(int)index;

/**
 * Returns a string representation of this object; useful for testing and
 * debugging.
 *
 * @return A string representation of this object.
 */
-(NSString *)description;

@end


text:
package com.sequenceiq.cloudbreak.cmtemplate.configproviders.nifiregistry;

import static com.sequenceiq.cloudbreak.cmtemplate.configproviders.ConfigUtils.config;
import static com.sequenceiq.cloudbreak.cmtemplate.configproviders.VolumeConfigProviderTestHelper.hostGroupWithVolumeCount;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

import java.util.List;
import java.util.Set;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import com.sequenceiq.cloudbreak.cmtemplate.CmTemplateProcessor;
import com.sequenceiq.cloudbreak.cmtemplate.configproviders.nifi.NifiRoles;
import com.sequenceiq.cloudbreak.template.TemplatePreparationObject;
import com.sequenceiq.cloudbreak.template.views.BlueprintView;
import com.sequenceiq.cloudbreak.template.views.HostgroupView;

public class NifiRegistryVolumeConfigProviderTest {

    private final NifiRegistryVolumeConfigProvider subject = new NifiRegistryVolumeConfigProvider();

    @Mock
    private CmTemplateProcessor cmTemplateProcessorMock;

    @Mock
    private BlueprintView blueprintViewMock;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        when(blueprintViewMock.getProcessor()).thenReturn(cmTemplateProcessorMock);
        when(cmTemplateProcessorMock.getStackVersion()).thenReturn("7.2.9");
    }

    @Test
    void testRoleConfigsWithOneVolume() {
        HostgroupView hostGroup = hostGroupWithVolumeCount(1);

        assertEquals(List.of(
                config("log_dir", "/hadoopfs/fs1/nifi-registry-log")),
                subject.getRoleConfigs(NifiRoles.NIFI_NODE, hostGroup, getTemplatePreparationObject(hostGroup))
        );
    }

    @Test
    void testRoleConfigsWithOneVolumeAndStackVersion7210() {
        when(cmTemplateProcessorMock.getStackVersion()).thenReturn("7.2.10");
        HostgroupView hostGroup = hostGroupWithVolumeCount(1);

        assertEquals(List.of(
                config("log_dir", "/hadoopfs/fs1/nifi-registry-log"),
                config("nifi.registry.working.directory", "/hadoopfs/fs1/working-dir")),
                subject.getRoleConfigs(NifiRoles.NIFI_NODE, hostGroup, getTemplatePreparationObject(hostGroup))
        );
    }

    @Test
    void testRoleConfigsWithOneVolumeAndStackVersion7211() {
        when(cmTemplateProcessorMock.getStackVersion()).thenReturn("7.2.11");
        HostgroupView hostGroup = hostGroupWithVolumeCount(1);

        assertEquals(List.of(
                config("log_dir", "/hadoopfs/fs1/nifi-registry-log"),
                config("nifi.registry.working.directory", "/hadoopfs/fs1/working-dir")),
                subject.getRoleConfigs(NifiRoles.NIFI_NODE, hostGroup, getTemplatePreparationObject(hostGroup))
        );
    }

    private TemplatePreparationObject getTemplatePreparationObject(HostgroupView hostGroup) {
        TemplatePreparationObject preparationObject = TemplatePreparationObject.Builder.builder()
                .withHostgroupViews(Set.of(hostGroup))
                .withBlueprintView(blueprintViewMock)
                .build();
        return preparationObject;
    }
}


text:
.class public Lcn/com/smartdevices/bracelet/eventbus/EventBatteryStatus;
.super Ljava/lang/Object;

# instance fields
.field public level:I

.field public status:B

# direct methods
.method public constructor <init>(BI)V
    .locals 1

    const/4 v0, 0x0

    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    iput-byte v0, p0, Lcn/com/smartdevices/bracelet/eventbus/EventBatteryStatus;->status:B

    iput v0, p0, Lcn/com/smartdevices/bracelet/eventbus/EventBatteryStatus;->level:I

    iput-byte p1, p0, Lcn/com/smartdevices/bracelet/eventbus/EventBatteryStatus;->status:B

    iput p2, p0, Lcn/com/smartdevices/bracelet/eventbus/EventBatteryStatus;->level:I

    return-void
.end method


text:
<p>
  injector works!
</p>
<button (click)="invokeService()">Get Value</button>


text:
goog.require('css_selectors.parseATypeSelector');
goog.require('json_testutil.renderJSON');
goog.require('parse_css.parseAStylesheet');
goog.require('parse_css.tokenize');

goog.provide('parse_css.ParseCssTest');

/**
 * A strict comparison between two values.
 * Note: Unfortunately assert.strictEqual has some drawbacks, including that
 * it truncates the provided arguments (and it's not configurable) and
 * with the Closure compiler, it requires a message argument to which
 * we'd always have to pass undefined. Too messy, so we roll our own.
 */
function assertStrictEqual(expected, saw) {
  assert.ok(expected === saw, 'expected: ' + expected + ' saw: ' + saw);
}

function errorsToString(errors) {
  const out = [];
  for (const error of errors) {
    out.push(error.toString());
  }
  return out.join('\n');
}

// Simple function which lets us sort the keys in json output from the parser
// in a way that makes the most logical sense for viewing in the output.
function jsonKeyCmp(a, b) {
  // Lower numbers will be displayed first in the rendered json output.
  const keyPriority = {
    'line': 0,
    'col': 1,
    'tokenType': 2,
    'name': 3,
    'prelude': 4,
    'declarations': 5,
    'rules': 6,
    'errorType': 7,
    'msg': 8,
    'type': 9,
    'value': 10,
    'repr': 11,
    'unit': 12,
    'eof': 13
  };

  // Handle cases where only only one of the two keys is recognized.
  // Unrecognized keys go last.
  if (keyPriority.hasOwnProperty(a) && !keyPriority.hasOwnProperty(b)) {
    return -1;
  }
  if (keyPriority.hasOwnProperty(b) && !keyPriority.hasOwnProperty(a)) {
    return 1;
  }

  // Handle case where both keys are recognized.
  if (keyPriority.hasOwnProperty(b) && keyPriority.hasOwnProperty(a)) {
    return keyPriority[a] - keyPriority[b];
  }

  return json_testutil.defaultCmpFn(a, b);
}

function assertJSONEquals(left, right) {
  assertStrictEqual(
      json_testutil.renderJSON(left, jsonKeyCmp, /*offset=*/4),
      json_testutil.renderJSON(right, jsonKeyCmp, /*offset=*/4));
}

/** @type {!Object<string,parse_css.BlockType>} */
const ampAtRuleParsingSpec = {
  'font-face': parse_css.BlockType.PARSE_AS_DECLARATIONS,
  'media': parse_css.BlockType.PARSE_AS_RULES
};

describe('tokenize', () => {
  it('generates tokens for simple example', () => {
    const css = 'foo { bar: baz; }';
    const errors = [];
    const tokenlist = parse_css.tokenize(css, 1, 0, errors);
    assertStrictEqual(
        'IDENT(foo) WS { WS IDENT(bar) : WS IDENT(baz) ; WS } EOF_TOKEN',
        tokenlist.join(' '));
    assertStrictEqual(0, errors.length);
  });

  it('tokenizes with parse errors', () => {
    const css = ' "\n "';
    const errors = [];
    const tokenlist = parse_css.tokenize(css, 1, 0, errors);
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'WHITESPACE'},
         {'line': 1, 'col': 2, 'tokenType': 'WHITESPACE'},
         {'line': 2, 'col': 1, 'tokenType': 'STRING', 'value': ''},
         {'line': 2, 'col': 2, 'tokenType': 'EOF_TOKEN'}],
        tokenlist);
    assertJSONEquals(
        [{'line': 1, 'col': 1, 'tokenType': 'ERROR', 'errorType':
          'TOKENIZATION', 'msg': 'unterminated string'}], errors);
    assertStrictEqual(':1:1 TOKENIZATION - unterminated string',
                      errorsToString(errors));
  });

  it('provides errors with line col offsets', () => {
    const css =
        'line 1 "unterminated\n' +
        'line 2 "unterminated\n';
    let errors = [];
    parse_css.tokenize(css, 1, 0, errors);
    assertStrictEqual(':1:7 TOKENIZATION - unterminated string\n' +
        ':2:7 TOKENIZATION - unterminated string', errorsToString(errors));
    errors = [];
    parse_css.tokenize(css, 5, 5, errors);
    assertStrictEqual(':5:12 TOKENIZATION - unterminated string\n' +
        ':6:7 TOKENIZATION - unterminated string', errorsToString(errors));
    assertJSONEquals(
        [{'line': 5, 'col': 12, 'tokenType': 'ERROR', 'errorType':
          'TOKENIZATION', 'msg': 'unterminated string'},
         {'line': 6, 'col': 7, 'tokenType': 'ERROR', 'errorType':
          'TOKENIZATION', 'msg': 'unterminated string'}],
        errors);
  });

  it('deals w/ stray backslashes, unterminated comments and bad urls', () => {
    // Note that Javascript has its own escaping, so there's really just one '\'.
    let errors = [];
    parse_css.tokenize('a trailing \\\nbackslash', 1, 0, errors);
    assertStrictEqual(':1:11 TOKENIZATION - stray trailing backslash',
                      errorsToString(errors));

    errors = [];
    parse_css.tokenize('h1 {color: red; } /*', 1, 0, errors);
    assertStrictEqual(':1:17 TOKENIZATION - unterminated comment',
                      errorsToString(errors));

    errors = [];
    parse_css.tokenize('oh hi url(foo"bar)', 1, 0, errors);
    assertStrictEqual(':1:6 TOKENIZATION - bad url', errorsToString(errors));
  });
});

describe('parseAStylesheet', () => {
  it('parses rgb values', () => {
    const css = 'foo { bar: rgb(255, 0, 127); }';
    const errors = [];
    const tokenlist = parse_css.tokenize(css, 1, 0, errors);
    const sheet = parse_css.parseAStylesheet(
        tokenlist, ampAtRuleParsingSpec, parse_css.BlockType.PARSE_AS_IGNORE,
        errors);
    assertJSONEquals(
        {'line': 1, 'col': 0, 'tokenType': 'STYLESHEET', 'rules':
         [{'line': 1, 'col': 0, 'tokenType': 'QUALIFIED_RULE', 'prelude':
           [{'line': 1, 'col': 0, 'tokenType': 'IDENT', 'value': 'foo'},
            {'line': 1, 'col': 3, 'tokenType': 'WHITESPACE'},
            {'line': 1, 'col': 4, 'tokenType': 'EOF_TOKEN'}], 'declarations':
           [{'line': 1, 'col': 6, 'tokenType': 'DECLARATION', 'name':
             'bar', 'value':
             [{'line': 1, 'col': 10, 'tokenType': 'WHITESPACE'},
              {'line': 1, 'col': 11, 'tokenType': 'FUNCTION_TOKEN',
               'value': 'rgb'},
              {'line': 1, 'col': 15, 'tokenType': 'NUMBER', 'type':
               'integer', 'value': 255, 'repr': '255'},
              {'line': 1, 'col': 18, 'tokenType': ','},
              {'line': 1, 'col': 19, 'tokenType': 'WHITESPACE'},
              {'line': 1, 'col': 20, 'tokenType': 'NUMBER', 'type':
               'integer', 'value': 0, 'repr': '0'},
              {'line': 1, 'col': 21, 'tokenType': ','},
              {'line': 1, 'col': 22, 'tokenType': 'WHITESPACE'},
              {'line': 1, 'col': 23, 'tokenType': 'NUMBER', 'type':
               'integer', 'value': 127, 'repr': '127'},
              {'line': 1, 'col': 26, 'tokenType': ')'},
              {'line': 1, 'col': 27, 'tokenType': 'EOF_TOKEN'}], 'important':
             false}]}], 'eof':
         {'line': 1, 'col': 30, 'tokenType': 'EOF_TOKEN'}},
        sheet);
  });

  it('parses a hash reference', () => {
    const css = '#foo {}';
    const errors = [];
    const tokenlist = parse_css.tokenize(css, 1, 0, errors);
    const sheet = parse_css.parseAStylesheet(
        tokenlist, ampAtRuleParsingSpec, parse_css.BlockType.PARSE_AS_IGNORE,
        errors);
    assertJSONEquals(
        {'line': 1, 'col': 0, 'tokenType': 'STYLESHEET', 'rules':
         [{'line': 1, 'col': 0, 'tokenType': 'QUALIFIED_RULE', 'prelude':
           [{'line': 1, 'col': 0, 'tokenType': 'HASH', 'type': 'id',
             'value': 'foo'},
            {'line': 1, 'col': 4, 'tokenType': 'WHITESPACE'},
            {'line': 1, 'col': 5, 'tokenType': 'EOF_TOKEN'}], 'declarations':
           []}], 'eof':
         {'line': 1, 'col': 7, 'tokenType': 'EOF_TOKEN'}},
        sheet);
  });

  it('parses an @media rule', () => {
    const css = '@media {}';
    const errors = [];
    const tokenlist = parse_css.tokenize(css, 1, 0, errors);
    const sheet = parse_css.parseAStylesheet(
        tokenlist, ampAtRuleParsingSpec, parse_css.BlockType.PARSE_AS_IGNORE,
        errors);
    assertJSONEquals(
        {'line': 1, 'col': 0, 'tokenType': 'STYLESHEET', 'rules':
         [{'line': 1, 'col': 0, 'tokenType': 'AT_RULE', 'name': 'media',
           'prelude':
           [{'line': 1, 'col': 6, 'tokenType': 'WHITESPACE'},
            {'line': 1, 'col': 7, 'tokenType': 'EOF_TOKEN'}], 'declarations':
           [], 'rules':
           []}], 'eof':
         {'line': 1, 'col': 9, 'tokenType': 'EOF_TOKEN'}},
        sheet);
  });

  it('parses nested media rules and declarations', () => {
    const css = 'h1 { color: red; }\n' +
        '@media print {\n' +
        '  @media print {\n' +
        '    h2.bar { size: 4px; }\n' +
        '  }\n' +
        '}\n' +
        '@font-face {\n' +
        '  font-family: \'MyFont\';\n' +
        '  src: url(\'foo.ttf\');\n' +
        '}';
    const errors = [];
    const tokenlist = parse_css.tokenize(css, 1, 0, errors);
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'IDENT', 'value': 'h1'},
         {'line': 1, 'col': 2, 'tokenType': 'WHITESPACE'},
         {'line': 1, 'col': 3, 'tokenType': '{'},
         {'line': 1, 'col': 4, 'tokenType': 'WHITESPACE'},
         {'line': 1, 'col': 5, 'tokenType': 'IDENT', 'value': 'color'},
         {'line': 1, 'col': 10, 'tokenType': ':'},
         {'line': 1, 'col': 11, 'tokenType': 'WHITESPACE'},
         {'line': 1, 'col': 12, 'tokenType': 'IDENT', 'value': 'red'},
         {'line': 1, 'col': 15, 'tokenType': ';'},
         {'line': 1, 'col': 16, 'tokenType': 'WHITESPACE'},
         {'line': 1, 'col': 17, 'tokenType': '}'},
         {'line': 1, 'col': 18, 'tokenType': 'WHITESPACE'},
         {'line': 2, 'col': 0, 'tokenType': 'AT-KEYWORD', 'value':
          'media'},
         {'line': 2, 'col': 6, 'tokenType': 'WHITESPACE'},
         {'line': 2, 'col': 7, 'tokenType': 'IDENT', 'value': 'print'},
         {'line': 2, 'col': 12, 'tokenType': 'WHITESPACE'},
         {'line': 2, 'col': 13, 'tokenType': '{'},
         {'line': 2, 'col': 14, 'tokenType': 'WHITESPACE'},
         {'line': 3, 'col': 2, 'tokenType': 'AT-KEYWORD', 'value':
          'media'},
         {'line': 3, 'col': 8, 'tokenType': 'WHITESPACE'},
         {'line': 3, 'col': 9, 'tokenType': 'IDENT', 'value': 'print'},
         {'line': 3, 'col': 14, 'tokenType': 'WHITESPACE'},
         {'line': 3, 'col': 15, 'tokenType': '{'},
         {'line': 3, 'col': 16, 'tokenType': 'WHITESPACE'},
         {'line': 4, 'col': 4, 'tokenType': 'IDENT', 'value': 'h2'},
         {'line': 4, 'col': 6, 'tokenType': 'DELIM', 'value': '.'},
         {'line': 4, 'col': 7, 'tokenType': 'IDENT', 'value': 'bar'},
         {'line': 4, 'col': 10, 'tokenType': 'WHITESPACE'},
         {'line': 4, 'col': 11, 'tokenType': '{'},
         {'line': 4, 'col': 12, 'tokenType': 'WHITESPACE'},
         {'line': 4, 'col': 13, 'tokenType': 'IDENT', 'value': 'size'},
         {'line': 4, 'col': 17, 'tokenType': ':'},
         {'line': 4, 'col': 18, 'tokenType': 'WHITESPACE'},
         {'line': 4, 'col': 19, 'tokenType': 'DIMENSION', 'type':
          'integer', 'value': 4, 'repr': '4', 'unit': 'px'},
         {'line': 4, 'col': 22, 'tokenType': ';'},
         {'line': 4, 'col': 23, 'tokenType': 'WHITESPACE'},
         {'line': 4, 'col': 24, 'tokenType': '}'},
         {'line': 4, 'col': 25, 'tokenType': 'WHITESPACE'},
         {'line': 5, 'col': 2, 'tokenType': '}'},
         {'line': 5, 'col': 3, 'tokenType': 'WHITESPACE'},
         {'line': 6, 'col': 0, 'tokenType': '}'},
         {'line': 6, 'col': 1, 'tokenType': 'WHITESPACE'},
         {'line': 7, 'col': 0, 'tokenType': 'AT-KEYWORD', 'value':
          'font-face'},
         {'line': 7, 'col': 10, 'tokenType': 'WHITESPACE'},
         {'line': 7, 'col': 11, 'tokenType': '{'},
         {'line': 7, 'col': 12, 'tokenType': 'WHITESPACE'},
         {'line': 8, 'col': 2, 'tokenType': 'IDENT', 'value': 'font-family'},
         {'line': 8, 'col': 13, 'tokenType': ':'},
         {'line': 8, 'col': 14, 'tokenType': 'WHITESPACE'},
         {'line': 8, 'col': 15, 'tokenType': 'STRING', 'value': 'MyFont'},
         {'line': 8, 'col': 23, 'tokenType': ';'},
         {'line': 8, 'col': 24, 'tokenType': 'WHITESPACE'},
         {'line': 9, 'col': 2, 'tokenType': 'IDENT', 'value': 'src'},
         {'line': 9, 'col': 5, 'tokenType': ':'},
         {'line': 9, 'col': 6, 'tokenType': 'WHITESPACE'},
         {'line': 9, 'col': 7, 'tokenType': 'FUNCTION_TOKEN', 'value':
          'url'},
         {'line': 9, 'col': 11, 'tokenType': 'STRING', 'value': 'foo.ttf'},
         {'line': 9, 'col': 20, 'tokenType': ')'},
         {'line': 9, 'col': 21, 'tokenType': ';'},
         {'line': 9, 'col': 22, 'tokenType': 'WHITESPACE'},
         {'line': 10, 'col': 0, 'tokenType': '}'},
         {'line': 10, 'col': 1, 'tokenType': 'EOF_TOKEN'}],
        tokenlist);
    const sheet = parse_css.parseAStylesheet(
        tokenlist, ampAtRuleParsingSpec, parse_css.BlockType.PARSE_AS_IGNORE,
        errors);
    assertStrictEqual(0, errors.length);
    assertJSONEquals(
        {'line': 1, 'col': 0, 'tokenType': 'STYLESHEET', 'rules':
         [{'line': 1, 'col': 0, 'tokenType': 'QUALIFIED_RULE', 'prelude':
           [{'line': 1, 'col': 0, 'tokenType': 'IDENT', 'value': 'h1'},
            {'line': 1, 'col': 2, 'tokenType': 'WHITESPACE'},
            {'line': 1, 'col': 3, 'tokenType': 'EOF_TOKEN'}], 'declarations':
           [{'line': 1, 'col': 5, 'tokenType': 'DECLARATION', 'name':
             'color', 'value':
             [{'line': 1, 'col': 11, 'tokenType': 'WHITESPACE'},
              {'line': 1, 'col': 12, 'tokenType': 'IDENT', 'value':
               'red'},
              {'line': 1, 'col': 15, 'tokenType': 'EOF_TOKEN'}], 'important':
             false}]},
          {'line': 2, 'col': 0, 'tokenType': 'AT_RULE', 'name': 'media',
           'prelude':
           [{'line': 2, 'col': 6, 'tokenType': 'WHITESPACE'},
            {'line': 2, 'col': 7, 'tokenType': 'IDENT', 'value': 'print'},
            {'line': 2, 'col': 12, 'tokenType': 'WHITESPACE'},
            {'line': 2, 'col': 13, 'tokenType': 'EOF_TOKEN'}], 'declarations':
           [], 'rules':
           [{'line': 3, 'col': 2, 'tokenType': 'AT_RULE', 'name':
             'media', 'prelude':
             [{'line': 3, 'col': 8, 'tokenType': 'WHITESPACE'},
              {'line': 3, 'col': 9, 'tokenType': 'IDENT', 'value':
               'print'},
              {'line': 3, 'col': 14, 'tokenType': 'WHITESPACE'},
              {'line': 3, 'col': 15, 'tokenType': 'EOF_TOKEN'}], 'declarations':
             [], 'rules':
             [{'line': 4, 'col': 4, 'tokenType': 'QUALIFIED_RULE',
               'prelude':
               [{'line': 4, 'col': 4, 'tokenType': 'IDENT', 'value':
                 'h2'},
                {'line': 4, 'col': 6, 'tokenType': 'DELIM', 'value':
                 '.'},
                {'line': 4, 'col': 7, 'tokenType': 'IDENT', 'value':
                 'bar'},
                {'line': 4, 'col': 10, 'tokenType': 'WHITESPACE'},
                {'line': 4, 'col': 11, 'tokenType': 'EOF_TOKEN'}],
               'declarations':
               [{'line': 4, 'col': 13, 'tokenType': 'DECLARATION',
                 'name': 'size', 'value':
                 [{'line': 4, 'col': 18, 'tokenType': 'WHITESPACE'},
                  {'line': 4, 'col': 19, 'tokenType': 'DIMENSION',
                   'type': 'integer', 'value': 4, 'repr': '4', 'unit':
                   'px'},
                  {'line': 4, 'col': 22, 'tokenType': 'EOF_TOKEN'}],
                 'important': false}]}]}]},
          {'line': 7, 'col': 0, 'tokenType': 'AT_RULE', 'name': 'font-face',
           'prelude':
           [{'line': 7, 'col': 10, 'tokenType': 'WHITESPACE'},
            {'line': 7, 'col': 11, 'tokenType': 'EOF_TOKEN'}], 'declarations':
           [{'line': 8, 'col': 2, 'tokenType': 'DECLARATION', 'name':
             'font-family', 'value':
             [{'line': 8, 'col': 14, 'tokenType': 'WHITESPACE'},
              {'line': 8, 'col': 15, 'tokenType': 'STRING', 'value':
               'MyFont'},
              {'line': 8, 'col': 23, 'tokenType': 'EOF_TOKEN'}], 'important':
             false},
            {'line': 9, 'col': 2, 'tokenType': 'DECLARATION', 'name':
             'src', 'value':
             [{'line': 9, 'col': 6, 'tokenType': 'WHITESPACE'},
              {'line': 9, 'col': 7, 'tokenType': 'FUNCTION_TOKEN',
               'value': 'url'},
              {'line': 9, 'col': 11, 'tokenType': 'STRING', 'value':
               'foo.ttf'},
              {'line': 9, 'col': 20, 'tokenType': ')'},
              {'line': 9, 'col': 21, 'tokenType': 'EOF_TOKEN'}], 'important':
             false}], 'rules':
           []}], 'eof':
         {'line': 10, 'col': 1, 'tokenType': 'EOF_TOKEN'}},
        sheet);
  });

  it('generates errors not assertions for invalid css', () => {
    const css = '#foo { foo.bar {} }\n' +  // qual. rule inside declarations
    '@font-face { @media {} }\n' +  // @rule inside declarations
    '@media { @gregable }\n' +  // unrecognized @rule, ignored
    'color: red;\n';  // declaration outside qualified rule.
    const errors = [];
    const tokenlist = parse_css.tokenize(css, 1, 0, errors);
    const sheet = parse_css.parseAStylesheet(
        tokenlist, ampAtRuleParsingSpec, parse_css.BlockType.PARSE_AS_IGNORE,
        errors);
    assertJSONEquals(
        [{'line': 1, 'col': 7, 'tokenType': 'ERROR', 'errorType':
          'PARSING', 'msg': 'Incomplete declaration'},
         {'line': 2, 'col': 13, 'tokenType': 'ERROR', 'errorType':
          'PARSING', 'msg': '@media found inside declaration'},
         {'line': 4, 'col': 0, 'tokenType': 'ERROR', 'errorType':
          'PARSING', 'msg':
          'Hit EOF when trying to parse the prelude of a ' +
              'qualified rule.'}],
        errors);
  });

  it('generates errors based on the grammar', () => {
    // @gregable is not supported by the grammar.
    const css = '@gregable {}\n.foo{prop}';
    const errors = [];
    const tokenlist = parse_css.tokenize(css, 1, 0, errors);
    const sheet = parse_css.parseAStylesheet(
        tokenlist, ampAtRuleParsingSpec, parse_css.BlockType.PARSE_AS_IGNORE,
        errors);
    assertJSONEquals(
        [{'line': 2, 'col': 5, 'tokenType': 'ERROR', 'errorType':
          'PARSING', 'msg': 'Incomplete declaration'}], errors);
    assertJSONEquals(
        {'line': 1, 'col': 0, 'tokenType': 'STYLESHEET', 'rules':
         [{'line': 1, 'col': 0, 'tokenType': 'AT_RULE', 'name': 'gregable',
           'prelude':
           [{'line': 1, 'col': 9, 'tokenType': 'WHITESPACE'},
            {'line': 1, 'col': 10, 'tokenType': 'EOF_TOKEN'}], 'declarations':
           [], 'rules':
           []},
          {'line': 2, 'col': 0, 'tokenType': 'QUALIFIED_RULE', 'prelude':
           [{'line': 2, 'col': 0, 'tokenType': 'DELIM', 'value': '.'},
            {'line': 2, 'col': 1, 'tokenType': 'IDENT', 'value': 'foo'},
            {'line': 2, 'col': 4, 'tokenType': 'EOF_TOKEN'}], 'declarations':
           []}], 'eof':
         {'line': 2, 'col': 10, 'tokenType': 'EOF_TOKEN'}},
        sheet);
  });

  it('handles a nested media rule with declarations', () => {
    const css =
        '@media print {\n' +
        '/* hide navigation controls when printing */\n' +
        '#navigation { display: none }\n' +
        '@media (max-width: 12cm) {\n' +
        '  /* keep notes in flow when printing to narrow pages */\n' +
        '  .note { float: none }\n' +
        '}';
    const errors = [];
    const tokenlist = parse_css.tokenize(css, 1, 0, errors);
    const sheet = parse_css.parseAStylesheet(
        tokenlist, ampAtRuleParsingSpec, parse_css.BlockType.PARSE_AS_IGNORE,
        errors);

    assertJSONEquals(
        {'line': 1, 'col': 0, 'tokenType': 'STYLESHEET', 'rules':
         [{'line': 1, 'col': 0, 'tokenType': 'AT_RULE', 'name': 'media',
           'prelude':
           [{'line': 1, 'col': 6, 'tokenType': 'WHITESPACE'},
            {'line': 1, 'col': 7, 'tokenType': 'IDENT', 'value': 'print'},
            {'line': 1, 'col': 12, 'tokenType': 'WHITESPACE'},
            {'line': 1, 'col': 13, 'tokenType': 'EOF_TOKEN'}], 'declarations':
           [], 'rules':
           [{'line': 3, 'col': 0, 'tokenType': 'QUALIFIED_RULE', 'prelude':
             [{'line': 3, 'col': 0, 'tokenType': 'HASH', 'type': 'id',
               'value': 'navigation'},
              {'line': 3, 'col': 11, 'tokenType': 'WHITESPACE'},
              {'line': 3, 'col': 12, 'tokenType': 'EOF_TOKEN'}],
             'declarations':
             [{'line': 3, 'col': 14, 'tokenType': 'DECLARATION', 'name':
               'display', 'value':
               [{'line': 3, 'col': 22, 'tokenType': 'WHITESPACE'},
                {'line': 3, 'col': 23, 'tokenType': 'IDENT', 'value':
                 'none'},
                {'line': 3, 'col': 27, 'tokenType': 'WHITESPACE'},
                {'line': 3, 'col': 28, 'tokenType': 'EOF_TOKEN'}],
               'important': false}]},
            {'line': 4, 'col': 0, 'tokenType': 'AT_RULE', 'name':
             'media', 'prelude':
             [{'line': 4, 'col': 6, 'tokenType': 'WHITESPACE'},
              {'line': 4, 'col': 7, 'tokenType': '('},
              {'line': 4, 'col': 8, 'tokenType': 'IDENT', 'value':
               'max-width'},
              {'line': 4, 'col': 17, 'tokenType': ':'},
              {'line': 4, 'col': 18, 'tokenType': 'WHITESPACE'},
              {'line': 4, 'col': 19, 'tokenType': 'DIMENSION', 'type':
               'integer', 'value': 12, 'repr': '12', 'unit': 'cm'},
              {'line': 4, 'col': 23, 'tokenType': ')'},
              {'line': 4, 'col': 24, 'tokenType': 'WHITESPACE'},
              {'line': 4, 'col': 25, 'tokenType': 'EOF_TOKEN'}],
             'declarations': [], 'rules':
             [{'line': 6, 'col': 2, 'tokenType': 'QUALIFIED_RULE',
               'prelude':
               [{'line': 6, 'col': 2, 'tokenType': 'DELIM', 'value':
                 '.'},
                {'line': 6, 'col': 3, 'tokenType': 'IDENT', 'value':
                 'note'},
                {'line': 6, 'col': 7, 'tokenType': 'WHITESPACE'},
                {'line': 6, 'col': 8, 'tokenType': 'EOF_TOKEN'}],
               'declarations':
               [{'line': 6, 'col': 10, 'tokenType': 'DECLARATION',
                 'name': 'float', 'value':
                 [{'line': 6, 'col': 16, 'tokenType': 'WHITESPACE'},
                  {'line': 6, 'col': 17, 'tokenType': 'IDENT', 'value':
                   'none'},
                  {'line': 6, 'col': 21, 'tokenType': 'WHITESPACE'},
                  {'line': 6, 'col': 22, 'tokenType': 'EOF_TOKEN'}],
                 'important': false}]}]}]}], 'eof':
         {'line': 7, 'col': 1, 'tokenType': 'EOF_TOKEN'}},
        sheet);
  });

  it('handles selectors but does not parse them in detail yet', () => {
    const css = ' h1 { color: blue; } ';
    const errors = [];
    const tokenlist = parse_css.tokenize(css, 1, 0, errors);
    const sheet = parse_css.parseAStylesheet(
        tokenlist, ampAtRuleParsingSpec, parse_css.BlockType.PARSE_AS_IGNORE,
        errors);

    assertJSONEquals(
        {'line': 1, 'col': 0, 'tokenType': 'STYLESHEET', 'rules':
         [{'line': 1, 'col': 1, 'tokenType': 'QUALIFIED_RULE', 'prelude':
           [{'line': 1, 'col': 1, 'tokenType': 'IDENT', 'value': 'h1'},
            {'line': 1, 'col': 3, 'tokenType': 'WHITESPACE'},
            {'line': 1, 'col': 4, 'tokenType': 'EOF_TOKEN'}], 'declarations':
           [{'line': 1, 'col': 6, 'tokenType': 'DECLARATION', 'name':
             'color', 'value':
             [{'line': 1, 'col': 12, 'tokenType': 'WHITESPACE'},
              {'line': 1, 'col': 13, 'tokenType': 'IDENT', 'value':
               'blue'},
              {'line': 1, 'col': 17, 'tokenType': 'EOF_TOKEN'}], 'important':
             false}]}], 'eof':
         {'line': 1, 'col': 21, 'tokenType': 'EOF_TOKEN'}},
        sheet);
  });

  // The tests below are exploratory - they tell us what the css parser
  // currently produces for these selectors. For a list of selectors, see
  // http://www.w3.org/TR/css3-selectors/#selectors.
  //
  // TODO(johannes): Get complete coverage.

  it('handles simple selector example', () => {
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'DELIM', 'value': '*'},
         {'line': 1, 'col': 1, 'tokenType': 'EOF_TOKEN'}],
        parseSelectorForTest('*'));
  });

  it('handles another selector example', () => {
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'IDENT', 'value': 'E'},
         {'line': 1, 'col': 1, 'tokenType': 'EOF_TOKEN'}],
        parseSelectorForTest('E'));
  });

  it('handles selector example with square braces', () => {
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'IDENT', 'value': 'E'},
         {'line': 1, 'col': 1, 'tokenType': '['},
         {'line': 1, 'col': 2, 'tokenType': 'IDENT', 'value': 'foo'},
         {'line': 1, 'col': 5, 'tokenType': ']'},
         {'line': 1, 'col': 6, 'tokenType': 'EOF_TOKEN'}],
        parseSelectorForTest('E[foo]'));
  });

  it('handles selector example with string matching', () => {
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'IDENT', 'value': 'E'},
         {'line': 1, 'col': 1, 'tokenType': '['},
         {'line': 1, 'col': 2, 'tokenType': 'IDENT', 'value': 'foo'},
         {'line': 1, 'col': 5, 'tokenType': 'DELIM', 'value': '='},
         {'line': 1, 'col': 6, 'tokenType': 'STRING', 'value': 'bar'},
         {'line': 1, 'col': 11, 'tokenType': ']'},
         {'line': 1, 'col': 12, 'tokenType': 'EOF_TOKEN'}],
        parseSelectorForTest('E[foo="bar"]'));
  });
});

function parseSelectorForTest(selector) {
  const css = selector + '{}';
  const errors = [];
  const tokenlist = parse_css.tokenize(css, 1, 0, errors);
  const sheet = parse_css.parseAStylesheet(
      tokenlist, ampAtRuleParsingSpec, parse_css.BlockType.PARSE_AS_IGNORE,
      errors);
  return sheet['rules'][0].prelude;
}

//
// Below this line: unittests for css-selectors.js.
//
describe('css_selectors', () => {
  it('parses a type selector', () => {
    const tokens = parseSelectorForTest('*');
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'DELIM', 'value': '*'},
         {'line': 1, 'col': 1, 'tokenType': 'EOF_TOKEN'}], tokens);
    let tokenStream = new parse_css.TokenStream(tokens);
    tokenStream.consume();
    let typeSelector = css_selectors.parseATypeSelector(tokenStream);
    assertStrictEqual('*', typeSelector.toString());

    tokenStream = new parse_css.TokenStream(parseSelectorForTest('*|*'));
    tokenStream.consume();
    typeSelector = css_selectors.parseATypeSelector(tokenStream);
    assertStrictEqual('*|*', typeSelector.toString());

    tokenStream = new parse_css.TokenStream(parseSelectorForTest('*|E'));
    tokenStream.consume();
    typeSelector = css_selectors.parseATypeSelector(tokenStream);
    assertStrictEqual('*|E', typeSelector.toString());

    tokenStream = new parse_css.TokenStream(parseSelectorForTest('svg|E'));
    tokenStream.consume();
    typeSelector = css_selectors.parseATypeSelector(tokenStream);
    assertStrictEqual('svg|E', typeSelector.toString());

    tokenStream = new parse_css.TokenStream(parseSelectorForTest('svg|*'));
    tokenStream.consume();
    typeSelector = css_selectors.parseATypeSelector(tokenStream);
    assertStrictEqual('svg|*', typeSelector.toString());

    tokenStream = new parse_css.TokenStream(parseSelectorForTest('|E'));
    tokenStream.consume();
    typeSelector = css_selectors.parseATypeSelector(tokenStream);
    assertStrictEqual('|E', typeSelector.toString());
  });

  it('parses an id selector', () => {
    const tokens = parseSelectorForTest('#hello-world');
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'HASH', 'type': 'id',
          'value': 'hello-world'},
         {'line': 1, 'col': 12, 'tokenType': 'EOF_TOKEN'}], tokens);
    const tokenStream = new parse_css.TokenStream(tokens);
    tokenStream.consume();
    const idSelector = css_selectors.parseAnIdSelector(tokenStream);
    assertStrictEqual('#hello-world', idSelector.toString());
    assertStrictEqual(1, idSelector.line);
    assertStrictEqual(0, idSelector.col);
  });

  it('parses a class selectro', () => {
    const tokens = parseSelectorForTest('.hello-world');
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'DELIM', 'value': '.'},
         {'line': 1, 'col': 1, 'tokenType': 'IDENT', 'value': 'hello-world'},
         {'line': 1, 'col': 12, 'tokenType': 'EOF_TOKEN'}],
        tokens);
    const tokenStream = new parse_css.TokenStream(tokens);
    tokenStream.consume();
    const classSelector = css_selectors.parseAClassSelector(tokenStream);
    assertStrictEqual('.hello-world', classSelector.toString());
    assertStrictEqual(1, classSelector.line);
    assertStrictEqual(0, classSelector.col);
  });

  it('parses a simple selector sequence', () => {
    let tokens = parseSelectorForTest('a|b#c');
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'IDENT', 'value': 'a'},
         {'line': 1, 'col': 1, 'tokenType': 'DELIM', 'value': '|'},
         {'line': 1, 'col': 2, 'tokenType': 'IDENT', 'value': 'b'},
         {'line': 1, 'col': 3, 'tokenType': 'HASH', 'type': 'id',
          'value': 'c'},
         {'line': 1, 'col': 5, 'tokenType': 'EOF_TOKEN'}], tokens);
    let tokenStream = new parse_css.TokenStream(tokens);
    tokenStream.consume();
    let sequence = css_selectors.parseASimpleSelectorSequence(tokenStream);
    assertJSONEquals(
        {'line': 1, 'col': 0, 'node': 'SIMPLE_SELECTOR_SEQUENCE',
         'otherSelectors':
         [{'line': 1, 'col': 3, 'value': 'c', 'node': 'ID_SELECTOR'}],
         'typeSelector':
         {'line': 1, 'col': 0, 'elementName': 'b', 'namespacePrefix':
          'a', 'node': 'TYPE_SELECTOR'}},
        sequence);
    tokens = parseSelectorForTest('a|foo#bar.baz');
    tokenStream = new parse_css.TokenStream(tokens);
    tokenStream.consume();
    sequence = css_selectors.parseASimpleSelectorSequence(tokenStream);
    assertJSONEquals(
        {'line': 1, 'col': 0, 'node': 'SIMPLE_SELECTOR_SEQUENCE',
         'otherSelectors':
         [{'line': 1, 'col': 5, 'value': 'bar', 'node': 'ID_SELECTOR'},
          {'line': 1, 'col': 9, 'value': 'baz', 'node': 'CLASS_SELECTOR'}],
         'typeSelector':
         {'line': 1, 'col': 0, 'elementName': 'foo', 'namespacePrefix':
          'a', 'node': 'TYPE_SELECTOR'}},
        sequence);
  });

  it('parses a selector', () => {
    const tokens = parseSelectorForTest('foo bar \n baz');
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'IDENT', 'value': 'foo'},
         {'line': 1, 'col': 3, 'tokenType': 'WHITESPACE'},
         {'line': 1, 'col': 4, 'tokenType': 'IDENT', 'value': 'bar'},
         {'line': 1, 'col': 7, 'tokenType': 'WHITESPACE'},
         {'line': 2, 'col': 1, 'tokenType': 'IDENT', 'value': 'baz'},
         {'line': 2, 'col': 4, 'tokenType': 'EOF_TOKEN'}],
        tokens);
    const tokenStream = new parse_css.TokenStream(tokens);
    tokenStream.consume();
    const selector = css_selectors.parseASelector(tokenStream);
    assertJSONEquals(
        {'line': 1, 'col': 7, 'combinatorType': 'DESCENDANT', 'left':
         {'line': 1, 'col': 3, 'combinatorType': 'DESCENDANT', 'left':
          {'line': 1, 'col': 0, 'node': 'SIMPLE_SELECTOR_SEQUENCE',
           'otherSelectors':
           [], 'typeSelector':
           {'line': 1, 'col': 0, 'elementName': 'foo', 'namespacePrefix':
            null, 'node': 'TYPE_SELECTOR'}}, 'node': 'COMBINATOR',
          'right':
          {'line': 1, 'col': 4, 'node': 'SIMPLE_SELECTOR_SEQUENCE',
           'otherSelectors':
           [], 'typeSelector':
           {'line': 1, 'col': 4, 'elementName': 'bar', 'namespacePrefix':
            null, 'node': 'TYPE_SELECTOR'}}}, 'node': 'COMBINATOR',
         'right':
         {'line': 2, 'col': 1, 'node': 'SIMPLE_SELECTOR_SEQUENCE',
          'otherSelectors':
          [], 'typeSelector':
          {'line': 2, 'col': 1, 'elementName': 'baz', 'namespacePrefix':
           null, 'node': 'TYPE_SELECTOR'}}},
        selector);
  });

  it('parses a selectors group', () => {
    const tokens = parseSelectorForTest('foo, bar \n, baz');
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'IDENT', 'value': 'foo'},
         {'line': 1, 'col': 3, 'tokenType': ','},
         {'line': 1, 'col': 4, 'tokenType': 'WHITESPACE'},
         {'line': 1, 'col': 5, 'tokenType': 'IDENT', 'value': 'bar'},
         {'line': 1, 'col': 8, 'tokenType': 'WHITESPACE'},
         {'line': 2, 'col': 0, 'tokenType': ','},
         {'line': 2, 'col': 1, 'tokenType': 'WHITESPACE'},
         {'line': 2, 'col': 2, 'tokenType': 'IDENT', 'value': 'baz'},
         {'line': 2, 'col': 5, 'tokenType': 'EOF_TOKEN'}],
        tokens);
    const tokenStream = new parse_css.TokenStream(tokens);
    tokenStream.consume();
    const selector = css_selectors.parseASelectorsGroup(tokenStream);
    assertJSONEquals(
        {'line': 1, 'col': 0, 'elements':
         [{'line': 1, 'col': 0, 'node': 'SIMPLE_SELECTOR_SEQUENCE',
           'otherSelectors':
           [], 'typeSelector':
           {'line': 1, 'col': 0, 'elementName': 'foo', 'namespacePrefix':
            null, 'node': 'TYPE_SELECTOR'}},
          {'line': 1, 'col': 5, 'node': 'SIMPLE_SELECTOR_SEQUENCE',
           'otherSelectors':
           [], 'typeSelector':
           {'line': 1, 'col': 5, 'elementName': 'bar', 'namespacePrefix':
            null, 'node': 'TYPE_SELECTOR'}},
          {'line': 2, 'col': 2, 'node': 'SIMPLE_SELECTOR_SEQUENCE',
           'otherSelectors':
           [], 'typeSelector':
           {'line': 2, 'col': 2, 'elementName': 'baz', 'namespacePrefix':
            null, 'node': 'TYPE_SELECTOR'}}], 'node': 'SELECTORS_GROUP'},
        selector);
  });

  it('parses a selectors group with an attrib match', () => {
    const tokens = parseSelectorForTest('a[href="http://www.w3.org/"]');
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'IDENT', 'value': 'a'},
         {'line': 1, 'col': 1, 'tokenType': '['},
         {'line': 1, 'col': 2, 'tokenType': 'IDENT', 'value': 'href'},
         {'line': 1, 'col': 6, 'tokenType': 'DELIM', 'value': '='},
         {'line': 1, 'col': 7, 'tokenType': 'STRING',
          'value': 'http://www.w3.org/'},
         {'line': 1, 'col': 27, 'tokenType': ']'},
         {'line': 1, 'col': 28, 'tokenType': 'EOF_TOKEN'}], tokens);
    const tokenStream = new parse_css.TokenStream(tokens);
    tokenStream.consume();
    const selector = css_selectors.parseASelectorsGroup(tokenStream);
    assertJSONEquals(
        {'line': 1, 'col': 0, 'node': 'SIMPLE_SELECTOR_SEQUENCE',
         'otherSelectors':
         [{'line': 1, 'col': 1, 'value':
           [{'line': 1, 'col': 2, 'tokenType': 'IDENT', 'value': 'href'},
            {'line': 1, 'col': 6, 'tokenType': 'DELIM', 'value': '='},
            {'line': 1, 'col': 7, 'tokenType': 'STRING', 'value':
             'http://www.w3.org/'},
            {'line': 1, 'col': 27, 'tokenType': 'EOF_TOKEN'}], 'node':
           'ATTR_SELECTOR'}], 'typeSelector':
         {'line': 1, 'col': 0, 'elementName': 'a', 'namespacePrefix':
          null, 'node': 'TYPE_SELECTOR'}},
        selector);
  });

  it('parses a selectors group with a pseudo class', () => {
    const tokens = parseSelectorForTest('a::b:lang(fr-be)]');
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'IDENT', 'value': 'a'},
         {'line': 1, 'col': 1, 'tokenType': ':'},
         {'line': 1, 'col': 2, 'tokenType': ':'},
         {'line': 1, 'col': 3, 'tokenType': 'IDENT', 'value': 'b'},
         {'line': 1, 'col': 4, 'tokenType': ':'},
         {'line': 1, 'col': 5, 'tokenType': 'FUNCTION_TOKEN', 'value':
          'lang'},
         {'line': 1, 'col': 10, 'tokenType': 'IDENT', 'value': 'fr-be'},
         {'line': 1, 'col': 15, 'tokenType': ')'},
         {'line': 1, 'col': 16, 'tokenType': ']'},
         {'line': 1, 'col': 17, 'tokenType': 'EOF_TOKEN'}], tokens);
    const tokenStream = new parse_css.TokenStream(tokens);
    tokenStream.consume();
    const selector = css_selectors.parseASelectorsGroup(tokenStream);
    assertJSONEquals(
        {'line': 1, 'col': 0, 'node': 'SIMPLE_SELECTOR_SEQUENCE',
         'otherSelectors':
         [{'line': 1, 'col': 1, 'name': 'b', 'isClass': false, 'node':
           'PSEUDO_SELECTOR'},
          {'line': 1, 'col': 4, 'name': 'lang', 'func':
           [{'line': 1, 'col': 5, 'tokenType': 'FUNCTION_TOKEN', 'value':
             'lang'},
            {'line': 1, 'col': 10, 'tokenType': 'IDENT', 'value':
             'fr-be'},
            {'line': 1, 'col': 15, 'tokenType': 'EOF_TOKEN'}], 'isClass':
           true, 'node': 'PSEUDO_SELECTOR'}], 'typeSelector':
         {'line': 1, 'col': 0, 'elementName': 'a', 'namespacePrefix':
          null, 'node': 'TYPE_SELECTOR'}},
        selector);
  });

  it('parses a selectors group with a negation', () => {
    // This test records the status quo with respect to negation:
    // We allow it, but don't currently parse the inside of it, we just
    // mirror it over into the 'func' field of the pseudo selector.
    const tokens = parseSelectorForTest('html|*:not(:link):not(:visited)');
    const tokenStream = new parse_css.TokenStream(tokens);
    tokenStream.consume();
    const selector = css_selectors.parseASelectorsGroup(tokenStream);
    assertJSONEquals(
        {'line': 1, 'col': 0, 'node': 'SIMPLE_SELECTOR_SEQUENCE',
         'otherSelectors':
         [{'line': 1, 'col': 6, 'name': 'not', 'func':
           [{'line': 1, 'col': 7, 'tokenType': 'FUNCTION_TOKEN', 'value':
             'not'},
            {'line': 1, 'col': 11, 'tokenType': ':'},
            {'line': 1, 'col': 12, 'tokenType': 'IDENT', 'value':
             'link'},
            {'line': 1, 'col': 16, 'tokenType': 'EOF_TOKEN'}], 'isClass':
           true, 'node': 'PSEUDO_SELECTOR'}], 'typeSelector':
         {'line': 1, 'col': 0, 'elementName': '*', 'namespacePrefix':
          'html', 'node': 'TYPE_SELECTOR'}},
        selector);
  });

  it('reports error for unparsed remainder of input', () => {
    const tokens = parseSelectorForTest('foo bar .');
    assertJSONEquals(
        [{'line': 1, 'col': 0, 'tokenType': 'IDENT', 'value': 'foo'},
         {'line': 1, 'col': 3, 'tokenType': 'WHITESPACE'},
         {'line': 1, 'col': 4, 'tokenType': 'IDENT', 'value': 'bar'},
         {'line': 1, 'col': 7, 'tokenType': 'WHITESPACE'},
         {'line': 1, 'col': 8, 'tokenType': 'DELIM', 'value': '.'},
         {'line': 1, 'col': 9, 'tokenType': 'EOF_TOKEN'}], tokens);
    const tokenStream = new parse_css.TokenStream(tokens);
    tokenStream.consume();
    const errors = [];
    const selector = css_selectors.parse(tokenStream, errors);
    assertStrictEqual(null, selector);
    assertStrictEqual(
        ':1:8 SELECTORS - no selector found\n' +
            ':1:8 SELECTORS - unparsed input remains',
        errorsToString(errors));
  });

  it('implements visitor pattern', () => {
    class CollectCombinatorNodes extends css_selectors.NodeVisitor {
      constructor() {
        this.combinatorNodes = [];
      }

      /** @override */
      visitCombinator(combinator) {
        this.combinatorNodes.push(combinator);
      }
    }
    const tokens = parseSelectorForTest('a > b c + d ~ e');
    const tokenStream = new parse_css.TokenStream(tokens);
    tokenStream.consume();
    const errors = [];
    const maybeSelector = css_selectors.parse(tokenStream, errors);
    const visitor = new CollectCombinatorNodes();
    assertStrictEqual(false, maybeSelector === null);
    const selector =
        /** @type {!css_selectors.SelectorNode} */ (maybeSelector);
    css_selectors.traverse(selector, visitor);
    assertStrictEqual(4, visitor.combinatorNodes.length);
    assertStrictEqual('GENERAL_SIBLING',
                      visitor.combinatorNodes[0].combinatorType);
    assertStrictEqual(1, visitor.combinatorNodes[0].line);
    assertStrictEqual(12, visitor.combinatorNodes[0].col);

    // The combinator #2 is the (in)famous whitespace operator.
    assertJSONEquals(
        {'line': 1, 'col': 5, 'combinatorType': 'DESCENDANT', 'left':
         {'line': 1, 'col': 2, 'combinatorType': 'CHILD', 'left':
          {'line': 1, 'col': 0, 'node': 'SIMPLE_SELECTOR_SEQUENCE',
           'otherSelectors':
           [], 'typeSelector':
           {'line': 1, 'col': 0, 'elementName': 'a', 'namespacePrefix':
            null, 'node': 'TYPE_SELECTOR'}}, 'node': 'COMBINATOR',
          'right':
          {'line': 1, 'col': 4, 'node': 'SIMPLE_SELECTOR_SEQUENCE',
           'otherSelectors':
           [], 'typeSelector':
           {'line': 1, 'col': 4, 'elementName': 'b', 'namespacePrefix':
            null, 'node': 'TYPE_SELECTOR'}}}, 'node': 'COMBINATOR',
         'right':
         {'line': 1, 'col': 6, 'node': 'SIMPLE_SELECTOR_SEQUENCE',
          'otherSelectors':
          [], 'typeSelector':
          {'line': 1, 'col': 6, 'elementName': 'c', 'namespacePrefix':
           null, 'node': 'TYPE_SELECTOR'}}},
        visitor.combinatorNodes[2]);
  });
});


text:
RAILS_GEM_VERSION = '2.3.5' unless defined? RAILS_GEM_VERSION

# Bootstrap the Rails environment, frameworks, and default configuration
require File.join(File.dirname(__FILE__), 'boot')

Rails::Initializer.run do |config|
  # Settings in config/environments/* take precedence over those specified here.
  # Application configuration should go into files in config/initializers
  # -- all .rb files in that directory are automatically loaded.

  # Add additional load paths for your own custom dirs
  # config.load_paths += %W( #{RAILS_ROOT}/extras )

  # Specify gems that this application depends on and have them installed with rake gems:install
  config.gem 'log4r'
  config.gem 'jruby-openssl', :lib => 'openssl'
  config.gem "net-ssh", :lib => 'net/ssh'
  config.gem 'net-scp', :lib => 'net/scp'
  config.gem 'net-sftp', :lib => 'net/sftp' #, :version => '2.0.4'
  config.gem 'net-ssh-gateway', :lib => 'net/ssh/gateway'
  config.gem 'capistrano'
  #config.gem 'buildr'
  #config.gem 'activerecord-jdbcmysql-adapter', :lib => 'active_record/connection_adapters/jdbcmysql_adapter'
  #config.gem 'jruby-rack'
  #config.gem 'rack'

  # Only load the plugins named here, in the order given (default is alphabetical).
  # :all can be used as a placeholder for all plugins not explicitly named
  # config.plugins = [ :exception_notification, :ssl_requirement, :all ]

  # Skip frameworks you're not going to use. To use Rails without a database,
  # you must remove the Active Record framework.
  # config.frameworks -= [ :active_record, :active_resource, :action_mailer ]

  # Activate observers that should always be running
  # config.active_record.observers = :cacher, :garbage_collector, :forum_observer

  # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
  # Run "rake -D time" for a list of tasks for finding time zone names.
  config.time_zone = 'UTC'

  # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
  # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
  # config.i18n.default_locale = :de

  config.action_controller.session = {
    :session_key => '_deployer_session',
    :secret      => 'b3edbcd5fb37f94da2d5464d1644b5a07b1d1c03327d250580fe6eb0afd323203616d3ad91f7083c0ef046be6e8419da476b3d54efea7968d728bbe00b61738a'
  }
end

# Load the Java Deployer Service
unless ENV['SKIP_JAVA'] == 'true'
  require 'powerplant/deployer'

  begin
    DeployProcess.destroy_all
  rescue
    RAILS_DEFAULT_LOGGER.error( "Failed to remove all stale DeployProcess: #{$!.inspect}" )
  end

  begin
    Deploy.update_all( "is_running = false" )
  rescue
    RAILS_DEFAULT_LOGGER.error( "Failed to reset all Deploy to non-running status: #{$!.inspect}" )
  end
end


text:
package de.foconis.osgi.services;

import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;

import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;

import com.ibm.commons.util.StringUtil;

import de.foconis.core.http.client.HttpResponse;
import de.foconis.core.http.client.NSFServiceHttpClient;
import de.foconis.core.scheduler.XPageScheduler;

/**
 *
 * @author Roland Praml, FOCONIS AG
 *
 */
public class OsgiCommandProvider implements CommandProvider {
	private static final String tab = "\t";
	private static final String newline = "\r\n";
	private static final Logger log_ = Logger.getLogger(OsgiCommandProvider.class.getName());

	private Map<String, Logger> configuredLoggers = new HashMap<String, Logger>();

	private void addHeader(final String title, final StringBuffer sb) {
		sb.append("---");
		sb.append(title);
		sb.append("---");
		sb.append(newline);
	}

	private void addCommand(final String cmd, final String desc, final StringBuffer sb) {
		sb.append(tab);
		sb.append(cmd);
		sb.append(" - ");
		sb.append(desc);
		sb.append(newline);
	}

	private void addCommand(final String cmd, final String params, final String desc, final StringBuffer sb) {
		sb.append(tab);
		sb.append(cmd);
		sb.append(" ");
		sb.append(params);
		sb.append(" - ");
		sb.append(desc);
		sb.append(newline);
	}

	/**
	 * Returns all available commands
	 */
	@Override
	public String getHelp() {
		StringBuffer sb = new StringBuffer(1024);
		sb.append(newline); // the previous call forgot newline
		addHeader("Foconis logger configuration", sb);
		addCommand("logging list", "(filter)", "Get status of all loaded loggers", sb);
		addCommand("logging set", "className level", "Get status of all loaded loggers", sb);
		addHeader("Foconis scheduler", sb);
		addCommand("scheduler (list)", "Return the scheduler plan", sb);
		addCommand("scheduler stop", "Stops the scheduler", sb);
		addCommand("scheduler start", "(numThreads)", "Starts the scheduler with the amount of threads (default: 5)", sb);
		addHeader("For debug", sb);
		addCommand("urlget url", "(username)", "Perform a fake HTTP request with username (url=/path/to.nsf/xpage.xsp)", sb);
		return sb.toString();
	}

	/**
	 * Returns a readable name for a logger.
	 *
	 * @param l
	 * @return
	 */
	private String getLoggerName(final Logger l) {
		String s = l.getName();
		if (StringUtil.isEmpty(s))
			return "(root)";
		return s;
	}

	/**
	 * Returns the readable loglevel
	 *
	 * @param l
	 * @return
	 */
	private String getLogLevel(final Logger l) {
		Level lvl = l.getLevel();
		if (lvl == null) {
			Logger parent = l.getParent();
			if (parent == null)
				return "UNKNWON";

			return getLoggerName(parent) + " > " + getLogLevel(parent);
		} else {
			return lvl.toString();
		}
	}

	/**
	 * focLoggers return all active loggers, filtered by a string
	 *
	 * @param ci
	 * @throws Exception
	 */
	public void _logging(final CommandInterpreter ci) throws Exception {
		String cmd = ci.nextArgument();
		try {
			if ("list".equals(cmd)) {
				focLog_list(ci);
			} else if ("set".equals(cmd)) {
				focLog_set(ci);
			} else {
			}
		} catch (Exception e) {
			ci.printStackTrace(e);
			ci.println("");
			throw e;
		}
	}

	/**
	 * List all loggers
	 *
	 * @param ci
	 */
	private void focLog_list(final CommandInterpreter ci) {
		LogManager logManager = LogManager.getLogManager();
		Enumeration<String> loggerNames = logManager.getLoggerNames();
		log_.warning("Test!!!");
		String filter = ci.nextArgument();

		Dictionary<String, String> ret = new Hashtable<String, String>();

		while (loggerNames.hasMoreElements()) {
			Logger l = logManager.getLogger(loggerNames.nextElement());
			String loggerName = getLoggerName(l);
			if (StringUtil.isEmpty(filter) || loggerName.indexOf(filter) >= 0) {
				if (l != null) {
					ret.put(loggerName, getLogLevel(l) + getHandlers(l));
				}
			}
		}

		ci.println("Loggers currently in memory");
		ci.printDictionary(ret, null);
	}

	/**
	 * com.ibm.domino.osgi.core.adaptor.DominoConsoleHandler com.ibm.domino.http.bootstrap.logger.RCPXMLLogHandler
	 * com.ibm.domino.http.bootstrap.logger.RCPXMLTraceHandler
	 *
	 * @param l
	 * @return
	 */
	private String getHandlers(final Logger l) {
		// TODO Auto-generated method stub
		StringBuilder ret = new StringBuilder();
		for (Handler h : l.getHandlers()) {
			ret.append("\n  => ");
			ret.append(h.getClass().getName());
			ret.append(" = ");
			ret.append(h.getLevel());
		}
		return ret.toString();
	}

	/**
	 * Set a certain logger to a value
	 *
	 * @param ci
	 */
	private void focLog_set(final CommandInterpreter ci) {
		String loggerName = ci.nextArgument();
		String loggerValue = ci.nextArgument();
		if (StringUtil.isEmpty(loggerName)) {
			ci.println("Usage: focLog set <name-of-logger> <OFF|SEVERE|WARNING|INFO|CONFIG|FINE|FINER|FINEST|ALL>");
			return;
		}
		if (loggerName.equals("(root)")) {
			loggerName = "";
		}
		int colon = loggerName.indexOf(":");

		if (colon >= 0) {
			int handlerIdx = Integer.parseInt(loggerName.substring(colon + 1));
			loggerName = loggerName.substring(0, colon);
			Logger l = Logger.getLogger(loggerName);
			Handler h = l.getHandlers()[handlerIdx];
			h.setLevel(Level.parse(loggerValue));
			ci.println("Logger " + l.getName() + ", Handler: " + h.getClass().getName() + " = " + h.getLevel());
		} else {

			Logger l = Logger.getLogger(loggerName);

			if (loggerValue == null) {
				configuredLoggers.remove(loggerName);
				l.setLevel(null);
			} else {
				configuredLoggers.put(l.getName(), l);
				l.setLevel(Level.parse(loggerValue));
			}
			ci.println("Logger " + l.getName() + " = " + getLogLevel(l));
		}
	}

	// protected String getJobState(final Job job) {
	// switch (job.getState()) {
	// case Job.RUNNING:
	// return "RUNNING";
	// case Job.WAITING:
	// return "WAITNING";
	// case Job.SLEEPING:
	// return "SLEEPING";
	// }
	// return "NONE";
	// }

	// protected String getJobId(final Job job) {
	// String s = Integer.toHexString(System.identityHashCode(job)).toUpperCase();
	// while (s.length() < 8) {
	// s = "0".concat(s);
	// }
	// return s.substring(0, 4) + "-" + s.substring(4);
	// }

	// private void printRunningJobs(final CommandInterpreter ci, final Scheduler sched) throws SchedulerException {
	//
	// List<JobExecutionContext> runningJobs = sched.getCurrentlyExecutingJobs();
	// ci.println("Current RUNNING jobs:");
	// if (runningJobs.isEmpty()) {
	// ci.println("- the scheduler is idle -");
	// } else {
	// for (JobExecutionContext jec : runningJobs) {
	// JobDetail jd = jec.getJobDetail();
	// jec.getJobInstance();
	// Date startTime = jec.getFireTime();
	// Long runTime = System.currentTimeMillis() - startTime.getTime();
	// if (runTime > 10000) {
	// sched.interrupt(jd.getKey());
	// }
	//
	// ci.println("JOB: " + jd.getKey());
	// ci.println(" Start at: " + jec.getFireTime() + " running " + runTime + " ms");
	// }
	// }
	// }

	public void _sched(final CommandInterpreter ci) {
		_scheduler(ci);
	}

	/**
	 * Return all running eclipse jobs
	 *
	 * @param ci
	 */
	public void _scheduler(final CommandInterpreter ci) {
		String cmd = ci.nextArgument();
		if (StringUtil.isEmpty(cmd) || "list".equals(cmd)) {
			ci.println(XPageScheduler.getInstance().getSchedulePlan(null));
		} else if ("stop".equals(cmd)) {
			XPageScheduler.getInstance().stop(System.out);
		} else if ("start".equals(cmd)) {
			String amount = ci.nextArgument();
			int threads = 5;
			if (!StringUtil.isEmpty(amount)) {
				threads = Integer.parseInt(amount);
			}
			XPageScheduler.getInstance().start(threads);
			// Scheduler sched = null; // XPageScheduler.getInstance().getScheduler();
			// try {
			// printRunningJobs(ci, sched);
			// Set<JobKey> jobs = sched.getJobKeys(GroupMatcher.anyJobGroup());
			// ci.println("Current active jobs");
			// ci.println("Job-ID\t\tJob-State\tThread\tJob-Name\tResult");
			// for (JobKey jobKey : jobs) {
			// ci.println(jobKey);
			// List<? extends Trigger> triggers = sched.getTriggersOfJob(jobKey);
			// for (Trigger trigger : triggers) {
			// ci.println(trigger);
			// }
			// }
			//
			// Set<TriggerKey> triggers = sched.getTriggerKeys(GroupMatcher.anyTriggerGroup());
			// ci.println("Current active triggers");
			// for (TriggerKey trigger : triggers) {
			// Trigger trg = sched.getTrigger(trigger);
			// ci.println(trigger);
			// ci.println(trg);
			// JobDetail jd = sched.getJobDetail(trg.getJobKey());
			// ci.println(jd);
			// }
			// } catch (SchedulerException e) {
			// ci.println(e);
			// }
		} else if ("kill".equals(cmd)) {
			// kill(ci);
		}
	}

	/**
	 * this is for debugging the NSFServiceHttpClient
	 *
	 * @param ci
	 */
	public void _urlget(final CommandInterpreter ci) {
		String url = ci.nextArgument();
		String name = ci.nextArgument();
		ci.println("urlget: " + url + " user:" + name);
		NSFServiceHttpClient cl = new NSFServiceHttpClient(name);
		HttpResponse resp = cl.doRequest("GET", url, null);
		ci.println("Return code: " + resp.getStatus() + " " + resp.getStatusMessage());
		ci.println(resp.getResponseText());
	}

	/**
	 * Kills the given job ID
	 *
	 * @param ci
	 */
	// private void kill(final CommandInterpreter ci) {
	//
	// String jobId = ci.nextArgument();
	// if (StringUtil.isEmpty(jobId)) {
	// ci.println("Usage: focJob kill <jobID> <waitsecs>");
	// return;
	// }
	// // read how long to wait
	// Integer secs = 0;
	// try {
	// String secsStr = ci.nextArgument();
	// if (!StringUtil.isEmpty(secsStr)) {
	// secs = Integer.parseInt(secsStr);
	// }
	// } catch (NumberFormatException e) {
	// ci.println("Usage: focJob kill <jobID> <waitsecs>");
	// return;
	//
	// }
	//
	// Job[] jobs = null; // XPageAgentManager.getInstance().getJobs();
	// Job jobToKill = null;
	// for (Job job : jobs) {
	// if (getJobId(job).indexOf(jobId) != -1 || job.getName().indexOf(jobId) != -1) {
	// if (jobToKill == null) {
	// jobToKill = job;
	// } else {
	// ci.println("The ID '" + jobId + "' is not unique");
	// return;
	// }
	// }
	// }
	// if (jobToKill == null) {
	// ci.println("The ID '" + jobId + "' was not found");
	// return;
	// }
	//
	// if (jobToKill.getState() != Job.RUNNING) {
	// ci.println("The Job '" + jobToKill.getName() + "' does not run. It will be canceled");
	// jobToKill.cancel();
	// return;
	// }
	//
	// System.err.println("Killing " + jobToKill.getName());
	//
	// try {
	// jobToKill.cancel();
	// if (secs == 0) {
	// // wait 5 seconds to give the job time to cancel
	// for (int i = 50; i > 0; i--) {
	// Thread.sleep(100);
	// if (jobToKill.getState() != Job.RUNNING) {
	// ci.println("The Job '" + jobToKill.getName() + "' quit normally");
	// return;
	// }
	// }
	// ci.println("The Job '" + jobToKill.getName() + "' is still running");
	// } else {
	// Thread t = jobToKill.getThread();
	// if (t != null) {
	// for (int i = secs; i > 0; i--) {
	// Thread.sleep(1000);
	// if (jobToKill.getState() != Job.RUNNING)
	// return;
	// System.err.println("Waiting " + i + " seconds for '" + jobToKill + "' to quit");
	// }
	// t.interrupt();
	// ci.print("Interrupt sent to Thread " + t.getName());
	// // TODO check if job is terminated
	// }
	// }
	// } catch (InterruptedException e) {
	// ci.println(e);
	// }
	// }

}


text:
"""
Provides various authentication policies.
"""

from abc import ABCMeta, abstractmethod

class Authenticator(metaclass=ABCMeta):
    """
    A base class from which all authenticator classes should inherit.
    """

    @abstractmethod
    def authenticate(self):
        """
        Authenticate the request and return a two-tuple of (user, token).
        """
        pass


text:
package uk.ac.rdg.evoportal.data;

import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import org.apache.wicket.markup.repeater.data.IDataProvider;
import org.apache.wicket.model.IModel;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import uk.ac.rdg.evoportal.beans.ScaleTest;
import uk.ac.rdg.util.HibernateUtil;

/**
 *
 * @author david
 */
public class ScaleTestsDataProvider implements IDataProvider {

    List<ScaleTest> l = new Vector<ScaleTest>();

    public ScaleTestsDataProvider(String owner) {
        Session s = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = s.beginTransaction();
        Query q = s.createQuery("from ScaleTest st where st.owner='" + owner + "' order by st.testID desc");
        List<ScaleTest> results = q.list();
        tx.commit();
        if (tx.wasCommitted()) {
            l.addAll(results);
        }
    }

    public static ScaleTest get(long testID) {
        ScaleTest scaleTest = null;
        Session s = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = s.beginTransaction();
        Object result = s.createQuery("from ScaleTest st where st.testID=" + testID).uniqueResult();
        tx.commit();
        if (tx.wasCommitted()) {
            scaleTest = (ScaleTest)result;
        }
        return scaleTest;
    }

    public Iterator iterator(int first, int count) {
        return l.iterator();
    }

    public void detach() {
        //l = null;
    }

    public IModel model(Object object) {
        ScaleTest scaleTest = (ScaleTest) object;
        return new ScaleTestLoadableDetachableModel(scaleTest.getTestID());
    }

    public int size() {
        return l.size();
    }
}


text:
var check=require("./weixin/checkToken");
module.exports=function(param,sysParam,cb){//微信校验
	var now=new Date();
	var req=sysParam.req;
	var query=req.query;
	var signature=query.signature;
	var timestamp=query.timestamp;
	var nonce=query.nonce;
	var echostr=query.echostr;

	console.log(now.getHours()+":"+now.getMinutes()+":"+now.getSeconds()+" "+now.getMilliseconds());

	console.log("wexin check",req.query);
	var result=check(signature,timestamp,nonce,echostr);
	console.log("check result=["+result+"]");

	return result;
}