text:
#include "FBXFile.h"
#include <fbxsdk.h>
#include <algorithm>
#include <set>

// only needed for texture cleanup
//#define GLEW_NO_GLU
//#include <GL/glew.h>
#include <gl_core_4_4.h>

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/matrix_inverse.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtx/norm.hpp>

struct ImportAssistor
{
	ImportAssistor() : evaluator(nullptr), loadAnimationOnly(false) {}
	~ImportAssistor() { evaluator = nullptr; }

	FbxScene*				scene;
	FbxAnimEvaluator*		evaluator;
	FbxImporter*			importer;
	std::vector<FBXNode*>	bones;

	bool					loadTextures;
	bool					loadAnimations;
	bool					loadAnimationOnly;
	float					unitScale;
	bool					flipTextureY;

	std::map<std::string,int> boneIndexList;
};

void FBXFile::unload()
{
	delete m_root;
	m_root = nullptr;

	for (auto m : m_materials)
		delete m.second;
	for (auto s : m_skeletons)
		delete s;
	for (auto a : m_animations)
		delete a.second;
	for (auto t : m_textures)
		delete t.second;

	m_meshes.clear();
	m_lights.clear();
	m_cameras.clear();
	m_materials.clear();
	m_skeletons.clear();
	m_animations.clear();
	m_textures.clear();
}

bool FBXFile::load(const char* a_filename, UNIT_SCALE a_scale /* = FBXFile::UNITS_METER */,
	bool a_loadTextures /* = true */, bool a_loadAnimations /* = true */, bool a_flipTextureY /*= true*/)
{
	if (m_root != nullptr)
	{
		printf("Scene already loaded!\n");
		return false;
	}

	FbxManager* lSdkManager = nullptr;
	FbxScene* lScene = nullptr;

	// The first thing to do is to create the FBX SDK manager which is the
	// object allocator for almost all the classes in the SDK.
	lSdkManager = FbxManager::Create();
	if ( !lSdkManager )
	{
		printf("Unable to create the FBX SDK manager\n");
		return false;
	}

	// create an IOSettings object
	FbxIOSettings * ios = FbxIOSettings::Create(lSdkManager, IOSROOT );
	lSdkManager->SetIOSettings(ios);

	// Create an importer.
	FbxImporter* lImporter = FbxImporter::Create(lSdkManager,"");

	// Initialize the importer by providing a filename.
	bool lImportStatus = lImporter->Initialize(a_filename, -1, lSdkManager->GetIOSettings());

	if ( !lImportStatus )
	{
		printf("Call to FbxImporter::Initialize() failed:\n\t%s\n", lImporter->GetStatus().GetErrorString());
		lImporter->Destroy();
		return false;
	}

	// Create the entity that will hold the scene.
	int lFileMajor, lFileMinor, lFileRevision;
	int lSDKMajor,  lSDKMinor,  lSDKRevision;

	unsigned int i;
	bool lStatus;

	// Get the file version number generate by the FBX SDK.
	FbxManager::GetFileFormatVersion(lSDKMajor, lSDKMinor, lSDKRevision);
	lImporter->GetFileVersion(lFileMajor, lFileMinor, lFileRevision);

	lScene = FbxScene::Create(lSdkManager,"root");

	// Import the scene.
	lStatus = lImporter->Import(lScene);
	lImporter->Destroy();
	if (lStatus == false)
	{
		printf("Unable to open FBX file!\n");
		return false;
	}

	float unitScale = 1;

	// convert scale
	if ( lScene->GetGlobalSettings().GetSystemUnit() != FbxSystemUnit::sPredefinedUnits[a_scale] )
	{
		const FbxSystemUnit::ConversionOptions lConversionOptions = {
			false, // mConvertRrsNodes
			true, // mConvertAllLimits
			true, // mConvertClusters
			true, // mConvertLightIntensity
			true, // mConvertPhotometricLProperties
			true  // mConvertCameraClipPlanes
		};

		unitScale = (float)(lScene->GetGlobalSettings().GetSystemUnit().GetScaleFactor() / FbxSystemUnit::sPredefinedUnits[a_scale].GetScaleFactor());

		// Convert the scene to meters using the defined options.
		FbxSystemUnit::sPredefinedUnits[a_scale].ConvertScene(lScene, lConversionOptions);
	}

	// convert the scene to OpenGL axis (right-handed Y up)
	FbxAxisSystem::OpenGL.ConvertScene(lScene);

	// DID NOT KNOW WE COULD DO THIS!!!!
	/*
	// Convert mesh, NURBS and patch into triangle mesh
	FbxGeometryConverter lGeomConverter(mSdkManager);
	lGeomConverter.Triangulate(mScene, true);

	// Split meshes per material, so that we only have one material per mesh (for VBO support)
	lGeomConverter.SplitMeshesPerMaterial(mScene, true);
	*/

	FbxNode* lNode = lScene->GetRootNode();

	if (lNode != nullptr)
	{
		// store the folder path of the scene
		m_path = a_filename;
		long iLastForward = m_path.find_last_of('/');
		long iLastBackward = m_path.find_last_of('\\');
		if (iLastForward > iLastBackward)
		{
			m_path.resize(iLastForward + 1);
		}
		else if (iLastBackward != 0)
		{
			m_path.resize(iLastBackward + 1);
		}
		else
		{
			m_path = "";
		}

		m_importAssistor = new ImportAssistor();
		m_importAssistor->scene = lScene;
		m_importAssistor->evaluator = lScene->GetAnimationEvaluator();
		m_importAssistor->importer = lImporter;
		m_importAssistor->loadTextures = a_loadTextures;
		m_importAssistor->loadAnimations = a_loadAnimations;
		m_importAssistor->unitScale = unitScale;
		m_importAssistor->flipTextureY = a_flipTextureY;

		m_root = new FBXNode();
		m_root->m_name = "root";
		m_root->m_globalTransform = m_root->m_localTransform = glm::mat4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);

		// grab the ambient light data from the scene
		m_ambientLight.x = (float)lScene->GetGlobalSettings().GetAmbientColor().mRed;
		m_ambientLight.y = (float)lScene->GetGlobalSettings().GetAmbientColor().mGreen;
		m_ambientLight.z = (float)lScene->GetGlobalSettings().GetAmbientColor().mBlue;
		m_ambientLight.w = (float)lScene->GetGlobalSettings().GetAmbientColor().mAlpha;

		// gather bones to create indices for them in a skeleton
		if (a_loadAnimations == true)
		{
			for (i = 0; i < (unsigned int)lNode->GetChildCount(); ++i)
			{
				gatherBones((void*)lNode->GetChild(i));
			}
		}

		// extract scene (meshes, lights, cameras)
		for (i = 0; i < (unsigned int)lNode->GetChildCount(); ++i)
		{
			extractObject(m_root, (void*)lNode->GetChild(i));
		}

		// ensure all threads are finished
		for (auto t : m_threads)
			t->join();
		m_threads.clear();

		// build skeleton and extract animation keyframes
		if (a_loadAnimations == true &&
			m_importAssistor->bones.size() > 0)
		{
			FBXSkeleton* skeleton = new FBXSkeleton();
			skeleton->m_boneCount = (unsigned int)m_importAssistor->bones.size();
			skeleton->m_nodes = new FBXNode * [ skeleton->m_boneCount ];
			skeleton->m_bones = new glm::mat4[ skeleton->m_boneCount ];
			skeleton->m_bindPoses = new glm::mat4[ skeleton->m_boneCount ];

			skeleton->m_parentIndex = new int[ skeleton->m_boneCount ];

			for ( i = 0 ; i < skeleton->m_boneCount ; ++i )
			{
				skeleton->m_nodes[ i ] = m_importAssistor->bones[ i ];
				skeleton->m_bones[ i ] = skeleton->m_nodes[ i ]->m_localTransform;
			}
			for ( i = 0 ; i < skeleton->m_boneCount ; ++i )
			{
				skeleton->m_parentIndex[i] = -1;
				for ( int j = 0 ; j < (int)skeleton->m_boneCount ; ++j )
				{
					if (skeleton->m_nodes[i]->m_parent == skeleton->m_nodes[j])
					{
						skeleton->m_parentIndex[i] = j;
						break;
					}
				}
			}

			extractSkeleton(skeleton, lScene);

			m_skeletons.push_back(skeleton);

			extractAnimation(lScene);
		}

		m_root->updateGlobalTransform();

		delete m_importAssistor;
		m_importAssistor = nullptr;
	}

	lSdkManager->Destroy();

	// load textures!
	for (auto texture : m_textures)
		m_threads.push_back( new std::thread( [](FBXTexture* t){

		t->data = stbi_load(t->path.c_str(), &t->width, &t->height, &t->format, STBI_default);
		//	t->data = SOIL_load_image(t->path.c_str(), &t->width, &t->height, &t->channels, SOIL_LOAD_AUTO);
			if (t->data == nullptr)
			{
				printf("Failed to load texture: %s\n", t->path.c_str());
			}
	}, texture.second));

	for (auto t : m_threads)
		t->join();
	m_threads.clear();

	return true;
}

bool FBXFile::loadAnimationsOnly(const char* a_filename, UNIT_SCALE a_scale /* = FBXFile::UNITS_METER */)
{
	if (m_root != nullptr)
	{
		printf("Scene already loaded!\n");
		return false;
	}

	FbxManager* lSdkManager = nullptr;
	FbxScene* lScene = nullptr;

	// The first thing to do is to create the FBX SDK manager which is the
	// object allocator for almost all the classes in the SDK.
	lSdkManager = FbxManager::Create();
	if ( !lSdkManager )
	{
		printf("Unable to create the FBX SDK manager\n");
		return false;
	}

	// create an IOSettings object
	FbxIOSettings * ios = FbxIOSettings::Create(lSdkManager, IOSROOT );
	lSdkManager->SetIOSettings(ios);

	// Create an importer.
	FbxImporter* lImporter = FbxImporter::Create(lSdkManager,"");

	// Initialize the importer by providing a filename.
	bool lImportStatus = lImporter->Initialize(a_filename, -1, lSdkManager->GetIOSettings());

	if ( !lImportStatus )
	{
		printf("Call to FbxImporter::Initialize() failed:\n\t%s\n", lImporter->GetStatus().GetErrorString());
		lImporter->Destroy();
		return false;
	}

	// Create the entity that will hold the scene.
	int lFileMajor, lFileMinor, lFileRevision;
	int lSDKMajor,  lSDKMinor,  lSDKRevision;

	unsigned int i;
	bool lStatus;

	// Get the file version number generate by the FBX SDK.
	FbxManager::GetFileFormatVersion(lSDKMajor, lSDKMinor, lSDKRevision);
	lImporter->GetFileVersion(lFileMajor, lFileMinor, lFileRevision);

	lScene = FbxScene::Create(lSdkManager,"root");

	// Import the scene.
	lStatus = lImporter->Import(lScene);
	lImporter->Destroy();
	if (lStatus == false)
	{
		printf("Unable to open FBX file!\n");
		return false;
	}

	float unitScale = 1;

	// convert scale
	if ( lScene->GetGlobalSettings().GetSystemUnit() != FbxSystemUnit::sPredefinedUnits[a_scale] )
	{
		const FbxSystemUnit::ConversionOptions lConversionOptions = {
			false, // mConvertRrsNodes
			true, // mConvertAllLimits
			true, // mConvertClusters
			true, // mConvertLightIntensity
			true, // mConvertPhotometricLProperties
			true  // mConvertCameraClipPlanes
		};

		unitScale = (float)(lScene->GetGlobalSettings().GetSystemUnit().GetScaleFactor() / FbxSystemUnit::sPredefinedUnits[a_scale].GetScaleFactor());

		// Convert the scene to meters using the defined options.
		FbxSystemUnit::sPredefinedUnits[a_scale].ConvertScene(lScene, lConversionOptions);
	}

	// convert the scene to OpenGL axis (right-handed Y up)
	FbxAxisSystem::OpenGL.ConvertScene(lScene);

	FbxNode* lNode = lScene->GetRootNode();

	if (lNode != nullptr)
	{
		// store the folder path of the scene
		m_path = a_filename;
		long iLastForward = m_path.find_last_of('/');
		long iLastBackward = m_path.find_last_of('\\');
		if (iLastForward > iLastBackward)
		{
			m_path.resize(iLastForward + 1);
		}
		else if (iLastBackward != 0)
		{
			m_path.resize(iLastBackward + 1);
		}
		else
		{
			m_path = "";
		}

		m_importAssistor = new ImportAssistor();

		m_importAssistor->scene = lScene;
		m_importAssistor->evaluator = lScene->GetAnimationEvaluator();
		m_importAssistor->importer = lImporter;
		m_importAssistor->loadTextures = false;
		m_importAssistor->loadAnimations = true;
		m_importAssistor->loadAnimationOnly = true;
		m_importAssistor->unitScale = unitScale;

		m_root = new FBXNode();
		m_root->m_name = "root";
		m_root->m_globalTransform = m_root->m_localTransform = glm::mat4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);

		// grab the ambient light data from the scene
		for (i = 0; i < (unsigned int)lNode->GetChildCount(); ++i)
		{
			gatherBones((void*)lNode->GetChild(i));
		}

		// extract children
		for (i = 0; i < (unsigned int)lNode->GetChildCount(); ++i)
		{
			extractObject(m_root, (void*)lNode->GetChild(i));
		}

		if (m_importAssistor->bones.size() > 0)
		{
			FBXSkeleton* skeleton = new FBXSkeleton();
			skeleton->m_boneCount = (unsigned int)m_importAssistor->bones.size();
			skeleton->m_nodes = new FBXNode * [ skeleton->m_boneCount ];
			skeleton->m_bones = new glm::mat4[ skeleton->m_boneCount ];
			skeleton->m_bindPoses = new glm::mat4[ skeleton->m_boneCount ];
			skeleton->m_parentIndex = new int[ skeleton->m_boneCount ];

			for ( i = 0 ; i < skeleton->m_boneCount ; ++i )
			{
				skeleton->m_nodes[ i ] = m_importAssistor->bones[ i ];
				skeleton->m_bones[ i ] = skeleton->m_nodes[ i ]->m_localTransform;
			}
			for ( i = 0 ; i < skeleton->m_boneCount ; ++i )
			{
				skeleton->m_parentIndex[i] = -1;
				for ( int j = 0 ; j < (int)skeleton->m_boneCount ; ++j )
				{
					if (skeleton->m_nodes[i]->m_parent == skeleton->m_nodes[j])
					{
						skeleton->m_parentIndex[i] = j;
						break;
					}
				}
			}

			extractSkeleton(skeleton, lScene);

			m_skeletons.push_back(skeleton);

			extractAnimation(lScene);
		}

		m_root->updateGlobalTransform();

		delete m_importAssistor;
		m_importAssistor = nullptr;
	}

	lSdkManager->Destroy();

	return true;
}

void FBXFile::extractObject(FBXNode* a_parent, void* a_object)
{
	FbxNode* fbxNode = (FbxNode*)a_object;

	FBXNode* node = nullptr;

	FbxNodeAttribute::EType lAttributeType;
	int i;

	bool bIsBone = false;

	if (fbxNode->GetNodeAttribute() != nullptr)
	{
		lAttributeType = (fbxNode->GetNodeAttribute()->GetAttributeType());

		switch (lAttributeType)
		{
		case FbxNodeAttribute::eSkeleton:
			{
				bIsBone = true;
			}
			break;

		case FbxNodeAttribute::eMesh:
			{
				if (m_importAssistor->loadAnimationOnly == false)
				{
					if (fbxNode->GetMaterialCount() > 1)
					{
						node = new FBXNode();
						extractMeshes(fbxNode,node);
					}
					else
					{
						node = new FBXMeshNode();
						extractMeshes(fbxNode,node);
					}
				}
			}
			break;

		case FbxNodeAttribute::eCamera:
			{
				if (m_importAssistor->loadAnimationOnly == false)
				{
					node = new FBXCameraNode();
					extractCamera((FBXCameraNode*)node,fbxNode);

					node->m_name = fbxNode->GetName();

					m_cameras[node->m_name] = (FBXCameraNode*)node;
				}
			}
			break;

		case FbxNodeAttribute::eLight:
			{
				if (m_importAssistor->loadAnimationOnly == false)
				{
					node = new FBXLightNode();
					extractLight((FBXLightNode*)node,fbxNode);

					node->m_name = fbxNode->GetName();

					m_lights[node->m_name] = (FBXLightNode*)node;
				}
			}
			break;

		default: break;
		}
	}

	// if null then use it as a plain 3D node
	if (node == nullptr)
	{
		node = new FBXNode();
		node->m_name = fbxNode->GetName();
	}

	// add to parent's children and update parent
	a_parent->m_children.push_back(node);
	node->m_parent = a_parent;

	// build local transform
	// use anim evaluator as bones store transforms in a different spot
	FbxAMatrix lLocal = m_importAssistor->evaluator->GetNodeLocalTransform(fbxNode);

	node->m_localTransform = glm::mat4( lLocal[0][0], lLocal[0][1], lLocal[0][2], lLocal[0][3],
										lLocal[1][0], lLocal[1][1], lLocal[1][2], lLocal[1][3],
										lLocal[2][0], lLocal[2][1], lLocal[2][2], lLocal[2][3],
										lLocal[3][0], lLocal[3][1], lLocal[3][2], lLocal[3][3] );

	if (m_importAssistor->loadAnimations == true &&
		bIsBone == true)
	{
		m_importAssistor->bones.push_back(node);
	}

	// children
	for (i = 0; i < fbxNode->GetChildCount(); i++)
	{
		extractObject(node, (void*)fbxNode->GetChild(i));
	}
}

void FBXFile::extractMeshes(void* a_object, void* a_aieNode)
{
	FbxNode* fbxNode = (FbxNode*)a_object;
	FbxMesh* fbxMesh = (FbxMesh*)fbxNode->GetNodeAttribute();

	int i, j, k, l, lPolygonCount = fbxMesh->GetPolygonCount();
	FbxVector4* lControlPoints = fbxMesh->GetControlPoints();
	FbxGeometryElementMaterial* lMaterialElement = fbxMesh->GetElementMaterial(0);

	int materialCount = fbxNode->GetMaterialCount();

	FBXMeshNode** meshes = new FBXMeshNode * [ materialCount ];
	if (materialCount == 1)
		meshes[0] = (FBXMeshNode*)a_aieNode;
	else
		for ( j = 0 ; j < materialCount ; ++j )
		{
			meshes[j] = new FBXMeshNode();
			meshes[j]->m_vertexAttributes = 0;
		}

	unsigned int vertexIndex[4] = {};
	FBXVertex vertexQuad[4];

	unsigned int* nextIndex = new unsigned int[ materialCount ];
	for ( j = 0 ; j < materialCount ; ++j )
		nextIndex[j] = 0;

	FbxGeometryElementVertexColor* fbxColours = fbxMesh->GetElementVertexColor(0);
	FbxGeometryElementUV* fbxTexCoord0 = fbxMesh->GetElementUV(0);
	FbxGeometryElementUV* fbxTexCoord1 = fbxMesh->GetElementUV(1);
	FbxGeometryElementNormal* fbxNormal = fbxMesh->GetElementNormal(0);

	// gather skinning info
	FbxSkin* fbxSkin = (FbxSkin*)fbxMesh->GetDeformer(0, FbxDeformer::eSkin);
	int skinClusterCount = fbxSkin != nullptr ? fbxSkin->GetClusterCount() : 0;
	FbxCluster** skinClusters = nullptr;
	int* skinClusterBoneIndices = nullptr;
	if (skinClusterCount > 0)
	{
		skinClusters = new FbxCluster * [ skinClusterCount ];
		skinClusterBoneIndices = new int[ skinClusterCount ];

		for (i = 0 ; i < skinClusterCount ; ++i)
		{
			skinClusters[i] = fbxSkin->GetCluster(i);
			if (skinClusters[i]->GetLink() == nullptr)
			{
				skinClusterBoneIndices[i] = -1;
			}
			else
			{
				skinClusterBoneIndices[i] = m_importAssistor->boneIndexList[ skinClusters[i]->GetLink()->GetName() ];
			}
		}
	}

	// needed for accessing certain vertex properties
	int vertexId = 0;

	// process each polygon (tris and quads only)
	for (i = 0; i < lPolygonCount; ++i)
	{
		int polygonSize = fbxMesh->GetPolygonSize(i);

		int material = lMaterialElement->GetIndexArray().GetAt(i);

		for (j = 0; j < polygonSize && j < 4 ; ++j)
		{
			FBXVertex vertex;

			int controlPointIndex = fbxMesh->GetPolygonVertex(i, j);

			FbxVector4 vPos = lControlPoints[controlPointIndex];
			vertex.position.x = (float)vPos[0];
			vertex.position.y = (float)vPos[1];
			vertex.position.z = (float)vPos[2];
			vertex.position.w = 1;

			meshes[material]->m_vertexAttributes |= FBXVertex::ePOSITION;

			// extract colour data
			if (fbxColours != nullptr)
			{
				switch (fbxColours->GetMappingMode())
				{
				case FbxGeometryElement::eByControlPoint:
					switch (fbxColours->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
						{
							FbxColor colour = fbxColours->GetDirectArray().GetAt(controlPointIndex);
							meshes[material]->m_vertexAttributes |= FBXVertex::eCOLOUR;

							vertex.colour.x = (float)colour.mRed;
							vertex.colour.y = (float)colour.mGreen;
							vertex.colour.z = (float)colour.mBlue;
							vertex.colour.w = (float)colour.mAlpha;
						}
						break;
					case FbxGeometryElement::eIndexToDirect:
						{
							int id = fbxColours->GetIndexArray().GetAt(controlPointIndex);
							FbxColor colour = fbxColours->GetDirectArray().GetAt(id);
							meshes[material]->m_vertexAttributes |= FBXVertex::eCOLOUR;

							vertex.colour.x = (float)colour.mRed;
							vertex.colour.y = (float)colour.mGreen;
							vertex.colour.z = (float)colour.mBlue;
							vertex.colour.w = (float)colour.mAlpha;
						}
						break;
					default:
						break; // other reference modes not shown here!
					}
					break;

				case FbxGeometryElement::eByPolygonVertex:
					{
						switch (fbxColours->GetReferenceMode())
						{
						case FbxGeometryElement::eDirect:
							{
								FbxColor colour = fbxColours->GetDirectArray().GetAt(vertexId);
								meshes[material]->m_vertexAttributes |= FBXVertex::eCOLOUR;

								vertex.colour.x = (float)colour.mRed;
								vertex.colour.y = (float)colour.mGreen;
								vertex.colour.z = (float)colour.mBlue;
								vertex.colour.w = (float)colour.mAlpha;
							}
							break;
						case FbxGeometryElement::eIndexToDirect:
							{
								int id = fbxColours->GetIndexArray().GetAt(vertexId);
								FbxColor colour = fbxColours->GetDirectArray().GetAt(id);
								meshes[material]->m_vertexAttributes |= FBXVertex::eCOLOUR;

								vertex.colour.x = (float)colour.mRed;
								vertex.colour.y = (float)colour.mGreen;
								vertex.colour.z = (float)colour.mBlue;
								vertex.colour.w = (float)colour.mAlpha;
							}
							break;
						default:
							break; // other reference modes not shown here!
						}
					}
					break;

				case FbxGeometryElement::eByPolygon: // doesn't make much sense for UVs
				case FbxGeometryElement::eAllSame:   // doesn't make much sense for UVs
				case FbxGeometryElement::eNone:       // doesn't make much sense for UVs
					break;
                    default:    break;
				}
			}
			// extract first texture coordinate set
			if (fbxTexCoord0 != nullptr)
			{
				switch (fbxTexCoord0->GetMappingMode())
				{
				case FbxGeometryElement::eByControlPoint:
					switch (fbxTexCoord0->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
						{
							FbxVector2 uv = fbxTexCoord0->GetDirectArray().GetAt(controlPointIndex);
							meshes[material]->m_vertexAttributes |= FBXVertex::eTEXCOORD1;

							vertex.texCoord1.x = (float)uv[0];
							if (m_importAssistor->flipTextureY == true)
								vertex.texCoord1.y = 1.0f - (float)uv[1];
							else
								vertex.texCoord1.y = (float)uv[1];
						}
						break;
					case FbxGeometryElement::eIndexToDirect:
						{
							int id = fbxTexCoord0->GetIndexArray().GetAt(controlPointIndex);
							FbxVector2 uv = fbxTexCoord0->GetDirectArray().GetAt(id);
							meshes[material]->m_vertexAttributes |= FBXVertex::eTEXCOORD1;

							vertex.texCoord1.x = (float)uv[0];
							if (m_importAssistor->flipTextureY == true)
								vertex.texCoord1.y = 1.0f - (float)uv[1];
							else
								vertex.texCoord1.y = (float)uv[1];
						}
						break;
					default:
						break; // other reference modes not shown here!
					}
					break;

				case FbxGeometryElement::eByPolygonVertex:
					{
						int lTextureUVIndex = fbxMesh->GetTextureUVIndex(i, j);
						switch (fbxTexCoord0->GetReferenceMode())
						{
						case FbxGeometryElement::eDirect:
						case FbxGeometryElement::eIndexToDirect:
							{
								FbxVector2 uv = fbxTexCoord0->GetDirectArray().GetAt(lTextureUVIndex);
								meshes[material]->m_vertexAttributes |= FBXVertex::eTEXCOORD1;

								vertex.texCoord1.x = (float)uv[0];
								if (m_importAssistor->flipTextureY == true)
									vertex.texCoord1.y = 1.0f - (float)uv[1];
								else
									vertex.texCoord1.y = (float)uv[1];
							}
							break;
						default:
							break; // other reference modes not shown here!
						}
					}
					break;

				case FbxGeometryElement::eByPolygon: // doesn't make much sense for UVs
				case FbxGeometryElement::eAllSame:   // doesn't make much sense for UVs
				case FbxGeometryElement::eNone:       // doesn't make much sense for UVs
					break;
                default: break;
				}
			}

			// extract second coordinate set
			if (fbxTexCoord1 != nullptr)
			{
				switch (fbxTexCoord1->GetMappingMode())
				{
				case FbxGeometryElement::eByControlPoint:
					switch (fbxTexCoord1->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
						{
							FbxVector2 uv = fbxTexCoord1->GetDirectArray().GetAt(controlPointIndex);
							meshes[material]->m_vertexAttributes |= FBXVertex::eTEXCOORD2;

							vertex.texCoord2.x = (float)uv[0];
							if (m_importAssistor->flipTextureY == true)
								vertex.texCoord2.y = 1.0f - (float)uv[1];
							else
								vertex.texCoord2.y = (float)uv[1];
						}
						break;
					case FbxGeometryElement::eIndexToDirect:
						{
							int id = fbxTexCoord1->GetIndexArray().GetAt(controlPointIndex);
							FbxVector2 uv = fbxTexCoord1->GetDirectArray().GetAt(id);
							meshes[material]->m_vertexAttributes |= FBXVertex::eTEXCOORD2;

							vertex.texCoord2.x = (float)uv[0];
							if (m_importAssistor->flipTextureY == true)
								vertex.texCoord2.y = 1.0f - (float)uv[1];
							else
								vertex.texCoord2.y = (float)uv[1];
						}
						break;
					default:
						break; // other reference modes not shown here!
					}
					break;

				case FbxGeometryElement::eByPolygonVertex:
					{
						int lTextureUVIndex = fbxMesh->GetTextureUVIndex(i, j);
						switch (fbxTexCoord1->GetReferenceMode())
						{
						case FbxGeometryElement::eDirect:
						case FbxGeometryElement::eIndexToDirect:
							{
								FbxVector2 uv = fbxTexCoord1->GetDirectArray().GetAt(lTextureUVIndex);
								meshes[material]->m_vertexAttributes |= FBXVertex::eTEXCOORD2;

								vertex.texCoord2.x = (float)uv[0];
								if (m_importAssistor->flipTextureY == true)
									vertex.texCoord2.y = 1.0f - (float)uv[1];
								else
									vertex.texCoord2.y = (float)uv[1];
							}
							break;
						default:
							break; // other reference modes not shown here!
						}
					}
					break;

				case FbxGeometryElement::eByPolygon: // doesn't make much sense for UVs
				case FbxGeometryElement::eAllSame:   // doesn't make much sense for UVs
				case FbxGeometryElement::eNone:       // doesn't make much sense for UVs
					break;
                    default:    break;
				}
			}

			// extract normal data
			if (fbxNormal != nullptr)
			{
				if (fbxNormal->GetMappingMode() == FbxGeometryElement::eByControlPoint)
				{
					switch (fbxNormal->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
						{
							FbxVector4 normal = fbxNormal->GetDirectArray().GetAt(controlPointIndex);
							meshes[material]->m_vertexAttributes |= FBXVertex::eNORMAL;

							vertex.normal.x = (float)normal[0];
							vertex.normal.y = (float)normal[1];
							vertex.normal.z = (float)normal[2];
							vertex.normal.w = 0;
						}
						break;
					case FbxGeometryElement::eIndexToDirect:
						{
							int id = fbxNormal->GetIndexArray().GetAt(controlPointIndex);
							FbxVector4 normal = fbxNormal->GetDirectArray().GetAt(id);
							meshes[material]->m_vertexAttributes |= FBXVertex::eNORMAL;

							vertex.normal.x = (float)normal[0];
							vertex.normal.y = (float)normal[1];
							vertex.normal.z = (float)normal[2];
							vertex.normal.w = 0;
						}
						break;
					default:
						break; // other reference modes not shown here!
					}
				}
				else if(fbxNormal->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)
				{
					switch (fbxNormal->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
						{
							FbxVector4 normal = fbxNormal->GetDirectArray().GetAt(vertexId);
							meshes[material]->m_vertexAttributes |= FBXVertex::eNORMAL;

							vertex.normal.x = (float)normal[0];
							vertex.normal.y = (float)normal[1];
							vertex.normal.z = (float)normal[2];
							vertex.normal.w = 0;
						}
						break;
					case FbxGeometryElement::eIndexToDirect:
						{
							int id = fbxNormal->GetIndexArray().GetAt(vertexId);
							FbxVector4 normal = fbxNormal->GetDirectArray().GetAt(id);
							meshes[material]->m_vertexAttributes |= FBXVertex::eNORMAL;

							vertex.normal.x = (float)normal[0];
							vertex.normal.y = (float)normal[1];
							vertex.normal.z = (float)normal[2];
							vertex.normal.w = 0;
						}
						break;
					default:
						break; // other reference modes not shown here!
					}
				}
			}

			// gather skinning data (slow but can't find any other way, yet!)
			if (fbxSkin != nullptr)
			{
				for (k = 0; k != skinClusterCount; ++k)
				{
					if (skinClusterBoneIndices[k] == -1)
						continue;

					int lIndexCount = skinClusters[k]->GetControlPointIndicesCount();
					int* lIndices = skinClusters[k]->GetControlPointIndices();
					double* lWeights = skinClusters[k]->GetControlPointWeights();

					for (l = 0; l < lIndexCount; l++)
					{
						if (controlPointIndex == lIndices[l])
						{
							// add weight and index
							if (vertex.weights.x == 0)
							{
								vertex.weights.x = (float)lWeights[l];
								vertex.indices.x = (float)skinClusterBoneIndices[k];
							}
							else if (vertex.weights.y == 0)
							{
								vertex.weights.y = (float)lWeights[l];
								vertex.indices.y = (float)skinClusterBoneIndices[k];
							}
							else if (vertex.weights.z == 0)
							{
								vertex.weights.z = (float)lWeights[l];
								vertex.indices.z = (float)skinClusterBoneIndices[k];
							}
							else
							{
								vertex.weights.w = (float)lWeights[l];
								vertex.indices.w = (float)skinClusterBoneIndices[k];
							}
						}
					}
				}
			}

			vertex.index[0] = nextIndex[material]++;
			vertexQuad[j] = vertex;
			meshes[material]->m_vertices.push_back(vertex);
			vertexId++;
		}

		// add triangle indices
		meshes[material]->m_indices.push_back(vertexQuad[0].index[0]);
		meshes[material]->m_indices.push_back(vertexQuad[1].index[0]);
		meshes[material]->m_indices.push_back(vertexQuad[2].index[0]);

		// handle quads
		if (polygonSize == 4)
		{
			meshes[material]->m_indices.push_back(vertexQuad[3].index[0]);

			vertexQuad[0].index[0] = nextIndex[material]++;
			meshes[material]->m_vertices.push_back(vertexQuad[0]);
			meshes[material]->m_indices.push_back(vertexQuad[0].index[0]);

			vertexQuad[2].index[0] = nextIndex[material]++;
			meshes[material]->m_vertices.push_back(vertexQuad[2]);
			meshes[material]->m_indices.push_back(vertexQuad[2].index[0]);
		}
	}

	for (int i = 0 ; i < materialCount ; ++i )
		m_threads.push_back( new std::thread( optimiseMesh, meshes[i] ) );

	// set mesh names, vertex attributes, extract material and add to mesh map
	for ( j = 0 ; j < materialCount ; ++j )
	{
		meshes[j]->m_name = fbxNode->GetName();

		// append material name to mesh name
		if (materialCount > 1)
			meshes[j]->m_name += fbxNode->GetMaterial(j)->GetName();

		meshes[j]->m_material = extractMaterial(fbxMesh,j);
		m_meshes.push_back(meshes[j]);
	}

	// if there is a single mesh return it, else make a new parent node and return that
	if (materialCount > 1)
	{
		FBXNode* node = (FBXNode*)a_aieNode;
		node->m_name = fbxNode->GetName();
		for ( j = 0 ; j < materialCount ; ++j )
		{
			node->m_children.push_back( meshes[j] );
			meshes[j]->m_parent = node;
		}
	}

	delete[] skinClusters;
	delete[] skinClusterBoneIndices;

	delete[] meshes;
	delete[] nextIndex;
}

void FBXFile::optimiseMesh(FBXMeshNode* a_mesh)
{
	//sort the vertex array so all common verts are adjacent in the array
	std::sort(a_mesh->m_vertices.begin(), a_mesh->m_vertices.end());

	unsigned int forward_iter = 1;
	int j = 0;

	while ( forward_iter < a_mesh->m_vertices.size() )
	{
		if ( a_mesh->m_vertices[j] == a_mesh->m_vertices[forward_iter] )
		{
			// if the adjacent verts are equal make all the duplicate vert's indicies point at the first one in the vector
			a_mesh->m_indices[a_mesh->m_vertices[forward_iter].index[0]] = j;
			++forward_iter;
		}
		else
		{
			// if they aren't duplicates, update the index to point at the vert's post sort position in the vector
			a_mesh->m_indices[a_mesh->m_vertices[j].index[0]] = j;
			++j;
			// then push the current forward iterator back
			// not sure if checking if j != forward pointer would be faster here.
			a_mesh->m_vertices[j] = a_mesh->m_vertices[forward_iter];
			a_mesh->m_indices[a_mesh->m_vertices[forward_iter].index[0]] = j;
			++forward_iter;
		}
	}
	a_mesh->m_vertices.resize(j+1);

	if ((a_mesh->m_vertexAttributes & FBXVertex::eTEXCOORD1) != 0)
	{
		a_mesh->m_vertexAttributes |= FBXVertex::eTANGENT|FBXVertex::eBINORMAL;
		calculateTangentsBinormals(a_mesh->m_vertices,a_mesh->m_indices);
	}
}

void FBXFile::extractLight(FBXLightNode* a_light, void* a_object)
{
	FbxNode* fbxNode = (FbxNode*)a_object;
	FbxLight* fbxLight = (FbxLight*)fbxNode->GetNodeAttribute();

	// get type, if on, and colour
	a_light->m_type = (FBXLightNode::LightType)fbxLight->LightType.Get();
	a_light->m_on = fbxLight->CastLight.Get();
	a_light->m_colour.x = (float)fbxLight->Color.Get()[0];
	a_light->m_colour.y = (float)fbxLight->Color.Get()[1];
	a_light->m_colour.z = (float)fbxLight->Color.Get()[2];
	a_light->m_colour.w = (float)fbxLight->Intensity.Get();

	// get spot light angles (will return data even for non-spotlights)
	a_light->m_innerAngle = (float)fbxLight->InnerAngle.Get() * (glm::pi<float>() / 180);
	a_light->m_outerAngle = (float)fbxLight->OuterAngle.Get() * (glm::pi<float>() / 180);

	// get falloff data (none,linear, quadratic), cubic is ignored
	switch (fbxLight->DecayType.Get())
	{
	case 0:
		a_light->m_attenuation = glm::vec4(1,0,0,0);
		break;
	case 1:
		break;
		a_light->m_attenuation = glm::vec4(0,1,0,0);
	case 2:
		break;
		a_light->m_attenuation = glm::vec4(0,0,1,0);
	default:
		break;
	};
}

void FBXFile::extractCamera(FBXCameraNode* a_camera, void* a_object)
{
	FbxNode* fbxNode = (FbxNode*)a_object;
	FbxCamera* fbxCamera = (FbxCamera*)fbxNode->GetNodeAttribute();

	// get field of view
	if (fbxCamera->ProjectionType.Get() != FbxCamera::eOrthogonal)
	{
		a_camera->m_fieldOfView = (float)fbxCamera->FieldOfView.Get() * (glm::pi<float>() / 180);
	}
	else
	{
		a_camera->m_fieldOfView = 0;
	}

	// get aspect ratio if one was defined
	if (fbxCamera->GetAspectRatioMode() != FbxCamera::eWindowSize)
	{
		a_camera->m_aspectRatio = (float)fbxCamera->AspectWidth.Get() / (float)fbxCamera->AspectHeight.Get();
	}
	else
	{
		a_camera->m_aspectRatio = 0;
	}

	// get near/far
	a_camera->m_near = (float)fbxCamera->NearPlane.Get();
	a_camera->m_far = (float)fbxCamera->FarPlane.Get();

	// build view matrix
	glm::vec3 vEye, vTo, vUp;

	vEye.x = (float)fbxCamera->Position.Get()[0];
	vEye.y = (float)fbxCamera->Position.Get()[1];
	vEye.z = (float)fbxCamera->Position.Get()[2];

	if (fbxNode->GetTarget() != nullptr)
	{
		vTo.x = (float)fbxNode->GetTarget()->LclTranslation.Get()[0];
		vTo.y = (float)fbxNode->GetTarget()->LclTranslation.Get()[1];
		vTo.z = (float)fbxNode->GetTarget()->LclTranslation.Get()[2];
	}
	else
	{
		vTo.x = (float)fbxCamera->InterestPosition.Get()[0];
		vTo.y = (float)fbxCamera->InterestPosition.Get()[1];
		vTo.z = (float)fbxCamera->InterestPosition.Get()[2];
	}

	if (fbxNode->GetTargetUp())
	{
		vUp.x = (float)fbxNode->GetTargetUp()->LclTranslation.Get()[0];
		vUp.y = (float)fbxNode->GetTargetUp()->LclTranslation.Get()[1];
		vUp.z = (float)fbxNode->GetTargetUp()->LclTranslation.Get()[2];

	}
	else
	{
		vUp.x = (float)fbxCamera->UpVector.Get()[0];
		vUp.y = (float)fbxCamera->UpVector.Get()[1];
		vUp.z = (float)fbxCamera->UpVector.Get()[2];
	}

	a_camera->m_viewMatrix = glm::lookAt(vEye,vTo,vUp);
}

FBXMaterial* FBXFile::extractMaterial(void* a_mesh, int a_materialIndex)
{
	FbxGeometry* pGeometry = (FbxGeometry*)a_mesh;
	FbxNode* lNode = pGeometry->GetNode();
	FbxSurfaceMaterial *lMaterial = lNode->GetMaterial(a_materialIndex);

	// check if material already loaded, else create new material
	m_materialMutex.lock();
	auto oIter = m_materials.find( lMaterial->GetName() );
	if (oIter != m_materials.end())
	{
		m_materialMutex.unlock();
		return oIter->second;
	}
	else
	{
		FBXMaterial* material = new FBXMaterial;
		material->name = lMaterial->GetName();

		// get the implementation to see if it's a hardware shader.
		const FbxImplementation* lImplementation = GetImplementation(lMaterial, FBXSDK_IMPLEMENTATION_HLSL);
		if (lImplementation == nullptr)
		{
			lImplementation = GetImplementation(lMaterial, FBXSDK_IMPLEMENTATION_CGFX);
		}
		if (lImplementation != nullptr)
		{
			FbxBindingTable const* lRootTable = lImplementation->GetRootTable();
			FbxString lFileName = lRootTable->DescAbsoluteURL.Get();
			FbxString lTechniqueName = lRootTable->DescTAG.Get();

			printf("Unsupported hardware shader material!\n");
			printf("\tFile: %s\n",lFileName.Buffer());
			printf("\tTechnique: %s\n\n",lTechniqueName.Buffer());
		}
		else if (lMaterial->GetClassId().Is(FbxSurfacePhong::ClassId))
		{
			// We found a Phong material
			FbxSurfacePhong* pPhong = (FbxSurfacePhong*)lMaterial;

			material->ambient.x = (float)pPhong->Ambient.Get()[0];
			material->ambient.y = (float)pPhong->Ambient.Get()[1];
			material->ambient.z = (float)pPhong->Ambient.Get()[2];
			material->ambient.w = (float)pPhong->AmbientFactor.Get();

			material->diffuse.x = (float)pPhong->Diffuse.Get()[0];
			material->diffuse.y = (float)pPhong->Diffuse.Get()[1];
			material->diffuse.z = (float)pPhong->Diffuse.Get()[2];
			material->diffuse.w = (float)pPhong->TransparencyFactor.Get();

			material->specular.x = (float)pPhong->Specular.Get()[0];
			material->specular.y = (float)pPhong->Specular.Get()[1];
			material->specular.z = (float)pPhong->Specular.Get()[2];
			material->specular.w = (float)pPhong->Shininess.Get();

			material->emissive.x = (float)pPhong->Emissive.Get()[0];
			material->emissive.y = (float)pPhong->Emissive.Get()[1];
			material->emissive.z = (float)pPhong->Emissive.Get()[2];
			material->emissive.w = (float)pPhong->EmissiveFactor.Get();
		}
		else if(lMaterial->GetClassId().Is(FbxSurfaceLambert::ClassId) )
		{
			FbxSurfaceLambert* pLambert = (FbxSurfaceLambert*)lMaterial;

			material->ambient.x = (float)pLambert->Ambient.Get()[0];
			material->ambient.y = (float)pLambert->Ambient.Get()[1];
			material->ambient.z = (float)pLambert->Ambient.Get()[2];
			material->ambient.w = (float)pLambert->AmbientFactor.Get();

			material->diffuse.x = (float)pLambert->Diffuse.Get()[0];
			material->diffuse.y = (float)pLambert->Diffuse.Get()[1];
			material->diffuse.z = (float)pLambert->Diffuse.Get()[2];
			material->diffuse.w = (float)pLambert->TransparencyFactor.Get();

			// No specular in lambert materials
			material->specular.x = 0;
			material->specular.y = 0;
			material->specular.z = 0;
			material->specular.w = 0;

			material->emissive.x = (float)pLambert->Emissive.Get()[0];
			material->emissive.y = (float)pLambert->Emissive.Get()[1];
			material->emissive.z = (float)pLambert->Emissive.Get()[2];
			material->emissive.w = (float)pLambert->EmissiveFactor.Get();
		}
		else
		{
			printf("Unknown type of Material: %s\n", lMaterial->GetClassId().GetName());
		}

		unsigned int auiTextureLookup[] =
		{
			FbxLayerElement::eTextureDiffuse - FbxLayerElement::sTypeTextureStartIndex,
			FbxLayerElement::eTextureAmbient - FbxLayerElement::sTypeTextureStartIndex,
			FbxLayerElement::eTextureEmissive - FbxLayerElement::sTypeTextureStartIndex,
			FbxLayerElement::eTextureSpecular - FbxLayerElement::sTypeTextureStartIndex,
			FbxLayerElement::eTextureShininess - FbxLayerElement::sTypeTextureStartIndex,
			FbxLayerElement::eTextureNormalMap - FbxLayerElement::sTypeTextureStartIndex,
			FbxLayerElement::eTextureTransparency - FbxLayerElement::sTypeTextureStartIndex,
			FbxLayerElement::eTextureDisplacement - FbxLayerElement::sTypeTextureStartIndex,
		};

		if (m_importAssistor->loadTextures == true)
		{
			for ( unsigned int i = 0 ; i < FBXMaterial::TextureTypes_Count ; ++i )
			{
				FbxProperty pProperty = lMaterial->FindProperty(FbxLayerElement::sTextureChannelNames[auiTextureLookup[i]]);
				if ( pProperty.IsValid() &&
					pProperty.GetSrcObjectCount<FbxTexture>() > 0)
				{
					FbxFileTexture* fileTexture = FbxCast<FbxFileTexture>(pProperty.GetSrcObject<FbxTexture>(0));
					if (fileTexture != nullptr)
					{
						const char* szLastForward = strrchr(fileTexture->GetFileName(),'/');
						const char* szLastBackward = strrchr(fileTexture->GetFileName(),'\\');
						const char* szFilename = fileTexture->GetFileName();

						material->textureRotation[i] = (float)fileTexture->GetRotationW();
						material->textureTiling[i].x = (float)fileTexture->GetScaleU();
						material->textureTiling[i].y = (float)fileTexture->GetScaleV();
						material->textureOffsets[i].x = (float)fileTexture->GetTranslationU();
						material->textureOffsets[i].y = (float)fileTexture->GetTranslationV();

						if (szLastForward != nullptr && szLastForward > szLastBackward)
							szFilename = szLastForward + 1;
						else if (szLastBackward != nullptr)
							szFilename = szLastBackward + 1;

						std::string fullPath = m_path + szFilename;

						auto iter = m_textures.find(fullPath);
						if (iter != m_textures.end())
						{
							material->textures[i] = iter->second;
						}
						else
						{
							FBXTexture* texture = new FBXTexture();
							texture->name = szFilename;
							texture->path = fullPath;
							material->textures[i] = texture;
							m_textures[ fullPath ] = texture;
						}
					}
				}
			}
		}

		m_materials[material->name] = material;
		m_materialMutex.unlock();
		return material;
	}

	m_materialMutex.unlock();
	return nullptr;
}

void FBXFile::initialiseOpenGLTextures()
{
	for (auto texture : m_textures)
	{
	//	texture.second->handle = SOIL_create_OGL_texture(texture.second->data, texture.second->width, texture.second->height, texture.second->channels,
	//		SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_TEXTURE_REPEATS);
		switch (texture.second->format)
		{
		case STBI_grey: texture.second->format = GL_RED; break;
		case STBI_grey_alpha: texture.second->format = GL_RG; break;
		case STBI_rgb: texture.second->format = GL_RGB; break;
		case STBI_rgb_alpha: texture.second->format = GL_RGBA; break;
		};

		glGenTextures(1, &texture.second->handle);
		glBindTexture(GL_TEXTURE_2D, texture.second->handle);
		glTexImage2D(GL_TEXTURE_2D, 0, texture.second->format, texture.second->width, texture.second->height, 0, texture.second->format, GL_UNSIGNED_BYTE, texture.second->data);
	//	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	//	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glGenerateMipmap(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, 0);
	}
}

void FBXFile::extractAnimation(void* a_scene)
{
	FbxScene* fbxScene = (FbxScene*)a_scene;

	int animStackCount = fbxScene->GetSrcObjectCount<FbxAnimStack>();

	std::vector<int> tracks;
	std::vector<void*> nodes;
	tracks.reserve(128);
	nodes.reserve(128);

	FbxTime frameTime;

	for (int i = 0; i < animStackCount; i++)
	{
		tracks.clear();
		nodes.clear();

		FbxAnimStack* lAnimStack = fbxScene->GetSrcObject<FbxAnimStack>(i);

		FBXAnimation* anim = new FBXAnimation();
		anim->m_name = lAnimStack->GetName();

		// get animated track bone indices and nodes, and calculate start/end frame
		int nbAnimLayers = lAnimStack->GetMemberCount(FbxCriteria::ObjectType(FbxAnimLayer::ClassId));
		for (int j = 0; j < nbAnimLayers; ++j)
		{
			FbxAnimLayer* lAnimLayer = lAnimStack->GetMember<FbxAnimLayer>(j);
			extractAnimationTrack(tracks, lAnimLayer, fbxScene->GetRootNode(), nodes, anim->m_startFrame, anim->m_endFrame);
		}

		// frame count (includes start/end frames)
		unsigned int frameCount = anim->m_endFrame - anim->m_startFrame + 1;

		// allocate tracks and keyframes
		anim->m_trackCount = (unsigned int)tracks.size();
		anim->m_tracks = new FBXTrack[ anim->m_trackCount ];
		for (unsigned int track = 0 ; track < anim->m_trackCount ; ++track )
		{
			anim->m_tracks[track].m_boneIndex = tracks[track];
			anim->m_tracks[track].m_keyframeCount = frameCount;
			anim->m_tracks[track].m_keyframes = new FBXKeyFrame[ frameCount ];
		}

		// evaluate all of the animated track keyframes
		// loop by frame first to limit FBX time changes (dreadfully slow!)
		for ( unsigned int frame = 0 ; frame < frameCount ; ++frame )
		{
			frameTime.SetFrame(frame + anim->m_startFrame);

			for (unsigned int track = 0 ; track < anim->m_trackCount ; ++track )
			{
				FbxAMatrix localMatrix = m_importAssistor->evaluator->GetNodeLocalTransform( (FbxNode*)nodes[ track ], frameTime );

				FbxQuaternion R = localMatrix.GetQ();
				FbxVector4 T = localMatrix.GetT();
				FbxVector4 S = localMatrix.GetS();

				anim->m_tracks[track].m_keyframes[ frame ].m_key = frame + anim->m_startFrame;
				anim->m_tracks[track].m_keyframes[ frame ].m_rotation = glm::quat((float)R[3],(float)R[0],(float)R[1],(float)R[2]);
				anim->m_tracks[track].m_keyframes[ frame ].m_translation = glm::vec3((float)T[0],(float)T[1],(float)T[2]);
				anim->m_tracks[track].m_keyframes[ frame ].m_scale = glm::vec3((float)S[0],(float)S[1],(float)S[2]);
			}
		}

		m_animations[ anim->m_name ] = anim;
	}
}

void FBXFile::extractAnimationTrack(std::vector<int>& a_tracks, void* a_layer, void* a_node, std::vector<void*>& a_nodes, unsigned int& a_startFrame, unsigned int& a_endFrame)
{
	FbxAnimLayer* fbxAnimLayer = (FbxAnimLayer*)a_layer;
	FbxNode* fbxNode = (FbxNode*)a_node;

	// find node index in skeleton
	int boneIndex = -1;
	FBXSkeleton* skeleton = m_skeletons[0];
	for ( unsigned int i = 0 ; i < skeleton->m_boneCount ; ++i )
	{
		if (skeleton->m_nodes[i]->m_name == fbxNode->GetName())
		{
			boneIndex = i;
			break;
		}
	}

	// extract bones that have animated properties on them only
	bool hasKeys = false;
	FbxAnimCurve* lAnimCurve = nullptr;
	if (boneIndex >= 0)
	{
		// translation
		lAnimCurve = fbxNode->LclTranslation.GetCurve(fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_X);
		if (lAnimCurve)
		{
			hasKeys = true;

			unsigned int frame = (unsigned int)lAnimCurve->KeyGetTime(0).GetFrameCount();
			if (frame < a_startFrame)
				a_startFrame = frame;

			frame = (unsigned int)lAnimCurve->KeyGetTime(lAnimCurve->KeyGetCount()-1).GetFrameCount();
			if (frame > a_endFrame)
				a_endFrame = frame;
		}
		lAnimCurve = fbxNode->LclTranslation.GetCurve(fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y);
		if (lAnimCurve)
		{
			hasKeys = true;

			unsigned int frame = (unsigned int)lAnimCurve->KeyGetTime(0).GetFrameCount();
			if (frame < a_startFrame)
				a_startFrame = frame;

			frame = (unsigned int)lAnimCurve->KeyGetTime(lAnimCurve->KeyGetCount()-1).GetFrameCount();
			if (frame > a_endFrame)
				a_endFrame = frame;

		}
		lAnimCurve = fbxNode->LclTranslation.GetCurve(fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z);
		if (lAnimCurve)
		{
			hasKeys = true;

			unsigned int frame = (unsigned int)lAnimCurve->KeyGetTime(0).GetFrameCount();
			if (frame < a_startFrame)
				a_startFrame = frame;

			frame = (unsigned int)lAnimCurve->KeyGetTime(lAnimCurve->KeyGetCount()-1).GetFrameCount();
			if (frame > a_endFrame)
				a_endFrame = frame;

		}

		// rotation
		lAnimCurve = fbxNode->LclRotation.GetCurve(fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_X);
		if (lAnimCurve)
		{
			hasKeys = true;

			unsigned int frame = (unsigned int)lAnimCurve->KeyGetTime(0).GetFrameCount();
			if (frame < a_startFrame)
				a_startFrame = frame;

			frame = (unsigned int)lAnimCurve->KeyGetTime(lAnimCurve->KeyGetCount()-1).GetFrameCount();
			if (frame > a_endFrame)
				a_endFrame = frame;

		}
		lAnimCurve = fbxNode->LclRotation.GetCurve(fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y);
		if (lAnimCurve)
		{
			hasKeys = true;

			unsigned int frame = (unsigned int)lAnimCurve->KeyGetTime(0).GetFrameCount();
			if (frame < a_startFrame)
				a_startFrame = frame;

			frame = (unsigned int)lAnimCurve->KeyGetTime(lAnimCurve->KeyGetCount()-1).GetFrameCount();
			if (frame > a_endFrame)
				a_endFrame = frame;

		}
		lAnimCurve = fbxNode->LclRotation.GetCurve(fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z);
		if (lAnimCurve)
		{
			hasKeys = true;

			unsigned int frame = (unsigned int)lAnimCurve->KeyGetTime(0).GetFrameCount();
			if (frame < a_startFrame)
				a_startFrame = frame;

			frame = (unsigned int)lAnimCurve->KeyGetTime(lAnimCurve->KeyGetCount()-1).GetFrameCount();
			if (frame > a_endFrame)
				a_endFrame = frame;

		}

		// scale
		lAnimCurve = fbxNode->LclScaling.GetCurve(fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_X);
		if (lAnimCurve)
		{
			hasKeys = true;

			unsigned int frame = (unsigned int)lAnimCurve->KeyGetTime(0).GetFrameCount();
			if (frame < a_startFrame)
				a_startFrame = frame;

			frame = (unsigned int)lAnimCurve->KeyGetTime(lAnimCurve->KeyGetCount()-1).GetFrameCount();
			if (frame > a_endFrame)
				a_endFrame = frame;

		}
		lAnimCurve = fbxNode->LclScaling.GetCurve(fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y);
		if (lAnimCurve)
		{
			hasKeys = true;

			unsigned int frame = (unsigned int)lAnimCurve->KeyGetTime(0).GetFrameCount();
			if (frame < a_startFrame)
				a_startFrame = frame;

			frame = (unsigned int)lAnimCurve->KeyGetTime(lAnimCurve->KeyGetCount()-1).GetFrameCount();
			if (frame > a_endFrame)
				a_endFrame = frame;

		}
		lAnimCurve = fbxNode->LclScaling.GetCurve(fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z);
		if (lAnimCurve)
		{
			hasKeys = true;

			unsigned int frame = (unsigned int)lAnimCurve->KeyGetTime(0).GetFrameCount();
			if (frame < a_startFrame)
				a_startFrame = frame;

			frame = (unsigned int)lAnimCurve->KeyGetTime(lAnimCurve->KeyGetCount()-1).GetFrameCount();
			if (frame > a_endFrame)
				a_endFrame = frame;
		}

		if (hasKeys)
		{
			a_nodes.push_back(fbxNode);
			a_tracks.push_back(boneIndex);
		}
	}

	for (int i = 0; i < fbxNode->GetChildCount(); ++i)
	{
		extractAnimationTrack(a_tracks, fbxAnimLayer, fbxNode->GetChild(i), a_nodes, a_startFrame, a_endFrame);
	}
}

void FBXFile::extractSkeleton(FBXSkeleton* a_skeleton, void* a_scene)
{
	FbxScene* fbxScene = (FbxScene*)a_scene;

	int poseCount = fbxScene->GetPoseCount();

	for (int i = 0; i < poseCount; ++i)
	{
		FbxPose* lPose = fbxScene->GetPose(i);

		for ( int j = 0 ; j < lPose->GetCount() ; ++j )
		{
			float scaleFactor = m_importAssistor->unitScale;

			FbxMatrix scale(scaleFactor,0,0,0,
							0,scaleFactor,0,0,
							0,0,scaleFactor,0,
							0,0,0,1);

			FbxMatrix lMatrix = lPose->GetMatrix(j);
			FbxMatrix lBindMatrix = lMatrix.Inverse() * scale;

			for ( unsigned int k = 0 ; k < a_skeleton->m_boneCount ; ++k )
			{
				if (a_skeleton->m_nodes[k]->m_name == lPose->GetNodeName(j).GetCurrentName())
				{
					FbxVector4 row0 = lBindMatrix.GetRow(0);
					FbxVector4 row1 = lBindMatrix.GetRow(1);
					FbxVector4 row2 = lBindMatrix.GetRow(2);
					FbxVector4 row3 = lBindMatrix.GetRow(3);

					a_skeleton->m_bindPoses[ k ][0] = glm::vec4( (float)row0[0], (float)row0[1], (float)row0[2], (float)row0[3] );
					a_skeleton->m_bindPoses[ k ][1] = glm::vec4( (float)row1[0], (float)row1[1], (float)row1[2], (float)row1[3] );
					a_skeleton->m_bindPoses[ k ][2] = glm::vec4( (float)row2[0], (float)row2[1], (float)row2[2], (float)row2[3] );
					a_skeleton->m_bindPoses[ k ][3] = glm::vec4( (float)row3[0], (float)row3[1], (float)row3[2], (float)row3[3] );
				}
			}
		}
	}
}

void FBXSkeleton::evaluate(const FBXAnimation* a_animation, float a_time, bool a_loop, float a_FPS)
{
	if (a_animation != nullptr)
	{
		// determine frame we're on
		int totalFrames = a_animation->m_endFrame - a_animation->m_startFrame;
		float animDuration = totalFrames / a_FPS;

		// get time through frame
		float frameTime = 0;
		if (a_loop)
			frameTime = glm::max(glm::mod(a_time,animDuration),0.0f);
		else
			frameTime = glm::min(glm::max(a_time,0.0f),animDuration);

		const FBXTrack* track = nullptr;
		const FBXKeyFrame* start = nullptr;
		const FBXKeyFrame* end = nullptr;

		for ( unsigned int i = 0 ; i < a_animation->m_trackCount ; ++i )
		{
			track = &(a_animation->m_tracks[i]);

			start = nullptr;
			end = nullptr;
			float startTime, endTime;

			// determine the two keyframes we're between
			for ( unsigned int j = 0 ; j < track->m_keyframeCount - 1 ; ++j )
			{
				startTime = (track->m_keyframes[j].m_key - a_animation->m_startFrame) / a_FPS;
				endTime = (track->m_keyframes[j + 1].m_key - a_animation->m_startFrame) / a_FPS;

				if (startTime <= frameTime &&
					endTime >= frameTime)
				{
					// found?
					start = &(track->m_keyframes[j]);
					end = &(track->m_keyframes[j+1]);
					break;
				}
			}

			// interpolate between them
			if (start != nullptr &&
				end != nullptr)
			{
				float fScale = glm::max(0.0f,glm::min(1.0f,(frameTime - startTime) / (endTime - startTime)));

				// translation
				glm::vec3 T = glm::mix(start->m_translation,end->m_translation,fScale);

				// scale
				glm::vec3 S = glm::mix(start->m_scale,end->m_scale,fScale);

				// rotation (quaternion slerp)
				glm::quat R = glm::normalize(glm::slerp(start->m_rotation,end->m_rotation,fScale));

				// build matrix
				glm::mat4 mRot = glm::mat4_cast( R );
				glm::mat4 mScale = glm::scale( S );
				glm::mat4 mTranslate = glm::translate( T );
				m_nodes[ track->m_boneIndex ]->m_localTransform = mTranslate * mScale * mRot;
			}
		}
	}
}

void FBXSkeleton::updateBones()
{
	// update bones
	for ( int i = 0 ; i < (int)m_boneCount ; ++i )
	{
		if ( m_parentIndex[i] == -1 )
			m_bones[ i ] = m_nodes[ i ]->m_localTransform;
		else
			m_bones[i] = m_bones[ m_parentIndex[ i ] ] * m_nodes[ i ]->m_localTransform;
	}
	// combine bind pose
	for ( int i = 0 ; i < (int)m_boneCount ; ++i )
	{
		m_bones[ i ] = m_bones[ i ] * m_bindPoses[ i ];
	}
}

void FBXFile::calculateTangentsBinormals(std::vector<FBXVertex>& a_vertices, const std::vector<unsigned int>& a_indices)
{
	unsigned int vertexCount = (unsigned int)a_vertices.size();
	glm::vec3* tan1 = new glm::vec3[vertexCount * 2];
	glm::vec3* tan2 = tan1 + vertexCount;
	memset(tan1, 0, vertexCount * sizeof(glm::vec3) * 2);

	unsigned int indexCount = (unsigned int)a_indices.size();
	for (unsigned int a = 0; a < indexCount; a += 3)
	{
		unsigned int i1 = a_indices[a];
		unsigned int i2 = a_indices[a + 1];
		unsigned int i3 = a_indices[a + 2];

		const glm::vec4& v1 = a_vertices[i1].position;
		const glm::vec4& v2 = a_vertices[i2].position;
		const glm::vec4& v3 = a_vertices[i3].position;

		const glm::vec2& w1 = a_vertices[i1].texCoord1;
		const glm::vec2& w2 = a_vertices[i2].texCoord1;
		const glm::vec2& w3 = a_vertices[i3].texCoord1;

		float x1 = v2.x - v1.x;
		float x2 = v3.x - v1.x;
		float y1 = v2.y - v1.y;
		float y2 = v3.y - v1.y;
		float z1 = v2.z - v1.z;
		float z2 = v3.z - v1.z;

		float s1 = w2.x - w1.x;
		float s2 = w3.x - w1.x;
		float t1 = w2.y - w1.y;
		float t2 = w3.y - w1.y;

		float t = s1 * t2 - s2 * t1;
		float r = t == 0 ? 0 : 1.0f / t;
		glm::vec3 sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
		glm::vec3 tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);

		tan1[i1] += sdir;
		tan1[i2] += sdir;
		tan1[i3] += sdir;

		tan2[i1] += tdir;
		tan2[i2] += tdir;
		tan2[i3] += tdir;
	}

	for (unsigned int a = 0; a < vertexCount; a++)
	{
		const glm::vec3& n = a_vertices[a].normal.xyz();
		const glm::vec3& t = tan1[a];

		// Gram-Schmidt orthogonalise
		glm::vec3 p = t - n * glm::dot(n, t);
		if ( glm::length2(p) != 0 )
		{
			a_vertices[a].tangent = glm::vec4( glm::normalize( p ), 0.0f );

			// calculate binormal
			float sign = glm::dot(glm::cross(n.xyz(), t.xyz()), tan2[a].xyz()) < 0.0f ? -1.0f : 1.0f;
			a_vertices[a].binormal = glm::vec4(glm::cross(a_vertices[a].normal.xyz(),a_vertices[a].tangent.xyz()) * sign, 0);
		}
	}

	delete[] tan1;
}

unsigned int FBXFile::nodeCount(FBXNode* a_node)
{
	if (a_node == nullptr)
		return 0;

	unsigned int uiCount = 1;

	for (auto n : a_node->m_children)
		uiCount += nodeCount(n);

	return uiCount;
}

FBXMeshNode* FBXFile::getMeshByName(const char* a_name)
{
	for (auto mesh : m_meshes)
		if (mesh->m_name == a_name) return mesh;
	return nullptr;
}

FBXLightNode* FBXFile::getLightByName(const char* a_name)
{
	auto oIter = m_lights.find(a_name);
	if (oIter != m_lights.end())
		return oIter->second;
	return nullptr;
}

FBXCameraNode* FBXFile::getCameraByName(const char* a_name)
{
	auto oIter = m_cameras.find(a_name);
	if (oIter != m_cameras.end())
		return oIter->second;
	return nullptr;
}

FBXMaterial* FBXFile::getMaterialByName(const char* a_name)
{
	auto oIter = m_materials.find(a_name);
	if (oIter != m_materials.end())
		return oIter->second;
	return nullptr;
}

FBXTexture* FBXFile::getTextureByName(const char* a_name)
{
	auto oIter = m_textures.find(a_name);
	if (oIter != m_textures.end())
		return oIter->second;
	return nullptr;
}

FBXAnimation* FBXFile::getAnimationByName(const char* a_name)
{
	auto oIter = m_animations.find(a_name);
	if (oIter != m_animations.end())
		return oIter->second;
	return nullptr;
}

FBXLightNode* FBXFile::getLightByIndex(unsigned int a_index)
{
	for (auto t : m_lights)
	{
		if (a_index-- == 0)
			return t.second;
	}

	return nullptr;
}

FBXCameraNode* FBXFile::getCameraByIndex(unsigned int a_index)
{
	for (auto t : m_cameras)
	{
		if (a_index-- == 0)
			return t.second;
	}

	return nullptr;
}

FBXMaterial* FBXFile::getMaterialByIndex(unsigned int a_index)
{
	for (auto t : m_materials)
	{
		if (a_index-- == 0)
			return t.second;
	}

	return nullptr;
}

FBXAnimation* FBXFile::getAnimationByIndex(unsigned int a_index)
{
	for (auto t : m_animations)
	{
		if (a_index-- == 0)
			return t.second;
	}

	return nullptr;
}

FBXTexture* FBXFile::getTextureByIndex(unsigned int a_index)
{
	for (auto t : m_textures)
	{
		if (a_index-- == 0)
			return t.second;
	}

	return nullptr;
}

void FBXFile::gatherBones(void* a_object)
{
	FbxNode* fbxNode = (FbxNode*)a_object;

	if (fbxNode->GetNodeAttribute() != nullptr &&
		fbxNode->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eSkeleton)
	{
		unsigned int index = (unsigned int)m_importAssistor->boneIndexList.size();
		m_importAssistor->boneIndexList[ fbxNode->GetName() ] = index;
	}

	for (int i = 0; i < fbxNode->GetChildCount(); i++)
	{
		gatherBones((void*)fbxNode->GetChild(i));
	}
}

void FBXNode::updateGlobalTransform()
{
	if (m_parent != nullptr)
		m_globalTransform = m_parent->m_globalTransform * m_localTransform;
	else
		m_globalTransform = m_localTransform;

	for (auto child : m_children)
		child->updateGlobalTransform();
}

void FBXCameraNode::updateGlobalTransform()
{
	if (m_parent != nullptr)
		m_globalTransform = m_parent->m_globalTransform * m_localTransform;
	else
		m_globalTransform = m_localTransform;

	m_viewMatrix = glm::inverse( m_globalTransform );

	for (auto child : m_children)
		child->updateGlobalTransform();
}

FBXTexture::~FBXTexture()
{
	delete[] data;
	glDeleteTextures(1, &handle);
}

FBXAnimation* FBXAnimation::clone() const
{
	FBXAnimation* copy = new FBXAnimation();
	copy->m_name = m_name;
	copy->m_startFrame = m_startFrame;
	copy->m_endFrame = m_endFrame;
	copy->m_trackCount = m_trackCount;
	copy->m_tracks = new FBXTrack[ m_trackCount ];

	for ( unsigned int i = 0 ; i < m_trackCount ; ++i )
	{
		copy->m_tracks[i].m_boneIndex = m_tracks[i].m_boneIndex;
		copy->m_tracks[i].m_keyframeCount = m_tracks[i].m_keyframeCount;
		copy->m_tracks[i].m_keyframes = new FBXKeyFrame[ m_tracks[i].m_keyframeCount ];

		memcpy(copy->m_tracks[i].m_keyframes,m_tracks[i].m_keyframes,sizeof(FBXKeyFrame) * m_tracks[i].m_keyframeCount);
	}

	return copy;
}


text:
package com.java110.core.event.app.common;

import com.alibaba.fastjson.JSONArray;
import com.java110.core.context.AppContext;
import com.java110.core.event.app.AppEvent;

/**
 * 通用处理事件,有些服务的处理方式是一模一样的
 * 没有必要 重复去创建类 做重复工作
 *
 * Created by wuxw on 2017/9/15.
 */
public class AppCommonEvent extends AppEvent {
    /**
     * Constructs a prototypical Event.
     *
     * @param source  The object on which the Event initially occurred.
     * @param context
     * @throws IllegalArgumentException if source is null.
     */
    public AppCommonEvent(Object source, AppContext context) {
        this(source, context,null);
    }

    public AppCommonEvent(Object source, AppContext context, JSONArray data){
        super(source, context);
        this.setData(data);
    }
}

redpajama_set_name: RedPajamaGithub


text:
#include "qxtslotjob_p.h"

/*!
\class QxtSlotJob

\inmodule QxtCore

\brief The QxtSlotJob class executes an arbitrary slot on a QThread.

\warning It is essential to understand that the QObject you pass is not safe to use untill done();  is emitted or result() or join() is called.
*/

/*!
execute \a slot from \a precv  on  \a thread  detached
returns a QFuture which offers the functions required to get the result.
\code
    QxtFuture f= QxtSlotJob::detach(&thread,&q,SLOT(exec(QString)),Q_ARG(QString, "select NOW();"));
\endcode

\warning keep your hands of \a recv until you called QFuture::result();
*/
QxtFuture QxtSlotJob::detach(QThread * thread, QObject* recv, const char* slot,
                             QGenericArgument p1,
                             QGenericArgument p2,
                             QGenericArgument p3,
                             QGenericArgument p4,
                             QGenericArgument p5,
                             QGenericArgument p6,
                             QGenericArgument p7,
                             QGenericArgument p8,
                             QGenericArgument p9,
                             QGenericArgument p10)
{
    QxtSlotJob * p = new  QxtSlotJob(recv, slot, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
    connect(p, SIGNAL(done()), p, SLOT(deleteLater()));
    return p->exec(thread);
}
/*!
Construct a new Job Object that will run \a slot from \a precv with the specified arguments
*/
QxtSlotJob::QxtSlotJob(QObject* recv, const char* slot,
                       QGenericArgument p1,
                       QGenericArgument p2,
                       QGenericArgument p3,
                       QGenericArgument p4,
                       QGenericArgument p5,
                       QGenericArgument p6,
                       QGenericArgument p7,
                       QGenericArgument p8,
                       QGenericArgument p9,
                       QGenericArgument p10)
{
    qxt_d().f = QxtMetaObject::bind(recv, slot, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
    qxt_d().receiver = recv;
    qxt_d().orginalthread = QThread::currentThread();

    connect(this, SIGNAL(done()), this, SLOT(pdone()));
}
/*!
asks for the result of the execution.
This calls QxtJob::join()  means it will _block_  the current thread untill the Slot has finished execution
*/
QVariant QxtSlotJob::result()
{
    join();
    return qxt_d().r;
}
/*!
execute this job on \a thread
\warning keep your hands of the Object you passed until you called result() or join()
*/
QxtFuture QxtSlotJob::exec(QThread *thread)
{
    qxt_d().receiver->moveToThread(thread);
    QxtJob::exec(thread);
    return QxtFuture(this);
}

void QxtSlotJob::run()
{
    qxt_d().r = qVariantFromValue(qxt_d().f->invoke());
    qxt_d().receiver->moveToThread(qxt_d().orginalthread);
}

void QxtSlotJob::pdone()
{
    emit(done(qxt_d().r));
}

/*!
\class QxtFuture

\inmodule QxtCore

\brief The QxtFuture class provides a reference to a future result of a QxtSlotJob

*/

QxtFuture::QxtFuture(const QxtFuture& other): QObject()
{
    job = other.job;
    connect(job, SIGNAL(done()), this, SIGNAL(done()));
    connect(job, SIGNAL(done(QVariant)), this, SIGNAL(done(QVariant)));
    waiter = new QxtSignalWaiter(job, SIGNAL(done()));
}

QxtFuture::QxtFuture(QxtSlotJob* j): QObject()
{
    job = j;
    connect(job, SIGNAL(done()), this, SIGNAL(done()));
    connect(job, SIGNAL(done(QVariant)), this, SIGNAL(done(QVariant)));
    waiter = new QxtSignalWaiter(job, SIGNAL(done()));
}

QxtFuture::~QxtFuture()
{
    delete waiter;
}
/*!
asks for the result of the execution.
This calls QxtJob::join()  means it will _block_  the current thread untill the Slot has finished execution
*/
QVariant QxtFuture::joinedResult()
{
    return job->result();
}

/*!
asks for the result of the execution.
waits until the done() signal occurred
or  return a QVariant() if the timout ocures earlier
This uses QxtSignalWaiter so it will _not_ block your current thread.
\warning this function is not reentrant. You have been warned

*/

QVariant QxtFuture::delayedResult(int msec)
{
    if (!waiter->wait(msec, false))
        return QVariant();
    return job->result();
}


text:
<?xml version="1.0" encoding="UTF-8"?>
<Addon Author="NASA" APIVersion="8" Name="GeminiColor" Description="An HSV Colorpicker with presets.">
    <Script Name="GeminiColor.lua"/>
    <Form Name="GeminiColor.xml"/>
</Addon>


text:
using namespace BinaryNinja;
using namespace std;

DataBuffer::DataBuffer()
{
	m_buffer = BNCreateDataBuffer(nullptr, 0);
}

DataBuffer::DataBuffer(size_t len)
{
	m_buffer = BNCreateDataBuffer(nullptr, len);
}

DataBuffer::DataBuffer(const void* data, size_t len)
{
	m_buffer = BNCreateDataBuffer(data, len);
}

DataBuffer::DataBuffer(const DataBuffer& buf)
{
	m_buffer = BNDuplicateDataBuffer(buf.m_buffer);
}

DataBuffer::DataBuffer(DataBuffer&& buf)
{
	m_buffer = buf.m_buffer;
	buf.m_buffer = BNCreateDataBuffer(nullptr, 0);
}

DataBuffer::DataBuffer(BNDataBuffer* buf)
{
	m_buffer = buf;
}

DataBuffer::~DataBuffer()
{
	BNFreeDataBuffer(m_buffer);
}

DataBuffer& DataBuffer::operator=(const DataBuffer& buf)
{
	if (this != &buf)
	{
		BNFreeDataBuffer(m_buffer);
		m_buffer = BNDuplicateDataBuffer(buf.m_buffer);
	}

	return *this;
}

DataBuffer& DataBuffer::operator=(DataBuffer&& buf)
{
	if (this != &buf)
	{
		BNClearDataBuffer(m_buffer);
		BNDataBuffer* temp = m_buffer;
		m_buffer = buf.m_buffer;
		buf.m_buffer = temp;
	}

	return *this;
}

bool DataBuffer::operator==(const DataBuffer& other) const
{
	uint8_t* data = (uint8_t*)GetData();
	uint8_t* otherData = (uint8_t*)other.GetData();
	if (GetLength() != other.GetLength())
		return false;
	if (data == otherData)
		return true;

	for (size_t i = 0; i < GetLength(); i++)
	{
		if (data[i] != otherData[i])
			return false;
	}
	return true;
}

bool DataBuffer::operator!=(const DataBuffer& other) const
{
	return !(*this == other);
}

void* DataBuffer::GetData()
{
	return BNGetDataBufferContents(m_buffer);
}

const void* DataBuffer::GetData() const
{
	return BNGetDataBufferContents(m_buffer);
}

void* DataBuffer::GetDataAt(size_t offset)
{
	return BNGetDataBufferContentsAt(m_buffer, offset);
}

const void* DataBuffer::GetDataAt(size_t offset) const
{
	return BNGetDataBufferContentsAt(m_buffer, offset);
}

size_t DataBuffer::GetLength() const
{
	return BNGetDataBufferLength(m_buffer);
}

void DataBuffer::SetSize(size_t len)
{
	BNSetDataBufferLength(m_buffer, len);
}

void DataBuffer::Clear()
{
	BNClearDataBuffer(m_buffer);
}

void DataBuffer::Append(const void* data, size_t len)
{
	BNAppendDataBufferContents(m_buffer, data, len);
}

void DataBuffer::Append(const DataBuffer& buf)
{
	BNAppendDataBuffer(m_buffer, buf.m_buffer);
}

void DataBuffer::AppendByte(uint8_t val)
{
	Append(&val, 1);
}

DataBuffer DataBuffer::GetSlice(size_t start, size_t len)
{
	BNDataBuffer* result = BNGetDataBufferSlice(m_buffer, start, len);
	return DataBuffer(result);
}

uint8_t& DataBuffer::operator[](size_t offset)
{
	return ((uint8_t*)GetData())[offset];
}

const uint8_t& DataBuffer::operator[](size_t offset) const
{
	return ((const uint8_t*)GetData())[offset];
}

string DataBuffer::ToEscapedString() const
{
	char* str = BNDataBufferToEscapedString(m_buffer);
	string result = str;
	BNFreeString(str);
	return result;
}

DataBuffer DataBuffer::FromEscapedString(const string& src)
{
	return DataBuffer(BNDecodeEscapedString(src.c_str()));
}

string DataBuffer::ToBase64() const
{
	char* str = BNDataBufferToBase64(m_buffer);
	string result = str;
	BNFreeString(str);
	return result;
}

DataBuffer DataBuffer::FromBase64(const string& src)
{
	return DataBuffer(BNDecodeBase64(src.c_str()));
}

bool DataBuffer::ZlibCompress(DataBuffer& output) const
{
	BNDataBuffer* result = BNZlibCompress(output.m_buffer);
	if (!result)
		return false;
	output = DataBuffer(result);
	return true;
}

bool DataBuffer::ZlibDecompress(DataBuffer& output) const
{
	BNDataBuffer* result = BNZlibDecompress(output.m_buffer);
	if (!result)
		return false;
	output = DataBuffer(result);
	return true;
}

string BinaryNinja::EscapeString(const string& s)
{
	DataBuffer buffer(s.c_str(), s.size());
	return buffer.ToEscapedString();
}

string BinaryNinja::UnescapeString(const string& s)
{
	DataBuffer buffer = DataBuffer::FromEscapedString(s);
	return string((const char*)buffer.GetData(), buffer.GetLength());
}


text:
package opengovcrawler;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.TreeMap;
import org.jsoup.HttpStatusException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

/**
 * Retrieves the Ministry names and their corresponding hyperlink from
 * opengov.gr
 *
 * @author Christos Sardianos
 * @version 1.0 - 20/02/2015
 */
public class GetMinistries {

    public static TreeMap<String, String> ministries;
    public static String configFile;
    public static int NUM_OF_CONS_THREADS;
    public static int NUM_OF_ART_THREADS;

    /**
     * Starts the crawling process of OpenGov and crawls the Ministry names and
     * their urls.
     *
     * @param args The file name of the configuration file (ex. crawler.conf)
     * @throws IOException
     * @throws java.lang.InterruptedException
     * @throws java.sql.SQLException
     */
    public static void main(String[] args) throws IOException, InterruptedException, SQLException {
        args = new String[1];
        args[0] = "config.properties";
        if (args.length > 1) {
            System.out.println();
            System.out.println("**************************************************************************************");
            System.out.println();
            System.out.println("Error:  You have specified too many arguments!");
            System.out.println("        Please provide ONLY the configuration file name as the first AND only argument.");
            System.out.println();
            System.out.println("**************************************************************************************");
            System.out.println();
            System.exit(1);
        }

        if (args.length == 0) {
            System.out.println();
            System.out.println("*********************************************************************************");
            System.out.println();
            System.out.println("Error:  No configuration file name was provided!");
            System.out.println("        Please provide the configuration file name as the first AND only argument.");
            System.out.println();
            System.out.println("*********************************************************************************");
            System.out.println();
            System.exit(1);
        }

        configFile = args[0];
        BufferedReader br = null;
        String line = "";
        String splitBy = "=";
        try {
            br = new BufferedReader(new FileReader(configFile));
            while ((line = br.readLine()) != null) {
                if (line.startsWith("NUM_OF_CONS_THREADS")) {
                    String[] lineParts = line.split(splitBy, 2);
                    NUM_OF_CONS_THREADS = Integer.parseInt(lineParts[1]);
                } else if (line.startsWith("NUM_OF_ART_THREADS")) {
                    String[] lineParts = line.split(splitBy, 2);
                    NUM_OF_ART_THREADS = Integer.parseInt(lineParts[1]);
                }
            }
        } catch (FileNotFoundException e) {
            System.out.println();
            System.out.println("*****************************************************************");
            System.out.println();
            System.out.println("Error:  The specified configuration file name does not exist!");
            System.out.println("        Please specify a correct configuration file and try again.");
            System.out.println();
            System.out.println("*****************************************************************");
            System.out.println();
//            e.printStackTrace();
            System.exit(1);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        Properties.verbose = true;
        ministries = new TreeMap<String, String>();

        try {
            DB.init();
            System.out.println("Crawling STARTED!");
            Document doc = Jsoup.connect("http://www.opengov.gr/home").timeout(CrawlHomeUrls.DEFAULT_TIMEOUT).userAgent("Mozilla").get();
            String title = doc.title();
            Elements ministryCategories = doc.select("div.ministeries.downspace_item");
            Elements ministriesAhrefs = null;
            HashSet ogReadMins = new HashSet();
            for (Element minCategory : ministryCategories) {
                String minGroup = minCategory.select("div.downspace_item_title").text();
                ministriesAhrefs = minCategory.select("div.downspace_item_content.side_list").select("li").select("a");
                for (Element link : ministriesAhrefs) {
                    ministries.put(link.text(), link.attr("href"));
                    DB.InsertOrganization(link.text(), link.attr("href"), minGroup);
                    ogReadMins.add(link.text());
                }
            }
            DB.UpdateGroupOfRemovedMinitries(ogReadMins);
            GetConsultationsList consultationList = new GetConsultationsList();
            consultationList.GetConsultationList(ministries);
        } catch (HttpStatusException ht) {
            ht.printStackTrace();
            System.out.println(ht);
        }
    }
}


text:
<!DOCTYPE html>

    <meta charset="utf-8">
    {!! HTML::style('packages/jacopo/laravel-authentication-acl/css/mail-base.css') !!}
    {!! HTML::style('//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css') !!}

Welcome to {!! Config::get('acl_base.app_name')!!}

Dear: {!! $body['email'] !!}

    Your email has been confirmed successfully.
    You can now login to the website using the
    Following link.


text:
package com.intel.analytics.zoo.pipeline.api.keras.layers

import com.intel.analytics.bigdl.nn.{Narrow => BNarrow}
import com.intel.analytics.zoo.pipeline.api.keras.layers.{Narrow => ZNarrow}
import com.intel.analytics.bigdl.tensor.Tensor
import com.intel.analytics.bigdl.utils.Shape
import com.intel.analytics.zoo.pipeline.api.autograd.Parameter
import com.intel.analytics.zoo.pipeline.api.keras.ZooSpecHelper
import com.intel.analytics.zoo.pipeline.api.keras.serializer.ModuleSerializationTest
import com.intel.analytics.zoo.pipeline.api.keras.models.{Model, Sequential}

class NarrowSpec extends ZooSpecHelper {

  "Narrow Zoo 1D" should "be the same as BigDL" in {
    val blayer = BNarrow[Float](1, 1, 2)
    val input1 = Parameter[Float](inputShape = Shape(4), name = "input1")
    val zlayer = new ZNarrow[Float](0, 0, 2).from(input1)
    val model = Model(input1, zlayer)
    model.getOutputShape().toSingle().toArray should be (Array(2))
    val input = Tensor[Float](Array(4)).rand()
    val output = model.forward(input).toTensor[Float]
    output.size() should be (Array(2))
    output.toTensor[Float].almostEqual(blayer.forward(input), 1e-4)
  }

  "Narrow Zoo 1D with batch" should "be the same as BigDL" in {
    val blayer = BNarrow[Float](1, 1, 2)
    val zlayer = ZNarrow[Float](0, 0, 2, inputShape = Shape(3))
    zlayer.build(Shape(-1, 3))
    zlayer.getOutputShape().toSingle().toArray should be (Array(2, 3))
    val input = Tensor[Float](Array(3, 3)).rand()
    val output = zlayer.forward(input).toTensor[Float]
    output.size() should be (Array(2, 3))
    output.toTensor[Float].almostEqual(blayer.forward(input), 1e-4)
  }

  "Narrow Zoo 2D" should "be the same as BigDL" in {
    val blayer = BNarrow[Float](2, 3, -1)
    val zlayer = ZNarrow[Float](1, 2, -1, inputShape = Shape(3))
    zlayer.build(Shape(-1, 3))
    zlayer.getOutputShape().toSingle().toArray should be (Array(-1, 1))
    val input = Tensor[Float](Array(2, 3)).rand()
    compareOutputAndGradInput(blayer, zlayer, input)
  }

  "Narrow Zoo 3D" should "be the same as BigDL" in {
    val blayer = BNarrow[Float](2, 2)
    val zlayer = ZNarrow[Float](1, 1, inputShape = Shape(5, 6))
    zlayer.build(Shape(-1, 5, 6))
    zlayer.getOutputShape().toSingle().toArray should be (Array(-1, 1, 6))
    val input = Tensor[Float](Array(4, 5, 6)).rand()
    compareOutputAndGradInput(blayer, zlayer, input)
  }

  "Narrow Zoo 3D with negative length" should "be the same as BigDL" in {
    val blayer = BNarrow[Float](3, 4, -1)
    val zlayer = ZNarrow[Float](2, 3, -1, inputShape = Shape(5, 6))
    zlayer.build(Shape(-1, 5, 6))
    zlayer.getOutputShape().toSingle().toArray should be (Array(-1, 5, 3))
    val input = Tensor[Float](Array(4, 5, 6)).rand()
    compareOutputAndGradInput(blayer, zlayer, input)
  }

  "Narrow Zoo 4D" should "be the same as BigDL" in {
    val blayer = BNarrow[Float](2, 3, 3)
    val zlayer = ZNarrow[Float](1, 2, 3, inputShape = Shape(8, 5, 6))
    zlayer.build(Shape(-1, 8, 5, 6))
    zlayer.getOutputShape().toSingle().toArray should be (Array(-1, 3, 5, 6))
    val input = Tensor[Float](Array(2, 8, 5, 6)).rand()
    compareOutputAndGradInput(blayer, zlayer, input)
  }

  "Narrow Zoo 4D with negative length" should "be the same as BigDL" in {
    val blayer = BNarrow[Float](-1, 4, -2)
    val zlayer = ZNarrow[Float](-1, 3, -2, inputShape = Shape(5, 6, 7))
    zlayer.build(Shape(-1, 5, 6, 7))
    zlayer.getOutputShape().toSingle().toArray should be (Array(-1, 5, 6, 3))
    val input = Tensor[Float](Array(2, 5, 6, 7)).rand()
    compareOutputAndGradInput(blayer, zlayer, input)
  }

// Open the restriction for batch dimension for now.
//  "Narrow the batch dimension" should "raise an exception" in {
//    intercept[RuntimeException] {
//      val zlayer = ZNarrow[Float](0, 0, inputShape = Shape(2, 3, 4))
//      zlayer.build(Shape(-1, 2, 3, 4))
//    }
//  }

  "Narrow offset too large" should "raise an exception" in {
    intercept[RuntimeException] {
      val zlayer = ZNarrow[Float](1, 2, inputShape = Shape(2, 3, 4))
      zlayer.build(Shape(-1, 2, 3, 4))
    }
  }

  "Narrow length too large" should "raise an exception" in {
    intercept[RuntimeException] {
      val zlayer = ZNarrow[Float](1, 1, 2, inputShape = Shape(2, 3, 4))
      zlayer.build(Shape(-1, 2, 3, 4))
    }
  }

}

class NarrowSerialTest extends ModuleSerializationTest {
  override def test(): Unit = {
    val layer = ZNarrow[Float](1, 1, inputShape = Shape(5, 6))
    layer.build(Shape(2, 5, 6))
    val input = Tensor[Float](2, 5, 6).rand()
    runSerializationTest(layer, input)
  }
}


text:
package griffon.swing;

import griffon.util.CallableWithArgs;
import griffon.util.CallableWithArgsClosure;
import groovy.util.FactoryBuilderSupport;

import java.util.LinkedHashMap;
import java.util.Map;

import static griffon.util.GriffonNameUtils.isBlank;

/**
 * Helper class for constructing bindings between two objects.
 *
 * @author Andres Almiray
 * @since 0.9.2
 */
public class BindUtils {
    /**
     * Create a new Binding using a builder.
     */
    public static BindingBuilder binding() {
        return new BindingBuilder();
    }

    public static class BindingBuilder {
        private Object source;
        private Object target;
        private String sourceProperty;
        private String targetProperty;
        private CallableWithArgs converter;
        private CallableWithArgs validator;
        private boolean mutual;

        public BindingBuilder withSource(Object source) {
            this.source = source;
            return this;
        }

        public BindingBuilder withTarget(Object target) {
            this.target = target;
            return this;
        }

        public BindingBuilder withSourceProperty(String sourceProperty) {
            this.sourceProperty = sourceProperty;
            return this;
        }

        public BindingBuilder withTargetProperty(String targetProperty) {
            this.targetProperty = targetProperty;
            return this;
        }

        public BindingBuilder withConverter(CallableWithArgs converter) {
            this.converter = converter;
            return this;
        }

        public BindingBuilder withValidator(CallableWithArgs validator) {
            this.validator = validator;
            return this;
        }

        public BindingBuilder withMutual(boolean mutual) {
            this.mutual = mutual;
            return this;
        }

        public void make(FactoryBuilderSupport builder) {
            if (builder == null) {
                throw new IllegalArgumentException("Cannot make binding with a null builder!");
            }

            Map<String, Object> attributes = new LinkedHashMap<String, Object>();

            if (source == null) {
                throw new IllegalArgumentException("Unspecified value for: source");
            }
            if (target == null) {
                throw new IllegalArgumentException("Unspecified value for: target");
            }
            if (isBlank(sourceProperty)) sourceProperty = targetProperty;
            if (isBlank(sourceProperty)) {
                throw new IllegalArgumentException("Unspecified values for: sourceProperty, targetProperty");
            }
            if (isBlank(targetProperty)) targetProperty = sourceProperty;

            attributes.put("source", source);
            attributes.put("target", target);
            attributes.put("sourceProperty", sourceProperty);
            attributes.put("targetProperty", targetProperty);
            attributes.put("mutual", mutual);

            if (converter != null) attributes.put("converter", new CallableWithArgsClosure(builder, converter));
            if (validator != null) attributes.put("validator", new CallableWithArgsClosure(builder, validator));

            builder.invokeMethod("bind", attributes);
        }
    }
}


text:
api-feiras-livres
========================================

O **api-feiras-livres** é um projeto, desenvolvido com o framework `Flask <http://flask.pocoo.org>`_,
para prover uma **API REST**, sobre os dados abertos de feiras livres que
acontecem na cidade de São Paulo.

A prefeitura de São Paulo fornece esses dados abertos, por meio de arquivos CSV
compactados (segue o link para download):

http://www.prefeitura.sp.gov.br/cidade/secretarias/upload/chamadas/feiras_livres_1429113213.zip

Essa API foi construida, baseada na estrutura de dados do arquivo (DEINFO_AB_FEIRASLIVRES_2014.csv), contida no zip acima.

Esse projeto foi desenvolvido por: **Samuel Sampaio**

Guia do usuário
------------

Esta parte da documentação irá demonstrar como instalar e utilizar a
aplicação **api-feiras-livres**.

.. toctree::
   :maxdepth: 4

   dependencies
   install
   database
   migrations
   run
   api
   unittests
   models
   populate
   docs


text:
package org.drools.compiler.integrationtests.incrementalcompilation;

public class ConstraintsPair {
    private final String constraints1;
    private final String constraints2;

    public ConstraintsPair(final String constraints1, final String constraints2) {
        this.constraints1 = constraints1;
        this.constraints2 = constraints2;
    }

    public String getConstraints1() {
        return constraints1;
    }

    public String getConstraints2() {
        return constraints2;
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        final ConstraintsPair that = (ConstraintsPair) o;

        return (constraints1.equals(that.constraints1) && constraints2.equals(that.constraints2))
                || (constraints1.equals(that.constraints2) && constraints2.equals(that.constraints1));
    }

    @Override
    public int hashCode() {
        return constraints1.hashCode() + constraints2.hashCode();
    }
}


text:
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System;
using System.IO;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;

namespace Microsoft.DotNet.Build.Tasks
{
    /// <summary>
    /// Takes a delay-signed assembly and flips its CLI header "strong-name signed" bit without
    /// adding a correct signature. This creates an assembly that can be loaded in full trust
    /// without registering for verification skipping. The assembly cannot be installed to the
    /// GAC.
    /// </summary>
    public sealed class OpenSourceSign : BuildTask
    {
        /// <summary>
        /// The full path to the assembly to "Open Source Sign". The file will be modified in place.
        /// </summary>
        [Required]
        public string AssemblyPath
        {
            get;
            set;
        }

        /// <summary>
        /// Whether the task should fail in the case the file is already signed. If not, it will re-sign.
        /// By default it does not fail, because this condition can occur simply because the build was
        /// interrupted at an inopportune moment.
        /// </summary>
        public bool FailIfAlreadySigned
        {
            get;
            set;
        }

        /// <summary>
        /// The number of bytes from the start of the <see cref="CorHeader"/> to its <see cref="CorFlags"/>.
        /// </summary>
        private const int OffsetFromStartOfCorHeaderToFlags =
           sizeof(Int32)  // byte count
         + sizeof(Int16)  // major version
         + sizeof(Int16)  // minor version
         + sizeof(Int64); // metadata directory

        public override bool Execute()
        {
            try
            {
                return ExecuteCore();
            }
            catch (IOException ex)
            {
                LogError("I/O error reading or writing PE file: {0}", ex.Message);
                return false;
            }
            catch (BadImageFormatException ex)
            {
                LogError("Invalid data encountered reading PE file: {0}.", ex.Message);
                return false;
            }
        }

        private bool ExecuteCore()
        {
            using (var stream = OpenFile(this.AssemblyPath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
            using (var reader = new PEReader(stream))
            using (var writer = new BinaryWriter(stream))
            {
                if (!Validate(reader))
                {
                    return false;
                }

                stream.Position = reader.PEHeaders.CorHeaderStartOffset + OffsetFromStartOfCorHeaderToFlags;
                writer.Write((UInt32)(reader.PEHeaders.CorHeader.Flags | CorFlags.StrongNameSigned));
            }

            return true;
        }

        /// <summary>
        /// Returns true if the PE file meets all of the pre-conditions to be Open Source Signed.
        /// Returns false and logs msbuild errors otherwise.
        /// </summary>
        private bool Validate(PEReader peReader)
        {
            if (!peReader.HasMetadata)
            {
                LogError("PE file is not a managed module.");
                return false;
            }

            var mdReader = peReader.GetMetadataReader();
            if (!mdReader.IsAssembly)
            {
                LogError("PE file is not an assembly.");
                return false;
            }

            CorHeader header = peReader.PEHeaders.CorHeader;
            if (FailIfAlreadySigned && ((header.Flags & CorFlags.StrongNameSigned) == CorFlags.StrongNameSigned))
            {
                LogError("PE file is already strong-name signed.");
                return false;
            }

            if ((header.StrongNameSignatureDirectory.Size <= 0) || mdReader.GetAssemblyDefinition().PublicKey.IsNil)
            {
                LogError("PE file is not a delay-signed assembly.");
                return false;
            }

            return true;
        }

        /// <summary>
        /// Wraps FileStream constructor to normalize all unpreventable exceptions to IOException.
        /// </summary>
        private static FileStream OpenFile(string path, FileMode mode, FileAccess access, FileShare share)
        {
            try
            {
                return new FileStream(path, mode, access, share);
            }
            catch (ArgumentException ex)
            {
                throw new IOException(ex.Message, ex);
            }
            catch (UnauthorizedAccessException ex)
            {
                throw new IOException(ex.Message, ex);
            }
            catch (NotSupportedException ex)
            {
                throw new IOException(ex.Message, ex);
            }
        }

        /// <summary>
        /// Logs an msbuild error with the assembly path being modified prepended.
        /// </summary>
        private void LogError(string format, params object[] args)
        {
            this.Log.LogError(this.AssemblyPath + ": " + String.Format(format, args));
        }
    }
}


text:
/*===
REPLACEMENT
undefined
foo
bar
===*/

/* Object.defineProperties is required to call the original
 * Object.defineProperty() regardless of the current value
 * of Object.defineProperty (which is a configurable value).
 */

var orig_define_property;
var obj;

orig_define_property = Object.defineProperty;
Object.defineProperty = function() { print("REPLACEMENT"); }

obj = {};
Object.defineProperty(obj, 'foo', { value: 'bar' });
print(obj.foo);

Object.defineProperties(obj, { prop1: { value: 'foo' }, prop2: { value: 'bar' } });
print(obj.prop1);
print(obj.prop2);


text:
class microsoft_mediacenter_itv_citvtuning {
    constructor() {
        // System.Object CurrentService {get;}
        this.CurrentService = undefined;

    }

    // void IiTvTuning.DoPassThruTuneRequest(string TuneString, bool Quiet)
    DoPassThruTuneRequest() {

    }

    // void IiTvTuning.DoTuneRequest(System.Object ServiceInfo, bool Quiet)
    DoTuneRequest() {

    }

    // bool Equals(System.Object obj)
    Equals() {

    }

    // System.Object IiTvTuning.FindServiceFromId(int ONID, int NID, int TSID, int SID, [ref] bool MultipleMatches)
    FindServiceFromId() {

    }

    // System.Object IiTvTuning.FindServiceFromLCN(int LCN)
    FindServiceFromLCN() {

    }

    // int GetHashCode()
    GetHashCode() {

    }

    // string IiTvTuning.GetTunerProperty(string PropertyName, string Language)
    GetTunerProperty() {

    }

    // type GetType()
    GetType() {

    }

    // string ToString()
    ToString() {

    }

}

module.exports = microsoft_mediacenter_itv_citvtuning;


text:
.SMParent {
    font:bold 10px verdana;
    color:navy;
    text-align:left;
    padding-left: 2px;
}
.SMParentOver {
	background-color: gold;
    font:bold 10px verdana;
    color:navy;
    text-align:left;
	text-decoration:none;
    padding-left: 2px;
    cursor:pointer;
}
.SMParentSelected {
    font:bold 10px verdana;
    color:crimson;
    text-align:left;
    padding-left: 2px;
	cursor:pointer;
}

.SMChild {
	font:10px verdana;
	color:navy;
	text-decoration:none;
    padding-left: 10px;
	cursor:pointer;
}
.SMChild a {
	color:navy;
	font:10px Verdana;
	text-decoration:none;
}

.SMChildOver {
	background-color:gold;
	font:10px verdana;
	color:#306090;
	text-decoration:underline;
    padding-left: 10px;
	cursor:pointer;
}
.SMChildOver a {
	color:#306090;
	font:10px Verdana;
	text-decoration:underline;
}

.SMChildSelected {
	background-color: #dfefff;
	font:10px verdana;
	color:#003060;
    padding-left: 10px;
}
.SMChildSelected a {
	color:#003060;
	font:10px Verdana;
	text-decoration:none;
}

.SMChildrenBox {
	padding-bottom:1px;
}

.SMMenu {
	background-color:white;
	width: 170px;
	border:1px dotted #CCCCCC;
	overflow:hidden;
}

.SMImageParent {
	border:0px;
	vertical-align:top;
}

.SMImageChild {
	border:0px;
	vertical-align:middle;
	margin:2px;
}


text:
package main

import (
	"errors"
	"fmt"
	"net"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"

	"github.com/coreos/fleet/machine"
	"github.com/coreos/fleet/pkg"
	"github.com/coreos/fleet/ssh"
)

var (
	flagMachine            string
	flagUnit               string
	flagSSHAgentForwarding bool
	cmdSSH                 = &Command{
		Name:    "ssh",
		Summary: "Open interactive shell on a machine in the cluster",
		Usage:   "[-A|--forward-agent] [--ssh-port=N] [--machine|--unit] {MACHINE|UNIT}",
		Description: `Open an interactive shell on a specific machine in the cluster or on the machine
where the specified unit is located.

fleetctl tries to detect whether your first argument is a machine or a unit.
To skip this check use the --machine or --unit flags.

Open a shell on a machine:
	fleetctl ssh 2444264c-eac2-4eff-a490-32d5e5e4af24

Open a shell from your laptop, to the machine running a specific unit, using a
cluster member as a bastion host:
	fleetctl --tunnel 10.10.10.10 ssh foo.service

Open a shell on a machine and forward the authentication agent connection:
	fleetctl ssh --forward-agent 2444264c-eac2-4eff-a490-32d5e5e4af24

Tip: Create an alias for --tunnel.
	- Add "alias fleetctl=fleetctl --tunnel 10.10.10.10" to your bash profile.
	- Now you can run all fleet commands locally.

This command does not work with global units.`,
		Run: runSSH,
	}
)

func init() {
	cmdSSH.Flags.StringVar(&flagMachine, "machine", "", "Open SSH connection to a specific machine.")
	cmdSSH.Flags.StringVar(&flagUnit, "unit", "", "Open SSH connection to machine running provided unit.")
	cmdSSH.Flags.BoolVar(&flagSSHAgentForwarding, "forward-agent", false, "Forward local ssh-agent to target machine.")
	cmdSSH.Flags.BoolVar(&flagSSHAgentForwarding, "A", false, "Shorthand for --forward-agent")
	cmdSSH.Flags.IntVar(&sharedFlags.SSHPort, "ssh-port", 22, "Connect to remote hosts over SSH using this TCP port.")
}

func runSSH(args []string) (exit int) {
	if flagUnit != "" && flagMachine != "" {
		stderr("Both machine and unit flags provided, please specify only one.")
		return 1
	}

	var err error
	var addr string

	switch {
	case flagMachine != "":
		addr, _, err = findAddressInMachineList(flagMachine)
	case flagUnit != "":
		addr, _, err = findAddressInRunningUnits(flagUnit)
	default:
		addr, err = globalMachineLookup(args)
		// trim machine/unit name from args
		if len(args) > 0 {
			args = args[1:]
		}
	}

	if err != nil {
		stderr("Unable to proceed: %v", err)
		return 1
	}

	if addr == "" {
		stderr("Could not determine address of machine.")
		return 1
	}

	addr = findSSHPort(addr)

	args = pkg.TrimToDashes(args)

	var sshClient *ssh.SSHForwardingClient
	timeout := getSSHTimeoutFlag()
	if tun := getTunnelFlag(); tun != "" {
		sshClient, err = ssh.NewTunnelledSSHClient(globalFlags.SSHUserName, tun, addr, getChecker(), flagSSHAgentForwarding, timeout)
	} else {
		sshClient, err = ssh.NewSSHClient(globalFlags.SSHUserName, addr, getChecker(), flagSSHAgentForwarding, timeout)
	}
	if err != nil {
		stderr("Failed building SSH client: %v", err)
		return 1
	}

	defer sshClient.Close()

	if len(args) > 0 {
		cmd := strings.Join(args, " ")
		err, exit = ssh.Execute(sshClient, cmd)
		if err != nil {
			stderr("Failed running command over SSH: %v", err)
		}
	} else {
		if err := ssh.Shell(sshClient); err != nil {
			stderr("Failed opening shell over SSH: %v", err)
			exit = 1
		}
	}
	return
}

func findSSHPort(addr string) string {
	if sharedFlags.SSHPort != 22 && !strings.Contains(addr, ":") {
		return net.JoinHostPort(addr, strconv.Itoa(sharedFlags.SSHPort))
	} else {
		return addr
	}
}

func globalMachineLookup(args []string) (string, error) {
	if len(args) == 0 {
		return "", errors.New("one machine or unit must be provided")
	}

	lookup := args[0]

	machineAddr, machineOk, _ := findAddressInMachineList(lookup)
	unitAddr, unitOk, _ := findAddressInRunningUnits(lookup)

	switch {
	case machineOk && unitOk:
		return "", fmt.Errorf("ambiguous argument, both machine and unit found for `%s`.\nPlease use flag `-m` or `-u` to refine the search", lookup)
	case machineOk:
		return machineAddr, nil
	case unitOk:
		return unitAddr, nil
	}

	return "", fmt.Errorf("could not find matching unit or machine")
}

func findAddressInMachineList(lookup string) (string, bool, error) {
	states, err := cAPI.Machines()
	if err != nil {
		return "", false, err
	}

	var match *machine.MachineState
	for i := range states {
		machState := states[i]
		if !strings.HasPrefix(machState.ID, lookup) {
			continue
		}

		if match != nil {
			return "", false, fmt.Errorf("found more than one machine")
		}

		match = &machState
	}

	if match == nil {
		return "", false, fmt.Errorf("machine does not exist")
	}

	return match.PublicIP, true, nil
}

func findAddressInRunningUnits(name string) (string, bool, error) {
	name = unitNameMangle(name)
	u, err := cAPI.Unit(name)
	if err != nil {
		return "", false, err
	} else if u == nil {
		return "", false, fmt.Errorf("unit does not exist")
	} else if suToGlobal(*u) {
		return "", false, fmt.Errorf("global units unsupported")
	}

	m := cachedMachineState(u.MachineID)
	if m != nil && m.PublicIP != "" {
		return m.PublicIP, true, nil
	}

	return "", false, nil
}

// runCommand will attempt to run a command on a given machine. It will attempt
// to SSH to the machine if it is identified as being remote.
func runCommand(machID string, cmd string, args ...string) (retcode int) {
	var err error
	if machine.IsLocalMachineID(machID) {
		err, retcode = runLocalCommand(cmd, args...)
		if err != nil {
			stderr("Error running local command: %v", err)
		}
	} else {
		ms, err := machineState(machID)
		if err != nil || ms == nil {
			stderr("Error getting machine IP: %v", err)
		} else {
			addr := findSSHPort(ms.PublicIP)
			err, retcode = runRemoteCommand(addr, cmd, args...)
			if err != nil {
				stderr("Error running remote command: %v", err)
			}
		}
	}
	return
}

// runLocalCommand runs the given command locally and returns any error encountered and the exit code of the command
func runLocalCommand(cmd string, args ...string) (error, int) {
	osCmd := exec.Command(cmd, args...)
	osCmd.Stderr = os.Stderr
	osCmd.Stdout = os.Stdout
	osCmd.Start()
	err := osCmd.Wait()
	if err != nil {
		// Get the command's exit status if we can
		if exiterr, ok := err.(*exec.ExitError); ok {
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				return nil, status.ExitStatus()
			}
		}
		// Otherwise, generic command error
		return err, -1
	}
	return nil, 0
}

// runRemoteCommand runs the given command over SSH on the given IP, and returns
// any error encountered and the exit status of the command
func runRemoteCommand(addr string, cmd string, args ...string) (err error, exit int) {
	var sshClient *ssh.SSHForwardingClient
	timeout := getSSHTimeoutFlag()
	if tun := getTunnelFlag(); tun != "" {
		sshClient, err = ssh.NewTunnelledSSHClient(globalFlags.SSHUserName, tun, addr, getChecker(), false, timeout)
	} else {
		sshClient, err = ssh.NewSSHClient(globalFlags.SSHUserName, addr, getChecker(), false, timeout)
	}
	if err != nil {
		return err, -1
	}

	cmdargs := cmd
	for _, arg := range args {
		cmdargs += fmt.Sprintf(" %q", arg)
	}

	defer sshClient.Close()

	return ssh.Execute(sshClient, cmdargs)
}


text:
<!DOCTYPE html>

    <meta charset="utf-8">
    <title>Rappid Demo Application</title>
    <link rel="stylesheet" type="text/css" href="../../build/rappid.min.css">
    <link rel="stylesheet" type="text/css" href="css/style.css">
    <link rel="stylesheet" type="text/css" href="css/theme-picker.css">
    <link rel="icon" href="favicon.ico" type="image/x-icon" />

Rappid

The application was open locally using the file protocol. It is recommended to access it trough a Web server.

Please see instructions.