text:
#include <algorithm>
#include <string>
#include <sstream>

#include "FBXSceneEncoder.h"
#include "FBXUtil.h"
#include "Sampler.h"

using namespace gameplay;
using std::string;
using std::vector;
using std::map;
using std::ostringstream;

// Fix bad material names
static void fixMaterialName(string& name);

static std::string UTF8toSJIS(const char *basestr)
{
    // UTF8 to cp932
    char* path_utf8;
    FbxUTF8ToAnsi(basestr, path_utf8);

    std::string coverted_path(path_utf8);
    FbxFree(path_utf8);

    return coverted_path;
}

FBXSceneEncoder::FBXSceneEncoder()
    : _groupAnimation(NULL), _autoGroupAnimations(false)
{
}

FBXSceneEncoder::~FBXSceneEncoder()
{
}

FbxNode* FBXSceneEncoder::getRootNode(FbxScene* fbxScene)
{
    // Load all of the nodes and their contents.
    FbxNode* rootNode = fbxScene->GetRootNode();

	if ( rootNode->GetChildCount() == 1 ) {
		rootNode = rootNode->GetChild(0);
	}
	return rootNode;
}

void FBXSceneEncoder::write(const string& filepath, const EncoderArguments& arguments)
{
    FbxManager* sdkManager = FbxManager::Create();
    FbxIOSettings *ios = FbxIOSettings::Create(sdkManager, IOSROOT);
    sdkManager->SetIOSettings(ios);

	FbxImporter* importer = FbxImporter::Create(sdkManager,"");

    if (!importer->Initialize(filepath.c_str(), -1, sdkManager->GetIOSettings()))
    {
        LOG(1, "Call to FbxImporter::Initialize() failed.\n");
        LOG(1, "Error returned: %s\n\n", importer->GetStatus().GetErrorString());
        exit(-1);
    }

	_OptionFilePath = arguments.getTextureOptionPath();

    FbxScene* fbxScene = FbxScene::Create(sdkManager,"__FBX_SCENE__");
	FbxScene* fbxScene2;

    print("Loading FBX file.");
    importer->Import(fbxScene);
    importer->Destroy();

	if (arguments.mergeAnimationEnabled()) {
		importer = FbxImporter::Create(sdkManager,"");

		if (!importer->Initialize( arguments.getMergeAnimationFBXName().c_str(), -1, sdkManager->GetIOSettings()))
		{
			LOG(1, "Call to FbxImporter::Initialize() failed.\n");
			LOG(1, "Error returned: %s\n\n", importer->GetStatus().GetErrorString());
			exit(-1);
		}

		fbxScene2 = FbxScene::Create(sdkManager,"__FBX_SCENE2__");
		importer->Import(fbxScene2);
		importer->Destroy();
		print("Loading FBX2 file.");
	}

    // Determine if animations should be grouped.
    if (arguments.getGroupAnimationAnimationId().empty() && isGroupAnimationPossible(fbxScene))
    {
        if ( arguments.getAnimationGrouping()==EncoderArguments::ANIMATIONGROUP_AUTO ||
            (arguments.getAnimationGrouping()==EncoderArguments::ANIMATIONGROUP_PROMPT && promptUserGroupAnimations()))
        {
            _autoGroupAnimations = true;
        }
    }

    if (arguments.tangentBinormalIdCount() > 0)
    {
        generateTangentsAndBinormals(getRootNode(fbxScene), arguments);
    }

    print("Loading Scene.");
	_fbxScene = fbxScene;
    loadScene(fbxScene);
    print("Load materials");
    loadMaterials(fbxScene, arguments.originalMaterialName());
    print("Loading animations.");
	if (arguments.mergeAnimationEnabled()) {
		loadAnimations(fbxScene2, arguments);
	} else {
		loadAnimations(fbxScene, arguments);
	}
    sdkManager->Destroy();

    print("Optimizing GamePlay Binary.");
    _gamePlayFile.adjust();
    if (_autoGroupAnimations)
    {
        _gamePlayFile.groupMeshSkinAnimations();
    }

    string outputFilePath = arguments.getOutputFilePath();

    if (arguments.textOutputEnabled())
    {
        int pos = outputFilePath.find_last_of('.');
        if (pos > 0)
        {
            string path = outputFilePath.substr(0, pos);
            path.append(".xml");
            LOG(1, "Saving debug file: %s\n", path.c_str());
            if (!_gamePlayFile.saveText(path))
            {
                LOG(1, "Error writing text file: %s\n", path.c_str());
            }
        }
    }
    else
    {
        LOG(1, "Saving binary file: %s\n", outputFilePath.c_str());
        if (!_gamePlayFile.saveBinary(outputFilePath))
        {
            LOG(1, "Error writing binary file: %s\n", outputFilePath.c_str());
        }
    }

    // Write the material file
    if (arguments.outputMaterialEnabled())
    {
        int pos = outputFilePath.find_last_of('.');
        if (pos > 0)
        {
            string path = outputFilePath.substr(0, pos);
            path.append(".material");
            writeMaterial(path);
        }
    }
}

bool FBXSceneEncoder::writeMaterial(const string& filepath)
{
    FILE* file = fopen(filepath.c_str(), "w");
    if (!file)
    {
        return false;
    }
    // Finds the base materials that are used.
    std::set<Material*> baseMaterialsToWrite;
    for (map<string, Material*>::iterator it = _materials.begin(); it != _materials.end(); ++it)
    {
        baseMaterialsToWrite.insert(it->second->getParent());
    }

    // Write the base materials that are used.
    for (std::set<Material*>::iterator it = baseMaterialsToWrite.begin(); it != baseMaterialsToWrite.end(); ++it)
    {
        Material* material = *it;
        material->writeMaterial(file);
        fprintf(file, "\n");
    }

    // Write all of the non-base materials.
    for (map<string, Material*>::iterator it = _materials.begin(); it != _materials.end(); ++it)
    {
        (*it).second->writeMaterial(file);
        fprintf(file, "\n");
    }

    fclose(file);
    return true;
}

void FBXSceneEncoder::loadScene(FbxScene* fbxScene)
{
    Scene* scene = new Scene();
    scene->setId(fbxScene->GetName());
    if (scene->getId().length() == 0)
    {
        scene->setId("__SCENE__");
    }

    // Load all of the nodes and their contents.
    FbxNode* rootNode = getRootNode(fbxScene);

    if (rootNode)
    {
        print("Triangulate.");
        FbxGeometryConverter converter(rootNode->GetFbxManager());
        converter.Triangulate(fbxScene, true);
        //triangulateRecursive(rootNode);

        // Don't include the FBX root node in the GPB.
        const int childCount = rootNode->GetChildCount();
		if (childCount == 0) {
			printf("Load single node.\n");
			Node* node = loadNode(rootNode);
			if (node)
			{
				scene->add(node);
			}
		} else {
			printf("Load nodes.(%d)\n",childCount);
			for (int i = 0; i < childCount; ++i)
			{
                std::string nodename = UTF8toSJIS(rootNode->GetChild(i)->GetName());
				printf("Node:%s\n", nodename.c_str());
				Node* node = loadNode(rootNode->GetChild(i));
				if (node)
				{
					scene->add(node);
				}
			}
		}

		//printf("Process Mesh.\n");
		//scene->processSceneMesh(0);
	}

	printf("Load Shapes.\n");

    // Load the MeshSkin information from the scene's poses.
    loadBindShapes(fbxScene);

    // Find the ambient light of the scene
    FbxColor ambientColor = fbxScene->GetGlobalSettings().GetAmbientColor();
    scene->setAmbientColor((float)ambientColor.mRed, (float)ambientColor.mGreen, (float)ambientColor.mBlue);

    // Assign the first camera node (if there is one) in the scene as the active camera
    // This ensures that if there's a camera in the scene that it is assigned as the
    // active camera.
    // TODO: add logic to find the "active" camera node in the fbxScene
    scene->setActiveCameraNode(scene->getFirstCameraNode());

    _gamePlayFile.addScene(scene);
}

void FBXSceneEncoder::loadAnimationChannels(FbxAnimLayer* animLayer, FbxNode* fbxNode, Animation* animation)
{
    const char* name = fbxNode->GetName();
    //Node* node = _gamePlayFile.getNode(name);

    // Determine which properties are animated on this node
    // Find the transform at each key frame
    // TODO: Ignore properties that are not animated (scale, rotation, translation)
    // This should result in only one animation channel per animated node.

    float startTime = FLT_MAX, stopTime = -1.0f, frameRate = -FLT_MAX;
    bool tx = false, ty = false, tz = false, rx = false, ry = false, rz = false, sx = false, sy = false, sz = false;
    FbxAnimCurve* animCurve = NULL;
    animCurve = getCurve(fbxNode->LclTranslation, animLayer, FBXSDK_CURVENODE_COMPONENT_X);
    if (animCurve)
    {
        tx = true;
        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
    }
    animCurve = getCurve(fbxNode->LclTranslation, animLayer, FBXSDK_CURVENODE_COMPONENT_Y);
    if (animCurve)
    {
        ty = true;
        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
    }
    animCurve = getCurve(fbxNode->LclTranslation, animLayer, FBXSDK_CURVENODE_COMPONENT_Z);
    if (animCurve)
    {
        tz = true;
        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
    }
    animCurve = getCurve(fbxNode->LclRotation, animLayer, FBXSDK_CURVENODE_COMPONENT_X);
    if (animCurve)
    {
        rx = true;
        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
    }
    animCurve = getCurve(fbxNode->LclRotation, animLayer, FBXSDK_CURVENODE_COMPONENT_Y);
    if (animCurve)
    {
        ry = true;
        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
    }
    animCurve = getCurve(fbxNode->LclRotation, animLayer, FBXSDK_CURVENODE_COMPONENT_Z);
    if (animCurve)
    {
        rz = true;
        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
    }
    animCurve = getCurve(fbxNode->LclScaling, animLayer, FBXSDK_CURVENODE_COMPONENT_X);
    if (animCurve)
    {
        sx = true;
        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
    }
    animCurve = getCurve(fbxNode->LclScaling, animLayer, FBXSDK_CURVENODE_COMPONENT_Y);
    if (animCurve)
    {
        sy = true;
        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
    }
    animCurve = getCurve(fbxNode->LclScaling, animLayer, FBXSDK_CURVENODE_COMPONENT_Z);
    if (animCurve)
    {
        sz = true;
        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
    }

    if (!(sx || sy || sz || rx || ry || rz || tx || ty || tz))
        return; // no animation channels

    assert(startTime != FLT_MAX);
    assert(stopTime >= 0.0f);

    // Determine which animation channels to create
    vector<unsigned int> channelAttribs;
    if (sx && sy && sz)
    {
        if (rx || ry || rz)
        {
            if (tx && ty && tz)
            {
                channelAttribs.push_back(Transform::ANIMATE_SCALE_ROTATE_TRANSLATE);
            }
            else
            {
                channelAttribs.push_back(Transform::ANIMATE_SCALE_ROTATE);
                if (tx)
                    channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_X);
                if (ty)
                    channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Y);
                if (tz)
                    channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Z);
            }
        }
        else
        {
            if (tx && ty && tz)
            {
                channelAttribs.push_back(Transform::ANIMATE_SCALE_TRANSLATE);
            }
            else
            {
                channelAttribs.push_back(Transform::ANIMATE_SCALE);
                if (tx)
                    channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_X);
                if (ty)
                    channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Y);
                if (tz)
                    channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Z);
            }
        }
    }
    else
    {
        if (rx || ry || rz)
        {
            if (tx && ty && tz)
            {
                channelAttribs.push_back(Transform::ANIMATE_ROTATE_TRANSLATE);
            }
            else
            {
                channelAttribs.push_back(Transform::ANIMATE_ROTATE);
                if (tx)
                    channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_X);
                if (ty)
                    channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Y);
                if (tz)
                    channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Z);
            }
        }
        else
        {
            if (tx && ty && tz)
            {
                channelAttribs.push_back(Transform::ANIMATE_TRANSLATE);
            }
            else
            {
                if (tx)
                    channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_X);
                if (ty)
                    channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Y);
                if (tz)
                    channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Z);
            }
        }

        if (sx)
            channelAttribs.push_back(Transform::ANIMATE_SCALE_X);
        if (sy)
            channelAttribs.push_back(Transform::ANIMATE_SCALE_Y);
        if (sz)
            channelAttribs.push_back(Transform::ANIMATE_SCALE_Z);
    }
    unsigned int channelCount = channelAttribs.size();
    assert(channelCount > 0);

    // Allocate channel list
    const int channelStart = animation->getAnimationChannelCount();
    for (unsigned int i = 0; i < channelCount; ++i)
    {
        AnimationChannel* channel = new AnimationChannel();
        channel->setTargetId(name);
        channel->setInterpolation(AnimationChannel::LINEAR);
        channel->setTargetAttribute(channelAttribs[i]);
        animation->add(channel);

        std::string nodename = UTF8toSJIS(name);
        printf( "Anim #%d [%s]\r\n",i, nodename.c_str());

    }

    // Evaulate animation curve in increments of frameRate and populate channel data.
    FbxAMatrix fbxMatrix;
    Matrix matrix;
    double increment = 1000.0 / (double)frameRate;
    int frameCount = (int)ceil((double)(stopTime - startTime) / increment) + 1; // +1 because stop time is inclusive

    // If the animation for this node only has only 1 key frame and it is equal to the node's transform then ignore it.
    // This is a work around for a bug in the Blender FBX exporter.
    if (frameCount == 1 && fbxMatrix == fbxNode->EvaluateLocalTransform(0))
    {
        return;
    }

    for (int frame = 0; frame < frameCount; ++frame)
    {
        double time = startTime + (frame * (double)increment);

        // Note: We used to clamp time to stop time, but FBX sdk does not always produce
        // and accurate stopTime (sometimes it is rounded down for some reason), so I'm
        // disabling this clamping for now as it seems more accurate under normal circumstances.
        //time = std::min(time, (double)stopTime);

        // Evalulate the animation at this time
        FbxTime kTime;
        kTime.SetMilliSeconds((FbxLongLong)time);
        fbxMatrix = fbxNode->EvaluateLocalTransform(kTime);
        copyMatrix(fbxMatrix, matrix);

        // Decompose the evalulated transformation matrix into separate
        // scale, rotation and translation.
        Vector3 scale;
        Quaternion rotation;
        Vector3 translation;
        matrix.decompose(&scale, &rotation, &translation);
        rotation.normalize();

        // Append keyframe data to all channels
        for (unsigned int i = channelStart, channelEnd = channelStart + channelCount; i < channelEnd; ++i)
        {
            appendKeyFrame(fbxNode, animation->getAnimationChannel(i), (float)time, scale, rotation, translation);
        }
    }

    if (_groupAnimation != animation)
    {
        _gamePlayFile.addAnimation(animation);
    }
}

void FBXSceneEncoder::loadAnimationLayer(FbxAnimLayer* fbxAnimLayer, FbxNode* fbxNode, const EncoderArguments& arguments)
{
    bool animationGroupId = false;
    const char* name = fbxNode->GetName();
    // Check if this node's animations are supposed to be grouped
    if (name && arguments.containsGroupNodeId(name))
    {
        animationGroupId = true;
        _groupAnimation = new Animation();
        _groupAnimation->setId(arguments.getAnimationId(name));
    }
    Animation* animation = _groupAnimation;
    if (!animation)
    {
        animation = new Animation();
        animation->setId(name);
    }
    loadAnimationChannels(fbxAnimLayer, fbxNode, animation);

    const int childCount = fbxNode->GetChildCount();
    for (int modelCount = 0; modelCount < childCount; ++modelCount)
    {
        loadAnimationLayer(fbxAnimLayer, fbxNode->GetChild(modelCount), arguments);
    }
    if (animationGroupId)
    {
        _gamePlayFile.addAnimation(_groupAnimation);
        _groupAnimation = NULL;
    }
}

void FBXSceneEncoder::loadAnimations(FbxScene* fbxScene, const EncoderArguments& arguments)
{
    FbxAnimEvaluator* evaluator = fbxScene->GetAnimationEvaluator();
    if (!evaluator)
        return;
    FbxAnimStack* animStack = fbxScene->GetCurrentAnimationStack();
    if (!animStack)
        return;

    for (int i = 0; i < fbxScene->GetSrcObjectCount<FbxAnimStack>(); ++i)
    {
        FbxAnimStack* animStack = FbxCast<FbxAnimStack>(fbxScene->GetSrcObject<FbxAnimStack>(i));
        int nbAnimLayers = animStack->GetMemberCount<FbxAnimLayer>();
        for (int l = 0; l < nbAnimLayers; ++l)
        {
            FbxAnimLayer* animLayer = animStack->GetMember<FbxAnimLayer>(l);
            loadAnimationLayer(animLayer, getRootNode(fbxScene), arguments);
        }
    }
}

	/**
	 * Get the world matrix of a node.
	 *
	 * \param _pnNode The node for which to get the world matrix.
	 * \param _psScene The scene containing the node.
	 * \return Returns the world matrix of a node.
	 */
FbxAMatrix &FBXSceneEncoder::GetNodeWorldMatrix( FbxNode * _pnNode ) {
		FbxScene * _psScene = _fbxScene;

		FbxAMatrix & xmTrans = _psScene->GetAnimationEvaluator()->GetNodeGlobalTransform( const_cast<FbxNode *>(_pnNode) );
		FbxAMatrix xmGeometry;
		FbxVector4 vTranslation, vRotation, vScaling;
		vTranslation = _pnNode->GetGeometricTranslation( FbxNode::eSourcePivot );
		vRotation = _pnNode->GetGeometricRotation( FbxNode::eSourcePivot );
		vScaling = _pnNode->GetGeometricScaling( FbxNode::eSourcePivot );
		xmGeometry.SetT( vTranslation );
		xmGeometry.SetR( vRotation );
		xmGeometry.SetS( vScaling );
		FbxAMatrix xmFinal = xmTrans * xmGeometry;
		return xmFinal;
}

Node* FBXSceneEncoder::loadNode(FbxNode* fbxNode, FbxNode *baseNode)
{
    Node* node = NULL;

    // Check if this node has already been loaded
    const char* id = fbxNode->GetName();
    if (id && strlen(id) > 0)
    {
        node = _gamePlayFile.getNode(fbxNode->GetName());
        if (node)
        {
            return node;
        }
    }
    node = new Node();
    if (id)
    {
        node->setId(id);
    }
    _gamePlayFile.addNode(node);

    transformNode(fbxNode, node);

#if 0
	if ( baseNode ) {
		float m[16];
		FbxAMatrix mat;
		FbxAMatrix mat2;
	    //mat = GetNodeWorldMatrix(fbxNode);
        mat = fbxNode->EvaluateLocalTransform();
		mat2 = baseNode->EvaluateLocalTransform();
		mat *= mat2.Inverse();
        copyMatrix(mat, m);
        node->setTransformMatrix(m);
	}
/*
		std::string name = node->getId();
		if ( strcmp( name.c_str(),"PronamaChan" )==0 ) {
            node->resetTransformMatrix();
		}
*/
#endif

    loadCamera(fbxNode, node);
    loadLight(fbxNode, node);
    loadModel(fbxNode, node);

    if (fbxNode->GetSkeleton())
    {
        // Indicate that this is a joint node for the purpose of debugging.
        // The XML debug output will print that this node is a joint.
        node->setIsJoint(true);
    }

    // Load child nodes
    const int childCount = fbxNode->GetChildCount();
    for (int i = 0; i < childCount; ++i)
    {
        Node* child = loadNode(fbxNode->GetChild(i),baseNode);
        if (child)
        {
            node->addChild(child);
        }
    }
    _nodeMap[fbxNode] = node;
    return node;
}

Mesh* FBXSceneEncoder::getMesh(FbxUInt64 meshId)
{
    // Check if this mesh was already loaded.
    map<FbxUInt64, Mesh*>::iterator it = _meshes.find(meshId);
    if (it != _meshes.end())
    {
        return it->second;
    }
    return NULL;
}

void FBXSceneEncoder::saveMesh(FbxUInt64 meshId, Mesh* mesh)
{
    assert(mesh);
    if (!getMesh(meshId))
    {
        _meshes[meshId] = mesh;
    }
}

void FBXSceneEncoder::print(const char* str)
{
    LOG(1, "%s\n", str);
}

void FBXSceneEncoder::transformNode(FbxNode* fbxNode, Node* node)
{
    FbxAMatrix matrix;
    float m[16];

    if (fbxNode->GetCamera() || fbxNode->GetLight())
    {
        FbxAMatrix rotateAdjust;

        if(fbxNode->GetLight())
        {
            /*
             * according to the fbx-documentation the light's forward vector
             * points along a node's negative Y axis.
             * so we have to rotate it by 90° around the X-axis to correct it.
             */
            if(fbxNode->RotationActive.Get())
            {
                const FbxVector4& postRotation = fbxNode->PostRotation.Get();
                fbxNode->SetPostRotation(FbxNode::eSourcePivot, FbxVector4(postRotation.mData[0] + 90.0,
                                                                           postRotation.mData[1],
                                                                           postRotation.mData[2])
                                         );
            }
            else
            {
                // if the rotation is deactivated we have to rotate it anyway to get the correct transformation in the end
                rotateAdjust.SetR(FbxVector4(-90.0, 0.0, 0.0));
            }

            matrix = fbxNode->EvaluateLocalTransform() * rotateAdjust;
        }
        else if(fbxNode->GetCamera())
        {
			/*
			* according to the fbx-documentation the camera's forward vector
			* points along a node's positive X axis.
			* so we have to rotate it by 90 around the Y-axis to correct it.
			*/
			if (fbxNode->RotationActive.Get())
			{
				const FbxVector4& postRotation = fbxNode->PostRotation.Get();
				fbxNode->SetPostRotation(FbxNode::eSourcePivot, FbxVector4(postRotation.mData[0],
					postRotation.mData[1] + 90.0,
					postRotation.mData[2]));
			}
			else
			{
				// usually for the fbx-exporter in Blender 2.75
				// if rotation is deactivated we have to rotate the local transform in 90°
				rotateAdjust.SetR(FbxVector4(0, 90.0, 0.0));
			}

			matrix = fbxNode->EvaluateLocalTransform() * rotateAdjust;
        }

        copyMatrix(matrix, m);
        node->setTransformMatrix(m);
    }
    else
    {
        matrix = fbxNode->EvaluateLocalTransform();
        copyMatrix(matrix, m);
        node->setTransformMatrix(m);
    }
}

Material* FBXSceneEncoder::getBaseMaterial(const char* id)
{
    map<string, Material*>::iterator it = _baseMaterials.find(string(id));
    if (it != _baseMaterials.end())
    {
        return it->second;
    }
    return NULL;
}

static string getBaseMaterialName(Material* material)
{
    ostringstream baseName;
    if (material->isTextured())
    {
        baseName << "textured";
    }
    else
    {
        baseName << "colored";
    }

    return baseName.str();
}

Material* FBXSceneEncoder::findBaseMaterial(Material* material)
{
    string baseMaterialName = getBaseMaterialName(material);
    Material* baseMaterial = getBaseMaterial(baseMaterialName.c_str());
    if (baseMaterial)
    {
        return baseMaterial;
    }
    baseMaterial = createBaseMaterial(baseMaterialName, material);
    _baseMaterials[baseMaterial->getId()] = baseMaterial;
    return baseMaterial;
}

Node* FBXSceneEncoder::findNode(FbxNode* fbxNode)
{
    if (fbxNode)
    {
        map<FbxNode*, Node*>::const_iterator it = _nodeMap.find(fbxNode);
        if (it != _nodeMap.end())
        {
            return it->second;
        }
    }
    return NULL;
}

Material* FBXSceneEncoder::createBaseMaterial(const string& baseMaterialName, Material* childMaterial)
{
    Material* baseMaterial = new Material(baseMaterialName);
    baseMaterial->setUniform("u_worldViewProjectionMatrix", "WORLD_VIEW_PROJECTION_MATRIX");
    baseMaterial->setRenderState("cullFace", "true");
    baseMaterial->setRenderState("depthTest", "true");

    baseMaterial->setRenderState("blend", "true");
    baseMaterial->setRenderState("blendSrc", "SRC_ALPHA");
    baseMaterial->setRenderState("blendDst", "ONE_MINUS_SRC_ALPHA");

    if (childMaterial->isTextured())
    {
		baseMaterial->setVertexShader("res/shaders/textured.vert");
        baseMaterial->setFragmentShader("res/shaders/textured.frag");

        Sampler* sampler = baseMaterial->createSampler(u_diffuseTexture);
        sampler->set("mipmap", "true");
        sampler->set("wrapS", CLAMP);
        sampler->set("wrapT", CLAMP);
        sampler->set(MIN_FILTER, LINEAR_MIPMAP_LINEAR);
        sampler->set(MAG_FILTER, LINEAR);
    }
    else
    {
		baseMaterial->setVertexShader("res/shaders/colored.vert");
        baseMaterial->setFragmentShader("res/shaders/colored.frag");
    }

	if (childMaterial->isLit())
    {
        baseMaterial->setLit(true);
		childMaterial->setUniform("u_inverseTransposeWorldViewMatrix", "INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX");

        if (childMaterial->isSpecular())
        {
            childMaterial->setUniform("u_cameraPosition", "CAMERA_WORLD_POSITION");
        }
    }
    assert(baseMaterial);
    return baseMaterial;
}

void FBXSceneEncoder::loadBindShapes(FbxScene* fbxScene)
{
    float m[16];
    const int poseCount = fbxScene->GetPoseCount();
    for (int i = 0; i < poseCount; ++i)
    {
        FbxPose* pose = fbxScene->GetPose(i);
        assert(pose);
        if (pose->IsBindPose() && pose->GetCount() > 0)
        {
            FbxNode* fbxNode = pose->GetNode(0);
            if (fbxNode->GetMesh() != NULL)
            {
                Node* node = _gamePlayFile.getNode(fbxNode->GetName());
                assert(node && node->getModel());

                Model* model = node->getModel();
                if (model && model->getSkin())
                {
                    MeshSkin* skin = model->getSkin();
                    copyMatrix(pose->GetMatrix(0), m);
                    skin->setBindShape(m);
                }
            }
        }
    }
}

void FBXSceneEncoder::loadCamera(FbxNode* fbxNode, Node* node)
{
    FbxCamera* fbxCamera = fbxNode->GetCamera();
    if (!fbxCamera)
    {
        return;
    }
    Camera* camera = new Camera();
    const char* name = fbxNode->GetName();
    if (name)
    {
        string id(name);
        id.append("_Camera");
        camera->setId(id);
    }

	// Clip planes have to by divided by the forward scale of the camera (x-axis) to get right values
	float scale = (float)fbxCamera->GetNode()->LclScaling.Get()[0];

    camera->setAspectRatio(getAspectRatio(fbxCamera));
	camera->setNearPlane((float)fbxCamera->NearPlane.Get() / scale);
	camera->setFarPlane((float)fbxCamera->FarPlane.Get() / scale);

    if (fbxCamera->ProjectionType.Get() == FbxCamera::eOrthogonal)
    {
        camera->setOrthographic();
        camera->setViewportWidth((float)fbxCamera->GetApertureWidth());
        camera->setViewportWidth((float)fbxCamera->GetApertureHeight());
        // xmag in FBX can be calculated from: OrthoZoom * 30.0 / 2.0
        camera->setViewportWidth((float)fbxCamera->OrthoZoom.Get() * 15.0f);
    }
    else if (fbxCamera->ProjectionType.Get() == FbxCamera::ePerspective)
    {
        camera->setPerspective();
        camera->setFieldOfView(getFieldOfView(fbxCamera));
    }
    else
    {
        LOG(2, "Warning: Unknown camera type in node.\n");
        return;
    }
    _gamePlayFile.addCamera(camera);
    node->setCamera(camera);
}

void FBXSceneEncoder::loadLight(FbxNode* fbxNode, Node* node)
{
    FbxLight* fbxLight = fbxNode->GetLight();
    if (!fbxLight)
    {
        return;
    }
    Light* light = new Light();
    const char* name = fbxNode->GetName();
    if (name)
    {
        string id(name);
        id.append("_Light");
        light->setId(id);
    }

    FbxDouble3 color = fbxLight->Color.Get();
    light->setColor((float)color[0], (float)color[1], (float)color[2]);

    float range;
    if( fbxLight->EnableFarAttenuation.Get() ) {
        // If FarAttenuation is enabled, that gives us range directly
        range = (float)fbxLight->FarAttenuationEnd.Get();
    } else {
        // Otherwise, we need to fit a decay type to calculate range
        // For each attenuation type, the range at which the intensity falls to 1/100 can be computed as:
        //
        // Linear:      1/100 = I/(a*r)     =>    r = 100*I/a
        // Quadratic:   1/100 = I/(a*r^2)   =>    r = sqrt(100*I/a)
        // Cubic:       1/100 = I/(a*r^3)   =>    r = pow(100*I/a,1/3.0)
        float attenuation = fbxLight->DecayStart.Get();
        float intensity = fbxLight->Intensity.Get()/100.0f;
        switch( fbxLight->DecayType.Get() ) {
            case FbxLight::eLinear:
                range = 100.0f*intensity/attenuation;
                break;
            case FbxLight::eQuadratic:
                range = 10.0f*sqrtf(intensity/attenuation);
                break;
            case FbxLight::eCubic:
                range = powf(100.0f*intensity/attenuation, (float)(1/3.0));
                break;
            case FbxLight::eNone:
                // We don't support no attenuation; set range to 1.0f by default
                range = 1.0f;
                break;
        }
    }

    switch (fbxLight->LightType.Get())
    {
        case FbxLight::ePoint:
        {
            FbxLight::EDecayType decayType = fbxLight->DecayType.Get();
            if( decayType == FbxLight::eNone && !fbxNode->GetVisibility() )
                light->setAmbientLight();
            else {
                light->setPointLight();
                light->setRange(range);
            }
            break;
        }
        case FbxLight::eDirectional:
        {
            light->setDirectionalLight();
            break;
        }
        case FbxLight::eSpot:
        {
            light->setSpotLight();
            light->setInnerAngle(MATH_DEG_TO_RAD((float)fbxLight->InnerAngle.Get()));
            light->setOuterAngle(MATH_DEG_TO_RAD((float)fbxLight->OuterAngle.Get()));
            light->setRange(range);
            break;
        }
        default:
        {
            LOG(2, "Warning: Unknown light type in node.\n");
            return;
        }
    }

    _gamePlayFile.addLight(light);
    node->setLight(light);
}

void FBXSceneEncoder::loadModel(FbxNode* fbxNode, Node* node)
{
	FbxMesh* fbxMesh = fbxNode->GetMesh();
	if (!fbxMesh || fbxMesh->GetPolygonVertexCount() == 0)
    {
        return;
    }
    if (fbxMesh->IsTriangleMesh())
    {
        Mesh* mesh = loadMesh(fbxMesh);
        Model* model = new Model();
        model->setMesh(mesh);
		node->setModel(model);
		//printf("#Model[%s]\n",node->getId().c_str());

		loadSkin(fbxMesh, model, fbxNode);
        if (model->getSkin())
        {
              node->resetTransformMatrix();
        }
    }
}

void FBXSceneEncoder::loadMaterials(FbxScene* fbxScene, bool orgName )
{
    FbxNode* rootNode = getRootNode(fbxScene);
    if (rootNode)
    {
        // Don't include the FBX root node
        const int childCount = rootNode->GetChildCount();
		if (childCount == 0) {
				loadMaterial( rootNode, orgName );
		} else {
			for (int i = 0; i < childCount; ++i)
			{
				FbxNode* fbxNode = rootNode->GetChild(i);
				if (fbxNode)
				{
					loadMaterial( fbxNode, orgName );
				}
			}
		}
    }
}

void FBXSceneEncoder::loadMaterial(FbxNode* fbxNode, bool orgName)
{
    Node* node = findNode(fbxNode);
    Model* model = (node) ? node->getModel() : NULL;

	const int materialCount = fbxNode->GetMaterialCount();
	if (materialCount == 0) {
		if (model) {
			printf("#Warning No Material node [%s]\n", node->getId().c_str());
		}
	}

    for (int index = 0; index < materialCount; ++index)
    {
        FbxSurfaceMaterial* fbxMaterial = fbxNode->GetMaterial(index);
        std::string materialName = UTF8toSJIS(fbxMaterial->GetName());

		unsigned int jointcount = 0;
		if (model) {
			MeshSkin *skin = model->getSkin();
			if ( skin ) {
				jointcount = skin->getJointCount();
			}
		}

        if ( orgName == false ) fixMaterialName(materialName);
		if (jointcount>0) {                    // FIX : aboid same material name of different joint count (onitama)
			materialName+="_";
			materialName+=std::to_string(jointcount);
		}

        Material* material = NULL;
        map<string, Material*>::iterator it = _materials.find(materialName);
		//printf( "Material(%s)(%d)\n",materialName.c_str(),jointcount );
        if (it != _materials.end())
        {
            // This material was already loaded so don't load it again
            material = it->second;
        }
        else
        {
            if (EncoderArguments::getInstance()->outputMaterialEnabled())
            {
                material = createMaterial(materialName, fbxMaterial, node);
            }
            else
            {
                // If outputMaterialEnabled() is not enabled then only create the materials for the purpose of writing
                // the material name in the GPB file. There is no need to load uniforms and samplers for the material.
                material = new Material(materialName);
            }
            _materials[materialName] = material;
        }

        if (materialCount == 1 && material && model)
        {
            model->setMaterial(material); // TODO: add support for materials per mesh part
        }
        else if (materialCount > 1 && material && model)
        {
            model->setMaterial(material, index);
        }
    }

    const int childCount = fbxNode->GetChildCount();
    for (int i = 0; i < childCount; ++i)
    {
        FbxNode* childNode = fbxNode->GetChild(i);
        if (childNode)
        {
            loadMaterial( childNode, orgName );
        }
    }
}

void FBXSceneEncoder::loadMaterialTextures(FbxSurfaceMaterial* fbxMaterial, Material* material)
{
    FbxProperty fbxProperty;
    int textureIndex;
    FBXSDK_FOR_EACH_TEXTURE(textureIndex)
    {
        fbxProperty = fbxMaterial->FindProperty(FbxLayerElement::sTextureChannelNames[textureIndex]);
        //FindAndDisplayTextureInfoByProperty(fbxProperty, lDisplayHeader, lMaterialIndex);
        if ( fbxProperty.IsValid() )
        {
            int textureCount = fbxProperty.GetSrcObjectCount<FbxTexture>();
            for (int j = 0; j < textureCount; ++j)
            {
                FbxLayeredTexture *layeredTexture = fbxProperty.GetSrcObject<FbxLayeredTexture>(j);
                if (layeredTexture)
                {
                    FbxLayeredTexture *layeredTexture = fbxProperty.GetSrcObject<FbxLayeredTexture>(j);
                    int lNbTextures = layeredTexture->GetSrcObjectCount<FbxTexture>();
                    for (int k = 0; k<lNbTextures; ++k)
                    {
                        FbxTexture* fbxTexture = layeredTexture->GetSrcObject<FbxTexture>(k);
                        if (fbxTexture)
                        {

                            // NOTE the blend mode is ALWAYS on the LayeredTexture and NOT the one on the texture.
                            // Why is that?  because one texture can be shared on different layered textures and might
                            // have different blend modes.

                            FbxLayeredTexture::EBlendMode lBlendMode;
                            layeredTexture->GetTextureBlendMode(k, lBlendMode);
                        }

                    }
                }
                else if (FbxTexture* fbxTexture = fbxProperty.GetSrcObject<FbxTexture>(j))
                {
                    //no layered texture simply get on the property
                    if (FbxFileTexture* fileTexture = FbxCast<FbxFileTexture>(fbxTexture))
                    {
                        loadMaterialFileTexture(fileTexture, material);
                    }
                }
            }
        }
    }
}

std::string FBXSceneEncoder::GetFileNameFromPath(const std::string &path)
{
    size_t pos1;

    pos1 = path.rfind('\\');
    if(pos1 != std::string::npos){
        return path.substr(pos1+1, path.size()-pos1-1);
    }

    pos1 = path.rfind('/');
    if(pos1 != std::string::npos){
        return path.substr(pos1+1, path.size()-pos1-1);
    }

    return path;
}

void FBXSceneEncoder::loadMaterialFileTexture(FbxFileTexture* fileTexture, Material* material)
{
    FbxTexture::ETextureUse textureUse = fileTexture->GetTextureUse();
    Sampler* sampler = NULL;
    if (textureUse == FbxTexture::eStandard)
    {
        if (!material->getSampler("u_diffuseTexture"))
            sampler = material->createSampler("u_diffuseTexture");
    }
    if (sampler)
    {
        char* ansiname;
        char* ansiname2;
        FbxUTF8ToAnsi(fileTexture->GetRelativeFileName(), ansiname);
        FbxUTF8ToAnsi(fileTexture->GetFileName(), ansiname2);

        string fname = _OptionFilePath + GetFileNameFromPath(ansiname);
        sampler->set("absolutePath", ansiname2);
        sampler->set("relativePath", fname );
        sampler->set("wrapS", fileTexture->GetWrapModeU() == FbxTexture::eClamp ? CLAMP : REPEAT);
        sampler->set("wrapT", fileTexture->GetWrapModeV() == FbxTexture::eClamp ? CLAMP : REPEAT);

        if (textureUse == FbxTexture::eStandard)
        {
            double scaleU = fileTexture->GetScaleU();
            double scaleV = fileTexture->GetScaleV();
            if (scaleU != 1 || scaleV != 1)
            {
                ostringstream stream;
                stream << scaleU << ", " << scaleV;
                material->setUniform("u_textureRepeat", stream.str());
                material->addDefine(TEXTURE_REPEAT);
            }

            double translationU = fileTexture->GetTranslationU();
            double translationV = fileTexture->GetTranslationV();
            if (translationU != 0 || translationV != 0)
            {
                ostringstream stream;
                stream << translationU << ", " << translationV;
                material->setUniform("u_textureOffset", stream.str());
                material->addDefine(TEXTURE_OFFSET);
            }
        }
        FbxFree(ansiname);
        FbxFree(ansiname2);
    }
}

void FBXSceneEncoder::loadMaterialUniforms(FbxSurfaceMaterial* fbxMaterial, Material* material)
{

    if ( fbxMaterial->GetClassId().Is(FbxSurfaceLambert::ClassId) )
    {
        FbxSurfaceLambert* lambert = FbxCast<FbxSurfaceLambert>(fbxMaterial);

        if (material->isLit())
        {
            FbxDouble3 ambient = lambert->Ambient.Get();
            //if (!isBlack(ambient))
            //{
                material->setUniform("u_ambientColor", toString(ambient));
            //}
        }
        if (!material->isTextured())
        {
            if (!material->isDefined(VERTEX_COLOR))
            {
                FbxDouble3 diffuse = lambert->Diffuse.Get();
                //if (!isBlack(diffuse))
                //{
                    material->setUniform("u_diffuseColor", toString(diffuse, 1.0));
                //}
            }
        }
    }
    if (fbxMaterial->GetClassId().Is(FbxSurfacePhong::ClassId))
    {
        FbxSurfacePhong* phong = FbxCast<FbxSurfacePhong>(fbxMaterial);

        if (material->isLit())
        {
            FbxDouble shininess = phong->Shininess.Get();
            if (shininess > 0)
            {
                ostringstream stream;
                stream << shininess;
                material->setUniform("u_specularExponent", stream.str());
                material->addDefine(SPECULAR);
            }
        }
    }
}

Material* FBXSceneEncoder::createMaterial(const string& name, FbxSurfaceMaterial* fbxMaterial, Node* node)
{
    assert(fbxMaterial);
    Material* material = new Material(name);
    Model* model = (node) ? node->getModel() : NULL;
    Mesh* mesh = (model) ? model->getMesh() : NULL;
    if (mesh)
    {
        // The material should be lit if the model has normals or there are lights in the scene.
        material->setLit(mesh->hasNormals() || _gamePlayFile.getLightCount() > 0);
        if (mesh->hasVertexColors())
        {
            material->addDefine(VERTEX_COLOR);
        }
    }
    MeshSkin* skin = (model) ? model->getSkin() : NULL;
    if (skin && skin->getJointCount() > 0)
    {
        material->setUniform("u_matrixPalette", "MATRIX_PALETTE");
        material->addDefine("SKINNING");
        ostringstream stream;
		stream << "SKINNING_JOINT_COUNT " << skin->getJointCount();
        material->addDefine(stream.str());
    }
    loadMaterialTextures(fbxMaterial, material);
    loadMaterialUniforms(fbxMaterial, material);
    material->setParent(findBaseMaterial(material));
    assert(material);
    return material;
}

void FBXSceneEncoder::loadSkin(FbxMesh* fbxMesh, Model* model, FbxNode *basenode)
{
    const int deformerCount = fbxMesh->GetDeformerCount();
    for (int i = 0; i < deformerCount; ++i)
    {
        FbxDeformer* deformer = fbxMesh->GetDeformer(i);
		//printf( "#Load Skin [%s]\n",deformer->GetName() );
        if (deformer->GetDeformerType() == FbxDeformer::eSkin)
        {
            FbxSkin* fbxSkin = FbxCast<FbxSkin>(deformer);

            MeshSkin* skin = new MeshSkin();

            vector<string> jointNames;
            vector<Node*> joints;
            vector<Matrix> bindPoses;

            const int clusterCount = fbxSkin->GetClusterCount();
            for (int j = 0; j < clusterCount; ++j)
            {
                FbxCluster* cluster = fbxSkin->GetCluster(j);
                assert(cluster);
                FbxNode* linkedNode = cluster->GetLink();
                if (linkedNode && linkedNode->GetSkeleton())
                {
                    const char* jointName = linkedNode->GetName();
                    assert(jointName);
                    jointNames.push_back(jointName);
					//printf( "#     Joint [%s]\n",jointName );
                    Node* joint = loadNode(linkedNode, basenode);
                    assert(joint);
                    joints.push_back(joint);

                    FbxAMatrix matrix;
                    cluster->GetTransformLinkMatrix(matrix);
                    Matrix m;
                    copyMatrix(matrix.Inverse(), m);
                    bindPoses.push_back(m);
                }
            }
            skin->setJointNames(jointNames);
            skin->setJoints(joints);
            skin->setBindPoses(bindPoses);
            model->setSkin(skin);
            break;
        }
    }
}

Mesh* FBXSceneEncoder::loadMesh(FbxMesh* fbxMesh)
{
    // Check if this mesh has already been loaded.
    Mesh* mesh = getMesh(fbxMesh->GetUniqueID());
    if (mesh)
    {
        return mesh;
    }
    mesh = new Mesh();
    // GamePlay requires that a mesh have a unique ID but FbxMesh doesn't have a string ID.
    const char* name = fbxMesh->GetNode()->GetName();
    if (name)
    {
        string id(name);
        id.append("_Mesh");
        mesh->setId(id);
    }

    // The number of mesh parts is equal to the number of materials that affect this mesh.
    // There is always at least one mesh part.
    vector<MeshPart*> meshParts;
    const int materialCount = fbxMesh->GetNode()->GetMaterialCount();
    int meshPartSize = (materialCount > 0) ? materialCount : 1;
    for (int i = 0; i < meshPartSize; ++i)
    {
        meshParts.push_back(new MeshPart());
    }

    // Find the blend weights and blend indices if this mesh is skinned.
    vector<vector<Vector2> > weights;
    bool hasSkin = loadBlendWeights(fbxMesh, weights);

    std::string nodename = UTF8toSJIS(name);
    printf( "#Load Mesh [%s] skin:%d\n", nodename.c_str(),hasSkin );

    // Get list of uv sets for mesh
    FbxStringList uvSetNameList;
    fbxMesh->GetUVSetNames(uvSetNameList);
    const int uvSetCount = uvSetNameList.GetCount();

    int vertexIndex = 0;
    FbxVector4* controlPoints = fbxMesh->GetControlPoints();
    const int polygonCount = fbxMesh->GetPolygonCount();
    for (int polyIndex = 0; polyIndex < polygonCount; ++polyIndex)
    {
        const int polygonSize = fbxMesh->GetPolygonSize(polyIndex);
        for (int posInPoly = 0; posInPoly < polygonSize; ++posInPoly)
        {
            int controlPointIndex = fbxMesh->GetPolygonVertex(polyIndex, posInPoly);
            Vertex vertex;

            FbxVector4& position = controlPoints[controlPointIndex];
            vertex.position.x = (float)position[0];
            vertex.position.y = (float)position[1];
            vertex.position.z = (float)position[2];

            // Load tex coords for all uv sets
            for (int uvSetIndex = 0; uvSetIndex < uvSetCount; ++uvSetIndex)
            {
                const FbxGeometryElementUV* uvElement = fbxMesh->GetElementUV(uvSetNameList.GetStringAt(uvSetIndex));
                if (uvElement)
                    loadTextureCoords(fbxMesh, uvElement, uvSetIndex, polyIndex, posInPoly, vertexIndex, &vertex);
            }

            // Load other data
            loadNormal(fbxMesh, vertexIndex, controlPointIndex, &vertex);
            loadTangent(fbxMesh, vertexIndex, controlPointIndex, &vertex);
            loadBinormal(fbxMesh, vertexIndex, controlPointIndex, &vertex);
            loadVertexColor(fbxMesh, vertexIndex, controlPointIndex, &vertex);

            if (hasSkin)
            {
                loadBlendData(weights[controlPointIndex], &vertex);
            }

            // Determine which mesh part this vertex index should be added to based on the material that affects it.
            int meshPartIndex = 0;
            const int elementMatrialCount = fbxMesh->GetElementMaterialCount();
            for (int k = 0; k < elementMatrialCount; ++k)
            {
                FbxGeometryElementMaterial* elementMaterial = fbxMesh->GetElementMaterial(k);
                meshPartIndex = elementMaterial->GetIndexArray().GetAt(polyIndex);
            }

            // Add the vertex to the mesh if it hasn't already been added and find the vertex index.
            unsigned int index;
            if (mesh->contains(vertex))
            {
                index = mesh->getVertexIndex(vertex);
            }
            else
            {
                index = mesh->addVertex(vertex);
            }
            meshParts[meshPartIndex]->addIndex(index);
            vertexIndex++;
        }
    }

    const size_t meshpartsSize = meshParts.size();
    for (size_t i = 0; i < meshpartsSize; ++i)
    {
        if (meshParts[i]->getIndicesCount() > 0)
            mesh->addMeshPart(meshParts[i]);
    }

    // The order that the vertex elements are add to the list matters.
    // It should be the same order as how the Vertex data is written.

    // Position
    mesh->addVetexAttribute(POSITION, Vertex::POSITION_COUNT);

    const Vertex& vertex = mesh->vertices[0];
    // Normals
    if (vertex.hasNormal)
    {
        mesh->addVetexAttribute(NORMAL, Vertex::NORMAL_COUNT);
    }
    // Tangents
    if (vertex.hasTangent)
    {
        mesh->addVetexAttribute(TANGENT, Vertex::TANGENT_COUNT);
    }
    // Binormals
    if (vertex.hasBinormal)
    {
        mesh->addVetexAttribute(BINORMAL, Vertex::BINORMAL_COUNT);
    }
    // Texture Coordinates
    for (unsigned int i = 0; i < MAX_UV_SETS; ++i)
    {
        if (vertex.hasTexCoord[i])
        {
            mesh->addVetexAttribute(TEXCOORD0 + i, Vertex::TEXCOORD_COUNT);
        }
    }
    // Diffuse Color
    if (vertex.hasDiffuse)
    {
        mesh->addVetexAttribute(COLOR, Vertex::DIFFUSE_COUNT);
    }
    // Skinning BlendWeights BlendIndices
    if (vertex.hasWeights)
    {
        mesh->addVetexAttribute(BLENDWEIGHTS, Vertex::BLEND_WEIGHTS_COUNT);
        mesh->addVetexAttribute(BLENDINDICES, Vertex::BLEND_INDICES_COUNT);
    }

    _gamePlayFile.addMesh(mesh);
    saveMesh(fbxMesh->GetUniqueID(), mesh);
    return mesh;
}

/*
void FBXSceneEncoder::triangulateRecursive(FbxNode* fbxNode)
{
    // Triangulate all NURBS, patch and mesh under this node recursively.
    FbxNodeAttribute* nodeAttribute = fbxNode->GetNodeAttribute();
    if (nodeAttribute)
    {
        FbxNodeAttribute::EType type = nodeAttribute->GetAttributeType();
        if (type == FbxNodeAttribute::eMesh ||
            type == FbxNodeAttribute::eNurbs ||
            type == FbxNodeAttribute::eNurbsSurface ||
            type == FbxNodeAttribute::ePatch)
        {
            FbxGeometryConverter converter(fbxNode->GetFbxManager());
            converter.T
        }
    }

    const int childCount = fbxNode->GetChildCount();
    for (int childIndex = 0; childIndex < childCount; ++childIndex)
    {
        triangulateRecursive(fbxNode->GetChild(childIndex));
    }
}
 */

// Functions

void fixMaterialName(string& name)
{
    static int unnamedCount = 0;

#if 0
    for (string::size_type i = 0, len = name.length(); i < len; ++i)
    {
        if (!isalnum(name[i]))
            name[i] = '_';
    }

    if (name.length() == 0)
    {
        ostringstream stream;
        stream << "unnamed_" << (++unnamedCount);
        name = stream.str();
    }
#endif
    ostringstream stream;
    stream << "material_" << (++unnamedCount);
    name = stream.str();
}


text:
<?php $this->load->helper('form'); ?>

<?php echo form_open('user/edit/'.$id); ?>

     Username:
     <input value=<?php echo $user->username; ?> required=true type="text" size="20" id="username" name="username"/>

     Email:
     <input value=<?php echo $user->email; ?> required=true type="text" size="20" id="email" name="email"/>

     Password:
     <input type="password" required=true size="20" id="password" name="password"/>

    <input type="hidden" id="admin" name="admin" value=<?php echo $user->admin; ?> />

        <?php echo form_submit('submit', 'Submit'); ?>

<?php echo form_close(); ?>

redpajama_set_name: RedPajamaGithub


text:
const ShareTempus = require('../lib/ShareTempus')('fakeAuthToken');

module.exports = ShareTempus;


text:
package com.thoughtworks.go.plugin.activation.test;

import com.thoughtworks.go.plugin.api.GoApplicationAccessor;
import com.thoughtworks.go.plugin.api.GoPlugin;
import com.thoughtworks.go.plugin.api.GoPluginIdentifier;
import com.thoughtworks.go.plugin.api.annotation.Extension;
import com.thoughtworks.go.plugin.api.exceptions.UnhandledRequestTypeException;
import com.thoughtworks.go.plugin.api.request.GoPluginApiRequest;
import com.thoughtworks.go.plugin.api.response.GoPluginApiResponse;

@Extension
public class DummyGoPluginWithOneArgConstructorOnly implements GoPlugin {
    public DummyGoPluginWithOneArgConstructorOnly(int x) {
    }

    @Override
    public void initializeGoApplicationAccessor(GoApplicationAccessor goApplicationAccessor) {
        throw new UnsupportedOperationException();
    }

    @Override
    public GoPluginApiResponse handle(GoPluginApiRequest requestMessage) throws UnhandledRequestTypeException {
        throw new UnsupportedOperationException();
    }

    @Override
    public GoPluginIdentifier pluginIdentifier() {
        throw new UnsupportedOperationException();
    }
}


text:
<html>
	<head></head>
	<body>
		<script type='text/javascript'
                src='../../steal.js?steal[app]=steal/build/test&steal[env]=development'
                compress='false'>
        </script>
	</body>
</html>


text:
/*
 * ----------------------------------------
 *          Jenkins Test Tracker
 * ----------------------------------------
 *          Produced by Dan Grew
 *                 2016
 * ----------------------------------------
 */
package uk.dangrew.jtt.desktop.core.jobupdating;

/**
 * {@link JenkinsTestTrackerCoreImpl} test.
 */
public class JttCoreJobUpdatingTest {

//   @Ignore
//   @Test public void manualInspection() throws InterruptedException {
//      SystemStyling.initialise();
//      DecoupledPlatformImpl.setInstance( new PlatformDecouplerImpl() );
//
//      final ExternalApi api = Mockito.mock( ExternalApi.class );
//      final JttTestCoreImpl core = new JttTestCoreImpl( api );
//
//      new Thread( () -> {
//
//         String response = TestCommon.readFileIntoString( getClass(), "jobs.json" );
//         Mockito.when( api.getJobsList() ).thenReturn( response );
//
//         response = TestCommon.readFileIntoString( getClass(), "job-details-success.json" );
//         Mockito.when( api.getLastBuildJobDetails( Mockito.any() ) ).thenReturn( response );
//
//         convenienceWait( 1000, core.getJobUpdater() );
//
//         JenkinsJob second = core.getJenkinsDatabase().jenkinsJobs().get( 1 );
//         response = TestCommon.readFileIntoString( getClass(), "building-state-10.json" );
//         Mockito.when( api.getLastBuildBuildingState( second ) ).thenReturn( response );
//
//         convenienceWait( 2000, core.getJobUpdater() );
//
//         JenkinsJob fifth = core.getJenkinsDatabase().jenkinsJobs().get( 4 );
//         response = TestCommon.readFileIntoString( getClass(), "building-state-10.json" );
//         Mockito.when( api.getLastBuildBuildingState( fifth ) ).thenReturn( response );
//
//         convenienceWait( 8000, core.getJobUpdater() );
//
//         response = TestCommon.readFileIntoString( getClass(), "built-state.json" );
//         Mockito.when( api.getLastBuildBuildingState( second ) ).thenReturn( response );
//         response = TestCommon.readFileIntoString( getClass(), "job-details-unstable.json" );
//         Mockito.when( api.getLastBuildJobDetails( second ) ).thenReturn( response );
//
//         convenienceWait( 10000, core.getJobUpdater() );
//
//         response = TestCommon.readFileIntoString( getClass(), "built-state.json" );
//         Mockito.when( api.getLastBuildBuildingState( fifth ) ).thenReturn( response );
//         response = TestCommon.readFileIntoString( getClass(), "job-details-failure.json" );
//         Mockito.when( api.getLastBuildJobDetails( fifth ) ).thenReturn( response );
//
//         convenienceWait( 5000, core.getJobUpdater() );
//
//      } ).start();
//
//      new BuildProgressor( core.getJenkinsDatabase(), new Timer(), 500l );
//      JavaFxInitializer.launchInWindow( () -> { return new BuildWallDisplayImpl( core.getJenkinsDatabase() ); } );
//      Thread.sleep( 100000 );
//   }//End Method
//
//   /**
//    * Method to prove a convenience method for waiting for a number of milliseconds.
//    * @param millis the number of milliseconds to wait.
//    */
//   private void convenienceWait( long millis, TimeKeeper timeKeeper ){
//      try {
//         timeKeeper.poll();
//         Thread.sleep( millis );
//      } catch ( Exception e ) {
//         e.printStackTrace();
//      }
//   }//End Method
//
//   @Test public void shouldPullInJobsAndUpdateBuiltStateAndTimes(){
//      final ExternalApi api = Mockito.mock( ExternalApi.class );
//      JttTestCoreImpl core = new JttTestCoreImpl( api );
//      core.initialiseTimeKeepers();
//      JenkinsDatabase database = core.getJenkinsDatabase();
//      TimeKeeper jobUpdater = core.getJobUpdater();
//
//      Assert.assertTrue( database.hasNoJenkinsJobs() );
//      Assert.assertTrue( database.hasNoTestClasses() );
//
//      //initialise jobs to success
//      String response = TestCommon.readFileIntoString( getClass(), "jobs.json" );
//      Mockito.when( api.getJobsList() ).thenReturn( response );
//      response = TestCommon.readFileIntoString( getClass(), "job-details-success.json" );
//      Mockito.when( api.getLastBuildJobDetails( Mockito.any() ) ).thenReturn( response );
//
//      jobUpdater.poll();
//      Assert.assertEquals( 7, database.jenkinsJobs().size() );
//      Assert.assertTrue( database.hasNoTestClasses() );
//
//      //start building the second job
//      JenkinsJob second = core.getJenkinsDatabase().jenkinsJobs().get( 1 );
//      response = TestCommon.readFileIntoString( getClass(), "building-state-10.json" );
//      Mockito.when( api.getLastBuildBuildingState( second ) ).thenReturn( response );
//
//      jobUpdater.poll();
//      core.setSimulatedTime( 2000 );
//      Assert.assertEquals( 10000, second.expectedBuildTimeProperty().get() );
//      Assert.assertEquals( 1000, second.currentBuildTimeProperty().get() );
//
//      //start building the fifth, from the same point for convenience
//      JenkinsJob fifth = core.getJenkinsDatabase().jenkinsJobs().get( 4 );
//      response = TestCommon.readFileIntoString( getClass(), "building-state-10.json" );
//      Mockito.when( api.getLastBuildBuildingState( fifth ) ).thenReturn( response );
//
//      jobUpdater.poll();
//      core.setSimulatedTime( 8000 );
//      Assert.assertEquals( 10000, second.expectedBuildTimeProperty().get() );
//      Assert.assertEquals( 7000, second.currentBuildTimeProperty().get() );
//      Assert.assertEquals( 10000, fifth.expectedBuildTimeProperty().get() );
//      Assert.assertEquals( 7000, fifth.currentBuildTimeProperty().get() );
//
//      //finish building the second leaving it at unstable
//      response = TestCommon.readFileIntoString( getClass(), "built-state.json" );
//      Mockito.when( api.getLastBuildBuildingState( second ) ).thenReturn( response );
//      response = TestCommon.readFileIntoString( getClass(), "job-details-unstable.json" );
//      Mockito.when( api.getLastBuildJobDetails( second ) ).thenReturn( response );
//
//      jobUpdater.poll();
//      core.setSimulatedTime( 12000 );
//      Assert.assertEquals( 10000, second.expectedBuildTimeProperty().get() );
//      Assert.assertEquals( 0, second.currentBuildTimeProperty().get() );
//      Assert.assertEquals( BuildState.Built, second.buildStateProperty().get() );
//      Assert.assertEquals( 10000, fifth.expectedBuildTimeProperty().get() );
//      Assert.assertEquals( 11000, fifth.currentBuildTimeProperty().get() );
//      Assert.assertEquals( BuildState.Building, fifth.buildStateProperty().get() );
//
//      //finish building the fifth, leaving it at failure
//      response = TestCommon.readFileIntoString( getClass(), "built-state.json" );
//      Mockito.when( api.getLastBuildBuildingState( fifth ) ).thenReturn( response );
//      response = TestCommon.readFileIntoString( getClass(), "job-details-failure.json" );
//      Mockito.when( api.getLastBuildJobDetails( fifth ) ).thenReturn( response );
//
//      jobUpdater.poll();
//      Assert.assertEquals( 10000, second.expectedBuildTimeProperty().get() );
//      Assert.assertEquals( 0, second.currentBuildTimeProperty().get() );
//      Assert.assertEquals( BuildState.Built, second.buildStateProperty().get() );
//      Assert.assertEquals( 10000, fifth.expectedBuildTimeProperty().get() );
//      Assert.assertEquals( 0, fifth.currentBuildTimeProperty().get() );
//      Assert.assertEquals( BuildState.Built, fifth.buildStateProperty().get() );
//   }//End Method

}//End Class


text:
class AddProvisionedAtToServer < ActiveRecord::Migration
  def change
    add_column :servers, :provisioned_at, :datetime
  end
end


text:
#include <cstdio>
#include <fstream>
#include <functional>
#include <hare/base/noncopyable.h>
#include <unordered_map>

using namespace hare;
using namespace hare::net;

using WordCountMap = std::unordered_map<String, int>;
class WordCountReceiver : NonCopyable {
private:
  EventLoop *loop_;
  TcpServer server_;
  int senders_;
  WordCountMap wordcounts_;

public:
  WordCountReceiver(EventLoop *loop, const InetAddress &listenAddr)
      : loop_(loop), server_(loop, listenAddr, "WordCountReceiver"),
        senders_(0) {
    server_.setConnectionCallback(std::bind(&WordCountReceiver::onConnection,
                                            this, std::placeholders::_1));
    server_.setMessageCallback(
        std::bind(&WordCountReceiver::onMessage, this, std::placeholders::_1,
                  std::placeholders::_2, std::placeholders::_3));
  }

  void start(int senders) {
    LOG_INFO << "start " << senders << " senders";
    senders_ = senders;
    wordcounts_.clear();
    server_.start();
  }

private:
  void onConnection(const TcpConnectionPtr &conn) {
    LOG_DEBUG << conn->peerAddress().toIpPort() << " -> "
              << conn->localAddress().toIpPort() << " is "
              << (conn->connected() ? "UP" : "DOWN");
    if (!conn->connected()) {
      if (--senders_ == 0) {
        output();
        loop_->quit();
      }
    }
  }

  void onMessage(const TcpConnectionPtr &conn, Buffer *buf, Timestamp) {
    const char *crlf = nullptr;
    while ((crlf = buf->findCRLF()) != nullptr) {
      const char *tab = std::find(buf->peek(), crlf, '\t');
      if (tab != crlf) {
        String word(buf->peek(), tab);
        int64_t cnt = atoll(tab);
        wordcounts_[word] += cnt;
      } else {
        LOG_ERROR << "Wrong format, no tab found";
        conn->shutdown();
      }
      buf->retrieveUntil(crlf + 2);
    }
  }

  void output() {
    LOG_INFO << "Writing shard";
    std::ofstream out("shard");
    for (WordCountMap::iterator it = wordcounts_.begin();
         it != wordcounts_.end(); ++it) {
      out << it->first << '\t' << it->second << '\n';
    }
  }
};

int main(int argc, char *argv[]) {
  if (argc < 3) {
    printf("Usage: %s listen_port number_of_senders\n", argv[0]);
  } else {
    EventLoop loop;
    int port = atoi(argv[1]);
    InetAddress addr(static_cast<uint16_t>(port));
    LOG_TRACE << "word_count receiver port " << port;
    WordCountReceiver receiver(&loop, addr);
    receiver.start(atoi(argv[2]));
    loop.loop();
  }
}


text:
import React from 'react';
import { asset, Environment, View } from 'react-360';
import { connect } from 'react-redux';
import { compose } from 'redux';
import Hero from './../components/locs/Hero/Hero';
// import ItemContainer from './../components/locs/Item/ItemContainer';
import config from './../config/homeConfig';
// import Item from './../components/locs/Item/Item';
import getDevice from './../components/hocs/getDevice';

// import VideoContainer from './../containers/MobileVideoContainer';

class Home extends React.Component {

  constructor(props) {
    super(props);
    this.webMode = 'webvr';
    // this.webMode = 'webvr'; // comment in production
  }

  componentDidMount() {
    Environment.setBackgroundImage(asset('360_world.jpg'), {
      format: '2D',
    });

    if (this.props.parentPathName === '/webvr') this.webMode = 'webvr'; // comment this in dev
    else this.webMode = 'web'; // comment this in dev
    // this.webMode = 'web'; // comment this in production
  }

  componentDidUpdate() {
    const { activeItem } = this.props;
    if (activeItem === 'hidden') {
      Environment.setBackgroundImage(asset('360_world.jpg'), {
        format: '2D',
      });
    } else Environment.clearBackground();
  }

  logoTextScrolled() {
    if (this.webMode === 'webvr') return config.heroFooterText.centerIcon.logoTextScrolledWebVR;
    return config.heroFooterText.centerIcon.logoTextScrolled;
  }

  logoImageScrolled() {
    if (this.webMode === 'webvr') return config.heroText.centerIcon.webvrLogoImageScrolled;
    return config.heroText.centerIcon.logoImageScrolled;
  }

  centerLogoIconName() {
    if (this.webMode === 'webvr') return config.heroText.centerIcon.webvrCenterLogoIconName;
    return config.heroText.centerIcon.centerLogoIconName;
  }

  href() {
    if (this.webMode === 'webvr') return config.heroText.centerIcon.webvrhref;
    return config.heroText.centerIcon.href;
  }

  content() {
    return (
      <View>
        <Hero
          textNoScroll={config.heroFooterText.none.text}
          textColorNoScroll={config.heroFooterText.none.color}
          textScrollHero={config.heroFooterText.centerIcon.text}
          textColorScrollHero={config.heroFooterText.centerIcon.color}
          textScrollCenterLeftIcon={config.heroFooterText.centerLeftIcon.text}
          textColorScrollCenterLeftIcon={config.heroFooterText.centerLeftIcon.color}
          textScrollCenterRightIcon={config.heroFooterText.centerRightIcon.text}
          textColorScrollCenterRightIcon={config.heroFooterText.centerRightIcon.color}
          logoImage={config.heroText.centerIcon.backgroundImage360}
          logoImageScrolled={this.logoImageScrolled()} //
          logoTextScrolled={this.logoTextScrolled()} //
          centerLogoIconName={this.centerLogoIconName()} //
          centerHref={this.href()} //
          centerLeftIconName={config.heroIcon.centerLeftIcon.name360}
          centerLeftIconImage={config.heroIcon.centerLeftIcon.image360}
          centerLeftIconHref={config.heroIcon.centerLeftIcon.href}
          centerRightIconName={config.heroIcon.centerRightIcon.name360}
          centerRightIconImage={config.heroIcon.centerRightIcon.image360}
          centerRightIconHref={config.heroIcon.centerRightIcon.href}
          webMode={this.webMode}
        />
      </View>
    );
  }

  render() {
    return (
      <View>
        {this.content()}
      </View>
    );
  }
}

const mapStateToProps = ({ activeItem, webMode }) => ({ activeItem, webMode });

// export default connect(mapStateToProps, null)(Home);

export default compose(getDevice, connect(mapStateToProps, null))(Home);
// export default Home;


text:
using System;
using System.Globalization;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using FacetedWorlds.MyCon.ImageUtilities;

namespace FacetedWorlds.MyCon.Converters
{
    public class CachedImageUrlValueConverter : IValueConverter
    {
        private static IsolatedStorageFile _isoStore = IsolatedStorageFile.GetUserStoreForApplication();

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (targetType != typeof(ImageSource))
                throw new InvalidOperationException("CachedImageUrlValueConverter can only be used on ImageSource properties.");

            if (value == null)
                return value;

            if (!(value is CachedImage))
                return null;
            CachedImage cachedImage = (CachedImage)value;
            if (cachedImage.Access != null)
                cachedImage.Access();
            string url = cachedImage.ImageUrl;
            if (url == null)
                return null;
            if (!url.StartsWith("storage:"))
                return new BitmapImage(new Uri(url, UriKind.RelativeOrAbsolute));

            url = url.Substring("storage:".Length);
            using (IsolatedStorageFileStream isoStream = _isoStore.OpenFile(url, FileMode.Open))
            {
                BitmapImage bmp = new BitmapImage();
                bmp.SetSource(isoStream);
                return bmp;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}


text:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Code generated by Microsoft (R) AutoRest Code Generator.

package com.azure.resourcemanager.machinelearning.models;

import com.azure.core.annotation.Immutable;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;

/** The desired maximum forecast horizon in units of time-series frequency. */
@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "mode",
    defaultImpl = ForecastHorizon.class)
@JsonTypeName("ForecastHorizon")
@JsonSubTypes({
    @JsonSubTypes.Type(name = "Auto", value = AutoForecastHorizon.class),
    @JsonSubTypes.Type(name = "Custom", value = CustomForecastHorizon.class)
})
@Immutable
public class ForecastHorizon {
    /** Creates an instance of ForecastHorizon class. */
    public ForecastHorizon() {
    }

    /**
     * Validates the instance.
     *
     * @throws IllegalArgumentException thrown if the instance is not valid.
     */
    public void validate() {
    }
}


text:
import {
    Ident,
    Number,
    Dimension,
    LeftParenthesis,
    RightParenthesis,
    Colon,
    Delim
} from '../../tokenizer/index.js';

export const name = 'MediaFeature';
export const structure = {
    name: String,
    value: ['Identifier', 'Number', 'Dimension', 'Ratio', null]
};

export function parse() {
    const start = this.tokenStart;
    let name;
    let value = null;

    this.eat(LeftParenthesis);
    this.skipSC();

    name = this.consume(Ident);
    this.skipSC();

    if (this.tokenType !== RightParenthesis) {
        this.eat(Colon);
        this.skipSC();

        switch (this.tokenType) {
            case Number:
                if (this.lookupNonWSType(1) === Delim) {
                    value = this.Ratio();
                } else {
                    value = this.Number();
                }

                break;

            case Dimension:
                value = this.Dimension();
                break;

            case Ident:
                value = this.Identifier();
                break;

            default:
                this.error('Number, dimension, ratio or identifier is expected');
        }

        this.skipSC();
    }

    this.eat(RightParenthesis);

    return {
        type: 'MediaFeature',
        loc: this.getLocation(start, this.tokenStart),
        name,
        value
    };
}

export function generate(node) {
    this.token(LeftParenthesis, '(');
    this.token(Ident, node.name);

    if (node.value !== null) {
        this.token(Colon, ':');
        this.node(node.value);
    }

    this.token(RightParenthesis, ')');
}


text:
package vindexes

import (
	"bytes"
	"crypto/md5"

	"vitess.io/vitess/go/sqltypes"
)

var (
	_ Functional = (*BinaryMD5)(nil)
)

// BinaryMD5 is a vindex that hashes binary bits to a keyspace id.
type BinaryMD5 struct {
	name string
}

// NewBinaryMD5 creates a new BinaryMD5.
func NewBinaryMD5(name string, _ map[string]string) (Vindex, error) {
	return &BinaryMD5{name: name}, nil
}

// String returns the name of the vindex.
func (vind *BinaryMD5) String() string {
	return vind.name
}

// Cost returns the cost as 1.
func (vind *BinaryMD5) Cost() int {
	return 1
}

// Verify returns true if ids maps to ksids.
func (vind *BinaryMD5) Verify(_ VCursor, ids []sqltypes.Value, ksids [][]byte) ([]bool, error) {
	out := make([]bool, len(ids))
	for i := range ids {
		out[i] = (bytes.Compare(binHash(ids[i].ToBytes()), ksids[i]) == 0)
	}
	return out, nil
}

// Map returns the corresponding keyspace id values for the given ids.
func (vind *BinaryMD5) Map(_ VCursor, ids []sqltypes.Value) ([]KsidOrRange, error) {
	out := make([]KsidOrRange, 0, len(ids))
	for _, id := range ids {
		out = append(out, KsidOrRange{ID: binHash(id.ToBytes())})
	}
	return out, nil
}

func binHash(source []byte) []byte {
	sum := md5.Sum(source)
	return sum[:]
}

func init() {
	Register("binary_md5", NewBinaryMD5)
}


text:
package org.apache.hyracks.storage.am.btree;

import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer;
import org.apache.hyracks.dataflow.common.data.marshalling.IntegerSerializerDeserializer;
import org.apache.hyracks.dataflow.common.util.SerdeUtils;
import org.apache.hyracks.storage.am.common.api.IIndex;
import org.apache.hyracks.storage.am.common.ophelpers.MultiComparator;

public abstract class AbstractOperationCallbackTest {
    protected static final int NUM_KEY_FIELDS = 1;

    @SuppressWarnings("rawtypes")
    protected final ISerializerDeserializer[] keySerdes;
    protected final MultiComparator cmp;
    protected final int[] bloomFilterKeyFields;

    protected IIndex index;

    protected abstract void createIndexInstance() throws Exception;

    public AbstractOperationCallbackTest() {
        this.keySerdes = new ISerializerDeserializer[] { IntegerSerializerDeserializer.INSTANCE };
        this.cmp = MultiComparator.create(SerdeUtils.serdesToComparatorFactories(keySerdes, keySerdes.length));
        bloomFilterKeyFields = new int[NUM_KEY_FIELDS];
        for (int i = 0; i < NUM_KEY_FIELDS; ++i) {
            bloomFilterKeyFields[i] = i;
        }
    }

    public void setup() throws Exception {
        createIndexInstance();
        index.create();
        index.activate();
    }

    public void tearDown() throws Exception {
        index.deactivate();
        index.destroy();
    }
}


text:
title: "Cleaning Up a Country: A Data-Driven Examination of Ethiopia's Growing Sanitation Issues"
excerpt: "Embedded above is a pure JavaScript-powered flowchart from a [team project](http://carlvlewis2.wpengine.com/dmchallenge) that was part of Columbia University's Tow Center"
tags:
  - "DATA-VIZ"
  - "INTERACTIVES"
  - "MULTIMEDIA"
  - "NEWS-APPS"
date: 2014-07-01
header:
  teaser: /portfolio/eth.png
sidebar:
  - title: "Role"
    image: /images/portfolio/eth.png
    image_alt: "logo"
    text: "Designer, Front-End Developer"
  - title: "Responsibilities"
    text: "Reuters try PR stupid commenters should isn't a business model"
gallery:
  - url:
    image_path:
    alt:
  - url:
    image_path:
    alt:
  - url:
    image_path:
    alt:
---

<iframe src="http://carlvlewis2.wpengine.com/dmchallenge/terrapretta/TerraPretaSlide.html" width="960px" height="600px"></iframe>

Hover over each stage to find out more information.

Embedded above is a pure JavaScript-powered flowchart from a [team project](http://carlvlewis2.wpengine.com/dmchallenge) that was part of Columbia University's Tow Center for Digital Journalism annual 24-hour digital media hackathon. The project took home first place at the end of the hackathon. I served as the team leader, divvying up content and slides to team members who later iFramed in their content under tight deadlines. I built this particular interactive in less than an hour from scratch using CSS3, HTML5 and JavaScript elements.

I also oversaw the larger presentation, including customizing the open-source [Coda Slider jQuery](http://kevinbatdorf.github.io/codaslider/) plugin to work within our project's constraints, and performing data analysis to ensure our team's conclusions were of statistical significance. Other team members who participated in the project included [Stephanie Vatz](http://www.linkedin.com/pub/stephanie-vatz/22/630/601), [Rani Molla](https://twitter.com/ranimolla), [Erin Richey](https://twitter.com/ErinCRichey) and Kelty Ortiz.

And, of course, the semester-long preparation we received from [Prof. Susan E. McGregor](http://susanemcgregor.com/) (and the donuts halfway in!) shouldn't go unnoticed.

# [Click here to view the project live>>](http://carlvlewis2.wpengine.com/dmchallenge)

{% include gallery caption="" %}


text:
package org.squin.common;

import java.util.Comparator;

/**
 * A {@link java.util.Comparator} for {@link PrioritizedObject}s.
 * For two objects with a different priority it holds that the object with the
 * higher priority is "less than" the other object. Two objects with the same
 * priority are equal.
 *
 * @author Olaf Hartig (hartig@informatik.hu-berlin.de)
 */
public class PriorityBasedComparator<T extends PrioritizedObject> implements Comparator<T>
{
	// implementation of the Comparator interface

	public int compare ( T o1, T o2 )
	{
		return ( (PrioritizedObject) o2 ).getPriority().numericalValue - ( (PrioritizedObject) o1 ).getPriority().numericalValue;
	}

	@Override
	public boolean equals ( Object obj )
	{
		return ( obj instanceof PriorityBasedComparator );
	}

}


text:
/**
 * Modify javascript prototypes.
 */

/**
 * Find out if the string has the argument at the beginning.
 */
String.prototype.startsWith = function (str)
{
	return this.slice(0, str.length) == str;
};

/**
 * Find out if the string has the argument at the end.
 */
String.prototype.endsWith = function (str)
{
	return this.slice(this.length - str.length) == str;
};

/**
 * Find out if the string contains the argument at any position.
 */
String.prototype.contains = function(str)
{
	return this.indexOf(str) != -1;
};

/**
 * Return the piece of string until the argument is found.
 * 'hi.there'.substringUpTo('.') => 'hi'
 */
String.prototype.substringUpTo = function(str)
{
	if (!this.contains(str))
	{
		return this;
	}
	return this.slice(0, this.indexOf(str));
}

/**
 * Return the piece of string starting with the argument; empty string if not found.
 * 'hi.there'.substringFrom('.') => 'there'
 */
String.prototype.substringFrom = function(str)
{
	if (!this.contains(str))
	{
		return '';
	}
	return this.slice(this.indexOf(str) + 1);
}

/**
 * Return the piece of string starting with the last instance of the argument; empty string if not found.
 * 'hi.there.you'.substringFromLast('.') => 'your'
 */
String.prototype.substringFromLast = function(str)
{
	if (!this.contains(str))
	{
		return '';
	}
	return this.slice(this.lastIndexOf(str) + 1);
}

/**
 * Splits the string using the dot as separator and returns the last element of the split with "List"
 * added at the end.
 */
String.prototype.listify = function ()
{
	return this.split('.').pop() + "List";
};


text:
package com.alachisoft.tayzgrid.common.caching.statistics.operations;

public enum ServerOperations implements Operations
{

    RequestsPerSec,
    ResponsesPerSec,
    ClientBytesSentPerSec,
    ClientBytesRecievedPerSec,
    MSecPerCacheOperation,ClientPort,
    GeneralNotificationQueueSize,byteSentPerSec,bytereceivePerSec,eventQueueCount,

    //<editor-fold defaultstate="collapsed" desc="System Counters">
    //Cpu usage is returned in percentage where as Memory is returned in bytes
    SystemFreeMemory,
    SystemCpuUsage,
    SystemMemoryUsage,
    SystemNetworkUsage,
    VMCpuUsage,
    VMCommittedMemory, //committed virtual memory guaranteed to be available to Vm
    VMMemoryUsage, // Total Memory used by VM
    VMMaxMemory, //Maximum amount of memory that VM may use
    VMNetworkUsage,
    //</editor-fold>
}


text:
namespace _02.DefaultValues
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    public class DefaultValues
    {
        public static void Main(string[] args)
        {
            var wordPairs = new Dictionary<string, string>();
            var line = Console.ReadLine();

            while (line != "end")
            {
                ReadValues(wordPairs, line);
                line = Console.ReadLine();
            }

            var defaultValue = Console.ReadLine();
            PrintValues(wordPairs, defaultValue);
        }

        private static void ReadValues(Dictionary<string, string> wordPairs, string line)
        {
            var lineTokens = line
                .Split("-> ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)
                .ToArray();

            var key = lineTokens[0];
            var value = lineTokens[1];

            if (!wordPairs.ContainsKey(key))
            {
                wordPairs.Add(key, string.Empty);
            }

            wordPairs[key] = value;
        }

        private static void PrintValues(Dictionary<string, string> wordPairs, string defaultValue)
        {
            var result = wordPairs
                .Where(x => !x.Value.Equals("null"))
                .OrderByDescending(x => x.Value.Length);

            foreach (var kvp in result)
            {
                Console.WriteLine($"{kvp.Key} <-> {kvp.Value}");
            }

            var defaultResult = wordPairs
                .Where(x => x.Value.Equals("null"));

            foreach (var kvp in defaultResult)
            {
                Console.WriteLine($"{kvp.Key} <-> {defaultValue}");
            }
        }
    }
}


text:
<!DOCTYPE html>
<meta charset="utf-8">

Info

current filter:

 .

 .

 .

frequency:

percent:

Exploration

          item 1
          item 2
          frequency
          percent

        <input id="sort" type="checkbox" onclick="sortItems()">sort by frequency

        <input id="update_Axis" type="checkbox" name="update" value="Car" onclick="render(false)">update axis

help


text:
package net.mijack.paperapp.ui;

import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.DialogInterface;
import android.content.Intent;
import android.support.annotation.Nullable;
import android.support.design.widget.NavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;

import net.mijack.paperapp.R;
import net.mijack.paperapp.api.Api;
import net.mijack.paperapp.api.ApiService;
import net.mijack.paperapp.bean.CreateResult;
import net.mijack.paperapp.bean.QueryResult;
import net.mijack.paperapp.bean.STATUS;
import net.mijack.paperapp.fragment.HistoryFragment;
import net.mijack.paperapp.fragment.HomeFragment;
import net.mijack.paperapp.fragment.SettingFragment;
import net.mijack.paperapp.rx.BaseSubscriber;
import net.mijack.paperapp.util.PreferenceUtil;

import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener /*implements DialogInterface.OnClickListener */ {
    private static final int REQUEST_CODE_SCAN = 1;
    NavigationView navigationView;
    FrameLayout frameLayout;
    Fragment currentFragment = null;
    SparseArray<Fragment> sparseArray;
    Toolbar toolbar;
    private ActionBarDrawerToggle drawerToggle;
    private DrawerLayout drawerLayout;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        navigationView = (NavigationView) findViewById(R.id.navigationView);
        frameLayout = (FrameLayout) findViewById(R.id.frameLayout);
        drawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close);
        drawerToggle.syncState();
        drawerLayout.addDrawerListener(drawerToggle);
        navigationView.setNavigationItemSelectedListener(this);
        sparseArray = new SparseArray<>();
        changeFragment(R.id.action_main);
    }

    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        int itemId = item.getItemId();
        switch (itemId) {
            case R.id.action_scan:
                Intent intent = new Intent(this, ScannerActivity.class);
                startActivityForResult(intent, REQUEST_CODE_SCAN);
                changeFragment(R.id.action_main);
                return true;
            case R.id.action_main:
            case R.id.action_history:
            case R.id.action_setting:
                changeFragment(itemId);
                return true;
            default:
                return false;
        }
    }

    private void changeFragment(int itemId) {
        drawerLayout.closeDrawers();
        Fragment fragment = sparseArray.get(itemId);
        boolean createFragment = fragment == null;
        if (createFragment) {
            switch (itemId) {
                case R.id.action_main:
                    fragment = new HomeFragment();
                    break;
                case R.id.action_history:
                    fragment = new HistoryFragment();
                    break;
                case R.id.action_setting:
                    fragment = new SettingFragment();
                    break;
            }
        }
        FragmentTransaction transaction = getSupportFragmentManager()
                .beginTransaction();
        if (currentFragment != null) {
            transaction.hide(currentFragment);
        }
        if (createFragment) {
            transaction.add(R.id.frameLayout, fragment);
        } else {
            transaction.show(fragment);
        }
        currentFragment = fragment;
        transaction.commit();
    }

//    private static final int REQUEST_CODE_SCAN = 1;
//    TextView textView;
//    Button button;
//    private Api api;
//    private EditText editText;
//
//    @Override
//    protected void onCreate(Bundle savedInstanceState) {
//        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);
//        api = ApiService.getService(Api.class);
//        textView = (TextView) findViewById(R.id.text);
//        button = (Button) findViewById(R.id.button);
//        button.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View v) {
//                Intent intent = new Intent(MainActivity.this, ScannerActivity.class);
//                startActivityForResult(intent, REQUEST_CODE_SCAN);
//            }
//        });
//    }
//
//    @Override
//    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//        super.onActivityResult(requestCode, resultCode, data);
//        if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_SCAN) {
//            String result = data.getStringExtra("result");
//            textView.setText(result);
////            发起网络请求
//            api.createTask(result)
//                    .subscribeOn(Schedulers.io())
//                    .observeOn(AndroidSchedulers.mainThread())
//                    .filter(new Func1<CreateResult, Boolean>() {
//                        @Override
//                        public Boolean call(CreateResult createResult) {
//                            STATUS status = createResult.getStatus();
//                            switch (status) {
//                                case WAIT:
//                                    Toast.makeText(MainActivity.this, "任务已提交,等待下载", Toast.LENGTH_SHORT).show();
//                                    break;
//                                case DOING:
//                                    Toast.makeText(MainActivity.this, "任务已下载", Toast.LENGTH_SHORT).show();
//                                    break;
//                                case UNKNOWN:
//                                    Toast.makeText(MainActivity.this, "提交异常", Toast.LENGTH_SHORT).show();
//                                    break;
//                            }
//                            return status.equals(STATUS.FINISH);
//                        }
//                    })
//                    .observeOn(Schedulers.io())
//                    .flatMap(new Func1<CreateResult, Observable<QueryResult>>() {
//                        @Override
//                        public Observable<QueryResult> call(CreateResult createResult) {
//                            String localPath = createResult.getLocalPath();
//                            int start = localPath.lastIndexOf("\\");
//                            String md5 = localPath.substring(start + 1, localPath.length() - 4);
//                            return api.queryTask(md5);
//                        }
//                    })
//                    .observeOn(AndroidSchedulers.mainThread())
//                    .subscribe(new BaseSubscriber<QueryResult>(){
//                        @Override
//                        public void onNext(QueryResult queryResult) {
//
//                        }
//                    })
//            ;
//        }
//    }
//
//
//    @Override
//    public boolean onCreateOptionsMenu(Menu menu) {
//        getMenuInflater().inflate(R.menu.menu_main, menu);
//        return super.onCreateOptionsMenu(menu);
//    }
//
//    @Override
//    public boolean onOptionsItemSelected(MenuItem item) {
//        if (item.getItemId() == R.id.setting) {
//            showSetting();
//            return true;
//        }
//        return super.onOptionsItemSelected(item);
//    }
//
//    private void showSetting() {
//        AlertDialog.Builder builder = new AlertDialog.Builder(this);
//        View view = LayoutInflater.from(this)
//                .inflate(R.layout.dialog_setting, null);
//        editText = (EditText) view.findViewById(R.id.editText);
//        ClipboardManager cm = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
//        ClipData cd = cm.getPrimaryClip();
//        String string = null;
//        try {
//            string = cd.getItemAt(0).getText().toString();
//        } catch (NullPointerException e) {
//            e.printStackTrace();
//        }
//        if (!TextUtils.isEmpty(string)) {
//            editText.setText(string);
//        }
//        builder.setTitle(getString(R.string.set_base_url))
//                .setView(view)
//                .setNegativeButton("取消", this)
//                .setPositiveButton("确定", this)
//                .create()
//                .show();
//    }
//
//    @Override
//    public void onClick(DialogInterface dialog, int which) {
//        if (which == DialogInterface.BUTTON_POSITIVE) {
//            if (editText != null) {
//                String baseUrl = editText.getText().toString();
//                PreferenceUtil.saveBaseUrl(getApplication(), baseUrl);
//            }
//        }
//    }
}


text:
"""Info extractor."""

import re

from bs4 import BeautifulSoup

from cmdlr.autil import run_in_nodejs

from .sharedjs import get_shared_js

async def _get_volumes_data_tag(soup, loop):
    """Get single tag contain volumes data from entry soup."""
    vs_tag = soup.find('input', id='__VIEWSTATE')

    if vs_tag:  # 18X only
        lzstring = vs_tag['value']
        question_js = ('LZString.decompressFromBase64("{lzstring}")'
                       .format(lzstring=lzstring))
        full_js = get_shared_js() + question_js

        volumes_html = await loop.run_in_executor(
            None,
            lambda: run_in_nodejs(full_js),
        )

        volumes_data_tag = BeautifulSoup(volumes_html, 'html.parser')

    else:
        volumes_data_tag = soup.find('div', class_=['chapter', 'cf'])

    return volumes_data_tag

def _get_volumes_from_volumes_data_tag(volumes_data_tag, absurl):
    """Get all volumes from volumes data tag."""
    result = {}

    for sect_title_tag in volumes_data_tag.find_all('h4'):
        sect_title = sect_title_tag.get_text()

        chapter_data_tag = (
            sect_title_tag
            .find_next_sibling(class_='chapter-list')
        )
        chapter_a_tags = (
            chapter_data_tag
            .find_all('a', href=re.compile(r'^/comic/.*\.html$'))
        )

        name_url_mapper = {
            '{}_{}'.format(sect_title, a['title']): absurl(a['href'])
            for a in chapter_a_tags
        }

        result.update(name_url_mapper)

    return result

async def extract_volumes(fetch_result, loop):
    """Get all volumes."""
    soup, absurl = fetch_result
    volumes_data_tag = await _get_volumes_data_tag(soup, loop)

    return _get_volumes_from_volumes_data_tag(volumes_data_tag, absurl)

def extract_name(fetch_result):
    """Get name."""
    return fetch_result.soup.find('div', class_='book-title').h1.string

def extract_finished(fetch_result):
    """Get finished state."""
    text = (fetch_result.soup
            .find('strong', string=re.compile('^(?:漫畫狀態:|漫画状态:)$'))
            .find_next_sibling('span')
            .string)

    if '已完結' in text or '已完结' in text:
        return True

    return False

def extract_description(fetch_result):
    """Get description."""
    return fetch_result.soup.find('div', id='intro-all').get_text()

def extract_authors(fetch_result):
    """Get authors."""
    return [a.string for a in fetch_result.soup
            .find('strong', string=re.compile('^(?:漫畫作者:|漫画作者:)$'))
            .parent('a')]


text:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Input;
using Quickblox.Sdk.Modules.UsersModule.Models;
using Xamarin.Forms;
using QbChat.Pcl.Repository;

namespace XamarinForms.QbChat.ViewModels
{
    public class ChatInfoViewModel : ViewModel
    {
        private string dialogId;
		private bool isLeaveStarted;

        public ChatInfoViewModel(string dialogId)
        {
            this.dialogId = dialogId;
            this.LeaveChatCommand = new Command(LeaveChatCommandExecute);
            this.AddOccupantsCommand = new Command(this.AddOccupantsCommandExecute);
        }

        private List<User> users;
        private bool isLoading;

        public List<User> Users
        {
            get { return this.users; }
            set
            {
                this.users = value;
                this.RaisePropertyChanged();
            }
        }

        public ICommand LeaveChatCommand { get; private set; }

        public ICommand AddOccupantsCommand { get; private set; }

        public override void OnAppearing()
        {
            base.OnAppearing();

            if (isLoading)
                return;

            this.isLoading = true;

            this.IsBusyIndicatorVisible = true;

            Task.Factory.StartNew(async () => {
                var dialog = Database.Instance().GetDialog(this.dialogId);

                var users = await App.QbProvider.GetUsersByIdsAsync(dialog.OccupantIds);
                Device.BeginInvokeOnMainThread(() => {
                    Users = users;
                    this.IsBusyIndicatorVisible = false;
                });
            });
        }

        private async void LeaveChatCommandExecute(object obj)
        {
			if (this.isLeaveStarted)
			{
				return;
			}

			this.isLeaveStarted = true;

            this.IsBusyIndicatorVisible = true;

            var result = await App.Current.MainPage.DisplayAlert("Leave Chat", "Do you really want to Leave Chat?", "Yes", "Cancel");
			if (result)
			{
				try
				{
					var dialogInfo = await App.QbProvider.GetDialogAsync(this.dialogId);
					if (dialogInfo != null)
					{
						dialogInfo.OccupantsIds.Remove(App.QbProvider.UserId);

						var groupManager = App.QbProvider.GetXmppClient().GetGroupChatManager(dialogInfo.XmppRoomJid, dialogInfo.Id);
						groupManager.NotifyAboutGroupUpdate(new List<int>(), new List<int>() { App.QbProvider.UserId }, dialogInfo);
						groupManager.LeaveGroup(App.QbProvider.UserId.ToString());

					 	await App.QbProvider.DeleteDialogAsync(dialogInfo.Id);
						Database.Instance().DeleteDialog(dialogId);

						await App.Navigation.PopToRootAsync();
					}
					else {
						this.isLeaveStarted = false;
					}
				}
				catch (Exception ex)
				{
					this.isLeaveStarted = false;
				}
			}
			else {
				this.isLeaveStarted = false;
			}

            this.IsBusyIndicatorVisible = false;
        }

        private void AddOccupantsCommandExecute(object obj)
        {
            App.Navigation.PushAsync(new AddOccupantsIdsPage(this.dialogId));
        }
    }
}


text:
package com.zeus.visitor;

/**
 * @author xuxingbo
 * @Date 2017/7/4
 */
public class Computer implements ComputerPart {

    ComputerPart[] parts;

    public Computer() {
        parts = new ComputerPart[]{new Mouse(), new Keyboard(), new Monitor()};
    }

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        for(int i = 0; i < parts.length; i++){
            parts[i].accept(computerPartVisitor);
        }
        computerPartVisitor.visit(this);
    }
}


text:
    <bool-expr bool-domain="{{boolDomain}}" bool-symbol="{{symbol}}" bool-symbol-small="{{symbolSmall}}" bool-value="{{expression.text}}" bind-expression="expression"></bool-expr>

Gruppen

        <bool-expr ng-repeat="group in groups" class="group" group="group" group-key="{{group.key}}" bool-domain="{{boolDomain}}" bool-symbol="{{group.key}}" bind-expression="group.expression"></bool-expr>

            Es wurden keine Gruppen angelegt.

            Markieren Sie einen gültigen Bereich im Ausdruck und klicken Sie
            [Gx]
            , um Gruppen anzulegen.


text:
import { connect } from 'react-redux'
import { setVisibilityFilter } from '../actions'
import Link from '../components/Link'

/**
 * [将 store state 映射到 props 上]
 * @param  {Object} ownProps [即 props]
 * @return {Object} [必须是一个对象]
 */
const mapStateToProps = (state, ownProps) => {
  return {
    active: ownProps.filter === state.visibilityFilter
  }
}

/**
 * [分发 action 到期望的 props(Link) 上]
 * @return {Object} [description]
 */
const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    onClick: () => {
      dispatch(setVisibilityFilter(ownProps.filter))
    }
  }
}

/**
 * [FilterLink 使用 connect 方法将组件 Link 与 Redux 关联起来]
 * @type {注意这里直接传入形参,不是传入对象!}
 */
const FilterLink = connect(
  mapStateToProps,
  mapDispatchToProps
)(Link)

export default FilterLink


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

<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.9.1"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Aspen MUD: src/optionManager.h Source File</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>

<link href="search/search.css" rel="stylesheet" type="text/css"/>

<link href="doxygen.css" rel="stylesheet" type="text/css" />

Aspen MUD

Aspen is a light-weight, barebones mud engine written in c++ utilizing Lua for its' scripting engine.

src

optionManager.h

    1 /*

    2 *Our option manager holds and keeps track of global options.

    3 */

    4 #pragma once

    5 #include <unordered_map>

    6 #include <vector>

    7 #include <string>

    8 #include "mud.h"

    9 #include "conf.h"

   10 #include "option.h"

   11 #include "optionMeta.h"

   12 #include "property.h"

   13

   14 class OptionManager

   15 {

   16     std::unordered_map<int, std::vector<OptionMeta*>> _sections;

   17     std::unordered_map<std::string, OptionMeta*> _options;

   18 public:

   19     OptionManager();

   20     ~OptionManager();

   21     bool OptionExists(const std::string& name) const;

   22     bool ListOptions(OptionSection section, std::vector<OptionMeta*>* opts);

   23     bool AddOption(OptionMeta* option);

   24     OptionMeta* GetOption(const std::string &name);

   25     void ListOptions(std::vector<OptionMeta*>* options) const;

   26 };

OptionManager

Definition: optionManager.h:15

OptionMeta

Definition: optionMeta.h:16

<address class="footer">
Generated on Wed Mar 17 2021 11:04:31 for Aspen MUD by  1.9.1
</address>