text:
//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2015, John Haddon. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "GafferSceneUI/StandardLightVisualiser.h"

#include "Gaffer/Metadata.h"

#include "IECoreGL/CurvesPrimitive.h"
#include "IECoreGL/DiskPrimitive.h"
#include "IECoreGL/Group.h"
#include "IECoreGL/QuadPrimitive.h"
#include "IECoreGL/ShaderLoader.h"
#include "IECoreGL/ShaderStateComponent.h"
#include "IECoreGL/SpherePrimitive.h"
#include "IECoreGL/TextureLoader.h"
#include "IECoreGL/ToGLMeshConverter.h"

#include "IECoreScene/MeshPrimitive.h"
#include "IECoreScene/Shader.h"

using namespace std;
using namespace boost;
using namespace Imath;
using namespace IECore;
using namespace IECoreScene;
using namespace IECoreGL;
using namespace Gaffer;
using namespace GafferSceneUI;
using namespace IECoreGLPreview;

//////////////////////////////////////////////////////////////////////////
// Utility methods. We define these in an anonymouse namespace rather
// than clutter up the header with private methods.
//////////////////////////////////////////////////////////////////////////

namespace
{

const Color3f g_lightWireframeColor = Color3f( 1.0f, 0.835f, 0.07f );
const Color4f g_lightWireframeColor4 = Color4f( g_lightWireframeColor.x, g_lightWireframeColor.y, g_lightWireframeColor.z, 1.0f );

enum Axis { X, Y, Z };

IECore::InternedString metadataTargetForNetwork( const IECoreScene::ShaderNetwork *shaderNetwork )
{
	const IECoreScene::Shader *shader = shaderNetwork->outputShader();
	return shader->getType() + ":" + shader->getName();
}

template<typename T>
T parameter( InternedString metadataTarget, const IECore::CompoundData *parameters, InternedString parameterNameMetadata, T defaultValue )
{
	ConstStringDataPtr parameterName = Metadata::value<StringData>( metadataTarget, parameterNameMetadata );
	if( !parameterName )
	{
		return defaultValue;
	}

	typedef IECore::TypedData<T> DataType;
	if( const DataType *parameterData = parameters->member<DataType>( parameterName->readable() ) )
	{
		return parameterData->readable();
	}

	return defaultValue;
}

void addRay( const V3f &start, const V3f &end, vector<int> &vertsPerCurve, vector<V3f> &p, float arrowScale = 0.05f )
{
	const V3f dir = end - start;
	V3f perp = dir % V3f( 1, 0, 0 );
	if( perp.length() == 0.0f )
	{
		perp = dir % V3f( 0, 1, 0 );
	}

	p.push_back( start );
	p.push_back( end );
	vertsPerCurve.push_back( 2 );

	p.push_back( end + arrowScale * ( perp * 2 - dir * 3 ) );
	p.push_back( end );
	p.push_back( end + arrowScale * ( perp * -2 - dir * 3 ) );
	vertsPerCurve.push_back( 3 );
}

void addCircle( Axis axis, const V3f &center, float radius, vector<int> &vertsPerCurve, vector<V3f> &p )
{
	const int numDivisions = 100;
	for( int i = 0; i < numDivisions; ++i )
	{
		const float angle = 2 * M_PI * (float)i/(float)(numDivisions-1);
		if( axis == Axis::Z )
		{
			p.push_back( center + radius * V3f( cos( angle ), sin( angle ), 0 ) );
		}
		else if( axis == Axis::X )
		{
			p.push_back( center + radius * V3f( 0, cos( angle ), sin( angle ) ) );
		}
		else
		{
			p.push_back( center + radius * V3f( cos( angle ), 0, sin( angle ) ) );
		}
	}
	vertsPerCurve.push_back( numDivisions );
}

void addSolidArc( Axis axis, const V3f &center, float majorRadius, float minorRadius, float startFraction, float stopFraction, vector<int> &vertsPerPoly, vector<int> &vertIds, vector<V3f> &p )
{
	const int numSegmentsForCircle = 100;
	int numSegments = max( 1, (int)ceil( (stopFraction - startFraction) * numSegmentsForCircle ) );

	int start = p.size();
	for( int i = 0; i < numSegments + 1; ++i )
	{
		const float angle = 2 * M_PI * ( startFraction + (stopFraction - startFraction) * (float)i/(float)(numSegments) );
		V3f dir( -sin( angle ), cos( angle ), 0 );
		if( axis == Axis::X ) dir = V3f( 0, dir[1], -dir[0] );
		else if( axis == Axis::Y ) dir = V3f( dir[1], 0, dir[0] );
		p.push_back( center + majorRadius * dir );
		p.push_back( center + minorRadius * dir );
	}
	for( int i = 0; i < numSegments; ++i )
	{
		vertIds.push_back( start + i * 2 );
		vertIds.push_back( start + i * 2  + 1);
		vertIds.push_back( start + i * 2  + 3);
		vertIds.push_back( start + i * 2  + 2);
		vertsPerPoly.push_back( 4 );
	}
}

void addCone( float angle, float startRadius, vector<int> &vertsPerCurve, vector<V3f> &p, float length, bool spokes )
{
	const float halfAngle = 0.5 * M_PI * angle / 180.0;
	const float baseRadius = length * sin( halfAngle );
	const float baseDistance = length * cos( halfAngle );

	if( startRadius > 0 )
	{
		addCircle( Axis::Z, V3f( 0 ), startRadius, vertsPerCurve, p );
	}
	addCircle( Axis::Z, V3f( 0, 0, -baseDistance ), baseRadius + startRadius, vertsPerCurve, p );

	if( spokes )
	{
		p.push_back( V3f( 0, startRadius, 0 ) );
		p.push_back( V3f( 0, baseRadius + startRadius, -baseDistance ) );
		vertsPerCurve.push_back( 2 );

		p.push_back( V3f( startRadius, 0, 0 ) );
		p.push_back( V3f( baseRadius + startRadius, 0, -baseDistance ) );
		vertsPerCurve.push_back( 2 );

		p.push_back( V3f( 0, -startRadius, 0 ) );
		p.push_back( V3f( 0, -baseRadius - startRadius, -baseDistance ) );
		vertsPerCurve.push_back( 2 );

		p.push_back( V3f( -startRadius, 0, 0 ) );
		p.push_back( V3f( -baseRadius - startRadius, 0, -baseDistance ) );
		vertsPerCurve.push_back( 2 );
	}
}

void addAreaSpread( float spread, vector<int> &vertsPerCurve, vector<V3f> &p )
{
	// Simple spaced parallel arrows that diverge by 45 degrees as spread approaches 1.

	static const float scale = 0.2f;

	const float spreadOffset = min( 1.0f, max( 0.0f, spread ) );

	// Offset the arrows from the center a little
	const V3f bl = V3f( -0.1f, -0.1f, 0.0f );
	const V3f tl = V3f( -0.1f, 0.1f, 0.0f );
	const V3f br = V3f( 0.1f, -0.1f, 0.0f );
	const V3f tr = V3f( 0.1f, 0.1f, 0.0f );

	addRay( bl, bl + scale * V3f( -spreadOffset, -spreadOffset, -1.0f ).normalized(), vertsPerCurve, p );
	addRay( tl, tl + scale * V3f( -spreadOffset, spreadOffset, -1.0f ).normalized(), vertsPerCurve, p );
	addRay( br, br + scale * V3f( spreadOffset, -spreadOffset, -1.0f ).normalized(), vertsPerCurve, p );
	addRay( tr, tr + scale * V3f( spreadOffset, spreadOffset, -1.0f ).normalized(), vertsPerCurve, p );
}

// Shaders

const char *constantFragSource()
{
	return
		"#version 120\n"
		""
		"#if __VERSION__ <= 120\n"
		"#define in varying\n"
		"#endif\n"
		""
		"#include \"IECoreGL/ColorAlgo.h\"\n"
		""
		"in vec3 fragmentCs;"
		""
		"uniform int linearColor;"
		"uniform vec3 tint;"
		""
		"void main()"
		"{"
			"if( linearColor == 1 ) {"
				"gl_FragColor = vec4( ieLinToSRGB( fragmentCs * tint ), 1 );"
			"} else {"
				"gl_FragColor = vec4( fragmentCs * tint, 1 );"
			"}"
		"}"
	;
}

const char *texturedConstantFragSource()
{
	return
		"#version 120\n"
		""
		"#if __VERSION__ <= 120\n"
		"#define in varying\n"
		"#endif\n"
		""
		"#include \"IECoreGL/ColorAlgo.h\"\n"
		""
		"in vec2 fragmentuv;"
		"uniform sampler2D texture;"
		"uniform vec3 tint;"
		""
		"void main()"
		"{"
			"vec3 c = texture2D( texture, fragmentuv ).xyz;"
			"gl_FragColor = vec4( ieLinToSRGB( c * tint ), 1.0 );"
		"}"
	;
}

const char *faceCameraVertexSource()
{
	return

		"#version 120\n"
		""
		"#if __VERSION__ <= 120\n"
		"#define in attribute\n"
		"#define out varying\n"
		"#endif\n"
		""
		"uniform int aimType;"
		""
		"uniform vec3 Cs = vec3( 1, 1, 1 );"
		"uniform bool vertexCsActive = false;"
		""
		"in vec3 vertexP;"
		"in vec3 vertexN;"
		"in vec2 vertexuv;"
		"in vec3 vertexCs;"
		""
		"out vec3 geometryI;"
		"out vec3 geometryP;"
		"out vec3 geometryN;"
		"out vec2 geometryuv;"
		"out vec3 geometryCs;"
		""
		"out vec3 fragmentI;"
		"out vec3 fragmentP;"
		"out vec3 fragmentN;"
		"out vec2 fragmentuv;"
		"out vec3 fragmentCs;"
		""
		"void main()"
		"{"
		""
		""
		"	vec3 aimedXAxis, aimedYAxis, aimedZAxis;"
		"	if( aimType == 0 )"
		"	{"
		"		vec4 viewDirectionInObjectSpace = gl_ModelViewMatrixInverse * vec4( 0, 0, -1, 0 );"
		"		vec3 viewCross = cross( viewDirectionInObjectSpace.xyz, vec3( 0, 0, -1 ) );"
		"		aimedYAxis = length( viewCross ) > 0.0001 ? normalize( viewCross ) : vec3( 1, 0, 0 );"
		"		aimedXAxis = normalize( cross( aimedYAxis, vec3( 0, 0, -1 ) ) );"
		"		aimedZAxis = vec3( 0, 0, 1 );"
		"	}"
		"	else"
		"	{"
		"		aimedXAxis = normalize( gl_ModelViewMatrixInverse * vec4( 0, 0, -1, 0 ) ).xyz;"
		"		aimedYAxis = normalize( gl_ModelViewMatrixInverse * vec4( 0, 1, 0, 0 ) ).xyz;"
		"		aimedZAxis = normalize( gl_ModelViewMatrixInverse * vec4( 1, 0, 0, 0 ) ).xyz;"
		"	}"
		""
		"	vec3 pAimed = vertexP.x * aimedXAxis + vertexP.y * aimedYAxis + vertexP.z * aimedZAxis;"
		""
		"	vec4 pCam = gl_ModelViewMatrix * vec4( pAimed, 1 );"
		"	gl_Position = gl_ProjectionMatrix * pCam;"
		"	geometryP = pCam.xyz;"
		"	geometryN = normalize( gl_NormalMatrix * vertexN );"
		"	if( gl_ProjectionMatrix[2][3] != 0.0 )"
		"	{"
		"		geometryI = normalize( -pCam.xyz );"
		"	}"
		"	else"
		"	{"
		"		geometryI = vec3( 0, 0, -1 );"
		"	}"
		""
		"	geometryuv = vertexuv;"
		"	geometryCs = mix( Cs, vertexCs, float( vertexCsActive ) );"
		""
		"	fragmentI = geometryI;"
		"	fragmentP = geometryP;"
		"	fragmentN = geometryN;"
		"	fragmentuv = geometryuv;"
		"	fragmentCs = geometryCs;"
		"}"

	;
}

// Shader state helpers

void addWireframeCurveState( IECoreGL::Group *group, float lineWidthScale = 1.0f )
{
	group->getState()->add( new IECoreGL::Primitive::DrawWireframe( false ) );
	group->getState()->add( new IECoreGL::Primitive::DrawSolid( true ) );
	group->getState()->add( new IECoreGL::CurvesPrimitive::UseGLLines( true ) );
	group->getState()->add( new IECoreGL::CurvesPrimitive::GLLineWidth( 1.5f * lineWidthScale ) );
	group->getState()->add( new IECoreGL::LineSmoothingStateComponent( true ) );
}

void addConstantShader( IECoreGL::Group *group, const Imath::Color3f &tint, bool linearColor = false, int aimType = -1 )
{
	IECore::CompoundObjectPtr parameters = new CompoundObject;

	if( aimType > -1 )
	{
		parameters->members()["aimType"] = new IntData( aimType );
	}

	parameters->members()["linearColor"] = new IntData( linearColor ? 1 : 0 );
	parameters->members()["tint"] = new Color3fData( tint );

	group->getState()->add(
		new IECoreGL::ShaderStateComponent(
			ShaderLoader::defaultShaderLoader(),
			TextureLoader::defaultTextureLoader(),
			aimType > -1 ? faceCameraVertexSource() : "",
			"",
			constantFragSource(),
			parameters
		)
	);
}

void addConstantShader( IECoreGL::Group *group, bool linearColor = false, int aimType = -1 )
{
	addConstantShader( group, Color3f( 1.0f ), linearColor, aimType );
}

void addTexturedConstantShader( IECoreGL::Group *group, IECore::ConstDataPtr textureData, const Color3f &tint, int maxTextureResolution )
{
	IECore::CompoundObjectPtr shaderParameters = new CompoundObject;

	shaderParameters->members()["texture"] = const_cast<Data *>( textureData.get() );
	shaderParameters->members()["texture:maxResolution"] = new IntData( maxTextureResolution );
	shaderParameters->members()["tint"] = new Color3fData( tint );

	group->getState()->add(
		new IECoreGL::ShaderStateComponent(
			ShaderLoader::defaultShaderLoader(),
			TextureLoader::defaultTextureLoader(),
			"",
			"",
			texturedConstantFragSource(),
			shaderParameters
		)
	);
}

} // namespace

//////////////////////////////////////////////////////////////////////////
// StandardLightVisualiser implementation.
//////////////////////////////////////////////////////////////////////////

// Register as the standard fallback visualiser.
LightVisualiser::LightVisualiserDescription<StandardLightVisualiser> StandardLightVisualiser::g_description( "light *:light", "*" );

StandardLightVisualiser::StandardLightVisualiser()
{
}

StandardLightVisualiser::~StandardLightVisualiser()
{
}

Visualisations StandardLightVisualiser::visualise( const IECore::InternedString &attributeName, const IECoreScene::ShaderNetwork *shaderNetwork, const IECore::CompoundObject *attributes, IECoreGL::ConstStatePtr &state ) const
{
	const InternedString metadataTarget = metadataTargetForNetwork( shaderNetwork );
	const IECore::CompoundData *shaderParameters = shaderNetwork->outputShader()->parametersData();

	ConstStringDataPtr type = Metadata::value<StringData>( metadataTarget, "type" );
	ConstM44fDataPtr orientation = Metadata::value<M44fData>( metadataTarget, "visualiserOrientation" );

	const Color3f color = parameter<Color3f>( metadataTarget, shaderParameters, "colorParameter", Color3f( 1.0f ) );
	const Color3f tint = parameter<Color3f>( metadataTarget, shaderParameters, "tintParameter", Color3f( 1.0f ) );

	// Ornaments are affected by visualiser:scale and not local scale.
	GroupPtr ornaments = new Group;
	// Bound ornaments are considered when 'f' is pressed in the viewer to fit.
	GroupPtr boundOrnaments = new Group;
	// As part of our assumption that renderer's largely ignore scale, this is
	// contains anything that should always be in fixed world scale and not be
	// affected by visualiser scale.
	GroupPtr fixedScaleOrnaments = new Group;
	// Geometry is only affected by local scale (its size matters for rendering).
	GroupPtr geometry = new Group;
	// As 'projections' are largely for display, and lights don't generally
	// scale this group only follows visualiser scale.
	GroupPtr frustum = new Group;

	const FloatData *visualiserScaleData = attributes->member<FloatData>( "gl:visualiser:scale" );
	const float visualiserScale = visualiserScaleData ? visualiserScaleData->readable() : 1.0;
	const FloatData *frustumScaleData = attributes->member<FloatData>( "gl:light:frustumScale" );
	const float frustumScale = frustumScaleData ? frustumScaleData->readable() : 1.0;
	const StringData *visualiserDrawingModeData = attributes->member<StringData>( "gl:light:drawingMode" );
	const std::string visualiserDrawingMode = visualiserDrawingModeData ? visualiserDrawingModeData->readable() : "texture";

	const bool drawShaded = visualiserDrawingMode != "wireframe";
	const bool drawTextured = visualiserDrawingMode == "texture";

	const IntData *maxTextureResolutionData = attributes->member<IntData>( "gl:visualiser:maxTextureResolution" );
	const int maxTextureResolution = maxTextureResolutionData ? maxTextureResolutionData->readable() : std::numeric_limits<int>::max();

	Imath::M44f topTransform;
	if( orientation )
	{
		topTransform = orientation->readable();
	}
	geometry->setTransform( topTransform );
	ornaments->setTransform( topTransform );
	boundOrnaments->setTransform( topTransform );
	fixedScaleOrnaments->setTransform( topTransform );
	frustum->setTransform( topTransform );

	// A shared curves primitive for ornament wireframes
	V3fVectorDataPtr ornamentWireframePoints = new V3fVectorData();
	IntVectorDataPtr ornamentWireframeVertsPerCurve = new IntVectorData();

	if( type && type->readable() == "environment" )
	{
		if( drawShaded )
		{
			ConstDataPtr textureData = drawTextured ? surfaceTexture( shaderNetwork, attributes, maxTextureResolution ) : nullptr;
			boundOrnaments->addChild( const_pointer_cast<IECoreGL::Renderable>( environmentSphereSurface( textureData, tint, maxTextureResolution, color ) ) );
		}
		boundOrnaments->addChild( const_pointer_cast<IECoreGL::Renderable>( sphereWireframe( 1.05f, Vec3<bool>( true ) ) ) );
	}
	else if( type && type->readable() == "spot" )
	{
		float innerAngle, outerAngle, radius, lensRadius;
		spotlightParameters( attributeName, shaderNetwork, innerAngle, outerAngle, radius, lensRadius );
		boundOrnaments->addChild( const_pointer_cast<IECoreGL::Renderable>( spotlightCone( innerAngle, outerAngle, lensRadius / visualiserScale, 1.0f, 1.0f ) ) );
		fixedScaleOrnaments->addChild( const_pointer_cast<IECoreGL::Renderable>( sphereWireframe( radius, Vec3<bool>( false, false, true ), 0.5f, V3f( 0.0f, 0.0f, 0.1f * visualiserScale ) ) ) );
		addRay( V3f( 0 ), V3f( 0, 0, -1 ), ornamentWireframeVertsPerCurve->writable(), ornamentWireframePoints->writable() );
		ornaments->addChild( const_pointer_cast<IECoreGL::Renderable>( colorIndicator( color ) ) );
		frustum->addChild( const_pointer_cast<IECoreGL::Renderable>( spotlightCone( innerAngle, outerAngle, lensRadius / visualiserScale, 10.0f * frustumScale, 0.5f ) ) );
	}
	else if( type && type->readable() == "distant" )
	{
		boundOrnaments->addChild( const_pointer_cast<IECoreGL::Renderable>( distantRays() ) );
		ornaments->addChild( const_pointer_cast<IECoreGL::Renderable>( colorIndicator( color ) ) );
	}
	else if( type && type->readable() == "quad" )
	{
		const V2f size( 2 );
		// Cycles/Arnold define portals via a parameter on a quad, rather than as it's own light type.
		if( parameter<bool>( metadataTarget, shaderParameters, "portalParameter", false ) )
		{
			// Because we don't support variable size lights, we keep a fixed hatching scale
			geometry->addChild( const_pointer_cast<IECoreGL::Renderable>( quadPortal( size ) ) );
		}
		else
		{
			if( drawShaded )
			{
				ConstDataPtr textureData = drawTextured ? surfaceTexture( shaderNetwork, attributes, maxTextureResolution ) : nullptr;
				geometry->addChild( const_pointer_cast<IECoreGL::Renderable>( quadSurface( size, textureData, tint, maxTextureResolution, color ) ) );
			}
			else
			{
				ornaments->addChild( const_pointer_cast<IECoreGL::Renderable>( colorIndicator( color * tint ) ) );
			}
			geometry->addChild( const_pointer_cast<IECoreGL::Renderable>( quadWireframe( size ) ) );

			const float spread = parameter<float>( metadataTarget, shaderParameters, "spreadParameter", -1 );
			if( spread >= 0.0f )
			{
				addAreaSpread( spread, ornamentWireframeVertsPerCurve->writable(), ornamentWireframePoints->writable() );
			}
		}
		addRay( V3f( 0 ), V3f( 0, 0, -1 ), ornamentWireframeVertsPerCurve->writable(), ornamentWireframePoints->writable() );
	}
	else if( type && type->readable() == "disk" )
	{
		const float radius = parameter<float>( metadataTarget, shaderParameters, "radiusParameter", 1 );

		if( drawShaded )
		{
			ConstDataPtr textureData = drawTextured ? surfaceTexture( shaderNetwork, attributes, maxTextureResolution ) : nullptr;
			geometry->addChild( const_pointer_cast<IECoreGL::Renderable>( diskSurface( radius, textureData, tint, maxTextureResolution, color ) ) );
		}
		else
		{
			ornaments->addChild( const_pointer_cast<IECoreGL::Renderable>( colorIndicator( color * tint ) ) );
		}
		geometry->addChild( const_pointer_cast<IECoreGL::Renderable>( diskWireframe( radius ) ) );
		addRay( V3f( 0 ), V3f( 0, 0, -1 ), ornamentWireframeVertsPerCurve->writable(), ornamentWireframePoints->writable() );

		const float spread = parameter<float>( metadataTarget, shaderParameters, "spreadParameter", -1 );
		if( spread >= 0.0f )
		{
			addAreaSpread( spread, ornamentWireframeVertsPerCurve->writable(), ornamentWireframePoints->writable() );
		}
	}
	else if( type && type->readable() == "cylinder" )
	{
		const float radius = parameter<float>( metadataTarget, shaderParameters, "radiusParameter", 1 );
		geometry->addChild( const_pointer_cast<IECoreGL::Renderable>( cylinderShape( radius, drawShaded, color * tint ) ) );
		ornaments->addChild( const_pointer_cast<IECoreGL::Renderable>( cylinderRays( radius ) ) );
		if( !drawShaded )
		{
			ornaments->addChild( const_pointer_cast<IECoreGL::Renderable>( colorIndicator( color * tint ) ) );
		}
	}
	else if( type && type->readable() == "mesh" )
	{
		// There isn't any meaningful place to draw anything for the mesh
		// light, so instead we make the mesh outline visible and light coloured.
		IECoreGL::StatePtr meshState = new IECoreGL::State( false );
		meshState->add( new IECoreGL::Primitive::DrawOutline( true ) );
		meshState->add( new IECoreGL::Primitive::OutlineWidth( 2.0f ) );
		meshState->add( new IECoreGL::OutlineColorStateComponent( g_lightWireframeColor4 ) );
		state = meshState;
	}
	else if( type && type->readable() == "photometric" )
	{
		const float radius = parameter<float>( metadataTarget, shaderParameters, "radiusParameter", 0 );
		if( radius > 0 )
		{
			fixedScaleOrnaments->addChild( const_pointer_cast<IECoreGL::Renderable>( sphereWireframe( radius, Vec3<bool>( true, false, true ), 0.5f ) ) );
		}
		ornaments->addChild( const_pointer_cast<IECoreGL::Renderable>( colorIndicator( color ) ) );
		addRay( V3f( 0 ), V3f( 0, 0, -1 ), ornamentWireframeVertsPerCurve->writable(), ornamentWireframePoints->writable() );
	}
	else
	{
		// Treat everything else as a point light.
		const float radius = parameter<float>( metadataTarget, shaderParameters, "radiusParameter", 0 );
		if( radius > 0 )
		{
			fixedScaleOrnaments->addChild( const_pointer_cast<IECoreGL::Renderable>( pointShape( radius ) ) );
		}

		boundOrnaments->addChild( const_pointer_cast<IECoreGL::Renderable>( pointRays( radius / visualiserScale ) ) );
		ornaments->addChild( const_pointer_cast<IECoreGL::Renderable>( colorIndicator( color ) ) );
	}

	if( ornamentWireframePoints->readable().size() > 0 )
	{
		IECoreGL::CurvesPrimitivePtr curves = new IECoreGL::CurvesPrimitive( IECore::CubicBasisf::linear(), false, ornamentWireframeVertsPerCurve );
		curves->addPrimitiveVariable( "P", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Vertex, ornamentWireframePoints ) );
		curves->addPrimitiveVariable( "Cs", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new Color3fData( g_lightWireframeColor ) ) );
		ornaments->addChild( curves );
	}

	Visualisations result;
	if( !geometry->children().empty() )
	{
		result.push_back( Visualisation::createGeometry( geometry ) );
	}
	if( !ornaments->children().empty() )
	{
		addWireframeCurveState( ornaments.get() );
		result.push_back( Visualisation::createOrnament( ornaments, false ) );
	}
	if( !boundOrnaments->children().empty() )
	{
		result.push_back( Visualisation::createOrnament( boundOrnaments, true ) );
	}
	if( !fixedScaleOrnaments->children().empty() )
	{
		result.push_back( Visualisation( fixedScaleOrnaments, Visualisation::Scale::None ) );
	}
	if( !frustum->children().empty() )
	{
		result.push_back( Visualisation::createFrustum( frustum, Visualisation::Scale::Visualiser ) );
	}
	return result;
}

IECore::DataPtr StandardLightVisualiser::surfaceTexture( const IECoreScene::ShaderNetwork *shaderNetwork, const IECore::CompoundObject *attributes, int maxTextureResolution ) const
{
	const IECore::InternedString metadataTarget = metadataTargetForNetwork( shaderNetwork );
	const IECore::CompoundData *shaderParameters = shaderNetwork->outputShader()->parametersData();
	const std::string textureName = parameter<std::string>( metadataTarget, shaderParameters, "textureNameParameter", "" );
	if( !textureName.empty() )
	{
		return new IECore::StringData( textureName );
	}

	return nullptr;
}

void StandardLightVisualiser::spotlightParameters( const InternedString &attributeName, const IECoreScene::ShaderNetwork *shaderNetwork, float &innerAngle, float &outerAngle, float &radius, float &lensRadius )
{

	InternedString metadataTarget = metadataTargetForNetwork( shaderNetwork );
	const IECore::CompoundData *shaderParameters = shaderNetwork->outputShader()->parametersData();

	float coneAngle = parameter<float>( metadataTarget, shaderParameters, "coneAngleParameter", 0.0f );
	float penumbraAngle = parameter<float>( metadataTarget, shaderParameters, "penumbraAngleParameter", 0.0f );
	if( ConstStringDataPtr angleUnit = Metadata::value<StringData>( metadataTarget, "angleUnit" ) )
	{
		if( angleUnit->readable() == "radians" )
		{
			coneAngle *= 180.0 / M_PI;
			penumbraAngle *= 180 / M_PI;
		}
	}

	innerAngle = 0;
	outerAngle = 0;

	ConstStringDataPtr penumbraTypeData = Metadata::value<StringData>( metadataTarget, "penumbraType" );
	const std::string *penumbraType = penumbraTypeData ? &penumbraTypeData->readable() : nullptr;

	if( !penumbraType || *penumbraType == "inset" )
	{
		outerAngle = coneAngle;
		innerAngle = coneAngle - 2.0f * penumbraAngle;
	}
	else if( *penumbraType == "outset" )
	{
		outerAngle = coneAngle + 2.0f * penumbraAngle;
		innerAngle = coneAngle ;
	}
	else if( *penumbraType == "absolute" )
	{
		outerAngle = coneAngle;
		innerAngle = penumbraAngle;
	}

	lensRadius = 0.0f;
	if( parameter<bool>( metadataTarget, shaderParameters, "lensRadiusEnableParameter", true ) )
	{
		lensRadius = parameter<float>( metadataTarget, shaderParameters, "lensRadiusParameter", 0.0f );
	}

	radius = parameter<float>( metadataTarget, shaderParameters, "radiusParameter", 0.0f );

}

IECoreGL::ConstRenderablePtr StandardLightVisualiser::ray()
{
	IECoreGL::GroupPtr group = new IECoreGL::Group();
	addWireframeCurveState( group.get() );
	addConstantShader( group.get(), false, 0 );

	IntVectorDataPtr vertsPerCurve = new IntVectorData;
	V3fVectorDataPtr p = new V3fVectorData;
	addRay( V3f( 0 ), V3f( 0, 0, -1 ), vertsPerCurve->writable(), p->writable() );

	IECoreGL::CurvesPrimitivePtr curves = new IECoreGL::CurvesPrimitive( IECore::CubicBasisf::linear(), false, vertsPerCurve );
	curves->addPrimitiveVariable( "P", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Vertex, p ) );
	curves->addPrimitiveVariable( "Cs", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new Color3fData( g_lightWireframeColor ) ) );

	group->addChild( curves );

	return group;
}

IECoreGL::ConstRenderablePtr StandardLightVisualiser::pointRays( float radius )
{
	IECoreGL::GroupPtr group = new IECoreGL::Group();
	addWireframeCurveState( group.get() );
	addConstantShader( group.get(), false, 1 );

	IntVectorDataPtr vertsPerCurve = new IntVectorData;
	V3fVectorDataPtr p = new V3fVectorData;

	const int numRays = 8;
	for( int i = 0; i < numRays; ++i )
	{
		const float angle = M_PI * 2.0f * float(i)/(float)numRays;
		const V3f dir( 0.0, sin( angle ), -cos( angle ) );
		addRay( dir * ( 0.2f + radius ), dir * ( 0.6f + radius ), vertsPerCurve->writable(), p->writable(), 0.1f );
	}

	IECoreGL::CurvesPrimitivePtr curves = new IECoreGL::CurvesPrimitive( IECore::CubicBasisf::linear(), false, vertsPerCurve );
	curves->addPrimitiveVariable( "P", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Vertex, p ) );
	curves->addPrimitiveVariable( "Cs", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new Color3fData( g_lightWireframeColor ) ) );

	group->addChild( curves );

	return group;
}

IECoreGL::ConstRenderablePtr StandardLightVisualiser::distantRays()
{
	GroupPtr result = new Group;
	for( int i = 0; i < 3; i++ )
	{
		IECoreGL::GroupPtr rayGroup = new IECoreGL::Group();

		Imath::M44f trans;
		trans.rotate( V3f( 0, 0, 2.0 * M_PI / 3.0 * i ) );
		trans.translate( V3f( 0, 0.4, 0.5 ) );
		rayGroup->addChild( const_pointer_cast<IECoreGL::Renderable>( ray() ) );
		rayGroup->setTransform( trans );

		result->addChild( rayGroup );
	}

	return result;
}

IECoreGL::ConstRenderablePtr StandardLightVisualiser::spotlightCone( float innerAngle, float outerAngle, float lensRadius, float length, float lineWidthScale )
{
	IECoreGL::GroupPtr group = new IECoreGL::Group();
	addWireframeCurveState( group.get(), lineWidthScale );
	addConstantShader( group.get(), false );

	IntVectorDataPtr vertsPerCurve = new IntVectorData;
	V3fVectorDataPtr p = new V3fVectorData;

	const bool drawSecondaryCone = fabs( innerAngle - outerAngle ) > 0.1;

	addCone( innerAngle, lensRadius, vertsPerCurve->writable(), p->writable(), length, !drawSecondaryCone );

	if( drawSecondaryCone )
	{
		addCone( outerAngle, lensRadius, vertsPerCurve->writable(), p->writable(), length, true );
	}

	IECoreGL::CurvesPrimitivePtr curves = new IECoreGL::CurvesPrimitive( IECore::CubicBasisf::linear(), false, vertsPerCurve );
	curves->addPrimitiveVariable( "P", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Vertex, p ) );

	const Color3fDataPtr color = new Color3fData( lineWidthScale < 1.0f ? Color3f( 0.627f, 0.580f, 0.352f ) : g_lightWireframeColor );
	curves->addPrimitiveVariable( "Cs", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, color ) );

	group->addChild( curves );

	return group;
}

IECoreGL::ConstRenderablePtr StandardLightVisualiser::colorIndicator( const Imath::Color3f &color )
{

	IECoreGL::GroupPtr group = new IECoreGL::Group();

	addConstantShader( group.get(), true, 1 );

	const float indicatorRad = 0.1f;

	{
		IntVectorDataPtr vertsPerPoly = new IntVectorData;
		IntVectorDataPtr vertIds = new IntVectorData;
		V3fVectorDataPtr p = new V3fVectorData;

		addSolidArc( Axis::X, V3f( 0 ), 0, indicatorRad, 0, 1, vertsPerPoly->writable(), vertIds->writable(), p->writable() );

		IECoreScene::MeshPrimitivePtr mesh = new IECoreScene::MeshPrimitive( vertsPerPoly, vertIds, "linear", p );
		mesh->variables["N"] = IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new V3fData( V3f( 0 ) ) );
		mesh->variables["Cs"] = IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new Color3fData( color ) );
		ToGLMeshConverterPtr meshConverter = new ToGLMeshConverter( mesh );
		group->addChild( IECore::runTimeCast<IECoreGL::Renderable>( meshConverter->convert() ) );
	}

	return group;
}

IECoreGL::ConstRenderablePtr StandardLightVisualiser::cylinderShape( float radius, bool filled, const Color3f &color )
{
	IECoreGL::GroupPtr group = new IECoreGL::Group();
	addWireframeCurveState( group.get() );
	addConstantShader( group.get(), false, 0 );

	if( filled )
	{
		IntVectorDataPtr vertsPerPolyData = new IntVectorData;
		IntVectorDataPtr vertIdsData = new IntVectorData;
		V3fVectorDataPtr pData = new V3fVectorData;

		vector<int> &vertIds = vertIdsData->writable();
		vector<V3f> &p = pData->writable();

		addSolidArc( Axis::Z, V3f( 0, 0, -1 ), radius, 0, 0, 1, vertsPerPolyData->writable(), vertIds, p );
		addSolidArc( Axis::Z, V3f( 0, 0, 1 ), radius, 0, 0, 1, vertsPerPolyData->writable(), vertIds, p );

		size_t lastIndex = p.size();
		p.push_back( V3f( 0, radius, -1 ) );
		p.push_back( V3f( 0, radius, 1 ) );
		p.push_back( V3f( 0, -radius, 1 ) );
		p.push_back( V3f( 0, -radius, -1 ) );
		vertIds.push_back( lastIndex++ );
		vertIds.push_back( lastIndex++ );
		vertIds.push_back( lastIndex++ );
		vertIds.push_back( lastIndex );
		vertsPerPolyData->writable().push_back( 4 );

		IECoreScene::MeshPrimitivePtr mesh = new IECoreScene::MeshPrimitive( vertsPerPolyData, vertIdsData, "linear", pData );
		mesh->variables["N"] = IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new V3fData( V3f( 0 ) ) );
		mesh->variables["Cs"] = IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new Color3fData( color ) );
		ToGLMeshConverterPtr meshConverter = new ToGLMeshConverter( mesh );
		group->addChild( IECore::runTimeCast<IECoreGL::Renderable>( meshConverter->convert() ) );
	}

	IntVectorDataPtr vertsPerCurveData = new IntVectorData;
	vector<int> &vertsPerCurve = vertsPerCurveData->writable();
	V3fVectorDataPtr pData = new V3fVectorData;
	vector<V3f> &p = pData->writable();

	addCircle( Axis::Z, V3f( 0, 0, -1 ), radius, vertsPerCurve, p );
	addCircle( Axis::Z, V3f( 0, 0, 1 ), radius, vertsPerCurve, p );

	p.push_back( V3f( 0, radius, -1 ) );
	p.push_back( V3f( 0, radius, 1 ) );
	vertsPerCurve.push_back( 2 );

	p.push_back( V3f( 0, -radius, -1 ) );
	p.push_back( V3f( 0, -radius, 1 ) );
	vertsPerCurve.push_back( 2 );

	IECoreGL::CurvesPrimitivePtr curves = new IECoreGL::CurvesPrimitive( IECore::CubicBasisf::linear(), false, vertsPerCurveData );
	curves->addPrimitiveVariable( "P", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Vertex, pData ) );
	curves->addPrimitiveVariable( "Cs", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new Color3fData( g_lightWireframeColor ) ) );

	group->addChild( curves );

	return group;
}

IECoreGL::ConstRenderablePtr StandardLightVisualiser::pointShape( float radius )
{
	IECoreGL::GroupPtr group = new IECoreGL::Group();
	addWireframeCurveState( group.get(), 0.5f );
	addConstantShader( group.get(), false, 1 );

	IntVectorDataPtr vertsPerCurveData = new IntVectorData;
	V3fVectorDataPtr pData = new V3fVectorData;

	addCircle( Axis::Z, V3f( 0 ), radius, vertsPerCurveData->writable(), pData->writable() );

	M44f t = M44f().rotate( V3f( 0, M_PI * 0.5, 0 ) );
	for( V3f &p : pData->writable() )
	{
		p *= t;
	}

	IECoreGL::CurvesPrimitivePtr curves = new IECoreGL::CurvesPrimitive( IECore::CubicBasisf::linear(), /* periodic = */ false, vertsPerCurveData );
	curves->addPrimitiveVariable( "P", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Vertex, pData ) );
	curves->addPrimitiveVariable( "Cs", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new Color3fData( g_lightWireframeColor ) ) );

	group->addChild( curves );

	return group;
}

/// \todo Expose publicly when we've decided what the
/// parameters should be.
IECoreGL::ConstRenderablePtr StandardLightVisualiser::cylinderRays( float radius )
{
	IECoreGL::GroupPtr group = new IECoreGL::Group();
	addWireframeCurveState( group.get() );
	addConstantShader( group.get(), false, 0 );

	const int numRays = 8;
	for( int i = 0; i < numRays; ++i )
	{
		GroupPtr rayGroup = new Group;
		rayGroup->addChild( const_pointer_cast<IECoreGL::Renderable>( StandardLightVisualiser::ray() ) );

		const float angle = M_PI * 2.0f * float(i)/(float)numRays;
		M44f m;
		m.rotate( V3f( angle, 0, 0 ) );
		m.translate( V3f( 0, 0, -radius ) );

		rayGroup->setTransform( m );
		group->addChild( rayGroup );
	}

	group->setTransform( M44f().rotate( V3f( 0, M_PI / 2.0, 0 ) ) );

	return group;
}

// Quads

IECoreGL::ConstRenderablePtr StandardLightVisualiser::quadSurface( const Imath::V2f &size, IECore::ConstDataPtr textureData, const Color3f &tint, int maxTextureResolution,  const Color3f &fallbackColor )
{
	IECoreGL::GroupPtr group = new IECoreGL::Group();
	if( textureData )
	{
		addTexturedConstantShader( group.get(), textureData, tint, maxTextureResolution );
	}
	else
	{
		addConstantShader( group.get(), tint, true );
	}

	IECoreGL::QuadPrimitivePtr textureQuad = new IECoreGL::QuadPrimitive( size.x, size.y );
	textureQuad->addPrimitiveVariable( "Cs", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new Color3fData( fallbackColor ) ) );
	group->addChild( textureQuad );

	M44f m;
	m.rotate( V3f( M_PI, 0, 0 ) );
	group->setTransform( m );

	return group;
}

IECoreGL::ConstRenderablePtr StandardLightVisualiser::quadWireframe( const V2f &size )
{
	IECoreGL::GroupPtr group = new IECoreGL::Group();
	addWireframeCurveState( group.get() );
	addConstantShader( group.get() );

	IntVectorDataPtr vertsPerCurveData = new IntVectorData;
	V3fVectorDataPtr pData = new V3fVectorData;

	vector<int> &vertsPerCurve = vertsPerCurveData->writable();
	vector<V3f> &p = pData->writable();

	vertsPerCurve.push_back( 4 );
	p.push_back( V3f( -size.x/2, -size.y/2, 0  ) );
	p.push_back( V3f( size.x/2, -size.y/2, 0  ) );
	p.push_back( V3f( size.x/2, size.y/2, 0  ) );
	p.push_back( V3f( -size.x/2, size.y/2, 0  ) );

	IECoreGL::CurvesPrimitivePtr curves = new IECoreGL::CurvesPrimitive( IECore::CubicBasisf::linear(), /* periodic = */ true, vertsPerCurveData );
	curves->addPrimitiveVariable( "P", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Vertex, pData ) );
	curves->addPrimitiveVariable( "Cs", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new Color3fData( g_lightWireframeColor ) ) );

	group->addChild( curves );

	return group;
}

IECoreGL::ConstRenderablePtr StandardLightVisualiser::quadPortal( const V2f &size, float hatchingScale )
{
	// Portals visualise differently as they only allow light through
	// their area. Effectively a hole cut in a big plane. We try to
	// represent this by shading outside of the quad area.

	IntVectorDataPtr vertsPerCurveData = new IntVectorData;
	V3fVectorDataPtr pData = new V3fVectorData;

	std::vector<int> &vertsPerCurve = vertsPerCurveData->writable();
	std::vector<V3f> &p = pData->writable();

	// Basic outline of the portal area

	vertsPerCurve.push_back( 4 );
	p.push_back( V3f( -size.x/2, -size.y/2, 0 ) );
	p.push_back( V3f( size.x/2, -size.y/2, 0 ) );
	p.push_back( V3f( size.x/2, size.y/2, 0 ) );
	p.push_back( V3f( -size.x/2, size.y/2, 0 ) );

	// 45 degree hatch outside the portal area (when centered at the origin)

	// Space between the lines
	const float spacing = 0.05f * hatchingScale;
	// Thickness of the shaded frame area
	const float fw = 0.25f * std::max( size.x, size.y );
	// Dimension of the shaded area
	const float dw = size.x + ( 2.0f * fw );
	const float dh = size.y + ( 2.0f * fw );

	// Working with a bottom left origin makes the maths easier for the lines
	const V3f origin( -(size.x/2)-fw, -(size.y/2)-fw, 0 );
	// Alternating line lengths creates a softer edge
	bool alt = true;

	// We iterate outwards from the bottom left corner drawing lines as we go.
	// We need different behaviour depending on whether we're overlapping the
	// portal region or not.
	const float oMax = dw + dh;
	for( float o = spacing; o < oMax; o += spacing, alt = !alt )
	{
		// extra length for alternate lines
		const float e = alt ? fw * 0.1f : 0.0f;

		if( o <= fw * 2.0f )
		{
			// A single line will do near the origin as we don't intersect the portal
			vertsPerCurve.push_back( 2 );
			p.push_back( origin + V3f( -e, o+e, 0 ) );
			p.push_back( origin + V3f( o+e, -e, 0 ) );
		}
		else if( o <= oMax - fw * 2.0f )
		{
			// We need to split either side of the central portal space
			// whilst we overlap it. As the iteration covers the maximum
			// dimension we need for non-square portals, we don't always
			// draw lines on each side.

			if( o <= dh )
			{
				// Left edge-to-frame
				vertsPerCurve.push_back( 2 );
				p.push_back( origin + V3f( -e, o+e, 0 ) );
				p.push_back( origin + V3f( fw, o-fw, 0 ) );
			}
			else if( o <= dh + size.x )
			{
				// Top edge-to-frame
				vertsPerCurve.push_back( 2 );
				p.push_back( origin + V3f( o-dh-e, dh+e, 0 ) );
				p.push_back( origin + V3f( o-dh+fw, dh-fw, 0 ) );
			}

			if( o <= dw )
			{
				// Bottom frame-to-edge
				vertsPerCurve.push_back( 2 );
				p.push_back( origin + V3f( o-fw, fw, 0 ) );
				p.push_back( origin + V3f( o+e, -e, 0 ) );
			}
			else if( o <= dw + size.y )
			{
				// Right frame-to-edge
				vertsPerCurve.push_back( 2 );
				p.push_back( origin + V3f( dw-fw, o-dw+fw, 0 ) );
				p.push_back( origin + V3f( dw+e, o-dw-e, 0 ) );
			}
		}
		else
		{
			// Single line at top-right corner
			vertsPerCurve.push_back( 2 );
			p.push_back( origin + V3f( o-dh-e, dh+e, 0 ) );
			p.push_back( origin + V3f( dw+e, dh-oMax+o-e, 0 ) );
		}
	}

	IECoreGL::CurvesPrimitivePtr curves = new IECoreGL::CurvesPrimitive( IECore::CubicBasisf::linear(), true, vertsPerCurveData );
	curves->addPrimitiveVariable( "P", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Vertex, pData ) );
	curves->addPrimitiveVariable( "Cs", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new Color3fData( V3f( 0.0f ) ) ) );
	return curves;
}

// Spheres

IECoreGL::ConstRenderablePtr StandardLightVisualiser::sphereWireframe( float radius, const Vec3<bool> &axisRings, float lineWidthScale, const V3f &center )
{
	IECoreGL::GroupPtr group = new IECoreGL::Group();
	addWireframeCurveState( group.get(), lineWidthScale );
	addConstantShader( group.get() );

	IntVectorDataPtr vertsPerCurve = new IntVectorData;
	V3fVectorDataPtr p = new V3fVectorData;

	if( axisRings.x )
	{
		addCircle( Axis::X,  center, radius, vertsPerCurve->writable(), p->writable() );
	}
	if( axisRings.y )
	{
		addCircle( Axis::Y,  center, radius, vertsPerCurve->writable(), p->writable() );
	}
	if( axisRings.z )
	{
		addCircle( Axis::Z,  center, radius, vertsPerCurve->writable(), p->writable() );
	}

	IECoreGL::CurvesPrimitivePtr curves = new IECoreGL::CurvesPrimitive( IECore::CubicBasisf::linear(), false, vertsPerCurve );
	curves->addPrimitiveVariable( "P", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Vertex, p ) );
	curves->addPrimitiveVariable( "Cs", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new Color3fData( Color3f( 1.0f, 0.835f, 0.07f ) ) ) );

	group->addChild( curves );

	return group;
}

IECoreGL::ConstRenderablePtr StandardLightVisualiser::environmentSphereSurface( IECore::ConstDataPtr texture, const Color3f &tint, int maxTextureResolution, const Imath::Color3f &fallbackColor )
{
	IECoreGL::GroupPtr sphereGroup = new IECoreGL::Group();
	sphereGroup->getState()->add( new IECoreGL::DoubleSidedStateComponent( false ) );

	if( texture )
	{
		addTexturedConstantShader( sphereGroup.get(), texture, tint, maxTextureResolution );
	}
	else
	{
		addConstantShader( sphereGroup.get(), tint, true );
	}

	IECoreGL::SpherePrimitivePtr sphere = new IECoreGL::SpherePrimitive();
	sphere->addPrimitiveVariable( "Cs", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new Color3fData( fallbackColor ) ) );
	sphereGroup->addChild( sphere );

	Imath::M44f trans;
	trans.scale( V3f( 1, 1, -1 ) );
	trans.rotate( V3f( -0.5 * M_PI, -0.5 * M_PI, 0 ) );
	sphereGroup->setTransform( trans );

	return sphereGroup;
}

// Disk

IECoreGL::ConstRenderablePtr StandardLightVisualiser::diskSurface( float radius, IECore::ConstDataPtr textureData, const Color3f &tint, int maxTextureResolution, const Imath::Color3f &fallbackColor )
{
	IECoreGL::GroupPtr group = new IECoreGL::Group();
	if( textureData )
	{
		addTexturedConstantShader( group.get(), textureData, tint, maxTextureResolution );
	}
	else
	{
		addConstantShader( group.get(), tint, true );
	}

	IntVectorDataPtr vertsPerPoly = new IntVectorData;
	IntVectorDataPtr vertIds = new IntVectorData;
	V3fVectorDataPtr p = new V3fVectorData;

	addSolidArc( Axis::Z, V3f( 0 ), radius, 0, 0, 1, vertsPerPoly->writable(), vertIds->writable(), p->writable() );

	IECoreScene::MeshPrimitivePtr mesh = new IECoreScene::MeshPrimitive( vertsPerPoly, vertIds, "linear", p );
	mesh->variables["N"] = IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new V3fData( V3f( 0 ) ) );
	mesh->variables["Cs"] = IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new Color3fData( fallbackColor ) );
	ToGLMeshConverterPtr meshConverter = new ToGLMeshConverter( mesh );
	group->addChild( IECore::runTimeCast<IECoreGL::Renderable>( meshConverter->convert() ) );

	return group;
}

IECoreGL::ConstRenderablePtr StandardLightVisualiser::diskWireframe( float radius )
{
	IECoreGL::GroupPtr group = new IECoreGL::Group();
	addWireframeCurveState( group.get() );
	addConstantShader( group.get() );

	IntVectorDataPtr vertsPerCurveData = new IntVectorData;
	V3fVectorDataPtr pData = new V3fVectorData;

	addCircle( Axis::Z, V3f( 0 ), radius, vertsPerCurveData->writable(), pData->writable() );

	IECoreGL::CurvesPrimitivePtr curves = new IECoreGL::CurvesPrimitive( IECore::CubicBasisf::linear(), /* periodic = */ false, vertsPerCurveData );
	curves->addPrimitiveVariable( "P", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Vertex, pData ) );
	curves->addPrimitiveVariable( "Cs", IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, new Color3fData( g_lightWireframeColor ) ) );

	group->addChild( curves );

	return group;
}


text:
from base64 import b64decode, b64encode
from hashlib import sha256 as _sha256
from os import environ, urandom
from typing import Generator

from coincurve.context import GLOBAL_CONTEXT, Context
from coincurve.types import Hasher

from ._libsecp256k1 import ffi, lib

GROUP_ORDER = (
    b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
    b'\xfe\xba\xae\xdc\xe6\xafH\xa0;\xbf\xd2^\x8c\xd06AA'
)
GROUP_ORDER_INT = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
KEY_SIZE = 32
ZERO = b'\x00'
PEM_HEADER = b'-----BEGIN PRIVATE KEY-----\n'
PEM_FOOTER = b'-----END PRIVATE KEY-----\n'

if environ.get('COINCURVE_BUILDING_DOCS') != 'true':
    DEFAULT_NONCE = (ffi.NULL, ffi.NULL)

    def sha256(bytestr: bytes) -> bytes:
        return _sha256(bytestr).digest()

else:  # no cov

    class __Nonce(tuple):
        def __repr__(self):
            return '(ffi.NULL, ffi.NULL)'

    class __HasherSHA256:
        def __call__(self, bytestr: bytes) -> bytes:
            return _sha256(bytestr).digest()

        def __repr__(self):
            return 'sha256'

    DEFAULT_NONCE = __Nonce((ffi.NULL, ffi.NULL))  # type: ignore
    sha256 = __HasherSHA256()

def pad_hex(hexed: str) -> str:
    # Pad odd-length hex strings.
    return hexed if not len(hexed) & 1 else f'0{hexed}'

def bytes_to_int(bytestr: bytes) -> int:
    return int.from_bytes(bytestr, 'big')

def int_to_bytes(num: int) -> bytes:
    return num.to_bytes((num.bit_length() + 7) // 8 or 1, 'big')

def int_to_bytes_padded(num: int) -> bytes:
    return pad_scalar(num.to_bytes((num.bit_length() + 7) // 8 or 1, 'big'))

def hex_to_bytes(hexed: str) -> bytes:
    return pad_scalar(bytes.fromhex(pad_hex(hexed)))

def chunk_data(data: bytes, size: int) -> Generator[bytes, None, None]:
    return (data[i : i + size] for i in range(0, len(data), size))

def der_to_pem(der: bytes) -> bytes:
    return b''.join([PEM_HEADER, b'\n'.join(chunk_data(b64encode(der), 64)), b'\n', PEM_FOOTER])

def pem_to_der(pem: bytes) -> bytes:
    return b64decode(b''.join(pem.strip().splitlines()[1:-1]))

def get_valid_secret() -> bytes:
    while True:
        secret = urandom(KEY_SIZE)
        if ZERO < secret < GROUP_ORDER:
            return secret

def pad_scalar(scalar: bytes) -> bytes:
    return (ZERO * (KEY_SIZE - len(scalar))) + scalar

def validate_secret(secret: bytes) -> bytes:
    if not 0 < bytes_to_int(secret) < GROUP_ORDER_INT:
        raise ValueError('Secret scalar must be greater than 0 and less than {}.'.format(GROUP_ORDER_INT))
    return pad_scalar(secret)

def verify_signature(
    signature: bytes, message: bytes, public_key: bytes, hasher: Hasher = sha256, context: Context = GLOBAL_CONTEXT
) -> bool:
    """
    :param signature: The ECDSA signature.
    :param message: The message that was supposedly signed.
    :param public_key: The formatted public key.
    :param hasher: The hash function to use, which must return 32 bytes. By default,
                   the `sha256` algorithm is used. If `None`, no hashing occurs.
    :param context:
    :return: A boolean indicating whether or not the signature is correct.
    :raises ValueError: If the public key could not be parsed or was invalid, the message hash was
                        not 32 bytes long, or the DER-encoded signature could not be parsed.
    """
    pubkey = ffi.new('secp256k1_pubkey *')

    pubkey_parsed = lib.secp256k1_ec_pubkey_parse(context.ctx, pubkey, public_key, len(public_key))

    if not pubkey_parsed:
        raise ValueError('The public key could not be parsed or is invalid.')

    msg_hash = hasher(message) if hasher is not None else message
    if len(msg_hash) != 32:
        raise ValueError('Message hash must be 32 bytes long.')

    sig = ffi.new('secp256k1_ecdsa_signature *')

    sig_parsed = lib.secp256k1_ecdsa_signature_parse_der(context.ctx, sig, signature, len(signature))

    if not sig_parsed:
        raise ValueError('The DER-encoded signature could not be parsed.')

    verified = lib.secp256k1_ecdsa_verify(context.ctx, sig, msg_hash, pubkey)

    # A performance hack to avoid global bool() lookup.
    return not not verified

redpajama_set_name: RedPajamaGithub


text:
use rustc_serialize::json;

use super::super::schema;
use super::super::validators;

macro_rules! kw_minmax_integer{
    ($name:ident, $keyword:expr) => {
        #[allow(missing_copy_implementations)]
        pub struct $name;
        impl super::Keyword for $name {
            fn compile(&self, def: &json::Json, ctx: &schema::WalkContext) -> super::KeywordResult {
                let length = keyword_key_exists!(def, $keyword);

                if length.is_number() {
                    let length_val = length.as_f64().unwrap();
                    if length_val >= 0f64 && length_val.fract() == 0f64 {
                        Ok(Some(Box::new(validators::$name {
                            length: length_val as u64
                        })))
                    } else {
                        Err(schema::SchemaError::Malformed {
                            path: ctx.fragment.connect("/"),
                            detail: "The value MUST be a positive integer or zero".to_string()
                        })
                    }
                } else {
                    Err(schema::SchemaError::Malformed {
                        path: ctx.fragment.connect("/"),
                        detail: "The value MUST be a positive integer or zero".to_string()
                    })
                }
            }
        }
    }
}

kw_minmax_integer!(MaxLength, "maxLength");
kw_minmax_integer!(MinLength, "minLength");

#[cfg(test)] use super::super::scope;
#[cfg(test)] use jsonway;
#[cfg(test)] use super::super::builder;
#[cfg(test)] use rustc_serialize::json::{ToJson};

#[test]
fn validate_max_length() {
    let mut scope = scope::Scope::new();
    let schema = scope.compile_and_return(builder::schema(|s| {
        s.max_length(5u64);
    }).into_json(), true).ok().unwrap();;

    assert_eq!(schema.validate(&"1234".to_json()).is_valid(), true);
    assert_eq!(schema.validate(&"12345".to_json()).is_valid(), true);
    assert_eq!(schema.validate(&"123456".to_json()).is_valid(), false);
}

#[test]
fn malformed_max_length() {
    let mut scope = scope::Scope::new();

    assert!(scope.compile_and_return(jsonway::object(|schema| {
        schema.set("maxLength", (-1).to_json());
    }).unwrap(), true).is_err());

    assert!(scope.compile_and_return(jsonway::object(|schema| {
        schema.set("maxLength", "".to_json());
    }).unwrap(), true).is_err());

    assert!(scope.compile_and_return(jsonway::object(|schema| {
        schema.set("maxLength", (1.1).to_json());
    }).unwrap(), true).is_err());
}

#[test]
fn validate_min_length() {
    let mut scope = scope::Scope::new();
    let schema = scope.compile_and_return(builder::schema(|s| {
        s.min_length(5u64);
    }).into_json(), true).ok().unwrap();;

    assert_eq!(schema.validate(&"1234".to_json()).is_valid(), false);
    assert_eq!(schema.validate(&"12345".to_json()).is_valid(), true);
    assert_eq!(schema.validate(&"123456".to_json()).is_valid(), true);
}

#[test]
fn malformed_min_length() {
    let mut scope = scope::Scope::new();

    assert!(scope.compile_and_return(jsonway::object(|schema| {
        schema.set("minLength", (-1).to_json());
    }).unwrap(), true).is_err());

    assert!(scope.compile_and_return(jsonway::object(|schema| {
        schema.set("minLength", "".to_json());
    }).unwrap(), true).is_err());

    assert!(scope.compile_and_return(jsonway::object(|schema| {
        schema.set("minLength", (1.1).to_json());
    }).unwrap(), true).is_err());
}


text:
FSM_DECLARE_STATE(state_engaged);
FSM_DECLARE_STATE(state_disengaged);

// Mechanical Brake FSM transition table definitions
FSM_STATE_TRANSITION(state_engaged) {
  FSM_ADD_TRANSITION(PEDAL_EVENT_INPUT_DRIVE_UPDATE_REQUESTED, state_engaged);

  FSM_ADD_TRANSITION(PEDAL_EVENT_INPUT_MECHANICAL_BRAKE_PRESSED, state_engaged);
  FSM_ADD_TRANSITION(PEDAL_EVENT_INPUT_MECHANICAL_BRAKE_RELEASED, state_disengaged);
}

FSM_STATE_TRANSITION(state_disengaged) {
  FSM_ADD_TRANSITION(PEDAL_EVENT_INPUT_DRIVE_UPDATE_REQUESTED, state_disengaged);

  FSM_ADD_TRANSITION(PEDAL_EVENT_INPUT_MECHANICAL_BRAKE_PRESSED, state_engaged);
  FSM_ADD_TRANSITION(PEDAL_EVENT_INPUT_MECHANICAL_BRAKE_RELEASED, state_disengaged);
}

// Mechanical Brake FSM arbiter functions
static bool prv_guard_engaged(const Event *e) {
  // While the brakes are engaged, the car shouldn't allow the car to enter
  // cruise control.
  // Motor controller interface should ignore throttle state if mechanical
  // brake is engaged.
  switch (e->id) {
    case PEDAL_EVENT_INPUT_CONTROL_STALK_ANALOG_CC_RESUME:
      return false;
    default:
      return true;
  }
}

static bool prv_guard_disengaged(const Event *e) {
  // The mechanical brake must be engaged in order for gear shifts to happen.
  // We allow shifting into neutral at any time.
  switch (e->id) {
    case PEDAL_EVENT_INPUT_CENTER_CONSOLE_DIRECTION_DRIVE:
      // Fall through
    case PEDAL_EVENT_INPUT_CENTER_CONSOLE_DIRECTION_REVERSE:
      return false;
    default:
      return true;
  }
}

// Mechanical Brake FSM output functions
static void prv_engaged_output(Fsm *fsm, const Event *e, void *context) {
  EventArbiterGuard *guard = fsm->context;
  event_arbiter_set_guard_fn(guard, prv_guard_engaged);

  int16_t position = INT16_MAX;
  if (status_ok(mech_brake_get_position(mech_brake_global(), &position))) {
    drive_output_update(drive_output_global(), DRIVE_OUTPUT_SOURCE_MECH_BRAKE, position);
  }
}

static void prv_disengaged_output(Fsm *fsm, const Event *e, void *context) {
  EventArbiterGuard *guard = fsm->context;
  event_arbiter_set_guard_fn(guard, prv_guard_disengaged);

  int16_t position = INT16_MAX;
  if (status_ok(mech_brake_get_position(mech_brake_global(), &position))) {
    drive_output_update(drive_output_global(), DRIVE_OUTPUT_SOURCE_MECH_BRAKE, position);
  }
}

StatusCode mechanical_brake_fsm_init(Fsm *fsm, EventArbiterStorage *storage) {
  fsm_state_init(state_engaged, prv_engaged_output);
  fsm_state_init(state_disengaged, prv_disengaged_output);

  EventArbiterGuard *guard = event_arbiter_add_fsm(storage, fsm, prv_guard_disengaged);

  if (guard == NULL) {
    return status_code(STATUS_CODE_RESOURCE_EXHAUSTED);
  }

  fsm_init(fsm, "Mechanical Brake FSM", &state_disengaged, guard);

  return STATUS_CODE_OK;
}


text:
layout: page
title: Card Blue Global Party
date: 2016-05-24
author: Madison Buchanan
tags: weekly links, java
status: published
summary: Nam sodales laoreet tellus, at.
banner: images/banner/leisure-01.jpg
booking:
  startDate: 11/05/2016
  endDate: 11/08/2016
  ctyhocn: AIKSCHX
  groupCode: CBGP
published: true
---
Sed malesuada ligula sit amet mi venenatis sagittis vel pulvinar nibh. Aenean elit tellus, semper sed porta eu, euismod a arcu. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed ac dui a elit efficitur blandit. Phasellus arcu tortor, dapibus vitae gravida ut, commodo et dolor. Morbi hendrerit tristique feugiat. Sed nec rutrum nulla. Nunc a enim quis nunc efficitur venenatis eget non elit. Ut commodo arcu in semper ultrices. Nulla lobortis enim vitae velit sodales, quis porta elit faucibus.

1 Integer eget justo ornare, molestie purus vitae, congue diam
1 Fusce mollis nulla eget orci euismod, sollicitudin eleifend dolor tristique
1 Aliquam ac ex in odio imperdiet fringilla
1 Phasellus non ipsum id nisi sagittis vestibulum in vitae erat.

Vestibulum sit amet enim sollicitudin, tincidunt sapien a, pulvinar dui. Duis at consequat lectus. Mauris vulputate elit eget neque luctus varius. Sed luctus scelerisque nulla viverra egestas. Proin posuere et risus nec hendrerit. Quisque at sapien vel ipsum luctus fringilla at non est. Nulla id pellentesque enim.
Nulla facilisi. Cras ac nisi eget nisl viverra vulputate. Aenean vulputate nibh sed nulla condimentum aliquet ut a sem. Ut pellentesque orci nisi, et congue metus hendrerit quis. Aenean sagittis lectus eget lectus lobortis, sed congue arcu rhoncus. Donec id dictum orci. Mauris facilisis feugiat eleifend. Praesent ullamcorper ornare mauris, id rhoncus mi lacinia mollis. Duis massa enim, porttitor eget ultricies nec, eleifend in justo. Suspendisse vitae erat ullamcorper, porta turpis vitae, aliquam nibh.


text:
You clicked on: {{ selected }}

    <mat-toolbar>
      <button mat-icon-button [matMenuTriggerFor]="menu" aria-label="Open basic menu">
        <mat-icon>more_vert</mat-icon>
      </button>
    </mat-toolbar>

    <mat-menu #menu="matMenu">
      <button mat-menu-item *ngFor="let item of items" (click)="select(item.text)" [disabled]="item.disabled">
        {{ item.text }}
      </button>
    </mat-menu>

Menu with divider

    <mat-toolbar>
      <button mat-icon-button [matMenuTriggerFor]="divider" aria-label="Open basic menu">
        <mat-icon>more_vert</mat-icon>
      </button>
    </mat-toolbar>

    <mat-menu #divider="matMenu">
      <ng-container *ngFor="let item of items; last as last">
        <button mat-menu-item [disabled]="item.disabled">
          {{ item.text }}
        </button>
        <mat-divider *ngIf="!last"></mat-divider>
      </ng-container>
    </mat-menu>

Nested menu

    <mat-toolbar>
      <button mat-icon-button [matMenuTriggerFor]="animals">
        <mat-icon>more_vert</mat-icon>
      </button>
    </mat-toolbar>

    <mat-menu #animals="matMenu">
      <button mat-menu-item [matMenuTriggerFor]="vertebrates">Vertebrates</button>
      <button mat-menu-item [matMenuTriggerFor]="invertebrates">Invertebrates</button>
    </mat-menu>

    <mat-menu #vertebrates="matMenu">
      <button mat-menu-item [matMenuTriggerFor]="fish">Fishes</button>
      <button mat-menu-item [matMenuTriggerFor]="amphibians">Amphibians</button>
      <button mat-menu-item [matMenuTriggerFor]="reptiles">Reptiles</button>
      <button mat-menu-item>Birds</button>
      <button mat-menu-item>Mammals</button>
    </mat-menu>

    <mat-menu #invertebrates="matMenu">
      <button mat-menu-item>Insects</button>
      <button mat-menu-item>Molluscs</button>
      <button mat-menu-item>Crustaceans</button>
      <button mat-menu-item>Corals</button>
      <button mat-menu-item>Arachnids</button>
      <button mat-menu-item>Velvet worms</button>
      <button mat-menu-item>Horseshoe crabs</button>
    </mat-menu>

    <mat-menu #fish="matMenu">
      <button mat-menu-item>Baikal oilfish</button>
      <button mat-menu-item>Bala shark</button>
      <button mat-menu-item>Ballan wrasse</button>
      <button mat-menu-item>Bamboo shark</button>
      <button mat-menu-item>Banded killifish</button>
    </mat-menu>

    <mat-menu #amphibians="matMenu">
      <button mat-menu-item>Sonoran desert toad</button>
      <button mat-menu-item>Western toad</button>
      <button mat-menu-item>Arroyo toad</button>
      <button mat-menu-item>Yosemite toad</button>
    </mat-menu>

    <mat-menu #reptiles="matMenu">
      <button mat-menu-item>Banded Day Gecko</button>
      <button mat-menu-item>Banded Gila Monster</button>
      <button mat-menu-item>Black Tree Monitor</button>
      <button mat-menu-item>Blue Spiny Lizard</button>
    </mat-menu>

Clicking these will navigate:

    <mat-toolbar>
      <button mat-icon-button [matMenuTriggerFor]="anchorMenu" aria-label="Open anchor menu">
        <mat-icon>more_vert</mat-icon>
      </button>
    </mat-toolbar>

    <mat-menu #anchorMenu="matMenu">

        {{ item.text }}

    </mat-menu>

      Position x: before

    <mat-toolbar class="demo-end-icon">
      <button mat-icon-button [matMenuTriggerFor]="posXMenu" aria-label="Open x-positioned menu">
        <mat-icon>more_vert</mat-icon>
      </button>
    </mat-toolbar>

    <mat-menu xPosition="before" #posXMenu="matMenu">
      <button mat-menu-item *ngFor="let item of iconItems" [disabled]="item.disabled">
        <mat-icon>{{ item.icon }}</mat-icon>
        {{ item.text }}
      </button>
    </mat-menu>

      Position y: above

    <mat-toolbar>
      <button mat-icon-button [matMenuTriggerFor]="posYMenu" aria-label="Open y-positioned menu">
        <mat-icon>more_vert</mat-icon>
      </button>
    </mat-toolbar>

    <mat-menu yPosition="above" #posYMenu="matMenu">
      <button mat-menu-item *ngFor="let item of items" [disabled]="item.disabled">
        {{ item.text }}
      </button>
    </mat-menu>

overlapTrigger: true

    <mat-toolbar>
      <button mat-icon-button [mat-menu-trigger-for]="menuOverlay">
        <mat-icon>more_vert</mat-icon>
      </button>
    </mat-toolbar>

    <mat-menu [overlapTrigger]="true" #menuOverlay="matMenu">
      <button mat-menu-item *ngFor="let item of items" [disabled]="item.disabled">
        {{ item.text }}
      </button>
    </mat-menu>

      Position x: before, overlapTrigger: true

    <mat-toolbar class="demo-end-icon">
      <button mat-icon-button [mat-menu-trigger-for]="posXMenuOverlay">
        <mat-icon>more_vert</mat-icon>
      </button>
    </mat-toolbar>

    <mat-menu xPosition="before" [overlapTrigger]="true" #posXMenuOverlay="matMenu">
      <button mat-menu-item *ngFor="let item of iconItems" [disabled]="item.disabled">
        <mat-icon>{{ item.icon }}</mat-icon>
        {{ item.text }}
      </button>
    </mat-menu>

      Position y: above, overlapTrigger: true

    <mat-toolbar>
      <button mat-icon-button [mat-menu-trigger-for]="posYMenuOverlay">
        <mat-icon>more_vert</mat-icon>
      </button>
    </mat-toolbar>

    <mat-menu yPosition="above" [overlapTrigger]="true" #posYMenuOverlay="matMenu">
      <button mat-menu-item *ngFor="let item of items" [disabled]="item.disabled">
        {{ item.text }}
      </button>
    </mat-menu>

This div is for testing scrolled menus.


text:
import security from '../lib/security';
import FilesService from '../services/files';

class FilesRoute {
	constructor(router) {
		this.router = router;
		this.registerRoutes();
	}

	registerRoutes() {
		this.router.get(
			'/v1/files',
			security.checkUserScope.bind(this, security.scope.READ_FILES),
			this.getFiles.bind(this)
		);
		this.router.post(
			'/v1/files',
			security.checkUserScope.bind(this, security.scope.WRITE_FILES),
			this.uploadFile.bind(this)
		);
		this.router.delete(
			'/v1/files/:file',
			security.checkUserScope.bind(this, security.scope.WRITE_FILES),
			this.deleteFile.bind(this)
		);
	}

	getFiles(req, res, next) {
		FilesService.getFiles()
			.then(data => {
				res.send(data);
			})
			.catch(next);
	}

	uploadFile(req, res, next) {
		FilesService.uploadFile(req, res, next);
	}

	deleteFile(req, res, next) {
		FilesService.deleteFile(req.params.file)
			.then(() => {
				res.end();
			})
			.catch(next);
	}
}

export default FilesRoute;


text:
package com.humorusz.practice.liveroom.intoRoom;

import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.AnimationDrawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.humorusz.practice.R;
import com.humorusz.practice.shader.widget.MaskLoadingView;

/**
 * Created by zhangzhiquan on 2017/8/19.
 */

public class IntoRoomAnimatorView extends LinearLayout implements Animation.AnimationListener {
    private static final String TAG = "IntoRoomAnimatorView";
    private TextView mTextView;
    private ViewGroup mTextContainer;
    private ImageView mStar;
    private Context mContext;
    private Animation inAnimation,outAnimation;
    private OnAnimationStateListener mListener;
    private Interpolator interpolator;
    private boolean isCancel;
    private boolean isRunning;
    private MaskLoadingView mTestMask;
    public IntoRoomAnimatorView(Context context) {
        this(context,null);
    }

    public IntoRoomAnimatorView(Context context, AttributeSet attrs) {
        this(context, attrs,-1);
    }

    public IntoRoomAnimatorView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        init();

    }

    private void init(){
        LayoutInflater.from(mContext).inflate(R.layout.layout_into_room_view,this);
        mTextContainer = findViewById(R.id.text_container);
        mStar = (ImageView) findViewById(R.id.star_img);
        mTextView = (TextView) findViewById(R.id.text_into);
        inAnimation = AnimationUtils.loadAnimation(mContext,R.anim.into_right_to_left);
        inAnimation.setFillAfter(true);
        inAnimation.setAnimationListener(this);
        outAnimation = AnimationUtils.loadAnimation(mContext,R.anim.into_out);
        outAnimation.setFillAfter(true);
        outAnimation.setAnimationListener(this);
        mStar.setImageResource(R.drawable.aa);
        mStar.clearAnimation();
        interpolator = new EaseCubicInterpolator(0f,1.17f,0f,0.9f);
        mTestMask = findViewById(R.id.text_mask);
        int[] colors = new int[]{Color.TRANSPARENT, Color.parseColor("#02ffffff"), Color.parseColor("#22ffffff"), Color.parseColor("#02ffffff"), Color.TRANSPARENT};
        float[] position = new float[]{0.3f, 0.4f, 0.5f, 0.6f, 0.7f};
        mTestMask.setColors(colors);
        mTestMask.setPositions(position);
    }

    public void setData(CharSequence data){
        if(isRunning)
            return;
        mTextView.setText(data);
        AnimationDrawable anim = (AnimationDrawable) mStar.getDrawable();
        anim.start();
        isCancel = false;
        Interpolator interpolator = new EaseCubicInterpolator(0f,1.17f,0f,0.9f);
        inAnimation.setInterpolator(interpolator);
        mTextContainer.startAnimation(inAnimation);
    }

    public void stopAnim(){
        isCancel = true;
        mTextContainer.clearAnimation();
        isRunning = false;

    }

    public void setOnAnimationStateListener(OnAnimationStateListener listener){
        mListener = listener;
    }

    @Override
    public void onAnimationStart(Animation animation) {
        if(mListener != null){
            mListener.onStart();
        }
        if(animation == inAnimation){
            isRunning = true;
        }
    }

    @Override
    public void onAnimationEnd(Animation animation) {
        if(animation == inAnimation){
            if(!isCancel){
                mTextContainer.startAnimation(outAnimation);
            }
        }else if(animation == outAnimation){
            isRunning = false;
            AnimationDrawable anim = (AnimationDrawable) mStar.getDrawable();
            anim.stop();
            if(mListener != null){
                mListener.onEnd();
            }
        }
    }

    @Override
    public void onAnimationRepeat(Animation animation) {

    }

    public interface OnAnimationStateListener{
        void onStart();
        void onEnd();
    }
}


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <title></title>

jQuery Demo


text:
package org.apache.cassandra.concurrent;

import org.apache.cassandra.utils.Closeable;
import org.apache.cassandra.utils.Shared;
import org.apache.cassandra.utils.WithResources;
import org.apache.cassandra.utils.concurrent.Future;
import org.apache.cassandra.utils.concurrent.ImmediateFuture;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

import static org.apache.cassandra.utils.Shared.Scope.SIMULATION;

@Shared(scope = SIMULATION) // shared to support instanceof check in SimulatedAction
public class ImmediateExecutor implements LocalAwareExecutorPlus
{
    public static final ImmediateExecutor INSTANCE = new ImmediateExecutor();

    private ImmediateExecutor() {}

    public <T> Future<T> submit(Callable<T> task)
    {
        try
        {
            return ImmediateFuture.success(task.call());
        }
        catch (Throwable t)
        {
            ExecutionFailure.handle(t);
            return ImmediateFuture.failure(t);
        }
    }

    public <T> Future<T> submit(Runnable task, T result)
    {
        try
        {
            task.run();
            return ImmediateFuture.success(result);
        }
        catch (Throwable t)
        {
            ExecutionFailure.handle(t);
            return ImmediateFuture.failure(t);
        }
    }

    public Future<?> submit(Runnable task)
    {
        try
        {
            task.run();
            return ImmediateFuture.success(null);
        }
        catch (Throwable t)
        {
            ExecutionFailure.handle(t);
            return ImmediateFuture.failure(t);
        }
    }

    @Override
    public void execute(WithResources withResources, Runnable task)
    {
        try (Closeable ignored = withResources.get())
        {
            task.run();
        }
        catch (Throwable t)
        {
            ExecutionFailure.handle(t);
        }
    }

    @Override
    public <T> Future<T> submit(WithResources withResources, Callable<T> task)
    {
        try (Closeable ignored = withResources.get())
        {
            return ImmediateFuture.success(task.call());
        }
        catch (Throwable t)
        {
            ExecutionFailure.handle(t);
            return ImmediateFuture.failure(t);
        }
    }

    @Override
    public Future<?> submit(WithResources withResources, Runnable task)
    {
        return submit(withResources, task, null);
    }

    @Override
    public <T> Future<T> submit(WithResources withResources, Runnable task, T result)
    {
        try (Closeable ignored = withResources.get())
        {
            task.run();
            return ImmediateFuture.success(result);
        }
        catch (Throwable t)
        {
            ExecutionFailure.handle(t);
            return ImmediateFuture.failure(t);
        }
    }

    @Override
    public boolean inExecutor()
    {
        return true;
    }

    public void execute(Runnable task)
    {
        try
        {
            task.run();
        }
        catch (Throwable t)
        {
            ExecutionFailure.handle(t);
        }
    }

    public int  getActiveTaskCount()    { return 0; }
    public long getCompletedTaskCount() { return 0; }
    public int  getPendingTaskCount()   { return 0; }
    public int  getCorePoolSize()       { return 0; }
    public int  getMaximumPoolSize()    { return 0; }
    public void setCorePoolSize(int newCorePoolSize) { throw new IllegalArgumentException("Cannot resize ImmediateExecutor"); }
    public void setMaximumPoolSize(int newMaximumPoolSize) { throw new IllegalArgumentException("Cannot resize ImmediateExecutor"); }

    public void shutdown() { }
    public List<Runnable> shutdownNow() { return Collections.emptyList(); }
    public boolean isShutdown() { return false; }
    public boolean isTerminated() { return false; }
    public boolean awaitTermination(long timeout, TimeUnit unit) { return true; }
}


text:
<!DOCTYPE html>

<meta name="generator" content="Hexo 3.8.0">

    <meta charset="utf-8">

    <title>存档: 2018 | 青史成灰 | Every journey begins with the first step</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

    <meta name="theme-color" content="#3F51B5">

    <meta name="keywords" content="html5,css3,js,nodejs,shell">
    <meta name="keywords" content="html5,css3,js,nodejs,shell">
<meta property="og:type" content="website">
<meta property="og:title" content="青史成灰">
<meta property="og:url" content="https://xxxxxmiss.github.io/archives/2018/page/2/index.html">
<meta property="og:site_name" content="青史成灰">
<meta property="og:locale" content="zh-CN">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="青史成灰">

        <link rel="alternate" type="application/atom+xml" title="青史成灰" href="/atom.xml">

    <link rel="shortcut icon" href="/favicon.ico">
    <link rel="stylesheet" href="//unpkg.com/hexo-theme-material-indigo@latest/css/style.css">

        <hgroup class="introduce">

xxxxxMiss

          794465731@qq.com
        </hgroup>

                主页

                存档

                标签

                分类

                Github

                Weibo

                测试

存档

            <input type="text" id="key" class="search-input" autocomplete="off" placeholder="输入感兴趣的关键字">

存档

三月, 2018

      <time class="post-time" title="2018-03-16 16:21:48" datetime="2018-03-16T08:21:48.000Z" itemprop="datePublished">2018-03-16</time>

工作流

      代码规范

changelog

git

lint

prettier

workflow

      <time class="post-time" title="2018-03-14 14:42:07" datetime="2018-03-14T06:42:07.000Z" itemprop="datePublished">2018-03-14</time>

      make

      <time class="post-time" title="2018-03-08 00:48:17" datetime="2018-03-07T16:48:17.000Z" itemprop="datePublished">2018-03-08</time>

      shell-command

      <time class="post-time" title="2018-03-06 23:58:01" datetime="2018-03-06T15:58:01.000Z" itemprop="datePublished">2018-03-06</time>

      docker

一月, 2018

      <time class="post-time" title="2018-01-07 22:47:43" datetime="2018-01-07T14:47:43.000Z" itemprop="datePublished">2018-01-07</time>

js

      DOM元素的坐标,大小相关API梳理

dom

    上一页12

        站点总访客数:

        站点总访问量:

            博客内容遵循 知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议

xxxxxMiss © 2016 - 2019

                Power by Hexo Theme indigo

扫一扫,分享到微信

    <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMYAAADGCAAAAACs8KCBAAACMUlEQVR42u3awW6EMAxF0f7/T9PtSBVwn52plPiyGlUQcli4tuOfH3xdH9fnX/7e8/z7buW7tyy+ZMiQsS3jerzu7nl+lmyUsMneZMiQMYdBQiEPxxxZC9YyZMiQkQbB5/SRPJt+PhkyZMhIA24tKPO/yJAhQwYvYslyaVlbK5JlyJAxjcG77v//+yvnGzJkyNiKcYVXJ2imnynYlQwZMo5mpK+pJYh8OIOnfTJkyJjMqJWRZLSLN/X4s8FCMmTI2JzxvcOAWsjmKebt22XIkHEcIx2q6G93VZooQ4aMCYxaKy1tsZFnyZov5asMGTKOZnTGKUiLjZTE6R7ifFaGDBmbM2qNMD6qFQdQvNuX1FCGDBkHMToNNdIOq41uBEFfhgwZwxhp4KsdbfIkEgVuGTJkDGCsWrqWMqYDGbcnGzJkyDiUwW8ijf40fewPlsX/PWTIkHEEgwfcNEGslanBWYAMGTIGMPiLeTpYO8IsHiTIkCFjMIOUo7yJn4bduIiVIUPGGEYnZUxDdm1Q7KV3KEOGjKMZpHAtDm/hxlwxQMuQIWMAg6RxJHXjh5ecF0+OyJAh4yDGFV4kcUyDLP/et2+UIUPG0Yza0v2UsfaBFnwsGTJkbMvotL3SQLz2ICH+TjJkyNicQUrT9Mizdv+CWlyGDBnjGTw4kqNNPv71QpUhQ4aMzsBWO+yigwcZMmQMYPD0jrfe0rHX1soyZMg4mtHpZfXL4FrR2zrfkCFDxk6MX+1JvCpELPInAAAAAElFTkSuQmCC" alt="微信分享二维码">

<template id="search-tpl">

{title}

                {tags}

            <time class="flex-col time">{date}</time>

</template>


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace MobileUI
{
  public class App
  {
    public static OrderVm MainViewModel { get; private set; }

    public static Page GetMainPage()
    {
      Csla.ApplicationContext.DataPortalProxy = typeof(Csla.DataPortalClient.WcfProxy).AssemblyQualifiedName;
      Csla.ApplicationContext.DataPortalUrlString = "http://simplentier.azurewebsites.net/SlPortal.svc";

      var page = new MainPage();

      MainViewModel = new OrderVm();
      page.ViewModel = MainViewModel;
      return new NavigationPage(page);
    }

    public static async Task InitializeViewModel()
    {
      try
      {
        await MainViewModel.LoadData();
      }
      catch (Exception ex)
      {
        var tmp = ex;
      }
    }
  }
}


text:
package com.amazonaws.services.ec2.model;

import java.io.Serializable;
import javax.annotation.Generated;

import com.amazonaws.AmazonWebServiceResult;

/**
 *

 * Contains the output for DescribeConversionTasks.
 *

 */
@Generated("com.amazonaws:aws-java-sdk-code-generator")
public class DescribeConversionTasksResult extends com.amazonaws.AmazonWebServiceResult<com.amazonaws.ResponseMetadata> implements Serializable, Cloneable {

    /**
     *

     * Information about the conversion tasks.
     *

     */
    private com.amazonaws.internal.SdkInternalList<ConversionTask> conversionTasks;

    /**
     *

     * Information about the conversion tasks.
     *

     *
     * @return Information about the conversion tasks.
     */

    public java.util.List<ConversionTask> getConversionTasks() {
        if (conversionTasks == null) {
            conversionTasks = new com.amazonaws.internal.SdkInternalList<ConversionTask>();
        }
        return conversionTasks;
    }

    /**
     *

     * Information about the conversion tasks.
     *

     *
     * @param conversionTasks
     *        Information about the conversion tasks.
     */

    public void setConversionTasks(java.util.Collection<ConversionTask> conversionTasks) {
        if (conversionTasks == null) {
            this.conversionTasks = null;
            return;
        }

        this.conversionTasks = new com.amazonaws.internal.SdkInternalList<ConversionTask>(conversionTasks);
    }

    /**
     *

     * Information about the conversion tasks.
     *

     *

     * NOTE: This method appends the values to the existing list (if any). Use
     * {@link #setConversionTasks(java.util.Collection)} or {@link #withConversionTasks(java.util.Collection)} if you
     * want to override the existing values.
     *

     *
     * @param conversionTasks
     *        Information about the conversion tasks.
     * @return Returns a reference to this object so that method calls can be chained together.
     */

    public DescribeConversionTasksResult withConversionTasks(ConversionTask... conversionTasks) {
        if (this.conversionTasks == null) {
            setConversionTasks(new com.amazonaws.internal.SdkInternalList<ConversionTask>(conversionTasks.length));
        }
        for (ConversionTask ele : conversionTasks) {
            this.conversionTasks.add(ele);
        }
        return this;
    }

    /**
     *

     * Information about the conversion tasks.
     *

     *
     * @param conversionTasks
     *        Information about the conversion tasks.
     * @return Returns a reference to this object so that method calls can be chained together.
     */

    public DescribeConversionTasksResult withConversionTasks(java.util.Collection<ConversionTask> conversionTasks) {
        setConversionTasks(conversionTasks);
        return this;
    }

    /**
     * Returns a string representation of this object; useful for testing and debugging.
     *
     * @return A string representation of this object.
     *
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("{");
        if (getConversionTasks() != null)
            sb.append("ConversionTasks: ").append(getConversionTasks());
        sb.append("}");
        return sb.toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;

        if (obj instanceof DescribeConversionTasksResult == false)
            return false;
        DescribeConversionTasksResult other = (DescribeConversionTasksResult) obj;
        if (other.getConversionTasks() == null ^ this.getConversionTasks() == null)
            return false;
        if (other.getConversionTasks() != null && other.getConversionTasks().equals(this.getConversionTasks()) == false)
            return false;
        return true;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int hashCode = 1;

        hashCode = prime * hashCode + ((getConversionTasks() == null) ? 0 : getConversionTasks().hashCode());
        return hashCode;
    }

    @Override
    public DescribeConversionTasksResult clone() {
        try {
            return (DescribeConversionTasksResult) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new IllegalStateException("Got a CloneNotSupportedException from Object.clone() " + "even though we're Cloneable!", e);
        }
    }
}


text:
from django.conf import settings
from django.urls import re_path
from django.views.generic import TemplateView
from course_grader.views.chooser import HomeView
from course_grader.views.section import SectionView
from course_grader.views.support.status import status
from course_grader.views.support.search import graderosters, grade_imports
from course_grader.views.api.sections import Sections
from course_grader.views.api.graderoster import (
    GradeRoster, GradeRosterStatus, GradeRosterExport)
from course_grader.views.api.importgrades import ImportGrades, UploadGrades
from course_grader.views.api.conversionscales import ConversionScales
from course_grader.views.api.submitted_graderoster import (
    SubmissionsByTerm, SubmittedGradeRoster)

urlpatterns = [
    re_path(r'^$', HomeView.as_view(), name='home'),
    re_path(
        r'^section/(?P<url_token>[^/]*)$',
        SectionView.as_view(), name='section'),
    re_path(
        r'^api/v1/sections/(?P<term_id>[^/]*)$',
        Sections.as_view(), name='section-list'),
    re_path(
        r'^api/v1/graderoster/(?P<section_id>[^/]*)$',
        GradeRoster.as_view(), name='graderoster-edit'),
    re_path(
        r'^api/v1/export/(?P<section_id>[^/]*)$',
        GradeRosterExport.as_view(), name='graderoster-export'),
    re_path(
        r'^api/v1/grading_status/(?P<section_id>[^/]*)$',
        GradeRosterStatus.as_view(), name='grading-status'),
    re_path(
        r'^api/v1/import/(?P<section_id>[^/]*)$',
        ImportGrades.as_view(), name='grade-import'),
    re_path(
        r'^api/v1/import/(?P<section_id>[^/]*)/(?P<import_id>[\d]*)$',
        ImportGrades.as_view(), name='grade-import-id'),
    re_path(
        r'^api/v1/import_file/(?P<section_id>[^/]+)/(?P<import_id>\d+)$',
        UploadGrades.as_view(), name='grade-import-file'),
    re_path(
        r'^api/v1/import_file/(?P<section_id>[^/]*)$',
        UploadGrades.as_view(), name='grade-import-file'),
    re_path(
        r'^api/v1/conversion_scales/(?P<scale>[a-z]*)$',
        ConversionScales.as_view(), name='conversion-scales'),

    # support urls
    re_path(r'^support/status/?$', status, name='gradepage-status'),
    re_path(r'^support/search/?$', graderosters, name='graderoster-search'),
    re_path(r'^support/imports/?$', grade_imports, name='grade-import-search'),
    re_path(
        r'^api/v1/submitted_graderosters/(?P<term_id>[^/]*)$',
        SubmissionsByTerm.as_view(), name='term-submissions'),
    re_path(
        r'^api/v1/submitted_graderoster/(?P<graderoster_id>[\d]*)$',
        SubmittedGradeRoster.as_view(), name='graderoster-download'),
]

# debug routes for developing error pages
if settings.DEBUG:
    urlpatterns.extend([
        re_path(r'^404$', TemplateView.as_view(template_name='404.html')),
        re_path(r'^500$', TemplateView.as_view(template_name='500.html')),
    ])


text:
import proto  # type: ignore

from google.ads.googleads.v12.enums.types import asset_field_type
from google.ads.googleads.v12.enums.types import asset_link_status
from google.ads.googleads.v12.enums.types import asset_source

__protobuf__ = proto.module(
    package="google.ads.googleads.v12.resources",
    marshal="google.ads.googleads.v12",
    manifest={"CampaignAsset",},
)

class CampaignAsset(proto.Message):
    r"""A link between a Campaign and an Asset.

    Attributes:
        resource_name (str):
            Immutable. The resource name of the campaign asset.
            CampaignAsset resource names have the form:

            ``customers/{customer_id}/campaignAssets/{campaign_id}~{asset_id}~{field_type}``
        campaign (str):
            Immutable. The campaign to which the asset is
            linked.

            This field is a member of `oneof`_ ``_campaign``.
        asset (str):
            Immutable. The asset which is linked to the
            campaign.

            This field is a member of `oneof`_ ``_asset``.
        field_type (google.ads.googleads.v12.enums.types.AssetFieldTypeEnum.AssetFieldType):
            Immutable. Role that the asset takes under
            the linked campaign. Required.
        source (google.ads.googleads.v12.enums.types.AssetSourceEnum.AssetSource):
            Output only. Source of the campaign asset
            link.
        status (google.ads.googleads.v12.enums.types.AssetLinkStatusEnum.AssetLinkStatus):
            Status of the campaign asset.
    """

    resource_name = proto.Field(proto.STRING, number=1,)
    campaign = proto.Field(proto.STRING, number=6, optional=True,)
    asset = proto.Field(proto.STRING, number=7, optional=True,)
    field_type = proto.Field(
        proto.ENUM,
        number=4,
        enum=asset_field_type.AssetFieldTypeEnum.AssetFieldType,
    )
    source = proto.Field(
        proto.ENUM, number=8, enum=asset_source.AssetSourceEnum.AssetSource,
    )
    status = proto.Field(
        proto.ENUM,
        number=5,
        enum=asset_link_status.AssetLinkStatusEnum.AssetLinkStatus,
    )

__all__ = tuple(sorted(__protobuf__.manifest))